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