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