}
+static void Generate_Runtime_NewObject(MacroAssembler* masm,
+ bool create_memento,
+ Register original_constructor,
+ Label* count_incremented,
+ Label* allocated) {
+ int offset = 0;
+ if (create_memento) {
+ // Get the cell or allocation site.
+ __ mov(edi, Operand(esp, kPointerSize * 2));
+ __ push(edi);
+ offset = kPointerSize;
+ }
+
+ // Must restore esi (context) and edi (constructor) before calling
+ // runtime.
+ __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
+ __ mov(edi, Operand(esp, offset));
+ __ push(edi);
+ __ push(original_constructor);
+ if (create_memento) {
+ __ CallRuntime(Runtime::kNewObjectWithAllocationSite, 3);
+ } else {
+ __ CallRuntime(Runtime::kNewObject, 2);
+ }
+ __ mov(ebx, eax); // store result in ebx
+
+ // 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) {
// -- eax: number of arguments
// -- edi: constructor function
// -- ebx: allocation site or undefined
+ // -- edx: original constructor
// -----------------------------------
// Should never create mementos for api functions.
// Push the function to invoke on the stack.
__ push(edi);
+ __ cmp(edx, edi);
+ Label normal_new;
+ Label count_incremented;
+ Label allocated;
+ __ j(equal, &normal_new);
+
+ // Original constructor and function are different.
+ Generate_Runtime_NewObject(masm, create_memento, edx, &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.
- Label rt_call, allocated;
+ Label rt_call;
if (FLAG_inline_new) {
Label undo_allocation;
ExternalReference debug_step_in_fp =
// Allocate the new receiver object using the runtime call.
__ bind(&rt_call);
- int offset = 0;
- if (create_memento) {
- // Get the cell or allocation site.
- __ mov(edi, Operand(esp, kPointerSize * 2));
- __ push(edi);
- offset = kPointerSize;
- }
-
- // Must restore esi (context) and edi (constructor) before calling runtime.
- __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
- __ mov(edi, Operand(esp, offset));
- // edi: function (constructor)
- __ push(edi);
- if (create_memento) {
- __ CallRuntime(Runtime::kNewObjectWithAllocationSite, 2);
- } else {
- __ CallRuntime(Runtime::kNewObject, 1);
- }
- __ mov(ebx, eax); // store result in ebx
-
- // 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, edi, &count_incremented,
+ &allocated);
// New object allocated.
// ebx: newly allocated object
__ bind(&allocated);
} else if (call_type == Call::GLOBAL_CALL) {
EmitCallWithLoadIC(expr);
-
} else if (call_type == Call::LOOKUP_SLOT_CALL) {
// Call to a lookup slot (dynamically introduced variable).
VariableProxy* proxy = callee->AsVariableProxy();
}
}
} 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 edi and eax.
+ __ Move(eax, Immediate(arg_count));
+ __ mov(edi, Operand(esp, 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);
+ */
+ }
+
+ __ LoadHeapObject(ebx, FeedbackVector());
+ __ mov(edx, Immediate(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(eax);
+}
+
+
void FullCodeGenerator::EmitIsSmi(CallRuntime* expr) {
ZoneList<Expression*>* args = expr->arguments();
DCHECK(args->length() == 1);