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 
     13 namespace v8 {
     14 namespace internal {
     15 
     16 RUNTIME_FUNCTION(Runtime_DoubleHi) {
     17   HandleScope scope(isolate);
     18   DCHECK(args.length() == 1);
     19   CONVERT_DOUBLE_ARG_CHECKED(x, 0);
     20   uint64_t unsigned64 = double_to_uint64(x);
     21   uint32_t unsigned32 = static_cast<uint32_t>(unsigned64 >> 32);
     22   int32_t signed32 = bit_cast<int32_t, uint32_t>(unsigned32);
     23   return *isolate->factory()->NewNumber(signed32);
     24 }
     25 
     26 
     27 RUNTIME_FUNCTION(Runtime_DoubleLo) {
     28   HandleScope scope(isolate);
     29   DCHECK(args.length() == 1);
     30   CONVERT_DOUBLE_ARG_CHECKED(x, 0);
     31   uint64_t unsigned64 = double_to_uint64(x);
     32   uint32_t unsigned32 = static_cast<uint32_t>(unsigned64);
     33   int32_t signed32 = bit_cast<int32_t, uint32_t>(unsigned32);
     34   return *isolate->factory()->NewNumber(signed32);
     35 }
     36 
     37 
     38 // Slow version of Math.pow.  We check for fast paths for special cases.
     39 // Used if VFP3 is not available.
     40 RUNTIME_FUNCTION(Runtime_MathPow) {
     41   HandleScope scope(isolate);
     42   DCHECK(args.length() == 2);
     43   isolate->counters()->math_pow_runtime()->Increment();
     44 
     45   CONVERT_DOUBLE_ARG_CHECKED(x, 0);
     46 
     47   // If the second argument is a smi, it is much faster to call the
     48   // custom powi() function than the generic pow().
     49   if (args[1]->IsSmi()) {
     50     int y = args.smi_at(1);
     51     return *isolate->factory()->NewNumber(power_double_int(x, y));
     52   }
     53 
     54   CONVERT_DOUBLE_ARG_CHECKED(y, 1);
     55   double result = power_helper(isolate, x, y);
     56   if (std::isnan(result)) return isolate->heap()->nan_value();
     57   return *isolate->factory()->NewNumber(result);
     58 }
     59 
     60 
     61 // Fast version of Math.pow if we know that y is not an integer and y is not
     62 // -0.5 or 0.5.  Used as slow case from full codegen.
     63 RUNTIME_FUNCTION(Runtime_MathPowRT) {
     64   HandleScope scope(isolate);
     65   DCHECK(args.length() == 2);
     66   isolate->counters()->math_pow_runtime()->Increment();
     67 
     68   CONVERT_DOUBLE_ARG_CHECKED(x, 0);
     69   CONVERT_DOUBLE_ARG_CHECKED(y, 1);
     70   if (y == 0) {
     71     return Smi::FromInt(1);
     72   } else {
     73     double result = power_double_double(x, y);
     74     if (std::isnan(result)) return isolate->heap()->nan_value();
     75     return *isolate->factory()->NewNumber(result);
     76   }
     77 }
     78 
     79 
     80 RUNTIME_FUNCTION(Runtime_GenerateRandomNumbers) {
     81   HandleScope scope(isolate);
     82   DCHECK(args.length() == 1);
     83   if (isolate->serializer_enabled()) {
     84     // Random numbers in the snapshot are not really that random. And we cannot
     85     // return a typed array as it cannot be serialized. To make calling
     86     // Math.random possible when creating a custom startup snapshot, we simply
     87     // return a normal array with a single random number.
     88     Handle<HeapNumber> random_number = isolate->factory()->NewHeapNumber(
     89         isolate->random_number_generator()->NextDouble());
     90     Handle<FixedArray> array_backing = isolate->factory()->NewFixedArray(1);
     91     array_backing->set(0, *random_number);
     92     return *isolate->factory()->NewJSArrayWithElements(array_backing);
     93   }
     94 
     95   static const int kState0Offset = 0;
     96   static const int kState1Offset = 1;
     97   static const int kRandomBatchSize = 64;
     98   CONVERT_ARG_HANDLE_CHECKED(Object, maybe_typed_array, 0);
     99   Handle<JSTypedArray> typed_array;
    100   // Allocate typed array if it does not yet exist.
    101   if (maybe_typed_array->IsJSTypedArray()) {
    102     typed_array = Handle<JSTypedArray>::cast(maybe_typed_array);
    103   } else {
    104     static const int kByteLength = kRandomBatchSize * kDoubleSize;
    105     Handle<JSArrayBuffer> buffer =
    106         isolate->factory()->NewJSArrayBuffer(SharedFlag::kNotShared, TENURED);
    107     JSArrayBuffer::SetupAllocatingData(buffer, isolate, kByteLength, true,
    108                                        SharedFlag::kNotShared);
    109     typed_array = isolate->factory()->NewJSTypedArray(
    110         kExternalFloat64Array, buffer, 0, kRandomBatchSize);
    111   }
    112 
    113   DisallowHeapAllocation no_gc;
    114   double* array =
    115       reinterpret_cast<double*>(typed_array->GetBuffer()->backing_store());
    116   // Fetch existing state.
    117   uint64_t state0 = double_to_uint64(array[kState0Offset]);
    118   uint64_t state1 = double_to_uint64(array[kState1Offset]);
    119   // Initialize state if not yet initialized.
    120   while (state0 == 0 || state1 == 0) {
    121     isolate->random_number_generator()->NextBytes(&state0, sizeof(state0));
    122     isolate->random_number_generator()->NextBytes(&state1, sizeof(state1));
    123   }
    124   // Create random numbers.
    125   for (int i = kState1Offset + 1; i < kRandomBatchSize; i++) {
    126     // Generate random numbers using xorshift128+.
    127     base::RandomNumberGenerator::XorShift128(&state0, &state1);
    128     array[i] = base::RandomNumberGenerator::ToDouble(state0, state1);
    129   }
    130   // Persist current state.
    131   array[kState0Offset] = uint64_to_double(state0);
    132   array[kState1Offset] = uint64_to_double(state1);
    133   return *typed_array;
    134 }
    135 }  // namespace internal
    136 }  // namespace v8
    137