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 
RUNTIME_FUNCTION(Runtime_IsValidSmi)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 
RUNTIME_FUNCTION(Runtime_StringToNumber)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
RUNTIME_FUNCTION(Runtime_StringParseInt)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)
RUNTIME_FUNCTION(Runtime_StringParseFloat)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 
RUNTIME_FUNCTION(Runtime_NumberToString)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
RUNTIME_FUNCTION(Runtime_SmiLexicographicCompare)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 
RUNTIME_FUNCTION(Runtime_MaxSmi)159 RUNTIME_FUNCTION(Runtime_MaxSmi) {
160   SealHandleScope shs(isolate);
161   DCHECK_EQ(0, args.length());
162   return Smi::FromInt(Smi::kMaxValue);
163 }
164 
165 
RUNTIME_FUNCTION(Runtime_IsSmi)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 
RUNTIME_FUNCTION(Runtime_GetHoleNaNUpper)174 RUNTIME_FUNCTION(Runtime_GetHoleNaNUpper) {
175   HandleScope scope(isolate);
176   DCHECK_EQ(0, args.length());
177   return *isolate->factory()->NewNumberFromUint(kHoleNanUpper32);
178 }
179 
180 
RUNTIME_FUNCTION(Runtime_GetHoleNaNLower)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