Commit c2d2d4d1 authored by rmcilroy's avatar rmcilroy Committed by Commit bot

[Compiler] Add compile operations to CompilerDispatcherJob.

Adds compile operations to the CompilerDispatcherJob interface. As such,
introduces Compiler::PrepareUnoptimizedCompilationJob and updates the
unoptimized compilation path to use CompilationJobs. Also unifies
FinalizeCompilationJob to deal with both optimized and unoptimized
compilation jobs.

A dummy FullCodegenCompilationJob is also introduced, where all the work
is done in the ExecuteJob phase, which cannot be run on a
background thread.

BUG=v8:5203

Review-Url: https://codereview.chromium.org/2251713002
Cr-Commit-Position: refs/heads/master@{#38897}
parent 25f3de99
......@@ -5,6 +5,7 @@
#include "src/compiler-dispatcher/compiler-dispatcher-job.h"
#include "src/assert-scope.h"
#include "src/compiler.h"
#include "src/global-handles.h"
#include "src/isolate.h"
#include "src/objects-inl.h"
......@@ -23,7 +24,8 @@ CompilerDispatcherJob::CompilerDispatcherJob(Isolate* isolate,
: isolate_(isolate),
function_(Handle<JSFunction>::cast(
isolate_->global_handles()->Create(*function))),
max_stack_size_(max_stack_size) {
max_stack_size_(max_stack_size),
can_compile_on_background_thread_(false) {
HandleScope scope(isolate_);
Handle<SharedFunctionInfo> shared(function_->shared(), isolate_);
Handle<Script> script(Script::cast(shared->script()), isolate_);
......@@ -131,7 +133,7 @@ bool CompilerDispatcherJob::FinalizeParsingOnMainThread() {
if (parse_info_->literal() == nullptr) {
status_ = CompileJobStatus::kFailed;
} else {
status_ = CompileJobStatus::kReadyToCompile;
status_ = CompileJobStatus::kReadyToAnalyse;
}
DeferredHandleScope scope(isolate_);
......@@ -146,6 +148,7 @@ bool CompilerDispatcherJob::FinalizeParsingOnMainThread() {
parse_info_->set_script(script);
parse_info_->set_context(handle(function_->context(), isolate_));
parse_info_->set_shared_info(handle(function_->shared(), isolate_));
// Do the parsing tasks which need to be done on the main thread. This will
// also handle parse errors.
......@@ -163,6 +166,79 @@ bool CompilerDispatcherJob::FinalizeParsingOnMainThread() {
return status_ != CompileJobStatus::kFailed;
}
bool CompilerDispatcherJob::PrepareToCompileOnMainThread() {
DCHECK(ThreadId::Current().Equals(isolate_->thread_id()));
DCHECK(status() == CompileJobStatus::kReadyToAnalyse);
compile_info_.reset(new CompilationInfo(parse_info_.get(), function_));
DeferredHandleScope scope(isolate_);
{
// Create a canonical handle scope before ast numbering if compiling
// bytecode. This is required for off-thread bytecode generation.
std::unique_ptr<CanonicalHandleScope> canonical;
if (FLAG_ignition) canonical.reset(new CanonicalHandleScope(isolate_));
if (Compiler::Analyze(parse_info_.get())) {
compile_job_.reset(
Compiler::PrepareUnoptimizedCompilationJob(compile_info_.get()));
}
}
compile_info_->set_deferred_handles(scope.Detach());
if (!compile_job_.get()) {
if (!isolate_->has_pending_exception()) isolate_->StackOverflow();
status_ = CompileJobStatus::kFailed;
return false;
}
can_compile_on_background_thread_ =
compile_job_->can_execute_on_background_thread();
status_ = CompileJobStatus::kReadyToCompile;
return true;
}
void CompilerDispatcherJob::Compile() {
DCHECK(status() == CompileJobStatus::kReadyToCompile);
DCHECK(can_compile_on_background_thread_ ||
ThreadId::Current().Equals(isolate_->thread_id()));
// Disallowing of handle dereference and heap access dealt with in
// CompilationJob::ExecuteJob.
uintptr_t stack_limit =
reinterpret_cast<uintptr_t>(&stack_limit) - 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;
}
bool CompilerDispatcherJob::FinalizeCompilingOnMainThread() {
DCHECK(ThreadId::Current().Equals(isolate_->thread_id()));
DCHECK(status() == CompileJobStatus::kCompiled);
if (compile_job_->state() == CompilationJob::State::kFailed ||
!Compiler::FinalizeCompilationJob(compile_job_.release())) {
if (!isolate_->has_pending_exception()) isolate_->StackOverflow();
status_ = CompileJobStatus::kFailed;
return false;
}
zone_.reset();
parse_info_.reset();
compile_info_.reset();
compile_job_.reset();
handles_from_parsing_.reset();
status_ = CompileJobStatus::kDone;
return true;
}
void CompilerDispatcherJob::ResetOnMainThread() {
DCHECK(ThreadId::Current().Equals(isolate_->thread_id()));
......@@ -172,6 +248,8 @@ void CompilerDispatcherJob::ResetOnMainThread() {
parse_info_.reset();
zone_.reset();
handles_from_parsing_.reset();
compile_info_.reset();
compile_job_.reset();
if (!source_.is_null()) {
i::GlobalHandles::Destroy(Handle<Object>::cast(source_).location());
......
......@@ -15,6 +15,7 @@ namespace v8 {
namespace internal {
class CompilationInfo;
class CompilationJob;
class Isolate;
class JSFunction;
class ParseInfo;
......@@ -28,7 +29,9 @@ enum class CompileJobStatus {
kInitial,
kReadyToParse,
kParsed,
kReadyToAnalyse,
kReadyToCompile,
kCompiled,
kFailed,
kDone,
};
......@@ -43,6 +46,11 @@ class CompilerDispatcherJob {
bool can_parse_on_background_thread() const {
return can_parse_on_background_thread_;
}
// Should only be called after kReadyToCompile.
bool can_compile_on_background_thread() const {
DCHECK(compile_job_.get());
return can_compile_on_background_thread_;
}
// Transition from kInitial to kReadyToParse.
void PrepareToParseOnMainThread();
......@@ -50,10 +58,21 @@ class CompilerDispatcherJob {
// Transition from kReadyToParse to kParsed.
void Parse();
// Transition from kParsed to kReadyToCompile (or kFailed). Returns false
// Transition from kParsed to kReadyToAnalyse (or kFailed). Returns false
// when transitioning to kFailed. In that case, an exception is pending.
bool FinalizeParsingOnMainThread();
// Transition from kReadyToAnalyse to kReadyToCompile (or kFailed). Returns
// false when transitioning to kFailed. In that case, an exception is pending.
bool PrepareToCompileOnMainThread();
// Transition from kReadyToCompile to kCompiled.
void Compile();
// Transition from kCompiled to kDone (or kFailed). Returns false when
// transitioning to kFailed. In that case, an exception is pending.
bool FinalizeCompilingOnMainThread();
// Transition from any state to kInitial and free all resources.
void ResetOnMainThread();
......@@ -74,7 +93,12 @@ class CompilerDispatcherJob {
std::unique_ptr<Parser> parser_;
std::unique_ptr<DeferredHandles> handles_from_parsing_;
// Members required for compiling.
std::unique_ptr<CompilationInfo> compile_info_;
std::unique_ptr<CompilationJob> compile_job_;
bool can_parse_on_background_thread_;
bool can_compile_on_background_thread_;
DISALLOW_COPY_AND_ASSIGN(CompilerDispatcherJob);
};
......
This diff is collapsed.
......@@ -57,8 +57,12 @@ class Compiler : public AllStatic {
static bool CompileDebugCode(Handle<SharedFunctionInfo> shared);
static MaybeHandle<JSArray> CompileForLiveEdit(Handle<Script> script);
// Prepare a compilation job for unoptimized code. Requires ParseAndAnalyse.
static CompilationJob* PrepareUnoptimizedCompilationJob(
CompilationInfo* info);
// Generate and install code from previously queued compilation job.
static void FinalizeCompilationJob(CompilationJob* job);
static bool FinalizeCompilationJob(CompilationJob* job);
// Give the compiler a chance to perform low-latency initialization tasks of
// the given {function} on its instantiation. Note that only the runtime will
......@@ -557,15 +561,20 @@ class CompilationJob {
kFailed,
};
explicit CompilationJob(CompilationInfo* info, const char* compiler_name,
State initial_state = State::kReadyToPrepare)
: info_(info), compiler_name_(compiler_name), state_(initial_state) {}
CompilationJob(Isolate* isolate, CompilationInfo* info,
const char* compiler_name,
State initial_state = State::kReadyToPrepare)
: info_(info),
compiler_name_(compiler_name),
state_(initial_state),
stack_limit_(isolate->stack_guard()->real_climit()) {}
virtual ~CompilationJob() {}
// Prepare the compile job. Must be called on the main thread.
MUST_USE_RESULT Status PrepareJob();
// Executes the compile job. Can be called off the main thread.
// Executes the compile job. Can be called on a background thread if
// can_execute_on_background_thread() returns true.
MUST_USE_RESULT Status ExecuteJob();
// Finalizes the compile job. Must be called on the main thread.
......@@ -589,7 +598,13 @@ class CompilationJob {
return FAILED;
}
void RecordOptimizationStats();
void RecordOptimizedCompilationStats() const;
void RecordUnoptimizedCompilationStats() const;
virtual bool can_execute_on_background_thread() const { return true; }
void set_stack_limit(uintptr_t stack_limit) { stack_limit_ = stack_limit; }
uintptr_t stack_limit() const { return stack_limit_; }
State state() const { return state_; }
CompilationInfo* info() const { return info_; }
......@@ -612,6 +627,7 @@ class CompilationJob {
base::TimeDelta time_taken_to_finalize_;
const char* compiler_name_;
State state_;
uintptr_t stack_limit_;
MUST_USE_RESULT Status UpdateState(Status status, State next_state) {
if (status == SUCCEEDED) {
......
......@@ -562,7 +562,7 @@ class PipelineCompilationJob final : public CompilationJob {
PipelineCompilationJob(Isolate* isolate, Handle<JSFunction> function)
// Note that the CompilationInfo is not initialized at the time we pass it
// to the CompilationJob constructor, but it is not dereferenced there.
: CompilationJob(&info_, "TurboFan"),
: CompilationJob(isolate, &info_, "TurboFan"),
zone_(isolate->allocator()),
zone_pool_(isolate->allocator()),
parse_info_(&zone_, function),
......@@ -660,7 +660,8 @@ class PipelineWasmCompilationJob final : public CompilationJob {
explicit PipelineWasmCompilationJob(CompilationInfo* info, Graph* graph,
CallDescriptor* descriptor,
SourcePositionTable* source_positions)
: CompilationJob(info, "TurboFan", State::kReadyToExecute),
: CompilationJob(info->isolate(), info, "TurboFan",
State::kReadyToExecute),
zone_pool_(info->isolate()->allocator()),
data_(&zone_pool_, info, graph, source_positions),
pipeline_(&data_),
......
......@@ -35,7 +35,7 @@ class Scope;
class HCompilationJob final : public CompilationJob {
public:
explicit HCompilationJob(Handle<JSFunction> function)
: CompilationJob(&info_, "Crankshaft"),
: CompilationJob(function->GetIsolate(), &info_, "Crankshaft"),
zone_(function->GetIsolate()->allocator()),
parse_info_(&zone_, function),
info_(&parse_info_, function),
......
......@@ -25,7 +25,31 @@ namespace internal {
#define __ ACCESS_MASM(masm())
bool FullCodeGenerator::MakeCode(CompilationInfo* info) {
class FullCodegenCompilationJob final : public CompilationJob {
public:
explicit FullCodegenCompilationJob(CompilationInfo* info)
: CompilationJob(info->isolate(), info, "Full-Codegen") {}
bool can_execute_on_background_thread() const override { return false; }
CompilationJob::Status PrepareJobImpl() final { return SUCCEEDED; }
CompilationJob::Status ExecuteJobImpl() final {
DCHECK(ThreadId::Current().Equals(isolate()->thread_id()));
return FullCodeGenerator::MakeCode(info(), stack_limit()) ? SUCCEEDED
: FAILED;
}
CompilationJob::Status FinalizeJobImpl() final { return SUCCEEDED; }
};
// static
CompilationJob* FullCodeGenerator::NewCompilationJob(CompilationInfo* info) {
return new FullCodegenCompilationJob(info);
}
// static
bool FullCodeGenerator::MakeCode(CompilationInfo* info, uintptr_t stack_limit) {
Isolate* isolate = info->isolate();
DCHECK(!FLAG_minimal);
......@@ -47,7 +71,7 @@ bool FullCodeGenerator::MakeCode(CompilationInfo* info) {
CodeObjectRequired::kYes);
if (info->will_serialize()) masm.enable_serializer();
FullCodeGenerator cgen(&masm, info);
FullCodeGenerator cgen(&masm, info, stack_limit);
cgen.Generate();
if (cgen.HasStackOverflow()) {
DCHECK(!isolate->has_pending_exception());
......@@ -157,9 +181,8 @@ bool FullCodeGenerator::MustCreateArrayLiteralWithRuntime(
expr->values()->length() > JSArray::kInitialMaxFastElementArray;
}
void FullCodeGenerator::Initialize() {
InitializeAstVisitor(info_->isolate());
void FullCodeGenerator::Initialize(uintptr_t stack_limit) {
InitializeAstVisitor(stack_limit);
masm_->set_emit_debug_code(FLAG_debug_code);
masm_->set_predictable_code_size(true);
}
......
......@@ -29,7 +29,8 @@ class JumpPatchSite;
class FullCodeGenerator final : public AstVisitor<FullCodeGenerator> {
public:
FullCodeGenerator(MacroAssembler* masm, CompilationInfo* info)
FullCodeGenerator(MacroAssembler* masm, CompilationInfo* info,
uintptr_t stack_limit)
: masm_(masm),
info_(info),
isolate_(info->isolate()),
......@@ -50,12 +51,17 @@ class FullCodeGenerator final : public AstVisitor<FullCodeGenerator> {
info->SourcePositionRecordingMode()),
ic_total_count_(0) {
DCHECK(!info->IsStub());
Initialize();
Initialize(stack_limit);
}
void Initialize();
void Initialize(uintptr_t stack_limit);
static bool MakeCode(CompilationInfo* info);
static CompilationJob* NewCompilationJob(CompilationInfo* info);
static bool MakeCode(CompilationInfo* info, uintptr_t stack_limit);
static bool MakeCode(CompilationInfo* info) {
return MakeCode(info, info->isolate()->stack_guard()->real_climit());
}
// Encode bailout state and pc-offset as a BitField<type, start, size>.
// Only use 30 bits because we encode the result as a smi.
......
......@@ -683,7 +683,6 @@ BytecodeGenerator::BytecodeGenerator(CompilationInfo* info)
loop_depth_(0),
home_object_symbol_(info->isolate()->factory()->home_object_symbol()),
prototype_string_(info->isolate()->factory()->prototype_string()) {
InitializeAstVisitor(info->isolate()->stack_guard()->real_climit());
}
Handle<BytecodeArray> BytecodeGenerator::FinalizeBytecode(Isolate* isolate) {
......@@ -726,11 +725,13 @@ void BytecodeGenerator::AllocateDeferredConstants() {
}
}
void BytecodeGenerator::GenerateBytecode() {
void BytecodeGenerator::GenerateBytecode(uintptr_t stack_limit) {
DisallowHeapAllocation no_allocation;
DisallowHandleAllocation no_handles;
DisallowHandleDereference no_deref;
InitializeAstVisitor(stack_limit);
// Initialize the incoming context.
ContextScope incoming_context(this, scope(), false);
......
......@@ -24,7 +24,7 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> {
public:
explicit BytecodeGenerator(CompilationInfo* info);
void GenerateBytecode();
void GenerateBytecode(uintptr_t stack_limit);
Handle<BytecodeArray> FinalizeBytecode(Isolate* isolate);
#define DECLARE_VISIT(type) void Visit##type(type* node);
......
......@@ -150,14 +150,40 @@ int Interpreter::InterruptBudget() {
}
InterpreterCompilationJob::InterpreterCompilationJob(CompilationInfo* info)
: CompilationJob(info, "Ignition"), generator_(info) {}
: CompilationJob(info->isolate(), info, "Ignition"), generator_(info) {}
InterpreterCompilationJob::Status InterpreterCompilationJob::PrepareJobImpl() {
if (FLAG_print_bytecode || FLAG_print_ast) {
OFStream os(stdout);
std::unique_ptr<char[]> name = info()->GetDebugName();
os << "[generating bytecode for function: " << info()->GetDebugName().get()
<< "]" << std::endl
<< std::flush;
}
#ifdef DEBUG
if (info()->parse_info() && FLAG_print_ast) {
OFStream os(stdout);
os << "--- AST ---" << std::endl
<< AstPrinter(info()->isolate()).PrintProgram(info()->literal())
<< std::endl
<< std::flush;
}
#endif // DEBUG
return SUCCEEDED;
}
InterpreterCompilationJob::Status InterpreterCompilationJob::ExecuteJobImpl() {
generator()->GenerateBytecode();
// TODO(5203): These timers aren't thread safe, move to using the CompilerJob
// timers.
RuntimeCallTimerScope runtimeTimer(info()->isolate(),
&RuntimeCallStats::CompileIgnition);
TimerEventScope<TimerEventCompileIgnition> timer(info()->isolate());
TRACE_EVENT_RUNTIME_CALL_STATS_TRACING_SCOPED(
info()->isolate(), &tracing::TraceEventStatsTable::CompileIgnition);
generator()->GenerateBytecode(stack_limit());
if (generator()->HasStackOverflow()) {
return FAILED;
......@@ -182,34 +208,8 @@ InterpreterCompilationJob::Status InterpreterCompilationJob::FinalizeJobImpl() {
return SUCCEEDED;
}
bool Interpreter::MakeBytecode(CompilationInfo* info) {
RuntimeCallTimerScope runtimeTimer(info->isolate(),
&RuntimeCallStats::CompileIgnition);
TimerEventScope<TimerEventCompileIgnition> timer(info->isolate());
TRACE_EVENT_RUNTIME_CALL_STATS_TRACING_SCOPED(
info->isolate(), &tracing::TraceEventStatsTable::CompileIgnition);
if (FLAG_print_bytecode || FLAG_print_ast) {
OFStream os(stdout);
std::unique_ptr<char[]> name = info->GetDebugName();
os << "[generating bytecode for function: " << info->GetDebugName().get()
<< "]" << std::endl
<< std::flush;
}
#ifdef DEBUG
if (info->parse_info() && FLAG_print_ast) {
OFStream os(stdout);
os << "--- AST ---" << std::endl
<< AstPrinter(info->isolate()).PrintProgram(info->literal()) << std::endl
<< std::flush;
}
#endif // DEBUG
InterpreterCompilationJob job(info);
if (job.PrepareJob() != CompilationJob::SUCCEEDED) return false;
if (job.ExecuteJob() != CompilationJob::SUCCEEDED) return false;
return job.FinalizeJob() == CompilationJob::SUCCEEDED;
CompilationJob* Interpreter::NewCompilationJob(CompilationInfo* info) {
return new InterpreterCompilationJob(info);
}
bool Interpreter::IsDispatchTableInitialized() {
......
......@@ -22,6 +22,7 @@ namespace internal {
class Isolate;
class Callable;
class CompilationInfo;
class CompilationJob;
namespace compiler {
class Node;
......@@ -42,8 +43,8 @@ class Interpreter {
// Returns the interrupt budget which should be used for the profiler counter.
static int InterruptBudget();
// Generate bytecode for |info|.
static bool MakeBytecode(CompilationInfo* info);
// Creates a compilation job which will generate bytecode for |info|.
static CompilationJob* NewCompilationJob(CompilationInfo* info);
// Return bytecode handler for |bytecode|.
Code* GetBytecodeHandler(Bytecode bytecode, OperandScale operand_scale);
......
......@@ -52,8 +52,8 @@ Handle<JSFunction> CreateFunction(
}
Handle<Script> script = isolate->factory()->NewScript(source);
Handle<SharedFunctionInfo> shared = isolate->factory()->NewSharedFunctionInfo(
isolate->factory()->NewStringFromAsciiChecked("f"), MaybeHandle<Code>(),
false);
isolate->factory()->NewStringFromAsciiChecked("f"),
isolate->builtins()->CompileLazy(), false);
SharedFunctionInfo::SetScript(shared, script);
shared->set_end_position(source->length());
Handle<JSFunction> function =
......@@ -62,6 +62,17 @@ Handle<JSFunction> CreateFunction(
return scope.CloseAndEscape(function);
}
Handle<Object> RunJS(v8::Isolate* isolate, const char* script) {
return Utils::OpenHandle(
*v8::Script::Compile(
isolate->GetCurrentContext(),
v8::String::NewFromUtf8(isolate, script, v8::NewStringType::kNormal)
.ToLocalChecked())
.ToLocalChecked()
->Run(isolate->GetCurrentContext())
.ToLocalChecked());
}
} // namespace
TEST_F(CompilerDispatcherJobTest, Construct) {
......@@ -93,7 +104,13 @@ TEST_F(CompilerDispatcherJobTest, StateTransitions) {
job->Parse();
ASSERT_TRUE(job->status() == CompileJobStatus::kParsed);
ASSERT_TRUE(job->FinalizeParsingOnMainThread());
ASSERT_TRUE(job->status() == CompileJobStatus::kReadyToAnalyse);
ASSERT_TRUE(job->PrepareToCompileOnMainThread());
ASSERT_TRUE(job->status() == CompileJobStatus::kReadyToCompile);
job->Compile();
ASSERT_TRUE(job->status() == CompileJobStatus::kCompiled);
ASSERT_TRUE(job->FinalizeCompilingOnMainThread());
ASSERT_TRUE(job->status() == CompileJobStatus::kDone);
job->ResetOnMainThread();
ASSERT_TRUE(job->status() == CompileJobStatus::kInitial);
}
......@@ -119,14 +136,7 @@ TEST_F(CompilerDispatcherJobTest, ScopeChain) {
const char script[] =
"function g() { var g = 1; function f(x) { return x * g }; return f; } "
"g();";
Handle<JSFunction> f = Handle<JSFunction>::cast(Utils::OpenHandle(
*v8::Script::Compile(isolate()->GetCurrentContext(),
v8::String::NewFromUtf8(isolate(), script,
v8::NewStringType::kNormal)
.ToLocalChecked())
.ToLocalChecked()
->Run(isolate()->GetCurrentContext())
.ToLocalChecked()));
Handle<JSFunction> f = Handle<JSFunction>::cast(RunJS(isolate(), script));
std::unique_ptr<CompilerDispatcherJob> job(
new CompilerDispatcherJob(i_isolate(), f, FLAG_stack_size));
......@@ -134,7 +144,7 @@ TEST_F(CompilerDispatcherJobTest, ScopeChain) {
job->PrepareToParseOnMainThread();
job->Parse();
ASSERT_TRUE(job->FinalizeParsingOnMainThread());
ASSERT_TRUE(job->status() == CompileJobStatus::kReadyToCompile);
ASSERT_TRUE(job->status() == CompileJobStatus::kReadyToAnalyse);
const AstRawString* var_x =
job->parse_info_->ast_value_factory()->GetOneByteString("x");
......@@ -152,5 +162,80 @@ TEST_F(CompilerDispatcherJobTest, ScopeChain) {
ASSERT_TRUE(job->status() == CompileJobStatus::kInitial);
}
TEST_F(CompilerDispatcherJobTest, CompileAndRun) {
const char script[] =
"function g() {\n"
" f = function(a) {\n"
" for (var i = 0; i < 3; i++) { a += 20; }\n"
" return a;\n"
" }\n"
" return f;\n"
"}\n"
"g();";
Handle<JSFunction> f = Handle<JSFunction>::cast(RunJS(isolate(), script));
std::unique_ptr<CompilerDispatcherJob> job(
new CompilerDispatcherJob(i_isolate(), f, FLAG_stack_size));
job->PrepareToParseOnMainThread();
job->Parse();
job->FinalizeParsingOnMainThread();
job->PrepareToCompileOnMainThread();
job->Compile();
ASSERT_TRUE(job->FinalizeCompilingOnMainThread());
ASSERT_TRUE(job->status() == CompileJobStatus::kDone);
Smi* value = Smi::cast(*RunJS(isolate(), "f(100);"));
ASSERT_TRUE(value == Smi::FromInt(160));
job->ResetOnMainThread();
ASSERT_TRUE(job->status() == CompileJobStatus::kInitial);
}
TEST_F(CompilerDispatcherJobTest, CompileFailureToPrepare) {
std::string raw_script("() { var a = ");
for (int i = 0; i < 100000; i++) {
raw_script += "'x' + ";
}
raw_script += " 'x'; }";
ScriptResource script(raw_script.c_str(), strlen(raw_script.c_str()));
std::unique_ptr<CompilerDispatcherJob> job(new CompilerDispatcherJob(
i_isolate(), CreateFunction(i_isolate(), &script), 100));
job->PrepareToParseOnMainThread();
job->Parse();
job->FinalizeParsingOnMainThread();
ASSERT_FALSE(job->PrepareToCompileOnMainThread());
ASSERT_TRUE(job->status() == CompileJobStatus::kFailed);
ASSERT_TRUE(i_isolate()->has_pending_exception());
i_isolate()->clear_pending_exception();
job->ResetOnMainThread();
ASSERT_TRUE(job->status() == CompileJobStatus::kInitial);
}
TEST_F(CompilerDispatcherJobTest, CompileFailureToFinalize) {
std::string raw_script("() { var a = ");
for (int i = 0; i < 1000; i++) {
raw_script += "'x' + ";
}
raw_script += " 'x'; }";
ScriptResource script(raw_script.c_str(), strlen(raw_script.c_str()));
std::unique_ptr<CompilerDispatcherJob> job(new CompilerDispatcherJob(
i_isolate(), CreateFunction(i_isolate(), &script), 100));
job->PrepareToParseOnMainThread();
job->Parse();
job->FinalizeParsingOnMainThread();
job->PrepareToCompileOnMainThread();
job->Compile();
ASSERT_FALSE(job->FinalizeCompilingOnMainThread());
ASSERT_TRUE(job->status() == CompileJobStatus::kFailed);
ASSERT_TRUE(i_isolate()->has_pending_exception());
i_isolate()->clear_pending_exception();
job->ResetOnMainThread();
ASSERT_TRUE(job->status() == CompileJobStatus::kInitial);
}
} // namespace internal
} // namespace v8
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment