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 3 // found in the LICENSE file. 4 5 #include "src/compiler-dispatcher/compiler-dispatcher-job.h" 6 7 #include "src/assert-scope.h" 8 #include "src/compilation-info.h" 9 #include "src/compiler-dispatcher/compiler-dispatcher-tracer.h" 10 #include "src/compiler.h" 11 #include "src/global-handles.h" 12 #include "src/isolate.h" 13 #include "src/objects-inl.h" 14 #include "src/parsing/parse-info.h" 15 #include "src/parsing/parser.h" 16 #include "src/parsing/scanner-character-streams.h" 17 #include "src/unicode-cache.h" 18 #include "src/zone/zone.h" 19 20 namespace v8 { 21 namespace internal { 22 23 CompilerDispatcherJob::CompilerDispatcherJob(Isolate* isolate, 24 Handle<SharedFunctionInfo> shared, 25 size_t max_stack_size) 26 : isolate_(isolate), 27 tracer_(isolate_->compiler_dispatcher_tracer()), 28 shared_(Handle<SharedFunctionInfo>::cast( 29 isolate_->global_handles()->Create(*shared))), 30 max_stack_size_(max_stack_size), 31 can_compile_on_background_thread_(false) { 32 HandleScope scope(isolate_); 33 DCHECK(!shared_->outer_scope_info()->IsTheHole(isolate_)); 34 Handle<Script> script(Script::cast(shared_->script()), isolate_); 35 Handle<String> source(String::cast(script->source()), isolate_); 36 can_parse_on_background_thread_ = 37 source->IsExternalTwoByteString() || source->IsExternalOneByteString(); 38 } 39 40 CompilerDispatcherJob::~CompilerDispatcherJob() { 41 DCHECK(ThreadId::Current().Equals(isolate_->thread_id())); 42 DCHECK(status_ == CompileJobStatus::kInitial || 43 status_ == CompileJobStatus::kDone); 44 i::GlobalHandles::Destroy(Handle<Object>::cast(shared_).location()); 45 } 46 47 void CompilerDispatcherJob::PrepareToParseOnMainThread() { 48 DCHECK(ThreadId::Current().Equals(isolate_->thread_id())); 49 DCHECK(status() == CompileJobStatus::kInitial); 50 COMPILER_DISPATCHER_TRACE_SCOPE(tracer_, kPrepareToParse); 51 HandleScope scope(isolate_); 52 unicode_cache_.reset(new UnicodeCache()); 53 zone_.reset(new Zone(isolate_->allocator(), ZONE_NAME)); 54 Handle<Script> script(Script::cast(shared_->script()), isolate_); 55 DCHECK(script->type() != Script::TYPE_NATIVE); 56 57 Handle<String> source(String::cast(script->source()), isolate_); 58 if (source->IsExternalTwoByteString() || source->IsExternalOneByteString()) { 59 character_stream_.reset(ScannerStream::For( 60 source, shared_->start_position(), shared_->end_position())); 61 } else { 62 source = String::Flatten(source); 63 // Have to globalize the reference here, so it survives between function 64 // calls. 65 source_ = Handle<String>::cast(isolate_->global_handles()->Create(*source)); 66 character_stream_.reset(ScannerStream::For( 67 source_, shared_->start_position(), shared_->end_position())); 68 } 69 parse_info_.reset(new ParseInfo(zone_.get())); 70 parse_info_->set_isolate(isolate_); 71 parse_info_->set_character_stream(character_stream_.get()); 72 parse_info_->set_hash_seed(isolate_->heap()->HashSeed()); 73 parse_info_->set_is_named_expression(shared_->is_named_expression()); 74 parse_info_->set_compiler_hints(shared_->compiler_hints()); 75 parse_info_->set_start_position(shared_->start_position()); 76 parse_info_->set_end_position(shared_->end_position()); 77 parse_info_->set_unicode_cache(unicode_cache_.get()); 78 parse_info_->set_language_mode(shared_->language_mode()); 79 80 parser_.reset(new Parser(parse_info_.get())); 81 Handle<ScopeInfo> outer_scope_info( 82 handle(ScopeInfo::cast(shared_->outer_scope_info()))); 83 parser_->DeserializeScopeChain(parse_info_.get(), 84 outer_scope_info->length() > 0 85 ? MaybeHandle<ScopeInfo>(outer_scope_info) 86 : MaybeHandle<ScopeInfo>()); 87 88 Handle<String> name(String::cast(shared_->name())); 89 parse_info_->set_function_name( 90 parse_info_->ast_value_factory()->GetString(name)); 91 status_ = CompileJobStatus::kReadyToParse; 92 } 93 94 void CompilerDispatcherJob::Parse() { 95 DCHECK(can_parse_on_background_thread_ || 96 ThreadId::Current().Equals(isolate_->thread_id())); 97 DCHECK(status() == CompileJobStatus::kReadyToParse); 98 COMPILER_DISPATCHER_TRACE_SCOPE_WITH_NUM( 99 tracer_, kParse, 100 parse_info_->end_position() - parse_info_->start_position()); 101 102 DisallowHeapAllocation no_allocation; 103 DisallowHandleAllocation no_handles; 104 std::unique_ptr<DisallowHandleDereference> no_deref; 105 // If we can't parse on a background thread, we need to be able to deref the 106 // source string. 107 if (can_parse_on_background_thread_) { 108 no_deref.reset(new DisallowHandleDereference()); 109 } 110 111 // Nullify the Isolate temporarily so that the parser doesn't accidentally 112 // use it. 113 parse_info_->set_isolate(nullptr); 114 115 uintptr_t stack_limit = GetCurrentStackPosition() - max_stack_size_ * KB; 116 117 parser_->set_stack_limit(stack_limit); 118 parser_->ParseOnBackground(parse_info_.get()); 119 120 parse_info_->set_isolate(isolate_); 121 122 status_ = CompileJobStatus::kParsed; 123 } 124 125 bool CompilerDispatcherJob::FinalizeParsingOnMainThread() { 126 DCHECK(ThreadId::Current().Equals(isolate_->thread_id())); 127 DCHECK(status() == CompileJobStatus::kParsed); 128 COMPILER_DISPATCHER_TRACE_SCOPE(tracer_, kFinalizeParsing); 129 130 if (!source_.is_null()) { 131 i::GlobalHandles::Destroy(Handle<Object>::cast(source_).location()); 132 source_ = Handle<String>::null(); 133 } 134 135 if (parse_info_->literal() == nullptr) { 136 status_ = CompileJobStatus::kFailed; 137 } else { 138 status_ = CompileJobStatus::kReadyToAnalyse; 139 } 140 141 DeferredHandleScope scope(isolate_); 142 { 143 Handle<Script> script(Script::cast(shared_->script()), isolate_); 144 145 parse_info_->set_script(script); 146 Handle<ScopeInfo> outer_scope_info( 147 handle(ScopeInfo::cast(shared_->outer_scope_info()))); 148 if (outer_scope_info->length() > 0) { 149 parse_info_->set_outer_scope_info(outer_scope_info); 150 } 151 parse_info_->set_shared_info(shared_); 152 153 // Do the parsing tasks which need to be done on the main thread. This 154 // will also handle parse errors. 155 parser_->Internalize(isolate_, script, parse_info_->literal() == nullptr); 156 parser_->HandleSourceURLComments(isolate_, script); 157 158 parse_info_->set_character_stream(nullptr); 159 parse_info_->set_unicode_cache(nullptr); 160 parser_.reset(); 161 unicode_cache_.reset(); 162 character_stream_.reset(); 163 } 164 handles_from_parsing_.reset(scope.Detach()); 165 166 return status_ != CompileJobStatus::kFailed; 167 } 168 169 bool CompilerDispatcherJob::PrepareToCompileOnMainThread() { 170 DCHECK(ThreadId::Current().Equals(isolate_->thread_id())); 171 DCHECK(status() == CompileJobStatus::kReadyToAnalyse); 172 COMPILER_DISPATCHER_TRACE_SCOPE(tracer_, kPrepareToCompile); 173 174 compile_info_.reset( 175 new CompilationInfo(parse_info_.get(), Handle<JSFunction>::null())); 176 177 DeferredHandleScope scope(isolate_); 178 if (Compiler::Analyze(parse_info_.get())) { 179 compile_job_.reset( 180 Compiler::PrepareUnoptimizedCompilationJob(compile_info_.get())); 181 } 182 compile_info_->set_deferred_handles(scope.Detach()); 183 184 if (!compile_job_.get()) { 185 if (!isolate_->has_pending_exception()) isolate_->StackOverflow(); 186 status_ = CompileJobStatus::kFailed; 187 return false; 188 } 189 190 can_compile_on_background_thread_ = 191 compile_job_->can_execute_on_background_thread(); 192 status_ = CompileJobStatus::kReadyToCompile; 193 return true; 194 } 195 196 void CompilerDispatcherJob::Compile() { 197 DCHECK(status() == CompileJobStatus::kReadyToCompile); 198 DCHECK(can_compile_on_background_thread_ || 199 ThreadId::Current().Equals(isolate_->thread_id())); 200 COMPILER_DISPATCHER_TRACE_SCOPE_WITH_NUM( 201 tracer_, kCompile, parse_info_->literal()->ast_node_count()); 202 203 // Disallowing of handle dereference and heap access dealt with in 204 // CompilationJob::ExecuteJob. 205 206 uintptr_t stack_limit = GetCurrentStackPosition() - max_stack_size_ * KB; 207 compile_job_->set_stack_limit(stack_limit); 208 209 CompilationJob::Status status = compile_job_->ExecuteJob(); 210 USE(status); 211 212 // Always transition to kCompiled - errors will be reported by 213 // FinalizeCompilingOnMainThread. 214 status_ = CompileJobStatus::kCompiled; 215 } 216 217 bool CompilerDispatcherJob::FinalizeCompilingOnMainThread() { 218 DCHECK(ThreadId::Current().Equals(isolate_->thread_id())); 219 DCHECK(status() == CompileJobStatus::kCompiled); 220 COMPILER_DISPATCHER_TRACE_SCOPE(tracer_, kFinalizeCompiling); 221 222 if (compile_job_->state() == CompilationJob::State::kFailed || 223 !Compiler::FinalizeCompilationJob(compile_job_.release())) { 224 if (!isolate_->has_pending_exception()) isolate_->StackOverflow(); 225 status_ = CompileJobStatus::kFailed; 226 return false; 227 } 228 229 zone_.reset(); 230 parse_info_.reset(); 231 compile_info_.reset(); 232 compile_job_.reset(); 233 handles_from_parsing_.reset(); 234 235 status_ = CompileJobStatus::kDone; 236 return true; 237 } 238 239 void CompilerDispatcherJob::ResetOnMainThread() { 240 DCHECK(ThreadId::Current().Equals(isolate_->thread_id())); 241 242 parser_.reset(); 243 unicode_cache_.reset(); 244 character_stream_.reset(); 245 parse_info_.reset(); 246 zone_.reset(); 247 handles_from_parsing_.reset(); 248 compile_info_.reset(); 249 compile_job_.reset(); 250 251 if (!source_.is_null()) { 252 i::GlobalHandles::Destroy(Handle<Object>::cast(source_).location()); 253 source_ = Handle<String>::null(); 254 } 255 256 status_ = CompileJobStatus::kInitial; 257 } 258 259 } // namespace internal 260 } // namespace v8 261