#pragma once
#if ENABLE(WEBASSEMBLY)
#include "WasmFormat.h"
#include "WasmMemory.h"
#include "WasmModule.h"
#include "WasmTable.h"
#include <wtf/Optional.h>
#include <wtf/Ref.h>
#include <wtf/RefPtr.h>
#include <wtf/ThreadSafeRefCounted.h>
namespace JSC { namespace Wasm {
struct Context;
class Instance : public ThreadSafeRefCounted<Instance> {
public:
using StoreTopCallFrameCallback = WTF::Function<void(void*)>;
static Ref<Instance> create(Context*, Ref<Module>&&, EntryFrame** pointerToTopEntryFrame, void** pointerToActualStackLimit, StoreTopCallFrameCallback&&);
void finalizeCreation(void* owner, Ref<CodeBlock>&& codeBlock)
{
m_owner = owner;
m_codeBlock = WTFMove(codeBlock);
}
JS_EXPORT_PRIVATE ~Instance();
template<typename T> T* owner() const { return reinterpret_cast<T*>(m_owner); }
static ptrdiff_t offsetOfOwner() { return OBJECT_OFFSETOF(Instance, m_owner); }
size_t extraMemoryAllocated() const;
Wasm::Context* context() const { return m_context; }
Module& module() { return m_module.get(); }
CodeBlock* codeBlock() { return m_codeBlock.get(); }
Memory* memory() { return m_memory.get(); }
Table* table() { return m_table.get(); }
void setMemory(Ref<Memory>&& memory) { m_memory = WTFMove(memory); }
void setTable(Ref<Table>&& table) { m_table = WTFMove(table); }
int32_t loadI32Global(unsigned i) const { return m_globals.get()[i]; }
int64_t loadI64Global(unsigned i) const { return m_globals.get()[i]; }
float loadF32Global(unsigned i) const { return bitwise_cast<float>(loadI32Global(i)); }
double loadF64Global(unsigned i) const { return bitwise_cast<double>(loadI64Global(i)); }
void setGlobal(unsigned i, int64_t bits) { m_globals.get()[i] = bits; }
static ptrdiff_t offsetOfMemory() { return OBJECT_OFFSETOF(Instance, m_memory); }
static ptrdiff_t offsetOfGlobals() { return OBJECT_OFFSETOF(Instance, m_globals); }
static ptrdiff_t offsetOfTable() { return OBJECT_OFFSETOF(Instance, m_table); }
static ptrdiff_t offsetOfPointerToTopEntryFrame() { return OBJECT_OFFSETOF(Instance, m_pointerToTopEntryFrame); }
static ptrdiff_t offsetOfPointerToActualStackLimit() { return OBJECT_OFFSETOF(Instance, m_pointerToActualStackLimit); }
static ptrdiff_t offsetOfCachedStackLimit() { return OBJECT_OFFSETOF(Instance, m_cachedStackLimit); }
void* cachedStackLimit() const
{
ASSERT(*m_pointerToActualStackLimit == m_cachedStackLimit);
return m_cachedStackLimit;
}
void setCachedStackLimit(void* limit)
{
ASSERT(*m_pointerToActualStackLimit == limit || bitwise_cast<void*>(std::numeric_limits<uintptr_t>::max()) == limit);
m_cachedStackLimit = limit;
}
static size_t offsetOfTail() { return WTF::roundUpToMultipleOf<sizeof(uint64_t)>(sizeof(Instance)); }
struct ImportFunctionInfo {
Instance* targetInstance { nullptr };
Wasm::WasmEntrypointLoadLocation wasmEntrypoint { nullptr };
void* wasmToEmbedderStubExecutableAddress { nullptr };
void* importFunction { nullptr }; };
unsigned numImportFunctions() const { return m_numImportFunctions; }
ImportFunctionInfo* importFunctionInfo(size_t importFunctionNum)
{
RELEASE_ASSERT(importFunctionNum < m_numImportFunctions);
return &bitwise_cast<ImportFunctionInfo*>(bitwise_cast<char*>(this) + offsetOfTail())[importFunctionNum];
}
static size_t offsetOfTargetInstance(size_t importFunctionNum) { return offsetOfTail() + importFunctionNum * sizeof(ImportFunctionInfo) + OBJECT_OFFSETOF(ImportFunctionInfo, targetInstance); }
static size_t offsetOfWasmEntrypoint(size_t importFunctionNum) { return offsetOfTail() + importFunctionNum * sizeof(ImportFunctionInfo) + OBJECT_OFFSETOF(ImportFunctionInfo, wasmEntrypoint); }
static size_t offsetOfWasmToEmbedderStubExecutableAddress(size_t importFunctionNum) { return offsetOfTail() + importFunctionNum * sizeof(ImportFunctionInfo) + OBJECT_OFFSETOF(ImportFunctionInfo, wasmToEmbedderStubExecutableAddress); }
static size_t offsetOfImportFunction(size_t importFunctionNum) { return offsetOfTail() + importFunctionNum * sizeof(ImportFunctionInfo) + OBJECT_OFFSETOF(ImportFunctionInfo, importFunction); }
template<typename T> T* importFunction(unsigned importFunctionNum) { return reinterpret_cast<T*>(&importFunctionInfo(importFunctionNum)->importFunction); }
void storeTopCallFrame(void* callFrame)
{
m_storeTopCallFrame(callFrame);
}
private:
Instance(Context*, Ref<Module>&&, EntryFrame**, void**, StoreTopCallFrameCallback&&);
static size_t allocationSize(Checked<size_t> numImportFunctions)
{
return (offsetOfTail() + sizeof(ImportFunctionInfo) * numImportFunctions).unsafeGet();
}
void* m_owner { nullptr }; Context* m_context { nullptr };
Ref<Module> m_module;
RefPtr<CodeBlock> m_codeBlock;
RefPtr<Memory> m_memory;
RefPtr<Table> m_table;
MallocPtr<uint64_t> m_globals;
EntryFrame** m_pointerToTopEntryFrame { nullptr };
void** m_pointerToActualStackLimit { nullptr };
void* m_cachedStackLimit { bitwise_cast<void*>(std::numeric_limits<uintptr_t>::max()) };
StoreTopCallFrameCallback m_storeTopCallFrame;
unsigned m_numImportFunctions { 0 };
};
} }
#endif // ENABLE(WEBASSEMBLY)