// containing the eval.
if (slot->var()->mode() == Variable::DYNAMIC_GLOBAL) {
LoadFromGlobalSlotCheckExtensions(slot, typeof_state, &slow);
- // If there was no control flow to slow, we can exit early.
- if (!slow.is_linked()) {
- frame_->EmitPush(r0);
- return;
- }
frame_->SpillAll();
-
done.Jump();
} else if (slot->var()->mode() == Variable::DYNAMIC_LOCAL) {
frame_->SpillAll();
Slot* potential_slot = slot->var()->local_if_not_shadowed()->slot();
- // Only generate the fast case for locals that rewrite to slots.
- // This rules out argument loads because eval forces arguments
- // access to be through the arguments object.
+ 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,
__ cmp(r0, ip);
__ LoadRoot(r0, Heap::kUndefinedValueRootIndex, eq);
}
- // There is always control flow to slow from
- // ContextSlotOperandCheckExtensions so we have to jump around
- // it.
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();
+ }
+ }
}
}
// ----------------------------------
// JavaScript examples:
//
- // with (obj) foo(1, 2, 3) // foo is in obj
+ // with (obj) foo(1, 2, 3) // foo may be in obj.
//
// function f() {};
// function g() {
// eval(...);
- // f(); // f could be in extension object
+ // f(); // f could be in extension object.
// }
// ----------------------------------
} else if (var->mode() == Variable::DYNAMIC_LOCAL) {
Slot* potential_slot = var->local_if_not_shadowed()->slot();
- // Only generate the fast case for locals that rewrite to slots.
- // This rules out argument loads because eval forces arguments
- // access to be through the arguments object.
+ 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,
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();
+ }
+ }
}
}
// containing the eval.
if (slot->var()->mode() == Variable::DYNAMIC_GLOBAL) {
result = LoadFromGlobalSlotCheckExtensions(slot, typeof_state, &slow);
- // If there was no control flow to slow, we can exit early.
- if (!slow.is_linked()) return result;
done.Jump(&result);
} else if (slot->var()->mode() == Variable::DYNAMIC_LOCAL) {
Slot* potential_slot = slot->var()->local_if_not_shadowed()->slot();
- // Only generate the fast case for locals that rewrite to slots.
- // This rules out argument loads because eval forces arguments
- // access to be through the arguments object.
+ 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.
done.Branch(not_equal, &result);
__ mov(result.reg(), Factory::undefined_value());
}
- // There is always control flow to slow from
- // ContextSlotOperandCheckExtensions so we have to jump around
- // it.
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);
+ }
+ }
}
}
// ----------------------------------
// JavaScript examples:
//
- // with (obj) foo(1, 2, 3) // foo is in obj
+ // with (obj) foo(1, 2, 3) // foo may be in obj.
//
// function f() {};
// function g() {
// eval(...);
- // f(); // f could be in extension object
+ // f(); // f could be in extension object.
// }
// ----------------------------------
// introducing variables. In those cases, we do not want to
// perform a runtime call for all variables in the scope
// containing the eval.
- Result function;
if (var->mode() == Variable::DYNAMIC_GLOBAL) {
- function = LoadFromGlobalSlotCheckExtensions(var->slot(),
- NOT_INSIDE_TYPEOF,
- &slow);
+ 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();
- // Only generate the fast case for locals that rewrite to slots.
- // This rules out argument loads because eval forces arguments
- // access to be through the arguments object.
+ 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();
+ Result function = allocator()->Allocate();
ASSERT(function.is_valid());
__ mov(function.reg(),
ContextSlotOperandCheckExtensions(potential_slot,
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();
+ }
+ }
}
}
// ----------------------------------
// JavaScript examples:
//
- // with (obj) foo(1, 2, 3) // foo is in obj
+ // with (obj) foo(1, 2, 3) // foo may be in obj.
//
// function f() {};
// function g() {
// eval(...);
- // f(); // f could be in extension object
+ // f(); // f could be in extension object.
// }
// ----------------------------------
} else if (var->mode() == Variable::DYNAMIC_LOCAL) {
Slot* potential_slot = var->local_if_not_shadowed()->slot();
- // Only generate the fast case for locals that rewrite to slots.
- // This rules out argument loads because eval forces arguments
- // access to be through the arguments object.
+ 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.
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();
+ }
+ }
}
}
// containing the eval.
if (slot->var()->mode() == Variable::DYNAMIC_GLOBAL) {
value = LoadFromGlobalSlotCheckExtensions(slot, typeof_state, &slow);
- // If there was no control flow to slow, we can exit early.
- if (!slow.is_linked()) {
- frame_->Push(&value);
- return;
- }
-
done.Jump(&value);
} else if (slot->var()->mode() == Variable::DYNAMIC_LOCAL) {
Slot* potential_slot = slot->var()->local_if_not_shadowed()->slot();
- // Only generate the fast case for locals that rewrite to slots.
- // This rules out argument loads because eval forces arguments
- // access to be through the arguments object.
+ 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.
done.Branch(not_equal, &value);
__ LoadRoot(value.reg(), Heap::kUndefinedValueRootIndex);
}
- // There is always control flow to slow from
- // ContextSlotOperandCheckExtensions so we have to jump around
- // it.
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);
+ }
+ }
}
}
--- /dev/null
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Tests loading of aguments across eval calls.
+
+// Test loading across an eval call that does not shadow variables.
+function testNoShadowing(x, h) {
+ function f() {
+ eval('1');
+ assertEquals(1, x);
+ assertEquals(2, h());
+ function g() {
+ assertEquals(1, x);
+ assertEquals(2, h());
+ }
+ g();
+ }
+ f();
+}
+
+testNoShadowing(1, function() { return 2; });
+
+// Test loading across eval calls that do not shadow variables.
+function testNoShadowing2(x, h) {
+ eval('1');
+ function f() {
+ eval('1');
+ assertEquals(1, x);
+ assertEquals(2, h());
+ function g() {
+ assertEquals(1, x);
+ assertEquals(2, h());
+ }
+ g();
+ }
+ f();
+}
+
+testNoShadowing2(1, function() { return 2; });
+
+// Test loading across an eval call that shadows variables.
+function testShadowing(x, h) {
+ function f() {
+ assertEquals(1, x);
+ assertEquals(2, h());
+ eval('var x = 3; var h = function() { return 4; };');
+ assertEquals(3, x);
+ assertEquals(4, h());
+ function g() {
+ assertEquals(3, x);
+ assertEquals(4, h());
+ }
+ g();
+ }
+ f();
+ assertEquals(1, x);
+ assertEquals(2, h());
+}
+
+testShadowing(1, function() { return 2; });
+
+
function f() {
eval('1');
assertEquals(1, x);
+ try { typeof(asdf); } catch(e) { assertUnreachable(); }
assertEquals(2, y);
assertEquals('global', global_function());
assertEquals('local', local_function());
assertEquals('const_local', local_const_initialized());
function g() {
assertEquals(1, x);
+ try { typeof(asdf); } catch(e) { assertUnreachable(); }
assertEquals(2, y);
assertEquals('global', global_function());
assertEquals('local', local_function());