• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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