Home | History | Annotate | Download | only in src
      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/objects.h"
     10 #include "src/objects/data-handler-inl.h"
     11 #include "src/objects/hash-table-inl.h"
     12 #include "src/objects/object-macros.h"
     13 
     14 namespace v8 {
     15 namespace internal {
     16 
     17 FeedbackSlot FeedbackVectorSpec::AddSlot(FeedbackSlotKind kind) {
     18   int slot = slots();
     19   int entries_per_slot = FeedbackMetadata::GetSlotSize(kind);
     20   append(kind);
     21   for (int i = 1; i < entries_per_slot; i++) {
     22     append(FeedbackSlotKind::kInvalid);
     23   }
     24   return FeedbackSlot(slot);
     25 }
     26 
     27 FeedbackSlot FeedbackVectorSpec::AddTypeProfileSlot() {
     28   FeedbackSlot slot = AddSlot(FeedbackSlotKind::kTypeProfile);
     29   CHECK_EQ(FeedbackVectorSpec::kTypeProfileSlotIndex,
     30            FeedbackVector::GetIndex(slot));
     31   return slot;
     32 }
     33 
     34 bool FeedbackVectorSpec::HasTypeProfileSlot() const {
     35   FeedbackSlot slot =
     36       FeedbackVector::ToSlot(FeedbackVectorSpec::kTypeProfileSlotIndex);
     37   if (slots() <= slot.ToInt()) {
     38     return false;
     39   }
     40   return GetKind(slot) == FeedbackSlotKind::kTypeProfile;
     41 }
     42 
     43 static bool IsPropertyNameFeedback(MaybeObject* feedback) {
     44   HeapObject* heap_object;
     45   if (!feedback->ToStrongHeapObject(&heap_object)) return false;
     46   if (heap_object->IsString()) return true;
     47   if (!heap_object->IsSymbol()) return false;
     48   Symbol* symbol = Symbol::cast(heap_object);
     49   ReadOnlyRoots roots = symbol->GetReadOnlyRoots();
     50   return symbol != roots.uninitialized_symbol() &&
     51          symbol != roots.premonomorphic_symbol() &&
     52          symbol != roots.megamorphic_symbol();
     53 }
     54 
     55 std::ostream& operator<<(std::ostream& os, FeedbackSlotKind kind) {
     56   return os << FeedbackMetadata::Kind2String(kind);
     57 }
     58 
     59 FeedbackSlotKind FeedbackMetadata::GetKind(FeedbackSlot slot) const {
     60   int index = VectorICComputer::index(0, slot.ToInt());
     61   int data = get(index);
     62   return VectorICComputer::decode(data, slot.ToInt());
     63 }
     64 
     65 void FeedbackMetadata::SetKind(FeedbackSlot slot, FeedbackSlotKind kind) {
     66   int index = VectorICComputer::index(0, slot.ToInt());
     67   int data = get(index);
     68   int new_data = VectorICComputer::encode(data, slot.ToInt(), kind);
     69   set(index, new_data);
     70 }
     71 
     72 // static
     73 Handle<FeedbackMetadata> FeedbackMetadata::New(Isolate* isolate,
     74                                                const FeedbackVectorSpec* spec) {
     75   Factory* factory = isolate->factory();
     76 
     77   const int slot_count = spec == nullptr ? 0 : spec->slots();
     78   if (slot_count == 0) {
     79     return factory->empty_feedback_metadata();
     80   }
     81 #ifdef DEBUG
     82   for (int i = 0; i < slot_count;) {
     83     DCHECK(spec);
     84     FeedbackSlotKind kind = spec->GetKind(FeedbackSlot(i));
     85     int entry_size = FeedbackMetadata::GetSlotSize(kind);
     86     for (int j = 1; j < entry_size; j++) {
     87       FeedbackSlotKind kind = spec->GetKind(FeedbackSlot(i + j));
     88       DCHECK_EQ(FeedbackSlotKind::kInvalid, kind);
     89     }
     90     i += entry_size;
     91   }
     92 #endif
     93 
     94   Handle<FeedbackMetadata> metadata = factory->NewFeedbackMetadata(slot_count);
     95 
     96   // Initialize the slots. The raw data section has already been pre-zeroed in
     97   // NewFeedbackMetadata.
     98   for (int i = 0; i < slot_count; i++) {
     99     DCHECK(spec);
    100     FeedbackSlot slot(i);
    101     FeedbackSlotKind kind = spec->GetKind(slot);
    102     metadata->SetKind(slot, kind);
    103   }
    104 
    105   return metadata;
    106 }
    107 
    108 bool FeedbackMetadata::SpecDiffersFrom(
    109     const FeedbackVectorSpec* other_spec) const {
    110   if (other_spec->slots() != slot_count()) {
    111     return true;
    112   }
    113 
    114   int slots = slot_count();
    115   for (int i = 0; i < slots;) {
    116     FeedbackSlot slot(i);
    117     FeedbackSlotKind kind = GetKind(slot);
    118     int entry_size = FeedbackMetadata::GetSlotSize(kind);
    119 
    120     if (kind != other_spec->GetKind(slot)) {
    121       return true;
    122     }
    123     i += entry_size;
    124   }
    125   return false;
    126 }
    127 
    128 const char* FeedbackMetadata::Kind2String(FeedbackSlotKind kind) {
    129   switch (kind) {
    130     case FeedbackSlotKind::kInvalid:
    131       return "Invalid";
    132     case FeedbackSlotKind::kCall:
    133       return "Call";
    134     case FeedbackSlotKind::kLoadProperty:
    135       return "LoadProperty";
    136     case FeedbackSlotKind::kLoadGlobalInsideTypeof:
    137       return "LoadGlobalInsideTypeof";
    138     case FeedbackSlotKind::kLoadGlobalNotInsideTypeof:
    139       return "LoadGlobalNotInsideTypeof";
    140     case FeedbackSlotKind::kLoadKeyed:
    141       return "LoadKeyed";
    142     case FeedbackSlotKind::kStoreNamedSloppy:
    143       return "StoreNamedSloppy";
    144     case FeedbackSlotKind::kStoreNamedStrict:
    145       return "StoreNamedStrict";
    146     case FeedbackSlotKind::kStoreOwnNamed:
    147       return "StoreOwnNamed";
    148     case FeedbackSlotKind::kStoreGlobalSloppy:
    149       return "StoreGlobalSloppy";
    150     case FeedbackSlotKind::kStoreGlobalStrict:
    151       return "StoreGlobalStrict";
    152     case FeedbackSlotKind::kStoreKeyedSloppy:
    153       return "StoreKeyedSloppy";
    154     case FeedbackSlotKind::kStoreKeyedStrict:
    155       return "StoreKeyedStrict";
    156     case FeedbackSlotKind::kStoreInArrayLiteral:
    157       return "StoreInArrayLiteral";
    158     case FeedbackSlotKind::kBinaryOp:
    159       return "BinaryOp";
    160     case FeedbackSlotKind::kCompareOp:
    161       return "CompareOp";
    162     case FeedbackSlotKind::kStoreDataPropertyInLiteral:
    163       return "StoreDataPropertyInLiteral";
    164     case FeedbackSlotKind::kCreateClosure:
    165       return "kCreateClosure";
    166     case FeedbackSlotKind::kLiteral:
    167       return "Literal";
    168     case FeedbackSlotKind::kTypeProfile:
    169       return "TypeProfile";
    170     case FeedbackSlotKind::kForIn:
    171       return "ForIn";
    172     case FeedbackSlotKind::kInstanceOf:
    173       return "InstanceOf";
    174     case FeedbackSlotKind::kCloneObject:
    175       return "CloneObject";
    176     case FeedbackSlotKind::kKindsNumber:
    177       break;
    178   }
    179   UNREACHABLE();
    180 }
    181 
    182 bool FeedbackMetadata::HasTypeProfileSlot() const {
    183   FeedbackSlot slot =
    184       FeedbackVector::ToSlot(FeedbackVectorSpec::kTypeProfileSlotIndex);
    185   return slot.ToInt() < slot_count() &&
    186          GetKind(slot) == FeedbackSlotKind::kTypeProfile;
    187 }
    188 
    189 FeedbackSlotKind FeedbackVector::GetKind(FeedbackSlot slot) const {
    190   DCHECK(!is_empty());
    191   return metadata()->GetKind(slot);
    192 }
    193 
    194 FeedbackSlot FeedbackVector::GetTypeProfileSlot() const {
    195   DCHECK(metadata()->HasTypeProfileSlot());
    196   FeedbackSlot slot =
    197       FeedbackVector::ToSlot(FeedbackVectorSpec::kTypeProfileSlotIndex);
    198   DCHECK_EQ(FeedbackSlotKind::kTypeProfile, GetKind(slot));
    199   return slot;
    200 }
    201 
    202 // static
    203 Handle<FeedbackVector> FeedbackVector::New(Isolate* isolate,
    204                                            Handle<SharedFunctionInfo> shared) {
    205   Factory* factory = isolate->factory();
    206 
    207   const int slot_count = shared->feedback_metadata()->slot_count();
    208 
    209   Handle<FeedbackVector> vector = factory->NewFeedbackVector(shared, TENURED);
    210 
    211   DCHECK_EQ(vector->length(), slot_count);
    212 
    213   DCHECK_EQ(vector->shared_function_info(), *shared);
    214   DCHECK_EQ(
    215       vector->optimized_code_weak_or_smi(),
    216       MaybeObject::FromSmi(Smi::FromEnum(
    217           FLAG_log_function_events ? OptimizationMarker::kLogFirstExecution
    218                                    : OptimizationMarker::kNone)));
    219   DCHECK_EQ(vector->invocation_count(), 0);
    220   DCHECK_EQ(vector->profiler_ticks(), 0);
    221   DCHECK_EQ(vector->deopt_count(), 0);
    222 
    223   // Ensure we can skip the write barrier
    224   Handle<Object> uninitialized_sentinel = UninitializedSentinel(isolate);
    225   DCHECK_EQ(ReadOnlyRoots(isolate).uninitialized_symbol(),
    226             *uninitialized_sentinel);
    227   Handle<Oddball> undefined_value = factory->undefined_value();
    228   for (int i = 0; i < slot_count;) {
    229     FeedbackSlot slot(i);
    230     FeedbackSlotKind kind = shared->feedback_metadata()->GetKind(slot);
    231     int index = FeedbackVector::GetIndex(slot);
    232     int entry_size = FeedbackMetadata::GetSlotSize(kind);
    233 
    234     Object* extra_value = *uninitialized_sentinel;
    235     switch (kind) {
    236       case FeedbackSlotKind::kLoadGlobalInsideTypeof:
    237       case FeedbackSlotKind::kLoadGlobalNotInsideTypeof:
    238       case FeedbackSlotKind::kStoreGlobalSloppy:
    239       case FeedbackSlotKind::kStoreGlobalStrict:
    240         vector->set(index, HeapObjectReference::ClearedValue(),
    241                     SKIP_WRITE_BARRIER);
    242         break;
    243       case FeedbackSlotKind::kForIn:
    244       case FeedbackSlotKind::kCompareOp:
    245       case FeedbackSlotKind::kBinaryOp:
    246         vector->set(index, Smi::kZero, SKIP_WRITE_BARRIER);
    247         break;
    248       case FeedbackSlotKind::kCreateClosure: {
    249         Handle<FeedbackCell> cell = factory->NewNoClosuresCell(undefined_value);
    250         vector->set(index, *cell);
    251         break;
    252       }
    253       case FeedbackSlotKind::kLiteral:
    254         vector->set(index, Smi::kZero, SKIP_WRITE_BARRIER);
    255         break;
    256       case FeedbackSlotKind::kCall:
    257         vector->set(index, *uninitialized_sentinel, SKIP_WRITE_BARRIER);
    258         extra_value = Smi::kZero;
    259         break;
    260       case FeedbackSlotKind::kCloneObject:
    261       case FeedbackSlotKind::kLoadProperty:
    262       case FeedbackSlotKind::kLoadKeyed:
    263       case FeedbackSlotKind::kStoreNamedSloppy:
    264       case FeedbackSlotKind::kStoreNamedStrict:
    265       case FeedbackSlotKind::kStoreOwnNamed:
    266       case FeedbackSlotKind::kStoreKeyedSloppy:
    267       case FeedbackSlotKind::kStoreKeyedStrict:
    268       case FeedbackSlotKind::kStoreInArrayLiteral:
    269       case FeedbackSlotKind::kStoreDataPropertyInLiteral:
    270       case FeedbackSlotKind::kTypeProfile:
    271       case FeedbackSlotKind::kInstanceOf:
    272         vector->set(index, *uninitialized_sentinel, SKIP_WRITE_BARRIER);
    273         break;
    274 
    275       case FeedbackSlotKind::kInvalid:
    276       case FeedbackSlotKind::kKindsNumber:
    277         UNREACHABLE();
    278         break;
    279     }
    280     for (int j = 1; j < entry_size; j++) {
    281       vector->set(index + j, extra_value, SKIP_WRITE_BARRIER);
    282     }
    283     i += entry_size;
    284   }
    285 
    286   Handle<FeedbackVector> result = Handle<FeedbackVector>::cast(vector);
    287   if (!isolate->is_best_effort_code_coverage() ||
    288       isolate->is_collecting_type_profile()) {
    289     AddToVectorsForProfilingTools(isolate, result);
    290   }
    291   return result;
    292 }
    293 
    294 // static
    295 void FeedbackVector::AddToVectorsForProfilingTools(
    296     Isolate* isolate, Handle<FeedbackVector> vector) {
    297   DCHECK(!isolate->is_best_effort_code_coverage() ||
    298          isolate->is_collecting_type_profile());
    299   if (!vector->shared_function_info()->IsSubjectToDebugging()) return;
    300   Handle<ArrayList> list = Handle<ArrayList>::cast(
    301       isolate->factory()->feedback_vectors_for_profiling_tools());
    302   list = ArrayList::Add(isolate, list, vector);
    303   isolate->SetFeedbackVectorsForProfilingTools(*list);
    304 }
    305 
    306 // static
    307 void FeedbackVector::SetOptimizedCode(Handle<FeedbackVector> vector,
    308                                       Handle<Code> code) {
    309   DCHECK_EQ(code->kind(), Code::OPTIMIZED_FUNCTION);
    310   vector->set_optimized_code_weak_or_smi(HeapObjectReference::Weak(*code));
    311 }
    312 
    313 void FeedbackVector::ClearOptimizedCode() {
    314   DCHECK(has_optimized_code());
    315   SetOptimizationMarker(OptimizationMarker::kNone);
    316 }
    317 
    318 void FeedbackVector::ClearOptimizationMarker() {
    319   DCHECK(!has_optimized_code());
    320   SetOptimizationMarker(OptimizationMarker::kNone);
    321 }
    322 
    323 void FeedbackVector::SetOptimizationMarker(OptimizationMarker marker) {
    324   set_optimized_code_weak_or_smi(MaybeObject::FromSmi(Smi::FromEnum(marker)));
    325 }
    326 
    327 void FeedbackVector::EvictOptimizedCodeMarkedForDeoptimization(
    328     SharedFunctionInfo* shared, const char* reason) {
    329   MaybeObject* slot = optimized_code_weak_or_smi();
    330   if (slot->IsSmi()) {
    331     return;
    332   }
    333 
    334   if (slot->IsClearedWeakHeapObject()) {
    335     ClearOptimizationMarker();
    336     return;
    337   }
    338 
    339   Code* code = Code::cast(slot->GetHeapObject());
    340   if (code->marked_for_deoptimization()) {
    341     if (FLAG_trace_deopt) {
    342       PrintF("[evicting optimizing code marked for deoptimization (%s) for ",
    343              reason);
    344       shared->ShortPrint();
    345       PrintF("]\n");
    346     }
    347     if (!code->deopt_already_counted()) {
    348       increment_deopt_count();
    349       code->set_deopt_already_counted(true);
    350     }
    351     ClearOptimizedCode();
    352   }
    353 }
    354 
    355 bool FeedbackVector::ClearSlots(Isolate* isolate) {
    356   MaybeObject* uninitialized_sentinel = MaybeObject::FromObject(
    357       FeedbackVector::RawUninitializedSentinel(isolate));
    358 
    359   bool feedback_updated = false;
    360   FeedbackMetadataIterator iter(metadata());
    361   while (iter.HasNext()) {
    362     FeedbackSlot slot = iter.Next();
    363 
    364     MaybeObject* obj = Get(slot);
    365     if (obj != uninitialized_sentinel) {
    366       FeedbackNexus nexus(this, slot);
    367       feedback_updated |= nexus.Clear();
    368     }
    369   }
    370   return feedback_updated;
    371 }
    372 
    373 void FeedbackVector::AssertNoLegacyTypes(MaybeObject* object) {
    374 #ifdef DEBUG
    375   HeapObject* heap_object;
    376   if (object->ToStrongOrWeakHeapObject(&heap_object)) {
    377     // Instead of FixedArray, the Feedback and the Extra should contain
    378     // WeakFixedArrays. The only allowed FixedArray subtype is HashTable.
    379     DCHECK_IMPLIES(heap_object->IsFixedArray(), heap_object->IsHashTable());
    380   }
    381 #endif
    382 }
    383 
    384 Handle<WeakFixedArray> FeedbackNexus::EnsureArrayOfSize(int length) {
    385   Isolate* isolate = GetIsolate();
    386   HeapObject* heap_object;
    387   if (GetFeedback()->ToStrongHeapObject(&heap_object) &&
    388       heap_object->IsWeakFixedArray() &&
    389       WeakFixedArray::cast(heap_object)->length() == length) {
    390     return handle(WeakFixedArray::cast(heap_object), isolate);
    391   }
    392   Handle<WeakFixedArray> array = isolate->factory()->NewWeakFixedArray(length);
    393   SetFeedback(*array);
    394   return array;
    395 }
    396 
    397 Handle<WeakFixedArray> FeedbackNexus::EnsureExtraArrayOfSize(int length) {
    398   Isolate* isolate = GetIsolate();
    399   HeapObject* heap_object;
    400   if (GetFeedbackExtra()->ToStrongHeapObject(&heap_object) &&
    401       heap_object->IsWeakFixedArray() &&
    402       WeakFixedArray::cast(heap_object)->length() == length) {
    403     return handle(WeakFixedArray::cast(heap_object), isolate);
    404   }
    405   Handle<WeakFixedArray> array = isolate->factory()->NewWeakFixedArray(length);
    406   SetFeedbackExtra(*array);
    407   return array;
    408 }
    409 
    410 void FeedbackNexus::ConfigureUninitialized() {
    411   Isolate* isolate = GetIsolate();
    412   switch (kind()) {
    413     case FeedbackSlotKind::kStoreGlobalSloppy:
    414     case FeedbackSlotKind::kStoreGlobalStrict:
    415     case FeedbackSlotKind::kLoadGlobalNotInsideTypeof:
    416     case FeedbackSlotKind::kLoadGlobalInsideTypeof: {
    417       SetFeedback(HeapObjectReference::ClearedValue(), SKIP_WRITE_BARRIER);
    418       SetFeedbackExtra(*FeedbackVector::UninitializedSentinel(isolate),
    419                        SKIP_WRITE_BARRIER);
    420       break;
    421     }
    422     case FeedbackSlotKind::kCloneObject:
    423     case FeedbackSlotKind::kCall: {
    424       SetFeedback(*FeedbackVector::UninitializedSentinel(isolate),
    425                   SKIP_WRITE_BARRIER);
    426       SetFeedbackExtra(Smi::kZero, SKIP_WRITE_BARRIER);
    427       break;
    428     }
    429     case FeedbackSlotKind::kInstanceOf: {
    430       SetFeedback(*FeedbackVector::UninitializedSentinel(isolate),
    431                   SKIP_WRITE_BARRIER);
    432       break;
    433     }
    434     case FeedbackSlotKind::kStoreNamedSloppy:
    435     case FeedbackSlotKind::kStoreNamedStrict:
    436     case FeedbackSlotKind::kStoreKeyedSloppy:
    437     case FeedbackSlotKind::kStoreKeyedStrict:
    438     case FeedbackSlotKind::kStoreInArrayLiteral:
    439     case FeedbackSlotKind::kStoreOwnNamed:
    440     case FeedbackSlotKind::kLoadProperty:
    441     case FeedbackSlotKind::kLoadKeyed:
    442     case FeedbackSlotKind::kStoreDataPropertyInLiteral: {
    443       SetFeedback(*FeedbackVector::UninitializedSentinel(isolate),
    444                   SKIP_WRITE_BARRIER);
    445       SetFeedbackExtra(*FeedbackVector::UninitializedSentinel(isolate),
    446                        SKIP_WRITE_BARRIER);
    447       break;
    448     }
    449     default:
    450       UNREACHABLE();
    451   }
    452 }
    453 
    454 bool FeedbackNexus::Clear() {
    455   bool feedback_updated = false;
    456 
    457   switch (kind()) {
    458     case FeedbackSlotKind::kCreateClosure:
    459     case FeedbackSlotKind::kTypeProfile:
    460       // We don't clear these kinds ever.
    461       break;
    462 
    463     case FeedbackSlotKind::kCompareOp:
    464     case FeedbackSlotKind::kForIn:
    465     case FeedbackSlotKind::kBinaryOp:
    466       // We don't clear these, either.
    467       break;
    468 
    469     case FeedbackSlotKind::kLiteral:
    470       SetFeedback(Smi::kZero, SKIP_WRITE_BARRIER);
    471       feedback_updated = true;
    472       break;
    473 
    474     case FeedbackSlotKind::kStoreNamedSloppy:
    475     case FeedbackSlotKind::kStoreNamedStrict:
    476     case FeedbackSlotKind::kStoreKeyedSloppy:
    477     case FeedbackSlotKind::kStoreKeyedStrict:
    478     case FeedbackSlotKind::kStoreInArrayLiteral:
    479     case FeedbackSlotKind::kStoreOwnNamed:
    480     case FeedbackSlotKind::kLoadProperty:
    481     case FeedbackSlotKind::kLoadKeyed:
    482     case FeedbackSlotKind::kStoreGlobalSloppy:
    483     case FeedbackSlotKind::kStoreGlobalStrict:
    484     case FeedbackSlotKind::kLoadGlobalNotInsideTypeof:
    485     case FeedbackSlotKind::kLoadGlobalInsideTypeof:
    486     case FeedbackSlotKind::kCall:
    487     case FeedbackSlotKind::kInstanceOf:
    488     case FeedbackSlotKind::kStoreDataPropertyInLiteral:
    489     case FeedbackSlotKind::kCloneObject:
    490       if (!IsCleared()) {
    491         ConfigureUninitialized();
    492         feedback_updated = true;
    493       }
    494       break;
    495 
    496     case FeedbackSlotKind::kInvalid:
    497     case FeedbackSlotKind::kKindsNumber:
    498       UNREACHABLE();
    499       break;
    500   }
    501   return feedback_updated;
    502 }
    503 
    504 void FeedbackNexus::ConfigurePremonomorphic(Handle<Map> receiver_map) {
    505   SetFeedback(*FeedbackVector::PremonomorphicSentinel(GetIsolate()),
    506               SKIP_WRITE_BARRIER);
    507   SetFeedbackExtra(HeapObjectReference::Weak(*receiver_map));
    508 }
    509 
    510 bool FeedbackNexus::ConfigureMegamorphic() {
    511   DisallowHeapAllocation no_gc;
    512   Isolate* isolate = GetIsolate();
    513   MaybeObject* sentinel =
    514       MaybeObject::FromObject(*FeedbackVector::MegamorphicSentinel(isolate));
    515   if (GetFeedback() != sentinel) {
    516     SetFeedback(sentinel, SKIP_WRITE_BARRIER);
    517     SetFeedbackExtra(HeapObjectReference::ClearedValue());
    518     return true;
    519   }
    520 
    521   return false;
    522 }
    523 
    524 bool FeedbackNexus::ConfigureMegamorphic(IcCheckType property_type) {
    525   DisallowHeapAllocation no_gc;
    526   Isolate* isolate = GetIsolate();
    527   bool changed = false;
    528   MaybeObject* sentinel =
    529       MaybeObject::FromObject(*FeedbackVector::MegamorphicSentinel(isolate));
    530   if (GetFeedback() != sentinel) {
    531     SetFeedback(sentinel, SKIP_WRITE_BARRIER);
    532     changed = true;
    533   }
    534 
    535   Smi* extra = Smi::FromInt(static_cast<int>(property_type));
    536   if (changed || GetFeedbackExtra() != MaybeObject::FromSmi(extra)) {
    537     SetFeedbackExtra(extra, SKIP_WRITE_BARRIER);
    538     changed = true;
    539   }
    540   return changed;
    541 }
    542 
    543 InlineCacheState FeedbackNexus::StateFromFeedback() const {
    544   Isolate* isolate = GetIsolate();
    545   MaybeObject* feedback = GetFeedback();
    546 
    547   switch (kind()) {
    548     case FeedbackSlotKind::kCreateClosure:
    549     case FeedbackSlotKind::kLiteral:
    550       // CreateClosure and literal slots don't have a notion of state.
    551       UNREACHABLE();
    552       break;
    553 
    554     case FeedbackSlotKind::kStoreGlobalSloppy:
    555     case FeedbackSlotKind::kStoreGlobalStrict:
    556     case FeedbackSlotKind::kLoadGlobalNotInsideTypeof:
    557     case FeedbackSlotKind::kLoadGlobalInsideTypeof: {
    558       if (feedback->IsSmi()) return MONOMORPHIC;
    559 
    560       DCHECK(feedback->IsWeakOrClearedHeapObject());
    561       MaybeObject* extra = GetFeedbackExtra();
    562       if (!feedback->IsClearedWeakHeapObject() ||
    563           extra != MaybeObject::FromObject(
    564                        *FeedbackVector::UninitializedSentinel(isolate))) {
    565         return MONOMORPHIC;
    566       }
    567       return UNINITIALIZED;
    568     }
    569 
    570     case FeedbackSlotKind::kStoreNamedSloppy:
    571     case FeedbackSlotKind::kStoreNamedStrict:
    572     case FeedbackSlotKind::kStoreKeyedSloppy:
    573     case FeedbackSlotKind::kStoreKeyedStrict:
    574     case FeedbackSlotKind::kStoreInArrayLiteral:
    575     case FeedbackSlotKind::kStoreOwnNamed:
    576     case FeedbackSlotKind::kLoadProperty:
    577     case FeedbackSlotKind::kLoadKeyed: {
    578       if (feedback == MaybeObject::FromObject(
    579                           *FeedbackVector::UninitializedSentinel(isolate))) {
    580         return UNINITIALIZED;
    581       }
    582       if (feedback == MaybeObject::FromObject(
    583                           *FeedbackVector::MegamorphicSentinel(isolate))) {
    584         return MEGAMORPHIC;
    585       }
    586       if (feedback == MaybeObject::FromObject(
    587                           *FeedbackVector::PremonomorphicSentinel(isolate))) {
    588         return PREMONOMORPHIC;
    589       }
    590       if (feedback->IsWeakOrClearedHeapObject()) {
    591         // Don't check if the map is cleared.
    592         return MONOMORPHIC;
    593       }
    594       HeapObject* heap_object;
    595       if (feedback->ToStrongHeapObject(&heap_object)) {
    596         if (heap_object->IsWeakFixedArray()) {
    597           // Determine state purely by our structure, don't check if the maps
    598           // are cleared.
    599           return POLYMORPHIC;
    600         }
    601         if (heap_object->IsName()) {
    602           DCHECK(IsKeyedLoadICKind(kind()) || IsKeyedStoreICKind(kind()));
    603           Object* extra = GetFeedbackExtra()->ToStrongHeapObject();
    604           WeakFixedArray* extra_array = WeakFixedArray::cast(extra);
    605           return extra_array->length() > 2 ? POLYMORPHIC : MONOMORPHIC;
    606         }
    607       }
    608       UNREACHABLE();
    609     }
    610     case FeedbackSlotKind::kCall: {
    611       HeapObject* heap_object;
    612       if (feedback == MaybeObject::FromObject(
    613                           *FeedbackVector::MegamorphicSentinel(isolate))) {
    614         return GENERIC;
    615       } else if (feedback->IsWeakOrClearedHeapObject() ||
    616                  (feedback->ToStrongHeapObject(&heap_object) &&
    617                   heap_object->IsAllocationSite())) {
    618         return MONOMORPHIC;
    619       }
    620 
    621       CHECK_EQ(feedback, MaybeObject::FromObject(
    622                              *FeedbackVector::UninitializedSentinel(isolate)));
    623       return UNINITIALIZED;
    624     }
    625     case FeedbackSlotKind::kBinaryOp: {
    626       BinaryOperationHint hint = GetBinaryOperationFeedback();
    627       if (hint == BinaryOperationHint::kNone) {
    628         return UNINITIALIZED;
    629       } else if (hint == BinaryOperationHint::kAny) {
    630         return GENERIC;
    631       }
    632 
    633       return MONOMORPHIC;
    634     }
    635     case FeedbackSlotKind::kCompareOp: {
    636       CompareOperationHint hint = GetCompareOperationFeedback();
    637       if (hint == CompareOperationHint::kNone) {
    638         return UNINITIALIZED;
    639       } else if (hint == CompareOperationHint::kAny) {
    640         return GENERIC;
    641       }
    642 
    643       return MONOMORPHIC;
    644     }
    645     case FeedbackSlotKind::kForIn: {
    646       ForInHint hint = GetForInFeedback();
    647       if (hint == ForInHint::kNone) {
    648         return UNINITIALIZED;
    649       } else if (hint == ForInHint::kAny) {
    650         return GENERIC;
    651       }
    652       return MONOMORPHIC;
    653     }
    654     case FeedbackSlotKind::kInstanceOf: {
    655       if (feedback == MaybeObject::FromObject(
    656                           *FeedbackVector::UninitializedSentinel(isolate))) {
    657         return UNINITIALIZED;
    658       } else if (feedback ==
    659                  MaybeObject::FromObject(
    660                      *FeedbackVector::MegamorphicSentinel(isolate))) {
    661         return MEGAMORPHIC;
    662       }
    663       return MONOMORPHIC;
    664     }
    665     case FeedbackSlotKind::kStoreDataPropertyInLiteral: {
    666       if (feedback == MaybeObject::FromObject(
    667                           *FeedbackVector::UninitializedSentinel(isolate))) {
    668         return UNINITIALIZED;
    669       } else if (feedback->IsWeakOrClearedHeapObject()) {
    670         // Don't check if the map is cleared.
    671         return MONOMORPHIC;
    672       }
    673 
    674       return MEGAMORPHIC;
    675     }
    676     case FeedbackSlotKind::kTypeProfile: {
    677       if (feedback == MaybeObject::FromObject(
    678                           *FeedbackVector::UninitializedSentinel(isolate))) {
    679         return UNINITIALIZED;
    680       }
    681       return MONOMORPHIC;
    682     }
    683 
    684     case FeedbackSlotKind::kCloneObject: {
    685       if (feedback == MaybeObject::FromObject(
    686                           *FeedbackVector::UninitializedSentinel(isolate))) {
    687         return UNINITIALIZED;
    688       }
    689       if (feedback == MaybeObject::FromObject(
    690                           *FeedbackVector::MegamorphicSentinel(isolate))) {
    691         return MEGAMORPHIC;
    692       }
    693       if (feedback->IsWeakOrClearedHeapObject()) {
    694         return MONOMORPHIC;
    695       }
    696 
    697       DCHECK(feedback->ToStrongHeapObject()->IsWeakFixedArray());
    698       return POLYMORPHIC;
    699     }
    700 
    701     case FeedbackSlotKind::kInvalid:
    702     case FeedbackSlotKind::kKindsNumber:
    703       UNREACHABLE();
    704       break;
    705   }
    706   return UNINITIALIZED;
    707 }
    708 
    709 void FeedbackNexus::ConfigurePropertyCellMode(Handle<PropertyCell> cell) {
    710   DCHECK(IsGlobalICKind(kind()));
    711   Isolate* isolate = GetIsolate();
    712   SetFeedback(HeapObjectReference::Weak(*cell));
    713   SetFeedbackExtra(*FeedbackVector::UninitializedSentinel(isolate),
    714                    SKIP_WRITE_BARRIER);
    715 }
    716 
    717 bool FeedbackNexus::ConfigureLexicalVarMode(int script_context_index,
    718                                             int context_slot_index) {
    719   DCHECK(IsGlobalICKind(kind()));
    720   DCHECK_LE(0, script_context_index);
    721   DCHECK_LE(0, context_slot_index);
    722   if (!ContextIndexBits::is_valid(script_context_index) ||
    723       !SlotIndexBits::is_valid(context_slot_index)) {
    724     return false;
    725   }
    726   int config = ContextIndexBits::encode(script_context_index) |
    727                SlotIndexBits::encode(context_slot_index);
    728 
    729   SetFeedback(Smi::FromInt(config));
    730   Isolate* isolate = GetIsolate();
    731   SetFeedbackExtra(*FeedbackVector::UninitializedSentinel(isolate),
    732                    SKIP_WRITE_BARRIER);
    733   return true;
    734 }
    735 
    736 void FeedbackNexus::ConfigureHandlerMode(const MaybeObjectHandle& handler) {
    737   DCHECK(IsGlobalICKind(kind()));
    738   DCHECK(IC::IsHandler(*handler));
    739   SetFeedback(HeapObjectReference::ClearedValue());
    740   SetFeedbackExtra(*handler);
    741 }
    742 
    743 void FeedbackNexus::ConfigureCloneObject(Handle<Map> source_map,
    744                                          Handle<Map> result_map) {
    745   Isolate* isolate = GetIsolate();
    746   MaybeObject* maybe_feedback = GetFeedback();
    747   Handle<HeapObject> feedback(maybe_feedback->IsStrongOrWeakHeapObject()
    748                                   ? maybe_feedback->GetHeapObject()
    749                                   : nullptr,
    750                               isolate);
    751   switch (ic_state()) {
    752     case UNINITIALIZED:
    753       // Cache the first map seen which meets the fast case requirements.
    754       SetFeedback(HeapObjectReference::Weak(*source_map));
    755       SetFeedbackExtra(*result_map);
    756       break;
    757     case MONOMORPHIC:
    758       if (maybe_feedback->IsClearedWeakHeapObject() ||
    759           feedback.is_identical_to(source_map) ||
    760           Map::cast(*feedback)->is_deprecated()) {
    761         // Remain in MONOMORPHIC state if previous feedback has been collected.
    762         SetFeedback(HeapObjectReference::Weak(*source_map));
    763         SetFeedbackExtra(*result_map);
    764       } else {
    765         // Transition to POLYMORPHIC.
    766         Handle<WeakFixedArray> array =
    767             EnsureArrayOfSize(2 * kCloneObjectPolymorphicEntrySize);
    768         array->Set(0, maybe_feedback);
    769         array->Set(1, GetFeedbackExtra());
    770         array->Set(2, HeapObjectReference::Weak(*source_map));
    771         array->Set(3, MaybeObject::FromObject(*result_map));
    772         SetFeedbackExtra(HeapObjectReference::ClearedValue());
    773       }
    774       break;
    775     case POLYMORPHIC: {
    776       static constexpr int kMaxElements =
    777           IC::kMaxPolymorphicMapCount * kCloneObjectPolymorphicEntrySize;
    778       Handle<WeakFixedArray> array = Handle<WeakFixedArray>::cast(feedback);
    779       int i = 0;
    780       for (; i < array->length(); i += kCloneObjectPolymorphicEntrySize) {
    781         MaybeObject* feedback = array->Get(i);
    782         if (feedback->IsClearedWeakHeapObject()) break;
    783         Handle<Map> cached_map(Map::cast(feedback->GetHeapObject()), isolate);
    784         if (cached_map.is_identical_to(source_map) ||
    785             cached_map->is_deprecated())
    786           break;
    787       }
    788 
    789       if (i >= array->length()) {
    790         if (i == kMaxElements) {
    791           // Transition to MEGAMORPHIC.
    792           MaybeObject* sentinel = MaybeObject::FromObject(
    793               *FeedbackVector::MegamorphicSentinel(isolate));
    794           SetFeedback(sentinel, SKIP_WRITE_BARRIER);
    795           SetFeedbackExtra(HeapObjectReference::ClearedValue());
    796           break;
    797         }
    798 
    799         // Grow polymorphic feedback array.
    800         Handle<WeakFixedArray> new_array = EnsureArrayOfSize(
    801             array->length() + kCloneObjectPolymorphicEntrySize);
    802         for (int j = 0; j < array->length(); ++j) {
    803           new_array->Set(j, array->Get(j));
    804         }
    805         array = new_array;
    806       }
    807 
    808       array->Set(i, HeapObjectReference::Weak(*source_map));
    809       array->Set(i + 1, MaybeObject::FromObject(*result_map));
    810       break;
    811     }
    812 
    813     default:
    814       UNREACHABLE();
    815   }
    816 }
    817 
    818 int FeedbackNexus::GetCallCount() {
    819   DCHECK(IsCallICKind(kind()));
    820 
    821   Object* call_count = GetFeedbackExtra()->ToObject();
    822   CHECK(call_count->IsSmi());
    823   uint32_t value = static_cast<uint32_t>(Smi::ToInt(call_count));
    824   return CallCountField::decode(value);
    825 }
    826 
    827 void FeedbackNexus::SetSpeculationMode(SpeculationMode mode) {
    828   DCHECK(IsCallICKind(kind()));
    829 
    830   Object* call_count = GetFeedbackExtra()->ToObject();
    831   CHECK(call_count->IsSmi());
    832   uint32_t count = static_cast<uint32_t>(Smi::ToInt(call_count));
    833   uint32_t value = CallCountField::encode(CallCountField::decode(count));
    834   int result = static_cast<int>(value | SpeculationModeField::encode(mode));
    835   SetFeedbackExtra(Smi::FromInt(result), SKIP_WRITE_BARRIER);
    836 }
    837 
    838 SpeculationMode FeedbackNexus::GetSpeculationMode() {
    839   DCHECK(IsCallICKind(kind()));
    840 
    841   Object* call_count = GetFeedbackExtra()->ToObject();
    842   CHECK(call_count->IsSmi());
    843   uint32_t value = static_cast<uint32_t>(Smi::ToInt(call_count));
    844   return SpeculationModeField::decode(value);
    845 }
    846 
    847 float FeedbackNexus::ComputeCallFrequency() {
    848   DCHECK(IsCallICKind(kind()));
    849 
    850   double const invocation_count = vector()->invocation_count();
    851   double const call_count = GetCallCount();
    852   if (invocation_count == 0) {
    853     // Prevent division by 0.
    854     return 0.0f;
    855   }
    856   return static_cast<float>(call_count / invocation_count);
    857 }
    858 
    859 void FeedbackNexus::ConfigureMonomorphic(Handle<Name> name,
    860                                          Handle<Map> receiver_map,
    861                                          const MaybeObjectHandle& handler) {
    862   DCHECK(handler.is_null() || IC::IsHandler(*handler));
    863   if (kind() == FeedbackSlotKind::kStoreDataPropertyInLiteral) {
    864     SetFeedback(HeapObjectReference::Weak(*receiver_map));
    865     SetFeedbackExtra(*name);
    866   } else {
    867     if (name.is_null()) {
    868       SetFeedback(HeapObjectReference::Weak(*receiver_map));
    869       SetFeedbackExtra(*handler);
    870     } else {
    871       Handle<WeakFixedArray> array = EnsureExtraArrayOfSize(2);
    872       SetFeedback(*name);
    873       array->Set(0, HeapObjectReference::Weak(*receiver_map));
    874       array->Set(1, *handler);
    875     }
    876   }
    877 }
    878 
    879 void FeedbackNexus::ConfigurePolymorphic(Handle<Name> name,
    880                                          MapHandles const& maps,
    881                                          MaybeObjectHandles* handlers) {
    882   DCHECK_EQ(handlers->size(), maps.size());
    883   int receiver_count = static_cast<int>(maps.size());
    884   DCHECK_GT(receiver_count, 1);
    885   Handle<WeakFixedArray> array;
    886   if (name.is_null()) {
    887     array = EnsureArrayOfSize(receiver_count * 2);
    888     SetFeedbackExtra(*FeedbackVector::UninitializedSentinel(GetIsolate()),
    889                      SKIP_WRITE_BARRIER);
    890   } else {
    891     array = EnsureExtraArrayOfSize(receiver_count * 2);
    892     SetFeedback(*name);
    893   }
    894 
    895   for (int current = 0; current < receiver_count; ++current) {
    896     Handle<Map> map = maps[current];
    897     array->Set(current * 2, HeapObjectReference::Weak(*map));
    898     DCHECK(IC::IsHandler(*handlers->at(current)));
    899     array->Set(current * 2 + 1, *handlers->at(current));
    900   }
    901 }
    902 
    903 int FeedbackNexus::ExtractMaps(MapHandles* maps) const {
    904   DCHECK(IsLoadICKind(kind()) || IsStoreICKind(kind()) ||
    905          IsKeyedLoadICKind(kind()) || IsKeyedStoreICKind(kind()) ||
    906          IsStoreOwnICKind(kind()) || IsStoreDataPropertyInLiteralKind(kind()) ||
    907          IsStoreInArrayLiteralICKind(kind()));
    908 
    909   Isolate* isolate = GetIsolate();
    910   MaybeObject* feedback = GetFeedback();
    911   bool is_named_feedback = IsPropertyNameFeedback(feedback);
    912   HeapObject* heap_object;
    913   if ((feedback->ToStrongHeapObject(&heap_object) &&
    914        heap_object->IsWeakFixedArray()) ||
    915       is_named_feedback) {
    916     int found = 0;
    917     WeakFixedArray* array;
    918     if (is_named_feedback) {
    919       array = WeakFixedArray::cast(GetFeedbackExtra()->ToStrongHeapObject());
    920     } else {
    921       array = WeakFixedArray::cast(heap_object);
    922     }
    923     const int increment = 2;
    924     HeapObject* heap_object;
    925     for (int i = 0; i < array->length(); i += increment) {
    926       DCHECK(array->Get(i)->IsWeakOrClearedHeapObject());
    927       if (array->Get(i)->ToWeakHeapObject(&heap_object)) {
    928         Map* map = Map::cast(heap_object);
    929         maps->push_back(handle(map, isolate));
    930         found++;
    931       }
    932     }
    933     return found;
    934   } else if (feedback->ToWeakHeapObject(&heap_object)) {
    935     Map* map = Map::cast(heap_object);
    936     maps->push_back(handle(map, isolate));
    937     return 1;
    938   } else if (feedback->ToStrongHeapObject(&heap_object) &&
    939              heap_object ==
    940                  heap_object->GetReadOnlyRoots().premonomorphic_symbol()) {
    941     if (GetFeedbackExtra()->ToWeakHeapObject(&heap_object)) {
    942       Map* map = Map::cast(heap_object);
    943       maps->push_back(handle(map, isolate));
    944       return 1;
    945     }
    946   }
    947 
    948   return 0;
    949 }
    950 
    951 MaybeObjectHandle FeedbackNexus::FindHandlerForMap(Handle<Map> map) const {
    952   DCHECK(IsLoadICKind(kind()) || IsStoreICKind(kind()) ||
    953          IsKeyedLoadICKind(kind()) || IsKeyedStoreICKind(kind()) ||
    954          IsStoreOwnICKind(kind()) || IsStoreDataPropertyInLiteralKind(kind()));
    955 
    956   MaybeObject* feedback = GetFeedback();
    957   Isolate* isolate = GetIsolate();
    958   bool is_named_feedback = IsPropertyNameFeedback(feedback);
    959   HeapObject* heap_object;
    960   if ((feedback->ToStrongHeapObject(&heap_object) &&
    961        heap_object->IsWeakFixedArray()) ||
    962       is_named_feedback) {
    963     WeakFixedArray* array;
    964     if (is_named_feedback) {
    965       array = WeakFixedArray::cast(GetFeedbackExtra()->ToStrongHeapObject());
    966     } else {
    967       array = WeakFixedArray::cast(heap_object);
    968     }
    969     const int increment = 2;
    970     HeapObject* heap_object;
    971     for (int i = 0; i < array->length(); i += increment) {
    972       DCHECK(array->Get(i)->IsWeakOrClearedHeapObject());
    973       if (array->Get(i)->ToWeakHeapObject(&heap_object)) {
    974         Map* array_map = Map::cast(heap_object);
    975         if (array_map == *map &&
    976             !array->Get(i + increment - 1)->IsClearedWeakHeapObject()) {
    977           MaybeObject* handler = array->Get(i + increment - 1);
    978           DCHECK(IC::IsHandler(handler));
    979           return handle(handler, isolate);
    980         }
    981       }
    982     }
    983   } else if (feedback->ToWeakHeapObject(&heap_object)) {
    984     Map* cell_map = Map::cast(heap_object);
    985     if (cell_map == *map && !GetFeedbackExtra()->IsClearedWeakHeapObject()) {
    986       MaybeObject* handler = GetFeedbackExtra();
    987       DCHECK(IC::IsHandler(handler));
    988       return handle(handler, isolate);
    989     }
    990   }
    991 
    992   return MaybeObjectHandle();
    993 }
    994 
    995 bool FeedbackNexus::FindHandlers(MaybeObjectHandles* code_list,
    996                                  int length) const {
    997   DCHECK(IsLoadICKind(kind()) || IsStoreICKind(kind()) ||
    998          IsKeyedLoadICKind(kind()) || IsKeyedStoreICKind(kind()) ||
    999          IsStoreOwnICKind(kind()) || IsStoreDataPropertyInLiteralKind(kind()) ||
   1000          IsStoreInArrayLiteralICKind(kind()));
   1001 
   1002   MaybeObject* feedback = GetFeedback();
   1003   Isolate* isolate = GetIsolate();
   1004   int count = 0;
   1005   bool is_named_feedback = IsPropertyNameFeedback(feedback);
   1006   HeapObject* heap_object;
   1007   if ((feedback->ToStrongHeapObject(&heap_object) &&
   1008        heap_object->IsWeakFixedArray()) ||
   1009       is_named_feedback) {
   1010     WeakFixedArray* array;
   1011     if (is_named_feedback) {
   1012       array = WeakFixedArray::cast(GetFeedbackExtra()->ToStrongHeapObject());
   1013     } else {
   1014       array = WeakFixedArray::cast(heap_object);
   1015     }
   1016     const int increment = 2;
   1017     HeapObject* heap_object;
   1018     for (int i = 0; i < array->length(); i += increment) {
   1019       // Be sure to skip handlers whose maps have been cleared.
   1020       DCHECK(array->Get(i)->IsWeakOrClearedHeapObject());
   1021       if (array->Get(i)->ToWeakHeapObject(&heap_object) &&
   1022           !array->Get(i + increment - 1)->IsClearedWeakHeapObject()) {
   1023         MaybeObject* handler = array->Get(i + increment - 1);
   1024         DCHECK(IC::IsHandler(handler));
   1025         code_list->push_back(handle(handler, isolate));
   1026         count++;
   1027       }
   1028     }
   1029   } else if (feedback->ToWeakHeapObject(&heap_object)) {
   1030     MaybeObject* extra = GetFeedbackExtra();
   1031     if (!extra->IsClearedWeakHeapObject()) {
   1032       DCHECK(IC::IsHandler(extra));
   1033       code_list->push_back(handle(extra, isolate));
   1034       count++;
   1035     }
   1036   }
   1037   return count == length;
   1038 }
   1039 
   1040 Name* FeedbackNexus::FindFirstName() const {
   1041   if (IsKeyedStoreICKind(kind()) || IsKeyedLoadICKind(kind())) {
   1042     MaybeObject* feedback = GetFeedback();
   1043     if (IsPropertyNameFeedback(feedback)) {
   1044       return Name::cast(feedback->ToStrongHeapObject());
   1045     }
   1046   }
   1047   return nullptr;
   1048 }
   1049 
   1050 KeyedAccessLoadMode FeedbackNexus::GetKeyedAccessLoadMode() const {
   1051   DCHECK(IsKeyedLoadICKind(kind()));
   1052   MapHandles maps;
   1053   MaybeObjectHandles handlers;
   1054 
   1055   if (GetKeyType() == PROPERTY) return STANDARD_LOAD;
   1056 
   1057   ExtractMaps(&maps);
   1058   FindHandlers(&handlers, static_cast<int>(maps.size()));
   1059   for (MaybeObjectHandle const& handler : handlers) {
   1060     KeyedAccessLoadMode mode = LoadHandler::GetKeyedAccessLoadMode(*handler);
   1061     if (mode != STANDARD_LOAD) return mode;
   1062   }
   1063 
   1064   return STANDARD_LOAD;
   1065 }
   1066 
   1067 KeyedAccessStoreMode FeedbackNexus::GetKeyedAccessStoreMode() const {
   1068   DCHECK(IsKeyedStoreICKind(kind()) || IsStoreInArrayLiteralICKind(kind()));
   1069   KeyedAccessStoreMode mode = STANDARD_STORE;
   1070   MapHandles maps;
   1071   MaybeObjectHandles handlers;
   1072 
   1073   if (GetKeyType() == PROPERTY) return mode;
   1074 
   1075   ExtractMaps(&maps);
   1076   FindHandlers(&handlers, static_cast<int>(maps.size()));
   1077   for (const MaybeObjectHandle& maybe_code_handler : handlers) {
   1078     // The first handler that isn't the slow handler will have the bits we need.
   1079     Handle<Code> handler;
   1080     if (maybe_code_handler.object()->IsStoreHandler()) {
   1081       Handle<StoreHandler> data_handler =
   1082           Handle<StoreHandler>::cast(maybe_code_handler.object());
   1083       handler = handle(Code::cast(data_handler->smi_handler()),
   1084                        vector()->GetIsolate());
   1085     } else if (maybe_code_handler.object()->IsSmi()) {
   1086       // Skip proxy handlers.
   1087       DCHECK_EQ(*(maybe_code_handler.object()),
   1088                 *StoreHandler::StoreProxy(GetIsolate()));
   1089       continue;
   1090     } else {
   1091       // Element store without prototype chain check.
   1092       handler = Handle<Code>::cast(maybe_code_handler.object());
   1093       if (handler->is_builtin()) continue;
   1094     }
   1095     CodeStub::Major major_key = CodeStub::MajorKeyFromKey(handler->stub_key());
   1096     uint32_t minor_key = CodeStub::MinorKeyFromKey(handler->stub_key());
   1097     CHECK(major_key == CodeStub::KeyedStoreSloppyArguments ||
   1098           major_key == CodeStub::StoreFastElement ||
   1099           major_key == CodeStub::StoreSlowElement ||
   1100           major_key == CodeStub::StoreInArrayLiteralSlow ||
   1101           major_key == CodeStub::ElementsTransitionAndStore ||
   1102           major_key == CodeStub::NoCache);
   1103     if (major_key != CodeStub::NoCache) {
   1104       mode = CommonStoreModeBits::decode(minor_key);
   1105       break;
   1106     }
   1107   }
   1108 
   1109   return mode;
   1110 }
   1111 
   1112 IcCheckType FeedbackNexus::GetKeyType() const {
   1113   DCHECK(IsKeyedStoreICKind(kind()) || IsKeyedLoadICKind(kind()) ||
   1114          IsStoreInArrayLiteralICKind(kind()));
   1115   MaybeObject* feedback = GetFeedback();
   1116   if (feedback == MaybeObject::FromObject(
   1117                       *FeedbackVector::MegamorphicSentinel(GetIsolate()))) {
   1118     return static_cast<IcCheckType>(Smi::ToInt(GetFeedbackExtra()->ToObject()));
   1119   }
   1120   return IsPropertyNameFeedback(feedback) ? PROPERTY : ELEMENT;
   1121 }
   1122 
   1123 BinaryOperationHint FeedbackNexus::GetBinaryOperationFeedback() const {
   1124   DCHECK_EQ(kind(), FeedbackSlotKind::kBinaryOp);
   1125   int feedback = Smi::ToInt(GetFeedback()->ToSmi());
   1126   return BinaryOperationHintFromFeedback(feedback);
   1127 }
   1128 
   1129 CompareOperationHint FeedbackNexus::GetCompareOperationFeedback() const {
   1130   DCHECK_EQ(kind(), FeedbackSlotKind::kCompareOp);
   1131   int feedback = Smi::ToInt(GetFeedback()->ToSmi());
   1132   return CompareOperationHintFromFeedback(feedback);
   1133 }
   1134 
   1135 ForInHint FeedbackNexus::GetForInFeedback() const {
   1136   DCHECK_EQ(kind(), FeedbackSlotKind::kForIn);
   1137   int feedback = Smi::ToInt(GetFeedback()->ToSmi());
   1138   return ForInHintFromFeedback(feedback);
   1139 }
   1140 
   1141 Handle<FeedbackCell> FeedbackNexus::GetFeedbackCell() const {
   1142   DCHECK_EQ(FeedbackSlotKind::kCreateClosure, kind());
   1143   return handle(FeedbackCell::cast(GetFeedback()->ToObject()),
   1144                 vector()->GetIsolate());
   1145 }
   1146 
   1147 MaybeHandle<JSObject> FeedbackNexus::GetConstructorFeedback() const {
   1148   DCHECK_EQ(kind(), FeedbackSlotKind::kInstanceOf);
   1149   Isolate* isolate = GetIsolate();
   1150   MaybeObject* feedback = GetFeedback();
   1151   HeapObject* heap_object;
   1152   if (feedback->ToWeakHeapObject(&heap_object)) {
   1153     return handle(JSObject::cast(heap_object), isolate);
   1154   }
   1155   return MaybeHandle<JSObject>();
   1156 }
   1157 
   1158 namespace {
   1159 
   1160 bool InList(Handle<ArrayList> types, Handle<String> type) {
   1161   for (int i = 0; i < types->Length(); i++) {
   1162     Object* obj = types->Get(i);
   1163     if (String::cast(obj)->Equals(*type)) {
   1164       return true;
   1165     }
   1166   }
   1167   return false;
   1168 }
   1169 }  // anonymous namespace
   1170 
   1171 void FeedbackNexus::Collect(Handle<String> type, int position) {
   1172   DCHECK(IsTypeProfileKind(kind()));
   1173   DCHECK_GE(position, 0);
   1174   Isolate* isolate = GetIsolate();
   1175 
   1176   MaybeObject* const feedback = GetFeedback();
   1177 
   1178   // Map source position to collection of types
   1179   Handle<SimpleNumberDictionary> types;
   1180 
   1181   if (feedback == MaybeObject::FromObject(
   1182                       *FeedbackVector::UninitializedSentinel(isolate))) {
   1183     types = SimpleNumberDictionary::New(isolate, 1);
   1184   } else {
   1185     types = handle(SimpleNumberDictionary::cast(feedback->ToStrongHeapObject()),
   1186                    isolate);
   1187   }
   1188 
   1189   Handle<ArrayList> position_specific_types;
   1190 
   1191   int entry = types->FindEntry(isolate, position);
   1192   if (entry == SimpleNumberDictionary::kNotFound) {
   1193     position_specific_types = ArrayList::New(isolate, 1);
   1194     types = SimpleNumberDictionary::Set(
   1195         isolate, types, position,
   1196         ArrayList::Add(isolate, position_specific_types, type));
   1197   } else {
   1198     DCHECK(types->ValueAt(entry)->IsArrayList());
   1199     position_specific_types =
   1200         handle(ArrayList::cast(types->ValueAt(entry)), isolate);
   1201     if (!InList(position_specific_types, type)) {  // Add type
   1202       types = SimpleNumberDictionary::Set(
   1203           isolate, types, position,
   1204           ArrayList::Add(isolate, position_specific_types, type));
   1205     }
   1206   }
   1207   SetFeedback(*types);
   1208 }
   1209 
   1210 std::vector<int> FeedbackNexus::GetSourcePositions() const {
   1211   DCHECK(IsTypeProfileKind(kind()));
   1212   std::vector<int> source_positions;
   1213   Isolate* isolate = GetIsolate();
   1214 
   1215   MaybeObject* const feedback = GetFeedback();
   1216 
   1217   if (feedback == MaybeObject::FromObject(
   1218                       *FeedbackVector::UninitializedSentinel(isolate))) {
   1219     return source_positions;
   1220   }
   1221 
   1222   Handle<SimpleNumberDictionary> types(
   1223       SimpleNumberDictionary::cast(feedback->ToStrongHeapObject()), isolate);
   1224 
   1225   for (int index = SimpleNumberDictionary::kElementsStartIndex;
   1226        index < types->length(); index += SimpleNumberDictionary::kEntrySize) {
   1227     int key_index = index + SimpleNumberDictionary::kEntryKeyIndex;
   1228     Object* key = types->get(key_index);
   1229     if (key->IsSmi()) {
   1230       int position = Smi::cast(key)->value();
   1231       source_positions.push_back(position);
   1232     }
   1233   }
   1234   return source_positions;
   1235 }
   1236 
   1237 std::vector<Handle<String>> FeedbackNexus::GetTypesForSourcePositions(
   1238     uint32_t position) const {
   1239   DCHECK(IsTypeProfileKind(kind()));
   1240   Isolate* isolate = GetIsolate();
   1241 
   1242   MaybeObject* const feedback = GetFeedback();
   1243   std::vector<Handle<String>> types_for_position;
   1244   if (feedback == MaybeObject::FromObject(
   1245                       *FeedbackVector::UninitializedSentinel(isolate))) {
   1246     return types_for_position;
   1247   }
   1248 
   1249   Handle<SimpleNumberDictionary> types(
   1250       SimpleNumberDictionary::cast(feedback->ToStrongHeapObject()), isolate);
   1251 
   1252   int entry = types->FindEntry(isolate, position);
   1253   if (entry == SimpleNumberDictionary::kNotFound) {
   1254     return types_for_position;
   1255   }
   1256   DCHECK(types->ValueAt(entry)->IsArrayList());
   1257   Handle<ArrayList> position_specific_types =
   1258       Handle<ArrayList>(ArrayList::cast(types->ValueAt(entry)), isolate);
   1259   for (int i = 0; i < position_specific_types->Length(); i++) {
   1260     Object* t = position_specific_types->Get(i);
   1261     types_for_position.push_back(Handle<String>(String::cast(t), isolate));
   1262   }
   1263 
   1264   return types_for_position;
   1265 }
   1266 
   1267 namespace {
   1268 
   1269 Handle<JSObject> ConvertToJSObject(Isolate* isolate,
   1270                                    Handle<SimpleNumberDictionary> feedback) {
   1271   Handle<JSObject> type_profile =
   1272       isolate->factory()->NewJSObject(isolate->object_function());
   1273 
   1274   for (int index = SimpleNumberDictionary::kElementsStartIndex;
   1275        index < feedback->length();
   1276        index += SimpleNumberDictionary::kEntrySize) {
   1277     int key_index = index + SimpleNumberDictionary::kEntryKeyIndex;
   1278     Object* key = feedback->get(key_index);
   1279     if (key->IsSmi()) {
   1280       int value_index = index + SimpleNumberDictionary::kEntryValueIndex;
   1281 
   1282       Handle<ArrayList> position_specific_types(
   1283           ArrayList::cast(feedback->get(value_index)), isolate);
   1284 
   1285       int position = Smi::ToInt(key);
   1286       JSObject::AddDataElement(
   1287           type_profile, position,
   1288           isolate->factory()->NewJSArrayWithElements(
   1289               ArrayList::Elements(isolate, position_specific_types)),
   1290           PropertyAttributes::NONE);
   1291     }
   1292   }
   1293   return type_profile;
   1294 }
   1295 }  // namespace
   1296 
   1297 JSObject* FeedbackNexus::GetTypeProfile() const {
   1298   DCHECK(IsTypeProfileKind(kind()));
   1299   Isolate* isolate = GetIsolate();
   1300 
   1301   MaybeObject* const feedback = GetFeedback();
   1302 
   1303   if (feedback == MaybeObject::FromObject(
   1304                       *FeedbackVector::UninitializedSentinel(isolate))) {
   1305     return *isolate->factory()->NewJSObject(isolate->object_function());
   1306   }
   1307 
   1308   return *ConvertToJSObject(
   1309       isolate,
   1310       handle(SimpleNumberDictionary::cast(feedback->ToStrongHeapObject()),
   1311              isolate));
   1312 }
   1313 
   1314 void FeedbackNexus::ResetTypeProfile() {
   1315   DCHECK(IsTypeProfileKind(kind()));
   1316   SetFeedback(*FeedbackVector::UninitializedSentinel(GetIsolate()));
   1317 }
   1318 
   1319 }  // namespace internal
   1320 }  // namespace v8
   1321