| 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/global-handles.h" | 12 #include "src/global-handles.h" |
| 12 #include "src/isolate.h" | 13 #include "src/isolate.h" |
| 13 #include "src/objects-inl.h" | 14 #include "src/objects-inl.h" |
| 14 #include "src/parsing/parse-info.h" | 15 #include "src/parsing/parse-info.h" |
| 15 #include "src/parsing/parser.h" | 16 #include "src/parsing/parser.h" |
| 16 #include "src/parsing/scanner-character-streams.h" | 17 #include "src/parsing/scanner-character-streams.h" |
| 17 #include "src/unicode-cache.h" | 18 #include "src/unicode-cache.h" |
| 19 #include "src/utils.h" |
| 18 #include "src/zone/zone.h" | 20 #include "src/zone/zone.h" |
| 19 | 21 |
| 20 namespace v8 { | 22 namespace v8 { |
| 21 namespace internal { | 23 namespace internal { |
| 22 | 24 |
| 23 CompilerDispatcherJob::CompilerDispatcherJob(Isolate* isolate, | 25 CompilerDispatcherJob::CompilerDispatcherJob(Isolate* isolate, |
| 24 CompilerDispatcherTracer* tracer, | 26 CompilerDispatcherTracer* tracer, |
| 25 Handle<SharedFunctionInfo> shared, | 27 Handle<SharedFunctionInfo> shared, |
| 26 size_t max_stack_size) | 28 size_t max_stack_size) |
| 27 : isolate_(isolate), | 29 : isolate_(isolate), |
| 28 tracer_(tracer), | 30 tracer_(tracer), |
| 29 shared_(Handle<SharedFunctionInfo>::cast( | 31 shared_(Handle<SharedFunctionInfo>::cast( |
| 30 isolate_->global_handles()->Create(*shared))), | 32 isolate_->global_handles()->Create(*shared))), |
| 31 max_stack_size_(max_stack_size), | 33 max_stack_size_(max_stack_size), |
| 32 can_compile_on_background_thread_(false) { | 34 can_compile_on_background_thread_(false), |
| 35 trace_compiler_dispatcher_jobs_(FLAG_trace_compiler_dispatcher_jobs) { |
| 33 HandleScope scope(isolate_); | 36 HandleScope scope(isolate_); |
| 34 DCHECK(!shared_->outer_scope_info()->IsTheHole(isolate_)); | 37 DCHECK(!shared_->outer_scope_info()->IsTheHole(isolate_)); |
| 35 Handle<Script> script(Script::cast(shared_->script()), isolate_); | 38 Handle<Script> script(Script::cast(shared_->script()), isolate_); |
| 36 Handle<String> source(String::cast(script->source()), isolate_); | 39 Handle<String> source(String::cast(script->source()), isolate_); |
| 37 can_parse_on_background_thread_ = | 40 can_parse_on_background_thread_ = |
| 38 source->IsExternalTwoByteString() || source->IsExternalOneByteString(); | 41 source->IsExternalTwoByteString() || source->IsExternalOneByteString(); |
| 42 if (trace_compiler_dispatcher_jobs_) { |
| 43 PrintF("CompilerDispatcherJob[%p] created for ", static_cast<void*>(this)); |
| 44 shared_->ShortPrint(); |
| 45 PrintF("\n"); |
| 46 } |
| 39 } | 47 } |
| 40 | 48 |
| 41 CompilerDispatcherJob::~CompilerDispatcherJob() { | 49 CompilerDispatcherJob::~CompilerDispatcherJob() { |
| 42 DCHECK(ThreadId::Current().Equals(isolate_->thread_id())); | 50 DCHECK(ThreadId::Current().Equals(isolate_->thread_id())); |
| 43 DCHECK(status_ == CompileJobStatus::kInitial || | 51 DCHECK(status_ == CompileJobStatus::kInitial || |
| 44 status_ == CompileJobStatus::kDone); | 52 status_ == CompileJobStatus::kDone); |
| 45 i::GlobalHandles::Destroy(Handle<Object>::cast(shared_).location()); | 53 i::GlobalHandles::Destroy(Handle<Object>::cast(shared_).location()); |
| 46 } | 54 } |
| 47 | 55 |
| 48 bool CompilerDispatcherJob::IsAssociatedWith( | 56 bool CompilerDispatcherJob::IsAssociatedWith( |
| 49 Handle<SharedFunctionInfo> shared) const { | 57 Handle<SharedFunctionInfo> shared) const { |
| 50 return *shared_ == *shared; | 58 return *shared_ == *shared; |
| 51 } | 59 } |
| 52 | 60 |
| 53 void CompilerDispatcherJob::PrepareToParseOnMainThread() { | 61 void CompilerDispatcherJob::PrepareToParseOnMainThread() { |
| 54 DCHECK(ThreadId::Current().Equals(isolate_->thread_id())); | 62 DCHECK(ThreadId::Current().Equals(isolate_->thread_id())); |
| 55 DCHECK(status() == CompileJobStatus::kInitial); | 63 DCHECK(status() == CompileJobStatus::kInitial); |
| 56 COMPILER_DISPATCHER_TRACE_SCOPE(tracer_, kPrepareToParse); | 64 COMPILER_DISPATCHER_TRACE_SCOPE(tracer_, kPrepareToParse); |
| 65 if (trace_compiler_dispatcher_jobs_) { |
| 66 PrintF("CompilerDispatcherJob[%p]: Preparing to parse\n", |
| 67 static_cast<void*>(this)); |
| 68 } |
| 57 HandleScope scope(isolate_); | 69 HandleScope scope(isolate_); |
| 58 unicode_cache_.reset(new UnicodeCache()); | 70 unicode_cache_.reset(new UnicodeCache()); |
| 59 zone_.reset(new Zone(isolate_->allocator(), ZONE_NAME)); | 71 zone_.reset(new Zone(isolate_->allocator(), ZONE_NAME)); |
| 60 Handle<Script> script(Script::cast(shared_->script()), isolate_); | 72 Handle<Script> script(Script::cast(shared_->script()), isolate_); |
| 61 DCHECK(script->type() != Script::TYPE_NATIVE); | 73 DCHECK(script->type() != Script::TYPE_NATIVE); |
| 62 | 74 |
| 63 Handle<String> source(String::cast(script->source()), isolate_); | 75 Handle<String> source(String::cast(script->source()), isolate_); |
| 64 if (source->IsExternalTwoByteString() || source->IsExternalOneByteString()) { | 76 if (source->IsExternalTwoByteString() || source->IsExternalOneByteString()) { |
| 65 character_stream_.reset(ScannerStream::For( | 77 character_stream_.reset(ScannerStream::For( |
| 66 source, shared_->start_position(), shared_->end_position())); | 78 source, shared_->start_position(), shared_->end_position())); |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 98 status_ = CompileJobStatus::kReadyToParse; | 110 status_ = CompileJobStatus::kReadyToParse; |
| 99 } | 111 } |
| 100 | 112 |
| 101 void CompilerDispatcherJob::Parse() { | 113 void CompilerDispatcherJob::Parse() { |
| 102 DCHECK(can_parse_on_background_thread_ || | 114 DCHECK(can_parse_on_background_thread_ || |
| 103 ThreadId::Current().Equals(isolate_->thread_id())); | 115 ThreadId::Current().Equals(isolate_->thread_id())); |
| 104 DCHECK(status() == CompileJobStatus::kReadyToParse); | 116 DCHECK(status() == CompileJobStatus::kReadyToParse); |
| 105 COMPILER_DISPATCHER_TRACE_SCOPE_WITH_NUM( | 117 COMPILER_DISPATCHER_TRACE_SCOPE_WITH_NUM( |
| 106 tracer_, kParse, | 118 tracer_, kParse, |
| 107 parse_info_->end_position() - parse_info_->start_position()); | 119 parse_info_->end_position() - parse_info_->start_position()); |
| 120 if (trace_compiler_dispatcher_jobs_) { |
| 121 PrintF("CompilerDispatcherJob[%p]: Parsing\n", static_cast<void*>(this)); |
| 122 } |
| 108 | 123 |
| 109 DisallowHeapAllocation no_allocation; | 124 DisallowHeapAllocation no_allocation; |
| 110 DisallowHandleAllocation no_handles; | 125 DisallowHandleAllocation no_handles; |
| 111 std::unique_ptr<DisallowHandleDereference> no_deref; | 126 std::unique_ptr<DisallowHandleDereference> no_deref; |
| 112 // If we can't parse on a background thread, we need to be able to deref the | 127 // If we can't parse on a background thread, we need to be able to deref the |
| 113 // source string. | 128 // source string. |
| 114 if (can_parse_on_background_thread_) { | 129 if (can_parse_on_background_thread_) { |
| 115 no_deref.reset(new DisallowHandleDereference()); | 130 no_deref.reset(new DisallowHandleDereference()); |
| 116 } | 131 } |
| 117 | 132 |
| 118 // Nullify the Isolate temporarily so that the parser doesn't accidentally | 133 // Nullify the Isolate temporarily so that the parser doesn't accidentally |
| 119 // use it. | 134 // use it. |
| 120 parse_info_->set_isolate(nullptr); | 135 parse_info_->set_isolate(nullptr); |
| 121 | 136 |
| 122 uintptr_t stack_limit = GetCurrentStackPosition() - max_stack_size_ * KB; | 137 uintptr_t stack_limit = GetCurrentStackPosition() - max_stack_size_ * KB; |
| 123 | 138 |
| 124 parser_->set_stack_limit(stack_limit); | 139 parser_->set_stack_limit(stack_limit); |
| 125 parser_->ParseOnBackground(parse_info_.get()); | 140 parser_->ParseOnBackground(parse_info_.get()); |
| 126 | 141 |
| 127 parse_info_->set_isolate(isolate_); | 142 parse_info_->set_isolate(isolate_); |
| 128 | 143 |
| 129 status_ = CompileJobStatus::kParsed; | 144 status_ = CompileJobStatus::kParsed; |
| 130 } | 145 } |
| 131 | 146 |
| 132 bool CompilerDispatcherJob::FinalizeParsingOnMainThread() { | 147 bool CompilerDispatcherJob::FinalizeParsingOnMainThread() { |
| 133 DCHECK(ThreadId::Current().Equals(isolate_->thread_id())); | 148 DCHECK(ThreadId::Current().Equals(isolate_->thread_id())); |
| 134 DCHECK(status() == CompileJobStatus::kParsed); | 149 DCHECK(status() == CompileJobStatus::kParsed); |
| 135 COMPILER_DISPATCHER_TRACE_SCOPE(tracer_, kFinalizeParsing); | 150 COMPILER_DISPATCHER_TRACE_SCOPE(tracer_, kFinalizeParsing); |
| 151 if (trace_compiler_dispatcher_jobs_) { |
| 152 PrintF("CompilerDispatcherJob[%p]: Finalizing parsing\n", |
| 153 static_cast<void*>(this)); |
| 154 } |
| 136 | 155 |
| 137 if (!source_.is_null()) { | 156 if (!source_.is_null()) { |
| 138 i::GlobalHandles::Destroy(Handle<Object>::cast(source_).location()); | 157 i::GlobalHandles::Destroy(Handle<Object>::cast(source_).location()); |
| 139 source_ = Handle<String>::null(); | 158 source_ = Handle<String>::null(); |
| 140 } | 159 } |
| 141 | 160 |
| 142 if (parse_info_->literal() == nullptr) { | 161 if (parse_info_->literal() == nullptr) { |
| 143 status_ = CompileJobStatus::kFailed; | 162 status_ = CompileJobStatus::kFailed; |
| 144 } else { | 163 } else { |
| 145 status_ = CompileJobStatus::kReadyToAnalyse; | 164 status_ = CompileJobStatus::kReadyToAnalyse; |
| (...skipping 24 matching lines...) Expand all Loading... |
| 170 } | 189 } |
| 171 handles_from_parsing_.reset(scope.Detach()); | 190 handles_from_parsing_.reset(scope.Detach()); |
| 172 | 191 |
| 173 return status_ != CompileJobStatus::kFailed; | 192 return status_ != CompileJobStatus::kFailed; |
| 174 } | 193 } |
| 175 | 194 |
| 176 bool CompilerDispatcherJob::PrepareToCompileOnMainThread() { | 195 bool CompilerDispatcherJob::PrepareToCompileOnMainThread() { |
| 177 DCHECK(ThreadId::Current().Equals(isolate_->thread_id())); | 196 DCHECK(ThreadId::Current().Equals(isolate_->thread_id())); |
| 178 DCHECK(status() == CompileJobStatus::kReadyToAnalyse); | 197 DCHECK(status() == CompileJobStatus::kReadyToAnalyse); |
| 179 COMPILER_DISPATCHER_TRACE_SCOPE(tracer_, kPrepareToCompile); | 198 COMPILER_DISPATCHER_TRACE_SCOPE(tracer_, kPrepareToCompile); |
| 199 if (trace_compiler_dispatcher_jobs_) { |
| 200 PrintF("CompilerDispatcherJob[%p]: Preparing to compile\n", |
| 201 static_cast<void*>(this)); |
| 202 } |
| 180 | 203 |
| 181 compile_info_.reset( | 204 compile_info_.reset( |
| 182 new CompilationInfo(parse_info_.get(), Handle<JSFunction>::null())); | 205 new CompilationInfo(parse_info_.get(), Handle<JSFunction>::null())); |
| 183 | 206 |
| 184 DeferredHandleScope scope(isolate_); | 207 DeferredHandleScope scope(isolate_); |
| 185 if (Compiler::Analyze(parse_info_.get())) { | 208 if (Compiler::Analyze(parse_info_.get())) { |
| 186 compile_job_.reset(Compiler::PrepareUnoptimizedCompilationJob( | 209 compile_job_.reset(Compiler::PrepareUnoptimizedCompilationJob( |
| 187 compile_info_.get(), LazyCompilationMode::kAlways)); | 210 compile_info_.get(), LazyCompilationMode::kAlways)); |
| 188 } | 211 } |
| 189 compile_info_->set_deferred_handles(scope.Detach()); | 212 compile_info_->set_deferred_handles(scope.Detach()); |
| 190 | 213 |
| 191 if (!compile_job_.get()) { | 214 if (!compile_job_.get()) { |
| 192 if (!isolate_->has_pending_exception()) isolate_->StackOverflow(); | 215 if (!isolate_->has_pending_exception()) isolate_->StackOverflow(); |
| 193 status_ = CompileJobStatus::kFailed; | 216 status_ = CompileJobStatus::kFailed; |
| 194 return false; | 217 return false; |
| 195 } | 218 } |
| 196 | 219 |
| 197 can_compile_on_background_thread_ = | 220 can_compile_on_background_thread_ = |
| 198 compile_job_->can_execute_on_background_thread(); | 221 compile_job_->can_execute_on_background_thread(); |
| 199 status_ = CompileJobStatus::kReadyToCompile; | 222 status_ = CompileJobStatus::kReadyToCompile; |
| 200 return true; | 223 return true; |
| 201 } | 224 } |
| 202 | 225 |
| 203 void CompilerDispatcherJob::Compile() { | 226 void CompilerDispatcherJob::Compile() { |
| 204 DCHECK(status() == CompileJobStatus::kReadyToCompile); | 227 DCHECK(status() == CompileJobStatus::kReadyToCompile); |
| 205 DCHECK(can_compile_on_background_thread_ || | 228 DCHECK(can_compile_on_background_thread_ || |
| 206 ThreadId::Current().Equals(isolate_->thread_id())); | 229 ThreadId::Current().Equals(isolate_->thread_id())); |
| 207 COMPILER_DISPATCHER_TRACE_SCOPE_WITH_NUM( | 230 COMPILER_DISPATCHER_TRACE_SCOPE_WITH_NUM( |
| 208 tracer_, kCompile, parse_info_->literal()->ast_node_count()); | 231 tracer_, kCompile, parse_info_->literal()->ast_node_count()); |
| 232 if (trace_compiler_dispatcher_jobs_) { |
| 233 PrintF("CompilerDispatcherJob[%p]: Compiling\n", static_cast<void*>(this)); |
| 234 } |
| 209 | 235 |
| 210 // Disallowing of handle dereference and heap access dealt with in | 236 // Disallowing of handle dereference and heap access dealt with in |
| 211 // CompilationJob::ExecuteJob. | 237 // CompilationJob::ExecuteJob. |
| 212 | 238 |
| 213 uintptr_t stack_limit = GetCurrentStackPosition() - max_stack_size_ * KB; | 239 uintptr_t stack_limit = GetCurrentStackPosition() - max_stack_size_ * KB; |
| 214 compile_job_->set_stack_limit(stack_limit); | 240 compile_job_->set_stack_limit(stack_limit); |
| 215 | 241 |
| 216 CompilationJob::Status status = compile_job_->ExecuteJob(); | 242 CompilationJob::Status status = compile_job_->ExecuteJob(); |
| 217 USE(status); | 243 USE(status); |
| 218 | 244 |
| 219 // Always transition to kCompiled - errors will be reported by | 245 // Always transition to kCompiled - errors will be reported by |
| 220 // FinalizeCompilingOnMainThread. | 246 // FinalizeCompilingOnMainThread. |
| 221 status_ = CompileJobStatus::kCompiled; | 247 status_ = CompileJobStatus::kCompiled; |
| 222 } | 248 } |
| 223 | 249 |
| 224 bool CompilerDispatcherJob::FinalizeCompilingOnMainThread() { | 250 bool CompilerDispatcherJob::FinalizeCompilingOnMainThread() { |
| 225 DCHECK(ThreadId::Current().Equals(isolate_->thread_id())); | 251 DCHECK(ThreadId::Current().Equals(isolate_->thread_id())); |
| 226 DCHECK(status() == CompileJobStatus::kCompiled); | 252 DCHECK(status() == CompileJobStatus::kCompiled); |
| 227 COMPILER_DISPATCHER_TRACE_SCOPE(tracer_, kFinalizeCompiling); | 253 COMPILER_DISPATCHER_TRACE_SCOPE(tracer_, kFinalizeCompiling); |
| 254 if (trace_compiler_dispatcher_jobs_) { |
| 255 PrintF("CompilerDispatcherJob[%p]: Finalizing compiling\n", |
| 256 static_cast<void*>(this)); |
| 257 } |
| 228 | 258 |
| 229 if (compile_job_->state() == CompilationJob::State::kFailed || | 259 if (compile_job_->state() == CompilationJob::State::kFailed || |
| 230 !Compiler::FinalizeCompilationJob(compile_job_.release())) { | 260 !Compiler::FinalizeCompilationJob(compile_job_.release())) { |
| 231 if (!isolate_->has_pending_exception()) isolate_->StackOverflow(); | 261 if (!isolate_->has_pending_exception()) isolate_->StackOverflow(); |
| 232 status_ = CompileJobStatus::kFailed; | 262 status_ = CompileJobStatus::kFailed; |
| 233 return false; | 263 return false; |
| 234 } | 264 } |
| 235 | 265 |
| 236 zone_.reset(); | 266 zone_.reset(); |
| 237 parse_info_.reset(); | 267 parse_info_.reset(); |
| 238 compile_info_.reset(); | 268 compile_info_.reset(); |
| 239 compile_job_.reset(); | 269 compile_job_.reset(); |
| 240 handles_from_parsing_.reset(); | 270 handles_from_parsing_.reset(); |
| 241 | 271 |
| 242 status_ = CompileJobStatus::kDone; | 272 status_ = CompileJobStatus::kDone; |
| 243 return true; | 273 return true; |
| 244 } | 274 } |
| 245 | 275 |
| 246 void CompilerDispatcherJob::ResetOnMainThread() { | 276 void CompilerDispatcherJob::ResetOnMainThread() { |
| 247 DCHECK(ThreadId::Current().Equals(isolate_->thread_id())); | 277 DCHECK(ThreadId::Current().Equals(isolate_->thread_id())); |
| 248 | 278 |
| 279 if (trace_compiler_dispatcher_jobs_) { |
| 280 PrintF("CompilerDispatcherJob[%p]: Resetting\n", static_cast<void*>(this)); |
| 281 } |
| 282 |
| 249 parser_.reset(); | 283 parser_.reset(); |
| 250 unicode_cache_.reset(); | 284 unicode_cache_.reset(); |
| 251 character_stream_.reset(); | 285 character_stream_.reset(); |
| 252 parse_info_.reset(); | 286 parse_info_.reset(); |
| 253 zone_.reset(); | 287 zone_.reset(); |
| 254 handles_from_parsing_.reset(); | 288 handles_from_parsing_.reset(); |
| 255 compile_info_.reset(); | 289 compile_info_.reset(); |
| 256 compile_job_.reset(); | 290 compile_job_.reset(); |
| 257 | 291 |
| 258 if (!source_.is_null()) { | 292 if (!source_.is_null()) { |
| (...skipping 28 matching lines...) Expand all Loading... |
| 287 | 321 |
| 288 case CompileJobStatus::kFailed: | 322 case CompileJobStatus::kFailed: |
| 289 case CompileJobStatus::kDone: | 323 case CompileJobStatus::kDone: |
| 290 return 0.0; | 324 return 0.0; |
| 291 } | 325 } |
| 292 | 326 |
| 293 UNREACHABLE(); | 327 UNREACHABLE(); |
| 294 return 0.0; | 328 return 0.0; |
| 295 } | 329 } |
| 296 | 330 |
| 331 void CompilerDispatcherJob::ShortPrint() { |
| 332 DCHECK(ThreadId::Current().Equals(isolate_->thread_id())); |
| 333 shared_->ShortPrint(); |
| 334 } |
| 335 |
| 297 } // namespace internal | 336 } // namespace internal |
| 298 } // namespace v8 | 337 } // namespace v8 |
| OLD | NEW |