blob: edd83bc5e80adb19b31ec41ff1dbe1a738658e54 [file] [log] [blame]
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001// 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
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005#include "src/runtime/runtime-utils.h"
Emily Bernierd0a1eb72015-03-24 16:35:39 -04006
7#include "src/arguments.h"
8#include "src/base/bits.h"
9#include "src/bootstrapper.h"
10#include "src/codegen.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000011#include "src/isolate-inl.h"
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012
13namespace v8 {
14namespace internal {
15
16RUNTIME_FUNCTION(Runtime_NumberToRadixString) {
17 HandleScope scope(isolate);
18 DCHECK(args.length() == 2);
19 CONVERT_SMI_ARG_CHECKED(radix, 1);
Ben Murdoch61f157c2016-09-16 13:49:30 +010020 CHECK(2 <= radix && radix <= 36);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040021
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
51RUNTIME_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:
Ben Murdoch61f157c2016-09-16 13:49:30 +010059 CHECK(f >= 0 && f <= 20);
60 CHECK(!Double(value).IsSpecial());
Emily Bernierd0a1eb72015-03-24 16:35:39 -040061 char* str = DoubleToFixedCString(value, f);
62 Handle<String> result = isolate->factory()->NewStringFromAsciiChecked(str);
63 DeleteArray(str);
64 return *result;
65}
66
67
68RUNTIME_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);
Ben Murdoch61f157c2016-09-16 13:49:30 +010075 CHECK(f >= -1 && f <= 20);
76 CHECK(!Double(value).IsSpecial());
Emily Bernierd0a1eb72015-03-24 16:35:39 -040077 char* str = DoubleToExponentialCString(value, f);
78 Handle<String> result = isolate->factory()->NewStringFromAsciiChecked(str);
79 DeleteArray(str);
80 return *result;
81}
82
83
84RUNTIME_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);
Ben Murdoch61f157c2016-09-16 13:49:30 +010091 CHECK(f >= 1 && f <= 21);
92 CHECK(!Double(value).IsSpecial());
Emily Bernierd0a1eb72015-03-24 16:35:39 -040093 char* str = DoubleToPrecisionCString(value, f);
94 Handle<String> result = isolate->factory()->NewStringFromAsciiChecked(str);
95 DeleteArray(str);
96 return *result;
97}
98
99
100RUNTIME_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
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400109RUNTIME_FUNCTION(Runtime_StringToNumber) {
110 HandleScope handle_scope(isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000111 DCHECK_EQ(1, args.length());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400112 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000113 return *String::ToNumber(subject);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400114}
115
116
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000117// ES6 18.2.5 parseInt(string, radix) slow path
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400118RUNTIME_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]);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000123 // Step 8.a. is already handled in the JS function.
Ben Murdoch61f157c2016-09-16 13:49:30 +0100124 CHECK(radix == 0 || (2 <= radix && radix <= 36));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400125
126 subject = String::Flatten(subject);
127 double value;
128
129 {
130 DisallowHeapAllocation no_gc;
131 String::FlatContent flat = subject->GetFlatContent();
132
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400133 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
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000145// ES6 18.2.4 parseFloat(string)
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400146RUNTIME_FUNCTION(Runtime_StringParseFloat) {
147 HandleScope shs(isolate);
148 DCHECK(args.length() == 1);
149 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
150
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000151 double value =
152 StringToDouble(isolate->unicode_cache(), subject, ALLOW_TRAILING_JUNK,
153 std::numeric_limits<double>::quiet_NaN());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400154
155 return *isolate->factory()->NewNumber(value);
156}
157
158
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000159RUNTIME_FUNCTION(Runtime_NumberToString) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400160 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
168RUNTIME_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
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400177// Converts a Number to a Smi, if possible. Returns NaN if the number is not
178// a small integer.
179RUNTIME_FUNCTION(Runtime_NumberToSmi) {
180 SealHandleScope shs(isolate);
181 DCHECK(args.length() == 1);
182 CONVERT_ARG_CHECKED(Object, obj, 0);
183 if (obj->IsSmi()) {
184 return obj;
185 }
186 if (obj->IsHeapNumber()) {
187 double value = HeapNumber::cast(obj)->value();
188 int int_value = FastD2I(value);
189 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
190 return Smi::FromInt(int_value);
191 }
192 }
193 return isolate->heap()->nan_value();
194}
195
196
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400197// Compare two Smis as if they were converted to strings and then
198// compared lexicographically.
199RUNTIME_FUNCTION(Runtime_SmiLexicographicCompare) {
200 SealHandleScope shs(isolate);
201 DCHECK(args.length() == 2);
202 CONVERT_SMI_ARG_CHECKED(x_value, 0);
203 CONVERT_SMI_ARG_CHECKED(y_value, 1);
204
205 // If the integers are equal so are the string representations.
206 if (x_value == y_value) return Smi::FromInt(EQUAL);
207
208 // If one of the integers is zero the normal integer order is the
209 // same as the lexicographic order of the string representations.
210 if (x_value == 0 || y_value == 0)
211 return Smi::FromInt(x_value < y_value ? LESS : GREATER);
212
213 // If only one of the integers is negative the negative number is
214 // smallest because the char code of '-' is less than the char code
215 // of any digit. Otherwise, we make both values positive.
216
217 // Use unsigned values otherwise the logic is incorrect for -MIN_INT on
218 // architectures using 32-bit Smis.
219 uint32_t x_scaled = x_value;
220 uint32_t y_scaled = y_value;
221 if (x_value < 0 || y_value < 0) {
222 if (y_value >= 0) return Smi::FromInt(LESS);
223 if (x_value >= 0) return Smi::FromInt(GREATER);
224 x_scaled = -x_value;
225 y_scaled = -y_value;
226 }
227
228 static const uint32_t kPowersOf10[] = {
229 1, 10, 100, 1000,
230 10 * 1000, 100 * 1000, 1000 * 1000, 10 * 1000 * 1000,
231 100 * 1000 * 1000, 1000 * 1000 * 1000};
232
233 // If the integers have the same number of decimal digits they can be
234 // compared directly as the numeric order is the same as the
235 // lexicographic order. If one integer has fewer digits, it is scaled
236 // by some power of 10 to have the same number of digits as the longer
237 // integer. If the scaled integers are equal it means the shorter
238 // integer comes first in the lexicographic order.
239
240 // From http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
241 int x_log2 = 31 - base::bits::CountLeadingZeros32(x_scaled);
242 int x_log10 = ((x_log2 + 1) * 1233) >> 12;
243 x_log10 -= x_scaled < kPowersOf10[x_log10];
244
245 int y_log2 = 31 - base::bits::CountLeadingZeros32(y_scaled);
246 int y_log10 = ((y_log2 + 1) * 1233) >> 12;
247 y_log10 -= y_scaled < kPowersOf10[y_log10];
248
249 int tie = EQUAL;
250
251 if (x_log10 < y_log10) {
252 // X has fewer digits. We would like to simply scale up X but that
253 // might overflow, e.g when comparing 9 with 1_000_000_000, 9 would
254 // be scaled up to 9_000_000_000. So we scale up by the next
255 // smallest power and scale down Y to drop one digit. It is OK to
256 // drop one digit from the longer integer since the final digit is
257 // past the length of the shorter integer.
258 x_scaled *= kPowersOf10[y_log10 - x_log10 - 1];
259 y_scaled /= 10;
260 tie = LESS;
261 } else if (y_log10 < x_log10) {
262 y_scaled *= kPowersOf10[x_log10 - y_log10 - 1];
263 x_scaled /= 10;
264 tie = GREATER;
265 }
266
267 if (x_scaled < y_scaled) return Smi::FromInt(LESS);
268 if (x_scaled > y_scaled) return Smi::FromInt(GREATER);
269 return Smi::FromInt(tie);
270}
271
272
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400273RUNTIME_FUNCTION(Runtime_MaxSmi) {
274 SealHandleScope shs(isolate);
275 DCHECK(args.length() == 0);
276 return Smi::FromInt(Smi::kMaxValue);
277}
278
279
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000280RUNTIME_FUNCTION(Runtime_IsSmi) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400281 SealHandleScope shs(isolate);
282 DCHECK(args.length() == 1);
283 CONVERT_ARG_CHECKED(Object, obj, 0);
284 return isolate->heap()->ToBoolean(obj->IsSmi());
285}
286
287
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000288RUNTIME_FUNCTION(Runtime_GetRootNaN) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400289 SealHandleScope shs(isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000290 DCHECK(args.length() == 0);
291 return isolate->heap()->nan_value();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400292}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000293
294
295RUNTIME_FUNCTION(Runtime_GetHoleNaNUpper) {
296 HandleScope scope(isolate);
297 DCHECK(args.length() == 0);
298 return *isolate->factory()->NewNumberFromUint(kHoleNanUpper32);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400299}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000300
301
302RUNTIME_FUNCTION(Runtime_GetHoleNaNLower) {
303 HandleScope scope(isolate);
304 DCHECK(args.length() == 0);
305 return *isolate->factory()->NewNumberFromUint(kHoleNanLower32);
306}
307
308
309} // namespace internal
310} // namespace v8