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