[compiler-dispatcher] Make compiler jobs abstract
Makes compiler dispatcher jobs an abstract interface, with unoptimized compile jobs as an implementation of this interface. Bug: v8:6537 Change-Id: I6569060a89c92d35e4bc7962623f77082a354934 Reviewed-on: https://chromium-review.googlesource.com/558290 Reviewed-by: Georg Neis <neis@chromium.org> Reviewed-by: Ross McIlroy <rmcilroy@chromium.org> Commit-Queue: Leszek Swirski <leszeks@chromium.org> Cr-Commit-Position: refs/heads/master@{#46931}
This commit is contained in:
parent
6a75fcd4df
commit
e4bbf92be3
2
BUILD.gn
2
BUILD.gn
@ -1246,6 +1246,8 @@ v8_source_set("v8_base") {
|
||||
"src/compiler-dispatcher/compiler-dispatcher.h",
|
||||
"src/compiler-dispatcher/optimizing-compile-dispatcher.cc",
|
||||
"src/compiler-dispatcher/optimizing-compile-dispatcher.h",
|
||||
"src/compiler-dispatcher/unoptimized-compile-job.cc",
|
||||
"src/compiler-dispatcher/unoptimized-compile-job.h",
|
||||
"src/compiler.cc",
|
||||
"src/compiler.h",
|
||||
"src/compiler/access-builder.cc",
|
||||
|
@ -4,572 +4,15 @@
|
||||
|
||||
#include "src/compiler-dispatcher/compiler-dispatcher-job.h"
|
||||
|
||||
#include "src/assert-scope.h"
|
||||
#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"
|
||||
#include "src/parsing/parse-info.h"
|
||||
#include "src/parsing/parser.h"
|
||||
#include "src/parsing/scanner-character-streams.h"
|
||||
#include "src/unicode-cache.h"
|
||||
#include "src/utils.h"
|
||||
#include "src/compiler-dispatcher/unoptimized-compile-job.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(
|
||||
CompilerDispatcherTracer* tracer, size_t max_stack_size,
|
||||
Handle<String> source, int start_position, int end_position,
|
||||
LanguageMode language_mode, int function_literal_id, bool native,
|
||||
bool module, bool is_named_expression, uint32_t hash_seed,
|
||||
AccountingAllocator* zone_allocator, int compiler_hints,
|
||||
const AstStringConstants* ast_string_constants,
|
||||
CompileJobFinishCallback* finish_callback)
|
||||
: status_(CompileJobStatus::kReadyToParse),
|
||||
isolate_(nullptr),
|
||||
tracer_(tracer),
|
||||
max_stack_size_(max_stack_size),
|
||||
finish_callback_(finish_callback),
|
||||
trace_compiler_dispatcher_jobs_(FLAG_trace_compiler_dispatcher_jobs) {
|
||||
parse_info_.reset(new ParseInfo(zone_allocator));
|
||||
DCHECK(source->IsExternalTwoByteString() ||
|
||||
source->IsExternalOneByteString());
|
||||
character_stream_.reset(
|
||||
ScannerStream::For(source, start_position, end_position));
|
||||
parse_info_->set_character_stream(character_stream_.get());
|
||||
parse_info_->set_hash_seed(hash_seed);
|
||||
parse_info_->set_compiler_hints(compiler_hints);
|
||||
parse_info_->set_start_position(start_position);
|
||||
parse_info_->set_end_position(end_position);
|
||||
unicode_cache_.reset(new UnicodeCache());
|
||||
parse_info_->set_unicode_cache(unicode_cache_.get());
|
||||
parse_info_->set_language_mode(language_mode);
|
||||
parse_info_->set_function_literal_id(function_literal_id);
|
||||
parse_info_->set_ast_string_constants(ast_string_constants);
|
||||
if (V8_UNLIKELY(FLAG_runtime_stats)) {
|
||||
parse_info_->set_runtime_call_stats(new (parse_info_->zone())
|
||||
RuntimeCallStats());
|
||||
}
|
||||
|
||||
parse_info_->set_native(native);
|
||||
parse_info_->set_module(module);
|
||||
parse_info_->set_is_named_expression(is_named_expression);
|
||||
|
||||
parser_.reset(new Parser(parse_info_.get()));
|
||||
parser_->DeserializeScopeChain(parse_info_.get(), MaybeHandle<ScopeInfo>());
|
||||
|
||||
if (trace_compiler_dispatcher_jobs_) {
|
||||
PrintF("CompilerDispatcherJob[%p] created for ", static_cast<void*>(this));
|
||||
ShortPrint();
|
||||
PrintF(" in ready to parse state.\n");
|
||||
}
|
||||
}
|
||||
|
||||
CompilerDispatcherJob::CompilerDispatcherJob(Isolate* isolate,
|
||||
CompilerDispatcherTracer* tracer,
|
||||
Handle<SharedFunctionInfo> shared,
|
||||
size_t max_stack_size)
|
||||
: status_(CompileJobStatus::kInitial),
|
||||
isolate_(isolate),
|
||||
tracer_(tracer),
|
||||
context_(isolate_->global_handles()->Create(isolate->context())),
|
||||
shared_(isolate_->global_handles()->Create(*shared)),
|
||||
max_stack_size_(max_stack_size),
|
||||
trace_compiler_dispatcher_jobs_(FLAG_trace_compiler_dispatcher_jobs) {
|
||||
DCHECK(!shared_->is_toplevel());
|
||||
HandleScope scope(isolate_);
|
||||
Handle<Script> script(Script::cast(shared_->script()), isolate_);
|
||||
Handle<String> source(String::cast(script->source()), isolate_);
|
||||
if (trace_compiler_dispatcher_jobs_) {
|
||||
PrintF("CompilerDispatcherJob[%p] created for ", static_cast<void*>(this));
|
||||
ShortPrint();
|
||||
PrintF(" in initial state.\n");
|
||||
}
|
||||
}
|
||||
|
||||
CompilerDispatcherJob::CompilerDispatcherJob(
|
||||
Isolate* isolate, CompilerDispatcherTracer* tracer, Handle<Script> script,
|
||||
Handle<SharedFunctionInfo> shared, FunctionLiteral* literal,
|
||||
ParseInfo* outer_parse_info,
|
||||
std::shared_ptr<DeferredHandles> compile_handles, size_t max_stack_size)
|
||||
: status_(CompileJobStatus::kAnalyzed),
|
||||
isolate_(isolate),
|
||||
tracer_(tracer),
|
||||
context_(isolate_->global_handles()->Create(isolate->context())),
|
||||
shared_(isolate_->global_handles()->Create(*shared)),
|
||||
max_stack_size_(max_stack_size),
|
||||
parse_info_(new ParseInfo(shared_)),
|
||||
compile_zone_(new Zone(isolate->allocator(), ZONE_NAME)),
|
||||
compile_info_(new CompilationInfo(compile_zone_.get(), parse_info_.get(),
|
||||
isolate_, shared_,
|
||||
Handle<JSFunction>::null())),
|
||||
trace_compiler_dispatcher_jobs_(FLAG_trace_compiler_dispatcher_jobs) {
|
||||
parse_info_->set_literal(literal);
|
||||
parse_info_->set_script(script);
|
||||
parse_info_->ShareAstValueFactory(outer_parse_info);
|
||||
parse_info_->ShareZone(outer_parse_info);
|
||||
compile_info_->set_deferred_handles(compile_handles);
|
||||
|
||||
if (trace_compiler_dispatcher_jobs_) {
|
||||
PrintF("CompilerDispatcherJob[%p] created for ", static_cast<void*>(this));
|
||||
ShortPrint();
|
||||
PrintF(" in Analyzed state.\n");
|
||||
}
|
||||
}
|
||||
|
||||
CompilerDispatcherJob::~CompilerDispatcherJob() {
|
||||
DCHECK(status_ == CompileJobStatus::kInitial ||
|
||||
(status_ == CompileJobStatus::kReadyToParse && finish_callback_) ||
|
||||
status_ == CompileJobStatus::kDone);
|
||||
if (!shared_.is_null()) {
|
||||
DCHECK(ThreadId::Current().Equals(isolate_->thread_id()));
|
||||
i::GlobalHandles::Destroy(Handle<Object>::cast(shared_).location());
|
||||
}
|
||||
if (!context_.is_null()) {
|
||||
DCHECK(ThreadId::Current().Equals(isolate_->thread_id()));
|
||||
i::GlobalHandles::Destroy(Handle<Object>::cast(context_).location());
|
||||
}
|
||||
}
|
||||
|
||||
bool CompilerDispatcherJob::IsAssociatedWith(
|
||||
Handle<SharedFunctionInfo> shared) const {
|
||||
return *shared_ == *shared;
|
||||
}
|
||||
|
||||
void CompilerDispatcherJob::StepNextOnMainThread() {
|
||||
switch (status()) {
|
||||
case CompileJobStatus::kInitial:
|
||||
return PrepareToParseOnMainThread();
|
||||
|
||||
case CompileJobStatus::kReadyToParse:
|
||||
return Parse();
|
||||
|
||||
case CompileJobStatus::kParsed:
|
||||
return FinalizeParsingOnMainThread();
|
||||
|
||||
case CompileJobStatus::kReadyToAnalyze:
|
||||
return AnalyzeOnMainThread();
|
||||
|
||||
case CompileJobStatus::kAnalyzed:
|
||||
return PrepareToCompileOnMainThread();
|
||||
|
||||
case CompileJobStatus::kReadyToCompile:
|
||||
return Compile();
|
||||
|
||||
case CompileJobStatus::kCompiled:
|
||||
return FinalizeCompilingOnMainThread();
|
||||
|
||||
case CompileJobStatus::kFailed:
|
||||
case CompileJobStatus::kDone:
|
||||
return;
|
||||
}
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
void CompilerDispatcherJob::StepNextOnBackgroundThread() {
|
||||
DCHECK(CanStepNextOnAnyThread());
|
||||
switch (status()) {
|
||||
case CompileJobStatus::kReadyToParse:
|
||||
return Parse();
|
||||
|
||||
case CompileJobStatus::kReadyToCompile:
|
||||
return Compile();
|
||||
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
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());
|
||||
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);
|
||||
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_ = 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_ = isolate_->global_handles()->Create(*wrapper);
|
||||
|
||||
character_stream_.reset(
|
||||
ScannerStream::For(wrapper_, shared_->start_position() - offset,
|
||||
shared_->end_position() - offset));
|
||||
}
|
||||
parse_info_->InitFromIsolate(isolate_);
|
||||
parse_info_->set_character_stream(character_stream_.get());
|
||||
parse_info_->set_hash_seed(isolate_->heap()->HashSeed());
|
||||
parse_info_->set_is_named_expression(shared_->is_named_expression());
|
||||
parse_info_->set_compiler_hints(shared_->compiler_hints());
|
||||
parse_info_->set_start_position(shared_->start_position());
|
||||
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());
|
||||
if (V8_UNLIKELY(FLAG_runtime_stats)) {
|
||||
parse_info_->set_runtime_call_stats(new (parse_info_->zone())
|
||||
RuntimeCallStats());
|
||||
}
|
||||
|
||||
parser_.reset(new Parser(parse_info_.get()));
|
||||
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(shared_->name());
|
||||
parse_info_->set_function_name(
|
||||
parse_info_->ast_value_factory()->GetString(name));
|
||||
status_ = CompileJobStatus::kReadyToParse;
|
||||
}
|
||||
|
||||
void CompilerDispatcherJob::Parse() {
|
||||
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;
|
||||
DisallowHandleDereference no_deref;
|
||||
|
||||
uintptr_t stack_limit = GetCurrentStackPosition() - max_stack_size_ * KB;
|
||||
|
||||
parser_->set_stack_limit(stack_limit);
|
||||
parser_->ParseOnBackground(parse_info_.get());
|
||||
|
||||
if (finish_callback_) {
|
||||
finish_callback_->ParseFinished(std::move(parse_info_));
|
||||
status_ = CompileJobStatus::kDone;
|
||||
} else {
|
||||
status_ = CompileJobStatus::kParsed;
|
||||
}
|
||||
}
|
||||
|
||||
void 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::kReadyToAnalyze;
|
||||
}
|
||||
parser_->UpdateStatistics(isolate_, script);
|
||||
parse_info_->UpdateStatisticsAfterBackgroundParse(isolate_);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
parser_->HandleSourceURLComments(isolate_, script);
|
||||
|
||||
parse_info_->set_character_stream(nullptr);
|
||||
parse_info_->set_unicode_cache(nullptr);
|
||||
parser_.reset();
|
||||
unicode_cache_.reset();
|
||||
character_stream_.reset();
|
||||
}
|
||||
|
||||
void CompilerDispatcherJob::AnalyzeOnMainThread() {
|
||||
DCHECK(ThreadId::Current().Equals(isolate_->thread_id()));
|
||||
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_zone_.reset(new Zone(isolate_->allocator(), ZONE_NAME));
|
||||
compile_info_.reset(new CompilationInfo(
|
||||
compile_zone_.get(), parse_info_.get(), isolate_,
|
||||
Handle<SharedFunctionInfo>::null(), Handle<JSFunction>::null()));
|
||||
|
||||
DeferredHandleScope scope(isolate_);
|
||||
{
|
||||
if (Compiler::Analyze(compile_info_.get())) {
|
||||
status_ = CompileJobStatus::kAnalyzed;
|
||||
} else {
|
||||
status_ = CompileJobStatus::kFailed;
|
||||
if (!isolate_->has_pending_exception()) isolate_->StackOverflow();
|
||||
}
|
||||
}
|
||||
compile_info_->set_deferred_handles(scope.Detach());
|
||||
}
|
||||
|
||||
void 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;
|
||||
}
|
||||
|
||||
CHECK(compile_job_->can_execute_on_background_thread());
|
||||
status_ = CompileJobStatus::kReadyToCompile;
|
||||
}
|
||||
|
||||
void CompilerDispatcherJob::Compile() {
|
||||
DCHECK(status() == CompileJobStatus::kReadyToCompile);
|
||||
COMPILER_DISPATCHER_TRACE_SCOPE(tracer_, kCompile);
|
||||
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.
|
||||
|
||||
uintptr_t stack_limit = GetCurrentStackPosition() - max_stack_size_ * KB;
|
||||
compile_job_->set_stack_limit(stack_limit);
|
||||
|
||||
CompilationJob::Status status = compile_job_->ExecuteJob();
|
||||
USE(status);
|
||||
|
||||
// Always transition to kCompiled - errors will be reported by
|
||||
// FinalizeCompilingOnMainThread.
|
||||
status_ = CompileJobStatus::kCompiled;
|
||||
}
|
||||
|
||||
void 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));
|
||||
}
|
||||
|
||||
{
|
||||
HandleScope scope(isolate_);
|
||||
|
||||
compile_info_->set_shared_info(shared_);
|
||||
if (compile_job_->state() == CompilationJob::State::kFailed ||
|
||||
!Compiler::FinalizeCompilationJob(compile_job_.release())) {
|
||||
if (!isolate_->has_pending_exception()) isolate_->StackOverflow();
|
||||
status_ = CompileJobStatus::kFailed;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
compile_job_.reset();
|
||||
compile_info_.reset();
|
||||
compile_zone_.reset();
|
||||
parse_info_.reset();
|
||||
|
||||
status_ = CompileJobStatus::kDone;
|
||||
}
|
||||
|
||||
void CompilerDispatcherJob::ResetOnMainThread() {
|
||||
if (trace_compiler_dispatcher_jobs_) {
|
||||
PrintF("CompilerDispatcherJob[%p]: Resetting\n", static_cast<void*>(this));
|
||||
}
|
||||
|
||||
compile_job_.reset();
|
||||
compile_info_.reset();
|
||||
compile_zone_.reset();
|
||||
parser_.reset();
|
||||
unicode_cache_.reset();
|
||||
character_stream_.reset();
|
||||
parse_info_.reset();
|
||||
finish_callback_ = nullptr;
|
||||
|
||||
if (!source_.is_null()) {
|
||||
DCHECK(ThreadId::Current().Equals(isolate_->thread_id()));
|
||||
i::GlobalHandles::Destroy(Handle<Object>::cast(source_).location());
|
||||
source_ = Handle<String>::null();
|
||||
}
|
||||
if (!wrapper_.is_null()) {
|
||||
DCHECK(ThreadId::Current().Equals(isolate_->thread_id()));
|
||||
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();
|
||||
|
||||
case CompileJobStatus::kCompiled:
|
||||
return tracer_->EstimateFinalizeCompilingInMs();
|
||||
|
||||
case CompileJobStatus::kFailed:
|
||||
case CompileJobStatus::kDone:
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
void CompilerDispatcherJob::ShortPrint() {
|
||||
if (isolate_) {
|
||||
DCHECK(ThreadId::Current().Equals(isolate_->thread_id()));
|
||||
DCHECK(!shared_.is_null());
|
||||
shared_->ShortPrint();
|
||||
} else {
|
||||
// TODO(wiktorg) more useful info in those cases
|
||||
if (parse_info_) {
|
||||
PrintF("function at %d", parse_info_->start_position());
|
||||
} else {
|
||||
PrintF("parsed function");
|
||||
}
|
||||
}
|
||||
const UnoptimizedCompileJob* CompilerDispatcherJob::AsUnoptimizedCompileJob()
|
||||
const {
|
||||
DCHECK_EQ(type(), kUnoptimizedCompile);
|
||||
return static_cast<const UnoptimizedCompileJob*>(this);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
@ -5,168 +5,54 @@
|
||||
#ifndef V8_COMPILER_DISPATCHER_COMPILER_DISPATCHER_JOB_H_
|
||||
#define V8_COMPILER_DISPATCHER_COMPILER_DISPATCHER_JOB_H_
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "include/v8.h"
|
||||
#include "src/base/macros.h"
|
||||
#include "src/globals.h"
|
||||
#include "src/contexts.h"
|
||||
#include "src/handles.h"
|
||||
#include "testing/gtest/include/gtest/gtest_prod.h" // nogncheck
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
class AstValueFactory;
|
||||
class AstStringConstants;
|
||||
class CompilerDispatcherTracer;
|
||||
class CompilationInfo;
|
||||
class CompilationJob;
|
||||
class DeferredHandles;
|
||||
class FunctionLiteral;
|
||||
class Isolate;
|
||||
class ParseInfo;
|
||||
class Parser;
|
||||
class SharedFunctionInfo;
|
||||
class String;
|
||||
class UnicodeCache;
|
||||
class Utf16CharacterStream;
|
||||
|
||||
enum class CompileJobStatus {
|
||||
kInitial,
|
||||
kReadyToParse,
|
||||
kParsed,
|
||||
kReadyToAnalyze,
|
||||
kAnalyzed,
|
||||
kReadyToCompile,
|
||||
kCompiled,
|
||||
kFailed,
|
||||
kDone,
|
||||
};
|
||||
|
||||
class V8_EXPORT_PRIVATE CompileJobFinishCallback {
|
||||
public:
|
||||
virtual ~CompileJobFinishCallback() {}
|
||||
virtual void ParseFinished(std::unique_ptr<ParseInfo> parse_info) = 0;
|
||||
};
|
||||
class UnoptimizedCompileJob;
|
||||
|
||||
class V8_EXPORT_PRIVATE CompilerDispatcherJob {
|
||||
public:
|
||||
// Creates a CompilerDispatcherJob in the initial state.
|
||||
CompilerDispatcherJob(Isolate* isolate, CompilerDispatcherTracer* tracer,
|
||||
Handle<SharedFunctionInfo> shared,
|
||||
size_t max_stack_size);
|
||||
// TODO(wiktorg) document it better once I know how it relates to whole stuff
|
||||
// Creates a CompilerDispatcherJob in ready to parse top-level function state.
|
||||
CompilerDispatcherJob(CompilerDispatcherTracer* tracer, size_t max_stack_size,
|
||||
Handle<String> source, int start_position,
|
||||
int end_position, LanguageMode language_mode,
|
||||
int function_literal_id, bool native, bool module,
|
||||
bool is_named_expression, uint32_t hash_seed,
|
||||
AccountingAllocator* zone_allocator, int compiler_hints,
|
||||
const AstStringConstants* ast_string_constants,
|
||||
CompileJobFinishCallback* finish_callback);
|
||||
// Creates a CompilerDispatcherJob in the analyzed state.
|
||||
CompilerDispatcherJob(Isolate* isolate, CompilerDispatcherTracer* tracer,
|
||||
Handle<Script> script,
|
||||
Handle<SharedFunctionInfo> shared,
|
||||
FunctionLiteral* literal, ParseInfo* outer_parse_info,
|
||||
std::shared_ptr<DeferredHandles> compile_handles,
|
||||
size_t max_stack_size);
|
||||
~CompilerDispatcherJob();
|
||||
enum Type { kUnoptimizedCompile };
|
||||
|
||||
bool has_context() const { return !context_.is_null(); }
|
||||
Context* context() { return *context_; }
|
||||
virtual ~CompilerDispatcherJob() {}
|
||||
|
||||
Handle<SharedFunctionInfo> shared() const { return shared_; }
|
||||
virtual Type type() const = 0;
|
||||
|
||||
// Returns true if this CompilerDispatcherJob was created for the given
|
||||
// function.
|
||||
bool IsAssociatedWith(Handle<SharedFunctionInfo> shared) const;
|
||||
// Returns true if this CompilerDispatcherJob has finished (either with a
|
||||
// success or a failure).
|
||||
virtual bool IsFinished() = 0;
|
||||
|
||||
bool IsFinished() {
|
||||
return status() == CompileJobStatus::kDone ||
|
||||
status() == CompileJobStatus::kFailed;
|
||||
}
|
||||
|
||||
bool IsFailed() { return status() == CompileJobStatus::kFailed; }
|
||||
// Returns true if this CompilerDispatcherJob has failed.
|
||||
virtual bool IsFailed() = 0;
|
||||
|
||||
// Return true if the next step can be run on any thread, that is when both
|
||||
// StepNextOnMainThread and StepNextOnBackgroundThread could be used for the
|
||||
// next step.
|
||||
bool CanStepNextOnAnyThread() {
|
||||
return status() == CompileJobStatus::kReadyToParse ||
|
||||
status() == CompileJobStatus::kReadyToCompile;
|
||||
}
|
||||
virtual bool CanStepNextOnAnyThread() = 0;
|
||||
|
||||
// Step the job forward by one state on the main thread.
|
||||
void StepNextOnMainThread();
|
||||
virtual void StepNextOnMainThread() = 0;
|
||||
|
||||
// Step the job forward by one state on a background thread.
|
||||
void StepNextOnBackgroundThread();
|
||||
virtual void StepNextOnBackgroundThread() = 0;
|
||||
|
||||
// Transition from any state to kInitial and free all resources.
|
||||
void ResetOnMainThread();
|
||||
virtual void ResetOnMainThread() = 0;
|
||||
|
||||
// Estimate how long the next step will take using the tracer.
|
||||
double EstimateRuntimeOfNextStepInMs() const;
|
||||
virtual double EstimateRuntimeOfNextStepInMs() const = 0;
|
||||
|
||||
// Even though the name does not imply this, ShortPrint() must only be invoked
|
||||
// on the main thread.
|
||||
void ShortPrint();
|
||||
virtual void ShortPrint() = 0;
|
||||
|
||||
private:
|
||||
friend class CompilerDispatcherTest;
|
||||
friend class CompilerDispatcherJobTest;
|
||||
|
||||
CompileJobStatus status() const { return status_; }
|
||||
|
||||
CompileJobStatus status_;
|
||||
Isolate* isolate_;
|
||||
CompilerDispatcherTracer* tracer_;
|
||||
Handle<Context> context_; // Global handle.
|
||||
Handle<SharedFunctionInfo> shared_; // Global handle.
|
||||
Handle<String> source_; // Global handle.
|
||||
Handle<String> wrapper_; // Global handle.
|
||||
std::unique_ptr<v8::String::ExternalStringResourceBase> source_wrapper_;
|
||||
size_t max_stack_size_;
|
||||
CompileJobFinishCallback* finish_callback_ = nullptr;
|
||||
|
||||
// Members required for parsing.
|
||||
std::unique_ptr<UnicodeCache> unicode_cache_;
|
||||
std::unique_ptr<Utf16CharacterStream> character_stream_;
|
||||
std::unique_ptr<ParseInfo> parse_info_;
|
||||
std::unique_ptr<Parser> parser_;
|
||||
|
||||
// Members required for compiling.
|
||||
std::unique_ptr<Zone> compile_zone_;
|
||||
std::unique_ptr<CompilationInfo> compile_info_;
|
||||
std::unique_ptr<CompilationJob> compile_job_;
|
||||
|
||||
bool trace_compiler_dispatcher_jobs_;
|
||||
|
||||
// Transition from kInitial to kReadyToParse.
|
||||
void PrepareToParseOnMainThread();
|
||||
|
||||
// Transition from kReadyToParse to kParsed (or kDone if there is
|
||||
// finish_callback).
|
||||
void Parse();
|
||||
|
||||
// Transition from kParsed to kReadyToAnalyze (or kFailed).
|
||||
void FinalizeParsingOnMainThread();
|
||||
|
||||
// Transition from kReadyToAnalyze to kAnalyzed (or kFailed).
|
||||
void AnalyzeOnMainThread();
|
||||
|
||||
// Transition from kAnalyzed to kReadyToCompile (or kFailed).
|
||||
void PrepareToCompileOnMainThread();
|
||||
|
||||
// Transition from kReadyToCompile to kCompiled.
|
||||
void Compile();
|
||||
|
||||
// Transition from kCompiled to kDone (or kFailed).
|
||||
void FinalizeCompilingOnMainThread();
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(CompilerDispatcherJob);
|
||||
// Casts to implementations.
|
||||
const UnoptimizedCompileJob* AsUnoptimizedCompileJob() const;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "src/compilation-info.h"
|
||||
#include "src/compiler-dispatcher/compiler-dispatcher-job.h"
|
||||
#include "src/compiler-dispatcher/compiler-dispatcher-tracer.h"
|
||||
#include "src/compiler-dispatcher/unoptimized-compile-job.h"
|
||||
#include "src/flags.h"
|
||||
#include "src/objects-inl.h"
|
||||
|
||||
@ -26,15 +27,6 @@ bool DoNextStepOnMainThread(Isolate* isolate, CompilerDispatcherJob* job,
|
||||
DCHECK(ThreadId::Current().Equals(isolate->thread_id()));
|
||||
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
|
||||
"V8.CompilerDispatcherForgroundStep");
|
||||
|
||||
// Ensure we are in the correct context for the job.
|
||||
SaveContext save(isolate);
|
||||
if (job->has_context()) {
|
||||
isolate->set_context(job->context());
|
||||
} else {
|
||||
DCHECK(job->CanStepNextOnAnyThread());
|
||||
}
|
||||
|
||||
job->StepNextOnMainThread();
|
||||
|
||||
DCHECK_EQ(job->IsFailed(), isolate->has_pending_exception());
|
||||
@ -170,7 +162,7 @@ CompilerDispatcher::CompilerDispatcher(Isolate* isolate, Platform* platform,
|
||||
tracer_(new CompilerDispatcherTracer(isolate_)),
|
||||
task_manager_(new CancelableTaskManager()),
|
||||
next_job_id_(0),
|
||||
shared_to_job_id_(isolate->heap()),
|
||||
shared_to_unoptimized_job_id_(isolate->heap()),
|
||||
memory_pressure_level_(MemoryPressureLevel::kNone),
|
||||
abort_(false),
|
||||
idle_task_scheduled_(false),
|
||||
@ -222,14 +214,7 @@ bool CompilerDispatcher::CanEnqueue(Handle<SharedFunctionInfo> function) {
|
||||
CompilerDispatcher::JobId CompilerDispatcher::Enqueue(
|
||||
std::unique_ptr<CompilerDispatcherJob> job) {
|
||||
DCHECK(!job->IsFinished());
|
||||
bool added;
|
||||
JobMap::const_iterator it;
|
||||
std::tie(it, added) =
|
||||
jobs_.insert(std::make_pair(next_job_id_++, std::move(job)));
|
||||
DCHECK(added);
|
||||
if (!it->second->shared().is_null()) {
|
||||
shared_to_job_id_.Set(it->second->shared(), it->first);
|
||||
}
|
||||
JobMap::const_iterator it = InsertJob(std::move(job));
|
||||
ConsiderJobForBackgroundProcessing(it->second.get());
|
||||
ScheduleIdleTaskIfNeeded();
|
||||
return it->first;
|
||||
@ -238,15 +223,7 @@ CompilerDispatcher::JobId CompilerDispatcher::Enqueue(
|
||||
CompilerDispatcher::JobId CompilerDispatcher::EnqueueAndStep(
|
||||
std::unique_ptr<CompilerDispatcherJob> job) {
|
||||
DCHECK(!job->IsFinished());
|
||||
bool added;
|
||||
JobMap::const_iterator it;
|
||||
std::tie(it, added) =
|
||||
jobs_.insert(std::make_pair(next_job_id_++, std::move(job)));
|
||||
DCHECK(added);
|
||||
if (!it->second->shared().is_null()) {
|
||||
shared_to_job_id_.Set(it->second->shared(), it->first);
|
||||
}
|
||||
JobId id = it->first;
|
||||
JobMap::const_iterator it = InsertJob(std::move(job));
|
||||
if (trace_compiler_dispatcher_) {
|
||||
PrintF("CompilerDispatcher: stepping ");
|
||||
it->second->ShortPrint();
|
||||
@ -257,7 +234,7 @@ CompilerDispatcher::JobId CompilerDispatcher::EnqueueAndStep(
|
||||
ConsiderJobForBackgroundProcessing(it->second.get());
|
||||
RemoveIfFinished(it);
|
||||
ScheduleIdleTaskIfNeeded();
|
||||
return id;
|
||||
return it->first;
|
||||
}
|
||||
|
||||
bool CompilerDispatcher::Enqueue(Handle<SharedFunctionInfo> function) {
|
||||
@ -272,19 +249,17 @@ bool CompilerDispatcher::Enqueue(Handle<SharedFunctionInfo> function) {
|
||||
PrintF(" for parse and compile\n");
|
||||
}
|
||||
|
||||
std::unique_ptr<CompilerDispatcherJob> job(new CompilerDispatcherJob(
|
||||
std::unique_ptr<CompilerDispatcherJob> job(new UnoptimizedCompileJob(
|
||||
isolate_, tracer_.get(), function, max_stack_size_));
|
||||
Enqueue(std::move(job));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CompilerDispatcher::Enqueue(Handle<String> source, int start_position,
|
||||
int end_position, LanguageMode language_mode,
|
||||
int function_literal_id, bool native,
|
||||
bool module, bool is_named_expression,
|
||||
int compiler_hints,
|
||||
CompileJobFinishCallback* finish_callback,
|
||||
JobId* job_id) {
|
||||
bool CompilerDispatcher::Enqueue(
|
||||
Handle<String> source, int start_position, int end_position,
|
||||
LanguageMode language_mode, int function_literal_id, bool native,
|
||||
bool module, bool is_named_expression, int compiler_hints,
|
||||
UnoptimizedCompileJobFinishCallback* finish_callback, JobId* job_id) {
|
||||
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
|
||||
"V8.CompilerDispatcherEnqueue");
|
||||
if (!CanEnqueue()) return false;
|
||||
@ -294,7 +269,7 @@ bool CompilerDispatcher::Enqueue(Handle<String> source, int start_position,
|
||||
start_position);
|
||||
}
|
||||
|
||||
std::unique_ptr<CompilerDispatcherJob> job(new CompilerDispatcherJob(
|
||||
std::unique_ptr<CompilerDispatcherJob> job(new UnoptimizedCompileJob(
|
||||
tracer_.get(), max_stack_size_, source, start_position, end_position,
|
||||
language_mode, function_literal_id, native, module, is_named_expression,
|
||||
isolate_->heap()->HashSeed(), isolate_->allocator(), compiler_hints,
|
||||
@ -318,7 +293,7 @@ bool CompilerDispatcher::EnqueueAndStep(Handle<SharedFunctionInfo> function) {
|
||||
PrintF(" for parse and compile\n");
|
||||
}
|
||||
|
||||
std::unique_ptr<CompilerDispatcherJob> job(new CompilerDispatcherJob(
|
||||
std::unique_ptr<CompilerDispatcherJob> job(new UnoptimizedCompileJob(
|
||||
isolate_, tracer_.get(), function, max_stack_size_));
|
||||
EnqueueAndStep(std::move(job));
|
||||
return true;
|
||||
@ -339,7 +314,7 @@ bool CompilerDispatcher::Enqueue(
|
||||
PrintF(" for compile\n");
|
||||
}
|
||||
|
||||
std::unique_ptr<CompilerDispatcherJob> job(new CompilerDispatcherJob(
|
||||
std::unique_ptr<CompilerDispatcherJob> job(new UnoptimizedCompileJob(
|
||||
isolate_, tracer_.get(), script, function, literal, outer_parse_info,
|
||||
compile_handles, max_stack_size_));
|
||||
Enqueue(std::move(job));
|
||||
@ -361,7 +336,7 @@ bool CompilerDispatcher::EnqueueAndStep(
|
||||
PrintF(" for compile\n");
|
||||
}
|
||||
|
||||
std::unique_ptr<CompilerDispatcherJob> job(new CompilerDispatcherJob(
|
||||
std::unique_ptr<CompilerDispatcherJob> job(new UnoptimizedCompileJob(
|
||||
isolate_, tracer_.get(), script, function, literal, outer_parse_info,
|
||||
compile_handles, max_stack_size_));
|
||||
EnqueueAndStep(std::move(job));
|
||||
@ -460,7 +435,7 @@ void CompilerDispatcher::AbortAll(BlockingBehavior blocking) {
|
||||
it.second->ResetOnMainThread();
|
||||
}
|
||||
jobs_.clear();
|
||||
shared_to_job_id_.Clear();
|
||||
shared_to_unoptimized_job_id_.Clear();
|
||||
{
|
||||
base::LockGuard<base::Mutex> lock(&mutex_);
|
||||
DCHECK(pending_background_jobs_.empty());
|
||||
@ -546,11 +521,12 @@ void CompilerDispatcher::MemoryPressureNotification(
|
||||
|
||||
CompilerDispatcher::JobMap::const_iterator CompilerDispatcher::GetJobFor(
|
||||
Handle<SharedFunctionInfo> shared) const {
|
||||
JobId* job_id_ptr = shared_to_job_id_.Find(shared);
|
||||
JobId* job_id_ptr = shared_to_unoptimized_job_id_.Find(shared);
|
||||
JobMap::const_iterator job = jobs_.end();
|
||||
if (job_id_ptr) {
|
||||
job = jobs_.find(*job_id_ptr);
|
||||
DCHECK(job == jobs_.end() || job->second->IsAssociatedWith(shared));
|
||||
DCHECK(job == jobs_.end() ||
|
||||
job->second->AsUnoptimizedCompileJob()->IsAssociatedWith(shared));
|
||||
}
|
||||
return job;
|
||||
}
|
||||
@ -751,18 +727,51 @@ CompilerDispatcher::JobMap::const_iterator CompilerDispatcher::RemoveIfFinished(
|
||||
return RemoveJob(job);
|
||||
}
|
||||
|
||||
CompilerDispatcher::JobMap::const_iterator CompilerDispatcher::RemoveJob(
|
||||
CompilerDispatcher::JobMap::const_iterator job) {
|
||||
job->second->ResetOnMainThread();
|
||||
if (!job->second->shared().is_null()) {
|
||||
shared_to_job_id_.Delete(job->second->shared());
|
||||
CompilerDispatcher::JobMap::const_iterator CompilerDispatcher::InsertJob(
|
||||
std::unique_ptr<CompilerDispatcherJob> job) {
|
||||
bool added;
|
||||
JobMap::const_iterator it;
|
||||
std::tie(it, added) =
|
||||
jobs_.insert(std::make_pair(next_job_id_++, std::move(job)));
|
||||
DCHECK(added);
|
||||
|
||||
JobId id = it->first;
|
||||
CompilerDispatcherJob* inserted_job = it->second.get();
|
||||
|
||||
// Maps unoptimized jobs' SFIs to their job id.
|
||||
if (inserted_job->type() == CompilerDispatcherJob::kUnoptimizedCompile) {
|
||||
Handle<SharedFunctionInfo> shared =
|
||||
inserted_job->AsUnoptimizedCompileJob()->shared();
|
||||
if (!shared.is_null()) {
|
||||
shared_to_unoptimized_job_id_.Set(shared, id);
|
||||
}
|
||||
}
|
||||
job = jobs_.erase(job);
|
||||
|
||||
return it;
|
||||
}
|
||||
|
||||
CompilerDispatcher::JobMap::const_iterator CompilerDispatcher::RemoveJob(
|
||||
CompilerDispatcher::JobMap::const_iterator it) {
|
||||
CompilerDispatcherJob* job = it->second.get();
|
||||
job->ResetOnMainThread();
|
||||
|
||||
// Unmaps unoptimized jobs' SFIs to their job id.
|
||||
if (job->type() == CompilerDispatcherJob::kUnoptimizedCompile) {
|
||||
Handle<SharedFunctionInfo> shared =
|
||||
job->AsUnoptimizedCompileJob()->shared();
|
||||
if (!shared.is_null()) {
|
||||
JobId deleted_id = shared_to_unoptimized_job_id_.Delete(shared);
|
||||
USE(deleted_id);
|
||||
DCHECK_EQ(it->first, deleted_id);
|
||||
}
|
||||
}
|
||||
|
||||
it = jobs_.erase(it);
|
||||
if (jobs_.empty()) {
|
||||
base::LockGuard<base::Mutex> lock(&mutex_);
|
||||
if (num_background_tasks_ == 0) abort_ = false;
|
||||
}
|
||||
return job;
|
||||
return it;
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
@ -29,8 +29,9 @@ namespace internal {
|
||||
|
||||
class AstValueFactory;
|
||||
class CancelableTaskManager;
|
||||
class CompileJobFinishCallback;
|
||||
class CompilerDispatcherJob;
|
||||
class UnoptimizedCompileJob;
|
||||
class UnoptimizedCompileJobFinishCallback;
|
||||
class CompilerDispatcherTracer;
|
||||
class DeferredHandles;
|
||||
class FunctionLiteral;
|
||||
@ -88,7 +89,8 @@ class V8_EXPORT_PRIVATE CompilerDispatcher {
|
||||
bool Enqueue(Handle<String> source, int start_pos, int end_position,
|
||||
LanguageMode language_mode, int function_literal_id, bool native,
|
||||
bool module, bool is_named_expression, int compiler_hints,
|
||||
CompileJobFinishCallback* finish_callback, JobId* job_id);
|
||||
UnoptimizedCompileJobFinishCallback* finish_callback,
|
||||
JobId* job_id);
|
||||
|
||||
// Like Enqueue, but also advances the job so that it can potentially
|
||||
// continue running on a background thread (if at all possible). Returns
|
||||
@ -167,6 +169,8 @@ class V8_EXPORT_PRIVATE CompilerDispatcher {
|
||||
JobId EnqueueAndStep(std::unique_ptr<CompilerDispatcherJob> job);
|
||||
// Returns job if not removed otherwise iterator following the removed job.
|
||||
JobMap::const_iterator RemoveIfFinished(JobMap::const_iterator job);
|
||||
// Returns iterator to the inserted job.
|
||||
JobMap::const_iterator InsertJob(std::unique_ptr<CompilerDispatcherJob> job);
|
||||
// Returns iterator following the removed job.
|
||||
JobMap::const_iterator RemoveJob(JobMap::const_iterator job);
|
||||
bool FinishNow(CompilerDispatcherJob* job);
|
||||
@ -188,8 +192,9 @@ class V8_EXPORT_PRIVATE CompilerDispatcher {
|
||||
// Mapping from job_id to job.
|
||||
JobMap jobs_;
|
||||
|
||||
// Mapping from SharedFunctionInfo to corresponding JobId;
|
||||
SharedToJobIdMap shared_to_job_id_;
|
||||
// Mapping from SharedFunctionInfo to the corresponding unoptimized
|
||||
// compilation's JobId;
|
||||
SharedToJobIdMap shared_to_unoptimized_job_id_;
|
||||
|
||||
base::AtomicValue<v8::MemoryPressureLevel> memory_pressure_level_;
|
||||
|
||||
|
587
src/compiler-dispatcher/unoptimized-compile-job.cc
Normal file
587
src/compiler-dispatcher/unoptimized-compile-job.cc
Normal file
@ -0,0 +1,587 @@
|
||||
// Copyright 2016 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "src/compiler-dispatcher/unoptimized-compile-job.h"
|
||||
|
||||
#include "src/assert-scope.h"
|
||||
#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"
|
||||
#include "src/parsing/parse-info.h"
|
||||
#include "src/parsing/parser.h"
|
||||
#include "src/parsing/scanner-character-streams.h"
|
||||
#include "src/unicode-cache.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
|
||||
|
||||
UnoptimizedCompileJob::UnoptimizedCompileJob(
|
||||
CompilerDispatcherTracer* tracer, size_t max_stack_size,
|
||||
Handle<String> source, int start_position, int end_position,
|
||||
LanguageMode language_mode, int function_literal_id, bool native,
|
||||
bool module, bool is_named_expression, uint32_t hash_seed,
|
||||
AccountingAllocator* zone_allocator, int compiler_hints,
|
||||
const AstStringConstants* ast_string_constants,
|
||||
UnoptimizedCompileJobFinishCallback* finish_callback)
|
||||
: status_(Status::kReadyToParse),
|
||||
isolate_(nullptr),
|
||||
tracer_(tracer),
|
||||
max_stack_size_(max_stack_size),
|
||||
finish_callback_(finish_callback),
|
||||
trace_compiler_dispatcher_jobs_(FLAG_trace_compiler_dispatcher_jobs) {
|
||||
parse_info_.reset(new ParseInfo(zone_allocator));
|
||||
DCHECK(source->IsExternalTwoByteString() ||
|
||||
source->IsExternalOneByteString());
|
||||
character_stream_.reset(
|
||||
ScannerStream::For(source, start_position, end_position));
|
||||
parse_info_->set_character_stream(character_stream_.get());
|
||||
parse_info_->set_hash_seed(hash_seed);
|
||||
parse_info_->set_compiler_hints(compiler_hints);
|
||||
parse_info_->set_start_position(start_position);
|
||||
parse_info_->set_end_position(end_position);
|
||||
unicode_cache_.reset(new UnicodeCache());
|
||||
parse_info_->set_unicode_cache(unicode_cache_.get());
|
||||
parse_info_->set_language_mode(language_mode);
|
||||
parse_info_->set_function_literal_id(function_literal_id);
|
||||
parse_info_->set_ast_string_constants(ast_string_constants);
|
||||
if (V8_UNLIKELY(FLAG_runtime_stats)) {
|
||||
parse_info_->set_runtime_call_stats(new (parse_info_->zone())
|
||||
RuntimeCallStats());
|
||||
}
|
||||
|
||||
parse_info_->set_native(native);
|
||||
parse_info_->set_module(module);
|
||||
parse_info_->set_is_named_expression(is_named_expression);
|
||||
|
||||
parser_.reset(new Parser(parse_info_.get()));
|
||||
parser_->DeserializeScopeChain(parse_info_.get(), MaybeHandle<ScopeInfo>());
|
||||
|
||||
if (trace_compiler_dispatcher_jobs_) {
|
||||
PrintF("UnoptimizedCompileJob[%p] created for ", static_cast<void*>(this));
|
||||
ShortPrint();
|
||||
PrintF(" in ready to parse state.\n");
|
||||
}
|
||||
}
|
||||
|
||||
UnoptimizedCompileJob::UnoptimizedCompileJob(Isolate* isolate,
|
||||
CompilerDispatcherTracer* tracer,
|
||||
Handle<SharedFunctionInfo> shared,
|
||||
size_t max_stack_size)
|
||||
: status_(Status::kInitial),
|
||||
isolate_(isolate),
|
||||
tracer_(tracer),
|
||||
context_(isolate_->global_handles()->Create(isolate->context())),
|
||||
shared_(isolate_->global_handles()->Create(*shared)),
|
||||
max_stack_size_(max_stack_size),
|
||||
trace_compiler_dispatcher_jobs_(FLAG_trace_compiler_dispatcher_jobs) {
|
||||
DCHECK(!shared_->is_toplevel());
|
||||
HandleScope scope(isolate_);
|
||||
Handle<Script> script(Script::cast(shared_->script()), isolate_);
|
||||
Handle<String> source(String::cast(script->source()), isolate_);
|
||||
if (trace_compiler_dispatcher_jobs_) {
|
||||
PrintF("UnoptimizedCompileJob[%p] created for ", static_cast<void*>(this));
|
||||
ShortPrint();
|
||||
PrintF(" in initial state.\n");
|
||||
}
|
||||
}
|
||||
|
||||
UnoptimizedCompileJob::UnoptimizedCompileJob(
|
||||
Isolate* isolate, CompilerDispatcherTracer* tracer, Handle<Script> script,
|
||||
Handle<SharedFunctionInfo> shared, FunctionLiteral* literal,
|
||||
ParseInfo* outer_parse_info,
|
||||
std::shared_ptr<DeferredHandles> compile_handles, size_t max_stack_size)
|
||||
: status_(Status::kAnalyzed),
|
||||
isolate_(isolate),
|
||||
tracer_(tracer),
|
||||
context_(isolate_->global_handles()->Create(isolate->context())),
|
||||
shared_(isolate_->global_handles()->Create(*shared)),
|
||||
max_stack_size_(max_stack_size),
|
||||
parse_info_(new ParseInfo(shared_)),
|
||||
compile_zone_(new Zone(isolate->allocator(), ZONE_NAME)),
|
||||
compile_info_(new CompilationInfo(compile_zone_.get(), parse_info_.get(),
|
||||
isolate_, shared_,
|
||||
Handle<JSFunction>::null())),
|
||||
trace_compiler_dispatcher_jobs_(FLAG_trace_compiler_dispatcher_jobs) {
|
||||
parse_info_->set_literal(literal);
|
||||
parse_info_->set_script(script);
|
||||
parse_info_->ShareAstValueFactory(outer_parse_info);
|
||||
parse_info_->ShareZone(outer_parse_info);
|
||||
|
||||
compile_info_->set_deferred_handles(compile_handles);
|
||||
|
||||
if (trace_compiler_dispatcher_jobs_) {
|
||||
PrintF("UnoptimizedCompileJob[%p] created for ", static_cast<void*>(this));
|
||||
ShortPrint();
|
||||
PrintF(" in Analyzed state.\n");
|
||||
}
|
||||
}
|
||||
|
||||
UnoptimizedCompileJob::~UnoptimizedCompileJob() {
|
||||
DCHECK(status_ == Status::kInitial ||
|
||||
(status_ == Status::kReadyToParse && finish_callback_) ||
|
||||
status_ == Status::kDone);
|
||||
if (!shared_.is_null()) {
|
||||
DCHECK(ThreadId::Current().Equals(isolate_->thread_id()));
|
||||
i::GlobalHandles::Destroy(Handle<Object>::cast(shared_).location());
|
||||
}
|
||||
if (!context_.is_null()) {
|
||||
DCHECK(ThreadId::Current().Equals(isolate_->thread_id()));
|
||||
i::GlobalHandles::Destroy(Handle<Object>::cast(context_).location());
|
||||
}
|
||||
}
|
||||
|
||||
bool UnoptimizedCompileJob::IsAssociatedWith(
|
||||
Handle<SharedFunctionInfo> shared) const {
|
||||
return *shared_ == *shared;
|
||||
}
|
||||
|
||||
void UnoptimizedCompileJob::StepNextOnMainThread() {
|
||||
// Ensure we are in the correct context for the job.
|
||||
DCHECK_NOT_NULL(isolate_);
|
||||
SaveContext save(isolate_);
|
||||
if (has_context()) {
|
||||
isolate_->set_context(context());
|
||||
} else {
|
||||
// Phases which can run off the main thread by definition can't execute any
|
||||
// JS code, and so we don't need to enter their context.
|
||||
DCHECK(CanStepNextOnAnyThread());
|
||||
}
|
||||
|
||||
switch (status()) {
|
||||
case Status::kInitial:
|
||||
return PrepareToParseOnMainThread();
|
||||
|
||||
case Status::kReadyToParse:
|
||||
return Parse();
|
||||
|
||||
case Status::kParsed:
|
||||
return FinalizeParsingOnMainThread();
|
||||
|
||||
case Status::kReadyToAnalyze:
|
||||
return AnalyzeOnMainThread();
|
||||
|
||||
case Status::kAnalyzed:
|
||||
return PrepareToCompileOnMainThread();
|
||||
|
||||
case Status::kReadyToCompile:
|
||||
return Compile();
|
||||
|
||||
case Status::kCompiled:
|
||||
return FinalizeCompilingOnMainThread();
|
||||
|
||||
case Status::kFailed:
|
||||
case Status::kDone:
|
||||
return;
|
||||
}
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
void UnoptimizedCompileJob::StepNextOnBackgroundThread() {
|
||||
DCHECK(CanStepNextOnAnyThread());
|
||||
switch (status()) {
|
||||
case Status::kReadyToParse:
|
||||
return Parse();
|
||||
|
||||
case Status::kReadyToCompile:
|
||||
return Compile();
|
||||
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
void UnoptimizedCompileJob::PrepareToParseOnMainThread() {
|
||||
DCHECK(ThreadId::Current().Equals(isolate_->thread_id()));
|
||||
DCHECK(status() == Status::kInitial);
|
||||
COMPILER_DISPATCHER_TRACE_SCOPE(tracer_, kPrepareToParse);
|
||||
if (trace_compiler_dispatcher_jobs_) {
|
||||
PrintF("UnoptimizedCompileJob[%p]: Preparing to parse\n",
|
||||
static_cast<void*>(this));
|
||||
}
|
||||
HandleScope scope(isolate_);
|
||||
unicode_cache_.reset(new UnicodeCache());
|
||||
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);
|
||||
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_ = 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_ = isolate_->global_handles()->Create(*wrapper);
|
||||
|
||||
character_stream_.reset(
|
||||
ScannerStream::For(wrapper_, shared_->start_position() - offset,
|
||||
shared_->end_position() - offset));
|
||||
}
|
||||
parse_info_->InitFromIsolate(isolate_);
|
||||
parse_info_->set_character_stream(character_stream_.get());
|
||||
parse_info_->set_hash_seed(isolate_->heap()->HashSeed());
|
||||
parse_info_->set_is_named_expression(shared_->is_named_expression());
|
||||
parse_info_->set_compiler_hints(shared_->compiler_hints());
|
||||
parse_info_->set_start_position(shared_->start_position());
|
||||
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());
|
||||
if (V8_UNLIKELY(FLAG_runtime_stats)) {
|
||||
parse_info_->set_runtime_call_stats(new (parse_info_->zone())
|
||||
RuntimeCallStats());
|
||||
}
|
||||
|
||||
parser_.reset(new Parser(parse_info_.get()));
|
||||
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(shared_->name());
|
||||
parse_info_->set_function_name(
|
||||
parse_info_->ast_value_factory()->GetString(name));
|
||||
status_ = Status::kReadyToParse;
|
||||
}
|
||||
|
||||
void UnoptimizedCompileJob::Parse() {
|
||||
DCHECK(status() == Status::kReadyToParse);
|
||||
COMPILER_DISPATCHER_TRACE_SCOPE_WITH_NUM(
|
||||
tracer_, kParse,
|
||||
parse_info_->end_position() - parse_info_->start_position());
|
||||
if (trace_compiler_dispatcher_jobs_) {
|
||||
PrintF("UnoptimizedCompileJob[%p]: Parsing\n", static_cast<void*>(this));
|
||||
}
|
||||
|
||||
DisallowHeapAllocation no_allocation;
|
||||
DisallowHandleAllocation no_handles;
|
||||
DisallowHandleDereference no_deref;
|
||||
|
||||
uintptr_t stack_limit = GetCurrentStackPosition() - max_stack_size_ * KB;
|
||||
|
||||
parser_->set_stack_limit(stack_limit);
|
||||
parser_->ParseOnBackground(parse_info_.get());
|
||||
|
||||
if (finish_callback_) {
|
||||
finish_callback_->ParseFinished(std::move(parse_info_));
|
||||
status_ = Status::kDone;
|
||||
} else {
|
||||
status_ = Status::kParsed;
|
||||
}
|
||||
}
|
||||
|
||||
void UnoptimizedCompileJob::FinalizeParsingOnMainThread() {
|
||||
DCHECK(ThreadId::Current().Equals(isolate_->thread_id()));
|
||||
DCHECK(status() == Status::kParsed);
|
||||
COMPILER_DISPATCHER_TRACE_SCOPE(tracer_, kFinalizeParsing);
|
||||
if (trace_compiler_dispatcher_jobs_) {
|
||||
PrintF("UnoptimizedCompileJob[%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_ = Status::kFailed;
|
||||
} else {
|
||||
status_ = Status::kReadyToAnalyze;
|
||||
}
|
||||
parser_->UpdateStatistics(isolate_, script);
|
||||
parse_info_->UpdateStatisticsAfterBackgroundParse(isolate_);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
parser_->HandleSourceURLComments(isolate_, script);
|
||||
|
||||
parse_info_->set_character_stream(nullptr);
|
||||
parse_info_->set_unicode_cache(nullptr);
|
||||
parser_.reset();
|
||||
unicode_cache_.reset();
|
||||
character_stream_.reset();
|
||||
}
|
||||
|
||||
void UnoptimizedCompileJob::AnalyzeOnMainThread() {
|
||||
DCHECK(ThreadId::Current().Equals(isolate_->thread_id()));
|
||||
DCHECK(status() == Status::kReadyToAnalyze);
|
||||
COMPILER_DISPATCHER_TRACE_SCOPE(tracer_, kAnalyze);
|
||||
if (trace_compiler_dispatcher_jobs_) {
|
||||
PrintF("UnoptimizedCompileJob[%p]: Analyzing\n", static_cast<void*>(this));
|
||||
}
|
||||
|
||||
compile_zone_.reset(new Zone(isolate_->allocator(), ZONE_NAME));
|
||||
compile_info_.reset(new CompilationInfo(
|
||||
compile_zone_.get(), parse_info_.get(), isolate_,
|
||||
Handle<SharedFunctionInfo>::null(), Handle<JSFunction>::null()));
|
||||
|
||||
DeferredHandleScope scope(isolate_);
|
||||
{
|
||||
if (Compiler::Analyze(compile_info_.get())) {
|
||||
status_ = Status::kAnalyzed;
|
||||
} else {
|
||||
status_ = Status::kFailed;
|
||||
if (!isolate_->has_pending_exception()) isolate_->StackOverflow();
|
||||
}
|
||||
}
|
||||
compile_info_->set_deferred_handles(scope.Detach());
|
||||
}
|
||||
|
||||
void UnoptimizedCompileJob::PrepareToCompileOnMainThread() {
|
||||
DCHECK(ThreadId::Current().Equals(isolate_->thread_id()));
|
||||
DCHECK(status() == Status::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_ = Status::kFailed;
|
||||
return;
|
||||
}
|
||||
|
||||
CHECK(compile_job_->can_execute_on_background_thread());
|
||||
status_ = Status::kReadyToCompile;
|
||||
}
|
||||
|
||||
void UnoptimizedCompileJob::Compile() {
|
||||
DCHECK(status() == Status::kReadyToCompile);
|
||||
COMPILER_DISPATCHER_TRACE_SCOPE(tracer_, kCompile);
|
||||
if (trace_compiler_dispatcher_jobs_) {
|
||||
PrintF("UnoptimizedCompileJob[%p]: Compiling\n", static_cast<void*>(this));
|
||||
}
|
||||
|
||||
// Disallowing of handle dereference and heap access dealt with in
|
||||
// CompilationJob::ExecuteJob.
|
||||
|
||||
uintptr_t stack_limit = GetCurrentStackPosition() - max_stack_size_ * KB;
|
||||
compile_job_->set_stack_limit(stack_limit);
|
||||
|
||||
CompilationJob::Status status = compile_job_->ExecuteJob();
|
||||
USE(status);
|
||||
|
||||
// Always transition to kCompiled - errors will be reported by
|
||||
// FinalizeCompilingOnMainThread.
|
||||
status_ = Status::kCompiled;
|
||||
}
|
||||
|
||||
void UnoptimizedCompileJob::FinalizeCompilingOnMainThread() {
|
||||
DCHECK(ThreadId::Current().Equals(isolate_->thread_id()));
|
||||
DCHECK(status() == Status::kCompiled);
|
||||
COMPILER_DISPATCHER_TRACE_SCOPE(tracer_, kFinalizeCompiling);
|
||||
if (trace_compiler_dispatcher_jobs_) {
|
||||
PrintF("UnoptimizedCompileJob[%p]: Finalizing compiling\n",
|
||||
static_cast<void*>(this));
|
||||
}
|
||||
|
||||
{
|
||||
HandleScope scope(isolate_);
|
||||
compile_info_->set_shared_info(shared_);
|
||||
if (compile_job_->state() == CompilationJob::State::kFailed ||
|
||||
!Compiler::FinalizeCompilationJob(compile_job_.release())) {
|
||||
if (!isolate_->has_pending_exception()) isolate_->StackOverflow();
|
||||
status_ = Status::kFailed;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
compile_job_.reset();
|
||||
compile_info_.reset();
|
||||
compile_zone_.reset();
|
||||
parse_info_.reset();
|
||||
|
||||
status_ = Status::kDone;
|
||||
}
|
||||
|
||||
void UnoptimizedCompileJob::ResetOnMainThread() {
|
||||
if (trace_compiler_dispatcher_jobs_) {
|
||||
PrintF("UnoptimizedCompileJob[%p]: Resetting\n", static_cast<void*>(this));
|
||||
}
|
||||
|
||||
compile_job_.reset();
|
||||
compile_info_.reset();
|
||||
compile_zone_.reset();
|
||||
parser_.reset();
|
||||
unicode_cache_.reset();
|
||||
character_stream_.reset();
|
||||
parse_info_.reset();
|
||||
finish_callback_ = nullptr;
|
||||
|
||||
if (!source_.is_null()) {
|
||||
DCHECK(ThreadId::Current().Equals(isolate_->thread_id()));
|
||||
i::GlobalHandles::Destroy(Handle<Object>::cast(source_).location());
|
||||
source_ = Handle<String>::null();
|
||||
}
|
||||
if (!wrapper_.is_null()) {
|
||||
DCHECK(ThreadId::Current().Equals(isolate_->thread_id()));
|
||||
i::GlobalHandles::Destroy(Handle<Object>::cast(wrapper_).location());
|
||||
wrapper_ = Handle<String>::null();
|
||||
}
|
||||
|
||||
status_ = Status::kInitial;
|
||||
}
|
||||
|
||||
double UnoptimizedCompileJob::EstimateRuntimeOfNextStepInMs() const {
|
||||
switch (status()) {
|
||||
case Status::kInitial:
|
||||
return tracer_->EstimatePrepareToParseInMs();
|
||||
|
||||
case Status::kReadyToParse:
|
||||
return tracer_->EstimateParseInMs(parse_info_->end_position() -
|
||||
parse_info_->start_position());
|
||||
|
||||
case Status::kParsed:
|
||||
return tracer_->EstimateFinalizeParsingInMs();
|
||||
|
||||
case Status::kReadyToAnalyze:
|
||||
return tracer_->EstimateAnalyzeInMs();
|
||||
|
||||
case Status::kAnalyzed:
|
||||
return tracer_->EstimatePrepareToCompileInMs();
|
||||
|
||||
case Status::kReadyToCompile:
|
||||
return tracer_->EstimateCompileInMs();
|
||||
|
||||
case Status::kCompiled:
|
||||
return tracer_->EstimateFinalizeCompilingInMs();
|
||||
|
||||
case Status::kFailed:
|
||||
case Status::kDone:
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
void UnoptimizedCompileJob::ShortPrint() {
|
||||
if (isolate_) {
|
||||
DCHECK(ThreadId::Current().Equals(isolate_->thread_id()));
|
||||
DCHECK(!shared_.is_null());
|
||||
shared_->ShortPrint();
|
||||
} else {
|
||||
// TODO(wiktorg) more useful info in those cases
|
||||
if (parse_info_) {
|
||||
PrintF("function at %d", parse_info_->start_position());
|
||||
} else {
|
||||
PrintF("parsed function");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
176
src/compiler-dispatcher/unoptimized-compile-job.h
Normal file
176
src/compiler-dispatcher/unoptimized-compile-job.h
Normal file
@ -0,0 +1,176 @@
|
||||
// Copyright 2016 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef V8_COMPILER_DISPATCHER_UNOPTIMIZED_COMPILE_JOB_H_
|
||||
#define V8_COMPILER_DISPATCHER_UNOPTIMIZED_COMPILE_JOB_H_
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "include/v8.h"
|
||||
#include "src/base/macros.h"
|
||||
#include "src/compiler-dispatcher/compiler-dispatcher-job.h"
|
||||
#include "src/globals.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
class AstValueFactory;
|
||||
class AstStringConstants;
|
||||
class CompilerDispatcherTracer;
|
||||
class CompilationInfo;
|
||||
class CompilationJob;
|
||||
class DeferredHandles;
|
||||
class FunctionLiteral;
|
||||
class Isolate;
|
||||
class ParseInfo;
|
||||
class Parser;
|
||||
class SharedFunctionInfo;
|
||||
class String;
|
||||
class UnicodeCache;
|
||||
class Utf16CharacterStream;
|
||||
|
||||
class V8_EXPORT_PRIVATE UnoptimizedCompileJobFinishCallback {
|
||||
public:
|
||||
virtual ~UnoptimizedCompileJobFinishCallback() {}
|
||||
virtual void ParseFinished(std::unique_ptr<ParseInfo> parse_info) = 0;
|
||||
};
|
||||
|
||||
class V8_EXPORT_PRIVATE UnoptimizedCompileJob : public CompilerDispatcherJob {
|
||||
public:
|
||||
enum class Status {
|
||||
kInitial,
|
||||
kReadyToParse,
|
||||
kParsed,
|
||||
kReadyToAnalyze,
|
||||
kAnalyzed,
|
||||
kReadyToCompile,
|
||||
kCompiled,
|
||||
kDone,
|
||||
kFailed,
|
||||
};
|
||||
|
||||
// Creates a UnoptimizedCompileJob in the initial state.
|
||||
UnoptimizedCompileJob(Isolate* isolate, CompilerDispatcherTracer* tracer,
|
||||
Handle<SharedFunctionInfo> shared,
|
||||
size_t max_stack_size);
|
||||
// TODO(wiktorg) document it better once I know how it relates to whole stuff
|
||||
// Creates a UnoptimizedCompileJob in ready to parse top-level function state.
|
||||
UnoptimizedCompileJob(CompilerDispatcherTracer* tracer, size_t max_stack_size,
|
||||
Handle<String> source, int start_position,
|
||||
int end_position, LanguageMode language_mode,
|
||||
int function_literal_id, bool native, bool module,
|
||||
bool is_named_expression, uint32_t hash_seed,
|
||||
AccountingAllocator* zone_allocator, int compiler_hints,
|
||||
const AstStringConstants* ast_string_constants,
|
||||
UnoptimizedCompileJobFinishCallback* finish_callback);
|
||||
// Creates a UnoptimizedCompileJob in the analyzed state.
|
||||
UnoptimizedCompileJob(Isolate* isolate, CompilerDispatcherTracer* tracer,
|
||||
Handle<Script> script,
|
||||
Handle<SharedFunctionInfo> shared,
|
||||
FunctionLiteral* literal, ParseInfo* outer_parse_info,
|
||||
std::shared_ptr<DeferredHandles> compile_handles,
|
||||
size_t max_stack_size);
|
||||
|
||||
~UnoptimizedCompileJob() override;
|
||||
|
||||
Type type() const override { return kUnoptimizedCompile; }
|
||||
|
||||
Handle<SharedFunctionInfo> shared() const { return shared_; }
|
||||
|
||||
// Returns true if this UnoptimizedCompileJob was created for the given
|
||||
// function.
|
||||
bool IsAssociatedWith(Handle<SharedFunctionInfo> shared) const;
|
||||
|
||||
bool IsFinished() override {
|
||||
return status() == Status::kDone || status() == Status::kFailed;
|
||||
}
|
||||
|
||||
bool IsFailed() override { return status() == Status::kFailed; }
|
||||
|
||||
// Return true if the next step can be run on any thread, that is when both
|
||||
// StepNextOnMainThread and StepNextOnBackgroundThread could be used for the
|
||||
// next step.
|
||||
bool CanStepNextOnAnyThread() override {
|
||||
return status() == Status::kReadyToParse ||
|
||||
status() == Status::kReadyToCompile;
|
||||
}
|
||||
|
||||
// Step the job forward by one state on the main thread.
|
||||
void StepNextOnMainThread() override;
|
||||
|
||||
// Step the job forward by one state on a background thread.
|
||||
void StepNextOnBackgroundThread() override;
|
||||
|
||||
// Transition from any state to kInitial and free all resources.
|
||||
void ResetOnMainThread() override;
|
||||
|
||||
// Estimate how long the next step will take using the tracer.
|
||||
double EstimateRuntimeOfNextStepInMs() const override;
|
||||
|
||||
// Even though the name does not imply this, ShortPrint() must only be invoked
|
||||
// on the main thread.
|
||||
void ShortPrint() override;
|
||||
|
||||
private:
|
||||
friend class CompilerDispatcherTest;
|
||||
friend class UnoptimizedCompileJobTest;
|
||||
|
||||
bool has_context() const { return !context_.is_null(); }
|
||||
Context* context() { return *context_; }
|
||||
|
||||
Status status() const { return status_; }
|
||||
|
||||
Status status_;
|
||||
Isolate* isolate_;
|
||||
CompilerDispatcherTracer* tracer_;
|
||||
Handle<Context> context_; // Global handle.
|
||||
Handle<SharedFunctionInfo> shared_; // Global handle.
|
||||
Handle<String> source_; // Global handle.
|
||||
Handle<String> wrapper_; // Global handle.
|
||||
std::unique_ptr<v8::String::ExternalStringResourceBase> source_wrapper_;
|
||||
size_t max_stack_size_;
|
||||
UnoptimizedCompileJobFinishCallback* finish_callback_ = nullptr;
|
||||
|
||||
// Members required for parsing.
|
||||
std::unique_ptr<UnicodeCache> unicode_cache_;
|
||||
std::unique_ptr<Utf16CharacterStream> character_stream_;
|
||||
std::unique_ptr<ParseInfo> parse_info_;
|
||||
std::unique_ptr<Parser> parser_;
|
||||
|
||||
// Members required for compiling.
|
||||
std::shared_ptr<Zone> compile_zone_;
|
||||
std::unique_ptr<CompilationInfo> compile_info_;
|
||||
std::unique_ptr<CompilationJob> compile_job_;
|
||||
|
||||
bool trace_compiler_dispatcher_jobs_;
|
||||
|
||||
// Transition from kInitial to kReadyToParse.
|
||||
void PrepareToParseOnMainThread();
|
||||
|
||||
// Transition from kReadyToParse to kParsed (or kDone if there is
|
||||
// finish_callback).
|
||||
void Parse();
|
||||
|
||||
// Transition from kParsed to kReadyToAnalyze (or kFailed).
|
||||
void FinalizeParsingOnMainThread();
|
||||
|
||||
// Transition from kReadyToAnalyze to kAnalyzed (or kFailed).
|
||||
void AnalyzeOnMainThread();
|
||||
|
||||
// Transition from kAnalyzed to kReadyToCompile (or kFailed).
|
||||
void PrepareToCompileOnMainThread();
|
||||
|
||||
// Transition from kReadyToCompile to kCompiled.
|
||||
void Compile();
|
||||
|
||||
// Transition from kCompiled to kDone (or kFailed).
|
||||
void FinalizeCompilingOnMainThread();
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(UnoptimizedCompileJob);
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
||||
#endif // V8_COMPILER_DISPATCHER_UNOPTIMIZED_COMPILE_JOB_H_
|
@ -10,7 +10,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include "include/v8.h"
|
||||
#include "src/compiler-dispatcher/compiler-dispatcher-job.h"
|
||||
#include "src/compiler-dispatcher/unoptimized-compile-job.h"
|
||||
#include "src/globals.h"
|
||||
#include "src/handles.h"
|
||||
#include "src/parsing/preparsed-scope-data.h"
|
||||
@ -35,7 +35,7 @@ class Utf16CharacterStream;
|
||||
class Zone;
|
||||
|
||||
// A container for the inputs, configuration options, and outputs of parsing.
|
||||
class V8_EXPORT_PRIVATE ParseInfo : public CompileJobFinishCallback {
|
||||
class V8_EXPORT_PRIVATE ParseInfo : public UnoptimizedCompileJobFinishCallback {
|
||||
public:
|
||||
explicit ParseInfo(AccountingAllocator* zone_allocator);
|
||||
ParseInfo(Handle<Script> script);
|
||||
|
@ -894,6 +894,8 @@
|
||||
'compiler-dispatcher/compiler-dispatcher-tracer.h',
|
||||
'compiler-dispatcher/optimizing-compile-dispatcher.cc',
|
||||
'compiler-dispatcher/optimizing-compile-dispatcher.h',
|
||||
'compiler-dispatcher/unoptimized-compile-job.cc',
|
||||
'compiler-dispatcher/unoptimized-compile-job.h',
|
||||
'compiler.cc',
|
||||
'compiler.h',
|
||||
'contexts-inl.h',
|
||||
|
@ -39,10 +39,10 @@ v8_executable("unittests") {
|
||||
"base/utils/random-number-generator-unittest.cc",
|
||||
"cancelable-tasks-unittest.cc",
|
||||
"char-predicates-unittest.cc",
|
||||
"compiler-dispatcher/compiler-dispatcher-job-unittest.cc",
|
||||
"compiler-dispatcher/compiler-dispatcher-tracer-unittest.cc",
|
||||
"compiler-dispatcher/compiler-dispatcher-unittest.cc",
|
||||
"compiler-dispatcher/optimizing-compile-dispatcher-unittest.cc",
|
||||
"compiler-dispatcher/unoptimized-compile-job-unittest.cc",
|
||||
"compiler/branch-elimination-unittest.cc",
|
||||
"compiler/bytecode-analysis-unittest.cc",
|
||||
"compiler/checkpoint-elimination-unittest.cc",
|
||||
|
@ -77,13 +77,15 @@ class CompilerDispatcherTest : public TestWithContext {
|
||||
CompilerDispatcherTestFlags::RestoreFlags();
|
||||
}
|
||||
|
||||
static CompileJobStatus GetJobStatus(const CompilerDispatcherJob* job) {
|
||||
return job->status();
|
||||
static UnoptimizedCompileJob::Status GetUnoptimizedJobStatus(
|
||||
const CompilerDispatcherJob* job) {
|
||||
CHECK_EQ(CompilerDispatcherJob::kUnoptimizedCompile, job->type());
|
||||
return job->AsUnoptimizedCompileJob()->status();
|
||||
}
|
||||
|
||||
static CompileJobStatus GetJobStatus(
|
||||
static UnoptimizedCompileJob::Status GetUnoptimizedJobStatus(
|
||||
const std::unique_ptr<CompilerDispatcherJob>& job) {
|
||||
return GetJobStatus(job.get());
|
||||
return GetUnoptimizedJobStatus(job.get());
|
||||
}
|
||||
|
||||
private:
|
||||
@ -405,8 +407,8 @@ TEST_F(CompilerDispatcherTest, IdleTaskSmallIdleTime) {
|
||||
|
||||
// The job should be scheduled for the main thread.
|
||||
ASSERT_EQ(dispatcher.jobs_.size(), 1u);
|
||||
ASSERT_EQ(CompileJobStatus::kInitial,
|
||||
GetJobStatus(dispatcher.jobs_.begin()->second));
|
||||
ASSERT_EQ(UnoptimizedCompileJob::Status::kInitial,
|
||||
GetUnoptimizedJobStatus(dispatcher.jobs_.begin()->second));
|
||||
|
||||
// Only grant a little idle time and have time advance beyond it in one step.
|
||||
platform.RunIdleTask(2.0, 1.0);
|
||||
@ -418,8 +420,8 @@ TEST_F(CompilerDispatcherTest, IdleTaskSmallIdleTime) {
|
||||
// The job should be still scheduled for the main thread, but ready for
|
||||
// parsing.
|
||||
ASSERT_EQ(dispatcher.jobs_.size(), 1u);
|
||||
ASSERT_EQ(CompileJobStatus::kReadyToParse,
|
||||
GetJobStatus(dispatcher.jobs_.begin()->second));
|
||||
ASSERT_EQ(UnoptimizedCompileJob::Status::kReadyToParse,
|
||||
GetUnoptimizedJobStatus(dispatcher.jobs_.begin()->second));
|
||||
|
||||
// Now grant a lot of idle time and freeze time.
|
||||
platform.RunIdleTask(1000.0, 0.0);
|
||||
@ -470,15 +472,15 @@ TEST_F(CompilerDispatcherTest, CompileOnBackgroundThread) {
|
||||
ASSERT_TRUE(platform.IdleTaskPending());
|
||||
|
||||
ASSERT_EQ(dispatcher.jobs_.size(), 1u);
|
||||
ASSERT_EQ(CompileJobStatus::kInitial,
|
||||
GetJobStatus(dispatcher.jobs_.begin()->second));
|
||||
ASSERT_EQ(UnoptimizedCompileJob::Status::kInitial,
|
||||
GetUnoptimizedJobStatus(dispatcher.jobs_.begin()->second));
|
||||
|
||||
// Make compiling super expensive, and advance job as much as possible on the
|
||||
// foreground thread.
|
||||
dispatcher.tracer_->RecordCompile(50000.0);
|
||||
platform.RunIdleTask(10.0, 0.0);
|
||||
ASSERT_EQ(CompileJobStatus::kReadyToCompile,
|
||||
GetJobStatus(dispatcher.jobs_.begin()->second));
|
||||
ASSERT_EQ(UnoptimizedCompileJob::Status::kReadyToCompile,
|
||||
GetUnoptimizedJobStatus(dispatcher.jobs_.begin()->second));
|
||||
|
||||
ASSERT_TRUE(dispatcher.IsEnqueued(shared));
|
||||
ASSERT_FALSE(shared->is_compiled());
|
||||
@ -489,8 +491,8 @@ TEST_F(CompilerDispatcherTest, CompileOnBackgroundThread) {
|
||||
|
||||
ASSERT_TRUE(platform.IdleTaskPending());
|
||||
ASSERT_FALSE(platform.BackgroundTasksPending());
|
||||
ASSERT_EQ(CompileJobStatus::kCompiled,
|
||||
GetJobStatus(dispatcher.jobs_.begin()->second));
|
||||
ASSERT_EQ(UnoptimizedCompileJob::Status::kCompiled,
|
||||
GetUnoptimizedJobStatus(dispatcher.jobs_.begin()->second));
|
||||
|
||||
// Now grant a lot of idle time and freeze time.
|
||||
platform.RunIdleTask(1000.0, 0.0);
|
||||
@ -514,15 +516,15 @@ TEST_F(CompilerDispatcherTest, FinishNowWithBackgroundTask) {
|
||||
ASSERT_TRUE(platform.IdleTaskPending());
|
||||
|
||||
ASSERT_EQ(dispatcher.jobs_.size(), 1u);
|
||||
ASSERT_EQ(CompileJobStatus::kInitial,
|
||||
GetJobStatus(dispatcher.jobs_.begin()->second));
|
||||
ASSERT_EQ(UnoptimizedCompileJob::Status::kInitial,
|
||||
GetUnoptimizedJobStatus(dispatcher.jobs_.begin()->second));
|
||||
|
||||
// Make compiling super expensive, and advance job as much as possible on the
|
||||
// foreground thread.
|
||||
dispatcher.tracer_->RecordCompile(50000.0);
|
||||
platform.RunIdleTask(10.0, 0.0);
|
||||
ASSERT_EQ(CompileJobStatus::kReadyToCompile,
|
||||
GetJobStatus(dispatcher.jobs_.begin()->second));
|
||||
ASSERT_EQ(UnoptimizedCompileJob::Status::kReadyToCompile,
|
||||
GetUnoptimizedJobStatus(dispatcher.jobs_.begin()->second));
|
||||
|
||||
ASSERT_TRUE(dispatcher.IsEnqueued(shared));
|
||||
ASSERT_FALSE(shared->is_compiled());
|
||||
@ -611,15 +613,15 @@ TEST_F(CompilerDispatcherTest, AsyncAbortAllPendingBackgroundTask) {
|
||||
ASSERT_TRUE(platform.IdleTaskPending());
|
||||
|
||||
ASSERT_EQ(dispatcher.jobs_.size(), 1u);
|
||||
ASSERT_EQ(CompileJobStatus::kInitial,
|
||||
GetJobStatus(dispatcher.jobs_.begin()->second));
|
||||
ASSERT_EQ(UnoptimizedCompileJob::Status::kInitial,
|
||||
GetUnoptimizedJobStatus(dispatcher.jobs_.begin()->second));
|
||||
|
||||
// Make compiling super expensive, and advance job as much as possible on the
|
||||
// foreground thread.
|
||||
dispatcher.tracer_->RecordCompile(50000.0);
|
||||
platform.RunIdleTask(10.0, 0.0);
|
||||
ASSERT_EQ(CompileJobStatus::kReadyToCompile,
|
||||
GetJobStatus(dispatcher.jobs_.begin()->second));
|
||||
ASSERT_EQ(UnoptimizedCompileJob::Status::kReadyToCompile,
|
||||
GetUnoptimizedJobStatus(dispatcher.jobs_.begin()->second));
|
||||
|
||||
ASSERT_TRUE(dispatcher.IsEnqueued(shared));
|
||||
ASSERT_FALSE(shared->is_compiled());
|
||||
@ -659,15 +661,15 @@ TEST_F(CompilerDispatcherTest, AsyncAbortAllRunningBackgroundTask) {
|
||||
ASSERT_TRUE(platform.IdleTaskPending());
|
||||
|
||||
ASSERT_EQ(dispatcher.jobs_.size(), 1u);
|
||||
ASSERT_EQ(CompileJobStatus::kInitial,
|
||||
GetJobStatus(dispatcher.jobs_.begin()->second));
|
||||
ASSERT_EQ(UnoptimizedCompileJob::Status::kInitial,
|
||||
GetUnoptimizedJobStatus(dispatcher.jobs_.begin()->second));
|
||||
|
||||
// Make compiling super expensive, and advance job as much as possible on the
|
||||
// foreground thread.
|
||||
dispatcher.tracer_->RecordCompile(50000.0);
|
||||
platform.RunIdleTask(10.0, 0.0);
|
||||
ASSERT_EQ(CompileJobStatus::kReadyToCompile,
|
||||
GetJobStatus(dispatcher.jobs_.begin()->second));
|
||||
ASSERT_EQ(UnoptimizedCompileJob::Status::kReadyToCompile,
|
||||
GetUnoptimizedJobStatus(dispatcher.jobs_.begin()->second));
|
||||
|
||||
ASSERT_TRUE(dispatcher.IsEnqueued(shared1));
|
||||
ASSERT_FALSE(shared1->is_compiled());
|
||||
@ -736,15 +738,15 @@ TEST_F(CompilerDispatcherTest, FinishNowDuringAbortAll) {
|
||||
ASSERT_TRUE(platform.IdleTaskPending());
|
||||
|
||||
ASSERT_EQ(dispatcher.jobs_.size(), 1u);
|
||||
ASSERT_EQ(CompileJobStatus::kInitial,
|
||||
GetJobStatus(dispatcher.jobs_.begin()->second));
|
||||
ASSERT_EQ(UnoptimizedCompileJob::Status::kInitial,
|
||||
GetUnoptimizedJobStatus(dispatcher.jobs_.begin()->second));
|
||||
|
||||
// Make compiling super expensive, and advance job as much as possible on the
|
||||
// foreground thread.
|
||||
dispatcher.tracer_->RecordCompile(50000.0);
|
||||
platform.RunIdleTask(10.0, 0.0);
|
||||
ASSERT_EQ(CompileJobStatus::kReadyToCompile,
|
||||
GetJobStatus(dispatcher.jobs_.begin()->second));
|
||||
ASSERT_EQ(UnoptimizedCompileJob::Status::kReadyToCompile,
|
||||
GetUnoptimizedJobStatus(dispatcher.jobs_.begin()->second));
|
||||
|
||||
ASSERT_TRUE(dispatcher.IsEnqueued(shared));
|
||||
ASSERT_FALSE(shared->is_compiled());
|
||||
@ -890,7 +892,7 @@ TEST_F(CompilerDispatcherTest, EnqueueJob) {
|
||||
Handle<JSFunction>::cast(test::RunJS(isolate(), script));
|
||||
Handle<SharedFunctionInfo> shared(f->shared(), i_isolate());
|
||||
std::unique_ptr<CompilerDispatcherJob> job(
|
||||
new CompilerDispatcherJob(i_isolate(), dispatcher.tracer_.get(), shared,
|
||||
new UnoptimizedCompileJob(i_isolate(), dispatcher.tracer_.get(), shared,
|
||||
dispatcher.max_stack_size_));
|
||||
ASSERT_FALSE(dispatcher.IsEnqueued(shared));
|
||||
dispatcher.Enqueue(std::move(job));
|
||||
@ -905,7 +907,7 @@ TEST_F(CompilerDispatcherTest, EnqueueWithoutSFI) {
|
||||
MockPlatform platform(V8::GetCurrentPlatform()->GetTracingController());
|
||||
CompilerDispatcher dispatcher(i_isolate(), &platform, FLAG_stack_size);
|
||||
ASSERT_TRUE(dispatcher.jobs_.empty());
|
||||
ASSERT_TRUE(dispatcher.shared_to_job_id_.empty());
|
||||
ASSERT_TRUE(dispatcher.shared_to_unoptimized_job_id_.empty());
|
||||
std::unique_ptr<test::FinishCallback> callback(new test::FinishCallback());
|
||||
std::unique_ptr<test::ScriptResource> resource(
|
||||
new test::ScriptResource(test_script, strlen(test_script)));
|
||||
@ -915,9 +917,9 @@ TEST_F(CompilerDispatcherTest, EnqueueWithoutSFI) {
|
||||
1, false, false, false, 0, callback.get(),
|
||||
nullptr));
|
||||
ASSERT_TRUE(!dispatcher.jobs_.empty());
|
||||
ASSERT_EQ(CompileJobStatus::kReadyToParse,
|
||||
GetJobStatus(dispatcher.jobs_.begin()->second));
|
||||
ASSERT_TRUE(dispatcher.shared_to_job_id_.empty());
|
||||
ASSERT_EQ(UnoptimizedCompileJob::Status::kReadyToParse,
|
||||
GetUnoptimizedJobStatus(dispatcher.jobs_.begin()->second));
|
||||
ASSERT_TRUE(dispatcher.shared_to_unoptimized_job_id_.empty());
|
||||
ASSERT_TRUE(callback->result() == nullptr);
|
||||
|
||||
ASSERT_TRUE(platform.IdleTaskPending());
|
||||
@ -939,8 +941,8 @@ TEST_F(CompilerDispatcherTest, EnqueueAndStep) {
|
||||
ASSERT_TRUE(dispatcher.EnqueueAndStep(shared));
|
||||
ASSERT_TRUE(dispatcher.IsEnqueued(shared));
|
||||
|
||||
ASSERT_EQ(CompileJobStatus::kReadyToParse,
|
||||
GetJobStatus(dispatcher.jobs_.begin()->second));
|
||||
ASSERT_EQ(UnoptimizedCompileJob::Status::kReadyToParse,
|
||||
GetUnoptimizedJobStatus(dispatcher.jobs_.begin()->second));
|
||||
|
||||
ASSERT_TRUE(platform.IdleTaskPending());
|
||||
platform.ClearIdleTask();
|
||||
@ -967,8 +969,8 @@ TEST_F(CompilerDispatcherTest, EnqueueParsed) {
|
||||
&parse_info, handles));
|
||||
ASSERT_TRUE(dispatcher.IsEnqueued(shared));
|
||||
|
||||
ASSERT_EQ(CompileJobStatus::kAnalyzed,
|
||||
GetJobStatus(dispatcher.jobs_.begin()->second));
|
||||
ASSERT_EQ(UnoptimizedCompileJob::Status::kAnalyzed,
|
||||
GetUnoptimizedJobStatus(dispatcher.jobs_.begin()->second));
|
||||
|
||||
ASSERT_TRUE(platform.IdleTaskPending());
|
||||
platform.ClearIdleTask();
|
||||
@ -994,8 +996,8 @@ TEST_F(CompilerDispatcherTest, EnqueueAndStepParsed) {
|
||||
&parse_info, handles));
|
||||
ASSERT_TRUE(dispatcher.IsEnqueued(shared));
|
||||
|
||||
ASSERT_EQ(CompileJobStatus::kReadyToCompile,
|
||||
GetJobStatus(dispatcher.jobs_.begin()->second));
|
||||
ASSERT_EQ(UnoptimizedCompileJob::Status::kReadyToCompile,
|
||||
GetUnoptimizedJobStatus(dispatcher.jobs_.begin()->second));
|
||||
|
||||
ASSERT_TRUE(platform.IdleTaskPending());
|
||||
ASSERT_TRUE(platform.BackgroundTasksPending());
|
||||
@ -1180,19 +1182,19 @@ TEST_F(CompilerDispatcherTest, EnqueueAndStepTwice) {
|
||||
&parse_info, handles));
|
||||
ASSERT_TRUE(dispatcher.IsEnqueued(shared));
|
||||
|
||||
ASSERT_EQ(CompileJobStatus::kReadyToCompile,
|
||||
GetJobStatus(dispatcher.jobs_.begin()->second));
|
||||
ASSERT_EQ(UnoptimizedCompileJob::Status::kReadyToCompile,
|
||||
GetUnoptimizedJobStatus(dispatcher.jobs_.begin()->second));
|
||||
|
||||
// EnqueueAndStep of the same function again (either already parsed or for
|
||||
// compile and parse) shouldn't step the job.
|
||||
ASSERT_TRUE(dispatcher.EnqueueAndStep(script, shared, parse_info.literal(),
|
||||
&parse_info, handles));
|
||||
ASSERT_TRUE(dispatcher.IsEnqueued(shared));
|
||||
ASSERT_EQ(CompileJobStatus::kReadyToCompile,
|
||||
GetJobStatus(dispatcher.jobs_.begin()->second));
|
||||
ASSERT_EQ(UnoptimizedCompileJob::Status::kReadyToCompile,
|
||||
GetUnoptimizedJobStatus(dispatcher.jobs_.begin()->second));
|
||||
ASSERT_TRUE(dispatcher.EnqueueAndStep(shared));
|
||||
ASSERT_EQ(CompileJobStatus::kReadyToCompile,
|
||||
GetJobStatus(dispatcher.jobs_.begin()->second));
|
||||
ASSERT_EQ(UnoptimizedCompileJob::Status::kReadyToCompile,
|
||||
GetUnoptimizedJobStatus(dispatcher.jobs_.begin()->second));
|
||||
|
||||
ASSERT_TRUE(platform.IdleTaskPending());
|
||||
ASSERT_TRUE(platform.BackgroundTasksPending());
|
||||
@ -1219,20 +1221,20 @@ TEST_F(CompilerDispatcherTest, CompileMultipleOnBackgroundThread) {
|
||||
ASSERT_TRUE(platform.IdleTaskPending());
|
||||
|
||||
ASSERT_EQ(dispatcher.jobs_.size(), 2u);
|
||||
ASSERT_EQ(CompileJobStatus::kInitial,
|
||||
GetJobStatus(dispatcher.jobs_.begin()->second));
|
||||
ASSERT_EQ(CompileJobStatus::kInitial,
|
||||
GetJobStatus((++dispatcher.jobs_.begin())->second));
|
||||
ASSERT_EQ(UnoptimizedCompileJob::Status::kInitial,
|
||||
GetUnoptimizedJobStatus(dispatcher.jobs_.begin()->second));
|
||||
ASSERT_EQ(UnoptimizedCompileJob::Status::kInitial,
|
||||
GetUnoptimizedJobStatus((++dispatcher.jobs_.begin())->second));
|
||||
|
||||
// Make compiling super expensive, and advance job as much as possible on the
|
||||
// foreground thread.
|
||||
dispatcher.tracer_->RecordCompile(50000.0);
|
||||
platform.RunIdleTask(10.0, 0.0);
|
||||
ASSERT_EQ(dispatcher.jobs_.size(), 2u);
|
||||
ASSERT_EQ(CompileJobStatus::kReadyToCompile,
|
||||
GetJobStatus(dispatcher.jobs_.begin()->second));
|
||||
ASSERT_EQ(CompileJobStatus::kReadyToCompile,
|
||||
GetJobStatus((++dispatcher.jobs_.begin())->second));
|
||||
ASSERT_EQ(UnoptimizedCompileJob::Status::kReadyToCompile,
|
||||
GetUnoptimizedJobStatus(dispatcher.jobs_.begin()->second));
|
||||
ASSERT_EQ(UnoptimizedCompileJob::Status::kReadyToCompile,
|
||||
GetUnoptimizedJobStatus((++dispatcher.jobs_.begin())->second));
|
||||
|
||||
ASSERT_TRUE(dispatcher.IsEnqueued(shared1));
|
||||
ASSERT_TRUE(dispatcher.IsEnqueued(shared2));
|
||||
@ -1246,10 +1248,10 @@ TEST_F(CompilerDispatcherTest, CompileMultipleOnBackgroundThread) {
|
||||
ASSERT_TRUE(platform.IdleTaskPending());
|
||||
ASSERT_FALSE(platform.BackgroundTasksPending());
|
||||
ASSERT_EQ(dispatcher.jobs_.size(), 2u);
|
||||
ASSERT_EQ(CompileJobStatus::kCompiled,
|
||||
GetJobStatus(dispatcher.jobs_.begin()->second));
|
||||
ASSERT_EQ(CompileJobStatus::kCompiled,
|
||||
GetJobStatus((++dispatcher.jobs_.begin())->second));
|
||||
ASSERT_EQ(UnoptimizedCompileJob::Status::kCompiled,
|
||||
GetUnoptimizedJobStatus(dispatcher.jobs_.begin()->second));
|
||||
ASSERT_EQ(UnoptimizedCompileJob::Status::kCompiled,
|
||||
GetUnoptimizedJobStatus((++dispatcher.jobs_.begin())->second));
|
||||
|
||||
// Now grant a lot of idle time and freeze time.
|
||||
platform.RunIdleTask(1000.0, 0.0);
|
||||
|
@ -22,10 +22,10 @@
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
class CompilerDispatcherJobTest : public TestWithContext {
|
||||
class UnoptimizedCompileJobTest : public TestWithContext {
|
||||
public:
|
||||
CompilerDispatcherJobTest() : tracer_(i_isolate()) {}
|
||||
~CompilerDispatcherJobTest() override {}
|
||||
UnoptimizedCompileJobTest() : tracer_(i_isolate()) {}
|
||||
~UnoptimizedCompileJobTest() override {}
|
||||
|
||||
CompilerDispatcherTracer* tracer() { return &tracer_; }
|
||||
|
||||
@ -43,16 +43,16 @@ class CompilerDispatcherJobTest : public TestWithContext {
|
||||
save_flags_ = nullptr;
|
||||
}
|
||||
|
||||
static CompileJobStatus GetStatus(CompilerDispatcherJob* job) {
|
||||
static UnoptimizedCompileJob::Status GetStatus(UnoptimizedCompileJob* job) {
|
||||
return job->status();
|
||||
}
|
||||
|
||||
static CompileJobStatus GetStatus(
|
||||
const std::unique_ptr<CompilerDispatcherJob>& job) {
|
||||
static UnoptimizedCompileJob::Status GetStatus(
|
||||
const std::unique_ptr<UnoptimizedCompileJob>& job) {
|
||||
return GetStatus(job.get());
|
||||
}
|
||||
|
||||
static Variable* LookupVariableByName(CompilerDispatcherJob* job,
|
||||
static Variable* LookupVariableByName(UnoptimizedCompileJob* job,
|
||||
const char* name) {
|
||||
const AstRawString* name_raw_string =
|
||||
job->parse_info_->ast_value_factory()->GetOneByteString(name);
|
||||
@ -63,10 +63,10 @@ class CompilerDispatcherJobTest : public TestWithContext {
|
||||
CompilerDispatcherTracer tracer_;
|
||||
static SaveFlags* save_flags_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(CompilerDispatcherJobTest);
|
||||
DISALLOW_COPY_AND_ASSIGN(UnoptimizedCompileJobTest);
|
||||
};
|
||||
|
||||
SaveFlags* CompilerDispatcherJobTest::save_flags_ = nullptr;
|
||||
SaveFlags* UnoptimizedCompileJobTest::save_flags_ = nullptr;
|
||||
|
||||
namespace {
|
||||
|
||||
@ -76,17 +76,17 @@ const char test_script[] = "(x) { x*x; }";
|
||||
|
||||
#define ASSERT_JOB_STATUS(STATUS, JOB) ASSERT_EQ(STATUS, GetStatus(JOB))
|
||||
|
||||
TEST_F(CompilerDispatcherJobTest, Construct) {
|
||||
std::unique_ptr<CompilerDispatcherJob> job(new CompilerDispatcherJob(
|
||||
TEST_F(UnoptimizedCompileJobTest, Construct) {
|
||||
std::unique_ptr<UnoptimizedCompileJob> job(new UnoptimizedCompileJob(
|
||||
i_isolate(), tracer(),
|
||||
test::CreateSharedFunctionInfo(i_isolate(), nullptr), FLAG_stack_size));
|
||||
}
|
||||
|
||||
TEST_F(CompilerDispatcherJobTest, ConstructWithoutSFI) {
|
||||
TEST_F(UnoptimizedCompileJobTest, ConstructWithoutSFI) {
|
||||
std::unique_ptr<test::FinishCallback> callback(new test::FinishCallback());
|
||||
std::unique_ptr<test::ScriptResource> resource(
|
||||
new test::ScriptResource(test_script, strlen(test_script)));
|
||||
std::unique_ptr<CompilerDispatcherJob> job(new CompilerDispatcherJob(
|
||||
std::unique_ptr<UnoptimizedCompileJob> job(new UnoptimizedCompileJob(
|
||||
tracer(), FLAG_stack_size,
|
||||
test::CreateSource(i_isolate(), resource.get()), 0,
|
||||
static_cast<int>(resource->length()), SLOPPY, 1, false, false, false,
|
||||
@ -95,60 +95,60 @@ TEST_F(CompilerDispatcherJobTest, ConstructWithoutSFI) {
|
||||
callback.get()));
|
||||
}
|
||||
|
||||
TEST_F(CompilerDispatcherJobTest, StateTransitions) {
|
||||
std::unique_ptr<CompilerDispatcherJob> job(new CompilerDispatcherJob(
|
||||
TEST_F(UnoptimizedCompileJobTest, StateTransitions) {
|
||||
std::unique_ptr<UnoptimizedCompileJob> job(new UnoptimizedCompileJob(
|
||||
i_isolate(), tracer(),
|
||||
test::CreateSharedFunctionInfo(i_isolate(), nullptr), FLAG_stack_size));
|
||||
|
||||
ASSERT_JOB_STATUS(CompileJobStatus::kInitial, job);
|
||||
ASSERT_JOB_STATUS(UnoptimizedCompileJob::Status::kInitial, job);
|
||||
job->StepNextOnMainThread();
|
||||
ASSERT_FALSE(job->IsFailed());
|
||||
ASSERT_JOB_STATUS(CompileJobStatus::kReadyToParse, job);
|
||||
ASSERT_JOB_STATUS(UnoptimizedCompileJob::Status::kReadyToParse, job);
|
||||
job->StepNextOnMainThread();
|
||||
ASSERT_FALSE(job->IsFailed());
|
||||
ASSERT_JOB_STATUS(CompileJobStatus::kParsed, job);
|
||||
ASSERT_JOB_STATUS(UnoptimizedCompileJob::Status::kParsed, job);
|
||||
job->StepNextOnMainThread();
|
||||
ASSERT_FALSE(job->IsFailed());
|
||||
ASSERT_JOB_STATUS(CompileJobStatus::kReadyToAnalyze, job);
|
||||
ASSERT_JOB_STATUS(UnoptimizedCompileJob::Status::kReadyToAnalyze, job);
|
||||
job->StepNextOnMainThread();
|
||||
ASSERT_FALSE(job->IsFailed());
|
||||
ASSERT_JOB_STATUS(CompileJobStatus::kAnalyzed, job);
|
||||
ASSERT_JOB_STATUS(UnoptimizedCompileJob::Status::kAnalyzed, job);
|
||||
job->StepNextOnMainThread();
|
||||
ASSERT_FALSE(job->IsFailed());
|
||||
ASSERT_JOB_STATUS(CompileJobStatus::kReadyToCompile, job);
|
||||
ASSERT_JOB_STATUS(UnoptimizedCompileJob::Status::kReadyToCompile, job);
|
||||
job->StepNextOnMainThread();
|
||||
ASSERT_FALSE(job->IsFailed());
|
||||
ASSERT_JOB_STATUS(CompileJobStatus::kCompiled, job);
|
||||
ASSERT_JOB_STATUS(UnoptimizedCompileJob::Status::kCompiled, job);
|
||||
job->StepNextOnMainThread();
|
||||
ASSERT_FALSE(job->IsFailed());
|
||||
ASSERT_JOB_STATUS(CompileJobStatus::kDone, job);
|
||||
ASSERT_JOB_STATUS(UnoptimizedCompileJob::Status::kDone, job);
|
||||
job->ResetOnMainThread();
|
||||
ASSERT_JOB_STATUS(CompileJobStatus::kInitial, job);
|
||||
ASSERT_JOB_STATUS(UnoptimizedCompileJob::Status::kInitial, job);
|
||||
}
|
||||
|
||||
TEST_F(CompilerDispatcherJobTest, StateTransitionsParseWithCallback) {
|
||||
TEST_F(UnoptimizedCompileJobTest, StateTransitionsParseWithCallback) {
|
||||
std::unique_ptr<test::FinishCallback> callback(new test::FinishCallback());
|
||||
std::unique_ptr<test::ScriptResource> resource(
|
||||
new test::ScriptResource(test_script, strlen(test_script)));
|
||||
std::unique_ptr<CompilerDispatcherJob> job(new CompilerDispatcherJob(
|
||||
std::unique_ptr<UnoptimizedCompileJob> job(new UnoptimizedCompileJob(
|
||||
tracer(), FLAG_stack_size,
|
||||
test::CreateSource(i_isolate(), resource.get()), 0,
|
||||
static_cast<int>(resource->length()), SLOPPY, 1, false, false, false,
|
||||
i_isolate()->heap()->HashSeed(), i_isolate()->allocator(),
|
||||
ScriptCompiler::kNoCompileOptions, i_isolate()->ast_string_constants(),
|
||||
callback.get()));
|
||||
ASSERT_JOB_STATUS(CompileJobStatus::kReadyToParse, job);
|
||||
job->StepNextOnMainThread();
|
||||
ASSERT_JOB_STATUS(UnoptimizedCompileJob::Status::kReadyToParse, job);
|
||||
job->StepNextOnBackgroundThread();
|
||||
ASSERT_FALSE(job->IsFailed());
|
||||
ASSERT_JOB_STATUS(CompileJobStatus::kDone, job);
|
||||
ASSERT_JOB_STATUS(UnoptimizedCompileJob::Status::kDone, job);
|
||||
job->ResetOnMainThread();
|
||||
ASSERT_JOB_STATUS(CompileJobStatus::kInitial, job);
|
||||
ASSERT_JOB_STATUS(UnoptimizedCompileJob::Status::kInitial, job);
|
||||
ASSERT_TRUE(callback->result() != nullptr);
|
||||
}
|
||||
|
||||
TEST_F(CompilerDispatcherJobTest, SyntaxError) {
|
||||
TEST_F(UnoptimizedCompileJobTest, SyntaxError) {
|
||||
test::ScriptResource script("^^^", strlen("^^^"));
|
||||
std::unique_ptr<CompilerDispatcherJob> job(new CompilerDispatcherJob(
|
||||
std::unique_ptr<UnoptimizedCompileJob> job(new UnoptimizedCompileJob(
|
||||
i_isolate(), tracer(),
|
||||
test::CreateSharedFunctionInfo(i_isolate(), &script), FLAG_stack_size));
|
||||
|
||||
@ -158,23 +158,23 @@ TEST_F(CompilerDispatcherJobTest, SyntaxError) {
|
||||
ASSERT_FALSE(job->IsFailed());
|
||||
job->StepNextOnMainThread();
|
||||
ASSERT_TRUE(job->IsFailed());
|
||||
ASSERT_JOB_STATUS(CompileJobStatus::kFailed, job);
|
||||
ASSERT_JOB_STATUS(UnoptimizedCompileJob::Status::kFailed, job);
|
||||
ASSERT_TRUE(i_isolate()->has_pending_exception());
|
||||
|
||||
i_isolate()->clear_pending_exception();
|
||||
|
||||
job->ResetOnMainThread();
|
||||
ASSERT_JOB_STATUS(CompileJobStatus::kInitial, job);
|
||||
ASSERT_JOB_STATUS(UnoptimizedCompileJob::Status::kInitial, job);
|
||||
}
|
||||
|
||||
TEST_F(CompilerDispatcherJobTest, ScopeChain) {
|
||||
TEST_F(UnoptimizedCompileJobTest, ScopeChain) {
|
||||
const char script[] =
|
||||
"function g() { var y = 1; function f(x) { return x * y }; return f; } "
|
||||
"g();";
|
||||
Handle<JSFunction> f =
|
||||
Handle<JSFunction>::cast(test::RunJS(isolate(), script));
|
||||
|
||||
std::unique_ptr<CompilerDispatcherJob> job(new CompilerDispatcherJob(
|
||||
std::unique_ptr<UnoptimizedCompileJob> job(new UnoptimizedCompileJob(
|
||||
i_isolate(), tracer(), handle(f->shared()), FLAG_stack_size));
|
||||
|
||||
job->StepNextOnMainThread();
|
||||
@ -187,7 +187,7 @@ TEST_F(CompilerDispatcherJobTest, ScopeChain) {
|
||||
ASSERT_FALSE(job->IsFailed());
|
||||
job->StepNextOnMainThread();
|
||||
ASSERT_FALSE(job->IsFailed());
|
||||
ASSERT_JOB_STATUS(CompileJobStatus::kReadyToCompile, job);
|
||||
ASSERT_JOB_STATUS(UnoptimizedCompileJob::Status::kReadyToCompile, job);
|
||||
|
||||
Variable* var = LookupVariableByName(job.get(), "x");
|
||||
ASSERT_TRUE(var);
|
||||
@ -198,10 +198,10 @@ TEST_F(CompilerDispatcherJobTest, ScopeChain) {
|
||||
ASSERT_TRUE(var->IsContextSlot());
|
||||
|
||||
job->ResetOnMainThread();
|
||||
ASSERT_JOB_STATUS(CompileJobStatus::kInitial, job);
|
||||
ASSERT_JOB_STATUS(UnoptimizedCompileJob::Status::kInitial, job);
|
||||
}
|
||||
|
||||
TEST_F(CompilerDispatcherJobTest, CompileAndRun) {
|
||||
TEST_F(UnoptimizedCompileJobTest, CompileAndRun) {
|
||||
const char script[] =
|
||||
"function g() {\n"
|
||||
" f = function(a) {\n"
|
||||
@ -213,7 +213,7 @@ TEST_F(CompilerDispatcherJobTest, CompileAndRun) {
|
||||
"g();";
|
||||
Handle<JSFunction> f =
|
||||
Handle<JSFunction>::cast(test::RunJS(isolate(), script));
|
||||
std::unique_ptr<CompilerDispatcherJob> job(new CompilerDispatcherJob(
|
||||
std::unique_ptr<UnoptimizedCompileJob> job(new UnoptimizedCompileJob(
|
||||
i_isolate(), tracer(), handle(f->shared()), FLAG_stack_size));
|
||||
|
||||
job->StepNextOnMainThread();
|
||||
@ -230,23 +230,23 @@ TEST_F(CompilerDispatcherJobTest, CompileAndRun) {
|
||||
ASSERT_FALSE(job->IsFailed());
|
||||
job->StepNextOnMainThread();
|
||||
ASSERT_FALSE(job->IsFailed());
|
||||
ASSERT_JOB_STATUS(CompileJobStatus::kDone, job);
|
||||
ASSERT_JOB_STATUS(UnoptimizedCompileJob::Status::kDone, job);
|
||||
|
||||
Smi* value = Smi::cast(*test::RunJS(isolate(), "f(100);"));
|
||||
ASSERT_TRUE(value == Smi::FromInt(160));
|
||||
|
||||
job->ResetOnMainThread();
|
||||
ASSERT_JOB_STATUS(CompileJobStatus::kInitial, job);
|
||||
ASSERT_JOB_STATUS(UnoptimizedCompileJob::Status::kInitial, job);
|
||||
}
|
||||
|
||||
TEST_F(CompilerDispatcherJobTest, CompileFailureToAnalyse) {
|
||||
TEST_F(UnoptimizedCompileJobTest, CompileFailureToAnalyse) {
|
||||
std::string raw_script("() { var a = ");
|
||||
for (int i = 0; i < 100000; i++) {
|
||||
raw_script += "'x' + ";
|
||||
}
|
||||
raw_script += " 'x'; }";
|
||||
test::ScriptResource script(raw_script.c_str(), strlen(raw_script.c_str()));
|
||||
std::unique_ptr<CompilerDispatcherJob> job(new CompilerDispatcherJob(
|
||||
std::unique_ptr<UnoptimizedCompileJob> job(new UnoptimizedCompileJob(
|
||||
i_isolate(), tracer(),
|
||||
test::CreateSharedFunctionInfo(i_isolate(), &script), 100));
|
||||
|
||||
@ -258,22 +258,22 @@ TEST_F(CompilerDispatcherJobTest, CompileFailureToAnalyse) {
|
||||
ASSERT_FALSE(job->IsFailed());
|
||||
job->StepNextOnMainThread();
|
||||
ASSERT_TRUE(job->IsFailed());
|
||||
ASSERT_JOB_STATUS(CompileJobStatus::kFailed, job);
|
||||
ASSERT_JOB_STATUS(UnoptimizedCompileJob::Status::kFailed, job);
|
||||
ASSERT_TRUE(i_isolate()->has_pending_exception());
|
||||
|
||||
i_isolate()->clear_pending_exception();
|
||||
job->ResetOnMainThread();
|
||||
ASSERT_JOB_STATUS(CompileJobStatus::kInitial, job);
|
||||
ASSERT_JOB_STATUS(UnoptimizedCompileJob::Status::kInitial, job);
|
||||
}
|
||||
|
||||
TEST_F(CompilerDispatcherJobTest, CompileFailureToFinalize) {
|
||||
TEST_F(UnoptimizedCompileJobTest, CompileFailureToFinalize) {
|
||||
std::string raw_script("() { var a = ");
|
||||
for (int i = 0; i < 1000; i++) {
|
||||
raw_script += "'x' + ";
|
||||
}
|
||||
raw_script += " 'x'; }";
|
||||
test::ScriptResource script(raw_script.c_str(), strlen(raw_script.c_str()));
|
||||
std::unique_ptr<CompilerDispatcherJob> job(new CompilerDispatcherJob(
|
||||
std::unique_ptr<UnoptimizedCompileJob> job(new UnoptimizedCompileJob(
|
||||
i_isolate(), tracer(),
|
||||
test::CreateSharedFunctionInfo(i_isolate(), &script), 50));
|
||||
|
||||
@ -291,17 +291,17 @@ TEST_F(CompilerDispatcherJobTest, CompileFailureToFinalize) {
|
||||
ASSERT_FALSE(job->IsFailed());
|
||||
job->StepNextOnMainThread();
|
||||
ASSERT_TRUE(job->IsFailed());
|
||||
ASSERT_JOB_STATUS(CompileJobStatus::kFailed, job);
|
||||
ASSERT_JOB_STATUS(UnoptimizedCompileJob::Status::kFailed, job);
|
||||
ASSERT_TRUE(i_isolate()->has_pending_exception());
|
||||
|
||||
i_isolate()->clear_pending_exception();
|
||||
job->ResetOnMainThread();
|
||||
ASSERT_JOB_STATUS(CompileJobStatus::kInitial, job);
|
||||
ASSERT_JOB_STATUS(UnoptimizedCompileJob::Status::kInitial, job);
|
||||
}
|
||||
|
||||
class CompileTask : public Task {
|
||||
public:
|
||||
CompileTask(CompilerDispatcherJob* job, base::Semaphore* semaphore)
|
||||
CompileTask(UnoptimizedCompileJob* job, base::Semaphore* semaphore)
|
||||
: job_(job), semaphore_(semaphore) {}
|
||||
~CompileTask() override {}
|
||||
|
||||
@ -312,12 +312,12 @@ class CompileTask : public Task {
|
||||
}
|
||||
|
||||
private:
|
||||
CompilerDispatcherJob* job_;
|
||||
UnoptimizedCompileJob* job_;
|
||||
base::Semaphore* semaphore_;
|
||||
DISALLOW_COPY_AND_ASSIGN(CompileTask);
|
||||
};
|
||||
|
||||
TEST_F(CompilerDispatcherJobTest, CompileOnBackgroundThread) {
|
||||
TEST_F(UnoptimizedCompileJobTest, CompileOnBackgroundThread) {
|
||||
const char* raw_script =
|
||||
"(a, b) {\n"
|
||||
" var c = a + b;\n"
|
||||
@ -326,7 +326,7 @@ TEST_F(CompilerDispatcherJobTest, CompileOnBackgroundThread) {
|
||||
" return bar;"
|
||||
"}";
|
||||
test::ScriptResource script(raw_script, strlen(raw_script));
|
||||
std::unique_ptr<CompilerDispatcherJob> job(new CompilerDispatcherJob(
|
||||
std::unique_ptr<UnoptimizedCompileJob> job(new UnoptimizedCompileJob(
|
||||
i_isolate(), tracer(),
|
||||
test::CreateSharedFunctionInfo(i_isolate(), &script), 100));
|
||||
|
||||
@ -343,19 +343,19 @@ TEST_F(CompilerDispatcherJobTest, CompileOnBackgroundThread) {
|
||||
|
||||
base::Semaphore semaphore(0);
|
||||
CompileTask* background_task = new CompileTask(job.get(), &semaphore);
|
||||
ASSERT_JOB_STATUS(CompileJobStatus::kReadyToCompile, job);
|
||||
ASSERT_JOB_STATUS(UnoptimizedCompileJob::Status::kReadyToCompile, job);
|
||||
V8::GetCurrentPlatform()->CallOnBackgroundThread(background_task,
|
||||
Platform::kShortRunningTask);
|
||||
semaphore.Wait();
|
||||
job->StepNextOnMainThread();
|
||||
ASSERT_FALSE(job->IsFailed());
|
||||
ASSERT_JOB_STATUS(CompileJobStatus::kDone, job);
|
||||
ASSERT_JOB_STATUS(UnoptimizedCompileJob::Status::kDone, job);
|
||||
|
||||
job->ResetOnMainThread();
|
||||
ASSERT_JOB_STATUS(CompileJobStatus::kInitial, job);
|
||||
ASSERT_JOB_STATUS(UnoptimizedCompileJob::Status::kInitial, job);
|
||||
}
|
||||
|
||||
TEST_F(CompilerDispatcherJobTest, LazyInnerFunctions) {
|
||||
TEST_F(UnoptimizedCompileJobTest, LazyInnerFunctions) {
|
||||
const char script[] =
|
||||
"function g() {\n"
|
||||
" f = function() {\n"
|
||||
@ -368,7 +368,7 @@ TEST_F(CompilerDispatcherJobTest, LazyInnerFunctions) {
|
||||
Handle<JSFunction> f =
|
||||
Handle<JSFunction>::cast(test::RunJS(isolate(), script));
|
||||
|
||||
std::unique_ptr<CompilerDispatcherJob> job(new CompilerDispatcherJob(
|
||||
std::unique_ptr<UnoptimizedCompileJob> job(new UnoptimizedCompileJob(
|
||||
i_isolate(), tracer(), handle(f->shared()), FLAG_stack_size));
|
||||
|
||||
job->StepNextOnMainThread();
|
||||
@ -385,7 +385,7 @@ TEST_F(CompilerDispatcherJobTest, LazyInnerFunctions) {
|
||||
ASSERT_FALSE(job->IsFailed());
|
||||
job->StepNextOnMainThread();
|
||||
ASSERT_FALSE(job->IsFailed());
|
||||
ASSERT_JOB_STATUS(CompileJobStatus::kDone, job);
|
||||
ASSERT_JOB_STATUS(UnoptimizedCompileJob::Status::kDone, job);
|
||||
|
||||
Handle<JSFunction> e =
|
||||
Handle<JSFunction>::cast(test::RunJS(isolate(), "f();"));
|
||||
@ -393,7 +393,7 @@ TEST_F(CompilerDispatcherJobTest, LazyInnerFunctions) {
|
||||
ASSERT_FALSE(e->shared()->HasBaselineCode());
|
||||
|
||||
job->ResetOnMainThread();
|
||||
ASSERT_JOB_STATUS(CompileJobStatus::kInitial, job);
|
||||
ASSERT_JOB_STATUS(UnoptimizedCompileJob::Status::kInitial, job);
|
||||
}
|
||||
|
||||
} // namespace internal
|
@ -40,7 +40,7 @@ class ScriptResource : public v8::String::ExternalOneByteStringResource {
|
||||
DISALLOW_COPY_AND_ASSIGN(ScriptResource);
|
||||
};
|
||||
|
||||
class FinishCallback : public CompileJobFinishCallback {
|
||||
class FinishCallback : public UnoptimizedCompileJobFinishCallback {
|
||||
public:
|
||||
void ParseFinished(std::unique_ptr<ParseInfo> result) override {
|
||||
result_ = std::move(result);
|
||||
|
@ -90,10 +90,10 @@
|
||||
'compiler/typer-unittest.cc',
|
||||
'compiler/value-numbering-reducer-unittest.cc',
|
||||
'compiler/zone-stats-unittest.cc',
|
||||
'compiler-dispatcher/compiler-dispatcher-job-unittest.cc',
|
||||
'compiler-dispatcher/compiler-dispatcher-tracer-unittest.cc',
|
||||
'compiler-dispatcher/compiler-dispatcher-unittest.cc',
|
||||
'compiler-dispatcher/optimizing-compile-dispatcher-unittest.cc',
|
||||
'compiler-dispatcher/unoptimized-compile-job-unittest.cc',
|
||||
'counters-unittest.cc',
|
||||
'eh-frame-iterator-unittest.cc',
|
||||
'eh-frame-writer-unittest.cc',
|
||||
|
Loading…
Reference in New Issue
Block a user