Chromium Code Reviews| Index: src/code-stubs.cc |
| diff --git a/src/code-stubs.cc b/src/code-stubs.cc |
| index 45d1bba446240023a784685e318f398051416401..63c077d6af0131ebf6e84a55c5b64a39c12588aa 100644 |
| --- a/src/code-stubs.cc |
| +++ b/src/code-stubs.cc |
| @@ -1169,6 +1169,211 @@ void MultiplyStub::GenerateAssembly( |
| } |
| } |
| +void DivideStub::GenerateAssembly( |
| + compiler::CodeStubAssembler* assembler) const { |
| + using compiler::Node; |
| + typedef compiler::CodeStubAssembler::Label Label; |
| + typedef compiler::CodeStubAssembler::Variable Variable; |
| + |
| + Node* context = assembler->Parameter(2); |
| + |
| + // Shared entry point for floating point division. |
| + Label do_fdiv(assembler); |
| + Variable var_dividend_float64(assembler, MachineRepresentation::kFloat64), |
| + var_divisor_float64(assembler, MachineRepresentation::kFloat64); |
| + |
| + Node* number_map = assembler->HeapNumberMapConstant(); |
| + |
| + // We might need to loop one or two times due to ToNumber conversions. |
| + Variable var_dividend(assembler, MachineRepresentation::kTagged), |
| + var_divisor(assembler, MachineRepresentation::kTagged); |
| + Variable* loop_variables[] = {&var_dividend, &var_divisor}; |
| + Label loop(assembler, 2, loop_variables); |
| + var_dividend.Bind(assembler->Parameter(0)); |
| + var_divisor.Bind(assembler->Parameter(1)); |
| + assembler->Goto(&loop); |
| + assembler->Bind(&loop); |
| + { |
| + Node* dividend = var_dividend.value(); |
| + Node* divisor = var_divisor.value(); |
| + |
| + Label dividend_is_smi(assembler), dividend_is_not_smi(assembler); |
| + assembler->Branch(assembler->WordIsSmi(dividend), ÷nd_is_smi, |
| + ÷nd_is_not_smi); |
| + |
| + assembler->Bind(÷nd_is_smi); |
| + { |
| + Label divisor_is_smi(assembler), divisor_is_not_smi(assembler); |
| + assembler->Branch(assembler->WordIsSmi(divisor), &divisor_is_smi, |
| + &divisor_is_not_smi); |
| + |
| + assembler->Bind(&divisor_is_smi); |
| + { |
| + Label bailout(assembler); |
| + |
| + // Do floating point division if {divisor} is zero. |
| + assembler->GotoIf( |
| + assembler->Word32Equal(divisor, assembler->Int32Constant(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->WordNotEqual(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->WordSar( |
| + divisor, assembler->IntPtrConstant(kSmiTagSize + kSmiShiftSize)); |
| + |
| + // Do floating point division if {dividend} is kMinInt 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(assembler->SmiUntag(dividend), |
| + assembler->Int32Constant(kMinInt)), |
| + &bailout); |
| + assembler->Goto(&divisor_is_not_minus_one); |
| + } |
| + assembler->Bind(&divisor_is_not_minus_one); |
| + |
| + // TODO(epertoso): consider adding a machine instruction that returns |
| + // both the result and the remainder. |
| + Node* result = assembler->IntPtrDiv(dividend, untagged_divisor); |
| + Node* truncated = assembler->IntPtrMul(result, untagged_divisor); |
| + // Do floating point division if the remainder is not 0. |
| + assembler->GotoIf(assembler->WordNotEqual(dividend, truncated), |
| + &bailout); |
| + assembler->Return(result); |
| + |
| + // Bailout: convert {dividend} and {divisor} to double and do double |
| + // division. |
| + assembler->Bind(&bailout); |
|
Benedikt Meurer
2016/04/08 04:25:03
Nit: Add { and } around the bailout code lines bel
epertoso
2016/04/08 08:25:17
Done.
|
| + var_dividend_float64.Bind(assembler->SmiToFloat64(dividend)); |
| + var_divisor_float64.Bind(assembler->SmiToFloat64(divisor)); |
| + assembler->Goto(&do_fdiv); |
| + } |
| + |
| + assembler->Bind(&divisor_is_not_smi); |
| + { |
| + Node* divisor_map = assembler->LoadMap(divisor); |
| + |
| + // Check if {divisor} is a HeapNumber. |
| + Label divisor_is_number(assembler), |
| + divisor_is_not_number(assembler, Label::kDeferred); |
| + assembler->Branch(assembler->WordEqual(divisor_map, number_map), |
| + &divisor_is_number, &divisor_is_not_number); |
| + |
| + assembler->Bind(&divisor_is_number); |
| + { |
| + // Convert {dividend} to a double and divide it with the value of |
| + // {divisor}. |
| + var_dividend_float64.Bind(assembler->SmiToFloat64(dividend)); |
| + var_divisor_float64.Bind(assembler->LoadHeapNumberValue(divisor)); |
| + assembler->Goto(&do_fdiv); |
| + } |
| + |
| + assembler->Bind(&divisor_is_not_number); |
| + { |
| + // Convert {divisor} to a number and loop. |
| + Callable callable = CodeFactory::NonNumberToNumber(isolate()); |
| + var_divisor.Bind(assembler->CallStub(callable, context, divisor)); |
| + assembler->Goto(&loop); |
| + } |
| + } |
| + } |
| + |
| + assembler->Bind(÷nd_is_not_smi); |
| + { |
| + Node* dividend_map = assembler->LoadMap(dividend); |
| + |
| + // Check if {dividend} is a HeapNumber. |
| + Label dividend_is_number(assembler), |
| + dividend_is_not_number(assembler, Label::kDeferred); |
| + assembler->Branch(assembler->WordEqual(dividend_map, number_map), |
| + ÷nd_is_number, ÷nd_is_not_number); |
| + |
| + assembler->Bind(÷nd_is_number); |
| + { |
| + // Check if {divisor} is a Smi. |
| + Label divisor_is_smi(assembler), divisor_is_not_smi(assembler); |
| + assembler->Branch(assembler->WordIsSmi(divisor), &divisor_is_smi, |
| + &divisor_is_not_smi); |
| + |
| + assembler->Bind(&divisor_is_smi); |
| + { |
| + // Convert {divisor} to a double and divide it with the value of |
| + // {dividend}. |
| + 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. |
| + Label divisor_is_number(assembler), |
| + divisor_is_not_number(assembler, Label::kDeferred); |
| + assembler->Branch(assembler->WordEqual(divisor_map, number_map), |
| + &divisor_is_number, &divisor_is_not_number); |
| + |
| + assembler->Bind(&divisor_is_number); |
| + { |
| + // Both {dividend} and {divisor} are HeapNumbers. Load their values |
| + // and |
| + // divide them. |
| + var_dividend_float64.Bind(assembler->LoadHeapNumberValue(dividend)); |
| + var_divisor_float64.Bind(assembler->LoadHeapNumberValue(divisor)); |
| + assembler->Goto(&do_fdiv); |
| + } |
| + |
| + assembler->Bind(&divisor_is_not_number); |
| + { |
| + // Convert {divisor} to a number and loop. |
| + Callable callable = CodeFactory::NonNumberToNumber(isolate()); |
| + var_divisor.Bind(assembler->CallStub(callable, context, divisor)); |
| + assembler->Goto(&loop); |
| + } |
| + } |
| + } |
| + |
| + assembler->Bind(÷nd_is_not_number); |
| + { |
| + // Convert {dividend} to a Number and loop. |
| + Callable callable = CodeFactory::NonNumberToNumber(isolate()); |
| + var_dividend.Bind(assembler->CallStub(callable, context, dividend)); |
| + assembler->Goto(&loop); |
| + } |
| + } |
| + } |
| + |
| + assembler->Bind(&do_fdiv); |
| + { |
| + Node* value = assembler->Float64Div(var_dividend_float64.value(), |
| + var_divisor_float64.value()); |
| + Node* result = assembler->ChangeFloat64ToTagged(value); |
| + assembler->Return(result); |
| + } |
| +} |
| + |
| void BitwiseAndStub::GenerateAssembly( |
| compiler::CodeStubAssembler* assembler) const { |
| using compiler::Node; |