1 // Copyright 2014 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "src/type-feedback-vector.h"
6
7 #include "src/code-stubs.h"
8 #include "src/ic/ic.h"
9 #include "src/ic/ic-state.h"
10 #include "src/objects.h"
11 #include "src/type-feedback-vector-inl.h"
12
13 namespace v8 {
14 namespace internal {
15
16
IsPropertyNameFeedback(Object * feedback)17 static bool IsPropertyNameFeedback(Object* feedback) {
18 if (feedback->IsString()) return true;
19 if (!feedback->IsSymbol()) return false;
20 Symbol* symbol = Symbol::cast(feedback);
21 Heap* heap = symbol->GetHeap();
22 return symbol != heap->uninitialized_symbol() &&
23 symbol != heap->premonomorphic_symbol() &&
24 symbol != heap->megamorphic_symbol();
25 }
26
27
operator <<(std::ostream & os,FeedbackVectorSlotKind kind)28 std::ostream& operator<<(std::ostream& os, FeedbackVectorSlotKind kind) {
29 return os << TypeFeedbackMetadata::Kind2String(kind);
30 }
31
32
GetKind(FeedbackVectorSlot slot) const33 FeedbackVectorSlotKind TypeFeedbackMetadata::GetKind(
34 FeedbackVectorSlot slot) const {
35 int index = VectorICComputer::index(kReservedIndexCount, slot.ToInt());
36 int data = Smi::cast(get(index))->value();
37 return VectorICComputer::decode(data, slot.ToInt());
38 }
39
GetName(FeedbackVectorSlot slot) const40 String* TypeFeedbackMetadata::GetName(FeedbackVectorSlot slot) const {
41 DCHECK(SlotRequiresName(GetKind(slot)));
42 FixedArray* names = FixedArray::cast(get(kNamesTableIndex));
43 // TODO(ishell): consider using binary search here or even Dictionary when we
44 // have more ICs with names.
45 Smi* key = Smi::FromInt(slot.ToInt());
46 for (int entry = 0; entry < names->length(); entry += kNameTableEntrySize) {
47 Object* current_key = names->get(entry + kNameTableSlotIndex);
48 if (current_key == key) {
49 Object* name = names->get(entry + kNameTableNameIndex);
50 DCHECK(name->IsString());
51 return String::cast(name);
52 }
53 }
54 UNREACHABLE();
55 return nullptr;
56 }
57
SetKind(FeedbackVectorSlot slot,FeedbackVectorSlotKind kind)58 void TypeFeedbackMetadata::SetKind(FeedbackVectorSlot slot,
59 FeedbackVectorSlotKind kind) {
60 int index = VectorICComputer::index(kReservedIndexCount, slot.ToInt());
61 int data = Smi::cast(get(index))->value();
62 int new_data = VectorICComputer::encode(data, slot.ToInt(), kind);
63 set(index, Smi::FromInt(new_data));
64 }
65
66
67 template Handle<TypeFeedbackMetadata> TypeFeedbackMetadata::New(
68 Isolate* isolate, const StaticFeedbackVectorSpec* spec);
69 template Handle<TypeFeedbackMetadata> TypeFeedbackMetadata::New(
70 Isolate* isolate, const FeedbackVectorSpec* spec);
71
72
73 // static
74 template <typename Spec>
New(Isolate * isolate,const Spec * spec)75 Handle<TypeFeedbackMetadata> TypeFeedbackMetadata::New(Isolate* isolate,
76 const Spec* spec) {
77 Factory* factory = isolate->factory();
78
79 const int slot_count = spec->slots();
80 const int slot_kinds_length = VectorICComputer::word_count(slot_count);
81 const int length = slot_kinds_length + kReservedIndexCount;
82 if (length == kReservedIndexCount) {
83 return Handle<TypeFeedbackMetadata>::cast(factory->empty_fixed_array());
84 }
85 #ifdef DEBUG
86 for (int i = 0; i < slot_count;) {
87 FeedbackVectorSlotKind kind = spec->GetKind(i);
88 int entry_size = TypeFeedbackMetadata::GetSlotSize(kind);
89 for (int j = 1; j < entry_size; j++) {
90 FeedbackVectorSlotKind kind = spec->GetKind(i + j);
91 DCHECK_EQ(FeedbackVectorSlotKind::INVALID, kind);
92 }
93 i += entry_size;
94 }
95 #endif
96
97 Handle<FixedArray> array = factory->NewFixedArray(length, TENURED);
98 array->set(kSlotsCountIndex, Smi::FromInt(slot_count));
99 // Fill the bit-vector part with zeros.
100 for (int i = 0; i < slot_kinds_length; i++) {
101 array->set(kReservedIndexCount + i, Smi::FromInt(0));
102 }
103
104 Handle<TypeFeedbackMetadata> metadata =
105 Handle<TypeFeedbackMetadata>::cast(array);
106
107 // Add names to NamesTable.
108 const int name_count = spec->name_count();
109
110 Handle<FixedArray> names =
111 name_count == 0
112 ? factory->empty_fixed_array()
113 : factory->NewFixedArray(name_count * kNameTableEntrySize);
114 int name_index = 0;
115 for (int i = 0; i < slot_count; i++) {
116 FeedbackVectorSlotKind kind = spec->GetKind(i);
117 metadata->SetKind(FeedbackVectorSlot(i), kind);
118 if (SlotRequiresName(kind)) {
119 Handle<String> name = spec->GetName(name_index);
120 DCHECK(!name.is_null());
121 int entry = name_index * kNameTableEntrySize;
122 names->set(entry + kNameTableSlotIndex, Smi::FromInt(i));
123 names->set(entry + kNameTableNameIndex, *name);
124 name_index++;
125 }
126 }
127 DCHECK_EQ(name_count, name_index);
128 metadata->set(kNamesTableIndex, *names);
129
130 // It's important that the TypeFeedbackMetadata have a COW map, since it's
131 // pointed to by both a SharedFunctionInfo and indirectly by closures through
132 // the TypeFeedbackVector. The serializer uses the COW map type to decide
133 // this object belongs in the startup snapshot and not the partial
134 // snapshot(s).
135 metadata->set_map(isolate->heap()->fixed_cow_array_map());
136
137 return metadata;
138 }
139
140
SpecDiffersFrom(const FeedbackVectorSpec * other_spec) const141 bool TypeFeedbackMetadata::SpecDiffersFrom(
142 const FeedbackVectorSpec* other_spec) const {
143 if (other_spec->slots() != slot_count()) {
144 return true;
145 }
146
147 int slots = slot_count();
148 int name_index = 0;
149 for (int i = 0; i < slots;) {
150 FeedbackVectorSlot slot(i);
151 FeedbackVectorSlotKind kind = GetKind(slot);
152 int entry_size = TypeFeedbackMetadata::GetSlotSize(kind);
153
154 if (kind != other_spec->GetKind(i)) {
155 return true;
156 }
157 if (SlotRequiresName(kind)) {
158 String* name = GetName(slot);
159 DCHECK(name != GetHeap()->empty_string());
160 String* other_name = *other_spec->GetName(name_index++);
161 if (name != other_name) {
162 return true;
163 }
164 }
165 i += entry_size;
166 }
167 return false;
168 }
169
DiffersFrom(const TypeFeedbackMetadata * other_metadata) const170 bool TypeFeedbackMetadata::DiffersFrom(
171 const TypeFeedbackMetadata* other_metadata) const {
172 if (other_metadata->slot_count() != slot_count()) {
173 return true;
174 }
175
176 int slots = slot_count();
177 for (int i = 0; i < slots;) {
178 FeedbackVectorSlot slot(i);
179 FeedbackVectorSlotKind kind = GetKind(slot);
180 int entry_size = TypeFeedbackMetadata::GetSlotSize(kind);
181 if (GetKind(slot) != other_metadata->GetKind(slot)) {
182 return true;
183 }
184 if (SlotRequiresName(kind)) {
185 if (GetName(slot) != other_metadata->GetName(slot)) {
186 return true;
187 }
188 }
189 i += entry_size;
190 }
191 return false;
192 }
193
Kind2String(FeedbackVectorSlotKind kind)194 const char* TypeFeedbackMetadata::Kind2String(FeedbackVectorSlotKind kind) {
195 switch (kind) {
196 case FeedbackVectorSlotKind::INVALID:
197 return "INVALID";
198 case FeedbackVectorSlotKind::CALL_IC:
199 return "CALL_IC";
200 case FeedbackVectorSlotKind::LOAD_IC:
201 return "LOAD_IC";
202 case FeedbackVectorSlotKind::LOAD_GLOBAL_IC:
203 return "LOAD_GLOBAL_IC";
204 case FeedbackVectorSlotKind::KEYED_LOAD_IC:
205 return "KEYED_LOAD_IC";
206 case FeedbackVectorSlotKind::STORE_IC:
207 return "STORE_IC";
208 case FeedbackVectorSlotKind::KEYED_STORE_IC:
209 return "KEYED_STORE_IC";
210 case FeedbackVectorSlotKind::GENERAL:
211 return "STUB";
212 case FeedbackVectorSlotKind::KINDS_NUMBER:
213 break;
214 }
215 UNREACHABLE();
216 return "?";
217 }
218
GetKind(FeedbackVectorSlot slot) const219 FeedbackVectorSlotKind TypeFeedbackVector::GetKind(
220 FeedbackVectorSlot slot) const {
221 DCHECK(!is_empty());
222 return metadata()->GetKind(slot);
223 }
224
GetName(FeedbackVectorSlot slot) const225 String* TypeFeedbackVector::GetName(FeedbackVectorSlot slot) const {
226 DCHECK(!is_empty());
227 return metadata()->GetName(slot);
228 }
229
230 // static
New(Isolate * isolate,Handle<TypeFeedbackMetadata> metadata)231 Handle<TypeFeedbackVector> TypeFeedbackVector::New(
232 Isolate* isolate, Handle<TypeFeedbackMetadata> metadata) {
233 Factory* factory = isolate->factory();
234
235 const int slot_count = metadata->slot_count();
236 const int length = slot_count + kReservedIndexCount;
237 if (length == kReservedIndexCount) {
238 return Handle<TypeFeedbackVector>::cast(factory->empty_fixed_array());
239 }
240
241 Handle<FixedArray> array = factory->NewFixedArray(length, TENURED);
242 array->set(kMetadataIndex, *metadata);
243
244 DisallowHeapAllocation no_gc;
245
246 // Ensure we can skip the write barrier
247 Handle<Object> uninitialized_sentinel = UninitializedSentinel(isolate);
248 DCHECK_EQ(*factory->uninitialized_symbol(), *uninitialized_sentinel);
249 for (int i = 0; i < slot_count;) {
250 FeedbackVectorSlot slot(i);
251 FeedbackVectorSlotKind kind = metadata->GetKind(slot);
252 int index = TypeFeedbackVector::GetIndex(slot);
253 int entry_size = TypeFeedbackMetadata::GetSlotSize(kind);
254
255 Object* value;
256 if (kind == FeedbackVectorSlotKind::LOAD_GLOBAL_IC) {
257 value = *factory->empty_weak_cell();
258 } else {
259 value = *uninitialized_sentinel;
260 }
261 array->set(index, value, SKIP_WRITE_BARRIER);
262 for (int j = 1; j < entry_size; j++) {
263 array->set(index + j, *uninitialized_sentinel, SKIP_WRITE_BARRIER);
264 }
265 i += entry_size;
266 }
267 return Handle<TypeFeedbackVector>::cast(array);
268 }
269
270
271 // static
GetIndexFromSpec(const FeedbackVectorSpec * spec,FeedbackVectorSlot slot)272 int TypeFeedbackVector::GetIndexFromSpec(const FeedbackVectorSpec* spec,
273 FeedbackVectorSlot slot) {
274 return kReservedIndexCount + slot.ToInt();
275 }
276
277
278 // static
Copy(Isolate * isolate,Handle<TypeFeedbackVector> vector)279 Handle<TypeFeedbackVector> TypeFeedbackVector::Copy(
280 Isolate* isolate, Handle<TypeFeedbackVector> vector) {
281 Handle<TypeFeedbackVector> result;
282 result = Handle<TypeFeedbackVector>::cast(
283 isolate->factory()->CopyFixedArray(Handle<FixedArray>::cast(vector)));
284 return result;
285 }
286
287
288 // This logic is copied from
289 // StaticMarkingVisitor<StaticVisitor>::VisitCodeTarget.
ClearLogic(Isolate * isolate)290 static bool ClearLogic(Isolate* isolate) {
291 return FLAG_cleanup_code_caches_at_gc && isolate->serializer_enabled();
292 }
293
294
ClearSlotsImpl(SharedFunctionInfo * shared,bool force_clear)295 void TypeFeedbackVector::ClearSlotsImpl(SharedFunctionInfo* shared,
296 bool force_clear) {
297 Isolate* isolate = GetIsolate();
298
299 if (!force_clear && !ClearLogic(isolate)) return;
300
301 Object* uninitialized_sentinel =
302 TypeFeedbackVector::RawUninitializedSentinel(isolate);
303
304 TypeFeedbackMetadataIterator iter(metadata());
305 while (iter.HasNext()) {
306 FeedbackVectorSlot slot = iter.Next();
307 FeedbackVectorSlotKind kind = iter.kind();
308
309 Object* obj = Get(slot);
310 if (obj != uninitialized_sentinel) {
311 switch (kind) {
312 case FeedbackVectorSlotKind::CALL_IC: {
313 CallICNexus nexus(this, slot);
314 nexus.Clear(shared->code());
315 break;
316 }
317 case FeedbackVectorSlotKind::LOAD_IC: {
318 LoadICNexus nexus(this, slot);
319 nexus.Clear(shared->code());
320 break;
321 }
322 case FeedbackVectorSlotKind::LOAD_GLOBAL_IC: {
323 LoadGlobalICNexus nexus(this, slot);
324 nexus.Clear(shared->code());
325 break;
326 }
327 case FeedbackVectorSlotKind::KEYED_LOAD_IC: {
328 KeyedLoadICNexus nexus(this, slot);
329 nexus.Clear(shared->code());
330 break;
331 }
332 case FeedbackVectorSlotKind::STORE_IC: {
333 StoreICNexus nexus(this, slot);
334 nexus.Clear(shared->code());
335 break;
336 }
337 case FeedbackVectorSlotKind::KEYED_STORE_IC: {
338 KeyedStoreICNexus nexus(this, slot);
339 nexus.Clear(shared->code());
340 break;
341 }
342 case FeedbackVectorSlotKind::GENERAL: {
343 if (obj->IsHeapObject()) {
344 InstanceType instance_type =
345 HeapObject::cast(obj)->map()->instance_type();
346 // AllocationSites are exempt from clearing. They don't store Maps
347 // or Code pointers which can cause memory leaks if not cleared
348 // regularly.
349 if (instance_type != ALLOCATION_SITE_TYPE) {
350 Set(slot, uninitialized_sentinel, SKIP_WRITE_BARRIER);
351 }
352 }
353 break;
354 }
355 case FeedbackVectorSlotKind::INVALID:
356 case FeedbackVectorSlotKind::KINDS_NUMBER:
357 UNREACHABLE();
358 break;
359 }
360 }
361 }
362 }
363
364
365 // static
ClearAllKeyedStoreICs(Isolate * isolate)366 void TypeFeedbackVector::ClearAllKeyedStoreICs(Isolate* isolate) {
367 SharedFunctionInfo::Iterator iterator(isolate);
368 SharedFunctionInfo* shared;
369 while ((shared = iterator.Next())) {
370 if (!shared->OptimizedCodeMapIsCleared()) {
371 FixedArray* optimized_code_map = shared->optimized_code_map();
372 int length = optimized_code_map->length();
373 for (int i = SharedFunctionInfo::kEntriesStart; i < length;
374 i += SharedFunctionInfo::kEntryLength) {
375 Object* lits =
376 optimized_code_map->get(i + SharedFunctionInfo::kLiteralsOffset);
377 TypeFeedbackVector* vector = nullptr;
378 if (lits->IsWeakCell()) {
379 WeakCell* cell = WeakCell::cast(lits);
380 if (cell->value()->IsLiteralsArray()) {
381 vector = LiteralsArray::cast(cell->value())->feedback_vector();
382 }
383 } else {
384 DCHECK(lits->IsLiteralsArray());
385 vector = LiteralsArray::cast(lits)->feedback_vector();
386 }
387 if (vector != nullptr) {
388 vector->ClearKeyedStoreICs(shared);
389 }
390 }
391 }
392 }
393 }
394
395
ClearKeyedStoreICs(SharedFunctionInfo * shared)396 void TypeFeedbackVector::ClearKeyedStoreICs(SharedFunctionInfo* shared) {
397 Isolate* isolate = GetIsolate();
398
399 Code* host = shared->code();
400 Object* uninitialized_sentinel =
401 TypeFeedbackVector::RawUninitializedSentinel(isolate);
402
403 TypeFeedbackMetadataIterator iter(metadata());
404 while (iter.HasNext()) {
405 FeedbackVectorSlot slot = iter.Next();
406 FeedbackVectorSlotKind kind = iter.kind();
407 if (kind != FeedbackVectorSlotKind::KEYED_STORE_IC) continue;
408 Object* obj = Get(slot);
409 if (obj != uninitialized_sentinel) {
410 KeyedStoreICNexus nexus(this, slot);
411 nexus.Clear(host);
412 }
413 }
414 }
415
416
417 // static
DummyVector(Isolate * isolate)418 Handle<TypeFeedbackVector> TypeFeedbackVector::DummyVector(Isolate* isolate) {
419 return isolate->factory()->dummy_vector();
420 }
421
422
EnsureArrayOfSize(int length)423 Handle<FixedArray> FeedbackNexus::EnsureArrayOfSize(int length) {
424 Isolate* isolate = GetIsolate();
425 Handle<Object> feedback = handle(GetFeedback(), isolate);
426 if (!feedback->IsFixedArray() ||
427 FixedArray::cast(*feedback)->length() != length) {
428 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
429 SetFeedback(*array);
430 return array;
431 }
432 return Handle<FixedArray>::cast(feedback);
433 }
434
435
EnsureExtraArrayOfSize(int length)436 Handle<FixedArray> FeedbackNexus::EnsureExtraArrayOfSize(int length) {
437 Isolate* isolate = GetIsolate();
438 Handle<Object> feedback_extra = handle(GetFeedbackExtra(), isolate);
439 if (!feedback_extra->IsFixedArray() ||
440 FixedArray::cast(*feedback_extra)->length() != length) {
441 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
442 SetFeedbackExtra(*array);
443 return array;
444 }
445 return Handle<FixedArray>::cast(feedback_extra);
446 }
447
448
InstallHandlers(Handle<FixedArray> array,MapHandleList * maps,CodeHandleList * handlers)449 void FeedbackNexus::InstallHandlers(Handle<FixedArray> array,
450 MapHandleList* maps,
451 CodeHandleList* handlers) {
452 int receiver_count = maps->length();
453 for (int current = 0; current < receiver_count; ++current) {
454 Handle<Map> map = maps->at(current);
455 Handle<WeakCell> cell = Map::WeakCellForMap(map);
456 array->set(current * 2, *cell);
457 array->set(current * 2 + 1, *handlers->at(current));
458 }
459 }
460
461
ConfigureUninitialized()462 void FeedbackNexus::ConfigureUninitialized() {
463 SetFeedback(*TypeFeedbackVector::UninitializedSentinel(GetIsolate()),
464 SKIP_WRITE_BARRIER);
465 SetFeedbackExtra(*TypeFeedbackVector::UninitializedSentinel(GetIsolate()),
466 SKIP_WRITE_BARRIER);
467 }
468
469
ConfigurePremonomorphic()470 void FeedbackNexus::ConfigurePremonomorphic() {
471 SetFeedback(*TypeFeedbackVector::PremonomorphicSentinel(GetIsolate()),
472 SKIP_WRITE_BARRIER);
473 SetFeedbackExtra(*TypeFeedbackVector::UninitializedSentinel(GetIsolate()),
474 SKIP_WRITE_BARRIER);
475 }
476
477
ConfigureMegamorphic()478 void FeedbackNexus::ConfigureMegamorphic() {
479 // Keyed ICs must use ConfigureMegamorphicKeyed.
480 DCHECK_NE(FeedbackVectorSlotKind::KEYED_LOAD_IC, vector()->GetKind(slot()));
481 DCHECK_NE(FeedbackVectorSlotKind::KEYED_STORE_IC, vector()->GetKind(slot()));
482
483 Isolate* isolate = GetIsolate();
484 SetFeedback(*TypeFeedbackVector::MegamorphicSentinel(isolate),
485 SKIP_WRITE_BARRIER);
486 SetFeedbackExtra(*TypeFeedbackVector::UninitializedSentinel(isolate),
487 SKIP_WRITE_BARRIER);
488 }
489
ConfigureMegamorphicKeyed(IcCheckType property_type)490 void KeyedLoadICNexus::ConfigureMegamorphicKeyed(IcCheckType property_type) {
491 Isolate* isolate = GetIsolate();
492 SetFeedback(*TypeFeedbackVector::MegamorphicSentinel(isolate),
493 SKIP_WRITE_BARRIER);
494 SetFeedbackExtra(Smi::FromInt(static_cast<int>(property_type)),
495 SKIP_WRITE_BARRIER);
496 }
497
ConfigureMegamorphicKeyed(IcCheckType property_type)498 void KeyedStoreICNexus::ConfigureMegamorphicKeyed(IcCheckType property_type) {
499 Isolate* isolate = GetIsolate();
500 SetFeedback(*TypeFeedbackVector::MegamorphicSentinel(isolate),
501 SKIP_WRITE_BARRIER);
502 SetFeedbackExtra(Smi::FromInt(static_cast<int>(property_type)),
503 SKIP_WRITE_BARRIER);
504 }
505
StateFromFeedback() const506 InlineCacheState LoadICNexus::StateFromFeedback() const {
507 Isolate* isolate = GetIsolate();
508 Object* feedback = GetFeedback();
509
510 if (feedback == *TypeFeedbackVector::UninitializedSentinel(isolate)) {
511 return UNINITIALIZED;
512 } else if (feedback == *TypeFeedbackVector::MegamorphicSentinel(isolate)) {
513 return MEGAMORPHIC;
514 } else if (feedback == *TypeFeedbackVector::PremonomorphicSentinel(isolate)) {
515 return PREMONOMORPHIC;
516 } else if (feedback->IsFixedArray()) {
517 // Determine state purely by our structure, don't check if the maps are
518 // cleared.
519 return POLYMORPHIC;
520 } else if (feedback->IsWeakCell()) {
521 // Don't check if the map is cleared.
522 return MONOMORPHIC;
523 }
524
525 return UNINITIALIZED;
526 }
527
StateFromFeedback() const528 InlineCacheState LoadGlobalICNexus::StateFromFeedback() const {
529 Isolate* isolate = GetIsolate();
530 Object* feedback = GetFeedback();
531
532 Object* extra = GetFeedbackExtra();
533 if (!WeakCell::cast(feedback)->cleared() ||
534 extra != *TypeFeedbackVector::UninitializedSentinel(isolate)) {
535 return MONOMORPHIC;
536 }
537 return UNINITIALIZED;
538 }
539
StateFromFeedback() const540 InlineCacheState KeyedLoadICNexus::StateFromFeedback() const {
541 Isolate* isolate = GetIsolate();
542 Object* feedback = GetFeedback();
543
544 if (feedback == *TypeFeedbackVector::UninitializedSentinel(isolate)) {
545 return UNINITIALIZED;
546 } else if (feedback == *TypeFeedbackVector::PremonomorphicSentinel(isolate)) {
547 return PREMONOMORPHIC;
548 } else if (feedback == *TypeFeedbackVector::MegamorphicSentinel(isolate)) {
549 return MEGAMORPHIC;
550 } else if (feedback->IsFixedArray()) {
551 // Determine state purely by our structure, don't check if the maps are
552 // cleared.
553 return POLYMORPHIC;
554 } else if (feedback->IsWeakCell()) {
555 // Don't check if the map is cleared.
556 return MONOMORPHIC;
557 } else if (feedback->IsName()) {
558 Object* extra = GetFeedbackExtra();
559 FixedArray* extra_array = FixedArray::cast(extra);
560 return extra_array->length() > 2 ? POLYMORPHIC : MONOMORPHIC;
561 }
562
563 return UNINITIALIZED;
564 }
565
566
StateFromFeedback() const567 InlineCacheState StoreICNexus::StateFromFeedback() const {
568 Isolate* isolate = GetIsolate();
569 Object* feedback = GetFeedback();
570
571 if (feedback == *TypeFeedbackVector::UninitializedSentinel(isolate)) {
572 return UNINITIALIZED;
573 } else if (feedback == *TypeFeedbackVector::MegamorphicSentinel(isolate)) {
574 return MEGAMORPHIC;
575 } else if (feedback == *TypeFeedbackVector::PremonomorphicSentinel(isolate)) {
576 return PREMONOMORPHIC;
577 } else if (feedback->IsFixedArray()) {
578 // Determine state purely by our structure, don't check if the maps are
579 // cleared.
580 return POLYMORPHIC;
581 } else if (feedback->IsWeakCell()) {
582 // Don't check if the map is cleared.
583 return MONOMORPHIC;
584 }
585
586 return UNINITIALIZED;
587 }
588
589
StateFromFeedback() const590 InlineCacheState KeyedStoreICNexus::StateFromFeedback() const {
591 Isolate* isolate = GetIsolate();
592 Object* feedback = GetFeedback();
593
594 if (feedback == *TypeFeedbackVector::UninitializedSentinel(isolate)) {
595 return UNINITIALIZED;
596 } else if (feedback == *TypeFeedbackVector::PremonomorphicSentinel(isolate)) {
597 return PREMONOMORPHIC;
598 } else if (feedback == *TypeFeedbackVector::MegamorphicSentinel(isolate)) {
599 return MEGAMORPHIC;
600 } else if (feedback->IsFixedArray()) {
601 // Determine state purely by our structure, don't check if the maps are
602 // cleared.
603 return POLYMORPHIC;
604 } else if (feedback->IsWeakCell()) {
605 // Don't check if the map is cleared.
606 return MONOMORPHIC;
607 } else if (feedback->IsName()) {
608 Object* extra = GetFeedbackExtra();
609 FixedArray* extra_array = FixedArray::cast(extra);
610 return extra_array->length() > 2 ? POLYMORPHIC : MONOMORPHIC;
611 }
612
613 return UNINITIALIZED;
614 }
615
616
StateFromFeedback() const617 InlineCacheState CallICNexus::StateFromFeedback() const {
618 Isolate* isolate = GetIsolate();
619 Object* feedback = GetFeedback();
620 DCHECK(GetFeedbackExtra() ==
621 *TypeFeedbackVector::UninitializedSentinel(isolate) ||
622 GetFeedbackExtra()->IsSmi());
623
624 if (feedback == *TypeFeedbackVector::MegamorphicSentinel(isolate)) {
625 return GENERIC;
626 } else if (feedback->IsAllocationSite() || feedback->IsWeakCell()) {
627 return MONOMORPHIC;
628 }
629
630 CHECK(feedback == *TypeFeedbackVector::UninitializedSentinel(isolate));
631 return UNINITIALIZED;
632 }
633
634
ExtractCallCount()635 int CallICNexus::ExtractCallCount() {
636 Object* call_count = GetFeedbackExtra();
637 if (call_count->IsSmi()) {
638 int value = Smi::cast(call_count)->value();
639 return value;
640 }
641 return -1;
642 }
643
644
Clear(Code * host)645 void CallICNexus::Clear(Code* host) { CallIC::Clear(GetIsolate(), host, this); }
646
647
ConfigureMonomorphicArray()648 void CallICNexus::ConfigureMonomorphicArray() {
649 Object* feedback = GetFeedback();
650 if (!feedback->IsAllocationSite()) {
651 Handle<AllocationSite> new_site =
652 GetIsolate()->factory()->NewAllocationSite();
653 SetFeedback(*new_site);
654 }
655 SetFeedbackExtra(Smi::FromInt(1), SKIP_WRITE_BARRIER);
656 }
657
658
ConfigureMonomorphic(Handle<JSFunction> function)659 void CallICNexus::ConfigureMonomorphic(Handle<JSFunction> function) {
660 Handle<WeakCell> new_cell = GetIsolate()->factory()->NewWeakCell(function);
661 SetFeedback(*new_cell);
662 SetFeedbackExtra(Smi::FromInt(1), SKIP_WRITE_BARRIER);
663 }
664
665
ConfigureMegamorphic()666 void CallICNexus::ConfigureMegamorphic() {
667 FeedbackNexus::ConfigureMegamorphic();
668 }
669
670
ConfigureMegamorphic(int call_count)671 void CallICNexus::ConfigureMegamorphic(int call_count) {
672 SetFeedback(*TypeFeedbackVector::MegamorphicSentinel(GetIsolate()),
673 SKIP_WRITE_BARRIER);
674 SetFeedbackExtra(Smi::FromInt(call_count), SKIP_WRITE_BARRIER);
675 }
676
677
ConfigureMonomorphic(Handle<Map> receiver_map,Handle<Code> handler)678 void LoadICNexus::ConfigureMonomorphic(Handle<Map> receiver_map,
679 Handle<Code> handler) {
680 Handle<WeakCell> cell = Map::WeakCellForMap(receiver_map);
681 SetFeedback(*cell);
682 SetFeedbackExtra(*handler);
683 }
684
ConfigureUninitialized()685 void LoadGlobalICNexus::ConfigureUninitialized() {
686 Isolate* isolate = GetIsolate();
687 SetFeedback(isolate->heap()->empty_weak_cell(), SKIP_WRITE_BARRIER);
688 SetFeedbackExtra(*TypeFeedbackVector::UninitializedSentinel(isolate),
689 SKIP_WRITE_BARRIER);
690 }
691
ConfigurePropertyCellMode(Handle<PropertyCell> cell)692 void LoadGlobalICNexus::ConfigurePropertyCellMode(Handle<PropertyCell> cell) {
693 Isolate* isolate = GetIsolate();
694 SetFeedback(*isolate->factory()->NewWeakCell(cell));
695 SetFeedbackExtra(*TypeFeedbackVector::UninitializedSentinel(isolate),
696 SKIP_WRITE_BARRIER);
697 }
698
ConfigureHandlerMode(Handle<Code> handler)699 void LoadGlobalICNexus::ConfigureHandlerMode(Handle<Code> handler) {
700 SetFeedback(GetIsolate()->heap()->empty_weak_cell());
701 SetFeedbackExtra(*handler);
702 }
703
ConfigureMonomorphic(Handle<Name> name,Handle<Map> receiver_map,Handle<Code> handler)704 void KeyedLoadICNexus::ConfigureMonomorphic(Handle<Name> name,
705 Handle<Map> receiver_map,
706 Handle<Code> handler) {
707 Handle<WeakCell> cell = Map::WeakCellForMap(receiver_map);
708 if (name.is_null()) {
709 SetFeedback(*cell);
710 SetFeedbackExtra(*handler);
711 } else {
712 Handle<FixedArray> array = EnsureExtraArrayOfSize(2);
713 SetFeedback(*name);
714 array->set(0, *cell);
715 array->set(1, *handler);
716 }
717 }
718
719
ConfigureMonomorphic(Handle<Map> receiver_map,Handle<Code> handler)720 void StoreICNexus::ConfigureMonomorphic(Handle<Map> receiver_map,
721 Handle<Code> handler) {
722 Handle<WeakCell> cell = Map::WeakCellForMap(receiver_map);
723 SetFeedback(*cell);
724 SetFeedbackExtra(*handler);
725 }
726
727
ConfigureMonomorphic(Handle<Name> name,Handle<Map> receiver_map,Handle<Code> handler)728 void KeyedStoreICNexus::ConfigureMonomorphic(Handle<Name> name,
729 Handle<Map> receiver_map,
730 Handle<Code> handler) {
731 Handle<WeakCell> cell = Map::WeakCellForMap(receiver_map);
732 if (name.is_null()) {
733 SetFeedback(*cell);
734 SetFeedbackExtra(*handler);
735 } else {
736 Handle<FixedArray> array = EnsureExtraArrayOfSize(2);
737 SetFeedback(*name);
738 array->set(0, *cell);
739 array->set(1, *handler);
740 }
741 }
742
743
ConfigurePolymorphic(MapHandleList * maps,CodeHandleList * handlers)744 void LoadICNexus::ConfigurePolymorphic(MapHandleList* maps,
745 CodeHandleList* handlers) {
746 Isolate* isolate = GetIsolate();
747 int receiver_count = maps->length();
748 Handle<FixedArray> array = EnsureArrayOfSize(receiver_count * 2);
749 InstallHandlers(array, maps, handlers);
750 SetFeedbackExtra(*TypeFeedbackVector::UninitializedSentinel(isolate),
751 SKIP_WRITE_BARRIER);
752 }
753
ConfigurePolymorphic(Handle<Name> name,MapHandleList * maps,CodeHandleList * handlers)754 void KeyedLoadICNexus::ConfigurePolymorphic(Handle<Name> name,
755 MapHandleList* maps,
756 CodeHandleList* handlers) {
757 int receiver_count = maps->length();
758 DCHECK(receiver_count > 1);
759 Handle<FixedArray> array;
760 if (name.is_null()) {
761 array = EnsureArrayOfSize(receiver_count * 2);
762 SetFeedbackExtra(*TypeFeedbackVector::UninitializedSentinel(GetIsolate()),
763 SKIP_WRITE_BARRIER);
764 } else {
765 array = EnsureExtraArrayOfSize(receiver_count * 2);
766 SetFeedback(*name);
767 }
768
769 InstallHandlers(array, maps, handlers);
770 }
771
772
ConfigurePolymorphic(MapHandleList * maps,CodeHandleList * handlers)773 void StoreICNexus::ConfigurePolymorphic(MapHandleList* maps,
774 CodeHandleList* handlers) {
775 Isolate* isolate = GetIsolate();
776 int receiver_count = maps->length();
777 Handle<FixedArray> array = EnsureArrayOfSize(receiver_count * 2);
778 InstallHandlers(array, maps, handlers);
779 SetFeedbackExtra(*TypeFeedbackVector::UninitializedSentinel(isolate),
780 SKIP_WRITE_BARRIER);
781 }
782
783
ConfigurePolymorphic(Handle<Name> name,MapHandleList * maps,CodeHandleList * handlers)784 void KeyedStoreICNexus::ConfigurePolymorphic(Handle<Name> name,
785 MapHandleList* maps,
786 CodeHandleList* handlers) {
787 int receiver_count = maps->length();
788 DCHECK(receiver_count > 1);
789 Handle<FixedArray> array;
790 if (name.is_null()) {
791 array = EnsureArrayOfSize(receiver_count * 2);
792 SetFeedbackExtra(*TypeFeedbackVector::UninitializedSentinel(GetIsolate()),
793 SKIP_WRITE_BARRIER);
794 } else {
795 array = EnsureExtraArrayOfSize(receiver_count * 2);
796 SetFeedback(*name);
797 }
798
799 InstallHandlers(array, maps, handlers);
800 }
801
802
ConfigurePolymorphic(MapHandleList * maps,MapHandleList * transitioned_maps,CodeHandleList * handlers)803 void KeyedStoreICNexus::ConfigurePolymorphic(MapHandleList* maps,
804 MapHandleList* transitioned_maps,
805 CodeHandleList* handlers) {
806 int receiver_count = maps->length();
807 DCHECK(receiver_count > 1);
808 Handle<FixedArray> array = EnsureArrayOfSize(receiver_count * 3);
809 SetFeedbackExtra(*TypeFeedbackVector::UninitializedSentinel(GetIsolate()),
810 SKIP_WRITE_BARRIER);
811
812 Handle<Oddball> undefined_value = GetIsolate()->factory()->undefined_value();
813 for (int i = 0; i < receiver_count; ++i) {
814 Handle<Map> map = maps->at(i);
815 Handle<WeakCell> cell = Map::WeakCellForMap(map);
816 array->set(i * 3, *cell);
817 if (!transitioned_maps->at(i).is_null()) {
818 Handle<Map> transitioned_map = transitioned_maps->at(i);
819 cell = Map::WeakCellForMap(transitioned_map);
820 array->set((i * 3) + 1, *cell);
821 } else {
822 array->set((i * 3) + 1, *undefined_value);
823 }
824 array->set((i * 3) + 2, *handlers->at(i));
825 }
826 }
827
828
ExtractMaps(MapHandleList * maps) const829 int FeedbackNexus::ExtractMaps(MapHandleList* maps) const {
830 Isolate* isolate = GetIsolate();
831 Object* feedback = GetFeedback();
832 bool is_named_feedback = IsPropertyNameFeedback(feedback);
833 if (feedback->IsFixedArray() || is_named_feedback) {
834 int found = 0;
835 if (is_named_feedback) {
836 feedback = GetFeedbackExtra();
837 }
838 FixedArray* array = FixedArray::cast(feedback);
839 // The array should be of the form
840 // [map, handler, map, handler, ...]
841 // or
842 // [map, map, handler, map, map, handler, ...]
843 DCHECK(array->length() >= 2);
844 int increment = array->get(1)->IsCode() ? 2 : 3;
845 for (int i = 0; i < array->length(); i += increment) {
846 DCHECK(array->get(i)->IsWeakCell());
847 WeakCell* cell = WeakCell::cast(array->get(i));
848 if (!cell->cleared()) {
849 Map* map = Map::cast(cell->value());
850 maps->Add(handle(map, isolate));
851 found++;
852 }
853 }
854 return found;
855 } else if (feedback->IsWeakCell()) {
856 WeakCell* cell = WeakCell::cast(feedback);
857 if (!cell->cleared()) {
858 Map* map = Map::cast(cell->value());
859 maps->Add(handle(map, isolate));
860 return 1;
861 }
862 }
863
864 return 0;
865 }
866
867
FindHandlerForMap(Handle<Map> map) const868 MaybeHandle<Code> FeedbackNexus::FindHandlerForMap(Handle<Map> map) const {
869 Object* feedback = GetFeedback();
870 bool is_named_feedback = IsPropertyNameFeedback(feedback);
871 if (feedback->IsFixedArray() || is_named_feedback) {
872 if (is_named_feedback) {
873 feedback = GetFeedbackExtra();
874 }
875 FixedArray* array = FixedArray::cast(feedback);
876 DCHECK(array->length() >= 2);
877 int increment = array->get(1)->IsCode() ? 2 : 3;
878 for (int i = 0; i < array->length(); i += increment) {
879 DCHECK(array->get(i)->IsWeakCell());
880 WeakCell* cell = WeakCell::cast(array->get(i));
881 if (!cell->cleared()) {
882 Map* array_map = Map::cast(cell->value());
883 if (array_map == *map) {
884 Code* code = Code::cast(array->get(i + increment - 1));
885 DCHECK(code->kind() == Code::HANDLER);
886 return handle(code);
887 }
888 }
889 }
890 } else if (feedback->IsWeakCell()) {
891 WeakCell* cell = WeakCell::cast(feedback);
892 if (!cell->cleared()) {
893 Map* cell_map = Map::cast(cell->value());
894 if (cell_map == *map) {
895 Code* code = Code::cast(GetFeedbackExtra());
896 DCHECK(code->kind() == Code::HANDLER);
897 return handle(code);
898 }
899 }
900 }
901
902 return MaybeHandle<Code>();
903 }
904
905
FindHandlers(CodeHandleList * code_list,int length) const906 bool FeedbackNexus::FindHandlers(CodeHandleList* code_list, int length) const {
907 Object* feedback = GetFeedback();
908 int count = 0;
909 bool is_named_feedback = IsPropertyNameFeedback(feedback);
910 if (feedback->IsFixedArray() || is_named_feedback) {
911 if (is_named_feedback) {
912 feedback = GetFeedbackExtra();
913 }
914 FixedArray* array = FixedArray::cast(feedback);
915 // The array should be of the form
916 // [map, handler, map, handler, ...]
917 // or
918 // [map, map, handler, map, map, handler, ...]
919 // Be sure to skip handlers whose maps have been cleared.
920 DCHECK(array->length() >= 2);
921 int increment = array->get(1)->IsCode() ? 2 : 3;
922 for (int i = 0; i < array->length(); i += increment) {
923 DCHECK(array->get(i)->IsWeakCell());
924 WeakCell* cell = WeakCell::cast(array->get(i));
925 if (!cell->cleared()) {
926 Code* code = Code::cast(array->get(i + increment - 1));
927 DCHECK(code->kind() == Code::HANDLER);
928 code_list->Add(handle(code));
929 count++;
930 }
931 }
932 } else if (feedback->IsWeakCell()) {
933 WeakCell* cell = WeakCell::cast(feedback);
934 if (!cell->cleared()) {
935 Code* code = Code::cast(GetFeedbackExtra());
936 DCHECK(code->kind() == Code::HANDLER);
937 code_list->Add(handle(code));
938 count++;
939 }
940 }
941 return count == length;
942 }
943
944
Clear(Code * host)945 void LoadICNexus::Clear(Code* host) { LoadIC::Clear(GetIsolate(), host, this); }
946
Clear(Code * host)947 void LoadGlobalICNexus::Clear(Code* host) {
948 LoadGlobalIC::Clear(GetIsolate(), host, this);
949 }
950
Clear(Code * host)951 void KeyedLoadICNexus::Clear(Code* host) {
952 KeyedLoadIC::Clear(GetIsolate(), host, this);
953 }
954
955
FindFirstName() const956 Name* KeyedLoadICNexus::FindFirstName() const {
957 Object* feedback = GetFeedback();
958 if (IsPropertyNameFeedback(feedback)) {
959 return Name::cast(feedback);
960 }
961 return NULL;
962 }
963
964
FindFirstName() const965 Name* KeyedStoreICNexus::FindFirstName() const {
966 Object* feedback = GetFeedback();
967 if (IsPropertyNameFeedback(feedback)) {
968 return Name::cast(feedback);
969 }
970 return NULL;
971 }
972
973
Clear(Code * host)974 void StoreICNexus::Clear(Code* host) {
975 StoreIC::Clear(GetIsolate(), host, this);
976 }
977
978
Clear(Code * host)979 void KeyedStoreICNexus::Clear(Code* host) {
980 KeyedStoreIC::Clear(GetIsolate(), host, this);
981 }
982
983
GetKeyedAccessStoreMode() const984 KeyedAccessStoreMode KeyedStoreICNexus::GetKeyedAccessStoreMode() const {
985 KeyedAccessStoreMode mode = STANDARD_STORE;
986 MapHandleList maps;
987 CodeHandleList handlers;
988
989 if (GetKeyType() == PROPERTY) return mode;
990
991 ExtractMaps(&maps);
992 FindHandlers(&handlers, maps.length());
993 for (int i = 0; i < handlers.length(); i++) {
994 // The first handler that isn't the slow handler will have the bits we need.
995 Handle<Code> handler = handlers.at(i);
996 CodeStub::Major major_key = CodeStub::MajorKeyFromKey(handler->stub_key());
997 uint32_t minor_key = CodeStub::MinorKeyFromKey(handler->stub_key());
998 CHECK(major_key == CodeStub::KeyedStoreSloppyArguments ||
999 major_key == CodeStub::StoreFastElement ||
1000 major_key == CodeStub::StoreElement ||
1001 major_key == CodeStub::ElementsTransitionAndStore ||
1002 major_key == CodeStub::NoCache);
1003 if (major_key != CodeStub::NoCache) {
1004 mode = CommonStoreModeBits::decode(minor_key);
1005 break;
1006 }
1007 }
1008
1009 return mode;
1010 }
1011
GetKeyType() const1012 IcCheckType KeyedLoadICNexus::GetKeyType() const {
1013 Object* feedback = GetFeedback();
1014 if (feedback == *TypeFeedbackVector::MegamorphicSentinel(GetIsolate())) {
1015 return static_cast<IcCheckType>(Smi::cast(GetFeedbackExtra())->value());
1016 }
1017 return IsPropertyNameFeedback(feedback) ? PROPERTY : ELEMENT;
1018 }
1019
GetKeyType() const1020 IcCheckType KeyedStoreICNexus::GetKeyType() const {
1021 Object* feedback = GetFeedback();
1022 if (feedback == *TypeFeedbackVector::MegamorphicSentinel(GetIsolate())) {
1023 return static_cast<IcCheckType>(Smi::cast(GetFeedbackExtra())->value());
1024 }
1025 return IsPropertyNameFeedback(feedback) ? PROPERTY : ELEMENT;
1026 }
1027 } // namespace internal
1028 } // namespace v8
1029