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