1 | // Copyright 2016 the V8 project authors. All rights reserved. Use of |
2 | // 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_OBJECTS_H_ |
6 | #define V8_WASM_WASM_OBJECTS_H_ |
7 | |
8 | #include "src/base/bits.h" |
9 | #include "src/debug/debug.h" |
10 | #include "src/debug/interface-types.h" |
11 | #include "src/heap/heap.h" |
12 | #include "src/objects.h" |
13 | #include "src/objects/script.h" |
14 | #include "src/signature.h" |
15 | #include "src/wasm/value-type.h" |
16 | |
17 | // Has to be the last include (doesn't have include guards) |
18 | #include "src/objects/object-macros.h" |
19 | |
20 | namespace v8 { |
21 | namespace internal { |
22 | namespace wasm { |
23 | struct CompilationEnv; |
24 | class InterpretedFrame; |
25 | struct InterpretedFrameDeleter; |
26 | class NativeModule; |
27 | class SignatureMap; |
28 | class WasmCode; |
29 | struct WasmException; |
30 | struct WasmFeatures; |
31 | class WasmInterpreter; |
32 | struct WasmModule; |
33 | class WasmValue; |
34 | class WireBytesRef; |
35 | } // namespace wasm |
36 | |
37 | class BreakPoint; |
38 | class JSArrayBuffer; |
39 | class SeqOneByteString; |
40 | class WasmDebugInfo; |
41 | class WasmExceptionTag; |
42 | class WasmInstanceObject; |
43 | class WasmModuleObject; |
44 | class WasmExportedFunction; |
45 | |
46 | template <class CppType> |
47 | class Managed; |
48 | |
49 | #define DECL_OPTIONAL_ACCESSORS(name, type) \ |
50 | V8_INLINE bool has_##name(); \ |
51 | DECL_ACCESSORS(name, type) |
52 | |
53 | // A helper for an entry in an indirect function table (IFT). |
54 | // The underlying storage in the instance is used by generated code to |
55 | // call functions indirectly at runtime. |
56 | // Each entry has the following fields: |
57 | // - object = target instance, if a Wasm function, tuple if imported |
58 | // - sig_id = signature id of function |
59 | // - target = entrypoint to Wasm code or import wrapper code |
60 | class IndirectFunctionTableEntry { |
61 | public: |
62 | inline IndirectFunctionTableEntry(Handle<WasmInstanceObject>, int index); |
63 | |
64 | void clear(); |
65 | V8_EXPORT_PRIVATE void Set(int sig_id, |
66 | Handle<WasmInstanceObject> target_instance, |
67 | int target_func_index); |
68 | |
69 | void CopyFrom(const IndirectFunctionTableEntry& that); |
70 | |
71 | Object object_ref(); |
72 | int sig_id(); |
73 | Address target(); |
74 | |
75 | private: |
76 | Handle<WasmInstanceObject> const instance_; |
77 | int const index_; |
78 | }; |
79 | |
80 | // A helper for an entry for an imported function, indexed statically. |
81 | // The underlying storage in the instance is used by generated code to |
82 | // call imported functions at runtime. |
83 | // Each entry is either: |
84 | // - WASM to JS, which has fields |
85 | // - object = a Tuple2 of the importing instance and the callable |
86 | // - target = entrypoint to import wrapper code |
87 | // - WASM to WASM, which has fields |
88 | // - object = target instance |
89 | // - target = entrypoint for the function |
90 | class ImportedFunctionEntry { |
91 | public: |
92 | inline ImportedFunctionEntry(Handle<WasmInstanceObject>, int index); |
93 | |
94 | // Initialize this entry as a WASM to JS call. This accepts the isolate as a |
95 | // parameter, since it must allocate a tuple. |
96 | V8_EXPORT_PRIVATE void SetWasmToJs(Isolate*, Handle<JSReceiver> callable, |
97 | const wasm::WasmCode* wasm_to_js_wrapper); |
98 | // Initialize this entry as a WASM to WASM call. |
99 | void SetWasmToWasm(WasmInstanceObject target_instance, Address call_target); |
100 | |
101 | WasmInstanceObject instance(); |
102 | JSReceiver callable(); |
103 | Object object_ref(); |
104 | Address target(); |
105 | |
106 | private: |
107 | Handle<WasmInstanceObject> const instance_; |
108 | int const index_; |
109 | }; |
110 | |
111 | // Representation of a WebAssembly.Module JavaScript-level object. |
112 | class WasmModuleObject : public JSObject { |
113 | public: |
114 | DECL_CAST(WasmModuleObject) |
115 | |
116 | DECL_ACCESSORS(managed_native_module, Managed<wasm::NativeModule>) |
117 | DECL_ACCESSORS(export_wrappers, FixedArray) |
118 | DECL_ACCESSORS(script, Script) |
119 | DECL_ACCESSORS(weak_instance_list, WeakArrayList) |
120 | DECL_OPTIONAL_ACCESSORS(asm_js_offset_table, ByteArray) |
121 | DECL_OPTIONAL_ACCESSORS(breakpoint_infos, FixedArray) |
122 | inline wasm::NativeModule* native_module() const; |
123 | inline const std::shared_ptr<wasm::NativeModule>& shared_native_module() |
124 | const; |
125 | inline const wasm::WasmModule* module() const; |
126 | inline void reset_breakpoint_infos(); |
127 | |
128 | // Dispatched behavior. |
129 | DECL_PRINTER(WasmModuleObject) |
130 | DECL_VERIFIER(WasmModuleObject) |
131 | |
132 | // Layout description. |
133 | #define WASM_MODULE_OBJECT_FIELDS(V) \ |
134 | V(kNativeModuleOffset, kTaggedSize) \ |
135 | V(kExportWrappersOffset, kTaggedSize) \ |
136 | V(kScriptOffset, kTaggedSize) \ |
137 | V(kWeakInstanceListOffset, kTaggedSize) \ |
138 | V(kAsmJsOffsetTableOffset, kTaggedSize) \ |
139 | V(kBreakPointInfosOffset, kTaggedSize) \ |
140 | V(kSize, 0) |
141 | |
142 | DEFINE_FIELD_OFFSET_CONSTANTS(JSObject::kHeaderSize, |
143 | WASM_MODULE_OBJECT_FIELDS) |
144 | #undef WASM_MODULE_OBJECT_FIELDS |
145 | |
146 | // Creates a new {WasmModuleObject} with a new {NativeModule} underneath. |
147 | V8_EXPORT_PRIVATE static Handle<WasmModuleObject> New( |
148 | Isolate* isolate, const wasm::WasmFeatures& enabled, |
149 | std::shared_ptr<const wasm::WasmModule> module, |
150 | OwnedVector<const uint8_t> wire_bytes, Handle<Script> script, |
151 | Handle<ByteArray> asm_js_offset_table); |
152 | |
153 | // Creates a new {WasmModuleObject} for an existing {NativeModule} that is |
154 | // reference counted and might be shared between multiple Isolates. |
155 | V8_EXPORT_PRIVATE static Handle<WasmModuleObject> New( |
156 | Isolate* isolate, std::shared_ptr<wasm::NativeModule> native_module, |
157 | Handle<Script> script, size_t code_size_estimate); |
158 | V8_EXPORT_PRIVATE static Handle<WasmModuleObject> New( |
159 | Isolate* isolate, std::shared_ptr<wasm::NativeModule> native_module, |
160 | Handle<Script> script, Handle<FixedArray> export_wrappers, |
161 | size_t code_size_estimate); |
162 | |
163 | // Set a breakpoint on the given byte position inside the given module. |
164 | // This will affect all live and future instances of the module. |
165 | // The passed position might be modified to point to the next breakable |
166 | // location inside the same function. |
167 | // If it points outside a function, or behind the last breakable location, |
168 | // this function returns false and does not set any breakpoint. |
169 | V8_EXPORT_PRIVATE static bool SetBreakPoint(Handle<WasmModuleObject>, |
170 | int* position, |
171 | Handle<BreakPoint> break_point); |
172 | |
173 | // Check whether this module was generated from asm.js source. |
174 | inline bool is_asm_js(); |
175 | |
176 | static void AddBreakpoint(Handle<WasmModuleObject>, int position, |
177 | Handle<BreakPoint> break_point); |
178 | |
179 | static void SetBreakpointsOnNewInstance(Handle<WasmModuleObject>, |
180 | Handle<WasmInstanceObject>); |
181 | |
182 | // Get the module name, if set. Returns an empty handle otherwise. |
183 | static MaybeHandle<String> GetModuleNameOrNull(Isolate*, |
184 | Handle<WasmModuleObject>); |
185 | |
186 | // Get the function name of the function identified by the given index. |
187 | // Returns a null handle if the function is unnamed or the name is not a valid |
188 | // UTF-8 string. |
189 | static MaybeHandle<String> GetFunctionNameOrNull(Isolate*, |
190 | Handle<WasmModuleObject>, |
191 | uint32_t func_index); |
192 | |
193 | // Get the function name of the function identified by the given index. |
194 | // Returns "wasm-function[func_index]" if the function is unnamed or the |
195 | // name is not a valid UTF-8 string. |
196 | static Handle<String> GetFunctionName(Isolate*, Handle<WasmModuleObject>, |
197 | uint32_t func_index); |
198 | |
199 | // Get the raw bytes of the function name of the function identified by the |
200 | // given index. |
201 | // Meant to be used for debugging or frame printing. |
202 | // Does not allocate, hence gc-safe. |
203 | Vector<const uint8_t> GetRawFunctionName(uint32_t func_index); |
204 | |
205 | // Return the byte offset of the function identified by the given index. |
206 | // The offset will be relative to the start of the module bytes. |
207 | // Returns -1 if the function index is invalid. |
208 | int GetFunctionOffset(uint32_t func_index); |
209 | |
210 | // Returns the function containing the given byte offset. |
211 | // Returns -1 if the byte offset is not contained in any function of this |
212 | // module. |
213 | int GetContainingFunction(uint32_t byte_offset); |
214 | |
215 | // Translate from byte offset in the module to function number and byte offset |
216 | // within that function, encoded as line and column in the position info. |
217 | // Returns true if the position is valid inside this module, false otherwise. |
218 | bool GetPositionInfo(uint32_t position, Script::PositionInfo* info); |
219 | |
220 | // Get the source position from a given function index and byte offset, |
221 | // for either asm.js or pure Wasm modules. |
222 | static int GetSourcePosition(Handle<WasmModuleObject>, uint32_t func_index, |
223 | uint32_t byte_offset, |
224 | bool is_at_number_conversion); |
225 | |
226 | // Compute the disassembly of a wasm function. |
227 | // Returns the disassembly string and a list of <byte_offset, line, column> |
228 | // entries, mapping wasm byte offsets to line and column in the disassembly. |
229 | // The list is guaranteed to be ordered by the byte_offset. |
230 | // Returns an empty string and empty vector if the function index is invalid. |
231 | V8_EXPORT_PRIVATE debug::WasmDisassembly DisassembleFunction(int func_index); |
232 | |
233 | // Extract a portion of the wire bytes as UTF-8 string. |
234 | // Returns a null handle if the respective bytes do not form a valid UTF-8 |
235 | // string. |
236 | static MaybeHandle<String> ExtractUtf8StringFromModuleBytes( |
237 | Isolate* isolate, Handle<WasmModuleObject>, wasm::WireBytesRef ref); |
238 | static MaybeHandle<String> ( |
239 | Isolate* isolate, Vector<const uint8_t> wire_byte, |
240 | wasm::WireBytesRef ref); |
241 | |
242 | // Get a list of all possible breakpoints within a given range of this module. |
243 | V8_EXPORT_PRIVATE bool GetPossibleBreakpoints( |
244 | const debug::Location& start, const debug::Location& end, |
245 | std::vector<debug::BreakLocation>* locations); |
246 | |
247 | // Return an empty handle if no breakpoint is hit at that location, or a |
248 | // FixedArray with all hit breakpoint objects. |
249 | static MaybeHandle<FixedArray> CheckBreakPoints(Isolate*, |
250 | Handle<WasmModuleObject>, |
251 | int position); |
252 | |
253 | OBJECT_CONSTRUCTORS(WasmModuleObject, JSObject); |
254 | }; |
255 | |
256 | // Representation of a WebAssembly.Table JavaScript-level object. |
257 | class V8_EXPORT_PRIVATE WasmTableObject : public JSObject { |
258 | public: |
259 | DECL_CAST(WasmTableObject) |
260 | |
261 | DECL_ACCESSORS(elements, FixedArray) |
262 | // TODO(titzer): introduce DECL_I64_ACCESSORS macro |
263 | DECL_ACCESSORS(maximum_length, Object) |
264 | DECL_ACCESSORS(dispatch_tables, FixedArray) |
265 | DECL_INT_ACCESSORS(raw_type) |
266 | |
267 | // Layout description. |
268 | #define WASM_TABLE_OBJECT_FIELDS(V) \ |
269 | V(kElementsOffset, kTaggedSize) \ |
270 | V(kMaximumLengthOffset, kTaggedSize) \ |
271 | V(kDispatchTablesOffset, kTaggedSize) \ |
272 | V(kRawTypeOffset, kTaggedSize) \ |
273 | V(kSize, 0) |
274 | |
275 | DEFINE_FIELD_OFFSET_CONSTANTS(JSObject::kHeaderSize, WASM_TABLE_OBJECT_FIELDS) |
276 | #undef WASM_TABLE_OBJECT_FIELDS |
277 | |
278 | inline uint32_t current_length(); |
279 | inline wasm::ValueType type(); |
280 | void Grow(Isolate* isolate, uint32_t count); |
281 | |
282 | static Handle<WasmTableObject> New(Isolate* isolate, wasm::ValueType type, |
283 | uint32_t initial, bool has_maximum, |
284 | uint32_t maximum, |
285 | Handle<FixedArray>* elements); |
286 | |
287 | static void AddDispatchTable(Isolate* isolate, Handle<WasmTableObject> table, |
288 | Handle<WasmInstanceObject> instance, |
289 | int table_index); |
290 | |
291 | static bool IsInBounds(Isolate* isolate, Handle<WasmTableObject> table, |
292 | uint32_t entry_index); |
293 | |
294 | static bool IsValidElement(Isolate* isolate, Handle<WasmTableObject> table, |
295 | Handle<Object> entry); |
296 | |
297 | static void Set(Isolate* isolate, Handle<WasmTableObject> table, |
298 | uint32_t index, Handle<Object> element); |
299 | |
300 | static Handle<Object> Get(Isolate* isolate, Handle<WasmTableObject> table, |
301 | uint32_t index); |
302 | |
303 | static void UpdateDispatchTables(Isolate* isolate, |
304 | Handle<WasmTableObject> table, |
305 | int entry_index, wasm::FunctionSig* sig, |
306 | Handle<WasmInstanceObject> target_instance, |
307 | int target_func_index); |
308 | |
309 | static void ClearDispatchTables(Isolate* isolate, |
310 | Handle<WasmTableObject> table, int index); |
311 | |
312 | static void SetFunctionTablePlaceholder(Isolate* isolate, |
313 | Handle<WasmTableObject> table, |
314 | int entry_index, |
315 | Handle<WasmInstanceObject> instance, |
316 | int func_index); |
317 | |
318 | // This function reads the content of a function table entry and returns it |
319 | // through the out parameters {is_valid}, {is_null}, {instance}, and |
320 | // {function_index}. |
321 | static void GetFunctionTableEntry(Isolate* isolate, |
322 | Handle<WasmTableObject> table, |
323 | int entry_index, bool* is_valid, |
324 | bool* is_null, |
325 | MaybeHandle<WasmInstanceObject>* instance, |
326 | int* function_index); |
327 | |
328 | OBJECT_CONSTRUCTORS(WasmTableObject, JSObject); |
329 | }; |
330 | |
331 | // Representation of a WebAssembly.Memory JavaScript-level object. |
332 | class WasmMemoryObject : public JSObject { |
333 | public: |
334 | DECL_CAST(WasmMemoryObject) |
335 | |
336 | DECL_ACCESSORS(array_buffer, JSArrayBuffer) |
337 | DECL_INT_ACCESSORS(maximum_pages) |
338 | DECL_OPTIONAL_ACCESSORS(instances, WeakArrayList) |
339 | |
340 | // Layout description. |
341 | #define WASM_MEMORY_OBJECT_FIELDS(V) \ |
342 | V(kArrayBufferOffset, kTaggedSize) \ |
343 | V(kMaximumPagesOffset, kTaggedSize) \ |
344 | V(kInstancesOffset, kTaggedSize) \ |
345 | V(kSize, 0) |
346 | |
347 | DEFINE_FIELD_OFFSET_CONSTANTS(JSObject::kHeaderSize, |
348 | WASM_MEMORY_OBJECT_FIELDS) |
349 | #undef WASM_MEMORY_OBJECT_FIELDS |
350 | |
351 | // Add an instance to the internal (weak) list. |
352 | V8_EXPORT_PRIVATE static void AddInstance(Isolate* isolate, |
353 | Handle<WasmMemoryObject> memory, |
354 | Handle<WasmInstanceObject> object); |
355 | inline bool has_maximum_pages(); |
356 | |
357 | // Return whether the underlying backing store has guard regions large enough |
358 | // to be used with trap handlers. |
359 | bool has_full_guard_region(Isolate* isolate); |
360 | |
361 | V8_EXPORT_PRIVATE static Handle<WasmMemoryObject> New( |
362 | Isolate* isolate, MaybeHandle<JSArrayBuffer> buffer, uint32_t maximum); |
363 | |
364 | V8_EXPORT_PRIVATE static MaybeHandle<WasmMemoryObject> New( |
365 | Isolate* isolate, uint32_t initial, uint32_t maximum, |
366 | bool is_shared_memory); |
367 | |
368 | void update_instances(Isolate* isolate, Handle<JSArrayBuffer> buffer); |
369 | |
370 | V8_EXPORT_PRIVATE static int32_t Grow(Isolate*, Handle<WasmMemoryObject>, |
371 | uint32_t pages); |
372 | |
373 | OBJECT_CONSTRUCTORS(WasmMemoryObject, JSObject); |
374 | }; |
375 | |
376 | // Representation of a WebAssembly.Global JavaScript-level object. |
377 | class WasmGlobalObject : public JSObject { |
378 | public: |
379 | DECL_CAST(WasmGlobalObject) |
380 | |
381 | DECL_ACCESSORS(untagged_buffer, JSArrayBuffer) |
382 | DECL_ACCESSORS(tagged_buffer, FixedArray) |
383 | DECL_INT32_ACCESSORS(offset) |
384 | DECL_INT_ACCESSORS(flags) |
385 | DECL_PRIMITIVE_ACCESSORS(type, wasm::ValueType) |
386 | DECL_BOOLEAN_ACCESSORS(is_mutable) |
387 | |
388 | #define WASM_GLOBAL_OBJECT_FLAGS_BIT_FIELDS(V, _) \ |
389 | V(TypeBits, wasm::ValueType, 8, _) \ |
390 | V(IsMutableBit, bool, 1, _) |
391 | |
392 | DEFINE_BIT_FIELDS(WASM_GLOBAL_OBJECT_FLAGS_BIT_FIELDS) |
393 | |
394 | #undef WASM_GLOBAL_OBJECT_FLAGS_BIT_FIELDS |
395 | |
396 | // Layout description. |
397 | #define WASM_GLOBAL_OBJECT_FIELDS(V) \ |
398 | V(kUntaggedBufferOffset, kTaggedSize) \ |
399 | V(kTaggedBufferOffset, kTaggedSize) \ |
400 | V(kOffsetOffset, kTaggedSize) \ |
401 | V(kFlagsOffset, kTaggedSize) \ |
402 | V(kSize, 0) |
403 | |
404 | DEFINE_FIELD_OFFSET_CONSTANTS(JSObject::kHeaderSize, |
405 | WASM_GLOBAL_OBJECT_FIELDS) |
406 | #undef WASM_GLOBAL_OBJECT_FIELDS |
407 | |
408 | V8_EXPORT_PRIVATE static MaybeHandle<WasmGlobalObject> New( |
409 | Isolate* isolate, MaybeHandle<JSArrayBuffer> maybe_untagged_buffer, |
410 | MaybeHandle<FixedArray> maybe_tagged_buffer, wasm::ValueType type, |
411 | int32_t offset, bool is_mutable); |
412 | |
413 | inline int type_size() const; |
414 | |
415 | inline int32_t GetI32(); |
416 | inline int64_t GetI64(); |
417 | inline float GetF32(); |
418 | inline double GetF64(); |
419 | inline Handle<Object> GetRef(); |
420 | |
421 | inline void SetI32(int32_t value); |
422 | inline void SetI64(int64_t value); |
423 | inline void SetF32(float value); |
424 | inline void SetF64(double value); |
425 | inline void SetAnyRef(Handle<Object> value); |
426 | inline bool SetAnyFunc(Isolate* isolate, Handle<Object> value); |
427 | |
428 | private: |
429 | // This function returns the address of the global's data in the |
430 | // JSArrayBuffer. This buffer may be allocated on-heap, in which case it may |
431 | // not have a fixed address. |
432 | inline Address address() const; |
433 | |
434 | OBJECT_CONSTRUCTORS(WasmGlobalObject, JSObject); |
435 | }; |
436 | |
437 | // Representation of a WebAssembly.Instance JavaScript-level object. |
438 | class WasmInstanceObject : public JSObject { |
439 | public: |
440 | DECL_CAST(WasmInstanceObject) |
441 | |
442 | DECL_ACCESSORS(module_object, WasmModuleObject) |
443 | DECL_ACCESSORS(exports_object, JSObject) |
444 | DECL_ACCESSORS(native_context, Context) |
445 | DECL_OPTIONAL_ACCESSORS(memory_object, WasmMemoryObject) |
446 | DECL_OPTIONAL_ACCESSORS(untagged_globals_buffer, JSArrayBuffer) |
447 | DECL_OPTIONAL_ACCESSORS(tagged_globals_buffer, FixedArray) |
448 | DECL_OPTIONAL_ACCESSORS(imported_mutable_globals_buffers, FixedArray) |
449 | DECL_OPTIONAL_ACCESSORS(debug_info, WasmDebugInfo) |
450 | DECL_OPTIONAL_ACCESSORS(tables, FixedArray) |
451 | DECL_ACCESSORS(imported_function_refs, FixedArray) |
452 | DECL_OPTIONAL_ACCESSORS(indirect_function_table_refs, FixedArray) |
453 | DECL_OPTIONAL_ACCESSORS(managed_native_allocations, Foreign) |
454 | DECL_OPTIONAL_ACCESSORS(exceptions_table, FixedArray) |
455 | DECL_ACCESSORS(undefined_value, Oddball) |
456 | DECL_ACCESSORS(null_value, Oddball) |
457 | DECL_ACCESSORS(centry_stub, Code) |
458 | DECL_OPTIONAL_ACCESSORS(wasm_exported_functions, FixedArray) |
459 | DECL_PRIMITIVE_ACCESSORS(memory_start, byte*) |
460 | DECL_PRIMITIVE_ACCESSORS(memory_size, size_t) |
461 | DECL_PRIMITIVE_ACCESSORS(memory_mask, size_t) |
462 | DECL_PRIMITIVE_ACCESSORS(isolate_root, Address) |
463 | DECL_PRIMITIVE_ACCESSORS(stack_limit_address, Address) |
464 | DECL_PRIMITIVE_ACCESSORS(real_stack_limit_address, Address) |
465 | DECL_PRIMITIVE_ACCESSORS(imported_function_targets, Address*) |
466 | DECL_PRIMITIVE_ACCESSORS(globals_start, byte*) |
467 | DECL_PRIMITIVE_ACCESSORS(imported_mutable_globals, Address*) |
468 | DECL_PRIMITIVE_ACCESSORS(indirect_function_table_size, uint32_t) |
469 | DECL_PRIMITIVE_ACCESSORS(indirect_function_table_sig_ids, uint32_t*) |
470 | DECL_PRIMITIVE_ACCESSORS(indirect_function_table_targets, Address*) |
471 | DECL_PRIMITIVE_ACCESSORS(jump_table_start, Address) |
472 | DECL_PRIMITIVE_ACCESSORS(data_segment_starts, Address*) |
473 | DECL_PRIMITIVE_ACCESSORS(data_segment_sizes, uint32_t*) |
474 | DECL_PRIMITIVE_ACCESSORS(dropped_data_segments, byte*) |
475 | DECL_PRIMITIVE_ACCESSORS(dropped_elem_segments, byte*) |
476 | |
477 | // Clear uninitialized padding space. This ensures that the snapshot content |
478 | // is deterministic. Depending on the V8 build mode there could be no padding. |
479 | V8_INLINE void clear_padding(); |
480 | |
481 | // Dispatched behavior. |
482 | DECL_PRINTER(WasmInstanceObject) |
483 | DECL_VERIFIER(WasmInstanceObject) |
484 | |
485 | // Layout description. |
486 | #define WASM_INSTANCE_OBJECT_FIELDS(V) \ |
487 | /* Often-accessed fields go first to minimize generated code size. */ \ |
488 | V(kMemoryStartOffset, kSystemPointerSize) \ |
489 | V(kMemorySizeOffset, kSizetSize) \ |
490 | V(kMemoryMaskOffset, kSizetSize) \ |
491 | V(kStackLimitAddressOffset, kSystemPointerSize) \ |
492 | V(kImportedFunctionRefsOffset, kTaggedSize) \ |
493 | V(kImportedFunctionTargetsOffset, kSystemPointerSize) \ |
494 | V(kIndirectFunctionTableRefsOffset, kTaggedSize) \ |
495 | V(kIndirectFunctionTableTargetsOffset, kSystemPointerSize) \ |
496 | V(kIndirectFunctionTableSigIdsOffset, kSystemPointerSize) \ |
497 | V(kIndirectFunctionTableSizeOffset, kUInt32Size) \ |
498 | /* Optional padding to align system pointer size fields */ \ |
499 | V(kOptionalPaddingOffset, POINTER_SIZE_PADDING(kOptionalPaddingOffset)) \ |
500 | V(kGlobalsStartOffset, kSystemPointerSize) \ |
501 | V(kImportedMutableGlobalsOffset, kSystemPointerSize) \ |
502 | V(kUndefinedValueOffset, kTaggedSize) \ |
503 | V(kIsolateRootOffset, kSystemPointerSize) \ |
504 | V(kJumpTableStartOffset, kSystemPointerSize) \ |
505 | /* End of often-accessed fields. */ \ |
506 | V(kModuleObjectOffset, kTaggedSize) \ |
507 | V(kExportsObjectOffset, kTaggedSize) \ |
508 | V(kNativeContextOffset, kTaggedSize) \ |
509 | V(kMemoryObjectOffset, kTaggedSize) \ |
510 | V(kUntaggedGlobalsBufferOffset, kTaggedSize) \ |
511 | V(kTaggedGlobalsBufferOffset, kTaggedSize) \ |
512 | V(kImportedMutableGlobalsBuffersOffset, kTaggedSize) \ |
513 | V(kDebugInfoOffset, kTaggedSize) \ |
514 | V(kTablesOffset, kTaggedSize) \ |
515 | V(kManagedNativeAllocationsOffset, kTaggedSize) \ |
516 | V(kExceptionsTableOffset, kTaggedSize) \ |
517 | V(kNullValueOffset, kTaggedSize) \ |
518 | V(kCEntryStubOffset, kTaggedSize) \ |
519 | V(kWasmExportedFunctionsOffset, kTaggedSize) \ |
520 | V(kRealStackLimitAddressOffset, kSystemPointerSize) \ |
521 | V(kDataSegmentStartsOffset, kSystemPointerSize) \ |
522 | V(kDataSegmentSizesOffset, kSystemPointerSize) \ |
523 | V(kDroppedDataSegmentsOffset, kSystemPointerSize) \ |
524 | V(kDroppedElemSegmentsOffset, kSystemPointerSize) \ |
525 | /* Header size. */ \ |
526 | V(kSize, 0) |
527 | |
528 | DEFINE_FIELD_OFFSET_CONSTANTS(JSObject::kHeaderSize, |
529 | WASM_INSTANCE_OBJECT_FIELDS) |
530 | STATIC_ASSERT(IsAligned(kSize, kTaggedSize)); |
531 | // TODO(ishell, v8:8875): When pointer compression is enabled 8-byte size |
532 | // fields (external pointers, doubles and BigInt data) are only kTaggedSize |
533 | // aligned so checking for alignments of fields bigger than kTaggedSize |
534 | // doesn't make sense until v8:8875 is fixed. |
535 | #define ASSERT_FIELD_ALIGNED(offset, size) \ |
536 | STATIC_ASSERT(size == 0 || IsAligned(offset, size) || \ |
537 | (COMPRESS_POINTERS_BOOL && (size == kSystemPointerSize) && \ |
538 | IsAligned(offset, kTaggedSize))); |
539 | WASM_INSTANCE_OBJECT_FIELDS(ASSERT_FIELD_ALIGNED) |
540 | #undef ASSERT_FIELD_ALIGNED |
541 | #undef WASM_INSTANCE_OBJECT_FIELDS |
542 | |
543 | static constexpr uint16_t kTaggedFieldOffsets[] = { |
544 | kImportedFunctionRefsOffset, |
545 | kIndirectFunctionTableRefsOffset, |
546 | kUndefinedValueOffset, |
547 | kModuleObjectOffset, |
548 | kExportsObjectOffset, |
549 | kNativeContextOffset, |
550 | kMemoryObjectOffset, |
551 | kUntaggedGlobalsBufferOffset, |
552 | kTaggedGlobalsBufferOffset, |
553 | kImportedMutableGlobalsBuffersOffset, |
554 | kDebugInfoOffset, |
555 | kTablesOffset, |
556 | kManagedNativeAllocationsOffset, |
557 | kExceptionsTableOffset, |
558 | kNullValueOffset, |
559 | kCEntryStubOffset, |
560 | kWasmExportedFunctionsOffset}; |
561 | |
562 | V8_EXPORT_PRIVATE const wasm::WasmModule* module(); |
563 | |
564 | V8_EXPORT_PRIVATE static bool EnsureIndirectFunctionTableWithMinimumSize( |
565 | Handle<WasmInstanceObject> instance, uint32_t minimum_size); |
566 | |
567 | bool has_indirect_function_table(); |
568 | |
569 | V8_EXPORT_PRIVATE void SetRawMemory(byte* mem_start, size_t mem_size); |
570 | |
571 | // Get the debug info associated with the given wasm object. |
572 | // If no debug info exists yet, it is created automatically. |
573 | V8_EXPORT_PRIVATE static Handle<WasmDebugInfo> GetOrCreateDebugInfo( |
574 | Handle<WasmInstanceObject>); |
575 | |
576 | V8_EXPORT_PRIVATE static Handle<WasmInstanceObject> New( |
577 | Isolate*, Handle<WasmModuleObject>); |
578 | |
579 | Address GetCallTarget(uint32_t func_index); |
580 | |
581 | // Copies table entries. Returns {false} if the ranges are out-of-bounds. |
582 | static bool CopyTableEntries(Isolate* isolate, |
583 | Handle<WasmInstanceObject> instance, |
584 | uint32_t table_src_index, |
585 | uint32_t table_dst_index, uint32_t dst, |
586 | uint32_t src, |
587 | uint32_t count) V8_WARN_UNUSED_RESULT; |
588 | |
589 | // Copy table entries from an element segment. Returns {false} if the ranges |
590 | // are out-of-bounds. |
591 | static bool InitTableEntries(Isolate* isolate, |
592 | Handle<WasmInstanceObject> instance, |
593 | uint32_t table_index, uint32_t segment_index, |
594 | uint32_t dst, uint32_t src, |
595 | uint32_t count) V8_WARN_UNUSED_RESULT; |
596 | |
597 | // Iterates all fields in the object except the untagged fields. |
598 | class BodyDescriptor; |
599 | |
600 | static MaybeHandle<WasmExportedFunction> GetWasmExportedFunction( |
601 | Isolate* isolate, Handle<WasmInstanceObject> instance, int index); |
602 | static void SetWasmExportedFunction(Isolate* isolate, |
603 | Handle<WasmInstanceObject> instance, |
604 | int index, |
605 | Handle<WasmExportedFunction> val); |
606 | |
607 | OBJECT_CONSTRUCTORS(WasmInstanceObject, JSObject); |
608 | |
609 | private: |
610 | static void InitDataSegmentArrays(Handle<WasmInstanceObject>, |
611 | Handle<WasmModuleObject>); |
612 | static void InitElemSegmentArrays(Handle<WasmInstanceObject>, |
613 | Handle<WasmModuleObject>); |
614 | }; |
615 | |
616 | // Representation of WebAssembly.Exception JavaScript-level object. |
617 | class WasmExceptionObject : public JSObject { |
618 | public: |
619 | DECL_CAST(WasmExceptionObject) |
620 | |
621 | DECL_ACCESSORS(serialized_signature, PodArray<wasm::ValueType>) |
622 | DECL_ACCESSORS(exception_tag, HeapObject) |
623 | |
624 | // Layout description. |
625 | #define WASM_EXCEPTION_OBJECT_FIELDS(V) \ |
626 | V(kSerializedSignatureOffset, kTaggedSize) \ |
627 | V(kExceptionTagOffset, kTaggedSize) \ |
628 | V(kSize, 0) |
629 | |
630 | DEFINE_FIELD_OFFSET_CONSTANTS(JSObject::kHeaderSize, |
631 | WASM_EXCEPTION_OBJECT_FIELDS) |
632 | #undef WASM_EXCEPTION_OBJECT_FIELDS |
633 | |
634 | // Checks whether the given {sig} has the same parameter types as the |
635 | // serialized signature stored within this exception object. |
636 | bool IsSignatureEqual(const wasm::FunctionSig* sig); |
637 | |
638 | static Handle<WasmExceptionObject> New(Isolate* isolate, |
639 | const wasm::FunctionSig* sig, |
640 | Handle<HeapObject> exception_tag); |
641 | |
642 | OBJECT_CONSTRUCTORS(WasmExceptionObject, JSObject); |
643 | }; |
644 | |
645 | // A Wasm exception that has been thrown out of Wasm code. |
646 | class WasmExceptionPackage : public JSReceiver { |
647 | public: |
648 | // TODO(mstarzinger): Ideally this interface would use {WasmExceptionPackage} |
649 | // instead of {JSReceiver} throughout. For now a type-check implies doing a |
650 | // property lookup however, which would result in casts being handlified. |
651 | static Handle<JSReceiver> New(Isolate* isolate, |
652 | Handle<WasmExceptionTag> exception_tag, |
653 | int encoded_size); |
654 | |
655 | // The below getters return {undefined} in case the given exception package |
656 | // does not carry the requested values (i.e. is of a different type). |
657 | static Handle<Object> GetExceptionTag(Isolate*, Handle<Object> exception); |
658 | static Handle<Object> GetExceptionValues(Isolate*, Handle<Object> exception); |
659 | |
660 | // Determines the size of the array holding all encoded exception values. |
661 | static uint32_t GetEncodedSize(const wasm::WasmException* exception); |
662 | }; |
663 | |
664 | // A Wasm function that is wrapped and exported to JavaScript. |
665 | class WasmExportedFunction : public JSFunction { |
666 | public: |
667 | WasmInstanceObject instance(); |
668 | V8_EXPORT_PRIVATE int function_index(); |
669 | |
670 | V8_EXPORT_PRIVATE static bool IsWasmExportedFunction(Object object); |
671 | |
672 | V8_EXPORT_PRIVATE static Handle<WasmExportedFunction> New( |
673 | Isolate* isolate, Handle<WasmInstanceObject> instance, |
674 | MaybeHandle<String> maybe_name, int func_index, int arity, |
675 | Handle<Code> export_wrapper); |
676 | |
677 | Address GetWasmCallTarget(); |
678 | |
679 | wasm::FunctionSig* sig(); |
680 | |
681 | DECL_CAST(WasmExportedFunction) |
682 | OBJECT_CONSTRUCTORS(WasmExportedFunction, JSFunction); |
683 | }; |
684 | |
685 | // Information for a WasmExportedFunction which is referenced as the function |
686 | // data of the SharedFunctionInfo underlying the function. For details please |
687 | // see the {SharedFunctionInfo::HasWasmExportedFunctionData} predicate. |
688 | class WasmExportedFunctionData : public Struct { |
689 | public: |
690 | DECL_ACCESSORS(wrapper_code, Code) |
691 | DECL_ACCESSORS(instance, WasmInstanceObject) |
692 | DECL_INT_ACCESSORS(jump_table_offset) |
693 | DECL_INT_ACCESSORS(function_index) |
694 | |
695 | DECL_CAST(WasmExportedFunctionData) |
696 | |
697 | // Dispatched behavior. |
698 | DECL_PRINTER(WasmExportedFunctionData) |
699 | DECL_VERIFIER(WasmExportedFunctionData) |
700 | |
701 | // Layout description. |
702 | #define WASM_EXPORTED_FUNCTION_DATA_FIELDS(V) \ |
703 | V(kWrapperCodeOffset, kTaggedSize) \ |
704 | V(kInstanceOffset, kTaggedSize) \ |
705 | V(kJumpTableOffsetOffset, kTaggedSize) /* Smi */ \ |
706 | V(kFunctionIndexOffset, kTaggedSize) /* Smi */ \ |
707 | V(kSize, 0) |
708 | |
709 | DEFINE_FIELD_OFFSET_CONSTANTS(HeapObject::kHeaderSize, |
710 | WASM_EXPORTED_FUNCTION_DATA_FIELDS) |
711 | #undef WASM_EXPORTED_FUNCTION_DATA_FIELDS |
712 | |
713 | OBJECT_CONSTRUCTORS(WasmExportedFunctionData, Struct); |
714 | }; |
715 | |
716 | class WasmDebugInfo : public Struct { |
717 | public: |
718 | NEVER_READ_ONLY_SPACE |
719 | DECL_ACCESSORS(wasm_instance, WasmInstanceObject) |
720 | DECL_ACCESSORS(interpreter_handle, Object) // Foreign or undefined |
721 | DECL_ACCESSORS(interpreted_functions, FixedArray) |
722 | DECL_OPTIONAL_ACCESSORS(locals_names, FixedArray) |
723 | DECL_OPTIONAL_ACCESSORS(c_wasm_entries, FixedArray) |
724 | DECL_OPTIONAL_ACCESSORS(c_wasm_entry_map, Managed<wasm::SignatureMap>) |
725 | |
726 | DECL_CAST(WasmDebugInfo) |
727 | |
728 | // Dispatched behavior. |
729 | DECL_PRINTER(WasmDebugInfo) |
730 | DECL_VERIFIER(WasmDebugInfo) |
731 | |
732 | // Layout description. |
733 | #define WASM_DEBUG_INFO_FIELDS(V) \ |
734 | V(kInstanceOffset, kTaggedSize) \ |
735 | V(kInterpreterHandleOffset, kTaggedSize) \ |
736 | V(kInterpretedFunctionsOffset, kTaggedSize) \ |
737 | V(kLocalsNamesOffset, kTaggedSize) \ |
738 | V(kCWasmEntriesOffset, kTaggedSize) \ |
739 | V(kCWasmEntryMapOffset, kTaggedSize) \ |
740 | V(kSize, 0) |
741 | |
742 | DEFINE_FIELD_OFFSET_CONSTANTS(HeapObject::kHeaderSize, WASM_DEBUG_INFO_FIELDS) |
743 | #undef WASM_DEBUG_INFO_FIELDS |
744 | |
745 | static Handle<WasmDebugInfo> New(Handle<WasmInstanceObject>); |
746 | |
747 | // Setup a WasmDebugInfo with an existing WasmInstance struct. |
748 | // Returns a pointer to the interpreter instantiated inside this |
749 | // WasmDebugInfo. |
750 | // Use for testing only. |
751 | V8_EXPORT_PRIVATE static wasm::WasmInterpreter* SetupForTesting( |
752 | Handle<WasmInstanceObject>); |
753 | |
754 | // Set a breakpoint in the given function at the given byte offset within that |
755 | // function. This will redirect all future calls to this function to the |
756 | // interpreter and will always pause at the given offset. |
757 | V8_EXPORT_PRIVATE static void SetBreakpoint(Handle<WasmDebugInfo>, |
758 | int func_index, int offset); |
759 | |
760 | // Make a set of functions always execute in the interpreter without setting |
761 | // breakpoints. |
762 | V8_EXPORT_PRIVATE static void RedirectToInterpreter(Handle<WasmDebugInfo>, |
763 | Vector<int> func_indexes); |
764 | |
765 | void PrepareStep(StepAction); |
766 | |
767 | // Execute the specified function in the interpreter. Read arguments from the |
768 | // {argument_values} vector and write to {return_values} on regular exit. |
769 | // The frame_pointer will be used to identify the new activation of the |
770 | // interpreter for unwinding and frame inspection. |
771 | // Returns true if exited regularly, false if a trap occurred. In the latter |
772 | // case, a pending exception will have been set on the isolate. |
773 | static bool RunInterpreter(Isolate* isolate, Handle<WasmDebugInfo>, |
774 | Address frame_pointer, int func_index, |
775 | Vector<wasm::WasmValue> argument_values, |
776 | Vector<wasm::WasmValue> return_values); |
777 | |
778 | // Get the stack of the wasm interpreter as pairs of <function index, byte |
779 | // offset>. The list is ordered bottom-to-top, i.e. caller before callee. |
780 | std::vector<std::pair<uint32_t, int>> GetInterpretedStack( |
781 | Address frame_pointer); |
782 | |
783 | V8_EXPORT_PRIVATE |
784 | std::unique_ptr<wasm::InterpretedFrame, wasm::InterpretedFrameDeleter> |
785 | GetInterpretedFrame(Address frame_pointer, int frame_index); |
786 | |
787 | // Returns the number of calls / function frames executed in the interpreter. |
788 | V8_EXPORT_PRIVATE uint64_t NumInterpretedCalls(); |
789 | |
790 | // Get scope details for a specific interpreted frame. |
791 | // Both of these methods return a JSArrays (for the global scope and local |
792 | // scope respectively) of size {ScopeIterator::kScopeDetailsSize} and layout |
793 | // as described in debug-scopes.h. |
794 | // - The global scope contains information about globals and the memory. |
795 | // - The local scope contains information about parameters, locals, and |
796 | // stack values. |
797 | static Handle<JSObject> GetGlobalScopeObject(Handle<WasmDebugInfo>, |
798 | Address frame_pointer, |
799 | int frame_index); |
800 | static Handle<JSObject> GetLocalScopeObject(Handle<WasmDebugInfo>, |
801 | Address frame_pointer, |
802 | int frame_index); |
803 | |
804 | V8_EXPORT_PRIVATE static Handle<JSFunction> GetCWasmEntry( |
805 | Handle<WasmDebugInfo>, wasm::FunctionSig*); |
806 | |
807 | OBJECT_CONSTRUCTORS(WasmDebugInfo, Struct); |
808 | }; |
809 | |
810 | // Tags provide an object identity for each exception defined in a wasm module |
811 | // header. They are referenced by the following fields: |
812 | // - {WasmExceptionObject::exception_tag} : The tag of the exception object. |
813 | // - {WasmInstanceObject::exceptions_table}: List of tags used by an instance. |
814 | class WasmExceptionTag : public Struct { |
815 | public: |
816 | V8_EXPORT_PRIVATE static Handle<WasmExceptionTag> New(Isolate* isolate, |
817 | int index); |
818 | |
819 | // Note that this index is only useful for debugging purposes and it is not |
820 | // unique across modules. The GC however does not allow objects without at |
821 | // least one field, hence this also serves as a padding field for now. |
822 | DECL_INT_ACCESSORS(index) |
823 | |
824 | DECL_CAST(WasmExceptionTag) |
825 | DECL_PRINTER(WasmExceptionTag) |
826 | DECL_VERIFIER(WasmExceptionTag) |
827 | |
828 | DEFINE_FIELD_OFFSET_CONSTANTS(Struct::kHeaderSize, |
829 | TORQUE_GENERATED_WASM_EXCEPTION_TAG_FIELDS) |
830 | |
831 | OBJECT_CONSTRUCTORS(WasmExceptionTag, Struct); |
832 | }; |
833 | |
834 | class AsmWasmData : public Struct { |
835 | public: |
836 | static Handle<AsmWasmData> New( |
837 | Isolate* isolate, std::shared_ptr<wasm::NativeModule> native_module, |
838 | Handle<FixedArray> export_wrappers, Handle<ByteArray> asm_js_offset_table, |
839 | Handle<HeapNumber> uses_bitset); |
840 | |
841 | DECL_ACCESSORS(managed_native_module, Managed<wasm::NativeModule>) |
842 | DECL_ACCESSORS(export_wrappers, FixedArray) |
843 | DECL_ACCESSORS(asm_js_offset_table, ByteArray) |
844 | DECL_ACCESSORS(uses_bitset, HeapNumber) |
845 | |
846 | DECL_CAST(AsmWasmData) |
847 | DECL_PRINTER(AsmWasmData) |
848 | DECL_VERIFIER(AsmWasmData) |
849 | |
850 | // Layout description. |
851 | #define ASM_WASM_DATA_FIELDS(V) \ |
852 | V(kManagedNativeModuleOffset, kTaggedSize) \ |
853 | V(kExportWrappersOffset, kTaggedSize) \ |
854 | V(kAsmJsOffsetTableOffset, kTaggedSize) \ |
855 | V(kUsesBitsetOffset, kTaggedSize) \ |
856 | /* Total size. */ \ |
857 | V(kSize, 0) |
858 | |
859 | DEFINE_FIELD_OFFSET_CONSTANTS(Struct::kHeaderSize, ASM_WASM_DATA_FIELDS) |
860 | #undef ASM_WASM_DATA_FIELDS |
861 | |
862 | OBJECT_CONSTRUCTORS(AsmWasmData, Struct); |
863 | }; |
864 | |
865 | #undef DECL_OPTIONAL_ACCESSORS |
866 | |
867 | } // namespace internal |
868 | } // namespace v8 |
869 | |
870 | #include "src/objects/object-macros-undef.h" |
871 | |
872 | #endif // V8_WASM_WASM_OBJECTS_H_ |
873 | |