Line data Source code
1 : // Copyright 2016 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 : #include <atomic>
6 : #include <type_traits>
7 :
8 : #include "src/wasm/wasm-interpreter.h"
9 :
10 : #include "src/assembler-inl.h"
11 : #include "src/base/overflowing-math.h"
12 : #include "src/boxed-float.h"
13 : #include "src/compiler/wasm-compiler.h"
14 : #include "src/conversions.h"
15 : #include "src/identity-map.h"
16 : #include "src/objects-inl.h"
17 : #include "src/trap-handler/trap-handler.h"
18 : #include "src/utils.h"
19 : #include "src/wasm/decoder.h"
20 : #include "src/wasm/function-body-decoder-impl.h"
21 : #include "src/wasm/function-body-decoder.h"
22 : #include "src/wasm/memory-tracing.h"
23 : #include "src/wasm/wasm-engine.h"
24 : #include "src/wasm/wasm-external-refs.h"
25 : #include "src/wasm/wasm-limits.h"
26 : #include "src/wasm/wasm-module.h"
27 : #include "src/wasm/wasm-objects-inl.h"
28 :
29 : #include "src/zone/accounting-allocator.h"
30 : #include "src/zone/zone-containers.h"
31 :
32 : namespace v8 {
33 : namespace internal {
34 : namespace wasm {
35 :
36 : #define TRACE(...) \
37 : do { \
38 : if (FLAG_trace_wasm_interpreter) PrintF(__VA_ARGS__); \
39 : } while (false)
40 :
41 : #if V8_TARGET_BIG_ENDIAN
42 : #define LANE(i, type) ((sizeof(type.val) / sizeof(type.val[0])) - (i)-1)
43 : #else
44 : #define LANE(i, type) (i)
45 : #endif
46 :
47 : #define FOREACH_INTERNAL_OPCODE(V) V(Breakpoint, 0xFF)
48 :
49 : #define WASM_CTYPES(V) \
50 : V(I32, int32_t) V(I64, int64_t) V(F32, float) V(F64, double) V(S128, Simd128)
51 :
52 : #define FOREACH_SIMPLE_BINOP(V) \
53 : V(I32Add, uint32_t, +) \
54 : V(I32Sub, uint32_t, -) \
55 : V(I32Mul, uint32_t, *) \
56 : V(I32And, uint32_t, &) \
57 : V(I32Ior, uint32_t, |) \
58 : V(I32Xor, uint32_t, ^) \
59 : V(I32Eq, uint32_t, ==) \
60 : V(I32Ne, uint32_t, !=) \
61 : V(I32LtU, uint32_t, <) \
62 : V(I32LeU, uint32_t, <=) \
63 : V(I32GtU, uint32_t, >) \
64 : V(I32GeU, uint32_t, >=) \
65 : V(I32LtS, int32_t, <) \
66 : V(I32LeS, int32_t, <=) \
67 : V(I32GtS, int32_t, >) \
68 : V(I32GeS, int32_t, >=) \
69 : V(I64Add, uint64_t, +) \
70 : V(I64Sub, uint64_t, -) \
71 : V(I64Mul, uint64_t, *) \
72 : V(I64And, uint64_t, &) \
73 : V(I64Ior, uint64_t, |) \
74 : V(I64Xor, uint64_t, ^) \
75 : V(I64Eq, uint64_t, ==) \
76 : V(I64Ne, uint64_t, !=) \
77 : V(I64LtU, uint64_t, <) \
78 : V(I64LeU, uint64_t, <=) \
79 : V(I64GtU, uint64_t, >) \
80 : V(I64GeU, uint64_t, >=) \
81 : V(I64LtS, int64_t, <) \
82 : V(I64LeS, int64_t, <=) \
83 : V(I64GtS, int64_t, >) \
84 : V(I64GeS, int64_t, >=) \
85 : V(F32Add, float, +) \
86 : V(F32Sub, float, -) \
87 : V(F32Eq, float, ==) \
88 : V(F32Ne, float, !=) \
89 : V(F32Lt, float, <) \
90 : V(F32Le, float, <=) \
91 : V(F32Gt, float, >) \
92 : V(F32Ge, float, >=) \
93 : V(F64Add, double, +) \
94 : V(F64Sub, double, -) \
95 : V(F64Eq, double, ==) \
96 : V(F64Ne, double, !=) \
97 : V(F64Lt, double, <) \
98 : V(F64Le, double, <=) \
99 : V(F64Gt, double, >) \
100 : V(F64Ge, double, >=) \
101 : V(F32Mul, float, *) \
102 : V(F64Mul, double, *) \
103 : V(F32Div, float, /) \
104 : V(F64Div, double, /)
105 :
106 : #define FOREACH_OTHER_BINOP(V) \
107 : V(I32DivS, int32_t) \
108 : V(I32DivU, uint32_t) \
109 : V(I32RemS, int32_t) \
110 : V(I32RemU, uint32_t) \
111 : V(I32Shl, uint32_t) \
112 : V(I32ShrU, uint32_t) \
113 : V(I32ShrS, int32_t) \
114 : V(I64DivS, int64_t) \
115 : V(I64DivU, uint64_t) \
116 : V(I64RemS, int64_t) \
117 : V(I64RemU, uint64_t) \
118 : V(I64Shl, uint64_t) \
119 : V(I64ShrU, uint64_t) \
120 : V(I64ShrS, int64_t) \
121 : V(I32Ror, int32_t) \
122 : V(I32Rol, int32_t) \
123 : V(I64Ror, int64_t) \
124 : V(I64Rol, int64_t) \
125 : V(F32Min, float) \
126 : V(F32Max, float) \
127 : V(F64Min, double) \
128 : V(F64Max, double) \
129 : V(I32AsmjsDivS, int32_t) \
130 : V(I32AsmjsDivU, uint32_t) \
131 : V(I32AsmjsRemS, int32_t) \
132 : V(I32AsmjsRemU, uint32_t) \
133 : V(F32CopySign, Float32) \
134 : V(F64CopySign, Float64)
135 :
136 : #define FOREACH_I32CONV_FLOATOP(V) \
137 : V(I32SConvertF32, int32_t, float) \
138 : V(I32SConvertF64, int32_t, double) \
139 : V(I32UConvertF32, uint32_t, float) \
140 : V(I32UConvertF64, uint32_t, double)
141 :
142 : #define FOREACH_OTHER_UNOP(V) \
143 : V(I32Clz, uint32_t) \
144 : V(I32Ctz, uint32_t) \
145 : V(I32Popcnt, uint32_t) \
146 : V(I32Eqz, uint32_t) \
147 : V(I64Clz, uint64_t) \
148 : V(I64Ctz, uint64_t) \
149 : V(I64Popcnt, uint64_t) \
150 : V(I64Eqz, uint64_t) \
151 : V(F32Abs, Float32) \
152 : V(F32Neg, Float32) \
153 : V(F32Ceil, float) \
154 : V(F32Floor, float) \
155 : V(F32Trunc, float) \
156 : V(F32NearestInt, float) \
157 : V(F64Abs, Float64) \
158 : V(F64Neg, Float64) \
159 : V(F64Ceil, double) \
160 : V(F64Floor, double) \
161 : V(F64Trunc, double) \
162 : V(F64NearestInt, double) \
163 : V(I32ConvertI64, int64_t) \
164 : V(I64SConvertF32, float) \
165 : V(I64SConvertF64, double) \
166 : V(I64UConvertF32, float) \
167 : V(I64UConvertF64, double) \
168 : V(I64SConvertI32, int32_t) \
169 : V(I64UConvertI32, uint32_t) \
170 : V(F32SConvertI32, int32_t) \
171 : V(F32UConvertI32, uint32_t) \
172 : V(F32SConvertI64, int64_t) \
173 : V(F32UConvertI64, uint64_t) \
174 : V(F32ConvertF64, double) \
175 : V(F32ReinterpretI32, int32_t) \
176 : V(F64SConvertI32, int32_t) \
177 : V(F64UConvertI32, uint32_t) \
178 : V(F64SConvertI64, int64_t) \
179 : V(F64UConvertI64, uint64_t) \
180 : V(F64ConvertF32, float) \
181 : V(F64ReinterpretI64, int64_t) \
182 : V(I32AsmjsSConvertF32, float) \
183 : V(I32AsmjsUConvertF32, float) \
184 : V(I32AsmjsSConvertF64, double) \
185 : V(I32AsmjsUConvertF64, double) \
186 : V(F32Sqrt, float) \
187 : V(F64Sqrt, double)
188 :
189 : namespace {
190 :
191 : constexpr uint32_t kFloat32SignBitMask = uint32_t{1} << 31;
192 : constexpr uint64_t kFloat64SignBitMask = uint64_t{1} << 63;
193 :
194 : inline int32_t ExecuteI32DivS(int32_t a, int32_t b, TrapReason* trap) {
195 51940 : if (b == 0) {
196 : *trap = kTrapDivByZero;
197 : return 0;
198 : }
199 47755 : if (b == -1 && a == std::numeric_limits<int32_t>::min()) {
200 : *trap = kTrapDivUnrepresentable;
201 : return 0;
202 : }
203 47740 : return a / b;
204 : }
205 :
206 : inline uint32_t ExecuteI32DivU(uint32_t a, uint32_t b, TrapReason* trap) {
207 51165 : if (b == 0) {
208 : *trap = kTrapDivByZero;
209 : return 0;
210 : }
211 47070 : return a / b;
212 : }
213 :
214 : inline int32_t ExecuteI32RemS(int32_t a, int32_t b, TrapReason* trap) {
215 51200 : if (b == 0) {
216 : *trap = kTrapRemByZero;
217 : return 0;
218 : }
219 47090 : if (b == -1) return 0;
220 43000 : return a % b;
221 : }
222 :
223 : inline uint32_t ExecuteI32RemU(uint32_t a, uint32_t b, TrapReason* trap) {
224 51165 : if (b == 0) {
225 : *trap = kTrapRemByZero;
226 : return 0;
227 : }
228 47070 : return a % b;
229 : }
230 :
231 : inline uint32_t ExecuteI32Shl(uint32_t a, uint32_t b, TrapReason* trap) {
232 51140 : return a << (b & 0x1F);
233 : }
234 :
235 : inline uint32_t ExecuteI32ShrU(uint32_t a, uint32_t b, TrapReason* trap) {
236 51140 : return a >> (b & 0x1F);
237 : }
238 :
239 : inline int32_t ExecuteI32ShrS(int32_t a, int32_t b, TrapReason* trap) {
240 51140 : return a >> (b & 0x1F);
241 : }
242 :
243 : inline int64_t ExecuteI64DivS(int64_t a, int64_t b, TrapReason* trap) {
244 67895 : if (b == 0) {
245 : *trap = kTrapDivByZero;
246 : return 0;
247 : }
248 62090 : if (b == -1 && a == std::numeric_limits<int64_t>::min()) {
249 : *trap = kTrapDivUnrepresentable;
250 : return 0;
251 : }
252 62085 : return a / b;
253 : }
254 :
255 : inline uint64_t ExecuteI64DivU(uint64_t a, uint64_t b, TrapReason* trap) {
256 67135 : if (b == 0) {
257 : *trap = kTrapDivByZero;
258 : return 0;
259 : }
260 61410 : return a / b;
261 : }
262 :
263 : inline int64_t ExecuteI64RemS(int64_t a, int64_t b, TrapReason* trap) {
264 67140 : if (b == 0) {
265 : *trap = kTrapRemByZero;
266 : return 0;
267 : }
268 61415 : if (b == -1) return 0;
269 56105 : return a % b;
270 : }
271 :
272 : inline uint64_t ExecuteI64RemU(uint64_t a, uint64_t b, TrapReason* trap) {
273 67135 : if (b == 0) {
274 : *trap = kTrapRemByZero;
275 : return 0;
276 : }
277 61410 : return a % b;
278 : }
279 :
280 : inline uint64_t ExecuteI64Shl(uint64_t a, uint64_t b, TrapReason* trap) {
281 101540 : return a << (b & 0x3F);
282 : }
283 :
284 : inline uint64_t ExecuteI64ShrU(uint64_t a, uint64_t b, TrapReason* trap) {
285 101540 : return a >> (b & 0x3F);
286 : }
287 :
288 : inline int64_t ExecuteI64ShrS(int64_t a, int64_t b, TrapReason* trap) {
289 101540 : return a >> (b & 0x3F);
290 : }
291 :
292 : inline uint32_t ExecuteI32Ror(uint32_t a, uint32_t b, TrapReason* trap) {
293 33640 : return (a >> (b & 0x1F)) | (a << ((32 - b) & 0x1F));
294 : }
295 :
296 : inline uint32_t ExecuteI32Rol(uint32_t a, uint32_t b, TrapReason* trap) {
297 33640 : return (a << (b & 0x1F)) | (a >> ((32 - b) & 0x1F));
298 : }
299 :
300 : inline uint64_t ExecuteI64Ror(uint64_t a, uint64_t b, TrapReason* trap) {
301 32825 : return (a >> (b & 0x3F)) | (a << ((64 - b) & 0x3F));
302 : }
303 :
304 : inline uint64_t ExecuteI64Rol(uint64_t a, uint64_t b, TrapReason* trap) {
305 32825 : return (a << (b & 0x3F)) | (a >> ((64 - b) & 0x3F));
306 : }
307 :
308 : inline float ExecuteF32Min(float a, float b, TrapReason* trap) {
309 66140 : return JSMin(a, b);
310 : }
311 :
312 : inline float ExecuteF32Max(float a, float b, TrapReason* trap) {
313 66130 : return JSMax(a, b);
314 : }
315 :
316 : inline Float32 ExecuteF32CopySign(Float32 a, Float32 b, TrapReason* trap) {
317 66135 : return Float32::FromBits((a.get_bits() & ~kFloat32SignBitMask) |
318 66135 : (b.get_bits() & kFloat32SignBitMask));
319 : }
320 :
321 : inline double ExecuteF64Min(double a, double b, TrapReason* trap) {
322 12010 : return JSMin(a, b);
323 : }
324 :
325 : inline double ExecuteF64Max(double a, double b, TrapReason* trap) {
326 12020 : return JSMax(a, b);
327 : }
328 :
329 : inline Float64 ExecuteF64CopySign(Float64 a, Float64 b, TrapReason* trap) {
330 12015 : return Float64::FromBits((a.get_bits() & ~kFloat64SignBitMask) |
331 12015 : (b.get_bits() & kFloat64SignBitMask));
332 : }
333 :
334 : inline int32_t ExecuteI32AsmjsDivS(int32_t a, int32_t b, TrapReason* trap) {
335 2925 : if (b == 0) return 0;
336 2620 : if (b == -1 && a == std::numeric_limits<int32_t>::min()) {
337 : return std::numeric_limits<int32_t>::min();
338 : }
339 2610 : return a / b;
340 : }
341 :
342 : inline uint32_t ExecuteI32AsmjsDivU(uint32_t a, uint32_t b, TrapReason* trap) {
343 25 : if (b == 0) return 0;
344 10 : return a / b;
345 : }
346 :
347 : inline int32_t ExecuteI32AsmjsRemS(int32_t a, int32_t b, TrapReason* trap) {
348 2925 : if (b == 0) return 0;
349 2620 : if (b == -1) return 0;
350 2325 : return a % b;
351 : }
352 :
353 : inline uint32_t ExecuteI32AsmjsRemU(uint32_t a, uint32_t b, TrapReason* trap) {
354 25 : if (b == 0) return 0;
355 10 : return a % b;
356 : }
357 :
358 : inline int32_t ExecuteI32AsmjsSConvertF32(float a, TrapReason* trap) {
359 575 : return DoubleToInt32(a);
360 : }
361 :
362 : inline uint32_t ExecuteI32AsmjsUConvertF32(float a, TrapReason* trap) {
363 575 : return DoubleToUint32(a);
364 : }
365 :
366 : inline int32_t ExecuteI32AsmjsSConvertF64(double a, TrapReason* trap) {
367 245 : return DoubleToInt32(a);
368 : }
369 :
370 : inline uint32_t ExecuteI32AsmjsUConvertF64(double a, TrapReason* trap) {
371 : return DoubleToUint32(a);
372 : }
373 :
374 : int32_t ExecuteI32Clz(uint32_t val, TrapReason* trap) {
375 330 : return base::bits::CountLeadingZeros(val);
376 : }
377 :
378 : uint32_t ExecuteI32Ctz(uint32_t val, TrapReason* trap) {
379 : return base::bits::CountTrailingZeros(val);
380 : }
381 :
382 : uint32_t ExecuteI32Popcnt(uint32_t val, TrapReason* trap) {
383 : return base::bits::CountPopulation(val);
384 : }
385 :
386 : inline uint32_t ExecuteI32Eqz(uint32_t val, TrapReason* trap) {
387 620 : return val == 0 ? 1 : 0;
388 : }
389 :
390 : int64_t ExecuteI64Clz(uint64_t val, TrapReason* trap) {
391 325 : return base::bits::CountLeadingZeros(val);
392 : }
393 :
394 : inline uint64_t ExecuteI64Ctz(uint64_t val, TrapReason* trap) {
395 325 : return base::bits::CountTrailingZeros(val);
396 : }
397 :
398 : inline int64_t ExecuteI64Popcnt(uint64_t val, TrapReason* trap) {
399 50 : return base::bits::CountPopulation(val);
400 : }
401 :
402 : inline int32_t ExecuteI64Eqz(uint64_t val, TrapReason* trap) {
403 415 : return val == 0 ? 1 : 0;
404 : }
405 :
406 : inline Float32 ExecuteF32Abs(Float32 a, TrapReason* trap) {
407 20 : return Float32::FromBits(a.get_bits() & ~kFloat32SignBitMask);
408 : }
409 :
410 : inline Float32 ExecuteF32Neg(Float32 a, TrapReason* trap) {
411 585 : return Float32::FromBits(a.get_bits() ^ kFloat32SignBitMask);
412 : }
413 :
414 575 : inline float ExecuteF32Ceil(float a, TrapReason* trap) { return ceilf(a); }
415 :
416 575 : inline float ExecuteF32Floor(float a, TrapReason* trap) { return floorf(a); }
417 :
418 575 : inline float ExecuteF32Trunc(float a, TrapReason* trap) { return truncf(a); }
419 :
420 : inline float ExecuteF32NearestInt(float a, TrapReason* trap) {
421 575 : return nearbyintf(a);
422 : }
423 :
424 : inline float ExecuteF32Sqrt(float a, TrapReason* trap) {
425 10 : float result = sqrtf(a);
426 : return result;
427 : }
428 :
429 : inline Float64 ExecuteF64Abs(Float64 a, TrapReason* trap) {
430 20 : return Float64::FromBits(a.get_bits() & ~kFloat64SignBitMask);
431 : }
432 :
433 : inline Float64 ExecuteF64Neg(Float64 a, TrapReason* trap) {
434 255 : return Float64::FromBits(a.get_bits() ^ kFloat64SignBitMask);
435 : }
436 :
437 245 : inline double ExecuteF64Ceil(double a, TrapReason* trap) { return ceil(a); }
438 :
439 245 : inline double ExecuteF64Floor(double a, TrapReason* trap) { return floor(a); }
440 :
441 245 : inline double ExecuteF64Trunc(double a, TrapReason* trap) { return trunc(a); }
442 :
443 : inline double ExecuteF64NearestInt(double a, TrapReason* trap) {
444 245 : return nearbyint(a);
445 : }
446 :
447 10 : inline double ExecuteF64Sqrt(double a, TrapReason* trap) { return sqrt(a); }
448 :
449 : template <typename int_type, typename float_type>
450 : int_type ExecuteConvert(float_type a, TrapReason* trap) {
451 3450 : if (is_inbounds<int_type>(a)) {
452 1940 : return static_cast<int_type>(a);
453 : }
454 : *trap = kTrapFloatUnrepresentable;
455 : return 0;
456 : }
457 :
458 : template <typename int_type, typename float_type>
459 : int_type ExecuteConvertSaturate(float_type a) {
460 : TrapReason base_trap = kTrapCount;
461 : int32_t val = ExecuteConvert<int_type>(a, &base_trap);
462 1640 : if (base_trap == kTrapCount) {
463 : return val;
464 : }
465 : return std::isnan(a) ? 0
466 : : (a < static_cast<float_type>(0.0)
467 : ? std::numeric_limits<int_type>::min()
468 755 : : std::numeric_limits<int_type>::max());
469 : }
470 :
471 : template <typename dst_type, typename src_type, void (*fn)(Address)>
472 755 : inline dst_type CallExternalIntToFloatFunction(src_type input) {
473 755 : uint8_t data[std::max(sizeof(dst_type), sizeof(src_type))];
474 755 : Address data_addr = reinterpret_cast<Address>(data);
475 : WriteUnalignedValue<src_type>(data_addr, input);
476 755 : fn(data_addr);
477 755 : return ReadUnalignedValue<dst_type>(data_addr);
478 : }
479 :
480 : template <typename dst_type, typename src_type, int32_t (*fn)(Address)>
481 3694 : inline dst_type CallExternalFloatToIntFunction(src_type input,
482 : TrapReason* trap) {
483 3694 : uint8_t data[std::max(sizeof(dst_type), sizeof(src_type))];
484 3694 : Address data_addr = reinterpret_cast<Address>(data);
485 : WriteUnalignedValue<src_type>(data_addr, input);
486 3694 : if (!fn(data_addr)) *trap = kTrapFloatUnrepresentable;
487 3694 : return ReadUnalignedValue<dst_type>(data_addr);
488 : }
489 :
490 : inline uint32_t ExecuteI32ConvertI64(int64_t a, TrapReason* trap) {
491 197464 : return static_cast<uint32_t>(a & 0xFFFFFFFF);
492 : }
493 :
494 : int64_t ExecuteI64SConvertF32(float a, TrapReason* trap) {
495 : return CallExternalFloatToIntFunction<int64_t, float,
496 1150 : float32_to_int64_wrapper>(a, trap);
497 : }
498 :
499 575 : int64_t ExecuteI64SConvertSatF32(float a) {
500 575 : TrapReason base_trap = kTrapCount;
501 : int64_t val = ExecuteI64SConvertF32(a, &base_trap);
502 575 : if (base_trap == kTrapCount) {
503 : return val;
504 : }
505 : return std::isnan(a) ? 0
506 : : (a < 0.0 ? std::numeric_limits<int64_t>::min()
507 160 : : std::numeric_limits<int64_t>::max());
508 : }
509 :
510 : int64_t ExecuteI64SConvertF64(double a, TrapReason* trap) {
511 : return CallExternalFloatToIntFunction<int64_t, double,
512 904 : float64_to_int64_wrapper>(a, trap);
513 : }
514 :
515 245 : int64_t ExecuteI64SConvertSatF64(double a) {
516 245 : TrapReason base_trap = kTrapCount;
517 : int64_t val = ExecuteI64SConvertF64(a, &base_trap);
518 245 : if (base_trap == kTrapCount) {
519 : return val;
520 : }
521 : return std::isnan(a) ? 0
522 : : (a < 0.0 ? std::numeric_limits<int64_t>::min()
523 55 : : std::numeric_limits<int64_t>::max());
524 : }
525 :
526 : uint64_t ExecuteI64UConvertF32(float a, TrapReason* trap) {
527 : return CallExternalFloatToIntFunction<uint64_t, float,
528 1150 : float32_to_uint64_wrapper>(a, trap);
529 : }
530 :
531 575 : uint64_t ExecuteI64UConvertSatF32(float a) {
532 575 : TrapReason base_trap = kTrapCount;
533 : uint64_t val = ExecuteI64UConvertF32(a, &base_trap);
534 575 : if (base_trap == kTrapCount) {
535 : return val;
536 : }
537 : return std::isnan(a) ? 0
538 : : (a < 0.0 ? std::numeric_limits<uint64_t>::min()
539 320 : : std::numeric_limits<uint64_t>::max());
540 : }
541 :
542 : uint64_t ExecuteI64UConvertF64(double a, TrapReason* trap) {
543 : return CallExternalFloatToIntFunction<uint64_t, double,
544 490 : float64_to_uint64_wrapper>(a, trap);
545 : }
546 :
547 245 : uint64_t ExecuteI64UConvertSatF64(double a) {
548 245 : TrapReason base_trap = kTrapCount;
549 : int64_t val = ExecuteI64UConvertF64(a, &base_trap);
550 245 : if (base_trap == kTrapCount) {
551 : return val;
552 : }
553 : return std::isnan(a) ? 0
554 : : (a < 0.0 ? std::numeric_limits<uint64_t>::min()
555 100 : : std::numeric_limits<uint64_t>::max());
556 : }
557 :
558 : inline int64_t ExecuteI64SConvertI32(int32_t a, TrapReason* trap) {
559 310 : return static_cast<int64_t>(a);
560 : }
561 :
562 : inline int64_t ExecuteI64UConvertI32(uint32_t a, TrapReason* trap) {
563 290 : return static_cast<uint64_t>(a);
564 : }
565 :
566 : inline float ExecuteF32SConvertI32(int32_t a, TrapReason* trap) {
567 30 : return static_cast<float>(a);
568 : }
569 :
570 : inline float ExecuteF32UConvertI32(uint32_t a, TrapReason* trap) {
571 9 : return static_cast<float>(a);
572 : }
573 :
574 : inline float ExecuteF32SConvertI64(int64_t a, TrapReason* trap) {
575 405 : return static_cast<float>(a);
576 : }
577 :
578 : inline float ExecuteF32UConvertI64(uint64_t a, TrapReason* trap) {
579 : return CallExternalIntToFloatFunction<float, uint64_t,
580 380 : uint64_to_float32_wrapper>(a);
581 : }
582 :
583 : inline float ExecuteF32ConvertF64(double a, TrapReason* trap) {
584 9 : return static_cast<float>(a);
585 : }
586 :
587 : inline Float32 ExecuteF32ReinterpretI32(int32_t a, TrapReason* trap) {
588 305 : return Float32::FromBits(a);
589 : }
590 :
591 : inline double ExecuteF64SConvertI32(int32_t a, TrapReason* trap) {
592 1170 : return static_cast<double>(a);
593 : }
594 :
595 : inline double ExecuteF64UConvertI32(uint32_t a, TrapReason* trap) {
596 10 : return static_cast<double>(a);
597 : }
598 :
599 : inline double ExecuteF64SConvertI64(int64_t a, TrapReason* trap) {
600 19213 : return static_cast<double>(a);
601 : }
602 :
603 : inline double ExecuteF64UConvertI64(uint64_t a, TrapReason* trap) {
604 : return CallExternalIntToFloatFunction<double, uint64_t,
605 375 : uint64_to_float64_wrapper>(a);
606 : }
607 :
608 : inline double ExecuteF64ConvertF32(float a, TrapReason* trap) {
609 1743 : return static_cast<double>(a);
610 : }
611 :
612 : inline Float64 ExecuteF64ReinterpretI64(int64_t a, TrapReason* trap) {
613 290 : return Float64::FromBits(a);
614 : }
615 :
616 : inline int32_t ExecuteI32ReinterpretF32(WasmValue a) {
617 320 : return a.to_f32_boxed().get_bits();
618 : }
619 :
620 : inline int64_t ExecuteI64ReinterpretF64(WasmValue a) {
621 305 : return a.to_f64_boxed().get_bits();
622 : }
623 :
624 : enum InternalOpcode {
625 : #define DECL_INTERNAL_ENUM(name, value) kInternal##name = value,
626 : FOREACH_INTERNAL_OPCODE(DECL_INTERNAL_ENUM)
627 : #undef DECL_INTERNAL_ENUM
628 : };
629 :
630 : const char* OpcodeName(uint32_t val) {
631 0 : switch (val) {
632 : #define DECL_INTERNAL_CASE(name, value) \
633 : case kInternal##name: \
634 : return "Internal" #name;
635 : FOREACH_INTERNAL_OPCODE(DECL_INTERNAL_CASE)
636 : #undef DECL_INTERNAL_CASE
637 : }
638 0 : return WasmOpcodes::OpcodeName(static_cast<WasmOpcode>(val));
639 : }
640 :
641 : } // namespace
642 :
643 : class SideTable;
644 :
645 : // Code and metadata needed to execute a function.
646 933102 : struct InterpreterCode {
647 : const WasmFunction* function; // wasm function
648 : BodyLocalDecls locals; // local declarations
649 : const byte* orig_start; // start of original code
650 : const byte* orig_end; // end of original code
651 : byte* start; // start of (maybe altered) code
652 : byte* end; // end of (maybe altered) code
653 : SideTable* side_table; // precomputed side table for control flow.
654 :
655 55004272 : const byte* at(pc_t pc) { return start + pc; }
656 : };
657 :
658 : // A helper class to compute the control transfers for each bytecode offset.
659 : // Control transfers allow Br, BrIf, BrTable, If, Else, and End bytecodes to
660 : // be directly executed without the need to dynamically track blocks.
661 : class SideTable : public ZoneObject {
662 : public:
663 : ControlTransferMap map_;
664 : uint32_t max_stack_height_ = 0;
665 :
666 916350 : SideTable(Zone* zone, const WasmModule* module, InterpreterCode* code)
667 458175 : : map_(zone) {
668 : // Create a zone for all temporary objects.
669 458175 : Zone control_transfer_zone(zone->allocator(), ZONE_NAME);
670 :
671 : // Represents a control flow label.
672 : class CLabel : public ZoneObject {
673 : explicit CLabel(Zone* zone, uint32_t target_stack_height, uint32_t arity)
674 : : target_stack_height(target_stack_height),
675 : arity(arity),
676 508500 : refs(zone) {}
677 :
678 : public:
679 : struct Ref {
680 : const byte* from_pc;
681 : const uint32_t stack_height;
682 : };
683 : const byte* target = nullptr;
684 : uint32_t target_stack_height;
685 : // Arity when branching to this label.
686 : const uint32_t arity;
687 : ZoneVector<Ref> refs;
688 :
689 508500 : static CLabel* New(Zone* zone, uint32_t stack_height, uint32_t arity) {
690 508500 : return new (zone) CLabel(zone, stack_height, arity);
691 : }
692 :
693 : // Bind this label to the given PC.
694 : void Bind(const byte* pc) {
695 : DCHECK_NULL(target);
696 508500 : target = pc;
697 : }
698 :
699 : // Reference this label from the given location.
700 : void Ref(const byte* from_pc, uint32_t stack_height) {
701 : // Target being bound before a reference means this is a loop.
702 : DCHECK_IMPLIES(target, *target == kExprLoop);
703 66852 : refs.push_back({from_pc, stack_height});
704 : }
705 :
706 508500 : void Finish(ControlTransferMap* map, const byte* start) {
707 : DCHECK_NOT_NULL(target);
708 1050426 : for (auto ref : refs) {
709 33426 : size_t offset = static_cast<size_t>(ref.from_pc - start);
710 33426 : auto pcdiff = static_cast<pcdiff_t>(target - ref.from_pc);
711 : DCHECK_GE(ref.stack_height, target_stack_height);
712 : spdiff_t spdiff =
713 33426 : static_cast<spdiff_t>(ref.stack_height - target_stack_height);
714 : TRACE("control transfer @%zu: Δpc %d, stack %u->%u = -%u\n", offset,
715 : pcdiff, ref.stack_height, target_stack_height, spdiff);
716 33426 : ControlTransferEntry& entry = (*map)[offset];
717 33426 : entry.pc_diff = pcdiff;
718 33426 : entry.sp_diff = spdiff;
719 33426 : entry.target_arity = arity;
720 : }
721 508500 : }
722 : };
723 :
724 : // An entry in the control stack.
725 : struct Control {
726 : const byte* pc;
727 : CLabel* end_label;
728 : CLabel* else_label;
729 : // Arity (number of values on the stack) when exiting this control
730 : // structure via |end|.
731 : uint32_t exit_arity;
732 : // Track whether this block was already left, i.e. all further
733 : // instructions are unreachable.
734 : bool unreachable = false;
735 :
736 : Control(const byte* pc, CLabel* end_label, CLabel* else_label,
737 : uint32_t exit_arity)
738 : : pc(pc),
739 : end_label(end_label),
740 : else_label(else_label),
741 496773 : exit_arity(exit_arity) {}
742 : Control(const byte* pc, CLabel* end_label, uint32_t exit_arity)
743 : : Control(pc, end_label, nullptr, exit_arity) {}
744 :
745 496773 : void Finish(ControlTransferMap* map, const byte* start) {
746 496773 : end_label->Finish(map, start);
747 496773 : if (else_label) else_label->Finish(map, start);
748 496773 : }
749 : };
750 :
751 : // Compute the ControlTransfer map.
752 : // This algorithm maintains a stack of control constructs similar to the
753 : // AST decoder. The {control_stack} allows matching {br,br_if,br_table}
754 : // bytecodes with their target, as well as determining whether the current
755 : // bytecodes are within the true or false block of an else.
756 : ZoneVector<Control> control_stack(&control_transfer_zone);
757 : uint32_t stack_height = 0;
758 : uint32_t func_arity =
759 458175 : static_cast<uint32_t>(code->function->sig->return_count());
760 : CLabel* func_label =
761 458175 : CLabel::New(&control_transfer_zone, stack_height, func_arity);
762 458175 : control_stack.emplace_back(code->orig_start, func_label, func_arity);
763 : auto control_parent = [&]() -> Control& {
764 : DCHECK_LE(2, control_stack.size());
765 77784 : return control_stack[control_stack.size() - 2];
766 458175 : };
767 : auto copy_unreachable = [&] {
768 38745 : control_stack.back().unreachable = control_parent().unreachable;
769 : };
770 3834615 : for (BytecodeIterator i(code->orig_start, code->orig_end, &code->locals);
771 2918265 : i.has_next(); i.next()) {
772 : WasmOpcode opcode = i.current();
773 2918265 : if (WasmOpcodes::IsPrefixOpcode(opcode)) opcode = i.prefixed_opcode();
774 2918265 : bool unreachable = control_stack.back().unreachable;
775 2918265 : if (unreachable) {
776 : TRACE("@%u: %s (is unreachable)\n", i.pc_offset(),
777 : WasmOpcodes::OpcodeName(opcode));
778 : } else {
779 : auto stack_effect =
780 2878547 : StackEffect(module, code->function->sig, i.pc(), i.end());
781 : TRACE("@%u: %s (sp %d - %d + %d)\n", i.pc_offset(),
782 : WasmOpcodes::OpcodeName(opcode), stack_height, stack_effect.first,
783 : stack_effect.second);
784 : DCHECK_GE(stack_height, stack_effect.first);
785 : DCHECK_GE(kMaxUInt32, static_cast<uint64_t>(stack_height) -
786 : stack_effect.first + stack_effect.second);
787 2878547 : stack_height = stack_height - stack_effect.first + stack_effect.second;
788 2878547 : if (stack_height > max_stack_height_) max_stack_height_ = stack_height;
789 : }
790 2918265 : switch (opcode) {
791 : case kExprBlock:
792 : case kExprLoop: {
793 26871 : bool is_loop = opcode == kExprLoop;
794 : BlockTypeImmediate<Decoder::kNoValidate> imm(kAllWasmFeatures, &i,
795 26871 : i.pc());
796 26871 : if (imm.type == kWasmVar) {
797 25 : imm.sig = module->signatures[imm.sig_index];
798 : }
799 : TRACE("control @%u: %s, arity %d->%d\n", i.pc_offset(),
800 : is_loop ? "Loop" : "Block", imm.in_arity(), imm.out_arity());
801 : CLabel* label =
802 : CLabel::New(&control_transfer_zone, stack_height,
803 53742 : is_loop ? imm.in_arity() : imm.out_arity());
804 53742 : control_stack.emplace_back(i.pc(), label, imm.out_arity());
805 : copy_unreachable();
806 26871 : if (is_loop) label->Bind(i.pc());
807 : break;
808 : }
809 : case kExprIf: {
810 : BlockTypeImmediate<Decoder::kNoValidate> imm(kAllWasmFeatures, &i,
811 11727 : i.pc());
812 11727 : if (imm.type == kWasmVar) {
813 10 : imm.sig = module->signatures[imm.sig_index];
814 : }
815 : TRACE("control @%u: If, arity %d->%d\n", i.pc_offset(),
816 : imm.in_arity(), imm.out_arity());
817 : CLabel* end_label = CLabel::New(&control_transfer_zone, stack_height,
818 11727 : imm.out_arity());
819 : CLabel* else_label =
820 11727 : CLabel::New(&control_transfer_zone, stack_height, 0);
821 11727 : control_stack.emplace_back(i.pc(), end_label, else_label,
822 35181 : imm.out_arity());
823 : copy_unreachable();
824 11727 : if (!unreachable) else_label->Ref(i.pc(), stack_height);
825 : break;
826 : }
827 : case kExprElse: {
828 : Control* c = &control_stack.back();
829 : copy_unreachable();
830 : TRACE("control @%u: Else\n", i.pc_offset());
831 147 : if (!control_parent().unreachable) {
832 141 : c->end_label->Ref(i.pc(), stack_height);
833 : }
834 : DCHECK_NOT_NULL(c->else_label);
835 147 : c->else_label->Bind(i.pc() + 1);
836 147 : c->else_label->Finish(&map_, code->orig_start);
837 147 : c->else_label = nullptr;
838 : DCHECK_GE(stack_height, c->end_label->target_stack_height);
839 147 : stack_height = c->end_label->target_stack_height;
840 147 : break;
841 : }
842 : case kExprEnd: {
843 496773 : Control* c = &control_stack.back();
844 : TRACE("control @%u: End\n", i.pc_offset());
845 : // Only loops have bound labels.
846 : DCHECK_IMPLIES(c->end_label->target, *c->pc == kExprLoop);
847 496773 : if (!c->end_label->target) {
848 496563 : if (c->else_label) c->else_label->Bind(i.pc());
849 496563 : c->end_label->Bind(i.pc() + 1);
850 : }
851 993546 : c->Finish(&map_, code->orig_start);
852 : DCHECK_GE(stack_height, c->end_label->target_stack_height);
853 496773 : stack_height = c->end_label->target_stack_height + c->exit_arity;
854 : control_stack.pop_back();
855 : break;
856 : }
857 : case kExprBr: {
858 532 : BranchDepthImmediate<Decoder::kNoValidate> imm(&i, i.pc());
859 : TRACE("control @%u: Br[depth=%u]\n", i.pc_offset(), imm.depth);
860 1064 : Control* c = &control_stack[control_stack.size() - imm.depth - 1];
861 532 : if (!unreachable) c->end_label->Ref(i.pc(), stack_height);
862 : break;
863 : }
864 : case kExprBrIf: {
865 121 : BranchDepthImmediate<Decoder::kNoValidate> imm(&i, i.pc());
866 : TRACE("control @%u: BrIf[depth=%u]\n", i.pc_offset(), imm.depth);
867 242 : Control* c = &control_stack[control_stack.size() - imm.depth - 1];
868 121 : if (!unreachable) c->end_label->Ref(i.pc(), stack_height);
869 : break;
870 : }
871 : case kExprBrTable: {
872 5255 : BranchTableImmediate<Decoder::kNoValidate> imm(&i, i.pc());
873 : BranchTableIterator<Decoder::kNoValidate> iterator(&i, imm);
874 : TRACE("control @%u: BrTable[count=%u]\n", i.pc_offset(),
875 : imm.table_count);
876 5255 : if (!unreachable) {
877 52356 : while (iterator.has_next()) {
878 : uint32_t j = iterator.cur_index();
879 20923 : uint32_t target = iterator.next();
880 41846 : Control* c = &control_stack[control_stack.size() - target - 1];
881 20923 : c->end_label->Ref(i.pc() + j, stack_height);
882 : }
883 : }
884 : break;
885 : }
886 : default:
887 : break;
888 : }
889 2918265 : if (WasmOpcodes::IsUnconditionalJump(opcode)) {
890 38186 : control_stack.back().unreachable = true;
891 : }
892 : }
893 : DCHECK_EQ(0, control_stack.size());
894 458175 : DCHECK_EQ(func_arity, stack_height);
895 458175 : }
896 :
897 : ControlTransferEntry& Lookup(pc_t from) {
898 : auto result = map_.find(from);
899 : DCHECK(result != map_.end());
900 : return result->second;
901 : }
902 : };
903 :
904 : // The main storage for interpreter code. It maps {WasmFunction} to the
905 : // metadata needed to execute each function.
906 : class CodeMap {
907 : Zone* zone_;
908 : const WasmModule* module_;
909 : ZoneVector<InterpreterCode> interpreter_code_;
910 : // TODO(wasm): Remove this testing wart. It is needed because interpreter
911 : // entry stubs are not generated in testing the interpreter in cctests.
912 : bool call_indirect_through_module_ = false;
913 :
914 : public:
915 456796 : CodeMap(const WasmModule* module, const uint8_t* module_start, Zone* zone)
916 913592 : : zone_(zone), module_(module), interpreter_code_(zone) {
917 913592 : if (module == nullptr) return;
918 913592 : interpreter_code_.reserve(module->functions.size());
919 916493 : for (const WasmFunction& function : module->functions) {
920 2901 : if (function.imported) {
921 : DCHECK(!function.code.is_set());
922 1594 : AddFunction(&function, nullptr, nullptr);
923 : } else {
924 : AddFunction(&function, module_start + function.code.offset(),
925 1307 : module_start + function.code.end_offset());
926 : }
927 : }
928 : }
929 :
930 : bool call_indirect_through_module() { return call_indirect_through_module_; }
931 :
932 : void set_call_indirect_through_module(bool val) {
933 455742 : call_indirect_through_module_ = val;
934 : }
935 :
936 : const WasmModule* module() const { return module_; }
937 :
938 : InterpreterCode* GetCode(const WasmFunction* function) {
939 : InterpreterCode* code = GetCode(function->func_index);
940 : DCHECK_EQ(function, code->function);
941 : return code;
942 : }
943 :
944 : InterpreterCode* GetCode(uint32_t function_index) {
945 : DCHECK_LT(function_index, interpreter_code_.size());
946 12640786 : return Preprocess(&interpreter_code_[function_index]);
947 : }
948 :
949 130 : InterpreterCode* GetIndirectCode(uint32_t table_index, uint32_t entry_index) {
950 : uint32_t saved_index;
951 : USE(saved_index);
952 260 : if (table_index >= module_->tables.size()) return nullptr;
953 : // Mask table index for SSCA mitigation.
954 : saved_index = table_index;
955 : table_index &= static_cast<int32_t>((table_index - module_->tables.size()) &
956 130 : ~static_cast<int32_t>(table_index)) >>
957 130 : 31;
958 : DCHECK_EQ(table_index, saved_index);
959 130 : const WasmTable* table = &module_->tables[table_index];
960 260 : if (entry_index >= table->values.size()) return nullptr;
961 : // Mask entry_index for SSCA mitigation.
962 : saved_index = entry_index;
963 : entry_index &= static_cast<int32_t>((entry_index - table->values.size()) &
964 85 : ~static_cast<int32_t>(entry_index)) >>
965 85 : 31;
966 : DCHECK_EQ(entry_index, saved_index);
967 170 : uint32_t index = table->values[entry_index];
968 170 : if (index >= interpreter_code_.size()) return nullptr;
969 : // Mask index for SSCA mitigation.
970 : saved_index = index;
971 : index &= static_cast<int32_t>((index - interpreter_code_.size()) &
972 85 : ~static_cast<int32_t>(index)) >>
973 85 : 31;
974 : DCHECK_EQ(index, saved_index);
975 :
976 85 : return GetCode(index);
977 : }
978 :
979 6777423 : InterpreterCode* Preprocess(InterpreterCode* code) {
980 : DCHECK_EQ(code->function->imported, code->start == nullptr);
981 6777423 : if (!code->side_table && code->start) {
982 : // Compute the control targets map and the local declarations.
983 916290 : code->side_table = new (zone_) SideTable(zone_, module_, code);
984 : }
985 6777423 : return code;
986 : }
987 :
988 461771 : void AddFunction(const WasmFunction* function, const byte* code_start,
989 : const byte* code_end) {
990 : InterpreterCode code = {
991 : function, BodyLocalDecls(zone_), code_start,
992 : code_end, const_cast<byte*>(code_start), const_cast<byte*>(code_end),
993 923542 : nullptr};
994 :
995 : DCHECK_EQ(interpreter_code_.size(), function->func_index);
996 461771 : interpreter_code_.push_back(code);
997 461771 : }
998 :
999 457030 : void SetFunctionCode(const WasmFunction* function, const byte* start,
1000 : const byte* end) {
1001 : DCHECK_LT(function->func_index, interpreter_code_.size());
1002 457030 : InterpreterCode* code = &interpreter_code_[function->func_index];
1003 : DCHECK_EQ(function, code->function);
1004 457030 : code->orig_start = start;
1005 457030 : code->orig_end = end;
1006 457030 : code->start = const_cast<byte*>(start);
1007 457030 : code->end = const_cast<byte*>(end);
1008 457030 : code->side_table = nullptr;
1009 457030 : Preprocess(code);
1010 457030 : }
1011 : };
1012 :
1013 : namespace {
1014 :
1015 : struct ExternalCallResult {
1016 : enum Type {
1017 : // The function should be executed inside this interpreter.
1018 : INTERNAL,
1019 : // For indirect calls: Table or function does not exist.
1020 : INVALID_FUNC,
1021 : // For indirect calls: Signature does not match expected signature.
1022 : SIGNATURE_MISMATCH,
1023 : // The function was executed and returned normally.
1024 : EXTERNAL_RETURNED,
1025 : // The function was executed, threw an exception, and the stack was unwound.
1026 : EXTERNAL_UNWOUND
1027 : };
1028 : Type type;
1029 : // If type is INTERNAL, this field holds the function to call internally.
1030 : InterpreterCode* interpreter_code;
1031 :
1032 : ExternalCallResult(Type type) : type(type) { // NOLINT
1033 : DCHECK_NE(INTERNAL, type);
1034 : }
1035 : ExternalCallResult(Type type, InterpreterCode* code)
1036 : : type(type), interpreter_code(code) {
1037 : DCHECK_EQ(INTERNAL, type);
1038 : }
1039 : };
1040 :
1041 : // Like a static_cast from src to dst, but specialized for boxed floats.
1042 : template <typename dst, typename src>
1043 : struct converter {
1044 984830 : dst operator()(src val) const { return static_cast<dst>(val); }
1045 : };
1046 : template <>
1047 : struct converter<Float64, uint64_t> {
1048 : Float64 operator()(uint64_t val) const { return Float64::FromBits(val); }
1049 : };
1050 : template <>
1051 : struct converter<Float32, uint32_t> {
1052 : Float32 operator()(uint32_t val) const { return Float32::FromBits(val); }
1053 : };
1054 : template <>
1055 : struct converter<uint64_t, Float64> {
1056 : uint64_t operator()(Float64 val) const { return val.get_bits(); }
1057 : };
1058 : template <>
1059 : struct converter<uint32_t, Float32> {
1060 : uint32_t operator()(Float32 val) const { return val.get_bits(); }
1061 : };
1062 :
1063 : template <typename T>
1064 : V8_INLINE bool has_nondeterminism(T val) {
1065 : static_assert(!std::is_floating_point<T>::value, "missing specialization");
1066 : return false;
1067 : }
1068 : template <>
1069 : V8_INLINE bool has_nondeterminism<float>(float val) {
1070 201647 : return std::isnan(val);
1071 : }
1072 : template <>
1073 : V8_INLINE bool has_nondeterminism<double>(double val) {
1074 76256 : return std::isnan(val);
1075 : }
1076 :
1077 : } // namespace
1078 :
1079 : // Responsible for executing code directly.
1080 0 : class ThreadImpl {
1081 : struct Activation {
1082 : uint32_t fp;
1083 : sp_t sp;
1084 39260 : Activation(uint32_t fp, sp_t sp) : fp(fp), sp(sp) {}
1085 : };
1086 :
1087 : public:
1088 : ThreadImpl(Zone* zone, CodeMap* codemap,
1089 : Handle<WasmInstanceObject> instance_object)
1090 : : codemap_(codemap),
1091 : instance_object_(instance_object),
1092 : frames_(zone),
1093 913592 : activations_(zone) {}
1094 :
1095 : //==========================================================================
1096 : // Implementation of public interface for WasmInterpreter::Thread.
1097 : //==========================================================================
1098 :
1099 : WasmInterpreter::State state() { return state_; }
1100 :
1101 5811710 : void InitFrame(const WasmFunction* function, WasmValue* args) {
1102 : DCHECK_EQ(current_activation().fp, frames_.size());
1103 : InterpreterCode* code = codemap()->GetCode(function);
1104 5811710 : size_t num_params = function->sig->parameter_count();
1105 5811710 : EnsureStackSpace(num_params);
1106 : Push(args, num_params);
1107 5811710 : PushFrame(code);
1108 5811710 : }
1109 :
1110 0 : WasmInterpreter::State Run(int num_steps = -1) {
1111 : DCHECK(state_ == WasmInterpreter::STOPPED ||
1112 : state_ == WasmInterpreter::PAUSED);
1113 : DCHECK(num_steps == -1 || num_steps > 0);
1114 : if (num_steps == -1) {
1115 : TRACE(" => Run()\n");
1116 : } else if (num_steps == 1) {
1117 : TRACE(" => Step()\n");
1118 : } else {
1119 : TRACE(" => Run(%d)\n", num_steps);
1120 : }
1121 5818485 : state_ = WasmInterpreter::RUNNING;
1122 5818485 : Execute(frames_.back().code, frames_.back().pc, num_steps);
1123 : // If state_ is STOPPED, the current activation must be fully unwound.
1124 : DCHECK_IMPLIES(state_ == WasmInterpreter::STOPPED,
1125 : current_activation().fp == frames_.size());
1126 5818485 : return state_;
1127 : }
1128 :
1129 0 : void Pause() { UNIMPLEMENTED(); }
1130 :
1131 : void Reset() {
1132 : TRACE("----- RESET -----\n");
1133 5772452 : sp_ = stack_.get();
1134 : frames_.clear();
1135 5772452 : state_ = WasmInterpreter::STOPPED;
1136 5772452 : trap_reason_ = kTrapCount;
1137 5772452 : possible_nondeterminism_ = false;
1138 : }
1139 :
1140 : int GetFrameCount() {
1141 : DCHECK_GE(kMaxInt, frames_.size());
1142 17304 : return static_cast<int>(frames_.size());
1143 : }
1144 :
1145 5765014 : WasmValue GetReturnValue(uint32_t index) {
1146 5765014 : if (state_ == WasmInterpreter::TRAPPED) return WasmValue(0xDEADBEEF);
1147 : DCHECK_EQ(WasmInterpreter::FINISHED, state_);
1148 : Activation act = current_activation();
1149 : // Current activation must be finished.
1150 : DCHECK_EQ(act.fp, frames_.size());
1151 5765014 : return GetStackValue(act.sp + index);
1152 : }
1153 :
1154 : WasmValue GetStackValue(sp_t index) {
1155 : DCHECK_GT(StackHeight(), index);
1156 27809961 : return stack_[index];
1157 : }
1158 :
1159 : void SetStackValue(sp_t index, WasmValue value) {
1160 : DCHECK_GT(StackHeight(), index);
1161 5585720 : stack_[index] = value;
1162 : }
1163 :
1164 : TrapReason GetTrapReason() { return trap_reason_; }
1165 :
1166 : pc_t GetBreakpointPc() { return break_pc_; }
1167 :
1168 : bool PossibleNondeterminism() { return possible_nondeterminism_; }
1169 :
1170 : uint64_t NumInterpretedCalls() { return num_interpreted_calls_; }
1171 :
1172 50 : void AddBreakFlags(uint8_t flags) { break_flags_ |= flags; }
1173 :
1174 0 : void ClearBreakFlags() { break_flags_ = WasmInterpreter::BreakFlag::None; }
1175 :
1176 : uint32_t NumActivations() {
1177 60 : return static_cast<uint32_t>(activations_.size());
1178 : }
1179 :
1180 39260 : uint32_t StartActivation() {
1181 39260 : TRACE("----- START ACTIVATION %zu -----\n", activations_.size());
1182 : // If you use activations, use them consistently:
1183 : DCHECK_IMPLIES(activations_.empty(), frames_.empty());
1184 : DCHECK_IMPLIES(activations_.empty(), StackHeight() == 0);
1185 39260 : uint32_t activation_id = static_cast<uint32_t>(activations_.size());
1186 39260 : activations_.emplace_back(static_cast<uint32_t>(frames_.size()),
1187 78520 : StackHeight());
1188 39260 : state_ = WasmInterpreter::STOPPED;
1189 39260 : return activation_id;
1190 : }
1191 :
1192 : void FinishActivation(uint32_t id) {
1193 : TRACE("----- FINISH ACTIVATION %zu -----\n", activations_.size() - 1);
1194 : DCHECK_LT(0, activations_.size());
1195 : DCHECK_EQ(activations_.size() - 1, id);
1196 : // Stack height must match the start of this activation (otherwise unwind
1197 : // first).
1198 : DCHECK_EQ(activations_.back().fp, frames_.size());
1199 : DCHECK_LE(activations_.back().sp, StackHeight());
1200 39258 : sp_ = stack_.get() + activations_.back().sp;
1201 : activations_.pop_back();
1202 : }
1203 :
1204 : uint32_t ActivationFrameBase(uint32_t id) {
1205 : DCHECK_GT(activations_.size(), id);
1206 14842 : return activations_[id].fp;
1207 : }
1208 :
1209 : // Handle a thrown exception. Returns whether the exception was handled inside
1210 : // the current activation. Unwinds the interpreted stack accordingly.
1211 1252 : WasmInterpreter::Thread::ExceptionHandlingResult HandleException(
1212 : Isolate* isolate) {
1213 : DCHECK(isolate->has_pending_exception());
1214 : // TODO(wasm): Add wasm exception handling (would return HANDLED).
1215 : USE(isolate->pending_exception());
1216 : TRACE("----- UNWIND -----\n");
1217 : DCHECK_LT(0, activations_.size());
1218 : Activation& act = activations_.back();
1219 : DCHECK_LE(act.fp, frames_.size());
1220 1252 : frames_.resize(act.fp);
1221 : DCHECK_LE(act.sp, StackHeight());
1222 1252 : sp_ = stack_.get() + act.sp;
1223 1252 : state_ = WasmInterpreter::STOPPED;
1224 1252 : return WasmInterpreter::Thread::UNWOUND;
1225 : }
1226 :
1227 : private:
1228 : // Entries on the stack of functions being evaluated.
1229 : struct Frame {
1230 : InterpreterCode* code;
1231 : pc_t pc;
1232 : sp_t sp;
1233 :
1234 : // Limit of parameters.
1235 : sp_t plimit() { return sp + code->function->sig->parameter_count(); }
1236 : // Limit of locals.
1237 : sp_t llimit() { return plimit() + code->locals.type_list.size(); }
1238 : };
1239 :
1240 : struct Block {
1241 : pc_t pc;
1242 : sp_t sp;
1243 : size_t fp;
1244 : uint32_t arity;
1245 : };
1246 :
1247 : friend class InterpretedFrameImpl;
1248 :
1249 : CodeMap* codemap_;
1250 : Handle<WasmInstanceObject> instance_object_;
1251 : std::unique_ptr<WasmValue[]> stack_;
1252 : WasmValue* stack_limit_ = nullptr; // End of allocated stack space.
1253 : WasmValue* sp_ = nullptr; // Current stack pointer.
1254 : ZoneVector<Frame> frames_;
1255 : WasmInterpreter::State state_ = WasmInterpreter::STOPPED;
1256 : pc_t break_pc_ = kInvalidPc;
1257 : TrapReason trap_reason_ = kTrapCount;
1258 : bool possible_nondeterminism_ = false;
1259 : uint8_t break_flags_ = 0; // a combination of WasmInterpreter::BreakFlag
1260 : uint64_t num_interpreted_calls_ = 0;
1261 : // Store the stack height of each activation (for unwind and frame
1262 : // inspection).
1263 : ZoneVector<Activation> activations_;
1264 :
1265 : CodeMap* codemap() const { return codemap_; }
1266 31261 : const WasmModule* module() const { return codemap_->module(); }
1267 :
1268 : void DoTrap(TrapReason trap, pc_t pc) {
1269 : TRACE("TRAP: %s\n", WasmOpcodes::TrapReasonMessage(trap));
1270 45281 : state_ = WasmInterpreter::TRAPPED;
1271 45281 : trap_reason_ = trap;
1272 : CommitPc(pc);
1273 : }
1274 :
1275 : // Push a frame with arguments already on the stack.
1276 6311730 : void PushFrame(InterpreterCode* code) {
1277 : DCHECK_NOT_NULL(code);
1278 : DCHECK_NOT_NULL(code->side_table);
1279 : EnsureStackSpace(code->side_table->max_stack_height_ +
1280 12623460 : code->locals.type_list.size());
1281 :
1282 6311730 : ++num_interpreted_calls_;
1283 6311730 : size_t arity = code->function->sig->parameter_count();
1284 : // The parameters will overlap the arguments already on the stack.
1285 : DCHECK_GE(StackHeight(), arity);
1286 18935190 : frames_.push_back({code, 0, StackHeight() - arity});
1287 6311730 : frames_.back().pc = InitLocals(code);
1288 : TRACE(" => PushFrame #%zu (#%u @%zu)\n", frames_.size() - 1,
1289 : code->function->func_index, frames_.back().pc);
1290 6311730 : }
1291 :
1292 6311730 : pc_t InitLocals(InterpreterCode* code) {
1293 26672481 : for (auto p : code->locals.type_list) {
1294 : WasmValue val;
1295 14049021 : switch (p) {
1296 : #define CASE_TYPE(wasm, ctype) \
1297 : case kWasm##wasm: \
1298 : val = WasmValue(ctype{}); \
1299 : break;
1300 14049021 : WASM_CTYPES(CASE_TYPE)
1301 : #undef CASE_TYPE
1302 : default:
1303 0 : UNREACHABLE();
1304 : break;
1305 : }
1306 : Push(val);
1307 : }
1308 6311730 : return code->locals.encoded_size;
1309 : }
1310 :
1311 : void CommitPc(pc_t pc) {
1312 : DCHECK(!frames_.empty());
1313 59028 : frames_.back().pc = pc;
1314 : }
1315 :
1316 : bool SkipBreakpoint(InterpreterCode* code, pc_t pc) {
1317 7490 : if (pc == break_pc_) {
1318 : // Skip the previously hit breakpoint when resuming.
1319 3745 : break_pc_ = kInvalidPc;
1320 : return true;
1321 : }
1322 : return false;
1323 : }
1324 :
1325 : int LookupTargetDelta(InterpreterCode* code, pc_t pc) {
1326 3985940 : return static_cast<int>(code->side_table->Lookup(pc).pc_diff);
1327 : }
1328 :
1329 318030 : int DoBreak(InterpreterCode* code, pc_t pc, size_t depth) {
1330 318030 : ControlTransferEntry& control_transfer_entry = code->side_table->Lookup(pc);
1331 318030 : DoStackTransfer(sp_ - control_transfer_entry.sp_diff,
1332 636060 : control_transfer_entry.target_arity);
1333 318030 : return control_transfer_entry.pc_diff;
1334 : }
1335 :
1336 243878 : pc_t ReturnPc(Decoder* decoder, InterpreterCode* code, pc_t pc) {
1337 121939 : switch (code->orig_start[pc]) {
1338 : case kExprCallFunction: {
1339 : CallFunctionImmediate<Decoder::kNoValidate> imm(decoder, code->at(pc));
1340 121850 : return pc + 1 + imm.length;
1341 : }
1342 : case kExprCallIndirect: {
1343 89 : CallIndirectImmediate<Decoder::kNoValidate> imm(decoder, code->at(pc));
1344 89 : return pc + 1 + imm.length;
1345 : }
1346 : default:
1347 0 : UNREACHABLE();
1348 : }
1349 : }
1350 :
1351 5887196 : bool DoReturn(Decoder* decoder, InterpreterCode** code, pc_t* pc, pc_t* limit,
1352 : size_t arity) {
1353 : DCHECK_GT(frames_.size(), 0);
1354 11774392 : WasmValue* sp_dest = stack_.get() + frames_.back().sp;
1355 : frames_.pop_back();
1356 5887196 : if (frames_.size() == current_activation().fp) {
1357 : // A return from the last frame terminates the execution.
1358 5765257 : state_ = WasmInterpreter::FINISHED;
1359 5765257 : DoStackTransfer(sp_dest, arity);
1360 : TRACE(" => finish\n");
1361 5765257 : return false;
1362 : } else {
1363 : // Return to caller frame.
1364 : Frame* top = &frames_.back();
1365 121939 : *code = top->code;
1366 121939 : decoder->Reset((*code)->start, (*code)->end);
1367 121939 : *pc = ReturnPc(decoder, *code, top->pc);
1368 121939 : *limit = top->code->end - top->code->start;
1369 : TRACE(" => Return to #%zu (#%u @%zu)\n", frames_.size() - 1,
1370 : (*code)->function->func_index, *pc);
1371 121939 : DoStackTransfer(sp_dest, arity);
1372 121939 : return true;
1373 : }
1374 : }
1375 :
1376 : // Returns true if the call was successful, false if the stack check failed
1377 : // and the current activation was fully unwound.
1378 500020 : bool DoCall(Decoder* decoder, InterpreterCode* target, pc_t* pc,
1379 : pc_t* limit) V8_WARN_UNUSED_RESULT {
1380 500020 : frames_.back().pc = *pc;
1381 500020 : PushFrame(target);
1382 500020 : if (!DoStackCheck()) return false;
1383 500002 : *pc = frames_.back().pc;
1384 500002 : *limit = target->end - target->start;
1385 500002 : decoder->Reset(target->start, target->end);
1386 500002 : return true;
1387 : }
1388 :
1389 : // Copies {arity} values on the top of the stack down the stack to {dest},
1390 : // dropping the values in-between.
1391 6205226 : void DoStackTransfer(WasmValue* dest, size_t arity) {
1392 : // before: |---------------| pop_count | arity |
1393 : // ^ 0 ^ dest ^ sp_
1394 : //
1395 : // after: |---------------| arity |
1396 : // ^ 0 ^ sp_
1397 : DCHECK_LE(dest, sp_);
1398 : DCHECK_LE(dest + arity, sp_);
1399 6205226 : if (arity) memmove(dest, sp_ - arity, arity * sizeof(*sp_));
1400 6205226 : sp_ = dest + arity;
1401 6205226 : }
1402 :
1403 : template <typename mtype>
1404 7664970 : inline Address BoundsCheckMem(uint32_t offset, uint32_t index) {
1405 7664970 : uint32_t effective_index = offset + index;
1406 7664970 : if (effective_index < index) {
1407 : return kNullAddress; // wraparound => oob
1408 : }
1409 7664970 : if (!IsInBounds(effective_index, sizeof(mtype),
1410 7664970 : instance_object_->memory_size())) {
1411 : return kNullAddress; // oob
1412 : }
1413 : // Compute the effective address of the access, making sure to condition
1414 : // the index even in the in-bounds case.
1415 : return reinterpret_cast<Address>(instance_object_->memory_start()) +
1416 15318264 : (effective_index & instance_object_->memory_mask());
1417 : }
1418 :
1419 : template <typename ctype, typename mtype>
1420 3966160 : bool ExecuteLoad(Decoder* decoder, InterpreterCode* code, pc_t pc, int& len,
1421 : MachineRepresentation rep) {
1422 : MemoryAccessImmediate<Decoder::kNoValidate> imm(decoder, code->at(pc),
1423 3966160 : sizeof(ctype));
1424 : uint32_t index = Pop().to<uint32_t>();
1425 3966160 : Address addr = BoundsCheckMem<mtype>(imm.offset, index);
1426 3966160 : if (!addr) {
1427 : DoTrap(kTrapMemOutOfBounds, pc);
1428 2658 : return false;
1429 : }
1430 : WasmValue result(
1431 : converter<ctype, mtype>{}(ReadLittleEndianValue<mtype>(addr)));
1432 :
1433 : Push(result);
1434 3963502 : len = 1 + imm.length;
1435 :
1436 3963502 : if (FLAG_trace_wasm_memory) {
1437 35 : MemoryTracingInfo info(imm.offset + index, false, rep);
1438 35 : TraceMemoryOperation(ExecutionTier::kInterpreter, &info,
1439 : code->function->func_index, static_cast<int>(pc),
1440 35 : instance_object_->memory_start());
1441 : }
1442 :
1443 : return true;
1444 : }
1445 :
1446 : template <typename ctype, typename mtype>
1447 3217170 : bool ExecuteStore(Decoder* decoder, InterpreterCode* code, pc_t pc, int& len,
1448 : MachineRepresentation rep) {
1449 : MemoryAccessImmediate<Decoder::kNoValidate> imm(decoder, code->at(pc),
1450 3217170 : sizeof(ctype));
1451 0 : ctype val = Pop().to<ctype>();
1452 :
1453 : uint32_t index = Pop().to<uint32_t>();
1454 3217170 : Address addr = BoundsCheckMem<mtype>(imm.offset, index);
1455 3217170 : if (!addr) {
1456 : DoTrap(kTrapMemOutOfBounds, pc);
1457 1620 : return false;
1458 : }
1459 : WriteLittleEndianValue<mtype>(addr, converter<mtype, ctype>{}(val));
1460 3215550 : len = 1 + imm.length;
1461 :
1462 3215550 : if (FLAG_trace_wasm_memory) {
1463 10 : MemoryTracingInfo info(imm.offset + index, true, rep);
1464 10 : TraceMemoryOperation(ExecutionTier::kInterpreter, &info,
1465 : code->function->func_index, static_cast<int>(pc),
1466 10 : instance_object_->memory_start());
1467 : }
1468 :
1469 : return true;
1470 : }
1471 :
1472 : template <typename type, typename op_type>
1473 960110 : bool ExtractAtomicOpParams(Decoder* decoder, InterpreterCode* code,
1474 : Address& address, pc_t pc, int& len,
1475 : type* val = nullptr, type* val2 = nullptr) {
1476 : MemoryAccessImmediate<Decoder::kNoValidate> imm(decoder, code->at(pc + 1),
1477 960110 : sizeof(type));
1478 548130 : if (val2) *val2 = static_cast<type>(Pop().to<op_type>());
1479 957770 : if (val) *val = static_cast<type>(Pop().to<op_type>());
1480 : uint32_t index = Pop().to<uint32_t>();
1481 480055 : address = BoundsCheckMem<type>(imm.offset, index);
1482 480055 : if (!address) {
1483 : DoTrap(kTrapMemOutOfBounds, pc);
1484 0 : return false;
1485 : }
1486 480055 : len = 2 + imm.length;
1487 480055 : return true;
1488 : }
1489 :
1490 3280 : bool ExecuteNumericOp(WasmOpcode opcode, Decoder* decoder,
1491 : InterpreterCode* code, pc_t pc, int& len) {
1492 3280 : switch (opcode) {
1493 : case kExprI32SConvertSatF32:
1494 575 : Push(WasmValue(ExecuteConvertSaturate<int32_t>(Pop().to<float>())));
1495 575 : return true;
1496 : case kExprI32UConvertSatF32:
1497 575 : Push(WasmValue(ExecuteConvertSaturate<uint32_t>(Pop().to<float>())));
1498 575 : return true;
1499 : case kExprI32SConvertSatF64:
1500 245 : Push(WasmValue(ExecuteConvertSaturate<int32_t>(Pop().to<double>())));
1501 245 : return true;
1502 : case kExprI32UConvertSatF64:
1503 245 : Push(WasmValue(ExecuteConvertSaturate<uint32_t>(Pop().to<double>())));
1504 245 : return true;
1505 : case kExprI64SConvertSatF32:
1506 1150 : Push(WasmValue(ExecuteI64SConvertSatF32(Pop().to<float>())));
1507 575 : return true;
1508 : case kExprI64UConvertSatF32:
1509 1150 : Push(WasmValue(ExecuteI64UConvertSatF32(Pop().to<float>())));
1510 575 : return true;
1511 : case kExprI64SConvertSatF64:
1512 490 : Push(WasmValue(ExecuteI64SConvertSatF64(Pop().to<double>())));
1513 245 : return true;
1514 : case kExprI64UConvertSatF64:
1515 490 : Push(WasmValue(ExecuteI64UConvertSatF64(Pop().to<double>())));
1516 245 : return true;
1517 : default:
1518 0 : FATAL("Unknown or unimplemented opcode #%d:%s", code->start[pc],
1519 0 : OpcodeName(code->start[pc]));
1520 : UNREACHABLE();
1521 : }
1522 : return false;
1523 : }
1524 :
1525 480055 : bool ExecuteAtomicOp(WasmOpcode opcode, Decoder* decoder,
1526 : InterpreterCode* code, pc_t pc, int& len) {
1527 : WasmValue result;
1528 480055 : switch (opcode) {
1529 : // Disabling on Mips as 32 bit atomics are not correctly laid out for load/store
1530 : // on big endian and 64 bit atomics fail to compile.
1531 : #if !(V8_TARGET_ARCH_MIPS && V8_TARGET_BIG_ENDIAN)
1532 : #define ATOMIC_BINOP_CASE(name, type, op_type, operation) \
1533 : case kExpr##name: { \
1534 : type val; \
1535 : Address addr; \
1536 : if (!ExtractAtomicOpParams<type, op_type>(decoder, code, addr, pc, len, \
1537 : &val)) { \
1538 : return false; \
1539 : } \
1540 : static_assert(sizeof(std::atomic<type>) == sizeof(type), \
1541 : "Size mismatch for types std::atomic<" #type \
1542 : ">, and " #type); \
1543 : result = WasmValue(static_cast<op_type>( \
1544 : std::operation(reinterpret_cast<std::atomic<type>*>(addr), val))); \
1545 : Push(result); \
1546 : break; \
1547 : }
1548 50475 : ATOMIC_BINOP_CASE(I32AtomicAdd, uint32_t, uint32_t, atomic_fetch_add);
1549 1620 : ATOMIC_BINOP_CASE(I32AtomicAdd8U, uint8_t, uint32_t, atomic_fetch_add);
1550 1620 : ATOMIC_BINOP_CASE(I32AtomicAdd16U, uint16_t, uint32_t, atomic_fetch_add);
1551 50460 : ATOMIC_BINOP_CASE(I32AtomicSub, uint32_t, uint32_t, atomic_fetch_sub);
1552 1620 : ATOMIC_BINOP_CASE(I32AtomicSub8U, uint8_t, uint32_t, atomic_fetch_sub);
1553 1620 : ATOMIC_BINOP_CASE(I32AtomicSub16U, uint16_t, uint32_t, atomic_fetch_sub);
1554 50460 : ATOMIC_BINOP_CASE(I32AtomicAnd, uint32_t, uint32_t, atomic_fetch_and);
1555 1620 : ATOMIC_BINOP_CASE(I32AtomicAnd8U, uint8_t, uint32_t, atomic_fetch_and);
1556 1620 : ATOMIC_BINOP_CASE(I32AtomicAnd16U, uint16_t, uint32_t, atomic_fetch_and);
1557 50460 : ATOMIC_BINOP_CASE(I32AtomicOr, uint32_t, uint32_t, atomic_fetch_or);
1558 1620 : ATOMIC_BINOP_CASE(I32AtomicOr8U, uint8_t, uint32_t, atomic_fetch_or);
1559 1620 : ATOMIC_BINOP_CASE(I32AtomicOr16U, uint16_t, uint32_t, atomic_fetch_or);
1560 50460 : ATOMIC_BINOP_CASE(I32AtomicXor, uint32_t, uint32_t, atomic_fetch_xor);
1561 1620 : ATOMIC_BINOP_CASE(I32AtomicXor8U, uint8_t, uint32_t, atomic_fetch_xor);
1562 1620 : ATOMIC_BINOP_CASE(I32AtomicXor16U, uint16_t, uint32_t, atomic_fetch_xor);
1563 50460 : ATOMIC_BINOP_CASE(I32AtomicExchange, uint32_t, uint32_t, atomic_exchange);
1564 1620 : ATOMIC_BINOP_CASE(I32AtomicExchange8U, uint8_t, uint32_t,
1565 : atomic_exchange);
1566 1620 : ATOMIC_BINOP_CASE(I32AtomicExchange16U, uint16_t, uint32_t,
1567 : atomic_exchange);
1568 98535 : ATOMIC_BINOP_CASE(I64AtomicAdd, uint64_t, uint64_t, atomic_fetch_add);
1569 1620 : ATOMIC_BINOP_CASE(I64AtomicAdd8U, uint8_t, uint64_t, atomic_fetch_add);
1570 1620 : ATOMIC_BINOP_CASE(I64AtomicAdd16U, uint16_t, uint64_t, atomic_fetch_add);
1571 67280 : ATOMIC_BINOP_CASE(I64AtomicAdd32U, uint32_t, uint64_t, atomic_fetch_add);
1572 98430 : ATOMIC_BINOP_CASE(I64AtomicSub, uint64_t, uint64_t, atomic_fetch_sub);
1573 1620 : ATOMIC_BINOP_CASE(I64AtomicSub8U, uint8_t, uint64_t, atomic_fetch_sub);
1574 1640 : ATOMIC_BINOP_CASE(I64AtomicSub16U, uint16_t, uint64_t, atomic_fetch_sub);
1575 67280 : ATOMIC_BINOP_CASE(I64AtomicSub32U, uint32_t, uint64_t, atomic_fetch_sub);
1576 98430 : ATOMIC_BINOP_CASE(I64AtomicAnd, uint64_t, uint64_t, atomic_fetch_and);
1577 1620 : ATOMIC_BINOP_CASE(I64AtomicAnd8U, uint8_t, uint64_t, atomic_fetch_and);
1578 1620 : ATOMIC_BINOP_CASE(I64AtomicAnd16U, uint16_t, uint64_t, atomic_fetch_and);
1579 67280 : ATOMIC_BINOP_CASE(I64AtomicAnd32U, uint32_t, uint64_t, atomic_fetch_and);
1580 98430 : ATOMIC_BINOP_CASE(I64AtomicOr, uint64_t, uint64_t, atomic_fetch_or);
1581 1620 : ATOMIC_BINOP_CASE(I64AtomicOr8U, uint8_t, uint64_t, atomic_fetch_or);
1582 1620 : ATOMIC_BINOP_CASE(I64AtomicOr16U, uint16_t, uint64_t, atomic_fetch_or);
1583 67280 : ATOMIC_BINOP_CASE(I64AtomicOr32U, uint32_t, uint64_t, atomic_fetch_or);
1584 98430 : ATOMIC_BINOP_CASE(I64AtomicXor, uint64_t, uint64_t, atomic_fetch_xor);
1585 1620 : ATOMIC_BINOP_CASE(I64AtomicXor8U, uint8_t, uint64_t, atomic_fetch_xor);
1586 1620 : ATOMIC_BINOP_CASE(I64AtomicXor16U, uint16_t, uint64_t, atomic_fetch_xor);
1587 67280 : ATOMIC_BINOP_CASE(I64AtomicXor32U, uint32_t, uint64_t, atomic_fetch_xor);
1588 98430 : ATOMIC_BINOP_CASE(I64AtomicExchange, uint64_t, uint64_t, atomic_exchange);
1589 1620 : ATOMIC_BINOP_CASE(I64AtomicExchange8U, uint8_t, uint64_t,
1590 : atomic_exchange);
1591 1620 : ATOMIC_BINOP_CASE(I64AtomicExchange16U, uint16_t, uint64_t,
1592 : atomic_exchange);
1593 67280 : ATOMIC_BINOP_CASE(I64AtomicExchange32U, uint32_t, uint64_t,
1594 : atomic_exchange);
1595 : #undef ATOMIC_BINOP_CASE
1596 : #define ATOMIC_COMPARE_EXCHANGE_CASE(name, type, op_type) \
1597 : case kExpr##name: { \
1598 : type val; \
1599 : type val2; \
1600 : Address addr; \
1601 : if (!ExtractAtomicOpParams<type, op_type>(decoder, code, addr, pc, len, \
1602 : &val, &val2)) { \
1603 : return false; \
1604 : } \
1605 : static_assert(sizeof(std::atomic<type>) == sizeof(type), \
1606 : "Size mismatch for types std::atomic<" #type \
1607 : ">, and " #type); \
1608 : std::atomic_compare_exchange_strong( \
1609 : reinterpret_cast<std::atomic<type>*>(addr), &val, val2); \
1610 : Push(WasmValue(static_cast<op_type>(val))); \
1611 : break; \
1612 : }
1613 50460 : ATOMIC_COMPARE_EXCHANGE_CASE(I32AtomicCompareExchange, uint32_t,
1614 : uint32_t);
1615 1215 : ATOMIC_COMPARE_EXCHANGE_CASE(I32AtomicCompareExchange8U, uint8_t,
1616 : uint32_t);
1617 1215 : ATOMIC_COMPARE_EXCHANGE_CASE(I32AtomicCompareExchange16U, uint16_t,
1618 : uint32_t);
1619 98445 : ATOMIC_COMPARE_EXCHANGE_CASE(I64AtomicCompareExchange, uint64_t,
1620 : uint64_t);
1621 1215 : ATOMIC_COMPARE_EXCHANGE_CASE(I64AtomicCompareExchange8U, uint8_t,
1622 : uint64_t);
1623 1215 : ATOMIC_COMPARE_EXCHANGE_CASE(I64AtomicCompareExchange16U, uint16_t,
1624 : uint64_t);
1625 50460 : ATOMIC_COMPARE_EXCHANGE_CASE(I64AtomicCompareExchange32U, uint32_t,
1626 : uint64_t);
1627 : #undef ATOMIC_COMPARE_EXCHANGE_CASE
1628 : #define ATOMIC_LOAD_CASE(name, type, op_type, operation) \
1629 : case kExpr##name: { \
1630 : Address addr; \
1631 : if (!ExtractAtomicOpParams<type, op_type>(decoder, code, addr, pc, len)) { \
1632 : return false; \
1633 : } \
1634 : static_assert(sizeof(std::atomic<type>) == sizeof(type), \
1635 : "Size mismatch for types std::atomic<" #type \
1636 : ">, and " #type); \
1637 : result = WasmValue(static_cast<op_type>( \
1638 : std::operation(reinterpret_cast<std::atomic<type>*>(addr)))); \
1639 : Push(result); \
1640 : break; \
1641 : }
1642 1740 : ATOMIC_LOAD_CASE(I32AtomicLoad, uint32_t, uint32_t, atomic_load);
1643 360 : ATOMIC_LOAD_CASE(I32AtomicLoad8U, uint8_t, uint32_t, atomic_load);
1644 360 : ATOMIC_LOAD_CASE(I32AtomicLoad16U, uint16_t, uint32_t, atomic_load);
1645 2460 : ATOMIC_LOAD_CASE(I64AtomicLoad, uint64_t, uint64_t, atomic_load);
1646 360 : ATOMIC_LOAD_CASE(I64AtomicLoad8U, uint8_t, uint64_t, atomic_load);
1647 360 : ATOMIC_LOAD_CASE(I64AtomicLoad16U, uint16_t, uint64_t, atomic_load);
1648 2320 : ATOMIC_LOAD_CASE(I64AtomicLoad32U, uint32_t, uint64_t, atomic_load);
1649 : #undef ATOMIC_LOAD_CASE
1650 : #define ATOMIC_STORE_CASE(name, type, op_type, operation) \
1651 : case kExpr##name: { \
1652 : type val; \
1653 : Address addr; \
1654 : if (!ExtractAtomicOpParams<type, op_type>(decoder, code, addr, pc, len, \
1655 : &val)) { \
1656 : return false; \
1657 : } \
1658 : static_assert(sizeof(std::atomic<type>) == sizeof(type), \
1659 : "Size mismatch for types std::atomic<" #type \
1660 : ">, and " #type); \
1661 : std::operation(reinterpret_cast<std::atomic<type>*>(addr), val); \
1662 : break; \
1663 : }
1664 590 : ATOMIC_STORE_CASE(I32AtomicStore, uint32_t, uint32_t, atomic_store);
1665 90 : ATOMIC_STORE_CASE(I32AtomicStore8U, uint8_t, uint32_t, atomic_store);
1666 90 : ATOMIC_STORE_CASE(I32AtomicStore16U, uint16_t, uint32_t, atomic_store);
1667 820 : ATOMIC_STORE_CASE(I64AtomicStore, uint64_t, uint64_t, atomic_store);
1668 90 : ATOMIC_STORE_CASE(I64AtomicStore8U, uint8_t, uint64_t, atomic_store);
1669 90 : ATOMIC_STORE_CASE(I64AtomicStore16U, uint16_t, uint64_t, atomic_store);
1670 580 : ATOMIC_STORE_CASE(I64AtomicStore32U, uint32_t, uint64_t, atomic_store);
1671 : #undef ATOMIC_STORE_CASE
1672 : #endif // !(V8_TARGET_ARCH_MIPS && V8_TARGET_BIG_ENDIAN)
1673 : default:
1674 0 : UNREACHABLE();
1675 : return false;
1676 : }
1677 : return true;
1678 : }
1679 :
1680 24343 : byte* GetGlobalPtr(const WasmGlobal* global) {
1681 24343 : if (global->mutability && global->imported) {
1682 : return reinterpret_cast<byte*>(
1683 0 : instance_object_->imported_mutable_globals()[global->index]);
1684 : } else {
1685 24343 : return instance_object_->globals_start() + global->offset;
1686 : }
1687 : }
1688 :
1689 10662745 : bool ExecuteSimdOp(WasmOpcode opcode, Decoder* decoder, InterpreterCode* code,
1690 : pc_t pc, int& len) {
1691 6652090 : switch (opcode) {
1692 : #define SPLAT_CASE(format, sType, valType, num) \
1693 : case kExpr##format##Splat: { \
1694 : WasmValue val = Pop(); \
1695 : valType v = val.to<valType>(); \
1696 : sType s; \
1697 : for (int i = 0; i < num; i++) s.val[i] = v; \
1698 : Push(WasmValue(Simd128(s))); \
1699 : return true; \
1700 : }
1701 1468710 : SPLAT_CASE(I32x4, int4, int32_t, 4)
1702 1971360 : SPLAT_CASE(F32x4, float4, float, 4)
1703 39980 : SPLAT_CASE(I16x8, int8, int32_t, 8)
1704 36200 : SPLAT_CASE(I8x16, int16, int32_t, 16)
1705 : #undef SPLAT_CASE
1706 : #define EXTRACT_LANE_CASE(format, name) \
1707 : case kExpr##format##ExtractLane: { \
1708 : SimdLaneImmediate<Decoder::kNoValidate> imm(decoder, code->at(pc)); \
1709 : ++len; \
1710 : WasmValue val = Pop(); \
1711 : Simd128 s = val.to_s128(); \
1712 : auto ss = s.to_##name(); \
1713 : Push(WasmValue(ss.val[LANE(imm.lane, ss)])); \
1714 : return true; \
1715 : }
1716 10178820 : EXTRACT_LANE_CASE(I32x4, i32x4)
1717 3592240 : EXTRACT_LANE_CASE(F32x4, f32x4)
1718 1423360 : EXTRACT_LANE_CASE(I16x8, i16x8)
1719 666080 : EXTRACT_LANE_CASE(I8x16, i8x16)
1720 : #undef EXTRACT_LANE_CASE
1721 : #define BINOP_CASE(op, name, stype, count, expr) \
1722 : case kExpr##op: { \
1723 : WasmValue v2 = Pop(); \
1724 : WasmValue v1 = Pop(); \
1725 : stype s1 = v1.to_s128().to_##name(); \
1726 : stype s2 = v2.to_s128().to_##name(); \
1727 : stype res; \
1728 : for (size_t i = 0; i < count; ++i) { \
1729 : auto a = s1.val[LANE(i, s1)]; \
1730 : auto b = s2.val[LANE(i, s1)]; \
1731 : res.val[LANE(i, s1)] = expr; \
1732 : } \
1733 : Push(WasmValue(Simd128(res))); \
1734 : return true; \
1735 : }
1736 225725 : BINOP_CASE(F32x4Add, f32x4, float4, 4, a + b)
1737 225625 : BINOP_CASE(F32x4Sub, f32x4, float4, 4, a - b)
1738 201400 : BINOP_CASE(F32x4Mul, f32x4, float4, 4, a * b)
1739 225625 : BINOP_CASE(F32x4Min, f32x4, float4, 4, a < b ? a : b)
1740 225625 : BINOP_CASE(F32x4Max, f32x4, float4, 4, a > b ? a : b)
1741 151650 : BINOP_CASE(I32x4Add, i32x4, int4, 4, base::AddWithWraparound(a, b))
1742 151380 : BINOP_CASE(I32x4Sub, i32x4, int4, 4, base::SubWithWraparound(a, b))
1743 151380 : BINOP_CASE(I32x4Mul, i32x4, int4, 4, base::MulWithWraparound(a, b))
1744 84100 : BINOP_CASE(I32x4MinS, i32x4, int4, 4, a < b ? a : b)
1745 84100 : BINOP_CASE(I32x4MinU, i32x4, int4, 4,
1746 : static_cast<uint32_t>(a) < static_cast<uint32_t>(b) ? a : b)
1747 84100 : BINOP_CASE(I32x4MaxS, i32x4, int4, 4, a > b ? a : b)
1748 84100 : BINOP_CASE(I32x4MaxU, i32x4, int4, 4,
1749 : static_cast<uint32_t>(a) > static_cast<uint32_t>(b) ? a : b)
1750 84100 : BINOP_CASE(S128And, i32x4, int4, 4, a & b)
1751 84100 : BINOP_CASE(S128Or, i32x4, int4, 4, a | b)
1752 84100 : BINOP_CASE(S128Xor, i32x4, int4, 4, a ^ b)
1753 5265 : BINOP_CASE(I16x8Add, i16x8, int8, 8, base::AddWithWraparound(a, b))
1754 5265 : BINOP_CASE(I16x8Sub, i16x8, int8, 8, base::SubWithWraparound(a, b))
1755 5265 : BINOP_CASE(I16x8Mul, i16x8, int8, 8, base::MulWithWraparound(a, b))
1756 2025 : BINOP_CASE(I16x8MinS, i16x8, int8, 8, a < b ? a : b)
1757 2025 : BINOP_CASE(I16x8MinU, i16x8, int8, 8,
1758 : static_cast<uint16_t>(a) < static_cast<uint16_t>(b) ? a : b)
1759 2025 : BINOP_CASE(I16x8MaxS, i16x8, int8, 8, a > b ? a : b)
1760 2025 : BINOP_CASE(I16x8MaxU, i16x8, int8, 8,
1761 : static_cast<uint16_t>(a) > static_cast<uint16_t>(b) ? a : b)
1762 2025 : BINOP_CASE(I16x8AddSaturateS, i16x8, int8, 8, SaturateAdd<int16_t>(a, b))
1763 5265 : BINOP_CASE(I16x8AddSaturateU, i16x8, int8, 8, SaturateAdd<uint16_t>(a, b))
1764 2025 : BINOP_CASE(I16x8SubSaturateS, i16x8, int8, 8, SaturateSub<int16_t>(a, b))
1765 5265 : BINOP_CASE(I16x8SubSaturateU, i16x8, int8, 8, SaturateSub<uint16_t>(a, b))
1766 8505 : BINOP_CASE(I8x16Add, i8x16, int16, 16, base::AddWithWraparound(a, b))
1767 8505 : BINOP_CASE(I8x16Sub, i8x16, int16, 16, base::SubWithWraparound(a, b))
1768 8505 : BINOP_CASE(I8x16Mul, i8x16, int16, 16, base::MulWithWraparound(a, b))
1769 2025 : BINOP_CASE(I8x16MinS, i8x16, int16, 16, a < b ? a : b)
1770 2025 : BINOP_CASE(I8x16MinU, i8x16, int16, 16,
1771 : static_cast<uint8_t>(a) < static_cast<uint8_t>(b) ? a : b)
1772 2025 : BINOP_CASE(I8x16MaxS, i8x16, int16, 16, a > b ? a : b)
1773 2025 : BINOP_CASE(I8x16MaxU, i8x16, int16, 16,
1774 : static_cast<uint8_t>(a) > static_cast<uint8_t>(b) ? a : b)
1775 2025 : BINOP_CASE(I8x16AddSaturateS, i8x16, int16, 16, SaturateAdd<int8_t>(a, b))
1776 8505 : BINOP_CASE(I8x16AddSaturateU, i8x16, int16, 16,
1777 : SaturateAdd<uint8_t>(a, b))
1778 2025 : BINOP_CASE(I8x16SubSaturateS, i8x16, int16, 16, SaturateSub<int8_t>(a, b))
1779 8505 : BINOP_CASE(I8x16SubSaturateU, i8x16, int16, 16,
1780 : SaturateSub<uint8_t>(a, b))
1781 : #undef BINOP_CASE
1782 : #define UNOP_CASE(op, name, stype, count, expr) \
1783 : case kExpr##op: { \
1784 : WasmValue v = Pop(); \
1785 : stype s = v.to_s128().to_##name(); \
1786 : stype res; \
1787 : for (size_t i = 0; i < count; ++i) { \
1788 : auto a = s.val[i]; \
1789 : res.val[i] = expr; \
1790 : } \
1791 : Push(WasmValue(Simd128(res))); \
1792 : return true; \
1793 : }
1794 3325 : UNOP_CASE(F32x4Abs, f32x4, float4, 4, std::abs(a))
1795 1425 : UNOP_CASE(F32x4Neg, f32x4, float4, 4, -a)
1796 3255 : UNOP_CASE(F32x4RecipApprox, f32x4, float4, 4, base::Recip(a))
1797 600 : UNOP_CASE(F32x4RecipSqrtApprox, f32x4, float4, 4, base::RecipSqrt(a))
1798 2030 : UNOP_CASE(I32x4Neg, i32x4, int4, 4, base::NegateWithWraparound(a))
1799 870 : UNOP_CASE(S128Not, i32x4, int4, 4, ~a)
1800 495 : UNOP_CASE(I16x8Neg, i16x8, int8, 8, base::NegateWithWraparound(a))
1801 855 : UNOP_CASE(I8x16Neg, i8x16, int16, 16, base::NegateWithWraparound(a))
1802 : #undef UNOP_CASE
1803 : #define CMPOP_CASE(op, name, stype, out_stype, count, expr) \
1804 : case kExpr##op: { \
1805 : WasmValue v2 = Pop(); \
1806 : WasmValue v1 = Pop(); \
1807 : stype s1 = v1.to_s128().to_##name(); \
1808 : stype s2 = v2.to_s128().to_##name(); \
1809 : out_stype res; \
1810 : for (size_t i = 0; i < count; ++i) { \
1811 : auto a = s1.val[i]; \
1812 : auto b = s2.val[i]; \
1813 : res.val[i] = expr ? -1 : 0; \
1814 : } \
1815 : Push(WasmValue(Simd128(res))); \
1816 : return true; \
1817 : }
1818 225625 : CMPOP_CASE(F32x4Eq, f32x4, float4, int4, 4, a == b)
1819 225625 : CMPOP_CASE(F32x4Ne, f32x4, float4, int4, 4, a != b)
1820 225625 : CMPOP_CASE(F32x4Gt, f32x4, float4, int4, 4, a > b)
1821 225625 : CMPOP_CASE(F32x4Ge, f32x4, float4, int4, 4, a >= b)
1822 225625 : CMPOP_CASE(F32x4Lt, f32x4, float4, int4, 4, a < b)
1823 225625 : CMPOP_CASE(F32x4Le, f32x4, float4, int4, 4, a <= b)
1824 84200 : CMPOP_CASE(I32x4Eq, i32x4, int4, int4, 4, a == b)
1825 84200 : CMPOP_CASE(I32x4Ne, i32x4, int4, int4, 4, a != b)
1826 84100 : CMPOP_CASE(I32x4GtS, i32x4, int4, int4, 4, a > b)
1827 84100 : CMPOP_CASE(I32x4GeS, i32x4, int4, int4, 4, a >= b)
1828 84100 : CMPOP_CASE(I32x4LtS, i32x4, int4, int4, 4, a < b)
1829 84100 : CMPOP_CASE(I32x4LeS, i32x4, int4, int4, 4, a <= b)
1830 84100 : CMPOP_CASE(I32x4GtU, i32x4, int4, int4, 4,
1831 : static_cast<uint32_t>(a) > static_cast<uint32_t>(b))
1832 84100 : CMPOP_CASE(I32x4GeU, i32x4, int4, int4, 4,
1833 : static_cast<uint32_t>(a) >= static_cast<uint32_t>(b))
1834 84100 : CMPOP_CASE(I32x4LtU, i32x4, int4, int4, 4,
1835 : static_cast<uint32_t>(a) < static_cast<uint32_t>(b))
1836 84100 : CMPOP_CASE(I32x4LeU, i32x4, int4, int4, 4,
1837 : static_cast<uint32_t>(a) <= static_cast<uint32_t>(b))
1838 2125 : CMPOP_CASE(I16x8Eq, i16x8, int8, int8, 8, a == b)
1839 2125 : CMPOP_CASE(I16x8Ne, i16x8, int8, int8, 8, a != b)
1840 2025 : CMPOP_CASE(I16x8GtS, i16x8, int8, int8, 8, a > b)
1841 2025 : CMPOP_CASE(I16x8GeS, i16x8, int8, int8, 8, a >= b)
1842 2025 : CMPOP_CASE(I16x8LtS, i16x8, int8, int8, 8, a < b)
1843 2025 : CMPOP_CASE(I16x8LeS, i16x8, int8, int8, 8, a <= b)
1844 2025 : CMPOP_CASE(I16x8GtU, i16x8, int8, int8, 8,
1845 : static_cast<uint16_t>(a) > static_cast<uint16_t>(b))
1846 2025 : CMPOP_CASE(I16x8GeU, i16x8, int8, int8, 8,
1847 : static_cast<uint16_t>(a) >= static_cast<uint16_t>(b))
1848 2025 : CMPOP_CASE(I16x8LtU, i16x8, int8, int8, 8,
1849 : static_cast<uint16_t>(a) < static_cast<uint16_t>(b))
1850 2025 : CMPOP_CASE(I16x8LeU, i16x8, int8, int8, 8,
1851 : static_cast<uint16_t>(a) <= static_cast<uint16_t>(b))
1852 2125 : CMPOP_CASE(I8x16Eq, i8x16, int16, int16, 16, a == b)
1853 2125 : CMPOP_CASE(I8x16Ne, i8x16, int16, int16, 16, a != b)
1854 2025 : CMPOP_CASE(I8x16GtS, i8x16, int16, int16, 16, a > b)
1855 2025 : CMPOP_CASE(I8x16GeS, i8x16, int16, int16, 16, a >= b)
1856 2025 : CMPOP_CASE(I8x16LtS, i8x16, int16, int16, 16, a < b)
1857 2025 : CMPOP_CASE(I8x16LeS, i8x16, int16, int16, 16, a <= b)
1858 2025 : CMPOP_CASE(I8x16GtU, i8x16, int16, int16, 16,
1859 : static_cast<uint8_t>(a) > static_cast<uint8_t>(b))
1860 2025 : CMPOP_CASE(I8x16GeU, i8x16, int16, int16, 16,
1861 : static_cast<uint8_t>(a) >= static_cast<uint8_t>(b))
1862 2025 : CMPOP_CASE(I8x16LtU, i8x16, int16, int16, 16,
1863 : static_cast<uint8_t>(a) < static_cast<uint8_t>(b))
1864 2025 : CMPOP_CASE(I8x16LeU, i8x16, int16, int16, 16,
1865 : static_cast<uint8_t>(a) <= static_cast<uint8_t>(b))
1866 : #undef CMPOP_CASE
1867 : #define REPLACE_LANE_CASE(format, name, stype, ctype) \
1868 : case kExpr##format##ReplaceLane: { \
1869 : SimdLaneImmediate<Decoder::kNoValidate> imm(decoder, code->at(pc)); \
1870 : ++len; \
1871 : WasmValue new_val = Pop(); \
1872 : WasmValue simd_val = Pop(); \
1873 : stype s = simd_val.to_s128().to_##name(); \
1874 : s.val[LANE(imm.lane, s)] = new_val.to<ctype>(); \
1875 : Push(WasmValue(Simd128(s))); \
1876 : return true; \
1877 : }
1878 160 : REPLACE_LANE_CASE(F32x4, f32x4, float4, float)
1879 200 : REPLACE_LANE_CASE(I32x4, i32x4, int4, int32_t)
1880 360 : REPLACE_LANE_CASE(I16x8, i16x8, int8, int32_t)
1881 520 : REPLACE_LANE_CASE(I8x16, i8x16, int16, int32_t)
1882 : #undef REPLACE_LANE_CASE
1883 : case kExprS128LoadMem:
1884 : return ExecuteLoad<Simd128, Simd128>(decoder, code, pc, len,
1885 0 : MachineRepresentation::kSimd128);
1886 : case kExprS128StoreMem:
1887 : return ExecuteStore<Simd128, Simd128>(decoder, code, pc, len,
1888 0 : MachineRepresentation::kSimd128);
1889 : #define SHIFT_CASE(op, name, stype, count, expr) \
1890 : case kExpr##op: { \
1891 : SimdShiftImmediate<Decoder::kNoValidate> imm(decoder, code->at(pc)); \
1892 : ++len; \
1893 : WasmValue v = Pop(); \
1894 : stype s = v.to_s128().to_##name(); \
1895 : stype res; \
1896 : for (size_t i = 0; i < count; ++i) { \
1897 : auto a = s.val[i]; \
1898 : res.val[i] = expr; \
1899 : } \
1900 : Push(WasmValue(Simd128(res))); \
1901 : return true; \
1902 : }
1903 35960 : SHIFT_CASE(I32x4Shl, i32x4, int4, 4, a << imm.shift)
1904 35960 : SHIFT_CASE(I32x4ShrS, i32x4, int4, 4, a >> imm.shift)
1905 35960 : SHIFT_CASE(I32x4ShrU, i32x4, int4, 4,
1906 : static_cast<uint32_t>(a) >> imm.shift)
1907 2700 : SHIFT_CASE(I16x8Shl, i16x8, int8, 8, a << imm.shift)
1908 2700 : SHIFT_CASE(I16x8ShrS, i16x8, int8, 8, a >> imm.shift)
1909 2700 : SHIFT_CASE(I16x8ShrU, i16x8, int8, 8,
1910 : static_cast<uint16_t>(a) >> imm.shift)
1911 1260 : SHIFT_CASE(I8x16Shl, i8x16, int16, 16, a << imm.shift)
1912 1260 : SHIFT_CASE(I8x16ShrS, i8x16, int16, 16, a >> imm.shift)
1913 1260 : SHIFT_CASE(I8x16ShrU, i8x16, int16, 16,
1914 : static_cast<uint8_t>(a) >> imm.shift)
1915 : #undef SHIFT_CASE
1916 : #define CONVERT_CASE(op, src_type, name, dst_type, count, start_index, ctype, \
1917 : expr) \
1918 : case kExpr##op: { \
1919 : WasmValue v = Pop(); \
1920 : src_type s = v.to_s128().to_##name(); \
1921 : dst_type res; \
1922 : for (size_t i = 0; i < count; ++i) { \
1923 : ctype a = s.val[LANE(start_index + i, s)]; \
1924 : res.val[LANE(i, res)] = expr; \
1925 : } \
1926 : Push(WasmValue(Simd128(res))); \
1927 : return true; \
1928 : }
1929 0 : CONVERT_CASE(F32x4SConvertI32x4, int4, i32x4, float4, 4, 0, int32_t,
1930 : static_cast<float>(a))
1931 0 : CONVERT_CASE(F32x4UConvertI32x4, int4, i32x4, float4, 4, 0, uint32_t,
1932 : static_cast<float>(a))
1933 1455 : CONVERT_CASE(I32x4SConvertF32x4, float4, f32x4, int4, 4, 0, double,
1934 : std::isnan(a) ? 0
1935 : : a<kMinInt ? kMinInt : a> kMaxInt
1936 : ? kMaxInt
1937 : : static_cast<int32_t>(a))
1938 1455 : CONVERT_CASE(I32x4UConvertF32x4, float4, f32x4, int4, 4, 0, double,
1939 : std::isnan(a)
1940 : ? 0
1941 : : a<0 ? 0 : a> kMaxUInt32 ? kMaxUInt32
1942 : : static_cast<uint32_t>(a))
1943 135 : CONVERT_CASE(I32x4SConvertI16x8High, int8, i16x8, int4, 4, 4, int16_t,
1944 : a)
1945 135 : CONVERT_CASE(I32x4UConvertI16x8High, int8, i16x8, int4, 4, 4, uint16_t,
1946 : a)
1947 135 : CONVERT_CASE(I32x4SConvertI16x8Low, int8, i16x8, int4, 4, 0, int16_t, a)
1948 135 : CONVERT_CASE(I32x4UConvertI16x8Low, int8, i16x8, int4, 4, 0, uint16_t,
1949 : a)
1950 135 : CONVERT_CASE(I16x8SConvertI8x16High, int16, i8x16, int8, 8, 8, int8_t,
1951 : a)
1952 135 : CONVERT_CASE(I16x8UConvertI8x16High, int16, i8x16, int8, 8, 8, uint8_t,
1953 : a)
1954 135 : CONVERT_CASE(I16x8SConvertI8x16Low, int16, i8x16, int8, 8, 0, int8_t, a)
1955 135 : CONVERT_CASE(I16x8UConvertI8x16Low, int16, i8x16, int8, 8, 0, uint8_t,
1956 : a)
1957 : #undef CONVERT_CASE
1958 : #define PACK_CASE(op, src_type, name, dst_type, count, ctype, dst_ctype, \
1959 : is_unsigned) \
1960 : case kExpr##op: { \
1961 : WasmValue v2 = Pop(); \
1962 : WasmValue v1 = Pop(); \
1963 : src_type s1 = v1.to_s128().to_##name(); \
1964 : src_type s2 = v2.to_s128().to_##name(); \
1965 : dst_type res; \
1966 : int64_t min = std::numeric_limits<ctype>::min(); \
1967 : int64_t max = std::numeric_limits<ctype>::max(); \
1968 : for (size_t i = 0; i < count; ++i) { \
1969 : int32_t v = i < count / 2 ? s1.val[LANE(i, s1)] \
1970 : : s2.val[LANE(i - count / 2, s2)]; \
1971 : int64_t a = is_unsigned ? static_cast<int64_t>(v & 0xFFFFFFFFu) : v; \
1972 : res.val[LANE(i, res)] = \
1973 : static_cast<dst_ctype>(std::max(min, std::min(max, a))); \
1974 : } \
1975 : Push(WasmValue(Simd128(res))); \
1976 : return true; \
1977 : }
1978 218660 : PACK_CASE(I16x8SConvertI32x4, int4, i32x4, int8, 8, int16_t, int16_t,
1979 : false)
1980 218660 : PACK_CASE(I16x8UConvertI32x4, int4, i32x4, int8, 8, uint16_t, int16_t,
1981 : true)
1982 8505 : PACK_CASE(I8x16SConvertI16x8, int8, i16x8, int16, 16, int8_t, int8_t,
1983 : false)
1984 8505 : PACK_CASE(I8x16UConvertI16x8, int8, i16x8, int16, 16, uint8_t, int8_t,
1985 : true)
1986 : #undef PACK_CASE
1987 : case kExprS128Select: {
1988 0 : int4 v2 = Pop().to_s128().to_i32x4();
1989 0 : int4 v1 = Pop().to_s128().to_i32x4();
1990 0 : int4 bool_val = Pop().to_s128().to_i32x4();
1991 : int4 res;
1992 0 : for (size_t i = 0; i < 4; ++i) {
1993 0 : res.val[i] = v2.val[i] ^ ((v1.val[i] ^ v2.val[i]) & bool_val.val[i]);
1994 : }
1995 0 : Push(WasmValue(Simd128(res)));
1996 : return true;
1997 : }
1998 : #define ADD_HORIZ_CASE(op, name, stype, count) \
1999 : case kExpr##op: { \
2000 : WasmValue v2 = Pop(); \
2001 : WasmValue v1 = Pop(); \
2002 : stype s1 = v1.to_s128().to_##name(); \
2003 : stype s2 = v2.to_s128().to_##name(); \
2004 : stype res; \
2005 : for (size_t i = 0; i < count / 2; ++i) { \
2006 : res.val[LANE(i, s1)] = \
2007 : s1.val[LANE(i * 2, s1)] + s1.val[LANE(i * 2 + 1, s1)]; \
2008 : res.val[LANE(i + count / 2, s1)] = \
2009 : s2.val[LANE(i * 2, s1)] + s2.val[LANE(i * 2 + 1, s1)]; \
2010 : } \
2011 : Push(WasmValue(Simd128(res))); \
2012 : return true; \
2013 : }
2014 25 : ADD_HORIZ_CASE(I32x4AddHoriz, i32x4, int4, 4)
2015 25 : ADD_HORIZ_CASE(F32x4AddHoriz, f32x4, float4, 4)
2016 25 : ADD_HORIZ_CASE(I16x8AddHoriz, i16x8, int8, 8)
2017 : #undef ADD_HORIZ_CASE
2018 : case kExprS8x16Shuffle: {
2019 : Simd8x16ShuffleImmediate<Decoder::kNoValidate> imm(decoder,
2020 : code->at(pc));
2021 15280 : len += 16;
2022 30560 : int16 v2 = Pop().to_s128().to_i8x16();
2023 30560 : int16 v1 = Pop().to_s128().to_i8x16();
2024 : int16 res;
2025 259760 : for (size_t i = 0; i < kSimd128Size; ++i) {
2026 244480 : int lane = imm.shuffle[i];
2027 : res.val[LANE(i, v1)] = lane < kSimd128Size
2028 : ? v1.val[LANE(lane, v1)]
2029 244480 : : v2.val[LANE(lane - kSimd128Size, v1)];
2030 : }
2031 15280 : Push(WasmValue(Simd128(res)));
2032 : return true;
2033 : }
2034 : #define REDUCTION_CASE(op, name, stype, count, operation) \
2035 : case kExpr##op: { \
2036 : stype s = Pop().to_s128().to_##name(); \
2037 : int32_t res = s.val[0]; \
2038 : for (size_t i = 1; i < count; ++i) { \
2039 : res = res operation static_cast<int32_t>(s.val[i]); \
2040 : } \
2041 : Push(WasmValue(res)); \
2042 : return true; \
2043 : }
2044 60 : REDUCTION_CASE(S1x4AnyTrue, i32x4, int4, 4, |)
2045 60 : REDUCTION_CASE(S1x4AllTrue, i32x4, int4, 4, &)
2046 60 : REDUCTION_CASE(S1x8AnyTrue, i16x8, int8, 8, |)
2047 60 : REDUCTION_CASE(S1x8AllTrue, i16x8, int8, 8, &)
2048 60 : REDUCTION_CASE(S1x16AnyTrue, i8x16, int16, 16, |)
2049 60 : REDUCTION_CASE(S1x16AllTrue, i8x16, int16, 16, &)
2050 : #undef REDUCTION_CASE
2051 : default:
2052 : return false;
2053 : }
2054 : }
2055 :
2056 : // Check if our control stack (frames_) exceeds the limit. Trigger stack
2057 : // overflow if it does, and unwinding the current frame.
2058 : // Returns true if execution can continue, false if the current activation was
2059 : // fully unwound.
2060 : // Do call this function immediately *after* pushing a new frame. The pc of
2061 : // the top frame will be reset to 0 if the stack check fails.
2062 500020 : bool DoStackCheck() V8_WARN_UNUSED_RESULT {
2063 : // The goal of this stack check is not to prevent actual stack overflows,
2064 : // but to simulate stack overflows during the execution of compiled code.
2065 : // That is why this function uses FLAG_stack_size, even though the value
2066 : // stack actually lies in zone memory.
2067 500020 : const size_t stack_size_limit = FLAG_stack_size * KB;
2068 : // Sum up the value stack size and the control stack size.
2069 : const size_t current_stack_size =
2070 1500060 : (sp_ - stack_.get()) + frames_.size() * sizeof(Frame);
2071 500020 : if (V8_LIKELY(current_stack_size <= stack_size_limit)) {
2072 : return true;
2073 : }
2074 : // The pc of the top frame is initialized to the first instruction. We reset
2075 : // it to 0 here such that we report the same position as in compiled code.
2076 18 : frames_.back().pc = 0;
2077 : Isolate* isolate = instance_object_->GetIsolate();
2078 : HandleScope handle_scope(isolate);
2079 18 : isolate->StackOverflow();
2080 18 : return HandleException(isolate) == WasmInterpreter::Thread::HANDLED;
2081 : }
2082 :
2083 6349464 : void Execute(InterpreterCode* code, pc_t pc, int max) {
2084 : DCHECK_NOT_NULL(code->side_table);
2085 : DCHECK(!frames_.empty());
2086 : // There must be enough space on the stack to hold the arguments, locals,
2087 : // and the value stack.
2088 : DCHECK_LE(code->function->sig->parameter_count() +
2089 : code->locals.type_list.size() +
2090 : code->side_table->max_stack_height_,
2091 : stack_limit_ - stack_.get() - frames_.back().sp);
2092 :
2093 53330748 : Decoder decoder(code->start, code->end);
2094 5818485 : pc_t limit = code->end - code->start;
2095 : bool hit_break = false;
2096 :
2097 : while (true) {
2098 : #define PAUSE_IF_BREAK_FLAG(flag) \
2099 : if (V8_UNLIKELY(break_flags_ & WasmInterpreter::BreakFlag::flag)) { \
2100 : hit_break = true; \
2101 : max = 0; \
2102 : }
2103 :
2104 : DCHECK_GT(limit, pc);
2105 : DCHECK_NOT_NULL(code->start);
2106 :
2107 : // Do first check for a breakpoint, in order to set hit_break correctly.
2108 : const char* skip = " ";
2109 75469038 : int len = 1;
2110 75469038 : byte orig = code->start[pc];
2111 75469038 : WasmOpcode opcode = static_cast<WasmOpcode>(orig);
2112 75469038 : if (WasmOpcodes::IsPrefixOpcode(opcode)) {
2113 7135425 : opcode = static_cast<WasmOpcode>(opcode << 8 | code->start[pc + 1]);
2114 : }
2115 75469038 : if (V8_UNLIKELY(orig == kInternalBreakpoint)) {
2116 7490 : orig = code->orig_start[pc];
2117 7490 : if (WasmOpcodes::IsPrefixOpcode(static_cast<WasmOpcode>(orig))) {
2118 : opcode =
2119 0 : static_cast<WasmOpcode>(orig << 8 | code->orig_start[pc + 1]);
2120 : }
2121 14980 : if (SkipBreakpoint(code, pc)) {
2122 : // skip breakpoint by switching on original code.
2123 : skip = "[skip] ";
2124 : } else {
2125 : TRACE("@%-3zu: [break] %-24s:", pc, WasmOpcodes::OpcodeName(opcode));
2126 : TraceValueStack();
2127 : TRACE("\n");
2128 : hit_break = true;
2129 6786 : break;
2130 : }
2131 : }
2132 :
2133 : // If max is 0, break. If max is positive (a limit is set), decrement it.
2134 75465293 : if (max == 0) break;
2135 75462252 : if (max > 0) --max;
2136 :
2137 : USE(skip);
2138 : TRACE("@%-3zu: %s%-24s:", pc, skip, WasmOpcodes::OpcodeName(opcode));
2139 : TraceValueStack();
2140 : TRACE("\n");
2141 :
2142 : #ifdef DEBUG
2143 : // Compute the stack effect of this opcode, and verify later that the
2144 : // stack was modified accordingly.
2145 : std::pair<uint32_t, uint32_t> stack_effect =
2146 : StackEffect(codemap_->module(), frames_.back().code->function->sig,
2147 : code->orig_start + pc, code->orig_end);
2148 : sp_t expected_new_stack_height =
2149 : StackHeight() - stack_effect.first + stack_effect.second;
2150 : #endif
2151 :
2152 75462252 : switch (orig) {
2153 : case kExprNop:
2154 : break;
2155 : case kExprBlock: {
2156 : BlockTypeImmediate<Decoder::kNoValidate> imm(kAllWasmFeatures,
2157 2839382 : &decoder, code->at(pc));
2158 1419691 : len = 1 + imm.length;
2159 : break;
2160 : }
2161 : case kExprLoop: {
2162 : BlockTypeImmediate<Decoder::kNoValidate> imm(kAllWasmFeatures,
2163 80512 : &decoder, code->at(pc));
2164 40256 : len = 1 + imm.length;
2165 : break;
2166 : }
2167 : case kExprIf: {
2168 : BlockTypeImmediate<Decoder::kNoValidate> imm(kAllWasmFeatures,
2169 7982740 : &decoder, code->at(pc));
2170 : WasmValue cond = Pop();
2171 : bool is_true = cond.to<uint32_t>() != 0;
2172 3991370 : if (is_true) {
2173 : // fall through to the true block.
2174 23755 : len = 1 + imm.length;
2175 : TRACE(" true => fallthrough\n");
2176 : } else {
2177 7935230 : len = LookupTargetDelta(code, pc);
2178 : TRACE(" false => @%zu\n", pc + len);
2179 : }
2180 : break;
2181 : }
2182 : case kExprElse: {
2183 36650 : len = LookupTargetDelta(code, pc);
2184 : TRACE(" end => @%zu\n", pc + len);
2185 18325 : break;
2186 : }
2187 : case kExprSelect: {
2188 : WasmValue cond = Pop();
2189 : WasmValue fval = Pop();
2190 : WasmValue tval = Pop();
2191 1165 : Push(cond.to<int32_t>() != 0 ? tval : fval);
2192 : break;
2193 : }
2194 : case kExprBr: {
2195 : BranchDepthImmediate<Decoder::kNoValidate> imm(&decoder,
2196 22275 : code->at(pc));
2197 44550 : len = DoBreak(code, pc, imm.depth);
2198 : TRACE(" br => @%zu\n", pc + len);
2199 : break;
2200 : }
2201 : case kExprBrIf: {
2202 : BranchDepthImmediate<Decoder::kNoValidate> imm(&decoder,
2203 35920 : code->at(pc));
2204 : WasmValue cond = Pop();
2205 : bool is_true = cond.to<uint32_t>() != 0;
2206 35920 : if (is_true) {
2207 36700 : len = DoBreak(code, pc, imm.depth);
2208 : TRACE(" br_if => @%zu\n", pc + len);
2209 : } else {
2210 : TRACE(" false => fallthrough\n");
2211 17570 : len = 1 + imm.length;
2212 : }
2213 : break;
2214 : }
2215 : case kExprBrTable: {
2216 : BranchTableImmediate<Decoder::kNoValidate> imm(&decoder,
2217 554810 : code->at(pc));
2218 : BranchTableIterator<Decoder::kNoValidate> iterator(&decoder, imm);
2219 277405 : uint32_t key = Pop().to<uint32_t>();
2220 : uint32_t depth = 0;
2221 277405 : if (key >= imm.table_count) key = imm.table_count;
2222 1352170 : for (uint32_t i = 0; i <= key; i++) {
2223 : DCHECK(iterator.has_next());
2224 1074765 : depth = iterator.next();
2225 : }
2226 554810 : len = key + DoBreak(code, pc + key, static_cast<size_t>(depth));
2227 : TRACE(" br[%u] => @%zu\n", key, pc + key + len);
2228 : break;
2229 : }
2230 : case kExprReturn: {
2231 5887196 : size_t arity = code->function->sig->return_count();
2232 6312384 : if (!DoReturn(&decoder, &code, &pc, &limit, arity)) return;
2233 15 : PAUSE_IF_BREAK_FLAG(AfterReturn);
2234 500017 : continue;
2235 : }
2236 : case kExprUnreachable: {
2237 42 : return DoTrap(kTrapUnreachable, pc);
2238 : }
2239 : case kExprEnd: {
2240 : break;
2241 : }
2242 : case kExprI32Const: {
2243 9250596 : ImmI32Immediate<Decoder::kNoValidate> imm(&decoder, code->at(pc));
2244 9250596 : Push(WasmValue(imm.value));
2245 9250596 : len = 1 + imm.length;
2246 : break;
2247 : }
2248 : case kExprI64Const: {
2249 8595 : ImmI64Immediate<Decoder::kNoValidate> imm(&decoder, code->at(pc));
2250 8595 : Push(WasmValue(imm.value));
2251 8595 : len = 1 + imm.length;
2252 : break;
2253 : }
2254 : case kExprF32Const: {
2255 350 : ImmF32Immediate<Decoder::kNoValidate> imm(&decoder, code->at(pc));
2256 350 : Push(WasmValue(imm.value));
2257 350 : len = 1 + imm.length;
2258 : break;
2259 : }
2260 : case kExprF64Const: {
2261 1405 : ImmF64Immediate<Decoder::kNoValidate> imm(&decoder, code->at(pc));
2262 1405 : Push(WasmValue(imm.value));
2263 1405 : len = 1 + imm.length;
2264 : break;
2265 : }
2266 : case kExprGetLocal: {
2267 22043437 : LocalIndexImmediate<Decoder::kNoValidate> imm(&decoder, code->at(pc));
2268 22043437 : Push(GetStackValue(frames_.back().sp + imm.index));
2269 22043437 : len = 1 + imm.length;
2270 : break;
2271 : }
2272 : case kExprSetLocal: {
2273 5582530 : LocalIndexImmediate<Decoder::kNoValidate> imm(&decoder, code->at(pc));
2274 : WasmValue val = Pop();
2275 5582530 : SetStackValue(frames_.back().sp + imm.index, val);
2276 5582530 : len = 1 + imm.length;
2277 : break;
2278 : }
2279 : case kExprTeeLocal: {
2280 3190 : LocalIndexImmediate<Decoder::kNoValidate> imm(&decoder, code->at(pc));
2281 : WasmValue val = Pop();
2282 3190 : SetStackValue(frames_.back().sp + imm.index, val);
2283 : Push(val);
2284 3190 : len = 1 + imm.length;
2285 : break;
2286 : }
2287 : case kExprDrop: {
2288 18075 : Pop();
2289 18075 : break;
2290 : }
2291 : case kExprCallFunction: {
2292 : CallFunctionImmediate<Decoder::kNoValidate> imm(&decoder,
2293 506636 : code->at(pc));
2294 : InterpreterCode* target = codemap()->GetCode(imm.index);
2295 506636 : if (target->function->imported) {
2296 6723 : CommitPc(pc);
2297 : ExternalCallResult result =
2298 6723 : CallImportedFunction(target->function->func_index);
2299 6723 : switch (result.type) {
2300 : case ExternalCallResult::INTERNAL:
2301 : // The import is a function of this instance. Call it directly.
2302 0 : target = result.interpreter_code;
2303 : DCHECK(!target->function->imported);
2304 0 : break;
2305 : case ExternalCallResult::INVALID_FUNC:
2306 : case ExternalCallResult::SIGNATURE_MISMATCH:
2307 : // Direct calls are checked statically.
2308 0 : UNREACHABLE();
2309 : case ExternalCallResult::EXTERNAL_RETURNED:
2310 5598 : PAUSE_IF_BREAK_FLAG(AfterCall);
2311 5598 : len = 1 + imm.length;
2312 5598 : break;
2313 : case ExternalCallResult::EXTERNAL_UNWOUND:
2314 1125 : return;
2315 : }
2316 5598 : if (result.type != ExternalCallResult::INTERNAL) break;
2317 : }
2318 : // Execute an internal call.
2319 499913 : if (!DoCall(&decoder, target, &pc, &limit)) return;
2320 499895 : code = target;
2321 499895 : PAUSE_IF_BREAK_FLAG(AfterCall);
2322 499895 : continue; // don't bump pc
2323 : } break;
2324 : case kExprCallIndirect: {
2325 : CallIndirectImmediate<Decoder::kNoValidate> imm(&decoder,
2326 476 : code->at(pc));
2327 238 : uint32_t entry_index = Pop().to<uint32_t>();
2328 : // Assume only one table for now.
2329 : DCHECK_LE(module()->tables.size(), 1u);
2330 238 : CommitPc(pc); // TODO(wasm): Be more disciplined about committing PC.
2331 : ExternalCallResult result =
2332 238 : CallIndirectFunction(0, entry_index, imm.sig_index);
2333 238 : switch (result.type) {
2334 : case ExternalCallResult::INTERNAL:
2335 : // The import is a function of this instance. Call it directly.
2336 107 : if (!DoCall(&decoder, result.interpreter_code, &pc, &limit))
2337 104 : return;
2338 107 : code = result.interpreter_code;
2339 107 : PAUSE_IF_BREAK_FLAG(AfterCall);
2340 107 : continue; // don't bump pc
2341 : case ExternalCallResult::INVALID_FUNC:
2342 54 : return DoTrap(kTrapFuncInvalid, pc);
2343 : case ExternalCallResult::SIGNATURE_MISMATCH:
2344 32 : return DoTrap(kTrapFuncSigMismatch, pc);
2345 : case ExternalCallResult::EXTERNAL_RETURNED:
2346 27 : PAUSE_IF_BREAK_FLAG(AfterCall);
2347 27 : len = 1 + imm.length;
2348 27 : break;
2349 : case ExternalCallResult::EXTERNAL_UNWOUND:
2350 : return;
2351 : }
2352 27 : } break;
2353 : case kExprGetGlobal: {
2354 : GlobalIndexImmediate<Decoder::kNoValidate> imm(&decoder,
2355 19872 : code->at(pc));
2356 39744 : const WasmGlobal* global = &module()->globals[imm.index];
2357 19872 : byte* ptr = GetGlobalPtr(global);
2358 : WasmValue val;
2359 19872 : switch (global->type) {
2360 : #define CASE_TYPE(wasm, ctype) \
2361 : case kWasm##wasm: \
2362 : val = WasmValue( \
2363 : ReadLittleEndianValue<ctype>(reinterpret_cast<Address>(ptr))); \
2364 : break;
2365 19872 : WASM_CTYPES(CASE_TYPE)
2366 : #undef CASE_TYPE
2367 : default:
2368 0 : UNREACHABLE();
2369 : }
2370 : Push(val);
2371 19872 : len = 1 + imm.length;
2372 : break;
2373 : }
2374 : case kExprSetGlobal: {
2375 : GlobalIndexImmediate<Decoder::kNoValidate> imm(&decoder,
2376 4471 : code->at(pc));
2377 8942 : const WasmGlobal* global = &module()->globals[imm.index];
2378 4471 : byte* ptr = GetGlobalPtr(global);
2379 : WasmValue val = Pop();
2380 4471 : switch (global->type) {
2381 : #define CASE_TYPE(wasm, ctype) \
2382 : case kWasm##wasm: \
2383 : WriteLittleEndianValue<ctype>(reinterpret_cast<Address>(ptr), \
2384 : val.to<ctype>()); \
2385 : break;
2386 4275 : WASM_CTYPES(CASE_TYPE)
2387 : #undef CASE_TYPE
2388 : default:
2389 0 : UNREACHABLE();
2390 : }
2391 4471 : len = 1 + imm.length;
2392 : break;
2393 : }
2394 :
2395 : #define LOAD_CASE(name, ctype, mtype, rep) \
2396 : case kExpr##name: { \
2397 : if (!ExecuteLoad<ctype, mtype>(&decoder, code, pc, len, \
2398 : MachineRepresentation::rep)) \
2399 : return; \
2400 : break; \
2401 : }
2402 :
2403 327965 : LOAD_CASE(I32LoadMem8S, int32_t, int8_t, kWord8);
2404 327975 : LOAD_CASE(I32LoadMem8U, int32_t, uint8_t, kWord8);
2405 164125 : LOAD_CASE(I32LoadMem16S, int32_t, int16_t, kWord16);
2406 164125 : LOAD_CASE(I32LoadMem16U, int32_t, uint16_t, kWord16);
2407 120 : LOAD_CASE(I64LoadMem8S, int64_t, int8_t, kWord8);
2408 0 : LOAD_CASE(I64LoadMem8U, int64_t, uint8_t, kWord16);
2409 120 : LOAD_CASE(I64LoadMem16S, int64_t, int16_t, kWord16);
2410 0 : LOAD_CASE(I64LoadMem16U, int64_t, uint16_t, kWord16);
2411 120 : LOAD_CASE(I64LoadMem32S, int64_t, int32_t, kWord32);
2412 0 : LOAD_CASE(I64LoadMem32U, int64_t, uint32_t, kWord32);
2413 1003755 : LOAD_CASE(I32LoadMem, int32_t, int32_t, kWord32);
2414 1928615 : LOAD_CASE(I64LoadMem, int64_t, int64_t, kWord64);
2415 11815 : LOAD_CASE(F32LoadMem, Float32, uint32_t, kFloat32);
2416 37425 : LOAD_CASE(F64LoadMem, Float64, uint64_t, kFloat64);
2417 : #undef LOAD_CASE
2418 :
2419 : #define STORE_CASE(name, ctype, mtype, rep) \
2420 : case kExpr##name: { \
2421 : if (!ExecuteStore<ctype, mtype>(&decoder, code, pc, len, \
2422 : MachineRepresentation::rep)) \
2423 : return; \
2424 : break; \
2425 : }
2426 :
2427 525 : STORE_CASE(I32StoreMem8, int32_t, int8_t, kWord8);
2428 495 : STORE_CASE(I32StoreMem16, int32_t, int16_t, kWord16);
2429 120 : STORE_CASE(I64StoreMem8, int64_t, int8_t, kWord8);
2430 115 : STORE_CASE(I64StoreMem16, int64_t, int16_t, kWord16);
2431 105 : STORE_CASE(I64StoreMem32, int64_t, int32_t, kWord32);
2432 1065120 : STORE_CASE(I32StoreMem, int32_t, int32_t, kWord32);
2433 2135535 : STORE_CASE(I64StoreMem, int64_t, int64_t, kWord64);
2434 1500 : STORE_CASE(F32StoreMem, Float32, uint32_t, kFloat32);
2435 13655 : STORE_CASE(F64StoreMem, Float64, uint64_t, kFloat64);
2436 : #undef STORE_CASE
2437 :
2438 : #define ASMJS_LOAD_CASE(name, ctype, mtype, defval) \
2439 : case kExpr##name: { \
2440 : uint32_t index = Pop().to<uint32_t>(); \
2441 : ctype result; \
2442 : Address addr = BoundsCheckMem<mtype>(0, index); \
2443 : if (!addr) { \
2444 : result = defval; \
2445 : } else { \
2446 : /* TODO(titzer): alignment for asmjs load mem? */ \
2447 : result = static_cast<ctype>(*reinterpret_cast<mtype*>(addr)); \
2448 : } \
2449 : Push(WasmValue(result)); \
2450 : break; \
2451 : }
2452 0 : ASMJS_LOAD_CASE(I32AsmjsLoadMem8S, int32_t, int8_t, 0);
2453 0 : ASMJS_LOAD_CASE(I32AsmjsLoadMem8U, int32_t, uint8_t, 0);
2454 0 : ASMJS_LOAD_CASE(I32AsmjsLoadMem16S, int32_t, int16_t, 0);
2455 0 : ASMJS_LOAD_CASE(I32AsmjsLoadMem16U, int32_t, uint16_t, 0);
2456 250 : ASMJS_LOAD_CASE(I32AsmjsLoadMem, int32_t, int32_t, 0);
2457 250 : ASMJS_LOAD_CASE(F32AsmjsLoadMem, float, float,
2458 : std::numeric_limits<float>::quiet_NaN());
2459 340 : ASMJS_LOAD_CASE(F64AsmjsLoadMem, double, double,
2460 : std::numeric_limits<double>::quiet_NaN());
2461 : #undef ASMJS_LOAD_CASE
2462 :
2463 : #define ASMJS_STORE_CASE(name, ctype, mtype) \
2464 : case kExpr##name: { \
2465 : WasmValue val = Pop(); \
2466 : uint32_t index = Pop().to<uint32_t>(); \
2467 : Address addr = BoundsCheckMem<mtype>(0, index); \
2468 : if (addr) { \
2469 : *(reinterpret_cast<mtype*>(addr)) = static_cast<mtype>(val.to<ctype>()); \
2470 : } \
2471 : Push(val); \
2472 : break; \
2473 : }
2474 :
2475 0 : ASMJS_STORE_CASE(I32AsmjsStoreMem8, int32_t, int8_t);
2476 0 : ASMJS_STORE_CASE(I32AsmjsStoreMem16, int32_t, int16_t);
2477 1165 : ASMJS_STORE_CASE(I32AsmjsStoreMem, int32_t, int32_t);
2478 0 : ASMJS_STORE_CASE(F32AsmjsStoreMem, float, float);
2479 0 : ASMJS_STORE_CASE(F64AsmjsStoreMem, double, double);
2480 : #undef ASMJS_STORE_CASE
2481 : case kExprMemoryGrow: {
2482 : MemoryIndexImmediate<Decoder::kNoValidate> imm(&decoder,
2483 56 : code->at(pc));
2484 56 : uint32_t delta_pages = Pop().to<uint32_t>();
2485 : Handle<WasmMemoryObject> memory(instance_object_->memory_object(),
2486 112 : instance_object_->GetIsolate());
2487 : Isolate* isolate = memory->GetIsolate();
2488 56 : int32_t result = WasmMemoryObject::Grow(isolate, memory, delta_pages);
2489 56 : Push(WasmValue(result));
2490 56 : len = 1 + imm.length;
2491 : // Treat one grow_memory instruction like 1000 other instructions,
2492 : // because it is a really expensive operation.
2493 56 : if (max > 0) max = std::max(0, max - 1000);
2494 : break;
2495 : }
2496 : case kExprMemorySize: {
2497 : MemoryIndexImmediate<Decoder::kNoValidate> imm(&decoder,
2498 0 : code->at(pc));
2499 0 : Push(WasmValue(static_cast<uint32_t>(instance_object_->memory_size() /
2500 0 : kWasmPageSize)));
2501 0 : len = 1 + imm.length;
2502 : break;
2503 : }
2504 : // We need to treat kExprI32ReinterpretF32 and kExprI64ReinterpretF64
2505 : // specially to guarantee that the quiet bit of a NaN is preserved on
2506 : // ia32 by the reinterpret casts.
2507 : case kExprI32ReinterpretF32: {
2508 : WasmValue val = Pop();
2509 320 : Push(WasmValue(ExecuteI32ReinterpretF32(val)));
2510 : break;
2511 : }
2512 : case kExprI64ReinterpretF64: {
2513 : WasmValue val = Pop();
2514 305 : Push(WasmValue(ExecuteI64ReinterpretF64(val)));
2515 : break;
2516 : }
2517 : #define SIGN_EXTENSION_CASE(name, wtype, ntype) \
2518 : case kExpr##name: { \
2519 : ntype val = static_cast<ntype>(Pop().to<wtype>()); \
2520 : Push(WasmValue(static_cast<wtype>(val))); \
2521 : break; \
2522 : }
2523 50 : SIGN_EXTENSION_CASE(I32SExtendI8, int32_t, int8_t);
2524 50 : SIGN_EXTENSION_CASE(I32SExtendI16, int32_t, int16_t);
2525 50 : SIGN_EXTENSION_CASE(I64SExtendI8, int64_t, int8_t);
2526 50 : SIGN_EXTENSION_CASE(I64SExtendI16, int64_t, int16_t);
2527 50 : SIGN_EXTENSION_CASE(I64SExtendI32, int64_t, int32_t);
2528 : #undef SIGN_EXTENSION_CASE
2529 : case kNumericPrefix: {
2530 3280 : ++len;
2531 3280 : if (!ExecuteNumericOp(opcode, &decoder, code, pc, len)) return;
2532 : break;
2533 : }
2534 : case kAtomicPrefix: {
2535 480055 : if (!ExecuteAtomicOp(opcode, &decoder, code, pc, len)) return;
2536 : break;
2537 : }
2538 : case kSimdPrefix: {
2539 6652090 : ++len;
2540 6652090 : if (!ExecuteSimdOp(opcode, &decoder, code, pc, len)) return;
2541 : break;
2542 : }
2543 :
2544 : #define EXECUTE_SIMPLE_BINOP(name, ctype, op) \
2545 : case kExpr##name: { \
2546 : WasmValue rval = Pop(); \
2547 : WasmValue lval = Pop(); \
2548 : auto result = lval.to<ctype>() op rval.to<ctype>(); \
2549 : possible_nondeterminism_ |= has_nondeterminism(result); \
2550 : Push(WasmValue(result)); \
2551 : break; \
2552 : }
2553 12289053 : FOREACH_SIMPLE_BINOP(EXECUTE_SIMPLE_BINOP)
2554 : #undef EXECUTE_SIMPLE_BINOP
2555 :
2556 : #define EXECUTE_OTHER_BINOP(name, ctype) \
2557 : case kExpr##name: { \
2558 : TrapReason trap = kTrapCount; \
2559 : ctype rval = Pop().to<ctype>(); \
2560 : ctype lval = Pop().to<ctype>(); \
2561 : auto result = Execute##name(lval, rval, &trap); \
2562 : possible_nondeterminism_ |= has_nondeterminism(result); \
2563 : if (trap != kTrapCount) return DoTrap(trap, pc); \
2564 : Push(WasmValue(result)); \
2565 : break; \
2566 : }
2567 4509875 : FOREACH_OTHER_BINOP(EXECUTE_OTHER_BINOP)
2568 : #undef EXECUTE_OTHER_BINOP
2569 :
2570 : #define EXECUTE_UNOP(name, ctype, exec_fn) \
2571 : case kExpr##name: { \
2572 : TrapReason trap = kTrapCount; \
2573 : ctype val = Pop().to<ctype>(); \
2574 : auto result = exec_fn(val, &trap); \
2575 : possible_nondeterminism_ |= has_nondeterminism(result); \
2576 : if (trap != kTrapCount) return DoTrap(trap, pc); \
2577 : Push(WasmValue(result)); \
2578 : break; \
2579 : }
2580 :
2581 : #define EXECUTE_OTHER_UNOP(name, ctype) EXECUTE_UNOP(name, ctype, Execute##name)
2582 493342 : FOREACH_OTHER_UNOP(EXECUTE_OTHER_UNOP)
2583 : #undef EXECUTE_OTHER_UNOP
2584 :
2585 : #define EXECUTE_I32CONV_FLOATOP(name, out_type, in_type) \
2586 : EXECUTE_UNOP(name, in_type, ExecuteConvert<out_type>)
2587 4675 : FOREACH_I32CONV_FLOATOP(EXECUTE_I32CONV_FLOATOP)
2588 : #undef EXECUTE_I32CONV_FLOATOP
2589 : #undef EXECUTE_UNOP
2590 :
2591 : default:
2592 0 : FATAL("Unknown or unimplemented opcode #%d:%s", code->start[pc],
2593 0 : OpcodeName(code->start[pc]));
2594 : UNREACHABLE();
2595 : }
2596 :
2597 : #ifdef DEBUG
2598 : if (!WasmOpcodes::IsControlOpcode(opcode)) {
2599 : DCHECK_EQ(expected_new_stack_height, StackHeight());
2600 : }
2601 : #endif
2602 :
2603 74415123 : pc += len;
2604 74415123 : if (pc == limit) {
2605 : // Fell off end of code; do an implicit return.
2606 : TRACE("@%-3zu: ImplicitReturn\n", pc);
2607 5386511 : if (!DoReturn(&decoder, &code, &pc, &limit,
2608 10773022 : code->function->sig->return_count()))
2609 : return;
2610 121924 : PAUSE_IF_BREAK_FLAG(AfterReturn);
2611 : }
2612 : #undef PAUSE_IF_BREAK_FLAG
2613 : }
2614 :
2615 6786 : state_ = WasmInterpreter::PAUSED;
2616 10581 : break_pc_ = hit_break ? pc : kInvalidPc;
2617 6786 : CommitPc(pc);
2618 : }
2619 :
2620 : WasmValue Pop() {
2621 : DCHECK_GT(frames_.size(), 0);
2622 : DCHECK_GT(StackHeight(), frames_.back().llimit()); // can't pop into locals
2623 33739949 : return *--sp_;
2624 : }
2625 :
2626 : void PopN(int n) {
2627 : DCHECK_GE(StackHeight(), n);
2628 : DCHECK_GT(frames_.size(), 0);
2629 : // Check that we don't pop into locals.
2630 : DCHECK_GE(StackHeight() - n, frames_.back().llimit());
2631 : sp_ -= n;
2632 : }
2633 :
2634 : WasmValue PopArity(size_t arity) {
2635 : if (arity == 0) return WasmValue();
2636 : CHECK_EQ(1, arity);
2637 : return Pop();
2638 : }
2639 :
2640 : void Push(WasmValue val) {
2641 : DCHECK_NE(kWasmStmt, val.type());
2642 : DCHECK_LE(1, stack_limit_ - sp_);
2643 64079681 : *sp_++ = val;
2644 : }
2645 :
2646 : void Push(WasmValue* vals, size_t arity) {
2647 : DCHECK_LE(arity, stack_limit_ - sp_);
2648 5811710 : for (WasmValue *val = vals, *end = vals + arity; val != end; ++val) {
2649 : DCHECK_NE(kWasmStmt, val->type());
2650 : }
2651 5811710 : memcpy(sp_, vals, arity * sizeof(*sp_));
2652 5811710 : sp_ += arity;
2653 : }
2654 :
2655 12123440 : void EnsureStackSpace(size_t size) {
2656 24246880 : if (V8_LIKELY(static_cast<size_t>(stack_limit_ - sp_) >= size)) return;
2657 455492 : size_t old_size = stack_limit_ - stack_.get();
2658 : size_t requested_size =
2659 455492 : base::bits::RoundUpToPowerOfTwo64((sp_ - stack_.get()) + size);
2660 455492 : size_t new_size = Max(size_t{8}, Max(2 * old_size, requested_size));
2661 22469828 : std::unique_ptr<WasmValue[]> new_stack(new WasmValue[new_size]);
2662 455492 : memcpy(new_stack.get(), stack_.get(), old_size * sizeof(*sp_));
2663 910984 : sp_ = new_stack.get() + (sp_ - stack_.get());
2664 : stack_ = std::move(new_stack);
2665 455492 : stack_limit_ = stack_.get() + new_size;
2666 : }
2667 :
2668 12703570 : sp_t StackHeight() { return sp_ - stack_.get(); }
2669 :
2670 : void TraceValueStack() {
2671 : #ifdef DEBUG
2672 : if (!FLAG_trace_wasm_interpreter) return;
2673 : Frame* top = frames_.size() > 0 ? &frames_.back() : nullptr;
2674 : sp_t sp = top ? top->sp : 0;
2675 : sp_t plimit = top ? top->plimit() : 0;
2676 : sp_t llimit = top ? top->llimit() : 0;
2677 : for (size_t i = sp; i < StackHeight(); ++i) {
2678 : if (i < plimit)
2679 : PrintF(" p%zu:", i);
2680 : else if (i < llimit)
2681 : PrintF(" l%zu:", i);
2682 : else
2683 : PrintF(" s%zu:", i);
2684 : WasmValue val = GetStackValue(i);
2685 : switch (val.type()) {
2686 : case kWasmI32:
2687 : PrintF("i32:%d", val.to<int32_t>());
2688 : break;
2689 : case kWasmI64:
2690 : PrintF("i64:%" PRId64 "", val.to<int64_t>());
2691 : break;
2692 : case kWasmF32:
2693 : PrintF("f32:%f", val.to<float>());
2694 : break;
2695 : case kWasmF64:
2696 : PrintF("f64:%lf", val.to<double>());
2697 : break;
2698 : case kWasmStmt:
2699 : PrintF("void");
2700 : break;
2701 : default:
2702 : UNREACHABLE();
2703 : break;
2704 : }
2705 : }
2706 : #endif // DEBUG
2707 : }
2708 :
2709 : ExternalCallResult TryHandleException(Isolate* isolate) {
2710 1143 : if (HandleException(isolate) == WasmInterpreter::Thread::UNWOUND) {
2711 : return {ExternalCallResult::EXTERNAL_UNWOUND};
2712 : }
2713 : return {ExternalCallResult::EXTERNAL_RETURNED};
2714 : }
2715 :
2716 6768 : ExternalCallResult CallExternalWasmFunction(Isolate* isolate,
2717 : Handle<Object> object_ref,
2718 6768 : const WasmCode* code,
2719 38007 : FunctionSig* sig) {
2720 : wasm::WasmFeatures enabled_features =
2721 6768 : wasm::WasmFeaturesFromIsolate(isolate);
2722 :
2723 13419 : if (code->kind() == WasmCode::kWasmToJsWrapper &&
2724 6651 : !IsJSCompatibleSignature(sig, enabled_features.bigint)) {
2725 : isolate->Throw(*isolate->factory()->NewTypeError(
2726 36 : MessageTemplate::kWasmTrapTypeError));
2727 : return TryHandleException(isolate);
2728 : }
2729 :
2730 13500 : Handle<WasmDebugInfo> debug_info(instance_object_->debug_info(), isolate);
2731 : Handle<JSFunction> wasm_entry =
2732 6750 : WasmDebugInfo::GetCWasmEntry(debug_info, sig);
2733 :
2734 : TRACE(" => Calling external wasm function\n");
2735 :
2736 : // Copy the arguments to one buffer.
2737 : // TODO(clemensh): Introduce a helper for all argument buffer
2738 : // con-/destruction.
2739 6750 : int num_args = static_cast<int>(sig->parameter_count());
2740 6750 : std::vector<uint8_t> arg_buffer(num_args * 8);
2741 : size_t offset = 0;
2742 6750 : WasmValue* wasm_args = sp_ - num_args;
2743 13437 : for (int i = 0; i < num_args; ++i) {
2744 13374 : int param_size = ValueTypes::ElementSizeInBytes(sig->GetParam(i));
2745 13374 : if (arg_buffer.size() < offset + param_size) {
2746 0 : arg_buffer.resize(std::max(2 * arg_buffer.size(), offset + param_size));
2747 : }
2748 6687 : Address address = reinterpret_cast<Address>(arg_buffer.data()) + offset;
2749 6687 : switch (sig->GetParam(i)) {
2750 : case kWasmI32:
2751 6678 : WriteUnalignedValue(address, wasm_args[i].to<uint32_t>());
2752 : break;
2753 : case kWasmI64:
2754 0 : WriteUnalignedValue(address, wasm_args[i].to<uint64_t>());
2755 : break;
2756 : case kWasmF32:
2757 0 : WriteUnalignedValue(address, wasm_args[i].to<float>());
2758 : break;
2759 : case kWasmF64:
2760 9 : WriteUnalignedValue(address, wasm_args[i].to<double>());
2761 : break;
2762 : default:
2763 0 : UNIMPLEMENTED();
2764 : }
2765 : offset += param_size;
2766 : }
2767 :
2768 : // Ensure that there is enough space in the arg_buffer to hold the return
2769 : // value(s).
2770 : size_t return_size = 0;
2771 12339 : for (ValueType t : sig->returns()) {
2772 5589 : return_size += ValueTypes::ElementSizeInBytes(t);
2773 : }
2774 13500 : if (arg_buffer.size() < return_size) {
2775 72 : arg_buffer.resize(return_size);
2776 : }
2777 :
2778 : // Wrap the arg_buffer and the code target data pointers in handles. As
2779 : // these are aligned pointers, to the GC it will look like Smis.
2780 : Handle<Object> arg_buffer_obj(
2781 6750 : Object(reinterpret_cast<Address>(arg_buffer.data())), isolate);
2782 : DCHECK(!arg_buffer_obj->IsHeapObject());
2783 : Handle<Object> code_entry_obj(Object(code->instruction_start()), isolate);
2784 : DCHECK(!code_entry_obj->IsHeapObject());
2785 :
2786 : static_assert(compiler::CWasmEntryParameters::kNumParameters == 3,
2787 : "code below needs adaption");
2788 27000 : Handle<Object> args[compiler::CWasmEntryParameters::kNumParameters];
2789 6750 : args[compiler::CWasmEntryParameters::kCodeEntry] = code_entry_obj;
2790 6750 : args[compiler::CWasmEntryParameters::kObjectRef] = object_ref;
2791 6750 : args[compiler::CWasmEntryParameters::kArgumentsBuffer] = arg_buffer_obj;
2792 :
2793 : Handle<Object> receiver = isolate->factory()->undefined_value();
2794 : trap_handler::SetThreadInWasm();
2795 : MaybeHandle<Object> maybe_retval =
2796 6750 : Execution::Call(isolate, wasm_entry, receiver, arraysize(args), args);
2797 : TRACE(" => External wasm function returned%s\n",
2798 : maybe_retval.is_null() ? " with exception" : "");
2799 :
2800 6750 : if (maybe_retval.is_null()) {
2801 : // JSEntry may throw a stack overflow before we actually get to wasm code
2802 : // or back to the interpreter, meaning the thread-in-wasm flag won't be
2803 : // cleared.
2804 1125 : if (trap_handler::IsThreadInWasm()) {
2805 : trap_handler::ClearThreadInWasm();
2806 : }
2807 : return TryHandleException(isolate);
2808 : }
2809 :
2810 : trap_handler::ClearThreadInWasm();
2811 :
2812 : // Pop arguments off the stack.
2813 5625 : sp_ -= num_args;
2814 : // Push return values.
2815 5625 : if (sig->return_count() > 0) {
2816 : // TODO(wasm): Handle multiple returns.
2817 : DCHECK_EQ(1, sig->return_count());
2818 : Address address = reinterpret_cast<Address>(arg_buffer.data());
2819 5508 : switch (sig->GetReturn()) {
2820 : case kWasmI32:
2821 5490 : Push(WasmValue(ReadUnalignedValue<uint32_t>(address)));
2822 5490 : break;
2823 : case kWasmI64:
2824 9 : Push(WasmValue(ReadUnalignedValue<uint64_t>(address)));
2825 9 : break;
2826 : case kWasmF32:
2827 9 : Push(WasmValue(ReadUnalignedValue<float>(address)));
2828 9 : break;
2829 : case kWasmF64:
2830 0 : Push(WasmValue(ReadUnalignedValue<double>(address)));
2831 0 : break;
2832 : default:
2833 0 : UNIMPLEMENTED();
2834 : }
2835 : }
2836 5625 : return {ExternalCallResult::EXTERNAL_RETURNED};
2837 : }
2838 :
2839 6795 : static WasmCode* GetTargetCode(WasmCodeManager* code_manager,
2840 : Address target) {
2841 6795 : NativeModule* native_module = code_manager->LookupNativeModule(target);
2842 6795 : if (native_module->is_jump_table_slot(target)) {
2843 : uint32_t func_index =
2844 144 : native_module->GetFunctionIndexFromJumpTableSlot(target);
2845 144 : return native_module->code(func_index);
2846 : }
2847 6651 : WasmCode* code = native_module->Lookup(target);
2848 : DCHECK_EQ(code->instruction_start(), target);
2849 6651 : return code;
2850 : }
2851 :
2852 13446 : ExternalCallResult CallImportedFunction(uint32_t function_index) {
2853 : DCHECK_GT(module()->num_imported_functions, function_index);
2854 : // Use a new HandleScope to avoid leaking / accumulating handles in the
2855 : // outer scope.
2856 : Isolate* isolate = instance_object_->GetIsolate();
2857 : HandleScope handle_scope(isolate);
2858 :
2859 6723 : ImportedFunctionEntry entry(instance_object_, function_index);
2860 6723 : Handle<Object> object_ref(entry.object_ref(), isolate);
2861 : WasmCode* code =
2862 13446 : GetTargetCode(isolate->wasm_engine()->code_manager(), entry.target());
2863 20169 : FunctionSig* sig = module()->functions[function_index].sig;
2864 13446 : return CallExternalWasmFunction(isolate, object_ref, code, sig);
2865 : }
2866 :
2867 238 : ExternalCallResult CallIndirectFunction(uint32_t table_index,
2868 : uint32_t entry_index,
2869 460 : uint32_t sig_index) {
2870 238 : if (codemap()->call_indirect_through_module()) {
2871 : // Rely on the information stored in the WasmModule.
2872 : InterpreterCode* code =
2873 130 : codemap()->GetIndirectCode(table_index, entry_index);
2874 130 : if (!code) return {ExternalCallResult::INVALID_FUNC};
2875 85 : if (code->function->sig_index != sig_index) {
2876 : // If not an exact match, we have to do a canonical check.
2877 : int function_canonical_id =
2878 45 : module()->signature_ids[code->function->sig_index];
2879 30 : int expected_canonical_id = module()->signature_ids[sig_index];
2880 : DCHECK_EQ(function_canonical_id,
2881 : module()->signature_map.Find(*code->function->sig));
2882 15 : if (function_canonical_id != expected_canonical_id) {
2883 5 : return {ExternalCallResult::SIGNATURE_MISMATCH};
2884 : }
2885 : }
2886 80 : return {ExternalCallResult::INTERNAL, code};
2887 : }
2888 :
2889 : Isolate* isolate = instance_object_->GetIsolate();
2890 324 : uint32_t expected_sig_id = module()->signature_ids[sig_index];
2891 : DCHECK_EQ(expected_sig_id,
2892 : module()->signature_map.Find(*module()->signatures[sig_index]));
2893 :
2894 : // The function table is stored in the instance.
2895 : // TODO(wasm): the wasm interpreter currently supports only one table.
2896 108 : CHECK_EQ(0, table_index);
2897 : // Bounds check against table size.
2898 108 : if (entry_index >= instance_object_->indirect_function_table_size()) {
2899 9 : return {ExternalCallResult::INVALID_FUNC};
2900 : }
2901 :
2902 99 : IndirectFunctionTableEntry entry(instance_object_, entry_index);
2903 : // Signature check.
2904 99 : if (entry.sig_id() != static_cast<int32_t>(expected_sig_id)) {
2905 27 : return {ExternalCallResult::SIGNATURE_MISMATCH};
2906 : }
2907 :
2908 : HandleScope scope(isolate);
2909 144 : FunctionSig* signature = module()->signatures[sig_index];
2910 72 : Handle<Object> object_ref = handle(entry.object_ref(), isolate);
2911 27 : WasmCode* code =
2912 144 : GetTargetCode(isolate->wasm_engine()->code_manager(), entry.target());
2913 :
2914 198 : if (!object_ref->IsWasmInstanceObject() || /* call to an import */
2915 : !instance_object_.is_identical_to(object_ref) /* cross-instance */) {
2916 45 : return CallExternalWasmFunction(isolate, object_ref, code, signature);
2917 : }
2918 :
2919 : DCHECK(code->kind() == WasmCode::kInterpreterEntry ||
2920 : code->kind() == WasmCode::kFunction);
2921 27 : return {ExternalCallResult::INTERNAL, codemap()->GetCode(code->index())};
2922 : }
2923 :
2924 : inline Activation current_activation() {
2925 11652210 : return activations_.empty() ? Activation(0, 0) : activations_.back();
2926 : }
2927 : };
2928 :
2929 : class InterpretedFrameImpl {
2930 : public:
2931 : InterpretedFrameImpl(ThreadImpl* thread, int index)
2932 763779 : : thread_(thread), index_(index) {
2933 : DCHECK_LE(0, index);
2934 : }
2935 :
2936 1529483 : const WasmFunction* function() const { return frame()->code->function; }
2937 :
2938 761589 : int pc() const {
2939 : DCHECK_LE(0, frame()->pc);
2940 : DCHECK_GE(kMaxInt, frame()->pc);
2941 761589 : return static_cast<int>(frame()->pc);
2942 : }
2943 :
2944 : int GetParameterCount() const {
2945 : DCHECK_GE(kMaxInt, function()->sig->parameter_count());
2946 575 : return static_cast<int>(function()->sig->parameter_count());
2947 : }
2948 :
2949 : int GetLocalCount() const {
2950 2440 : size_t num_locals = function()->sig->parameter_count() +
2951 4880 : frame()->code->locals.type_list.size();
2952 : DCHECK_GE(kMaxInt, num_locals);
2953 2440 : return static_cast<int>(num_locals);
2954 : }
2955 :
2956 875 : int GetStackHeight() const {
2957 : bool is_top_frame =
2958 875 : static_cast<size_t>(index_) + 1 == thread_->frames_.size();
2959 : size_t stack_limit =
2960 1035 : is_top_frame ? thread_->StackHeight() : thread_->frames_[index_ + 1].sp;
2961 : DCHECK_LE(frame()->sp, stack_limit);
2962 875 : size_t frame_size = stack_limit - frame()->sp;
2963 : DCHECK_LE(GetLocalCount(), frame_size);
2964 1750 : return static_cast<int>(frame_size) - GetLocalCount();
2965 : }
2966 :
2967 1180 : WasmValue GetLocalValue(int index) const {
2968 : DCHECK_LE(0, index);
2969 : DCHECK_GT(GetLocalCount(), index);
2970 1180 : return thread_->GetStackValue(static_cast<int>(frame()->sp) + index);
2971 : }
2972 :
2973 330 : WasmValue GetStackValue(int index) const {
2974 : DCHECK_LE(0, index);
2975 : // Index must be within the number of stack values of this frame.
2976 : DCHECK_GT(GetStackHeight(), index);
2977 660 : return thread_->GetStackValue(static_cast<int>(frame()->sp) +
2978 660 : GetLocalCount() + index);
2979 : }
2980 :
2981 : private:
2982 : ThreadImpl* thread_;
2983 : int index_;
2984 :
2985 : ThreadImpl::Frame* frame() const {
2986 : DCHECK_GT(thread_->frames_.size(), index_);
2987 1527238 : return &thread_->frames_[index_];
2988 : }
2989 : };
2990 :
2991 : namespace {
2992 :
2993 : // Converters between WasmInterpreter::Thread and WasmInterpreter::ThreadImpl.
2994 : // Thread* is the public interface, without knowledge of the object layout.
2995 : // This cast is potentially risky, but as long as we always cast it back before
2996 : // accessing any data, it should be fine. UBSan is not complaining.
2997 : WasmInterpreter::Thread* ToThread(ThreadImpl* impl) {
2998 : return reinterpret_cast<WasmInterpreter::Thread*>(impl);
2999 : }
3000 : ThreadImpl* ToImpl(WasmInterpreter::Thread* thread) {
3001 : return reinterpret_cast<ThreadImpl*>(thread);
3002 : }
3003 :
3004 : // Same conversion for InterpretedFrame and InterpretedFrameImpl.
3005 : InterpretedFrame* ToFrame(InterpretedFrameImpl* impl) {
3006 : return reinterpret_cast<InterpretedFrame*>(impl);
3007 : }
3008 : const InterpretedFrameImpl* ToImpl(const InterpretedFrame* frame) {
3009 : return reinterpret_cast<const InterpretedFrameImpl*>(frame);
3010 : }
3011 :
3012 : } // namespace
3013 :
3014 : //============================================================================
3015 : // Implementation of the pimpl idiom for WasmInterpreter::Thread.
3016 : // Instead of placing a pointer to the ThreadImpl inside of the Thread object,
3017 : // we just reinterpret_cast them. ThreadImpls are only allocated inside this
3018 : // translation unit anyway.
3019 : //============================================================================
3020 54771 : WasmInterpreter::State WasmInterpreter::Thread::state() {
3021 54771 : return ToImpl(this)->state();
3022 : }
3023 5811710 : void WasmInterpreter::Thread::InitFrame(const WasmFunction* function,
3024 : WasmValue* args) {
3025 5811710 : ToImpl(this)->InitFrame(function, args);
3026 5811710 : }
3027 5818485 : WasmInterpreter::State WasmInterpreter::Thread::Run(int num_steps) {
3028 5818485 : return ToImpl(this)->Run(num_steps);
3029 : }
3030 0 : void WasmInterpreter::Thread::Pause() { return ToImpl(this)->Pause(); }
3031 11544904 : void WasmInterpreter::Thread::Reset() { return ToImpl(this)->Reset(); }
3032 : WasmInterpreter::Thread::ExceptionHandlingResult
3033 91 : WasmInterpreter::Thread::HandleException(Isolate* isolate) {
3034 91 : return ToImpl(this)->HandleException(isolate);
3035 : }
3036 3480 : pc_t WasmInterpreter::Thread::GetBreakpointPc() {
3037 3480 : return ToImpl(this)->GetBreakpointPc();
3038 : }
3039 8652 : int WasmInterpreter::Thread::GetFrameCount() {
3040 8652 : return ToImpl(this)->GetFrameCount();
3041 : }
3042 763779 : WasmInterpreter::FramePtr WasmInterpreter::Thread::GetFrame(int index) {
3043 : DCHECK_LE(0, index);
3044 : DCHECK_GT(GetFrameCount(), index);
3045 1527558 : return FramePtr(ToFrame(new InterpretedFrameImpl(ToImpl(this), index)));
3046 : }
3047 5765014 : WasmValue WasmInterpreter::Thread::GetReturnValue(int index) {
3048 5765014 : return ToImpl(this)->GetReturnValue(index);
3049 : }
3050 81 : TrapReason WasmInterpreter::Thread::GetTrapReason() {
3051 81 : return ToImpl(this)->GetTrapReason();
3052 : }
3053 5723771 : bool WasmInterpreter::Thread::PossibleNondeterminism() {
3054 5723771 : return ToImpl(this)->PossibleNondeterminism();
3055 : }
3056 64488 : uint64_t WasmInterpreter::Thread::NumInterpretedCalls() {
3057 64488 : return ToImpl(this)->NumInterpretedCalls();
3058 : }
3059 50 : void WasmInterpreter::Thread::AddBreakFlags(uint8_t flags) {
3060 : ToImpl(this)->AddBreakFlags(flags);
3061 50 : }
3062 0 : void WasmInterpreter::Thread::ClearBreakFlags() {
3063 : ToImpl(this)->ClearBreakFlags();
3064 0 : }
3065 30 : uint32_t WasmInterpreter::Thread::NumActivations() {
3066 30 : return ToImpl(this)->NumActivations();
3067 : }
3068 39260 : uint32_t WasmInterpreter::Thread::StartActivation() {
3069 39260 : return ToImpl(this)->StartActivation();
3070 : }
3071 39258 : void WasmInterpreter::Thread::FinishActivation(uint32_t id) {
3072 : ToImpl(this)->FinishActivation(id);
3073 39258 : }
3074 7421 : uint32_t WasmInterpreter::Thread::ActivationFrameBase(uint32_t id) {
3075 7421 : return ToImpl(this)->ActivationFrameBase(id);
3076 : }
3077 :
3078 : //============================================================================
3079 : // The implementation details of the interpreter.
3080 : //============================================================================
3081 : class WasmInterpreterInternals : public ZoneObject {
3082 : public:
3083 : // Create a copy of the module bytes for the interpreter, since the passed
3084 : // pointer might be invalidated after constructing the interpreter.
3085 : const ZoneVector<uint8_t> module_bytes_;
3086 : CodeMap codemap_;
3087 : ZoneVector<ThreadImpl> threads_;
3088 :
3089 456796 : WasmInterpreterInternals(Zone* zone, const WasmModule* module,
3090 : const ModuleWireBytes& wire_bytes,
3091 : Handle<WasmInstanceObject> instance_object)
3092 : : module_bytes_(wire_bytes.start(), wire_bytes.end(), zone),
3093 : codemap_(module, module_bytes_.data(), zone),
3094 1370388 : threads_(zone) {
3095 456796 : threads_.emplace_back(zone, &codemap_, instance_object);
3096 456796 : }
3097 : };
3098 :
3099 : namespace {
3100 426784 : void NopFinalizer(const v8::WeakCallbackInfo<void>& data) {
3101 : Address* global_handle_location =
3102 : reinterpret_cast<Address*>(data.GetParameter());
3103 426784 : GlobalHandles::Destroy(global_handle_location);
3104 426784 : }
3105 :
3106 456796 : Handle<WasmInstanceObject> MakeWeak(
3107 456796 : Isolate* isolate, Handle<WasmInstanceObject> instance_object) {
3108 : Handle<WasmInstanceObject> weak_instance =
3109 : isolate->global_handles()->Create<WasmInstanceObject>(*instance_object);
3110 : Address* global_handle_location = weak_instance.location();
3111 : GlobalHandles::MakeWeak(global_handle_location, global_handle_location,
3112 456796 : &NopFinalizer, v8::WeakCallbackType::kParameter);
3113 456796 : return weak_instance;
3114 : }
3115 : } // namespace
3116 :
3117 : //============================================================================
3118 : // Implementation of the public interface of the interpreter.
3119 : //============================================================================
3120 456796 : WasmInterpreter::WasmInterpreter(Isolate* isolate, const WasmModule* module,
3121 : const ModuleWireBytes& wire_bytes,
3122 : Handle<WasmInstanceObject> instance_object)
3123 : : zone_(isolate->allocator(), ZONE_NAME),
3124 : internals_(new (&zone_) WasmInterpreterInternals(
3125 913592 : &zone_, module, wire_bytes, MakeWeak(isolate, instance_object))) {}
3126 :
3127 913592 : WasmInterpreter::~WasmInterpreter() { internals_->~WasmInterpreterInternals(); }
3128 :
3129 0 : void WasmInterpreter::Run() { internals_->threads_[0].Run(); }
3130 :
3131 0 : void WasmInterpreter::Pause() { internals_->threads_[0].Pause(); }
3132 :
3133 3870 : bool WasmInterpreter::SetBreakpoint(const WasmFunction* function, pc_t pc,
3134 : bool enabled) {
3135 1935 : InterpreterCode* code = internals_->codemap_.GetCode(function);
3136 1935 : size_t size = static_cast<size_t>(code->end - code->start);
3137 : // Check bounds for {pc}.
3138 1935 : if (pc < code->locals.encoded_size || pc >= size) return false;
3139 : // Make a copy of the code before enabling a breakpoint.
3140 1935 : if (enabled && code->orig_start == code->start) {
3141 80 : code->start = reinterpret_cast<byte*>(zone_.New(size));
3142 80 : memcpy(code->start, code->orig_start, size);
3143 80 : code->end = code->start + size;
3144 : }
3145 1935 : bool prev = code->start[pc] == kInternalBreakpoint;
3146 1935 : if (enabled) {
3147 1065 : code->start[pc] = kInternalBreakpoint;
3148 : } else {
3149 870 : code->start[pc] = code->orig_start[pc];
3150 : }
3151 1935 : return prev;
3152 : }
3153 :
3154 0 : bool WasmInterpreter::GetBreakpoint(const WasmFunction* function, pc_t pc) {
3155 0 : InterpreterCode* code = internals_->codemap_.GetCode(function);
3156 0 : size_t size = static_cast<size_t>(code->end - code->start);
3157 : // Check bounds for {pc}.
3158 0 : if (pc < code->locals.encoded_size || pc >= size) return false;
3159 : // Check if a breakpoint is present at that place in the code.
3160 0 : return code->start[pc] == kInternalBreakpoint;
3161 : }
3162 :
3163 0 : bool WasmInterpreter::SetTracing(const WasmFunction* function, bool enabled) {
3164 0 : UNIMPLEMENTED();
3165 : return false;
3166 : }
3167 :
3168 0 : int WasmInterpreter::GetThreadCount() {
3169 0 : return 1; // only one thread for now.
3170 : }
3171 :
3172 5959678 : WasmInterpreter::Thread* WasmInterpreter::GetThread(int id) {
3173 5959678 : CHECK_EQ(0, id); // only one thread for now.
3174 11919356 : return ToThread(&internals_->threads_[id]);
3175 : }
3176 :
3177 458870 : void WasmInterpreter::AddFunctionForTesting(const WasmFunction* function) {
3178 458870 : internals_->codemap_.AddFunction(function, nullptr, nullptr);
3179 458870 : }
3180 :
3181 914060 : void WasmInterpreter::SetFunctionCodeForTesting(const WasmFunction* function,
3182 : const byte* start,
3183 : const byte* end) {
3184 914060 : internals_->codemap_.SetFunctionCode(function, start, end);
3185 457030 : }
3186 :
3187 455742 : void WasmInterpreter::SetCallIndirectTestMode() {
3188 455742 : internals_->codemap_.set_call_indirect_through_module(true);
3189 455742 : }
3190 :
3191 30 : ControlTransferMap WasmInterpreter::ComputeControlTransfersForTesting(
3192 : Zone* zone, const WasmModule* module, const byte* start, const byte* end) {
3193 : // Create some dummy structures, to avoid special-casing the implementation
3194 : // just for testing.
3195 30 : FunctionSig sig(0, 0, nullptr);
3196 30 : WasmFunction function{&sig, 0, 0, {0, 0}, false, false};
3197 : InterpreterCode code{
3198 60 : &function, BodyLocalDecls(zone), start, end, nullptr, nullptr, nullptr};
3199 :
3200 : // Now compute and return the control transfers.
3201 30 : SideTable side_table(zone, module, &code);
3202 30 : return side_table.map_;
3203 : }
3204 :
3205 : //============================================================================
3206 : // Implementation of the frame inspection interface.
3207 : //============================================================================
3208 762329 : const WasmFunction* InterpretedFrame::function() const {
3209 762329 : return ToImpl(this)->function();
3210 : }
3211 1523178 : int InterpretedFrame::pc() const { return ToImpl(this)->pc(); }
3212 575 : int InterpretedFrame::GetParameterCount() const {
3213 575 : return ToImpl(this)->GetParameterCount();
3214 : }
3215 1235 : int InterpretedFrame::GetLocalCount() const {
3216 1235 : return ToImpl(this)->GetLocalCount();
3217 : }
3218 875 : int InterpretedFrame::GetStackHeight() const {
3219 875 : return ToImpl(this)->GetStackHeight();
3220 : }
3221 1180 : WasmValue InterpretedFrame::GetLocalValue(int index) const {
3222 1180 : return ToImpl(this)->GetLocalValue(index);
3223 : }
3224 330 : WasmValue InterpretedFrame::GetStackValue(int index) const {
3225 330 : return ToImpl(this)->GetStackValue(index);
3226 : }
3227 763779 : void InterpretedFrameDeleter::operator()(InterpretedFrame* ptr) {
3228 763779 : delete ToImpl(ptr);
3229 763779 : }
3230 :
3231 : #undef TRACE
3232 : #undef LANE
3233 : #undef FOREACH_INTERNAL_OPCODE
3234 : #undef WASM_CTYPES
3235 : #undef FOREACH_SIMPLE_BINOP
3236 : #undef FOREACH_OTHER_BINOP
3237 : #undef FOREACH_I32CONV_FLOATOP
3238 : #undef FOREACH_OTHER_UNOP
3239 :
3240 : } // namespace wasm
3241 : } // namespace internal
3242 183867 : } // namespace v8
|