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}
This commit is contained in:
verwaest 2016-11-24 08:06:43 -08:00 committed by Commit bot
parent c70a12449a
commit c4ccbaa3ea
5 changed files with 93 additions and 31 deletions

View File

@ -1006,7 +1006,7 @@ VariableProxy* Scope::NewUnresolved(AstNodeFactory* factory,
// the same name because they may be removed selectively via
// RemoveUnresolved().
DCHECK(!already_resolved_);
DCHECK_EQ(!needs_migration_, factory->zone() == zone());
DCHECK_EQ(factory->zone(), zone());
VariableProxy* proxy = factory->NewVariableProxy(name, kind, start_position);
proxy->set_next_unresolved(unresolved_);
unresolved_ = proxy;
@ -1289,14 +1289,22 @@ void DeclarationScope::ResetAfterPreparsing(AstValueFactory* ast_value_factory,
params_.Clear();
decls_.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;
unresolved_ = nullptr;
if (aborted && !IsArrowFunction(function_kind_)) {
DeclareDefaultFunctionVariables(ast_value_factory);
if (aborted) {
// 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
@ -1502,7 +1510,7 @@ void Scope::Print(int n) {
PrintVar(n1, function);
}
if (variables_.Start() != NULL) {
if (variables_.occupancy() != 0) {
Indent(n1, "// local vars:\n");
PrintMap(n1, &variables_, true);
@ -1536,6 +1544,12 @@ void Scope::CheckScopePositions() {
void Scope::CheckZones() {
DCHECK(!needs_migration_);
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());
scope->CheckZones();
}
@ -1723,35 +1737,62 @@ void Scope::ResolveTo(ParseInfo* info, VariableProxy* proxy, Variable* var) {
void Scope::ResolveVariablesRecursively(ParseInfo* info) {
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.
for (VariableProxy* proxy = unresolved_; proxy != nullptr;
proxy = proxy->next_unresolved()) {
ResolveVariable(info, proxy);
}
// Resolve unresolved variables for inner scopes.
for (Scope* scope = inner_scope_; scope != nullptr; scope = scope->sibling_) {
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,
bool try_to_resolve, ParseInfo* info,
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;
proxy = next) {
next = proxy->next_unresolved();
DCHECK(!proxy->is_resolved());
Variable* var = nullptr;
if (try_to_resolve) {
var = LookupRecursive(proxy, max_outer_scope->outer_scope());
var = lookup->LookupRecursive(proxy, max_outer_scope->outer_scope());
}
if (var == nullptr) {
proxy->set_next_unresolved(stack);
stack = proxy;
} 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);
if (!var->is_dynamic() && lookup != this) var->ForceContextAllocation();
} else {
var->set_is_used();
}

View File

@ -555,7 +555,6 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) {
Handle<ScopeInfo> scope_info);
void AddInnerScope(Scope* inner_scope) {
DCHECK_EQ(!needs_migration_, inner_scope->zone() == zone());
inner_scope->sibling_ = inner_scope_;
inner_scope_ = inner_scope;
inner_scope->outer_scope_ = this;

View File

@ -70,6 +70,14 @@ class TemplateHashMapImpl {
// Empties the hash map (occupancy() == 0).
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.
uint32_t occupancy() const { return occupancy_; }
@ -89,6 +97,14 @@ class TemplateHashMapImpl {
Entry* Start() const;
Entry* Next(Entry* entry) const;
void Reset(AllocationPolicy allocator) {
Initialize(capacity_, allocator);
occupancy_ = 0;
}
protected:
void Initialize(uint32_t capacity, AllocationPolicy allocator);
private:
Entry* map_;
uint32_t capacity_;
@ -102,7 +118,6 @@ class TemplateHashMapImpl {
Entry* FillEmptyEntry(Entry* entry, const Key& key, const Value& value,
uint32_t hash,
AllocationPolicy allocator = AllocationPolicy());
void Initialize(uint32_t capacity, AllocationPolicy allocator);
void Resize(AllocationPolicy allocator);
};
template <typename Key, typename Value, typename MatchFun,

View File

@ -712,10 +712,15 @@ class ParserBase {
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());
DeclarationScope* result =
new (zone()) DeclarationScope(zone(), scope(), FUNCTION_SCOPE, kind);
if (target_zone == nullptr) target_zone = zone();
DeclarationScope* result = new (target_zone)
DeclarationScope(zone(), scope(), FUNCTION_SCOPE, kind);
// TODO(verwaest): Move into the DeclarationScope constructor.
if (!IsArrowFunction(kind)) {
result->DeclareDefaultFunctionVariables(ast_value_factory());

View File

@ -2626,13 +2626,6 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
bool is_lazy_inner_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;
int materialized_literal_count = -1;
int expected_property_count = -1;
@ -2641,8 +2634,8 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
int function_length = -1;
bool has_duplicate_parameters = false;
Expect(Token::LPAREN, CHECK_OK);
scope->set_start_position(scanner()->location().beg_pos);
Zone* outer_zone = zone();
DeclarationScope* scope;
{
// Temporary zones can nest. When we migrate free variables (see below), we
@ -2657,10 +2650,19 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
// information when the function is parsed.
Zone temp_zone(zone()->allocator(), ZONE_NAME);
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
scope->SetScopeName(function_name);
if (use_temp_zone) scope->set_needs_migration();
#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
// lazily. We'll call SkipFunction, which may decide to
// abort lazy parsing if it suspects that wasn't a good idea. If so (in