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,
|
static void Generate_JSConstructStubHelper(MacroAssembler* masm,
|
||||||
bool is_api_function,
|
bool is_api_function,
|
||||||
bool create_memento) {
|
bool create_memento) {
|
||||||
@ -107,6 +143,7 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
|
|||||||
// -- eax: number of arguments
|
// -- eax: number of arguments
|
||||||
// -- edi: constructor function
|
// -- edi: constructor function
|
||||||
// -- ebx: allocation site or undefined
|
// -- ebx: allocation site or undefined
|
||||||
|
// -- edx: original constructor
|
||||||
// -----------------------------------
|
// -----------------------------------
|
||||||
|
|
||||||
// Should never create mementos for api functions.
|
// 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 the function to invoke on the stack.
|
||||||
__ push(edi);
|
__ 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
|
// 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.
|
// the preconditions is not met, the code bails out to the runtime call.
|
||||||
Label rt_call, allocated;
|
Label rt_call;
|
||||||
if (FLAG_inline_new) {
|
if (FLAG_inline_new) {
|
||||||
Label undo_allocation;
|
Label undo_allocation;
|
||||||
ExternalReference debug_step_in_fp =
|
ExternalReference debug_step_in_fp =
|
||||||
@ -344,34 +392,8 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
|
|||||||
|
|
||||||
// Allocate the new receiver object using the runtime call.
|
// Allocate the new receiver object using the runtime call.
|
||||||
__ bind(&rt_call);
|
__ bind(&rt_call);
|
||||||
int offset = 0;
|
Generate_Runtime_NewObject(masm, create_memento, edi, &count_incremented,
|
||||||
if (create_memento) {
|
&allocated);
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
// New object allocated.
|
// New object allocated.
|
||||||
// ebx: newly allocated object
|
// ebx: newly allocated object
|
||||||
__ bind(&allocated);
|
__ bind(&allocated);
|
||||||
|
@ -1836,6 +1836,9 @@ void CallConstructStub::Generate(MacroAssembler* masm) {
|
|||||||
__ AssertUndefinedOrAllocationSite(ebx);
|
__ AssertUndefinedOrAllocationSite(ebx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Pass original constructor to construct stub.
|
||||||
|
__ mov(edx, edi);
|
||||||
|
|
||||||
// Jump to the function-specific construct stub.
|
// Jump to the function-specific construct stub.
|
||||||
Register jmp_reg = ecx;
|
Register jmp_reg = ecx;
|
||||||
__ mov(jmp_reg, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
|
__ mov(jmp_reg, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
|
||||||
|
@ -2991,7 +2991,6 @@ void FullCodeGenerator::VisitCall(Call* expr) {
|
|||||||
|
|
||||||
} else if (call_type == Call::GLOBAL_CALL) {
|
} else if (call_type == Call::GLOBAL_CALL) {
|
||||||
EmitCallWithLoadIC(expr);
|
EmitCallWithLoadIC(expr);
|
||||||
|
|
||||||
} else if (call_type == Call::LOOKUP_SLOT_CALL) {
|
} else if (call_type == Call::LOOKUP_SLOT_CALL) {
|
||||||
// Call to a lookup slot (dynamically introduced variable).
|
// Call to a lookup slot (dynamically introduced variable).
|
||||||
VariableProxy* proxy = callee->AsVariableProxy();
|
VariableProxy* proxy = callee->AsVariableProxy();
|
||||||
@ -3050,11 +3049,15 @@ void FullCodeGenerator::VisitCall(Call* expr) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (call_type == Call::SUPER_CALL) {
|
} else if (call_type == Call::SUPER_CALL) {
|
||||||
SuperReference* super_ref = callee->AsSuperReference();
|
if (FLAG_experimental_classes) {
|
||||||
EmitLoadSuperConstructor(super_ref);
|
EmitSuperConstructorCall(expr);
|
||||||
__ push(result_register());
|
} else {
|
||||||
VisitForStackValue(super_ref->this_var());
|
SuperReference* super_ref = callee->AsSuperReference();
|
||||||
EmitCall(expr, CallICState::METHOD);
|
EmitLoadSuperConstructor(super_ref);
|
||||||
|
__ push(result_register());
|
||||||
|
VisitForStackValue(super_ref->this_var());
|
||||||
|
EmitCall(expr, CallICState::METHOD);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
DCHECK(call_type == Call::OTHER_CALL);
|
DCHECK(call_type == Call::OTHER_CALL);
|
||||||
// Call to an arbitrary expression not handled specially above.
|
// 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) {
|
void FullCodeGenerator::EmitIsSmi(CallRuntime* expr) {
|
||||||
ZoneList<Expression*>* args = expr->arguments();
|
ZoneList<Expression*>* args = expr->arguments();
|
||||||
DCHECK(args->length() == 1);
|
DCHECK(args->length() == 1);
|
||||||
|
Loading…
Reference in New Issue
Block a user