Commit b4b5e3ca authored by ager@chromium.org's avatar ager@chromium.org

Not sure what happened, but my revert did not get everything out. Fixing the...

Not sure what happened, but my revert did not get everything out.  Fixing the problem instead.  The issue was using tmp instead of context in two places.

TBR=kasperl

Review URL: http://codereview.chromium.org/20459

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@1303 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 19f04d16
......@@ -256,6 +256,11 @@ class CodeGenerator: public AstVisitor {
MemOperand SlotOperand(Slot* slot, Register tmp);
MemOperand ContextSlotOperandCheckExtensions(Slot* slot,
Register tmp,
Register tmp2,
Label* slow);
// Expressions
MemOperand GlobalObject() const {
return ContextOperand(cp, Context::GLOBAL_INDEX);
......@@ -272,6 +277,11 @@ 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 LoadFromGlobalSlotCheckExtensions(Slot* slot,
TypeofState typeof_state,
Register tmp,
Register tmp2,
Label* slow);
// Special code for typeof expressions: Unfortunately, we must
// be careful when loading the expression in 'typeof'
......
......@@ -267,6 +267,9 @@ class CodeGenerator: public AstVisitor {
Operand SlotOperand(Slot* slot, Register tmp);
Operand ContextSlotOperandCheckExtensions(Slot* slot,
Register tmp,
Label* slow);
// Expressions
Operand GlobalObject() const {
......@@ -284,6 +287,10 @@ 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 LoadFromGlobalSlotCheckExtensions(Slot* slot,
TypeofState typeof_state,
Register tmp,
Label* slow);
// Special code for typeof expressions: Unfortunately, we must
// be careful when loading the expression in 'typeof'
......
......@@ -134,10 +134,12 @@ Handle<Object> Context::Lookup(Handle<String> name, ContextLookupFlags flags,
// declared variables that were introduced through declaration nodes)
// must not appear here.
switch (mode) {
case Variable::INTERNAL : // fall through
case Variable::VAR : *attributes = NONE; break;
case Variable::CONST : *attributes = READ_ONLY; break;
case Variable::DYNAMIC : UNREACHABLE(); break;
case Variable::INTERNAL: // fall through
case Variable::VAR: *attributes = NONE; break;
case Variable::CONST: *attributes = READ_ONLY; break;
case Variable::DYNAMIC: UNREACHABLE(); break;
case Variable::DYNAMIC_GLOBAL: UNREACHABLE(); break;
case Variable::DYNAMIC_LOCAL: UNREACHABLE(); break;
case Variable::TEMPORARY: UNREACHABLE(); break;
}
return context;
......
......@@ -139,6 +139,7 @@ Scope::Scope(Scope* outer_scope, Type type)
scope_calls_eval_(false),
outer_scope_calls_eval_(false),
inner_scope_calls_eval_(false),
outer_scope_is_eval_scope_(false),
force_eager_compilation_(false),
num_stack_slots_(0),
num_heap_slots_(0) {
......@@ -312,7 +313,8 @@ void Scope::AllocateVariables() {
// and assume they may invoke eval themselves. Eventually we could capture
// this information in the ScopeInfo and then use it here (by traversing
// the call chain stack, at compile time).
PropagateScopeInfo(is_eval_scope());
bool eval_scope = is_eval_scope();
PropagateScopeInfo(eval_scope, eval_scope);
// 2) Resolve variables.
Scope* global_scope = NULL;
......@@ -442,6 +444,9 @@ void Scope::Print(int n) {
if (scope_calls_eval_) Indent(n1, "// scope calls 'eval'\n");
if (outer_scope_calls_eval_) Indent(n1, "// outer scope calls 'eval'\n");
if (inner_scope_calls_eval_) Indent(n1, "// inner scope calls 'eval'\n");
if (outer_scope_is_eval_scope_) {
Indent(n1, "// outer scope is 'eval' scope\n");
}
if (num_stack_slots_ > 0) { Indent(n1, "// ");
PrintF("%d stack slots\n", num_stack_slots_); }
if (num_heap_slots_ > 0) { Indent(n1, "// ");
......@@ -482,20 +487,18 @@ void Scope::Print(int n) {
#endif // DEBUG
Variable* Scope::NonLocal(Handle<String> name) {
// Space optimization: reuse existing non-local with the same name.
Variable* Scope::NonLocal(Handle<String> name, Variable::Mode mode) {
// Space optimization: reuse existing non-local with the same name
// and mode.
for (int i = 0; i < nonlocals_.length(); i++) {
Variable* var = nonlocals_[i];
if (var->name().is_identical_to(name)) {
ASSERT(var->mode() == Variable::DYNAMIC);
if (var->name().is_identical_to(name) && var->mode() == mode) {
return var;
}
}
// Otherwise create a new new-local and add it to the list.
Variable* var = new Variable(
NULL /* we don't know the scope */,
name, Variable::DYNAMIC, true, false);
// Otherwise create a new non-local and add it to the list.
Variable* var = new Variable(NULL, name, mode, true, false);
nonlocals_.Add(var);
// Allocate it by giving it a dynamic lookup.
......@@ -511,7 +514,9 @@ Variable* Scope::NonLocal(Handle<String> name) {
// because the variable is just a guess (and may be shadowed by another
// variable that is introduced dynamically via an 'eval' call or a 'with'
// statement).
Variable* Scope::LookupRecursive(Handle<String> name, bool inner_lookup) {
Variable* Scope::LookupRecursive(Handle<String> name,
bool inner_lookup,
Variable** invalidated_local) {
// If we find a variable, but the current scope calls 'eval', the found
// variable may not be the correct one (the 'eval' may introduce a
// property with the same name). In that case, remember that the variable
......@@ -542,7 +547,7 @@ Variable* Scope::LookupRecursive(Handle<String> name, bool inner_lookup) {
var = function_;
} else if (outer_scope_ != NULL) {
var = outer_scope_->LookupRecursive(name, true /* inner lookup */);
var = outer_scope_->LookupRecursive(name, true, invalidated_local);
// We may have found a variable in an outer scope. However, if
// the current scope is inside a 'with', the actual variable may
// be a property introduced via the 'with' statement. Then, the
......@@ -563,8 +568,10 @@ Variable* Scope::LookupRecursive(Handle<String> name, bool inner_lookup) {
var->is_accessed_from_inner_scope_ = true;
// If the variable we have found is just a guess, invalidate the result.
if (guess)
if (guess) {
*invalidated_local = var;
var = NULL;
}
return var;
}
......@@ -578,7 +585,8 @@ void Scope::ResolveVariable(Scope* global_scope, VariableProxy* proxy) {
if (proxy->var() != NULL) return;
// Otherwise, try to resolve the variable.
Variable* var = LookupRecursive(proxy->name(), false);
Variable* invalidated_local = NULL;
Variable* var = LookupRecursive(proxy->name(), false, &invalidated_local);
if (proxy->inside_with()) {
// If we are inside a local 'with' statement, all bets are off
......@@ -587,7 +595,7 @@ void Scope::ResolveVariable(Scope* global_scope, VariableProxy* proxy) {
// Note that we must do a lookup anyway, because if we find one,
// we must mark that variable as potentially accessed from this
// inner scope (the property may not be in the 'with' object).
var = NonLocal(proxy->name());
var = NonLocal(proxy->name(), Variable::DYNAMIC);
} else {
// We are not inside a local 'with' statement.
......@@ -601,11 +609,22 @@ void Scope::ResolveVariable(Scope* global_scope, VariableProxy* proxy) {
// or we don't know about the outer scope (because we are
// in an eval scope).
if (!is_global_scope() &&
(is_eval_scope() || outer_scope_calls_eval_ ||
scope_calls_eval_ || scope_inside_with_)) {
// We must look up the variable at runtime, and we don't
// know anything else.
var = NonLocal(proxy->name());
(scope_inside_with_ || outer_scope_is_eval_scope_)) {
// If we are inside a with statement or the code is executed
// using eval, we give up and look up the variable at runtime.
var = NonLocal(proxy->name(), Variable::DYNAMIC);
} else if (!is_global_scope() &&
(scope_calls_eval_ || outer_scope_calls_eval_)) {
// If the code is not executed using eval and there are no
// with scopes, either we have a local or a global variable
// that might be shadowed by an eval-introduced variable.
if (invalidated_local != NULL) {
var = NonLocal(proxy->name(), Variable::DYNAMIC_LOCAL);
var->set_local_if_not_shadowed(invalidated_local);
} else {
var = NonLocal(proxy->name(), Variable::DYNAMIC_GLOBAL);
}
} else {
// We must have a global variable.
......@@ -643,15 +662,21 @@ void Scope::ResolveVariablesRecursively(Scope* global_scope) {
}
bool Scope::PropagateScopeInfo(bool outer_scope_calls_eval) {
bool Scope::PropagateScopeInfo(bool outer_scope_calls_eval,
bool outer_scope_is_eval_scope) {
if (outer_scope_calls_eval) {
outer_scope_calls_eval_ = true;
}
bool b = scope_calls_eval_ || outer_scope_calls_eval_;
if (outer_scope_is_eval_scope) {
outer_scope_is_eval_scope_ = true;
}
bool calls_eval = scope_calls_eval_ || outer_scope_calls_eval_;
bool is_eval = is_eval_scope() || outer_scope_is_eval_scope_;
for (int i = 0; i < inner_scopes_.length(); i++) {
Scope* inner_scope = inner_scopes_[i];
if (inner_scope->PropagateScopeInfo(b)) {
if (inner_scope->PropagateScopeInfo(calls_eval, is_eval)) {
inner_scope_calls_eval_ = true;
}
if (inner_scope->force_eager_compilation_) {
......
......@@ -166,10 +166,13 @@ class Scope: public ZoneObject {
bool is_function_scope() const { return type_ == FUNCTION_SCOPE; }
bool is_global_scope() const { return type_ == GLOBAL_SCOPE; }
// Information about which scopes calls eval.
bool calls_eval() const { return scope_calls_eval_; }
bool outer_scope_calls_eval() const { return outer_scope_calls_eval_; }
// The scope immediately surrounding this scope, or NULL.
Scope* outer_scope() const { return outer_scope_; }
// ---------------------------------------------------------------------------
// Accessors.
......@@ -290,6 +293,7 @@ class Scope: public ZoneObject {
// Computed via PropagateScopeInfo.
bool outer_scope_calls_eval_;
bool inner_scope_calls_eval_;
bool outer_scope_is_eval_scope_;
bool force_eager_compilation_;
// Computed via AllocateVariables; function scopes only.
......@@ -298,15 +302,18 @@ class Scope: public ZoneObject {
// Create a non-local variable with a given name.
// These variables are looked up dynamically at runtime.
Variable* NonLocal(Handle<String> name);
Variable* NonLocal(Handle<String> name, Variable::Mode mode);
// Variable resolution.
Variable* LookupRecursive(Handle<String> name, bool inner_lookup);
Variable* LookupRecursive(Handle<String> name,
bool inner_lookup,
Variable** invalidated_local);
void ResolveVariable(Scope* global_scope, VariableProxy* proxy);
void ResolveVariablesRecursively(Scope* global_scope);
// Scope analysis.
bool PropagateScopeInfo(bool outer_scope_calls_eval);
bool PropagateScopeInfo(bool outer_scope_calls_eval,
bool outer_scope_is_eval_scope);
bool HasTrivialContext() const;
// Predicates.
......
......@@ -110,6 +110,8 @@ const char* Variable::Mode2String(Mode mode) {
case VAR: return "VAR";
case CONST: return "CONST";
case DYNAMIC: return "DYNAMIC";
case DYNAMIC_GLOBAL: return "DYNAMIC_GLOBAL";
case DYNAMIC_LOCAL: return "DYNAMIC_LOCAL";
case INTERNAL: return "INTERNAL";
case TEMPORARY: return "TEMPORARY";
}
......@@ -143,6 +145,7 @@ Variable::Variable(Scope* scope,
mode_(mode),
is_valid_LHS_(is_valid_LHS),
is_this_(is_this),
local_if_not_shadowed_(NULL),
is_accessed_from_inner_scope_(false),
rewrite_(NULL) {
// names must be canonicalized for fast equality checks
......@@ -156,5 +159,4 @@ bool Variable::is_global() const {
return mode_ != TEMPORARY && scope_ != NULL && scope_->is_global_scope();
}
} } // namespace v8::internal
......@@ -113,13 +113,27 @@ class Variable: public ZoneObject {
enum Mode {
// User declared variables:
VAR, // declared via 'var', and 'function' declarations
CONST, // declared via 'const' declarations
// Variables introduced by the compiler:
DYNAMIC, // always require dynamic lookup (we don't know the declaration)
INTERNAL, // like VAR, but not user-visible (may or may not be in a
// context)
TEMPORARY // temporary variables (not user-visible), never in a context
DYNAMIC, // always require dynamic lookup (we don't know
// the declaration)
DYNAMIC_GLOBAL, // requires dynamic lookup, but we know that the
// variable is global unless it has been shadowed
// by an eval-introduced variable
DYNAMIC_LOCAL, // requires dynamic lookup, but we know that the
// variable is local and where it is unless it
// has been shadowed by an eval-introduced
// variable
INTERNAL, // like VAR, but not user-visible (may or may not
// be in a context)
TEMPORARY // temporary variables (not user-visible), never
// in a context
};
// Printing support
......@@ -150,9 +164,24 @@ class Variable: public ZoneObject {
return !is_this() && name().is_identical_to(n);
}
bool is_dynamic() const {
return (mode_ == DYNAMIC ||
mode_ == DYNAMIC_GLOBAL ||
mode_ == DYNAMIC_LOCAL);
}
bool is_global() const;
bool is_this() const { return is_this_; }
Variable* local_if_not_shadowed() const {
ASSERT(mode_ == DYNAMIC_LOCAL && local_if_not_shadowed_ != NULL);
return local_if_not_shadowed_;
}
void set_local_if_not_shadowed(Variable* local) {
local_if_not_shadowed_ = local;
}
Expression* rewrite() const { return rewrite_; }
Slot* slot() const;
......@@ -168,6 +197,8 @@ class Variable: public ZoneObject {
bool is_valid_LHS_;
bool is_this_;
Variable* local_if_not_shadowed_;
// Usage info.
bool is_accessed_from_inner_scope_; // set by variable resolver
UseCount var_uses_; // uses of the variable value
......
// Copyright 2009 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 global loads from eval inside of a with statement.
var x = 27;
function test(obj, source) {
with (obj) {
eval(source);
}
}
// Test shadowing in eval scope.
test({ x: 42 }, "assertEquals(42, x)");
test({ y: 42 }, "assertEquals(27, x)");
// Test shadowing in local scope inside an eval scope.
test({ x: 42 }, "function f() { assertEquals(42, x) }; f();");
test({ y: 42 }, "function f() { assertEquals(27, x) }; f();");
// Test shadowing in local scope inside an eval scope. Deeper nesting
// this time.
test({ x: 42 }, "function f() { function g() { assertEquals(42, x) }; g() }; f();");
test({ y: 42 }, "function f() { function g() { assertEquals(27, x) }; g() }; f();");
// Test shadowing in local scope inside an eval scope with eval calls in the eval scopes.
test({ x: 42 }, "function f() { eval('1'); assertEquals(42, x) }; f();");
test({ y: 42 }, "function f() { eval('1'); assertEquals(27, x) }; f();");
// Test shadowing in local scope inside an eval scope with eval calls
// in the eval scopes. Deeper nesting this time.
test({ x: 42 }, "function f() { function g() { eval('1'); assertEquals(42, x) }; g() }; f();");
test({ y: 42 }, "function f() { function g() { eval('1'); assertEquals(27, x) }; g() }; f();");
// Copyright 2009 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 loads of local properties from eval.
function test(source) {
var x = 27;
eval(source);
}
test("assertEquals(27, x);");
test("(function() { assertEquals(27, x) })();");
// Copyright 2009 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 properties across eval calls.
var x = 1;
// Test loading across an eval call that does not shadow variables.
function testNoShadowing() {
var y = 2;
function f() {
eval('1');
assertEquals(1, x);
assertEquals(2, y);
function g() {
assertEquals(1, x);
assertEquals(2, y);
}
g();
}
f();
}
testNoShadowing();
// Test loading across eval calls that do not shadow variables.
function testNoShadowing2() {
var y = 2;
eval('1');
function f() {
eval('1');
assertEquals(1, x);
assertEquals(2, y);
function g() {
assertEquals(1, x);
assertEquals(2, y);
}
g();
}
f();
}
testNoShadowing2();
// Test loading across an eval call that shadows variables.
function testShadowing() {
var y = 2;
function f() {
eval('var x = 3; var y = 4;');
assertEquals(3, x);
assertEquals(4, y);
function g() {
assertEquals(3, x);
assertEquals(4, y);
}
g();
}
f();
}
testShadowing();
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