aboutsummaryrefslogtreecommitdiff
path: root/src/compiler-dispatcher/compiler-dispatcher-job.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/compiler-dispatcher/compiler-dispatcher-job.cc')
-rw-r--r--src/compiler-dispatcher/compiler-dispatcher-job.cc348
1 files changed, 285 insertions, 63 deletions
diff --git a/src/compiler-dispatcher/compiler-dispatcher-job.cc b/src/compiler-dispatcher/compiler-dispatcher-job.cc
index b87a4a5c..56d166f5 100644
--- a/src/compiler-dispatcher/compiler-dispatcher-job.cc
+++ b/src/compiler-dispatcher/compiler-dispatcher-job.cc
@@ -8,6 +8,7 @@
#include "src/compilation-info.h"
#include "src/compiler-dispatcher/compiler-dispatcher-tracer.h"
#include "src/compiler.h"
+#include "src/flags.h"
#include "src/global-handles.h"
#include "src/isolate.h"
#include "src/objects-inl.h"
@@ -15,26 +16,104 @@
#include "src/parsing/parser.h"
#include "src/parsing/scanner-character-streams.h"
#include "src/unicode-cache.h"
-#include "src/zone/zone.h"
+#include "src/utils.h"
namespace v8 {
namespace internal {
+namespace {
+
+class OneByteWrapper : public v8::String::ExternalOneByteStringResource {
+ public:
+ OneByteWrapper(const void* data, int length) : data_(data), length_(length) {}
+ ~OneByteWrapper() override = default;
+
+ const char* data() const override {
+ return reinterpret_cast<const char*>(data_);
+ }
+
+ size_t length() const override { return static_cast<size_t>(length_); }
+
+ private:
+ const void* data_;
+ int length_;
+
+ DISALLOW_COPY_AND_ASSIGN(OneByteWrapper);
+};
+
+class TwoByteWrapper : public v8::String::ExternalStringResource {
+ public:
+ TwoByteWrapper(const void* data, int length) : data_(data), length_(length) {}
+ ~TwoByteWrapper() override = default;
+
+ const uint16_t* data() const override {
+ return reinterpret_cast<const uint16_t*>(data_);
+ }
+
+ size_t length() const override { return static_cast<size_t>(length_); }
+
+ private:
+ const void* data_;
+ int length_;
+
+ DISALLOW_COPY_AND_ASSIGN(TwoByteWrapper);
+};
+
+} // namespace
+
CompilerDispatcherJob::CompilerDispatcherJob(Isolate* isolate,
+ CompilerDispatcherTracer* tracer,
Handle<SharedFunctionInfo> shared,
size_t max_stack_size)
- : isolate_(isolate),
- tracer_(isolate_->compiler_dispatcher_tracer()),
+ : status_(CompileJobStatus::kInitial),
+ isolate_(isolate),
+ tracer_(tracer),
+ context_(Handle<Context>::cast(
+ isolate_->global_handles()->Create(isolate->context()))),
shared_(Handle<SharedFunctionInfo>::cast(
isolate_->global_handles()->Create(*shared))),
max_stack_size_(max_stack_size),
- can_compile_on_background_thread_(false) {
+ trace_compiler_dispatcher_jobs_(FLAG_trace_compiler_dispatcher_jobs) {
+ DCHECK(!shared_->is_toplevel());
HandleScope scope(isolate_);
- DCHECK(!shared_->outer_scope_info()->IsTheHole(isolate_));
Handle<Script> script(Script::cast(shared_->script()), isolate_);
Handle<String> source(String::cast(script->source()), isolate_);
- can_parse_on_background_thread_ =
- source->IsExternalTwoByteString() || source->IsExternalOneByteString();
+ if (trace_compiler_dispatcher_jobs_) {
+ PrintF("CompilerDispatcherJob[%p] created for ", static_cast<void*>(this));
+ shared_->ShortPrint();
+ PrintF(" in initial state.\n");
+ }
+}
+
+CompilerDispatcherJob::CompilerDispatcherJob(
+ Isolate* isolate, CompilerDispatcherTracer* tracer, Handle<Script> script,
+ 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),
+ context_(Handle<Context>::cast(
+ isolate_->global_handles()->Create(isolate->context()))),
+ shared_(Handle<SharedFunctionInfo>::cast(
+ isolate_->global_handles()->Create(*shared))),
+ max_stack_size_(max_stack_size),
+ 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_script(script);
+ 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();
+ PrintF(" in Analyzed state.\n");
+ }
}
CompilerDispatcherJob::~CompilerDispatcherJob() {
@@ -42,31 +121,97 @@ CompilerDispatcherJob::~CompilerDispatcherJob() {
DCHECK(status_ == CompileJobStatus::kInitial ||
status_ == CompileJobStatus::kDone);
i::GlobalHandles::Destroy(Handle<Object>::cast(shared_).location());
+ i::GlobalHandles::Destroy(Handle<Object>::cast(context_).location());
+}
+
+bool CompilerDispatcherJob::IsAssociatedWith(
+ Handle<SharedFunctionInfo> shared) const {
+ return *shared_ == *shared;
}
void CompilerDispatcherJob::PrepareToParseOnMainThread() {
DCHECK(ThreadId::Current().Equals(isolate_->thread_id()));
DCHECK(status() == CompileJobStatus::kInitial);
COMPILER_DISPATCHER_TRACE_SCOPE(tracer_, kPrepareToParse);
+ if (trace_compiler_dispatcher_jobs_) {
+ PrintF("CompilerDispatcherJob[%p]: Preparing to parse\n",
+ static_cast<void*>(this));
+ }
HandleScope scope(isolate_);
unicode_cache_.reset(new UnicodeCache());
- zone_.reset(new Zone(isolate_->allocator(), ZONE_NAME));
Handle<Script> script(Script::cast(shared_->script()), isolate_);
DCHECK(script->type() != Script::TYPE_NATIVE);
Handle<String> source(String::cast(script->source()), isolate_);
+ parse_info_.reset(new ParseInfo(isolate_->allocator()));
if (source->IsExternalTwoByteString() || source->IsExternalOneByteString()) {
character_stream_.reset(ScannerStream::For(
source, shared_->start_position(), shared_->end_position()));
} else {
source = String::Flatten(source);
- // Have to globalize the reference here, so it survives between function
- // calls.
- source_ = Handle<String>::cast(isolate_->global_handles()->Create(*source));
- character_stream_.reset(ScannerStream::For(
- source_, shared_->start_position(), shared_->end_position()));
+ const void* data;
+ int offset = 0;
+ int length = source->length();
+
+ // Objects in lo_space don't move, so we can just read the contents from
+ // any thread.
+ if (isolate_->heap()->lo_space()->Contains(*source)) {
+ // We need to globalize the handle to the flattened string here, in
+ // case it's not referenced from anywhere else.
+ source_ =
+ Handle<String>::cast(isolate_->global_handles()->Create(*source));
+ DisallowHeapAllocation no_allocation;
+ String::FlatContent content = source->GetFlatContent();
+ DCHECK(content.IsFlat());
+ data =
+ content.IsOneByte()
+ ? reinterpret_cast<const void*>(content.ToOneByteVector().start())
+ : reinterpret_cast<const void*>(content.ToUC16Vector().start());
+ } else {
+ // Otherwise, create a copy of the part of the string we'll parse in the
+ // zone.
+ length = (shared_->end_position() - shared_->start_position());
+ offset = shared_->start_position();
+
+ int byte_len = length * (source->IsOneByteRepresentation() ? 1 : 2);
+ data = parse_info_->zone()->New(byte_len);
+
+ DisallowHeapAllocation no_allocation;
+ String::FlatContent content = source->GetFlatContent();
+ DCHECK(content.IsFlat());
+ if (content.IsOneByte()) {
+ MemCopy(const_cast<void*>(data),
+ &content.ToOneByteVector().at(shared_->start_position()),
+ byte_len);
+ } else {
+ MemCopy(const_cast<void*>(data),
+ &content.ToUC16Vector().at(shared_->start_position()),
+ byte_len);
+ }
+ }
+ Handle<String> wrapper;
+ if (source->IsOneByteRepresentation()) {
+ ExternalOneByteString::Resource* resource =
+ new OneByteWrapper(data, length);
+ source_wrapper_.reset(resource);
+ wrapper = isolate_->factory()
+ ->NewExternalStringFromOneByte(resource)
+ .ToHandleChecked();
+ } else {
+ ExternalTwoByteString::Resource* resource =
+ new TwoByteWrapper(data, length);
+ source_wrapper_.reset(resource);
+ wrapper = isolate_->factory()
+ ->NewExternalStringFromTwoByte(resource)
+ .ToHandleChecked();
+ }
+ wrapper_ =
+ Handle<String>::cast(isolate_->global_handles()->Create(*wrapper));
+
+ character_stream_.reset(
+ ScannerStream::For(wrapper_, shared_->start_position() - offset,
+ shared_->end_position() - offset));
}
- parse_info_.reset(new ParseInfo(zone_.get()));
parse_info_->set_isolate(isolate_);
parse_info_->set_character_stream(character_stream_.get());
parse_info_->set_hash_seed(isolate_->heap()->HashSeed());
@@ -76,14 +221,15 @@ void CompilerDispatcherJob::PrepareToParseOnMainThread() {
parse_info_->set_end_position(shared_->end_position());
parse_info_->set_unicode_cache(unicode_cache_.get());
parse_info_->set_language_mode(shared_->language_mode());
+ parse_info_->set_function_literal_id(shared_->function_literal_id());
parser_.reset(new Parser(parse_info_.get()));
- Handle<ScopeInfo> outer_scope_info(
- handle(ScopeInfo::cast(shared_->outer_scope_info())));
- parser_->DeserializeScopeChain(parse_info_.get(),
- outer_scope_info->length() > 0
- ? MaybeHandle<ScopeInfo>(outer_scope_info)
- : MaybeHandle<ScopeInfo>());
+ MaybeHandle<ScopeInfo> outer_scope_info;
+ if (!shared_->outer_scope_info()->IsTheHole(isolate_) &&
+ ScopeInfo::cast(shared_->outer_scope_info())->length() > 0) {
+ outer_scope_info = handle(ScopeInfo::cast(shared_->outer_scope_info()));
+ }
+ parser_->DeserializeScopeChain(parse_info_.get(), outer_scope_info);
Handle<String> name(String::cast(shared_->name()));
parse_info_->set_function_name(
@@ -92,21 +238,17 @@ void CompilerDispatcherJob::PrepareToParseOnMainThread() {
}
void CompilerDispatcherJob::Parse() {
- DCHECK(can_parse_on_background_thread_ ||
- ThreadId::Current().Equals(isolate_->thread_id()));
DCHECK(status() == CompileJobStatus::kReadyToParse);
COMPILER_DISPATCHER_TRACE_SCOPE_WITH_NUM(
tracer_, kParse,
parse_info_->end_position() - parse_info_->start_position());
+ if (trace_compiler_dispatcher_jobs_) {
+ PrintF("CompilerDispatcherJob[%p]: Parsing\n", static_cast<void*>(this));
+ }
DisallowHeapAllocation no_allocation;
DisallowHandleAllocation no_handles;
- std::unique_ptr<DisallowHandleDereference> no_deref;
- // If we can't parse on a background thread, we need to be able to deref the
- // source string.
- if (can_parse_on_background_thread_) {
- no_deref.reset(new DisallowHandleDereference());
- }
+ DisallowHandleDereference no_deref;
// Nullify the Isolate temporarily so that the parser doesn't accidentally
// use it.
@@ -126,33 +268,44 @@ bool CompilerDispatcherJob::FinalizeParsingOnMainThread() {
DCHECK(ThreadId::Current().Equals(isolate_->thread_id()));
DCHECK(status() == CompileJobStatus::kParsed);
COMPILER_DISPATCHER_TRACE_SCOPE(tracer_, kFinalizeParsing);
+ if (trace_compiler_dispatcher_jobs_) {
+ PrintF("CompilerDispatcherJob[%p]: Finalizing parsing\n",
+ static_cast<void*>(this));
+ }
if (!source_.is_null()) {
i::GlobalHandles::Destroy(Handle<Object>::cast(source_).location());
source_ = Handle<String>::null();
}
+ if (!wrapper_.is_null()) {
+ i::GlobalHandles::Destroy(Handle<Object>::cast(wrapper_).location());
+ 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::kReadyToAnalyse;
+ status_ = CompileJobStatus::kReadyToAnalyze;
}
+ parser_->UpdateStatistics(isolate_, script);
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::cast(shared_->outer_scope_info())));
- if (outer_scope_info->length() > 0) {
+ if (!shared_->outer_scope_info()->IsTheHole(isolate_) &&
+ ScopeInfo::cast(shared_->outer_scope_info())->length() > 0) {
+ Handle<ScopeInfo> outer_scope_info(
+ handle(ScopeInfo::cast(shared_->outer_scope_info())));
parse_info_->set_outer_scope_info(outer_scope_info);
}
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);
@@ -161,44 +314,61 @@ 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;
}
-bool CompilerDispatcherJob::PrepareToCompileOnMainThread() {
+bool CompilerDispatcherJob::AnalyzeOnMainThread() {
DCHECK(ThreadId::Current().Equals(isolate_->thread_id()));
- DCHECK(status() == CompileJobStatus::kReadyToAnalyse);
- COMPILER_DISPATCHER_TRACE_SCOPE(tracer_, kPrepareToCompile);
+ DCHECK(status() == CompileJobStatus::kReadyToAnalyze);
+ COMPILER_DISPATCHER_TRACE_SCOPE(tracer_, kAnalyze);
+ if (trace_compiler_dispatcher_jobs_) {
+ PrintF("CompilerDispatcherJob[%p]: Analyzing\n", static_cast<void*>(this));
+ }
- compile_info_.reset(
- new CompilationInfo(parse_info_.get(), Handle<JSFunction>::null()));
+ compile_info_.reset(new CompilationInfo(
+ parse_info_->zone(), parse_info_.get(), Handle<JSFunction>::null()));
DeferredHandleScope scope(isolate_);
- if (Compiler::Analyze(parse_info_.get())) {
- compile_job_.reset(
- Compiler::PrepareUnoptimizedCompilationJob(compile_info_.get()));
+ {
+ if (Compiler::Analyze(parse_info_.get())) {
+ status_ = CompileJobStatus::kAnalyzed;
+ } else {
+ status_ = CompileJobStatus::kFailed;
+ if (!isolate_->has_pending_exception()) isolate_->StackOverflow();
+ }
}
compile_info_->set_deferred_handles(scope.Detach());
+ return status_ != CompileJobStatus::kFailed;
+}
+
+bool CompilerDispatcherJob::PrepareToCompileOnMainThread() {
+ DCHECK(ThreadId::Current().Equals(isolate_->thread_id()));
+ DCHECK(status() == CompileJobStatus::kAnalyzed);
+ COMPILER_DISPATCHER_TRACE_SCOPE(tracer_, kPrepareToCompile);
+
+ compile_job_.reset(
+ Compiler::PrepareUnoptimizedCompilationJob(compile_info_.get()));
if (!compile_job_.get()) {
if (!isolate_->has_pending_exception()) isolate_->StackOverflow();
status_ = CompileJobStatus::kFailed;
return false;
}
- can_compile_on_background_thread_ =
- compile_job_->can_execute_on_background_thread();
+ CHECK(compile_job_->can_execute_on_background_thread());
status_ = CompileJobStatus::kReadyToCompile;
return true;
}
void CompilerDispatcherJob::Compile() {
DCHECK(status() == CompileJobStatus::kReadyToCompile);
- DCHECK(can_compile_on_background_thread_ ||
- ThreadId::Current().Equals(isolate_->thread_id()));
COMPILER_DISPATCHER_TRACE_SCOPE_WITH_NUM(
tracer_, kCompile, parse_info_->literal()->ast_node_count());
+ if (trace_compiler_dispatcher_jobs_) {
+ PrintF("CompilerDispatcherJob[%p]: Compiling\n", static_cast<void*>(this));
+ }
// Disallowing of handle dereference and heap access dealt with in
// CompilationJob::ExecuteJob.
@@ -218,19 +388,25 @@ bool CompilerDispatcherJob::FinalizeCompilingOnMainThread() {
DCHECK(ThreadId::Current().Equals(isolate_->thread_id()));
DCHECK(status() == CompileJobStatus::kCompiled);
COMPILER_DISPATCHER_TRACE_SCOPE(tracer_, kFinalizeCompiling);
+ if (trace_compiler_dispatcher_jobs_) {
+ PrintF("CompilerDispatcherJob[%p]: Finalizing compiling\n",
+ static_cast<void*>(this));
+ }
- if (compile_job_->state() == CompilationJob::State::kFailed ||
- !Compiler::FinalizeCompilationJob(compile_job_.release())) {
- if (!isolate_->has_pending_exception()) isolate_->StackOverflow();
- status_ = CompileJobStatus::kFailed;
- return false;
+ {
+ HandleScope scope(isolate_);
+ if (compile_job_->state() == CompilationJob::State::kFailed ||
+ !Compiler::FinalizeCompilationJob(compile_job_.release())) {
+ if (!isolate_->has_pending_exception()) isolate_->StackOverflow();
+ status_ = CompileJobStatus::kFailed;
+ return false;
+ }
}
- zone_.reset();
- parse_info_.reset();
- compile_info_.reset();
compile_job_.reset();
- handles_from_parsing_.reset();
+ compile_info_.reset();
+ parse_zone_.reset();
+ parse_info_.reset();
status_ = CompileJobStatus::kDone;
return true;
@@ -239,22 +415,68 @@ bool CompilerDispatcherJob::FinalizeCompilingOnMainThread() {
void CompilerDispatcherJob::ResetOnMainThread() {
DCHECK(ThreadId::Current().Equals(isolate_->thread_id()));
+ if (trace_compiler_dispatcher_jobs_) {
+ PrintF("CompilerDispatcherJob[%p]: Resetting\n", static_cast<void*>(this));
+ }
+
+ compile_job_.reset();
+ compile_info_.reset();
+ parse_zone_.reset();
parser_.reset();
unicode_cache_.reset();
character_stream_.reset();
parse_info_.reset();
- zone_.reset();
- handles_from_parsing_.reset();
- compile_info_.reset();
- compile_job_.reset();
if (!source_.is_null()) {
i::GlobalHandles::Destroy(Handle<Object>::cast(source_).location());
source_ = Handle<String>::null();
}
+ if (!wrapper_.is_null()) {
+ i::GlobalHandles::Destroy(Handle<Object>::cast(wrapper_).location());
+ wrapper_ = Handle<String>::null();
+ }
status_ = CompileJobStatus::kInitial;
}
+double CompilerDispatcherJob::EstimateRuntimeOfNextStepInMs() const {
+ switch (status_) {
+ case CompileJobStatus::kInitial:
+ return tracer_->EstimatePrepareToParseInMs();
+
+ case CompileJobStatus::kReadyToParse:
+ return tracer_->EstimateParseInMs(parse_info_->end_position() -
+ parse_info_->start_position());
+
+ case CompileJobStatus::kParsed:
+ return tracer_->EstimateFinalizeParsingInMs();
+
+ case CompileJobStatus::kReadyToAnalyze:
+ return tracer_->EstimateAnalyzeInMs();
+
+ case CompileJobStatus::kAnalyzed:
+ return tracer_->EstimatePrepareToCompileInMs();
+
+ case CompileJobStatus::kReadyToCompile:
+ return tracer_->EstimateCompileInMs(
+ parse_info_->literal()->ast_node_count());
+
+ case CompileJobStatus::kCompiled:
+ return tracer_->EstimateFinalizeCompilingInMs();
+
+ case CompileJobStatus::kFailed:
+ case CompileJobStatus::kDone:
+ return 0.0;
+ }
+
+ UNREACHABLE();
+ return 0.0;
+}
+
+void CompilerDispatcherJob::ShortPrint() {
+ DCHECK(ThreadId::Current().Equals(isolate_->thread_id()));
+ shared_->ShortPrint();
+}
+
} // namespace internal
} // namespace v8