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 <math.h>
6 #include <stdint.h>
7 #include <stdlib.h>
8
9 #include <limits>
10
11 #include "include/v8config.h"
12 #include "src/base/bits.h"
13 #include "src/base/ieee754.h"
14 #include "src/base/safe_conversions.h"
15 #include "src/common/assert-scope.h"
16 #include "src/utils/memcopy.h"
17 #include "src/wasm/wasm-objects-inl.h"
18
19 #if defined(ADDRESS_SANITIZER) || defined(MEMORY_SANITIZER) || \
20 defined(THREAD_SANITIZER) || defined(LEAK_SANITIZER) || \
21 defined(UNDEFINED_SANITIZER)
22 #define V8_WITH_SANITIZER
23 #endif
24
25 #if defined(V8_OS_WIN) && defined(V8_WITH_SANITIZER)
26 // With ASAN on Windows we have to reset the thread-in-wasm flag. Exceptions
27 // caused by ASAN let the thread-in-wasm flag get out of sync. Even marking
28 // functions with DISABLE_ASAN is not sufficient when the compiler produces
29 // calls to memset. Therefore we add test-specific code for ASAN on
30 // Windows.
31 #define RESET_THREAD_IN_WASM_FLAG_FOR_ASAN_ON_WINDOWS
32 #include "src/trap-handler/trap-handler.h"
33 #endif
34
35 #include "src/base/memory.h"
36 #include "src/utils/utils.h"
37 #include "src/wasm/wasm-external-refs.h"
38
39 namespace v8 {
40 namespace internal {
41 namespace wasm {
42
43 using base::ReadUnalignedValue;
44 using base::WriteUnalignedValue;
45
f32_trunc_wrapper(Address data)46 void f32_trunc_wrapper(Address data) {
47 WriteUnalignedValue<float>(data, truncf(ReadUnalignedValue<float>(data)));
48 }
49
f32_floor_wrapper(Address data)50 void f32_floor_wrapper(Address data) {
51 WriteUnalignedValue<float>(data, floorf(ReadUnalignedValue<float>(data)));
52 }
53
f32_ceil_wrapper(Address data)54 void f32_ceil_wrapper(Address data) {
55 WriteUnalignedValue<float>(data, ceilf(ReadUnalignedValue<float>(data)));
56 }
57
f32_nearest_int_wrapper(Address data)58 void f32_nearest_int_wrapper(Address data) {
59 float input = ReadUnalignedValue<float>(data);
60 float value = nearbyintf(input);
61 #if V8_OS_AIX
62 value = FpOpWorkaround<float>(input, value);
63 #endif
64 WriteUnalignedValue<float>(data, value);
65 }
66
f64_trunc_wrapper(Address data)67 void f64_trunc_wrapper(Address data) {
68 WriteUnalignedValue<double>(data, trunc(ReadUnalignedValue<double>(data)));
69 }
70
f64_floor_wrapper(Address data)71 void f64_floor_wrapper(Address data) {
72 WriteUnalignedValue<double>(data, floor(ReadUnalignedValue<double>(data)));
73 }
74
f64_ceil_wrapper(Address data)75 void f64_ceil_wrapper(Address data) {
76 WriteUnalignedValue<double>(data, ceil(ReadUnalignedValue<double>(data)));
77 }
78
f64_nearest_int_wrapper(Address data)79 void f64_nearest_int_wrapper(Address data) {
80 double input = ReadUnalignedValue<double>(data);
81 double value = nearbyint(input);
82 #if V8_OS_AIX
83 value = FpOpWorkaround<double>(input, value);
84 #endif
85 WriteUnalignedValue<double>(data, value);
86 }
87
int64_to_float32_wrapper(Address data)88 void int64_to_float32_wrapper(Address data) {
89 int64_t input = ReadUnalignedValue<int64_t>(data);
90 WriteUnalignedValue<float>(data, static_cast<float>(input));
91 }
92
uint64_to_float32_wrapper(Address data)93 void uint64_to_float32_wrapper(Address data) {
94 uint64_t input = ReadUnalignedValue<uint64_t>(data);
95 #if defined(V8_OS_WIN)
96 // On Windows, the FP stack registers calculate with less precision, which
97 // leads to a uint64_t to float32 conversion which does not satisfy the
98 // WebAssembly specification. Therefore we do a different approach here:
99 //
100 // / leading 0 \/ 24 float data bits \/ for rounding \/ trailing 0 \
101 // 00000000000001XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX100000000000000
102 //
103 // Float32 can only represent 24 data bit (1 implicit 1 bit + 23 mantissa
104 // bits). Starting from the most significant 1 bit, we can therefore extract
105 // 24 bits and do the conversion only on them. The other bits can affect the
106 // result only through rounding. Rounding works as follows:
107 // * If the most significant rounding bit is not set, then round down.
108 // * If the most significant rounding bit is set, and at least one of the
109 // other rounding bits is set, then round up.
110 // * If the most significant rounding bit is set, but all other rounding bits
111 // are not set, then round to even.
112 // We can aggregate 'all other rounding bits' in the second-most significant
113 // rounding bit.
114 // The resulting algorithm is therefore as follows:
115 // * Check if the distance between the most significant bit (MSB) and the
116 // least significant bit (LSB) is greater than 25 bits. If the distance is
117 // less or equal to 25 bits, the uint64 to float32 conversion is anyways
118 // exact, and we just use the C++ conversion.
119 // * Find the most significant bit (MSB).
120 // * Starting from the MSB, extract 25 bits (24 data bits + the first rounding
121 // bit).
122 // * The remaining rounding bits are guaranteed to contain at least one 1 bit,
123 // due to the check we did above.
124 // * Store the 25 bits + 1 aggregated bit in an uint32_t.
125 // * Convert this uint32_t to float. The conversion does the correct rounding
126 // now.
127 // * Shift the result back to the original magnitude.
128 uint32_t leading_zeros = base::bits::CountLeadingZeros(input);
129 uint32_t trailing_zeros = base::bits::CountTrailingZeros(input);
130 constexpr uint32_t num_extracted_bits = 25;
131 // Check if there are any rounding bits we have to aggregate.
132 if (leading_zeros + trailing_zeros + num_extracted_bits < 64) {
133 // Shift to extract the data bits.
134 uint32_t num_aggregation_bits = 64 - num_extracted_bits - leading_zeros;
135 // We extract the bits we want to convert. Note that we convert one bit more
136 // than necessary. This bit is a placeholder where we will store the
137 // aggregation bit.
138 int32_t extracted_bits =
139 static_cast<int32_t>(input >> (num_aggregation_bits - 1));
140 // Set the aggregation bit. We don't have to clear the slot first, because
141 // the bit there is also part of the aggregation.
142 extracted_bits |= 1;
143 float result = static_cast<float>(extracted_bits);
144 // We have to shift the result back. The shift amount is
145 // (num_aggregation_bits - 1), which is the shift amount we did originally,
146 // and (-2), which is for the two additional bits we kept originally for
147 // rounding.
148 int32_t shift_back = static_cast<int32_t>(num_aggregation_bits) - 1 - 2;
149 // Calculate the multiplier to shift the extracted bits back to the original
150 // magnitude. This multiplier is a power of two, so in the float32 bit
151 // representation we just have to construct the correct exponent and put it
152 // at the correct bit offset. The exponent consists of 8 bits, starting at
153 // the second MSB (a.k.a '<< 23'). The encoded exponent itself is
154 // ('actual exponent' - 127).
155 int32_t multiplier_bits = ((shift_back - 127) & 0xff) << 23;
156 result *= bit_cast<float>(multiplier_bits);
157 WriteUnalignedValue<float>(data, result);
158 return;
159 }
160 #endif // defined(V8_OS_WIN)
161 WriteUnalignedValue<float>(data, static_cast<float>(input));
162 }
163
int64_to_float64_wrapper(Address data)164 void int64_to_float64_wrapper(Address data) {
165 int64_t input = ReadUnalignedValue<int64_t>(data);
166 WriteUnalignedValue<double>(data, static_cast<double>(input));
167 }
168
uint64_to_float64_wrapper(Address data)169 void uint64_to_float64_wrapper(Address data) {
170 uint64_t input = ReadUnalignedValue<uint64_t>(data);
171 double result = static_cast<double>(input);
172
173 #if V8_CC_MSVC
174 // With MSVC we use static_cast<double>(uint32_t) instead of
175 // static_cast<double>(uint64_t) to achieve round-to-nearest-ties-even
176 // semantics. The idea is to calculate
177 // static_cast<double>(high_word) * 2^32 + static_cast<double>(low_word).
178 uint32_t low_word = static_cast<uint32_t>(input & 0xFFFFFFFF);
179 uint32_t high_word = static_cast<uint32_t>(input >> 32);
180
181 double shift = static_cast<double>(1ull << 32);
182
183 result = static_cast<double>(high_word);
184 result *= shift;
185 result += static_cast<double>(low_word);
186 #endif
187
188 WriteUnalignedValue<double>(data, result);
189 }
190
float32_to_int64_wrapper(Address data)191 int32_t float32_to_int64_wrapper(Address data) {
192 float input = ReadUnalignedValue<float>(data);
193 if (base::IsValueInRangeForNumericType<int64_t>(input)) {
194 WriteUnalignedValue<int64_t>(data, static_cast<int64_t>(input));
195 return 1;
196 }
197 return 0;
198 }
199
float32_to_uint64_wrapper(Address data)200 int32_t float32_to_uint64_wrapper(Address data) {
201 float input = ReadUnalignedValue<float>(data);
202 if (base::IsValueInRangeForNumericType<uint64_t>(input)) {
203 WriteUnalignedValue<uint64_t>(data, static_cast<uint64_t>(input));
204 return 1;
205 }
206 return 0;
207 }
208
float64_to_int64_wrapper(Address data)209 int32_t float64_to_int64_wrapper(Address data) {
210 double input = ReadUnalignedValue<double>(data);
211 if (base::IsValueInRangeForNumericType<int64_t>(input)) {
212 WriteUnalignedValue<int64_t>(data, static_cast<int64_t>(input));
213 return 1;
214 }
215 return 0;
216 }
217
float64_to_uint64_wrapper(Address data)218 int32_t float64_to_uint64_wrapper(Address data) {
219 double input = ReadUnalignedValue<double>(data);
220 if (base::IsValueInRangeForNumericType<uint64_t>(input)) {
221 WriteUnalignedValue<uint64_t>(data, static_cast<uint64_t>(input));
222 return 1;
223 }
224 return 0;
225 }
226
float32_to_int64_sat_wrapper(Address data)227 void float32_to_int64_sat_wrapper(Address data) {
228 float input = ReadUnalignedValue<float>(data);
229 if (base::IsValueInRangeForNumericType<int64_t>(input)) {
230 WriteUnalignedValue<int64_t>(data, static_cast<int64_t>(input));
231 return;
232 }
233 if (std::isnan(input)) {
234 WriteUnalignedValue<int64_t>(data, 0);
235 return;
236 }
237 if (input < 0.0) {
238 WriteUnalignedValue<int64_t>(data, std::numeric_limits<int64_t>::min());
239 return;
240 }
241 WriteUnalignedValue<int64_t>(data, std::numeric_limits<int64_t>::max());
242 }
243
float32_to_uint64_sat_wrapper(Address data)244 void float32_to_uint64_sat_wrapper(Address data) {
245 float input = ReadUnalignedValue<float>(data);
246 if (base::IsValueInRangeForNumericType<uint64_t>(input)) {
247 WriteUnalignedValue<uint64_t>(data, static_cast<uint64_t>(input));
248 return;
249 }
250 if (input >= static_cast<float>(std::numeric_limits<uint64_t>::max())) {
251 WriteUnalignedValue<uint64_t>(data, std::numeric_limits<uint64_t>::max());
252 return;
253 }
254 WriteUnalignedValue<uint64_t>(data, 0);
255 }
256
float64_to_int64_sat_wrapper(Address data)257 void float64_to_int64_sat_wrapper(Address data) {
258 double input = ReadUnalignedValue<double>(data);
259 if (base::IsValueInRangeForNumericType<int64_t>(input)) {
260 WriteUnalignedValue<int64_t>(data, static_cast<int64_t>(input));
261 return;
262 }
263 if (std::isnan(input)) {
264 WriteUnalignedValue<int64_t>(data, 0);
265 return;
266 }
267 if (input < 0.0) {
268 WriteUnalignedValue<int64_t>(data, std::numeric_limits<int64_t>::min());
269 return;
270 }
271 WriteUnalignedValue<int64_t>(data, std::numeric_limits<int64_t>::max());
272 }
273
float64_to_uint64_sat_wrapper(Address data)274 void float64_to_uint64_sat_wrapper(Address data) {
275 double input = ReadUnalignedValue<double>(data);
276 if (base::IsValueInRangeForNumericType<uint64_t>(input)) {
277 WriteUnalignedValue<uint64_t>(data, static_cast<uint64_t>(input));
278 return;
279 }
280 if (input >= static_cast<double>(std::numeric_limits<uint64_t>::max())) {
281 WriteUnalignedValue<uint64_t>(data, std::numeric_limits<uint64_t>::max());
282 return;
283 }
284 WriteUnalignedValue<uint64_t>(data, 0);
285 }
286
int64_div_wrapper(Address data)287 int32_t int64_div_wrapper(Address data) {
288 int64_t dividend = ReadUnalignedValue<int64_t>(data);
289 int64_t divisor = ReadUnalignedValue<int64_t>(data + sizeof(dividend));
290 if (divisor == 0) {
291 return 0;
292 }
293 if (divisor == -1 && dividend == std::numeric_limits<int64_t>::min()) {
294 return -1;
295 }
296 WriteUnalignedValue<int64_t>(data, dividend / divisor);
297 return 1;
298 }
299
int64_mod_wrapper(Address data)300 int32_t int64_mod_wrapper(Address data) {
301 int64_t dividend = ReadUnalignedValue<int64_t>(data);
302 int64_t divisor = ReadUnalignedValue<int64_t>(data + sizeof(dividend));
303 if (divisor == 0) {
304 return 0;
305 }
306 if (divisor == -1 && dividend == std::numeric_limits<int64_t>::min()) {
307 WriteUnalignedValue<int64_t>(data, 0);
308 return 1;
309 }
310 WriteUnalignedValue<int64_t>(data, dividend % divisor);
311 return 1;
312 }
313
uint64_div_wrapper(Address data)314 int32_t uint64_div_wrapper(Address data) {
315 uint64_t dividend = ReadUnalignedValue<uint64_t>(data);
316 uint64_t divisor = ReadUnalignedValue<uint64_t>(data + sizeof(dividend));
317 if (divisor == 0) {
318 return 0;
319 }
320 WriteUnalignedValue<uint64_t>(data, dividend / divisor);
321 return 1;
322 }
323
uint64_mod_wrapper(Address data)324 int32_t uint64_mod_wrapper(Address data) {
325 uint64_t dividend = ReadUnalignedValue<uint64_t>(data);
326 uint64_t divisor = ReadUnalignedValue<uint64_t>(data + sizeof(dividend));
327 if (divisor == 0) {
328 return 0;
329 }
330 WriteUnalignedValue<uint64_t>(data, dividend % divisor);
331 return 1;
332 }
333
word32_ctz_wrapper(Address data)334 uint32_t word32_ctz_wrapper(Address data) {
335 return base::bits::CountTrailingZeros(ReadUnalignedValue<uint32_t>(data));
336 }
337
word64_ctz_wrapper(Address data)338 uint32_t word64_ctz_wrapper(Address data) {
339 return base::bits::CountTrailingZeros(ReadUnalignedValue<uint64_t>(data));
340 }
341
word32_popcnt_wrapper(Address data)342 uint32_t word32_popcnt_wrapper(Address data) {
343 return base::bits::CountPopulation(ReadUnalignedValue<uint32_t>(data));
344 }
345
word64_popcnt_wrapper(Address data)346 uint32_t word64_popcnt_wrapper(Address data) {
347 return base::bits::CountPopulation(ReadUnalignedValue<uint64_t>(data));
348 }
349
word32_rol_wrapper(Address data)350 uint32_t word32_rol_wrapper(Address data) {
351 uint32_t input = ReadUnalignedValue<uint32_t>(data);
352 uint32_t shift = ReadUnalignedValue<uint32_t>(data + sizeof(input)) & 31;
353 return (input << shift) | (input >> ((32 - shift) & 31));
354 }
355
word32_ror_wrapper(Address data)356 uint32_t word32_ror_wrapper(Address data) {
357 uint32_t input = ReadUnalignedValue<uint32_t>(data);
358 uint32_t shift = ReadUnalignedValue<uint32_t>(data + sizeof(input)) & 31;
359 return (input >> shift) | (input << ((32 - shift) & 31));
360 }
361
word64_rol_wrapper(Address data)362 void word64_rol_wrapper(Address data) {
363 uint64_t input = ReadUnalignedValue<uint64_t>(data);
364 uint64_t shift = ReadUnalignedValue<uint64_t>(data + sizeof(input)) & 63;
365 uint64_t result = (input << shift) | (input >> ((64 - shift) & 63));
366 WriteUnalignedValue<uint64_t>(data, result);
367 }
368
word64_ror_wrapper(Address data)369 void word64_ror_wrapper(Address data) {
370 uint64_t input = ReadUnalignedValue<uint64_t>(data);
371 uint64_t shift = ReadUnalignedValue<uint64_t>(data + sizeof(input)) & 63;
372 uint64_t result = (input >> shift) | (input << ((64 - shift) & 63));
373 WriteUnalignedValue<uint64_t>(data, result);
374 }
375
float64_pow_wrapper(Address data)376 void float64_pow_wrapper(Address data) {
377 double x = ReadUnalignedValue<double>(data);
378 double y = ReadUnalignedValue<double>(data + sizeof(x));
379 WriteUnalignedValue<double>(data, base::ieee754::pow(x, y));
380 }
381
382 template <typename T, T (*float_round_op)(T)>
simd_float_round_wrapper(Address data)383 void simd_float_round_wrapper(Address data) {
384 constexpr int n = kSimd128Size / sizeof(T);
385 for (int i = 0; i < n; i++) {
386 T input = ReadUnalignedValue<T>(data + (i * sizeof(T)));
387 T value = float_round_op(input);
388 #if V8_OS_AIX
389 value = FpOpWorkaround<T>(input, value);
390 #endif
391 WriteUnalignedValue<T>(data + (i * sizeof(T)), value);
392 }
393 }
394
f64x2_ceil_wrapper(Address data)395 void f64x2_ceil_wrapper(Address data) {
396 simd_float_round_wrapper<double, &ceil>(data);
397 }
398
f64x2_floor_wrapper(Address data)399 void f64x2_floor_wrapper(Address data) {
400 simd_float_round_wrapper<double, &floor>(data);
401 }
402
f64x2_trunc_wrapper(Address data)403 void f64x2_trunc_wrapper(Address data) {
404 simd_float_round_wrapper<double, &trunc>(data);
405 }
406
f64x2_nearest_int_wrapper(Address data)407 void f64x2_nearest_int_wrapper(Address data) {
408 simd_float_round_wrapper<double, &nearbyint>(data);
409 }
410
f32x4_ceil_wrapper(Address data)411 void f32x4_ceil_wrapper(Address data) {
412 simd_float_round_wrapper<float, &ceilf>(data);
413 }
414
f32x4_floor_wrapper(Address data)415 void f32x4_floor_wrapper(Address data) {
416 simd_float_round_wrapper<float, &floorf>(data);
417 }
418
f32x4_trunc_wrapper(Address data)419 void f32x4_trunc_wrapper(Address data) {
420 simd_float_round_wrapper<float, &truncf>(data);
421 }
422
f32x4_nearest_int_wrapper(Address data)423 void f32x4_nearest_int_wrapper(Address data) {
424 simd_float_round_wrapper<float, &nearbyintf>(data);
425 }
426
427 namespace {
428 class V8_NODISCARD ThreadNotInWasmScope {
429 // Asan on Windows triggers exceptions to allocate shadow memory lazily. When
430 // this function is called from WebAssembly, these exceptions would be handled
431 // by the trap handler before they get handled by Asan, and thereby confuse the
432 // thread-in-wasm flag. Therefore we disable ASAN for this function.
433 // Alternatively we could reset the thread-in-wasm flag before calling this
434 // function. However, as this is only a problem with Asan on Windows, we did not
435 // consider it worth the overhead.
436 #if defined(RESET_THREAD_IN_WASM_FLAG_FOR_ASAN_ON_WINDOWS)
437
438 public:
ThreadNotInWasmScope()439 ThreadNotInWasmScope() : thread_was_in_wasm_(trap_handler::IsThreadInWasm()) {
440 if (thread_was_in_wasm_) {
441 trap_handler::ClearThreadInWasm();
442 }
443 }
444
~ThreadNotInWasmScope()445 ~ThreadNotInWasmScope() {
446 if (thread_was_in_wasm_) {
447 trap_handler::SetThreadInWasm();
448 }
449 }
450
451 private:
452 bool thread_was_in_wasm_;
453 #else
454
455 public:
456 ThreadNotInWasmScope() {
457 // This is needed to avoid compilation errors (unused variable).
458 USE(this);
459 }
460 #endif
461 };
462
EffectiveAddress(WasmInstanceObject instance,uintptr_t index)463 inline byte* EffectiveAddress(WasmInstanceObject instance, uintptr_t index) {
464 return instance.memory_start() + index;
465 }
466
467 template <typename V>
ReadAndIncrementOffset(Address data,size_t * offset)468 V ReadAndIncrementOffset(Address data, size_t* offset) {
469 V result = ReadUnalignedValue<V>(data + *offset);
470 *offset += sizeof(V);
471 return result;
472 }
473
474 constexpr int32_t kSuccess = 1;
475 constexpr int32_t kOutOfBounds = 0;
476 } // namespace
477
memory_init_wrapper(Address data)478 int32_t memory_init_wrapper(Address data) {
479 ThreadNotInWasmScope thread_not_in_wasm_scope;
480 DisallowGarbageCollection no_gc;
481 size_t offset = 0;
482 Object raw_instance = ReadAndIncrementOffset<Object>(data, &offset);
483 WasmInstanceObject instance = WasmInstanceObject::cast(raw_instance);
484 uintptr_t dst = ReadAndIncrementOffset<uintptr_t>(data, &offset);
485 uint32_t src = ReadAndIncrementOffset<uint32_t>(data, &offset);
486 uint32_t seg_index = ReadAndIncrementOffset<uint32_t>(data, &offset);
487 uint32_t size = ReadAndIncrementOffset<uint32_t>(data, &offset);
488
489 uint64_t mem_size = instance.memory_size();
490 if (!base::IsInBounds<uint64_t>(dst, size, mem_size)) return kOutOfBounds;
491
492 uint32_t seg_size = instance.data_segment_sizes()[seg_index];
493 if (!base::IsInBounds<uint32_t>(src, size, seg_size)) return kOutOfBounds;
494
495 byte* seg_start =
496 reinterpret_cast<byte*>(instance.data_segment_starts()[seg_index]);
497 std::memcpy(EffectiveAddress(instance, dst), seg_start + src, size);
498 return kSuccess;
499 }
500
memory_copy_wrapper(Address data)501 int32_t memory_copy_wrapper(Address data) {
502 ThreadNotInWasmScope thread_not_in_wasm_scope;
503 DisallowGarbageCollection no_gc;
504 size_t offset = 0;
505 Object raw_instance = ReadAndIncrementOffset<Object>(data, &offset);
506 WasmInstanceObject instance = WasmInstanceObject::cast(raw_instance);
507 uintptr_t dst = ReadAndIncrementOffset<uintptr_t>(data, &offset);
508 uintptr_t src = ReadAndIncrementOffset<uintptr_t>(data, &offset);
509 uintptr_t size = ReadAndIncrementOffset<uintptr_t>(data, &offset);
510
511 uint64_t mem_size = instance.memory_size();
512 if (!base::IsInBounds<uint64_t>(dst, size, mem_size)) return kOutOfBounds;
513 if (!base::IsInBounds<uint64_t>(src, size, mem_size)) return kOutOfBounds;
514
515 // Use std::memmove, because the ranges can overlap.
516 std::memmove(EffectiveAddress(instance, dst), EffectiveAddress(instance, src),
517 size);
518 return kSuccess;
519 }
520
memory_fill_wrapper(Address data)521 int32_t memory_fill_wrapper(Address data) {
522 ThreadNotInWasmScope thread_not_in_wasm_scope;
523 DisallowGarbageCollection no_gc;
524
525 size_t offset = 0;
526 Object raw_instance = ReadAndIncrementOffset<Object>(data, &offset);
527 WasmInstanceObject instance = WasmInstanceObject::cast(raw_instance);
528 uintptr_t dst = ReadAndIncrementOffset<uintptr_t>(data, &offset);
529 uint8_t value =
530 static_cast<uint8_t>(ReadAndIncrementOffset<uint32_t>(data, &offset));
531 uintptr_t size = ReadAndIncrementOffset<uintptr_t>(data, &offset);
532
533 uint64_t mem_size = instance.memory_size();
534 if (!base::IsInBounds<uint64_t>(dst, size, mem_size)) return kOutOfBounds;
535
536 std::memset(EffectiveAddress(instance, dst), value, size);
537 return kSuccess;
538 }
539
540 namespace {
ArrayElementAddress(WasmArray array,uint32_t index,int element_size_bytes)541 inline void* ArrayElementAddress(WasmArray array, uint32_t index,
542 int element_size_bytes) {
543 return reinterpret_cast<void*>(array.ptr() + WasmArray::kHeaderSize -
544 kHeapObjectTag + index * element_size_bytes);
545 }
546 } // namespace
547
array_copy_wrapper(Address raw_instance,Address raw_dst_array,uint32_t dst_index,Address raw_src_array,uint32_t src_index,uint32_t length)548 void array_copy_wrapper(Address raw_instance, Address raw_dst_array,
549 uint32_t dst_index, Address raw_src_array,
550 uint32_t src_index, uint32_t length) {
551 DCHECK_GT(length, 0);
552 ThreadNotInWasmScope thread_not_in_wasm_scope;
553 DisallowGarbageCollection no_gc;
554 WasmArray dst_array = WasmArray::cast(Object(raw_dst_array));
555 WasmArray src_array = WasmArray::cast(Object(raw_src_array));
556
557 bool overlapping_ranges =
558 dst_array.ptr() == src_array.ptr() &&
559 (dst_index < src_index ? dst_index + length > src_index
560 : src_index + length > dst_index);
561 wasm::ValueType element_type = src_array.type()->element_type();
562 if (element_type.is_reference()) {
563 WasmInstanceObject instance =
564 WasmInstanceObject::cast(Object(raw_instance));
565 Isolate* isolate = Isolate::FromRootAddress(instance.isolate_root());
566 ObjectSlot dst_slot = dst_array.ElementSlot(dst_index);
567 ObjectSlot src_slot = src_array.ElementSlot(src_index);
568 if (overlapping_ranges) {
569 isolate->heap()->MoveRange(dst_array, dst_slot, src_slot, length,
570 UPDATE_WRITE_BARRIER);
571 } else {
572 isolate->heap()->CopyRange(dst_array, dst_slot, src_slot, length,
573 UPDATE_WRITE_BARRIER);
574 }
575 } else {
576 int element_size_bytes = element_type.value_kind_size();
577 void* dst = ArrayElementAddress(dst_array, dst_index, element_size_bytes);
578 void* src = ArrayElementAddress(src_array, src_index, element_size_bytes);
579 size_t copy_size = length * element_size_bytes;
580 if (overlapping_ranges) {
581 MemMove(dst, src, copy_size);
582 } else {
583 MemCopy(dst, src, copy_size);
584 }
585 }
586 }
587
588 static WasmTrapCallbackForTesting wasm_trap_callback_for_testing = nullptr;
589
set_trap_callback_for_testing(WasmTrapCallbackForTesting callback)590 void set_trap_callback_for_testing(WasmTrapCallbackForTesting callback) {
591 wasm_trap_callback_for_testing = callback;
592 }
593
call_trap_callback_for_testing()594 void call_trap_callback_for_testing() {
595 if (wasm_trap_callback_for_testing) {
596 wasm_trap_callback_for_testing();
597 }
598 }
599
600 } // namespace wasm
601 } // namespace internal
602 } // namespace v8
603
604 #undef V8_WITH_SANITIZER
605 #undef RESET_THREAD_IN_WASM_FLAG_FOR_ASAN_ON_WINDOWS
606