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