Home | History | Annotate | Download | only in runtime
      1 // Copyright 2014 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 "src/runtime/runtime-utils.h"
      6 
      7 #include "src/arguments.h"
      8 #include "src/assembler.h"
      9 #include "src/base/utils/random-number-generator.h"
     10 #include "src/bootstrapper.h"
     11 #include "src/codegen.h"
     12 #include "src/third_party/fdlibm/fdlibm.h"
     13 
     14 namespace v8 {
     15 namespace internal {
     16 
     17 #define RUNTIME_UNARY_MATH(Name, name)                       \
     18   RUNTIME_FUNCTION(Runtime_Math##Name) {                     \
     19     HandleScope scope(isolate);                              \
     20     DCHECK(args.length() == 1);                              \
     21     isolate->counters()->math_##name()->Increment();         \
     22     CONVERT_DOUBLE_ARG_CHECKED(x, 0);                        \
     23     return *isolate->factory()->NewHeapNumber(std::name(x)); \
     24   }
     25 
     26 RUNTIME_UNARY_MATH(Acos, acos)
     27 RUNTIME_UNARY_MATH(Asin, asin)
     28 RUNTIME_UNARY_MATH(Atan, atan)
     29 RUNTIME_UNARY_MATH(LogRT, log)
     30 #undef RUNTIME_UNARY_MATH
     31 
     32 
     33 RUNTIME_FUNCTION(Runtime_DoubleHi) {
     34   HandleScope scope(isolate);
     35   DCHECK(args.length() == 1);
     36   CONVERT_DOUBLE_ARG_CHECKED(x, 0);
     37   uint64_t unsigned64 = double_to_uint64(x);
     38   uint32_t unsigned32 = static_cast<uint32_t>(unsigned64 >> 32);
     39   int32_t signed32 = bit_cast<int32_t, uint32_t>(unsigned32);
     40   return *isolate->factory()->NewNumber(signed32);
     41 }
     42 
     43 
     44 RUNTIME_FUNCTION(Runtime_DoubleLo) {
     45   HandleScope scope(isolate);
     46   DCHECK(args.length() == 1);
     47   CONVERT_DOUBLE_ARG_CHECKED(x, 0);
     48   uint64_t unsigned64 = double_to_uint64(x);
     49   uint32_t unsigned32 = static_cast<uint32_t>(unsigned64);
     50   int32_t signed32 = bit_cast<int32_t, uint32_t>(unsigned32);
     51   return *isolate->factory()->NewNumber(signed32);
     52 }
     53 
     54 
     55 RUNTIME_FUNCTION(Runtime_ConstructDouble) {
     56   HandleScope scope(isolate);
     57   DCHECK(args.length() == 2);
     58   CONVERT_NUMBER_CHECKED(uint32_t, hi, Uint32, args[0]);
     59   CONVERT_NUMBER_CHECKED(uint32_t, lo, Uint32, args[1]);
     60   uint64_t result = (static_cast<uint64_t>(hi) << 32) | lo;
     61   return *isolate->factory()->NewNumber(uint64_to_double(result));
     62 }
     63 
     64 
     65 RUNTIME_FUNCTION(Runtime_RemPiO2) {
     66   SealHandleScope shs(isolate);
     67   DisallowHeapAllocation no_gc;
     68   DCHECK(args.length() == 2);
     69   CONVERT_DOUBLE_ARG_CHECKED(x, 0);
     70   CONVERT_ARG_CHECKED(JSTypedArray, result, 1);
     71   RUNTIME_ASSERT(result->byte_length() == Smi::FromInt(2 * sizeof(double)));
     72   FixedFloat64Array* array = FixedFloat64Array::cast(result->elements());
     73   double* y = static_cast<double*>(array->DataPtr());
     74   return Smi::FromInt(fdlibm::rempio2(x, y));
     75 }
     76 
     77 
     78 static const double kPiDividedBy4 = 0.78539816339744830962;
     79 
     80 
     81 RUNTIME_FUNCTION(Runtime_MathAtan2) {
     82   HandleScope scope(isolate);
     83   DCHECK(args.length() == 2);
     84   isolate->counters()->math_atan2()->Increment();
     85 
     86   CONVERT_DOUBLE_ARG_CHECKED(x, 0);
     87   CONVERT_DOUBLE_ARG_CHECKED(y, 1);
     88   double result;
     89   if (std::isinf(x) && std::isinf(y)) {
     90     // Make sure that the result in case of two infinite arguments
     91     // is a multiple of Pi / 4. The sign of the result is determined
     92     // by the first argument (x) and the sign of the second argument
     93     // determines the multiplier: one or three.
     94     int multiplier = (x < 0) ? -1 : 1;
     95     if (y < 0) multiplier *= 3;
     96     result = multiplier * kPiDividedBy4;
     97   } else {
     98     result = std::atan2(x, y);
     99   }
    100   return *isolate->factory()->NewNumber(result);
    101 }
    102 
    103 
    104 RUNTIME_FUNCTION(Runtime_MathExpRT) {
    105   HandleScope scope(isolate);
    106   DCHECK(args.length() == 1);
    107   isolate->counters()->math_exp()->Increment();
    108 
    109   CONVERT_DOUBLE_ARG_CHECKED(x, 0);
    110   lazily_initialize_fast_exp(isolate);
    111   return *isolate->factory()->NewNumber(fast_exp(x, isolate));
    112 }
    113 
    114 
    115 RUNTIME_FUNCTION(Runtime_MathClz32) {
    116   HandleScope scope(isolate);
    117   DCHECK(args.length() == 1);
    118   isolate->counters()->math_clz32()->Increment();
    119 
    120   CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
    121   return *isolate->factory()->NewNumberFromUint(
    122       base::bits::CountLeadingZeros32(x));
    123 }
    124 
    125 
    126 RUNTIME_FUNCTION(Runtime_MathFloor) {
    127   HandleScope scope(isolate);
    128   DCHECK(args.length() == 1);
    129   isolate->counters()->math_floor()->Increment();
    130 
    131   CONVERT_DOUBLE_ARG_CHECKED(x, 0);
    132   return *isolate->factory()->NewNumber(Floor(x));
    133 }
    134 
    135 
    136 // Slow version of Math.pow.  We check for fast paths for special cases.
    137 // Used if VFP3 is not available.
    138 RUNTIME_FUNCTION(Runtime_MathPow) {
    139   HandleScope scope(isolate);
    140   DCHECK(args.length() == 2);
    141   isolate->counters()->math_pow()->Increment();
    142 
    143   CONVERT_DOUBLE_ARG_CHECKED(x, 0);
    144 
    145   // If the second argument is a smi, it is much faster to call the
    146   // custom powi() function than the generic pow().
    147   if (args[1]->IsSmi()) {
    148     int y = args.smi_at(1);
    149     return *isolate->factory()->NewNumber(power_double_int(x, y));
    150   }
    151 
    152   CONVERT_DOUBLE_ARG_CHECKED(y, 1);
    153   double result = power_helper(isolate, x, y);
    154   if (std::isnan(result)) return isolate->heap()->nan_value();
    155   return *isolate->factory()->NewNumber(result);
    156 }
    157 
    158 
    159 // Fast version of Math.pow if we know that y is not an integer and y is not
    160 // -0.5 or 0.5.  Used as slow case from full codegen.
    161 RUNTIME_FUNCTION(Runtime_MathPowRT) {
    162   HandleScope scope(isolate);
    163   DCHECK(args.length() == 2);
    164   isolate->counters()->math_pow()->Increment();
    165 
    166   CONVERT_DOUBLE_ARG_CHECKED(x, 0);
    167   CONVERT_DOUBLE_ARG_CHECKED(y, 1);
    168   if (y == 0) {
    169     return Smi::FromInt(1);
    170   } else {
    171     double result = power_double_double(x, y);
    172     if (std::isnan(result)) return isolate->heap()->nan_value();
    173     return *isolate->factory()->NewNumber(result);
    174   }
    175 }
    176 
    177 
    178 RUNTIME_FUNCTION(Runtime_RoundNumber) {
    179   HandleScope scope(isolate);
    180   DCHECK(args.length() == 1);
    181   CONVERT_NUMBER_ARG_HANDLE_CHECKED(input, 0);
    182   isolate->counters()->math_round()->Increment();
    183 
    184   if (!input->IsHeapNumber()) {
    185     DCHECK(input->IsSmi());
    186     return *input;
    187   }
    188 
    189   Handle<HeapNumber> number = Handle<HeapNumber>::cast(input);
    190 
    191   double value = number->value();
    192   int exponent = number->get_exponent();
    193   int sign = number->get_sign();
    194 
    195   if (exponent < -1) {
    196     // Number in range ]-0.5..0.5[. These always round to +/-zero.
    197     if (sign) return isolate->heap()->minus_zero_value();
    198     return Smi::FromInt(0);
    199   }
    200 
    201   // We compare with kSmiValueSize - 2 because (2^30 - 0.1) has exponent 29 and
    202   // should be rounded to 2^30, which is not smi (for 31-bit smis, similar
    203   // argument holds for 32-bit smis).
    204   if (!sign && exponent < kSmiValueSize - 2) {
    205     return Smi::FromInt(static_cast<int>(value + 0.5));
    206   }
    207 
    208   // If the magnitude is big enough, there's no place for fraction part. If we
    209   // try to add 0.5 to this number, 1.0 will be added instead.
    210   if (exponent >= 52) {
    211     return *number;
    212   }
    213 
    214   if (sign && value >= -0.5) return isolate->heap()->minus_zero_value();
    215 
    216   // Do not call NumberFromDouble() to avoid extra checks.
    217   return *isolate->factory()->NewNumber(Floor(value + 0.5));
    218 }
    219 
    220 
    221 RUNTIME_FUNCTION(Runtime_MathSqrt) {
    222   HandleScope scope(isolate);
    223   DCHECK(args.length() == 1);
    224   isolate->counters()->math_sqrt()->Increment();
    225 
    226   CONVERT_DOUBLE_ARG_CHECKED(x, 0);
    227   lazily_initialize_fast_sqrt(isolate);
    228   return *isolate->factory()->NewNumber(fast_sqrt(x, isolate));
    229 }
    230 
    231 
    232 RUNTIME_FUNCTION(Runtime_MathFround) {
    233   HandleScope scope(isolate);
    234   DCHECK(args.length() == 1);
    235 
    236   CONVERT_DOUBLE_ARG_CHECKED(x, 0);
    237   float xf = DoubleToFloat32(x);
    238   return *isolate->factory()->NewNumber(xf);
    239 }
    240 
    241 
    242 RUNTIME_FUNCTION(Runtime_IsMinusZero) {
    243   SealHandleScope shs(isolate);
    244   DCHECK(args.length() == 1);
    245   CONVERT_ARG_CHECKED(Object, obj, 0);
    246   if (!obj->IsHeapNumber()) return isolate->heap()->false_value();
    247   HeapNumber* number = HeapNumber::cast(obj);
    248   return isolate->heap()->ToBoolean(IsMinusZero(number->value()));
    249 }
    250 
    251 
    252 RUNTIME_FUNCTION(Runtime_GenerateRandomNumbers) {
    253   HandleScope scope(isolate);
    254   DCHECK(args.length() == 1);
    255   // Random numbers in the snapshot are not really that random.
    256   DCHECK(!isolate->bootstrapper()->IsActive());
    257   static const int kState0Offset = 0;
    258   static const int kState1Offset = 1;
    259   static const int kRandomBatchSize = 64;
    260   CONVERT_ARG_HANDLE_CHECKED(Object, maybe_typed_array, 0);
    261   Handle<JSTypedArray> typed_array;
    262   // Allocate typed array if it does not yet exist.
    263   if (maybe_typed_array->IsJSTypedArray()) {
    264     typed_array = Handle<JSTypedArray>::cast(maybe_typed_array);
    265   } else {
    266     static const int kByteLength = kRandomBatchSize * kDoubleSize;
    267     Handle<JSArrayBuffer> buffer =
    268         isolate->factory()->NewJSArrayBuffer(SharedFlag::kNotShared, TENURED);
    269     JSArrayBuffer::SetupAllocatingData(buffer, isolate, kByteLength, true,
    270                                        SharedFlag::kNotShared);
    271     typed_array = isolate->factory()->NewJSTypedArray(
    272         kExternalFloat64Array, buffer, 0, kRandomBatchSize);
    273   }
    274 
    275   DisallowHeapAllocation no_gc;
    276   double* array =
    277       reinterpret_cast<double*>(typed_array->GetBuffer()->backing_store());
    278   // Fetch existing state.
    279   uint64_t state0 = double_to_uint64(array[kState0Offset]);
    280   uint64_t state1 = double_to_uint64(array[kState1Offset]);
    281   // Initialize state if not yet initialized.
    282   while (state0 == 0 || state1 == 0) {
    283     isolate->random_number_generator()->NextBytes(&state0, sizeof(state0));
    284     isolate->random_number_generator()->NextBytes(&state1, sizeof(state1));
    285   }
    286   // Create random numbers.
    287   for (int i = kState1Offset + 1; i < kRandomBatchSize; i++) {
    288     // Generate random numbers using xorshift128+.
    289     base::RandomNumberGenerator::XorShift128(&state0, &state1);
    290     array[i] = base::RandomNumberGenerator::ToDouble(state0, state1);
    291   }
    292   // Persist current state.
    293   array[kState0Offset] = uint64_to_double(state0);
    294   array[kState1Offset] = uint64_to_double(state1);
    295   return *typed_array;
    296 }
    297 }  // namespace internal
    298 }  // namespace v8
    299