1 // Copyright 2017 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 #ifndef V8_WASM_MODULE_COMPILER_H_
6 #define V8_WASM_MODULE_COMPILER_H_
7 
8 #include <functional>
9 #include <memory>
10 
11 #include "src/base/atomic-utils.h"
12 #include "src/cancelable-task.h"
13 #include "src/globals.h"
14 #include "src/wasm/wasm-module.h"
15 
16 namespace v8 {
17 namespace internal {
18 
19 class JSArrayBuffer;
20 class JSPromise;
21 class Counters;
22 class WasmModuleObject;
23 class WasmInstanceObject;
24 
25 template <typename T>
26 class Vector;
27 
28 namespace wasm {
29 
30 class CompilationState;
31 class ErrorThrower;
32 class ModuleCompiler;
33 class WasmCode;
34 struct ModuleEnv;
35 struct WasmModule;
36 
37 struct CompilationStateDeleter {
38   void operator()(CompilationState* compilation_state) const;
39 };
40 
41 // Wrapper to create a CompilationState exists in order to avoid having
42 // the the CompilationState in the header file.
43 std::unique_ptr<CompilationState, CompilationStateDeleter> NewCompilationState(
44     Isolate* isolate, ModuleEnv& env);
45 
46 ModuleEnv* GetModuleEnv(CompilationState* compilation_state);
47 
48 MaybeHandle<WasmModuleObject> CompileToModuleObject(
49     Isolate* isolate, ErrorThrower* thrower, std::unique_ptr<WasmModule> module,
50     const ModuleWireBytes& wire_bytes, Handle<Script> asm_js_script,
51     Vector<const byte> asm_js_offset_table_bytes);
52 
53 MaybeHandle<WasmInstanceObject> InstantiateToInstanceObject(
54     Isolate* isolate, ErrorThrower* thrower,
55     Handle<WasmModuleObject> module_object, MaybeHandle<JSReceiver> imports,
56     MaybeHandle<JSArrayBuffer> memory);
57 
58 V8_EXPORT_PRIVATE
59 void CompileJsToWasmWrappers(Isolate* isolate,
60                              Handle<WasmModuleObject> module_object,
61                              Counters* counters);
62 
63 V8_EXPORT_PRIVATE Handle<Script> CreateWasmScript(
64     Isolate* isolate, const ModuleWireBytes& wire_bytes);
65 
66 // Triggered by the WasmCompileLazy builtin.
67 // Walks the stack (top three frames) to determine the wasm instance involved
68 // and which function to compile.
69 // Then triggers WasmCompiledModule::CompileLazy, taking care of correctly
70 // patching the call site or indirect function tables.
71 // Returns either the Code object that has been lazily compiled, or Illegal if
72 // an error occurred. In the latter case, a pending exception has been set,
73 // which will be triggered when returning from the runtime function, i.e. the
74 // Illegal builtin will never be called.
75 Address CompileLazy(Isolate* isolate, Handle<WasmInstanceObject> instance);
76 
77 // Encapsulates all the state and steps of an asynchronous compilation.
78 // An asynchronous compile job consists of a number of tasks that are executed
79 // as foreground and background tasks. Any phase that touches the V8 heap or
80 // allocates on the V8 heap (e.g. creating the module object) must be a
81 // foreground task. All other tasks (e.g. decoding and validating, the majority
82 // of the work of compilation) can be background tasks.
83 // TODO(wasm): factor out common parts of this with the synchronous pipeline.
84 class AsyncCompileJob {
85  public:
86   explicit AsyncCompileJob(Isolate* isolate, std::unique_ptr<byte[]> bytes_copy,
87                            size_t length, Handle<Context> context,
88                            Handle<JSPromise> promise);
89 
90   void Start();
91 
92   std::shared_ptr<StreamingDecoder> CreateStreamingDecoder();
93 
94   void Abort();
95 
96   ~AsyncCompileJob();
97 
98  private:
99   class CompileTask;
100   class CompileStep;
101 
102   // States of the AsyncCompileJob.
103   class DecodeModule;
104   class DecodeFail;
105   class PrepareAndStartCompile;
106   class CompileFailed;
107   class CompileWrappers;
108   class FinishModule;
109   class AbortCompilation;
110   class UpdateToTopTierCompiledCode;
111 
async_counters()112   const std::shared_ptr<Counters>& async_counters() const {
113     return async_counters_;
114   }
counters()115   Counters* counters() const { return async_counters().get(); }
116 
117   void FinishCompile();
118 
119   void AsyncCompileFailed(Handle<Object> error_reason);
120 
121   void AsyncCompileSucceeded(Handle<Object> result);
122 
123   void StartForegroundTask();
124 
125   void StartBackgroundTask();
126 
127   // Switches to the compilation step {Step} and starts a foreground task to
128   // execute it.
129   template <typename Step, typename... Args>
130   void DoSync(Args&&... args);
131 
132   // Switches to the compilation step {Step} and starts a background task to
133   // execute it.
134   template <typename Step, typename... Args>
135   void DoAsync(Args&&... args);
136 
137   // Switches to the compilation step {Step} but does not start a task to
138   // execute it.
139   template <typename Step, typename... Args>
140   void NextStep(Args&&... args);
141 
isolate()142   Isolate* isolate() { return isolate_; }
143 
144   friend class AsyncStreamingProcessor;
145 
146   Isolate* isolate_;
147   const std::shared_ptr<Counters> async_counters_;
148   std::unique_ptr<byte[]> bytes_copy_;
149   ModuleWireBytes wire_bytes_;
150   Handle<Context> context_;
151   Handle<JSPromise> module_promise_;
152   std::unique_ptr<WasmModule> module_;
153 
154   std::vector<DeferredHandles*> deferred_handles_;
155   Handle<WasmCompiledModule> compiled_module_;
156   Handle<WasmModuleObject> module_object_;
157 
158   std::unique_ptr<CompileStep> step_;
159   CancelableTaskManager background_task_manager_;
160   Handle<Code> centry_stub_;
161 
162   std::shared_ptr<v8::TaskRunner> foreground_task_runner_;
163   std::shared_ptr<v8::TaskRunner> background_task_runner_;
164 
165   // For async compilation the AsyncCompileJob is the only finisher. For
166   // streaming compilation also the AsyncStreamingProcessor has to finish before
167   // compilation can be finished.
168   base::AtomicNumber<int32_t> outstanding_finishers_{1};
169 
170   // Decrements the number of outstanding finishers. The last caller of this
171   // function should finish the asynchronous compilation, see the comment on
172   // {outstanding_finishers_}.
DecrementAndCheckFinisherCount()173   V8_WARN_UNUSED_RESULT bool DecrementAndCheckFinisherCount() {
174     return outstanding_finishers_.Decrement(1) == 0;
175   }
176 
177   // Counts the number of pending foreground tasks.
178   int32_t num_pending_foreground_tasks_ = 0;
179 
180   // The AsyncCompileJob owns the StreamingDecoder because the StreamingDecoder
181   // contains data which is needed by the AsyncCompileJob for streaming
182   // compilation. The AsyncCompileJob does not actively use the
183   // StreamingDecoder.
184   std::shared_ptr<StreamingDecoder> stream_;
185 
186   bool tiering_completed_ = false;
187 };
188 }  // namespace wasm
189 }  // namespace internal
190 }  // namespace v8
191 
192 #endif  // V8_WASM_MODULE_COMPILER_H_
193