| 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_FEEDBACK_VECTOR_H_ |
| 6 | #define V8_FEEDBACK_VECTOR_H_ |
| 7 | |
| 8 | #include <vector> |
| 9 | |
| 10 | #include "src/base/logging.h" |
| 11 | #include "src/base/macros.h" |
| 12 | #include "src/elements-kind.h" |
| 13 | #include "src/globals.h" |
| 14 | #include "src/objects/map.h" |
| 15 | #include "src/objects/name.h" |
| 16 | #include "src/type-hints.h" |
| 17 | #include "src/zone/zone-containers.h" |
| 18 | |
| 19 | // Has to be the last include (doesn't have include guards): |
| 20 | #include "src/objects/object-macros.h" |
| 21 | |
| 22 | namespace v8 { |
| 23 | namespace internal { |
| 24 | |
| 25 | enum class FeedbackSlotKind { |
| 26 | // This kind means that the slot points to the middle of other slot |
| 27 | // which occupies more than one feedback vector element. |
| 28 | // There must be no such slots in the system. |
| 29 | kInvalid, |
| 30 | |
| 31 | // Sloppy kinds come first, for easy language mode testing. |
| 32 | kStoreGlobalSloppy, |
| 33 | kStoreNamedSloppy, |
| 34 | kStoreKeyedSloppy, |
| 35 | kLastSloppyKind = kStoreKeyedSloppy, |
| 36 | |
| 37 | // Strict and language mode unaware kinds. |
| 38 | kCall, |
| 39 | kLoadProperty, |
| 40 | kLoadGlobalNotInsideTypeof, |
| 41 | kLoadGlobalInsideTypeof, |
| 42 | kLoadKeyed, |
| 43 | kHasKeyed, |
| 44 | kStoreGlobalStrict, |
| 45 | kStoreNamedStrict, |
| 46 | kStoreOwnNamed, |
| 47 | kStoreKeyedStrict, |
| 48 | kStoreInArrayLiteral, |
| 49 | kBinaryOp, |
| 50 | kCompareOp, |
| 51 | kStoreDataPropertyInLiteral, |
| 52 | kTypeProfile, |
| 53 | kLiteral, |
| 54 | kForIn, |
| 55 | kInstanceOf, |
| 56 | kCloneObject, |
| 57 | |
| 58 | kKindsNumber // Last value indicating number of kinds. |
| 59 | }; |
| 60 | |
| 61 | inline bool IsCallICKind(FeedbackSlotKind kind) { |
| 62 | return kind == FeedbackSlotKind::kCall; |
| 63 | } |
| 64 | |
| 65 | inline bool IsLoadICKind(FeedbackSlotKind kind) { |
| 66 | return kind == FeedbackSlotKind::kLoadProperty; |
| 67 | } |
| 68 | |
| 69 | inline bool IsLoadGlobalICKind(FeedbackSlotKind kind) { |
| 70 | return kind == FeedbackSlotKind::kLoadGlobalNotInsideTypeof || |
| 71 | kind == FeedbackSlotKind::kLoadGlobalInsideTypeof; |
| 72 | } |
| 73 | |
| 74 | inline bool IsKeyedLoadICKind(FeedbackSlotKind kind) { |
| 75 | return kind == FeedbackSlotKind::kLoadKeyed; |
| 76 | } |
| 77 | |
| 78 | inline bool IsKeyedHasICKind(FeedbackSlotKind kind) { |
| 79 | return kind == FeedbackSlotKind::kHasKeyed; |
| 80 | } |
| 81 | |
| 82 | inline bool IsStoreGlobalICKind(FeedbackSlotKind kind) { |
| 83 | return kind == FeedbackSlotKind::kStoreGlobalSloppy || |
| 84 | kind == FeedbackSlotKind::kStoreGlobalStrict; |
| 85 | } |
| 86 | |
| 87 | inline bool IsStoreICKind(FeedbackSlotKind kind) { |
| 88 | return kind == FeedbackSlotKind::kStoreNamedSloppy || |
| 89 | kind == FeedbackSlotKind::kStoreNamedStrict; |
| 90 | } |
| 91 | |
| 92 | inline bool IsStoreOwnICKind(FeedbackSlotKind kind) { |
| 93 | return kind == FeedbackSlotKind::kStoreOwnNamed; |
| 94 | } |
| 95 | |
| 96 | inline bool IsStoreDataPropertyInLiteralKind(FeedbackSlotKind kind) { |
| 97 | return kind == FeedbackSlotKind::kStoreDataPropertyInLiteral; |
| 98 | } |
| 99 | |
| 100 | inline bool IsKeyedStoreICKind(FeedbackSlotKind kind) { |
| 101 | return kind == FeedbackSlotKind::kStoreKeyedSloppy || |
| 102 | kind == FeedbackSlotKind::kStoreKeyedStrict; |
| 103 | } |
| 104 | |
| 105 | inline bool IsStoreInArrayLiteralICKind(FeedbackSlotKind kind) { |
| 106 | return kind == FeedbackSlotKind::kStoreInArrayLiteral; |
| 107 | } |
| 108 | |
| 109 | inline bool IsGlobalICKind(FeedbackSlotKind kind) { |
| 110 | return IsLoadGlobalICKind(kind) || IsStoreGlobalICKind(kind); |
| 111 | } |
| 112 | |
| 113 | inline bool IsTypeProfileKind(FeedbackSlotKind kind) { |
| 114 | return kind == FeedbackSlotKind::kTypeProfile; |
| 115 | } |
| 116 | |
| 117 | inline bool IsCloneObjectKind(FeedbackSlotKind kind) { |
| 118 | return kind == FeedbackSlotKind::kCloneObject; |
| 119 | } |
| 120 | |
| 121 | inline TypeofMode GetTypeofModeFromSlotKind(FeedbackSlotKind kind) { |
| 122 | DCHECK(IsLoadGlobalICKind(kind)); |
| 123 | return (kind == FeedbackSlotKind::kLoadGlobalInsideTypeof) |
| 124 | ? INSIDE_TYPEOF |
| 125 | : NOT_INSIDE_TYPEOF; |
| 126 | } |
| 127 | |
| 128 | inline LanguageMode GetLanguageModeFromSlotKind(FeedbackSlotKind kind) { |
| 129 | DCHECK(IsStoreICKind(kind) || IsStoreOwnICKind(kind) || |
| 130 | IsStoreGlobalICKind(kind) || IsKeyedStoreICKind(kind)); |
| 131 | STATIC_ASSERT(FeedbackSlotKind::kStoreGlobalSloppy <= |
| 132 | FeedbackSlotKind::kLastSloppyKind); |
| 133 | STATIC_ASSERT(FeedbackSlotKind::kStoreKeyedSloppy <= |
| 134 | FeedbackSlotKind::kLastSloppyKind); |
| 135 | STATIC_ASSERT(FeedbackSlotKind::kStoreNamedSloppy <= |
| 136 | FeedbackSlotKind::kLastSloppyKind); |
| 137 | return (kind <= FeedbackSlotKind::kLastSloppyKind) ? LanguageMode::kSloppy |
| 138 | : LanguageMode::kStrict; |
| 139 | } |
| 140 | |
| 141 | V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os, |
| 142 | FeedbackSlotKind kind); |
| 143 | |
| 144 | typedef std::vector<MaybeObjectHandle> MaybeObjectHandles; |
| 145 | |
| 146 | class FeedbackMetadata; |
| 147 | |
| 148 | // ClosureFeedbackCellArray is a FixedArray that contains feedback cells used |
| 149 | // when creating closures from a function. Along with the feedback |
| 150 | // cells, the first slot (slot 0) is used to hold a budget to measure the |
| 151 | // hotness of the function. This is created once the function is compiled and is |
| 152 | // either held by the feedback vector (if allocated) or by the FeedbackCell of |
| 153 | // the closure. |
| 154 | class ClosureFeedbackCellArray : public FixedArray { |
| 155 | public: |
| 156 | NEVER_READ_ONLY_SPACE |
| 157 | |
| 158 | DECL_CAST(ClosureFeedbackCellArray) |
| 159 | |
| 160 | V8_EXPORT_PRIVATE static Handle<ClosureFeedbackCellArray> New( |
| 161 | Isolate* isolate, Handle<SharedFunctionInfo> shared); |
| 162 | inline Handle<FeedbackCell> GetFeedbackCell(int index); |
| 163 | |
| 164 | DECL_VERIFIER(ClosureFeedbackCellArray) |
| 165 | DECL_PRINTER(ClosureFeedbackCellArray) |
| 166 | |
| 167 | private: |
| 168 | OBJECT_CONSTRUCTORS(ClosureFeedbackCellArray, FixedArray); |
| 169 | }; |
| 170 | |
| 171 | // A FeedbackVector has a fixed header with: |
| 172 | // - shared function info (which includes feedback metadata) |
| 173 | // - invocation count |
| 174 | // - runtime profiler ticks |
| 175 | // - optimized code cell (weak cell or Smi marker) |
| 176 | // followed by an array of feedback slots, of length determined by the feedback |
| 177 | // metadata. |
| 178 | class FeedbackVector : public HeapObject { |
| 179 | public: |
| 180 | NEVER_READ_ONLY_SPACE |
| 181 | |
| 182 | DECL_CAST(FeedbackVector) |
| 183 | |
| 184 | inline bool is_empty() const; |
| 185 | |
| 186 | inline FeedbackMetadata metadata() const; |
| 187 | |
| 188 | // [shared_function_info]: The shared function info for the function with this |
| 189 | // feedback vector. |
| 190 | DECL_ACCESSORS(shared_function_info, SharedFunctionInfo) |
| 191 | |
| 192 | // [optimized_code_weak_or_smi]: weak reference to optimized code or a Smi |
| 193 | // marker defining optimization behaviour. |
| 194 | DECL_ACCESSORS(optimized_code_weak_or_smi, MaybeObject) |
| 195 | |
| 196 | // [feedback_cell_array]: The FixedArray to hold the feedback cells for any |
| 197 | // closures created by this function. |
| 198 | DECL_ACCESSORS(closure_feedback_cell_array, ClosureFeedbackCellArray) |
| 199 | |
| 200 | // [length]: The length of the feedback vector (not including the header, i.e. |
| 201 | // the number of feedback slots). |
| 202 | DECL_INT32_ACCESSORS(length) |
| 203 | |
| 204 | // [invocation_count]: The number of times this function has been invoked. |
| 205 | DECL_INT32_ACCESSORS(invocation_count) |
| 206 | |
| 207 | // [invocation_count]: The number of times this function has been seen by the |
| 208 | // runtime profiler. |
| 209 | DECL_INT32_ACCESSORS(profiler_ticks) |
| 210 | |
| 211 | // [deopt_count]: The number of times this function has deoptimized. |
| 212 | DECL_INT32_ACCESSORS(deopt_count) |
| 213 | |
| 214 | inline void clear_invocation_count(); |
| 215 | inline void increment_deopt_count(); |
| 216 | |
| 217 | inline Code optimized_code() const; |
| 218 | inline OptimizationMarker optimization_marker() const; |
| 219 | inline bool has_optimized_code() const; |
| 220 | inline bool has_optimization_marker() const; |
| 221 | void ClearOptimizedCode(); |
| 222 | void EvictOptimizedCodeMarkedForDeoptimization(SharedFunctionInfo shared, |
| 223 | const char* reason); |
| 224 | static void SetOptimizedCode(Handle<FeedbackVector> vector, |
| 225 | Handle<Code> code); |
| 226 | void SetOptimizationMarker(OptimizationMarker marker); |
| 227 | |
| 228 | // Clears the optimization marker in the feedback vector. |
| 229 | void ClearOptimizationMarker(); |
| 230 | |
| 231 | // Conversion from a slot to an integer index to the underlying array. |
| 232 | static int GetIndex(FeedbackSlot slot) { return slot.ToInt(); } |
| 233 | |
| 234 | // Conversion from an integer index to the underlying array to a slot. |
| 235 | static inline FeedbackSlot ToSlot(int index); |
| 236 | inline MaybeObject Get(FeedbackSlot slot) const; |
| 237 | inline MaybeObject get(int index) const; |
| 238 | inline void Set(FeedbackSlot slot, MaybeObject value, |
| 239 | WriteBarrierMode mode = UPDATE_WRITE_BARRIER); |
| 240 | inline void set(int index, MaybeObject value, |
| 241 | WriteBarrierMode mode = UPDATE_WRITE_BARRIER); |
| 242 | inline void Set(FeedbackSlot slot, Object value, |
| 243 | WriteBarrierMode mode = UPDATE_WRITE_BARRIER); |
| 244 | inline void set(int index, Object value, |
| 245 | WriteBarrierMode mode = UPDATE_WRITE_BARRIER); |
| 246 | |
| 247 | // Returns the feedback cell at |index| that is used to create the |
| 248 | // closure. |
| 249 | inline Handle<FeedbackCell> GetClosureFeedbackCell(int index) const; |
| 250 | |
| 251 | // Gives access to raw memory which stores the array's data. |
| 252 | inline MaybeObjectSlot slots_start(); |
| 253 | |
| 254 | // Returns slot kind for given slot. |
| 255 | V8_EXPORT_PRIVATE FeedbackSlotKind GetKind(FeedbackSlot slot) const; |
| 256 | |
| 257 | FeedbackSlot GetTypeProfileSlot() const; |
| 258 | |
| 259 | V8_EXPORT_PRIVATE static Handle<FeedbackVector> New( |
| 260 | Isolate* isolate, Handle<SharedFunctionInfo> shared, |
| 261 | Handle<ClosureFeedbackCellArray> closure_feedback_cell_array); |
| 262 | |
| 263 | #define DEFINE_SLOT_KIND_PREDICATE(Name) \ |
| 264 | bool Name(FeedbackSlot slot) const { return Name##Kind(GetKind(slot)); } |
| 265 | |
| 266 | DEFINE_SLOT_KIND_PREDICATE(IsCallIC) |
| 267 | DEFINE_SLOT_KIND_PREDICATE(IsGlobalIC) |
| 268 | DEFINE_SLOT_KIND_PREDICATE(IsLoadIC) |
| 269 | DEFINE_SLOT_KIND_PREDICATE(IsLoadGlobalIC) |
| 270 | DEFINE_SLOT_KIND_PREDICATE(IsKeyedLoadIC) |
| 271 | DEFINE_SLOT_KIND_PREDICATE(IsStoreIC) |
| 272 | DEFINE_SLOT_KIND_PREDICATE(IsStoreOwnIC) |
| 273 | DEFINE_SLOT_KIND_PREDICATE(IsStoreGlobalIC) |
| 274 | DEFINE_SLOT_KIND_PREDICATE(IsKeyedStoreIC) |
| 275 | DEFINE_SLOT_KIND_PREDICATE(IsTypeProfile) |
| 276 | #undef DEFINE_SLOT_KIND_PREDICATE |
| 277 | |
| 278 | // Returns typeof mode encoded into kind of given slot. |
| 279 | inline TypeofMode GetTypeofMode(FeedbackSlot slot) const { |
| 280 | return GetTypeofModeFromSlotKind(GetKind(slot)); |
| 281 | } |
| 282 | |
| 283 | // Returns language mode encoded into kind of given slot. |
| 284 | inline LanguageMode GetLanguageMode(FeedbackSlot slot) const { |
| 285 | return GetLanguageModeFromSlotKind(GetKind(slot)); |
| 286 | } |
| 287 | |
| 288 | V8_EXPORT_PRIVATE static void AssertNoLegacyTypes(MaybeObject object); |
| 289 | |
| 290 | DECL_PRINTER(FeedbackVector) |
| 291 | DECL_VERIFIER(FeedbackVector) |
| 292 | |
| 293 | void FeedbackSlotPrint(std::ostream& os, FeedbackSlot slot); // NOLINT |
| 294 | |
| 295 | // Clears the vector slots. Return true if feedback has changed. |
| 296 | bool ClearSlots(Isolate* isolate); |
| 297 | |
| 298 | // The object that indicates an uninitialized cache. |
| 299 | static inline Handle<Symbol> UninitializedSentinel(Isolate* isolate); |
| 300 | |
| 301 | // The object that indicates a generic state. |
| 302 | static inline Handle<Symbol> GenericSentinel(Isolate* isolate); |
| 303 | |
| 304 | // The object that indicates a megamorphic state. |
| 305 | static inline Handle<Symbol> MegamorphicSentinel(Isolate* isolate); |
| 306 | |
| 307 | // The object that indicates a premonomorphic state. |
| 308 | static inline Handle<Symbol> PremonomorphicSentinel(Isolate* isolate); |
| 309 | |
| 310 | // A raw version of the uninitialized sentinel that's safe to read during |
| 311 | // garbage collection (e.g., for patching the cache). |
| 312 | static inline Symbol RawUninitializedSentinel(Isolate* isolate); |
| 313 | |
| 314 | // Layout description. |
| 315 | #define FEEDBACK_VECTOR_FIELDS(V) \ |
| 316 | /* Header fields. */ \ |
| 317 | V(kSharedFunctionInfoOffset, kTaggedSize) \ |
| 318 | V(kOptimizedCodeOffset, kTaggedSize) \ |
| 319 | V(kClosureFeedbackCellArrayOffset, kTaggedSize) \ |
| 320 | V(kLengthOffset, kInt32Size) \ |
| 321 | V(kInvocationCountOffset, kInt32Size) \ |
| 322 | V(kProfilerTicksOffset, kInt32Size) \ |
| 323 | V(kDeoptCountOffset, kInt32Size) \ |
| 324 | V(, 0) |
| 325 | |
| 326 | DEFINE_FIELD_OFFSET_CONSTANTS(HeapObject::kHeaderSize, FEEDBACK_VECTOR_FIELDS) |
| 327 | #undef FEEDBACK_VECTOR_FIELDS |
| 328 | |
| 329 | static const int = |
| 330 | RoundUp<kObjectAlignment>(int{kUnalignedHeaderSize}); |
| 331 | static const int kFeedbackSlotsOffset = kHeaderSize; |
| 332 | |
| 333 | class BodyDescriptor; |
| 334 | |
| 335 | // Garbage collection support. |
| 336 | static constexpr int SizeFor(int length) { |
| 337 | return kFeedbackSlotsOffset + length * kTaggedSize; |
| 338 | } |
| 339 | |
| 340 | private: |
| 341 | static void AddToVectorsForProfilingTools(Isolate* isolate, |
| 342 | Handle<FeedbackVector> vector); |
| 343 | |
| 344 | OBJECT_CONSTRUCTORS(FeedbackVector, HeapObject); |
| 345 | }; |
| 346 | |
| 347 | class V8_EXPORT_PRIVATE FeedbackVectorSpec { |
| 348 | public: |
| 349 | explicit FeedbackVectorSpec(Zone* zone) |
| 350 | : slot_kinds_(zone), num_closure_feedback_cells_(0) { |
| 351 | slot_kinds_.reserve(16); |
| 352 | } |
| 353 | |
| 354 | int slots() const { return static_cast<int>(slot_kinds_.size()); } |
| 355 | int closure_feedback_cells() const { return num_closure_feedback_cells_; } |
| 356 | |
| 357 | int AddFeedbackCellForCreateClosure() { |
| 358 | return num_closure_feedback_cells_++; |
| 359 | } |
| 360 | |
| 361 | FeedbackSlotKind GetKind(FeedbackSlot slot) const { |
| 362 | return static_cast<FeedbackSlotKind>(slot_kinds_.at(slot.ToInt())); |
| 363 | } |
| 364 | |
| 365 | bool HasTypeProfileSlot() const; |
| 366 | |
| 367 | // If used, the TypeProfileSlot is always added as the first slot and its |
| 368 | // index is constant. If other slots are added before the TypeProfileSlot, |
| 369 | // this number changes. |
| 370 | static const int kTypeProfileSlotIndex = 0; |
| 371 | |
| 372 | FeedbackSlot AddCallICSlot() { return AddSlot(FeedbackSlotKind::kCall); } |
| 373 | |
| 374 | FeedbackSlot AddLoadICSlot() { |
| 375 | return AddSlot(FeedbackSlotKind::kLoadProperty); |
| 376 | } |
| 377 | |
| 378 | FeedbackSlot AddLoadGlobalICSlot(TypeofMode typeof_mode) { |
| 379 | return AddSlot(typeof_mode == INSIDE_TYPEOF |
| 380 | ? FeedbackSlotKind::kLoadGlobalInsideTypeof |
| 381 | : FeedbackSlotKind::kLoadGlobalNotInsideTypeof); |
| 382 | } |
| 383 | |
| 384 | FeedbackSlot AddKeyedLoadICSlot() { |
| 385 | return AddSlot(FeedbackSlotKind::kLoadKeyed); |
| 386 | } |
| 387 | |
| 388 | FeedbackSlot AddKeyedHasICSlot() { |
| 389 | return AddSlot(FeedbackSlotKind::kHasKeyed); |
| 390 | } |
| 391 | |
| 392 | FeedbackSlotKind GetStoreICSlot(LanguageMode language_mode) { |
| 393 | STATIC_ASSERT(LanguageModeSize == 2); |
| 394 | return is_strict(language_mode) ? FeedbackSlotKind::kStoreNamedStrict |
| 395 | : FeedbackSlotKind::kStoreNamedSloppy; |
| 396 | } |
| 397 | |
| 398 | FeedbackSlot AddStoreICSlot(LanguageMode language_mode) { |
| 399 | return AddSlot(GetStoreICSlot(language_mode)); |
| 400 | } |
| 401 | |
| 402 | FeedbackSlot AddStoreOwnICSlot() { |
| 403 | return AddSlot(FeedbackSlotKind::kStoreOwnNamed); |
| 404 | } |
| 405 | |
| 406 | FeedbackSlot AddStoreGlobalICSlot(LanguageMode language_mode) { |
| 407 | STATIC_ASSERT(LanguageModeSize == 2); |
| 408 | return AddSlot(is_strict(language_mode) |
| 409 | ? FeedbackSlotKind::kStoreGlobalStrict |
| 410 | : FeedbackSlotKind::kStoreGlobalSloppy); |
| 411 | } |
| 412 | |
| 413 | FeedbackSlotKind GetKeyedStoreICSlotKind(LanguageMode language_mode) { |
| 414 | STATIC_ASSERT(LanguageModeSize == 2); |
| 415 | return is_strict(language_mode) ? FeedbackSlotKind::kStoreKeyedStrict |
| 416 | : FeedbackSlotKind::kStoreKeyedSloppy; |
| 417 | } |
| 418 | |
| 419 | FeedbackSlot AddKeyedStoreICSlot(LanguageMode language_mode) { |
| 420 | return AddSlot(GetKeyedStoreICSlotKind(language_mode)); |
| 421 | } |
| 422 | |
| 423 | FeedbackSlot AddStoreInArrayLiteralICSlot() { |
| 424 | return AddSlot(FeedbackSlotKind::kStoreInArrayLiteral); |
| 425 | } |
| 426 | |
| 427 | FeedbackSlot AddBinaryOpICSlot() { |
| 428 | return AddSlot(FeedbackSlotKind::kBinaryOp); |
| 429 | } |
| 430 | |
| 431 | FeedbackSlot AddCompareICSlot() { |
| 432 | return AddSlot(FeedbackSlotKind::kCompareOp); |
| 433 | } |
| 434 | |
| 435 | FeedbackSlot AddForInSlot() { return AddSlot(FeedbackSlotKind::kForIn); } |
| 436 | |
| 437 | FeedbackSlot AddInstanceOfSlot() { |
| 438 | return AddSlot(FeedbackSlotKind::kInstanceOf); |
| 439 | } |
| 440 | |
| 441 | FeedbackSlot AddLiteralSlot() { return AddSlot(FeedbackSlotKind::kLiteral); } |
| 442 | |
| 443 | FeedbackSlot AddStoreDataPropertyInLiteralICSlot() { |
| 444 | return AddSlot(FeedbackSlotKind::kStoreDataPropertyInLiteral); |
| 445 | } |
| 446 | |
| 447 | FeedbackSlot AddTypeProfileSlot(); |
| 448 | |
| 449 | FeedbackSlot AddCloneObjectSlot() { |
| 450 | return AddSlot(FeedbackSlotKind::kCloneObject); |
| 451 | } |
| 452 | |
| 453 | #ifdef OBJECT_PRINT |
| 454 | // For gdb debugging. |
| 455 | void Print(); |
| 456 | #endif // OBJECT_PRINT |
| 457 | |
| 458 | DECL_PRINTER(FeedbackVectorSpec) |
| 459 | |
| 460 | private: |
| 461 | FeedbackSlot AddSlot(FeedbackSlotKind kind); |
| 462 | |
| 463 | void append(FeedbackSlotKind kind) { |
| 464 | slot_kinds_.push_back(static_cast<unsigned char>(kind)); |
| 465 | } |
| 466 | |
| 467 | ZoneVector<unsigned char> slot_kinds_; |
| 468 | unsigned int num_closure_feedback_cells_; |
| 469 | |
| 470 | friend class SharedFeedbackSlot; |
| 471 | }; |
| 472 | |
| 473 | // Helper class that creates a feedback slot on-demand. |
| 474 | class SharedFeedbackSlot { |
| 475 | public: |
| 476 | // FeedbackSlot default constructor constructs an invalid slot. |
| 477 | SharedFeedbackSlot(FeedbackVectorSpec* spec, FeedbackSlotKind kind) |
| 478 | : kind_(kind), spec_(spec) {} |
| 479 | |
| 480 | FeedbackSlot Get() { |
| 481 | if (slot_.IsInvalid()) slot_ = spec_->AddSlot(kind_); |
| 482 | return slot_; |
| 483 | } |
| 484 | |
| 485 | private: |
| 486 | FeedbackSlotKind kind_; |
| 487 | FeedbackSlot slot_; |
| 488 | FeedbackVectorSpec* spec_; |
| 489 | }; |
| 490 | |
| 491 | // FeedbackMetadata is an array-like object with a slot count (indicating how |
| 492 | // many slots are stored). We save space by packing several slots into an array |
| 493 | // of int32 data. The length is never stored - it is always calculated from |
| 494 | // slot_count. All instances are created through the static New function, and |
| 495 | // the number of slots is static once an instance is created. |
| 496 | class FeedbackMetadata : public HeapObject { |
| 497 | public: |
| 498 | DECL_CAST(FeedbackMetadata) |
| 499 | |
| 500 | // The number of slots that this metadata contains. Stored as an int32. |
| 501 | DECL_INT32_ACCESSORS(slot_count) |
| 502 | |
| 503 | // The number of feedback cells required for create closures. Stored as an |
| 504 | // int32. |
| 505 | // TODO(mythria): Consider using 16 bits for this and slot_count so that we |
| 506 | // can save 4 bytes. |
| 507 | DECL_INT32_ACCESSORS(closure_feedback_cell_count) |
| 508 | |
| 509 | // Get slot_count using an acquire load. |
| 510 | inline int32_t synchronized_slot_count() const; |
| 511 | |
| 512 | // Returns number of feedback vector elements used by given slot kind. |
| 513 | static inline int GetSlotSize(FeedbackSlotKind kind); |
| 514 | |
| 515 | bool SpecDiffersFrom(const FeedbackVectorSpec* other_spec) const; |
| 516 | |
| 517 | inline bool is_empty() const; |
| 518 | |
| 519 | // Returns slot kind for given slot. |
| 520 | V8_EXPORT_PRIVATE FeedbackSlotKind GetKind(FeedbackSlot slot) const; |
| 521 | |
| 522 | // If {spec} is null, then it is considered empty. |
| 523 | V8_EXPORT_PRIVATE static Handle<FeedbackMetadata> New( |
| 524 | Isolate* isolate, const FeedbackVectorSpec* spec = nullptr); |
| 525 | |
| 526 | DECL_PRINTER(FeedbackMetadata) |
| 527 | DECL_VERIFIER(FeedbackMetadata) |
| 528 | |
| 529 | static const char* Kind2String(FeedbackSlotKind kind); |
| 530 | bool HasTypeProfileSlot() const; |
| 531 | |
| 532 | // Garbage collection support. |
| 533 | // This includes any necessary padding at the end of the object for pointer |
| 534 | // size alignment. |
| 535 | static int SizeFor(int slot_count) { |
| 536 | return OBJECT_POINTER_ALIGN(kHeaderSize + length(slot_count) * kInt32Size); |
| 537 | } |
| 538 | |
| 539 | static const int kSlotCountOffset = HeapObject::kHeaderSize; |
| 540 | static const int kFeedbackCellCountOffset = kSlotCountOffset + kInt32Size; |
| 541 | static const int = kFeedbackCellCountOffset + kInt32Size; |
| 542 | |
| 543 | class BodyDescriptor; |
| 544 | |
| 545 | private: |
| 546 | friend class AccessorAssembler; |
| 547 | |
| 548 | // Raw accessors to the encoded slot data. |
| 549 | inline int32_t get(int index) const; |
| 550 | inline void set(int index, int32_t value); |
| 551 | |
| 552 | // The number of int32 data fields needed to store {slot_count} slots. |
| 553 | // Does not include any extra padding for pointer size alignment. |
| 554 | static int length(int slot_count) { |
| 555 | return VectorICComputer::word_count(slot_count); |
| 556 | } |
| 557 | inline int length() const; |
| 558 | |
| 559 | static const int kFeedbackSlotKindBits = 5; |
| 560 | STATIC_ASSERT(static_cast<int>(FeedbackSlotKind::kKindsNumber) < |
| 561 | (1 << kFeedbackSlotKindBits)); |
| 562 | |
| 563 | void SetKind(FeedbackSlot slot, FeedbackSlotKind kind); |
| 564 | |
| 565 | typedef BitSetComputer<FeedbackSlotKind, kFeedbackSlotKindBits, |
| 566 | kInt32Size * kBitsPerByte, uint32_t> |
| 567 | VectorICComputer; |
| 568 | |
| 569 | OBJECT_CONSTRUCTORS(FeedbackMetadata, HeapObject); |
| 570 | }; |
| 571 | |
| 572 | // Verify that an empty hash field looks like a tagged object, but can't |
| 573 | // possibly be confused with a pointer. |
| 574 | STATIC_ASSERT((Name::kEmptyHashField & kHeapObjectTag) == kHeapObjectTag); |
| 575 | STATIC_ASSERT(Name::kEmptyHashField == 0x3); |
| 576 | // Verify that a set hash field will not look like a tagged object. |
| 577 | STATIC_ASSERT(Name::kHashNotComputedMask == kHeapObjectTag); |
| 578 | |
| 579 | class FeedbackMetadataIterator { |
| 580 | public: |
| 581 | explicit FeedbackMetadataIterator(Handle<FeedbackMetadata> metadata) |
| 582 | : metadata_handle_(metadata), |
| 583 | next_slot_(FeedbackSlot(0)), |
| 584 | slot_kind_(FeedbackSlotKind::kInvalid) {} |
| 585 | |
| 586 | explicit FeedbackMetadataIterator(FeedbackMetadata metadata) |
| 587 | : metadata_(metadata), |
| 588 | next_slot_(FeedbackSlot(0)), |
| 589 | slot_kind_(FeedbackSlotKind::kInvalid) {} |
| 590 | |
| 591 | inline bool HasNext() const; |
| 592 | |
| 593 | inline FeedbackSlot Next(); |
| 594 | |
| 595 | // Returns slot kind of the last slot returned by Next(). |
| 596 | FeedbackSlotKind kind() const { |
| 597 | DCHECK_NE(FeedbackSlotKind::kInvalid, slot_kind_); |
| 598 | DCHECK_NE(FeedbackSlotKind::kKindsNumber, slot_kind_); |
| 599 | return slot_kind_; |
| 600 | } |
| 601 | |
| 602 | // Returns entry size of the last slot returned by Next(). |
| 603 | inline int entry_size() const; |
| 604 | |
| 605 | private: |
| 606 | FeedbackMetadata metadata() const { |
| 607 | return !metadata_handle_.is_null() ? *metadata_handle_ : metadata_; |
| 608 | } |
| 609 | |
| 610 | // The reason for having a handle and a raw pointer to the meta data is |
| 611 | // to have a single iterator implementation for both "handlified" and raw |
| 612 | // pointer use cases. |
| 613 | Handle<FeedbackMetadata> metadata_handle_; |
| 614 | FeedbackMetadata metadata_; |
| 615 | FeedbackSlot cur_slot_; |
| 616 | FeedbackSlot next_slot_; |
| 617 | FeedbackSlotKind slot_kind_; |
| 618 | }; |
| 619 | |
| 620 | // A FeedbackNexus is the combination of a FeedbackVector and a slot. |
| 621 | class V8_EXPORT_PRIVATE FeedbackNexus final { |
| 622 | public: |
| 623 | FeedbackNexus(Handle<FeedbackVector> vector, FeedbackSlot slot) |
| 624 | : vector_handle_(vector), slot_(slot) { |
| 625 | kind_ = |
| 626 | (vector.is_null()) ? FeedbackSlotKind::kInvalid : vector->GetKind(slot); |
| 627 | } |
| 628 | FeedbackNexus(FeedbackVector vector, FeedbackSlot slot) |
| 629 | : vector_(vector), slot_(slot) { |
| 630 | kind_ = |
| 631 | (vector.is_null()) ? FeedbackSlotKind::kInvalid : vector->GetKind(slot); |
| 632 | } |
| 633 | |
| 634 | Handle<FeedbackVector> vector_handle() const { |
| 635 | DCHECK(vector_.is_null()); |
| 636 | return vector_handle_; |
| 637 | } |
| 638 | FeedbackVector vector() const { |
| 639 | return vector_handle_.is_null() ? vector_ : *vector_handle_; |
| 640 | } |
| 641 | FeedbackSlot slot() const { return slot_; } |
| 642 | FeedbackSlotKind kind() const { return kind_; } |
| 643 | |
| 644 | inline LanguageMode GetLanguageMode() const { |
| 645 | return vector()->GetLanguageMode(slot()); |
| 646 | } |
| 647 | |
| 648 | InlineCacheState ic_state() const; |
| 649 | bool IsUninitialized() const { return ic_state() == UNINITIALIZED; } |
| 650 | bool IsMegamorphic() const { return ic_state() == MEGAMORPHIC; } |
| 651 | bool IsGeneric() const { return ic_state() == GENERIC; } |
| 652 | |
| 653 | void Print(std::ostream& os); // NOLINT |
| 654 | |
| 655 | // For map-based ICs (load, keyed-load, store, keyed-store). |
| 656 | Map GetFirstMap() const; |
| 657 | |
| 658 | int ExtractMaps(MapHandles* maps) const; |
| 659 | MaybeObjectHandle FindHandlerForMap(Handle<Map> map) const; |
| 660 | bool FindHandlers(MaybeObjectHandles* code_list, int length = -1) const; |
| 661 | |
| 662 | bool IsCleared() const { |
| 663 | InlineCacheState state = ic_state(); |
| 664 | return !FLAG_use_ic || state == UNINITIALIZED || state == PREMONOMORPHIC; |
| 665 | } |
| 666 | |
| 667 | // Clear() returns true if the state of the underlying vector was changed. |
| 668 | bool Clear(); |
| 669 | void ConfigureUninitialized(); |
| 670 | void ConfigurePremonomorphic(Handle<Map> receiver_map); |
| 671 | // ConfigureMegamorphic() returns true if the state of the underlying vector |
| 672 | // was changed. Extra feedback is cleared if the 0 parameter version is used. |
| 673 | bool ConfigureMegamorphic(); |
| 674 | bool ConfigureMegamorphic(IcCheckType property_type); |
| 675 | |
| 676 | inline MaybeObject GetFeedback() const; |
| 677 | inline MaybeObject () const; |
| 678 | |
| 679 | inline Isolate* GetIsolate() const; |
| 680 | |
| 681 | void ConfigureMonomorphic(Handle<Name> name, Handle<Map> receiver_map, |
| 682 | const MaybeObjectHandle& handler); |
| 683 | |
| 684 | void ConfigurePolymorphic(Handle<Name> name, MapHandles const& maps, |
| 685 | MaybeObjectHandles* handlers); |
| 686 | |
| 687 | BinaryOperationHint GetBinaryOperationFeedback() const; |
| 688 | CompareOperationHint GetCompareOperationFeedback() const; |
| 689 | ForInHint GetForInFeedback() const; |
| 690 | |
| 691 | // For KeyedLoad ICs. |
| 692 | KeyedAccessLoadMode GetKeyedAccessLoadMode() const; |
| 693 | |
| 694 | // For KeyedStore ICs. |
| 695 | KeyedAccessStoreMode GetKeyedAccessStoreMode() const; |
| 696 | |
| 697 | // For KeyedLoad and KeyedStore ICs. |
| 698 | IcCheckType GetKeyType() const; |
| 699 | Name GetName() const; |
| 700 | |
| 701 | // For Call ICs. |
| 702 | int GetCallCount(); |
| 703 | void SetSpeculationMode(SpeculationMode mode); |
| 704 | SpeculationMode GetSpeculationMode(); |
| 705 | |
| 706 | // Compute the call frequency based on the call count and the invocation |
| 707 | // count (taken from the type feedback vector). |
| 708 | float ComputeCallFrequency(); |
| 709 | |
| 710 | typedef BitField<SpeculationMode, 0, 1> SpeculationModeField; |
| 711 | typedef BitField<uint32_t, 1, 31> CallCountField; |
| 712 | |
| 713 | // For InstanceOf ICs. |
| 714 | MaybeHandle<JSObject> GetConstructorFeedback() const; |
| 715 | |
| 716 | // For Global Load and Store ICs. |
| 717 | void ConfigurePropertyCellMode(Handle<PropertyCell> cell); |
| 718 | // Returns false if given combination of indices is not allowed. |
| 719 | bool ConfigureLexicalVarMode(int script_context_index, int context_slot_index, |
| 720 | bool immutable); |
| 721 | void ConfigureHandlerMode(const MaybeObjectHandle& handler); |
| 722 | |
| 723 | // For CloneObject ICs |
| 724 | static constexpr int kCloneObjectPolymorphicEntrySize = 2; |
| 725 | void ConfigureCloneObject(Handle<Map> source_map, Handle<Map> result_map); |
| 726 | |
| 727 | // Bit positions in a smi that encodes lexical environment variable access. |
| 728 | #define LEXICAL_MODE_BIT_FIELDS(V, _) \ |
| 729 | V(ContextIndexBits, unsigned, 12, _) \ |
| 730 | V(SlotIndexBits, unsigned, 18, _) \ |
| 731 | V(ImmutabilityBit, bool, 1, _) |
| 732 | |
| 733 | DEFINE_BIT_FIELDS(LEXICAL_MODE_BIT_FIELDS) |
| 734 | #undef LEXICAL_MODE_BIT_FIELDS |
| 735 | |
| 736 | // Make sure we don't overflow the smi. |
| 737 | STATIC_ASSERT(LEXICAL_MODE_BIT_FIELDS_Ranges::kBitsCount <= kSmiValueSize); |
| 738 | |
| 739 | // For TypeProfile feedback vector slots. |
| 740 | // ResetTypeProfile will always reset type profile information. |
| 741 | void ResetTypeProfile(); |
| 742 | |
| 743 | // Add a type to the list of types for source position <position>. |
| 744 | void Collect(Handle<String> type, int position); |
| 745 | JSObject GetTypeProfile() const; |
| 746 | |
| 747 | std::vector<int> GetSourcePositions() const; |
| 748 | std::vector<Handle<String>> GetTypesForSourcePositions(uint32_t pos) const; |
| 749 | |
| 750 | inline void SetFeedback(Object feedback, |
| 751 | WriteBarrierMode mode = UPDATE_WRITE_BARRIER); |
| 752 | inline void SetFeedback(MaybeObject feedback, |
| 753 | WriteBarrierMode mode = UPDATE_WRITE_BARRIER); |
| 754 | inline void (Object , |
| 755 | WriteBarrierMode mode = UPDATE_WRITE_BARRIER); |
| 756 | inline void (MaybeObject , |
| 757 | WriteBarrierMode mode = UPDATE_WRITE_BARRIER); |
| 758 | |
| 759 | Handle<WeakFixedArray> EnsureArrayOfSize(int length); |
| 760 | Handle<WeakFixedArray> (int length); |
| 761 | |
| 762 | private: |
| 763 | // The reason for having a vector handle and a raw pointer is that we can and |
| 764 | // should use handles during IC miss, but not during GC when we clear ICs. If |
| 765 | // you have a handle to the vector that is better because more operations can |
| 766 | // be done, like allocation. |
| 767 | Handle<FeedbackVector> vector_handle_; |
| 768 | FeedbackVector vector_; |
| 769 | FeedbackSlot slot_; |
| 770 | FeedbackSlotKind kind_; |
| 771 | }; |
| 772 | |
| 773 | inline BinaryOperationHint BinaryOperationHintFromFeedback(int type_feedback); |
| 774 | inline CompareOperationHint CompareOperationHintFromFeedback(int type_feedback); |
| 775 | inline ForInHint ForInHintFromFeedback(int type_feedback); |
| 776 | |
| 777 | } // namespace internal |
| 778 | } // namespace v8 |
| 779 | |
| 780 | #include "src/objects/object-macros-undef.h" |
| 781 | |
| 782 | #endif // V8_FEEDBACK_VECTOR_H_ |
| 783 | |