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/arguments-inl.h"
      6 #include "src/base/bits.h"
      7 #include "src/bootstrapper.h"
      8 #include "src/isolate-inl.h"
      9 #include "src/runtime/runtime-utils.h"
     10 
     11 namespace v8 {
     12 namespace internal {
     13 
     14 RUNTIME_FUNCTION(Runtime_IsValidSmi) {
     15   SealHandleScope shs(isolate);
     16   DCHECK_EQ(1, args.length());
     17 
     18   CONVERT_NUMBER_CHECKED(int32_t, number, Int32, args[0]);
     19   return isolate->heap()->ToBoolean(Smi::IsValid(number));
     20 }
     21 
     22 
     23 RUNTIME_FUNCTION(Runtime_StringToNumber) {
     24   HandleScope handle_scope(isolate);
     25   DCHECK_EQ(1, args.length());
     26   CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
     27   return *String::ToNumber(isolate, subject);
     28 }
     29 
     30 
     31 // ES6 18.2.5 parseInt(string, radix) slow path
     32 RUNTIME_FUNCTION(Runtime_StringParseInt) {
     33   HandleScope handle_scope(isolate);
     34   DCHECK_EQ(2, args.length());
     35   CONVERT_ARG_HANDLE_CHECKED(Object, string, 0);
     36   CONVERT_ARG_HANDLE_CHECKED(Object, radix, 1);
     37 
     38   // Convert {string} to a String first, and flatten it.
     39   Handle<String> subject;
     40   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, subject,
     41                                      Object::ToString(isolate, string));
     42   subject = String::Flatten(isolate, subject);
     43 
     44   // Convert {radix} to Int32.
     45   if (!radix->IsNumber()) {
     46     ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, radix,
     47                                        Object::ToNumber(isolate, radix));
     48   }
     49   int radix32 = DoubleToInt32(radix->Number());
     50   if (radix32 != 0 && (radix32 < 2 || radix32 > 36)) {
     51     return ReadOnlyRoots(isolate).nan_value();
     52   }
     53 
     54   double result = StringToInt(isolate, subject, radix32);
     55   return *isolate->factory()->NewNumber(result);
     56 }
     57 
     58 
     59 // ES6 18.2.4 parseFloat(string)
     60 RUNTIME_FUNCTION(Runtime_StringParseFloat) {
     61   HandleScope shs(isolate);
     62   DCHECK_EQ(1, args.length());
     63   CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
     64 
     65   double value = StringToDouble(isolate, isolate->unicode_cache(), subject,
     66                                 ALLOW_TRAILING_JUNK,
     67                                 std::numeric_limits<double>::quiet_NaN());
     68 
     69   return *isolate->factory()->NewNumber(value);
     70 }
     71 
     72 RUNTIME_FUNCTION(Runtime_NumberToString) {
     73   HandleScope scope(isolate);
     74   DCHECK_EQ(1, args.length());
     75   CONVERT_NUMBER_ARG_HANDLE_CHECKED(number, 0);
     76 
     77   return *isolate->factory()->NumberToString(number);
     78 }
     79 
     80 // Compare two Smis x, y as if they were converted to strings and then
     81 // compared lexicographically. Returns:
     82 // -1 if x < y
     83 //  0 if x == y
     84 //  1 if x > y
     85 RUNTIME_FUNCTION(Runtime_SmiLexicographicCompare) {
     86   SealHandleScope shs(isolate);
     87   DCHECK_EQ(2, args.length());
     88   CONVERT_SMI_ARG_CHECKED(x_value, 0);
     89   CONVERT_SMI_ARG_CHECKED(y_value, 1);
     90 
     91   // If the integers are equal so are the string representations.
     92   if (x_value == y_value) return Smi::FromInt(0);
     93 
     94   // If one of the integers is zero the normal integer order is the
     95   // same as the lexicographic order of the string representations.
     96   if (x_value == 0 || y_value == 0)
     97     return Smi::FromInt(x_value < y_value ? -1 : 1);
     98 
     99   // If only one of the integers is negative the negative number is
    100   // smallest because the char code of '-' is less than the char code
    101   // of any digit.  Otherwise, we make both values positive.
    102 
    103   // Use unsigned values otherwise the logic is incorrect for -MIN_INT on
    104   // architectures using 32-bit Smis.
    105   uint32_t x_scaled = x_value;
    106   uint32_t y_scaled = y_value;
    107   if (x_value < 0 || y_value < 0) {
    108     if (y_value >= 0) return Smi::FromInt(-1);
    109     if (x_value >= 0) return Smi::FromInt(1);
    110     x_scaled = -x_value;
    111     y_scaled = -y_value;
    112   }
    113 
    114   static const uint32_t kPowersOf10[] = {
    115       1,                 10,                100,         1000,
    116       10 * 1000,         100 * 1000,        1000 * 1000, 10 * 1000 * 1000,
    117       100 * 1000 * 1000, 1000 * 1000 * 1000};
    118 
    119   // If the integers have the same number of decimal digits they can be
    120   // compared directly as the numeric order is the same as the
    121   // lexicographic order.  If one integer has fewer digits, it is scaled
    122   // by some power of 10 to have the same number of digits as the longer
    123   // integer.  If the scaled integers are equal it means the shorter
    124   // integer comes first in the lexicographic order.
    125 
    126   // From http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
    127   int x_log2 = 31 - base::bits::CountLeadingZeros(x_scaled);
    128   int x_log10 = ((x_log2 + 1) * 1233) >> 12;
    129   x_log10 -= x_scaled < kPowersOf10[x_log10];
    130 
    131   int y_log2 = 31 - base::bits::CountLeadingZeros(y_scaled);
    132   int y_log10 = ((y_log2 + 1) * 1233) >> 12;
    133   y_log10 -= y_scaled < kPowersOf10[y_log10];
    134 
    135   int tie = 0;
    136 
    137   if (x_log10 < y_log10) {
    138     // X has fewer digits.  We would like to simply scale up X but that
    139     // might overflow, e.g when comparing 9 with 1_000_000_000, 9 would
    140     // be scaled up to 9_000_000_000. So we scale up by the next
    141     // smallest power and scale down Y to drop one digit. It is OK to
    142     // drop one digit from the longer integer since the final digit is
    143     // past the length of the shorter integer.
    144     x_scaled *= kPowersOf10[y_log10 - x_log10 - 1];
    145     y_scaled /= 10;
    146     tie = -1;
    147   } else if (y_log10 < x_log10) {
    148     y_scaled *= kPowersOf10[x_log10 - y_log10 - 1];
    149     x_scaled /= 10;
    150     tie = 1;
    151   }
    152 
    153   if (x_scaled < y_scaled) return Smi::FromInt(-1);
    154   if (x_scaled > y_scaled) return Smi::FromInt(1);
    155   return Smi::FromInt(tie);
    156 }
    157 
    158 
    159 RUNTIME_FUNCTION(Runtime_MaxSmi) {
    160   SealHandleScope shs(isolate);
    161   DCHECK_EQ(0, args.length());
    162   return Smi::FromInt(Smi::kMaxValue);
    163 }
    164 
    165 
    166 RUNTIME_FUNCTION(Runtime_IsSmi) {
    167   SealHandleScope shs(isolate);
    168   DCHECK_EQ(1, args.length());
    169   CONVERT_ARG_CHECKED(Object, obj, 0);
    170   return isolate->heap()->ToBoolean(obj->IsSmi());
    171 }
    172 
    173 
    174 RUNTIME_FUNCTION(Runtime_GetHoleNaNUpper) {
    175   HandleScope scope(isolate);
    176   DCHECK_EQ(0, args.length());
    177   return *isolate->factory()->NewNumberFromUint(kHoleNanUpper32);
    178 }
    179 
    180 
    181 RUNTIME_FUNCTION(Runtime_GetHoleNaNLower) {
    182   HandleScope scope(isolate);
    183   DCHECK_EQ(0, args.length());
    184   return *isolate->factory()->NewNumberFromUint(kHoleNanLower32);
    185 }
    186 
    187 
    188 }  // namespace internal
    189 }  // namespace v8
    190