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/code-factory.h" 11 #include "src/code-stub-assembler.h" 12 #include "src/factory.h" 13 #include "src/gdb-jit.h" 14 #include "src/ic/handler-compiler.h" 15 #include "src/ic/ic.h" 16 #include "src/macro-assembler.h" 17 #include "src/parsing/parser.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(CodeEventListener::STUB_TAG, 86 AbstractCode::cast(*code), os.str().c_str())); 87 Counters* counters = isolate()->counters(); 88 counters->total_stubs_code_size()->Increment(code->instruction_size()); 89 #ifdef DEBUG 90 code->VerifyEmbeddedObjects(); 91 #endif 92 } 93 94 95 Code::Kind CodeStub::GetCodeKind() const { 96 return Code::STUB; 97 } 98 99 100 Code::Flags CodeStub::GetCodeFlags() const { 101 return Code::ComputeFlags(GetCodeKind(), GetExtraICState()); 102 } 103 104 105 Handle<Code> CodeStub::GetCodeCopy(const Code::FindAndReplacePattern& pattern) { 106 Handle<Code> ic = GetCode(); 107 ic = isolate()->factory()->CopyCode(ic); 108 ic->FindAndReplace(pattern); 109 RecordCodeGeneration(ic); 110 return ic; 111 } 112 113 114 Handle<Code> PlatformCodeStub::GenerateCode() { 115 Factory* factory = isolate()->factory(); 116 117 // Generate the new code. 118 MacroAssembler masm(isolate(), NULL, 256, CodeObjectRequired::kYes); 119 120 { 121 // Update the static counter each time a new code stub is generated. 122 isolate()->counters()->code_stubs()->Increment(); 123 124 // Generate the code for the stub. 125 masm.set_generating_stub(true); 126 // TODO(yangguo): remove this once we can serialize IC stubs. 127 masm.enable_serializer(); 128 NoCurrentFrameScope scope(&masm); 129 Generate(&masm); 130 } 131 132 // Create the code object. 133 CodeDesc desc; 134 masm.GetCode(&desc); 135 // Copy the generated code into a heap object. 136 Code::Flags flags = Code::ComputeFlags(GetCodeKind(), GetExtraICState()); 137 Handle<Code> new_object = factory->NewCode( 138 desc, flags, masm.CodeObject(), NeedsImmovableCode()); 139 return new_object; 140 } 141 142 143 Handle<Code> CodeStub::GetCode() { 144 Heap* heap = isolate()->heap(); 145 Code* code; 146 if (UseSpecialCache() ? FindCodeInSpecialCache(&code) 147 : FindCodeInCache(&code)) { 148 DCHECK(GetCodeKind() == code->kind()); 149 return Handle<Code>(code); 150 } 151 152 { 153 HandleScope scope(isolate()); 154 155 Handle<Code> new_object = GenerateCode(); 156 new_object->set_stub_key(GetKey()); 157 FinishCode(new_object); 158 RecordCodeGeneration(new_object); 159 160 #ifdef ENABLE_DISASSEMBLER 161 if (FLAG_print_code_stubs) { 162 CodeTracer::Scope trace_scope(isolate()->GetCodeTracer()); 163 OFStream os(trace_scope.file()); 164 std::ostringstream name; 165 name << *this; 166 new_object->Disassemble(name.str().c_str(), os); 167 os << "\n"; 168 } 169 #endif 170 171 if (UseSpecialCache()) { 172 AddToSpecialCache(new_object); 173 } else { 174 // Update the dictionary and the root in Heap. 175 Handle<UnseededNumberDictionary> dict = 176 UnseededNumberDictionary::AtNumberPut( 177 Handle<UnseededNumberDictionary>(heap->code_stubs()), 178 GetKey(), 179 new_object); 180 heap->SetRootCodeStubs(*dict); 181 } 182 code = *new_object; 183 } 184 185 Activate(code); 186 DCHECK(!NeedsImmovableCode() || 187 heap->lo_space()->Contains(code) || 188 heap->code_space()->FirstPage()->Contains(code->address())); 189 return Handle<Code>(code, isolate()); 190 } 191 192 193 const char* CodeStub::MajorName(CodeStub::Major major_key) { 194 switch (major_key) { 195 #define DEF_CASE(name) case name: return #name "Stub"; 196 CODE_STUB_LIST(DEF_CASE) 197 #undef DEF_CASE 198 case NoCache: 199 return "<NoCache>Stub"; 200 case NUMBER_OF_IDS: 201 UNREACHABLE(); 202 return NULL; 203 } 204 return NULL; 205 } 206 207 208 void CodeStub::PrintBaseName(std::ostream& os) const { // NOLINT 209 os << MajorName(MajorKey()); 210 } 211 212 213 void CodeStub::PrintName(std::ostream& os) const { // NOLINT 214 PrintBaseName(os); 215 PrintState(os); 216 } 217 218 219 void CodeStub::Dispatch(Isolate* isolate, uint32_t key, void** value_out, 220 DispatchedCall call) { 221 switch (MajorKeyFromKey(key)) { 222 #define DEF_CASE(NAME) \ 223 case NAME: { \ 224 NAME##Stub stub(key, isolate); \ 225 CodeStub* pstub = &stub; \ 226 call(pstub, value_out); \ 227 break; \ 228 } 229 CODE_STUB_LIST(DEF_CASE) 230 #undef DEF_CASE 231 case NUMBER_OF_IDS: 232 case NoCache: 233 UNREACHABLE(); 234 break; 235 } 236 } 237 238 239 static void InitializeDescriptorDispatchedCall(CodeStub* stub, 240 void** value_out) { 241 CodeStubDescriptor* descriptor_out = 242 reinterpret_cast<CodeStubDescriptor*>(value_out); 243 stub->InitializeDescriptor(descriptor_out); 244 descriptor_out->set_call_descriptor(stub->GetCallInterfaceDescriptor()); 245 } 246 247 248 void CodeStub::InitializeDescriptor(Isolate* isolate, uint32_t key, 249 CodeStubDescriptor* desc) { 250 void** value_out = reinterpret_cast<void**>(desc); 251 Dispatch(isolate, key, value_out, &InitializeDescriptorDispatchedCall); 252 } 253 254 255 void CodeStub::GetCodeDispatchCall(CodeStub* stub, void** value_out) { 256 Handle<Code>* code_out = reinterpret_cast<Handle<Code>*>(value_out); 257 // Code stubs with special cache cannot be recreated from stub key. 258 *code_out = stub->UseSpecialCache() ? Handle<Code>() : stub->GetCode(); 259 } 260 261 262 MaybeHandle<Code> CodeStub::GetCode(Isolate* isolate, uint32_t key) { 263 HandleScope scope(isolate); 264 Handle<Code> code; 265 void** value_out = reinterpret_cast<void**>(&code); 266 Dispatch(isolate, key, value_out, &GetCodeDispatchCall); 267 return scope.CloseAndEscape(code); 268 } 269 270 271 // static 272 void BinaryOpICStub::GenerateAheadOfTime(Isolate* isolate) { 273 // Generate the uninitialized versions of the stub. 274 for (int op = Token::BIT_OR; op <= Token::MOD; ++op) { 275 BinaryOpICStub stub(isolate, static_cast<Token::Value>(op)); 276 stub.GetCode(); 277 } 278 279 // Generate special versions of the stub. 280 BinaryOpICState::GenerateAheadOfTime(isolate, &GenerateAheadOfTime); 281 } 282 283 284 void BinaryOpICStub::PrintState(std::ostream& os) const { // NOLINT 285 os << state(); 286 } 287 288 289 // static 290 void BinaryOpICStub::GenerateAheadOfTime(Isolate* isolate, 291 const BinaryOpICState& state) { 292 BinaryOpICStub stub(isolate, state); 293 stub.GetCode(); 294 } 295 296 297 // static 298 void BinaryOpICWithAllocationSiteStub::GenerateAheadOfTime(Isolate* isolate) { 299 // Generate special versions of the stub. 300 BinaryOpICState::GenerateAheadOfTime(isolate, &GenerateAheadOfTime); 301 } 302 303 304 void BinaryOpICWithAllocationSiteStub::PrintState( 305 std::ostream& os) const { // NOLINT 306 os << state(); 307 } 308 309 310 // static 311 void BinaryOpICWithAllocationSiteStub::GenerateAheadOfTime( 312 Isolate* isolate, const BinaryOpICState& state) { 313 if (state.CouldCreateAllocationMementos()) { 314 BinaryOpICWithAllocationSiteStub stub(isolate, state); 315 stub.GetCode(); 316 } 317 } 318 319 320 std::ostream& operator<<(std::ostream& os, const StringAddFlags& flags) { 321 switch (flags) { 322 case STRING_ADD_CHECK_NONE: 323 return os << "CheckNone"; 324 case STRING_ADD_CHECK_LEFT: 325 return os << "CheckLeft"; 326 case STRING_ADD_CHECK_RIGHT: 327 return os << "CheckRight"; 328 case STRING_ADD_CHECK_BOTH: 329 return os << "CheckBoth"; 330 case STRING_ADD_CONVERT_LEFT: 331 return os << "ConvertLeft"; 332 case STRING_ADD_CONVERT_RIGHT: 333 return os << "ConvertRight"; 334 case STRING_ADD_CONVERT: 335 break; 336 } 337 UNREACHABLE(); 338 return os; 339 } 340 341 342 void StringAddStub::PrintBaseName(std::ostream& os) const { // NOLINT 343 os << "StringAddStub_" << flags() << "_" << pretenure_flag(); 344 } 345 346 347 InlineCacheState CompareICStub::GetICState() const { 348 CompareICState::State state = Max(left(), right()); 349 switch (state) { 350 case CompareICState::UNINITIALIZED: 351 return ::v8::internal::UNINITIALIZED; 352 case CompareICState::BOOLEAN: 353 case CompareICState::SMI: 354 case CompareICState::NUMBER: 355 case CompareICState::INTERNALIZED_STRING: 356 case CompareICState::STRING: 357 case CompareICState::UNIQUE_NAME: 358 case CompareICState::RECEIVER: 359 case CompareICState::KNOWN_RECEIVER: 360 return MONOMORPHIC; 361 case CompareICState::GENERIC: 362 return ::v8::internal::GENERIC; 363 } 364 UNREACHABLE(); 365 return ::v8::internal::UNINITIALIZED; 366 } 367 368 369 Condition CompareICStub::GetCondition() const { 370 return CompareIC::ComputeCondition(op()); 371 } 372 373 374 void CompareICStub::Generate(MacroAssembler* masm) { 375 switch (state()) { 376 case CompareICState::UNINITIALIZED: 377 GenerateMiss(masm); 378 break; 379 case CompareICState::BOOLEAN: 380 GenerateBooleans(masm); 381 break; 382 case CompareICState::SMI: 383 GenerateSmis(masm); 384 break; 385 case CompareICState::NUMBER: 386 GenerateNumbers(masm); 387 break; 388 case CompareICState::STRING: 389 GenerateStrings(masm); 390 break; 391 case CompareICState::INTERNALIZED_STRING: 392 GenerateInternalizedStrings(masm); 393 break; 394 case CompareICState::UNIQUE_NAME: 395 GenerateUniqueNames(masm); 396 break; 397 case CompareICState::RECEIVER: 398 GenerateReceivers(masm); 399 break; 400 case CompareICState::KNOWN_RECEIVER: 401 DCHECK(*known_map_ != NULL); 402 GenerateKnownReceivers(masm); 403 break; 404 case CompareICState::GENERIC: 405 GenerateGeneric(masm); 406 break; 407 } 408 } 409 410 Handle<Code> TurboFanCodeStub::GenerateCode() { 411 const char* name = CodeStub::MajorName(MajorKey()); 412 Zone zone(isolate()->allocator()); 413 CallInterfaceDescriptor descriptor(GetCallInterfaceDescriptor()); 414 CodeStubAssembler assembler(isolate(), &zone, descriptor, GetCodeFlags(), 415 name); 416 GenerateAssembly(&assembler); 417 return assembler.GenerateCode(); 418 } 419 420 void LoadICTrampolineTFStub::GenerateAssembly( 421 CodeStubAssembler* assembler) const { 422 typedef compiler::Node Node; 423 424 Node* receiver = assembler->Parameter(0); 425 Node* name = assembler->Parameter(1); 426 Node* slot = assembler->Parameter(2); 427 Node* context = assembler->Parameter(3); 428 Node* vector = assembler->LoadTypeFeedbackVectorForStub(); 429 430 CodeStubAssembler::LoadICParameters p(context, receiver, name, slot, vector); 431 assembler->LoadIC(&p); 432 } 433 434 void LoadICTFStub::GenerateAssembly(CodeStubAssembler* assembler) const { 435 typedef compiler::Node Node; 436 437 Node* receiver = assembler->Parameter(0); 438 Node* name = assembler->Parameter(1); 439 Node* slot = assembler->Parameter(2); 440 Node* vector = assembler->Parameter(3); 441 Node* context = assembler->Parameter(4); 442 443 CodeStubAssembler::LoadICParameters p(context, receiver, name, slot, vector); 444 assembler->LoadIC(&p); 445 } 446 447 void LoadGlobalICTrampolineStub::GenerateAssembly( 448 CodeStubAssembler* assembler) const { 449 typedef compiler::Node Node; 450 451 Node* slot = assembler->Parameter(0); 452 Node* context = assembler->Parameter(1); 453 Node* vector = assembler->LoadTypeFeedbackVectorForStub(); 454 455 CodeStubAssembler::LoadICParameters p(context, nullptr, nullptr, slot, 456 vector); 457 assembler->LoadGlobalIC(&p); 458 } 459 460 void LoadGlobalICStub::GenerateAssembly(CodeStubAssembler* assembler) const { 461 typedef compiler::Node Node; 462 463 Node* slot = assembler->Parameter(0); 464 Node* vector = assembler->Parameter(1); 465 Node* context = assembler->Parameter(2); 466 467 CodeStubAssembler::LoadICParameters p(context, nullptr, nullptr, slot, 468 vector); 469 assembler->LoadGlobalIC(&p); 470 } 471 472 void AllocateHeapNumberStub::GenerateAssembly( 473 CodeStubAssembler* assembler) const { 474 typedef compiler::Node Node; 475 476 Node* result = assembler->AllocateHeapNumber(); 477 assembler->Return(result); 478 } 479 480 #define SIMD128_GEN_ASM(TYPE, Type, type, lane_count, lane_type) \ 481 void Allocate##Type##Stub::GenerateAssembly(CodeStubAssembler* assembler) \ 482 const { \ 483 compiler::Node* result = \ 484 assembler->Allocate(Simd128Value::kSize, CodeStubAssembler::kNone); \ 485 compiler::Node* map_offset = \ 486 assembler->IntPtrConstant(HeapObject::kMapOffset - kHeapObjectTag); \ 487 compiler::Node* map = assembler->IntPtrAdd(result, map_offset); \ 488 assembler->StoreNoWriteBarrier( \ 489 MachineRepresentation::kTagged, map, \ 490 assembler->HeapConstant(isolate()->factory()->type##_map())); \ 491 assembler->Return(result); \ 492 } 493 SIMD128_TYPES(SIMD128_GEN_ASM) 494 #undef SIMD128_GEN_ASM 495 496 void StringLengthStub::GenerateAssembly(CodeStubAssembler* assembler) const { 497 compiler::Node* value = assembler->Parameter(0); 498 compiler::Node* string = 499 assembler->LoadObjectField(value, JSValue::kValueOffset); 500 compiler::Node* result = 501 assembler->LoadObjectField(string, String::kLengthOffset); 502 assembler->Return(result); 503 } 504 505 // static 506 compiler::Node* AddStub::Generate(CodeStubAssembler* assembler, 507 compiler::Node* left, compiler::Node* right, 508 compiler::Node* context) { 509 typedef CodeStubAssembler::Label Label; 510 typedef compiler::Node Node; 511 typedef CodeStubAssembler::Variable Variable; 512 513 // Shared entry for floating point addition. 514 Label do_fadd(assembler); 515 Variable var_fadd_lhs(assembler, MachineRepresentation::kFloat64), 516 var_fadd_rhs(assembler, MachineRepresentation::kFloat64); 517 518 // We might need to loop several times due to ToPrimitive, ToString and/or 519 // ToNumber conversions. 520 Variable var_lhs(assembler, MachineRepresentation::kTagged), 521 var_rhs(assembler, MachineRepresentation::kTagged), 522 var_result(assembler, MachineRepresentation::kTagged); 523 Variable* loop_vars[2] = {&var_lhs, &var_rhs}; 524 Label loop(assembler, 2, loop_vars), end(assembler), 525 string_add_convert_left(assembler, Label::kDeferred), 526 string_add_convert_right(assembler, Label::kDeferred); 527 var_lhs.Bind(left); 528 var_rhs.Bind(right); 529 assembler->Goto(&loop); 530 assembler->Bind(&loop); 531 { 532 // Load the current {lhs} and {rhs} values. 533 Node* lhs = var_lhs.value(); 534 Node* rhs = var_rhs.value(); 535 536 // Check if the {lhs} is a Smi or a HeapObject. 537 Label if_lhsissmi(assembler), if_lhsisnotsmi(assembler); 538 assembler->Branch(assembler->WordIsSmi(lhs), &if_lhsissmi, &if_lhsisnotsmi); 539 540 assembler->Bind(&if_lhsissmi); 541 { 542 // Check if the {rhs} is also a Smi. 543 Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler); 544 assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi, 545 &if_rhsisnotsmi); 546 547 assembler->Bind(&if_rhsissmi); 548 { 549 // Try fast Smi addition first. 550 Node* pair = assembler->SmiAddWithOverflow(lhs, rhs); 551 Node* overflow = assembler->Projection(1, pair); 552 553 // Check if the Smi additon overflowed. 554 Label if_overflow(assembler), if_notoverflow(assembler); 555 assembler->Branch(overflow, &if_overflow, &if_notoverflow); 556 557 assembler->Bind(&if_overflow); 558 { 559 var_fadd_lhs.Bind(assembler->SmiToFloat64(lhs)); 560 var_fadd_rhs.Bind(assembler->SmiToFloat64(rhs)); 561 assembler->Goto(&do_fadd); 562 } 563 564 assembler->Bind(&if_notoverflow); 565 var_result.Bind(assembler->Projection(0, pair)); 566 assembler->Goto(&end); 567 } 568 569 assembler->Bind(&if_rhsisnotsmi); 570 { 571 // Load the map of {rhs}. 572 Node* rhs_map = assembler->LoadObjectField(rhs, HeapObject::kMapOffset); 573 574 // Check if the {rhs} is a HeapNumber. 575 Label if_rhsisnumber(assembler), 576 if_rhsisnotnumber(assembler, Label::kDeferred); 577 Node* number_map = assembler->HeapNumberMapConstant(); 578 assembler->Branch(assembler->WordEqual(rhs_map, number_map), 579 &if_rhsisnumber, &if_rhsisnotnumber); 580 581 assembler->Bind(&if_rhsisnumber); 582 { 583 var_fadd_lhs.Bind(assembler->SmiToFloat64(lhs)); 584 var_fadd_rhs.Bind(assembler->LoadHeapNumberValue(rhs)); 585 assembler->Goto(&do_fadd); 586 } 587 588 assembler->Bind(&if_rhsisnotnumber); 589 { 590 // Load the instance type of {rhs}. 591 Node* rhs_instance_type = assembler->LoadMapInstanceType(rhs_map); 592 593 // Check if the {rhs} is a String. 594 Label if_rhsisstring(assembler, Label::kDeferred), 595 if_rhsisnotstring(assembler, Label::kDeferred); 596 assembler->Branch(assembler->Int32LessThan( 597 rhs_instance_type, 598 assembler->Int32Constant(FIRST_NONSTRING_TYPE)), 599 &if_rhsisstring, &if_rhsisnotstring); 600 601 assembler->Bind(&if_rhsisstring); 602 { 603 var_lhs.Bind(lhs); 604 var_rhs.Bind(rhs); 605 assembler->Goto(&string_add_convert_left); 606 } 607 608 assembler->Bind(&if_rhsisnotstring); 609 { 610 // Check if {rhs} is a JSReceiver. 611 Label if_rhsisreceiver(assembler, Label::kDeferred), 612 if_rhsisnotreceiver(assembler, Label::kDeferred); 613 assembler->Branch( 614 assembler->Int32LessThanOrEqual( 615 assembler->Int32Constant(FIRST_JS_RECEIVER_TYPE), 616 rhs_instance_type), 617 &if_rhsisreceiver, &if_rhsisnotreceiver); 618 619 assembler->Bind(&if_rhsisreceiver); 620 { 621 // Convert {rhs} to a primitive first passing no hint. 622 // TODO(bmeurer): Hook up ToPrimitiveStub here, once it's there. 623 var_rhs.Bind( 624 assembler->CallRuntime(Runtime::kToPrimitive, context, rhs)); 625 assembler->Goto(&loop); 626 } 627 628 assembler->Bind(&if_rhsisnotreceiver); 629 { 630 // Convert {rhs} to a Number first. 631 Callable callable = 632 CodeFactory::NonNumberToNumber(assembler->isolate()); 633 var_rhs.Bind(assembler->CallStub(callable, context, rhs)); 634 assembler->Goto(&loop); 635 } 636 } 637 } 638 } 639 } 640 641 assembler->Bind(&if_lhsisnotsmi); 642 { 643 // Load the map and instance type of {lhs}. 644 Node* lhs_instance_type = assembler->LoadInstanceType(lhs); 645 646 // Check if {lhs} is a String. 647 Label if_lhsisstring(assembler), if_lhsisnotstring(assembler); 648 assembler->Branch(assembler->Int32LessThan( 649 lhs_instance_type, 650 assembler->Int32Constant(FIRST_NONSTRING_TYPE)), 651 &if_lhsisstring, &if_lhsisnotstring); 652 653 assembler->Bind(&if_lhsisstring); 654 { 655 var_lhs.Bind(lhs); 656 var_rhs.Bind(rhs); 657 assembler->Goto(&string_add_convert_right); 658 } 659 660 assembler->Bind(&if_lhsisnotstring); 661 { 662 // Check if {rhs} is a Smi. 663 Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler); 664 assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi, 665 &if_rhsisnotsmi); 666 667 assembler->Bind(&if_rhsissmi); 668 { 669 // Check if {lhs} is a Number. 670 Label if_lhsisnumber(assembler), 671 if_lhsisnotnumber(assembler, Label::kDeferred); 672 assembler->Branch(assembler->Word32Equal( 673 lhs_instance_type, 674 assembler->Int32Constant(HEAP_NUMBER_TYPE)), 675 &if_lhsisnumber, &if_lhsisnotnumber); 676 677 assembler->Bind(&if_lhsisnumber); 678 { 679 // The {lhs} is a HeapNumber, the {rhs} is a Smi, just add them. 680 var_fadd_lhs.Bind(assembler->LoadHeapNumberValue(lhs)); 681 var_fadd_rhs.Bind(assembler->SmiToFloat64(rhs)); 682 assembler->Goto(&do_fadd); 683 } 684 685 assembler->Bind(&if_lhsisnotnumber); 686 { 687 // The {lhs} is neither a Number nor a String, and the {rhs} is a 688 // Smi. 689 Label if_lhsisreceiver(assembler, Label::kDeferred), 690 if_lhsisnotreceiver(assembler, Label::kDeferred); 691 assembler->Branch( 692 assembler->Int32LessThanOrEqual( 693 assembler->Int32Constant(FIRST_JS_RECEIVER_TYPE), 694 lhs_instance_type), 695 &if_lhsisreceiver, &if_lhsisnotreceiver); 696 697 assembler->Bind(&if_lhsisreceiver); 698 { 699 // Convert {lhs} to a primitive first passing no hint. 700 // TODO(bmeurer): Hook up ToPrimitiveStub here, once it's there. 701 var_lhs.Bind( 702 assembler->CallRuntime(Runtime::kToPrimitive, context, lhs)); 703 assembler->Goto(&loop); 704 } 705 706 assembler->Bind(&if_lhsisnotreceiver); 707 { 708 // Convert {lhs} to a Number first. 709 Callable callable = 710 CodeFactory::NonNumberToNumber(assembler->isolate()); 711 var_lhs.Bind(assembler->CallStub(callable, context, lhs)); 712 assembler->Goto(&loop); 713 } 714 } 715 } 716 717 assembler->Bind(&if_rhsisnotsmi); 718 { 719 // Load the instance type of {rhs}. 720 Node* rhs_instance_type = assembler->LoadInstanceType(rhs); 721 722 // Check if {rhs} is a String. 723 Label if_rhsisstring(assembler), if_rhsisnotstring(assembler); 724 assembler->Branch(assembler->Int32LessThan( 725 rhs_instance_type, 726 assembler->Int32Constant(FIRST_NONSTRING_TYPE)), 727 &if_rhsisstring, &if_rhsisnotstring); 728 729 assembler->Bind(&if_rhsisstring); 730 { 731 var_lhs.Bind(lhs); 732 var_rhs.Bind(rhs); 733 assembler->Goto(&string_add_convert_left); 734 } 735 736 assembler->Bind(&if_rhsisnotstring); 737 { 738 // Check if {lhs} is a HeapNumber. 739 Label if_lhsisnumber(assembler), if_lhsisnotnumber(assembler); 740 assembler->Branch(assembler->Word32Equal( 741 lhs_instance_type, 742 assembler->Int32Constant(HEAP_NUMBER_TYPE)), 743 &if_lhsisnumber, &if_lhsisnotnumber); 744 745 assembler->Bind(&if_lhsisnumber); 746 { 747 // Check if {rhs} is also a HeapNumber. 748 Label if_rhsisnumber(assembler), 749 if_rhsisnotnumber(assembler, Label::kDeferred); 750 assembler->Branch(assembler->Word32Equal( 751 rhs_instance_type, 752 assembler->Int32Constant(HEAP_NUMBER_TYPE)), 753 &if_rhsisnumber, &if_rhsisnotnumber); 754 755 assembler->Bind(&if_rhsisnumber); 756 { 757 // Perform a floating point addition. 758 var_fadd_lhs.Bind(assembler->LoadHeapNumberValue(lhs)); 759 var_fadd_rhs.Bind(assembler->LoadHeapNumberValue(rhs)); 760 assembler->Goto(&do_fadd); 761 } 762 763 assembler->Bind(&if_rhsisnotnumber); 764 { 765 // Check if {rhs} is a JSReceiver. 766 Label if_rhsisreceiver(assembler, Label::kDeferred), 767 if_rhsisnotreceiver(assembler, Label::kDeferred); 768 assembler->Branch( 769 assembler->Int32LessThanOrEqual( 770 assembler->Int32Constant(FIRST_JS_RECEIVER_TYPE), 771 rhs_instance_type), 772 &if_rhsisreceiver, &if_rhsisnotreceiver); 773 774 assembler->Bind(&if_rhsisreceiver); 775 { 776 // Convert {rhs} to a primitive first passing no hint. 777 // TODO(bmeurer): Hook up ToPrimitiveStub here too. 778 var_rhs.Bind(assembler->CallRuntime(Runtime::kToPrimitive, 779 context, rhs)); 780 assembler->Goto(&loop); 781 } 782 783 assembler->Bind(&if_rhsisnotreceiver); 784 { 785 // Convert {rhs} to a Number first. 786 Callable callable = 787 CodeFactory::NonNumberToNumber(assembler->isolate()); 788 var_rhs.Bind(assembler->CallStub(callable, context, rhs)); 789 assembler->Goto(&loop); 790 } 791 } 792 } 793 794 assembler->Bind(&if_lhsisnotnumber); 795 { 796 // Check if {lhs} is a JSReceiver. 797 Label if_lhsisreceiver(assembler, Label::kDeferred), 798 if_lhsisnotreceiver(assembler); 799 assembler->Branch( 800 assembler->Int32LessThanOrEqual( 801 assembler->Int32Constant(FIRST_JS_RECEIVER_TYPE), 802 lhs_instance_type), 803 &if_lhsisreceiver, &if_lhsisnotreceiver); 804 805 assembler->Bind(&if_lhsisreceiver); 806 { 807 // Convert {lhs} to a primitive first passing no hint. 808 // TODO(bmeurer): Hook up ToPrimitiveStub here, once it's there. 809 var_lhs.Bind(assembler->CallRuntime(Runtime::kToPrimitive, 810 context, lhs)); 811 assembler->Goto(&loop); 812 } 813 814 assembler->Bind(&if_lhsisnotreceiver); 815 { 816 // Check if {rhs} is a JSReceiver. 817 Label if_rhsisreceiver(assembler, Label::kDeferred), 818 if_rhsisnotreceiver(assembler, Label::kDeferred); 819 assembler->Branch( 820 assembler->Int32LessThanOrEqual( 821 assembler->Int32Constant(FIRST_JS_RECEIVER_TYPE), 822 rhs_instance_type), 823 &if_rhsisreceiver, &if_rhsisnotreceiver); 824 825 assembler->Bind(&if_rhsisreceiver); 826 { 827 // Convert {rhs} to a primitive first passing no hint. 828 // TODO(bmeurer): Hook up ToPrimitiveStub here too. 829 var_rhs.Bind(assembler->CallRuntime(Runtime::kToPrimitive, 830 context, rhs)); 831 assembler->Goto(&loop); 832 } 833 834 assembler->Bind(&if_rhsisnotreceiver); 835 { 836 // Convert {lhs} to a Number first. 837 Callable callable = 838 CodeFactory::NonNumberToNumber(assembler->isolate()); 839 var_lhs.Bind(assembler->CallStub(callable, context, lhs)); 840 assembler->Goto(&loop); 841 } 842 } 843 } 844 } 845 } 846 } 847 } 848 } 849 assembler->Bind(&string_add_convert_left); 850 { 851 // Convert {lhs}, which is a Smi, to a String and concatenate the 852 // resulting string with the String {rhs}. 853 Callable callable = CodeFactory::StringAdd( 854 assembler->isolate(), STRING_ADD_CONVERT_LEFT, NOT_TENURED); 855 var_result.Bind(assembler->CallStub(callable, context, var_lhs.value(), 856 var_rhs.value())); 857 assembler->Goto(&end); 858 } 859 860 assembler->Bind(&string_add_convert_right); 861 { 862 // Convert {lhs}, which is a Smi, to a String and concatenate the 863 // resulting string with the String {rhs}. 864 Callable callable = CodeFactory::StringAdd( 865 assembler->isolate(), STRING_ADD_CONVERT_RIGHT, NOT_TENURED); 866 var_result.Bind(assembler->CallStub(callable, context, var_lhs.value(), 867 var_rhs.value())); 868 assembler->Goto(&end); 869 } 870 871 assembler->Bind(&do_fadd); 872 { 873 Node* lhs_value = var_fadd_lhs.value(); 874 Node* rhs_value = var_fadd_rhs.value(); 875 Node* value = assembler->Float64Add(lhs_value, rhs_value); 876 Node* result = assembler->ChangeFloat64ToTagged(value); 877 var_result.Bind(result); 878 assembler->Goto(&end); 879 } 880 assembler->Bind(&end); 881 return var_result.value(); 882 } 883 884 // static 885 compiler::Node* SubtractStub::Generate(CodeStubAssembler* assembler, 886 compiler::Node* left, 887 compiler::Node* right, 888 compiler::Node* context) { 889 typedef CodeStubAssembler::Label Label; 890 typedef compiler::Node Node; 891 typedef CodeStubAssembler::Variable Variable; 892 893 // Shared entry for floating point subtraction. 894 Label do_fsub(assembler), end(assembler); 895 Variable var_fsub_lhs(assembler, MachineRepresentation::kFloat64), 896 var_fsub_rhs(assembler, MachineRepresentation::kFloat64); 897 898 // We might need to loop several times due to ToPrimitive and/or ToNumber 899 // conversions. 900 Variable var_lhs(assembler, MachineRepresentation::kTagged), 901 var_rhs(assembler, MachineRepresentation::kTagged), 902 var_result(assembler, MachineRepresentation::kTagged); 903 Variable* loop_vars[2] = {&var_lhs, &var_rhs}; 904 Label loop(assembler, 2, loop_vars); 905 var_lhs.Bind(left); 906 var_rhs.Bind(right); 907 assembler->Goto(&loop); 908 assembler->Bind(&loop); 909 { 910 // Load the current {lhs} and {rhs} values. 911 Node* lhs = var_lhs.value(); 912 Node* rhs = var_rhs.value(); 913 914 // Check if the {lhs} is a Smi or a HeapObject. 915 Label if_lhsissmi(assembler), if_lhsisnotsmi(assembler); 916 assembler->Branch(assembler->WordIsSmi(lhs), &if_lhsissmi, &if_lhsisnotsmi); 917 918 assembler->Bind(&if_lhsissmi); 919 { 920 // Check if the {rhs} is also a Smi. 921 Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler); 922 assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi, 923 &if_rhsisnotsmi); 924 925 assembler->Bind(&if_rhsissmi); 926 { 927 // Try a fast Smi subtraction first. 928 Node* pair = assembler->SmiSubWithOverflow(lhs, rhs); 929 Node* overflow = assembler->Projection(1, pair); 930 931 // Check if the Smi subtraction overflowed. 932 Label if_overflow(assembler), if_notoverflow(assembler); 933 assembler->Branch(overflow, &if_overflow, &if_notoverflow); 934 935 assembler->Bind(&if_overflow); 936 { 937 // The result doesn't fit into Smi range. 938 var_fsub_lhs.Bind(assembler->SmiToFloat64(lhs)); 939 var_fsub_rhs.Bind(assembler->SmiToFloat64(rhs)); 940 assembler->Goto(&do_fsub); 941 } 942 943 assembler->Bind(&if_notoverflow); 944 var_result.Bind(assembler->Projection(0, pair)); 945 assembler->Goto(&end); 946 } 947 948 assembler->Bind(&if_rhsisnotsmi); 949 { 950 // Load the map of the {rhs}. 951 Node* rhs_map = assembler->LoadMap(rhs); 952 953 // Check if {rhs} is a HeapNumber. 954 Label if_rhsisnumber(assembler), 955 if_rhsisnotnumber(assembler, Label::kDeferred); 956 Node* number_map = assembler->HeapNumberMapConstant(); 957 assembler->Branch(assembler->WordEqual(rhs_map, number_map), 958 &if_rhsisnumber, &if_rhsisnotnumber); 959 960 assembler->Bind(&if_rhsisnumber); 961 { 962 // Perform a floating point subtraction. 963 var_fsub_lhs.Bind(assembler->SmiToFloat64(lhs)); 964 var_fsub_rhs.Bind(assembler->LoadHeapNumberValue(rhs)); 965 assembler->Goto(&do_fsub); 966 } 967 968 assembler->Bind(&if_rhsisnotnumber); 969 { 970 // Convert the {rhs} to a Number first. 971 Callable callable = 972 CodeFactory::NonNumberToNumber(assembler->isolate()); 973 var_rhs.Bind(assembler->CallStub(callable, context, rhs)); 974 assembler->Goto(&loop); 975 } 976 } 977 } 978 979 assembler->Bind(&if_lhsisnotsmi); 980 { 981 // Load the map of the {lhs}. 982 Node* lhs_map = assembler->LoadMap(lhs); 983 984 // Check if the {lhs} is a HeapNumber. 985 Label if_lhsisnumber(assembler), 986 if_lhsisnotnumber(assembler, Label::kDeferred); 987 Node* number_map = assembler->HeapNumberMapConstant(); 988 assembler->Branch(assembler->WordEqual(lhs_map, number_map), 989 &if_lhsisnumber, &if_lhsisnotnumber); 990 991 assembler->Bind(&if_lhsisnumber); 992 { 993 // Check if the {rhs} is a Smi. 994 Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler); 995 assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi, 996 &if_rhsisnotsmi); 997 998 assembler->Bind(&if_rhsissmi); 999 { 1000 // Perform a floating point subtraction. 1001 var_fsub_lhs.Bind(assembler->LoadHeapNumberValue(lhs)); 1002 var_fsub_rhs.Bind(assembler->SmiToFloat64(rhs)); 1003 assembler->Goto(&do_fsub); 1004 } 1005 1006 assembler->Bind(&if_rhsisnotsmi); 1007 { 1008 // Load the map of the {rhs}. 1009 Node* rhs_map = assembler->LoadMap(rhs); 1010 1011 // Check if the {rhs} is a HeapNumber. 1012 Label if_rhsisnumber(assembler), 1013 if_rhsisnotnumber(assembler, Label::kDeferred); 1014 assembler->Branch(assembler->WordEqual(rhs_map, number_map), 1015 &if_rhsisnumber, &if_rhsisnotnumber); 1016 1017 assembler->Bind(&if_rhsisnumber); 1018 { 1019 // Perform a floating point subtraction. 1020 var_fsub_lhs.Bind(assembler->LoadHeapNumberValue(lhs)); 1021 var_fsub_rhs.Bind(assembler->LoadHeapNumberValue(rhs)); 1022 assembler->Goto(&do_fsub); 1023 } 1024 1025 assembler->Bind(&if_rhsisnotnumber); 1026 { 1027 // Convert the {rhs} to a Number first. 1028 Callable callable = 1029 CodeFactory::NonNumberToNumber(assembler->isolate()); 1030 var_rhs.Bind(assembler->CallStub(callable, context, rhs)); 1031 assembler->Goto(&loop); 1032 } 1033 } 1034 } 1035 1036 assembler->Bind(&if_lhsisnotnumber); 1037 { 1038 // Convert the {lhs} to a Number first. 1039 Callable callable = 1040 CodeFactory::NonNumberToNumber(assembler->isolate()); 1041 var_lhs.Bind(assembler->CallStub(callable, context, lhs)); 1042 assembler->Goto(&loop); 1043 } 1044 } 1045 } 1046 1047 assembler->Bind(&do_fsub); 1048 { 1049 Node* lhs_value = var_fsub_lhs.value(); 1050 Node* rhs_value = var_fsub_rhs.value(); 1051 Node* value = assembler->Float64Sub(lhs_value, rhs_value); 1052 var_result.Bind(assembler->ChangeFloat64ToTagged(value)); 1053 assembler->Goto(&end); 1054 } 1055 assembler->Bind(&end); 1056 return var_result.value(); 1057 } 1058 1059 // static 1060 compiler::Node* MultiplyStub::Generate(CodeStubAssembler* assembler, 1061 compiler::Node* left, 1062 compiler::Node* right, 1063 compiler::Node* context) { 1064 using compiler::Node; 1065 typedef CodeStubAssembler::Label Label; 1066 typedef CodeStubAssembler::Variable Variable; 1067 1068 // Shared entry point for floating point multiplication. 1069 Label do_fmul(assembler); 1070 Variable var_lhs_float64(assembler, MachineRepresentation::kFloat64), 1071 var_rhs_float64(assembler, MachineRepresentation::kFloat64); 1072 1073 Node* number_map = assembler->HeapNumberMapConstant(); 1074 1075 // We might need to loop one or two times due to ToNumber conversions. 1076 Variable var_lhs(assembler, MachineRepresentation::kTagged), 1077 var_rhs(assembler, MachineRepresentation::kTagged); 1078 Variable* loop_variables[] = {&var_lhs, &var_rhs}; 1079 Label loop(assembler, 2, loop_variables); 1080 var_lhs.Bind(left); 1081 var_rhs.Bind(right); 1082 assembler->Goto(&loop); 1083 assembler->Bind(&loop); 1084 { 1085 Node* lhs = var_lhs.value(); 1086 Node* rhs = var_rhs.value(); 1087 1088 Label lhs_is_smi(assembler), lhs_is_not_smi(assembler); 1089 assembler->Branch(assembler->WordIsSmi(lhs), &lhs_is_smi, &lhs_is_not_smi); 1090 1091 assembler->Bind(&lhs_is_smi); 1092 { 1093 Label rhs_is_smi(assembler), rhs_is_not_smi(assembler); 1094 assembler->Branch(assembler->WordIsSmi(rhs), &rhs_is_smi, 1095 &rhs_is_not_smi); 1096 1097 assembler->Bind(&rhs_is_smi); 1098 { 1099 // Both {lhs} and {rhs} are Smis. Convert them to double and multiply. 1100 // TODO(epertoso): use SmiMulWithOverflow once available. 1101 var_lhs_float64.Bind(assembler->SmiToFloat64(lhs)); 1102 var_rhs_float64.Bind(assembler->SmiToFloat64(rhs)); 1103 assembler->Goto(&do_fmul); 1104 } 1105 1106 assembler->Bind(&rhs_is_not_smi); 1107 { 1108 Node* rhs_map = assembler->LoadMap(rhs); 1109 1110 // Check if {rhs} is a HeapNumber. 1111 Label rhs_is_number(assembler), 1112 rhs_is_not_number(assembler, Label::kDeferred); 1113 assembler->Branch(assembler->WordEqual(rhs_map, number_map), 1114 &rhs_is_number, &rhs_is_not_number); 1115 1116 assembler->Bind(&rhs_is_number); 1117 { 1118 // Convert {lhs} to a double and multiply it with the value of {rhs}. 1119 var_lhs_float64.Bind(assembler->SmiToFloat64(lhs)); 1120 var_rhs_float64.Bind(assembler->LoadHeapNumberValue(rhs)); 1121 assembler->Goto(&do_fmul); 1122 } 1123 1124 assembler->Bind(&rhs_is_not_number); 1125 { 1126 // Multiplication is commutative, swap {lhs} with {rhs} and loop. 1127 var_lhs.Bind(rhs); 1128 var_rhs.Bind(lhs); 1129 assembler->Goto(&loop); 1130 } 1131 } 1132 } 1133 1134 assembler->Bind(&lhs_is_not_smi); 1135 { 1136 Node* lhs_map = assembler->LoadMap(lhs); 1137 1138 // Check if {lhs} is a HeapNumber. 1139 Label lhs_is_number(assembler), 1140 lhs_is_not_number(assembler, Label::kDeferred); 1141 assembler->Branch(assembler->WordEqual(lhs_map, number_map), 1142 &lhs_is_number, &lhs_is_not_number); 1143 1144 assembler->Bind(&lhs_is_number); 1145 { 1146 // Check if {rhs} is a Smi. 1147 Label rhs_is_smi(assembler), rhs_is_not_smi(assembler); 1148 assembler->Branch(assembler->WordIsSmi(rhs), &rhs_is_smi, 1149 &rhs_is_not_smi); 1150 1151 assembler->Bind(&rhs_is_smi); 1152 { 1153 // Convert {rhs} to a double and multiply it with the value of {lhs}. 1154 var_lhs_float64.Bind(assembler->LoadHeapNumberValue(lhs)); 1155 var_rhs_float64.Bind(assembler->SmiToFloat64(rhs)); 1156 assembler->Goto(&do_fmul); 1157 } 1158 1159 assembler->Bind(&rhs_is_not_smi); 1160 { 1161 Node* rhs_map = assembler->LoadMap(rhs); 1162 1163 // Check if {rhs} is a HeapNumber. 1164 Label rhs_is_number(assembler), 1165 rhs_is_not_number(assembler, Label::kDeferred); 1166 assembler->Branch(assembler->WordEqual(rhs_map, number_map), 1167 &rhs_is_number, &rhs_is_not_number); 1168 1169 assembler->Bind(&rhs_is_number); 1170 { 1171 // Both {lhs} and {rhs} are HeapNumbers. Load their values and 1172 // multiply them. 1173 var_lhs_float64.Bind(assembler->LoadHeapNumberValue(lhs)); 1174 var_rhs_float64.Bind(assembler->LoadHeapNumberValue(rhs)); 1175 assembler->Goto(&do_fmul); 1176 } 1177 1178 assembler->Bind(&rhs_is_not_number); 1179 { 1180 // Multiplication is commutative, swap {lhs} with {rhs} and loop. 1181 var_lhs.Bind(rhs); 1182 var_rhs.Bind(lhs); 1183 assembler->Goto(&loop); 1184 } 1185 } 1186 } 1187 1188 assembler->Bind(&lhs_is_not_number); 1189 { 1190 // Convert {lhs} to a Number and loop. 1191 Callable callable = 1192 CodeFactory::NonNumberToNumber(assembler->isolate()); 1193 var_lhs.Bind(assembler->CallStub(callable, context, lhs)); 1194 assembler->Goto(&loop); 1195 } 1196 } 1197 } 1198 1199 assembler->Bind(&do_fmul); 1200 { 1201 Node* value = 1202 assembler->Float64Mul(var_lhs_float64.value(), var_rhs_float64.value()); 1203 Node* result = assembler->ChangeFloat64ToTagged(value); 1204 return result; 1205 } 1206 } 1207 1208 // static 1209 compiler::Node* DivideStub::Generate(CodeStubAssembler* assembler, 1210 compiler::Node* left, 1211 compiler::Node* right, 1212 compiler::Node* context) { 1213 using compiler::Node; 1214 typedef CodeStubAssembler::Label Label; 1215 typedef CodeStubAssembler::Variable Variable; 1216 1217 // Shared entry point for floating point division. 1218 Label do_fdiv(assembler), end(assembler); 1219 Variable var_dividend_float64(assembler, MachineRepresentation::kFloat64), 1220 var_divisor_float64(assembler, MachineRepresentation::kFloat64); 1221 1222 Node* number_map = assembler->HeapNumberMapConstant(); 1223 1224 // We might need to loop one or two times due to ToNumber conversions. 1225 Variable var_dividend(assembler, MachineRepresentation::kTagged), 1226 var_divisor(assembler, MachineRepresentation::kTagged), 1227 var_result(assembler, MachineRepresentation::kTagged); 1228 Variable* loop_variables[] = {&var_dividend, &var_divisor}; 1229 Label loop(assembler, 2, loop_variables); 1230 var_dividend.Bind(left); 1231 var_divisor.Bind(right); 1232 assembler->Goto(&loop); 1233 assembler->Bind(&loop); 1234 { 1235 Node* dividend = var_dividend.value(); 1236 Node* divisor = var_divisor.value(); 1237 1238 Label dividend_is_smi(assembler), dividend_is_not_smi(assembler); 1239 assembler->Branch(assembler->WordIsSmi(dividend), ÷nd_is_smi, 1240 ÷nd_is_not_smi); 1241 1242 assembler->Bind(÷nd_is_smi); 1243 { 1244 Label divisor_is_smi(assembler), divisor_is_not_smi(assembler); 1245 assembler->Branch(assembler->WordIsSmi(divisor), &divisor_is_smi, 1246 &divisor_is_not_smi); 1247 1248 assembler->Bind(&divisor_is_smi); 1249 { 1250 Label bailout(assembler); 1251 1252 // Do floating point division if {divisor} is zero. 1253 assembler->GotoIf( 1254 assembler->WordEqual(divisor, assembler->IntPtrConstant(0)), 1255 &bailout); 1256 1257 // Do floating point division {dividend} is zero and {divisor} is 1258 // negative. 1259 Label dividend_is_zero(assembler), dividend_is_not_zero(assembler); 1260 assembler->Branch( 1261 assembler->WordEqual(dividend, assembler->IntPtrConstant(0)), 1262 ÷nd_is_zero, ÷nd_is_not_zero); 1263 1264 assembler->Bind(÷nd_is_zero); 1265 { 1266 assembler->GotoIf( 1267 assembler->IntPtrLessThan(divisor, assembler->IntPtrConstant(0)), 1268 &bailout); 1269 assembler->Goto(÷nd_is_not_zero); 1270 } 1271 assembler->Bind(÷nd_is_not_zero); 1272 1273 Node* untagged_divisor = assembler->SmiUntag(divisor); 1274 Node* untagged_dividend = assembler->SmiUntag(dividend); 1275 1276 // Do floating point division if {dividend} is kMinInt (or kMinInt - 1 1277 // if the Smi size is 31) and {divisor} is -1. 1278 Label divisor_is_minus_one(assembler), 1279 divisor_is_not_minus_one(assembler); 1280 assembler->Branch(assembler->Word32Equal(untagged_divisor, 1281 assembler->Int32Constant(-1)), 1282 &divisor_is_minus_one, &divisor_is_not_minus_one); 1283 1284 assembler->Bind(&divisor_is_minus_one); 1285 { 1286 assembler->GotoIf( 1287 assembler->Word32Equal( 1288 untagged_dividend, 1289 assembler->Int32Constant( 1290 kSmiValueSize == 32 ? kMinInt : (kMinInt >> 1))), 1291 &bailout); 1292 assembler->Goto(&divisor_is_not_minus_one); 1293 } 1294 assembler->Bind(&divisor_is_not_minus_one); 1295 1296 // TODO(epertoso): consider adding a machine instruction that returns 1297 // both the result and the remainder. 1298 Node* untagged_result = 1299 assembler->Int32Div(untagged_dividend, untagged_divisor); 1300 Node* truncated = 1301 assembler->IntPtrMul(untagged_result, untagged_divisor); 1302 // Do floating point division if the remainder is not 0. 1303 assembler->GotoIf( 1304 assembler->Word32NotEqual(untagged_dividend, truncated), &bailout); 1305 var_result.Bind(assembler->SmiTag(untagged_result)); 1306 assembler->Goto(&end); 1307 1308 // Bailout: convert {dividend} and {divisor} to double and do double 1309 // division. 1310 assembler->Bind(&bailout); 1311 { 1312 var_dividend_float64.Bind(assembler->SmiToFloat64(dividend)); 1313 var_divisor_float64.Bind(assembler->SmiToFloat64(divisor)); 1314 assembler->Goto(&do_fdiv); 1315 } 1316 } 1317 1318 assembler->Bind(&divisor_is_not_smi); 1319 { 1320 Node* divisor_map = assembler->LoadMap(divisor); 1321 1322 // Check if {divisor} is a HeapNumber. 1323 Label divisor_is_number(assembler), 1324 divisor_is_not_number(assembler, Label::kDeferred); 1325 assembler->Branch(assembler->WordEqual(divisor_map, number_map), 1326 &divisor_is_number, &divisor_is_not_number); 1327 1328 assembler->Bind(&divisor_is_number); 1329 { 1330 // Convert {dividend} to a double and divide it with the value of 1331 // {divisor}. 1332 var_dividend_float64.Bind(assembler->SmiToFloat64(dividend)); 1333 var_divisor_float64.Bind(assembler->LoadHeapNumberValue(divisor)); 1334 assembler->Goto(&do_fdiv); 1335 } 1336 1337 assembler->Bind(&divisor_is_not_number); 1338 { 1339 // Convert {divisor} to a number and loop. 1340 Callable callable = 1341 CodeFactory::NonNumberToNumber(assembler->isolate()); 1342 var_divisor.Bind(assembler->CallStub(callable, context, divisor)); 1343 assembler->Goto(&loop); 1344 } 1345 } 1346 } 1347 1348 assembler->Bind(÷nd_is_not_smi); 1349 { 1350 Node* dividend_map = assembler->LoadMap(dividend); 1351 1352 // Check if {dividend} is a HeapNumber. 1353 Label dividend_is_number(assembler), 1354 dividend_is_not_number(assembler, Label::kDeferred); 1355 assembler->Branch(assembler->WordEqual(dividend_map, number_map), 1356 ÷nd_is_number, ÷nd_is_not_number); 1357 1358 assembler->Bind(÷nd_is_number); 1359 { 1360 // Check if {divisor} is a Smi. 1361 Label divisor_is_smi(assembler), divisor_is_not_smi(assembler); 1362 assembler->Branch(assembler->WordIsSmi(divisor), &divisor_is_smi, 1363 &divisor_is_not_smi); 1364 1365 assembler->Bind(&divisor_is_smi); 1366 { 1367 // Convert {divisor} to a double and use it for a floating point 1368 // division. 1369 var_dividend_float64.Bind(assembler->LoadHeapNumberValue(dividend)); 1370 var_divisor_float64.Bind(assembler->SmiToFloat64(divisor)); 1371 assembler->Goto(&do_fdiv); 1372 } 1373 1374 assembler->Bind(&divisor_is_not_smi); 1375 { 1376 Node* divisor_map = assembler->LoadMap(divisor); 1377 1378 // Check if {divisor} is a HeapNumber. 1379 Label divisor_is_number(assembler), 1380 divisor_is_not_number(assembler, Label::kDeferred); 1381 assembler->Branch(assembler->WordEqual(divisor_map, number_map), 1382 &divisor_is_number, &divisor_is_not_number); 1383 1384 assembler->Bind(&divisor_is_number); 1385 { 1386 // Both {dividend} and {divisor} are HeapNumbers. Load their values 1387 // and divide them. 1388 var_dividend_float64.Bind(assembler->LoadHeapNumberValue(dividend)); 1389 var_divisor_float64.Bind(assembler->LoadHeapNumberValue(divisor)); 1390 assembler->Goto(&do_fdiv); 1391 } 1392 1393 assembler->Bind(&divisor_is_not_number); 1394 { 1395 // Convert {divisor} to a number and loop. 1396 Callable callable = 1397 CodeFactory::NonNumberToNumber(assembler->isolate()); 1398 var_divisor.Bind(assembler->CallStub(callable, context, divisor)); 1399 assembler->Goto(&loop); 1400 } 1401 } 1402 } 1403 1404 assembler->Bind(÷nd_is_not_number); 1405 { 1406 // Convert {dividend} to a Number and loop. 1407 Callable callable = 1408 CodeFactory::NonNumberToNumber(assembler->isolate()); 1409 var_dividend.Bind(assembler->CallStub(callable, context, dividend)); 1410 assembler->Goto(&loop); 1411 } 1412 } 1413 } 1414 1415 assembler->Bind(&do_fdiv); 1416 { 1417 Node* value = assembler->Float64Div(var_dividend_float64.value(), 1418 var_divisor_float64.value()); 1419 var_result.Bind(assembler->ChangeFloat64ToTagged(value)); 1420 assembler->Goto(&end); 1421 } 1422 assembler->Bind(&end); 1423 return var_result.value(); 1424 } 1425 1426 // static 1427 compiler::Node* ModulusStub::Generate(CodeStubAssembler* assembler, 1428 compiler::Node* left, 1429 compiler::Node* right, 1430 compiler::Node* context) { 1431 using compiler::Node; 1432 typedef CodeStubAssembler::Label Label; 1433 typedef CodeStubAssembler::Variable Variable; 1434 1435 // Shared entry point for floating point modulus. 1436 Label do_fmod(assembler); 1437 Variable var_dividend_float64(assembler, MachineRepresentation::kFloat64), 1438 var_divisor_float64(assembler, MachineRepresentation::kFloat64); 1439 1440 Node* number_map = assembler->HeapNumberMapConstant(); 1441 1442 // We might need to loop one or two times due to ToNumber conversions. 1443 Variable var_dividend(assembler, MachineRepresentation::kTagged), 1444 var_divisor(assembler, MachineRepresentation::kTagged); 1445 Variable* loop_variables[] = {&var_dividend, &var_divisor}; 1446 Label loop(assembler, 2, loop_variables); 1447 var_dividend.Bind(left); 1448 var_divisor.Bind(right); 1449 assembler->Goto(&loop); 1450 assembler->Bind(&loop); 1451 { 1452 Node* dividend = var_dividend.value(); 1453 Node* divisor = var_divisor.value(); 1454 1455 Label dividend_is_smi(assembler), dividend_is_not_smi(assembler); 1456 assembler->Branch(assembler->WordIsSmi(dividend), ÷nd_is_smi, 1457 ÷nd_is_not_smi); 1458 1459 assembler->Bind(÷nd_is_smi); 1460 { 1461 Label dividend_is_not_zero(assembler); 1462 Label divisor_is_smi(assembler), divisor_is_not_smi(assembler); 1463 assembler->Branch(assembler->WordIsSmi(divisor), &divisor_is_smi, 1464 &divisor_is_not_smi); 1465 1466 assembler->Bind(&divisor_is_smi); 1467 { 1468 var_dividend_float64.Bind(assembler->SmiToFloat64(dividend)); 1469 var_divisor_float64.Bind(assembler->SmiToFloat64(divisor)); 1470 assembler->Goto(&do_fmod); 1471 } 1472 1473 assembler->Bind(&divisor_is_not_smi); 1474 { 1475 Node* divisor_map = assembler->LoadMap(divisor); 1476 1477 // Check if {divisor} is a HeapNumber. 1478 Label divisor_is_number(assembler), 1479 divisor_is_not_number(assembler, Label::kDeferred); 1480 assembler->Branch(assembler->WordEqual(divisor_map, number_map), 1481 &divisor_is_number, &divisor_is_not_number); 1482 1483 assembler->Bind(&divisor_is_number); 1484 { 1485 // Convert {dividend} to a double and compute its modulus with the 1486 // value of {dividend}. 1487 var_dividend_float64.Bind(assembler->SmiToFloat64(dividend)); 1488 var_divisor_float64.Bind(assembler->LoadHeapNumberValue(divisor)); 1489 assembler->Goto(&do_fmod); 1490 } 1491 1492 assembler->Bind(&divisor_is_not_number); 1493 { 1494 // Convert {divisor} to a number and loop. 1495 Callable callable = 1496 CodeFactory::NonNumberToNumber(assembler->isolate()); 1497 var_divisor.Bind(assembler->CallStub(callable, context, divisor)); 1498 assembler->Goto(&loop); 1499 } 1500 } 1501 } 1502 1503 assembler->Bind(÷nd_is_not_smi); 1504 { 1505 Node* dividend_map = assembler->LoadMap(dividend); 1506 1507 // Check if {dividend} is a HeapNumber. 1508 Label dividend_is_number(assembler), 1509 dividend_is_not_number(assembler, Label::kDeferred); 1510 assembler->Branch(assembler->WordEqual(dividend_map, number_map), 1511 ÷nd_is_number, ÷nd_is_not_number); 1512 1513 assembler->Bind(÷nd_is_number); 1514 { 1515 // Check if {divisor} is a Smi. 1516 Label divisor_is_smi(assembler), divisor_is_not_smi(assembler); 1517 assembler->Branch(assembler->WordIsSmi(divisor), &divisor_is_smi, 1518 &divisor_is_not_smi); 1519 1520 assembler->Bind(&divisor_is_smi); 1521 { 1522 // Convert {divisor} to a double and compute {dividend}'s modulus with 1523 // it. 1524 var_dividend_float64.Bind(assembler->LoadHeapNumberValue(dividend)); 1525 var_divisor_float64.Bind(assembler->SmiToFloat64(divisor)); 1526 assembler->Goto(&do_fmod); 1527 } 1528 1529 assembler->Bind(&divisor_is_not_smi); 1530 { 1531 Node* divisor_map = assembler->LoadMap(divisor); 1532 1533 // Check if {divisor} is a HeapNumber. 1534 Label divisor_is_number(assembler), 1535 divisor_is_not_number(assembler, Label::kDeferred); 1536 assembler->Branch(assembler->WordEqual(divisor_map, number_map), 1537 &divisor_is_number, &divisor_is_not_number); 1538 1539 assembler->Bind(&divisor_is_number); 1540 { 1541 // Both {dividend} and {divisor} are HeapNumbers. Load their values 1542 // and compute their modulus. 1543 var_dividend_float64.Bind(assembler->LoadHeapNumberValue(dividend)); 1544 var_divisor_float64.Bind(assembler->LoadHeapNumberValue(divisor)); 1545 assembler->Goto(&do_fmod); 1546 } 1547 1548 assembler->Bind(&divisor_is_not_number); 1549 { 1550 // Convert {divisor} to a number and loop. 1551 Callable callable = 1552 CodeFactory::NonNumberToNumber(assembler->isolate()); 1553 var_divisor.Bind(assembler->CallStub(callable, context, divisor)); 1554 assembler->Goto(&loop); 1555 } 1556 } 1557 } 1558 1559 assembler->Bind(÷nd_is_not_number); 1560 { 1561 // Convert {dividend} to a Number and loop. 1562 Callable callable = 1563 CodeFactory::NonNumberToNumber(assembler->isolate()); 1564 var_dividend.Bind(assembler->CallStub(callable, context, dividend)); 1565 assembler->Goto(&loop); 1566 } 1567 } 1568 } 1569 1570 assembler->Bind(&do_fmod); 1571 { 1572 Node* value = assembler->Float64Mod(var_dividend_float64.value(), 1573 var_divisor_float64.value()); 1574 Node* result = assembler->ChangeFloat64ToTagged(value); 1575 return result; 1576 } 1577 } 1578 1579 // static 1580 compiler::Node* ShiftLeftStub::Generate(CodeStubAssembler* assembler, 1581 compiler::Node* left, 1582 compiler::Node* right, 1583 compiler::Node* context) { 1584 using compiler::Node; 1585 1586 Node* lhs_value = assembler->TruncateTaggedToWord32(context, left); 1587 Node* rhs_value = assembler->TruncateTaggedToWord32(context, right); 1588 Node* shift_count = 1589 assembler->Word32And(rhs_value, assembler->Int32Constant(0x1f)); 1590 Node* value = assembler->Word32Shl(lhs_value, shift_count); 1591 Node* result = assembler->ChangeInt32ToTagged(value); 1592 return result; 1593 } 1594 1595 // static 1596 compiler::Node* ShiftRightStub::Generate(CodeStubAssembler* assembler, 1597 compiler::Node* left, 1598 compiler::Node* right, 1599 compiler::Node* context) { 1600 using compiler::Node; 1601 1602 Node* lhs_value = assembler->TruncateTaggedToWord32(context, left); 1603 Node* rhs_value = assembler->TruncateTaggedToWord32(context, right); 1604 Node* shift_count = 1605 assembler->Word32And(rhs_value, assembler->Int32Constant(0x1f)); 1606 Node* value = assembler->Word32Sar(lhs_value, shift_count); 1607 Node* result = assembler->ChangeInt32ToTagged(value); 1608 return result; 1609 } 1610 1611 // static 1612 compiler::Node* ShiftRightLogicalStub::Generate(CodeStubAssembler* assembler, 1613 compiler::Node* left, 1614 compiler::Node* right, 1615 compiler::Node* context) { 1616 using compiler::Node; 1617 1618 Node* lhs_value = assembler->TruncateTaggedToWord32(context, left); 1619 Node* rhs_value = assembler->TruncateTaggedToWord32(context, right); 1620 Node* shift_count = 1621 assembler->Word32And(rhs_value, assembler->Int32Constant(0x1f)); 1622 Node* value = assembler->Word32Shr(lhs_value, shift_count); 1623 Node* result = assembler->ChangeUint32ToTagged(value); 1624 return result; 1625 } 1626 1627 // static 1628 compiler::Node* BitwiseAndStub::Generate(CodeStubAssembler* assembler, 1629 compiler::Node* left, 1630 compiler::Node* right, 1631 compiler::Node* context) { 1632 using compiler::Node; 1633 1634 Node* lhs_value = assembler->TruncateTaggedToWord32(context, left); 1635 Node* rhs_value = assembler->TruncateTaggedToWord32(context, right); 1636 Node* value = assembler->Word32And(lhs_value, rhs_value); 1637 Node* result = assembler->ChangeInt32ToTagged(value); 1638 return result; 1639 } 1640 1641 // static 1642 compiler::Node* BitwiseOrStub::Generate(CodeStubAssembler* assembler, 1643 compiler::Node* left, 1644 compiler::Node* right, 1645 compiler::Node* context) { 1646 using compiler::Node; 1647 1648 Node* lhs_value = assembler->TruncateTaggedToWord32(context, left); 1649 Node* rhs_value = assembler->TruncateTaggedToWord32(context, right); 1650 Node* value = assembler->Word32Or(lhs_value, rhs_value); 1651 Node* result = assembler->ChangeInt32ToTagged(value); 1652 return result; 1653 } 1654 1655 // static 1656 compiler::Node* BitwiseXorStub::Generate(CodeStubAssembler* assembler, 1657 compiler::Node* left, 1658 compiler::Node* right, 1659 compiler::Node* context) { 1660 using compiler::Node; 1661 1662 Node* lhs_value = assembler->TruncateTaggedToWord32(context, left); 1663 Node* rhs_value = assembler->TruncateTaggedToWord32(context, right); 1664 Node* value = assembler->Word32Xor(lhs_value, rhs_value); 1665 Node* result = assembler->ChangeInt32ToTagged(value); 1666 return result; 1667 } 1668 1669 // static 1670 compiler::Node* IncStub::Generate(CodeStubAssembler* assembler, 1671 compiler::Node* value, 1672 compiler::Node* context) { 1673 typedef CodeStubAssembler::Label Label; 1674 typedef compiler::Node Node; 1675 typedef CodeStubAssembler::Variable Variable; 1676 1677 // Shared entry for floating point increment. 1678 Label do_finc(assembler), end(assembler); 1679 Variable var_finc_value(assembler, MachineRepresentation::kFloat64); 1680 1681 // We might need to try again due to ToNumber conversion. 1682 Variable value_var(assembler, MachineRepresentation::kTagged); 1683 Variable result_var(assembler, MachineRepresentation::kTagged); 1684 Label start(assembler, &value_var); 1685 value_var.Bind(value); 1686 assembler->Goto(&start); 1687 assembler->Bind(&start); 1688 { 1689 value = value_var.value(); 1690 1691 Label if_issmi(assembler), if_isnotsmi(assembler); 1692 assembler->Branch(assembler->WordIsSmi(value), &if_issmi, &if_isnotsmi); 1693 1694 assembler->Bind(&if_issmi); 1695 { 1696 // Try fast Smi addition first. 1697 Node* one = assembler->SmiConstant(Smi::FromInt(1)); 1698 Node* pair = assembler->SmiAddWithOverflow(value, one); 1699 Node* overflow = assembler->Projection(1, pair); 1700 1701 // Check if the Smi additon overflowed. 1702 Label if_overflow(assembler), if_notoverflow(assembler); 1703 assembler->Branch(overflow, &if_overflow, &if_notoverflow); 1704 1705 assembler->Bind(&if_notoverflow); 1706 result_var.Bind(assembler->Projection(0, pair)); 1707 assembler->Goto(&end); 1708 1709 assembler->Bind(&if_overflow); 1710 { 1711 var_finc_value.Bind(assembler->SmiToFloat64(value)); 1712 assembler->Goto(&do_finc); 1713 } 1714 } 1715 1716 assembler->Bind(&if_isnotsmi); 1717 { 1718 // Check if the value is a HeapNumber. 1719 Label if_valueisnumber(assembler), 1720 if_valuenotnumber(assembler, Label::kDeferred); 1721 Node* value_map = assembler->LoadMap(value); 1722 Node* number_map = assembler->HeapNumberMapConstant(); 1723 assembler->Branch(assembler->WordEqual(value_map, number_map), 1724 &if_valueisnumber, &if_valuenotnumber); 1725 1726 assembler->Bind(&if_valueisnumber); 1727 { 1728 // Load the HeapNumber value. 1729 var_finc_value.Bind(assembler->LoadHeapNumberValue(value)); 1730 assembler->Goto(&do_finc); 1731 } 1732 1733 assembler->Bind(&if_valuenotnumber); 1734 { 1735 // Convert to a Number first and try again. 1736 Callable callable = 1737 CodeFactory::NonNumberToNumber(assembler->isolate()); 1738 value_var.Bind(assembler->CallStub(callable, context, value)); 1739 assembler->Goto(&start); 1740 } 1741 } 1742 } 1743 1744 assembler->Bind(&do_finc); 1745 { 1746 Node* finc_value = var_finc_value.value(); 1747 Node* one = assembler->Float64Constant(1.0); 1748 Node* finc_result = assembler->Float64Add(finc_value, one); 1749 result_var.Bind(assembler->ChangeFloat64ToTagged(finc_result)); 1750 assembler->Goto(&end); 1751 } 1752 1753 assembler->Bind(&end); 1754 return result_var.value(); 1755 } 1756 1757 // static 1758 compiler::Node* DecStub::Generate(CodeStubAssembler* assembler, 1759 compiler::Node* value, 1760 compiler::Node* context) { 1761 typedef CodeStubAssembler::Label Label; 1762 typedef compiler::Node Node; 1763 typedef CodeStubAssembler::Variable Variable; 1764 1765 // Shared entry for floating point decrement. 1766 Label do_fdec(assembler), end(assembler); 1767 Variable var_fdec_value(assembler, MachineRepresentation::kFloat64); 1768 1769 // We might need to try again due to ToNumber conversion. 1770 Variable value_var(assembler, MachineRepresentation::kTagged); 1771 Variable result_var(assembler, MachineRepresentation::kTagged); 1772 Label start(assembler, &value_var); 1773 value_var.Bind(value); 1774 assembler->Goto(&start); 1775 assembler->Bind(&start); 1776 { 1777 value = value_var.value(); 1778 1779 Label if_issmi(assembler), if_isnotsmi(assembler); 1780 assembler->Branch(assembler->WordIsSmi(value), &if_issmi, &if_isnotsmi); 1781 1782 assembler->Bind(&if_issmi); 1783 { 1784 // Try fast Smi subtraction first. 1785 Node* one = assembler->SmiConstant(Smi::FromInt(1)); 1786 Node* pair = assembler->SmiSubWithOverflow(value, one); 1787 Node* overflow = assembler->Projection(1, pair); 1788 1789 // Check if the Smi subtraction overflowed. 1790 Label if_overflow(assembler), if_notoverflow(assembler); 1791 assembler->Branch(overflow, &if_overflow, &if_notoverflow); 1792 1793 assembler->Bind(&if_notoverflow); 1794 result_var.Bind(assembler->Projection(0, pair)); 1795 assembler->Goto(&end); 1796 1797 assembler->Bind(&if_overflow); 1798 { 1799 var_fdec_value.Bind(assembler->SmiToFloat64(value)); 1800 assembler->Goto(&do_fdec); 1801 } 1802 } 1803 1804 assembler->Bind(&if_isnotsmi); 1805 { 1806 // Check if the value is a HeapNumber. 1807 Label if_valueisnumber(assembler), 1808 if_valuenotnumber(assembler, Label::kDeferred); 1809 Node* value_map = assembler->LoadMap(value); 1810 Node* number_map = assembler->HeapNumberMapConstant(); 1811 assembler->Branch(assembler->WordEqual(value_map, number_map), 1812 &if_valueisnumber, &if_valuenotnumber); 1813 1814 assembler->Bind(&if_valueisnumber); 1815 { 1816 // Load the HeapNumber value. 1817 var_fdec_value.Bind(assembler->LoadHeapNumberValue(value)); 1818 assembler->Goto(&do_fdec); 1819 } 1820 1821 assembler->Bind(&if_valuenotnumber); 1822 { 1823 // Convert to a Number first and try again. 1824 Callable callable = 1825 CodeFactory::NonNumberToNumber(assembler->isolate()); 1826 value_var.Bind(assembler->CallStub(callable, context, value)); 1827 assembler->Goto(&start); 1828 } 1829 } 1830 } 1831 1832 assembler->Bind(&do_fdec); 1833 { 1834 Node* fdec_value = var_fdec_value.value(); 1835 Node* one = assembler->Float64Constant(1.0); 1836 Node* fdec_result = assembler->Float64Sub(fdec_value, one); 1837 result_var.Bind(assembler->ChangeFloat64ToTagged(fdec_result)); 1838 assembler->Goto(&end); 1839 } 1840 1841 assembler->Bind(&end); 1842 return result_var.value(); 1843 } 1844 1845 // static 1846 compiler::Node* InstanceOfStub::Generate(CodeStubAssembler* assembler, 1847 compiler::Node* object, 1848 compiler::Node* callable, 1849 compiler::Node* context) { 1850 typedef CodeStubAssembler::Label Label; 1851 typedef CodeStubAssembler::Variable Variable; 1852 1853 Label return_runtime(assembler, Label::kDeferred), end(assembler); 1854 Variable result(assembler, MachineRepresentation::kTagged); 1855 1856 // Check if no one installed @@hasInstance somewhere. 1857 assembler->GotoUnless( 1858 assembler->WordEqual( 1859 assembler->LoadObjectField( 1860 assembler->LoadRoot(Heap::kHasInstanceProtectorRootIndex), 1861 PropertyCell::kValueOffset), 1862 assembler->SmiConstant(Smi::FromInt(Isolate::kArrayProtectorValid))), 1863 &return_runtime); 1864 1865 // Check if {callable} is a valid receiver. 1866 assembler->GotoIf(assembler->WordIsSmi(callable), &return_runtime); 1867 assembler->GotoIf( 1868 assembler->Word32Equal( 1869 assembler->Word32And( 1870 assembler->LoadMapBitField(assembler->LoadMap(callable)), 1871 assembler->Int32Constant(1 << Map::kIsCallable)), 1872 assembler->Int32Constant(0)), 1873 &return_runtime); 1874 1875 // Use the inline OrdinaryHasInstance directly. 1876 result.Bind(assembler->OrdinaryHasInstance(context, callable, object)); 1877 assembler->Goto(&end); 1878 1879 // TODO(bmeurer): Use GetPropertyStub here once available. 1880 assembler->Bind(&return_runtime); 1881 { 1882 result.Bind(assembler->CallRuntime(Runtime::kInstanceOf, context, object, 1883 callable)); 1884 assembler->Goto(&end); 1885 } 1886 1887 assembler->Bind(&end); 1888 return result.value(); 1889 } 1890 1891 namespace { 1892 1893 enum RelationalComparisonMode { 1894 kLessThan, 1895 kLessThanOrEqual, 1896 kGreaterThan, 1897 kGreaterThanOrEqual 1898 }; 1899 1900 compiler::Node* GenerateAbstractRelationalComparison( 1901 CodeStubAssembler* assembler, RelationalComparisonMode mode, 1902 compiler::Node* lhs, compiler::Node* rhs, compiler::Node* context) { 1903 typedef CodeStubAssembler::Label Label; 1904 typedef compiler::Node Node; 1905 typedef CodeStubAssembler::Variable Variable; 1906 1907 Label return_true(assembler), return_false(assembler), end(assembler); 1908 Variable result(assembler, MachineRepresentation::kTagged); 1909 1910 // Shared entry for floating point comparison. 1911 Label do_fcmp(assembler); 1912 Variable var_fcmp_lhs(assembler, MachineRepresentation::kFloat64), 1913 var_fcmp_rhs(assembler, MachineRepresentation::kFloat64); 1914 1915 // We might need to loop several times due to ToPrimitive and/or ToNumber 1916 // conversions. 1917 Variable var_lhs(assembler, MachineRepresentation::kTagged), 1918 var_rhs(assembler, MachineRepresentation::kTagged); 1919 Variable* loop_vars[2] = {&var_lhs, &var_rhs}; 1920 Label loop(assembler, 2, loop_vars); 1921 var_lhs.Bind(lhs); 1922 var_rhs.Bind(rhs); 1923 assembler->Goto(&loop); 1924 assembler->Bind(&loop); 1925 { 1926 // Load the current {lhs} and {rhs} values. 1927 lhs = var_lhs.value(); 1928 rhs = var_rhs.value(); 1929 1930 // Check if the {lhs} is a Smi or a HeapObject. 1931 Label if_lhsissmi(assembler), if_lhsisnotsmi(assembler); 1932 assembler->Branch(assembler->WordIsSmi(lhs), &if_lhsissmi, &if_lhsisnotsmi); 1933 1934 assembler->Bind(&if_lhsissmi); 1935 { 1936 // Check if {rhs} is a Smi or a HeapObject. 1937 Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler); 1938 assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi, 1939 &if_rhsisnotsmi); 1940 1941 assembler->Bind(&if_rhsissmi); 1942 { 1943 // Both {lhs} and {rhs} are Smi, so just perform a fast Smi comparison. 1944 switch (mode) { 1945 case kLessThan: 1946 assembler->BranchIfSmiLessThan(lhs, rhs, &return_true, 1947 &return_false); 1948 break; 1949 case kLessThanOrEqual: 1950 assembler->BranchIfSmiLessThanOrEqual(lhs, rhs, &return_true, 1951 &return_false); 1952 break; 1953 case kGreaterThan: 1954 assembler->BranchIfSmiLessThan(rhs, lhs, &return_true, 1955 &return_false); 1956 break; 1957 case kGreaterThanOrEqual: 1958 assembler->BranchIfSmiLessThanOrEqual(rhs, lhs, &return_true, 1959 &return_false); 1960 break; 1961 } 1962 } 1963 1964 assembler->Bind(&if_rhsisnotsmi); 1965 { 1966 // Load the map of {rhs}. 1967 Node* rhs_map = assembler->LoadMap(rhs); 1968 1969 // Check if the {rhs} is a HeapNumber. 1970 Node* number_map = assembler->HeapNumberMapConstant(); 1971 Label if_rhsisnumber(assembler), 1972 if_rhsisnotnumber(assembler, Label::kDeferred); 1973 assembler->Branch(assembler->WordEqual(rhs_map, number_map), 1974 &if_rhsisnumber, &if_rhsisnotnumber); 1975 1976 assembler->Bind(&if_rhsisnumber); 1977 { 1978 // Convert the {lhs} and {rhs} to floating point values, and 1979 // perform a floating point comparison. 1980 var_fcmp_lhs.Bind(assembler->SmiToFloat64(lhs)); 1981 var_fcmp_rhs.Bind(assembler->LoadHeapNumberValue(rhs)); 1982 assembler->Goto(&do_fcmp); 1983 } 1984 1985 assembler->Bind(&if_rhsisnotnumber); 1986 { 1987 // Convert the {rhs} to a Number; we don't need to perform the 1988 // dedicated ToPrimitive(rhs, hint Number) operation, as the 1989 // ToNumber(rhs) will by itself already invoke ToPrimitive with 1990 // a Number hint. 1991 Callable callable = 1992 CodeFactory::NonNumberToNumber(assembler->isolate()); 1993 var_rhs.Bind(assembler->CallStub(callable, context, rhs)); 1994 assembler->Goto(&loop); 1995 } 1996 } 1997 } 1998 1999 assembler->Bind(&if_lhsisnotsmi); 2000 { 2001 // Load the HeapNumber map for later comparisons. 2002 Node* number_map = assembler->HeapNumberMapConstant(); 2003 2004 // Load the map of {lhs}. 2005 Node* lhs_map = assembler->LoadMap(lhs); 2006 2007 // Check if {rhs} is a Smi or a HeapObject. 2008 Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler); 2009 assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi, 2010 &if_rhsisnotsmi); 2011 2012 assembler->Bind(&if_rhsissmi); 2013 { 2014 // Check if the {lhs} is a HeapNumber. 2015 Label if_lhsisnumber(assembler), 2016 if_lhsisnotnumber(assembler, Label::kDeferred); 2017 assembler->Branch(assembler->WordEqual(lhs_map, number_map), 2018 &if_lhsisnumber, &if_lhsisnotnumber); 2019 2020 assembler->Bind(&if_lhsisnumber); 2021 { 2022 // Convert the {lhs} and {rhs} to floating point values, and 2023 // perform a floating point comparison. 2024 var_fcmp_lhs.Bind(assembler->LoadHeapNumberValue(lhs)); 2025 var_fcmp_rhs.Bind(assembler->SmiToFloat64(rhs)); 2026 assembler->Goto(&do_fcmp); 2027 } 2028 2029 assembler->Bind(&if_lhsisnotnumber); 2030 { 2031 // Convert the {lhs} to a Number; we don't need to perform the 2032 // dedicated ToPrimitive(lhs, hint Number) operation, as the 2033 // ToNumber(lhs) will by itself already invoke ToPrimitive with 2034 // a Number hint. 2035 Callable callable = 2036 CodeFactory::NonNumberToNumber(assembler->isolate()); 2037 var_lhs.Bind(assembler->CallStub(callable, context, lhs)); 2038 assembler->Goto(&loop); 2039 } 2040 } 2041 2042 assembler->Bind(&if_rhsisnotsmi); 2043 { 2044 // Load the map of {rhs}. 2045 Node* rhs_map = assembler->LoadMap(rhs); 2046 2047 // Check if {lhs} is a HeapNumber. 2048 Label if_lhsisnumber(assembler), if_lhsisnotnumber(assembler); 2049 assembler->Branch(assembler->WordEqual(lhs_map, number_map), 2050 &if_lhsisnumber, &if_lhsisnotnumber); 2051 2052 assembler->Bind(&if_lhsisnumber); 2053 { 2054 // Check if {rhs} is also a HeapNumber. 2055 Label if_rhsisnumber(assembler), 2056 if_rhsisnotnumber(assembler, Label::kDeferred); 2057 assembler->Branch(assembler->WordEqual(lhs_map, rhs_map), 2058 &if_rhsisnumber, &if_rhsisnotnumber); 2059 2060 assembler->Bind(&if_rhsisnumber); 2061 { 2062 // Convert the {lhs} and {rhs} to floating point values, and 2063 // perform a floating point comparison. 2064 var_fcmp_lhs.Bind(assembler->LoadHeapNumberValue(lhs)); 2065 var_fcmp_rhs.Bind(assembler->LoadHeapNumberValue(rhs)); 2066 assembler->Goto(&do_fcmp); 2067 } 2068 2069 assembler->Bind(&if_rhsisnotnumber); 2070 { 2071 // Convert the {rhs} to a Number; we don't need to perform 2072 // dedicated ToPrimitive(rhs, hint Number) operation, as the 2073 // ToNumber(rhs) will by itself already invoke ToPrimitive with 2074 // a Number hint. 2075 Callable callable = 2076 CodeFactory::NonNumberToNumber(assembler->isolate()); 2077 var_rhs.Bind(assembler->CallStub(callable, context, rhs)); 2078 assembler->Goto(&loop); 2079 } 2080 } 2081 2082 assembler->Bind(&if_lhsisnotnumber); 2083 { 2084 // Load the instance type of {lhs}. 2085 Node* lhs_instance_type = assembler->LoadMapInstanceType(lhs_map); 2086 2087 // Check if {lhs} is a String. 2088 Label if_lhsisstring(assembler), 2089 if_lhsisnotstring(assembler, Label::kDeferred); 2090 assembler->Branch(assembler->Int32LessThan( 2091 lhs_instance_type, 2092 assembler->Int32Constant(FIRST_NONSTRING_TYPE)), 2093 &if_lhsisstring, &if_lhsisnotstring); 2094 2095 assembler->Bind(&if_lhsisstring); 2096 { 2097 // Load the instance type of {rhs}. 2098 Node* rhs_instance_type = assembler->LoadMapInstanceType(rhs_map); 2099 2100 // Check if {rhs} is also a String. 2101 Label if_rhsisstring(assembler, Label::kDeferred), 2102 if_rhsisnotstring(assembler, Label::kDeferred); 2103 assembler->Branch(assembler->Int32LessThan( 2104 rhs_instance_type, assembler->Int32Constant( 2105 FIRST_NONSTRING_TYPE)), 2106 &if_rhsisstring, &if_rhsisnotstring); 2107 2108 assembler->Bind(&if_rhsisstring); 2109 { 2110 // Both {lhs} and {rhs} are strings. 2111 switch (mode) { 2112 case kLessThan: 2113 result.Bind(assembler->CallStub( 2114 CodeFactory::StringLessThan(assembler->isolate()), 2115 context, lhs, rhs)); 2116 assembler->Goto(&end); 2117 break; 2118 case kLessThanOrEqual: 2119 result.Bind(assembler->CallStub( 2120 CodeFactory::StringLessThanOrEqual(assembler->isolate()), 2121 context, lhs, rhs)); 2122 assembler->Goto(&end); 2123 break; 2124 case kGreaterThan: 2125 result.Bind(assembler->CallStub( 2126 CodeFactory::StringGreaterThan(assembler->isolate()), 2127 context, lhs, rhs)); 2128 assembler->Goto(&end); 2129 break; 2130 case kGreaterThanOrEqual: 2131 result.Bind( 2132 assembler->CallStub(CodeFactory::StringGreaterThanOrEqual( 2133 assembler->isolate()), 2134 context, lhs, rhs)); 2135 assembler->Goto(&end); 2136 break; 2137 } 2138 } 2139 2140 assembler->Bind(&if_rhsisnotstring); 2141 { 2142 // The {lhs} is a String, while {rhs} is neither a Number nor a 2143 // String, so we need to call ToPrimitive(rhs, hint Number) if 2144 // {rhs} is a receiver or ToNumber(lhs) and ToNumber(rhs) in the 2145 // other cases. 2146 STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE); 2147 Label if_rhsisreceiver(assembler, Label::kDeferred), 2148 if_rhsisnotreceiver(assembler, Label::kDeferred); 2149 assembler->Branch( 2150 assembler->Int32LessThanOrEqual( 2151 assembler->Int32Constant(FIRST_JS_RECEIVER_TYPE), 2152 rhs_instance_type), 2153 &if_rhsisreceiver, &if_rhsisnotreceiver); 2154 2155 assembler->Bind(&if_rhsisreceiver); 2156 { 2157 // Convert {rhs} to a primitive first passing Number hint. 2158 // TODO(bmeurer): Hook up ToPrimitiveStub here, once it's there. 2159 var_rhs.Bind(assembler->CallRuntime( 2160 Runtime::kToPrimitive_Number, context, rhs)); 2161 assembler->Goto(&loop); 2162 } 2163 2164 assembler->Bind(&if_rhsisnotreceiver); 2165 { 2166 // Convert both {lhs} and {rhs} to Number. 2167 Callable callable = CodeFactory::ToNumber(assembler->isolate()); 2168 var_lhs.Bind(assembler->CallStub(callable, context, lhs)); 2169 var_rhs.Bind(assembler->CallStub(callable, context, rhs)); 2170 assembler->Goto(&loop); 2171 } 2172 } 2173 } 2174 2175 assembler->Bind(&if_lhsisnotstring); 2176 { 2177 // The {lhs} is neither a Number nor a String, so we need to call 2178 // ToPrimitive(lhs, hint Number) if {lhs} is a receiver or 2179 // ToNumber(lhs) and ToNumber(rhs) in the other cases. 2180 STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE); 2181 Label if_lhsisreceiver(assembler, Label::kDeferred), 2182 if_lhsisnotreceiver(assembler, Label::kDeferred); 2183 assembler->Branch( 2184 assembler->Int32LessThanOrEqual( 2185 assembler->Int32Constant(FIRST_JS_RECEIVER_TYPE), 2186 lhs_instance_type), 2187 &if_lhsisreceiver, &if_lhsisnotreceiver); 2188 2189 assembler->Bind(&if_lhsisreceiver); 2190 { 2191 // Convert {lhs} to a primitive first passing Number hint. 2192 // TODO(bmeurer): Hook up ToPrimitiveStub here, once it's there. 2193 var_lhs.Bind(assembler->CallRuntime(Runtime::kToPrimitive_Number, 2194 context, lhs)); 2195 assembler->Goto(&loop); 2196 } 2197 2198 assembler->Bind(&if_lhsisnotreceiver); 2199 { 2200 // Convert both {lhs} and {rhs} to Number. 2201 Callable callable = CodeFactory::ToNumber(assembler->isolate()); 2202 var_lhs.Bind(assembler->CallStub(callable, context, lhs)); 2203 var_rhs.Bind(assembler->CallStub(callable, context, rhs)); 2204 assembler->Goto(&loop); 2205 } 2206 } 2207 } 2208 } 2209 } 2210 } 2211 2212 assembler->Bind(&do_fcmp); 2213 { 2214 // Load the {lhs} and {rhs} floating point values. 2215 Node* lhs = var_fcmp_lhs.value(); 2216 Node* rhs = var_fcmp_rhs.value(); 2217 2218 // Perform a fast floating point comparison. 2219 switch (mode) { 2220 case kLessThan: 2221 assembler->BranchIfFloat64LessThan(lhs, rhs, &return_true, 2222 &return_false); 2223 break; 2224 case kLessThanOrEqual: 2225 assembler->BranchIfFloat64LessThanOrEqual(lhs, rhs, &return_true, 2226 &return_false); 2227 break; 2228 case kGreaterThan: 2229 assembler->BranchIfFloat64GreaterThan(lhs, rhs, &return_true, 2230 &return_false); 2231 break; 2232 case kGreaterThanOrEqual: 2233 assembler->BranchIfFloat64GreaterThanOrEqual(lhs, rhs, &return_true, 2234 &return_false); 2235 break; 2236 } 2237 } 2238 2239 assembler->Bind(&return_true); 2240 { 2241 result.Bind(assembler->BooleanConstant(true)); 2242 assembler->Goto(&end); 2243 } 2244 2245 assembler->Bind(&return_false); 2246 { 2247 result.Bind(assembler->BooleanConstant(false)); 2248 assembler->Goto(&end); 2249 } 2250 2251 assembler->Bind(&end); 2252 return result.value(); 2253 } 2254 2255 enum ResultMode { kDontNegateResult, kNegateResult }; 2256 2257 void GenerateEqual_Same(CodeStubAssembler* assembler, compiler::Node* value, 2258 CodeStubAssembler::Label* if_equal, 2259 CodeStubAssembler::Label* if_notequal) { 2260 // In case of abstract or strict equality checks, we need additional checks 2261 // for NaN values because they are not considered equal, even if both the 2262 // left and the right hand side reference exactly the same value. 2263 // TODO(bmeurer): This seems to violate the SIMD.js specification, but it 2264 // seems to be what is tested in the current SIMD.js testsuite. 2265 2266 typedef CodeStubAssembler::Label Label; 2267 typedef compiler::Node Node; 2268 2269 // Check if {value} is a Smi or a HeapObject. 2270 Label if_valueissmi(assembler), if_valueisnotsmi(assembler); 2271 assembler->Branch(assembler->WordIsSmi(value), &if_valueissmi, 2272 &if_valueisnotsmi); 2273 2274 assembler->Bind(&if_valueisnotsmi); 2275 { 2276 // Load the map of {value}. 2277 Node* value_map = assembler->LoadMap(value); 2278 2279 // Check if {value} (and therefore {rhs}) is a HeapNumber. 2280 Node* number_map = assembler->HeapNumberMapConstant(); 2281 Label if_valueisnumber(assembler), if_valueisnotnumber(assembler); 2282 assembler->Branch(assembler->WordEqual(value_map, number_map), 2283 &if_valueisnumber, &if_valueisnotnumber); 2284 2285 assembler->Bind(&if_valueisnumber); 2286 { 2287 // Convert {value} (and therefore {rhs}) to floating point value. 2288 Node* value_value = assembler->LoadHeapNumberValue(value); 2289 2290 // Check if the HeapNumber value is a NaN. 2291 assembler->BranchIfFloat64IsNaN(value_value, if_notequal, if_equal); 2292 } 2293 2294 assembler->Bind(&if_valueisnotnumber); 2295 assembler->Goto(if_equal); 2296 } 2297 2298 assembler->Bind(&if_valueissmi); 2299 assembler->Goto(if_equal); 2300 } 2301 2302 void GenerateEqual_Simd128Value_HeapObject( 2303 CodeStubAssembler* assembler, compiler::Node* lhs, compiler::Node* lhs_map, 2304 compiler::Node* rhs, compiler::Node* rhs_map, 2305 CodeStubAssembler::Label* if_equal, CodeStubAssembler::Label* if_notequal) { 2306 typedef CodeStubAssembler::Label Label; 2307 typedef compiler::Node Node; 2308 2309 // Check if {lhs} and {rhs} have the same map. 2310 Label if_mapsame(assembler), if_mapnotsame(assembler); 2311 assembler->Branch(assembler->WordEqual(lhs_map, rhs_map), &if_mapsame, 2312 &if_mapnotsame); 2313 2314 assembler->Bind(&if_mapsame); 2315 { 2316 // Both {lhs} and {rhs} are Simd128Values with the same map, need special 2317 // handling for Float32x4 because of NaN comparisons. 2318 Label if_float32x4(assembler), if_notfloat32x4(assembler); 2319 Node* float32x4_map = 2320 assembler->HeapConstant(assembler->factory()->float32x4_map()); 2321 assembler->Branch(assembler->WordEqual(lhs_map, float32x4_map), 2322 &if_float32x4, &if_notfloat32x4); 2323 2324 assembler->Bind(&if_float32x4); 2325 { 2326 // Both {lhs} and {rhs} are Float32x4, compare the lanes individually 2327 // using a floating point comparison. 2328 for (int offset = Float32x4::kValueOffset - kHeapObjectTag; 2329 offset < Float32x4::kSize - kHeapObjectTag; 2330 offset += sizeof(float)) { 2331 // Load the floating point values for {lhs} and {rhs}. 2332 Node* lhs_value = assembler->Load(MachineType::Float32(), lhs, 2333 assembler->IntPtrConstant(offset)); 2334 Node* rhs_value = assembler->Load(MachineType::Float32(), rhs, 2335 assembler->IntPtrConstant(offset)); 2336 2337 // Perform a floating point comparison. 2338 Label if_valueequal(assembler), if_valuenotequal(assembler); 2339 assembler->Branch(assembler->Float32Equal(lhs_value, rhs_value), 2340 &if_valueequal, &if_valuenotequal); 2341 assembler->Bind(&if_valuenotequal); 2342 assembler->Goto(if_notequal); 2343 assembler->Bind(&if_valueequal); 2344 } 2345 2346 // All 4 lanes match, {lhs} and {rhs} considered equal. 2347 assembler->Goto(if_equal); 2348 } 2349 2350 assembler->Bind(&if_notfloat32x4); 2351 { 2352 // For other Simd128Values we just perform a bitwise comparison. 2353 for (int offset = Simd128Value::kValueOffset - kHeapObjectTag; 2354 offset < Simd128Value::kSize - kHeapObjectTag; 2355 offset += kPointerSize) { 2356 // Load the word values for {lhs} and {rhs}. 2357 Node* lhs_value = assembler->Load(MachineType::Pointer(), lhs, 2358 assembler->IntPtrConstant(offset)); 2359 Node* rhs_value = assembler->Load(MachineType::Pointer(), rhs, 2360 assembler->IntPtrConstant(offset)); 2361 2362 // Perform a bitwise word-comparison. 2363 Label if_valueequal(assembler), if_valuenotequal(assembler); 2364 assembler->Branch(assembler->WordEqual(lhs_value, rhs_value), 2365 &if_valueequal, &if_valuenotequal); 2366 assembler->Bind(&if_valuenotequal); 2367 assembler->Goto(if_notequal); 2368 assembler->Bind(&if_valueequal); 2369 } 2370 2371 // Bitwise comparison succeeded, {lhs} and {rhs} considered equal. 2372 assembler->Goto(if_equal); 2373 } 2374 } 2375 2376 assembler->Bind(&if_mapnotsame); 2377 assembler->Goto(if_notequal); 2378 } 2379 2380 // ES6 section 7.2.12 Abstract Equality Comparison 2381 compiler::Node* GenerateEqual(CodeStubAssembler* assembler, ResultMode mode, 2382 compiler::Node* lhs, compiler::Node* rhs, 2383 compiler::Node* context) { 2384 // This is a slightly optimized version of Object::Equals represented as 2385 // scheduled TurboFan graph utilizing the CodeStubAssembler. Whenever you 2386 // change something functionality wise in here, remember to update the 2387 // Object::Equals method as well. 2388 typedef CodeStubAssembler::Label Label; 2389 typedef compiler::Node Node; 2390 typedef CodeStubAssembler::Variable Variable; 2391 2392 Label if_equal(assembler), if_notequal(assembler), 2393 do_rhsstringtonumber(assembler, Label::kDeferred), end(assembler); 2394 Variable result(assembler, MachineRepresentation::kTagged); 2395 2396 // Shared entry for floating point comparison. 2397 Label do_fcmp(assembler); 2398 Variable var_fcmp_lhs(assembler, MachineRepresentation::kFloat64), 2399 var_fcmp_rhs(assembler, MachineRepresentation::kFloat64); 2400 2401 // We might need to loop several times due to ToPrimitive and/or ToNumber 2402 // conversions. 2403 Variable var_lhs(assembler, MachineRepresentation::kTagged), 2404 var_rhs(assembler, MachineRepresentation::kTagged); 2405 Variable* loop_vars[2] = {&var_lhs, &var_rhs}; 2406 Label loop(assembler, 2, loop_vars); 2407 var_lhs.Bind(lhs); 2408 var_rhs.Bind(rhs); 2409 assembler->Goto(&loop); 2410 assembler->Bind(&loop); 2411 { 2412 // Load the current {lhs} and {rhs} values. 2413 lhs = var_lhs.value(); 2414 rhs = var_rhs.value(); 2415 2416 // Check if {lhs} and {rhs} refer to the same object. 2417 Label if_same(assembler), if_notsame(assembler); 2418 assembler->Branch(assembler->WordEqual(lhs, rhs), &if_same, &if_notsame); 2419 2420 assembler->Bind(&if_same); 2421 { 2422 // The {lhs} and {rhs} reference the exact same value, yet we need special 2423 // treatment for HeapNumber, as NaN is not equal to NaN. 2424 GenerateEqual_Same(assembler, lhs, &if_equal, &if_notequal); 2425 } 2426 2427 assembler->Bind(&if_notsame); 2428 { 2429 // Check if {lhs} is a Smi or a HeapObject. 2430 Label if_lhsissmi(assembler), if_lhsisnotsmi(assembler); 2431 assembler->Branch(assembler->WordIsSmi(lhs), &if_lhsissmi, 2432 &if_lhsisnotsmi); 2433 2434 assembler->Bind(&if_lhsissmi); 2435 { 2436 // Check if {rhs} is a Smi or a HeapObject. 2437 Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler); 2438 assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi, 2439 &if_rhsisnotsmi); 2440 2441 assembler->Bind(&if_rhsissmi); 2442 // We have already checked for {lhs} and {rhs} being the same value, so 2443 // if both are Smis when we get here they must not be equal. 2444 assembler->Goto(&if_notequal); 2445 2446 assembler->Bind(&if_rhsisnotsmi); 2447 { 2448 // Load the map of {rhs}. 2449 Node* rhs_map = assembler->LoadMap(rhs); 2450 2451 // Check if {rhs} is a HeapNumber. 2452 Node* number_map = assembler->HeapNumberMapConstant(); 2453 Label if_rhsisnumber(assembler), if_rhsisnotnumber(assembler); 2454 assembler->Branch(assembler->WordEqual(rhs_map, number_map), 2455 &if_rhsisnumber, &if_rhsisnotnumber); 2456 2457 assembler->Bind(&if_rhsisnumber); 2458 { 2459 // Convert {lhs} and {rhs} to floating point values, and 2460 // perform a floating point comparison. 2461 var_fcmp_lhs.Bind(assembler->SmiToFloat64(lhs)); 2462 var_fcmp_rhs.Bind(assembler->LoadHeapNumberValue(rhs)); 2463 assembler->Goto(&do_fcmp); 2464 } 2465 2466 assembler->Bind(&if_rhsisnotnumber); 2467 { 2468 // Load the instance type of the {rhs}. 2469 Node* rhs_instance_type = assembler->LoadMapInstanceType(rhs_map); 2470 2471 // Check if the {rhs} is a String. 2472 Label if_rhsisstring(assembler, Label::kDeferred), 2473 if_rhsisnotstring(assembler); 2474 assembler->Branch(assembler->Int32LessThan( 2475 rhs_instance_type, assembler->Int32Constant( 2476 FIRST_NONSTRING_TYPE)), 2477 &if_rhsisstring, &if_rhsisnotstring); 2478 2479 assembler->Bind(&if_rhsisstring); 2480 { 2481 // The {rhs} is a String and the {lhs} is a Smi; we need 2482 // to convert the {rhs} to a Number and compare the output to 2483 // the Number on the {lhs}. 2484 assembler->Goto(&do_rhsstringtonumber); 2485 } 2486 2487 assembler->Bind(&if_rhsisnotstring); 2488 { 2489 // Check if the {rhs} is a Boolean. 2490 Node* boolean_map = assembler->BooleanMapConstant(); 2491 Label if_rhsisboolean(assembler), if_rhsisnotboolean(assembler); 2492 assembler->Branch(assembler->WordEqual(rhs_map, boolean_map), 2493 &if_rhsisboolean, &if_rhsisnotboolean); 2494 2495 assembler->Bind(&if_rhsisboolean); 2496 { 2497 // The {rhs} is a Boolean, load its number value. 2498 var_rhs.Bind( 2499 assembler->LoadObjectField(rhs, Oddball::kToNumberOffset)); 2500 assembler->Goto(&loop); 2501 } 2502 2503 assembler->Bind(&if_rhsisnotboolean); 2504 { 2505 // Check if the {rhs} is a Receiver. 2506 STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE); 2507 Label if_rhsisreceiver(assembler, Label::kDeferred), 2508 if_rhsisnotreceiver(assembler); 2509 assembler->Branch( 2510 assembler->Int32LessThanOrEqual( 2511 assembler->Int32Constant(FIRST_JS_RECEIVER_TYPE), 2512 rhs_instance_type), 2513 &if_rhsisreceiver, &if_rhsisnotreceiver); 2514 2515 assembler->Bind(&if_rhsisreceiver); 2516 { 2517 // Convert {rhs} to a primitive first (passing no hint). 2518 // TODO(bmeurer): Hook up ToPrimitiveStub here once it exists. 2519 var_rhs.Bind(assembler->CallRuntime(Runtime::kToPrimitive, 2520 context, rhs)); 2521 assembler->Goto(&loop); 2522 } 2523 2524 assembler->Bind(&if_rhsisnotreceiver); 2525 assembler->Goto(&if_notequal); 2526 } 2527 } 2528 } 2529 } 2530 } 2531 2532 assembler->Bind(&if_lhsisnotsmi); 2533 { 2534 // Check if {rhs} is a Smi or a HeapObject. 2535 Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler); 2536 assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi, 2537 &if_rhsisnotsmi); 2538 2539 assembler->Bind(&if_rhsissmi); 2540 { 2541 // The {lhs} is a HeapObject and the {rhs} is a Smi; swapping {lhs} 2542 // and {rhs} is not observable and doesn't matter for the result, so 2543 // we can just swap them and use the Smi handling above (for {lhs} 2544 // being a Smi). 2545 var_lhs.Bind(rhs); 2546 var_rhs.Bind(lhs); 2547 assembler->Goto(&loop); 2548 } 2549 2550 assembler->Bind(&if_rhsisnotsmi); 2551 { 2552 Label if_lhsisstring(assembler), if_lhsisnumber(assembler), 2553 if_lhsissymbol(assembler), if_lhsissimd128value(assembler), 2554 if_lhsisoddball(assembler), if_lhsisreceiver(assembler); 2555 2556 // Both {lhs} and {rhs} are HeapObjects, load their maps 2557 // and their instance types. 2558 Node* lhs_map = assembler->LoadMap(lhs); 2559 Node* rhs_map = assembler->LoadMap(rhs); 2560 2561 // Load the instance types of {lhs} and {rhs}. 2562 Node* lhs_instance_type = assembler->LoadMapInstanceType(lhs_map); 2563 Node* rhs_instance_type = assembler->LoadMapInstanceType(rhs_map); 2564 2565 // Dispatch based on the instance type of {lhs}. 2566 size_t const kNumCases = FIRST_NONSTRING_TYPE + 4; 2567 Label* case_labels[kNumCases]; 2568 int32_t case_values[kNumCases]; 2569 for (int32_t i = 0; i < FIRST_NONSTRING_TYPE; ++i) { 2570 case_labels[i] = new Label(assembler); 2571 case_values[i] = i; 2572 } 2573 case_labels[FIRST_NONSTRING_TYPE + 0] = &if_lhsisnumber; 2574 case_values[FIRST_NONSTRING_TYPE + 0] = HEAP_NUMBER_TYPE; 2575 case_labels[FIRST_NONSTRING_TYPE + 1] = &if_lhsissymbol; 2576 case_values[FIRST_NONSTRING_TYPE + 1] = SYMBOL_TYPE; 2577 case_labels[FIRST_NONSTRING_TYPE + 2] = &if_lhsissimd128value; 2578 case_values[FIRST_NONSTRING_TYPE + 2] = SIMD128_VALUE_TYPE; 2579 case_labels[FIRST_NONSTRING_TYPE + 3] = &if_lhsisoddball; 2580 case_values[FIRST_NONSTRING_TYPE + 3] = ODDBALL_TYPE; 2581 assembler->Switch(lhs_instance_type, &if_lhsisreceiver, case_values, 2582 case_labels, arraysize(case_values)); 2583 for (int32_t i = 0; i < FIRST_NONSTRING_TYPE; ++i) { 2584 assembler->Bind(case_labels[i]); 2585 assembler->Goto(&if_lhsisstring); 2586 delete case_labels[i]; 2587 } 2588 2589 assembler->Bind(&if_lhsisstring); 2590 { 2591 // Check if {rhs} is also a String. 2592 Label if_rhsisstring(assembler, Label::kDeferred), 2593 if_rhsisnotstring(assembler); 2594 assembler->Branch(assembler->Int32LessThan( 2595 rhs_instance_type, assembler->Int32Constant( 2596 FIRST_NONSTRING_TYPE)), 2597 &if_rhsisstring, &if_rhsisnotstring); 2598 2599 assembler->Bind(&if_rhsisstring); 2600 { 2601 // Both {lhs} and {rhs} are of type String, just do the 2602 // string comparison then. 2603 Callable callable = 2604 (mode == kDontNegateResult) 2605 ? CodeFactory::StringEqual(assembler->isolate()) 2606 : CodeFactory::StringNotEqual(assembler->isolate()); 2607 result.Bind(assembler->CallStub(callable, context, lhs, rhs)); 2608 assembler->Goto(&end); 2609 } 2610 2611 assembler->Bind(&if_rhsisnotstring); 2612 { 2613 // The {lhs} is a String and the {rhs} is some other HeapObject. 2614 // Swapping {lhs} and {rhs} is not observable and doesn't matter 2615 // for the result, so we can just swap them and use the String 2616 // handling below (for {rhs} being a String). 2617 var_lhs.Bind(rhs); 2618 var_rhs.Bind(lhs); 2619 assembler->Goto(&loop); 2620 } 2621 } 2622 2623 assembler->Bind(&if_lhsisnumber); 2624 { 2625 // Check if {rhs} is also a HeapNumber. 2626 Label if_rhsisnumber(assembler), if_rhsisnotnumber(assembler); 2627 assembler->Branch( 2628 assembler->Word32Equal(lhs_instance_type, rhs_instance_type), 2629 &if_rhsisnumber, &if_rhsisnotnumber); 2630 2631 assembler->Bind(&if_rhsisnumber); 2632 { 2633 // Convert {lhs} and {rhs} to floating point values, and 2634 // perform a floating point comparison. 2635 var_fcmp_lhs.Bind(assembler->LoadHeapNumberValue(lhs)); 2636 var_fcmp_rhs.Bind(assembler->LoadHeapNumberValue(rhs)); 2637 assembler->Goto(&do_fcmp); 2638 } 2639 2640 assembler->Bind(&if_rhsisnotnumber); 2641 { 2642 // The {lhs} is a Number, the {rhs} is some other HeapObject. 2643 Label if_rhsisstring(assembler, Label::kDeferred), 2644 if_rhsisnotstring(assembler); 2645 assembler->Branch( 2646 assembler->Int32LessThan( 2647 rhs_instance_type, 2648 assembler->Int32Constant(FIRST_NONSTRING_TYPE)), 2649 &if_rhsisstring, &if_rhsisnotstring); 2650 2651 assembler->Bind(&if_rhsisstring); 2652 { 2653 // The {rhs} is a String and the {lhs} is a HeapNumber; we need 2654 // to convert the {rhs} to a Number and compare the output to 2655 // the Number on the {lhs}. 2656 assembler->Goto(&do_rhsstringtonumber); 2657 } 2658 2659 assembler->Bind(&if_rhsisnotstring); 2660 { 2661 // Check if the {rhs} is a JSReceiver. 2662 Label if_rhsisreceiver(assembler), 2663 if_rhsisnotreceiver(assembler); 2664 STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE); 2665 assembler->Branch( 2666 assembler->Int32LessThanOrEqual( 2667 assembler->Int32Constant(FIRST_JS_RECEIVER_TYPE), 2668 rhs_instance_type), 2669 &if_rhsisreceiver, &if_rhsisnotreceiver); 2670 2671 assembler->Bind(&if_rhsisreceiver); 2672 { 2673 // The {lhs} is a Primitive and the {rhs} is a JSReceiver. 2674 // Swapping {lhs} and {rhs} is not observable and doesn't 2675 // matter for the result, so we can just swap them and use 2676 // the JSReceiver handling below (for {lhs} being a 2677 // JSReceiver). 2678 var_lhs.Bind(rhs); 2679 var_rhs.Bind(lhs); 2680 assembler->Goto(&loop); 2681 } 2682 2683 assembler->Bind(&if_rhsisnotreceiver); 2684 { 2685 // Check if {rhs} is a Boolean. 2686 Label if_rhsisboolean(assembler), 2687 if_rhsisnotboolean(assembler); 2688 Node* boolean_map = assembler->BooleanMapConstant(); 2689 assembler->Branch(assembler->WordEqual(rhs_map, boolean_map), 2690 &if_rhsisboolean, &if_rhsisnotboolean); 2691 2692 assembler->Bind(&if_rhsisboolean); 2693 { 2694 // The {rhs} is a Boolean, convert it to a Smi first. 2695 var_rhs.Bind(assembler->LoadObjectField( 2696 rhs, Oddball::kToNumberOffset)); 2697 assembler->Goto(&loop); 2698 } 2699 2700 assembler->Bind(&if_rhsisnotboolean); 2701 assembler->Goto(&if_notequal); 2702 } 2703 } 2704 } 2705 } 2706 2707 assembler->Bind(&if_lhsisoddball); 2708 { 2709 // The {lhs} is an Oddball and {rhs} is some other HeapObject. 2710 Label if_lhsisboolean(assembler), if_lhsisnotboolean(assembler); 2711 Node* boolean_map = assembler->BooleanMapConstant(); 2712 assembler->Branch(assembler->WordEqual(lhs_map, boolean_map), 2713 &if_lhsisboolean, &if_lhsisnotboolean); 2714 2715 assembler->Bind(&if_lhsisboolean); 2716 { 2717 // The {lhs} is a Boolean, check if {rhs} is also a Boolean. 2718 Label if_rhsisboolean(assembler), if_rhsisnotboolean(assembler); 2719 assembler->Branch(assembler->WordEqual(rhs_map, boolean_map), 2720 &if_rhsisboolean, &if_rhsisnotboolean); 2721 2722 assembler->Bind(&if_rhsisboolean); 2723 { 2724 // Both {lhs} and {rhs} are distinct Boolean values. 2725 assembler->Goto(&if_notequal); 2726 } 2727 2728 assembler->Bind(&if_rhsisnotboolean); 2729 { 2730 // Convert the {lhs} to a Number first. 2731 var_lhs.Bind( 2732 assembler->LoadObjectField(lhs, Oddball::kToNumberOffset)); 2733 assembler->Goto(&loop); 2734 } 2735 } 2736 2737 assembler->Bind(&if_lhsisnotboolean); 2738 { 2739 // The {lhs} is either Null or Undefined; check if the {rhs} is 2740 // undetectable (i.e. either also Null or Undefined or some 2741 // undetectable JSReceiver). 2742 Node* rhs_bitfield = assembler->LoadMapBitField(rhs_map); 2743 assembler->BranchIfWord32Equal( 2744 assembler->Word32And( 2745 rhs_bitfield, 2746 assembler->Int32Constant(1 << Map::kIsUndetectable)), 2747 assembler->Int32Constant(0), &if_notequal, &if_equal); 2748 } 2749 } 2750 2751 assembler->Bind(&if_lhsissymbol); 2752 { 2753 // Check if the {rhs} is a JSReceiver. 2754 Label if_rhsisreceiver(assembler), if_rhsisnotreceiver(assembler); 2755 STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE); 2756 assembler->Branch( 2757 assembler->Int32LessThanOrEqual( 2758 assembler->Int32Constant(FIRST_JS_RECEIVER_TYPE), 2759 rhs_instance_type), 2760 &if_rhsisreceiver, &if_rhsisnotreceiver); 2761 2762 assembler->Bind(&if_rhsisreceiver); 2763 { 2764 // The {lhs} is a Primitive and the {rhs} is a JSReceiver. 2765 // Swapping {lhs} and {rhs} is not observable and doesn't 2766 // matter for the result, so we can just swap them and use 2767 // the JSReceiver handling below (for {lhs} being a JSReceiver). 2768 var_lhs.Bind(rhs); 2769 var_rhs.Bind(lhs); 2770 assembler->Goto(&loop); 2771 } 2772 2773 assembler->Bind(&if_rhsisnotreceiver); 2774 { 2775 // The {rhs} is not a JSReceiver and also not the same Symbol 2776 // as the {lhs}, so this is equality check is considered false. 2777 assembler->Goto(&if_notequal); 2778 } 2779 } 2780 2781 assembler->Bind(&if_lhsissimd128value); 2782 { 2783 // Check if the {rhs} is also a Simd128Value. 2784 Label if_rhsissimd128value(assembler), 2785 if_rhsisnotsimd128value(assembler); 2786 assembler->Branch( 2787 assembler->Word32Equal(lhs_instance_type, rhs_instance_type), 2788 &if_rhsissimd128value, &if_rhsisnotsimd128value); 2789 2790 assembler->Bind(&if_rhsissimd128value); 2791 { 2792 // Both {lhs} and {rhs} is a Simd128Value. 2793 GenerateEqual_Simd128Value_HeapObject(assembler, lhs, lhs_map, 2794 rhs, rhs_map, &if_equal, 2795 &if_notequal); 2796 } 2797 2798 assembler->Bind(&if_rhsisnotsimd128value); 2799 { 2800 // Check if the {rhs} is a JSReceiver. 2801 Label if_rhsisreceiver(assembler), if_rhsisnotreceiver(assembler); 2802 STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE); 2803 assembler->Branch( 2804 assembler->Int32LessThanOrEqual( 2805 assembler->Int32Constant(FIRST_JS_RECEIVER_TYPE), 2806 rhs_instance_type), 2807 &if_rhsisreceiver, &if_rhsisnotreceiver); 2808 2809 assembler->Bind(&if_rhsisreceiver); 2810 { 2811 // The {lhs} is a Primitive and the {rhs} is a JSReceiver. 2812 // Swapping {lhs} and {rhs} is not observable and doesn't 2813 // matter for the result, so we can just swap them and use 2814 // the JSReceiver handling below (for {lhs} being a JSReceiver). 2815 var_lhs.Bind(rhs); 2816 var_rhs.Bind(lhs); 2817 assembler->Goto(&loop); 2818 } 2819 2820 assembler->Bind(&if_rhsisnotreceiver); 2821 { 2822 // The {rhs} is some other Primitive. 2823 assembler->Goto(&if_notequal); 2824 } 2825 } 2826 } 2827 2828 assembler->Bind(&if_lhsisreceiver); 2829 { 2830 // Check if the {rhs} is also a JSReceiver. 2831 Label if_rhsisreceiver(assembler), if_rhsisnotreceiver(assembler); 2832 STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE); 2833 assembler->Branch( 2834 assembler->Int32LessThanOrEqual( 2835 assembler->Int32Constant(FIRST_JS_RECEIVER_TYPE), 2836 rhs_instance_type), 2837 &if_rhsisreceiver, &if_rhsisnotreceiver); 2838 2839 assembler->Bind(&if_rhsisreceiver); 2840 { 2841 // Both {lhs} and {rhs} are different JSReceiver references, so 2842 // this cannot be considered equal. 2843 assembler->Goto(&if_notequal); 2844 } 2845 2846 assembler->Bind(&if_rhsisnotreceiver); 2847 { 2848 // Check if {rhs} is Null or Undefined (an undetectable check 2849 // is sufficient here, since we already know that {rhs} is not 2850 // a JSReceiver). 2851 Label if_rhsisundetectable(assembler), 2852 if_rhsisnotundetectable(assembler, Label::kDeferred); 2853 Node* rhs_bitfield = assembler->LoadMapBitField(rhs_map); 2854 assembler->BranchIfWord32Equal( 2855 assembler->Word32And( 2856 rhs_bitfield, 2857 assembler->Int32Constant(1 << Map::kIsUndetectable)), 2858 assembler->Int32Constant(0), &if_rhsisnotundetectable, 2859 &if_rhsisundetectable); 2860 2861 assembler->Bind(&if_rhsisundetectable); 2862 { 2863 // Check if {lhs} is an undetectable JSReceiver. 2864 Node* lhs_bitfield = assembler->LoadMapBitField(lhs_map); 2865 assembler->BranchIfWord32Equal( 2866 assembler->Word32And( 2867 lhs_bitfield, 2868 assembler->Int32Constant(1 << Map::kIsUndetectable)), 2869 assembler->Int32Constant(0), &if_notequal, &if_equal); 2870 } 2871 2872 assembler->Bind(&if_rhsisnotundetectable); 2873 { 2874 // The {rhs} is some Primitive different from Null and 2875 // Undefined, need to convert {lhs} to Primitive first. 2876 // TODO(bmeurer): Hook up ToPrimitiveStub here once it exists. 2877 var_lhs.Bind(assembler->CallRuntime(Runtime::kToPrimitive, 2878 context, lhs)); 2879 assembler->Goto(&loop); 2880 } 2881 } 2882 } 2883 } 2884 } 2885 } 2886 2887 assembler->Bind(&do_rhsstringtonumber); 2888 { 2889 Callable callable = CodeFactory::StringToNumber(assembler->isolate()); 2890 var_rhs.Bind(assembler->CallStub(callable, context, rhs)); 2891 assembler->Goto(&loop); 2892 } 2893 } 2894 2895 assembler->Bind(&do_fcmp); 2896 { 2897 // Load the {lhs} and {rhs} floating point values. 2898 Node* lhs = var_fcmp_lhs.value(); 2899 Node* rhs = var_fcmp_rhs.value(); 2900 2901 // Perform a fast floating point comparison. 2902 assembler->BranchIfFloat64Equal(lhs, rhs, &if_equal, &if_notequal); 2903 } 2904 2905 assembler->Bind(&if_equal); 2906 { 2907 result.Bind(assembler->BooleanConstant(mode == kDontNegateResult)); 2908 assembler->Goto(&end); 2909 } 2910 2911 assembler->Bind(&if_notequal); 2912 { 2913 result.Bind(assembler->BooleanConstant(mode == kNegateResult)); 2914 assembler->Goto(&end); 2915 } 2916 2917 assembler->Bind(&end); 2918 return result.value(); 2919 } 2920 2921 compiler::Node* GenerateStrictEqual(CodeStubAssembler* assembler, 2922 ResultMode mode, compiler::Node* lhs, 2923 compiler::Node* rhs, 2924 compiler::Node* context) { 2925 // Here's pseudo-code for the algorithm below in case of kDontNegateResult 2926 // mode; for kNegateResult mode we properly negate the result. 2927 // 2928 // if (lhs == rhs) { 2929 // if (lhs->IsHeapNumber()) return HeapNumber::cast(lhs)->value() != NaN; 2930 // return true; 2931 // } 2932 // if (!lhs->IsSmi()) { 2933 // if (lhs->IsHeapNumber()) { 2934 // if (rhs->IsSmi()) { 2935 // return Smi::cast(rhs)->value() == HeapNumber::cast(lhs)->value(); 2936 // } else if (rhs->IsHeapNumber()) { 2937 // return HeapNumber::cast(rhs)->value() == 2938 // HeapNumber::cast(lhs)->value(); 2939 // } else { 2940 // return false; 2941 // } 2942 // } else { 2943 // if (rhs->IsSmi()) { 2944 // return false; 2945 // } else { 2946 // if (lhs->IsString()) { 2947 // if (rhs->IsString()) { 2948 // return %StringEqual(lhs, rhs); 2949 // } else { 2950 // return false; 2951 // } 2952 // } else if (lhs->IsSimd128()) { 2953 // if (rhs->IsSimd128()) { 2954 // return %StrictEqual(lhs, rhs); 2955 // } 2956 // } else { 2957 // return false; 2958 // } 2959 // } 2960 // } 2961 // } else { 2962 // if (rhs->IsSmi()) { 2963 // return false; 2964 // } else { 2965 // if (rhs->IsHeapNumber()) { 2966 // return Smi::cast(lhs)->value() == HeapNumber::cast(rhs)->value(); 2967 // } else { 2968 // return false; 2969 // } 2970 // } 2971 // } 2972 2973 typedef CodeStubAssembler::Label Label; 2974 typedef CodeStubAssembler::Variable Variable; 2975 typedef compiler::Node Node; 2976 2977 Label if_equal(assembler), if_notequal(assembler), end(assembler); 2978 Variable result(assembler, MachineRepresentation::kTagged); 2979 2980 // Check if {lhs} and {rhs} refer to the same object. 2981 Label if_same(assembler), if_notsame(assembler); 2982 assembler->Branch(assembler->WordEqual(lhs, rhs), &if_same, &if_notsame); 2983 2984 assembler->Bind(&if_same); 2985 { 2986 // The {lhs} and {rhs} reference the exact same value, yet we need special 2987 // treatment for HeapNumber, as NaN is not equal to NaN. 2988 GenerateEqual_Same(assembler, lhs, &if_equal, &if_notequal); 2989 } 2990 2991 assembler->Bind(&if_notsame); 2992 { 2993 // The {lhs} and {rhs} reference different objects, yet for Smi, HeapNumber, 2994 // String and Simd128Value they can still be considered equal. 2995 Node* number_map = assembler->HeapNumberMapConstant(); 2996 2997 // Check if {lhs} is a Smi or a HeapObject. 2998 Label if_lhsissmi(assembler), if_lhsisnotsmi(assembler); 2999 assembler->Branch(assembler->WordIsSmi(lhs), &if_lhsissmi, &if_lhsisnotsmi); 3000 3001 assembler->Bind(&if_lhsisnotsmi); 3002 { 3003 // Load the map of {lhs}. 3004 Node* lhs_map = assembler->LoadMap(lhs); 3005 3006 // Check if {lhs} is a HeapNumber. 3007 Label if_lhsisnumber(assembler), if_lhsisnotnumber(assembler); 3008 assembler->Branch(assembler->WordEqual(lhs_map, number_map), 3009 &if_lhsisnumber, &if_lhsisnotnumber); 3010 3011 assembler->Bind(&if_lhsisnumber); 3012 { 3013 // Check if {rhs} is a Smi or a HeapObject. 3014 Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler); 3015 assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi, 3016 &if_rhsisnotsmi); 3017 3018 assembler->Bind(&if_rhsissmi); 3019 { 3020 // Convert {lhs} and {rhs} to floating point values. 3021 Node* lhs_value = assembler->LoadHeapNumberValue(lhs); 3022 Node* rhs_value = assembler->SmiToFloat64(rhs); 3023 3024 // Perform a floating point comparison of {lhs} and {rhs}. 3025 assembler->BranchIfFloat64Equal(lhs_value, rhs_value, &if_equal, 3026 &if_notequal); 3027 } 3028 3029 assembler->Bind(&if_rhsisnotsmi); 3030 { 3031 // Load the map of {rhs}. 3032 Node* rhs_map = assembler->LoadMap(rhs); 3033 3034 // Check if {rhs} is also a HeapNumber. 3035 Label if_rhsisnumber(assembler), if_rhsisnotnumber(assembler); 3036 assembler->Branch(assembler->WordEqual(rhs_map, number_map), 3037 &if_rhsisnumber, &if_rhsisnotnumber); 3038 3039 assembler->Bind(&if_rhsisnumber); 3040 { 3041 // Convert {lhs} and {rhs} to floating point values. 3042 Node* lhs_value = assembler->LoadHeapNumberValue(lhs); 3043 Node* rhs_value = assembler->LoadHeapNumberValue(rhs); 3044 3045 // Perform a floating point comparison of {lhs} and {rhs}. 3046 assembler->BranchIfFloat64Equal(lhs_value, rhs_value, &if_equal, 3047 &if_notequal); 3048 } 3049 3050 assembler->Bind(&if_rhsisnotnumber); 3051 assembler->Goto(&if_notequal); 3052 } 3053 } 3054 3055 assembler->Bind(&if_lhsisnotnumber); 3056 { 3057 // Check if {rhs} is a Smi or a HeapObject. 3058 Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler); 3059 assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi, 3060 &if_rhsisnotsmi); 3061 3062 assembler->Bind(&if_rhsissmi); 3063 assembler->Goto(&if_notequal); 3064 3065 assembler->Bind(&if_rhsisnotsmi); 3066 { 3067 // Load the instance type of {lhs}. 3068 Node* lhs_instance_type = assembler->LoadMapInstanceType(lhs_map); 3069 3070 // Check if {lhs} is a String. 3071 Label if_lhsisstring(assembler), if_lhsisnotstring(assembler); 3072 assembler->Branch(assembler->Int32LessThan( 3073 lhs_instance_type, 3074 assembler->Int32Constant(FIRST_NONSTRING_TYPE)), 3075 &if_lhsisstring, &if_lhsisnotstring); 3076 3077 assembler->Bind(&if_lhsisstring); 3078 { 3079 // Load the instance type of {rhs}. 3080 Node* rhs_instance_type = assembler->LoadInstanceType(rhs); 3081 3082 // Check if {rhs} is also a String. 3083 Label if_rhsisstring(assembler, Label::kDeferred), 3084 if_rhsisnotstring(assembler); 3085 assembler->Branch(assembler->Int32LessThan( 3086 rhs_instance_type, assembler->Int32Constant( 3087 FIRST_NONSTRING_TYPE)), 3088 &if_rhsisstring, &if_rhsisnotstring); 3089 3090 assembler->Bind(&if_rhsisstring); 3091 { 3092 Callable callable = 3093 (mode == kDontNegateResult) 3094 ? CodeFactory::StringEqual(assembler->isolate()) 3095 : CodeFactory::StringNotEqual(assembler->isolate()); 3096 result.Bind(assembler->CallStub(callable, context, lhs, rhs)); 3097 assembler->Goto(&end); 3098 } 3099 3100 assembler->Bind(&if_rhsisnotstring); 3101 assembler->Goto(&if_notequal); 3102 } 3103 3104 assembler->Bind(&if_lhsisnotstring); 3105 { 3106 // Check if {lhs} is a Simd128Value. 3107 Label if_lhsissimd128value(assembler), 3108 if_lhsisnotsimd128value(assembler); 3109 assembler->Branch(assembler->Word32Equal( 3110 lhs_instance_type, 3111 assembler->Int32Constant(SIMD128_VALUE_TYPE)), 3112 &if_lhsissimd128value, &if_lhsisnotsimd128value); 3113 3114 assembler->Bind(&if_lhsissimd128value); 3115 { 3116 // Load the map of {rhs}. 3117 Node* rhs_map = assembler->LoadMap(rhs); 3118 3119 // Check if {rhs} is also a Simd128Value that is equal to {lhs}. 3120 GenerateEqual_Simd128Value_HeapObject(assembler, lhs, lhs_map, 3121 rhs, rhs_map, &if_equal, 3122 &if_notequal); 3123 } 3124 3125 assembler->Bind(&if_lhsisnotsimd128value); 3126 assembler->Goto(&if_notequal); 3127 } 3128 } 3129 } 3130 } 3131 3132 assembler->Bind(&if_lhsissmi); 3133 { 3134 // We already know that {lhs} and {rhs} are not reference equal, and {lhs} 3135 // is a Smi; so {lhs} and {rhs} can only be strictly equal if {rhs} is a 3136 // HeapNumber with an equal floating point value. 3137 3138 // Check if {rhs} is a Smi or a HeapObject. 3139 Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler); 3140 assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi, 3141 &if_rhsisnotsmi); 3142 3143 assembler->Bind(&if_rhsissmi); 3144 assembler->Goto(&if_notequal); 3145 3146 assembler->Bind(&if_rhsisnotsmi); 3147 { 3148 // Load the map of the {rhs}. 3149 Node* rhs_map = assembler->LoadMap(rhs); 3150 3151 // The {rhs} could be a HeapNumber with the same value as {lhs}. 3152 Label if_rhsisnumber(assembler), if_rhsisnotnumber(assembler); 3153 assembler->Branch(assembler->WordEqual(rhs_map, number_map), 3154 &if_rhsisnumber, &if_rhsisnotnumber); 3155 3156 assembler->Bind(&if_rhsisnumber); 3157 { 3158 // Convert {lhs} and {rhs} to floating point values. 3159 Node* lhs_value = assembler->SmiToFloat64(lhs); 3160 Node* rhs_value = assembler->LoadHeapNumberValue(rhs); 3161 3162 // Perform a floating point comparison of {lhs} and {rhs}. 3163 assembler->BranchIfFloat64Equal(lhs_value, rhs_value, &if_equal, 3164 &if_notequal); 3165 } 3166 3167 assembler->Bind(&if_rhsisnotnumber); 3168 assembler->Goto(&if_notequal); 3169 } 3170 } 3171 } 3172 3173 assembler->Bind(&if_equal); 3174 { 3175 result.Bind(assembler->BooleanConstant(mode == kDontNegateResult)); 3176 assembler->Goto(&end); 3177 } 3178 3179 assembler->Bind(&if_notequal); 3180 { 3181 result.Bind(assembler->BooleanConstant(mode == kNegateResult)); 3182 assembler->Goto(&end); 3183 } 3184 3185 assembler->Bind(&end); 3186 return result.value(); 3187 } 3188 3189 void GenerateStringRelationalComparison(CodeStubAssembler* assembler, 3190 RelationalComparisonMode mode) { 3191 typedef CodeStubAssembler::Label Label; 3192 typedef compiler::Node Node; 3193 typedef CodeStubAssembler::Variable Variable; 3194 3195 Node* lhs = assembler->Parameter(0); 3196 Node* rhs = assembler->Parameter(1); 3197 Node* context = assembler->Parameter(2); 3198 3199 Label if_less(assembler), if_equal(assembler), if_greater(assembler); 3200 3201 // Fast check to see if {lhs} and {rhs} refer to the same String object. 3202 Label if_same(assembler), if_notsame(assembler); 3203 assembler->Branch(assembler->WordEqual(lhs, rhs), &if_same, &if_notsame); 3204 3205 assembler->Bind(&if_same); 3206 assembler->Goto(&if_equal); 3207 3208 assembler->Bind(&if_notsame); 3209 { 3210 // Load instance types of {lhs} and {rhs}. 3211 Node* lhs_instance_type = assembler->LoadInstanceType(lhs); 3212 Node* rhs_instance_type = assembler->LoadInstanceType(rhs); 3213 3214 // Combine the instance types into a single 16-bit value, so we can check 3215 // both of them at once. 3216 Node* both_instance_types = assembler->Word32Or( 3217 lhs_instance_type, 3218 assembler->Word32Shl(rhs_instance_type, assembler->Int32Constant(8))); 3219 3220 // Check that both {lhs} and {rhs} are flat one-byte strings. 3221 int const kBothSeqOneByteStringMask = 3222 kStringEncodingMask | kStringRepresentationMask | 3223 ((kStringEncodingMask | kStringRepresentationMask) << 8); 3224 int const kBothSeqOneByteStringTag = 3225 kOneByteStringTag | kSeqStringTag | 3226 ((kOneByteStringTag | kSeqStringTag) << 8); 3227 Label if_bothonebyteseqstrings(assembler), 3228 if_notbothonebyteseqstrings(assembler); 3229 assembler->Branch(assembler->Word32Equal( 3230 assembler->Word32And(both_instance_types, 3231 assembler->Int32Constant( 3232 kBothSeqOneByteStringMask)), 3233 assembler->Int32Constant(kBothSeqOneByteStringTag)), 3234 &if_bothonebyteseqstrings, &if_notbothonebyteseqstrings); 3235 3236 assembler->Bind(&if_bothonebyteseqstrings); 3237 { 3238 // Load the length of {lhs} and {rhs}. 3239 Node* lhs_length = assembler->LoadObjectField(lhs, String::kLengthOffset); 3240 Node* rhs_length = assembler->LoadObjectField(rhs, String::kLengthOffset); 3241 3242 // Determine the minimum length. 3243 Node* length = assembler->SmiMin(lhs_length, rhs_length); 3244 3245 // Compute the effective offset of the first character. 3246 Node* begin = assembler->IntPtrConstant(SeqOneByteString::kHeaderSize - 3247 kHeapObjectTag); 3248 3249 // Compute the first offset after the string from the length. 3250 Node* end = assembler->IntPtrAdd(begin, assembler->SmiUntag(length)); 3251 3252 // Loop over the {lhs} and {rhs} strings to see if they are equal. 3253 Variable var_offset(assembler, MachineType::PointerRepresentation()); 3254 Label loop(assembler, &var_offset); 3255 var_offset.Bind(begin); 3256 assembler->Goto(&loop); 3257 assembler->Bind(&loop); 3258 { 3259 // Check if {offset} equals {end}. 3260 Node* offset = var_offset.value(); 3261 Label if_done(assembler), if_notdone(assembler); 3262 assembler->Branch(assembler->WordEqual(offset, end), &if_done, 3263 &if_notdone); 3264 3265 assembler->Bind(&if_notdone); 3266 { 3267 // Load the next characters from {lhs} and {rhs}. 3268 Node* lhs_value = assembler->Load(MachineType::Uint8(), lhs, offset); 3269 Node* rhs_value = assembler->Load(MachineType::Uint8(), rhs, offset); 3270 3271 // Check if the characters match. 3272 Label if_valueissame(assembler), if_valueisnotsame(assembler); 3273 assembler->Branch(assembler->Word32Equal(lhs_value, rhs_value), 3274 &if_valueissame, &if_valueisnotsame); 3275 3276 assembler->Bind(&if_valueissame); 3277 { 3278 // Advance to next character. 3279 var_offset.Bind( 3280 assembler->IntPtrAdd(offset, assembler->IntPtrConstant(1))); 3281 } 3282 assembler->Goto(&loop); 3283 3284 assembler->Bind(&if_valueisnotsame); 3285 assembler->BranchIf(assembler->Uint32LessThan(lhs_value, rhs_value), 3286 &if_less, &if_greater); 3287 } 3288 3289 assembler->Bind(&if_done); 3290 { 3291 // All characters up to the min length are equal, decide based on 3292 // string length. 3293 Label if_lengthisequal(assembler), if_lengthisnotequal(assembler); 3294 assembler->Branch(assembler->SmiEqual(lhs_length, rhs_length), 3295 &if_lengthisequal, &if_lengthisnotequal); 3296 3297 assembler->Bind(&if_lengthisequal); 3298 assembler->Goto(&if_equal); 3299 3300 assembler->Bind(&if_lengthisnotequal); 3301 assembler->BranchIfSmiLessThan(lhs_length, rhs_length, &if_less, 3302 &if_greater); 3303 } 3304 } 3305 } 3306 3307 assembler->Bind(&if_notbothonebyteseqstrings); 3308 { 3309 // TODO(bmeurer): Add fast case support for flattened cons strings; 3310 // also add support for two byte string relational comparisons. 3311 switch (mode) { 3312 case kLessThan: 3313 assembler->TailCallRuntime(Runtime::kStringLessThan, context, lhs, 3314 rhs); 3315 break; 3316 case kLessThanOrEqual: 3317 assembler->TailCallRuntime(Runtime::kStringLessThanOrEqual, context, 3318 lhs, rhs); 3319 break; 3320 case kGreaterThan: 3321 assembler->TailCallRuntime(Runtime::kStringGreaterThan, context, lhs, 3322 rhs); 3323 break; 3324 case kGreaterThanOrEqual: 3325 assembler->TailCallRuntime(Runtime::kStringGreaterThanOrEqual, 3326 context, lhs, rhs); 3327 break; 3328 } 3329 } 3330 } 3331 3332 assembler->Bind(&if_less); 3333 switch (mode) { 3334 case kLessThan: 3335 case kLessThanOrEqual: 3336 assembler->Return(assembler->BooleanConstant(true)); 3337 break; 3338 3339 case kGreaterThan: 3340 case kGreaterThanOrEqual: 3341 assembler->Return(assembler->BooleanConstant(false)); 3342 break; 3343 } 3344 3345 assembler->Bind(&if_equal); 3346 switch (mode) { 3347 case kLessThan: 3348 case kGreaterThan: 3349 assembler->Return(assembler->BooleanConstant(false)); 3350 break; 3351 3352 case kLessThanOrEqual: 3353 case kGreaterThanOrEqual: 3354 assembler->Return(assembler->BooleanConstant(true)); 3355 break; 3356 } 3357 3358 assembler->Bind(&if_greater); 3359 switch (mode) { 3360 case kLessThan: 3361 case kLessThanOrEqual: 3362 assembler->Return(assembler->BooleanConstant(false)); 3363 break; 3364 3365 case kGreaterThan: 3366 case kGreaterThanOrEqual: 3367 assembler->Return(assembler->BooleanConstant(true)); 3368 break; 3369 } 3370 } 3371 3372 void GenerateStringEqual(CodeStubAssembler* assembler, ResultMode mode) { 3373 // Here's pseudo-code for the algorithm below in case of kDontNegateResult 3374 // mode; for kNegateResult mode we properly negate the result. 3375 // 3376 // if (lhs == rhs) return true; 3377 // if (lhs->length() != rhs->length()) return false; 3378 // if (lhs->IsInternalizedString() && rhs->IsInternalizedString()) { 3379 // return false; 3380 // } 3381 // if (lhs->IsSeqOneByteString() && rhs->IsSeqOneByteString()) { 3382 // for (i = 0; i != lhs->length(); ++i) { 3383 // if (lhs[i] != rhs[i]) return false; 3384 // } 3385 // return true; 3386 // } 3387 // return %StringEqual(lhs, rhs); 3388 3389 typedef CodeStubAssembler::Label Label; 3390 typedef compiler::Node Node; 3391 typedef CodeStubAssembler::Variable Variable; 3392 3393 Node* lhs = assembler->Parameter(0); 3394 Node* rhs = assembler->Parameter(1); 3395 Node* context = assembler->Parameter(2); 3396 3397 Label if_equal(assembler), if_notequal(assembler); 3398 3399 // Fast check to see if {lhs} and {rhs} refer to the same String object. 3400 Label if_same(assembler), if_notsame(assembler); 3401 assembler->Branch(assembler->WordEqual(lhs, rhs), &if_same, &if_notsame); 3402 3403 assembler->Bind(&if_same); 3404 assembler->Goto(&if_equal); 3405 3406 assembler->Bind(&if_notsame); 3407 { 3408 // The {lhs} and {rhs} don't refer to the exact same String object. 3409 3410 // Load the length of {lhs} and {rhs}. 3411 Node* lhs_length = assembler->LoadObjectField(lhs, String::kLengthOffset); 3412 Node* rhs_length = assembler->LoadObjectField(rhs, String::kLengthOffset); 3413 3414 // Check if the lengths of {lhs} and {rhs} are equal. 3415 Label if_lengthisequal(assembler), if_lengthisnotequal(assembler); 3416 assembler->Branch(assembler->WordEqual(lhs_length, rhs_length), 3417 &if_lengthisequal, &if_lengthisnotequal); 3418 3419 assembler->Bind(&if_lengthisequal); 3420 { 3421 // Load instance types of {lhs} and {rhs}. 3422 Node* lhs_instance_type = assembler->LoadInstanceType(lhs); 3423 Node* rhs_instance_type = assembler->LoadInstanceType(rhs); 3424 3425 // Combine the instance types into a single 16-bit value, so we can check 3426 // both of them at once. 3427 Node* both_instance_types = assembler->Word32Or( 3428 lhs_instance_type, 3429 assembler->Word32Shl(rhs_instance_type, assembler->Int32Constant(8))); 3430 3431 // Check if both {lhs} and {rhs} are internalized. 3432 int const kBothInternalizedMask = 3433 kIsNotInternalizedMask | (kIsNotInternalizedMask << 8); 3434 int const kBothInternalizedTag = 3435 kInternalizedTag | (kInternalizedTag << 8); 3436 Label if_bothinternalized(assembler), if_notbothinternalized(assembler); 3437 assembler->Branch(assembler->Word32Equal( 3438 assembler->Word32And(both_instance_types, 3439 assembler->Int32Constant( 3440 kBothInternalizedMask)), 3441 assembler->Int32Constant(kBothInternalizedTag)), 3442 &if_bothinternalized, &if_notbothinternalized); 3443 3444 assembler->Bind(&if_bothinternalized); 3445 { 3446 // Fast negative check for internalized-to-internalized equality. 3447 assembler->Goto(&if_notequal); 3448 } 3449 3450 assembler->Bind(&if_notbothinternalized); 3451 { 3452 // Check that both {lhs} and {rhs} are flat one-byte strings. 3453 int const kBothSeqOneByteStringMask = 3454 kStringEncodingMask | kStringRepresentationMask | 3455 ((kStringEncodingMask | kStringRepresentationMask) << 8); 3456 int const kBothSeqOneByteStringTag = 3457 kOneByteStringTag | kSeqStringTag | 3458 ((kOneByteStringTag | kSeqStringTag) << 8); 3459 Label if_bothonebyteseqstrings(assembler), 3460 if_notbothonebyteseqstrings(assembler); 3461 assembler->Branch( 3462 assembler->Word32Equal( 3463 assembler->Word32And( 3464 both_instance_types, 3465 assembler->Int32Constant(kBothSeqOneByteStringMask)), 3466 assembler->Int32Constant(kBothSeqOneByteStringTag)), 3467 &if_bothonebyteseqstrings, &if_notbothonebyteseqstrings); 3468 3469 assembler->Bind(&if_bothonebyteseqstrings); 3470 { 3471 // Compute the effective offset of the first character. 3472 Node* begin = assembler->IntPtrConstant( 3473 SeqOneByteString::kHeaderSize - kHeapObjectTag); 3474 3475 // Compute the first offset after the string from the length. 3476 Node* end = 3477 assembler->IntPtrAdd(begin, assembler->SmiUntag(lhs_length)); 3478 3479 // Loop over the {lhs} and {rhs} strings to see if they are equal. 3480 Variable var_offset(assembler, MachineType::PointerRepresentation()); 3481 Label loop(assembler, &var_offset); 3482 var_offset.Bind(begin); 3483 assembler->Goto(&loop); 3484 assembler->Bind(&loop); 3485 { 3486 // Check if {offset} equals {end}. 3487 Node* offset = var_offset.value(); 3488 Label if_done(assembler), if_notdone(assembler); 3489 assembler->Branch(assembler->WordEqual(offset, end), &if_done, 3490 &if_notdone); 3491 3492 assembler->Bind(&if_notdone); 3493 { 3494 // Load the next characters from {lhs} and {rhs}. 3495 Node* lhs_value = 3496 assembler->Load(MachineType::Uint8(), lhs, offset); 3497 Node* rhs_value = 3498 assembler->Load(MachineType::Uint8(), rhs, offset); 3499 3500 // Check if the characters match. 3501 Label if_valueissame(assembler), if_valueisnotsame(assembler); 3502 assembler->Branch(assembler->Word32Equal(lhs_value, rhs_value), 3503 &if_valueissame, &if_valueisnotsame); 3504 3505 assembler->Bind(&if_valueissame); 3506 { 3507 // Advance to next character. 3508 var_offset.Bind( 3509 assembler->IntPtrAdd(offset, assembler->IntPtrConstant(1))); 3510 } 3511 assembler->Goto(&loop); 3512 3513 assembler->Bind(&if_valueisnotsame); 3514 assembler->Goto(&if_notequal); 3515 } 3516 3517 assembler->Bind(&if_done); 3518 assembler->Goto(&if_equal); 3519 } 3520 } 3521 3522 assembler->Bind(&if_notbothonebyteseqstrings); 3523 { 3524 // TODO(bmeurer): Add fast case support for flattened cons strings; 3525 // also add support for two byte string equality checks. 3526 Runtime::FunctionId function_id = (mode == kDontNegateResult) 3527 ? Runtime::kStringEqual 3528 : Runtime::kStringNotEqual; 3529 assembler->TailCallRuntime(function_id, context, lhs, rhs); 3530 } 3531 } 3532 } 3533 3534 assembler->Bind(&if_lengthisnotequal); 3535 { 3536 // Mismatch in length of {lhs} and {rhs}, cannot be equal. 3537 assembler->Goto(&if_notequal); 3538 } 3539 } 3540 3541 assembler->Bind(&if_equal); 3542 assembler->Return(assembler->BooleanConstant(mode == kDontNegateResult)); 3543 3544 assembler->Bind(&if_notequal); 3545 assembler->Return(assembler->BooleanConstant(mode == kNegateResult)); 3546 } 3547 3548 } // namespace 3549 3550 void LoadApiGetterStub::GenerateAssembly(CodeStubAssembler* assembler) const { 3551 typedef compiler::Node Node; 3552 Node* context = assembler->Parameter(3); 3553 Node* receiver = assembler->Parameter(0); 3554 // For now we only support receiver_is_holder. 3555 DCHECK(receiver_is_holder()); 3556 Node* holder = receiver; 3557 Node* map = assembler->LoadMap(receiver); 3558 Node* descriptors = assembler->LoadMapDescriptors(map); 3559 Node* offset = 3560 assembler->Int32Constant(DescriptorArray::ToValueIndex(index())); 3561 Node* callback = assembler->LoadFixedArrayElement(descriptors, offset); 3562 assembler->TailCallStub(CodeFactory::ApiGetter(isolate()), context, receiver, 3563 holder, callback); 3564 } 3565 3566 // static 3567 compiler::Node* LessThanStub::Generate(CodeStubAssembler* assembler, 3568 compiler::Node* lhs, compiler::Node* rhs, 3569 compiler::Node* context) { 3570 return GenerateAbstractRelationalComparison(assembler, kLessThan, lhs, rhs, 3571 context); 3572 } 3573 3574 // static 3575 compiler::Node* LessThanOrEqualStub::Generate(CodeStubAssembler* assembler, 3576 compiler::Node* lhs, 3577 compiler::Node* rhs, 3578 compiler::Node* context) { 3579 return GenerateAbstractRelationalComparison(assembler, kLessThanOrEqual, lhs, 3580 rhs, context); 3581 } 3582 3583 // static 3584 compiler::Node* GreaterThanStub::Generate(CodeStubAssembler* assembler, 3585 compiler::Node* lhs, 3586 compiler::Node* rhs, 3587 compiler::Node* context) { 3588 return GenerateAbstractRelationalComparison(assembler, kGreaterThan, lhs, rhs, 3589 context); 3590 } 3591 3592 // static 3593 compiler::Node* GreaterThanOrEqualStub::Generate(CodeStubAssembler* assembler, 3594 compiler::Node* lhs, 3595 compiler::Node* rhs, 3596 compiler::Node* context) { 3597 return GenerateAbstractRelationalComparison(assembler, kGreaterThanOrEqual, 3598 lhs, rhs, context); 3599 } 3600 3601 // static 3602 compiler::Node* EqualStub::Generate(CodeStubAssembler* assembler, 3603 compiler::Node* lhs, compiler::Node* rhs, 3604 compiler::Node* context) { 3605 return GenerateEqual(assembler, kDontNegateResult, lhs, rhs, context); 3606 } 3607 3608 // static 3609 compiler::Node* NotEqualStub::Generate(CodeStubAssembler* assembler, 3610 compiler::Node* lhs, compiler::Node* rhs, 3611 compiler::Node* context) { 3612 return GenerateEqual(assembler, kNegateResult, lhs, rhs, context); 3613 } 3614 3615 // static 3616 compiler::Node* StrictEqualStub::Generate(CodeStubAssembler* assembler, 3617 compiler::Node* lhs, 3618 compiler::Node* rhs, 3619 compiler::Node* context) { 3620 return GenerateStrictEqual(assembler, kDontNegateResult, lhs, rhs, context); 3621 } 3622 3623 // static 3624 compiler::Node* StrictNotEqualStub::Generate(CodeStubAssembler* assembler, 3625 compiler::Node* lhs, 3626 compiler::Node* rhs, 3627 compiler::Node* context) { 3628 return GenerateStrictEqual(assembler, kNegateResult, lhs, rhs, context); 3629 } 3630 3631 void StringEqualStub::GenerateAssembly(CodeStubAssembler* assembler) const { 3632 GenerateStringEqual(assembler, kDontNegateResult); 3633 } 3634 3635 void StringNotEqualStub::GenerateAssembly(CodeStubAssembler* assembler) const { 3636 GenerateStringEqual(assembler, kNegateResult); 3637 } 3638 3639 void StringLessThanStub::GenerateAssembly(CodeStubAssembler* assembler) const { 3640 GenerateStringRelationalComparison(assembler, kLessThan); 3641 } 3642 3643 void StringLessThanOrEqualStub::GenerateAssembly( 3644 CodeStubAssembler* assembler) const { 3645 GenerateStringRelationalComparison(assembler, kLessThanOrEqual); 3646 } 3647 3648 void StringGreaterThanStub::GenerateAssembly( 3649 CodeStubAssembler* assembler) const { 3650 GenerateStringRelationalComparison(assembler, kGreaterThan); 3651 } 3652 3653 void StringGreaterThanOrEqualStub::GenerateAssembly( 3654 CodeStubAssembler* assembler) const { 3655 GenerateStringRelationalComparison(assembler, kGreaterThanOrEqual); 3656 } 3657 3658 void ToLengthStub::GenerateAssembly(CodeStubAssembler* assembler) const { 3659 typedef CodeStubAssembler::Label Label; 3660 typedef compiler::Node Node; 3661 typedef CodeStubAssembler::Variable Variable; 3662 3663 Node* context = assembler->Parameter(1); 3664 3665 // We might need to loop once for ToNumber conversion. 3666 Variable var_len(assembler, MachineRepresentation::kTagged); 3667 Label loop(assembler, &var_len); 3668 var_len.Bind(assembler->Parameter(0)); 3669 assembler->Goto(&loop); 3670 assembler->Bind(&loop); 3671 { 3672 // Shared entry points. 3673 Label return_len(assembler), 3674 return_two53minus1(assembler, Label::kDeferred), 3675 return_zero(assembler, Label::kDeferred); 3676 3677 // Load the current {len} value. 3678 Node* len = var_len.value(); 3679 3680 // Check if {len} is a positive Smi. 3681 assembler->GotoIf(assembler->WordIsPositiveSmi(len), &return_len); 3682 3683 // Check if {len} is a (negative) Smi. 3684 assembler->GotoIf(assembler->WordIsSmi(len), &return_zero); 3685 3686 // Check if {len} is a HeapNumber. 3687 Label if_lenisheapnumber(assembler), 3688 if_lenisnotheapnumber(assembler, Label::kDeferred); 3689 assembler->Branch(assembler->WordEqual(assembler->LoadMap(len), 3690 assembler->HeapNumberMapConstant()), 3691 &if_lenisheapnumber, &if_lenisnotheapnumber); 3692 3693 assembler->Bind(&if_lenisheapnumber); 3694 { 3695 // Load the floating-point value of {len}. 3696 Node* len_value = assembler->LoadHeapNumberValue(len); 3697 3698 // Check if {len} is not greater than zero. 3699 assembler->GotoUnless(assembler->Float64GreaterThan( 3700 len_value, assembler->Float64Constant(0.0)), 3701 &return_zero); 3702 3703 // Check if {len} is greater than or equal to 2^53-1. 3704 assembler->GotoIf( 3705 assembler->Float64GreaterThanOrEqual( 3706 len_value, assembler->Float64Constant(kMaxSafeInteger)), 3707 &return_two53minus1); 3708 3709 // Round the {len} towards -Infinity. 3710 Node* value = assembler->Float64Floor(len_value); 3711 Node* result = assembler->ChangeFloat64ToTagged(value); 3712 assembler->Return(result); 3713 } 3714 3715 assembler->Bind(&if_lenisnotheapnumber); 3716 { 3717 // Need to convert {len} to a Number first. 3718 Callable callable = CodeFactory::NonNumberToNumber(assembler->isolate()); 3719 var_len.Bind(assembler->CallStub(callable, context, len)); 3720 assembler->Goto(&loop); 3721 } 3722 3723 assembler->Bind(&return_len); 3724 assembler->Return(var_len.value()); 3725 3726 assembler->Bind(&return_two53minus1); 3727 assembler->Return(assembler->NumberConstant(kMaxSafeInteger)); 3728 3729 assembler->Bind(&return_zero); 3730 assembler->Return(assembler->SmiConstant(Smi::FromInt(0))); 3731 } 3732 } 3733 3734 // static 3735 compiler::Node* ToBooleanStub::Generate(CodeStubAssembler* assembler, 3736 compiler::Node* value, 3737 compiler::Node* context) { 3738 typedef compiler::Node Node; 3739 typedef CodeStubAssembler::Label Label; 3740 typedef CodeStubAssembler::Variable Variable; 3741 3742 Variable result(assembler, MachineRepresentation::kTagged); 3743 Label if_valueissmi(assembler), if_valueisnotsmi(assembler), 3744 return_true(assembler), return_false(assembler), end(assembler); 3745 3746 // Check if {value} is a Smi or a HeapObject. 3747 assembler->Branch(assembler->WordIsSmi(value), &if_valueissmi, 3748 &if_valueisnotsmi); 3749 3750 assembler->Bind(&if_valueissmi); 3751 { 3752 // The {value} is a Smi, only need to check against zero. 3753 assembler->Branch(assembler->SmiEqual(value, assembler->SmiConstant(0)), 3754 &return_false, &return_true); 3755 } 3756 3757 assembler->Bind(&if_valueisnotsmi); 3758 { 3759 Label if_valueisstring(assembler), if_valueisnotstring(assembler), 3760 if_valueisheapnumber(assembler), if_valueisoddball(assembler), 3761 if_valueisother(assembler); 3762 3763 // The {value} is a HeapObject, load its map. 3764 Node* value_map = assembler->LoadMap(value); 3765 3766 // Load the {value}s instance type. 3767 Node* value_instance_type = assembler->Load( 3768 MachineType::Uint8(), value_map, 3769 assembler->IntPtrConstant(Map::kInstanceTypeOffset - kHeapObjectTag)); 3770 3771 // Dispatch based on the instance type; we distinguish all String instance 3772 // types, the HeapNumber type and the Oddball type. 3773 assembler->Branch(assembler->Int32LessThan( 3774 value_instance_type, 3775 assembler->Int32Constant(FIRST_NONSTRING_TYPE)), 3776 &if_valueisstring, &if_valueisnotstring); 3777 assembler->Bind(&if_valueisnotstring); 3778 size_t const kNumCases = 2; 3779 Label* case_labels[kNumCases]; 3780 int32_t case_values[kNumCases]; 3781 case_labels[0] = &if_valueisheapnumber; 3782 case_values[0] = HEAP_NUMBER_TYPE; 3783 case_labels[1] = &if_valueisoddball; 3784 case_values[1] = ODDBALL_TYPE; 3785 assembler->Switch(value_instance_type, &if_valueisother, case_values, 3786 case_labels, arraysize(case_values)); 3787 3788 assembler->Bind(&if_valueisstring); 3789 { 3790 // Load the string length field of the {value}. 3791 Node* value_length = 3792 assembler->LoadObjectField(value, String::kLengthOffset); 3793 3794 // Check if the {value} is the empty string. 3795 assembler->Branch( 3796 assembler->SmiEqual(value_length, assembler->SmiConstant(0)), 3797 &return_false, &return_true); 3798 } 3799 3800 assembler->Bind(&if_valueisheapnumber); 3801 { 3802 Node* value_value = assembler->Load( 3803 MachineType::Float64(), value, 3804 assembler->IntPtrConstant(HeapNumber::kValueOffset - kHeapObjectTag)); 3805 3806 Label if_valueisnotpositive(assembler); 3807 assembler->Branch(assembler->Float64LessThan( 3808 assembler->Float64Constant(0.0), value_value), 3809 &return_true, &if_valueisnotpositive); 3810 3811 assembler->Bind(&if_valueisnotpositive); 3812 assembler->Branch(assembler->Float64LessThan( 3813 value_value, assembler->Float64Constant(0.0)), 3814 &return_true, &return_false); 3815 } 3816 3817 assembler->Bind(&if_valueisoddball); 3818 { 3819 // The {value} is an Oddball, and every Oddball knows its boolean value. 3820 Node* value_toboolean = 3821 assembler->LoadObjectField(value, Oddball::kToBooleanOffset); 3822 result.Bind(value_toboolean); 3823 assembler->Goto(&end); 3824 } 3825 3826 assembler->Bind(&if_valueisother); 3827 { 3828 Node* value_map_bitfield = assembler->Load( 3829 MachineType::Uint8(), value_map, 3830 assembler->IntPtrConstant(Map::kBitFieldOffset - kHeapObjectTag)); 3831 Node* value_map_undetectable = assembler->Word32And( 3832 value_map_bitfield, 3833 assembler->Int32Constant(1 << Map::kIsUndetectable)); 3834 3835 // Check if the {value} is undetectable. 3836 assembler->Branch(assembler->Word32Equal(value_map_undetectable, 3837 assembler->Int32Constant(0)), 3838 &return_true, &return_false); 3839 } 3840 } 3841 3842 assembler->Bind(&return_false); 3843 { 3844 result.Bind(assembler->BooleanConstant(false)); 3845 assembler->Goto(&end); 3846 } 3847 3848 assembler->Bind(&return_true); 3849 { 3850 result.Bind(assembler->BooleanConstant(true)); 3851 assembler->Goto(&end); 3852 } 3853 3854 assembler->Bind(&end); 3855 return result.value(); 3856 } 3857 3858 void ToIntegerStub::GenerateAssembly(CodeStubAssembler* assembler) const { 3859 typedef CodeStubAssembler::Label Label; 3860 typedef compiler::Node Node; 3861 typedef CodeStubAssembler::Variable Variable; 3862 3863 Node* context = assembler->Parameter(1); 3864 3865 // We might need to loop once for ToNumber conversion. 3866 Variable var_arg(assembler, MachineRepresentation::kTagged); 3867 Label loop(assembler, &var_arg); 3868 var_arg.Bind(assembler->Parameter(0)); 3869 assembler->Goto(&loop); 3870 assembler->Bind(&loop); 3871 { 3872 // Shared entry points. 3873 Label return_arg(assembler), return_zero(assembler, Label::kDeferred); 3874 3875 // Load the current {arg} value. 3876 Node* arg = var_arg.value(); 3877 3878 // Check if {arg} is a Smi. 3879 assembler->GotoIf(assembler->WordIsSmi(arg), &return_arg); 3880 3881 // Check if {arg} is a HeapNumber. 3882 Label if_argisheapnumber(assembler), 3883 if_argisnotheapnumber(assembler, Label::kDeferred); 3884 assembler->Branch(assembler->WordEqual(assembler->LoadMap(arg), 3885 assembler->HeapNumberMapConstant()), 3886 &if_argisheapnumber, &if_argisnotheapnumber); 3887 3888 assembler->Bind(&if_argisheapnumber); 3889 { 3890 // Load the floating-point value of {arg}. 3891 Node* arg_value = assembler->LoadHeapNumberValue(arg); 3892 3893 // Check if {arg} is NaN. 3894 assembler->GotoUnless(assembler->Float64Equal(arg_value, arg_value), 3895 &return_zero); 3896 3897 // Truncate {arg} towards zero. 3898 Node* value = assembler->Float64Trunc(arg_value); 3899 var_arg.Bind(assembler->ChangeFloat64ToTagged(value)); 3900 assembler->Goto(&return_arg); 3901 } 3902 3903 assembler->Bind(&if_argisnotheapnumber); 3904 { 3905 // Need to convert {arg} to a Number first. 3906 Callable callable = CodeFactory::NonNumberToNumber(assembler->isolate()); 3907 var_arg.Bind(assembler->CallStub(callable, context, arg)); 3908 assembler->Goto(&loop); 3909 } 3910 3911 assembler->Bind(&return_arg); 3912 assembler->Return(var_arg.value()); 3913 3914 assembler->Bind(&return_zero); 3915 assembler->Return(assembler->SmiConstant(Smi::FromInt(0))); 3916 } 3917 } 3918 3919 void StoreInterceptorStub::GenerateAssembly( 3920 CodeStubAssembler* assembler) const { 3921 typedef compiler::Node Node; 3922 Node* receiver = assembler->Parameter(0); 3923 Node* name = assembler->Parameter(1); 3924 Node* value = assembler->Parameter(2); 3925 Node* context = assembler->Parameter(3); 3926 assembler->TailCallRuntime(Runtime::kStorePropertyWithInterceptor, context, 3927 receiver, name, value); 3928 } 3929 3930 void LoadIndexedInterceptorStub::GenerateAssembly( 3931 CodeStubAssembler* assembler) const { 3932 typedef compiler::Node Node; 3933 typedef CodeStubAssembler::Label Label; 3934 Node* receiver = assembler->Parameter(0); 3935 Node* key = assembler->Parameter(1); 3936 Node* slot = assembler->Parameter(2); 3937 Node* vector = assembler->Parameter(3); 3938 Node* context = assembler->Parameter(4); 3939 3940 Label if_keyispositivesmi(assembler), if_keyisinvalid(assembler); 3941 assembler->Branch(assembler->WordIsPositiveSmi(key), &if_keyispositivesmi, 3942 &if_keyisinvalid); 3943 assembler->Bind(&if_keyispositivesmi); 3944 assembler->TailCallRuntime(Runtime::kLoadElementWithInterceptor, context, 3945 receiver, key); 3946 3947 assembler->Bind(&if_keyisinvalid); 3948 assembler->TailCallRuntime(Runtime::kKeyedLoadIC_Miss, context, receiver, key, 3949 slot, vector); 3950 } 3951 3952 // static 3953 bool FastCloneShallowObjectStub::IsSupported(ObjectLiteral* expr) { 3954 // FastCloneShallowObjectStub doesn't copy elements, and object literals don't 3955 // support copy-on-write (COW) elements for now. 3956 // TODO(mvstanton): make object literals support COW elements. 3957 return expr->fast_elements() && expr->has_shallow_properties() && 3958 expr->properties_count() <= kMaximumClonedProperties; 3959 } 3960 3961 // static 3962 int FastCloneShallowObjectStub::PropertiesCount(int literal_length) { 3963 // This heuristic of setting empty literals to have 3964 // kInitialGlobalObjectUnusedPropertiesCount must remain in-sync with the 3965 // runtime. 3966 // TODO(verwaest): Unify this with the heuristic in the runtime. 3967 return literal_length == 0 3968 ? JSObject::kInitialGlobalObjectUnusedPropertiesCount 3969 : literal_length; 3970 } 3971 3972 // static 3973 compiler::Node* FastCloneShallowObjectStub::GenerateFastPath( 3974 CodeStubAssembler* assembler, compiler::CodeAssembler::Label* call_runtime, 3975 compiler::Node* closure, compiler::Node* literals_index, 3976 compiler::Node* properties_count) { 3977 typedef compiler::Node Node; 3978 typedef compiler::CodeAssembler::Label Label; 3979 typedef compiler::CodeAssembler::Variable Variable; 3980 3981 Node* undefined = assembler->UndefinedConstant(); 3982 Node* literals_array = 3983 assembler->LoadObjectField(closure, JSFunction::kLiteralsOffset); 3984 Node* allocation_site = assembler->LoadFixedArrayElement( 3985 literals_array, literals_index, 3986 LiteralsArray::kFirstLiteralIndex * kPointerSize, 3987 CodeStubAssembler::SMI_PARAMETERS); 3988 assembler->GotoIf(assembler->WordEqual(allocation_site, undefined), 3989 call_runtime); 3990 3991 // Calculate the object and allocation size based on the properties count. 3992 Node* object_size = assembler->IntPtrAdd( 3993 assembler->WordShl(properties_count, kPointerSizeLog2), 3994 assembler->IntPtrConstant(JSObject::kHeaderSize)); 3995 Node* allocation_size = object_size; 3996 if (FLAG_allocation_site_pretenuring) { 3997 allocation_size = assembler->IntPtrAdd( 3998 object_size, assembler->IntPtrConstant(AllocationMemento::kSize)); 3999 } 4000 Node* boilerplate = assembler->LoadObjectField( 4001 allocation_site, AllocationSite::kTransitionInfoOffset); 4002 Node* boilerplate_map = assembler->LoadMap(boilerplate); 4003 Node* instance_size = assembler->LoadMapInstanceSize(boilerplate_map); 4004 Node* size_in_words = assembler->WordShr(object_size, kPointerSizeLog2); 4005 assembler->GotoUnless(assembler->Word32Equal(instance_size, size_in_words), 4006 call_runtime); 4007 4008 Node* copy = assembler->Allocate(allocation_size); 4009 4010 // Copy boilerplate elements. 4011 Variable offset(assembler, MachineType::PointerRepresentation()); 4012 offset.Bind(assembler->IntPtrConstant(-kHeapObjectTag)); 4013 Node* end_offset = assembler->IntPtrAdd(object_size, offset.value()); 4014 Label loop_body(assembler, &offset), loop_check(assembler, &offset); 4015 // We should always have an object size greater than zero. 4016 assembler->Goto(&loop_body); 4017 assembler->Bind(&loop_body); 4018 { 4019 // The Allocate above guarantees that the copy lies in new space. This 4020 // allows us to skip write barriers. This is necessary since we may also be 4021 // copying unboxed doubles. 4022 Node* field = 4023 assembler->Load(MachineType::IntPtr(), boilerplate, offset.value()); 4024 assembler->StoreNoWriteBarrier(MachineType::PointerRepresentation(), copy, 4025 offset.value(), field); 4026 assembler->Goto(&loop_check); 4027 } 4028 assembler->Bind(&loop_check); 4029 { 4030 offset.Bind(assembler->IntPtrAdd(offset.value(), 4031 assembler->IntPtrConstant(kPointerSize))); 4032 assembler->GotoUnless( 4033 assembler->IntPtrGreaterThanOrEqual(offset.value(), end_offset), 4034 &loop_body); 4035 } 4036 4037 if (FLAG_allocation_site_pretenuring) { 4038 Node* memento = assembler->InnerAllocate(copy, object_size); 4039 assembler->StoreObjectFieldNoWriteBarrier( 4040 memento, HeapObject::kMapOffset, 4041 assembler->LoadRoot(Heap::kAllocationMementoMapRootIndex)); 4042 assembler->StoreObjectFieldNoWriteBarrier( 4043 memento, AllocationMemento::kAllocationSiteOffset, allocation_site); 4044 Node* memento_create_count = assembler->LoadObjectField( 4045 allocation_site, AllocationSite::kPretenureCreateCountOffset); 4046 memento_create_count = assembler->SmiAdd( 4047 memento_create_count, assembler->SmiConstant(Smi::FromInt(1))); 4048 assembler->StoreObjectFieldNoWriteBarrier( 4049 allocation_site, AllocationSite::kPretenureCreateCountOffset, 4050 memento_create_count); 4051 } 4052 4053 // TODO(verwaest): Allocate and fill in double boxes. 4054 return copy; 4055 } 4056 4057 void FastCloneShallowObjectStub::GenerateAssembly( 4058 CodeStubAssembler* assembler) const { 4059 typedef CodeStubAssembler::Label Label; 4060 typedef compiler::Node Node; 4061 Label call_runtime(assembler); 4062 Node* closure = assembler->Parameter(0); 4063 Node* literals_index = assembler->Parameter(1); 4064 4065 Node* properties_count = 4066 assembler->IntPtrConstant(PropertiesCount(this->length())); 4067 Node* copy = GenerateFastPath(assembler, &call_runtime, closure, 4068 literals_index, properties_count); 4069 assembler->Return(copy); 4070 4071 assembler->Bind(&call_runtime); 4072 Node* constant_properties = assembler->Parameter(2); 4073 Node* flags = assembler->Parameter(3); 4074 Node* context = assembler->Parameter(4); 4075 assembler->TailCallRuntime(Runtime::kCreateObjectLiteral, context, closure, 4076 literals_index, constant_properties, flags); 4077 } 4078 4079 template<class StateType> 4080 void HydrogenCodeStub::TraceTransition(StateType from, StateType to) { 4081 // Note: Although a no-op transition is semantically OK, it is hinting at a 4082 // bug somewhere in our state transition machinery. 4083 DCHECK(from != to); 4084 if (!FLAG_trace_ic) return; 4085 OFStream os(stdout); 4086 os << "["; 4087 PrintBaseName(os); 4088 os << ": " << from << "=>" << to << "]" << std::endl; 4089 } 4090 4091 4092 // TODO(svenpanne) Make this a real infix_ostream_iterator. 4093 class SimpleListPrinter { 4094 public: 4095 explicit SimpleListPrinter(std::ostream& os) : os_(os), first_(true) {} 4096 4097 void Add(const char* s) { 4098 if (first_) { 4099 first_ = false; 4100 } else { 4101 os_ << ","; 4102 } 4103 os_ << s; 4104 } 4105 4106 private: 4107 std::ostream& os_; 4108 bool first_; 4109 }; 4110 4111 4112 void CallICStub::PrintState(std::ostream& os) const { // NOLINT 4113 os << state(); 4114 } 4115 4116 4117 void JSEntryStub::FinishCode(Handle<Code> code) { 4118 Handle<FixedArray> handler_table = 4119 code->GetIsolate()->factory()->NewFixedArray(1, TENURED); 4120 handler_table->set(0, Smi::FromInt(handler_offset_)); 4121 code->set_handler_table(*handler_table); 4122 } 4123 4124 4125 void LoadDictionaryElementStub::InitializeDescriptor( 4126 CodeStubDescriptor* descriptor) { 4127 descriptor->Initialize( 4128 FUNCTION_ADDR(Runtime_KeyedLoadIC_MissFromStubFailure)); 4129 } 4130 4131 4132 void KeyedLoadGenericStub::InitializeDescriptor( 4133 CodeStubDescriptor* descriptor) { 4134 descriptor->Initialize( 4135 Runtime::FunctionForId(Runtime::kKeyedGetProperty)->entry); 4136 } 4137 4138 4139 void HandlerStub::InitializeDescriptor(CodeStubDescriptor* descriptor) { 4140 if (kind() == Code::STORE_IC) { 4141 descriptor->Initialize(FUNCTION_ADDR(Runtime_StoreIC_MissFromStubFailure)); 4142 } else if (kind() == Code::KEYED_LOAD_IC) { 4143 descriptor->Initialize( 4144 FUNCTION_ADDR(Runtime_KeyedLoadIC_MissFromStubFailure)); 4145 } else if (kind() == Code::KEYED_STORE_IC) { 4146 descriptor->Initialize( 4147 FUNCTION_ADDR(Runtime_KeyedStoreIC_MissFromStubFailure)); 4148 } 4149 } 4150 4151 4152 CallInterfaceDescriptor HandlerStub::GetCallInterfaceDescriptor() const { 4153 if (kind() == Code::LOAD_IC || kind() == Code::KEYED_LOAD_IC) { 4154 return LoadWithVectorDescriptor(isolate()); 4155 } else { 4156 DCHECK(kind() == Code::STORE_IC || kind() == Code::KEYED_STORE_IC); 4157 return VectorStoreICDescriptor(isolate()); 4158 } 4159 } 4160 4161 4162 void StoreFastElementStub::InitializeDescriptor( 4163 CodeStubDescriptor* descriptor) { 4164 descriptor->Initialize( 4165 FUNCTION_ADDR(Runtime_KeyedStoreIC_MissFromStubFailure)); 4166 } 4167 4168 4169 void ElementsTransitionAndStoreStub::InitializeDescriptor( 4170 CodeStubDescriptor* descriptor) { 4171 descriptor->Initialize( 4172 FUNCTION_ADDR(Runtime_ElementsTransitionAndStoreIC_Miss)); 4173 } 4174 4175 4176 void ToObjectStub::InitializeDescriptor(CodeStubDescriptor* descriptor) { 4177 descriptor->Initialize(Runtime::FunctionForId(Runtime::kToObject)->entry); 4178 } 4179 4180 4181 CallInterfaceDescriptor StoreTransitionStub::GetCallInterfaceDescriptor() 4182 const { 4183 return VectorStoreTransitionDescriptor(isolate()); 4184 } 4185 4186 4187 CallInterfaceDescriptor 4188 ElementsTransitionAndStoreStub::GetCallInterfaceDescriptor() const { 4189 return VectorStoreTransitionDescriptor(isolate()); 4190 } 4191 4192 void FastNewClosureStub::InitializeDescriptor(CodeStubDescriptor* descriptor) {} 4193 4194 void FastNewContextStub::InitializeDescriptor(CodeStubDescriptor* d) {} 4195 4196 4197 void TypeofStub::InitializeDescriptor(CodeStubDescriptor* descriptor) {} 4198 4199 4200 void NumberToStringStub::InitializeDescriptor(CodeStubDescriptor* descriptor) { 4201 descriptor->Initialize( 4202 Runtime::FunctionForId(Runtime::kNumberToString)->entry); 4203 } 4204 4205 4206 void FastCloneRegExpStub::InitializeDescriptor(CodeStubDescriptor* descriptor) { 4207 FastCloneRegExpDescriptor call_descriptor(isolate()); 4208 descriptor->Initialize( 4209 Runtime::FunctionForId(Runtime::kCreateRegExpLiteral)->entry); 4210 } 4211 4212 4213 void FastCloneShallowArrayStub::InitializeDescriptor( 4214 CodeStubDescriptor* descriptor) { 4215 FastCloneShallowArrayDescriptor call_descriptor(isolate()); 4216 descriptor->Initialize( 4217 Runtime::FunctionForId(Runtime::kCreateArrayLiteralStubBailout)->entry); 4218 } 4219 4220 4221 void CreateAllocationSiteStub::InitializeDescriptor(CodeStubDescriptor* d) {} 4222 4223 4224 void CreateWeakCellStub::InitializeDescriptor(CodeStubDescriptor* d) {} 4225 4226 4227 void RegExpConstructResultStub::InitializeDescriptor( 4228 CodeStubDescriptor* descriptor) { 4229 descriptor->Initialize( 4230 Runtime::FunctionForId(Runtime::kRegExpConstructResult)->entry); 4231 } 4232 4233 4234 void TransitionElementsKindStub::InitializeDescriptor( 4235 CodeStubDescriptor* descriptor) { 4236 descriptor->Initialize( 4237 Runtime::FunctionForId(Runtime::kTransitionElementsKind)->entry); 4238 } 4239 4240 4241 void AllocateHeapNumberStub::InitializeDescriptor( 4242 CodeStubDescriptor* descriptor) { 4243 descriptor->Initialize( 4244 Runtime::FunctionForId(Runtime::kAllocateHeapNumber)->entry); 4245 } 4246 4247 4248 #define SIMD128_INIT_DESC(TYPE, Type, type, lane_count, lane_type) \ 4249 void Allocate##Type##Stub::InitializeDescriptor( \ 4250 CodeStubDescriptor* descriptor) { \ 4251 descriptor->Initialize( \ 4252 Runtime::FunctionForId(Runtime::kCreate##Type)->entry); \ 4253 } 4254 SIMD128_TYPES(SIMD128_INIT_DESC) 4255 #undef SIMD128_INIT_DESC 4256 4257 void ToBooleanICStub::InitializeDescriptor(CodeStubDescriptor* descriptor) { 4258 descriptor->Initialize(FUNCTION_ADDR(Runtime_ToBooleanIC_Miss)); 4259 descriptor->SetMissHandler(ExternalReference( 4260 Runtime::FunctionForId(Runtime::kToBooleanIC_Miss), isolate())); 4261 } 4262 4263 4264 void BinaryOpICStub::InitializeDescriptor(CodeStubDescriptor* descriptor) { 4265 descriptor->Initialize(FUNCTION_ADDR(Runtime_BinaryOpIC_Miss)); 4266 descriptor->SetMissHandler(ExternalReference( 4267 Runtime::FunctionForId(Runtime::kBinaryOpIC_Miss), isolate())); 4268 } 4269 4270 4271 void BinaryOpWithAllocationSiteStub::InitializeDescriptor( 4272 CodeStubDescriptor* descriptor) { 4273 descriptor->Initialize( 4274 FUNCTION_ADDR(Runtime_BinaryOpIC_MissWithAllocationSite)); 4275 } 4276 4277 4278 void StringAddStub::InitializeDescriptor(CodeStubDescriptor* descriptor) { 4279 descriptor->Initialize(Runtime::FunctionForId(Runtime::kStringAdd)->entry); 4280 } 4281 4282 4283 void GrowArrayElementsStub::InitializeDescriptor( 4284 CodeStubDescriptor* descriptor) { 4285 descriptor->Initialize( 4286 Runtime::FunctionForId(Runtime::kGrowArrayElements)->entry); 4287 } 4288 4289 4290 void TypeofStub::GenerateAheadOfTime(Isolate* isolate) { 4291 TypeofStub stub(isolate); 4292 stub.GetCode(); 4293 } 4294 4295 // static 4296 compiler::Node* HasPropertyStub::Generate(CodeStubAssembler* assembler, 4297 compiler::Node* key, 4298 compiler::Node* object, 4299 compiler::Node* context) { 4300 typedef compiler::Node Node; 4301 typedef CodeStubAssembler::Label Label; 4302 typedef CodeStubAssembler::Variable Variable; 4303 4304 Label call_runtime(assembler, Label::kDeferred), return_true(assembler), 4305 return_false(assembler), end(assembler); 4306 4307 // Ensure object is JSReceiver, otherwise call runtime to throw error. 4308 Label if_objectisnotsmi(assembler); 4309 assembler->Branch(assembler->WordIsSmi(object), &call_runtime, 4310 &if_objectisnotsmi); 4311 assembler->Bind(&if_objectisnotsmi); 4312 4313 Node* map = assembler->LoadMap(object); 4314 Node* instance_type = assembler->LoadMapInstanceType(map); 4315 { 4316 Label if_objectisreceiver(assembler); 4317 STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE); 4318 assembler->Branch( 4319 assembler->Int32GreaterThanOrEqual( 4320 instance_type, assembler->Int32Constant(FIRST_JS_RECEIVER_TYPE)), 4321 &if_objectisreceiver, &call_runtime); 4322 assembler->Bind(&if_objectisreceiver); 4323 } 4324 4325 Variable var_index(assembler, MachineRepresentation::kWord32); 4326 4327 Label keyisindex(assembler), if_iskeyunique(assembler); 4328 assembler->TryToName(key, &keyisindex, &var_index, &if_iskeyunique, 4329 &call_runtime); 4330 4331 assembler->Bind(&if_iskeyunique); 4332 { 4333 Variable var_object(assembler, MachineRepresentation::kTagged); 4334 Variable var_map(assembler, MachineRepresentation::kTagged); 4335 Variable var_instance_type(assembler, MachineRepresentation::kWord8); 4336 4337 Variable* merged_variables[] = {&var_object, &var_map, &var_instance_type}; 4338 Label loop(assembler, arraysize(merged_variables), merged_variables); 4339 var_object.Bind(object); 4340 var_map.Bind(map); 4341 var_instance_type.Bind(instance_type); 4342 assembler->Goto(&loop); 4343 assembler->Bind(&loop); 4344 { 4345 Label next_proto(assembler); 4346 assembler->TryHasOwnProperty(var_object.value(), var_map.value(), 4347 var_instance_type.value(), key, &return_true, 4348 &next_proto, &call_runtime); 4349 assembler->Bind(&next_proto); 4350 4351 Node* proto = assembler->LoadMapPrototype(var_map.value()); 4352 4353 Label if_not_null(assembler); 4354 assembler->Branch(assembler->WordEqual(proto, assembler->NullConstant()), 4355 &return_false, &if_not_null); 4356 assembler->Bind(&if_not_null); 4357 4358 Node* map = assembler->LoadMap(proto); 4359 Node* instance_type = assembler->LoadMapInstanceType(map); 4360 4361 var_object.Bind(proto); 4362 var_map.Bind(map); 4363 var_instance_type.Bind(instance_type); 4364 assembler->Goto(&loop); 4365 } 4366 } 4367 assembler->Bind(&keyisindex); 4368 { 4369 Variable var_object(assembler, MachineRepresentation::kTagged); 4370 Variable var_map(assembler, MachineRepresentation::kTagged); 4371 Variable var_instance_type(assembler, MachineRepresentation::kWord8); 4372 4373 Variable* merged_variables[] = {&var_object, &var_map, &var_instance_type}; 4374 Label loop(assembler, arraysize(merged_variables), merged_variables); 4375 var_object.Bind(object); 4376 var_map.Bind(map); 4377 var_instance_type.Bind(instance_type); 4378 assembler->Goto(&loop); 4379 assembler->Bind(&loop); 4380 { 4381 Label next_proto(assembler); 4382 assembler->TryLookupElement(var_object.value(), var_map.value(), 4383 var_instance_type.value(), var_index.value(), 4384 &return_true, &next_proto, &call_runtime); 4385 assembler->Bind(&next_proto); 4386 4387 Node* proto = assembler->LoadMapPrototype(var_map.value()); 4388 4389 Label if_not_null(assembler); 4390 assembler->Branch(assembler->WordEqual(proto, assembler->NullConstant()), 4391 &return_false, &if_not_null); 4392 assembler->Bind(&if_not_null); 4393 4394 Node* map = assembler->LoadMap(proto); 4395 Node* instance_type = assembler->LoadMapInstanceType(map); 4396 4397 var_object.Bind(proto); 4398 var_map.Bind(map); 4399 var_instance_type.Bind(instance_type); 4400 assembler->Goto(&loop); 4401 } 4402 } 4403 4404 Variable result(assembler, MachineRepresentation::kTagged); 4405 assembler->Bind(&return_true); 4406 { 4407 result.Bind(assembler->BooleanConstant(true)); 4408 assembler->Goto(&end); 4409 } 4410 4411 assembler->Bind(&return_false); 4412 { 4413 result.Bind(assembler->BooleanConstant(false)); 4414 assembler->Goto(&end); 4415 } 4416 4417 assembler->Bind(&call_runtime); 4418 { 4419 result.Bind( 4420 assembler->CallRuntime(Runtime::kHasProperty, context, key, object)); 4421 assembler->Goto(&end); 4422 } 4423 4424 assembler->Bind(&end); 4425 return result.value(); 4426 } 4427 4428 void CreateAllocationSiteStub::GenerateAheadOfTime(Isolate* isolate) { 4429 CreateAllocationSiteStub stub(isolate); 4430 stub.GetCode(); 4431 } 4432 4433 4434 void CreateWeakCellStub::GenerateAheadOfTime(Isolate* isolate) { 4435 CreateWeakCellStub stub(isolate); 4436 stub.GetCode(); 4437 } 4438 4439 4440 void StoreElementStub::Generate(MacroAssembler* masm) { 4441 DCHECK_EQ(DICTIONARY_ELEMENTS, elements_kind()); 4442 ElementHandlerCompiler::GenerateStoreSlow(masm); 4443 } 4444 4445 4446 // static 4447 void StoreFastElementStub::GenerateAheadOfTime(Isolate* isolate) { 4448 StoreFastElementStub(isolate, false, FAST_HOLEY_ELEMENTS, STANDARD_STORE) 4449 .GetCode(); 4450 StoreFastElementStub(isolate, false, FAST_HOLEY_ELEMENTS, 4451 STORE_AND_GROW_NO_TRANSITION).GetCode(); 4452 for (int i = FIRST_FAST_ELEMENTS_KIND; i <= LAST_FAST_ELEMENTS_KIND; i++) { 4453 ElementsKind kind = static_cast<ElementsKind>(i); 4454 StoreFastElementStub(isolate, true, kind, STANDARD_STORE).GetCode(); 4455 StoreFastElementStub(isolate, true, kind, STORE_AND_GROW_NO_TRANSITION) 4456 .GetCode(); 4457 } 4458 } 4459 4460 4461 void ArrayConstructorStub::PrintName(std::ostream& os) const { // NOLINT 4462 os << "ArrayConstructorStub"; 4463 switch (argument_count()) { 4464 case ANY: 4465 os << "_Any"; 4466 break; 4467 case NONE: 4468 os << "_None"; 4469 break; 4470 case ONE: 4471 os << "_One"; 4472 break; 4473 case MORE_THAN_ONE: 4474 os << "_More_Than_One"; 4475 break; 4476 } 4477 return; 4478 } 4479 4480 4481 bool ToBooleanICStub::UpdateStatus(Handle<Object> object) { 4482 Types new_types = types(); 4483 Types old_types = new_types; 4484 bool to_boolean_value = new_types.UpdateStatus(isolate(), object); 4485 TraceTransition(old_types, new_types); 4486 set_sub_minor_key(TypesBits::update(sub_minor_key(), new_types.ToIntegral())); 4487 return to_boolean_value; 4488 } 4489 4490 void ToBooleanICStub::PrintState(std::ostream& os) const { // NOLINT 4491 os << types(); 4492 } 4493 4494 std::ostream& operator<<(std::ostream& os, const ToBooleanICStub::Types& s) { 4495 os << "("; 4496 SimpleListPrinter p(os); 4497 if (s.IsEmpty()) p.Add("None"); 4498 if (s.Contains(ToBooleanICStub::UNDEFINED)) p.Add("Undefined"); 4499 if (s.Contains(ToBooleanICStub::BOOLEAN)) p.Add("Bool"); 4500 if (s.Contains(ToBooleanICStub::NULL_TYPE)) p.Add("Null"); 4501 if (s.Contains(ToBooleanICStub::SMI)) p.Add("Smi"); 4502 if (s.Contains(ToBooleanICStub::SPEC_OBJECT)) p.Add("SpecObject"); 4503 if (s.Contains(ToBooleanICStub::STRING)) p.Add("String"); 4504 if (s.Contains(ToBooleanICStub::SYMBOL)) p.Add("Symbol"); 4505 if (s.Contains(ToBooleanICStub::HEAP_NUMBER)) p.Add("HeapNumber"); 4506 if (s.Contains(ToBooleanICStub::SIMD_VALUE)) p.Add("SimdValue"); 4507 return os << ")"; 4508 } 4509 4510 bool ToBooleanICStub::Types::UpdateStatus(Isolate* isolate, 4511 Handle<Object> object) { 4512 if (object->IsUndefined(isolate)) { 4513 Add(UNDEFINED); 4514 return false; 4515 } else if (object->IsBoolean()) { 4516 Add(BOOLEAN); 4517 return object->IsTrue(isolate); 4518 } else if (object->IsNull(isolate)) { 4519 Add(NULL_TYPE); 4520 return false; 4521 } else if (object->IsSmi()) { 4522 Add(SMI); 4523 return Smi::cast(*object)->value() != 0; 4524 } else if (object->IsJSReceiver()) { 4525 Add(SPEC_OBJECT); 4526 return !object->IsUndetectable(); 4527 } else if (object->IsString()) { 4528 DCHECK(!object->IsUndetectable()); 4529 Add(STRING); 4530 return String::cast(*object)->length() != 0; 4531 } else if (object->IsSymbol()) { 4532 Add(SYMBOL); 4533 return true; 4534 } else if (object->IsHeapNumber()) { 4535 DCHECK(!object->IsUndetectable()); 4536 Add(HEAP_NUMBER); 4537 double value = HeapNumber::cast(*object)->value(); 4538 return value != 0 && !std::isnan(value); 4539 } else if (object->IsSimd128Value()) { 4540 Add(SIMD_VALUE); 4541 return true; 4542 } else { 4543 // We should never see an internal object at runtime here! 4544 UNREACHABLE(); 4545 return true; 4546 } 4547 } 4548 4549 bool ToBooleanICStub::Types::NeedsMap() const { 4550 return Contains(ToBooleanICStub::SPEC_OBJECT) || 4551 Contains(ToBooleanICStub::STRING) || 4552 Contains(ToBooleanICStub::SYMBOL) || 4553 Contains(ToBooleanICStub::HEAP_NUMBER) || 4554 Contains(ToBooleanICStub::SIMD_VALUE); 4555 } 4556 4557 4558 void StubFailureTrampolineStub::GenerateAheadOfTime(Isolate* isolate) { 4559 StubFailureTrampolineStub stub1(isolate, NOT_JS_FUNCTION_STUB_MODE); 4560 StubFailureTrampolineStub stub2(isolate, JS_FUNCTION_STUB_MODE); 4561 stub1.GetCode(); 4562 stub2.GetCode(); 4563 } 4564 4565 4566 void ProfileEntryHookStub::EntryHookTrampoline(intptr_t function, 4567 intptr_t stack_pointer, 4568 Isolate* isolate) { 4569 FunctionEntryHook entry_hook = isolate->function_entry_hook(); 4570 DCHECK(entry_hook != NULL); 4571 entry_hook(function, stack_pointer); 4572 } 4573 4574 void ArrayNoArgumentConstructorStub::GenerateAssembly( 4575 CodeStubAssembler* assembler) const { 4576 typedef compiler::Node Node; 4577 Node* native_context = assembler->LoadObjectField( 4578 assembler->Parameter( 4579 ArrayNoArgumentConstructorDescriptor::kFunctionIndex), 4580 JSFunction::kContextOffset); 4581 bool track_allocation_site = 4582 AllocationSite::GetMode(elements_kind()) == TRACK_ALLOCATION_SITE && 4583 override_mode() != DISABLE_ALLOCATION_SITES; 4584 Node* allocation_site = 4585 track_allocation_site 4586 ? assembler->Parameter( 4587 ArrayNoArgumentConstructorDescriptor::kAllocationSiteIndex) 4588 : nullptr; 4589 Node* array_map = 4590 assembler->LoadJSArrayElementsMap(elements_kind(), native_context); 4591 Node* array = assembler->AllocateJSArray( 4592 elements_kind(), array_map, 4593 assembler->IntPtrConstant(JSArray::kPreallocatedArrayElements), 4594 assembler->IntPtrConstant(0), allocation_site); 4595 assembler->Return(array); 4596 } 4597 4598 void InternalArrayNoArgumentConstructorStub::GenerateAssembly( 4599 CodeStubAssembler* assembler) const { 4600 typedef compiler::Node Node; 4601 Node* array_map = assembler->LoadObjectField( 4602 assembler->Parameter( 4603 ArrayNoArgumentConstructorDescriptor::kFunctionIndex), 4604 JSFunction::kPrototypeOrInitialMapOffset); 4605 Node* array = assembler->AllocateJSArray( 4606 elements_kind(), array_map, 4607 assembler->IntPtrConstant(JSArray::kPreallocatedArrayElements), 4608 assembler->IntPtrConstant(0), nullptr); 4609 assembler->Return(array); 4610 } 4611 4612 namespace { 4613 4614 void SingleArgumentConstructorCommon(CodeStubAssembler* assembler, 4615 ElementsKind elements_kind, 4616 compiler::Node* array_map, 4617 compiler::Node* allocation_site, 4618 AllocationSiteMode mode) { 4619 typedef compiler::Node Node; 4620 typedef CodeStubAssembler::Label Label; 4621 4622 Label ok(assembler); 4623 Label smi_size(assembler); 4624 Label small_smi_size(assembler); 4625 Label call_runtime(assembler, Label::kDeferred); 4626 4627 Node* size = assembler->Parameter( 4628 ArraySingleArgumentConstructorDescriptor::kArraySizeSmiParameterIndex); 4629 assembler->Branch(assembler->WordIsSmi(size), &smi_size, &call_runtime); 4630 4631 assembler->Bind(&smi_size); 4632 int element_size = 4633 IsFastDoubleElementsKind(elements_kind) ? kDoubleSize : kPointerSize; 4634 int max_fast_elements = 4635 (Page::kMaxRegularHeapObjectSize - FixedArray::kHeaderSize - 4636 JSArray::kSize - AllocationMemento::kSize) / 4637 element_size; 4638 assembler->Branch( 4639 assembler->SmiAboveOrEqual( 4640 size, assembler->SmiConstant(Smi::FromInt(max_fast_elements))), 4641 &call_runtime, &small_smi_size); 4642 4643 assembler->Bind(&small_smi_size); 4644 { 4645 Node* array = assembler->AllocateJSArray( 4646 elements_kind, array_map, size, size, 4647 mode == DONT_TRACK_ALLOCATION_SITE ? nullptr : allocation_site, 4648 CodeStubAssembler::SMI_PARAMETERS); 4649 assembler->Return(array); 4650 } 4651 4652 assembler->Bind(&call_runtime); 4653 { 4654 Node* context = assembler->Parameter( 4655 ArraySingleArgumentConstructorDescriptor::kContextIndex); 4656 Node* function = assembler->Parameter( 4657 ArraySingleArgumentConstructorDescriptor::kFunctionIndex); 4658 Node* array_size = assembler->Parameter( 4659 ArraySingleArgumentConstructorDescriptor::kArraySizeSmiParameterIndex); 4660 Node* allocation_site = assembler->Parameter( 4661 ArraySingleArgumentConstructorDescriptor::kAllocationSiteIndex); 4662 assembler->TailCallRuntime(Runtime::kNewArray, context, function, 4663 array_size, function, allocation_site); 4664 } 4665 } 4666 } // namespace 4667 4668 void ArraySingleArgumentConstructorStub::GenerateAssembly( 4669 CodeStubAssembler* assembler) const { 4670 typedef compiler::Node Node; 4671 Node* function = assembler->Parameter( 4672 ArraySingleArgumentConstructorDescriptor::kFunctionIndex); 4673 Node* native_context = 4674 assembler->LoadObjectField(function, JSFunction::kContextOffset); 4675 Node* array_map = 4676 assembler->LoadJSArrayElementsMap(elements_kind(), native_context); 4677 AllocationSiteMode mode = override_mode() == DISABLE_ALLOCATION_SITES 4678 ? DONT_TRACK_ALLOCATION_SITE 4679 : AllocationSite::GetMode(elements_kind()); 4680 Node* allocation_site = assembler->Parameter( 4681 ArrayNoArgumentConstructorDescriptor::kAllocationSiteIndex); 4682 SingleArgumentConstructorCommon(assembler, elements_kind(), array_map, 4683 allocation_site, mode); 4684 } 4685 4686 void InternalArraySingleArgumentConstructorStub::GenerateAssembly( 4687 CodeStubAssembler* assembler) const { 4688 typedef compiler::Node Node; 4689 Node* function = assembler->Parameter( 4690 ArraySingleArgumentConstructorDescriptor::kFunctionIndex); 4691 Node* array_map = assembler->LoadObjectField( 4692 function, JSFunction::kPrototypeOrInitialMapOffset); 4693 SingleArgumentConstructorCommon(assembler, elements_kind(), array_map, 4694 assembler->UndefinedConstant(), 4695 DONT_TRACK_ALLOCATION_SITE); 4696 } 4697 4698 ArrayConstructorStub::ArrayConstructorStub(Isolate* isolate) 4699 : PlatformCodeStub(isolate) { 4700 minor_key_ = ArgumentCountBits::encode(ANY); 4701 } 4702 4703 4704 ArrayConstructorStub::ArrayConstructorStub(Isolate* isolate, 4705 int argument_count) 4706 : PlatformCodeStub(isolate) { 4707 if (argument_count == 0) { 4708 minor_key_ = ArgumentCountBits::encode(NONE); 4709 } else if (argument_count == 1) { 4710 minor_key_ = ArgumentCountBits::encode(ONE); 4711 } else if (argument_count >= 2) { 4712 minor_key_ = ArgumentCountBits::encode(MORE_THAN_ONE); 4713 } else { 4714 UNREACHABLE(); 4715 } 4716 } 4717 4718 InternalArrayConstructorStub::InternalArrayConstructorStub(Isolate* isolate) 4719 : PlatformCodeStub(isolate) {} 4720 4721 Representation RepresentationFromType(Type* type) { 4722 if (type->Is(Type::UntaggedIntegral())) { 4723 return Representation::Integer32(); 4724 } 4725 4726 if (type->Is(Type::TaggedSigned())) { 4727 return Representation::Smi(); 4728 } 4729 4730 if (type->Is(Type::UntaggedPointer())) { 4731 return Representation::External(); 4732 } 4733 4734 DCHECK(!type->Is(Type::Untagged())); 4735 return Representation::Tagged(); 4736 } 4737 4738 } // namespace internal 4739 } // namespace v8 4740