/
githubmirror
/
node
Обзор
Документация
Войти
/
githubmirror
/
node
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
deps/v8/src/wasm/wasm-objects.h
1 723 строки
71 KB
Michaël Zasso
deps: update V8 to 14.6.202.33
24 апр 2026, 19:01
Не верифицирован
24 апр 2026, 19:01
f1e0b83
Код
Авторство
О чём код?
// Copyright 2016 the V8 project authors. All rights reserved. Use of // this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef V8_WASM_WASM_OBJECTS_H_ #define V8_WASM_WASM_OBJECTS_H_ #if !V8_ENABLE_WEBASSEMBLY #error This header should only be included if WebAssembly is enabled. #endif // !V8_ENABLE_WEBASSEMBLY #include <memory> #include <optional> #include "include/v8-wasm.h" #include "src/base/bit-field.h" #include "src/debug/interface-types.h" #include "src/heap/heap.h" #include "src/objects/backing-store.h" #include "src/objects/contexts.h" #include "src/objects/foreign.h" #include "src/objects/js-function.h" #include "src/objects/js-objects.h" #include "src/objects/objects-body-descriptors.h" #include "src/objects/objects.h" #include "src/objects/struct.h" #include "src/objects/trusted-object.h" #include "src/wasm/module-instantiate.h" #include "src/wasm/stacks.h" #include "src/wasm/struct-types.h" #include "src/wasm/value-type.h" #include "src/wasm/wasm-code-manager.h" #include "src/wasm/wasm-module.h" // Has to be the last include (doesn't have include guards) #include "src/objects/object-macros.h" namespace v8 { namespace internal { namespace wasm { class NativeModule; class WasmCode; struct WasmFunction; struct WasmGlobal; class WasmWrapperHandle; struct WasmModule; struct WasmTag; using WasmTagSig = FunctionSig; class WasmValue; class WireBytesRef; } // namespace wasm class BreakPoint; class JSArrayBuffer; class SeqOneByteString; class StructBodyDescriptor; class WasmCapiFunction; class WasmDispatchTableForImports; class WasmExceptionTag; class WasmExportedFunction; class WasmExternalFunction; class WasmTrustedInstanceData; class WasmJSFunction; class WasmModuleObject; enum class SharedFlag : uint8_t; template <typename CppType> class Managed; template <typename CppType> class TrustedManaged; #include "torque-generated/src/wasm/wasm-objects-tq.inc" #define DECL_OPTIONAL_ACCESSORS(name, type) \ DECL_GETTER(has_##name, bool) \ DECL_ACCESSORS(name, type) class V8_EXPORT_PRIVATE FunctionTargetAndImplicitArg { public: FunctionTargetAndImplicitArg( Isolate* isolate, DirectHandle<WasmTrustedInstanceData> target_instance_data, int target_func_index); // The "implicit_arg" will be a WasmTrustedInstanceData or a WasmImportData. DirectHandle<TrustedObject> implicit_arg() { return implicit_arg_; } WasmCodePointer call_target() { return call_target_; } #if V8_ENABLE_DRUMBRAKE int target_func_index() { return target_func_index_; } #endif // V8_ENABLE_DRUMBRAKE private: DirectHandle<TrustedObject> implicit_arg_; WasmCodePointer call_target_; #if V8_ENABLE_DRUMBRAKE int target_func_index_; #endif // V8_ENABLE_DRUMBRAKE }; namespace wasm { enum class OnResume : int { kContinue, kThrow }; // Generated "constructor" functions (per the Custom Descriptors proposal) // store the exported Wasm function they're calling in a context slot. // We use the first slot in a context with one slot. static constexpr int kConstructorFunctionContextSlot = Context::MIN_CONTEXT_SLOTS; static constexpr int kConstructorFunctionContextLength = kConstructorFunctionContextSlot + 1; // Same trick for generated method wrappers. static constexpr int kMethodWrapperContextSlot = Context::MIN_CONTEXT_SLOTS; static constexpr int kMethodWrapperContextLength = kMethodWrapperContextSlot + 1; } // namespace wasm // A helper for an entry for an imported function, indexed statically. // The underlying storage in the instance is used by generated code to // call imported functions at runtime. // Each entry is either: // - Wasm to Wrapper, which has fields // - object = a WasmImportData // - target = entrypoint to import wrapper code // - Wasm to Wasm, which has fields // - object = target instance data // - target = entrypoint for the function class ImportedFunctionEntry { public: inline ImportedFunctionEntry(DirectHandle<WasmTrustedInstanceData>, int index); // Initialize this entry as a Wasm to Wasm call. void SetWasmToWasm(Tagged<WasmTrustedInstanceData> target_instance_object, WasmCodePointer call_target, wasm::CanonicalTypeIndex sig_id #if V8_ENABLE_DRUMBRAKE , int exported_function_index #endif // V8_ENABLE_DRUMBRAKE ); // Initialize this entry as a Wasm to non-Wasm call, i.e. anything that needs // an import wrapper. This accepts the isolate as a parameter since it // allocates a WasmImportData. V8_EXPORT_PRIVATE void SetWasmToWrapper( Isolate*, DirectHandle<JSReceiver> callable, std::shared_ptr<wasm::WasmWrapperHandle> wrapper_handle, wasm::Suspend suspend, const wasm::CanonicalSig* sig); Tagged<JSReceiver> callable(); Tagged<Object> maybe_callable(); Tagged<Object> implicit_arg(); WasmCodePointer target(); #if V8_ENABLE_DRUMBRAKE int function_index_in_called_module(); #endif // V8_ENABLE_DRUMBRAKE private: DirectHandle<WasmTrustedInstanceData> const instance_data_; int const index_; }; enum InternalizeString : bool { kInternalize = true, kNoInternalize = false }; // Representation of a WebAssembly.Module JavaScript-level object. class WasmModuleObject : public TorqueGeneratedWasmModuleObject<WasmModuleObject, JSObject> { public: inline wasm::NativeModule* native_module() const; inline const std::shared_ptr<wasm::NativeModule>& shared_native_module() const; // Dispatched behavior. DECL_PRINTER(WasmModuleObject) // Creates a new {WasmModuleObject} for an existing {NativeModule} that is // reference counted and might be shared between multiple Isolates. V8_EXPORT_PRIVATE static DirectHandle<WasmModuleObject> New( Isolate* isolate, std::shared_ptr<wasm::NativeModule> native_module, DirectHandle<Script> script); // Get the module name, if set. Returns an empty handle otherwise. static MaybeDirectHandle<String> GetModuleNameOrNull( Isolate*, DirectHandle<WasmModuleObject>); // Get the function name of the function identified by the given index. // Returns a null handle if the function is unnamed or the name is not a valid // UTF-8 string. static MaybeDirectHandle<String> GetFunctionNameOrNull( Isolate*, DirectHandle<WasmModuleObject>, uint32_t func_index); // Get the raw bytes of the function name of the function identified by the // given index. // Meant to be used for debugging or frame printing. // Does not allocate, hence gc-safe. base::Vector<const uint8_t> GetRawFunctionName(int func_index); // Extract a portion of the wire bytes as UTF-8 string, optionally // internalized. (Prefer to internalize early if the string will be used for a // property lookup anyway.) static DirectHandle<String> ExtractUtf8StringFromModuleBytes( Isolate*, base::Vector<const uint8_t> wire_bytes, wasm::WireBytesRef, InternalizeString); TQ_OBJECT_CONSTRUCTORS(WasmModuleObject) }; #if V8_ENABLE_SANDBOX || DEBUG // This should be checked on all code paths that write into WasmDispatchTables. bool FunctionSigMatchesTable(wasm::CanonicalTypeIndex sig_id, wasm::CanonicalValueType table_type); #endif // Representation of a WebAssembly.Table JavaScript-level object. class WasmTableObject : public TorqueGeneratedWasmTableObject<WasmTableObject, JSObject> { public: class BodyDescriptor; inline wasm::ValueType type(const wasm::WasmModule* module); inline wasm::CanonicalValueType canonical_type( const wasm::WasmModule* module); // Use this when you don't care whether the type stored on the in-sandbox // object might have been corrupted to contain an invalid type index. // That implies that you can't even canonicalize the type! inline wasm::ValueType unsafe_type(); DECL_TRUSTED_POINTER_ACCESSORS(trusted_data, WasmTrustedInstanceData) DECL_TRUSTED_POINTER_ACCESSORS(trusted_dispatch_table, WasmDispatchTable) DECL_VERIFIER(WasmTableObject) V8_EXPORT_PRIVATE static int Grow(Isolate* isolate, DirectHandle<WasmTableObject> table, uint32_t count, DirectHandle<Object> init_value); // TODO(jkummerow): Consider getting rid of {type}, use {canonical_type} // instead. V8_EXPORT_PRIVATE static DirectHandle<WasmTableObject> New( Isolate* isolate, DirectHandle<WasmTrustedInstanceData> trusted_data, wasm::ValueType type, wasm::CanonicalValueType canonical_type, uint32_t initial, bool has_maximum, uint64_t maximum, DirectHandle<Object> initial_value, wasm::AddressType address_type, DirectHandle<WasmDispatchTable>* out_dispatch_table = nullptr); inline bool is_in_bounds(uint32_t entry_index); inline bool is_table64() const; // Get the declared maximum as uint64_t or nullopt if no maximum was declared. inline std::optional<uint64_t> maximum_length_u64() const; // Thin wrapper around {JsToWasmObject}. static MaybeDirectHandle<Object> JSToWasmElement( Isolate* isolate, DirectHandle<WasmTableObject> table, DirectHandle<Object> entry, const char** error_message); // This function will not handle JS objects; i.e., {entry} needs to be in wasm // representation. V8_EXPORT_PRIVATE static void Set(Isolate* isolate, DirectHandle<WasmTableObject> table, uint32_t index, DirectHandle<Object> entry); V8_EXPORT_PRIVATE static DirectHandle<Object> Get( Isolate* isolate, DirectHandle<WasmTableObject> table, uint32_t index); V8_EXPORT_PRIVATE static void Fill(Isolate* isolate, DirectHandle<WasmTableObject> table, uint32_t start, DirectHandle<Object> entry, uint32_t count); // TODO(wasm): Unify these three methods into one. static void UpdateDispatchTable( Isolate* isolate, DirectHandle<WasmTableObject> table, int entry_index, const wasm::WasmFunction* func, DirectHandle<WasmTrustedInstanceData> target_instance #if V8_ENABLE_DRUMBRAKE , int target_func_index #endif // V8_ENABLE_DRUMBRAKE ); static void UpdateDispatchTable(Isolate* isolate, DirectHandle<WasmTableObject> table, int entry_index, DirectHandle<WasmJSFunction> function); static void UpdateDispatchTable(Isolate* isolate, DirectHandle<WasmTableObject> table, int entry_index, DirectHandle<WasmCapiFunction> capi_function); void ClearDispatchTable(int index); V8_EXPORT_PRIVATE static void SetFunctionTablePlaceholder( Isolate* isolate, DirectHandle<WasmTableObject> table, int entry_index, DirectHandle<WasmTrustedInstanceData> trusted_instance_data, int func_index); // This function reads the content of a function table entry and returns it // through the output parameters. static void GetFunctionTableEntry( Isolate* isolate, DirectHandle<WasmTableObject> table, int entry_index, bool* is_valid, bool* is_null, MaybeDirectHandle<WasmTrustedInstanceData>* instance_data, int* function_index, MaybeDirectHandle<WasmJSFunction>* maybe_js_function); private: // {entry} is either {Null} or a {WasmInternalFunction}. static void SetFunctionTableEntry(Isolate* isolate, DirectHandle<WasmTableObject> table, int entry_index, DirectHandle<Object> entry); TQ_OBJECT_CONSTRUCTORS(WasmTableObject) }; class WasmMemoryMapDescriptor : public TorqueGeneratedWasmMemoryMapDescriptor<WasmMemoryMapDescriptor, JSObject> { public: V8_EXPORT_PRIVATE static MaybeDirectHandle<WasmMemoryMapDescriptor> NewFromAnonymous(Isolate* isolate, size_t length); V8_EXPORT_PRIVATE static DirectHandle<WasmMemoryMapDescriptor> NewFromFileDescriptor( Isolate* isolate, v8::WasmMemoryMapDescriptor::WasmFileDescriptor file_descriptor); // Returns the number of bytes that got mapped into the WebAssembly.Memory. V8_EXPORT_PRIVATE size_t MapDescriptor(DirectHandle<WasmMemoryObject> memory, size_t offset); // Returns `false` if an error occurred, otherwise `true`. V8_EXPORT_PRIVATE bool UnmapDescriptor(); class BodyDescriptor; TQ_OBJECT_CONSTRUCTORS(WasmMemoryMapDescriptor) }; // Representation of a WebAssembly.Memory JavaScript-level object. class WasmMemoryObject : public TorqueGeneratedWasmMemoryObject<WasmMemoryObject, JSObject> { public: class BodyDescriptor; DECL_ACCESSORS(instances, Tagged<WeakArrayList>) inline const std::shared_ptr<BackingStore>& backing_store() const; // Add a use of this memory object to the given instance. This updates the // internal weak list of instances that use this memory and also updates the // fields of the instance to reference this memory's buffer. // Note that we update both the non-shared and shared (if any) parts of the // instance for faster access to shared memory. V8_EXPORT_PRIVATE static void UseInInstance( Isolate* isolate, DirectHandle<WasmMemoryObject> memory, DirectHandle<WasmTrustedInstanceData> trusted_instance_data, DirectHandle<WasmTrustedInstanceData> shared_trusted_instance_data, int memory_index_in_instance); inline bool has_maximum_pages(); inline bool is_memory64() const; V8_EXPORT_PRIVATE static DirectHandle<WasmMemoryObject> New( Isolate* isolate, MaybeDirectHandle<JSArrayBuffer> maybe_buffer, std::shared_ptr<BackingStore> backing_store, int maximum, wasm::AddressType address_type); V8_EXPORT_PRIVATE static MaybeDirectHandle<WasmMemoryObject> New( Isolate* isolate, int initial, int maximum, SharedFlag shared, wasm::AddressType address_type); // Assign a new (grown) buffer to this memory, also updating the shortcut // fields of all instances that use this memory. void SetNewBuffer(Isolate* isolate, Tagged<JSArrayBuffer> new_buffer); // Updates all WebAssembly instances that use this Memory as a memory, after // growing or refreshing the memory. void UpdateInstances(Isolate* isolate); // Fix up a resizable ArrayBuffer that exposes Wasm memory. // // Usually, an ArrayBuffer is setup from metadata on its BackingStore. // However, ABs that are actually WebAssembly memories may have metadata that // diverge from their BackingStore's. // // SABs' is_resizable_by_js may be true even when the BackingStore's // equivalent field is false. This happens when there are both growable and // non-growable SABs pointing to the same shared WebAssembly memory. // // AB and SABs' max_byte_length is the requested max passed to the // WebAssembly.Memory constructor, while the BackingStore's max is an // engine-determined heuristic that may be smaller. // // Both divergences are impossible for JS-created buffers. void FixUpResizableArrayBuffer(Tagged<JSArrayBuffer> new_buffer); // Makes a new buffer backed by backing_store and update all the links. // The resizability of the new AB is determined by the bit on the backing // store, except if `override_resizable` is given (for shared ABs where the // bit on the backing store is not authoritative). static DirectHandle<JSArrayBuffer> RefreshBuffer( Isolate* isolate, DirectHandle<WasmMemoryObject> memory, std::shared_ptr<BackingStore> backing_store, std::optional<ResizableFlag> override_resizable = {}); V8_EXPORT_PRIVATE static int32_t Grow(Isolate*, DirectHandle<WasmMemoryObject>, uint32_t pages); // Returns the current JSArrayBuffer bound to this memory object. If there is // none yet it will be allocated and stored in the `array_buffer` field. V8_EXPORT_PRIVATE static DirectHandle<JSArrayBuffer> GetArrayBuffer( Isolate* isolate, DirectHandle<WasmMemoryObject> memory); // Changes resizability of the attached ArrayBuffer. // Detaches the existing buffer if it is not shared. static DirectHandle<JSArrayBuffer> ChangeArrayBufferResizability( Isolate* isolate, DirectHandle<WasmMemoryObject> memory, ResizableFlag new_resizability); static constexpr int kNoMaximum = -1; TQ_OBJECT_CONSTRUCTORS(WasmMemoryObject) }; // Representation of a WebAssembly.Global JavaScript-level object. class WasmGlobalObject : public TorqueGeneratedWasmGlobalObject<WasmGlobalObject, JSObject> { public: class BodyDescriptor; DECL_ACCESSORS(untagged_buffer, Tagged<JSArrayBuffer>) DECL_ACCESSORS(tagged_buffer, Tagged<FixedArray>) DECL_PRIMITIVE_ACCESSORS(unsafe_type, wasm::ValueType) DECL_TRUSTED_POINTER_ACCESSORS(trusted_data, WasmTrustedInstanceData) // Dispatched behavior. DECL_PRINTER(WasmGlobalObject) V8_EXPORT_PRIVATE static MaybeDirectHandle<WasmGlobalObject> New( Isolate* isolate, DirectHandle<WasmTrustedInstanceData> instance_object, MaybeDirectHandle<JSArrayBuffer> maybe_untagged_buffer, MaybeDirectHandle<FixedArray> maybe_tagged_buffer, wasm::ValueType type, int32_t offset, bool is_mutable); inline int unsafe_type_size() const; inline int32_t GetI32() const; inline int64_t GetI64() const; inline float GetF32() const; inline double GetF64() const; inline uint8_t* GetS128RawBytes() const; inline DirectHandle<Object> GetRef() const; inline void SetI32(int32_t value); inline void SetI64(int64_t value); inline void SetF32(float value); inline void SetF64(double value); // {value} must be an object in Wasm representation. inline void SetRef(DirectHandle<Object> value); private: // This function returns the address of the global's data in the // JSArrayBuffer. This buffer may be allocated on-heap, in which case it may // not have a fixed address. inline Address address() const; TQ_OBJECT_CONSTRUCTORS(WasmGlobalObject) }; class FeedbackConstants { public: static constexpr int kHeaderSlots = 1; static constexpr int kSlotsPerInstruction = 2; }; // The trusted part of a WebAssembly instance. // This object lives in trusted space and is never modified from user space. class V8_EXPORT_PRIVATE WasmTrustedInstanceData : public ExposedTrustedObject { public: DECL_OPTIONAL_ACCESSORS(instance_object, Tagged<WasmInstanceObject>) DECL_OPTIONAL_ACCESSORS(native_context, Tagged<Context>) DECL_ACCESSORS(memory_objects, Tagged<FixedArray>) #if V8_ENABLE_DRUMBRAKE DECL_OPTIONAL_ACCESSORS(interpreter_object, Tagged<Tuple2>) #endif // V8_ENABLE_DRUMBRAKE DECL_OPTIONAL_ACCESSORS(untagged_globals_buffer, Tagged<JSArrayBuffer>) DECL_OPTIONAL_ACCESSORS(tagged_globals_buffer, Tagged<FixedArray>) DECL_OPTIONAL_ACCESSORS(imported_mutable_globals_buffers, Tagged<FixedArray>) // tables: FixedArray of WasmTableObject. DECL_OPTIONAL_ACCESSORS(tables, Tagged<FixedArray>) DECL_PROTECTED_POINTER_ACCESSORS(dispatch_table_for_imports, WasmDispatchTableForImports) DECL_ACCESSORS(imported_mutable_globals, Tagged<FixedAddressArray>) #if V8_ENABLE_DRUMBRAKE // Points to an array that contains the function index for each imported Wasm // function. This is required to call imported functions from the Wasm // interpreter. DECL_ACCESSORS(imported_function_indices, Tagged<FixedInt32Array>) #endif // V8_ENABLE_DRUMBRAKE DECL_PROTECTED_POINTER_ACCESSORS(shared_part, WasmTrustedInstanceData) DECL_PROTECTED_POINTER_ACCESSORS(dispatch_table0, WasmDispatchTable) DECL_PROTECTED_POINTER_ACCESSORS(dispatch_tables, ProtectedFixedArray) DECL_OPTIONAL_ACCESSORS(tags_table, Tagged<FixedArray>) DECL_ACCESSORS(func_refs, Tagged<FixedArray>) DECL_ACCESSORS(managed_object_maps, Tagged<FixedArray>) DECL_ACCESSORS(feedback_vectors, Tagged<FixedArray>) DECL_ACCESSORS(well_known_imports, Tagged<FixedArray>) DECL_PRIMITIVE_ACCESSORS(memory0_start, uint8_t*) DECL_PRIMITIVE_ACCESSORS(memory0_size, size_t) DECL_PROTECTED_POINTER_ACCESSORS(managed_native_module, TrustedManaged<wasm::NativeModule>) DECL_PRIMITIVE_ACCESSORS(globals_start, uint8_t*) DECL_PRIMITIVE_ACCESSORS(jump_table_start, Address) DECL_PRIMITIVE_ACCESSORS(hook_on_function_call_address, Address) DECL_PRIMITIVE_ACCESSORS(tiering_budget_array, std::atomic<uint32_t>*) DECL_PROTECTED_POINTER_ACCESSORS(memory_bases_and_sizes, TrustedFixedAddressArray) DECL_PROTECTED_POINTER_ACCESSORS(data_segments, TrustedPodArray<wasm::WireBytesRef>) DECL_ACCESSORS(element_segments, Tagged<FixedArray>) DECL_PRIMITIVE_ACCESSORS(break_on_entry, uint8_t) // Clear uninitialized padding space. This ensures that the snapshot content // is deterministic. Depending on the V8 build mode there could be no padding. inline void clear_padding(); inline Tagged<WasmMemoryObject> memory_object(int memory_index) const; inline uint8_t* memory_base(int memory_index) const; inline size_t memory_size(int memory_index) const; inline wasm::NativeModule* native_module() const; inline Tagged<WasmModuleObject> module_object() const; inline const wasm::WasmModule* module() const; // Dispatched behavior. DECL_PRINTER(WasmTrustedInstanceData) DECL_VERIFIER(WasmTrustedInstanceData) // Layout description. #define FIELD_LIST(V) \ /* Often-accessed fields go first to minimize generated code size. */ \ /* Less than system pointer sized fields come first. */ \ V(kProtectedDispatchTable0Offset, kTaggedSize) \ V(kProtectedDispatchTableForImportsOffset, kTaggedSize) \ V(kImportedMutableGlobalsOffset, kTaggedSize) \ IF_WASM_DRUMBRAKE(V, kImportedFunctionIndicesOffset, kTaggedSize) \ /* Optional padding to align system pointer size fields */ \ V(kOptionalPaddingOffset, POINTER_SIZE_PADDING(kOptionalPaddingOffset)) \ V(kMemory0StartOffset, kSystemPointerSize) \ V(kMemory0SizeOffset, kSizetSize) \ V(kGlobalsStartOffset, kSystemPointerSize) \ V(kJumpTableStartOffset, kSystemPointerSize) \ /* End of often-accessed fields. */ \ /* Continue with system pointer size fields to maintain alignment. */ \ V(kHookOnFunctionCallAddressOffset, kSystemPointerSize) \ V(kTieringBudgetArrayOffset, kSystemPointerSize) \ /* Less than system pointer size aligned fields are below. */ \ V(kProtectedMemoryBasesAndSizesOffset, kTaggedSize) \ V(kProtectedDataSegmentsOffset, kTaggedSize) \ V(kElementSegmentsOffset, kTaggedSize) \ V(kInstanceObjectOffset, kTaggedSize) \ V(kNativeContextOffset, kTaggedSize) \ V(kProtectedSharedPartOffset, kTaggedSize) \ V(kMemoryObjectsOffset, kTaggedSize) \ V(kUntaggedGlobalsBufferOffset, kTaggedSize) \ V(kTaggedGlobalsBufferOffset, kTaggedSize) \ V(kImportedMutableGlobalsBuffersOffset, kTaggedSize) \ IF_WASM_DRUMBRAKE(V, kInterpreterObjectOffset, kTaggedSize) \ V(kTablesOffset, kTaggedSize) \ V(kProtectedDispatchTablesOffset, kTaggedSize) \ V(kTagsTableOffset, kTaggedSize) \ V(kFuncRefsOffset, kTaggedSize) \ V(kManagedObjectMapsOffset, kTaggedSize) \ V(kFeedbackVectorsOffset, kTaggedSize) \ V(kWellKnownImportsOffset, kTaggedSize) \ V(kProtectedManagedNativeModuleOffset, kTaggedSize) \ V(kBreakOnEntryOffset, kUInt8Size) \ /* More padding to make the header pointer-size aligned */ \ V(kHeaderPaddingOffset, POINTER_SIZE_PADDING(kHeaderPaddingOffset)) \ V(kHeaderSize, 0) \ V(kSize, 0) DEFINE_FIELD_OFFSET_CONSTANTS(ExposedTrustedObject::kHeaderSize, FIELD_LIST) static_assert(IsAligned(kHeaderSize, kTaggedSize)); // TODO(ishell, v8:8875): When pointer compression is enabled 8-byte size // fields (external pointers, doubles and BigInt data) are only kTaggedSize // aligned so checking for alignments of fields bigger than kTaggedSize // doesn't make sense until v8:8875 is fixed. #define ASSERT_FIELD_ALIGNED(offset, size) \ static_assert(size == 0 || IsAligned(offset, size) || \ (COMPRESS_POINTERS_BOOL && (size == kSystemPointerSize) && \ IsAligned(offset, kTaggedSize))); FIELD_LIST(ASSERT_FIELD_ALIGNED) #undef ASSERT_FIELD_ALIGNED #undef FIELD_LIST // GC support: List all tagged fields and protected fields. // V(offset, name) #define WASM_TAGGED_INSTANCE_DATA_FIELDS(V) \ V(kInstanceObjectOffset, "instance_object") \ V(kNativeContextOffset, "native_context") \ V(kMemoryObjectsOffset, "memory_objects") \ V(kUntaggedGlobalsBufferOffset, "untagged_globals_buffer") \ V(kTaggedGlobalsBufferOffset, "tagged_globals_buffer") \ V(kImportedMutableGlobalsBuffersOffset, "imported_mutable_globals_buffers") \ IF_WASM_DRUMBRAKE(V, kInterpreterObjectOffset, "interpreter_object") \ V(kTablesOffset, "tables") \ V(kTagsTableOffset, "tags_table") \ V(kFuncRefsOffset, "func_refs") \ V(kManagedObjectMapsOffset, "managed_object_maps") \ V(kFeedbackVectorsOffset, "feedback_vectors") \ V(kWellKnownImportsOffset, "well_known_imports") \ V(kImportedMutableGlobalsOffset, "imported_mutable_globals") \ IF_WASM_DRUMBRAKE(V, kImportedFunctionIndicesOffset, \ "imported_function_indices") \ V(kElementSegmentsOffset, "element_segments") #define WASM_PROTECTED_INSTANCE_DATA_FIELDS(V) \ V(kProtectedSharedPartOffset, "shared_part") \ V(kProtectedMemoryBasesAndSizesOffset, "memory_bases_and_sizes") \ V(kProtectedDataSegmentsOffset, "data_segments") \ V(kProtectedDispatchTable0Offset, "dispatch_table0") \ V(kProtectedDispatchTablesOffset, "dispatch_tables") \ V(kProtectedDispatchTableForImportsOffset, "dispatch_table_for_imports") \ V(kProtectedManagedNativeModuleOffset, "managed_native_module") #define WASM_INSTANCE_FIELD_OFFSET(offset, _) offset, #define WASM_INSTANCE_FIELD_NAME(_, name) name, #define PLUS_ONE(...) +1 static constexpr size_t kTaggedFieldsCount = WASM_TAGGED_INSTANCE_DATA_FIELDS(PLUS_ONE); static constexpr size_t kProtectedFieldsCount = WASM_PROTECTED_INSTANCE_DATA_FIELDS(PLUS_ONE); #undef PLUS_ONE static constexpr std::array<uint16_t, kTaggedFieldsCount> kTaggedFieldOffsets = { WASM_TAGGED_INSTANCE_DATA_FIELDS(WASM_INSTANCE_FIELD_OFFSET)}; static constexpr std::array<const char*, kTaggedFieldsCount> kTaggedFieldNames = { WASM_TAGGED_INSTANCE_DATA_FIELDS(WASM_INSTANCE_FIELD_NAME)}; static constexpr std::array<uint16_t, kProtectedFieldsCount> kProtectedFieldOffsets = { WASM_PROTECTED_INSTANCE_DATA_FIELDS(WASM_INSTANCE_FIELD_OFFSET)}; static constexpr std::array<const char*, kProtectedFieldsCount> kProtectedFieldNames = { WASM_PROTECTED_INSTANCE_DATA_FIELDS(WASM_INSTANCE_FIELD_NAME)}; #undef WASM_INSTANCE_FIELD_OFFSET #undef WASM_INSTANCE_FIELD_NAME #undef WASM_TAGGED_INSTANCE_DATA_FIELDS #undef WASM_PROTECTED_INSTANCE_DATA_FIELDS static_assert(kTaggedFieldOffsets.size() == kTaggedFieldNames.size(), "every tagged field offset needs a name"); static_assert(kProtectedFieldOffsets.size() == kProtectedFieldNames.size(), "every protected field offset needs a name"); void SetRawMemory(int memory_index, uint8_t* mem_start, size_t mem_size); #if V8_ENABLE_DRUMBRAKE // Get the interpreter object associated with the given wasm object. // If no interpreter object exists yet, it is created automatically. static DirectHandle<Tuple2> GetOrCreateInterpreterObject( DirectHandle<WasmInstanceObject>); static DirectHandle<Tuple2> GetInterpreterObject( DirectHandle<WasmInstanceObject>); #endif // V8_ENABLE_DRUMBRAKE static DirectHandle<WasmTrustedInstanceData> New( Isolate*, DirectHandle<WasmModuleObject>, std::shared_ptr<wasm::NativeModule>, bool shared); WasmCodePointer GetCallTarget(uint32_t func_index); inline Tagged<WasmDispatchTable> dispatch_table(uint32_t table_index); inline bool has_dispatch_table(uint32_t table_index); // Copies table entries. Returns {false} if the ranges are out-of-bounds. static bool CopyTableEntries( Isolate* isolate, DirectHandle<WasmTrustedInstanceData> trusted_instance_data, uint32_t table_dst_index, uint32_t table_src_index, uint32_t dst, uint32_t src, uint32_t count) V8_WARN_UNUSED_RESULT; // Loads a range of elements from element segment into a table. // Returns the empty {Optional} if the operation succeeds, or an {Optional} // with the error {MessageTemplate} if it fails. static std::optional<MessageTemplate> InitTableEntries( Isolate* isolate, DirectHandle<WasmTrustedInstanceData> trusted_instance_data, DirectHandle<WasmTrustedInstanceData> shared_trusted_instance_data, uint32_t table_index, uint32_t segment_index, uint32_t dst, uint32_t src, uint32_t count) V8_WARN_UNUSED_RESULT; class BodyDescriptor; // Read a WasmFuncRef from the func_refs FixedArray. Returns true on success // and writes the result in the output parameter. Returns false if no func_ref // exists yet for this function. Use GetOrCreateFuncRef to always create one. bool try_get_func_ref(int index, Tagged<WasmFuncRef>* result); // Acquires the {WasmFuncRef} for a given {function_index} from the cache of // the given {trusted_instance_data}, or creates a new {WasmInternalFunction} // and {WasmFuncRef} if it does not exist yet. The new objects are added to // the cache of the {trusted_instance_data} immediately. // {precreate_external}: Allocate the corresponding WasmExportedFunction // immediately (which is slightly more efficient than letting // {WasmInternalFunction::GetOrCreateExternal} do the work separately). static DirectHandle<WasmFuncRef> GetOrCreateFuncRef( Isolate* isolate, DirectHandle<WasmTrustedInstanceData> trusted_instance_data, int function_index, wasm::PrecreateExternal precreate_external = wasm::kOnlyInternalFunction); // Get a raw pointer to the location where the given global is stored. // {global} must not be a reference type. uint8_t* GetGlobalStorage(const wasm::WasmGlobal&); // Get the FixedArray and the index in that FixedArray for the given global, // which must be a reference type. std::pair<Tagged<FixedArray>, uint32_t> GetGlobalBufferAndIndex( const wasm::WasmGlobal&); // Get the value of a global. wasm::WasmValue GetGlobalValue(Isolate*, const wasm::WasmGlobal&); OBJECT_CONSTRUCTORS(WasmTrustedInstanceData, ExposedTrustedObject); private: void InitDataSegmentArrays(const wasm::NativeModule*); }; // Representation of a WebAssembly.Instance JavaScript-level object. // This is mostly a wrapper around the WasmTrustedInstanceData, plus any // user-set properties. class WasmInstanceObject : public TorqueGeneratedWasmInstanceObject<WasmInstanceObject, JSObject> { public: DECL_TRUSTED_POINTER_ACCESSORS(trusted_data, WasmTrustedInstanceData) inline const wasm::WasmModule* module() const; class BodyDescriptor; DECL_PRINTER(WasmInstanceObject) TQ_OBJECT_CONSTRUCTORS(WasmInstanceObject) }; // Representation of WebAssembly.Exception JavaScript-level object. class WasmTagObject : public TorqueGeneratedWasmTagObject<WasmTagObject, JSObject> { public: class BodyDescriptor; // Checks whether the given {sig} has the same parameter types as the // serialized signature stored within this tag object. bool MatchesSignature(wasm::CanonicalTypeIndex expected_index); static DirectHandle<WasmTagObject> New( Isolate* isolate, const wasm::FunctionSig* sig, wasm::CanonicalTypeIndex type_index, DirectHandle<HeapObject> tag, DirectHandle<WasmTrustedInstanceData> instance); DECL_TRUSTED_POINTER_ACCESSORS(trusted_data, WasmTrustedInstanceData) TQ_OBJECT_CONSTRUCTORS(WasmTagObject) }; // Off-heap data object owned by a WasmDispatchTable. Owns the {shared_ptr}s // which manage the lifetimes of the {WasmWrapperHandle}s. class WasmDispatchTableData { public: // If a wrapper is installed at the given {index}, returns the corresponding // {WasmWrapperHandle} so that it can be reused in other tables. V8_EXPORT_PRIVATE std::optional<std::shared_ptr<wasm::WasmWrapperHandle>> MaybeGetWrapperHandle( int index) const; #ifdef DEBUG WasmCodePointer WrapperCodePointerForDebugging(int index); #endif void Add(int index, std::shared_ptr<wasm::WasmWrapperHandle> wrapper_handle); void Remove(int index); private: friend class WasmDispatchTable; std::unordered_map<int, std::shared_ptr<wasm::WasmWrapperHandle>> wrappers_; }; // The dispatch table is referenced from a WasmTableObject and from every // WasmTrustedInstanceData which uses the table. It is used from generated code // for executing indirect calls. class WasmDispatchTable : public ExposedTrustedObject { public: #if V8_ENABLE_DRUMBRAKE static const uint32_t kInvalidFunctionIndex = UINT_MAX; #endif // V8_ENABLE_DRUMBRAKE // Indicate whether we are modifying an existing entry (for which we might // have to update the ref count), or if we are initializing a slot for the // first time (in which case we should not read the uninitialized memory). enum NewOrExistingEntry : bool { kNewEntry, kExistingEntry }; class BodyDescriptor; static constexpr size_t kLengthOffset = kHeaderSize; static constexpr size_t kCapacityOffset = kLengthOffset + kUInt32Size; static constexpr size_t kProtectedOffheapDataOffset = kCapacityOffset + kUInt32Size; static constexpr size_t kProtectedUsesOffset = kProtectedOffheapDataOffset + kTaggedSize; static constexpr size_t kTableTypeOffset = kProtectedUsesOffset + kTaggedSize; static constexpr size_t kPaddingSize = TAGGED_SIZE_8_BYTES ? kUInt32Size : 0; static constexpr size_t kEntriesOffset = kTableTypeOffset + kUInt32Size + kPaddingSize; // Entries consist of // - target (WasmCodePointer == entry in WasmCodePointerTable), #if V8_ENABLE_DRUMBRAKE // - function_index (uint32_t) (located in place of target pointer), #endif // V8_ENABLE_DRUMBRAKE // - sig (canonical type index == uint32_t); unused for imports which check // the signature statically, // - implicit_arg (protected pointer, tagged sized). static constexpr size_t kTargetBias = 0; #if V8_ENABLE_DRUMBRAKE // In jitless mode, reuse the 'target' field storage to hold the (uint32_t) // function index. static constexpr size_t kFunctionIndexBias = kTargetBias; #endif // V8_ENABLE_DRUMBRAKE static_assert(sizeof(WasmCodePointer) == kUInt32Size); static constexpr size_t kSigBias = kTargetBias + kUInt32Size; static constexpr size_t kImplicitArgBias = kSigBias + kUInt32Size; static constexpr size_t kEntrySize = kImplicitArgBias + kTaggedSize; // Tagged fields must be tagged-size-aligned. static_assert(IsAligned(kProtectedOffheapDataOffset, kTaggedSize)); static_assert(IsAligned(kEntriesOffset, kTaggedSize)); static_assert(IsAligned(kEntrySize, kTaggedSize)); static_assert(IsAligned(kImplicitArgBias, kTaggedSize)); // The total byte size must still fit in an integer. static constexpr int kMaxLength = (kMaxInt - kEntriesOffset) / kEntrySize; static constexpr int SizeFor(int length) { DCHECK_LE(length, kMaxLength); return kEntriesOffset + length * kEntrySize; } static constexpr int OffsetOf(int index) { DCHECK_LT(index, kMaxLength); return SizeFor(index); } // The current length of this dispatch table. This is always <= the capacity. inline int length() const; inline int length(AcquireLoadTag) const; // The current capacity. Can be bigger than the current length to allow for // more efficient growing. inline int capacity() const; DECL_PROTECTED_POINTER_ACCESSORS(protected_offheap_data, TrustedManaged<WasmDispatchTableData>) inline WasmDispatchTableData* offheap_data() const; // Stores all WasmTrustedInstanceData that refer to this WasmDispatchTable. DECL_PROTECTED_POINTER_ACCESSORS(protected_uses, ProtectedWeakFixedArray) // Stores the canonical type of the table. DECL_PRIMITIVE_ACCESSORS(table_type, wasm::CanonicalValueType) // {implicit_arg} will be a WasmImportData, a WasmTrustedInstanceData, or // Smi::zero() (if the entry was cleared). inline Tagged<Object> implicit_arg(int index) const; inline WasmCodePointer target(int index) const; inline wasm::CanonicalTypeIndex sig(int index) const; // Set an entry for indirect calls that don't go to a WasmToJS wrapper. // Wrappers are special since we own the CPT entries for the wrappers. // {implicit_arg} has to be a WasmTrustedInstanceData, or Smi::zero() for // clearing the slot. void V8_EXPORT_PRIVATE SetForNonWrapper( int index, Tagged<Union<Smi, WasmTrustedInstanceData>> implicit_arg, WasmCodePointer call_target, wasm::CanonicalTypeIndex sig_id, #if V8_ENABLE_DRUMBRAKE uint32_t function_index, #endif // V8_ENABLE_DRUMBRAKE NewOrExistingEntry new_or_existing); // Set an entry for indirect calls to a WasmToJS wrapper. void V8_EXPORT_PRIVATE SetForWrapper(int index, Tagged<WasmImportData> implicit_arg, std::shared_ptr<wasm::WasmWrapperHandle> wrapper_handle, wasm::CanonicalTypeIndex sig_id, #if V8_ENABLE_DRUMBRAKE uint32_t function_index, #endif // V8_ENABLE_DRUMBRAKE NewOrExistingEntry new_or_existing); #if V8_ENABLE_DRUMBRAKE inline uint32_t function_index(int index) const; #endif // V8_ENABLE_DRUMBRAKE void Clear(int index, NewOrExistingEntry new_or_existing); std::optional<std::shared_ptr<wasm::WasmWrapperHandle>> MaybeGetWrapperHandle( int index); static void V8_EXPORT_PRIVATE AddUse(Isolate* isolate, DirectHandle<WasmDispatchTable> dispatch_table, DirectHandle<WasmTrustedInstanceData> instance, int table_index); // Internal helpers for management of the uses list. These could be factored // out into a class similar to WeakArrayList if there are additional use // cases for them. // The first slot in the list is the used length. After that, we store // pairs of <instance, table_index>. static Tagged<ProtectedWeakFixedArray> MaybeGrowUsesList( Isolate* isolate, DirectHandle<WasmDispatchTable> dispatch_table); static V8_WARN_UNUSED_RESULT DirectHandle<WasmDispatchTable> Grow( Isolate*, DirectHandle<WasmDispatchTable>, uint32_t new_length); DECL_PRINTER(WasmDispatchTable) DECL_VERIFIER(WasmDispatchTable) OBJECT_CONSTRUCTORS(WasmDispatchTable, ExposedTrustedObject); }; class WasmDispatchTableForImports : public TrustedObject { public: class BodyDescriptor; static constexpr size_t kLengthOffset = kHeaderSize; static constexpr size_t kPaddingSize = TAGGED_SIZE_8_BYTES ? kUInt32Size : 0; static constexpr size_t kProtectedOffheapDataOffset = kLengthOffset + kUInt32Size + kPaddingSize; static constexpr size_t kEntriesOffset = kProtectedOffheapDataOffset + kTaggedSize; // Entries consist of // - target (WasmCodePointer == entry in WasmCodePointerTable), #if V8_ENABLE_DRUMBRAKE // - function_index (uint32_t) (located in place of target pointer), #endif // V8_ENABLE_DRUMBRAKE // - implicit_arg (protected pointer, tagged sized). static constexpr size_t kTargetBias = 0; #if V8_ENABLE_DRUMBRAKE // In jitless mode, reuse the 'target' field storage to hold the (uint32_t) // function index. static constexpr size_t kFunctionIndexBias = kTargetBias; #endif // V8_ENABLE_DRUMBRAKE static constexpr size_t kEntryPaddingSize = TAGGED_SIZE_8_BYTES ? kUInt32Size : 0; static_assert(sizeof(WasmCodePointer) == kUInt32Size); static constexpr size_t kImplicitArgBias = kTargetBias + kEntryPaddingSize + kUInt32Size; static constexpr size_t kEntrySize = kImplicitArgBias + kTaggedSize; // Tagged fields must be tagged-size-aligned. static_assert(IsAligned(kProtectedOffheapDataOffset, kTaggedSize)); static_assert(IsAligned(kEntriesOffset, kTaggedSize)); static_assert(IsAligned(kEntrySize, kTaggedSize)); static_assert(IsAligned(kImplicitArgBias, kTaggedSize)); // The total byte size must still fit in an integer. static constexpr int kMaxLength = (kMaxInt - kEntriesOffset) / kEntrySize; static constexpr int SizeFor(int length) { DCHECK_LE(length, kMaxLength); return kEntriesOffset + length * kEntrySize; } static constexpr int OffsetOf(int index) { DCHECK_LT(index, kMaxLength); return SizeFor(index); } // The current length of this dispatch table. This is always <= the capacity. inline int length() const; inline int length(AcquireLoadTag) const; DECL_PROTECTED_POINTER_ACCESSORS(protected_offheap_data, TrustedManaged<WasmDispatchTableData>) inline WasmDispatchTableData* offheap_data() const; // {implicit_arg} will be a WasmImportData, a WasmTrustedInstanceData, or // Smi::zero() (if the entry was cleared). inline Tagged<Object> implicit_arg(int index) const; inline WasmCodePointer target(int index) const; // Set an entry for indirect calls that don't go to a WasmToJS wrapper. // Wrappers are special since we own the CPT entries for the wrappers. // {implicit_arg} has to be a WasmTrustedInstanceData, or Smi::zero() for // clearing the slot. void V8_EXPORT_PRIVATE SetForNonWrapper( int index, Tagged<Union<Smi, WasmTrustedInstanceData>> implicit_arg, WasmCodePointer call_target, wasm::CanonicalTypeIndex sig_id, #if V8_ENABLE_DRUMBRAKE uint32_t function_index, #endif // V8_ENABLE_DRUMBRAKE WasmDispatchTable::NewOrExistingEntry new_or_existing); // Set an entry for indirect calls to a WasmToJS wrapper. void SetForWrapper(int index, Tagged<WasmImportData> implicit_arg, std::shared_ptr<wasm::WasmWrapperHandle> wrapper_handle, wasm::CanonicalTypeIndex sig_id, #if V8_ENABLE_DRUMBRAKE uint32_t function_index, #endif // V8_ENABLE_DRUMBRAKE WasmDispatchTable::NewOrExistingEntry new_or_existing); void Clear(int index, WasmDispatchTable::NewOrExistingEntry new_or_existing); V8_EXPORT_PRIVATE std::optional<std::shared_ptr<wasm::WasmWrapperHandle>> MaybeGetWrapperHandle( int index); DECL_PRINTER(WasmDispatchTableForImports) DECL_VERIFIER(WasmDispatchTableForImports) OBJECT_CONSTRUCTORS(WasmDispatchTableForImports, TrustedObject); }; // A Wasm exception that has been thrown out of Wasm code. class V8_EXPORT_PRIVATE WasmExceptionPackage : public JSObject { public: static DirectHandle<WasmExceptionPackage> New( Isolate* isolate, DirectHandle<WasmExceptionTag> exception_tag, int encoded_size); static DirectHandle<WasmExceptionPackage> New( Isolate* isolate, DirectHandle<WasmExceptionTag> exception_tag, DirectHandle<FixedArray> values); // The below getters return {undefined} in case the given exception package // does not carry the requested values (i.e. is of a different type). static DirectHandle<Object> GetExceptionTag( Isolate* isolate, DirectHandle<WasmExceptionPackage> exception_package); static DirectHandle<Object> GetExceptionValues( Isolate* isolate, DirectHandle<WasmExceptionPackage> exception_package); // Determines the size of the array holding all encoded exception values. static uint32_t GetEncodedSize(const wasm::WasmModule* module, const wasm::WasmTag* tag); static uint32_t GetEncodedSize(const wasm::CanonicalSig* sig); // In-object fields. enum { kTagIndex, kValuesIndex, kInObjectFieldCount }; static constexpr int kSize = kHeaderSize + (kTaggedSize * kInObjectFieldCount); DECL_PRINTER(WasmExceptionPackage) DECL_VERIFIER(WasmExceptionPackage) OBJECT_CONSTRUCTORS(WasmExceptionPackage, JSObject); }; void V8_EXPORT_PRIVATE EncodeI32ExceptionValue(DirectHandle<FixedArray> encoded_values, uint32_t* encoded_index, uint32_t value); void V8_EXPORT_PRIVATE EncodeI64ExceptionValue(DirectHandle<FixedArray> encoded_values, uint32_t* encoded_index, uint64_t value); void V8_EXPORT_PRIVATE DecodeI32ExceptionValue(DirectHandle<FixedArray> encoded_values, uint32_t* encoded_index, uint32_t* value); void V8_EXPORT_PRIVATE DecodeI64ExceptionValue(DirectHandle<FixedArray> encoded_values, uint32_t* encoded_index, uint64_t* value); bool UseGenericWasmToJSWrapper(wasm::ImportCallKind kind, const wasm::CanonicalSig* sig, wasm::Suspend suspend); // A Wasm function that is wrapped and exported to JavaScript. // Representation of WebAssembly.Function JavaScript-level object. class WasmExportedFunction : public JSFunction { public: V8_EXPORT_PRIVATE static bool IsWasmExportedFunction(Tagged<Object> object); V8_EXPORT_PRIVATE static DirectHandle<WasmExportedFunction> New( Isolate* isolate, DirectHandle<WasmTrustedInstanceData> instance_data, DirectHandle<WasmFuncRef> func_ref, DirectHandle<WasmInternalFunction> internal_function, int arity, DirectHandle<Code> export_wrapper); // Compared to the version above, the extra parameters are redundant // information, but passing them along from callers that have them readily // available is faster than looking them up. static DirectHandle<WasmExportedFunction> New( Isolate* isolate, DirectHandle<WasmTrustedInstanceData> instance_data, DirectHandle<WasmFuncRef> func_ref, DirectHandle<WasmInternalFunction> internal_function, int arity, DirectHandle<Code> export_wrapper, wasm::ModuleOrigin origin, int func_index, wasm::Promise promise); static void MarkAsReceiverIsFirstParam( Isolate* isolate, DirectHandle<WasmExportedFunction> exported_function); // Returns the generic wrapper, or a cached compiled wrapper, or // a freshly-compiled wrapper. static DirectHandle<Code> GetWrapper(Isolate* isolate, const wasm::CanonicalSig* sig, bool receiver_is_first_param, wasm::ModuleOrigin origin); // Return a null-terminated string with the debug name in the form // 'js-to-wasm:<sig>'. static std::unique_ptr<char[]> GetDebugName(const wasm::CanonicalSig* sig); OBJECT_CONSTRUCTORS(WasmExportedFunction, JSFunction); }; // A Wasm function that was created by wrapping a JavaScript callable. // Representation of WebAssembly.Function JavaScript-level object. class WasmJSFunction : public JSFunction { public: static bool IsWasmJSFunction(Tagged<Object> object); static DirectHandle<WasmJSFunction> New(Isolate* isolate, const wasm::FunctionSig* sig, DirectHandle<JSReceiver> callable, wasm::Suspend suspend); OBJECT_CONSTRUCTORS(WasmJSFunction, JSFunction); }; // An external function exposed to Wasm via the C/C++ API. class WasmCapiFunction : public JSFunction { public: static bool IsWasmCapiFunction(Tagged<Object> object); static DirectHandle<WasmCapiFunction> New(Isolate* isolate, Address call_target, DirectHandle<Foreign> embedder_data, const wasm::CanonicalSig* sig); // TODO(clemensb): Remove this accessor. const wasm::CanonicalSig* sig() const; // Checks whether the given {sig} has the same parameter types as the // serialized signature stored within this C-API function object. bool MatchesSignature( wasm::CanonicalTypeIndex other_canonical_sig_index) const; OBJECT_CONSTRUCTORS(WasmCapiFunction, JSFunction); }; // Any external function that can be imported/exported in modules. This abstract // class just dispatches to the following concrete classes: // - {WasmExportedFunction}: A proper Wasm function exported from a module. // - {WasmJSFunction}: A function constructed via WebAssembly.Function in JS. // - {WasmCapiFunction}: A function constructed via the C/C++ API. class WasmExternalFunction : public JSFunction { public: static bool IsWasmExternalFunction(Tagged<Object> object); inline Tagged<WasmFuncRef> func_ref() const; OBJECT_CONSTRUCTORS(WasmExternalFunction, JSFunction); }; class WasmFunctionData : public TorqueGeneratedWasmFunctionData<WasmFunctionData, ExposedTrustedObject> { public: DECL_CODE_POINTER_ACCESSORS(wrapper_code) DECL_PROTECTED_POINTER_ACCESSORS(internal, WasmInternalFunction) DECL_PRINTER(WasmFunctionData) using BodyDescriptor = StackedBodyDescriptor< FixedExposedTrustedObjectBodyDescriptor< WasmFunctionData, kWasmFunctionDataIndirectPointerTagRange>, WithStrongCodePointer<kWrapperCodeOffset>, WithProtectedPointer<kProtectedInternalOffset>>; using SuspendField = base::BitField<wasm::Suspend, 0, 1>; using PromiseField = SuspendField::Next<wasm::Promise, 1>; TQ_OBJECT_CONSTRUCTORS(WasmFunctionData) }; // Information for a WasmExportedFunction which is referenced as the function // data of the SharedFunctionInfo underlying the function. For details please // see the {SharedFunctionInfo::HasWasmExportedFunctionData} predicate. class WasmExportedFunctionData : public TorqueGeneratedWasmExportedFunctionData<WasmExportedFunctionData, WasmFunctionData> { public: DECL_PROTECTED_POINTER_ACCESSORS(instance_data, WasmTrustedInstanceData) DECL_CODE_POINTER_ACCESSORS(c_wrapper_code) inline bool is_promising() const; // Dispatched behavior. DECL_PRINTER(WasmExportedFunctionData) DECL_VERIFIER(WasmExportedFunctionData) using BodyDescriptor = StackedBodyDescriptor< SubclassBodyDescriptor<WasmFunctionData::BodyDescriptor, FixedBodyDescriptorFor<WasmExportedFunctionData>>, WithProtectedPointer<kProtectedInstanceDataOffset>, WithStrongCodePointer<kCWrapperCodeOffset>>; TQ_OBJECT_CONSTRUCTORS(WasmExportedFunctionData) }; class WasmImportData : public TorqueGeneratedWasmImportData<WasmImportData, TrustedObject> { public: // Dispatched behavior. DECL_PRINTER(WasmImportData) DECL_PROTECTED_POINTER_ACCESSORS(instance_data, WasmTrustedInstanceData) DECL_PROTECTED_POINTER_ACCESSORS(call_origin, TrustedObject) DECL_PRIMITIVE_ACCESSORS(suspend, wasm::Suspend) DECL_PRIMITIVE_ACCESSORS(table_slot, uint32_t) static constexpr int kInvalidCallOrigin = 0; void SetIndexInTableAsCallOrigin(Tagged<WasmDispatchTable> table, int entry_index); void SetIndexInTableAsCallOrigin(Tagged<WasmDispatchTableForImports> table, int entry_index); void SetFuncRefAsCallOrigin(Tagged<WasmInternalFunction> func); using BodyDescriptor = StackedBodyDescriptor<FixedBodyDescriptorFor<WasmImportData>, WithProtectedPointer<kProtectedInstanceDataOffset>, WithProtectedPointer<kProtectedCallOriginOffset>>; // Usage of the {bit_field()}. // "Suspend" is always present. using SuspendField = base::BitField<wasm::Suspend, 0, 1>; // "TableSlot" is populated when {protected_call_origin} is a // {WasmDispatchTable}, and describes the slot in that table. static constexpr int kTableSlotBits = 24; static_assert(wasm::kV8MaxWasmTableSize < (1u << kTableSlotBits)); using TableSlotField = SuspendField::Next<uint32_t, kTableSlotBits>; TQ_OBJECT_CONSTRUCTORS(WasmImportData) }; class WasmInternalFunction : public TorqueGeneratedWasmInternalFunction<WasmInternalFunction, ExposedTrustedObject> { public: // Get the external function if it exists. Returns true and writes to the // output parameter if an external function exists. Returns false otherwise. bool try_get_external(Tagged<JSFunction>* result); V8_EXPORT_PRIVATE static DirectHandle<JSFunction> GetOrCreateExternal( DirectHandle<WasmInternalFunction> internal); DECL_PROTECTED_POINTER_ACCESSORS(implicit_arg, TrustedObject) V8_INLINE WasmCodePointer call_target(); V8_INLINE void set_call_target(WasmCodePointer code_pointer); // Dispatched behavior. DECL_PRINTER(WasmInternalFunction) using BodyDescriptor = StackedBodyDescriptor< FixedExposedTrustedObjectBodyDescriptor< WasmInternalFunction, kWasmInternalFunctionIndirectPointerTag>, WithProtectedPointer<kProtectedImplicitArgOffset>>; TQ_OBJECT_CONSTRUCTORS(WasmInternalFunction) }; class WasmFuncRef : public TorqueGeneratedWasmFuncRef<WasmFuncRef, HeapObject> { public: DECL_TRUSTED_POINTER_ACCESSORS(internal, WasmInternalFunction) DECL_PRINTER(WasmFuncRef) using BodyDescriptor = StackedBodyDescriptor< FixedBodyDescriptorFor<WasmFuncRef>, WithStrongTrustedPointer<kTrustedInternalOffset, kWasmInternalFunctionIndirectPointerTag>>; TQ_OBJECT_CONSTRUCTORS(WasmFuncRef) }; // Information for a WasmJSFunction which is referenced as the function data of // the SharedFunctionInfo underlying the function. For details please see the // {SharedFunctionInfo::HasWasmJSFunctionData} predicate. class WasmJSFunctionData : public TorqueGeneratedWasmJSFunctionData<WasmJSFunctionData, WasmFunctionData> { public: // The purpose of this class is to provide lifetime management for compiled // wrappers: the {WasmJSFunction} owns an {OffheapData} via {TrustedManaged}, // which decrements the wrapper handle's refcount when the {WasmJSFunction} is // garbage-collected. class OffheapData { public: explicit OffheapData( std::shared_ptr<wasm::WasmWrapperHandle> wrapper_handle) : wrapper_handle_(wrapper_handle) {} std::shared_ptr<wasm::WasmWrapperHandle> wrapper_handle() const { return wrapper_handle_; } private: const std::shared_ptr<wasm::WasmWrapperHandle> wrapper_handle_; }; DECL_PROTECTED_POINTER_ACCESSORS(protected_offheap_data, TrustedManaged<OffheapData>) inline OffheapData* offheap_data() const; Tagged<JSReceiver> GetCallable() const; wasm::Suspend GetSuspend() const; bool MatchesSignature( wasm::CanonicalTypeIndex other_canonical_sig_index) const; // Dispatched behavior. DECL_PRINTER(WasmJSFunctionData) using BodyDescriptor = StackedBodyDescriptor< SubclassBodyDescriptor<WasmFunctionData::BodyDescriptor, FixedBodyDescriptorFor<WasmJSFunctionData>>, WithProtectedPointer<kProtectedOffheapDataOffset>>; private: TQ_OBJECT_CONSTRUCTORS(WasmJSFunctionData) }; class WasmCapiFunctionData : public TorqueGeneratedWasmCapiFunctionData<WasmCapiFunctionData, WasmFunctionData> { public: DECL_PRINTER(WasmCapiFunctionData) using BodyDescriptor = SubclassBodyDescriptor<WasmFunctionData::BodyDescriptor, FixedBodyDescriptorFor<WasmCapiFunctionData>>; TQ_OBJECT_CONSTRUCTORS(WasmCapiFunctionData) }; class WasmResumeData : public TorqueGeneratedWasmResumeData<WasmResumeData, HeapObject> { public: using BodyDescriptor = StackedBodyDescriptor< FlexibleBodyDescriptor<WasmResumeData::kStartOfStrongFieldsOffset>, WithStrongTrustedPointer<kTrustedSuspenderOffset, kWasmSuspenderIndirectPointerTag>>; DECL_PRINTER(WasmResumeData) DECL_TRUSTED_POINTER_ACCESSORS(trusted_suspender, WasmSuspenderObject) TQ_OBJECT_CONSTRUCTORS(WasmResumeData) }; class WasmScript : public AllStatic { public: // Position used for storing "on entry" breakpoints (a.k.a. instrumentation // breakpoints). This would be an illegal position for any other breakpoint. static constexpr int kOnEntryBreakpointPosition = -1; // Set a breakpoint on the given byte position inside the given module. // This will affect all live and future instances of the module. // The passed position might be modified to point to the next breakable // location inside the same function. // If it points outside a function, or behind the last breakable location, // this function returns false and does not set any breakpoint. V8_EXPORT_PRIVATE static bool SetBreakPoint( DirectHandle<Script>, int* position, DirectHandle<BreakPoint> break_point); // Set an "on entry" breakpoint (a.k.a. instrumentation breakpoint) inside // the given module. This will affect all live and future instances of the // module. V8_EXPORT_PRIVATE static void SetInstrumentationBreakpoint( DirectHandle<Script>, DirectHandle<BreakPoint> break_point); // Set a breakpoint on first breakable position of the given function index // inside the given module. This will affect all live and future instances of // the module. V8_EXPORT_PRIVATE static bool SetBreakPointOnFirstBreakableForFunction( DirectHandle<Script>, int function_index, DirectHandle<BreakPoint> break_point); // Set a breakpoint at the breakable offset of the given function index // inside the given module. This will affect all live and future instances of // the module. V8_EXPORT_PRIVATE static bool SetBreakPointForFunction( DirectHandle<Script>, int function_index, int breakable_offset, DirectHandle<BreakPoint> break_point); // Remove a previously set breakpoint at the given byte position inside the // given module. If this breakpoint is not found this function returns false. V8_EXPORT_PRIVATE static bool ClearBreakPoint( DirectHandle<Script>, int position, DirectHandle<BreakPoint> break_point); // Remove a previously set breakpoint by id. If this breakpoint is not found, // returns false. V8_EXPORT_PRIVATE static bool ClearBreakPointById(DirectHandle<Script>, int breakpoint_id); // Remove all set breakpoints. static void ClearAllBreakpoints(Tagged<Script>); // Get a list of all possible breakpoints within a given range of this module. V8_EXPORT_PRIVATE static bool GetPossibleBreakpoints( wasm::NativeModule* native_module, const debug::Location& start, const debug::Location& end, std::vector<debug::BreakLocation>* locations); // Return an empty handle if no breakpoint is hit at that location, or a // FixedArray with all hit breakpoint objects. static MaybeDirectHandle<FixedArray> CheckBreakPoints( Isolate*, DirectHandle<Script>, int position, StackFrameId stack_frame_id); private: // Helper functions that update the breakpoint info list. static void AddBreakpointToInfo(DirectHandle<Script>, int position, DirectHandle<BreakPoint> break_point); }; // Tags provide an object identity for each exception defined in a wasm module // header. They are referenced by the following fields: // - {WasmTagObject::tag}: The tag of the {Tag} object. // - {WasmInstanceObject::tags_table}: List of tags used by an instance. class WasmExceptionTag : public TorqueGeneratedWasmExceptionTag<WasmExceptionTag, Struct> { public: V8_EXPORT_PRIVATE static DirectHandle<WasmExceptionTag> New(Isolate* isolate, int index); using BodyDescriptor = StructBodyDescriptor; TQ_OBJECT_CONSTRUCTORS(WasmExceptionTag) }; // Data annotated to the asm.js Module function. Used for later instantiation of // that function. class AsmWasmData : public TorqueGeneratedAsmWasmData<AsmWasmData, Struct> { public: static Handle<AsmWasmData> New( Isolate* isolate, std::shared_ptr<wasm::NativeModule> native_module, DirectHandle<HeapNumber> uses_bitset); DECL_PRINTER(AsmWasmData) using BodyDescriptor = StructBodyDescriptor; TQ_OBJECT_CONSTRUCTORS(AsmWasmData) }; class WasmTypeInfo : public TorqueGeneratedWasmTypeInfo<WasmTypeInfo, HeapObject> { public: inline wasm::CanonicalValueType type() const; inline wasm::CanonicalTypeIndex type_index() const; inline wasm::CanonicalValueType element_type() const; // Only for WasmArrays. DECL_PRINTER(WasmTypeInfo) class BodyDescriptor; TQ_OBJECT_CONSTRUCTORS(WasmTypeInfo) }; class WasmObject : public TorqueGeneratedWasmObject<WasmObject, JSReceiver> { protected: // Returns boxed value of the object's field/element with given type and // offset. static inline DirectHandle<Object> ReadValueAt(Isolate* isolate, DirectHandle<HeapObject> obj, wasm::CanonicalValueType type, uint32_t offset); private: template <typename ElementType> static ElementType FromNumber(Tagged<Object> value); TQ_OBJECT_CONSTRUCTORS(WasmObject) }; class WasmStruct : public TorqueGeneratedWasmStruct<WasmStruct, WasmObject> { public: static const wasm::CanonicalStructType* GcSafeType(Tagged<Map> map); static inline int Size(const wasm::StructType* type); static inline int Size(const wasm::CanonicalStructType* type); static inline int GcSafeSize(Tagged<Map> map); static inline void EncodeInstanceSizeInMap(int instance_size, Tagged<Map> map); static inline int DecodeInstanceSizeFromMap(Tagged<Map> map); // Returns the address of the field at given offset. inline Address RawFieldAddress(int raw_offset); // Returns the ObjectSlot for tagged value at given offset. inline ObjectSlot RawField(int raw_offset); // Only for structs whose type describes another type. static DirectHandle<WasmStruct> AllocateDescriptorUninitialized( Isolate* isolate, DirectHandle<WasmTrustedInstanceData> trusted_data, wasm::ModuleTypeIndex index, DirectHandle<Map> map, DirectHandle<Object> first_field); DECL_ACCESSORS(described_rtt, Tagged<Map>) // The RTT on descriptor structs can have a prototype when exposed to JS. static DirectHandle<JSObject> AllocatePrototype( Isolate* isolate, DirectHandle<JSPrototype> parent); V8_EXPORT_PRIVATE wasm::WasmValue GetFieldValue(uint32_t field_index); inline void SetTaggedFieldValue(int raw_offset, Tagged<Object> value, WriteBarrierMode mode = UPDATE_WRITE_BARRIER); DECL_PRINTER(WasmStruct) class BodyDescriptor; TQ_OBJECT_CONSTRUCTORS(WasmStruct) }; int WasmStruct::Size(const wasm::StructType* type) { // Object size must fit into a Smi (because of filler objects), and its // computation must not overflow. static_assert(Smi::kMaxValue <= kMaxInt); DCHECK_LE(type->total_fields_size(), Smi::kMaxValue - kHeaderSize); return std::max(kHeaderSize + static_cast<int>(type->total_fields_size()), Heap::kMinObjectSizeInTaggedWords * kTaggedSize); } int WasmStruct::Size(const wasm::CanonicalStructType* type) { // Object size must fit into a Smi (because of filler objects), and its // computation must not overflow. static_assert(Smi::kMaxValue <= kMaxInt); DCHECK_LE(type->total_fields_size(), Smi::kMaxValue - kHeaderSize); return std::max(kHeaderSize + static_cast<int>(type->total_fields_size()), Heap::kMinObjectSizeInTaggedWords * kTaggedSize); } class WasmArray : public TorqueGeneratedWasmArray<WasmArray, WasmObject> { public: static inline wasm::CanonicalTypeIndex type_index(Tagged<Map> map); static inline const wasm::CanonicalValueType GcSafeElementType( Tagged<Map> map); // Get the {ObjectSlot} corresponding to the element at {index}. Requires that // this is a reference array. inline ObjectSlot ElementSlot(uint32_t index); V8_EXPORT_PRIVATE wasm::WasmValue GetElement(uint32_t index); static inline int SizeFor(Tagged<Map> map, int length); static constexpr int SizeFor(int element_size, int length); // Returns boxed value of the array's element. static inline DirectHandle<Object> GetElement(Isolate* isolate, DirectHandle<WasmArray> array, uint32_t index); void SetTaggedElement(uint32_t index, DirectHandle<Object> value, WriteBarrierMode mode = UPDATE_WRITE_BARRIER); // Returns the offset/Address of the element at {index}. inline uint32_t element_offset(uint32_t index); inline Address ElementAddress(uint32_t index); static constexpr int MaxLength(uint32_t element_size_bytes) { // The total object size must fit into a Smi, for filler objects. To make // the behavior of Wasm programs independent from the Smi configuration, // we hard-code the smaller of the two supported ranges. return RoundDown( (int{SmiTagging<4>::kSmiMaxValue} - kHeaderSize) / element_size_bytes, kTaggedSize); } static int MaxLength(const wasm::ArrayType* type) { return MaxLength(type->element_type().value_kind_size()); } static inline void EncodeElementSizeInMap(int element_size, Tagged<Map> map); static inline int DecodeElementSizeFromMap(Tagged<Map> map); DECL_PRINTER(WasmArray) class BodyDescriptor; TQ_OBJECT_CONSTRUCTORS(WasmArray) }; // The suspender object provides an API to suspend and resume wasm code using // promises. See: https://github.com/WebAssembly/js-promise-integration. class WasmSuspenderObject : public TorqueGeneratedWasmSuspenderObject<WasmSuspenderObject, ExposedTrustedObject> { public: using BodyDescriptor = StackedBodyDescriptor< FixedExposedTrustedObjectBodyDescriptor<WasmSuspenderObject, kWasmSuspenderIndirectPointerTag>, WithExternalPointer<kStackOffset, kWasmStackMemoryTag>, WithProtectedPointer<kParentOffset>>; enum State : int { kInactive = 0, kActive, kSuspended }; DECL_EXTERNAL_POINTER_ACCESSORS(stack, wasm::StackMemory*) DECL_PROTECTED_POINTER_ACCESSORS(parent, WasmSuspenderObject) DECL_PRINTER(WasmSuspenderObject) TQ_OBJECT_CONSTRUCTORS(WasmSuspenderObject) }; class WasmSuspendingObject : public TorqueGeneratedWasmSuspendingObject<WasmSuspendingObject, JSObject> { public: V8_EXPORT_PRIVATE static DirectHandle<WasmSuspendingObject> New( Isolate* isolate, DirectHandle<JSReceiver> callable); DECL_PRINTER(WasmSuspendingObject) TQ_OBJECT_CONSTRUCTORS(WasmSuspendingObject) }; // The continuation object is a token used during resume & suspend // See: https://github.com/WebAssembly/stack-switching. class WasmContinuationObject : public TorqueGeneratedWasmContinuationObject<WasmContinuationObject, HeapObject> { public: using BodyDescriptor = StackedBodyDescriptor< FixedBodyDescriptorFor<WasmContinuationObject>, WithExternalPointer<kStackOffset, kWasmStackMemoryTag>>; DECL_EXTERNAL_POINTER_ACCESSORS(stack, wasm::StackMemory*) DECL_PRINTER(WasmContinuationObject) TQ_OBJECT_CONSTRUCTORS(WasmContinuationObject) }; class WasmNull : public TorqueGeneratedWasmNull<WasmNull, HeapObject> { public: #if V8_STATIC_ROOTS_BOOL || V8_STATIC_ROOTS_GENERATION_BOOL // TODO(manoskouk): Make it smaller if able and needed. static constexpr int kPayloadSize = 64 * KB; // Payload should be a multiple of page size. static_assert(kPayloadSize % kMinimumOSPageSize == 0); Address payload() { return field_address(kPayloadOffset); } static constexpr int kPayloadOffset = HeapObject::kHeaderSize; static constexpr int kSizeWithPayload = kPayloadOffset + kPayloadSize; static constexpr int kSize = kSizeWithPayload; // Any wasm struct offset should fit in the object. static_assert(kSizeWithPayload >= WasmStruct::kHeaderSize + (wasm::kMaxStructFieldIndexForImplicitNullCheck + 1) * kSimd128Size); #else static constexpr int kSize = HeapObject::kHeaderSize; #endif // WasmNull cannot use `FixedBodyDescriptorFor()` as its map is variable size // (not fixed size) as kSize is too large for a fixed-size map. class BodyDescriptor; TQ_OBJECT_CONSTRUCTORS(WasmNull) }; #undef DECL_OPTIONAL_ACCESSORS // If {opt_native_context} is not null, creates a contextful map bound to // that context; otherwise creates a context-independent map (which must then // not point to any context-specific objects!). DirectHandle<Map> CreateStructMap( Isolate* isolate, wasm::CanonicalTypeIndex type, DirectHandle<Map> opt_rtt_parent, int num_supertypes, DirectHandle<NativeContext> opt_native_context); DirectHandle<Map> CreateArrayMap(Isolate* isolate, wasm::CanonicalTypeIndex array_index, DirectHandle<Map> opt_rtt_parent, int num_supertypes); DirectHandle<Map> CreateFuncRefMap(Isolate* isolate, wasm::CanonicalTypeIndex type, DirectHandle<Map> opt_rtt_parent, int num_supertypes, bool shared); DirectHandle<Map> CreateContRefMap(Isolate* isolate, wasm::CanonicalTypeIndex type); namespace wasm { // Takes a {value} in the JS representation and typechecks it according to // {expected}. If the typecheck succeeds, returns the wasm representation of the // object; otherwise, returns the empty handle. MaybeDirectHandle<Object> JSToWasmObject(Isolate* isolate, DirectHandle<Object> value, CanonicalValueType expected, const char** error_message); // Utility which canonicalizes {expected} in addition. MaybeDirectHandle<Object> JSToWasmObject(Isolate* isolate, const WasmModule* module, DirectHandle<Object> value, ValueType expected, const char** error_message); // Takes a {value} in the Wasm representation and transforms it to the // respective JS representation. The caller is responsible for not providing an // object which cannot be transformed to JS. DirectHandle<Object> WasmToJSObject(Isolate* isolate, DirectHandle<Object> value); } // namespace wasm } // namespace internal } // namespace v8 #include "src/objects/object-macros-undef.h" #endif // V8_WASM_WASM_OBJECTS_H_