• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_NumberToRadixString)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 
RUNTIME_FUNCTION(Runtime_NumberToFixed)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 
RUNTIME_FUNCTION(Runtime_NumberToExponential)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 
RUNTIME_FUNCTION(Runtime_NumberToPrecision)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 
RUNTIME_FUNCTION(Runtime_IsValidSmi)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 
RUNTIME_FUNCTION(Runtime_StringToNumber)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
RUNTIME_FUNCTION(Runtime_StringParseInt)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)
RUNTIME_FUNCTION(Runtime_StringParseFloat)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 
RUNTIME_FUNCTION(Runtime_NumberToString)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 
RUNTIME_FUNCTION(Runtime_NumberToStringSkipCache)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.
RUNTIME_FUNCTION(Runtime_NumberToIntegerMapMinusZero)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.
RUNTIME_FUNCTION(Runtime_NumberToSmi)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 
RUNTIME_FUNCTION(Runtime_NumberImul)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.
RUNTIME_FUNCTION(Runtime_SmiLexicographicCompare)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 
RUNTIME_FUNCTION(Runtime_MaxSmi)300 RUNTIME_FUNCTION(Runtime_MaxSmi) {
301   SealHandleScope shs(isolate);
302   DCHECK(args.length() == 0);
303   return Smi::FromInt(Smi::kMaxValue);
304 }
305 
306 
RUNTIME_FUNCTION(Runtime_IsSmi)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 
RUNTIME_FUNCTION(Runtime_GetRootNaN)315 RUNTIME_FUNCTION(Runtime_GetRootNaN) {
316   SealHandleScope shs(isolate);
317   DCHECK(args.length() == 0);
318   return isolate->heap()->nan_value();
319 }
320 
321 
RUNTIME_FUNCTION(Runtime_GetHoleNaNUpper)322 RUNTIME_FUNCTION(Runtime_GetHoleNaNUpper) {
323   HandleScope scope(isolate);
324   DCHECK(args.length() == 0);
325   return *isolate->factory()->NewNumberFromUint(kHoleNanUpper32);
326 }
327 
328 
RUNTIME_FUNCTION(Runtime_GetHoleNaNLower)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