}
+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) {
// -- a0 : number of arguments
// -- a1 : constructor function
// -- a2 : allocation site or undefined
+ // -- a3 : original constructor
// -- ra : return address
// -- sp[...]: constructor arguments
// -----------------------------------
FrameScope scope(masm, StackFrame::CONSTRUCT);
if (create_memento) {
- __ AssertUndefinedOrAllocationSite(a2, a3);
+ __ AssertUndefinedOrAllocationSite(a2, t0);
__ push(a2);
}
__ 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) {
// 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
__ 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));
}
}
} 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.
}
+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);
}
+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) {
// -- a0 : number of arguments
// -- a1 : constructor function
// -- a2 : allocation site or undefined
+ // -- a3 : original constructor
// -- ra : return address
// -- sp[...]: constructor arguments
// -----------------------------------
FrameScope scope(masm, StackFrame::CONSTRUCT);
if (create_memento) {
- __ AssertUndefinedOrAllocationSite(a2, a3);
+ __ AssertUndefinedOrAllocationSite(a2, t0);
__ push(a2);
}
__ 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) {
// 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
__ 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));
}
}
} 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.
}
+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);