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/ic/ic-state.h" 10 #include "src/objects.h" 11 12 namespace v8 { 13 namespace internal { 14 15 static bool IsPropertyNameFeedback(Object* feedback) { 16 if (feedback->IsString()) return true; 17 if (!feedback->IsSymbol()) return false; 18 Symbol* symbol = Symbol::cast(feedback); 19 Heap* heap = symbol->GetHeap(); 20 return symbol != heap->uninitialized_symbol() && 21 symbol != heap->premonomorphic_symbol() && 22 symbol != heap->megamorphic_symbol(); 23 } 24 25 std::ostream& operator<<(std::ostream& os, FeedbackSlotKind kind) { 26 return os << FeedbackMetadata::Kind2String(kind); 27 } 28 29 FeedbackSlotKind FeedbackMetadata::GetKind(FeedbackSlot slot) const { 30 int index = VectorICComputer::index(kReservedIndexCount, slot.ToInt()); 31 int data = Smi::cast(get(index))->value(); 32 return VectorICComputer::decode(data, slot.ToInt()); 33 } 34 35 void FeedbackMetadata::SetKind(FeedbackSlot slot, FeedbackSlotKind kind) { 36 int index = VectorICComputer::index(kReservedIndexCount, slot.ToInt()); 37 int data = Smi::cast(get(index))->value(); 38 int new_data = VectorICComputer::encode(data, slot.ToInt(), kind); 39 set(index, Smi::FromInt(new_data)); 40 } 41 42 template Handle<FeedbackMetadata> FeedbackMetadata::New( 43 Isolate* isolate, const StaticFeedbackVectorSpec* spec); 44 template Handle<FeedbackMetadata> FeedbackMetadata::New( 45 Isolate* isolate, const FeedbackVectorSpec* spec); 46 47 // static 48 template <typename Spec> 49 Handle<FeedbackMetadata> FeedbackMetadata::New(Isolate* isolate, 50 const Spec* spec) { 51 Factory* factory = isolate->factory(); 52 53 const int slot_count = spec->slots(); 54 const int slot_kinds_length = VectorICComputer::word_count(slot_count); 55 const int length = slot_kinds_length + kReservedIndexCount; 56 if (length == kReservedIndexCount) { 57 return Handle<FeedbackMetadata>::cast(factory->empty_fixed_array()); 58 } 59 #ifdef DEBUG 60 for (int i = 0; i < slot_count;) { 61 FeedbackSlotKind kind = spec->GetKind(FeedbackSlot(i)); 62 int entry_size = FeedbackMetadata::GetSlotSize(kind); 63 for (int j = 1; j < entry_size; j++) { 64 FeedbackSlotKind kind = spec->GetKind(FeedbackSlot(i + j)); 65 DCHECK_EQ(FeedbackSlotKind::kInvalid, kind); 66 } 67 i += entry_size; 68 } 69 #endif 70 71 Handle<FixedArray> array = factory->NewFixedArray(length, TENURED); 72 array->set(kSlotsCountIndex, Smi::FromInt(slot_count)); 73 // Fill the bit-vector part with zeros. 74 for (int i = 0; i < slot_kinds_length; i++) { 75 array->set(kReservedIndexCount + i, Smi::kZero); 76 } 77 78 Handle<FeedbackMetadata> metadata = Handle<FeedbackMetadata>::cast(array); 79 80 for (int i = 0; i < slot_count; i++) { 81 FeedbackSlot slot(i); 82 FeedbackSlotKind kind = spec->GetKind(slot); 83 metadata->SetKind(slot, kind); 84 } 85 86 // It's important that the FeedbackMetadata have a COW map, since it's 87 // pointed to by both a SharedFunctionInfo and indirectly by closures through 88 // the FeedbackVector. The serializer uses the COW map type to decide 89 // this object belongs in the startup snapshot and not the partial 90 // snapshot(s). 91 metadata->set_map(isolate->heap()->fixed_cow_array_map()); 92 93 return metadata; 94 } 95 96 bool FeedbackMetadata::SpecDiffersFrom( 97 const FeedbackVectorSpec* other_spec) const { 98 if (other_spec->slots() != slot_count()) { 99 return true; 100 } 101 102 int slots = slot_count(); 103 for (int i = 0; i < slots;) { 104 FeedbackSlot slot(i); 105 FeedbackSlotKind kind = GetKind(slot); 106 int entry_size = FeedbackMetadata::GetSlotSize(kind); 107 108 if (kind != other_spec->GetKind(slot)) { 109 return true; 110 } 111 i += entry_size; 112 } 113 return false; 114 } 115 116 const char* FeedbackMetadata::Kind2String(FeedbackSlotKind kind) { 117 switch (kind) { 118 case FeedbackSlotKind::kInvalid: 119 return "INVALID"; 120 case FeedbackSlotKind::kCall: 121 return "CALL_IC"; 122 case FeedbackSlotKind::kLoadProperty: 123 return "LOAD_IC"; 124 case FeedbackSlotKind::kLoadGlobalInsideTypeof: 125 return "LOAD_GLOBAL_INSIDE_TYPEOF_IC"; 126 case FeedbackSlotKind::kLoadGlobalNotInsideTypeof: 127 return "LOAD_GLOBAL_NOT_INSIDE_TYPEOF_IC"; 128 case FeedbackSlotKind::kLoadKeyed: 129 return "KEYED_LOAD_IC"; 130 case FeedbackSlotKind::kStoreNamedSloppy: 131 return "STORE_SLOPPY_IC"; 132 case FeedbackSlotKind::kStoreNamedStrict: 133 return "STORE_STRICT_IC"; 134 case FeedbackSlotKind::kStoreOwnNamed: 135 return "STORE_OWN_IC"; 136 case FeedbackSlotKind::kStoreKeyedSloppy: 137 return "KEYED_STORE_SLOPPY_IC"; 138 case FeedbackSlotKind::kStoreKeyedStrict: 139 return "KEYED_STORE_STRICT_IC"; 140 case FeedbackSlotKind::kBinaryOp: 141 return "INTERPRETER_BINARYOP_IC"; 142 case FeedbackSlotKind::kCompareOp: 143 return "INTERPRETER_COMPARE_IC"; 144 case FeedbackSlotKind::kToBoolean: 145 return "TO_BOOLEAN_IC"; 146 case FeedbackSlotKind::kStoreDataPropertyInLiteral: 147 return "STORE_DATA_PROPERTY_IN_LITERAL_IC"; 148 case FeedbackSlotKind::kCreateClosure: 149 return "kCreateClosure"; 150 case FeedbackSlotKind::kLiteral: 151 return "LITERAL"; 152 case FeedbackSlotKind::kGeneral: 153 return "STUB"; 154 case FeedbackSlotKind::kKindsNumber: 155 break; 156 } 157 UNREACHABLE(); 158 return "?"; 159 } 160 161 FeedbackSlotKind FeedbackVector::GetKind(FeedbackSlot slot) const { 162 DCHECK(!is_empty()); 163 return metadata()->GetKind(slot); 164 } 165 166 // static 167 Handle<FeedbackVector> FeedbackVector::New(Isolate* isolate, 168 Handle<SharedFunctionInfo> shared) { 169 Factory* factory = isolate->factory(); 170 171 const int slot_count = shared->feedback_metadata()->slot_count(); 172 const int length = slot_count + kReservedIndexCount; 173 174 Handle<FixedArray> array = factory->NewFixedArray(length, TENURED); 175 array->set_map_no_write_barrier(isolate->heap()->feedback_vector_map()); 176 array->set(kSharedFunctionInfoIndex, *shared); 177 array->set(kInvocationCountIndex, Smi::kZero); 178 179 // Ensure we can skip the write barrier 180 Handle<Object> uninitialized_sentinel = UninitializedSentinel(isolate); 181 DCHECK_EQ(isolate->heap()->uninitialized_symbol(), *uninitialized_sentinel); 182 Handle<Oddball> undefined_value = factory->undefined_value(); 183 for (int i = 0; i < slot_count;) { 184 FeedbackSlot slot(i); 185 FeedbackSlotKind kind = shared->feedback_metadata()->GetKind(slot); 186 int index = FeedbackVector::GetIndex(slot); 187 int entry_size = FeedbackMetadata::GetSlotSize(kind); 188 189 Object* extra_value = *uninitialized_sentinel; 190 switch (kind) { 191 case FeedbackSlotKind::kLoadGlobalInsideTypeof: 192 case FeedbackSlotKind::kLoadGlobalNotInsideTypeof: 193 array->set(index, isolate->heap()->empty_weak_cell(), 194 SKIP_WRITE_BARRIER); 195 break; 196 case FeedbackSlotKind::kCompareOp: 197 case FeedbackSlotKind::kBinaryOp: 198 case FeedbackSlotKind::kToBoolean: 199 array->set(index, Smi::kZero, SKIP_WRITE_BARRIER); 200 break; 201 case FeedbackSlotKind::kCreateClosure: { 202 Handle<Cell> cell = factory->NewNoClosuresCell(undefined_value); 203 array->set(index, *cell); 204 break; 205 } 206 case FeedbackSlotKind::kLiteral: 207 array->set(index, *undefined_value, SKIP_WRITE_BARRIER); 208 break; 209 case FeedbackSlotKind::kCall: 210 array->set(index, *uninitialized_sentinel, SKIP_WRITE_BARRIER); 211 extra_value = Smi::kZero; 212 break; 213 case FeedbackSlotKind::kLoadProperty: 214 case FeedbackSlotKind::kLoadKeyed: 215 case FeedbackSlotKind::kStoreNamedSloppy: 216 case FeedbackSlotKind::kStoreNamedStrict: 217 case FeedbackSlotKind::kStoreOwnNamed: 218 case FeedbackSlotKind::kStoreKeyedSloppy: 219 case FeedbackSlotKind::kStoreKeyedStrict: 220 case FeedbackSlotKind::kStoreDataPropertyInLiteral: 221 case FeedbackSlotKind::kGeneral: 222 array->set(index, *uninitialized_sentinel, SKIP_WRITE_BARRIER); 223 break; 224 225 case FeedbackSlotKind::kInvalid: 226 case FeedbackSlotKind::kKindsNumber: 227 UNREACHABLE(); 228 array->set(index, Smi::kZero, SKIP_WRITE_BARRIER); 229 break; 230 } 231 for (int j = 1; j < entry_size; j++) { 232 array->set(index + j, extra_value, SKIP_WRITE_BARRIER); 233 } 234 i += entry_size; 235 } 236 237 Handle<FeedbackVector> result = Handle<FeedbackVector>::cast(array); 238 if (isolate->IsCodeCoverageEnabled()) AddToCodeCoverageList(isolate, result); 239 return result; 240 } 241 242 // static 243 Handle<FeedbackVector> FeedbackVector::Copy(Isolate* isolate, 244 Handle<FeedbackVector> vector) { 245 Handle<FeedbackVector> result; 246 result = Handle<FeedbackVector>::cast( 247 isolate->factory()->CopyFixedArray(Handle<FixedArray>::cast(vector))); 248 if (isolate->IsCodeCoverageEnabled()) AddToCodeCoverageList(isolate, result); 249 return result; 250 } 251 252 // static 253 void FeedbackVector::AddToCodeCoverageList(Isolate* isolate, 254 Handle<FeedbackVector> vector) { 255 DCHECK(isolate->IsCodeCoverageEnabled()); 256 if (!vector->shared_function_info()->IsSubjectToDebugging()) return; 257 Handle<ArrayList> list = 258 Handle<ArrayList>::cast(isolate->factory()->code_coverage_list()); 259 list = ArrayList::Add(list, vector); 260 isolate->SetCodeCoverageList(*list); 261 } 262 263 void FeedbackVector::ClearSlots(JSFunction* host_function) { 264 Isolate* isolate = GetIsolate(); 265 266 Object* uninitialized_sentinel = 267 FeedbackVector::RawUninitializedSentinel(isolate); 268 Oddball* undefined_value = isolate->heap()->undefined_value(); 269 270 bool feedback_updated = false; 271 FeedbackMetadataIterator iter(metadata()); 272 while (iter.HasNext()) { 273 FeedbackSlot slot = iter.Next(); 274 FeedbackSlotKind kind = iter.kind(); 275 276 Object* obj = Get(slot); 277 if (obj != uninitialized_sentinel) { 278 switch (kind) { 279 case FeedbackSlotKind::kCall: { 280 CallICNexus nexus(this, slot); 281 if (!nexus.IsCleared()) { 282 nexus.Clear(); 283 feedback_updated = true; 284 } 285 break; 286 } 287 case FeedbackSlotKind::kLoadProperty: { 288 LoadICNexus nexus(this, slot); 289 if (!nexus.IsCleared()) { 290 nexus.Clear(); 291 feedback_updated = true; 292 } 293 break; 294 } 295 case FeedbackSlotKind::kLoadGlobalInsideTypeof: 296 case FeedbackSlotKind::kLoadGlobalNotInsideTypeof: { 297 LoadGlobalICNexus nexus(this, slot); 298 if (!nexus.IsCleared()) { 299 nexus.Clear(); 300 feedback_updated = true; 301 } 302 break; 303 } 304 case FeedbackSlotKind::kLoadKeyed: { 305 KeyedLoadICNexus nexus(this, slot); 306 if (!nexus.IsCleared()) { 307 nexus.Clear(); 308 feedback_updated = true; 309 } 310 break; 311 } 312 case FeedbackSlotKind::kStoreNamedSloppy: 313 case FeedbackSlotKind::kStoreNamedStrict: 314 case FeedbackSlotKind::kStoreOwnNamed: { 315 StoreICNexus nexus(this, slot); 316 if (!nexus.IsCleared()) { 317 nexus.Clear(); 318 feedback_updated = true; 319 } 320 break; 321 } 322 case FeedbackSlotKind::kStoreKeyedSloppy: 323 case FeedbackSlotKind::kStoreKeyedStrict: { 324 KeyedStoreICNexus nexus(this, slot); 325 if (!nexus.IsCleared()) { 326 nexus.Clear(); 327 feedback_updated = true; 328 } 329 break; 330 } 331 case FeedbackSlotKind::kBinaryOp: 332 case FeedbackSlotKind::kCompareOp: { 333 DCHECK(Get(slot)->IsSmi()); 334 // don't clear these smi slots. 335 // Set(slot, Smi::kZero); 336 break; 337 } 338 case FeedbackSlotKind::kCreateClosure: { 339 break; 340 } 341 case FeedbackSlotKind::kGeneral: { 342 if (obj->IsHeapObject()) { 343 InstanceType instance_type = 344 HeapObject::cast(obj)->map()->instance_type(); 345 // AllocationSites are exempt from clearing. They don't store Maps 346 // or Code pointers which can cause memory leaks if not cleared 347 // regularly. 348 if (instance_type != ALLOCATION_SITE_TYPE) { 349 Set(slot, uninitialized_sentinel, SKIP_WRITE_BARRIER); 350 feedback_updated = true; 351 } 352 } 353 break; 354 } 355 case FeedbackSlotKind::kLiteral: { 356 Set(slot, undefined_value, SKIP_WRITE_BARRIER); 357 feedback_updated = true; 358 break; 359 } 360 case FeedbackSlotKind::kStoreDataPropertyInLiteral: { 361 StoreDataPropertyInLiteralICNexus nexus(this, slot); 362 if (!nexus.IsCleared()) { 363 nexus.Clear(); 364 feedback_updated = true; 365 } 366 break; 367 } 368 case FeedbackSlotKind::kToBoolean: 369 case FeedbackSlotKind::kInvalid: 370 case FeedbackSlotKind::kKindsNumber: 371 UNREACHABLE(); 372 break; 373 } 374 } 375 } 376 if (feedback_updated) { 377 IC::OnFeedbackChanged(isolate, host_function); 378 } 379 } 380 381 Handle<FixedArray> FeedbackNexus::EnsureArrayOfSize(int length) { 382 Isolate* isolate = GetIsolate(); 383 Handle<Object> feedback = handle(GetFeedback(), isolate); 384 if (!feedback->IsFixedArray() || 385 FixedArray::cast(*feedback)->length() != length) { 386 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length); 387 SetFeedback(*array); 388 return array; 389 } 390 return Handle<FixedArray>::cast(feedback); 391 } 392 393 Handle<FixedArray> FeedbackNexus::EnsureExtraArrayOfSize(int length) { 394 Isolate* isolate = GetIsolate(); 395 Handle<Object> feedback_extra = handle(GetFeedbackExtra(), isolate); 396 if (!feedback_extra->IsFixedArray() || 397 FixedArray::cast(*feedback_extra)->length() != length) { 398 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length); 399 SetFeedbackExtra(*array); 400 return array; 401 } 402 return Handle<FixedArray>::cast(feedback_extra); 403 } 404 405 void FeedbackNexus::InstallHandlers(Handle<FixedArray> array, 406 MapHandleList* maps, 407 List<Handle<Object>>* handlers) { 408 int receiver_count = maps->length(); 409 for (int current = 0; current < receiver_count; ++current) { 410 Handle<Map> map = maps->at(current); 411 Handle<WeakCell> cell = Map::WeakCellForMap(map); 412 array->set(current * 2, *cell); 413 array->set(current * 2 + 1, *handlers->at(current)); 414 } 415 } 416 417 void FeedbackNexus::ConfigureUninitialized() { 418 SetFeedback(*FeedbackVector::UninitializedSentinel(GetIsolate()), 419 SKIP_WRITE_BARRIER); 420 SetFeedbackExtra(*FeedbackVector::UninitializedSentinel(GetIsolate()), 421 SKIP_WRITE_BARRIER); 422 } 423 424 void FeedbackNexus::ConfigurePremonomorphic() { 425 SetFeedback(*FeedbackVector::PremonomorphicSentinel(GetIsolate()), 426 SKIP_WRITE_BARRIER); 427 SetFeedbackExtra(*FeedbackVector::UninitializedSentinel(GetIsolate()), 428 SKIP_WRITE_BARRIER); 429 } 430 431 void FeedbackNexus::ConfigureMegamorphic() { 432 // Keyed ICs must use ConfigureMegamorphicKeyed. 433 DCHECK(!vector()->IsKeyedLoadIC(slot())); 434 DCHECK(!vector()->IsKeyedStoreIC(slot())); 435 436 Isolate* isolate = GetIsolate(); 437 SetFeedback(*FeedbackVector::MegamorphicSentinel(isolate), 438 SKIP_WRITE_BARRIER); 439 SetFeedbackExtra(*FeedbackVector::UninitializedSentinel(isolate), 440 SKIP_WRITE_BARRIER); 441 } 442 443 void KeyedLoadICNexus::ConfigureMegamorphicKeyed(IcCheckType property_type) { 444 Isolate* isolate = GetIsolate(); 445 SetFeedback(*FeedbackVector::MegamorphicSentinel(isolate), 446 SKIP_WRITE_BARRIER); 447 SetFeedbackExtra(Smi::FromInt(static_cast<int>(property_type)), 448 SKIP_WRITE_BARRIER); 449 } 450 451 void KeyedStoreICNexus::ConfigureMegamorphicKeyed(IcCheckType property_type) { 452 Isolate* isolate = GetIsolate(); 453 SetFeedback(*FeedbackVector::MegamorphicSentinel(isolate), 454 SKIP_WRITE_BARRIER); 455 SetFeedbackExtra(Smi::FromInt(static_cast<int>(property_type)), 456 SKIP_WRITE_BARRIER); 457 } 458 459 InlineCacheState LoadICNexus::StateFromFeedback() const { 460 Isolate* isolate = GetIsolate(); 461 Object* feedback = GetFeedback(); 462 463 if (feedback == *FeedbackVector::UninitializedSentinel(isolate)) { 464 return UNINITIALIZED; 465 } else if (feedback == *FeedbackVector::MegamorphicSentinel(isolate)) { 466 return MEGAMORPHIC; 467 } else if (feedback == *FeedbackVector::PremonomorphicSentinel(isolate)) { 468 return PREMONOMORPHIC; 469 } else if (feedback->IsFixedArray()) { 470 // Determine state purely by our structure, don't check if the maps are 471 // cleared. 472 return POLYMORPHIC; 473 } else if (feedback->IsWeakCell()) { 474 // Don't check if the map is cleared. 475 return MONOMORPHIC; 476 } 477 478 return UNINITIALIZED; 479 } 480 481 InlineCacheState LoadGlobalICNexus::StateFromFeedback() const { 482 Isolate* isolate = GetIsolate(); 483 Object* feedback = GetFeedback(); 484 485 Object* extra = GetFeedbackExtra(); 486 if (!WeakCell::cast(feedback)->cleared() || 487 extra != *FeedbackVector::UninitializedSentinel(isolate)) { 488 return MONOMORPHIC; 489 } 490 return UNINITIALIZED; 491 } 492 493 InlineCacheState KeyedLoadICNexus::StateFromFeedback() const { 494 Isolate* isolate = GetIsolate(); 495 Object* feedback = GetFeedback(); 496 497 if (feedback == *FeedbackVector::UninitializedSentinel(isolate)) { 498 return UNINITIALIZED; 499 } else if (feedback == *FeedbackVector::PremonomorphicSentinel(isolate)) { 500 return PREMONOMORPHIC; 501 } else if (feedback == *FeedbackVector::MegamorphicSentinel(isolate)) { 502 return MEGAMORPHIC; 503 } else if (feedback->IsFixedArray()) { 504 // Determine state purely by our structure, don't check if the maps are 505 // cleared. 506 return POLYMORPHIC; 507 } else if (feedback->IsWeakCell()) { 508 // Don't check if the map is cleared. 509 return MONOMORPHIC; 510 } else if (feedback->IsName()) { 511 Object* extra = GetFeedbackExtra(); 512 FixedArray* extra_array = FixedArray::cast(extra); 513 return extra_array->length() > 2 ? POLYMORPHIC : MONOMORPHIC; 514 } 515 516 return UNINITIALIZED; 517 } 518 519 InlineCacheState StoreICNexus::StateFromFeedback() const { 520 Isolate* isolate = GetIsolate(); 521 Object* feedback = GetFeedback(); 522 523 if (feedback == *FeedbackVector::UninitializedSentinel(isolate)) { 524 return UNINITIALIZED; 525 } else if (feedback == *FeedbackVector::MegamorphicSentinel(isolate)) { 526 return MEGAMORPHIC; 527 } else if (feedback == *FeedbackVector::PremonomorphicSentinel(isolate)) { 528 return PREMONOMORPHIC; 529 } else if (feedback->IsFixedArray()) { 530 // Determine state purely by our structure, don't check if the maps are 531 // cleared. 532 return POLYMORPHIC; 533 } else if (feedback->IsWeakCell()) { 534 // Don't check if the map is cleared. 535 return MONOMORPHIC; 536 } 537 538 return UNINITIALIZED; 539 } 540 541 InlineCacheState KeyedStoreICNexus::StateFromFeedback() const { 542 Isolate* isolate = GetIsolate(); 543 Object* feedback = GetFeedback(); 544 545 if (feedback == *FeedbackVector::UninitializedSentinel(isolate)) { 546 return UNINITIALIZED; 547 } else if (feedback == *FeedbackVector::PremonomorphicSentinel(isolate)) { 548 return PREMONOMORPHIC; 549 } else if (feedback == *FeedbackVector::MegamorphicSentinel(isolate)) { 550 return MEGAMORPHIC; 551 } else if (feedback->IsFixedArray()) { 552 // Determine state purely by our structure, don't check if the maps are 553 // cleared. 554 return POLYMORPHIC; 555 } else if (feedback->IsWeakCell()) { 556 // Don't check if the map is cleared. 557 return MONOMORPHIC; 558 } else if (feedback->IsName()) { 559 Object* extra = GetFeedbackExtra(); 560 FixedArray* extra_array = FixedArray::cast(extra); 561 return extra_array->length() > 2 ? POLYMORPHIC : MONOMORPHIC; 562 } 563 564 return UNINITIALIZED; 565 } 566 567 InlineCacheState CallICNexus::StateFromFeedback() const { 568 Isolate* isolate = GetIsolate(); 569 Object* feedback = GetFeedback(); 570 DCHECK(GetFeedbackExtra() == 571 *FeedbackVector::UninitializedSentinel(isolate) || 572 GetFeedbackExtra()->IsSmi()); 573 574 if (feedback == *FeedbackVector::MegamorphicSentinel(isolate)) { 575 return GENERIC; 576 } else if (feedback->IsAllocationSite() || feedback->IsWeakCell()) { 577 return MONOMORPHIC; 578 } 579 580 CHECK(feedback == *FeedbackVector::UninitializedSentinel(isolate)); 581 return UNINITIALIZED; 582 } 583 584 int CallICNexus::ExtractCallCount() { 585 Object* call_count = GetFeedbackExtra(); 586 CHECK(call_count->IsSmi()); 587 int value = Smi::cast(call_count)->value(); 588 return value; 589 } 590 591 float CallICNexus::ComputeCallFrequency() { 592 double const invocation_count = vector()->invocation_count(); 593 double const call_count = ExtractCallCount(); 594 return static_cast<float>(call_count / invocation_count); 595 } 596 597 void CallICNexus::ConfigureUninitialized() { 598 Isolate* isolate = GetIsolate(); 599 SetFeedback(*FeedbackVector::UninitializedSentinel(isolate), 600 SKIP_WRITE_BARRIER); 601 SetFeedbackExtra(Smi::kZero, SKIP_WRITE_BARRIER); 602 } 603 604 void CallICNexus::ConfigureMonomorphicArray() { 605 Object* feedback = GetFeedback(); 606 if (!feedback->IsAllocationSite()) { 607 Handle<AllocationSite> new_site = 608 GetIsolate()->factory()->NewAllocationSite(); 609 SetFeedback(*new_site); 610 } 611 SetFeedbackExtra(Smi::FromInt(1), SKIP_WRITE_BARRIER); 612 } 613 614 void CallICNexus::ConfigureMonomorphic(Handle<JSFunction> function) { 615 Handle<WeakCell> new_cell = GetIsolate()->factory()->NewWeakCell(function); 616 SetFeedback(*new_cell); 617 SetFeedbackExtra(Smi::FromInt(1), SKIP_WRITE_BARRIER); 618 } 619 620 void CallICNexus::ConfigureMegamorphic() { 621 SetFeedback(*FeedbackVector::MegamorphicSentinel(GetIsolate()), 622 SKIP_WRITE_BARRIER); 623 Smi* count = Smi::cast(GetFeedbackExtra()); 624 int new_count = count->value() + 1; 625 SetFeedbackExtra(Smi::FromInt(new_count), SKIP_WRITE_BARRIER); 626 } 627 628 void CallICNexus::ConfigureMegamorphic(int call_count) { 629 SetFeedback(*FeedbackVector::MegamorphicSentinel(GetIsolate()), 630 SKIP_WRITE_BARRIER); 631 SetFeedbackExtra(Smi::FromInt(call_count), SKIP_WRITE_BARRIER); 632 } 633 634 void LoadICNexus::ConfigureMonomorphic(Handle<Map> receiver_map, 635 Handle<Object> handler) { 636 Handle<WeakCell> cell = Map::WeakCellForMap(receiver_map); 637 SetFeedback(*cell); 638 SetFeedbackExtra(*handler); 639 } 640 641 void LoadGlobalICNexus::ConfigureUninitialized() { 642 Isolate* isolate = GetIsolate(); 643 SetFeedback(isolate->heap()->empty_weak_cell(), SKIP_WRITE_BARRIER); 644 SetFeedbackExtra(*FeedbackVector::UninitializedSentinel(isolate), 645 SKIP_WRITE_BARRIER); 646 } 647 648 void LoadGlobalICNexus::ConfigurePropertyCellMode(Handle<PropertyCell> cell) { 649 Isolate* isolate = GetIsolate(); 650 SetFeedback(*isolate->factory()->NewWeakCell(cell)); 651 SetFeedbackExtra(*FeedbackVector::UninitializedSentinel(isolate), 652 SKIP_WRITE_BARRIER); 653 } 654 655 void LoadGlobalICNexus::ConfigureHandlerMode(Handle<Object> handler) { 656 SetFeedback(GetIsolate()->heap()->empty_weak_cell()); 657 SetFeedbackExtra(*handler); 658 } 659 660 void KeyedLoadICNexus::ConfigureMonomorphic(Handle<Name> name, 661 Handle<Map> receiver_map, 662 Handle<Object> handler) { 663 Handle<WeakCell> cell = Map::WeakCellForMap(receiver_map); 664 if (name.is_null()) { 665 SetFeedback(*cell); 666 SetFeedbackExtra(*handler); 667 } else { 668 Handle<FixedArray> array = EnsureExtraArrayOfSize(2); 669 SetFeedback(*name); 670 array->set(0, *cell); 671 array->set(1, *handler); 672 } 673 } 674 675 void StoreICNexus::ConfigureMonomorphic(Handle<Map> receiver_map, 676 Handle<Object> handler) { 677 Handle<WeakCell> cell = Map::WeakCellForMap(receiver_map); 678 SetFeedback(*cell); 679 SetFeedbackExtra(*handler); 680 } 681 682 void KeyedStoreICNexus::ConfigureMonomorphic(Handle<Name> name, 683 Handle<Map> receiver_map, 684 Handle<Object> handler) { 685 Handle<WeakCell> cell = Map::WeakCellForMap(receiver_map); 686 if (name.is_null()) { 687 SetFeedback(*cell); 688 SetFeedbackExtra(*handler); 689 } else { 690 Handle<FixedArray> array = EnsureExtraArrayOfSize(2); 691 SetFeedback(*name); 692 array->set(0, *cell); 693 array->set(1, *handler); 694 } 695 } 696 697 void LoadICNexus::ConfigurePolymorphic(MapHandleList* maps, 698 List<Handle<Object>>* handlers) { 699 Isolate* isolate = GetIsolate(); 700 int receiver_count = maps->length(); 701 Handle<FixedArray> array = EnsureArrayOfSize(receiver_count * 2); 702 InstallHandlers(array, maps, handlers); 703 SetFeedbackExtra(*FeedbackVector::UninitializedSentinel(isolate), 704 SKIP_WRITE_BARRIER); 705 } 706 707 void KeyedLoadICNexus::ConfigurePolymorphic(Handle<Name> name, 708 MapHandleList* maps, 709 List<Handle<Object>>* handlers) { 710 int receiver_count = maps->length(); 711 DCHECK(receiver_count > 1); 712 Handle<FixedArray> array; 713 if (name.is_null()) { 714 array = EnsureArrayOfSize(receiver_count * 2); 715 SetFeedbackExtra(*FeedbackVector::UninitializedSentinel(GetIsolate()), 716 SKIP_WRITE_BARRIER); 717 } else { 718 array = EnsureExtraArrayOfSize(receiver_count * 2); 719 SetFeedback(*name); 720 } 721 722 InstallHandlers(array, maps, handlers); 723 } 724 725 void StoreICNexus::ConfigurePolymorphic(MapHandleList* maps, 726 List<Handle<Object>>* handlers) { 727 Isolate* isolate = GetIsolate(); 728 int receiver_count = maps->length(); 729 Handle<FixedArray> array = EnsureArrayOfSize(receiver_count * 2); 730 InstallHandlers(array, maps, handlers); 731 SetFeedbackExtra(*FeedbackVector::UninitializedSentinel(isolate), 732 SKIP_WRITE_BARRIER); 733 } 734 735 void KeyedStoreICNexus::ConfigurePolymorphic(Handle<Name> name, 736 MapHandleList* maps, 737 List<Handle<Object>>* handlers) { 738 int receiver_count = maps->length(); 739 DCHECK(receiver_count > 1); 740 Handle<FixedArray> array; 741 if (name.is_null()) { 742 array = EnsureArrayOfSize(receiver_count * 2); 743 SetFeedbackExtra(*FeedbackVector::UninitializedSentinel(GetIsolate()), 744 SKIP_WRITE_BARRIER); 745 } else { 746 array = EnsureExtraArrayOfSize(receiver_count * 2); 747 SetFeedback(*name); 748 } 749 750 InstallHandlers(array, maps, handlers); 751 } 752 753 void KeyedStoreICNexus::ConfigurePolymorphic(MapHandleList* maps, 754 MapHandleList* transitioned_maps, 755 List<Handle<Object>>* handlers) { 756 int receiver_count = maps->length(); 757 DCHECK(receiver_count > 1); 758 Handle<FixedArray> array = EnsureArrayOfSize(receiver_count * 3); 759 SetFeedbackExtra(*FeedbackVector::UninitializedSentinel(GetIsolate()), 760 SKIP_WRITE_BARRIER); 761 762 Handle<Oddball> undefined_value = GetIsolate()->factory()->undefined_value(); 763 for (int i = 0; i < receiver_count; ++i) { 764 Handle<Map> map = maps->at(i); 765 Handle<WeakCell> cell = Map::WeakCellForMap(map); 766 array->set(i * 3, *cell); 767 if (!transitioned_maps->at(i).is_null()) { 768 Handle<Map> transitioned_map = transitioned_maps->at(i); 769 cell = Map::WeakCellForMap(transitioned_map); 770 array->set((i * 3) + 1, *cell); 771 } else { 772 array->set((i * 3) + 1, *undefined_value); 773 } 774 array->set((i * 3) + 2, *handlers->at(i)); 775 } 776 } 777 778 namespace { 779 780 int GetStepSize(FixedArray* array, Isolate* isolate) { 781 // The array should be of the form 782 // [map, handler, map, handler, ...] 783 // or 784 // [map, map, handler, map, map, handler, ...] 785 // where "map" is either a WeakCell or |undefined|, 786 // and "handler" is either a Code object or a Smi. 787 DCHECK(array->length() >= 2); 788 Object* second = array->get(1); 789 if (second->IsWeakCell() || second->IsUndefined(isolate)) return 3; 790 DCHECK(IC::IsHandler(second)); 791 return 2; 792 } 793 794 } // namespace 795 796 int FeedbackNexus::ExtractMaps(MapHandleList* maps) const { 797 Isolate* isolate = GetIsolate(); 798 Object* feedback = GetFeedback(); 799 bool is_named_feedback = IsPropertyNameFeedback(feedback); 800 if (feedback->IsFixedArray() || is_named_feedback) { 801 int found = 0; 802 if (is_named_feedback) { 803 feedback = GetFeedbackExtra(); 804 } 805 FixedArray* array = FixedArray::cast(feedback); 806 int increment = GetStepSize(array, isolate); 807 for (int i = 0; i < array->length(); i += increment) { 808 DCHECK(array->get(i)->IsWeakCell()); 809 WeakCell* cell = WeakCell::cast(array->get(i)); 810 if (!cell->cleared()) { 811 Map* map = Map::cast(cell->value()); 812 maps->Add(handle(map, isolate)); 813 found++; 814 } 815 } 816 return found; 817 } else if (feedback->IsWeakCell()) { 818 WeakCell* cell = WeakCell::cast(feedback); 819 if (!cell->cleared()) { 820 Map* map = Map::cast(cell->value()); 821 maps->Add(handle(map, isolate)); 822 return 1; 823 } 824 } 825 826 return 0; 827 } 828 829 MaybeHandle<Object> FeedbackNexus::FindHandlerForMap(Handle<Map> map) const { 830 Object* feedback = GetFeedback(); 831 Isolate* isolate = GetIsolate(); 832 bool is_named_feedback = IsPropertyNameFeedback(feedback); 833 if (feedback->IsFixedArray() || is_named_feedback) { 834 if (is_named_feedback) { 835 feedback = GetFeedbackExtra(); 836 } 837 FixedArray* array = FixedArray::cast(feedback); 838 int increment = GetStepSize(array, isolate); 839 for (int i = 0; i < array->length(); i += increment) { 840 DCHECK(array->get(i)->IsWeakCell()); 841 WeakCell* cell = WeakCell::cast(array->get(i)); 842 if (!cell->cleared()) { 843 Map* array_map = Map::cast(cell->value()); 844 if (array_map == *map) { 845 Object* code = array->get(i + increment - 1); 846 DCHECK(IC::IsHandler(code)); 847 return handle(code, isolate); 848 } 849 } 850 } 851 } else if (feedback->IsWeakCell()) { 852 WeakCell* cell = WeakCell::cast(feedback); 853 if (!cell->cleared()) { 854 Map* cell_map = Map::cast(cell->value()); 855 if (cell_map == *map) { 856 Object* code = GetFeedbackExtra(); 857 DCHECK(IC::IsHandler(code)); 858 return handle(code, isolate); 859 } 860 } 861 } 862 863 return MaybeHandle<Code>(); 864 } 865 866 bool FeedbackNexus::FindHandlers(List<Handle<Object>>* code_list, 867 int length) const { 868 Object* feedback = GetFeedback(); 869 Isolate* isolate = GetIsolate(); 870 int count = 0; 871 bool is_named_feedback = IsPropertyNameFeedback(feedback); 872 if (feedback->IsFixedArray() || is_named_feedback) { 873 if (is_named_feedback) { 874 feedback = GetFeedbackExtra(); 875 } 876 FixedArray* array = FixedArray::cast(feedback); 877 int increment = GetStepSize(array, isolate); 878 for (int i = 0; i < array->length(); i += increment) { 879 DCHECK(array->get(i)->IsWeakCell()); 880 WeakCell* cell = WeakCell::cast(array->get(i)); 881 // Be sure to skip handlers whose maps have been cleared. 882 if (!cell->cleared()) { 883 Object* code = array->get(i + increment - 1); 884 DCHECK(IC::IsHandler(code)); 885 code_list->Add(handle(code, isolate)); 886 count++; 887 } 888 } 889 } else if (feedback->IsWeakCell()) { 890 WeakCell* cell = WeakCell::cast(feedback); 891 if (!cell->cleared()) { 892 Object* code = GetFeedbackExtra(); 893 DCHECK(IC::IsHandler(code)); 894 code_list->Add(handle(code, isolate)); 895 count++; 896 } 897 } 898 return count == length; 899 } 900 901 Name* KeyedLoadICNexus::FindFirstName() const { 902 Object* feedback = GetFeedback(); 903 if (IsPropertyNameFeedback(feedback)) { 904 return Name::cast(feedback); 905 } 906 return NULL; 907 } 908 909 Name* KeyedStoreICNexus::FindFirstName() const { 910 Object* feedback = GetFeedback(); 911 if (IsPropertyNameFeedback(feedback)) { 912 return Name::cast(feedback); 913 } 914 return NULL; 915 } 916 917 KeyedAccessStoreMode KeyedStoreICNexus::GetKeyedAccessStoreMode() const { 918 KeyedAccessStoreMode mode = STANDARD_STORE; 919 MapHandleList maps; 920 List<Handle<Object>> handlers; 921 922 if (GetKeyType() == PROPERTY) return mode; 923 924 ExtractMaps(&maps); 925 FindHandlers(&handlers, maps.length()); 926 for (int i = 0; i < handlers.length(); i++) { 927 // The first handler that isn't the slow handler will have the bits we need. 928 Handle<Object> maybe_code_handler = handlers.at(i); 929 Handle<Code> handler; 930 if (maybe_code_handler->IsTuple2()) { 931 Handle<Tuple2> data_handler = Handle<Tuple2>::cast(maybe_code_handler); 932 handler = handle(Code::cast(data_handler->value2())); 933 } else { 934 handler = Handle<Code>::cast(maybe_code_handler); 935 } 936 CodeStub::Major major_key = CodeStub::MajorKeyFromKey(handler->stub_key()); 937 uint32_t minor_key = CodeStub::MinorKeyFromKey(handler->stub_key()); 938 CHECK(major_key == CodeStub::KeyedStoreSloppyArguments || 939 major_key == CodeStub::StoreFastElement || 940 major_key == CodeStub::StoreSlowElement || 941 major_key == CodeStub::ElementsTransitionAndStore || 942 major_key == CodeStub::NoCache); 943 if (major_key != CodeStub::NoCache) { 944 mode = CommonStoreModeBits::decode(minor_key); 945 break; 946 } 947 } 948 949 return mode; 950 } 951 952 IcCheckType KeyedLoadICNexus::GetKeyType() const { 953 Object* feedback = GetFeedback(); 954 if (feedback == *FeedbackVector::MegamorphicSentinel(GetIsolate())) { 955 return static_cast<IcCheckType>(Smi::cast(GetFeedbackExtra())->value()); 956 } 957 return IsPropertyNameFeedback(feedback) ? PROPERTY : ELEMENT; 958 } 959 960 IcCheckType KeyedStoreICNexus::GetKeyType() const { 961 Object* feedback = GetFeedback(); 962 if (feedback == *FeedbackVector::MegamorphicSentinel(GetIsolate())) { 963 return static_cast<IcCheckType>(Smi::cast(GetFeedbackExtra())->value()); 964 } 965 return IsPropertyNameFeedback(feedback) ? PROPERTY : ELEMENT; 966 } 967 968 InlineCacheState BinaryOpICNexus::StateFromFeedback() const { 969 BinaryOperationHint hint = GetBinaryOperationFeedback(); 970 if (hint == BinaryOperationHint::kNone) { 971 return UNINITIALIZED; 972 } else if (hint == BinaryOperationHint::kAny) { 973 return GENERIC; 974 } 975 976 return MONOMORPHIC; 977 } 978 979 InlineCacheState CompareICNexus::StateFromFeedback() const { 980 CompareOperationHint hint = GetCompareOperationFeedback(); 981 if (hint == CompareOperationHint::kNone) { 982 return UNINITIALIZED; 983 } else if (hint == CompareOperationHint::kAny) { 984 return GENERIC; 985 } 986 987 return MONOMORPHIC; 988 } 989 990 BinaryOperationHint BinaryOpICNexus::GetBinaryOperationFeedback() const { 991 int feedback = Smi::cast(GetFeedback())->value(); 992 return BinaryOperationHintFromFeedback(feedback); 993 } 994 995 CompareOperationHint CompareICNexus::GetCompareOperationFeedback() const { 996 int feedback = Smi::cast(GetFeedback())->value(); 997 return CompareOperationHintFromFeedback(feedback); 998 } 999 1000 InlineCacheState StoreDataPropertyInLiteralICNexus::StateFromFeedback() const { 1001 Isolate* isolate = GetIsolate(); 1002 Object* feedback = GetFeedback(); 1003 1004 if (feedback == *FeedbackVector::UninitializedSentinel(isolate)) { 1005 return UNINITIALIZED; 1006 } else if (feedback->IsWeakCell()) { 1007 // Don't check if the map is cleared. 1008 return MONOMORPHIC; 1009 } 1010 1011 return MEGAMORPHIC; 1012 } 1013 1014 void StoreDataPropertyInLiteralICNexus::ConfigureMonomorphic( 1015 Handle<Name> name, Handle<Map> receiver_map) { 1016 Handle<WeakCell> cell = Map::WeakCellForMap(receiver_map); 1017 1018 SetFeedback(*cell); 1019 SetFeedbackExtra(*name); 1020 } 1021 1022 } // namespace internal 1023 } // namespace v8 1024