Reapply "Fix receiver when calling eval() bound by with scope"

Originally applied in https://codereview.chromium.org/1202963005

BUG=v8:4214
CQ_INCLUDE_TRYBOTS=tryserver.chromium.linux:linux_chromium_rel_ng;tryserver.blink:linux_blink_rel
LOG=N
R=arv@chromium.org, mstarzinger@chromium.org

Review URL: https://codereview.chromium.org/1208873002

Cr-Commit-Position: refs/heads/master@{#29293}
This commit is contained in:
wingo 2015-06-25 06:46:31 -07:00 committed by Commit bot
parent 876ae42598
commit 40b7d874b2
12 changed files with 412 additions and 321 deletions

View File

@ -3137,6 +3137,53 @@ void FullCodeGenerator::EmitInitializeThisAfterSuper(
}
// See http://www.ecma-international.org/ecma-262/6.0/#sec-function-calls.
void FullCodeGenerator::PushCalleeAndWithBaseObject(Call* expr) {
VariableProxy* callee = expr->expression()->AsVariableProxy();
if (callee->var()->IsLookupSlot()) {
Label slow, done;
SetSourcePosition(callee->position());
{
PreservePositionScope scope(masm()->positions_recorder());
// Generate code for loading from variables potentially shadowed
// by eval-introduced variables.
EmitDynamicLookupFastCase(callee, NOT_INSIDE_TYPEOF, &slow, &done);
}
__ bind(&slow);
// Call the runtime to find the function to call (returned in r0)
// and the object holding it (returned in edx).
DCHECK(!context_register().is(r2));
__ mov(r2, Operand(callee->name()));
__ Push(context_register(), r2);
__ CallRuntime(Runtime::kLoadLookupSlot, 2);
__ Push(r0, r1); // Function, receiver.
PrepareForBailoutForId(expr->LookupId(), NO_REGISTERS);
// If fast case code has been generated, emit code to push the
// function and receiver and have the slow path jump around this
// code.
if (done.is_linked()) {
Label call;
__ b(&call);
__ bind(&done);
// Push function.
__ push(r0);
// The receiver is implicitly the global receiver. Indicate this
// by passing the hole to the call function stub.
__ LoadRoot(r1, Heap::kUndefinedValueRootIndex);
__ push(r1);
__ bind(&call);
}
} else {
VisitForStackValue(callee);
// refEnv.WithBaseObject()
__ LoadRoot(r2, Heap::kUndefinedValueRootIndex);
__ push(r2); // Reserved receiver slot.
}
}
void FullCodeGenerator::VisitCall(Call* expr) {
#ifdef DEBUG
// We want to verify that RecordJSReturnSite gets called on all paths
@ -3156,9 +3203,7 @@ void FullCodeGenerator::VisitCall(Call* expr) {
int arg_count = args->length();
{ PreservePositionScope pos_scope(masm()->positions_recorder());
VisitForStackValue(callee);
__ LoadRoot(r2, Heap::kUndefinedValueRootIndex);
__ push(r2); // Reserved receiver slot.
PushCalleeAndWithBaseObject(expr);
// Push the arguments.
for (int i = 0; i < arg_count; i++) {
@ -3174,7 +3219,7 @@ void FullCodeGenerator::VisitCall(Call* expr) {
// Touch up the stack with the resolved function.
__ str(r0, MemOperand(sp, (arg_count + 1) * kPointerSize));
PrepareForBailoutForId(expr->EvalOrLookupId(), NO_REGISTERS);
PrepareForBailoutForId(expr->EvalId(), NO_REGISTERS);
}
// Record source position for debugger.
@ -3191,43 +3236,7 @@ void FullCodeGenerator::VisitCall(Call* expr) {
} else if (call_type == Call::LOOKUP_SLOT_CALL) {
// Call to a lookup slot (dynamically introduced variable).
VariableProxy* proxy = callee->AsVariableProxy();
Label slow, done;
{ PreservePositionScope scope(masm()->positions_recorder());
// Generate code for loading from variables potentially shadowed
// by eval-introduced variables.
EmitDynamicLookupFastCase(proxy, NOT_INSIDE_TYPEOF, &slow, &done);
}
__ bind(&slow);
// Call the runtime to find the function to call (returned in r0)
// and the object holding it (returned in edx).
DCHECK(!context_register().is(r2));
__ mov(r2, Operand(proxy->name()));
__ Push(context_register(), r2);
__ CallRuntime(Runtime::kLoadLookupSlot, 2);
__ Push(r0, r1); // Function, receiver.
PrepareForBailoutForId(expr->EvalOrLookupId(), NO_REGISTERS);
// If fast case code has been generated, emit code to push the
// function and receiver and have the slow path jump around this
// code.
if (done.is_linked()) {
Label call;
__ b(&call);
__ bind(&done);
// Push function.
__ push(r0);
// The receiver is implicitly the global receiver. Indicate this
// by passing the hole to the call function stub.
__ LoadRoot(r1, Heap::kUndefinedValueRootIndex);
__ push(r1);
__ bind(&call);
}
// The receiver is either the global receiver or an object found
// by LoadContextSlot.
PushCalleeAndWithBaseObject(expr);
EmitCall(expr);
} else if (call_type == Call::PROPERTY_CALL) {
Property* property = callee->AsProperty();

View File

@ -2829,6 +2829,51 @@ void FullCodeGenerator::EmitInitializeThisAfterSuper(
}
// See http://www.ecma-international.org/ecma-262/6.0/#sec-function-calls.
void FullCodeGenerator::PushCalleeAndWithBaseObject(Call* expr) {
VariableProxy* callee = expr->expression()->AsVariableProxy();
if (callee->var()->IsLookupSlot()) {
Label slow, done;
SetSourcePosition(callee->position());
{
PreservePositionScope scope(masm()->positions_recorder());
// Generate code for loading from variables potentially shadowed
// by eval-introduced variables.
EmitDynamicLookupFastCase(callee, NOT_INSIDE_TYPEOF, &slow, &done);
}
__ Bind(&slow);
// Call the runtime to find the function to call (returned in x0)
// and the object holding it (returned in x1).
__ Mov(x10, Operand(callee->name()));
__ Push(context_register(), x10);
__ CallRuntime(Runtime::kLoadLookupSlot, 2);
__ Push(x0, x1); // Receiver, function.
PrepareForBailoutForId(expr->LookupId(), NO_REGISTERS);
// If fast case code has been generated, emit code to push the
// function and receiver and have the slow path jump around this
// code.
if (done.is_linked()) {
Label call;
__ B(&call);
__ Bind(&done);
// Push function.
// The receiver is implicitly the global receiver. Indicate this
// by passing the undefined to the call function stub.
__ LoadRoot(x1, Heap::kUndefinedValueRootIndex);
__ Push(x0, x1);
__ Bind(&call);
}
} else {
VisitForStackValue(callee);
// refEnv.WithBaseObject()
__ LoadRoot(x10, Heap::kUndefinedValueRootIndex);
__ Push(x10); // Reserved receiver slot.
}
}
void FullCodeGenerator::VisitCall(Call* expr) {
#ifdef DEBUG
// We want to verify that RecordJSReturnSite gets called on all paths
@ -2849,9 +2894,7 @@ void FullCodeGenerator::VisitCall(Call* expr) {
{
PreservePositionScope pos_scope(masm()->positions_recorder());
VisitForStackValue(callee);
__ LoadRoot(x10, Heap::kUndefinedValueRootIndex);
__ Push(x10); // Reserved receiver slot.
PushCalleeAndWithBaseObject(expr);
// Push the arguments.
for (int i = 0; i < arg_count; i++) {
@ -2867,7 +2910,7 @@ void FullCodeGenerator::VisitCall(Call* expr) {
// Touch up the stack with the resolved function.
__ Poke(x0, (arg_count + 1) * kPointerSize);
PrepareForBailoutForId(expr->EvalOrLookupId(), NO_REGISTERS);
PrepareForBailoutForId(expr->EvalId(), NO_REGISTERS);
}
// Record source position for debugger.
@ -2887,41 +2930,7 @@ void FullCodeGenerator::VisitCall(Call* expr) {
} else if (call_type == Call::LOOKUP_SLOT_CALL) {
// Call to a lookup slot (dynamically introduced variable).
VariableProxy* proxy = callee->AsVariableProxy();
Label slow, done;
{ PreservePositionScope scope(masm()->positions_recorder());
// Generate code for loading from variables potentially shadowed
// by eval-introduced variables.
EmitDynamicLookupFastCase(proxy, NOT_INSIDE_TYPEOF, &slow, &done);
}
__ Bind(&slow);
// Call the runtime to find the function to call (returned in x0)
// and the object holding it (returned in x1).
__ Mov(x10, Operand(proxy->name()));
__ Push(context_register(), x10);
__ CallRuntime(Runtime::kLoadLookupSlot, 2);
__ Push(x0, x1); // Receiver, function.
PrepareForBailoutForId(expr->EvalOrLookupId(), NO_REGISTERS);
// If fast case code has been generated, emit code to push the
// function and receiver and have the slow path jump around this
// code.
if (done.is_linked()) {
Label call;
__ B(&call);
__ Bind(&done);
// Push function.
// The receiver is implicitly the global receiver. Indicate this
// by passing the undefined to the call function stub.
__ LoadRoot(x1, Heap::kUndefinedValueRootIndex);
__ Push(x0, x1);
__ Bind(&call);
}
// The receiver is either the global receiver or an object found
// by LoadContextSlot.
PushCalleeAndWithBaseObject(expr);
EmitCall(expr);
} else if (call_type == Call::PROPERTY_CALL) {
Property* property = callee->AsProperty();

View File

@ -1869,9 +1869,10 @@ class Call final : public Expression {
allocation_site_ = site;
}
static int num_ids() { return parent_num_ids() + 2; }
static int num_ids() { return parent_num_ids() + 3; }
BailoutId ReturnId() const { return BailoutId(local_id(0)); }
BailoutId EvalOrLookupId() const { return BailoutId(local_id(1)); }
BailoutId EvalId() const { return BailoutId(local_id(1)); }
BailoutId LookupId() const { return BailoutId(local_id(2)); }
bool is_uninitialized() const {
return IsUninitializedField::decode(bit_field_);

View File

@ -2356,7 +2356,7 @@ void AstGraphBuilder::VisitCall(Call* expr) {
callee_value = NewNode(common()->Projection(0), pair);
receiver_value = NewNode(common()->Projection(1), pair);
PrepareFrameState(pair, expr->EvalOrLookupId(),
PrepareFrameState(pair, expr->LookupId(),
OutputFrameStateCombine::Push(2));
break;
}
@ -2424,6 +2424,18 @@ void AstGraphBuilder::VisitCall(Call* expr) {
break;
case Call::POSSIBLY_EVAL_CALL:
possibly_eval = true;
if (callee->AsVariableProxy()->var()->IsLookupSlot()) {
Variable* variable = callee->AsVariableProxy()->var();
Node* name = jsgraph()->Constant(variable->name());
const Operator* op =
javascript()->CallRuntime(Runtime::kLoadLookupSlot, 2);
Node* pair = NewNode(op, current_context(), name);
callee_value = NewNode(common()->Projection(0), pair);
receiver_value = NewNode(common()->Projection(1), pair);
PrepareFrameState(pair, expr->LookupId(),
OutputFrameStateCombine::Push(2));
break;
}
// Fall through.
case Call::OTHER_CALL:
VisitForValue(callee);
@ -2459,7 +2471,7 @@ void AstGraphBuilder::VisitCall(Call* expr) {
javascript()->CallRuntime(Runtime::kResolvePossiblyDirectEval, 5);
Node* new_callee =
NewNode(op, callee, source, function, language, position);
PrepareFrameState(new_callee, expr->EvalOrLookupId(),
PrepareFrameState(new_callee, expr->EvalId(),
OutputFrameStateCombine::PokeAt(arg_count + 1));
// Patch callee on the environment.

View File

@ -736,6 +736,8 @@ class FullCodeGenerator: public AstVisitor {
// and PushCatchContext.
void PushFunctionArgumentForContextAllocation();
void PushCalleeAndWithBaseObject(Call* expr);
// AST node visit functions.
#define DECLARE_VISIT(type) virtual void Visit##type(type* node) override;
AST_NODE_LIST(DECLARE_VISIT)

View File

@ -3036,6 +3036,49 @@ void FullCodeGenerator::EmitInitializeThisAfterSuper(
}
// See http://www.ecma-international.org/ecma-262/6.0/#sec-function-calls.
void FullCodeGenerator::PushCalleeAndWithBaseObject(Call* expr) {
VariableProxy* callee = expr->expression()->AsVariableProxy();
if (callee->var()->IsLookupSlot()) {
Label slow, done;
SetSourcePosition(callee->position());
{
PreservePositionScope scope(masm()->positions_recorder());
// Generate code for loading from variables potentially shadowed by
// eval-introduced variables.
EmitDynamicLookupFastCase(callee, NOT_INSIDE_TYPEOF, &slow, &done);
}
__ bind(&slow);
// Call the runtime to find the function to call (returned in eax) and
// the object holding it (returned in edx).
__ push(context_register());
__ push(Immediate(callee->name()));
__ CallRuntime(Runtime::kLoadLookupSlot, 2);
__ push(eax); // Function.
__ push(edx); // Receiver.
PrepareForBailoutForId(expr->LookupId(), NO_REGISTERS);
// If fast case code has been generated, emit code to push the function
// and receiver and have the slow path jump around this code.
if (done.is_linked()) {
Label call;
__ jmp(&call, Label::kNear);
__ bind(&done);
// Push function.
__ push(eax);
// The receiver is implicitly the global receiver. Indicate this by
// passing the hole to the call function stub.
__ push(Immediate(isolate()->factory()->undefined_value()));
__ bind(&call);
}
} else {
VisitForStackValue(callee);
// refEnv.WithBaseObject()
__ push(Immediate(isolate()->factory()->undefined_value()));
}
}
void FullCodeGenerator::VisitCall(Call* expr) {
#ifdef DEBUG
// We want to verify that RecordJSReturnSite gets called on all paths
@ -3054,9 +3097,8 @@ void FullCodeGenerator::VisitCall(Call* expr) {
ZoneList<Expression*>* args = expr->arguments();
int arg_count = args->length();
{ PreservePositionScope pos_scope(masm()->positions_recorder());
VisitForStackValue(callee);
// Reserved receiver slot.
__ push(Immediate(isolate()->factory()->undefined_value()));
PushCalleeAndWithBaseObject(expr);
// Push the arguments.
for (int i = 0; i < arg_count; i++) {
VisitForStackValue(args->at(i));
@ -3070,7 +3112,7 @@ void FullCodeGenerator::VisitCall(Call* expr) {
// Touch up the stack with the resolved function.
__ mov(Operand(esp, (arg_count + 1) * kPointerSize), eax);
PrepareForBailoutForId(expr->EvalOrLookupId(), NO_REGISTERS);
PrepareForBailoutForId(expr->EvalId(), NO_REGISTERS);
}
// Record source position for debugger.
SetSourcePosition(expr->position());
@ -3086,41 +3128,8 @@ void FullCodeGenerator::VisitCall(Call* expr) {
EmitCallWithLoadIC(expr);
} else if (call_type == Call::LOOKUP_SLOT_CALL) {
// Call to a lookup slot (dynamically introduced variable).
VariableProxy* proxy = callee->AsVariableProxy();
Label slow, done;
{ PreservePositionScope scope(masm()->positions_recorder());
// Generate code for loading from variables potentially shadowed by
// eval-introduced variables.
EmitDynamicLookupFastCase(proxy, NOT_INSIDE_TYPEOF, &slow, &done);
}
__ bind(&slow);
// Call the runtime to find the function to call (returned in eax) and
// the object holding it (returned in edx).
__ push(context_register());
__ push(Immediate(proxy->name()));
__ CallRuntime(Runtime::kLoadLookupSlot, 2);
__ push(eax); // Function.
__ push(edx); // Receiver.
PrepareForBailoutForId(expr->EvalOrLookupId(), NO_REGISTERS);
// If fast case code has been generated, emit code to push the function
// and receiver and have the slow path jump around this code.
if (done.is_linked()) {
Label call;
__ jmp(&call, Label::kNear);
__ bind(&done);
// Push function.
__ push(eax);
// The receiver is implicitly the global receiver. Indicate this by
// passing the hole to the call function stub.
__ push(Immediate(isolate()->factory()->undefined_value()));
__ bind(&call);
}
// The receiver is either the global receiver or an object found by
// LoadContextSlot.
PushCalleeAndWithBaseObject(expr);
EmitCall(expr);
} else if (call_type == Call::PROPERTY_CALL) {
Property* property = callee->AsProperty();
bool is_named_call = property->key()->IsPropertyName();

View File

@ -3121,6 +3121,53 @@ void FullCodeGenerator::EmitInitializeThisAfterSuper(
}
// See http://www.ecma-international.org/ecma-262/6.0/#sec-function-calls.
void FullCodeGenerator::PushCalleeAndWithBaseObject(Call* expr) {
VariableProxy* callee = expr->expression()->AsVariableProxy();
if (callee->var()->IsLookupSlot()) {
Label slow, done;
SetSourcePosition(callee->position());
{
PreservePositionScope scope(masm()->positions_recorder());
// Generate code for loading from variables potentially shadowed
// by eval-introduced variables.
EmitDynamicLookupFastCase(callee, NOT_INSIDE_TYPEOF, &slow, &done);
}
__ bind(&slow);
// Call the runtime to find the function to call (returned in v0)
// and the object holding it (returned in v1).
DCHECK(!context_register().is(a2));
__ li(a2, Operand(callee->name()));
__ Push(context_register(), a2);
__ CallRuntime(Runtime::kLoadLookupSlot, 2);
__ Push(v0, v1); // Function, receiver.
PrepareForBailoutForId(expr->LookupId(), NO_REGISTERS);
// If fast case code has been generated, emit code to push the
// function and receiver and have the slow path jump around this
// code.
if (done.is_linked()) {
Label call;
__ Branch(&call);
__ bind(&done);
// Push function.
__ push(v0);
// The receiver is implicitly the global receiver. Indicate this
// by passing the hole to the call function stub.
__ LoadRoot(a1, Heap::kUndefinedValueRootIndex);
__ push(a1);
__ bind(&call);
}
} else {
VisitForStackValue(callee);
// refEnv.WithBaseObject()
__ LoadRoot(a2, Heap::kUndefinedValueRootIndex);
__ push(a2); // Reserved receiver slot.
}
}
void FullCodeGenerator::VisitCall(Call* expr) {
#ifdef DEBUG
// We want to verify that RecordJSReturnSite gets called on all paths
@ -3140,9 +3187,7 @@ void FullCodeGenerator::VisitCall(Call* expr) {
int arg_count = args->length();
{ PreservePositionScope pos_scope(masm()->positions_recorder());
VisitForStackValue(callee);
__ LoadRoot(a2, Heap::kUndefinedValueRootIndex);
__ push(a2); // Reserved receiver slot.
PushCalleeAndWithBaseObject(expr);
// Push the arguments.
for (int i = 0; i < arg_count; i++) {
@ -3158,7 +3203,7 @@ void FullCodeGenerator::VisitCall(Call* expr) {
// Touch up the stack with the resolved function.
__ sw(v0, MemOperand(sp, (arg_count + 1) * kPointerSize));
PrepareForBailoutForId(expr->EvalOrLookupId(), NO_REGISTERS);
PrepareForBailoutForId(expr->EvalId(), NO_REGISTERS);
}
// Record source position for debugger.
SetSourcePosition(expr->position());
@ -3173,43 +3218,7 @@ void FullCodeGenerator::VisitCall(Call* expr) {
EmitCallWithLoadIC(expr);
} else if (call_type == Call::LOOKUP_SLOT_CALL) {
// Call to a lookup slot (dynamically introduced variable).
VariableProxy* proxy = callee->AsVariableProxy();
Label slow, done;
{ PreservePositionScope scope(masm()->positions_recorder());
// Generate code for loading from variables potentially shadowed
// by eval-introduced variables.
EmitDynamicLookupFastCase(proxy, NOT_INSIDE_TYPEOF, &slow, &done);
}
__ bind(&slow);
// Call the runtime to find the function to call (returned in v0)
// and the object holding it (returned in v1).
DCHECK(!context_register().is(a2));
__ li(a2, Operand(proxy->name()));
__ Push(context_register(), a2);
__ CallRuntime(Runtime::kLoadLookupSlot, 2);
__ Push(v0, v1); // Function, receiver.
PrepareForBailoutForId(expr->EvalOrLookupId(), NO_REGISTERS);
// If fast case code has been generated, emit code to push the
// function and receiver and have the slow path jump around this
// code.
if (done.is_linked()) {
Label call;
__ Branch(&call);
__ bind(&done);
// Push function.
__ push(v0);
// The receiver is implicitly the global receiver. Indicate this
// by passing the hole to the call function stub.
__ LoadRoot(a1, Heap::kUndefinedValueRootIndex);
__ push(a1);
__ bind(&call);
}
// The receiver is either the global receiver or an object found
// by LoadContextSlot.
PushCalleeAndWithBaseObject(expr);
EmitCall(expr);
} else if (call_type == Call::PROPERTY_CALL) {
Property* property = callee->AsProperty();

View File

@ -3122,6 +3122,53 @@ void FullCodeGenerator::EmitInitializeThisAfterSuper(
}
// See http://www.ecma-international.org/ecma-262/6.0/#sec-function-calls.
void FullCodeGenerator::PushCalleeAndWithBaseObject(Call* expr) {
VariableProxy* callee = expr->expression()->AsVariableProxy();
if (callee->var()->IsLookupSlot()) {
Label slow, done;
SetSourcePosition(callee->position());
{
PreservePositionScope scope(masm()->positions_recorder());
// Generate code for loading from variables potentially shadowed
// by eval-introduced variables.
EmitDynamicLookupFastCase(callee, NOT_INSIDE_TYPEOF, &slow, &done);
}
__ bind(&slow);
// Call the runtime to find the function to call (returned in v0)
// and the object holding it (returned in v1).
DCHECK(!context_register().is(a2));
__ li(a2, Operand(callee->name()));
__ Push(context_register(), a2);
__ CallRuntime(Runtime::kLoadLookupSlot, 2);
__ Push(v0, v1); // Function, receiver.
PrepareForBailoutForId(expr->LookupId(), NO_REGISTERS);
// If fast case code has been generated, emit code to push the
// function and receiver and have the slow path jump around this
// code.
if (done.is_linked()) {
Label call;
__ Branch(&call);
__ bind(&done);
// Push function.
__ push(v0);
// The receiver is implicitly the global receiver. Indicate this
// by passing the hole to the call function stub.
__ LoadRoot(a1, Heap::kUndefinedValueRootIndex);
__ push(a1);
__ bind(&call);
}
} else {
VisitForStackValue(callee);
// refEnv.WithBaseObject()
__ LoadRoot(a2, Heap::kUndefinedValueRootIndex);
__ push(a2); // Reserved receiver slot.
}
}
void FullCodeGenerator::VisitCall(Call* expr) {
#ifdef DEBUG
// We want to verify that RecordJSReturnSite gets called on all paths
@ -3141,9 +3188,7 @@ void FullCodeGenerator::VisitCall(Call* expr) {
int arg_count = args->length();
{ PreservePositionScope pos_scope(masm()->positions_recorder());
VisitForStackValue(callee);
__ LoadRoot(a2, Heap::kUndefinedValueRootIndex);
__ push(a2); // Reserved receiver slot.
PushCalleeAndWithBaseObject(expr);
// Push the arguments.
for (int i = 0; i < arg_count; i++) {
@ -3159,7 +3204,7 @@ void FullCodeGenerator::VisitCall(Call* expr) {
// Touch up the stack with the resolved function.
__ sd(v0, MemOperand(sp, (arg_count + 1) * kPointerSize));
PrepareForBailoutForId(expr->EvalOrLookupId(), NO_REGISTERS);
PrepareForBailoutForId(expr->EvalId(), NO_REGISTERS);
}
// Record source position for debugger.
SetSourcePosition(expr->position());
@ -3174,43 +3219,7 @@ void FullCodeGenerator::VisitCall(Call* expr) {
EmitCallWithLoadIC(expr);
} else if (call_type == Call::LOOKUP_SLOT_CALL) {
// Call to a lookup slot (dynamically introduced variable).
VariableProxy* proxy = callee->AsVariableProxy();
Label slow, done;
{ PreservePositionScope scope(masm()->positions_recorder());
// Generate code for loading from variables potentially shadowed
// by eval-introduced variables.
EmitDynamicLookupFastCase(proxy, NOT_INSIDE_TYPEOF, &slow, &done);
}
__ bind(&slow);
// Call the runtime to find the function to call (returned in v0)
// and the object holding it (returned in v1).
DCHECK(!context_register().is(a2));
__ li(a2, Operand(proxy->name()));
__ Push(context_register(), a2);
__ CallRuntime(Runtime::kLoadLookupSlot, 2);
__ Push(v0, v1); // Function, receiver.
PrepareForBailoutForId(expr->EvalOrLookupId(), NO_REGISTERS);
// If fast case code has been generated, emit code to push the
// function and receiver and have the slow path jump around this
// code.
if (done.is_linked()) {
Label call;
__ Branch(&call);
__ bind(&done);
// Push function.
__ push(v0);
// The receiver is implicitly the global receiver. Indicate this
// by passing the hole to the call function stub.
__ LoadRoot(a1, Heap::kUndefinedValueRootIndex);
__ push(a1);
__ bind(&call);
}
// The receiver is either the global receiver or an object found
// by LoadContextSlot.
PushCalleeAndWithBaseObject(expr);
EmitCall(expr);
} else if (call_type == Call::PROPERTY_CALL) {
Property* property = callee->AsProperty();

View File

@ -3135,6 +3135,51 @@ void FullCodeGenerator::EmitInitializeThisAfterSuper(
}
// See http://www.ecma-international.org/ecma-262/6.0/#sec-function-calls.
void FullCodeGenerator::PushCalleeAndWithBaseObject(Call* expr) {
VariableProxy* callee = expr->expression()->AsVariableProxy();
if (callee->var()->IsLookupSlot()) {
Label slow, done;
SetSourcePosition(callee->position());
{
PreservePositionScope scope(masm()->positions_recorder());
// Generate code for loading from variables potentially shadowed by
// eval-introduced variables.
EmitDynamicLookupFastCase(callee, NOT_INSIDE_TYPEOF, &slow, &done);
}
__ bind(&slow);
// Call the runtime to find the function to call (returned in rax) and
// the object holding it (returned in rdx).
__ Push(context_register());
__ Push(callee->name());
__ CallRuntime(Runtime::kLoadLookupSlot, 2);
__ Push(rax); // Function.
__ Push(rdx); // Receiver.
PrepareForBailoutForId(expr->LookupId(), NO_REGISTERS);
// If fast case code has been generated, emit code to push the function
// and receiver and have the slow path jump around this code.
if (done.is_linked()) {
Label call;
__ jmp(&call, Label::kNear);
__ bind(&done);
// Push function.
__ Push(rax);
// Pass undefined as the receiver, which is the WithBaseObject of a
// non-object environment record. If the callee is sloppy, it will patch
// it up to be the global receiver.
__ PushRoot(Heap::kUndefinedValueRootIndex);
__ bind(&call);
}
} else {
VisitForStackValue(callee);
// refEnv.WithBaseObject()
__ LoadRoot(r5, Heap::kUndefinedValueRootIndex);
__ push(r5);
}
}
void FullCodeGenerator::VisitCall(Call* expr) {
#ifdef DEBUG
// We want to verify that RecordJSReturnSite gets called on all paths
@ -3155,9 +3200,7 @@ void FullCodeGenerator::VisitCall(Call* expr) {
{
PreservePositionScope pos_scope(masm()->positions_recorder());
VisitForStackValue(callee);
__ LoadRoot(r5, Heap::kUndefinedValueRootIndex);
__ push(r5); // Reserved receiver slot.
PushCalleeAndWithBaseObject(expr);
// Push the arguments.
for (int i = 0; i < arg_count; i++) {
@ -3173,7 +3216,7 @@ void FullCodeGenerator::VisitCall(Call* expr) {
// Touch up the stack with the resolved function.
__ StoreP(r3, MemOperand(sp, (arg_count + 1) * kPointerSize), r0);
PrepareForBailoutForId(expr->EvalOrLookupId(), NO_REGISTERS);
PrepareForBailoutForId(expr->EvalId(), NO_REGISTERS);
}
// Record source position for debugger.
@ -3190,44 +3233,7 @@ void FullCodeGenerator::VisitCall(Call* expr) {
} else if (call_type == Call::LOOKUP_SLOT_CALL) {
// Call to a lookup slot (dynamically introduced variable).
VariableProxy* proxy = callee->AsVariableProxy();
Label slow, done;
{
PreservePositionScope scope(masm()->positions_recorder());
// Generate code for loading from variables potentially shadowed
// by eval-introduced variables.
EmitDynamicLookupFastCase(proxy, NOT_INSIDE_TYPEOF, &slow, &done);
}
__ bind(&slow);
// Call the runtime to find the function to call (returned in r3)
// and the object holding it (returned in edx).
DCHECK(!context_register().is(r5));
__ mov(r5, Operand(proxy->name()));
__ Push(context_register(), r5);
__ CallRuntime(Runtime::kLoadLookupSlot, 2);
__ Push(r3, r4); // Function, receiver.
PrepareForBailoutForId(expr->EvalOrLookupId(), NO_REGISTERS);
// If fast case code has been generated, emit code to push the
// function and receiver and have the slow path jump around this
// code.
if (done.is_linked()) {
Label call;
__ b(&call);
__ bind(&done);
// Push function.
__ push(r3);
// The receiver is implicitly the global receiver. Indicate this
// by passing the hole to the call function stub.
__ LoadRoot(r4, Heap::kUndefinedValueRootIndex);
__ push(r4);
__ bind(&call);
}
// The receiver is either the global receiver or an object found
// by LoadContextSlot.
PushCalleeAndWithBaseObject(expr);
EmitCall(expr);
} else if (call_type == Call::PROPERTY_CALL) {
Property* property = callee->AsProperty();

View File

@ -3032,6 +3032,50 @@ void FullCodeGenerator::EmitInitializeThisAfterSuper(
}
// See http://www.ecma-international.org/ecma-262/6.0/#sec-function-calls.
void FullCodeGenerator::PushCalleeAndWithBaseObject(Call* expr) {
VariableProxy* callee = expr->expression()->AsVariableProxy();
if (callee->var()->IsLookupSlot()) {
Label slow, done;
SetSourcePosition(callee->position());
{
PreservePositionScope scope(masm()->positions_recorder());
// Generate code for loading from variables potentially shadowed by
// eval-introduced variables.
EmitDynamicLookupFastCase(callee, NOT_INSIDE_TYPEOF, &slow, &done);
}
__ bind(&slow);
// Call the runtime to find the function to call (returned in rax) and
// the object holding it (returned in rdx).
__ Push(context_register());
__ Push(callee->name());
__ CallRuntime(Runtime::kLoadLookupSlot, 2);
__ Push(rax); // Function.
__ Push(rdx); // Receiver.
PrepareForBailoutForId(expr->LookupId(), NO_REGISTERS);
// If fast case code has been generated, emit code to push the function
// and receiver and have the slow path jump around this code.
if (done.is_linked()) {
Label call;
__ jmp(&call, Label::kNear);
__ bind(&done);
// Push function.
__ Push(rax);
// Pass undefined as the receiver, which is the WithBaseObject of a
// non-object environment record. If the callee is sloppy, it will patch
// it up to be the global receiver.
__ PushRoot(Heap::kUndefinedValueRootIndex);
__ bind(&call);
}
} else {
VisitForStackValue(callee);
// refEnv.WithBaseObject()
__ PushRoot(Heap::kUndefinedValueRootIndex);
}
}
void FullCodeGenerator::VisitCall(Call* expr) {
#ifdef DEBUG
// We want to verify that RecordJSReturnSite gets called on all paths
@ -3050,8 +3094,7 @@ void FullCodeGenerator::VisitCall(Call* expr) {
ZoneList<Expression*>* args = expr->arguments();
int arg_count = args->length();
{ PreservePositionScope pos_scope(masm()->positions_recorder());
VisitForStackValue(callee);
__ PushRoot(Heap::kUndefinedValueRootIndex); // Reserved receiver slot.
PushCalleeAndWithBaseObject(expr);
// Push the arguments.
for (int i = 0; i < arg_count; i++) {
@ -3066,7 +3109,7 @@ void FullCodeGenerator::VisitCall(Call* expr) {
// Touch up the callee.
__ movp(Operand(rsp, (arg_count + 1) * kPointerSize), rax);
PrepareForBailoutForId(expr->EvalOrLookupId(), NO_REGISTERS);
PrepareForBailoutForId(expr->EvalId(), NO_REGISTERS);
}
// Record source position for debugger.
SetSourcePosition(expr->position());
@ -3082,40 +3125,7 @@ void FullCodeGenerator::VisitCall(Call* expr) {
} else if (call_type == Call::LOOKUP_SLOT_CALL) {
// Call to a lookup slot (dynamically introduced variable).
VariableProxy* proxy = callee->AsVariableProxy();
Label slow, done;
{ PreservePositionScope scope(masm()->positions_recorder());
// Generate code for loading from variables potentially shadowed by
// eval-introduced variables.
EmitDynamicLookupFastCase(proxy, NOT_INSIDE_TYPEOF, &slow, &done);
}
__ bind(&slow);
// Call the runtime to find the function to call (returned in rax) and
// the object holding it (returned in rdx).
__ Push(context_register());
__ Push(proxy->name());
__ CallRuntime(Runtime::kLoadLookupSlot, 2);
__ Push(rax); // Function.
__ Push(rdx); // Receiver.
PrepareForBailoutForId(expr->EvalOrLookupId(), NO_REGISTERS);
// If fast case code has been generated, emit code to push the function
// and receiver and have the slow path jump around this code.
if (done.is_linked()) {
Label call;
__ jmp(&call, Label::kNear);
__ bind(&done);
// Push function.
__ Push(rax);
// The receiver is implicitly the global receiver. Indicate this by
// passing the hole to the call function stub.
__ PushRoot(Heap::kUndefinedValueRootIndex);
__ bind(&call);
}
// The receiver is either the global receiver or an object found by
// LoadContextSlot.
PushCalleeAndWithBaseObject(expr);
EmitCall(expr);
} else if (call_type == Call::PROPERTY_CALL) {
Property* property = callee->AsProperty();

View File

@ -3017,6 +3017,49 @@ void FullCodeGenerator::EmitInitializeThisAfterSuper(
}
// See http://www.ecma-international.org/ecma-262/6.0/#sec-function-calls.
void FullCodeGenerator::PushCalleeAndWithBaseObject(Call* expr) {
VariableProxy* callee = expr->expression()->AsVariableProxy();
if (callee->var()->IsLookupSlot()) {
Label slow, done;
SetSourcePosition(callee->position());
{
PreservePositionScope scope(masm()->positions_recorder());
// Generate code for loading from variables potentially shadowed by
// eval-introduced variables.
EmitDynamicLookupFastCase(callee, NOT_INSIDE_TYPEOF, &slow, &done);
}
__ bind(&slow);
// Call the runtime to find the function to call (returned in eax) and
// the object holding it (returned in edx).
__ push(context_register());
__ push(Immediate(callee->name()));
__ CallRuntime(Runtime::kLoadLookupSlot, 2);
__ push(eax); // Function.
__ push(edx); // Receiver.
PrepareForBailoutForId(expr->LookupId(), NO_REGISTERS);
// If fast case code has been generated, emit code to push the function
// and receiver and have the slow path jump around this code.
if (done.is_linked()) {
Label call;
__ jmp(&call, Label::kNear);
__ bind(&done);
// Push function.
__ push(eax);
// The receiver is implicitly the global receiver. Indicate this by
// passing the hole to the call function stub.
__ push(Immediate(isolate()->factory()->undefined_value()));
__ bind(&call);
}
} else {
VisitForStackValue(callee);
// refEnv.WithBaseObject()
__ push(Immediate(isolate()->factory()->undefined_value()));
}
}
void FullCodeGenerator::VisitCall(Call* expr) {
#ifdef DEBUG
// We want to verify that RecordJSReturnSite gets called on all paths
@ -3035,9 +3078,8 @@ void FullCodeGenerator::VisitCall(Call* expr) {
ZoneList<Expression*>* args = expr->arguments();
int arg_count = args->length();
{ PreservePositionScope pos_scope(masm()->positions_recorder());
VisitForStackValue(callee);
// Reserved receiver slot.
__ push(Immediate(isolate()->factory()->undefined_value()));
PushCalleeAndWithBaseObject(expr);
// Push the arguments.
for (int i = 0; i < arg_count; i++) {
VisitForStackValue(args->at(i));
@ -3051,7 +3093,7 @@ void FullCodeGenerator::VisitCall(Call* expr) {
// Touch up the stack with the resolved function.
__ mov(Operand(esp, (arg_count + 1) * kPointerSize), eax);
PrepareForBailoutForId(expr->EvalOrLookupId(), NO_REGISTERS);
PrepareForBailoutForId(expr->EvalId(), NO_REGISTERS);
}
// Record source position for debugger.
SetSourcePosition(expr->position());
@ -3067,41 +3109,8 @@ void FullCodeGenerator::VisitCall(Call* expr) {
EmitCallWithLoadIC(expr);
} else if (call_type == Call::LOOKUP_SLOT_CALL) {
// Call to a lookup slot (dynamically introduced variable).
VariableProxy* proxy = callee->AsVariableProxy();
Label slow, done;
{ PreservePositionScope scope(masm()->positions_recorder());
// Generate code for loading from variables potentially shadowed by
// eval-introduced variables.
EmitDynamicLookupFastCase(proxy, NOT_INSIDE_TYPEOF, &slow, &done);
}
__ bind(&slow);
// Call the runtime to find the function to call (returned in eax) and
// the object holding it (returned in edx).
__ push(context_register());
__ push(Immediate(proxy->name()));
__ CallRuntime(Runtime::kLoadLookupSlot, 2);
__ push(eax); // Function.
__ push(edx); // Receiver.
PrepareForBailoutForId(expr->EvalOrLookupId(), NO_REGISTERS);
// If fast case code has been generated, emit code to push the function
// and receiver and have the slow path jump around this code.
if (done.is_linked()) {
Label call;
__ jmp(&call, Label::kNear);
__ bind(&done);
// Push function.
__ push(eax);
// The receiver is implicitly the global receiver. Indicate this by
// passing the hole to the call function stub.
__ push(Immediate(isolate()->factory()->undefined_value()));
__ bind(&call);
}
// The receiver is either the global receiver or an object found by
// LoadContextSlot.
PushCalleeAndWithBaseObject(expr);
EmitCall(expr);
} else if (call_type == Call::PROPERTY_CALL) {
Property* property = callee->AsProperty();
bool is_named_call = property->key()->IsPropertyName();

View File

@ -0,0 +1,6 @@
// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
var o = { eval: function() { return this; } }
with (o) assertSame(o, eval());