PPC: [builtins] Add support for NewTarget to Execution::New.
Port 1dfac69f1f
Original commit message:
Introduce new builtins Construct and ConstructFunction (in line
with the Call and CallFunction builtins that we already have) as
proper bottleneck for Construct and [[Construct]] on JSFunctions.
Use these builtins to support passing NewTarget from C++ to
JavaScript land.
Long-term we want the CallConstructStub to be used for
gathering feedback on entry to construction chain (i.e. the
initial new Foo), and use the Construct builtins to do the
actual work inside the construction chain (i.e. calling into
super and stuff).
R=bmeurer@chromium.org, joransiu@ca.ibm.com, jyan@ca.ibm.com, michael_dawson@ca.ibm.com, dstence@us.ibm.com
BUG=v8:4430
LOG=n
Review URL: https://codereview.chromium.org/1358203002
Cr-Commit-Position: refs/heads/master@{#30872}
This commit is contained in:
parent
3028534498
commit
0ad9b9e523
@ -4015,14 +4015,14 @@ void FullCodeGenerator::EmitDefaultConstructorCallSuper(CallRuntime* expr) {
|
|||||||
__ push(result_register());
|
__ push(result_register());
|
||||||
__ mr(r4, result_register());
|
__ mr(r4, result_register());
|
||||||
|
|
||||||
// Load original constructor into r7.
|
// Load original constructor into r6.
|
||||||
__ LoadP(r7, MemOperand(sp, 1 * kPointerSize));
|
__ LoadP(r6, MemOperand(sp, 1 * kPointerSize));
|
||||||
|
|
||||||
// Check if the calling frame is an arguments adaptor frame.
|
// Check if the calling frame is an arguments adaptor frame.
|
||||||
Label adaptor_frame, args_set_up, runtime;
|
Label adaptor_frame, args_set_up, runtime;
|
||||||
__ LoadP(r5, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
|
__ LoadP(r5, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
|
||||||
__ LoadP(r6, MemOperand(r5, StandardFrameConstants::kContextOffset));
|
__ LoadP(r7, MemOperand(r5, StandardFrameConstants::kContextOffset));
|
||||||
__ CmpSmiLiteral(r6, Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR), r0);
|
__ CmpSmiLiteral(r7, Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR), r0);
|
||||||
__ beq(&adaptor_frame);
|
__ beq(&adaptor_frame);
|
||||||
|
|
||||||
// default constructor has no arguments, so no adaptor frame means no args.
|
// default constructor has no arguments, so no adaptor frame means no args.
|
||||||
@ -4044,16 +4044,13 @@ void FullCodeGenerator::EmitDefaultConstructorCallSuper(CallRuntime* expr) {
|
|||||||
__ mtctr(r3);
|
__ mtctr(r3);
|
||||||
__ bind(&loop);
|
__ bind(&loop);
|
||||||
// Pre-decrement in order to skip receiver.
|
// Pre-decrement in order to skip receiver.
|
||||||
__ LoadPU(r6, MemOperand(r5, -kPointerSize));
|
__ LoadPU(r7, MemOperand(r5, -kPointerSize));
|
||||||
__ Push(r6);
|
__ Push(r7);
|
||||||
__ bdnz(&loop);
|
__ bdnz(&loop);
|
||||||
}
|
}
|
||||||
|
|
||||||
__ bind(&args_set_up);
|
__ bind(&args_set_up);
|
||||||
__ LoadRoot(r5, Heap::kUndefinedValueRootIndex);
|
__ Call(isolate()->builtins()->Construct(), RelocInfo::CONSTRUCT_CALL);
|
||||||
|
|
||||||
CallConstructStub stub(isolate(), SUPER_CONSTRUCTOR_CALL);
|
|
||||||
__ Call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL);
|
|
||||||
|
|
||||||
// Restore context register.
|
// Restore context register.
|
||||||
__ LoadP(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
|
__ LoadP(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
|
||||||
|
@ -23,12 +23,19 @@ void Builtins::Generate_Adaptor(MacroAssembler* masm, CFunctionId id,
|
|||||||
// -- r3 : number of arguments excluding receiver
|
// -- r3 : number of arguments excluding receiver
|
||||||
// -- r4 : called function (only guaranteed when
|
// -- r4 : called function (only guaranteed when
|
||||||
// extra_args requires it)
|
// extra_args requires it)
|
||||||
// -- cp : context
|
|
||||||
// -- sp[0] : last argument
|
// -- sp[0] : last argument
|
||||||
// -- ...
|
// -- ...
|
||||||
// -- sp[4 * (argc - 1)] : first argument (argc == r0)
|
// -- sp[4 * (argc - 1)] : first argument (argc == r0)
|
||||||
// -- sp[4 * argc] : receiver
|
// -- sp[4 * argc] : receiver
|
||||||
// -----------------------------------
|
// -----------------------------------
|
||||||
|
__ AssertFunction(r4);
|
||||||
|
|
||||||
|
// Make sure we operate in the context of the called function (for example
|
||||||
|
// ConstructStubs implemented in C++ will be run in the context of the caller
|
||||||
|
// instead of the callee, due to the way that [[Construct]] is defined for
|
||||||
|
// ordinary functions).
|
||||||
|
// TODO(bmeurer): Can we make this more robust?
|
||||||
|
__ LoadP(cp, FieldMemOperand(r4, JSFunction::kContextOffset));
|
||||||
|
|
||||||
// Insert extra arguments.
|
// Insert extra arguments.
|
||||||
int num_extra_args = 0;
|
int num_extra_args = 0;
|
||||||
@ -725,7 +732,7 @@ static void Generate_CheckStackOverflow(MacroAssembler* masm,
|
|||||||
static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm,
|
static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm,
|
||||||
bool is_construct) {
|
bool is_construct) {
|
||||||
// Called from Generate_JS_Entry
|
// Called from Generate_JS_Entry
|
||||||
// r3: code entry
|
// r3: new.target
|
||||||
// r4: function
|
// r4: function
|
||||||
// r5: receiver
|
// r5: receiver
|
||||||
// r6: argc
|
// r6: argc
|
||||||
@ -740,14 +747,16 @@ static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm,
|
|||||||
{
|
{
|
||||||
FrameScope scope(masm, StackFrame::INTERNAL);
|
FrameScope scope(masm, StackFrame::INTERNAL);
|
||||||
|
|
||||||
// Set up the context from the function argument.
|
// Setup the context (we need to use the caller context from the isolate).
|
||||||
__ LoadP(cp, FieldMemOperand(r4, JSFunction::kContextOffset));
|
ExternalReference context_address(Isolate::kContextAddress,
|
||||||
|
masm->isolate());
|
||||||
|
__ mov(cp, Operand(context_address));
|
||||||
|
__ LoadP(cp, MemOperand(cp));
|
||||||
|
|
||||||
__ InitializeRootRegister();
|
__ InitializeRootRegister();
|
||||||
|
|
||||||
// Push the function and the receiver onto the stack.
|
// Push the function and the receiver onto the stack.
|
||||||
__ push(r4);
|
__ Push(r4, r5);
|
||||||
__ push(r5);
|
|
||||||
|
|
||||||
// Check if we have enough stack space to push all arguments.
|
// Check if we have enough stack space to push all arguments.
|
||||||
// The function is the first thing that was pushed above after entering
|
// The function is the first thing that was pushed above after entering
|
||||||
@ -775,6 +784,11 @@ static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm,
|
|||||||
__ cmp(r7, r5);
|
__ cmp(r7, r5);
|
||||||
__ bne(&loop);
|
__ bne(&loop);
|
||||||
|
|
||||||
|
// Setup new.target and argc.
|
||||||
|
__ mr(r7, r3);
|
||||||
|
__ mr(r3, r6);
|
||||||
|
__ mr(r6, r7);
|
||||||
|
|
||||||
// Initialize all JavaScript callee-saved registers, since they will be seen
|
// Initialize all JavaScript callee-saved registers, since they will be seen
|
||||||
// by the garbage collector as part of handlers.
|
// by the garbage collector as part of handlers.
|
||||||
__ LoadRoot(r7, Heap::kUndefinedValueRootIndex);
|
__ LoadRoot(r7, Heap::kUndefinedValueRootIndex);
|
||||||
@ -783,16 +797,12 @@ static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm,
|
|||||||
__ mr(r16, r7);
|
__ mr(r16, r7);
|
||||||
__ mr(r17, r7);
|
__ mr(r17, r7);
|
||||||
|
|
||||||
// Invoke the code and pass argc as r3.
|
// Invoke the code.
|
||||||
__ mr(r3, r6);
|
Handle<Code> builtin = is_construct
|
||||||
if (is_construct) {
|
? masm->isolate()->builtins()->Construct()
|
||||||
// No type feedback cell is available
|
: masm->isolate()->builtins()->Call();
|
||||||
__ LoadRoot(r5, Heap::kUndefinedValueRootIndex);
|
__ Call(builtin, RelocInfo::CODE_TARGET);
|
||||||
CallConstructStub stub(masm->isolate(), NO_CALL_CONSTRUCTOR_FLAGS);
|
|
||||||
__ CallStub(&stub);
|
|
||||||
} else {
|
|
||||||
__ Call(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
|
|
||||||
}
|
|
||||||
// Exit the JS frame and remove the parameters (except function), and
|
// Exit the JS frame and remove the parameters (except function), and
|
||||||
// return.
|
// return.
|
||||||
}
|
}
|
||||||
@ -1638,6 +1648,67 @@ void Builtins::Generate_Call(MacroAssembler* masm) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// static
|
||||||
|
void Builtins::Generate_ConstructFunction(MacroAssembler* masm) {
|
||||||
|
// ----------- S t a t e -------------
|
||||||
|
// -- r3 : the number of arguments (not including the receiver)
|
||||||
|
// -- r4 : the constructor to call (checked to be a JSFunction)
|
||||||
|
// -- r6 : the original constructor (checked to be a JSFunction)
|
||||||
|
// -----------------------------------
|
||||||
|
__ AssertFunction(r4);
|
||||||
|
__ AssertFunction(r6);
|
||||||
|
|
||||||
|
// Calling convention for function specific ConstructStubs require
|
||||||
|
// r5 to contain either an AllocationSite or undefined.
|
||||||
|
__ LoadRoot(r5, Heap::kUndefinedValueRootIndex);
|
||||||
|
|
||||||
|
// Tail call to the function-specific construct stub (still in the caller
|
||||||
|
// context at this point).
|
||||||
|
__ LoadP(r7, FieldMemOperand(r4, JSFunction::kSharedFunctionInfoOffset));
|
||||||
|
__ LoadP(r7, FieldMemOperand(r7, SharedFunctionInfo::kConstructStubOffset));
|
||||||
|
__ addi(ip, r7, Operand(Code::kHeaderSize - kHeapObjectTag));
|
||||||
|
__ JumpToJSEntry(ip);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// static
|
||||||
|
void Builtins::Generate_Construct(MacroAssembler* masm) {
|
||||||
|
// ----------- S t a t e -------------
|
||||||
|
// -- r3 : the number of arguments (not including the receiver)
|
||||||
|
// -- r4 : the constructor to call (can be any Object)
|
||||||
|
// -- r6 : the original constructor (either the same as the constructor or
|
||||||
|
// the JSFunction on which new was invoked initially)
|
||||||
|
// -----------------------------------
|
||||||
|
|
||||||
|
Label slow;
|
||||||
|
__ JumpIfSmi(r4, &slow);
|
||||||
|
__ CompareObjectType(r4, r8, r8, JS_FUNCTION_TYPE);
|
||||||
|
__ Jump(masm->isolate()->builtins()->ConstructFunction(),
|
||||||
|
RelocInfo::CODE_TARGET, eq);
|
||||||
|
__ cmpi(r8, Operand(JS_FUNCTION_PROXY_TYPE));
|
||||||
|
__ bne(&slow);
|
||||||
|
|
||||||
|
// TODO(neis): This doesn't match the ES6 spec for [[Construct]] on proxies.
|
||||||
|
__ LoadP(r4, FieldMemOperand(r4, JSFunctionProxy::kConstructTrapOffset));
|
||||||
|
__ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
|
||||||
|
|
||||||
|
__ bind(&slow);
|
||||||
|
{
|
||||||
|
// Determine the delegate for the target (if any).
|
||||||
|
FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
|
||||||
|
__ SmiTag(r3);
|
||||||
|
__ Push(r3, r4);
|
||||||
|
__ CallRuntime(Runtime::kGetConstructorDelegate, 1);
|
||||||
|
__ mr(r4, r3);
|
||||||
|
__ Pop(r3);
|
||||||
|
__ SmiUntag(r3);
|
||||||
|
}
|
||||||
|
// The delegate is always a regular function.
|
||||||
|
__ AssertFunction(r4);
|
||||||
|
__ Jump(masm->isolate()->builtins()->CallFunction(), RelocInfo::CODE_TARGET);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// static
|
// static
|
||||||
void Builtins::Generate_PushArgsAndCall(MacroAssembler* masm) {
|
void Builtins::Generate_PushArgsAndCall(MacroAssembler* masm) {
|
||||||
// ----------- S t a t e -------------
|
// ----------- S t a t e -------------
|
||||||
|
@ -2643,13 +2643,13 @@ void CallConstructStub::Generate(MacroAssembler* masm) {
|
|||||||
// r5 : feedback vector
|
// r5 : feedback vector
|
||||||
// r6 : slot in feedback vector (Smi, for RecordCallTarget)
|
// r6 : slot in feedback vector (Smi, for RecordCallTarget)
|
||||||
// r7 : original constructor (for IsSuperConstructorCall)
|
// r7 : original constructor (for IsSuperConstructorCall)
|
||||||
Label slow, non_function_call;
|
|
||||||
|
|
||||||
|
Label non_function;
|
||||||
// Check that the function is not a smi.
|
// Check that the function is not a smi.
|
||||||
__ JumpIfSmi(r4, &non_function_call);
|
__ JumpIfSmi(r4, &non_function);
|
||||||
// Check that the function is a JSFunction.
|
// Check that the function is a JSFunction.
|
||||||
__ CompareObjectType(r4, r8, r8, JS_FUNCTION_TYPE);
|
__ CompareObjectType(r4, r8, r8, JS_FUNCTION_TYPE);
|
||||||
__ bne(&slow);
|
__ bne(&non_function);
|
||||||
|
|
||||||
if (RecordCallTarget()) {
|
if (RecordCallTarget()) {
|
||||||
GenerateRecordCallTarget(masm, IsSuperConstructorCall());
|
GenerateRecordCallTarget(masm, IsSuperConstructorCall());
|
||||||
@ -2680,42 +2680,16 @@ void CallConstructStub::Generate(MacroAssembler* masm) {
|
|||||||
__ mr(r6, r4);
|
__ mr(r6, r4);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Jump to the function-specific construct stub.
|
// Tail call to the function-specific construct stub (still in the caller
|
||||||
Register jmp_reg = r7;
|
// context at this point).
|
||||||
__ LoadP(jmp_reg, FieldMemOperand(r4, JSFunction::kSharedFunctionInfoOffset));
|
__ LoadP(r7, FieldMemOperand(r4, JSFunction::kSharedFunctionInfoOffset));
|
||||||
__ LoadP(jmp_reg,
|
__ LoadP(r7, FieldMemOperand(r7, SharedFunctionInfo::kConstructStubOffset));
|
||||||
FieldMemOperand(jmp_reg, SharedFunctionInfo::kConstructStubOffset));
|
__ addi(ip, r7, Operand(Code::kHeaderSize - kHeapObjectTag));
|
||||||
__ addi(ip, jmp_reg, Operand(Code::kHeaderSize - kHeapObjectTag));
|
|
||||||
__ JumpToJSEntry(ip);
|
__ JumpToJSEntry(ip);
|
||||||
|
|
||||||
// r3: number of arguments
|
__ bind(&non_function);
|
||||||
// r4: called object
|
__ mr(r6, r4);
|
||||||
// r8: object type
|
__ Jump(isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET);
|
||||||
__ bind(&slow);
|
|
||||||
{
|
|
||||||
STATIC_ASSERT(JS_FUNCTION_PROXY_TYPE < 0xffffu);
|
|
||||||
__ cmpi(r8, Operand(JS_FUNCTION_PROXY_TYPE));
|
|
||||||
__ bne(&non_function_call);
|
|
||||||
// TODO(neis): This doesn't match the ES6 spec for [[Construct]] on proxies.
|
|
||||||
__ LoadP(r4, FieldMemOperand(r4, JSFunctionProxy::kConstructTrapOffset));
|
|
||||||
__ Jump(isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
|
|
||||||
|
|
||||||
__ bind(&non_function_call);
|
|
||||||
{
|
|
||||||
// Determine the delegate for the target (if any).
|
|
||||||
FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
|
|
||||||
__ SmiTag(r3);
|
|
||||||
__ Push(r3, r4);
|
|
||||||
__ CallRuntime(Runtime::kGetConstructorDelegate, 1);
|
|
||||||
__ mr(r4, r3);
|
|
||||||
__ pop(r3);
|
|
||||||
__ SmiUntag(r3);
|
|
||||||
}
|
|
||||||
// The delegate is always a regular function.
|
|
||||||
__ AssertFunction(r4);
|
|
||||||
__ Jump(masm->isolate()->builtins()->CallFunction(),
|
|
||||||
RelocInfo::CODE_TARGET);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user