Commit 366d30c9 authored by Toon Verwaest's avatar Toon Verwaest Committed by Commit Bot

[builtins] Streamline the construct stubs

- don't restore the context register after InvokeFunction unless we need
  to for throwing exceptions.
- manually manage the frame to improve code layout for the fast path

Change-Id: Ibccb3bf604085bd470c4279d0348edcf6f18d796
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2523196
Commit-Queue: Toon Verwaest <verwaest@chromium.org>
Reviewed-by: 's avatarIgor Sheludko <ishell@chromium.org>
Cr-Commit-Position: refs/heads/master@{#71094}
parent 6c693794
......@@ -151,158 +151,155 @@ void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) {
// -- sp[...]: constructor arguments
// -----------------------------------
FrameScope scope(masm, StackFrame::MANUAL);
// Enter a construct frame.
{
FrameAndConstantPoolScope scope(masm, StackFrame::CONSTRUCT);
Label post_instantiation_deopt_entry, not_create_implicit_receiver;
// Preserve the incoming parameters on the stack.
__ LoadRoot(r4, RootIndex::kTheHoleValue);
__ SmiTag(r0);
__ Push(cp, r0, r1, r4, r3);
// ----------- S t a t e -------------
// -- sp[0*kPointerSize]: new target
// -- sp[1*kPointerSize]: padding
// -- r1 and sp[2*kPointerSize]: constructor function
// -- sp[3*kPointerSize]: number of arguments (tagged)
// -- sp[4*kPointerSize]: context
// -----------------------------------
__ ldr(r4, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
__ ldr(r4, FieldMemOperand(r4, SharedFunctionInfo::kFlagsOffset));
__ DecodeField<SharedFunctionInfo::FunctionKindBits>(r4);
__ JumpIfIsInRange(r4, kDefaultDerivedConstructor, kDerivedConstructor,
&not_create_implicit_receiver);
// If not derived class constructor: Allocate the new receiver object.
__ IncrementCounter(masm->isolate()->counters()->constructed_objects(), 1,
r4, r5);
__ Call(BUILTIN_CODE(masm->isolate(), FastNewObject),
RelocInfo::CODE_TARGET);
__ b(&post_instantiation_deopt_entry);
// Else: use TheHoleValue as receiver for constructor call
__ bind(&not_create_implicit_receiver);
__ LoadRoot(r0, RootIndex::kTheHoleValue);
// ----------- S t a t e -------------
// -- r0: receiver
// -- Slot 3 / sp[0*kPointerSize]: new target
// -- Slot 2 / sp[1*kPointerSize]: constructor function
// -- Slot 1 / sp[2*kPointerSize]: number of arguments (tagged)
// -- Slot 0 / sp[3*kPointerSize]: context
// -----------------------------------
// Deoptimizer enters here.
masm->isolate()->heap()->SetConstructStubCreateDeoptPCOffset(
masm->pc_offset());
__ bind(&post_instantiation_deopt_entry);
// Restore new target.
__ Pop(r3);
// Push the allocated receiver to the stack.
__ Push(r0);
// We need two copies because we may have to return the original one
// and the calling conventions dictate that the called function pops the
// receiver. The second copy is pushed after the arguments, we saved in r6
// since r0 needs to store the number of arguments before
// InvokingFunction.
__ mov(r6, r0);
// Set up pointer to first argument (skip receiver).
__ add(
r4, fp,
Operand(StandardFrameConstants::kCallerSPOffset + kSystemPointerSize));
Label post_instantiation_deopt_entry, not_create_implicit_receiver;
__ EnterFrame(StackFrame::CONSTRUCT);
// Restore constructor function and argument count.
__ ldr(r1, MemOperand(fp, ConstructFrameConstants::kConstructorOffset));
__ ldr(r0, MemOperand(fp, ConstructFrameConstants::kLengthOffset));
__ SmiUntag(r0);
// Preserve the incoming parameters on the stack.
__ LoadRoot(r4, RootIndex::kTheHoleValue);
__ SmiTag(r0);
__ Push(cp, r0, r1, r4, r3);
Label enough_stack_space, stack_overflow;
__ StackOverflowCheck(r0, r5, &stack_overflow);
__ b(&enough_stack_space);
// ----------- S t a t e -------------
// -- sp[0*kPointerSize]: new target
// -- sp[1*kPointerSize]: padding
// -- r1 and sp[2*kPointerSize]: constructor function
// -- sp[3*kPointerSize]: number of arguments (tagged)
// -- sp[4*kPointerSize]: context
// -----------------------------------
__ bind(&stack_overflow);
// Restore the context from the frame.
__ ldr(cp, MemOperand(fp, ConstructFrameConstants::kContextOffset));
__ CallRuntime(Runtime::kThrowStackOverflow);
// Unreachable code.
__ bkpt(0);
__ ldr(r4, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
__ ldr(r4, FieldMemOperand(r4, SharedFunctionInfo::kFlagsOffset));
__ DecodeField<SharedFunctionInfo::FunctionKindBits>(r4);
__ JumpIfIsInRange(r4, kDefaultDerivedConstructor, kDerivedConstructor,
&not_create_implicit_receiver);
__ bind(&enough_stack_space);
// If not derived class constructor: Allocate the new receiver object.
__ IncrementCounter(masm->isolate()->counters()->constructed_objects(), 1, r4,
r5);
__ Call(BUILTIN_CODE(masm->isolate(), FastNewObject), RelocInfo::CODE_TARGET);
__ b(&post_instantiation_deopt_entry);
// TODO(victorgomes): When the arguments adaptor is completely removed, we
// should get the formal parameter count and copy the arguments in its
// correct position (including any undefined), instead of delaying this to
// InvokeFunction.
// Else: use TheHoleValue as receiver for constructor call
__ bind(&not_create_implicit_receiver);
__ LoadRoot(r0, RootIndex::kTheHoleValue);
// Copy arguments to the expression stack.
__ PushArray(r4, r0, r5);
// ----------- S t a t e -------------
// -- r0: receiver
// -- Slot 3 / sp[0*kPointerSize]: new target
// -- Slot 2 / sp[1*kPointerSize]: constructor function
// -- Slot 1 / sp[2*kPointerSize]: number of arguments (tagged)
// -- Slot 0 / sp[3*kPointerSize]: context
// -----------------------------------
// Deoptimizer enters here.
masm->isolate()->heap()->SetConstructStubCreateDeoptPCOffset(
masm->pc_offset());
__ bind(&post_instantiation_deopt_entry);
// Restore new target.
__ Pop(r3);
// Push the allocated receiver to the stack.
__ Push(r0);
// We need two copies because we may have to return the original one
// and the calling conventions dictate that the called function pops the
// receiver. The second copy is pushed after the arguments, we saved in r6
// since r0 needs to store the number of arguments before
// InvokingFunction.
__ mov(r6, r0);
// Set up pointer to first argument (skip receiver).
__ add(r4, fp,
Operand(StandardFrameConstants::kCallerSPOffset + kSystemPointerSize));
// Restore constructor function and argument count.
__ ldr(r1, MemOperand(fp, ConstructFrameConstants::kConstructorOffset));
__ ldr(r0, MemOperand(fp, ConstructFrameConstants::kLengthOffset));
__ SmiUntag(r0);
// Push implicit receiver.
__ Push(r6);
Label stack_overflow;
__ StackOverflowCheck(r0, r5, &stack_overflow);
// Call the function.
__ InvokeFunctionWithNewTarget(r1, r3, r0, CALL_FUNCTION);
// TODO(victorgomes): When the arguments adaptor is completely removed, we
// should get the formal parameter count and copy the arguments in its
// correct position (including any undefined), instead of delaying this to
// InvokeFunction.
// ----------- S t a t e -------------
// -- r0: constructor result
// -- sp[0*kPointerSize]: implicit receiver
// -- sp[1*kPointerSize]: padding
// -- sp[2*kPointerSize]: constructor function
// -- sp[3*kPointerSize]: number of arguments
// -- sp[4*kPointerSize]: context
// -----------------------------------
// Copy arguments to the expression stack.
__ PushArray(r4, r0, r5);
// Store offset of return address for deoptimizer.
masm->isolate()->heap()->SetConstructStubInvokeDeoptPCOffset(
masm->pc_offset());
// Push implicit receiver.
__ Push(r6);
// Restore the context from the frame.
__ ldr(cp, MemOperand(fp, ConstructFrameConstants::kContextOffset));
// Call the function.
__ InvokeFunctionWithNewTarget(r1, r3, r0, CALL_FUNCTION);
// If the result is an object (in the ECMA sense), we should get rid
// of the receiver and use the result; see ECMA-262 section 13.2.2-7
// on page 74.
Label use_receiver, do_throw, leave_frame;
// ----------- S t a t e -------------
// -- r0: constructor result
// -- sp[0*kPointerSize]: implicit receiver
// -- sp[1*kPointerSize]: padding
// -- sp[2*kPointerSize]: constructor function
// -- sp[3*kPointerSize]: number of arguments
// -- sp[4*kPointerSize]: context
// -----------------------------------
// If the result is undefined, we jump out to using the implicit receiver.
__ JumpIfRoot(r0, RootIndex::kUndefinedValue, &use_receiver);
// Store offset of return address for deoptimizer.
masm->isolate()->heap()->SetConstructStubInvokeDeoptPCOffset(
masm->pc_offset());
// Otherwise we do a smi check and fall through to check if the return value
// is a valid receiver.
// If the result is an object (in the ECMA sense), we should get rid
// of the receiver and use the result; see ECMA-262 section 13.2.2-7
// on page 74.
Label use_receiver, do_throw, leave_and_return, check_receiver;
// If the result is a smi, it is *not* an object in the ECMA sense.
__ JumpIfSmi(r0, &use_receiver);
// If the result is undefined, we jump out to using the implicit receiver.
__ JumpIfNotRoot(r0, RootIndex::kUndefinedValue, &check_receiver);
// If the type of the result (stored in its map) is less than
// FIRST_JS_RECEIVER_TYPE, it is not an object in the ECMA sense.
STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
__ CompareObjectType(r0, r4, r5, FIRST_JS_RECEIVER_TYPE);
__ b(ge, &leave_frame);
__ b(&use_receiver);
// Otherwise we do a smi check and fall through to check if the return value
// is a valid receiver.
__ bind(&do_throw);
__ CallRuntime(Runtime::kThrowConstructorReturnedNonObject);
// Throw away the result of the constructor invocation and use the
// on-stack receiver as the result.
__ bind(&use_receiver);
__ ldr(r0, MemOperand(sp, 0 * kPointerSize));
__ JumpIfRoot(r0, RootIndex::kTheHoleValue, &do_throw);
// Throw away the result of the constructor invocation and use the
// on-stack receiver as the result.
__ bind(&use_receiver);
__ ldr(r0, MemOperand(sp, 0 * kPointerSize));
__ JumpIfRoot(r0, RootIndex::kTheHoleValue, &do_throw);
__ bind(&leave_and_return);
// Restore smi-tagged arguments count from the frame.
__ ldr(r1, MemOperand(fp, ConstructFrameConstants::kLengthOffset));
// Leave construct frame.
__ LeaveFrame(StackFrame::CONSTRUCT);
__ bind(&leave_frame);
// Restore smi-tagged arguments count from the frame.
__ ldr(r1, MemOperand(fp, ConstructFrameConstants::kLengthOffset));
// Leave construct frame.
}
// Remove caller arguments from the stack and return.
STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
__ add(sp, sp, Operand(r1, LSL, kPointerSizeLog2 - kSmiTagSize));
__ add(sp, sp, Operand(kPointerSize));
__ Jump(lr);
__ bind(&check_receiver);
// If the result is a smi, it is *not* an object in the ECMA sense.
__ JumpIfSmi(r0, &use_receiver);
// If the type of the result (stored in its map) is less than
// FIRST_JS_RECEIVER_TYPE, it is not an object in the ECMA sense.
STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
__ CompareObjectType(r0, r4, r5, FIRST_JS_RECEIVER_TYPE);
__ b(ge, &leave_and_return);
__ b(&use_receiver);
__ bind(&do_throw);
// Restore the context from the frame.
__ ldr(cp, MemOperand(fp, ConstructFrameConstants::kContextOffset));
__ CallRuntime(Runtime::kThrowConstructorReturnedNonObject);
__ bkpt(0);
__ bind(&stack_overflow);
// Restore the context from the frame.
__ ldr(cp, MemOperand(fp, ConstructFrameConstants::kContextOffset));
__ CallRuntime(Runtime::kThrowStackOverflow);
// Unreachable code.
__ bkpt(0);
}
void Builtins::Generate_JSBuiltinsConstructStub(MacroAssembler* masm) {
......
......@@ -210,194 +210,192 @@ void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) {
ASM_LOCATION("Builtins::Generate_JSConstructStubGeneric");
FrameScope scope(masm, StackFrame::MANUAL);
// Enter a construct frame.
{
FrameScope scope(masm, StackFrame::CONSTRUCT);
Label post_instantiation_deopt_entry, not_create_implicit_receiver;
__ EnterFrame(StackFrame::CONSTRUCT);
Label post_instantiation_deopt_entry, not_create_implicit_receiver;
if (__ emit_debug_code()) {
// Check that FrameScope pushed the context on to the stack already.
__ Peek(x2, 0);
__ Cmp(x2, cp);
__ Check(eq, AbortReason::kUnexpectedValue);
}
// Preserve the incoming parameters on the stack.
__ SmiTag(x0);
__ Push(x0, x1, padreg, x3);
// ----------- S t a t e -------------
// -- sp[0*kSystemPointerSize]: new target
// -- sp[1*kSystemPointerSize]: padding
// -- x1 and sp[2*kSystemPointerSize]: constructor function
// -- sp[3*kSystemPointerSize]: number of arguments (tagged)
// -- sp[4*kSystemPointerSize]: context (pushed by FrameScope)
// -----------------------------------
__ LoadTaggedPointerField(
x4, FieldMemOperand(x1, JSFunction::kSharedFunctionInfoOffset));
__ Ldr(w4, FieldMemOperand(x4, SharedFunctionInfo::kFlagsOffset));
__ DecodeField<SharedFunctionInfo::FunctionKindBits>(w4);
__ JumpIfIsInRange(w4, kDefaultDerivedConstructor, kDerivedConstructor,
&not_create_implicit_receiver);
// If not derived class constructor: Allocate the new receiver object.
__ IncrementCounter(masm->isolate()->counters()->constructed_objects(), 1,
x4, x5);
if (__ emit_debug_code()) {
// Check that FrameScope pushed the context on to the stack already.
__ Peek(x2, 0);
__ Cmp(x2, cp);
__ Check(eq, AbortReason::kUnexpectedValue);
}
__ Call(BUILTIN_CODE(masm->isolate(), FastNewObject),
RelocInfo::CODE_TARGET);
// Preserve the incoming parameters on the stack.
__ SmiTag(x0);
__ Push(x0, x1, padreg, x3);
__ B(&post_instantiation_deopt_entry);
// ----------- S t a t e -------------
// -- sp[0*kSystemPointerSize]: new target
// -- sp[1*kSystemPointerSize]: padding
// -- x1 and sp[2*kSystemPointerSize]: constructor function
// -- sp[3*kSystemPointerSize]: number of arguments (tagged)
// -- sp[4*kSystemPointerSize]: context (pushed by FrameScope)
// -----------------------------------
// Else: use TheHoleValue as receiver for constructor call
__ Bind(&not_create_implicit_receiver);
__ LoadRoot(x0, RootIndex::kTheHoleValue);
__ LoadTaggedPointerField(
x4, FieldMemOperand(x1, JSFunction::kSharedFunctionInfoOffset));
__ Ldr(w4, FieldMemOperand(x4, SharedFunctionInfo::kFlagsOffset));
__ DecodeField<SharedFunctionInfo::FunctionKindBits>(w4);
__ JumpIfIsInRange(w4, kDefaultDerivedConstructor, kDerivedConstructor,
&not_create_implicit_receiver);
// ----------- S t a t e -------------
// -- x0: receiver
// -- Slot 4 / sp[0*kSystemPointerSize]: new target
// -- Slot 3 / sp[1*kSystemPointerSize]: padding
// -- Slot 2 / sp[2*kSystemPointerSize]: constructor function
// -- Slot 1 / sp[3*kSystemPointerSize]: number of arguments (tagged)
// -- Slot 0 / sp[4*kSystemPointerSize]: context
// -----------------------------------
// Deoptimizer enters here.
masm->isolate()->heap()->SetConstructStubCreateDeoptPCOffset(
masm->pc_offset());
// If not derived class constructor: Allocate the new receiver object.
__ IncrementCounter(masm->isolate()->counters()->constructed_objects(), 1, x4,
x5);
__ Bind(&post_instantiation_deopt_entry);
__ Call(BUILTIN_CODE(masm->isolate(), FastNewObject), RelocInfo::CODE_TARGET);
// Restore new target from the top of the stack.
__ Peek(x3, 0 * kSystemPointerSize);
__ B(&post_instantiation_deopt_entry);
// Restore constructor function and argument count.
__ Ldr(x1, MemOperand(fp, ConstructFrameConstants::kConstructorOffset));
__ SmiUntag(x12, MemOperand(fp, ConstructFrameConstants::kLengthOffset));
// Else: use TheHoleValue as receiver for constructor call
__ Bind(&not_create_implicit_receiver);
__ LoadRoot(x0, RootIndex::kTheHoleValue);
// Copy arguments to the expression stack. The called function pops the
// receiver along with its arguments, so we need an extra receiver on the
// stack, in case we have to return it later.
// ----------- S t a t e -------------
// -- x0: receiver
// -- Slot 4 / sp[0*kSystemPointerSize]: new target
// -- Slot 3 / sp[1*kSystemPointerSize]: padding
// -- Slot 2 / sp[2*kSystemPointerSize]: constructor function
// -- Slot 1 / sp[3*kSystemPointerSize]: number of arguments (tagged)
// -- Slot 0 / sp[4*kSystemPointerSize]: context
// -----------------------------------
// Deoptimizer enters here.
masm->isolate()->heap()->SetConstructStubCreateDeoptPCOffset(
masm->pc_offset());
// Overwrite the new target with a receiver.
__ Poke(x0, 0);
__ Bind(&post_instantiation_deopt_entry);
// Push two further copies of the receiver. One will be popped by the called
// function. The second acts as padding if the number of arguments plus
// receiver is odd - pushing receiver twice avoids branching. It also means
// that we don't have to handle the even and odd cases specially on
// InvokeFunction's return, as top of stack will be the receiver in either
// case.
__ Push(x0, x0);
// Restore new target from the top of the stack.
__ Peek(x3, 0 * kSystemPointerSize);
// ----------- S t a t e -------------
// -- x3: new target
// -- x12: number of arguments (untagged)
// -- sp[0*kSystemPointerSize]: implicit receiver (overwrite if argc
// odd)
// -- sp[1*kSystemPointerSize]: implicit receiver
// -- sp[2*kSystemPointerSize]: implicit receiver
// -- sp[3*kSystemPointerSize]: padding
// -- x1 and sp[4*kSystemPointerSize]: constructor function
// -- sp[5*kSystemPointerSize]: number of arguments (tagged)
// -- sp[6*kSystemPointerSize]: context
// -----------------------------------
// Restore constructor function and argument count.
__ Ldr(x1, MemOperand(fp, ConstructFrameConstants::kConstructorOffset));
__ SmiUntag(x12, MemOperand(fp, ConstructFrameConstants::kLengthOffset));
// Round the number of arguments down to the next even number, and claim
// slots for the arguments. If the number of arguments was odd, the last
// argument will overwrite one of the receivers pushed above.
__ Bic(x10, x12, 1);
// Copy arguments to the expression stack. The called function pops the
// receiver along with its arguments, so we need an extra receiver on the
// stack, in case we have to return it later.
// Check if we have enough stack space to push all arguments.
Label enough_stack_space, stack_overflow;
__ StackOverflowCheck(x10, &stack_overflow);
__ B(&enough_stack_space);
// Overwrite the new target with a receiver.
__ Poke(x0, 0);
__ Bind(&stack_overflow);
// Restore the context from the frame.
__ Ldr(cp, MemOperand(fp, ConstructFrameConstants::kContextOffset));
__ CallRuntime(Runtime::kThrowStackOverflow);
__ Unreachable();
// Push two further copies of the receiver. One will be popped by the called
// function. The second acts as padding if the number of arguments plus
// receiver is odd - pushing receiver twice avoids branching. It also means
// that we don't have to handle the even and odd cases specially on
// InvokeFunction's return, as top of stack will be the receiver in either
// case.
__ Push(x0, x0);
__ Bind(&enough_stack_space);
__ Claim(x10);
// TODO(victorgomes): When the arguments adaptor is completely removed, we
// should get the formal parameter count and copy the arguments in its
// correct position (including any undefined), instead of delaying this to
// InvokeFunction.
// Copy the arguments.
{
Register count = x2;
Register dst = x10;
Register src = x11;
__ Mov(count, x12);
__ Poke(x0, 0); // Add the receiver.
__ SlotAddress(dst, 1); // Skip receiver.
__ Add(src, fp,
StandardFrameConstants::kCallerSPOffset + kSystemPointerSize);
__ CopyDoubleWords(dst, src, count);
}
// ----------- S t a t e -------------
// -- x3: new target
// -- x12: number of arguments (untagged)
// -- sp[0*kSystemPointerSize]: implicit receiver (overwrite if argc
// odd)
// -- sp[1*kSystemPointerSize]: implicit receiver
// -- sp[2*kSystemPointerSize]: implicit receiver
// -- sp[3*kSystemPointerSize]: padding
// -- x1 and sp[4*kSystemPointerSize]: constructor function
// -- sp[5*kSystemPointerSize]: number of arguments (tagged)
// -- sp[6*kSystemPointerSize]: context
// -----------------------------------
// Call the function.
__ Mov(x0, x12);
__ InvokeFunctionWithNewTarget(x1, x3, x0, CALL_FUNCTION);
// Round the number of arguments down to the next even number, and claim
// slots for the arguments. If the number of arguments was odd, the last
// argument will overwrite one of the receivers pushed above.
__ Bic(x10, x12, 1);
// ----------- S t a t e -------------
// -- sp[0*kSystemPointerSize]: implicit receiver
// -- sp[1*kSystemPointerSize]: padding
// -- sp[2*kSystemPointerSize]: constructor function
// -- sp[3*kSystemPointerSize]: number of arguments
// -- sp[4*kSystemPointerSize]: context
// -----------------------------------
// Check if we have enough stack space to push all arguments.
Label stack_overflow;
__ StackOverflowCheck(x10, &stack_overflow);
__ Claim(x10);
// Store offset of return address for deoptimizer.
masm->isolate()->heap()->SetConstructStubInvokeDeoptPCOffset(
masm->pc_offset());
// TODO(victorgomes): When the arguments adaptor is completely removed, we
// should get the formal parameter count and copy the arguments in its
// correct position (including any undefined), instead of delaying this to
// InvokeFunction.
// Restore the context from the frame.
__ Ldr(cp, MemOperand(fp, ConstructFrameConstants::kContextOffset));
// Copy the arguments.
{
Register count = x2;
Register dst = x10;
Register src = x11;
__ Mov(count, x12);
__ Poke(x0, 0); // Add the receiver.
__ SlotAddress(dst, 1); // Skip receiver.
__ Add(src, fp,
StandardFrameConstants::kCallerSPOffset + kSystemPointerSize);
__ CopyDoubleWords(dst, src, count);
}
// If the result is an object (in the ECMA sense), we should get rid
// of the receiver and use the result; see ECMA-262 section 13.2.2-7
// on page 74.
Label use_receiver, do_throw, leave_frame;
// Call the function.
__ Mov(x0, x12);
__ InvokeFunctionWithNewTarget(x1, x3, x0, CALL_FUNCTION);
// If the result is undefined, we jump out to using the implicit receiver.
__ CompareRoot(x0, RootIndex::kUndefinedValue);
__ B(eq, &use_receiver);
// ----------- S t a t e -------------
// -- sp[0*kSystemPointerSize]: implicit receiver
// -- sp[1*kSystemPointerSize]: padding
// -- sp[2*kSystemPointerSize]: constructor function
// -- sp[3*kSystemPointerSize]: number of arguments
// -- sp[4*kSystemPointerSize]: context
// -----------------------------------
// Otherwise we do a smi check and fall through to check if the return value
// is a valid receiver.
// Store offset of return address for deoptimizer.
masm->isolate()->heap()->SetConstructStubInvokeDeoptPCOffset(
masm->pc_offset());
// If the result is an object (in the ECMA sense), we should get rid
// of the receiver and use the result; see ECMA-262 section 13.2.2-7
// on page 74.
Label use_receiver, do_throw, leave_and_return, check_receiver;
// If the result is undefined, we jump out to using the implicit receiver.
__ CompareRoot(x0, RootIndex::kUndefinedValue);
__ B(ne, &check_receiver);
// Throw away the result of the constructor invocation and use the
// on-stack receiver as the result.
__ Bind(&use_receiver);
__ Peek(x0, 0 * kSystemPointerSize);
__ CompareRoot(x0, RootIndex::kTheHoleValue);
__ B(eq, &do_throw);
__ Bind(&leave_and_return);
// Restore smi-tagged arguments count from the frame.
__ SmiUntag(x1, MemOperand(fp, ConstructFrameConstants::kLengthOffset));
// Leave construct frame.
__ LeaveFrame(StackFrame::CONSTRUCT);
// Remove caller arguments from the stack and return.
__ DropArguments(x1, TurboAssembler::kCountExcludesReceiver);
__ Ret();
// If the result is a smi, it is *not* an object in the ECMA sense.
__ JumpIfSmi(x0, &use_receiver);
// Otherwise we do a smi check and fall through to check if the return value
// is a valid receiver.
__ bind(&check_receiver);
// If the type of the result (stored in its map) is less than
// FIRST_JS_RECEIVER_TYPE, it is not an object in the ECMA sense.
STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
__ JumpIfObjectType(x0, x4, x5, FIRST_JS_RECEIVER_TYPE, &leave_frame, ge);
__ B(&use_receiver);
// If the result is a smi, it is *not* an object in the ECMA sense.
__ JumpIfSmi(x0, &use_receiver);
__ Bind(&do_throw);
__ CallRuntime(Runtime::kThrowConstructorReturnedNonObject);
// If the type of the result (stored in its map) is less than
// FIRST_JS_RECEIVER_TYPE, it is not an object in the ECMA sense.
STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
__ JumpIfObjectType(x0, x4, x5, FIRST_JS_RECEIVER_TYPE, &leave_and_return,
ge);
__ B(&use_receiver);
// Throw away the result of the constructor invocation and use the
// on-stack receiver as the result.
__ Bind(&use_receiver);
__ Peek(x0, 0 * kSystemPointerSize);
__ CompareRoot(x0, RootIndex::kTheHoleValue);
__ B(eq, &do_throw);
__ Bind(&do_throw);
// Restore the context from the frame.
__ Ldr(cp, MemOperand(fp, ConstructFrameConstants::kContextOffset));
__ CallRuntime(Runtime::kThrowConstructorReturnedNonObject);
__ Unreachable();
__ Bind(&leave_frame);
// Restore smi-tagged arguments count from the frame.
__ SmiUntag(x1, MemOperand(fp, ConstructFrameConstants::kLengthOffset));
// Leave construct frame.
}
// Remove caller arguments from the stack and return.
__ DropArguments(x1, TurboAssembler::kCountExcludesReceiver);
__ Ret();
__ Bind(&stack_overflow);
// Restore the context from the frame.
__ Ldr(cp, MemOperand(fp, ConstructFrameConstants::kContextOffset));
__ CallRuntime(Runtime::kThrowStackOverflow);
__ Unreachable();
}
void Builtins::Generate_JSBuiltinsConstructStub(MacroAssembler* masm) {
Generate_JSBuiltinsConstructStubHelper(masm);
......
......@@ -150,161 +150,133 @@ void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) {
// -- sp[...]: constructor arguments
// -----------------------------------
FrameScope scope(masm, StackFrame::MANUAL);
// Enter a construct frame.
{
FrameScope scope(masm, StackFrame::CONSTRUCT);
Label post_instantiation_deopt_entry, not_create_implicit_receiver;
// Preserve the incoming parameters on the stack.
__ mov(ecx, eax);
__ SmiTag(ecx);
__ Push(esi);
__ Push(ecx);
__ Push(edi);
__ PushRoot(RootIndex::kTheHoleValue);
__ Push(edx);
__ EnterFrame(StackFrame::CONSTRUCT);
// ----------- S t a t e -------------
// -- sp[0*kSystemPointerSize]: new target
// -- sp[1*kSystemPointerSize]: padding
// -- edi and sp[2*kSystemPointerSize]: constructor function
// -- sp[3*kSystemPointerSize]: argument count
// -- sp[4*kSystemPointerSize]: context
// -----------------------------------
__ mov(eax, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
__ mov(eax, FieldOperand(eax, SharedFunctionInfo::kFlagsOffset));
__ DecodeField<SharedFunctionInfo::FunctionKindBits>(eax);
__ JumpIfIsInRange(eax, kDefaultDerivedConstructor, kDerivedConstructor,
ecx, &not_create_implicit_receiver, Label::kNear);
// If not derived class constructor: Allocate the new receiver object.
__ IncrementCounter(masm->isolate()->counters()->constructed_objects(), 1,
eax);
__ Call(BUILTIN_CODE(masm->isolate(), FastNewObject),
RelocInfo::CODE_TARGET);
__ jmp(&post_instantiation_deopt_entry, Label::kNear);
// Else: use TheHoleValue as receiver for constructor call
__ bind(&not_create_implicit_receiver);
__ LoadRoot(eax, RootIndex::kTheHoleValue);
// ----------- S t a t e -------------
// -- eax: implicit receiver
// -- Slot 4 / sp[0*kSystemPointerSize]: new target
// -- Slot 3 / sp[1*kSystemPointerSize]: padding
// -- Slot 2 / sp[2*kSystemPointerSize]: constructor function
// -- Slot 1 / sp[3*kSystemPointerSize]: number of arguments (tagged)
// -- Slot 0 / sp[4*kSystemPointerSize]: context
// -----------------------------------
// Deoptimizer enters here.
masm->isolate()->heap()->SetConstructStubCreateDeoptPCOffset(
masm->pc_offset());
__ bind(&post_instantiation_deopt_entry);
Label post_instantiation_deopt_entry, not_create_implicit_receiver;
// Restore new target.
__ Pop(edx);
// Preserve the incoming parameters on the stack.
__ mov(ecx, eax);
__ SmiTag(ecx);
__ Push(esi);
__ Push(ecx);
__ Push(edi);
__ PushRoot(RootIndex::kTheHoleValue);
__ Push(edx);
// Push the allocated receiver to the stack.
__ Push(eax);
// ----------- S t a t e -------------
// -- sp[0*kSystemPointerSize]: new target
// -- sp[1*kSystemPointerSize]: padding
// -- edi and sp[2*kSystemPointerSize]: constructor function
// -- sp[3*kSystemPointerSize]: argument count
// -- sp[4*kSystemPointerSize]: context
// -----------------------------------
// We need two copies because we may have to return the original one
// and the calling conventions dictate that the called function pops the
// receiver. The second copy is pushed after the arguments, we saved in r8
// since rax needs to store the number of arguments before
// InvokingFunction.
__ movd(xmm0, eax);
__ mov(eax, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
__ mov(eax, FieldOperand(eax, SharedFunctionInfo::kFlagsOffset));
__ DecodeField<SharedFunctionInfo::FunctionKindBits>(eax);
__ JumpIfIsInRange(eax, kDefaultDerivedConstructor, kDerivedConstructor, ecx,
&not_create_implicit_receiver, Label::kNear);
// Set up pointer to first argument (skip receiver).
__ lea(edi, Operand(ebp, StandardFrameConstants::kCallerSPOffset +
kSystemPointerSize));
// If not derived class constructor: Allocate the new receiver object.
__ IncrementCounter(masm->isolate()->counters()->constructed_objects(), 1,
eax);
__ Call(BUILTIN_CODE(masm->isolate(), FastNewObject), RelocInfo::CODE_TARGET);
__ jmp(&post_instantiation_deopt_entry, Label::kNear);
// Restore argument count.
__ mov(eax, Operand(ebp, ConstructFrameConstants::kLengthOffset));
__ SmiUntag(eax);
// Else: use TheHoleValue as receiver for constructor call
__ bind(&not_create_implicit_receiver);
__ LoadRoot(eax, RootIndex::kTheHoleValue);
// Check if we have enough stack space to push all arguments.
// Argument count in eax. Clobbers ecx.
Label enough_stack_space, stack_overflow;
__ StackOverflowCheck(eax, ecx, &stack_overflow);
__ jmp(&enough_stack_space);
// ----------- S t a t e -------------
// -- eax: implicit receiver
// -- Slot 4 / sp[0*kSystemPointerSize]: new target
// -- Slot 3 / sp[1*kSystemPointerSize]: padding
// -- Slot 2 / sp[2*kSystemPointerSize]: constructor function
// -- Slot 1 / sp[3*kSystemPointerSize]: number of arguments (tagged)
// -- Slot 0 / sp[4*kSystemPointerSize]: context
// -----------------------------------
// Deoptimizer enters here.
masm->isolate()->heap()->SetConstructStubCreateDeoptPCOffset(
masm->pc_offset());
__ bind(&post_instantiation_deopt_entry);
__ bind(&stack_overflow);
// Restore context from the frame.
__ mov(esi, Operand(ebp, ConstructFrameConstants::kContextOffset));
__ CallRuntime(Runtime::kThrowStackOverflow);
// This should be unreachable.
__ int3();
// Restore new target.
__ Pop(edx);
__ bind(&enough_stack_space);
// Push the allocated receiver to the stack.
__ Push(eax);
// TODO(victorgomes): When the arguments adaptor is completely removed, we
// should get the formal parameter count and copy the arguments in its
// correct position (including any undefined), instead of delaying this to
// InvokeFunction.
// We need two copies because we may have to return the original one
// and the calling conventions dictate that the called function pops the
// receiver. The second copy is pushed after the arguments, we saved in r8
// since rax needs to store the number of arguments before
// InvokingFunction.
__ movd(xmm0, eax);
// Copy arguments to the expression stack.
__ PushArray(edi, eax, ecx);
// Set up pointer to first argument (skip receiver).
__ lea(edi, Operand(ebp, StandardFrameConstants::kCallerSPOffset +
kSystemPointerSize));
// Push implicit receiver.
__ movd(ecx, xmm0);
__ Push(ecx);
// Restore argument count.
__ mov(eax, Operand(ebp, ConstructFrameConstants::kLengthOffset));
__ SmiUntag(eax);
// Restore and and call the constructor function.
__ mov(edi, Operand(ebp, ConstructFrameConstants::kConstructorOffset));
__ InvokeFunction(edi, edx, eax, CALL_FUNCTION);
// Check if we have enough stack space to push all arguments.
// Argument count in eax. Clobbers ecx.
Label stack_overflow;
__ StackOverflowCheck(eax, ecx, &stack_overflow);
// ----------- S t a t e -------------
// -- eax: constructor result
// -- sp[0*kSystemPointerSize]: implicit receiver
// -- sp[1*kSystemPointerSize]: padding
// -- sp[2*kSystemPointerSize]: constructor function
// -- sp[3*kSystemPointerSize]: number of arguments
// -- sp[4*kSystemPointerSize]: context
// -----------------------------------
// TODO(victorgomes): When the arguments adaptor is completely removed, we
// should get the formal parameter count and copy the arguments in its
// correct position (including any undefined), instead of delaying this to
// InvokeFunction.
// Store offset of return address for deoptimizer.
masm->isolate()->heap()->SetConstructStubInvokeDeoptPCOffset(
masm->pc_offset());
// Copy arguments to the expression stack.
__ PushArray(edi, eax, ecx);
// Restore context from the frame.
__ mov(esi, Operand(ebp, ConstructFrameConstants::kContextOffset));
// Push implicit receiver.
__ movd(ecx, xmm0);
__ Push(ecx);
// If the result is an object (in the ECMA sense), we should get rid
// of the receiver and use the result; see ECMA-262 section 13.2.2-7
// on page 74.
Label use_receiver, do_throw, leave_frame;
// Restore and and call the constructor function.
__ mov(edi, Operand(ebp, ConstructFrameConstants::kConstructorOffset));
__ InvokeFunction(edi, edx, eax, CALL_FUNCTION);
// If the result is undefined, we jump out to using the implicit receiver.
__ JumpIfRoot(eax, RootIndex::kUndefinedValue, &use_receiver, Label::kNear);
// ----------- S t a t e -------------
// -- eax: constructor result
// -- sp[0*kSystemPointerSize]: implicit receiver
// -- sp[1*kSystemPointerSize]: padding
// -- sp[2*kSystemPointerSize]: constructor function
// -- sp[3*kSystemPointerSize]: number of arguments
// -- sp[4*kSystemPointerSize]: context
// -----------------------------------
// Otherwise we do a smi check and fall through to check if the return value
// is a valid receiver.
// Store offset of return address for deoptimizer.
masm->isolate()->heap()->SetConstructStubInvokeDeoptPCOffset(
masm->pc_offset());
// If the result is a smi, it is *not* an object in the ECMA sense.
__ JumpIfSmi(eax, &use_receiver, Label::kNear);
// If the result is an object (in the ECMA sense), we should get rid
// of the receiver and use the result; see ECMA-262 section 13.2.2-7
// on page 74.
// If the type of the result (stored in its map) is less than
// FIRST_JS_RECEIVER_TYPE, it is not an object in the ECMA sense.
STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
__ CmpObjectType(eax, FIRST_JS_RECEIVER_TYPE, ecx);
__ j(above_equal, &leave_frame, Label::kNear);
__ jmp(&use_receiver, Label::kNear);
Label check_result, use_receiver, do_throw, leave_and_return;
// If the result is undefined, we jump out to using the implicit receiver.
__ JumpIfNotRoot(eax, RootIndex::kUndefinedValue, &check_result,
Label::kNear);
__ bind(&do_throw);
__ CallRuntime(Runtime::kThrowConstructorReturnedNonObject);
// Throw away the result of the constructor invocation and use the
// on-stack receiver as the result.
__ bind(&use_receiver);
__ mov(eax, Operand(esp, 0 * kSystemPointerSize));
__ JumpIfRoot(eax, RootIndex::kTheHoleValue, &do_throw);
// Throw away the result of the constructor invocation and use the
// on-stack receiver as the result.
__ bind(&use_receiver);
__ mov(eax, Operand(esp, 0 * kSystemPointerSize));
__ JumpIfRoot(eax, RootIndex::kTheHoleValue, &do_throw);
__ bind(&leave_and_return);
// Restore smi-tagged arguments count from the frame.
__ mov(edx, Operand(ebp, ConstructFrameConstants::kLengthOffset));
__ LeaveFrame(StackFrame::CONSTRUCT);
__ bind(&leave_frame);
// Restore smi-tagged arguments count from the frame.
__ mov(edx, Operand(ebp, ConstructFrameConstants::kLengthOffset));
// Leave construct frame.
}
// Remove caller arguments from the stack and return.
STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
__ pop(ecx);
......@@ -312,6 +284,34 @@ void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) {
1 * kSystemPointerSize)); // 1 ~ receiver
__ push(ecx);
__ ret(0);
// Otherwise we do a smi check and fall through to check if the return value
// is a valid receiver.
__ bind(&check_result);
// If the result is a smi, it is *not* an object in the ECMA sense.
__ JumpIfSmi(eax, &use_receiver, Label::kNear);
// If the type of the result (stored in its map) is less than
// FIRST_JS_RECEIVER_TYPE, it is not an object in the ECMA sense.
STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
__ CmpObjectType(eax, FIRST_JS_RECEIVER_TYPE, ecx);
__ j(above_equal, &leave_and_return, Label::kNear);
__ jmp(&use_receiver, Label::kNear);
__ bind(&do_throw);
// Restore context from the frame.
__ mov(esi, Operand(ebp, ConstructFrameConstants::kContextOffset));
__ CallRuntime(Runtime::kThrowConstructorReturnedNonObject);
// This should be unreachable.
__ int3();
__ bind(&stack_overflow);
// Restore context from the frame.
__ mov(esi, Operand(ebp, ConstructFrameConstants::kContextOffset));
__ CallRuntime(Runtime::kThrowStackOverflow);
// This should be unreachable.
__ int3();
}
void Builtins::Generate_JSBuiltinsConstructStub(MacroAssembler* masm) {
......
......@@ -114,8 +114,6 @@ void Generate_JSBuiltinsConstructStubHelper(MacroAssembler* masm) {
// rdx: new target
__ InvokeFunction(rdi, rdx, rax, CALL_FUNCTION);
// Restore context from the frame.
__ movq(rsi, Operand(rbp, ConstructFrameConstants::kContextOffset));
// Restore smi-tagged arguments count from the frame.
__ movq(rbx, Operand(rbp, ConstructFrameConstants::kLengthOffset));
......@@ -150,164 +148,161 @@ void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) {
// -- sp[...]: constructor arguments
// -----------------------------------
FrameScope scope(masm, StackFrame::MANUAL);
// Enter a construct frame.
{
FrameScope scope(masm, StackFrame::CONSTRUCT);
Label post_instantiation_deopt_entry, not_create_implicit_receiver;
// Preserve the incoming parameters on the stack.
__ SmiTag(rcx, rax);
__ Push(rsi);
__ Push(rcx);
__ Push(rdi);
__ PushRoot(RootIndex::kTheHoleValue);
__ Push(rdx);
// ----------- S t a t e -------------
// -- sp[0*kSystemPointerSize]: new target
// -- sp[1*kSystemPointerSize]: padding
// -- rdi and sp[2*kSystemPointerSize]: constructor function
// -- sp[3*kSystemPointerSize]: argument count
// -- sp[4*kSystemPointerSize]: context
// -----------------------------------
__ LoadTaggedPointerField(
rbx, FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset));
__ movl(rbx, FieldOperand(rbx, SharedFunctionInfo::kFlagsOffset));
__ DecodeField<SharedFunctionInfo::FunctionKindBits>(rbx);
__ JumpIfIsInRange(rbx, kDefaultDerivedConstructor, kDerivedConstructor,
&not_create_implicit_receiver, Label::kNear);
// If not derived class constructor: Allocate the new receiver object.
__ IncrementCounter(masm->isolate()->counters()->constructed_objects(), 1);
__ Call(BUILTIN_CODE(masm->isolate(), FastNewObject),
RelocInfo::CODE_TARGET);
__ jmp(&post_instantiation_deopt_entry, Label::kNear);
// Else: use TheHoleValue as receiver for constructor call
__ bind(&not_create_implicit_receiver);
__ LoadRoot(rax, RootIndex::kTheHoleValue);
// ----------- S t a t e -------------
// -- rax implicit receiver
// -- Slot 4 / sp[0*kSystemPointerSize] new target
// -- Slot 3 / sp[1*kSystemPointerSize] padding
// -- Slot 2 / sp[2*kSystemPointerSize] constructor function
// -- Slot 1 / sp[3*kSystemPointerSize] number of arguments (tagged)
// -- Slot 0 / sp[4*kSystemPointerSize] context
// -----------------------------------
// Deoptimizer enters here.
masm->isolate()->heap()->SetConstructStubCreateDeoptPCOffset(
masm->pc_offset());
__ bind(&post_instantiation_deopt_entry);
// Restore new target.
__ Pop(rdx);
// Push the allocated receiver to the stack.
__ Push(rax);
// We need two copies because we may have to return the original one
// and the calling conventions dictate that the called function pops the
// receiver. The second copy is pushed after the arguments, we saved in r8
// since rax needs to store the number of arguments before
// InvokingFunction.
__ movq(r8, rax);
// Set up pointer to first argument (skip receiver).
__ leaq(rbx, Operand(rbp, StandardFrameConstants::kCallerSPOffset +
kSystemPointerSize));
// Restore constructor function and argument count.
__ movq(rdi, Operand(rbp, ConstructFrameConstants::kConstructorOffset));
__ SmiUntag(rax, Operand(rbp, ConstructFrameConstants::kLengthOffset));
__ EnterFrame(StackFrame::CONSTRUCT);
Label post_instantiation_deopt_entry, not_create_implicit_receiver;
// Check if we have enough stack space to push all arguments.
// Argument count in rax. Clobbers rcx.
Label enough_stack_space, stack_overflow;
__ StackOverflowCheck(rax, rcx, &stack_overflow, Label::kNear);
__ jmp(&enough_stack_space, Label::kNear);
__ bind(&stack_overflow);
// Restore context from the frame.
__ movq(rsi, Operand(rbp, ConstructFrameConstants::kContextOffset));
__ CallRuntime(Runtime::kThrowStackOverflow);
// This should be unreachable.
__ int3();
__ bind(&enough_stack_space);
// TODO(victorgomes): When the arguments adaptor is completely removed, we
// should get the formal parameter count and copy the arguments in its
// correct position (including any undefined), instead of delaying this to
// InvokeFunction.
// Copy arguments to the expression stack.
__ PushArray(rbx, rax, rcx);
// Push implicit receiver.
__ Push(r8);
// Call the function.
__ InvokeFunction(rdi, rdx, rax, CALL_FUNCTION);
// Preserve the incoming parameters on the stack.
__ SmiTag(rcx, rax);
__ Push(rsi);
__ Push(rcx);
__ Push(rdi);
__ PushRoot(RootIndex::kTheHoleValue);
__ Push(rdx);
// ----------- S t a t e -------------
// -- rax constructor result
// -- sp[0*kSystemPointerSize] implicit receiver
// -- sp[1*kSystemPointerSize] padding
// -- sp[2*kSystemPointerSize] constructor function
// -- sp[3*kSystemPointerSize] number of arguments
// -- sp[4*kSystemPointerSize] context
// -----------------------------------
// ----------- S t a t e -------------
// -- sp[0*kSystemPointerSize]: new target
// -- sp[1*kSystemPointerSize]: padding
// -- rdi and sp[2*kSystemPointerSize]: constructor function
// -- sp[3*kSystemPointerSize]: argument count
// -- sp[4*kSystemPointerSize]: context
// -----------------------------------
// Store offset of return address for deoptimizer.
masm->isolate()->heap()->SetConstructStubInvokeDeoptPCOffset(
masm->pc_offset());
__ LoadTaggedPointerField(
rbx, FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset));
__ movl(rbx, FieldOperand(rbx, SharedFunctionInfo::kFlagsOffset));
__ DecodeField<SharedFunctionInfo::FunctionKindBits>(rbx);
__ JumpIfIsInRange(rbx, kDefaultDerivedConstructor, kDerivedConstructor,
&not_create_implicit_receiver, Label::kNear);
// Restore context from the frame.
__ movq(rsi, Operand(rbp, ConstructFrameConstants::kContextOffset));
// If not derived class constructor: Allocate the new receiver object.
__ IncrementCounter(masm->isolate()->counters()->constructed_objects(), 1);
__ Call(BUILTIN_CODE(masm->isolate(), FastNewObject), RelocInfo::CODE_TARGET);
__ jmp(&post_instantiation_deopt_entry, Label::kNear);
// If the result is an object (in the ECMA sense), we should get rid
// of the receiver and use the result; see ECMA-262 section 13.2.2-7
// on page 74.
Label use_receiver, do_throw, leave_frame;
// Else: use TheHoleValue as receiver for constructor call
__ bind(&not_create_implicit_receiver);
__ LoadRoot(rax, RootIndex::kTheHoleValue);
// If the result is undefined, we jump out to using the implicit receiver.
__ JumpIfRoot(rax, RootIndex::kUndefinedValue, &use_receiver, Label::kNear);
// ----------- S t a t e -------------
// -- rax implicit receiver
// -- Slot 4 / sp[0*kSystemPointerSize] new target
// -- Slot 3 / sp[1*kSystemPointerSize] padding
// -- Slot 2 / sp[2*kSystemPointerSize] constructor function
// -- Slot 1 / sp[3*kSystemPointerSize] number of arguments (tagged)
// -- Slot 0 / sp[4*kSystemPointerSize] context
// -----------------------------------
// Deoptimizer enters here.
masm->isolate()->heap()->SetConstructStubCreateDeoptPCOffset(
masm->pc_offset());
__ bind(&post_instantiation_deopt_entry);
// Restore new target.
__ Pop(rdx);
// Push the allocated receiver to the stack.
__ Push(rax);
// We need two copies because we may have to return the original one
// and the calling conventions dictate that the called function pops the
// receiver. The second copy is pushed after the arguments, we saved in r8
// since rax needs to store the number of arguments before
// InvokingFunction.
__ movq(r8, rax);
// Set up pointer to first argument (skip receiver).
__ leaq(rbx, Operand(rbp, StandardFrameConstants::kCallerSPOffset +
kSystemPointerSize));
// Restore constructor function and argument count.
__ movq(rdi, Operand(rbp, ConstructFrameConstants::kConstructorOffset));
__ SmiUntag(rax, Operand(rbp, ConstructFrameConstants::kLengthOffset));
// Check if we have enough stack space to push all arguments.
// Argument count in rax. Clobbers rcx.
Label stack_overflow;
__ StackOverflowCheck(rax, rcx, &stack_overflow);
// Otherwise we do a smi check and fall through to check if the return value
// is a valid receiver.
// TODO(victorgomes): When the arguments adaptor is completely removed, we
// should get the formal parameter count and copy the arguments in its
// correct position (including any undefined), instead of delaying this to
// InvokeFunction.
// If the result is a smi, it is *not* an object in the ECMA sense.
__ JumpIfSmi(rax, &use_receiver, Label::kNear);
// Copy arguments to the expression stack.
__ PushArray(rbx, rax, rcx);
// If the type of the result (stored in its map) is less than
// FIRST_JS_RECEIVER_TYPE, it is not an object in the ECMA sense.
STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
__ CmpObjectType(rax, FIRST_JS_RECEIVER_TYPE, rcx);
__ j(above_equal, &leave_frame, Label::kNear);
__ jmp(&use_receiver, Label::kNear);
// Push implicit receiver.
__ Push(r8);
__ bind(&do_throw);
__ CallRuntime(Runtime::kThrowConstructorReturnedNonObject);
// Call the function.
__ InvokeFunction(rdi, rdx, rax, CALL_FUNCTION);
// Throw away the result of the constructor invocation and use the
// on-stack receiver as the result.
__ bind(&use_receiver);
__ movq(rax, Operand(rsp, 0 * kSystemPointerSize));
__ JumpIfRoot(rax, RootIndex::kTheHoleValue, &do_throw, Label::kNear);
// ----------- S t a t e -------------
// -- rax constructor result
// -- sp[0*kSystemPointerSize] implicit receiver
// -- sp[1*kSystemPointerSize] padding
// -- sp[2*kSystemPointerSize] constructor function
// -- sp[3*kSystemPointerSize] number of arguments
// -- sp[4*kSystemPointerSize] context
// -----------------------------------
__ bind(&leave_frame);
// Restore the arguments count.
__ movq(rbx, Operand(rbp, ConstructFrameConstants::kLengthOffset));
// Leave construct frame.
}
// Store offset of return address for deoptimizer.
masm->isolate()->heap()->SetConstructStubInvokeDeoptPCOffset(
masm->pc_offset());
// If the result is an object (in the ECMA sense), we should get rid
// of the receiver and use the result; see ECMA-262 section 13.2.2-7
// on page 74.
Label use_receiver, do_throw, leave_and_return, check_result;
// If the result is undefined, we'll use the implicit receiver. Otherwise we
// do a smi check and fall through to check if the return value is a valid
// receiver.
__ JumpIfNotRoot(rax, RootIndex::kUndefinedValue, &check_result,
Label::kNear);
// Throw away the result of the constructor invocation and use the
// on-stack receiver as the result.
__ bind(&use_receiver);
__ movq(rax, Operand(rsp, 0 * kSystemPointerSize));
__ JumpIfRoot(rax, RootIndex::kTheHoleValue, &do_throw, Label::kNear);
__ bind(&leave_and_return);
// Restore the arguments count.
__ movq(rbx, Operand(rbp, ConstructFrameConstants::kLengthOffset));
__ LeaveFrame(StackFrame::CONSTRUCT);
// Remove caller arguments from the stack and return.
__ PopReturnAddressTo(rcx);
SmiIndex index = masm->SmiToIndex(rbx, rbx, kSystemPointerSizeLog2);
__ leaq(rsp, Operand(rsp, index.reg, index.scale, 1 * kSystemPointerSize));
__ PushReturnAddressFrom(rcx);
__ ret(0);
// If the result is a smi, it is *not* an object in the ECMA sense.
__ bind(&check_result);
__ JumpIfSmi(rax, &use_receiver, Label::kNear);
// If the type of the result (stored in its map) is less than
// FIRST_JS_RECEIVER_TYPE, it is not an object in the ECMA sense.
STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
__ CmpObjectType(rax, FIRST_JS_RECEIVER_TYPE, rcx);
__ j(above_equal, &leave_and_return, Label::kNear);
__ jmp(&use_receiver);
__ bind(&do_throw);
// Restore context from the frame.
__ movq(rsi, Operand(rbp, ConstructFrameConstants::kContextOffset));
__ CallRuntime(Runtime::kThrowConstructorReturnedNonObject);
// We don't return here.
__ int3();
__ bind(&stack_overflow);
// Restore the context from the frame.
__ movq(rsi, Operand(rbp, ConstructFrameConstants::kContextOffset));
__ CallRuntime(Runtime::kThrowStackOverflow);
// This should be unreachable.
__ int3();
}
void Builtins::Generate_JSBuiltinsConstructStub(MacroAssembler* masm) {
......
......@@ -2265,7 +2265,7 @@ void MacroAssembler::InvokeFunctionCode(Register function, Register new_target,
Register actual_parameter_count,
InvokeFlag flag) {
// You can't call a function without a valid frame.
DCHECK(flag == JUMP_FUNCTION || has_frame());
DCHECK_IMPLIES(flag == CALL_FUNCTION, has_frame());
DCHECK_EQ(function, x1);
DCHECK_IMPLIES(new_target.is_valid(), new_target == x3);
......
......@@ -1283,7 +1283,7 @@ void MacroAssembler::InvokeFunctionCode(Register function, Register new_target,
Register actual_parameter_count,
InvokeFlag flag) {
// You can't call a function without a valid frame.
DCHECK(flag == JUMP_FUNCTION || has_frame());
DCHECK_IMPLIES(flag == CALL_FUNCTION, has_frame());
DCHECK_EQ(function, edi);
DCHECK_IMPLIES(new_target.is_valid(), new_target == edx);
DCHECK(expected_parameter_count == ecx || expected_parameter_count == eax);
......
......@@ -2394,8 +2394,8 @@ void MacroAssembler::InvokeFunctionCode(Register function, Register new_target,
Register actual_parameter_count,
InvokeFlag flag) {
// You can't call a function without a valid frame.
DCHECK(flag == JUMP_FUNCTION || has_frame());
DCHECK(function == rdi);
DCHECK_IMPLIES(flag == CALL_FUNCTION, has_frame());
DCHECK_EQ(function, rdi);
DCHECK_IMPLIES(new_target.is_valid(), new_target == rdx);
// On function call, call into the debugger if necessary.
......
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