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