Line data Source code
1 : // Copyright 2017 the V8 project authors. All rights reserved.
2 : // Use of this source code is governed by a BSD-style license that can be
3 : // found in the LICENSE file.
4 :
5 : #ifndef V8_WASM_FUNCTION_BODY_DECODER_IMPL_H_
6 : #define V8_WASM_FUNCTION_BODY_DECODER_IMPL_H_
7 :
8 : // Do only include this header for implementing new Interface of the
9 : // WasmFullDecoder.
10 :
11 : #include "src/base/platform/elapsed-timer.h"
12 : #include "src/bit-vector.h"
13 : #include "src/wasm/decoder.h"
14 : #include "src/wasm/function-body-decoder.h"
15 : #include "src/wasm/wasm-features.h"
16 : #include "src/wasm/wasm-limits.h"
17 : #include "src/wasm/wasm-module.h"
18 : #include "src/wasm/wasm-opcodes.h"
19 :
20 : namespace v8 {
21 : namespace internal {
22 : namespace wasm {
23 :
24 : struct WasmGlobal;
25 : struct WasmException;
26 :
27 : #define TRACE(...) \
28 : do { \
29 : if (FLAG_trace_wasm_decoder) PrintF(__VA_ARGS__); \
30 : } while (false)
31 :
32 : #define TRACE_INST_FORMAT " @%-8d #%-20s|"
33 :
34 : // Return the evaluation of `condition` if validate==true, DCHECK that it's
35 : // true and always return true otherwise.
36 : #define VALIDATE(condition) \
37 : (validate ? (condition) : [&] { \
38 : DCHECK(condition); \
39 : return true; \
40 : }())
41 :
42 : #define RET_ON_PROTOTYPE_OPCODE(feat) \
43 : DCHECK(!this->module_ || this->module_->origin == kWasmOrigin); \
44 : if (!this->enabled_.feat) { \
45 : this->error("Invalid opcode (enable with --experimental-wasm-" #feat ")"); \
46 : } else { \
47 : this->detected_->feat = true; \
48 : }
49 :
50 : #define CHECK_PROTOTYPE_OPCODE(feat) \
51 : DCHECK(!this->module_ || this->module_->origin == kWasmOrigin); \
52 : if (!this->enabled_.feat) { \
53 : this->error("Invalid opcode (enable with --experimental-wasm-" #feat ")"); \
54 : break; \
55 : } else { \
56 : this->detected_->feat = true; \
57 : }
58 :
59 : #define OPCODE_ERROR(opcode, message) \
60 : (this->errorf(this->pc_, "%s: %s", WasmOpcodes::OpcodeName(opcode), \
61 : (message)))
62 :
63 : #define ATOMIC_OP_LIST(V) \
64 : V(AtomicNotify, Uint32) \
65 : V(I32AtomicWait, Uint32) \
66 : V(I64AtomicWait, Uint32) \
67 : V(I32AtomicLoad, Uint32) \
68 : V(I64AtomicLoad, Uint64) \
69 : V(I32AtomicLoad8U, Uint8) \
70 : V(I32AtomicLoad16U, Uint16) \
71 : V(I64AtomicLoad8U, Uint8) \
72 : V(I64AtomicLoad16U, Uint16) \
73 : V(I64AtomicLoad32U, Uint32) \
74 : V(I32AtomicAdd, Uint32) \
75 : V(I32AtomicAdd8U, Uint8) \
76 : V(I32AtomicAdd16U, Uint16) \
77 : V(I64AtomicAdd, Uint64) \
78 : V(I64AtomicAdd8U, Uint8) \
79 : V(I64AtomicAdd16U, Uint16) \
80 : V(I64AtomicAdd32U, Uint32) \
81 : V(I32AtomicSub, Uint32) \
82 : V(I64AtomicSub, Uint64) \
83 : V(I32AtomicSub8U, Uint8) \
84 : V(I32AtomicSub16U, Uint16) \
85 : V(I64AtomicSub8U, Uint8) \
86 : V(I64AtomicSub16U, Uint16) \
87 : V(I64AtomicSub32U, Uint32) \
88 : V(I32AtomicAnd, Uint32) \
89 : V(I64AtomicAnd, Uint64) \
90 : V(I32AtomicAnd8U, Uint8) \
91 : V(I32AtomicAnd16U, Uint16) \
92 : V(I64AtomicAnd8U, Uint8) \
93 : V(I64AtomicAnd16U, Uint16) \
94 : V(I64AtomicAnd32U, Uint32) \
95 : V(I32AtomicOr, Uint32) \
96 : V(I64AtomicOr, Uint64) \
97 : V(I32AtomicOr8U, Uint8) \
98 : V(I32AtomicOr16U, Uint16) \
99 : V(I64AtomicOr8U, Uint8) \
100 : V(I64AtomicOr16U, Uint16) \
101 : V(I64AtomicOr32U, Uint32) \
102 : V(I32AtomicXor, Uint32) \
103 : V(I64AtomicXor, Uint64) \
104 : V(I32AtomicXor8U, Uint8) \
105 : V(I32AtomicXor16U, Uint16) \
106 : V(I64AtomicXor8U, Uint8) \
107 : V(I64AtomicXor16U, Uint16) \
108 : V(I64AtomicXor32U, Uint32) \
109 : V(I32AtomicExchange, Uint32) \
110 : V(I64AtomicExchange, Uint64) \
111 : V(I32AtomicExchange8U, Uint8) \
112 : V(I32AtomicExchange16U, Uint16) \
113 : V(I64AtomicExchange8U, Uint8) \
114 : V(I64AtomicExchange16U, Uint16) \
115 : V(I64AtomicExchange32U, Uint32) \
116 : V(I32AtomicCompareExchange, Uint32) \
117 : V(I64AtomicCompareExchange, Uint64) \
118 : V(I32AtomicCompareExchange8U, Uint8) \
119 : V(I32AtomicCompareExchange16U, Uint16) \
120 : V(I64AtomicCompareExchange8U, Uint8) \
121 : V(I64AtomicCompareExchange16U, Uint16) \
122 : V(I64AtomicCompareExchange32U, Uint32)
123 :
124 : #define ATOMIC_STORE_OP_LIST(V) \
125 : V(I32AtomicStore, Uint32) \
126 : V(I64AtomicStore, Uint64) \
127 : V(I32AtomicStore8U, Uint8) \
128 : V(I32AtomicStore16U, Uint16) \
129 : V(I64AtomicStore8U, Uint8) \
130 : V(I64AtomicStore16U, Uint16) \
131 : V(I64AtomicStore32U, Uint32)
132 :
133 : // Helpers for decoding different kinds of immediates which follow bytecodes.
134 : template <Decoder::ValidateFlag validate>
135 : struct LocalIndexImmediate {
136 : uint32_t index;
137 : ValueType type = kWasmStmt;
138 : uint32_t length;
139 :
140 18146540 : inline LocalIndexImmediate(Decoder* decoder, const byte* pc) {
141 19960749 : index = decoder->read_u32v<validate>(pc + 1, &length, "local index");
142 : }
143 : };
144 :
145 : template <Decoder::ValidateFlag validate>
146 : struct ExceptionIndexImmediate {
147 : uint32_t index;
148 : const WasmException* exception = nullptr;
149 : uint32_t length;
150 :
151 3534 : inline ExceptionIndexImmediate(Decoder* decoder, const byte* pc) {
152 5817 : index = decoder->read_u32v<validate>(pc + 1, &length, "exception index");
153 : }
154 : };
155 :
156 : template <Decoder::ValidateFlag validate>
157 : struct ImmI32Immediate {
158 : int32_t value;
159 : uint32_t length;
160 : inline ImmI32Immediate(Decoder* decoder, const byte* pc) {
161 24121948 : value = decoder->read_i32v<validate>(pc + 1, &length, "immi32");
162 : }
163 : };
164 :
165 : template <Decoder::ValidateFlag validate>
166 : struct ImmI64Immediate {
167 : int64_t value;
168 : uint32_t length;
169 : inline ImmI64Immediate(Decoder* decoder, const byte* pc) {
170 232523 : value = decoder->read_i64v<validate>(pc + 1, &length, "immi64");
171 : }
172 : };
173 :
174 : template <Decoder::ValidateFlag validate>
175 : struct ImmF32Immediate {
176 : float value;
177 : uint32_t length = 4;
178 717908 : inline ImmF32Immediate(Decoder* decoder, const byte* pc) {
179 : // Avoid bit_cast because it might not preserve the signalling bit of a NaN.
180 1435817 : uint32_t tmp = decoder->read_u32<validate>(pc + 1, "immf32");
181 717909 : memcpy(&value, &tmp, sizeof(value));
182 717909 : }
183 : };
184 :
185 : template <Decoder::ValidateFlag validate>
186 : struct ImmF64Immediate {
187 : double value;
188 : uint32_t length = 8;
189 288907 : inline ImmF64Immediate(Decoder* decoder, const byte* pc) {
190 : // Avoid bit_cast because it might not preserve the signalling bit of a NaN.
191 577819 : uint64_t tmp = decoder->read_u64<validate>(pc + 1, "immf64");
192 288912 : memcpy(&value, &tmp, sizeof(value));
193 288912 : }
194 : };
195 :
196 : template <Decoder::ValidateFlag validate>
197 : struct GlobalIndexImmediate {
198 : uint32_t index;
199 : ValueType type = kWasmStmt;
200 : const WasmGlobal* global = nullptr;
201 : uint32_t length;
202 :
203 886163 : inline GlobalIndexImmediate(Decoder* decoder, const byte* pc) {
204 945071 : index = decoder->read_u32v<validate>(pc + 1, &length, "global index");
205 : }
206 : };
207 :
208 : template <Decoder::ValidateFlag validate>
209 : struct BlockTypeImmediate {
210 : uint32_t length = 1;
211 : ValueType type = kWasmStmt;
212 : uint32_t sig_index = 0;
213 : FunctionSig* sig = nullptr;
214 :
215 1881138 : inline BlockTypeImmediate(const WasmFeatures& enabled, Decoder* decoder,
216 1881138 : const byte* pc) {
217 499561 : uint8_t val = decoder->read_u8<validate>(pc + 1, "block type");
218 1881154 : if (!decode_local_type(val, &type)) {
219 : // Handle multi-value blocks.
220 301 : if (!VALIDATE(enabled.mv)) {
221 59 : decoder->error(pc + 1, "invalid block type");
222 58 : return;
223 : }
224 242 : if (!VALIDATE(decoder->ok())) return;
225 : int32_t index =
226 40613 : decoder->read_i32v<validate>(pc + 1, &length, "block arity");
227 221 : if (!VALIDATE(length > 0 && index >= 0)) {
228 0 : decoder->error(pc + 1, "invalid block type index");
229 0 : return;
230 : }
231 40613 : sig_index = static_cast<uint32_t>(index);
232 : }
233 : }
234 :
235 : // Decode a byte representing a local type. Return {false} if the encoded
236 : // byte was invalid or the start of a type index.
237 1881163 : inline bool decode_local_type(uint8_t val, ValueType* result) {
238 1881163 : switch (static_cast<ValueTypeCode>(val)) {
239 : case kLocalVoid:
240 1652612 : *result = kWasmStmt;
241 1652612 : return true;
242 : case kLocalI32:
243 180429 : *result = kWasmI32;
244 180429 : return true;
245 : case kLocalI64:
246 1812 : *result = kWasmI64;
247 1812 : return true;
248 : case kLocalF32:
249 2637 : *result = kWasmF32;
250 2637 : return true;
251 : case kLocalF64:
252 2738 : *result = kWasmF64;
253 2738 : return true;
254 : case kLocalS128:
255 43 : *result = kWasmS128;
256 43 : return true;
257 : case kLocalAnyFunc:
258 0 : *result = kWasmAnyFunc;
259 0 : return true;
260 : case kLocalAnyRef:
261 199 : *result = kWasmAnyRef;
262 199 : return true;
263 : default:
264 40693 : *result = kWasmVar;
265 40693 : return false;
266 : }
267 : }
268 :
269 : uint32_t in_arity() const {
270 414469 : if (type != kWasmVar) return 0;
271 257 : return static_cast<uint32_t>(sig->parameter_count());
272 : }
273 : uint32_t out_arity() const {
274 459376 : if (type == kWasmStmt) return 0;
275 28812 : if (type != kWasmVar) return 1;
276 281 : return static_cast<uint32_t>(sig->return_count());
277 : }
278 : ValueType in_type(uint32_t index) {
279 : DCHECK_EQ(kWasmVar, type);
280 : return sig->GetParam(index);
281 : }
282 : ValueType out_type(uint32_t index) {
283 27401 : if (type == kWasmVar) return sig->GetReturn(index);
284 : DCHECK_NE(kWasmStmt, type);
285 : DCHECK_EQ(0, index);
286 : return type;
287 : }
288 : };
289 :
290 : template <Decoder::ValidateFlag validate>
291 : struct BranchDepthImmediate {
292 : uint32_t depth;
293 : uint32_t length;
294 : inline BranchDepthImmediate(Decoder* decoder, const byte* pc) {
295 779244 : depth = decoder->read_u32v<validate>(pc + 1, &length, "branch depth");
296 : }
297 : };
298 :
299 : template <Decoder::ValidateFlag validate>
300 : struct BranchOnExceptionImmediate {
301 : BranchDepthImmediate<validate> depth;
302 : ExceptionIndexImmediate<validate> index;
303 : uint32_t length = 0;
304 1350 : inline BranchOnExceptionImmediate(Decoder* decoder, const byte* pc)
305 : : depth(BranchDepthImmediate<validate>(decoder, pc)),
306 2699 : index(ExceptionIndexImmediate<validate>(decoder, pc + depth.length)) {
307 1350 : length = depth.length + index.length;
308 1350 : }
309 : };
310 :
311 : template <Decoder::ValidateFlag validate>
312 : struct CallIndirectImmediate {
313 : uint32_t table_index;
314 : uint32_t sig_index;
315 : FunctionSig* sig = nullptr;
316 : uint32_t length = 0;
317 50584 : inline CallIndirectImmediate(const WasmFeatures enabled, Decoder* decoder,
318 50584 : const byte* pc) {
319 50584 : uint32_t len = 0;
320 59595 : sig_index = decoder->read_u32v<validate>(pc + 1, &len, "signature index");
321 59595 : table_index = decoder->read_u8<validate>(pc + 1 + len, "table index");
322 9011 : if (!VALIDATE(table_index == 0 || enabled.anyref)) {
323 62 : decoder->errorf(pc + 1 + len, "expected table index 0, found %u",
324 : table_index);
325 : }
326 50583 : length = 1 + len;
327 50583 : }
328 : };
329 :
330 : template <Decoder::ValidateFlag validate>
331 : struct CallFunctionImmediate {
332 : uint32_t index;
333 : FunctionSig* sig = nullptr;
334 : uint32_t length;
335 995864 : inline CallFunctionImmediate(Decoder* decoder, const byte* pc) {
336 1316180 : index = decoder->read_u32v<validate>(pc + 1, &length, "function index");
337 : }
338 : };
339 :
340 : template <Decoder::ValidateFlag validate>
341 : struct MemoryIndexImmediate {
342 : uint32_t index = 0;
343 : uint32_t length = 1;
344 258 : inline MemoryIndexImmediate() = default;
345 3973 : inline MemoryIndexImmediate(Decoder* decoder, const byte* pc) {
346 7986 : index = decoder->read_u8<validate>(pc + 1, "memory index");
347 3925 : if (!VALIDATE(index == 0)) {
348 318 : decoder->errorf(pc + 1, "expected memory index 0, found %u", index);
349 : }
350 3925 : }
351 : };
352 :
353 : template <Decoder::ValidateFlag validate>
354 : struct TableIndexImmediate {
355 : uint32_t index = 0;
356 : unsigned length = 1;
357 244 : inline TableIndexImmediate() = default;
358 342 : inline TableIndexImmediate(Decoder* decoder, const byte* pc) {
359 1580 : index = decoder->read_u8<validate>(pc + 1, "table index");
360 342 : }
361 : };
362 :
363 : template <Decoder::ValidateFlag validate>
364 : struct BranchTableImmediate {
365 : uint32_t table_count;
366 : const byte* start;
367 : const byte* table;
368 242750 : inline BranchTableImmediate(Decoder* decoder, const byte* pc) {
369 : DCHECK_EQ(kExprBrTable, decoder->read_u8<validate>(pc, "opcode"));
370 242750 : start = pc + 1;
371 242750 : uint32_t len = 0;
372 242749 : table_count = decoder->read_u32v<validate>(pc + 1, &len, "table count");
373 242749 : table = pc + 1 + len;
374 242749 : }
375 : };
376 :
377 : // A helper to iterate over a branch table.
378 : template <Decoder::ValidateFlag validate>
379 : class BranchTableIterator {
380 : public:
381 : uint32_t cur_index() { return index_; }
382 794254 : bool has_next() { return VALIDATE(decoder_->ok()) && index_ <= table_count_; }
383 1708094 : uint32_t next() {
384 : DCHECK(has_next());
385 1708094 : index_++;
386 : uint32_t length;
387 : uint32_t result =
388 1708094 : decoder_->read_u32v<validate>(pc_, &length, "branch table entry");
389 1708092 : pc_ += length;
390 1708092 : return result;
391 : }
392 : // length, including the length of the {BranchTableImmediate}, but not the
393 : // opcode.
394 11643 : uint32_t length() {
395 32845 : while (has_next()) next();
396 15848 : return static_cast<uint32_t>(pc_ - start_);
397 : }
398 : const byte* pc() { return pc_; }
399 :
400 : BranchTableIterator(Decoder* decoder,
401 : const BranchTableImmediate<validate>& imm)
402 : : decoder_(decoder),
403 : start_(imm.start),
404 : pc_(imm.table),
405 252691 : table_count_(imm.table_count) {}
406 :
407 : private:
408 : Decoder* decoder_;
409 : const byte* start_;
410 : const byte* pc_;
411 : uint32_t index_ = 0; // the current index.
412 : uint32_t table_count_; // the count of entries, not including default.
413 : };
414 :
415 : template <Decoder::ValidateFlag validate>
416 : struct MemoryAccessImmediate {
417 : uint32_t alignment;
418 : uint32_t offset;
419 : uint32_t length = 0;
420 6770440 : inline MemoryAccessImmediate(Decoder* decoder, const byte* pc,
421 6770440 : uint32_t max_alignment) {
422 : uint32_t alignment_length;
423 7266491 : alignment =
424 : decoder->read_u32v<validate>(pc + 1, &alignment_length, "alignment");
425 496051 : if (!VALIDATE(alignment <= max_alignment)) {
426 1132 : decoder->errorf(pc + 1,
427 : "invalid alignment; expected maximum alignment is %u, "
428 : "actual alignment is %u",
429 : max_alignment, alignment);
430 : }
431 : uint32_t offset_length;
432 13541213 : offset = decoder->read_u32v<validate>(pc + 1 + alignment_length,
433 : &offset_length, "offset");
434 6770702 : length = alignment_length + offset_length;
435 6770702 : }
436 : };
437 :
438 : // Immediate for SIMD lane operations.
439 : template <Decoder::ValidateFlag validate>
440 : struct SimdLaneImmediate {
441 : uint8_t lane;
442 : uint32_t length = 1;
443 :
444 784 : inline SimdLaneImmediate(Decoder* decoder, const byte* pc) {
445 1568 : lane = decoder->read_u8<validate>(pc + 2, "lane");
446 784 : }
447 : };
448 :
449 : // Immediate for SIMD shift operations.
450 : template <Decoder::ValidateFlag validate>
451 : struct SimdShiftImmediate {
452 : uint8_t shift;
453 : uint32_t length = 1;
454 :
455 1272 : inline SimdShiftImmediate(Decoder* decoder, const byte* pc) {
456 2544 : shift = decoder->read_u8<validate>(pc + 2, "shift");
457 1272 : }
458 : };
459 :
460 : // Immediate for SIMD S8x16 shuffle operations.
461 : template <Decoder::ValidateFlag validate>
462 : struct Simd8x16ShuffleImmediate {
463 : uint8_t shuffle[kSimd128Size] = {0};
464 :
465 23889 : inline Simd8x16ShuffleImmediate(Decoder* decoder, const byte* pc) {
466 788337 : for (uint32_t i = 0; i < kSimd128Size; ++i) {
467 593952 : shuffle[i] = decoder->read_u8<validate>(pc + 2 + i, "shuffle");
468 : }
469 13233 : }
470 : };
471 :
472 : template <Decoder::ValidateFlag validate>
473 : struct MemoryInitImmediate {
474 : uint32_t data_segment_index = 0;
475 : MemoryIndexImmediate<validate> memory;
476 : unsigned length = 0;
477 :
478 388 : inline MemoryInitImmediate(Decoder* decoder, const byte* pc) {
479 194 : uint32_t len = 0;
480 388 : data_segment_index =
481 : decoder->read_i32v<validate>(pc + 2, &len, "data segment index");
482 282 : memory = MemoryIndexImmediate<validate>(decoder, pc + 1 + len);
483 193 : length = len + memory.length;
484 193 : }
485 : };
486 :
487 : template <Decoder::ValidateFlag validate>
488 : struct DataDropImmediate {
489 : uint32_t index;
490 : unsigned length;
491 :
492 : inline DataDropImmediate(Decoder* decoder, const byte* pc) {
493 176 : index = decoder->read_i32v<validate>(pc + 2, &length, "data segment index");
494 : }
495 : };
496 :
497 : template <Decoder::ValidateFlag validate>
498 : struct MemoryCopyImmediate {
499 : MemoryIndexImmediate<validate> memory_src;
500 : MemoryIndexImmediate<validate> memory_dst;
501 : unsigned length = 0;
502 :
503 128 : inline MemoryCopyImmediate(Decoder* decoder, const byte* pc) {
504 64 : memory_src = MemoryIndexImmediate<validate>(decoder, pc + 1);
505 64 : memory_dst =
506 64 : MemoryIndexImmediate<validate>(decoder, pc + 1 + memory_src.length);
507 64 : length = memory_src.length + memory_dst.length;
508 64 : }
509 : };
510 :
511 : template <Decoder::ValidateFlag validate>
512 : struct TableInitImmediate {
513 : uint32_t elem_segment_index = 0;
514 : TableIndexImmediate<validate> table;
515 : unsigned length = 0;
516 :
517 336 : inline TableInitImmediate(Decoder* decoder, const byte* pc) {
518 168 : uint32_t len = 0;
519 336 : elem_segment_index =
520 : decoder->read_i32v<validate>(pc + 2, &len, "elem segment index");
521 296 : table = TableIndexImmediate<validate>(decoder, pc + 1 + len);
522 168 : length = len + table.length;
523 168 : }
524 : };
525 :
526 : template <Decoder::ValidateFlag validate>
527 : struct ElemDropImmediate {
528 : uint32_t index;
529 : unsigned length;
530 :
531 : inline ElemDropImmediate(Decoder* decoder, const byte* pc) {
532 122 : index = decoder->read_i32v<validate>(pc + 2, &length, "elem segment index");
533 : }
534 : };
535 :
536 : template <Decoder::ValidateFlag validate>
537 : struct TableCopyImmediate {
538 : TableIndexImmediate<validate> table_src;
539 : TableIndexImmediate<validate> table_dst;
540 : unsigned length = 0;
541 :
542 152 : inline TableCopyImmediate(Decoder* decoder, const byte* pc) {
543 76 : table_src = TableIndexImmediate<validate>(decoder, pc + 1);
544 76 : table_dst =
545 76 : TableIndexImmediate<validate>(decoder, pc + 1 + table_src.length);
546 76 : length = table_src.length + table_dst.length;
547 76 : }
548 : };
549 :
550 : // An entry on the value stack.
551 : struct ValueBase {
552 : const byte* pc = nullptr;
553 : ValueType type = kWasmStmt;
554 :
555 8175592 : ValueBase(const byte* pc, ValueType type) : pc(pc), type(type) {}
556 : };
557 :
558 : template <typename Value>
559 : struct Merge {
560 : uint32_t arity = 0;
561 : union { // Either multiple values or a single value.
562 : Value* array;
563 : Value first;
564 : } vals = {nullptr}; // Initialize {array} with {nullptr}.
565 :
566 : // Tracks whether this merge was ever reached. Uses precise reachability, like
567 : // Reachability::kReachable.
568 : bool reached;
569 :
570 1672191 : Merge(bool reached = false) : reached(reached) {}
571 :
572 : Value& operator[](uint32_t i) {
573 : DCHECK_GT(arity, i);
574 968018 : return arity == 1 ? vals.first : vals.array[i];
575 : }
576 : };
577 :
578 : enum ControlKind : uint8_t {
579 : kControlIf,
580 : kControlIfElse,
581 : kControlBlock,
582 : kControlLoop,
583 : kControlTry,
584 : kControlTryCatch
585 : };
586 :
587 : enum Reachability : uint8_t {
588 : // reachable code.
589 : kReachable,
590 : // reachable code in unreachable block (implies normal validation).
591 : kSpecOnlyReachable,
592 : // code unreachable in its own block (implies polymorphic validation).
593 : kUnreachable
594 : };
595 :
596 : // An entry on the control stack (i.e. if, block, loop, or try).
597 : template <typename Value>
598 : struct ControlBase {
599 : ControlKind kind = kControlBlock;
600 : uint32_t stack_depth = 0; // stack height at the beginning of the construct.
601 : const uint8_t* pc = nullptr;
602 : Reachability reachability = kReachable;
603 :
604 : // Values merged into the start or end of this control construct.
605 : Merge<Value> start_merge;
606 : Merge<Value> end_merge;
607 :
608 : MOVE_ONLY_NO_DEFAULT_CONSTRUCTOR(ControlBase);
609 :
610 : ControlBase(ControlKind kind, uint32_t stack_depth, const uint8_t* pc,
611 : Reachability reachability)
612 : : kind(kind),
613 : stack_depth(stack_depth),
614 : pc(pc),
615 : reachability(reachability),
616 1672191 : start_merge(reachability == kReachable) {}
617 :
618 : // Check whether the current block is reachable.
619 : bool reachable() const { return reachability == kReachable; }
620 :
621 : // Check whether the rest of the block is unreachable.
622 : // Note that this is different from {!reachable()}, as there is also the
623 : // "indirect unreachable state", for which both {reachable()} and
624 : // {unreachable()} return false.
625 : bool unreachable() const { return reachability == kUnreachable; }
626 :
627 : // Return the reachability of new control structs started in this block.
628 : Reachability innerReachability() const {
629 435783 : return reachability == kReachable ? kReachable : kSpecOnlyReachable;
630 : }
631 :
632 20953 : bool is_if() const { return is_onearmed_if() || is_if_else(); }
633 : bool is_onearmed_if() const { return kind == kControlIf; }
634 : bool is_if_else() const { return kind == kControlIfElse; }
635 : bool is_block() const { return kind == kControlBlock; }
636 : bool is_loop() const { return kind == kControlLoop; }
637 : bool is_incomplete_try() const { return kind == kControlTry; }
638 : bool is_try_catch() const { return kind == kControlTryCatch; }
639 776 : bool is_try() const { return is_incomplete_try() || is_try_catch(); }
640 :
641 : inline Merge<Value>* br_merge() {
642 1234233 : return is_loop() ? &this->start_merge : &this->end_merge;
643 : }
644 : };
645 :
646 : // This is the list of callback functions that an interface for the
647 : // WasmFullDecoder should implement.
648 : // F(Name, args...)
649 : #define INTERFACE_FUNCTIONS(F) \
650 : /* General: */ \
651 : F(StartFunction) \
652 : F(StartFunctionBody, Control* block) \
653 : F(FinishFunction) \
654 : F(OnFirstError) \
655 : F(NextInstruction, WasmOpcode) \
656 : /* Control: */ \
657 : F(Block, Control* block) \
658 : F(Loop, Control* block) \
659 : F(Try, Control* block) \
660 : F(Catch, Control* block, Value* exception) \
661 : F(If, const Value& cond, Control* if_block) \
662 : F(FallThruTo, Control* c) \
663 : F(PopControl, Control* block) \
664 : F(EndControl, Control* block) \
665 : /* Instructions: */ \
666 : F(UnOp, WasmOpcode opcode, const Value& value, Value* result) \
667 : F(BinOp, WasmOpcode opcode, const Value& lhs, const Value& rhs, \
668 : Value* result) \
669 : F(I32Const, Value* result, int32_t value) \
670 : F(I64Const, Value* result, int64_t value) \
671 : F(F32Const, Value* result, float value) \
672 : F(F64Const, Value* result, double value) \
673 : F(RefNull, Value* result) \
674 : F(Drop, const Value& value) \
675 : F(DoReturn, Vector<Value> values) \
676 : F(GetLocal, Value* result, const LocalIndexImmediate<validate>& imm) \
677 : F(SetLocal, const Value& value, const LocalIndexImmediate<validate>& imm) \
678 : F(TeeLocal, const Value& value, Value* result, \
679 : const LocalIndexImmediate<validate>& imm) \
680 : F(GetGlobal, Value* result, const GlobalIndexImmediate<validate>& imm) \
681 : F(SetGlobal, const Value& value, const GlobalIndexImmediate<validate>& imm) \
682 : F(GetTable, const Value& index, Value* result, \
683 : const TableIndexImmediate<validate>& imm) \
684 : F(SetTable, const Value& index, const Value& value, \
685 : const TableIndexImmediate<validate>& imm) \
686 : F(Unreachable) \
687 : F(Select, const Value& cond, const Value& fval, const Value& tval, \
688 : Value* result) \
689 : F(Br, Control* target) \
690 : F(BrIf, const Value& cond, uint32_t depth) \
691 : F(BrTable, const BranchTableImmediate<validate>& imm, const Value& key) \
692 : F(Else, Control* if_block) \
693 : F(LoadMem, LoadType type, const MemoryAccessImmediate<validate>& imm, \
694 : const Value& index, Value* result) \
695 : F(StoreMem, StoreType type, const MemoryAccessImmediate<validate>& imm, \
696 : const Value& index, const Value& value) \
697 : F(CurrentMemoryPages, Value* result) \
698 : F(MemoryGrow, const Value& value, Value* result) \
699 : F(CallDirect, const CallFunctionImmediate<validate>& imm, \
700 : const Value args[], Value returns[]) \
701 : F(CallIndirect, const Value& index, \
702 : const CallIndirectImmediate<validate>& imm, const Value args[], \
703 : Value returns[]) \
704 : F(ReturnCall, const CallFunctionImmediate<validate>& imm, \
705 : const Value args[]) \
706 : F(ReturnCallIndirect, const Value& index, \
707 : const CallIndirectImmediate<validate>& imm, const Value args[]) \
708 : F(SimdOp, WasmOpcode opcode, Vector<Value> args, Value* result) \
709 : F(SimdLaneOp, WasmOpcode opcode, const SimdLaneImmediate<validate>& imm, \
710 : const Vector<Value> inputs, Value* result) \
711 : F(SimdShiftOp, WasmOpcode opcode, const SimdShiftImmediate<validate>& imm, \
712 : const Value& input, Value* result) \
713 : F(Simd8x16ShuffleOp, const Simd8x16ShuffleImmediate<validate>& imm, \
714 : const Value& input0, const Value& input1, Value* result) \
715 : F(Throw, const ExceptionIndexImmediate<validate>& imm, \
716 : const Vector<Value>& args) \
717 : F(Rethrow, const Value& exception) \
718 : F(BrOnException, const Value& exception, \
719 : const ExceptionIndexImmediate<validate>& imm, uint32_t depth, \
720 : Vector<Value> values) \
721 : F(AtomicOp, WasmOpcode opcode, Vector<Value> args, \
722 : const MemoryAccessImmediate<validate>& imm, Value* result) \
723 : F(MemoryInit, const MemoryInitImmediate<validate>& imm, const Value& dst, \
724 : const Value& src, const Value& size) \
725 : F(DataDrop, const DataDropImmediate<validate>& imm) \
726 : F(MemoryCopy, const MemoryCopyImmediate<validate>& imm, const Value& dst, \
727 : const Value& src, const Value& size) \
728 : F(MemoryFill, const MemoryIndexImmediate<validate>& imm, const Value& dst, \
729 : const Value& value, const Value& size) \
730 : F(TableInit, const TableInitImmediate<validate>& imm, Vector<Value> args) \
731 : F(ElemDrop, const ElemDropImmediate<validate>& imm) \
732 : F(TableCopy, const TableCopyImmediate<validate>& imm, Vector<Value> args)
733 :
734 : // Generic Wasm bytecode decoder with utilities for decoding immediates,
735 : // lengths, etc.
736 : template <Decoder::ValidateFlag validate>
737 6487114 : class WasmDecoder : public Decoder {
738 : public:
739 : WasmDecoder(const WasmModule* module, const WasmFeatures& enabled,
740 : WasmFeatures* detected, FunctionSig* sig, const byte* start,
741 : const byte* end, uint32_t buffer_offset = 0)
742 : : Decoder(start, end, buffer_offset),
743 : module_(module),
744 : enabled_(enabled),
745 : detected_(detected),
746 : sig_(sig),
747 3243603 : local_types_(nullptr) {}
748 : const WasmModule* module_;
749 : const WasmFeatures enabled_;
750 : WasmFeatures* detected_;
751 : FunctionSig* sig_;
752 :
753 : ZoneVector<ValueType>* local_types_;
754 :
755 : uint32_t total_locals() const {
756 : return local_types_ == nullptr
757 : ? 0
758 2835691 : : static_cast<uint32_t>(local_types_->size());
759 : }
760 :
761 1626706 : static bool DecodeLocals(const WasmFeatures& enabled, Decoder* decoder,
762 : const FunctionSig* sig,
763 : ZoneVector<ValueType>* type_list) {
764 : DCHECK_NOT_NULL(type_list);
765 : DCHECK_EQ(0, type_list->size());
766 : // Initialize from signature.
767 1626706 : if (sig != nullptr) {
768 1258564 : type_list->assign(sig->parameters().begin(), sig->parameters().end());
769 : }
770 : // Decode local declarations, if any.
771 : uint32_t entries = decoder->consume_u32v("local decls count");
772 1627570 : if (decoder->failed()) return false;
773 :
774 : TRACE("local decls count: %u\n", entries);
775 1727271 : while (entries-- > 0 && decoder->more()) {
776 : uint32_t count = decoder->consume_u32v("local count");
777 50006 : if (decoder->failed()) return false;
778 :
779 : DCHECK_LE(type_list->size(), kV8MaxWasmFunctionLocals);
780 99826 : if (count > kV8MaxWasmFunctionLocals - type_list->size()) {
781 55 : decoder->error(decoder->pc() - 1, "local count too large");
782 55 : return false;
783 : }
784 : byte code = decoder->consume_u8("local type");
785 49858 : if (decoder->failed()) return false;
786 :
787 : ValueType type;
788 49858 : switch (code) {
789 : case kLocalI32:
790 23665 : type = kWasmI32;
791 23665 : break;
792 : case kLocalI64:
793 19097 : type = kWasmI64;
794 19097 : break;
795 : case kLocalF32:
796 1257 : type = kWasmF32;
797 1257 : break;
798 : case kLocalF64:
799 2094 : type = kWasmF64;
800 2094 : break;
801 : case kLocalAnyRef:
802 70 : if (enabled.anyref) {
803 70 : type = kWasmAnyRef;
804 70 : break;
805 : }
806 0 : decoder->error(decoder->pc() - 1, "invalid local type");
807 0 : return false;
808 : case kLocalAnyFunc:
809 120 : if (enabled.anyref) {
810 120 : type = kWasmAnyFunc;
811 120 : break;
812 : }
813 0 : decoder->error(decoder->pc() - 1,
814 : "local type 'anyfunc' is not enabled with "
815 : "--experimental-wasm-anyref");
816 0 : return false;
817 : case kLocalExceptRef:
818 203 : if (enabled.eh) {
819 203 : type = kWasmExceptRef;
820 203 : break;
821 : }
822 0 : decoder->error(decoder->pc() - 1, "invalid local type");
823 0 : return false;
824 : case kLocalS128:
825 3324 : if (enabled.simd) {
826 3316 : type = kWasmS128;
827 3316 : break;
828 : }
829 : V8_FALLTHROUGH;
830 : default:
831 38 : decoder->error(decoder->pc() - 1, "invalid local type");
832 38 : return false;
833 : }
834 49822 : type_list->insert(type_list->end(), count, type);
835 : }
836 : DCHECK(decoder->ok());
837 : return true;
838 : }
839 :
840 9653 : static BitVector* AnalyzeLoopAssignment(Decoder* decoder, const byte* pc,
841 : uint32_t locals_count, Zone* zone) {
842 9653 : if (pc >= decoder->end()) return nullptr;
843 9653 : if (*pc != kExprLoop) return nullptr;
844 :
845 : // The number of locals_count is augmented by 2 so that 'locals_count - 2'
846 : // can be used to track mem_size, and 'locals_count - 1' to track mem_start.
847 9653 : BitVector* assigned = new (zone) BitVector(locals_count, zone);
848 : int depth = 0;
849 : // Iteratively process all AST nodes nested inside the loop.
850 3185142 : while (pc < decoder->end() && VALIDATE(decoder->ok())) {
851 1597409 : WasmOpcode opcode = static_cast<WasmOpcode>(*pc);
852 : uint32_t length = 1;
853 1597409 : switch (opcode) {
854 : case kExprLoop:
855 : case kExprIf:
856 : case kExprBlock:
857 : case kExprTry:
858 84734 : length = OpcodeLength(decoder, pc);
859 84736 : depth++;
860 84736 : break;
861 : case kExprSetLocal: // fallthru
862 : case kExprTeeLocal: {
863 : LocalIndexImmediate<validate> imm(decoder, pc);
864 112864 : if (assigned->length() > 0 &&
865 : imm.index < static_cast<uint32_t>(assigned->length())) {
866 : // Unverified code might have an out-of-bounds index.
867 112863 : assigned->Add(imm.index);
868 : }
869 112864 : length = 1 + imm.length;
870 : break;
871 : }
872 : case kExprMemoryGrow:
873 : case kExprCallFunction:
874 : case kExprCallIndirect:
875 : case kExprReturnCall:
876 : case kExprReturnCallIndirect:
877 : // Add instance cache nodes to the assigned set.
878 : // TODO(titzer): make this more clear.
879 18325 : assigned->Add(locals_count - 1);
880 18325 : length = OpcodeLength(decoder, pc);
881 18325 : break;
882 : case kExprEnd:
883 84716 : depth--;
884 84716 : break;
885 : default:
886 1296771 : length = OpcodeLength(decoder, pc);
887 1296773 : break;
888 : }
889 1597414 : if (depth <= 0) break;
890 1587748 : pc += length;
891 : }
892 9651 : return VALIDATE(decoder->ok()) ? assigned : nullptr;
893 : }
894 :
895 1398786 : inline bool Validate(const byte* pc, LocalIndexImmediate<validate>& imm) {
896 2797572 : if (!VALIDATE(imm.index < total_locals())) {
897 625 : errorf(pc + 1, "invalid local index: %u", imm.index);
898 624 : return false;
899 : }
900 2796237 : imm.type = local_types_ ? local_types_->at(imm.index) : kWasmStmt;
901 1398161 : return true;
902 : }
903 :
904 : inline bool Complete(const byte* pc, ExceptionIndexImmediate<validate>& imm) {
905 2941 : if (!VALIDATE(module_ != nullptr &&
906 : imm.index < module_->exceptions.size())) {
907 : return false;
908 : }
909 3572 : imm.exception = &module_->exceptions[imm.index];
910 : return true;
911 : }
912 :
913 1470 : inline bool Validate(const byte* pc, ExceptionIndexImmediate<validate>& imm) {
914 1470 : if (!Complete(pc, imm)) {
915 9 : errorf(pc + 1, "Invalid exception index: %u", imm.index);
916 9 : return false;
917 : }
918 : return true;
919 : }
920 :
921 55417 : inline bool Validate(const byte* pc, GlobalIndexImmediate<validate>& imm) {
922 110835 : if (!VALIDATE(module_ != nullptr && imm.index < module_->globals.size())) {
923 28 : errorf(pc + 1, "invalid global index: %u", imm.index);
924 28 : return false;
925 : }
926 110778 : imm.global = &module_->globals[imm.index];
927 55389 : imm.type = imm.global->type;
928 55389 : return true;
929 : }
930 :
931 : inline bool CanReturnCall(FunctionSig* target_sig) {
932 323 : if (target_sig == nullptr) return false;
933 322 : size_t num_returns = sig_->return_count();
934 322 : if (num_returns != target_sig->return_count()) return false;
935 961 : for (size_t i = 0; i < num_returns; ++i) {
936 323 : if (sig_->GetReturn(i) != target_sig->GetReturn(i)) return false;
937 : }
938 : return true;
939 : }
940 :
941 : inline bool Complete(const byte* pc, CallFunctionImmediate<validate>& imm) {
942 606311 : if (!VALIDATE(module_ != nullptr &&
943 : imm.index < module_->functions.size())) {
944 : return false;
945 : }
946 611738 : imm.sig = module_->functions[imm.index].sig;
947 : return true;
948 : }
949 :
950 303144 : inline bool Validate(const byte* pc, CallFunctionImmediate<validate>& imm) {
951 303144 : if (Complete(pc, imm)) {
952 : return true;
953 : }
954 84 : errorf(pc + 1, "invalid function index: %u", imm.index);
955 84 : return false;
956 : }
957 :
958 : inline bool Complete(const byte* pc, CallIndirectImmediate<validate>& imm) {
959 15578 : if (!VALIDATE(module_ != nullptr &&
960 : imm.sig_index < module_->signatures.size())) {
961 : return false;
962 : }
963 15978 : imm.sig = module_->signatures[imm.sig_index];
964 : return true;
965 : }
966 :
967 7905 : inline bool Validate(const byte* pc, CallIndirectImmediate<validate>& imm) {
968 15808 : if (!VALIDATE(module_ != nullptr &&
969 : imm.table_index < module_->tables.size())) {
970 96 : error("function table has to exist to execute call_indirect");
971 96 : return false;
972 : }
973 15617 : if (!VALIDATE(module_ != nullptr &&
974 : module_->tables[imm.table_index].type == kWasmAnyFunc)) {
975 20 : error("table of call_indirect must be of type anyfunc");
976 20 : return false;
977 : }
978 7789 : if (!Complete(pc, imm)) {
979 63 : errorf(pc + 1, "invalid signature index: #%u", imm.sig_index);
980 63 : return false;
981 : }
982 : return true;
983 : }
984 :
985 : inline bool Validate(const byte* pc, BranchDepthImmediate<validate>& imm,
986 : size_t control_depth) {
987 309135 : if (!VALIDATE(imm.depth < control_depth)) {
988 659 : errorf(pc + 1, "invalid branch depth: %u", imm.depth);
989 : return false;
990 : }
991 : return true;
992 : }
993 :
994 12111 : bool Validate(const byte* pc, BranchTableImmediate<validate>& imm,
995 : size_t block_depth) {
996 12111 : if (!VALIDATE(imm.table_count < kV8MaxWasmFunctionSize)) {
997 21 : errorf(pc + 1, "invalid table count (> max function size): %u",
998 : imm.table_count);
999 : return false;
1000 : }
1001 12090 : return checkAvailable(imm.table_count);
1002 : }
1003 :
1004 784 : inline bool Validate(const byte* pc, WasmOpcode opcode,
1005 : SimdLaneImmediate<validate>& imm) {
1006 : uint8_t num_lanes = 0;
1007 : switch (opcode) {
1008 : case kExprF32x4ExtractLane:
1009 : case kExprF32x4ReplaceLane:
1010 : case kExprI32x4ExtractLane:
1011 : case kExprI32x4ReplaceLane:
1012 : num_lanes = 4;
1013 : break;
1014 : case kExprI16x8ExtractLane:
1015 : case kExprI16x8ReplaceLane:
1016 : num_lanes = 8;
1017 : break;
1018 : case kExprI8x16ExtractLane:
1019 : case kExprI8x16ReplaceLane:
1020 : num_lanes = 16;
1021 : break;
1022 : default:
1023 0 : UNREACHABLE();
1024 : break;
1025 : }
1026 784 : if (!VALIDATE(imm.lane >= 0 && imm.lane < num_lanes)) {
1027 0 : error(pc_ + 2, "invalid lane index");
1028 : return false;
1029 : } else {
1030 : return true;
1031 : }
1032 : }
1033 :
1034 1272 : inline bool Validate(const byte* pc, WasmOpcode opcode,
1035 : SimdShiftImmediate<validate>& imm) {
1036 : uint8_t max_shift = 0;
1037 : switch (opcode) {
1038 : case kExprI32x4Shl:
1039 : case kExprI32x4ShrS:
1040 : case kExprI32x4ShrU:
1041 : max_shift = 32;
1042 : break;
1043 : case kExprI16x8Shl:
1044 : case kExprI16x8ShrS:
1045 : case kExprI16x8ShrU:
1046 : max_shift = 16;
1047 : break;
1048 : case kExprI8x16Shl:
1049 : case kExprI8x16ShrS:
1050 : case kExprI8x16ShrU:
1051 : max_shift = 8;
1052 : break;
1053 : default:
1054 0 : UNREACHABLE();
1055 : break;
1056 : }
1057 1272 : if (!VALIDATE(imm.shift >= 0 && imm.shift < max_shift)) {
1058 0 : error(pc_ + 2, "invalid shift amount");
1059 : return false;
1060 : } else {
1061 : return true;
1062 : }
1063 : }
1064 :
1065 13233 : inline bool Validate(const byte* pc,
1066 : Simd8x16ShuffleImmediate<validate>& imm) {
1067 13233 : uint8_t max_lane = 0;
1068 436689 : for (uint32_t i = 0; i < kSimd128Size; ++i) {
1069 423456 : max_lane = std::max(max_lane, imm.shuffle[i]);
1070 : }
1071 : // Shuffle indices must be in [0..31] for a 16 lane shuffle.
1072 13233 : if (!VALIDATE(max_lane <= 2 * kSimd128Size)) {
1073 0 : error(pc_ + 2, "invalid shuffle mask");
1074 : return false;
1075 : }
1076 : return true;
1077 : }
1078 :
1079 414830 : inline bool Complete(BlockTypeImmediate<validate>& imm) {
1080 414830 : if (imm.type != kWasmVar) return true;
1081 531 : if (!VALIDATE(module_ && imm.sig_index < module_->signatures.size())) {
1082 : return false;
1083 : }
1084 514 : imm.sig = module_->signatures[imm.sig_index];
1085 : return true;
1086 : }
1087 :
1088 414827 : inline bool Validate(BlockTypeImmediate<validate>& imm) {
1089 414827 : if (!Complete(imm)) {
1090 34 : errorf(pc_, "block type index %u out of bounds (%zu signatures)",
1091 : imm.sig_index, module_ ? module_->signatures.size() : 0);
1092 17 : return false;
1093 : }
1094 : return true;
1095 : }
1096 :
1097 : inline bool Validate(const byte* pc, MemoryIndexImmediate<validate>& imm) {
1098 295 : if (!VALIDATE(module_ != nullptr && module_->has_memory)) {
1099 2 : errorf(pc + 1, "memory instruction with no memory");
1100 : return false;
1101 : }
1102 : return true;
1103 : }
1104 :
1105 105 : inline bool Validate(MemoryInitImmediate<validate>& imm) {
1106 105 : if (!VALIDATE(module_ != nullptr &&
1107 : imm.data_segment_index <
1108 : module_->num_declared_data_segments)) {
1109 1 : errorf(pc_ + 2, "invalid data segment index: %u", imm.data_segment_index);
1110 1 : return false;
1111 : }
1112 208 : if (!Validate(pc_ + imm.length - imm.memory.length - 1, imm.memory))
1113 : return false;
1114 104 : return true;
1115 : }
1116 :
1117 68 : inline bool Validate(DataDropImmediate<validate>& imm) {
1118 68 : if (!VALIDATE(module_ != nullptr &&
1119 : imm.index < module_->num_declared_data_segments)) {
1120 1 : errorf(pc_ + 2, "invalid data segment index: %u", imm.index);
1121 : return false;
1122 : }
1123 : return true;
1124 : }
1125 :
1126 64 : inline bool Validate(MemoryCopyImmediate<validate>& imm) {
1127 128 : if (!Validate(pc_ + 1, imm.memory_src)) return false;
1128 126 : if (!Validate(pc_ + 2, imm.memory_dst)) return false;
1129 : return true;
1130 : }
1131 :
1132 338 : inline bool Validate(const byte* pc, TableIndexImmediate<validate>& imm) {
1133 675 : if (!VALIDATE(module_ != nullptr && imm.index < module_->tables.size())) {
1134 5 : errorf(pc, "invalid table index: %u", imm.index);
1135 5 : return false;
1136 : }
1137 : return true;
1138 : }
1139 :
1140 40 : inline bool Validate(TableInitImmediate<validate>& imm) {
1141 79 : if (!VALIDATE(module_ != nullptr &&
1142 : imm.elem_segment_index < module_->elem_segments.size())) {
1143 3 : errorf(pc_ + 2, "invalid element segment index: %u",
1144 : imm.elem_segment_index);
1145 3 : return false;
1146 : }
1147 37 : if (!Validate(pc_ + imm.length - imm.table.length - 1, imm.table))
1148 : return false;
1149 37 : return true;
1150 : }
1151 :
1152 41 : inline bool Validate(ElemDropImmediate<validate>& imm) {
1153 81 : if (!VALIDATE(module_ != nullptr &&
1154 : imm.index < module_->elem_segments.size())) {
1155 2 : errorf(pc_ + 2, "invalid element segment index: %u", imm.index);
1156 2 : return false;
1157 : }
1158 : return true;
1159 : }
1160 :
1161 76 : inline bool Validate(TableCopyImmediate<validate>& imm) {
1162 76 : if (!Validate(pc_ + 1, imm.table_src)) return false;
1163 75 : if (!Validate(pc_ + 2, imm.table_dst)) return false;
1164 75 : return true;
1165 : }
1166 :
1167 3408608 : static uint32_t OpcodeLength(Decoder* decoder, const byte* pc) {
1168 3408608 : WasmOpcode opcode = static_cast<WasmOpcode>(*pc);
1169 3408608 : switch (opcode) {
1170 : #define DECLARE_OPCODE_CASE(name, opcode, sig) case kExpr##name:
1171 : FOREACH_LOAD_MEM_OPCODE(DECLARE_OPCODE_CASE)
1172 : FOREACH_STORE_MEM_OPCODE(DECLARE_OPCODE_CASE)
1173 : #undef DECLARE_OPCODE_CASE
1174 : {
1175 143375 : MemoryAccessImmediate<validate> imm(decoder, pc, UINT32_MAX);
1176 143375 : return 1 + imm.length;
1177 : }
1178 : case kExprBr:
1179 : case kExprBrIf: {
1180 : BranchDepthImmediate<validate> imm(decoder, pc);
1181 55965 : return 1 + imm.length;
1182 : }
1183 : case kExprGetGlobal:
1184 : case kExprSetGlobal: {
1185 : GlobalIndexImmediate<validate> imm(decoder, pc);
1186 22670 : return 1 + imm.length;
1187 : }
1188 : case kExprGetTable:
1189 : case kExprSetTable: {
1190 0 : TableIndexImmediate<validate> imm(decoder, pc);
1191 0 : return 1 + imm.length;
1192 : }
1193 : case kExprCallFunction:
1194 : case kExprReturnCall: {
1195 : CallFunctionImmediate<validate> imm(decoder, pc);
1196 20033 : return 1 + imm.length;
1197 : }
1198 : case kExprCallIndirect:
1199 : case kExprReturnCallIndirect: {
1200 1392 : CallIndirectImmediate<validate> imm(kAllWasmFeatures, decoder, pc);
1201 1392 : return 1 + imm.length;
1202 : }
1203 :
1204 : case kExprTry:
1205 : case kExprIf: // fall through
1206 : case kExprLoop:
1207 : case kExprBlock: {
1208 107406 : BlockTypeImmediate<validate> imm(kAllWasmFeatures, decoder, pc);
1209 107408 : return 1 + imm.length;
1210 : }
1211 :
1212 : case kExprThrow: {
1213 : ExceptionIndexImmediate<validate> imm(decoder, pc);
1214 325 : return 1 + imm.length;
1215 : }
1216 :
1217 : case kExprBrOnExn: {
1218 204 : BranchOnExceptionImmediate<validate> imm(decoder, pc);
1219 203 : return 1 + imm.length;
1220 : }
1221 :
1222 : case kExprSetLocal:
1223 : case kExprTeeLocal:
1224 : case kExprGetLocal: {
1225 : LocalIndexImmediate<validate> imm(decoder, pc);
1226 478312 : return 1 + imm.length;
1227 : }
1228 : case kExprBrTable: {
1229 4294 : BranchTableImmediate<validate> imm(decoder, pc);
1230 : BranchTableIterator<validate> iterator(decoder, imm);
1231 4294 : return 1 + iterator.length();
1232 : }
1233 : case kExprI32Const: {
1234 : ImmI32Immediate<validate> imm(decoder, pc);
1235 1161210 : return 1 + imm.length;
1236 : }
1237 : case kExprI64Const: {
1238 : ImmI64Immediate<validate> imm(decoder, pc);
1239 2819 : return 1 + imm.length;
1240 : }
1241 : case kExprRefNull: {
1242 : return 1;
1243 : }
1244 : case kExprMemoryGrow:
1245 : case kExprMemorySize: {
1246 73 : MemoryIndexImmediate<validate> imm(decoder, pc);
1247 73 : return 1 + imm.length;
1248 : }
1249 : case kExprF32Const:
1250 566 : return 5;
1251 : case kExprF64Const:
1252 3757 : return 9;
1253 : case kNumericPrefix: {
1254 : byte numeric_index =
1255 0 : decoder->read_u8<validate>(pc + 1, "numeric_index");
1256 : WasmOpcode opcode =
1257 128 : static_cast<WasmOpcode>(kNumericPrefix << 8 | numeric_index);
1258 128 : switch (opcode) {
1259 : case kExprI32SConvertSatF32:
1260 : case kExprI32UConvertSatF32:
1261 : case kExprI32SConvertSatF64:
1262 : case kExprI32UConvertSatF64:
1263 : case kExprI64SConvertSatF32:
1264 : case kExprI64UConvertSatF32:
1265 : case kExprI64SConvertSatF64:
1266 : case kExprI64UConvertSatF64:
1267 : return 2;
1268 : case kExprMemoryInit: {
1269 16 : MemoryInitImmediate<validate> imm(decoder, pc);
1270 16 : return 2 + imm.length;
1271 : }
1272 : case kExprDataDrop: {
1273 : DataDropImmediate<validate> imm(decoder, pc);
1274 8 : return 2 + imm.length;
1275 : }
1276 : case kExprMemoryCopy: {
1277 0 : MemoryCopyImmediate<validate> imm(decoder, pc);
1278 0 : return 2 + imm.length;
1279 : }
1280 : case kExprMemoryFill: {
1281 0 : MemoryIndexImmediate<validate> imm(decoder, pc + 1);
1282 0 : return 2 + imm.length;
1283 : }
1284 : case kExprTableInit: {
1285 12 : TableInitImmediate<validate> imm(decoder, pc);
1286 12 : return 2 + imm.length;
1287 : }
1288 : case kExprElemDrop: {
1289 : ElemDropImmediate<validate> imm(decoder, pc);
1290 8 : return 2 + imm.length;
1291 : }
1292 : case kExprTableCopy: {
1293 0 : TableCopyImmediate<validate> imm(decoder, pc);
1294 0 : return 2 + imm.length;
1295 : }
1296 : default:
1297 0 : decoder->error(pc, "invalid numeric opcode");
1298 0 : return 2;
1299 : }
1300 : }
1301 : case kSimdPrefix: {
1302 32 : byte simd_index = decoder->read_u8<validate>(pc + 1, "simd_index");
1303 : WasmOpcode opcode =
1304 14114 : static_cast<WasmOpcode>(kSimdPrefix << 8 | simd_index);
1305 14114 : switch (opcode) {
1306 : #define DECLARE_OPCODE_CASE(name, opcode, sig) case kExpr##name:
1307 : FOREACH_SIMD_0_OPERAND_OPCODE(DECLARE_OPCODE_CASE)
1308 : #undef DECLARE_OPCODE_CASE
1309 : return 2;
1310 : #define DECLARE_OPCODE_CASE(name, opcode, sig) case kExpr##name:
1311 : FOREACH_SIMD_1_OPERAND_OPCODE(DECLARE_OPCODE_CASE)
1312 : #undef DECLARE_OPCODE_CASE
1313 1093 : return 3;
1314 : #define DECLARE_OPCODE_CASE(name, opcode, sig) case kExpr##name:
1315 : FOREACH_SIMD_MEM_OPCODE(DECLARE_OPCODE_CASE)
1316 : #undef DECLARE_OPCODE_CASE
1317 : {
1318 0 : MemoryAccessImmediate<validate> imm(decoder, pc + 1, UINT32_MAX);
1319 0 : return 2 + imm.length;
1320 : }
1321 : // Shuffles require a byte per lane, or 16 immediate bytes.
1322 : case kExprS8x16Shuffle:
1323 10657 : return 2 + kSimd128Size;
1324 : default:
1325 1 : decoder->error(pc, "invalid SIMD opcode");
1326 1 : return 2;
1327 : }
1328 : }
1329 : case kAtomicPrefix: {
1330 109 : byte atomic_index = decoder->read_u8<validate>(pc + 1, "atomic_index");
1331 : WasmOpcode opcode =
1332 553 : static_cast<WasmOpcode>(kAtomicPrefix << 8 | atomic_index);
1333 553 : switch (opcode) {
1334 : #define DECLARE_OPCODE_CASE(name, opcode, sig) case kExpr##name:
1335 : FOREACH_ATOMIC_OPCODE(DECLARE_OPCODE_CASE)
1336 : #undef DECLARE_OPCODE_CASE
1337 : {
1338 553 : MemoryAccessImmediate<validate> imm(decoder, pc + 1, UINT32_MAX);
1339 554 : return 2 + imm.length;
1340 : }
1341 : default:
1342 0 : decoder->error(pc, "invalid Atomics opcode");
1343 0 : return 2;
1344 : }
1345 : }
1346 : default:
1347 : return 1;
1348 : }
1349 : }
1350 :
1351 1984584 : std::pair<uint32_t, uint32_t> StackEffect(const byte* pc) {
1352 1984584 : WasmOpcode opcode = static_cast<WasmOpcode>(*pc);
1353 : // Handle "simple" opcodes with a fixed signature first.
1354 1984584 : FunctionSig* sig = WasmOpcodes::Signature(opcode);
1355 1984584 : if (!sig) sig = WasmOpcodes::AsmjsSignature(opcode);
1356 2336282 : if (sig) return {sig->parameter_count(), sig->return_count()};
1357 :
1358 : #define DECLARE_OPCODE_CASE(name, opcode, sig) case kExpr##name:
1359 : // clang-format off
1360 1632886 : switch (opcode) {
1361 : case kExprSelect:
1362 20 : return {3, 1};
1363 : case kExprSetTable:
1364 : FOREACH_STORE_MEM_OPCODE(DECLARE_OPCODE_CASE)
1365 74496 : return {2, 0};
1366 : FOREACH_LOAD_MEM_OPCODE(DECLARE_OPCODE_CASE)
1367 : case kExprGetTable:
1368 : case kExprTeeLocal:
1369 : case kExprMemoryGrow:
1370 68553 : return {1, 1};
1371 : case kExprSetLocal:
1372 : case kExprSetGlobal:
1373 : case kExprDrop:
1374 : case kExprBrIf:
1375 : case kExprBrTable:
1376 : case kExprIf:
1377 : case kExprRethrow:
1378 76454 : return {1, 0};
1379 : case kExprGetLocal:
1380 : case kExprGetGlobal:
1381 : case kExprI32Const:
1382 : case kExprI64Const:
1383 : case kExprF32Const:
1384 : case kExprF64Const:
1385 : case kExprRefNull:
1386 : case kExprMemorySize:
1387 985332 : return {0, 1};
1388 : case kExprCallFunction: {
1389 : CallFunctionImmediate<validate> imm(this, pc);
1390 : CHECK(Complete(pc, imm));
1391 2767 : return {imm.sig->parameter_count(), imm.sig->return_count()};
1392 : }
1393 : case kExprCallIndirect: {
1394 264 : CallIndirectImmediate<validate> imm(this->enabled_, this, pc);
1395 : CHECK(Complete(pc, imm));
1396 : // Indirect calls pop an additional argument for the table index.
1397 : return {imm.sig->parameter_count() + 1,
1398 528 : imm.sig->return_count()};
1399 : }
1400 : case kExprThrow: {
1401 : ExceptionIndexImmediate<validate> imm(this, pc);
1402 : CHECK(Complete(pc, imm));
1403 : DCHECK_EQ(0, imm.exception->sig->return_count());
1404 648 : return {imm.exception->sig->parameter_count(), 0};
1405 : }
1406 : case kExprBr:
1407 : case kExprBlock:
1408 : case kExprLoop:
1409 : case kExprEnd:
1410 : case kExprElse:
1411 : case kExprTry:
1412 : case kExprCatch:
1413 : case kExprBrOnExn:
1414 : case kExprNop:
1415 : case kExprReturn:
1416 : case kExprReturnCall:
1417 : case kExprReturnCallIndirect:
1418 : case kExprUnreachable:
1419 410160 : return {0, 0};
1420 : case kNumericPrefix:
1421 : case kAtomicPrefix:
1422 : case kSimdPrefix: {
1423 14516 : opcode = static_cast<WasmOpcode>(opcode << 8 | *(pc + 1));
1424 14516 : switch (opcode) {
1425 : FOREACH_SIMD_1_OPERAND_1_PARAM_OPCODE(DECLARE_OPCODE_CASE)
1426 852 : return {1, 1};
1427 : FOREACH_SIMD_1_OPERAND_2_PARAM_OPCODE(DECLARE_OPCODE_CASE)
1428 : FOREACH_SIMD_MASK_OPERAND_OPCODE(DECLARE_OPCODE_CASE)
1429 10880 : return {2, 1};
1430 : default: {
1431 2784 : sig = WasmOpcodes::Signature(opcode);
1432 2784 : if (sig) {
1433 2784 : return {sig->parameter_count(), sig->return_count()};
1434 : }
1435 : }
1436 : }
1437 : V8_FALLTHROUGH;
1438 : }
1439 : default:
1440 0 : V8_Fatal(__FILE__, __LINE__, "unimplemented opcode: %x (%s)", opcode,
1441 : WasmOpcodes::OpcodeName(opcode));
1442 : return {0, 0};
1443 : }
1444 : #undef DECLARE_OPCODE_CASE
1445 : // clang-format on
1446 : }
1447 : };
1448 :
1449 : #define CALL_INTERFACE(name, ...) interface_.name(this, ##__VA_ARGS__)
1450 : #define CALL_INTERFACE_IF_REACHABLE(name, ...) \
1451 : do { \
1452 : DCHECK(!control_.empty()); \
1453 : if (VALIDATE(this->ok()) && control_.back().reachable()) { \
1454 : interface_.name(this, ##__VA_ARGS__); \
1455 : } \
1456 : } while (false)
1457 : #define CALL_INTERFACE_IF_PARENT_REACHABLE(name, ...) \
1458 : do { \
1459 : DCHECK(!control_.empty()); \
1460 : if (VALIDATE(this->ok()) && \
1461 : (control_.size() == 1 || control_at(1)->reachable())) { \
1462 : interface_.name(this, ##__VA_ARGS__); \
1463 : } \
1464 : } while (false)
1465 :
1466 : template <Decoder::ValidateFlag validate, typename Interface>
1467 2977058 : class WasmFullDecoder : public WasmDecoder<validate> {
1468 : using Value = typename Interface::Value;
1469 : using Control = typename Interface::Control;
1470 : using MergeValues = Merge<Value>;
1471 :
1472 : // All Value types should be trivially copyable for performance. We push, pop,
1473 : // and store them in local variables.
1474 : ASSERT_TRIVIALLY_COPYABLE(Value);
1475 :
1476 : public:
1477 : template <typename... InterfaceArgs>
1478 461149 : WasmFullDecoder(Zone* zone, const WasmModule* module,
1479 : const WasmFeatures& enabled, WasmFeatures* detected,
1480 : const FunctionBody& body, InterfaceArgs&&... interface_args)
1481 : : WasmDecoder<validate>(module, enabled, detected, body.sig, body.start,
1482 : body.end, body.offset),
1483 : zone_(zone),
1484 : interface_(std::forward<InterfaceArgs>(interface_args)...),
1485 : local_type_vec_(zone),
1486 : stack_(zone),
1487 : control_(zone),
1488 3439958 : args_(zone) {
1489 1258649 : this->local_types_ = &local_type_vec_;
1490 460787 : }
1491 :
1492 : Interface& interface() { return interface_; }
1493 :
1494 1258407 : bool Decode() {
1495 : DCHECK(stack_.empty());
1496 : DCHECK(control_.empty());
1497 :
1498 : base::ElapsedTimer decode_timer;
1499 : if (FLAG_trace_wasm_decode_time) {
1500 : decode_timer.Start();
1501 : }
1502 :
1503 1258407 : if (this->end_ < this->pc_) {
1504 0 : this->error("function body end < start");
1505 0 : return false;
1506 : }
1507 :
1508 : DCHECK_EQ(0, this->local_types_->size());
1509 1258407 : WasmDecoder<validate>::DecodeLocals(this->enabled_, this, this->sig_,
1510 : this->local_types_);
1511 1089607 : CALL_INTERFACE(StartFunction);
1512 1258091 : DecodeFunctionBody();
1513 1088319 : if (!this->failed()) CALL_INTERFACE(FinishFunction);
1514 :
1515 : // Generate a better error message whether the unterminated control
1516 : // structure is the function body block or an innner structure.
1517 1257617 : if (control_.size() > 1) {
1518 11615 : this->error(control_.back().pc, "unterminated control structure");
1519 1246002 : } else if (control_.size() == 1) {
1520 49935 : this->error("function body must end with \"end\" opcode");
1521 : }
1522 :
1523 1257772 : if (this->failed()) return this->TraceFailed();
1524 :
1525 : if (FLAG_trace_wasm_decode_time) {
1526 : double ms = decode_timer.Elapsed().InMillisecondsF();
1527 : PrintF("wasm-decode %s (%0.3f ms)\n\n",
1528 : VALIDATE(this->ok()) ? "ok" : "failed", ms);
1529 : } else {
1530 : TRACE("wasm-decode %s\n\n", VALIDATE(this->ok()) ? "ok" : "failed");
1531 : }
1532 :
1533 1195598 : return true;
1534 : }
1535 :
1536 : bool TraceFailed() {
1537 : TRACE("wasm-error module+%-6d func+%d: %s\n\n", this->error_.offset(),
1538 : this->GetBufferRelativeOffset(this->error_.offset()),
1539 : this->error_.message().c_str());
1540 : return false;
1541 : }
1542 :
1543 : const char* SafeOpcodeNameAt(const byte* pc) {
1544 77931 : if (pc >= this->end_) return "<end>";
1545 64345 : return WasmOpcodes::OpcodeName(static_cast<WasmOpcode>(*pc));
1546 : }
1547 :
1548 : inline Zone* zone() const { return zone_; }
1549 :
1550 : inline uint32_t num_locals() const {
1551 1347995 : return static_cast<uint32_t>(local_type_vec_.size());
1552 : }
1553 :
1554 : inline ValueType GetLocalType(uint32_t index) {
1555 2582972 : return local_type_vec_[index];
1556 : }
1557 :
1558 : inline WasmCodePosition position() {
1559 2301965 : int offset = static_cast<int>(this->pc_ - this->start_);
1560 : DCHECK_EQ(this->pc_ - this->start_, offset); // overflows cannot happen
1561 : return offset;
1562 : }
1563 :
1564 : inline uint32_t control_depth() const {
1565 411467 : return static_cast<uint32_t>(control_.size());
1566 : }
1567 :
1568 : inline Control* control_at(uint32_t depth) {
1569 : DCHECK_GT(control_.size(), depth);
1570 763368 : return &control_.back() - depth;
1571 : }
1572 :
1573 : inline uint32_t stack_size() const {
1574 : DCHECK_GE(kMaxUInt32, stack_.size());
1575 1689231 : return static_cast<uint32_t>(stack_.size());
1576 : }
1577 :
1578 : inline Value* stack_value(uint32_t depth) {
1579 : DCHECK_LT(0, depth);
1580 : DCHECK_GE(stack_.size(), depth);
1581 : return &*(stack_.end() - depth);
1582 : }
1583 :
1584 : private:
1585 : Zone* zone_;
1586 :
1587 : Interface interface_;
1588 :
1589 : ZoneVector<ValueType> local_type_vec_; // types of local variables.
1590 : ZoneVector<Value> stack_; // stack of values.
1591 : ZoneVector<Control> control_; // stack of blocks, loops, and ifs.
1592 : ZoneVector<Value> args_; // parameters of current block or call
1593 :
1594 : static Value UnreachableValue(const uint8_t* pc) {
1595 : return Value{pc, kWasmVar};
1596 : }
1597 :
1598 : bool CheckHasMemory() {
1599 451426 : if (!VALIDATE(this->module_->has_memory)) {
1600 196 : this->error(this->pc_ - 1, "memory instruction with no memory");
1601 : return false;
1602 : }
1603 : return true;
1604 : }
1605 :
1606 : bool CheckHasSharedMemory() {
1607 47477 : if (!VALIDATE(this->module_->has_shared_memory)) {
1608 22 : this->error(this->pc_ - 1, "Atomic opcodes used without shared memory");
1609 : return false;
1610 : }
1611 : return true;
1612 : }
1613 :
1614 : class TraceLine {
1615 : public:
1616 : static constexpr int kMaxLen = 512;
1617 : ~TraceLine() {
1618 : if (!FLAG_trace_wasm_decoder) return;
1619 : PrintF("%.*s\n", len_, buffer_);
1620 : }
1621 :
1622 : // Appends a formatted string.
1623 : PRINTF_FORMAT(2, 3)
1624 : void Append(const char* format, ...) {
1625 : if (!FLAG_trace_wasm_decoder) return;
1626 : va_list va_args;
1627 : va_start(va_args, format);
1628 : size_t remaining_len = kMaxLen - len_;
1629 : Vector<char> remaining_msg_space(buffer_ + len_, remaining_len);
1630 : int len = VSNPrintF(remaining_msg_space, format, va_args);
1631 : va_end(va_args);
1632 : len_ += len < 0 ? remaining_len : len;
1633 : }
1634 :
1635 : private:
1636 : char buffer_[kMaxLen];
1637 : int len_ = 0;
1638 : };
1639 :
1640 : // Decodes the body of a function.
1641 1257829 : void DecodeFunctionBody() {
1642 : TRACE("wasm-decode %p...%p (module+%u, %d bytes)\n",
1643 : reinterpret_cast<const void*>(this->start()),
1644 : reinterpret_cast<const void*>(this->end()), this->pc_offset(),
1645 : static_cast<int>(this->end() - this->start()));
1646 :
1647 : // Set up initial function block.
1648 : {
1649 1257829 : auto* c = PushControl(kControlBlock);
1650 : InitMerge(&c->start_merge, 0, [](uint32_t) -> Value { UNREACHABLE(); });
1651 2515514 : InitMerge(&c->end_merge,
1652 1257757 : static_cast<uint32_t>(this->sig_->return_count()),
1653 : [&](uint32_t i) {
1654 948115 : return Value{this->pc_, this->sig_->GetReturn(i)};
1655 458266 : });
1656 460439 : CALL_INTERFACE(StartFunctionBody, c);
1657 : }
1658 :
1659 26090223 : while (this->pc_ < this->end_) { // decoding loop.
1660 : uint32_t len = 1;
1661 12415850 : WasmOpcode opcode = static_cast<WasmOpcode>(*this->pc_);
1662 :
1663 : CALL_INTERFACE_IF_REACHABLE(NextInstruction, opcode);
1664 :
1665 : #if DEBUG
1666 : TraceLine trace_msg;
1667 : #define TRACE_PART(...) trace_msg.Append(__VA_ARGS__)
1668 : if (!WasmOpcodes::IsPrefixOpcode(opcode)) {
1669 : TRACE_PART(TRACE_INST_FORMAT, startrel(this->pc_),
1670 : WasmOpcodes::OpcodeName(opcode));
1671 : }
1672 : #else
1673 : #define TRACE_PART(...)
1674 : #endif
1675 :
1676 12415850 : switch (opcode) {
1677 : #define BUILD_SIMPLE_OPCODE(op, _, sig) \
1678 : case kExpr##op: \
1679 : BuildSimpleOperator_##sig(opcode); \
1680 : break;
1681 : FOREACH_SIMPLE_OPCODE(BUILD_SIMPLE_OPCODE)
1682 : #undef BUILD_SIMPLE_OPCODE
1683 : case kExprNop:
1684 : break;
1685 : case kExprBlock: {
1686 353480 : BlockTypeImmediate<validate> imm(this->enabled_, this, this->pc_);
1687 353467 : if (!this->Validate(imm)) break;
1688 353466 : PopArgs(imm.sig);
1689 353452 : auto* block = PushControl(kControlBlock);
1690 353476 : SetBlockType(block, imm);
1691 167332 : CALL_INTERFACE_IF_REACHABLE(Block, block);
1692 353442 : PushMergeValues(block, &block->start_merge);
1693 353452 : len = 1 + imm.length;
1694 353452 : break;
1695 : }
1696 : case kExprRethrow: {
1697 657 : CHECK_PROTOTYPE_OPCODE(eh);
1698 : auto exception = Pop(0, kWasmExceptRef);
1699 404 : CALL_INTERFACE_IF_REACHABLE(Rethrow, exception);
1700 658 : EndControl();
1701 657 : break;
1702 : }
1703 : case kExprThrow: {
1704 932 : CHECK_PROTOTYPE_OPCODE(eh);
1705 932 : ExceptionIndexImmediate<validate> imm(this, this->pc_);
1706 933 : len = 1 + imm.length;
1707 933 : if (!this->Validate(this->pc_, imm)) break;
1708 932 : PopArgs(imm.exception->ToFunctionSig());
1709 1159 : CALL_INTERFACE_IF_REACHABLE(Throw, imm, VectorOf(args_));
1710 933 : EndControl();
1711 930 : break;
1712 : }
1713 : case kExprTry: {
1714 889 : CHECK_PROTOTYPE_OPCODE(eh);
1715 889 : BlockTypeImmediate<validate> imm(this->enabled_, this, this->pc_);
1716 890 : if (!this->Validate(imm)) break;
1717 891 : PopArgs(imm.sig);
1718 891 : auto* try_block = PushControl(kControlTry);
1719 889 : SetBlockType(try_block, imm);
1720 887 : len = 1 + imm.length;
1721 610 : CALL_INTERFACE_IF_REACHABLE(Try, try_block);
1722 888 : PushMergeValues(try_block, &try_block->start_merge);
1723 890 : break;
1724 : }
1725 : case kExprCatch: {
1726 776 : CHECK_PROTOTYPE_OPCODE(eh);
1727 776 : if (!VALIDATE(!control_.empty())) {
1728 0 : this->error("catch does not match any try");
1729 0 : break;
1730 : }
1731 : Control* c = &control_.back();
1732 776 : if (!VALIDATE(c->is_try())) {
1733 1 : this->error("catch does not match any try");
1734 1 : break;
1735 : }
1736 775 : if (!VALIDATE(c->is_incomplete_try())) {
1737 1 : this->error("catch already present for try");
1738 1 : break;
1739 : }
1740 774 : c->kind = kControlTryCatch;
1741 499 : FallThruTo(c);
1742 1546 : stack_.erase(stack_.begin() + c->stack_depth, stack_.end());
1743 773 : c->reachability = control_at(1)->innerReachability();
1744 : auto* exception = Push(kWasmExceptRef);
1745 1548 : CALL_INTERFACE_IF_PARENT_REACHABLE(Catch, c, exception);
1746 : break;
1747 : }
1748 : case kExprBrOnExn: {
1749 538 : CHECK_PROTOTYPE_OPCODE(eh);
1750 538 : BranchOnExceptionImmediate<validate> imm(this, this->pc_);
1751 1078 : if (!this->Validate(this->pc_, imm.depth, control_.size())) break;
1752 538 : if (!this->Validate(this->pc_ + imm.depth.length, imm.index)) break;
1753 529 : Control* c = control_at(imm.depth.depth);
1754 : auto exception = Pop(0, kWasmExceptRef);
1755 530 : const WasmExceptionSig* sig = imm.index.exception->sig;
1756 : size_t value_count = sig->parameter_count();
1757 : // TODO(mstarzinger): This operand stack mutation is an ugly hack to
1758 : // make both type checking here as well as environment merging in the
1759 : // graph builder interface work out of the box. We should introduce
1760 : // special handling for both and do minimal/no stack mutation here.
1761 1252 : for (size_t i = 0; i < value_count; ++i) Push(sig->GetParam(i));
1762 330 : Vector<Value> values(stack_.data() + c->stack_depth, value_count);
1763 530 : if (!TypeCheckBranch(c)) break;
1764 529 : if (control_.back().reachable()) {
1765 329 : CALL_INTERFACE(BrOnException, exception, imm.index, imm.depth.depth,
1766 : values);
1767 530 : c->br_merge()->reached = true;
1768 : }
1769 530 : len = 1 + imm.length;
1770 1254 : for (size_t i = 0; i < value_count; ++i) Pop();
1771 : auto* pexception = Push(kWasmExceptRef);
1772 530 : *pexception = exception;
1773 530 : break;
1774 : }
1775 : case kExprLoop: {
1776 15804 : BlockTypeImmediate<validate> imm(this->enabled_, this, this->pc_);
1777 15805 : if (!this->Validate(imm)) break;
1778 15803 : PopArgs(imm.sig);
1779 15800 : auto* block = PushControl(kControlLoop);
1780 15800 : SetBlockType(&control_.back(), imm);
1781 15799 : len = 1 + imm.length;
1782 10627 : CALL_INTERFACE_IF_REACHABLE(Loop, block);
1783 15795 : PushMergeValues(block, &block->start_merge);
1784 15797 : break;
1785 : }
1786 : case kExprIf: {
1787 44687 : BlockTypeImmediate<validate> imm(this->enabled_, this, this->pc_);
1788 44684 : if (!this->Validate(imm)) break;
1789 : auto cond = Pop(0, kWasmI32);
1790 44671 : PopArgs(imm.sig);
1791 44671 : if (!VALIDATE(this->ok())) break;
1792 44148 : auto* if_block = PushControl(kControlIf);
1793 44151 : SetBlockType(if_block, imm);
1794 40627 : CALL_INTERFACE_IF_REACHABLE(If, cond, if_block);
1795 44150 : len = 1 + imm.length;
1796 44150 : PushMergeValues(if_block, &if_block->start_merge);
1797 44152 : break;
1798 : }
1799 : case kExprElse: {
1800 20953 : if (!VALIDATE(!control_.empty())) {
1801 0 : this->error("else does not match any if");
1802 0 : break;
1803 : }
1804 : Control* c = &control_.back();
1805 20953 : if (!VALIDATE(c->is_if())) {
1806 0 : this->error(this->pc_, "else does not match an if");
1807 0 : break;
1808 : }
1809 20953 : if (c->is_if_else()) {
1810 2 : this->error(this->pc_, "else already present for if");
1811 2 : break;
1812 : }
1813 20951 : if (!TypeCheckFallThru(c)) break;
1814 20714 : c->kind = kControlIfElse;
1815 37948 : CALL_INTERFACE_IF_PARENT_REACHABLE(Else, c);
1816 20711 : if (c->reachable()) c->end_merge.reached = true;
1817 20711 : PushMergeValues(c, &c->start_merge);
1818 20712 : c->reachability = control_at(1)->innerReachability();
1819 20712 : break;
1820 : }
1821 : case kExprEnd: {
1822 1602460 : if (!VALIDATE(!control_.empty())) {
1823 0 : this->error("end does not match any if, try, or block");
1824 0 : break;
1825 : }
1826 : Control* c = &control_.back();
1827 1602460 : if (!VALIDATE(!c->is_incomplete_try())) {
1828 1 : this->error(this->pc_, "missing catch or catch-all in try");
1829 1 : break;
1830 : }
1831 1602459 : if (c->is_onearmed_if()) {
1832 22062 : if (!VALIDATE(c->end_merge.arity == c->start_merge.arity)) {
1833 115 : this->error(
1834 : c->pc,
1835 : "start-arity and end-arity of one-armed if must match");
1836 115 : break;
1837 : }
1838 : }
1839 :
1840 1602344 : if (!TypeCheckFallThru(c)) break;
1841 :
1842 1595049 : if (control_.size() == 1) {
1843 : // If at the last (implicit) control, check we are at end.
1844 1196319 : if (!VALIDATE(this->pc_ + 1 == this->end_)) {
1845 192 : this->error(this->pc_ + 1, "trailing code after function end");
1846 191 : break;
1847 : }
1848 : // The result of the block is the return value.
1849 : TRACE_PART("\n" TRACE_INST_FORMAT, startrel(this->pc_),
1850 : "(implicit) return");
1851 1060485 : DoReturn();
1852 : control_.clear();
1853 : break;
1854 : }
1855 :
1856 398730 : PopControl(c);
1857 398752 : break;
1858 : }
1859 : case kExprSelect: {
1860 : auto cond = Pop(2, kWasmI32);
1861 : auto fval = Pop();
1862 1406 : auto tval = Pop(0, fval.type);
1863 3542 : auto* result = Push(tval.type == kWasmVar ? fval.type : tval.type);
1864 1917 : CALL_INTERFACE_IF_REACHABLE(Select, cond, fval, tval, result);
1865 : break;
1866 : }
1867 : case kExprBr: {
1868 31110 : BranchDepthImmediate<validate> imm(this, this->pc_);
1869 62221 : if (!this->Validate(this->pc_, imm, control_.size())) break;
1870 30536 : Control* c = control_at(imm.depth);
1871 30536 : if (!TypeCheckBranch(c)) break;
1872 55566 : if (imm.depth == control_.size() - 1) {
1873 211 : DoReturn();
1874 27352 : } else if (control_.back().reachable()) {
1875 23053 : CALL_INTERFACE(Br, c);
1876 26810 : c->br_merge()->reached = true;
1877 : }
1878 27786 : len = 1 + imm.length;
1879 27786 : EndControl();
1880 27782 : break;
1881 : }
1882 : case kExprBrIf: {
1883 277816 : BranchDepthImmediate<validate> imm(this, this->pc_);
1884 : auto cond = Pop(0, kWasmI32);
1885 277795 : if (this->failed()) break;
1886 554970 : if (!this->Validate(this->pc_, imm, control_.size())) break;
1887 277400 : Control* c = control_at(imm.depth);
1888 277400 : if (!TypeCheckBranch(c)) break;
1889 277113 : if (control_.back().reachable()) {
1890 170698 : CALL_INTERFACE(BrIf, cond, imm.depth);
1891 276554 : c->br_merge()->reached = true;
1892 : }
1893 277130 : len = 1 + imm.length;
1894 277130 : break;
1895 : }
1896 : case kExprBrTable: {
1897 12310 : BranchTableImmediate<validate> imm(this, this->pc_);
1898 : BranchTableIterator<validate> iterator(this, imm);
1899 : auto key = Pop(0, kWasmI32);
1900 12306 : if (this->failed()) break;
1901 12111 : if (!this->Validate(this->pc_, imm, control_.size())) break;
1902 : uint32_t br_arity = 0;
1903 12072 : std::vector<bool> br_targets(control_.size());
1904 520031 : while (iterator.has_next()) {
1905 : const uint32_t i = iterator.cur_index();
1906 : const byte* pos = iterator.pc();
1907 508420 : uint32_t target = iterator.next();
1908 1016840 : if (!VALIDATE(target < control_.size())) {
1909 201 : this->errorf(pos,
1910 : "improper branch in br_table target %u (depth %u)",
1911 : i, target);
1912 201 : break;
1913 : }
1914 : // Avoid redundant branch target checks.
1915 508219 : if (br_targets[target]) continue;
1916 : br_targets[target] = true;
1917 : // Check that label types match up.
1918 : Control* c = control_at(target);
1919 28211 : uint32_t arity = c->br_merge()->arity;
1920 28211 : if (i == 0) {
1921 : br_arity = arity;
1922 16207 : } else if (!VALIDATE(br_arity == arity)) {
1923 76 : this->errorf(pos,
1924 : "inconsistent arity in br_table target %u"
1925 : " (previous was %u, this one %u)",
1926 : i, br_arity, arity);
1927 : }
1928 28211 : if (!TypeCheckBranch(c)) break;
1929 : }
1930 12071 : if (this->failed()) break;
1931 :
1932 11535 : if (control_.back().reachable()) {
1933 9938 : CALL_INTERFACE(BrTable, imm, key);
1934 :
1935 68260 : for (uint32_t depth = control_depth(); depth-- > 0;) {
1936 114302 : if (!br_targets[depth]) continue;
1937 27167 : control_at(depth)->br_merge()->reached = true;
1938 : }
1939 : }
1940 :
1941 11535 : len = 1 + iterator.length();
1942 11536 : EndControl();
1943 11536 : break;
1944 : }
1945 : case kExprReturn: {
1946 342796 : if (!TypeCheckReturn()) break;
1947 233814 : DoReturn();
1948 342084 : EndControl();
1949 341951 : break;
1950 : }
1951 : case kExprUnreachable: {
1952 149774 : CALL_INTERFACE_IF_REACHABLE(Unreachable);
1953 259462 : EndControl();
1954 259477 : break;
1955 : }
1956 : case kExprI32Const: {
1957 3131177 : ImmI32Immediate<validate> imm(this, this->pc_);
1958 : auto* value = Push(kWasmI32);
1959 3018775 : CALL_INTERFACE_IF_REACHABLE(I32Const, value, imm.value);
1960 3133367 : len = 1 + imm.length;
1961 : break;
1962 : }
1963 : case kExprI64Const: {
1964 106211 : ImmI64Immediate<validate> imm(this, this->pc_);
1965 : auto* value = Push(kWasmI64);
1966 71827 : CALL_INTERFACE_IF_REACHABLE(I64Const, value, imm.value);
1967 106273 : len = 1 + imm.length;
1968 : break;
1969 : }
1970 : case kExprF32Const: {
1971 281867 : ImmF32Immediate<validate> imm(this, this->pc_);
1972 : auto* value = Push(kWasmF32);
1973 163234 : CALL_INTERFACE_IF_REACHABLE(F32Const, value, imm.value);
1974 281895 : len = 1 + imm.length;
1975 : break;
1976 : }
1977 : case kExprF64Const: {
1978 288335 : ImmF64Immediate<validate> imm(this, this->pc_);
1979 : auto* value = Push(kWasmF64);
1980 170662 : CALL_INTERFACE_IF_REACHABLE(F64Const, value, imm.value);
1981 288367 : len = 1 + imm.length;
1982 : break;
1983 : }
1984 : case kExprRefNull: {
1985 208 : CHECK_PROTOTYPE_OPCODE(anyref);
1986 : auto* value = Push(kWasmNullRef);
1987 280 : CALL_INTERFACE_IF_REACHABLE(RefNull, value);
1988 : len = 1;
1989 : break;
1990 : }
1991 : case kExprGetLocal: {
1992 861277 : LocalIndexImmediate<validate> imm(this, this->pc_);
1993 861471 : if (!this->Validate(this->pc_, imm)) break;
1994 861034 : auto* value = Push(imm.type);
1995 801340 : CALL_INTERFACE_IF_REACHABLE(GetLocal, value, imm);
1996 861222 : len = 1 + imm.length;
1997 861222 : break;
1998 : }
1999 : case kExprSetLocal: {
2000 436977 : LocalIndexImmediate<validate> imm(this, this->pc_);
2001 436977 : if (!this->Validate(this->pc_, imm)) break;
2002 873588 : auto value = Pop(0, local_type_vec_[imm.index]);
2003 425231 : CALL_INTERFACE_IF_REACHABLE(SetLocal, value, imm);
2004 436803 : len = 1 + imm.length;
2005 436803 : break;
2006 : }
2007 : case kExprTeeLocal: {
2008 100840 : LocalIndexImmediate<validate> imm(this, this->pc_);
2009 100837 : if (!this->Validate(this->pc_, imm)) break;
2010 201672 : auto value = Pop(0, local_type_vec_[imm.index]);
2011 : auto* result = Push(value.type);
2012 99360 : CALL_INTERFACE_IF_REACHABLE(TeeLocal, value, result, imm);
2013 100835 : len = 1 + imm.length;
2014 100835 : break;
2015 : }
2016 : case kExprDrop: {
2017 : auto value = Pop();
2018 1358 : CALL_INTERFACE_IF_REACHABLE(Drop, value);
2019 : break;
2020 : }
2021 : case kExprGetGlobal: {
2022 36800 : GlobalIndexImmediate<validate> imm(this, this->pc_);
2023 36804 : len = 1 + imm.length;
2024 36804 : if (!this->Validate(this->pc_, imm)) break;
2025 36775 : auto* result = Push(imm.type);
2026 35969 : CALL_INTERFACE_IF_REACHABLE(GetGlobal, result, imm);
2027 : break;
2028 : }
2029 : case kExprSetGlobal: {
2030 18617 : GlobalIndexImmediate<validate> imm(this, this->pc_);
2031 18617 : len = 1 + imm.length;
2032 18617 : if (!this->Validate(this->pc_, imm)) break;
2033 18617 : if (!VALIDATE(imm.global->mutability)) {
2034 29 : this->errorf(this->pc_, "immutable global #%u cannot be assigned",
2035 : imm.index);
2036 29 : break;
2037 : }
2038 18588 : auto value = Pop(0, imm.type);
2039 17989 : CALL_INTERFACE_IF_REACHABLE(SetGlobal, value, imm);
2040 : break;
2041 : }
2042 : case kExprGetTable: {
2043 96 : CHECK_PROTOTYPE_OPCODE(anyref);
2044 96 : TableIndexImmediate<validate> imm(this, this->pc_);
2045 96 : len = 1 + imm.length;
2046 96 : if (!this->Validate(this->pc_, imm)) break;
2047 : DCHECK_NOT_NULL(this->module_);
2048 : auto index = Pop(0, kWasmI32);
2049 188 : auto* result = Push(this->module_->tables[imm.index].type);
2050 104 : CALL_INTERFACE_IF_REACHABLE(GetTable, index, result, imm);
2051 : break;
2052 : }
2053 : case kExprSetTable: {
2054 56 : CHECK_PROTOTYPE_OPCODE(anyref);
2055 56 : TableIndexImmediate<validate> imm(this, this->pc_);
2056 56 : len = 1 + imm.length;
2057 56 : if (!this->Validate(this->pc_, imm)) break;
2058 108 : auto value = Pop(0, this->module_->tables[imm.index].type);
2059 : auto index = Pop(0, kWasmI32);
2060 59 : CALL_INTERFACE_IF_REACHABLE(SetTable, index, value, imm);
2061 : break;
2062 : }
2063 :
2064 : case kExprI32LoadMem8S:
2065 4134 : len = 1 + DecodeLoadMem(LoadType::kI32Load8S);
2066 4134 : break;
2067 : case kExprI32LoadMem8U:
2068 1504 : len = 1 + DecodeLoadMem(LoadType::kI32Load8U);
2069 1502 : break;
2070 : case kExprI32LoadMem16S:
2071 422 : len = 1 + DecodeLoadMem(LoadType::kI32Load16S);
2072 422 : break;
2073 : case kExprI32LoadMem16U:
2074 650 : len = 1 + DecodeLoadMem(LoadType::kI32Load16U);
2075 650 : break;
2076 : case kExprI32LoadMem:
2077 85434 : len = 1 + DecodeLoadMem(LoadType::kI32Load);
2078 85193 : break;
2079 : case kExprI64LoadMem8S:
2080 436 : len = 1 + DecodeLoadMem(LoadType::kI64Load8S);
2081 436 : break;
2082 : case kExprI64LoadMem8U:
2083 357 : len = 1 + DecodeLoadMem(LoadType::kI64Load8U);
2084 357 : break;
2085 : case kExprI64LoadMem16S:
2086 400 : len = 1 + DecodeLoadMem(LoadType::kI64Load16S);
2087 400 : break;
2088 : case kExprI64LoadMem16U:
2089 393 : len = 1 + DecodeLoadMem(LoadType::kI64Load16U);
2090 393 : break;
2091 : case kExprI64LoadMem32S:
2092 418 : len = 1 + DecodeLoadMem(LoadType::kI64Load32S);
2093 418 : break;
2094 : case kExprI64LoadMem32U:
2095 414 : len = 1 + DecodeLoadMem(LoadType::kI64Load32U);
2096 414 : break;
2097 : case kExprI64LoadMem:
2098 84489 : len = 1 + DecodeLoadMem(LoadType::kI64Load);
2099 84490 : break;
2100 : case kExprF32LoadMem:
2101 2689 : len = 1 + DecodeLoadMem(LoadType::kF32Load);
2102 2689 : break;
2103 : case kExprF64LoadMem:
2104 3436 : len = 1 + DecodeLoadMem(LoadType::kF64Load);
2105 3437 : break;
2106 : case kExprI32StoreMem8:
2107 1859 : len = 1 + DecodeStoreMem(StoreType::kI32Store8);
2108 1859 : break;
2109 : case kExprI32StoreMem16:
2110 696 : len = 1 + DecodeStoreMem(StoreType::kI32Store16);
2111 695 : break;
2112 : case kExprI32StoreMem:
2113 160402 : len = 1 + DecodeStoreMem(StoreType::kI32Store);
2114 160446 : break;
2115 : case kExprI64StoreMem8:
2116 306 : len = 1 + DecodeStoreMem(StoreType::kI64Store8);
2117 306 : break;
2118 : case kExprI64StoreMem16:
2119 428 : len = 1 + DecodeStoreMem(StoreType::kI64Store16);
2120 428 : break;
2121 : case kExprI64StoreMem32:
2122 392 : len = 1 + DecodeStoreMem(StoreType::kI64Store32);
2123 392 : break;
2124 : case kExprI64StoreMem:
2125 96741 : len = 1 + DecodeStoreMem(StoreType::kI64Store);
2126 96728 : break;
2127 : case kExprF32StoreMem:
2128 703 : len = 1 + DecodeStoreMem(StoreType::kF32Store);
2129 703 : break;
2130 : case kExprF64StoreMem:
2131 1352 : len = 1 + DecodeStoreMem(StoreType::kF64Store);
2132 1352 : break;
2133 : case kExprMemoryGrow: {
2134 2705 : if (!CheckHasMemory()) break;
2135 2655 : MemoryIndexImmediate<validate> imm(this, this->pc_);
2136 2655 : len = 1 + imm.length;
2137 : DCHECK_NOT_NULL(this->module_);
2138 2655 : if (!VALIDATE(this->module_->origin == kWasmOrigin)) {
2139 1 : this->error("grow_memory is not supported for asmjs modules");
2140 1 : break;
2141 : }
2142 : auto value = Pop(0, kWasmI32);
2143 : auto* result = Push(kWasmI32);
2144 3151 : CALL_INTERFACE_IF_REACHABLE(MemoryGrow, value, result);
2145 : break;
2146 : }
2147 : case kExprMemorySize: {
2148 930 : if (!CheckHasMemory()) break;
2149 901 : MemoryIndexImmediate<validate> imm(this, this->pc_);
2150 : auto* result = Push(kWasmI32);
2151 902 : len = 1 + imm.length;
2152 952 : CALL_INTERFACE_IF_REACHABLE(CurrentMemoryPages, result);
2153 : break;
2154 : }
2155 : case kExprCallFunction: {
2156 302999 : CallFunctionImmediate<validate> imm(this, this->pc_);
2157 302948 : len = 1 + imm.length;
2158 302948 : if (!this->Validate(this->pc_, imm)) break;
2159 : // TODO(clemensh): Better memory management.
2160 302891 : PopArgs(imm.sig);
2161 302901 : auto* returns = PushReturns(imm.sig);
2162 188277 : CALL_INTERFACE_IF_REACHABLE(CallDirect, imm, args_.data(), returns);
2163 : break;
2164 : }
2165 : case kExprCallIndirect: {
2166 7791 : CallIndirectImmediate<validate> imm(this->enabled_, this, this->pc_);
2167 7790 : len = 1 + imm.length;
2168 7790 : if (!this->Validate(this->pc_, imm)) break;
2169 : auto index = Pop(0, kWasmI32);
2170 7627 : PopArgs(imm.sig);
2171 7626 : auto* returns = PushReturns(imm.sig);
2172 5648 : CALL_INTERFACE_IF_REACHABLE(CallIndirect, index, imm, args_.data(),
2173 : returns);
2174 : break;
2175 : }
2176 : case kExprReturnCall: {
2177 224 : CHECK_PROTOTYPE_OPCODE(return_call);
2178 :
2179 224 : CallFunctionImmediate<validate> imm(this, this->pc_);
2180 223 : len = 1 + imm.length;
2181 223 : if (!this->Validate(this->pc_, imm)) break;
2182 448 : if (!this->CanReturnCall(imm.sig)) {
2183 4 : OPCODE_ERROR(opcode, "tail call return types mismatch");
2184 4 : break;
2185 : }
2186 :
2187 : PopArgs(imm.sig);
2188 :
2189 212 : CALL_INTERFACE_IF_REACHABLE(ReturnCall, imm, args_.data());
2190 219 : EndControl();
2191 219 : break;
2192 : }
2193 : case kExprReturnCallIndirect: {
2194 115 : CHECK_PROTOTYPE_OPCODE(return_call);
2195 114 : CallIndirectImmediate<validate> imm(this->enabled_, this, this->pc_);
2196 114 : len = 1 + imm.length;
2197 114 : if (!this->Validate(this->pc_, imm)) break;
2198 198 : if (!this->CanReturnCall(imm.sig)) {
2199 0 : OPCODE_ERROR(opcode, "tail call return types mismatch");
2200 0 : break;
2201 : }
2202 : auto index = Pop(0, kWasmI32);
2203 99 : PopArgs(imm.sig);
2204 94 : CALL_INTERFACE_IF_REACHABLE(ReturnCallIndirect, index, imm,
2205 : args_.data());
2206 99 : EndControl();
2207 99 : break;
2208 : }
2209 : case kNumericPrefix: {
2210 : ++len;
2211 : byte numeric_index =
2212 564 : this->template read_u8<validate>(this->pc_ + 1, "numeric index");
2213 564 : opcode = static_cast<WasmOpcode>(opcode << 8 | numeric_index);
2214 564 : if (opcode < kExprMemoryInit) {
2215 98 : CHECK_PROTOTYPE_OPCODE(sat_f2i_conversions);
2216 : } else {
2217 466 : CHECK_PROTOTYPE_OPCODE(bulk_memory);
2218 : }
2219 : TRACE_PART(TRACE_INST_FORMAT, startrel(this->pc_),
2220 : WasmOpcodes::OpcodeName(opcode));
2221 555 : len += DecodeNumericOpcode(opcode);
2222 554 : break;
2223 : }
2224 : case kSimdPrefix: {
2225 19633 : CHECK_PROTOTYPE_OPCODE(simd);
2226 : len++;
2227 : byte simd_index =
2228 19633 : this->template read_u8<validate>(this->pc_ + 1, "simd index");
2229 19633 : opcode = static_cast<WasmOpcode>(opcode << 8 | simd_index);
2230 : TRACE_PART(TRACE_INST_FORMAT, startrel(this->pc_),
2231 : WasmOpcodes::OpcodeName(opcode));
2232 19633 : len += DecodeSimdOpcode(opcode);
2233 19633 : break;
2234 : }
2235 : case kAtomicPrefix: {
2236 47477 : CHECK_PROTOTYPE_OPCODE(threads);
2237 47477 : if (!CheckHasSharedMemory()) break;
2238 : len++;
2239 : byte atomic_index =
2240 47455 : this->template read_u8<validate>(this->pc_ + 1, "atomic index");
2241 47570 : opcode = static_cast<WasmOpcode>(opcode << 8 | atomic_index);
2242 : TRACE_PART(TRACE_INST_FORMAT, startrel(this->pc_),
2243 : WasmOpcodes::OpcodeName(opcode));
2244 47570 : len += DecodeAtomicOpcode(opcode);
2245 47920 : break;
2246 : }
2247 : // Note that prototype opcodes are not handled in the fastpath
2248 : // above this switch, to avoid checking a feature flag.
2249 : #define SIMPLE_PROTOTYPE_CASE(name, opc, sig) \
2250 : case kExpr##name: /* fallthrough */
2251 : FOREACH_SIMPLE_PROTOTYPE_OPCODE(SIMPLE_PROTOTYPE_CASE)
2252 : #undef SIMPLE_PROTOTYPE_CASE
2253 130 : BuildSimplePrototypeOperator(opcode);
2254 130 : break;
2255 : default: {
2256 : // Deal with special asmjs opcodes.
2257 200402 : if (this->module_ != nullptr &&
2258 100201 : this->module_->origin == kAsmJsOrigin) {
2259 100170 : FunctionSig* sig = WasmOpcodes::AsmjsSignature(opcode);
2260 100170 : if (sig) {
2261 100170 : BuildSimpleOperator(opcode, sig);
2262 : }
2263 : } else {
2264 31 : this->error("Invalid opcode");
2265 31 : return;
2266 : }
2267 : }
2268 : }
2269 :
2270 : #if DEBUG
2271 : if (FLAG_trace_wasm_decoder) {
2272 : TRACE_PART(" ");
2273 : for (Control& c : control_) {
2274 : switch (c.kind) {
2275 : case kControlIf:
2276 : TRACE_PART("I");
2277 : break;
2278 : case kControlBlock:
2279 : TRACE_PART("B");
2280 : break;
2281 : case kControlLoop:
2282 : TRACE_PART("L");
2283 : break;
2284 : case kControlTry:
2285 : TRACE_PART("T");
2286 : break;
2287 : default:
2288 : break;
2289 : }
2290 : if (c.start_merge.arity) TRACE_PART("%u-", c.start_merge.arity);
2291 : TRACE_PART("%u", c.end_merge.arity);
2292 : if (!c.reachable()) TRACE_PART("%c", c.unreachable() ? '*' : '#');
2293 : }
2294 : TRACE_PART(" | ");
2295 : for (size_t i = 0; i < stack_.size(); ++i) {
2296 : auto& val = stack_[i];
2297 : WasmOpcode opcode = static_cast<WasmOpcode>(*val.pc);
2298 : if (WasmOpcodes::IsPrefixOpcode(opcode)) {
2299 : opcode = static_cast<WasmOpcode>(opcode << 8 | *(val.pc + 1));
2300 : }
2301 : TRACE_PART(" %c@%d:%s", ValueTypes::ShortNameOf(val.type),
2302 : static_cast<int>(val.pc - this->start_),
2303 : WasmOpcodes::OpcodeName(opcode));
2304 : // If the decoder failed, don't try to decode the immediates, as this
2305 : // can trigger a DCHECK failure.
2306 : if (this->failed()) continue;
2307 : switch (opcode) {
2308 : case kExprI32Const: {
2309 : ImmI32Immediate<Decoder::kNoValidate> imm(this, val.pc);
2310 : TRACE_PART("[%d]", imm.value);
2311 : break;
2312 : }
2313 : case kExprGetLocal:
2314 : case kExprSetLocal:
2315 : case kExprTeeLocal: {
2316 : LocalIndexImmediate<Decoder::kNoValidate> imm(this, val.pc);
2317 : TRACE_PART("[%u]", imm.index);
2318 : break;
2319 : }
2320 : case kExprGetGlobal:
2321 : case kExprSetGlobal: {
2322 : GlobalIndexImmediate<Decoder::kNoValidate> imm(this, val.pc);
2323 : TRACE_PART("[%u]", imm.index);
2324 : break;
2325 : }
2326 : default:
2327 : break;
2328 : }
2329 : }
2330 : }
2331 : #endif
2332 12416467 : this->pc_ += len;
2333 : } // end decode loop
2334 1257906 : if (!VALIDATE(this->pc_ == this->end_) && this->ok()) {
2335 0 : this->error("Beyond end of code");
2336 : }
2337 : }
2338 :
2339 642550 : void EndControl() {
2340 : DCHECK(!control_.empty());
2341 : auto* current = &control_.back();
2342 1285100 : stack_.erase(stack_.begin() + current->stack_depth, stack_.end());
2343 315590 : CALL_INTERFACE_IF_REACHABLE(EndControl, current);
2344 642609 : current->reachability = kUnreachable;
2345 642609 : }
2346 :
2347 : template<typename func>
2348 2086128 : void InitMerge(Merge<Value>* merge, uint32_t arity, func get_val) {
2349 3343885 : merge->arity = arity;
2350 2086128 : if (arity == 1) {
2351 969499 : merge->vals.first = get_val(0);
2352 1116629 : } else if (arity > 1) {
2353 6196 : merge->vals.array = zone_->NewArray<Value>(arity);
2354 15526 : for (uint32_t i = 0; i < arity; i++) {
2355 12428 : merge->vals.array[i] = get_val(i);
2356 : }
2357 : }
2358 2086128 : }
2359 :
2360 414297 : void SetBlockType(Control* c, BlockTypeImmediate<validate>& imm) {
2361 : DCHECK_EQ(imm.in_arity(), this->args_.size());
2362 414297 : const byte* pc = this->pc_;
2363 : Value* args = this->args_.data();
2364 828594 : InitMerge(&c->end_merge, imm.out_arity(), [pc, &imm](uint32_t i) {
2365 : return Value{pc, imm.out_type(i)};
2366 : });
2367 828600 : InitMerge(&c->start_merge, imm.in_arity(),
2368 197 : [args](uint32_t i) { return args[i]; });
2369 414286 : }
2370 :
2371 : // Pops arguments as required by signature into {args_}.
2372 : V8_INLINE void PopArgs(FunctionSig* sig) {
2373 778614 : int count = sig ? static_cast<int>(sig->parameter_count()) : 0;
2374 778614 : args_.resize(count, UnreachableValue(nullptr));
2375 1497018 : for (int i = count - 1; i >= 0; --i) {
2376 1436254 : args_[i] = Pop(i, sig->GetParam(i));
2377 : }
2378 : }
2379 :
2380 : ValueType GetReturnType(FunctionSig* sig) {
2381 : DCHECK_GE(1, sig->return_count());
2382 89768 : return sig->return_count() == 0 ? kWasmStmt : sig->GetReturn();
2383 : }
2384 :
2385 1672033 : Control* PushControl(ControlKind kind) {
2386 : Reachability reachability =
2387 3344066 : control_.empty() ? kReachable : control_.back().innerReachability();
2388 3344066 : control_.emplace_back(kind, stack_size(), this->pc_, reachability);
2389 1672056 : return &control_.back();
2390 : }
2391 :
2392 398728 : void PopControl(Control* c) {
2393 : DCHECK_EQ(c, &control_.back());
2394 555899 : CALL_INTERFACE_IF_PARENT_REACHABLE(PopControl, c);
2395 :
2396 : // A loop just leaves the values on the stack.
2397 398768 : if (!c->is_loop()) PushMergeValues(c, &c->end_merge);
2398 :
2399 : bool parent_reached =
2400 398773 : c->reachable() || c->end_merge.reached || c->is_onearmed_if();
2401 : control_.pop_back();
2402 : // If the parent block was reachable before, but the popped control does not
2403 : // return to here, this block becomes "spec only reachable".
2404 398768 : if (!parent_reached && control_.back().reachable()) {
2405 38264 : control_.back().reachability = kSpecOnlyReachable;
2406 : }
2407 398768 : }
2408 :
2409 184987 : int DecodeLoadMem(LoadType type, int prefix_len = 0) {
2410 185106 : if (!CheckHasMemory()) return 0;
2411 185047 : MemoryAccessImmediate<validate> imm(this, this->pc_ + prefix_len,
2412 185047 : type.size_log_2());
2413 : auto index = Pop(0, kWasmI32);
2414 : auto* result = Push(type.value_type());
2415 172641 : CALL_INTERFACE_IF_REACHABLE(LoadMem, type, imm, index, result);
2416 185146 : return imm.length;
2417 : }
2418 :
2419 262804 : int DecodeStoreMem(StoreType store, int prefix_len = 0) {
2420 262990 : if (!CheckHasMemory()) return 0;
2421 262932 : MemoryAccessImmediate<validate> imm(this, this->pc_ + prefix_len,
2422 262932 : store.size_log_2());
2423 : auto value = Pop(1, store.value_type());
2424 : auto index = Pop(0, kWasmI32);
2425 251707 : CALL_INTERFACE_IF_REACHABLE(StoreMem, store, imm, index, value);
2426 263200 : return imm.length;
2427 : }
2428 :
2429 360 : uint32_t SimdExtractLane(WasmOpcode opcode, ValueType type) {
2430 360 : SimdLaneImmediate<validate> imm(this, this->pc_);
2431 360 : if (this->Validate(this->pc_, opcode, imm)) {
2432 0 : Value inputs[] = {Pop(0, kWasmS128)};
2433 : auto* result = Push(type);
2434 360 : CALL_INTERFACE_IF_REACHABLE(SimdLaneOp, opcode, imm, ArrayVector(inputs),
2435 : result);
2436 : }
2437 360 : return imm.length;
2438 : }
2439 :
2440 424 : uint32_t SimdReplaceLane(WasmOpcode opcode, ValueType type) {
2441 424 : SimdLaneImmediate<validate> imm(this, this->pc_);
2442 424 : if (this->Validate(this->pc_, opcode, imm)) {
2443 424 : Value inputs[2] = {UnreachableValue(this->pc_),
2444 0 : UnreachableValue(this->pc_)};
2445 424 : inputs[1] = Pop(1, type);
2446 424 : inputs[0] = Pop(0, kWasmS128);
2447 : auto* result = Push(kWasmS128);
2448 424 : CALL_INTERFACE_IF_REACHABLE(SimdLaneOp, opcode, imm, ArrayVector(inputs),
2449 : result);
2450 : }
2451 424 : return imm.length;
2452 : }
2453 :
2454 1272 : uint32_t SimdShiftOp(WasmOpcode opcode) {
2455 1272 : SimdShiftImmediate<validate> imm(this, this->pc_);
2456 1272 : if (this->Validate(this->pc_, opcode, imm)) {
2457 : auto input = Pop(0, kWasmS128);
2458 : auto* result = Push(kWasmS128);
2459 1272 : CALL_INTERFACE_IF_REACHABLE(SimdShiftOp, opcode, imm, input, result);
2460 : }
2461 1272 : return imm.length;
2462 : }
2463 :
2464 13233 : uint32_t Simd8x16ShuffleOp() {
2465 13233 : Simd8x16ShuffleImmediate<validate> imm(this, this->pc_);
2466 13233 : if (this->Validate(this->pc_, imm)) {
2467 : auto input1 = Pop(1, kWasmS128);
2468 : auto input0 = Pop(0, kWasmS128);
2469 : auto* result = Push(kWasmS128);
2470 13232 : CALL_INTERFACE_IF_REACHABLE(Simd8x16ShuffleOp, imm, input0, input1,
2471 : result);
2472 : }
2473 13233 : return 16;
2474 : }
2475 :
2476 19633 : uint32_t DecodeSimdOpcode(WasmOpcode opcode) {
2477 : uint32_t len = 0;
2478 19633 : switch (opcode) {
2479 : case kExprF32x4ExtractLane: {
2480 64 : len = SimdExtractLane(opcode, kWasmF32);
2481 64 : break;
2482 : }
2483 : case kExprI32x4ExtractLane:
2484 : case kExprI16x8ExtractLane:
2485 : case kExprI8x16ExtractLane: {
2486 296 : len = SimdExtractLane(opcode, kWasmI32);
2487 296 : break;
2488 : }
2489 : case kExprF32x4ReplaceLane: {
2490 64 : len = SimdReplaceLane(opcode, kWasmF32);
2491 64 : break;
2492 : }
2493 : case kExprI32x4ReplaceLane:
2494 : case kExprI16x8ReplaceLane:
2495 : case kExprI8x16ReplaceLane: {
2496 360 : len = SimdReplaceLane(opcode, kWasmI32);
2497 360 : break;
2498 : }
2499 : case kExprI32x4Shl:
2500 : case kExprI32x4ShrS:
2501 : case kExprI32x4ShrU:
2502 : case kExprI16x8Shl:
2503 : case kExprI16x8ShrS:
2504 : case kExprI16x8ShrU:
2505 : case kExprI8x16Shl:
2506 : case kExprI8x16ShrS:
2507 : case kExprI8x16ShrU: {
2508 1272 : len = SimdShiftOp(opcode);
2509 1272 : break;
2510 : }
2511 : case kExprS8x16Shuffle: {
2512 13233 : len = Simd8x16ShuffleOp();
2513 13233 : break;
2514 : }
2515 : case kExprS128LoadMem:
2516 16 : len = DecodeLoadMem(LoadType::kS128Load, 1);
2517 16 : break;
2518 : case kExprS128StoreMem:
2519 8 : len = DecodeStoreMem(StoreType::kS128Store, 1);
2520 8 : break;
2521 : default: {
2522 4320 : FunctionSig* sig = WasmOpcodes::Signature(opcode);
2523 4320 : if (!VALIDATE(sig != nullptr)) {
2524 0 : this->error("invalid simd opcode");
2525 0 : break;
2526 : }
2527 : PopArgs(sig);
2528 : auto* results =
2529 4320 : sig->return_count() == 0 ? nullptr : Push(GetReturnType(sig));
2530 8640 : CALL_INTERFACE_IF_REACHABLE(SimdOp, opcode, VectorOf(args_), results);
2531 : }
2532 : }
2533 19633 : return len;
2534 : }
2535 :
2536 47547 : uint32_t DecodeAtomicOpcode(WasmOpcode opcode) {
2537 : uint32_t len = 0;
2538 : ValueType ret_type;
2539 47547 : FunctionSig* sig = WasmOpcodes::Signature(opcode);
2540 47487 : if (sig != nullptr) {
2541 : MachineType memtype;
2542 47487 : switch (opcode) {
2543 : #define CASE_ATOMIC_STORE_OP(Name, Type) \
2544 : case kExpr##Name: { \
2545 : memtype = MachineType::Type(); \
2546 : ret_type = kWasmStmt; \
2547 : break; \
2548 : }
2549 422 : ATOMIC_STORE_OP_LIST(CASE_ATOMIC_STORE_OP)
2550 : #undef CASE_ATOMIC_OP
2551 : #define CASE_ATOMIC_OP(Name, Type) \
2552 : case kExpr##Name: { \
2553 : memtype = MachineType::Type(); \
2554 : ret_type = GetReturnType(sig); \
2555 : break; \
2556 : }
2557 42899 : ATOMIC_OP_LIST(CASE_ATOMIC_OP)
2558 : #undef CASE_ATOMIC_OP
2559 : default:
2560 0 : this->error("invalid atomic opcode");
2561 0 : return 0;
2562 : }
2563 : MemoryAccessImmediate<validate> imm(
2564 47487 : this, this->pc_ + 1, ElementSizeLog2Of(memtype.representation()));
2565 47582 : len += imm.length;
2566 : PopArgs(sig);
2567 47885 : auto result = ret_type == kWasmStmt ? nullptr : Push(GetReturnType(sig));
2568 81510 : CALL_INTERFACE_IF_REACHABLE(AtomicOp, opcode, VectorOf(args_), imm,
2569 : result);
2570 : } else {
2571 0 : this->error("invalid atomic opcode");
2572 : }
2573 : return len;
2574 : }
2575 :
2576 555 : unsigned DecodeNumericOpcode(WasmOpcode opcode) {
2577 : unsigned len = 0;
2578 555 : FunctionSig* sig = WasmOpcodes::Signature(opcode);
2579 555 : if (sig != nullptr) {
2580 555 : switch (opcode) {
2581 : case kExprI32SConvertSatF32:
2582 : case kExprI32UConvertSatF32:
2583 : case kExprI32SConvertSatF64:
2584 : case kExprI32UConvertSatF64:
2585 : case kExprI64SConvertSatF32:
2586 : case kExprI64UConvertSatF32:
2587 : case kExprI64SConvertSatF64:
2588 : case kExprI64UConvertSatF64:
2589 96 : BuildSimpleOperator(opcode, sig);
2590 96 : break;
2591 : case kExprMemoryInit: {
2592 106 : MemoryInitImmediate<validate> imm(this, this->pc_);
2593 105 : if (!this->Validate(imm)) break;
2594 104 : len += imm.length;
2595 : auto size = Pop(2, sig->GetParam(2));
2596 : auto src = Pop(1, sig->GetParam(1));
2597 : auto dst = Pop(0, sig->GetParam(0));
2598 108 : CALL_INTERFACE_IF_REACHABLE(MemoryInit, imm, dst, src, size);
2599 : break;
2600 : }
2601 : case kExprDataDrop: {
2602 68 : DataDropImmediate<validate> imm(this, this->pc_);
2603 68 : if (!this->Validate(imm)) break;
2604 67 : len += imm.length;
2605 68 : CALL_INTERFACE_IF_REACHABLE(DataDrop, imm);
2606 : break;
2607 : }
2608 : case kExprMemoryCopy: {
2609 64 : MemoryCopyImmediate<validate> imm(this, this->pc_);
2610 64 : if (!this->Validate(imm)) break;
2611 63 : len += imm.length;
2612 : auto size = Pop(2, sig->GetParam(2));
2613 : auto src = Pop(1, sig->GetParam(1));
2614 : auto dst = Pop(0, sig->GetParam(0));
2615 64 : CALL_INTERFACE_IF_REACHABLE(MemoryCopy, imm, dst, src, size);
2616 : break;
2617 : }
2618 : case kExprMemoryFill: {
2619 64 : MemoryIndexImmediate<validate> imm(this, this->pc_ + 1);
2620 128 : if (!this->Validate(this->pc_ + 1, imm)) break;
2621 63 : len += imm.length;
2622 : auto size = Pop(2, sig->GetParam(2));
2623 : auto value = Pop(1, sig->GetParam(1));
2624 : auto dst = Pop(0, sig->GetParam(0));
2625 64 : CALL_INTERFACE_IF_REACHABLE(MemoryFill, imm, dst, value, size);
2626 : break;
2627 : }
2628 : case kExprTableInit: {
2629 40 : TableInitImmediate<validate> imm(this, this->pc_);
2630 40 : if (!this->Validate(imm)) break;
2631 37 : len += imm.length;
2632 : PopArgs(sig);
2633 64 : CALL_INTERFACE_IF_REACHABLE(TableInit, imm, VectorOf(args_));
2634 : break;
2635 : }
2636 : case kExprElemDrop: {
2637 41 : ElemDropImmediate<validate> imm(this, this->pc_);
2638 41 : if (!this->Validate(imm)) break;
2639 39 : len += imm.length;
2640 40 : CALL_INTERFACE_IF_REACHABLE(ElemDrop, imm);
2641 : break;
2642 : }
2643 : case kExprTableCopy: {
2644 76 : TableCopyImmediate<validate> imm(this, this->pc_);
2645 76 : if (!this->Validate(imm)) break;
2646 75 : len += imm.length;
2647 : PopArgs(sig);
2648 127 : CALL_INTERFACE_IF_REACHABLE(TableCopy, imm, VectorOf(args_));
2649 : break;
2650 : }
2651 : default:
2652 0 : this->error("invalid numeric opcode");
2653 0 : break;
2654 : }
2655 : } else {
2656 0 : this->error("invalid numeric opcode");
2657 : }
2658 554 : return len;
2659 : }
2660 :
2661 1294357 : void DoReturn() {
2662 794764 : size_t return_count = this->sig_->return_count();
2663 : DCHECK_GE(stack_.size(), return_count);
2664 : Vector<Value> return_values =
2665 : return_count == 0
2666 : ? Vector<Value>{}
2667 794764 : : Vector<Value>{&*(stack_.end() - return_count), return_count};
2668 :
2669 1294357 : CALL_INTERFACE_IF_REACHABLE(DoReturn, return_values);
2670 1294336 : }
2671 :
2672 : inline Value* Push(ValueType type) {
2673 : DCHECK_NE(kWasmStmt, type);
2674 7751582 : stack_.emplace_back(this->pc_, type);
2675 : return &stack_.back();
2676 : }
2677 :
2678 820558 : void PushMergeValues(Control* c, Merge<Value>* merge) {
2679 : DCHECK_EQ(c, &control_.back());
2680 : DCHECK(merge == &c->start_merge || merge == &c->end_merge);
2681 1641116 : stack_.erase(stack_.begin() + c->stack_depth, stack_.end());
2682 820591 : if (merge->arity == 1) {
2683 18095 : stack_.push_back(merge->vals.first);
2684 : } else {
2685 803152 : for (uint32_t i = 0; i < merge->arity; i++) {
2686 329 : stack_.push_back(merge->vals.array[i]);
2687 : }
2688 : }
2689 : DCHECK_EQ(c->stack_depth + merge->arity, stack_.size());
2690 820590 : }
2691 :
2692 310500 : Value* PushReturns(FunctionSig* sig) {
2693 : size_t return_count = sig->return_count();
2694 310500 : if (return_count == 0) return nullptr;
2695 : size_t old_size = stack_.size();
2696 851920 : for (size_t i = 0; i < return_count; ++i) {
2697 : Push(sig->GetReturn(i));
2698 : }
2699 282048 : return stack_.data() + old_size;
2700 : }
2701 :
2702 : V8_INLINE Value Pop(int index, ValueType expected) {
2703 : auto val = Pop();
2704 6551009 : if (!VALIDATE(ValueTypes::IsSubType(expected, val.type) ||
2705 : val.type == kWasmVar || expected == kWasmVar)) {
2706 103885 : this->errorf(val.pc, "%s[%d] expected type %s, found %s of type %s",
2707 : SafeOpcodeNameAt(this->pc_), index,
2708 : ValueTypes::TypeName(expected), SafeOpcodeNameAt(val.pc),
2709 : ValueTypes::TypeName(val.type));
2710 : }
2711 : return val;
2712 : }
2713 :
2714 : V8_INLINE Value Pop() {
2715 : DCHECK(!control_.empty());
2716 6735395 : uint32_t limit = control_.back().stack_depth;
2717 6735395 : if (stack_.size() <= limit) {
2718 : // Popping past the current control start in reachable code.
2719 15868 : if (!VALIDATE(control_.back().unreachable())) {
2720 17209 : this->errorf(this->pc_, "%s found empty stack",
2721 : SafeOpcodeNameAt(this->pc_));
2722 : }
2723 15140 : return UnreachableValue(this->pc_);
2724 : }
2725 6538711 : auto val = stack_.back();
2726 : stack_.pop_back();
2727 3141453 : return val;
2728 : }
2729 :
2730 6211 : int startrel(const byte* ptr) { return static_cast<int>(ptr - this->start_); }
2731 :
2732 499 : void FallThruTo(Control* c) {
2733 : DCHECK_EQ(c, &control_.back());
2734 774 : if (!TypeCheckFallThru(c)) return;
2735 775 : if (!c->reachable()) return;
2736 :
2737 270 : if (!c->is_loop()) CALL_INTERFACE(FallThruTo, c);
2738 377 : c->end_merge.reached = true;
2739 : }
2740 :
2741 948616 : bool TypeCheckMergeValues(Control* c, Merge<Value>* merge) {
2742 : DCHECK(merge == &c->start_merge || merge == &c->end_merge);
2743 : DCHECK_GE(stack_.size(), c->stack_depth + merge->arity);
2744 : // The computation of {stack_values} is only valid if {merge->arity} is >0.
2745 : DCHECK_LT(0, merge->arity);
2746 948616 : Value* stack_values = &*(stack_.end() - merge->arity);
2747 : // Typecheck the topmost {merge->arity} values on the stack.
2748 2840118 : for (uint32_t i = 0; i < merge->arity; ++i) {
2749 950689 : Value& val = stack_values[i];
2750 : Value& old = (*merge)[i];
2751 950689 : if (ValueTypes::IsSubType(old.type, val.type)) continue;
2752 : // If {val.type} is polymorphic, which results from unreachable, make
2753 : // it more specific by using the merge value's expected type.
2754 : // If it is not polymorphic, this is a type error.
2755 28100 : if (!VALIDATE(val.type == kWasmVar)) {
2756 6306 : this->errorf(this->pc_, "type error in merge[%u] (expected %s, got %s)",
2757 1450 : i, ValueTypes::TypeName(old.type),
2758 : ValueTypes::TypeName(val.type));
2759 3406 : return false;
2760 : }
2761 23244 : val.type = old.type;
2762 : }
2763 :
2764 : return true;
2765 : }
2766 :
2767 1623808 : bool TypeCheckFallThru(Control* c) {
2768 : DCHECK_EQ(c, &control_.back());
2769 : if (!validate) return true;
2770 1623808 : uint32_t expected = c->end_merge.arity;
2771 : DCHECK_GE(stack_.size(), c->stack_depth);
2772 1623808 : uint32_t actual = static_cast<uint32_t>(stack_.size()) - c->stack_depth;
2773 : // Fallthrus must match the arity of the control exactly.
2774 1623808 : if (!InsertUnreachablesIfNecessary(expected, actual) || actual > expected) {
2775 8732 : this->errorf(
2776 : this->pc_,
2777 : "expected %u elements on the stack for fallthru to @%d, found %u",
2778 : expected, startrel(c->pc), actual);
2779 4364 : return false;
2780 : }
2781 1619747 : if (expected == 0) return true; // Fast path.
2782 :
2783 938805 : return TypeCheckMergeValues(c, &c->end_merge);
2784 : }
2785 :
2786 336668 : bool TypeCheckBranch(Control* c) {
2787 : // Branches must have at least the number of values expected; can have more.
2788 336668 : uint32_t expected = c->br_merge()->arity;
2789 336668 : if (expected == 0) return true; // Fast path.
2790 : DCHECK_GE(stack_.size(), control_.back().stack_depth);
2791 : uint32_t actual =
2792 17292 : static_cast<uint32_t>(stack_.size()) - control_.back().stack_depth;
2793 11878 : if (!InsertUnreachablesIfNecessary(expected, actual)) {
2794 3690 : this->errorf(this->pc_,
2795 : "expected %u elements on the stack for br to @%d, found %u",
2796 : expected, startrel(c->pc), actual);
2797 1844 : return false;
2798 : }
2799 10030 : return TypeCheckMergeValues(c, c->br_merge());
2800 : }
2801 :
2802 342689 : bool TypeCheckReturn() {
2803 : // Returns must have at least the number of values expected; can have more.
2804 342689 : uint32_t num_returns = static_cast<uint32_t>(this->sig_->return_count());
2805 : DCHECK_GE(stack_.size(), control_.back().stack_depth);
2806 : uint32_t actual =
2807 451279 : static_cast<uint32_t>(stack_.size()) - control_.back().stack_depth;
2808 342689 : if (!InsertUnreachablesIfNecessary(num_returns, actual)) {
2809 688 : this->errorf(this->pc_,
2810 : "expected %u elements on the stack for return, found %u",
2811 : num_returns, actual);
2812 688 : return false;
2813 : }
2814 :
2815 : // Typecheck the topmost {num_returns} values on the stack.
2816 342040 : if (num_returns == 0) return true;
2817 : // This line requires num_returns > 0.
2818 : Value* stack_values = &*(stack_.end() - num_returns);
2819 213732 : for (uint32_t i = 0; i < num_returns; ++i) {
2820 71342 : auto& val = stack_values[i];
2821 71342 : ValueType expected_type = this->sig_->GetReturn(i);
2822 71342 : if (ValueTypes::IsSubType(expected_type, val.type)) continue;
2823 : // If {val.type} is polymorphic, which results from unreachable,
2824 : // make it more specific by using the return's expected type.
2825 : // If it is not polymorphic, this is a type error.
2826 220 : if (!VALIDATE(val.type == kWasmVar)) {
2827 144 : this->errorf(this->pc_,
2828 : "type error in return[%u] (expected %s, got %s)", i,
2829 : ValueTypes::TypeName(expected_type),
2830 : ValueTypes::TypeName(val.type));
2831 144 : return false;
2832 : }
2833 76 : val.type = expected_type;
2834 : }
2835 : return true;
2836 : }
2837 :
2838 1978402 : inline bool InsertUnreachablesIfNecessary(uint32_t expected,
2839 : uint32_t actual) {
2840 1978402 : if (V8_LIKELY(actual >= expected)) {
2841 : return true; // enough actual values are there.
2842 : }
2843 27146 : if (!VALIDATE(control_.back().unreachable())) {
2844 : // There aren't enough values on the stack.
2845 : return false;
2846 : }
2847 : // A slow path. When the actual number of values on the stack is less
2848 : // than the expected number of values and the current control is
2849 : // unreachable, insert unreachable values below the actual values.
2850 : // This simplifies {TypeCheckMergeValues}.
2851 22641 : auto pos = stack_.begin() + (stack_.size() - actual);
2852 64703 : stack_.insert(pos, expected - actual, UnreachableValue(this->pc_));
2853 22639 : return true;
2854 : }
2855 :
2856 62066 : void onFirstError() override {
2857 62066 : this->end_ = this->pc_; // Terminate decoding loop.
2858 : TRACE(" !%s\n", this->error_.message().c_str());
2859 : CALL_INTERFACE(OnFirstError);
2860 62066 : }
2861 :
2862 130 : void BuildSimplePrototypeOperator(WasmOpcode opcode) {
2863 130 : if (WasmOpcodes::IsSignExtensionOpcode(opcode)) {
2864 62 : RET_ON_PROTOTYPE_OPCODE(se);
2865 : }
2866 130 : if (WasmOpcodes::IsAnyRefOpcode(opcode)) {
2867 68 : RET_ON_PROTOTYPE_OPCODE(anyref);
2868 : }
2869 130 : FunctionSig* sig = WasmOpcodes::Signature(opcode);
2870 129 : BuildSimpleOperator(opcode, sig);
2871 130 : }
2872 :
2873 100395 : void BuildSimpleOperator(WasmOpcode opcode, FunctionSig* sig) {
2874 100395 : switch (sig->parameter_count()) {
2875 : case 1: {
2876 : auto val = Pop(0, sig->GetParam(0));
2877 : auto* ret =
2878 57610 : sig->return_count() == 0 ? nullptr : Push(sig->GetReturn(0));
2879 57112 : CALL_INTERFACE_IF_REACHABLE(UnOp, opcode, val, ret);
2880 : break;
2881 : }
2882 : case 2: {
2883 : auto rval = Pop(1, sig->GetParam(1));
2884 : auto lval = Pop(0, sig->GetParam(0));
2885 : auto* ret =
2886 42785 : sig->return_count() == 0 ? nullptr : Push(sig->GetReturn(0));
2887 41285 : CALL_INTERFACE_IF_REACHABLE(BinOp, opcode, lval, rval, ret);
2888 : break;
2889 : }
2890 : default:
2891 0 : UNREACHABLE();
2892 : }
2893 100396 : }
2894 :
2895 567390 : void BuildSimpleOperator(WasmOpcode opcode, ValueType return_type,
2896 : ValueType arg_type) {
2897 : auto val = Pop(0, arg_type);
2898 567431 : auto* ret = return_type == kWasmStmt ? nullptr : Push(return_type);
2899 354925 : CALL_INTERFACE_IF_REACHABLE(UnOp, opcode, val, ret);
2900 567484 : }
2901 :
2902 1735852 : void BuildSimpleOperator(WasmOpcode opcode, ValueType return_type,
2903 : ValueType lhs_type, ValueType rhs_type) {
2904 : auto rval = Pop(1, rhs_type);
2905 : auto lval = Pop(0, lhs_type);
2906 1736012 : auto* ret = return_type == kWasmStmt ? nullptr : Push(return_type);
2907 1591334 : CALL_INTERFACE_IF_REACHABLE(BinOp, opcode, lval, rval, ret);
2908 1735852 : }
2909 :
2910 : #define DEFINE_SIMPLE_SIG_OPERATOR(sig, ...) \
2911 : void BuildSimpleOperator_##sig(WasmOpcode opcode) { \
2912 : BuildSimpleOperator(opcode, __VA_ARGS__); \
2913 : }
2914 260395 : FOREACH_SIGNATURE(DEFINE_SIMPLE_SIG_OPERATOR)
2915 : #undef DEFINE_SIMPLE_SIG_OPERATOR
2916 : };
2917 :
2918 : #undef CALL_INTERFACE
2919 : #undef CALL_INTERFACE_IF_REACHABLE
2920 : #undef CALL_INTERFACE_IF_PARENT_REACHABLE
2921 :
2922 : class EmptyInterface {
2923 : public:
2924 : static constexpr Decoder::ValidateFlag validate = Decoder::kValidate;
2925 : using Value = ValueBase;
2926 : using Control = ControlBase<Value>;
2927 : using FullDecoder = WasmFullDecoder<validate, EmptyInterface>;
2928 :
2929 : #define DEFINE_EMPTY_CALLBACK(name, ...) \
2930 : void name(FullDecoder* decoder, ##__VA_ARGS__) {}
2931 : INTERFACE_FUNCTIONS(DEFINE_EMPTY_CALLBACK)
2932 : #undef DEFINE_EMPTY_CALLBACK
2933 : };
2934 :
2935 : #undef TRACE
2936 : #undef TRACE_INST_FORMAT
2937 : #undef VALIDATE
2938 : #undef CHECK_PROTOTYPE_OPCODE
2939 : #undef OPCODE_ERROR
2940 :
2941 : } // namespace wasm
2942 : } // namespace internal
2943 : } // namespace v8
2944 :
2945 : #endif // V8_WASM_FUNCTION_BODY_DECODER_IMPL_H_
|