Commit 3cbceb21 authored by Ross McIlroy's avatar Ross McIlroy Committed by Commit Bot

[Compiler] Split ScopeInfo allocation out of DeclarationScope::Analyse.

Move ScopeInfo allocation out of DeclarationScope::Analyse and do it later
in the compile when finalizing unoptimized code generation. This is to enable
scope analysis to be done without heap allocation so it could run off-thread.

BUG=v8:5203

Change-Id: I954aacd4353925bbbd5a940d979027de2c52e1fd
Reviewed-on: https://chromium-review.googlesource.com/581108Reviewed-by: 's avatarYang Guo <yangguo@chromium.org>
Reviewed-by: 's avatarMichael Starzinger <mstarzinger@chromium.org>
Commit-Queue: Ross McIlroy <rmcilroy@chromium.org>
Cr-Commit-Position: refs/heads/master@{#46862}
parent 89ef9556
......@@ -622,8 +622,7 @@ void DeclarationScope::HoistSloppyBlockFunctions(AstNodeFactory* factory) {
}
}
void DeclarationScope::Analyze(ParseInfo* info, Isolate* isolate,
AnalyzeMode mode) {
void DeclarationScope::Analyze(ParseInfo* info, Isolate* isolate) {
RuntimeCallTimerScope runtimeTimer(isolate,
&RuntimeCallStats::CompileScopeAnalysis);
DCHECK(info->literal() != NULL);
......@@ -670,13 +669,7 @@ void DeclarationScope::Analyze(ParseInfo* info, Isolate* isolate,
info->consumed_preparsed_scope_data()->RestoreScopeAllocationData(scope);
}
scope->AllocateVariables(info, isolate, mode);
// Ensuring that the outer script scope has a scope info avoids having
// special case for native contexts vs other contexts.
if (info->script_scope()->scope_info_.is_null()) {
info->script_scope()->scope_info_ = handle(ScopeInfo::Empty(isolate));
}
scope->AllocateVariables(info);
#ifdef DEBUG
if (info->script_is_native() ? FLAG_print_builtin_scopes
......@@ -1317,29 +1310,13 @@ Declaration* Scope::CheckLexDeclarationsConflictingWith(
return nullptr;
}
void DeclarationScope::AllocateVariables(ParseInfo* info, Isolate* isolate,
AnalyzeMode mode) {
void DeclarationScope::AllocateVariables(ParseInfo* info) {
// Module variables must be allocated before variable resolution
// to ensure that UpdateNeedsHoleCheck() can detect import variables.
if (is_module_scope()) AsModuleScope()->AllocateModuleVariables();
ResolveVariablesRecursively(info);
AllocateVariablesRecursively();
MaybeHandle<ScopeInfo> outer_scope;
if (outer_scope_ != nullptr) outer_scope = outer_scope_->scope_info_;
AllocateScopeInfosRecursively(isolate, outer_scope);
if (mode == AnalyzeMode::kDebugger) {
AllocateDebuggerScopeInfos(isolate, outer_scope);
}
// The debugger expects all shared function infos to contain a scope info.
// Since the top-most scope will end up in a shared function info, make sure
// it has one, even if it doesn't need a scope info.
// TODO(jochen|yangguo): Remove this requirement.
if (scope_info_.is_null()) {
scope_info_ = ScopeInfo::Create(isolate, zone(), this, outer_scope);
}
}
bool Scope::AllowsLazyParsingWithoutUnresolvedVariables(
......@@ -2346,6 +2323,38 @@ void Scope::AllocateDebuggerScopeInfos(Isolate* isolate,
}
}
// static
void DeclarationScope::AllocateScopeInfos(ParseInfo* info, Isolate* isolate,
AnalyzeMode mode) {
DeclarationScope* scope = info->literal()->scope();
if (!scope->scope_info_.is_null()) return; // Allocated by outer function.
MaybeHandle<ScopeInfo> outer_scope;
if (scope->outer_scope_ != nullptr) {
outer_scope = scope->outer_scope_->scope_info_;
}
scope->AllocateScopeInfosRecursively(isolate, outer_scope);
if (mode == AnalyzeMode::kDebugger) {
scope->AllocateDebuggerScopeInfos(isolate, outer_scope);
}
// The debugger expects all shared function infos to contain a scope info.
// Since the top-most scope will end up in a shared function info, make sure
// it has one, even if it doesn't need a scope info.
// TODO(jochen|yangguo): Remove this requirement.
if (scope->scope_info_.is_null()) {
scope->scope_info_ =
ScopeInfo::Create(isolate, scope->zone(), scope, outer_scope);
}
// Ensuring that the outer script scope has a scope info avoids having
// special case for native contexts vs other contexts.
if (info->script_scope() && info->script_scope()->scope_info_.is_null()) {
info->script_scope()->scope_info_ = handle(ScopeInfo::Empty(isolate));
}
}
int Scope::StackLocalCount() const {
Variable* function =
is_function_scope() ? AsDeclarationScope()->function_var() : nullptr;
......
......@@ -861,7 +861,7 @@ class V8_EXPORT_PRIVATE DeclarationScope : public Scope {
// Compute top scope and allocate variables. For lazy compilation the top
// scope only contains the single lazily compiled function, so this
// doesn't re-allocate variables repeatedly.
static void Analyze(ParseInfo* info, Isolate* isolate, AnalyzeMode mode);
static void Analyze(ParseInfo* info, Isolate* isolate);
// To be called during parsing. Do just enough scope analysis that we can
// discard the Scope contents for lazily compiled functions. In particular,
......@@ -870,6 +870,11 @@ class V8_EXPORT_PRIVATE DeclarationScope : public Scope {
// and recreates them with the correct Zone with ast_node_factory.
void AnalyzePartially(AstNodeFactory* ast_node_factory);
// Allocate ScopeInfos for top scope and any inner scopes that need them.
// Does nothing if ScopeInfo is already allocated.
static void AllocateScopeInfos(ParseInfo* info, Isolate* isolate,
AnalyzeMode mode);
Handle<StringSet> CollectNonLocals(ParseInfo* info,
Handle<StringSet> non_locals);
......@@ -927,7 +932,7 @@ class V8_EXPORT_PRIVATE DeclarationScope : public Scope {
// In the case of code compiled and run using 'eval', the context
// parameter is the context in which eval was called. In all other
// cases the context parameter is an empty handle.
void AllocateVariables(ParseInfo* info, Isolate* isolate, AnalyzeMode mode);
void AllocateVariables(ParseInfo* info);
void SetDefaults();
......
......@@ -401,6 +401,10 @@ CompilationJob::Status FinalizeUnoptimizedCompilationJob(CompilationJob* job) {
ParseInfo* parse_info = info->parse_info();
Isolate* isolate = info->isolate();
// Allocate scope infos for the literal.
DeclarationScope::AllocateScopeInfos(parse_info, isolate,
AnalyzeMode::kRegular);
if (parse_info->is_toplevel()) {
// Allocate a shared function info and an array for shared function infos
// for inner functions.
......@@ -445,6 +449,8 @@ bool GenerateUnoptimizedCode(CompilationInfo* info) {
wasm_data = AsmJs::CompileAsmViaWasm(info);
if (!wasm_data.is_null()) {
SetSharedFunctionFlagsFromLiteral(info->literal(), info->shared_info());
DeclarationScope::AllocateScopeInfos(info->parse_info(), info->isolate(),
AnalyzeMode::kRegular);
info->shared_info()->set_asm_wasm_data(*wasm_data.ToHandleChecked());
info->SetCode(info->isolate()->builtins()->InstantiateAsmJs());
InstallUnoptimizedCode(info);
......@@ -545,13 +551,18 @@ bool CompileUnoptimizedCode(CompilationInfo* info,
}
}
if (info->parse_info()->is_toplevel() &&
(ShouldUseFullCodegen(info->literal()) ||
InnerFunctionShouldUseFullCodegen(&inner_literals))) {
// Full-codegen needs to access SFI when compiling, so allocate the array
// now.
EnsureSharedFunctionInfosArrayOnScript(info);
if (ShouldUseFullCodegen(info->literal()) ||
InnerFunctionShouldUseFullCodegen(&inner_literals)) {
inner_function_mode = ConcurrencyMode::kNotConcurrent;
// Full-codegen needs to access ScopeInfos when compiling, so allocate now.
DeclarationScope::AllocateScopeInfos(info->parse_info(), isolate,
AnalyzeMode::kRegular);
if (info->parse_info()->is_toplevel()) {
// Full-codegen needs to access SFI when compiling, so allocate the array
// now.
EnsureSharedFunctionInfosArrayOnScript(info);
}
}
std::shared_ptr<Zone> parse_zone;
......@@ -674,6 +685,8 @@ bool GetOptimizedCodeNow(CompilationJob* job) {
// Parsing is not required when optimizing from existing bytecode.
if (!info->is_optimizing_from_bytecode()) {
if (!Compiler::ParseAndAnalyze(info)) return false;
DeclarationScope::AllocateScopeInfos(info->parse_info(), isolate,
AnalyzeMode::kRegular);
EnsureFeedbackMetadata(info);
}
......@@ -729,6 +742,8 @@ bool GetOptimizedCodeLater(CompilationJob* job) {
// Parsing is not required when optimizing from existing bytecode.
if (!info->is_optimizing_from_bytecode()) {
if (!Compiler::ParseAndAnalyze(info)) return false;
DeclarationScope::AllocateScopeInfos(info->parse_info(), isolate,
AnalyzeMode::kRegular);
EnsureFeedbackMetadata(info);
}
......@@ -1079,7 +1094,7 @@ bool Compiler::Analyze(ParseInfo* info, Isolate* isolate,
RuntimeCallTimerScope runtimeTimer(isolate,
&RuntimeCallStats::CompileAnalyse);
if (!Rewriter::Rewrite(info, isolate)) return false;
DeclarationScope::Analyze(info, isolate, AnalyzeMode::kRegular);
DeclarationScope::Analyze(info, isolate);
if (!Renumber(info, eager_literals)) {
return false;
}
......
......@@ -121,7 +121,9 @@ void ScopeIterator::TryParseAndRetrieveScopes(ScopeIterator::Option option) {
CollectNonLocals(info.get(), scope);
}
if (!ignore_nested_scopes) {
DeclarationScope::Analyze(info.get(), isolate_, AnalyzeMode::kDebugger);
DeclarationScope::Analyze(info.get(), isolate_);
DeclarationScope::AllocateScopeInfos(info.get(), isolate_,
AnalyzeMode::kDebugger);
RetrieveScopeChain(scope);
}
} else {
......
......@@ -41,8 +41,7 @@ struct TestHelper : public HandleAndZoneScope {
CHECK(parsing::ParseFunction(&parse_info, info.shared_info(),
info.isolate()));
CHECK(Rewriter::Rewrite(&parse_info, function->GetIsolate()));
DeclarationScope::Analyze(&parse_info, info.isolate(),
AnalyzeMode::kRegular);
DeclarationScope::Analyze(&parse_info, info.isolate());
DeclarationScope* scope = info.literal()->scope();
AstValueFactory* factory = parse_info.ast_value_factory();
......
......@@ -834,7 +834,9 @@ TEST(ScopeUsesArgumentsSuperThis) {
info.set_allow_lazy_parsing(false);
CHECK(i::parsing::ParseProgram(&info, isolate));
CHECK(i::Rewriter::Rewrite(&info, isolate));
i::DeclarationScope::Analyze(&info, isolate, i::AnalyzeMode::kRegular);
i::DeclarationScope::Analyze(&info, isolate);
i::DeclarationScope::AllocateScopeInfos(&info, isolate,
i::AnalyzeMode::kRegular);
CHECK(info.literal() != NULL);
i::DeclarationScope* script_scope = info.literal()->scope();
......@@ -10267,7 +10269,9 @@ TEST(LexicalLoopVariable) {
info.set_allow_lazy_parsing(false);
CHECK(i::parsing::ParseProgram(&info, isolate));
CHECK(i::Rewriter::Rewrite(&info, isolate));
i::DeclarationScope::Analyze(&info, isolate, i::AnalyzeMode::kRegular);
i::DeclarationScope::Analyze(&info, isolate);
i::DeclarationScope::AllocateScopeInfos(&info, isolate,
i::AnalyzeMode::kRegular);
CHECK(info.literal() != NULL);
i::DeclarationScope* script_scope = info.literal()->scope();
......
......@@ -1019,8 +1019,8 @@ TEST_F(CompilerDispatcherTest, CompileParsedOutOfScope) {
ASSERT_FALSE(shared->is_compiled());
ParseInfo parse_info(shared);
ASSERT_TRUE(parsing::ParseAny(&parse_info, shared, i_isolate()));
DeferredHandleScope handles_scope(i_isolate());
ASSERT_TRUE(parsing::ParseAny(&parse_info, shared, i_isolate()));
{ ASSERT_TRUE(Compiler::Analyze(&parse_info, i_isolate())); }
std::shared_ptr<DeferredHandles> compilation_handles(
handles_scope.Detach());
......
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