Commit 75cd61a9 authored by ager@chromium.org's avatar ager@chromium.org

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@4645 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent e5a188c2
......@@ -2791,60 +2791,13 @@ void CodeGenerator::LoadFromSlot(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();
}
}
}
}
// 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_);
......@@ -3059,6 +3012,67 @@ void CodeGenerator::LoadFromGlobalSlotCheckExtensions(Slot* slot,
}
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) {
#ifdef DEBUG
int original_height = frame_->height();
......@@ -3756,67 +3770,15 @@ void CodeGenerator::VisitCall(Call* node) {
// JumpTargets do not yet support merging frames so the frame must be
// spilled when jumping to these targets.
JumpTarget slow;
JumpTarget done;
JumpTarget slow, 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();
}
}
}
}
// 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 @@ void CodeGenerator::VisitCall(Call* node) {
frame_->EmitPush(r0); // function
frame_->EmitPush(r1); // 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()) {
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());
......
......@@ -314,6 +314,7 @@ class CodeGenerator: public AstVisitor {
// 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 @@ class CodeGenerator: public AstVisitor {
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
......
......@@ -4723,62 +4723,14 @@ Result CodeGenerator::LoadFromSlot(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) {
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
......@@ -4947,6 +4899,68 @@ Result CodeGenerator::LoadFromGlobalSlotCheckExtensions(
}
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) {
if (slot->type() == Slot::LOOKUP) {
ASSERT(slot->var()->is_dynamic());
......@@ -5792,75 +5806,17 @@ void CodeGenerator::VisitCall(Call* node) {
// }
// ----------------------------------
JumpTarget slow;
JumpTarget done;
JumpTarget slow, done;
Result function;
// 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(),
// 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);
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();
}
}
}
}
&function,
&slow,
&done);
slow.Bind();
// Enter the runtime system to load the function from the context.
......@@ -5882,7 +5838,18 @@ void CodeGenerator::VisitCall(Call* node) {
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());
......
......@@ -465,6 +465,16 @@ class CodeGenerator: public AstVisitor {
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);
......
......@@ -2876,77 +2876,17 @@ void CodeGenerator::VisitCall(Call* node) {
// }
// ----------------------------------
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 @@ void CodeGenerator::VisitCall(Call* node) {
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 @@ void CodeGenerator::LoadFromSlot(Slot* slot, TypeofState typeof_state) {
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
......@@ -5689,6 +5591,71 @@ Result CodeGenerator::LoadFromGlobalSlotCheckExtensions(
}
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());
......
......@@ -435,6 +435,16 @@ class CodeGenerator: public AstVisitor {
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);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment