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 M_insist(memory_.size() >= pre_alloc_addr_, "allocation must fit in memory");
263 return ptr;
264 }
265 Ptr<void> pre_allocate(uint32_t bytes, uint32_t alignment) override {
266 M_insist(not pre_allocations_performed_,
267 "must not request a pre-allocation after `perform_pre_allocations()` was already called");
268 M_insist(alignment);
269 M_insist(is_pow_2(alignment), "alignment must be a power of 2");
270 if (alignment != 1U)
271 align_pre_memory(alignment);
272 Ptr<void> ptr(U32x1(pre_alloc_addr_).template to<void*>());
273 pre_alloc_addr_ += bytes; // advance memory size by bytes
274 pre_alloc_total_mem_ += bytes;
275 M_insist(memory_.size() >= pre_alloc_addr_, "allocation must fit in memory");
276 return ptr;
277 }
278 Var<Ptr<void>> allocate(U32x1 bytes, uint32_t alignment) override {
279 M_insist(alignment);
280 M_insist(is_pow_2(alignment), "alignment must be a power of 2");
281 if (alignment != 1U)
282 align_memory(alignment);
283 Var<Ptr<void>> ptr(alloc_addr_.template to<void*>());
284 alloc_addr_ += bytes.clone(); // advance memory size by bytes
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");
288 return ptr;
289 }
290
291 void deallocate(Ptr<void> ptr, U32x1 bytes) override {
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_) { // last allocation can be freed
294 alloc_addr_ -= bytes; // free by decreasing memory size
295 };
296 }
297
298 uint32_t perform_pre_allocations() override {
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_;
304 }
305
306 uint32_t pre_allocated_memory_consumption() const override { return pre_alloc_total_mem_; }
307 U32x1 allocated_memory_consumption() const override { return alloc_total_mem_; }
308 U32x1 allocated_memory_peak() const override { return alloc_peak_mem_; }
309
310 private:
312 void align_pre_memory(uint32_t alignment) {
313 M_insist(is_pow_2(alignment));
314 pre_alloc_addr_ = (pre_alloc_addr_ + (alignment - 1U)) bitand ~(alignment - 1U);
315 }
317 void align_memory(uint32_t alignment) {
318 M_insist(is_pow_2(alignment));
319 alloc_addr_ = (alloc_addr_ + (alignment - 1U)) bitand ~(alignment - 1U);
320 }
321};
322
323
324/*======================================================================================================================
325 * Module
326 *====================================================================================================================*/
327
328thread_local std::unique_ptr<Module> Module::the_module_;
329
331 : id_(NEXT_MODULE_ID_.fetch_add(1U, std::memory_order_relaxed))
332 , module_()
333 , builder_(module_)
334{
335 /*----- Import functions from the environment. -----*/
336 emit_function_import<void(uint64_t)>("insist"); // to implement insist at Wasm site
337 emit_function_import<void(uint64_t, uint64_t)>("throw"); // to throw exceptions from Wasm site
338
339 /*----- Create module memory. -----*/
340 ::wasm::Name memory_name = std::to_string(id_);
341 {
342 auto mem = std::make_unique<::wasm::Memory>();
343 mem->name = memory_name;
344 module_.addMemory(std::move(mem));
345 }
346
347 /*----- Export the Wasm linear memory, s.t. it can be accessed from the environment (JavaScript). -----*/
348 memory_ = module_.getMemory(memory_name);
349 memory_->initial = 1; // otherwise the Binaryen interpreter traps
351 module_.exports.emplace_back(
352 builder_.makeExport("memory", memory_->name, ::wasm::ExternalKind::Memory)
353 );
354
355 /*----- Set features. -----*/
356 module_.features.setBulkMemory(true);
357 module_.features.setSIMD(true);
358}
359
361{
362 if (not interface_) [[unlikely]]
363 interface_ = std::make_unique<MockInterface>(Memory(), std::move(imports));
364 return interface_.get();
365}
366
367bool Module::Validate(bool verbose, bool global)
368{
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);
373}
374
375void Module::Optimize(int optimization_level)
376{
377 ::wasm::PassOptions options;
378 options.optimizeLevel = optimization_level;
379 options.shrinkLevel = 0; // shrinking not required
380 ::wasm::PassRunner runner(&Get().module_, options);
381 runner.addDefaultOptimizationPasses();
382 runner.run();
383}
384
385std::pair<uint8_t*, std::size_t> Module::binary()
386{
387 ::wasm::BufferWithRandomAccess buffer;
388 ::wasm::WasmBinaryWriter writer(&module_, buffer);
389 writer.setNamesSection(false);
390 writer.write();
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());
394}
395
396template<std::size_t L>
397void Module::emit_insist(PrimitiveExpr<bool, L> cond, const char *filename, unsigned line, const char *msg)
398{
399 emit_insist(cond.all_true(), filename, line, msg);
400}
401
402// explicit instantiations to prevent linker errors
403template void Module::emit_insist(PrimitiveExpr<bool, 2>, const char*, unsigned, const char*);
404template void Module::emit_insist(PrimitiveExpr<bool, 4>, const char*, unsigned, const char*);
405template void Module::emit_insist(PrimitiveExpr<bool, 8>, const char*, unsigned, const char*);
406template void Module::emit_insist(PrimitiveExpr<bool, 16>, const char*, unsigned, const char*);
407template void Module::emit_insist(PrimitiveExpr<bool, 32>, const char*, unsigned, const char*);
408
409template<>
410void Module::emit_insist(PrimitiveExpr<bool, 1> cond, const char *filename, unsigned line, const char *msg)
411{
412 static thread_local struct {} _; // unique caller handle
413 struct data_t : GarbageCollectedData
414 {
415 public:
416 std::optional<FunctionProxy<void(uint64_t)>> delegate_insist;
417
418 data_t(GarbageCollectedData &&d) : GarbageCollectedData(std::move(d)) { }
419 };
420 auto &d = add_garbage_collected_data<data_t>(&_); // garbage collect the `data_t` instance
421
422 if (not d.delegate_insist) {
423 /*----- Create function to delegate to host (used for easier debugging since one can break in here). -----*/
424 FUNCTION(delegate_insist, void(uint64_t))
425 {
426 emit_call<void>("insist", PARAMETER(0).val());
427 }
428 d.delegate_insist = std::move(delegate_insist);
429 }
430
431 uint64_t idx = messages_.size();
432 messages_.emplace_back(filename, line, msg);
433
434 /*----- Check condition and possibly delegate to host. --*/
435 M_insist(bool(d.delegate_insist));
436 IF (not cond) {
437 (*d.delegate_insist)(idx);
438 };
439}
440
441void Module::emit_throw(exception::exception_t type, const char *filename, unsigned line, const char *msg)
442{
443 uint64_t idx = messages_.size();
444 messages_.emplace_back(filename, line, msg);
445 std::vector<::wasm::Expression*> args = {
446 builder_.makeConst(::wasm::Literal(type)), // type id
447 builder_.makeConst(::wasm::Literal(idx)) // message index
448 };
449 active_block_->list.push_back(builder_.makeCall("throw", args, wasm_type<void, 1>()));
450}
451
453void Module::emit_continue(std::size_t level)
454{
455 M_insist(level > 0);
456 M_insist(branch_target_stack_.size() >= level);
457 auto &branch_targets = branch_target_stack_[branch_target_stack_.size() - level];
458 if (branch_targets.condition) {
459 PrimitiveExpr<bool, 1> condition(
460 ::wasm::ExpressionManipulator::copy(branch_targets.condition, Module::Get().module_)
461 );
462 /* Continue if condition is satisfied, break otherwise. */
463 IF (condition) {
464 active_block_->list.push_back(builder_.makeBreak(branch_targets.continu));
465 } ELSE {
466 BREAK();
467 };
468 } else {
469 /* Continue unconditionally. */
470 active_block_->list.push_back(builder_.makeBreak(branch_targets.continu));
471 }
472}
473
477{
478 M_insist(level > 0);
479 M_insist(branch_target_stack_.size() >= level);
480 IF (cond) {
481 emit_continue(level);
482 };
483}
484
486{
489 } else {
490 if (not Get().vm_) [[unlikely]] {
492 auto mem = Catalog::Get().allocator().allocate(vm.size());
493 mem.map(vm.size(), 0, vm, 0); // map backed memory into vm
494 Get().vm_ = std::make_unique<std::pair<memory::AddressSpace, memory::Memory>>(std::move(vm), std::move(mem));
495 }
496 return Get().vm_->first;
497 }
498}
499
501{
502 if (not Get().allocator_) [[unlikely]] {
504 Get().allocator_ = std::make_unique<LinearAllocator>(Memory(), WasmEngine::Get_Wasm_Context_By_ID(ID()).heap);
505 else
506 Get().allocator_ = std::make_unique<LinearAllocator>(Memory(), 1); // reserve address 0 for `nullptr`
507 }
508 return *Get().allocator_;
509}
510
511
512/*======================================================================================================================
513 * Callback functions
514 *====================================================================================================================*/
515
516::wasm::Literals m::wasm::insist_interpreter(::wasm::Literals &args)
517{
518 M_insist(args.size() == 1);
519 auto idx = args[0].getUnsigned();
520 auto [filename, line, msg] = Module::Get().get_message(idx);
521
522 std::cout.flush();
523 std::cerr << filename << ':' << line << ": Wasm_insist failed.";
524 if (msg)
525 std::cerr << " " << msg << '.';
526 std::cerr << std::endl;
527
528 abort();
529}
530
531::wasm::Literals m::wasm::throw_interpreter(::wasm::Literals &args)
532{
533 M_insist(args.size() == 2);
534 auto type = static_cast<exception::exception_t>(args[0].getUnsigned());
535 auto idx = args[1].getUnsigned();
536 auto [filename, line, msg] = Module::Get().get_message(idx);
537
538 std::ostringstream oss;
539 oss << filename << ':' << line << ": Exception `" << exception::names_[type] << "` thrown.";
540 if (*msg)
541 oss << " " << msg << '.';
542 oss << std::endl;
543
544 throw exception(type, oss.str());
545}
546
547
548/*======================================================================================================================
549 * Control flow
550 *====================================================================================================================*/
551
552/*----- If -----------------------------------------------------------------------------------------------------------*/
553
555{
556 M_insist(bool(Then), "If must have a Then");
557
558 Block then_block(name_ + ".then", false);
559 Block else_block(name_ + ".else", false);
560
561 BLOCK_OPEN(then_block) {
562 Then();
563 }
564
565 if (Else) {
566 BLOCK_OPEN(else_block) {
567 Else();
568 }
569 }
570
571 auto cond = cond_.expr();
572 switch (ConstantFolding::EvalBoolean(cond)) {
574 /*----- If -----*/
575 Module::Block().list.push_back(
576 Module::Builder().makeIf(
577 cond,
578 &then_block.get(),
579 Else ? &else_block.get() : nullptr
580 )
581 );
582 break;
584 /*----- Then-block -----*/
585 Module::Block().list.push_back(&then_block.get());
586 break;
588 /*----- Else-block -----*/
589 if (Else)
590 Module::Block().list.push_back(&else_block.get());
591 break;
592 }
593}
594
595/*----- Do-While -----------------------------------------------------------------------------------------------------*/
596
598 BLOCK_OPEN(body()) {
599 CONTINUE(); // emit conditional branch back to loop header at the end of the loop's body
600 }
601}
602
603/*----- While --------------------------------------------------------------------------------------------------------*/
604
606 IF (cond_) {
607 do_while_.reset(); // emit do-while code within IF
608 };
609}
__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 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:5779
::wasm::Literals insist_interpreter(::wasm::Literals &args)
Reports a runtime error.
Definition: WasmDSL.cpp:516
typename detail::global_helper< T >::type Global
Global variable.
Definition: WasmDSL.hpp:5789
Bool< L > value
Definition: WasmUtil.hpp:1317
auto Select(C &&_cond, T &&_tru, U &&_fals)
Definition: WasmDSL.hpp:6215
std::size_t bool
Definition: WasmDSL.hpp:528
::wasm::Literals throw_interpreter(::wasm::Literals &args)
Throws an exception.
Definition: WasmDSL.cpp:531
void CONTINUE(std::size_t level=1)
Definition: WasmDSL.hpp:6187
const std::map<::wasm::Name, std::function<::wasm::Literals(::wasm::Literals &)> > callback_functions
Definition: WasmDSL.hpp:587
void BREAK(std::size_t level=1)
Definition: WasmDSL.hpp:6176
‍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:312
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:265
uint32_t pre_allocated_memory_consumption() const override
Returns the pre-allocated memory overall consumption.
Definition: WasmDSL.cpp:306
uint32_t perform_pre_allocations() override
Performs the actual pre-allocations.
Definition: WasmDSL.cpp:298
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:278
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:317
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:308
U32x1 allocated_memory_consumption() const override
Returns the allocated memory overall consumption.
Definition: WasmDSL.cpp:307
void deallocate(Ptr< void > ptr, U32x1 bytes) override
Deallocates the bytes consecutive bytes of allocated memory at address ptr.
Definition: WasmDSL.cpp:291
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
Represents a code block, i.e.
Definition: WasmDSL.hpp:1005
::wasm::Block & get() const
Definition: WasmDSL.hpp:1062
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:1367
Helper struct for garbage collection done by the Module.
Definition: WasmDSL.hpp:603
continuation_t Else
Definition: WasmDSL.hpp:6365
std::string name_
Definition: WasmDSL.hpp:6362
PrimitiveExpr< bool, 1 > cond_
Definition: WasmDSL.hpp:6361
continuation_t Then
Definition: WasmDSL.hpp:6365
Block & body()
Definition: WasmDSL.hpp:6426
::wasm::Builder & Builder()
Returns the expression builder of the current module.
Definition: WasmDSL.hpp:739
std::unique_ptr<::wasm::ModuleRunner::ExternalInterface > interface_
‍this module's interface, if any
Definition: WasmDSL.hpp:690
std::vector< branch_target_t > branch_target_stack_
‍stack of Binaryen branch targets
Definition: WasmDSL.hpp:686
::wasm::Block * active_block_
‍the currently active Binaryen block
Definition: WasmDSL.hpp:676
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:682
void emit_throw(exception::exception_t type, const char *filename, unsigned line, const char *msg)
Definition: WasmDSL.cpp:441
static thread_local std::unique_ptr< Module > the_module_
Definition: WasmDSL.hpp:700
void emit_insist(PrimitiveExpr< bool, L > cond, const char *filename, unsigned line, const char *msg)
Definition: WasmDSL.cpp:397
static memory::AddressSpace & Memory()
Returns the virtual address space.
Definition: WasmDSL.cpp:485
void emit_continue(std::size_t level=1)
Emit an unconditional continue, continuing level levels above.
Definition: WasmDSL.cpp:453
static Module & Get()
Definition: WasmDSL.hpp:714
unsigned id_
‍the unique ID for this Module
Definition: WasmDSL.hpp:660
::wasm::ModuleRunner::ExternalInterface * get_mock_interface(::wasm::GlobalValueSet imports={})
Definition: WasmDSL.cpp:360
static bool Validate(bool verbose=true, bool global=true)
Validates that the module is well-formed.
Definition: WasmDSL.cpp:367
friend struct Allocator
Definition: WasmDSL.hpp:652
static unsigned ID()
Returns the ID of the current module.
Definition: WasmDSL.hpp:721
static void Optimize(int optimization_level)
Optimizes the module with the optimization level set to level.
Definition: WasmDSL.cpp:375
::wasm::Memory * memory_
‍the main memory of the module
Definition: WasmDSL.hpp:680
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:688
std::unique_ptr< Allocator > allocator_
‍the allocator
Definition: WasmDSL.hpp:684
::wasm::Module module_
‍the Binaryen Wasm module
Definition: WasmDSL.hpp:672
friend struct Block
Definition: WasmDSL.hpp:646
::wasm::Builder builder_
‍the Binaryen expression builder for the module_
Definition: WasmDSL.hpp:674
const std::tuple< const char *, unsigned, const char * > & get_message(std::size_t idx) const
Definition: WasmDSL.hpp:907
std::pair< uint8_t *, std::size_t > binary()
Returns the binary representation of module_ in a freshly allocated memory.
Definition: WasmDSL.cpp:385
std::unique_ptr< DoWhile > do_while_
Definition: WasmDSL.hpp:6458
PrimitiveExpr< bool, 1 > cond_
Definition: WasmDSL.hpp:6457
static constexpr const char *const names_[]
Definition: WasmDSL.hpp:562
Helper type to deduce the Expr<U> type given a.
Definition: WasmDSL.hpp:160