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 #ifndef V8_TYPE_FEEDBACK_VECTOR_H_
      6 #define V8_TYPE_FEEDBACK_VECTOR_H_
      7 
      8 #include <vector>
      9 
     10 #include "src/base/logging.h"
     11 #include "src/elements-kind.h"
     12 #include "src/objects.h"
     13 #include "src/zone-containers.h"
     14 
     15 namespace v8 {
     16 namespace internal {
     17 
     18 
     19 enum class FeedbackVectorSlotKind {
     20   // This kind means that the slot points to the middle of other slot
     21   // which occupies more than one feedback vector element.
     22   // There must be no such slots in the system.
     23   INVALID,
     24 
     25   CALL_IC,
     26   LOAD_IC,
     27   KEYED_LOAD_IC,
     28   STORE_IC,
     29   KEYED_STORE_IC,
     30 
     31   // This is a general purpose slot that occupies one feedback vector element.
     32   GENERAL,
     33 
     34   KINDS_NUMBER  // Last value indicating number of kinds.
     35 };
     36 
     37 
     38 std::ostream& operator<<(std::ostream& os, FeedbackVectorSlotKind kind);
     39 
     40 
     41 template <typename Derived>
     42 class FeedbackVectorSpecBase {
     43  public:
     44   inline FeedbackVectorSlot AddSlot(FeedbackVectorSlotKind kind);
     45 
     46   FeedbackVectorSlot AddCallICSlot() {
     47     return AddSlot(FeedbackVectorSlotKind::CALL_IC);
     48   }
     49 
     50   FeedbackVectorSlot AddLoadICSlot() {
     51     return AddSlot(FeedbackVectorSlotKind::LOAD_IC);
     52   }
     53 
     54   FeedbackVectorSlot AddKeyedLoadICSlot() {
     55     return AddSlot(FeedbackVectorSlotKind::KEYED_LOAD_IC);
     56   }
     57 
     58   FeedbackVectorSlot AddStoreICSlot() {
     59     return AddSlot(FeedbackVectorSlotKind::STORE_IC);
     60   }
     61 
     62   FeedbackVectorSlot AddKeyedStoreICSlot() {
     63     return AddSlot(FeedbackVectorSlotKind::KEYED_STORE_IC);
     64   }
     65 
     66   FeedbackVectorSlot AddGeneralSlot() {
     67     return AddSlot(FeedbackVectorSlotKind::GENERAL);
     68   }
     69 };
     70 
     71 
     72 class StaticFeedbackVectorSpec
     73     : public FeedbackVectorSpecBase<StaticFeedbackVectorSpec> {
     74  public:
     75   StaticFeedbackVectorSpec() : slots_(0) {}
     76 
     77   int slots() const { return slots_; }
     78 
     79   FeedbackVectorSlotKind GetKind(int slot) const {
     80     DCHECK(slot >= 0 && slot < slots_);
     81     return kinds_[slot];
     82   }
     83 
     84  private:
     85   friend class FeedbackVectorSpecBase<StaticFeedbackVectorSpec>;
     86 
     87   void append(FeedbackVectorSlotKind kind) {
     88     DCHECK(slots_ < kMaxLength);
     89     kinds_[slots_++] = kind;
     90   }
     91 
     92   static const int kMaxLength = 12;
     93 
     94   int slots_;
     95   FeedbackVectorSlotKind kinds_[kMaxLength];
     96 };
     97 
     98 
     99 class FeedbackVectorSpec : public FeedbackVectorSpecBase<FeedbackVectorSpec> {
    100  public:
    101   explicit FeedbackVectorSpec(Zone* zone) : slot_kinds_(zone) {
    102     slot_kinds_.reserve(16);
    103   }
    104 
    105   int slots() const { return static_cast<int>(slot_kinds_.size()); }
    106 
    107   FeedbackVectorSlotKind GetKind(int slot) const {
    108     return static_cast<FeedbackVectorSlotKind>(slot_kinds_.at(slot));
    109   }
    110 
    111  private:
    112   friend class FeedbackVectorSpecBase<FeedbackVectorSpec>;
    113 
    114   void append(FeedbackVectorSlotKind kind) {
    115     slot_kinds_.push_back(static_cast<unsigned char>(kind));
    116   }
    117 
    118   ZoneVector<unsigned char> slot_kinds_;
    119 };
    120 
    121 
    122 // The shape of the TypeFeedbackMetadata is an array with:
    123 // 0: slot_count
    124 // 1..N: slot kinds packed into a bit vector
    125 //
    126 class TypeFeedbackMetadata : public FixedArray {
    127  public:
    128   // Casting.
    129   static inline TypeFeedbackMetadata* cast(Object* obj);
    130 
    131   static const int kSlotsCountIndex = 0;
    132   static const int kReservedIndexCount = 1;
    133 
    134   // Returns number of feedback vector elements used by given slot kind.
    135   static inline int GetSlotSize(FeedbackVectorSlotKind kind);
    136 
    137   bool SpecDiffersFrom(const FeedbackVectorSpec* other_spec) const;
    138 
    139   // Returns number of slots in the vector.
    140   inline int slot_count() const;
    141 
    142   // Returns slot kind for given slot.
    143   FeedbackVectorSlotKind GetKind(FeedbackVectorSlot slot) const;
    144 
    145   template <typename Spec>
    146   static Handle<TypeFeedbackMetadata> New(Isolate* isolate, const Spec* spec);
    147 
    148 #ifdef OBJECT_PRINT
    149   // For gdb debugging.
    150   void Print();
    151 #endif  // OBJECT_PRINT
    152 
    153   DECLARE_PRINTER(TypeFeedbackMetadata)
    154 
    155   static const char* Kind2String(FeedbackVectorSlotKind kind);
    156 
    157  private:
    158   static const int kFeedbackVectorSlotKindBits = 3;
    159   STATIC_ASSERT(static_cast<int>(FeedbackVectorSlotKind::KINDS_NUMBER) <
    160                 (1 << kFeedbackVectorSlotKindBits));
    161 
    162   void SetKind(FeedbackVectorSlot slot, FeedbackVectorSlotKind kind);
    163 
    164   typedef BitSetComputer<FeedbackVectorSlotKind, kFeedbackVectorSlotKindBits,
    165                          kSmiValueSize, uint32_t> VectorICComputer;
    166 
    167   DISALLOW_IMPLICIT_CONSTRUCTORS(TypeFeedbackMetadata);
    168 };
    169 
    170 
    171 // The shape of the TypeFeedbackVector is an array with:
    172 // 0: feedback metadata
    173 // 1: ics_with_types
    174 // 2: ics_with_generic_info
    175 // 3: feedback slot #0 (N >= 3)
    176 // ...
    177 // N + slot_count - 1: feedback slot #(slot_count-1)
    178 //
    179 class TypeFeedbackVector : public FixedArray {
    180  public:
    181   // Casting.
    182   static inline TypeFeedbackVector* cast(Object* obj);
    183 
    184   static const int kMetadataIndex = 0;
    185   static const int kReservedIndexCount = 1;
    186 
    187   inline void ComputeCounts(int* with_type_info, int* generic);
    188 
    189   inline bool is_empty() const;
    190 
    191   // Returns number of slots in the vector.
    192   inline int slot_count() const;
    193 
    194   inline TypeFeedbackMetadata* metadata() const;
    195 
    196   // Conversion from a slot to an integer index to the underlying array.
    197   inline int GetIndex(FeedbackVectorSlot slot) const;
    198   static int GetIndexFromSpec(const FeedbackVectorSpec* spec,
    199                               FeedbackVectorSlot slot);
    200 
    201   // Conversion from an integer index to the underlying array to a slot.
    202   inline FeedbackVectorSlot ToSlot(int index) const;
    203   inline Object* Get(FeedbackVectorSlot slot) const;
    204   inline void Set(FeedbackVectorSlot slot, Object* value,
    205                   WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
    206 
    207   // Returns slot kind for given slot.
    208   inline FeedbackVectorSlotKind GetKind(FeedbackVectorSlot slot) const;
    209 
    210   static Handle<TypeFeedbackVector> New(Isolate* isolate,
    211                                         Handle<TypeFeedbackMetadata> metadata);
    212 
    213   static Handle<TypeFeedbackVector> Copy(Isolate* isolate,
    214                                          Handle<TypeFeedbackVector> vector);
    215 
    216 #ifdef OBJECT_PRINT
    217   // For gdb debugging.
    218   void Print();
    219 #endif  // OBJECT_PRINT
    220 
    221   DECLARE_PRINTER(TypeFeedbackVector)
    222 
    223   // Clears the vector slots.
    224   void ClearSlots(SharedFunctionInfo* shared) { ClearSlotsImpl(shared, true); }
    225 
    226   void ClearSlotsAtGCTime(SharedFunctionInfo* shared) {
    227     ClearSlotsImpl(shared, false);
    228   }
    229 
    230   static void ClearAllKeyedStoreICs(Isolate* isolate);
    231   void ClearKeyedStoreICs(SharedFunctionInfo* shared);
    232 
    233   // The object that indicates an uninitialized cache.
    234   static inline Handle<Object> UninitializedSentinel(Isolate* isolate);
    235 
    236   // The object that indicates a megamorphic state.
    237   static inline Handle<Object> MegamorphicSentinel(Isolate* isolate);
    238 
    239   // The object that indicates a premonomorphic state.
    240   static inline Handle<Object> PremonomorphicSentinel(Isolate* isolate);
    241 
    242   // A raw version of the uninitialized sentinel that's safe to read during
    243   // garbage collection (e.g., for patching the cache).
    244   static inline Object* RawUninitializedSentinel(Isolate* isolate);
    245 
    246   static const int kDummyLoadICSlot = 0;
    247   static const int kDummyKeyedLoadICSlot = 2;
    248   static const int kDummyStoreICSlot = 4;
    249   static const int kDummyKeyedStoreICSlot = 6;
    250 
    251   static Handle<TypeFeedbackVector> DummyVector(Isolate* isolate);
    252   static FeedbackVectorSlot DummySlot(int dummyIndex) {
    253     DCHECK(dummyIndex >= 0 && dummyIndex <= kDummyKeyedStoreICSlot);
    254     return FeedbackVectorSlot(dummyIndex);
    255   }
    256 
    257  private:
    258   void ClearSlotsImpl(SharedFunctionInfo* shared, bool force_clear);
    259 
    260   DISALLOW_IMPLICIT_CONSTRUCTORS(TypeFeedbackVector);
    261 };
    262 
    263 
    264 // The following asserts protect an optimization in type feedback vector
    265 // code that looks into the contents of a slot assuming to find a String,
    266 // a Symbol, an AllocationSite, a WeakCell, or a FixedArray.
    267 STATIC_ASSERT(WeakCell::kSize >= 2 * kPointerSize);
    268 STATIC_ASSERT(WeakCell::kValueOffset == AllocationSite::kTransitionInfoOffset);
    269 STATIC_ASSERT(WeakCell::kValueOffset == FixedArray::kLengthOffset);
    270 STATIC_ASSERT(WeakCell::kValueOffset == Name::kHashFieldSlot);
    271 // Verify that an empty hash field looks like a tagged object, but can't
    272 // possibly be confused with a pointer.
    273 STATIC_ASSERT((Name::kEmptyHashField & kHeapObjectTag) == kHeapObjectTag);
    274 STATIC_ASSERT(Name::kEmptyHashField == 0x3);
    275 // Verify that a set hash field will not look like a tagged object.
    276 STATIC_ASSERT(Name::kHashNotComputedMask == kHeapObjectTag);
    277 
    278 
    279 class TypeFeedbackMetadataIterator {
    280  public:
    281   explicit TypeFeedbackMetadataIterator(Handle<TypeFeedbackMetadata> metadata)
    282       : metadata_handle_(metadata),
    283         slot_(FeedbackVectorSlot(0)),
    284         slot_kind_(FeedbackVectorSlotKind::INVALID) {}
    285 
    286   explicit TypeFeedbackMetadataIterator(TypeFeedbackMetadata* metadata)
    287       : metadata_(metadata),
    288         slot_(FeedbackVectorSlot(0)),
    289         slot_kind_(FeedbackVectorSlotKind::INVALID) {}
    290 
    291   bool HasNext() const { return slot_.ToInt() < metadata()->slot_count(); }
    292 
    293   FeedbackVectorSlot Next() {
    294     DCHECK(HasNext());
    295     FeedbackVectorSlot slot = slot_;
    296     slot_kind_ = metadata()->GetKind(slot);
    297     slot_ = FeedbackVectorSlot(slot_.ToInt() + entry_size());
    298     return slot;
    299   }
    300 
    301   // Returns slot kind of the last slot returned by Next().
    302   FeedbackVectorSlotKind kind() const {
    303     DCHECK_NE(FeedbackVectorSlotKind::INVALID, slot_kind_);
    304     DCHECK_NE(FeedbackVectorSlotKind::KINDS_NUMBER, slot_kind_);
    305     return slot_kind_;
    306   }
    307 
    308   // Returns entry size of the last slot returned by Next().
    309   int entry_size() const { return TypeFeedbackMetadata::GetSlotSize(kind()); }
    310 
    311  private:
    312   TypeFeedbackMetadata* metadata() const {
    313     return !metadata_handle_.is_null() ? *metadata_handle_ : metadata_;
    314   }
    315 
    316   // The reason for having a handle and a raw pointer to the meta data is
    317   // to have a single iterator implementation for both "handlified" and raw
    318   // pointer use cases.
    319   Handle<TypeFeedbackMetadata> metadata_handle_;
    320   TypeFeedbackMetadata* metadata_;
    321   FeedbackVectorSlot slot_;
    322   FeedbackVectorSlotKind slot_kind_;
    323 };
    324 
    325 
    326 // A FeedbackNexus is the combination of a TypeFeedbackVector and a slot.
    327 // Derived classes customize the update and retrieval of feedback.
    328 class FeedbackNexus {
    329  public:
    330   FeedbackNexus(Handle<TypeFeedbackVector> vector, FeedbackVectorSlot slot)
    331       : vector_handle_(vector), vector_(NULL), slot_(slot) {}
    332   FeedbackNexus(TypeFeedbackVector* vector, FeedbackVectorSlot slot)
    333       : vector_(vector), slot_(slot) {}
    334   virtual ~FeedbackNexus() {}
    335 
    336   Handle<TypeFeedbackVector> vector_handle() const {
    337     DCHECK(vector_ == NULL);
    338     return vector_handle_;
    339   }
    340   TypeFeedbackVector* vector() const {
    341     return vector_handle_.is_null() ? vector_ : *vector_handle_;
    342   }
    343   FeedbackVectorSlot slot() const { return slot_; }
    344 
    345   InlineCacheState ic_state() const { return StateFromFeedback(); }
    346   Map* FindFirstMap() const {
    347     MapHandleList maps;
    348     ExtractMaps(&maps);
    349     if (maps.length() > 0) return *maps.at(0);
    350     return NULL;
    351   }
    352 
    353   // TODO(mvstanton): remove FindAllMaps, it didn't survive a code review.
    354   void FindAllMaps(MapHandleList* maps) const { ExtractMaps(maps); }
    355 
    356   virtual InlineCacheState StateFromFeedback() const = 0;
    357   virtual int ExtractMaps(MapHandleList* maps) const;
    358   virtual MaybeHandle<Code> FindHandlerForMap(Handle<Map> map) const;
    359   virtual bool FindHandlers(CodeHandleList* code_list, int length = -1) const;
    360   virtual Name* FindFirstName() const { return NULL; }
    361 
    362   virtual void ConfigureUninitialized();
    363   virtual void ConfigurePremonomorphic();
    364   virtual void ConfigureMegamorphic();
    365 
    366   inline Object* GetFeedback() const;
    367   inline Object* GetFeedbackExtra() const;
    368 
    369   inline Isolate* GetIsolate() const;
    370 
    371  protected:
    372   inline void SetFeedback(Object* feedback,
    373                           WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
    374   inline void SetFeedbackExtra(Object* feedback_extra,
    375                                WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
    376 
    377   Handle<FixedArray> EnsureArrayOfSize(int length);
    378   Handle<FixedArray> EnsureExtraArrayOfSize(int length);
    379   void InstallHandlers(Handle<FixedArray> array, MapHandleList* maps,
    380                        CodeHandleList* handlers);
    381 
    382  private:
    383   // The reason for having a vector handle and a raw pointer is that we can and
    384   // should use handles during IC miss, but not during GC when we clear ICs. If
    385   // you have a handle to the vector that is better because more operations can
    386   // be done, like allocation.
    387   Handle<TypeFeedbackVector> vector_handle_;
    388   TypeFeedbackVector* vector_;
    389   FeedbackVectorSlot slot_;
    390 };
    391 
    392 
    393 class CallICNexus final : public FeedbackNexus {
    394  public:
    395   // Monomorphic call ics store call counts. Platform code needs to increment
    396   // the count appropriately (ie, by 2).
    397   static const int kCallCountIncrement = 2;
    398 
    399   CallICNexus(Handle<TypeFeedbackVector> vector, FeedbackVectorSlot slot)
    400       : FeedbackNexus(vector, slot) {
    401     DCHECK_EQ(FeedbackVectorSlotKind::CALL_IC, vector->GetKind(slot));
    402   }
    403   CallICNexus(TypeFeedbackVector* vector, FeedbackVectorSlot slot)
    404       : FeedbackNexus(vector, slot) {
    405     DCHECK_EQ(FeedbackVectorSlotKind::CALL_IC, vector->GetKind(slot));
    406   }
    407 
    408   void Clear(Code* host);
    409 
    410   void ConfigureMonomorphicArray();
    411   void ConfigureMonomorphic(Handle<JSFunction> function);
    412   void ConfigureMegamorphic() final;
    413   void ConfigureMegamorphic(int call_count);
    414 
    415   InlineCacheState StateFromFeedback() const final;
    416 
    417   int ExtractMaps(MapHandleList* maps) const final {
    418     // CallICs don't record map feedback.
    419     return 0;
    420   }
    421   MaybeHandle<Code> FindHandlerForMap(Handle<Map> map) const final {
    422     return MaybeHandle<Code>();
    423   }
    424   bool FindHandlers(CodeHandleList* code_list, int length = -1) const final {
    425     return length == 0;
    426   }
    427 
    428   int ExtractCallCount();
    429 };
    430 
    431 
    432 class LoadICNexus : public FeedbackNexus {
    433  public:
    434   LoadICNexus(Handle<TypeFeedbackVector> vector, FeedbackVectorSlot slot)
    435       : FeedbackNexus(vector, slot) {
    436     DCHECK_EQ(FeedbackVectorSlotKind::LOAD_IC, vector->GetKind(slot));
    437   }
    438   explicit LoadICNexus(Isolate* isolate)
    439       : FeedbackNexus(
    440             TypeFeedbackVector::DummyVector(isolate),
    441             FeedbackVectorSlot(TypeFeedbackVector::kDummyLoadICSlot)) {}
    442   LoadICNexus(TypeFeedbackVector* vector, FeedbackVectorSlot slot)
    443       : FeedbackNexus(vector, slot) {
    444     DCHECK_EQ(FeedbackVectorSlotKind::LOAD_IC, vector->GetKind(slot));
    445   }
    446 
    447   void Clear(Code* host);
    448 
    449   void ConfigureMonomorphic(Handle<Map> receiver_map, Handle<Code> handler);
    450 
    451   void ConfigurePolymorphic(MapHandleList* maps, CodeHandleList* handlers);
    452 
    453   InlineCacheState StateFromFeedback() const override;
    454 };
    455 
    456 
    457 class KeyedLoadICNexus : public FeedbackNexus {
    458  public:
    459   KeyedLoadICNexus(Handle<TypeFeedbackVector> vector, FeedbackVectorSlot slot)
    460       : FeedbackNexus(vector, slot) {
    461     DCHECK_EQ(FeedbackVectorSlotKind::KEYED_LOAD_IC, vector->GetKind(slot));
    462   }
    463   KeyedLoadICNexus(TypeFeedbackVector* vector, FeedbackVectorSlot slot)
    464       : FeedbackNexus(vector, slot) {
    465     DCHECK_EQ(FeedbackVectorSlotKind::KEYED_LOAD_IC, vector->GetKind(slot));
    466   }
    467 
    468   void Clear(Code* host);
    469 
    470   // name can be a null handle for element loads.
    471   void ConfigureMonomorphic(Handle<Name> name, Handle<Map> receiver_map,
    472                             Handle<Code> handler);
    473   // name can be null.
    474   void ConfigurePolymorphic(Handle<Name> name, MapHandleList* maps,
    475                             CodeHandleList* handlers);
    476 
    477   InlineCacheState StateFromFeedback() const override;
    478   Name* FindFirstName() const override;
    479 };
    480 
    481 
    482 class StoreICNexus : public FeedbackNexus {
    483  public:
    484   StoreICNexus(Handle<TypeFeedbackVector> vector, FeedbackVectorSlot slot)
    485       : FeedbackNexus(vector, slot) {
    486     DCHECK_EQ(FeedbackVectorSlotKind::STORE_IC, vector->GetKind(slot));
    487   }
    488   explicit StoreICNexus(Isolate* isolate)
    489       : FeedbackNexus(
    490             TypeFeedbackVector::DummyVector(isolate),
    491             FeedbackVectorSlot(TypeFeedbackVector::kDummyStoreICSlot)) {}
    492   StoreICNexus(TypeFeedbackVector* vector, FeedbackVectorSlot slot)
    493       : FeedbackNexus(vector, slot) {
    494     DCHECK_EQ(FeedbackVectorSlotKind::STORE_IC, vector->GetKind(slot));
    495   }
    496 
    497   void Clear(Code* host);
    498 
    499   void ConfigureMonomorphic(Handle<Map> receiver_map, Handle<Code> handler);
    500 
    501   void ConfigurePolymorphic(MapHandleList* maps, CodeHandleList* handlers);
    502 
    503   InlineCacheState StateFromFeedback() const override;
    504 };
    505 
    506 
    507 class KeyedStoreICNexus : public FeedbackNexus {
    508  public:
    509   KeyedStoreICNexus(Handle<TypeFeedbackVector> vector, FeedbackVectorSlot slot)
    510       : FeedbackNexus(vector, slot) {
    511     DCHECK_EQ(FeedbackVectorSlotKind::KEYED_STORE_IC, vector->GetKind(slot));
    512   }
    513   explicit KeyedStoreICNexus(Isolate* isolate)
    514       : FeedbackNexus(
    515             TypeFeedbackVector::DummyVector(isolate),
    516             FeedbackVectorSlot(TypeFeedbackVector::kDummyKeyedStoreICSlot)) {}
    517   KeyedStoreICNexus(TypeFeedbackVector* vector, FeedbackVectorSlot slot)
    518       : FeedbackNexus(vector, slot) {
    519     DCHECK_EQ(FeedbackVectorSlotKind::KEYED_STORE_IC, vector->GetKind(slot));
    520   }
    521 
    522   void Clear(Code* host);
    523 
    524   // name can be a null handle for element loads.
    525   void ConfigureMonomorphic(Handle<Name> name, Handle<Map> receiver_map,
    526                             Handle<Code> handler);
    527   // name can be null.
    528   void ConfigurePolymorphic(Handle<Name> name, MapHandleList* maps,
    529                             CodeHandleList* handlers);
    530   void ConfigurePolymorphic(MapHandleList* maps,
    531                             MapHandleList* transitioned_maps,
    532                             CodeHandleList* handlers);
    533 
    534   KeyedAccessStoreMode GetKeyedAccessStoreMode() const;
    535   IcCheckType GetKeyType() const;
    536 
    537   InlineCacheState StateFromFeedback() const override;
    538   Name* FindFirstName() const override;
    539 };
    540 }  // namespace internal
    541 }  // namespace v8
    542 
    543 #endif  // V8_TRANSITIONS_H_
    544