[mips][builtins] Streamline the construct stubs

Port: 366d30c990

Change-Id: I8cb720b7de38344627818c578efc36f42c33bbcb
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2531367
Reviewed-by: Jakob Gruber <jgruber@chromium.org>
Commit-Queue: Jakob Gruber <jgruber@chromium.org>
Auto-Submit: Liu yu <liuyu@loongson.cn>
Cr-Commit-Position: refs/heads/master@{#71105}
This commit is contained in:
Liu Yu 2020-11-11 16:07:04 +08:00 committed by Commit Bot
parent c1d85f5359
commit 838ce2befc
2 changed files with 265 additions and 267 deletions

View File

@ -128,168 +128,168 @@ void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) {
// -----------------------------------
// Enter a construct frame.
{
FrameScope scope(masm, StackFrame::CONSTRUCT);
Label post_instantiation_deopt_entry, not_create_implicit_receiver;
FrameScope scope(masm, StackFrame::MANUAL);
Label post_instantiation_deopt_entry, not_create_implicit_receiver;
__ EnterFrame(StackFrame::CONSTRUCT);
// Preserve the incoming parameters on the stack.
__ SmiTag(a0);
__ Push(cp, a0, a1);
__ PushRoot(RootIndex::kTheHoleValue);
__ Push(a3);
// Preserve the incoming parameters on the stack.
__ SmiTag(a0);
__ Push(cp, a0, a1);
__ PushRoot(RootIndex::kTheHoleValue);
__ Push(a3);
// ----------- S t a t e -------------
// -- sp[0*kPointerSize]: new target
// -- sp[1*kPointerSize]: padding
// -- a1 and sp[2*kPointerSize]: constructor function
// -- sp[3*kPointerSize]: number of arguments (tagged)
// -- sp[4*kPointerSize]: context
// -----------------------------------
// ----------- S t a t e -------------
// -- sp[0*kPointerSize]: new target
// -- sp[1*kPointerSize]: padding
// -- a1 and sp[2*kPointerSize]: constructor function
// -- sp[3*kPointerSize]: number of arguments (tagged)
// -- sp[4*kPointerSize]: context
// -----------------------------------
__ lw(t2, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
__ lw(t2, FieldMemOperand(t2, SharedFunctionInfo::kFlagsOffset));
__ DecodeField<SharedFunctionInfo::FunctionKindBits>(t2);
__ JumpIfIsInRange(t2, kDefaultDerivedConstructor, kDerivedConstructor,
&not_create_implicit_receiver);
__ lw(t2, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
__ lw(t2, FieldMemOperand(t2, SharedFunctionInfo::kFlagsOffset));
__ DecodeField<SharedFunctionInfo::FunctionKindBits>(t2);
__ JumpIfIsInRange(t2, kDefaultDerivedConstructor, kDerivedConstructor,
&not_create_implicit_receiver);
// If not derived class constructor: Allocate the new receiver object.
__ IncrementCounter(masm->isolate()->counters()->constructed_objects(), 1,
t2, t3);
__ Call(BUILTIN_CODE(masm->isolate(), FastNewObject),
RelocInfo::CODE_TARGET);
__ Branch(&post_instantiation_deopt_entry);
// If not derived class constructor: Allocate the new receiver object.
__ IncrementCounter(masm->isolate()->counters()->constructed_objects(), 1,
t2, t3);
__ Call(BUILTIN_CODE(masm->isolate(), FastNewObject), RelocInfo::CODE_TARGET);
__ Branch(&post_instantiation_deopt_entry);
// Else: use TheHoleValue as receiver for constructor call
__ bind(&not_create_implicit_receiver);
__ LoadRoot(v0, RootIndex::kTheHoleValue);
// Else: use TheHoleValue as receiver for constructor call
__ bind(&not_create_implicit_receiver);
__ LoadRoot(v0, RootIndex::kTheHoleValue);
// ----------- S t a t e -------------
// -- v0: receiver
// -- Slot 4 / sp[0*kPointerSize]: new target
// -- Slot 3 / sp[1*kPointerSize]: padding
// -- Slot 2 / sp[2*kPointerSize]: constructor function
// -- Slot 1 / sp[3*kPointerSize]: number of arguments (tagged)
// -- Slot 0 / sp[4*kPointerSize]: context
// -----------------------------------
// Deoptimizer enters here.
masm->isolate()->heap()->SetConstructStubCreateDeoptPCOffset(
masm->pc_offset());
__ bind(&post_instantiation_deopt_entry);
// ----------- S t a t e -------------
// -- v0: receiver
// -- Slot 4 / sp[0*kPointerSize]: new target
// -- Slot 3 / sp[1*kPointerSize]: padding
// -- Slot 2 / sp[2*kPointerSize]: constructor function
// -- Slot 1 / sp[3*kPointerSize]: number of arguments (tagged)
// -- Slot 0 / sp[4*kPointerSize]: context
// -----------------------------------
// Deoptimizer enters here.
masm->isolate()->heap()->SetConstructStubCreateDeoptPCOffset(
masm->pc_offset());
__ bind(&post_instantiation_deopt_entry);
// Restore new target.
__ Pop(a3);
// Restore new target.
__ Pop(a3);
// Push the allocated receiver to the stack.
__ Push(v0);
// 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 s0
// since v0 will store the return value of callRuntime.
__ mov(s0, v0);
// Push the allocated receiver to the stack.
__ Push(v0);
// Set up pointer to last argument.
__ Addu(
t2, fp,
Operand(StandardFrameConstants::kCallerSPOffset + kSystemPointerSize));
// 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 s0
// since v0 will store the return value of callRuntime.
__ mov(s0, v0);
// ----------- S t a t e -------------
// -- r3: new target
// -- sp[0*kPointerSize]: implicit receiver
// -- sp[1*kPointerSize]: implicit receiver
// -- sp[2*kPointerSize]: padding
// -- sp[3*kPointerSize]: constructor function
// -- sp[4*kPointerSize]: number of arguments (tagged)
// -- sp[5*kPointerSize]: context
// -----------------------------------
// Set up pointer to last argument.
__ Addu(t2, fp, Operand(StandardFrameConstants::kCallerSPOffset +
kSystemPointerSize));
// Restore constructor function and argument count.
__ lw(a1, MemOperand(fp, ConstructFrameConstants::kConstructorOffset));
__ lw(a0, MemOperand(fp, ConstructFrameConstants::kLengthOffset));
__ SmiUntag(a0);
// ----------- S t a t e -------------
// -- r3: new target
// -- sp[0*kPointerSize]: implicit receiver
// -- sp[1*kPointerSize]: implicit receiver
// -- sp[2*kPointerSize]: padding
// -- sp[3*kPointerSize]: constructor function
// -- sp[4*kPointerSize]: number of arguments (tagged)
// -- sp[5*kPointerSize]: context
// -----------------------------------
Label enough_stack_space, stack_overflow;
__ StackOverflowCheck(a0, t0, t1, &stack_overflow);
__ Branch(&enough_stack_space);
// Restore constructor function and argument count.
__ lw(a1, MemOperand(fp, ConstructFrameConstants::kConstructorOffset));
__ lw(a0, MemOperand(fp, ConstructFrameConstants::kLengthOffset));
__ SmiUntag(a0);
__ bind(&stack_overflow);
// Restore the context from the frame.
__ lw(cp, MemOperand(fp, ConstructFrameConstants::kContextOffset));
__ CallRuntime(Runtime::kThrowStackOverflow);
// Unreachable code.
__ break_(0xCC);
Label stack_overflow;
__ StackOverflowCheck(a0, t0, t1, &stack_overflow);
__ 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.
// 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 and receiver to the expression stack.
__ PushArray(t2, a0, t0, t1);
// Copy arguments and receiver to the expression stack.
__ PushArray(t2, a0, t0, t1);
// 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.
__ Push(s0);
// 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.
__ Push(s0);
// Call the function.
__ InvokeFunctionWithNewTarget(a1, a3, a0, CALL_FUNCTION);
// Call the function.
__ InvokeFunctionWithNewTarget(a1, a3, a0, CALL_FUNCTION);
// ----------- S t a t e -------------
// -- v0: 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
// -----------------------------------
// ----------- S t a t e -------------
// -- v0: 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
// -----------------------------------
// Store offset of return address for deoptimizer.
masm->isolate()->heap()->SetConstructStubInvokeDeoptPCOffset(
masm->pc_offset());
// Store offset of return address for deoptimizer.
masm->isolate()->heap()->SetConstructStubInvokeDeoptPCOffset(
masm->pc_offset());
// Restore the context from the frame.
__ lw(cp, MemOperand(fp, ConstructFrameConstants::kContextOffset));
// 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 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;
// If the result is undefined, we jump out to using the implicit receiver.
__ JumpIfNotRoot(v0, RootIndex::kUndefinedValue, &check_receiver);
// If the result is undefined, we jump out to using the implicit receiver.
__ JumpIfRoot(v0, RootIndex::kUndefinedValue, &use_receiver);
// Otherwise we do a smi check and fall through to check if the return value
// is a valid receiver.
// Otherwise we do a smi check and fall through to check if the return value
// is a valid receiver.
// Throw away the result of the constructor invocation and use the
// on-stack receiver as the result.
__ bind(&use_receiver);
__ lw(v0, MemOperand(sp, 0 * kPointerSize));
__ JumpIfRoot(v0, RootIndex::kTheHoleValue, &do_throw);
// If the result is a smi, it is *not* an object in the ECMA sense.
__ JumpIfSmi(v0, &use_receiver);
__ bind(&leave_and_return);
// Restore smi-tagged arguments count from the frame.
__ lw(a1, MemOperand(fp, ConstructFrameConstants::kLengthOffset));
// Leave construct frame.
__ LeaveFrame(StackFrame::CONSTRUCT);
// 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.
__ GetObjectType(v0, t2, t2);
STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
__ Branch(&leave_frame, greater_equal, t2, Operand(FIRST_JS_RECEIVER_TYPE));
__ Branch(&use_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);
__ lw(v0, MemOperand(sp, 0 * kPointerSize));
__ JumpIfRoot(v0, RootIndex::kTheHoleValue, &do_throw);
__ bind(&leave_frame);
// Restore smi-tagged arguments count from the frame.
__ lw(a1, MemOperand(fp, ConstructFrameConstants::kLengthOffset));
// Leave construct frame.
}
// Remove caller arguments from the stack and return.
__ Lsa(sp, sp, a1, kPointerSizeLog2 - kSmiTagSize);
__ Addu(sp, sp, kPointerSize);
__ Ret();
__ bind(&check_receiver);
// If the result is a smi, it is *not* an object in the ECMA sense.
__ JumpIfSmi(v0, &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.
__ GetObjectType(v0, t2, t2);
STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
__ Branch(&leave_and_return, greater_equal, t2,
Operand(FIRST_JS_RECEIVER_TYPE));
__ Branch(&use_receiver);
__ bind(&do_throw);
// Restore the context from the frame.
__ lw(cp, MemOperand(fp, ConstructFrameConstants::kContextOffset));
__ CallRuntime(Runtime::kThrowConstructorReturnedNonObject);
__ break_(0xCC);
__ bind(&stack_overflow);
// Restore the context from the frame.
__ lw(cp, MemOperand(fp, ConstructFrameConstants::kContextOffset));
__ CallRuntime(Runtime::kThrowStackOverflow);
// Unreachable code.
__ break_(0xCC);
}
void Builtins::Generate_JSBuiltinsConstructStub(MacroAssembler* masm) {

View File

@ -129,169 +129,167 @@ void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) {
// -----------------------------------
// Enter a construct frame.
{
FrameScope scope(masm, StackFrame::CONSTRUCT);
Label post_instantiation_deopt_entry, not_create_implicit_receiver;
FrameScope scope(masm, StackFrame::MANUAL);
Label post_instantiation_deopt_entry, not_create_implicit_receiver;
__ EnterFrame(StackFrame::CONSTRUCT);
// Preserve the incoming parameters on the stack.
__ SmiTag(a0);
__ Push(cp, a0, a1);
__ PushRoot(RootIndex::kUndefinedValue);
__ Push(a3);
// Preserve the incoming parameters on the stack.
__ SmiTag(a0);
__ Push(cp, a0, a1);
__ PushRoot(RootIndex::kUndefinedValue);
__ Push(a3);
// ----------- S t a t e -------------
// -- sp[0*kPointerSize]: new target
// -- sp[1*kPointerSize]: padding
// -- a1 and sp[2*kPointerSize]: constructor function
// -- sp[3*kPointerSize]: number of arguments (tagged)
// -- sp[4*kPointerSize]: context
// -----------------------------------
// ----------- S t a t e -------------
// -- sp[0*kPointerSize]: new target
// -- sp[1*kPointerSize]: padding
// -- a1 and sp[2*kPointerSize]: constructor function
// -- sp[3*kPointerSize]: number of arguments (tagged)
// -- sp[4*kPointerSize]: context
// -----------------------------------
__ Ld(t2, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
__ lwu(t2, FieldMemOperand(t2, SharedFunctionInfo::kFlagsOffset));
__ DecodeField<SharedFunctionInfo::FunctionKindBits>(t2);
__ JumpIfIsInRange(t2, kDefaultDerivedConstructor, kDerivedConstructor,
&not_create_implicit_receiver);
__ Ld(t2, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
__ lwu(t2, FieldMemOperand(t2, SharedFunctionInfo::kFlagsOffset));
__ DecodeField<SharedFunctionInfo::FunctionKindBits>(t2);
__ JumpIfIsInRange(t2, kDefaultDerivedConstructor, kDerivedConstructor,
&not_create_implicit_receiver);
// If not derived class constructor: Allocate the new receiver object.
__ IncrementCounter(masm->isolate()->counters()->constructed_objects(), 1,
t2, t3);
__ Call(BUILTIN_CODE(masm->isolate(), FastNewObject),
RelocInfo::CODE_TARGET);
__ Branch(&post_instantiation_deopt_entry);
// If not derived class constructor: Allocate the new receiver object.
__ IncrementCounter(masm->isolate()->counters()->constructed_objects(), 1,
t2, t3);
__ Call(BUILTIN_CODE(masm->isolate(), FastNewObject),
RelocInfo::CODE_TARGET);
__ Branch(&post_instantiation_deopt_entry);
// Else: use TheHoleValue as receiver for constructor call
__ bind(&not_create_implicit_receiver);
__ LoadRoot(v0, RootIndex::kTheHoleValue);
// Else: use TheHoleValue as receiver for constructor call
__ bind(&not_create_implicit_receiver);
__ LoadRoot(v0, RootIndex::kTheHoleValue);
// ----------- S t a t e -------------
// -- v0: receiver
// -- Slot 4 / sp[0*kPointerSize]: new target
// -- Slot 3 / sp[1*kPointerSize]: padding
// -- Slot 2 / sp[2*kPointerSize]: constructor function
// -- Slot 1 / sp[3*kPointerSize]: number of arguments (tagged)
// -- Slot 0 / sp[4*kPointerSize]: context
// -----------------------------------
// Deoptimizer enters here.
masm->isolate()->heap()->SetConstructStubCreateDeoptPCOffset(
masm->pc_offset());
__ bind(&post_instantiation_deopt_entry);
// ----------- S t a t e -------------
// -- v0: receiver
// -- Slot 4 / sp[0*kPointerSize]: new target
// -- Slot 3 / sp[1*kPointerSize]: padding
// -- Slot 2 / sp[2*kPointerSize]: constructor function
// -- Slot 1 / sp[3*kPointerSize]: number of arguments (tagged)
// -- Slot 0 / sp[4*kPointerSize]: context
// -----------------------------------
// Deoptimizer enters here.
masm->isolate()->heap()->SetConstructStubCreateDeoptPCOffset(
masm->pc_offset());
__ bind(&post_instantiation_deopt_entry);
// Restore new target.
__ Pop(a3);
// Restore new target.
__ Pop(a3);
// Push the allocated receiver to the stack.
__ Push(v0);
// Push the allocated receiver to the stack.
__ Push(v0);
// 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 a6
// since v0 will store the return value of callRuntime.
__ mov(a6, v0);
// 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 a6
// since v0 will store the return value of callRuntime.
__ mov(a6, v0);
// Set up pointer to last argument.
__ Daddu(t2, fp, Operand(StandardFrameConstants::kCallerSPOffset +
kSystemPointerSize));
// Set up pointer to last argument.
__ Daddu(t2, fp, Operand(StandardFrameConstants::kCallerSPOffset +
kSystemPointerSize));
// ----------- S t a t e -------------
// -- r3: new target
// -- sp[0*kPointerSize]: implicit receiver
// -- sp[1*kPointerSize]: implicit receiver
// -- sp[2*kPointerSize]: padding
// -- sp[3*kPointerSize]: constructor function
// -- sp[4*kPointerSize]: number of arguments (tagged)
// -- sp[5*kPointerSize]: context
// -----------------------------------
// ----------- S t a t e -------------
// -- r3: new target
// -- sp[0*kPointerSize]: implicit receiver
// -- sp[1*kPointerSize]: implicit receiver
// -- sp[2*kPointerSize]: padding
// -- sp[3*kPointerSize]: constructor function
// -- sp[4*kPointerSize]: number of arguments (tagged)
// -- sp[5*kPointerSize]: context
// -----------------------------------
// Restore constructor function and argument count.
__ Ld(a1, MemOperand(fp, ConstructFrameConstants::kConstructorOffset));
__ Ld(a0, MemOperand(fp, ConstructFrameConstants::kLengthOffset));
__ SmiUntag(a0);
// Restore constructor function and argument count.
__ Ld(a1, MemOperand(fp, ConstructFrameConstants::kConstructorOffset));
__ Ld(a0, MemOperand(fp, ConstructFrameConstants::kLengthOffset));
__ SmiUntag(a0);
Label enough_stack_space, stack_overflow;
__ StackOverflowCheck(a0, t0, t1, &stack_overflow);
__ Branch(&enough_stack_space);
Label stack_overflow;
__ StackOverflowCheck(a0, t0, t1, &stack_overflow);
__ bind(&stack_overflow);
// Restore the context from the frame.
__ Ld(cp, MemOperand(fp, ConstructFrameConstants::kContextOffset));
__ CallRuntime(Runtime::kThrowStackOverflow);
// Unreachable code.
__ break_(0xCC);
// 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.
__ bind(&enough_stack_space);
// Copy arguments and receiver to the expression stack.
__ PushArray(t2, a0, t0, t1);
// 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,
__ Push(a6);
// 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.
// Call the function.
__ InvokeFunctionWithNewTarget(a1, a3, a0, CALL_FUNCTION);
// Copy arguments and receiver to the expression stack.
__ PushArray(t2, a0, t0, t1);
// 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,
__ Push(a6);
// ----------- S t a t e -------------
// -- v0: 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
// -----------------------------------
// Call the function.
__ InvokeFunctionWithNewTarget(a1, a3, a0, CALL_FUNCTION);
// Store offset of return address for deoptimizer.
masm->isolate()->heap()->SetConstructStubInvokeDeoptPCOffset(
masm->pc_offset());
// ----------- S t a t e -------------
// -- v0: 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 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;
// Store offset of return address for deoptimizer.
masm->isolate()->heap()->SetConstructStubInvokeDeoptPCOffset(
masm->pc_offset());
// If the result is undefined, we jump out to using the implicit receiver.
__ JumpIfNotRoot(v0, RootIndex::kUndefinedValue, &check_receiver);
// Restore the context from the frame.
__ Ld(cp, MemOperand(fp, ConstructFrameConstants::kContextOffset));
// 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_frame;
// Throw away the result of the constructor invocation and use the
// on-stack receiver as the result.
__ bind(&use_receiver);
__ Ld(v0, MemOperand(sp, 0 * kPointerSize));
__ JumpIfRoot(v0, RootIndex::kTheHoleValue, &do_throw);
// If the result is undefined, we jump out to using the implicit receiver.
__ JumpIfRoot(v0, RootIndex::kUndefinedValue, &use_receiver);
__ bind(&leave_and_return);
// Restore smi-tagged arguments count from the frame.
__ Ld(a1, MemOperand(fp, ConstructFrameConstants::kLengthOffset));
// Leave construct frame.
__ LeaveFrame(StackFrame::CONSTRUCT);
// Otherwise we do a smi check and fall through to check if the return value
// is a valid receiver.
// If the result is a smi, it is *not* an object in the ECMA sense.
__ JumpIfSmi(v0, &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.
__ GetObjectType(v0, t2, t2);
STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
__ Branch(&leave_frame, greater_equal, t2, Operand(FIRST_JS_RECEIVER_TYPE));
__ Branch(&use_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);
__ Ld(v0, MemOperand(sp, 0 * kPointerSize));
__ JumpIfRoot(v0, RootIndex::kTheHoleValue, &do_throw);
__ bind(&leave_frame);
// Restore smi-tagged arguments count from the frame.
__ Ld(a1, MemOperand(fp, ConstructFrameConstants::kLengthOffset));
// Leave construct frame.
}
// Remove caller arguments from the stack and return.
__ SmiScale(a4, a1, kPointerSizeLog2);
__ Daddu(sp, sp, a4);
__ Daddu(sp, sp, kPointerSize);
__ Ret();
__ bind(&check_receiver);
__ JumpIfSmi(v0, &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.
__ GetObjectType(v0, t2, t2);
STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
__ Branch(&leave_and_return, greater_equal, t2,
Operand(FIRST_JS_RECEIVER_TYPE));
__ Branch(&use_receiver);
__ bind(&do_throw);
// Restore the context from the frame.
__ Ld(cp, MemOperand(fp, ConstructFrameConstants::kContextOffset));
__ CallRuntime(Runtime::kThrowConstructorReturnedNonObject);
__ break_(0xCC);
__ bind(&stack_overflow);
// Restore the context from the frame.
__ Ld(cp, MemOperand(fp, ConstructFrameConstants::kContextOffset));
__ CallRuntime(Runtime::kThrowStackOverflow);
__ break_(0xCC);
}
void Builtins::Generate_JSBuiltinsConstructStub(MacroAssembler* masm) {