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