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