Index: src/code-stubs.cc |
diff --git a/src/code-stubs.cc b/src/code-stubs.cc |
index 64341694233b0fe4f69911fbf51c1fdfea3530f0..8dc1ff9811e948e74b36cee40a9d07c20bf8a9bf 100644 |
--- a/src/code-stubs.cc |
+++ b/src/code-stubs.cc |
@@ -907,6 +907,139 @@ compiler::Node* AddStub::Generate(CodeStubAssembler* assembler, |
} |
// static |
+compiler::Node* AddWithFeedbackStub::Generate( |
+ CodeStubAssembler* assembler, compiler::Node* lhs, compiler::Node* rhs, |
+ compiler::Node* context, compiler::Node* type_feedback_vector, |
+ compiler::Node* slot_id) { |
+ typedef CodeStubAssembler::Label Label; |
+ typedef compiler::Node Node; |
+ typedef CodeStubAssembler::Variable Variable; |
+ |
+ // Shared entry for floating point addition. |
+ Label do_fadd(assembler), end(assembler), |
+ call_add_stub(assembler, Label::kDeferred); |
+ Variable var_fadd_lhs(assembler, MachineRepresentation::kFloat64), |
+ var_fadd_rhs(assembler, MachineRepresentation::kFloat64), |
+ var_type_feedback(assembler, MachineRepresentation::kWord32), |
+ var_result(assembler, MachineRepresentation::kTagged); |
+ |
+ // 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_type_feedback.Bind( |
+ assembler->Int32Constant(BinaryOperationFeedback::kSignedSmall)); |
+ 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. |
+ assembler->GotoUnless( |
+ assembler->WordEqual(rhs_map, assembler->HeapNumberMapConstant()), |
+ &call_add_stub); |
+ |
+ var_fadd_lhs.Bind(assembler->SmiToFloat64(lhs)); |
+ var_fadd_rhs.Bind(assembler->LoadHeapNumberValue(rhs)); |
+ assembler->Goto(&do_fadd); |
+ } |
+ } |
+ |
+ 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->GotoUnless( |
+ assembler->WordEqual(lhs_map, assembler->HeapNumberMapConstant()), |
+ &call_add_stub); |
+ |
+ // Check if the {rhs} is Smi. |
+ Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler); |
+ assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi, &if_rhsisnotsmi); |
+ |
+ assembler->Bind(&if_rhsissmi); |
+ { |
+ var_fadd_lhs.Bind(assembler->LoadHeapNumberValue(lhs)); |
+ var_fadd_rhs.Bind(assembler->SmiToFloat64(rhs)); |
+ assembler->Goto(&do_fadd); |
+ } |
+ |
+ assembler->Bind(&if_rhsisnotsmi); |
+ { |
+ // Load the map of {rhs}. |
+ Node* rhs_map = assembler->LoadMap(rhs); |
+ |
+ // Check if the {rhs} is a HeapNumber. |
+ Node* number_map = assembler->HeapNumberMapConstant(); |
+ assembler->GotoUnless(assembler->WordEqual(rhs_map, number_map), |
+ &call_add_stub); |
+ |
+ 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->ChangeFloat64ToTagged(value); |
+ var_result.Bind(result); |
+ assembler->Goto(&end); |
+ } |
+ |
+ assembler->Bind(&call_add_stub); |
+ { |
+ var_type_feedback.Bind( |
+ assembler->Int32Constant(BinaryOperationFeedback::kAny)); |
+ Callable callable = CodeFactory::Add(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* SubtractStub::Generate(CodeStubAssembler* assembler, |
compiler::Node* left, |
compiler::Node* right, |
@@ -1091,12 +1224,12 @@ compiler::Node* SubtractWithFeedbackStub::Generate( |
typedef CodeStubAssembler::Variable Variable; |
// Shared entry for floating point subtraction. |
- Label do_fsub(assembler), record_feedback(assembler), |
+ Label do_fsub(assembler), end(assembler), |
call_subtract_stub(assembler, Label::kDeferred); |
Variable var_fsub_lhs(assembler, MachineRepresentation::kFloat64), |
- var_fsub_rhs(assembler, MachineRepresentation::kFloat64); |
- Variable var_type_feedback(assembler, MachineRepresentation::kWord32); |
- Variable var_result(assembler, MachineRepresentation::kTagged); |
+ var_fsub_rhs(assembler, MachineRepresentation::kFloat64), |
+ var_type_feedback(assembler, MachineRepresentation::kWord32), |
+ var_result(assembler, MachineRepresentation::kTagged); |
// Check if the {lhs} is a Smi or a HeapObject. |
Label if_lhsissmi(assembler), if_lhsisnotsmi(assembler); |
@@ -1122,8 +1255,6 @@ compiler::Node* SubtractWithFeedbackStub::Generate( |
{ |
// lhs, rhs - smi and result - number. combined - number. |
// The result doesn't fit into Smi range. |
- var_type_feedback.Bind( |
- assembler->Int32Constant(BinaryOperationFeedback::kNumber)); |
var_fsub_lhs.Bind(assembler->SmiToFloat64(lhs)); |
var_fsub_rhs.Bind(assembler->SmiToFloat64(rhs)); |
assembler->Goto(&do_fsub); |
@@ -1134,7 +1265,7 @@ compiler::Node* SubtractWithFeedbackStub::Generate( |
var_type_feedback.Bind( |
assembler->Int32Constant(BinaryOperationFeedback::kSignedSmall)); |
var_result.Bind(assembler->Projection(0, pair)); |
- assembler->Goto(&record_feedback); |
+ assembler->Goto(&end); |
} |
assembler->Bind(&if_rhsisnotsmi); |
@@ -1143,28 +1274,14 @@ compiler::Node* SubtractWithFeedbackStub::Generate( |
Node* rhs_map = assembler->LoadMap(rhs); |
// Check if {rhs} is a HeapNumber. |
- Label if_rhsisnumber(assembler), |
- if_rhsisnotnumber(assembler, Label::kDeferred); |
- Node* number_map = assembler->HeapNumberMapConstant(); |
- assembler->Branch(assembler->WordEqual(rhs_map, number_map), |
- &if_rhsisnumber, &if_rhsisnotnumber); |
- |
- assembler->Bind(&if_rhsisnumber); |
- { |
- var_type_feedback.Bind( |
- assembler->Int32Constant(BinaryOperationFeedback::kNumber)); |
- // 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); |
- { |
- var_type_feedback.Bind( |
- assembler->Int32Constant(BinaryOperationFeedback::kAny)); |
- assembler->Goto(&call_subtract_stub); |
- } |
+ assembler->GotoUnless( |
+ assembler->WordEqual(rhs_map, assembler->HeapNumberMapConstant()), |
+ &call_subtract_stub); |
+ |
+ // Perform a floating point subtraction. |
+ var_fsub_lhs.Bind(assembler->SmiToFloat64(lhs)); |
+ var_fsub_rhs.Bind(assembler->LoadHeapNumberValue(rhs)); |
+ assembler->Goto(&do_fsub); |
} |
} |
@@ -1174,116 +1291,62 @@ compiler::Node* SubtractWithFeedbackStub::Generate( |
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); |
- { |
- var_type_feedback.Bind( |
- assembler->Int32Constant(BinaryOperationFeedback::kNumber)); |
- // 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->GotoUnless( |
+ assembler->WordEqual(lhs_map, assembler->HeapNumberMapConstant()), |
+ &call_subtract_stub); |
- assembler->Bind(&if_rhsisnumber); |
- { |
- var_type_feedback.Bind( |
- assembler->Int32Constant(BinaryOperationFeedback::kNumber)); |
- // Perform a floating point subtraction. |
- var_fsub_lhs.Bind(assembler->LoadHeapNumberValue(lhs)); |
- var_fsub_rhs.Bind(assembler->LoadHeapNumberValue(rhs)); |
- assembler->Goto(&do_fsub); |
- } |
+ // 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_rhsisnotnumber); |
- { |
- var_type_feedback.Bind( |
- assembler->Int32Constant(BinaryOperationFeedback::kAny)); |
- assembler->Goto(&call_subtract_stub); |
- } |
- } |
+ 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_lhsisnotnumber); |
+ assembler->Bind(&if_rhsisnotsmi); |
{ |
- var_type_feedback.Bind( |
- assembler->Int32Constant(BinaryOperationFeedback::kAny)); |
- assembler->Goto(&call_subtract_stub); |
+ // Load the map of the {rhs}. |
+ Node* rhs_map = assembler->LoadMap(rhs); |
+ |
+ // Check if the {rhs} is a HeapNumber. |
+ assembler->GotoUnless( |
+ assembler->WordEqual(rhs_map, assembler->HeapNumberMapConstant()), |
+ &call_subtract_stub); |
+ |
+ // 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(&do_fsub); |
{ |
+ var_type_feedback.Bind( |
+ assembler->Int32Constant(BinaryOperationFeedback::kNumber)); |
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(&record_feedback); |
+ assembler->Goto(&end); |
} |
assembler->Bind(&call_subtract_stub); |
{ |
+ 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(&record_feedback); |
- } |
- |
- assembler->Bind(&record_feedback); |
- Label combine_feedback(assembler), initialize_feedback(assembler), |
- return_value(assembler); |
- |
- Node* previous_feedback = |
- assembler->LoadFixedArrayElement(type_feedback_vector, slot_id); |
- Node* is_uninitialized = assembler->WordEqual( |
- previous_feedback, |
- assembler->HeapConstant( |
- TypeFeedbackVector::UninitializedSentinel(assembler->isolate()))); |
- assembler->BranchIf(is_uninitialized, &initialize_feedback, |
- &combine_feedback); |
- |
- assembler->Bind(&initialize_feedback); |
- { |
- assembler->StoreFixedArrayElement( |
- type_feedback_vector, slot_id, |
- assembler->SmiTag(var_type_feedback.value()), SKIP_WRITE_BARRIER); |
- assembler->Goto(&return_value); |
- } |
- |
- assembler->Bind(&combine_feedback); |
- { |
- Node* previous_feedback_int = assembler->SmiUntag(previous_feedback); |
- Node* combined_feedback = |
- assembler->Word32Or(previous_feedback_int, var_type_feedback.value()); |
- assembler->StoreFixedArrayElement(type_feedback_vector, slot_id, |
- assembler->SmiTag(combined_feedback), |
- SKIP_WRITE_BARRIER); |
- assembler->Goto(&return_value); |
+ assembler->Goto(&end); |
} |
- assembler->Bind(&return_value); |
+ assembler->Bind(&end); |
+ assembler->UpdateFeedback(var_type_feedback.value(), type_feedback_vector, |
+ slot_id); |
return var_result.value(); |
} |
@@ -1441,6 +1504,123 @@ compiler::Node* MultiplyStub::Generate(CodeStubAssembler* assembler, |
} |
// static |
+compiler::Node* MultiplyWithFeedbackStub::Generate( |
+ CodeStubAssembler* assembler, compiler::Node* lhs, compiler::Node* rhs, |
+ compiler::Node* context, compiler::Node* type_feedback_vector, |
+ compiler::Node* slot_id) { |
+ using compiler::Node; |
+ typedef CodeStubAssembler::Label Label; |
+ typedef CodeStubAssembler::Variable Variable; |
+ |
+ // Shared entry point for floating point multiplication. |
+ Label do_fmul(assembler), end(assembler), |
+ call_multiply_stub(assembler, Label::kDeferred); |
+ Variable var_lhs_float64(assembler, MachineRepresentation::kFloat64), |
+ var_rhs_float64(assembler, MachineRepresentation::kFloat64), |
+ var_result(assembler, MachineRepresentation::kTagged), |
+ var_type_feedback(assembler, MachineRepresentation::kWord32); |
+ |
+ 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->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->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)); |
+ var_type_feedback.Bind(assembler->Select( |
+ assembler->WordIsSmi(var_result.value()), |
+ assembler->Int32Constant(BinaryOperationFeedback::kSignedSmall), |
+ assembler->Int32Constant(BinaryOperationFeedback::kNumber), |
+ MachineRepresentation::kWord32)); |
+ assembler->Goto(&end); |
+ } |
+ |
+ assembler->Bind(&rhs_is_not_smi); |
+ { |
+ Node* rhs_map = assembler->LoadMap(rhs); |
+ |
+ // Check if {rhs} is a HeapNumber. |
+ assembler->GotoUnless(assembler->WordEqual(rhs_map, number_map), |
+ &call_multiply_stub); |
+ |
+ // 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(&lhs_is_not_smi); |
+ { |
+ Node* lhs_map = assembler->LoadMap(lhs); |
+ |
+ // Check if {lhs} is a HeapNumber. |
+ assembler->GotoUnless(assembler->WordEqual(lhs_map, number_map), |
+ &call_multiply_stub); |
+ |
+ // 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->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(&rhs_is_not_smi); |
+ { |
+ Node* rhs_map = assembler->LoadMap(rhs); |
+ |
+ // Check if {rhs} is a HeapNumber. |
+ assembler->GotoUnless(assembler->WordEqual(rhs_map, number_map), |
+ &call_multiply_stub); |
+ |
+ // 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(&do_fmul); |
+ { |
+ var_type_feedback.Bind( |
+ assembler->Int32Constant(BinaryOperationFeedback::kNumber)); |
+ Node* value = |
+ assembler->Float64Mul(var_lhs_float64.value(), var_rhs_float64.value()); |
+ Node* result = assembler->ChangeFloat64ToTagged(value); |
+ var_result.Bind(result); |
+ assembler->Goto(&end); |
+ } |
+ |
+ assembler->Bind(&call_multiply_stub); |
+ { |
+ 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(); |
+} |
+ |
+// static |
compiler::Node* DivideStub::Generate(CodeStubAssembler* assembler, |
compiler::Node* left, |
compiler::Node* right, |
@@ -1659,6 +1839,182 @@ compiler::Node* DivideStub::Generate(CodeStubAssembler* assembler, |
} |
// static |
+compiler::Node* DivideWithFeedbackStub::Generate( |
+ CodeStubAssembler* assembler, compiler::Node* dividend, |
+ compiler::Node* divisor, compiler::Node* context, |
+ compiler::Node* type_feedback_vector, compiler::Node* slot_id) { |
+ using compiler::Node; |
+ typedef CodeStubAssembler::Label Label; |
+ typedef CodeStubAssembler::Variable Variable; |
+ |
+ // Shared entry point for floating point division. |
+ Label do_fdiv(assembler), end(assembler), call_divide_stub(assembler); |
+ Variable var_dividend_float64(assembler, MachineRepresentation::kFloat64), |
+ var_divisor_float64(assembler, MachineRepresentation::kFloat64), |
+ var_result(assembler, MachineRepresentation::kTagged), |
+ var_type_feedback(assembler, MachineRepresentation::kWord32); |
+ |
+ Node* number_map = assembler->HeapNumberMapConstant(); |
+ |
+ 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); |
+ |
+ Node* untagged_result = |
+ assembler->Int32Div(untagged_dividend, untagged_divisor); |
+ Node* truncated = assembler->IntPtrMul(untagged_result, untagged_divisor); |
+ // Do floating point division if the remainder is not 0. |
+ assembler->GotoIf(assembler->Word32NotEqual(untagged_dividend, truncated), |
+ &bailout); |
+ var_type_feedback.Bind( |
+ assembler->Int32Constant(BinaryOperationFeedback::kSignedSmall)); |
+ 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. |
+ assembler->GotoUnless(assembler->WordEqual(divisor_map, number_map), |
+ &call_divide_stub); |
+ |
+ // 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(÷nd_is_not_smi); |
+ { |
+ Node* dividend_map = assembler->LoadMap(dividend); |
+ |
+ // Check if {dividend} is a HeapNumber. |
+ assembler->GotoUnless(assembler->WordEqual(dividend_map, number_map), |
+ &call_divide_stub); |
+ |
+ // 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); |
+ } |
+ |
+ assembler->Bind(&divisor_is_not_smi); |
+ { |
+ Node* divisor_map = assembler->LoadMap(divisor); |
+ |
+ // Check if {divisor} is a HeapNumber. |
+ assembler->GotoUnless(assembler->WordEqual(divisor_map, number_map), |
+ &call_divide_stub); |
+ |
+ // 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(&do_fdiv); |
+ { |
+ var_type_feedback.Bind( |
+ assembler->Int32Constant(BinaryOperationFeedback::kNumber)); |
+ Node* value = assembler->Float64Div(var_dividend_float64.value(), |
+ var_divisor_float64.value()); |
+ var_result.Bind(assembler->ChangeFloat64ToTagged(value)); |
+ assembler->Goto(&end); |
+ } |
+ |
+ assembler->Bind(&call_divide_stub); |
+ { |
+ 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); |
+ } |
+ |
+ 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, |
@@ -1818,6 +2174,122 @@ compiler::Node* ModulusStub::Generate(CodeStubAssembler* assembler, |
} |
// static |
+compiler::Node* ModulusWithFeedbackStub::Generate( |
+ CodeStubAssembler* assembler, compiler::Node* dividend, |
+ compiler::Node* divisor, compiler::Node* context, |
+ compiler::Node* type_feedback_vector, compiler::Node* slot_id) { |
+ using compiler::Node; |
+ typedef CodeStubAssembler::Label Label; |
+ typedef CodeStubAssembler::Variable Variable; |
+ |
+ // Shared entry point for floating point division. |
+ Label do_fmod(assembler), end(assembler), call_modulus_stub(assembler); |
+ Variable var_dividend_float64(assembler, MachineRepresentation::kFloat64), |
+ var_divisor_float64(assembler, MachineRepresentation::kFloat64), |
+ var_result(assembler, MachineRepresentation::kTagged), |
+ var_type_feedback(assembler, MachineRepresentation::kWord32); |
+ |
+ Node* number_map = assembler->HeapNumberMapConstant(); |
+ |
+ 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); |
+ { |
+ var_result.Bind(assembler->SmiMod(dividend, divisor)); |
+ var_type_feedback.Bind(assembler->Select( |
+ assembler->WordIsSmi(var_result.value()), |
+ assembler->Int32Constant(BinaryOperationFeedback::kSignedSmall), |
+ assembler->Int32Constant(BinaryOperationFeedback::kNumber))); |
+ assembler->Goto(&end); |
+ } |
+ |
+ assembler->Bind(&divisor_is_not_smi); |
+ { |
+ Node* divisor_map = assembler->LoadMap(divisor); |
+ |
+ // Check if {divisor} is a HeapNumber. |
+ assembler->GotoUnless(assembler->WordEqual(divisor_map, number_map), |
+ &call_modulus_stub); |
+ |
+ // 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_fmod); |
+ } |
+ } |
+ |
+ assembler->Bind(÷nd_is_not_smi); |
+ { |
+ Node* dividend_map = assembler->LoadMap(dividend); |
+ |
+ // Check if {dividend} is a HeapNumber. |
+ assembler->GotoUnless(assembler->WordEqual(dividend_map, number_map), |
+ &call_modulus_stub); |
+ |
+ // 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_fmod); |
+ } |
+ |
+ assembler->Bind(&divisor_is_not_smi); |
+ { |
+ Node* divisor_map = assembler->LoadMap(divisor); |
+ |
+ // Check if {divisor} is a HeapNumber. |
+ assembler->GotoUnless(assembler->WordEqual(divisor_map, number_map), |
+ &call_modulus_stub); |
+ |
+ // 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_fmod); |
+ } |
+ } |
+ |
+ assembler->Bind(&do_fmod); |
+ { |
+ var_type_feedback.Bind( |
+ assembler->Int32Constant(BinaryOperationFeedback::kNumber)); |
+ Node* value = assembler->Float64Mod(var_dividend_float64.value(), |
+ var_divisor_float64.value()); |
+ var_result.Bind(assembler->ChangeFloat64ToTagged(value)); |
+ assembler->Goto(&end); |
+ } |
+ |
+ assembler->Bind(&call_modulus_stub); |
+ { |
+ var_type_feedback.Bind( |
+ assembler->Int32Constant(BinaryOperationFeedback::kAny)); |
+ Callable callable = CodeFactory::Modulus(assembler->isolate()); |
+ var_result.Bind(assembler->CallStub(callable, context, dividend, divisor)); |
+ assembler->Goto(&end); |
+ } |
+ |
+ assembler->Bind(&end); |
+ assembler->UpdateFeedback(var_type_feedback.value(), type_feedback_vector, |
+ slot_id); |
+ return var_result.value(); |
+} |
+// static |
compiler::Node* ShiftLeftStub::Generate(CodeStubAssembler* assembler, |
compiler::Node* left, |
compiler::Node* right, |