Revision: 4645
Author: [email protected]
Date: Wed May 12 02:12:23 2010
Log: Refactor the fast-case code for loading local/global variables and
arguments in the presence of eval to avoid code duplication. Almost
the same code was duplicated for loading properties and calling
properties.
Review URL: http://codereview.chromium.org/2053003
http://code.google.com/p/v8/source/detail?r=4645
Modified:
/branches/bleeding_edge/src/arm/codegen-arm.cc
/branches/bleeding_edge/src/arm/codegen-arm.h
/branches/bleeding_edge/src/ia32/codegen-ia32.cc
/branches/bleeding_edge/src/ia32/codegen-ia32.h
/branches/bleeding_edge/src/x64/codegen-x64.cc
/branches/bleeding_edge/src/x64/codegen-x64.h
=======================================
--- /branches/bleeding_edge/src/arm/codegen-arm.cc Wed May 12 02:00:29 2010
+++ /branches/bleeding_edge/src/arm/codegen-arm.cc Wed May 12 02:12:23 2010
@@ -2791,60 +2791,13 @@
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) {
- LoadFromGlobalSlotCheckExtensions(slot, typeof_state, &slow);
- frame_->SpillAll();
- done.Jump();
-
- } else if (slot->var()->mode() == Variable::DYNAMIC_LOCAL) {
- frame_->SpillAll();
- 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,
- r1,
- r2,
- &slow));
- if (potential_slot->var()->mode() == Variable::CONST) {
- __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
- __ cmp(r0, ip);
- __ LoadRoot(r0, Heap::kUndefinedValueRootIndex, eq);
- }
- done.Jump();
- } 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.
- __ ldr(r0,
-
ContextSlotOperandCheckExtensions(obj_proxy->var()->slot(),
- r1,
- r2,
- &slow));
- frame_->EmitPush(r0);
- __ mov(r1, Operand(key_literal->handle()));
- frame_->EmitPush(r1);
- EmitKeyedLoad();
- done.Jump();
- }
- }
- }
- }
+ // 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,
+ &slow,
+ &done);
slow.Bind();
VirtualFrame::SpilledScope spilled_scope(frame_);
@@ -3057,6 +3010,67 @@
// Drop the global object. The result is in r0.
frame_->Drop();
}
+
+
+void CodeGenerator::EmitDynamicLoadFromSlotFastCase(Slot* slot,
+ TypeofState
typeof_state,
+ 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) {
+ LoadFromGlobalSlotCheckExtensions(slot, typeof_state, slow);
+ frame_->SpillAll();
+ done->Jump();
+
+ } else if (slot->var()->mode() == Variable::DYNAMIC_LOCAL) {
+ frame_->SpillAll();
+ 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,
+ r1,
+ r2,
+ slow));
+ if (potential_slot->var()->mode() == Variable::CONST) {
+ __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
+ __ cmp(r0, ip);
+ __ LoadRoot(r0, Heap::kUndefinedValueRootIndex, eq);
+ }
+ done->Jump();
+ } 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.
+ __ ldr(r0,
+
ContextSlotOperandCheckExtensions(obj_proxy->var()->slot(),
+ r1,
+ r2,
+ slow));
+ frame_->EmitPush(r0);
+ __ mov(r1, Operand(key_literal->handle()));
+ frame_->EmitPush(r1);
+ EmitKeyedLoad();
+ done->Jump();
+ }
+ }
+ }
+ }
+}
void CodeGenerator::VisitSlot(Slot* node) {
@@ -3756,67 +3770,15 @@
// JumpTargets do not yet support merging frames so the frame must be
// spilled when jumping to these targets.
- 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 (var->mode() == Variable::DYNAMIC_GLOBAL) {
- LoadFromGlobalSlotCheckExtensions(var->slot(), NOT_INSIDE_TYPEOF,
&slow);
- frame_->EmitPush(r0);
- LoadGlobalReceiver(r1);
- 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.
- __ ldr(r0,
- ContextSlotOperandCheckExtensions(potential_slot,
- r1,
- r2,
- &slow));
- if (potential_slot->var()->mode() == Variable::CONST) {
- __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
- __ cmp(r0, ip);
- __ LoadRoot(r0, Heap::kUndefinedValueRootIndex, eq);
- }
- frame_->EmitPush(r0);
- LoadGlobalReceiver(r1);
- 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.
- __ ldr(r0,
-
ContextSlotOperandCheckExtensions(obj_proxy->var()->slot(),
- r1,
- r2,
- &slow));
- frame_->EmitPush(r0);
- __ mov(r1, Operand(key_literal->handle()));
- frame_->EmitPush(r1);
- EmitKeyedLoad();
- frame_->EmitPush(r0);
- LoadGlobalReceiver(r1);
- done.Jump();
- }
- }
- }
- }
+ JumpTarget slow, done;
+
+ // 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,
+ &slow,
+ &done);
slow.Bind();
// Load the function
@@ -3830,7 +3792,18 @@
frame_->EmitPush(r0); // function
frame_->EmitPush(r1); // receiver
- 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();
+ frame_->EmitPush(r0); // function
+ LoadGlobalReceiver(r1); // receiver
+ call.Bind();
+ }
+
// Call the function. At this point, everything is spilled but the
// function and receiver are in r0 and r1.
CallWithArguments(args, NO_CALL_FUNCTION_FLAGS, node->position());
=======================================
--- /branches/bleeding_edge/src/arm/codegen-arm.h Mon May 10 06:23:42 2010
+++ /branches/bleeding_edge/src/arm/codegen-arm.h Wed May 12 02:12:23 2010
@@ -314,6 +314,7 @@
// Read a value from a slot and leave it on top of the expression stack.
void LoadFromSlot(Slot* slot, TypeofState typeof_state);
void LoadFromSlotCheckForArguments(Slot* slot, TypeofState state);
+
// Store the value on top of the stack to a slot.
void StoreToSlot(Slot* slot, InitState init_state);
@@ -343,6 +344,15 @@
TypeofState typeof_state,
JumpTarget* slow);
+ // Support for loading from local/global variables and arguments
+ // whose location is known unless they are shadowed by
+ // eval-introduced bindings. Generates no code for unsupported slot
+ // types and therefore expects to fall through to the slow jump target.
+ void EmitDynamicLoadFromSlotFastCase(Slot* slot,
+ TypeofState typeof_state,
+ JumpTarget* slow,
+ JumpTarget* done);
+
// Special code for typeof expressions: Unfortunately, we must
// be careful when loading the expression in 'typeof'
// expressions. We are not allowed to throw reference errors for
=======================================
--- /branches/bleeding_edge/src/ia32/codegen-ia32.cc Tue May 11 05:38:30
2010
+++ /branches/bleeding_edge/src/ia32/codegen-ia32.cc Wed May 12 02:12:23
2010
@@ -4723,62 +4723,14 @@
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());
- __ mov(result.reg(),
- ContextSlotOperandCheckExtensions(potential_slot,
- result,
- &slow));
- if (potential_slot->var()->mode() == Variable::CONST) {
- __ cmp(result.reg(), Factory::the_hole_value());
- done.Branch(not_equal, &result);
- __ mov(result.reg(), Factory::undefined_value());
- }
- 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());
- __ mov(arguments.reg(),
-
ContextSlotOperandCheckExtensions(obj_proxy->var()->slot(),
- arguments,
- &slow));
- frame_->Push(&arguments);
- frame_->Push(key_literal->handle());
- result = EmitKeyedLoad();
- done.Jump(&result);
- }
- }
- }
- }
+ // 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,
+ &result,
+ &slow,
+ &done);
slow.Bind();
// A runtime call is inevitable. We eagerly sync frame elements
@@ -4945,6 +4897,68 @@
__ nop();
return answer;
}
+
+
+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());
+ __ mov(result->reg(),
+ ContextSlotOperandCheckExtensions(potential_slot, *result,
slow));
+ if (potential_slot->var()->mode() == Variable::CONST) {
+ __ cmp(result->reg(), Factory::the_hole_value());
+ done->Branch(not_equal, result);
+ __ mov(result->reg(), Factory::undefined_value());
+ }
+ done->Jump(result);
+ } 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());
+ __ mov(arguments.reg(),
+
ContextSlotOperandCheckExtensions(obj_proxy->var()->slot(),
+ arguments,
+ slow));
+ frame_->Push(&arguments);
+ frame_->Push(key_literal->handle());
+ *result = EmitKeyedLoad();
+ done->Jump(result);
+ }
+ }
+ }
+ }
+}
void CodeGenerator::StoreToSlot(Slot* slot, InitState init_state) {
@@ -5792,75 +5806,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.
- if (var->mode() == Variable::DYNAMIC_GLOBAL) {
- Result 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.
- Result function = allocator()->Allocate();
- ASSERT(function.is_valid());
- __ mov(function.reg(),
- ContextSlotOperandCheckExtensions(potential_slot,
- function,
- &slow));
- JumpTarget push_function_and_receiver;
- if (potential_slot->var()->mode() == Variable::CONST) {
- __ cmp(function.reg(), Factory::the_hole_value());
- push_function_and_receiver.Branch(not_equal, &function);
- __ mov(function.reg(), Factory::undefined_value());
- }
- 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());
- __ mov(arguments.reg(),
-
ContextSlotOperandCheckExtensions(obj_proxy->var()->slot(),
- arguments,
- &slow));
- frame_->Push(&arguments);
- frame_->Push(key_literal->handle());
- Result value = EmitKeyedLoad();
- frame_->Push(&value);
- LoadGlobalReceiver();
- done.Jump();
- }
- }
- }
- }
+ JumpTarget slow, done;
+ Result function;
+
+ // 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();
// Enter the runtime system to load the function from the context.
@@ -5882,7 +5838,18 @@
ASSERT(!allocator()->is_used(edx));
frame_->EmitPush(edx);
- 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());
=======================================
--- /branches/bleeding_edge/src/ia32/codegen-ia32.h Tue May 11 05:38:30 2010
+++ /branches/bleeding_edge/src/ia32/codegen-ia32.h Wed May 12 02:12:23 2010
@@ -465,6 +465,16 @@
TypeofState typeof_state,
JumpTarget* slow);
+ // Support for loading from local/global variables and arguments
+ // whose location is known unless they are shadowed by
+ // eval-introduced bindings. Generates no code for unsupported slot
+ // types and therefore expects to fall through to the slow jump target.
+ void EmitDynamicLoadFromSlotFastCase(Slot* slot,
+ TypeofState typeof_state,
+ Result* result,
+ JumpTarget* slow,
+ JumpTarget* done);
+
// Store the value on top of the expression stack into a slot, leaving
the
// value in place.
void StoreToSlot(Slot* slot, InitState init_state);
=======================================
--- /branches/bleeding_edge/src/x64/codegen-x64.cc Tue May 11 01:32:13 2010
+++ /branches/bleeding_edge/src/x64/codegen-x64.cc Wed May 12 02:12:23 2010
@@ -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,63 +5318,14 @@
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);
-
- } 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);
- }
- }
- }
- }
+ // 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);
slow.Bind();
// A runtime call is inevitable. We eagerly sync frame elements
@@ -5687,6 +5589,71 @@
frame_->Drop();
return answer;
}
+
+
+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() {
=======================================
--- /branches/bleeding_edge/src/x64/codegen-x64.h Mon May 10 04:38:58 2010
+++ /branches/bleeding_edge/src/x64/codegen-x64.h Wed May 12 02:12:23 2010
@@ -435,6 +435,16 @@
TypeofState typeof_state,
JumpTarget* slow);
+ // Support for loading from local/global variables and arguments
+ // whose location is known unless they are shadowed by
+ // eval-introduced bindings. Generates no code for unsupported slot
+ // types and therefore expects to fall through to the slow jump target.
+ void EmitDynamicLoadFromSlotFastCase(Slot* slot,
+ TypeofState typeof_state,
+ Result* result,
+ JumpTarget* slow,
+ JumpTarget* done);
+
// Store the value on top of the expression stack into a slot, leaving
the
// value in place.
void StoreToSlot(Slot* slot, InitState init_state);
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev