OLD | NEW |
1 // Copyright 2016 the V8 project authors. All rights reserved. | 1 // Copyright 2016 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/compiler-dispatcher/compiler-dispatcher-job.h" | 5 #include "src/compiler-dispatcher/compiler-dispatcher-job.h" |
6 | 6 |
7 #include "src/assert-scope.h" | 7 #include "src/assert-scope.h" |
8 #include "src/compilation-info.h" | 8 #include "src/compilation-info.h" |
9 #include "src/compiler-dispatcher/compiler-dispatcher-tracer.h" | 9 #include "src/compiler-dispatcher/compiler-dispatcher-tracer.h" |
10 #include "src/compiler.h" | 10 #include "src/compiler.h" |
11 #include "src/flags.h" | 11 #include "src/flags.h" |
12 #include "src/global-handles.h" | 12 #include "src/global-handles.h" |
13 #include "src/isolate.h" | 13 #include "src/isolate.h" |
14 #include "src/objects-inl.h" | 14 #include "src/objects-inl.h" |
15 #include "src/parsing/parse-info.h" | 15 #include "src/parsing/parse-info.h" |
16 #include "src/parsing/parser.h" | 16 #include "src/parsing/parser.h" |
17 #include "src/parsing/scanner-character-streams.h" | 17 #include "src/parsing/scanner-character-streams.h" |
18 #include "src/unicode-cache.h" | 18 #include "src/unicode-cache.h" |
19 #include "src/utils.h" | 19 #include "src/utils.h" |
20 #include "src/zone/zone.h" | 20 #include "src/zone/zone.h" |
21 | 21 |
22 namespace v8 { | 22 namespace v8 { |
23 namespace internal { | 23 namespace internal { |
24 | 24 |
| 25 namespace { |
| 26 |
| 27 class OneByteWrapper : public v8::String::ExternalOneByteStringResource { |
| 28 public: |
| 29 OneByteWrapper(const void* data, int length) : data_(data), length_(length) {} |
| 30 ~OneByteWrapper() override = default; |
| 31 |
| 32 const char* data() const override { |
| 33 return reinterpret_cast<const char*>(data_); |
| 34 } |
| 35 |
| 36 size_t length() const override { return static_cast<size_t>(length_); } |
| 37 |
| 38 private: |
| 39 const void* data_; |
| 40 int length_; |
| 41 |
| 42 DISALLOW_COPY_AND_ASSIGN(OneByteWrapper); |
| 43 }; |
| 44 |
| 45 class TwoByteWrapper : public v8::String::ExternalStringResource { |
| 46 public: |
| 47 TwoByteWrapper(const void* data, int length) : data_(data), length_(length) {} |
| 48 ~TwoByteWrapper() override = default; |
| 49 |
| 50 const uint16_t* data() const override { |
| 51 return reinterpret_cast<const uint16_t*>(data_); |
| 52 } |
| 53 |
| 54 size_t length() const override { return static_cast<size_t>(length_); } |
| 55 |
| 56 private: |
| 57 const void* data_; |
| 58 int length_; |
| 59 |
| 60 DISALLOW_COPY_AND_ASSIGN(TwoByteWrapper); |
| 61 }; |
| 62 |
| 63 } // namespace |
| 64 |
25 CompilerDispatcherJob::CompilerDispatcherJob(Isolate* isolate, | 65 CompilerDispatcherJob::CompilerDispatcherJob(Isolate* isolate, |
26 CompilerDispatcherTracer* tracer, | 66 CompilerDispatcherTracer* tracer, |
27 Handle<SharedFunctionInfo> shared, | 67 Handle<SharedFunctionInfo> shared, |
28 size_t max_stack_size) | 68 size_t max_stack_size) |
29 : isolate_(isolate), | 69 : isolate_(isolate), |
30 tracer_(tracer), | 70 tracer_(tracer), |
31 shared_(Handle<SharedFunctionInfo>::cast( | 71 shared_(Handle<SharedFunctionInfo>::cast( |
32 isolate_->global_handles()->Create(*shared))), | 72 isolate_->global_handles()->Create(*shared))), |
33 max_stack_size_(max_stack_size), | 73 max_stack_size_(max_stack_size), |
34 can_compile_on_background_thread_(false), | |
35 trace_compiler_dispatcher_jobs_(FLAG_trace_compiler_dispatcher_jobs) { | 74 trace_compiler_dispatcher_jobs_(FLAG_trace_compiler_dispatcher_jobs) { |
36 HandleScope scope(isolate_); | 75 HandleScope scope(isolate_); |
37 DCHECK(!shared_->outer_scope_info()->IsTheHole(isolate_)); | 76 DCHECK(!shared_->outer_scope_info()->IsTheHole(isolate_)); |
38 Handle<Script> script(Script::cast(shared_->script()), isolate_); | 77 Handle<Script> script(Script::cast(shared_->script()), isolate_); |
39 Handle<String> source(String::cast(script->source()), isolate_); | 78 Handle<String> source(String::cast(script->source()), isolate_); |
40 can_parse_on_background_thread_ = | |
41 source->IsExternalTwoByteString() || source->IsExternalOneByteString(); | |
42 if (trace_compiler_dispatcher_jobs_) { | 79 if (trace_compiler_dispatcher_jobs_) { |
43 PrintF("CompilerDispatcherJob[%p] created for ", static_cast<void*>(this)); | 80 PrintF("CompilerDispatcherJob[%p] created for ", static_cast<void*>(this)); |
44 shared_->ShortPrint(); | 81 shared_->ShortPrint(); |
45 PrintF("\n"); | 82 PrintF("\n"); |
46 } | 83 } |
47 } | 84 } |
48 | 85 |
49 CompilerDispatcherJob::~CompilerDispatcherJob() { | 86 CompilerDispatcherJob::~CompilerDispatcherJob() { |
50 DCHECK(ThreadId::Current().Equals(isolate_->thread_id())); | 87 DCHECK(ThreadId::Current().Equals(isolate_->thread_id())); |
51 DCHECK(status_ == CompileJobStatus::kInitial || | 88 DCHECK(status_ == CompileJobStatus::kInitial || |
(...skipping 19 matching lines...) Expand all Loading... |
71 zone_.reset(new Zone(isolate_->allocator(), ZONE_NAME)); | 108 zone_.reset(new Zone(isolate_->allocator(), ZONE_NAME)); |
72 Handle<Script> script(Script::cast(shared_->script()), isolate_); | 109 Handle<Script> script(Script::cast(shared_->script()), isolate_); |
73 DCHECK(script->type() != Script::TYPE_NATIVE); | 110 DCHECK(script->type() != Script::TYPE_NATIVE); |
74 | 111 |
75 Handle<String> source(String::cast(script->source()), isolate_); | 112 Handle<String> source(String::cast(script->source()), isolate_); |
76 if (source->IsExternalTwoByteString() || source->IsExternalOneByteString()) { | 113 if (source->IsExternalTwoByteString() || source->IsExternalOneByteString()) { |
77 character_stream_.reset(ScannerStream::For( | 114 character_stream_.reset(ScannerStream::For( |
78 source, shared_->start_position(), shared_->end_position())); | 115 source, shared_->start_position(), shared_->end_position())); |
79 } else { | 116 } else { |
80 source = String::Flatten(source); | 117 source = String::Flatten(source); |
81 // Have to globalize the reference here, so it survives between function | 118 const void* data; |
82 // calls. | 119 int offset = 0; |
83 source_ = Handle<String>::cast(isolate_->global_handles()->Create(*source)); | 120 int length = source->length(); |
84 character_stream_.reset(ScannerStream::For( | 121 |
85 source_, shared_->start_position(), shared_->end_position())); | 122 // Objects in lo_space don't move, so we can just read the contents from |
| 123 // any thread. |
| 124 if (isolate_->heap()->lo_space()->Contains(*source)) { |
| 125 // We need to globalize the handle to the flattened string here, in |
| 126 // case it's not referenced from anywhere else. |
| 127 source_ = |
| 128 Handle<String>::cast(isolate_->global_handles()->Create(*source)); |
| 129 DisallowHeapAllocation no_allocation; |
| 130 String::FlatContent content = source->GetFlatContent(); |
| 131 DCHECK(content.IsFlat()); |
| 132 data = |
| 133 content.IsOneByte() |
| 134 ? reinterpret_cast<const void*>(content.ToOneByteVector().start()) |
| 135 : reinterpret_cast<const void*>(content.ToUC16Vector().start()); |
| 136 } else { |
| 137 // Otherwise, create a copy of the part of the string we'll parse in the |
| 138 // zone. |
| 139 length = (shared_->end_position() - shared_->start_position()); |
| 140 offset = shared_->start_position(); |
| 141 |
| 142 int byte_len = length * (source->IsOneByteRepresentation() ? 1 : 2); |
| 143 data = zone_->New(byte_len); |
| 144 |
| 145 DisallowHeapAllocation no_allocation; |
| 146 String::FlatContent content = source->GetFlatContent(); |
| 147 DCHECK(content.IsFlat()); |
| 148 if (content.IsOneByte()) { |
| 149 MemCopy(const_cast<void*>(data), |
| 150 &content.ToOneByteVector().at(shared_->start_position()), |
| 151 byte_len); |
| 152 } else { |
| 153 MemCopy(const_cast<void*>(data), |
| 154 &content.ToUC16Vector().at(shared_->start_position()), |
| 155 byte_len); |
| 156 } |
| 157 } |
| 158 Handle<String> wrapper; |
| 159 if (source->IsOneByteRepresentation()) { |
| 160 ExternalOneByteString::Resource* resource = |
| 161 new OneByteWrapper(data, length); |
| 162 source_wrapper_.reset(resource); |
| 163 wrapper = isolate_->factory() |
| 164 ->NewExternalStringFromOneByte(resource) |
| 165 .ToHandleChecked(); |
| 166 } else { |
| 167 ExternalTwoByteString::Resource* resource = |
| 168 new TwoByteWrapper(data, length); |
| 169 source_wrapper_.reset(resource); |
| 170 wrapper = isolate_->factory() |
| 171 ->NewExternalStringFromTwoByte(resource) |
| 172 .ToHandleChecked(); |
| 173 } |
| 174 wrapper_ = |
| 175 Handle<String>::cast(isolate_->global_handles()->Create(*wrapper)); |
| 176 |
| 177 character_stream_.reset( |
| 178 ScannerStream::For(wrapper_, shared_->start_position() - offset, |
| 179 shared_->end_position() - offset)); |
86 } | 180 } |
87 parse_info_.reset(new ParseInfo(zone_.get())); | 181 parse_info_.reset(new ParseInfo(zone_.get())); |
88 parse_info_->set_isolate(isolate_); | 182 parse_info_->set_isolate(isolate_); |
89 parse_info_->set_character_stream(character_stream_.get()); | 183 parse_info_->set_character_stream(character_stream_.get()); |
90 parse_info_->set_hash_seed(isolate_->heap()->HashSeed()); | 184 parse_info_->set_hash_seed(isolate_->heap()->HashSeed()); |
91 parse_info_->set_is_named_expression(shared_->is_named_expression()); | 185 parse_info_->set_is_named_expression(shared_->is_named_expression()); |
92 parse_info_->set_compiler_hints(shared_->compiler_hints()); | 186 parse_info_->set_compiler_hints(shared_->compiler_hints()); |
93 parse_info_->set_start_position(shared_->start_position()); | 187 parse_info_->set_start_position(shared_->start_position()); |
94 parse_info_->set_end_position(shared_->end_position()); | 188 parse_info_->set_end_position(shared_->end_position()); |
95 parse_info_->set_unicode_cache(unicode_cache_.get()); | 189 parse_info_->set_unicode_cache(unicode_cache_.get()); |
96 parse_info_->set_language_mode(shared_->language_mode()); | 190 parse_info_->set_language_mode(shared_->language_mode()); |
97 parse_info_->set_function_literal_id(shared_->function_literal_id()); | 191 parse_info_->set_function_literal_id(shared_->function_literal_id()); |
98 | 192 |
99 parser_.reset(new Parser(parse_info_.get())); | 193 parser_.reset(new Parser(parse_info_.get())); |
100 Handle<ScopeInfo> outer_scope_info( | 194 Handle<ScopeInfo> outer_scope_info( |
101 handle(ScopeInfo::cast(shared_->outer_scope_info()))); | 195 handle(ScopeInfo::cast(shared_->outer_scope_info()))); |
102 parser_->DeserializeScopeChain(parse_info_.get(), | 196 parser_->DeserializeScopeChain(parse_info_.get(), |
103 outer_scope_info->length() > 0 | 197 outer_scope_info->length() > 0 |
104 ? MaybeHandle<ScopeInfo>(outer_scope_info) | 198 ? MaybeHandle<ScopeInfo>(outer_scope_info) |
105 : MaybeHandle<ScopeInfo>()); | 199 : MaybeHandle<ScopeInfo>()); |
106 | 200 |
107 Handle<String> name(String::cast(shared_->name())); | 201 Handle<String> name(String::cast(shared_->name())); |
108 parse_info_->set_function_name( | 202 parse_info_->set_function_name( |
109 parse_info_->ast_value_factory()->GetString(name)); | 203 parse_info_->ast_value_factory()->GetString(name)); |
110 status_ = CompileJobStatus::kReadyToParse; | 204 status_ = CompileJobStatus::kReadyToParse; |
111 } | 205 } |
112 | 206 |
113 void CompilerDispatcherJob::Parse() { | 207 void CompilerDispatcherJob::Parse() { |
114 DCHECK(can_parse_on_background_thread_ || | |
115 ThreadId::Current().Equals(isolate_->thread_id())); | |
116 DCHECK(status() == CompileJobStatus::kReadyToParse); | 208 DCHECK(status() == CompileJobStatus::kReadyToParse); |
117 COMPILER_DISPATCHER_TRACE_SCOPE_WITH_NUM( | 209 COMPILER_DISPATCHER_TRACE_SCOPE_WITH_NUM( |
118 tracer_, kParse, | 210 tracer_, kParse, |
119 parse_info_->end_position() - parse_info_->start_position()); | 211 parse_info_->end_position() - parse_info_->start_position()); |
120 if (trace_compiler_dispatcher_jobs_) { | 212 if (trace_compiler_dispatcher_jobs_) { |
121 PrintF("CompilerDispatcherJob[%p]: Parsing\n", static_cast<void*>(this)); | 213 PrintF("CompilerDispatcherJob[%p]: Parsing\n", static_cast<void*>(this)); |
122 } | 214 } |
123 | 215 |
124 DisallowHeapAllocation no_allocation; | 216 DisallowHeapAllocation no_allocation; |
125 DisallowHandleAllocation no_handles; | 217 DisallowHandleAllocation no_handles; |
126 std::unique_ptr<DisallowHandleDereference> no_deref; | 218 DisallowHandleDereference no_deref; |
127 // If we can't parse on a background thread, we need to be able to deref the | |
128 // source string. | |
129 if (can_parse_on_background_thread_) { | |
130 no_deref.reset(new DisallowHandleDereference()); | |
131 } | |
132 | 219 |
133 // Nullify the Isolate temporarily so that the parser doesn't accidentally | 220 // Nullify the Isolate temporarily so that the parser doesn't accidentally |
134 // use it. | 221 // use it. |
135 parse_info_->set_isolate(nullptr); | 222 parse_info_->set_isolate(nullptr); |
136 | 223 |
137 uintptr_t stack_limit = GetCurrentStackPosition() - max_stack_size_ * KB; | 224 uintptr_t stack_limit = GetCurrentStackPosition() - max_stack_size_ * KB; |
138 | 225 |
139 parser_->set_stack_limit(stack_limit); | 226 parser_->set_stack_limit(stack_limit); |
140 parser_->ParseOnBackground(parse_info_.get()); | 227 parser_->ParseOnBackground(parse_info_.get()); |
141 | 228 |
142 parse_info_->set_isolate(isolate_); | 229 parse_info_->set_isolate(isolate_); |
143 | 230 |
144 status_ = CompileJobStatus::kParsed; | 231 status_ = CompileJobStatus::kParsed; |
145 } | 232 } |
146 | 233 |
147 bool CompilerDispatcherJob::FinalizeParsingOnMainThread() { | 234 bool CompilerDispatcherJob::FinalizeParsingOnMainThread() { |
148 DCHECK(ThreadId::Current().Equals(isolate_->thread_id())); | 235 DCHECK(ThreadId::Current().Equals(isolate_->thread_id())); |
149 DCHECK(status() == CompileJobStatus::kParsed); | 236 DCHECK(status() == CompileJobStatus::kParsed); |
150 COMPILER_DISPATCHER_TRACE_SCOPE(tracer_, kFinalizeParsing); | 237 COMPILER_DISPATCHER_TRACE_SCOPE(tracer_, kFinalizeParsing); |
151 if (trace_compiler_dispatcher_jobs_) { | 238 if (trace_compiler_dispatcher_jobs_) { |
152 PrintF("CompilerDispatcherJob[%p]: Finalizing parsing\n", | 239 PrintF("CompilerDispatcherJob[%p]: Finalizing parsing\n", |
153 static_cast<void*>(this)); | 240 static_cast<void*>(this)); |
154 } | 241 } |
155 | 242 |
156 if (!source_.is_null()) { | 243 if (!source_.is_null()) { |
157 i::GlobalHandles::Destroy(Handle<Object>::cast(source_).location()); | 244 i::GlobalHandles::Destroy(Handle<Object>::cast(source_).location()); |
158 source_ = Handle<String>::null(); | 245 source_ = Handle<String>::null(); |
159 } | 246 } |
| 247 if (!wrapper_.is_null()) { |
| 248 i::GlobalHandles::Destroy(Handle<Object>::cast(wrapper_).location()); |
| 249 wrapper_ = Handle<String>::null(); |
| 250 } |
160 | 251 |
161 if (parse_info_->literal() == nullptr) { | 252 if (parse_info_->literal() == nullptr) { |
162 status_ = CompileJobStatus::kFailed; | 253 status_ = CompileJobStatus::kFailed; |
163 } else { | 254 } else { |
164 status_ = CompileJobStatus::kReadyToAnalyse; | 255 status_ = CompileJobStatus::kReadyToAnalyse; |
165 } | 256 } |
166 | 257 |
167 DeferredHandleScope scope(isolate_); | 258 DeferredHandleScope scope(isolate_); |
168 { | 259 { |
169 Handle<Script> script(Script::cast(shared_->script()), isolate_); | 260 Handle<Script> script(Script::cast(shared_->script()), isolate_); |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
210 Compiler::PrepareUnoptimizedCompilationJob(compile_info_.get())); | 301 Compiler::PrepareUnoptimizedCompilationJob(compile_info_.get())); |
211 } | 302 } |
212 compile_info_->set_deferred_handles(scope.Detach()); | 303 compile_info_->set_deferred_handles(scope.Detach()); |
213 | 304 |
214 if (!compile_job_.get()) { | 305 if (!compile_job_.get()) { |
215 if (!isolate_->has_pending_exception()) isolate_->StackOverflow(); | 306 if (!isolate_->has_pending_exception()) isolate_->StackOverflow(); |
216 status_ = CompileJobStatus::kFailed; | 307 status_ = CompileJobStatus::kFailed; |
217 return false; | 308 return false; |
218 } | 309 } |
219 | 310 |
220 can_compile_on_background_thread_ = | 311 CHECK(compile_job_->can_execute_on_background_thread()); |
221 compile_job_->can_execute_on_background_thread(); | |
222 status_ = CompileJobStatus::kReadyToCompile; | 312 status_ = CompileJobStatus::kReadyToCompile; |
223 return true; | 313 return true; |
224 } | 314 } |
225 | 315 |
226 void CompilerDispatcherJob::Compile() { | 316 void CompilerDispatcherJob::Compile() { |
227 DCHECK(status() == CompileJobStatus::kReadyToCompile); | 317 DCHECK(status() == CompileJobStatus::kReadyToCompile); |
228 DCHECK(can_compile_on_background_thread_ || | |
229 ThreadId::Current().Equals(isolate_->thread_id())); | |
230 COMPILER_DISPATCHER_TRACE_SCOPE_WITH_NUM( | 318 COMPILER_DISPATCHER_TRACE_SCOPE_WITH_NUM( |
231 tracer_, kCompile, parse_info_->literal()->ast_node_count()); | 319 tracer_, kCompile, parse_info_->literal()->ast_node_count()); |
232 if (trace_compiler_dispatcher_jobs_) { | 320 if (trace_compiler_dispatcher_jobs_) { |
233 PrintF("CompilerDispatcherJob[%p]: Compiling\n", static_cast<void*>(this)); | 321 PrintF("CompilerDispatcherJob[%p]: Compiling\n", static_cast<void*>(this)); |
234 } | 322 } |
235 | 323 |
236 // Disallowing of handle dereference and heap access dealt with in | 324 // Disallowing of handle dereference and heap access dealt with in |
237 // CompilationJob::ExecuteJob. | 325 // CompilationJob::ExecuteJob. |
238 | 326 |
239 uintptr_t stack_limit = GetCurrentStackPosition() - max_stack_size_ * KB; | 327 uintptr_t stack_limit = GetCurrentStackPosition() - max_stack_size_ * KB; |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
286 parse_info_.reset(); | 374 parse_info_.reset(); |
287 handles_from_parsing_.reset(); | 375 handles_from_parsing_.reset(); |
288 compile_info_.reset(); | 376 compile_info_.reset(); |
289 compile_job_.reset(); | 377 compile_job_.reset(); |
290 zone_.reset(); | 378 zone_.reset(); |
291 | 379 |
292 if (!source_.is_null()) { | 380 if (!source_.is_null()) { |
293 i::GlobalHandles::Destroy(Handle<Object>::cast(source_).location()); | 381 i::GlobalHandles::Destroy(Handle<Object>::cast(source_).location()); |
294 source_ = Handle<String>::null(); | 382 source_ = Handle<String>::null(); |
295 } | 383 } |
| 384 if (!wrapper_.is_null()) { |
| 385 i::GlobalHandles::Destroy(Handle<Object>::cast(wrapper_).location()); |
| 386 wrapper_ = Handle<String>::null(); |
| 387 } |
296 | 388 |
297 status_ = CompileJobStatus::kInitial; | 389 status_ = CompileJobStatus::kInitial; |
298 } | 390 } |
299 | 391 |
300 double CompilerDispatcherJob::EstimateRuntimeOfNextStepInMs() const { | 392 double CompilerDispatcherJob::EstimateRuntimeOfNextStepInMs() const { |
301 switch (status_) { | 393 switch (status_) { |
302 case CompileJobStatus::kInitial: | 394 case CompileJobStatus::kInitial: |
303 return tracer_->EstimatePrepareToParseInMs(); | 395 return tracer_->EstimatePrepareToParseInMs(); |
304 | 396 |
305 case CompileJobStatus::kReadyToParse: | 397 case CompileJobStatus::kReadyToParse: |
(...skipping 22 matching lines...) Expand all Loading... |
328 return 0.0; | 420 return 0.0; |
329 } | 421 } |
330 | 422 |
331 void CompilerDispatcherJob::ShortPrint() { | 423 void CompilerDispatcherJob::ShortPrint() { |
332 DCHECK(ThreadId::Current().Equals(isolate_->thread_id())); | 424 DCHECK(ThreadId::Current().Equals(isolate_->thread_id())); |
333 shared_->ShortPrint(); | 425 shared_->ShortPrint(); |
334 } | 426 } |
335 | 427 |
336 } // namespace internal | 428 } // namespace internal |
337 } // namespace v8 | 429 } // namespace v8 |
OLD | NEW |