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,
}
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
// also handle parse errors.
source->parser->Internalize(isolate, script,
source->info->literal() == nullptr);
source->parser->HandleSourceURLComments(isolate, script);
i::DeferredHandleScope deferred_handle_scope(isolate);
{
// Internalize AST values on the main thread.
source->info->ReopenHandlesInNewHandleScope();
source->info->ast_value_factory()->Internalize(isolate);
source->parser->HandleSourceURLComments(isolate, script);
}
source->info->set_deferred_handles(deferred_handle_scope.Detach());
i::Handle<i::SharedFunctionInfo> result;
if (source->info->literal() != nullptr) {
......
......@@ -349,8 +349,7 @@ OPEN_HANDLE_LIST(MAKE_OPEN_HANDLE)
namespace internal {
class DeferredHandles {
class V8_EXPORT_PRIVATE DeferredHandles {
public:
~DeferredHandles();
......
......@@ -108,7 +108,6 @@ CompilationInfo::~CompilationInfo() {
shared_info()->DisableOptimization(bailout_reason());
}
dependencies()->Rollback();
delete deferred_handles_;
}
int CompilationInfo::num_parameters() const {
......@@ -132,8 +131,21 @@ bool CompilationInfo::ShouldSelfOptimize() {
!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() {
closure_ = Handle<JSFunction>(*closure_);
if (!closure_.is_null()) {
closure_ = Handle<JSFunction>(*closure_);
}
}
bool CompilationInfo::has_simple_parameters() {
......
......@@ -232,9 +232,10 @@ class V8_EXPORT_PRIVATE CompilationInfo final {
// Determines whether or not to insert a self-optimization header.
bool ShouldSelfOptimize();
void set_deferred_handles(DeferredHandles* deferred_handles) {
DCHECK(deferred_handles_ == NULL);
deferred_handles_ = deferred_handles;
void set_deferred_handles(std::shared_ptr<DeferredHandles> deferred_handles);
void set_deferred_handles(DeferredHandles* deferred_handles);
std::shared_ptr<DeferredHandles> deferred_handles() {
return deferred_handles_;
}
void ReopenHandlesInNewHandleScope();
......@@ -364,7 +365,7 @@ class V8_EXPORT_PRIVATE CompilationInfo final {
// CompilationInfo allocates.
Zone* zone_;
DeferredHandles* deferred_handles_;
std::shared_ptr<DeferredHandles> deferred_handles_;
// Dependencies for this compilation, e.g. stable maps.
CompilationDependencies dependencies_;
......
......@@ -84,26 +84,27 @@ CompilerDispatcherJob::CompilerDispatcherJob(Isolate* isolate,
}
}
CompilerDispatcherJob::CompilerDispatcherJob(Isolate* isolate,
CompilerDispatcherTracer* tracer,
Handle<SharedFunctionInfo> shared,
FunctionLiteral* literal,
size_t max_stack_size)
CompilerDispatcherJob::CompilerDispatcherJob(
Isolate* isolate, CompilerDispatcherTracer* tracer,
Handle<SharedFunctionInfo> shared, 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)
: status_(CompileJobStatus::kAnalyzed),
isolate_(isolate),
tracer_(tracer),
shared_(Handle<SharedFunctionInfo>::cast(
isolate_->global_handles()->Create(*shared))),
max_stack_size_(max_stack_size),
parse_info_(
new ParseInfo(Handle<Script>(Script::cast(shared->script())))),
parse_info_(new ParseInfo(shared_)),
parse_zone_(parse_zone),
compile_info_(new CompilationInfo(parse_info_->zone(), parse_info_.get(),
Handle<JSFunction>::null())),
trace_compiler_dispatcher_jobs_(FLAG_trace_compiler_dispatcher_jobs) {
parse_info_->set_literal(literal);
parse_info_->set_shared_info(shared);
parse_info_->set_function_literal_id(shared->function_literal_id());
parse_info_->set_language_mode(literal->scope()->language_mode());
parse_info_->set_deferred_handles(parse_handles);
compile_info_->set_deferred_handles(compile_handles);
if (trace_compiler_dispatcher_jobs_) {
PrintF("CompilerDispatcherJob[%p] created for ", static_cast<void*>(this));
shared_->ShortPrint();
......@@ -276,17 +277,19 @@ bool CompilerDispatcherJob::FinalizeParsingOnMainThread() {
wrapper_ = Handle<String>::null();
}
Handle<Script> script(Script::cast(shared_->script()), isolate_);
parse_info_->set_script(script);
if (parse_info_->literal() == nullptr) {
parser_->ReportErrors(isolate_, script);
status_ = CompileJobStatus::kFailed;
} else {
status_ = CompileJobStatus::kReadyToAnalyze;
}
parser_->UpdateStatistics(isolate_, script);
DeferredHandleScope scope(isolate_);
{
Handle<Script> script(Script::cast(shared_->script()), isolate_);
parse_info_->set_script(script);
parse_info_->ReopenHandlesInNewHandleScope();
Handle<ScopeInfo> outer_scope_info(
handle(ScopeInfo::cast(shared_->outer_scope_info())));
if (outer_scope_info->length() > 0) {
......@@ -294,9 +297,8 @@ bool CompilerDispatcherJob::FinalizeParsingOnMainThread() {
}
parse_info_->set_shared_info(shared_);
// Do the parsing tasks which need to be done on the main thread. This
// will also handle parse errors.
parser_->Internalize(isolate_, script, parse_info_->literal() == nullptr);
// Internalize ast values on the main thread.
parse_info_->ast_value_factory()->Internalize(isolate_);
parser_->HandleSourceURLComments(isolate_, script);
parse_info_->set_character_stream(nullptr);
......@@ -305,7 +307,7 @@ bool CompilerDispatcherJob::FinalizeParsingOnMainThread() {
unicode_cache_.reset();
character_stream_.reset();
}
handles_from_parsing_.reset(scope.Detach());
parse_info_->set_deferred_handles(scope.Detach());
return status_ != CompileJobStatus::kFailed;
}
......@@ -393,7 +395,7 @@ bool CompilerDispatcherJob::FinalizeCompilingOnMainThread() {
compile_job_.reset();
compile_info_.reset();
handles_from_parsing_.reset();
parse_zone_.reset();
parse_info_.reset();
status_ = CompileJobStatus::kDone;
......@@ -409,10 +411,10 @@ void CompilerDispatcherJob::ResetOnMainThread() {
compile_job_.reset();
compile_info_.reset();
parse_zone_.reset();
parser_.reset();
unicode_cache_.reset();
character_stream_.reset();
handles_from_parsing_.reset();
parse_info_.reset();
if (!source_.is_null()) {
......
......@@ -20,6 +20,7 @@ class AstValueFactory;
class CompilerDispatcherTracer;
class CompilationInfo;
class CompilationJob;
class DeferredHandles;
class FunctionLiteral;
class Isolate;
class ParseInfo;
......@@ -50,7 +51,11 @@ class V8_EXPORT_PRIVATE CompilerDispatcherJob {
// Creates a CompilerDispatcherJob in the analyzed state.
CompilerDispatcherJob(Isolate* isolate, CompilerDispatcherTracer* tracer,
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();
CompileJobStatus status() const { return status_; }
......@@ -111,7 +116,9 @@ class V8_EXPORT_PRIVATE CompilerDispatcherJob {
std::unique_ptr<Utf16CharacterStream> character_stream_;
std::unique_ptr<ParseInfo> parse_info_;
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.
std::unique_ptr<CompilationInfo> compile_info_;
......
......@@ -287,8 +287,11 @@ bool CompilerDispatcher::EnqueueAndStep(Handle<SharedFunctionInfo> function) {
return true;
}
bool CompilerDispatcher::Enqueue(Handle<SharedFunctionInfo> function,
FunctionLiteral* literal) {
bool CompilerDispatcher::Enqueue(
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 (IsEnqueued(function)) return true;
......@@ -299,7 +302,8 @@ bool CompilerDispatcher::Enqueue(Handle<SharedFunctionInfo> function,
}
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(),
function->function_literal_id());
jobs_.insert(std::make_pair(key, std::move(job)));
......@@ -307,9 +311,14 @@ bool CompilerDispatcher::Enqueue(Handle<SharedFunctionInfo> function,
return true;
}
bool CompilerDispatcher::EnqueueAndStep(Handle<SharedFunctionInfo> function,
FunctionLiteral* literal) {
if (!Enqueue(function, literal)) return false;
bool CompilerDispatcher::EnqueueAndStep(
Handle<SharedFunctionInfo> function, FunctionLiteral* literal,
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_) {
PrintF("CompilerDispatcher: stepping ");
......
......@@ -28,9 +28,11 @@ namespace internal {
class CancelableTaskManager;
class CompilerDispatcherJob;
class CompilerDispatcherTracer;
class DeferredHandles;
class FunctionLiteral;
class Isolate;
class SharedFunctionInfo;
class Zone;
template <typename T>
class Handle;
......@@ -82,13 +84,19 @@ class V8_EXPORT_PRIVATE CompilerDispatcher {
// 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.
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
// continue running on a background thread (if at all possible). Returns
// true if the job was enqueued.
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.
bool IsEnqueued(Handle<SharedFunctionInfo> function) const;
......
......@@ -39,6 +39,19 @@
namespace v8 {
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
// the underlying DeferredHandleScope and stores them in info_ on
// destruction.
......@@ -512,7 +525,7 @@ bool GenerateUnoptimizedCode(CompilationInfo* info) {
bool CompileUnoptimizedInnerFunctions(
Compiler::EagerInnerFunctionLiterals* literals,
Compiler::ConcurrencyMode inner_function_mode,
CompilationInfo* outer_info) {
std::shared_ptr<Zone> parse_zone, CompilationInfo* outer_info) {
Isolate* isolate = outer_info->isolate();
Handle<Script> script = outer_info->script();
bool is_debug = outer_info->is_debug();
......@@ -534,7 +547,9 @@ bool CompileUnoptimizedInnerFunctions(
CompilerDispatcher* dispatcher = isolate->compiler_dispatcher();
if (UseCompilerDispatcher(inner_function_mode, dispatcher, literal->scope(),
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
// compiler dispatcher then we are done.
continue;
......@@ -579,9 +594,15 @@ bool CompileUnoptimizedCode(CompilationInfo* info,
DCHECK(AllowCompilation::IsAllowed(isolate));
Compiler::EagerInnerFunctionLiterals inner_literals;
if (!Compiler::Analyze(info->parse_info(), &inner_literals)) {
if (!isolate->has_pending_exception()) isolate->StackOverflow();
return false;
{
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 (!isolate->has_pending_exception()) isolate->StackOverflow();
return false;
}
}
// Disable concurrent inner compilation for asm-wasm code.
......@@ -592,15 +613,17 @@ bool CompileUnoptimizedCode(CompilationInfo* info,
inner_function_mode = Compiler::NOT_CONCURRENT;
}
std::shared_ptr<Zone> parse_zone;
if (inner_function_mode == Compiler::CONCURRENT) {
// Seal the parse zone so that it can be shared by parallel inner function
// compilation jobs.
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,
info) ||
parse_zone, info) ||
!GenerateUnoptimizedCode(info)) {
if (!isolate->has_pending_exception()) isolate->StackOverflow();
return false;
......@@ -641,8 +664,20 @@ MUST_USE_RESULT MaybeHandle<Code> GetUnoptimizedCode(
VMState<COMPILER> state(info->isolate());
PostponeInterruptsScope postpone(info->isolate());
// Parse and update CompilationInfo with the results.
if (!parsing::ParseAny(info->parse_info())) return MaybeHandle<Code>();
// Parse and update ParseInfo with the results.
{
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()) {
EnsureSharedFunctionInfosArrayOnScript(info->parse_info());
}
......@@ -1134,9 +1169,16 @@ Handle<SharedFunctionInfo> CompileToplevel(CompilationInfo* info) {
Handle<SharedFunctionInfo> result;
{ VMState<COMPILER> state(info->isolate());
if (parse_info->literal() == nullptr &&
!parsing::ParseProgram(parse_info)) {
return Handle<SharedFunctionInfo>::null();
if (parse_info->literal() == nullptr) {
if (!parsing::ParseProgram(parse_info, false)) {
return Handle<SharedFunctionInfo>::null();
}
{
ParseHandleScope parse_handles(parse_info);
parse_info->ReopenHandlesInNewHandleScope();
parse_info->ast_value_factory()->Internalize(info->isolate());
}
}
EnsureSharedFunctionInfosArrayOnScript(parse_info);
......
......@@ -361,8 +361,7 @@ class V8_EXPORT_PRIVATE CanonicalHandleScope final {
friend class HandleScope;
};
class DeferredHandleScope final {
class V8_EXPORT_PRIVATE DeferredHandleScope final {
public:
explicit DeferredHandleScope(Isolate* isolate);
// The DeferredHandles object returned stores the Handles created
......
......@@ -4,6 +4,7 @@
#include "src/parsing/parse-info.h"
#include "src/api.h"
#include "src/ast/ast-value-factory.h"
#include "src/ast/ast.h"
#include "src/heap/heap-inl.h"
......@@ -36,7 +37,8 @@ ParseInfo::ParseInfo(AccountingAllocator* zone_allocator)
cached_data_(nullptr),
ast_value_factory_(nullptr),
function_name_(nullptr),
literal_(nullptr) {}
literal_(nullptr),
deferred_handles_(nullptr) {}
ParseInfo::ParseInfo(Handle<SharedFunctionInfo> shared)
: ParseInfo(shared->GetIsolate()->allocator()) {
......@@ -108,6 +110,17 @@ FunctionKind ParseInfo::function_kind() const {
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
bool ParseInfo::script_is_native() const {
return script_->type() == Script::TYPE_NATIVE;
......
......@@ -22,6 +22,7 @@ class AccountingAllocator;
class AstRawString;
class AstValueFactory;
class DeclarationScope;
class DeferredHandles;
class FunctionLiteral;
class ScriptData;
class SharedFunctionInfo;
......@@ -45,6 +46,12 @@ class V8_EXPORT_PRIVATE ParseInfo {
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.
#define FLAG_ACCESSOR(flag, getter, setter) \
bool getter() const { return GetFlag(flag); } \
......@@ -201,8 +208,12 @@ class V8_EXPORT_PRIVATE ParseInfo {
}
void ReopenHandlesInNewHandleScope() {
shared_ = Handle<SharedFunctionInfo>(*shared_);
script_ = Handle<Script>(*script_);
if (!script_.is_null()) {
script_ = Handle<Script>(*script_);
}
if (!shared_.is_null()) {
shared_ = Handle<SharedFunctionInfo>(*shared_);
}
Handle<ScopeInfo> outer_scope_info;
if (maybe_outer_scope_info_.ToHandle(&outer_scope_info)) {
maybe_outer_scope_info_ = Handle<ScopeInfo>(*outer_scope_info);
......@@ -266,6 +277,7 @@ class V8_EXPORT_PRIVATE ParseInfo {
//----------- Output of parsing and scope analysis ------------------------
FunctionLiteral* literal_;
std::shared_ptr<DeferredHandles> deferred_handles_;
void SetFlag(Flag 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) {
}
}
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()) {
isolate->StackOverflow();
} else {
DCHECK(pending_error_handler_.has_pending_error());
pending_error_handler_.ThrowPendingError(isolate, script);
}
void Parser::ReportErrors(Isolate* isolate, Handle<Script> script) {
if (stack_overflow()) {
isolate->StackOverflow();
} else {
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);
}
}
void Parser::UpdateStatistics(Isolate* isolate, Handle<Script> script) {
// Move statistics to Isolate.
for (int feature = 0; feature < v8::Isolate::kUseCounterFeatureCount;
++feature) {
......
......@@ -222,16 +222,17 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
void DeserializeScopeChain(ParseInfo* info,
MaybeHandle<ScopeInfo> maybe_outer_scope_info);
// Handle errors detected during parsing, move statistics to Isolate,
// internalize strings (move them to the heap).
void Internalize(Isolate* isolate, Handle<Script> script, bool error);
// Handle errors detected during parsing
void ReportErrors(Isolate* isolate, Handle<Script> script);
// Move statistics to Isolate
void UpdateStatistics(Isolate* isolate, Handle<Script> script);
void HandleSourceURLComments(Isolate* isolate, Handle<Script> script);
private:
friend class ParserBase<Parser>;
friend class v8::internal::ExpressionClassifier<ParserTypes<Parser>>;
friend bool v8::internal::parsing::ParseProgram(ParseInfo*);
friend bool v8::internal::parsing::ParseFunction(ParseInfo*);
friend bool v8::internal::parsing::ParseProgram(ParseInfo*, bool);
friend bool v8::internal::parsing::ParseFunction(ParseInfo*, bool);
bool AllowsLazyParsingWithoutUnresolvedVariables() const {
return scope()->AllowsLazyParsingWithoutUnresolvedVariables(
......
......@@ -15,7 +15,7 @@ namespace v8 {
namespace internal {
namespace parsing {
bool ParseProgram(ParseInfo* info) {
bool ParseProgram(ParseInfo* info, bool internalize) {
DCHECK(info->is_toplevel());
DCHECK_NULL(info->literal());
......@@ -29,14 +29,19 @@ bool ParseProgram(ParseInfo* info) {
parser.SetCachedData(info);
result = parser.ParseProgram(isolate, info);
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());
}
parser.UpdateStatistics(isolate, info->script());
if (internalize) {
info->ast_value_factory()->Internalize(isolate);
}
return (result != nullptr);
}
bool ParseFunction(ParseInfo* info) {
bool ParseFunction(ParseInfo* info, bool internalize) {
DCHECK(!info->is_toplevel());
DCHECK_NULL(info->literal());
......@@ -49,12 +54,19 @@ bool ParseFunction(ParseInfo* info) {
result = parser.ParseFunction(isolate, info);
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);
}
bool ParseAny(ParseInfo* info) {
return info->is_toplevel() ? ParseProgram(info) : ParseFunction(info);
bool ParseAny(ParseInfo* info, bool internalize) {
return info->is_toplevel() ? ParseProgram(info, internalize)
: ParseFunction(info, internalize);
}
} // namespace parsing
......
......@@ -16,16 +16,18 @@ namespace parsing {
// Parses the top-level source code represented by the parse info and sets its
// function literal. Returns false (and deallocates any allocated AST
// nodes) if parsing failed.
V8_EXPORT_PRIVATE bool ParseProgram(ParseInfo* info);
// nodes) if parsing failed. Internalizes AST nodes on the heap if
// |internalize|.
V8_EXPORT_PRIVATE bool ParseProgram(ParseInfo* info, bool internalize = true);
// Like ParseProgram but for an individual function.
V8_EXPORT_PRIVATE bool ParseFunction(ParseInfo* info);
// Like ParseProgram but for an individual function. Internalizes AST nodes on
// 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
// to dispatch to either of the above functions. Prefer to use the above methods
// whenever possible.
V8_EXPORT_PRIVATE bool ParseAny(ParseInfo* info);
// whenever possible. Internalizes AST nodes on the heap if |internalize|.
V8_EXPORT_PRIVATE bool ParseAny(ParseInfo* info, bool internalize = true);
} // namespace parsing
} // namespace internal
......
......@@ -22,7 +22,6 @@ Handle<String> PendingCompilationErrorHandler::ArgumentString(
->NewStringFromUtf8(CStrVector(char_arg_))
.ToHandleChecked();
}
if (!handle_arg_.is_null()) return handle_arg_;
return isolate->factory()->undefined_string();
}
......
......@@ -58,20 +58,6 @@ class PendingCompilationErrorHandler {
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_; }
void ThrowPendingError(Isolate* isolate, Handle<Script> script);
......@@ -86,7 +72,6 @@ class PendingCompilationErrorHandler {
MessageTemplate::Template message_;
const AstRawString* arg_;
const char* char_arg_;
Handle<String> handle_arg_;
ParseErrorType error_type_;
DISALLOW_COPY_AND_ASSIGN(PendingCompilationErrorHandler);
......
......@@ -13,6 +13,7 @@
#include "src/handles.h"
#include "src/objects-inl.h"
#include "src/parsing/parse-info.h"
#include "src/parsing/parsing.h"
#include "src/v8.h"
#include "test/unittests/compiler-dispatcher/compiler-dispatcher-helper.h"
#include "test/unittests/test-utils.h"
......@@ -816,9 +817,11 @@ TEST_F(CompilerDispatcherTest, EnqueueParsed) {
ParseInfo parse_info(shared);
ASSERT_TRUE(Compiler::ParseAndAnalyze(&parse_info));
std::shared_ptr<DeferredHandles> handles;
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.jobs_.begin()->second->status() ==
......@@ -841,9 +844,12 @@ TEST_F(CompilerDispatcherTest, EnqueueAndStepParsed) {
ParseInfo parse_info(shared);
ASSERT_TRUE(Compiler::ParseAndAnalyze(&parse_info));
std::shared_ptr<DeferredHandles> handles;
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.jobs_.begin()->second->status() ==
......@@ -877,7 +883,9 @@ TEST_F(CompilerDispatcherTest, FinishAllNow) {
// Enqueue shared1 as already parsed.
ParseInfo parse_info(shared1);
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
ASSERT_TRUE(dispatcher.Enqueue(shared2));
......@@ -893,5 +901,43 @@ TEST_F(CompilerDispatcherTest, FinishAllNow) {
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 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