blob: bc0bb3656dccc9c61cd5cc8cfe81e262d3fc7d58 [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
5#include "src/v8.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/runtime/runtime-utils.h"
12
13
14#ifndef _STLP_VENDOR_CSTD
15// STLPort doesn't import fpclassify and isless into the std namespace.
16using std::fpclassify;
17using std::isless;
18#endif
19
20namespace v8 {
21namespace internal {
22
23RUNTIME_FUNCTION(Runtime_NumberToRadixString) {
24 HandleScope scope(isolate);
25 DCHECK(args.length() == 2);
26 CONVERT_SMI_ARG_CHECKED(radix, 1);
27 RUNTIME_ASSERT(2 <= radix && radix <= 36);
28
29 // Fast case where the result is a one character string.
30 if (args[0]->IsSmi()) {
31 int value = args.smi_at(0);
32 if (value >= 0 && value < radix) {
33 // Character array used for conversion.
34 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
35 return *isolate->factory()->LookupSingleCharacterStringFromCode(
36 kCharTable[value]);
37 }
38 }
39
40 // Slow case.
41 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
42 if (std::isnan(value)) {
43 return isolate->heap()->nan_string();
44 }
45 if (std::isinf(value)) {
46 if (value < 0) {
47 return isolate->heap()->minus_infinity_string();
48 }
49 return isolate->heap()->infinity_string();
50 }
51 char* str = DoubleToRadixCString(value, radix);
52 Handle<String> result = isolate->factory()->NewStringFromAsciiChecked(str);
53 DeleteArray(str);
54 return *result;
55}
56
57
58RUNTIME_FUNCTION(Runtime_NumberToFixed) {
59 HandleScope scope(isolate);
60 DCHECK(args.length() == 2);
61
62 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
63 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
64 int f = FastD2IChecked(f_number);
65 // See DoubleToFixedCString for these constants:
66 RUNTIME_ASSERT(f >= 0 && f <= 20);
67 RUNTIME_ASSERT(!Double(value).IsSpecial());
68 char* str = DoubleToFixedCString(value, f);
69 Handle<String> result = isolate->factory()->NewStringFromAsciiChecked(str);
70 DeleteArray(str);
71 return *result;
72}
73
74
75RUNTIME_FUNCTION(Runtime_NumberToExponential) {
76 HandleScope scope(isolate);
77 DCHECK(args.length() == 2);
78
79 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
80 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
81 int f = FastD2IChecked(f_number);
82 RUNTIME_ASSERT(f >= -1 && f <= 20);
83 RUNTIME_ASSERT(!Double(value).IsSpecial());
84 char* str = DoubleToExponentialCString(value, f);
85 Handle<String> result = isolate->factory()->NewStringFromAsciiChecked(str);
86 DeleteArray(str);
87 return *result;
88}
89
90
91RUNTIME_FUNCTION(Runtime_NumberToPrecision) {
92 HandleScope scope(isolate);
93 DCHECK(args.length() == 2);
94
95 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
96 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
97 int f = FastD2IChecked(f_number);
98 RUNTIME_ASSERT(f >= 1 && f <= 21);
99 RUNTIME_ASSERT(!Double(value).IsSpecial());
100 char* str = DoubleToPrecisionCString(value, f);
101 Handle<String> result = isolate->factory()->NewStringFromAsciiChecked(str);
102 DeleteArray(str);
103 return *result;
104}
105
106
107RUNTIME_FUNCTION(Runtime_IsValidSmi) {
108 SealHandleScope shs(isolate);
109 DCHECK(args.length() == 1);
110
111 CONVERT_NUMBER_CHECKED(int32_t, number, Int32, args[0]);
112 return isolate->heap()->ToBoolean(Smi::IsValid(number));
113}
114
115
116static bool AreDigits(const uint8_t* s, int from, int to) {
117 for (int i = from; i < to; i++) {
118 if (s[i] < '0' || s[i] > '9') return false;
119 }
120
121 return true;
122}
123
124
125static int ParseDecimalInteger(const uint8_t* s, int from, int to) {
126 DCHECK(to - from < 10); // Overflow is not possible.
127 DCHECK(from < to);
128 int d = s[from] - '0';
129
130 for (int i = from + 1; i < to; i++) {
131 d = 10 * d + (s[i] - '0');
132 }
133
134 return d;
135}
136
137
138RUNTIME_FUNCTION(Runtime_StringToNumber) {
139 HandleScope handle_scope(isolate);
140 DCHECK(args.length() == 1);
141 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
142 subject = String::Flatten(subject);
143
144 // Fast case: short integer or some sorts of junk values.
145 if (subject->IsSeqOneByteString()) {
146 int len = subject->length();
147 if (len == 0) return Smi::FromInt(0);
148
149 DisallowHeapAllocation no_gc;
150 uint8_t const* data = Handle<SeqOneByteString>::cast(subject)->GetChars();
151 bool minus = (data[0] == '-');
152 int start_pos = (minus ? 1 : 0);
153
154 if (start_pos == len) {
155 return isolate->heap()->nan_value();
156 } else if (data[start_pos] > '9') {
157 // Fast check for a junk value. A valid string may start from a
158 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit
159 // or the 'I' character ('Infinity'). All of that have codes not greater
160 // than '9' except 'I' and &nbsp;.
161 if (data[start_pos] != 'I' && data[start_pos] != 0xa0) {
162 return isolate->heap()->nan_value();
163 }
164 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
165 // The maximal/minimal smi has 10 digits. If the string has less digits
166 // we know it will fit into the smi-data type.
167 int d = ParseDecimalInteger(data, start_pos, len);
168 if (minus) {
169 if (d == 0) return isolate->heap()->minus_zero_value();
170 d = -d;
171 } else if (!subject->HasHashCode() && len <= String::kMaxArrayIndexSize &&
172 (len == 1 || data[0] != '0')) {
173 // String hash is not calculated yet but all the data are present.
174 // Update the hash field to speed up sequential convertions.
175 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
176#ifdef DEBUG
177 subject->Hash(); // Force hash calculation.
178 DCHECK_EQ(static_cast<int>(subject->hash_field()),
179 static_cast<int>(hash));
180#endif
181 subject->set_hash_field(hash);
182 }
183 return Smi::FromInt(d);
184 }
185 }
186
187 // Slower case.
188 int flags = ALLOW_HEX;
189 if (FLAG_harmony_numeric_literals) {
190 // The current spec draft has not updated "ToNumber Applied to the String
191 // Type", https://bugs.ecmascript.org/show_bug.cgi?id=1584
192 flags |= ALLOW_OCTAL | ALLOW_BINARY;
193 }
194
195 return *isolate->factory()->NewNumber(
196 StringToDouble(isolate->unicode_cache(), subject, flags));
197}
198
199
200RUNTIME_FUNCTION(Runtime_StringParseInt) {
201 HandleScope handle_scope(isolate);
202 DCHECK(args.length() == 2);
203 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
204 CONVERT_NUMBER_CHECKED(int, radix, Int32, args[1]);
205 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
206
207 subject = String::Flatten(subject);
208 double value;
209
210 {
211 DisallowHeapAllocation no_gc;
212 String::FlatContent flat = subject->GetFlatContent();
213
214 // ECMA-262 section 15.1.2.3, empty string is NaN
215 if (flat.IsOneByte()) {
216 value =
217 StringToInt(isolate->unicode_cache(), flat.ToOneByteVector(), radix);
218 } else {
219 value = StringToInt(isolate->unicode_cache(), flat.ToUC16Vector(), radix);
220 }
221 }
222
223 return *isolate->factory()->NewNumber(value);
224}
225
226
227RUNTIME_FUNCTION(Runtime_StringParseFloat) {
228 HandleScope shs(isolate);
229 DCHECK(args.length() == 1);
230 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
231
232 double value = StringToDouble(isolate->unicode_cache(), subject,
233 ALLOW_TRAILING_JUNK, base::OS::nan_value());
234
235 return *isolate->factory()->NewNumber(value);
236}
237
238
239RUNTIME_FUNCTION(Runtime_NumberToStringRT) {
240 HandleScope scope(isolate);
241 DCHECK(args.length() == 1);
242 CONVERT_NUMBER_ARG_HANDLE_CHECKED(number, 0);
243
244 return *isolate->factory()->NumberToString(number);
245}
246
247
248RUNTIME_FUNCTION(Runtime_NumberToStringSkipCache) {
249 HandleScope scope(isolate);
250 DCHECK(args.length() == 1);
251 CONVERT_NUMBER_ARG_HANDLE_CHECKED(number, 0);
252
253 return *isolate->factory()->NumberToString(number, false);
254}
255
256
257RUNTIME_FUNCTION(Runtime_NumberToInteger) {
258 HandleScope scope(isolate);
259 DCHECK(args.length() == 1);
260
261 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
262 return *isolate->factory()->NewNumber(DoubleToInteger(number));
263}
264
265
266RUNTIME_FUNCTION(Runtime_NumberToIntegerMapMinusZero) {
267 HandleScope scope(isolate);
268 DCHECK(args.length() == 1);
269
270 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
271 double double_value = DoubleToInteger(number);
272 // Map both -0 and +0 to +0.
273 if (double_value == 0) double_value = 0;
274
275 return *isolate->factory()->NewNumber(double_value);
276}
277
278
279RUNTIME_FUNCTION(Runtime_NumberToJSUint32) {
280 HandleScope scope(isolate);
281 DCHECK(args.length() == 1);
282
283 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
284 return *isolate->factory()->NewNumberFromUint(number);
285}
286
287
288RUNTIME_FUNCTION(Runtime_NumberToJSInt32) {
289 HandleScope scope(isolate);
290 DCHECK(args.length() == 1);
291
292 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
293 return *isolate->factory()->NewNumberFromInt(DoubleToInt32(number));
294}
295
296
297// Converts a Number to a Smi, if possible. Returns NaN if the number is not
298// a small integer.
299RUNTIME_FUNCTION(Runtime_NumberToSmi) {
300 SealHandleScope shs(isolate);
301 DCHECK(args.length() == 1);
302 CONVERT_ARG_CHECKED(Object, obj, 0);
303 if (obj->IsSmi()) {
304 return obj;
305 }
306 if (obj->IsHeapNumber()) {
307 double value = HeapNumber::cast(obj)->value();
308 int int_value = FastD2I(value);
309 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
310 return Smi::FromInt(int_value);
311 }
312 }
313 return isolate->heap()->nan_value();
314}
315
316
317RUNTIME_FUNCTION(Runtime_NumberAdd) {
318 HandleScope scope(isolate);
319 DCHECK(args.length() == 2);
320
321 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
322 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
323 return *isolate->factory()->NewNumber(x + y);
324}
325
326
327RUNTIME_FUNCTION(Runtime_NumberSub) {
328 HandleScope scope(isolate);
329 DCHECK(args.length() == 2);
330
331 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
332 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
333 return *isolate->factory()->NewNumber(x - y);
334}
335
336
337RUNTIME_FUNCTION(Runtime_NumberMul) {
338 HandleScope scope(isolate);
339 DCHECK(args.length() == 2);
340
341 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
342 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
343 return *isolate->factory()->NewNumber(x * y);
344}
345
346
347RUNTIME_FUNCTION(Runtime_NumberUnaryMinus) {
348 HandleScope scope(isolate);
349 DCHECK(args.length() == 1);
350
351 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
352 return *isolate->factory()->NewNumber(-x);
353}
354
355
356RUNTIME_FUNCTION(Runtime_NumberDiv) {
357 HandleScope scope(isolate);
358 DCHECK(args.length() == 2);
359
360 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
361 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
362 return *isolate->factory()->NewNumber(x / y);
363}
364
365
366RUNTIME_FUNCTION(Runtime_NumberMod) {
367 HandleScope scope(isolate);
368 DCHECK(args.length() == 2);
369
370 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
371 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
372 return *isolate->factory()->NewNumber(modulo(x, y));
373}
374
375
376RUNTIME_FUNCTION(Runtime_NumberImul) {
377 HandleScope scope(isolate);
378 DCHECK(args.length() == 2);
379
380 // We rely on implementation-defined behavior below, but at least not on
381 // undefined behavior.
382 CONVERT_NUMBER_CHECKED(uint32_t, x, Int32, args[0]);
383 CONVERT_NUMBER_CHECKED(uint32_t, y, Int32, args[1]);
384 int32_t product = static_cast<int32_t>(x * y);
385 return *isolate->factory()->NewNumberFromInt(product);
386}
387
388
389RUNTIME_FUNCTION(Runtime_NumberOr) {
390 HandleScope scope(isolate);
391 DCHECK(args.length() == 2);
392
393 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
394 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
395 return *isolate->factory()->NewNumberFromInt(x | y);
396}
397
398
399RUNTIME_FUNCTION(Runtime_NumberAnd) {
400 HandleScope scope(isolate);
401 DCHECK(args.length() == 2);
402
403 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
404 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
405 return *isolate->factory()->NewNumberFromInt(x & y);
406}
407
408
409RUNTIME_FUNCTION(Runtime_NumberXor) {
410 HandleScope scope(isolate);
411 DCHECK(args.length() == 2);
412
413 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
414 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
415 return *isolate->factory()->NewNumberFromInt(x ^ y);
416}
417
418
419RUNTIME_FUNCTION(Runtime_NumberShl) {
420 HandleScope scope(isolate);
421 DCHECK(args.length() == 2);
422
423 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
424 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
425 return *isolate->factory()->NewNumberFromInt(x << (y & 0x1f));
426}
427
428
429RUNTIME_FUNCTION(Runtime_NumberShr) {
430 HandleScope scope(isolate);
431 DCHECK(args.length() == 2);
432
433 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
434 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
435 return *isolate->factory()->NewNumberFromUint(x >> (y & 0x1f));
436}
437
438
439RUNTIME_FUNCTION(Runtime_NumberSar) {
440 HandleScope scope(isolate);
441 DCHECK(args.length() == 2);
442
443 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
444 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
445 return *isolate->factory()->NewNumberFromInt(
446 ArithmeticShiftRight(x, y & 0x1f));
447}
448
449
450RUNTIME_FUNCTION(Runtime_NumberEquals) {
451 SealHandleScope shs(isolate);
452 DCHECK(args.length() == 2);
453
454 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
455 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
456 if (std::isnan(x)) return Smi::FromInt(NOT_EQUAL);
457 if (std::isnan(y)) return Smi::FromInt(NOT_EQUAL);
458 if (x == y) return Smi::FromInt(EQUAL);
459 Object* result;
460 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
461 result = Smi::FromInt(EQUAL);
462 } else {
463 result = Smi::FromInt(NOT_EQUAL);
464 }
465 return result;
466}
467
468
469RUNTIME_FUNCTION(Runtime_NumberCompare) {
470 SealHandleScope shs(isolate);
471 DCHECK(args.length() == 3);
472
473 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
474 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
475 CONVERT_ARG_HANDLE_CHECKED(Object, uncomparable_result, 2)
476 if (std::isnan(x) || std::isnan(y)) return *uncomparable_result;
477 if (x == y) return Smi::FromInt(EQUAL);
478 if (isless(x, y)) return Smi::FromInt(LESS);
479 return Smi::FromInt(GREATER);
480}
481
482
483// Compare two Smis as if they were converted to strings and then
484// compared lexicographically.
485RUNTIME_FUNCTION(Runtime_SmiLexicographicCompare) {
486 SealHandleScope shs(isolate);
487 DCHECK(args.length() == 2);
488 CONVERT_SMI_ARG_CHECKED(x_value, 0);
489 CONVERT_SMI_ARG_CHECKED(y_value, 1);
490
491 // If the integers are equal so are the string representations.
492 if (x_value == y_value) return Smi::FromInt(EQUAL);
493
494 // If one of the integers is zero the normal integer order is the
495 // same as the lexicographic order of the string representations.
496 if (x_value == 0 || y_value == 0)
497 return Smi::FromInt(x_value < y_value ? LESS : GREATER);
498
499 // If only one of the integers is negative the negative number is
500 // smallest because the char code of '-' is less than the char code
501 // of any digit. Otherwise, we make both values positive.
502
503 // Use unsigned values otherwise the logic is incorrect for -MIN_INT on
504 // architectures using 32-bit Smis.
505 uint32_t x_scaled = x_value;
506 uint32_t y_scaled = y_value;
507 if (x_value < 0 || y_value < 0) {
508 if (y_value >= 0) return Smi::FromInt(LESS);
509 if (x_value >= 0) return Smi::FromInt(GREATER);
510 x_scaled = -x_value;
511 y_scaled = -y_value;
512 }
513
514 static const uint32_t kPowersOf10[] = {
515 1, 10, 100, 1000,
516 10 * 1000, 100 * 1000, 1000 * 1000, 10 * 1000 * 1000,
517 100 * 1000 * 1000, 1000 * 1000 * 1000};
518
519 // If the integers have the same number of decimal digits they can be
520 // compared directly as the numeric order is the same as the
521 // lexicographic order. If one integer has fewer digits, it is scaled
522 // by some power of 10 to have the same number of digits as the longer
523 // integer. If the scaled integers are equal it means the shorter
524 // integer comes first in the lexicographic order.
525
526 // From http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
527 int x_log2 = 31 - base::bits::CountLeadingZeros32(x_scaled);
528 int x_log10 = ((x_log2 + 1) * 1233) >> 12;
529 x_log10 -= x_scaled < kPowersOf10[x_log10];
530
531 int y_log2 = 31 - base::bits::CountLeadingZeros32(y_scaled);
532 int y_log10 = ((y_log2 + 1) * 1233) >> 12;
533 y_log10 -= y_scaled < kPowersOf10[y_log10];
534
535 int tie = EQUAL;
536
537 if (x_log10 < y_log10) {
538 // X has fewer digits. We would like to simply scale up X but that
539 // might overflow, e.g when comparing 9 with 1_000_000_000, 9 would
540 // be scaled up to 9_000_000_000. So we scale up by the next
541 // smallest power and scale down Y to drop one digit. It is OK to
542 // drop one digit from the longer integer since the final digit is
543 // past the length of the shorter integer.
544 x_scaled *= kPowersOf10[y_log10 - x_log10 - 1];
545 y_scaled /= 10;
546 tie = LESS;
547 } else if (y_log10 < x_log10) {
548 y_scaled *= kPowersOf10[x_log10 - y_log10 - 1];
549 x_scaled /= 10;
550 tie = GREATER;
551 }
552
553 if (x_scaled < y_scaled) return Smi::FromInt(LESS);
554 if (x_scaled > y_scaled) return Smi::FromInt(GREATER);
555 return Smi::FromInt(tie);
556}
557
558
559RUNTIME_FUNCTION(Runtime_GetRootNaN) {
560 SealHandleScope shs(isolate);
561 DCHECK(args.length() == 0);
562 RUNTIME_ASSERT(isolate->bootstrapper()->IsActive());
563 return isolate->heap()->nan_value();
564}
565
566
567RUNTIME_FUNCTION(Runtime_MaxSmi) {
568 SealHandleScope shs(isolate);
569 DCHECK(args.length() == 0);
570 return Smi::FromInt(Smi::kMaxValue);
571}
572
573
574RUNTIME_FUNCTION(RuntimeReference_NumberToString) {
575 SealHandleScope shs(isolate);
576 return __RT_impl_Runtime_NumberToStringRT(args, isolate);
577}
578
579
580RUNTIME_FUNCTION(RuntimeReference_IsSmi) {
581 SealHandleScope shs(isolate);
582 DCHECK(args.length() == 1);
583 CONVERT_ARG_CHECKED(Object, obj, 0);
584 return isolate->heap()->ToBoolean(obj->IsSmi());
585}
586
587
588RUNTIME_FUNCTION(RuntimeReference_IsNonNegativeSmi) {
589 SealHandleScope shs(isolate);
590 DCHECK(args.length() == 1);
591 CONVERT_ARG_CHECKED(Object, obj, 0);
592 return isolate->heap()->ToBoolean(obj->IsSmi() &&
593 Smi::cast(obj)->value() >= 0);
594}
595}
596} // namespace v8::internal