[parser] Customize preparsed scope variable resolution

Otherwise preparsed variables will cause unnecessary dynamic variable
allocation, which is especially bad when we're preparsing top-level functions
with references to other global variables.

Change-Id: I2fa17dae8c1cc5264a26ddc8b8868de1d791b0ac
Reviewed-on: https://chromium-review.googlesource.com/c/1456040
Commit-Queue: Toon Verwaest <verwaest@chromium.org>
Reviewed-by: Leszek Swirski <leszeks@chromium.org>
Cr-Commit-Position: refs/heads/master@{#59420}
This commit is contained in:
Toon Verwaest 2019-02-06 16:37:26 +01:00 committed by Commit Bot
parent d691fde360
commit c1119e2180
2 changed files with 38 additions and 7 deletions

View File

@ -2004,6 +2004,37 @@ void Scope::ResolveTo(ParseInfo* info, VariableProxy* proxy, Variable* var) {
proxy->BindTo(var);
}
bool Scope::ResolvePreparsedVariable(VariableProxy* proxy, Scope* scope,
Scope* end) {
// Resolve the variable in all parsed scopes to force context allocation.
for (; scope != end; scope = scope->outer_scope_) {
Variable* var = scope->LookupLocal(proxy->raw_name());
if (var != nullptr) {
var->set_is_used();
if (!var->is_dynamic()) {
var->ForceContextAllocation();
if (proxy->is_assigned()) var->set_maybe_assigned();
}
return true;
}
}
if (!proxy->IsPrivateName()) return true;
// If we're resolving a private name, throw an exception of we didn't manage
// to resolve. In case of eval, also look in all outer scope-info backed
// scopes except for the script scope. Don't throw an exception if a reference
// was found.
Scope* start = scope;
for (; !scope->is_script_scope(); scope = scope->outer_scope_) {
if (scope->LookupInScopeInfo(proxy->raw_name(), start) != nullptr) {
return true;
}
}
return false;
}
bool Scope::ResolveVariablesRecursively(ParseInfo* info) {
DCHECK(info->script_scope()->is_script_scope());
// Lazy parsed declaration scopes are already partially analyzed. If there are
@ -2011,9 +2042,12 @@ bool Scope::ResolveVariablesRecursively(ParseInfo* info) {
// scopes.
if (WasLazilyParsed(this)) {
DCHECK_EQ(variables_.occupancy(), 0);
Scope* end = info->scope();
// Resolve in all parsed scopes except for the script scope.
if (!end->is_script_scope()) end = end->outer_scope();
for (VariableProxy* proxy : unresolved_list_) {
Variable* var = Lookup<kParsedScope>(proxy, outer_scope(), nullptr);
if (var == nullptr) {
if (!ResolvePreparsedVariable(proxy, outer_scope(), end)) {
info->pending_error_handler()->ReportMessageAt(
proxy->position(), proxy->position() + 1,
MessageTemplate::kInvalidPrivateFieldResolution, proxy->raw_name(),
@ -2021,11 +2055,6 @@ bool Scope::ResolveVariablesRecursively(ParseInfo* info) {
DCHECK(proxy->IsPrivateName());
return false;
}
var->set_is_used();
if (!var->is_dynamic()) {
var->ForceContextAllocation();
if (proxy->is_assigned()) var->set_maybe_assigned();
}
}
} else {
// Resolve unresolved variables for this scope.

View File

@ -588,6 +588,8 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) {
static Variable* LookupSloppyEval(VariableProxy* proxy, Scope* scope,
Scope* outer_scope_end, Scope* entry_point,
bool force_context_allocation);
static bool ResolvePreparsedVariable(VariableProxy* proxy, Scope* scope,
Scope* end);
void ResolveTo(ParseInfo* info, VariableProxy* proxy, Variable* var);
V8_WARN_UNUSED_RESULT bool ResolveVariable(ParseInfo* info,
VariableProxy* proxy);