compiler.h 15.5 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

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

70 71 72 73 74 75 76 77
  // 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);
78 79 80 81 82 83 84

  // 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.
85
  static bool ParseAndAnalyze(ParseInfo* parse_info,
86 87
                              Handle<SharedFunctionInfo> shared_info,
                              Isolate* isolate);
88
  // Rewrite and analyze scopes.
89
  static bool Analyze(ParseInfo* parse_info);
90

91 92 93 94 95 96 97 98 99 100
  // ===========================================================================
  // 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.
101
  V8_WARN_UNUSED_RESULT static MaybeHandle<JSFunction> GetFunctionFromEval(
102 103
      Handle<String> source, Handle<SharedFunctionInfo> outer_info,
      Handle<Context> context, LanguageMode language_mode,
104
      ParseRestriction restriction, int parameters_end_pos,
105
      int eval_scope_position, int eval_position);
106

107 108 109 110 111 112 113 114 115 116 117 118
  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;
  };

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

128 129 130 131 132 133
  // 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);

134
  // Create a (bound) function for a String source within a context for eval.
135
  V8_WARN_UNUSED_RESULT static MaybeHandle<JSFunction> GetFunctionFromString(
136
      Handle<Context> context, Handle<String> source,
137
      ParseRestriction restriction, int parameters_end_pos);
138

139
  // Create a shared function info object for a String source.
140
  static MaybeHandle<SharedFunctionInfo> GetSharedFunctionInfoForScript(
141 142 143 144
      Isolate* isolate, Handle<String> source,
      const ScriptDetails& script_details, ScriptOriginOptions origin_options,
      v8::Extension* extension, ScriptData* cached_data,
      ScriptCompiler::CompileOptions compile_options,
145
      ScriptCompiler::NoCacheReason no_cache_reason,
146 147 148 149 150 151 152
      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.
153
  static MaybeHandle<SharedFunctionInfo> GetSharedFunctionInfoForStreamedScript(
154 155 156
      Isolate* isolate, Handle<String> source,
      const ScriptDetails& script_details, ScriptOriginOptions origin_options,
      ScriptStreamingData* streaming_data);
157

158 159 160 161 162 163
  // 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);

164 165 166 167 168 169 170 171 172 173
  // ===========================================================================
  // 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.
174
  V8_WARN_UNUSED_RESULT static MaybeHandle<Code> GetOptimizedCodeForOSR(
175
      Handle<JSFunction> function, BailoutId osr_offset,
176 177
      JavaScriptFrame* osr_frame);
};
178

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

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

196 197 198 199 200 201
  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:
202
  V8_WARN_UNUSED_RESULT Status UpdateState(Status status, State next_state) {
203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232
    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.
233
  V8_WARN_UNUSED_RESULT Status ExecuteJob();
234 235

  // Finalizes the compile job. Must be called on the main thread.
236 237
  V8_WARN_UNUSED_RESULT Status
  FinalizeJob(Handle<SharedFunctionInfo> shared_info, Isolate* isolate);
238 239 240 241 242 243 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

  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:
273
  OptimizedCompilationJob(uintptr_t stack_limit,
274 275 276 277 278 279 280
                          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) {}

281
  // Prepare the compile job. Must be called on the main thread.
282
  V8_WARN_UNUSED_RESULT Status PrepareJob(Isolate* isolate);
283

284 285
  // Executes the compile job. Can be called on a background thread if
  // can_execute_on_background_thread() returns true.
286
  V8_WARN_UNUSED_RESULT Status ExecuteJob();
287

288
  // Finalizes the compile job. Must be called on the main thread.
289
  V8_WARN_UNUSED_RESULT Status FinalizeJob(Isolate* isolate);
290

291 292
  // Report a transient failure, try again next time. Should only be called on
  // optimization compilation jobs.
293
  Status RetryOptimization(BailoutReason reason);
294

295 296
  // Report a persistent failure, disable future optimization on the function.
  // Should only be called on optimization compilation jobs.
297
  Status AbortOptimization(BailoutReason reason);
298

299
  void RecordCompilationStats() const;
300 301
  void RecordFunctionCompilation(CodeEventListener::LogEventsAndTags tag,
                                 Isolate* isolate) const;
302

303 304 305
  OptimizedCompilationInfo* compilation_info() const {
    return compilation_info_;
  }
306

307
 protected:
308
  // Overridden by the actual implementation.
309
  virtual Status PrepareJobImpl(Isolate* isolate) = 0;
310
  virtual Status ExecuteJobImpl() = 0;
311
  virtual Status FinalizeJobImpl(Isolate* isolate) = 0;
312

313
 private:
314
  OptimizedCompilationInfo* compilation_info_;
315 316 317
  base::TimeDelta time_taken_to_prepare_;
  base::TimeDelta time_taken_to_execute_;
  base::TimeDelta time_taken_to_finalize_;
318
  const char* compiler_name_;
319 320
};

321
class V8_EXPORT_PRIVATE BackgroundCompileTask {
322 323 324 325 326 327
 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);
328
  ~BackgroundCompileTask();
329

330 331 332 333 334 335 336 337 338 339
  // 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);

340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369
  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);
};

370 371 372 373 374 375 376 377 378 379 380 381 382
// 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;

383 384
  // Task that performs background parsing and compilation.
  std::unique_ptr<BackgroundCompileTask> task;
385 386 387 388

  DISALLOW_COPY_AND_ASSIGN(ScriptStreamingData);
};

389 390
}  // namespace internal
}  // namespace v8
391 392

#endif  // V8_COMPILER_H_