diff --git a/BUILD.gn b/BUILD.gn index a75e8b8d5d..73204bf6d7 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -937,6 +937,8 @@ v8_source_set("v8_builtins_generators") { "src/builtins/builtins-wasm-gen.cc", "src/ic/accessor-assembler.cc", "src/ic/accessor-assembler.h", + "src/ic/binary-op-assembler.cc", + "src/ic/binary-op-assembler.h", "src/ic/keyed-store-generic.cc", "src/ic/keyed-store-generic.h", "src/interpreter/interpreter-assembler.cc", diff --git a/src/builtins/builtins-number-gen.cc b/src/builtins/builtins-number-gen.cc index 1bfa34cd91..85f494e7c6 100644 --- a/src/builtins/builtins-number-gen.cc +++ b/src/builtins/builtins-number-gen.cc @@ -5,6 +5,7 @@ #include "src/builtins/builtins-utils-gen.h" #include "src/builtins/builtins.h" #include "src/code-stub-assembler.h" +#include "src/ic/binary-op-assembler.h" namespace v8 { namespace internal { @@ -1392,5 +1393,27 @@ TF_BUILTIN(StrictEqual, CodeStubAssembler) { Return(StrictEqual(lhs, rhs)); } +TF_BUILTIN(AddWithFeedback, BinaryOpAssembler) { + Node* context = Parameter(Descriptor::kContext); + Node* left = Parameter(Descriptor::kLeft); + Node* right = Parameter(Descriptor::kRight); + Node* slot = Parameter(Descriptor::kSlot); + Node* vector = Parameter(Descriptor::kVector); + + Return(Generate_AddWithFeedback(context, left, right, + ChangeUint32ToWord(slot), vector)); +} + +TF_BUILTIN(SubtractWithFeedback, BinaryOpAssembler) { + Node* context = Parameter(Descriptor::kContext); + Node* left = Parameter(Descriptor::kLeft); + Node* right = Parameter(Descriptor::kRight); + Node* slot = Parameter(Descriptor::kSlot); + Node* vector = Parameter(Descriptor::kVector); + + Return(Generate_SubtractWithFeedback(context, left, right, + ChangeUint32ToWord(slot), vector)); +} + } // namespace internal } // namespace v8 diff --git a/src/builtins/builtins.h b/src/builtins/builtins.h index 2445dae2ae..6479535109 100644 --- a/src/builtins/builtins.h +++ b/src/builtins/builtins.h @@ -635,6 +635,8 @@ class Isolate; TFS(GreaterThanOrEqual, BUILTIN, kNoExtraICState, Compare, 1) \ TFS(Equal, BUILTIN, kNoExtraICState, Compare, 1) \ TFS(StrictEqual, BUILTIN, kNoExtraICState, Compare, 1) \ + TFS(AddWithFeedback, BUILTIN, kNoExtraICState, BinaryOpWithVector, 1) \ + TFS(SubtractWithFeedback, BUILTIN, kNoExtraICState, BinaryOpWithVector, 1) \ \ /* Object */ \ CPP(ObjectAssign) \ diff --git a/src/code-stubs.cc b/src/code-stubs.cc index 32bc87e79b..2f8891ffec 100644 --- a/src/code-stubs.cc +++ b/src/code-stubs.cc @@ -491,906 +491,6 @@ TF_STUB(StringLengthStub, CodeStubAssembler) { Return(result); } -// TODO(ishell): Move to appropriate file. -class BinaryOpAssembler : public CodeStubAssembler { - public: - typedef compiler::Node Node; - - explicit BinaryOpAssembler(compiler::CodeAssemblerState* state) - : CodeStubAssembler(state) {} - - void GenerateConstructor(Node* context, Node* array_function, Node* array_map, - Node* array_size, Node* allocation_site, - ElementsKind elements_kind, AllocationSiteMode mode); - - Node* Generate_AddWithFeedback(Node* context, Node* lhs, Node* rhs, - Node* slot_id, Node* feedback_vector); - - Node* Generate_SubtractWithFeedback(Node* context, Node* lhs, Node* rhs, - Node* slot_id, Node* feedback_vector); - - Node* Generate_MultiplyWithFeedback(Node* context, Node* lhs, Node* rhs, - Node* slot_id, Node* feedback_vector); - - Node* Generate_DivideWithFeedback(Node* context, Node* dividend, - Node* divisor, Node* slot_id, - Node* feedback_vector); - - Node* Generate_ModulusWithFeedback(Node* context, Node* dividend, - Node* divisor, Node* slot_id, - Node* feedback_vector); -}; - -compiler::Node* BinaryOpAssembler::Generate_AddWithFeedback( - Node* context, Node* lhs, Node* rhs, Node* slot_id, Node* feedback_vector) { - // Shared entry for floating point addition. - Label do_fadd(this), if_lhsisnotnumber(this, Label::kDeferred), - check_rhsisoddball(this, Label::kDeferred), - call_with_oddball_feedback(this), call_with_any_feedback(this), - call_add_stub(this), end(this); - Variable var_fadd_lhs(this, MachineRepresentation::kFloat64), - var_fadd_rhs(this, MachineRepresentation::kFloat64), - var_type_feedback(this, MachineRepresentation::kTaggedSigned), - var_result(this, MachineRepresentation::kTagged); - - // Check if the {lhs} is a Smi or a HeapObject. - Label if_lhsissmi(this), if_lhsisnotsmi(this); - Branch(TaggedIsSmi(lhs), &if_lhsissmi, &if_lhsisnotsmi); - - Bind(&if_lhsissmi); - { - // Check if the {rhs} is also a Smi. - Label if_rhsissmi(this), if_rhsisnotsmi(this); - Branch(TaggedIsSmi(rhs), &if_rhsissmi, &if_rhsisnotsmi); - - Bind(&if_rhsissmi); - { - // Try fast Smi addition first. - Node* pair = IntPtrAddWithOverflow(BitcastTaggedToWord(lhs), - BitcastTaggedToWord(rhs)); - Node* overflow = Projection(1, pair); - - // Check if the Smi additon overflowed. - Label if_overflow(this), if_notoverflow(this); - Branch(overflow, &if_overflow, &if_notoverflow); - - Bind(&if_overflow); - { - var_fadd_lhs.Bind(SmiToFloat64(lhs)); - var_fadd_rhs.Bind(SmiToFloat64(rhs)); - Goto(&do_fadd); - } - - Bind(&if_notoverflow); - { - var_type_feedback.Bind( - SmiConstant(BinaryOperationFeedback::kSignedSmall)); - var_result.Bind(BitcastWordToTaggedSigned(Projection(0, pair))); - Goto(&end); - } - } - - Bind(&if_rhsisnotsmi); - { - // Load the map of {rhs}. - Node* rhs_map = LoadMap(rhs); - - // Check if the {rhs} is a HeapNumber. - GotoIfNot(IsHeapNumberMap(rhs_map), &check_rhsisoddball); - - var_fadd_lhs.Bind(SmiToFloat64(lhs)); - var_fadd_rhs.Bind(LoadHeapNumberValue(rhs)); - Goto(&do_fadd); - } - } - - Bind(&if_lhsisnotsmi); - { - // Load the map of {lhs}. - Node* lhs_map = LoadMap(lhs); - - // Check if {lhs} is a HeapNumber. - GotoIfNot(IsHeapNumberMap(lhs_map), &if_lhsisnotnumber); - - // Check if the {rhs} is Smi. - Label if_rhsissmi(this), if_rhsisnotsmi(this); - Branch(TaggedIsSmi(rhs), &if_rhsissmi, &if_rhsisnotsmi); - - Bind(&if_rhsissmi); - { - var_fadd_lhs.Bind(LoadHeapNumberValue(lhs)); - var_fadd_rhs.Bind(SmiToFloat64(rhs)); - Goto(&do_fadd); - } - - Bind(&if_rhsisnotsmi); - { - // Load the map of {rhs}. - Node* rhs_map = LoadMap(rhs); - - // Check if the {rhs} is a HeapNumber. - GotoIfNot(IsHeapNumberMap(rhs_map), &check_rhsisoddball); - - var_fadd_lhs.Bind(LoadHeapNumberValue(lhs)); - var_fadd_rhs.Bind(LoadHeapNumberValue(rhs)); - Goto(&do_fadd); - } - } - - Bind(&do_fadd); - { - var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kNumber)); - Node* value = Float64Add(var_fadd_lhs.value(), var_fadd_rhs.value()); - Node* result = AllocateHeapNumberWithValue(value); - var_result.Bind(result); - Goto(&end); - } - - Bind(&if_lhsisnotnumber); - { - // No checks on rhs are done yet. We just know lhs is not a number or Smi. - Label if_lhsisoddball(this), if_lhsisnotoddball(this); - Node* lhs_instance_type = LoadInstanceType(lhs); - Node* lhs_is_oddball = - Word32Equal(lhs_instance_type, Int32Constant(ODDBALL_TYPE)); - Branch(lhs_is_oddball, &if_lhsisoddball, &if_lhsisnotoddball); - - Bind(&if_lhsisoddball); - { - GotoIf(TaggedIsSmi(rhs), &call_with_oddball_feedback); - - // Load the map of the {rhs}. - Node* rhs_map = LoadMap(rhs); - - // Check if {rhs} is a HeapNumber. - Branch(IsHeapNumberMap(rhs_map), &call_with_oddball_feedback, - &check_rhsisoddball); - } - - Bind(&if_lhsisnotoddball); - { - // Exit unless {lhs} is a string - GotoIfNot(IsStringInstanceType(lhs_instance_type), - &call_with_any_feedback); - - // Check if the {rhs} is a smi, and exit the string check early if it is. - GotoIf(TaggedIsSmi(rhs), &call_with_any_feedback); - - Node* rhs_instance_type = LoadInstanceType(rhs); - - // Exit unless {rhs} is a string. Since {lhs} is a string we no longer - // need an Oddball check. - GotoIfNot(IsStringInstanceType(rhs_instance_type), - &call_with_any_feedback); - - var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kString)); - Callable callable = - CodeFactory::StringAdd(isolate(), STRING_ADD_CHECK_NONE, NOT_TENURED); - var_result.Bind(CallStub(callable, context, lhs, rhs)); - - Goto(&end); - } - } - - 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 = LoadInstanceType(rhs); - Node* rhs_is_oddball = - Word32Equal(rhs_instance_type, Int32Constant(ODDBALL_TYPE)); - Branch(rhs_is_oddball, &call_with_oddball_feedback, - &call_with_any_feedback); - } - - Bind(&call_with_oddball_feedback); - { - var_type_feedback.Bind( - SmiConstant(BinaryOperationFeedback::kNumberOrOddball)); - Goto(&call_add_stub); - } - - Bind(&call_with_any_feedback); - { - var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kAny)); - Goto(&call_add_stub); - } - - Bind(&call_add_stub); - { - Callable callable = CodeFactory::Add(isolate()); - var_result.Bind(CallStub(callable, context, lhs, rhs)); - Goto(&end); - } - - Bind(&end); - UpdateFeedback(var_type_feedback.value(), feedback_vector, slot_id); - return var_result.value(); -} - -compiler::Node* BinaryOpAssembler::Generate_SubtractWithFeedback( - Node* context, Node* lhs, Node* rhs, Node* slot_id, Node* feedback_vector) { - // Shared entry for floating point subtraction. - Label do_fsub(this), end(this), call_subtract_stub(this), - if_lhsisnotnumber(this), check_rhsisoddball(this), - call_with_any_feedback(this); - Variable var_fsub_lhs(this, MachineRepresentation::kFloat64), - var_fsub_rhs(this, MachineRepresentation::kFloat64), - var_type_feedback(this, MachineRepresentation::kTaggedSigned), - var_result(this, MachineRepresentation::kTagged); - - // Check if the {lhs} is a Smi or a HeapObject. - Label if_lhsissmi(this), if_lhsisnotsmi(this); - Branch(TaggedIsSmi(lhs), &if_lhsissmi, &if_lhsisnotsmi); - - Bind(&if_lhsissmi); - { - // Check if the {rhs} is also a Smi. - Label if_rhsissmi(this), if_rhsisnotsmi(this); - Branch(TaggedIsSmi(rhs), &if_rhsissmi, &if_rhsisnotsmi); - - Bind(&if_rhsissmi); - { - // Try a fast Smi subtraction first. - Node* pair = IntPtrSubWithOverflow(BitcastTaggedToWord(lhs), - BitcastTaggedToWord(rhs)); - Node* overflow = Projection(1, pair); - - // Check if the Smi subtraction overflowed. - Label if_overflow(this), if_notoverflow(this); - Branch(overflow, &if_overflow, &if_notoverflow); - - Bind(&if_overflow); - { - // lhs, rhs - smi and result - number. combined - number. - // The result doesn't fit into Smi range. - var_fsub_lhs.Bind(SmiToFloat64(lhs)); - var_fsub_rhs.Bind(SmiToFloat64(rhs)); - Goto(&do_fsub); - } - - Bind(&if_notoverflow); - // lhs, rhs, result smi. combined - smi. - var_type_feedback.Bind( - SmiConstant(BinaryOperationFeedback::kSignedSmall)); - var_result.Bind(BitcastWordToTaggedSigned(Projection(0, pair))); - Goto(&end); - } - - Bind(&if_rhsisnotsmi); - { - // Load the map of the {rhs}. - Node* rhs_map = LoadMap(rhs); - - // Check if {rhs} is a HeapNumber. - GotoIfNot(IsHeapNumberMap(rhs_map), &check_rhsisoddball); - - // Perform a floating point subtraction. - var_fsub_lhs.Bind(SmiToFloat64(lhs)); - var_fsub_rhs.Bind(LoadHeapNumberValue(rhs)); - Goto(&do_fsub); - } - } - - Bind(&if_lhsisnotsmi); - { - // Load the map of the {lhs}. - Node* lhs_map = LoadMap(lhs); - - // Check if the {lhs} is a HeapNumber. - GotoIfNot(IsHeapNumberMap(lhs_map), &if_lhsisnotnumber); - - // Check if the {rhs} is a Smi. - Label if_rhsissmi(this), if_rhsisnotsmi(this); - Branch(TaggedIsSmi(rhs), &if_rhsissmi, &if_rhsisnotsmi); - - Bind(&if_rhsissmi); - { - // Perform a floating point subtraction. - var_fsub_lhs.Bind(LoadHeapNumberValue(lhs)); - var_fsub_rhs.Bind(SmiToFloat64(rhs)); - Goto(&do_fsub); - } - - Bind(&if_rhsisnotsmi); - { - // Load the map of the {rhs}. - Node* rhs_map = LoadMap(rhs); - - // Check if the {rhs} is a HeapNumber. - GotoIfNot(IsHeapNumberMap(rhs_map), &check_rhsisoddball); - - // Perform a floating point subtraction. - var_fsub_lhs.Bind(LoadHeapNumberValue(lhs)); - var_fsub_rhs.Bind(LoadHeapNumberValue(rhs)); - Goto(&do_fsub); - } - } - - Bind(&do_fsub); - { - var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kNumber)); - Node* lhs_value = var_fsub_lhs.value(); - Node* rhs_value = var_fsub_rhs.value(); - Node* value = Float64Sub(lhs_value, rhs_value); - var_result.Bind(AllocateHeapNumberWithValue(value)); - Goto(&end); - } - - Bind(&if_lhsisnotnumber); - { - // 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 = LoadInstanceType(lhs); - Node* lhs_is_oddball = - Word32Equal(lhs_instance_type, Int32Constant(ODDBALL_TYPE)); - GotoIfNot(lhs_is_oddball, &call_with_any_feedback); - - Label if_rhsissmi(this), if_rhsisnotsmi(this); - Branch(TaggedIsSmi(rhs), &if_rhsissmi, &if_rhsisnotsmi); - - Bind(&if_rhsissmi); - { - var_type_feedback.Bind( - SmiConstant(BinaryOperationFeedback::kNumberOrOddball)); - Goto(&call_subtract_stub); - } - - Bind(&if_rhsisnotsmi); - { - // Load the map of the {rhs}. - Node* rhs_map = LoadMap(rhs); - - // Check if {rhs} is a HeapNumber. - GotoIfNot(IsHeapNumberMap(rhs_map), &check_rhsisoddball); - - var_type_feedback.Bind( - SmiConstant(BinaryOperationFeedback::kNumberOrOddball)); - Goto(&call_subtract_stub); - } - } - - 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 = LoadInstanceType(rhs); - Node* rhs_is_oddball = - Word32Equal(rhs_instance_type, Int32Constant(ODDBALL_TYPE)); - GotoIfNot(rhs_is_oddball, &call_with_any_feedback); - - var_type_feedback.Bind( - SmiConstant(BinaryOperationFeedback::kNumberOrOddball)); - Goto(&call_subtract_stub); - } - - Bind(&call_with_any_feedback); - { - var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kAny)); - Goto(&call_subtract_stub); - } - - Bind(&call_subtract_stub); - { - Callable callable = CodeFactory::Subtract(isolate()); - var_result.Bind(CallStub(callable, context, lhs, rhs)); - Goto(&end); - } - - Bind(&end); - UpdateFeedback(var_type_feedback.value(), feedback_vector, slot_id); - return var_result.value(); -} - -compiler::Node* BinaryOpAssembler::Generate_MultiplyWithFeedback( - Node* context, Node* lhs, Node* rhs, Node* slot_id, Node* feedback_vector) { - // Shared entry point for floating point multiplication. - Label do_fmul(this), if_lhsisnotnumber(this, Label::kDeferred), - check_rhsisoddball(this, Label::kDeferred), - call_with_oddball_feedback(this), call_with_any_feedback(this), - call_multiply_stub(this), end(this); - Variable var_lhs_float64(this, MachineRepresentation::kFloat64), - var_rhs_float64(this, MachineRepresentation::kFloat64), - var_result(this, MachineRepresentation::kTagged), - var_type_feedback(this, MachineRepresentation::kTaggedSigned); - - Label lhs_is_smi(this), lhs_is_not_smi(this); - Branch(TaggedIsSmi(lhs), &lhs_is_smi, &lhs_is_not_smi); - - Bind(&lhs_is_smi); - { - Label rhs_is_smi(this), rhs_is_not_smi(this); - Branch(TaggedIsSmi(rhs), &rhs_is_smi, &rhs_is_not_smi); - - Bind(&rhs_is_smi); - { - // Both {lhs} and {rhs} are Smis. The result is not necessarily a smi, - // in case of overflow. - var_result.Bind(SmiMul(lhs, rhs)); - var_type_feedback.Bind( - SelectSmiConstant(TaggedIsSmi(var_result.value()), - BinaryOperationFeedback::kSignedSmall, - BinaryOperationFeedback::kNumber)); - Goto(&end); - } - - Bind(&rhs_is_not_smi); - { - Node* rhs_map = LoadMap(rhs); - - // Check if {rhs} is a HeapNumber. - GotoIfNot(IsHeapNumberMap(rhs_map), &check_rhsisoddball); - - // Convert {lhs} to a double and multiply it with the value of {rhs}. - var_lhs_float64.Bind(SmiToFloat64(lhs)); - var_rhs_float64.Bind(LoadHeapNumberValue(rhs)); - Goto(&do_fmul); - } - } - - Bind(&lhs_is_not_smi); - { - Node* lhs_map = LoadMap(lhs); - - // Check if {lhs} is a HeapNumber. - GotoIfNot(IsHeapNumberMap(lhs_map), &if_lhsisnotnumber); - - // Check if {rhs} is a Smi. - Label rhs_is_smi(this), rhs_is_not_smi(this); - Branch(TaggedIsSmi(rhs), &rhs_is_smi, &rhs_is_not_smi); - - Bind(&rhs_is_smi); - { - // Convert {rhs} to a double and multiply it with the value of {lhs}. - var_lhs_float64.Bind(LoadHeapNumberValue(lhs)); - var_rhs_float64.Bind(SmiToFloat64(rhs)); - Goto(&do_fmul); - } - - Bind(&rhs_is_not_smi); - { - Node* rhs_map = LoadMap(rhs); - - // Check if {rhs} is a HeapNumber. - GotoIfNot(IsHeapNumberMap(rhs_map), &check_rhsisoddball); - - // Both {lhs} and {rhs} are HeapNumbers. Load their values and - // multiply them. - var_lhs_float64.Bind(LoadHeapNumberValue(lhs)); - var_rhs_float64.Bind(LoadHeapNumberValue(rhs)); - Goto(&do_fmul); - } - } - - Bind(&do_fmul); - { - var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kNumber)); - Node* value = Float64Mul(var_lhs_float64.value(), var_rhs_float64.value()); - Node* result = AllocateHeapNumberWithValue(value); - var_result.Bind(result); - Goto(&end); - } - - Bind(&if_lhsisnotnumber); - { - // 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 = LoadInstanceType(lhs); - Node* lhs_is_oddball = - Word32Equal(lhs_instance_type, Int32Constant(ODDBALL_TYPE)); - GotoIfNot(lhs_is_oddball, &call_with_any_feedback); - - GotoIf(TaggedIsSmi(rhs), &call_with_oddball_feedback); - - // Load the map of the {rhs}. - Node* rhs_map = LoadMap(rhs); - - // Check if {rhs} is a HeapNumber. - Branch(IsHeapNumberMap(rhs_map), &call_with_oddball_feedback, - &check_rhsisoddball); - } - - 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 = LoadInstanceType(rhs); - Node* rhs_is_oddball = - Word32Equal(rhs_instance_type, Int32Constant(ODDBALL_TYPE)); - Branch(rhs_is_oddball, &call_with_oddball_feedback, - &call_with_any_feedback); - } - - Bind(&call_with_oddball_feedback); - { - var_type_feedback.Bind( - SmiConstant(BinaryOperationFeedback::kNumberOrOddball)); - Goto(&call_multiply_stub); - } - - Bind(&call_with_any_feedback); - { - var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kAny)); - Goto(&call_multiply_stub); - } - - Bind(&call_multiply_stub); - { - Callable callable = CodeFactory::Multiply(isolate()); - var_result.Bind(CallStub(callable, context, lhs, rhs)); - Goto(&end); - } - - Bind(&end); - UpdateFeedback(var_type_feedback.value(), feedback_vector, slot_id); - return var_result.value(); -} - -compiler::Node* BinaryOpAssembler::Generate_DivideWithFeedback( - Node* context, Node* dividend, Node* divisor, Node* slot_id, - Node* feedback_vector) { - // Shared entry point for floating point division. - Label do_fdiv(this), dividend_is_not_number(this, Label::kDeferred), - check_divisor_for_oddball(this, Label::kDeferred), - call_with_oddball_feedback(this), call_with_any_feedback(this), - call_divide_stub(this), end(this); - Variable var_dividend_float64(this, MachineRepresentation::kFloat64), - var_divisor_float64(this, MachineRepresentation::kFloat64), - var_result(this, MachineRepresentation::kTagged), - var_type_feedback(this, MachineRepresentation::kTaggedSigned); - - Label dividend_is_smi(this), dividend_is_not_smi(this); - Branch(TaggedIsSmi(dividend), ÷nd_is_smi, ÷nd_is_not_smi); - - Bind(÷nd_is_smi); - { - Label divisor_is_smi(this), divisor_is_not_smi(this); - Branch(TaggedIsSmi(divisor), &divisor_is_smi, &divisor_is_not_smi); - - Bind(&divisor_is_smi); - { - Label bailout(this); - - // Do floating point division if {divisor} is zero. - GotoIf(WordEqual(divisor, SmiConstant(0)), &bailout); - - // Do floating point division {dividend} is zero and {divisor} is - // negative. - Label dividend_is_zero(this), dividend_is_not_zero(this); - Branch(WordEqual(dividend, SmiConstant(0)), ÷nd_is_zero, - ÷nd_is_not_zero); - - Bind(÷nd_is_zero); - { - GotoIf(SmiLessThan(divisor, SmiConstant(0)), &bailout); - Goto(÷nd_is_not_zero); - } - Bind(÷nd_is_not_zero); - - Node* untagged_divisor = SmiToWord32(divisor); - Node* untagged_dividend = SmiToWord32(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(this), divisor_is_not_minus_one(this); - Branch(Word32Equal(untagged_divisor, Int32Constant(-1)), - &divisor_is_minus_one, &divisor_is_not_minus_one); - - Bind(&divisor_is_minus_one); - { - GotoIf(Word32Equal(untagged_dividend, - Int32Constant(kSmiValueSize == 32 ? kMinInt - : (kMinInt >> 1))), - &bailout); - Goto(&divisor_is_not_minus_one); - } - Bind(&divisor_is_not_minus_one); - - Node* untagged_result = Int32Div(untagged_dividend, untagged_divisor); - Node* truncated = Int32Mul(untagged_result, untagged_divisor); - // Do floating point division if the remainder is not 0. - GotoIf(Word32NotEqual(untagged_dividend, truncated), &bailout); - var_type_feedback.Bind( - SmiConstant(BinaryOperationFeedback::kSignedSmall)); - var_result.Bind(SmiFromWord32(untagged_result)); - Goto(&end); - - // Bailout: convert {dividend} and {divisor} to double and do double - // division. - Bind(&bailout); - { - var_dividend_float64.Bind(SmiToFloat64(dividend)); - var_divisor_float64.Bind(SmiToFloat64(divisor)); - Goto(&do_fdiv); - } - } - - Bind(&divisor_is_not_smi); - { - Node* divisor_map = LoadMap(divisor); - - // Check if {divisor} is a HeapNumber. - GotoIfNot(IsHeapNumberMap(divisor_map), &check_divisor_for_oddball); - - // Convert {dividend} to a double and divide it with the value of - // {divisor}. - var_dividend_float64.Bind(SmiToFloat64(dividend)); - var_divisor_float64.Bind(LoadHeapNumberValue(divisor)); - Goto(&do_fdiv); - } - - Bind(÷nd_is_not_smi); - { - Node* dividend_map = LoadMap(dividend); - - // Check if {dividend} is a HeapNumber. - GotoIfNot(IsHeapNumberMap(dividend_map), ÷nd_is_not_number); - - // Check if {divisor} is a Smi. - Label divisor_is_smi(this), divisor_is_not_smi(this); - Branch(TaggedIsSmi(divisor), &divisor_is_smi, &divisor_is_not_smi); - - Bind(&divisor_is_smi); - { - // Convert {divisor} to a double and use it for a floating point - // division. - var_dividend_float64.Bind(LoadHeapNumberValue(dividend)); - var_divisor_float64.Bind(SmiToFloat64(divisor)); - Goto(&do_fdiv); - } - - Bind(&divisor_is_not_smi); - { - Node* divisor_map = LoadMap(divisor); - - // Check if {divisor} is a HeapNumber. - GotoIfNot(IsHeapNumberMap(divisor_map), &check_divisor_for_oddball); - - // Both {dividend} and {divisor} are HeapNumbers. Load their values - // and divide them. - var_dividend_float64.Bind(LoadHeapNumberValue(dividend)); - var_divisor_float64.Bind(LoadHeapNumberValue(divisor)); - Goto(&do_fdiv); - } - } - } - - Bind(&do_fdiv); - { - var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kNumber)); - Node* value = - Float64Div(var_dividend_float64.value(), var_divisor_float64.value()); - var_result.Bind(AllocateHeapNumberWithValue(value)); - Goto(&end); - } - - Bind(÷nd_is_not_number); - { - // 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 = LoadInstanceType(dividend); - Node* dividend_is_oddball = - Word32Equal(dividend_instance_type, Int32Constant(ODDBALL_TYPE)); - GotoIfNot(dividend_is_oddball, &call_with_any_feedback); - - GotoIf(TaggedIsSmi(divisor), &call_with_oddball_feedback); - - // Load the map of the {divisor}. - Node* divisor_map = LoadMap(divisor); - - // Check if {divisor} is a HeapNumber. - Branch(IsHeapNumberMap(divisor_map), &call_with_oddball_feedback, - &check_divisor_for_oddball); - } - - 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 = LoadInstanceType(divisor); - Node* divisor_is_oddball = - Word32Equal(divisor_instance_type, Int32Constant(ODDBALL_TYPE)); - Branch(divisor_is_oddball, &call_with_oddball_feedback, - &call_with_any_feedback); - } - - Bind(&call_with_oddball_feedback); - { - var_type_feedback.Bind( - SmiConstant(BinaryOperationFeedback::kNumberOrOddball)); - Goto(&call_divide_stub); - } - - Bind(&call_with_any_feedback); - { - var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kAny)); - Goto(&call_divide_stub); - } - - Bind(&call_divide_stub); - { - Callable callable = CodeFactory::Divide(isolate()); - var_result.Bind(CallStub(callable, context, dividend, divisor)); - Goto(&end); - } - - Bind(&end); - UpdateFeedback(var_type_feedback.value(), feedback_vector, slot_id); - return var_result.value(); -} - -compiler::Node* BinaryOpAssembler::Generate_ModulusWithFeedback( - Node* context, Node* dividend, Node* divisor, Node* slot_id, - Node* feedback_vector) { - // Shared entry point for floating point division. - Label do_fmod(this), dividend_is_not_number(this, Label::kDeferred), - check_divisor_for_oddball(this, Label::kDeferred), - call_with_oddball_feedback(this), call_with_any_feedback(this), - call_modulus_stub(this), end(this); - Variable var_dividend_float64(this, MachineRepresentation::kFloat64), - var_divisor_float64(this, MachineRepresentation::kFloat64), - var_result(this, MachineRepresentation::kTagged), - var_type_feedback(this, MachineRepresentation::kTaggedSigned); - - Label dividend_is_smi(this), dividend_is_not_smi(this); - Branch(TaggedIsSmi(dividend), ÷nd_is_smi, ÷nd_is_not_smi); - - Bind(÷nd_is_smi); - { - Label divisor_is_smi(this), divisor_is_not_smi(this); - Branch(TaggedIsSmi(divisor), &divisor_is_smi, &divisor_is_not_smi); - - Bind(&divisor_is_smi); - { - var_result.Bind(SmiMod(dividend, divisor)); - var_type_feedback.Bind( - SelectSmiConstant(TaggedIsSmi(var_result.value()), - BinaryOperationFeedback::kSignedSmall, - BinaryOperationFeedback::kNumber)); - Goto(&end); - } - - Bind(&divisor_is_not_smi); - { - Node* divisor_map = LoadMap(divisor); - - // Check if {divisor} is a HeapNumber. - GotoIfNot(IsHeapNumberMap(divisor_map), &check_divisor_for_oddball); - - // Convert {dividend} to a double and divide it with the value of - // {divisor}. - var_dividend_float64.Bind(SmiToFloat64(dividend)); - var_divisor_float64.Bind(LoadHeapNumberValue(divisor)); - Goto(&do_fmod); - } - } - - Bind(÷nd_is_not_smi); - { - Node* dividend_map = LoadMap(dividend); - - // Check if {dividend} is a HeapNumber. - GotoIfNot(IsHeapNumberMap(dividend_map), ÷nd_is_not_number); - - // Check if {divisor} is a Smi. - Label divisor_is_smi(this), divisor_is_not_smi(this); - Branch(TaggedIsSmi(divisor), &divisor_is_smi, &divisor_is_not_smi); - - Bind(&divisor_is_smi); - { - // Convert {divisor} to a double and use it for a floating point - // division. - var_dividend_float64.Bind(LoadHeapNumberValue(dividend)); - var_divisor_float64.Bind(SmiToFloat64(divisor)); - Goto(&do_fmod); - } - - Bind(&divisor_is_not_smi); - { - Node* divisor_map = LoadMap(divisor); - - // Check if {divisor} is a HeapNumber. - GotoIfNot(IsHeapNumberMap(divisor_map), &check_divisor_for_oddball); - - // Both {dividend} and {divisor} are HeapNumbers. Load their values - // and divide them. - var_dividend_float64.Bind(LoadHeapNumberValue(dividend)); - var_divisor_float64.Bind(LoadHeapNumberValue(divisor)); - Goto(&do_fmod); - } - } - - Bind(&do_fmod); - { - var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kNumber)); - Node* value = - Float64Mod(var_dividend_float64.value(), var_divisor_float64.value()); - var_result.Bind(AllocateHeapNumberWithValue(value)); - Goto(&end); - } - - 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 = LoadInstanceType(dividend); - Node* dividend_is_oddball = - Word32Equal(dividend_instance_type, Int32Constant(ODDBALL_TYPE)); - GotoIfNot(dividend_is_oddball, &call_with_any_feedback); - - GotoIf(TaggedIsSmi(divisor), &call_with_oddball_feedback); - - // Load the map of the {divisor}. - Node* divisor_map = LoadMap(divisor); - - // Check if {divisor} is a HeapNumber. - Branch(IsHeapNumberMap(divisor_map), &call_with_oddball_feedback, - &check_divisor_for_oddball); - } - - 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 = LoadInstanceType(divisor); - Node* divisor_is_oddball = - Word32Equal(divisor_instance_type, Int32Constant(ODDBALL_TYPE)); - Branch(divisor_is_oddball, &call_with_oddball_feedback, - &call_with_any_feedback); - } - - Bind(&call_with_oddball_feedback); - { - var_type_feedback.Bind( - SmiConstant(BinaryOperationFeedback::kNumberOrOddball)); - Goto(&call_modulus_stub); - } - - Bind(&call_with_any_feedback); - { - var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kAny)); - Goto(&call_modulus_stub); - } - - Bind(&call_modulus_stub); - { - Callable callable = CodeFactory::Modulus(isolate()); - var_result.Bind(CallStub(callable, context, dividend, divisor)); - Goto(&end); - } - - Bind(&end); - UpdateFeedback(var_type_feedback.value(), feedback_vector, slot_id); - return var_result.value(); -} - -#define BINARY_OP_STUB(Name) \ - TF_STUB(Name##Stub, BinaryOpAssembler) { \ - Node* context = Parameter(Descriptor::kContext); \ - Node* left = Parameter(Descriptor::kLeft); \ - Node* right = Parameter(Descriptor::kRight); \ - Node* slot = Parameter(Descriptor::kSlot); \ - Node* vector = Parameter(Descriptor::kVector); \ - Return(Generate_##Name(context, left, right, ChangeUint32ToWord(slot), \ - vector)); \ - } \ - compiler::Node* Name##Stub::Generate( \ - CodeStubAssembler* assembler, compiler::Node* left, \ - compiler::Node* right, compiler::Node* slot, \ - compiler::Node* feedback_vector, compiler::Node* context) { \ - BinaryOpAssembler basm(assembler->state()); \ - return basm.Generate_##Name(context, left, right, slot, feedback_vector); \ - } - -// TODO(ishell): don't have to be stubs. Interpreter can use BinaryOpICAssembler -// directly. -BINARY_OP_STUB(AddWithFeedback) -BINARY_OP_STUB(SubtractWithFeedback) -BINARY_OP_STUB(MultiplyWithFeedback) -BINARY_OP_STUB(DivideWithFeedback) -BINARY_OP_STUB(ModulusWithFeedback) -#undef BINARY_OP_STUB - // TODO(ishell): move to builtins. TF_STUB(NumberToStringStub, CodeStubAssembler) { Node* context = Parameter(Descriptor::kContext); diff --git a/src/code-stubs.h b/src/code-stubs.h index 9d899bb6d5..330f47ecd6 100644 --- a/src/code-stubs.h +++ b/src/code-stubs.h @@ -74,11 +74,6 @@ class Node; V(CreateAllocationSite) \ V(CreateWeakCell) \ V(StringLength) \ - V(AddWithFeedback) \ - V(SubtractWithFeedback) \ - V(MultiplyWithFeedback) \ - V(DivideWithFeedback) \ - V(ModulusWithFeedback) \ V(InternalArrayNoArgumentConstructor) \ V(InternalArraySingleArgumentConstructor) \ V(ElementsTransitionAndStore) \ @@ -343,15 +338,6 @@ class CodeStub BASE_EMBEDDED { void GenerateAssembly(compiler::CodeAssemblerState* state) const override; \ DEFINE_CODE_STUB(NAME, SUPER) -#define DEFINE_TURBOFAN_BINARY_OP_CODE_STUB_WITH_FEEDBACK(NAME, SUPER) \ - public: \ - static compiler::Node* Generate( \ - CodeStubAssembler* assembler, compiler::Node* left, \ - compiler::Node* right, compiler::Node* slot_id, \ - compiler::Node* feedback_vector, compiler::Node* context); \ - void GenerateAssembly(compiler::CodeAssemblerState* state) const override; \ - DEFINE_CODE_STUB(NAME, SUPER) - #define DEFINE_TURBOFAN_UNARY_OP_CODE_STUB_WITH_FEEDBACK(NAME, SUPER) \ public: \ static compiler::Node* Generate( \ @@ -645,55 +631,6 @@ class StringLengthStub : public TurboFanCodeStub { DEFINE_TURBOFAN_CODE_STUB(StringLength, TurboFanCodeStub); }; -class AddWithFeedbackStub final : public TurboFanCodeStub { - public: - explicit AddWithFeedbackStub(Isolate* isolate) : TurboFanCodeStub(isolate) {} - - DEFINE_CALL_INTERFACE_DESCRIPTOR(BinaryOpWithVector); - DEFINE_TURBOFAN_BINARY_OP_CODE_STUB_WITH_FEEDBACK(AddWithFeedback, - TurboFanCodeStub); -}; - -class SubtractWithFeedbackStub final : public TurboFanCodeStub { - public: - explicit SubtractWithFeedbackStub(Isolate* isolate) - : TurboFanCodeStub(isolate) {} - - DEFINE_CALL_INTERFACE_DESCRIPTOR(BinaryOpWithVector); - DEFINE_TURBOFAN_BINARY_OP_CODE_STUB_WITH_FEEDBACK(SubtractWithFeedback, - TurboFanCodeStub); -}; - -class MultiplyWithFeedbackStub final : public TurboFanCodeStub { - public: - explicit MultiplyWithFeedbackStub(Isolate* isolate) - : TurboFanCodeStub(isolate) {} - - DEFINE_CALL_INTERFACE_DESCRIPTOR(BinaryOpWithVector); - DEFINE_TURBOFAN_BINARY_OP_CODE_STUB_WITH_FEEDBACK(MultiplyWithFeedback, - TurboFanCodeStub); -}; - -class DivideWithFeedbackStub final : public TurboFanCodeStub { - public: - explicit DivideWithFeedbackStub(Isolate* isolate) - : TurboFanCodeStub(isolate) {} - - DEFINE_CALL_INTERFACE_DESCRIPTOR(BinaryOpWithVector); - DEFINE_TURBOFAN_BINARY_OP_CODE_STUB_WITH_FEEDBACK(DivideWithFeedback, - TurboFanCodeStub); -}; - -class ModulusWithFeedbackStub final : public TurboFanCodeStub { - public: - explicit ModulusWithFeedbackStub(Isolate* isolate) - : TurboFanCodeStub(isolate) {} - - DEFINE_CALL_INTERFACE_DESCRIPTOR(BinaryOpWithVector); - DEFINE_TURBOFAN_BINARY_OP_CODE_STUB_WITH_FEEDBACK(ModulusWithFeedback, - TurboFanCodeStub); -}; - class StoreInterceptorStub : public TurboFanCodeStub { public: explicit StoreInterceptorStub(Isolate* isolate) : TurboFanCodeStub(isolate) {} diff --git a/src/ic/binary-op-assembler.cc b/src/ic/binary-op-assembler.cc new file mode 100644 index 0000000000..b35c7dfb57 --- /dev/null +++ b/src/ic/binary-op-assembler.cc @@ -0,0 +1,865 @@ +// Copyright 2016 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "src/ic/binary-op-assembler.h" + +#include "src/globals.h" + +namespace v8 { +namespace internal { + +using compiler::Node; + +Node* BinaryOpAssembler::Generate_AddWithFeedback(Node* context, Node* lhs, + Node* rhs, Node* slot_id, + Node* feedback_vector) { + // Shared entry for floating point addition. + Label do_fadd(this), if_lhsisnotnumber(this, Label::kDeferred), + check_rhsisoddball(this, Label::kDeferred), + call_with_oddball_feedback(this), call_with_any_feedback(this), + call_add_stub(this), end(this); + Variable var_fadd_lhs(this, MachineRepresentation::kFloat64), + var_fadd_rhs(this, MachineRepresentation::kFloat64), + var_type_feedback(this, MachineRepresentation::kTaggedSigned), + var_result(this, MachineRepresentation::kTagged); + + // Check if the {lhs} is a Smi or a HeapObject. + Label if_lhsissmi(this), if_lhsisnotsmi(this); + Branch(TaggedIsSmi(lhs), &if_lhsissmi, &if_lhsisnotsmi); + + Bind(&if_lhsissmi); + { + // Check if the {rhs} is also a Smi. + Label if_rhsissmi(this), if_rhsisnotsmi(this); + Branch(TaggedIsSmi(rhs), &if_rhsissmi, &if_rhsisnotsmi); + + Bind(&if_rhsissmi); + { + // Try fast Smi addition first. + Node* pair = IntPtrAddWithOverflow(BitcastTaggedToWord(lhs), + BitcastTaggedToWord(rhs)); + Node* overflow = Projection(1, pair); + + // Check if the Smi additon overflowed. + Label if_overflow(this), if_notoverflow(this); + Branch(overflow, &if_overflow, &if_notoverflow); + + Bind(&if_overflow); + { + var_fadd_lhs.Bind(SmiToFloat64(lhs)); + var_fadd_rhs.Bind(SmiToFloat64(rhs)); + Goto(&do_fadd); + } + + Bind(&if_notoverflow); + { + var_type_feedback.Bind( + SmiConstant(BinaryOperationFeedback::kSignedSmall)); + var_result.Bind(BitcastWordToTaggedSigned(Projection(0, pair))); + Goto(&end); + } + } + + Bind(&if_rhsisnotsmi); + { + // Load the map of {rhs}. + Node* rhs_map = LoadMap(rhs); + + // Check if the {rhs} is a HeapNumber. + GotoIfNot(IsHeapNumberMap(rhs_map), &check_rhsisoddball); + + var_fadd_lhs.Bind(SmiToFloat64(lhs)); + var_fadd_rhs.Bind(LoadHeapNumberValue(rhs)); + Goto(&do_fadd); + } + } + + Bind(&if_lhsisnotsmi); + { + // Load the map of {lhs}. + Node* lhs_map = LoadMap(lhs); + + // Check if {lhs} is a HeapNumber. + GotoIfNot(IsHeapNumberMap(lhs_map), &if_lhsisnotnumber); + + // Check if the {rhs} is Smi. + Label if_rhsissmi(this), if_rhsisnotsmi(this); + Branch(TaggedIsSmi(rhs), &if_rhsissmi, &if_rhsisnotsmi); + + Bind(&if_rhsissmi); + { + var_fadd_lhs.Bind(LoadHeapNumberValue(lhs)); + var_fadd_rhs.Bind(SmiToFloat64(rhs)); + Goto(&do_fadd); + } + + Bind(&if_rhsisnotsmi); + { + // Load the map of {rhs}. + Node* rhs_map = LoadMap(rhs); + + // Check if the {rhs} is a HeapNumber. + GotoIfNot(IsHeapNumberMap(rhs_map), &check_rhsisoddball); + + var_fadd_lhs.Bind(LoadHeapNumberValue(lhs)); + var_fadd_rhs.Bind(LoadHeapNumberValue(rhs)); + Goto(&do_fadd); + } + } + + Bind(&do_fadd); + { + var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kNumber)); + Node* value = Float64Add(var_fadd_lhs.value(), var_fadd_rhs.value()); + Node* result = AllocateHeapNumberWithValue(value); + var_result.Bind(result); + Goto(&end); + } + + Bind(&if_lhsisnotnumber); + { + // No checks on rhs are done yet. We just know lhs is not a number or Smi. + Label if_lhsisoddball(this), if_lhsisnotoddball(this); + Node* lhs_instance_type = LoadInstanceType(lhs); + Node* lhs_is_oddball = + Word32Equal(lhs_instance_type, Int32Constant(ODDBALL_TYPE)); + Branch(lhs_is_oddball, &if_lhsisoddball, &if_lhsisnotoddball); + + Bind(&if_lhsisoddball); + { + GotoIf(TaggedIsSmi(rhs), &call_with_oddball_feedback); + + // Load the map of the {rhs}. + Node* rhs_map = LoadMap(rhs); + + // Check if {rhs} is a HeapNumber. + Branch(IsHeapNumberMap(rhs_map), &call_with_oddball_feedback, + &check_rhsisoddball); + } + + Bind(&if_lhsisnotoddball); + { + // Exit unless {lhs} is a string + GotoIfNot(IsStringInstanceType(lhs_instance_type), + &call_with_any_feedback); + + // Check if the {rhs} is a smi, and exit the string check early if it is. + GotoIf(TaggedIsSmi(rhs), &call_with_any_feedback); + + Node* rhs_instance_type = LoadInstanceType(rhs); + + // Exit unless {rhs} is a string. Since {lhs} is a string we no longer + // need an Oddball check. + GotoIfNot(IsStringInstanceType(rhs_instance_type), + &call_with_any_feedback); + + var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kString)); + Callable callable = + CodeFactory::StringAdd(isolate(), STRING_ADD_CHECK_NONE, NOT_TENURED); + var_result.Bind(CallStub(callable, context, lhs, rhs)); + + Goto(&end); + } + } + + 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 = LoadInstanceType(rhs); + Node* rhs_is_oddball = + Word32Equal(rhs_instance_type, Int32Constant(ODDBALL_TYPE)); + Branch(rhs_is_oddball, &call_with_oddball_feedback, + &call_with_any_feedback); + } + + Bind(&call_with_oddball_feedback); + { + var_type_feedback.Bind( + SmiConstant(BinaryOperationFeedback::kNumberOrOddball)); + Goto(&call_add_stub); + } + + Bind(&call_with_any_feedback); + { + var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kAny)); + Goto(&call_add_stub); + } + + Bind(&call_add_stub); + { + Callable callable = CodeFactory::Add(isolate()); + var_result.Bind(CallStub(callable, context, lhs, rhs)); + Goto(&end); + } + + Bind(&end); + UpdateFeedback(var_type_feedback.value(), feedback_vector, slot_id); + return var_result.value(); +} + +Node* BinaryOpAssembler::Generate_SubtractWithFeedback(Node* context, Node* lhs, + Node* rhs, Node* slot_id, + Node* feedback_vector) { + // Shared entry for floating point subtraction. + Label do_fsub(this), end(this), call_subtract_stub(this), + if_lhsisnotnumber(this), check_rhsisoddball(this), + call_with_any_feedback(this); + Variable var_fsub_lhs(this, MachineRepresentation::kFloat64), + var_fsub_rhs(this, MachineRepresentation::kFloat64), + var_type_feedback(this, MachineRepresentation::kTaggedSigned), + var_result(this, MachineRepresentation::kTagged); + + // Check if the {lhs} is a Smi or a HeapObject. + Label if_lhsissmi(this), if_lhsisnotsmi(this); + Branch(TaggedIsSmi(lhs), &if_lhsissmi, &if_lhsisnotsmi); + + Bind(&if_lhsissmi); + { + // Check if the {rhs} is also a Smi. + Label if_rhsissmi(this), if_rhsisnotsmi(this); + Branch(TaggedIsSmi(rhs), &if_rhsissmi, &if_rhsisnotsmi); + + Bind(&if_rhsissmi); + { + // Try a fast Smi subtraction first. + Node* pair = IntPtrSubWithOverflow(BitcastTaggedToWord(lhs), + BitcastTaggedToWord(rhs)); + Node* overflow = Projection(1, pair); + + // Check if the Smi subtraction overflowed. + Label if_overflow(this), if_notoverflow(this); + Branch(overflow, &if_overflow, &if_notoverflow); + + Bind(&if_overflow); + { + // lhs, rhs - smi and result - number. combined - number. + // The result doesn't fit into Smi range. + var_fsub_lhs.Bind(SmiToFloat64(lhs)); + var_fsub_rhs.Bind(SmiToFloat64(rhs)); + Goto(&do_fsub); + } + + Bind(&if_notoverflow); + // lhs, rhs, result smi. combined - smi. + var_type_feedback.Bind( + SmiConstant(BinaryOperationFeedback::kSignedSmall)); + var_result.Bind(BitcastWordToTaggedSigned(Projection(0, pair))); + Goto(&end); + } + + Bind(&if_rhsisnotsmi); + { + // Load the map of the {rhs}. + Node* rhs_map = LoadMap(rhs); + + // Check if {rhs} is a HeapNumber. + GotoIfNot(IsHeapNumberMap(rhs_map), &check_rhsisoddball); + + // Perform a floating point subtraction. + var_fsub_lhs.Bind(SmiToFloat64(lhs)); + var_fsub_rhs.Bind(LoadHeapNumberValue(rhs)); + Goto(&do_fsub); + } + } + + Bind(&if_lhsisnotsmi); + { + // Load the map of the {lhs}. + Node* lhs_map = LoadMap(lhs); + + // Check if the {lhs} is a HeapNumber. + GotoIfNot(IsHeapNumberMap(lhs_map), &if_lhsisnotnumber); + + // Check if the {rhs} is a Smi. + Label if_rhsissmi(this), if_rhsisnotsmi(this); + Branch(TaggedIsSmi(rhs), &if_rhsissmi, &if_rhsisnotsmi); + + Bind(&if_rhsissmi); + { + // Perform a floating point subtraction. + var_fsub_lhs.Bind(LoadHeapNumberValue(lhs)); + var_fsub_rhs.Bind(SmiToFloat64(rhs)); + Goto(&do_fsub); + } + + Bind(&if_rhsisnotsmi); + { + // Load the map of the {rhs}. + Node* rhs_map = LoadMap(rhs); + + // Check if the {rhs} is a HeapNumber. + GotoIfNot(IsHeapNumberMap(rhs_map), &check_rhsisoddball); + + // Perform a floating point subtraction. + var_fsub_lhs.Bind(LoadHeapNumberValue(lhs)); + var_fsub_rhs.Bind(LoadHeapNumberValue(rhs)); + Goto(&do_fsub); + } + } + + Bind(&do_fsub); + { + var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kNumber)); + Node* lhs_value = var_fsub_lhs.value(); + Node* rhs_value = var_fsub_rhs.value(); + Node* value = Float64Sub(lhs_value, rhs_value); + var_result.Bind(AllocateHeapNumberWithValue(value)); + Goto(&end); + } + + Bind(&if_lhsisnotnumber); + { + // 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 = LoadInstanceType(lhs); + Node* lhs_is_oddball = + Word32Equal(lhs_instance_type, Int32Constant(ODDBALL_TYPE)); + GotoIfNot(lhs_is_oddball, &call_with_any_feedback); + + Label if_rhsissmi(this), if_rhsisnotsmi(this); + Branch(TaggedIsSmi(rhs), &if_rhsissmi, &if_rhsisnotsmi); + + Bind(&if_rhsissmi); + { + var_type_feedback.Bind( + SmiConstant(BinaryOperationFeedback::kNumberOrOddball)); + Goto(&call_subtract_stub); + } + + Bind(&if_rhsisnotsmi); + { + // Load the map of the {rhs}. + Node* rhs_map = LoadMap(rhs); + + // Check if {rhs} is a HeapNumber. + GotoIfNot(IsHeapNumberMap(rhs_map), &check_rhsisoddball); + + var_type_feedback.Bind( + SmiConstant(BinaryOperationFeedback::kNumberOrOddball)); + Goto(&call_subtract_stub); + } + } + + 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 = LoadInstanceType(rhs); + Node* rhs_is_oddball = + Word32Equal(rhs_instance_type, Int32Constant(ODDBALL_TYPE)); + GotoIfNot(rhs_is_oddball, &call_with_any_feedback); + + var_type_feedback.Bind( + SmiConstant(BinaryOperationFeedback::kNumberOrOddball)); + Goto(&call_subtract_stub); + } + + Bind(&call_with_any_feedback); + { + var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kAny)); + Goto(&call_subtract_stub); + } + + Bind(&call_subtract_stub); + { + Callable callable = CodeFactory::Subtract(isolate()); + var_result.Bind(CallStub(callable, context, lhs, rhs)); + Goto(&end); + } + + Bind(&end); + UpdateFeedback(var_type_feedback.value(), feedback_vector, slot_id); + return var_result.value(); +} + +Node* BinaryOpAssembler::Generate_MultiplyWithFeedback(Node* context, Node* lhs, + Node* rhs, Node* slot_id, + Node* feedback_vector) { + // Shared entry point for floating point multiplication. + Label do_fmul(this), if_lhsisnotnumber(this, Label::kDeferred), + check_rhsisoddball(this, Label::kDeferred), + call_with_oddball_feedback(this), call_with_any_feedback(this), + call_multiply_stub(this), end(this); + Variable var_lhs_float64(this, MachineRepresentation::kFloat64), + var_rhs_float64(this, MachineRepresentation::kFloat64), + var_result(this, MachineRepresentation::kTagged), + var_type_feedback(this, MachineRepresentation::kTaggedSigned); + + Label lhs_is_smi(this), lhs_is_not_smi(this); + Branch(TaggedIsSmi(lhs), &lhs_is_smi, &lhs_is_not_smi); + + Bind(&lhs_is_smi); + { + Label rhs_is_smi(this), rhs_is_not_smi(this); + Branch(TaggedIsSmi(rhs), &rhs_is_smi, &rhs_is_not_smi); + + Bind(&rhs_is_smi); + { + // Both {lhs} and {rhs} are Smis. The result is not necessarily a smi, + // in case of overflow. + var_result.Bind(SmiMul(lhs, rhs)); + var_type_feedback.Bind( + SelectSmiConstant(TaggedIsSmi(var_result.value()), + BinaryOperationFeedback::kSignedSmall, + BinaryOperationFeedback::kNumber)); + Goto(&end); + } + + Bind(&rhs_is_not_smi); + { + Node* rhs_map = LoadMap(rhs); + + // Check if {rhs} is a HeapNumber. + GotoIfNot(IsHeapNumberMap(rhs_map), &check_rhsisoddball); + + // Convert {lhs} to a double and multiply it with the value of {rhs}. + var_lhs_float64.Bind(SmiToFloat64(lhs)); + var_rhs_float64.Bind(LoadHeapNumberValue(rhs)); + Goto(&do_fmul); + } + } + + Bind(&lhs_is_not_smi); + { + Node* lhs_map = LoadMap(lhs); + + // Check if {lhs} is a HeapNumber. + GotoIfNot(IsHeapNumberMap(lhs_map), &if_lhsisnotnumber); + + // Check if {rhs} is a Smi. + Label rhs_is_smi(this), rhs_is_not_smi(this); + Branch(TaggedIsSmi(rhs), &rhs_is_smi, &rhs_is_not_smi); + + Bind(&rhs_is_smi); + { + // Convert {rhs} to a double and multiply it with the value of {lhs}. + var_lhs_float64.Bind(LoadHeapNumberValue(lhs)); + var_rhs_float64.Bind(SmiToFloat64(rhs)); + Goto(&do_fmul); + } + + Bind(&rhs_is_not_smi); + { + Node* rhs_map = LoadMap(rhs); + + // Check if {rhs} is a HeapNumber. + GotoIfNot(IsHeapNumberMap(rhs_map), &check_rhsisoddball); + + // Both {lhs} and {rhs} are HeapNumbers. Load their values and + // multiply them. + var_lhs_float64.Bind(LoadHeapNumberValue(lhs)); + var_rhs_float64.Bind(LoadHeapNumberValue(rhs)); + Goto(&do_fmul); + } + } + + Bind(&do_fmul); + { + var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kNumber)); + Node* value = Float64Mul(var_lhs_float64.value(), var_rhs_float64.value()); + Node* result = AllocateHeapNumberWithValue(value); + var_result.Bind(result); + Goto(&end); + } + + Bind(&if_lhsisnotnumber); + { + // 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 = LoadInstanceType(lhs); + Node* lhs_is_oddball = + Word32Equal(lhs_instance_type, Int32Constant(ODDBALL_TYPE)); + GotoIfNot(lhs_is_oddball, &call_with_any_feedback); + + GotoIf(TaggedIsSmi(rhs), &call_with_oddball_feedback); + + // Load the map of the {rhs}. + Node* rhs_map = LoadMap(rhs); + + // Check if {rhs} is a HeapNumber. + Branch(IsHeapNumberMap(rhs_map), &call_with_oddball_feedback, + &check_rhsisoddball); + } + + 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 = LoadInstanceType(rhs); + Node* rhs_is_oddball = + Word32Equal(rhs_instance_type, Int32Constant(ODDBALL_TYPE)); + Branch(rhs_is_oddball, &call_with_oddball_feedback, + &call_with_any_feedback); + } + + Bind(&call_with_oddball_feedback); + { + var_type_feedback.Bind( + SmiConstant(BinaryOperationFeedback::kNumberOrOddball)); + Goto(&call_multiply_stub); + } + + Bind(&call_with_any_feedback); + { + var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kAny)); + Goto(&call_multiply_stub); + } + + Bind(&call_multiply_stub); + { + Callable callable = CodeFactory::Multiply(isolate()); + var_result.Bind(CallStub(callable, context, lhs, rhs)); + Goto(&end); + } + + Bind(&end); + UpdateFeedback(var_type_feedback.value(), feedback_vector, slot_id); + return var_result.value(); +} + +Node* BinaryOpAssembler::Generate_DivideWithFeedback(Node* context, + Node* dividend, + Node* divisor, + Node* slot_id, + Node* feedback_vector) { + // Shared entry point for floating point division. + Label do_fdiv(this), dividend_is_not_number(this, Label::kDeferred), + check_divisor_for_oddball(this, Label::kDeferred), + call_with_oddball_feedback(this), call_with_any_feedback(this), + call_divide_stub(this), end(this); + Variable var_dividend_float64(this, MachineRepresentation::kFloat64), + var_divisor_float64(this, MachineRepresentation::kFloat64), + var_result(this, MachineRepresentation::kTagged), + var_type_feedback(this, MachineRepresentation::kTaggedSigned); + + Label dividend_is_smi(this), dividend_is_not_smi(this); + Branch(TaggedIsSmi(dividend), ÷nd_is_smi, ÷nd_is_not_smi); + + Bind(÷nd_is_smi); + { + Label divisor_is_smi(this), divisor_is_not_smi(this); + Branch(TaggedIsSmi(divisor), &divisor_is_smi, &divisor_is_not_smi); + + Bind(&divisor_is_smi); + { + Label bailout(this); + + // Do floating point division if {divisor} is zero. + GotoIf(WordEqual(divisor, SmiConstant(0)), &bailout); + + // Do floating point division {dividend} is zero and {divisor} is + // negative. + Label dividend_is_zero(this), dividend_is_not_zero(this); + Branch(WordEqual(dividend, SmiConstant(0)), ÷nd_is_zero, + ÷nd_is_not_zero); + + Bind(÷nd_is_zero); + { + GotoIf(SmiLessThan(divisor, SmiConstant(0)), &bailout); + Goto(÷nd_is_not_zero); + } + Bind(÷nd_is_not_zero); + + Node* untagged_divisor = SmiToWord32(divisor); + Node* untagged_dividend = SmiToWord32(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(this), divisor_is_not_minus_one(this); + Branch(Word32Equal(untagged_divisor, Int32Constant(-1)), + &divisor_is_minus_one, &divisor_is_not_minus_one); + + Bind(&divisor_is_minus_one); + { + GotoIf(Word32Equal(untagged_dividend, + Int32Constant(kSmiValueSize == 32 ? kMinInt + : (kMinInt >> 1))), + &bailout); + Goto(&divisor_is_not_minus_one); + } + Bind(&divisor_is_not_minus_one); + + Node* untagged_result = Int32Div(untagged_dividend, untagged_divisor); + Node* truncated = Int32Mul(untagged_result, untagged_divisor); + // Do floating point division if the remainder is not 0. + GotoIf(Word32NotEqual(untagged_dividend, truncated), &bailout); + var_type_feedback.Bind( + SmiConstant(BinaryOperationFeedback::kSignedSmall)); + var_result.Bind(SmiFromWord32(untagged_result)); + Goto(&end); + + // Bailout: convert {dividend} and {divisor} to double and do double + // division. + Bind(&bailout); + { + var_dividend_float64.Bind(SmiToFloat64(dividend)); + var_divisor_float64.Bind(SmiToFloat64(divisor)); + Goto(&do_fdiv); + } + } + + Bind(&divisor_is_not_smi); + { + Node* divisor_map = LoadMap(divisor); + + // Check if {divisor} is a HeapNumber. + GotoIfNot(IsHeapNumberMap(divisor_map), &check_divisor_for_oddball); + + // Convert {dividend} to a double and divide it with the value of + // {divisor}. + var_dividend_float64.Bind(SmiToFloat64(dividend)); + var_divisor_float64.Bind(LoadHeapNumberValue(divisor)); + Goto(&do_fdiv); + } + + Bind(÷nd_is_not_smi); + { + Node* dividend_map = LoadMap(dividend); + + // Check if {dividend} is a HeapNumber. + GotoIfNot(IsHeapNumberMap(dividend_map), ÷nd_is_not_number); + + // Check if {divisor} is a Smi. + Label divisor_is_smi(this), divisor_is_not_smi(this); + Branch(TaggedIsSmi(divisor), &divisor_is_smi, &divisor_is_not_smi); + + Bind(&divisor_is_smi); + { + // Convert {divisor} to a double and use it for a floating point + // division. + var_dividend_float64.Bind(LoadHeapNumberValue(dividend)); + var_divisor_float64.Bind(SmiToFloat64(divisor)); + Goto(&do_fdiv); + } + + Bind(&divisor_is_not_smi); + { + Node* divisor_map = LoadMap(divisor); + + // Check if {divisor} is a HeapNumber. + GotoIfNot(IsHeapNumberMap(divisor_map), &check_divisor_for_oddball); + + // Both {dividend} and {divisor} are HeapNumbers. Load their values + // and divide them. + var_dividend_float64.Bind(LoadHeapNumberValue(dividend)); + var_divisor_float64.Bind(LoadHeapNumberValue(divisor)); + Goto(&do_fdiv); + } + } + } + + Bind(&do_fdiv); + { + var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kNumber)); + Node* value = + Float64Div(var_dividend_float64.value(), var_divisor_float64.value()); + var_result.Bind(AllocateHeapNumberWithValue(value)); + Goto(&end); + } + + Bind(÷nd_is_not_number); + { + // 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 = LoadInstanceType(dividend); + Node* dividend_is_oddball = + Word32Equal(dividend_instance_type, Int32Constant(ODDBALL_TYPE)); + GotoIfNot(dividend_is_oddball, &call_with_any_feedback); + + GotoIf(TaggedIsSmi(divisor), &call_with_oddball_feedback); + + // Load the map of the {divisor}. + Node* divisor_map = LoadMap(divisor); + + // Check if {divisor} is a HeapNumber. + Branch(IsHeapNumberMap(divisor_map), &call_with_oddball_feedback, + &check_divisor_for_oddball); + } + + 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 = LoadInstanceType(divisor); + Node* divisor_is_oddball = + Word32Equal(divisor_instance_type, Int32Constant(ODDBALL_TYPE)); + Branch(divisor_is_oddball, &call_with_oddball_feedback, + &call_with_any_feedback); + } + + Bind(&call_with_oddball_feedback); + { + var_type_feedback.Bind( + SmiConstant(BinaryOperationFeedback::kNumberOrOddball)); + Goto(&call_divide_stub); + } + + Bind(&call_with_any_feedback); + { + var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kAny)); + Goto(&call_divide_stub); + } + + Bind(&call_divide_stub); + { + Callable callable = CodeFactory::Divide(isolate()); + var_result.Bind(CallStub(callable, context, dividend, divisor)); + Goto(&end); + } + + Bind(&end); + UpdateFeedback(var_type_feedback.value(), feedback_vector, slot_id); + return var_result.value(); +} + +Node* BinaryOpAssembler::Generate_ModulusWithFeedback(Node* context, + Node* dividend, + Node* divisor, + Node* slot_id, + Node* feedback_vector) { + // Shared entry point for floating point division. + Label do_fmod(this), dividend_is_not_number(this, Label::kDeferred), + check_divisor_for_oddball(this, Label::kDeferred), + call_with_oddball_feedback(this), call_with_any_feedback(this), + call_modulus_stub(this), end(this); + Variable var_dividend_float64(this, MachineRepresentation::kFloat64), + var_divisor_float64(this, MachineRepresentation::kFloat64), + var_result(this, MachineRepresentation::kTagged), + var_type_feedback(this, MachineRepresentation::kTaggedSigned); + + Label dividend_is_smi(this), dividend_is_not_smi(this); + Branch(TaggedIsSmi(dividend), ÷nd_is_smi, ÷nd_is_not_smi); + + Bind(÷nd_is_smi); + { + Label divisor_is_smi(this), divisor_is_not_smi(this); + Branch(TaggedIsSmi(divisor), &divisor_is_smi, &divisor_is_not_smi); + + Bind(&divisor_is_smi); + { + var_result.Bind(SmiMod(dividend, divisor)); + var_type_feedback.Bind( + SelectSmiConstant(TaggedIsSmi(var_result.value()), + BinaryOperationFeedback::kSignedSmall, + BinaryOperationFeedback::kNumber)); + Goto(&end); + } + + Bind(&divisor_is_not_smi); + { + Node* divisor_map = LoadMap(divisor); + + // Check if {divisor} is a HeapNumber. + GotoIfNot(IsHeapNumberMap(divisor_map), &check_divisor_for_oddball); + + // Convert {dividend} to a double and divide it with the value of + // {divisor}. + var_dividend_float64.Bind(SmiToFloat64(dividend)); + var_divisor_float64.Bind(LoadHeapNumberValue(divisor)); + Goto(&do_fmod); + } + } + + Bind(÷nd_is_not_smi); + { + Node* dividend_map = LoadMap(dividend); + + // Check if {dividend} is a HeapNumber. + GotoIfNot(IsHeapNumberMap(dividend_map), ÷nd_is_not_number); + + // Check if {divisor} is a Smi. + Label divisor_is_smi(this), divisor_is_not_smi(this); + Branch(TaggedIsSmi(divisor), &divisor_is_smi, &divisor_is_not_smi); + + Bind(&divisor_is_smi); + { + // Convert {divisor} to a double and use it for a floating point + // division. + var_dividend_float64.Bind(LoadHeapNumberValue(dividend)); + var_divisor_float64.Bind(SmiToFloat64(divisor)); + Goto(&do_fmod); + } + + Bind(&divisor_is_not_smi); + { + Node* divisor_map = LoadMap(divisor); + + // Check if {divisor} is a HeapNumber. + GotoIfNot(IsHeapNumberMap(divisor_map), &check_divisor_for_oddball); + + // Both {dividend} and {divisor} are HeapNumbers. Load their values + // and divide them. + var_dividend_float64.Bind(LoadHeapNumberValue(dividend)); + var_divisor_float64.Bind(LoadHeapNumberValue(divisor)); + Goto(&do_fmod); + } + } + + Bind(&do_fmod); + { + var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kNumber)); + Node* value = + Float64Mod(var_dividend_float64.value(), var_divisor_float64.value()); + var_result.Bind(AllocateHeapNumberWithValue(value)); + Goto(&end); + } + + 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 = LoadInstanceType(dividend); + Node* dividend_is_oddball = + Word32Equal(dividend_instance_type, Int32Constant(ODDBALL_TYPE)); + GotoIfNot(dividend_is_oddball, &call_with_any_feedback); + + GotoIf(TaggedIsSmi(divisor), &call_with_oddball_feedback); + + // Load the map of the {divisor}. + Node* divisor_map = LoadMap(divisor); + + // Check if {divisor} is a HeapNumber. + Branch(IsHeapNumberMap(divisor_map), &call_with_oddball_feedback, + &check_divisor_for_oddball); + } + + 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 = LoadInstanceType(divisor); + Node* divisor_is_oddball = + Word32Equal(divisor_instance_type, Int32Constant(ODDBALL_TYPE)); + Branch(divisor_is_oddball, &call_with_oddball_feedback, + &call_with_any_feedback); + } + + Bind(&call_with_oddball_feedback); + { + var_type_feedback.Bind( + SmiConstant(BinaryOperationFeedback::kNumberOrOddball)); + Goto(&call_modulus_stub); + } + + Bind(&call_with_any_feedback); + { + var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kAny)); + Goto(&call_modulus_stub); + } + + Bind(&call_modulus_stub); + { + Callable callable = CodeFactory::Modulus(isolate()); + var_result.Bind(CallStub(callable, context, dividend, divisor)); + Goto(&end); + } + + Bind(&end); + UpdateFeedback(var_type_feedback.value(), feedback_vector, slot_id); + return var_result.value(); +} + +} // namespace internal +} // namespace v8 diff --git a/src/ic/binary-op-assembler.h b/src/ic/binary-op-assembler.h new file mode 100644 index 0000000000..849dfc29dc --- /dev/null +++ b/src/ic/binary-op-assembler.h @@ -0,0 +1,45 @@ +// Copyright 2017 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef V8_SRC_IC_BINARY_OP_ASSEMBLER_H_ +#define V8_SRC_IC_BINARY_OP_ASSEMBLER_H_ + +#include "src/code-stub-assembler.h" + +namespace v8 { +namespace internal { + +namespace compiler { +class CodeAssemblerState; +} + +class BinaryOpAssembler : public CodeStubAssembler { + public: + typedef compiler::Node Node; + + explicit BinaryOpAssembler(compiler::CodeAssemblerState* state) + : CodeStubAssembler(state) {} + + Node* Generate_AddWithFeedback(Node* context, Node* lhs, Node* rhs, + Node* slot_id, Node* feedback_vector); + + Node* Generate_SubtractWithFeedback(Node* context, Node* lhs, Node* rhs, + Node* slot_id, Node* feedback_vector); + + Node* Generate_MultiplyWithFeedback(Node* context, Node* lhs, Node* rhs, + Node* slot_id, Node* feedback_vector); + + Node* Generate_DivideWithFeedback(Node* context, Node* dividend, + Node* divisor, Node* slot_id, + Node* feedback_vector); + + Node* Generate_ModulusWithFeedback(Node* context, Node* dividend, + Node* divisor, Node* slot_id, + Node* feedback_vector); +}; + +} // namespace internal +} // namespace v8 + +#endif // V8_SRC_IC_BINARY_OP_ASSEMBLER_H_ diff --git a/src/interpreter/interpreter-generator.cc b/src/interpreter/interpreter-generator.cc index fca8a50ab1..4f5ba53f54 100644 --- a/src/interpreter/interpreter-generator.cc +++ b/src/interpreter/interpreter-generator.cc @@ -14,6 +14,7 @@ #include "src/code-factory.h" #include "src/factory.h" #include "src/ic/accessor-assembler.h" +#include "src/ic/binary-op-assembler.h" #include "src/interpreter/bytecode-flags.h" #include "src/interpreter/bytecodes.h" #include "src/interpreter/interpreter-assembler.h" @@ -39,9 +40,14 @@ class InterpreterGenerator { #undef DECLARE_BYTECODE_HANDLER_GENERATOR private: + typedef Node* (BinaryOpAssembler::*BinaryOpGenerator)(Node* context, + Node* left, Node* right, + Node* slot, + Node* vector); + // Generates code to perform the binary operation via |Generator|. - template - void DoBinaryOpWithFeedback(InterpreterAssembler* assembler); + void DoBinaryOpWithFeedback(InterpreterAssembler* assembler, + BinaryOpGenerator generator); // Generates code to perform the comparison via |Generator| while gathering // type feedback. @@ -963,17 +969,18 @@ void InterpreterGenerator::DoCompareOp(Token::Value compare_op, __ Dispatch(); } -template void InterpreterGenerator::DoBinaryOpWithFeedback( - InterpreterAssembler* assembler) { + InterpreterAssembler* assembler, BinaryOpGenerator generator) { Node* reg_index = __ BytecodeOperandReg(0); Node* lhs = __ LoadRegister(reg_index); Node* rhs = __ GetAccumulator(); Node* context = __ GetContext(); Node* slot_index = __ BytecodeOperandIdx(1); Node* feedback_vector = __ LoadFeedbackVector(); - Node* result = Generator::Generate(assembler, lhs, rhs, slot_index, - feedback_vector, context); + + BinaryOpAssembler binop_asm(assembler->state()); + Node* result = + (binop_asm.*generator)(context, lhs, rhs, slot_index, feedback_vector); __ SetAccumulator(result); __ Dispatch(); } @@ -1171,35 +1178,40 @@ void InterpreterGenerator::DoCompareOpWithFeedback( // // Add register to accumulator. void InterpreterGenerator::DoAdd(InterpreterAssembler* assembler) { - DoBinaryOpWithFeedback(assembler); + DoBinaryOpWithFeedback(assembler, + &BinaryOpAssembler::Generate_AddWithFeedback); } // Sub // // Subtract register from accumulator. void InterpreterGenerator::DoSub(InterpreterAssembler* assembler) { - DoBinaryOpWithFeedback(assembler); + DoBinaryOpWithFeedback(assembler, + &BinaryOpAssembler::Generate_SubtractWithFeedback); } // Mul // // Multiply accumulator by register . void InterpreterGenerator::DoMul(InterpreterAssembler* assembler) { - DoBinaryOpWithFeedback(assembler); + DoBinaryOpWithFeedback(assembler, + &BinaryOpAssembler::Generate_MultiplyWithFeedback); } // Div // // Divide register by accumulator. void InterpreterGenerator::DoDiv(InterpreterAssembler* assembler) { - DoBinaryOpWithFeedback(assembler); + DoBinaryOpWithFeedback(assembler, + &BinaryOpAssembler::Generate_DivideWithFeedback); } // Mod // // Modulo register by accumulator. void InterpreterGenerator::DoMod(InterpreterAssembler* assembler) { - DoBinaryOpWithFeedback(assembler); + DoBinaryOpWithFeedback(assembler, + &BinaryOpAssembler::Generate_ModulusWithFeedback); } void InterpreterGenerator::DoBitwiseBinaryOp(Token::Value bitwise_op, @@ -1365,12 +1377,10 @@ void InterpreterGenerator::DoAddSmi(InterpreterAssembler* assembler) { __ Bind(&slowpath); { Node* context = __ GetContext(); - AddWithFeedbackStub stub(__ isolate()); - Callable callable = - Callable(stub.GetCode(), AddWithFeedbackStub::Descriptor(__ isolate())); - var_result.Bind(__ CallStub(callable, context, left, right, - __ TruncateWordToWord32(slot_index), - feedback_vector)); + // TODO(ishell): pass slot as word-size value. + var_result.Bind(__ CallBuiltin(Builtins::kAddWithFeedback, context, left, + right, __ TruncateWordToWord32(slot_index), + feedback_vector)); __ Goto(&end); } __ Bind(&end); @@ -1419,12 +1429,10 @@ void InterpreterGenerator::DoSubSmi(InterpreterAssembler* assembler) { __ Bind(&slowpath); { Node* context = __ GetContext(); - SubtractWithFeedbackStub stub(__ isolate()); - Callable callable = Callable( - stub.GetCode(), SubtractWithFeedbackStub::Descriptor(__ isolate())); - var_result.Bind(__ CallStub(callable, context, left, right, - __ TruncateWordToWord32(slot_index), - feedback_vector)); + // TODO(ishell): pass slot as word-size value. + var_result.Bind( + __ CallBuiltin(Builtins::kSubtractWithFeedback, context, left, right, + __ TruncateWordToWord32(slot_index), feedback_vector)); __ Goto(&end); } __ Bind(&end); diff --git a/src/v8.gyp b/src/v8.gyp index feef1be75d..e0a2e04834 100644 --- a/src/v8.gyp +++ b/src/v8.gyp @@ -998,6 +998,8 @@ 'ic/access-compiler.h', 'ic/accessor-assembler.cc', 'ic/accessor-assembler.h', + 'ic/binary-op-assembler.cc', + 'ic/binary-op-assembler.h', 'ic/call-optimization.cc', 'ic/call-optimization.h', 'ic/handler-compiler.cc',