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   return feedback->IsString() ||
19          (feedback->IsSymbol() && !Symbol::cast(feedback)->is_private());
20 }
21 
22 
operator <<(std::ostream & os,FeedbackVectorSlotKind kind)23 std::ostream& operator<<(std::ostream& os, FeedbackVectorSlotKind kind) {
24   return os << TypeFeedbackMetadata::Kind2String(kind);
25 }
26 
27 
GetKind(FeedbackVectorSlot slot) const28 FeedbackVectorSlotKind TypeFeedbackMetadata::GetKind(
29     FeedbackVectorSlot 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 
35 
SetKind(FeedbackVectorSlot slot,FeedbackVectorSlotKind kind)36 void TypeFeedbackMetadata::SetKind(FeedbackVectorSlot slot,
37                                    FeedbackVectorSlotKind kind) {
38   int index = VectorICComputer::index(kReservedIndexCount, slot.ToInt());
39   int data = Smi::cast(get(index))->value();
40   int new_data = VectorICComputer::encode(data, slot.ToInt(), kind);
41   set(index, Smi::FromInt(new_data));
42 }
43 
44 
45 template Handle<TypeFeedbackMetadata> TypeFeedbackMetadata::New(
46     Isolate* isolate, const StaticFeedbackVectorSpec* spec);
47 template Handle<TypeFeedbackMetadata> TypeFeedbackMetadata::New(
48     Isolate* isolate, const FeedbackVectorSpec* spec);
49 
50 
51 // static
52 template <typename Spec>
New(Isolate * isolate,const Spec * spec)53 Handle<TypeFeedbackMetadata> TypeFeedbackMetadata::New(Isolate* isolate,
54                                                        const Spec* spec) {
55   const int slot_count = spec->slots();
56   const int slot_kinds_length = VectorICComputer::word_count(slot_count);
57   const int length = slot_kinds_length + kReservedIndexCount;
58   if (length == kReservedIndexCount) {
59     return Handle<TypeFeedbackMetadata>::cast(
60         isolate->factory()->empty_fixed_array());
61   }
62 #ifdef DEBUG
63   for (int i = 0; i < slot_count;) {
64     FeedbackVectorSlotKind kind = spec->GetKind(i);
65     int entry_size = TypeFeedbackMetadata::GetSlotSize(kind);
66     for (int j = 1; j < entry_size; j++) {
67       FeedbackVectorSlotKind kind = spec->GetKind(i + j);
68       DCHECK_EQ(FeedbackVectorSlotKind::INVALID, kind);
69     }
70     i += entry_size;
71   }
72 #endif
73 
74   Handle<FixedArray> array = isolate->factory()->NewFixedArray(length, TENURED);
75   array->set(kSlotsCountIndex, Smi::FromInt(slot_count));
76   // Fill the bit-vector part with zeros.
77   for (int i = 0; i < slot_kinds_length; i++) {
78     array->set(kReservedIndexCount + i, Smi::FromInt(0));
79   }
80 
81   Handle<TypeFeedbackMetadata> metadata =
82       Handle<TypeFeedbackMetadata>::cast(array);
83   for (int i = 0; i < slot_count; i++) {
84     metadata->SetKind(FeedbackVectorSlot(i), spec->GetKind(i));
85   }
86   return metadata;
87 }
88 
89 
SpecDiffersFrom(const FeedbackVectorSpec * other_spec) const90 bool TypeFeedbackMetadata::SpecDiffersFrom(
91     const FeedbackVectorSpec* other_spec) const {
92   if (other_spec->slots() != slot_count()) {
93     return true;
94   }
95 
96   int slots = slot_count();
97   for (int i = 0; i < slots; i++) {
98     if (GetKind(FeedbackVectorSlot(i)) != other_spec->GetKind(i)) {
99       return true;
100     }
101   }
102   return false;
103 }
104 
105 
Kind2String(FeedbackVectorSlotKind kind)106 const char* TypeFeedbackMetadata::Kind2String(FeedbackVectorSlotKind kind) {
107   switch (kind) {
108     case FeedbackVectorSlotKind::INVALID:
109       return "INVALID";
110     case FeedbackVectorSlotKind::CALL_IC:
111       return "CALL_IC";
112     case FeedbackVectorSlotKind::LOAD_IC:
113       return "LOAD_IC";
114     case FeedbackVectorSlotKind::KEYED_LOAD_IC:
115       return "KEYED_LOAD_IC";
116     case FeedbackVectorSlotKind::STORE_IC:
117       return "STORE_IC";
118     case FeedbackVectorSlotKind::KEYED_STORE_IC:
119       return "KEYED_STORE_IC";
120     case FeedbackVectorSlotKind::GENERAL:
121       return "STUB";
122     case FeedbackVectorSlotKind::KINDS_NUMBER:
123       break;
124   }
125   UNREACHABLE();
126   return "?";
127 }
128 
129 
130 // static
New(Isolate * isolate,Handle<TypeFeedbackMetadata> metadata)131 Handle<TypeFeedbackVector> TypeFeedbackVector::New(
132     Isolate* isolate, Handle<TypeFeedbackMetadata> metadata) {
133   Factory* factory = isolate->factory();
134 
135   const int slot_count = metadata->slot_count();
136   const int length = slot_count + kReservedIndexCount;
137   if (length == kReservedIndexCount) {
138     return Handle<TypeFeedbackVector>::cast(factory->empty_fixed_array());
139   }
140 
141   Handle<FixedArray> array = factory->NewFixedArray(length, TENURED);
142   array->set(kMetadataIndex, *metadata);
143 
144   // Ensure we can skip the write barrier
145   Handle<Object> uninitialized_sentinel = UninitializedSentinel(isolate);
146   DCHECK_EQ(*factory->uninitialized_symbol(), *uninitialized_sentinel);
147   for (int i = kReservedIndexCount; i < length; i++) {
148     array->set(i, *uninitialized_sentinel, SKIP_WRITE_BARRIER);
149   }
150 
151   return Handle<TypeFeedbackVector>::cast(array);
152 }
153 
154 
155 // static
GetIndexFromSpec(const FeedbackVectorSpec * spec,FeedbackVectorSlot slot)156 int TypeFeedbackVector::GetIndexFromSpec(const FeedbackVectorSpec* spec,
157                                          FeedbackVectorSlot slot) {
158   return kReservedIndexCount + slot.ToInt();
159 }
160 
161 
162 // static
Copy(Isolate * isolate,Handle<TypeFeedbackVector> vector)163 Handle<TypeFeedbackVector> TypeFeedbackVector::Copy(
164     Isolate* isolate, Handle<TypeFeedbackVector> vector) {
165   Handle<TypeFeedbackVector> result;
166   result = Handle<TypeFeedbackVector>::cast(
167       isolate->factory()->CopyFixedArray(Handle<FixedArray>::cast(vector)));
168   return result;
169 }
170 
171 
172 // This logic is copied from
173 // StaticMarkingVisitor<StaticVisitor>::VisitCodeTarget.
ClearLogic(Isolate * isolate)174 static bool ClearLogic(Isolate* isolate) {
175   return FLAG_cleanup_code_caches_at_gc && isolate->serializer_enabled();
176 }
177 
178 
ClearSlotsImpl(SharedFunctionInfo * shared,bool force_clear)179 void TypeFeedbackVector::ClearSlotsImpl(SharedFunctionInfo* shared,
180                                         bool force_clear) {
181   Isolate* isolate = GetIsolate();
182 
183   if (!force_clear && !ClearLogic(isolate)) return;
184 
185   Object* uninitialized_sentinel =
186       TypeFeedbackVector::RawUninitializedSentinel(isolate);
187 
188   TypeFeedbackMetadataIterator iter(metadata());
189   while (iter.HasNext()) {
190     FeedbackVectorSlot slot = iter.Next();
191     FeedbackVectorSlotKind kind = iter.kind();
192 
193     Object* obj = Get(slot);
194     if (obj != uninitialized_sentinel) {
195       switch (kind) {
196         case FeedbackVectorSlotKind::CALL_IC: {
197           CallICNexus nexus(this, slot);
198           nexus.Clear(shared->code());
199           break;
200         }
201         case FeedbackVectorSlotKind::LOAD_IC: {
202           LoadICNexus nexus(this, slot);
203           nexus.Clear(shared->code());
204           break;
205         }
206         case FeedbackVectorSlotKind::KEYED_LOAD_IC: {
207           KeyedLoadICNexus nexus(this, slot);
208           nexus.Clear(shared->code());
209           break;
210         }
211         case FeedbackVectorSlotKind::STORE_IC: {
212           StoreICNexus nexus(this, slot);
213           nexus.Clear(shared->code());
214           break;
215         }
216         case FeedbackVectorSlotKind::KEYED_STORE_IC: {
217           KeyedStoreICNexus nexus(this, slot);
218           nexus.Clear(shared->code());
219           break;
220         }
221         case FeedbackVectorSlotKind::GENERAL: {
222           if (obj->IsHeapObject()) {
223             InstanceType instance_type =
224                 HeapObject::cast(obj)->map()->instance_type();
225             // AllocationSites are exempt from clearing. They don't store Maps
226             // or Code pointers which can cause memory leaks if not cleared
227             // regularly.
228             if (instance_type != ALLOCATION_SITE_TYPE) {
229               Set(slot, uninitialized_sentinel, SKIP_WRITE_BARRIER);
230             }
231           }
232           break;
233         }
234         case FeedbackVectorSlotKind::INVALID:
235         case FeedbackVectorSlotKind::KINDS_NUMBER:
236           UNREACHABLE();
237           break;
238       }
239     }
240   }
241 }
242 
243 
244 // static
ClearAllKeyedStoreICs(Isolate * isolate)245 void TypeFeedbackVector::ClearAllKeyedStoreICs(Isolate* isolate) {
246   SharedFunctionInfo::Iterator iterator(isolate);
247   SharedFunctionInfo* shared;
248   while ((shared = iterator.Next())) {
249     TypeFeedbackVector* vector = shared->feedback_vector();
250     vector->ClearKeyedStoreICs(shared);
251   }
252 }
253 
254 
ClearKeyedStoreICs(SharedFunctionInfo * shared)255 void TypeFeedbackVector::ClearKeyedStoreICs(SharedFunctionInfo* shared) {
256   Isolate* isolate = GetIsolate();
257 
258   Code* host = shared->code();
259   Object* uninitialized_sentinel =
260       TypeFeedbackVector::RawUninitializedSentinel(isolate);
261 
262   TypeFeedbackMetadataIterator iter(metadata());
263   while (iter.HasNext()) {
264     FeedbackVectorSlot slot = iter.Next();
265     FeedbackVectorSlotKind kind = iter.kind();
266     if (kind != FeedbackVectorSlotKind::KEYED_STORE_IC) continue;
267     Object* obj = Get(slot);
268     if (obj != uninitialized_sentinel) {
269       KeyedStoreICNexus nexus(this, slot);
270       nexus.Clear(host);
271     }
272   }
273 }
274 
275 
276 // static
DummyVector(Isolate * isolate)277 Handle<TypeFeedbackVector> TypeFeedbackVector::DummyVector(Isolate* isolate) {
278   return isolate->factory()->dummy_vector();
279 }
280 
281 
EnsureArrayOfSize(int length)282 Handle<FixedArray> FeedbackNexus::EnsureArrayOfSize(int length) {
283   Isolate* isolate = GetIsolate();
284   Handle<Object> feedback = handle(GetFeedback(), isolate);
285   if (!feedback->IsFixedArray() ||
286       FixedArray::cast(*feedback)->length() != length) {
287     Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
288     SetFeedback(*array);
289     return array;
290   }
291   return Handle<FixedArray>::cast(feedback);
292 }
293 
294 
EnsureExtraArrayOfSize(int length)295 Handle<FixedArray> FeedbackNexus::EnsureExtraArrayOfSize(int length) {
296   Isolate* isolate = GetIsolate();
297   Handle<Object> feedback_extra = handle(GetFeedbackExtra(), isolate);
298   if (!feedback_extra->IsFixedArray() ||
299       FixedArray::cast(*feedback_extra)->length() != length) {
300     Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
301     SetFeedbackExtra(*array);
302     return array;
303   }
304   return Handle<FixedArray>::cast(feedback_extra);
305 }
306 
307 
InstallHandlers(Handle<FixedArray> array,MapHandleList * maps,CodeHandleList * handlers)308 void FeedbackNexus::InstallHandlers(Handle<FixedArray> array,
309                                     MapHandleList* maps,
310                                     CodeHandleList* handlers) {
311   int receiver_count = maps->length();
312   for (int current = 0; current < receiver_count; ++current) {
313     Handle<Map> map = maps->at(current);
314     Handle<WeakCell> cell = Map::WeakCellForMap(map);
315     array->set(current * 2, *cell);
316     array->set(current * 2 + 1, *handlers->at(current));
317   }
318 }
319 
320 
ConfigureUninitialized()321 void FeedbackNexus::ConfigureUninitialized() {
322   SetFeedback(*TypeFeedbackVector::UninitializedSentinel(GetIsolate()),
323               SKIP_WRITE_BARRIER);
324   SetFeedbackExtra(*TypeFeedbackVector::UninitializedSentinel(GetIsolate()),
325                    SKIP_WRITE_BARRIER);
326 }
327 
328 
ConfigurePremonomorphic()329 void FeedbackNexus::ConfigurePremonomorphic() {
330   SetFeedback(*TypeFeedbackVector::PremonomorphicSentinel(GetIsolate()),
331               SKIP_WRITE_BARRIER);
332   SetFeedbackExtra(*TypeFeedbackVector::UninitializedSentinel(GetIsolate()),
333                    SKIP_WRITE_BARRIER);
334 }
335 
336 
ConfigureMegamorphic()337 void FeedbackNexus::ConfigureMegamorphic() {
338   Isolate* isolate = GetIsolate();
339   SetFeedback(*TypeFeedbackVector::MegamorphicSentinel(isolate),
340               SKIP_WRITE_BARRIER);
341   SetFeedbackExtra(*TypeFeedbackVector::UninitializedSentinel(isolate),
342                    SKIP_WRITE_BARRIER);
343 }
344 
345 
StateFromFeedback() const346 InlineCacheState LoadICNexus::StateFromFeedback() const {
347   Isolate* isolate = GetIsolate();
348   Object* feedback = GetFeedback();
349 
350   if (feedback == *TypeFeedbackVector::UninitializedSentinel(isolate)) {
351     return UNINITIALIZED;
352   } else if (feedback == *TypeFeedbackVector::MegamorphicSentinel(isolate)) {
353     return MEGAMORPHIC;
354   } else if (feedback == *TypeFeedbackVector::PremonomorphicSentinel(isolate)) {
355     return PREMONOMORPHIC;
356   } else if (feedback->IsFixedArray()) {
357     // Determine state purely by our structure, don't check if the maps are
358     // cleared.
359     return POLYMORPHIC;
360   } else if (feedback->IsWeakCell()) {
361     // Don't check if the map is cleared.
362     return MONOMORPHIC;
363   }
364 
365   return UNINITIALIZED;
366 }
367 
368 
StateFromFeedback() const369 InlineCacheState KeyedLoadICNexus::StateFromFeedback() const {
370   Isolate* isolate = GetIsolate();
371   Object* feedback = GetFeedback();
372 
373   if (feedback == *TypeFeedbackVector::UninitializedSentinel(isolate)) {
374     return UNINITIALIZED;
375   } else if (feedback == *TypeFeedbackVector::PremonomorphicSentinel(isolate)) {
376     return PREMONOMORPHIC;
377   } else if (feedback == *TypeFeedbackVector::MegamorphicSentinel(isolate)) {
378     return MEGAMORPHIC;
379   } else if (feedback->IsFixedArray()) {
380     // Determine state purely by our structure, don't check if the maps are
381     // cleared.
382     return POLYMORPHIC;
383   } else if (feedback->IsWeakCell()) {
384     // Don't check if the map is cleared.
385     return MONOMORPHIC;
386   } else if (feedback->IsName()) {
387     Object* extra = GetFeedbackExtra();
388     FixedArray* extra_array = FixedArray::cast(extra);
389     return extra_array->length() > 2 ? POLYMORPHIC : MONOMORPHIC;
390   }
391 
392   return UNINITIALIZED;
393 }
394 
395 
StateFromFeedback() const396 InlineCacheState StoreICNexus::StateFromFeedback() const {
397   Isolate* isolate = GetIsolate();
398   Object* feedback = GetFeedback();
399 
400   if (feedback == *TypeFeedbackVector::UninitializedSentinel(isolate)) {
401     return UNINITIALIZED;
402   } else if (feedback == *TypeFeedbackVector::MegamorphicSentinel(isolate)) {
403     return MEGAMORPHIC;
404   } else if (feedback == *TypeFeedbackVector::PremonomorphicSentinel(isolate)) {
405     return PREMONOMORPHIC;
406   } else if (feedback->IsFixedArray()) {
407     // Determine state purely by our structure, don't check if the maps are
408     // cleared.
409     return POLYMORPHIC;
410   } else if (feedback->IsWeakCell()) {
411     // Don't check if the map is cleared.
412     return MONOMORPHIC;
413   }
414 
415   return UNINITIALIZED;
416 }
417 
418 
StateFromFeedback() const419 InlineCacheState KeyedStoreICNexus::StateFromFeedback() const {
420   Isolate* isolate = GetIsolate();
421   Object* feedback = GetFeedback();
422 
423   if (feedback == *TypeFeedbackVector::UninitializedSentinel(isolate)) {
424     return UNINITIALIZED;
425   } else if (feedback == *TypeFeedbackVector::PremonomorphicSentinel(isolate)) {
426     return PREMONOMORPHIC;
427   } else if (feedback == *TypeFeedbackVector::MegamorphicSentinel(isolate)) {
428     return MEGAMORPHIC;
429   } else if (feedback->IsFixedArray()) {
430     // Determine state purely by our structure, don't check if the maps are
431     // cleared.
432     return POLYMORPHIC;
433   } else if (feedback->IsWeakCell()) {
434     // Don't check if the map is cleared.
435     return MONOMORPHIC;
436   } else if (feedback->IsName()) {
437     Object* extra = GetFeedbackExtra();
438     FixedArray* extra_array = FixedArray::cast(extra);
439     return extra_array->length() > 2 ? POLYMORPHIC : MONOMORPHIC;
440   }
441 
442   return UNINITIALIZED;
443 }
444 
445 
StateFromFeedback() const446 InlineCacheState CallICNexus::StateFromFeedback() const {
447   Isolate* isolate = GetIsolate();
448   Object* feedback = GetFeedback();
449   DCHECK(GetFeedbackExtra() ==
450              *TypeFeedbackVector::UninitializedSentinel(isolate) ||
451          GetFeedbackExtra()->IsSmi());
452 
453   if (feedback == *TypeFeedbackVector::MegamorphicSentinel(isolate)) {
454     return GENERIC;
455   } else if (feedback->IsAllocationSite() || feedback->IsWeakCell()) {
456     return MONOMORPHIC;
457   }
458 
459   CHECK(feedback == *TypeFeedbackVector::UninitializedSentinel(isolate));
460   return UNINITIALIZED;
461 }
462 
463 
ExtractCallCount()464 int CallICNexus::ExtractCallCount() {
465   Object* call_count = GetFeedbackExtra();
466   if (call_count->IsSmi()) {
467     int value = Smi::cast(call_count)->value() / 2;
468     return value;
469   }
470   return -1;
471 }
472 
473 
Clear(Code * host)474 void CallICNexus::Clear(Code* host) { CallIC::Clear(GetIsolate(), host, this); }
475 
476 
ConfigureMonomorphicArray()477 void CallICNexus::ConfigureMonomorphicArray() {
478   Object* feedback = GetFeedback();
479   if (!feedback->IsAllocationSite()) {
480     Handle<AllocationSite> new_site =
481         GetIsolate()->factory()->NewAllocationSite();
482     SetFeedback(*new_site);
483   }
484   SetFeedbackExtra(Smi::FromInt(kCallCountIncrement), SKIP_WRITE_BARRIER);
485 }
486 
487 
ConfigureMonomorphic(Handle<JSFunction> function)488 void CallICNexus::ConfigureMonomorphic(Handle<JSFunction> function) {
489   Handle<WeakCell> new_cell = GetIsolate()->factory()->NewWeakCell(function);
490   SetFeedback(*new_cell);
491   SetFeedbackExtra(Smi::FromInt(kCallCountIncrement), SKIP_WRITE_BARRIER);
492 }
493 
494 
ConfigureMegamorphic()495 void CallICNexus::ConfigureMegamorphic() {
496   FeedbackNexus::ConfigureMegamorphic();
497 }
498 
499 
ConfigureMegamorphic(int call_count)500 void CallICNexus::ConfigureMegamorphic(int call_count) {
501   SetFeedback(*TypeFeedbackVector::MegamorphicSentinel(GetIsolate()),
502               SKIP_WRITE_BARRIER);
503   SetFeedbackExtra(Smi::FromInt(call_count * kCallCountIncrement),
504                    SKIP_WRITE_BARRIER);
505 }
506 
507 
ConfigureMonomorphic(Handle<Map> receiver_map,Handle<Code> handler)508 void LoadICNexus::ConfigureMonomorphic(Handle<Map> receiver_map,
509                                        Handle<Code> handler) {
510   Handle<WeakCell> cell = Map::WeakCellForMap(receiver_map);
511   SetFeedback(*cell);
512   SetFeedbackExtra(*handler);
513 }
514 
515 
ConfigureMonomorphic(Handle<Name> name,Handle<Map> receiver_map,Handle<Code> handler)516 void KeyedLoadICNexus::ConfigureMonomorphic(Handle<Name> name,
517                                             Handle<Map> receiver_map,
518                                             Handle<Code> handler) {
519   Handle<WeakCell> cell = Map::WeakCellForMap(receiver_map);
520   if (name.is_null()) {
521     SetFeedback(*cell);
522     SetFeedbackExtra(*handler);
523   } else {
524     Handle<FixedArray> array = EnsureExtraArrayOfSize(2);
525     SetFeedback(*name);
526     array->set(0, *cell);
527     array->set(1, *handler);
528   }
529 }
530 
531 
ConfigureMonomorphic(Handle<Map> receiver_map,Handle<Code> handler)532 void StoreICNexus::ConfigureMonomorphic(Handle<Map> receiver_map,
533                                         Handle<Code> handler) {
534   Handle<WeakCell> cell = Map::WeakCellForMap(receiver_map);
535   SetFeedback(*cell);
536   SetFeedbackExtra(*handler);
537 }
538 
539 
ConfigureMonomorphic(Handle<Name> name,Handle<Map> receiver_map,Handle<Code> handler)540 void KeyedStoreICNexus::ConfigureMonomorphic(Handle<Name> name,
541                                              Handle<Map> receiver_map,
542                                              Handle<Code> handler) {
543   Handle<WeakCell> cell = Map::WeakCellForMap(receiver_map);
544   if (name.is_null()) {
545     SetFeedback(*cell);
546     SetFeedbackExtra(*handler);
547   } else {
548     Handle<FixedArray> array = EnsureExtraArrayOfSize(2);
549     SetFeedback(*name);
550     array->set(0, *cell);
551     array->set(1, *handler);
552   }
553 }
554 
555 
ConfigurePolymorphic(MapHandleList * maps,CodeHandleList * handlers)556 void LoadICNexus::ConfigurePolymorphic(MapHandleList* maps,
557                                        CodeHandleList* handlers) {
558   Isolate* isolate = GetIsolate();
559   int receiver_count = maps->length();
560   Handle<FixedArray> array = EnsureArrayOfSize(receiver_count * 2);
561   InstallHandlers(array, maps, handlers);
562   SetFeedbackExtra(*TypeFeedbackVector::UninitializedSentinel(isolate),
563                    SKIP_WRITE_BARRIER);
564 }
565 
566 
ConfigurePolymorphic(Handle<Name> name,MapHandleList * maps,CodeHandleList * handlers)567 void KeyedLoadICNexus::ConfigurePolymorphic(Handle<Name> name,
568                                             MapHandleList* maps,
569                                             CodeHandleList* handlers) {
570   int receiver_count = maps->length();
571   DCHECK(receiver_count > 1);
572   Handle<FixedArray> array;
573   if (name.is_null()) {
574     array = EnsureArrayOfSize(receiver_count * 2);
575     SetFeedbackExtra(*TypeFeedbackVector::UninitializedSentinel(GetIsolate()),
576                      SKIP_WRITE_BARRIER);
577   } else {
578     array = EnsureExtraArrayOfSize(receiver_count * 2);
579     SetFeedback(*name);
580   }
581 
582   InstallHandlers(array, maps, handlers);
583 }
584 
585 
ConfigurePolymorphic(MapHandleList * maps,CodeHandleList * handlers)586 void StoreICNexus::ConfigurePolymorphic(MapHandleList* maps,
587                                         CodeHandleList* handlers) {
588   Isolate* isolate = GetIsolate();
589   int receiver_count = maps->length();
590   Handle<FixedArray> array = EnsureArrayOfSize(receiver_count * 2);
591   InstallHandlers(array, maps, handlers);
592   SetFeedbackExtra(*TypeFeedbackVector::UninitializedSentinel(isolate),
593                    SKIP_WRITE_BARRIER);
594 }
595 
596 
ConfigurePolymorphic(Handle<Name> name,MapHandleList * maps,CodeHandleList * handlers)597 void KeyedStoreICNexus::ConfigurePolymorphic(Handle<Name> name,
598                                              MapHandleList* maps,
599                                              CodeHandleList* handlers) {
600   int receiver_count = maps->length();
601   DCHECK(receiver_count > 1);
602   Handle<FixedArray> array;
603   if (name.is_null()) {
604     array = EnsureArrayOfSize(receiver_count * 2);
605     SetFeedbackExtra(*TypeFeedbackVector::UninitializedSentinel(GetIsolate()),
606                      SKIP_WRITE_BARRIER);
607   } else {
608     array = EnsureExtraArrayOfSize(receiver_count * 2);
609     SetFeedback(*name);
610   }
611 
612   InstallHandlers(array, maps, handlers);
613 }
614 
615 
ConfigurePolymorphic(MapHandleList * maps,MapHandleList * transitioned_maps,CodeHandleList * handlers)616 void KeyedStoreICNexus::ConfigurePolymorphic(MapHandleList* maps,
617                                              MapHandleList* transitioned_maps,
618                                              CodeHandleList* handlers) {
619   int receiver_count = maps->length();
620   DCHECK(receiver_count > 1);
621   Handle<FixedArray> array = EnsureArrayOfSize(receiver_count * 3);
622   SetFeedbackExtra(*TypeFeedbackVector::UninitializedSentinel(GetIsolate()),
623                    SKIP_WRITE_BARRIER);
624 
625   Handle<Oddball> undefined_value = GetIsolate()->factory()->undefined_value();
626   for (int i = 0; i < receiver_count; ++i) {
627     Handle<Map> map = maps->at(i);
628     Handle<WeakCell> cell = Map::WeakCellForMap(map);
629     array->set(i * 3, *cell);
630     if (!transitioned_maps->at(i).is_null()) {
631       Handle<Map> transitioned_map = transitioned_maps->at(i);
632       cell = Map::WeakCellForMap(transitioned_map);
633       array->set((i * 3) + 1, *cell);
634     } else {
635       array->set((i * 3) + 1, *undefined_value);
636     }
637     array->set((i * 3) + 2, *handlers->at(i));
638   }
639 }
640 
641 
ExtractMaps(MapHandleList * maps) const642 int FeedbackNexus::ExtractMaps(MapHandleList* maps) const {
643   Isolate* isolate = GetIsolate();
644   Object* feedback = GetFeedback();
645   bool is_named_feedback = IsPropertyNameFeedback(feedback);
646   if (feedback->IsFixedArray() || is_named_feedback) {
647     int found = 0;
648     if (is_named_feedback) {
649       feedback = GetFeedbackExtra();
650     }
651     FixedArray* array = FixedArray::cast(feedback);
652     // The array should be of the form
653     // [map, handler, map, handler, ...]
654     // or
655     // [map, map, handler, map, map, handler, ...]
656     DCHECK(array->length() >= 2);
657     int increment = array->get(1)->IsCode() ? 2 : 3;
658     for (int i = 0; i < array->length(); i += increment) {
659       DCHECK(array->get(i)->IsWeakCell());
660       WeakCell* cell = WeakCell::cast(array->get(i));
661       if (!cell->cleared()) {
662         Map* map = Map::cast(cell->value());
663         maps->Add(handle(map, isolate));
664         found++;
665       }
666     }
667     return found;
668   } else if (feedback->IsWeakCell()) {
669     WeakCell* cell = WeakCell::cast(feedback);
670     if (!cell->cleared()) {
671       Map* map = Map::cast(cell->value());
672       maps->Add(handle(map, isolate));
673       return 1;
674     }
675   }
676 
677   return 0;
678 }
679 
680 
FindHandlerForMap(Handle<Map> map) const681 MaybeHandle<Code> FeedbackNexus::FindHandlerForMap(Handle<Map> map) const {
682   Object* feedback = GetFeedback();
683   bool is_named_feedback = IsPropertyNameFeedback(feedback);
684   if (feedback->IsFixedArray() || is_named_feedback) {
685     if (is_named_feedback) {
686       feedback = GetFeedbackExtra();
687     }
688     FixedArray* array = FixedArray::cast(feedback);
689     DCHECK(array->length() >= 2);
690     int increment = array->get(1)->IsCode() ? 2 : 3;
691     for (int i = 0; i < array->length(); i += increment) {
692       DCHECK(array->get(i)->IsWeakCell());
693       WeakCell* cell = WeakCell::cast(array->get(i));
694       if (!cell->cleared()) {
695         Map* array_map = Map::cast(cell->value());
696         if (array_map == *map) {
697           Code* code = Code::cast(array->get(i + increment - 1));
698           DCHECK(code->kind() == Code::HANDLER);
699           return handle(code);
700         }
701       }
702     }
703   } else if (feedback->IsWeakCell()) {
704     WeakCell* cell = WeakCell::cast(feedback);
705     if (!cell->cleared()) {
706       Map* cell_map = Map::cast(cell->value());
707       if (cell_map == *map) {
708         Code* code = Code::cast(GetFeedbackExtra());
709         DCHECK(code->kind() == Code::HANDLER);
710         return handle(code);
711       }
712     }
713   }
714 
715   return MaybeHandle<Code>();
716 }
717 
718 
FindHandlers(CodeHandleList * code_list,int length) const719 bool FeedbackNexus::FindHandlers(CodeHandleList* code_list, int length) const {
720   Object* feedback = GetFeedback();
721   int count = 0;
722   bool is_named_feedback = IsPropertyNameFeedback(feedback);
723   if (feedback->IsFixedArray() || is_named_feedback) {
724     if (is_named_feedback) {
725       feedback = GetFeedbackExtra();
726     }
727     FixedArray* array = FixedArray::cast(feedback);
728     // The array should be of the form
729     // [map, handler, map, handler, ...]
730     // or
731     // [map, map, handler, map, map, handler, ...]
732     // Be sure to skip handlers whose maps have been cleared.
733     DCHECK(array->length() >= 2);
734     int increment = array->get(1)->IsCode() ? 2 : 3;
735     for (int i = 0; i < array->length(); i += increment) {
736       DCHECK(array->get(i)->IsWeakCell());
737       WeakCell* cell = WeakCell::cast(array->get(i));
738       if (!cell->cleared()) {
739         Code* code = Code::cast(array->get(i + increment - 1));
740         DCHECK(code->kind() == Code::HANDLER);
741         code_list->Add(handle(code));
742         count++;
743       }
744     }
745   } else if (feedback->IsWeakCell()) {
746     WeakCell* cell = WeakCell::cast(feedback);
747     if (!cell->cleared()) {
748       Code* code = Code::cast(GetFeedbackExtra());
749       DCHECK(code->kind() == Code::HANDLER);
750       code_list->Add(handle(code));
751       count++;
752     }
753   }
754   return count == length;
755 }
756 
757 
Clear(Code * host)758 void LoadICNexus::Clear(Code* host) { LoadIC::Clear(GetIsolate(), host, this); }
759 
760 
Clear(Code * host)761 void KeyedLoadICNexus::Clear(Code* host) {
762   KeyedLoadIC::Clear(GetIsolate(), host, this);
763 }
764 
765 
FindFirstName() const766 Name* KeyedLoadICNexus::FindFirstName() const {
767   Object* feedback = GetFeedback();
768   if (IsPropertyNameFeedback(feedback)) {
769     return Name::cast(feedback);
770   }
771   return NULL;
772 }
773 
774 
FindFirstName() const775 Name* KeyedStoreICNexus::FindFirstName() const {
776   Object* feedback = GetFeedback();
777   if (IsPropertyNameFeedback(feedback)) {
778     return Name::cast(feedback);
779   }
780   return NULL;
781 }
782 
783 
Clear(Code * host)784 void StoreICNexus::Clear(Code* host) {
785   StoreIC::Clear(GetIsolate(), host, this);
786 }
787 
788 
Clear(Code * host)789 void KeyedStoreICNexus::Clear(Code* host) {
790   KeyedStoreIC::Clear(GetIsolate(), host, this);
791 }
792 
793 
GetKeyedAccessStoreMode() const794 KeyedAccessStoreMode KeyedStoreICNexus::GetKeyedAccessStoreMode() const {
795   KeyedAccessStoreMode mode = STANDARD_STORE;
796   MapHandleList maps;
797   CodeHandleList handlers;
798 
799   if (GetKeyType() == PROPERTY) return mode;
800 
801   ExtractMaps(&maps);
802   FindHandlers(&handlers, maps.length());
803   for (int i = 0; i < handlers.length(); i++) {
804     // The first handler that isn't the slow handler will have the bits we need.
805     Handle<Code> handler = handlers.at(i);
806     CodeStub::Major major_key = CodeStub::MajorKeyFromKey(handler->stub_key());
807     uint32_t minor_key = CodeStub::MinorKeyFromKey(handler->stub_key());
808     CHECK(major_key == CodeStub::KeyedStoreSloppyArguments ||
809           major_key == CodeStub::StoreFastElement ||
810           major_key == CodeStub::StoreElement ||
811           major_key == CodeStub::ElementsTransitionAndStore ||
812           major_key == CodeStub::NoCache);
813     if (major_key != CodeStub::NoCache) {
814       mode = CommonStoreModeBits::decode(minor_key);
815       break;
816     }
817   }
818 
819   return mode;
820 }
821 
822 
GetKeyType() const823 IcCheckType KeyedStoreICNexus::GetKeyType() const {
824   // The structure of the vector slots tells us the type.
825   return GetFeedback()->IsName() ? PROPERTY : ELEMENT;
826 }
827 }  // namespace internal
828 }  // namespace v8
829