Index: src/scopes.cc |
diff --git a/src/scopes.cc b/src/scopes.cc |
index 3565e11b58f710e280f1080c0fb479e5e01376f9..58a10ee346401d9ba6bac3c49e24a490f4d81140 100644 |
--- a/src/scopes.cc |
+++ b/src/scopes.cc |
@@ -112,68 +112,74 @@ Variable* VariableMap::Lookup(Handle<String> name) { |
// Dummy constructor |
Scope::Scope(Type type) |
- : outer_scope_(NULL), |
- inner_scopes_(0), |
- type_(type), |
- scope_name_(Factory::empty_symbol()), |
+ : inner_scopes_(0), |
variables_(false), |
temps_(0), |
params_(0), |
- dynamics_(NULL), |
unresolved_(0), |
- decls_(0), |
- receiver_(NULL), |
- function_(NULL), |
- arguments_(NULL), |
- arguments_shadow_(NULL), |
- illegal_redecl_(NULL), |
- scope_inside_with_(false), |
- scope_contains_with_(false), |
- 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) { |
+ decls_(0) { |
+ SetDefaults(type, NULL, NULL); |
+ ASSERT(!resolved()); |
} |
Scope::Scope(Scope* outer_scope, Type type) |
- : outer_scope_(outer_scope), |
- inner_scopes_(4), |
- type_(type), |
- scope_name_(Factory::empty_symbol()), |
+ : inner_scopes_(4), |
+ variables_(), |
temps_(4), |
params_(4), |
- dynamics_(NULL), |
unresolved_(16), |
- decls_(4), |
- receiver_(NULL), |
- function_(NULL), |
- arguments_(NULL), |
- arguments_shadow_(NULL), |
- illegal_redecl_(NULL), |
- scope_inside_with_(false), |
- scope_contains_with_(false), |
- 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) { |
+ decls_(4) { |
+ SetDefaults(type, outer_scope, NULL); |
// 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(!HasIllegalRedeclaration()); |
+ ASSERT(!resolved()); |
} |
+Scope::Scope(Scope* inner_scope, SerializedScopeInfo* scope_info) |
+ : inner_scopes_(4), |
+ variables_(), |
+ temps_(4), |
+ params_(4), |
+ unresolved_(16), |
+ decls_(4) { |
+ ASSERT(scope_info != NULL); |
+ SetDefaults(FUNCTION_SCOPE, inner_scope->outer_scope(), scope_info); |
+ ASSERT(resolved()); |
+ InsertAfterScope(inner_scope); |
+ if (scope_info->HasHeapAllocatedLocals()) { |
+ num_heap_slots_ = scope_info_->NumberOfContextSlots(); |
+ } |
+} |
+ |
+ |
+ |
bool Scope::Analyze(CompilationInfo* info) { |
ASSERT(info->function() != NULL); |
Scope* top = info->function()->scope(); |
+ |
+ // If we have a serialized scope info, reuse it. |
+ if (!info->closure().is_null()) { |
+ SerializedScopeInfo* scope_info = info->closure()->shared()->scope_info(); |
+ if (scope_info != SerializedScopeInfo::Empty()) { |
+ Scope* scope = top; |
+ JSFunction* current = *info->closure(); |
+ do { |
+ current = current->context()->closure(); |
+ SerializedScopeInfo* scope_info = current->shared()->scope_info(); |
+ if (scope_info != SerializedScopeInfo::Empty()) { |
+ scope = new Scope(scope, scope_info); |
+ } else { |
+ ASSERT(current->context()->IsGlobalContext()); |
+ } |
+ } while (!current->context()->IsGlobalContext()); |
+ } |
+ } |
+ |
while (top->outer_scope() != NULL) top = top->outer_scope(); |
top->AllocateVariables(info->calling_context()); |
@@ -191,6 +197,8 @@ bool Scope::Analyze(CompilationInfo* info) { |
void Scope::Initialize(bool inside_with) { |
+ ASSERT(!resolved()); |
+ |
// Add this scope as a new inner scope of the outer scope. |
if (outer_scope_ != NULL) { |
outer_scope_->inner_scopes_.Add(this); |
@@ -210,7 +218,7 @@ void Scope::Initialize(bool inside_with) { |
Variable* var = |
variables_.Declare(this, Factory::this_symbol(), Variable::VAR, |
false, Variable::THIS); |
- var->rewrite_ = new Slot(var, Slot::PARAMETER, -1); |
+ var->set_rewrite(new Slot(var, Slot::PARAMETER, -1)); |
receiver_ = var; |
if (is_function_scope()) { |
@@ -224,7 +232,28 @@ void Scope::Initialize(bool inside_with) { |
Variable* Scope::LocalLookup(Handle<String> name) { |
- return variables_.Lookup(name); |
+ Variable* result = variables_.Lookup(name); |
+ if (result != NULL || !resolved()) { |
+ return result; |
+ } |
+ // If the scope is resolved, we can find a variable in serialized scope info. |
+ |
+ // We should never lookup 'arguments' in this scope |
+ // as it is impllicitly present in any scope. |
+ ASSERT(*name != *Factory::arguments_symbol()); |
+ |
+ // Check context slot lookup. |
+ Variable::Mode mode; |
+ int index = scope_info_->ContextSlotIndex(*name, &mode); |
+ if (index < 0) { |
+ return NULL; |
+ } |
+ |
+ // Check that there is no local slot with the given name. |
+ ASSERT(scope_info_->StackSlotIndex(*name) < 0); |
+ Variable* var = variables_.Declare(this, name, mode, true, Variable::NORMAL); |
+ var->set_rewrite(new Slot(var, Slot::CONTEXT, index)); |
+ return var; |
} |
@@ -250,6 +279,7 @@ Variable* Scope::DeclareLocal(Handle<String> name, Variable::Mode mode) { |
// DYNAMIC variables are introduces during variable allocation, |
// INTERNAL variables are allocated explicitly, and TEMPORARY |
// variables are allocated via NewTemporary(). |
+ ASSERT(!resolved()); |
ASSERT(mode == Variable::VAR || mode == Variable::CONST); |
return variables_.Declare(this, name, mode, true, Variable::NORMAL); |
} |
@@ -273,6 +303,7 @@ VariableProxy* Scope::NewUnresolved(Handle<String> name, bool inside_with) { |
// Note that we must not share the unresolved variables with |
// the same name because they may be removed selectively via |
// RemoveUnresolved(). |
+ ASSERT(!resolved()); |
VariableProxy* proxy = new VariableProxy(name, false, inside_with); |
unresolved_.Add(proxy); |
return proxy; |
@@ -292,6 +323,7 @@ void Scope::RemoveUnresolved(VariableProxy* var) { |
Variable* Scope::NewTemporary(Handle<String> name) { |
+ ASSERT(!resolved()); |
Variable* var = |
new Variable(this, name, Variable::TEMPORARY, true, Variable::NORMAL); |
temps_.Add(var); |
@@ -550,7 +582,7 @@ Variable* Scope::NonLocal(Handle<String> name, Variable::Mode mode) { |
// Declare a new non-local. |
var = map->Declare(NULL, name, mode, true, Variable::NORMAL); |
// Allocate it by giving it a dynamic lookup. |
- var->rewrite_ = new Slot(var, Slot::LOOKUP, -1); |
+ var->set_rewrite(new Slot(var, Slot::LOOKUP, -1)); |
} |
return var; |
} |
@@ -612,8 +644,9 @@ Variable* Scope::LookupRecursive(Handle<String> name, |
ASSERT(var != NULL); |
// If this is a lookup from an inner scope, mark the variable. |
- if (inner_lookup) |
- var->is_accessed_from_inner_scope_ = true; |
+ if (inner_lookup) { |
+ var->MarkAsAccessedFromInnerScope(); |
+ } |
// If the variable we have found is just a guess, invalidate the |
// result. If the found variable is local, record that fact so we |
@@ -753,7 +786,7 @@ bool Scope::MustAllocate(Variable* var) { |
// via an eval() call. This is only possible if the variable has a |
// visible name. |
if ((var->is_this() || var->name()->length() > 0) && |
- (var->is_accessed_from_inner_scope_ || |
+ (var->is_accessed_from_inner_scope() || |
scope_calls_eval_ || inner_scope_calls_eval_ || |
scope_contains_with_)) { |
var->set_is_used(true); |
@@ -771,7 +804,7 @@ bool Scope::MustAllocateInContext(Variable* var) { |
// context. |
return |
var->mode() != Variable::TEMPORARY && |
- (var->is_accessed_from_inner_scope_ || |
+ (var->is_accessed_from_inner_scope() || |
scope_calls_eval_ || inner_scope_calls_eval_ || |
scope_contains_with_ || var->is_global()); |
} |
@@ -787,12 +820,12 @@ bool Scope::HasArgumentsParameter() { |
void Scope::AllocateStackSlot(Variable* var) { |
- var->rewrite_ = new Slot(var, Slot::LOCAL, num_stack_slots_++); |
+ var->set_rewrite(new Slot(var, Slot::LOCAL, num_stack_slots_++)); |
} |
void Scope::AllocateHeapSlot(Variable* var) { |
- var->rewrite_ = new Slot(var, Slot::CONTEXT, num_heap_slots_++); |
+ var->set_rewrite(new Slot(var, Slot::CONTEXT, num_heap_slots_++)); |
} |
@@ -857,7 +890,7 @@ void Scope::AllocateParameterLocals() { |
// It is ok to set this only now, because arguments is a local |
// variable that is allocated after the parameters have been |
// allocated. |
- arguments_shadow_->is_accessed_from_inner_scope_ = true; |
+ arguments_shadow_->MarkAsAccessedFromInnerScope(); |
} |
Property* rewrite = |
new Property(new VariableProxy(arguments_shadow_), |
@@ -865,7 +898,7 @@ void Scope::AllocateParameterLocals() { |
RelocInfo::kNoPosition, |
Property::SYNTHETIC); |
rewrite->set_is_arguments_access(true); |
- var->rewrite_ = rewrite; |
+ var->set_rewrite(rewrite); |
} |
} |
@@ -880,23 +913,23 @@ void Scope::AllocateParameterLocals() { |
ASSERT(var->scope() == this); |
if (MustAllocate(var)) { |
if (MustAllocateInContext(var)) { |
- ASSERT(var->rewrite_ == NULL || |
+ ASSERT(var->rewrite() == NULL || |
(var->AsSlot() != NULL && |
var->AsSlot()->type() == Slot::CONTEXT)); |
- if (var->rewrite_ == NULL) { |
+ if (var->rewrite() == NULL) { |
// Only set the heap allocation if the parameter has not |
// been allocated yet. |
AllocateHeapSlot(var); |
} |
} else { |
- ASSERT(var->rewrite_ == NULL || |
+ ASSERT(var->rewrite() == NULL || |
(var->AsSlot() != NULL && |
var->AsSlot()->type() == Slot::PARAMETER)); |
// Set the parameter index always, even if the parameter |
// was seen before! (We need to access the actual parameter |
// supplied for the last occurrence of a multiply declared |
// parameter.) |
- var->rewrite_ = new Slot(var, Slot::PARAMETER, i); |
+ var->set_rewrite(new Slot(var, Slot::PARAMETER, i)); |
} |
} |
} |
@@ -906,10 +939,10 @@ void Scope::AllocateParameterLocals() { |
void Scope::AllocateNonParameterLocal(Variable* var) { |
ASSERT(var->scope() == this); |
- ASSERT(var->rewrite_ == NULL || |
+ ASSERT(var->rewrite() == NULL || |
(!var->IsVariable(Factory::result_symbol())) || |
(var->AsSlot() == NULL || var->AsSlot()->type() != Slot::LOCAL)); |
- if (var->rewrite_ == NULL && MustAllocate(var)) { |
+ if (var->rewrite() == NULL && MustAllocate(var)) { |
if (MustAllocateInContext(var)) { |
AllocateHeapSlot(var); |
} else { |
@@ -943,15 +976,18 @@ void Scope::AllocateNonParameterLocals() { |
void Scope::AllocateVariablesRecursively() { |
- // The number of slots required for variables. |
- num_stack_slots_ = 0; |
- num_heap_slots_ = Context::MIN_CONTEXT_SLOTS; |
- |
// Allocate variables for inner scopes. |
for (int i = 0; i < inner_scopes_.length(); i++) { |
inner_scopes_[i]->AllocateVariablesRecursively(); |
} |
+ // If scope is already resolved, we still need to allocate |
+ // variables in inner scopes which might not had been resolved yet. |
+ if (resolved()) return; |
+ // The number of slots required for variables. |
+ num_stack_slots_ = 0; |
+ num_heap_slots_ = Context::MIN_CONTEXT_SLOTS; |
+ |
// Allocate variables for this scope. |
// Parameters must be allocated first, if any. |
if (is_function_scope()) AllocateParameterLocals(); |