[compiler-dispatcher] Just parse functions without SFI.

This is inital work in order to utilize CompilerDispatcher in parallel
parsing.

BUG=v8:6093

Change-Id: I6aae4f32ddb2314585d09039c1c5d7e658dc896f
Reviewed-on: https://chromium-review.googlesource.com/469709
Reviewed-by: Marja Hölttä <marja@chromium.org>
Reviewed-by: Jochen Eisinger <jochen@chromium.org>
Commit-Queue: Wiktor Garbacz <wiktorg@google.com>
Cr-Commit-Position: refs/heads/master@{#44509}
This commit is contained in:
Wiktor Garbacz 2017-04-06 13:58:38 +02:00 committed by Commit Bot
parent 45e152a60d
commit c8bc0cac8d
5 changed files with 162 additions and 28 deletions

View File

@ -61,6 +61,51 @@ class TwoByteWrapper : public v8::String::ExternalStringResource {
} // 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, bool calls_eval, uint32_t hash_seed,
AccountingAllocator* zone_allocator, int compiler_hints,
const AstStringConstants* ast_string_constants,
FinishCallback* 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);
parse_info_->set_native(native);
parse_info_->set_module(module);
parse_info_->set_is_named_expression(is_named_expression);
parse_info_->set_calls_eval(calls_eval);
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,
@ -78,7 +123,7 @@ CompilerDispatcherJob::CompilerDispatcherJob(Isolate* isolate,
Handle<String> source(String::cast(script->source()), isolate_);
if (trace_compiler_dispatcher_jobs_) {
PrintF("CompilerDispatcherJob[%p] created for ", static_cast<void*>(this));
shared_->ShortPrint();
ShortPrint();
PrintF(" in initial state.\n");
}
}
@ -107,17 +152,23 @@ CompilerDispatcherJob::CompilerDispatcherJob(
if (trace_compiler_dispatcher_jobs_) {
PrintF("CompilerDispatcherJob[%p] created for ", static_cast<void*>(this));
shared_->ShortPrint();
ShortPrint();
PrintF(" in Analyzed state.\n");
}
}
CompilerDispatcherJob::~CompilerDispatcherJob() {
DCHECK(ThreadId::Current().Equals(isolate_->thread_id()));
DCHECK(status_ == CompileJobStatus::kInitial ||
(status_ == CompileJobStatus::kReadyToParse && finish_callback_) ||
status_ == CompileJobStatus::kDone);
i::GlobalHandles::Destroy(Handle<Object>::cast(shared_).location());
i::GlobalHandles::Destroy(Handle<Object>::cast(context_).location());
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(
@ -249,7 +300,12 @@ void CompilerDispatcherJob::Parse() {
parser_->set_stack_limit(stack_limit);
parser_->ParseOnBackground(parse_info_.get());
status_ = CompileJobStatus::kParsed;
if (finish_callback_) {
finish_callback_->ParseFinished(std::move(parse_info_));
status_ = CompileJobStatus::kDone;
} else {
status_ = CompileJobStatus::kParsed;
}
}
bool CompilerDispatcherJob::FinalizeParsingOnMainThread() {
@ -402,8 +458,6 @@ bool CompilerDispatcherJob::FinalizeCompilingOnMainThread() {
}
void CompilerDispatcherJob::ResetOnMainThread() {
DCHECK(ThreadId::Current().Equals(isolate_->thread_id()));
if (trace_compiler_dispatcher_jobs_) {
PrintF("CompilerDispatcherJob[%p]: Resetting\n", static_cast<void*>(this));
}
@ -415,12 +469,15 @@ void CompilerDispatcherJob::ResetOnMainThread() {
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();
}
@ -463,8 +520,18 @@ double CompilerDispatcherJob::EstimateRuntimeOfNextStepInMs() const {
}
void CompilerDispatcherJob::ShortPrint() {
DCHECK(ThreadId::Current().Equals(isolate_->thread_id()));
shared_->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

View File

@ -17,6 +17,7 @@ namespace v8 {
namespace internal {
class AstValueFactory;
class AstStringConstants;
class CompilerDispatcherTracer;
class CompilationInfo;
class CompilationJob;
@ -44,10 +45,27 @@ enum class CompileJobStatus {
class V8_EXPORT_PRIVATE CompilerDispatcherJob {
public:
class FinishCallback {
public:
virtual ~FinishCallback() {}
virtual void ParseFinished(std::unique_ptr<ParseInfo> parse_info) = 0;
};
// 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, bool calls_eval,
uint32_t hash_seed, AccountingAllocator* zone_allocator,
int compiler_hints,
const AstStringConstants* ast_string_constants,
FinishCallback* finish_callback);
// Creates a CompilerDispatcherJob in the analyzed state.
CompilerDispatcherJob(Isolate* isolate, CompilerDispatcherTracer* tracer,
Handle<Script> script,
@ -72,7 +90,8 @@ class V8_EXPORT_PRIVATE CompilerDispatcherJob {
// Transition from kInitial to kReadyToParse.
void PrepareToParseOnMainThread();
// Transition from kReadyToParse to kParsed.
// Transition from kReadyToParse to kParsed (or kDone if there is
// finish_callback).
void Parse();
// Transition from kParsed to kReadyToAnalyze (or kFailed). Returns false
@ -116,6 +135,7 @@ class V8_EXPORT_PRIVATE CompilerDispatcherJob {
Handle<String> wrapper_; // Global handle.
std::unique_ptr<v8::String::ExternalStringResourceBase> source_wrapper_;
size_t max_stack_size_;
FinishCallback* finish_callback_ = nullptr;
// Members required for parsing.
std::unique_ptr<UnicodeCache> unicode_cache_;

View File

@ -805,8 +805,8 @@ FunctionLiteral* Parser::ParseFunction(Isolate* isolate, ParseInfo* info) {
std::unique_ptr<Utf16CharacterStream> stream(ScannerStream::For(
source, shared_info->start_position(), shared_info->end_position()));
Handle<String> name(String::cast(shared_info->name()));
result = DoParseFunction(info, ast_value_factory()->GetString(name),
stream.get());
scanner_.Initialize(stream.get());
result = DoParseFunction(info, ast_value_factory()->GetString(name));
if (result != nullptr) {
Handle<String> inferred_name(shared_info->inferred_name());
result->set_inferred_name(inferred_name);
@ -836,9 +836,8 @@ static FunctionLiteral::FunctionType ComputeFunctionType(ParseInfo* info) {
}
FunctionLiteral* Parser::DoParseFunction(ParseInfo* info,
const AstRawString* raw_name,
Utf16CharacterStream* source) {
scanner_.Initialize(source);
const AstRawString* raw_name) {
DCHECK_NOT_NULL(raw_name);
DCHECK_NULL(scope_);
DCHECK_NULL(target_stack_);
@ -3534,6 +3533,7 @@ void Parser::ParseOnBackground(ParseInfo* info) {
runtime_call_stats_));
stream_ptr = stream.get();
}
scanner_.Initialize(stream_ptr);
DCHECK(info->maybe_outer_scope_info().is_null());
DCHECK(original_scope_);
@ -3546,10 +3546,14 @@ void Parser::ParseOnBackground(ParseInfo* info) {
// scopes) and set their end position after we know the script length.
if (info->is_toplevel()) {
fni_ = new (zone()) FuncNameInferrer(ast_value_factory(), zone());
scanner_.Initialize(stream_ptr);
result = DoParseProgram(info);
} else {
result = DoParseFunction(info, info->function_name(), stream_ptr);
const AstRawString* function_name = info->function_name();
if (!function_name) {
// FIXME(wiktorg) solve fni in parse tasks
function_name = ast_value_factory()->empty_string();
}
result = DoParseFunction(info, function_name);
}
info->set_literal(result);

View File

@ -275,8 +275,7 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
FunctionLiteral* ParseFunction(Isolate* isolate, ParseInfo* info);
FunctionLiteral* DoParseFunction(ParseInfo* info,
const AstRawString* raw_name,
Utf16CharacterStream* source);
const AstRawString* raw_name);
// Called by ParseProgram after setting up the scanner.
FunctionLiteral* DoParseProgram(ParseInfo* info);

View File

@ -72,17 +72,20 @@ class ScriptResource : public v8::String::ExternalOneByteStringResource {
DISALLOW_COPY_AND_ASSIGN(ScriptResource);
};
Handle<String> CreateSource(Isolate* isolate,
ExternalOneByteString::Resource* maybe_resource) {
if (maybe_resource) {
return isolate->factory()
->NewExternalStringFromOneByte(maybe_resource)
.ToHandleChecked();
}
return isolate->factory()->NewStringFromAsciiChecked(test_script);
}
Handle<SharedFunctionInfo> CreateSharedFunctionInfo(
Isolate* isolate, ExternalOneByteString::Resource* maybe_resource) {
HandleScope scope(isolate);
Handle<String> source;
if (maybe_resource) {
source = isolate->factory()
->NewExternalStringFromOneByte(maybe_resource)
.ToHandleChecked();
} else {
source = isolate->factory()->NewStringFromAsciiChecked(test_script);
}
Handle<String> source = CreateSource(isolate, maybe_resource);
Handle<Script> script = isolate->factory()->NewScript(source);
Handle<FixedArray> infos = isolate->factory()->NewFixedArray(3);
script->set_shared_function_infos(*infos);
@ -96,6 +99,17 @@ Handle<SharedFunctionInfo> CreateSharedFunctionInfo(
return scope.CloseAndEscape(shared);
}
class FinishCallback : public CompilerDispatcherJob::FinishCallback {
public:
void ParseFinished(std::unique_ptr<ParseInfo> result) override {
result_ = std::move(result);
}
ParseInfo* result() const { return result_.get(); }
private:
std::unique_ptr<ParseInfo> result_;
};
} // namespace
TEST_F(CompilerDispatcherJobTest, Construct) {
@ -104,6 +118,18 @@ TEST_F(CompilerDispatcherJobTest, Construct) {
FLAG_stack_size));
}
TEST_F(CompilerDispatcherJobTest, ConstructWithoutSFI) {
std::unique_ptr<FinishCallback> callback(new FinishCallback());
std::unique_ptr<ScriptResource> resource(
new ScriptResource(test_script, strlen(test_script)));
std::unique_ptr<CompilerDispatcherJob> job(new CompilerDispatcherJob(
tracer(), FLAG_stack_size, CreateSource(i_isolate(), resource.get()), 0,
static_cast<int>(resource->length()), SLOPPY, 1, false, false, false,
false, i_isolate()->heap()->HashSeed(), i_isolate()->allocator(),
ScriptCompiler::kNoCompileOptions, i_isolate()->ast_string_constants(),
callback.get()));
}
TEST_F(CompilerDispatcherJobTest, StateTransitions) {
std::unique_ptr<CompilerDispatcherJob> job(new CompilerDispatcherJob(
i_isolate(), tracer(), CreateSharedFunctionInfo(i_isolate(), nullptr),
@ -128,6 +154,24 @@ TEST_F(CompilerDispatcherJobTest, StateTransitions) {
ASSERT_TRUE(job->status() == CompileJobStatus::kInitial);
}
TEST_F(CompilerDispatcherJobTest, StateTransitionsParseWithCallback) {
std::unique_ptr<FinishCallback> callback(new FinishCallback());
std::unique_ptr<ScriptResource> resource(
new ScriptResource(test_script, strlen(test_script)));
std::unique_ptr<CompilerDispatcherJob> job(new CompilerDispatcherJob(
tracer(), FLAG_stack_size, CreateSource(i_isolate(), resource.get()), 0,
static_cast<int>(resource->length()), SLOPPY, 1, false, false, false,
false, i_isolate()->heap()->HashSeed(), i_isolate()->allocator(),
ScriptCompiler::kNoCompileOptions, i_isolate()->ast_string_constants(),
callback.get()));
ASSERT_TRUE(job->status() == CompileJobStatus::kReadyToParse);
job->Parse();
ASSERT_TRUE(job->status() == CompileJobStatus::kDone);
job->ResetOnMainThread();
ASSERT_TRUE(job->status() == CompileJobStatus::kInitial);
ASSERT_TRUE(callback->result() != nullptr);
}
TEST_F(CompilerDispatcherJobTest, SyntaxError) {
ScriptResource script("^^^", strlen("^^^"));
std::unique_ptr<CompilerDispatcherJob> job(new CompilerDispatcherJob(