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:
cdai2 2015-02-07 14:20:27 +08:00
parent b9e15ea3aa
commit bd4476a623
3 changed files with 108 additions and 35 deletions

View File

@ -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);

View File

@ -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));

View File

@ -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<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);