Commit 48cb56ab authored by akos.palfi's avatar akos.palfi Committed by Commit bot

MIPS: new classes: change semantics of super(...) call and add new.target to construct stub.

Port 22ce08ad

BUG=

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

Cr-Commit-Position: refs/heads/master@{#26232}
parent ce457e2b
......@@ -315,6 +315,36 @@ void Builtins::Generate_InOptimizationQueue(MacroAssembler* masm) {
}
static void Generate_Runtime_NewObject(MacroAssembler* masm,
bool create_memento,
Register original_constructor,
Label* count_incremented,
Label* allocated) {
if (create_memento) {
// Get the cell or allocation site.
__ lw(a2, MemOperand(sp, 2 * kPointerSize));
__ push(a2);
}
__ push(a1); // argument for Runtime_NewObject
__ push(original_constructor); // original constructor
if (create_memento) {
__ CallRuntime(Runtime::kNewObjectWithAllocationSite, 3);
} else {
__ CallRuntime(Runtime::kNewObject, 2);
}
__ mov(t4, v0);
// Runtime_NewObjectWithAllocationSite increments allocation count.
// Skip the increment.
if (create_memento) {
__ jmp(count_incremented);
} else {
__ jmp(allocated);
}
}
static void Generate_JSConstructStubHelper(MacroAssembler* masm,
bool is_api_function,
bool create_memento) {
......@@ -322,6 +352,7 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
// -- a0 : number of arguments
// -- a1 : constructor function
// -- a2 : allocation site or undefined
// -- a3 : original constructor
// -- ra : return address
// -- sp[...]: constructor arguments
// -----------------------------------
......@@ -343,7 +374,7 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
FrameScope scope(masm, StackFrame::CONSTRUCT);
if (create_memento) {
__ AssertUndefinedOrAllocationSite(a2, a3);
__ AssertUndefinedOrAllocationSite(a2, t0);
__ push(a2);
}
......@@ -351,7 +382,14 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
__ sll(a0, a0, kSmiTagSize); // Tag arguments count.
__ MultiPushReversed(a0.bit() | a1.bit());
Label rt_call, allocated;
Label rt_call, allocated, normal_new, count_incremented;
__ Branch(&normal_new, eq, a1, Operand(a3));
// Original constructor and function are different.
Generate_Runtime_NewObject(masm, create_memento, a3, &count_incremented,
&allocated);
__ bind(&normal_new);
// Try to allocate the object without transitioning into C code. If any of
// the preconditions is not met, the code bails out to the runtime call.
if (FLAG_inline_new) {
......@@ -590,27 +628,8 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
// Allocate the new receiver object using the runtime call.
// a1: constructor function
__ bind(&rt_call);
if (create_memento) {
// Get the cell or allocation site.
__ lw(a2, MemOperand(sp, 2 * kPointerSize));
__ push(a2);
}
__ push(a1); // Argument for Runtime_NewObject.
if (create_memento) {
__ CallRuntime(Runtime::kNewObjectWithAllocationSite, 2);
} else {
__ CallRuntime(Runtime::kNewObject, 1);
}
__ mov(t4, v0);
// If we ended up using the runtime, and we want a memento, then the
// runtime call made it for us, and we shouldn't do create count
// increment.
Label count_incremented;
if (create_memento) {
__ jmp(&count_incremented);
}
Generate_Runtime_NewObject(masm, create_memento, a1, &count_incremented,
&allocated);
// Receiver for constructor call allocated.
// t4: JSObject
......
......@@ -2704,6 +2704,9 @@ void CallConstructStub::Generate(MacroAssembler* masm) {
__ AssertUndefinedOrAllocationSite(a2, t1);
}
// Pass function as original constructor.
__ mov(a3, a1);
// Jump to the function-specific construct stub.
Register jmp_reg = t0;
__ lw(jmp_reg, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
......
......@@ -3146,11 +3146,15 @@ void FullCodeGenerator::VisitCall(Call* expr) {
}
}
} else if (call_type == Call::SUPER_CALL) {
SuperReference* super_ref = callee->AsSuperReference();
EmitLoadSuperConstructor(super_ref);
__ Push(result_register());
VisitForStackValue(super_ref->this_var());
EmitCall(expr, CallICState::METHOD);
if (FLAG_experimental_classes) {
EmitSuperConstructorCall(expr);
} else {
SuperReference* super_ref = callee->AsSuperReference();
EmitLoadSuperConstructor(super_ref);
__ Push(result_register());
VisitForStackValue(super_ref->this_var());
EmitCall(expr, CallICState::METHOD);
}
} else {
DCHECK(call_type == Call::OTHER_CALL);
// Call to an arbitrary expression not handled specially above.
......@@ -3218,6 +3222,51 @@ void FullCodeGenerator::VisitCallNew(CallNew* expr) {
}
void FullCodeGenerator::EmitSuperConstructorCall(Call* expr) {
SuperReference* super_ref = expr->expression()->AsSuperReference();
EmitLoadSuperConstructor(super_ref);
__ push(result_register());
// Push the arguments ("left-to-right") on the stack.
ZoneList<Expression*>* args = expr->arguments();
int arg_count = args->length();
for (int i = 0; i < arg_count; i++) {
VisitForStackValue(args->at(i));
}
// Call the construct call builtin that handles allocation and
// constructor invocation.
SetSourcePosition(expr->position());
// Load function and argument count into a1 and a0.
__ li(a0, Operand(arg_count));
__ lw(a1, MemOperand(sp, arg_count * kPointerSize));
// Record call targets in unoptimized code.
if (FLAG_pretenuring_call_new) {
UNREACHABLE();
/* TODO(dslomov): support pretenuring.
EnsureSlotContainsAllocationSite(expr->AllocationSiteFeedbackSlot());
DCHECK(expr->AllocationSiteFeedbackSlot().ToInt() ==
expr->CallNewFeedbackSlot().ToInt() + 1);
*/
}
__ li(a2, FeedbackVector());
__ li(a3, Operand(SmiFromSlot(expr->CallFeedbackSlot())));
// TODO(dslomov): use a different stub and propagate new.target.
CallConstructStub stub(isolate(), RECORD_CONSTRUCTOR_TARGET);
__ Call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL);
RecordJSReturnSite(expr);
// TODO(dslomov): implement TDZ for `this`.
EmitVariableAssignment(super_ref->this_var()->var(), Token::ASSIGN);
context()->Plug(v0);
}
void FullCodeGenerator::EmitIsSmi(CallRuntime* expr) {
ZoneList<Expression*>* args = expr->arguments();
DCHECK(args->length() == 1);
......
......@@ -314,6 +314,36 @@ void Builtins::Generate_InOptimizationQueue(MacroAssembler* masm) {
}
static void Generate_Runtime_NewObject(MacroAssembler* masm,
bool create_memento,
Register original_constructor,
Label* count_incremented,
Label* allocated) {
if (create_memento) {
// Get the cell or allocation site.
__ ld(a2, MemOperand(sp, 2 * kPointerSize));
__ push(a2);
}
__ push(a1); // argument for Runtime_NewObject
__ push(original_constructor); // original constructor
if (create_memento) {
__ CallRuntime(Runtime::kNewObjectWithAllocationSite, 3);
} else {
__ CallRuntime(Runtime::kNewObject, 2);
}
__ mov(t0, v0);
// Runtime_NewObjectWithAllocationSite increments allocation count.
// Skip the increment.
if (create_memento) {
__ jmp(count_incremented);
} else {
__ jmp(allocated);
}
}
static void Generate_JSConstructStubHelper(MacroAssembler* masm,
bool is_api_function,
bool create_memento) {
......@@ -321,6 +351,7 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
// -- a0 : number of arguments
// -- a1 : constructor function
// -- a2 : allocation site or undefined
// -- a3 : original constructor
// -- ra : return address
// -- sp[...]: constructor arguments
// -----------------------------------
......@@ -342,7 +373,7 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
FrameScope scope(masm, StackFrame::CONSTRUCT);
if (create_memento) {
__ AssertUndefinedOrAllocationSite(a2, a3);
__ AssertUndefinedOrAllocationSite(a2, t0);
__ push(a2);
}
......@@ -351,7 +382,14 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
__ dsll32(a0, a0, 0);
__ MultiPushReversed(a0.bit() | a1.bit());
Label rt_call, allocated;
Label rt_call, allocated, normal_new, count_incremented;
__ Branch(&normal_new, eq, a1, Operand(a3));
// Original constructor and function are different.
Generate_Runtime_NewObject(masm, create_memento, a3, &count_incremented,
&allocated);
__ bind(&normal_new);
// Try to allocate the object without transitioning into C code. If any of
// the preconditions is not met, the code bails out to the runtime call.
if (FLAG_inline_new) {
......@@ -597,27 +635,9 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
// Allocate the new receiver object using the runtime call.
// a1: constructor function
__ bind(&rt_call);
if (create_memento) {
// Get the cell or allocation site.
__ ld(a2, MemOperand(sp, 2 * kPointerSize));
__ push(a2);
}
__ push(a1); // Argument for Runtime_NewObject.
if (create_memento) {
__ CallRuntime(Runtime::kNewObjectWithAllocationSite, 2);
} else {
__ CallRuntime(Runtime::kNewObject, 1);
}
__ mov(t0, v0);
Generate_Runtime_NewObject(masm, create_memento, a1, &count_incremented,
&allocated);
// If we ended up using the runtime, and we want a memento, then the
// runtime call made it for us, and we shouldn't do create count
// increment.
Label count_incremented;
if (create_memento) {
__ jmp(&count_incremented);
}
// Receiver for constructor call allocated.
// t0: JSObject
......
......@@ -2739,6 +2739,9 @@ void CallConstructStub::Generate(MacroAssembler* masm) {
__ AssertUndefinedOrAllocationSite(a2, a5);
}
// Pass function as original constructor.
__ mov(a3, a1);
// Jump to the function-specific construct stub.
Register jmp_reg = a4;
__ ld(jmp_reg, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
......
......@@ -3145,11 +3145,15 @@ void FullCodeGenerator::VisitCall(Call* expr) {
}
}
} else if (call_type == Call::SUPER_CALL) {
SuperReference* super_ref = callee->AsSuperReference();
EmitLoadSuperConstructor(super_ref);
__ Push(result_register());
VisitForStackValue(super_ref->this_var());
EmitCall(expr, CallICState::METHOD);
if (FLAG_experimental_classes) {
EmitSuperConstructorCall(expr);
} else {
SuperReference* super_ref = callee->AsSuperReference();
EmitLoadSuperConstructor(super_ref);
__ Push(result_register());
VisitForStackValue(super_ref->this_var());
EmitCall(expr, CallICState::METHOD);
}
} else {
DCHECK(call_type == Call::OTHER_CALL);
// Call to an arbitrary expression not handled specially above.
......@@ -3216,6 +3220,51 @@ void FullCodeGenerator::VisitCallNew(CallNew* expr) {
}
void FullCodeGenerator::EmitSuperConstructorCall(Call* expr) {
SuperReference* super_ref = expr->expression()->AsSuperReference();
EmitLoadSuperConstructor(super_ref);
__ push(result_register());
// Push the arguments ("left-to-right") on the stack.
ZoneList<Expression*>* args = expr->arguments();
int arg_count = args->length();
for (int i = 0; i < arg_count; i++) {
VisitForStackValue(args->at(i));
}
// Call the construct call builtin that handles allocation and
// constructor invocation.
SetSourcePosition(expr->position());
// Load function and argument count into a1 and a0.
__ li(a0, Operand(arg_count));
__ ld(a1, MemOperand(sp, arg_count * kPointerSize));
// Record call targets in unoptimized code.
if (FLAG_pretenuring_call_new) {
UNREACHABLE();
/* TODO(dslomov): support pretenuring.
EnsureSlotContainsAllocationSite(expr->AllocationSiteFeedbackSlot());
DCHECK(expr->AllocationSiteFeedbackSlot().ToInt() ==
expr->CallNewFeedbackSlot().ToInt() + 1);
*/
}
__ li(a2, FeedbackVector());
__ li(a3, Operand(SmiFromSlot(expr->CallFeedbackSlot())));
// TODO(dslomov): use a different stub and propagate new.target.
CallConstructStub stub(isolate(), RECORD_CONSTRUCTOR_TARGET);
__ Call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL);
RecordJSReturnSite(expr);
// TODO(dslomov): implement TDZ for `this`.
EmitVariableAssignment(super_ref->this_var()->var(), Token::ASSIGN);
context()->Plug(v0);
}
void FullCodeGenerator::EmitIsSmi(CallRuntime* expr) {
ZoneList<Expression*>* args = expr->arguments();
DCHECK(args->length() == 1);
......
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