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:
parent
c70a12449a
commit
c4ccbaa3ea
@ -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,15 +1289,23 @@ 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_)) {
|
||||
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
|
||||
needs_migration_ = false;
|
||||
@ -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,7 +1737,21 @@ 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()) {
|
||||
@ -1731,27 +1759,40 @@ void Scope::ResolveVariablesRecursively(ParseInfo* info) {
|
||||
}
|
||||
|
||||
// Resolve unresolved variables for inner scopes.
|
||||
for (Scope* scope = inner_scope_; scope != nullptr; scope = scope->sibling_) {
|
||||
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();
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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());
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user