1 /*
2 * Copyright 2015 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 //
18 // Parses and emits WebAssembly binary code
19 //
20
21 #ifndef wasm_wasm_binary_h
22 #define wasm_wasm_binary_h
23
24 #include <cassert>
25 #include <ostream>
26 #include <type_traits>
27
28 #include "asm_v_wasm.h"
29 #include "asmjs/shared-constants.h"
30 #include "ir/import-utils.h"
31 #include "ir/module-utils.h"
32 #include "parsing.h"
33 #include "support/debug.h"
34 #include "wasm-builder.h"
35 #include "wasm-traversal.h"
36 #include "wasm-validator.h"
37 #include "wasm.h"
38
39 #define DEBUG_TYPE "binary"
40
41 namespace wasm {
42
43 enum {
44 // the maximum amount of bytes we emit per LEB
45 MaxLEB32Bytes = 5,
46 };
47
48 // wasm VMs on the web have decided to impose some limits on what they
49 // accept
50 enum WebLimitations : uint32_t {
51 MaxDataSegments = 100 * 1000,
52 MaxFunctionBodySize = 128 * 1024,
53 MaxFunctionLocals = 50 * 1000
54 };
55
56 template<typename T, typename MiniT> struct LEB {
57 static_assert(sizeof(MiniT) == 1, "MiniT must be a byte");
58
59 T value;
60
61 LEB() = default;
LEBLEB62 LEB(T value) : value(value) {}
63
hasMoreLEB64 bool hasMore(T temp, MiniT byte) {
65 // for signed, we must ensure the last bit has the right sign, as it will
66 // zero extend
67 return std::is_signed<T>::value
68 ? (temp != 0 && temp != T(-1)) || (value >= 0 && (byte & 64)) ||
69 (value < 0 && !(byte & 64))
70 : (temp != 0);
71 }
72
writeLEB73 void write(std::vector<uint8_t>* out) {
74 T temp = value;
75 bool more;
76 do {
77 uint8_t byte = temp & 127;
78 temp >>= 7;
79 more = hasMore(temp, byte);
80 if (more) {
81 byte = byte | 128;
82 }
83 out->push_back(byte);
84 } while (more);
85 }
86
87 // @minimum: a minimum number of bytes to write, padding as necessary
88 // returns the number of bytes written
89 size_t writeAt(std::vector<uint8_t>* out, size_t at, size_t minimum = 0) {
90 T temp = value;
91 size_t offset = 0;
92 bool more;
93 do {
94 uint8_t byte = temp & 127;
95 temp >>= 7;
96 more = hasMore(temp, byte) || offset + 1 < minimum;
97 if (more) {
98 byte = byte | 128;
99 }
100 (*out)[at + offset] = byte;
101 offset++;
102 } while (more);
103 return offset;
104 }
105
readLEB106 LEB<T, MiniT>& read(std::function<MiniT()> get) {
107 value = 0;
108 T shift = 0;
109 MiniT byte;
110 while (1) {
111 byte = get();
112 bool last = !(byte & 128);
113 T payload = byte & 127;
114 typedef typename std::make_unsigned<T>::type mask_type;
115 auto shift_mask = 0 == shift
116 ? ~mask_type(0)
117 : ((mask_type(1) << (sizeof(T) * 8 - shift)) - 1u);
118 T significant_payload = payload & shift_mask;
119 if (significant_payload != payload) {
120 if (!(std::is_signed<T>::value && last)) {
121 throw ParseException("LEB dropped bits only valid for signed LEB");
122 }
123 }
124 value |= significant_payload << shift;
125 if (last) {
126 break;
127 }
128 shift += 7;
129 if (size_t(shift) >= sizeof(T) * 8) {
130 throw ParseException("LEB overflow");
131 }
132 }
133 // If signed LEB, then we might need to sign-extend. (compile should
134 // optimize this out if not needed).
135 if (std::is_signed<T>::value) {
136 shift += 7;
137 if ((byte & 64) && size_t(shift) < 8 * sizeof(T)) {
138 size_t sext_bits = 8 * sizeof(T) - size_t(shift);
139 value <<= sext_bits;
140 value >>= sext_bits;
141 if (value >= 0) {
142 throw ParseException(
143 " LEBsign-extend should produce a negative value");
144 }
145 }
146 }
147 return *this;
148 }
149 };
150
151 typedef LEB<uint32_t, uint8_t> U32LEB;
152 typedef LEB<uint64_t, uint8_t> U64LEB;
153 typedef LEB<int32_t, int8_t> S32LEB;
154 typedef LEB<int64_t, int8_t> S64LEB;
155
156 //
157 // We mostly stream into a buffer as we create the binary format, however,
158 // sometimes we need to backtrack and write to a location behind us - wasm
159 // is optimized for reading, not writing.
160 //
161 class BufferWithRandomAccess : public std::vector<uint8_t> {
162 public:
163 BufferWithRandomAccess() = default;
164
165 BufferWithRandomAccess& operator<<(int8_t x) {
166 BYN_TRACE("writeInt8: " << (int)(uint8_t)x << " (at " << size() << ")\n");
167 push_back(x);
168 return *this;
169 }
170 BufferWithRandomAccess& operator<<(int16_t x) {
171 BYN_TRACE("writeInt16: " << x << " (at " << size() << ")\n");
172 push_back(x & 0xff);
173 push_back(x >> 8);
174 return *this;
175 }
176 BufferWithRandomAccess& operator<<(int32_t x) {
177 BYN_TRACE("writeInt32: " << x << " (at " << size() << ")\n");
178 push_back(x & 0xff);
179 x >>= 8;
180 push_back(x & 0xff);
181 x >>= 8;
182 push_back(x & 0xff);
183 x >>= 8;
184 push_back(x & 0xff);
185 return *this;
186 }
187 BufferWithRandomAccess& operator<<(int64_t x) {
188 BYN_TRACE("writeInt64: " << x << " (at " << size() << ")\n");
189 push_back(x & 0xff);
190 x >>= 8;
191 push_back(x & 0xff);
192 x >>= 8;
193 push_back(x & 0xff);
194 x >>= 8;
195 push_back(x & 0xff);
196 x >>= 8;
197 push_back(x & 0xff);
198 x >>= 8;
199 push_back(x & 0xff);
200 x >>= 8;
201 push_back(x & 0xff);
202 x >>= 8;
203 push_back(x & 0xff);
204 return *this;
205 }
206 BufferWithRandomAccess& operator<<(U32LEB x) {
207 size_t before = -1;
208 WASM_UNUSED(before);
209 BYN_DEBUG(before = size(); std::cerr << "writeU32LEB: " << x.value
210 << " (at " << before << ")"
211 << std::endl;);
212 x.write(this);
213 BYN_DEBUG(for (size_t i = before; i < size(); i++) {
214 std::cerr << " " << (int)at(i) << " (at " << i << ")\n";
215 });
216 return *this;
217 }
218 BufferWithRandomAccess& operator<<(U64LEB x) {
219 size_t before = -1;
220 WASM_UNUSED(before);
221 BYN_DEBUG(before = size(); std::cerr << "writeU64LEB: " << x.value
222 << " (at " << before << ")"
223 << std::endl;);
224 x.write(this);
225 BYN_DEBUG(for (size_t i = before; i < size(); i++) {
226 std::cerr << " " << (int)at(i) << " (at " << i << ")\n";
227 });
228 return *this;
229 }
230 BufferWithRandomAccess& operator<<(S32LEB x) {
231 size_t before = -1;
232 WASM_UNUSED(before);
233 BYN_DEBUG(before = size(); std::cerr << "writeS32LEB: " << x.value
234 << " (at " << before << ")"
235 << std::endl;);
236 x.write(this);
237 BYN_DEBUG(for (size_t i = before; i < size(); i++) {
238 std::cerr << " " << (int)at(i) << " (at " << i << ")\n";
239 });
240 return *this;
241 }
242 BufferWithRandomAccess& operator<<(S64LEB x) {
243 size_t before = -1;
244 WASM_UNUSED(before);
245 BYN_DEBUG(before = size(); std::cerr << "writeS64LEB: " << x.value
246 << " (at " << before << ")"
247 << std::endl;);
248 x.write(this);
249 BYN_DEBUG(for (size_t i = before; i < size(); i++) {
250 std::cerr << " " << (int)at(i) << " (at " << i << ")\n";
251 });
252 return *this;
253 }
254
255 BufferWithRandomAccess& operator<<(uint8_t x) { return *this << (int8_t)x; }
256 BufferWithRandomAccess& operator<<(uint16_t x) { return *this << (int16_t)x; }
257 BufferWithRandomAccess& operator<<(uint32_t x) { return *this << (int32_t)x; }
258 BufferWithRandomAccess& operator<<(uint64_t x) { return *this << (int64_t)x; }
259
260 BufferWithRandomAccess& operator<<(float x) {
261 BYN_TRACE("writeFloat32: " << x << " (at " << size() << ")\n");
262 return *this << Literal(x).reinterpreti32();
263 }
264 BufferWithRandomAccess& operator<<(double x) {
265 BYN_TRACE("writeFloat64: " << x << " (at " << size() << ")\n");
266 return *this << Literal(x).reinterpreti64();
267 }
268
writeAt(size_t i,uint16_t x)269 void writeAt(size_t i, uint16_t x) {
270 BYN_TRACE("backpatchInt16: " << x << " (at " << i << ")\n");
271 (*this)[i] = x & 0xff;
272 (*this)[i + 1] = x >> 8;
273 }
writeAt(size_t i,uint32_t x)274 void writeAt(size_t i, uint32_t x) {
275 BYN_TRACE("backpatchInt32: " << x << " (at " << i << ")\n");
276 (*this)[i] = x & 0xff;
277 x >>= 8;
278 (*this)[i + 1] = x & 0xff;
279 x >>= 8;
280 (*this)[i + 2] = x & 0xff;
281 x >>= 8;
282 (*this)[i + 3] = x & 0xff;
283 }
284
285 // writes out an LEB to an arbitrary location. this writes the LEB as a full
286 // 5 bytes, the fixed amount that can easily be set aside ahead of time
writeAtFullFixedSize(size_t i,U32LEB x)287 void writeAtFullFixedSize(size_t i, U32LEB x) {
288 BYN_TRACE("backpatchU32LEB: " << x.value << " (at " << i << ")\n");
289 // fill all 5 bytes, we have to do this when backpatching
290 x.writeAt(this, i, MaxLEB32Bytes);
291 }
292 // writes out an LEB of normal size
293 // returns how many bytes were written
writeAt(size_t i,U32LEB x)294 size_t writeAt(size_t i, U32LEB x) {
295 BYN_TRACE("writeAtU32LEB: " << x.value << " (at " << i << ")\n");
296 return x.writeAt(this, i);
297 }
298
writeTo(T & o)299 template<typename T> void writeTo(T& o) {
300 for (auto c : *this) {
301 o << c;
302 }
303 }
304
getAsChars()305 std::vector<char> getAsChars() {
306 std::vector<char> ret;
307 ret.resize(size());
308 std::copy(begin(), end(), ret.begin());
309 return ret;
310 }
311 };
312
313 namespace BinaryConsts {
314
315 enum Meta { Magic = 0x6d736100, Version = 0x01 };
316
317 enum Section {
318 User = 0,
319 Type = 1,
320 Import = 2,
321 Function = 3,
322 Table = 4,
323 Memory = 5,
324 Global = 6,
325 Export = 7,
326 Start = 8,
327 Element = 9,
328 Code = 10,
329 Data = 11,
330 DataCount = 12,
331 Event = 13
332 };
333
334 enum SegmentFlag { IsPassive = 0x01, HasMemIndex = 0x02 };
335
336 enum EncodedType {
337 // value_type
338 i32 = -0x1, // 0x7f
339 i64 = -0x2, // 0x7e
340 f32 = -0x3, // 0x7d
341 f64 = -0x4, // 0x7c
342 v128 = -0x5, // 0x7b
343 // function reference type
344 funcref = -0x10, // 0x70
345 // opaque host reference type
346 externref = -0x11, // 0x6f
347 // any reference type
348 anyref = -0x12, // 0x6e
349 // comparable reference type
350 eqref = -0x13, // 0x6d
351 // integer reference type
352 i31ref = -0x16, // 0x6a
353 // exception reference type
354 exnref = -0x18, // 0x68
355 // func_type form
356 Func = -0x20, // 0x60
357 // block_type
358 Empty = -0x40 // 0x40
359 };
360
361 enum EncodedHeapType {
362 func = -0x10, // 0x70
363 extern_ = -0x11, // 0x6f
364 any = -0x12, // 0x6e
365 eq = -0x13, // 0x6d
366 i31 = -0x17, // 0x69, != i31ref
367 exn = -0x18, // 0x68
368 };
369
370 namespace UserSections {
371 extern const char* Name;
372 extern const char* SourceMapUrl;
373 extern const char* Dylink;
374 extern const char* Linking;
375 extern const char* Producers;
376 extern const char* TargetFeatures;
377
378 extern const char* AtomicsFeature;
379 extern const char* BulkMemoryFeature;
380 extern const char* ExceptionHandlingFeature;
381 extern const char* MutableGlobalsFeature;
382 extern const char* TruncSatFeature;
383 extern const char* SignExtFeature;
384 extern const char* SIMD128Feature;
385 extern const char* ExceptionHandlingFeature;
386 extern const char* TailCallFeature;
387 extern const char* ReferenceTypesFeature;
388 extern const char* MultivalueFeature;
389 extern const char* GCFeature;
390 extern const char* Memory64Feature;
391
392 enum Subsection {
393 NameModule = 0,
394 NameFunction = 1,
395 NameLocal = 2,
396 // see: https://github.com/WebAssembly/extended-name-section
397 NameLabel = 3,
398 NameType = 4,
399 NameTable = 5,
400 NameMemory = 6,
401 NameGlobal = 7,
402 NameElem = 8,
403 NameData = 9
404 };
405
406 } // namespace UserSections
407
408 enum ASTNodes {
409 Unreachable = 0x00,
410 Nop = 0x01,
411 Block = 0x02,
412 Loop = 0x03,
413 If = 0x04,
414 Else = 0x05,
415
416 End = 0x0b,
417 Br = 0x0c,
418 BrIf = 0x0d,
419 BrTable = 0x0e,
420 Return = 0x0f,
421
422 CallFunction = 0x10,
423 CallIndirect = 0x11,
424 RetCallFunction = 0x12,
425 RetCallIndirect = 0x13,
426
427 Drop = 0x1a,
428 Select = 0x1b,
429 SelectWithType = 0x1c, // added in reference types proposal
430
431 LocalGet = 0x20,
432 LocalSet = 0x21,
433 LocalTee = 0x22,
434 GlobalGet = 0x23,
435 GlobalSet = 0x24,
436
437 I32LoadMem = 0x28,
438 I64LoadMem = 0x29,
439 F32LoadMem = 0x2a,
440 F64LoadMem = 0x2b,
441
442 I32LoadMem8S = 0x2c,
443 I32LoadMem8U = 0x2d,
444 I32LoadMem16S = 0x2e,
445 I32LoadMem16U = 0x2f,
446 I64LoadMem8S = 0x30,
447 I64LoadMem8U = 0x31,
448 I64LoadMem16S = 0x32,
449 I64LoadMem16U = 0x33,
450 I64LoadMem32S = 0x34,
451 I64LoadMem32U = 0x35,
452
453 I32StoreMem = 0x36,
454 I64StoreMem = 0x37,
455 F32StoreMem = 0x38,
456 F64StoreMem = 0x39,
457
458 I32StoreMem8 = 0x3a,
459 I32StoreMem16 = 0x3b,
460 I64StoreMem8 = 0x3c,
461 I64StoreMem16 = 0x3d,
462 I64StoreMem32 = 0x3e,
463
464 MemorySize = 0x3f,
465 MemoryGrow = 0x40,
466
467 I32Const = 0x41,
468 I64Const = 0x42,
469 F32Const = 0x43,
470 F64Const = 0x44,
471
472 I32EqZ = 0x45,
473 I32Eq = 0x46,
474 I32Ne = 0x47,
475 I32LtS = 0x48,
476 I32LtU = 0x49,
477 I32GtS = 0x4a,
478 I32GtU = 0x4b,
479 I32LeS = 0x4c,
480 I32LeU = 0x4d,
481 I32GeS = 0x4e,
482 I32GeU = 0x4f,
483 I64EqZ = 0x50,
484 I64Eq = 0x51,
485 I64Ne = 0x52,
486 I64LtS = 0x53,
487 I64LtU = 0x54,
488 I64GtS = 0x55,
489 I64GtU = 0x56,
490 I64LeS = 0x57,
491 I64LeU = 0x58,
492 I64GeS = 0x59,
493 I64GeU = 0x5a,
494 F32Eq = 0x5b,
495 F32Ne = 0x5c,
496 F32Lt = 0x5d,
497 F32Gt = 0x5e,
498 F32Le = 0x5f,
499 F32Ge = 0x60,
500 F64Eq = 0x61,
501 F64Ne = 0x62,
502 F64Lt = 0x63,
503 F64Gt = 0x64,
504 F64Le = 0x65,
505 F64Ge = 0x66,
506
507 I32Clz = 0x67,
508 I32Ctz = 0x68,
509 I32Popcnt = 0x69,
510 I32Add = 0x6a,
511 I32Sub = 0x6b,
512 I32Mul = 0x6c,
513 I32DivS = 0x6d,
514 I32DivU = 0x6e,
515 I32RemS = 0x6f,
516 I32RemU = 0x70,
517 I32And = 0x71,
518 I32Or = 0x72,
519 I32Xor = 0x73,
520 I32Shl = 0x74,
521 I32ShrS = 0x75,
522 I32ShrU = 0x76,
523 I32RotL = 0x77,
524 I32RotR = 0x78,
525
526 I64Clz = 0x79,
527 I64Ctz = 0x7a,
528 I64Popcnt = 0x7b,
529 I64Add = 0x7c,
530 I64Sub = 0x7d,
531 I64Mul = 0x7e,
532 I64DivS = 0x7f,
533 I64DivU = 0x80,
534 I64RemS = 0x81,
535 I64RemU = 0x82,
536 I64And = 0x83,
537 I64Or = 0x84,
538 I64Xor = 0x85,
539 I64Shl = 0x86,
540 I64ShrS = 0x87,
541 I64ShrU = 0x88,
542 I64RotL = 0x89,
543 I64RotR = 0x8a,
544
545 F32Abs = 0x8b,
546 F32Neg = 0x8c,
547 F32Ceil = 0x8d,
548 F32Floor = 0x8e,
549 F32Trunc = 0x8f,
550 F32NearestInt = 0x90,
551 F32Sqrt = 0x91,
552 F32Add = 0x92,
553 F32Sub = 0x93,
554 F32Mul = 0x94,
555 F32Div = 0x95,
556 F32Min = 0x96,
557 F32Max = 0x97,
558 F32CopySign = 0x98,
559
560 F64Abs = 0x99,
561 F64Neg = 0x9a,
562 F64Ceil = 0x9b,
563 F64Floor = 0x9c,
564 F64Trunc = 0x9d,
565 F64NearestInt = 0x9e,
566 F64Sqrt = 0x9f,
567 F64Add = 0xa0,
568 F64Sub = 0xa1,
569 F64Mul = 0xa2,
570 F64Div = 0xa3,
571 F64Min = 0xa4,
572 F64Max = 0xa5,
573 F64CopySign = 0xa6,
574
575 I32WrapI64 = 0xa7,
576 I32STruncF32 = 0xa8,
577 I32UTruncF32 = 0xa9,
578 I32STruncF64 = 0xaa,
579 I32UTruncF64 = 0xab,
580 I64SExtendI32 = 0xac,
581 I64UExtendI32 = 0xad,
582 I64STruncF32 = 0xae,
583 I64UTruncF32 = 0xaf,
584 I64STruncF64 = 0xb0,
585 I64UTruncF64 = 0xb1,
586 F32SConvertI32 = 0xb2,
587 F32UConvertI32 = 0xb3,
588 F32SConvertI64 = 0xb4,
589 F32UConvertI64 = 0xb5,
590 F32DemoteI64 = 0xb6,
591 F64SConvertI32 = 0xb7,
592 F64UConvertI32 = 0xb8,
593 F64SConvertI64 = 0xb9,
594 F64UConvertI64 = 0xba,
595 F64PromoteF32 = 0xbb,
596
597 I32ReinterpretF32 = 0xbc,
598 I64ReinterpretF64 = 0xbd,
599 F32ReinterpretI32 = 0xbe,
600 F64ReinterpretI64 = 0xbf,
601
602 I32ExtendS8 = 0xc0,
603 I32ExtendS16 = 0xc1,
604 I64ExtendS8 = 0xc2,
605 I64ExtendS16 = 0xc3,
606 I64ExtendS32 = 0xc4,
607
608 // prefixes
609
610 GCPrefix = 0xfb,
611 MiscPrefix = 0xfc,
612 SIMDPrefix = 0xfd,
613 AtomicPrefix = 0xfe,
614
615 // atomic opcodes
616
617 AtomicNotify = 0x00,
618 I32AtomicWait = 0x01,
619 I64AtomicWait = 0x02,
620 AtomicFence = 0x03,
621
622 I32AtomicLoad = 0x10,
623 I64AtomicLoad = 0x11,
624 I32AtomicLoad8U = 0x12,
625 I32AtomicLoad16U = 0x13,
626 I64AtomicLoad8U = 0x14,
627 I64AtomicLoad16U = 0x15,
628 I64AtomicLoad32U = 0x16,
629 I32AtomicStore = 0x17,
630 I64AtomicStore = 0x18,
631 I32AtomicStore8 = 0x19,
632 I32AtomicStore16 = 0x1a,
633 I64AtomicStore8 = 0x1b,
634 I64AtomicStore16 = 0x1c,
635 I64AtomicStore32 = 0x1d,
636
637 AtomicRMWOps_Begin = 0x1e,
638 I32AtomicRMWAdd = 0x1e,
639 I64AtomicRMWAdd = 0x1f,
640 I32AtomicRMWAdd8U = 0x20,
641 I32AtomicRMWAdd16U = 0x21,
642 I64AtomicRMWAdd8U = 0x22,
643 I64AtomicRMWAdd16U = 0x23,
644 I64AtomicRMWAdd32U = 0x24,
645 I32AtomicRMWSub = 0x25,
646 I64AtomicRMWSub = 0x26,
647 I32AtomicRMWSub8U = 0x27,
648 I32AtomicRMWSub16U = 0x28,
649 I64AtomicRMWSub8U = 0x29,
650 I64AtomicRMWSub16U = 0x2a,
651 I64AtomicRMWSub32U = 0x2b,
652 I32AtomicRMWAnd = 0x2c,
653 I64AtomicRMWAnd = 0x2d,
654 I32AtomicRMWAnd8U = 0x2e,
655 I32AtomicRMWAnd16U = 0x2f,
656 I64AtomicRMWAnd8U = 0x30,
657 I64AtomicRMWAnd16U = 0x31,
658 I64AtomicRMWAnd32U = 0x32,
659 I32AtomicRMWOr = 0x33,
660 I64AtomicRMWOr = 0x34,
661 I32AtomicRMWOr8U = 0x35,
662 I32AtomicRMWOr16U = 0x36,
663 I64AtomicRMWOr8U = 0x37,
664 I64AtomicRMWOr16U = 0x38,
665 I64AtomicRMWOr32U = 0x39,
666 I32AtomicRMWXor = 0x3a,
667 I64AtomicRMWXor = 0x3b,
668 I32AtomicRMWXor8U = 0x3c,
669 I32AtomicRMWXor16U = 0x3d,
670 I64AtomicRMWXor8U = 0x3e,
671 I64AtomicRMWXor16U = 0x3f,
672 I64AtomicRMWXor32U = 0x40,
673 I32AtomicRMWXchg = 0x41,
674 I64AtomicRMWXchg = 0x42,
675 I32AtomicRMWXchg8U = 0x43,
676 I32AtomicRMWXchg16U = 0x44,
677 I64AtomicRMWXchg8U = 0x45,
678 I64AtomicRMWXchg16U = 0x46,
679 I64AtomicRMWXchg32U = 0x47,
680 AtomicRMWOps_End = 0x47,
681
682 AtomicCmpxchgOps_Begin = 0x48,
683 I32AtomicCmpxchg = 0x48,
684 I64AtomicCmpxchg = 0x49,
685 I32AtomicCmpxchg8U = 0x4a,
686 I32AtomicCmpxchg16U = 0x4b,
687 I64AtomicCmpxchg8U = 0x4c,
688 I64AtomicCmpxchg16U = 0x4d,
689 I64AtomicCmpxchg32U = 0x4e,
690 AtomicCmpxchgOps_End = 0x4e,
691
692 // truncsat opcodes
693
694 I32STruncSatF32 = 0x00,
695 I32UTruncSatF32 = 0x01,
696 I32STruncSatF64 = 0x02,
697 I32UTruncSatF64 = 0x03,
698 I64STruncSatF32 = 0x04,
699 I64UTruncSatF32 = 0x05,
700 I64STruncSatF64 = 0x06,
701 I64UTruncSatF64 = 0x07,
702
703 // SIMD opcodes
704
705 V128Load = 0x00,
706 I16x8LoadExtSVec8x8 = 0x01,
707 I16x8LoadExtUVec8x8 = 0x02,
708 I32x4LoadExtSVec16x4 = 0x03,
709 I32x4LoadExtUVec16x4 = 0x04,
710 I64x2LoadExtSVec32x2 = 0x05,
711 I64x2LoadExtUVec32x2 = 0x06,
712 V8x16LoadSplat = 0x07,
713 V16x8LoadSplat = 0x08,
714 V32x4LoadSplat = 0x09,
715 V64x2LoadSplat = 0x0a,
716 V128Store = 0x0b,
717
718 V128Const = 0x0c,
719 V8x16Shuffle = 0x0d,
720 V8x16Swizzle = 0x0e,
721
722 I8x16Splat = 0x0f,
723 I16x8Splat = 0x10,
724 I32x4Splat = 0x11,
725 I64x2Splat = 0x12,
726 F32x4Splat = 0x13,
727 F64x2Splat = 0x14,
728
729 I8x16ExtractLaneS = 0x15,
730 I8x16ExtractLaneU = 0x16,
731 I8x16ReplaceLane = 0x17,
732 I16x8ExtractLaneS = 0x18,
733 I16x8ExtractLaneU = 0x19,
734 I16x8ReplaceLane = 0x1a,
735 I32x4ExtractLane = 0x1b,
736 I32x4ReplaceLane = 0x1c,
737 I64x2ExtractLane = 0x1d,
738 I64x2ReplaceLane = 0x1e,
739 F32x4ExtractLane = 0x1f,
740 F32x4ReplaceLane = 0x20,
741 F64x2ExtractLane = 0x21,
742 F64x2ReplaceLane = 0x22,
743
744 I8x16Eq = 0x23,
745 I8x16Ne = 0x24,
746 I8x16LtS = 0x25,
747 I8x16LtU = 0x26,
748 I8x16GtS = 0x27,
749 I8x16GtU = 0x28,
750 I8x16LeS = 0x29,
751 I8x16LeU = 0x2a,
752 I8x16GeS = 0x2b,
753 I8x16GeU = 0x2c,
754 I16x8Eq = 0x2d,
755 I16x8Ne = 0x2e,
756 I16x8LtS = 0x2f,
757 I16x8LtU = 0x30,
758 I16x8GtS = 0x31,
759 I16x8GtU = 0x32,
760 I16x8LeS = 0x33,
761 I16x8LeU = 0x34,
762 I16x8GeS = 0x35,
763 I16x8GeU = 0x36,
764 I32x4Eq = 0x37,
765 I32x4Ne = 0x38,
766 I32x4LtS = 0x39,
767 I32x4LtU = 0x3a,
768 I32x4GtS = 0x3b,
769 I32x4GtU = 0x3c,
770 I32x4LeS = 0x3d,
771 I32x4LeU = 0x3e,
772 I32x4GeS = 0x3f,
773 I32x4GeU = 0x40,
774 F32x4Eq = 0x41,
775 F32x4Ne = 0x42,
776 F32x4Lt = 0x43,
777 F32x4Gt = 0x44,
778 F32x4Le = 0x45,
779 F32x4Ge = 0x46,
780 F64x2Eq = 0x47,
781 F64x2Ne = 0x48,
782 F64x2Lt = 0x49,
783 F64x2Gt = 0x4a,
784 F64x2Le = 0x4b,
785 F64x2Ge = 0x4c,
786
787 V128Not = 0x4d,
788 V128And = 0x4e,
789 V128AndNot = 0x4f,
790 V128Or = 0x50,
791 V128Xor = 0x51,
792 V128Bitselect = 0x52,
793
794 I8x16Abs = 0x60,
795 I8x16Neg = 0x61,
796 I8x16AnyTrue = 0x62,
797 I8x16AllTrue = 0x63,
798 I8x16Bitmask = 0x64,
799 I8x16NarrowSI16x8 = 0x65,
800 I8x16NarrowUI16x8 = 0x66,
801 I8x16Shl = 0x6b,
802 I8x16ShrS = 0x6c,
803 I8x16ShrU = 0x6d,
804 I8x16Add = 0x6e,
805 I8x16AddSatS = 0x6f,
806 I8x16AddSatU = 0x70,
807 I8x16Sub = 0x71,
808 I8x16SubSatS = 0x72,
809 I8x16SubSatU = 0x73,
810 I8x16Mul = 0x75,
811 I8x16MinS = 0x76,
812 I8x16MinU = 0x77,
813 I8x16MaxS = 0x78,
814 I8x16MaxU = 0x79,
815 I8x16AvgrU = 0x7b,
816
817 I16x8Abs = 0x80,
818 I16x8Neg = 0x81,
819 I16x8AnyTrue = 0x82,
820 I16x8AllTrue = 0x83,
821 I16x8Bitmask = 0x84,
822 I16x8NarrowSI32x4 = 0x85,
823 I16x8NarrowUI32x4 = 0x86,
824 I16x8WidenLowSI8x16 = 0x87,
825 I16x8WidenHighSI8x16 = 0x88,
826 I16x8WidenLowUI8x16 = 0x89,
827 I16x8WidenHighUI8x16 = 0x8a,
828 I16x8Shl = 0x8b,
829 I16x8ShrS = 0x8c,
830 I16x8ShrU = 0x8d,
831 I16x8Add = 0x8e,
832 I16x8AddSatS = 0x8f,
833 I16x8AddSatU = 0x90,
834 I16x8Sub = 0x91,
835 I16x8SubSatS = 0x92,
836 I16x8SubSatU = 0x93,
837 I16x8Mul = 0x95,
838 I16x8MinS = 0x96,
839 I16x8MinU = 0x97,
840 I16x8MaxS = 0x98,
841 I16x8MaxU = 0x99,
842 I16x8AvgrU = 0x9b,
843
844 I32x4Abs = 0xa0,
845 I32x4Neg = 0xa1,
846 I32x4AnyTrue = 0xa2,
847 I32x4AllTrue = 0xa3,
848 I32x4Bitmask = 0xa4,
849 I32x4WidenLowSI16x8 = 0xa7,
850 I32x4WidenHighSI16x8 = 0xa8,
851 I32x4WidenLowUI16x8 = 0xa9,
852 I32x4WidenHighUI16x8 = 0xaa,
853 I32x4Shl = 0xab,
854 I32x4ShrS = 0xac,
855 I32x4ShrU = 0xad,
856 I32x4Add = 0xae,
857 I32x4Sub = 0xb1,
858 I32x4Mul = 0xb5,
859 I32x4MinS = 0xb6,
860 I32x4MinU = 0xb7,
861 I32x4MaxS = 0xb8,
862 I32x4MaxU = 0xb9,
863 I32x4DotSVecI16x8 = 0xba,
864
865 I64x2Neg = 0xc1,
866 I64x2AnyTrue = 0xc2,
867 I64x2AllTrue = 0xc3,
868 I64x2Shl = 0xcb,
869 I64x2ShrS = 0xcc,
870 I64x2ShrU = 0xcd,
871 I64x2Add = 0xce,
872 I64x2Sub = 0xd1,
873 I64x2Mul = 0xd5,
874
875 F32x4Abs = 0xe0,
876 F32x4Neg = 0xe1,
877 F32x4Sqrt = 0xe3,
878 F32x4Add = 0xe4,
879 F32x4Sub = 0xe5,
880 F32x4Mul = 0xe6,
881 F32x4Div = 0xe7,
882 F32x4Min = 0xe8,
883 F32x4Max = 0xe9,
884 F32x4PMin = 0xea,
885 F32x4PMax = 0xeb,
886
887 F32x4Ceil = 0xd8,
888 F32x4Floor = 0xd9,
889 F32x4Trunc = 0xda,
890 F32x4Nearest = 0xdb,
891 F64x2Ceil = 0xdc,
892 F64x2Floor = 0xdd,
893 F64x2Trunc = 0xde,
894 F64x2Nearest = 0xdf,
895
896 F64x2Abs = 0xec,
897 F64x2Neg = 0xed,
898 F64x2Sqrt = 0xef,
899 F64x2Add = 0xf0,
900 F64x2Sub = 0xf1,
901 F64x2Mul = 0xf2,
902 F64x2Div = 0xf3,
903 F64x2Min = 0xf4,
904 F64x2Max = 0xf5,
905 F64x2PMin = 0xf6,
906 F64x2PMax = 0xf7,
907
908 I32x4TruncSatSF32x4 = 0xf8,
909 I32x4TruncSatUF32x4 = 0xf9,
910 F32x4ConvertSI32x4 = 0xfa,
911 F32x4ConvertUI32x4 = 0xfb,
912
913 V128Load32Zero = 0xfc,
914 V128Load64Zero = 0xfd,
915
916 F32x4QFMA = 0xb4,
917 F32x4QFMS = 0xd4,
918 F64x2QFMA = 0xfe,
919 F64x2QFMS = 0xff,
920
921 I64x2TruncSatSF64x2 = 0x0100,
922 I64x2TruncSatUF64x2 = 0x0101,
923 F64x2ConvertSI64x2 = 0x0102,
924 F64x2ConvertUI64x2 = 0x0103,
925
926 // bulk memory opcodes
927
928 MemoryInit = 0x08,
929 DataDrop = 0x09,
930 MemoryCopy = 0x0a,
931 MemoryFill = 0x0b,
932
933 // reference types opcodes
934
935 RefNull = 0xd0,
936 RefIsNull = 0xd1,
937 RefFunc = 0xd2,
938
939 // exception handling opcodes
940
941 Try = 0x06,
942 Catch = 0x07,
943 Throw = 0x08,
944 Rethrow = 0x09,
945 BrOnExn = 0x0a,
946
947 // gc opcodes
948
949 RefEq = 0xd5,
950 StructNewWithRtt = 0x01,
951 StructNewDefaultWithRtt = 0x02,
952 StructGet = 0x03,
953 StructGetS = 0x04,
954 StructGetU = 0x05,
955 StructSet = 0x06,
956 ArrayNewWithRtt = 0x11,
957 ArrayNewDefaultWithRtt = 0x12,
958 ArrayGet = 0x13,
959 ArrayGetS = 0x14,
960 ArrayGetU = 0x15,
961 ArraySet = 0x16,
962 ArrayLen = 0x17,
963 I31New = 0x20,
964 I31GetS = 0x21,
965 I31GetU = 0x22,
966 RttCanon = 0x30,
967 RttSub = 0x31,
968 RefTest = 0x40,
969 RefCast = 0x41,
970 BrOnCast = 0x42
971 };
972
973 enum MemoryAccess {
974 Offset = 0x10, // bit 4
975 Alignment = 0x80, // bit 7
976 NaturalAlignment = 0
977 };
978
979 enum MemoryFlags { HasMaximum = 1 << 0, IsShared = 1 << 1, Is64 = 1 << 2 };
980
981 enum FeaturePrefix {
982 FeatureUsed = '+',
983 FeatureRequired = '=',
984 FeatureDisallowed = '-'
985 };
986
987 } // namespace BinaryConsts
988
binaryType(Type type)989 inline S32LEB binaryType(Type type) {
990 int ret = 0;
991 TODO_SINGLE_COMPOUND(type);
992 switch (type.getBasic()) {
993 // None only used for block signatures. TODO: Separate out?
994 case Type::none:
995 ret = BinaryConsts::EncodedType::Empty;
996 break;
997 case Type::i32:
998 ret = BinaryConsts::EncodedType::i32;
999 break;
1000 case Type::i64:
1001 ret = BinaryConsts::EncodedType::i64;
1002 break;
1003 case Type::f32:
1004 ret = BinaryConsts::EncodedType::f32;
1005 break;
1006 case Type::f64:
1007 ret = BinaryConsts::EncodedType::f64;
1008 break;
1009 case Type::v128:
1010 ret = BinaryConsts::EncodedType::v128;
1011 break;
1012 case Type::funcref:
1013 ret = BinaryConsts::EncodedType::funcref;
1014 break;
1015 case Type::externref:
1016 ret = BinaryConsts::EncodedType::externref;
1017 break;
1018 case Type::exnref:
1019 ret = BinaryConsts::EncodedType::exnref;
1020 break;
1021 case Type::anyref:
1022 ret = BinaryConsts::EncodedType::anyref;
1023 break;
1024 case Type::eqref:
1025 ret = BinaryConsts::EncodedType::eqref;
1026 break;
1027 case Type::i31ref:
1028 ret = BinaryConsts::EncodedType::i31ref;
1029 break;
1030 case Type::unreachable:
1031 WASM_UNREACHABLE("unexpected type");
1032 }
1033 return S32LEB(ret);
1034 }
1035
binaryHeapType(HeapType type)1036 inline S32LEB binaryHeapType(HeapType type) {
1037 int ret = 0;
1038 switch (type.kind) {
1039 case HeapType::FuncKind:
1040 ret = BinaryConsts::EncodedHeapType::func;
1041 break;
1042 case HeapType::ExternKind:
1043 ret = BinaryConsts::EncodedHeapType::extern_;
1044 break;
1045 case HeapType::ExnKind:
1046 ret = BinaryConsts::EncodedHeapType::exn;
1047 break;
1048 case HeapType::AnyKind:
1049 ret = BinaryConsts::EncodedHeapType::any;
1050 break;
1051 case HeapType::EqKind:
1052 ret = BinaryConsts::EncodedHeapType::eq;
1053 break;
1054 case HeapType::I31Kind:
1055 ret = BinaryConsts::EncodedHeapType::i31;
1056 break;
1057 case HeapType::SignatureKind:
1058 case HeapType::StructKind:
1059 case HeapType::ArrayKind:
1060 WASM_UNREACHABLE("TODO: compound GC types");
1061 }
1062 return S32LEB(ret); // TODO: Actually encoded as s33
1063 }
1064
1065 // Writes out wasm to the binary format
1066
1067 class WasmBinaryWriter {
1068 // Computes the indexes in a wasm binary, i.e., with function imports
1069 // and function implementations sharing a single index space, etc.,
1070 // and with the imports first (the Module's functions and globals
1071 // arrays are not assumed to be in a particular order, so we can't
1072 // just use them directly).
1073 struct BinaryIndexes {
1074 std::unordered_map<Name, Index> functionIndexes;
1075 std::unordered_map<Name, Index> eventIndexes;
1076 std::unordered_map<Name, Index> globalIndexes;
1077
BinaryIndexesBinaryIndexes1078 BinaryIndexes(Module& wasm) {
1079 auto addIndexes = [&](auto& source, auto& indexes) {
1080 auto addIndex = [&](auto* curr) {
1081 auto index = indexes.size();
1082 indexes[curr->name] = index;
1083 };
1084 for (auto& curr : source) {
1085 if (curr->imported()) {
1086 addIndex(curr.get());
1087 }
1088 }
1089 for (auto& curr : source) {
1090 if (!curr->imported()) {
1091 addIndex(curr.get());
1092 }
1093 }
1094 };
1095 addIndexes(wasm.functions, functionIndexes);
1096 addIndexes(wasm.events, eventIndexes);
1097
1098 // Globals may have tuple types in the IR, in which case they lower to
1099 // multiple globals, one for each tuple element, in the binary. Tuple
1100 // globals therefore occupy multiple binary indices, and we have to take
1101 // that into account when calculating indices.
1102 Index globalCount = 0;
1103 auto addGlobal = [&](auto* curr) {
1104 globalIndexes[curr->name] = globalCount;
1105 globalCount += curr->type.size();
1106 };
1107 for (auto& curr : wasm.globals) {
1108 if (curr->imported()) {
1109 addGlobal(curr.get());
1110 }
1111 }
1112 for (auto& curr : wasm.globals) {
1113 if (!curr->imported()) {
1114 addGlobal(curr.get());
1115 }
1116 }
1117 }
1118 };
1119
1120 public:
WasmBinaryWriter(Module * input,BufferWithRandomAccess & o)1121 WasmBinaryWriter(Module* input, BufferWithRandomAccess& o)
1122 : wasm(input), o(o), indexes(*input) {
1123 prepare();
1124 }
1125
1126 // locations in the output binary for the various parts of the module
1127 struct TableOfContents {
1128 struct Entry {
1129 Name name;
1130 size_t offset; // where the entry starts
1131 size_t size; // the size of the entry
EntryTableOfContents::Entry1132 Entry(Name name, size_t offset, size_t size)
1133 : name(name), offset(offset), size(size) {}
1134 };
1135 std::vector<Entry> functionBodies;
1136 } tableOfContents;
1137
setNamesSection(bool set)1138 void setNamesSection(bool set) { debugInfo = set; }
setSourceMap(std::ostream * set,std::string url)1139 void setSourceMap(std::ostream* set, std::string url) {
1140 sourceMap = set;
1141 sourceMapUrl = url;
1142 }
setSymbolMap(std::string set)1143 void setSymbolMap(std::string set) { symbolMap = set; }
1144
1145 void write();
1146 void writeHeader();
1147 int32_t writeU32LEBPlaceholder();
1148 void writeResizableLimits(
1149 Address initial, Address maximum, bool hasMaximum, bool shared, bool is64);
1150 template<typename T> int32_t startSection(T code);
1151 void finishSection(int32_t start);
1152 int32_t startSubsection(BinaryConsts::UserSections::Subsection code);
1153 void finishSubsection(int32_t start);
1154 void writeStart();
1155 void writeMemory();
1156 void writeTypes();
1157 void writeImports();
1158
1159 void writeFunctionSignatures();
1160 void writeExpression(Expression* curr);
1161 void writeFunctions();
1162 void writeGlobals();
1163 void writeExports();
1164 void writeDataCount();
1165 void writeDataSegments();
1166 void writeEvents();
1167
1168 uint32_t getFunctionIndex(Name name) const;
1169 uint32_t getGlobalIndex(Name name) const;
1170 uint32_t getEventIndex(Name name) const;
1171 uint32_t getTypeIndex(Signature sig) const;
1172
1173 void writeFunctionTableDeclaration();
1174 void writeTableElements();
1175 void writeNames();
1176 void writeSourceMapUrl();
1177 void writeSymbolMap();
1178 void writeLateUserSections();
1179 void writeUserSection(const UserSection& section);
1180 void writeFeaturesSection();
1181 void writeDylinkSection();
1182
1183 void initializeDebugInfo();
1184 void writeSourceMapProlog();
1185 void writeSourceMapEpilog();
1186 void writeDebugLocation(const Function::DebugLocation& loc);
1187 void writeDebugLocation(Expression* curr, Function* func);
1188 void writeDebugLocationEnd(Expression* curr, Function* func);
1189 void writeExtraDebugLocation(Expression* curr,
1190 Function* func,
1191 BinaryLocations::DelimiterId id);
1192
1193 // helpers
1194 void writeInlineString(const char* name);
1195 void writeEscapedName(const char* name);
1196 void writeInlineBuffer(const char* data, size_t size);
1197
1198 struct Buffer {
1199 const char* data;
1200 size_t size;
1201 size_t pointerLocation;
BufferBuffer1202 Buffer(const char* data, size_t size, size_t pointerLocation)
1203 : data(data), size(size), pointerLocation(pointerLocation) {}
1204 };
1205
1206 std::vector<Buffer> buffersToWrite;
1207
1208 void emitBuffer(const char* data, size_t size);
1209 void emitString(const char* str);
1210 void finishUp();
1211
getModule()1212 Module* getModule() { return wasm; }
1213
1214 private:
1215 Module* wasm;
1216 BufferWithRandomAccess& o;
1217 BinaryIndexes indexes;
1218 std::unordered_map<Signature, Index> typeIndices;
1219 std::vector<Signature> types;
1220
1221 bool debugInfo = true;
1222 std::ostream* sourceMap = nullptr;
1223 std::string sourceMapUrl;
1224 std::string symbolMap;
1225
1226 MixedArena allocator;
1227
1228 // storage of source map locations until the section is placed at its final
1229 // location (shrinking LEBs may cause changes there)
1230 std::vector<std::pair<size_t, const Function::DebugLocation*>>
1231 sourceMapLocations;
1232 size_t sourceMapLocationsSizeAtSectionStart;
1233 Function::DebugLocation lastDebugLocation;
1234
1235 std::unique_ptr<ImportInfo> importInfo;
1236
1237 // General debugging info: track locations as we write.
1238 BinaryLocations binaryLocations;
1239 size_t binaryLocationsSizeAtSectionStart;
1240 // Track the expressions that we added for the current function being
1241 // written, so that we can update those specific binary locations when
1242 // the function is written out.
1243 std::vector<Expression*> binaryLocationTrackedExpressionsForFunc;
1244
1245 void prepare();
1246 };
1247
1248 class WasmBinaryBuilder {
1249 Module& wasm;
1250 MixedArena& allocator;
1251 const std::vector<char>& input;
1252 std::istream* sourceMap;
1253 std::pair<uint32_t, Function::DebugLocation> nextDebugLocation;
1254 bool DWARF = false;
1255
1256 size_t pos = 0;
1257 Index startIndex = -1;
1258 std::set<Function::DebugLocation> debugLocation;
1259 size_t codeSectionLocation;
1260
1261 std::set<BinaryConsts::Section> seenSections;
1262
1263 // All signatures present in the type section
1264 std::vector<Signature> signatures;
1265
1266 public:
WasmBinaryBuilder(Module & wasm,const std::vector<char> & input)1267 WasmBinaryBuilder(Module& wasm, const std::vector<char>& input)
1268 : wasm(wasm), allocator(wasm.allocator), input(input), sourceMap(nullptr),
1269 nextDebugLocation(0, {0, 0, 0}), debugLocation() {}
1270
setDWARF(bool value)1271 void setDWARF(bool value) { DWARF = value; }
1272 void read();
1273 void readUserSection(size_t payloadLen);
1274
more()1275 bool more() { return pos < input.size(); }
1276
1277 uint8_t getInt8();
1278 uint16_t getInt16();
1279 uint32_t getInt32();
1280 uint64_t getInt64();
1281 uint8_t getLaneIndex(size_t lanes);
1282 // it is unsafe to return a float directly, due to ABI issues with the
1283 // signalling bit
1284 Literal getFloat32Literal();
1285 Literal getFloat64Literal();
1286 Literal getVec128Literal();
1287 uint32_t getU32LEB();
1288 uint64_t getU64LEB();
1289 int32_t getS32LEB();
1290 int64_t getS64LEB();
1291 Type getType();
1292 HeapType getHeapType();
1293 Type getConcreteType();
1294 Name getInlineString();
1295 void verifyInt8(int8_t x);
1296 void verifyInt16(int16_t x);
1297 void verifyInt32(int32_t x);
1298 void verifyInt64(int64_t x);
1299 void ungetInt8();
1300 void readHeader();
1301 void readStart();
1302 void readMemory();
1303 void readSignatures();
1304
1305 // gets a name in the combined import+defined space
1306 Name getFunctionName(Index index);
1307 Name getGlobalName(Index index);
1308 Name getEventName(Index index);
1309
1310 void getResizableLimits(Address& initial,
1311 Address& max,
1312 bool& shared,
1313 Type& indexType,
1314 Address defaultIfNoMax);
1315 void readImports();
1316
1317 // The signatures of each function, given in the function section
1318 std::vector<Signature> functionSignatures;
1319
1320 void readFunctionSignatures();
1321 size_t nextLabel;
1322
1323 Name getNextLabel();
1324
1325 // We read functions and globals before we know their names, so we need to
1326 // backpatch the names later
1327
1328 // we store functions here before wasm.addFunction after we know their names
1329 std::vector<Function*> functions;
1330 // we store function imports here before wasm.addFunctionImport after we know
1331 // their names
1332 std::vector<Function*> functionImports;
1333 // at index i we have all refs to the function i
1334 std::map<Index, std::vector<Expression*>> functionRefs;
1335 Function* currFunction = nullptr;
1336 // before we see a function (like global init expressions), there is no end of
1337 // function to check
1338 Index endOfFunction = -1;
1339
1340 // we store globals here before wasm.addGlobal after we know their names
1341 std::vector<Global*> globals;
1342 // we store global imports here before wasm.addGlobalImport after we know
1343 // their names
1344 std::vector<Global*> globalImports;
1345 // at index i we have all refs to the global i
1346 std::map<Index, std::vector<Expression*>> globalRefs;
1347
1348 // Throws a parsing error if we are not in a function context
1349 void requireFunctionContext(const char* error);
1350
1351 void readFunctions();
1352
1353 std::map<Export*, Index> exportIndices;
1354 std::vector<Export*> exportOrder;
1355 void readExports();
1356
1357 Expression* readExpression();
1358 void readGlobals();
1359
1360 struct BreakTarget {
1361 Name name;
1362 Type type;
BreakTargetBreakTarget1363 BreakTarget(Name name, Type type) : name(name), type(type) {}
1364 };
1365 std::vector<BreakTarget> breakStack;
1366 // the names that breaks target. this lets us know if a block has breaks to it
1367 // or not.
1368 std::unordered_set<Name> breakTargetNames;
1369
1370 std::vector<Expression*> expressionStack;
1371
1372 // Control flow structure parsing: these have not just the normal binary
1373 // data for an instruction, but also some bytes later on like "end" or "else".
1374 // We must be aware of the connection between those things, for debug info.
1375 std::vector<Expression*> controlFlowStack;
1376
1377 // Called when we parse the beginning of a control flow structure.
1378 void startControlFlow(Expression* curr);
1379
1380 // Called when we parse a later part of a control flow structure, like "end"
1381 // or "else".
1382 void continueControlFlow(BinaryLocations::DelimiterId id, BinaryLocation pos);
1383
1384 // set when we know code is unreachable in the sense of the wasm spec: we are
1385 // in a block and after an unreachable element. this helps parse stacky wasm
1386 // code, which can be unsuitable for our IR when unreachable.
1387 bool unreachableInTheWasmSense;
1388
1389 // set when the current code being processed will not be emitted in the
1390 // output, which is the case when it is literally unreachable, for example,
1391 // (block $a
1392 // (unreachable)
1393 // (block $b
1394 // ;; code here is reachable in the wasm sense, even though $b as a whole
1395 // ;; is not
1396 // (unreachable)
1397 // ;; code here is unreachable in the wasm sense
1398 // )
1399 // )
1400 bool willBeIgnored;
1401
1402 BinaryConsts::ASTNodes lastSeparator = BinaryConsts::End;
1403
1404 // process a block-type scope, until an end or else marker, or the end of the
1405 // function
1406 void processExpressions();
1407 void skipUnreachableCode();
1408
1409 void pushExpression(Expression* curr);
1410 Expression* popExpression();
1411 Expression* popNonVoidExpression();
1412 Expression* popTuple(size_t numElems);
1413 Expression* popTypedExpression(Type type);
1414
1415 void validateBinary(); // validations that cannot be performed on the Module
1416 void processNames();
1417
1418 size_t dataCount = 0;
1419 bool hasDataCount = false;
1420
1421 void readDataSegments();
1422 void readDataCount();
1423
1424 std::map<Index, std::vector<Index>> functionTable;
1425
1426 void readFunctionTableDeclaration();
1427 void readTableElements();
1428
1429 void readEvents();
1430
1431 static Name escape(Name name);
1432 void readNames(size_t);
1433 void readFeatures(size_t);
1434 void readDylink(size_t);
1435
1436 // Debug information reading helpers
setDebugLocations(std::istream * sourceMap_)1437 void setDebugLocations(std::istream* sourceMap_) { sourceMap = sourceMap_; }
1438 std::unordered_map<std::string, Index> debugInfoFileIndices;
1439 void readNextDebugLocation();
1440 void readSourceMapHeader();
1441
1442 void handleBrOnExnNotTaken(Expression* curr);
1443
1444 // AST reading
1445 int depth = 0; // only for debugging
1446
1447 BinaryConsts::ASTNodes readExpression(Expression*& curr);
1448 void pushBlockElements(Block* curr, Type type, size_t start);
1449 void visitBlock(Block* curr);
1450
1451 // Gets a block of expressions. If it's just one, return that singleton.
1452 Expression* getBlockOrSingleton(Type type);
1453
1454 void visitIf(If* curr);
1455 void visitLoop(Loop* curr);
1456 BreakTarget getBreakTarget(int32_t offset);
1457 void visitBreak(Break* curr, uint8_t code);
1458 void visitSwitch(Switch* curr);
1459
1460 void visitCall(Call* curr);
1461 void visitCallIndirect(CallIndirect* curr);
1462 void visitLocalGet(LocalGet* curr);
1463 void visitLocalSet(LocalSet* curr, uint8_t code);
1464 void visitGlobalGet(GlobalGet* curr);
1465 void visitGlobalSet(GlobalSet* curr);
1466 void readMemoryAccess(Address& alignment, Address& offset);
1467 bool maybeVisitLoad(Expression*& out, uint8_t code, bool isAtomic);
1468 bool maybeVisitStore(Expression*& out, uint8_t code, bool isAtomic);
1469 bool maybeVisitNontrappingTrunc(Expression*& out, uint32_t code);
1470 bool maybeVisitAtomicRMW(Expression*& out, uint8_t code);
1471 bool maybeVisitAtomicCmpxchg(Expression*& out, uint8_t code);
1472 bool maybeVisitAtomicWait(Expression*& out, uint8_t code);
1473 bool maybeVisitAtomicNotify(Expression*& out, uint8_t code);
1474 bool maybeVisitAtomicFence(Expression*& out, uint8_t code);
1475 bool maybeVisitConst(Expression*& out, uint8_t code);
1476 bool maybeVisitUnary(Expression*& out, uint8_t code);
1477 bool maybeVisitBinary(Expression*& out, uint8_t code);
1478 bool maybeVisitTruncSat(Expression*& out, uint32_t code);
1479 bool maybeVisitSIMDBinary(Expression*& out, uint32_t code);
1480 bool maybeVisitSIMDUnary(Expression*& out, uint32_t code);
1481 bool maybeVisitSIMDConst(Expression*& out, uint32_t code);
1482 bool maybeVisitSIMDStore(Expression*& out, uint32_t code);
1483 bool maybeVisitSIMDExtract(Expression*& out, uint32_t code);
1484 bool maybeVisitSIMDReplace(Expression*& out, uint32_t code);
1485 bool maybeVisitSIMDShuffle(Expression*& out, uint32_t code);
1486 bool maybeVisitSIMDTernary(Expression*& out, uint32_t code);
1487 bool maybeVisitSIMDShift(Expression*& out, uint32_t code);
1488 bool maybeVisitSIMDLoad(Expression*& out, uint32_t code);
1489 bool maybeVisitMemoryInit(Expression*& out, uint32_t code);
1490 bool maybeVisitDataDrop(Expression*& out, uint32_t code);
1491 bool maybeVisitMemoryCopy(Expression*& out, uint32_t code);
1492 bool maybeVisitMemoryFill(Expression*& out, uint32_t code);
1493 bool maybeVisitI31New(Expression*& out, uint32_t code);
1494 bool maybeVisitI31Get(Expression*& out, uint32_t code);
1495 bool maybeVisitRefTest(Expression*& out, uint32_t code);
1496 bool maybeVisitRefCast(Expression*& out, uint32_t code);
1497 bool maybeVisitBrOnCast(Expression*& out, uint32_t code);
1498 bool maybeVisitRttCanon(Expression*& out, uint32_t code);
1499 bool maybeVisitRttSub(Expression*& out, uint32_t code);
1500 bool maybeVisitStructNew(Expression*& out, uint32_t code);
1501 bool maybeVisitStructGet(Expression*& out, uint32_t code);
1502 bool maybeVisitStructSet(Expression*& out, uint32_t code);
1503 bool maybeVisitArrayNew(Expression*& out, uint32_t code);
1504 bool maybeVisitArrayGet(Expression*& out, uint32_t code);
1505 bool maybeVisitArraySet(Expression*& out, uint32_t code);
1506 bool maybeVisitArrayLen(Expression*& out, uint32_t code);
1507 void visitSelect(Select* curr, uint8_t code);
1508 void visitReturn(Return* curr);
1509 void visitMemorySize(MemorySize* curr);
1510 void visitMemoryGrow(MemoryGrow* curr);
1511 void visitNop(Nop* curr);
1512 void visitUnreachable(Unreachable* curr);
1513 void visitDrop(Drop* curr);
1514 void visitRefNull(RefNull* curr);
1515 void visitRefIsNull(RefIsNull* curr);
1516 void visitRefFunc(RefFunc* curr);
1517 void visitRefEq(RefEq* curr);
1518 void visitTryOrTryInBlock(Expression*& out);
1519 void visitThrow(Throw* curr);
1520 void visitRethrow(Rethrow* curr);
1521 void visitBrOnExn(BrOnExn* curr);
1522
1523 void throwError(std::string text);
1524
1525 private:
1526 bool hasDWARFSections();
1527 };
1528
1529 } // namespace wasm
1530
1531 #undef DEBUG_TYPE
1532
1533 #endif // wasm_wasm_binary_h
1534