Commit 8944d36f authored by zhengxing.li's avatar zhengxing.li Committed by Commit bot

X87: [builtins] Make Math.max and Math.min fast by default.

  port cb9b8010 (r33582)

  original commit message:
  The previous versions of Math.max and Math.min made it difficult to
  optimize those (that's why we already have custom code in Crankshaft),
  and due to lack of ideas what to do about the variable number of
  arguments, we will probably need to stick in special code in TurboFan
  as well; so inlining those builtins is off the table, hence there's no
  real advantage in having them around as "not quite JS" with extra work
  necessary in the optimizing compilers to still make those builtins
  somewhat fast in cases where we cannot inline them (also there's a
  tricky deopt loop in Crankshaft related to Math.min and Math.max, but
  that will be dealt with later).

  So to sum up: Instead of trying to make Math.max and Math.min semi-fast
  in the optimizing compilers with weird work-arounds support %_Arguments
  %_ArgumentsLength, we do provide the optimal code as native builtins
  instead and call it a day (which gives a nice performance boost on some
  benchmarks).

BUG=

Review URL: https://codereview.chromium.org/1659623003

Cr-Commit-Position: refs/heads/master@{#33652}
parent 15da9843
......@@ -1415,6 +1415,140 @@ void Builtins::Generate_ArrayCode(MacroAssembler* masm) {
}
// static
void Builtins::Generate_MathMaxMin(MacroAssembler* masm, MathMaxMinKind kind) {
// ----------- S t a t e -------------
// -- eax : number of arguments
// -- esp[0] : return address
// -- esp[(argc - n) * 8] : arg[n] (zero-based)
// -- esp[(argc + 1) * 8] : receiver
// -----------------------------------
Condition const cc = (kind == MathMaxMinKind::kMin) ? below : above;
Heap::RootListIndex const root_index =
(kind == MathMaxMinKind::kMin) ? Heap::kInfinityValueRootIndex
: Heap::kMinusInfinityValueRootIndex;
const int reg_sel = (kind == MathMaxMinKind::kMin) ? 1 : 0;
// Load the accumulator with the default return value (either -Infinity or
// +Infinity), with the tagged value in edx and the double value in stx_0.
__ LoadRoot(edx, root_index);
__ fld_d(FieldOperand(edx, HeapNumber::kValueOffset));
__ Move(ecx, eax);
Label done_loop, loop;
__ bind(&loop);
{
// Check if all parameters done.
__ test(ecx, ecx);
__ j(zero, &done_loop);
// Load the next parameter tagged value into ebx.
__ mov(ebx, Operand(esp, ecx, times_pointer_size, 0));
// Load the double value of the parameter into stx_1, maybe converting the
// parameter to a number first using the ToNumberStub if necessary.
Label convert, convert_smi, convert_number, done_convert;
__ bind(&convert);
__ JumpIfSmi(ebx, &convert_smi);
__ JumpIfRoot(FieldOperand(ebx, HeapObject::kMapOffset),
Heap::kHeapNumberMapRootIndex, &convert_number);
{
// Parameter is not a Number, use the ToNumberStub to convert it.
FrameScope scope(masm, StackFrame::INTERNAL);
__ SmiTag(eax);
__ SmiTag(ecx);
__ Push(eax);
__ Push(ecx);
__ Push(edx);
__ mov(eax, ebx);
ToNumberStub stub(masm->isolate());
__ CallStub(&stub);
__ mov(ebx, eax);
__ Pop(edx);
__ Pop(ecx);
__ Pop(eax);
{
// Restore the double accumulator value (stX_0).
Label restore_smi, done_restore;
__ JumpIfSmi(edx, &restore_smi, Label::kNear);
__ fld_d(FieldOperand(edx, HeapNumber::kValueOffset));
__ jmp(&done_restore, Label::kNear);
__ bind(&restore_smi);
__ SmiUntag(edx);
__ push(edx);
__ fild_s(Operand(esp, 0));
__ pop(edx);
__ SmiTag(edx);
__ bind(&done_restore);
}
__ SmiUntag(ecx);
__ SmiUntag(eax);
}
__ jmp(&convert);
__ bind(&convert_number);
// Load another value into stx_1
__ fld_d(FieldOperand(ebx, HeapNumber::kValueOffset));
__ fxch();
__ jmp(&done_convert, Label::kNear);
__ bind(&convert_smi);
__ SmiUntag(ebx);
__ push(ebx);
__ fild_s(Operand(esp, 0));
__ pop(ebx);
__ fxch();
__ SmiTag(ebx);
__ bind(&done_convert);
// Perform the actual comparison with the accumulator value on the left hand
// side (stx_0) and the next parameter value on the right hand side (stx_1).
Label compare_equal, compare_nan, compare_swap, done_compare;
// Duplicates the 2 float data for FCmp
__ fld(1);
__ fld(1);
__ FCmp();
__ j(parity_even, &compare_nan, Label::kNear);
__ j(cc, &done_compare, Label::kNear);
__ j(equal, &compare_equal, Label::kNear);
// Result is on the right hand side(stx_0).
__ bind(&compare_swap);
__ fxch();
__ mov(edx, ebx);
__ jmp(&done_compare, Label::kNear);
// At least one side is NaN, which means that the result will be NaN too.
__ bind(&compare_nan);
// Set the result on the right hand side (stx_0) to nan
__ fstp(0);
__ LoadRoot(edx, Heap::kNanValueRootIndex);
__ fld_d(FieldOperand(edx, HeapNumber::kValueOffset));
__ jmp(&done_compare, Label::kNear);
// Left and right hand side are equal, check for -0 vs. +0.
__ bind(&compare_equal);
// Check the sign of the value in reg_sel
__ fld(reg_sel);
__ FXamSign();
__ j(not_zero, &compare_swap);
__ bind(&done_compare);
// The right result is on the right hand side(stx_0)
// and can remove the useless stx_1 now.
__ fxch();
__ fstp(0);
__ dec(ecx);
__ jmp(&loop);
}
__ bind(&done_loop);
__ PopReturnAddressTo(ecx);
__ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize));
__ PushReturnAddressFrom(ecx);
__ mov(eax, edx);
__ Ret();
}
// static
void Builtins::Generate_NumberConstructor(MacroAssembler* masm) {
// ----------- S t a t e -------------
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment