Home | History | Annotate | Download | only in wasm
      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