X87: new classes: change semantics of super(...) call and add new.target to construct stub.
port 22ce08ade6
(r26227)
original commit message:
new classes: change semantics of super(...) call and add new.target to construct stub.
BUG=
R=weiliang.lin@intel.com
Review URL: https://codereview.chromium.org/900423002
Cr-Commit-Position: refs/heads/master@{#26500}
This commit is contained in:
parent
b9e15ea3aa
commit
bd4476a623
@ -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);
|
||||
|
@ -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));
|
||||
|
@ -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) {
|
||||
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<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);
|
||||
|
Loading…
Reference in New Issue
Block a user