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
#ifndef wasm_op_iter_h
20
#define wasm_op_iter_h
21
22
#include "mozilla/Pair.h"
23
#include "mozilla/Poison.h"
24
25
#include "jit/AtomicOp.h"
26
#include "js/Printf.h"
27
#include "wasm/WasmUtility.h"
28
#include "wasm/WasmValidate.h"
29
30
namespace js {
31
namespace wasm {
32
33
template <typename PointerType>
34
class TaggedValue {
35
public:
36
enum Kind {
37
ImmediateKind1 = 0,
38
ImmediateKind2 = 1,
39
PointerKind1 = 2,
40
PointerKind2 = 3
41
};
42
43
private:
44
uintptr_t bits_;
45
46
static constexpr uintptr_t PayloadShift = 2;
47
static constexpr uintptr_t KindMask = 0x3;
48
static constexpr uintptr_t PointerKindBit = 0x2;
49
50
constexpr static bool IsPointerKind(Kind kind) {
51
return uintptr_t(kind) & PointerKindBit;
52
}
53
constexpr static bool IsImmediateKind(Kind kind) {
54
return !IsPointerKind(kind);
55
}
56
57
static_assert(IsImmediateKind(ImmediateKind1), "immediate kind 1");
58
static_assert(IsImmediateKind(ImmediateKind2), "immediate kind 2");
59
static_assert(IsPointerKind(PointerKind1), "pointer kind 1");
60
static_assert(IsPointerKind(PointerKind2), "pointer kind 2");
61
62
static uintptr_t PackImmediate(Kind kind, uint32_t imm) {
63
MOZ_ASSERT(IsImmediateKind(kind));
64
MOZ_ASSERT((uintptr_t(kind) & KindMask) == kind);
65
MOZ_ASSERT((imm & (uint32_t(KindMask) << (32 - PayloadShift))) == 0);
66
return uintptr_t(kind) | (uintptr_t(imm) << PayloadShift);
67
}
68
69
static uintptr_t PackPointer(Kind kind, PointerType* ptr) {
70
uintptr_t ptrBits = reinterpret_cast<uintptr_t>(ptr);
71
MOZ_ASSERT(IsPointerKind(kind));
72
MOZ_ASSERT((uintptr_t(kind) & KindMask) == kind);
73
MOZ_ASSERT((ptrBits & KindMask) == 0);
74
return uintptr_t(kind) | ptrBits;
75
}
76
77
public:
78
TaggedValue(Kind kind, uint32_t imm) : bits_(PackImmediate(kind, imm)) {}
79
TaggedValue(Kind kind, PointerType* ptr) : bits_(PackPointer(kind, ptr)) {}
80
81
uintptr_t bits() const { return bits_; }
82
Kind kind() const { return Kind(bits() & KindMask); }
83
uint32_t immediate() const {
84
MOZ_ASSERT(IsImmediateKind(kind()));
85
return mozilla::AssertedCast<uint32_t>(bits() >> PayloadShift);
86
}
87
PointerType* pointer() const {
88
MOZ_ASSERT(IsPointerKind(kind()));
89
return reinterpret_cast<PointerType*>(bits() & ~KindMask);
90
}
91
};
92
93
// ResultType represents the WebAssembly spec's `resulttype`. Semantically, a
94
// result type is just a vec(valtype). For effiency, though, the ResultType
95
// value is packed into a word, with separate encodings for these 3 cases:
96
// []
97
// [valtype]
98
// pointer to ValTypeVector
99
//
100
// Additionally there is an encoding indicating uninitialized ResultType
101
// values.
102
//
103
// Generally in the latter case the ValTypeVector is the args() or results() of
104
// a FuncType in the compilation unit, so as long as the lifetime of the
105
// ResultType value is less than the OpIter, we can just borrow the pointer
106
// without ownership or copying.
107
class ResultType {
108
typedef TaggedValue<const ValTypeVector> Tagged;
109
Tagged tagged_;
110
111
enum Kind {
112
EmptyKind = Tagged::ImmediateKind1,
113
SingleKind = Tagged::ImmediateKind2,
114
#ifdef ENABLE_WASM_MULTI_VALUE
115
VectorKind = Tagged::PointerKind1,
116
#endif
117
InvalidKind = Tagged::PointerKind2,
118
};
119
120
ResultType(Kind kind, uint32_t imm) : tagged_(Tagged::Kind(kind), imm) {}
121
#ifdef ENABLE_WASM_MULTI_VALUE
122
explicit ResultType(const ValTypeVector* ptr)
123
: tagged_(Tagged::Kind(VectorKind), ptr) {}
124
#endif
125
126
Kind kind() const { return Kind(tagged_.kind()); }
127
128
ValType singleValType() const {
129
MOZ_ASSERT(kind() == SingleKind);
130
return ValType(PackedTypeCodeFromBits(tagged_.immediate()));
131
}
132
133
#ifdef ENABLE_WASM_MULTI_VALUE
134
const ValTypeVector& values() const {
135
MOZ_ASSERT(kind() == VectorKind);
136
return *tagged_.pointer();
137
}
138
#endif
139
140
public:
141
ResultType() : tagged_(Tagged::Kind(InvalidKind), nullptr) {}
142
143
static ResultType Empty() { return ResultType(EmptyKind, uint32_t(0)); }
144
static ResultType Single(ValType vt) {
145
return ResultType(SingleKind, vt.bitsUnsafe());
146
}
147
static ResultType Vector(const ValTypeVector& vals) {
148
switch (vals.length()) {
149
case 0:
150
return Empty();
151
case 1:
152
return Single(vals[0]);
153
default:
154
#ifdef ENABLE_WASM_MULTI_VALUE
155
return ResultType(&vals);
156
#else
157
MOZ_CRASH("multi-value returns not supported");
158
#endif
159
}
160
}
161
162
bool empty() const { return kind() == EmptyKind; }
163
164
size_t length() const {
165
switch (kind()) {
166
case EmptyKind:
167
return 0;
168
case SingleKind:
169
return 1;
170
#ifdef ENABLE_WASM_MULTI_VALUE
171
case VectorKind:
172
return values().length();
173
#endif
174
default:
175
MOZ_CRASH("bad resulttype");
176
}
177
}
178
179
ValType operator[](size_t i) const {
180
switch (kind()) {
181
case SingleKind:
182
MOZ_ASSERT(i == 0);
183
return singleValType();
184
#ifdef ENABLE_WASM_MULTI_VALUE
185
case VectorKind:
186
return values()[i];
187
#endif
188
default:
189
MOZ_CRASH("bad resulttype");
190
}
191
}
192
193
bool operator==(ResultType rhs) const {
194
switch (kind()) {
195
case EmptyKind:
196
case SingleKind:
197
case InvalidKind:
198
return tagged_.bits() == rhs.tagged_.bits();
199
#ifdef ENABLE_WASM_MULTI_VALUE
200
case VectorKind: {
201
if (rhs.kind() != VectorKind) {
202
return false;
203
}
204
return EqualContainers(values(), rhs.values());
205
}
206
#endif
207
default:
208
MOZ_CRASH("bad resulttype");
209
}
210
}
211
bool operator!=(ResultType rhs) const { return !(*this == rhs); }
212
};
213
214
// BlockType represents the WebAssembly spec's `blocktype`. Semantically, a
215
// block type is just a (vec(valtype) -> vec(valtype)) with four special
216
// encodings which are represented explicitly in BlockType:
217
// [] -> []
218
// [] -> [valtype]
219
// [params] -> [results] via pointer to FuncType
220
// [] -> [results] via pointer to FuncType (ignoring [params])
221
222
class BlockType {
223
typedef TaggedValue<const FuncType> Tagged;
224
Tagged tagged_;
225
226
enum Kind {
227
VoidToVoidKind = Tagged::ImmediateKind1,
228
VoidToSingleKind = Tagged::ImmediateKind2,
229
#ifdef ENABLE_WASM_MULTI_VALUE
230
FuncKind = Tagged::PointerKind1,
231
FuncResultsKind = Tagged::PointerKind2
232
#endif
233
};
234
235
BlockType(Kind kind, uint32_t imm) : tagged_(Tagged::Kind(kind), imm) {}
236
#ifdef ENABLE_WASM_MULTI_VALUE
237
BlockType(Kind kind, const FuncType& type)
238
: tagged_(Tagged::Kind(kind), &type) {}
239
#endif
240
241
Kind kind() const { return Kind(tagged_.kind()); }
242
ValType singleValType() const {
243
MOZ_ASSERT(kind() == VoidToSingleKind);
244
return ValType(PackedTypeCodeFromBits(tagged_.immediate()));
245
}
246
247
#ifdef ENABLE_WASM_MULTI_VALUE
248
const FuncType& funcType() const { return *tagged_.pointer(); }
249
#endif
250
251
public:
252
BlockType()
253
: tagged_(Tagged::Kind(VoidToVoidKind),
254
uint32_t(InvalidPackedTypeCode())) {}
255
256
static BlockType VoidToVoid() {
257
return BlockType(VoidToVoidKind, uint32_t(0));
258
}
259
static BlockType VoidToSingle(ValType vt) {
260
return BlockType(VoidToSingleKind, vt.bitsUnsafe());
261
}
262
static BlockType Func(const FuncType& type) {
263
#ifdef ENABLE_WASM_MULTI_VALUE
264
if (type.args().length() == 0) {
265
return FuncResults(type);
266
}
267
return BlockType(FuncKind, type);
268
#else
269
MOZ_ASSERT(type.args().length() == 0);
270
return FuncResults(type);
271
#endif
272
}
273
static BlockType FuncResults(const FuncType& type) {
274
switch (type.results().length()) {
275
case 0:
276
return VoidToVoid();
277
case 1:
278
return VoidToSingle(type.results()[0]);
279
default:
280
#ifdef ENABLE_WASM_MULTI_VALUE
281
return BlockType(FuncResultsKind, type);
282
#else
283
MOZ_CRASH("multi-value returns not supported");
284
#endif
285
}
286
}
287
288
ResultType params() const {
289
switch (kind()) {
290
case VoidToVoidKind:
291
case VoidToSingleKind:
292
#ifdef ENABLE_WASM_MULTI_VALUE
293
case FuncResultsKind:
294
#endif
295
return ResultType::Empty();
296
#ifdef ENABLE_WASM_MULTI_VALUE
297
case FuncKind:
298
return ResultType::Vector(funcType().args());
299
#endif
300
default:
301
MOZ_CRASH("unexpected kind");
302
}
303
}
304
305
ResultType results() const {
306
switch (kind()) {
307
case VoidToVoidKind:
308
return ResultType::Empty();
309
case VoidToSingleKind:
310
return ResultType::Single(singleValType());
311
#ifdef ENABLE_WASM_MULTI_VALUE
312
case FuncKind:
313
case FuncResultsKind:
314
return ResultType::Vector(funcType().results());
315
#endif
316
default:
317
MOZ_CRASH("unexpected kind");
318
}
319
}
320
321
bool operator==(BlockType rhs) const {
322
if (kind() != rhs.kind()) {
323
return false;
324
}
325
switch (kind()) {
326
case VoidToVoidKind:
327
case VoidToSingleKind:
328
return tagged_.bits() == rhs.tagged_.bits();
329
#ifdef ENABLE_WASM_MULTI_VALUE
330
case FuncKind:
331
return funcType() == rhs.funcType();
332
case FuncResultsKind:
333
return EqualContainers(funcType().results(), rhs.funcType().results());
334
#endif
335
default:
336
MOZ_CRASH("unexpected kind");
337
}
338
}
339
340
bool operator!=(BlockType rhs) const { return !(*this == rhs); }
341
};
342
343
// The kind of a control-flow stack item.
344
enum class LabelKind : uint8_t { Body, Block, Loop, Then, Else };
345
346
// The type of values on the operand stack during validation. The Any type
347
// represents the type of a value produced by an unconditional branch.
348
349
class StackType {
350
PackedTypeCode tc_;
351
352
#ifdef DEBUG
353
bool isValidCode() {
354
switch (UnpackTypeCodeType(tc_)) {
355
case TypeCode::I32:
356
case TypeCode::I64:
357
case TypeCode::F32:
358
case TypeCode::F64:
359
case TypeCode::AnyRef:
360
case TypeCode::FuncRef:
361
case TypeCode::Ref:
362
case TypeCode::NullRef:
363
case TypeCode::Limit:
364
return true;
365
default:
366
return false;
367
}
368
}
369
#endif
370
371
public:
372
enum Code {
373
I32 = uint8_t(ValType::I32),
374
I64 = uint8_t(ValType::I64),
375
F32 = uint8_t(ValType::F32),
376
F64 = uint8_t(ValType::F64),
377
378
AnyRef = uint8_t(ValType::AnyRef),
379
FuncRef = uint8_t(ValType::FuncRef),
380
Ref = uint8_t(ValType::Ref),
381
NullRef = uint8_t(ValType::NullRef),
382
383
Bottom = uint8_t(TypeCode::Limit),
384
};
385
386
StackType() : tc_(InvalidPackedTypeCode()) {}
387
388
MOZ_IMPLICIT StackType(Code c) : tc_(PackTypeCode(TypeCode(c))) {
389
MOZ_ASSERT(isValidCode());
390
}
391
392
explicit StackType(const ValType& t) : tc_(t.packed()) {}
393
394
PackedTypeCode packed() const { return tc_; }
395
396
Code code() const { return Code(UnpackTypeCodeType(tc_)); }
397
398
bool isNumeric() const {
399
switch (code()) {
400
case Code::Bottom:
401
case Code::I32:
402
case Code::I64:
403
case Code::F32:
404
case Code::F64:
405
return true;
406
default:
407
return false;
408
}
409
}
410
411
uint32_t refTypeIndex() const { return UnpackTypeCodeIndex(tc_); }
412
bool isRef() const { return UnpackTypeCodeType(tc_) == TypeCode::Ref; }
413
414
bool isReference() const { return IsReferenceType(tc_); }
415
416
bool operator==(const StackType& that) const { return tc_ == that.tc_; }
417
bool operator!=(const StackType& that) const { return tc_ != that.tc_; }
418
bool operator==(Code that) const {
419
MOZ_ASSERT(that != Code::Ref);
420
return code() == that;
421
}
422
bool operator!=(Code that) const { return !(*this == that); }
423
};
424
425
static inline ValType NonBottomToValType(StackType type) {
426
MOZ_ASSERT(type != StackType::Bottom);
427
return ValType(type.packed());
428
}
429
430
#ifdef DEBUG
431
// Families of opcodes that share a signature and validation logic.
432
enum class OpKind {
433
Block,
434
Loop,
435
Unreachable,
436
Drop,
437
I32,
438
I64,
439
F32,
440
F64,
441
Br,
442
BrIf,
443
BrTable,
444
Nop,
445
Unary,
446
Binary,
447
Comparison,
448
Conversion,
449
Load,
450
Store,
451
TeeStore,
452
MemorySize,
453
MemoryGrow,
454
Select,
455
GetLocal,
456
SetLocal,
457
TeeLocal,
458
GetGlobal,
459
SetGlobal,
460
TeeGlobal,
461
Call,
462
CallIndirect,
463
OldCallDirect,
464
OldCallIndirect,
465
Return,
466
If,
467
Else,
468
End,
469
Wait,
470
Wake,
471
Fence,
472
AtomicLoad,
473
AtomicStore,
474
AtomicBinOp,
475
AtomicCompareExchange,
476
OldAtomicLoad,
477
OldAtomicStore,
478
OldAtomicBinOp,
479
OldAtomicCompareExchange,
480
OldAtomicExchange,
481
ExtractLane,
482
ReplaceLane,
483
Swizzle,
484
Shuffle,
485
Splat,
486
MemOrTableCopy,
487
DataOrElemDrop,
488
MemFill,
489
MemOrTableInit,
490
TableFill,
491
TableGet,
492
TableGrow,
493
TableSet,
494
TableSize,
495
RefNull,
496
RefFunc,
497
StructNew,
498
StructGet,
499
StructSet,
500
StructNarrow,
501
};
502
503
// Return the OpKind for a given Op. This is used for sanity-checking that
504
// API users use the correct read function for a given Op.
505
OpKind Classify(OpBytes op);
506
#endif
507
508
// Common fields for linear memory access.
509
template <typename Value>
510
struct LinearMemoryAddress {
511
Value base;
512
uint32_t offset;
513
uint32_t align;
514
515
LinearMemoryAddress() : offset(0), align(0) {}
516
LinearMemoryAddress(Value base, uint32_t offset, uint32_t align)
517
: base(base), offset(offset), align(align) {}
518
};
519
520
template <typename ControlItem>
521
class ControlStackEntry {
522
// Use a Pair to optimize away empty ControlItem.
523
mozilla::Pair<BlockType, ControlItem> typeAndItem_;
524
525
// The "base" of a control stack entry is valueStack_.length() minus
526
// type().params().length(), i.e., the size of the value stack "below"
527
// this block.
528
uint32_t valueStackBase_;
529
bool polymorphicBase_;
530
531
LabelKind kind_;
532
533
public:
534
ControlStackEntry(LabelKind kind, BlockType type, uint32_t valueStackBase)
535
: typeAndItem_(type, ControlItem()),
536
valueStackBase_(valueStackBase),
537
polymorphicBase_(false),
538
kind_(kind) {
539
MOZ_ASSERT(type != BlockType());
540
}
541
542
LabelKind kind() const { return kind_; }
543
BlockType type() const { return typeAndItem_.first(); }
544
ResultType resultType() const { return type().results(); }
545
ResultType branchTargetType() const {
546
return kind_ == LabelKind::Loop ? type().params() : type().results();
547
}
548
uint32_t valueStackBase() const { return valueStackBase_; }
549
ControlItem& controlItem() { return typeAndItem_.second(); }
550
void setPolymorphicBase() { polymorphicBase_ = true; }
551
bool polymorphicBase() const { return polymorphicBase_; }
552
553
void switchToElse() {
554
MOZ_ASSERT(kind() == LabelKind::Then);
555
kind_ = LabelKind::Else;
556
polymorphicBase_ = false;
557
}
558
};
559
560
template <typename Value>
561
class TypeAndValueT {
562
// Use a Pair to optimize away empty Value.
563
mozilla::Pair<StackType, Value> tv_;
564
565
public:
566
TypeAndValueT() : tv_(StackType::Bottom, Value()) {}
567
explicit TypeAndValueT(StackType type) : tv_(type, Value()) {}
568
explicit TypeAndValueT(ValType type) : tv_(StackType(type), Value()) {}
569
TypeAndValueT(StackType type, Value value) : tv_(type, value) {}
570
TypeAndValueT(ValType type, Value value) : tv_(StackType(type), value) {}
571
StackType type() const { return tv_.first(); }
572
StackType& typeRef() { return tv_.first(); }
573
Value value() const { return tv_.second(); }
574
void setValue(Value value) { tv_.second() = value; }
575
};
576
577
// An iterator over the bytes of a function body. It performs validation
578
// and unpacks the data into a usable form.
579
//
580
// The MOZ_STACK_CLASS attribute here is because of the use of DebugOnly.
581
// There's otherwise nothing inherent in this class which would require
582
// it to be used on the stack.
583
template <typename Policy>
584
class MOZ_STACK_CLASS OpIter : private Policy {
585
public:
586
typedef typename Policy::Value Value;
587
typedef typename Policy::ValueVector ValueVector;
588
typedef TypeAndValueT<Value> TypeAndValue;
589
typedef Vector<TypeAndValue, 8, SystemAllocPolicy> TypeAndValueStack;
590
typedef typename Policy::ControlItem ControlItem;
591
typedef ControlStackEntry<ControlItem> Control;
592
typedef Vector<Control, 8, SystemAllocPolicy> ControlStack;
593
594
private:
595
Decoder& d_;
596
const ModuleEnvironment& env_;
597
598
TypeAndValueStack valueStack_;
599
TypeAndValueStack elseParamStack_;
600
ControlStack controlStack_;
601
602
#ifdef DEBUG
603
OpBytes op_;
604
#endif
605
size_t offsetOfLastReadOp_;
606
607
MOZ_MUST_USE bool readFixedU8(uint8_t* out) { return d_.readFixedU8(out); }
608
MOZ_MUST_USE bool readFixedU32(uint32_t* out) { return d_.readFixedU32(out); }
609
MOZ_MUST_USE bool readVarS32(int32_t* out) { return d_.readVarS32(out); }
610
MOZ_MUST_USE bool readVarU32(uint32_t* out) { return d_.readVarU32(out); }
611
MOZ_MUST_USE bool readVarS64(int64_t* out) { return d_.readVarS64(out); }
612
MOZ_MUST_USE bool readVarU64(uint64_t* out) { return d_.readVarU64(out); }
613
MOZ_MUST_USE bool readFixedF32(float* out) { return d_.readFixedF32(out); }
614
MOZ_MUST_USE bool readFixedF64(double* out) { return d_.readFixedF64(out); }
615
616
MOZ_MUST_USE bool readMemOrTableIndex(bool isMem, uint32_t* index);
617
MOZ_MUST_USE bool readLinearMemoryAddress(uint32_t byteSize,
618
LinearMemoryAddress<Value>* addr);
619
MOZ_MUST_USE bool readLinearMemoryAddressAligned(
620
uint32_t byteSize, LinearMemoryAddress<Value>* addr);
621
MOZ_MUST_USE bool readBlockType(BlockType* type);
622
MOZ_MUST_USE bool readStructTypeIndex(uint32_t* typeIndex);
623
MOZ_MUST_USE bool readFieldIndex(uint32_t* fieldIndex,
624
const StructType& structType);
625
626
MOZ_MUST_USE bool popCallArgs(const ValTypeVector& expectedTypes,
627
ValueVector* values);
628
629
MOZ_MUST_USE bool failEmptyStack();
630
MOZ_MUST_USE bool popStackType(StackType* type, Value* value);
631
MOZ_MUST_USE bool popWithType(ValType expected, Value* value);
632
MOZ_MUST_USE bool popWithType(ResultType expected, ValueVector* values);
633
MOZ_MUST_USE bool popThenPushType(ResultType expected, ValueVector* values);
634
MOZ_MUST_USE bool ensureTopHasType(ResultType expected, ValueVector* values);
635
636
MOZ_MUST_USE bool pushControl(LabelKind kind, BlockType type);
637
MOZ_MUST_USE bool checkStackAtEndOfBlock(ResultType* type,
638
ValueVector* values);
639
MOZ_MUST_USE bool getControl(uint32_t relativeDepth, Control** controlEntry);
640
MOZ_MUST_USE bool checkBranchValue(uint32_t relativeDepth, ResultType* type,
641
ValueVector* values);
642
MOZ_MUST_USE bool checkBrTableEntry(uint32_t* relativeDepth,
643
ResultType prevBranchType,
644
ResultType* branchType,
645
ValueVector* branchValues);
646
647
MOZ_MUST_USE bool push(ValType t) { return valueStack_.emplaceBack(t); }
648
MOZ_MUST_USE bool push(TypeAndValue tv) { return valueStack_.append(tv); }
649
MOZ_MUST_USE bool push(ResultType t) {
650
for (size_t i = 0; i < t.length(); i++) {
651
if (!push(t[i])) {
652
return false;
653
}
654
}
655
return true;
656
}
657
void infalliblePush(StackType t) { valueStack_.infallibleEmplaceBack(t); }
658
void infalliblePush(ValType t) {
659
valueStack_.infallibleEmplaceBack(StackType(t));
660
}
661
void infalliblePush(TypeAndValue tv) { valueStack_.infallibleAppend(tv); }
662
663
void afterUnconditionalBranch() {
664
valueStack_.shrinkTo(controlStack_.back().valueStackBase());
665
controlStack_.back().setPolymorphicBase();
666
}
667
668
inline bool checkIsSubtypeOf(ValType lhs, ValType rhs);
669
670
public:
671
#ifdef DEBUG
672
explicit OpIter(const ModuleEnvironment& env, Decoder& decoder)
673
: d_(decoder),
674
env_(env),
675
op_(OpBytes(Op::Limit)),
676
offsetOfLastReadOp_(0) {}
677
#else
678
explicit OpIter(const ModuleEnvironment& env, Decoder& decoder)
679
: d_(decoder), env_(env), offsetOfLastReadOp_(0) {}
680
#endif
681
682
// Return the decoding byte offset.
683
uint32_t currentOffset() const { return d_.currentOffset(); }
684
685
// Return the offset within the entire module of the last-read op.
686
size_t lastOpcodeOffset() const {
687
return offsetOfLastReadOp_ ? offsetOfLastReadOp_ : d_.currentOffset();
688
}
689
690
// Return a BytecodeOffset describing where the current op should be reported
691
// to trap/call.
692
BytecodeOffset bytecodeOffset() const {
693
return BytecodeOffset(lastOpcodeOffset());
694
}
695
696
// Test whether the iterator has reached the end of the buffer.
697
bool done() const { return d_.done(); }
698
699
// Return a pointer to the end of the buffer being decoded by this iterator.
700
const uint8_t* end() const { return d_.end(); }
701
702
// Report a general failure.
703
MOZ_MUST_USE bool fail(const char* msg) MOZ_COLD;
704
705
// Report a general failure with a context
706
MOZ_MUST_USE bool fail_ctx(const char* fmt, const char* context) MOZ_COLD;
707
708
// Report an unrecognized opcode.
709
MOZ_MUST_USE bool unrecognizedOpcode(const OpBytes* expr) MOZ_COLD;
710
711
// Return whether the innermost block has a polymorphic base of its stack.
712
// Ideally this accessor would be removed; consider using something else.
713
bool currentBlockHasPolymorphicBase() const {
714
return !controlStack_.empty() && controlStack_.back().polymorphicBase();
715
}
716
717
// ------------------------------------------------------------------------
718
// Decoding and validation interface.
719
720
MOZ_MUST_USE bool readOp(OpBytes* op);
721
MOZ_MUST_USE bool readFunctionStart(uint32_t funcIndex);
722
MOZ_MUST_USE bool readFunctionEnd(const uint8_t* bodyEnd);
723
MOZ_MUST_USE bool readReturn(ValueVector* values);
724
MOZ_MUST_USE bool readBlock(ResultType* paramType);
725
MOZ_MUST_USE bool readLoop(ResultType* paramType);
726
MOZ_MUST_USE bool readIf(ResultType* paramType, Value* condition);
727
MOZ_MUST_USE bool readElse(ResultType* paramType, ResultType* resultType,
728
ValueVector* thenResults);
729
MOZ_MUST_USE bool readEnd(LabelKind* kind, ResultType* type,
730
ValueVector* results,
731
ValueVector* resultsForEmptyElse);
732
void popEnd();
733
MOZ_MUST_USE bool readBr(uint32_t* relativeDepth, ResultType* type,
734
ValueVector* values);
735
MOZ_MUST_USE bool readBrIf(uint32_t* relativeDepth, ResultType* type,
736
ValueVector* values, Value* condition);
737
MOZ_MUST_USE bool readBrTable(Uint32Vector* depths, uint32_t* defaultDepth,
738
ResultType* defaultBranchValueType,
739
ValueVector* branchValues, Value* index);
740
MOZ_MUST_USE bool readUnreachable();
741
MOZ_MUST_USE bool readDrop();
742
MOZ_MUST_USE bool readUnary(ValType operandType, Value* input);
743
MOZ_MUST_USE bool readConversion(ValType operandType, ValType resultType,
744
Value* input);
745
MOZ_MUST_USE bool readBinary(ValType operandType, Value* lhs, Value* rhs);
746
MOZ_MUST_USE bool readComparison(ValType operandType, Value* lhs, Value* rhs);
747
MOZ_MUST_USE bool readLoad(ValType resultType, uint32_t byteSize,
748
LinearMemoryAddress<Value>* addr);
749
MOZ_MUST_USE bool readStore(ValType resultType, uint32_t byteSize,
750
LinearMemoryAddress<Value>* addr, Value* value);
751
MOZ_MUST_USE bool readTeeStore(ValType resultType, uint32_t byteSize,
752
LinearMemoryAddress<Value>* addr,
753
Value* value);
754
MOZ_MUST_USE bool readNop();
755
MOZ_MUST_USE bool readMemorySize();
756
MOZ_MUST_USE bool readMemoryGrow(Value* input);
757
MOZ_MUST_USE bool readSelect(bool typed, StackType* type, Value* trueValue,
758
Value* falseValue, Value* condition);
759
MOZ_MUST_USE bool readGetLocal(const ValTypeVector& locals, uint32_t* id);
760
MOZ_MUST_USE bool readSetLocal(const ValTypeVector& locals, uint32_t* id,
761
Value* value);
762
MOZ_MUST_USE bool readTeeLocal(const ValTypeVector& locals, uint32_t* id,
763
Value* value);
764
MOZ_MUST_USE bool readGetGlobal(uint32_t* id);
765
MOZ_MUST_USE bool readSetGlobal(uint32_t* id, Value* value);
766
MOZ_MUST_USE bool readTeeGlobal(uint32_t* id, Value* value);
767
MOZ_MUST_USE bool readI32Const(int32_t* i32);
768
MOZ_MUST_USE bool readI64Const(int64_t* i64);
769
MOZ_MUST_USE bool readF32Const(float* f32);
770
MOZ_MUST_USE bool readF64Const(double* f64);
771
MOZ_MUST_USE bool readRefFunc(uint32_t* funcTypeIndex);
772
MOZ_MUST_USE bool readRefNull();
773
MOZ_MUST_USE bool readCall(uint32_t* calleeIndex, ValueVector* argValues);
774
MOZ_MUST_USE bool readCallIndirect(uint32_t* funcTypeIndex,
775
uint32_t* tableIndex, Value* callee,
776
ValueVector* argValues);
777
MOZ_MUST_USE bool readOldCallDirect(uint32_t numFuncImports,
778
uint32_t* funcIndex,
779
ValueVector* argValues);
780
MOZ_MUST_USE bool readOldCallIndirect(uint32_t* funcTypeIndex, Value* callee,
781
ValueVector* argValues);
782
MOZ_MUST_USE bool readWake(LinearMemoryAddress<Value>* addr, Value* count);
783
MOZ_MUST_USE bool readWait(LinearMemoryAddress<Value>* addr,
784
ValType resultType, uint32_t byteSize,
785
Value* value, Value* timeout);
786
MOZ_MUST_USE bool readFence();
787
MOZ_MUST_USE bool readAtomicLoad(LinearMemoryAddress<Value>* addr,
788
ValType resultType, uint32_t byteSize);
789
MOZ_MUST_USE bool readAtomicStore(LinearMemoryAddress<Value>* addr,
790
ValType resultType, uint32_t byteSize,
791
Value* value);
792
MOZ_MUST_USE bool readAtomicRMW(LinearMemoryAddress<Value>* addr,
793
ValType resultType, uint32_t byteSize,
794
Value* value);
795
MOZ_MUST_USE bool readAtomicCmpXchg(LinearMemoryAddress<Value>* addr,
796
ValType resultType, uint32_t byteSize,
797
Value* oldValue, Value* newValue);
798
MOZ_MUST_USE bool readMemOrTableCopy(bool isMem, uint32_t* dstMemOrTableIndex,
799
Value* dst, uint32_t* srcMemOrTableIndex,
800
Value* src, Value* len);
801
MOZ_MUST_USE bool readDataOrElemDrop(bool isData, uint32_t* segIndex);
802
MOZ_MUST_USE bool readMemFill(Value* start, Value* val, Value* len);
803
MOZ_MUST_USE bool readMemOrTableInit(bool isMem, uint32_t* segIndex,
804
uint32_t* dstTableIndex, Value* dst,
805
Value* src, Value* len);
806
MOZ_MUST_USE bool readTableFill(uint32_t* tableIndex, Value* start,
807
Value* val, Value* len);
808
MOZ_MUST_USE bool readTableGet(uint32_t* tableIndex, Value* index);
809
MOZ_MUST_USE bool readTableGrow(uint32_t* tableIndex, Value* initValue,
810
Value* delta);
811
MOZ_MUST_USE bool readTableSet(uint32_t* tableIndex, Value* index,
812
Value* value);
813
MOZ_MUST_USE bool readTableSize(uint32_t* tableIndex);
814
MOZ_MUST_USE bool readStructNew(uint32_t* typeIndex, ValueVector* argValues);
815
MOZ_MUST_USE bool readStructGet(uint32_t* typeIndex, uint32_t* fieldIndex,
816
Value* ptr);
817
MOZ_MUST_USE bool readStructSet(uint32_t* typeIndex, uint32_t* fieldIndex,
818
Value* ptr, Value* val);
819
MOZ_MUST_USE bool readStructNarrow(ValType* inputType, ValType* outputType,
820
Value* ptr);
821
MOZ_MUST_USE bool readValType(ValType* type);
822
MOZ_MUST_USE bool readReferenceType(ValType* type, const char* const context);
823
824
// At a location where readOp is allowed, peek at the next opcode
825
// without consuming it or updating any internal state.
826
// Never fails: returns uint16_t(Op::Limit) in op->b0 if it can't read.
827
void peekOp(OpBytes* op);
828
829
// ------------------------------------------------------------------------
830
// Stack management.
831
832
// Set the top N result values.
833
void setResults(size_t count, const ValueVector& values) {
834
MOZ_ASSERT(valueStack_.length() >= count);
835
size_t base = valueStack_.length() - count;
836
for (size_t i = 0; i < count; i++) {
837
valueStack_[base + i].setValue(values[i]);
838
}
839
}
840
841
bool getResults(size_t count, ValueVector* values) {
842
MOZ_ASSERT(valueStack_.length() >= count);
843
if (!values->resize(count)) {
844
return false;
845
}
846
size_t base = valueStack_.length() - count;
847
for (size_t i = 0; i < count; i++) {
848
(*values)[i] = valueStack_[base + i].value();
849
}
850
return true;
851
}
852
853
// Set the result value of the current top-of-value-stack expression.
854
void setResult(Value value) { valueStack_.back().setValue(value); }
855
856
// Return the result value of the current top-of-value-stack expression.
857
Value getResult() { return valueStack_.back().value(); }
858
859
// Return a reference to the top of the control stack.
860
ControlItem& controlItem() { return controlStack_.back().controlItem(); }
861
862
// Return a reference to an element in the control stack.
863
ControlItem& controlItem(uint32_t relativeDepth) {
864
return controlStack_[controlStack_.length() - 1 - relativeDepth]
865
.controlItem();
866
}
867
868
// Return a reference to the outermost element on the control stack.
869
ControlItem& controlOutermost() { return controlStack_[0].controlItem(); }
870
871
// Test whether the control-stack is empty, meaning we've consumed the final
872
// end of the function body.
873
bool controlStackEmpty() const { return controlStack_.empty(); }
874
};
875
876
template <typename Policy>
877
inline bool OpIter<Policy>::checkIsSubtypeOf(ValType actual, ValType expected) {
878
if (actual == expected) {
879
return true;
880
}
881
882
if (actual.isReference() && expected.isReference() &&
883
env_.isRefSubtypeOf(actual, expected)) {
884
return true;
885
}
886
887
UniqueChars error(
888
JS_smprintf("type mismatch: expression has type %s but expected %s",
889
ToCString(actual), ToCString(expected)));
890
if (!error) {
891
return false;
892
}
893
894
return fail(error.get());
895
}
896
897
template <typename Policy>
898
inline bool OpIter<Policy>::unrecognizedOpcode(const OpBytes* expr) {
899
UniqueChars error(JS_smprintf("unrecognized opcode: %x %x", expr->b0,
900
IsPrefixByte(expr->b0) ? expr->b1 : 0));
901
if (!error) {
902
return false;
903
}
904
905
return fail(error.get());
906
}
907
908
template <typename Policy>
909
inline bool OpIter<Policy>::fail(const char* msg) {
910
return d_.fail(lastOpcodeOffset(), msg);
911
}
912
913
template <typename Policy>
914
inline bool OpIter<Policy>::fail_ctx(const char* fmt, const char* context) {
915
UniqueChars error(JS_smprintf(fmt, context));
916
if (!error) {
917
return false;
918
}
919
return fail(error.get());
920
}
921
922
template <typename Policy>
923
inline bool OpIter<Policy>::failEmptyStack() {
924
return valueStack_.empty() ? fail("popping value from empty stack")
925
: fail("popping value from outside block");
926
}
927
928
// This function pops exactly one value from the stack, yielding Bottom types in
929
// various cases and therefore making it the caller's responsibility to do the
930
// right thing for StackType::Bottom. Prefer (pop|top)WithType. This is an
931
// optimization for the super-common case where the caller is statically
932
// expecting the resulttype `[valtype]`.
933
template <typename Policy>
934
inline bool OpIter<Policy>::popStackType(StackType* type, Value* value) {
935
Control& block = controlStack_.back();
936
937
MOZ_ASSERT(valueStack_.length() >= block.valueStackBase());
938
if (MOZ_UNLIKELY(valueStack_.length() == block.valueStackBase())) {
939
// If the base of this block's stack is polymorphic, then we can pop a
940
// dummy value of any type; it won't be used since we're in unreachable
941
// code.
942
if (block.polymorphicBase()) {
943
*type = StackType::Bottom;
944
*value = Value();
945
946
// Maintain the invariant that, after a pop, there is always memory
947
// reserved to push a value infallibly.
948
return valueStack_.reserve(valueStack_.length() + 1);
949
}
950
951
return failEmptyStack();
952
}
953
954
TypeAndValue& tv = valueStack_.back();
955
*type = tv.type();
956
*value = tv.value();
957
valueStack_.popBack();
958
return true;
959
}
960
961
// This function pops exactly one value from the stack, checking that it has the
962
// expected type which can either be a specific value type or a type variable.
963
template <typename Policy>
964
inline bool OpIter<Policy>::popWithType(ValType expectedType, Value* value) {
965
StackType stackType;
966
if (!popStackType(&stackType, value)) {
967
return false;
968
}
969
970
return stackType == StackType::Bottom ||
971
checkIsSubtypeOf(NonBottomToValType(stackType), expectedType);
972
}
973
974
// Pops each of the given expected types (in reverse, because it's a stack).
975
template <typename Policy>
976
inline bool OpIter<Policy>::popWithType(ResultType expected,
977
ValueVector* values) {
978
size_t expectedLength = expected.length();
979
if (!values->resize(expectedLength)) {
980
return false;
981
}
982
for (size_t i = 0; i < expectedLength; i++) {
983
size_t reverseIndex = expectedLength - i - 1;
984
ValType expectedType = expected[reverseIndex];
985
Value* value = &(*values)[reverseIndex];
986
if (!popWithType(expectedType, value)) {
987
return false;
988
}
989
}
990
return true;
991
}
992
993
// This function is an optimization of the sequence:
994
// popWithType(ResultType, tmp)
995
// push(ResultType, tmp)
996
template <typename Policy>
997
inline bool OpIter<Policy>::popThenPushType(ResultType expected,
998
ValueVector* values) {
999
if (expected.empty()) {
1000
return true;
1001
}
1002
1003
Control& block = controlStack_.back();
1004
1005
size_t expectedLength = expected.length();
1006
if (!values->resize(expectedLength)) {
1007
return false;
1008
}
1009
1010
for (size_t i = 0; i != expectedLength; i++) {
1011
// We're iterating as-if we were popping each expected/actual type one by
1012
// one, which means iterating the array of expected results backwards.
1013
// The "current" value stack length refers to what the value stack length
1014
// would have been if we were popping it.
1015
size_t reverseIndex = expectedLength - i - 1;
1016
ValType expectedType = expected[reverseIndex];
1017
Value* value = &(*values)[reverseIndex];
1018
size_t currentValueStackLength = valueStack_.length() - i;
1019
1020
MOZ_ASSERT(currentValueStackLength >= block.valueStackBase());
1021
if (currentValueStackLength == block.valueStackBase()) {
1022
if (!block.polymorphicBase()) {
1023
return failEmptyStack();
1024
}
1025
1026
// If the base of this block's stack is polymorphic, then we can just
1027
// pull out as many fake values as we need to validate; they won't be used
1028
// since we're in unreachable code. We must however push these types on
1029
// the operand stack since they are now fixed by this constraint.
1030
if (!valueStack_.insert(valueStack_.begin() + currentValueStackLength,
1031
TypeAndValue(expectedType))) {
1032
return false;
1033
}
1034
1035
*value = Value();
1036
} else {
1037
TypeAndValue& observed = valueStack_[currentValueStackLength - 1];
1038
1039
if (observed.type() == StackType::Bottom) {
1040
observed.typeRef() = StackType(expectedType);
1041
*value = Value();
1042
} else {
1043
if (!checkIsSubtypeOf(NonBottomToValType(observed.type()),
1044
expectedType)) {
1045
return false;
1046
}
1047
1048
*value = observed.value();
1049
}
1050
}
1051
}
1052
return true;
1053
}
1054
1055
// This function checks that the top of the stack is a subtype of expected.
1056
// Like topWithType, it may insert synthetic StackType::Bottom entries if the
1057
// block's stack is polymorphic, which happens during unreachable code. However
1058
// unlike popThenPushType, it doesn't otherwise modify the value stack to update
1059
// stack types. Finally, ensureTopHasType allows passing |nullptr| as |values|
1060
// to avoid collecting values.
1061
1062
template <typename Policy>
1063
inline bool OpIter<Policy>::ensureTopHasType(ResultType expected,
1064
ValueVector* values) {
1065
if (expected.empty()) {
1066
return true;
1067
}
1068
1069
Control& block = controlStack_.back();
1070
1071
size_t expectedLength = expected.length();
1072
if (values && !values->resize(expectedLength)) {
1073
return false;
1074
}
1075
1076
for (size_t i = 0; i != expectedLength; i++) {
1077
// We're iterating as-if we were popping each expected/actual type one by
1078
// one, which means iterating the array of expected results backwards.
1079
// The "current" value stack length refers to what the value stack length
1080
// would have been if we were popping it.
1081
size_t reverseIndex = expectedLength - i - 1;
1082
ValType expectedType = expected[reverseIndex];
1083
auto collectValue = [&](const Value& v) {
1084
if (values) {
1085
(*values)[reverseIndex] = v;
1086
}
1087
};
1088
size_t currentValueStackLength = valueStack_.length() - i;
1089
1090
MOZ_ASSERT(currentValueStackLength >= block.valueStackBase());
1091
if (currentValueStackLength == block.valueStackBase()) {
1092
if (!block.polymorphicBase()) {
1093
return failEmptyStack();
1094
}
1095
1096
// Fill missing values with StackType::Bottom.
1097
if (!valueStack_.insert(valueStack_.begin() + currentValueStackLength,
1098
TypeAndValue(StackType::Bottom))) {
1099
return false;
1100
}
1101
1102
collectValue(Value());
1103
} else {
1104
TypeAndValue& observed = valueStack_[currentValueStackLength - 1];
1105
1106
if (observed.type() == StackType::Bottom) {
1107
collectValue(Value());
1108
} else {
1109
if (!checkIsSubtypeOf(NonBottomToValType(observed.type()),
1110
expectedType)) {
1111
return false;
1112
}
1113
1114
collectValue(observed.value());
1115
}
1116
}
1117
}
1118
1119
return true;
1120
}
1121
1122
template <typename Policy>
1123
inline bool OpIter<Policy>::pushControl(LabelKind kind, BlockType type) {
1124
ResultType paramType = type.params();
1125
1126
ValueVector values;
1127
if (!popThenPushType(paramType, &values)) {
1128
return false;
1129
}
1130
MOZ_ASSERT(valueStack_.length() >= paramType.length());
1131
uint32_t valueStackBase = valueStack_.length() - paramType.length();
1132
return controlStack_.emplaceBack(kind, type, valueStackBase);
1133
}
1134
1135
template <typename Policy>
1136
inline bool OpIter<Policy>::checkStackAtEndOfBlock(ResultType* expectedType,
1137
ValueVector* values) {
1138
Control& block = controlStack_.back();
1139
*expectedType = block.type().results();
1140
1141
MOZ_ASSERT(valueStack_.length() >= block.valueStackBase());
1142
if (expectedType->length() < valueStack_.length() - block.valueStackBase()) {
1143
return fail("unused values not explicitly dropped by end of block");
1144
}
1145
1146
return popThenPushType(*expectedType, values);
1147
}
1148
1149
template <typename Policy>
1150
inline bool OpIter<Policy>::getControl(uint32_t relativeDepth,
1151
Control** controlEntry) {
1152
if (relativeDepth >= controlStack_.length()) {
1153
return fail("branch depth exceeds current nesting level");
1154
}
1155
1156
*controlEntry = &controlStack_[controlStack_.length() - 1 - relativeDepth];
1157
return true;
1158
}
1159
1160
template <typename Policy>
1161
inline bool OpIter<Policy>::readBlockType(BlockType* type) {
1162
uint8_t nextByte;
1163
if (!d_.peekByte(&nextByte)) {
1164
return fail("unable to read block type");
1165
}
1166
1167
if (nextByte == uint8_t(TypeCode::BlockVoid)) {
1168
d_.uncheckedReadFixedU8();
1169
*type = BlockType::VoidToVoid();
1170
return true;
1171
}
1172
1173
if ((nextByte & SLEB128SignMask) == SLEB128SignBit) {
1174
ValType v;
1175
if (!readValType(&v)) {
1176
return false;
1177
}
1178
*type = BlockType::VoidToSingle(v);
1179
return true;
1180
}
1181
1182
#ifdef ENABLE_WASM_MULTI_VALUE
1183
if (!env_.multiValuesEnabled()) {
1184
return fail("invalid block type reference");
1185
}
1186
1187
int32_t x;
1188
if (!d_.readVarS32(&x) || x < 0 || uint32_t(x) >= env_.types.length()) {
1189
return fail("invalid block type type index");
1190
}
1191
1192
if (!env_.types[x].isFuncType()) {
1193
return fail("block type type index must be func type");
1194
}
1195
1196
*type = BlockType::Func(env_.types[x].funcType());
1197
1198
return true;
1199
#else
1200
return fail("invalid block type reference");
1201
#endif
1202
}
1203
1204
template <typename Policy>
1205
inline bool OpIter<Policy>::readOp(OpBytes* op) {
1206
MOZ_ASSERT(!controlStack_.empty());
1207
1208
offsetOfLastReadOp_ = d_.currentOffset();
1209
1210
if (MOZ_UNLIKELY(!d_.readOp(op))) {
1211
return fail("unable to read opcode");
1212
}
1213
1214
#ifdef DEBUG
1215
op_ = *op;
1216
#endif
1217
1218
return true;
1219
}
1220
1221
template <typename Policy>
1222
inline void OpIter<Policy>::peekOp(OpBytes* op) {
1223
const uint8_t* pos = d_.currentPosition();
1224
1225
if (MOZ_UNLIKELY(!d_.readOp(op))) {
1226
op->b0 = uint16_t(Op::Limit);
1227
}
1228
1229
d_.rollbackPosition(pos);
1230
}
1231
1232
template <typename Policy>
1233
inline bool OpIter<Policy>::readFunctionStart(uint32_t funcIndex) {
1234
MOZ_ASSERT(elseParamStack_.empty());
1235
MOZ_ASSERT(valueStack_.empty());
1236
MOZ_ASSERT(controlStack_.empty());
1237
MOZ_ASSERT(op_.b0 == uint16_t(Op::Limit));
1238
BlockType type = BlockType::FuncResults(*env_.funcTypes[funcIndex]);
1239
return pushControl(LabelKind::Body, type);
1240
}
1241
1242
template <typename Policy>
1243
inline bool OpIter<Policy>::readFunctionEnd(const uint8_t* bodyEnd) {
1244
if (d_.currentPosition() != bodyEnd) {
1245
return fail("function body length mismatch");
1246
}
1247
1248
if (!controlStack_.empty()) {
1249
return fail("unbalanced function body control flow");
1250
}
1251
MOZ_ASSERT(elseParamStack_.empty());
1252
1253
#ifdef DEBUG
1254
op_ = OpBytes(Op::Limit);
1255
#endif
1256
valueStack_.clear();
1257
return true;
1258
}
1259
1260
template <typename Policy>
1261
inline bool OpIter<Policy>::readReturn(ValueVector* values) {
1262
MOZ_ASSERT(Classify(op_) == OpKind::Return);
1263
1264
Control& body = controlStack_[0];
1265
MOZ_ASSERT(body.kind() == LabelKind::Body);
1266
1267
if (!popWithType(body.resultType(), values)) {
1268
return false;
1269
}
1270
1271
afterUnconditionalBranch();
1272
return true;
1273
}
1274
1275
template <typename Policy>
1276
inline bool OpIter<Policy>::readBlock(ResultType* paramType) {
1277
MOZ_ASSERT(Classify(op_) == OpKind::Block);
1278
1279
BlockType type;
1280
if (!readBlockType(&type)) {
1281
return false;
1282
}
1283
1284
*paramType = type.params();
1285
return pushControl(LabelKind::Block, type);
1286
}
1287
1288
template <typename Policy>
1289
inline bool OpIter<Policy>::readLoop(ResultType* paramType) {
1290
MOZ_ASSERT(Classify(op_) == OpKind::Loop);
1291
1292
BlockType type;
1293
if (!readBlockType(&type)) {
1294
return false;
1295
}
1296
1297
*paramType = type.params();
1298
return pushControl(LabelKind::Loop, type);
1299
}
1300
1301
template <typename Policy>
1302
inline bool OpIter<Policy>::readIf(ResultType* paramType, Value* condition) {
1303
MOZ_ASSERT(Classify(op_) == OpKind::If);
1304
1305
BlockType type;
1306
if (!readBlockType(&type)) {
1307
return false;
1308
}
1309
1310
if (!popWithType(ValType::I32, condition)) {
1311
return false;
1312
}
1313
1314
if (!pushControl(LabelKind::Then, type)) {
1315
return false;
1316
}
1317
1318
*paramType = type.params();
1319
size_t paramsLength = type.params().length();
1320
return elseParamStack_.append(valueStack_.end() - paramsLength, paramsLength);
1321
}
1322
1323
template <typename Policy>
1324
inline bool OpIter<Policy>::readElse(ResultType* paramType,
1325
ResultType* resultType,
1326
ValueVector* thenResults) {
1327
MOZ_ASSERT(Classify(op_) == OpKind::Else);
1328
1329
Control& block = controlStack_.back();
1330
if (block.kind() != LabelKind::Then) {
1331
return fail("else can only be used within an if");
1332
}
1333
1334
*paramType = block.type().params();
1335
if (!checkStackAtEndOfBlock(resultType, thenResults)) {
1336
return false;
1337
}
1338
1339
valueStack_.shrinkTo(block.valueStackBase());
1340
1341
size_t nparams = block.type().params().length();
1342
MOZ_ASSERT(elseParamStack_.length() >= nparams);
1343
valueStack_.infallibleAppend(elseParamStack_.end() - nparams, nparams);
1344
elseParamStack_.shrinkBy(nparams);
1345
1346
block.switchToElse();
1347
return true;
1348
}
1349
1350
template <typename Policy>
1351
inline bool OpIter<Policy>::readEnd(LabelKind* kind, ResultType* type,
1352
ValueVector* results,
1353
ValueVector* resultsForEmptyElse) {
1354
MOZ_ASSERT(Classify(op_) == OpKind::End);
1355
1356
if (!checkStackAtEndOfBlock(type, results)) {
1357
return false;
1358
}
1359
1360
Control& block = controlStack_.back();
1361
1362
if (block.kind() == LabelKind::Then) {
1363
ResultType params = block.type().params();
1364
// If an `if` block ends with `end` instead of `else`, then the `else` block
1365
// implicitly passes the `if` parameters as the `else` results. In that
1366
// case, assert that the `if`'s param type matches the result type.
1367
if (params != block.type().results()) {
1368
return fail("if without else with a result value");
1369
}
1370
1371
size_t nparams = params.length();
1372
MOZ_ASSERT(elseParamStack_.length() >= nparams);
1373
if (!resultsForEmptyElse->resize(nparams)) {
1374
return false;
1375
}
1376
const TypeAndValue* elseParams = elseParamStack_.end() - nparams;
1377
for (size_t i = 0; i < nparams; i++) {
1378
(*resultsForEmptyElse)[i] = elseParams[i].value();
1379
}
1380
elseParamStack_.shrinkBy(nparams);
1381
}
1382
1383
*kind = block.kind();
1384
return true;
1385
}
1386
1387
template <typename Policy>
1388
inline void OpIter<Policy>::popEnd() {
1389
MOZ_ASSERT(Classify(op_) == OpKind::End);
1390
1391
controlStack_.popBack();
1392
}
1393
1394
template <typename Policy>
1395
inline bool OpIter<Policy>::checkBranchValue(uint32_t relativeDepth,
1396
ResultType* type,
1397
ValueVector* values) {
1398
Control* block = nullptr;
1399
if (!getControl(relativeDepth, &block)) {
1400
return false;
1401
}
1402
1403
*type = block->branchTargetType();
1404
return popThenPushType(*type, values);
1405
}
1406
1407
template <typename Policy>
1408
inline bool OpIter<Policy>::readBr(uint32_t* relativeDepth, ResultType* type,
1409
ValueVector* values) {
1410
MOZ_ASSERT(Classify(op_) == OpKind::Br);
1411
1412
if (!readVarU32(relativeDepth)) {
1413
return fail("unable to read br depth");
1414
}
1415
1416
if (!checkBranchValue(*relativeDepth, type, values)) {
1417
return false;
1418
}
1419
1420
afterUnconditionalBranch();
1421
return true;
1422
}
1423
1424
template <typename Policy>
1425
inline bool OpIter<Policy>::readBrIf(uint32_t* relativeDepth, ResultType* type,
1426
ValueVector* values, Value* condition) {
1427
MOZ_ASSERT(Classify(op_) == OpKind::BrIf);
1428
1429
if (!readVarU32(relativeDepth)) {
1430
return fail("unable to read br_if depth");
1431
}
1432
1433
if (!popWithType(ValType::I32, condition)) {
1434
return false;
1435
}
1436
1437
return checkBranchValue(*relativeDepth, type, values);
1438
}
1439
1440
#define UNKNOWN_ARITY UINT32_MAX
1441
1442
template <typename Policy>
1443
inline bool OpIter<Policy>::checkBrTableEntry(uint32_t* relativeDepth,
1444
ResultType prevType,
1445
ResultType* type,
1446
ValueVector* branchValues) {
1447
if (!readVarU32(relativeDepth)) {
1448
return false;
1449
}
1450
1451
Control* block = nullptr;
1452
if (!getControl(*relativeDepth, &block)) {
1453
return false;
1454
}
1455
1456
*type = block->branchTargetType();
1457
1458
if (prevType != ResultType()) {
1459
if (prevType.length() != type->length()) {
1460
return fail("br_table targets must all have the same arity");
1461
}
1462
1463
// Avoid re-collecting the same values for subsequent branch targets.
1464
branchValues = nullptr;
1465
}
1466
1467
return ensureTopHasType(*type, branchValues);
1468
}
1469
1470
template <typename Policy>
1471
inline bool OpIter<Policy>::readBrTable(Uint32Vector* depths,
1472
uint32_t* defaultDepth,
1473
ResultType* defaultBranchType,
1474
ValueVector* branchValues,
1475
Value* index) {
1476
MOZ_ASSERT(Classify(op_) == OpKind::BrTable);
1477
1478
uint32_t tableLength;
1479
if (!readVarU32(&tableLength)) {
1480
return fail("unable to read br_table table length");
1481
}
1482
1483
if (tableLength > MaxBrTableElems) {
1484
return fail("br_table too big");
1485
}
1486
1487
if (!popWithType(ValType::I32, index)) {
1488
return false;
1489
}
1490
1491
if (!depths->resize(tableLength)) {
1492
return false;
1493
}
1494
1495
ResultType prevBranchType;
1496
for (uint32_t i = 0; i < tableLength; i++) {
1497
ResultType branchType;
1498
if (!checkBrTableEntry(&(*depths)[i], prevBranchType, &branchType,
1499
branchValues)) {
1500
return false;
1501
}
1502
prevBranchType = branchType;
1503
}
1504
1505
if (!checkBrTableEntry(defaultDepth, prevBranchType, defaultBranchType,
1506
branchValues)) {
1507
return false;
1508
}
1509
1510
MOZ_ASSERT(*defaultBranchType != ResultType());
1511
1512
afterUnconditionalBranch();
1513
return true;
1514
}
1515
1516
#undef UNKNOWN_ARITY
1517
1518
template <typename Policy>
1519
inline bool OpIter<Policy>::readUnreachable() {
1520
MOZ_ASSERT(Classify(op_) == OpKind::Unreachable);
1521
1522
afterUnconditionalBranch();
1523
return true;
1524
}
1525
1526
template <typename Policy>
1527
inline bool OpIter<Policy>::readDrop() {
1528
MOZ_ASSERT(Classify(op_) == OpKind::Drop);
1529
StackType type;
1530
Value value;
1531
return popStackType(&type, &value);
1532
}
1533
1534
template <typename Policy>
1535
inline bool OpIter<Policy>::readUnary(ValType operandType, Value* input) {
1536
MOZ_ASSERT(Classify(op_) == OpKind::Unary);
1537
1538
if (!popWithType(operandType, input)) {
1539
return false;
1540
}
1541
1542
infalliblePush(operandType);
1543
1544
return true;
1545
}
1546
1547
template <typename Policy>
1548
inline bool OpIter<Policy>::readConversion(ValType operandType,
1549
ValType resultType, Value* input) {
1550
MOZ_ASSERT(Classify(op_) == OpKind::Conversion);
1551
1552
if (!popWithType(operandType, input)) {
1553
return false;
1554
}
1555
1556
infalliblePush(resultType);
1557
1558
return true;
1559
}
1560
1561
template <typename Policy>
1562
inline bool OpIter<Policy>::readBinary(ValType operandType, Value* lhs,
1563
Value* rhs) {
1564
MOZ_ASSERT(Classify(op_) == OpKind::Binary);
1565
1566
if (!popWithType(operandType, rhs)) {
1567
return false;
1568
}
1569
1570
if (!popWithType(operandType, lhs)) {
1571
return false;
1572
}
1573
1574
infalliblePush(operandType);
1575
1576
return true;
1577
}
1578
1579
template <typename Policy>
1580
inline bool OpIter<Policy>::readComparison(ValType operandType, Value* lhs,
1581
Value* rhs) {
1582
MOZ_ASSERT(Classify(op_) == OpKind::Comparison);
1583
1584
if (!popWithType(operandType, rhs)) {
1585
return false;
1586
}
1587
1588
if (!popWithType(operandType, lhs)) {
1589
return false;
1590
}
1591
1592
infalliblePush(ValType::I32);
1593
1594
return true;
1595
}
1596
1597
// For memories, the index is currently always a placeholder zero byte.
1598
//
1599
// For tables, the index is a placeholder zero byte until we get multi-table
1600
// with the reftypes proposal.
1601
//
1602
// The zero-ness of the value must be checked by the caller.
1603
template <typename Policy>
1604
inline bool OpIter<Policy>::readMemOrTableIndex(bool isMem, uint32_t* index) {
1605
#ifdef ENABLE_WASM_REFTYPES
1606
bool readByte = isMem;
1607
#else
1608
bool readByte = true;
1609
#endif
1610
if (readByte) {
1611
uint8_t indexTmp;
1612
if (!readFixedU8(&indexTmp)) {
1613
return false;
1614
}
1615
*index = indexTmp;
1616
} else {
1617
if (!readVarU32(index)) {
1618
return false;
1619
}
1620
}
1621
return true;
1622
}
1623
1624
template <typename Policy>
1625
inline bool OpIter<Policy>::readLinearMemoryAddress(
1626
uint32_t byteSize, LinearMemoryAddress<Value>* addr) {
1627
if (!env_.usesMemory()) {
1628
return fail("can't touch memory without memory");
1629
}
1630
1631
uint8_t alignLog2;
1632
if (!readFixedU8(&alignLog2)) {
1633
return fail("unable to read load alignment");
1634
}
1635
1636
if (!readVarU32(&addr->offset)) {
1637
return fail("unable to read load offset");
1638
}
1639
1640
if (alignLog2 >= 32 || (uint32_t(1) << alignLog2) > byteSize) {
1641
return fail("greater than natural alignment");
1642
}
1643
1644
if (!popWithType(ValType::I32, &addr->base)) {
1645
return false;
1646
}
1647
1648
addr->align = uint32_t(1) << alignLog2;
1649
return true;
1650
}
1651
1652
template <typename Policy>
1653
inline bool OpIter<Policy>::readLinearMemoryAddressAligned(
1654
uint32_t byteSize, LinearMemoryAddress<Value>* addr) {
1655
if (!readLinearMemoryAddress(byteSize, addr)) {
1656
return false;
1657
}
1658
1659
if (addr->align != byteSize) {
1660
return fail("not natural alignment");
1661
}
1662
1663
return true;
1664
}
1665
1666
template <typename Policy>
1667
inline bool OpIter<Policy>::readLoad(ValType resultType, uint32_t byteSize,
1668
LinearMemoryAddress<Value>* addr) {
1669
MOZ_ASSERT(Classify(op_) == OpKind::Load);
1670
1671
if (!readLinearMemoryAddress(byteSize, addr)) {
1672
return false;
1673
}
1674
1675
infalliblePush(resultType);
1676
1677
return true;
1678
}
1679
1680
template <typename Policy>
1681
inline bool OpIter<Policy>::readStore(ValType resultType, uint32_t byteSize,
1682
LinearMemoryAddress<Value>* addr,
1683
Value* value) {
1684
MOZ_ASSERT(Classify(op_) == OpKind::Store);
1685
1686
if (!popWithType(resultType, value)) {
1687
return false;
1688
}
1689
1690
if (!readLinearMemoryAddress(byteSize, addr)) {
1691
return false;
1692
}
1693
1694
return true;
1695
}
1696
1697
template <typename Policy>
1698
inline bool OpIter<Policy>::readTeeStore(ValType resultType, uint32_t byteSize,
1699
LinearMemoryAddress<Value>* addr,
1700
Value* value) {
1701
MOZ_ASSERT(Classify(op_) == OpKind::TeeStore);
1702
1703
if (!popWithType(resultType, value)) {
1704
return false;
1705
}
1706
1707
if (!readLinearMemoryAddress(byteSize, addr)) {
1708
return false;
1709
}
1710
1711
infalliblePush(TypeAndValue(resultType, *value));
1712
return true;
1713
}
1714
1715
template <typename Policy>
1716
inline bool OpIter<Policy>::readNop() {
1717
MOZ_ASSERT(Classify(op_) == OpKind::Nop);
1718
1719
return true;
1720
}
1721
1722
template <typename Policy>
1723
inline bool OpIter<Policy>::readMemorySize() {
1724
MOZ_ASSERT(Classify(op_) == OpKind::MemorySize);
1725
1726
if (!env_.usesMemory()) {
1727
return fail("can't touch memory without memory");
1728
}
1729
1730
uint8_t flags;
1731
if (!readFixedU8(&flags)) {
1732
return false;
1733
}
1734
1735
if (flags != uint8_t(MemoryTableFlags::Default)) {
1736
return fail("unexpected flags");
1737
}
1738
1739
return push(ValType::I32);
1740
}
1741
1742
template <typename Policy>
1743
inline bool OpIter<Policy>::readMemoryGrow(Value* input) {
1744
MOZ_ASSERT(Classify(op_) == OpKind::MemoryGrow);
1745
1746
if (!env_.usesMemory()) {
1747
return fail("can't touch memory without memory");
1748
}
1749
1750
uint8_t flags;
1751
if (!readFixedU8(&flags)) {
1752
return false;
1753
}
1754
1755
if (flags != uint8_t(MemoryTableFlags::Default)) {