Source code

Revision control

Other Tools

1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2
* vim: set ts=8 sts=2 et sw=2 tw=80:
3
*
4
* Copyright 2016 Mozilla Foundation
5
*
6
* Licensed under the Apache License, Version 2.0 (the "License");
7
* you may not use this file except in compliance with the License.
8
* You may obtain a copy of the License at
9
*
11
*
12
* Unless required by applicable law or agreed to in writing, software
13
* distributed under the License is distributed on an "AS IS" BASIS,
14
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
* See the License for the specific language governing permissions and
16
* limitations under the License.
17
*/
18
19
#include "wasm/WasmValidate.h"
20
21
#include "mozilla/CheckedInt.h"
22
#include "mozilla/Unused.h"
23
#include "mozilla/Utf8.h"
24
25
#include "builtin/TypedObject.h"
26
#include "jit/JitOptions.h"
27
#include "js/Printf.h"
28
#include "vm/JSContext.h"
29
#include "vm/Realm.h"
30
#include "wasm/WasmOpIter.h"
31
32
using namespace js;
33
using namespace js::jit;
34
using namespace js::wasm;
35
36
using mozilla::AsChars;
37
using mozilla::CheckedInt;
38
using mozilla::CheckedInt32;
39
using mozilla::IsUtf8;
40
using mozilla::MakeSpan;
41
using mozilla::Unused;
42
43
// Decoder implementation.
44
45
bool Decoder::failf(const char* msg, ...) {
46
va_list ap;
47
va_start(ap, msg);
48
UniqueChars str(JS_vsmprintf(msg, ap));
49
va_end(ap);
50
if (!str) {
51
return false;
52
}
53
54
return fail(str.get());
55
}
56
57
void Decoder::warnf(const char* msg, ...) {
58
if (!warnings_) {
59
return;
60
}
61
62
va_list ap;
63
va_start(ap, msg);
64
UniqueChars str(JS_vsmprintf(msg, ap));
65
va_end(ap);
66
if (!str) {
67
return;
68
}
69
70
Unused << warnings_->append(std::move(str));
71
}
72
73
bool Decoder::fail(size_t errorOffset, const char* msg) {
74
MOZ_ASSERT(error_);
75
UniqueChars strWithOffset(JS_smprintf("at offset %zu: %s", errorOffset, msg));
76
if (!strWithOffset) {
77
return false;
78
}
79
80
*error_ = std::move(strWithOffset);
81
return false;
82
}
83
84
bool Decoder::readSectionHeader(uint8_t* id, SectionRange* range) {
85
if (!readFixedU8(id)) {
86
return false;
87
}
88
89
uint32_t size;
90
if (!readVarU32(&size)) {
91
return false;
92
}
93
94
range->start = currentOffset();
95
range->size = size;
96
return true;
97
}
98
99
bool Decoder::startSection(SectionId id, ModuleEnvironment* env,
100
MaybeSectionRange* range, const char* sectionName) {
101
MOZ_ASSERT(!*range);
102
103
// Record state at beginning of section to allow rewinding to this point
104
// if, after skipping through several custom sections, we don't find the
105
// section 'id'.
106
const uint8_t* const initialCur = cur_;
107
const size_t initialCustomSectionsLength = env->customSections.length();
108
109
// Maintain a pointer to the current section that gets updated as custom
110
// sections are skipped.
111
const uint8_t* currentSectionStart = cur_;
112
113
// Only start a section with 'id', skipping any custom sections before it.
114
115
uint8_t idValue;
116
if (!readFixedU8(&idValue)) {
117
goto rewind;
118
}
119
120
while (idValue != uint8_t(id)) {
121
if (idValue != uint8_t(SectionId::Custom)) {
122
goto rewind;
123
}
124
125
// Rewind to the beginning of the current section since this is what
126
// skipCustomSection() assumes.
127
cur_ = currentSectionStart;
128
if (!skipCustomSection(env)) {
129
return false;
130
}
131
132
// Having successfully skipped a custom section, consider the next
133
// section.
134
currentSectionStart = cur_;
135
if (!readFixedU8(&idValue)) {
136
goto rewind;
137
}
138
}
139
140
// Don't check the size since the range of bytes being decoded might not
141
// contain the section body. (This is currently the case when streaming: the
142
// code section header is decoded with the module environment bytes, the
143
// body of the code section is streamed in separately.)
144
145
uint32_t size;
146
if (!readVarU32(&size)) {
147
goto fail;
148
}
149
150
range->emplace();
151
(*range)->start = currentOffset();
152
(*range)->size = size;
153
return true;
154
155
rewind:
156
cur_ = initialCur;
157
env->customSections.shrinkTo(initialCustomSectionsLength);
158
return true;
159
160
fail:
161
return failf("failed to start %s section", sectionName);
162
}
163
164
bool Decoder::finishSection(const SectionRange& range,
165
const char* sectionName) {
166
if (resilientMode_) {
167
return true;
168
}
169
if (range.size != currentOffset() - range.start) {
170
return failf("byte size mismatch in %s section", sectionName);
171
}
172
return true;
173
}
174
175
bool Decoder::startCustomSection(const char* expected, size_t expectedLength,
176
ModuleEnvironment* env,
177
MaybeSectionRange* range) {
178
// Record state at beginning of section to allow rewinding to this point
179
// if, after skipping through several custom sections, we don't find the
180
// section 'id'.
181
const uint8_t* const initialCur = cur_;
182
const size_t initialCustomSectionsLength = env->customSections.length();
183
184
while (true) {
185
// Try to start a custom section. If we can't, rewind to the beginning
186
// since we may have skipped several custom sections already looking for
187
// 'expected'.
188
if (!startSection(SectionId::Custom, env, range, "custom")) {
189
return false;
190
}
191
if (!*range) {
192
goto rewind;
193
}
194
195
if (bytesRemain() < (*range)->size) {
196
goto fail;
197
}
198
199
CustomSectionEnv sec;
200
if (!readVarU32(&sec.nameLength) || sec.nameLength > bytesRemain()) {
201
goto fail;
202
}
203
204
sec.nameOffset = currentOffset();
205
sec.payloadOffset = sec.nameOffset + sec.nameLength;
206
207
uint32_t payloadEnd = (*range)->start + (*range)->size;
208
if (sec.payloadOffset > payloadEnd) {
209
goto fail;
210
}
211
212
sec.payloadLength = payloadEnd - sec.payloadOffset;
213
214
// Now that we have a valid custom section, record its offsets in the
215
// metadata which can be queried by the user via Module.customSections.
216
// Note: after an entry is appended, it may be popped if this loop or
217
// the loop in startSection needs to rewind.
218
if (!env->customSections.append(sec)) {
219
return false;
220
}
221
222
// If this is the expected custom section, we're done.
223
if (!expected || (expectedLength == sec.nameLength &&
224
!memcmp(cur_, expected, sec.nameLength))) {
225
cur_ += sec.nameLength;
226
return true;
227
}
228
229
// Otherwise, blindly skip the custom section and keep looking.
230
skipAndFinishCustomSection(**range);
231
range->reset();
232
}
233
MOZ_CRASH("unreachable");
234
235
rewind:
236
cur_ = initialCur;
237
env->customSections.shrinkTo(initialCustomSectionsLength);
238
return true;
239
240
fail:
241
return fail("failed to start custom section");
242
}
243
244
void Decoder::finishCustomSection(const char* name, const SectionRange& range) {
245
MOZ_ASSERT(cur_ >= beg_);
246
MOZ_ASSERT(cur_ <= end_);
247
248
if (error_ && *error_) {
249
warnf("in the '%s' custom section: %s", name, error_->get());
250
skipAndFinishCustomSection(range);
251
return;
252
}
253
254
uint32_t actualSize = currentOffset() - range.start;
255
if (range.size != actualSize) {
256
if (actualSize < range.size) {
257
warnf("in the '%s' custom section: %" PRIu32 " unconsumed bytes", name,
258
uint32_t(range.size - actualSize));
259
} else {
260
warnf("in the '%s' custom section: %" PRIu32
261
" bytes consumed past the end",
262
name, uint32_t(actualSize - range.size));
263
}
264
skipAndFinishCustomSection(range);
265
return;
266
}
267
268
// Nothing to do! (c.f. skipAndFinishCustomSection())
269
}
270
271
void Decoder::skipAndFinishCustomSection(const SectionRange& range) {
272
MOZ_ASSERT(cur_ >= beg_);
273
MOZ_ASSERT(cur_ <= end_);
274
cur_ = (beg_ + (range.start - offsetInModule_)) + range.size;
275
MOZ_ASSERT(cur_ <= end_);
276
clearError();
277
}
278
279
bool Decoder::skipCustomSection(ModuleEnvironment* env) {
280
MaybeSectionRange range;
281
if (!startCustomSection(nullptr, 0, env, &range)) {
282
return false;
283
}
284
if (!range) {
285
return fail("expected custom section");
286
}
287
288
skipAndFinishCustomSection(*range);
289
return true;
290
}
291
292
bool Decoder::startNameSubsection(NameType nameType,
293
Maybe<uint32_t>* endOffset) {
294
MOZ_ASSERT(!*endOffset);
295
296
const uint8_t* const initialPosition = cur_;
297
298
uint8_t nameTypeValue;
299
if (!readFixedU8(&nameTypeValue)) {
300
goto rewind;
301
}
302
303
if (nameTypeValue != uint8_t(nameType)) {
304
goto rewind;
305
}
306
307
uint32_t payloadLength;
308
if (!readVarU32(&payloadLength) || payloadLength > bytesRemain()) {
309
return fail("bad name subsection payload length");
310
}
311
312
*endOffset = Some(currentOffset() + payloadLength);
313
return true;
314
315
rewind:
316
cur_ = initialPosition;
317
return true;
318
}
319
320
bool Decoder::finishNameSubsection(uint32_t expected) {
321
uint32_t actual = currentOffset();
322
if (expected != actual) {
323
return failf("bad name subsection length (expected: %" PRIu32
324
", actual: %" PRIu32 ")",
325
expected, actual);
326
}
327
328
return true;
329
}
330
331
bool Decoder::skipNameSubsection() {
332
uint8_t nameTypeValue;
333
if (!readFixedU8(&nameTypeValue)) {
334
return fail("unable to read name subsection id");
335
}
336
337
switch (nameTypeValue) {
338
case uint8_t(NameType::Module):
339
case uint8_t(NameType::Function):
340
return fail("out of order name subsections");
341
default:
342
break;
343
}
344
345
uint32_t payloadLength;
346
if (!readVarU32(&payloadLength) || !readBytes(payloadLength)) {
347
return fail("bad name subsection payload length");
348
}
349
350
return true;
351
}
352
353
// Misc helpers.
354
355
bool wasm::EncodeLocalEntries(Encoder& e, const ValTypeVector& locals) {
356
if (locals.length() > MaxLocals) {
357
return false;
358
}
359
360
uint32_t numLocalEntries = 0;
361
ValType prev;
362
for (ValType t : locals) {
363
if (t != prev) {
364
numLocalEntries++;
365
prev = t;
366
}
367
}
368
369
if (!e.writeVarU32(numLocalEntries)) {
370
return false;
371
}
372
373
if (numLocalEntries) {
374
prev = locals[0];
375
uint32_t count = 1;
376
for (uint32_t i = 1; i < locals.length(); i++, count++) {
377
if (prev != locals[i]) {
378
if (!e.writeVarU32(count)) {
379
return false;
380
}
381
if (!e.writeValType(prev)) {
382
return false;
383
}
384
prev = locals[i];
385
count = 0;
386
}
387
}
388
if (!e.writeVarU32(count)) {
389
return false;
390
}
391
if (!e.writeValType(prev)) {
392
return false;
393
}
394
}
395
396
return true;
397
}
398
399
bool wasm::DecodeLocalEntries(Decoder& d, const TypeDefVector& types,
400
bool refTypesEnabled, bool gcTypesEnabled,
401
ValTypeVector* locals) {
402
uint32_t numLocalEntries;
403
if (!d.readVarU32(&numLocalEntries)) {
404
return d.fail("failed to read number of local entries");
405
}
406
407
for (uint32_t i = 0; i < numLocalEntries; i++) {
408
uint32_t count;
409
if (!d.readVarU32(&count)) {
410
return d.fail("failed to read local entry count");
411
}
412
413
if (MaxLocals - locals->length() < count) {
414
return d.fail("too many locals");
415
}
416
417
ValType type;
418
if (!d.readValType(types, refTypesEnabled, gcTypesEnabled, &type)) {
419
return false;
420
}
421
422
if (!locals->appendN(type, count)) {
423
return false;
424
}
425
}
426
427
return true;
428
}
429
430
bool wasm::DecodeValidatedLocalEntries(Decoder& d, ValTypeVector* locals) {
431
uint32_t numLocalEntries;
432
MOZ_ALWAYS_TRUE(d.readVarU32(&numLocalEntries));
433
434
for (uint32_t i = 0; i < numLocalEntries; i++) {
435
uint32_t count = d.uncheckedReadVarU32();
436
MOZ_ASSERT(MaxLocals - locals->length() >= count);
437
if (!locals->appendN(d.uncheckedReadValType(), count)) {
438
return false;
439
}
440
}
441
442
return true;
443
}
444
445
// Function body validation.
446
447
class NothingVector {
448
Nothing unused_;
449
450
public:
451
bool resize(size_t length) { return true; }
452
Nothing& operator[](size_t) { return unused_; }
453
Nothing& back() { return unused_; }
454
};
455
456
struct ValidatingPolicy {
457
typedef Nothing Value;
458
typedef NothingVector ValueVector;
459
typedef Nothing ControlItem;
460
};
461
462
typedef OpIter<ValidatingPolicy> ValidatingOpIter;
463
464
static bool DecodeFunctionBodyExprs(const ModuleEnvironment& env,
465
uint32_t funcIndex,
466
const ValTypeVector& locals,
467
const uint8_t* bodyEnd, Decoder* d) {
468
ValidatingOpIter iter(env, *d);
469
470
if (!iter.readFunctionStart(funcIndex)) {
471
return false;
472
}
473
474
#define CHECK(c) \
475
if (!(c)) return false; \
476
break
477
478
while (true) {
479
OpBytes op;
480
if (!iter.readOp(&op)) {
481
return false;
482
}
483
484
Nothing nothing;
485
NothingVector nothings;
486
ResultType unusedType;
487
488
switch (op.b0) {
489
case uint16_t(Op::End): {
490
LabelKind unusedKind;
491
if (!iter.readEnd(&unusedKind, &unusedType, &nothings, &nothings)) {
492
return false;
493
}
494
iter.popEnd();
495
if (iter.controlStackEmpty()) {
496
return iter.readFunctionEnd(bodyEnd);
497
}
498
break;
499
}
500
case uint16_t(Op::Nop):
501
CHECK(iter.readNop());
502
case uint16_t(Op::Drop):
503
CHECK(iter.readDrop());
504
case uint16_t(Op::Call): {
505
uint32_t unusedIndex;
506
NothingVector unusedArgs;
507
CHECK(iter.readCall(&unusedIndex, &unusedArgs));
508
}
509
case uint16_t(Op::CallIndirect): {
510
uint32_t unusedIndex, unusedIndex2;
511
NothingVector unusedArgs;
512
CHECK(iter.readCallIndirect(&unusedIndex, &unusedIndex2, &nothing,
513
&unusedArgs));
514
}
515
case uint16_t(Op::I32Const): {
516
int32_t unused;
517
CHECK(iter.readI32Const(&unused));
518
}
519
case uint16_t(Op::I64Const): {
520
int64_t unused;
521
CHECK(iter.readI64Const(&unused));
522
}
523
case uint16_t(Op::F32Const): {
524
float unused;
525
CHECK(iter.readF32Const(&unused));
526
}
527
case uint16_t(Op::F64Const): {
528
double unused;
529
CHECK(iter.readF64Const(&unused));
530
}
531
case uint16_t(Op::GetLocal): {
532
uint32_t unused;
533
CHECK(iter.readGetLocal(locals, &unused));
534
}
535
case uint16_t(Op::SetLocal): {
536
uint32_t unused;
537
CHECK(iter.readSetLocal(locals, &unused, &nothing));
538
}
539
case uint16_t(Op::TeeLocal): {
540
uint32_t unused;
541
CHECK(iter.readTeeLocal(locals, &unused, &nothing));
542
}
543
case uint16_t(Op::GetGlobal): {
544
uint32_t unused;
545
CHECK(iter.readGetGlobal(&unused));
546
}
547
case uint16_t(Op::SetGlobal): {
548
uint32_t unused;
549
CHECK(iter.readSetGlobal(&unused, &nothing));
550
}
551
#ifdef ENABLE_WASM_REFTYPES
552
case uint16_t(Op::TableGet): {
553
if (!env.refTypesEnabled()) {
554
return iter.unrecognizedOpcode(&op);
555
}
556
uint32_t unusedTableIndex;
557
CHECK(iter.readTableGet(&unusedTableIndex, &nothing));
558
}
559
case uint16_t(Op::TableSet): {
560
if (!env.refTypesEnabled()) {
561
return iter.unrecognizedOpcode(&op);
562
}
563
uint32_t unusedTableIndex;
564
CHECK(iter.readTableSet(&unusedTableIndex, &nothing, &nothing));
565
}
566
#endif
567
case uint16_t(Op::SelectNumeric): {
568
StackType unused;
569
CHECK(iter.readSelect(/*typed*/ false, &unused, &nothing, &nothing,
570
&nothing));
571
}
572
case uint16_t(Op::SelectTyped): {
573
if (!env.refTypesEnabled()) {
574
return iter.unrecognizedOpcode(&op);
575
}
576
StackType unused;
577
CHECK(iter.readSelect(/*typed*/ true, &unused, &nothing, &nothing,
578
&nothing));
579
}
580
case uint16_t(Op::Block):
581
CHECK(iter.readBlock(&unusedType));
582
case uint16_t(Op::Loop):
583
CHECK(iter.readLoop(&unusedType));
584
case uint16_t(Op::If):
585
CHECK(iter.readIf(&unusedType, &nothing));
586
case uint16_t(Op::Else):
587
CHECK(iter.readElse(&unusedType, &unusedType, &nothings));
588
case uint16_t(Op::I32Clz):
589
case uint16_t(Op::I32Ctz):
590
case uint16_t(Op::I32Popcnt):
591
CHECK(iter.readUnary(ValType::I32, &nothing));
592
case uint16_t(Op::I64Clz):
593
case uint16_t(Op::I64Ctz):
594
case uint16_t(Op::I64Popcnt):
595
CHECK(iter.readUnary(ValType::I64, &nothing));
596
case uint16_t(Op::F32Abs):
597
case uint16_t(Op::F32Neg):
598
case uint16_t(Op::F32Ceil):
599
case uint16_t(Op::F32Floor):
600
case uint16_t(Op::F32Sqrt):
601
case uint16_t(Op::F32Trunc):
602
case uint16_t(Op::F32Nearest):
603
CHECK(iter.readUnary(ValType::F32, &nothing));
604
case uint16_t(Op::F64Abs):
605
case uint16_t(Op::F64Neg):
606
case uint16_t(Op::F64Ceil):
607
case uint16_t(Op::F64Floor):
608
case uint16_t(Op::F64Sqrt):
609
case uint16_t(Op::F64Trunc):
610
case uint16_t(Op::F64Nearest):
611
CHECK(iter.readUnary(ValType::F64, &nothing));
612
case uint16_t(Op::I32Add):
613
case uint16_t(Op::I32Sub):
614
case uint16_t(Op::I32Mul):
615
case uint16_t(Op::I32DivS):
616
case uint16_t(Op::I32DivU):
617
case uint16_t(Op::I32RemS):
618
case uint16_t(Op::I32RemU):
619
case uint16_t(Op::I32And):
620
case uint16_t(Op::I32Or):
621
case uint16_t(Op::I32Xor):
622
case uint16_t(Op::I32Shl):
623
case uint16_t(Op::I32ShrS):
624
case uint16_t(Op::I32ShrU):
625
case uint16_t(Op::I32Rotl):
626
case uint16_t(Op::I32Rotr):
627
CHECK(iter.readBinary(ValType::I32, &nothing, &nothing));
628
case uint16_t(Op::I64Add):
629
case uint16_t(Op::I64Sub):
630
case uint16_t(Op::I64Mul):
631
case uint16_t(Op::I64DivS):
632
case uint16_t(Op::I64DivU):
633
case uint16_t(Op::I64RemS):
634
case uint16_t(Op::I64RemU):
635
case uint16_t(Op::I64And):
636
case uint16_t(Op::I64Or):
637
case uint16_t(Op::I64Xor):
638
case uint16_t(Op::I64Shl):
639
case uint16_t(Op::I64ShrS):
640
case uint16_t(Op::I64ShrU):
641
case uint16_t(Op::I64Rotl):
642
case uint16_t(Op::I64Rotr):
643
CHECK(iter.readBinary(ValType::I64, &nothing, &nothing));
644
case uint16_t(Op::F32Add):
645
case uint16_t(Op::F32Sub):
646
case uint16_t(Op::F32Mul):
647
case uint16_t(Op::F32Div):
648
case uint16_t(Op::F32Min):
649
case uint16_t(Op::F32Max):
650
case uint16_t(Op::F32CopySign):
651
CHECK(iter.readBinary(ValType::F32, &nothing, &nothing));
652
case uint16_t(Op::F64Add):
653
case uint16_t(Op::F64Sub):
654
case uint16_t(Op::F64Mul):
655
case uint16_t(Op::F64Div):
656
case uint16_t(Op::F64Min):
657
case uint16_t(Op::F64Max):
658
case uint16_t(Op::F64CopySign):
659
CHECK(iter.readBinary(ValType::F64, &nothing, &nothing));
660
case uint16_t(Op::I32Eq):
661
case uint16_t(Op::I32Ne):
662
case uint16_t(Op::I32LtS):
663
case uint16_t(Op::I32LtU):
664
case uint16_t(Op::I32LeS):
665
case uint16_t(Op::I32LeU):
666
case uint16_t(Op::I32GtS):
667
case uint16_t(Op::I32GtU):
668
case uint16_t(Op::I32GeS):
669
case uint16_t(Op::I32GeU):
670
CHECK(iter.readComparison(ValType::I32, &nothing, &nothing));
671
case uint16_t(Op::I64Eq):
672
case uint16_t(Op::I64Ne):
673
case uint16_t(Op::I64LtS):
674
case uint16_t(Op::I64LtU):
675
case uint16_t(Op::I64LeS):
676
case uint16_t(Op::I64LeU):
677
case uint16_t(Op::I64GtS):
678
case uint16_t(Op::I64GtU):
679
case uint16_t(Op::I64GeS):
680
case uint16_t(Op::I64GeU):
681
CHECK(iter.readComparison(ValType::I64, &nothing, &nothing));
682
case uint16_t(Op::F32Eq):
683
case uint16_t(Op::F32Ne):
684
case uint16_t(Op::F32Lt):
685
case uint16_t(Op::F32Le):
686
case uint16_t(Op::F32Gt):
687
case uint16_t(Op::F32Ge):
688
CHECK(iter.readComparison(ValType::F32, &nothing, &nothing));
689
case uint16_t(Op::F64Eq):
690
case uint16_t(Op::F64Ne):
691
case uint16_t(Op::F64Lt):
692
case uint16_t(Op::F64Le):
693
case uint16_t(Op::F64Gt):
694
case uint16_t(Op::F64Ge):
695
CHECK(iter.readComparison(ValType::F64, &nothing, &nothing));
696
case uint16_t(Op::I32Eqz):
697
CHECK(iter.readConversion(ValType::I32, ValType::I32, &nothing));
698
case uint16_t(Op::I64Eqz):
699
case uint16_t(Op::I32WrapI64):
700
CHECK(iter.readConversion(ValType::I64, ValType::I32, &nothing));
701
case uint16_t(Op::I32TruncSF32):
702
case uint16_t(Op::I32TruncUF32):
703
case uint16_t(Op::I32ReinterpretF32):
704
CHECK(iter.readConversion(ValType::F32, ValType::I32, &nothing));
705
case uint16_t(Op::I32TruncSF64):
706
case uint16_t(Op::I32TruncUF64):
707
CHECK(iter.readConversion(ValType::F64, ValType::I32, &nothing));
708
case uint16_t(Op::I64ExtendSI32):
709
case uint16_t(Op::I64ExtendUI32):
710
CHECK(iter.readConversion(ValType::I32, ValType::I64, &nothing));
711
case uint16_t(Op::I64TruncSF32):
712
case uint16_t(Op::I64TruncUF32):
713
CHECK(iter.readConversion(ValType::F32, ValType::I64, &nothing));
714
case uint16_t(Op::I64TruncSF64):
715
case uint16_t(Op::I64TruncUF64):
716
case uint16_t(Op::I64ReinterpretF64):
717
CHECK(iter.readConversion(ValType::F64, ValType::I64, &nothing));
718
case uint16_t(Op::F32ConvertSI32):
719
case uint16_t(Op::F32ConvertUI32):
720
case uint16_t(Op::F32ReinterpretI32):
721
CHECK(iter.readConversion(ValType::I32, ValType::F32, &nothing));
722
case uint16_t(Op::F32ConvertSI64):
723
case uint16_t(Op::F32ConvertUI64):
724
CHECK(iter.readConversion(ValType::I64, ValType::F32, &nothing));
725
case uint16_t(Op::F32DemoteF64):
726
CHECK(iter.readConversion(ValType::F64, ValType::F32, &nothing));
727
case uint16_t(Op::F64ConvertSI32):
728
case uint16_t(Op::F64ConvertUI32):
729
CHECK(iter.readConversion(ValType::I32, ValType::F64, &nothing));
730
case uint16_t(Op::F64ConvertSI64):
731
case uint16_t(Op::F64ConvertUI64):
732
case uint16_t(Op::F64ReinterpretI64):
733
CHECK(iter.readConversion(ValType::I64, ValType::F64, &nothing));
734
case uint16_t(Op::F64PromoteF32):
735
CHECK(iter.readConversion(ValType::F32, ValType::F64, &nothing));
736
case uint16_t(Op::I32Extend8S):
737
case uint16_t(Op::I32Extend16S):
738
CHECK(iter.readConversion(ValType::I32, ValType::I32, &nothing));
739
case uint16_t(Op::I64Extend8S):
740
case uint16_t(Op::I64Extend16S):
741
case uint16_t(Op::I64Extend32S):
742
CHECK(iter.readConversion(ValType::I64, ValType::I64, &nothing));
743
case uint16_t(Op::I32Load8S):
744
case uint16_t(Op::I32Load8U): {
745
LinearMemoryAddress<Nothing> addr;
746
CHECK(iter.readLoad(ValType::I32, 1, &addr));
747
}
748
case uint16_t(Op::I32Load16S):
749
case uint16_t(Op::I32Load16U): {
750
LinearMemoryAddress<Nothing> addr;
751
CHECK(iter.readLoad(ValType::I32, 2, &addr));
752
}
753
case uint16_t(Op::I32Load): {
754
LinearMemoryAddress<Nothing> addr;
755
CHECK(iter.readLoad(ValType::I32, 4, &addr));
756
}
757
case uint16_t(Op::I64Load8S):
758
case uint16_t(Op::I64Load8U): {
759
LinearMemoryAddress<Nothing> addr;
760
CHECK(iter.readLoad(ValType::I64, 1, &addr));
761
}
762
case uint16_t(Op::I64Load16S):
763
case uint16_t(Op::I64Load16U): {
764
LinearMemoryAddress<Nothing> addr;
765
CHECK(iter.readLoad(ValType::I64, 2, &addr));
766
}
767
case uint16_t(Op::I64Load32S):
768
case uint16_t(Op::I64Load32U): {
769
LinearMemoryAddress<Nothing> addr;
770
CHECK(iter.readLoad(ValType::I64, 4, &addr));
771
}
772
case uint16_t(Op::I64Load): {
773
LinearMemoryAddress<Nothing> addr;
774
CHECK(iter.readLoad(ValType::I64, 8, &addr));
775
}
776
case uint16_t(Op::F32Load): {
777
LinearMemoryAddress<Nothing> addr;
778
CHECK(iter.readLoad(ValType::F32, 4, &addr));
779
}
780
case uint16_t(Op::F64Load): {
781
LinearMemoryAddress<Nothing> addr;
782
CHECK(iter.readLoad(ValType::F64, 8, &addr));
783
}
784
case uint16_t(Op::I32Store8): {
785
LinearMemoryAddress<Nothing> addr;
786
CHECK(iter.readStore(ValType::I32, 1, &addr, &nothing));
787
}
788
case uint16_t(Op::I32Store16): {
789
LinearMemoryAddress<Nothing> addr;
790
CHECK(iter.readStore(ValType::I32, 2, &addr, &nothing));
791
}
792
case uint16_t(Op::I32Store): {
793
LinearMemoryAddress<Nothing> addr;
794
CHECK(iter.readStore(ValType::I32, 4, &addr, &nothing));
795
}
796
case uint16_t(Op::I64Store8): {
797
LinearMemoryAddress<Nothing> addr;
798
CHECK(iter.readStore(ValType::I64, 1, &addr, &nothing));
799
}
800
case uint16_t(Op::I64Store16): {
801
LinearMemoryAddress<Nothing> addr;
802
CHECK(iter.readStore(ValType::I64, 2, &addr, &nothing));
803
}
804
case uint16_t(Op::I64Store32): {
805
LinearMemoryAddress<Nothing> addr;
806
CHECK(iter.readStore(ValType::I64, 4, &addr, &nothing));
807
}
808
case uint16_t(Op::I64Store): {
809
LinearMemoryAddress<Nothing> addr;
810
CHECK(iter.readStore(ValType::I64, 8, &addr, &nothing));
811
}
812
case uint16_t(Op::F32Store): {
813
LinearMemoryAddress<Nothing> addr;
814
CHECK(iter.readStore(ValType::F32, 4, &addr, &nothing));
815
}
816
case uint16_t(Op::F64Store): {
817
LinearMemoryAddress<Nothing> addr;
818
CHECK(iter.readStore(ValType::F64, 8, &addr, &nothing));
819
}
820
case uint16_t(Op::MemoryGrow):
821
CHECK(iter.readMemoryGrow(&nothing));
822
case uint16_t(Op::MemorySize):
823
CHECK(iter.readMemorySize());
824
case uint16_t(Op::Br): {
825
uint32_t unusedDepth;
826
CHECK(iter.readBr(&unusedDepth, &unusedType, &nothings));
827
}
828
case uint16_t(Op::BrIf): {
829
uint32_t unusedDepth;
830
CHECK(iter.readBrIf(&unusedDepth, &unusedType, &nothings, &nothing));
831
}
832
case uint16_t(Op::BrTable): {
833
Uint32Vector unusedDepths;
834
uint32_t unusedDefault;
835
CHECK(iter.readBrTable(&unusedDepths, &unusedDefault, &unusedType,
836
&nothings, &nothing));
837
}
838
case uint16_t(Op::Return):
839
CHECK(iter.readReturn(&nothings));
840
case uint16_t(Op::Unreachable):
841
CHECK(iter.readUnreachable());
842
case uint16_t(Op::MiscPrefix): {
843
switch (op.b1) {
844
case uint32_t(MiscOp::I32TruncSSatF32):
845
case uint32_t(MiscOp::I32TruncUSatF32):
846
CHECK(iter.readConversion(ValType::F32, ValType::I32, &nothing));
847
case uint32_t(MiscOp::I32TruncSSatF64):
848
case uint32_t(MiscOp::I32TruncUSatF64):
849
CHECK(iter.readConversion(ValType::F64, ValType::I32, &nothing));
850
case uint32_t(MiscOp::I64TruncSSatF32):
851
case uint32_t(MiscOp::I64TruncUSatF32):
852
CHECK(iter.readConversion(ValType::F32, ValType::I64, &nothing));
853
case uint32_t(MiscOp::I64TruncSSatF64):
854
case uint32_t(MiscOp::I64TruncUSatF64):
855
CHECK(iter.readConversion(ValType::F64, ValType::I64, &nothing));
856
case uint32_t(MiscOp::MemCopy): {
857
#ifndef ENABLE_WASM_BULKMEM_OPS
858
// Bulk memory must be available if shared memory is enabled.
859
if (env.sharedMemoryEnabled == Shareable::False) {
860
return iter.fail("bulk memory ops disabled");
861
}
862
#endif
863
uint32_t unusedDestMemIndex;
864
uint32_t unusedSrcMemIndex;
865
CHECK(iter.readMemOrTableCopy(/*isMem=*/true, &unusedDestMemIndex,
866
&nothing, &unusedSrcMemIndex,
867
&nothing, &nothing));
868
}
869
case uint32_t(MiscOp::DataDrop): {
870
#ifndef ENABLE_WASM_BULKMEM_OPS
871
// Bulk memory must be available if shared memory is enabled.
872
if (env.sharedMemoryEnabled == Shareable::False) {
873
return iter.fail("bulk memory ops disabled");
874
}
875
#endif
876
uint32_t unusedSegIndex;
877
CHECK(iter.readDataOrElemDrop(/*isData=*/true, &unusedSegIndex));
878
}
879
case uint32_t(MiscOp::MemFill):
880
#ifndef ENABLE_WASM_BULKMEM_OPS
881
// Bulk memory must be available if shared memory is enabled.
882
if (env.sharedMemoryEnabled == Shareable::False) {
883
return iter.fail("bulk memory ops disabled");
884
}
885
#endif
886
CHECK(iter.readMemFill(&nothing, &nothing, &nothing));
887
case uint32_t(MiscOp::MemInit): {
888
#ifndef ENABLE_WASM_BULKMEM_OPS
889
// Bulk memory must be available if shared memory is enabled.
890
if (env.sharedMemoryEnabled == Shareable::False) {
891
return iter.fail("bulk memory ops disabled");
892
}
893
#endif
894
uint32_t unusedSegIndex;
895
uint32_t unusedTableIndex;
896
CHECK(iter.readMemOrTableInit(/*isMem=*/true, &unusedSegIndex,
897
&unusedTableIndex, &nothing, &nothing,
898
&nothing));
899
}
900
case uint32_t(MiscOp::TableCopy): {
901
#ifndef ENABLE_WASM_BULKMEM_OPS
902
// Bulk memory must be available if shared memory is enabled.
903
if (env.sharedMemoryEnabled == Shareable::False) {
904
return iter.fail("bulk memory ops disabled");
905
}
906
#endif
907
uint32_t unusedDestTableIndex;
908
uint32_t unusedSrcTableIndex;
909
CHECK(iter.readMemOrTableCopy(
910
/*isMem=*/false, &unusedDestTableIndex, &nothing,
911
&unusedSrcTableIndex, &nothing, &nothing));
912
}
913
case uint32_t(MiscOp::ElemDrop): {
914
#ifndef ENABLE_WASM_BULKMEM_OPS
915
// Bulk memory must be available if shared memory is enabled.
916
if (env.sharedMemoryEnabled == Shareable::False) {
917
return iter.fail("bulk memory ops disabled");
918
}
919
#endif
920
uint32_t unusedSegIndex;
921
CHECK(iter.readDataOrElemDrop(/*isData=*/false, &unusedSegIndex));
922
}
923
case uint32_t(MiscOp::TableInit): {
924
#ifndef ENABLE_WASM_BULKMEM_OPS
925
// Bulk memory must be available if shared memory is enabled.
926
if (env.sharedMemoryEnabled == Shareable::False) {
927
return iter.fail("bulk memory ops disabled");
928
}
929
#endif
930
uint32_t unusedSegIndex;
931
uint32_t unusedTableIndex;
932
CHECK(iter.readMemOrTableInit(/*isMem=*/false, &unusedSegIndex,
933
&unusedTableIndex, &nothing, &nothing,
934
&nothing));
935
}
936
#ifdef ENABLE_WASM_REFTYPES
937
case uint32_t(MiscOp::TableFill): {
938
if (!env.refTypesEnabled()) {
939
return iter.unrecognizedOpcode(&op);
940
}
941
uint32_t unusedTableIndex;
942
CHECK(iter.readTableFill(&unusedTableIndex, &nothing, &nothing,
943
&nothing));
944
}
945
case uint32_t(MiscOp::TableGrow): {
946
if (!env.refTypesEnabled()) {
947
return iter.unrecognizedOpcode(&op);
948
}
949
uint32_t unusedTableIndex;
950
CHECK(iter.readTableGrow(&unusedTableIndex, &nothing, &nothing));
951
}
952
case uint32_t(MiscOp::TableSize): {
953
if (!env.refTypesEnabled()) {
954
return iter.unrecognizedOpcode(&op);
955
}
956
uint32_t unusedTableIndex;
957
CHECK(iter.readTableSize(&unusedTableIndex));
958
}
959
#endif
960
#ifdef ENABLE_WASM_GC
961
case uint32_t(MiscOp::StructNew): {
962
if (!env.gcTypesEnabled()) {
963
return iter.unrecognizedOpcode(&op);
964
}
965
uint32_t unusedUint;
966
NothingVector unusedArgs;
967
CHECK(iter.readStructNew(&unusedUint, &unusedArgs));
968
}
969
case uint32_t(MiscOp::StructGet): {
970
if (!env.gcTypesEnabled()) {
971
return iter.unrecognizedOpcode(&op);
972
}
973
uint32_t unusedUint1, unusedUint2;
974
CHECK(iter.readStructGet(&unusedUint1, &unusedUint2, &nothing));
975
}
976
case uint32_t(MiscOp::StructSet): {
977
if (!env.gcTypesEnabled()) {
978
return iter.unrecognizedOpcode(&op);
979
}
980
uint32_t unusedUint1, unusedUint2;
981
CHECK(iter.readStructSet(&unusedUint1, &unusedUint2, &nothing,
982
&nothing));
983
}
984
case uint32_t(MiscOp::StructNarrow): {
985
if (!env.gcTypesEnabled()) {
986
return iter.unrecognizedOpcode(&op);
987
}
988
ValType unusedTy, unusedTy2;
989
CHECK(iter.readStructNarrow(&unusedTy, &unusedTy2, &nothing));
990
}
991
#endif
992
default:
993
return iter.unrecognizedOpcode(&op);
994
}
995
break;
996
}
997
#ifdef ENABLE_WASM_GC
998
case uint16_t(Op::RefEq): {
999
if (!env.gcTypesEnabled()) {
1000
return iter.unrecognizedOpcode(&op);
1001
}
1002
CHECK(iter.readComparison(ValType::AnyRef, &nothing, &nothing));
1003
break;
1004
}
1005
#endif
1006
#ifdef ENABLE_WASM_REFTYPES
1007
case uint16_t(Op::RefFunc): {
1008
uint32_t unusedIndex;
1009
CHECK(iter.readRefFunc(&unusedIndex));
1010
break;
1011
}
1012
case uint16_t(Op::RefNull): {
1013
if (!env.refTypesEnabled()) {
1014
return iter.unrecognizedOpcode(&op);
1015
}
1016
CHECK(iter.readRefNull());
1017
break;
1018
}
1019
case uint16_t(Op::RefIsNull): {
1020
if (!env.refTypesEnabled()) {
1021
return iter.unrecognizedOpcode(&op);
1022
}
1023
CHECK(iter.readConversion(ValType::AnyRef, ValType::I32, &nothing));
1024
break;
1025
}
1026
#endif
1027
case uint16_t(Op::ThreadPrefix): {
1028
switch (op.b1) {
1029
case uint32_t(ThreadOp::Wake): {
1030
LinearMemoryAddress<Nothing> addr;
1031
CHECK(iter.readWake(&addr, &nothing));
1032
}
1033
case uint32_t(ThreadOp::I32Wait): {
1034
LinearMemoryAddress<Nothing> addr;
1035
CHECK(iter.readWait(&addr, ValType::I32, 4, &nothing, &nothing));
1036
}
1037
case uint32_t(ThreadOp::I64Wait): {
1038
LinearMemoryAddress<Nothing> addr;
1039
CHECK(iter.readWait(&addr, ValType::I64, 8, &nothing, &nothing));
1040
}
1041
case uint32_t(ThreadOp::Fence): {
1042
CHECK(iter.readFence());
1043
}
1044
case uint32_t(ThreadOp::I32AtomicLoad): {
1045
LinearMemoryAddress<Nothing> addr;
1046
CHECK(iter.readAtomicLoad(&addr, ValType::I32, 4));
1047
}
1048
case uint32_t(ThreadOp::I64AtomicLoad): {
1049
LinearMemoryAddress<Nothing> addr;
1050
CHECK(iter.readAtomicLoad(&addr, ValType::I64, 8));
1051
}
1052
case uint32_t(ThreadOp::I32AtomicLoad8U): {
1053
LinearMemoryAddress<Nothing> addr;
1054
CHECK(iter.readAtomicLoad(&addr, ValType::I32, 1));
1055
}
1056
case uint32_t(ThreadOp::I32AtomicLoad16U): {
1057
LinearMemoryAddress<Nothing> addr;
1058
CHECK(iter.readAtomicLoad(&addr, ValType::I32, 2));
1059
}
1060
case uint32_t(ThreadOp::I64AtomicLoad8U): {
1061
LinearMemoryAddress<Nothing> addr;
1062
CHECK(iter.readAtomicLoad(&addr, ValType::I64, 1));
1063
}
1064
case uint32_t(ThreadOp::I64AtomicLoad16U): {
1065
LinearMemoryAddress<Nothing> addr;
1066
CHECK(iter.readAtomicLoad(&addr, ValType::I64, 2));
1067
}
1068
case uint32_t(ThreadOp::I64AtomicLoad32U): {
1069
LinearMemoryAddress<Nothing> addr;
1070
CHECK(iter.readAtomicLoad(&addr, ValType::I64, 4));
1071
}
1072
case uint32_t(ThreadOp::I32AtomicStore): {
1073
LinearMemoryAddress<Nothing> addr;
1074
CHECK(iter.readAtomicStore(&addr, ValType::I32, 4, &nothing));
1075
}
1076
case uint32_t(ThreadOp::I64AtomicStore): {
1077
LinearMemoryAddress<Nothing> addr;
1078
CHECK(iter.readAtomicStore(&addr, ValType::I64, 8, &nothing));
1079
}
1080
case uint32_t(ThreadOp::I32AtomicStore8U): {
1081
LinearMemoryAddress<Nothing> addr;
1082
CHECK(iter.readAtomicStore(&addr, ValType::I32, 1, &nothing));
1083
}
1084
case uint32_t(ThreadOp::I32AtomicStore16U): {
1085
LinearMemoryAddress<Nothing> addr;
1086
CHECK(iter.readAtomicStore(&addr, ValType::I32, 2, &nothing));
1087
}
1088
case uint32_t(ThreadOp::I64AtomicStore8U): {
1089
LinearMemoryAddress<Nothing> addr;
1090
CHECK(iter.readAtomicStore(&addr, ValType::I64, 1, &nothing));
1091
}
1092
case uint32_t(ThreadOp::I64AtomicStore16U): {
1093
LinearMemoryAddress<Nothing> addr;
1094
CHECK(iter.readAtomicStore(&addr, ValType::I64, 2, &nothing));
1095
}
1096
case uint32_t(ThreadOp::I64AtomicStore32U): {
1097
LinearMemoryAddress<Nothing> addr;
1098
CHECK(iter.readAtomicStore(&addr, ValType::I64, 4, &nothing));
1099
}
1100
case uint32_t(ThreadOp::I32AtomicAdd):
1101
case uint32_t(ThreadOp::I32AtomicSub):
1102
case uint32_t(ThreadOp::I32AtomicAnd):
1103
case uint32_t(ThreadOp::I32AtomicOr):
1104
case uint32_t(ThreadOp::I32AtomicXor):
1105
case uint32_t(ThreadOp::I32AtomicXchg): {
1106
LinearMemoryAddress<Nothing> addr;
1107
CHECK(iter.readAtomicRMW(&addr, ValType::I32, 4, &nothing));
1108
}
1109
case uint32_t(ThreadOp::I64AtomicAdd):
1110
case uint32_t(ThreadOp::I64AtomicSub):
1111
case uint32_t(ThreadOp::I64AtomicAnd):
1112
case uint32_t(ThreadOp::I64AtomicOr):
1113
case uint32_t(ThreadOp::I64AtomicXor):
1114
case uint32_t(ThreadOp::I64AtomicXchg): {
1115
LinearMemoryAddress<Nothing> addr;
1116
CHECK(iter.readAtomicRMW(&addr, ValType::I64, 8, &nothing));
1117
}
1118
case uint32_t(ThreadOp::I32AtomicAdd8U):
1119
case uint32_t(ThreadOp::I32AtomicSub8U):
1120
case uint32_t(ThreadOp::I32AtomicAnd8U):
1121
case uint32_t(ThreadOp::I32AtomicOr8U):
1122
case uint32_t(ThreadOp::I32AtomicXor8U):
1123
case uint32_t(ThreadOp::I32AtomicXchg8U): {
1124
LinearMemoryAddress<Nothing> addr;
1125
CHECK(iter.readAtomicRMW(&addr, ValType::I32, 1, &nothing));
1126
}
1127
case uint32_t(ThreadOp::I32AtomicAdd16U):
1128
case uint32_t(ThreadOp::I32AtomicSub16U):
1129
case uint32_t(ThreadOp::I32AtomicAnd16U):
1130
case uint32_t(ThreadOp::I32AtomicOr16U):
1131
case uint32_t(ThreadOp::I32AtomicXor16U):
1132
case uint32_t(ThreadOp::I32AtomicXchg16U): {
1133
LinearMemoryAddress<Nothing> addr;
1134
CHECK(iter.readAtomicRMW(&addr, ValType::I32, 2, &nothing));
1135
}
1136
case uint32_t(ThreadOp::I64AtomicAdd8U):
1137
case uint32_t(ThreadOp::I64AtomicSub8U):
1138
case uint32_t(ThreadOp::I64AtomicAnd8U):
1139
case uint32_t(ThreadOp::I64AtomicOr8U):
1140
case uint32_t(ThreadOp::I64AtomicXor8U):
1141
case uint32_t(ThreadOp::I64AtomicXchg8U): {
1142
LinearMemoryAddress<Nothing> addr;
1143
CHECK(iter.readAtomicRMW(&addr, ValType::I64, 1, &nothing));
1144
}
1145
case uint32_t(ThreadOp::I64AtomicAdd16U):
1146
case uint32_t(ThreadOp::I64AtomicSub16U):
1147
case uint32_t(ThreadOp::I64AtomicAnd16U):
1148
case uint32_t(ThreadOp::I64AtomicOr16U):
1149
case uint32_t(ThreadOp::I64AtomicXor16U):
1150
case uint32_t(ThreadOp::I64AtomicXchg16U): {
1151
LinearMemoryAddress<Nothing> addr;
1152
CHECK(iter.readAtomicRMW(&addr, ValType::I64, 2, &nothing));
1153
}
1154
case uint32_t(ThreadOp::I64AtomicAdd32U):
1155
case uint32_t(ThreadOp::I64AtomicSub32U):
1156
case uint32_t(ThreadOp::I64AtomicAnd32U):
1157
case uint32_t(ThreadOp::I64AtomicOr32U):
1158
case uint32_t(ThreadOp::I64AtomicXor32U):
1159
case uint32_t(ThreadOp::I64AtomicXchg32U): {
1160
LinearMemoryAddress<Nothing> addr;
1161
CHECK(iter.readAtomicRMW(&addr, ValType::I64, 4, &nothing));
1162
}
1163
case uint32_t(ThreadOp::I32AtomicCmpXchg): {
1164
LinearMemoryAddress<Nothing> addr;
1165
CHECK(iter.readAtomicCmpXchg(&addr, ValType::I32, 4, &nothing,
1166
&nothing));
1167
}
1168
case uint32_t(ThreadOp::I64AtomicCmpXchg): {
1169
LinearMemoryAddress<Nothing> addr;
1170
CHECK(iter.readAtomicCmpXchg(&addr, ValType::I64, 8, &nothing,
1171
&nothing));
1172
}
1173
case uint32_t(ThreadOp::I32AtomicCmpXchg8U): {
1174
LinearMemoryAddress<Nothing> addr;
1175
CHECK(iter.readAtomicCmpXchg(&addr, ValType::I32, 1, &nothing,
1176
&nothing));
1177
}
1178
case uint32_t(ThreadOp::I32AtomicCmpXchg16U): {
1179
LinearMemoryAddress<Nothing> addr;
1180
CHECK(iter.readAtomicCmpXchg(&addr, ValType::I32, 2, &nothing,
1181
&nothing));
1182
}
1183
case uint32_t(ThreadOp::I64AtomicCmpXchg8U): {
1184
LinearMemoryAddress<Nothing> addr;
1185
CHECK(iter.readAtomicCmpXchg(&addr, ValType::I64, 1, &nothing,
1186
&nothing));
1187
}
1188
case uint32_t(ThreadOp::I64AtomicCmpXchg16U): {
1189
LinearMemoryAddress<Nothing> addr;
1190
CHECK(iter.readAtomicCmpXchg(&addr, ValType::I64, 2, &nothing,
1191
&nothing));
1192
}
1193
case uint32_t(ThreadOp::I64AtomicCmpXchg32U): {
1194
LinearMemoryAddress<Nothing> addr;
1195
CHECK(iter.readAtomicCmpXchg(&addr, ValType::I64, 4, &nothing,
1196
&nothing));
1197
}
1198
default:
1199
return iter.unrecognizedOpcode(&op);
1200
}
1201
break;
1202
}
1203
case uint16_t(Op::MozPrefix):
1204
return iter.unrecognizedOpcode(&op);
1205
default:
1206
return iter.unrecognizedOpcode(&op);
1207
}
1208
}
1209
1210
MOZ_CRASH("unreachable");
1211
1212
#undef CHECK
1213
}
1214
1215
bool wasm::ValidateFunctionBody(const ModuleEnvironment& env,
1216
uint32_t funcIndex, uint32_t bodySize,
1217
Decoder& d) {
1218
MOZ_ASSERT(env.funcTypes[funcIndex]->results().length() <= MaxFuncResults);
1219
1220
ValTypeVector locals;
1221
if (!locals.appendAll(env.funcTypes[funcIndex]->args())) {
1222
return false;
1223
}
1224
1225
const uint8_t* bodyBegin = d.currentPosition();
1226
1227
if (!DecodeLocalEntries(d, env.types, env.refTypesEnabled(),
1228
env.gcTypesEnabled(), &locals)) {
1229
return false;
1230
}
1231
1232
if (!DecodeFunctionBodyExprs(env, funcIndex, locals, bodyBegin + bodySize,
1233
&d)) {
1234
return false;
1235
}
1236
1237
return true;
1238
}
1239
1240
// Section macros.
1241
1242
static bool DecodePreamble(Decoder& d) {
1243
if (d.bytesRemain() > MaxModuleBytes) {
1244
return d.fail("module too big");
1245
}
1246
1247
uint32_t u32;
1248
if (!d.readFixedU32(&u32) || u32 != MagicNumber) {
1249
return d.fail("failed to match magic number");
1250
}
1251
1252
if (!d.readFixedU32(&u32) || u32 != EncodingVersion) {
1253
return d.failf("binary version 0x%" PRIx32
1254
" does not match expected version 0x%" PRIx32,
1255
u32, EncodingVersion);
1256
}
1257
1258
return true;
1259
}
1260
1261
enum class TypeState { None, Struct, ForwardStruct, Func };
1262
1263
typedef Vector<TypeState, 0, SystemAllocPolicy> TypeStateVector;
1264
1265
static bool ValidateTypeState(Decoder& d, TypeStateVector* typeState,
1266
ValType type) {
1267
if (!type.isRef()) {
1268
return true;
1269
}
1270
1271
uint32_t refTypeIndex = type.refTypeIndex();
1272
switch ((*typeState)[refTypeIndex]) {
1273
case TypeState::None:
1274
(*typeState)[refTypeIndex] = TypeState::ForwardStruct;
1275
break;
1276
case TypeState::Struct:
1277
case TypeState::ForwardStruct:
1278
break;
1279
case TypeState::Func:
1280
return d.fail("ref does not reference a struct type");
1281
}
1282
return true;
1283
}
1284
1285
#ifdef WASM_PRIVATE_REFTYPES
1286
static bool FuncTypeIsJSCompatible(Decoder& d, const FuncType& ft) {
1287
if (ft.exposesRef()) {
1288
return d.fail("cannot expose reference type");
1289
}
1290
return true;
1291
}
1292
#endif
1293
1294
static bool DecodeTypeVector(Decoder& d, ModuleEnvironment* env,
1295
TypeStateVector* typeState, uint32_t count,
1296
ValTypeVector* types) {
1297
if (!types->resize(count)) {
1298
return false;
1299
}
1300
1301
for (uint32_t i = 0; i < count; i++) {
1302
if (!d.readValType(env->types.length(), env->refTypesEnabled(),
1303
env->gcTypesEnabled(), &(*types)[i])) {
1304
return false;
1305
}
1306
if (!ValidateTypeState(d, typeState, (*types)[i])) {
1307
return false;
1308
}
1309
}
1310
return true;
1311
}
1312
1313
static bool DecodeFuncType(Decoder& d, ModuleEnvironment* env,
1314
TypeStateVector* typeState, uint32_t typeIndex) {
1315
uint32_t numArgs;
1316
if (!d.readVarU32(&numArgs)) {
1317
return d.fail("bad number of function args");
1318
}
1319
if (numArgs > MaxParams) {
1320
return d.fail("too many arguments in signature");
1321
}
1322
ValTypeVector args;
1323
if (!DecodeTypeVector(d, env, typeState, numArgs, &args)) {
1324
return false;
1325
}
1326
1327
uint32_t numResults;
1328
if (!d.readVarU32(&numResults)) {
1329
return d.fail("bad number of function returns");
1330
}
1331
if (numResults > env->funcMaxResults()) {
1332
return d.fail("too many returns in signature");
1333
}
1334
ValTypeVector results;
1335
if (!DecodeTypeVector(d, env, typeState, numResults, &results)) {
1336
return false;
1337
}
1338
1339
if ((*typeState)[typeIndex] != TypeState::None) {
1340
return d.fail("function type entry referenced as struct");
1341
}
1342
1343
env->types[typeIndex] =
1344
TypeDef(FuncType(std::move(args), std::move(results)));
1345
(*typeState)[typeIndex] = TypeState::Func;
1346
1347
return true;
1348
}
1349
1350
static bool DecodeStructType(Decoder& d, ModuleEnvironment* env,
1351
TypeStateVector* typeState, uint32_t typeIndex) {
1352
if (!env->gcTypesEnabled()) {
1353
return d.fail("Structure types not enabled");
1354
}
1355
1356
uint32_t numFields;
1357
if (!d.readVarU32(&numFields)) {
1358
return d.fail("Bad number of fields");
1359
}
1360
1361
if (numFields > MaxStructFields) {
1362
return d.fail("too many fields in structure");
1363
}
1364
1365
StructFieldVector fields;
1366
if (!fields.resize(numFields)) {
1367
return false;
1368
}
1369
1370
StructMetaTypeDescr::Layout layout;
1371
for (uint32_t i = 0; i < numFields; i++) {
1372
uint8_t flags;
1373
if (!d.readFixedU8(&flags)) {
1374
return d.fail("expected flag");
1375
}
1376
if ((flags & ~uint8_t(FieldFlags::AllowedMask)) != 0) {
1377
return d.fail("garbage flag bits");
1378
}
1379
fields[i].isMutable = flags & uint8_t(FieldFlags::Mutable);
1380
if (!d.readValType(env->types.length(), env->refTypesEnabled(),
1381
env->gcTypesEnabled(), &fields[i].type)) {
1382
return false;
1383
}
1384
if (!ValidateTypeState(d, typeState, fields[i].type)) {
1385
return false;
1386
}
1387
1388
CheckedInt32 offset;
1389
switch (fields[i].type.code()) {
1390
case ValType::I32:
1391
offset = layout.addScalar(Scalar::Int32);
1392
break;
1393
case ValType::I64:
1394
offset = layout.addScalar(Scalar::Int64);
1395
break;
1396
case ValType::F32:
1397
offset = layout.addScalar(Scalar::Float32);
1398
break;
1399
case ValType::F64:
1400
offset = layout.addScalar(Scalar::Float64);
1401
break;
1402
case ValType::Ref:
1403
offset = layout.addReference(ReferenceType::TYPE_OBJECT);
1404
break;
1405
case ValType::FuncRef:
1406
case ValType::AnyRef:
1407
offset = layout.addReference(ReferenceType::TYPE_WASM_ANYREF);
1408
break;
1409
default:
1410
MOZ_CRASH("Unknown type");
1411
}
1412
if (!offset.isValid()) {
1413
return d.fail("Object too large");
1414
}
1415
1416
fields[i].offset = offset.value();
1417
}
1418
1419
CheckedInt32 totalSize = layout.close();
1420
if (!totalSize.isValid()) {
1421
return d.fail("Object too large");
1422
}
1423
1424
bool isInline = InlineTypedObject::canAccommodateSize(totalSize.value());
1425
uint32_t offsetBy = isInline ? InlineTypedObject::offsetOfDataStart() : 0;
1426
1427
for (StructField& f : fields) {
1428
f.offset += offsetBy;
1429
}
1430
1431
if ((*typeState)[typeIndex] != TypeState::None &&
1432
(*typeState)[typeIndex] != TypeState::ForwardStruct) {
1433
return d.fail("struct type entry referenced as function");
1434
}
1435
1436
env->types[typeIndex] =
1437
TypeDef(StructType(std::move(fields), env->numStructTypes, isInline));
1438
(*typeState)[typeIndex] = TypeState::Struct;
1439
env->numStructTypes++;
1440
1441
return true;
1442
}
1443
1444
#ifdef ENABLE_WASM_GC
1445
static bool DecodeGCFeatureOptInSection(Decoder& d, ModuleEnvironment* env) {
1446
MaybeSectionRange range;
1447
if (!d.startSection(SectionId::GcFeatureOptIn, env, &range,
1448
"gcfeatureoptin")) {
1449
return false;
1450
}
1451
if (!range) {
1452
return true;
1453
}
1454
1455
uint32_t version;
1456
if (!d.readVarU32(&version)) {
1457
return d.fail("expected gc feature version");
1458
}
1459
1460
// For documentation of what's in the various versions, see
1462
//
1463
// Version 1 is complete and obsolete.
1464
// Version 2 is incomplete but obsolete.
1465
// Version 3 is in progress.
1466
1467
switch (version) {
1468
case 1:
1469
case 2:
1470
return d.fail(
1471
"Wasm GC feature versions 1 and 2 are no longer supported by this "
1472
"engine.\n"
1473
"The current version is 3, which is not backward-compatible with "
1474
"earlier\n"
1475
"versions:\n"
1476
" - The v1 encoding of ref.null is no longer accepted.\n"
1477
" - The v2 encodings of ref.eq, table.get, table.set, and "
1478
"table.size\n"
1479
" are no longer accepted.\n");
1480
case 3:
1481
break;
1482
default:
1483
return d.fail(
1484
"The specified Wasm GC feature version is unknown.\n"
1485
"The current version is 3.");
1486
}
1487
1488
env->gcFeatureOptIn = true;
1489
return d.finishSection(*range, "gcfeatureoptin");
1490
}
1491
#endif
1492
1493
static bool DecodeTypeSection(Decoder& d, ModuleEnvironment* env) {
1494
MaybeSectionRange range;
1495
if (!d.startSection(SectionId::Type, env, &range, "type")) {
1496
return false;
1497
}
1498
if (!range) {
1499
return true;
1500
}
1501
1502
uint32_t numTypes;
1503
if (!d.readVarU32(&numTypes)) {
1504
return d.fail("expected number of types");
1505
}
1506
1507
if (numTypes > MaxTypes) {
1508
return d.fail("too many types");
1509
}
1510
1511
if (!env->types.resize(numTypes)) {
1512
return false;
1513
}
1514
1515
TypeStateVector typeState;
1516
if (!typeState.appendN(TypeState::None, numTypes)) {
1517
return false;
1518
}
1519
1520
for (uint32_t typeIndex = 0; typeIndex < numTypes; typeIndex++) {
1521
uint8_t form;
1522
if (!d.readFixedU8(&form)) {
1523
return d.fail("expected type form");
1524
}
1525
1526
switch (form) {
1527
case uint8_t(TypeCode::Func):
1528
if (!DecodeFuncType(d, env, &typeState, typeIndex)) {
1529
return false;
1530
}
1531
break;
1532
case uint8_t(TypeCode::Struct):
1533
if (!DecodeStructType(d, env, &typeState, typeIndex)) {
1534
return false;
1535
}
1536
break;
1537
default:
1538
return d.fail("expected type form");
1539
}
1540
}
1541
1542
return d.finishSection(*range, "type");
1543
}
1544
1545
static UniqueChars DecodeName(Decoder& d) {
1546
uint32_t numBytes;
1547
if (!d.readVarU32(&numBytes)) {
1548
return nullptr;
1549
}
1550
1551
if (numBytes > MaxStringBytes) {
1552
return nullptr;
1553
}
1554
1555
const uint8_t* bytes;
1556
if (!d.readBytes(numBytes, &bytes)) {
1557
return nullptr;
1558
}
1559
1560
if (!IsUtf8(AsChars(MakeSpan(bytes, numBytes)))) {
1561
return nullptr;
1562
}
1563
1564
UniqueChars name(js_pod_malloc<char>(numBytes + 1));
1565
if (!name) {
1566
return nullptr;
1567
}
1568
1569
memcpy(name.get(), bytes, numBytes);
1570
name[numBytes] = '\0';
1571
1572
return name;
1573
}
1574
1575
static bool DecodeSignatureIndex(Decoder& d, const TypeDefVector& types,
1576
uint32_t* funcTypeIndex) {
1577
if (!d.readVarU32(funcTypeIndex)) {
1578
return d.fail("expected signature index");
1579
}
1580
1581
if (*funcTypeIndex >= types.length()) {
1582
return d.fail("signature index out of range");
1583
}
1584
1585
const TypeDef& def = types[*funcTypeIndex];
1586
1587
if (!def.isFuncType()) {
1588
return d.fail("signature index references non-signature");
1589
}
1590
1591
// FIXME: Remove this check when full multi-value function returns land.
1592
// Bug 1585909.
1593
if (def.funcType().results().length() > MaxFuncResults) {
1594
return d.fail("too many returns in signature");
1595
}
1596
1597
return true;
1598
}
1599
1600
static bool DecodeLimits(Decoder& d, Limits* limits,
1601
Shareable allowShared = Shareable::False) {
1602
uint8_t flags;
1603
if (!d.readFixedU8(&flags)) {
1604
return d.fail("expected flags");
1605
}
1606
1607
uint8_t mask = allowShared == Shareable::True
1608
? uint8_t(MemoryMasks::AllowShared)
1609
: uint8_t(MemoryMasks::AllowUnshared);
1610
1611
if (flags & ~uint8_t(mask)) {
1612
return d.failf("unexpected bits set in flags: %" PRIu32,
1613
(flags & ~uint8_t(mask)));
1614
}
1615
1616
if (!d.readVarU32(&limits->initial)) {
1617
return d.fail("expected initial length");
1618
}
1619
1620
if (flags & uint8_t(MemoryTableFlags::HasMaximum)) {
1621
uint32_t maximum;
1622
if (!d.readVarU32(&maximum)) {
1623
return d.fail("expected maximum length");
1624
}
1625
1626
if (limits->initial > maximum) {
1627
return d.failf(
1628
"memory size minimum must not be greater than maximum; "
1629
"maximum length %" PRIu32 " is less than initial length %" PRIu32,
1630
maximum, limits->initial);
1631
}
1632
1633
limits->maximum.emplace(maximum);
1634
}
1635
1636
limits->shared = Shareable::False;
1637
1638
if (allowShared == Shareable::True) {
1639
if ((flags & uint8_t(MemoryTableFlags::IsShared)) &&
1640
!(flags & uint8_t(MemoryTableFlags::HasMaximum))) {
1641
return d.fail("maximum length required for shared memory");
1642
}
1643
1644
limits->shared = (flags & uint8_t(MemoryTableFlags::IsShared))
1645
? Shareable::True
1646
: Shareable::False;
1647
}
1648
1649
return true;
1650
}
1651
1652
static bool DecodeTableTypeAndLimits(Decoder& d, bool refTypesEnabled,