mutable
A Database System for Research and Fast Prototyping
Loading...
Searching...
No Matches
WasmDSL.cpp
Go to the documentation of this file.
1#include "backend/WasmDSL.hpp"
2
6#ifdef __BMI2__
7#include <immintrin.h>
8#endif
9
10
11using namespace m;
12using namespace m::wasm;
13
14
15namespace {
16
17__attribute__((constructor(201)))
18static void add_wasm_dsl_args()
19{
20 Catalog &C = Catalog::Get();
21
22#if !defined(NDEBUG) && defined(M_ENABLE_SANITY_FIELDS)
23 /*----- Command-line arguments -----*/
24 C.arg_parser().add<bool>(
25 /* group= */ "Wasm",
26 /* short= */ nullptr,
27 /* long= */ "--insist-no-ternary-logic",
28 /* description= */ "insist that there is no ternary logic, i.e. NULL value computation",
29 /* callback= */ [](bool){ dsl_options::insist_no_ternary_logic = true; }
30 );
31#endif
32}
33
34}
35
36
37/*======================================================================================================================
38 * ConstantFolding
39 *====================================================================================================================*/
40
41#define CASE(TYPE, BLOCK) \
42 case ::wasm::Expression::TYPE##Id: { \
43 auto _expr = expr; \
44 auto *expr = static_cast<const ::wasm::TYPE*>(_expr); \
45 BLOCK \
46 break; \
47 }
48
50{
51 switch (expr->_id) {
52 default:
53 break;
54 CASE(Const, {
55 M_insist(expr->value.type == ::wasm::Type::i32, "invalid boolean expression");
56 return expr->value.geti32() ? TRUE : FALSE;
57 })
58 CASE(Unary, {
59 if (expr->op == ::wasm::UnaryOp::EqZInt32) { // negation
60 switch (EvalBoolean(expr->value)) {
61 case UNDEF:
62 return UNDEF;
63 case TRUE:
64 return FALSE;
65 case FALSE:
66 return TRUE;
67 }
68 }
69 })
70 CASE(Binary, {
71 if (expr->op == ::wasm::BinaryOp::AndInt32) { // conjunction
72 switch (EvalBoolean(expr->left)) {
73 case UNDEF:
74 switch (EvalBoolean(expr->right)) {
75 case UNDEF:
76 case TRUE:
77 return UNDEF;
78 case FALSE: // dominating element
79 return FALSE;
80 }
81 case TRUE: // neutral element
82 return EvalBoolean(expr->right);
83 case FALSE: // dominating element
84 return FALSE;
85 }
86 } else if (expr->op == ::wasm::BinaryOp::OrInt32) { // disjunction
87 switch (EvalBoolean(expr->left)) {
88 case UNDEF:
89 switch (EvalBoolean(expr->right)) {
90 case UNDEF:
91 case FALSE:
92 return UNDEF;
93 case TRUE: // dominating element
94 return TRUE;
95 }
96 case TRUE: // dominating element
97 return TRUE;
98 case FALSE: // neutral element
99 return EvalBoolean(expr->right);
100 }
101 }
102 })
103 }
104 return UNDEF;
105}
106
107#undef CASE
108
109
110/*======================================================================================================================
111 * MockInterface
112 *====================================================================================================================*/
113
115{
117
118 private:
122 ::wasm::GlobalValueSet imports_;
123
124 public:
125 MockInterface(const memory::AddressSpace &memory, ::wasm::GlobalValueSet imports = {})
126 : memory_(memory), imports_(std::move(imports))
127 { }
128
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_);
132 }
133 ::wasm::Literals callImport(::wasm::Function *f, ::wasm::Literals &args) override {
134 if (auto it = callback_functions.find(f->name); it != callback_functions.end())
135 return it->second(args);
136 else
137 M_unreachable("callback function not found");
138 }
139 ::wasm::Literals callTable(::wasm::Name,
140 ::wasm::Index,
141 ::wasm::HeapType,
142 ::wasm::Literals&,
143 ::wasm::Type,
144 ::wasm::ModuleRunner&) override { M_unreachable("not supported"); }
145 bool growMemory(::wasm::Name, ::wasm::Address, ::wasm::Address) override { M_unreachable("not supported"); }
146 bool growTable(::wasm::Name,
147 const ::wasm::Literal&,
148 ::wasm::Index,
149 ::wasm::Index) override { M_unreachable("not implemented"); }
150 ::wasm::Index tableSize(::wasm::Name) override { M_unreachable("not implemented"); }
151 void trap(const char*) override { M_unreachable("not supported"); }
152 void hostLimit(const char*) override { M_unreachable("not supported"); }
153 void throwException(const ::wasm::WasmException&) override { M_unreachable("not supported"); }
154
155 private:
156 template<typename T = void>
157 T _load(::wasm::Address addr) {
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);
161 }
162 template<>
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));
167 }
168 template<typename T = void>
169 void _store(::wasm::Address addr, T value) {
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;
173 }
174 template<>
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];
179 }
180
181 public:
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); \
185 }
186 DECLARE_LOAD(8s, int8_t)
187 DECLARE_LOAD(8u, uint8_t)
188 DECLARE_LOAD(16s, int16_t)
189 DECLARE_LOAD(16u, uint16_t)
190 DECLARE_LOAD(32s, int32_t)
191 DECLARE_LOAD(32u, uint32_t)
192 DECLARE_LOAD(64s, int64_t)
193 DECLARE_LOAD(64u, uint64_t)
194 DECLARE_LOAD(128, std::array<M_COMMA(uint8_t) 16>)
195#undef DECLARE_LOAD
196
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); \
200 }
201 DECLARE_STORE(8, int8_t)
202 DECLARE_STORE(16, int16_t)
203 DECLARE_STORE(32, int32_t)
204 DECLARE_STORE(64, int64_t)
205 DECLARE_STORE(128, const std::array<M_COMMA(uint8_t) 16>&)
206#undef DECLARE_STORE
207};
208
209
210/*======================================================================================================================
211 * LinearAllocator
212 *====================================================================================================================*/
213
218{
219 private:
223 bool pre_allocations_performed_ = false;
229 uint64_t pre_alloc_total_mem_ = 0;
234
235 public:
236 LinearAllocator(const memory::AddressSpace &memory, uint64_t start_addr)
237 : memory_(memory)
238 , pre_alloc_addr_(start_addr)
239 {
240 M_insist(start_addr != 0, "memory address 0 is reserved as `nullptr`");
241#ifdef M_ENABLE_SANITY_FIELDS
242 alloc_addr_.val().discard(); // artificial use of `alloc_addr_` to silence diagnostics if allocator is not used
243 alloc_total_mem_.val().discard(); // artificial use of `alloc_total_mem_` to silence diagnostics if allocator is not used
244 alloc_peak_mem_.val().discard(); // artificial use of `alloc_peak_mem_` to silence diagnostics if allocator is not used
245#endif
246 }
247
249 M_insist(pre_allocations_performed_, "must call `perform_pre_allocations()` before destruction");
250 }
251
252 void * raw_allocate(uint64_t bytes, uint32_t alignment) override {
253 M_insist(not pre_allocations_performed_,
254 "must not request a pre-allocation after `perform_pre_allocations()` was already called");
255 M_insist(alignment);
256 M_insist(is_pow_2(alignment), "alignment must be a power of 2");
257 if (alignment != 1U)
258 align_pre_memory(alignment);
259 void *ptr = static_cast<uint8_t*>(memory_.addr()) + pre_alloc_addr_;
260 pre_alloc_addr_ += bytes; // advance memory size by bytes
261 pre_alloc_total_mem_ += bytes;
262 if (memory_.size() < pre_alloc_addr_)
263 throw m::runtime_error("allocation must fit in memory");
264 return ptr;
265 }
266 Ptr<void> pre_allocate(uint64_t bytes, uint32_t alignment) override {
267 M_insist(not pre_allocations_performed_,
268 "must not request a pre-allocation after `perform_pre_allocations()` was already called");
269 M_insist(alignment);
270 M_insist(is_pow_2(alignment), "alignment must be a power of 2");
271 if (alignment != 1U)
272 align_pre_memory(alignment);
273 Ptr<void> ptr(U64x1(pre_alloc_addr_).template to<void*>());
274 pre_alloc_addr_ += bytes; // advance memory size by bytes
275 pre_alloc_total_mem_ += bytes;
276 if (memory_.size() < pre_alloc_addr_)
277 throw m::runtime_error("allocation must fit in memory");
278 return ptr;
279 }
280 Var<Ptr<void>> allocate(U64x1 bytes, uint32_t alignment) override {
281 M_insist(alignment);
282 M_insist(is_pow_2(alignment), "alignment must be a power of 2");
283 if (alignment != 1U)
284 align_memory(alignment);
285 Var<Ptr<void>> ptr(alloc_addr_.template to<void*>());
286 alloc_addr_ += bytes.clone(); // advance memory size by bytes
287 alloc_total_mem_ += bytes;
288 alloc_peak_mem_ = Select(alloc_peak_mem_ > alloc_addr_, alloc_peak_mem_, alloc_addr_);
289 IF (memory_.size() < alloc_addr_) {
290 Throw(m::wasm::exception::runtime_error, "allocation must fit in memory");
291 };
292 return ptr;
293 }
294
295 void deallocate(Ptr<void> ptr, U64x1 bytes) override {
296 Wasm_insist(ptr.clone().template to<uint64_t>() < alloc_addr_, "must not try to free unallocated memory");
297 IF (ptr.template to<uint64_t>() + bytes.clone() == alloc_addr_) { // last allocation can be freed
298 alloc_addr_ -= bytes; // free by decreasing memory size
299 };
300 }
301
302 uint64_t perform_pre_allocations() override {
303 M_insist(not pre_allocations_performed_,
304 "must not call `perform_pre_allocations()` multiple times");
305 alloc_addr_.init(Module::Get().get_global<uint64_t>("alloc_addr_init"));
306 pre_allocations_performed_ = true;
307 return pre_alloc_addr_;
308 }
309
310 uint64_t pre_allocated_memory_consumption() const override { return pre_alloc_total_mem_; }
311 U64x1 allocated_memory_consumption() const override { return alloc_total_mem_; }
312 U64x1 allocated_memory_peak() const override { return alloc_peak_mem_; }
313
314 private:
316 void align_pre_memory(uint32_t alignment) {
317 M_insist(is_pow_2(alignment));
318 pre_alloc_addr_ = (pre_alloc_addr_ + uint64_t(alignment - 1U)) bitand ~uint64_t(alignment - 1U);
319 }
321 void align_memory(uint32_t alignment) {
322 M_insist(is_pow_2(alignment));
323 alloc_addr_ = (alloc_addr_ + uint64_t(alignment - 1U)) bitand ~uint64_t(alignment - 1U);
324 }
325};
326
327
328/*======================================================================================================================
329 * Module
330 *====================================================================================================================*/
331
332thread_local std::unique_ptr<Module> Module::the_module_;
333
335 : id_(NEXT_MODULE_ID_.fetch_add(1U, std::memory_order_relaxed))
336 , module_()
337 , builder_(module_)
338{
339 /*----- Import functions from the environment. -----*/
340 emit_function_import<void(uint64_t)>("insist"); // to implement insist at Wasm site
341 emit_function_import<void(uint64_t, uint64_t)>("throw"); // to throw exceptions from Wasm site
342
343 /*----- Create module memory. -----*/
344 ::wasm::Name memory_name = std::to_string(id_);
345 {
346 auto mem = std::make_unique<::wasm::Memory>();
347 mem->name = memory_name;
348 module_.addMemory(std::move(mem));
349 }
350
351 /*----- Export the Wasm linear memory, s.t. it can be accessed from the environment (JavaScript). -----*/
352 memory_ = module_.getMemory(memory_name);
353 memory_->initial = 1; // otherwise the Binaryen interpreter traps
355 memory_->indexType = ::wasm::Type::i64;
356 module_.exports.emplace_back(
357 builder_.makeExport("memory", memory_->name, ::wasm::ExternalKind::Memory)
358 );
359
360 /*----- Set features. -----*/
361 module_.features.setBulkMemory(true);
362 module_.features.setMemory64(true);
363 module_.features.setSIMD(true);
364}
365
367{
368 if (not interface_) [[unlikely]]
369 interface_ = std::make_unique<MockInterface>(Memory(), std::move(imports));
370 return interface_.get();
371}
372
373bool Module::Validate(bool verbose, bool global)
374{
375 ::wasm::WasmValidator::Flags flags(0);
376 if (not verbose) flags |= ::wasm::WasmValidator::Quiet;
377 if (global) flags |= ::wasm::WasmValidator::Globally;
378 return ::wasm::WasmValidator{}.validate(Get().module_, flags);
379}
380
381void Module::Optimize(int optimization_level)
382{
383 ::wasm::PassOptions options;
384 options.optimizeLevel = optimization_level;
385 options.shrinkLevel = 0; // shrinking not required
386 ::wasm::PassRunner runner(&Get().module_, options);
387 runner.addDefaultOptimizationPasses();
388 runner.run();
389}
390
391std::pair<uint8_t*, std::size_t> Module::binary()
392{
393 ::wasm::BufferWithRandomAccess buffer;
394 ::wasm::WasmBinaryWriter writer(&module_, buffer);
395 writer.setNamesSection(false);
396 writer.write();
397 void *binary = malloc(buffer.size());
398 std::copy_n(buffer.begin(), buffer.size(), static_cast<char*>(binary));
399 return std::make_pair(reinterpret_cast<uint8_t*>(binary), buffer.size());
400}
401
402template<std::size_t L>
403void Module::emit_insist(PrimitiveExpr<bool, L> cond, const char *filename, unsigned line, const char *msg)
404{
405 emit_insist(cond.all_true(), filename, line, msg);
406}
407
408// explicit instantiations to prevent linker errors
409template void Module::emit_insist(PrimitiveExpr<bool, 2>, const char*, unsigned, const char*);
410template void Module::emit_insist(PrimitiveExpr<bool, 4>, const char*, unsigned, const char*);
411template void Module::emit_insist(PrimitiveExpr<bool, 8>, const char*, unsigned, const char*);
412template void Module::emit_insist(PrimitiveExpr<bool, 16>, const char*, unsigned, const char*);
413template void Module::emit_insist(PrimitiveExpr<bool, 32>, const char*, unsigned, const char*);
414
415template<>
416void Module::emit_insist(PrimitiveExpr<bool, 1> cond, const char *filename, unsigned line, const char *msg)
417{
418 static thread_local struct {} _; // unique caller handle
419 struct data_t : GarbageCollectedData
420 {
421 public:
422 std::optional<FunctionProxy<void(uint64_t)>> delegate_insist;
423
424 data_t(GarbageCollectedData &&d) : GarbageCollectedData(std::move(d)) { }
425 };
426 auto &d = add_garbage_collected_data<data_t>(&_); // garbage collect the `data_t` instance
427
428 if (not d.delegate_insist) {
429 /*----- Create function to delegate to host (used for easier debugging since one can break in here). -----*/
430 FUNCTION(delegate_insist, void(uint64_t))
431 {
432 emit_call<void>("insist", PARAMETER(0).val());
433 }
434 d.delegate_insist = std::move(delegate_insist);
435 }
436
437 uint64_t idx = messages_.size();
438 messages_.emplace_back(filename, line, msg);
439
440 /*----- Check condition and possibly delegate to host. --*/
441 M_insist(bool(d.delegate_insist));
442 IF (not cond) {
443 (*d.delegate_insist)(idx);
444 };
445}
446
447void Module::emit_throw(exception::exception_t type, const char *filename, unsigned line, const char *msg)
448{
449 uint64_t idx = messages_.size();
450 messages_.emplace_back(filename, line, msg);
451 std::vector<::wasm::Expression*> args = {
452 builder_.makeConst(::wasm::Literal(type)), // type id
453 builder_.makeConst(::wasm::Literal(idx)) // message index
454 };
455 active_block_->list.push_back(builder_.makeCall("throw", args, wasm_type<void, 1>()));
456}
457
459void Module::emit_continue(std::size_t level)
460{
461 M_insist(level > 0);
462 M_insist(branch_target_stack_.size() >= level);
463 auto &branch_targets = branch_target_stack_[branch_target_stack_.size() - level];
464 if (branch_targets.condition) {
465 PrimitiveExpr<bool, 1> condition(
466 ::wasm::ExpressionManipulator::copy(branch_targets.condition, Module::Get().module_)
467 );
468 /* Continue if condition is satisfied, break otherwise. */
469 IF (condition) {
470 active_block_->list.push_back(builder_.makeBreak(branch_targets.continu));
471 } ELSE {
472 BREAK();
473 };
474 } else {
475 /* Continue unconditionally. */
476 active_block_->list.push_back(builder_.makeBreak(branch_targets.continu));
477 }
478}
479
483{
484 M_insist(level > 0);
485 M_insist(branch_target_stack_.size() >= level);
486 IF (cond) {
487 emit_continue(level);
488 };
489}
490
492{
495 } else {
496 if (not Get().vm_) [[unlikely]] {
498 auto mem = Catalog::Get().allocator().allocate(vm.size());
499 mem.map(vm.size(), 0, vm, 0); // map backed memory into vm
500 Get().vm_ = std::make_unique<std::pair<memory::AddressSpace, memory::Memory>>(std::move(vm), std::move(mem));
501 }
502 return Get().vm_->first;
503 }
504}
505
507{
508 if (not Get().allocator_) [[unlikely]] {
510 Get().allocator_ = std::make_unique<LinearAllocator>(Memory(), WasmEngine::Get_Wasm_Context_By_ID(ID()).heap);
511 else
512 Get().allocator_ = std::make_unique<LinearAllocator>(Memory(), 1); // reserve address 0 for `nullptr`
513 }
514 return *Get().allocator_;
515}
516
517
518/*======================================================================================================================
519 * Callback functions
520 *====================================================================================================================*/
521
522::wasm::Literals m::wasm::insist_interpreter(::wasm::Literals &args)
523{
524 M_insist(args.size() == 1);
525 auto idx = args[0].getUnsigned();
526 auto [filename, line, msg] = Module::Get().get_message(idx);
527
528 std::cout.flush();
529 std::cerr << filename << ':' << line << ": Wasm_insist failed.";
530 if (msg)
531 std::cerr << " " << msg << '.';
532 std::cerr << std::endl;
533
534 abort();
535}
536
537::wasm::Literals m::wasm::throw_interpreter(::wasm::Literals &args)
538{
539 M_insist(args.size() == 2);
540 auto type = static_cast<exception::exception_t>(args[0].getUnsigned());
541 auto idx = args[1].getUnsigned();
542 auto [filename, line, msg] = Module::Get().get_message(idx);
543
544 std::ostringstream oss;
545 oss << filename << ':' << line << ": Exception `" << exception::names_[type] << "` thrown.";
546 if (*msg)
547 oss << " " << msg << '.';
548 oss << std::endl;
549
550 throw exception(type, oss.str());
551}
552
553
554/*======================================================================================================================
555 * Control flow
556 *====================================================================================================================*/
557
558/*----- If -----------------------------------------------------------------------------------------------------------*/
559
561{
562 M_insist(bool(Then), "If must have a Then");
563
564 Block then_block(name_ + ".then", false);
565 Block else_block(name_ + ".else", false);
566
567 BLOCK_OPEN(then_block) {
568 Then();
569 }
570
571 if (Else) {
572 BLOCK_OPEN(else_block) {
573 Else();
574 }
575 }
576
577 auto cond = cond_.expr();
578 switch (ConstantFolding::EvalBoolean(cond)) {
580 /*----- If -----*/
581 Module::Block().list.push_back(
582 Module::Builder().makeIf(
583 cond,
584 &then_block.get(),
585 Else ? &else_block.get() : nullptr
586 )
587 );
588 break;
590 /*----- Then-block -----*/
591 Module::Block().list.push_back(&then_block.get());
592 break;
594 /*----- Else-block -----*/
595 if (Else)
596 Module::Block().list.push_back(&else_block.get());
597 break;
598 }
599}
600
601/*----- Do-While -----------------------------------------------------------------------------------------------------*/
602
604 BLOCK_OPEN(body()) {
605 CONTINUE(); // emit conditional branch back to loop header at the end of the loop's body
606 }
607}
608
609/*----- While --------------------------------------------------------------------------------------------------------*/
610
612 IF (cond_) {
613 do_while_.reset(); // emit do-while code within IF
614 };
615}
__attribute__((constructor(202))) static void register_interpreter()
#define CASE(TYPE, BLOCK)
Definition: WasmDSL.cpp:41
#define DECLARE_LOAD(BINARYEN_TYPE, C_TYPE)
Definition: WasmDSL.cpp:182
#define DECLARE_STORE(BINARYEN_TYPE, C_TYPE)
#define Wasm_insist(...)
Definition: WasmDSL.hpp:373
#define Throw(...)
Definition: WasmMacro.hpp:48
#define ELSE
Definition: WasmMacro.hpp:24
#define PARAMETER(IDX)
Definition: WasmMacro.hpp:20
#define IF(COND)
Definition: WasmMacro.hpp:23
#define FUNCTION(NAME, TYPE)
Definition: WasmMacro.hpp:17
#define BLOCK_OPEN(BLK)
Definition: WasmMacro.hpp:8
struct @5 args
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.
Definition: ArgParser.hpp:84
#define M_unreachable(MSG)
Definition: macro.hpp:146
#define M_COMMA(X)
Definition: macro.hpp:23
#define M_insist(...)
Definition: macro.hpp:129
typename detail::var_helper< T >::type Var
Local variable.
Definition: WasmDSL.hpp:5780
::wasm::Literals insist_interpreter(::wasm::Literals &args)
Reports a runtime error.
Definition: WasmDSL.cpp:522
typename detail::global_helper< T >::type Global
Global variable.
Definition: WasmDSL.hpp:5790
Bool< L > value
Definition: WasmUtil.hpp:1317
auto Select(C &&_cond, T &&_tru, U &&_fals)
Definition: WasmDSL.hpp:6216
std::size_t bool
Definition: WasmDSL.hpp:528
::wasm::Literals throw_interpreter(::wasm::Literals &args)
Throws an exception.
Definition: WasmDSL.cpp:537
void CONTINUE(std::size_t level=1)
Definition: WasmDSL.hpp:6188
const std::map<::wasm::Name, std::function<::wasm::Literals(::wasm::Literals &)> > callback_functions
Definition: WasmDSL.hpp:588
void BREAK(std::size_t level=1)
Definition: WasmDSL.hpp:6177
‍mutable namespace
Definition: Backend.hpp:10
M_EXPORT constexpr bool is_pow_2(T n)
Definition: fn.hpp:129
T(x)
‍command-line options for the HeuristicSearchPlanEnumerator
Definition: V8Engine.cpp:44
STL namespace.
A simple linear allocator which keeps a global pointer to the next free memory address and advances i...
Definition: WasmDSL.cpp:218
void align_pre_memory(uint32_t alignment)
Aligns the memory for pre-allocations with alignment requirement align.
Definition: WasmDSL.cpp:316
uint64_t pre_allocated_memory_consumption() const override
Returns the pre-allocated memory overall consumption.
Definition: WasmDSL.cpp:310
U64x1 allocated_memory_consumption() const override
Returns the allocated memory overall consumption.
Definition: WasmDSL.cpp:311
uint64_t pre_alloc_addr_
‍compile-time size of the currently used memory, used as pointer to next free pre-allocation
Definition: WasmDSL.cpp:225
U64x1 allocated_memory_peak() const override
Returns the allocated memory peak consumption.
Definition: WasmDSL.cpp:312
uint64_t perform_pre_allocations() override
Performs the actual pre-allocations.
Definition: WasmDSL.cpp:302
LinearAllocator(const memory::AddressSpace &memory, uint64_t start_addr)
Definition: WasmDSL.cpp:236
Global< U64x1 > alloc_total_mem_
‍runtime total memory consumption
Definition: WasmDSL.cpp:231
void * raw_allocate(uint64_t bytes, uint32_t alignment) override
Pre-allocates memory for bytes consecutive bytes with alignment requirement align and returns a raw p...
Definition: WasmDSL.cpp:252
Global< U64x1 > alloc_addr_
‍runtime global size of the currently used memory, used as pointer to next free allocation
Definition: WasmDSL.cpp:227
void deallocate(Ptr< void > ptr, U64x1 bytes) override
Deallocates the bytes consecutive bytes of allocated memory at address ptr.
Definition: WasmDSL.cpp:295
void align_memory(uint32_t alignment)
Aligns the memory for allocations with alignment requirement align.
Definition: WasmDSL.cpp:321
Global< U64x1 > alloc_peak_mem_
‍runtime peak memory consumption
Definition: WasmDSL.cpp:233
Var< Ptr< void > > allocate(U64x1 bytes, uint32_t alignment) override
Allocates memory for bytes consecutive bytes with alignment requirement align and returns a pointer t...
Definition: WasmDSL.cpp:280
Ptr< void > pre_allocate(uint64_t bytes, uint32_t alignment) override
Pre-allocates memory for bytes consecutive bytes with alignment requirement align and returns a point...
Definition: WasmDSL.cpp:266
const memory::AddressSpace & memory_
‍the underlying virtual address space used
Definition: WasmDSL.cpp:221
bool growTable(::wasm::Name, const ::wasm::Literal &, ::wasm::Index, ::wasm::Index) override
Definition: WasmDSL.cpp:146
DECLARE_LOAD(8s, int8_t) DECLARE_LOAD(8u
void importGlobals(::wasm::GlobalValueSet &globals, ::wasm::Module &) override
Definition: WasmDSL.cpp:129
::wasm::Literals callImport(::wasm::Function *f, ::wasm::Literals &args) override
Definition: WasmDSL.cpp:133
void throwException(const ::wasm::WasmException &) override
Definition: WasmDSL.cpp:153
::wasm::Literals callTable(::wasm::Name, ::wasm::Index, ::wasm::HeapType, ::wasm::Literals &, ::wasm::Type, ::wasm::ModuleRunner &) override
Definition: WasmDSL.cpp:139
bool growMemory(::wasm::Name, ::wasm::Address, ::wasm::Address) override
Definition: WasmDSL.cpp:145
void hostLimit(const char *) override
Definition: WasmDSL.cpp:152
const memory::AddressSpace & memory_
‍the underlying virtual address space used
Definition: WasmDSL.cpp:120
void _store(::wasm::Address addr, T value)
Definition: WasmDSL.cpp:169
::wasm::Index tableSize(::wasm::Name) override
Definition: WasmDSL.cpp:150
MockInterface(const memory::AddressSpace &memory, ::wasm::GlobalValueSet imports={})
Definition: WasmDSL.cpp:125
::wasm::GlobalValueSet imports_
‍the given imports
Definition: WasmDSL.cpp:122
void trap(const char *) override
Definition: WasmDSL.cpp:151
T _load(::wasm::Address addr)
Definition: WasmDSL.cpp:157
The catalog contains all Databases and keeps track of all meta information of the database system.
Definition: Catalog.hpp:215
memory::Allocator & allocator()
Returns a reference to the memory::Allocator.
Definition: Catalog.hpp:269
static Catalog & Get()
Return a reference to the single Catalog instance.
m::ArgParser & arg_parser()
Definition: Catalog.hpp:253
memory::AddressSpace vm
WebAssembly module instance's virtual address space aka. linear memory
Definition: WebAssembly.hpp:41
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.
Definition: WebAssembly.hpp:19
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, 16 GiB.
Definition: WebAssembly.hpp:21
This class represents a reserved address space in virtual memory.
Definition: memory.hpp:45
void * addr() const
Returns a pointer to the beginning of the virtual address space.
Definition: memory.hpp:65
std::size_t size() const
Returns the size in bytes of the virtual address space.
Definition: memory.hpp:67
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.
Definition: memory.cpp:85
Signals a runtime error that mu*t*able is not responsible for and that mu*t*able was not able to reco...
Definition: exception.hpp:49
Represents a code block, i.e.
Definition: WasmDSL.hpp:1006
::wasm::Block & get() const
Definition: WasmDSL.hpp:1063
static boolean_result_t EvalBoolean(const ::wasm::Expression *expr)
Tries to evaluate the given boolean expression expr using constant folding.
Definition: WasmDSL.cpp:49
A handle to create a Function and to create invocations of that function.
Definition: WasmDSL.hpp:1368
Helper struct for garbage collection done by the Module.
Definition: WasmDSL.hpp:604
continuation_t Else
Definition: WasmDSL.hpp:6366
std::string name_
Definition: WasmDSL.hpp:6363
PrimitiveExpr< bool, 1 > cond_
Definition: WasmDSL.hpp:6362
continuation_t Then
Definition: WasmDSL.hpp:6366
Block & body()
Definition: WasmDSL.hpp:6427
::wasm::Builder & Builder()
Returns the expression builder of the current module.
Definition: WasmDSL.hpp:740
std::unique_ptr<::wasm::ModuleRunner::ExternalInterface > interface_
‍this module's interface, if any
Definition: WasmDSL.hpp:691
std::vector< branch_target_t > branch_target_stack_
‍stack of Binaryen branch targets
Definition: WasmDSL.hpp:687
::wasm::Block * active_block_
‍the currently active Binaryen block
Definition: WasmDSL.hpp:677
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
Definition: WasmDSL.hpp:683
void emit_throw(exception::exception_t type, const char *filename, unsigned line, const char *msg)
Definition: WasmDSL.cpp:447
static thread_local std::unique_ptr< Module > the_module_
Definition: WasmDSL.hpp:701
void emit_insist(PrimitiveExpr< bool, L > cond, const char *filename, unsigned line, const char *msg)
Definition: WasmDSL.cpp:403
static memory::AddressSpace & Memory()
Returns the virtual address space.
Definition: WasmDSL.cpp:491
void emit_continue(std::size_t level=1)
Emit an unconditional continue, continuing level levels above.
Definition: WasmDSL.cpp:459
static Module & Get()
Definition: WasmDSL.hpp:715
unsigned id_
‍the unique ID for this Module
Definition: WasmDSL.hpp:661
::wasm::ModuleRunner::ExternalInterface * get_mock_interface(::wasm::GlobalValueSet imports={})
Definition: WasmDSL.cpp:366
static bool Validate(bool verbose=true, bool global=true)
Validates that the module is well-formed.
Definition: WasmDSL.cpp:373
friend struct Allocator
Definition: WasmDSL.hpp:653
static unsigned ID()
Returns the ID of the current module.
Definition: WasmDSL.hpp:722
static void Optimize(int optimization_level)
Optimizes the module with the optimization level set to level.
Definition: WasmDSL.cpp:381
::wasm::Memory * memory_
‍the main memory of the module
Definition: WasmDSL.hpp:681
std::vector< std::tuple< const char *, unsigned, const char * > > messages_
‍filename, line, and an optional message for each emitted insist or exception throw
Definition: WasmDSL.hpp:689
std::unique_ptr< Allocator > allocator_
‍the allocator
Definition: WasmDSL.hpp:685
::wasm::Module module_
‍the Binaryen Wasm module
Definition: WasmDSL.hpp:673
friend struct Block
Definition: WasmDSL.hpp:647
::wasm::Builder builder_
‍the Binaryen expression builder for the module_
Definition: WasmDSL.hpp:675
const std::tuple< const char *, unsigned, const char * > & get_message(std::size_t idx) const
Definition: WasmDSL.hpp:908
std::pair< uint8_t *, std::size_t > binary()
Returns the binary representation of module_ in a freshly allocated memory.
Definition: WasmDSL.cpp:391
std::unique_ptr< DoWhile > do_while_
Definition: WasmDSL.hpp:6459
PrimitiveExpr< bool, 1 > cond_
Definition: WasmDSL.hpp:6458
static constexpr const char *const names_[]
Definition: WasmDSL.hpp:563
Helper type to deduce the Expr<U> type given a.
Definition: WasmDSL.hpp:160