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_WASM_ENGINE_H_
6 : #define V8_WASM_WASM_ENGINE_H_
7 :
8 : #include <memory>
9 : #include <unordered_set>
10 :
11 : #include "src/cancelable-task.h"
12 : #include "src/wasm/wasm-code-manager.h"
13 : #include "src/wasm/wasm-memory.h"
14 : #include "src/wasm/wasm-tier.h"
15 : #include "src/zone/accounting-allocator.h"
16 :
17 : namespace v8 {
18 : namespace internal {
19 :
20 : class AsmWasmData;
21 : class CodeTracer;
22 : class CompilationStatistics;
23 : class HeapNumber;
24 : class WasmInstanceObject;
25 : class WasmModuleObject;
26 :
27 : namespace wasm {
28 :
29 : class AsyncCompileJob;
30 : class ErrorThrower;
31 : struct ModuleWireBytes;
32 : struct WasmFeatures;
33 :
34 2915 : class V8_EXPORT_PRIVATE CompilationResultResolver {
35 : public:
36 : virtual void OnCompilationSucceeded(Handle<WasmModuleObject> result) = 0;
37 : virtual void OnCompilationFailed(Handle<Object> error_reason) = 0;
38 2915 : virtual ~CompilationResultResolver() = default;
39 : };
40 :
41 9242 : class V8_EXPORT_PRIVATE InstantiationResultResolver {
42 : public:
43 : virtual void OnInstantiationSucceeded(Handle<WasmInstanceObject> result) = 0;
44 : virtual void OnInstantiationFailed(Handle<Object> error_reason) = 0;
45 9242 : virtual ~InstantiationResultResolver() = default;
46 : };
47 :
48 : // The central data structure that represents an engine instance capable of
49 : // loading, instantiating, and executing WASM code.
50 : class V8_EXPORT_PRIVATE WasmEngine {
51 : public:
52 : WasmEngine();
53 : ~WasmEngine();
54 :
55 : // Synchronously validates the given bytes that represent an encoded WASM
56 : // module.
57 : bool SyncValidate(Isolate* isolate, const WasmFeatures& enabled,
58 : const ModuleWireBytes& bytes);
59 :
60 : // Synchronously compiles the given bytes that represent a translated
61 : // asm.js module.
62 : MaybeHandle<AsmWasmData> SyncCompileTranslatedAsmJs(
63 : Isolate* isolate, ErrorThrower* thrower, const ModuleWireBytes& bytes,
64 : Vector<const byte> asm_js_offset_table_bytes,
65 : Handle<HeapNumber> uses_bitset);
66 : Handle<WasmModuleObject> FinalizeTranslatedAsmJs(
67 : Isolate* isolate, Handle<AsmWasmData> asm_wasm_data,
68 : Handle<Script> script);
69 :
70 : // Synchronously compiles the given bytes that represent an encoded WASM
71 : // module.
72 : MaybeHandle<WasmModuleObject> SyncCompile(Isolate* isolate,
73 : const WasmFeatures& enabled,
74 : ErrorThrower* thrower,
75 : const ModuleWireBytes& bytes);
76 :
77 : // Synchronously instantiate the given WASM module with the given imports.
78 : // If the module represents an asm.js module, then the supplied {memory}
79 : // should be used as the memory of the instance.
80 : MaybeHandle<WasmInstanceObject> SyncInstantiate(
81 : Isolate* isolate, ErrorThrower* thrower,
82 : Handle<WasmModuleObject> module_object, MaybeHandle<JSReceiver> imports,
83 : MaybeHandle<JSArrayBuffer> memory);
84 :
85 : // Begin an asynchronous compilation of the given bytes that represent an
86 : // encoded WASM module.
87 : // The {is_shared} flag indicates if the bytes backing the module could
88 : // be shared across threads, i.e. could be concurrently modified.
89 : void AsyncCompile(Isolate* isolate, const WasmFeatures& enabled,
90 : std::shared_ptr<CompilationResultResolver> resolver,
91 : const ModuleWireBytes& bytes, bool is_shared);
92 :
93 : // Begin an asynchronous instantiation of the given WASM module.
94 : void AsyncInstantiate(Isolate* isolate,
95 : std::unique_ptr<InstantiationResultResolver> resolver,
96 : Handle<WasmModuleObject> module_object,
97 : MaybeHandle<JSReceiver> imports);
98 :
99 : std::shared_ptr<StreamingDecoder> StartStreamingCompilation(
100 : Isolate* isolate, const WasmFeatures& enabled, Handle<Context> context,
101 : std::shared_ptr<CompilationResultResolver> resolver);
102 :
103 : // Compiles the function with the given index at a specific compilation tier.
104 : // Errors are stored internally in the CompilationState.
105 : // This is mostly used for testing to force a function into a specific tier.
106 : void CompileFunction(Isolate* isolate, NativeModule* native_module,
107 : uint32_t function_index, ExecutionTier tier);
108 :
109 : // Exports the sharable parts of the given module object so that they can be
110 : // transferred to a different Context/Isolate using the same engine.
111 : std::shared_ptr<NativeModule> ExportNativeModule(
112 : Handle<WasmModuleObject> module_object);
113 :
114 : // Imports the shared part of a module from a different Context/Isolate using
115 : // the the same engine, recreating a full module object in the given Isolate.
116 : Handle<WasmModuleObject> ImportNativeModule(
117 : Isolate* isolate, std::shared_ptr<NativeModule> shared_module);
118 :
119 57513085 : WasmCodeManager* code_manager() { return &code_manager_; }
120 :
121 561119 : WasmMemoryTracker* memory_tracker() { return &memory_tracker_; }
122 :
123 3740698 : AccountingAllocator* allocator() { return &allocator_; }
124 :
125 : // Compilation statistics for TurboFan compilations.
126 : CompilationStatistics* GetOrCreateTurboStatistics();
127 :
128 : // Prints the gathered compilation statistics, then resets them.
129 : void DumpAndResetTurboStatistics();
130 :
131 : // Used to redirect tracing output from {stdout} to a file.
132 : CodeTracer* GetCodeTracer();
133 :
134 : // Remove {job} from the list of active compile jobs.
135 : std::unique_ptr<AsyncCompileJob> RemoveCompileJob(AsyncCompileJob* job);
136 :
137 : // Returns true if at least one AsyncCompileJob that belongs to the given
138 : // Isolate is currently running.
139 : bool HasRunningCompileJob(Isolate* isolate);
140 :
141 : // Deletes all AsyncCompileJobs that belong to the given Isolate. All
142 : // compilation is aborted, no more callbacks will be triggered. This is used
143 : // for tearing down an isolate, or to clean it up to be reused.
144 : void DeleteCompileJobsOnIsolate(Isolate* isolate);
145 :
146 : // Manage the set of Isolates that use this WasmEngine.
147 : void AddIsolate(Isolate* isolate);
148 : void RemoveIsolate(Isolate* isolate);
149 :
150 : template <typename T, typename... Args>
151 : std::unique_ptr<T> NewBackgroundCompileTask(Args&&... args) {
152 : return base::make_unique<T>(&background_compile_task_manager_,
153 224224 : std::forward<Args>(args)...);
154 : }
155 :
156 : // Trigger code logging for this WasmCode in all Isolates which have access to
157 : // the NativeModule containing this code. This method can be called from
158 : // background threads.
159 : void LogCode(WasmCode*);
160 :
161 : // Enable code logging for the given Isolate. Initially, code logging is
162 : // enabled if {WasmCode::ShouldBeLogged(Isolate*)} returns true during
163 : // {AddIsolate}.
164 : void EnableCodeLogging(Isolate*);
165 :
166 : // This is called from the foreground thread of the Isolate to log all
167 : // outstanding code objects (added via {LogCode}).
168 : void LogOutstandingCodesForIsolate(Isolate*);
169 :
170 : // Create a new NativeModule. The caller is responsible for its
171 : // lifetime. The native module will be given some memory for code,
172 : // which will be page size aligned. The size of the initial memory
173 : // is determined with a heuristic based on the total size of wasm
174 : // code. The native module may later request more memory.
175 : // TODO(titzer): isolate is only required here for CompilationState.
176 : std::shared_ptr<NativeModule> NewNativeModule(
177 : Isolate* isolate, const WasmFeatures& enabled_features,
178 : size_t code_size_estimate, bool can_request_more,
179 : std::shared_ptr<const WasmModule> module);
180 :
181 : void FreeNativeModule(NativeModule*);
182 :
183 : // Sample the code size of the given {NativeModule} in all isolates that have
184 : // access to it. Call this after top-tier compilation finished.
185 : // This will spawn foreground tasks that do *not* keep the NativeModule alive.
186 : void SampleTopTierCodeSizeInAllIsolates(const std::shared_ptr<NativeModule>&);
187 :
188 : // Called by each Isolate to report its live code for a GC cycle.
189 : void ReportLiveCodeForGC(Isolate*, Vector<WasmCode*> live_code);
190 :
191 : // Add potentially dead code. The occurrence in the set of potentially dead
192 : // code counts as a reference, and is decremented on the next GC.
193 : // Returns {true} if the code was added to the set of potentially dead code,
194 : // {false} if an entry already exists. The ref count is *unchanged* in any
195 : // case.
196 : V8_WARN_UNUSED_RESULT bool AddPotentiallyDeadCode(WasmCode*);
197 :
198 : // Call on process start and exit.
199 : static void InitializeOncePerProcess();
200 : static void GlobalTearDown();
201 :
202 : // Constructs a WasmEngine instance. Depending on whether we are sharing
203 : // engines this might be a pointer to a new instance or to a shared one.
204 : static std::shared_ptr<WasmEngine> GetWasmEngine();
205 :
206 : private:
207 : struct CurrentGCInfo;
208 : struct IsolateInfo;
209 : struct NativeModuleInfo;
210 :
211 : AsyncCompileJob* CreateAsyncCompileJob(
212 : Isolate* isolate, const WasmFeatures& enabled,
213 : std::unique_ptr<byte[]> bytes_copy, size_t length,
214 : Handle<Context> context,
215 : std::shared_ptr<CompilationResultResolver> resolver);
216 :
217 : void TriggerGC();
218 :
219 : WasmMemoryTracker memory_tracker_;
220 : WasmCodeManager code_manager_;
221 : AccountingAllocator allocator_;
222 :
223 : // Task manager managing all background compile jobs. Before shut down of the
224 : // engine, they must all be finished because they access the allocator.
225 : CancelableTaskManager background_compile_task_manager_;
226 :
227 : // This mutex protects all information which is mutated concurrently or
228 : // fields that are initialized lazily on the first access.
229 : base::Mutex mutex_;
230 :
231 : //////////////////////////////////////////////////////////////////////////////
232 : // Protected by {mutex_}:
233 :
234 : // We use an AsyncCompileJob as the key for itself so that we can delete the
235 : // job from the map when it is finished.
236 : std::unordered_map<AsyncCompileJob*, std::unique_ptr<AsyncCompileJob>>
237 : async_compile_jobs_;
238 :
239 : std::unique_ptr<CompilationStatistics> compilation_stats_;
240 : std::unique_ptr<CodeTracer> code_tracer_;
241 :
242 : // Set of isolates which use this WasmEngine.
243 : std::unordered_map<Isolate*, std::unique_ptr<IsolateInfo>> isolates_;
244 :
245 : // Set of native modules managed by this engine.
246 : std::unordered_map<NativeModule*, std::unique_ptr<NativeModuleInfo>>
247 : native_modules_;
248 :
249 : // Size of code that became dead since the last GC. If this exceeds a certain
250 : // threshold, a new GC is triggered.
251 : size_t new_potentially_dead_code_size_ = 0;
252 :
253 : // If an engine-wide GC is currently running, this pointer stores information
254 : // about that.
255 : std::unique_ptr<CurrentGCInfo> current_gc_info_;
256 :
257 : // End of fields protected by {mutex_}.
258 : //////////////////////////////////////////////////////////////////////////////
259 :
260 : DISALLOW_COPY_AND_ASSIGN(WasmEngine);
261 : };
262 :
263 : } // namespace wasm
264 : } // namespace internal
265 : } // namespace v8
266 :
267 : #endif // V8_WASM_WASM_ENGINE_H_
|