| Index: src/ia32/codegen-ia32.cc
|
| ===================================================================
|
| --- src/ia32/codegen-ia32.cc (revision 4644)
|
| +++ src/ia32/codegen-ia32.cc (working copy)
|
| @@ -4723,63 +4723,15 @@
|
| 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);
|
| + // 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);
|
|
|
| - } 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);
|
| - }
|
| - }
|
| - }
|
| - }
|
| -
|
| slow.Bind();
|
| // A runtime call is inevitable. We eagerly sync frame elements
|
| // to memory so that we can push the arguments directly into place
|
| @@ -4947,6 +4899,68 @@
|
| }
|
|
|
|
|
| +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,76 +5806,18 @@
|
| // }
|
| // ----------------------------------
|
|
|
| - 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(),
|
| - NOT_INSIDE_TYPEOF,
|
| - &slow);
|
| - frame_->Push(&function);
|
| - 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);
|
|
|
| - } 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();
|
| - }
|
| - }
|
| - }
|
| - }
|
| -
|
| slow.Bind();
|
| // Enter the runtime system to load the function from the context.
|
| // Sync the frame so we can push the arguments directly into
|
| @@ -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());
|
|
|
|
|