Revision: 5441
Author: [email protected]
Date: Fri Sep 10 03:57:07 2010
Log: 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
http://code.google.com/p/v8/source/detail?r=5441
Modified:
/branches/bleeding_edge/src/arm/full-codegen-arm.cc
/branches/bleeding_edge/src/full-codegen.h
/branches/bleeding_edge/src/ia32/full-codegen-ia32.cc
/branches/bleeding_edge/src/x64/assembler-x64.cc
/branches/bleeding_edge/src/x64/full-codegen-x64.cc
=======================================
--- /branches/bleeding_edge/src/arm/full-codegen-arm.cc Thu Sep 9 03:44:24
2010
+++ /branches/bleeding_edge/src/arm/full-codegen-arm.cc Fri Sep 10 03:57:07
2010
@@ -877,6 +877,89 @@
Comment cmnt(masm_, "[ VariableProxy");
EmitVariableLoad(expr->var(), context_);
}
+
+
+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(
@@ -899,8 +982,7 @@
// 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 @@
} 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 @@
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 @@
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 @@
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 @@
} 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.
=======================================
--- /branches/bleeding_edge/src/full-codegen.h Thu Sep 9 03:44:24 2010
+++ /branches/bleeding_edge/src/full-codegen.h Fri Sep 10 03:57:07 2010
@@ -384,6 +384,11 @@
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
=======================================
--- /branches/bleeding_edge/src/ia32/full-codegen-ia32.cc Thu Sep 9
03:44:24 2010
+++ /branches/bleeding_edge/src/ia32/full-codegen-ia32.cc Fri Sep 10
03:57:07 2010
@@ -902,8 +902,7 @@
// 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
@@ -945,6 +944,88 @@
: RelocInfo::CODE_TARGET_CONTEXT;
__ call(ic, mode);
}
+
+
+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,
@@ -973,25 +1054,19 @@
} 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 @@
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 @@
} 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.
=======================================
--- /branches/bleeding_edge/src/x64/assembler-x64.cc Wed Aug 11 03:52:34
2010
+++ /branches/bleeding_edge/src/x64/assembler-x64.cc Fri Sep 10 03:57:07
2010
@@ -829,6 +829,7 @@
void Assembler::call(Handle<Code> target, RelocInfo::Mode rmode) {
+ WriteRecordedPositions();
EnsureSpace ensure_space(this);
last_pc_ = pc_;
// 1110 1000 #32-bit disp.
=======================================
--- /branches/bleeding_edge/src/x64/full-codegen-x64.cc Thu Sep 9 03:44:24
2010
+++ /branches/bleeding_edge/src/x64/full-codegen-x64.cc Fri Sep 10 03:57:07
2010
@@ -897,8 +897,7 @@
// 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
@@ -941,6 +940,88 @@
: RelocInfo::CODE_TARGET_CONTEXT;
__ call(ic, mode);
}
+
+
+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,
@@ -968,25 +1049,19 @@
} 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 @@
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 @@
} 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.
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev