18static
void add_wasm_dsl_args()
22#if !defined(NDEBUG) && defined(M_ENABLE_SANITY_FIELDS)
27 "--insist-no-ternary-logic",
28 "insist that there is no ternary logic, i.e. NULL value computation",
29 [](
bool){ dsl_options::insist_no_ternary_logic =
true; }
41#define CASE(TYPE, BLOCK) \
42 case ::wasm::Expression::TYPE##Id: { \
44 auto *expr = static_cast<const ::wasm::TYPE*>(_expr); \
55 M_insist(
expr->value.type == ::wasm::Type::i32,
"invalid boolean expression");
59 if (
expr->op == ::wasm::UnaryOp::EqZInt32) {
71 if (
expr->op == ::wasm::BinaryOp::AndInt32) {
86 }
else if (
expr->op == ::wasm::BinaryOp::OrInt32) {
126 : memory_(memory), imports_(std::move(imports))
129 void importGlobals(::wasm::GlobalValueSet &globals, ::wasm::Module&)
override {
130 M_insist(globals.empty(),
"globals can only be imported once");
131 globals = std::move(imports_);
133 ::wasm::Literals
callImport(::wasm::Function *f, ::wasm::Literals &
args)
override {
135 return it->second(
args);
144 ::wasm::ModuleRunner&)
override {
M_unreachable(
"not supported"); }
147 const ::wasm::Literal&,
149 ::wasm::Index)
override {
M_unreachable(
"not implemented"); }
156 template<
typename T =
void>
158 M_insist(addr.addr < memory_.
size(),
"invalid address");
159 M_insist(addr.addr %
alignof(
T) == 0,
"misaligned address");
160 return *
reinterpret_cast<T*
>(
reinterpret_cast<uint8_t*
>(memory_.
addr()) + addr.addr);
163 std::array<uint8_t, 16> _load<std::array<uint8_t, 16>>(::wasm::Address _addr) {
164 M_insist(_addr.addr + 16 <= memory_.
size(),
"invalid address");
165 auto addr =
reinterpret_cast<uint8_t*
>(memory_.
addr()) + _addr.addr;
166 return std::to_array<uint8_t, 16>(*
reinterpret_cast<uint8_t(*)[16]
>(addr));
168 template<
typename T =
void>
170 M_insist(addr.addr < memory_.
size(),
"invalid address");
171 M_insist(addr.addr %
alignof(
T) == 0,
"misaligned address");
172 *
reinterpret_cast<T*
>(
reinterpret_cast<uint8_t*
>(memory_.
addr()) + addr.addr) =
value;
175 void _store<const std::array<uint8_t, 16>&>(::wasm::Address addr,
const std::array<uint8_t, 16> &
value) {
176 M_insist(addr.addr + 16 <= memory_.
size(),
"invalid address");
177 for (uint32_t idx = 0; idx < 16; ++idx)
178 *(
reinterpret_cast<uint8_t*
>(memory_.
addr()) + addr.addr + idx) =
value[idx];
182#define DECLARE_LOAD(BINARYEN_TYPE, C_TYPE) \
183 C_TYPE load##BINARYEN_TYPE(::wasm::Address addr, ::wasm::Name) override { \
184 return _load<C_TYPE>(addr); \
197#define DECLARE_STORE(BINARYEN_TYPE, C_TYPE) \
198 void store##BINARYEN_TYPE(::wasm::Address addr, C_TYPE value, ::wasm::Name) override { \
199 return _store<C_TYPE>(addr, value); \
223 bool pre_allocations_performed_ =
false;
229 uint32_t pre_alloc_total_mem_ = 0;
238 , pre_alloc_addr_(start_addr)
240 M_insist(start_addr != 0,
"memory address 0 is reserved as `nullptr`");
241#ifdef M_ENABLE_SANITY_FIELDS
242 alloc_addr_.val().discard();
243 alloc_total_mem_.val().discard();
244 alloc_peak_mem_.val().discard();
249 M_insist(pre_allocations_performed_,
"must call `perform_pre_allocations()` before destruction");
253 M_insist(not pre_allocations_performed_,
254 "must not request a pre-allocation after `perform_pre_allocations()` was already called");
258 align_pre_memory(alignment);
259 void *ptr =
static_cast<uint8_t*
>(memory_.
addr()) + pre_alloc_addr_;
260 pre_alloc_addr_ += bytes;
261 pre_alloc_total_mem_ += bytes;
262 M_insist(memory_.
size() >= pre_alloc_addr_,
"allocation must fit in memory");
266 M_insist(not pre_allocations_performed_,
267 "must not request a pre-allocation after `perform_pre_allocations()` was already called");
271 align_pre_memory(alignment);
272 Ptr<void> ptr(U32x1(pre_alloc_addr_).
template to<void*>());
273 pre_alloc_addr_ += bytes;
274 pre_alloc_total_mem_ += bytes;
275 M_insist(memory_.
size() >= pre_alloc_addr_,
"allocation must fit in memory");
282 align_memory(alignment);
284 alloc_addr_ += bytes.clone();
285 alloc_total_mem_ += bytes;
286 alloc_peak_mem_ =
Select(alloc_peak_mem_ > alloc_addr_, alloc_peak_mem_, alloc_addr_);
287 Wasm_insist(memory_.
size() >= alloc_addr_,
"allocation must fit in memory");
292 Wasm_insist(ptr.clone().template to<uint32_t>() < alloc_addr_,
"must not try to free unallocated memory");
293 IF (ptr.template to<uint32_t>() + bytes.clone() == alloc_addr_) {
294 alloc_addr_ -= bytes;
299 M_insist(not pre_allocations_performed_,
300 "must not call `perform_pre_allocations()` multiple times");
301 alloc_addr_.init(
Module::Get().get_global<uint32_t>(
"alloc_addr_init"));
302 pre_allocations_performed_ =
true;
303 return pre_alloc_addr_;
314 pre_alloc_addr_ = (pre_alloc_addr_ + (alignment - 1U)) bitand ~(alignment - 1U);
319 alloc_addr_ = (alloc_addr_ + (alignment - 1U)) bitand ~(alignment - 1U);
331 : id_(NEXT_MODULE_ID_.fetch_add(1U,
std::memory_order_relaxed))
336 emit_function_import<void(uint64_t)>(
"insist");
337 emit_function_import<void(uint64_t, uint64_t)>(
"throw");
340 ::wasm::Name memory_name = std::to_string(
id_);
342 auto mem = std::make_unique<::wasm::Memory>();
343 mem->name = memory_name;
344 module_.addMemory(std::move(mem));
352 builder_.makeExport(
"memory",
memory_->name, ::wasm::ExternalKind::Memory)
356 module_.features.setBulkMemory(
true);
357 module_.features.setSIMD(
true);
369 ::wasm::WasmValidator::Flags flags(0);
370 if (not verbose) flags |= ::wasm::WasmValidator::Quiet;
371 if (global) flags |= ::wasm::WasmValidator::Globally;
372 return ::wasm::WasmValidator{}.validate(
Get().
module_, flags);
378 options.optimizeLevel = optimization_level;
381 runner.addDefaultOptimizationPasses();
387 ::wasm::BufferWithRandomAccess buffer;
388 ::wasm::WasmBinaryWriter writer(&
module_, buffer);
389 writer.setNamesSection(
false);
391 void *
binary = malloc(buffer.size());
392 std::copy_n(buffer.begin(), buffer.size(),
static_cast<char*
>(
binary));
393 return std::make_pair(
reinterpret_cast<uint8_t*
>(
binary), buffer.size());
396template<std::
size_t L>
412 static thread_local struct {} _;
416 std::optional<
FunctionProxy<void(uint64_t)>> delegate_insist;
420 auto &d = add_garbage_collected_data<data_t>(&_);
422 if (not d.delegate_insist) {
424 FUNCTION(delegate_insist,
void(uint64_t))
426 emit_call<void>(
"insist",
PARAMETER(0).val());
428 d.delegate_insist = std::move(delegate_insist);
432 messages_.emplace_back(filename, line, msg);
437 (*d.delegate_insist)(idx);
444 messages_.emplace_back(filename, line, msg);
445 std::vector<::wasm::Expression*>
args = {
446 builder_.makeConst(::wasm::Literal(type)),
447 builder_.makeConst(::wasm::Literal(idx))
458 if (branch_targets.condition) {
490 if (not
Get().
vm_) [[unlikely]] {
494 Get().
vm_ = std::make_unique<std::pair<memory::AddressSpace, memory::Memory>>(std::move(vm), std::move(mem));
519 auto idx =
args[0].getUnsigned();
523 std::cerr << filename <<
':' << line <<
": Wasm_insist failed.";
525 std::cerr <<
" " << msg <<
'.';
526 std::cerr << std::endl;
535 auto idx =
args[1].getUnsigned();
538 std::ostringstream oss;
539 oss << filename <<
':' << line <<
": Exception `" <<
exception::names_[type] <<
"` thrown.";
541 oss <<
" " << msg <<
'.';
571 auto cond =
cond_.expr();
579 Else ? &else_block.
get() :
nullptr
__attribute__((constructor(202))) static void register_interpreter()
#define CASE(TYPE, BLOCK)
#define DECLARE_LOAD(BINARYEN_TYPE, C_TYPE)
#define DECLARE_STORE(BINARYEN_TYPE, C_TYPE)
#define FUNCTION(NAME, TYPE)
void add(const char *group_name, const char *short_name, const char *long_name, const char *description, Callback &&callback)
Adds a new group option to the ArgParser.
#define M_unreachable(MSG)
typename detail::var_helper< T >::type Var
Local variable.
::wasm::Literals insist_interpreter(::wasm::Literals &args)
Reports a runtime error.
typename detail::global_helper< T >::type Global
Global variable.
auto Select(C &&_cond, T &&_tru, U &&_fals)
::wasm::Literals throw_interpreter(::wasm::Literals &args)
Throws an exception.
void CONTINUE(std::size_t level=1)
const std::map<::wasm::Name, std::function<::wasm::Literals(::wasm::Literals &)> > callback_functions
void BREAK(std::size_t level=1)
M_EXPORT constexpr bool is_pow_2(T n)
command-line options for the HeuristicSearchPlanEnumerator
A simple linear allocator which keeps a global pointer to the next free memory address and advances i...
void align_pre_memory(uint32_t alignment)
Aligns the memory for pre-allocations with alignment requirement align.
Ptr< void > pre_allocate(uint32_t bytes, uint32_t alignment) override
Pre-allocates memory for bytes consecutive bytes with alignment requirement align and returns a point...
uint32_t pre_allocated_memory_consumption() const override
Returns the pre-allocated memory overall consumption.
uint32_t perform_pre_allocations() override
Performs the actual pre-allocations.
Var< Ptr< void > > allocate(U32x1 bytes, uint32_t alignment) override
Allocates memory for bytes consecutive bytes with alignment requirement align and returns a pointer t...
LinearAllocator(const memory::AddressSpace &memory, uint32_t start_addr)
uint32_t pre_alloc_addr_
compile-time size of the currently used memory, used as pointer to next free pre-allocation
void align_memory(uint32_t alignment)
Aligns the memory for allocations with alignment requirement align.
Global< U32x1 > alloc_total_mem_
runtime total memory consumption
U32x1 allocated_memory_peak() const override
Returns the allocated memory peak consumption.
U32x1 allocated_memory_consumption() const override
Returns the allocated memory overall consumption.
void deallocate(Ptr< void > ptr, U32x1 bytes) override
Deallocates the bytes consecutive bytes of allocated memory at address ptr.
Global< U32x1 > alloc_peak_mem_
runtime peak memory consumption
Global< U32x1 > alloc_addr_
runtime global size of the currently used memory, used as pointer to next free allocation
const memory::AddressSpace & memory_
the underlying virtual address space used
void * raw_allocate(uint32_t bytes, uint32_t alignment) override
Pre-allocates memory for bytes consecutive bytes with alignment requirement align and returns a raw p...
bool growTable(::wasm::Name, const ::wasm::Literal &, ::wasm::Index, ::wasm::Index) override
DECLARE_LOAD(8s, int8_t) DECLARE_LOAD(8u
void importGlobals(::wasm::GlobalValueSet &globals, ::wasm::Module &) override
::wasm::Literals callImport(::wasm::Function *f, ::wasm::Literals &args) override
void throwException(const ::wasm::WasmException &) override
::wasm::Literals callTable(::wasm::Name, ::wasm::Index, ::wasm::HeapType, ::wasm::Literals &, ::wasm::Type, ::wasm::ModuleRunner &) override
bool growMemory(::wasm::Name, ::wasm::Address, ::wasm::Address) override
void hostLimit(const char *) override
const memory::AddressSpace & memory_
the underlying virtual address space used
void _store(::wasm::Address addr, T value)
::wasm::Index tableSize(::wasm::Name) override
MockInterface(const memory::AddressSpace &memory, ::wasm::GlobalValueSet imports={})
::wasm::GlobalValueSet imports_
the given imports
void trap(const char *) override
T _load(::wasm::Address addr)
The catalog contains all Databases and keeps track of all meta information of the database system.
memory::Allocator & allocator()
Returns a reference to the memory::Allocator.
static Catalog & Get()
Return a reference to the single Catalog instance.
m::ArgParser & arg_parser()
memory::AddressSpace vm
WebAssembly module instance's virtual address space aka. linear memory
static bool Has_Wasm_Context(unsigned id)
Tests if the WasmContext with ID id exists.
static constexpr std::size_t WASM_PAGE_SIZE
the size of a WebAssembly memory page, 64 KiB.
static WasmContext & Get_Wasm_Context_By_ID(unsigned id)
Returns a reference to the WasmContext with ID id.
static constexpr std::size_t WASM_MAX_MEMORY
The maximum memory of a WebAssembly module: 2^32 - 2^16 bytes ≈ 4 GiB.
This class represents a reserved address space in virtual memory.
void * addr() const
Returns a pointer to the beginning of the virtual address space.
std::size_t size() const
Returns the size in bytes of the virtual address space.
virtual Memory allocate(std::size_t size)=0
Creates a new memory object with size bytes of freshly allocated memory.
void map(std::size_t size, std::size_t offset_src, const AddressSpace &vm, std::size_t offset_dst) const
Map size bytes starting at offset_src into the address space of vm at offset offset_dst.
Represents a code block, i.e.
::wasm::Block & get() const
static boolean_result_t EvalBoolean(const ::wasm::Expression *expr)
Tries to evaluate the given boolean expression expr using constant folding.
A handle to create a Function and to create invocations of that function.
Helper struct for garbage collection done by the Module.
PrimitiveExpr< bool, 1 > cond_
::wasm::Builder & Builder()
Returns the expression builder of the current module.
std::unique_ptr<::wasm::ModuleRunner::ExternalInterface > interface_
this module's interface, if any
std::vector< branch_target_t > branch_target_stack_
stack of Binaryen branch targets
::wasm::Block * active_block_
the currently active Binaryen block
std::unique_ptr< std::pair< memory::AddressSpace, memory::Memory > > vm_
the virtual address space and its backed memory; only set if no WasmContext was created
void emit_throw(exception::exception_t type, const char *filename, unsigned line, const char *msg)
static thread_local std::unique_ptr< Module > the_module_
void emit_insist(PrimitiveExpr< bool, L > cond, const char *filename, unsigned line, const char *msg)
static memory::AddressSpace & Memory()
Returns the virtual address space.
void emit_continue(std::size_t level=1)
Emit an unconditional continue, continuing level levels above.
unsigned id_
the unique ID for this Module
::wasm::ModuleRunner::ExternalInterface * get_mock_interface(::wasm::GlobalValueSet imports={})
static bool Validate(bool verbose=true, bool global=true)
Validates that the module is well-formed.
static unsigned ID()
Returns the ID of the current module.
static void Optimize(int optimization_level)
Optimizes the module with the optimization level set to level.
::wasm::Memory * memory_
the main memory of the module
std::vector< std::tuple< const char *, unsigned, const char * > > messages_
filename, line, and an optional message for each emitted insist or exception throw
std::unique_ptr< Allocator > allocator_
the allocator
::wasm::Module module_
the Binaryen Wasm module
::wasm::Builder builder_
the Binaryen expression builder for the module_
const std::tuple< const char *, unsigned, const char * > & get_message(std::size_t idx) const
std::pair< uint8_t *, std::size_t > binary()
Returns the binary representation of module_ in a freshly allocated memory.
std::unique_ptr< DoWhile > do_while_
PrimitiveExpr< bool, 1 > cond_
static constexpr const char *const names_[]
Helper type to deduce the Expr<U> type given a.