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 <math.h>
6 : #include <stdint.h>
7 : #include <stdlib.h>
8 : #include <limits>
9 :
10 : #include "include/v8config.h"
11 :
12 : #include "src/base/bits.h"
13 : #include "src/memcopy.h"
14 : #include "src/utils.h"
15 : #include "src/v8memory.h"
16 : #include "src/wasm/wasm-external-refs.h"
17 :
18 : namespace v8 {
19 : namespace internal {
20 : namespace wasm {
21 :
22 1150 : void f32_trunc_wrapper(Address data) {
23 1150 : WriteUnalignedValue<float>(data, truncf(ReadUnalignedValue<float>(data)));
24 1150 : }
25 :
26 1150 : void f32_floor_wrapper(Address data) {
27 1150 : WriteUnalignedValue<float>(data, floorf(ReadUnalignedValue<float>(data)));
28 1150 : }
29 :
30 1150 : void f32_ceil_wrapper(Address data) {
31 1150 : WriteUnalignedValue<float>(data, ceilf(ReadUnalignedValue<float>(data)));
32 1150 : }
33 :
34 1150 : void f32_nearest_int_wrapper(Address data) {
35 1150 : WriteUnalignedValue<float>(data, nearbyintf(ReadUnalignedValue<float>(data)));
36 1150 : }
37 :
38 490 : void f64_trunc_wrapper(Address data) {
39 490 : WriteUnalignedValue<double>(data, trunc(ReadUnalignedValue<double>(data)));
40 490 : }
41 :
42 490 : void f64_floor_wrapper(Address data) {
43 490 : WriteUnalignedValue<double>(data, floor(ReadUnalignedValue<double>(data)));
44 490 : }
45 :
46 490 : void f64_ceil_wrapper(Address data) {
47 490 : WriteUnalignedValue<double>(data, ceil(ReadUnalignedValue<double>(data)));
48 490 : }
49 :
50 490 : void f64_nearest_int_wrapper(Address data) {
51 : WriteUnalignedValue<double>(data,
52 490 : nearbyint(ReadUnalignedValue<double>(data)));
53 490 : }
54 :
55 810 : void int64_to_float32_wrapper(Address data) {
56 : int64_t input = ReadUnalignedValue<int64_t>(data);
57 810 : WriteUnalignedValue<float>(data, static_cast<float>(input));
58 810 : }
59 :
60 1190 : void uint64_to_float32_wrapper(Address data) {
61 : uint64_t input = ReadUnalignedValue<uint64_t>(data);
62 1190 : float result = static_cast<float>(input);
63 :
64 : #if V8_CC_MSVC
65 : // With MSVC we use static_cast<float>(uint32_t) instead of
66 : // static_cast<float>(uint64_t) to achieve round-to-nearest-ties-even
67 : // semantics. The idea is to calculate
68 : // static_cast<float>(high_word) * 2^32 + static_cast<float>(low_word). To
69 : // achieve proper rounding in all cases we have to adjust the high_word
70 : // with a "rounding bit" sometimes. The rounding bit is stored in the LSB of
71 : // the high_word if the low_word may affect the rounding of the high_word.
72 : uint32_t low_word = static_cast<uint32_t>(input & 0xFFFFFFFF);
73 : uint32_t high_word = static_cast<uint32_t>(input >> 32);
74 :
75 : float shift = static_cast<float>(1ull << 32);
76 : // If the MSB of the high_word is set, then we make space for a rounding bit.
77 : if (high_word < 0x80000000) {
78 : high_word <<= 1;
79 : shift = static_cast<float>(1ull << 31);
80 : }
81 :
82 : if ((high_word & 0xFE000000) && low_word) {
83 : // Set the rounding bit.
84 : high_word |= 1;
85 : }
86 :
87 : result = static_cast<float>(high_word);
88 : result *= shift;
89 : result += static_cast<float>(low_word);
90 : #endif
91 :
92 : WriteUnalignedValue<float>(data, result);
93 1190 : }
94 :
95 810 : void int64_to_float64_wrapper(Address data) {
96 : int64_t input = ReadUnalignedValue<int64_t>(data);
97 810 : WriteUnalignedValue<double>(data, static_cast<double>(input));
98 810 : }
99 :
100 1185 : void uint64_to_float64_wrapper(Address data) {
101 : uint64_t input = ReadUnalignedValue<uint64_t>(data);
102 1185 : double result = static_cast<double>(input);
103 :
104 : #if V8_CC_MSVC
105 : // With MSVC we use static_cast<double>(uint32_t) instead of
106 : // static_cast<double>(uint64_t) to achieve round-to-nearest-ties-even
107 : // semantics. The idea is to calculate
108 : // static_cast<double>(high_word) * 2^32 + static_cast<double>(low_word).
109 : uint32_t low_word = static_cast<uint32_t>(input & 0xFFFFFFFF);
110 : uint32_t high_word = static_cast<uint32_t>(input >> 32);
111 :
112 : double shift = static_cast<double>(1ull << 32);
113 :
114 : result = static_cast<double>(high_word);
115 : result *= shift;
116 : result += static_cast<double>(low_word);
117 : #endif
118 :
119 : WriteUnalignedValue<double>(data, result);
120 1185 : }
121 :
122 2300 : int32_t float32_to_int64_wrapper(Address data) {
123 : // We use "<" here to check the upper bound because of rounding problems: With
124 : // "<=" some inputs would be considered within int64 range which are actually
125 : // not within int64 range.
126 : float input = ReadUnalignedValue<float>(data);
127 2300 : if (input >= static_cast<float>(std::numeric_limits<int64_t>::min()) &&
128 : input < static_cast<float>(std::numeric_limits<int64_t>::max())) {
129 1660 : WriteUnalignedValue<int64_t>(data, static_cast<int64_t>(input));
130 1660 : return 1;
131 : }
132 : return 0;
133 : }
134 :
135 2300 : int32_t float32_to_uint64_wrapper(Address data) {
136 : float input = ReadUnalignedValue<float>(data);
137 : // We use "<" here to check the upper bound because of rounding problems: With
138 : // "<=" some inputs would be considered within uint64 range which are actually
139 : // not within uint64 range.
140 2300 : if (input > -1.0 &&
141 : input < static_cast<float>(std::numeric_limits<uint64_t>::max())) {
142 1020 : WriteUnalignedValue<uint64_t>(data, static_cast<uint64_t>(input));
143 1020 : return 1;
144 : }
145 : return 0;
146 : }
147 :
148 1394 : int32_t float64_to_int64_wrapper(Address data) {
149 : // We use "<" here to check the upper bound because of rounding problems: With
150 : // "<=" some inputs would be considered within int64 range which are actually
151 : // not within int64 range.
152 : double input = ReadUnalignedValue<double>(data);
153 1394 : if (input >= static_cast<double>(std::numeric_limits<int64_t>::min()) &&
154 : input < static_cast<double>(std::numeric_limits<int64_t>::max())) {
155 1174 : WriteUnalignedValue<int64_t>(data, static_cast<int64_t>(input));
156 1174 : return 1;
157 : }
158 : return 0;
159 : }
160 :
161 980 : int32_t float64_to_uint64_wrapper(Address data) {
162 : // We use "<" here to check the upper bound because of rounding problems: With
163 : // "<=" some inputs would be considered within uint64 range which are actually
164 : // not within uint64 range.
165 : double input = ReadUnalignedValue<double>(data);
166 980 : if (input > -1.0 &&
167 : input < static_cast<double>(std::numeric_limits<uint64_t>::max())) {
168 580 : WriteUnalignedValue<uint64_t>(data, static_cast<uint64_t>(input));
169 580 : return 1;
170 : }
171 : return 0;
172 : }
173 :
174 65610 : int32_t int64_div_wrapper(Address data) {
175 : int64_t dividend = ReadUnalignedValue<int64_t>(data);
176 65610 : int64_t divisor = ReadUnalignedValue<int64_t>(data + sizeof(dividend));
177 65610 : if (divisor == 0) {
178 : return 0;
179 : }
180 63990 : if (divisor == -1 && dividend == std::numeric_limits<int64_t>::min()) {
181 : return -1;
182 : }
183 63990 : WriteUnalignedValue<int64_t>(data, dividend / divisor);
184 63990 : return 1;
185 : }
186 :
187 65610 : int32_t int64_mod_wrapper(Address data) {
188 : int64_t dividend = ReadUnalignedValue<int64_t>(data);
189 65610 : int64_t divisor = ReadUnalignedValue<int64_t>(data + sizeof(dividend));
190 65610 : if (divisor == 0) {
191 : return 0;
192 : }
193 63990 : WriteUnalignedValue<int64_t>(data, dividend % divisor);
194 63990 : return 1;
195 : }
196 :
197 65610 : int32_t uint64_div_wrapper(Address data) {
198 : uint64_t dividend = ReadUnalignedValue<uint64_t>(data);
199 65610 : uint64_t divisor = ReadUnalignedValue<uint64_t>(data + sizeof(dividend));
200 65610 : if (divisor == 0) {
201 : return 0;
202 : }
203 63990 : WriteUnalignedValue<uint64_t>(data, dividend / divisor);
204 63990 : return 1;
205 : }
206 :
207 65610 : int32_t uint64_mod_wrapper(Address data) {
208 : uint64_t dividend = ReadUnalignedValue<uint64_t>(data);
209 65610 : uint64_t divisor = ReadUnalignedValue<uint64_t>(data + sizeof(dividend));
210 65610 : if (divisor == 0) {
211 : return 0;
212 : }
213 63990 : WriteUnalignedValue<uint64_t>(data, dividend % divisor);
214 63990 : return 1;
215 : }
216 :
217 580 : uint32_t word32_ctz_wrapper(Address data) {
218 580 : return base::bits::CountTrailingZeros(ReadUnalignedValue<uint32_t>(data));
219 : }
220 :
221 810 : uint32_t word64_ctz_wrapper(Address data) {
222 810 : return base::bits::CountTrailingZeros(ReadUnalignedValue<uint64_t>(data));
223 : }
224 :
225 580 : uint32_t word32_popcnt_wrapper(Address data) {
226 580 : return base::bits::CountPopulation(ReadUnalignedValue<uint32_t>(data));
227 : }
228 :
229 810 : uint32_t word64_popcnt_wrapper(Address data) {
230 810 : return base::bits::CountPopulation(ReadUnalignedValue<uint64_t>(data));
231 : }
232 :
233 33649 : uint32_t word32_rol_wrapper(Address data) {
234 : uint32_t input = ReadUnalignedValue<uint32_t>(data);
235 67298 : uint32_t shift = ReadUnalignedValue<uint32_t>(data + sizeof(input)) & 31;
236 33649 : return (input << shift) | (input >> ((32 - shift) & 31));
237 : }
238 :
239 33640 : uint32_t word32_ror_wrapper(Address data) {
240 : uint32_t input = ReadUnalignedValue<uint32_t>(data);
241 67280 : uint32_t shift = ReadUnalignedValue<uint32_t>(data + sizeof(input)) & 31;
242 33640 : return (input >> shift) | (input << ((32 - shift) & 31));
243 : }
244 :
245 24049 : void float64_pow_wrapper(Address data) {
246 : double x = ReadUnalignedValue<double>(data);
247 24049 : double y = ReadUnalignedValue<double>(data + sizeof(x));
248 24049 : WriteUnalignedValue<double>(data, Pow(x, y));
249 24049 : }
250 :
251 99 : void memory_copy_wrapper(Address dst, Address src, uint32_t size) {
252 99 : MemMove(reinterpret_cast<void*>(dst), reinterpret_cast<void*>(src), size);
253 99 : }
254 :
255 54 : void memory_fill_wrapper(Address dst, uint32_t value, uint32_t size) {
256 54 : memset(reinterpret_cast<void*>(dst), value, size);
257 54 : }
258 :
259 : static WasmTrapCallbackForTesting wasm_trap_callback_for_testing = nullptr;
260 :
261 11627460 : void set_trap_callback_for_testing(WasmTrapCallbackForTesting callback) {
262 11627460 : wasm_trap_callback_for_testing = callback;
263 11627460 : }
264 :
265 90390 : void call_trap_callback_for_testing() {
266 90390 : if (wasm_trap_callback_for_testing) {
267 90390 : wasm_trap_callback_for_testing();
268 : }
269 90390 : }
270 :
271 : } // namespace wasm
272 : } // namespace internal
273 183867 : } // namespace v8
|