flags_(0),
function_(NULL),
scope_(NULL),
+ global_scope_(NULL),
script_(script),
extension_(NULL),
pre_parse_data_(NULL),
flags_(IsLazy::encode(true)),
function_(NULL),
scope_(NULL),
+ global_scope_(NULL),
shared_info_(shared_info),
script_(Handle<Script>(Script::cast(shared_info->script()))),
extension_(NULL),
flags_(IsLazy::encode(true)),
function_(NULL),
scope_(NULL),
+ global_scope_(NULL),
closure_(closure),
shared_info_(Handle<SharedFunctionInfo>(closure->shared())),
script_(Handle<Script>(Script::cast(shared_info_->script()))),
bool is_in_loop() const { return IsInLoop::decode(flags_); }
FunctionLiteral* function() const { return function_; }
Scope* scope() const { return scope_; }
+ Scope* global_scope() const { return global_scope_; }
Handle<Code> code() const { return code_; }
Handle<JSFunction> closure() const { return closure_; }
Handle<SharedFunctionInfo> shared_info() const { return shared_info_; }
ASSERT(scope_ == NULL);
scope_ = scope;
}
+ void SetGlobalScope(Scope* global_scope) {
+ ASSERT(global_scope_ == NULL);
+ global_scope_ = global_scope;
+ }
void SetCode(Handle<Code> code) { code_ = code; }
void SetExtension(v8::Extension* extension) {
ASSERT(!is_lazy());
// The scope of the function literal as a convenience. Set to indicate
// that scopes have been analyzed.
Scope* scope_;
+ // The global scope provided as a convenience.
+ Scope* global_scope_;
// The compiled code.
Handle<Code> code_;
}
-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) {
ASSERT(IsGlobalContext());
#ifdef DEBUG
PropertyAttributes* attributes,
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.
static int SlotOffset(int index) {
return kHeaderSize + index * kPointerSize - kHeapObjectTag;
}
-FunctionLiteral* Parser::ParseProgram(Handle<String> source,
- bool in_global_context,
- StrictModeFlag strict_mode) {
+FunctionLiteral* Parser::ParseProgram(CompilationInfo* info) {
ZoneScope zone_scope(isolate(), DONT_DELETE_ON_EXIT);
HistogramTimerScope timer(isolate()->counters()->parse());
+ Handle<String> source(String::cast(script_->source()));
isolate()->counters()->total_parse_size()->Increment(source->length());
fni_ = new(zone()) FuncNameInferrer(isolate());
ExternalTwoByteStringUC16CharacterStream stream(
Handle<ExternalTwoByteString>::cast(source), 0, source->length());
scanner_.Initialize(&stream);
- return DoParseProgram(source, in_global_context, strict_mode, &zone_scope);
+ return DoParseProgram(info, source, &zone_scope);
} else {
GenericStringUC16CharacterStream stream(source, 0, source->length());
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,
- bool in_global_context,
- StrictModeFlag strict_mode,
+FunctionLiteral* Parser::DoParseProgram(CompilationInfo* info,
+ Handle<String> source,
ZoneScope* zone_scope) {
ASSERT(top_scope_ == NULL);
ASSERT(target_stack_ == NULL);
mode_ = FLAG_lazy ? PARSE_LAZILY : 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();
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_end_position(source->length());
FunctionState function_state(this, scope, isolate());
- ASSERT(top_scope_->strict_mode_flag() == kNonStrictMode);
- top_scope_->SetStrictModeFlag(strict_mode);
+ top_scope_->SetStrictModeFlag(info->strict_mode_flag());
ZoneList<Statement*>* body = new(zone()) ZoneList<Statement*>(16);
bool ok = true;
int beg_loc = scanner().location().beg_pos;
{
// Parse the function literal.
Scope* scope = NewScope(top_scope_, GLOBAL_SCOPE);
+ info->SetGlobalScope(scope);
if (!info->closure().is_null()) {
- scope = Scope::DeserializeScopeChain(info, scope);
+ scope = Scope::DeserializeScopeChain(info->closure()->context(), scope);
}
FunctionState function_state(this, scope, isolate());
ASSERT(scope->strict_mode_flag() == kNonStrictMode ||
// enclosing scope.
Scope* declaration_scope = (mode == LET || mode == CONST_HARMONY)
? 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
// variable and also set its mode. In any case, a Declaration node
var = declaration_scope->LocalLookup(name);
if (var == NULL) {
// Declare the name.
- InitializationFlag init_flag = (fun != NULL || mode == VAR)
- ? kCreatedInitialized : kNeedsInitialization;
var = declaration_scope->DeclareLocal(name, mode, init_flag);
} else {
// The name was declared in this scope before; check for conflicting
declaration_scope->AddDeclaration(
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) &&
declaration_scope->is_global_scope()) {
+ // For global const variables we bind the proxy to a variable.
ASSERT(resolve); // should be set by all callers
Variable::Kind kind = Variable::NORMAL;
var = new(zone()) Variable(declaration_scope,
name,
- CONST,
+ mode,
true,
kind,
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
}
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
- // have a pending initialization value. We must distinguish between
- // 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.
+ // have a pending initialization value.
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);
Assignment* assignment =
new(zone()) Assignment(isolate(), init_op, proxy, value, position);
Handle<Script> script = info->script();
bool harmony_scoping = !info->is_native() && FLAG_harmony_scoping;
if (info->is_lazy()) {
+ ASSERT(!info->is_eval());
bool allow_natives_syntax =
FLAG_allow_natives_syntax ||
info->is_native();
DeleteArray(args.start());
ASSERT(info->isolate()->has_pending_exception());
} else {
- Handle<String> source = Handle<String>(String::cast(script->source()));
- result = parser.ParseProgram(source,
- info->is_global(),
- info->strict_mode_flag());
+ result = parser.ParseProgram(info);
}
}
info->SetFunction(result);
virtual ~Parser() { }
// Returns NULL if parsing failed.
- FunctionLiteral* ParseProgram(Handle<String> source,
- bool in_global_context,
- StrictModeFlag strict_mode);
-
+ FunctionLiteral* ParseProgram(CompilationInfo* info);
FunctionLiteral* ParseLazy(CompilationInfo* info);
void ReportMessageAt(Scanner::Location loc,
Zone* zone() { return isolate_->zone(); }
// Called by ParseProgram after setting up the scanner.
- FunctionLiteral* DoParseProgram(Handle<String> source,
- bool in_global_context,
- StrictModeFlag strict_mode,
+ FunctionLiteral* DoParseProgram(CompilationInfo* info,
+ Handle<String> source,
ZoneScope* zone_scope);
// Report syntax error
bool is_global = true;
if (additional_context->IsJSObject()) {
- // Create a function context first, than put 'with' context on top of it.
- Handle<JSFunction> go_between = isolate->factory()->NewFunction(
- isolate->factory()->empty_string(),
- isolate->factory()->undefined_value());
- go_between->set_context(*context);
- context =
- isolate->factory()->NewFunctionContext(
- Context::MIN_CONTEXT_SLOTS, go_between);
- context->set_extension(JSObject::cast(*additional_context));
+ // Create a new with context with the additional context information between
+ // the context of the debugged function and the eval code to be executed.
+ context = isolate->factory()->NewWithContext(
+ Handle<JSFunction>(context->closure()),
+ context,
+ Handle<JSObject>::cast(additional_context));
is_global = false;
}
// At some point we might want to provide outer scopes to
// eval scopes (by walking the stack and reading the scope info).
// In that case, the ASSERT below needs to be adjusted.
- ASSERT((type == GLOBAL_SCOPE || type == EVAL_SCOPE) == (outer_scope == NULL));
+ ASSERT_EQ(type == GLOBAL_SCOPE, outer_scope == NULL);
ASSERT(!HasIllegalRedeclaration());
}
SetDefaults(type, NULL, scope_info);
if (!scope_info.is_null()) {
num_heap_slots_ = scope_info_->ContextLength();
+ } else if (is_with_scope()) {
+ num_heap_slots_ = Context::MIN_CONTEXT_SLOTS;
}
AddInnerScope(inner_scope);
}
SetDefaults(CATCH_SCOPE, NULL, Handle<ScopeInfo>::null());
AddInnerScope(inner_scope);
++num_var_or_const_;
+ num_heap_slots_ = Context::MIN_CONTEXT_SLOTS;
Variable* variable = variables_.Declare(this,
catch_variable_name,
VAR,
scope_info_ = scope_info;
start_position_ = RelocInfo::kNoPosition;
end_position_ = RelocInfo::kNoPosition;
+ if (!scope_info.is_null()) {
+ scope_calls_eval_ = scope_info->CallsEval();
+ strict_mode_flag_ =
+ scope_info->IsStrictMode() ? kStrictMode : kNonStrictMode;
+ }
}
-Scope* Scope::DeserializeScopeChain(CompilationInfo* info,
- Scope* global_scope) {
+Scope* Scope::DeserializeScopeChain(Context* context, Scope* global_scope) {
// Reconstruct the outer scope chain from a closure's context chain.
- ASSERT(!info->closure().is_null());
- Context* context = info->closure()->context();
Scope* current_scope = NULL;
Scope* innermost_scope = NULL;
bool contains_with = false;
}
global_scope->AddInnerScope(current_scope);
+ global_scope->PropagateScopeInfo(false);
return (innermost_scope == NULL) ? global_scope : innermost_scope;
}
bool Scope::Analyze(CompilationInfo* info) {
ASSERT(info->function() != NULL);
- Scope* top = info->function()->scope();
+ Scope* scope = info->function()->scope();
+ Scope* top = scope;
+
+ // Traverse the scope tree up to the first unresolved scope or the global
+ // scope and start scope resolution and variable allocation from that scope.
+ while (!top->is_global_scope() &&
+ !top->outer_scope()->already_resolved()) {
+ top = top->outer_scope();
+ }
- while (top->outer_scope() != NULL) top = top->outer_scope();
- top->AllocateVariables(info->calling_context());
+ // Allocated the variables.
+ top->AllocateVariables(info->global_scope());
#ifdef DEBUG
if (info->isolate()->bootstrapper()->IsActive()
? FLAG_print_builtin_scopes
: FLAG_print_scopes) {
- info->function()->scope()->Print();
+ scope->Print();
}
#endif
- info->SetScope(info->function()->scope());
+ info->SetScope(scope);
return true; // Can not fail.
}
return result;
}
// If we have a serialized scope info, we might find the variable there.
- //
- // We should never lookup 'arguments' in this scope as it is implicitly
- // present in every scope.
- ASSERT(*name != *isolate_->factory()->arguments_symbol());
// There should be no local slot with the given name.
ASSERT(scope_info_->StackSlotIndex(*name) < 0);
mode = VAR;
init_flag = kCreatedInitialized;
index = scope_info_->ParameterIndex(*name);
- if (index < 0) {
- // Check the function name.
- index = scope_info_->FunctionContextSlotIndex(*name, &mode);
- if (index < 0) return NULL;
- }
+ if (index < 0) return NULL;
}
Variable* var =
}
+Variable* Scope::LookupFunctionVar(Handle<String> name) {
+ if (function_ != NULL && function_->name().is_identical_to(name)) {
+ return function_->var();
+ } else if (!scope_info_.is_null()) {
+ // If we are backed by a scope info, try to lookup the variable there.
+ VariableMode mode;
+ int index = scope_info_->FunctionContextSlotIndex(*name, &mode);
+ if (index < 0) return NULL;
+ Variable* var = DeclareFunctionVar(name, mode);
+ var->AllocateTo(Variable::CONTEXT, index);
+ return var;
+ } else {
+ return NULL;
+ }
+}
+
+
Variable* Scope::Lookup(Handle<String> name) {
for (Scope* scope = this;
scope != NULL;
}
-void Scope::AllocateVariables(Handle<Context> context) {
- ASSERT(outer_scope_ == NULL); // eval or global scopes only
-
+void Scope::AllocateVariables(Scope* global_scope) {
// 1) Propagate scope information.
- // If we are in an eval scope, we may have other outer scopes about
- // which we don't know anything at this point. Thus we must be conservative
- // 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).
-
bool outer_scope_calls_non_strict_eval = false;
- if (!is_global_scope()) {
- context->ComputeEvalScopeInfo(&outer_scope_calls_non_strict_eval);
+ if (outer_scope_ != NULL) {
+ outer_scope_calls_non_strict_eval =
+ outer_scope_->outer_scope_calls_non_strict_eval() |
+ outer_scope_->calls_non_strict_eval();
}
PropagateScopeInfo(outer_scope_calls_non_strict_eval);
// 2) Resolve variables.
- Scope* global_scope = NULL;
- if (is_global_scope()) global_scope = this;
- ResolveVariablesRecursively(global_scope, context);
+ ResolveVariablesRecursively(global_scope);
// 3) Allocate variables.
AllocateVariablesRecursively();
Variable* Scope::LookupRecursive(Handle<String> name,
- Handle<Context> context,
BindingKind* binding_kind) {
ASSERT(binding_kind != NULL);
// Try to find the variable in this scope.
// We did not find a variable locally. Check against the function variable,
// if any. We can do this for all scopes, since the function variable is
// only present - if at all - for function scopes.
- //
- // 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.)
*binding_kind = UNBOUND;
- if (function_ != NULL && function_->name().is_identical_to(name)) {
- var = function_->var();
+ var = LookupFunctionVar(name);
+ if (var != NULL) {
*binding_kind = BOUND;
} else if (outer_scope_ != NULL) {
- var = outer_scope_->LookupRecursive(name, context, binding_kind);
+ var = outer_scope_->LookupRecursive(name, binding_kind);
if (*binding_kind == BOUND && (is_function_scope() || is_with_scope())) {
var->ForceContextAllocation();
}
+ } else {
+ ASSERT(is_global_scope());
}
if (is_with_scope()) {
// object).
*binding_kind = DYNAMIC_LOOKUP;
return NULL;
- } else if (is_eval_scope()) {
- // No local binding was found, no 'with' statements have been encountered
- // and the code is executed as part of a call to 'eval'. The calling context
- // contains scope information that we can use to determine if the variable
- // is global, i.e. the calling context chain does not contain a binding and
- // no 'with' contexts.
- ASSERT(*binding_kind == UNBOUND);
- *binding_kind = context->GlobalIfNotShadowedByEval(name)
- ? UNBOUND_EVAL_SHADOWED : DYNAMIC_LOOKUP;
- return NULL;
} else if (calls_non_strict_eval()) {
// A variable binding may have been found in an outer scope, but the current
// scope makes a non-strict 'eval' call, so the found variable may not be
void Scope::ResolveVariable(Scope* global_scope,
- Handle<Context> context,
VariableProxy* proxy) {
ASSERT(global_scope == NULL || global_scope->is_global_scope());
// Otherwise, try to resolve the variable.
BindingKind binding_kind;
- Variable* var = LookupRecursive(proxy->name(), context, &binding_kind);
+ Variable* var = LookupRecursive(proxy->name(), &binding_kind);
switch (binding_kind) {
case BOUND:
// We found a variable binding.
}
-void Scope::ResolveVariablesRecursively(Scope* global_scope,
- Handle<Context> context) {
+void Scope::ResolveVariablesRecursively(Scope* global_scope) {
ASSERT(global_scope == NULL || global_scope->is_global_scope());
// Resolve unresolved variables for this scope.
for (int i = 0; i < unresolved_.length(); i++) {
- ResolveVariable(global_scope, context, unresolved_[i]);
+ ResolveVariable(global_scope, unresolved_[i]);
}
// Resolve unresolved variables for inner scopes.
for (int i = 0; i < inner_scopes_.length(); i++) {
- inner_scopes_[i]->ResolveVariablesRecursively(global_scope, context);
+ inner_scopes_[i]->ResolveVariablesRecursively(global_scope);
}
}
}
bool calls_non_strict_eval =
- (scope_calls_eval_ && !is_strict_mode()) ||
- outer_scope_calls_non_strict_eval_;
+ this->calls_non_strict_eval() || outer_scope_calls_non_strict_eval_;
for (int i = 0; i < inner_scopes_.length(); i++) {
Scope* inner_scope = inner_scopes_[i];
if (inner_scope->PropagateScopeInfo(calls_non_strict_eval)) {
// doesn't re-allocate variables repeatedly.
static bool Analyze(CompilationInfo* info);
- static Scope* DeserializeScopeChain(CompilationInfo* info,
- Scope* innermost_scope);
+ static Scope* DeserializeScopeChain(Context* context, Scope* global_scope);
// The scope name is only used for printing/debugging.
void SetScopeName(Handle<String> scope_name) { scope_name_ = scope_name; }
// Lookup a variable in this scope. Returns the variable or NULL if not found.
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.
// Returns the variable or NULL if not found.
Variable* Lookup(Handle<String> name);
// In the case of code compiled and run using 'eval', the context
// parameter is the context in which eval was called. In all other
// 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.
int num_var_or_const() { return num_var_or_const_; }
// scope. If the code is executed because of a call to 'eval', the context
// parameter should be set to the calling context of 'eval'.
Variable* LookupRecursive(Handle<String> name,
- Handle<Context> context,
BindingKind* binding_kind);
void ResolveVariable(Scope* global_scope,
- Handle<Context> context,
VariableProxy* proxy);
- void ResolveVariablesRecursively(Scope* global_scope,
- Handle<Context> context);
+ void ResolveVariablesRecursively(Scope* global_scope);
// Scope analysis.
bool PropagateScopeInfo(bool outer_scope_calls_non_strict_eval);
#include "v8.h"
#include "cctest.h"
+#include "compiler.h"
#include "execution.h"
#include "isolate.h"
#include "parser.h"
i::Handle<i::Script> script = FACTORY->NewScript(source);
i::Parser parser(script, false, NULL, NULL);
parser.SetHarmonyScoping(true);
- i::FunctionLiteral* function =
- parser.ParseProgram(source, true, i::kNonStrictMode);
- ASSERT(function != NULL);
+ i::CompilationInfo info(script);
+ info.MarkAsGlobal();
+ i::FunctionLiteral* function = parser.ParseProgram(&info);
+ CHECK(function != NULL);
// Check scope types and positions.
i::Scope* scope = function->scope();