[parser] Speed up variable allocation in Scopes

- Inline single-call-site functions
- Pull out pre-check from AllocateVariablesRecursively

Change-Id: Ieceaf2d5b3ef6902b293d09e6fa63e58e60f3607
Reviewed-on: https://chromium-review.googlesource.com/c/1426696
Reviewed-by: Toon Verwaest <verwaest@chromium.org>
Commit-Queue: Camillo Bruni <cbruni@chromium.org>
Cr-Commit-Position: refs/heads/master@{#59025}
This commit is contained in:
Camillo Bruni 2019-01-23 10:24:36 +01:00 committed by Commit Bot
parent be213cfc48
commit 93adf913ce
4 changed files with 51 additions and 53 deletions

View File

@ -319,10 +319,6 @@ bool Scope::HasSimpleParameters() {
return !scope->is_function_scope() || scope->has_simple_parameters();
}
bool DeclarationScope::ShouldEagerCompile() const {
return force_eager_compilation_ || should_eager_compile_;
}
void DeclarationScope::set_should_eager_compile() {
should_eager_compile_ = !was_lazily_parsed_;
}
@ -1197,7 +1193,9 @@ bool DeclarationScope::AllocateVariables(ParseInfo* info) {
DCHECK(info->pending_error_handler()->has_pending_error());
return false;
}
AllocateVariablesRecursively();
// // Don't allocate variables of preparsed scopes.
if (!was_lazily_parsed()) AllocateVariablesRecursively();
return true;
}
@ -1310,6 +1308,13 @@ Scope* Scope::GetOuterScopeWithContext() {
return scope;
}
namespace {
bool WasLazilyParsed(Scope* scope) {
return scope->is_declaration_scope() &&
scope->AsDeclarationScope()->was_lazily_parsed();
}
} // namespace
void Scope::CollectNonLocals(DeclarationScope* max_outer_scope,
Isolate* isolate, ParseInfo* info,
Handle<StringSet>* non_locals) {
@ -1320,10 +1325,7 @@ void Scope::CollectNonLocals(DeclarationScope* max_outer_scope,
// 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()->was_lazily_parsed()
? outer_scope()
: this;
Scope* lookup = WasLazilyParsed(this) ? outer_scope() : this;
for (VariableProxy* proxy : unresolved_list_) {
DCHECK(!proxy->is_resolved());
@ -1428,8 +1430,20 @@ void DeclarationScope::ResetAfterPreparsing(AstValueFactory* ast_value_factory,
was_lazily_parsed_ = !aborted;
}
bool Scope::IsSkippableFunctionScope() {
// Lazy non-arrow function scopes are skippable. Lazy functions are exactly
// those Scopes which have their own PreparseDataBuilder object. This
// logic ensures that the scope allocation data is consistent with the
// skippable function data (both agree on where the lazy function boundaries
// are).
if (!is_function_scope()) return false;
DeclarationScope* declaration_scope = AsDeclarationScope();
return !declaration_scope->is_arrow_scope() &&
declaration_scope->preparse_data_builder() != nullptr;
}
void Scope::SavePreparseData(Parser* parser) {
if (PreparseDataBuilder::ScopeIsSkippableFunctionScope(this)) {
if (IsSkippableFunctionScope()) {
AsDeclarationScope()->SavePreparseDataForDeclarationScope(parser);
}
@ -1698,8 +1712,7 @@ 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()->was_lazily_parsed()) {
if (WasLazilyParsed(scope)) {
DCHECK_NULL(scope->zone());
DCHECK_NULL(scope->inner_scope_);
continue;
@ -1999,7 +2012,7 @@ bool Scope::ResolveVariablesRecursively(ParseInfo* info) {
// 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()->was_lazily_parsed()) {
if (WasLazilyParsed(this)) {
DCHECK_EQ(variables_.occupancy(), 0);
for (VariableProxy* proxy : unresolved_list_) {
Variable* var = Lookup<kParsedScope>(proxy, outer_scope(), nullptr);
@ -2118,18 +2131,15 @@ void DeclarationScope::AllocateParameterLocals() {
}
void DeclarationScope::AllocateParameter(Variable* var, int index) {
if (MustAllocate(var)) {
if (has_forced_context_allocation_for_parameters() ||
MustAllocateInContext(var)) {
DCHECK(var->IsUnallocated() || var->IsContextSlot());
if (var->IsUnallocated()) {
AllocateHeapSlot(var);
}
} else {
DCHECK(var->IsUnallocated() || var->IsParameter());
if (var->IsUnallocated()) {
var->AllocateTo(VariableLocation::PARAMETER, index);
}
if (!MustAllocate(var)) return;
if (has_forced_context_allocation_for_parameters() ||
MustAllocateInContext(var)) {
DCHECK(var->IsUnallocated() || var->IsContextSlot());
if (var->IsUnallocated()) AllocateHeapSlot(var);
} else {
DCHECK(var->IsUnallocated() || var->IsParameter());
if (var->IsUnallocated()) {
var->AllocateTo(VariableLocation::PARAMETER, index);
}
}
}
@ -2202,14 +2212,11 @@ void ModuleScope::AllocateModuleVariables() {
void Scope::AllocateVariablesRecursively() {
DCHECK(!already_resolved_);
// Don't allocate variables of preparsed scopes.
if (is_declaration_scope() && AsDeclarationScope()->was_lazily_parsed()) {
return;
}
DCHECK(!WasLazilyParsed(this));
// Allocate variables for inner scopes.
for (Scope* scope = inner_scope_; scope != nullptr; scope = scope->sibling_) {
if (WasLazilyParsed(scope)) continue;
scope->AllocateVariablesRecursively();
}
@ -2219,9 +2226,7 @@ void Scope::AllocateVariablesRecursively() {
// Allocate variables for this scope.
// Parameters must be allocated first, if any.
if (is_declaration_scope()) {
if (is_function_scope()) {
AsDeclarationScope()->AllocateParameterLocals();
}
if (is_function_scope()) AsDeclarationScope()->AllocateParameterLocals();
AsDeclarationScope()->AllocateReceiver();
}
AllocateNonParameterLocalsAndDeclaredGlobals();

View File

@ -513,6 +513,7 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) {
bool HasSimpleParameters();
void set_is_debug_evaluate_scope() { is_debug_evaluate_scope_ = true; }
bool is_debug_evaluate_scope() const { return is_debug_evaluate_scope_; }
bool IsSkippableFunctionScope();
bool RemoveInnerScope(Scope* inner_scope) {
DCHECK_NOT_NULL(inner_scope);
@ -618,14 +619,15 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) {
// Variable allocation.
void AllocateStackSlot(Variable* var);
void AllocateHeapSlot(Variable* var);
V8_INLINE void AllocateHeapSlot(Variable* var);
void AllocateNonParameterLocal(Variable* var);
void AllocateDeclaredGlobal(Variable* var);
void AllocateNonParameterLocalsAndDeclaredGlobals();
V8_INLINE void AllocateNonParameterLocalsAndDeclaredGlobals();
void AllocateVariablesRecursively();
void AllocateScopeInfosRecursively(Isolate* isolate,
MaybeHandle<ScopeInfo> outer_scope);
void AllocateDebuggerScopeInfos(Isolate* isolate,
MaybeHandle<ScopeInfo> outer_scope);
@ -779,7 +781,10 @@ class V8_EXPORT_PRIVATE DeclarationScope : public Scope {
zone_ = zone;
}
bool ShouldEagerCompile() const;
bool ShouldEagerCompile() const {
return force_eager_compilation_ || should_eager_compile_;
}
void set_should_eager_compile();
void SetScriptScopeInfo(Handle<ScopeInfo> scope_info) {
@ -988,9 +993,9 @@ class V8_EXPORT_PRIVATE DeclarationScope : public Scope {
void PrintParameters();
#endif
void AllocateLocals();
void AllocateParameterLocals();
void AllocateReceiver();
V8_INLINE void AllocateLocals();
V8_INLINE void AllocateParameterLocals();
V8_INLINE void AllocateReceiver();
void ResetAfterPreparsing(AstValueFactory* ast_value_factory, bool aborted);
@ -1021,7 +1026,7 @@ class V8_EXPORT_PRIVATE DeclarationScope : public Scope {
}
private:
void AllocateParameter(Variable* var, int index);
V8_INLINE void AllocateParameter(Variable* var, int index);
// Resolve and fill in the allocation information for all variables
// in this scopes. Must be called *after* all scopes have been

View File

@ -363,7 +363,7 @@ void PreparseDataBuilder::SaveDataForInnerScopes(Scope* scope) {
// want to recurse here.
for (Scope* inner = scope->inner_scope(); inner != nullptr;
inner = inner->sibling()) {
if (ScopeIsSkippableFunctionScope(inner)) {
if (inner->IsSkippableFunctionScope()) {
// Don't save data about function scopes, since they'll have their own
// PreparseDataBuilder where their data is saved.
DCHECK_NOT_NULL(inner->AsDeclarationScope()->preparse_data_builder());
@ -374,17 +374,6 @@ void PreparseDataBuilder::SaveDataForInnerScopes(Scope* scope) {
}
}
bool PreparseDataBuilder::ScopeIsSkippableFunctionScope(Scope* scope) {
// Lazy non-arrow function scopes are skippable. Lazy functions are exactly
// those Scopes which have their own PreparseDataBuilder object. This
// logic ensures that the scope allocation data is consistent with the
// skippable function data (both agree on where the lazy function boundaries
// are).
if (scope->scope_type() != ScopeType::FUNCTION_SCOPE) return false;
DeclarationScope* declaration_scope = scope->AsDeclarationScope();
return !declaration_scope->is_arrow_scope() &&
declaration_scope->preparse_data_builder() != nullptr;
}
Handle<PreparseData> PreparseDataBuilder::ByteData::CopyToHeap(
Isolate* isolate, int children_length) {

View File

@ -180,7 +180,6 @@ class PreparseDataBuilder : public ZoneObject,
bool HasDataForParent() const;
static bool ScopeNeedsData(Scope* scope);
static bool ScopeIsSkippableFunctionScope(Scope* scope);
void AddSkippableFunction(int start_position, int end_position,
int num_parameters, int num_inner_functions,
LanguageMode language_mode, bool has_data,