Chromium Code Reviews| 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. |