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