• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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