Commit 0a9d4a3b authored by rmcilroy's avatar rmcilroy Committed by Commit bot

Reland: [Compiler] Enable handles created during parsing and scope analysis to be deferred.

In order to compile eager inner functions on a background thread we need to
keep the handles created during parsing and scope analysis alive until the
background compilation is complete. In order to do that, we allocate the
handles in a deferred handle scope and keep the deferred handles alive with
a shared_ptr in the ParseInfo and CompileInfo respectively.

BUG=v8:5203

Review-Url: https://codereview.chromium.org/2650883002
Cr-Commit-Position: refs/heads/master@{#43107}
parent bfd65a54
...@@ -2418,12 +2418,19 @@ MaybeLocal<Script> ScriptCompiler::Compile(Local<Context> context, ...@@ -2418,12 +2418,19 @@ MaybeLocal<Script> ScriptCompiler::Compile(Local<Context> context,
} }
source->info->set_script(script); source->info->set_script(script);
if (source->info->literal() == nullptr) {
source->parser->ReportErrors(isolate, script);
}
source->parser->UpdateStatistics(isolate, script);
// Do the parsing tasks which need to be done on the main thread. This will i::DeferredHandleScope deferred_handle_scope(isolate);
// also handle parse errors. {
source->parser->Internalize(isolate, script, // Internalize AST values on the main thread.
source->info->literal() == nullptr); source->info->ReopenHandlesInNewHandleScope();
source->info->ast_value_factory()->Internalize(isolate);
source->parser->HandleSourceURLComments(isolate, script); source->parser->HandleSourceURLComments(isolate, script);
}
source->info->set_deferred_handles(deferred_handle_scope.Detach());
i::Handle<i::SharedFunctionInfo> result; i::Handle<i::SharedFunctionInfo> result;
if (source->info->literal() != nullptr) { if (source->info->literal() != nullptr) {
......
...@@ -349,8 +349,7 @@ OPEN_HANDLE_LIST(MAKE_OPEN_HANDLE) ...@@ -349,8 +349,7 @@ OPEN_HANDLE_LIST(MAKE_OPEN_HANDLE)
namespace internal { namespace internal {
class V8_EXPORT_PRIVATE DeferredHandles {
class DeferredHandles {
public: public:
~DeferredHandles(); ~DeferredHandles();
......
...@@ -108,7 +108,6 @@ CompilationInfo::~CompilationInfo() { ...@@ -108,7 +108,6 @@ CompilationInfo::~CompilationInfo() {
shared_info()->DisableOptimization(bailout_reason()); shared_info()->DisableOptimization(bailout_reason());
} }
dependencies()->Rollback(); dependencies()->Rollback();
delete deferred_handles_;
} }
int CompilationInfo::num_parameters() const { int CompilationInfo::num_parameters() const {
...@@ -132,8 +131,21 @@ bool CompilationInfo::ShouldSelfOptimize() { ...@@ -132,8 +131,21 @@ bool CompilationInfo::ShouldSelfOptimize() {
!shared_info()->optimization_disabled(); !shared_info()->optimization_disabled();
} }
void CompilationInfo::set_deferred_handles(
std::shared_ptr<DeferredHandles> deferred_handles) {
DCHECK(deferred_handles_.get() == nullptr);
deferred_handles_.swap(deferred_handles);
}
void CompilationInfo::set_deferred_handles(DeferredHandles* deferred_handles) {
DCHECK(deferred_handles_.get() == nullptr);
deferred_handles_.reset(deferred_handles);
}
void CompilationInfo::ReopenHandlesInNewHandleScope() { void CompilationInfo::ReopenHandlesInNewHandleScope() {
if (!closure_.is_null()) {
closure_ = Handle<JSFunction>(*closure_); closure_ = Handle<JSFunction>(*closure_);
}
} }
bool CompilationInfo::has_simple_parameters() { bool CompilationInfo::has_simple_parameters() {
......
...@@ -232,9 +232,10 @@ class V8_EXPORT_PRIVATE CompilationInfo final { ...@@ -232,9 +232,10 @@ class V8_EXPORT_PRIVATE CompilationInfo final {
// Determines whether or not to insert a self-optimization header. // Determines whether or not to insert a self-optimization header.
bool ShouldSelfOptimize(); bool ShouldSelfOptimize();
void set_deferred_handles(DeferredHandles* deferred_handles) { void set_deferred_handles(std::shared_ptr<DeferredHandles> deferred_handles);
DCHECK(deferred_handles_ == NULL); void set_deferred_handles(DeferredHandles* deferred_handles);
deferred_handles_ = deferred_handles; std::shared_ptr<DeferredHandles> deferred_handles() {
return deferred_handles_;
} }
void ReopenHandlesInNewHandleScope(); void ReopenHandlesInNewHandleScope();
...@@ -364,7 +365,7 @@ class V8_EXPORT_PRIVATE CompilationInfo final { ...@@ -364,7 +365,7 @@ class V8_EXPORT_PRIVATE CompilationInfo final {
// CompilationInfo allocates. // CompilationInfo allocates.
Zone* zone_; Zone* zone_;
DeferredHandles* deferred_handles_; std::shared_ptr<DeferredHandles> deferred_handles_;
// Dependencies for this compilation, e.g. stable maps. // Dependencies for this compilation, e.g. stable maps.
CompilationDependencies dependencies_; CompilationDependencies dependencies_;
......
...@@ -84,26 +84,27 @@ CompilerDispatcherJob::CompilerDispatcherJob(Isolate* isolate, ...@@ -84,26 +84,27 @@ CompilerDispatcherJob::CompilerDispatcherJob(Isolate* isolate,
} }
} }
CompilerDispatcherJob::CompilerDispatcherJob(Isolate* isolate, CompilerDispatcherJob::CompilerDispatcherJob(
CompilerDispatcherTracer* tracer, Isolate* isolate, CompilerDispatcherTracer* tracer,
Handle<SharedFunctionInfo> shared, Handle<SharedFunctionInfo> shared, FunctionLiteral* literal,
FunctionLiteral* literal, std::shared_ptr<Zone> parse_zone,
size_t max_stack_size) std::shared_ptr<DeferredHandles> parse_handles,
std::shared_ptr<DeferredHandles> compile_handles, size_t max_stack_size)
: status_(CompileJobStatus::kAnalyzed), : status_(CompileJobStatus::kAnalyzed),
isolate_(isolate), isolate_(isolate),
tracer_(tracer), tracer_(tracer),
shared_(Handle<SharedFunctionInfo>::cast( shared_(Handle<SharedFunctionInfo>::cast(
isolate_->global_handles()->Create(*shared))), isolate_->global_handles()->Create(*shared))),
max_stack_size_(max_stack_size), max_stack_size_(max_stack_size),
parse_info_( parse_info_(new ParseInfo(shared_)),
new ParseInfo(Handle<Script>(Script::cast(shared->script())))), parse_zone_(parse_zone),
compile_info_(new CompilationInfo(parse_info_->zone(), parse_info_.get(), compile_info_(new CompilationInfo(parse_info_->zone(), parse_info_.get(),
Handle<JSFunction>::null())), Handle<JSFunction>::null())),
trace_compiler_dispatcher_jobs_(FLAG_trace_compiler_dispatcher_jobs) { trace_compiler_dispatcher_jobs_(FLAG_trace_compiler_dispatcher_jobs) {
parse_info_->set_literal(literal); parse_info_->set_literal(literal);
parse_info_->set_shared_info(shared); parse_info_->set_deferred_handles(parse_handles);
parse_info_->set_function_literal_id(shared->function_literal_id()); compile_info_->set_deferred_handles(compile_handles);
parse_info_->set_language_mode(literal->scope()->language_mode());
if (trace_compiler_dispatcher_jobs_) { if (trace_compiler_dispatcher_jobs_) {
PrintF("CompilerDispatcherJob[%p] created for ", static_cast<void*>(this)); PrintF("CompilerDispatcherJob[%p] created for ", static_cast<void*>(this));
shared_->ShortPrint(); shared_->ShortPrint();
...@@ -276,17 +277,19 @@ bool CompilerDispatcherJob::FinalizeParsingOnMainThread() { ...@@ -276,17 +277,19 @@ bool CompilerDispatcherJob::FinalizeParsingOnMainThread() {
wrapper_ = Handle<String>::null(); wrapper_ = Handle<String>::null();
} }
Handle<Script> script(Script::cast(shared_->script()), isolate_);
parse_info_->set_script(script);
if (parse_info_->literal() == nullptr) { if (parse_info_->literal() == nullptr) {
parser_->ReportErrors(isolate_, script);
status_ = CompileJobStatus::kFailed; status_ = CompileJobStatus::kFailed;
} else { } else {
status_ = CompileJobStatus::kReadyToAnalyze; status_ = CompileJobStatus::kReadyToAnalyze;
} }
parser_->UpdateStatistics(isolate_, script);
DeferredHandleScope scope(isolate_); DeferredHandleScope scope(isolate_);
{ {
Handle<Script> script(Script::cast(shared_->script()), isolate_); parse_info_->ReopenHandlesInNewHandleScope();
parse_info_->set_script(script);
Handle<ScopeInfo> outer_scope_info( Handle<ScopeInfo> outer_scope_info(
handle(ScopeInfo::cast(shared_->outer_scope_info()))); handle(ScopeInfo::cast(shared_->outer_scope_info())));
if (outer_scope_info->length() > 0) { if (outer_scope_info->length() > 0) {
...@@ -294,9 +297,8 @@ bool CompilerDispatcherJob::FinalizeParsingOnMainThread() { ...@@ -294,9 +297,8 @@ bool CompilerDispatcherJob::FinalizeParsingOnMainThread() {
} }
parse_info_->set_shared_info(shared_); parse_info_->set_shared_info(shared_);
// Do the parsing tasks which need to be done on the main thread. This // Internalize ast values on the main thread.
// will also handle parse errors. parse_info_->ast_value_factory()->Internalize(isolate_);
parser_->Internalize(isolate_, script, parse_info_->literal() == nullptr);
parser_->HandleSourceURLComments(isolate_, script); parser_->HandleSourceURLComments(isolate_, script);
parse_info_->set_character_stream(nullptr); parse_info_->set_character_stream(nullptr);
...@@ -305,7 +307,7 @@ bool CompilerDispatcherJob::FinalizeParsingOnMainThread() { ...@@ -305,7 +307,7 @@ bool CompilerDispatcherJob::FinalizeParsingOnMainThread() {
unicode_cache_.reset(); unicode_cache_.reset();
character_stream_.reset(); character_stream_.reset();
} }
handles_from_parsing_.reset(scope.Detach()); parse_info_->set_deferred_handles(scope.Detach());
return status_ != CompileJobStatus::kFailed; return status_ != CompileJobStatus::kFailed;
} }
...@@ -393,7 +395,7 @@ bool CompilerDispatcherJob::FinalizeCompilingOnMainThread() { ...@@ -393,7 +395,7 @@ bool CompilerDispatcherJob::FinalizeCompilingOnMainThread() {
compile_job_.reset(); compile_job_.reset();
compile_info_.reset(); compile_info_.reset();
handles_from_parsing_.reset(); parse_zone_.reset();
parse_info_.reset(); parse_info_.reset();
status_ = CompileJobStatus::kDone; status_ = CompileJobStatus::kDone;
...@@ -409,10 +411,10 @@ void CompilerDispatcherJob::ResetOnMainThread() { ...@@ -409,10 +411,10 @@ void CompilerDispatcherJob::ResetOnMainThread() {
compile_job_.reset(); compile_job_.reset();
compile_info_.reset(); compile_info_.reset();
parse_zone_.reset();
parser_.reset(); parser_.reset();
unicode_cache_.reset(); unicode_cache_.reset();
character_stream_.reset(); character_stream_.reset();
handles_from_parsing_.reset();
parse_info_.reset(); parse_info_.reset();
if (!source_.is_null()) { if (!source_.is_null()) {
......
...@@ -20,6 +20,7 @@ class AstValueFactory; ...@@ -20,6 +20,7 @@ class AstValueFactory;
class CompilerDispatcherTracer; class CompilerDispatcherTracer;
class CompilationInfo; class CompilationInfo;
class CompilationJob; class CompilationJob;
class DeferredHandles;
class FunctionLiteral; class FunctionLiteral;
class Isolate; class Isolate;
class ParseInfo; class ParseInfo;
...@@ -50,7 +51,11 @@ class V8_EXPORT_PRIVATE CompilerDispatcherJob { ...@@ -50,7 +51,11 @@ class V8_EXPORT_PRIVATE CompilerDispatcherJob {
// Creates a CompilerDispatcherJob in the analyzed state. // Creates a CompilerDispatcherJob in the analyzed state.
CompilerDispatcherJob(Isolate* isolate, CompilerDispatcherTracer* tracer, CompilerDispatcherJob(Isolate* isolate, CompilerDispatcherTracer* tracer,
Handle<SharedFunctionInfo> shared, Handle<SharedFunctionInfo> shared,
FunctionLiteral* literal, size_t max_stack_size); FunctionLiteral* literal,
std::shared_ptr<Zone> parse_zone,
std::shared_ptr<DeferredHandles> parse_handles,
std::shared_ptr<DeferredHandles> compile_handles,
size_t max_stack_size);
~CompilerDispatcherJob(); ~CompilerDispatcherJob();
CompileJobStatus status() const { return status_; } CompileJobStatus status() const { return status_; }
...@@ -111,7 +116,9 @@ class V8_EXPORT_PRIVATE CompilerDispatcherJob { ...@@ -111,7 +116,9 @@ class V8_EXPORT_PRIVATE CompilerDispatcherJob {
std::unique_ptr<Utf16CharacterStream> character_stream_; std::unique_ptr<Utf16CharacterStream> character_stream_;
std::unique_ptr<ParseInfo> parse_info_; std::unique_ptr<ParseInfo> parse_info_;
std::unique_ptr<Parser> parser_; std::unique_ptr<Parser> parser_;
std::unique_ptr<DeferredHandles> handles_from_parsing_;
// Members required for compiling a parsed function.
std::shared_ptr<Zone> parse_zone_;
// Members required for compiling. // Members required for compiling.
std::unique_ptr<CompilationInfo> compile_info_; std::unique_ptr<CompilationInfo> compile_info_;
......
...@@ -287,8 +287,11 @@ bool CompilerDispatcher::EnqueueAndStep(Handle<SharedFunctionInfo> function) { ...@@ -287,8 +287,11 @@ bool CompilerDispatcher::EnqueueAndStep(Handle<SharedFunctionInfo> function) {
return true; return true;
} }
bool CompilerDispatcher::Enqueue(Handle<SharedFunctionInfo> function, bool CompilerDispatcher::Enqueue(
FunctionLiteral* literal) { Handle<SharedFunctionInfo> function, FunctionLiteral* literal,
std::shared_ptr<Zone> parse_zone,
std::shared_ptr<DeferredHandles> parse_handles,
std::shared_ptr<DeferredHandles> compile_handles) {
if (!CanEnqueue(function)) return false; if (!CanEnqueue(function)) return false;
if (IsEnqueued(function)) return true; if (IsEnqueued(function)) return true;
...@@ -299,7 +302,8 @@ bool CompilerDispatcher::Enqueue(Handle<SharedFunctionInfo> function, ...@@ -299,7 +302,8 @@ bool CompilerDispatcher::Enqueue(Handle<SharedFunctionInfo> function,
} }
std::unique_ptr<CompilerDispatcherJob> job(new CompilerDispatcherJob( std::unique_ptr<CompilerDispatcherJob> job(new CompilerDispatcherJob(
isolate_, tracer_.get(), function, literal, max_stack_size_)); isolate_, tracer_.get(), function, literal, parse_zone, parse_handles,
compile_handles, max_stack_size_));
std::pair<int, int> key(Script::cast(function->script())->id(), std::pair<int, int> key(Script::cast(function->script())->id(),
function->function_literal_id()); function->function_literal_id());
jobs_.insert(std::make_pair(key, std::move(job))); jobs_.insert(std::make_pair(key, std::move(job)));
...@@ -307,9 +311,14 @@ bool CompilerDispatcher::Enqueue(Handle<SharedFunctionInfo> function, ...@@ -307,9 +311,14 @@ bool CompilerDispatcher::Enqueue(Handle<SharedFunctionInfo> function,
return true; return true;
} }
bool CompilerDispatcher::EnqueueAndStep(Handle<SharedFunctionInfo> function, bool CompilerDispatcher::EnqueueAndStep(
FunctionLiteral* literal) { Handle<SharedFunctionInfo> function, FunctionLiteral* literal,
if (!Enqueue(function, literal)) return false; std::shared_ptr<Zone> parse_zone,
std::shared_ptr<DeferredHandles> parse_handles,
std::shared_ptr<DeferredHandles> compile_handles) {
if (!Enqueue(function, literal, parse_zone, parse_handles, compile_handles)) {
return false;
}
if (trace_compiler_dispatcher_) { if (trace_compiler_dispatcher_) {
PrintF("CompilerDispatcher: stepping "); PrintF("CompilerDispatcher: stepping ");
......
...@@ -28,9 +28,11 @@ namespace internal { ...@@ -28,9 +28,11 @@ namespace internal {
class CancelableTaskManager; class CancelableTaskManager;
class CompilerDispatcherJob; class CompilerDispatcherJob;
class CompilerDispatcherTracer; class CompilerDispatcherTracer;
class DeferredHandles;
class FunctionLiteral; class FunctionLiteral;
class Isolate; class Isolate;
class SharedFunctionInfo; class SharedFunctionInfo;
class Zone;
template <typename T> template <typename T>
class Handle; class Handle;
...@@ -82,13 +84,19 @@ class V8_EXPORT_PRIVATE CompilerDispatcher { ...@@ -82,13 +84,19 @@ class V8_EXPORT_PRIVATE CompilerDispatcher {
// Enqueue a job for compilation. Function must have already been parsed and // Enqueue a job for compilation. Function must have already been parsed and
// analyzed and be ready for compilation. Returns true if a job was enqueued. // analyzed and be ready for compilation. Returns true if a job was enqueued.
bool Enqueue(Handle<SharedFunctionInfo> function, FunctionLiteral* literal); bool Enqueue(Handle<SharedFunctionInfo> function, FunctionLiteral* literal,
std::shared_ptr<Zone> parse_zone,
std::shared_ptr<DeferredHandles> parse_handles,
std::shared_ptr<DeferredHandles> compile_handles);
// Like Enqueue, but also advances the job so that it can potentially // Like Enqueue, but also advances the job so that it can potentially
// continue running on a background thread (if at all possible). Returns // continue running on a background thread (if at all possible). Returns
// true if the job was enqueued. // true if the job was enqueued.
bool EnqueueAndStep(Handle<SharedFunctionInfo> function, bool EnqueueAndStep(Handle<SharedFunctionInfo> function,
FunctionLiteral* literal); FunctionLiteral* literal,
std::shared_ptr<Zone> parse_zone,
std::shared_ptr<DeferredHandles> parse_handles,
std::shared_ptr<DeferredHandles> compile_handles);
// Returns true if there is a pending job for the given function. // Returns true if there is a pending job for the given function.
bool IsEnqueued(Handle<SharedFunctionInfo> function) const; bool IsEnqueued(Handle<SharedFunctionInfo> function) const;
......
...@@ -39,6 +39,19 @@ ...@@ -39,6 +39,19 @@
namespace v8 { namespace v8 {
namespace internal { namespace internal {
// A wrapper around a ParseInfo that detaches the parser handles from the
// underlying DeferredHandleScope and stores them in info_ on destruction.
class ParseHandleScope final {
public:
explicit ParseHandleScope(ParseInfo* info)
: deferred_(info->isolate()), info_(info) {}
~ParseHandleScope() { info_->set_deferred_handles(deferred_.Detach()); }
private:
DeferredHandleScope deferred_;
ParseInfo* info_;
};
// A wrapper around a CompilationInfo that detaches the Handles from // A wrapper around a CompilationInfo that detaches the Handles from
// the underlying DeferredHandleScope and stores them in info_ on // the underlying DeferredHandleScope and stores them in info_ on
// destruction. // destruction.
...@@ -512,7 +525,7 @@ bool GenerateUnoptimizedCode(CompilationInfo* info) { ...@@ -512,7 +525,7 @@ bool GenerateUnoptimizedCode(CompilationInfo* info) {
bool CompileUnoptimizedInnerFunctions( bool CompileUnoptimizedInnerFunctions(
Compiler::EagerInnerFunctionLiterals* literals, Compiler::EagerInnerFunctionLiterals* literals,
Compiler::ConcurrencyMode inner_function_mode, Compiler::ConcurrencyMode inner_function_mode,
CompilationInfo* outer_info) { std::shared_ptr<Zone> parse_zone, CompilationInfo* outer_info) {
Isolate* isolate = outer_info->isolate(); Isolate* isolate = outer_info->isolate();
Handle<Script> script = outer_info->script(); Handle<Script> script = outer_info->script();
bool is_debug = outer_info->is_debug(); bool is_debug = outer_info->is_debug();
...@@ -534,7 +547,9 @@ bool CompileUnoptimizedInnerFunctions( ...@@ -534,7 +547,9 @@ bool CompileUnoptimizedInnerFunctions(
CompilerDispatcher* dispatcher = isolate->compiler_dispatcher(); CompilerDispatcher* dispatcher = isolate->compiler_dispatcher();
if (UseCompilerDispatcher(inner_function_mode, dispatcher, literal->scope(), if (UseCompilerDispatcher(inner_function_mode, dispatcher, literal->scope(),
shared, is_debug, will_serialize) && shared, is_debug, will_serialize) &&
dispatcher->EnqueueAndStep(shared, literal)) { dispatcher->EnqueueAndStep(shared, literal, parse_zone,
outer_info->parse_info()->deferred_handles(),
outer_info->deferred_handles())) {
// If we have successfully queued up the function for compilation on the // If we have successfully queued up the function for compilation on the
// compiler dispatcher then we are done. // compiler dispatcher then we are done.
continue; continue;
...@@ -579,10 +594,16 @@ bool CompileUnoptimizedCode(CompilationInfo* info, ...@@ -579,10 +594,16 @@ bool CompileUnoptimizedCode(CompilationInfo* info,
DCHECK(AllowCompilation::IsAllowed(isolate)); DCHECK(AllowCompilation::IsAllowed(isolate));
Compiler::EagerInnerFunctionLiterals inner_literals; Compiler::EagerInnerFunctionLiterals inner_literals;
{
std::unique_ptr<CompilationHandleScope> compilation_handle_scope;
if (inner_function_mode == Compiler::CONCURRENT) {
compilation_handle_scope.reset(new CompilationHandleScope(info));
}
if (!Compiler::Analyze(info->parse_info(), &inner_literals)) { if (!Compiler::Analyze(info->parse_info(), &inner_literals)) {
if (!isolate->has_pending_exception()) isolate->StackOverflow(); if (!isolate->has_pending_exception()) isolate->StackOverflow();
return false; return false;
} }
}
// Disable concurrent inner compilation for asm-wasm code. // Disable concurrent inner compilation for asm-wasm code.
// TODO(rmcilroy,bradnelson): Remove this AsmWasm check once the asm-wasm // TODO(rmcilroy,bradnelson): Remove this AsmWasm check once the asm-wasm
...@@ -592,15 +613,17 @@ bool CompileUnoptimizedCode(CompilationInfo* info, ...@@ -592,15 +613,17 @@ bool CompileUnoptimizedCode(CompilationInfo* info,
inner_function_mode = Compiler::NOT_CONCURRENT; inner_function_mode = Compiler::NOT_CONCURRENT;
} }
std::shared_ptr<Zone> parse_zone;
if (inner_function_mode == Compiler::CONCURRENT) { if (inner_function_mode == Compiler::CONCURRENT) {
// Seal the parse zone so that it can be shared by parallel inner function // Seal the parse zone so that it can be shared by parallel inner function
// compilation jobs. // compilation jobs.
DCHECK_NE(info->parse_info()->zone(), info->zone()); DCHECK_NE(info->parse_info()->zone(), info->zone());
info->parse_info()->zone()->Seal(); parse_zone = info->parse_info()->zone_shared();
parse_zone->Seal();
} }
if (!CompileUnoptimizedInnerFunctions(&inner_literals, inner_function_mode, if (!CompileUnoptimizedInnerFunctions(&inner_literals, inner_function_mode,
info) || parse_zone, info) ||
!GenerateUnoptimizedCode(info)) { !GenerateUnoptimizedCode(info)) {
if (!isolate->has_pending_exception()) isolate->StackOverflow(); if (!isolate->has_pending_exception()) isolate->StackOverflow();
return false; return false;
...@@ -641,8 +664,20 @@ MUST_USE_RESULT MaybeHandle<Code> GetUnoptimizedCode( ...@@ -641,8 +664,20 @@ MUST_USE_RESULT MaybeHandle<Code> GetUnoptimizedCode(
VMState<COMPILER> state(info->isolate()); VMState<COMPILER> state(info->isolate());
PostponeInterruptsScope postpone(info->isolate()); PostponeInterruptsScope postpone(info->isolate());
// Parse and update CompilationInfo with the results. // Parse and update ParseInfo with the results.
if (!parsing::ParseAny(info->parse_info())) return MaybeHandle<Code>(); {
if (!parsing::ParseAny(info->parse_info(),
inner_function_mode != Compiler::CONCURRENT)) {
return MaybeHandle<Code>();
}
if (inner_function_mode == Compiler::CONCURRENT) {
ParseHandleScope parse_handles(info->parse_info());
info->parse_info()->ReopenHandlesInNewHandleScope();
info->parse_info()->ast_value_factory()->Internalize(info->isolate());
}
}
if (info->parse_info()->is_toplevel()) { if (info->parse_info()->is_toplevel()) {
EnsureSharedFunctionInfosArrayOnScript(info->parse_info()); EnsureSharedFunctionInfosArrayOnScript(info->parse_info());
} }
...@@ -1134,11 +1169,18 @@ Handle<SharedFunctionInfo> CompileToplevel(CompilationInfo* info) { ...@@ -1134,11 +1169,18 @@ Handle<SharedFunctionInfo> CompileToplevel(CompilationInfo* info) {
Handle<SharedFunctionInfo> result; Handle<SharedFunctionInfo> result;
{ VMState<COMPILER> state(info->isolate()); { VMState<COMPILER> state(info->isolate());
if (parse_info->literal() == nullptr && if (parse_info->literal() == nullptr) {
!parsing::ParseProgram(parse_info)) { if (!parsing::ParseProgram(parse_info, false)) {
return Handle<SharedFunctionInfo>::null(); return Handle<SharedFunctionInfo>::null();
} }
{
ParseHandleScope parse_handles(parse_info);
parse_info->ReopenHandlesInNewHandleScope();
parse_info->ast_value_factory()->Internalize(info->isolate());
}
}
EnsureSharedFunctionInfosArrayOnScript(parse_info); EnsureSharedFunctionInfosArrayOnScript(parse_info);
// Measure how long it takes to do the compilation; only take the // Measure how long it takes to do the compilation; only take the
......
...@@ -361,8 +361,7 @@ class V8_EXPORT_PRIVATE CanonicalHandleScope final { ...@@ -361,8 +361,7 @@ class V8_EXPORT_PRIVATE CanonicalHandleScope final {
friend class HandleScope; friend class HandleScope;
}; };
class V8_EXPORT_PRIVATE DeferredHandleScope final {
class DeferredHandleScope final {
public: public:
explicit DeferredHandleScope(Isolate* isolate); explicit DeferredHandleScope(Isolate* isolate);
// The DeferredHandles object returned stores the Handles created // The DeferredHandles object returned stores the Handles created
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#include "src/parsing/parse-info.h" #include "src/parsing/parse-info.h"
#include "src/api.h"
#include "src/ast/ast-value-factory.h" #include "src/ast/ast-value-factory.h"
#include "src/ast/ast.h" #include "src/ast/ast.h"
#include "src/heap/heap-inl.h" #include "src/heap/heap-inl.h"
...@@ -36,7 +37,8 @@ ParseInfo::ParseInfo(AccountingAllocator* zone_allocator) ...@@ -36,7 +37,8 @@ ParseInfo::ParseInfo(AccountingAllocator* zone_allocator)
cached_data_(nullptr), cached_data_(nullptr),
ast_value_factory_(nullptr), ast_value_factory_(nullptr),
function_name_(nullptr), function_name_(nullptr),
literal_(nullptr) {} literal_(nullptr),
deferred_handles_(nullptr) {}
ParseInfo::ParseInfo(Handle<SharedFunctionInfo> shared) ParseInfo::ParseInfo(Handle<SharedFunctionInfo> shared)
: ParseInfo(shared->GetIsolate()->allocator()) { : ParseInfo(shared->GetIsolate()->allocator()) {
...@@ -108,6 +110,17 @@ FunctionKind ParseInfo::function_kind() const { ...@@ -108,6 +110,17 @@ FunctionKind ParseInfo::function_kind() const {
return SharedFunctionInfo::FunctionKindBits::decode(compiler_hints_); return SharedFunctionInfo::FunctionKindBits::decode(compiler_hints_);
} }
void ParseInfo::set_deferred_handles(
std::shared_ptr<DeferredHandles> deferred_handles) {
DCHECK(deferred_handles_.get() == nullptr);
deferred_handles_.swap(deferred_handles);
}
void ParseInfo::set_deferred_handles(DeferredHandles* deferred_handles) {
DCHECK(deferred_handles_.get() == nullptr);
deferred_handles_.reset(deferred_handles);
}
#ifdef DEBUG #ifdef DEBUG
bool ParseInfo::script_is_native() const { bool ParseInfo::script_is_native() const {
return script_->type() == Script::TYPE_NATIVE; return script_->type() == Script::TYPE_NATIVE;
......
...@@ -22,6 +22,7 @@ class AccountingAllocator; ...@@ -22,6 +22,7 @@ class AccountingAllocator;
class AstRawString; class AstRawString;
class AstValueFactory; class AstValueFactory;
class DeclarationScope; class DeclarationScope;
class DeferredHandles;
class FunctionLiteral; class FunctionLiteral;
class ScriptData; class ScriptData;
class SharedFunctionInfo; class SharedFunctionInfo;
...@@ -45,6 +46,12 @@ class V8_EXPORT_PRIVATE ParseInfo { ...@@ -45,6 +46,12 @@ class V8_EXPORT_PRIVATE ParseInfo {
std::shared_ptr<Zone> zone_shared() const { return zone_; } std::shared_ptr<Zone> zone_shared() const { return zone_; }
void set_deferred_handles(std::shared_ptr<DeferredHandles> deferred_handles);
void set_deferred_handles(DeferredHandles* deferred_handles);
std::shared_ptr<DeferredHandles> deferred_handles() const {
return deferred_handles_;
}
// Convenience accessor methods for flags. // Convenience accessor methods for flags.
#define FLAG_ACCESSOR(flag, getter, setter) \ #define FLAG_ACCESSOR(flag, getter, setter) \
bool getter() const { return GetFlag(flag); } \ bool getter() const { return GetFlag(flag); } \
...@@ -201,8 +208,12 @@ class V8_EXPORT_PRIVATE ParseInfo { ...@@ -201,8 +208,12 @@ class V8_EXPORT_PRIVATE ParseInfo {
} }
void ReopenHandlesInNewHandleScope() { void ReopenHandlesInNewHandleScope() {
shared_ = Handle<SharedFunctionInfo>(*shared_); if (!script_.is_null()) {
script_ = Handle<Script>(*script_); script_ = Handle<Script>(*script_);
}
if (!shared_.is_null()) {
shared_ = Handle<SharedFunctionInfo>(*shared_);
}
Handle<ScopeInfo> outer_scope_info; Handle<ScopeInfo> outer_scope_info;
if (maybe_outer_scope_info_.ToHandle(&outer_scope_info)) { if (maybe_outer_scope_info_.ToHandle(&outer_scope_info)) {
maybe_outer_scope_info_ = Handle<ScopeInfo>(*outer_scope_info); maybe_outer_scope_info_ = Handle<ScopeInfo>(*outer_scope_info);
...@@ -266,6 +277,7 @@ class V8_EXPORT_PRIVATE ParseInfo { ...@@ -266,6 +277,7 @@ class V8_EXPORT_PRIVATE ParseInfo {
//----------- Output of parsing and scope analysis ------------------------ //----------- Output of parsing and scope analysis ------------------------
FunctionLiteral* literal_; FunctionLiteral* literal_;
std::shared_ptr<DeferredHandles> deferred_handles_;
void SetFlag(Flag f) { flags_ |= f; } void SetFlag(Flag f) { flags_ |= f; }
void SetFlag(Flag f, bool v) { flags_ = v ? flags_ | f : flags_ & ~f; } void SetFlag(Flag f, bool v) { flags_ = v ? flags_ | f : flags_ & ~f; }
......
...@@ -3356,21 +3356,18 @@ void Parser::HandleSourceURLComments(Isolate* isolate, Handle<Script> script) { ...@@ -3356,21 +3356,18 @@ void Parser::HandleSourceURLComments(Isolate* isolate, Handle<Script> script) {
} }
} }
void Parser::ReportErrors(Isolate* isolate, Handle<Script> script) {
void Parser::Internalize(Isolate* isolate, Handle<Script> script, bool error) {
// Internalize strings and values.
ast_value_factory()->Internalize(isolate);
// Error processing.
if (error) {
if (stack_overflow()) { if (stack_overflow()) {
isolate->StackOverflow(); isolate->StackOverflow();
} else { } else {
DCHECK(pending_error_handler_.has_pending_error()); DCHECK(pending_error_handler_.has_pending_error());
// Internalize ast values for throwing the pending error.
ast_value_factory()->Internalize(isolate);
pending_error_handler_.ThrowPendingError(isolate, script); pending_error_handler_.ThrowPendingError(isolate, script);
} }
} }
void Parser::UpdateStatistics(Isolate* isolate, Handle<Script> script) {
// Move statistics to Isolate. // Move statistics to Isolate.
for (int feature = 0; feature < v8::Isolate::kUseCounterFeatureCount; for (int feature = 0; feature < v8::Isolate::kUseCounterFeatureCount;
++feature) { ++feature) {
......
...@@ -222,16 +222,17 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) { ...@@ -222,16 +222,17 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
void DeserializeScopeChain(ParseInfo* info, void DeserializeScopeChain(ParseInfo* info,
MaybeHandle<ScopeInfo> maybe_outer_scope_info); MaybeHandle<ScopeInfo> maybe_outer_scope_info);
// Handle errors detected during parsing, move statistics to Isolate, // Handle errors detected during parsing
// internalize strings (move them to the heap). void ReportErrors(Isolate* isolate, Handle<Script> script);
void Internalize(Isolate* isolate, Handle<Script> script, bool error); // Move statistics to Isolate
void UpdateStatistics(Isolate* isolate, Handle<Script> script);
void HandleSourceURLComments(Isolate* isolate, Handle<Script> script); void HandleSourceURLComments(Isolate* isolate, Handle<Script> script);
private: private:
friend class ParserBase<Parser>; friend class ParserBase<Parser>;
friend class v8::internal::ExpressionClassifier<ParserTypes<Parser>>; friend class v8::internal::ExpressionClassifier<ParserTypes<Parser>>;
friend bool v8::internal::parsing::ParseProgram(ParseInfo*); friend bool v8::internal::parsing::ParseProgram(ParseInfo*, bool);
friend bool v8::internal::parsing::ParseFunction(ParseInfo*); friend bool v8::internal::parsing::ParseFunction(ParseInfo*, bool);
bool AllowsLazyParsingWithoutUnresolvedVariables() const { bool AllowsLazyParsingWithoutUnresolvedVariables() const {
return scope()->AllowsLazyParsingWithoutUnresolvedVariables( return scope()->AllowsLazyParsingWithoutUnresolvedVariables(
......
...@@ -15,7 +15,7 @@ namespace v8 { ...@@ -15,7 +15,7 @@ namespace v8 {
namespace internal { namespace internal {
namespace parsing { namespace parsing {
bool ParseProgram(ParseInfo* info) { bool ParseProgram(ParseInfo* info, bool internalize) {
DCHECK(info->is_toplevel()); DCHECK(info->is_toplevel());
DCHECK_NULL(info->literal()); DCHECK_NULL(info->literal());
...@@ -29,14 +29,19 @@ bool ParseProgram(ParseInfo* info) { ...@@ -29,14 +29,19 @@ bool ParseProgram(ParseInfo* info) {
parser.SetCachedData(info); parser.SetCachedData(info);
result = parser.ParseProgram(isolate, info); result = parser.ParseProgram(isolate, info);
info->set_literal(result); info->set_literal(result);
parser.Internalize(isolate, info->script(), result == nullptr); if (result == nullptr) {
if (result != nullptr) { parser.ReportErrors(isolate, info->script());
} else {
info->set_language_mode(info->literal()->language_mode()); info->set_language_mode(info->literal()->language_mode());
} }
parser.UpdateStatistics(isolate, info->script());
if (internalize) {
info->ast_value_factory()->Internalize(isolate);
}
return (result != nullptr); return (result != nullptr);
} }
bool ParseFunction(ParseInfo* info) { bool ParseFunction(ParseInfo* info, bool internalize) {
DCHECK(!info->is_toplevel()); DCHECK(!info->is_toplevel());
DCHECK_NULL(info->literal()); DCHECK_NULL(info->literal());
...@@ -49,12 +54,19 @@ bool ParseFunction(ParseInfo* info) { ...@@ -49,12 +54,19 @@ bool ParseFunction(ParseInfo* info) {
result = parser.ParseFunction(isolate, info); result = parser.ParseFunction(isolate, info);
info->set_literal(result); info->set_literal(result);
parser.Internalize(isolate, info->script(), result == nullptr); if (result == nullptr) {
parser.ReportErrors(isolate, info->script());
}
parser.UpdateStatistics(isolate, info->script());
if (internalize) {
info->ast_value_factory()->Internalize(isolate);
}
return (result != nullptr); return (result != nullptr);
} }
bool ParseAny(ParseInfo* info) { bool ParseAny(ParseInfo* info, bool internalize) {
return info->is_toplevel() ? ParseProgram(info) : ParseFunction(info); return info->is_toplevel() ? ParseProgram(info, internalize)
: ParseFunction(info, internalize);
} }
} // namespace parsing } // namespace parsing
......
...@@ -16,16 +16,18 @@ namespace parsing { ...@@ -16,16 +16,18 @@ namespace parsing {
// Parses the top-level source code represented by the parse info and sets its // Parses the top-level source code represented by the parse info and sets its
// function literal. Returns false (and deallocates any allocated AST // function literal. Returns false (and deallocates any allocated AST
// nodes) if parsing failed. // nodes) if parsing failed. Internalizes AST nodes on the heap if
V8_EXPORT_PRIVATE bool ParseProgram(ParseInfo* info); // |internalize|.
V8_EXPORT_PRIVATE bool ParseProgram(ParseInfo* info, bool internalize = true);
// Like ParseProgram but for an individual function. // Like ParseProgram but for an individual function. Internalizes AST nodes on
V8_EXPORT_PRIVATE bool ParseFunction(ParseInfo* info); // the heap if |internalize|.
V8_EXPORT_PRIVATE bool ParseFunction(ParseInfo* info, bool internalize = true);
// If you don't know whether info->is_toplevel() is true or not, use this method // If you don't know whether info->is_toplevel() is true or not, use this method
// to dispatch to either of the above functions. Prefer to use the above methods // to dispatch to either of the above functions. Prefer to use the above methods
// whenever possible. // whenever possible. Internalizes AST nodes on the heap if |internalize|.
V8_EXPORT_PRIVATE bool ParseAny(ParseInfo* info); V8_EXPORT_PRIVATE bool ParseAny(ParseInfo* info, bool internalize = true);
} // namespace parsing } // namespace parsing
} // namespace internal } // namespace internal
......
...@@ -22,7 +22,6 @@ Handle<String> PendingCompilationErrorHandler::ArgumentString( ...@@ -22,7 +22,6 @@ Handle<String> PendingCompilationErrorHandler::ArgumentString(
->NewStringFromUtf8(CStrVector(char_arg_)) ->NewStringFromUtf8(CStrVector(char_arg_))
.ToHandleChecked(); .ToHandleChecked();
} }
if (!handle_arg_.is_null()) return handle_arg_;
return isolate->factory()->undefined_string(); return isolate->factory()->undefined_string();
} }
......
...@@ -58,20 +58,6 @@ class PendingCompilationErrorHandler { ...@@ -58,20 +58,6 @@ class PendingCompilationErrorHandler {
error_type_ = error_type; error_type_ = error_type;
} }
void ReportMessageAt(int start_position, int end_position,
MessageTemplate::Template message, Handle<String> arg,
ParseErrorType error_type = kSyntaxError) {
if (has_pending_error_) return;
has_pending_error_ = true;
start_position_ = start_position;
end_position_ = end_position;
message_ = message;
char_arg_ = nullptr;
arg_ = nullptr;
handle_arg_ = arg;
error_type_ = error_type;
}
bool has_pending_error() const { return has_pending_error_; } bool has_pending_error() const { return has_pending_error_; }
void ThrowPendingError(Isolate* isolate, Handle<Script> script); void ThrowPendingError(Isolate* isolate, Handle<Script> script);
...@@ -86,7 +72,6 @@ class PendingCompilationErrorHandler { ...@@ -86,7 +72,6 @@ class PendingCompilationErrorHandler {
MessageTemplate::Template message_; MessageTemplate::Template message_;
const AstRawString* arg_; const AstRawString* arg_;
const char* char_arg_; const char* char_arg_;
Handle<String> handle_arg_;
ParseErrorType error_type_; ParseErrorType error_type_;
DISALLOW_COPY_AND_ASSIGN(PendingCompilationErrorHandler); DISALLOW_COPY_AND_ASSIGN(PendingCompilationErrorHandler);
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include "src/handles.h" #include "src/handles.h"
#include "src/objects-inl.h" #include "src/objects-inl.h"
#include "src/parsing/parse-info.h" #include "src/parsing/parse-info.h"
#include "src/parsing/parsing.h"
#include "src/v8.h" #include "src/v8.h"
#include "test/unittests/compiler-dispatcher/compiler-dispatcher-helper.h" #include "test/unittests/compiler-dispatcher/compiler-dispatcher-helper.h"
#include "test/unittests/test-utils.h" #include "test/unittests/test-utils.h"
...@@ -816,9 +817,11 @@ TEST_F(CompilerDispatcherTest, EnqueueParsed) { ...@@ -816,9 +817,11 @@ TEST_F(CompilerDispatcherTest, EnqueueParsed) {
ParseInfo parse_info(shared); ParseInfo parse_info(shared);
ASSERT_TRUE(Compiler::ParseAndAnalyze(&parse_info)); ASSERT_TRUE(Compiler::ParseAndAnalyze(&parse_info));
std::shared_ptr<DeferredHandles> handles;
ASSERT_FALSE(dispatcher.IsEnqueued(shared)); ASSERT_FALSE(dispatcher.IsEnqueued(shared));
ASSERT_TRUE(dispatcher.Enqueue(shared, parse_info.literal())); ASSERT_TRUE(dispatcher.Enqueue(shared, parse_info.literal(),
parse_info.zone_shared(), handles, handles));
ASSERT_TRUE(dispatcher.IsEnqueued(shared)); ASSERT_TRUE(dispatcher.IsEnqueued(shared));
ASSERT_TRUE(dispatcher.jobs_.begin()->second->status() == ASSERT_TRUE(dispatcher.jobs_.begin()->second->status() ==
...@@ -841,9 +844,12 @@ TEST_F(CompilerDispatcherTest, EnqueueAndStepParsed) { ...@@ -841,9 +844,12 @@ TEST_F(CompilerDispatcherTest, EnqueueAndStepParsed) {
ParseInfo parse_info(shared); ParseInfo parse_info(shared);
ASSERT_TRUE(Compiler::ParseAndAnalyze(&parse_info)); ASSERT_TRUE(Compiler::ParseAndAnalyze(&parse_info));
std::shared_ptr<DeferredHandles> handles;
ASSERT_FALSE(dispatcher.IsEnqueued(shared)); ASSERT_FALSE(dispatcher.IsEnqueued(shared));
ASSERT_TRUE(dispatcher.EnqueueAndStep(shared, parse_info.literal())); ASSERT_TRUE(dispatcher.EnqueueAndStep(shared, parse_info.literal(),
parse_info.zone_shared(), handles,
handles));
ASSERT_TRUE(dispatcher.IsEnqueued(shared)); ASSERT_TRUE(dispatcher.IsEnqueued(shared));
ASSERT_TRUE(dispatcher.jobs_.begin()->second->status() == ASSERT_TRUE(dispatcher.jobs_.begin()->second->status() ==
...@@ -877,7 +883,9 @@ TEST_F(CompilerDispatcherTest, FinishAllNow) { ...@@ -877,7 +883,9 @@ TEST_F(CompilerDispatcherTest, FinishAllNow) {
// Enqueue shared1 as already parsed. // Enqueue shared1 as already parsed.
ParseInfo parse_info(shared1); ParseInfo parse_info(shared1);
ASSERT_TRUE(Compiler::ParseAndAnalyze(&parse_info)); ASSERT_TRUE(Compiler::ParseAndAnalyze(&parse_info));
ASSERT_TRUE(dispatcher.Enqueue(shared1, parse_info.literal())); std::shared_ptr<DeferredHandles> handles;
ASSERT_TRUE(dispatcher.Enqueue(shared1, parse_info.literal(),
parse_info.zone_shared(), handles, handles));
// Enqueue shared2 for parsing and compiling // Enqueue shared2 for parsing and compiling
ASSERT_TRUE(dispatcher.Enqueue(shared2)); ASSERT_TRUE(dispatcher.Enqueue(shared2));
...@@ -893,5 +901,43 @@ TEST_F(CompilerDispatcherTest, FinishAllNow) { ...@@ -893,5 +901,43 @@ TEST_F(CompilerDispatcherTest, FinishAllNow) {
platform.ClearIdleTask(); platform.ClearIdleTask();
} }
TEST_F(CompilerDispatcherTest, CompileParsedOutOfScope) {
MockPlatform platform;
CompilerDispatcher dispatcher(i_isolate(), &platform, FLAG_stack_size);
const char script[] =
"function g() { var y = 1; function f20(x) { return x + y }; return f20; "
"} g();";
Handle<JSFunction> f = Handle<JSFunction>::cast(RunJS(isolate(), script));
Handle<SharedFunctionInfo> shared(f->shared(), i_isolate());
{
HandleScope scope(i_isolate()); // Create handles scope for parsing.
ASSERT_FALSE(shared->is_compiled());
ParseInfo parse_info(shared);
ASSERT_TRUE(parsing::ParseAny(&parse_info));
DeferredHandleScope handles_scope(i_isolate());
{ ASSERT_TRUE(Compiler::Analyze(&parse_info)); }
std::shared_ptr<DeferredHandles> compilation_handles(
handles_scope.Detach());
ASSERT_FALSE(platform.IdleTaskPending());
ASSERT_TRUE(dispatcher.Enqueue(
shared, parse_info.literal(), parse_info.zone_shared(),
parse_info.deferred_handles(), compilation_handles));
ASSERT_TRUE(platform.IdleTaskPending());
}
// Exit the handles scope and destroy ParseInfo before running the idle task.
// Since time doesn't progress on the MockPlatform, this is enough idle time
// to finish compiling the function.
platform.RunIdleTask(1000.0, 0.0);
ASSERT_FALSE(dispatcher.IsEnqueued(shared));
ASSERT_TRUE(shared->is_compiled());
}
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
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