PPC/s390: [turbofan] [builtins] Unify construct builtins for JS functions and classes and add inlining and deoptimizer support
Port 2026d5cb79
R=tebbi@chromium.org, joransiu@ca.ibm.com, jyan@ca.ibm.com, michael_dawson@ca.ibm.com
BUG=v8:6180
LOG=N
Review-Url: https://codereview.chromium.org/2875073003
Cr-Commit-Position: refs/heads/master@{#45383}
This commit is contained in:
parent
d692f5e683
commit
6bd1aeee00
@ -446,9 +446,7 @@ void Builtins::Generate_InOptimizationQueue(MacroAssembler* masm) {
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
void Generate_JSConstructStubHelper(MacroAssembler* masm, bool is_api_function,
|
void Generate_JSBuiltinsConstructStubHelper(MacroAssembler* masm) {
|
||||||
bool create_implicit_receiver,
|
|
||||||
bool disallow_non_object_return) {
|
|
||||||
Label post_instantiation_deopt_entry;
|
Label post_instantiation_deopt_entry;
|
||||||
// ----------- S t a t e -------------
|
// ----------- S t a t e -------------
|
||||||
// -- r3 : number of arguments
|
// -- r3 : number of arguments
|
||||||
@ -459,74 +457,46 @@ void Generate_JSConstructStubHelper(MacroAssembler* masm, bool is_api_function,
|
|||||||
// -- sp[...]: constructor arguments
|
// -- sp[...]: constructor arguments
|
||||||
// -----------------------------------
|
// -----------------------------------
|
||||||
|
|
||||||
Isolate* isolate = masm->isolate();
|
|
||||||
|
|
||||||
// Enter a construct frame.
|
// Enter a construct frame.
|
||||||
{
|
{
|
||||||
FrameAndConstantPoolScope scope(masm, StackFrame::CONSTRUCT);
|
FrameAndConstantPoolScope scope(masm, StackFrame::CONSTRUCT);
|
||||||
|
|
||||||
// Preserve the incoming parameters on the stack.
|
// Preserve the incoming parameters on the stack.
|
||||||
|
|
||||||
if (!create_implicit_receiver) {
|
__ SmiTag(r3);
|
||||||
__ SmiTag(r7, r3, SetRC);
|
__ Push(cp, r3);
|
||||||
__ Push(cp, r7);
|
__ SmiUntag(r3, SetRC);
|
||||||
__ PushRoot(Heap::kTheHoleValueRootIndex);
|
// The receiver for the builtin/api call.
|
||||||
} else {
|
__ PushRoot(Heap::kTheHoleValueRootIndex);
|
||||||
__ SmiTag(r3);
|
|
||||||
__ Push(cp, r3);
|
|
||||||
|
|
||||||
// Allocate the new receiver object.
|
|
||||||
__ Push(r4, r6);
|
|
||||||
__ Call(CodeFactory::FastNewObject(masm->isolate()).code(),
|
|
||||||
RelocInfo::CODE_TARGET);
|
|
||||||
__ mr(r7, r3);
|
|
||||||
__ Pop(r4, r6);
|
|
||||||
|
|
||||||
// ----------- S t a t e -------------
|
|
||||||
// -- r4: constructor function
|
|
||||||
// -- r6: new target
|
|
||||||
// -- r7: newly allocated object
|
|
||||||
// -----------------------------------
|
|
||||||
|
|
||||||
// Retrieve smi-tagged arguments count from the stack.
|
|
||||||
__ LoadP(r3, MemOperand(sp));
|
|
||||||
__ SmiUntag(r3, SetRC);
|
|
||||||
|
|
||||||
// Push the allocated receiver to the stack. 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.
|
|
||||||
__ Push(r7, r7);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deoptimizer re-enters stub code here.
|
|
||||||
__ bind(&post_instantiation_deopt_entry);
|
|
||||||
|
|
||||||
// Set up pointer to last argument.
|
// Set up pointer to last argument.
|
||||||
__ addi(r5, fp, Operand(StandardFrameConstants::kCallerSPOffset));
|
__ addi(r7, fp, Operand(StandardFrameConstants::kCallerSPOffset));
|
||||||
|
|
||||||
// Copy arguments and receiver to the expression stack.
|
// Copy arguments and receiver to the expression stack.
|
||||||
// r3: number of arguments
|
|
||||||
// r4: constructor function
|
|
||||||
// r5: address of last argument (caller sp)
|
|
||||||
// r6: new target
|
|
||||||
// cr0: condition indicating whether r3 is zero
|
|
||||||
// sp[0]: receiver
|
|
||||||
// sp[1]: receiver
|
|
||||||
// sp[2]: number of arguments (smi-tagged)
|
|
||||||
Label loop, no_args;
|
Label loop, no_args;
|
||||||
|
// ----------- S t a t e -------------
|
||||||
|
// -- r3: number of arguments (untagged)
|
||||||
|
// -- r4: constructor function
|
||||||
|
// -- r6: new target
|
||||||
|
// -- r7: pointer to last argument
|
||||||
|
// -- cr0: condition indicating whether r3 is zero
|
||||||
|
// -- sp[0*kPointerSize]: the hole (receiver)
|
||||||
|
// -- sp[1*kPointerSize]: number of arguments (tagged)
|
||||||
|
// -- sp[2*kPointerSize]: context
|
||||||
|
// -----------------------------------
|
||||||
__ beq(&no_args, cr0);
|
__ beq(&no_args, cr0);
|
||||||
__ ShiftLeftImm(ip, r3, Operand(kPointerSizeLog2));
|
__ ShiftLeftImm(ip, r3, Operand(kPointerSizeLog2));
|
||||||
__ sub(sp, sp, ip);
|
__ sub(sp, sp, ip);
|
||||||
__ mtctr(r3);
|
__ mtctr(r3);
|
||||||
__ bind(&loop);
|
__ bind(&loop);
|
||||||
__ subi(ip, ip, Operand(kPointerSize));
|
__ subi(ip, ip, Operand(kPointerSize));
|
||||||
__ LoadPX(r0, MemOperand(r5, ip));
|
__ LoadPX(r0, MemOperand(r7, ip));
|
||||||
__ StorePX(r0, MemOperand(sp, ip));
|
__ StorePX(r0, MemOperand(sp, ip));
|
||||||
__ bdnz(&loop);
|
__ bdnz(&loop);
|
||||||
__ bind(&no_args);
|
__ bind(&no_args);
|
||||||
|
|
||||||
// Call the function.
|
// Call the function.
|
||||||
// r3: number of arguments
|
// r3: number of arguments (untagged)
|
||||||
// r4: constructor function
|
// r4: constructor function
|
||||||
// r6: new target
|
// r6: new target
|
||||||
{
|
{
|
||||||
@ -536,146 +506,231 @@ void Generate_JSConstructStubHelper(MacroAssembler* masm, bool is_api_function,
|
|||||||
CheckDebugStepCallWrapper());
|
CheckDebugStepCallWrapper());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store offset of return address for deoptimizer.
|
|
||||||
if (create_implicit_receiver && !disallow_non_object_return &&
|
|
||||||
!is_api_function) {
|
|
||||||
masm->isolate()->heap()->SetConstructStubInvokeDeoptPCOffset(
|
|
||||||
masm->pc_offset());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Restore context from the frame.
|
// Restore context from the frame.
|
||||||
// r3: result
|
|
||||||
// sp[0]: receiver
|
|
||||||
// sp[1]: number of arguments (smi-tagged)
|
|
||||||
__ LoadP(cp, MemOperand(fp, ConstructFrameConstants::kContextOffset));
|
__ LoadP(cp, MemOperand(fp, ConstructFrameConstants::kContextOffset));
|
||||||
|
// Restore smi-tagged arguments count from the frame.
|
||||||
if (create_implicit_receiver) {
|
__ LoadP(r4, MemOperand(fp, ConstructFrameConstants::kLengthOffset));
|
||||||
// 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, return_value, do_throw;
|
|
||||||
|
|
||||||
// If the result is a smi, it is *not* an object in the ECMA sense.
|
|
||||||
// r3: result
|
|
||||||
// sp[0]: receiver
|
|
||||||
// sp[1]: number of arguments (smi-tagged)
|
|
||||||
// If the result is undefined, we jump out to using the implicit
|
|
||||||
// receiver, otherwise we do a smi check and fall through to
|
|
||||||
// check if the return value is a valid receiver.
|
|
||||||
if (disallow_non_object_return) {
|
|
||||||
__ CompareRoot(r3, Heap::kUndefinedValueRootIndex);
|
|
||||||
__ beq(&use_receiver);
|
|
||||||
__ JumpIfSmi(r3, &do_throw);
|
|
||||||
} else {
|
|
||||||
__ JumpIfSmi(r3, &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.
|
|
||||||
__ CompareObjectType(r3, r4, r6, FIRST_JS_RECEIVER_TYPE);
|
|
||||||
__ bge(&return_value);
|
|
||||||
|
|
||||||
if (disallow_non_object_return) {
|
|
||||||
__ 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);
|
|
||||||
__ LoadP(r3, MemOperand(sp));
|
|
||||||
|
|
||||||
// Remove receiver from the stack, remove caller arguments, and
|
|
||||||
// return.
|
|
||||||
__ bind(&return_value);
|
|
||||||
// r3: result
|
|
||||||
// sp[0]: receiver (newly allocated object)
|
|
||||||
// sp[1]: number of arguments (smi-tagged)
|
|
||||||
__ LoadP(r4, MemOperand(sp, 1 * kPointerSize));
|
|
||||||
} else {
|
|
||||||
__ LoadP(r4, MemOperand(sp));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Leave construct frame.
|
// Leave construct frame.
|
||||||
}
|
}
|
||||||
|
// Remove caller arguments from the stack and return.
|
||||||
|
STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
|
||||||
|
|
||||||
// ES6 9.2.2. Step 13+
|
__ SmiToPtrArrayOffset(r4, r4);
|
||||||
// For derived class constructors, throw a TypeError here if the result
|
__ add(sp, sp, r4);
|
||||||
// is not a JSReceiver. For the base constructor, we've already checked
|
__ addi(sp, sp, Operand(kPointerSize));
|
||||||
// the result, so we omit the check.
|
__ blr();
|
||||||
if (disallow_non_object_return && !create_implicit_receiver) {
|
}
|
||||||
Label do_throw, dont_throw;
|
|
||||||
__ JumpIfSmi(r3, &do_throw);
|
// The construct stub for ES5 constructor functions and ES6 class constructors.
|
||||||
|
void Generate_JSConstructStubGeneric(MacroAssembler* masm,
|
||||||
|
bool restrict_constructor_return) {
|
||||||
|
// ----------- S t a t e -------------
|
||||||
|
// -- r3: number of arguments (untagged)
|
||||||
|
// -- r4: constructor function
|
||||||
|
// -- r6: new target
|
||||||
|
// -- cp: context
|
||||||
|
// -- lr: return address
|
||||||
|
// -- sp[...]: constructor arguments
|
||||||
|
// -----------------------------------
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
__ SmiTag(r3);
|
||||||
|
__ Push(cp, r3, r4, r6);
|
||||||
|
|
||||||
|
// ----------- S t a t e -------------
|
||||||
|
// -- sp[0*kPointerSize]: new target
|
||||||
|
// -- r4 and sp[1*kPointerSize]: constructor function
|
||||||
|
// -- sp[2*kPointerSize]: number of arguments (tagged)
|
||||||
|
// -- sp[3*kPointerSize]: context
|
||||||
|
// -----------------------------------
|
||||||
|
|
||||||
|
__ LoadP(r7, FieldMemOperand(r4, JSFunction::kSharedFunctionInfoOffset));
|
||||||
|
__ lwz(r7, FieldMemOperand(r7, SharedFunctionInfo::kCompilerHintsOffset));
|
||||||
|
__ TestBitMask(r7,
|
||||||
|
FunctionKind::kDerivedConstructor
|
||||||
|
<< SharedFunctionInfo::kFunctionKindShift,
|
||||||
|
r0);
|
||||||
|
__ bne(¬_create_implicit_receiver, cr0);
|
||||||
|
|
||||||
|
// If not derived class constructor: Allocate the new receiver object.
|
||||||
|
__ IncrementCounter(masm->isolate()->counters()->constructed_objects(), 1,
|
||||||
|
r7, r8);
|
||||||
|
__ Call(CodeFactory::FastNewObject(masm->isolate()).code(),
|
||||||
|
RelocInfo::CODE_TARGET);
|
||||||
|
__ b(&post_instantiation_deopt_entry);
|
||||||
|
|
||||||
|
// Else: use TheHoleValue as receiver for constructor call
|
||||||
|
__ bind(¬_create_implicit_receiver);
|
||||||
|
__ LoadRoot(r3, Heap::kTheHoleValueRootIndex);
|
||||||
|
|
||||||
|
// ----------- S t a t e -------------
|
||||||
|
// -- r3: 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(r6);
|
||||||
|
// Push the allocated receiver to the stack. 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.
|
||||||
|
__ Push(r3, r3);
|
||||||
|
|
||||||
|
// ----------- S t a t e -------------
|
||||||
|
// -- r6: new target
|
||||||
|
// -- sp[0*kPointerSize]: implicit receiver
|
||||||
|
// -- sp[1*kPointerSize]: implicit receiver
|
||||||
|
// -- sp[2*kPointerSize]: constructor function
|
||||||
|
// -- sp[3*kPointerSize]: number of arguments (tagged)
|
||||||
|
// -- sp[4*kPointerSize]: context
|
||||||
|
// -----------------------------------
|
||||||
|
|
||||||
|
// Restore constructor function and argument count.
|
||||||
|
__ LoadP(r4, MemOperand(fp, ConstructFrameConstants::kConstructorOffset));
|
||||||
|
__ LoadP(r3, MemOperand(fp, ConstructFrameConstants::kLengthOffset));
|
||||||
|
__ SmiUntag(r3, SetRC);
|
||||||
|
|
||||||
|
// Set up pointer to last argument.
|
||||||
|
__ addi(r7, fp, Operand(StandardFrameConstants::kCallerSPOffset));
|
||||||
|
|
||||||
|
// Copy arguments and receiver to the expression stack.
|
||||||
|
Label loop, no_args;
|
||||||
|
// ----------- S t a t e -------------
|
||||||
|
// -- r3: number of arguments (untagged)
|
||||||
|
// -- r6: new target
|
||||||
|
// -- r7: pointer to last argument
|
||||||
|
// -- cr0: condition indicating whether r3 is zero
|
||||||
|
// -- sp[0*kPointerSize]: implicit receiver
|
||||||
|
// -- sp[1*kPointerSize]: implicit receiver
|
||||||
|
// -- r4 and sp[2*kPointerSize]: constructor function
|
||||||
|
// -- sp[3*kPointerSize]: number of arguments (tagged)
|
||||||
|
// -- sp[4*kPointerSize]: context
|
||||||
|
// -----------------------------------
|
||||||
|
__ beq(&no_args, cr0);
|
||||||
|
__ ShiftLeftImm(ip, r3, Operand(kPointerSizeLog2));
|
||||||
|
__ sub(sp, sp, ip);
|
||||||
|
__ mtctr(r3);
|
||||||
|
__ bind(&loop);
|
||||||
|
__ subi(ip, ip, Operand(kPointerSize));
|
||||||
|
__ LoadPX(r0, MemOperand(r7, ip));
|
||||||
|
__ StorePX(r0, MemOperand(sp, ip));
|
||||||
|
__ bdnz(&loop);
|
||||||
|
__ bind(&no_args);
|
||||||
|
|
||||||
|
// Call the function.
|
||||||
|
{
|
||||||
|
ConstantPoolUnavailableScope constant_pool_unavailable(masm);
|
||||||
|
ParameterCount actual(r3);
|
||||||
|
__ InvokeFunction(r4, r6, actual, CALL_FUNCTION,
|
||||||
|
CheckDebugStepCallWrapper());
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------- S t a t e -------------
|
||||||
|
// -- r0: constructor result
|
||||||
|
// -- sp[0*kPointerSize]: implicit receiver
|
||||||
|
// -- sp[1*kPointerSize]: constructor function
|
||||||
|
// -- sp[2*kPointerSize]: number of arguments
|
||||||
|
// -- sp[3*kPointerSize]: context
|
||||||
|
// -----------------------------------
|
||||||
|
|
||||||
|
// Store offset of return address for deoptimizer.
|
||||||
|
masm->isolate()->heap()->SetConstructStubInvokeDeoptPCOffset(
|
||||||
|
masm->pc_offset());
|
||||||
|
|
||||||
|
// Restore the context from the frame.
|
||||||
|
__ LoadP(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, other_result, leave_frame;
|
||||||
|
|
||||||
|
// If the result is undefined, we jump out to using the implicit receiver.
|
||||||
|
__ JumpIfRoot(r3, Heap::kUndefinedValueRootIndex, &use_receiver);
|
||||||
|
|
||||||
|
// 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(r3, &other_result);
|
||||||
|
|
||||||
|
// 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);
|
STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
|
||||||
__ CompareObjectType(r3, r6, r6, FIRST_JS_RECEIVER_TYPE);
|
__ CompareObjectType(r3, r7, r7, FIRST_JS_RECEIVER_TYPE);
|
||||||
__ bge(&dont_throw);
|
__ bge(&leave_frame);
|
||||||
|
|
||||||
|
__ bind(&other_result);
|
||||||
|
// The result is now neither undefined nor an object.
|
||||||
|
if (restrict_constructor_return) {
|
||||||
|
// Throw if constructor function is a class constructor
|
||||||
|
__ LoadP(r7, MemOperand(fp, ConstructFrameConstants::kConstructorOffset));
|
||||||
|
__ LoadP(r7, FieldMemOperand(r7, JSFunction::kSharedFunctionInfoOffset));
|
||||||
|
__ lwz(r7, FieldMemOperand(r7, SharedFunctionInfo::kCompilerHintsOffset));
|
||||||
|
__ TestBitMask(r7,
|
||||||
|
FunctionKind::kClassConstructor
|
||||||
|
<< SharedFunctionInfo::kFunctionKindShift,
|
||||||
|
r0);
|
||||||
|
__ beq(&use_receiver, cr0);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
__ b(&use_receiver);
|
||||||
|
}
|
||||||
|
|
||||||
__ bind(&do_throw);
|
__ bind(&do_throw);
|
||||||
{
|
{
|
||||||
FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
|
FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
|
||||||
__ CallRuntime(Runtime::kThrowConstructorReturnedNonObject);
|
__ CallRuntime(Runtime::kThrowConstructorReturnedNonObject);
|
||||||
}
|
}
|
||||||
__ bind(&dont_throw);
|
|
||||||
|
// Throw away the result of the constructor invocation and use the
|
||||||
|
// on-stack receiver as the result.
|
||||||
|
__ bind(&use_receiver);
|
||||||
|
__ LoadP(r3, MemOperand(sp));
|
||||||
|
__ JumpIfRoot(r3, Heap::kTheHoleValueRootIndex, &do_throw);
|
||||||
|
|
||||||
|
__ bind(&leave_frame);
|
||||||
|
// Restore smi-tagged arguments count from the frame.
|
||||||
|
__ LoadP(r4, MemOperand(fp, ConstructFrameConstants::kLengthOffset));
|
||||||
|
// Leave construct frame.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Remove caller arguments from the stack and return.
|
||||||
|
STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
|
||||||
|
|
||||||
__ SmiToPtrArrayOffset(r4, r4);
|
__ SmiToPtrArrayOffset(r4, r4);
|
||||||
__ add(sp, sp, r4);
|
__ add(sp, sp, r4);
|
||||||
__ addi(sp, sp, Operand(kPointerSize));
|
__ addi(sp, sp, Operand(kPointerSize));
|
||||||
if (create_implicit_receiver) {
|
|
||||||
__ IncrementCounter(isolate->counters()->constructed_objects(), 1, r4, r5);
|
|
||||||
}
|
|
||||||
__ blr();
|
__ blr();
|
||||||
// Store offset of trampoline address for deoptimizer. This is the bailout
|
|
||||||
// point after the receiver instantiation but before the function invocation.
|
|
||||||
// We need to restore some registers in order to continue the above code.
|
|
||||||
if (create_implicit_receiver && !disallow_non_object_return &&
|
|
||||||
!is_api_function) {
|
|
||||||
masm->isolate()->heap()->SetConstructStubCreateDeoptPCOffset(
|
|
||||||
masm->pc_offset());
|
|
||||||
|
|
||||||
// ----------- S t a t e -------------
|
|
||||||
// -- r3 : newly allocated object
|
|
||||||
// -- sp[0] : constructor function
|
|
||||||
// -----------------------------------
|
|
||||||
|
|
||||||
__ pop(r4);
|
|
||||||
__ Push(r3, r3);
|
|
||||||
|
|
||||||
// Retrieve smi-tagged arguments count from the stack.
|
|
||||||
__ LoadP(r3, MemOperand(fp, ConstructFrameConstants::kLengthOffset));
|
|
||||||
__ SmiUntag(r3);
|
|
||||||
|
|
||||||
// Retrieve the new target value from the stack. This was placed into the
|
|
||||||
// frame description in place of the receiver by the optimizing compiler.
|
|
||||||
__ addi(r6, fp, Operand(StandardFrameConstants::kCallerSPOffset));
|
|
||||||
__ ShiftLeftImm(ip, r3, Operand(kPointerSizeLog2));
|
|
||||||
__ LoadPX(r6, MemOperand(r6, ip));
|
|
||||||
|
|
||||||
// Continue with constructor function invocation.
|
|
||||||
__ b(&post_instantiation_deopt_entry);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) {
|
void Builtins::Generate_JSConstructStubGenericRestrictedReturn(
|
||||||
Generate_JSConstructStubHelper(masm, false, true, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Builtins::Generate_JSConstructStubApi(MacroAssembler* masm) {
|
|
||||||
Generate_JSConstructStubHelper(masm, true, false, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Builtins::Generate_JSBuiltinsConstructStub(MacroAssembler* masm) {
|
|
||||||
Generate_JSConstructStubHelper(masm, false, false, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Builtins::Generate_JSBuiltinsConstructStubForBase(MacroAssembler* masm) {
|
|
||||||
Generate_JSConstructStubHelper(masm, false, true, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Builtins::Generate_JSBuiltinsConstructStubForDerived(
|
|
||||||
MacroAssembler* masm) {
|
MacroAssembler* masm) {
|
||||||
Generate_JSConstructStubHelper(masm, false, false, true);
|
Generate_JSConstructStubGeneric(masm, true);
|
||||||
|
}
|
||||||
|
void Builtins::Generate_JSConstructStubGenericUnrestrictedReturn(
|
||||||
|
MacroAssembler* masm) {
|
||||||
|
Generate_JSConstructStubGeneric(masm, false);
|
||||||
|
}
|
||||||
|
void Builtins::Generate_JSConstructStubApi(MacroAssembler* masm) {
|
||||||
|
Generate_JSBuiltinsConstructStubHelper(masm);
|
||||||
|
}
|
||||||
|
void Builtins::Generate_JSBuiltinsConstructStub(MacroAssembler* masm) {
|
||||||
|
Generate_JSBuiltinsConstructStubHelper(masm);
|
||||||
}
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
|
@ -442,9 +442,7 @@ void Builtins::Generate_InOptimizationQueue(MacroAssembler* masm) {
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
void Generate_JSConstructStubHelper(MacroAssembler* masm, bool is_api_function,
|
void Generate_JSBuiltinsConstructStubHelper(MacroAssembler* masm) {
|
||||||
bool create_implicit_receiver,
|
|
||||||
bool disallow_non_object_return) {
|
|
||||||
Label post_instantiation_deopt_entry;
|
Label post_instantiation_deopt_entry;
|
||||||
// ----------- S t a t e -------------
|
// ----------- S t a t e -------------
|
||||||
// -- r2 : number of arguments
|
// -- r2 : number of arguments
|
||||||
@ -455,52 +453,18 @@ void Generate_JSConstructStubHelper(MacroAssembler* masm, bool is_api_function,
|
|||||||
// -- sp[...]: constructor arguments
|
// -- sp[...]: constructor arguments
|
||||||
// -----------------------------------
|
// -----------------------------------
|
||||||
|
|
||||||
Isolate* isolate = masm->isolate();
|
|
||||||
|
|
||||||
// Enter a construct frame.
|
// Enter a construct frame.
|
||||||
{
|
{
|
||||||
FrameAndConstantPoolScope scope(masm, StackFrame::CONSTRUCT);
|
FrameAndConstantPoolScope scope(masm, StackFrame::CONSTRUCT);
|
||||||
|
|
||||||
// Preserve the incoming parameters on the stack.
|
// Preserve the incoming parameters on the stack.
|
||||||
|
__ SmiTag(r2);
|
||||||
if (!create_implicit_receiver) {
|
__ Push(cp, r2);
|
||||||
__ SmiTag(r6, r2);
|
__ SmiUntag(r2);
|
||||||
__ LoadAndTestP(r6, r6);
|
// The receiver for the builtin/api call.
|
||||||
__ Push(cp, r6);
|
__ PushRoot(Heap::kTheHoleValueRootIndex);
|
||||||
__ PushRoot(Heap::kTheHoleValueRootIndex);
|
|
||||||
} else {
|
|
||||||
__ SmiTag(r2);
|
|
||||||
__ Push(cp, r2);
|
|
||||||
|
|
||||||
// Allocate the new receiver object.
|
|
||||||
__ Push(r3, r5);
|
|
||||||
__ Call(CodeFactory::FastNewObject(masm->isolate()).code(),
|
|
||||||
RelocInfo::CODE_TARGET);
|
|
||||||
__ LoadRR(r6, r2);
|
|
||||||
__ Pop(r3, r5);
|
|
||||||
|
|
||||||
// ----------- S t a t e -------------
|
|
||||||
// -- r3: constructor function
|
|
||||||
// -- r5: new target
|
|
||||||
// -- r6: newly allocated object
|
|
||||||
// -----------------------------------
|
|
||||||
|
|
||||||
// Retrieve smi-tagged arguments count from the stack.
|
|
||||||
__ LoadP(r2, MemOperand(sp));
|
|
||||||
__ SmiUntag(r2);
|
|
||||||
__ LoadAndTestP(r2, r2);
|
|
||||||
|
|
||||||
// Push the allocated receiver to the stack. 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.
|
|
||||||
__ Push(r6, r6);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deoptimizer re-enters stub code here.
|
|
||||||
__ bind(&post_instantiation_deopt_entry);
|
|
||||||
|
|
||||||
// Set up pointer to last argument.
|
// Set up pointer to last argument.
|
||||||
__ la(r4, MemOperand(fp, StandardFrameConstants::kCallerSPOffset));
|
__ la(r6, MemOperand(fp, StandardFrameConstants::kCallerSPOffset));
|
||||||
|
|
||||||
// Copy arguments and receiver to the expression stack.
|
// Copy arguments and receiver to the expression stack.
|
||||||
// r2: number of arguments
|
// r2: number of arguments
|
||||||
@ -518,7 +482,7 @@ void Generate_JSConstructStubHelper(MacroAssembler* masm, bool is_api_function,
|
|||||||
__ LoadRR(r1, r2);
|
__ LoadRR(r1, r2);
|
||||||
__ bind(&loop);
|
__ bind(&loop);
|
||||||
__ lay(ip, MemOperand(ip, -kPointerSize));
|
__ lay(ip, MemOperand(ip, -kPointerSize));
|
||||||
__ LoadP(r0, MemOperand(ip, r4));
|
__ LoadP(r0, MemOperand(ip, r6));
|
||||||
__ StoreP(r0, MemOperand(ip, sp));
|
__ StoreP(r0, MemOperand(ip, sp));
|
||||||
__ BranchOnCount(r1, &loop);
|
__ BranchOnCount(r1, &loop);
|
||||||
__ bind(&no_args);
|
__ bind(&no_args);
|
||||||
@ -532,148 +496,228 @@ void Generate_JSConstructStubHelper(MacroAssembler* masm, bool is_api_function,
|
|||||||
__ InvokeFunction(r3, r5, actual, CALL_FUNCTION,
|
__ InvokeFunction(r3, r5, actual, CALL_FUNCTION,
|
||||||
CheckDebugStepCallWrapper());
|
CheckDebugStepCallWrapper());
|
||||||
|
|
||||||
// Store offset of return address for deoptimizer.
|
|
||||||
if (create_implicit_receiver && !disallow_non_object_return &&
|
|
||||||
!is_api_function) {
|
|
||||||
masm->isolate()->heap()->SetConstructStubInvokeDeoptPCOffset(
|
|
||||||
masm->pc_offset());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Restore context from the frame.
|
// Restore context from the frame.
|
||||||
// r2: result
|
|
||||||
// sp[0]: receiver
|
|
||||||
// sp[1]: number of arguments (smi-tagged)
|
|
||||||
__ LoadP(cp, MemOperand(fp, ConstructFrameConstants::kContextOffset));
|
__ LoadP(cp, MemOperand(fp, ConstructFrameConstants::kContextOffset));
|
||||||
|
// Restore smi-tagged arguments count from the frame.
|
||||||
if (create_implicit_receiver) {
|
__ LoadP(r3, MemOperand(fp, ConstructFrameConstants::kLengthOffset));
|
||||||
// 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, return_value, do_throw;
|
|
||||||
|
|
||||||
// If the result is a smi, it is *not* an object in the ECMA sense.
|
|
||||||
// r2: result
|
|
||||||
// sp[0]: receiver
|
|
||||||
// sp[1]: new.target
|
|
||||||
// sp[2]: number of arguments (smi-tagged)
|
|
||||||
// If the result is undefined, we jump out to using the implicit
|
|
||||||
// receiver, otherwise we do a smi check and fall through to
|
|
||||||
// check if the return value is a valid receiver.
|
|
||||||
if (disallow_non_object_return) {
|
|
||||||
__ CompareRoot(r2, Heap::kUndefinedValueRootIndex);
|
|
||||||
__ beq(&use_receiver);
|
|
||||||
__ JumpIfSmi(r2, &do_throw);
|
|
||||||
} else {
|
|
||||||
__ JumpIfSmi(r2, &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.
|
|
||||||
__ CompareObjectType(r2, r3, r5, FIRST_JS_RECEIVER_TYPE);
|
|
||||||
__ bge(&return_value);
|
|
||||||
|
|
||||||
if (disallow_non_object_return) {
|
|
||||||
__ 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);
|
|
||||||
__ LoadP(r2, MemOperand(sp));
|
|
||||||
|
|
||||||
// Remove receiver from the stack, remove caller arguments, and
|
|
||||||
// return.
|
|
||||||
__ bind(&return_value);
|
|
||||||
// r2: result
|
|
||||||
// sp[0]: receiver (newly allocated object)
|
|
||||||
// sp[1]: number of arguments (smi-tagged)
|
|
||||||
__ LoadP(r3, MemOperand(sp, 1 * kPointerSize));
|
|
||||||
} else {
|
|
||||||
__ LoadP(r3, MemOperand(sp));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Leave construct frame.
|
// Leave construct frame.
|
||||||
}
|
}
|
||||||
|
// Remove caller arguments from the stack and return.
|
||||||
|
STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
|
||||||
|
|
||||||
// ES6 9.2.2. Step 13+
|
__ SmiToPtrArrayOffset(r3, r3);
|
||||||
// For derived class constructors, throw a TypeError here if the result
|
__ AddP(sp, sp, r3);
|
||||||
// is not a JSReceiver. For the base constructor, we've already checked
|
__ AddP(sp, sp, Operand(kPointerSize));
|
||||||
// the result, so we omit the check.
|
__ Ret();
|
||||||
if (disallow_non_object_return && !create_implicit_receiver) {
|
}
|
||||||
Label do_throw, dont_throw;
|
|
||||||
__ JumpIfSmi(r2, &do_throw);
|
// The construct stub for ES5 constructor functions and ES6 class constructors.
|
||||||
|
void Generate_JSConstructStubGeneric(MacroAssembler* masm,
|
||||||
|
bool restrict_constructor_return) {
|
||||||
|
// ----------- S t a t e -------------
|
||||||
|
// -- r2: number of arguments (untagged)
|
||||||
|
// -- r3: constructor function
|
||||||
|
// -- r5: new target
|
||||||
|
// -- cp: context
|
||||||
|
// -- lr: return address
|
||||||
|
// -- sp[...]: constructor arguments
|
||||||
|
// -----------------------------------
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
__ SmiTag(r2);
|
||||||
|
__ Push(cp, r2, r3, r5);
|
||||||
|
|
||||||
|
// ----------- S t a t e -------------
|
||||||
|
// -- sp[0*kPointerSize]: new target
|
||||||
|
// -- r3 and sp[1*kPointerSize]: constructor function
|
||||||
|
// -- sp[2*kPointerSize]: number of arguments (tagged)
|
||||||
|
// -- sp[3*kPointerSize]: context
|
||||||
|
// -----------------------------------
|
||||||
|
|
||||||
|
__ LoadP(r6, FieldMemOperand(r3, JSFunction::kSharedFunctionInfoOffset));
|
||||||
|
__ LoadlW(r6,
|
||||||
|
FieldMemOperand(r6, SharedFunctionInfo::kCompilerHintsOffset));
|
||||||
|
__ TestBitMask(r6,
|
||||||
|
FunctionKind::kDerivedConstructor
|
||||||
|
<< SharedFunctionInfo::kFunctionKindShift,
|
||||||
|
r0);
|
||||||
|
__ bne(¬_create_implicit_receiver);
|
||||||
|
|
||||||
|
// If not derived class constructor: Allocate the new receiver object.
|
||||||
|
__ IncrementCounter(masm->isolate()->counters()->constructed_objects(), 1,
|
||||||
|
r6, r7);
|
||||||
|
__ Call(CodeFactory::FastNewObject(masm->isolate()).code(),
|
||||||
|
RelocInfo::CODE_TARGET);
|
||||||
|
__ b(&post_instantiation_deopt_entry);
|
||||||
|
|
||||||
|
// Else: use TheHoleValue as receiver for constructor call
|
||||||
|
__ bind(¬_create_implicit_receiver);
|
||||||
|
__ LoadRoot(r2, Heap::kTheHoleValueRootIndex);
|
||||||
|
|
||||||
|
// ----------- S t a t e -------------
|
||||||
|
// -- r2: 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(r5);
|
||||||
|
// Push the allocated receiver to the stack. 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.
|
||||||
|
__ Push(r2, r2);
|
||||||
|
|
||||||
|
// ----------- S t a t e -------------
|
||||||
|
// -- r5: new target
|
||||||
|
// -- sp[0*kPointerSize]: implicit receiver
|
||||||
|
// -- sp[1*kPointerSize]: implicit receiver
|
||||||
|
// -- sp[2*kPointerSize]: constructor function
|
||||||
|
// -- sp[3*kPointerSize]: number of arguments (tagged)
|
||||||
|
// -- sp[4*kPointerSize]: context
|
||||||
|
// -----------------------------------
|
||||||
|
|
||||||
|
// Restore constructor function and argument count.
|
||||||
|
__ LoadP(r3, MemOperand(fp, ConstructFrameConstants::kConstructorOffset));
|
||||||
|
__ LoadP(r2, MemOperand(fp, ConstructFrameConstants::kLengthOffset));
|
||||||
|
__ SmiUntag(r2);
|
||||||
|
|
||||||
|
// Set up pointer to last argument.
|
||||||
|
__ la(r6, MemOperand(fp, StandardFrameConstants::kCallerSPOffset));
|
||||||
|
|
||||||
|
// Copy arguments and receiver to the expression stack.
|
||||||
|
Label loop, no_args;
|
||||||
|
// ----------- S t a t e -------------
|
||||||
|
// -- r2: number of arguments (untagged)
|
||||||
|
// -- r5: new target
|
||||||
|
// -- r6: pointer to last argument
|
||||||
|
// -- cr0: condition indicating whether r2 is zero
|
||||||
|
// -- sp[0*kPointerSize]: implicit receiver
|
||||||
|
// -- sp[1*kPointerSize]: implicit receiver
|
||||||
|
// -- r3 and sp[2*kPointerSize]: constructor function
|
||||||
|
// -- sp[3*kPointerSize]: number of arguments (tagged)
|
||||||
|
// -- sp[4*kPointerSize]: context
|
||||||
|
// -----------------------------------
|
||||||
|
|
||||||
|
__ beq(&no_args);
|
||||||
|
__ ShiftLeftP(ip, r2, Operand(kPointerSizeLog2));
|
||||||
|
__ SubP(sp, sp, ip);
|
||||||
|
__ LoadRR(r1, r2);
|
||||||
|
__ bind(&loop);
|
||||||
|
__ lay(ip, MemOperand(ip, -kPointerSize));
|
||||||
|
__ LoadP(r0, MemOperand(ip, r6));
|
||||||
|
__ StoreP(r0, MemOperand(ip, sp));
|
||||||
|
__ BranchOnCount(r1, &loop);
|
||||||
|
__ bind(&no_args);
|
||||||
|
|
||||||
|
// Call the function.
|
||||||
|
ParameterCount actual(r2);
|
||||||
|
__ InvokeFunction(r3, r5, actual, CALL_FUNCTION,
|
||||||
|
CheckDebugStepCallWrapper());
|
||||||
|
|
||||||
|
// ----------- S t a t e -------------
|
||||||
|
// -- r0: constructor result
|
||||||
|
// -- sp[0*kPointerSize]: implicit receiver
|
||||||
|
// -- sp[1*kPointerSize]: constructor function
|
||||||
|
// -- sp[2*kPointerSize]: number of arguments
|
||||||
|
// -- sp[3*kPointerSize]: context
|
||||||
|
// -----------------------------------
|
||||||
|
|
||||||
|
// Store offset of return address for deoptimizer.
|
||||||
|
masm->isolate()->heap()->SetConstructStubInvokeDeoptPCOffset(
|
||||||
|
masm->pc_offset());
|
||||||
|
|
||||||
|
// Restore the context from the frame.
|
||||||
|
__ LoadP(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, other_result, leave_frame;
|
||||||
|
|
||||||
|
// If the result is undefined, we jump out to using the implicit receiver.
|
||||||
|
__ JumpIfRoot(r2, Heap::kUndefinedValueRootIndex, &use_receiver);
|
||||||
|
|
||||||
|
// 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(r2, &other_result);
|
||||||
|
|
||||||
|
// 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);
|
STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
|
||||||
__ CompareObjectType(r2, r5, r5, FIRST_JS_RECEIVER_TYPE);
|
__ CompareObjectType(r2, r6, r6, FIRST_JS_RECEIVER_TYPE);
|
||||||
__ bge(&dont_throw);
|
__ bge(&leave_frame);
|
||||||
|
|
||||||
|
__ bind(&other_result);
|
||||||
|
// The result is now neither undefined nor an object.
|
||||||
|
if (restrict_constructor_return) {
|
||||||
|
// Throw if constructor function is a class constructor
|
||||||
|
__ LoadP(r6, MemOperand(fp, ConstructFrameConstants::kConstructorOffset));
|
||||||
|
__ LoadP(r6, FieldMemOperand(r6, JSFunction::kSharedFunctionInfoOffset));
|
||||||
|
__ LoadlW(r6,
|
||||||
|
FieldMemOperand(r6, SharedFunctionInfo::kCompilerHintsOffset));
|
||||||
|
__ TestBitMask(r6,
|
||||||
|
FunctionKind::kClassConstructor
|
||||||
|
<< SharedFunctionInfo::kFunctionKindShift,
|
||||||
|
r0);
|
||||||
|
__ beq(&use_receiver);
|
||||||
|
} else {
|
||||||
|
__ b(&use_receiver);
|
||||||
|
}
|
||||||
__ bind(&do_throw);
|
__ bind(&do_throw);
|
||||||
{
|
{
|
||||||
FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
|
FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
|
||||||
__ CallRuntime(Runtime::kThrowConstructorReturnedNonObject);
|
__ CallRuntime(Runtime::kThrowConstructorReturnedNonObject);
|
||||||
}
|
}
|
||||||
__ bind(&dont_throw);
|
|
||||||
|
// Throw away the result of the constructor invocation and use the
|
||||||
|
// on-stack receiver as the result.
|
||||||
|
__ bind(&use_receiver);
|
||||||
|
__ LoadP(r2, MemOperand(sp));
|
||||||
|
__ JumpIfRoot(r2, Heap::kTheHoleValueRootIndex, &do_throw);
|
||||||
|
|
||||||
|
__ bind(&leave_frame);
|
||||||
|
// Restore smi-tagged arguments count from the frame.
|
||||||
|
__ LoadP(r3, MemOperand(fp, ConstructFrameConstants::kLengthOffset));
|
||||||
|
// Leave construct frame.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Remove caller arguments from the stack and return.
|
||||||
|
STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
|
||||||
|
|
||||||
__ SmiToPtrArrayOffset(r3, r3);
|
__ SmiToPtrArrayOffset(r3, r3);
|
||||||
__ AddP(sp, sp, r3);
|
__ AddP(sp, sp, r3);
|
||||||
__ AddP(sp, sp, Operand(kPointerSize));
|
__ AddP(sp, sp, Operand(kPointerSize));
|
||||||
if (create_implicit_receiver) {
|
|
||||||
__ IncrementCounter(isolate->counters()->constructed_objects(), 1, r3, r4);
|
|
||||||
}
|
|
||||||
__ Ret();
|
__ Ret();
|
||||||
|
|
||||||
// Store offset of trampoline address for deoptimizer. This is the bailout
|
|
||||||
// point after the receiver instantiation but before the function invocation.
|
|
||||||
// We need to restore some registers in order to continue the above code.
|
|
||||||
if (create_implicit_receiver && !disallow_non_object_return &&
|
|
||||||
!is_api_function) {
|
|
||||||
masm->isolate()->heap()->SetConstructStubCreateDeoptPCOffset(
|
|
||||||
masm->pc_offset());
|
|
||||||
|
|
||||||
// ----------- S t a t e -------------
|
|
||||||
// -- r2 : newly allocated object
|
|
||||||
// -- sp[0] : constructor function
|
|
||||||
// -----------------------------------
|
|
||||||
|
|
||||||
__ pop(r3);
|
|
||||||
__ Push(r2, r2);
|
|
||||||
|
|
||||||
// Retrieve smi-tagged arguments count from the stack.
|
|
||||||
__ LoadP(r2, MemOperand(fp, ConstructFrameConstants::kLengthOffset));
|
|
||||||
__ SmiUntag(r2);
|
|
||||||
|
|
||||||
// Retrieve the new target value from the stack. This was placed into the
|
|
||||||
// frame description in place of the receiver by the optimizing compiler.
|
|
||||||
__ la(r5, MemOperand(fp, StandardFrameConstants::kCallerSPOffset));
|
|
||||||
__ ShiftLeftP(ip, r2, Operand(kPointerSizeLog2));
|
|
||||||
__ LoadP(r5, MemOperand(r5, ip));
|
|
||||||
|
|
||||||
// Continue with constructor function invocation.
|
|
||||||
__ b(&post_instantiation_deopt_entry);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) {
|
void Builtins::Generate_JSConstructStubGenericRestrictedReturn(
|
||||||
Generate_JSConstructStubHelper(masm, false, true, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Builtins::Generate_JSConstructStubApi(MacroAssembler* masm) {
|
|
||||||
Generate_JSConstructStubHelper(masm, true, false, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Builtins::Generate_JSBuiltinsConstructStub(MacroAssembler* masm) {
|
|
||||||
Generate_JSConstructStubHelper(masm, false, false, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Builtins::Generate_JSBuiltinsConstructStubForBase(MacroAssembler* masm) {
|
|
||||||
Generate_JSConstructStubHelper(masm, false, true, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Builtins::Generate_JSBuiltinsConstructStubForDerived(
|
|
||||||
MacroAssembler* masm) {
|
MacroAssembler* masm) {
|
||||||
Generate_JSConstructStubHelper(masm, false, false, true);
|
Generate_JSConstructStubGeneric(masm, true);
|
||||||
|
}
|
||||||
|
void Builtins::Generate_JSConstructStubGenericUnrestrictedReturn(
|
||||||
|
MacroAssembler* masm) {
|
||||||
|
Generate_JSConstructStubGeneric(masm, false);
|
||||||
|
}
|
||||||
|
void Builtins::Generate_JSConstructStubApi(MacroAssembler* masm) {
|
||||||
|
Generate_JSBuiltinsConstructStubHelper(masm);
|
||||||
|
}
|
||||||
|
void Builtins::Generate_JSBuiltinsConstructStub(MacroAssembler* masm) {
|
||||||
|
Generate_JSBuiltinsConstructStubHelper(masm);
|
||||||
}
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
|
Loading…
Reference in New Issue
Block a user