Index: src/compiler-dispatcher/compiler-dispatcher-job.cc |
diff --git a/src/compiler-dispatcher/compiler-dispatcher-job.cc b/src/compiler-dispatcher/compiler-dispatcher-job.cc |
index 2ca26011bb5646dbacef9b725ac015d2de52af5c..fdb975a5e419fde3427a53514cc5a8730ec33694 100644 |
--- a/src/compiler-dispatcher/compiler-dispatcher-job.cc |
+++ b/src/compiler-dispatcher/compiler-dispatcher-job.cc |
@@ -22,6 +22,46 @@ |
namespace v8 { |
namespace internal { |
+namespace { |
+ |
+class OneByteWrapper : public v8::String::ExternalOneByteStringResource { |
+ public: |
+ OneByteWrapper(const void* data, int length) : data_(data), length_(length) {} |
+ ~OneByteWrapper() override = default; |
+ |
+ const char* data() const override { |
+ return reinterpret_cast<const char*>(data_); |
+ } |
+ |
+ size_t length() const override { return static_cast<size_t>(length_); } |
+ |
+ private: |
+ const void* data_; |
+ int length_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(OneByteWrapper); |
+}; |
+ |
+class TwoByteWrapper : public v8::String::ExternalStringResource { |
+ public: |
+ TwoByteWrapper(const void* data, int length) : data_(data), length_(length) {} |
+ ~TwoByteWrapper() override = default; |
+ |
+ const uint16_t* data() const override { |
+ return reinterpret_cast<const uint16_t*>(data_); |
+ } |
+ |
+ size_t length() const override { return static_cast<size_t>(length_); } |
+ |
+ private: |
+ const void* data_; |
+ int length_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(TwoByteWrapper); |
+}; |
+ |
+} // namespace |
+ |
CompilerDispatcherJob::CompilerDispatcherJob(Isolate* isolate, |
CompilerDispatcherTracer* tracer, |
Handle<SharedFunctionInfo> shared, |
@@ -31,14 +71,11 @@ CompilerDispatcherJob::CompilerDispatcherJob(Isolate* isolate, |
shared_(Handle<SharedFunctionInfo>::cast( |
isolate_->global_handles()->Create(*shared))), |
max_stack_size_(max_stack_size), |
- can_compile_on_background_thread_(false), |
trace_compiler_dispatcher_jobs_(FLAG_trace_compiler_dispatcher_jobs) { |
HandleScope scope(isolate_); |
DCHECK(!shared_->outer_scope_info()->IsTheHole(isolate_)); |
Handle<Script> script(Script::cast(shared_->script()), isolate_); |
Handle<String> source(String::cast(script->source()), isolate_); |
- can_parse_on_background_thread_ = |
- source->IsExternalTwoByteString() || source->IsExternalOneByteString(); |
if (trace_compiler_dispatcher_jobs_) { |
PrintF("CompilerDispatcherJob[%p] created for ", static_cast<void*>(this)); |
shared_->ShortPrint(); |
@@ -78,11 +115,68 @@ void CompilerDispatcherJob::PrepareToParseOnMainThread() { |
source, shared_->start_position(), shared_->end_position())); |
} else { |
source = String::Flatten(source); |
- // Have to globalize the reference here, so it survives between function |
- // calls. |
- source_ = Handle<String>::cast(isolate_->global_handles()->Create(*source)); |
- character_stream_.reset(ScannerStream::For( |
- source_, shared_->start_position(), shared_->end_position())); |
+ const void* data; |
+ int offset = 0; |
+ int length = source->length(); |
+ |
+ // Objects in lo_space don't move, so we can just read the contents from |
+ // any thread. |
+ if (isolate_->heap()->lo_space()->Contains(*source)) { |
+ // We need to globalize the handle to the flattened string here, in |
+ // case it's not referenced from anywhere else. |
+ source_ = |
+ Handle<String>::cast(isolate_->global_handles()->Create(*source)); |
+ DisallowHeapAllocation no_allocation; |
+ String::FlatContent content = source->GetFlatContent(); |
+ DCHECK(content.IsFlat()); |
+ data = |
+ content.IsOneByte() |
+ ? reinterpret_cast<const void*>(content.ToOneByteVector().start()) |
+ : reinterpret_cast<const void*>(content.ToUC16Vector().start()); |
+ } else { |
+ // Otherwise, create a copy of the part of the string we'll parse in the |
+ // zone. |
+ length = (shared_->end_position() - shared_->start_position()); |
+ offset = shared_->start_position(); |
+ |
+ int byte_len = length * (source->IsOneByteRepresentation() ? 1 : 2); |
+ data = zone_->New(byte_len); |
+ |
+ DisallowHeapAllocation no_allocation; |
+ String::FlatContent content = source->GetFlatContent(); |
+ DCHECK(content.IsFlat()); |
+ if (content.IsOneByte()) { |
+ MemCopy(const_cast<void*>(data), |
+ &content.ToOneByteVector().at(shared_->start_position()), |
+ byte_len); |
+ } else { |
+ MemCopy(const_cast<void*>(data), |
+ &content.ToUC16Vector().at(shared_->start_position()), |
+ byte_len); |
+ } |
+ } |
+ Handle<String> wrapper; |
+ if (source->IsOneByteRepresentation()) { |
+ ExternalOneByteString::Resource* resource = |
+ new OneByteWrapper(data, length); |
+ source_wrapper_.reset(resource); |
+ wrapper = isolate_->factory() |
+ ->NewExternalStringFromOneByte(resource) |
+ .ToHandleChecked(); |
+ } else { |
+ ExternalTwoByteString::Resource* resource = |
+ new TwoByteWrapper(data, length); |
+ source_wrapper_.reset(resource); |
+ wrapper = isolate_->factory() |
+ ->NewExternalStringFromTwoByte(resource) |
+ .ToHandleChecked(); |
+ } |
+ wrapper_ = |
+ Handle<String>::cast(isolate_->global_handles()->Create(*wrapper)); |
+ |
+ character_stream_.reset( |
+ ScannerStream::For(wrapper_, shared_->start_position() - offset, |
+ shared_->end_position() - offset)); |
} |
parse_info_.reset(new ParseInfo(zone_.get())); |
parse_info_->set_isolate(isolate_); |
@@ -111,8 +205,6 @@ void CompilerDispatcherJob::PrepareToParseOnMainThread() { |
} |
void CompilerDispatcherJob::Parse() { |
- DCHECK(can_parse_on_background_thread_ || |
- ThreadId::Current().Equals(isolate_->thread_id())); |
DCHECK(status() == CompileJobStatus::kReadyToParse); |
COMPILER_DISPATCHER_TRACE_SCOPE_WITH_NUM( |
tracer_, kParse, |
@@ -123,12 +215,7 @@ void CompilerDispatcherJob::Parse() { |
DisallowHeapAllocation no_allocation; |
DisallowHandleAllocation no_handles; |
- std::unique_ptr<DisallowHandleDereference> no_deref; |
- // If we can't parse on a background thread, we need to be able to deref the |
- // source string. |
- if (can_parse_on_background_thread_) { |
- no_deref.reset(new DisallowHandleDereference()); |
- } |
+ DisallowHandleDereference no_deref; |
// Nullify the Isolate temporarily so that the parser doesn't accidentally |
// use it. |
@@ -157,6 +244,10 @@ bool CompilerDispatcherJob::FinalizeParsingOnMainThread() { |
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(); |
+ } |
if (parse_info_->literal() == nullptr) { |
status_ = CompileJobStatus::kFailed; |
@@ -217,16 +308,13 @@ bool CompilerDispatcherJob::PrepareToCompileOnMainThread() { |
return false; |
} |
- can_compile_on_background_thread_ = |
- compile_job_->can_execute_on_background_thread(); |
+ CHECK(compile_job_->can_execute_on_background_thread()); |
status_ = CompileJobStatus::kReadyToCompile; |
return true; |
} |
void CompilerDispatcherJob::Compile() { |
DCHECK(status() == CompileJobStatus::kReadyToCompile); |
- DCHECK(can_compile_on_background_thread_ || |
- ThreadId::Current().Equals(isolate_->thread_id())); |
COMPILER_DISPATCHER_TRACE_SCOPE_WITH_NUM( |
tracer_, kCompile, parse_info_->literal()->ast_node_count()); |
if (trace_compiler_dispatcher_jobs_) { |
@@ -293,6 +381,10 @@ void CompilerDispatcherJob::ResetOnMainThread() { |
i::GlobalHandles::Destroy(Handle<Object>::cast(source_).location()); |
source_ = Handle<String>::null(); |
} |
+ if (!wrapper_.is_null()) { |
+ i::GlobalHandles::Destroy(Handle<Object>::cast(wrapper_).location()); |
+ wrapper_ = Handle<String>::null(); |
+ } |
status_ = CompileJobStatus::kInitial; |
} |