diff options
author | Michaël Zasso <targos@protonmail.com> | 2017-02-14 11:27:26 +0100 |
---|---|---|
committer | Michaël Zasso <targos@protonmail.com> | 2017-02-22 15:55:42 +0100 |
commit | 7a77daf24344db7942e34c962b0f1ee729ab7af5 (patch) | |
tree | e7cbe7bf4e2f4b802a8f5bc18336c546cd6a0d7f /deps/v8/src/code-stubs.cc | |
parent | 5f08871ee93ea739148cc49e0f7679e33c70295a (diff) | |
download | android-node-v8-7a77daf24344db7942e34c962b0f1ee729ab7af5.tar.gz android-node-v8-7a77daf24344db7942e34c962b0f1ee729ab7af5.tar.bz2 android-node-v8-7a77daf24344db7942e34c962b0f1ee729ab7af5.zip |
deps: update V8 to 5.6.326.55
PR-URL: https://github.com/nodejs/node/pull/10992
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Diffstat (limited to 'deps/v8/src/code-stubs.cc')
-rw-r--r-- | deps/v8/src/code-stubs.cc | 3696 |
1 files changed, 542 insertions, 3154 deletions
diff --git a/deps/v8/src/code-stubs.cc b/deps/v8/src/code-stubs.cc index b899943e98..2ee5ece8da 100644 --- a/deps/v8/src/code-stubs.cc +++ b/deps/v8/src/code-stubs.cc @@ -22,7 +22,7 @@ namespace internal { RUNTIME_FUNCTION(UnexpectedStubMiss) { FATAL("Unexpected deopt of a stub"); - return Smi::FromInt(0); + return Smi::kZero; } CodeStubDescriptor::CodeStubDescriptor(CodeStub* stub) @@ -318,33 +318,42 @@ void BinaryOpICWithAllocationSiteStub::GenerateAheadOfTime( } } - -std::ostream& operator<<(std::ostream& os, const StringAddFlags& flags) { - switch (flags) { - case STRING_ADD_CHECK_NONE: - return os << "CheckNone"; - case STRING_ADD_CHECK_LEFT: - return os << "CheckLeft"; - case STRING_ADD_CHECK_RIGHT: - return os << "CheckRight"; - case STRING_ADD_CHECK_BOTH: - return os << "CheckBoth"; - case STRING_ADD_CONVERT_LEFT: - return os << "ConvertLeft"; - case STRING_ADD_CONVERT_RIGHT: - return os << "ConvertRight"; - case STRING_ADD_CONVERT: - break; - } - UNREACHABLE(); - return os; -} - - void StringAddStub::PrintBaseName(std::ostream& os) const { // NOLINT os << "StringAddStub_" << flags() << "_" << pretenure_flag(); } +void StringAddStub::GenerateAssembly(CodeStubAssembler* assembler) const { + typedef compiler::Node Node; + Node* left = assembler->Parameter(Descriptor::kLeft); + Node* right = assembler->Parameter(Descriptor::kRight); + Node* context = assembler->Parameter(Descriptor::kContext); + + if ((flags() & STRING_ADD_CHECK_LEFT) != 0) { + DCHECK((flags() & STRING_ADD_CONVERT) != 0); + // TODO(danno): The ToString and JSReceiverToPrimitive below could be + // combined to avoid duplicate smi and instance type checks. + left = assembler->ToString(context, + assembler->JSReceiverToPrimitive(context, left)); + } + if ((flags() & STRING_ADD_CHECK_RIGHT) != 0) { + DCHECK((flags() & STRING_ADD_CONVERT) != 0); + // TODO(danno): The ToString and JSReceiverToPrimitive below could be + // combined to avoid duplicate smi and instance type checks. + right = assembler->ToString( + context, assembler->JSReceiverToPrimitive(context, right)); + } + + if ((flags() & STRING_ADD_CHECK_BOTH) == 0) { + CodeStubAssembler::AllocationFlag flags = + (pretenure_flag() == TENURED) ? CodeStubAssembler::kPretenured + : CodeStubAssembler::kNone; + assembler->Return(assembler->StringAdd(context, left, right, flags)); + } else { + Callable callable = CodeFactory::StringAdd(isolate(), STRING_ADD_CHECK_NONE, + pretenure_flag()); + assembler->TailCallStub(callable, context, left, right); + } +} InlineCacheState CompareICStub::GetICState() const { CompareICState::State state = Max(left(), right()); @@ -411,7 +420,7 @@ void CompareICStub::Generate(MacroAssembler* masm) { Handle<Code> TurboFanCodeStub::GenerateCode() { const char* name = CodeStub::MajorName(MajorKey()); - Zone zone(isolate()->allocator()); + Zone zone(isolate()->allocator(), ZONE_NAME); CallInterfaceDescriptor descriptor(GetCallInterfaceDescriptor()); CodeStubAssembler assembler(isolate(), &zone, descriptor, GetCodeFlags(), name); @@ -419,7 +428,7 @@ Handle<Code> TurboFanCodeStub::GenerateCode() { return assembler.GenerateCode(); } -void LoadICTrampolineTFStub::GenerateAssembly( +void LoadICTrampolineStub::GenerateAssembly( CodeStubAssembler* assembler) const { typedef compiler::Node Node; @@ -433,7 +442,7 @@ void LoadICTrampolineTFStub::GenerateAssembly( assembler->LoadIC(&p); } -void LoadICTFStub::GenerateAssembly(CodeStubAssembler* assembler) const { +void LoadICStub::GenerateAssembly(CodeStubAssembler* assembler) const { typedef compiler::Node Node; Node* receiver = assembler->Parameter(Descriptor::kReceiver); @@ -446,6 +455,21 @@ void LoadICTFStub::GenerateAssembly(CodeStubAssembler* assembler) const { assembler->LoadIC(&p); } +void LoadICProtoArrayStub::GenerateAssembly( + CodeStubAssembler* assembler) const { + typedef compiler::Node Node; + + Node* receiver = assembler->Parameter(Descriptor::kReceiver); + Node* name = assembler->Parameter(Descriptor::kName); + Node* slot = assembler->Parameter(Descriptor::kSlot); + Node* vector = assembler->Parameter(Descriptor::kVector); + Node* handler = assembler->Parameter(Descriptor::kHandler); + Node* context = assembler->Parameter(Descriptor::kContext); + + CodeStubAssembler::LoadICParameters p(context, receiver, name, slot, vector); + assembler->LoadICProtoArray(&p, handler); +} + void LoadGlobalICTrampolineStub::GenerateAssembly( CodeStubAssembler* assembler) const { typedef compiler::Node Node; @@ -498,7 +522,7 @@ void KeyedLoadICTFStub::GenerateAssembly(CodeStubAssembler* assembler) const { assembler->KeyedLoadIC(&p); } -void StoreICTrampolineTFStub::GenerateAssembly( +void StoreICTrampolineStub::GenerateAssembly( CodeStubAssembler* assembler) const { typedef compiler::Node Node; @@ -514,7 +538,7 @@ void StoreICTrampolineTFStub::GenerateAssembly( assembler->StoreIC(&p); } -void StoreICTFStub::GenerateAssembly(CodeStubAssembler* assembler) const { +void StoreICStub::GenerateAssembly(CodeStubAssembler* assembler) const { typedef compiler::Node Node; Node* receiver = assembler->Parameter(Descriptor::kReceiver); @@ -529,6 +553,37 @@ void StoreICTFStub::GenerateAssembly(CodeStubAssembler* assembler) const { assembler->StoreIC(&p); } +void KeyedStoreICTrampolineTFStub::GenerateAssembly( + CodeStubAssembler* assembler) const { + typedef compiler::Node Node; + + Node* receiver = assembler->Parameter(Descriptor::kReceiver); + Node* name = assembler->Parameter(Descriptor::kName); + Node* value = assembler->Parameter(Descriptor::kValue); + Node* slot = assembler->Parameter(Descriptor::kSlot); + Node* context = assembler->Parameter(Descriptor::kContext); + Node* vector = assembler->LoadTypeFeedbackVectorForStub(); + + CodeStubAssembler::StoreICParameters p(context, receiver, name, value, slot, + vector); + assembler->KeyedStoreIC(&p, StoreICState::GetLanguageMode(GetExtraICState())); +} + +void KeyedStoreICTFStub::GenerateAssembly(CodeStubAssembler* assembler) const { + typedef compiler::Node Node; + + Node* receiver = assembler->Parameter(Descriptor::kReceiver); + Node* name = assembler->Parameter(Descriptor::kName); + Node* value = assembler->Parameter(Descriptor::kValue); + Node* slot = assembler->Parameter(Descriptor::kSlot); + Node* vector = assembler->Parameter(Descriptor::kVector); + Node* context = assembler->Parameter(Descriptor::kContext); + + CodeStubAssembler::StoreICParameters p(context, receiver, name, value, slot, + vector); + assembler->KeyedStoreIC(&p, StoreICState::GetLanguageMode(GetExtraICState())); +} + void StoreMapStub::GenerateAssembly(CodeStubAssembler* assembler) const { typedef compiler::Node Node; @@ -662,368 +717,6 @@ void StringLengthStub::GenerateAssembly(CodeStubAssembler* assembler) const { } // static -compiler::Node* AddStub::Generate(CodeStubAssembler* assembler, - compiler::Node* left, compiler::Node* right, - compiler::Node* context) { - typedef CodeStubAssembler::Label Label; - typedef compiler::Node Node; - typedef CodeStubAssembler::Variable Variable; - - // Shared entry for floating point addition. - Label do_fadd(assembler); - Variable var_fadd_lhs(assembler, MachineRepresentation::kFloat64), - var_fadd_rhs(assembler, MachineRepresentation::kFloat64); - - // We might need to loop several times due to ToPrimitive, ToString and/or - // ToNumber conversions. - Variable var_lhs(assembler, MachineRepresentation::kTagged), - var_rhs(assembler, MachineRepresentation::kTagged), - var_result(assembler, MachineRepresentation::kTagged); - Variable* loop_vars[2] = {&var_lhs, &var_rhs}; - Label loop(assembler, 2, loop_vars), end(assembler), - string_add_convert_left(assembler, Label::kDeferred), - string_add_convert_right(assembler, Label::kDeferred); - var_lhs.Bind(left); - var_rhs.Bind(right); - assembler->Goto(&loop); - assembler->Bind(&loop); - { - // Load the current {lhs} and {rhs} values. - Node* lhs = var_lhs.value(); - Node* rhs = var_rhs.value(); - - // Check if the {lhs} is a Smi or a HeapObject. - Label if_lhsissmi(assembler), if_lhsisnotsmi(assembler); - assembler->Branch(assembler->WordIsSmi(lhs), &if_lhsissmi, &if_lhsisnotsmi); - - assembler->Bind(&if_lhsissmi); - { - // Check if the {rhs} is also a Smi. - Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler); - assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi, - &if_rhsisnotsmi); - - assembler->Bind(&if_rhsissmi); - { - // Try fast Smi addition first. - Node* pair = assembler->SmiAddWithOverflow(lhs, rhs); - Node* overflow = assembler->Projection(1, pair); - - // Check if the Smi additon overflowed. - Label if_overflow(assembler), if_notoverflow(assembler); - assembler->Branch(overflow, &if_overflow, &if_notoverflow); - - assembler->Bind(&if_overflow); - { - var_fadd_lhs.Bind(assembler->SmiToFloat64(lhs)); - var_fadd_rhs.Bind(assembler->SmiToFloat64(rhs)); - assembler->Goto(&do_fadd); - } - - assembler->Bind(&if_notoverflow); - var_result.Bind(assembler->Projection(0, pair)); - assembler->Goto(&end); - } - - assembler->Bind(&if_rhsisnotsmi); - { - // Load the map of {rhs}. - Node* rhs_map = assembler->LoadMap(rhs); - - // Check if the {rhs} is a HeapNumber. - Label if_rhsisnumber(assembler), - if_rhsisnotnumber(assembler, Label::kDeferred); - assembler->Branch(assembler->IsHeapNumberMap(rhs_map), &if_rhsisnumber, - &if_rhsisnotnumber); - - assembler->Bind(&if_rhsisnumber); - { - var_fadd_lhs.Bind(assembler->SmiToFloat64(lhs)); - var_fadd_rhs.Bind(assembler->LoadHeapNumberValue(rhs)); - assembler->Goto(&do_fadd); - } - - assembler->Bind(&if_rhsisnotnumber); - { - // Load the instance type of {rhs}. - Node* rhs_instance_type = assembler->LoadMapInstanceType(rhs_map); - - // Check if the {rhs} is a String. - Label if_rhsisstring(assembler, Label::kDeferred), - if_rhsisnotstring(assembler, Label::kDeferred); - assembler->Branch(assembler->IsStringInstanceType(rhs_instance_type), - &if_rhsisstring, &if_rhsisnotstring); - - assembler->Bind(&if_rhsisstring); - { - var_lhs.Bind(lhs); - var_rhs.Bind(rhs); - assembler->Goto(&string_add_convert_left); - } - - assembler->Bind(&if_rhsisnotstring); - { - // Check if {rhs} is a JSReceiver. - Label if_rhsisreceiver(assembler, Label::kDeferred), - if_rhsisnotreceiver(assembler, Label::kDeferred); - assembler->Branch( - assembler->IsJSReceiverInstanceType(rhs_instance_type), - &if_rhsisreceiver, &if_rhsisnotreceiver); - - assembler->Bind(&if_rhsisreceiver); - { - // Convert {rhs} to a primitive first passing no hint. - Callable callable = - CodeFactory::NonPrimitiveToPrimitive(assembler->isolate()); - var_rhs.Bind(assembler->CallStub(callable, context, rhs)); - assembler->Goto(&loop); - } - - assembler->Bind(&if_rhsisnotreceiver); - { - // Convert {rhs} to a Number first. - Callable callable = - CodeFactory::NonNumberToNumber(assembler->isolate()); - var_rhs.Bind(assembler->CallStub(callable, context, rhs)); - assembler->Goto(&loop); - } - } - } - } - } - - assembler->Bind(&if_lhsisnotsmi); - { - // Load the map and instance type of {lhs}. - Node* lhs_instance_type = assembler->LoadInstanceType(lhs); - - // Check if {lhs} is a String. - Label if_lhsisstring(assembler), if_lhsisnotstring(assembler); - assembler->Branch(assembler->IsStringInstanceType(lhs_instance_type), - &if_lhsisstring, &if_lhsisnotstring); - - assembler->Bind(&if_lhsisstring); - { - var_lhs.Bind(lhs); - var_rhs.Bind(rhs); - assembler->Goto(&string_add_convert_right); - } - - assembler->Bind(&if_lhsisnotstring); - { - // Check if {rhs} is a Smi. - Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler); - assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi, - &if_rhsisnotsmi); - - assembler->Bind(&if_rhsissmi); - { - // Check if {lhs} is a Number. - Label if_lhsisnumber(assembler), - if_lhsisnotnumber(assembler, Label::kDeferred); - assembler->Branch(assembler->Word32Equal( - lhs_instance_type, - assembler->Int32Constant(HEAP_NUMBER_TYPE)), - &if_lhsisnumber, &if_lhsisnotnumber); - - assembler->Bind(&if_lhsisnumber); - { - // The {lhs} is a HeapNumber, the {rhs} is a Smi, just add them. - var_fadd_lhs.Bind(assembler->LoadHeapNumberValue(lhs)); - var_fadd_rhs.Bind(assembler->SmiToFloat64(rhs)); - assembler->Goto(&do_fadd); - } - - assembler->Bind(&if_lhsisnotnumber); - { - // The {lhs} is neither a Number nor a String, and the {rhs} is a - // Smi. - Label if_lhsisreceiver(assembler, Label::kDeferred), - if_lhsisnotreceiver(assembler, Label::kDeferred); - assembler->Branch( - assembler->IsJSReceiverInstanceType(lhs_instance_type), - &if_lhsisreceiver, &if_lhsisnotreceiver); - - assembler->Bind(&if_lhsisreceiver); - { - // Convert {lhs} to a primitive first passing no hint. - Callable callable = - CodeFactory::NonPrimitiveToPrimitive(assembler->isolate()); - var_lhs.Bind(assembler->CallStub(callable, context, lhs)); - assembler->Goto(&loop); - } - - assembler->Bind(&if_lhsisnotreceiver); - { - // Convert {lhs} to a Number first. - Callable callable = - CodeFactory::NonNumberToNumber(assembler->isolate()); - var_lhs.Bind(assembler->CallStub(callable, context, lhs)); - assembler->Goto(&loop); - } - } - } - - assembler->Bind(&if_rhsisnotsmi); - { - // Load the instance type of {rhs}. - Node* rhs_instance_type = assembler->LoadInstanceType(rhs); - - // Check if {rhs} is a String. - Label if_rhsisstring(assembler), if_rhsisnotstring(assembler); - assembler->Branch(assembler->IsStringInstanceType(rhs_instance_type), - &if_rhsisstring, &if_rhsisnotstring); - - assembler->Bind(&if_rhsisstring); - { - var_lhs.Bind(lhs); - var_rhs.Bind(rhs); - assembler->Goto(&string_add_convert_left); - } - - assembler->Bind(&if_rhsisnotstring); - { - // Check if {lhs} is a HeapNumber. - Label if_lhsisnumber(assembler), if_lhsisnotnumber(assembler); - assembler->Branch(assembler->Word32Equal( - lhs_instance_type, - assembler->Int32Constant(HEAP_NUMBER_TYPE)), - &if_lhsisnumber, &if_lhsisnotnumber); - - assembler->Bind(&if_lhsisnumber); - { - // Check if {rhs} is also a HeapNumber. - Label if_rhsisnumber(assembler), - if_rhsisnotnumber(assembler, Label::kDeferred); - assembler->Branch(assembler->Word32Equal( - rhs_instance_type, - assembler->Int32Constant(HEAP_NUMBER_TYPE)), - &if_rhsisnumber, &if_rhsisnotnumber); - - assembler->Bind(&if_rhsisnumber); - { - // Perform a floating point addition. - var_fadd_lhs.Bind(assembler->LoadHeapNumberValue(lhs)); - var_fadd_rhs.Bind(assembler->LoadHeapNumberValue(rhs)); - assembler->Goto(&do_fadd); - } - - assembler->Bind(&if_rhsisnotnumber); - { - // Check if {rhs} is a JSReceiver. - Label if_rhsisreceiver(assembler, Label::kDeferred), - if_rhsisnotreceiver(assembler, Label::kDeferred); - assembler->Branch( - assembler->IsJSReceiverInstanceType(rhs_instance_type), - &if_rhsisreceiver, &if_rhsisnotreceiver); - - assembler->Bind(&if_rhsisreceiver); - { - // Convert {rhs} to a primitive first passing no hint. - Callable callable = CodeFactory::NonPrimitiveToPrimitive( - assembler->isolate()); - var_rhs.Bind(assembler->CallStub(callable, context, rhs)); - assembler->Goto(&loop); - } - - assembler->Bind(&if_rhsisnotreceiver); - { - // Convert {rhs} to a Number first. - Callable callable = - CodeFactory::NonNumberToNumber(assembler->isolate()); - var_rhs.Bind(assembler->CallStub(callable, context, rhs)); - assembler->Goto(&loop); - } - } - } - - assembler->Bind(&if_lhsisnotnumber); - { - // Check if {lhs} is a JSReceiver. - Label if_lhsisreceiver(assembler, Label::kDeferred), - if_lhsisnotreceiver(assembler); - assembler->Branch( - assembler->IsJSReceiverInstanceType(lhs_instance_type), - &if_lhsisreceiver, &if_lhsisnotreceiver); - - assembler->Bind(&if_lhsisreceiver); - { - // Convert {lhs} to a primitive first passing no hint. - Callable callable = - CodeFactory::NonPrimitiveToPrimitive(assembler->isolate()); - var_lhs.Bind(assembler->CallStub(callable, context, lhs)); - assembler->Goto(&loop); - } - - assembler->Bind(&if_lhsisnotreceiver); - { - // Check if {rhs} is a JSReceiver. - Label if_rhsisreceiver(assembler, Label::kDeferred), - if_rhsisnotreceiver(assembler, Label::kDeferred); - assembler->Branch( - assembler->IsJSReceiverInstanceType(rhs_instance_type), - &if_rhsisreceiver, &if_rhsisnotreceiver); - - assembler->Bind(&if_rhsisreceiver); - { - // Convert {rhs} to a primitive first passing no hint. - Callable callable = CodeFactory::NonPrimitiveToPrimitive( - assembler->isolate()); - var_rhs.Bind(assembler->CallStub(callable, context, rhs)); - assembler->Goto(&loop); - } - - assembler->Bind(&if_rhsisnotreceiver); - { - // Convert {lhs} to a Number first. - Callable callable = - CodeFactory::NonNumberToNumber(assembler->isolate()); - var_lhs.Bind(assembler->CallStub(callable, context, lhs)); - assembler->Goto(&loop); - } - } - } - } - } - } - } - } - assembler->Bind(&string_add_convert_left); - { - // Convert {lhs}, which is a Smi, to a String and concatenate the - // resulting string with the String {rhs}. - Callable callable = CodeFactory::StringAdd( - assembler->isolate(), STRING_ADD_CONVERT_LEFT, NOT_TENURED); - var_result.Bind(assembler->CallStub(callable, context, var_lhs.value(), - var_rhs.value())); - assembler->Goto(&end); - } - - assembler->Bind(&string_add_convert_right); - { - // Convert {lhs}, which is a Smi, to a String and concatenate the - // resulting string with the String {rhs}. - Callable callable = CodeFactory::StringAdd( - assembler->isolate(), STRING_ADD_CONVERT_RIGHT, NOT_TENURED); - var_result.Bind(assembler->CallStub(callable, context, var_lhs.value(), - var_rhs.value())); - assembler->Goto(&end); - } - - assembler->Bind(&do_fadd); - { - Node* lhs_value = var_fadd_lhs.value(); - Node* rhs_value = var_fadd_rhs.value(); - Node* value = assembler->Float64Add(lhs_value, rhs_value); - Node* result = assembler->ChangeFloat64ToTagged(value); - var_result.Bind(result); - assembler->Goto(&end); - } - assembler->Bind(&end); - return var_result.value(); -} - -// static compiler::Node* AddWithFeedbackStub::Generate( CodeStubAssembler* assembler, compiler::Node* lhs, compiler::Node* rhs, compiler::Node* slot_id, compiler::Node* type_feedback_vector, @@ -1033,8 +726,10 @@ compiler::Node* AddWithFeedbackStub::Generate( typedef CodeStubAssembler::Variable Variable; // Shared entry for floating point addition. - Label do_fadd(assembler), end(assembler), - do_add_any(assembler, Label::kDeferred), call_add_stub(assembler); + Label do_fadd(assembler), if_lhsisnotnumber(assembler, Label::kDeferred), + check_rhsisoddball(assembler, Label::kDeferred), + call_with_oddball_feedback(assembler), call_with_any_feedback(assembler), + call_add_stub(assembler), end(assembler); Variable var_fadd_lhs(assembler, MachineRepresentation::kFloat64), var_fadd_rhs(assembler, MachineRepresentation::kFloat64), var_type_feedback(assembler, MachineRepresentation::kWord32), @@ -1042,18 +737,21 @@ compiler::Node* AddWithFeedbackStub::Generate( // Check if the {lhs} is a Smi or a HeapObject. Label if_lhsissmi(assembler), if_lhsisnotsmi(assembler); - assembler->Branch(assembler->WordIsSmi(lhs), &if_lhsissmi, &if_lhsisnotsmi); + assembler->Branch(assembler->TaggedIsSmi(lhs), &if_lhsissmi, &if_lhsisnotsmi); assembler->Bind(&if_lhsissmi); { // Check if the {rhs} is also a Smi. Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler); - assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi, &if_rhsisnotsmi); + assembler->Branch(assembler->TaggedIsSmi(rhs), &if_rhsissmi, + &if_rhsisnotsmi); assembler->Bind(&if_rhsissmi); { // Try fast Smi addition first. - Node* pair = assembler->SmiAddWithOverflow(lhs, rhs); + Node* pair = + assembler->IntPtrAddWithOverflow(assembler->BitcastTaggedToWord(lhs), + assembler->BitcastTaggedToWord(rhs)); Node* overflow = assembler->Projection(1, pair); // Check if the Smi additon overflowed. @@ -1071,7 +769,8 @@ compiler::Node* AddWithFeedbackStub::Generate( { var_type_feedback.Bind( assembler->Int32Constant(BinaryOperationFeedback::kSignedSmall)); - var_result.Bind(assembler->Projection(0, pair)); + var_result.Bind(assembler->BitcastWordToTaggedSigned( + assembler->Projection(0, pair))); assembler->Goto(&end); } } @@ -1082,7 +781,8 @@ compiler::Node* AddWithFeedbackStub::Generate( Node* rhs_map = assembler->LoadMap(rhs); // Check if the {rhs} is a HeapNumber. - assembler->GotoUnless(assembler->IsHeapNumberMap(rhs_map), &do_add_any); + assembler->GotoUnless(assembler->IsHeapNumberMap(rhs_map), + &check_rhsisoddball); var_fadd_lhs.Bind(assembler->SmiToFloat64(lhs)); var_fadd_rhs.Bind(assembler->LoadHeapNumberValue(rhs)); @@ -1092,18 +792,17 @@ compiler::Node* AddWithFeedbackStub::Generate( assembler->Bind(&if_lhsisnotsmi); { - Label check_string(assembler); - // Load the map of {lhs}. Node* lhs_map = assembler->LoadMap(lhs); // Check if {lhs} is a HeapNumber. - Label if_lhsisnumber(assembler), if_lhsisnotnumber(assembler); - assembler->GotoUnless(assembler->IsHeapNumberMap(lhs_map), &check_string); + assembler->GotoUnless(assembler->IsHeapNumberMap(lhs_map), + &if_lhsisnotnumber); // Check if the {rhs} is Smi. Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler); - assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi, &if_rhsisnotsmi); + assembler->Branch(assembler->TaggedIsSmi(rhs), &if_rhsissmi, + &if_rhsisnotsmi); assembler->Bind(&if_rhsissmi); { @@ -1118,48 +817,93 @@ compiler::Node* AddWithFeedbackStub::Generate( Node* rhs_map = assembler->LoadMap(rhs); // Check if the {rhs} is a HeapNumber. - assembler->GotoUnless(assembler->IsHeapNumberMap(rhs_map), &do_add_any); + assembler->GotoUnless(assembler->IsHeapNumberMap(rhs_map), + &check_rhsisoddball); var_fadd_lhs.Bind(assembler->LoadHeapNumberValue(lhs)); var_fadd_rhs.Bind(assembler->LoadHeapNumberValue(rhs)); assembler->Goto(&do_fadd); } + } + + assembler->Bind(&do_fadd); + { + var_type_feedback.Bind( + assembler->Int32Constant(BinaryOperationFeedback::kNumber)); + Node* value = + assembler->Float64Add(var_fadd_lhs.value(), var_fadd_rhs.value()); + Node* result = assembler->AllocateHeapNumberWithValue(value); + var_result.Bind(result); + assembler->Goto(&end); + } - assembler->Bind(&check_string); + assembler->Bind(&if_lhsisnotnumber); + { + // No checks on rhs are done yet. We just know lhs is not a number or Smi. + Label if_lhsisoddball(assembler), if_lhsisnotoddball(assembler); + Node* lhs_instance_type = assembler->LoadInstanceType(lhs); + Node* lhs_is_oddball = assembler->Word32Equal( + lhs_instance_type, assembler->Int32Constant(ODDBALL_TYPE)); + assembler->Branch(lhs_is_oddball, &if_lhsisoddball, &if_lhsisnotoddball); + + assembler->Bind(&if_lhsisoddball); { - // Check if the {rhs} is a smi, and exit the string check early if it is. - assembler->GotoIf(assembler->WordIsSmi(rhs), &do_add_any); + assembler->GotoIf(assembler->TaggedIsSmi(rhs), + &call_with_oddball_feedback); - Node* lhs_instance_type = assembler->LoadMapInstanceType(lhs_map); + // Load the map of the {rhs}. + Node* rhs_map = assembler->LoadMap(rhs); + // Check if {rhs} is a HeapNumber. + assembler->Branch(assembler->IsHeapNumberMap(rhs_map), + &call_with_oddball_feedback, &check_rhsisoddball); + } + + assembler->Bind(&if_lhsisnotoddball); + { // Exit unless {lhs} is a string assembler->GotoUnless(assembler->IsStringInstanceType(lhs_instance_type), - &do_add_any); + &call_with_any_feedback); + + // Check if the {rhs} is a smi, and exit the string check early if it is. + assembler->GotoIf(assembler->TaggedIsSmi(rhs), &call_with_any_feedback); Node* rhs_instance_type = assembler->LoadInstanceType(rhs); - // Exit unless {rhs} is a string + // Exit unless {rhs} is a string. Since {lhs} is a string we no longer + // need an Oddball check. assembler->GotoUnless(assembler->IsStringInstanceType(rhs_instance_type), - &do_add_any); + &call_with_any_feedback); var_type_feedback.Bind( assembler->Int32Constant(BinaryOperationFeedback::kString)); - assembler->Goto(&call_add_stub); + Callable callable = CodeFactory::StringAdd( + assembler->isolate(), STRING_ADD_CHECK_NONE, NOT_TENURED); + var_result.Bind(assembler->CallStub(callable, context, lhs, rhs)); + + assembler->Goto(&end); } } - assembler->Bind(&do_fadd); + assembler->Bind(&check_rhsisoddball); + { + // Check if rhs is an oddball. At this point we know lhs is either a + // Smi or number or oddball and rhs is not a number or Smi. + Node* rhs_instance_type = assembler->LoadInstanceType(rhs); + Node* rhs_is_oddball = assembler->Word32Equal( + rhs_instance_type, assembler->Int32Constant(ODDBALL_TYPE)); + assembler->Branch(rhs_is_oddball, &call_with_oddball_feedback, + &call_with_any_feedback); + } + + assembler->Bind(&call_with_oddball_feedback); { var_type_feedback.Bind( - assembler->Int32Constant(BinaryOperationFeedback::kNumber)); - Node* value = - assembler->Float64Add(var_fadd_lhs.value(), var_fadd_rhs.value()); - Node* result = assembler->ChangeFloat64ToTagged(value); - var_result.Bind(result); - assembler->Goto(&end); + assembler->Int32Constant(BinaryOperationFeedback::kNumberOrOddball)); + assembler->Goto(&call_add_stub); } - assembler->Bind(&do_add_any); + assembler->Bind(&call_with_any_feedback); { var_type_feedback.Bind( assembler->Int32Constant(BinaryOperationFeedback::kAny)); @@ -1180,180 +924,6 @@ compiler::Node* AddWithFeedbackStub::Generate( } // static -compiler::Node* SubtractStub::Generate(CodeStubAssembler* assembler, - compiler::Node* left, - compiler::Node* right, - compiler::Node* context) { - typedef CodeStubAssembler::Label Label; - typedef compiler::Node Node; - typedef CodeStubAssembler::Variable Variable; - - // Shared entry for floating point subtraction. - Label do_fsub(assembler), end(assembler); - Variable var_fsub_lhs(assembler, MachineRepresentation::kFloat64), - var_fsub_rhs(assembler, MachineRepresentation::kFloat64); - - // We might need to loop several times due to ToPrimitive and/or ToNumber - // conversions. - Variable var_lhs(assembler, MachineRepresentation::kTagged), - var_rhs(assembler, MachineRepresentation::kTagged), - var_result(assembler, MachineRepresentation::kTagged); - Variable* loop_vars[2] = {&var_lhs, &var_rhs}; - Label loop(assembler, 2, loop_vars); - var_lhs.Bind(left); - var_rhs.Bind(right); - assembler->Goto(&loop); - assembler->Bind(&loop); - { - // Load the current {lhs} and {rhs} values. - Node* lhs = var_lhs.value(); - Node* rhs = var_rhs.value(); - - // Check if the {lhs} is a Smi or a HeapObject. - Label if_lhsissmi(assembler), if_lhsisnotsmi(assembler); - assembler->Branch(assembler->WordIsSmi(lhs), &if_lhsissmi, &if_lhsisnotsmi); - - assembler->Bind(&if_lhsissmi); - { - // Check if the {rhs} is also a Smi. - Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler); - assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi, - &if_rhsisnotsmi); - - assembler->Bind(&if_rhsissmi); - { - // Try a fast Smi subtraction first. - Node* pair = assembler->SmiSubWithOverflow(lhs, rhs); - Node* overflow = assembler->Projection(1, pair); - - // Check if the Smi subtraction overflowed. - Label if_overflow(assembler), if_notoverflow(assembler); - assembler->Branch(overflow, &if_overflow, &if_notoverflow); - - assembler->Bind(&if_overflow); - { - // The result doesn't fit into Smi range. - var_fsub_lhs.Bind(assembler->SmiToFloat64(lhs)); - var_fsub_rhs.Bind(assembler->SmiToFloat64(rhs)); - assembler->Goto(&do_fsub); - } - - assembler->Bind(&if_notoverflow); - var_result.Bind(assembler->Projection(0, pair)); - assembler->Goto(&end); - } - - assembler->Bind(&if_rhsisnotsmi); - { - // Load the map of the {rhs}. - Node* rhs_map = assembler->LoadMap(rhs); - - // Check if {rhs} is a HeapNumber. - Label if_rhsisnumber(assembler), - if_rhsisnotnumber(assembler, Label::kDeferred); - assembler->Branch(assembler->IsHeapNumberMap(rhs_map), &if_rhsisnumber, - &if_rhsisnotnumber); - - assembler->Bind(&if_rhsisnumber); - { - // Perform a floating point subtraction. - var_fsub_lhs.Bind(assembler->SmiToFloat64(lhs)); - var_fsub_rhs.Bind(assembler->LoadHeapNumberValue(rhs)); - assembler->Goto(&do_fsub); - } - - assembler->Bind(&if_rhsisnotnumber); - { - // Convert the {rhs} to a Number first. - Callable callable = - CodeFactory::NonNumberToNumber(assembler->isolate()); - var_rhs.Bind(assembler->CallStub(callable, context, rhs)); - assembler->Goto(&loop); - } - } - } - - assembler->Bind(&if_lhsisnotsmi); - { - // Load the map of the {lhs}. - Node* lhs_map = assembler->LoadMap(lhs); - - // Check if the {lhs} is a HeapNumber. - Label if_lhsisnumber(assembler), - if_lhsisnotnumber(assembler, Label::kDeferred); - Node* number_map = assembler->HeapNumberMapConstant(); - assembler->Branch(assembler->WordEqual(lhs_map, number_map), - &if_lhsisnumber, &if_lhsisnotnumber); - - assembler->Bind(&if_lhsisnumber); - { - // Check if the {rhs} is a Smi. - Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler); - assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi, - &if_rhsisnotsmi); - - assembler->Bind(&if_rhsissmi); - { - // Perform a floating point subtraction. - var_fsub_lhs.Bind(assembler->LoadHeapNumberValue(lhs)); - var_fsub_rhs.Bind(assembler->SmiToFloat64(rhs)); - assembler->Goto(&do_fsub); - } - - assembler->Bind(&if_rhsisnotsmi); - { - // Load the map of the {rhs}. - Node* rhs_map = assembler->LoadMap(rhs); - - // Check if the {rhs} is a HeapNumber. - Label if_rhsisnumber(assembler), - if_rhsisnotnumber(assembler, Label::kDeferred); - assembler->Branch(assembler->WordEqual(rhs_map, number_map), - &if_rhsisnumber, &if_rhsisnotnumber); - - assembler->Bind(&if_rhsisnumber); - { - // Perform a floating point subtraction. - var_fsub_lhs.Bind(assembler->LoadHeapNumberValue(lhs)); - var_fsub_rhs.Bind(assembler->LoadHeapNumberValue(rhs)); - assembler->Goto(&do_fsub); - } - - assembler->Bind(&if_rhsisnotnumber); - { - // Convert the {rhs} to a Number first. - Callable callable = - CodeFactory::NonNumberToNumber(assembler->isolate()); - var_rhs.Bind(assembler->CallStub(callable, context, rhs)); - assembler->Goto(&loop); - } - } - } - - assembler->Bind(&if_lhsisnotnumber); - { - // Convert the {lhs} to a Number first. - Callable callable = - CodeFactory::NonNumberToNumber(assembler->isolate()); - var_lhs.Bind(assembler->CallStub(callable, context, lhs)); - assembler->Goto(&loop); - } - } - } - - assembler->Bind(&do_fsub); - { - Node* lhs_value = var_fsub_lhs.value(); - Node* rhs_value = var_fsub_rhs.value(); - Node* value = assembler->Float64Sub(lhs_value, rhs_value); - var_result.Bind(assembler->ChangeFloat64ToTagged(value)); - assembler->Goto(&end); - } - assembler->Bind(&end); - return var_result.value(); -} - -// static compiler::Node* SubtractWithFeedbackStub::Generate( CodeStubAssembler* assembler, compiler::Node* lhs, compiler::Node* rhs, compiler::Node* slot_id, compiler::Node* type_feedback_vector, @@ -1363,8 +933,9 @@ compiler::Node* SubtractWithFeedbackStub::Generate( typedef CodeStubAssembler::Variable Variable; // Shared entry for floating point subtraction. - Label do_fsub(assembler), end(assembler), - call_subtract_stub(assembler, Label::kDeferred); + Label do_fsub(assembler), end(assembler), call_subtract_stub(assembler), + if_lhsisnotnumber(assembler), check_rhsisoddball(assembler), + call_with_any_feedback(assembler); Variable var_fsub_lhs(assembler, MachineRepresentation::kFloat64), var_fsub_rhs(assembler, MachineRepresentation::kFloat64), var_type_feedback(assembler, MachineRepresentation::kWord32), @@ -1372,18 +943,21 @@ compiler::Node* SubtractWithFeedbackStub::Generate( // Check if the {lhs} is a Smi or a HeapObject. Label if_lhsissmi(assembler), if_lhsisnotsmi(assembler); - assembler->Branch(assembler->WordIsSmi(lhs), &if_lhsissmi, &if_lhsisnotsmi); + assembler->Branch(assembler->TaggedIsSmi(lhs), &if_lhsissmi, &if_lhsisnotsmi); assembler->Bind(&if_lhsissmi); { // Check if the {rhs} is also a Smi. Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler); - assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi, &if_rhsisnotsmi); + assembler->Branch(assembler->TaggedIsSmi(rhs), &if_rhsissmi, + &if_rhsisnotsmi); assembler->Bind(&if_rhsissmi); { // Try a fast Smi subtraction first. - Node* pair = assembler->SmiSubWithOverflow(lhs, rhs); + Node* pair = + assembler->IntPtrSubWithOverflow(assembler->BitcastTaggedToWord(lhs), + assembler->BitcastTaggedToWord(rhs)); Node* overflow = assembler->Projection(1, pair); // Check if the Smi subtraction overflowed. @@ -1403,7 +977,8 @@ compiler::Node* SubtractWithFeedbackStub::Generate( // lhs, rhs, result smi. combined - smi. var_type_feedback.Bind( assembler->Int32Constant(BinaryOperationFeedback::kSignedSmall)); - var_result.Bind(assembler->Projection(0, pair)); + var_result.Bind( + assembler->BitcastWordToTaggedSigned(assembler->Projection(0, pair))); assembler->Goto(&end); } @@ -1414,7 +989,7 @@ compiler::Node* SubtractWithFeedbackStub::Generate( // Check if {rhs} is a HeapNumber. assembler->GotoUnless(assembler->IsHeapNumberMap(rhs_map), - &call_subtract_stub); + &check_rhsisoddball); // Perform a floating point subtraction. var_fsub_lhs.Bind(assembler->SmiToFloat64(lhs)); @@ -1430,11 +1005,12 @@ compiler::Node* SubtractWithFeedbackStub::Generate( // Check if the {lhs} is a HeapNumber. assembler->GotoUnless(assembler->IsHeapNumberMap(lhs_map), - &call_subtract_stub); + &if_lhsisnotnumber); // Check if the {rhs} is a Smi. Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler); - assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi, &if_rhsisnotsmi); + assembler->Branch(assembler->TaggedIsSmi(rhs), &if_rhsissmi, + &if_rhsisnotsmi); assembler->Bind(&if_rhsissmi); { @@ -1451,7 +1027,7 @@ compiler::Node* SubtractWithFeedbackStub::Generate( // Check if the {rhs} is a HeapNumber. assembler->GotoUnless(assembler->IsHeapNumberMap(rhs_map), - &call_subtract_stub); + &check_rhsisoddball); // Perform a floating point subtraction. var_fsub_lhs.Bind(assembler->LoadHeapNumberValue(lhs)); @@ -1467,178 +1043,80 @@ compiler::Node* SubtractWithFeedbackStub::Generate( Node* lhs_value = var_fsub_lhs.value(); Node* rhs_value = var_fsub_rhs.value(); Node* value = assembler->Float64Sub(lhs_value, rhs_value); - var_result.Bind(assembler->ChangeFloat64ToTagged(value)); + var_result.Bind(assembler->AllocateHeapNumberWithValue(value)); assembler->Goto(&end); } - assembler->Bind(&call_subtract_stub); + assembler->Bind(&if_lhsisnotnumber); { - var_type_feedback.Bind( - assembler->Int32Constant(BinaryOperationFeedback::kAny)); - Callable callable = CodeFactory::Subtract(assembler->isolate()); - var_result.Bind(assembler->CallStub(callable, context, lhs, rhs)); - assembler->Goto(&end); - } + // No checks on rhs are done yet. We just know lhs is not a number or Smi. + // Check if lhs is an oddball. + Node* lhs_instance_type = assembler->LoadInstanceType(lhs); + Node* lhs_is_oddball = assembler->Word32Equal( + lhs_instance_type, assembler->Int32Constant(ODDBALL_TYPE)); + assembler->GotoUnless(lhs_is_oddball, &call_with_any_feedback); - assembler->Bind(&end); - assembler->UpdateFeedback(var_type_feedback.value(), type_feedback_vector, - slot_id); - return var_result.value(); -} - -// static -compiler::Node* MultiplyStub::Generate(CodeStubAssembler* assembler, - compiler::Node* left, - compiler::Node* right, - compiler::Node* context) { - using compiler::Node; - typedef CodeStubAssembler::Label Label; - typedef CodeStubAssembler::Variable Variable; - - // Shared entry point for floating point multiplication. - Label do_fmul(assembler), return_result(assembler); - Variable var_lhs_float64(assembler, MachineRepresentation::kFloat64), - var_rhs_float64(assembler, MachineRepresentation::kFloat64); - - Node* number_map = assembler->HeapNumberMapConstant(); - - // We might need to loop one or two times due to ToNumber conversions. - Variable var_lhs(assembler, MachineRepresentation::kTagged), - var_rhs(assembler, MachineRepresentation::kTagged), - var_result(assembler, MachineRepresentation::kTagged); - Variable* loop_variables[] = {&var_lhs, &var_rhs}; - Label loop(assembler, 2, loop_variables); - var_lhs.Bind(left); - var_rhs.Bind(right); - assembler->Goto(&loop); - assembler->Bind(&loop); - { - Node* lhs = var_lhs.value(); - Node* rhs = var_rhs.value(); - - Label lhs_is_smi(assembler), lhs_is_not_smi(assembler); - assembler->Branch(assembler->WordIsSmi(lhs), &lhs_is_smi, &lhs_is_not_smi); + Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler); + assembler->Branch(assembler->TaggedIsSmi(rhs), &if_rhsissmi, + &if_rhsisnotsmi); - assembler->Bind(&lhs_is_smi); + assembler->Bind(&if_rhsissmi); { - Label rhs_is_smi(assembler), rhs_is_not_smi(assembler); - assembler->Branch(assembler->WordIsSmi(rhs), &rhs_is_smi, - &rhs_is_not_smi); - - assembler->Bind(&rhs_is_smi); - { - // Both {lhs} and {rhs} are Smis. The result is not necessarily a smi, - // in case of overflow. - var_result.Bind(assembler->SmiMul(lhs, rhs)); - assembler->Goto(&return_result); - } - - assembler->Bind(&rhs_is_not_smi); - { - Node* rhs_map = assembler->LoadMap(rhs); - - // Check if {rhs} is a HeapNumber. - Label rhs_is_number(assembler), - rhs_is_not_number(assembler, Label::kDeferred); - assembler->Branch(assembler->WordEqual(rhs_map, number_map), - &rhs_is_number, &rhs_is_not_number); - - assembler->Bind(&rhs_is_number); - { - // Convert {lhs} to a double and multiply it with the value of {rhs}. - var_lhs_float64.Bind(assembler->SmiToFloat64(lhs)); - var_rhs_float64.Bind(assembler->LoadHeapNumberValue(rhs)); - assembler->Goto(&do_fmul); - } - - assembler->Bind(&rhs_is_not_number); - { - // Multiplication is commutative, swap {lhs} with {rhs} and loop. - var_lhs.Bind(rhs); - var_rhs.Bind(lhs); - assembler->Goto(&loop); - } - } + var_type_feedback.Bind( + assembler->Int32Constant(BinaryOperationFeedback::kNumberOrOddball)); + assembler->Goto(&call_subtract_stub); } - assembler->Bind(&lhs_is_not_smi); + assembler->Bind(&if_rhsisnotsmi); { - Node* lhs_map = assembler->LoadMap(lhs); + // Load the map of the {rhs}. + Node* rhs_map = assembler->LoadMap(rhs); - // Check if {lhs} is a HeapNumber. - Label lhs_is_number(assembler), - lhs_is_not_number(assembler, Label::kDeferred); - assembler->Branch(assembler->WordEqual(lhs_map, number_map), - &lhs_is_number, &lhs_is_not_number); + // Check if {rhs} is a HeapNumber. + assembler->GotoUnless(assembler->IsHeapNumberMap(rhs_map), + &check_rhsisoddball); - assembler->Bind(&lhs_is_number); - { - // Check if {rhs} is a Smi. - Label rhs_is_smi(assembler), rhs_is_not_smi(assembler); - assembler->Branch(assembler->WordIsSmi(rhs), &rhs_is_smi, - &rhs_is_not_smi); + var_type_feedback.Bind( + assembler->Int32Constant(BinaryOperationFeedback::kNumberOrOddball)); + assembler->Goto(&call_subtract_stub); + } + } - assembler->Bind(&rhs_is_smi); - { - // Convert {rhs} to a double and multiply it with the value of {lhs}. - var_lhs_float64.Bind(assembler->LoadHeapNumberValue(lhs)); - var_rhs_float64.Bind(assembler->SmiToFloat64(rhs)); - assembler->Goto(&do_fmul); - } + assembler->Bind(&check_rhsisoddball); + { + // Check if rhs is an oddball. At this point we know lhs is either a + // Smi or number or oddball and rhs is not a number or Smi. + Node* rhs_instance_type = assembler->LoadInstanceType(rhs); + Node* rhs_is_oddball = assembler->Word32Equal( + rhs_instance_type, assembler->Int32Constant(ODDBALL_TYPE)); + assembler->GotoUnless(rhs_is_oddball, &call_with_any_feedback); - assembler->Bind(&rhs_is_not_smi); - { - Node* rhs_map = assembler->LoadMap(rhs); - - // Check if {rhs} is a HeapNumber. - Label rhs_is_number(assembler), - rhs_is_not_number(assembler, Label::kDeferred); - assembler->Branch(assembler->WordEqual(rhs_map, number_map), - &rhs_is_number, &rhs_is_not_number); - - assembler->Bind(&rhs_is_number); - { - // Both {lhs} and {rhs} are HeapNumbers. Load their values and - // multiply them. - var_lhs_float64.Bind(assembler->LoadHeapNumberValue(lhs)); - var_rhs_float64.Bind(assembler->LoadHeapNumberValue(rhs)); - assembler->Goto(&do_fmul); - } - - assembler->Bind(&rhs_is_not_number); - { - // Multiplication is commutative, swap {lhs} with {rhs} and loop. - var_lhs.Bind(rhs); - var_rhs.Bind(lhs); - assembler->Goto(&loop); - } - } - } + var_type_feedback.Bind( + assembler->Int32Constant(BinaryOperationFeedback::kNumberOrOddball)); + assembler->Goto(&call_subtract_stub); + } - assembler->Bind(&lhs_is_not_number); - { - // Convert {lhs} to a Number and loop. - Callable callable = - CodeFactory::NonNumberToNumber(assembler->isolate()); - var_lhs.Bind(assembler->CallStub(callable, context, lhs)); - assembler->Goto(&loop); - } - } + assembler->Bind(&call_with_any_feedback); + { + var_type_feedback.Bind( + assembler->Int32Constant(BinaryOperationFeedback::kAny)); + assembler->Goto(&call_subtract_stub); } - assembler->Bind(&do_fmul); + assembler->Bind(&call_subtract_stub); { - Node* value = - assembler->Float64Mul(var_lhs_float64.value(), var_rhs_float64.value()); - Node* result = assembler->ChangeFloat64ToTagged(value); - var_result.Bind(result); - assembler->Goto(&return_result); + Callable callable = CodeFactory::Subtract(assembler->isolate()); + var_result.Bind(assembler->CallStub(callable, context, lhs, rhs)); + assembler->Goto(&end); } - assembler->Bind(&return_result); + assembler->Bind(&end); + assembler->UpdateFeedback(var_type_feedback.value(), type_feedback_vector, + slot_id); return var_result.value(); } + // static compiler::Node* MultiplyWithFeedbackStub::Generate( CodeStubAssembler* assembler, compiler::Node* lhs, compiler::Node* rhs, @@ -1649,8 +1127,10 @@ compiler::Node* MultiplyWithFeedbackStub::Generate( typedef CodeStubAssembler::Variable Variable; // Shared entry point for floating point multiplication. - Label do_fmul(assembler), end(assembler), - call_multiply_stub(assembler, Label::kDeferred); + Label do_fmul(assembler), if_lhsisnotnumber(assembler, Label::kDeferred), + check_rhsisoddball(assembler, Label::kDeferred), + call_with_oddball_feedback(assembler), call_with_any_feedback(assembler), + call_multiply_stub(assembler), end(assembler); Variable var_lhs_float64(assembler, MachineRepresentation::kFloat64), var_rhs_float64(assembler, MachineRepresentation::kFloat64), var_result(assembler, MachineRepresentation::kTagged), @@ -1659,12 +1139,13 @@ compiler::Node* MultiplyWithFeedbackStub::Generate( Node* number_map = assembler->HeapNumberMapConstant(); Label lhs_is_smi(assembler), lhs_is_not_smi(assembler); - assembler->Branch(assembler->WordIsSmi(lhs), &lhs_is_smi, &lhs_is_not_smi); + assembler->Branch(assembler->TaggedIsSmi(lhs), &lhs_is_smi, &lhs_is_not_smi); assembler->Bind(&lhs_is_smi); { Label rhs_is_smi(assembler), rhs_is_not_smi(assembler); - assembler->Branch(assembler->WordIsSmi(rhs), &rhs_is_smi, &rhs_is_not_smi); + assembler->Branch(assembler->TaggedIsSmi(rhs), &rhs_is_smi, + &rhs_is_not_smi); assembler->Bind(&rhs_is_smi); { @@ -1672,7 +1153,7 @@ compiler::Node* MultiplyWithFeedbackStub::Generate( // in case of overflow. var_result.Bind(assembler->SmiMul(lhs, rhs)); var_type_feedback.Bind(assembler->Select( - assembler->WordIsSmi(var_result.value()), + assembler->TaggedIsSmi(var_result.value()), assembler->Int32Constant(BinaryOperationFeedback::kSignedSmall), assembler->Int32Constant(BinaryOperationFeedback::kNumber), MachineRepresentation::kWord32)); @@ -1685,7 +1166,7 @@ compiler::Node* MultiplyWithFeedbackStub::Generate( // Check if {rhs} is a HeapNumber. assembler->GotoUnless(assembler->WordEqual(rhs_map, number_map), - &call_multiply_stub); + &check_rhsisoddball); // Convert {lhs} to a double and multiply it with the value of {rhs}. var_lhs_float64.Bind(assembler->SmiToFloat64(lhs)); @@ -1700,11 +1181,12 @@ compiler::Node* MultiplyWithFeedbackStub::Generate( // Check if {lhs} is a HeapNumber. assembler->GotoUnless(assembler->WordEqual(lhs_map, number_map), - &call_multiply_stub); + &if_lhsisnotnumber); // Check if {rhs} is a Smi. Label rhs_is_smi(assembler), rhs_is_not_smi(assembler); - assembler->Branch(assembler->WordIsSmi(rhs), &rhs_is_smi, &rhs_is_not_smi); + assembler->Branch(assembler->TaggedIsSmi(rhs), &rhs_is_smi, + &rhs_is_not_smi); assembler->Bind(&rhs_is_smi); { @@ -1720,7 +1202,7 @@ compiler::Node* MultiplyWithFeedbackStub::Generate( // Check if {rhs} is a HeapNumber. assembler->GotoUnless(assembler->WordEqual(rhs_map, number_map), - &call_multiply_stub); + &check_rhsisoddball); // Both {lhs} and {rhs} are HeapNumbers. Load their values and // multiply them. @@ -1736,244 +1218,69 @@ compiler::Node* MultiplyWithFeedbackStub::Generate( assembler->Int32Constant(BinaryOperationFeedback::kNumber)); Node* value = assembler->Float64Mul(var_lhs_float64.value(), var_rhs_float64.value()); - Node* result = assembler->ChangeFloat64ToTagged(value); + Node* result = assembler->AllocateHeapNumberWithValue(value); var_result.Bind(result); assembler->Goto(&end); } - assembler->Bind(&call_multiply_stub); + assembler->Bind(&if_lhsisnotnumber); { - var_type_feedback.Bind( - assembler->Int32Constant(BinaryOperationFeedback::kAny)); - Callable callable = CodeFactory::Multiply(assembler->isolate()); - var_result.Bind(assembler->CallStub(callable, context, lhs, rhs)); - assembler->Goto(&end); - } - - assembler->Bind(&end); - assembler->UpdateFeedback(var_type_feedback.value(), type_feedback_vector, - slot_id); - return var_result.value(); -} + // No checks on rhs are done yet. We just know lhs is not a number or Smi. + // Check if lhs is an oddball. + Node* lhs_instance_type = assembler->LoadInstanceType(lhs); + Node* lhs_is_oddball = assembler->Word32Equal( + lhs_instance_type, assembler->Int32Constant(ODDBALL_TYPE)); + assembler->GotoUnless(lhs_is_oddball, &call_with_any_feedback); -// static -compiler::Node* DivideStub::Generate(CodeStubAssembler* assembler, - compiler::Node* left, - compiler::Node* right, - compiler::Node* context) { - using compiler::Node; - typedef CodeStubAssembler::Label Label; - typedef CodeStubAssembler::Variable Variable; + assembler->GotoIf(assembler->TaggedIsSmi(rhs), &call_with_oddball_feedback); - // Shared entry point for floating point division. - Label do_fdiv(assembler), end(assembler); - Variable var_dividend_float64(assembler, MachineRepresentation::kFloat64), - var_divisor_float64(assembler, MachineRepresentation::kFloat64); + // Load the map of the {rhs}. + Node* rhs_map = assembler->LoadMap(rhs); - Node* number_map = assembler->HeapNumberMapConstant(); + // Check if {rhs} is a HeapNumber. + assembler->Branch(assembler->IsHeapNumberMap(rhs_map), + &call_with_oddball_feedback, &check_rhsisoddball); + } - // We might need to loop one or two times due to ToNumber conversions. - Variable var_dividend(assembler, MachineRepresentation::kTagged), - var_divisor(assembler, MachineRepresentation::kTagged), - var_result(assembler, MachineRepresentation::kTagged); - Variable* loop_variables[] = {&var_dividend, &var_divisor}; - Label loop(assembler, 2, loop_variables); - var_dividend.Bind(left); - var_divisor.Bind(right); - assembler->Goto(&loop); - assembler->Bind(&loop); + assembler->Bind(&check_rhsisoddball); { - Node* dividend = var_dividend.value(); - Node* divisor = var_divisor.value(); - - Label dividend_is_smi(assembler), dividend_is_not_smi(assembler); - assembler->Branch(assembler->WordIsSmi(dividend), ÷nd_is_smi, - ÷nd_is_not_smi); - - assembler->Bind(÷nd_is_smi); - { - Label divisor_is_smi(assembler), divisor_is_not_smi(assembler); - assembler->Branch(assembler->WordIsSmi(divisor), &divisor_is_smi, - &divisor_is_not_smi); - - assembler->Bind(&divisor_is_smi); - { - Label bailout(assembler); - - // Do floating point division if {divisor} is zero. - assembler->GotoIf( - assembler->WordEqual(divisor, assembler->IntPtrConstant(0)), - &bailout); - - // Do floating point division {dividend} is zero and {divisor} is - // negative. - Label dividend_is_zero(assembler), dividend_is_not_zero(assembler); - assembler->Branch( - assembler->WordEqual(dividend, assembler->IntPtrConstant(0)), - ÷nd_is_zero, ÷nd_is_not_zero); - - assembler->Bind(÷nd_is_zero); - { - assembler->GotoIf( - assembler->IntPtrLessThan(divisor, assembler->IntPtrConstant(0)), - &bailout); - assembler->Goto(÷nd_is_not_zero); - } - assembler->Bind(÷nd_is_not_zero); - - Node* untagged_divisor = assembler->SmiUntag(divisor); - Node* untagged_dividend = assembler->SmiUntag(dividend); - - // Do floating point division if {dividend} is kMinInt (or kMinInt - 1 - // if the Smi size is 31) and {divisor} is -1. - Label divisor_is_minus_one(assembler), - divisor_is_not_minus_one(assembler); - assembler->Branch(assembler->Word32Equal(untagged_divisor, - assembler->Int32Constant(-1)), - &divisor_is_minus_one, &divisor_is_not_minus_one); - - assembler->Bind(&divisor_is_minus_one); - { - assembler->GotoIf( - assembler->Word32Equal( - untagged_dividend, - assembler->Int32Constant( - kSmiValueSize == 32 ? kMinInt : (kMinInt >> 1))), - &bailout); - assembler->Goto(&divisor_is_not_minus_one); - } - assembler->Bind(&divisor_is_not_minus_one); - - // TODO(epertoso): consider adding a machine instruction that returns - // both the result and the remainder. - Node* untagged_result = - assembler->Int32Div(untagged_dividend, untagged_divisor); - Node* truncated = - assembler->Int32Mul(untagged_result, untagged_divisor); - // Do floating point division if the remainder is not 0. - assembler->GotoIf( - assembler->Word32NotEqual(untagged_dividend, truncated), &bailout); - var_result.Bind(assembler->SmiTag(untagged_result)); - assembler->Goto(&end); - - // Bailout: convert {dividend} and {divisor} to double and do double - // division. - assembler->Bind(&bailout); - { - var_dividend_float64.Bind(assembler->SmiToFloat64(dividend)); - var_divisor_float64.Bind(assembler->SmiToFloat64(divisor)); - assembler->Goto(&do_fdiv); - } - } - - assembler->Bind(&divisor_is_not_smi); - { - Node* divisor_map = assembler->LoadMap(divisor); - - // Check if {divisor} is a HeapNumber. - Label divisor_is_number(assembler), - divisor_is_not_number(assembler, Label::kDeferred); - assembler->Branch(assembler->WordEqual(divisor_map, number_map), - &divisor_is_number, &divisor_is_not_number); - - assembler->Bind(&divisor_is_number); - { - // Convert {dividend} to a double and divide it with the value of - // {divisor}. - var_dividend_float64.Bind(assembler->SmiToFloat64(dividend)); - var_divisor_float64.Bind(assembler->LoadHeapNumberValue(divisor)); - assembler->Goto(&do_fdiv); - } - - assembler->Bind(&divisor_is_not_number); - { - // Convert {divisor} to a number and loop. - Callable callable = - CodeFactory::NonNumberToNumber(assembler->isolate()); - var_divisor.Bind(assembler->CallStub(callable, context, divisor)); - assembler->Goto(&loop); - } - } - } - - assembler->Bind(÷nd_is_not_smi); - { - Node* dividend_map = assembler->LoadMap(dividend); - - // Check if {dividend} is a HeapNumber. - Label dividend_is_number(assembler), - dividend_is_not_number(assembler, Label::kDeferred); - assembler->Branch(assembler->WordEqual(dividend_map, number_map), - ÷nd_is_number, ÷nd_is_not_number); - - assembler->Bind(÷nd_is_number); - { - // Check if {divisor} is a Smi. - Label divisor_is_smi(assembler), divisor_is_not_smi(assembler); - assembler->Branch(assembler->WordIsSmi(divisor), &divisor_is_smi, - &divisor_is_not_smi); - - assembler->Bind(&divisor_is_smi); - { - // Convert {divisor} to a double and use it for a floating point - // division. - var_dividend_float64.Bind(assembler->LoadHeapNumberValue(dividend)); - var_divisor_float64.Bind(assembler->SmiToFloat64(divisor)); - assembler->Goto(&do_fdiv); - } + // Check if rhs is an oddball. At this point we know lhs is either a + // Smi or number or oddball and rhs is not a number or Smi. + Node* rhs_instance_type = assembler->LoadInstanceType(rhs); + Node* rhs_is_oddball = assembler->Word32Equal( + rhs_instance_type, assembler->Int32Constant(ODDBALL_TYPE)); + assembler->Branch(rhs_is_oddball, &call_with_oddball_feedback, + &call_with_any_feedback); + } - assembler->Bind(&divisor_is_not_smi); - { - Node* divisor_map = assembler->LoadMap(divisor); - - // Check if {divisor} is a HeapNumber. - Label divisor_is_number(assembler), - divisor_is_not_number(assembler, Label::kDeferred); - assembler->Branch(assembler->WordEqual(divisor_map, number_map), - &divisor_is_number, &divisor_is_not_number); - - assembler->Bind(&divisor_is_number); - { - // Both {dividend} and {divisor} are HeapNumbers. Load their values - // and divide them. - var_dividend_float64.Bind(assembler->LoadHeapNumberValue(dividend)); - var_divisor_float64.Bind(assembler->LoadHeapNumberValue(divisor)); - assembler->Goto(&do_fdiv); - } - - assembler->Bind(&divisor_is_not_number); - { - // Convert {divisor} to a number and loop. - Callable callable = - CodeFactory::NonNumberToNumber(assembler->isolate()); - var_divisor.Bind(assembler->CallStub(callable, context, divisor)); - assembler->Goto(&loop); - } - } - } + assembler->Bind(&call_with_oddball_feedback); + { + var_type_feedback.Bind( + assembler->Int32Constant(BinaryOperationFeedback::kNumberOrOddball)); + assembler->Goto(&call_multiply_stub); + } - assembler->Bind(÷nd_is_not_number); - { - // Convert {dividend} to a Number and loop. - Callable callable = - CodeFactory::NonNumberToNumber(assembler->isolate()); - var_dividend.Bind(assembler->CallStub(callable, context, dividend)); - assembler->Goto(&loop); - } - } + assembler->Bind(&call_with_any_feedback); + { + var_type_feedback.Bind( + assembler->Int32Constant(BinaryOperationFeedback::kAny)); + assembler->Goto(&call_multiply_stub); } - assembler->Bind(&do_fdiv); + assembler->Bind(&call_multiply_stub); { - Node* value = assembler->Float64Div(var_dividend_float64.value(), - var_divisor_float64.value()); - var_result.Bind(assembler->ChangeFloat64ToTagged(value)); + Callable callable = CodeFactory::Multiply(assembler->isolate()); + var_result.Bind(assembler->CallStub(callable, context, lhs, rhs)); assembler->Goto(&end); } + assembler->Bind(&end); + assembler->UpdateFeedback(var_type_feedback.value(), type_feedback_vector, + slot_id); return var_result.value(); } + // static compiler::Node* DivideWithFeedbackStub::Generate( CodeStubAssembler* assembler, compiler::Node* dividend, @@ -1984,7 +1291,10 @@ compiler::Node* DivideWithFeedbackStub::Generate( typedef CodeStubAssembler::Variable Variable; // Shared entry point for floating point division. - Label do_fdiv(assembler), end(assembler), call_divide_stub(assembler); + Label do_fdiv(assembler), dividend_is_not_number(assembler, Label::kDeferred), + check_divisor_for_oddball(assembler, Label::kDeferred), + call_with_oddball_feedback(assembler), call_with_any_feedback(assembler), + call_divide_stub(assembler), end(assembler); Variable var_dividend_float64(assembler, MachineRepresentation::kFloat64), var_divisor_float64(assembler, MachineRepresentation::kFloat64), var_result(assembler, MachineRepresentation::kTagged), @@ -1993,13 +1303,13 @@ compiler::Node* DivideWithFeedbackStub::Generate( Node* number_map = assembler->HeapNumberMapConstant(); Label dividend_is_smi(assembler), dividend_is_not_smi(assembler); - assembler->Branch(assembler->WordIsSmi(dividend), ÷nd_is_smi, + assembler->Branch(assembler->TaggedIsSmi(dividend), ÷nd_is_smi, ÷nd_is_not_smi); assembler->Bind(÷nd_is_smi); { Label divisor_is_smi(assembler), divisor_is_not_smi(assembler); - assembler->Branch(assembler->WordIsSmi(divisor), &divisor_is_smi, + assembler->Branch(assembler->TaggedIsSmi(divisor), &divisor_is_smi, &divisor_is_not_smi); assembler->Bind(&divisor_is_smi); @@ -2077,7 +1387,7 @@ compiler::Node* DivideWithFeedbackStub::Generate( // Check if {divisor} is a HeapNumber. assembler->GotoUnless(assembler->WordEqual(divisor_map, number_map), - &call_divide_stub); + &check_divisor_for_oddball); // Convert {dividend} to a double and divide it with the value of // {divisor}. @@ -2092,11 +1402,11 @@ compiler::Node* DivideWithFeedbackStub::Generate( // Check if {dividend} is a HeapNumber. assembler->GotoUnless(assembler->WordEqual(dividend_map, number_map), - &call_divide_stub); + ÷nd_is_not_number); // Check if {divisor} is a Smi. Label divisor_is_smi(assembler), divisor_is_not_smi(assembler); - assembler->Branch(assembler->WordIsSmi(divisor), &divisor_is_smi, + assembler->Branch(assembler->TaggedIsSmi(divisor), &divisor_is_smi, &divisor_is_not_smi); assembler->Bind(&divisor_is_smi); @@ -2114,7 +1424,7 @@ compiler::Node* DivideWithFeedbackStub::Generate( // Check if {divisor} is a HeapNumber. assembler->GotoUnless(assembler->WordEqual(divisor_map, number_map), - &call_divide_stub); + &check_divisor_for_oddball); // Both {dividend} and {divisor} are HeapNumbers. Load their values // and divide them. @@ -2131,181 +1441,65 @@ compiler::Node* DivideWithFeedbackStub::Generate( assembler->Int32Constant(BinaryOperationFeedback::kNumber)); Node* value = assembler->Float64Div(var_dividend_float64.value(), var_divisor_float64.value()); - var_result.Bind(assembler->ChangeFloat64ToTagged(value)); + var_result.Bind(assembler->AllocateHeapNumberWithValue(value)); assembler->Goto(&end); } - assembler->Bind(&call_divide_stub); + assembler->Bind(÷nd_is_not_number); { - var_type_feedback.Bind( - assembler->Int32Constant(BinaryOperationFeedback::kAny)); - Callable callable = CodeFactory::Divide(assembler->isolate()); - var_result.Bind(assembler->CallStub(callable, context, dividend, divisor)); - assembler->Goto(&end); - } + // We just know dividend is not a number or Smi. No checks on divisor yet. + // Check if dividend is an oddball. + Node* dividend_instance_type = assembler->LoadInstanceType(dividend); + Node* dividend_is_oddball = assembler->Word32Equal( + dividend_instance_type, assembler->Int32Constant(ODDBALL_TYPE)); + assembler->GotoUnless(dividend_is_oddball, &call_with_any_feedback); - assembler->Bind(&end); - assembler->UpdateFeedback(var_type_feedback.value(), type_feedback_vector, - slot_id); - return var_result.value(); -} - -// static -compiler::Node* ModulusStub::Generate(CodeStubAssembler* assembler, - compiler::Node* left, - compiler::Node* right, - compiler::Node* context) { - using compiler::Node; - typedef CodeStubAssembler::Label Label; - typedef CodeStubAssembler::Variable Variable; - - Variable var_result(assembler, MachineRepresentation::kTagged); - Label return_result(assembler, &var_result); + assembler->GotoIf(assembler->TaggedIsSmi(divisor), + &call_with_oddball_feedback); - // Shared entry point for floating point modulus. - Label do_fmod(assembler); - Variable var_dividend_float64(assembler, MachineRepresentation::kFloat64), - var_divisor_float64(assembler, MachineRepresentation::kFloat64); + // Load the map of the {divisor}. + Node* divisor_map = assembler->LoadMap(divisor); - Node* number_map = assembler->HeapNumberMapConstant(); + // Check if {divisor} is a HeapNumber. + assembler->Branch(assembler->IsHeapNumberMap(divisor_map), + &call_with_oddball_feedback, &check_divisor_for_oddball); + } - // We might need to loop one or two times due to ToNumber conversions. - Variable var_dividend(assembler, MachineRepresentation::kTagged), - var_divisor(assembler, MachineRepresentation::kTagged); - Variable* loop_variables[] = {&var_dividend, &var_divisor}; - Label loop(assembler, 2, loop_variables); - var_dividend.Bind(left); - var_divisor.Bind(right); - assembler->Goto(&loop); - assembler->Bind(&loop); + assembler->Bind(&check_divisor_for_oddball); { - Node* dividend = var_dividend.value(); - Node* divisor = var_divisor.value(); - - Label dividend_is_smi(assembler), dividend_is_not_smi(assembler); - assembler->Branch(assembler->WordIsSmi(dividend), ÷nd_is_smi, - ÷nd_is_not_smi); - - assembler->Bind(÷nd_is_smi); - { - Label dividend_is_not_zero(assembler); - Label divisor_is_smi(assembler), divisor_is_not_smi(assembler); - assembler->Branch(assembler->WordIsSmi(divisor), &divisor_is_smi, - &divisor_is_not_smi); - - assembler->Bind(&divisor_is_smi); - { - // Compute the modulus of two Smis. - var_result.Bind(assembler->SmiMod(dividend, divisor)); - assembler->Goto(&return_result); - } - - assembler->Bind(&divisor_is_not_smi); - { - Node* divisor_map = assembler->LoadMap(divisor); - - // Check if {divisor} is a HeapNumber. - Label divisor_is_number(assembler), - divisor_is_not_number(assembler, Label::kDeferred); - assembler->Branch(assembler->WordEqual(divisor_map, number_map), - &divisor_is_number, &divisor_is_not_number); - - assembler->Bind(&divisor_is_number); - { - // Convert {dividend} to a double and compute its modulus with the - // value of {dividend}. - var_dividend_float64.Bind(assembler->SmiToFloat64(dividend)); - var_divisor_float64.Bind(assembler->LoadHeapNumberValue(divisor)); - assembler->Goto(&do_fmod); - } - - assembler->Bind(&divisor_is_not_number); - { - // Convert {divisor} to a number and loop. - Callable callable = - CodeFactory::NonNumberToNumber(assembler->isolate()); - var_divisor.Bind(assembler->CallStub(callable, context, divisor)); - assembler->Goto(&loop); - } - } - } - - assembler->Bind(÷nd_is_not_smi); - { - Node* dividend_map = assembler->LoadMap(dividend); - - // Check if {dividend} is a HeapNumber. - Label dividend_is_number(assembler), - dividend_is_not_number(assembler, Label::kDeferred); - assembler->Branch(assembler->WordEqual(dividend_map, number_map), - ÷nd_is_number, ÷nd_is_not_number); - - assembler->Bind(÷nd_is_number); - { - // Check if {divisor} is a Smi. - Label divisor_is_smi(assembler), divisor_is_not_smi(assembler); - assembler->Branch(assembler->WordIsSmi(divisor), &divisor_is_smi, - &divisor_is_not_smi); - - assembler->Bind(&divisor_is_smi); - { - // Convert {divisor} to a double and compute {dividend}'s modulus with - // it. - var_dividend_float64.Bind(assembler->LoadHeapNumberValue(dividend)); - var_divisor_float64.Bind(assembler->SmiToFloat64(divisor)); - assembler->Goto(&do_fmod); - } + // Check if divisor is an oddball. At this point we know dividend is either + // a Smi or number or oddball and divisor is not a number or Smi. + Node* divisor_instance_type = assembler->LoadInstanceType(divisor); + Node* divisor_is_oddball = assembler->Word32Equal( + divisor_instance_type, assembler->Int32Constant(ODDBALL_TYPE)); + assembler->Branch(divisor_is_oddball, &call_with_oddball_feedback, + &call_with_any_feedback); + } - assembler->Bind(&divisor_is_not_smi); - { - Node* divisor_map = assembler->LoadMap(divisor); - - // Check if {divisor} is a HeapNumber. - Label divisor_is_number(assembler), - divisor_is_not_number(assembler, Label::kDeferred); - assembler->Branch(assembler->WordEqual(divisor_map, number_map), - &divisor_is_number, &divisor_is_not_number); - - assembler->Bind(&divisor_is_number); - { - // Both {dividend} and {divisor} are HeapNumbers. Load their values - // and compute their modulus. - var_dividend_float64.Bind(assembler->LoadHeapNumberValue(dividend)); - var_divisor_float64.Bind(assembler->LoadHeapNumberValue(divisor)); - assembler->Goto(&do_fmod); - } - - assembler->Bind(&divisor_is_not_number); - { - // Convert {divisor} to a number and loop. - Callable callable = - CodeFactory::NonNumberToNumber(assembler->isolate()); - var_divisor.Bind(assembler->CallStub(callable, context, divisor)); - assembler->Goto(&loop); - } - } - } + assembler->Bind(&call_with_oddball_feedback); + { + var_type_feedback.Bind( + assembler->Int32Constant(BinaryOperationFeedback::kNumberOrOddball)); + assembler->Goto(&call_divide_stub); + } - assembler->Bind(÷nd_is_not_number); - { - // Convert {dividend} to a Number and loop. - Callable callable = - CodeFactory::NonNumberToNumber(assembler->isolate()); - var_dividend.Bind(assembler->CallStub(callable, context, dividend)); - assembler->Goto(&loop); - } - } + assembler->Bind(&call_with_any_feedback); + { + var_type_feedback.Bind( + assembler->Int32Constant(BinaryOperationFeedback::kAny)); + assembler->Goto(&call_divide_stub); } - assembler->Bind(&do_fmod); + assembler->Bind(&call_divide_stub); { - Node* value = assembler->Float64Mod(var_dividend_float64.value(), - var_divisor_float64.value()); - var_result.Bind(assembler->ChangeFloat64ToTagged(value)); - assembler->Goto(&return_result); + Callable callable = CodeFactory::Divide(assembler->isolate()); + var_result.Bind(assembler->CallStub(callable, context, dividend, divisor)); + assembler->Goto(&end); } - assembler->Bind(&return_result); + assembler->Bind(&end); + assembler->UpdateFeedback(var_type_feedback.value(), type_feedback_vector, + slot_id); return var_result.value(); } @@ -2319,7 +1513,10 @@ compiler::Node* ModulusWithFeedbackStub::Generate( typedef CodeStubAssembler::Variable Variable; // Shared entry point for floating point division. - Label do_fmod(assembler), end(assembler), call_modulus_stub(assembler); + Label do_fmod(assembler), dividend_is_not_number(assembler, Label::kDeferred), + check_divisor_for_oddball(assembler, Label::kDeferred), + call_with_oddball_feedback(assembler), call_with_any_feedback(assembler), + call_modulus_stub(assembler), end(assembler); Variable var_dividend_float64(assembler, MachineRepresentation::kFloat64), var_divisor_float64(assembler, MachineRepresentation::kFloat64), var_result(assembler, MachineRepresentation::kTagged), @@ -2328,20 +1525,20 @@ compiler::Node* ModulusWithFeedbackStub::Generate( Node* number_map = assembler->HeapNumberMapConstant(); Label dividend_is_smi(assembler), dividend_is_not_smi(assembler); - assembler->Branch(assembler->WordIsSmi(dividend), ÷nd_is_smi, + assembler->Branch(assembler->TaggedIsSmi(dividend), ÷nd_is_smi, ÷nd_is_not_smi); assembler->Bind(÷nd_is_smi); { Label divisor_is_smi(assembler), divisor_is_not_smi(assembler); - assembler->Branch(assembler->WordIsSmi(divisor), &divisor_is_smi, + assembler->Branch(assembler->TaggedIsSmi(divisor), &divisor_is_smi, &divisor_is_not_smi); assembler->Bind(&divisor_is_smi); { var_result.Bind(assembler->SmiMod(dividend, divisor)); var_type_feedback.Bind(assembler->Select( - assembler->WordIsSmi(var_result.value()), + assembler->TaggedIsSmi(var_result.value()), assembler->Int32Constant(BinaryOperationFeedback::kSignedSmall), assembler->Int32Constant(BinaryOperationFeedback::kNumber))); assembler->Goto(&end); @@ -2353,7 +1550,7 @@ compiler::Node* ModulusWithFeedbackStub::Generate( // Check if {divisor} is a HeapNumber. assembler->GotoUnless(assembler->WordEqual(divisor_map, number_map), - &call_modulus_stub); + &check_divisor_for_oddball); // Convert {dividend} to a double and divide it with the value of // {divisor}. @@ -2369,11 +1566,11 @@ compiler::Node* ModulusWithFeedbackStub::Generate( // Check if {dividend} is a HeapNumber. assembler->GotoUnless(assembler->WordEqual(dividend_map, number_map), - &call_modulus_stub); + ÷nd_is_not_number); // Check if {divisor} is a Smi. Label divisor_is_smi(assembler), divisor_is_not_smi(assembler); - assembler->Branch(assembler->WordIsSmi(divisor), &divisor_is_smi, + assembler->Branch(assembler->TaggedIsSmi(divisor), &divisor_is_smi, &divisor_is_not_smi); assembler->Bind(&divisor_is_smi); @@ -2391,7 +1588,7 @@ compiler::Node* ModulusWithFeedbackStub::Generate( // Check if {divisor} is a HeapNumber. assembler->GotoUnless(assembler->WordEqual(divisor_map, number_map), - &call_modulus_stub); + &check_divisor_for_oddball); // Both {dividend} and {divisor} are HeapNumbers. Load their values // and divide them. @@ -2407,14 +1604,57 @@ compiler::Node* ModulusWithFeedbackStub::Generate( assembler->Int32Constant(BinaryOperationFeedback::kNumber)); Node* value = assembler->Float64Mod(var_dividend_float64.value(), var_divisor_float64.value()); - var_result.Bind(assembler->ChangeFloat64ToTagged(value)); + var_result.Bind(assembler->AllocateHeapNumberWithValue(value)); assembler->Goto(&end); } - assembler->Bind(&call_modulus_stub); + assembler->Bind(÷nd_is_not_number); + { + // No checks on divisor yet. We just know dividend is not a number or Smi. + // Check if dividend is an oddball. + Node* dividend_instance_type = assembler->LoadInstanceType(dividend); + Node* dividend_is_oddball = assembler->Word32Equal( + dividend_instance_type, assembler->Int32Constant(ODDBALL_TYPE)); + assembler->GotoUnless(dividend_is_oddball, &call_with_any_feedback); + + assembler->GotoIf(assembler->TaggedIsSmi(divisor), + &call_with_oddball_feedback); + + // Load the map of the {divisor}. + Node* divisor_map = assembler->LoadMap(divisor); + + // Check if {divisor} is a HeapNumber. + assembler->Branch(assembler->IsHeapNumberMap(divisor_map), + &call_with_oddball_feedback, &check_divisor_for_oddball); + } + + assembler->Bind(&check_divisor_for_oddball); + { + // Check if divisor is an oddball. At this point we know dividend is either + // a Smi or number or oddball and divisor is not a number or Smi. + Node* divisor_instance_type = assembler->LoadInstanceType(divisor); + Node* divisor_is_oddball = assembler->Word32Equal( + divisor_instance_type, assembler->Int32Constant(ODDBALL_TYPE)); + assembler->Branch(divisor_is_oddball, &call_with_oddball_feedback, + &call_with_any_feedback); + } + + assembler->Bind(&call_with_oddball_feedback); + { + var_type_feedback.Bind( + assembler->Int32Constant(BinaryOperationFeedback::kNumberOrOddball)); + assembler->Goto(&call_modulus_stub); + } + + assembler->Bind(&call_with_any_feedback); { var_type_feedback.Bind( assembler->Int32Constant(BinaryOperationFeedback::kAny)); + assembler->Goto(&call_modulus_stub); + } + + assembler->Bind(&call_modulus_stub); + { Callable callable = CodeFactory::Modulus(assembler->isolate()); var_result.Bind(assembler->CallStub(callable, context, dividend, divisor)); assembler->Goto(&end); @@ -2425,95 +1665,6 @@ compiler::Node* ModulusWithFeedbackStub::Generate( slot_id); return var_result.value(); } -// static -compiler::Node* ShiftLeftStub::Generate(CodeStubAssembler* assembler, - compiler::Node* left, - compiler::Node* right, - compiler::Node* context) { - using compiler::Node; - - Node* lhs_value = assembler->TruncateTaggedToWord32(context, left); - Node* rhs_value = assembler->TruncateTaggedToWord32(context, right); - Node* shift_count = - assembler->Word32And(rhs_value, assembler->Int32Constant(0x1f)); - Node* value = assembler->Word32Shl(lhs_value, shift_count); - Node* result = assembler->ChangeInt32ToTagged(value); - return result; -} - -// static -compiler::Node* ShiftRightStub::Generate(CodeStubAssembler* assembler, - compiler::Node* left, - compiler::Node* right, - compiler::Node* context) { - using compiler::Node; - - Node* lhs_value = assembler->TruncateTaggedToWord32(context, left); - Node* rhs_value = assembler->TruncateTaggedToWord32(context, right); - Node* shift_count = - assembler->Word32And(rhs_value, assembler->Int32Constant(0x1f)); - Node* value = assembler->Word32Sar(lhs_value, shift_count); - Node* result = assembler->ChangeInt32ToTagged(value); - return result; -} - -// static -compiler::Node* ShiftRightLogicalStub::Generate(CodeStubAssembler* assembler, - compiler::Node* left, - compiler::Node* right, - compiler::Node* context) { - using compiler::Node; - - Node* lhs_value = assembler->TruncateTaggedToWord32(context, left); - Node* rhs_value = assembler->TruncateTaggedToWord32(context, right); - Node* shift_count = - assembler->Word32And(rhs_value, assembler->Int32Constant(0x1f)); - Node* value = assembler->Word32Shr(lhs_value, shift_count); - Node* result = assembler->ChangeUint32ToTagged(value); - return result; -} - -// static -compiler::Node* BitwiseAndStub::Generate(CodeStubAssembler* assembler, - compiler::Node* left, - compiler::Node* right, - compiler::Node* context) { - using compiler::Node; - - Node* lhs_value = assembler->TruncateTaggedToWord32(context, left); - Node* rhs_value = assembler->TruncateTaggedToWord32(context, right); - Node* value = assembler->Word32And(lhs_value, rhs_value); - Node* result = assembler->ChangeInt32ToTagged(value); - return result; -} - -// static -compiler::Node* BitwiseOrStub::Generate(CodeStubAssembler* assembler, - compiler::Node* left, - compiler::Node* right, - compiler::Node* context) { - using compiler::Node; - - Node* lhs_value = assembler->TruncateTaggedToWord32(context, left); - Node* rhs_value = assembler->TruncateTaggedToWord32(context, right); - Node* value = assembler->Word32Or(lhs_value, rhs_value); - Node* result = assembler->ChangeInt32ToTagged(value); - return result; -} - -// static -compiler::Node* BitwiseXorStub::Generate(CodeStubAssembler* assembler, - compiler::Node* left, - compiler::Node* right, - compiler::Node* context) { - using compiler::Node; - - Node* lhs_value = assembler->TruncateTaggedToWord32(context, left); - Node* rhs_value = assembler->TruncateTaggedToWord32(context, right); - Node* value = assembler->Word32Xor(lhs_value, rhs_value); - Node* result = assembler->ChangeInt32ToTagged(value); - return result; -} // static compiler::Node* IncStub::Generate(CodeStubAssembler* assembler, @@ -2544,13 +1695,15 @@ compiler::Node* IncStub::Generate(CodeStubAssembler* assembler, value = value_var.value(); Label if_issmi(assembler), if_isnotsmi(assembler); - assembler->Branch(assembler->WordIsSmi(value), &if_issmi, &if_isnotsmi); + assembler->Branch(assembler->TaggedIsSmi(value), &if_issmi, &if_isnotsmi); assembler->Bind(&if_issmi); { // Try fast Smi addition first. Node* one = assembler->SmiConstant(Smi::FromInt(1)); - Node* pair = assembler->SmiAddWithOverflow(value, one); + Node* pair = assembler->IntPtrAddWithOverflow( + assembler->BitcastTaggedToWord(value), + assembler->BitcastTaggedToWord(one)); Node* overflow = assembler->Projection(1, pair); // Check if the Smi addition overflowed. @@ -2561,7 +1714,8 @@ compiler::Node* IncStub::Generate(CodeStubAssembler* assembler, var_type_feedback.Bind(assembler->Word32Or( var_type_feedback.value(), assembler->Int32Constant(BinaryOperationFeedback::kSignedSmall))); - result_var.Bind(assembler->Projection(0, pair)); + result_var.Bind( + assembler->BitcastWordToTaggedSigned(assembler->Projection(0, pair))); assembler->Goto(&end); assembler->Bind(&if_overflow); @@ -2589,13 +1743,40 @@ compiler::Node* IncStub::Generate(CodeStubAssembler* assembler, assembler->Bind(&if_valuenotnumber); { - // Convert to a Number first and try again. - Callable callable = - CodeFactory::NonNumberToNumber(assembler->isolate()); - var_type_feedback.Bind( - assembler->Int32Constant(BinaryOperationFeedback::kAny)); - value_var.Bind(assembler->CallStub(callable, context, value)); - assembler->Goto(&start); + // We do not require an Or with earlier feedback here because once we + // convert the value to a number, we cannot reach this path. We can + // only reach this path on the first pass when the feedback is kNone. + CSA_ASSERT(assembler, + assembler->Word32Equal(var_type_feedback.value(), + assembler->Int32Constant( + BinaryOperationFeedback::kNone))); + + Label if_valueisoddball(assembler), if_valuenotoddball(assembler); + Node* instance_type = assembler->LoadMapInstanceType(value_map); + Node* is_oddball = assembler->Word32Equal( + instance_type, assembler->Int32Constant(ODDBALL_TYPE)); + assembler->Branch(is_oddball, &if_valueisoddball, &if_valuenotoddball); + + assembler->Bind(&if_valueisoddball); + { + // Convert Oddball to Number and check again. + value_var.Bind( + assembler->LoadObjectField(value, Oddball::kToNumberOffset)); + var_type_feedback.Bind(assembler->Int32Constant( + BinaryOperationFeedback::kNumberOrOddball)); + assembler->Goto(&start); + } + + assembler->Bind(&if_valuenotoddball); + { + // Convert to a Number first and try again. + Callable callable = + CodeFactory::NonNumberToNumber(assembler->isolate()); + var_type_feedback.Bind( + assembler->Int32Constant(BinaryOperationFeedback::kAny)); + value_var.Bind(assembler->CallStub(callable, context, value)); + assembler->Goto(&start); + } } } } @@ -2608,7 +1789,7 @@ compiler::Node* IncStub::Generate(CodeStubAssembler* assembler, var_type_feedback.Bind(assembler->Word32Or( var_type_feedback.value(), assembler->Int32Constant(BinaryOperationFeedback::kNumber))); - result_var.Bind(assembler->ChangeFloat64ToTagged(finc_result)); + result_var.Bind(assembler->AllocateHeapNumberWithValue(finc_result)); assembler->Goto(&end); } @@ -2618,6 +1799,13 @@ compiler::Node* IncStub::Generate(CodeStubAssembler* assembler, return result_var.value(); } +void NumberToStringStub::GenerateAssembly(CodeStubAssembler* assembler) const { + typedef compiler::Node Node; + Node* argument = assembler->Parameter(Descriptor::kArgument); + Node* context = assembler->Parameter(Descriptor::kContext); + assembler->Return(assembler->NumberToString(context, argument)); +} + // static compiler::Node* DecStub::Generate(CodeStubAssembler* assembler, compiler::Node* value, @@ -2647,13 +1835,15 @@ compiler::Node* DecStub::Generate(CodeStubAssembler* assembler, value = value_var.value(); Label if_issmi(assembler), if_isnotsmi(assembler); - assembler->Branch(assembler->WordIsSmi(value), &if_issmi, &if_isnotsmi); + assembler->Branch(assembler->TaggedIsSmi(value), &if_issmi, &if_isnotsmi); assembler->Bind(&if_issmi); { // Try fast Smi subtraction first. Node* one = assembler->SmiConstant(Smi::FromInt(1)); - Node* pair = assembler->SmiSubWithOverflow(value, one); + Node* pair = assembler->IntPtrSubWithOverflow( + assembler->BitcastTaggedToWord(value), + assembler->BitcastTaggedToWord(one)); Node* overflow = assembler->Projection(1, pair); // Check if the Smi subtraction overflowed. @@ -2664,7 +1854,8 @@ compiler::Node* DecStub::Generate(CodeStubAssembler* assembler, var_type_feedback.Bind(assembler->Word32Or( var_type_feedback.value(), assembler->Int32Constant(BinaryOperationFeedback::kSignedSmall))); - result_var.Bind(assembler->Projection(0, pair)); + result_var.Bind( + assembler->BitcastWordToTaggedSigned(assembler->Projection(0, pair))); assembler->Goto(&end); assembler->Bind(&if_overflow); @@ -2692,13 +1883,40 @@ compiler::Node* DecStub::Generate(CodeStubAssembler* assembler, assembler->Bind(&if_valuenotnumber); { - // Convert to a Number first and try again. - Callable callable = - CodeFactory::NonNumberToNumber(assembler->isolate()); - var_type_feedback.Bind( - assembler->Int32Constant(BinaryOperationFeedback::kAny)); - value_var.Bind(assembler->CallStub(callable, context, value)); - assembler->Goto(&start); + // We do not require an Or with earlier feedback here because once we + // convert the value to a number, we cannot reach this path. We can + // only reach this path on the first pass when the feedback is kNone. + CSA_ASSERT(assembler, + assembler->Word32Equal(var_type_feedback.value(), + assembler->Int32Constant( + BinaryOperationFeedback::kNone))); + + Label if_valueisoddball(assembler), if_valuenotoddball(assembler); + Node* instance_type = assembler->LoadMapInstanceType(value_map); + Node* is_oddball = assembler->Word32Equal( + instance_type, assembler->Int32Constant(ODDBALL_TYPE)); + assembler->Branch(is_oddball, &if_valueisoddball, &if_valuenotoddball); + + assembler->Bind(&if_valueisoddball); + { + // Convert Oddball to Number and check again. + value_var.Bind( + assembler->LoadObjectField(value, Oddball::kToNumberOffset)); + var_type_feedback.Bind(assembler->Int32Constant( + BinaryOperationFeedback::kNumberOrOddball)); + assembler->Goto(&start); + } + + assembler->Bind(&if_valuenotoddball); + { + // Convert to a Number first and try again. + Callable callable = + CodeFactory::NonNumberToNumber(assembler->isolate()); + var_type_feedback.Bind( + assembler->Int32Constant(BinaryOperationFeedback::kAny)); + value_var.Bind(assembler->CallStub(callable, context, value)); + assembler->Goto(&start); + } } } } @@ -2711,7 +1929,7 @@ compiler::Node* DecStub::Generate(CodeStubAssembler* assembler, var_type_feedback.Bind(assembler->Word32Or( var_type_feedback.value(), assembler->Int32Constant(BinaryOperationFeedback::kNumber))); - result_var.Bind(assembler->ChangeFloat64ToTagged(fdec_result)); + result_var.Bind(assembler->AllocateHeapNumberWithValue(fdec_result)); assembler->Goto(&end); } @@ -2730,1439 +1948,6 @@ compiler::Node* SubStringStub::Generate(CodeStubAssembler* assembler, return assembler->SubString(context, string, from, to); } -// ES6 section 7.1.13 ToObject (argument) -void ToObjectStub::GenerateAssembly(CodeStubAssembler* assembler) const { - typedef compiler::Node Node; - typedef CodeStubAssembler::Label Label; - typedef CodeStubAssembler::Variable Variable; - - Label if_number(assembler, Label::kDeferred), if_notsmi(assembler), - if_jsreceiver(assembler), if_noconstructor(assembler, Label::kDeferred), - if_wrapjsvalue(assembler); - - Node* object = assembler->Parameter(Descriptor::kArgument); - Node* context = assembler->Parameter(Descriptor::kContext); - - Variable constructor_function_index_var(assembler, - MachineType::PointerRepresentation()); - - assembler->Branch(assembler->WordIsSmi(object), &if_number, &if_notsmi); - - assembler->Bind(&if_notsmi); - Node* map = assembler->LoadMap(object); - - assembler->GotoIf(assembler->IsHeapNumberMap(map), &if_number); - - Node* instance_type = assembler->LoadMapInstanceType(map); - assembler->GotoIf(assembler->IsJSReceiverInstanceType(instance_type), - &if_jsreceiver); - - Node* constructor_function_index = - assembler->LoadMapConstructorFunctionIndex(map); - assembler->GotoIf(assembler->WordEqual(constructor_function_index, - assembler->IntPtrConstant( - Map::kNoConstructorFunctionIndex)), - &if_noconstructor); - constructor_function_index_var.Bind(constructor_function_index); - assembler->Goto(&if_wrapjsvalue); - - assembler->Bind(&if_number); - constructor_function_index_var.Bind( - assembler->IntPtrConstant(Context::NUMBER_FUNCTION_INDEX)); - assembler->Goto(&if_wrapjsvalue); - - assembler->Bind(&if_wrapjsvalue); - Node* native_context = assembler->LoadNativeContext(context); - Node* constructor = assembler->LoadFixedArrayElement( - native_context, constructor_function_index_var.value(), 0, - CodeStubAssembler::INTPTR_PARAMETERS); - Node* initial_map = assembler->LoadObjectField( - constructor, JSFunction::kPrototypeOrInitialMapOffset); - Node* js_value = assembler->Allocate(JSValue::kSize); - assembler->StoreMapNoWriteBarrier(js_value, initial_map); - assembler->StoreObjectFieldRoot(js_value, JSValue::kPropertiesOffset, - Heap::kEmptyFixedArrayRootIndex); - assembler->StoreObjectFieldRoot(js_value, JSObject::kElementsOffset, - Heap::kEmptyFixedArrayRootIndex); - assembler->StoreObjectField(js_value, JSValue::kValueOffset, object); - assembler->Return(js_value); - - assembler->Bind(&if_noconstructor); - assembler->TailCallRuntime( - Runtime::kThrowUndefinedOrNullToObject, context, - assembler->HeapConstant(assembler->factory()->NewStringFromAsciiChecked( - "ToObject", TENURED))); - - assembler->Bind(&if_jsreceiver); - assembler->Return(object); -} - -// static -// ES6 section 12.5.5 typeof operator -compiler::Node* TypeofStub::Generate(CodeStubAssembler* assembler, - compiler::Node* value, - compiler::Node* context) { - typedef compiler::Node Node; - typedef CodeStubAssembler::Label Label; - typedef CodeStubAssembler::Variable Variable; - - Variable result_var(assembler, MachineRepresentation::kTagged); - - Label return_number(assembler, Label::kDeferred), if_oddball(assembler), - return_function(assembler), return_undefined(assembler), - return_object(assembler), return_string(assembler), - return_result(assembler); - - assembler->GotoIf(assembler->WordIsSmi(value), &return_number); - - Node* map = assembler->LoadMap(value); - - assembler->GotoIf(assembler->IsHeapNumberMap(map), &return_number); - - Node* instance_type = assembler->LoadMapInstanceType(map); - - assembler->GotoIf(assembler->Word32Equal( - instance_type, assembler->Int32Constant(ODDBALL_TYPE)), - &if_oddball); - - Node* callable_or_undetectable_mask = - assembler->Word32And(assembler->LoadMapBitField(map), - assembler->Int32Constant(1 << Map::kIsCallable | - 1 << Map::kIsUndetectable)); - - assembler->GotoIf( - assembler->Word32Equal(callable_or_undetectable_mask, - assembler->Int32Constant(1 << Map::kIsCallable)), - &return_function); - - assembler->GotoUnless(assembler->Word32Equal(callable_or_undetectable_mask, - assembler->Int32Constant(0)), - &return_undefined); - - assembler->GotoIf(assembler->IsJSReceiverInstanceType(instance_type), - &return_object); - - assembler->GotoIf(assembler->IsStringInstanceType(instance_type), - &return_string); - -#define SIMD128_BRANCH(TYPE, Type, type, lane_count, lane_type) \ - Label return_##type(assembler); \ - Node* type##_map = \ - assembler->HeapConstant(assembler->factory()->type##_map()); \ - assembler->GotoIf(assembler->WordEqual(map, type##_map), &return_##type); - SIMD128_TYPES(SIMD128_BRANCH) -#undef SIMD128_BRANCH - - assembler->Assert(assembler->Word32Equal( - instance_type, assembler->Int32Constant(SYMBOL_TYPE))); - result_var.Bind(assembler->HeapConstant( - assembler->isolate()->factory()->symbol_string())); - assembler->Goto(&return_result); - - assembler->Bind(&return_number); - { - result_var.Bind(assembler->HeapConstant( - assembler->isolate()->factory()->number_string())); - assembler->Goto(&return_result); - } - - assembler->Bind(&if_oddball); - { - Node* type = assembler->LoadObjectField(value, Oddball::kTypeOfOffset); - result_var.Bind(type); - assembler->Goto(&return_result); - } - - assembler->Bind(&return_function); - { - result_var.Bind(assembler->HeapConstant( - assembler->isolate()->factory()->function_string())); - assembler->Goto(&return_result); - } - - assembler->Bind(&return_undefined); - { - result_var.Bind(assembler->HeapConstant( - assembler->isolate()->factory()->undefined_string())); - assembler->Goto(&return_result); - } - - assembler->Bind(&return_object); - { - result_var.Bind(assembler->HeapConstant( - assembler->isolate()->factory()->object_string())); - assembler->Goto(&return_result); - } - - assembler->Bind(&return_string); - { - result_var.Bind(assembler->HeapConstant( - assembler->isolate()->factory()->string_string())); - assembler->Goto(&return_result); - } - -#define SIMD128_BIND_RETURN(TYPE, Type, type, lane_count, lane_type) \ - assembler->Bind(&return_##type); \ - { \ - result_var.Bind(assembler->HeapConstant( \ - assembler->isolate()->factory()->type##_string())); \ - assembler->Goto(&return_result); \ - } - SIMD128_TYPES(SIMD128_BIND_RETURN) -#undef SIMD128_BIND_RETURN - - assembler->Bind(&return_result); - return result_var.value(); -} - -// static -compiler::Node* InstanceOfStub::Generate(CodeStubAssembler* assembler, - compiler::Node* object, - compiler::Node* callable, - compiler::Node* context) { - typedef CodeStubAssembler::Label Label; - typedef CodeStubAssembler::Variable Variable; - - Label return_runtime(assembler, Label::kDeferred), end(assembler); - Variable result(assembler, MachineRepresentation::kTagged); - - // Check if no one installed @@hasInstance somewhere. - assembler->GotoUnless( - assembler->WordEqual( - assembler->LoadObjectField( - assembler->LoadRoot(Heap::kHasInstanceProtectorRootIndex), - PropertyCell::kValueOffset), - assembler->SmiConstant(Smi::FromInt(Isolate::kArrayProtectorValid))), - &return_runtime); - - // Check if {callable} is a valid receiver. - assembler->GotoIf(assembler->WordIsSmi(callable), &return_runtime); - assembler->GotoIf( - assembler->Word32Equal( - assembler->Word32And( - assembler->LoadMapBitField(assembler->LoadMap(callable)), - assembler->Int32Constant(1 << Map::kIsCallable)), - assembler->Int32Constant(0)), - &return_runtime); - - // Use the inline OrdinaryHasInstance directly. - result.Bind(assembler->OrdinaryHasInstance(context, callable, object)); - assembler->Goto(&end); - - // TODO(bmeurer): Use GetPropertyStub here once available. - assembler->Bind(&return_runtime); - { - result.Bind(assembler->CallRuntime(Runtime::kInstanceOf, context, object, - callable)); - assembler->Goto(&end); - } - - assembler->Bind(&end); - return result.value(); -} - -namespace { - -enum RelationalComparisonMode { - kLessThan, - kLessThanOrEqual, - kGreaterThan, - kGreaterThanOrEqual -}; - -compiler::Node* GenerateAbstractRelationalComparison( - CodeStubAssembler* assembler, RelationalComparisonMode mode, - compiler::Node* lhs, compiler::Node* rhs, compiler::Node* context) { - typedef CodeStubAssembler::Label Label; - typedef compiler::Node Node; - typedef CodeStubAssembler::Variable Variable; - - Label return_true(assembler), return_false(assembler), end(assembler); - Variable result(assembler, MachineRepresentation::kTagged); - - // Shared entry for floating point comparison. - Label do_fcmp(assembler); - Variable var_fcmp_lhs(assembler, MachineRepresentation::kFloat64), - var_fcmp_rhs(assembler, MachineRepresentation::kFloat64); - - // We might need to loop several times due to ToPrimitive and/or ToNumber - // conversions. - Variable var_lhs(assembler, MachineRepresentation::kTagged), - var_rhs(assembler, MachineRepresentation::kTagged); - Variable* loop_vars[2] = {&var_lhs, &var_rhs}; - Label loop(assembler, 2, loop_vars); - var_lhs.Bind(lhs); - var_rhs.Bind(rhs); - assembler->Goto(&loop); - assembler->Bind(&loop); - { - // Load the current {lhs} and {rhs} values. - lhs = var_lhs.value(); - rhs = var_rhs.value(); - - // Check if the {lhs} is a Smi or a HeapObject. - Label if_lhsissmi(assembler), if_lhsisnotsmi(assembler); - assembler->Branch(assembler->WordIsSmi(lhs), &if_lhsissmi, &if_lhsisnotsmi); - - assembler->Bind(&if_lhsissmi); - { - // Check if {rhs} is a Smi or a HeapObject. - Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler); - assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi, - &if_rhsisnotsmi); - - assembler->Bind(&if_rhsissmi); - { - // Both {lhs} and {rhs} are Smi, so just perform a fast Smi comparison. - switch (mode) { - case kLessThan: - assembler->BranchIfSmiLessThan(lhs, rhs, &return_true, - &return_false); - break; - case kLessThanOrEqual: - assembler->BranchIfSmiLessThanOrEqual(lhs, rhs, &return_true, - &return_false); - break; - case kGreaterThan: - assembler->BranchIfSmiLessThan(rhs, lhs, &return_true, - &return_false); - break; - case kGreaterThanOrEqual: - assembler->BranchIfSmiLessThanOrEqual(rhs, lhs, &return_true, - &return_false); - break; - } - } - - assembler->Bind(&if_rhsisnotsmi); - { - // Load the map of {rhs}. - Node* rhs_map = assembler->LoadMap(rhs); - - // Check if the {rhs} is a HeapNumber. - Label if_rhsisnumber(assembler), - if_rhsisnotnumber(assembler, Label::kDeferred); - assembler->Branch(assembler->IsHeapNumberMap(rhs_map), &if_rhsisnumber, - &if_rhsisnotnumber); - - assembler->Bind(&if_rhsisnumber); - { - // Convert the {lhs} and {rhs} to floating point values, and - // perform a floating point comparison. - var_fcmp_lhs.Bind(assembler->SmiToFloat64(lhs)); - var_fcmp_rhs.Bind(assembler->LoadHeapNumberValue(rhs)); - assembler->Goto(&do_fcmp); - } - - assembler->Bind(&if_rhsisnotnumber); - { - // Convert the {rhs} to a Number; we don't need to perform the - // dedicated ToPrimitive(rhs, hint Number) operation, as the - // ToNumber(rhs) will by itself already invoke ToPrimitive with - // a Number hint. - Callable callable = - CodeFactory::NonNumberToNumber(assembler->isolate()); - var_rhs.Bind(assembler->CallStub(callable, context, rhs)); - assembler->Goto(&loop); - } - } - } - - assembler->Bind(&if_lhsisnotsmi); - { - // Load the HeapNumber map for later comparisons. - Node* number_map = assembler->HeapNumberMapConstant(); - - // Load the map of {lhs}. - Node* lhs_map = assembler->LoadMap(lhs); - - // Check if {rhs} is a Smi or a HeapObject. - Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler); - assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi, - &if_rhsisnotsmi); - - assembler->Bind(&if_rhsissmi); - { - // Check if the {lhs} is a HeapNumber. - Label if_lhsisnumber(assembler), - if_lhsisnotnumber(assembler, Label::kDeferred); - assembler->Branch(assembler->WordEqual(lhs_map, number_map), - &if_lhsisnumber, &if_lhsisnotnumber); - - assembler->Bind(&if_lhsisnumber); - { - // Convert the {lhs} and {rhs} to floating point values, and - // perform a floating point comparison. - var_fcmp_lhs.Bind(assembler->LoadHeapNumberValue(lhs)); - var_fcmp_rhs.Bind(assembler->SmiToFloat64(rhs)); - assembler->Goto(&do_fcmp); - } - - assembler->Bind(&if_lhsisnotnumber); - { - // Convert the {lhs} to a Number; we don't need to perform the - // dedicated ToPrimitive(lhs, hint Number) operation, as the - // ToNumber(lhs) will by itself already invoke ToPrimitive with - // a Number hint. - Callable callable = - CodeFactory::NonNumberToNumber(assembler->isolate()); - var_lhs.Bind(assembler->CallStub(callable, context, lhs)); - assembler->Goto(&loop); - } - } - - assembler->Bind(&if_rhsisnotsmi); - { - // Load the map of {rhs}. - Node* rhs_map = assembler->LoadMap(rhs); - - // Check if {lhs} is a HeapNumber. - Label if_lhsisnumber(assembler), if_lhsisnotnumber(assembler); - assembler->Branch(assembler->WordEqual(lhs_map, number_map), - &if_lhsisnumber, &if_lhsisnotnumber); - - assembler->Bind(&if_lhsisnumber); - { - // Check if {rhs} is also a HeapNumber. - Label if_rhsisnumber(assembler), - if_rhsisnotnumber(assembler, Label::kDeferred); - assembler->Branch(assembler->WordEqual(lhs_map, rhs_map), - &if_rhsisnumber, &if_rhsisnotnumber); - - assembler->Bind(&if_rhsisnumber); - { - // Convert the {lhs} and {rhs} to floating point values, and - // perform a floating point comparison. - var_fcmp_lhs.Bind(assembler->LoadHeapNumberValue(lhs)); - var_fcmp_rhs.Bind(assembler->LoadHeapNumberValue(rhs)); - assembler->Goto(&do_fcmp); - } - - assembler->Bind(&if_rhsisnotnumber); - { - // Convert the {rhs} to a Number; we don't need to perform - // dedicated ToPrimitive(rhs, hint Number) operation, as the - // ToNumber(rhs) will by itself already invoke ToPrimitive with - // a Number hint. - Callable callable = - CodeFactory::NonNumberToNumber(assembler->isolate()); - var_rhs.Bind(assembler->CallStub(callable, context, rhs)); - assembler->Goto(&loop); - } - } - - assembler->Bind(&if_lhsisnotnumber); - { - // Load the instance type of {lhs}. - Node* lhs_instance_type = assembler->LoadMapInstanceType(lhs_map); - - // Check if {lhs} is a String. - Label if_lhsisstring(assembler), - if_lhsisnotstring(assembler, Label::kDeferred); - assembler->Branch(assembler->IsStringInstanceType(lhs_instance_type), - &if_lhsisstring, &if_lhsisnotstring); - - assembler->Bind(&if_lhsisstring); - { - // Load the instance type of {rhs}. - Node* rhs_instance_type = assembler->LoadMapInstanceType(rhs_map); - - // Check if {rhs} is also a String. - Label if_rhsisstring(assembler, Label::kDeferred), - if_rhsisnotstring(assembler, Label::kDeferred); - assembler->Branch( - assembler->IsStringInstanceType(rhs_instance_type), - &if_rhsisstring, &if_rhsisnotstring); - - assembler->Bind(&if_rhsisstring); - { - // Both {lhs} and {rhs} are strings. - switch (mode) { - case kLessThan: - result.Bind(assembler->CallStub( - CodeFactory::StringLessThan(assembler->isolate()), - context, lhs, rhs)); - assembler->Goto(&end); - break; - case kLessThanOrEqual: - result.Bind(assembler->CallStub( - CodeFactory::StringLessThanOrEqual(assembler->isolate()), - context, lhs, rhs)); - assembler->Goto(&end); - break; - case kGreaterThan: - result.Bind(assembler->CallStub( - CodeFactory::StringGreaterThan(assembler->isolate()), - context, lhs, rhs)); - assembler->Goto(&end); - break; - case kGreaterThanOrEqual: - result.Bind( - assembler->CallStub(CodeFactory::StringGreaterThanOrEqual( - assembler->isolate()), - context, lhs, rhs)); - assembler->Goto(&end); - break; - } - } - - assembler->Bind(&if_rhsisnotstring); - { - // The {lhs} is a String, while {rhs} is neither a Number nor a - // String, so we need to call ToPrimitive(rhs, hint Number) if - // {rhs} is a receiver or ToNumber(lhs) and ToNumber(rhs) in the - // other cases. - STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE); - Label if_rhsisreceiver(assembler, Label::kDeferred), - if_rhsisnotreceiver(assembler, Label::kDeferred); - assembler->Branch( - assembler->IsJSReceiverInstanceType(rhs_instance_type), - &if_rhsisreceiver, &if_rhsisnotreceiver); - - assembler->Bind(&if_rhsisreceiver); - { - // Convert {rhs} to a primitive first passing Number hint. - Callable callable = CodeFactory::NonPrimitiveToPrimitive( - assembler->isolate(), ToPrimitiveHint::kNumber); - var_rhs.Bind(assembler->CallStub(callable, context, rhs)); - assembler->Goto(&loop); - } - - assembler->Bind(&if_rhsisnotreceiver); - { - // Convert both {lhs} and {rhs} to Number. - Callable callable = CodeFactory::ToNumber(assembler->isolate()); - var_lhs.Bind(assembler->CallStub(callable, context, lhs)); - var_rhs.Bind(assembler->CallStub(callable, context, rhs)); - assembler->Goto(&loop); - } - } - } - - assembler->Bind(&if_lhsisnotstring); - { - // The {lhs} is neither a Number nor a String, so we need to call - // ToPrimitive(lhs, hint Number) if {lhs} is a receiver or - // ToNumber(lhs) and ToNumber(rhs) in the other cases. - STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE); - Label if_lhsisreceiver(assembler, Label::kDeferred), - if_lhsisnotreceiver(assembler, Label::kDeferred); - assembler->Branch( - assembler->IsJSReceiverInstanceType(lhs_instance_type), - &if_lhsisreceiver, &if_lhsisnotreceiver); - - assembler->Bind(&if_lhsisreceiver); - { - // Convert {lhs} to a primitive first passing Number hint. - Callable callable = CodeFactory::NonPrimitiveToPrimitive( - assembler->isolate(), ToPrimitiveHint::kNumber); - var_lhs.Bind(assembler->CallStub(callable, context, lhs)); - assembler->Goto(&loop); - } - - assembler->Bind(&if_lhsisnotreceiver); - { - // Convert both {lhs} and {rhs} to Number. - Callable callable = CodeFactory::ToNumber(assembler->isolate()); - var_lhs.Bind(assembler->CallStub(callable, context, lhs)); - var_rhs.Bind(assembler->CallStub(callable, context, rhs)); - assembler->Goto(&loop); - } - } - } - } - } - } - - assembler->Bind(&do_fcmp); - { - // Load the {lhs} and {rhs} floating point values. - Node* lhs = var_fcmp_lhs.value(); - Node* rhs = var_fcmp_rhs.value(); - - // Perform a fast floating point comparison. - switch (mode) { - case kLessThan: - assembler->BranchIfFloat64LessThan(lhs, rhs, &return_true, - &return_false); - break; - case kLessThanOrEqual: - assembler->BranchIfFloat64LessThanOrEqual(lhs, rhs, &return_true, - &return_false); - break; - case kGreaterThan: - assembler->BranchIfFloat64GreaterThan(lhs, rhs, &return_true, - &return_false); - break; - case kGreaterThanOrEqual: - assembler->BranchIfFloat64GreaterThanOrEqual(lhs, rhs, &return_true, - &return_false); - break; - } - } - - assembler->Bind(&return_true); - { - result.Bind(assembler->BooleanConstant(true)); - assembler->Goto(&end); - } - - assembler->Bind(&return_false); - { - result.Bind(assembler->BooleanConstant(false)); - assembler->Goto(&end); - } - - assembler->Bind(&end); - return result.value(); -} - -enum ResultMode { kDontNegateResult, kNegateResult }; - -void GenerateEqual_Same(CodeStubAssembler* assembler, compiler::Node* value, - CodeStubAssembler::Label* if_equal, - CodeStubAssembler::Label* if_notequal) { - // In case of abstract or strict equality checks, we need additional checks - // for NaN values because they are not considered equal, even if both the - // left and the right hand side reference exactly the same value. - // TODO(bmeurer): This seems to violate the SIMD.js specification, but it - // seems to be what is tested in the current SIMD.js testsuite. - - typedef CodeStubAssembler::Label Label; - typedef compiler::Node Node; - - // Check if {value} is a Smi or a HeapObject. - Label if_valueissmi(assembler), if_valueisnotsmi(assembler); - assembler->Branch(assembler->WordIsSmi(value), &if_valueissmi, - &if_valueisnotsmi); - - assembler->Bind(&if_valueisnotsmi); - { - // Load the map of {value}. - Node* value_map = assembler->LoadMap(value); - - // Check if {value} (and therefore {rhs}) is a HeapNumber. - Label if_valueisnumber(assembler), if_valueisnotnumber(assembler); - assembler->Branch(assembler->IsHeapNumberMap(value_map), &if_valueisnumber, - &if_valueisnotnumber); - - assembler->Bind(&if_valueisnumber); - { - // Convert {value} (and therefore {rhs}) to floating point value. - Node* value_value = assembler->LoadHeapNumberValue(value); - - // Check if the HeapNumber value is a NaN. - assembler->BranchIfFloat64IsNaN(value_value, if_notequal, if_equal); - } - - assembler->Bind(&if_valueisnotnumber); - assembler->Goto(if_equal); - } - - assembler->Bind(&if_valueissmi); - assembler->Goto(if_equal); -} - -void GenerateEqual_Simd128Value_HeapObject( - CodeStubAssembler* assembler, compiler::Node* lhs, compiler::Node* lhs_map, - compiler::Node* rhs, compiler::Node* rhs_map, - CodeStubAssembler::Label* if_equal, CodeStubAssembler::Label* if_notequal) { - assembler->BranchIfSimd128Equal(lhs, lhs_map, rhs, rhs_map, if_equal, - if_notequal); -} - -// ES6 section 7.2.12 Abstract Equality Comparison -compiler::Node* GenerateEqual(CodeStubAssembler* assembler, ResultMode mode, - compiler::Node* lhs, compiler::Node* rhs, - compiler::Node* context) { - // This is a slightly optimized version of Object::Equals represented as - // scheduled TurboFan graph utilizing the CodeStubAssembler. Whenever you - // change something functionality wise in here, remember to update the - // Object::Equals method as well. - typedef CodeStubAssembler::Label Label; - typedef compiler::Node Node; - typedef CodeStubAssembler::Variable Variable; - - Label if_equal(assembler), if_notequal(assembler), - do_rhsstringtonumber(assembler, Label::kDeferred), end(assembler); - Variable result(assembler, MachineRepresentation::kTagged); - - // Shared entry for floating point comparison. - Label do_fcmp(assembler); - Variable var_fcmp_lhs(assembler, MachineRepresentation::kFloat64), - var_fcmp_rhs(assembler, MachineRepresentation::kFloat64); - - // We might need to loop several times due to ToPrimitive and/or ToNumber - // conversions. - Variable var_lhs(assembler, MachineRepresentation::kTagged), - var_rhs(assembler, MachineRepresentation::kTagged); - Variable* loop_vars[2] = {&var_lhs, &var_rhs}; - Label loop(assembler, 2, loop_vars); - var_lhs.Bind(lhs); - var_rhs.Bind(rhs); - assembler->Goto(&loop); - assembler->Bind(&loop); - { - // Load the current {lhs} and {rhs} values. - lhs = var_lhs.value(); - rhs = var_rhs.value(); - - // Check if {lhs} and {rhs} refer to the same object. - Label if_same(assembler), if_notsame(assembler); - assembler->Branch(assembler->WordEqual(lhs, rhs), &if_same, &if_notsame); - - assembler->Bind(&if_same); - { - // The {lhs} and {rhs} reference the exact same value, yet we need special - // treatment for HeapNumber, as NaN is not equal to NaN. - GenerateEqual_Same(assembler, lhs, &if_equal, &if_notequal); - } - - assembler->Bind(&if_notsame); - { - // Check if {lhs} is a Smi or a HeapObject. - Label if_lhsissmi(assembler), if_lhsisnotsmi(assembler); - assembler->Branch(assembler->WordIsSmi(lhs), &if_lhsissmi, - &if_lhsisnotsmi); - - assembler->Bind(&if_lhsissmi); - { - // Check if {rhs} is a Smi or a HeapObject. - Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler); - assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi, - &if_rhsisnotsmi); - - assembler->Bind(&if_rhsissmi); - // We have already checked for {lhs} and {rhs} being the same value, so - // if both are Smis when we get here they must not be equal. - assembler->Goto(&if_notequal); - - assembler->Bind(&if_rhsisnotsmi); - { - // Load the map of {rhs}. - Node* rhs_map = assembler->LoadMap(rhs); - - // Check if {rhs} is a HeapNumber. - Node* number_map = assembler->HeapNumberMapConstant(); - Label if_rhsisnumber(assembler), if_rhsisnotnumber(assembler); - assembler->Branch(assembler->WordEqual(rhs_map, number_map), - &if_rhsisnumber, &if_rhsisnotnumber); - - assembler->Bind(&if_rhsisnumber); - { - // Convert {lhs} and {rhs} to floating point values, and - // perform a floating point comparison. - var_fcmp_lhs.Bind(assembler->SmiToFloat64(lhs)); - var_fcmp_rhs.Bind(assembler->LoadHeapNumberValue(rhs)); - assembler->Goto(&do_fcmp); - } - - assembler->Bind(&if_rhsisnotnumber); - { - // Load the instance type of the {rhs}. - Node* rhs_instance_type = assembler->LoadMapInstanceType(rhs_map); - - // Check if the {rhs} is a String. - Label if_rhsisstring(assembler, Label::kDeferred), - if_rhsisnotstring(assembler); - assembler->Branch( - assembler->IsStringInstanceType(rhs_instance_type), - &if_rhsisstring, &if_rhsisnotstring); - - assembler->Bind(&if_rhsisstring); - { - // The {rhs} is a String and the {lhs} is a Smi; we need - // to convert the {rhs} to a Number and compare the output to - // the Number on the {lhs}. - assembler->Goto(&do_rhsstringtonumber); - } - - assembler->Bind(&if_rhsisnotstring); - { - // Check if the {rhs} is a Boolean. - Label if_rhsisboolean(assembler), if_rhsisnotboolean(assembler); - assembler->Branch(assembler->IsBooleanMap(rhs_map), - &if_rhsisboolean, &if_rhsisnotboolean); - - assembler->Bind(&if_rhsisboolean); - { - // The {rhs} is a Boolean, load its number value. - var_rhs.Bind( - assembler->LoadObjectField(rhs, Oddball::kToNumberOffset)); - assembler->Goto(&loop); - } - - assembler->Bind(&if_rhsisnotboolean); - { - // Check if the {rhs} is a Receiver. - STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE); - Label if_rhsisreceiver(assembler, Label::kDeferred), - if_rhsisnotreceiver(assembler); - assembler->Branch( - assembler->IsJSReceiverInstanceType(rhs_instance_type), - &if_rhsisreceiver, &if_rhsisnotreceiver); - - assembler->Bind(&if_rhsisreceiver); - { - // Convert {rhs} to a primitive first (passing no hint). - Callable callable = CodeFactory::NonPrimitiveToPrimitive( - assembler->isolate()); - var_rhs.Bind(assembler->CallStub(callable, context, rhs)); - assembler->Goto(&loop); - } - - assembler->Bind(&if_rhsisnotreceiver); - assembler->Goto(&if_notequal); - } - } - } - } - } - - assembler->Bind(&if_lhsisnotsmi); - { - // Check if {rhs} is a Smi or a HeapObject. - Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler); - assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi, - &if_rhsisnotsmi); - - assembler->Bind(&if_rhsissmi); - { - // The {lhs} is a HeapObject and the {rhs} is a Smi; swapping {lhs} - // and {rhs} is not observable and doesn't matter for the result, so - // we can just swap them and use the Smi handling above (for {lhs} - // being a Smi). - var_lhs.Bind(rhs); - var_rhs.Bind(lhs); - assembler->Goto(&loop); - } - - assembler->Bind(&if_rhsisnotsmi); - { - Label if_lhsisstring(assembler), if_lhsisnumber(assembler), - if_lhsissymbol(assembler), if_lhsissimd128value(assembler), - if_lhsisoddball(assembler), if_lhsisreceiver(assembler); - - // Both {lhs} and {rhs} are HeapObjects, load their maps - // and their instance types. - Node* lhs_map = assembler->LoadMap(lhs); - Node* rhs_map = assembler->LoadMap(rhs); - - // Load the instance types of {lhs} and {rhs}. - Node* lhs_instance_type = assembler->LoadMapInstanceType(lhs_map); - Node* rhs_instance_type = assembler->LoadMapInstanceType(rhs_map); - - // Dispatch based on the instance type of {lhs}. - size_t const kNumCases = FIRST_NONSTRING_TYPE + 4; - Label* case_labels[kNumCases]; - int32_t case_values[kNumCases]; - for (int32_t i = 0; i < FIRST_NONSTRING_TYPE; ++i) { - case_labels[i] = new Label(assembler); - case_values[i] = i; - } - case_labels[FIRST_NONSTRING_TYPE + 0] = &if_lhsisnumber; - case_values[FIRST_NONSTRING_TYPE + 0] = HEAP_NUMBER_TYPE; - case_labels[FIRST_NONSTRING_TYPE + 1] = &if_lhsissymbol; - case_values[FIRST_NONSTRING_TYPE + 1] = SYMBOL_TYPE; - case_labels[FIRST_NONSTRING_TYPE + 2] = &if_lhsissimd128value; - case_values[FIRST_NONSTRING_TYPE + 2] = SIMD128_VALUE_TYPE; - case_labels[FIRST_NONSTRING_TYPE + 3] = &if_lhsisoddball; - case_values[FIRST_NONSTRING_TYPE + 3] = ODDBALL_TYPE; - assembler->Switch(lhs_instance_type, &if_lhsisreceiver, case_values, - case_labels, arraysize(case_values)); - for (int32_t i = 0; i < FIRST_NONSTRING_TYPE; ++i) { - assembler->Bind(case_labels[i]); - assembler->Goto(&if_lhsisstring); - delete case_labels[i]; - } - - assembler->Bind(&if_lhsisstring); - { - // Check if {rhs} is also a String. - Label if_rhsisstring(assembler, Label::kDeferred), - if_rhsisnotstring(assembler); - assembler->Branch( - assembler->IsStringInstanceType(rhs_instance_type), - &if_rhsisstring, &if_rhsisnotstring); - - assembler->Bind(&if_rhsisstring); - { - // Both {lhs} and {rhs} are of type String, just do the - // string comparison then. - Callable callable = - (mode == kDontNegateResult) - ? CodeFactory::StringEqual(assembler->isolate()) - : CodeFactory::StringNotEqual(assembler->isolate()); - result.Bind(assembler->CallStub(callable, context, lhs, rhs)); - assembler->Goto(&end); - } - - assembler->Bind(&if_rhsisnotstring); - { - // The {lhs} is a String and the {rhs} is some other HeapObject. - // Swapping {lhs} and {rhs} is not observable and doesn't matter - // for the result, so we can just swap them and use the String - // handling below (for {rhs} being a String). - var_lhs.Bind(rhs); - var_rhs.Bind(lhs); - assembler->Goto(&loop); - } - } - - assembler->Bind(&if_lhsisnumber); - { - // Check if {rhs} is also a HeapNumber. - Label if_rhsisnumber(assembler), if_rhsisnotnumber(assembler); - assembler->Branch( - assembler->Word32Equal(lhs_instance_type, rhs_instance_type), - &if_rhsisnumber, &if_rhsisnotnumber); - - assembler->Bind(&if_rhsisnumber); - { - // Convert {lhs} and {rhs} to floating point values, and - // perform a floating point comparison. - var_fcmp_lhs.Bind(assembler->LoadHeapNumberValue(lhs)); - var_fcmp_rhs.Bind(assembler->LoadHeapNumberValue(rhs)); - assembler->Goto(&do_fcmp); - } - - assembler->Bind(&if_rhsisnotnumber); - { - // The {lhs} is a Number, the {rhs} is some other HeapObject. - Label if_rhsisstring(assembler, Label::kDeferred), - if_rhsisnotstring(assembler); - assembler->Branch( - assembler->IsStringInstanceType(rhs_instance_type), - &if_rhsisstring, &if_rhsisnotstring); - - assembler->Bind(&if_rhsisstring); - { - // The {rhs} is a String and the {lhs} is a HeapNumber; we need - // to convert the {rhs} to a Number and compare the output to - // the Number on the {lhs}. - assembler->Goto(&do_rhsstringtonumber); - } - - assembler->Bind(&if_rhsisnotstring); - { - // Check if the {rhs} is a JSReceiver. - Label if_rhsisreceiver(assembler), - if_rhsisnotreceiver(assembler); - STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE); - assembler->Branch( - assembler->IsJSReceiverInstanceType(rhs_instance_type), - &if_rhsisreceiver, &if_rhsisnotreceiver); - - assembler->Bind(&if_rhsisreceiver); - { - // The {lhs} is a Primitive and the {rhs} is a JSReceiver. - // Swapping {lhs} and {rhs} is not observable and doesn't - // matter for the result, so we can just swap them and use - // the JSReceiver handling below (for {lhs} being a - // JSReceiver). - var_lhs.Bind(rhs); - var_rhs.Bind(lhs); - assembler->Goto(&loop); - } - - assembler->Bind(&if_rhsisnotreceiver); - { - // Check if {rhs} is a Boolean. - Label if_rhsisboolean(assembler), - if_rhsisnotboolean(assembler); - assembler->Branch(assembler->IsBooleanMap(rhs_map), - &if_rhsisboolean, &if_rhsisnotboolean); - - assembler->Bind(&if_rhsisboolean); - { - // The {rhs} is a Boolean, convert it to a Smi first. - var_rhs.Bind(assembler->LoadObjectField( - rhs, Oddball::kToNumberOffset)); - assembler->Goto(&loop); - } - - assembler->Bind(&if_rhsisnotboolean); - assembler->Goto(&if_notequal); - } - } - } - } - - assembler->Bind(&if_lhsisoddball); - { - // The {lhs} is an Oddball and {rhs} is some other HeapObject. - Label if_lhsisboolean(assembler), if_lhsisnotboolean(assembler); - Node* boolean_map = assembler->BooleanMapConstant(); - assembler->Branch(assembler->WordEqual(lhs_map, boolean_map), - &if_lhsisboolean, &if_lhsisnotboolean); - - assembler->Bind(&if_lhsisboolean); - { - // The {lhs} is a Boolean, check if {rhs} is also a Boolean. - Label if_rhsisboolean(assembler), if_rhsisnotboolean(assembler); - assembler->Branch(assembler->WordEqual(rhs_map, boolean_map), - &if_rhsisboolean, &if_rhsisnotboolean); - - assembler->Bind(&if_rhsisboolean); - { - // Both {lhs} and {rhs} are distinct Boolean values. - assembler->Goto(&if_notequal); - } - - assembler->Bind(&if_rhsisnotboolean); - { - // Convert the {lhs} to a Number first. - var_lhs.Bind( - assembler->LoadObjectField(lhs, Oddball::kToNumberOffset)); - assembler->Goto(&loop); - } - } - - assembler->Bind(&if_lhsisnotboolean); - { - // The {lhs} is either Null or Undefined; check if the {rhs} is - // undetectable (i.e. either also Null or Undefined or some - // undetectable JSReceiver). - Node* rhs_bitfield = assembler->LoadMapBitField(rhs_map); - assembler->BranchIfWord32Equal( - assembler->Word32And( - rhs_bitfield, - assembler->Int32Constant(1 << Map::kIsUndetectable)), - assembler->Int32Constant(0), &if_notequal, &if_equal); - } - } - - assembler->Bind(&if_lhsissymbol); - { - // Check if the {rhs} is a JSReceiver. - Label if_rhsisreceiver(assembler), if_rhsisnotreceiver(assembler); - STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE); - assembler->Branch( - assembler->IsJSReceiverInstanceType(rhs_instance_type), - &if_rhsisreceiver, &if_rhsisnotreceiver); - - assembler->Bind(&if_rhsisreceiver); - { - // The {lhs} is a Primitive and the {rhs} is a JSReceiver. - // Swapping {lhs} and {rhs} is not observable and doesn't - // matter for the result, so we can just swap them and use - // the JSReceiver handling below (for {lhs} being a JSReceiver). - var_lhs.Bind(rhs); - var_rhs.Bind(lhs); - assembler->Goto(&loop); - } - - assembler->Bind(&if_rhsisnotreceiver); - { - // The {rhs} is not a JSReceiver and also not the same Symbol - // as the {lhs}, so this is equality check is considered false. - assembler->Goto(&if_notequal); - } - } - - assembler->Bind(&if_lhsissimd128value); - { - // Check if the {rhs} is also a Simd128Value. - Label if_rhsissimd128value(assembler), - if_rhsisnotsimd128value(assembler); - assembler->Branch( - assembler->Word32Equal(lhs_instance_type, rhs_instance_type), - &if_rhsissimd128value, &if_rhsisnotsimd128value); - - assembler->Bind(&if_rhsissimd128value); - { - // Both {lhs} and {rhs} is a Simd128Value. - GenerateEqual_Simd128Value_HeapObject(assembler, lhs, lhs_map, - rhs, rhs_map, &if_equal, - &if_notequal); - } - - assembler->Bind(&if_rhsisnotsimd128value); - { - // Check if the {rhs} is a JSReceiver. - Label if_rhsisreceiver(assembler), if_rhsisnotreceiver(assembler); - STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE); - assembler->Branch( - assembler->IsJSReceiverInstanceType(rhs_instance_type), - &if_rhsisreceiver, &if_rhsisnotreceiver); - - assembler->Bind(&if_rhsisreceiver); - { - // The {lhs} is a Primitive and the {rhs} is a JSReceiver. - // Swapping {lhs} and {rhs} is not observable and doesn't - // matter for the result, so we can just swap them and use - // the JSReceiver handling below (for {lhs} being a JSReceiver). - var_lhs.Bind(rhs); - var_rhs.Bind(lhs); - assembler->Goto(&loop); - } - - assembler->Bind(&if_rhsisnotreceiver); - { - // The {rhs} is some other Primitive. - assembler->Goto(&if_notequal); - } - } - } - - assembler->Bind(&if_lhsisreceiver); - { - // Check if the {rhs} is also a JSReceiver. - Label if_rhsisreceiver(assembler), if_rhsisnotreceiver(assembler); - STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE); - assembler->Branch( - assembler->IsJSReceiverInstanceType(rhs_instance_type), - &if_rhsisreceiver, &if_rhsisnotreceiver); - - assembler->Bind(&if_rhsisreceiver); - { - // Both {lhs} and {rhs} are different JSReceiver references, so - // this cannot be considered equal. - assembler->Goto(&if_notequal); - } - - assembler->Bind(&if_rhsisnotreceiver); - { - // Check if {rhs} is Null or Undefined (an undetectable check - // is sufficient here, since we already know that {rhs} is not - // a JSReceiver). - Label if_rhsisundetectable(assembler), - if_rhsisnotundetectable(assembler, Label::kDeferred); - Node* rhs_bitfield = assembler->LoadMapBitField(rhs_map); - assembler->BranchIfWord32Equal( - assembler->Word32And( - rhs_bitfield, - assembler->Int32Constant(1 << Map::kIsUndetectable)), - assembler->Int32Constant(0), &if_rhsisnotundetectable, - &if_rhsisundetectable); - - assembler->Bind(&if_rhsisundetectable); - { - // Check if {lhs} is an undetectable JSReceiver. - Node* lhs_bitfield = assembler->LoadMapBitField(lhs_map); - assembler->BranchIfWord32Equal( - assembler->Word32And( - lhs_bitfield, - assembler->Int32Constant(1 << Map::kIsUndetectable)), - assembler->Int32Constant(0), &if_notequal, &if_equal); - } - - assembler->Bind(&if_rhsisnotundetectable); - { - // The {rhs} is some Primitive different from Null and - // Undefined, need to convert {lhs} to Primitive first. - Callable callable = - CodeFactory::NonPrimitiveToPrimitive(assembler->isolate()); - var_lhs.Bind(assembler->CallStub(callable, context, lhs)); - assembler->Goto(&loop); - } - } - } - } - } - } - - assembler->Bind(&do_rhsstringtonumber); - { - Callable callable = CodeFactory::StringToNumber(assembler->isolate()); - var_rhs.Bind(assembler->CallStub(callable, context, rhs)); - assembler->Goto(&loop); - } - } - - assembler->Bind(&do_fcmp); - { - // Load the {lhs} and {rhs} floating point values. - Node* lhs = var_fcmp_lhs.value(); - Node* rhs = var_fcmp_rhs.value(); - - // Perform a fast floating point comparison. - assembler->BranchIfFloat64Equal(lhs, rhs, &if_equal, &if_notequal); - } - - assembler->Bind(&if_equal); - { - result.Bind(assembler->BooleanConstant(mode == kDontNegateResult)); - assembler->Goto(&end); - } - - assembler->Bind(&if_notequal); - { - result.Bind(assembler->BooleanConstant(mode == kNegateResult)); - assembler->Goto(&end); - } - - assembler->Bind(&end); - return result.value(); -} - -compiler::Node* GenerateStrictEqual(CodeStubAssembler* assembler, - ResultMode mode, compiler::Node* lhs, - compiler::Node* rhs, - compiler::Node* context) { - // Here's pseudo-code for the algorithm below in case of kDontNegateResult - // mode; for kNegateResult mode we properly negate the result. - // - // if (lhs == rhs) { - // if (lhs->IsHeapNumber()) return HeapNumber::cast(lhs)->value() != NaN; - // return true; - // } - // if (!lhs->IsSmi()) { - // if (lhs->IsHeapNumber()) { - // if (rhs->IsSmi()) { - // return Smi::cast(rhs)->value() == HeapNumber::cast(lhs)->value(); - // } else if (rhs->IsHeapNumber()) { - // return HeapNumber::cast(rhs)->value() == - // HeapNumber::cast(lhs)->value(); - // } else { - // return false; - // } - // } else { - // if (rhs->IsSmi()) { - // return false; - // } else { - // if (lhs->IsString()) { - // if (rhs->IsString()) { - // return %StringEqual(lhs, rhs); - // } else { - // return false; - // } - // } else if (lhs->IsSimd128()) { - // if (rhs->IsSimd128()) { - // return %StrictEqual(lhs, rhs); - // } - // } else { - // return false; - // } - // } - // } - // } else { - // if (rhs->IsSmi()) { - // return false; - // } else { - // if (rhs->IsHeapNumber()) { - // return Smi::cast(lhs)->value() == HeapNumber::cast(rhs)->value(); - // } else { - // return false; - // } - // } - // } - - typedef CodeStubAssembler::Label Label; - typedef CodeStubAssembler::Variable Variable; - typedef compiler::Node Node; - - Label if_equal(assembler), if_notequal(assembler), end(assembler); - Variable result(assembler, MachineRepresentation::kTagged); - - // Check if {lhs} and {rhs} refer to the same object. - Label if_same(assembler), if_notsame(assembler); - assembler->Branch(assembler->WordEqual(lhs, rhs), &if_same, &if_notsame); - - assembler->Bind(&if_same); - { - // The {lhs} and {rhs} reference the exact same value, yet we need special - // treatment for HeapNumber, as NaN is not equal to NaN. - GenerateEqual_Same(assembler, lhs, &if_equal, &if_notequal); - } - - assembler->Bind(&if_notsame); - { - // The {lhs} and {rhs} reference different objects, yet for Smi, HeapNumber, - // String and Simd128Value they can still be considered equal. - Node* number_map = assembler->HeapNumberMapConstant(); - - // Check if {lhs} is a Smi or a HeapObject. - Label if_lhsissmi(assembler), if_lhsisnotsmi(assembler); - assembler->Branch(assembler->WordIsSmi(lhs), &if_lhsissmi, &if_lhsisnotsmi); - - assembler->Bind(&if_lhsisnotsmi); - { - // Load the map of {lhs}. - Node* lhs_map = assembler->LoadMap(lhs); - - // Check if {lhs} is a HeapNumber. - Label if_lhsisnumber(assembler), if_lhsisnotnumber(assembler); - assembler->Branch(assembler->WordEqual(lhs_map, number_map), - &if_lhsisnumber, &if_lhsisnotnumber); - - assembler->Bind(&if_lhsisnumber); - { - // Check if {rhs} is a Smi or a HeapObject. - Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler); - assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi, - &if_rhsisnotsmi); - - assembler->Bind(&if_rhsissmi); - { - // Convert {lhs} and {rhs} to floating point values. - Node* lhs_value = assembler->LoadHeapNumberValue(lhs); - Node* rhs_value = assembler->SmiToFloat64(rhs); - - // Perform a floating point comparison of {lhs} and {rhs}. - assembler->BranchIfFloat64Equal(lhs_value, rhs_value, &if_equal, - &if_notequal); - } - - assembler->Bind(&if_rhsisnotsmi); - { - // Load the map of {rhs}. - Node* rhs_map = assembler->LoadMap(rhs); - - // Check if {rhs} is also a HeapNumber. - Label if_rhsisnumber(assembler), if_rhsisnotnumber(assembler); - assembler->Branch(assembler->WordEqual(rhs_map, number_map), - &if_rhsisnumber, &if_rhsisnotnumber); - - assembler->Bind(&if_rhsisnumber); - { - // Convert {lhs} and {rhs} to floating point values. - Node* lhs_value = assembler->LoadHeapNumberValue(lhs); - Node* rhs_value = assembler->LoadHeapNumberValue(rhs); - - // Perform a floating point comparison of {lhs} and {rhs}. - assembler->BranchIfFloat64Equal(lhs_value, rhs_value, &if_equal, - &if_notequal); - } - - assembler->Bind(&if_rhsisnotnumber); - assembler->Goto(&if_notequal); - } - } - - assembler->Bind(&if_lhsisnotnumber); - { - // Check if {rhs} is a Smi or a HeapObject. - Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler); - assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi, - &if_rhsisnotsmi); - - assembler->Bind(&if_rhsissmi); - assembler->Goto(&if_notequal); - - assembler->Bind(&if_rhsisnotsmi); - { - // Load the instance type of {lhs}. - Node* lhs_instance_type = assembler->LoadMapInstanceType(lhs_map); - - // Check if {lhs} is a String. - Label if_lhsisstring(assembler), if_lhsisnotstring(assembler); - assembler->Branch(assembler->IsStringInstanceType(lhs_instance_type), - &if_lhsisstring, &if_lhsisnotstring); - - assembler->Bind(&if_lhsisstring); - { - // Load the instance type of {rhs}. - Node* rhs_instance_type = assembler->LoadInstanceType(rhs); - - // Check if {rhs} is also a String. - Label if_rhsisstring(assembler, Label::kDeferred), - if_rhsisnotstring(assembler); - assembler->Branch( - assembler->IsStringInstanceType(rhs_instance_type), - &if_rhsisstring, &if_rhsisnotstring); - - assembler->Bind(&if_rhsisstring); - { - Callable callable = - (mode == kDontNegateResult) - ? CodeFactory::StringEqual(assembler->isolate()) - : CodeFactory::StringNotEqual(assembler->isolate()); - result.Bind(assembler->CallStub(callable, context, lhs, rhs)); - assembler->Goto(&end); - } - - assembler->Bind(&if_rhsisnotstring); - assembler->Goto(&if_notequal); - } - - assembler->Bind(&if_lhsisnotstring); - { - // Check if {lhs} is a Simd128Value. - Label if_lhsissimd128value(assembler), - if_lhsisnotsimd128value(assembler); - assembler->Branch(assembler->Word32Equal( - lhs_instance_type, - assembler->Int32Constant(SIMD128_VALUE_TYPE)), - &if_lhsissimd128value, &if_lhsisnotsimd128value); - - assembler->Bind(&if_lhsissimd128value); - { - // Load the map of {rhs}. - Node* rhs_map = assembler->LoadMap(rhs); - - // Check if {rhs} is also a Simd128Value that is equal to {lhs}. - GenerateEqual_Simd128Value_HeapObject(assembler, lhs, lhs_map, - rhs, rhs_map, &if_equal, - &if_notequal); - } - - assembler->Bind(&if_lhsisnotsimd128value); - assembler->Goto(&if_notequal); - } - } - } - } - - assembler->Bind(&if_lhsissmi); - { - // We already know that {lhs} and {rhs} are not reference equal, and {lhs} - // is a Smi; so {lhs} and {rhs} can only be strictly equal if {rhs} is a - // HeapNumber with an equal floating point value. - - // Check if {rhs} is a Smi or a HeapObject. - Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler); - assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi, - &if_rhsisnotsmi); - - assembler->Bind(&if_rhsissmi); - assembler->Goto(&if_notequal); - - assembler->Bind(&if_rhsisnotsmi); - { - // Load the map of the {rhs}. - Node* rhs_map = assembler->LoadMap(rhs); - - // The {rhs} could be a HeapNumber with the same value as {lhs}. - Label if_rhsisnumber(assembler), if_rhsisnotnumber(assembler); - assembler->Branch(assembler->WordEqual(rhs_map, number_map), - &if_rhsisnumber, &if_rhsisnotnumber); - - assembler->Bind(&if_rhsisnumber); - { - // Convert {lhs} and {rhs} to floating point values. - Node* lhs_value = assembler->SmiToFloat64(lhs); - Node* rhs_value = assembler->LoadHeapNumberValue(rhs); - - // Perform a floating point comparison of {lhs} and {rhs}. - assembler->BranchIfFloat64Equal(lhs_value, rhs_value, &if_equal, - &if_notequal); - } - - assembler->Bind(&if_rhsisnotnumber); - assembler->Goto(&if_notequal); - } - } - } - - assembler->Bind(&if_equal); - { - result.Bind(assembler->BooleanConstant(mode == kDontNegateResult)); - assembler->Goto(&end); - } - - assembler->Bind(&if_notequal); - { - result.Bind(assembler->BooleanConstant(mode == kNegateResult)); - assembler->Goto(&end); - } - - assembler->Bind(&end); - return result.value(); -} - -} // namespace - void LoadApiGetterStub::GenerateAssembly(CodeStubAssembler* assembler) const { typedef compiler::Node Node; Node* context = assembler->Parameter(Descriptor::kContext); @@ -4244,7 +2029,7 @@ void StoreGlobalStub::GenerateAssembly(CodeStubAssembler* assembler) const { Node* global = assembler->LoadObjectField(proxy_map, Map::kPrototypeOffset); Node* map_cell = assembler->HeapConstant(isolate()->factory()->NewWeakCell( StoreGlobalStub::global_map_placeholder(isolate()))); - Node* expected_map = assembler->LoadWeakCellValue(map_cell); + Node* expected_map = assembler->LoadWeakCellValueUnchecked(map_cell); Node* map = assembler->LoadMap(global); assembler->GotoIf(assembler->WordNotEqual(expected_map, map), &miss); } @@ -4252,7 +2037,7 @@ void StoreGlobalStub::GenerateAssembly(CodeStubAssembler* assembler) const { Node* weak_cell = assembler->HeapConstant(isolate()->factory()->NewWeakCell( StoreGlobalStub::property_cell_placeholder(isolate()))); Node* cell = assembler->LoadWeakCellValue(weak_cell); - assembler->GotoIf(assembler->WordIsSmi(cell), &miss); + assembler->GotoIf(assembler->TaggedIsSmi(cell), &miss); // Load the payload of the global parameter cell. A hole indicates that the // cell has been invalidated and that the store must be handled by the @@ -4274,7 +2059,7 @@ void StoreGlobalStub::GenerateAssembly(CodeStubAssembler* assembler) const { if (cell_type == PropertyCellType::kConstantType) { switch (constant_type()) { case PropertyCellConstantType::kSmi: - assembler->GotoUnless(assembler->WordIsSmi(value), &miss); + assembler->GotoUnless(assembler->TaggedIsSmi(value), &miss); value_is_smi = true; break; case PropertyCellConstantType::kStableMap: { @@ -4283,8 +2068,8 @@ void StoreGlobalStub::GenerateAssembly(CodeStubAssembler* assembler) const { // are the maps that were originally in the cell or not. If optimized // code will deopt when a cell has a unstable map and if it has a // dependency on a stable map, it will deopt if the map destabilizes. - assembler->GotoIf(assembler->WordIsSmi(value), &miss); - assembler->GotoIf(assembler->WordIsSmi(cell_contents), &miss); + assembler->GotoIf(assembler->TaggedIsSmi(value), &miss); + assembler->GotoIf(assembler->TaggedIsSmi(cell_contents), &miss); Node* expected_map = assembler->LoadMap(cell_contents); Node* map = assembler->LoadMap(value); assembler->GotoIf(assembler->WordNotEqual(expected_map, map), &miss); @@ -4392,155 +2177,6 @@ void StoreScriptContextFieldStub::GenerateAssembly( assembler->Return(value); } -// static -compiler::Node* LessThanStub::Generate(CodeStubAssembler* assembler, - compiler::Node* lhs, compiler::Node* rhs, - compiler::Node* context) { - return GenerateAbstractRelationalComparison(assembler, kLessThan, lhs, rhs, - context); -} - -// static -compiler::Node* LessThanOrEqualStub::Generate(CodeStubAssembler* assembler, - compiler::Node* lhs, - compiler::Node* rhs, - compiler::Node* context) { - return GenerateAbstractRelationalComparison(assembler, kLessThanOrEqual, lhs, - rhs, context); -} - -// static -compiler::Node* GreaterThanStub::Generate(CodeStubAssembler* assembler, - compiler::Node* lhs, - compiler::Node* rhs, - compiler::Node* context) { - return GenerateAbstractRelationalComparison(assembler, kGreaterThan, lhs, rhs, - context); -} - -// static -compiler::Node* GreaterThanOrEqualStub::Generate(CodeStubAssembler* assembler, - compiler::Node* lhs, - compiler::Node* rhs, - compiler::Node* context) { - return GenerateAbstractRelationalComparison(assembler, kGreaterThanOrEqual, - lhs, rhs, context); -} - -// static -compiler::Node* EqualStub::Generate(CodeStubAssembler* assembler, - compiler::Node* lhs, compiler::Node* rhs, - compiler::Node* context) { - return GenerateEqual(assembler, kDontNegateResult, lhs, rhs, context); -} - -// static -compiler::Node* NotEqualStub::Generate(CodeStubAssembler* assembler, - compiler::Node* lhs, compiler::Node* rhs, - compiler::Node* context) { - return GenerateEqual(assembler, kNegateResult, lhs, rhs, context); -} - -// static -compiler::Node* StrictEqualStub::Generate(CodeStubAssembler* assembler, - compiler::Node* lhs, - compiler::Node* rhs, - compiler::Node* context) { - return GenerateStrictEqual(assembler, kDontNegateResult, lhs, rhs, context); -} - -// static -compiler::Node* StrictNotEqualStub::Generate(CodeStubAssembler* assembler, - compiler::Node* lhs, - compiler::Node* rhs, - compiler::Node* context) { - return GenerateStrictEqual(assembler, kNegateResult, lhs, rhs, context); -} - -void ToLengthStub::GenerateAssembly(CodeStubAssembler* assembler) const { - typedef CodeStubAssembler::Label Label; - typedef compiler::Node Node; - typedef CodeStubAssembler::Variable Variable; - - Node* context = assembler->Parameter(1); - - // We might need to loop once for ToNumber conversion. - Variable var_len(assembler, MachineRepresentation::kTagged); - Label loop(assembler, &var_len); - var_len.Bind(assembler->Parameter(0)); - assembler->Goto(&loop); - assembler->Bind(&loop); - { - // Shared entry points. - Label return_len(assembler), - return_two53minus1(assembler, Label::kDeferred), - return_zero(assembler, Label::kDeferred); - - // Load the current {len} value. - Node* len = var_len.value(); - - // Check if {len} is a positive Smi. - assembler->GotoIf(assembler->WordIsPositiveSmi(len), &return_len); - - // Check if {len} is a (negative) Smi. - assembler->GotoIf(assembler->WordIsSmi(len), &return_zero); - - // Check if {len} is a HeapNumber. - Label if_lenisheapnumber(assembler), - if_lenisnotheapnumber(assembler, Label::kDeferred); - assembler->Branch(assembler->IsHeapNumberMap(assembler->LoadMap(len)), - &if_lenisheapnumber, &if_lenisnotheapnumber); - - assembler->Bind(&if_lenisheapnumber); - { - // Load the floating-point value of {len}. - Node* len_value = assembler->LoadHeapNumberValue(len); - - // Check if {len} is not greater than zero. - assembler->GotoUnless(assembler->Float64GreaterThan( - len_value, assembler->Float64Constant(0.0)), - &return_zero); - - // Check if {len} is greater than or equal to 2^53-1. - assembler->GotoIf( - assembler->Float64GreaterThanOrEqual( - len_value, assembler->Float64Constant(kMaxSafeInteger)), - &return_two53minus1); - - // Round the {len} towards -Infinity. - Node* value = assembler->Float64Floor(len_value); - Node* result = assembler->ChangeFloat64ToTagged(value); - assembler->Return(result); - } - - assembler->Bind(&if_lenisnotheapnumber); - { - // Need to convert {len} to a Number first. - Callable callable = CodeFactory::NonNumberToNumber(assembler->isolate()); - var_len.Bind(assembler->CallStub(callable, context, len)); - assembler->Goto(&loop); - } - - assembler->Bind(&return_len); - assembler->Return(var_len.value()); - - assembler->Bind(&return_two53minus1); - assembler->Return(assembler->NumberConstant(kMaxSafeInteger)); - - assembler->Bind(&return_zero); - assembler->Return(assembler->SmiConstant(Smi::FromInt(0))); - } -} - -void ToIntegerStub::GenerateAssembly(CodeStubAssembler* assembler) const { - typedef compiler::Node Node; - - Node* input = assembler->Parameter(Descriptor::kArgument); - Node* context = assembler->Parameter(Descriptor::kContext); - - assembler->Return(assembler->ToInteger(context, input)); -} - void StoreInterceptorStub::GenerateAssembly( CodeStubAssembler* assembler) const { typedef compiler::Node Node; @@ -4713,27 +2349,6 @@ void HydrogenCodeStub::TraceTransition(StateType from, StateType to) { os << ": " << from << "=>" << to << "]" << std::endl; } - -// TODO(svenpanne) Make this a real infix_ostream_iterator. -class SimpleListPrinter { - public: - explicit SimpleListPrinter(std::ostream& os) : os_(os), first_(true) {} - - void Add(const char* s) { - if (first_) { - first_ = false; - } else { - os_ << ","; - } - os_ << s; - } - - private: - std::ostream& os_; - bool first_; -}; - - void CallICStub::PrintState(std::ostream& os) const { // NOLINT os << state(); } @@ -4753,14 +2368,6 @@ void LoadDictionaryElementStub::InitializeDescriptor( FUNCTION_ADDR(Runtime_KeyedLoadIC_MissFromStubFailure)); } - -void KeyedLoadGenericStub::InitializeDescriptor( - CodeStubDescriptor* descriptor) { - descriptor->Initialize( - Runtime::FunctionForId(Runtime::kKeyedGetProperty)->entry); -} - - void HandlerStub::InitializeDescriptor(CodeStubDescriptor* descriptor) { DCHECK(kind() == Code::LOAD_IC || kind() == Code::KEYED_LOAD_IC); if (kind() == Code::KEYED_LOAD_IC) { @@ -4779,21 +2386,6 @@ CallInterfaceDescriptor HandlerStub::GetCallInterfaceDescriptor() const { } } - -void NumberToStringStub::InitializeDescriptor(CodeStubDescriptor* descriptor) { - descriptor->Initialize( - Runtime::FunctionForId(Runtime::kNumberToString)->entry); - descriptor->SetMissHandler(Runtime::kNumberToString); -} - -void RegExpConstructResultStub::InitializeDescriptor( - CodeStubDescriptor* descriptor) { - descriptor->Initialize( - Runtime::FunctionForId(Runtime::kRegExpConstructResult)->entry); - descriptor->SetMissHandler(Runtime::kRegExpConstructResult); -} - - void TransitionElementsKindStub::InitializeDescriptor( CodeStubDescriptor* descriptor) { descriptor->Initialize( @@ -4835,118 +2427,6 @@ void BinaryOpWithAllocationSiteStub::InitializeDescriptor( FUNCTION_ADDR(Runtime_BinaryOpIC_MissWithAllocationSite)); } - -void StringAddStub::InitializeDescriptor(CodeStubDescriptor* descriptor) { - descriptor->Initialize(Runtime::FunctionForId(Runtime::kStringAdd)->entry); - descriptor->SetMissHandler(Runtime::kStringAdd); -} - -namespace { - -compiler::Node* GenerateHasProperty( - CodeStubAssembler* assembler, compiler::Node* object, compiler::Node* key, - compiler::Node* context, Runtime::FunctionId fallback_runtime_function_id) { - typedef compiler::Node Node; - typedef CodeStubAssembler::Label Label; - typedef CodeStubAssembler::Variable Variable; - - Label call_runtime(assembler, Label::kDeferred), return_true(assembler), - return_false(assembler), end(assembler); - - CodeStubAssembler::LookupInHolder lookup_property_in_holder = - [assembler, &return_true](Node* receiver, Node* holder, Node* holder_map, - Node* holder_instance_type, Node* unique_name, - Label* next_holder, Label* if_bailout) { - assembler->TryHasOwnProperty(holder, holder_map, holder_instance_type, - unique_name, &return_true, next_holder, - if_bailout); - }; - - CodeStubAssembler::LookupInHolder lookup_element_in_holder = - [assembler, &return_true](Node* receiver, Node* holder, Node* holder_map, - Node* holder_instance_type, Node* index, - Label* next_holder, Label* if_bailout) { - assembler->TryLookupElement(holder, holder_map, holder_instance_type, - index, &return_true, next_holder, - if_bailout); - }; - - assembler->TryPrototypeChainLookup(object, key, lookup_property_in_holder, - lookup_element_in_holder, &return_false, - &call_runtime); - - Variable result(assembler, MachineRepresentation::kTagged); - assembler->Bind(&return_true); - { - result.Bind(assembler->BooleanConstant(true)); - assembler->Goto(&end); - } - - assembler->Bind(&return_false); - { - result.Bind(assembler->BooleanConstant(false)); - assembler->Goto(&end); - } - - assembler->Bind(&call_runtime); - { - result.Bind(assembler->CallRuntime(fallback_runtime_function_id, context, - object, key)); - assembler->Goto(&end); - } - - assembler->Bind(&end); - return result.value(); -} - -} // namespace - -// static -compiler::Node* HasPropertyStub::Generate(CodeStubAssembler* assembler, - compiler::Node* key, - compiler::Node* object, - compiler::Node* context) { - return GenerateHasProperty(assembler, object, key, context, - Runtime::kHasProperty); -} - -// static -compiler::Node* ForInFilterStub::Generate(CodeStubAssembler* assembler, - compiler::Node* key, - compiler::Node* object, - compiler::Node* context) { - typedef compiler::Node Node; - typedef CodeStubAssembler::Label Label; - typedef CodeStubAssembler::Variable Variable; - - Label return_undefined(assembler, Label::kDeferred), - return_to_name(assembler), end(assembler); - - Variable var_result(assembler, MachineRepresentation::kTagged); - - Node* has_property = GenerateHasProperty(assembler, object, key, context, - Runtime::kForInHasProperty); - - assembler->Branch( - assembler->WordEqual(has_property, assembler->BooleanConstant(true)), - &return_to_name, &return_undefined); - - assembler->Bind(&return_to_name); - { - var_result.Bind(assembler->ToName(context, key)); - assembler->Goto(&end); - } - - assembler->Bind(&return_undefined); - { - var_result.Bind(assembler->UndefinedConstant()); - assembler->Goto(&end); - } - - assembler->Bind(&end); - return var_result.value(); -} - void GetPropertyStub::GenerateAssembly(CodeStubAssembler* assembler) const { typedef compiler::Node Node; typedef CodeStubAssembler::Label Label; @@ -5064,12 +2544,13 @@ compiler::Node* FastNewClosureStub::Generate(CodeStubAssembler* assembler, if (FLAG_debug_code) { // Function must be a function without a prototype. - assembler->Assert(assembler->Word32And( - compiler_hints, - assembler->Int32Constant((FunctionKind::kAccessorFunction | - FunctionKind::kArrowFunction | - FunctionKind::kConciseMethod) - << SharedFunctionInfo::kFunctionKindShift))); + CSA_ASSERT(assembler, assembler->Word32And( + compiler_hints, + assembler->Int32Constant( + (FunctionKind::kAccessorFunction | + FunctionKind::kArrowFunction | + FunctionKind::kConciseMethod) + << SharedFunctionInfo::kFunctionKindShift))); } assembler->Goto(&if_function_without_prototype); @@ -5167,9 +2648,7 @@ void FastNewClosureStub::GenerateAssembly(CodeStubAssembler* assembler) const { compiler::Node* FastNewFunctionContextStub::Generate( CodeStubAssembler* assembler, compiler::Node* function, compiler::Node* slots, compiler::Node* context) { - typedef CodeStubAssembler::Label Label; typedef compiler::Node Node; - typedef CodeStubAssembler::Variable Variable; Node* min_context_slots = assembler->Int32Constant(Context::MIN_CONTEXT_SLOTS); @@ -5208,24 +2687,12 @@ compiler::Node* FastNewFunctionContextStub::Generate( // Initialize the rest of the slots to undefined. Node* undefined = assembler->UndefinedConstant(); - Variable var_slot_index(assembler, MachineRepresentation::kWord32); - var_slot_index.Bind(min_context_slots); - Label loop(assembler, &var_slot_index), after_loop(assembler); - assembler->Goto(&loop); - - assembler->Bind(&loop); - { - Node* slot_index = var_slot_index.value(); - assembler->GotoUnless(assembler->Int32LessThan(slot_index, length), - &after_loop); - assembler->StoreFixedArrayElement(function_context, slot_index, undefined, - SKIP_WRITE_BARRIER); - Node* one = assembler->Int32Constant(1); - Node* next_index = assembler->Int32Add(slot_index, one); - var_slot_index.Bind(next_index); - assembler->Goto(&loop); - } - assembler->Bind(&after_loop); + assembler->BuildFastFixedArrayForEach( + function_context, FAST_ELEMENTS, min_context_slots, length, + [undefined](CodeStubAssembler* assembler, Node* context, Node* offset) { + assembler->StoreNoWriteBarrier(MachineType::PointerRepresentation(), + context, offset, undefined); + }); return function_context; } @@ -5380,7 +2847,7 @@ compiler::Node* FastCloneShallowArrayStub::Generate( allocation_site = allocation_site_mode == TRACK_ALLOCATION_SITE ? allocation_site : nullptr; - Node* zero = assembler->SmiConstant(Smi::FromInt(0)); + Node* zero = assembler->SmiConstant(Smi::kZero); assembler->GotoIf(assembler->SmiEqual(capacity, zero), &zero_capacity); Node* elements_map = assembler->LoadMap(boilerplate_elements); @@ -5391,14 +2858,16 @@ compiler::Node* FastCloneShallowArrayStub::Generate( assembler->Comment("fast double elements path"); if (FLAG_debug_code) { Label correct_elements_map(assembler), abort(assembler, Label::kDeferred); - assembler->BranchIf(assembler->IsFixedDoubleArrayMap(elements_map), - &correct_elements_map, &abort); + assembler->Branch(assembler->IsFixedDoubleArrayMap(elements_map), + &correct_elements_map, &abort); assembler->Bind(&abort); { Node* abort_id = assembler->SmiConstant( Smi::FromInt(BailoutReason::kExpectedFixedDoubleArrayMap)); - assembler->TailCallRuntime(Runtime::kAbort, context, abort_id); + assembler->CallRuntime(Runtime::kAbort, context, abort_id); + result.Bind(assembler->UndefinedConstant()); + assembler->Goto(&return_result); } assembler->Bind(&correct_elements_map); } @@ -5544,103 +3013,54 @@ void StoreFastElementStub::GenerateAheadOfTime(Isolate* isolate) { } } -void ArrayConstructorStub::PrintName(std::ostream& os) const { // NOLINT - os << "ArrayConstructorStub"; - switch (argument_count()) { - case ANY: - os << "_Any"; - break; - case NONE: - os << "_None"; - break; - case ONE: - os << "_One"; - break; - case MORE_THAN_ONE: - os << "_More_Than_One"; - break; - } - return; -} - - bool ToBooleanICStub::UpdateStatus(Handle<Object> object) { - Types new_types = types(); - Types old_types = new_types; - bool to_boolean_value = new_types.UpdateStatus(isolate(), object); - TraceTransition(old_types, new_types); - set_sub_minor_key(TypesBits::update(sub_minor_key(), new_types.ToIntegral())); - return to_boolean_value; -} - -void ToBooleanICStub::PrintState(std::ostream& os) const { // NOLINT - os << types(); -} - -std::ostream& operator<<(std::ostream& os, const ToBooleanICStub::Types& s) { - os << "("; - SimpleListPrinter p(os); - if (s.IsEmpty()) p.Add("None"); - if (s.Contains(ToBooleanICStub::UNDEFINED)) p.Add("Undefined"); - if (s.Contains(ToBooleanICStub::BOOLEAN)) p.Add("Bool"); - if (s.Contains(ToBooleanICStub::NULL_TYPE)) p.Add("Null"); - if (s.Contains(ToBooleanICStub::SMI)) p.Add("Smi"); - if (s.Contains(ToBooleanICStub::SPEC_OBJECT)) p.Add("SpecObject"); - if (s.Contains(ToBooleanICStub::STRING)) p.Add("String"); - if (s.Contains(ToBooleanICStub::SYMBOL)) p.Add("Symbol"); - if (s.Contains(ToBooleanICStub::HEAP_NUMBER)) p.Add("HeapNumber"); - if (s.Contains(ToBooleanICStub::SIMD_VALUE)) p.Add("SimdValue"); - return os << ")"; -} - -bool ToBooleanICStub::Types::UpdateStatus(Isolate* isolate, - Handle<Object> object) { - if (object->IsUndefined(isolate)) { - Add(UNDEFINED); - return false; + ToBooleanHints old_hints = hints(); + ToBooleanHints new_hints = old_hints; + bool to_boolean_value = false; // Dummy initialization. + if (object->IsUndefined(isolate())) { + new_hints |= ToBooleanHint::kUndefined; + to_boolean_value = false; } else if (object->IsBoolean()) { - Add(BOOLEAN); - return object->IsTrue(isolate); - } else if (object->IsNull(isolate)) { - Add(NULL_TYPE); - return false; + new_hints |= ToBooleanHint::kBoolean; + to_boolean_value = object->IsTrue(isolate()); + } else if (object->IsNull(isolate())) { + new_hints |= ToBooleanHint::kNull; + to_boolean_value = false; } else if (object->IsSmi()) { - Add(SMI); - return Smi::cast(*object)->value() != 0; + new_hints |= ToBooleanHint::kSmallInteger; + to_boolean_value = Smi::cast(*object)->value() != 0; } else if (object->IsJSReceiver()) { - Add(SPEC_OBJECT); - return !object->IsUndetectable(); + new_hints |= ToBooleanHint::kReceiver; + to_boolean_value = !object->IsUndetectable(); } else if (object->IsString()) { DCHECK(!object->IsUndetectable()); - Add(STRING); - return String::cast(*object)->length() != 0; + new_hints |= ToBooleanHint::kString; + to_boolean_value = String::cast(*object)->length() != 0; } else if (object->IsSymbol()) { - Add(SYMBOL); - return true; + new_hints |= ToBooleanHint::kSymbol; + to_boolean_value = true; } else if (object->IsHeapNumber()) { DCHECK(!object->IsUndetectable()); - Add(HEAP_NUMBER); + new_hints |= ToBooleanHint::kHeapNumber; double value = HeapNumber::cast(*object)->value(); - return value != 0 && !std::isnan(value); + to_boolean_value = value != 0 && !std::isnan(value); } else if (object->IsSimd128Value()) { - Add(SIMD_VALUE); - return true; + new_hints |= ToBooleanHint::kSimdValue; + to_boolean_value = true; } else { // We should never see an internal object at runtime here! UNREACHABLE(); - return true; + to_boolean_value = true; } + TraceTransition(old_hints, new_hints); + set_sub_minor_key(HintsBits::update(sub_minor_key(), new_hints)); + return to_boolean_value; } -bool ToBooleanICStub::Types::NeedsMap() const { - return Contains(ToBooleanICStub::SPEC_OBJECT) || - Contains(ToBooleanICStub::STRING) || - Contains(ToBooleanICStub::SYMBOL) || - Contains(ToBooleanICStub::HEAP_NUMBER) || - Contains(ToBooleanICStub::SIMD_VALUE); +void ToBooleanICStub::PrintState(std::ostream& os) const { // NOLINT + os << hints(); } - void StubFailureTrampolineStub::GenerateAheadOfTime(Isolate* isolate) { StubFailureTrampolineStub stub1(isolate, NOT_JS_FUNCTION_STUB_MODE); StubFailureTrampolineStub stub2(isolate, JS_FUNCTION_STUB_MODE); @@ -5687,7 +3107,7 @@ void ArrayNoArgumentConstructorStub::GenerateAssembly( Node* array = assembler->AllocateJSArray( elements_kind(), array_map, assembler->IntPtrConstant(JSArray::kPreallocatedArrayElements), - assembler->SmiConstant(Smi::FromInt(0)), allocation_site); + assembler->SmiConstant(Smi::kZero), allocation_site); assembler->Return(array); } @@ -5700,7 +3120,7 @@ void InternalArrayNoArgumentConstructorStub::GenerateAssembly( Node* array = assembler->AllocateJSArray( elements_kind(), array_map, assembler->IntPtrConstant(JSArray::kPreallocatedArrayElements), - assembler->SmiConstant(Smi::FromInt(0)), nullptr); + assembler->SmiConstant(Smi::kZero), nullptr); assembler->Return(array); } @@ -5721,14 +3141,14 @@ void SingleArgumentConstructorCommon(CodeStubAssembler* assembler, Label call_runtime(assembler, Label::kDeferred); Node* size = assembler->Parameter(Descriptor::kArraySizeSmiParameter); - assembler->Branch(assembler->WordIsSmi(size), &smi_size, &call_runtime); + assembler->Branch(assembler->TaggedIsSmi(size), &smi_size, &call_runtime); assembler->Bind(&smi_size); if (IsFastPackedElementsKind(elements_kind)) { Label abort(assembler, Label::kDeferred); assembler->Branch( - assembler->SmiEqual(size, assembler->SmiConstant(Smi::FromInt(0))), + assembler->SmiEqual(size, assembler->SmiConstant(Smi::kZero)), &small_smi_size, &abort); assembler->Bind(&abort); @@ -5828,42 +3248,10 @@ void GrowArrayElementsStub::GenerateAssembly( } ArrayConstructorStub::ArrayConstructorStub(Isolate* isolate) - : PlatformCodeStub(isolate) { - minor_key_ = ArgumentCountBits::encode(ANY); -} - -ArrayConstructorStub::ArrayConstructorStub(Isolate* isolate, - int argument_count) - : PlatformCodeStub(isolate) { - if (argument_count == 0) { - minor_key_ = ArgumentCountBits::encode(NONE); - } else if (argument_count == 1) { - minor_key_ = ArgumentCountBits::encode(ONE); - } else if (argument_count >= 2) { - minor_key_ = ArgumentCountBits::encode(MORE_THAN_ONE); - } else { - UNREACHABLE(); - } -} + : PlatformCodeStub(isolate) {} InternalArrayConstructorStub::InternalArrayConstructorStub(Isolate* isolate) : PlatformCodeStub(isolate) {} -Representation RepresentationFromMachineType(MachineType type) { - if (type == MachineType::Int32()) { - return Representation::Integer32(); - } - - if (type == MachineType::TaggedSigned()) { - return Representation::Smi(); - } - - if (type == MachineType::Pointer()) { - return Representation::External(); - } - - return Representation::Tagged(); -} - } // namespace internal } // namespace v8 |