• 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 #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