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