// 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_ #include "src/base/bits.h" #include "src/debug/debug.h" #include "src/debug/interface-types.h" #include "src/managed.h" #include "src/objects.h" #include "src/objects/script.h" #include "src/wasm/decoder.h" #include "src/wasm/wasm-interpreter.h" #include "src/wasm/wasm-limits.h" #include "src/wasm/wasm-module.h" #include "src/heap/heap.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 InterpretedFrame; class NativeModule; class WasmCode; struct WasmModule; class SignatureMap; using ValueType = MachineRepresentation; using FunctionSig = Signature; } // namespace wasm class WasmCompiledModule; class WasmDebugInfo; class WasmInstanceObject; #define DECL_OPTIONAL_ACCESSORS(name, type) \ INLINE(bool has_##name()); \ DECL_ACCESSORS(name, type) // An entry in an indirect function table (IFT). // Each entry in the IFT has the following fields: // - instance = target instance // - sig_id = signature id of function // - target = entrypoint to wasm code for the function, or wasm-to-js wrapper class IndirectFunctionTableEntry { public: inline IndirectFunctionTableEntry(WasmInstanceObject*, int index); void clear(); void set(int sig_id, WasmInstanceObject* instance, const wasm::WasmCode* wasm_code); WasmInstanceObject* instance(); int sig_id(); Address target(); private: #ifdef DEBUG DisallowHeapAllocation no_gc; #endif WasmInstanceObject* const instance_; int const index_; }; // An entry for an imported function. // (note this is not called a "table" since it is not dynamically indexed). // The imported function entries are used to call imported functions. // For each imported function there is an entry which is either: // - an imported JSReceiver, which has fields // - instance = importing instance // - receiver = JSReceiver, either a JS function or other callable // - target = pointer to wasm-to-js wrapper code entrypoint // - an imported wasm function from another instance, which has fields // - instance = target instance // - target = entrypoint to wasm code of the function class ImportedFunctionEntry { public: inline ImportedFunctionEntry(WasmInstanceObject*, int index); // Initialize this entry as a {JSReceiver} call. void set(JSReceiver* callable, const wasm::WasmCode* wasm_to_js_wrapper); // Initialize this entry as a WASM to WASM call. void set(WasmInstanceObject* target_instance, const wasm::WasmCode* wasm_function); WasmInstanceObject* instance(); JSReceiver* callable(); Address target(); bool is_js_receiver_entry(); private: #ifdef DEBUG DisallowHeapAllocation no_gc; #endif WasmInstanceObject* const instance_; int const index_; }; // Representation of a WebAssembly.Module JavaScript-level object. class WasmModuleObject : public JSObject { public: DECL_CAST(WasmModuleObject) // Shared compiled code between multiple WebAssembly.Module objects. DECL_ACCESSORS(compiled_module, WasmCompiledModule) // Layout description. #define WASM_MODULE_OBJECT_FIELDS(V) \ V(kCompiledModuleOffset, kPointerSize) \ V(kSize, 0) DEFINE_FIELD_OFFSET_CONSTANTS(JSObject::kHeaderSize, WASM_MODULE_OBJECT_FIELDS) #undef WASM_MODULE_OBJECT_FIELDS static Handle New( Isolate* isolate, Handle compiled_module); static void ValidateStateForTesting(Isolate* isolate, Handle module); }; // Representation of a WebAssembly.Table JavaScript-level object. class WasmTableObject : public JSObject { public: DECL_CAST(WasmTableObject) DECL_ACCESSORS(functions, FixedArray) // TODO(titzer): introduce DECL_I64_ACCESSORS macro DECL_ACCESSORS(maximum_length, Object) DECL_ACCESSORS(dispatch_tables, FixedArray) // Layout description. #define WASM_TABLE_OBJECT_FIELDS(V) \ V(kFunctionsOffset, kPointerSize) \ V(kMaximumLengthOffset, kPointerSize) \ V(kDispatchTablesOffset, kPointerSize) \ V(kSize, 0) DEFINE_FIELD_OFFSET_CONSTANTS(JSObject::kHeaderSize, WASM_TABLE_OBJECT_FIELDS) #undef WASM_TABLE_OBJECT_FIELDS inline uint32_t current_length(); void Grow(Isolate* isolate, uint32_t count); static Handle New(Isolate* isolate, uint32_t initial, int64_t maximum, Handle* js_functions); static void AddDispatchTable(Isolate* isolate, Handle table, Handle instance, int table_index); static void Set(Isolate* isolate, Handle table, int32_t index, Handle function); static void UpdateDispatchTables(Isolate* isolate, Handle table, int table_index, wasm::FunctionSig* sig, Handle from_instance, wasm::WasmCode* wasm_code); static void ClearDispatchTables(Handle table, int index); }; // Representation of a WebAssembly.Memory JavaScript-level object. class WasmMemoryObject : public JSObject { public: DECL_CAST(WasmMemoryObject) DECL_ACCESSORS(array_buffer, JSArrayBuffer) DECL_INT_ACCESSORS(maximum_pages) DECL_OPTIONAL_ACCESSORS(instances, FixedArrayOfWeakCells) // Layout description. #define WASM_MEMORY_OBJECT_FIELDS(V) \ V(kArrayBufferOffset, kPointerSize) \ V(kMaximumPagesOffset, kPointerSize) \ V(kInstancesOffset, kPointerSize) \ V(kSize, 0) DEFINE_FIELD_OFFSET_CONSTANTS(JSObject::kHeaderSize, WASM_MEMORY_OBJECT_FIELDS) #undef WASM_MEMORY_OBJECT_FIELDS // Add an instance to the internal (weak) list. static void AddInstance(Isolate* isolate, Handle memory, Handle object); // Remove an instance from the internal (weak) list. static void RemoveInstance(Isolate* isolate, Handle memory, Handle object); uint32_t current_pages(); inline bool has_maximum_pages(); V8_EXPORT_PRIVATE static Handle New( Isolate* isolate, MaybeHandle buffer, int32_t maximum); static int32_t Grow(Isolate*, Handle, uint32_t pages); }; // Representation of a WebAssembly.Global JavaScript-level object. class WasmGlobalObject : public JSObject { public: DECL_CAST(WasmGlobalObject) DECL_ACCESSORS(array_buffer, JSArrayBuffer) DECL_INT32_ACCESSORS(offset) DECL_INT_ACCESSORS(flags) DECL_PRIMITIVE_ACCESSORS(type, wasm::ValueType) DECL_BOOLEAN_ACCESSORS(is_mutable) #define WASM_GLOBAL_OBJECT_FLAGS_BIT_FIELDS(V, _) \ V(TypeBits, wasm::ValueType, 8, _) \ V(IsMutableBit, bool, 1, _) DEFINE_BIT_FIELDS(WASM_GLOBAL_OBJECT_FLAGS_BIT_FIELDS) #undef WASM_GLOBAL_OBJECT_FLAGS_BIT_FIELDS // Layout description. #define WASM_GLOBAL_OBJECT_FIELDS(V) \ V(kArrayBufferOffset, kPointerSize) \ V(kOffsetOffset, kPointerSize) \ V(kFlagsOffset, kPointerSize) \ V(kSize, 0) DEFINE_FIELD_OFFSET_CONSTANTS(JSObject::kHeaderSize, WASM_GLOBAL_OBJECT_FIELDS) #undef WASM_GLOBAL_OBJECT_FIELDS V8_EXPORT_PRIVATE static MaybeHandle New( Isolate* isolate, MaybeHandle buffer, wasm::ValueType type, int32_t offset, bool is_mutable); static inline uint32_t TypeSize(wasm::ValueType); inline uint32_t type_size() const; inline int32_t GetI32(); inline float GetF32(); inline double GetF64(); inline void SetI32(int32_t value); inline void SetF32(float value); inline void SetF64(double 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; }; // A WebAssembly.Instance JavaScript-level object. class WasmInstanceObject : public JSObject { public: DECL_CAST(WasmInstanceObject) DECL_ACCESSORS(compiled_module, WasmCompiledModule) DECL_ACCESSORS(exports_object, JSObject) DECL_OPTIONAL_ACCESSORS(memory_object, WasmMemoryObject) DECL_OPTIONAL_ACCESSORS(globals_buffer, JSArrayBuffer) DECL_OPTIONAL_ACCESSORS(debug_info, WasmDebugInfo) DECL_OPTIONAL_ACCESSORS(table_object, WasmTableObject) DECL_ACCESSORS(imported_function_instances, FixedArray) DECL_ACCESSORS(imported_function_callables, FixedArray) DECL_OPTIONAL_ACCESSORS(indirect_function_table_instances, FixedArray) DECL_OPTIONAL_ACCESSORS(managed_native_allocations, Foreign) DECL_OPTIONAL_ACCESSORS(managed_indirect_patcher, Foreign) DECL_PRIMITIVE_ACCESSORS(memory_start, byte*) DECL_PRIMITIVE_ACCESSORS(memory_size, uint32_t) DECL_PRIMITIVE_ACCESSORS(memory_mask, uint32_t) DECL_PRIMITIVE_ACCESSORS(imported_function_targets, Address*) DECL_PRIMITIVE_ACCESSORS(globals_start, byte*) DECL_PRIMITIVE_ACCESSORS(indirect_function_table_size, uint32_t) DECL_PRIMITIVE_ACCESSORS(indirect_function_table_sig_ids, uint32_t*) DECL_PRIMITIVE_ACCESSORS(indirect_function_table_targets, Address*) // Layout description. #define WASM_INSTANCE_OBJECT_FIELDS(V) \ V(kCompiledModuleOffset, kPointerSize) \ V(kExportsObjectOffset, kPointerSize) \ V(kMemoryObjectOffset, kPointerSize) \ V(kGlobalsBufferOffset, kPointerSize) \ V(kDebugInfoOffset, kPointerSize) \ V(kTableObjectOffset, kPointerSize) \ V(kFunctionTablesOffset, kPointerSize) \ V(kImportedFunctionInstancesOffset, kPointerSize) \ V(kImportedFunctionCallablesOffset, kPointerSize) \ V(kIndirectFunctionTableInstancesOffset, kPointerSize) \ V(kManagedNativeAllocationsOffset, kPointerSize) \ V(kManagedIndirectPatcherOffset, kPointerSize) \ V(kFirstUntaggedOffset, 0) /* marker */ \ V(kMemoryStartOffset, kPointerSize) /* untagged */ \ V(kMemorySizeOffset, kUInt32Size) /* untagged */ \ V(kMemoryMaskOffset, kUInt32Size) /* untagged */ \ V(kImportedFunctionTargetsOffset, kPointerSize) /* untagged */ \ V(kGlobalsStartOffset, kPointerSize) /* untagged */ \ V(kIndirectFunctionTableSigIdsOffset, kPointerSize) /* untagged */ \ V(kIndirectFunctionTableTargetsOffset, kPointerSize) /* untagged */ \ V(kIndirectFunctionTableSizeOffset, kUInt32Size) /* untagged */ \ V(k64BitArchPaddingOffset, kPointerSize - kUInt32Size) /* padding */ \ V(kSize, 0) DEFINE_FIELD_OFFSET_CONSTANTS(JSObject::kHeaderSize, WASM_INSTANCE_OBJECT_FIELDS) #undef WASM_INSTANCE_OBJECT_FIELDS WasmModuleObject* module_object(); V8_EXPORT_PRIVATE wasm::WasmModule* module(); static bool EnsureIndirectFunctionTableWithMinimumSize( Handle instance, uint32_t minimum_size); bool has_indirect_function_table(); void SetRawMemory(byte* mem_start, uint32_t mem_size); // Get the debug info associated with the given wasm object. // If no debug info exists yet, it is created automatically. static Handle GetOrCreateDebugInfo(Handle); static Handle New(Isolate*, Handle); // Assumed to be called with a code object associated to a wasm module // instance. Intended to be called from runtime functions. Returns nullptr on // failing to get owning instance. static WasmInstanceObject* GetOwningInstance(const wasm::WasmCode* code); static void ValidateInstancesChainForTesting( Isolate* isolate, Handle module_obj, int instance_count); static void ValidateOrphanedInstanceForTesting( Isolate* isolate, Handle instance); static void InstallFinalizer(Isolate* isolate, Handle instance); // Iterates all fields in the object except the untagged fields. class BodyDescriptor; // No weak fields. typedef BodyDescriptor BodyDescriptorWeak; }; // A WASM function that is wrapped and exported to JavaScript. class WasmExportedFunction : public JSFunction { public: WasmInstanceObject* instance(); V8_EXPORT_PRIVATE int function_index(); V8_EXPORT_PRIVATE static WasmExportedFunction* cast(Object* object); static bool IsWasmExportedFunction(Object* object); static Handle New(Isolate* isolate, Handle instance, MaybeHandle maybe_name, int func_index, int arity, Handle export_wrapper); wasm::WasmCode* GetWasmCode(); }; // Information shared by all WasmCompiledModule objects for the same module. class WasmSharedModuleData : public Struct { public: DECL_ACCESSORS(module_wrapper, Object) wasm::WasmModule* module() const; DECL_ACCESSORS(module_bytes, SeqOneByteString) DECL_ACCESSORS(script, Script) DECL_OPTIONAL_ACCESSORS(asm_js_offset_table, ByteArray) DECL_OPTIONAL_ACCESSORS(breakpoint_infos, FixedArray) inline void reset_breakpoint_infos(); DECL_CAST(WasmSharedModuleData) // Dispatched behavior. DECL_PRINTER(WasmSharedModuleData) DECL_VERIFIER(WasmSharedModuleData) // Layout description. #define WASM_SHARED_MODULE_DATA_FIELDS(V) \ V(kModuleWrapperOffset, kPointerSize) \ V(kModuleBytesOffset, kPointerSize) \ V(kScriptOffset, kPointerSize) \ V(kAsmJsOffsetTableOffset, kPointerSize) \ V(kBreakPointInfosOffset, kPointerSize) \ V(kSize, 0) DEFINE_FIELD_OFFSET_CONSTANTS(HeapObject::kHeaderSize, WASM_SHARED_MODULE_DATA_FIELDS) #undef WASM_SHARED_MODULE_DATA_FIELDS // Check whether this module was generated from asm.js source. bool is_asm_js(); static void AddBreakpoint(Handle, int position, Handle break_point); static void SetBreakpointsOnNewInstance(Handle, Handle); static Handle New( Isolate* isolate, Handle module_wrapper, Handle module_bytes, Handle