Commit c4ccbaa3 authored by verwaest's avatar verwaest Committed by Commit bot

Fix zone in which temp-zone parsed data is allocated for the function scope on the boundary.

BUG=chromium:417697

Review-Url: https://codereview.chromium.org/2522223002
Cr-Commit-Position: refs/heads/master@{#41271}
parent c70a1244
...@@ -1006,7 +1006,7 @@ VariableProxy* Scope::NewUnresolved(AstNodeFactory* factory, ...@@ -1006,7 +1006,7 @@ VariableProxy* Scope::NewUnresolved(AstNodeFactory* factory,
// the same name because they may be removed selectively via // the same name because they may be removed selectively via
// RemoveUnresolved(). // RemoveUnresolved().
DCHECK(!already_resolved_); DCHECK(!already_resolved_);
DCHECK_EQ(!needs_migration_, factory->zone() == zone()); DCHECK_EQ(factory->zone(), zone());
VariableProxy* proxy = factory->NewVariableProxy(name, kind, start_position); VariableProxy* proxy = factory->NewVariableProxy(name, kind, start_position);
proxy->set_next_unresolved(unresolved_); proxy->set_next_unresolved(unresolved_);
unresolved_ = proxy; unresolved_ = proxy;
...@@ -1289,14 +1289,22 @@ void DeclarationScope::ResetAfterPreparsing(AstValueFactory* ast_value_factory, ...@@ -1289,14 +1289,22 @@ void DeclarationScope::ResetAfterPreparsing(AstValueFactory* ast_value_factory,
params_.Clear(); params_.Clear();
decls_.Clear(); decls_.Clear();
locals_.Clear(); locals_.Clear();
sloppy_block_function_map_.Clear();
variables_.Clear();
// Make sure we won't walk the scope tree from here on.
inner_scope_ = nullptr; inner_scope_ = nullptr;
unresolved_ = nullptr; unresolved_ = nullptr;
if (aborted && !IsArrowFunction(function_kind_)) { if (aborted) {
DeclareDefaultFunctionVariables(ast_value_factory); // Prepare scope for use in the outer zone.
zone_ = ast_value_factory->zone();
variables_.Reset(ZoneAllocationPolicy(zone_));
sloppy_block_function_map_.Reset(ZoneAllocationPolicy(zone_));
if (!IsArrowFunction(function_kind_)) {
DeclareDefaultFunctionVariables(ast_value_factory);
}
} else {
// Make sure this scope isn't used for allocation anymore.
zone_ = nullptr;
variables_.Invalidate();
sloppy_block_function_map_.Invalidate();
} }
#ifdef DEBUG #ifdef DEBUG
...@@ -1502,7 +1510,7 @@ void Scope::Print(int n) { ...@@ -1502,7 +1510,7 @@ void Scope::Print(int n) {
PrintVar(n1, function); PrintVar(n1, function);
} }
if (variables_.Start() != NULL) { if (variables_.occupancy() != 0) {
Indent(n1, "// local vars:\n"); Indent(n1, "// local vars:\n");
PrintMap(n1, &variables_, true); PrintMap(n1, &variables_, true);
...@@ -1536,6 +1544,12 @@ void Scope::CheckScopePositions() { ...@@ -1536,6 +1544,12 @@ void Scope::CheckScopePositions() {
void Scope::CheckZones() { void Scope::CheckZones() {
DCHECK(!needs_migration_); DCHECK(!needs_migration_);
for (Scope* scope = inner_scope_; scope != nullptr; scope = scope->sibling_) { for (Scope* scope = inner_scope_; scope != nullptr; scope = scope->sibling_) {
if (scope->is_declaration_scope() &&
scope->AsDeclarationScope()->is_lazily_parsed()) {
DCHECK_NULL(scope->zone());
DCHECK_NULL(scope->inner_scope_);
continue;
}
CHECK_EQ(scope->zone(), zone()); CHECK_EQ(scope->zone(), zone());
scope->CheckZones(); scope->CheckZones();
} }
...@@ -1723,35 +1737,62 @@ void Scope::ResolveTo(ParseInfo* info, VariableProxy* proxy, Variable* var) { ...@@ -1723,35 +1737,62 @@ void Scope::ResolveTo(ParseInfo* info, VariableProxy* proxy, Variable* var) {
void Scope::ResolveVariablesRecursively(ParseInfo* info) { void Scope::ResolveVariablesRecursively(ParseInfo* info) {
DCHECK(info->script_scope()->is_script_scope()); DCHECK(info->script_scope()->is_script_scope());
// Lazy parsed declaration scopes are already partially analyzed. If there are
// unresolved references remaining, they just need to be resolved in outer
// scopes.
if (is_declaration_scope() && AsDeclarationScope()->is_lazily_parsed()) {
DCHECK(variables_.occupancy() == 0);
for (VariableProxy* proxy = unresolved_; proxy != nullptr;
proxy = proxy->next_unresolved()) {
Variable* var = outer_scope()->LookupRecursive(proxy, nullptr);
if (!var->is_dynamic()) {
var->set_is_used();
var->ForceContextAllocation();
if (proxy->is_assigned()) var->set_maybe_assigned();
}
}
} else {
// Resolve unresolved variables for this scope.
for (VariableProxy* proxy = unresolved_; proxy != nullptr;
proxy = proxy->next_unresolved()) {
ResolveVariable(info, proxy);
}
// Resolve unresolved variables for this scope. // Resolve unresolved variables for inner scopes.
for (VariableProxy* proxy = unresolved_; proxy != nullptr; for (Scope* scope = inner_scope_; scope != nullptr;
proxy = proxy->next_unresolved()) { scope = scope->sibling_) {
ResolveVariable(info, proxy); scope->ResolveVariablesRecursively(info);
} }
// Resolve unresolved variables for inner scopes.
for (Scope* scope = inner_scope_; scope != nullptr; scope = scope->sibling_) {
scope->ResolveVariablesRecursively(info);
} }
} }
VariableProxy* Scope::FetchFreeVariables(DeclarationScope* max_outer_scope, VariableProxy* Scope::FetchFreeVariables(DeclarationScope* max_outer_scope,
bool try_to_resolve, ParseInfo* info, bool try_to_resolve, ParseInfo* info,
VariableProxy* stack) { VariableProxy* stack) {
// Lazy parsed declaration scopes are already partially analyzed. If there are
// unresolved references remaining, they just need to be resolved in outer
// scopes.
Scope* lookup =
is_declaration_scope() && AsDeclarationScope()->is_lazily_parsed()
? outer_scope()
: this;
for (VariableProxy *proxy = unresolved_, *next = nullptr; proxy != nullptr; for (VariableProxy *proxy = unresolved_, *next = nullptr; proxy != nullptr;
proxy = next) { proxy = next) {
next = proxy->next_unresolved(); next = proxy->next_unresolved();
DCHECK(!proxy->is_resolved()); DCHECK(!proxy->is_resolved());
Variable* var = nullptr; Variable* var = nullptr;
if (try_to_resolve) { if (try_to_resolve) {
var = LookupRecursive(proxy, max_outer_scope->outer_scope()); var = lookup->LookupRecursive(proxy, max_outer_scope->outer_scope());
} }
if (var == nullptr) { if (var == nullptr) {
proxy->set_next_unresolved(stack); proxy->set_next_unresolved(stack);
stack = proxy; stack = proxy;
} else if (info != nullptr) { } else if (info != nullptr) {
// In this case we need to leave scopes in a way that they can be
// allocated. If we resolved variables from lazy parsed scopes, we need to
// context allocate the var.
ResolveTo(info, proxy, var); ResolveTo(info, proxy, var);
if (!var->is_dynamic() && lookup != this) var->ForceContextAllocation();
} else { } else {
var->set_is_used(); var->set_is_used();
} }
......
...@@ -555,7 +555,6 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) { ...@@ -555,7 +555,6 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) {
Handle<ScopeInfo> scope_info); Handle<ScopeInfo> scope_info);
void AddInnerScope(Scope* inner_scope) { void AddInnerScope(Scope* inner_scope) {
DCHECK_EQ(!needs_migration_, inner_scope->zone() == zone());
inner_scope->sibling_ = inner_scope_; inner_scope->sibling_ = inner_scope_;
inner_scope_ = inner_scope; inner_scope_ = inner_scope;
inner_scope->outer_scope_ = this; inner_scope->outer_scope_ = this;
......
...@@ -70,6 +70,14 @@ class TemplateHashMapImpl { ...@@ -70,6 +70,14 @@ class TemplateHashMapImpl {
// Empties the hash map (occupancy() == 0). // Empties the hash map (occupancy() == 0).
void Clear(); void Clear();
// Empties the map and makes it unusable for allocation.
void Invalidate() {
AllocationPolicy::Delete(map_);
map_ = nullptr;
occupancy_ = 0;
capacity_ = 0;
}
// The number of (non-empty) entries in the table. // The number of (non-empty) entries in the table.
uint32_t occupancy() const { return occupancy_; } uint32_t occupancy() const { return occupancy_; }
...@@ -89,6 +97,14 @@ class TemplateHashMapImpl { ...@@ -89,6 +97,14 @@ class TemplateHashMapImpl {
Entry* Start() const; Entry* Start() const;
Entry* Next(Entry* entry) const; Entry* Next(Entry* entry) const;
void Reset(AllocationPolicy allocator) {
Initialize(capacity_, allocator);
occupancy_ = 0;
}
protected:
void Initialize(uint32_t capacity, AllocationPolicy allocator);
private: private:
Entry* map_; Entry* map_;
uint32_t capacity_; uint32_t capacity_;
...@@ -102,7 +118,6 @@ class TemplateHashMapImpl { ...@@ -102,7 +118,6 @@ class TemplateHashMapImpl {
Entry* FillEmptyEntry(Entry* entry, const Key& key, const Value& value, Entry* FillEmptyEntry(Entry* entry, const Key& key, const Value& value,
uint32_t hash, uint32_t hash,
AllocationPolicy allocator = AllocationPolicy()); AllocationPolicy allocator = AllocationPolicy());
void Initialize(uint32_t capacity, AllocationPolicy allocator);
void Resize(AllocationPolicy allocator); void Resize(AllocationPolicy allocator);
}; };
template <typename Key, typename Value, typename MatchFun, template <typename Key, typename Value, typename MatchFun,
......
...@@ -712,10 +712,15 @@ class ParserBase { ...@@ -712,10 +712,15 @@ class ParserBase {
return new (zone()) Scope(zone(), parent, scope_type); return new (zone()) Scope(zone(), parent, scope_type);
} }
DeclarationScope* NewFunctionScope(FunctionKind kind) const { // Creates a function scope that always allocates in zone(). The function
// scope itself is either allocated in zone() or in target_zone if one is
// passed in.
DeclarationScope* NewFunctionScope(FunctionKind kind,
Zone* target_zone = nullptr) const {
DCHECK(ast_value_factory()); DCHECK(ast_value_factory());
DeclarationScope* result = if (target_zone == nullptr) target_zone = zone();
new (zone()) DeclarationScope(zone(), scope(), FUNCTION_SCOPE, kind); DeclarationScope* result = new (target_zone)
DeclarationScope(zone(), scope(), FUNCTION_SCOPE, kind);
// TODO(verwaest): Move into the DeclarationScope constructor. // TODO(verwaest): Move into the DeclarationScope constructor.
if (!IsArrowFunction(kind)) { if (!IsArrowFunction(kind)) {
result->DeclareDefaultFunctionVariables(ast_value_factory()); result->DeclareDefaultFunctionVariables(ast_value_factory());
......
...@@ -2626,13 +2626,6 @@ FunctionLiteral* Parser::ParseFunctionLiteral( ...@@ -2626,13 +2626,6 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
bool is_lazy_inner_function = bool is_lazy_inner_function =
use_temp_zone && FLAG_lazy_inner_functions && !is_lazy_top_level_function; use_temp_zone && FLAG_lazy_inner_functions && !is_lazy_top_level_function;
// This Scope lives in the main zone. We'll migrate data into that zone later.
DeclarationScope* scope = NewFunctionScope(kind);
SetLanguageMode(scope, language_mode);
#ifdef DEBUG
scope->SetScopeName(function_name);
#endif
ZoneList<Statement*>* body = nullptr; ZoneList<Statement*>* body = nullptr;
int materialized_literal_count = -1; int materialized_literal_count = -1;
int expected_property_count = -1; int expected_property_count = -1;
...@@ -2641,8 +2634,8 @@ FunctionLiteral* Parser::ParseFunctionLiteral( ...@@ -2641,8 +2634,8 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
int function_length = -1; int function_length = -1;
bool has_duplicate_parameters = false; bool has_duplicate_parameters = false;
Expect(Token::LPAREN, CHECK_OK); Zone* outer_zone = zone();
scope->set_start_position(scanner()->location().beg_pos); DeclarationScope* scope;
{ {
// Temporary zones can nest. When we migrate free variables (see below), we // Temporary zones can nest. When we migrate free variables (see below), we
...@@ -2657,10 +2650,19 @@ FunctionLiteral* Parser::ParseFunctionLiteral( ...@@ -2657,10 +2650,19 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
// information when the function is parsed. // information when the function is parsed.
Zone temp_zone(zone()->allocator(), ZONE_NAME); Zone temp_zone(zone()->allocator(), ZONE_NAME);
DiscardableZoneScope zone_scope(this, &temp_zone, use_temp_zone); DiscardableZoneScope zone_scope(this, &temp_zone, use_temp_zone);
// This Scope lives in the main zone. We'll migrate data into that zone
// later.
scope = NewFunctionScope(kind, outer_zone);
SetLanguageMode(scope, language_mode);
#ifdef DEBUG #ifdef DEBUG
scope->SetScopeName(function_name);
if (use_temp_zone) scope->set_needs_migration(); if (use_temp_zone) scope->set_needs_migration();
#endif #endif
Expect(Token::LPAREN, CHECK_OK);
scope->set_start_position(scanner()->location().beg_pos);
// Eager or lazy parse? If is_lazy_top_level_function, we'll parse // Eager or lazy parse? If is_lazy_top_level_function, we'll parse
// lazily. We'll call SkipFunction, which may decide to // lazily. We'll call SkipFunction, which may decide to
// abort lazy parsing if it suspects that wasn't a good idea. If so (in // abort lazy parsing if it suspects that wasn't a good idea. If so (in
......
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