Home | History | Annotate | Download | only in src
      1 // Copyright 2012 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 #ifndef V8_FEEDBACK_VECTOR_INL_H_
      6 #define V8_FEEDBACK_VECTOR_INL_H_
      7 
      8 #include "src/feedback-vector.h"
      9 #include "src/globals.h"
     10 #include "src/heap/factory-inl.h"
     11 #include "src/heap/heap-inl.h"
     12 #include "src/objects/maybe-object-inl.h"
     13 #include "src/objects/shared-function-info.h"
     14 
     15 // Has to be the last include (doesn't have include guards):
     16 #include "src/objects/object-macros.h"
     17 
     18 namespace v8 {
     19 namespace internal {
     20 
     21 INT32_ACCESSORS(FeedbackMetadata, slot_count, kSlotCountOffset)
     22 
     23 int32_t FeedbackMetadata::synchronized_slot_count() const {
     24   return base::Acquire_Load(reinterpret_cast<const base::Atomic32*>(
     25       FIELD_ADDR(this, kSlotCountOffset)));
     26 }
     27 
     28 // static
     29 FeedbackMetadata* FeedbackMetadata::cast(Object* obj) {
     30   DCHECK(obj->IsFeedbackMetadata());
     31   return reinterpret_cast<FeedbackMetadata*>(obj);
     32 }
     33 
     34 int32_t FeedbackMetadata::get(int index) const {
     35   DCHECK(index >= 0 && index < length());
     36   int offset = kHeaderSize + index * kInt32Size;
     37   return READ_INT32_FIELD(this, offset);
     38 }
     39 
     40 void FeedbackMetadata::set(int index, int32_t value) {
     41   DCHECK(index >= 0 && index < length());
     42   int offset = kHeaderSize + index * kInt32Size;
     43   WRITE_INT32_FIELD(this, offset, value);
     44 }
     45 
     46 bool FeedbackMetadata::is_empty() const { return slot_count() == 0; }
     47 
     48 int FeedbackMetadata::length() const {
     49   return FeedbackMetadata::length(slot_count());
     50 }
     51 
     52 // static
     53 FeedbackVector* FeedbackVector::cast(Object* obj) {
     54   DCHECK(obj->IsFeedbackVector());
     55   return reinterpret_cast<FeedbackVector*>(obj);
     56 }
     57 
     58 int FeedbackMetadata::GetSlotSize(FeedbackSlotKind kind) {
     59   switch (kind) {
     60     case FeedbackSlotKind::kForIn:
     61     case FeedbackSlotKind::kInstanceOf:
     62     case FeedbackSlotKind::kCompareOp:
     63     case FeedbackSlotKind::kBinaryOp:
     64     case FeedbackSlotKind::kLiteral:
     65     case FeedbackSlotKind::kCreateClosure:
     66     case FeedbackSlotKind::kTypeProfile:
     67       return 1;
     68 
     69     case FeedbackSlotKind::kCall:
     70     case FeedbackSlotKind::kCloneObject:
     71     case FeedbackSlotKind::kLoadProperty:
     72     case FeedbackSlotKind::kLoadGlobalInsideTypeof:
     73     case FeedbackSlotKind::kLoadGlobalNotInsideTypeof:
     74     case FeedbackSlotKind::kLoadKeyed:
     75     case FeedbackSlotKind::kStoreNamedSloppy:
     76     case FeedbackSlotKind::kStoreNamedStrict:
     77     case FeedbackSlotKind::kStoreOwnNamed:
     78     case FeedbackSlotKind::kStoreGlobalSloppy:
     79     case FeedbackSlotKind::kStoreGlobalStrict:
     80     case FeedbackSlotKind::kStoreKeyedSloppy:
     81     case FeedbackSlotKind::kStoreKeyedStrict:
     82     case FeedbackSlotKind::kStoreInArrayLiteral:
     83     case FeedbackSlotKind::kStoreDataPropertyInLiteral:
     84       return 2;
     85 
     86     case FeedbackSlotKind::kInvalid:
     87     case FeedbackSlotKind::kKindsNumber:
     88       UNREACHABLE();
     89       break;
     90   }
     91   return 1;
     92 }
     93 
     94 ACCESSORS(FeedbackVector, shared_function_info, SharedFunctionInfo,
     95           kSharedFunctionInfoOffset)
     96 WEAK_ACCESSORS(FeedbackVector, optimized_code_weak_or_smi, kOptimizedCodeOffset)
     97 INT32_ACCESSORS(FeedbackVector, length, kLengthOffset)
     98 INT32_ACCESSORS(FeedbackVector, invocation_count, kInvocationCountOffset)
     99 INT32_ACCESSORS(FeedbackVector, profiler_ticks, kProfilerTicksOffset)
    100 INT32_ACCESSORS(FeedbackVector, deopt_count, kDeoptCountOffset)
    101 
    102 bool FeedbackVector::is_empty() const { return length() == 0; }
    103 
    104 FeedbackMetadata* FeedbackVector::metadata() const {
    105   return shared_function_info()->feedback_metadata();
    106 }
    107 
    108 void FeedbackVector::clear_invocation_count() { set_invocation_count(0); }
    109 
    110 void FeedbackVector::increment_deopt_count() {
    111   int count = deopt_count();
    112   if (count < std::numeric_limits<int32_t>::max()) {
    113     set_deopt_count(count + 1);
    114   }
    115 }
    116 
    117 Code* FeedbackVector::optimized_code() const {
    118   MaybeObject* slot = optimized_code_weak_or_smi();
    119   DCHECK(slot->IsSmi() || slot->IsClearedWeakHeapObject() ||
    120          slot->IsWeakHeapObject());
    121   HeapObject* heap_object;
    122   return slot->ToStrongOrWeakHeapObject(&heap_object) ? Code::cast(heap_object)
    123                                                       : nullptr;
    124 }
    125 
    126 OptimizationMarker FeedbackVector::optimization_marker() const {
    127   MaybeObject* slot = optimized_code_weak_or_smi();
    128   Smi* value;
    129   if (!slot->ToSmi(&value)) return OptimizationMarker::kNone;
    130   return static_cast<OptimizationMarker>(value->value());
    131 }
    132 
    133 bool FeedbackVector::has_optimized_code() const {
    134   return optimized_code() != nullptr;
    135 }
    136 
    137 bool FeedbackVector::has_optimization_marker() const {
    138   return optimization_marker() != OptimizationMarker::kLogFirstExecution &&
    139          optimization_marker() != OptimizationMarker::kNone;
    140 }
    141 
    142 // Conversion from an integer index to either a slot or an ic slot.
    143 // static
    144 FeedbackSlot FeedbackVector::ToSlot(int index) {
    145   DCHECK_GE(index, 0);
    146   return FeedbackSlot(index);
    147 }
    148 
    149 MaybeObject* FeedbackVector::Get(FeedbackSlot slot) const {
    150   return get(GetIndex(slot));
    151 }
    152 
    153 MaybeObject* FeedbackVector::get(int index) const {
    154   DCHECK_GE(index, 0);
    155   DCHECK_LT(index, this->length());
    156   int offset = kFeedbackSlotsOffset + index * kPointerSize;
    157   return RELAXED_READ_WEAK_FIELD(this, offset);
    158 }
    159 
    160 void FeedbackVector::Set(FeedbackSlot slot, MaybeObject* value,
    161                          WriteBarrierMode mode) {
    162   set(GetIndex(slot), value, mode);
    163 }
    164 
    165 void FeedbackVector::set(int index, MaybeObject* value, WriteBarrierMode mode) {
    166   DCHECK_GE(index, 0);
    167   DCHECK_LT(index, this->length());
    168   int offset = kFeedbackSlotsOffset + index * kPointerSize;
    169   RELAXED_WRITE_FIELD(this, offset, value);
    170   CONDITIONAL_WEAK_WRITE_BARRIER(this, offset, value, mode);
    171 }
    172 
    173 void FeedbackVector::Set(FeedbackSlot slot, Object* value,
    174                          WriteBarrierMode mode) {
    175   set(GetIndex(slot), MaybeObject::FromObject(value), mode);
    176 }
    177 
    178 void FeedbackVector::set(int index, Object* value, WriteBarrierMode mode) {
    179   set(index, MaybeObject::FromObject(value), mode);
    180 }
    181 
    182 inline MaybeObject** FeedbackVector::slots_start() {
    183   return HeapObject::RawMaybeWeakField(this, kFeedbackSlotsOffset);
    184 }
    185 
    186 // Helper function to transform the feedback to BinaryOperationHint.
    187 BinaryOperationHint BinaryOperationHintFromFeedback(int type_feedback) {
    188   switch (type_feedback) {
    189     case BinaryOperationFeedback::kNone:
    190       return BinaryOperationHint::kNone;
    191     case BinaryOperationFeedback::kSignedSmall:
    192       return BinaryOperationHint::kSignedSmall;
    193     case BinaryOperationFeedback::kSignedSmallInputs:
    194       return BinaryOperationHint::kSignedSmallInputs;
    195     case BinaryOperationFeedback::kNumber:
    196       return BinaryOperationHint::kNumber;
    197     case BinaryOperationFeedback::kNumberOrOddball:
    198       return BinaryOperationHint::kNumberOrOddball;
    199     case BinaryOperationFeedback::kString:
    200       return BinaryOperationHint::kString;
    201     case BinaryOperationFeedback::kBigInt:
    202       return BinaryOperationHint::kBigInt;
    203     default:
    204       return BinaryOperationHint::kAny;
    205   }
    206   UNREACHABLE();
    207 }
    208 
    209 // Helper function to transform the feedback to CompareOperationHint.
    210 CompareOperationHint CompareOperationHintFromFeedback(int type_feedback) {
    211   switch (type_feedback) {
    212     case CompareOperationFeedback::kNone:
    213       return CompareOperationHint::kNone;
    214     case CompareOperationFeedback::kSignedSmall:
    215       return CompareOperationHint::kSignedSmall;
    216     case CompareOperationFeedback::kNumber:
    217       return CompareOperationHint::kNumber;
    218     case CompareOperationFeedback::kNumberOrOddball:
    219       return CompareOperationHint::kNumberOrOddball;
    220     case CompareOperationFeedback::kInternalizedString:
    221       return CompareOperationHint::kInternalizedString;
    222     case CompareOperationFeedback::kString:
    223       return CompareOperationHint::kString;
    224     case CompareOperationFeedback::kSymbol:
    225       return CompareOperationHint::kSymbol;
    226     case CompareOperationFeedback::kBigInt:
    227       return CompareOperationHint::kBigInt;
    228     case CompareOperationFeedback::kReceiver:
    229       return CompareOperationHint::kReceiver;
    230     default:
    231       return CompareOperationHint::kAny;
    232   }
    233   UNREACHABLE();
    234 }
    235 
    236 // Helper function to transform the feedback to ForInHint.
    237 ForInHint ForInHintFromFeedback(int type_feedback) {
    238   switch (type_feedback) {
    239     case ForInFeedback::kNone:
    240       return ForInHint::kNone;
    241     case ForInFeedback::kEnumCacheKeys:
    242       return ForInHint::kEnumCacheKeys;
    243     case ForInFeedback::kEnumCacheKeysAndIndices:
    244       return ForInHint::kEnumCacheKeysAndIndices;
    245     default:
    246       return ForInHint::kAny;
    247   }
    248   UNREACHABLE();
    249 }
    250 
    251 void FeedbackVector::ComputeCounts(int* with_type_info, int* generic,
    252                                    int* vector_ic_count) {
    253   MaybeObject* megamorphic_sentinel = MaybeObject::FromObject(
    254       *FeedbackVector::MegamorphicSentinel(GetIsolate()));
    255   int with = 0;
    256   int gen = 0;
    257   int total = 0;
    258   FeedbackMetadataIterator iter(metadata());
    259   while (iter.HasNext()) {
    260     FeedbackSlot slot = iter.Next();
    261     FeedbackSlotKind kind = iter.kind();
    262 
    263     MaybeObject* const obj = Get(slot);
    264     AssertNoLegacyTypes(obj);
    265     switch (kind) {
    266       case FeedbackSlotKind::kCall:
    267       case FeedbackSlotKind::kLoadProperty:
    268       case FeedbackSlotKind::kLoadGlobalInsideTypeof:
    269       case FeedbackSlotKind::kLoadGlobalNotInsideTypeof:
    270       case FeedbackSlotKind::kLoadKeyed:
    271       case FeedbackSlotKind::kStoreNamedSloppy:
    272       case FeedbackSlotKind::kStoreNamedStrict:
    273       case FeedbackSlotKind::kStoreOwnNamed:
    274       case FeedbackSlotKind::kStoreGlobalSloppy:
    275       case FeedbackSlotKind::kStoreGlobalStrict:
    276       case FeedbackSlotKind::kStoreKeyedSloppy:
    277       case FeedbackSlotKind::kStoreKeyedStrict:
    278       case FeedbackSlotKind::kStoreInArrayLiteral:
    279       case FeedbackSlotKind::kStoreDataPropertyInLiteral:
    280       case FeedbackSlotKind::kTypeProfile: {
    281         HeapObject* heap_object;
    282         if (obj->IsWeakOrClearedHeapObject() ||
    283             (obj->ToStrongHeapObject(&heap_object) &&
    284              (heap_object->IsWeakFixedArray() || heap_object->IsString()))) {
    285           with++;
    286         } else if (obj == megamorphic_sentinel) {
    287           gen++;
    288           with++;
    289         }
    290         total++;
    291         break;
    292       }
    293       case FeedbackSlotKind::kBinaryOp: {
    294         int const feedback = Smi::ToInt(obj->ToSmi());
    295         BinaryOperationHint hint = BinaryOperationHintFromFeedback(feedback);
    296         if (hint == BinaryOperationHint::kAny) {
    297           gen++;
    298         }
    299         if (hint != BinaryOperationHint::kNone) {
    300           with++;
    301         }
    302         total++;
    303         break;
    304       }
    305       case FeedbackSlotKind::kCompareOp: {
    306         int const feedback = Smi::ToInt(obj->ToSmi());
    307         CompareOperationHint hint = CompareOperationHintFromFeedback(feedback);
    308         if (hint == CompareOperationHint::kAny) {
    309           gen++;
    310         }
    311         if (hint != CompareOperationHint::kNone) {
    312           with++;
    313         }
    314         total++;
    315         break;
    316       }
    317       case FeedbackSlotKind::kForIn: {
    318         int const feedback = Smi::ToInt(obj->ToSmi());
    319         ForInHint hint = ForInHintFromFeedback(feedback);
    320         if (hint == ForInHint::kAny) {
    321           gen++;
    322         }
    323         if (hint != ForInHint::kNone) {
    324           with++;
    325         }
    326         total++;
    327         break;
    328       }
    329       case FeedbackSlotKind::kInstanceOf: {
    330         if (obj->IsWeakOrClearedHeapObject()) {
    331           with++;
    332         } else if (obj == megamorphic_sentinel) {
    333           gen++;
    334           with++;
    335         }
    336         total++;
    337         break;
    338       }
    339       case FeedbackSlotKind::kCreateClosure:
    340       case FeedbackSlotKind::kLiteral:
    341       case FeedbackSlotKind::kCloneObject:
    342         break;
    343       case FeedbackSlotKind::kInvalid:
    344       case FeedbackSlotKind::kKindsNumber:
    345         UNREACHABLE();
    346         break;
    347     }
    348   }
    349 
    350   *with_type_info = with;
    351   *generic = gen;
    352   *vector_ic_count = total;
    353 }
    354 
    355 Handle<Symbol> FeedbackVector::UninitializedSentinel(Isolate* isolate) {
    356   return isolate->factory()->uninitialized_symbol();
    357 }
    358 
    359 Handle<Symbol> FeedbackVector::GenericSentinel(Isolate* isolate) {
    360   return isolate->factory()->generic_symbol();
    361 }
    362 
    363 Handle<Symbol> FeedbackVector::MegamorphicSentinel(Isolate* isolate) {
    364   return isolate->factory()->megamorphic_symbol();
    365 }
    366 
    367 Handle<Symbol> FeedbackVector::PremonomorphicSentinel(Isolate* isolate) {
    368   return isolate->factory()->premonomorphic_symbol();
    369 }
    370 
    371 Symbol* FeedbackVector::RawUninitializedSentinel(Isolate* isolate) {
    372   return ReadOnlyRoots(isolate).uninitialized_symbol();
    373 }
    374 
    375 bool FeedbackMetadataIterator::HasNext() const {
    376   return next_slot_.ToInt() < metadata()->slot_count();
    377 }
    378 
    379 FeedbackSlot FeedbackMetadataIterator::Next() {
    380   DCHECK(HasNext());
    381   cur_slot_ = next_slot_;
    382   slot_kind_ = metadata()->GetKind(cur_slot_);
    383   next_slot_ = FeedbackSlot(next_slot_.ToInt() + entry_size());
    384   return cur_slot_;
    385 }
    386 
    387 int FeedbackMetadataIterator::entry_size() const {
    388   return FeedbackMetadata::GetSlotSize(kind());
    389 }
    390 
    391 MaybeObject* FeedbackNexus::GetFeedback() const {
    392   MaybeObject* feedback = vector()->Get(slot());
    393   FeedbackVector::AssertNoLegacyTypes(feedback);
    394   return feedback;
    395 }
    396 
    397 MaybeObject* FeedbackNexus::GetFeedbackExtra() const {
    398 #ifdef DEBUG
    399   FeedbackSlotKind kind = vector()->GetKind(slot());
    400   DCHECK_LT(1, FeedbackMetadata::GetSlotSize(kind));
    401 #endif
    402   int extra_index = vector()->GetIndex(slot()) + 1;
    403   return vector()->get(extra_index);
    404 }
    405 
    406 void FeedbackNexus::SetFeedback(Object* feedback, WriteBarrierMode mode) {
    407   SetFeedback(MaybeObject::FromObject(feedback));
    408 }
    409 
    410 void FeedbackNexus::SetFeedback(MaybeObject* feedback, WriteBarrierMode mode) {
    411   FeedbackVector::AssertNoLegacyTypes(feedback);
    412   vector()->Set(slot(), feedback, mode);
    413 }
    414 
    415 void FeedbackNexus::SetFeedbackExtra(Object* feedback_extra,
    416                                      WriteBarrierMode mode) {
    417 #ifdef DEBUG
    418   FeedbackSlotKind kind = vector()->GetKind(slot());
    419   DCHECK_LT(1, FeedbackMetadata::GetSlotSize(kind));
    420   FeedbackVector::AssertNoLegacyTypes(MaybeObject::FromObject(feedback_extra));
    421 #endif
    422   int index = vector()->GetIndex(slot()) + 1;
    423   vector()->set(index, MaybeObject::FromObject(feedback_extra), mode);
    424 }
    425 
    426 void FeedbackNexus::SetFeedbackExtra(MaybeObject* feedback_extra,
    427                                      WriteBarrierMode mode) {
    428 #ifdef DEBUG
    429   FeedbackVector::AssertNoLegacyTypes(feedback_extra);
    430 #endif
    431   int index = vector()->GetIndex(slot()) + 1;
    432   vector()->set(index, feedback_extra, mode);
    433 }
    434 
    435 Isolate* FeedbackNexus::GetIsolate() const { return vector()->GetIsolate(); }
    436 }  // namespace internal
    437 }  // namespace v8
    438 
    439 #include "src/objects/object-macros-undef.h"
    440 
    441 #endif  // V8_FEEDBACK_VECTOR_INL_H_
    442