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 AddCallICSlot()46 FeedbackVectorSlot AddCallICSlot() { 47 return AddSlot(FeedbackVectorSlotKind::CALL_IC); 48 } 49 AddLoadICSlot()50 FeedbackVectorSlot AddLoadICSlot() { 51 return AddSlot(FeedbackVectorSlotKind::LOAD_IC); 52 } 53 AddKeyedLoadICSlot()54 FeedbackVectorSlot AddKeyedLoadICSlot() { 55 return AddSlot(FeedbackVectorSlotKind::KEYED_LOAD_IC); 56 } 57 AddStoreICSlot()58 FeedbackVectorSlot AddStoreICSlot() { 59 return AddSlot(FeedbackVectorSlotKind::STORE_IC); 60 } 61 AddKeyedStoreICSlot()62 FeedbackVectorSlot AddKeyedStoreICSlot() { 63 return AddSlot(FeedbackVectorSlotKind::KEYED_STORE_IC); 64 } 65 AddGeneralSlot()66 FeedbackVectorSlot AddGeneralSlot() { 67 return AddSlot(FeedbackVectorSlotKind::GENERAL); 68 } 69 }; 70 71 72 class StaticFeedbackVectorSpec 73 : public FeedbackVectorSpecBase<StaticFeedbackVectorSpec> { 74 public: StaticFeedbackVectorSpec()75 StaticFeedbackVectorSpec() : slots_(0) {} 76 slots()77 int slots() const { return slots_; } 78 GetKind(int slot)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 append(FeedbackVectorSlotKind kind)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: FeedbackVectorSpec(Zone * zone)101 explicit FeedbackVectorSpec(Zone* zone) : slot_kinds_(zone) { 102 slot_kinds_.reserve(16); 103 } 104 slots()105 int slots() const { return static_cast<int>(slot_kinds_.size()); } 106 GetKind(int slot)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 append(FeedbackVectorSlotKind kind)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 DECLARE_PRINTER(TypeFeedbackVector)221 DECLARE_PRINTER(TypeFeedbackVector) 222 223 // Clears the vector slots. 224 void ClearSlots(SharedFunctionInfo* shared) { ClearSlotsImpl(shared, true); } 225 ClearSlotsAtGCTime(SharedFunctionInfo * shared)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); DummySlot(int dummyIndex)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: TypeFeedbackMetadataIterator(Handle<TypeFeedbackMetadata> metadata)281 explicit TypeFeedbackMetadataIterator(Handle<TypeFeedbackMetadata> metadata) 282 : metadata_handle_(metadata), 283 slot_(FeedbackVectorSlot(0)), 284 slot_kind_(FeedbackVectorSlotKind::INVALID) {} 285 TypeFeedbackMetadataIterator(TypeFeedbackMetadata * metadata)286 explicit TypeFeedbackMetadataIterator(TypeFeedbackMetadata* metadata) 287 : metadata_(metadata), 288 slot_(FeedbackVectorSlot(0)), 289 slot_kind_(FeedbackVectorSlotKind::INVALID) {} 290 HasNext()291 bool HasNext() const { return slot_.ToInt() < metadata()->slot_count(); } 292 Next()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(). kind()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(). entry_size()309 int entry_size() const { return TypeFeedbackMetadata::GetSlotSize(kind()); } 310 311 private: metadata()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: FeedbackNexus(Handle<TypeFeedbackVector> vector,FeedbackVectorSlot slot)330 FeedbackNexus(Handle<TypeFeedbackVector> vector, FeedbackVectorSlot slot) 331 : vector_handle_(vector), vector_(NULL), slot_(slot) {} FeedbackNexus(TypeFeedbackVector * vector,FeedbackVectorSlot slot)332 FeedbackNexus(TypeFeedbackVector* vector, FeedbackVectorSlot slot) 333 : vector_(vector), slot_(slot) {} ~FeedbackNexus()334 virtual ~FeedbackNexus() {} 335 vector_handle()336 Handle<TypeFeedbackVector> vector_handle() const { 337 DCHECK(vector_ == NULL); 338 return vector_handle_; 339 } vector()340 TypeFeedbackVector* vector() const { 341 return vector_handle_.is_null() ? vector_ : *vector_handle_; 342 } slot()343 FeedbackVectorSlot slot() const { return slot_; } 344 ic_state()345 InlineCacheState ic_state() const { return StateFromFeedback(); } FindFirstMap()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. FindAllMaps(MapHandleList * maps)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; FindFirstName()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 CallICNexus(Handle<TypeFeedbackVector> vector,FeedbackVectorSlot slot)399 CallICNexus(Handle<TypeFeedbackVector> vector, FeedbackVectorSlot slot) 400 : FeedbackNexus(vector, slot) { 401 DCHECK_EQ(FeedbackVectorSlotKind::CALL_IC, vector->GetKind(slot)); 402 } CallICNexus(TypeFeedbackVector * vector,FeedbackVectorSlot slot)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 ExtractMaps(MapHandleList * maps)417 int ExtractMaps(MapHandleList* maps) const final { 418 // CallICs don't record map feedback. 419 return 0; 420 } FindHandlerForMap(Handle<Map> map)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: LoadICNexus(Handle<TypeFeedbackVector> vector,FeedbackVectorSlot slot)434 LoadICNexus(Handle<TypeFeedbackVector> vector, FeedbackVectorSlot slot) 435 : FeedbackNexus(vector, slot) { 436 DCHECK_EQ(FeedbackVectorSlotKind::LOAD_IC, vector->GetKind(slot)); 437 } LoadICNexus(Isolate * isolate)438 explicit LoadICNexus(Isolate* isolate) 439 : FeedbackNexus( 440 TypeFeedbackVector::DummyVector(isolate), 441 FeedbackVectorSlot(TypeFeedbackVector::kDummyLoadICSlot)) {} LoadICNexus(TypeFeedbackVector * vector,FeedbackVectorSlot slot)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: KeyedLoadICNexus(Handle<TypeFeedbackVector> vector,FeedbackVectorSlot slot)459 KeyedLoadICNexus(Handle<TypeFeedbackVector> vector, FeedbackVectorSlot slot) 460 : FeedbackNexus(vector, slot) { 461 DCHECK_EQ(FeedbackVectorSlotKind::KEYED_LOAD_IC, vector->GetKind(slot)); 462 } KeyedLoadICNexus(TypeFeedbackVector * vector,FeedbackVectorSlot slot)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: StoreICNexus(Handle<TypeFeedbackVector> vector,FeedbackVectorSlot slot)484 StoreICNexus(Handle<TypeFeedbackVector> vector, FeedbackVectorSlot slot) 485 : FeedbackNexus(vector, slot) { 486 DCHECK_EQ(FeedbackVectorSlotKind::STORE_IC, vector->GetKind(slot)); 487 } StoreICNexus(Isolate * isolate)488 explicit StoreICNexus(Isolate* isolate) 489 : FeedbackNexus( 490 TypeFeedbackVector::DummyVector(isolate), 491 FeedbackVectorSlot(TypeFeedbackVector::kDummyStoreICSlot)) {} StoreICNexus(TypeFeedbackVector * vector,FeedbackVectorSlot slot)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: KeyedStoreICNexus(Handle<TypeFeedbackVector> vector,FeedbackVectorSlot slot)509 KeyedStoreICNexus(Handle<TypeFeedbackVector> vector, FeedbackVectorSlot slot) 510 : FeedbackNexus(vector, slot) { 511 DCHECK_EQ(FeedbackVectorSlotKind::KEYED_STORE_IC, vector->GetKind(slot)); 512 } KeyedStoreICNexus(Isolate * isolate)513 explicit KeyedStoreICNexus(Isolate* isolate) 514 : FeedbackNexus( 515 TypeFeedbackVector::DummyVector(isolate), 516 FeedbackVectorSlot(TypeFeedbackVector::kDummyKeyedStoreICSlot)) {} KeyedStoreICNexus(TypeFeedbackVector * vector,FeedbackVectorSlot slot)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