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