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