Index: src/x64/codegen-x64.cc |
=================================================================== |
--- src/x64/codegen-x64.cc (revision 4644) |
+++ src/x64/codegen-x64.cc (working copy) |
@@ -2876,77 +2876,17 @@ |
// } |
// ---------------------------------- |
- JumpTarget slow; |
- JumpTarget 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. |
+ JumpTarget slow, done; |
Result function; |
- if (var->mode() == Variable::DYNAMIC_GLOBAL) { |
- function = LoadFromGlobalSlotCheckExtensions(var->slot(), |
- NOT_INSIDE_TYPEOF, |
- &slow); |
- frame_->Push(&function); |
- LoadGlobalReceiver(); |
- done.Jump(); |
- } else if (var->mode() == Variable::DYNAMIC_LOCAL) { |
- Slot* potential_slot = var->local_if_not_shadowed()->slot(); |
- Expression* rewrite = var->local_if_not_shadowed()->rewrite(); |
- if (potential_slot != NULL) { |
- // Generate fast case for locals that rewrite to slots. |
- // Allocate a fresh register to use as a temp in |
- // ContextSlotOperandCheckExtensions and to hold the result |
- // value. |
- function = allocator()->Allocate(); |
- ASSERT(function.is_valid()); |
- __ movq(function.reg(), |
- ContextSlotOperandCheckExtensions(potential_slot, |
- function, |
- &slow)); |
- JumpTarget push_function_and_receiver; |
- if (potential_slot->var()->mode() == Variable::CONST) { |
- __ CompareRoot(function.reg(), Heap::kTheHoleValueRootIndex); |
- push_function_and_receiver.Branch(not_equal, &function); |
- __ LoadRoot(function.reg(), Heap::kUndefinedValueRootIndex); |
- } |
- push_function_and_receiver.Bind(&function); |
- frame_->Push(&function); |
- LoadGlobalReceiver(); |
- done.Jump(); |
- } 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. |
- Result arguments = allocator()->Allocate(); |
- ASSERT(arguments.is_valid()); |
- __ movq(arguments.reg(), |
- ContextSlotOperandCheckExtensions(obj_proxy->var()->slot(), |
- arguments, |
- &slow)); |
- frame_->Push(&arguments); |
- frame_->Push(key_literal->handle()); |
- Result value = EmitKeyedLoad(false); |
- frame_->Drop(2); // Drop key and receiver. |
- frame_->Push(&value); |
- LoadGlobalReceiver(); |
- done.Jump(); |
- } |
- } |
- } |
- } |
+ // Generate fast case for loading functions from slots that |
+ // correspond to local/global variables or arguments unless they |
+ // are shadowed by eval-introduced bindings. |
+ EmitDynamicLoadFromSlotFastCase(var->slot(), |
+ NOT_INSIDE_TYPEOF, |
+ &function, |
+ &slow, |
+ &done); |
slow.Bind(); |
// Load the function from the context. Sync the frame so we can |
@@ -2967,7 +2907,18 @@ |
ASSERT(!allocator()->is_used(rdx)); |
frame_->EmitPush(rdx); |
- done.Bind(); |
+ // 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()) { |
+ JumpTarget call; |
+ call.Jump(); |
+ done.Bind(&function); |
+ frame_->Push(&function); |
+ LoadGlobalReceiver(); |
+ call.Bind(); |
+ } |
+ |
// Call the function. |
CallWithArguments(args, NO_CALL_FUNCTION_FLAGS, node->position()); |
@@ -5367,64 +5318,15 @@ |
JumpTarget done; |
Result value; |
- // 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) { |
- value = LoadFromGlobalSlotCheckExtensions(slot, typeof_state, &slow); |
- done.Jump(&value); |
+ // Generate fast case for loading from slots that correspond to |
+ // local/global variables or arguments unless they are shadowed by |
+ // eval-introduced bindings. |
+ EmitDynamicLoadFromSlotFastCase(slot, |
+ typeof_state, |
+ &value, |
+ &slow, |
+ &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. |
- // Allocate a fresh register to use as a temp in |
- // ContextSlotOperandCheckExtensions and to hold the result |
- // value. |
- value = allocator_->Allocate(); |
- ASSERT(value.is_valid()); |
- __ movq(value.reg(), |
- ContextSlotOperandCheckExtensions(potential_slot, |
- value, |
- &slow)); |
- if (potential_slot->var()->mode() == Variable::CONST) { |
- __ CompareRoot(value.reg(), Heap::kTheHoleValueRootIndex); |
- done.Branch(not_equal, &value); |
- __ LoadRoot(value.reg(), Heap::kUndefinedValueRootIndex); |
- } |
- done.Jump(&value); |
- } else if (rewrite != NULL) { |
- // Generate fast case for argument loads. |
- 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. |
- Result arguments = allocator()->Allocate(); |
- ASSERT(arguments.is_valid()); |
- __ movq(arguments.reg(), |
- ContextSlotOperandCheckExtensions(obj_proxy->var()->slot(), |
- arguments, |
- &slow)); |
- frame_->Push(&arguments); |
- frame_->Push(key_literal->handle()); |
- value = EmitKeyedLoad(false); |
- frame_->Drop(2); // Drop key and receiver. |
- done.Jump(&value); |
- } |
- } |
- } |
- } |
- |
slow.Bind(); |
// A runtime call is inevitable. We eagerly sync frame elements |
// to memory so that we can push the arguments directly into place |
@@ -5689,6 +5591,71 @@ |
} |
+void CodeGenerator::EmitDynamicLoadFromSlotFastCase(Slot* slot, |
+ TypeofState typeof_state, |
+ Result* result, |
+ JumpTarget* slow, |
+ JumpTarget* 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) { |
+ *result = LoadFromGlobalSlotCheckExtensions(slot, typeof_state, slow); |
+ done->Jump(result); |
+ |
+ } 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. |
+ // Allocate a fresh register to use as a temp in |
+ // ContextSlotOperandCheckExtensions and to hold the result |
+ // value. |
+ *result = allocator_->Allocate(); |
+ ASSERT(result->is_valid()); |
+ __ movq(result->reg(), |
+ ContextSlotOperandCheckExtensions(potential_slot, |
+ *result, |
+ slow)); |
+ if (potential_slot->var()->mode() == Variable::CONST) { |
+ __ CompareRoot(result->reg(), Heap::kTheHoleValueRootIndex); |
+ done->Branch(not_equal, result); |
+ __ LoadRoot(result->reg(), Heap::kUndefinedValueRootIndex); |
+ } |
+ done->Jump(result); |
+ } else if (rewrite != NULL) { |
+ // Generate fast case for argument loads. |
+ 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. |
+ Result arguments = allocator()->Allocate(); |
+ ASSERT(arguments.is_valid()); |
+ __ movq(arguments.reg(), |
+ ContextSlotOperandCheckExtensions(obj_proxy->var()->slot(), |
+ arguments, |
+ slow)); |
+ frame_->Push(&arguments); |
+ frame_->Push(key_literal->handle()); |
+ *result = EmitKeyedLoad(false); |
+ frame_->Drop(2); // Drop key and receiver. |
+ done->Jump(result); |
+ } |
+ } |
+ } |
+ } |
+} |
+ |
+ |
void CodeGenerator::LoadGlobal() { |
if (in_spilled_code()) { |
frame_->EmitPush(GlobalObject()); |