1/*
2 * Copyright 2016 WebAssembly Community Group participants
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#ifndef wasm_wasm_builder_h
18#define wasm_wasm_builder_h
19
20#include "ir/manipulation.h"
21#include "parsing.h"
22#include "wasm.h"
23
24namespace wasm {
25
26// Useful data structures
27
28struct NameType {
29 Name name;
30 Type type;
31 NameType() : name(nullptr), type(Type::none) {}
32 NameType(Name name, Type type) : name(name), type(type) {}
33};
34
35// General AST node builder
36
37class Builder {
38 Module& wasm;
39
40public:
41 Builder(Module& wasm) : wasm(wasm) {}
42
43 // make* functions create an expression instance.
44
45 static std::unique_ptr<Function> makeFunction(Name name,
46 HeapType type,
47 std::vector<Type>&& vars,
48 Expression* body = nullptr) {
49 assert(type.isSignature());
50 auto func = std::make_unique<Function>();
51 func->name = name;
52 func->type = type;
53 func->body = body;
54 func->vars.swap(vars);
55 return func;
56 }
57
58 static std::unique_ptr<Function> makeFunction(Name name,
59 std::vector<NameType>&& params,
60 HeapType type,
61 std::vector<NameType>&& vars,
62 Expression* body = nullptr) {
63 assert(type.isSignature());
64 auto func = std::make_unique<Function>();
65 func->name = name;
66 func->type = type;
67 func->body = body;
68 for (size_t i = 0; i < params.size(); ++i) {
69 NameType& param = params[i];
70 assert(func->getParams()[i] == param.type);
71 Index index = func->localNames.size();
72 func->localIndices[param.name] = index;
73 func->localNames[index] = param.name;
74 }
75 for (auto& var : vars) {
76 func->vars.push_back(var.type);
77 Index index = func->localNames.size();
78 func->localIndices[var.name] = index;
79 func->localNames[index] = var.name;
80 }
81 return func;
82 }
83
84 static std::unique_ptr<Table> makeTable(Name name,
85 Type type = Type(HeapType::func,
86 Nullable),
87 Address initial = 0,
88 Address max = Table::kMaxSize) {
89 auto table = std::make_unique<Table>();
90 table->name = name;
91 table->type = type;
92 table->initial = initial;
93 table->max = max;
94 return table;
95 }
96
97 static std::unique_ptr<ElementSegment>
98 makeElementSegment(Name name,
99 Name table,
100 Expression* offset = nullptr,
101 Type type = Type(HeapType::func, Nullable)) {
102 auto seg = std::make_unique<ElementSegment>();
103 seg->name = name;
104 seg->table = table;
105 seg->offset = offset;
106 seg->type = type;
107 return seg;
108 }
109
110 static std::unique_ptr<Memory> makeMemory(Name name,
111 Address initial = 0,
112 Address max = Memory::kMaxSize32,
113 bool shared = false,
114 Type indexType = Type::i32) {
115 auto memory = std::make_unique<Memory>();
116 memory->name = name;
117 memory->initial = initial;
118 memory->max = max;
119 memory->shared = shared;
120 memory->indexType = indexType;
121 return memory;
122 }
123
124 static std::unique_ptr<DataSegment>
125 makeDataSegment(Name name = "",
126 Name memory = "",
127 bool isPassive = false,
128 Expression* offset = nullptr,
129 const char* init = "",
130 Address size = 0) {
131 auto seg = std::make_unique<DataSegment>();
132 seg->name = name;
133 seg->memory = memory;
134 seg->isPassive = isPassive;
135 seg->offset = offset;
136 seg->data.resize(size);
137 std::copy_n(init, size, seg->data.begin());
138 return seg;
139 }
140
141 static std::unique_ptr<Export>
142 makeExport(Name name, Name value, ExternalKind kind) {
143 auto export_ = std::make_unique<Export>();
144 export_->name = name;
145 export_->value = value;
146 export_->kind = kind;
147 return export_;
148 }
149
150 enum Mutability { Mutable, Immutable };
151
152 static std::unique_ptr<Global>
153 makeGlobal(Name name, Type type, Expression* init, Mutability mutable_) {
154 auto glob = std::make_unique<Global>();
155 glob->name = name;
156 glob->type = type;
157 glob->init = init;
158 glob->mutable_ = mutable_ == Mutable;
159 return glob;
160 }
161
162 static std::unique_ptr<Tag> makeTag(Name name, Signature sig) {
163 auto tag = std::make_unique<Tag>();
164 tag->name = name;
165 tag->sig = sig;
166 return tag;
167 }
168
169 // IR nodes
170 Nop* makeNop() { return wasm.allocator.alloc<Nop>(); }
171 Block* makeBlock(Expression* first = nullptr) {
172 auto* ret = wasm.allocator.alloc<Block>();
173 if (first) {
174 ret->list.push_back(first);
175 ret->finalize();
176 }
177 return ret;
178 }
179 Block* makeBlock(Name name, Expression* first = nullptr) {
180 auto* ret = makeBlock(first);
181 ret->name = name;
182 ret->finalize();
183 return ret;
184 }
185
186 template<typename T>
187 using bool_if_not_expr_t =
188 std::enable_if_t<std::negation_v<std::is_convertible<T, Expression*>>,
189 bool>;
190
191 template<typename T, bool_if_not_expr_t<T> = true>
192 Block* makeBlock(const T& items) {
193 auto* ret = wasm.allocator.alloc<Block>();
194 ret->list.set(items);
195 ret->finalize();
196 return ret;
197 }
198
199 template<typename T, bool_if_not_expr_t<T> = true>
200 Block* makeBlock(const T& items, Type type) {
201 auto* ret = wasm.allocator.alloc<Block>();
202 ret->list.set(items);
203 ret->finalize(type);
204 return ret;
205 }
206
207 template<typename T, bool_if_not_expr_t<T> = true>
208 Block* makeBlock(Name name, const T& items, Type type) {
209 auto* ret = wasm.allocator.alloc<Block>();
210 ret->name = name;
211 ret->list.set(items);
212 ret->finalize(type);
213 return ret;
214 }
215 Block* makeBlock(std::initializer_list<Expression*>&& items) {
216 return makeBlock(items);
217 }
218 Block* makeBlock(std::initializer_list<Expression*>&& items, Type type) {
219 return makeBlock(items, type);
220 }
221 Block*
222 makeBlock(Name name, std::initializer_list<Expression*>&& items, Type type) {
223 return makeBlock(name, items, type);
224 }
225
226 If* makeIf(Expression* condition,
227 Expression* ifTrue,
228 Expression* ifFalse = nullptr) {
229 auto* ret = wasm.allocator.alloc<If>();
230 ret->condition = condition;
231 ret->ifTrue = ifTrue;
232 ret->ifFalse = ifFalse;
233 ret->finalize();
234 return ret;
235 }
236 If* makeIf(Expression* condition,
237 Expression* ifTrue,
238 Expression* ifFalse,
239 Type type) {
240 auto* ret = wasm.allocator.alloc<If>();
241 ret->condition = condition;
242 ret->ifTrue = ifTrue;
243 ret->ifFalse = ifFalse;
244 ret->finalize(type);
245 return ret;
246 }
247 Loop* makeLoop(Name name, Expression* body) {
248 auto* ret = wasm.allocator.alloc<Loop>();
249 ret->name = name;
250 ret->body = body;
251 ret->finalize();
252 return ret;
253 }
254 Loop* makeLoop(Name name, Expression* body, Type type) {
255 auto* ret = wasm.allocator.alloc<Loop>();
256 ret->name = name;
257 ret->body = body;
258 ret->finalize(type);
259 return ret;
260 }
261 Break* makeBreak(Name name,
262 Expression* value = nullptr,
263 Expression* condition = nullptr) {
264 auto* ret = wasm.allocator.alloc<Break>();
265 ret->name = name;
266 ret->value = value;
267 ret->condition = condition;
268 ret->finalize();
269 return ret;
270 }
271 template<typename T>
272 Switch* makeSwitch(T& list,
273 Name default_,
274 Expression* condition,
275 Expression* value = nullptr) {
276 auto* ret = wasm.allocator.alloc<Switch>();
277 ret->targets.set(list);
278 ret->default_ = default_;
279 ret->value = value;
280 ret->condition = condition;
281 return ret;
282 }
283 Call* makeCall(Name target,
284 const std::vector<Expression*>& args,
285 Type type,
286 bool isReturn = false) {
287 auto* call = wasm.allocator.alloc<Call>();
288 // not all functions may exist yet, so type must be provided
289 call->type = type;
290 call->target = target;
291 call->operands.set(args);
292 call->isReturn = isReturn;
293 return call;
294 }
295 template<typename T>
296 Call* makeCall(Name target, const T& args, Type type, bool isReturn = false) {
297 auto* call = wasm.allocator.alloc<Call>();
298 // not all functions may exist yet, so type must be provided
299 call->type = type;
300 call->target = target;
301 call->operands.set(args);
302 call->isReturn = isReturn;
303 call->finalize();
304 return call;
305 }
306 template<typename T>
307 CallIndirect* makeCallIndirect(const Name table,
308 Expression* target,
309 const T& args,
310 HeapType heapType,
311 bool isReturn = false) {
312 assert(heapType.isSignature());
313 auto* call = wasm.allocator.alloc<CallIndirect>();
314 call->table = table;
315 call->heapType = heapType;
316 call->type = heapType.getSignature().results;
317 call->target = target;
318 call->operands.set(args);
319 call->isReturn = isReturn;
320 call->finalize();
321 return call;
322 }
323 template<typename T>
324 CallRef* makeCallRef(Expression* target,
325 const T& args,
326 Type type,
327 bool isReturn = false) {
328 auto* call = wasm.allocator.alloc<CallRef>();
329 call->type = type;
330 call->target = target;
331 call->operands.set(args);
332 call->isReturn = isReturn;
333 call->finalize();
334 return call;
335 }
336 LocalGet* makeLocalGet(Index index, Type type) {
337 auto* ret = wasm.allocator.alloc<LocalGet>();
338 ret->index = index;
339 ret->type = type;
340 return ret;
341 }
342 LocalSet* makeLocalSet(Index index, Expression* value) {
343 auto* ret = wasm.allocator.alloc<LocalSet>();
344 ret->index = index;
345 ret->value = value;
346 ret->makeSet();
347 ret->finalize();
348 return ret;
349 }
350 LocalSet* makeLocalTee(Index index, Expression* value, Type type) {
351 auto* ret = wasm.allocator.alloc<LocalSet>();
352 ret->index = index;
353 ret->value = value;
354 ret->makeTee(type);
355 return ret;
356 }
357 GlobalGet* makeGlobalGet(Name name, Type type) {
358 auto* ret = wasm.allocator.alloc<GlobalGet>();
359 ret->name = name;
360 ret->type = type;
361 return ret;
362 }
363 GlobalSet* makeGlobalSet(Name name, Expression* value) {
364 auto* ret = wasm.allocator.alloc<GlobalSet>();
365 ret->name = name;
366 ret->value = value;
367 ret->finalize();
368 return ret;
369 }
370 Load* makeLoad(unsigned bytes,
371 bool signed_,
372 Address offset,
373 unsigned align,
374 Expression* ptr,
375 Type type,
376 Name memory) {
377 auto* ret = wasm.allocator.alloc<Load>();
378 ret->isAtomic = false;
379 ret->bytes = bytes;
380 ret->signed_ = signed_;
381 ret->offset = offset;
382 ret->align = align;
383 ret->ptr = ptr;
384 ret->type = type;
385 ret->memory = memory;
386 return ret;
387 }
388 Load* makeAtomicLoad(
389 unsigned bytes, Address offset, Expression* ptr, Type type, Name memory) {
390 Load* load = makeLoad(bytes, signed_: false, offset, align: bytes, ptr, type, memory);
391 load->isAtomic = true;
392 return load;
393 }
394 AtomicWait* makeAtomicWait(Expression* ptr,
395 Expression* expected,
396 Expression* timeout,
397 Type expectedType,
398 Address offset,
399 Name memory) {
400 auto* wait = wasm.allocator.alloc<AtomicWait>();
401 wait->offset = offset;
402 wait->ptr = ptr;
403 wait->expected = expected;
404 wait->timeout = timeout;
405 wait->expectedType = expectedType;
406 wait->finalize();
407 wait->memory = memory;
408 return wait;
409 }
410 AtomicNotify* makeAtomicNotify(Expression* ptr,
411 Expression* notifyCount,
412 Address offset,
413 Name memory) {
414 auto* notify = wasm.allocator.alloc<AtomicNotify>();
415 notify->offset = offset;
416 notify->ptr = ptr;
417 notify->notifyCount = notifyCount;
418 notify->finalize();
419 notify->memory = memory;
420 return notify;
421 }
422 AtomicFence* makeAtomicFence() { return wasm.allocator.alloc<AtomicFence>(); }
423 Store* makeStore(unsigned bytes,
424 Address offset,
425 unsigned align,
426 Expression* ptr,
427 Expression* value,
428 Type type,
429 Name memory) {
430 auto* ret = wasm.allocator.alloc<Store>();
431 ret->isAtomic = false;
432 ret->bytes = bytes;
433 ret->offset = offset;
434 ret->align = align;
435 ret->ptr = ptr;
436 ret->value = value;
437 ret->valueType = type;
438 ret->memory = memory;
439 ret->finalize();
440 assert(ret->value->type.isConcrete() ? ret->value->type == type : true);
441 return ret;
442 }
443 Store* makeAtomicStore(unsigned bytes,
444 Address offset,
445 Expression* ptr,
446 Expression* value,
447 Type type,
448 Name memory) {
449 Store* store = makeStore(bytes, offset, align: bytes, ptr, value, type, memory);
450 store->isAtomic = true;
451 return store;
452 }
453 AtomicRMW* makeAtomicRMW(AtomicRMWOp op,
454 unsigned bytes,
455 Address offset,
456 Expression* ptr,
457 Expression* value,
458 Type type,
459 Name memory) {
460 auto* ret = wasm.allocator.alloc<AtomicRMW>();
461 ret->op = op;
462 ret->bytes = bytes;
463 ret->offset = offset;
464 ret->ptr = ptr;
465 ret->value = value;
466 ret->type = type;
467 ret->finalize();
468 ret->memory = memory;
469 return ret;
470 }
471 AtomicCmpxchg* makeAtomicCmpxchg(unsigned bytes,
472 Address offset,
473 Expression* ptr,
474 Expression* expected,
475 Expression* replacement,
476 Type type,
477 Name memory) {
478 auto* ret = wasm.allocator.alloc<AtomicCmpxchg>();
479 ret->bytes = bytes;
480 ret->offset = offset;
481 ret->ptr = ptr;
482 ret->expected = expected;
483 ret->replacement = replacement;
484 ret->type = type;
485 ret->finalize();
486 ret->memory = memory;
487 return ret;
488 }
489 SIMDExtract*
490 makeSIMDExtract(SIMDExtractOp op, Expression* vec, uint8_t index) {
491 auto* ret = wasm.allocator.alloc<SIMDExtract>();
492 ret->op = op;
493 ret->vec = vec;
494 ret->index = index;
495 ret->finalize();
496 return ret;
497 }
498 SIMDReplace* makeSIMDReplace(SIMDReplaceOp op,
499 Expression* vec,
500 uint8_t index,
501 Expression* value) {
502 auto* ret = wasm.allocator.alloc<SIMDReplace>();
503 ret->op = op;
504 ret->vec = vec;
505 ret->index = index;
506 ret->value = value;
507 ret->finalize();
508 return ret;
509 }
510 SIMDShuffle* makeSIMDShuffle(Expression* left,
511 Expression* right,
512 const std::array<uint8_t, 16>& mask) {
513 auto* ret = wasm.allocator.alloc<SIMDShuffle>();
514 ret->left = left;
515 ret->right = right;
516 ret->mask = mask;
517 ret->finalize();
518 return ret;
519 }
520 SIMDTernary* makeSIMDTernary(SIMDTernaryOp op,
521 Expression* a,
522 Expression* b,
523 Expression* c) {
524 auto* ret = wasm.allocator.alloc<SIMDTernary>();
525 ret->op = op;
526 ret->a = a;
527 ret->b = b;
528 ret->c = c;
529 ret->finalize();
530 return ret;
531 }
532 SIMDShift* makeSIMDShift(SIMDShiftOp op, Expression* vec, Expression* shift) {
533 auto* ret = wasm.allocator.alloc<SIMDShift>();
534 ret->op = op;
535 ret->vec = vec;
536 ret->shift = shift;
537 ret->finalize();
538 return ret;
539 }
540 SIMDLoad* makeSIMDLoad(SIMDLoadOp op,
541 Address offset,
542 Address align,
543 Expression* ptr,
544 Name memory) {
545 auto* ret = wasm.allocator.alloc<SIMDLoad>();
546 ret->op = op;
547 ret->offset = offset;
548 ret->align = align;
549 ret->ptr = ptr;
550 ret->memory = memory;
551 ret->finalize();
552 return ret;
553 }
554 SIMDLoadStoreLane* makeSIMDLoadStoreLane(SIMDLoadStoreLaneOp op,
555 Address offset,
556 Address align,
557 uint8_t index,
558 Expression* ptr,
559 Expression* vec,
560 Name memory) {
561 auto* ret = wasm.allocator.alloc<SIMDLoadStoreLane>();
562 ret->op = op;
563 ret->offset = offset;
564 ret->align = align;
565 ret->index = index;
566 ret->ptr = ptr;
567 ret->vec = vec;
568 ret->finalize();
569 ret->memory = memory;
570 return ret;
571 }
572 MemoryInit* makeMemoryInit(Name segment,
573 Expression* dest,
574 Expression* offset,
575 Expression* size,
576 Name memory) {
577 auto* ret = wasm.allocator.alloc<MemoryInit>();
578 ret->segment = segment;
579 ret->dest = dest;
580 ret->offset = offset;
581 ret->size = size;
582 ret->memory = memory;
583 ret->finalize();
584 return ret;
585 }
586 DataDrop* makeDataDrop(Name segment) {
587 auto* ret = wasm.allocator.alloc<DataDrop>();
588 ret->segment = segment;
589 ret->finalize();
590 return ret;
591 }
592 MemoryCopy* makeMemoryCopy(Expression* dest,
593 Expression* source,
594 Expression* size,
595 Name destMemory,
596 Name sourceMemory) {
597 auto* ret = wasm.allocator.alloc<MemoryCopy>();
598 ret->dest = dest;
599 ret->source = source;
600 ret->size = size;
601 ret->destMemory = destMemory;
602 ret->sourceMemory = sourceMemory;
603 ret->finalize();
604 return ret;
605 }
606 MemoryFill* makeMemoryFill(Expression* dest,
607 Expression* value,
608 Expression* size,
609 Name memory) {
610 auto* ret = wasm.allocator.alloc<MemoryFill>();
611 ret->dest = dest;
612 ret->value = value;
613 ret->size = size;
614 ret->memory = memory;
615 ret->finalize();
616 return ret;
617 }
618 Const* makeConst(Literal value) {
619 assert(value.type.isNumber());
620 auto* ret = wasm.allocator.alloc<Const>();
621 ret->value = value;
622 ret->type = value.type;
623 return ret;
624 }
625 template<typename T> Const* makeConst(T x) { return makeConst(value: Literal(x)); }
626 Unary* makeUnary(UnaryOp op, Expression* value) {
627 auto* ret = wasm.allocator.alloc<Unary>();
628 ret->op = op;
629 ret->value = value;
630 ret->finalize();
631 return ret;
632 }
633 Const* makeConstPtr(uint64_t val, Type indexType) {
634 return makeConst(value: Literal::makeFromInt64(x: val, type: indexType));
635 }
636 Binary* makeBinary(BinaryOp op, Expression* left, Expression* right) {
637 auto* ret = wasm.allocator.alloc<Binary>();
638 ret->op = op;
639 ret->left = left;
640 ret->right = right;
641 ret->finalize();
642 return ret;
643 }
644 Select*
645 makeSelect(Expression* condition, Expression* ifTrue, Expression* ifFalse) {
646 auto* ret = wasm.allocator.alloc<Select>();
647 ret->condition = condition;
648 ret->ifTrue = ifTrue;
649 ret->ifFalse = ifFalse;
650 ret->finalize();
651 return ret;
652 }
653 Select* makeSelect(Expression* condition,
654 Expression* ifTrue,
655 Expression* ifFalse,
656 Type type) {
657 auto* ret = wasm.allocator.alloc<Select>();
658 ret->condition = condition;
659 ret->ifTrue = ifTrue;
660 ret->ifFalse = ifFalse;
661 ret->finalize(type);
662 return ret;
663 }
664 Return* makeReturn(Expression* value = nullptr) {
665 auto* ret = wasm.allocator.alloc<Return>();
666 ret->value = value;
667 return ret;
668 }
669
670 // Some APIs can be told if the memory is 32 or 64-bit. If they are not
671 // informed of that, then the memory they refer to is looked up and that
672 // information fetched from there.
673 enum MemoryInfo { Memory32, Memory64, Unspecified };
674
675 bool isMemory64(Name memoryName, MemoryInfo info) {
676 return info == MemoryInfo::Memory64 || (info == MemoryInfo::Unspecified &&
677 wasm.getMemory(name: memoryName)->is64());
678 }
679
680 MemorySize* makeMemorySize(Name memoryName,
681 MemoryInfo info = MemoryInfo::Unspecified) {
682 auto* ret = wasm.allocator.alloc<MemorySize>();
683 if (isMemory64(memoryName, info)) {
684 ret->make64();
685 }
686 ret->memory = memoryName;
687 ret->finalize();
688 return ret;
689 }
690 MemoryGrow* makeMemoryGrow(Expression* delta,
691 Name memoryName,
692 MemoryInfo info = MemoryInfo::Unspecified) {
693 auto* ret = wasm.allocator.alloc<MemoryGrow>();
694 if (isMemory64(memoryName, info)) {
695 ret->make64();
696 }
697 ret->delta = delta;
698 ret->memory = memoryName;
699 ret->finalize();
700 return ret;
701 }
702 RefNull* makeRefNull(HeapType type) {
703 auto* ret = wasm.allocator.alloc<RefNull>();
704 ret->finalize(Type(type.getBottom(), Nullable));
705 return ret;
706 }
707 RefNull* makeRefNull(Type type) {
708 assert(type.isNullable() && type.isNull());
709 auto* ret = wasm.allocator.alloc<RefNull>();
710 ret->finalize(type);
711 return ret;
712 }
713 RefIsNull* makeRefIsNull(Expression* value) {
714 auto* ret = wasm.allocator.alloc<RefIsNull>();
715 ret->value = value;
716 ret->finalize();
717 return ret;
718 }
719 RefFunc* makeRefFunc(Name func, HeapType heapType) {
720 auto* ret = wasm.allocator.alloc<RefFunc>();
721 ret->func = func;
722 ret->finalize(Type(heapType, NonNullable));
723 return ret;
724 }
725 RefEq* makeRefEq(Expression* left, Expression* right) {
726 auto* ret = wasm.allocator.alloc<RefEq>();
727 ret->left = left;
728 ret->right = right;
729 ret->finalize();
730 return ret;
731 }
732 TableGet* makeTableGet(Name table, Expression* index, Type type) {
733 auto* ret = wasm.allocator.alloc<TableGet>();
734 ret->table = table;
735 ret->index = index;
736 ret->type = type;
737 ret->finalize();
738 return ret;
739 }
740 TableSet* makeTableSet(Name table, Expression* index, Expression* value) {
741 auto* ret = wasm.allocator.alloc<TableSet>();
742 ret->table = table;
743 ret->index = index;
744 ret->value = value;
745 ret->finalize();
746 return ret;
747 }
748 TableSize* makeTableSize(Name table) {
749 auto* ret = wasm.allocator.alloc<TableSize>();
750 ret->table = table;
751 ret->finalize();
752 return ret;
753 }
754 TableGrow* makeTableGrow(Name table, Expression* value, Expression* delta) {
755 auto* ret = wasm.allocator.alloc<TableGrow>();
756 ret->table = table;
757 ret->value = value;
758 ret->delta = delta;
759 ret->finalize();
760 return ret;
761 }
762
763private:
764 Try* makeTry(Name name,
765 Expression* body,
766 const std::vector<Name>& catchTags,
767 const std::vector<Expression*>& catchBodies,
768 Name delegateTarget,
769 Type type,
770 bool hasType) { // differentiate whether a type was passed in
771 auto* ret = wasm.allocator.alloc<Try>();
772 ret->name = name;
773 ret->body = body;
774 ret->catchTags.set(catchTags);
775 ret->catchBodies.set(catchBodies);
776 if (hasType) {
777 ret->finalize(type);
778 } else {
779 ret->finalize();
780 }
781 return ret;
782 }
783
784public:
785 Try* makeTry(Expression* body,
786 const std::vector<Name>& catchTags,
787 const std::vector<Expression*>& catchBodies) {
788 return makeTry(
789 Name(), body, catchTags, catchBodies, Name(), Type::none, false);
790 }
791 Try* makeTry(Expression* body,
792 const std::vector<Name>& catchTags,
793 const std::vector<Expression*>& catchBodies,
794 Type type) {
795 return makeTry(Name(), body, catchTags, catchBodies, Name(), type, true);
796 }
797 Try* makeTry(Name name,
798 Expression* body,
799 const std::vector<Name>& catchTags,
800 const std::vector<Expression*>& catchBodies) {
801 return makeTry(
802 name, body, catchTags, catchBodies, Name(), Type::none, false);
803 }
804 Try* makeTry(Name name,
805 Expression* body,
806 const std::vector<Name>& catchTags,
807 const std::vector<Expression*>& catchBodies,
808 Type type) {
809 return makeTry(name, body, catchTags, catchBodies, Name(), type, true);
810 }
811 Try* makeTry(Expression* body, Name delegateTarget) {
812 return makeTry(Name(), body, {}, {}, delegateTarget, Type::none, false);
813 }
814 Try* makeTry(Expression* body, Name delegateTarget, Type type) {
815 return makeTry(Name(), body, {}, {}, delegateTarget, type, true);
816 }
817 Try* makeTry(Name name, Expression* body, Name delegateTarget) {
818 return makeTry(name, body, {}, {}, delegateTarget, Type::none, false);
819 }
820 Try* makeTry(Name name, Expression* body, Name delegateTarget, Type type) {
821 return makeTry(name, body, {}, {}, delegateTarget, type, true);
822 }
823 Throw* makeThrow(Tag* tag, const std::vector<Expression*>& args) {
824 return makeThrow(tag->name, args);
825 }
826 Throw* makeThrow(Name tag, const std::vector<Expression*>& args) {
827 auto* ret = wasm.allocator.alloc<Throw>();
828 ret->tag = tag;
829 ret->operands.set(args);
830 ret->finalize();
831 return ret;
832 }
833 Rethrow* makeRethrow(Name target) {
834 auto* ret = wasm.allocator.alloc<Rethrow>();
835 ret->target = target;
836 ret->finalize();
837 return ret;
838 }
839 Unreachable* makeUnreachable() { return wasm.allocator.alloc<Unreachable>(); }
840 Pop* makePop(Type type) {
841 auto* ret = wasm.allocator.alloc<Pop>();
842 ret->type = type;
843 ret->finalize();
844 return ret;
845 }
846 template<typename ListType> TupleMake* makeTupleMake(ListType&& operands) {
847 auto* ret = wasm.allocator.alloc<TupleMake>();
848 ret->operands.set(operands);
849 ret->finalize();
850 return ret;
851 }
852 TupleExtract* makeTupleExtract(Expression* tuple, Index index) {
853 auto* ret = wasm.allocator.alloc<TupleExtract>();
854 ret->tuple = tuple;
855 ret->index = index;
856 ret->finalize();
857 return ret;
858 }
859 I31New* makeI31New(Expression* value) {
860 auto* ret = wasm.allocator.alloc<I31New>();
861 ret->value = value;
862 ret->finalize();
863 return ret;
864 }
865 I31Get* makeI31Get(Expression* i31, bool signed_) {
866 auto* ret = wasm.allocator.alloc<I31Get>();
867 ret->i31 = i31;
868 ret->signed_ = signed_;
869 ret->finalize();
870 return ret;
871 }
872 RefTest* makeRefTest(Expression* ref, Type castType) {
873 auto* ret = wasm.allocator.alloc<RefTest>();
874 ret->ref = ref;
875 ret->castType = castType;
876 ret->finalize();
877 return ret;
878 }
879 RefCast* makeRefCast(Expression* ref, Type type, RefCast::Safety safety) {
880 auto* ret = wasm.allocator.alloc<RefCast>();
881 ret->ref = ref;
882 ret->type = type;
883 ret->safety = safety;
884 ret->finalize();
885 return ret;
886 }
887 BrOn*
888 makeBrOn(BrOnOp op, Name name, Expression* ref, Type castType = Type::none) {
889 auto* ret = wasm.allocator.alloc<BrOn>();
890 ret->op = op;
891 ret->name = name;
892 ret->ref = ref;
893 ret->castType = castType;
894 ret->finalize();
895 return ret;
896 }
897 template<typename T> StructNew* makeStructNew(HeapType type, const T& args) {
898 auto* ret = wasm.allocator.alloc<StructNew>();
899 ret->operands.set(args);
900 ret->type = Type(type, NonNullable);
901 ret->finalize();
902 return ret;
903 }
904 StructGet*
905 makeStructGet(Index index, Expression* ref, Type type, bool signed_ = false) {
906 auto* ret = wasm.allocator.alloc<StructGet>();
907 ret->index = index;
908 ret->ref = ref;
909 ret->type = type;
910 ret->signed_ = signed_;
911 ret->finalize();
912 return ret;
913 }
914 StructSet* makeStructSet(Index index, Expression* ref, Expression* value) {
915 auto* ret = wasm.allocator.alloc<StructSet>();
916 ret->index = index;
917 ret->ref = ref;
918 ret->value = value;
919 ret->finalize();
920 return ret;
921 }
922 ArrayNew*
923 makeArrayNew(HeapType type, Expression* size, Expression* init = nullptr) {
924 auto* ret = wasm.allocator.alloc<ArrayNew>();
925 ret->size = size;
926 ret->init = init;
927 ret->type = Type(type, NonNullable);
928 ret->finalize();
929 return ret;
930 }
931 ArrayNewData* makeArrayNewData(HeapType type,
932 Name seg,
933 Expression* offset,
934 Expression* size) {
935 auto* ret = wasm.allocator.alloc<ArrayNewData>();
936 ret->segment = seg;
937 ret->offset = offset;
938 ret->size = size;
939 ret->type = Type(type, NonNullable);
940 ret->finalize();
941 return ret;
942 }
943 ArrayNewElem* makeArrayNewElem(HeapType type,
944 Name seg,
945 Expression* offset,
946 Expression* size) {
947 auto* ret = wasm.allocator.alloc<ArrayNewElem>();
948 ret->segment = seg;
949 ret->offset = offset;
950 ret->size = size;
951 ret->type = Type(type, NonNullable);
952 ret->finalize();
953 return ret;
954 }
955 ArrayNewFixed* makeArrayNewFixed(HeapType type,
956 const std::vector<Expression*>& values) {
957 auto* ret = wasm.allocator.alloc<ArrayNewFixed>();
958 ret->values.set(values);
959 ret->type = Type(type, NonNullable);
960 ret->finalize();
961 return ret;
962 }
963 ArrayGet* makeArrayGet(Expression* ref,
964 Expression* index,
965 Type type,
966 bool signed_ = false) {
967 auto* ret = wasm.allocator.alloc<ArrayGet>();
968 ret->ref = ref;
969 ret->index = index;
970 ret->type = type;
971 ret->signed_ = signed_;
972 ret->finalize();
973 return ret;
974 }
975 ArraySet*
976 makeArraySet(Expression* ref, Expression* index, Expression* value) {
977 auto* ret = wasm.allocator.alloc<ArraySet>();
978 ret->ref = ref;
979 ret->index = index;
980 ret->value = value;
981 ret->finalize();
982 return ret;
983 }
984 ArrayLen* makeArrayLen(Expression* ref) {
985 auto* ret = wasm.allocator.alloc<ArrayLen>();
986 ret->ref = ref;
987 ret->finalize();
988 return ret;
989 }
990 ArrayCopy* makeArrayCopy(Expression* destRef,
991 Expression* destIndex,
992 Expression* srcRef,
993 Expression* srcIndex,
994 Expression* length) {
995 auto* ret = wasm.allocator.alloc<ArrayCopy>();
996 ret->destRef = destRef;
997 ret->destIndex = destIndex;
998 ret->srcRef = srcRef;
999 ret->srcIndex = srcIndex;
1000 ret->length = length;
1001 ret->finalize();
1002 return ret;
1003 }
1004 ArrayFill* makeArrayFill(Expression* ref,
1005 Expression* index,
1006 Expression* value,
1007 Expression* size) {
1008 auto* ret = wasm.allocator.alloc<ArrayFill>();
1009 ret->ref = ref;
1010 ret->index = index;
1011 ret->value = value;
1012 ret->size = size;
1013 ret->finalize();
1014 return ret;
1015 }
1016 ArrayInitData* makeArrayInitData(Name seg,
1017 Expression* ref,
1018 Expression* index,
1019 Expression* offset,
1020 Expression* size) {
1021 auto* ret = wasm.allocator.alloc<ArrayInitData>();
1022 ret->segment = seg;
1023 ret->ref = ref;
1024 ret->index = index;
1025 ret->offset = offset;
1026 ret->size = size;
1027 ret->finalize();
1028 return ret;
1029 }
1030 ArrayInitElem* makeArrayInitElem(Name seg,
1031 Expression* ref,
1032 Expression* index,
1033 Expression* offset,
1034 Expression* size) {
1035 auto* ret = wasm.allocator.alloc<ArrayInitElem>();
1036 ret->segment = seg;
1037 ret->ref = ref;
1038 ret->index = index;
1039 ret->offset = offset;
1040 ret->size = size;
1041 ret->finalize();
1042 return ret;
1043 }
1044 RefAs* makeRefAs(RefAsOp op, Expression* value) {
1045 auto* ret = wasm.allocator.alloc<RefAs>();
1046 ret->op = op;
1047 ret->value = value;
1048 ret->finalize();
1049 return ret;
1050 }
1051 StringNew* makeStringNew(StringNewOp op,
1052 Expression* ptr,
1053 Expression* length,
1054 bool try_) {
1055 auto* ret = wasm.allocator.alloc<StringNew>();
1056 ret->op = op;
1057 ret->ptr = ptr;
1058 ret->length = length;
1059 ret->try_ = try_;
1060 ret->finalize();
1061 return ret;
1062 }
1063 StringNew* makeStringNew(StringNewOp op,
1064 Expression* ptr,
1065 Expression* start,
1066 Expression* end,
1067 bool try_) {
1068 auto* ret = wasm.allocator.alloc<StringNew>();
1069 ret->op = op;
1070 ret->ptr = ptr;
1071 ret->start = start;
1072 ret->end = end;
1073 ret->try_ = try_;
1074 ret->finalize();
1075 return ret;
1076 }
1077 StringConst* makeStringConst(Name string) {
1078 auto* ret = wasm.allocator.alloc<StringConst>();
1079 ret->string = string;
1080 ret->finalize();
1081 return ret;
1082 }
1083 StringMeasure* makeStringMeasure(StringMeasureOp op, Expression* ref) {
1084 auto* ret = wasm.allocator.alloc<StringMeasure>();
1085 ret->op = op;
1086 ret->ref = ref;
1087 ret->finalize();
1088 return ret;
1089 }
1090 StringEncode* makeStringEncode(StringEncodeOp op,
1091 Expression* ref,
1092 Expression* ptr,
1093 Expression* start = nullptr) {
1094 auto* ret = wasm.allocator.alloc<StringEncode>();
1095 ret->op = op;
1096 ret->ref = ref;
1097 ret->ptr = ptr;
1098 ret->start = start;
1099 ret->finalize();
1100 return ret;
1101 }
1102 StringConcat* makeStringConcat(Expression* left, Expression* right) {
1103 auto* ret = wasm.allocator.alloc<StringConcat>();
1104 ret->left = left;
1105 ret->right = right;
1106 ret->finalize();
1107 return ret;
1108 }
1109 StringEq* makeStringEq(StringEqOp op, Expression* left, Expression* right) {
1110 auto* ret = wasm.allocator.alloc<StringEq>();
1111 ret->op = op;
1112 ret->left = left;
1113 ret->right = right;
1114 ret->finalize();
1115 return ret;
1116 }
1117 StringAs* makeStringAs(StringAsOp op, Expression* ref) {
1118 auto* ret = wasm.allocator.alloc<StringAs>();
1119 ret->op = op;
1120 ret->ref = ref;
1121 ret->finalize();
1122 return ret;
1123 }
1124 StringWTF8Advance*
1125 makeStringWTF8Advance(Expression* ref, Expression* pos, Expression* bytes) {
1126 auto* ret = wasm.allocator.alloc<StringWTF8Advance>();
1127 ret->ref = ref;
1128 ret->pos = pos;
1129 ret->bytes = bytes;
1130 ret->finalize();
1131 return ret;
1132 }
1133 StringWTF16Get* makeStringWTF16Get(Expression* ref, Expression* pos) {
1134 auto* ret = wasm.allocator.alloc<StringWTF16Get>();
1135 ret->ref = ref;
1136 ret->pos = pos;
1137 ret->finalize();
1138 return ret;
1139 }
1140 StringIterNext* makeStringIterNext(Expression* ref) {
1141 auto* ret = wasm.allocator.alloc<StringIterNext>();
1142 ret->ref = ref;
1143 ret->finalize();
1144 return ret;
1145 }
1146 StringIterMove*
1147 makeStringIterMove(StringIterMoveOp op, Expression* ref, Expression* num) {
1148 auto* ret = wasm.allocator.alloc<StringIterMove>();
1149 ret->op = op;
1150 ret->ref = ref;
1151 ret->num = num;
1152 ret->finalize();
1153 return ret;
1154 }
1155 StringSliceWTF* makeStringSliceWTF(StringSliceWTFOp op,
1156 Expression* ref,
1157 Expression* start,
1158 Expression* end) {
1159 auto* ret = wasm.allocator.alloc<StringSliceWTF>();
1160 ret->op = op;
1161 ret->ref = ref;
1162 ret->start = start;
1163 ret->end = end;
1164 ret->finalize();
1165 return ret;
1166 }
1167 StringSliceIter* makeStringSliceIter(Expression* ref, Expression* num) {
1168 auto* ret = wasm.allocator.alloc<StringSliceIter>();
1169 ret->ref = ref;
1170 ret->num = num;
1171 ret->finalize();
1172 return ret;
1173 }
1174
1175 // Additional helpers
1176
1177 Drop* makeDrop(Expression* value) {
1178 auto* ret = wasm.allocator.alloc<Drop>();
1179 ret->value = value;
1180 ret->finalize();
1181 return ret;
1182 }
1183
1184 // Make a constant expression. This might be a wasm Const, or something
1185 // else of constant value like ref.null.
1186 Expression* makeConstantExpression(Literal value) {
1187 auto type = value.type;
1188 if (type.isNumber()) {
1189 return makeConst(value);
1190 }
1191 if (value.isNull()) {
1192 return makeRefNull(type);
1193 }
1194 if (type.isFunction()) {
1195 return makeRefFunc(func: value.getFunc(), heapType: type.getHeapType());
1196 }
1197 if (type.isRef() && type.getHeapType() == HeapType::i31) {
1198 return makeI31New(value: makeConst(x: value.geti31()));
1199 }
1200 if (type.isString()) {
1201 // TODO: more than ascii support
1202 std::string string;
1203 for (auto c : value.getGCData()->values) {
1204 string.push_back(c.getInteger());
1205 }
1206 return makeStringConst(string: string);
1207 }
1208 if (type.isRef() && type.getHeapType() == HeapType::ext) {
1209 return makeRefAs(op: ExternExternalize,
1210 value: makeConstantExpression(value: value.internalize()));
1211 }
1212 TODO_SINGLE_COMPOUND(type);
1213 WASM_UNREACHABLE("unsupported constant expression");
1214 }
1215
1216 Expression* makeConstantExpression(Literals values) {
1217 assert(values.size() > 0);
1218 if (values.size() == 1) {
1219 return makeConstantExpression(values[0]);
1220 } else {
1221 std::vector<Expression*> consts;
1222 for (auto value : values) {
1223 consts.push_back(makeConstantExpression(value));
1224 }
1225 return makeTupleMake(consts);
1226 }
1227 }
1228
1229 // Additional utility functions for building on top of nodes
1230 // Convenient to have these on Builder, as it has allocation built in
1231
1232 static Index addParam(Function* func, Name name, Type type) {
1233 // only ok to add a param if no vars, otherwise indices are invalidated
1234 assert(func->localIndices.size() == func->getParams().size());
1235 assert(name.is());
1236 Signature sig = func->getSig();
1237 std::vector<Type> params(sig.params.begin(), sig.params.end());
1238 params.push_back(type);
1239 func->type = Signature(Type(params), sig.results);
1240 Index index = func->localNames.size();
1241 func->localIndices[name] = index;
1242 func->localNames[index] = name;
1243 return index;
1244 }
1245
1246 static Index addVar(Function* func, Name name, Type type) {
1247 // always ok to add a var, it does not affect other indices
1248 assert(type.isConcrete());
1249 Index index = func->getNumLocals();
1250 if (name.is()) {
1251 func->localIndices[name] = index;
1252 func->localNames[index] = name;
1253 }
1254 func->vars.emplace_back(type);
1255 return index;
1256 }
1257
1258 static Index addVar(Function* func, Type type) {
1259 return addVar(func, name: Name(), type);
1260 }
1261
1262 static void clearLocalNames(Function* func) {
1263 func->localNames.clear();
1264 func->localIndices.clear();
1265 }
1266
1267 // ensure a node is a block, if it isn't already, and optionally append to the
1268 // block
1269 Block* blockify(Expression* any, Expression* append = nullptr) {
1270 Block* block = nullptr;
1271 if (any) {
1272 block = any->dynCast<Block>();
1273 }
1274 if (!block) {
1275 block = makeBlock(first: any);
1276 }
1277 if (append) {
1278 block->list.push_back(append);
1279 block->finalize();
1280 }
1281 return block;
1282 }
1283
1284 template<typename... Ts>
1285 Block* blockify(Expression* any, Expression* append, Ts... args) {
1286 return blockify(blockify(any, append), args...);
1287 }
1288
1289 // ensure a node is a block, if it isn't already, and optionally append to the
1290 // block this variant sets a name for the block, so it will not reuse a block
1291 // already named
1292 Block*
1293 blockifyWithName(Expression* any, Name name, Expression* append = nullptr) {
1294 Block* block = nullptr;
1295 if (any) {
1296 block = any->dynCast<Block>();
1297 }
1298 if (!block || block->name.is()) {
1299 block = makeBlock(first: any);
1300 }
1301 block->name = name;
1302 if (append) {
1303 block->list.push_back(append);
1304 block->finalize();
1305 }
1306 return block;
1307 }
1308
1309 // a helper for the common pattern of a sequence of two expressions. Similar
1310 // to blockify, but does *not* reuse a block if the first is one.
1311 Block* makeSequence(Expression* left, Expression* right) {
1312 auto* block = makeBlock(first: left);
1313 block->list.push_back(right);
1314 block->finalize();
1315 return block;
1316 }
1317
1318 Block* makeSequence(Expression* left, Expression* right, Type type) {
1319 auto* block = makeBlock(first: left);
1320 block->list.push_back(right);
1321 block->finalize(type_: type);
1322 return block;
1323 }
1324
1325 // Drop an expression if it has a concrete type
1326 Expression* dropIfConcretelyTyped(Expression* curr) {
1327 if (!curr->type.isConcrete()) {
1328 return curr;
1329 }
1330 return makeDrop(value: curr);
1331 }
1332
1333 void flip(If* iff) {
1334 std::swap(iff->ifTrue, iff->ifFalse);
1335 iff->condition = makeUnary(op: EqZInt32, value: iff->condition);
1336 }
1337
1338 // Returns a replacement with the precise same type, and with minimal contents
1339 // as best we can. As a replacement, this may reuse the input node.
1340 template<typename T> Expression* replaceWithIdenticalType(T* curr) {
1341 if (curr->type.isTuple() && curr->type.isDefaultable()) {
1342 return makeConstantExpression(Literal::makeZeros(type: curr->type));
1343 }
1344 if (curr->type.isNullable() && curr->type.isNull()) {
1345 return ExpressionManipulator::refNull(curr, curr->type);
1346 }
1347 if (curr->type.isRef() && curr->type.getHeapType() == HeapType::i31) {
1348 Expression* ret = makeI31New(value: makeConst(x: 0));
1349 if (curr->type.isNullable()) {
1350 // To keep the type identical, wrap it in a block that adds nullability.
1351 ret = makeBlock({ret}, curr->type);
1352 }
1353 return ret;
1354 }
1355 if (!curr->type.isBasic()) {
1356 // We can't do any better, keep the original.
1357 return curr;
1358 }
1359 Literal value;
1360 // TODO: reuse node conditionally when possible for literals
1361 switch (curr->type.getBasic()) {
1362 case Type::i32:
1363 value = Literal(int32_t(0));
1364 break;
1365 case Type::i64:
1366 value = Literal(int64_t(0));
1367 break;
1368 case Type::f32:
1369 value = Literal(float(0));
1370 break;
1371 case Type::f64:
1372 value = Literal(double(0));
1373 break;
1374 case Type::v128: {
1375 std::array<uint8_t, 16> bytes;
1376 bytes.fill(0);
1377 value = Literal(bytes.data());
1378 break;
1379 }
1380 case Type::none:
1381 return ExpressionManipulator::nop(curr);
1382 case Type::unreachable:
1383 return ExpressionManipulator::unreachable(curr);
1384 }
1385 return makeConst(value);
1386 }
1387};
1388
1389} // namespace wasm
1390
1391#endif // wasm_wasm_builder_h
1392

source code of dart_sdk/third_party/binaryen/src/src/wasm-builder.h