compiler.h 15.8 KB
Newer Older
1
// Copyright 2012 the V8 project authors. All rights reserved.
2 3
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
4 5 6 7

#ifndef V8_COMPILER_H_
#define V8_COMPILER_H_

8
#include <forward_list>
9 10
#include <memory>

11
#include "src/allocation.h"
12
#include "src/bailout-reason.h"
13
#include "src/code-events.h"
14 15
#include "src/contexts.h"
#include "src/isolate.h"
16
#include "src/zone/zone.h"
17

18 19
namespace v8 {
namespace internal {
20

21
// Forward declarations.
22
class AstRawString;
23
class BackgroundCompileTask;
24
class IsCompiledScope;
25
class JavaScriptFrame;
26 27
class OptimizedCompilationInfo;
class OptimizedCompilationJob;
28
class ParseInfo;
29
class Parser;
30
class ScriptData;
31
struct ScriptStreamingData;
32
class TimedHistogram;
33 34
class UnoptimizedCompilationInfo;
class UnoptimizedCompilationJob;
35
class WorkerThreadRuntimeCallStats;
36

37 38
typedef std::forward_list<std::unique_ptr<UnoptimizedCompilationJob>>
    UnoptimizedCompilationJobList;
39

40 41 42 43 44 45 46 47 48 49
// The V8 compiler API.
//
// This is the central hub for dispatching to the various compilers within V8.
// Logic for which compiler to choose and how to wire compilation results into
// the object heap should be kept inside this class.
//
// General strategy: Scripts are translated into anonymous functions w/o
// parameters which then can be executed. If the source code contains other
// functions, they might be compiled and allocated as part of the compilation
// of the source code or deferred for lazy compilation at a later point.
50
class V8_EXPORT_PRIVATE Compiler : public AllStatic {
51 52 53 54 55 56 57 58 59
 public:
  enum ClearExceptionFlag { KEEP_EXCEPTION, CLEAR_EXCEPTION };

  // ===========================================================================
  // The following family of methods ensures a given function is compiled. The
  // general contract is that failures will be reported by returning {false},
  // whereas successful compilation ensures the {is_compiled} predicate on the
  // given function holds (except for live-edit, which compiles the world).

60
  static bool Compile(Handle<SharedFunctionInfo> shared,
61 62 63 64
                      ClearExceptionFlag flag,
                      IsCompiledScope* is_compiled_scope);
  static bool Compile(Handle<JSFunction> function, ClearExceptionFlag flag,
                      IsCompiledScope* is_compiled_scope);
65
  static bool CompileOptimized(Handle<JSFunction> function, ConcurrencyMode);
66

67 68 69 70 71 72
  // Collect source positions for a function that has already been compiled to
  // bytecode, but for which source positions were not collected (e.g. because
  // they were not immediately needed).
  static bool CollectSourcePositions(Isolate* isolate,
                                     Handle<SharedFunctionInfo> shared);

73 74
  V8_WARN_UNUSED_RESULT static MaybeHandle<SharedFunctionInfo>
  CompileForLiveEdit(ParseInfo* parse_info, Isolate* isolate);
75

76 77 78 79 80 81 82 83
  // Finalize and install code from previously run background compile task.
  static bool FinalizeBackgroundCompileTask(
      BackgroundCompileTask* task, Handle<SharedFunctionInfo> shared_info,
      Isolate* isolate, ClearExceptionFlag flag);

  // Finalize and install optimized code from previously run job.
  static bool FinalizeOptimizedCompilationJob(OptimizedCompilationJob* job,
                                              Isolate* isolate);
84 85 86 87 88 89 90

  // Give the compiler a chance to perform low-latency initialization tasks of
  // the given {function} on its instantiation. Note that only the runtime will
  // offer this chance, optimized closure instantiation will not call this.
  static void PostInstantiation(Handle<JSFunction> function, PretenureFlag);

  // Parser::Parse, then Compiler::Analyze.
91
  static bool ParseAndAnalyze(ParseInfo* parse_info,
92 93
                              Handle<SharedFunctionInfo> shared_info,
                              Isolate* isolate);
94
  // Rewrite and analyze scopes.
95
  static bool Analyze(ParseInfo* parse_info);
96

97 98 99 100 101 102 103 104 105 106
  // ===========================================================================
  // The following family of methods instantiates new functions for scripts or
  // function literals. The decision whether those functions will be compiled,
  // is left to the discretion of the compiler.
  //
  // Please note this interface returns shared function infos.  This means you
  // need to call Factory::NewFunctionFromSharedFunctionInfo before you have a
  // real function with a context.

  // Create a (bound) function for a String source within a context for eval.
107
  V8_WARN_UNUSED_RESULT static MaybeHandle<JSFunction> GetFunctionFromEval(
108 109
      Handle<String> source, Handle<SharedFunctionInfo> outer_info,
      Handle<Context> context, LanguageMode language_mode,
110
      ParseRestriction restriction, int parameters_end_pos,
111
      int eval_scope_position, int eval_position);
112

113 114 115 116 117 118 119 120 121 122 123 124
  struct ScriptDetails {
    ScriptDetails() : line_offset(0), column_offset(0) {}
    explicit ScriptDetails(Handle<Object> script_name)
        : line_offset(0), column_offset(0), name_obj(script_name) {}

    int line_offset;
    int column_offset;
    i::MaybeHandle<i::Object> name_obj;
    i::MaybeHandle<i::Object> source_map_url;
    i::MaybeHandle<i::FixedArray> host_defined_options;
  };

125 126
  // Create a function that results from wrapping |source| in a function,
  // with |arguments| being a list of parameters for that function.
127
  V8_WARN_UNUSED_RESULT static MaybeHandle<JSFunction> GetWrappedFunction(
128
      Handle<String> source, Handle<FixedArray> arguments,
129 130 131 132
      Handle<Context> context, const ScriptDetails& script_details,
      ScriptOriginOptions origin_options, ScriptData* cached_data,
      v8::ScriptCompiler::CompileOptions compile_options,
      v8::ScriptCompiler::NoCacheReason no_cache_reason);
133

134 135 136 137 138 139
  // Returns true if the embedder permits compiling the given source string in
  // the given context.
  static bool CodeGenerationFromStringsAllowed(Isolate* isolate,
                                               Handle<Context> context,
                                               Handle<String> source);

140
  // Create a (bound) function for a String source within a context for eval.
141
  V8_WARN_UNUSED_RESULT static MaybeHandle<JSFunction> GetFunctionFromString(
142
      Handle<Context> context, Handle<String> source,
143
      ParseRestriction restriction, int parameters_end_pos);
144

145
  // Create a shared function info object for a String source.
146
  static MaybeHandle<SharedFunctionInfo> GetSharedFunctionInfoForScript(
147 148 149 150
      Isolate* isolate, Handle<String> source,
      const ScriptDetails& script_details, ScriptOriginOptions origin_options,
      v8::Extension* extension, ScriptData* cached_data,
      ScriptCompiler::CompileOptions compile_options,
151
      ScriptCompiler::NoCacheReason no_cache_reason,
152 153 154 155 156 157 158
      NativesFlag is_natives_code);

  // Create a shared function info object for a Script source that has already
  // been parsed and possibly compiled on a background thread while being loaded
  // from a streamed source. On return, the data held by |streaming_data| will
  // have been released, however the object itself isn't freed and is still
  // owned by the caller.
159
  static MaybeHandle<SharedFunctionInfo> GetSharedFunctionInfoForStreamedScript(
160 161 162
      Isolate* isolate, Handle<String> source,
      const ScriptDetails& script_details, ScriptOriginOptions origin_options,
      ScriptStreamingData* streaming_data);
163

164 165 166 167 168 169
  // Create a shared function info object for the given function literal
  // node (the code may be lazily compiled).
  static Handle<SharedFunctionInfo> GetSharedFunctionInfo(FunctionLiteral* node,
                                                          Handle<Script> script,
                                                          Isolate* isolate);

170 171 172 173 174 175 176 177 178 179
  // ===========================================================================
  // The following family of methods provides support for OSR. Code generated
  // for entry via OSR might not be suitable for normal entry, hence will be
  // returned directly to the caller.
  //
  // Please note this interface is the only part dealing with {Code} objects
  // directly. Other methods are agnostic to {Code} and can use an interpreter
  // instead of generating JIT code for a function at all.

  // Generate and return optimized code for OSR, or empty handle on failure.
180
  V8_WARN_UNUSED_RESULT static MaybeHandle<Code> GetOptimizedCodeForOSR(
181
      Handle<JSFunction> function, BailoutId osr_offset,
182 183
      JavaScriptFrame* osr_frame);
};
184

185
// A base class for compilation jobs intended to run concurrent to the main
186
// thread. The current state of the job can be checked using {state()}.
187
class V8_EXPORT_PRIVATE CompilationJob {
188
 public:
189 190 191 192 193 194 195 196
  enum Status { SUCCEEDED, FAILED };
  enum class State {
    kReadyToPrepare,
    kReadyToExecute,
    kReadyToFinalize,
    kSucceeded,
    kFailed,
  };
197 198 199

  CompilationJob(uintptr_t stack_limit, State initial_state)
      : state_(initial_state), stack_limit_(stack_limit) {}
200
  virtual ~CompilationJob() = default;
201

202 203 204 205 206 207
  void set_stack_limit(uintptr_t stack_limit) { stack_limit_ = stack_limit; }
  uintptr_t stack_limit() const { return stack_limit_; }

  State state() const { return state_; }

 protected:
208
  V8_WARN_UNUSED_RESULT Status UpdateState(Status status, State next_state) {
209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238
    if (status == SUCCEEDED) {
      state_ = next_state;
    } else {
      state_ = State::kFailed;
    }
    return status;
  }

 private:
  State state_;
  uintptr_t stack_limit_;
};

// A base class for unoptimized compilation jobs.
//
// The job is split into two phases which are called in sequence on
// different threads and with different limitations:
//  1) ExecuteJob:   Runs concurrently. No heap allocation or handle derefs.
//  2) FinalizeJob:  Runs on main thread. No dependency changes.
//
// Either of phases can either fail or succeed.
class UnoptimizedCompilationJob : public CompilationJob {
 public:
  UnoptimizedCompilationJob(intptr_t stack_limit, ParseInfo* parse_info,
                            UnoptimizedCompilationInfo* compilation_info)
      : CompilationJob(stack_limit, State::kReadyToExecute),
        parse_info_(parse_info),
        compilation_info_(compilation_info) {}

  // Executes the compile job. Can be called on a background thread.
239
  V8_WARN_UNUSED_RESULT Status ExecuteJob();
240 241

  // Finalizes the compile job. Must be called on the main thread.
242 243
  V8_WARN_UNUSED_RESULT Status
  FinalizeJob(Handle<SharedFunctionInfo> shared_info, Isolate* isolate);
244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278

  void RecordCompilationStats(Isolate* isolate) const;
  void RecordFunctionCompilation(CodeEventListener::LogEventsAndTags tag,
                                 Handle<SharedFunctionInfo> shared,
                                 Isolate* isolate) const;

  ParseInfo* parse_info() const { return parse_info_; }
  UnoptimizedCompilationInfo* compilation_info() const {
    return compilation_info_;
  }

 protected:
  // Overridden by the actual implementation.
  virtual Status ExecuteJobImpl() = 0;
  virtual Status FinalizeJobImpl(Handle<SharedFunctionInfo> shared_info,
                                 Isolate* isolate) = 0;

 private:
  ParseInfo* parse_info_;
  UnoptimizedCompilationInfo* compilation_info_;
  base::TimeDelta time_taken_to_execute_;
  base::TimeDelta time_taken_to_finalize_;
};

// A base class for optimized compilation jobs.
//
// The job is split into three phases which are called in sequence on
// different threads and with different limitations:
//  1) PrepareJob:   Runs on main thread. No major limitations.
//  2) ExecuteJob:   Runs concurrently. No heap allocation or handle derefs.
//  3) FinalizeJob:  Runs on main thread. No dependency changes.
//
// Each of the three phases can either fail or succeed.
class OptimizedCompilationJob : public CompilationJob {
 public:
279
  OptimizedCompilationJob(uintptr_t stack_limit,
280 281 282 283 284 285 286
                          OptimizedCompilationInfo* compilation_info,
                          const char* compiler_name,
                          State initial_state = State::kReadyToPrepare)
      : CompilationJob(stack_limit, initial_state),
        compilation_info_(compilation_info),
        compiler_name_(compiler_name) {}

287
  // Prepare the compile job. Must be called on the main thread.
288
  V8_WARN_UNUSED_RESULT Status PrepareJob(Isolate* isolate);
289

290 291
  // Executes the compile job. Can be called on a background thread if
  // can_execute_on_background_thread() returns true.
292
  V8_WARN_UNUSED_RESULT Status ExecuteJob();
293

294
  // Finalizes the compile job. Must be called on the main thread.
295
  V8_WARN_UNUSED_RESULT Status FinalizeJob(Isolate* isolate);
296

297 298
  // Report a transient failure, try again next time. Should only be called on
  // optimization compilation jobs.
299
  Status RetryOptimization(BailoutReason reason);
300

301 302
  // Report a persistent failure, disable future optimization on the function.
  // Should only be called on optimization compilation jobs.
303
  Status AbortOptimization(BailoutReason reason);
304

305
  void RecordCompilationStats() const;
306 307
  void RecordFunctionCompilation(CodeEventListener::LogEventsAndTags tag,
                                 Isolate* isolate) const;
308

309 310 311
  OptimizedCompilationInfo* compilation_info() const {
    return compilation_info_;
  }
312

313
 protected:
314
  // Overridden by the actual implementation.
315
  virtual Status PrepareJobImpl(Isolate* isolate) = 0;
316
  virtual Status ExecuteJobImpl() = 0;
317
  virtual Status FinalizeJobImpl(Isolate* isolate) = 0;
318

319
 private:
320
  OptimizedCompilationInfo* compilation_info_;
321 322 323
  base::TimeDelta time_taken_to_prepare_;
  base::TimeDelta time_taken_to_execute_;
  base::TimeDelta time_taken_to_finalize_;
324
  const char* compiler_name_;
325 326
};

327
class V8_EXPORT_PRIVATE BackgroundCompileTask {
328 329 330 331 332 333
 public:
  // Creates a new task that when run will parse and compile the streamed
  // script associated with |data| and can be finalized with
  // Compiler::GetSharedFunctionInfoForStreamedScript.
  // Note: does not take ownership of |data|.
  BackgroundCompileTask(ScriptStreamingData* data, Isolate* isolate);
334
  ~BackgroundCompileTask();
335

336 337 338 339 340 341 342 343 344 345
  // Creates a new task that when run will parse and compile the
  // |function_literal| and can be finalized with
  // Compiler::FinalizeBackgroundCompileTask.
  BackgroundCompileTask(
      AccountingAllocator* allocator, const ParseInfo* outer_parse_info,
      const AstRawString* function_name,
      const FunctionLiteral* function_literal,
      WorkerThreadRuntimeCallStats* worker_thread_runtime_stats,
      TimedHistogram* timer, int max_stack_size);

346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375
  void Run();

  ParseInfo* info() { return info_.get(); }
  Parser* parser() { return parser_.get(); }
  UnoptimizedCompilationJob* outer_function_job() {
    return outer_function_job_.get();
  }
  UnoptimizedCompilationJobList* inner_function_jobs() {
    return &inner_function_jobs_;
  }

 private:
  // Data needed for parsing, and data needed to to be passed between thread
  // between parsing and compilation. These need to be initialized before the
  // compilation starts.
  std::unique_ptr<ParseInfo> info_;
  std::unique_ptr<Parser> parser_;

  // Data needed for finalizing compilation after background compilation.
  std::unique_ptr<UnoptimizedCompilationJob> outer_function_job_;
  UnoptimizedCompilationJobList inner_function_jobs_;

  int stack_size_;
  WorkerThreadRuntimeCallStats* worker_thread_runtime_call_stats_;
  AccountingAllocator* allocator_;
  TimedHistogram* timer_;

  DISALLOW_COPY_AND_ASSIGN(BackgroundCompileTask);
};

376 377 378 379 380 381 382 383 384 385 386 387 388
// Contains all data which needs to be transmitted between threads for
// background parsing and compiling and finalizing it on the main thread.
struct ScriptStreamingData {
  ScriptStreamingData(ScriptCompiler::ExternalSourceStream* source_stream,
                      ScriptCompiler::StreamedSource::Encoding encoding);
  ~ScriptStreamingData();

  void Release();

  // Internal implementation of v8::ScriptCompiler::StreamedSource.
  std::unique_ptr<ScriptCompiler::ExternalSourceStream> source_stream;
  ScriptCompiler::StreamedSource::Encoding encoding;

389 390
  // Task that performs background parsing and compilation.
  std::unique_ptr<BackgroundCompileTask> task;
391 392 393 394

  DISALLOW_COPY_AND_ASSIGN(ScriptStreamingData);
};

395 396
}  // namespace internal
}  // namespace v8
397 398

#endif  // V8_COMPILER_H_