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