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(AtomicWake, 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 30298801 : inline LocalIndexImmediate(Decoder* decoder, const byte* pc) {
141 60597623 : 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 1118 : inline ExceptionIndexImmediate(Decoder* decoder, const byte* pc) {
152 2237 : 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 30940169 : 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 240889 : 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 705549 : inline ImmF32Immediate(Decoder* decoder, const byte* pc) {
179 : // Avoid bit_cast because it might not preserve the signalling bit of a NaN.
180 1411097 : uint32_t tmp = decoder->read_u32<validate>(pc + 1, "immf32");
181 705548 : memcpy(&value, &tmp, sizeof(value));
182 705548 : }
183 : };
184 :
185 : template <Decoder::ValidateFlag validate>
186 : struct ImmF64Immediate {
187 : double value;
188 : uint32_t length = 8;
189 278549 : inline ImmF64Immediate(Decoder* decoder, const byte* pc) {
190 : // Avoid bit_cast because it might not preserve the signalling bit of a NaN.
191 557098 : uint64_t tmp = decoder->read_u64<validate>(pc + 1, "immf64");
192 278549 : memcpy(&value, &tmp, sizeof(value));
193 278549 : }
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 142046 : inline GlobalIndexImmediate(Decoder* decoder, const byte* pc) {
204 284092 : index = decoder->read_u32v<validate>(pc + 1, &length, "global index");
205 93644 : }
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 6116152 : inline BlockTypeImmediate(const WasmFeatures& enabled, Decoder* decoder,
216 6116152 : const byte* pc) {
217 6116152 : uint8_t val = decoder->read_u8<validate>(pc + 1, "block type");
218 6116156 : if (!decode_local_type(val, &type)) {
219 : // Handle multi-value blocks.
220 320 : if (!VALIDATE(enabled.mv)) {
221 53 : decoder->error(pc + 1, "invalid block type");
222 53 : return;
223 : }
224 267 : if (!VALIDATE(decoder->ok())) return;
225 : int32_t index =
226 50739 : decoder->read_i32v<validate>(pc + 1, &length, "block arity");
227 249 : if (!VALIDATE(length > 0 && index >= 0)) {
228 0 : decoder->error(pc + 1, "invalid block type index");
229 0 : return;
230 : }
231 50739 : 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 6116164 : inline bool decode_local_type(uint8_t val, ValueType* result) {
238 6116164 : switch (static_cast<ValueTypeCode>(val)) {
239 : case kLocalVoid:
240 6015963 : *result = kWasmStmt;
241 : return true;
242 : case kLocalI32:
243 41529 : *result = kWasmI32;
244 : return true;
245 : case kLocalI64:
246 1704 : *result = kWasmI64;
247 : return true;
248 : case kLocalF32:
249 3004 : *result = kWasmF32;
250 : return true;
251 : case kLocalF64:
252 3082 : *result = kWasmF64;
253 : return true;
254 : case kLocalS128:
255 9 : *result = kWasmS128;
256 : return true;
257 : case kLocalAnyFunc:
258 0 : *result = kWasmAnyFunc;
259 : return true;
260 : case kLocalAnyRef:
261 63 : *result = kWasmAnyRef;
262 : return true;
263 : default:
264 50810 : *result = kWasmVar;
265 : return false;
266 : }
267 : }
268 :
269 : uint32_t in_arity() const {
270 489541 : if (type != kWasmVar) return 0;
271 285 : return static_cast<uint32_t>(sig->parameter_count());
272 : }
273 : uint32_t out_arity() const {
274 566362 : if (type == kWasmStmt) return 0;
275 33785 : if (type != kWasmVar) return 1;
276 315 : 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 32786 : 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 863264 : depth = decoder->read_u32v<validate>(pc + 1, &length, "branch depth");
296 : }
297 : };
298 :
299 : template <Decoder::ValidateFlag validate>
300 : struct CallIndirectImmediate {
301 : uint32_t table_index;
302 : uint32_t sig_index;
303 : FunctionSig* sig = nullptr;
304 : uint32_t length = 0;
305 11758 : inline CallIndirectImmediate(Decoder* decoder, const byte* pc) {
306 11758 : uint32_t len = 0;
307 23516 : sig_index = decoder->read_u32v<validate>(pc + 1, &len, "signature index");
308 11759 : if (!VALIDATE(decoder->ok())) return;
309 22601 : table_index = decoder->read_u8<validate>(pc + 1 + len, "table index");
310 10844 : if (!VALIDATE(table_index == 0)) {
311 126 : decoder->errorf(pc + 1 + len, "expected table index 0, found %u",
312 63 : table_index);
313 : }
314 11757 : length = 1 + len;
315 : }
316 : };
317 :
318 : template <Decoder::ValidateFlag validate>
319 : struct CallFunctionImmediate {
320 : uint32_t index;
321 : FunctionSig* sig = nullptr;
322 : uint32_t length;
323 955820 : inline CallFunctionImmediate(Decoder* decoder, const byte* pc) {
324 1911633 : index = decoder->read_u32v<validate>(pc + 1, &length, "function index");
325 : }
326 : };
327 :
328 : template <Decoder::ValidateFlag validate>
329 : struct MemoryIndexImmediate {
330 : uint32_t index;
331 : uint32_t length = 1;
332 4975 : inline MemoryIndexImmediate(Decoder* decoder, const byte* pc) {
333 10006 : index = decoder->read_u8<validate>(pc + 1, "memory index");
334 4975 : if (!VALIDATE(index == 0)) {
335 288 : decoder->errorf(pc + 1, "expected memory index 0, found %u", index);
336 : }
337 4975 : }
338 : };
339 :
340 : template <Decoder::ValidateFlag validate>
341 : struct TableIndexImmediate {
342 : uint32_t index;
343 : unsigned length = 1;
344 145 : inline TableIndexImmediate(Decoder* decoder, const byte* pc) {
345 290 : index = decoder->read_u8<validate>(pc + 1, "table index");
346 145 : if (!VALIDATE(index == 0)) {
347 0 : decoder->errorf(pc + 1, "expected table index 0, found %u", index);
348 : }
349 145 : }
350 : };
351 :
352 : template <Decoder::ValidateFlag validate>
353 : struct BranchTableImmediate {
354 : uint32_t table_count;
355 : const byte* start;
356 : const byte* table;
357 308828 : inline BranchTableImmediate(Decoder* decoder, const byte* pc) {
358 : DCHECK_EQ(kExprBrTable, decoder->read_u8<validate>(pc, "opcode"));
359 308828 : start = pc + 1;
360 308828 : uint32_t len = 0;
361 308828 : table_count = decoder->read_u32v<validate>(pc + 1, &len, "table count");
362 308828 : table = pc + 1 + len;
363 308828 : }
364 : };
365 :
366 : // A helper to iterate over a branch table.
367 : template <Decoder::ValidateFlag validate>
368 : class BranchTableIterator {
369 : public:
370 : uint32_t cur_index() { return index_; }
371 2161968 : bool has_next() { return VALIDATE(decoder_->ok()) && index_ <= table_count_; }
372 2359227 : uint32_t next() {
373 : DCHECK(has_next());
374 2359227 : index_++;
375 : uint32_t length;
376 : uint32_t result =
377 2359227 : decoder_->read_u32v<validate>(pc_, &length, "branch table entry");
378 2360868 : pc_ += length;
379 2360868 : return result;
380 : }
381 : // length, including the length of the {BranchTableImmediate}, but not the
382 : // opcode.
383 51693 : uint32_t length() {
384 72272 : while (has_next()) next();
385 25517 : return static_cast<uint32_t>(pc_ - start_);
386 : }
387 : const byte* pc() { return pc_; }
388 :
389 : BranchTableIterator(Decoder* decoder,
390 : const BranchTableImmediate<validate>& imm)
391 : : decoder_(decoder),
392 : start_(imm.start),
393 : pc_(imm.table),
394 327069 : table_count_(imm.table_count) {}
395 :
396 : private:
397 : Decoder* decoder_;
398 : const byte* start_;
399 : const byte* pc_;
400 : uint32_t index_ = 0; // the current index.
401 : uint32_t table_count_; // the count of entries, not including default.
402 : };
403 :
404 : template <Decoder::ValidateFlag validate>
405 : struct MemoryAccessImmediate {
406 : uint32_t alignment;
407 : uint32_t offset;
408 : uint32_t length = 0;
409 8613434 : inline MemoryAccessImmediate(Decoder* decoder, const byte* pc,
410 8613434 : uint32_t max_alignment) {
411 : uint32_t alignment_length;
412 17226884 : alignment =
413 : decoder->read_u32v<validate>(pc + 1, &alignment_length, "alignment");
414 770877 : if (!VALIDATE(alignment <= max_alignment)) {
415 1055 : decoder->errorf(pc + 1,
416 : "invalid alignment; expected maximum alignment is %u, "
417 : "actual alignment is %u",
418 : max_alignment, alignment);
419 : }
420 8614506 : if (!VALIDATE(decoder->ok())) return;
421 : uint32_t offset_length;
422 17224791 : offset = decoder->read_u32v<validate>(pc + 1 + alignment_length,
423 : &offset_length, "offset");
424 8612397 : length = alignment_length + offset_length;
425 : }
426 : };
427 :
428 : // Immediate for SIMD lane operations.
429 : template <Decoder::ValidateFlag validate>
430 : struct SimdLaneImmediate {
431 : uint8_t lane;
432 : uint32_t length = 1;
433 :
434 34880 : inline SimdLaneImmediate(Decoder* decoder, const byte* pc) {
435 4035195 : lane = decoder->read_u8<validate>(pc + 2, "lane");
436 : }
437 : };
438 :
439 : // Immediate for SIMD shift operations.
440 : template <Decoder::ValidateFlag validate>
441 : struct SimdShiftImmediate {
442 : uint8_t shift;
443 : uint32_t length = 1;
444 :
445 2385 : inline SimdShiftImmediate(Decoder* decoder, const byte* pc) {
446 34710 : shift = decoder->read_u8<validate>(pc + 2, "shift");
447 : }
448 : };
449 :
450 : // Immediate for SIMD S8x16 shuffle operations.
451 : template <Decoder::ValidateFlag validate>
452 : struct Simd8x16ShuffleImmediate {
453 : uint8_t shuffle[kSimd128Size] = {0};
454 :
455 49061 : inline Simd8x16ShuffleImmediate(Decoder* decoder, const byte* pc) {
456 818741 : for (uint32_t i = 0; i < kSimd128Size; ++i) {
457 1325442 : shuffle[i] = decoder->read_u8<validate>(pc + 2 + i, "shuffle");
458 574262 : if (!VALIDATE(decoder->ok())) return;
459 : }
460 : }
461 : };
462 :
463 : template <Decoder::ValidateFlag validate>
464 : struct MemoryInitImmediate {
465 : MemoryIndexImmediate<validate> memory;
466 : uint32_t data_segment_index = 0;
467 : unsigned length = 0;
468 :
469 87 : inline MemoryInitImmediate(Decoder* decoder, const byte* pc)
470 87 : : memory(decoder, pc + 1) {
471 88 : if (!VALIDATE(decoder->ok())) return;
472 86 : uint32_t len = 0;
473 172 : data_segment_index = decoder->read_i32v<validate>(
474 86 : pc + 2 + memory.length, &len, "data segment index");
475 86 : length = memory.length + len;
476 : }
477 : };
478 :
479 : template <Decoder::ValidateFlag validate>
480 : struct MemoryDropImmediate {
481 : uint32_t index;
482 : unsigned length;
483 :
484 : inline MemoryDropImmediate(Decoder* decoder, const byte* pc) {
485 94 : index = decoder->read_i32v<validate>(pc + 2, &length, "data segment index");
486 : }
487 : };
488 :
489 : template <Decoder::ValidateFlag validate>
490 : struct TableInitImmediate {
491 : TableIndexImmediate<validate> table;
492 : uint32_t elem_segment_index = 0;
493 : unsigned length = 0;
494 :
495 26 : inline TableInitImmediate(Decoder* decoder, const byte* pc)
496 26 : : table(decoder, pc + 1) {
497 27 : if (!VALIDATE(decoder->ok())) return;
498 25 : uint32_t len = 0;
499 50 : elem_segment_index = decoder->read_i32v<validate>(
500 25 : pc + 2 + table.length, &len, "elem segment index");
501 25 : length = table.length + len;
502 : }
503 : };
504 :
505 : template <Decoder::ValidateFlag validate>
506 : struct TableDropImmediate {
507 : uint32_t index;
508 : unsigned length;
509 :
510 : inline TableDropImmediate(Decoder* decoder, const byte* pc) {
511 78 : index = decoder->read_i32v<validate>(pc + 2, &length, "elem segment index");
512 : }
513 : };
514 :
515 : // An entry on the value stack.
516 : struct ValueBase {
517 : const byte* pc = nullptr;
518 : ValueType type = kWasmStmt;
519 :
520 10887744 : ValueBase(const byte* pc, ValueType type) : pc(pc), type(type) {}
521 : };
522 :
523 : template <typename Value>
524 : struct Merge {
525 : uint32_t arity = 0;
526 : union { // Either multiple values or a single value.
527 : Value* array;
528 : Value first;
529 : } vals = {nullptr}; // Initialize {array} with {nullptr}.
530 :
531 : // Tracks whether this merge was ever reached. Uses precise reachability, like
532 : // Reachability::kReachable.
533 : bool reached;
534 :
535 2443372 : Merge(bool reached = false) : reached(reached) {}
536 :
537 : Value& operator[](uint32_t i) {
538 : DCHECK_GT(arity, i);
539 1694701 : return arity == 1 ? vals.first : vals.array[i];
540 : }
541 : };
542 :
543 : enum ControlKind : uint8_t {
544 : kControlIf,
545 : kControlIfElse,
546 : kControlBlock,
547 : kControlLoop,
548 : kControlTry,
549 : kControlTryCatch
550 : };
551 :
552 : enum Reachability : uint8_t {
553 : // reachable code.
554 : kReachable,
555 : // reachable code in unreachable block (implies normal validation).
556 : kSpecOnlyReachable,
557 : // code unreachable in its own block (implies polymorphic validation).
558 : kUnreachable
559 : };
560 :
561 : // An entry on the control stack (i.e. if, block, loop, or try).
562 : template <typename Value>
563 : struct ControlBase {
564 : ControlKind kind = kControlBlock;
565 : uint32_t stack_depth = 0; // stack height at the beginning of the construct.
566 : const uint8_t* pc = nullptr;
567 : Reachability reachability = kReachable;
568 :
569 : // Values merged into the start or end of this control construct.
570 : Merge<Value> start_merge;
571 : Merge<Value> end_merge;
572 :
573 : MOVE_ONLY_NO_DEFAULT_CONSTRUCTOR(ControlBase);
574 :
575 : ControlBase(ControlKind kind, uint32_t stack_depth, const uint8_t* pc,
576 : Reachability reachability)
577 : : kind(kind),
578 : stack_depth(stack_depth),
579 : pc(pc),
580 : reachability(reachability),
581 2443372 : start_merge(reachability == kReachable) {}
582 :
583 : // Check whether the current block is reachable.
584 : bool reachable() const { return reachability == kReachable; }
585 :
586 : // Check whether the rest of the block is unreachable.
587 : // Note that this is different from {!reachable()}, as there is also the
588 : // "indirect unreachable state", for which both {reachable()} and
589 : // {unreachable()} return false.
590 11976 : bool unreachable() const { return reachability == kUnreachable; }
591 :
592 : // Return the reachability of new control structs started in this block.
593 : Reachability innerReachability() const {
594 514454 : return reachability == kReachable ? kReachable : kSpecOnlyReachable;
595 : }
596 :
597 24841 : bool is_if() const { return is_onearmed_if() || is_if_else(); }
598 : bool is_onearmed_if() const { return kind == kControlIf; }
599 : bool is_if_else() const { return kind == kControlIfElse; }
600 : bool is_block() const { return kind == kControlBlock; }
601 : bool is_loop() const { return kind == kControlLoop; }
602 : bool is_incomplete_try() const { return kind == kControlTry; }
603 : bool is_try_catch() const { return kind == kControlTryCatch; }
604 517 : bool is_try() const { return is_incomplete_try() || is_try_catch(); }
605 :
606 1372103 : inline Merge<Value>* br_merge() {
607 1508860 : return is_loop() ? &this->start_merge : &this->end_merge;
608 : }
609 : };
610 :
611 : // This is the list of callback functions that an interface for the
612 : // WasmFullDecoder should implement.
613 : // F(Name, args...)
614 : #define INTERFACE_FUNCTIONS(F) \
615 : /* General: */ \
616 : F(StartFunction) \
617 : F(StartFunctionBody, Control* block) \
618 : F(FinishFunction) \
619 : F(OnFirstError) \
620 : F(NextInstruction, WasmOpcode) \
621 : /* Control: */ \
622 : F(Block, Control* block) \
623 : F(Loop, Control* block) \
624 : F(Try, Control* block) \
625 : F(Catch, Control* block, Value* exception) \
626 : F(If, const Value& cond, Control* if_block) \
627 : F(FallThruTo, Control* c) \
628 : F(PopControl, Control* block) \
629 : F(EndControl, Control* block) \
630 : /* Instructions: */ \
631 : F(UnOp, WasmOpcode opcode, const Value& value, Value* result) \
632 : F(BinOp, WasmOpcode opcode, const Value& lhs, const Value& rhs, \
633 : Value* result) \
634 : F(I32Const, Value* result, int32_t value) \
635 : F(I64Const, Value* result, int64_t value) \
636 : F(F32Const, Value* result, float value) \
637 : F(F64Const, Value* result, double value) \
638 : F(RefNull, Value* result) \
639 : F(Drop, const Value& value) \
640 : F(DoReturn, Vector<Value> values) \
641 : F(GetLocal, Value* result, const LocalIndexImmediate<validate>& imm) \
642 : F(SetLocal, const Value& value, const LocalIndexImmediate<validate>& imm) \
643 : F(TeeLocal, const Value& value, Value* result, \
644 : const LocalIndexImmediate<validate>& imm) \
645 : F(GetGlobal, Value* result, const GlobalIndexImmediate<validate>& imm) \
646 : F(SetGlobal, const Value& value, const GlobalIndexImmediate<validate>& imm) \
647 : F(Unreachable) \
648 : F(Select, const Value& cond, const Value& fval, const Value& tval, \
649 : Value* result) \
650 : F(Br, Control* target) \
651 : F(BrIf, const Value& cond, uint32_t depth) \
652 : F(BrTable, const BranchTableImmediate<validate>& imm, const Value& key) \
653 : F(Else, Control* if_block) \
654 : F(LoadMem, LoadType type, const MemoryAccessImmediate<validate>& imm, \
655 : const Value& index, Value* result) \
656 : F(StoreMem, StoreType type, const MemoryAccessImmediate<validate>& imm, \
657 : const Value& index, const Value& value) \
658 : F(CurrentMemoryPages, Value* result) \
659 : F(MemoryGrow, const Value& value, Value* result) \
660 : F(CallDirect, const CallFunctionImmediate<validate>& imm, \
661 : const Value args[], Value returns[]) \
662 : F(CallIndirect, const Value& index, \
663 : const CallIndirectImmediate<validate>& imm, const Value args[], \
664 : Value returns[]) \
665 : F(SimdOp, WasmOpcode opcode, Vector<Value> args, Value* result) \
666 : F(SimdLaneOp, WasmOpcode opcode, const SimdLaneImmediate<validate>& imm, \
667 : const Vector<Value> inputs, Value* result) \
668 : F(SimdShiftOp, WasmOpcode opcode, const SimdShiftImmediate<validate>& imm, \
669 : const Value& input, Value* result) \
670 : F(Simd8x16ShuffleOp, const Simd8x16ShuffleImmediate<validate>& imm, \
671 : const Value& input0, const Value& input1, Value* result) \
672 : F(Throw, const ExceptionIndexImmediate<validate>& imm, \
673 : const Vector<Value>& args) \
674 : F(Rethrow, const Value& exception) \
675 : F(BrOnException, const Value& exception, \
676 : const ExceptionIndexImmediate<validate>& imm, uint32_t depth, \
677 : Vector<Value> values) \
678 : F(AtomicOp, WasmOpcode opcode, Vector<Value> args, \
679 : const MemoryAccessImmediate<validate>& imm, Value* result) \
680 : F(MemoryInit, const MemoryInitImmediate<validate>& imm, const Value& dst, \
681 : const Value& src, const Value& size) \
682 : F(MemoryDrop, const MemoryDropImmediate<validate>& imm) \
683 : F(MemoryCopy, const MemoryIndexImmediate<validate>& imm, const Value& dst, \
684 : const Value& src, const Value& size) \
685 : F(MemoryFill, const MemoryIndexImmediate<validate>& imm, const Value& dst, \
686 : const Value& value, const Value& size) \
687 : F(TableInit, const TableInitImmediate<validate>& imm, Vector<Value> args) \
688 : F(TableDrop, const TableDropImmediate<validate>& imm) \
689 : F(TableCopy, const TableIndexImmediate<validate>& imm, Vector<Value> args)
690 :
691 : // Generic Wasm bytecode decoder with utilities for decoding immediates,
692 : // lengths, etc.
693 : template <Decoder::ValidateFlag validate>
694 4832776 : class WasmDecoder : public Decoder {
695 : public:
696 : WasmDecoder(const WasmModule* module, const WasmFeatures& enabled,
697 : WasmFeatures* detected, FunctionSig* sig, const byte* start,
698 : const byte* end, uint32_t buffer_offset = 0)
699 : : Decoder(start, end, buffer_offset),
700 : module_(module),
701 : enabled_(enabled),
702 : detected_(detected),
703 : sig_(sig),
704 4832739 : local_types_(nullptr) {}
705 : const WasmModule* module_;
706 : const WasmFeatures enabled_;
707 : WasmFeatures* detected_;
708 : FunctionSig* sig_;
709 :
710 : ZoneVector<ValueType>* local_types_;
711 :
712 : uint32_t total_locals() const {
713 : return local_types_ == nullptr
714 : ? 0
715 3926266 : : static_cast<uint32_t>(local_types_->size());
716 : }
717 :
718 2488916 : static bool DecodeLocals(const WasmFeatures& enabled, Decoder* decoder,
719 : const FunctionSig* sig,
720 : ZoneVector<ValueType>* type_list) {
721 : DCHECK_NOT_NULL(type_list);
722 : DCHECK_EQ(0, type_list->size());
723 : // Initialize from signature.
724 2412563 : if (sig != nullptr) {
725 2030389 : type_list->assign(sig->parameters().begin(), sig->parameters().end());
726 : }
727 : // Decode local declarations, if any.
728 : uint32_t entries = decoder->consume_u32v("local decls count");
729 2412705 : if (decoder->failed()) return false;
730 :
731 : TRACE("local decls count: %u\n", entries);
732 2641415 : while (entries-- > 0 && VALIDATE(decoder->ok()) && decoder->more()) {
733 : uint32_t count = decoder->consume_u32v("local count");
734 76349 : if (decoder->failed()) return false;
735 :
736 : DCHECK_LE(type_list->size(), kV8MaxWasmFunctionLocals);
737 152524 : if (count > kV8MaxWasmFunctionLocals - type_list->size()) {
738 48 : decoder->error(decoder->pc() - 1, "local count too large");
739 48 : return false;
740 : }
741 : byte code = decoder->consume_u8("local type");
742 76214 : if (decoder->failed()) return false;
743 :
744 : ValueType type;
745 76214 : switch (code) {
746 : case kLocalI32:
747 35915 : type = kWasmI32;
748 35915 : break;
749 : case kLocalI64:
750 30490 : type = kWasmI64;
751 30490 : break;
752 : case kLocalF32:
753 1626 : type = kWasmF32;
754 1626 : break;
755 : case kLocalF64:
756 2647 : type = kWasmF64;
757 2647 : break;
758 : case kLocalAnyRef:
759 38 : if (enabled.anyref) {
760 38 : type = kWasmAnyRef;
761 38 : break;
762 : }
763 0 : decoder->error(decoder->pc() - 1, "invalid local type");
764 0 : return false;
765 : case kLocalExceptRef:
766 145 : if (enabled.eh) {
767 145 : type = kWasmExceptRef;
768 145 : break;
769 : }
770 0 : decoder->error(decoder->pc() - 1, "invalid local type");
771 0 : return false;
772 : case kLocalS128:
773 5320 : if (enabled.simd) {
774 5311 : type = kWasmS128;
775 5311 : break;
776 : }
777 : V8_FALLTHROUGH;
778 : default:
779 42 : decoder->error(decoder->pc() - 1, "invalid local type");
780 39 : return false;
781 : }
782 76172 : type_list->insert(type_list->end(), count, type);
783 : }
784 : DCHECK(decoder->ok());
785 : return true;
786 : }
787 :
788 1879491 : static BitVector* AnalyzeLoopAssignment(Decoder* decoder, const byte* pc,
789 : uint32_t locals_count, Zone* zone) {
790 10751 : if (pc >= decoder->end()) return nullptr;
791 10750 : if (*pc != kExprLoop) return nullptr;
792 :
793 : // The number of locals_count is augmented by 2 so that 'locals_count - 2'
794 : // can be used to track mem_size, and 'locals_count - 1' to track mem_start.
795 143150 : BitVector* assigned = new (zone) BitVector(locals_count, zone);
796 : int depth = 0;
797 : // Iteratively process all AST nodes nested inside the loop.
798 3748211 : while (pc < decoder->end() && VALIDATE(decoder->ok())) {
799 1868727 : WasmOpcode opcode = static_cast<WasmOpcode>(*pc);
800 : uint32_t length = 1;
801 1868727 : switch (opcode) {
802 : case kExprLoop:
803 : case kExprIf:
804 : case kExprBlock:
805 : case kExprTry:
806 98008 : length = OpcodeLength(decoder, pc);
807 98013 : depth++;
808 98013 : break;
809 : case kExprSetLocal: // fallthru
810 : case kExprTeeLocal: {
811 : LocalIndexImmediate<validate> imm(decoder, pc);
812 132399 : if (assigned->length() > 0 &&
813 : imm.index < static_cast<uint32_t>(assigned->length())) {
814 : // Unverified code might have an out-of-bounds index.
815 132397 : assigned->Add(imm.index);
816 : }
817 132399 : length = 1 + imm.length;
818 : break;
819 : }
820 : case kExprMemoryGrow:
821 : case kExprCallFunction:
822 : case kExprCallIndirect:
823 : // Add instance cache nodes to the assigned set.
824 : // TODO(titzer): make this more clear.
825 20966 : assigned->Add(locals_count - 1);
826 20966 : length = OpcodeLength(decoder, pc);
827 20966 : break;
828 : case kExprEnd:
829 97999 : depth--;
830 97999 : break;
831 : default:
832 1519355 : length = OpcodeLength(decoder, pc);
833 1519362 : break;
834 : }
835 1868739 : if (depth <= 0) break;
836 1857997 : pc += length;
837 : }
838 10755 : return VALIDATE(decoder->ok()) ? assigned : nullptr;
839 : }
840 :
841 3883648 : inline bool Validate(const byte* pc, LocalIndexImmediate<validate>& imm) {
842 3883648 : if (!VALIDATE(imm.index < total_locals())) {
843 563 : errorf(pc + 1, "invalid local index: %u", imm.index);
844 563 : return false;
845 : }
846 3882494 : imm.type = local_types_ ? local_types_->at(imm.index) : kWasmStmt;
847 1941261 : return true;
848 : }
849 :
850 1117 : inline bool Validate(const byte* pc, ExceptionIndexImmediate<validate>& imm) {
851 3350 : if (!VALIDATE(module_ != nullptr &&
852 : imm.index < module_->exceptions.size())) {
853 1 : errorf(pc + 1, "Invalid exception index: %u", imm.index);
854 : return false;
855 : }
856 2232 : imm.exception = &module_->exceptions[imm.index];
857 : return true;
858 : }
859 :
860 89250 : inline bool Validate(const byte* pc, GlobalIndexImmediate<validate>& imm) {
861 267722 : if (!VALIDATE(module_ != nullptr && imm.index < module_->globals.size())) {
862 27 : errorf(pc + 1, "invalid global index: %u", imm.index);
863 27 : return false;
864 : }
865 178446 : imm.global = &module_->globals[imm.index];
866 89223 : imm.type = imm.global->type;
867 89223 : return true;
868 : }
869 :
870 : inline bool Complete(const byte* pc, CallFunctionImmediate<validate>& imm) {
871 905010 : if (!VALIDATE(module_ != nullptr &&
872 : imm.index < module_->functions.size())) {
873 : return false;
874 : }
875 608986 : imm.sig = module_->functions[imm.index].sig;
876 : return true;
877 : }
878 :
879 301690 : inline bool Validate(const byte* pc, CallFunctionImmediate<validate>& imm) {
880 301690 : if (Complete(pc, imm)) {
881 : return true;
882 : }
883 81 : errorf(pc + 1, "invalid function index: %u", imm.index);
884 81 : return false;
885 : }
886 :
887 : inline bool Complete(const byte* pc, CallIndirectImmediate<validate>& imm) {
888 29065 : if (!VALIDATE(module_ != nullptr &&
889 : imm.sig_index < module_->signatures.size())) {
890 : return false;
891 : }
892 19866 : imm.sig = module_->signatures[imm.sig_index];
893 : return true;
894 : }
895 :
896 9740 : inline bool Validate(const byte* pc, CallIndirectImmediate<validate>& imm) {
897 19480 : if (!VALIDATE(module_ != nullptr && !module_->tables.empty())) {
898 30 : error("function table has to exist to execute call_indirect");
899 30 : return false;
900 : }
901 9710 : if (!Complete(pc, imm)) {
902 67 : errorf(pc + 1, "invalid signature index: #%u", imm.sig_index);
903 67 : return false;
904 : }
905 : return true;
906 : }
907 :
908 : inline bool Validate(const byte* pc, BranchDepthImmediate<validate>& imm,
909 : size_t control_depth) {
910 307470 : if (!VALIDATE(imm.depth < control_depth)) {
911 651 : errorf(pc + 1, "invalid branch depth: %u", imm.depth);
912 : return false;
913 : }
914 : return true;
915 : }
916 :
917 20648 : bool Validate(const byte* pc, BranchTableImmediate<validate>& imm,
918 : size_t block_depth) {
919 20648 : if (!VALIDATE(imm.table_count < kV8MaxWasmFunctionSize)) {
920 18 : errorf(pc + 1, "invalid table count (> max function size): %u",
921 : imm.table_count);
922 : return false;
923 : }
924 20630 : return checkAvailable(imm.table_count);
925 : }
926 :
927 34880 : inline bool Validate(const byte* pc, WasmOpcode opcode,
928 : SimdLaneImmediate<validate>& imm) {
929 : uint8_t num_lanes = 0;
930 34880 : switch (opcode) {
931 : case kExprF32x4ExtractLane:
932 : case kExprF32x4ReplaceLane:
933 : case kExprI32x4ExtractLane:
934 : case kExprI32x4ReplaceLane:
935 : num_lanes = 4;
936 : break;
937 : case kExprI16x8ExtractLane:
938 : case kExprI16x8ReplaceLane:
939 : num_lanes = 8;
940 : break;
941 : case kExprI8x16ExtractLane:
942 : case kExprI8x16ReplaceLane:
943 : num_lanes = 16;
944 : break;
945 : default:
946 0 : UNREACHABLE();
947 : break;
948 : }
949 34880 : if (!VALIDATE(imm.lane >= 0 && imm.lane < num_lanes)) {
950 0 : error(pc_ + 2, "invalid lane index");
951 : return false;
952 : } else {
953 : return true;
954 : }
955 : }
956 :
957 2385 : inline bool Validate(const byte* pc, WasmOpcode opcode,
958 : SimdShiftImmediate<validate>& imm) {
959 : uint8_t max_shift = 0;
960 2385 : switch (opcode) {
961 : case kExprI32x4Shl:
962 : case kExprI32x4ShrS:
963 : case kExprI32x4ShrU:
964 : max_shift = 32;
965 : break;
966 : case kExprI16x8Shl:
967 : case kExprI16x8ShrS:
968 : case kExprI16x8ShrU:
969 : max_shift = 16;
970 : break;
971 : case kExprI8x16Shl:
972 : case kExprI8x16ShrS:
973 : case kExprI8x16ShrU:
974 : max_shift = 8;
975 : break;
976 : default:
977 0 : UNREACHABLE();
978 : break;
979 : }
980 2385 : if (!VALIDATE(imm.shift >= 0 && imm.shift < max_shift)) {
981 0 : error(pc_ + 2, "invalid shift amount");
982 : return false;
983 : } else {
984 : return true;
985 : }
986 : }
987 :
988 33781 : inline bool Validate(const byte* pc,
989 : Simd8x16ShuffleImmediate<validate>& imm) {
990 33781 : uint8_t max_lane = 0;
991 540496 : for (uint32_t i = 0; i < kSimd128Size; ++i) {
992 1080992 : max_lane = std::max(max_lane, imm.shuffle[i]);
993 : }
994 : // Shuffle indices must be in [0..31] for a 16 lane shuffle.
995 33781 : if (!VALIDATE(max_lane <= 2 * kSimd128Size)) {
996 0 : error(pc_ + 2, "invalid shuffle mask");
997 : return false;
998 : }
999 : return true;
1000 : }
1001 :
1002 489511 : inline bool Complete(BlockTypeImmediate<validate>& imm) {
1003 489511 : if (imm.type != kWasmVar) return true;
1004 872 : if (!VALIDATE((module_ && imm.sig_index < module_->signatures.size()))) {
1005 : return false;
1006 : }
1007 570 : imm.sig = module_->signatures[imm.sig_index];
1008 : return true;
1009 : }
1010 :
1011 489510 : inline bool Validate(BlockTypeImmediate<validate>& imm) {
1012 489510 : if (!Complete(imm)) {
1013 34 : errorf(pc_, "block type index %u out of bounds (%zu signatures)",
1014 0 : imm.sig_index, module_ ? module_->signatures.size() : 0);
1015 17 : return false;
1016 : }
1017 : return true;
1018 : }
1019 :
1020 199 : inline bool Validate(MemoryIndexImmediate<validate>& imm) {
1021 199 : if (!VALIDATE(module_ != nullptr && module_->has_memory)) {
1022 3 : errorf(pc_ + 1, "memory instruction with no memory");
1023 : return false;
1024 : }
1025 : return true;
1026 : }
1027 :
1028 87 : inline bool Validate(MemoryInitImmediate<validate>& imm) {
1029 87 : if (!Validate(imm.memory)) return false;
1030 86 : if (!VALIDATE(module_ != nullptr &&
1031 : imm.data_segment_index <
1032 : module_->num_declared_data_segments)) {
1033 0 : errorf(pc_ + 2, "invalid data segment index: %u", imm.data_segment_index);
1034 : return false;
1035 : }
1036 : return true;
1037 : }
1038 :
1039 47 : inline bool Validate(MemoryDropImmediate<validate>& imm) {
1040 47 : if (!VALIDATE(module_ != nullptr &&
1041 : imm.index < module_->num_declared_data_segments)) {
1042 1 : errorf(pc_ + 2, "invalid data segment index: %u", imm.index);
1043 : return false;
1044 : }
1045 : return true;
1046 : }
1047 :
1048 145 : inline bool Validate(const byte* pc, TableIndexImmediate<validate>& imm) {
1049 288 : if (!VALIDATE(module_ != nullptr && imm.index < module_->tables.size())) {
1050 3 : errorf(pc_ + 1, "invalid table index: %u", imm.index);
1051 : return false;
1052 : }
1053 : return true;
1054 : }
1055 :
1056 26 : inline bool Validate(TableInitImmediate<validate>& imm) {
1057 26 : if (!Validate(pc_ + 1, imm.table)) return false;
1058 48 : if (!VALIDATE(module_ != nullptr &&
1059 : imm.elem_segment_index < module_->elem_segments.size())) {
1060 1 : errorf(pc_ + 2, "invalid element segment index: %u",
1061 : imm.elem_segment_index);
1062 1 : return false;
1063 : }
1064 : return true;
1065 : }
1066 :
1067 39 : inline bool Validate(TableDropImmediate<validate>& imm) {
1068 77 : if (!VALIDATE(module_ != nullptr &&
1069 : imm.index < module_->elem_segments.size())) {
1070 2 : errorf(pc_ + 2, "invalid element segment index: %u", imm.index);
1071 2 : return false;
1072 : }
1073 : return true;
1074 : }
1075 :
1076 4557774 : static uint32_t OpcodeLength(Decoder* decoder, const byte* pc) {
1077 4557774 : WasmOpcode opcode = static_cast<WasmOpcode>(*pc);
1078 4557774 : switch (opcode) {
1079 : #define DECLARE_OPCODE_CASE(name, opcode, sig) case kExpr##name:
1080 : FOREACH_LOAD_MEM_OPCODE(DECLARE_OPCODE_CASE)
1081 : FOREACH_STORE_MEM_OPCODE(DECLARE_OPCODE_CASE)
1082 : #undef DECLARE_OPCODE_CASE
1083 : {
1084 179018 : MemoryAccessImmediate<validate> imm(decoder, pc, UINT32_MAX);
1085 179018 : return 1 + imm.length;
1086 : }
1087 : case kExprBr:
1088 : case kExprBrIf: {
1089 : BranchDepthImmediate<validate> imm(decoder, pc);
1090 65057 : return 1 + imm.length;
1091 : }
1092 : case kExprSetGlobal:
1093 : case kExprGetGlobal: {
1094 3977 : GlobalIndexImmediate<validate> imm(decoder, pc);
1095 28036 : return 1 + imm.length;
1096 : }
1097 :
1098 : case kExprCallFunction: {
1099 : CallFunctionImmediate<validate> imm(decoder, pc);
1100 22719 : return 1 + imm.length;
1101 : }
1102 : case kExprCallIndirect: {
1103 1398 : CallIndirectImmediate<validate> imm(decoder, pc);
1104 1398 : return 1 + imm.length;
1105 : }
1106 :
1107 : case kExprTry:
1108 : case kExprIf: // fall through
1109 : case kExprLoop:
1110 : case kExprBlock: {
1111 136687 : BlockTypeImmediate<validate> imm(kAllWasmFeatures, decoder, pc);
1112 136690 : return 1 + imm.length;
1113 : }
1114 :
1115 : case kExprThrow: {
1116 : ExceptionIndexImmediate<validate> imm(decoder, pc);
1117 1 : return 1 + imm.length;
1118 : }
1119 :
1120 : case kExprBrOnExn: {
1121 : BranchDepthImmediate<validate> imm_br(decoder, pc);
1122 9 : if (!VALIDATE(decoder->ok())) return 1 + imm_br.length;
1123 1 : ExceptionIndexImmediate<validate> imm_idx(decoder, pc + imm_br.length);
1124 1 : return 1 + imm_br.length + imm_idx.length;
1125 : }
1126 :
1127 : case kExprSetLocal:
1128 : case kExprTeeLocal:
1129 : case kExprGetLocal: {
1130 : LocalIndexImmediate<validate> imm(decoder, pc);
1131 594774 : return 1 + imm.length;
1132 : }
1133 : case kExprBrTable: {
1134 5366 : BranchTableImmediate<validate> imm(decoder, pc);
1135 : BranchTableIterator<validate> iterator(decoder, imm);
1136 5366 : return 1 + iterator.length();
1137 : }
1138 : case kExprI32Const: {
1139 : ImmI32Immediate<validate> imm(decoder, pc);
1140 1436849 : return 1 + imm.length;
1141 : }
1142 : case kExprI64Const: {
1143 : ImmI64Immediate<validate> imm(decoder, pc);
1144 3285 : return 1 + imm.length;
1145 : }
1146 : case kExprRefNull: {
1147 : return 1;
1148 : }
1149 : case kExprMemoryGrow:
1150 : case kExprMemorySize: {
1151 72 : MemoryIndexImmediate<validate> imm(decoder, pc);
1152 72 : return 1 + imm.length;
1153 : }
1154 : case kExprF32Const:
1155 630 : return 5;
1156 : case kExprF64Const:
1157 4374 : return 9;
1158 : case kNumericPrefix: {
1159 : byte numeric_index =
1160 30725 : decoder->read_u8<validate>(pc + 1, "numeric_index");
1161 0 : if (!VALIDATE(decoder->ok())) return 2;
1162 : WasmOpcode opcode =
1163 40 : static_cast<WasmOpcode>(kNumericPrefix << 8 | numeric_index);
1164 40 : switch (opcode) {
1165 : case kExprI32SConvertSatF32:
1166 : case kExprI32UConvertSatF32:
1167 : case kExprI32SConvertSatF64:
1168 : case kExprI32UConvertSatF64:
1169 : case kExprI64SConvertSatF32:
1170 : case kExprI64UConvertSatF32:
1171 : case kExprI64SConvertSatF64:
1172 : case kExprI64UConvertSatF64:
1173 : return 2;
1174 : case kExprMemoryInit: {
1175 0 : MemoryInitImmediate<validate> imm(decoder, pc);
1176 0 : return 2 + imm.length;
1177 : }
1178 : case kExprMemoryDrop: {
1179 : MemoryDropImmediate<validate> imm(decoder, pc);
1180 0 : return 2 + imm.length;
1181 : }
1182 : case kExprMemoryCopy:
1183 : case kExprMemoryFill: {
1184 0 : MemoryIndexImmediate<validate> imm(decoder, pc + 1);
1185 0 : return 2 + imm.length;
1186 : }
1187 : case kExprTableInit: {
1188 0 : TableInitImmediate<validate> imm(decoder, pc);
1189 0 : return 2 + imm.length;
1190 : }
1191 : case kExprTableDrop: {
1192 : TableDropImmediate<validate> imm(decoder, pc);
1193 0 : return 2 + imm.length;
1194 : }
1195 : case kExprTableCopy: {
1196 0 : TableIndexImmediate<validate> imm(decoder, pc + 1);
1197 0 : return 2 + imm.length;
1198 : }
1199 : default:
1200 0 : decoder->error(pc, "invalid numeric opcode");
1201 0 : return 2;
1202 : }
1203 : }
1204 : case kSimdPrefix: {
1205 60 : byte simd_index = decoder->read_u8<validate>(pc + 1, "simd_index");
1206 60 : if (!VALIDATE(decoder->ok())) return 2;
1207 : WasmOpcode opcode =
1208 30280 : static_cast<WasmOpcode>(kSimdPrefix << 8 | simd_index);
1209 30280 : switch (opcode) {
1210 : #define DECLARE_OPCODE_CASE(name, opcode, sig) case kExpr##name:
1211 : FOREACH_SIMD_0_OPERAND_OPCODE(DECLARE_OPCODE_CASE)
1212 : #undef DECLARE_OPCODE_CASE
1213 : return 2;
1214 : #define DECLARE_OPCODE_CASE(name, opcode, sig) case kExpr##name:
1215 : FOREACH_SIMD_1_OPERAND_OPCODE(DECLARE_OPCODE_CASE)
1216 : #undef DECLARE_OPCODE_CASE
1217 12347 : return 3;
1218 : #define DECLARE_OPCODE_CASE(name, opcode, sig) case kExpr##name:
1219 : FOREACH_SIMD_MEM_OPCODE(DECLARE_OPCODE_CASE)
1220 : #undef DECLARE_OPCODE_CASE
1221 : {
1222 0 : MemoryAccessImmediate<validate> imm(decoder, pc + 1, UINT32_MAX);
1223 0 : return 2 + imm.length;
1224 : }
1225 : // Shuffles require a byte per lane, or 16 immediate bytes.
1226 : case kExprS8x16Shuffle:
1227 15281 : return 2 + kSimd128Size;
1228 : default:
1229 1 : decoder->error(pc, "invalid SIMD opcode");
1230 1 : return 2;
1231 : }
1232 : }
1233 : case kAtomicPrefix: {
1234 84 : byte atomic_index = decoder->read_u8<validate>(pc + 1, "atomic_index");
1235 84 : if (!VALIDATE(decoder->ok())) return 2;
1236 : WasmOpcode opcode =
1237 549 : static_cast<WasmOpcode>(kAtomicPrefix << 8 | atomic_index);
1238 549 : switch (opcode) {
1239 : #define DECLARE_OPCODE_CASE(name, opcode, sig) case kExpr##name:
1240 : FOREACH_ATOMIC_OPCODE(DECLARE_OPCODE_CASE)
1241 : #undef DECLARE_OPCODE_CASE
1242 : {
1243 549 : MemoryAccessImmediate<validate> imm(decoder, pc + 1, UINT32_MAX);
1244 549 : return 2 + imm.length;
1245 : }
1246 : default:
1247 0 : decoder->error(pc, "invalid Atomics opcode");
1248 0 : return 2;
1249 : }
1250 : }
1251 : default:
1252 : return 1;
1253 : }
1254 : }
1255 :
1256 2881705 : std::pair<uint32_t, uint32_t> StackEffect(const byte* pc) {
1257 2878547 : WasmOpcode opcode = static_cast<WasmOpcode>(*pc);
1258 : // Handle "simple" opcodes with a fixed signature first.
1259 3331418 : FunctionSig* sig = WasmOpcodes::Signature(opcode);
1260 2878547 : if (!sig) sig = WasmOpcodes::AsmjsSignature(opcode);
1261 3328443 : if (sig) return {sig->parameter_count(), sig->return_count()};
1262 :
1263 : #define DECLARE_OPCODE_CASE(name, opcode, sig) case kExpr##name:
1264 : // clang-format off
1265 2428651 : switch (opcode) {
1266 : case kExprSelect:
1267 25 : return {3, 1};
1268 : FOREACH_STORE_MEM_OPCODE(DECLARE_OPCODE_CASE)
1269 93120 : return {2, 0};
1270 : FOREACH_LOAD_MEM_OPCODE(DECLARE_OPCODE_CASE)
1271 : case kExprTeeLocal:
1272 : case kExprMemoryGrow:
1273 85659 : return {1, 1};
1274 : case kExprSetLocal:
1275 : case kExprSetGlobal:
1276 : case kExprDrop:
1277 : case kExprBrIf:
1278 : case kExprBrTable:
1279 : case kExprIf:
1280 105123 : return {1, 0};
1281 : case kExprGetLocal:
1282 : case kExprGetGlobal:
1283 : case kExprI32Const:
1284 : case kExprI64Const:
1285 : case kExprF32Const:
1286 : case kExprF64Const:
1287 : case kExprRefNull:
1288 : case kExprMemorySize:
1289 1262302 : return {0, 1};
1290 : case kExprCallFunction: {
1291 : CallFunctionImmediate<validate> imm(this, pc);
1292 : CHECK(Complete(pc, imm));
1293 5740 : return {imm.sig->parameter_count(), imm.sig->return_count()};
1294 : }
1295 : case kExprCallIndirect: {
1296 288 : CallIndirectImmediate<validate> imm(this, pc);
1297 288 : CHECK(Complete(pc, imm));
1298 : // Indirect calls pop an additional argument for the table index.
1299 : return {imm.sig->parameter_count() + 1,
1300 576 : imm.sig->return_count()};
1301 : }
1302 : case kExprBr:
1303 : case kExprBlock:
1304 : case kExprLoop:
1305 : case kExprEnd:
1306 : case kExprElse:
1307 : case kExprNop:
1308 : case kExprReturn:
1309 : case kExprUnreachable:
1310 848679 : return {0, 0};
1311 : case kNumericPrefix:
1312 : case kAtomicPrefix:
1313 : case kSimdPrefix: {
1314 30585 : opcode = static_cast<WasmOpcode>(opcode << 8 | *(pc + 1));
1315 30585 : switch (opcode) {
1316 : FOREACH_SIMD_1_OPERAND_1_PARAM_OPCODE(DECLARE_OPCODE_CASE)
1317 12100 : return {1, 1};
1318 : FOREACH_SIMD_1_OPERAND_2_PARAM_OPCODE(DECLARE_OPCODE_CASE)
1319 : FOREACH_SIMD_MASK_OPERAND_OPCODE(DECLARE_OPCODE_CASE)
1320 15510 : return {2, 1};
1321 : default: {
1322 2975 : sig = WasmOpcodes::Signature(opcode);
1323 2975 : if (sig) {
1324 2975 : return {sig->parameter_count(), sig->return_count()};
1325 : }
1326 : }
1327 : }
1328 : V8_FALLTHROUGH;
1329 : }
1330 : default:
1331 0 : V8_Fatal(__FILE__, __LINE__, "unimplemented opcode: %x (%s)", opcode,
1332 0 : WasmOpcodes::OpcodeName(opcode));
1333 : return {0, 0};
1334 : }
1335 : #undef DECLARE_OPCODE_CASE
1336 : // clang-format on
1337 : }
1338 : };
1339 :
1340 : #define CALL_INTERFACE(name, ...) interface_.name(this, ##__VA_ARGS__)
1341 : #define CALL_INTERFACE_IF_REACHABLE(name, ...) \
1342 : do { \
1343 : DCHECK(!control_.empty()); \
1344 : if (VALIDATE(this->ok()) && control_.back().reachable()) { \
1345 : interface_.name(this, ##__VA_ARGS__); \
1346 : } \
1347 : } while (false)
1348 : #define CALL_INTERFACE_IF_PARENT_REACHABLE(name, ...) \
1349 : do { \
1350 : DCHECK(!control_.empty()); \
1351 : if (VALIDATE(this->ok()) && \
1352 : (control_.size() == 1 || control_at(1)->reachable())) { \
1353 : interface_.name(this, ##__VA_ARGS__); \
1354 : } \
1355 : } while (false)
1356 :
1357 : template <Decoder::ValidateFlag validate, typename Interface>
1358 3378130 : class WasmFullDecoder : public WasmDecoder<validate> {
1359 : using Value = typename Interface::Value;
1360 : using Control = typename Interface::Control;
1361 : using MergeValues = Merge<Value>;
1362 :
1363 : // All Value types should be trivially copyable for performance. We push, pop,
1364 : // and store them in local variables.
1365 : ASSERT_TRIVIALLY_COPYABLE(Value);
1366 :
1367 : public:
1368 : template <typename... InterfaceArgs>
1369 1954192 : WasmFullDecoder(Zone* zone, const WasmModule* module,
1370 : const WasmFeatures& enabled, WasmFeatures* detected,
1371 : const FunctionBody& body, InterfaceArgs&&... interface_args)
1372 : : WasmDecoder<validate>(module, enabled, detected, body.sig, body.start,
1373 : body.end, body.offset),
1374 : zone_(zone),
1375 : interface_(std::forward<InterfaceArgs>(interface_args)...),
1376 : local_type_vec_(zone),
1377 : stack_(zone),
1378 : control_(zone),
1379 3908384 : args_(zone) {
1380 1954144 : this->local_types_ = &local_type_vec_;
1381 1954144 : }
1382 :
1383 : Interface& interface() { return interface_; }
1384 :
1385 1954143 : bool Decode() {
1386 : DCHECK(stack_.empty());
1387 : DCHECK(control_.empty());
1388 :
1389 : base::ElapsedTimer decode_timer;
1390 : if (FLAG_trace_wasm_decode_time) {
1391 : decode_timer.Start();
1392 : }
1393 :
1394 1954143 : if (this->end_ < this->pc_) {
1395 0 : this->error("function body end < start");
1396 0 : return false;
1397 : }
1398 :
1399 : DCHECK_EQ(0, this->local_types_->size());
1400 1954143 : WasmDecoder<validate>::DecodeLocals(this->enabled_, this, this->sig_,
1401 1954143 : this->local_types_);
1402 2840083 : CALL_INTERFACE(StartFunction);
1403 1954197 : DecodeFunctionBody();
1404 1779052 : if (!this->failed()) CALL_INTERFACE(FinishFunction);
1405 :
1406 : // Generate a better error message whether the unterminated control
1407 : // structure is the function body block or an innner structure.
1408 3907248 : if (control_.size() > 1) {
1409 8046 : this->error(control_.back().pc, "unterminated control structure");
1410 1945578 : } else if (control_.size() == 1) {
1411 47906 : this->error("function body must end with \"end\" opcode");
1412 : }
1413 :
1414 1953774 : if (this->failed()) return this->TraceFailed();
1415 :
1416 : if (FLAG_trace_wasm_decode_time) {
1417 : double ms = decode_timer.Elapsed().InMillisecondsF();
1418 : PrintF("wasm-decode %s (%0.3f ms)\n\n",
1419 : VALIDATE(this->ok()) ? "ok" : "failed", ms);
1420 : } else {
1421 : TRACE("wasm-decode %s\n\n", VALIDATE(this->ok()) ? "ok" : "failed");
1422 : }
1423 :
1424 1897141 : return true;
1425 : }
1426 :
1427 : bool TraceFailed() {
1428 : TRACE("wasm-error module+%-6d func+%d: %s\n\n", this->error_.offset(),
1429 : this->GetBufferRelativeOffset(this->error_.offset()),
1430 : this->error_.message().c_str());
1431 : return false;
1432 : }
1433 :
1434 71272 : const char* SafeOpcodeNameAt(const byte* pc) {
1435 71272 : if (pc >= this->end_) return "<end>";
1436 58913 : return WasmOpcodes::OpcodeName(static_cast<WasmOpcode>(*pc));
1437 : }
1438 :
1439 : inline Zone* zone() const { return zone_; }
1440 :
1441 : inline uint32_t num_locals() const {
1442 4933204 : return static_cast<uint32_t>(local_type_vec_.size());
1443 : }
1444 :
1445 : inline ValueType GetLocalType(uint32_t index) {
1446 5154888 : return local_type_vec_[index];
1447 : }
1448 :
1449 : inline WasmCodePosition position() {
1450 2602826 : int offset = static_cast<int>(this->pc_ - this->start_);
1451 : DCHECK_EQ(this->pc_ - this->start_, offset); // overflows cannot happen
1452 : return offset;
1453 : }
1454 :
1455 : inline uint32_t control_depth() const {
1456 908152 : return static_cast<uint32_t>(control_.size());
1457 : }
1458 :
1459 : inline Control* control_at(uint32_t depth) {
1460 : DCHECK_GT(control_.size(), depth);
1461 839438 : return &control_.back() - depth;
1462 : }
1463 :
1464 : inline uint32_t stack_size() const {
1465 : DCHECK_GE(kMaxUInt32, stack_.size());
1466 4926692 : return static_cast<uint32_t>(stack_.size());
1467 : }
1468 :
1469 : inline Value* stack_value(uint32_t depth) {
1470 : DCHECK_LT(0, depth);
1471 : DCHECK_GE(stack_.size(), depth);
1472 : return &*(stack_.end() - depth);
1473 : }
1474 :
1475 : private:
1476 : Zone* zone_;
1477 :
1478 : Interface interface_;
1479 :
1480 : ZoneVector<ValueType> local_type_vec_; // types of local variables.
1481 : ZoneVector<Value> stack_; // stack of values.
1482 : ZoneVector<Control> control_; // stack of blocks, loops, and ifs.
1483 : ZoneVector<Value> args_; // parameters of current block or call
1484 :
1485 869787 : static Value UnreachableValue(const uint8_t* pc) {
1486 869787 : return Value{pc, kWasmVar};
1487 : }
1488 :
1489 726814 : bool CheckHasMemory() {
1490 726814 : if (!VALIDATE(this->module_->has_memory)) {
1491 180 : this->error(this->pc_ - 1, "memory instruction with no memory");
1492 180 : return false;
1493 : }
1494 : return true;
1495 : }
1496 :
1497 48560 : bool CheckHasSharedMemory() {
1498 48560 : if (!VALIDATE(this->module_->has_shared_memory)) {
1499 18 : this->error(this->pc_ - 1, "Atomic opcodes used without shared memory");
1500 18 : return false;
1501 : }
1502 : return true;
1503 : }
1504 :
1505 : class TraceLine {
1506 : public:
1507 : static constexpr int kMaxLen = 512;
1508 : ~TraceLine() {
1509 : if (!FLAG_trace_wasm_decoder) return;
1510 : PrintF("%.*s\n", len_, buffer_);
1511 : }
1512 :
1513 : // Appends a formatted string.
1514 : PRINTF_FORMAT(2, 3)
1515 : void Append(const char* format, ...) {
1516 : if (!FLAG_trace_wasm_decoder) return;
1517 : va_list va_args;
1518 : va_start(va_args, format);
1519 : size_t remaining_len = kMaxLen - len_;
1520 : Vector<char> remaining_msg_space(buffer_ + len_, remaining_len);
1521 : int len = VSNPrintF(remaining_msg_space, format, va_args);
1522 : va_end(va_args);
1523 : len_ += len < 0 ? remaining_len : len;
1524 : }
1525 :
1526 : private:
1527 : char buffer_[kMaxLen];
1528 : int len_ = 0;
1529 : };
1530 :
1531 : // Decodes the body of a function.
1532 1954127 : void DecodeFunctionBody() {
1533 : TRACE("wasm-decode %p...%p (module+%u, %d bytes)\n",
1534 : reinterpret_cast<const void*>(this->start()),
1535 : reinterpret_cast<const void*>(this->end()), this->pc_offset(),
1536 : static_cast<int>(this->end() - this->start()));
1537 :
1538 : // Set up initial function block.
1539 : {
1540 1954127 : auto* c = PushControl(kControlBlock);
1541 1954045 : InitMerge(&c->start_merge, 0, [](uint32_t) -> Value { UNREACHABLE(); });
1542 3908116 : InitMerge(&c->end_merge,
1543 : static_cast<uint32_t>(this->sig_->return_count()),
1544 : [&](uint32_t i) {
1545 : return Value{this->pc_, this->sig_->GetReturn(i)};
1546 4227387 : });
1547 5166566 : CALL_INTERFACE(StartFunctionBody, c);
1548 : }
1549 :
1550 19646432 : while (this->pc_ < this->end_) { // decoding loop.
1551 : uint32_t len = 1;
1552 16980887 : WasmOpcode opcode = static_cast<WasmOpcode>(*this->pc_);
1553 :
1554 3497879 : CALL_INTERFACE_IF_REACHABLE(NextInstruction, opcode);
1555 :
1556 : #if DEBUG
1557 : TraceLine trace_msg;
1558 : #define TRACE_PART(...) trace_msg.Append(__VA_ARGS__)
1559 : if (!WasmOpcodes::IsPrefixOpcode(opcode)) {
1560 : TRACE_PART(TRACE_INST_FORMAT, startrel(this->pc_),
1561 : WasmOpcodes::OpcodeName(opcode));
1562 : }
1563 : #else
1564 : #define TRACE_PART(...)
1565 : #endif
1566 :
1567 16980887 : switch (opcode) {
1568 : #define BUILD_SIMPLE_OPCODE(op, _, sig) \
1569 : case kExpr##op: \
1570 : BuildSimpleOperator_##sig(opcode); \
1571 : break;
1572 : FOREACH_SIMPLE_OPCODE(BUILD_SIMPLE_OPCODE)
1573 : #undef BUILD_SIMPLE_OPCODE
1574 : case kExprNop:
1575 : break;
1576 : case kExprBlock: {
1577 385515 : BlockTypeImmediate<validate> imm(this->enabled_, this, this->pc_);
1578 385518 : if (!this->Validate(imm)) break;
1579 385512 : PopArgs(imm.sig);
1580 771024 : auto* block = PushControl(kControlBlock);
1581 385521 : SetBlockType(block, imm);
1582 195633 : CALL_INTERFACE_IF_REACHABLE(Block, block);
1583 771026 : PushMergeValues(block, &block->start_merge);
1584 385517 : len = 1 + imm.length;
1585 385517 : break;
1586 : }
1587 : case kExprRethrow: {
1588 481 : CHECK_PROTOTYPE_OPCODE(eh);
1589 : auto exception = Pop(0, kWasmExceptRef);
1590 954 : CALL_INTERFACE_IF_REACHABLE(Rethrow, exception);
1591 481 : EndControl();
1592 481 : break;
1593 : }
1594 : case kExprThrow: {
1595 685 : CHECK_PROTOTYPE_OPCODE(eh);
1596 685 : ExceptionIndexImmediate<validate> imm(this, this->pc_);
1597 686 : len = 1 + imm.length;
1598 686 : if (!this->Validate(this->pc_, imm)) break;
1599 685 : PopArgs(imm.exception->ToFunctionSig());
1600 1904 : CALL_INTERFACE_IF_REACHABLE(Throw, imm, VectorOf(args_));
1601 685 : EndControl();
1602 686 : break;
1603 : }
1604 : case kExprTry: {
1605 742 : CHECK_PROTOTYPE_OPCODE(eh);
1606 742 : BlockTypeImmediate<validate> imm(this->enabled_, this, this->pc_);
1607 742 : if (!this->Validate(imm)) break;
1608 742 : PopArgs(imm.sig);
1609 1483 : auto* try_block = PushControl(kControlTry);
1610 743 : SetBlockType(try_block, imm);
1611 743 : len = 1 + imm.length;
1612 1458 : CALL_INTERFACE_IF_REACHABLE(Try, try_block);
1613 1482 : PushMergeValues(try_block, &try_block->start_merge);
1614 740 : break;
1615 : }
1616 : case kExprCatch: {
1617 517 : CHECK_PROTOTYPE_OPCODE(eh);
1618 517 : if (!VALIDATE(!control_.empty())) {
1619 0 : this->error("catch does not match any try");
1620 0 : break;
1621 : }
1622 517 : Control* c = &control_.back();
1623 517 : if (!VALIDATE(c->is_try())) {
1624 1 : this->error("catch does not match any try");
1625 1 : break;
1626 : }
1627 516 : if (!VALIDATE(c->is_incomplete_try())) {
1628 1 : this->error("catch already present for try");
1629 1 : break;
1630 : }
1631 515 : c->kind = kControlTryCatch;
1632 515 : FallThruTo(c);
1633 1032 : stack_.erase(stack_.begin() + c->stack_depth, stack_.end());
1634 1032 : c->reachability = control_at(1)->innerReachability();
1635 : auto* exception = Push(kWasmExceptRef);
1636 1032 : CALL_INTERFACE_IF_PARENT_REACHABLE(Catch, c, exception);
1637 : break;
1638 : }
1639 : case kExprBrOnExn: {
1640 432 : CHECK_PROTOTYPE_OPCODE(eh);
1641 432 : BranchDepthImmediate<validate> imm_br(this, this->pc_);
1642 864 : if (!this->Validate(this->pc_, imm_br, control_.size())) break;
1643 : ExceptionIndexImmediate<validate> imm_idx(this,
1644 431 : this->pc_ + imm_br.length);
1645 431 : if (!this->Validate(this->pc_ + imm_br.length, imm_idx)) break;
1646 431 : Control* c = control_at(imm_br.depth);
1647 : auto exception = Pop(0, kWasmExceptRef);
1648 711 : const WasmExceptionSig* sig = imm_idx.exception->sig;
1649 : size_t value_count = sig->parameter_count();
1650 : // TODO(mstarzinger): This operand stack mutation is an ugly hack to
1651 : // make both type checking here as well as environment merging in the
1652 : // graph builder interface work out of the box. We should introduce
1653 : // special handling for both and do minimal/no stack mutation here.
1654 711 : for (size_t i = 0; i < value_count; ++i) Push(sig->GetParam(i));
1655 423 : Vector<Value> values(stack_.data() + c->stack_depth, value_count);
1656 431 : if (!TypeCheckBranch(c)) break;
1657 431 : if (control_.back().reachable()) {
1658 423 : CALL_INTERFACE(BrOnException, exception, imm_idx, imm_br.depth,
1659 : values);
1660 431 : c->br_merge()->reached = true;
1661 : }
1662 431 : len = 1 + imm_br.length + imm_idx.length;
1663 711 : for (size_t i = 0; i < value_count; ++i) Pop();
1664 : auto* pexception = Push(kWasmExceptRef);
1665 431 : *pexception = exception;
1666 431 : break;
1667 : }
1668 : case kExprLoop: {
1669 17955 : BlockTypeImmediate<validate> imm(this->enabled_, this, this->pc_);
1670 17958 : if (!this->Validate(imm)) break;
1671 17960 : PopArgs(imm.sig);
1672 35920 : auto* block = PushControl(kControlLoop);
1673 17961 : SetBlockType(&control_.back(), imm);
1674 17961 : len = 1 + imm.length;
1675 26457 : CALL_INTERFACE_IF_REACHABLE(Loop, block);
1676 35926 : PushMergeValues(block, &block->start_merge);
1677 17958 : break;
1678 : }
1679 : case kExprIf: {
1680 85294 : BlockTypeImmediate<validate> imm(this->enabled_, this, this->pc_);
1681 85295 : if (!this->Validate(imm)) break;
1682 : auto cond = Pop(0, kWasmI32);
1683 85284 : PopArgs(imm.sig);
1684 85283 : if (!VALIDATE(this->ok())) break;
1685 170231 : auto* if_block = PushControl(kControlIf);
1686 85118 : SetBlockType(if_block, imm);
1687 164607 : CALL_INTERFACE_IF_REACHABLE(If, cond, if_block);
1688 85120 : len = 1 + imm.length;
1689 170240 : PushMergeValues(if_block, &if_block->start_merge);
1690 85115 : break;
1691 : }
1692 : case kExprElse: {
1693 24841 : if (!VALIDATE(!control_.empty())) {
1694 0 : this->error("else does not match any if");
1695 0 : break;
1696 : }
1697 51099 : Control* c = &control_.back();
1698 47813 : if (!VALIDATE(c->is_if())) {
1699 0 : this->error(this->pc_, "else does not match an if");
1700 0 : break;
1701 : }
1702 24841 : if (c->is_if_else()) {
1703 2 : this->error(this->pc_, "else already present for if");
1704 2 : break;
1705 : }
1706 24839 : if (!TypeCheckFallThru(c)) break;
1707 24617 : c->kind = kControlIfElse;
1708 45949 : CALL_INTERFACE_IF_PARENT_REACHABLE(Else, c);
1709 24615 : if (c->reachable()) c->end_merge.reached = true;
1710 49230 : PushMergeValues(c, &c->start_merge);
1711 49234 : c->reachability = control_at(1)->innerReachability();
1712 24617 : break;
1713 : }
1714 : case kExprEnd: {
1715 2382588 : if (!VALIDATE(!control_.empty())) {
1716 0 : this->error("end does not match any if, try, or block");
1717 0 : break;
1718 : }
1719 2382588 : Control* c = &control_.back();
1720 2382588 : if (!VALIDATE(!c->is_incomplete_try())) {
1721 1 : this->error(this->pc_, "missing catch or catch-all in try");
1722 1 : break;
1723 : }
1724 2382587 : if (c->is_onearmed_if()) {
1725 59703 : if (!VALIDATE(c->end_merge.arity == c->start_merge.arity)) {
1726 109 : this->error(
1727 : c->pc,
1728 : "start-arity and end-arity of one-armed if must match");
1729 109 : break;
1730 : }
1731 : }
1732 :
1733 2382478 : if (!TypeCheckFallThru(c)) break;
1734 :
1735 2375526 : if (control_.size() == 1) {
1736 : // If at the last (implicit) control, check we are at end.
1737 1897905 : if (!VALIDATE(this->pc_ + 1 == this->end_)) {
1738 2 : this->error(this->pc_ + 1, "trailing code after function end");
1739 2 : break;
1740 : }
1741 : // The result of the block is the return value.
1742 : TRACE_PART("\n" TRACE_INST_FORMAT, startrel(this->pc_),
1743 : "(implicit) return");
1744 1748416 : DoReturn();
1745 : control_.clear();
1746 : break;
1747 : }
1748 :
1749 477621 : PopControl(c);
1750 477627 : break;
1751 : }
1752 : case kExprSelect: {
1753 : auto cond = Pop(2, kWasmI32);
1754 : auto fval = Pop();
1755 1387 : auto tval = Pop(0, fval.type);
1756 4147 : auto* result = Push(tval.type == kWasmVar ? fval.type : tval.type);
1757 5476 : CALL_INTERFACE_IF_REACHABLE(Select, cond, fval, tval, result);
1758 : break;
1759 : }
1760 : case kExprBr: {
1761 36329 : BranchDepthImmediate<validate> imm(this, this->pc_);
1762 72657 : if (!this->Validate(this->pc_, imm, control_.size())) break;
1763 35760 : Control* c = control_at(imm.depth);
1764 35760 : if (!TypeCheckBranch(c)) break;
1765 66876 : if (imm.depth == control_.size() - 1) {
1766 322 : DoReturn();
1767 32905 : } else if (control_.back().reachable()) {
1768 26989 : CALL_INTERFACE(Br, c);
1769 32221 : c->br_merge()->reached = true;
1770 : }
1771 33438 : len = 1 + imm.length;
1772 33438 : EndControl();
1773 33435 : break;
1774 : }
1775 : case kExprBrIf: {
1776 270949 : BranchDepthImmediate<validate> imm(this, this->pc_);
1777 : auto cond = Pop(0, kWasmI32);
1778 270945 : if (this->failed()) break;
1779 541422 : if (!this->Validate(this->pc_, imm, control_.size())) break;
1780 270630 : Control* c = control_at(imm.depth);
1781 270630 : if (!TypeCheckBranch(c)) break;
1782 270384 : if (control_.back().reachable()) {
1783 150665 : CALL_INTERFACE(BrIf, cond, imm.depth);
1784 269659 : c->br_merge()->reached = true;
1785 : }
1786 270389 : len = 1 + imm.length;
1787 270389 : break;
1788 : }
1789 : case kExprBrTable: {
1790 20784 : BranchTableImmediate<validate> imm(this, this->pc_);
1791 : BranchTableIterator<validate> iterator(this, imm);
1792 : auto key = Pop(0, kWasmI32);
1793 20735 : if (this->failed()) break;
1794 20647 : if (!this->Validate(this->pc_, imm, control_.size())) break;
1795 : uint32_t br_arity = 0;
1796 20613 : std::vector<bool> br_targets(control_.size());
1797 778168 : while (iterator.has_next()) {
1798 737296 : const uint32_t i = iterator.cur_index();
1799 737296 : const byte* pos = iterator.pc();
1800 737296 : uint32_t target = iterator.next();
1801 1474688 : if (!VALIDATE(target < control_.size())) {
1802 199 : this->errorf(pos,
1803 : "improper branch in br_table target %u (depth %u)",
1804 : i, target);
1805 199 : break;
1806 : }
1807 : // Avoid redundant branch target checks.
1808 1474290 : if (br_targets[target]) continue;
1809 : br_targets[target] = true;
1810 : // Check that label types match up.
1811 : Control* c = control_at(target);
1812 50106 : uint32_t arity = c->br_merge()->arity;
1813 50106 : if (i == 0) {
1814 : br_arity = arity;
1815 29559 : } else if (!VALIDATE(br_arity == arity)) {
1816 76 : this->errorf(pos,
1817 : "inconsistent arity in br_table target %u"
1818 : " (previous was %u, this one %u)",
1819 : i, br_arity, arity);
1820 : }
1821 50106 : if (!TypeCheckBranch(c)) break;
1822 : }
1823 20661 : if (this->failed()) break;
1824 :
1825 20134 : if (control_.back().reachable()) {
1826 18241 : CALL_INTERFACE(BrTable, imm, key);
1827 :
1828 142892 : for (uint32_t depth = control_depth(); depth-- > 0;) {
1829 207660 : if (!br_targets[depth]) continue;
1830 48930 : control_at(depth)->br_merge()->reached = true;
1831 : }
1832 : }
1833 :
1834 20136 : len = 1 + iterator.length();
1835 20133 : EndControl();
1836 20133 : break;
1837 : }
1838 : case kExprReturn: {
1839 398510 : if (!TypeCheckReturn()) break;
1840 276587 : DoReturn();
1841 398016 : EndControl();
1842 398018 : break;
1843 : }
1844 : case kExprUnreachable: {
1845 249450 : CALL_INTERFACE_IF_REACHABLE(Unreachable);
1846 246959 : EndControl();
1847 246960 : break;
1848 : }
1849 : case kExprI32Const: {
1850 4778354 : ImmI32Immediate<validate> imm(this, this->pc_);
1851 : auto* value = Push(kWasmI32);
1852 9319498 : CALL_INTERFACE_IF_REACHABLE(I32Const, value, imm.value);
1853 4778377 : len = 1 + imm.length;
1854 : break;
1855 : }
1856 : case kExprI64Const: {
1857 108375 : ImmI64Immediate<validate> imm(this, this->pc_);
1858 : auto* value = Push(kWasmI64);
1859 142539 : CALL_INTERFACE_IF_REACHABLE(I64Const, value, imm.value);
1860 108374 : len = 1 + imm.length;
1861 : break;
1862 : }
1863 : case kExprF32Const: {
1864 269470 : ImmF32Immediate<validate> imm(this, this->pc_);
1865 : auto* value = Push(kWasmF32);
1866 274898 : CALL_INTERFACE_IF_REACHABLE(F32Const, value, imm.value);
1867 269472 : len = 1 + imm.length;
1868 : break;
1869 : }
1870 : case kExprF64Const: {
1871 277863 : ImmF64Immediate<validate> imm(this, this->pc_);
1872 : auto* value = Push(kWasmF64);
1873 291934 : CALL_INTERFACE_IF_REACHABLE(F64Const, value, imm.value);
1874 277865 : len = 1 + imm.length;
1875 : break;
1876 : }
1877 : case kExprRefNull: {
1878 83 : CHECK_PROTOTYPE_OPCODE(anyref);
1879 : auto* value = Push(kWasmAnyRef);
1880 164 : CALL_INTERFACE_IF_REACHABLE(RefNull, value);
1881 : len = 1;
1882 : break;
1883 : }
1884 : case kExprGetLocal: {
1885 1205988 : LocalIndexImmediate<validate> imm(this, this->pc_);
1886 1205999 : if (!this->Validate(this->pc_, imm)) break;
1887 1205630 : auto* value = Push(imm.type);
1888 2288883 : CALL_INTERFACE_IF_REACHABLE(GetLocal, value, imm);
1889 1205629 : len = 1 + imm.length;
1890 1205629 : break;
1891 : }
1892 : case kExprSetLocal: {
1893 618230 : LocalIndexImmediate<validate> imm(this, this->pc_);
1894 618239 : if (!this->Validate(this->pc_, imm)) break;
1895 1354313 : auto value = Pop(0, local_type_vec_[imm.index]);
1896 1211107 : CALL_INTERFACE_IF_REACHABLE(SetLocal, value, imm);
1897 618055 : len = 1 + imm.length;
1898 618055 : break;
1899 : }
1900 : case kExprTeeLocal: {
1901 118185 : LocalIndexImmediate<validate> imm(this, this->pc_);
1902 118184 : if (!this->Validate(this->pc_, imm)) break;
1903 236366 : auto value = Pop(0, local_type_vec_[imm.index]);
1904 : auto* result = Push(value.type);
1905 233817 : CALL_INTERFACE_IF_REACHABLE(TeeLocal, value, result, imm);
1906 118185 : len = 1 + imm.length;
1907 118185 : break;
1908 : }
1909 : case kExprDrop: {
1910 : auto value = Pop();
1911 7488 : CALL_INTERFACE_IF_REACHABLE(Drop, value);
1912 : break;
1913 : }
1914 : case kExprGetGlobal: {
1915 65709 : GlobalIndexImmediate<validate> imm(this, this->pc_);
1916 65709 : len = 1 + imm.length;
1917 65709 : if (!this->Validate(this->pc_, imm)) break;
1918 65682 : auto* result = Push(imm.type);
1919 130216 : CALL_INTERFACE_IF_REACHABLE(GetGlobal, result, imm);
1920 : break;
1921 : }
1922 : case kExprSetGlobal: {
1923 23542 : GlobalIndexImmediate<validate> imm(this, this->pc_);
1924 23542 : len = 1 + imm.length;
1925 23542 : if (!this->Validate(this->pc_, imm)) break;
1926 23542 : if (!VALIDATE(imm.global->mutability)) {
1927 28 : this->errorf(this->pc_, "immutable global #%u cannot be assigned",
1928 : imm.index);
1929 28 : break;
1930 : }
1931 23514 : auto value = Pop(0, imm.type);
1932 46542 : CALL_INTERFACE_IF_REACHABLE(SetGlobal, value, imm);
1933 : break;
1934 : }
1935 : case kExprI32LoadMem8S:
1936 3640 : len = 1 + DecodeLoadMem(LoadType::kI32Load8S);
1937 3640 : break;
1938 : case kExprI32LoadMem8U:
1939 2301 : len = 1 + DecodeLoadMem(LoadType::kI32Load8U);
1940 2301 : break;
1941 : case kExprI32LoadMem16S:
1942 547 : len = 1 + DecodeLoadMem(LoadType::kI32Load16S);
1943 547 : break;
1944 : case kExprI32LoadMem16U:
1945 904 : len = 1 + DecodeLoadMem(LoadType::kI32Load16U);
1946 904 : break;
1947 : case kExprI32LoadMem:
1948 147299 : len = 1 + DecodeLoadMem(LoadType::kI32Load);
1949 147299 : break;
1950 : case kExprI64LoadMem8S:
1951 566 : len = 1 + DecodeLoadMem(LoadType::kI64Load8S);
1952 566 : break;
1953 : case kExprI64LoadMem8U:
1954 434 : len = 1 + DecodeLoadMem(LoadType::kI64Load8U);
1955 434 : break;
1956 : case kExprI64LoadMem16S:
1957 512 : len = 1 + DecodeLoadMem(LoadType::kI64Load16S);
1958 512 : break;
1959 : case kExprI64LoadMem16U:
1960 488 : len = 1 + DecodeLoadMem(LoadType::kI64Load16U);
1961 488 : break;
1962 : case kExprI64LoadMem32S:
1963 539 : len = 1 + DecodeLoadMem(LoadType::kI64Load32S);
1964 539 : break;
1965 : case kExprI64LoadMem32U:
1966 515 : len = 1 + DecodeLoadMem(LoadType::kI64Load32U);
1967 515 : break;
1968 : case kExprI64LoadMem:
1969 149007 : len = 1 + DecodeLoadMem(LoadType::kI64Load);
1970 149007 : break;
1971 : case kExprF32LoadMem:
1972 4582 : len = 1 + DecodeLoadMem(LoadType::kF32Load);
1973 4580 : break;
1974 : case kExprF64LoadMem:
1975 5906 : len = 1 + DecodeLoadMem(LoadType::kF64Load);
1976 5907 : break;
1977 : case kExprI32StoreMem8:
1978 2736 : len = 1 + DecodeStoreMem(StoreType::kI32Store8);
1979 2736 : break;
1980 : case kExprI32StoreMem16:
1981 985 : len = 1 + DecodeStoreMem(StoreType::kI32Store16);
1982 985 : break;
1983 : case kExprI32StoreMem:
1984 226358 : len = 1 + DecodeStoreMem(StoreType::kI32Store);
1985 226345 : break;
1986 : case kExprI64StoreMem8:
1987 366 : len = 1 + DecodeStoreMem(StoreType::kI64Store8);
1988 366 : break;
1989 : case kExprI64StoreMem16:
1990 546 : len = 1 + DecodeStoreMem(StoreType::kI64Store16);
1991 546 : break;
1992 : case kExprI64StoreMem32:
1993 492 : len = 1 + DecodeStoreMem(StoreType::kI64Store32);
1994 492 : break;
1995 : case kExprI64StoreMem:
1996 170212 : len = 1 + DecodeStoreMem(StoreType::kI64Store);
1997 170216 : break;
1998 : case kExprF32StoreMem:
1999 1015 : len = 1 + DecodeStoreMem(StoreType::kF32Store);
2000 1015 : break;
2001 : case kExprF64StoreMem:
2002 2083 : len = 1 + DecodeStoreMem(StoreType::kF64Store);
2003 2083 : break;
2004 : case kExprMemoryGrow: {
2005 3585 : if (!CheckHasMemory()) break;
2006 3540 : MemoryIndexImmediate<validate> imm(this, this->pc_);
2007 3540 : len = 1 + imm.length;
2008 : DCHECK_NOT_NULL(this->module_);
2009 3540 : if (!VALIDATE(this->module_->origin == kWasmOrigin)) {
2010 1 : this->error("grow_memory is not supported for asmjs modules");
2011 1 : break;
2012 : }
2013 : auto value = Pop(0, kWasmI32);
2014 : auto* result = Push(kWasmI32);
2015 6915 : CALL_INTERFACE_IF_REACHABLE(MemoryGrow, value, result);
2016 : break;
2017 : }
2018 : case kExprMemorySize: {
2019 1196 : if (!CheckHasMemory()) break;
2020 1169 : MemoryIndexImmediate<validate> imm(this, this->pc_);
2021 : auto* result = Push(kWasmI32);
2022 1169 : len = 1 + imm.length;
2023 2185 : CALL_INTERFACE_IF_REACHABLE(CurrentMemoryPages, result);
2024 : break;
2025 : }
2026 : case kExprCallFunction: {
2027 301697 : CallFunctionImmediate<validate> imm(this, this->pc_);
2028 301690 : len = 1 + imm.length;
2029 301690 : if (!this->Validate(this->pc_, imm)) break;
2030 : // TODO(clemensh): Better memory management.
2031 301623 : PopArgs(imm.sig);
2032 301624 : auto* returns = PushReturns(imm.sig);
2033 382715 : CALL_INTERFACE_IF_REACHABLE(CallDirect, imm, args_.data(), returns);
2034 : break;
2035 : }
2036 : case kExprCallIndirect: {
2037 9741 : CallIndirectImmediate<validate> imm(this, this->pc_);
2038 9740 : len = 1 + imm.length;
2039 9740 : if (!this->Validate(this->pc_, imm)) break;
2040 : auto index = Pop(0, kWasmI32);
2041 9643 : PopArgs(imm.sig);
2042 9641 : auto* returns = PushReturns(imm.sig);
2043 19037 : CALL_INTERFACE_IF_REACHABLE(CallIndirect, index, imm, args_.data(),
2044 : returns);
2045 : break;
2046 : }
2047 : case kNumericPrefix: {
2048 : ++len;
2049 : byte numeric_index =
2050 599 : this->template read_u8<validate>(this->pc_ + 1, "numeric index");
2051 599 : opcode = static_cast<WasmOpcode>(opcode << 8 | numeric_index);
2052 599 : if (opcode < kExprMemoryInit) {
2053 162 : CHECK_PROTOTYPE_OPCODE(sat_f2i_conversions);
2054 : } else {
2055 437 : CHECK_PROTOTYPE_OPCODE(bulk_memory);
2056 : }
2057 : TRACE_PART(TRACE_INST_FORMAT, startrel(this->pc_),
2058 : WasmOpcodes::OpcodeName(opcode));
2059 590 : len += DecodeNumericOpcode(opcode);
2060 590 : break;
2061 : }
2062 : case kSimdPrefix: {
2063 78761 : CHECK_PROTOTYPE_OPCODE(simd);
2064 : len++;
2065 : byte simd_index =
2066 78761 : this->template read_u8<validate>(this->pc_ + 1, "simd index");
2067 78761 : opcode = static_cast<WasmOpcode>(opcode << 8 | simd_index);
2068 : TRACE_PART(TRACE_INST_FORMAT, startrel(this->pc_),
2069 : WasmOpcodes::OpcodeName(opcode));
2070 78761 : len += DecodeSimdOpcode(opcode);
2071 78761 : break;
2072 : }
2073 : case kAtomicPrefix: {
2074 48560 : CHECK_PROTOTYPE_OPCODE(threads);
2075 48560 : if (!CheckHasSharedMemory()) break;
2076 : len++;
2077 : byte atomic_index =
2078 48556 : this->template read_u8<validate>(this->pc_ + 1, "atomic index");
2079 48555 : opcode = static_cast<WasmOpcode>(opcode << 8 | atomic_index);
2080 : TRACE_PART(TRACE_INST_FORMAT, startrel(this->pc_),
2081 : WasmOpcodes::OpcodeName(opcode));
2082 48555 : len += DecodeAtomicOpcode(opcode);
2083 48580 : break;
2084 : }
2085 : // Note that prototype opcodes are not handled in the fastpath
2086 : // above this switch, to avoid checking a feature flag.
2087 : #define SIMPLE_PROTOTYPE_CASE(name, opc, sig) \
2088 : case kExpr##name: /* fallthrough */
2089 : FOREACH_SIMPLE_PROTOTYPE_OPCODE(SIMPLE_PROTOTYPE_CASE)
2090 : #undef SIMPLE_PROTOTYPE_CASE
2091 129 : BuildSimplePrototypeOperator(opcode);
2092 129 : break;
2093 : default: {
2094 : // Deal with special asmjs opcodes.
2095 117444 : if (this->module_ != nullptr &&
2096 : this->module_->origin == kAsmJsOrigin) {
2097 117413 : FunctionSig* sig = WasmOpcodes::AsmjsSignature(opcode);
2098 117413 : if (sig) {
2099 117413 : BuildSimpleOperator(opcode, sig);
2100 : }
2101 : } else {
2102 31 : this->error("Invalid opcode");
2103 1953967 : return;
2104 : }
2105 : }
2106 : }
2107 :
2108 : #if DEBUG
2109 : if (FLAG_trace_wasm_decoder) {
2110 : TRACE_PART(" ");
2111 : for (Control& c : control_) {
2112 : switch (c.kind) {
2113 : case kControlIf:
2114 : TRACE_PART("I");
2115 : break;
2116 : case kControlBlock:
2117 : TRACE_PART("B");
2118 : break;
2119 : case kControlLoop:
2120 : TRACE_PART("L");
2121 : break;
2122 : case kControlTry:
2123 : TRACE_PART("T");
2124 : break;
2125 : default:
2126 : break;
2127 : }
2128 : if (c.start_merge.arity) TRACE_PART("%u-", c.start_merge.arity);
2129 : TRACE_PART("%u", c.end_merge.arity);
2130 : if (!c.reachable()) TRACE_PART("%c", c.unreachable() ? '*' : '#');
2131 : }
2132 : TRACE_PART(" | ");
2133 : for (size_t i = 0; i < stack_.size(); ++i) {
2134 : auto& val = stack_[i];
2135 : WasmOpcode opcode = static_cast<WasmOpcode>(*val.pc);
2136 : if (WasmOpcodes::IsPrefixOpcode(opcode)) {
2137 : opcode = static_cast<WasmOpcode>(opcode << 8 | *(val.pc + 1));
2138 : }
2139 : TRACE_PART(" %c@%d:%s", ValueTypes::ShortNameOf(val.type),
2140 : static_cast<int>(val.pc - this->start_),
2141 : WasmOpcodes::OpcodeName(opcode));
2142 : // If the decoder failed, don't try to decode the immediates, as this
2143 : // can trigger a DCHECK failure.
2144 : if (this->failed()) continue;
2145 : switch (opcode) {
2146 : case kExprI32Const: {
2147 : ImmI32Immediate<Decoder::kNoValidate> imm(this, val.pc);
2148 : TRACE_PART("[%d]", imm.value);
2149 : break;
2150 : }
2151 : case kExprGetLocal:
2152 : case kExprSetLocal:
2153 : case kExprTeeLocal: {
2154 : LocalIndexImmediate<Decoder::kNoValidate> imm(this, val.pc);
2155 : TRACE_PART("[%u]", imm.index);
2156 : break;
2157 : }
2158 : case kExprGetGlobal:
2159 : case kExprSetGlobal: {
2160 : GlobalIndexImmediate<Decoder::kNoValidate> imm(this, val.pc);
2161 : TRACE_PART("[%u]", imm.index);
2162 : break;
2163 : }
2164 : default:
2165 : break;
2166 : }
2167 : }
2168 : }
2169 : #endif
2170 16980913 : this->pc_ += len;
2171 : } // end decode loop
2172 2010117 : if (!VALIDATE(this->pc_ == this->end_) && this->ok()) {
2173 0 : this->error("Beyond end of code");
2174 : }
2175 : }
2176 :
2177 699709 : void EndControl() {
2178 : DCHECK(!control_.empty());
2179 : auto* current = &control_.back();
2180 1399418 : stack_.erase(stack_.begin() + current->stack_depth, stack_.end());
2181 353733 : CALL_INTERFACE_IF_REACHABLE(EndControl, current);
2182 699714 : current->reachability = kUnreachable;
2183 699714 : }
2184 :
2185 : template<typename func>
2186 4886665 : void InitMerge(Merge<Value>* merge, uint32_t arity, func get_val) {
2187 4886665 : merge->arity = arity;
2188 4886665 : if (arity == 1) {
2189 1680681 : merge->vals.first = get_val(0);
2190 3205984 : } else if (arity > 1) {
2191 8500 : merge->vals.array = zone_->NewArray<Value>(arity);
2192 9825 : for (uint32_t i = 0; i < arity; i++) {
2193 17062 : merge->vals.array[i] = get_val(i);
2194 : }
2195 : }
2196 4886665 : }
2197 :
2198 1467993 : void SetBlockType(Control* c, BlockTypeImmediate<validate>& imm) {
2199 : DCHECK_EQ(imm.in_arity(), this->args_.size());
2200 489331 : const byte* pc = this->pc_;
2201 : Value* args = this->args_.data();
2202 978662 : InitMerge(&c->end_merge, imm.out_arity(), [pc, &imm](uint32_t i) {
2203 : return Value{pc, imm.out_type(i)};
2204 522117 : });
2205 978662 : InitMerge(&c->start_merge, imm.in_arity(),
2206 489545 : [args](uint32_t i) { return args[i]; });
2207 489332 : }
2208 :
2209 : // Pops arguments as required by signature into {args_}.
2210 357654 : V8_INLINE void PopArgs(FunctionSig* sig) {
2211 987879 : int count = sig ? static_cast<int>(sig->parameter_count()) : 0;
2212 857826 : args_.resize(count, UnreachableValue(nullptr));
2213 1591777 : for (int i = count - 1; i >= 0; --i) {
2214 1695529 : args_[i] = Pop(i, sig->GetParam(i));
2215 : }
2216 : }
2217 :
2218 177235 : ValueType GetReturnType(FunctionSig* sig) {
2219 : DCHECK_GE(1, sig->return_count());
2220 92457 : return sig->return_count() == 0 ? kWasmStmt : sig->GetReturn();
2221 : }
2222 :
2223 2443356 : Control* PushControl(ControlKind kind) {
2224 : Reachability reachability =
2225 4886712 : control_.empty() ? kReachable : control_.back().innerReachability();
2226 4886712 : control_.emplace_back(kind, stack_size(), this->pc_, reachability);
2227 2443370 : return &control_.back();
2228 : }
2229 :
2230 1079704 : void PopControl(Control* c) {
2231 : DCHECK_EQ(c, &control_.back());
2232 687268 : CALL_INTERFACE_IF_PARENT_REACHABLE(PopControl, c);
2233 :
2234 : // A loop just leaves the values on the stack.
2235 1037110 : if (!c->is_loop()) PushMergeValues(c, &c->end_merge);
2236 :
2237 : bool parent_reached =
2238 581623 : c->reachable() || c->end_merge.reached || c->is_onearmed_if();
2239 : control_.pop_back();
2240 : // If the parent block was reachable before, but the popped control does not
2241 : // return to here, this block becomes "spec only reachable".
2242 493418 : if (!parent_reached && control_.back().reachable()) {
2243 56451 : control_.back().reachability = kSpecOnlyReachable;
2244 : }
2245 477628 : }
2246 :
2247 317257 : int DecodeLoadMem(LoadType type, int prefix_len = 0) {
2248 317257 : if (!CheckHasMemory()) return 0;
2249 : MemoryAccessImmediate<validate> imm(this, this->pc_ + prefix_len,
2250 317203 : type.size_log_2());
2251 : auto index = Pop(0, kWasmI32);
2252 : auto* result = Push(type.value_type());
2253 607431 : CALL_INTERFACE_IF_REACHABLE(LoadMem, type, imm, index, result);
2254 317203 : return imm.length;
2255 : }
2256 :
2257 404794 : int DecodeStoreMem(StoreType store, int prefix_len = 0) {
2258 404794 : if (!CheckHasMemory()) return 0;
2259 : MemoryAccessImmediate<validate> imm(this, this->pc_ + prefix_len,
2260 404750 : store.size_log_2());
2261 : auto value = Pop(1, store.value_type());
2262 : auto index = Pop(0, kWasmI32);
2263 785072 : CALL_INTERFACE_IF_REACHABLE(StoreMem, store, imm, index, value);
2264 404750 : return imm.length;
2265 : }
2266 :
2267 34130 : uint32_t SimdExtractLane(WasmOpcode opcode, ValueType type) {
2268 34130 : SimdLaneImmediate<validate> imm(this, this->pc_);
2269 34130 : if (this->Validate(this->pc_, opcode, imm)) {
2270 0 : Value inputs[] = {Pop(0, kWasmS128)};
2271 : auto* result = Push(type);
2272 68260 : CALL_INTERFACE_IF_REACHABLE(SimdLaneOp, opcode, imm, ArrayVector(inputs),
2273 : result);
2274 : }
2275 34130 : return imm.length;
2276 : }
2277 :
2278 750 : uint32_t SimdReplaceLane(WasmOpcode opcode, ValueType type) {
2279 750 : SimdLaneImmediate<validate> imm(this, this->pc_);
2280 750 : if (this->Validate(this->pc_, opcode, imm)) {
2281 750 : Value inputs[2] = {UnreachableValue(this->pc_),
2282 0 : UnreachableValue(this->pc_)};
2283 750 : inputs[1] = Pop(1, type);
2284 750 : inputs[0] = Pop(0, kWasmS128);
2285 : auto* result = Push(kWasmS128);
2286 1500 : CALL_INTERFACE_IF_REACHABLE(SimdLaneOp, opcode, imm, ArrayVector(inputs),
2287 : result);
2288 : }
2289 750 : return imm.length;
2290 : }
2291 :
2292 2385 : uint32_t SimdShiftOp(WasmOpcode opcode) {
2293 2385 : SimdShiftImmediate<validate> imm(this, this->pc_);
2294 2385 : if (this->Validate(this->pc_, opcode, imm)) {
2295 : auto input = Pop(0, kWasmS128);
2296 : auto* result = Push(kWasmS128);
2297 4770 : CALL_INTERFACE_IF_REACHABLE(SimdShiftOp, opcode, imm, input, result);
2298 : }
2299 2385 : return imm.length;
2300 : }
2301 :
2302 33781 : uint32_t Simd8x16ShuffleOp() {
2303 33781 : Simd8x16ShuffleImmediate<validate> imm(this, this->pc_);
2304 33781 : if (this->Validate(this->pc_, imm)) {
2305 : auto input1 = Pop(1, kWasmS128);
2306 : auto input0 = Pop(0, kWasmS128);
2307 : auto* result = Push(kWasmS128);
2308 67560 : CALL_INTERFACE_IF_REACHABLE(Simd8x16ShuffleOp, imm, input0, input1,
2309 : result);
2310 : }
2311 33781 : return 16;
2312 : }
2313 :
2314 78761 : uint32_t DecodeSimdOpcode(WasmOpcode opcode) {
2315 : uint32_t len = 0;
2316 78761 : switch (opcode) {
2317 : case kExprF32x4ExtractLane: {
2318 1280 : len = SimdExtractLane(opcode, kWasmF32);
2319 1280 : break;
2320 : }
2321 : case kExprI32x4ExtractLane:
2322 : case kExprI16x8ExtractLane:
2323 : case kExprI8x16ExtractLane: {
2324 32850 : len = SimdExtractLane(opcode, kWasmI32);
2325 32850 : break;
2326 : }
2327 : case kExprF32x4ReplaceLane: {
2328 120 : len = SimdReplaceLane(opcode, kWasmF32);
2329 120 : break;
2330 : }
2331 : case kExprI32x4ReplaceLane:
2332 : case kExprI16x8ReplaceLane:
2333 : case kExprI8x16ReplaceLane: {
2334 630 : len = SimdReplaceLane(opcode, kWasmI32);
2335 630 : break;
2336 : }
2337 : case kExprI32x4Shl:
2338 : case kExprI32x4ShrS:
2339 : case kExprI32x4ShrU:
2340 : case kExprI16x8Shl:
2341 : case kExprI16x8ShrS:
2342 : case kExprI16x8ShrU:
2343 : case kExprI8x16Shl:
2344 : case kExprI8x16ShrS:
2345 : case kExprI8x16ShrU: {
2346 2385 : len = SimdShiftOp(opcode);
2347 2385 : break;
2348 : }
2349 : case kExprS8x16Shuffle: {
2350 33781 : len = Simd8x16ShuffleOp();
2351 33781 : break;
2352 : }
2353 : case kExprS128LoadMem:
2354 20 : len = DecodeLoadMem(LoadType::kS128Load, 1);
2355 20 : break;
2356 : case kExprS128StoreMem:
2357 10 : len = DecodeStoreMem(StoreType::kS128Store, 1);
2358 10 : break;
2359 : default: {
2360 15370 : FunctionSig* sig = WasmOpcodes::Signature(opcode);
2361 7685 : if (!VALIDATE(sig != nullptr)) {
2362 0 : this->error("invalid simd opcode");
2363 0 : break;
2364 : }
2365 : PopArgs(sig);
2366 : auto* results =
2367 15370 : sig->return_count() == 0 ? nullptr : Push(GetReturnType(sig));
2368 23055 : CALL_INTERFACE_IF_REACHABLE(SimdOp, opcode, VectorOf(args_), results);
2369 : }
2370 : }
2371 78761 : return len;
2372 : }
2373 :
2374 48553 : uint32_t DecodeAtomicOpcode(WasmOpcode opcode) {
2375 : uint32_t len = 0;
2376 : ValueType ret_type;
2377 48553 : FunctionSig* sig = WasmOpcodes::Signature(opcode);
2378 48552 : if (sig != nullptr) {
2379 : MachineType memtype;
2380 48552 : switch (opcode) {
2381 : #define CASE_ATOMIC_STORE_OP(Name, Type) \
2382 : case kExpr##Name: { \
2383 : memtype = MachineType::Type(); \
2384 : ret_type = kWasmStmt; \
2385 : break; \
2386 : }
2387 454 : ATOMIC_STORE_OP_LIST(CASE_ATOMIC_STORE_OP)
2388 : #undef CASE_ATOMIC_OP
2389 : #define CASE_ATOMIC_OP(Name, Type) \
2390 : case kExpr##Name: { \
2391 : memtype = MachineType::Type(); \
2392 : ret_type = GetReturnType(sig); \
2393 : break; \
2394 : }
2395 42396 : ATOMIC_OP_LIST(CASE_ATOMIC_OP)
2396 : #undef CASE_ATOMIC_OP
2397 : default:
2398 0 : this->error("invalid atomic opcode");
2399 0 : return 0;
2400 : }
2401 : MemoryAccessImmediate<validate> imm(
2402 48552 : this, this->pc_ + 1, ElementSizeLog2Of(memtype.representation()));
2403 48556 : len += imm.length;
2404 : PopArgs(sig);
2405 77836 : auto result = ret_type == kWasmStmt ? nullptr : Push(GetReturnType(sig));
2406 130710 : CALL_INTERFACE_IF_REACHABLE(AtomicOp, opcode, VectorOf(args_), imm,
2407 : result);
2408 : } else {
2409 0 : this->error("invalid atomic opcode");
2410 : }
2411 48584 : return len;
2412 : }
2413 :
2414 590 : unsigned DecodeNumericOpcode(WasmOpcode opcode) {
2415 : unsigned len = 0;
2416 1178 : FunctionSig* sig = WasmOpcodes::Signature(opcode);
2417 590 : if (sig != nullptr) {
2418 590 : switch (opcode) {
2419 : case kExprI32SConvertSatF32:
2420 : case kExprI32UConvertSatF32:
2421 : case kExprI32SConvertSatF64:
2422 : case kExprI32UConvertSatF64:
2423 : case kExprI64SConvertSatF32:
2424 : case kExprI64UConvertSatF32:
2425 : case kExprI64SConvertSatF64:
2426 : case kExprI64UConvertSatF64:
2427 160 : BuildSimpleOperator(opcode, sig);
2428 160 : break;
2429 : case kExprMemoryInit: {
2430 87 : MemoryInitImmediate<validate> imm(this, this->pc_);
2431 87 : if (!this->Validate(imm)) break;
2432 86 : len += imm.length;
2433 : auto size = Pop(2, sig->GetParam(2));
2434 : auto src = Pop(1, sig->GetParam(1));
2435 : auto dst = Pop(0, sig->GetParam(0));
2436 170 : CALL_INTERFACE_IF_REACHABLE(MemoryInit, imm, dst, src, size);
2437 : break;
2438 : }
2439 : case kExprMemoryDrop: {
2440 47 : MemoryDropImmediate<validate> imm(this, this->pc_);
2441 47 : if (!this->Validate(imm)) break;
2442 46 : len += imm.length;
2443 92 : CALL_INTERFACE_IF_REACHABLE(MemoryDrop, imm);
2444 : break;
2445 : }
2446 : case kExprMemoryCopy: {
2447 56 : MemoryIndexImmediate<validate> imm(this, this->pc_ + 1);
2448 56 : if (!this->Validate(imm)) break;
2449 55 : len += imm.length;
2450 : auto size = Pop(2, sig->GetParam(2));
2451 : auto src = Pop(1, sig->GetParam(1));
2452 : auto dst = Pop(0, sig->GetParam(0));
2453 110 : CALL_INTERFACE_IF_REACHABLE(MemoryCopy, imm, dst, src, size);
2454 : break;
2455 : }
2456 : case kExprMemoryFill: {
2457 56 : MemoryIndexImmediate<validate> imm(this, this->pc_ + 1);
2458 56 : if (!this->Validate(imm)) break;
2459 55 : len += imm.length;
2460 : auto size = Pop(2, sig->GetParam(2));
2461 : auto value = Pop(1, sig->GetParam(1));
2462 : auto dst = Pop(0, sig->GetParam(0));
2463 110 : CALL_INTERFACE_IF_REACHABLE(MemoryFill, imm, dst, value, size);
2464 : break;
2465 : }
2466 : case kExprTableInit: {
2467 26 : TableInitImmediate<validate> imm(this, this->pc_);
2468 26 : if (!this->Validate(imm)) break;
2469 23 : len += imm.length;
2470 : PopArgs(sig);
2471 53 : CALL_INTERFACE_IF_REACHABLE(TableInit, imm, VectorOf(args_));
2472 : break;
2473 : }
2474 : case kExprTableDrop: {
2475 39 : TableDropImmediate<validate> imm(this, this->pc_);
2476 39 : if (!this->Validate(imm)) break;
2477 37 : len += imm.length;
2478 74 : CALL_INTERFACE_IF_REACHABLE(TableDrop, imm);
2479 : break;
2480 : }
2481 : case kExprTableCopy: {
2482 119 : TableIndexImmediate<validate> imm(this, this->pc_ + 1);
2483 119 : if (!this->Validate(this->pc_ + 1, imm)) break;
2484 118 : len += imm.length;
2485 : PopArgs(sig);
2486 308 : CALL_INTERFACE_IF_REACHABLE(TableCopy, imm, VectorOf(args_));
2487 : break;
2488 : }
2489 : default:
2490 0 : this->error("invalid numeric opcode");
2491 0 : break;
2492 : }
2493 : } else {
2494 0 : this->error("invalid numeric opcode");
2495 : }
2496 590 : return len;
2497 : }
2498 :
2499 2025314 : void DoReturn() {
2500 1194742 : size_t return_count = this->sig_->return_count();
2501 : DCHECK_GE(stack_.size(), return_count);
2502 : Vector<Value> return_values =
2503 : return_count == 0
2504 : ? Vector<Value>{}
2505 1194742 : : Vector<Value>{&*(stack_.end() - return_count), return_count};
2506 :
2507 4050695 : CALL_INTERFACE_IF_REACHABLE(DoReturn, return_values);
2508 2025270 : }
2509 :
2510 : inline Value* Push(ValueType type) {
2511 : DCHECK_NE(kWasmStmt, type);
2512 10592249 : stack_.emplace_back(this->pc_, type);
2513 : return &stack_.back();
2514 : }
2515 :
2516 975721 : void PushMergeValues(Control* c, Merge<Value>* merge) {
2517 : DCHECK_EQ(c, &control_.back());
2518 : DCHECK(merge == &c->start_merge || merge == &c->end_merge);
2519 1951442 : stack_.erase(stack_.begin() + c->stack_depth, stack_.end());
2520 975731 : if (merge->arity == 1) {
2521 23889 : stack_.push_back(merge->vals.first);
2522 : } else {
2523 372 : for (uint32_t i = 0; i < merge->arity; i++) {
2524 372 : stack_.push_back(merge->vals.array[i]);
2525 : }
2526 : }
2527 : DCHECK_EQ(c->stack_depth + merge->arity, stack_.size());
2528 975731 : }
2529 :
2530 594258 : Value* PushReturns(FunctionSig* sig) {
2531 : size_t return_count = sig->return_count();
2532 311266 : if (return_count == 0) return nullptr;
2533 278968 : size_t old_size = stack_.size();
2534 561957 : for (size_t i = 0; i < return_count; ++i) {
2535 : Push(sig->GetReturn(i));
2536 : }
2537 278965 : return stack_.data() + old_size;
2538 : }
2539 :
2540 : V8_INLINE Value Pop(int index, ValueType expected) {
2541 : auto val = Pop();
2542 8581607 : if (!VALIDATE(val.type == expected || val.type == kWasmVar ||
2543 : expected == kWasmVar)) {
2544 34278 : this->errorf(val.pc, "%s[%d] expected type %s, found %s of type %s",
2545 : SafeOpcodeNameAt(this->pc_), index,
2546 : ValueTypes::TypeName(expected), SafeOpcodeNameAt(val.pc),
2547 : ValueTypes::TypeName(val.type));
2548 : }
2549 : return val;
2550 : }
2551 :
2552 : V8_INLINE Value Pop() {
2553 : DCHECK(!control_.empty());
2554 8795041 : uint32_t limit = control_.back().stack_depth;
2555 8795057 : if (stack_.size() <= limit) {
2556 : // Popping past the current control start in reachable code.
2557 11976 : if (!VALIDATE(control_.back().unreachable())) {
2558 2716 : this->errorf(this->pc_, "%s found empty stack",
2559 : SafeOpcodeNameAt(this->pc_));
2560 : }
2561 11976 : return UnreachableValue(this->pc_);
2562 : }
2563 8783052 : auto val = stack_.back();
2564 8783043 : stack_.pop_back();
2565 3734457 : return val;
2566 : }
2567 :
2568 5341 : int startrel(const byte* ptr) { return static_cast<int>(ptr - this->start_); }
2569 :
2570 527 : void FallThruTo(Control* c) {
2571 : DCHECK_EQ(c, &control_.back());
2572 515 : if (!TypeCheckFallThru(c)) return;
2573 516 : if (!c->reachable()) return;
2574 :
2575 279 : if (!c->is_loop()) CALL_INTERFACE(FallThruTo, c);
2576 291 : c->end_merge.reached = true;
2577 : }
2578 :
2579 1670798 : bool TypeCheckMergeValues(Control* c, Merge<Value>* merge) {
2580 : DCHECK(merge == &c->start_merge || merge == &c->end_merge);
2581 : DCHECK_GE(stack_.size(), c->stack_depth + merge->arity);
2582 : // The computation of {stack_values} is only valid if {merge->arity} is >0.
2583 : DCHECK_LT(0, merge->arity);
2584 1670798 : Value* stack_values = &*(stack_.end() - merge->arity);
2585 : // Typecheck the topmost {merge->arity} values on the stack.
2586 1708678 : for (uint32_t i = 0; i < merge->arity; ++i) {
2587 1674572 : Value& val = stack_values[i];
2588 : Value& old = (*merge)[i];
2589 1674572 : if (val.type == old.type) continue;
2590 : // If {val.type} is polymorphic, which results from unreachable, make
2591 : // it more specific by using the merge value's expected type.
2592 : // If it is not polymorphic, this is a type error.
2593 30945 : if (!VALIDATE(val.type == kWasmVar)) {
2594 4602 : this->errorf(this->pc_, "type error in merge[%u] (expected %s, got %s)",
2595 : i, ValueTypes::TypeName(old.type),
2596 : ValueTypes::TypeName(val.type));
2597 2611 : return false;
2598 : }
2599 26343 : val.type = old.type;
2600 : }
2601 :
2602 : return true;
2603 : }
2604 :
2605 2411693 : bool TypeCheckFallThru(Control* c) {
2606 : DCHECK_EQ(c, &control_.back());
2607 : if (!validate) return true;
2608 2407742 : uint32_t expected = c->end_merge.arity;
2609 : DCHECK_GE(stack_.size(), c->stack_depth);
2610 4815484 : uint32_t actual = static_cast<uint32_t>(stack_.size()) - c->stack_depth;
2611 : // Fallthrus must match the arity of the control exactly.
2612 2407742 : if (!InsertUnreachablesIfNecessary(expected, actual) || actual > expected) {
2613 7902 : this->errorf(
2614 : this->pc_,
2615 : "expected %u elements on the stack for fallthru to @%d, found %u",
2616 : expected, startrel(c->pc), actual);
2617 3951 : return false;
2618 : }
2619 2404011 : if (expected == 0) return true; // Fast path.
2620 :
2621 1657588 : return TypeCheckMergeValues(c, &c->end_merge);
2622 : }
2623 :
2624 358311 : bool TypeCheckBranch(Control* c) {
2625 : // Branches must have at least the number of values expected; can have more.
2626 356921 : uint32_t expected = c->br_merge()->arity;
2627 356921 : if (expected == 0) return true; // Fast path.
2628 : DCHECK_GE(stack_.size(), control_.back().stack_depth);
2629 : uint32_t actual =
2630 43947 : static_cast<uint32_t>(stack_.size()) - control_.back().stack_depth;
2631 14649 : if (!InsertUnreachablesIfNecessary(expected, actual)) {
2632 2780 : this->errorf(this->pc_,
2633 : "expected %u elements on the stack for br to @%d, found %u",
2634 : expected, startrel(c->pc), actual);
2635 1390 : return false;
2636 : }
2637 13259 : return TypeCheckMergeValues(c, c->br_merge());
2638 : }
2639 :
2640 398510 : bool TypeCheckReturn() {
2641 : // Returns must have at least the number of values expected; can have more.
2642 538710 : uint32_t num_returns = static_cast<uint32_t>(this->sig_->return_count());
2643 : DCHECK_GE(stack_.size(), control_.back().stack_depth);
2644 : uint32_t actual =
2645 1195530 : static_cast<uint32_t>(stack_.size()) - control_.back().stack_depth;
2646 398510 : if (!InsertUnreachablesIfNecessary(num_returns, actual)) {
2647 326 : this->errorf(this->pc_,
2648 : "expected %u elements on the stack for return, found %u",
2649 : num_returns, actual);
2650 326 : return false;
2651 : }
2652 :
2653 : // Typecheck the topmost {num_returns} values on the stack.
2654 398185 : if (num_returns == 0) return true;
2655 : // This line requires num_returns > 0.
2656 : Value* stack_values = &*(stack_.end() - num_returns);
2657 280207 : for (uint32_t i = 0; i < num_returns; ++i) {
2658 140200 : auto& val = stack_values[i];
2659 140200 : ValueType expected_type = this->sig_->GetReturn(i);
2660 140200 : if (val.type == expected_type) continue;
2661 : // If {val.type} is polymorphic, which results from unreachable,
2662 : // make it more specific by using the return's expected type.
2663 : // If it is not polymorphic, this is a type error.
2664 271 : if (!VALIDATE(val.type == kWasmVar)) {
2665 163 : this->errorf(this->pc_,
2666 : "type error in return[%u] (expected %s, got %s)", i,
2667 : ValueTypes::TypeName(expected_type),
2668 : ValueTypes::TypeName(val.type));
2669 163 : return false;
2670 : }
2671 108 : val.type = expected_type;
2672 : }
2673 : return true;
2674 : }
2675 :
2676 2820898 : inline bool InsertUnreachablesIfNecessary(uint32_t expected,
2677 : uint32_t actual) {
2678 2820898 : if (V8_LIKELY(actual >= expected)) {
2679 : return true; // enough actual values are there.
2680 : }
2681 28885 : if (!VALIDATE(control_.back().unreachable())) {
2682 : // There aren't enough values on the stack.
2683 : return false;
2684 : }
2685 : // A slow path. When the actual number of values on the stack is less
2686 : // than the expected number of values and the current control is
2687 : // unreachable, insert unreachable values below the actual values.
2688 : // This simplifies {TypeCheckMergeValues}.
2689 50948 : auto pos = stack_.begin() + (stack_.size() - actual);
2690 71847 : stack_.insert(pos, expected - actual, UnreachableValue(this->pc_));
2691 25474 : return true;
2692 : }
2693 :
2694 56623 : void onFirstError() override {
2695 56623 : this->end_ = this->pc_; // Terminate decoding loop.
2696 : TRACE(" !%s\n", this->error_.message().c_str());
2697 : CALL_INTERFACE(OnFirstError);
2698 56623 : }
2699 :
2700 129 : void BuildSimplePrototypeOperator(WasmOpcode opcode) {
2701 129 : if (WasmOpcodes::IsSignExtensionOpcode(opcode)) {
2702 93 : RET_ON_PROTOTYPE_OPCODE(se);
2703 : }
2704 129 : if (WasmOpcodes::IsAnyRefOpcode(opcode)) {
2705 36 : RET_ON_PROTOTYPE_OPCODE(anyref);
2706 : }
2707 129 : FunctionSig* sig = WasmOpcodes::Signature(opcode);
2708 129 : BuildSimpleOperator(opcode, sig);
2709 129 : }
2710 :
2711 520973 : void BuildSimpleOperator(WasmOpcode opcode, FunctionSig* sig) {
2712 117702 : switch (sig->parameter_count()) {
2713 : case 1: {
2714 : auto val = Pop(0, sig->GetParam(0));
2715 : auto* ret =
2716 134481 : sig->return_count() == 0 ? nullptr : Push(sig->GetReturn(0));
2717 134124 : CALL_INTERFACE_IF_REACHABLE(UnOp, opcode, val, ret);
2718 : break;
2719 : }
2720 : case 2: {
2721 : auto rval = Pop(1, sig->GetParam(1));
2722 : auto lval = Pop(0, sig->GetParam(0));
2723 : auto* ret =
2724 98705 : sig->return_count() == 0 ? nullptr : Push(sig->GetReturn(0));
2725 97330 : CALL_INTERFACE_IF_REACHABLE(BinOp, opcode, lval, rval, ret);
2726 : break;
2727 : }
2728 : default:
2729 0 : UNREACHABLE();
2730 : }
2731 117702 : }
2732 :
2733 551243 : void BuildSimpleOperator(WasmOpcode opcode, ValueType return_type,
2734 : ValueType arg_type) {
2735 : auto val = Pop(0, arg_type);
2736 611536 : auto* ret = return_type == kWasmStmt ? nullptr : Push(return_type);
2737 625394 : CALL_INTERFACE_IF_REACHABLE(UnOp, opcode, val, ret);
2738 551256 : }
2739 :
2740 2368233 : void BuildSimpleOperator(WasmOpcode opcode, ValueType return_type,
2741 : ValueType lhs_type, ValueType rhs_type) {
2742 : auto rval = Pop(1, rhs_type);
2743 : auto lval = Pop(0, lhs_type);
2744 3673745 : auto* ret = return_type == kWasmStmt ? nullptr : Push(return_type);
2745 4415515 : CALL_INTERFACE_IF_REACHABLE(BinOp, opcode, lval, rval, ret);
2746 2368251 : }
2747 :
2748 : #define DEFINE_SIMPLE_SIG_OPERATOR(sig, ...) \
2749 : void BuildSimpleOperator_##sig(WasmOpcode opcode) { \
2750 : BuildSimpleOperator(opcode, __VA_ARGS__); \
2751 : }
2752 249113 : FOREACH_SIGNATURE(DEFINE_SIMPLE_SIG_OPERATOR)
2753 : #undef DEFINE_SIMPLE_SIG_OPERATOR
2754 : };
2755 :
2756 : #undef CALL_INTERFACE
2757 : #undef CALL_INTERFACE_IF_REACHABLE
2758 : #undef CALL_INTERFACE_IF_PARENT_REACHABLE
2759 :
2760 : class EmptyInterface {
2761 : public:
2762 : static constexpr Decoder::ValidateFlag validate = Decoder::kValidate;
2763 : using Value = ValueBase;
2764 : using Control = ControlBase<Value>;
2765 : using FullDecoder = WasmFullDecoder<validate, EmptyInterface>;
2766 :
2767 : #define DEFINE_EMPTY_CALLBACK(name, ...) \
2768 : void name(FullDecoder* decoder, ##__VA_ARGS__) {}
2769 : INTERFACE_FUNCTIONS(DEFINE_EMPTY_CALLBACK)
2770 : #undef DEFINE_EMPTY_CALLBACK
2771 : };
2772 :
2773 : #undef TRACE
2774 : #undef TRACE_INST_FORMAT
2775 : #undef VALIDATE
2776 : #undef CHECK_PROTOTYPE_OPCODE
2777 : #undef OPCODE_ERROR
2778 :
2779 : } // namespace wasm
2780 : } // namespace internal
2781 : } // namespace v8
2782 :
2783 : #endif // V8_WASM_FUNCTION_BODY_DECODER_IMPL_H_
|