Handle both global and local variables potentially shadowed by
eval-introduced variables in full-codegen. Make sure that x64 assembler records source positions for calls. Review URL: http://codereview.chromium.org/3357022 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@5441 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
bc2bf76129
commit
666b98fb4b
@ -879,6 +879,89 @@ void FullCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
|
||||
}
|
||||
|
||||
|
||||
MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions(
|
||||
Slot* slot,
|
||||
Label* slow) {
|
||||
ASSERT(slot->type() == Slot::CONTEXT);
|
||||
Register current = cp;
|
||||
Register next = r3;
|
||||
Register temp = r4;
|
||||
|
||||
for (Scope* s = scope(); s != slot->var()->scope(); s = s->outer_scope()) {
|
||||
if (s->num_heap_slots() > 0) {
|
||||
if (s->calls_eval()) {
|
||||
// Check that extension is NULL.
|
||||
__ ldr(temp, ContextOperand(current, Context::EXTENSION_INDEX));
|
||||
__ tst(temp, temp);
|
||||
__ b(ne, slow);
|
||||
}
|
||||
__ ldr(next, ContextOperand(current, Context::CLOSURE_INDEX));
|
||||
__ ldr(next, FieldMemOperand(next, JSFunction::kContextOffset));
|
||||
// Walk the rest of the chain without clobbering cp.
|
||||
current = next;
|
||||
}
|
||||
}
|
||||
// Check that last extension is NULL.
|
||||
__ ldr(temp, ContextOperand(current, Context::EXTENSION_INDEX));
|
||||
__ tst(temp, temp);
|
||||
__ b(ne, slow);
|
||||
__ ldr(temp, ContextOperand(current, Context::FCONTEXT_INDEX));
|
||||
return ContextOperand(temp, slot->index());
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitDynamicLoadFromSlotFastCase(
|
||||
Slot* slot,
|
||||
TypeofState typeof_state,
|
||||
Label* slow,
|
||||
Label* done) {
|
||||
// Generate fast-case code for variables that might be shadowed by
|
||||
// eval-introduced variables. Eval is used a lot without
|
||||
// introducing variables. In those cases, we do not want to
|
||||
// perform a runtime call for all variables in the scope
|
||||
// containing the eval.
|
||||
if (slot->var()->mode() == Variable::DYNAMIC_GLOBAL) {
|
||||
EmitLoadGlobalSlotCheckExtensions(slot, typeof_state, slow);
|
||||
__ jmp(done);
|
||||
} else if (slot->var()->mode() == Variable::DYNAMIC_LOCAL) {
|
||||
Slot* potential_slot = slot->var()->local_if_not_shadowed()->slot();
|
||||
Expression* rewrite = slot->var()->local_if_not_shadowed()->rewrite();
|
||||
if (potential_slot != NULL) {
|
||||
// Generate fast case for locals that rewrite to slots.
|
||||
__ ldr(r0, ContextSlotOperandCheckExtensions(potential_slot, slow));
|
||||
if (potential_slot->var()->mode() == Variable::CONST) {
|
||||
__ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
|
||||
__ cmp(r0, ip);
|
||||
__ LoadRoot(r0, Heap::kUndefinedValueRootIndex, eq);
|
||||
}
|
||||
__ jmp(done);
|
||||
} else if (rewrite != NULL) {
|
||||
// Generate fast case for calls of an argument function.
|
||||
Property* property = rewrite->AsProperty();
|
||||
if (property != NULL) {
|
||||
VariableProxy* obj_proxy = property->obj()->AsVariableProxy();
|
||||
Literal* key_literal = property->key()->AsLiteral();
|
||||
if (obj_proxy != NULL &&
|
||||
key_literal != NULL &&
|
||||
obj_proxy->IsArguments() &&
|
||||
key_literal->handle()->IsSmi()) {
|
||||
// Load arguments object if there are no eval-introduced
|
||||
// variables. Then load the argument from the arguments
|
||||
// object using keyed load.
|
||||
__ ldr(r1,
|
||||
ContextSlotOperandCheckExtensions(obj_proxy->var()->slot(),
|
||||
slow));
|
||||
__ mov(r0, Operand(key_literal->handle()));
|
||||
Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
|
||||
__ Call(ic, RelocInfo::CODE_TARGET);
|
||||
__ jmp(done);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitLoadGlobalSlotCheckExtensions(
|
||||
Slot* slot,
|
||||
TypeofState typeof_state,
|
||||
@ -899,8 +982,7 @@ void FullCodeGenerator::EmitLoadGlobalSlotCheckExtensions(
|
||||
// Load next context in chain.
|
||||
__ ldr(next, ContextOperand(current, Context::CLOSURE_INDEX));
|
||||
__ ldr(next, FieldMemOperand(next, JSFunction::kContextOffset));
|
||||
// Walk the rest of the chain using a single register without
|
||||
// clobbering cp.
|
||||
// Walk the rest of the chain without clobbering cp.
|
||||
current = next;
|
||||
}
|
||||
// If no outer scope calls eval, we do not need to check more
|
||||
@ -962,25 +1044,19 @@ void FullCodeGenerator::EmitVariableLoad(Variable* var,
|
||||
} else if (slot != NULL && slot->type() == Slot::LOOKUP) {
|
||||
Label done, slow;
|
||||
|
||||
// Generate fast-case code for variables that might be shadowed by
|
||||
// eval-introduced variables. Eval is used a lot without
|
||||
// introducing variables. In those cases, we do not want to
|
||||
// perform a runtime call for all variables in the scope
|
||||
// containing the eval.
|
||||
if (slot->var()->mode() == Variable::DYNAMIC_GLOBAL) {
|
||||
EmitLoadGlobalSlotCheckExtensions(slot, NOT_INSIDE_TYPEOF, &slow);
|
||||
Apply(context, r0);
|
||||
__ jmp(&done);
|
||||
}
|
||||
// Generate code for loading from variables potentially shadowed
|
||||
// by eval-introduced variables.
|
||||
EmitDynamicLoadFromSlotFastCase(slot, NOT_INSIDE_TYPEOF, &slow, &done);
|
||||
|
||||
__ bind(&slow);
|
||||
Comment cmnt(masm_, "Lookup slot");
|
||||
__ mov(r1, Operand(var->name()));
|
||||
__ Push(cp, r1); // Context and name.
|
||||
__ CallRuntime(Runtime::kLoadContextSlot, 2);
|
||||
Apply(context, r0);
|
||||
__ bind(&done);
|
||||
|
||||
Apply(context, r0);
|
||||
|
||||
} else if (slot != NULL) {
|
||||
Comment cmnt(masm_, (slot->type() == Slot::CONTEXT)
|
||||
? "Context slot"
|
||||
@ -988,14 +1064,11 @@ void FullCodeGenerator::EmitVariableLoad(Variable* var,
|
||||
if (var->mode() == Variable::CONST) {
|
||||
// Constants may be the hole value if they have not been initialized.
|
||||
// Unhole them.
|
||||
Label done;
|
||||
MemOperand slot_operand = EmitSlotSearch(slot, r0);
|
||||
__ ldr(r0, slot_operand);
|
||||
__ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
|
||||
__ cmp(r0, ip);
|
||||
__ b(ne, &done);
|
||||
__ LoadRoot(r0, Heap::kUndefinedValueRootIndex);
|
||||
__ bind(&done);
|
||||
__ LoadRoot(r0, Heap::kUndefinedValueRootIndex, eq);
|
||||
Apply(context, r0);
|
||||
} else {
|
||||
Apply(context, slot);
|
||||
@ -1722,15 +1795,41 @@ void FullCodeGenerator::VisitCall(Call* expr) {
|
||||
EmitCallWithIC(expr, var->name(), RelocInfo::CODE_TARGET_CONTEXT);
|
||||
} else if (var != NULL && var->slot() != NULL &&
|
||||
var->slot()->type() == Slot::LOOKUP) {
|
||||
// Call to a lookup slot (dynamically introduced variable). Call the
|
||||
// runtime to find the function to call (returned in eax) and the object
|
||||
// holding it (returned in edx).
|
||||
// Call to a lookup slot (dynamically introduced variable).
|
||||
Label slow, done;
|
||||
|
||||
// Generate code for loading from variables potentially shadowed
|
||||
// by eval-introduced variables.
|
||||
EmitDynamicLoadFromSlotFastCase(var->slot(),
|
||||
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());
|
||||
__ mov(r2, Operand(var->name()));
|
||||
__ push(r2);
|
||||
__ CallRuntime(Runtime::kLoadContextSlot, 2);
|
||||
__ push(r0); // Function.
|
||||
__ push(r1); // Receiver.
|
||||
__ Push(r0, r1); // Function, receiver.
|
||||
|
||||
// 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);
|
||||
// Push global receiver.
|
||||
__ ldr(r1, CodeGenerator::GlobalObject());
|
||||
__ ldr(r1, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset));
|
||||
__ push(r1);
|
||||
__ bind(&call);
|
||||
}
|
||||
|
||||
EmitCallWithStub(expr);
|
||||
} else if (fun->AsProperty() != NULL) {
|
||||
// Call to an object property.
|
||||
@ -1753,12 +1852,9 @@ void FullCodeGenerator::VisitCall(Call* expr) {
|
||||
|
||||
Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
|
||||
__ Call(ic, RelocInfo::CODE_TARGET);
|
||||
// Push result (function).
|
||||
__ push(r0);
|
||||
// Push Global receiver.
|
||||
__ ldr(r1, CodeGenerator::GlobalObject());
|
||||
__ ldr(r1, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset));
|
||||
__ push(r1);
|
||||
__ Push(r0, r1); // Function, receiver.
|
||||
EmitCallWithStub(expr);
|
||||
} else {
|
||||
EmitKeyedCallWithIC(expr, prop->key(), RelocInfo::CODE_TARGET);
|
||||
@ -3002,9 +3098,19 @@ void FullCodeGenerator::VisitForTypeofValue(Expression* expr, Location where) {
|
||||
} else if (proxy != NULL &&
|
||||
proxy->var()->slot() != NULL &&
|
||||
proxy->var()->slot()->type() == Slot::LOOKUP) {
|
||||
Label done, slow;
|
||||
|
||||
// Generate code for loading from variables potentially shadowed
|
||||
// by eval-introduced variables.
|
||||
Slot* slot = proxy->var()->slot();
|
||||
EmitDynamicLoadFromSlotFastCase(slot, INSIDE_TYPEOF, &slow, &done);
|
||||
|
||||
__ bind(&slow);
|
||||
__ mov(r0, Operand(proxy->name()));
|
||||
__ Push(cp, r0);
|
||||
__ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2);
|
||||
__ bind(&done);
|
||||
|
||||
if (where == kStack) __ push(r0);
|
||||
} else {
|
||||
// This expression cannot throw a reference error at the top level.
|
||||
|
@ -384,6 +384,11 @@ class FullCodeGenerator: public AstVisitor {
|
||||
void EmitLoadGlobalSlotCheckExtensions(Slot* slot,
|
||||
TypeofState typeof_state,
|
||||
Label* slow);
|
||||
MemOperand ContextSlotOperandCheckExtensions(Slot* slot, Label* slow);
|
||||
void EmitDynamicLoadFromSlotFastCase(Slot* slot,
|
||||
TypeofState typeof_state,
|
||||
Label* slow,
|
||||
Label* done);
|
||||
void EmitVariableLoad(Variable* expr, Expression::Context context);
|
||||
|
||||
// Platform-specific support for allocating a new closure based on
|
||||
|
@ -902,8 +902,7 @@ void FullCodeGenerator::EmitLoadGlobalSlotCheckExtensions(
|
||||
// Load next context in chain.
|
||||
__ mov(temp, ContextOperand(context, Context::CLOSURE_INDEX));
|
||||
__ mov(temp, FieldOperand(temp, JSFunction::kContextOffset));
|
||||
// Walk the rest of the chain using a single register without
|
||||
// clobbering esi.
|
||||
// Walk the rest of the chain without clobbering esi.
|
||||
context = temp;
|
||||
}
|
||||
// If no outer scope calls eval, we do not need to check more
|
||||
@ -947,6 +946,88 @@ void FullCodeGenerator::EmitLoadGlobalSlotCheckExtensions(
|
||||
}
|
||||
|
||||
|
||||
MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions(
|
||||
Slot* slot,
|
||||
Label* slow) {
|
||||
ASSERT(slot->type() == Slot::CONTEXT);
|
||||
Register context = esi;
|
||||
Register temp = ebx;
|
||||
|
||||
for (Scope* s = scope(); s != slot->var()->scope(); s = s->outer_scope()) {
|
||||
if (s->num_heap_slots() > 0) {
|
||||
if (s->calls_eval()) {
|
||||
// Check that extension is NULL.
|
||||
__ cmp(ContextOperand(context, Context::EXTENSION_INDEX),
|
||||
Immediate(0));
|
||||
__ j(not_equal, slow);
|
||||
}
|
||||
__ mov(temp, ContextOperand(context, Context::CLOSURE_INDEX));
|
||||
__ mov(temp, FieldOperand(temp, JSFunction::kContextOffset));
|
||||
// Walk the rest of the chain without clobbering esi.
|
||||
context = temp;
|
||||
}
|
||||
}
|
||||
// Check that last extension is NULL.
|
||||
__ cmp(ContextOperand(context, Context::EXTENSION_INDEX), Immediate(0));
|
||||
__ j(not_equal, slow);
|
||||
__ mov(temp, ContextOperand(context, Context::FCONTEXT_INDEX));
|
||||
return ContextOperand(temp, slot->index());
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitDynamicLoadFromSlotFastCase(
|
||||
Slot* slot,
|
||||
TypeofState typeof_state,
|
||||
Label* slow,
|
||||
Label* done) {
|
||||
// Generate fast-case code for variables that might be shadowed by
|
||||
// eval-introduced variables. Eval is used a lot without
|
||||
// introducing variables. In those cases, we do not want to
|
||||
// perform a runtime call for all variables in the scope
|
||||
// containing the eval.
|
||||
if (slot->var()->mode() == Variable::DYNAMIC_GLOBAL) {
|
||||
EmitLoadGlobalSlotCheckExtensions(slot, typeof_state, slow);
|
||||
__ jmp(done);
|
||||
} else if (slot->var()->mode() == Variable::DYNAMIC_LOCAL) {
|
||||
Slot* potential_slot = slot->var()->local_if_not_shadowed()->slot();
|
||||
Expression* rewrite = slot->var()->local_if_not_shadowed()->rewrite();
|
||||
if (potential_slot != NULL) {
|
||||
// Generate fast case for locals that rewrite to slots.
|
||||
__ mov(eax,
|
||||
ContextSlotOperandCheckExtensions(potential_slot, slow));
|
||||
if (potential_slot->var()->mode() == Variable::CONST) {
|
||||
__ cmp(eax, Factory::the_hole_value());
|
||||
__ j(not_equal, done);
|
||||
__ mov(eax, Factory::undefined_value());
|
||||
}
|
||||
__ jmp(done);
|
||||
} else if (rewrite != NULL) {
|
||||
// Generate fast case for calls of an argument function.
|
||||
Property* property = rewrite->AsProperty();
|
||||
if (property != NULL) {
|
||||
VariableProxy* obj_proxy = property->obj()->AsVariableProxy();
|
||||
Literal* key_literal = property->key()->AsLiteral();
|
||||
if (obj_proxy != NULL &&
|
||||
key_literal != NULL &&
|
||||
obj_proxy->IsArguments() &&
|
||||
key_literal->handle()->IsSmi()) {
|
||||
// Load arguments object if there are no eval-introduced
|
||||
// variables. Then load the argument from the arguments
|
||||
// object using keyed load.
|
||||
__ mov(edx,
|
||||
ContextSlotOperandCheckExtensions(obj_proxy->var()->slot(),
|
||||
slow));
|
||||
__ mov(eax, Immediate(key_literal->handle()));
|
||||
Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
|
||||
__ call(ic, RelocInfo::CODE_TARGET);
|
||||
__ jmp(done);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitVariableLoad(Variable* var,
|
||||
Expression::Context context) {
|
||||
// Four cases: non-this global variables, lookup slots, all other
|
||||
@ -973,25 +1054,19 @@ void FullCodeGenerator::EmitVariableLoad(Variable* var,
|
||||
} else if (slot != NULL && slot->type() == Slot::LOOKUP) {
|
||||
Label done, slow;
|
||||
|
||||
// Generate fast-case code for variables that might be shadowed by
|
||||
// eval-introduced variables. Eval is used a lot without
|
||||
// introducing variables. In those cases, we do not want to
|
||||
// perform a runtime call for all variables in the scope
|
||||
// containing the eval.
|
||||
if (slot->var()->mode() == Variable::DYNAMIC_GLOBAL) {
|
||||
EmitLoadGlobalSlotCheckExtensions(slot, NOT_INSIDE_TYPEOF, &slow);
|
||||
Apply(context, eax);
|
||||
__ jmp(&done);
|
||||
}
|
||||
// Generate code for loading from variables potentially shadowed
|
||||
// by eval-introduced variables.
|
||||
EmitDynamicLoadFromSlotFastCase(slot, NOT_INSIDE_TYPEOF, &slow, &done);
|
||||
|
||||
__ bind(&slow);
|
||||
Comment cmnt(masm_, "Lookup slot");
|
||||
__ push(esi); // Context.
|
||||
__ push(Immediate(var->name()));
|
||||
__ CallRuntime(Runtime::kLoadContextSlot, 2);
|
||||
Apply(context, eax);
|
||||
__ bind(&done);
|
||||
|
||||
Apply(context, eax);
|
||||
|
||||
} else if (slot != NULL) {
|
||||
Comment cmnt(masm_, (slot->type() == Slot::CONTEXT)
|
||||
? "Context slot"
|
||||
@ -2030,14 +2105,40 @@ void FullCodeGenerator::VisitCall(Call* expr) {
|
||||
EmitCallWithIC(expr, var->name(), RelocInfo::CODE_TARGET_CONTEXT);
|
||||
} else if (var != NULL && var->slot() != NULL &&
|
||||
var->slot()->type() == Slot::LOOKUP) {
|
||||
// Call to a lookup slot (dynamically introduced variable). Call the
|
||||
// runtime to find the function to call (returned in eax) and the object
|
||||
// holding it (returned in edx).
|
||||
// Call to a lookup slot (dynamically introduced variable).
|
||||
Label slow, done;
|
||||
|
||||
// Generate code for loading from variables potentially shadowed
|
||||
// by eval-introduced variables.
|
||||
EmitDynamicLoadFromSlotFastCase(var->slot(),
|
||||
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(var->name()));
|
||||
__ CallRuntime(Runtime::kLoadContextSlot, 2);
|
||||
__ push(eax); // Function.
|
||||
__ push(edx); // Receiver.
|
||||
|
||||
// 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);
|
||||
__ bind(&done);
|
||||
// Push function.
|
||||
__ push(eax);
|
||||
// Push global receiver.
|
||||
__ mov(ebx, CodeGenerator::GlobalObject());
|
||||
__ push(FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset));
|
||||
__ bind(&call);
|
||||
}
|
||||
|
||||
EmitCallWithStub(expr);
|
||||
} else if (fun->AsProperty() != NULL) {
|
||||
// Call to an object property.
|
||||
@ -3341,9 +3442,19 @@ void FullCodeGenerator::VisitForTypeofValue(Expression* expr, Location where) {
|
||||
} else if (proxy != NULL &&
|
||||
proxy->var()->slot() != NULL &&
|
||||
proxy->var()->slot()->type() == Slot::LOOKUP) {
|
||||
Label done, slow;
|
||||
|
||||
// Generate code for loading from variables potentially shadowed
|
||||
// by eval-introduced variables.
|
||||
Slot* slot = proxy->var()->slot();
|
||||
EmitDynamicLoadFromSlotFastCase(slot, INSIDE_TYPEOF, &slow, &done);
|
||||
|
||||
__ bind(&slow);
|
||||
__ push(esi);
|
||||
__ push(Immediate(proxy->name()));
|
||||
__ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2);
|
||||
__ bind(&done);
|
||||
|
||||
if (where == kStack) __ push(eax);
|
||||
} else {
|
||||
// This expression cannot throw a reference error at the top level.
|
||||
|
@ -829,6 +829,7 @@ void Assembler::call(Label* L) {
|
||||
|
||||
|
||||
void Assembler::call(Handle<Code> target, RelocInfo::Mode rmode) {
|
||||
WriteRecordedPositions();
|
||||
EnsureSpace ensure_space(this);
|
||||
last_pc_ = pc_;
|
||||
// 1110 1000 #32-bit disp.
|
||||
|
@ -897,8 +897,7 @@ void FullCodeGenerator::EmitLoadGlobalSlotCheckExtensions(
|
||||
// Load next context in chain.
|
||||
__ movq(temp, ContextOperand(context, Context::CLOSURE_INDEX));
|
||||
__ movq(temp, FieldOperand(temp, JSFunction::kContextOffset));
|
||||
// Walk the rest of the chain using a single register without
|
||||
// clobbering rsi.
|
||||
// Walk the rest of the chain without clobbering rsi.
|
||||
context = temp;
|
||||
}
|
||||
// If no outer scope calls eval, we do not need to check more
|
||||
@ -943,6 +942,88 @@ void FullCodeGenerator::EmitLoadGlobalSlotCheckExtensions(
|
||||
}
|
||||
|
||||
|
||||
MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions(
|
||||
Slot* slot,
|
||||
Label* slow) {
|
||||
ASSERT(slot->type() == Slot::CONTEXT);
|
||||
Register context = rsi;
|
||||
Register temp = rbx;
|
||||
|
||||
for (Scope* s = scope(); s != slot->var()->scope(); s = s->outer_scope()) {
|
||||
if (s->num_heap_slots() > 0) {
|
||||
if (s->calls_eval()) {
|
||||
// Check that extension is NULL.
|
||||
__ cmpq(ContextOperand(context, Context::EXTENSION_INDEX),
|
||||
Immediate(0));
|
||||
__ j(not_equal, slow);
|
||||
}
|
||||
__ movq(temp, ContextOperand(context, Context::CLOSURE_INDEX));
|
||||
__ movq(temp, FieldOperand(temp, JSFunction::kContextOffset));
|
||||
// Walk the rest of the chain without clobbering rsi.
|
||||
context = temp;
|
||||
}
|
||||
}
|
||||
// Check that last extension is NULL.
|
||||
__ cmpq(ContextOperand(context, Context::EXTENSION_INDEX), Immediate(0));
|
||||
__ j(not_equal, slow);
|
||||
__ movq(temp, ContextOperand(context, Context::FCONTEXT_INDEX));
|
||||
return ContextOperand(temp, slot->index());
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitDynamicLoadFromSlotFastCase(
|
||||
Slot* slot,
|
||||
TypeofState typeof_state,
|
||||
Label* slow,
|
||||
Label* done) {
|
||||
// Generate fast-case code for variables that might be shadowed by
|
||||
// eval-introduced variables. Eval is used a lot without
|
||||
// introducing variables. In those cases, we do not want to
|
||||
// perform a runtime call for all variables in the scope
|
||||
// containing the eval.
|
||||
if (slot->var()->mode() == Variable::DYNAMIC_GLOBAL) {
|
||||
EmitLoadGlobalSlotCheckExtensions(slot, typeof_state, slow);
|
||||
__ jmp(done);
|
||||
} else if (slot->var()->mode() == Variable::DYNAMIC_LOCAL) {
|
||||
Slot* potential_slot = slot->var()->local_if_not_shadowed()->slot();
|
||||
Expression* rewrite = slot->var()->local_if_not_shadowed()->rewrite();
|
||||
if (potential_slot != NULL) {
|
||||
// Generate fast case for locals that rewrite to slots.
|
||||
__ movq(rax,
|
||||
ContextSlotOperandCheckExtensions(potential_slot, slow));
|
||||
if (potential_slot->var()->mode() == Variable::CONST) {
|
||||
__ CompareRoot(rax, Heap::kTheHoleValueRootIndex);
|
||||
__ j(not_equal, done);
|
||||
__ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
|
||||
}
|
||||
__ jmp(done);
|
||||
} else if (rewrite != NULL) {
|
||||
// Generate fast case for calls of an argument function.
|
||||
Property* property = rewrite->AsProperty();
|
||||
if (property != NULL) {
|
||||
VariableProxy* obj_proxy = property->obj()->AsVariableProxy();
|
||||
Literal* key_literal = property->key()->AsLiteral();
|
||||
if (obj_proxy != NULL &&
|
||||
key_literal != NULL &&
|
||||
obj_proxy->IsArguments() &&
|
||||
key_literal->handle()->IsSmi()) {
|
||||
// Load arguments object if there are no eval-introduced
|
||||
// variables. Then load the argument from the arguments
|
||||
// object using keyed load.
|
||||
__ movq(rdx,
|
||||
ContextSlotOperandCheckExtensions(obj_proxy->var()->slot(),
|
||||
slow));
|
||||
__ Move(rax, key_literal->handle());
|
||||
Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
|
||||
__ call(ic, RelocInfo::CODE_TARGET);
|
||||
__ jmp(done);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitVariableLoad(Variable* var,
|
||||
Expression::Context context) {
|
||||
// Four cases: non-this global variables, lookup slots, all other
|
||||
@ -968,25 +1049,19 @@ void FullCodeGenerator::EmitVariableLoad(Variable* var,
|
||||
} else if (slot != NULL && slot->type() == Slot::LOOKUP) {
|
||||
Label done, slow;
|
||||
|
||||
// Generate fast-case code for variables that might be shadowed by
|
||||
// eval-introduced variables. Eval is used a lot without
|
||||
// introducing variables. In those cases, we do not want to
|
||||
// perform a runtime call for all variables in the scope
|
||||
// containing the eval.
|
||||
if (slot->var()->mode() == Variable::DYNAMIC_GLOBAL) {
|
||||
EmitLoadGlobalSlotCheckExtensions(slot, NOT_INSIDE_TYPEOF, &slow);
|
||||
Apply(context, rax);
|
||||
__ jmp(&done);
|
||||
}
|
||||
// Generate code for loading from variables potentially shadowed
|
||||
// by eval-introduced variables.
|
||||
EmitDynamicLoadFromSlotFastCase(slot, NOT_INSIDE_TYPEOF, &slow, &done);
|
||||
|
||||
__ bind(&slow);
|
||||
Comment cmnt(masm_, "Lookup slot");
|
||||
__ push(rsi); // Context.
|
||||
__ Push(var->name());
|
||||
__ CallRuntime(Runtime::kLoadContextSlot, 2);
|
||||
Apply(context, rax);
|
||||
__ bind(&done);
|
||||
|
||||
Apply(context, rax);
|
||||
|
||||
} else if (slot != NULL) {
|
||||
Comment cmnt(masm_, (slot->type() == Slot::CONTEXT)
|
||||
? "Context slot"
|
||||
@ -1790,15 +1865,42 @@ void FullCodeGenerator::VisitCall(Call* expr) {
|
||||
EmitCallWithIC(expr, var->name(), RelocInfo::CODE_TARGET_CONTEXT);
|
||||
} else if (var != NULL && var->slot() != NULL &&
|
||||
var->slot()->type() == Slot::LOOKUP) {
|
||||
// Call to a lookup slot (dynamically introduced variable). Call
|
||||
// the runtime to find the function to call (returned in rax) and
|
||||
// the object holding it (returned in rdx).
|
||||
// Call to a lookup slot (dynamically introduced variable).
|
||||
Label slow, done;
|
||||
|
||||
// Generate code for loading from variables potentially shadowed
|
||||
// by eval-introduced variables.
|
||||
EmitDynamicLoadFromSlotFastCase(var->slot(),
|
||||
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(var->name());
|
||||
__ CallRuntime(Runtime::kLoadContextSlot, 2);
|
||||
__ push(rax); // Function.
|
||||
__ push(rdx); // Receiver.
|
||||
|
||||
// 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);
|
||||
__ bind(&done);
|
||||
// Push function.
|
||||
__ push(rax);
|
||||
// Push global receiver.
|
||||
__ movq(rbx, CodeGenerator::GlobalObject());
|
||||
__ push(FieldOperand(rbx, GlobalObject::kGlobalReceiverOffset));
|
||||
__ bind(&call);
|
||||
}
|
||||
|
||||
EmitCallWithStub(expr);
|
||||
|
||||
} else if (fun->AsProperty() != NULL) {
|
||||
// Call to an object property.
|
||||
Property* prop = fun->AsProperty();
|
||||
@ -3077,9 +3179,19 @@ void FullCodeGenerator::VisitForTypeofValue(Expression* expr, Location where) {
|
||||
} else if (proxy != NULL &&
|
||||
proxy->var()->slot() != NULL &&
|
||||
proxy->var()->slot()->type() == Slot::LOOKUP) {
|
||||
Label done, slow;
|
||||
|
||||
// Generate code for loading from variables potentially shadowed
|
||||
// by eval-introduced variables.
|
||||
Slot* slot = proxy->var()->slot();
|
||||
EmitDynamicLoadFromSlotFastCase(slot, INSIDE_TYPEOF, &slow, &done);
|
||||
|
||||
__ bind(&slow);
|
||||
__ push(rsi);
|
||||
__ Push(proxy->name());
|
||||
__ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2);
|
||||
__ bind(&done);
|
||||
|
||||
if (where == kStack) __ push(rax);
|
||||
} else {
|
||||
// This expression cannot throw a reference error at the top level.
|
||||
|
Loading…
Reference in New Issue
Block a user