1 // Copyright 2012 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "src/v8.h" 6 7 #include "src/bootstrapper.h" 8 #include "src/code-stubs.h" 9 #include "src/cpu-profiler.h" 10 #include "src/factory.h" 11 #include "src/gdb-jit.h" 12 #include "src/ic/handler-compiler.h" 13 #include "src/ic/ic.h" 14 #include "src/macro-assembler.h" 15 16 namespace v8 { 17 namespace internal { 18 19 20 CodeStubDescriptor::CodeStubDescriptor(CodeStub* stub) 21 : call_descriptor_(stub->GetCallInterfaceDescriptor()), 22 stack_parameter_count_(no_reg), 23 hint_stack_parameter_count_(-1), 24 function_mode_(NOT_JS_FUNCTION_STUB_MODE), 25 deoptimization_handler_(NULL), 26 handler_arguments_mode_(DONT_PASS_ARGUMENTS), 27 miss_handler_(), 28 has_miss_handler_(false) { 29 stub->InitializeDescriptor(this); 30 } 31 32 33 CodeStubDescriptor::CodeStubDescriptor(Isolate* isolate, uint32_t stub_key) 34 : stack_parameter_count_(no_reg), 35 hint_stack_parameter_count_(-1), 36 function_mode_(NOT_JS_FUNCTION_STUB_MODE), 37 deoptimization_handler_(NULL), 38 handler_arguments_mode_(DONT_PASS_ARGUMENTS), 39 miss_handler_(), 40 has_miss_handler_(false) { 41 CodeStub::InitializeDescriptor(isolate, stub_key, this); 42 } 43 44 45 void CodeStubDescriptor::Initialize(Address deoptimization_handler, 46 int hint_stack_parameter_count, 47 StubFunctionMode function_mode) { 48 deoptimization_handler_ = deoptimization_handler; 49 hint_stack_parameter_count_ = hint_stack_parameter_count; 50 function_mode_ = function_mode; 51 } 52 53 54 void CodeStubDescriptor::Initialize(Register stack_parameter_count, 55 Address deoptimization_handler, 56 int hint_stack_parameter_count, 57 StubFunctionMode function_mode, 58 HandlerArgumentsMode handler_mode) { 59 Initialize(deoptimization_handler, hint_stack_parameter_count, function_mode); 60 stack_parameter_count_ = stack_parameter_count; 61 handler_arguments_mode_ = handler_mode; 62 } 63 64 65 bool CodeStub::FindCodeInCache(Code** code_out) { 66 UnseededNumberDictionary* stubs = isolate()->heap()->code_stubs(); 67 int index = stubs->FindEntry(GetKey()); 68 if (index != UnseededNumberDictionary::kNotFound) { 69 *code_out = Code::cast(stubs->ValueAt(index)); 70 return true; 71 } 72 return false; 73 } 74 75 76 void CodeStub::RecordCodeGeneration(Handle<Code> code) { 77 IC::RegisterWeakMapDependency(code); 78 OStringStream os; 79 os << *this; 80 PROFILE(isolate(), CodeCreateEvent(Logger::STUB_TAG, *code, os.c_str())); 81 Counters* counters = isolate()->counters(); 82 counters->total_stubs_code_size()->Increment(code->instruction_size()); 83 } 84 85 86 Code::Kind CodeStub::GetCodeKind() const { 87 return Code::STUB; 88 } 89 90 91 Handle<Code> CodeStub::GetCodeCopy(const Code::FindAndReplacePattern& pattern) { 92 Handle<Code> ic = GetCode(); 93 ic = isolate()->factory()->CopyCode(ic); 94 ic->FindAndReplace(pattern); 95 RecordCodeGeneration(ic); 96 return ic; 97 } 98 99 100 Handle<Code> PlatformCodeStub::GenerateCode() { 101 Factory* factory = isolate()->factory(); 102 103 // Generate the new code. 104 MacroAssembler masm(isolate(), NULL, 256); 105 106 // TODO(yangguo) remove this once the code serializer handles code stubs. 107 if (FLAG_serialize_toplevel) masm.enable_serializer(); 108 109 { 110 // Update the static counter each time a new code stub is generated. 111 isolate()->counters()->code_stubs()->Increment(); 112 113 // Generate the code for the stub. 114 masm.set_generating_stub(true); 115 NoCurrentFrameScope scope(&masm); 116 Generate(&masm); 117 } 118 119 // Create the code object. 120 CodeDesc desc; 121 masm.GetCode(&desc); 122 123 // Copy the generated code into a heap object. 124 Code::Flags flags = Code::ComputeFlags( 125 GetCodeKind(), 126 GetICState(), 127 GetExtraICState(), 128 GetStubType()); 129 Handle<Code> new_object = factory->NewCode( 130 desc, flags, masm.CodeObject(), NeedsImmovableCode()); 131 return new_object; 132 } 133 134 135 Handle<Code> CodeStub::GetCode() { 136 Heap* heap = isolate()->heap(); 137 Code* code; 138 if (UseSpecialCache() ? FindCodeInSpecialCache(&code) 139 : FindCodeInCache(&code)) { 140 DCHECK(GetCodeKind() == code->kind()); 141 return Handle<Code>(code); 142 } 143 144 { 145 HandleScope scope(isolate()); 146 147 Handle<Code> new_object = GenerateCode(); 148 new_object->set_stub_key(GetKey()); 149 FinishCode(new_object); 150 RecordCodeGeneration(new_object); 151 152 #ifdef ENABLE_DISASSEMBLER 153 if (FLAG_print_code_stubs) { 154 CodeTracer::Scope trace_scope(isolate()->GetCodeTracer()); 155 OFStream os(trace_scope.file()); 156 OStringStream name; 157 name << *this; 158 new_object->Disassemble(name.c_str(), os); 159 os << "\n"; 160 } 161 #endif 162 163 if (UseSpecialCache()) { 164 AddToSpecialCache(new_object); 165 } else { 166 // Update the dictionary and the root in Heap. 167 Handle<UnseededNumberDictionary> dict = 168 UnseededNumberDictionary::AtNumberPut( 169 Handle<UnseededNumberDictionary>(heap->code_stubs()), 170 GetKey(), 171 new_object); 172 heap->public_set_code_stubs(*dict); 173 } 174 code = *new_object; 175 } 176 177 Activate(code); 178 DCHECK(!NeedsImmovableCode() || 179 heap->lo_space()->Contains(code) || 180 heap->code_space()->FirstPage()->Contains(code->address())); 181 return Handle<Code>(code, isolate()); 182 } 183 184 185 const char* CodeStub::MajorName(CodeStub::Major major_key, 186 bool allow_unknown_keys) { 187 switch (major_key) { 188 #define DEF_CASE(name) case name: return #name "Stub"; 189 CODE_STUB_LIST(DEF_CASE) 190 #undef DEF_CASE 191 case NoCache: 192 return "<NoCache>Stub"; 193 case NUMBER_OF_IDS: 194 UNREACHABLE(); 195 return NULL; 196 } 197 return NULL; 198 } 199 200 201 void CodeStub::PrintBaseName(OStream& os) const { // NOLINT 202 os << MajorName(MajorKey(), false); 203 } 204 205 206 void CodeStub::PrintName(OStream& os) const { // NOLINT 207 PrintBaseName(os); 208 PrintState(os); 209 } 210 211 212 void CodeStub::Dispatch(Isolate* isolate, uint32_t key, void** value_out, 213 DispatchedCall call) { 214 switch (MajorKeyFromKey(key)) { 215 #define DEF_CASE(NAME) \ 216 case NAME: { \ 217 NAME##Stub stub(key, isolate); \ 218 CodeStub* pstub = &stub; \ 219 call(pstub, value_out); \ 220 break; \ 221 } 222 CODE_STUB_LIST(DEF_CASE) 223 #undef DEF_CASE 224 case NUMBER_OF_IDS: 225 UNREACHABLE(); 226 case NoCache: 227 *value_out = NULL; 228 break; 229 } 230 } 231 232 233 static void InitializeDescriptorDispatchedCall(CodeStub* stub, 234 void** value_out) { 235 CodeStubDescriptor* descriptor_out = 236 reinterpret_cast<CodeStubDescriptor*>(value_out); 237 stub->InitializeDescriptor(descriptor_out); 238 descriptor_out->set_call_descriptor(stub->GetCallInterfaceDescriptor()); 239 } 240 241 242 void CodeStub::InitializeDescriptor(Isolate* isolate, uint32_t key, 243 CodeStubDescriptor* desc) { 244 void** value_out = reinterpret_cast<void**>(desc); 245 Dispatch(isolate, key, value_out, &InitializeDescriptorDispatchedCall); 246 } 247 248 249 void CodeStub::GetCodeDispatchCall(CodeStub* stub, void** value_out) { 250 Handle<Code>* code_out = reinterpret_cast<Handle<Code>*>(value_out); 251 // Code stubs with special cache cannot be recreated from stub key. 252 *code_out = stub->UseSpecialCache() ? Handle<Code>() : stub->GetCode(); 253 } 254 255 256 MaybeHandle<Code> CodeStub::GetCode(Isolate* isolate, uint32_t key) { 257 HandleScope scope(isolate); 258 Handle<Code> code; 259 void** value_out = reinterpret_cast<void**>(&code); 260 Dispatch(isolate, key, value_out, &GetCodeDispatchCall); 261 return scope.CloseAndEscape(code); 262 } 263 264 265 // static 266 void BinaryOpICStub::GenerateAheadOfTime(Isolate* isolate) { 267 // Generate the uninitialized versions of the stub. 268 for (int op = Token::BIT_OR; op <= Token::MOD; ++op) { 269 for (int mode = NO_OVERWRITE; mode <= OVERWRITE_RIGHT; ++mode) { 270 BinaryOpICStub stub(isolate, 271 static_cast<Token::Value>(op), 272 static_cast<OverwriteMode>(mode)); 273 stub.GetCode(); 274 } 275 } 276 277 // Generate special versions of the stub. 278 BinaryOpICState::GenerateAheadOfTime(isolate, &GenerateAheadOfTime); 279 } 280 281 282 void BinaryOpICStub::PrintState(OStream& os) const { // NOLINT 283 os << state(); 284 } 285 286 287 // static 288 void BinaryOpICStub::GenerateAheadOfTime(Isolate* isolate, 289 const BinaryOpICState& state) { 290 BinaryOpICStub stub(isolate, state); 291 stub.GetCode(); 292 } 293 294 295 // static 296 void BinaryOpICWithAllocationSiteStub::GenerateAheadOfTime(Isolate* isolate) { 297 // Generate special versions of the stub. 298 BinaryOpICState::GenerateAheadOfTime(isolate, &GenerateAheadOfTime); 299 } 300 301 302 void BinaryOpICWithAllocationSiteStub::PrintState( 303 OStream& os) const { // NOLINT 304 os << state(); 305 } 306 307 308 // static 309 void BinaryOpICWithAllocationSiteStub::GenerateAheadOfTime( 310 Isolate* isolate, const BinaryOpICState& state) { 311 if (state.CouldCreateAllocationMementos()) { 312 BinaryOpICWithAllocationSiteStub stub(isolate, state); 313 stub.GetCode(); 314 } 315 } 316 317 318 void StringAddStub::PrintBaseName(OStream& os) const { // NOLINT 319 os << "StringAddStub"; 320 if ((flags() & STRING_ADD_CHECK_BOTH) == STRING_ADD_CHECK_BOTH) { 321 os << "_CheckBoth"; 322 } else if ((flags() & STRING_ADD_CHECK_LEFT) == STRING_ADD_CHECK_LEFT) { 323 os << "_CheckLeft"; 324 } else if ((flags() & STRING_ADD_CHECK_RIGHT) == STRING_ADD_CHECK_RIGHT) { 325 os << "_CheckRight"; 326 } 327 if (pretenure_flag() == TENURED) { 328 os << "_Tenured"; 329 } 330 } 331 332 333 InlineCacheState CompareICStub::GetICState() const { 334 CompareICState::State state = Max(left(), right()); 335 switch (state) { 336 case CompareICState::UNINITIALIZED: 337 return ::v8::internal::UNINITIALIZED; 338 case CompareICState::SMI: 339 case CompareICState::NUMBER: 340 case CompareICState::INTERNALIZED_STRING: 341 case CompareICState::STRING: 342 case CompareICState::UNIQUE_NAME: 343 case CompareICState::OBJECT: 344 case CompareICState::KNOWN_OBJECT: 345 return MONOMORPHIC; 346 case CompareICState::GENERIC: 347 return ::v8::internal::GENERIC; 348 } 349 UNREACHABLE(); 350 return ::v8::internal::UNINITIALIZED; 351 } 352 353 354 Condition CompareICStub::GetCondition() const { 355 return CompareIC::ComputeCondition(op()); 356 } 357 358 359 void CompareICStub::AddToSpecialCache(Handle<Code> new_object) { 360 DCHECK(*known_map_ != NULL); 361 Isolate* isolate = new_object->GetIsolate(); 362 Factory* factory = isolate->factory(); 363 return Map::UpdateCodeCache(known_map_, 364 strict() ? 365 factory->strict_compare_ic_string() : 366 factory->compare_ic_string(), 367 new_object); 368 } 369 370 371 bool CompareICStub::FindCodeInSpecialCache(Code** code_out) { 372 Factory* factory = isolate()->factory(); 373 Code::Flags flags = Code::ComputeFlags( 374 GetCodeKind(), 375 UNINITIALIZED); 376 DCHECK(op() == Token::EQ || op() == Token::EQ_STRICT); 377 Handle<Object> probe( 378 known_map_->FindInCodeCache( 379 strict() ? 380 *factory->strict_compare_ic_string() : 381 *factory->compare_ic_string(), 382 flags), 383 isolate()); 384 if (probe->IsCode()) { 385 *code_out = Code::cast(*probe); 386 #ifdef DEBUG 387 CompareICStub decode((*code_out)->stub_key(), isolate()); 388 DCHECK(op() == decode.op()); 389 DCHECK(left() == decode.left()); 390 DCHECK(right() == decode.right()); 391 DCHECK(state() == decode.state()); 392 #endif 393 return true; 394 } 395 return false; 396 } 397 398 399 void CompareICStub::Generate(MacroAssembler* masm) { 400 switch (state()) { 401 case CompareICState::UNINITIALIZED: 402 GenerateMiss(masm); 403 break; 404 case CompareICState::SMI: 405 GenerateSmis(masm); 406 break; 407 case CompareICState::NUMBER: 408 GenerateNumbers(masm); 409 break; 410 case CompareICState::STRING: 411 GenerateStrings(masm); 412 break; 413 case CompareICState::INTERNALIZED_STRING: 414 GenerateInternalizedStrings(masm); 415 break; 416 case CompareICState::UNIQUE_NAME: 417 GenerateUniqueNames(masm); 418 break; 419 case CompareICState::OBJECT: 420 GenerateObjects(masm); 421 break; 422 case CompareICState::KNOWN_OBJECT: 423 DCHECK(*known_map_ != NULL); 424 GenerateKnownObjects(masm); 425 break; 426 case CompareICState::GENERIC: 427 GenerateGeneric(masm); 428 break; 429 } 430 } 431 432 433 void CompareNilICStub::UpdateStatus(Handle<Object> object) { 434 State state = this->state(); 435 DCHECK(!state.Contains(GENERIC)); 436 State old_state = state; 437 if (object->IsNull()) { 438 state.Add(NULL_TYPE); 439 } else if (object->IsUndefined()) { 440 state.Add(UNDEFINED); 441 } else if (object->IsUndetectableObject() || 442 object->IsOddball() || 443 !object->IsHeapObject()) { 444 state.RemoveAll(); 445 state.Add(GENERIC); 446 } else if (IsMonomorphic()) { 447 state.RemoveAll(); 448 state.Add(GENERIC); 449 } else { 450 state.Add(MONOMORPHIC_MAP); 451 } 452 TraceTransition(old_state, state); 453 set_sub_minor_key(TypesBits::update(sub_minor_key(), state.ToIntegral())); 454 } 455 456 457 template<class StateType> 458 void HydrogenCodeStub::TraceTransition(StateType from, StateType to) { 459 // Note: Although a no-op transition is semantically OK, it is hinting at a 460 // bug somewhere in our state transition machinery. 461 DCHECK(from != to); 462 if (!FLAG_trace_ic) return; 463 OFStream os(stdout); 464 os << "["; 465 PrintBaseName(os); 466 os << ": " << from << "=>" << to << "]" << endl; 467 } 468 469 470 void CompareNilICStub::PrintBaseName(OStream& os) const { // NOLINT 471 CodeStub::PrintBaseName(os); 472 os << ((nil_value() == kNullValue) ? "(NullValue)" : "(UndefinedValue)"); 473 } 474 475 476 void CompareNilICStub::PrintState(OStream& os) const { // NOLINT 477 os << state(); 478 } 479 480 481 // TODO(svenpanne) Make this a real infix_ostream_iterator. 482 class SimpleListPrinter { 483 public: 484 explicit SimpleListPrinter(OStream& os) : os_(os), first_(true) {} 485 486 void Add(const char* s) { 487 if (first_) { 488 first_ = false; 489 } else { 490 os_ << ","; 491 } 492 os_ << s; 493 } 494 495 private: 496 OStream& os_; 497 bool first_; 498 }; 499 500 501 OStream& operator<<(OStream& os, const CompareNilICStub::State& s) { 502 os << "("; 503 SimpleListPrinter p(os); 504 if (s.IsEmpty()) p.Add("None"); 505 if (s.Contains(CompareNilICStub::UNDEFINED)) p.Add("Undefined"); 506 if (s.Contains(CompareNilICStub::NULL_TYPE)) p.Add("Null"); 507 if (s.Contains(CompareNilICStub::MONOMORPHIC_MAP)) p.Add("MonomorphicMap"); 508 if (s.Contains(CompareNilICStub::GENERIC)) p.Add("Generic"); 509 return os << ")"; 510 } 511 512 513 Type* CompareNilICStub::GetType(Zone* zone, Handle<Map> map) { 514 State state = this->state(); 515 if (state.Contains(CompareNilICStub::GENERIC)) return Type::Any(zone); 516 517 Type* result = Type::None(zone); 518 if (state.Contains(CompareNilICStub::UNDEFINED)) { 519 result = Type::Union(result, Type::Undefined(zone), zone); 520 } 521 if (state.Contains(CompareNilICStub::NULL_TYPE)) { 522 result = Type::Union(result, Type::Null(zone), zone); 523 } 524 if (state.Contains(CompareNilICStub::MONOMORPHIC_MAP)) { 525 Type* type = 526 map.is_null() ? Type::Detectable(zone) : Type::Class(map, zone); 527 result = Type::Union(result, type, zone); 528 } 529 530 return result; 531 } 532 533 534 Type* CompareNilICStub::GetInputType(Zone* zone, Handle<Map> map) { 535 Type* output_type = GetType(zone, map); 536 Type* nil_type = 537 nil_value() == kNullValue ? Type::Null(zone) : Type::Undefined(zone); 538 return Type::Union(output_type, nil_type, zone); 539 } 540 541 542 void CallIC_ArrayStub::PrintState(OStream& os) const { // NOLINT 543 os << state() << " (Array)"; 544 } 545 546 547 void CallICStub::PrintState(OStream& os) const { // NOLINT 548 os << state(); 549 } 550 551 552 void InstanceofStub::PrintName(OStream& os) const { // NOLINT 553 os << "InstanceofStub"; 554 if (HasArgsInRegisters()) os << "_REGS"; 555 if (HasCallSiteInlineCheck()) os << "_INLINE"; 556 if (ReturnTrueFalseObject()) os << "_TRUEFALSE"; 557 } 558 559 560 void JSEntryStub::FinishCode(Handle<Code> code) { 561 Handle<FixedArray> handler_table = 562 code->GetIsolate()->factory()->NewFixedArray(1, TENURED); 563 handler_table->set(0, Smi::FromInt(handler_offset_)); 564 code->set_handler_table(*handler_table); 565 } 566 567 568 void LoadFastElementStub::InitializeDescriptor(CodeStubDescriptor* descriptor) { 569 descriptor->Initialize(FUNCTION_ADDR(KeyedLoadIC_MissFromStubFailure)); 570 } 571 572 573 void LoadDictionaryElementStub::InitializeDescriptor( 574 CodeStubDescriptor* descriptor) { 575 descriptor->Initialize(FUNCTION_ADDR(KeyedLoadIC_MissFromStubFailure)); 576 } 577 578 579 void KeyedLoadGenericStub::InitializeDescriptor( 580 CodeStubDescriptor* descriptor) { 581 descriptor->Initialize( 582 Runtime::FunctionForId(Runtime::kKeyedGetProperty)->entry); 583 } 584 585 586 void HandlerStub::InitializeDescriptor(CodeStubDescriptor* descriptor) { 587 if (kind() == Code::STORE_IC) { 588 descriptor->Initialize(FUNCTION_ADDR(StoreIC_MissFromStubFailure)); 589 } else if (kind() == Code::KEYED_LOAD_IC) { 590 descriptor->Initialize(FUNCTION_ADDR(KeyedLoadIC_MissFromStubFailure)); 591 } 592 } 593 594 595 CallInterfaceDescriptor HandlerStub::GetCallInterfaceDescriptor() { 596 if (kind() == Code::LOAD_IC || kind() == Code::KEYED_LOAD_IC) { 597 return LoadDescriptor(isolate()); 598 } else { 599 DCHECK_EQ(Code::STORE_IC, kind()); 600 return StoreDescriptor(isolate()); 601 } 602 } 603 604 605 void StoreFastElementStub::InitializeDescriptor( 606 CodeStubDescriptor* descriptor) { 607 descriptor->Initialize(FUNCTION_ADDR(KeyedStoreIC_MissFromStubFailure)); 608 } 609 610 611 void ElementsTransitionAndStoreStub::InitializeDescriptor( 612 CodeStubDescriptor* descriptor) { 613 descriptor->Initialize(FUNCTION_ADDR(ElementsTransitionAndStoreIC_Miss)); 614 } 615 616 617 static void InitializeVectorLoadStub(Isolate* isolate, 618 CodeStubDescriptor* descriptor, 619 Address deoptimization_handler) { 620 DCHECK(FLAG_vector_ics); 621 descriptor->Initialize(deoptimization_handler); 622 } 623 624 625 void VectorLoadStub::InitializeDescriptor(CodeStubDescriptor* descriptor) { 626 InitializeVectorLoadStub(isolate(), descriptor, 627 FUNCTION_ADDR(VectorLoadIC_MissFromStubFailure)); 628 } 629 630 631 void VectorKeyedLoadStub::InitializeDescriptor(CodeStubDescriptor* descriptor) { 632 InitializeVectorLoadStub( 633 isolate(), descriptor, 634 FUNCTION_ADDR(VectorKeyedLoadIC_MissFromStubFailure)); 635 } 636 637 638 void MegamorphicLoadStub::InitializeDescriptor(CodeStubDescriptor* d) {} 639 640 641 void FastNewClosureStub::InitializeDescriptor(CodeStubDescriptor* descriptor) { 642 descriptor->Initialize( 643 Runtime::FunctionForId(Runtime::kNewClosureFromStubFailure)->entry); 644 } 645 646 647 void FastNewContextStub::InitializeDescriptor(CodeStubDescriptor* d) {} 648 649 650 void ToNumberStub::InitializeDescriptor(CodeStubDescriptor* d) {} 651 652 653 void NumberToStringStub::InitializeDescriptor(CodeStubDescriptor* descriptor) { 654 NumberToStringDescriptor call_descriptor(isolate()); 655 descriptor->Initialize( 656 Runtime::FunctionForId(Runtime::kNumberToStringRT)->entry); 657 } 658 659 660 void FastCloneShallowArrayStub::InitializeDescriptor( 661 CodeStubDescriptor* descriptor) { 662 FastCloneShallowArrayDescriptor call_descriptor(isolate()); 663 descriptor->Initialize( 664 Runtime::FunctionForId(Runtime::kCreateArrayLiteralStubBailout)->entry); 665 } 666 667 668 void FastCloneShallowObjectStub::InitializeDescriptor( 669 CodeStubDescriptor* descriptor) { 670 FastCloneShallowObjectDescriptor call_descriptor(isolate()); 671 descriptor->Initialize( 672 Runtime::FunctionForId(Runtime::kCreateObjectLiteral)->entry); 673 } 674 675 676 void CreateAllocationSiteStub::InitializeDescriptor(CodeStubDescriptor* d) {} 677 678 679 void RegExpConstructResultStub::InitializeDescriptor( 680 CodeStubDescriptor* descriptor) { 681 descriptor->Initialize( 682 Runtime::FunctionForId(Runtime::kRegExpConstructResult)->entry); 683 } 684 685 686 void TransitionElementsKindStub::InitializeDescriptor( 687 CodeStubDescriptor* descriptor) { 688 descriptor->Initialize( 689 Runtime::FunctionForId(Runtime::kTransitionElementsKind)->entry); 690 } 691 692 693 void CompareNilICStub::InitializeDescriptor(CodeStubDescriptor* descriptor) { 694 descriptor->Initialize(FUNCTION_ADDR(CompareNilIC_Miss)); 695 descriptor->SetMissHandler( 696 ExternalReference(IC_Utility(IC::kCompareNilIC_Miss), isolate())); 697 } 698 699 700 void ToBooleanStub::InitializeDescriptor(CodeStubDescriptor* descriptor) { 701 descriptor->Initialize(FUNCTION_ADDR(ToBooleanIC_Miss)); 702 descriptor->SetMissHandler( 703 ExternalReference(IC_Utility(IC::kToBooleanIC_Miss), isolate())); 704 } 705 706 707 void BinaryOpICStub::InitializeDescriptor(CodeStubDescriptor* descriptor) { 708 descriptor->Initialize(FUNCTION_ADDR(BinaryOpIC_Miss)); 709 descriptor->SetMissHandler( 710 ExternalReference(IC_Utility(IC::kBinaryOpIC_Miss), isolate())); 711 } 712 713 714 void BinaryOpWithAllocationSiteStub::InitializeDescriptor( 715 CodeStubDescriptor* descriptor) { 716 descriptor->Initialize(FUNCTION_ADDR(BinaryOpIC_MissWithAllocationSite)); 717 } 718 719 720 void StringAddStub::InitializeDescriptor(CodeStubDescriptor* descriptor) { 721 descriptor->Initialize(Runtime::FunctionForId(Runtime::kStringAdd)->entry); 722 } 723 724 725 void CreateAllocationSiteStub::GenerateAheadOfTime(Isolate* isolate) { 726 CreateAllocationSiteStub stub(isolate); 727 stub.GetCode(); 728 } 729 730 731 void StoreElementStub::Generate(MacroAssembler* masm) { 732 switch (elements_kind()) { 733 case FAST_ELEMENTS: 734 case FAST_HOLEY_ELEMENTS: 735 case FAST_SMI_ELEMENTS: 736 case FAST_HOLEY_SMI_ELEMENTS: 737 case FAST_DOUBLE_ELEMENTS: 738 case FAST_HOLEY_DOUBLE_ELEMENTS: 739 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \ 740 case EXTERNAL_##TYPE##_ELEMENTS: \ 741 case TYPE##_ELEMENTS: 742 743 TYPED_ARRAYS(TYPED_ARRAY_CASE) 744 #undef TYPED_ARRAY_CASE 745 UNREACHABLE(); 746 break; 747 case DICTIONARY_ELEMENTS: 748 ElementHandlerCompiler::GenerateStoreSlow(masm); 749 break; 750 case SLOPPY_ARGUMENTS_ELEMENTS: 751 UNREACHABLE(); 752 break; 753 } 754 } 755 756 757 void ArgumentsAccessStub::Generate(MacroAssembler* masm) { 758 switch (type()) { 759 case READ_ELEMENT: 760 GenerateReadElement(masm); 761 break; 762 case NEW_SLOPPY_FAST: 763 GenerateNewSloppyFast(masm); 764 break; 765 case NEW_SLOPPY_SLOW: 766 GenerateNewSloppySlow(masm); 767 break; 768 case NEW_STRICT: 769 GenerateNewStrict(masm); 770 break; 771 } 772 } 773 774 775 void ArgumentsAccessStub::PrintName(OStream& os) const { // NOLINT 776 os << "ArgumentsAccessStub_"; 777 switch (type()) { 778 case READ_ELEMENT: 779 os << "ReadElement"; 780 break; 781 case NEW_SLOPPY_FAST: 782 os << "NewSloppyFast"; 783 break; 784 case NEW_SLOPPY_SLOW: 785 os << "NewSloppySlow"; 786 break; 787 case NEW_STRICT: 788 os << "NewStrict"; 789 break; 790 } 791 return; 792 } 793 794 795 void CallFunctionStub::PrintName(OStream& os) const { // NOLINT 796 os << "CallFunctionStub_Args" << argc(); 797 } 798 799 800 void CallConstructStub::PrintName(OStream& os) const { // NOLINT 801 os << "CallConstructStub"; 802 if (RecordCallTarget()) os << "_Recording"; 803 } 804 805 806 void ArrayConstructorStub::PrintName(OStream& os) const { // NOLINT 807 os << "ArrayConstructorStub"; 808 switch (argument_count()) { 809 case ANY: 810 os << "_Any"; 811 break; 812 case NONE: 813 os << "_None"; 814 break; 815 case ONE: 816 os << "_One"; 817 break; 818 case MORE_THAN_ONE: 819 os << "_More_Than_One"; 820 break; 821 } 822 return; 823 } 824 825 826 OStream& ArrayConstructorStubBase::BasePrintName(OStream& os, // NOLINT 827 const char* name) const { 828 os << name << "_" << ElementsKindToString(elements_kind()); 829 if (override_mode() == DISABLE_ALLOCATION_SITES) { 830 os << "_DISABLE_ALLOCATION_SITES"; 831 } 832 return os; 833 } 834 835 836 bool ToBooleanStub::UpdateStatus(Handle<Object> object) { 837 Types new_types = types(); 838 Types old_types = new_types; 839 bool to_boolean_value = new_types.UpdateStatus(object); 840 TraceTransition(old_types, new_types); 841 set_sub_minor_key(TypesBits::update(sub_minor_key(), new_types.ToByte())); 842 return to_boolean_value; 843 } 844 845 846 void ToBooleanStub::PrintState(OStream& os) const { // NOLINT 847 os << types(); 848 } 849 850 851 OStream& operator<<(OStream& os, const ToBooleanStub::Types& s) { 852 os << "("; 853 SimpleListPrinter p(os); 854 if (s.IsEmpty()) p.Add("None"); 855 if (s.Contains(ToBooleanStub::UNDEFINED)) p.Add("Undefined"); 856 if (s.Contains(ToBooleanStub::BOOLEAN)) p.Add("Bool"); 857 if (s.Contains(ToBooleanStub::NULL_TYPE)) p.Add("Null"); 858 if (s.Contains(ToBooleanStub::SMI)) p.Add("Smi"); 859 if (s.Contains(ToBooleanStub::SPEC_OBJECT)) p.Add("SpecObject"); 860 if (s.Contains(ToBooleanStub::STRING)) p.Add("String"); 861 if (s.Contains(ToBooleanStub::SYMBOL)) p.Add("Symbol"); 862 if (s.Contains(ToBooleanStub::HEAP_NUMBER)) p.Add("HeapNumber"); 863 return os << ")"; 864 } 865 866 867 bool ToBooleanStub::Types::UpdateStatus(Handle<Object> object) { 868 if (object->IsUndefined()) { 869 Add(UNDEFINED); 870 return false; 871 } else if (object->IsBoolean()) { 872 Add(BOOLEAN); 873 return object->IsTrue(); 874 } else if (object->IsNull()) { 875 Add(NULL_TYPE); 876 return false; 877 } else if (object->IsSmi()) { 878 Add(SMI); 879 return Smi::cast(*object)->value() != 0; 880 } else if (object->IsSpecObject()) { 881 Add(SPEC_OBJECT); 882 return !object->IsUndetectableObject(); 883 } else if (object->IsString()) { 884 Add(STRING); 885 return !object->IsUndetectableObject() && 886 String::cast(*object)->length() != 0; 887 } else if (object->IsSymbol()) { 888 Add(SYMBOL); 889 return true; 890 } else if (object->IsHeapNumber()) { 891 DCHECK(!object->IsUndetectableObject()); 892 Add(HEAP_NUMBER); 893 double value = HeapNumber::cast(*object)->value(); 894 return value != 0 && !std::isnan(value); 895 } else { 896 // We should never see an internal object at runtime here! 897 UNREACHABLE(); 898 return true; 899 } 900 } 901 902 903 bool ToBooleanStub::Types::NeedsMap() const { 904 return Contains(ToBooleanStub::SPEC_OBJECT) 905 || Contains(ToBooleanStub::STRING) 906 || Contains(ToBooleanStub::SYMBOL) 907 || Contains(ToBooleanStub::HEAP_NUMBER); 908 } 909 910 911 bool ToBooleanStub::Types::CanBeUndetectable() const { 912 return Contains(ToBooleanStub::SPEC_OBJECT) 913 || Contains(ToBooleanStub::STRING); 914 } 915 916 917 void StubFailureTrampolineStub::GenerateAheadOfTime(Isolate* isolate) { 918 StubFailureTrampolineStub stub1(isolate, NOT_JS_FUNCTION_STUB_MODE); 919 StubFailureTrampolineStub stub2(isolate, JS_FUNCTION_STUB_MODE); 920 stub1.GetCode(); 921 stub2.GetCode(); 922 } 923 924 925 void ProfileEntryHookStub::EntryHookTrampoline(intptr_t function, 926 intptr_t stack_pointer, 927 Isolate* isolate) { 928 FunctionEntryHook entry_hook = isolate->function_entry_hook(); 929 DCHECK(entry_hook != NULL); 930 entry_hook(function, stack_pointer); 931 } 932 933 934 ArrayConstructorStub::ArrayConstructorStub(Isolate* isolate) 935 : PlatformCodeStub(isolate) { 936 minor_key_ = ArgumentCountBits::encode(ANY); 937 ArrayConstructorStubBase::GenerateStubsAheadOfTime(isolate); 938 } 939 940 941 ArrayConstructorStub::ArrayConstructorStub(Isolate* isolate, 942 int argument_count) 943 : PlatformCodeStub(isolate) { 944 if (argument_count == 0) { 945 minor_key_ = ArgumentCountBits::encode(NONE); 946 } else if (argument_count == 1) { 947 minor_key_ = ArgumentCountBits::encode(ONE); 948 } else if (argument_count >= 2) { 949 minor_key_ = ArgumentCountBits::encode(MORE_THAN_ONE); 950 } else { 951 UNREACHABLE(); 952 } 953 ArrayConstructorStubBase::GenerateStubsAheadOfTime(isolate); 954 } 955 956 957 InternalArrayConstructorStub::InternalArrayConstructorStub( 958 Isolate* isolate) : PlatformCodeStub(isolate) { 959 InternalArrayConstructorStubBase::GenerateStubsAheadOfTime(isolate); 960 } 961 962 963 } } // namespace v8::internal 964