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 21 void f32_trunc_wrapper(Address data) { 22 WriteUnalignedValue<float>(data, truncf(ReadUnalignedValue<float>(data))); 23 } 24 25 void f32_floor_wrapper(Address data) { 26 WriteUnalignedValue<float>(data, floorf(ReadUnalignedValue<float>(data))); 27 } 28 29 void f32_ceil_wrapper(Address data) { 30 WriteUnalignedValue<float>(data, ceilf(ReadUnalignedValue<float>(data))); 31 } 32 33 void f32_nearest_int_wrapper(Address data) { 34 WriteUnalignedValue<float>(data, nearbyintf(ReadUnalignedValue<float>(data))); 35 } 36 37 void f64_trunc_wrapper(Address data) { 38 WriteUnalignedValue<double>(data, trunc(ReadUnalignedValue<double>(data))); 39 } 40 41 void f64_floor_wrapper(Address data) { 42 WriteUnalignedValue<double>(data, floor(ReadUnalignedValue<double>(data))); 43 } 44 45 void f64_ceil_wrapper(Address data) { 46 WriteUnalignedValue<double>(data, ceil(ReadUnalignedValue<double>(data))); 47 } 48 49 void f64_nearest_int_wrapper(Address data) { 50 WriteUnalignedValue<double>(data, 51 nearbyint(ReadUnalignedValue<double>(data))); 52 } 53 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 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 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 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 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 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 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 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 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 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 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 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 216 uint32_t word32_ctz_wrapper(Address data) { 217 return base::bits::CountTrailingZeros(ReadUnalignedValue<uint32_t>(data)); 218 } 219 220 uint32_t word64_ctz_wrapper(Address data) { 221 return base::bits::CountTrailingZeros(ReadUnalignedValue<uint64_t>(data)); 222 } 223 224 uint32_t word32_popcnt_wrapper(Address data) { 225 return base::bits::CountPopulation(ReadUnalignedValue<uint32_t>(data)); 226 } 227 228 uint32_t word64_popcnt_wrapper(Address data) { 229 return base::bits::CountPopulation(ReadUnalignedValue<uint64_t>(data)); 230 } 231 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 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 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 252 void set_trap_callback_for_testing(WasmTrapCallbackForTesting callback) { 253 wasm_trap_callback_for_testing = callback; 254 } 255 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