Commit 26a52ed4 authored by mbrandy's avatar mbrandy Committed by Commit bot

PPC: [builtins] Migrate Number constructor similar to String constructor.

Port 322ffda3

Original commit message:
    Also migrate the Number constructor to a native builtin, using the
    same mechanism already used by the String constructor. Otherwise just
    parsing and compiling the Number constructor to optimized code already
    eats 2ms on desktop for no good reason, and the resulting optimized
    code is not even close to awesome.

    Drive-by-fix: Use correct context for the [[Construct]] case of the
    String constructor as well, and share some code with it.

R=bmeurer@chromium.org, joransiu@ca.ibm.com, jyan@ca.ibm.com, michael_dawson@ca.ibm.com
BUG=

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

Cr-Commit-Position: refs/heads/master@{#33272}
parent fd733987
...@@ -135,6 +135,110 @@ void Builtins::Generate_ArrayCode(MacroAssembler* masm) { ...@@ -135,6 +135,110 @@ void Builtins::Generate_ArrayCode(MacroAssembler* masm) {
} }
// static
void Builtins::Generate_NumberConstructor(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- r3 : number of arguments
// -- r4 : constructor function
// -- lr : return address
// -- sp[(argc - n - 1) * 4] : arg[n] (zero based)
// -- sp[argc * 4] : receiver
// -----------------------------------
// 1. Load the first argument into r3 and get rid of the rest (including the
// receiver).
Label no_arguments;
{
__ cmpi(r3, Operand::Zero());
__ beq(&no_arguments);
__ subi(r3, r3, Operand(1));
__ ShiftLeftImm(r3, r3, Operand(kPointerSizeLog2));
__ LoadPUX(r3, MemOperand(sp, r3));
__ Drop(2);
}
// 2a. Convert the first argument to a number.
ToNumberStub stub(masm->isolate());
__ TailCallStub(&stub);
// 2b. No arguments, return +0.
__ bind(&no_arguments);
__ LoadSmiLiteral(r3, Smi::FromInt(0));
__ Ret(1);
}
// static
void Builtins::Generate_NumberConstructor_ConstructStub(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- r3 : number of arguments
// -- r4 : constructor function
// -- r6 : new target
// -- lr : return address
// -- sp[(argc - n - 1) * 4] : arg[n] (zero based)
// -- sp[argc * 4] : receiver
// -----------------------------------
// 1. Make sure we operate in the context of the called function.
__ LoadP(cp, FieldMemOperand(r4, JSFunction::kContextOffset));
// 2. Load the first argument into r5 and get rid of the rest (including the
// receiver).
{
Label no_arguments, done;
__ cmpi(r3, Operand::Zero());
__ beq(&no_arguments);
__ subi(r3, r3, Operand(1));
__ ShiftLeftImm(r5, r3, Operand(kPointerSizeLog2));
__ LoadPUX(r5, MemOperand(sp, r5));
__ Drop(2);
__ b(&done);
__ bind(&no_arguments);
__ LoadSmiLiteral(r5, Smi::FromInt(0));
__ Drop(1);
__ bind(&done);
}
// 3. Make sure r5 is a number.
{
Label done_convert;
__ JumpIfSmi(r5, &done_convert);
__ CompareObjectType(r5, r7, r7, HEAP_NUMBER_TYPE);
__ beq(&done_convert);
{
FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
__ Push(r4, r6);
__ mr(r3, r5);
ToNumberStub stub(masm->isolate());
__ CallStub(&stub);
__ mr(r5, r3);
__ Pop(r4, r6);
}
__ bind(&done_convert);
}
// 4. Check if new target and constructor differ.
Label new_object;
__ cmp(r4, r6);
__ bne(&new_object);
// 5. Allocate a JSValue wrapper for the number.
__ AllocateJSValue(r3, r4, r5, r7, r8, &new_object);
__ Ret();
// 6. Fallback to the runtime to create new object.
__ bind(&new_object);
{
FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
__ Push(r5, r4, r6); // first argument, constructor, new target
__ CallRuntime(Runtime::kNewObject);
__ Pop(r5);
}
__ StoreP(r5, FieldMemOperand(r3, JSValue::kValueOffset), r0);
__ Ret();
}
// static // static
void Builtins::Generate_StringConstructor(MacroAssembler* masm) { void Builtins::Generate_StringConstructor(MacroAssembler* masm) {
// ----------- S t a t e ------------- // ----------- S t a t e -------------
...@@ -203,7 +307,10 @@ void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) { ...@@ -203,7 +307,10 @@ void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) {
// -- sp[argc * 4] : receiver // -- sp[argc * 4] : receiver
// ----------------------------------- // -----------------------------------
// 1. Load the first argument into r5 and get rid of the rest (including the // 1. Make sure we operate in the context of the called function.
__ LoadP(cp, FieldMemOperand(r4, JSFunction::kContextOffset));
// 2. Load the first argument into r5 and get rid of the rest (including the
// receiver). // receiver).
{ {
Label no_arguments, done; Label no_arguments, done;
...@@ -220,7 +327,7 @@ void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) { ...@@ -220,7 +327,7 @@ void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) {
__ bind(&done); __ bind(&done);
} }
// 2. Make sure r5 is a string. // 3. Make sure r5 is a string.
{ {
Label convert, done_convert; Label convert, done_convert;
__ JumpIfSmi(r5, &convert); __ JumpIfSmi(r5, &convert);
...@@ -239,33 +346,16 @@ void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) { ...@@ -239,33 +346,16 @@ void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) {
__ bind(&done_convert); __ bind(&done_convert);
} }
// 3. Check if new target and constructor differ. // 4. Check if new target and constructor differ.
Label new_object; Label new_object;
__ cmp(r4, r6); __ cmp(r4, r6);
__ bne(&new_object); __ bne(&new_object);
// 4. Allocate a JSValue wrapper for the string. // 5. Allocate a JSValue wrapper for the string.
{ __ AllocateJSValue(r3, r4, r5, r7, r8, &new_object);
// ----------- S t a t e ------------- __ Ret();
// -- r5 : the first argument
// -- r4 : constructor function
// -- r6 : new target
// -- lr : return address
// -----------------------------------
__ Allocate(JSValue::kSize, r3, r7, r8, &new_object, TAG_OBJECT);
// Initialize the JSValue in r3.
__ LoadGlobalFunctionInitialMap(r4, r6, r7);
__ StoreP(r6, FieldMemOperand(r3, HeapObject::kMapOffset), r0);
__ LoadRoot(r6, Heap::kEmptyFixedArrayRootIndex);
__ StoreP(r6, FieldMemOperand(r3, JSObject::kPropertiesOffset), r0);
__ StoreP(r6, FieldMemOperand(r3, JSObject::kElementsOffset), r0);
__ StoreP(r5, FieldMemOperand(r3, JSValue::kValueOffset), r0);
STATIC_ASSERT(JSValue::kSize == 4 * kPointerSize);
__ Ret();
}
// 5. Fallback to the runtime to create new object. // 6. Fallback to the runtime to create new object.
__ bind(&new_object); __ bind(&new_object);
{ {
FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL); FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
......
...@@ -2767,6 +2767,28 @@ void MacroAssembler::AllocateHeapNumberWithValue( ...@@ -2767,6 +2767,28 @@ void MacroAssembler::AllocateHeapNumberWithValue(
} }
void MacroAssembler::AllocateJSValue(Register result, Register constructor,
Register value, Register scratch1,
Register scratch2, Label* gc_required) {
DCHECK(!result.is(constructor));
DCHECK(!result.is(scratch1));
DCHECK(!result.is(scratch2));
DCHECK(!result.is(value));
// Allocate JSValue in new space.
Allocate(JSValue::kSize, result, scratch1, scratch2, gc_required, TAG_OBJECT);
// Initialize the JSValue.
LoadGlobalFunctionInitialMap(constructor, scratch1, scratch2);
StoreP(scratch1, FieldMemOperand(result, HeapObject::kMapOffset), r0);
LoadRoot(scratch1, Heap::kEmptyFixedArrayRootIndex);
StoreP(scratch1, FieldMemOperand(result, JSObject::kPropertiesOffset), r0);
StoreP(scratch1, FieldMemOperand(result, JSObject::kElementsOffset), r0);
StoreP(value, FieldMemOperand(result, JSValue::kValueOffset), r0);
STATIC_ASSERT(JSValue::kSize == 4 * kPointerSize);
}
void MacroAssembler::CopyBytes(Register src, Register dst, Register length, void MacroAssembler::CopyBytes(Register src, Register dst, Register length,
Register scratch) { Register scratch) {
Label align_loop, aligned, word_loop, byte_loop, byte_loop_1, done; Label align_loop, aligned, word_loop, byte_loop, byte_loop_1, done;
......
...@@ -690,6 +690,12 @@ class MacroAssembler : public Assembler { ...@@ -690,6 +690,12 @@ class MacroAssembler : public Assembler {
Register heap_number_map, Register heap_number_map,
Label* gc_required); Label* gc_required);
// Allocate and initialize a JSValue wrapper with the specified {constructor}
// and {value}.
void AllocateJSValue(Register result, Register constructor, Register value,
Register scratch1, Register scratch2,
Label* gc_required);
// Copies a number of bytes from src to dst. All registers are clobbered. On // Copies a number of bytes from src to dst. All registers are clobbered. On
// exit src and dst will point to the place just after where the last byte was // exit src and dst will point to the place just after where the last byte was
// read or written and length will be zero. // read or written and length will be zero.
......
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