Home | History | Annotate | Download | only in compiler-dispatcher
      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