Commit 4fa2ebcb authored by verwaest's avatar verwaest Committed by Commit bot

Turn Scope::locals_ into a ThreadedList

This turns the ZoneList with minimum 6 words overhead into a linked list through variables, using 2 words for the empty list. Additionally the average number of pointers per entry goes down to the optimal 1 per variable that's in a list.

This does introduce 1 pointer unnecessary overhead for dynamic variables. If that becomes a problem we could distinguish between variables in lists and variables not in lists. We can distinguish them at construction-time.

BUG=v8:5209

Review-Url: https://codereview.chromium.org/2475433002
Cr-Commit-Position: refs/heads/master@{#40714}
parent 8f85aba4
...@@ -58,7 +58,6 @@ bool ScopeInfo::Equals(ScopeInfo* other) const { ...@@ -58,7 +58,6 @@ bool ScopeInfo::Equals(ScopeInfo* other) const {
Handle<ScopeInfo> ScopeInfo::Create(Isolate* isolate, Zone* zone, Scope* scope, Handle<ScopeInfo> ScopeInfo::Create(Isolate* isolate, Zone* zone, Scope* scope,
MaybeHandle<ScopeInfo> outer_scope) { MaybeHandle<ScopeInfo> outer_scope) {
// Collect variables. // Collect variables.
ZoneList<Variable*>* locals = scope->locals();
int stack_local_count = 0; int stack_local_count = 0;
int context_local_count = 0; int context_local_count = 0;
int module_vars_count = 0; int module_vars_count = 0;
...@@ -67,8 +66,7 @@ Handle<ScopeInfo> ScopeInfo::Create(Isolate* isolate, Zone* zone, Scope* scope, ...@@ -67,8 +66,7 @@ Handle<ScopeInfo> ScopeInfo::Create(Isolate* isolate, Zone* zone, Scope* scope,
// slot index indicates at which offset a particular scope starts in the // slot index indicates at which offset a particular scope starts in the
// parent declaration scope. // parent declaration scope.
int first_slot_index = 0; int first_slot_index = 0;
for (int i = 0; i < locals->length(); i++) { for (Variable* var : *scope->locals()) {
Variable* var = locals->at(i);
switch (var->location()) { switch (var->location()) {
case VariableLocation::LOCAL: case VariableLocation::LOCAL:
if (stack_local_count == 0) first_slot_index = var->index(); if (stack_local_count == 0) first_slot_index = var->index();
...@@ -198,8 +196,7 @@ Handle<ScopeInfo> ScopeInfo::Create(Isolate* isolate, Zone* zone, Scope* scope, ...@@ -198,8 +196,7 @@ Handle<ScopeInfo> ScopeInfo::Create(Isolate* isolate, Zone* zone, Scope* scope,
int context_local_info_base = context_local_base + context_local_count; int context_local_info_base = context_local_base + context_local_count;
int module_var_entry = scope_info->ModuleVariablesIndex(); int module_var_entry = scope_info->ModuleVariablesIndex();
for (int i = 0; i < locals->length(); ++i) { for (Variable* var : *scope->locals()) {
Variable* var = locals->at(i);
switch (var->location()) { switch (var->location()) {
case VariableLocation::LOCAL: { case VariableLocation::LOCAL: {
int local_index = var->index() - first_slot_index; int local_index = var->index() - first_slot_index;
......
...@@ -96,7 +96,6 @@ Scope::Scope(Zone* zone) ...@@ -96,7 +96,6 @@ Scope::Scope(Zone* zone)
: zone_(zone), : zone_(zone),
outer_scope_(nullptr), outer_scope_(nullptr),
variables_(zone), variables_(zone),
locals_(4, zone),
scope_type_(SCRIPT_SCOPE) { scope_type_(SCRIPT_SCOPE) {
SetDefaults(); SetDefaults();
} }
...@@ -105,7 +104,6 @@ Scope::Scope(Zone* zone, Scope* outer_scope, ScopeType scope_type) ...@@ -105,7 +104,6 @@ Scope::Scope(Zone* zone, Scope* outer_scope, ScopeType scope_type)
: zone_(zone), : zone_(zone),
outer_scope_(outer_scope), outer_scope_(outer_scope),
variables_(zone), variables_(zone),
locals_(4, zone),
scope_type_(scope_type) { scope_type_(scope_type) {
DCHECK_NE(SCRIPT_SCOPE, scope_type); DCHECK_NE(SCRIPT_SCOPE, scope_type);
SetDefaults(); SetDefaults();
...@@ -119,7 +117,7 @@ Scope::Snapshot::Snapshot(Scope* scope) ...@@ -119,7 +117,7 @@ Scope::Snapshot::Snapshot(Scope* scope)
: outer_scope_(scope), : outer_scope_(scope),
top_inner_scope_(scope->inner_scope_), top_inner_scope_(scope->inner_scope_),
top_unresolved_(scope->unresolved_), top_unresolved_(scope->unresolved_),
top_local_(scope->GetClosureScope()->locals_.length()), top_local_(scope->GetClosureScope()->locals_.end()),
top_decl_(scope->GetClosureScope()->decls_.end()) {} top_decl_(scope->GetClosureScope()->decls_.end()) {}
DeclarationScope::DeclarationScope(Zone* zone, DeclarationScope::DeclarationScope(Zone* zone,
...@@ -209,7 +207,6 @@ Scope::Scope(Zone* zone, ScopeType scope_type, Handle<ScopeInfo> scope_info) ...@@ -209,7 +207,6 @@ Scope::Scope(Zone* zone, ScopeType scope_type, Handle<ScopeInfo> scope_info)
: zone_(zone), : zone_(zone),
outer_scope_(nullptr), outer_scope_(nullptr),
variables_(zone), variables_(zone),
locals_(0, zone),
scope_info_(scope_info), scope_info_(scope_info),
scope_type_(scope_type) { scope_type_(scope_type) {
DCHECK(!scope_info.is_null()); DCHECK(!scope_info.is_null());
...@@ -238,7 +235,6 @@ Scope::Scope(Zone* zone, const AstRawString* catch_variable_name, ...@@ -238,7 +235,6 @@ Scope::Scope(Zone* zone, const AstRawString* catch_variable_name,
: zone_(zone), : zone_(zone),
outer_scope_(nullptr), outer_scope_(nullptr),
variables_(zone), variables_(zone),
locals_(0, zone),
scope_info_(scope_info), scope_info_(scope_info),
scope_type_(CATCH_SCOPE) { scope_type_(CATCH_SCOPE) {
SetDefaults(); SetDefaults();
...@@ -684,13 +680,32 @@ Scope* Scope::FinalizeBlockScope() { ...@@ -684,13 +680,32 @@ Scope* Scope::FinalizeBlockScope() {
return NULL; return NULL;
} }
void DeclarationScope::AddLocal(Variable* var) {
DCHECK(!already_resolved_);
// Temporaries are only placed in ClosureScopes.
DCHECK_EQ(GetClosureScope(), this);
locals_.Add(var);
}
Variable* Scope::Declare(Zone* zone, Scope* scope, const AstRawString* name,
VariableMode mode, VariableKind kind,
InitializationFlag initialization_flag,
MaybeAssignedFlag maybe_assigned_flag) {
bool added;
Variable* var =
variables_.Declare(zone, scope, name, mode, kind, initialization_flag,
maybe_assigned_flag, &added);
if (added) locals_.Add(var);
return var;
}
void Scope::Snapshot::Reparent(DeclarationScope* new_parent) const { void Scope::Snapshot::Reparent(DeclarationScope* new_parent) const {
DCHECK_EQ(new_parent, outer_scope_->inner_scope_); DCHECK_EQ(new_parent, outer_scope_->inner_scope_);
DCHECK_EQ(new_parent->outer_scope_, outer_scope_); DCHECK_EQ(new_parent->outer_scope_, outer_scope_);
DCHECK_EQ(new_parent, new_parent->GetClosureScope()); DCHECK_EQ(new_parent, new_parent->GetClosureScope());
DCHECK_NULL(new_parent->inner_scope_); DCHECK_NULL(new_parent->inner_scope_);
DCHECK_NULL(new_parent->unresolved_); DCHECK_NULL(new_parent->unresolved_);
DCHECK_EQ(0, new_parent->locals_.length()); DCHECK(new_parent->locals_.is_empty());
Scope* inner_scope = new_parent->sibling_; Scope* inner_scope = new_parent->sibling_;
if (inner_scope != top_inner_scope_) { if (inner_scope != top_inner_scope_) {
for (; inner_scope->sibling() != top_inner_scope_; for (; inner_scope->sibling() != top_inner_scope_;
...@@ -722,13 +737,13 @@ void Scope::Snapshot::Reparent(DeclarationScope* new_parent) const { ...@@ -722,13 +737,13 @@ void Scope::Snapshot::Reparent(DeclarationScope* new_parent) const {
// name in the closure-scope. See // name in the closure-scope. See
// test/mjsunit/harmony/default-parameter-do-expression.js. // test/mjsunit/harmony/default-parameter-do-expression.js.
DeclarationScope* outer_closure = outer_scope_->GetClosureScope(); DeclarationScope* outer_closure = outer_scope_->GetClosureScope();
for (int i = top_local_; i < outer_closure->locals_.length(); i++) {
Variable* local = outer_closure->locals_.at(i); new_parent->locals_.MoveTail(outer_closure->locals(), top_local_);
for (Variable* local : new_parent->locals_) {
DCHECK(local->mode() == TEMPORARY || local->mode() == VAR); DCHECK(local->mode() == TEMPORARY || local->mode() == VAR);
DCHECK_EQ(local->scope(), local->scope()->GetClosureScope()); DCHECK_EQ(local->scope(), local->scope()->GetClosureScope());
DCHECK_NE(local->scope(), new_parent); DCHECK_NE(local->scope(), new_parent);
local->set_scope(new_parent); local->set_scope(new_parent);
new_parent->AddLocal(local);
if (local->mode() == VAR) { if (local->mode() == VAR) {
outer_closure->variables_.Remove(local); outer_closure->variables_.Remove(local);
new_parent->variables_.Add(new_parent->zone(), local); new_parent->variables_.Add(new_parent->zone(), local);
...@@ -1238,7 +1253,7 @@ void DeclarationScope::ResetAfterPreparsing(AstValueFactory* ast_value_factory, ...@@ -1238,7 +1253,7 @@ void DeclarationScope::ResetAfterPreparsing(AstValueFactory* ast_value_factory,
// Reset all non-trivial members. // Reset all non-trivial members.
decls_.Clear(); decls_.Clear();
locals_.Rewind(0); locals_.Clear();
sloppy_block_function_map_.Clear(); sloppy_block_function_map_.Clear();
variables_.Clear(); variables_.Clear();
// Make sure we won't walk the scope tree from here on. // Make sure we won't walk the scope tree from here on.
...@@ -1255,10 +1270,14 @@ void DeclarationScope::ResetAfterPreparsing(AstValueFactory* ast_value_factory, ...@@ -1255,10 +1270,14 @@ void DeclarationScope::ResetAfterPreparsing(AstValueFactory* ast_value_factory,
for (int i = 0; i < params_.length(); i++) { for (int i = 0; i < params_.length(); i++) {
Variable* var = params_[i]; Variable* var = params_[i];
if (var->mode() == TEMPORARY) { if (var->mode() == TEMPORARY) {
locals_.Add(var, zone()); // TODO(verwaest): Remove and unfriend DeclarationScope from Variable.
*var->next() = nullptr;
locals_.Add(var);
} else if (variables_.Lookup(var->raw_name()) == nullptr) { } else if (variables_.Lookup(var->raw_name()) == nullptr) {
// TODO(verwaest): Remove and unfriend DeclarationScope from Variable.
*var->next() = nullptr;
variables_.Add(zone(), var); variables_.Add(zone(), var);
locals_.Add(var, zone()); locals_.Add(var);
} }
} }
} else { } else {
...@@ -1884,8 +1903,8 @@ void Scope::AllocateNonParameterLocal(Variable* var) { ...@@ -1884,8 +1903,8 @@ void Scope::AllocateNonParameterLocal(Variable* var) {
} }
void Scope::AllocateNonParameterLocalsAndDeclaredGlobals() { void Scope::AllocateNonParameterLocalsAndDeclaredGlobals() {
for (int i = 0; i < locals_.length(); i++) { for (Variable* local : locals_) {
AllocateNonParameterLocal(locals_[i]); AllocateNonParameterLocal(local);
} }
if (is_declaration_scope()) { if (is_declaration_scope()) {
......
...@@ -96,7 +96,7 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) { ...@@ -96,7 +96,7 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) {
Scope* outer_scope_; Scope* outer_scope_;
Scope* top_inner_scope_; Scope* top_inner_scope_;
VariableProxy* top_unresolved_; VariableProxy* top_unresolved_;
int top_local_; ThreadedList<Variable>::Iterator top_local_;
ThreadedList<Declaration>::Iterator top_decl_; ThreadedList<Declaration>::Iterator top_decl_;
}; };
...@@ -155,7 +155,7 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) { ...@@ -155,7 +155,7 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) {
// Declarations list. // Declarations list.
ThreadedList<Declaration>* declarations() { return &decls_; } ThreadedList<Declaration>* declarations() { return &decls_; }
ZoneList<Variable*>* locals() { return &locals_; } ThreadedList<Variable>* locals() { return &locals_; }
// Create a new unresolved variable. // Create a new unresolved variable.
VariableProxy* NewUnresolved(AstNodeFactory* factory, VariableProxy* NewUnresolved(AstNodeFactory* factory,
...@@ -429,14 +429,7 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) { ...@@ -429,14 +429,7 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) {
Variable* Declare(Zone* zone, Scope* scope, const AstRawString* name, Variable* Declare(Zone* zone, Scope* scope, const AstRawString* name,
VariableMode mode, VariableKind kind, VariableMode mode, VariableKind kind,
InitializationFlag initialization_flag, InitializationFlag initialization_flag,
MaybeAssignedFlag maybe_assigned_flag = kNotAssigned) { MaybeAssignedFlag maybe_assigned_flag = kNotAssigned);
bool added;
Variable* var =
variables_.Declare(zone, scope, name, mode, kind, initialization_flag,
maybe_assigned_flag, &added);
if (added) locals_.Add(var, zone);
return var;
}
// This method should only be invoked on scopes created during parsing (i.e., // This method should only be invoked on scopes created during parsing (i.e.,
// not deserialized from a context). Also, since NeedsContext() is only // not deserialized from a context). Also, since NeedsContext() is only
...@@ -459,8 +452,7 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) { ...@@ -459,8 +452,7 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) {
VariableMap variables_; VariableMap variables_;
// In case of non-scopeinfo-backed scopes, this contains the variables of the // In case of non-scopeinfo-backed scopes, this contains the variables of the
// map above in order of addition. // map above in order of addition.
// TODO(verwaest): Thread through Variable. ThreadedList<Variable> locals_;
ZoneList<Variable*> locals_;
// Unresolved variables referred to from this scope. The proxies themselves // Unresolved variables referred to from this scope. The proxies themselves
// form a linked list of all unresolved proxies. // form a linked list of all unresolved proxies.
VariableProxy* unresolved_; VariableProxy* unresolved_;
...@@ -737,12 +729,7 @@ class DeclarationScope : public Scope { ...@@ -737,12 +729,7 @@ class DeclarationScope : public Scope {
// Adds a local variable in this scope's locals list. This is for adjusting // Adds a local variable in this scope's locals list. This is for adjusting
// the scope of temporaries and do-expression vars when desugaring parameter // the scope of temporaries and do-expression vars when desugaring parameter
// initializers. // initializers.
void AddLocal(Variable* var) { void AddLocal(Variable* var);
DCHECK(!already_resolved_);
// Temporaries are only placed in ClosureScopes.
DCHECK_EQ(GetClosureScope(), this);
locals_.Add(var, zone());
}
void DeclareSloppyBlockFunction(const AstRawString* name, void DeclareSloppyBlockFunction(const AstRawString* name,
SloppyBlockFunctionStatement* statement) { SloppyBlockFunctionStatement* statement) {
......
...@@ -19,6 +19,7 @@ Variable::Variable(Scope* scope, const AstRawString* name, VariableMode mode, ...@@ -19,6 +19,7 @@ Variable::Variable(Scope* scope, const AstRawString* name, VariableMode mode,
: scope_(scope), : scope_(scope),
name_(name), name_(name),
local_if_not_shadowed_(nullptr), local_if_not_shadowed_(nullptr),
next_(nullptr),
index_(-1), index_(-1),
initializer_position_(kNoSourcePosition), initializer_position_(kNoSourcePosition),
bit_field_(MaybeAssignedFlagField::encode(maybe_assigned_flag) | bit_field_(MaybeAssignedFlagField::encode(maybe_assigned_flag) |
......
...@@ -123,6 +123,8 @@ class Variable final : public ZoneObject { ...@@ -123,6 +123,8 @@ class Variable final : public ZoneObject {
return mode == VAR ? kCreatedInitialized : kNeedsInitialization; return mode == VAR ? kCreatedInitialized : kNeedsInitialization;
} }
typedef ThreadedList<Variable> List;
private: private:
Scope* scope_; Scope* scope_;
const AstRawString* name_; const AstRawString* name_;
...@@ -132,6 +134,7 @@ class Variable final : public ZoneObject { ...@@ -132,6 +134,7 @@ class Variable final : public ZoneObject {
// sloppy 'eval' calls between the reference scope (inclusive) and the // sloppy 'eval' calls between the reference scope (inclusive) and the
// binding scope (exclusive). // binding scope (exclusive).
Variable* local_if_not_shadowed_; Variable* local_if_not_shadowed_;
Variable* next_;
int index_; int index_;
int initializer_position_; int initializer_position_;
uint16_t bit_field_; uint16_t bit_field_;
...@@ -150,6 +153,11 @@ class Variable final : public ZoneObject { ...@@ -150,6 +153,11 @@ class Variable final : public ZoneObject {
class MaybeAssignedFlagField class MaybeAssignedFlagField
: public BitField16<MaybeAssignedFlag, InitializationFlagField::kNext, : public BitField16<MaybeAssignedFlag, InitializationFlagField::kNext,
2> {}; 2> {};
Variable** next() { return &next_; }
friend List;
// To reset next to nullptr upon resetting after preparsing.
// TODO(verwaest): Remove once we properly preparse parameters.
friend class DeclarationScope;
}; };
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
......
...@@ -85,10 +85,8 @@ void AstTyper::ObserveTypesAtOsrEntry(IterationStatement* stmt) { ...@@ -85,10 +85,8 @@ void AstTyper::ObserveTypesAtOsrEntry(IterationStatement* stmt) {
store_.LookupBounds(parameter_index(i)).lower); store_.LookupBounds(parameter_index(i)).lower);
} }
ZoneList<Variable*>* local_vars = scope_->locals();
int local_index = 0; int local_index = 0;
for (int i = 0; i < local_vars->length(); i++) { for (Variable* var : *scope_->locals()) {
Variable* var = local_vars->at(i);
if (var->IsStackLocal()) { if (var->IsStackLocal()) {
PrintObserved( PrintObserved(
var, frame->GetExpression(local_index), var, frame->GetExpression(local_index),
......
...@@ -1900,9 +1900,7 @@ Handle<Object> LiveEditFunctionTracker::SerializeFunctionScope(Scope* scope) { ...@@ -1900,9 +1900,7 @@ Handle<Object> LiveEditFunctionTracker::SerializeFunctionScope(Scope* scope) {
Scope* current_scope = scope; Scope* current_scope = scope;
while (current_scope != NULL) { while (current_scope != NULL) {
HandleScope handle_scope(isolate_); HandleScope handle_scope(isolate_);
ZoneList<Variable*>* locals = current_scope->locals(); for (Variable* var : *current_scope->locals()) {
for (int i = 0; i < locals->length(); i++) {
Variable* var = locals->at(i);
if (!var->IsContextSlot()) continue; if (!var->IsContextSlot()) continue;
int context_index = var->index() - Context::MIN_CONTEXT_SLOTS; int context_index = var->index() - Context::MIN_CONTEXT_SLOTS;
int location = scope_info_length + context_index * 2; int location = scope_info_length + context_index * 2;
......
...@@ -1648,6 +1648,15 @@ class ThreadedList final { ...@@ -1648,6 +1648,15 @@ class ThreadedList final {
*tail_ = nullptr; *tail_ = nullptr;
} }
void MoveTail(ThreadedList<T>* parent, Iterator location) {
if (parent->end() != location) {
DCHECK_NULL(*tail_);
*tail_ = *location;
tail_ = parent->tail_;
parent->Rewind(location);
}
}
bool is_empty() const { return head_ == nullptr; } bool is_empty() const { return head_ == nullptr; }
// Slow. For testing purposes. // Slow. For testing purposes.
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
var outer_a; var outer_a;
function f(a) { function f(a, b, a) {
outer_a = a; outer_a = a;
x = 1; x = 1;
x = 1; x = 1;
...@@ -942,5 +942,5 @@ function f(a) { ...@@ -942,5 +942,5 @@ function f(a) {
x = 1; x = 1;
x = 1; x = 1;
} }
f(1); f(1, 2, 1);
assertEquals(1, outer_a); assertEquals(1, outer_a);
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