Index: src/x64/full-codegen-x64.cc |
=================================================================== |
--- src/x64/full-codegen-x64.cc (revision 5430) |
+++ src/x64/full-codegen-x64.cc (working copy) |
@@ -943,6 +943,89 @@ |
} |
+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 using a single register without |
+ // clobbering esi. |
Søren Thygesen Gjesse
2010/09/10 07:44:24
esi -> rsi
Mads Ager (chromium)
2010/09/10 10:51:43
Done.
|
+ 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 +1051,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 +1867,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 +3181,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. |