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 uint32_t pre_alloc_total_mem_ = 0;
234
235 public:
236 LinearAllocator(const memory::AddressSpace &memory, uint32_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(uint32_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(uint32_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(U32x1(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(U32x1 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, U32x1 bytes) override {
296 Wasm_insist(ptr.clone().template to<uint32_t>() < alloc_addr_, "must not try to free unallocated memory");
297 IF (ptr.template to<uint32_t>() + bytes.clone() == alloc_addr_) { // last allocation can be freed
298 alloc_addr_ -= bytes; // free by decreasing memory size
299 };
300 }
301
302 uint32_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<uint32_t>("alloc_addr_init"));
306 pre_allocations_performed_ = true;
307 return pre_alloc_addr_;
308 }
309
310 uint32_t pre_allocated_memory_consumption() const override { return pre_alloc_total_mem_; }
311 U32x1 allocated_memory_consumption() const override { return alloc_total_mem_; }
312 U32x1 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_ + (alignment - 1U)) bitand ~(alignment - 1U);
319 }
321 void align_memory(uint32_t alignment) {
322 M_insist(is_pow_2(alignment));
323 alloc_addr_ = (alloc_addr_ + (alignment - 1U)) bitand ~(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 module_.exports.emplace_back(
356 builder_.makeExport("memory", memory_->name, ::wasm::ExternalKind::Memory)
357 );
358
359 /*----- Set features. -----*/
360 module_.features.setBulkMemory(true);
361 module_.features.setSIMD(true);
362}
363
365{
366 if (not interface_) [[unlikely]]
367 interface_ = std::make_unique<MockInterface>(Memory(), std::move(imports));
368 return interface_.get();
369}
370
371bool Module::Validate(bool verbose, bool global)
372{
373 ::wasm::WasmValidator::Flags flags(0);
374 if (not verbose) flags |= ::wasm::WasmValidator::Quiet;
375 if (global) flags |= ::wasm::WasmValidator::Globally;
376 return ::wasm::WasmValidator{}.validate(Get().module_, flags);
377}
378
379void Module::Optimize(int optimization_level)
380{
381 ::wasm::PassOptions options;
382 options.optimizeLevel = optimization_level;
383 options.shrinkLevel = 0; // shrinking not required
384 ::wasm::PassRunner runner(&Get().module_, options);
385 runner.addDefaultOptimizationPasses();
386 runner.run();
387}
388
389std::pair<uint8_t*, std::size_t> Module::binary()
390{
391 ::wasm::BufferWithRandomAccess buffer;
392 ::wasm::WasmBinaryWriter writer(&module_, buffer);
393 writer.setNamesSection(false);
394 writer.write();
395 void *binary = malloc(buffer.size());
396 std::copy_n(buffer.begin(), buffer.size(), static_cast<char*>(binary));
397 return std::make_pair(reinterpret_cast<uint8_t*>(binary), buffer.size());
398}
399
400template<std::size_t L>
401void Module::emit_insist(PrimitiveExpr<bool, L> cond, const char *filename, unsigned line, const char *msg)
402{
403 emit_insist(cond.all_true(), filename, line, msg);
404}
405
406// explicit instantiations to prevent linker errors
407template void Module::emit_insist(PrimitiveExpr<bool, 2>, const char*, unsigned, const char*);
408template void Module::emit_insist(PrimitiveExpr<bool, 4>, const char*, unsigned, const char*);
409template void Module::emit_insist(PrimitiveExpr<bool, 8>, const char*, unsigned, const char*);
410template void Module::emit_insist(PrimitiveExpr<bool, 16>, const char*, unsigned, const char*);
411template void Module::emit_insist(PrimitiveExpr<bool, 32>, const char*, unsigned, const char*);
412
413template<>
414void Module::emit_insist(PrimitiveExpr<bool, 1> cond, const char *filename, unsigned line, const char *msg)
415{
416 static thread_local struct {} _; // unique caller handle
417 struct data_t : GarbageCollectedData
418 {
419 public:
420 std::optional<FunctionProxy<void(uint64_t)>> delegate_insist;
421
422 data_t(GarbageCollectedData &&d) : GarbageCollectedData(std::move(d)) { }
423 };
424 auto &d = add_garbage_collected_data<data_t>(&_); // garbage collect the `data_t` instance
425
426 if (not d.delegate_insist) {
427 /*----- Create function to delegate to host (used for easier debugging since one can break in here). -----*/
428 FUNCTION(delegate_insist, void(uint64_t))
429 {
430 emit_call<void>("insist", PARAMETER(0).val());
431 }
432 d.delegate_insist = std::move(delegate_insist);
433 }
434
435 uint64_t idx = messages_.size();
436 messages_.emplace_back(filename, line, msg);
437
438 /*----- Check condition and possibly delegate to host. --*/
439 M_insist(bool(d.delegate_insist));
440 IF (not cond) {
441 (*d.delegate_insist)(idx);
442 };
443}
444
445void Module::emit_throw(exception::exception_t type, const char *filename, unsigned line, const char *msg)
446{
447 uint64_t idx = messages_.size();
448 messages_.emplace_back(filename, line, msg);
449 std::vector<::wasm::Expression*> args = {
450 builder_.makeConst(::wasm::Literal(type)), // type id
451 builder_.makeConst(::wasm::Literal(idx)) // message index
452 };
453 active_block_->list.push_back(builder_.makeCall("throw", args, wasm_type<void, 1>()));
454}
455
457void Module::emit_continue(std::size_t level)
458{
459 M_insist(level > 0);
460 M_insist(branch_target_stack_.size() >= level);
461 auto &branch_targets = branch_target_stack_[branch_target_stack_.size() - level];
462 if (branch_targets.condition) {
463 PrimitiveExpr<bool, 1> condition(
464 ::wasm::ExpressionManipulator::copy(branch_targets.condition, Module::Get().module_)
465 );
466 /* Continue if condition is satisfied, break otherwise. */
467 IF (condition) {
468 active_block_->list.push_back(builder_.makeBreak(branch_targets.continu));
469 } ELSE {
470 BREAK();
471 };
472 } else {
473 /* Continue unconditionally. */
474 active_block_->list.push_back(builder_.makeBreak(branch_targets.continu));
475 }
476}
477
481{
482 M_insist(level > 0);
483 M_insist(branch_target_stack_.size() >= level);
484 IF (cond) {
485 emit_continue(level);
486 };
487}
488
490{
493 } else {
494 if (not Get().vm_) [[unlikely]] {
496 auto mem = Catalog::Get().allocator().allocate(vm.size());
497 mem.map(vm.size(), 0, vm, 0); // map backed memory into vm
498 Get().vm_ = std::make_unique<std::pair<memory::AddressSpace, memory::Memory>>(std::move(vm), std::move(mem));
499 }
500 return Get().vm_->first;
501 }
502}
503
505{
506 if (not Get().allocator_) [[unlikely]] {
508 Get().allocator_ = std::make_unique<LinearAllocator>(Memory(), WasmEngine::Get_Wasm_Context_By_ID(ID()).heap);
509 else
510 Get().allocator_ = std::make_unique<LinearAllocator>(Memory(), 1); // reserve address 0 for `nullptr`
511 }
512 return *Get().allocator_;
513}
514
515
516/*======================================================================================================================
517 * Callback functions
518 *====================================================================================================================*/
519
520::wasm::Literals m::wasm::insist_interpreter(::wasm::Literals &args)
521{
522 M_insist(args.size() == 1);
523 auto idx = args[0].getUnsigned();
524 auto [filename, line, msg] = Module::Get().get_message(idx);
525
526 std::cout.flush();
527 std::cerr << filename << ':' << line << ": Wasm_insist failed.";
528 if (msg)
529 std::cerr << " " << msg << '.';
530 std::cerr << std::endl;
531
532 abort();
533}
534
535::wasm::Literals m::wasm::throw_interpreter(::wasm::Literals &args)
536{
537 M_insist(args.size() == 2);
538 auto type = static_cast<exception::exception_t>(args[0].getUnsigned());
539 auto idx = args[1].getUnsigned();
540 auto [filename, line, msg] = Module::Get().get_message(idx);
541
542 std::ostringstream oss;
543 oss << filename << ':' << line << ": Exception `" << exception::names_[type] << "` thrown.";
544 if (*msg)
545 oss << " " << msg << '.';
546 oss << std::endl;
547
548 throw exception(type, oss.str());
549}
550
551
552/*======================================================================================================================
553 * Control flow
554 *====================================================================================================================*/
555
556/*----- If -----------------------------------------------------------------------------------------------------------*/
557
559{
560 M_insist(bool(Then), "If must have a Then");
561
562 Block then_block(name_ + ".then", false);
563 Block else_block(name_ + ".else", false);
564
565 BLOCK_OPEN(then_block) {
566 Then();
567 }
568
569 if (Else) {
570 BLOCK_OPEN(else_block) {
571 Else();
572 }
573 }
574
575 auto cond = cond_.expr();
576 switch (ConstantFolding::EvalBoolean(cond)) {
578 /*----- If -----*/
579 Module::Block().list.push_back(
580 Module::Builder().makeIf(
581 cond,
582 &then_block.get(),
583 Else ? &else_block.get() : nullptr
584 )
585 );
586 break;
588 /*----- Then-block -----*/
589 Module::Block().list.push_back(&then_block.get());
590 break;
592 /*----- Else-block -----*/
593 if (Else)
594 Module::Block().list.push_back(&else_block.get());
595 break;
596 }
597}
598
599/*----- Do-While -----------------------------------------------------------------------------------------------------*/
600
602 BLOCK_OPEN(body()) {
603 CONTINUE(); // emit conditional branch back to loop header at the end of the loop's body
604 }
605}
606
607/*----- While --------------------------------------------------------------------------------------------------------*/
608
610 IF (cond_) {
611 do_while_.reset(); // emit do-while code within IF
612 };
613}
__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:520
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:535
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
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...
Definition: WasmDSL.cpp:266
uint32_t pre_allocated_memory_consumption() const override
Returns the pre-allocated memory overall consumption.
Definition: WasmDSL.cpp:310
uint32_t perform_pre_allocations() override
Performs the actual pre-allocations.
Definition: WasmDSL.cpp:302
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...
Definition: WasmDSL.cpp:280
LinearAllocator(const memory::AddressSpace &memory, uint32_t start_addr)
Definition: WasmDSL.cpp:236
uint32_t pre_alloc_addr_
‍compile-time size of the currently used memory, used as pointer to next free pre-allocation
Definition: WasmDSL.cpp:225
void align_memory(uint32_t alignment)
Aligns the memory for allocations with alignment requirement align.
Definition: WasmDSL.cpp:321
Global< U32x1 > alloc_total_mem_
‍runtime total memory consumption
Definition: WasmDSL.cpp:231
U32x1 allocated_memory_peak() const override
Returns the allocated memory peak consumption.
Definition: WasmDSL.cpp:312
U32x1 allocated_memory_consumption() const override
Returns the allocated memory overall consumption.
Definition: WasmDSL.cpp:311
void deallocate(Ptr< void > ptr, U32x1 bytes) override
Deallocates the bytes consecutive bytes of allocated memory at address ptr.
Definition: WasmDSL.cpp:295
Global< U32x1 > alloc_peak_mem_
‍runtime peak memory consumption
Definition: WasmDSL.cpp:233
Global< U32x1 > alloc_addr_
‍runtime global size of the currently used memory, used as pointer to next free allocation
Definition: WasmDSL.cpp:227
const memory::AddressSpace & memory_
‍the underlying virtual address space used
Definition: WasmDSL.cpp:221
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...
Definition: WasmDSL.cpp:252
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: 2^32 - 2^16 bytes ≈ 4 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:445
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:401
static memory::AddressSpace & Memory()
Returns the virtual address space.
Definition: WasmDSL.cpp:489
void emit_continue(std::size_t level=1)
Emit an unconditional continue, continuing level levels above.
Definition: WasmDSL.cpp:457
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:364
static bool Validate(bool verbose=true, bool global=true)
Validates that the module is well-formed.
Definition: WasmDSL.cpp:371
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:379
::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:389
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