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 #include "src/feedback-vector.h" 6 #include "src/code-stubs.h" 7 #include "src/feedback-vector-inl.h" 8 #include "src/ic/ic-inl.h" 9 #include "src/objects.h" 10 #include "src/objects/data-handler-inl.h" 11 #include "src/objects/hash-table-inl.h" 12 #include "src/objects/object-macros.h" 13 14 namespace v8 { 15 namespace internal { 16 17 FeedbackSlot FeedbackVectorSpec::AddSlot(FeedbackSlotKind kind) { 18 int slot = slots(); 19 int entries_per_slot = FeedbackMetadata::GetSlotSize(kind); 20 append(kind); 21 for (int i = 1; i < entries_per_slot; i++) { 22 append(FeedbackSlotKind::kInvalid); 23 } 24 return FeedbackSlot(slot); 25 } 26 27 FeedbackSlot FeedbackVectorSpec::AddTypeProfileSlot() { 28 FeedbackSlot slot = AddSlot(FeedbackSlotKind::kTypeProfile); 29 CHECK_EQ(FeedbackVectorSpec::kTypeProfileSlotIndex, 30 FeedbackVector::GetIndex(slot)); 31 return slot; 32 } 33 34 bool FeedbackVectorSpec::HasTypeProfileSlot() const { 35 FeedbackSlot slot = 36 FeedbackVector::ToSlot(FeedbackVectorSpec::kTypeProfileSlotIndex); 37 if (slots() <= slot.ToInt()) { 38 return false; 39 } 40 return GetKind(slot) == FeedbackSlotKind::kTypeProfile; 41 } 42 43 static bool IsPropertyNameFeedback(MaybeObject* feedback) { 44 HeapObject* heap_object; 45 if (!feedback->ToStrongHeapObject(&heap_object)) return false; 46 if (heap_object->IsString()) return true; 47 if (!heap_object->IsSymbol()) return false; 48 Symbol* symbol = Symbol::cast(heap_object); 49 ReadOnlyRoots roots = symbol->GetReadOnlyRoots(); 50 return symbol != roots.uninitialized_symbol() && 51 symbol != roots.premonomorphic_symbol() && 52 symbol != roots.megamorphic_symbol(); 53 } 54 55 std::ostream& operator<<(std::ostream& os, FeedbackSlotKind kind) { 56 return os << FeedbackMetadata::Kind2String(kind); 57 } 58 59 FeedbackSlotKind FeedbackMetadata::GetKind(FeedbackSlot slot) const { 60 int index = VectorICComputer::index(0, slot.ToInt()); 61 int data = get(index); 62 return VectorICComputer::decode(data, slot.ToInt()); 63 } 64 65 void FeedbackMetadata::SetKind(FeedbackSlot slot, FeedbackSlotKind kind) { 66 int index = VectorICComputer::index(0, slot.ToInt()); 67 int data = get(index); 68 int new_data = VectorICComputer::encode(data, slot.ToInt(), kind); 69 set(index, new_data); 70 } 71 72 // static 73 Handle<FeedbackMetadata> FeedbackMetadata::New(Isolate* isolate, 74 const FeedbackVectorSpec* spec) { 75 Factory* factory = isolate->factory(); 76 77 const int slot_count = spec == nullptr ? 0 : spec->slots(); 78 if (slot_count == 0) { 79 return factory->empty_feedback_metadata(); 80 } 81 #ifdef DEBUG 82 for (int i = 0; i < slot_count;) { 83 DCHECK(spec); 84 FeedbackSlotKind kind = spec->GetKind(FeedbackSlot(i)); 85 int entry_size = FeedbackMetadata::GetSlotSize(kind); 86 for (int j = 1; j < entry_size; j++) { 87 FeedbackSlotKind kind = spec->GetKind(FeedbackSlot(i + j)); 88 DCHECK_EQ(FeedbackSlotKind::kInvalid, kind); 89 } 90 i += entry_size; 91 } 92 #endif 93 94 Handle<FeedbackMetadata> metadata = factory->NewFeedbackMetadata(slot_count); 95 96 // Initialize the slots. The raw data section has already been pre-zeroed in 97 // NewFeedbackMetadata. 98 for (int i = 0; i < slot_count; i++) { 99 DCHECK(spec); 100 FeedbackSlot slot(i); 101 FeedbackSlotKind kind = spec->GetKind(slot); 102 metadata->SetKind(slot, kind); 103 } 104 105 return metadata; 106 } 107 108 bool FeedbackMetadata::SpecDiffersFrom( 109 const FeedbackVectorSpec* other_spec) const { 110 if (other_spec->slots() != slot_count()) { 111 return true; 112 } 113 114 int slots = slot_count(); 115 for (int i = 0; i < slots;) { 116 FeedbackSlot slot(i); 117 FeedbackSlotKind kind = GetKind(slot); 118 int entry_size = FeedbackMetadata::GetSlotSize(kind); 119 120 if (kind != other_spec->GetKind(slot)) { 121 return true; 122 } 123 i += entry_size; 124 } 125 return false; 126 } 127 128 const char* FeedbackMetadata::Kind2String(FeedbackSlotKind kind) { 129 switch (kind) { 130 case FeedbackSlotKind::kInvalid: 131 return "Invalid"; 132 case FeedbackSlotKind::kCall: 133 return "Call"; 134 case FeedbackSlotKind::kLoadProperty: 135 return "LoadProperty"; 136 case FeedbackSlotKind::kLoadGlobalInsideTypeof: 137 return "LoadGlobalInsideTypeof"; 138 case FeedbackSlotKind::kLoadGlobalNotInsideTypeof: 139 return "LoadGlobalNotInsideTypeof"; 140 case FeedbackSlotKind::kLoadKeyed: 141 return "LoadKeyed"; 142 case FeedbackSlotKind::kStoreNamedSloppy: 143 return "StoreNamedSloppy"; 144 case FeedbackSlotKind::kStoreNamedStrict: 145 return "StoreNamedStrict"; 146 case FeedbackSlotKind::kStoreOwnNamed: 147 return "StoreOwnNamed"; 148 case FeedbackSlotKind::kStoreGlobalSloppy: 149 return "StoreGlobalSloppy"; 150 case FeedbackSlotKind::kStoreGlobalStrict: 151 return "StoreGlobalStrict"; 152 case FeedbackSlotKind::kStoreKeyedSloppy: 153 return "StoreKeyedSloppy"; 154 case FeedbackSlotKind::kStoreKeyedStrict: 155 return "StoreKeyedStrict"; 156 case FeedbackSlotKind::kStoreInArrayLiteral: 157 return "StoreInArrayLiteral"; 158 case FeedbackSlotKind::kBinaryOp: 159 return "BinaryOp"; 160 case FeedbackSlotKind::kCompareOp: 161 return "CompareOp"; 162 case FeedbackSlotKind::kStoreDataPropertyInLiteral: 163 return "StoreDataPropertyInLiteral"; 164 case FeedbackSlotKind::kCreateClosure: 165 return "kCreateClosure"; 166 case FeedbackSlotKind::kLiteral: 167 return "Literal"; 168 case FeedbackSlotKind::kTypeProfile: 169 return "TypeProfile"; 170 case FeedbackSlotKind::kForIn: 171 return "ForIn"; 172 case FeedbackSlotKind::kInstanceOf: 173 return "InstanceOf"; 174 case FeedbackSlotKind::kCloneObject: 175 return "CloneObject"; 176 case FeedbackSlotKind::kKindsNumber: 177 break; 178 } 179 UNREACHABLE(); 180 } 181 182 bool FeedbackMetadata::HasTypeProfileSlot() const { 183 FeedbackSlot slot = 184 FeedbackVector::ToSlot(FeedbackVectorSpec::kTypeProfileSlotIndex); 185 return slot.ToInt() < slot_count() && 186 GetKind(slot) == FeedbackSlotKind::kTypeProfile; 187 } 188 189 FeedbackSlotKind FeedbackVector::GetKind(FeedbackSlot slot) const { 190 DCHECK(!is_empty()); 191 return metadata()->GetKind(slot); 192 } 193 194 FeedbackSlot FeedbackVector::GetTypeProfileSlot() const { 195 DCHECK(metadata()->HasTypeProfileSlot()); 196 FeedbackSlot slot = 197 FeedbackVector::ToSlot(FeedbackVectorSpec::kTypeProfileSlotIndex); 198 DCHECK_EQ(FeedbackSlotKind::kTypeProfile, GetKind(slot)); 199 return slot; 200 } 201 202 // static 203 Handle<FeedbackVector> FeedbackVector::New(Isolate* isolate, 204 Handle<SharedFunctionInfo> shared) { 205 Factory* factory = isolate->factory(); 206 207 const int slot_count = shared->feedback_metadata()->slot_count(); 208 209 Handle<FeedbackVector> vector = factory->NewFeedbackVector(shared, TENURED); 210 211 DCHECK_EQ(vector->length(), slot_count); 212 213 DCHECK_EQ(vector->shared_function_info(), *shared); 214 DCHECK_EQ( 215 vector->optimized_code_weak_or_smi(), 216 MaybeObject::FromSmi(Smi::FromEnum( 217 FLAG_log_function_events ? OptimizationMarker::kLogFirstExecution 218 : OptimizationMarker::kNone))); 219 DCHECK_EQ(vector->invocation_count(), 0); 220 DCHECK_EQ(vector->profiler_ticks(), 0); 221 DCHECK_EQ(vector->deopt_count(), 0); 222 223 // Ensure we can skip the write barrier 224 Handle<Object> uninitialized_sentinel = UninitializedSentinel(isolate); 225 DCHECK_EQ(ReadOnlyRoots(isolate).uninitialized_symbol(), 226 *uninitialized_sentinel); 227 Handle<Oddball> undefined_value = factory->undefined_value(); 228 for (int i = 0; i < slot_count;) { 229 FeedbackSlot slot(i); 230 FeedbackSlotKind kind = shared->feedback_metadata()->GetKind(slot); 231 int index = FeedbackVector::GetIndex(slot); 232 int entry_size = FeedbackMetadata::GetSlotSize(kind); 233 234 Object* extra_value = *uninitialized_sentinel; 235 switch (kind) { 236 case FeedbackSlotKind::kLoadGlobalInsideTypeof: 237 case FeedbackSlotKind::kLoadGlobalNotInsideTypeof: 238 case FeedbackSlotKind::kStoreGlobalSloppy: 239 case FeedbackSlotKind::kStoreGlobalStrict: 240 vector->set(index, HeapObjectReference::ClearedValue(), 241 SKIP_WRITE_BARRIER); 242 break; 243 case FeedbackSlotKind::kForIn: 244 case FeedbackSlotKind::kCompareOp: 245 case FeedbackSlotKind::kBinaryOp: 246 vector->set(index, Smi::kZero, SKIP_WRITE_BARRIER); 247 break; 248 case FeedbackSlotKind::kCreateClosure: { 249 Handle<FeedbackCell> cell = factory->NewNoClosuresCell(undefined_value); 250 vector->set(index, *cell); 251 break; 252 } 253 case FeedbackSlotKind::kLiteral: 254 vector->set(index, Smi::kZero, SKIP_WRITE_BARRIER); 255 break; 256 case FeedbackSlotKind::kCall: 257 vector->set(index, *uninitialized_sentinel, SKIP_WRITE_BARRIER); 258 extra_value = Smi::kZero; 259 break; 260 case FeedbackSlotKind::kCloneObject: 261 case FeedbackSlotKind::kLoadProperty: 262 case FeedbackSlotKind::kLoadKeyed: 263 case FeedbackSlotKind::kStoreNamedSloppy: 264 case FeedbackSlotKind::kStoreNamedStrict: 265 case FeedbackSlotKind::kStoreOwnNamed: 266 case FeedbackSlotKind::kStoreKeyedSloppy: 267 case FeedbackSlotKind::kStoreKeyedStrict: 268 case FeedbackSlotKind::kStoreInArrayLiteral: 269 case FeedbackSlotKind::kStoreDataPropertyInLiteral: 270 case FeedbackSlotKind::kTypeProfile: 271 case FeedbackSlotKind::kInstanceOf: 272 vector->set(index, *uninitialized_sentinel, SKIP_WRITE_BARRIER); 273 break; 274 275 case FeedbackSlotKind::kInvalid: 276 case FeedbackSlotKind::kKindsNumber: 277 UNREACHABLE(); 278 break; 279 } 280 for (int j = 1; j < entry_size; j++) { 281 vector->set(index + j, extra_value, SKIP_WRITE_BARRIER); 282 } 283 i += entry_size; 284 } 285 286 Handle<FeedbackVector> result = Handle<FeedbackVector>::cast(vector); 287 if (!isolate->is_best_effort_code_coverage() || 288 isolate->is_collecting_type_profile()) { 289 AddToVectorsForProfilingTools(isolate, result); 290 } 291 return result; 292 } 293 294 // static 295 void FeedbackVector::AddToVectorsForProfilingTools( 296 Isolate* isolate, Handle<FeedbackVector> vector) { 297 DCHECK(!isolate->is_best_effort_code_coverage() || 298 isolate->is_collecting_type_profile()); 299 if (!vector->shared_function_info()->IsSubjectToDebugging()) return; 300 Handle<ArrayList> list = Handle<ArrayList>::cast( 301 isolate->factory()->feedback_vectors_for_profiling_tools()); 302 list = ArrayList::Add(isolate, list, vector); 303 isolate->SetFeedbackVectorsForProfilingTools(*list); 304 } 305 306 // static 307 void FeedbackVector::SetOptimizedCode(Handle<FeedbackVector> vector, 308 Handle<Code> code) { 309 DCHECK_EQ(code->kind(), Code::OPTIMIZED_FUNCTION); 310 vector->set_optimized_code_weak_or_smi(HeapObjectReference::Weak(*code)); 311 } 312 313 void FeedbackVector::ClearOptimizedCode() { 314 DCHECK(has_optimized_code()); 315 SetOptimizationMarker(OptimizationMarker::kNone); 316 } 317 318 void FeedbackVector::ClearOptimizationMarker() { 319 DCHECK(!has_optimized_code()); 320 SetOptimizationMarker(OptimizationMarker::kNone); 321 } 322 323 void FeedbackVector::SetOptimizationMarker(OptimizationMarker marker) { 324 set_optimized_code_weak_or_smi(MaybeObject::FromSmi(Smi::FromEnum(marker))); 325 } 326 327 void FeedbackVector::EvictOptimizedCodeMarkedForDeoptimization( 328 SharedFunctionInfo* shared, const char* reason) { 329 MaybeObject* slot = optimized_code_weak_or_smi(); 330 if (slot->IsSmi()) { 331 return; 332 } 333 334 if (slot->IsClearedWeakHeapObject()) { 335 ClearOptimizationMarker(); 336 return; 337 } 338 339 Code* code = Code::cast(slot->GetHeapObject()); 340 if (code->marked_for_deoptimization()) { 341 if (FLAG_trace_deopt) { 342 PrintF("[evicting optimizing code marked for deoptimization (%s) for ", 343 reason); 344 shared->ShortPrint(); 345 PrintF("]\n"); 346 } 347 if (!code->deopt_already_counted()) { 348 increment_deopt_count(); 349 code->set_deopt_already_counted(true); 350 } 351 ClearOptimizedCode(); 352 } 353 } 354 355 bool FeedbackVector::ClearSlots(Isolate* isolate) { 356 MaybeObject* uninitialized_sentinel = MaybeObject::FromObject( 357 FeedbackVector::RawUninitializedSentinel(isolate)); 358 359 bool feedback_updated = false; 360 FeedbackMetadataIterator iter(metadata()); 361 while (iter.HasNext()) { 362 FeedbackSlot slot = iter.Next(); 363 364 MaybeObject* obj = Get(slot); 365 if (obj != uninitialized_sentinel) { 366 FeedbackNexus nexus(this, slot); 367 feedback_updated |= nexus.Clear(); 368 } 369 } 370 return feedback_updated; 371 } 372 373 void FeedbackVector::AssertNoLegacyTypes(MaybeObject* object) { 374 #ifdef DEBUG 375 HeapObject* heap_object; 376 if (object->ToStrongOrWeakHeapObject(&heap_object)) { 377 // Instead of FixedArray, the Feedback and the Extra should contain 378 // WeakFixedArrays. The only allowed FixedArray subtype is HashTable. 379 DCHECK_IMPLIES(heap_object->IsFixedArray(), heap_object->IsHashTable()); 380 } 381 #endif 382 } 383 384 Handle<WeakFixedArray> FeedbackNexus::EnsureArrayOfSize(int length) { 385 Isolate* isolate = GetIsolate(); 386 HeapObject* heap_object; 387 if (GetFeedback()->ToStrongHeapObject(&heap_object) && 388 heap_object->IsWeakFixedArray() && 389 WeakFixedArray::cast(heap_object)->length() == length) { 390 return handle(WeakFixedArray::cast(heap_object), isolate); 391 } 392 Handle<WeakFixedArray> array = isolate->factory()->NewWeakFixedArray(length); 393 SetFeedback(*array); 394 return array; 395 } 396 397 Handle<WeakFixedArray> FeedbackNexus::EnsureExtraArrayOfSize(int length) { 398 Isolate* isolate = GetIsolate(); 399 HeapObject* heap_object; 400 if (GetFeedbackExtra()->ToStrongHeapObject(&heap_object) && 401 heap_object->IsWeakFixedArray() && 402 WeakFixedArray::cast(heap_object)->length() == length) { 403 return handle(WeakFixedArray::cast(heap_object), isolate); 404 } 405 Handle<WeakFixedArray> array = isolate->factory()->NewWeakFixedArray(length); 406 SetFeedbackExtra(*array); 407 return array; 408 } 409 410 void FeedbackNexus::ConfigureUninitialized() { 411 Isolate* isolate = GetIsolate(); 412 switch (kind()) { 413 case FeedbackSlotKind::kStoreGlobalSloppy: 414 case FeedbackSlotKind::kStoreGlobalStrict: 415 case FeedbackSlotKind::kLoadGlobalNotInsideTypeof: 416 case FeedbackSlotKind::kLoadGlobalInsideTypeof: { 417 SetFeedback(HeapObjectReference::ClearedValue(), SKIP_WRITE_BARRIER); 418 SetFeedbackExtra(*FeedbackVector::UninitializedSentinel(isolate), 419 SKIP_WRITE_BARRIER); 420 break; 421 } 422 case FeedbackSlotKind::kCloneObject: 423 case FeedbackSlotKind::kCall: { 424 SetFeedback(*FeedbackVector::UninitializedSentinel(isolate), 425 SKIP_WRITE_BARRIER); 426 SetFeedbackExtra(Smi::kZero, SKIP_WRITE_BARRIER); 427 break; 428 } 429 case FeedbackSlotKind::kInstanceOf: { 430 SetFeedback(*FeedbackVector::UninitializedSentinel(isolate), 431 SKIP_WRITE_BARRIER); 432 break; 433 } 434 case FeedbackSlotKind::kStoreNamedSloppy: 435 case FeedbackSlotKind::kStoreNamedStrict: 436 case FeedbackSlotKind::kStoreKeyedSloppy: 437 case FeedbackSlotKind::kStoreKeyedStrict: 438 case FeedbackSlotKind::kStoreInArrayLiteral: 439 case FeedbackSlotKind::kStoreOwnNamed: 440 case FeedbackSlotKind::kLoadProperty: 441 case FeedbackSlotKind::kLoadKeyed: 442 case FeedbackSlotKind::kStoreDataPropertyInLiteral: { 443 SetFeedback(*FeedbackVector::UninitializedSentinel(isolate), 444 SKIP_WRITE_BARRIER); 445 SetFeedbackExtra(*FeedbackVector::UninitializedSentinel(isolate), 446 SKIP_WRITE_BARRIER); 447 break; 448 } 449 default: 450 UNREACHABLE(); 451 } 452 } 453 454 bool FeedbackNexus::Clear() { 455 bool feedback_updated = false; 456 457 switch (kind()) { 458 case FeedbackSlotKind::kCreateClosure: 459 case FeedbackSlotKind::kTypeProfile: 460 // We don't clear these kinds ever. 461 break; 462 463 case FeedbackSlotKind::kCompareOp: 464 case FeedbackSlotKind::kForIn: 465 case FeedbackSlotKind::kBinaryOp: 466 // We don't clear these, either. 467 break; 468 469 case FeedbackSlotKind::kLiteral: 470 SetFeedback(Smi::kZero, SKIP_WRITE_BARRIER); 471 feedback_updated = true; 472 break; 473 474 case FeedbackSlotKind::kStoreNamedSloppy: 475 case FeedbackSlotKind::kStoreNamedStrict: 476 case FeedbackSlotKind::kStoreKeyedSloppy: 477 case FeedbackSlotKind::kStoreKeyedStrict: 478 case FeedbackSlotKind::kStoreInArrayLiteral: 479 case FeedbackSlotKind::kStoreOwnNamed: 480 case FeedbackSlotKind::kLoadProperty: 481 case FeedbackSlotKind::kLoadKeyed: 482 case FeedbackSlotKind::kStoreGlobalSloppy: 483 case FeedbackSlotKind::kStoreGlobalStrict: 484 case FeedbackSlotKind::kLoadGlobalNotInsideTypeof: 485 case FeedbackSlotKind::kLoadGlobalInsideTypeof: 486 case FeedbackSlotKind::kCall: 487 case FeedbackSlotKind::kInstanceOf: 488 case FeedbackSlotKind::kStoreDataPropertyInLiteral: 489 case FeedbackSlotKind::kCloneObject: 490 if (!IsCleared()) { 491 ConfigureUninitialized(); 492 feedback_updated = true; 493 } 494 break; 495 496 case FeedbackSlotKind::kInvalid: 497 case FeedbackSlotKind::kKindsNumber: 498 UNREACHABLE(); 499 break; 500 } 501 return feedback_updated; 502 } 503 504 void FeedbackNexus::ConfigurePremonomorphic(Handle<Map> receiver_map) { 505 SetFeedback(*FeedbackVector::PremonomorphicSentinel(GetIsolate()), 506 SKIP_WRITE_BARRIER); 507 SetFeedbackExtra(HeapObjectReference::Weak(*receiver_map)); 508 } 509 510 bool FeedbackNexus::ConfigureMegamorphic() { 511 DisallowHeapAllocation no_gc; 512 Isolate* isolate = GetIsolate(); 513 MaybeObject* sentinel = 514 MaybeObject::FromObject(*FeedbackVector::MegamorphicSentinel(isolate)); 515 if (GetFeedback() != sentinel) { 516 SetFeedback(sentinel, SKIP_WRITE_BARRIER); 517 SetFeedbackExtra(HeapObjectReference::ClearedValue()); 518 return true; 519 } 520 521 return false; 522 } 523 524 bool FeedbackNexus::ConfigureMegamorphic(IcCheckType property_type) { 525 DisallowHeapAllocation no_gc; 526 Isolate* isolate = GetIsolate(); 527 bool changed = false; 528 MaybeObject* sentinel = 529 MaybeObject::FromObject(*FeedbackVector::MegamorphicSentinel(isolate)); 530 if (GetFeedback() != sentinel) { 531 SetFeedback(sentinel, SKIP_WRITE_BARRIER); 532 changed = true; 533 } 534 535 Smi* extra = Smi::FromInt(static_cast<int>(property_type)); 536 if (changed || GetFeedbackExtra() != MaybeObject::FromSmi(extra)) { 537 SetFeedbackExtra(extra, SKIP_WRITE_BARRIER); 538 changed = true; 539 } 540 return changed; 541 } 542 543 InlineCacheState FeedbackNexus::StateFromFeedback() const { 544 Isolate* isolate = GetIsolate(); 545 MaybeObject* feedback = GetFeedback(); 546 547 switch (kind()) { 548 case FeedbackSlotKind::kCreateClosure: 549 case FeedbackSlotKind::kLiteral: 550 // CreateClosure and literal slots don't have a notion of state. 551 UNREACHABLE(); 552 break; 553 554 case FeedbackSlotKind::kStoreGlobalSloppy: 555 case FeedbackSlotKind::kStoreGlobalStrict: 556 case FeedbackSlotKind::kLoadGlobalNotInsideTypeof: 557 case FeedbackSlotKind::kLoadGlobalInsideTypeof: { 558 if (feedback->IsSmi()) return MONOMORPHIC; 559 560 DCHECK(feedback->IsWeakOrClearedHeapObject()); 561 MaybeObject* extra = GetFeedbackExtra(); 562 if (!feedback->IsClearedWeakHeapObject() || 563 extra != MaybeObject::FromObject( 564 *FeedbackVector::UninitializedSentinel(isolate))) { 565 return MONOMORPHIC; 566 } 567 return UNINITIALIZED; 568 } 569 570 case FeedbackSlotKind::kStoreNamedSloppy: 571 case FeedbackSlotKind::kStoreNamedStrict: 572 case FeedbackSlotKind::kStoreKeyedSloppy: 573 case FeedbackSlotKind::kStoreKeyedStrict: 574 case FeedbackSlotKind::kStoreInArrayLiteral: 575 case FeedbackSlotKind::kStoreOwnNamed: 576 case FeedbackSlotKind::kLoadProperty: 577 case FeedbackSlotKind::kLoadKeyed: { 578 if (feedback == MaybeObject::FromObject( 579 *FeedbackVector::UninitializedSentinel(isolate))) { 580 return UNINITIALIZED; 581 } 582 if (feedback == MaybeObject::FromObject( 583 *FeedbackVector::MegamorphicSentinel(isolate))) { 584 return MEGAMORPHIC; 585 } 586 if (feedback == MaybeObject::FromObject( 587 *FeedbackVector::PremonomorphicSentinel(isolate))) { 588 return PREMONOMORPHIC; 589 } 590 if (feedback->IsWeakOrClearedHeapObject()) { 591 // Don't check if the map is cleared. 592 return MONOMORPHIC; 593 } 594 HeapObject* heap_object; 595 if (feedback->ToStrongHeapObject(&heap_object)) { 596 if (heap_object->IsWeakFixedArray()) { 597 // Determine state purely by our structure, don't check if the maps 598 // are cleared. 599 return POLYMORPHIC; 600 } 601 if (heap_object->IsName()) { 602 DCHECK(IsKeyedLoadICKind(kind()) || IsKeyedStoreICKind(kind())); 603 Object* extra = GetFeedbackExtra()->ToStrongHeapObject(); 604 WeakFixedArray* extra_array = WeakFixedArray::cast(extra); 605 return extra_array->length() > 2 ? POLYMORPHIC : MONOMORPHIC; 606 } 607 } 608 UNREACHABLE(); 609 } 610 case FeedbackSlotKind::kCall: { 611 HeapObject* heap_object; 612 if (feedback == MaybeObject::FromObject( 613 *FeedbackVector::MegamorphicSentinel(isolate))) { 614 return GENERIC; 615 } else if (feedback->IsWeakOrClearedHeapObject() || 616 (feedback->ToStrongHeapObject(&heap_object) && 617 heap_object->IsAllocationSite())) { 618 return MONOMORPHIC; 619 } 620 621 CHECK_EQ(feedback, MaybeObject::FromObject( 622 *FeedbackVector::UninitializedSentinel(isolate))); 623 return UNINITIALIZED; 624 } 625 case FeedbackSlotKind::kBinaryOp: { 626 BinaryOperationHint hint = GetBinaryOperationFeedback(); 627 if (hint == BinaryOperationHint::kNone) { 628 return UNINITIALIZED; 629 } else if (hint == BinaryOperationHint::kAny) { 630 return GENERIC; 631 } 632 633 return MONOMORPHIC; 634 } 635 case FeedbackSlotKind::kCompareOp: { 636 CompareOperationHint hint = GetCompareOperationFeedback(); 637 if (hint == CompareOperationHint::kNone) { 638 return UNINITIALIZED; 639 } else if (hint == CompareOperationHint::kAny) { 640 return GENERIC; 641 } 642 643 return MONOMORPHIC; 644 } 645 case FeedbackSlotKind::kForIn: { 646 ForInHint hint = GetForInFeedback(); 647 if (hint == ForInHint::kNone) { 648 return UNINITIALIZED; 649 } else if (hint == ForInHint::kAny) { 650 return GENERIC; 651 } 652 return MONOMORPHIC; 653 } 654 case FeedbackSlotKind::kInstanceOf: { 655 if (feedback == MaybeObject::FromObject( 656 *FeedbackVector::UninitializedSentinel(isolate))) { 657 return UNINITIALIZED; 658 } else if (feedback == 659 MaybeObject::FromObject( 660 *FeedbackVector::MegamorphicSentinel(isolate))) { 661 return MEGAMORPHIC; 662 } 663 return MONOMORPHIC; 664 } 665 case FeedbackSlotKind::kStoreDataPropertyInLiteral: { 666 if (feedback == MaybeObject::FromObject( 667 *FeedbackVector::UninitializedSentinel(isolate))) { 668 return UNINITIALIZED; 669 } else if (feedback->IsWeakOrClearedHeapObject()) { 670 // Don't check if the map is cleared. 671 return MONOMORPHIC; 672 } 673 674 return MEGAMORPHIC; 675 } 676 case FeedbackSlotKind::kTypeProfile: { 677 if (feedback == MaybeObject::FromObject( 678 *FeedbackVector::UninitializedSentinel(isolate))) { 679 return UNINITIALIZED; 680 } 681 return MONOMORPHIC; 682 } 683 684 case FeedbackSlotKind::kCloneObject: { 685 if (feedback == MaybeObject::FromObject( 686 *FeedbackVector::UninitializedSentinel(isolate))) { 687 return UNINITIALIZED; 688 } 689 if (feedback == MaybeObject::FromObject( 690 *FeedbackVector::MegamorphicSentinel(isolate))) { 691 return MEGAMORPHIC; 692 } 693 if (feedback->IsWeakOrClearedHeapObject()) { 694 return MONOMORPHIC; 695 } 696 697 DCHECK(feedback->ToStrongHeapObject()->IsWeakFixedArray()); 698 return POLYMORPHIC; 699 } 700 701 case FeedbackSlotKind::kInvalid: 702 case FeedbackSlotKind::kKindsNumber: 703 UNREACHABLE(); 704 break; 705 } 706 return UNINITIALIZED; 707 } 708 709 void FeedbackNexus::ConfigurePropertyCellMode(Handle<PropertyCell> cell) { 710 DCHECK(IsGlobalICKind(kind())); 711 Isolate* isolate = GetIsolate(); 712 SetFeedback(HeapObjectReference::Weak(*cell)); 713 SetFeedbackExtra(*FeedbackVector::UninitializedSentinel(isolate), 714 SKIP_WRITE_BARRIER); 715 } 716 717 bool FeedbackNexus::ConfigureLexicalVarMode(int script_context_index, 718 int context_slot_index) { 719 DCHECK(IsGlobalICKind(kind())); 720 DCHECK_LE(0, script_context_index); 721 DCHECK_LE(0, context_slot_index); 722 if (!ContextIndexBits::is_valid(script_context_index) || 723 !SlotIndexBits::is_valid(context_slot_index)) { 724 return false; 725 } 726 int config = ContextIndexBits::encode(script_context_index) | 727 SlotIndexBits::encode(context_slot_index); 728 729 SetFeedback(Smi::FromInt(config)); 730 Isolate* isolate = GetIsolate(); 731 SetFeedbackExtra(*FeedbackVector::UninitializedSentinel(isolate), 732 SKIP_WRITE_BARRIER); 733 return true; 734 } 735 736 void FeedbackNexus::ConfigureHandlerMode(const MaybeObjectHandle& handler) { 737 DCHECK(IsGlobalICKind(kind())); 738 DCHECK(IC::IsHandler(*handler)); 739 SetFeedback(HeapObjectReference::ClearedValue()); 740 SetFeedbackExtra(*handler); 741 } 742 743 void FeedbackNexus::ConfigureCloneObject(Handle<Map> source_map, 744 Handle<Map> result_map) { 745 Isolate* isolate = GetIsolate(); 746 MaybeObject* maybe_feedback = GetFeedback(); 747 Handle<HeapObject> feedback(maybe_feedback->IsStrongOrWeakHeapObject() 748 ? maybe_feedback->GetHeapObject() 749 : nullptr, 750 isolate); 751 switch (ic_state()) { 752 case UNINITIALIZED: 753 // Cache the first map seen which meets the fast case requirements. 754 SetFeedback(HeapObjectReference::Weak(*source_map)); 755 SetFeedbackExtra(*result_map); 756 break; 757 case MONOMORPHIC: 758 if (maybe_feedback->IsClearedWeakHeapObject() || 759 feedback.is_identical_to(source_map) || 760 Map::cast(*feedback)->is_deprecated()) { 761 // Remain in MONOMORPHIC state if previous feedback has been collected. 762 SetFeedback(HeapObjectReference::Weak(*source_map)); 763 SetFeedbackExtra(*result_map); 764 } else { 765 // Transition to POLYMORPHIC. 766 Handle<WeakFixedArray> array = 767 EnsureArrayOfSize(2 * kCloneObjectPolymorphicEntrySize); 768 array->Set(0, maybe_feedback); 769 array->Set(1, GetFeedbackExtra()); 770 array->Set(2, HeapObjectReference::Weak(*source_map)); 771 array->Set(3, MaybeObject::FromObject(*result_map)); 772 SetFeedbackExtra(HeapObjectReference::ClearedValue()); 773 } 774 break; 775 case POLYMORPHIC: { 776 static constexpr int kMaxElements = 777 IC::kMaxPolymorphicMapCount * kCloneObjectPolymorphicEntrySize; 778 Handle<WeakFixedArray> array = Handle<WeakFixedArray>::cast(feedback); 779 int i = 0; 780 for (; i < array->length(); i += kCloneObjectPolymorphicEntrySize) { 781 MaybeObject* feedback = array->Get(i); 782 if (feedback->IsClearedWeakHeapObject()) break; 783 Handle<Map> cached_map(Map::cast(feedback->GetHeapObject()), isolate); 784 if (cached_map.is_identical_to(source_map) || 785 cached_map->is_deprecated()) 786 break; 787 } 788 789 if (i >= array->length()) { 790 if (i == kMaxElements) { 791 // Transition to MEGAMORPHIC. 792 MaybeObject* sentinel = MaybeObject::FromObject( 793 *FeedbackVector::MegamorphicSentinel(isolate)); 794 SetFeedback(sentinel, SKIP_WRITE_BARRIER); 795 SetFeedbackExtra(HeapObjectReference::ClearedValue()); 796 break; 797 } 798 799 // Grow polymorphic feedback array. 800 Handle<WeakFixedArray> new_array = EnsureArrayOfSize( 801 array->length() + kCloneObjectPolymorphicEntrySize); 802 for (int j = 0; j < array->length(); ++j) { 803 new_array->Set(j, array->Get(j)); 804 } 805 array = new_array; 806 } 807 808 array->Set(i, HeapObjectReference::Weak(*source_map)); 809 array->Set(i + 1, MaybeObject::FromObject(*result_map)); 810 break; 811 } 812 813 default: 814 UNREACHABLE(); 815 } 816 } 817 818 int FeedbackNexus::GetCallCount() { 819 DCHECK(IsCallICKind(kind())); 820 821 Object* call_count = GetFeedbackExtra()->ToObject(); 822 CHECK(call_count->IsSmi()); 823 uint32_t value = static_cast<uint32_t>(Smi::ToInt(call_count)); 824 return CallCountField::decode(value); 825 } 826 827 void FeedbackNexus::SetSpeculationMode(SpeculationMode mode) { 828 DCHECK(IsCallICKind(kind())); 829 830 Object* call_count = GetFeedbackExtra()->ToObject(); 831 CHECK(call_count->IsSmi()); 832 uint32_t count = static_cast<uint32_t>(Smi::ToInt(call_count)); 833 uint32_t value = CallCountField::encode(CallCountField::decode(count)); 834 int result = static_cast<int>(value | SpeculationModeField::encode(mode)); 835 SetFeedbackExtra(Smi::FromInt(result), SKIP_WRITE_BARRIER); 836 } 837 838 SpeculationMode FeedbackNexus::GetSpeculationMode() { 839 DCHECK(IsCallICKind(kind())); 840 841 Object* call_count = GetFeedbackExtra()->ToObject(); 842 CHECK(call_count->IsSmi()); 843 uint32_t value = static_cast<uint32_t>(Smi::ToInt(call_count)); 844 return SpeculationModeField::decode(value); 845 } 846 847 float FeedbackNexus::ComputeCallFrequency() { 848 DCHECK(IsCallICKind(kind())); 849 850 double const invocation_count = vector()->invocation_count(); 851 double const call_count = GetCallCount(); 852 if (invocation_count == 0) { 853 // Prevent division by 0. 854 return 0.0f; 855 } 856 return static_cast<float>(call_count / invocation_count); 857 } 858 859 void FeedbackNexus::ConfigureMonomorphic(Handle<Name> name, 860 Handle<Map> receiver_map, 861 const MaybeObjectHandle& handler) { 862 DCHECK(handler.is_null() || IC::IsHandler(*handler)); 863 if (kind() == FeedbackSlotKind::kStoreDataPropertyInLiteral) { 864 SetFeedback(HeapObjectReference::Weak(*receiver_map)); 865 SetFeedbackExtra(*name); 866 } else { 867 if (name.is_null()) { 868 SetFeedback(HeapObjectReference::Weak(*receiver_map)); 869 SetFeedbackExtra(*handler); 870 } else { 871 Handle<WeakFixedArray> array = EnsureExtraArrayOfSize(2); 872 SetFeedback(*name); 873 array->Set(0, HeapObjectReference::Weak(*receiver_map)); 874 array->Set(1, *handler); 875 } 876 } 877 } 878 879 void FeedbackNexus::ConfigurePolymorphic(Handle<Name> name, 880 MapHandles const& maps, 881 MaybeObjectHandles* handlers) { 882 DCHECK_EQ(handlers->size(), maps.size()); 883 int receiver_count = static_cast<int>(maps.size()); 884 DCHECK_GT(receiver_count, 1); 885 Handle<WeakFixedArray> array; 886 if (name.is_null()) { 887 array = EnsureArrayOfSize(receiver_count * 2); 888 SetFeedbackExtra(*FeedbackVector::UninitializedSentinel(GetIsolate()), 889 SKIP_WRITE_BARRIER); 890 } else { 891 array = EnsureExtraArrayOfSize(receiver_count * 2); 892 SetFeedback(*name); 893 } 894 895 for (int current = 0; current < receiver_count; ++current) { 896 Handle<Map> map = maps[current]; 897 array->Set(current * 2, HeapObjectReference::Weak(*map)); 898 DCHECK(IC::IsHandler(*handlers->at(current))); 899 array->Set(current * 2 + 1, *handlers->at(current)); 900 } 901 } 902 903 int FeedbackNexus::ExtractMaps(MapHandles* maps) const { 904 DCHECK(IsLoadICKind(kind()) || IsStoreICKind(kind()) || 905 IsKeyedLoadICKind(kind()) || IsKeyedStoreICKind(kind()) || 906 IsStoreOwnICKind(kind()) || IsStoreDataPropertyInLiteralKind(kind()) || 907 IsStoreInArrayLiteralICKind(kind())); 908 909 Isolate* isolate = GetIsolate(); 910 MaybeObject* feedback = GetFeedback(); 911 bool is_named_feedback = IsPropertyNameFeedback(feedback); 912 HeapObject* heap_object; 913 if ((feedback->ToStrongHeapObject(&heap_object) && 914 heap_object->IsWeakFixedArray()) || 915 is_named_feedback) { 916 int found = 0; 917 WeakFixedArray* array; 918 if (is_named_feedback) { 919 array = WeakFixedArray::cast(GetFeedbackExtra()->ToStrongHeapObject()); 920 } else { 921 array = WeakFixedArray::cast(heap_object); 922 } 923 const int increment = 2; 924 HeapObject* heap_object; 925 for (int i = 0; i < array->length(); i += increment) { 926 DCHECK(array->Get(i)->IsWeakOrClearedHeapObject()); 927 if (array->Get(i)->ToWeakHeapObject(&heap_object)) { 928 Map* map = Map::cast(heap_object); 929 maps->push_back(handle(map, isolate)); 930 found++; 931 } 932 } 933 return found; 934 } else if (feedback->ToWeakHeapObject(&heap_object)) { 935 Map* map = Map::cast(heap_object); 936 maps->push_back(handle(map, isolate)); 937 return 1; 938 } else if (feedback->ToStrongHeapObject(&heap_object) && 939 heap_object == 940 heap_object->GetReadOnlyRoots().premonomorphic_symbol()) { 941 if (GetFeedbackExtra()->ToWeakHeapObject(&heap_object)) { 942 Map* map = Map::cast(heap_object); 943 maps->push_back(handle(map, isolate)); 944 return 1; 945 } 946 } 947 948 return 0; 949 } 950 951 MaybeObjectHandle FeedbackNexus::FindHandlerForMap(Handle<Map> map) const { 952 DCHECK(IsLoadICKind(kind()) || IsStoreICKind(kind()) || 953 IsKeyedLoadICKind(kind()) || IsKeyedStoreICKind(kind()) || 954 IsStoreOwnICKind(kind()) || IsStoreDataPropertyInLiteralKind(kind())); 955 956 MaybeObject* feedback = GetFeedback(); 957 Isolate* isolate = GetIsolate(); 958 bool is_named_feedback = IsPropertyNameFeedback(feedback); 959 HeapObject* heap_object; 960 if ((feedback->ToStrongHeapObject(&heap_object) && 961 heap_object->IsWeakFixedArray()) || 962 is_named_feedback) { 963 WeakFixedArray* array; 964 if (is_named_feedback) { 965 array = WeakFixedArray::cast(GetFeedbackExtra()->ToStrongHeapObject()); 966 } else { 967 array = WeakFixedArray::cast(heap_object); 968 } 969 const int increment = 2; 970 HeapObject* heap_object; 971 for (int i = 0; i < array->length(); i += increment) { 972 DCHECK(array->Get(i)->IsWeakOrClearedHeapObject()); 973 if (array->Get(i)->ToWeakHeapObject(&heap_object)) { 974 Map* array_map = Map::cast(heap_object); 975 if (array_map == *map && 976 !array->Get(i + increment - 1)->IsClearedWeakHeapObject()) { 977 MaybeObject* handler = array->Get(i + increment - 1); 978 DCHECK(IC::IsHandler(handler)); 979 return handle(handler, isolate); 980 } 981 } 982 } 983 } else if (feedback->ToWeakHeapObject(&heap_object)) { 984 Map* cell_map = Map::cast(heap_object); 985 if (cell_map == *map && !GetFeedbackExtra()->IsClearedWeakHeapObject()) { 986 MaybeObject* handler = GetFeedbackExtra(); 987 DCHECK(IC::IsHandler(handler)); 988 return handle(handler, isolate); 989 } 990 } 991 992 return MaybeObjectHandle(); 993 } 994 995 bool FeedbackNexus::FindHandlers(MaybeObjectHandles* code_list, 996 int length) const { 997 DCHECK(IsLoadICKind(kind()) || IsStoreICKind(kind()) || 998 IsKeyedLoadICKind(kind()) || IsKeyedStoreICKind(kind()) || 999 IsStoreOwnICKind(kind()) || IsStoreDataPropertyInLiteralKind(kind()) || 1000 IsStoreInArrayLiteralICKind(kind())); 1001 1002 MaybeObject* feedback = GetFeedback(); 1003 Isolate* isolate = GetIsolate(); 1004 int count = 0; 1005 bool is_named_feedback = IsPropertyNameFeedback(feedback); 1006 HeapObject* heap_object; 1007 if ((feedback->ToStrongHeapObject(&heap_object) && 1008 heap_object->IsWeakFixedArray()) || 1009 is_named_feedback) { 1010 WeakFixedArray* array; 1011 if (is_named_feedback) { 1012 array = WeakFixedArray::cast(GetFeedbackExtra()->ToStrongHeapObject()); 1013 } else { 1014 array = WeakFixedArray::cast(heap_object); 1015 } 1016 const int increment = 2; 1017 HeapObject* heap_object; 1018 for (int i = 0; i < array->length(); i += increment) { 1019 // Be sure to skip handlers whose maps have been cleared. 1020 DCHECK(array->Get(i)->IsWeakOrClearedHeapObject()); 1021 if (array->Get(i)->ToWeakHeapObject(&heap_object) && 1022 !array->Get(i + increment - 1)->IsClearedWeakHeapObject()) { 1023 MaybeObject* handler = array->Get(i + increment - 1); 1024 DCHECK(IC::IsHandler(handler)); 1025 code_list->push_back(handle(handler, isolate)); 1026 count++; 1027 } 1028 } 1029 } else if (feedback->ToWeakHeapObject(&heap_object)) { 1030 MaybeObject* extra = GetFeedbackExtra(); 1031 if (!extra->IsClearedWeakHeapObject()) { 1032 DCHECK(IC::IsHandler(extra)); 1033 code_list->push_back(handle(extra, isolate)); 1034 count++; 1035 } 1036 } 1037 return count == length; 1038 } 1039 1040 Name* FeedbackNexus::FindFirstName() const { 1041 if (IsKeyedStoreICKind(kind()) || IsKeyedLoadICKind(kind())) { 1042 MaybeObject* feedback = GetFeedback(); 1043 if (IsPropertyNameFeedback(feedback)) { 1044 return Name::cast(feedback->ToStrongHeapObject()); 1045 } 1046 } 1047 return nullptr; 1048 } 1049 1050 KeyedAccessLoadMode FeedbackNexus::GetKeyedAccessLoadMode() const { 1051 DCHECK(IsKeyedLoadICKind(kind())); 1052 MapHandles maps; 1053 MaybeObjectHandles handlers; 1054 1055 if (GetKeyType() == PROPERTY) return STANDARD_LOAD; 1056 1057 ExtractMaps(&maps); 1058 FindHandlers(&handlers, static_cast<int>(maps.size())); 1059 for (MaybeObjectHandle const& handler : handlers) { 1060 KeyedAccessLoadMode mode = LoadHandler::GetKeyedAccessLoadMode(*handler); 1061 if (mode != STANDARD_LOAD) return mode; 1062 } 1063 1064 return STANDARD_LOAD; 1065 } 1066 1067 KeyedAccessStoreMode FeedbackNexus::GetKeyedAccessStoreMode() const { 1068 DCHECK(IsKeyedStoreICKind(kind()) || IsStoreInArrayLiteralICKind(kind())); 1069 KeyedAccessStoreMode mode = STANDARD_STORE; 1070 MapHandles maps; 1071 MaybeObjectHandles handlers; 1072 1073 if (GetKeyType() == PROPERTY) return mode; 1074 1075 ExtractMaps(&maps); 1076 FindHandlers(&handlers, static_cast<int>(maps.size())); 1077 for (const MaybeObjectHandle& maybe_code_handler : handlers) { 1078 // The first handler that isn't the slow handler will have the bits we need. 1079 Handle<Code> handler; 1080 if (maybe_code_handler.object()->IsStoreHandler()) { 1081 Handle<StoreHandler> data_handler = 1082 Handle<StoreHandler>::cast(maybe_code_handler.object()); 1083 handler = handle(Code::cast(data_handler->smi_handler()), 1084 vector()->GetIsolate()); 1085 } else if (maybe_code_handler.object()->IsSmi()) { 1086 // Skip proxy handlers. 1087 DCHECK_EQ(*(maybe_code_handler.object()), 1088 *StoreHandler::StoreProxy(GetIsolate())); 1089 continue; 1090 } else { 1091 // Element store without prototype chain check. 1092 handler = Handle<Code>::cast(maybe_code_handler.object()); 1093 if (handler->is_builtin()) continue; 1094 } 1095 CodeStub::Major major_key = CodeStub::MajorKeyFromKey(handler->stub_key()); 1096 uint32_t minor_key = CodeStub::MinorKeyFromKey(handler->stub_key()); 1097 CHECK(major_key == CodeStub::KeyedStoreSloppyArguments || 1098 major_key == CodeStub::StoreFastElement || 1099 major_key == CodeStub::StoreSlowElement || 1100 major_key == CodeStub::StoreInArrayLiteralSlow || 1101 major_key == CodeStub::ElementsTransitionAndStore || 1102 major_key == CodeStub::NoCache); 1103 if (major_key != CodeStub::NoCache) { 1104 mode = CommonStoreModeBits::decode(minor_key); 1105 break; 1106 } 1107 } 1108 1109 return mode; 1110 } 1111 1112 IcCheckType FeedbackNexus::GetKeyType() const { 1113 DCHECK(IsKeyedStoreICKind(kind()) || IsKeyedLoadICKind(kind()) || 1114 IsStoreInArrayLiteralICKind(kind())); 1115 MaybeObject* feedback = GetFeedback(); 1116 if (feedback == MaybeObject::FromObject( 1117 *FeedbackVector::MegamorphicSentinel(GetIsolate()))) { 1118 return static_cast<IcCheckType>(Smi::ToInt(GetFeedbackExtra()->ToObject())); 1119 } 1120 return IsPropertyNameFeedback(feedback) ? PROPERTY : ELEMENT; 1121 } 1122 1123 BinaryOperationHint FeedbackNexus::GetBinaryOperationFeedback() const { 1124 DCHECK_EQ(kind(), FeedbackSlotKind::kBinaryOp); 1125 int feedback = Smi::ToInt(GetFeedback()->ToSmi()); 1126 return BinaryOperationHintFromFeedback(feedback); 1127 } 1128 1129 CompareOperationHint FeedbackNexus::GetCompareOperationFeedback() const { 1130 DCHECK_EQ(kind(), FeedbackSlotKind::kCompareOp); 1131 int feedback = Smi::ToInt(GetFeedback()->ToSmi()); 1132 return CompareOperationHintFromFeedback(feedback); 1133 } 1134 1135 ForInHint FeedbackNexus::GetForInFeedback() const { 1136 DCHECK_EQ(kind(), FeedbackSlotKind::kForIn); 1137 int feedback = Smi::ToInt(GetFeedback()->ToSmi()); 1138 return ForInHintFromFeedback(feedback); 1139 } 1140 1141 Handle<FeedbackCell> FeedbackNexus::GetFeedbackCell() const { 1142 DCHECK_EQ(FeedbackSlotKind::kCreateClosure, kind()); 1143 return handle(FeedbackCell::cast(GetFeedback()->ToObject()), 1144 vector()->GetIsolate()); 1145 } 1146 1147 MaybeHandle<JSObject> FeedbackNexus::GetConstructorFeedback() const { 1148 DCHECK_EQ(kind(), FeedbackSlotKind::kInstanceOf); 1149 Isolate* isolate = GetIsolate(); 1150 MaybeObject* feedback = GetFeedback(); 1151 HeapObject* heap_object; 1152 if (feedback->ToWeakHeapObject(&heap_object)) { 1153 return handle(JSObject::cast(heap_object), isolate); 1154 } 1155 return MaybeHandle<JSObject>(); 1156 } 1157 1158 namespace { 1159 1160 bool InList(Handle<ArrayList> types, Handle<String> type) { 1161 for (int i = 0; i < types->Length(); i++) { 1162 Object* obj = types->Get(i); 1163 if (String::cast(obj)->Equals(*type)) { 1164 return true; 1165 } 1166 } 1167 return false; 1168 } 1169 } // anonymous namespace 1170 1171 void FeedbackNexus::Collect(Handle<String> type, int position) { 1172 DCHECK(IsTypeProfileKind(kind())); 1173 DCHECK_GE(position, 0); 1174 Isolate* isolate = GetIsolate(); 1175 1176 MaybeObject* const feedback = GetFeedback(); 1177 1178 // Map source position to collection of types 1179 Handle<SimpleNumberDictionary> types; 1180 1181 if (feedback == MaybeObject::FromObject( 1182 *FeedbackVector::UninitializedSentinel(isolate))) { 1183 types = SimpleNumberDictionary::New(isolate, 1); 1184 } else { 1185 types = handle(SimpleNumberDictionary::cast(feedback->ToStrongHeapObject()), 1186 isolate); 1187 } 1188 1189 Handle<ArrayList> position_specific_types; 1190 1191 int entry = types->FindEntry(isolate, position); 1192 if (entry == SimpleNumberDictionary::kNotFound) { 1193 position_specific_types = ArrayList::New(isolate, 1); 1194 types = SimpleNumberDictionary::Set( 1195 isolate, types, position, 1196 ArrayList::Add(isolate, position_specific_types, type)); 1197 } else { 1198 DCHECK(types->ValueAt(entry)->IsArrayList()); 1199 position_specific_types = 1200 handle(ArrayList::cast(types->ValueAt(entry)), isolate); 1201 if (!InList(position_specific_types, type)) { // Add type 1202 types = SimpleNumberDictionary::Set( 1203 isolate, types, position, 1204 ArrayList::Add(isolate, position_specific_types, type)); 1205 } 1206 } 1207 SetFeedback(*types); 1208 } 1209 1210 std::vector<int> FeedbackNexus::GetSourcePositions() const { 1211 DCHECK(IsTypeProfileKind(kind())); 1212 std::vector<int> source_positions; 1213 Isolate* isolate = GetIsolate(); 1214 1215 MaybeObject* const feedback = GetFeedback(); 1216 1217 if (feedback == MaybeObject::FromObject( 1218 *FeedbackVector::UninitializedSentinel(isolate))) { 1219 return source_positions; 1220 } 1221 1222 Handle<SimpleNumberDictionary> types( 1223 SimpleNumberDictionary::cast(feedback->ToStrongHeapObject()), isolate); 1224 1225 for (int index = SimpleNumberDictionary::kElementsStartIndex; 1226 index < types->length(); index += SimpleNumberDictionary::kEntrySize) { 1227 int key_index = index + SimpleNumberDictionary::kEntryKeyIndex; 1228 Object* key = types->get(key_index); 1229 if (key->IsSmi()) { 1230 int position = Smi::cast(key)->value(); 1231 source_positions.push_back(position); 1232 } 1233 } 1234 return source_positions; 1235 } 1236 1237 std::vector<Handle<String>> FeedbackNexus::GetTypesForSourcePositions( 1238 uint32_t position) const { 1239 DCHECK(IsTypeProfileKind(kind())); 1240 Isolate* isolate = GetIsolate(); 1241 1242 MaybeObject* const feedback = GetFeedback(); 1243 std::vector<Handle<String>> types_for_position; 1244 if (feedback == MaybeObject::FromObject( 1245 *FeedbackVector::UninitializedSentinel(isolate))) { 1246 return types_for_position; 1247 } 1248 1249 Handle<SimpleNumberDictionary> types( 1250 SimpleNumberDictionary::cast(feedback->ToStrongHeapObject()), isolate); 1251 1252 int entry = types->FindEntry(isolate, position); 1253 if (entry == SimpleNumberDictionary::kNotFound) { 1254 return types_for_position; 1255 } 1256 DCHECK(types->ValueAt(entry)->IsArrayList()); 1257 Handle<ArrayList> position_specific_types = 1258 Handle<ArrayList>(ArrayList::cast(types->ValueAt(entry)), isolate); 1259 for (int i = 0; i < position_specific_types->Length(); i++) { 1260 Object* t = position_specific_types->Get(i); 1261 types_for_position.push_back(Handle<String>(String::cast(t), isolate)); 1262 } 1263 1264 return types_for_position; 1265 } 1266 1267 namespace { 1268 1269 Handle<JSObject> ConvertToJSObject(Isolate* isolate, 1270 Handle<SimpleNumberDictionary> feedback) { 1271 Handle<JSObject> type_profile = 1272 isolate->factory()->NewJSObject(isolate->object_function()); 1273 1274 for (int index = SimpleNumberDictionary::kElementsStartIndex; 1275 index < feedback->length(); 1276 index += SimpleNumberDictionary::kEntrySize) { 1277 int key_index = index + SimpleNumberDictionary::kEntryKeyIndex; 1278 Object* key = feedback->get(key_index); 1279 if (key->IsSmi()) { 1280 int value_index = index + SimpleNumberDictionary::kEntryValueIndex; 1281 1282 Handle<ArrayList> position_specific_types( 1283 ArrayList::cast(feedback->get(value_index)), isolate); 1284 1285 int position = Smi::ToInt(key); 1286 JSObject::AddDataElement( 1287 type_profile, position, 1288 isolate->factory()->NewJSArrayWithElements( 1289 ArrayList::Elements(isolate, position_specific_types)), 1290 PropertyAttributes::NONE); 1291 } 1292 } 1293 return type_profile; 1294 } 1295 } // namespace 1296 1297 JSObject* FeedbackNexus::GetTypeProfile() const { 1298 DCHECK(IsTypeProfileKind(kind())); 1299 Isolate* isolate = GetIsolate(); 1300 1301 MaybeObject* const feedback = GetFeedback(); 1302 1303 if (feedback == MaybeObject::FromObject( 1304 *FeedbackVector::UninitializedSentinel(isolate))) { 1305 return *isolate->factory()->NewJSObject(isolate->object_function()); 1306 } 1307 1308 return *ConvertToJSObject( 1309 isolate, 1310 handle(SimpleNumberDictionary::cast(feedback->ToStrongHeapObject()), 1311 isolate)); 1312 } 1313 1314 void FeedbackNexus::ResetTypeProfile() { 1315 DCHECK(IsTypeProfileKind(kind())); 1316 SetFeedback(*FeedbackVector::UninitializedSentinel(GetIsolate())); 1317 } 1318 1319 } // namespace internal 1320 } // namespace v8 1321