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/base/bits.h"
      9 #include "src/bootstrapper.h"
     10 #include "src/codegen.h"
     11 #include "src/isolate-inl.h"
     12 
     13 namespace v8 {
     14 namespace internal {
     15 
     16 RUNTIME_FUNCTION(Runtime_NumberToRadixString) {
     17   HandleScope scope(isolate);
     18   DCHECK(args.length() == 2);
     19   CONVERT_SMI_ARG_CHECKED(radix, 1);
     20   RUNTIME_ASSERT(2 <= radix && radix <= 36);
     21 
     22   // Fast case where the result is a one character string.
     23   if (args[0]->IsSmi()) {
     24     int value = args.smi_at(0);
     25     if (value >= 0 && value < radix) {
     26       // Character array used for conversion.
     27       static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
     28       return *isolate->factory()->LookupSingleCharacterStringFromCode(
     29           kCharTable[value]);
     30     }
     31   }
     32 
     33   // Slow case.
     34   CONVERT_DOUBLE_ARG_CHECKED(value, 0);
     35   if (std::isnan(value)) {
     36     return isolate->heap()->nan_string();
     37   }
     38   if (std::isinf(value)) {
     39     if (value < 0) {
     40       return isolate->heap()->minus_infinity_string();
     41     }
     42     return isolate->heap()->infinity_string();
     43   }
     44   char* str = DoubleToRadixCString(value, radix);
     45   Handle<String> result = isolate->factory()->NewStringFromAsciiChecked(str);
     46   DeleteArray(str);
     47   return *result;
     48 }
     49 
     50 
     51 RUNTIME_FUNCTION(Runtime_NumberToFixed) {
     52   HandleScope scope(isolate);
     53   DCHECK(args.length() == 2);
     54 
     55   CONVERT_DOUBLE_ARG_CHECKED(value, 0);
     56   CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
     57   int f = FastD2IChecked(f_number);
     58   // See DoubleToFixedCString for these constants:
     59   RUNTIME_ASSERT(f >= 0 && f <= 20);
     60   RUNTIME_ASSERT(!Double(value).IsSpecial());
     61   char* str = DoubleToFixedCString(value, f);
     62   Handle<String> result = isolate->factory()->NewStringFromAsciiChecked(str);
     63   DeleteArray(str);
     64   return *result;
     65 }
     66 
     67 
     68 RUNTIME_FUNCTION(Runtime_NumberToExponential) {
     69   HandleScope scope(isolate);
     70   DCHECK(args.length() == 2);
     71 
     72   CONVERT_DOUBLE_ARG_CHECKED(value, 0);
     73   CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
     74   int f = FastD2IChecked(f_number);
     75   RUNTIME_ASSERT(f >= -1 && f <= 20);
     76   RUNTIME_ASSERT(!Double(value).IsSpecial());
     77   char* str = DoubleToExponentialCString(value, f);
     78   Handle<String> result = isolate->factory()->NewStringFromAsciiChecked(str);
     79   DeleteArray(str);
     80   return *result;
     81 }
     82 
     83 
     84 RUNTIME_FUNCTION(Runtime_NumberToPrecision) {
     85   HandleScope scope(isolate);
     86   DCHECK(args.length() == 2);
     87 
     88   CONVERT_DOUBLE_ARG_CHECKED(value, 0);
     89   CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
     90   int f = FastD2IChecked(f_number);
     91   RUNTIME_ASSERT(f >= 1 && f <= 21);
     92   RUNTIME_ASSERT(!Double(value).IsSpecial());
     93   char* str = DoubleToPrecisionCString(value, f);
     94   Handle<String> result = isolate->factory()->NewStringFromAsciiChecked(str);
     95   DeleteArray(str);
     96   return *result;
     97 }
     98 
     99 
    100 RUNTIME_FUNCTION(Runtime_IsValidSmi) {
    101   SealHandleScope shs(isolate);
    102   DCHECK(args.length() == 1);
    103 
    104   CONVERT_NUMBER_CHECKED(int32_t, number, Int32, args[0]);
    105   return isolate->heap()->ToBoolean(Smi::IsValid(number));
    106 }
    107 
    108 
    109 RUNTIME_FUNCTION(Runtime_StringToNumber) {
    110   HandleScope handle_scope(isolate);
    111   DCHECK_EQ(1, args.length());
    112   CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
    113   return *String::ToNumber(subject);
    114 }
    115 
    116 
    117 // ES6 18.2.5 parseInt(string, radix) slow path
    118 RUNTIME_FUNCTION(Runtime_StringParseInt) {
    119   HandleScope handle_scope(isolate);
    120   DCHECK(args.length() == 2);
    121   CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
    122   CONVERT_NUMBER_CHECKED(int, radix, Int32, args[1]);
    123   // Step 8.a. is already handled in the JS function.
    124   RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
    125 
    126   subject = String::Flatten(subject);
    127   double value;
    128 
    129   {
    130     DisallowHeapAllocation no_gc;
    131     String::FlatContent flat = subject->GetFlatContent();
    132 
    133     if (flat.IsOneByte()) {
    134       value =
    135           StringToInt(isolate->unicode_cache(), flat.ToOneByteVector(), radix);
    136     } else {
    137       value = StringToInt(isolate->unicode_cache(), flat.ToUC16Vector(), radix);
    138     }
    139   }
    140 
    141   return *isolate->factory()->NewNumber(value);
    142 }
    143 
    144 
    145 // ES6 18.2.4 parseFloat(string)
    146 RUNTIME_FUNCTION(Runtime_StringParseFloat) {
    147   HandleScope shs(isolate);
    148   DCHECK(args.length() == 1);
    149   CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
    150 
    151   double value =
    152       StringToDouble(isolate->unicode_cache(), subject, ALLOW_TRAILING_JUNK,
    153                      std::numeric_limits<double>::quiet_NaN());
    154 
    155   return *isolate->factory()->NewNumber(value);
    156 }
    157 
    158 
    159 RUNTIME_FUNCTION(Runtime_NumberToString) {
    160   HandleScope scope(isolate);
    161   DCHECK(args.length() == 1);
    162   CONVERT_NUMBER_ARG_HANDLE_CHECKED(number, 0);
    163 
    164   return *isolate->factory()->NumberToString(number);
    165 }
    166 
    167 
    168 RUNTIME_FUNCTION(Runtime_NumberToStringSkipCache) {
    169   HandleScope scope(isolate);
    170   DCHECK(args.length() == 1);
    171   CONVERT_NUMBER_ARG_HANDLE_CHECKED(number, 0);
    172 
    173   return *isolate->factory()->NumberToString(number, false);
    174 }
    175 
    176 
    177 // TODO(bmeurer): Kill this runtime entry. Uses in date.js are wrong anyway.
    178 RUNTIME_FUNCTION(Runtime_NumberToIntegerMapMinusZero) {
    179   HandleScope scope(isolate);
    180   DCHECK(args.length() == 1);
    181   CONVERT_ARG_HANDLE_CHECKED(Object, input, 0);
    182   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, input, Object::ToNumber(input));
    183   double double_value = DoubleToInteger(input->Number());
    184   // Map both -0 and +0 to +0.
    185   if (double_value == 0) double_value = 0;
    186 
    187   return *isolate->factory()->NewNumber(double_value);
    188 }
    189 
    190 
    191 // Converts a Number to a Smi, if possible. Returns NaN if the number is not
    192 // a small integer.
    193 RUNTIME_FUNCTION(Runtime_NumberToSmi) {
    194   SealHandleScope shs(isolate);
    195   DCHECK(args.length() == 1);
    196   CONVERT_ARG_CHECKED(Object, obj, 0);
    197   if (obj->IsSmi()) {
    198     return obj;
    199   }
    200   if (obj->IsHeapNumber()) {
    201     double value = HeapNumber::cast(obj)->value();
    202     int int_value = FastD2I(value);
    203     if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
    204       return Smi::FromInt(int_value);
    205     }
    206   }
    207   return isolate->heap()->nan_value();
    208 }
    209 
    210 
    211 RUNTIME_FUNCTION(Runtime_NumberImul) {
    212   HandleScope scope(isolate);
    213   DCHECK(args.length() == 2);
    214 
    215   // We rely on implementation-defined behavior below, but at least not on
    216   // undefined behavior.
    217   CONVERT_NUMBER_CHECKED(uint32_t, x, Int32, args[0]);
    218   CONVERT_NUMBER_CHECKED(uint32_t, y, Int32, args[1]);
    219   int32_t product = static_cast<int32_t>(x * y);
    220   return *isolate->factory()->NewNumberFromInt(product);
    221 }
    222 
    223 
    224 // Compare two Smis as if they were converted to strings and then
    225 // compared lexicographically.
    226 RUNTIME_FUNCTION(Runtime_SmiLexicographicCompare) {
    227   SealHandleScope shs(isolate);
    228   DCHECK(args.length() == 2);
    229   CONVERT_SMI_ARG_CHECKED(x_value, 0);
    230   CONVERT_SMI_ARG_CHECKED(y_value, 1);
    231 
    232   // If the integers are equal so are the string representations.
    233   if (x_value == y_value) return Smi::FromInt(EQUAL);
    234 
    235   // If one of the integers is zero the normal integer order is the
    236   // same as the lexicographic order of the string representations.
    237   if (x_value == 0 || y_value == 0)
    238     return Smi::FromInt(x_value < y_value ? LESS : GREATER);
    239 
    240   // If only one of the integers is negative the negative number is
    241   // smallest because the char code of '-' is less than the char code
    242   // of any digit.  Otherwise, we make both values positive.
    243 
    244   // Use unsigned values otherwise the logic is incorrect for -MIN_INT on
    245   // architectures using 32-bit Smis.
    246   uint32_t x_scaled = x_value;
    247   uint32_t y_scaled = y_value;
    248   if (x_value < 0 || y_value < 0) {
    249     if (y_value >= 0) return Smi::FromInt(LESS);
    250     if (x_value >= 0) return Smi::FromInt(GREATER);
    251     x_scaled = -x_value;
    252     y_scaled = -y_value;
    253   }
    254 
    255   static const uint32_t kPowersOf10[] = {
    256       1,                 10,                100,         1000,
    257       10 * 1000,         100 * 1000,        1000 * 1000, 10 * 1000 * 1000,
    258       100 * 1000 * 1000, 1000 * 1000 * 1000};
    259 
    260   // If the integers have the same number of decimal digits they can be
    261   // compared directly as the numeric order is the same as the
    262   // lexicographic order.  If one integer has fewer digits, it is scaled
    263   // by some power of 10 to have the same number of digits as the longer
    264   // integer.  If the scaled integers are equal it means the shorter
    265   // integer comes first in the lexicographic order.
    266 
    267   // From http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
    268   int x_log2 = 31 - base::bits::CountLeadingZeros32(x_scaled);
    269   int x_log10 = ((x_log2 + 1) * 1233) >> 12;
    270   x_log10 -= x_scaled < kPowersOf10[x_log10];
    271 
    272   int y_log2 = 31 - base::bits::CountLeadingZeros32(y_scaled);
    273   int y_log10 = ((y_log2 + 1) * 1233) >> 12;
    274   y_log10 -= y_scaled < kPowersOf10[y_log10];
    275 
    276   int tie = EQUAL;
    277 
    278   if (x_log10 < y_log10) {
    279     // X has fewer digits.  We would like to simply scale up X but that
    280     // might overflow, e.g when comparing 9 with 1_000_000_000, 9 would
    281     // be scaled up to 9_000_000_000. So we scale up by the next
    282     // smallest power and scale down Y to drop one digit. It is OK to
    283     // drop one digit from the longer integer since the final digit is
    284     // past the length of the shorter integer.
    285     x_scaled *= kPowersOf10[y_log10 - x_log10 - 1];
    286     y_scaled /= 10;
    287     tie = LESS;
    288   } else if (y_log10 < x_log10) {
    289     y_scaled *= kPowersOf10[x_log10 - y_log10 - 1];
    290     x_scaled /= 10;
    291     tie = GREATER;
    292   }
    293 
    294   if (x_scaled < y_scaled) return Smi::FromInt(LESS);
    295   if (x_scaled > y_scaled) return Smi::FromInt(GREATER);
    296   return Smi::FromInt(tie);
    297 }
    298 
    299 
    300 RUNTIME_FUNCTION(Runtime_MaxSmi) {
    301   SealHandleScope shs(isolate);
    302   DCHECK(args.length() == 0);
    303   return Smi::FromInt(Smi::kMaxValue);
    304 }
    305 
    306 
    307 RUNTIME_FUNCTION(Runtime_IsSmi) {
    308   SealHandleScope shs(isolate);
    309   DCHECK(args.length() == 1);
    310   CONVERT_ARG_CHECKED(Object, obj, 0);
    311   return isolate->heap()->ToBoolean(obj->IsSmi());
    312 }
    313 
    314 
    315 RUNTIME_FUNCTION(Runtime_GetRootNaN) {
    316   SealHandleScope shs(isolate);
    317   DCHECK(args.length() == 0);
    318   return isolate->heap()->nan_value();
    319 }
    320 
    321 
    322 RUNTIME_FUNCTION(Runtime_GetHoleNaNUpper) {
    323   HandleScope scope(isolate);
    324   DCHECK(args.length() == 0);
    325   return *isolate->factory()->NewNumberFromUint(kHoleNanUpper32);
    326 }
    327 
    328 
    329 RUNTIME_FUNCTION(Runtime_GetHoleNaNLower) {
    330   HandleScope scope(isolate);
    331   DCHECK(args.length() == 0);
    332   return *isolate->factory()->NewNumberFromUint(kHoleNanLower32);
    333 }
    334 
    335 
    336 }  // namespace internal
    337 }  // namespace v8
    338