v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
wasm-engine.h
Go to the documentation of this file.
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#if !V8_ENABLE_WEBASSEMBLY
9#error This header should only be included if WebAssembly is enabled.
10#endif // !V8_ENABLE_WEBASSEMBLY
11
12#include <algorithm>
13#include <map>
14#include <memory>
15#include <optional>
16#include <unordered_map>
17#include <unordered_set>
18
25#include "src/wasm/stacks.h"
27#include "src/wasm/wasm-tier.h"
29
30namespace v8 {
31namespace internal {
32
33class AsmWasmData;
34class CodeTracer;
35class CompilationStatistics;
36class HeapNumber;
37class WasmInstanceObject;
38class WasmModuleObject;
39class JSArrayBuffer;
40
41namespace wasm {
42
43#ifdef V8_ENABLE_WASM_GDB_REMOTE_DEBUGGING
44namespace gdb_server {
45class GdbServer;
46} // namespace gdb_server
47#endif // V8_ENABLE_WASM_GDB_REMOTE_DEBUGGING
48
49class AsyncCompileJob;
50class ErrorThrower;
51struct ModuleWireBytes;
52class StreamingDecoder;
53class WasmEnabledFeatures;
54class WasmOrphanedGlobalHandle;
55
63
71
72// Native modules cached by their wire bytes and compile-time imports.
74 public:
75 struct Key {
81
82 // Store the prefix hash as part of the key for faster lookup, and to
83 // quickly check existing prefixes for streaming compilation.
87
88 bool operator==(const Key& other) const {
89 bool eq = bytes == other.bytes &&
90 compile_imports.compare(other.compile_imports) == 0;
91 DCHECK_IMPLIES(eq, prefix_hash == other.prefix_hash);
92 return eq;
93 }
94
95 bool operator<(const Key& other) const {
96 if (prefix_hash != other.prefix_hash) {
97 DCHECK_IMPLIES(!bytes.empty() && !other.bytes.empty(),
98 bytes != other.bytes);
99 return prefix_hash < other.prefix_hash;
100 }
101 if (bytes.size() != other.bytes.size()) {
102 return bytes.size() < other.bytes.size();
103 }
104 if (int cmp = compile_imports.compare(other.compile_imports)) {
105 return cmp < 0;
106 }
107 // Fast path when the base pointers are the same.
108 // Also handles the {nullptr} case which would be UB for memcmp.
109 if (bytes.begin() == other.bytes.begin()) {
110 DCHECK_EQ(prefix_hash, other.prefix_hash);
111 return false;
112 }
113 DCHECK_NOT_NULL(bytes.begin());
114 DCHECK_NOT_NULL(other.bytes.begin());
115 return memcmp(bytes.begin(), other.bytes.begin(), bytes.size()) < 0;
116 }
117 };
118
119 std::shared_ptr<NativeModule> MaybeGetNativeModule(
120 ModuleOrigin origin, base::Vector<const uint8_t> wire_bytes,
121 const CompileTimeImports& compile_imports);
123 size_t prefix_hash, const CompileTimeImports& compile_imports);
124 void StreamingCompilationFailed(size_t prefix_hash,
125 const CompileTimeImports& compile_imports);
126 std::shared_ptr<NativeModule> Update(
127 std::shared_ptr<NativeModule> native_module, bool error);
128 void Erase(NativeModule* native_module);
129
130 bool empty() const { return map_.empty(); }
131
132 // Hash the wire bytes up to the code section header. Used as a heuristic to
133 // avoid streaming compilation of modules that are likely already in the
134 // cache. See {GetStreamingCompilationOwnership}. Assumes that the bytes have
135 // already been validated.
136 static size_t PrefixHash(base::Vector<const uint8_t> wire_bytes);
137
138 private:
139 // Each key points to the corresponding native module's wire bytes, so they
140 // should always be valid as long as the native module is alive. When
141 // the native module dies, {FreeNativeModule} deletes the entry from the
142 // map, so that we do not leave any dangling key pointing to an expired
143 // weak_ptr. This also serves as a way to regularly clean up the map, which
144 // would otherwise accumulate expired entries.
145 // A {nullopt} value is inserted to indicate that this native module is
146 // currently being created in some thread, and that other threads should wait
147 // before trying to get it from the cache.
148 // By contrast, an expired {weak_ptr} indicates that the native module died
149 // and will soon be cleaned up from the cache.
150 std::map<Key, std::optional<std::weak_ptr<NativeModule>>> map_;
151
153
154 // This condition variable is used to synchronize threads compiling the same
155 // module. Only one thread will create the {NativeModule}. Other threads
156 // will wait on this variable until the first thread wakes them up.
158};
159
160// The central data structure that represents an engine instance capable of
161// loading, instantiating, and executing Wasm code.
163 class LogCodesTask;
164
165 public:
166 WasmEngine();
167 WasmEngine(const WasmEngine&) = delete;
168 WasmEngine& operator=(const WasmEngine&) = delete;
169 ~WasmEngine();
170
171 // Synchronously validates the given bytes. Returns whether the bytes
172 // represent a valid encoded Wasm module.
173 bool SyncValidate(Isolate* isolate, WasmEnabledFeatures enabled,
174 CompileTimeImports compile_imports,
176
177 // Synchronously compiles the given bytes that represent a translated
178 // asm.js module.
179 MaybeHandle<AsmWasmData> SyncCompileTranslatedAsmJs(
180 Isolate* isolate, ErrorThrower* thrower,
182 base::Vector<const uint8_t> asm_js_offset_table_bytes,
183 DirectHandle<HeapNumber> uses_bitset, LanguageMode language_mode);
184 DirectHandle<WasmModuleObject> FinalizeTranslatedAsmJs(
185 Isolate* isolate, DirectHandle<AsmWasmData> asm_wasm_data,
186 DirectHandle<Script> script);
187
188 // Synchronously compiles the given bytes that represent an encoded Wasm
189 // module.
191 Isolate* isolate, WasmEnabledFeatures enabled,
192 CompileTimeImports compile_imports, ErrorThrower* thrower,
194
195 // Synchronously instantiate the given Wasm module with the given imports.
196 // If the module represents an asm.js module, then the supplied {memory}
197 // should be used as the memory of the instance.
199 Isolate* isolate, ErrorThrower* thrower,
200 DirectHandle<WasmModuleObject> module_object,
203
204 // Begin an asynchronous compilation of the given bytes that represent an
205 // encoded Wasm module.
206 void AsyncCompile(Isolate* isolate, WasmEnabledFeatures enabled,
207 CompileTimeImports compile_imports,
208 std::shared_ptr<CompilationResultResolver> resolver,
210 const char* api_method_name_for_errors);
211
212 // Begin an asynchronous instantiation of the given Wasm module.
213 void AsyncInstantiate(Isolate* isolate,
214 std::unique_ptr<InstantiationResultResolver> resolver,
215 DirectHandle<WasmModuleObject> module_object,
217
218 std::shared_ptr<StreamingDecoder> StartStreamingCompilation(
219 Isolate* isolate, WasmEnabledFeatures enabled,
220 CompileTimeImports compile_imports, DirectHandle<Context> context,
221 const char* api_method_name,
222 std::shared_ptr<CompilationResultResolver> resolver);
223
224 // Compiles the function with the given index at a specific compilation tier.
225 // Errors are stored internally in the CompilationState.
226 // This is mostly used for testing to force a function into a specific tier.
227 void CompileFunction(Counters* counters, NativeModule* native_module,
228 uint32_t function_index, ExecutionTier tier);
229
230 void EnterDebuggingForIsolate(Isolate* isolate);
231
232 void LeaveDebuggingForIsolate(Isolate* isolate);
233
234 // Imports the shared part of a module from a different Context/Isolate using
235 // the the same engine, recreating a full module object in the given Isolate.
236 DirectHandle<WasmModuleObject> ImportNativeModule(
237 Isolate* isolate, std::shared_ptr<NativeModule> shared_module,
238 base::Vector<const char> source_url);
239
240 // Flushes all Liftoff code and returns the sizes of the removed
241 // (executable) code and the removed metadata.
242 std::pair<size_t, size_t> FlushLiftoffCode();
243
244 // Returns the code size of all Liftoff compiled functions in all modules.
245 size_t GetLiftoffCodeSizeForTesting();
246
248
249 // Compilation statistics for TurboFan compilations. Returns a shared_ptr
250 // so that background compilation jobs can hold on to it while the main thread
251 // shuts down.
252 std::shared_ptr<CompilationStatistics> GetOrCreateTurboStatistics();
253
254 // Prints the gathered compilation statistics, then resets them.
255 void DumpAndResetTurboStatistics();
256 // Prints the gathered compilation statistics (without resetting them).
257 void DumpTurboStatistics();
258
259 // Used to redirect tracing output from {stdout} to a file.
260 CodeTracer* GetCodeTracer();
261
262 // Remove {job} from the list of active compile jobs.
263 std::unique_ptr<AsyncCompileJob> RemoveCompileJob(AsyncCompileJob* job);
264
265 // Returns true if at least one AsyncCompileJob that belongs to the given
266 // Isolate is currently running.
267 bool HasRunningCompileJob(Isolate* isolate);
268
269 // Deletes all AsyncCompileJobs that belong to the given context. All
270 // compilation is aborted, no more callbacks will be triggered. This is used
271 // when a context is disposed, e.g. because of browser navigation.
272 void DeleteCompileJobsOnContext(DirectHandle<Context> context);
273
274 // Deletes all AsyncCompileJobs that belong to the given Isolate. All
275 // compilation is aborted, no more callbacks will be triggered. This is used
276 // for tearing down an isolate, or to clean it up to be reused.
277 void DeleteCompileJobsOnIsolate(Isolate* isolate);
278
279 // Manage the set of Isolates that use this WasmEngine.
280 void AddIsolate(Isolate* isolate);
281 void RemoveIsolate(Isolate* isolate);
282
283 // Trigger code logging for the given code objects in all Isolates which have
284 // access to the NativeModule containing this code. This method can be called
285 // from background threads.
286 void LogCode(base::Vector<WasmCode*>);
287 // Trigger code logging for the given code object, which must be a wrapper
288 // that is shared engine-wide. This method can be called from background
289 // threads.
290 // Returns whether code logging was triggered in any isolate.
291 bool LogWrapperCode(WasmCode*);
292
293 // Enable code logging for the given Isolate. Initially, code logging is
294 // enabled if {WasmCode::ShouldBeLogged(Isolate*)} returns true during
295 // {AddIsolate}.
296 void EnableCodeLogging(Isolate*);
297
298 // This is called from the foreground thread of the Isolate to log all
299 // outstanding code objects (added via {LogCode}).
300 void LogOutstandingCodesForIsolate(Isolate*);
301
302 // Create a new NativeModule. The caller is responsible for its
303 // lifetime. The native module will be given some memory for code,
304 // which will be page size aligned. The size of the initial memory
305 // is determined by {code_size_estimate}. The native module may later request
306 // more memory.
307 // TODO(wasm): isolate is only required here for CompilationState.
308 std::shared_ptr<NativeModule> NewNativeModule(
309 Isolate* isolate, WasmEnabledFeatures enabled_features,
310 WasmDetectedFeatures detected_features,
311 CompileTimeImports compile_imports,
312 std::shared_ptr<const WasmModule> module, size_t code_size_estimate);
313
314 // Try getting a cached {NativeModule}, or get ownership for its creation.
315 // Return {nullptr} if no {NativeModule} exists for these bytes. In this case,
316 // a {nullopt} entry is added to let other threads know that a {NativeModule}
317 // for these bytes is currently being created. The caller should eventually
318 // call {UpdateNativeModuleCache} to update the entry and wake up other
319 // threads. The {wire_bytes}' underlying array should be valid at least until
320 // the call to {UpdateNativeModuleCache}.
321 // The provided {CompileTimeImports} are considered part of the caching key,
322 // because they change the generated code as well as the behavior of the
323 // {imports()} function of any WasmModuleObjects we'll create for this
324 // NativeModule later.
325 std::shared_ptr<NativeModule> MaybeGetNativeModule(
326 ModuleOrigin origin, base::Vector<const uint8_t> wire_bytes,
327 const CompileTimeImports& compile_imports, Isolate* isolate);
328
329 // Replace the temporary {nullopt} with the new native module, or
330 // erase it if any error occurred. Wake up blocked threads waiting for this
331 // module.
332 // To avoid a deadlock on the main thread between synchronous and streaming
333 // compilation, two compilation jobs might compile the same native module at
334 // the same time. In this case the first call to {UpdateNativeModuleCache}
335 // will insert the native module in the cache, and the last call will receive
336 // the existing entry from the cache.
337 // Return the cached entry, or {native_module} if there was no previously
338 // cached module.
339 std::shared_ptr<NativeModule> UpdateNativeModuleCache(
340 bool has_error, std::shared_ptr<NativeModule> native_module,
341 Isolate* isolate);
342
343 // Register this prefix hash for a streaming compilation job.
344 // If the hash is not in the cache yet, the function returns true and the
345 // caller owns the compilation of this module.
346 // Otherwise another compilation job is currently preparing or has already
347 // prepared a module with the same prefix hash. The caller should wait until
348 // the stream is finished and call {MaybeGetNativeModule} to either get the
349 // module from the cache or get ownership for the compilation of these bytes.
350 bool GetStreamingCompilationOwnership(
351 size_t prefix_hash, const CompileTimeImports& compile_imports);
352
353 // Remove the prefix hash from the cache when compilation failed. If
354 // compilation succeeded, {UpdateNativeModuleCache} should be called instead.
355 void StreamingCompilationFailed(size_t prefix_hash,
356 const CompileTimeImports& compile_imports);
357
358 void FreeNativeModule(NativeModule*);
359 void ClearWeakScriptHandle(Isolate* isolate,
360 std::unique_ptr<Address*> location);
361
362 // Sample the code size of the given {NativeModule} in all isolates that have
363 // access to it. Call this after top-tier compilation finished.
364 // This will spawn foreground tasks that do *not* keep the NativeModule alive.
365 void SampleTopTierCodeSizeInAllIsolates(const std::shared_ptr<NativeModule>&);
366
367 // Called by each Isolate to report its live code for a GC cycle. First
368 // version reports an externally determined set of live code (might be empty),
369 // second version gets live code from the execution stack of that isolate.
370 void ReportLiveCodeForGC(Isolate*, std::unordered_set<WasmCode*>& live_code);
371 void ReportLiveCodeFromStackForGC(Isolate*);
372
373 // Add potentially dead code. The occurrence in the set of potentially dead
374 // code counts as a reference, and is decremented on the next GC.
375 void AddPotentiallyDeadCode(WasmCode*);
376
377 // Allow tests to trigger a GC independently of adding potentially dead code.
378 void TriggerCodeGCForTesting();
379
380 // Free dead code.
381 using DeadCodeMap = std::unordered_map<NativeModule*, std::vector<WasmCode*>>;
382 void FreeDeadCode(const DeadCodeMap&, std::vector<WasmCode*>&);
383 void FreeDeadCodeLocked(const DeadCodeMap&, std::vector<WasmCode*>&);
384
385 DirectHandle<Script> GetOrCreateScript(Isolate*,
386 const std::shared_ptr<NativeModule>&,
387 base::Vector<const char> source_url);
388
389 // Returns a barrier allowing background compile operations if valid and
390 // preventing this object from being destroyed.
391 std::shared_ptr<OperationsBarrier> GetBarrierForBackgroundCompile();
392
393 TypeCanonicalizer* type_canonicalizer() { return &type_canonicalizer_; }
394
395 void DecodeAllNameSections(CanonicalTypeNamesProvider* target);
396
398 return &call_descriptors_;
399 }
400
401 // Returns an approximation of current off-heap memory used by this engine,
402 // excluding code space.
403 size_t EstimateCurrentMemoryConsumption() const;
404 // Print the current memory consumption estimate to standard output.
405 void PrintCurrentMemoryConsumptionEstimate() const;
406
407 int GetDeoptsExecutedCount() const;
408 int IncrementDeoptsExecutedCount();
409
410 // Call on process start and exit.
411 static void InitializeOncePerProcess();
412 static void GlobalTearDown();
413
414 static WasmOrphanedGlobalHandle* NewOrphanedGlobalHandle(
415 WasmOrphanedGlobalHandle** pointer);
416 static void FreeAllOrphanedGlobalHandles(WasmOrphanedGlobalHandle* start);
417
418 size_t NativeModuleCount() const;
419
420 // Get the address of the static {had_nondeterminism_} flag, for embedding in
421 // generated code.
422 static Address GetNondeterminismAddr() {
423 return reinterpret_cast<Address>(&had_nondeterminism_);
424 }
425
426 // Return {true} if nondeterminism was detected during previous execution.
427 static bool had_nondeterminism() {
428 return had_nondeterminism_.load(std::memory_order_relaxed) != 0;
429 }
430
431 // Set the {had_nondeterminism_} flag.
433 had_nondeterminism_.store(1, std::memory_order_relaxed);
434 }
435
436 // Clear the {had_nondeterminism_} flag and return whether nondeterminism was
437 // detected before clearing.
438 static bool clear_nondeterminism() {
439 return had_nondeterminism_.exchange(0, std::memory_order_relaxed) != 0;
440 }
441
442 private:
443 struct CurrentGCInfo;
444 struct IsolateInfo;
445 struct NativeModuleInfo;
446
447 AsyncCompileJob* CreateAsyncCompileJob(
448 Isolate* isolate, WasmEnabledFeatures enabled,
449 CompileTimeImports compile_imports,
451 const char* api_method_name,
452 std::shared_ptr<CompilationResultResolver> resolver, int compilation_id);
453
454 void TriggerCodeGC_Locked(size_t dead_code_limit);
455 void TriggerGC(int8_t gc_sequence_index);
456
457 // Remove an isolate from the outstanding isolates of the current GC. Returns
458 // true if the isolate was still outstanding, false otherwise. Hold {mutex_}
459 // when calling this method.
460 bool RemoveIsolateFromCurrentGC(Isolate*);
461
462 // Finish a GC if there are no more outstanding isolates. Hold {mutex_} when
463 // calling this method.
464 void PotentiallyFinishCurrentGC();
465
466 // Enable/disable code logging on the NativeModule, updating
467 // {num_modules_with_code_logging_} accordingly.
468 void EnableCodeLogging(NativeModule*);
469 void DisableCodeLogging(NativeModule*);
470
471 // Remember in a global flag whether we saw nondeterminism during execution.
472 // This is used in differential fuzzing.
473 // The address of this global is embedded in generated Liftoff code, and also
474 // some runtime functions update it (notably for growing memory, which can
475 // fail nondeterministically). In non-Liftoff executions, we still get the
476 // latter.
477 // This is typed as {int32_t} to have a deterministic bit pattern (in contrast
478 // to {bool}). A value of `0` means no nondeterminism, everything else
479 // indicates nondeterminism.
480 static std::atomic<int32_t> had_nondeterminism_;
481
483
484#ifdef V8_ENABLE_WASM_GDB_REMOTE_DEBUGGING
485 // Implements a GDB-remote stub for WebAssembly debugging.
486 std::unique_ptr<gdb_server::GdbServer> gdb_server_;
487#endif // V8_ENABLE_WASM_GDB_REMOTE_DEBUGGING
488
489 std::atomic<int> next_compilation_id_{0};
490
491 // Counter for number of times a deopt was executed.
492 std::atomic<int> deopts_executed_{0};
493
495
497
498 // This mutex protects all information which is mutated concurrently or
499 // fields that are initialized lazily on the first access.
501
503 // Protected by {mutex_}:
504
505 // We use an AsyncCompileJob as the key for itself so that we can delete the
506 // job from the map when it is finished.
507 std::unordered_map<AsyncCompileJob*, std::unique_ptr<AsyncCompileJob>>
509
510 std::shared_ptr<CompilationStatistics> compilation_stats_;
511 std::unique_ptr<CodeTracer> code_tracer_;
512
513 // Set of isolates which use this WasmEngine.
514 std::unordered_map<Isolate*, std::unique_ptr<IsolateInfo>> isolates_;
515
516 // Set of native modules managed by this engine.
517 std::unordered_map<NativeModule*, std::unique_ptr<NativeModuleInfo>>
519
520 std::shared_ptr<OperationsBarrier> operations_barrier_{
521 std::make_shared<OperationsBarrier>()};
522
523 // Store the number of modules which have code logging enabled. This is then
524 // used for a fast-path to avoid taking the mutex and iterating Isolates or
525 // NativeModules.
526 std::atomic<size_t> num_modules_with_code_logging_{0};
527
528 // Size of code that became dead since the last GC. If this exceeds a certain
529 // threshold, a new GC is triggered.
530 size_t new_potentially_dead_code_size_ = 0;
531 // Set of potentially dead code. This set holds one ref for each code object,
532 // until code is detected to be really dead. At that point, the ref count is
533 // decremented and code is removed from the set.
534 std::unordered_set<WasmCode*> potentially_dead_code_;
535 int8_t num_code_gcs_triggered_ = 0;
536
537 // If an engine-wide GC is currently running, this pointer stores information
538 // about that.
539 std::unique_ptr<CurrentGCInfo> current_gc_info_;
540
542
543 // End of fields protected by {mutex_}.
545};
546
547// Returns a reference to the WasmEngine shared by the entire process.
549
550// Returns a reference to the WasmCodeManager shared by the entire process.
552
553// Returns a reference to the WasmImportWrapperCache shared by the entire
554// process.
556
558
559} // namespace wasm
560} // namespace internal
561} // namespace v8
562
563#endif // V8_WASM_WASM_ENGINE_H_
RegisterAllocator * allocator_
virtual void OnCompilationFailed(DirectHandle< JSAny > error_reason)=0
virtual void OnCompilationSucceeded(DirectHandle< WasmModuleObject > result)=0
int compare(const CompileTimeImports &other) const
virtual void OnInstantiationSucceeded(DirectHandle< WasmInstanceObject > result)=0
virtual void OnInstantiationFailed(DirectHandle< JSAny > error_reason)=0
void StreamingCompilationFailed(size_t prefix_hash, const CompileTimeImports &compile_imports)
void Erase(NativeModule *native_module)
std::shared_ptr< NativeModule > MaybeGetNativeModule(ModuleOrigin origin, base::Vector< const uint8_t > wire_bytes, const CompileTimeImports &compile_imports)
std::map< Key, std::optional< std::weak_ptr< NativeModule > > > map_
base::ConditionVariable cache_cv_
static size_t PrefixHash(base::Vector< const uint8_t > wire_bytes)
std::shared_ptr< NativeModule > Update(std::shared_ptr< NativeModule > native_module, bool error)
bool GetStreamingCompilationOwnership(size_t prefix_hash, const CompileTimeImports &compile_imports)
static Address GetNondeterminismAddr()
std::unique_ptr< CurrentGCInfo > current_gc_info_
std::unordered_set< WasmCode * > potentially_dead_code_
WasmEngine & operator=(const WasmEngine &)=delete
TypeCanonicalizer * type_canonicalizer()
AccountingAllocator * allocator()
AccountingAllocator allocator_
void SampleTopTierCodeSizeInAllIsolates(const std::shared_ptr< NativeModule > &)
static std::atomic< int32_t > had_nondeterminism_
std::unordered_map< Isolate *, std::unique_ptr< IsolateInfo > > isolates_
std::unique_ptr< CodeTracer > code_tracer_
compiler::WasmCallDescriptors * call_descriptors()
std::unordered_map< NativeModule *, std::unique_ptr< NativeModuleInfo > > native_modules_
WasmEngine(const WasmEngine &)=delete
std::unordered_map< AsyncCompileJob *, std::unique_ptr< AsyncCompileJob > > async_compile_jobs_
compiler::WasmCallDescriptors call_descriptors_
std::shared_ptr< CompilationStatistics > compilation_stats_
NativeModuleCache native_module_cache_
std::unordered_map< NativeModule *, std::vector< WasmCode * > > DeadCodeMap
TypeCanonicalizer type_canonicalizer_
int start
ZoneVector< RpoNumber > & result
STL namespace.
WasmImportWrapperCache * GetWasmImportWrapperCache()
WasmCodeManager * GetWasmCodeManager()
CanonicalTypeNamesProvider * GetCanonicalTypeNamesProvider()
WasmEngine * GetWasmEngine()
Definition c-api.cc:87
#define DCHECK_NOT_NULL(val)
Definition logging.h:492
#define DCHECK_IMPLIES(v1, v2)
Definition logging.h:493
#define DCHECK_EQ(v1, v2)
Definition logging.h:485
#define V8_EXPORT_PRIVATE
Definition macros.h:460
bool operator==(const Key &other) const
Definition wasm-engine.h:88
base::Vector< const uint8_t > bytes
Definition wasm-engine.h:86
bool operator<(const Key &other) const
Definition wasm-engine.h:95
Key(size_t prefix_hash, CompileTimeImports compile_imports, const base::Vector< const uint8_t > &bytes)
Definition wasm-engine.h:76