Commit 08c9629f authored by keuchel@chromium.org's avatar keuchel@chromium.org

Static resolution of outer variables in eval code.

So far free variables references in eval code are not statically
resolved. For example in
    function foo() { var x = 1; eval("y = x"); }
the variable x will get mode DYNAMIC and y will get mode DYNAMIC_GLOBAL,
i.e. free variable references trigger dynamic lookups with a fast case
handling for global variables.

The CL introduces static resolution of free variables references in eval
code. If possible variable references are resolved to bindings belonging to
outer scopes of the eval call site.

This is achieved by deserializing the outer scope chain using
Scope::DeserializeScopeChain prior to parsing the eval code similar to lazy
parsing of functions. The existing code for variable resolution is used,
however resolution starts at the first outer unresolved scope instead of
always starting at the root of the scope tree.

This is a prerequisite for statically checking validity of assignments in
the extended code as specified by the current ES.next draft which will be
introduced by a subsequent CL. More specifically section 11.13 of revision 4
of the ES.next draft reads:
* It is a Syntax Error if the AssignmentExpression is contained in extended
  code and the LeftHandSideExpression is an Identifier that does not
  statically resolve to a declarative environment record binding or if the
  resolved binding is an immutable binding.

TEST=existing tests in mjsunit

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@9999 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 4c41d327
...@@ -56,6 +56,7 @@ CompilationInfo::CompilationInfo(Handle<Script> script) ...@@ -56,6 +56,7 @@ CompilationInfo::CompilationInfo(Handle<Script> script)
flags_(0), flags_(0),
function_(NULL), function_(NULL),
scope_(NULL), scope_(NULL),
global_scope_(NULL),
script_(script), script_(script),
extension_(NULL), extension_(NULL),
pre_parse_data_(NULL), pre_parse_data_(NULL),
...@@ -69,6 +70,7 @@ CompilationInfo::CompilationInfo(Handle<SharedFunctionInfo> shared_info) ...@@ -69,6 +70,7 @@ CompilationInfo::CompilationInfo(Handle<SharedFunctionInfo> shared_info)
flags_(IsLazy::encode(true)), flags_(IsLazy::encode(true)),
function_(NULL), function_(NULL),
scope_(NULL), scope_(NULL),
global_scope_(NULL),
shared_info_(shared_info), shared_info_(shared_info),
script_(Handle<Script>(Script::cast(shared_info->script()))), script_(Handle<Script>(Script::cast(shared_info->script()))),
extension_(NULL), extension_(NULL),
...@@ -83,6 +85,7 @@ CompilationInfo::CompilationInfo(Handle<JSFunction> closure) ...@@ -83,6 +85,7 @@ CompilationInfo::CompilationInfo(Handle<JSFunction> closure)
flags_(IsLazy::encode(true)), flags_(IsLazy::encode(true)),
function_(NULL), function_(NULL),
scope_(NULL), scope_(NULL),
global_scope_(NULL),
closure_(closure), closure_(closure),
shared_info_(Handle<SharedFunctionInfo>(closure->shared())), shared_info_(Handle<SharedFunctionInfo>(closure->shared())),
script_(Handle<Script>(Script::cast(shared_info_->script()))), script_(Handle<Script>(Script::cast(shared_info_->script()))),
......
...@@ -59,6 +59,7 @@ class CompilationInfo BASE_EMBEDDED { ...@@ -59,6 +59,7 @@ class CompilationInfo BASE_EMBEDDED {
bool is_in_loop() const { return IsInLoop::decode(flags_); } bool is_in_loop() const { return IsInLoop::decode(flags_); }
FunctionLiteral* function() const { return function_; } FunctionLiteral* function() const { return function_; }
Scope* scope() const { return scope_; } Scope* scope() const { return scope_; }
Scope* global_scope() const { return global_scope_; }
Handle<Code> code() const { return code_; } Handle<Code> code() const { return code_; }
Handle<JSFunction> closure() const { return closure_; } Handle<JSFunction> closure() const { return closure_; }
Handle<SharedFunctionInfo> shared_info() const { return shared_info_; } Handle<SharedFunctionInfo> shared_info() const { return shared_info_; }
...@@ -99,6 +100,10 @@ class CompilationInfo BASE_EMBEDDED { ...@@ -99,6 +100,10 @@ class CompilationInfo BASE_EMBEDDED {
ASSERT(scope_ == NULL); ASSERT(scope_ == NULL);
scope_ = scope; scope_ = scope;
} }
void SetGlobalScope(Scope* global_scope) {
ASSERT(global_scope_ == NULL);
global_scope_ = global_scope;
}
void SetCode(Handle<Code> code) { code_ = code; } void SetCode(Handle<Code> code) { code_ = code; }
void SetExtension(v8::Extension* extension) { void SetExtension(v8::Extension* extension) {
ASSERT(!is_lazy()); ASSERT(!is_lazy());
...@@ -228,6 +233,8 @@ class CompilationInfo BASE_EMBEDDED { ...@@ -228,6 +233,8 @@ class CompilationInfo BASE_EMBEDDED {
// The scope of the function literal as a convenience. Set to indicate // The scope of the function literal as a convenience. Set to indicate
// that scopes have been analyzed. // that scopes have been analyzed.
Scope* scope_; Scope* scope_;
// The global scope provided as a convenience.
Scope* global_scope_;
// The compiled code. // The compiled code.
Handle<Code> code_; Handle<Code> code_;
......
...@@ -240,62 +240,6 @@ Handle<Object> Context::Lookup(Handle<String> name, ...@@ -240,62 +240,6 @@ Handle<Object> Context::Lookup(Handle<String> name,
} }
bool Context::GlobalIfNotShadowedByEval(Handle<String> name) {
Context* context = this;
// Check that there is no local with the given name in contexts
// before the global context and check that there are no context
// extension objects (conservative check for with statements).
while (!context->IsGlobalContext()) {
// Check if the context is a catch or with context, or has introduced
// bindings by calling non-strict eval.
if (context->has_extension()) return false;
// Not a with context so it must be a function context.
ASSERT(context->IsFunctionContext());
// Check non-parameter locals.
Handle<ScopeInfo> scope_info(context->closure()->shared()->scope_info());
VariableMode mode;
InitializationFlag init_flag;
int index = scope_info->ContextSlotIndex(*name, &mode, &init_flag);
ASSERT(index < 0 || index >= MIN_CONTEXT_SLOTS);
if (index >= 0) return false;
// Check parameter locals.
int param_index = scope_info->ParameterIndex(*name);
if (param_index >= 0) return false;
// Check context only holding the function name variable.
index = scope_info->FunctionContextSlotIndex(*name, &mode);
if (index >= 0) return false;
context = context->previous();
}
// No local or potential with statement found so the variable is
// global unless it is shadowed by an eval-introduced variable.
return true;
}
void Context::ComputeEvalScopeInfo(bool* outer_scope_calls_non_strict_eval) {
// Skip up the context chain checking all the function contexts to see
// whether they call eval.
Context* context = this;
while (!context->IsGlobalContext()) {
if (context->IsFunctionContext()) {
if (context->closure()->shared()->scope_info()->CallsNonStrictEval()) {
// No need to go further since the answers will not change from
// here.
*outer_scope_calls_non_strict_eval = true;
return;
}
}
context = context->previous();
}
}
void Context::AddOptimizedFunction(JSFunction* function) { void Context::AddOptimizedFunction(JSFunction* function) {
ASSERT(IsGlobalContext()); ASSERT(IsGlobalContext());
#ifdef DEBUG #ifdef DEBUG
......
...@@ -398,19 +398,6 @@ class Context: public FixedArray { ...@@ -398,19 +398,6 @@ class Context: public FixedArray {
PropertyAttributes* attributes, PropertyAttributes* attributes,
BindingFlags* binding_flags); BindingFlags* binding_flags);
// Determine if a local variable with the given name exists in a
// context. Do not consider context extension objects. This is
// used for compiling code using eval. If the context surrounding
// the eval call does not have a local variable with this name and
// does not contain a with statement the property is global unless
// it is shadowed by a property in an extension object introduced by
// eval.
bool GlobalIfNotShadowedByEval(Handle<String> name);
// Determine if any function scope in the context call eval and if
// any of those calls are in non-strict mode.
void ComputeEvalScopeInfo(bool* outer_scope_calls_non_strict_eval);
// Code generation support. // Code generation support.
static int SlotOffset(int index) { static int SlotOffset(int index) {
return kHeaderSize + index * kPointerSize - kHeapObjectTag; return kHeaderSize + index * kPointerSize - kHeapObjectTag;
......
...@@ -607,12 +607,11 @@ Parser::Parser(Handle<Script> script, ...@@ -607,12 +607,11 @@ Parser::Parser(Handle<Script> script,
} }
FunctionLiteral* Parser::ParseProgram(Handle<String> source, FunctionLiteral* Parser::ParseProgram(CompilationInfo* info) {
bool in_global_context,
StrictModeFlag strict_mode) {
ZoneScope zone_scope(isolate(), DONT_DELETE_ON_EXIT); ZoneScope zone_scope(isolate(), DONT_DELETE_ON_EXIT);
HistogramTimerScope timer(isolate()->counters()->parse()); HistogramTimerScope timer(isolate()->counters()->parse());
Handle<String> source(String::cast(script_->source()));
isolate()->counters()->total_parse_size()->Increment(source->length()); isolate()->counters()->total_parse_size()->Increment(source->length());
fni_ = new(zone()) FuncNameInferrer(isolate()); fni_ = new(zone()) FuncNameInferrer(isolate());
...@@ -625,18 +624,17 @@ FunctionLiteral* Parser::ParseProgram(Handle<String> source, ...@@ -625,18 +624,17 @@ FunctionLiteral* Parser::ParseProgram(Handle<String> source,
ExternalTwoByteStringUC16CharacterStream stream( ExternalTwoByteStringUC16CharacterStream stream(
Handle<ExternalTwoByteString>::cast(source), 0, source->length()); Handle<ExternalTwoByteString>::cast(source), 0, source->length());
scanner_.Initialize(&stream); scanner_.Initialize(&stream);
return DoParseProgram(source, in_global_context, strict_mode, &zone_scope); return DoParseProgram(info, source, &zone_scope);
} else { } else {
GenericStringUC16CharacterStream stream(source, 0, source->length()); GenericStringUC16CharacterStream stream(source, 0, source->length());
scanner_.Initialize(&stream); scanner_.Initialize(&stream);
return DoParseProgram(source, in_global_context, strict_mode, &zone_scope); return DoParseProgram(info, source, &zone_scope);
} }
} }
FunctionLiteral* Parser::DoParseProgram(Handle<String> source, FunctionLiteral* Parser::DoParseProgram(CompilationInfo* info,
bool in_global_context, Handle<String> source,
StrictModeFlag strict_mode,
ZoneScope* zone_scope) { ZoneScope* zone_scope) {
ASSERT(top_scope_ == NULL); ASSERT(top_scope_ == NULL);
ASSERT(target_stack_ == NULL); ASSERT(target_stack_ == NULL);
...@@ -646,16 +644,19 @@ FunctionLiteral* Parser::DoParseProgram(Handle<String> source, ...@@ -646,16 +644,19 @@ FunctionLiteral* Parser::DoParseProgram(Handle<String> source,
mode_ = FLAG_lazy ? PARSE_LAZILY : PARSE_EAGERLY; mode_ = FLAG_lazy ? PARSE_LAZILY : PARSE_EAGERLY;
if (allow_natives_syntax_ || extension_ != NULL) mode_ = PARSE_EAGERLY; if (allow_natives_syntax_ || extension_ != NULL) mode_ = PARSE_EAGERLY;
ScopeType type = in_global_context ? GLOBAL_SCOPE : EVAL_SCOPE;
Handle<String> no_name = isolate()->factory()->empty_symbol(); Handle<String> no_name = isolate()->factory()->empty_symbol();
FunctionLiteral* result = NULL; FunctionLiteral* result = NULL;
{ Scope* scope = NewScope(top_scope_, type); { Scope* scope = NewScope(top_scope_, GLOBAL_SCOPE);
info->SetGlobalScope(scope);
if (!info->is_global()) {
scope = Scope::DeserializeScopeChain(*info->calling_context(), scope);
scope = NewScope(scope, EVAL_SCOPE);
}
scope->set_start_position(0); scope->set_start_position(0);
scope->set_end_position(source->length()); scope->set_end_position(source->length());
FunctionState function_state(this, scope, isolate()); FunctionState function_state(this, scope, isolate());
ASSERT(top_scope_->strict_mode_flag() == kNonStrictMode); top_scope_->SetStrictModeFlag(info->strict_mode_flag());
top_scope_->SetStrictModeFlag(strict_mode);
ZoneList<Statement*>* body = new(zone()) ZoneList<Statement*>(16); ZoneList<Statement*>* body = new(zone()) ZoneList<Statement*>(16);
bool ok = true; bool ok = true;
int beg_loc = scanner().location().beg_pos; int beg_loc = scanner().location().beg_pos;
...@@ -742,8 +743,9 @@ FunctionLiteral* Parser::ParseLazy(CompilationInfo* info, ...@@ -742,8 +743,9 @@ FunctionLiteral* Parser::ParseLazy(CompilationInfo* info,
{ {
// Parse the function literal. // Parse the function literal.
Scope* scope = NewScope(top_scope_, GLOBAL_SCOPE); Scope* scope = NewScope(top_scope_, GLOBAL_SCOPE);
info->SetGlobalScope(scope);
if (!info->closure().is_null()) { if (!info->closure().is_null()) {
scope = Scope::DeserializeScopeChain(info, scope); scope = Scope::DeserializeScopeChain(info->closure()->context(), scope);
} }
FunctionState function_state(this, scope, isolate()); FunctionState function_state(this, scope, isolate());
ASSERT(scope->strict_mode_flag() == kNonStrictMode || ASSERT(scope->strict_mode_flag() == kNonStrictMode ||
...@@ -1370,6 +1372,8 @@ VariableProxy* Parser::Declare(Handle<String> name, ...@@ -1370,6 +1372,8 @@ VariableProxy* Parser::Declare(Handle<String> name,
// enclosing scope. // enclosing scope.
Scope* declaration_scope = (mode == LET || mode == CONST_HARMONY) Scope* declaration_scope = (mode == LET || mode == CONST_HARMONY)
? top_scope_ : top_scope_->DeclarationScope(); ? top_scope_ : top_scope_->DeclarationScope();
InitializationFlag init_flag = (fun != NULL || mode == VAR)
? kCreatedInitialized : kNeedsInitialization;
// If a function scope exists, then we can statically declare this // If a function scope exists, then we can statically declare this
// variable and also set its mode. In any case, a Declaration node // variable and also set its mode. In any case, a Declaration node
...@@ -1388,8 +1392,6 @@ VariableProxy* Parser::Declare(Handle<String> name, ...@@ -1388,8 +1392,6 @@ VariableProxy* Parser::Declare(Handle<String> name,
var = declaration_scope->LocalLookup(name); var = declaration_scope->LocalLookup(name);
if (var == NULL) { if (var == NULL) {
// Declare the name. // Declare the name.
InitializationFlag init_flag = (fun != NULL || mode == VAR)
? kCreatedInitialized : kNeedsInitialization;
var = declaration_scope->DeclareLocal(name, mode, init_flag); var = declaration_scope->DeclareLocal(name, mode, init_flag);
} else { } else {
// The name was declared in this scope before; check for conflicting // The name was declared in this scope before; check for conflicting
...@@ -1452,17 +1454,31 @@ VariableProxy* Parser::Declare(Handle<String> name, ...@@ -1452,17 +1454,31 @@ VariableProxy* Parser::Declare(Handle<String> name,
declaration_scope->AddDeclaration( declaration_scope->AddDeclaration(
new(zone()) Declaration(proxy, mode, fun, top_scope_)); new(zone()) Declaration(proxy, mode, fun, top_scope_));
// For global const variables we bind the proxy to a variable.
if ((mode == CONST || mode == CONST_HARMONY) && if ((mode == CONST || mode == CONST_HARMONY) &&
declaration_scope->is_global_scope()) { declaration_scope->is_global_scope()) {
// For global const variables we bind the proxy to a variable.
ASSERT(resolve); // should be set by all callers ASSERT(resolve); // should be set by all callers
Variable::Kind kind = Variable::NORMAL; Variable::Kind kind = Variable::NORMAL;
var = new(zone()) Variable(declaration_scope, var = new(zone()) Variable(declaration_scope,
name, name,
CONST, mode,
true, true,
kind, kind,
kNeedsInitialization); kNeedsInitialization);
} else if (declaration_scope->is_eval_scope() &&
!declaration_scope->is_strict_mode()) {
// For variable declarations in a non-strict eval scope the proxy is bound
// to a lookup variable to force a dynamic declaration using the
// DeclareContextSlot runtime function.
Variable::Kind kind = Variable::NORMAL;
var = new(zone()) Variable(declaration_scope,
name,
mode,
true,
kind,
init_flag);
var->AllocateTo(Variable::LOOKUP, -1);
resolve = true;
} }
// If requested and we have a local variable, bind the proxy to the variable // If requested and we have a local variable, bind the proxy to the variable
...@@ -1909,22 +1925,30 @@ Block* Parser::ParseVariableDeclarations( ...@@ -1909,22 +1925,30 @@ Block* Parser::ParseVariableDeclarations(
} }
block->AddStatement(new(zone()) ExpressionStatement(initialize)); block->AddStatement(new(zone()) ExpressionStatement(initialize));
} else if (needs_init) {
// Constant initializations always assign to the declared constant which
// is always at the function scope level. This is only relevant for
// dynamically looked-up variables and constants (the start context for
// constant lookups is always the function context, while it is the top
// context for var declared variables). Sigh...
// For 'let' and 'const' declared variables in harmony mode the
// initialization also always assigns to the declared variable.
ASSERT(proxy != NULL);
ASSERT(proxy->var() != NULL);
ASSERT(value != NULL);
Assignment* assignment =
new(zone()) Assignment(isolate(), init_op, proxy, value, position);
block->AddStatement(new(zone()) ExpressionStatement(assignment));
value = NULL;
} }
// Add an assignment node to the initialization statement block if we still // Add an assignment node to the initialization statement block if we still
// have a pending initialization value. We must distinguish between // have a pending initialization value.
// different kinds of declarations: 'var' initializations are simply
// assignments (with all the consequences if they are inside a 'with'
// statement - they may change a 'with' object property). Constant
// initializations always assign to the declared constant which is
// always at the function scope level. This is only relevant for
// dynamically looked-up variables and constants (the start context
// for constant lookups is always the function context, while it is
// the top context for var declared variables). Sigh...
// For 'let' and 'const' declared variables in harmony mode the
// initialization is in the same scope as the declaration. Thus dynamic
// lookups are unnecessary even if the block scope is inside a with.
if (value != NULL) { if (value != NULL) {
ASSERT(mode == VAR);
// 'var' initializations are simply assignments (with all the consequences
// if they are inside a 'with' statement - they may change a 'with' object
// property).
VariableProxy* proxy = initialization_scope->NewUnresolved(name); VariableProxy* proxy = initialization_scope->NewUnresolved(name);
Assignment* assignment = Assignment* assignment =
new(zone()) Assignment(isolate(), init_op, proxy, value, position); new(zone()) Assignment(isolate(), init_op, proxy, value, position);
...@@ -5405,6 +5429,7 @@ bool ParserApi::Parse(CompilationInfo* info) { ...@@ -5405,6 +5429,7 @@ bool ParserApi::Parse(CompilationInfo* info) {
Handle<Script> script = info->script(); Handle<Script> script = info->script();
bool harmony_scoping = !info->is_native() && FLAG_harmony_scoping; bool harmony_scoping = !info->is_native() && FLAG_harmony_scoping;
if (info->is_lazy()) { if (info->is_lazy()) {
ASSERT(!info->is_eval());
bool allow_natives_syntax = bool allow_natives_syntax =
FLAG_allow_natives_syntax || FLAG_allow_natives_syntax ||
info->is_native(); info->is_native();
...@@ -5433,10 +5458,7 @@ bool ParserApi::Parse(CompilationInfo* info) { ...@@ -5433,10 +5458,7 @@ bool ParserApi::Parse(CompilationInfo* info) {
DeleteArray(args.start()); DeleteArray(args.start());
ASSERT(info->isolate()->has_pending_exception()); ASSERT(info->isolate()->has_pending_exception());
} else { } else {
Handle<String> source = Handle<String>(String::cast(script->source())); result = parser.ParseProgram(info);
result = parser.ParseProgram(source,
info->is_global(),
info->strict_mode_flag());
} }
} }
info->SetFunction(result); info->SetFunction(result);
......
...@@ -430,10 +430,7 @@ class Parser { ...@@ -430,10 +430,7 @@ class Parser {
virtual ~Parser() { } virtual ~Parser() { }
// Returns NULL if parsing failed. // Returns NULL if parsing failed.
FunctionLiteral* ParseProgram(Handle<String> source, FunctionLiteral* ParseProgram(CompilationInfo* info);
bool in_global_context,
StrictModeFlag strict_mode);
FunctionLiteral* ParseLazy(CompilationInfo* info); FunctionLiteral* ParseLazy(CompilationInfo* info);
void ReportMessageAt(Scanner::Location loc, void ReportMessageAt(Scanner::Location loc,
...@@ -480,9 +477,8 @@ class Parser { ...@@ -480,9 +477,8 @@ class Parser {
Zone* zone() { return isolate_->zone(); } Zone* zone() { return isolate_->zone(); }
// Called by ParseProgram after setting up the scanner. // Called by ParseProgram after setting up the scanner.
FunctionLiteral* DoParseProgram(Handle<String> source, FunctionLiteral* DoParseProgram(CompilationInfo* info,
bool in_global_context, Handle<String> source,
StrictModeFlag strict_mode,
ZoneScope* zone_scope); ZoneScope* zone_scope);
// Report syntax error // Report syntax error
......
...@@ -12191,15 +12191,12 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluateGlobal) { ...@@ -12191,15 +12191,12 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluateGlobal) {
bool is_global = true; bool is_global = true;
if (additional_context->IsJSObject()) { if (additional_context->IsJSObject()) {
// Create a function context first, than put 'with' context on top of it. // Create a new with context with the additional context information between
Handle<JSFunction> go_between = isolate->factory()->NewFunction( // the context of the debugged function and the eval code to be executed.
isolate->factory()->empty_string(), context = isolate->factory()->NewWithContext(
isolate->factory()->undefined_value()); Handle<JSFunction>(context->closure()),
go_between->set_context(*context); context,
context = Handle<JSObject>::cast(additional_context));
isolate->factory()->NewFunctionContext(
Context::MIN_CONTEXT_SLOTS, go_between);
context->set_extension(JSObject::cast(*additional_context));
is_global = false; is_global = false;
} }
......
This diff is collapsed.
...@@ -93,8 +93,7 @@ class Scope: public ZoneObject { ...@@ -93,8 +93,7 @@ class Scope: public ZoneObject {
// doesn't re-allocate variables repeatedly. // doesn't re-allocate variables repeatedly.
static bool Analyze(CompilationInfo* info); static bool Analyze(CompilationInfo* info);
static Scope* DeserializeScopeChain(CompilationInfo* info, static Scope* DeserializeScopeChain(Context* context, Scope* global_scope);
Scope* innermost_scope);
// The scope name is only used for printing/debugging. // The scope name is only used for printing/debugging.
void SetScopeName(Handle<String> scope_name) { scope_name_ = scope_name; } void SetScopeName(Handle<String> scope_name) { scope_name_ = scope_name; }
...@@ -112,6 +111,12 @@ class Scope: public ZoneObject { ...@@ -112,6 +111,12 @@ class Scope: public ZoneObject {
// Lookup a variable in this scope. Returns the variable or NULL if not found. // Lookup a variable in this scope. Returns the variable or NULL if not found.
Variable* LocalLookup(Handle<String> name); Variable* LocalLookup(Handle<String> name);
// This lookup corresponds to a lookup in the "intermediate" scope sitting
// between this scope and the outer scope. (ECMA-262, 3rd., requires that
// the name of named function literal is kept in an intermediate scope
// in between this scope and the next outer scope.)
Variable* LookupFunctionVar(Handle<String> name);
// Lookup a variable in this scope or outer scopes. // Lookup a variable in this scope or outer scopes.
// Returns the variable or NULL if not found. // Returns the variable or NULL if not found.
Variable* Lookup(Handle<String> name); Variable* Lookup(Handle<String> name);
...@@ -317,7 +322,7 @@ class Scope: public ZoneObject { ...@@ -317,7 +322,7 @@ class Scope: public ZoneObject {
// In the case of code compiled and run using 'eval', the context // In the case of code compiled and run using 'eval', the context
// parameter is the context in which eval was called. In all other // parameter is the context in which eval was called. In all other
// cases the context parameter is an empty handle. // cases the context parameter is an empty handle.
void AllocateVariables(Handle<Context> context); void AllocateVariables(Scope* global_scope);
// Current number of var or const locals. // Current number of var or const locals.
int num_var_or_const() { return num_var_or_const_; } int num_var_or_const() { return num_var_or_const_; }
...@@ -504,13 +509,10 @@ class Scope: public ZoneObject { ...@@ -504,13 +509,10 @@ class Scope: public ZoneObject {
// scope. If the code is executed because of a call to 'eval', the context // scope. If the code is executed because of a call to 'eval', the context
// parameter should be set to the calling context of 'eval'. // parameter should be set to the calling context of 'eval'.
Variable* LookupRecursive(Handle<String> name, Variable* LookupRecursive(Handle<String> name,
Handle<Context> context,
BindingKind* binding_kind); BindingKind* binding_kind);
void ResolveVariable(Scope* global_scope, void ResolveVariable(Scope* global_scope,
Handle<Context> context,
VariableProxy* proxy); VariableProxy* proxy);
void ResolveVariablesRecursively(Scope* global_scope, void ResolveVariablesRecursively(Scope* global_scope);
Handle<Context> context);
// Scope analysis. // Scope analysis.
bool PropagateScopeInfo(bool outer_scope_calls_non_strict_eval); bool PropagateScopeInfo(bool outer_scope_calls_non_strict_eval);
......
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
#include "v8.h" #include "v8.h"
#include "cctest.h" #include "cctest.h"
#include "compiler.h"
#include "execution.h" #include "execution.h"
#include "isolate.h" #include "isolate.h"
#include "parser.h" #include "parser.h"
...@@ -856,9 +857,10 @@ TEST(ScopePositions) { ...@@ -856,9 +857,10 @@ TEST(ScopePositions) {
i::Handle<i::Script> script = FACTORY->NewScript(source); i::Handle<i::Script> script = FACTORY->NewScript(source);
i::Parser parser(script, false, NULL, NULL); i::Parser parser(script, false, NULL, NULL);
parser.SetHarmonyScoping(true); parser.SetHarmonyScoping(true);
i::FunctionLiteral* function = i::CompilationInfo info(script);
parser.ParseProgram(source, true, i::kNonStrictMode); info.MarkAsGlobal();
ASSERT(function != NULL); i::FunctionLiteral* function = parser.ParseProgram(&info);
CHECK(function != NULL);
// Check scope types and positions. // Check scope types and positions.
i::Scope* scope = function->scope(); i::Scope* scope = function->scope();
......
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