diff --git a/src/x87/builtins-x87.cc b/src/x87/builtins-x87.cc index 51bb3a7c65..b7be786a43 100644 --- a/src/x87/builtins-x87.cc +++ b/src/x87/builtins-x87.cc @@ -100,6 +100,42 @@ void Builtins::Generate_InOptimizationQueue(MacroAssembler* masm) { } +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) { @@ -107,6 +143,7 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm, // -- eax: number of arguments // -- edi: constructor function // -- ebx: allocation site or undefined + // -- edx: original constructor // ----------------------------------- // Should never create mementos for api functions. @@ -128,9 +165,20 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm, // 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 = @@ -344,34 +392,8 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm, // 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); diff --git a/src/x87/code-stubs-x87.cc b/src/x87/code-stubs-x87.cc index f0901b32b7..a8b3e62235 100644 --- a/src/x87/code-stubs-x87.cc +++ b/src/x87/code-stubs-x87.cc @@ -1836,6 +1836,9 @@ void CallConstructStub::Generate(MacroAssembler* masm) { __ AssertUndefinedOrAllocationSite(ebx); } + // Pass original constructor to construct stub. + __ mov(edx, edi); + // Jump to the function-specific construct stub. Register jmp_reg = ecx; __ mov(jmp_reg, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); diff --git a/src/x87/full-codegen-x87.cc b/src/x87/full-codegen-x87.cc index 7cd503e58c..4a3e5cc376 100644 --- a/src/x87/full-codegen-x87.cc +++ b/src/x87/full-codegen-x87.cc @@ -2991,7 +2991,6 @@ void FullCodeGenerator::VisitCall(Call* expr) { } 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(); @@ -3050,11 +3049,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. @@ -3121,6 +3124,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* 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* args = expr->arguments(); DCHECK(args->length() == 1);