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
RUNTIME_FUNCTION(Runtime_IsValidSmi)16 RUNTIME_FUNCTION(Runtime_IsValidSmi) {
17 SealHandleScope shs(isolate);
18 DCHECK(args.length() == 1);
19
20 CONVERT_NUMBER_CHECKED(int32_t, number, Int32, args[0]);
21 return isolate->heap()->ToBoolean(Smi::IsValid(number));
22 }
23
24
RUNTIME_FUNCTION(Runtime_StringToNumber)25 RUNTIME_FUNCTION(Runtime_StringToNumber) {
26 HandleScope handle_scope(isolate);
27 DCHECK_EQ(1, args.length());
28 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
29 return *String::ToNumber(subject);
30 }
31
32
33 // ES6 18.2.5 parseInt(string, radix) slow path
RUNTIME_FUNCTION(Runtime_StringParseInt)34 RUNTIME_FUNCTION(Runtime_StringParseInt) {
35 HandleScope handle_scope(isolate);
36 DCHECK_EQ(2, args.length());
37 CONVERT_ARG_HANDLE_CHECKED(Object, string, 0);
38 CONVERT_ARG_HANDLE_CHECKED(Object, radix, 1);
39
40 // Convert {string} to a String first, and flatten it.
41 Handle<String> subject;
42 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, subject,
43 Object::ToString(isolate, string));
44 subject = String::Flatten(subject);
45
46 // Convert {radix} to Int32.
47 if (!radix->IsNumber()) {
48 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, radix, Object::ToNumber(radix));
49 }
50 int radix32 = DoubleToInt32(radix->Number());
51 if (radix32 != 0 && (radix32 < 2 || radix32 > 36)) {
52 return isolate->heap()->nan_value();
53 }
54
55 double result;
56 {
57 DisallowHeapAllocation no_gc;
58 String::FlatContent flat = subject->GetFlatContent();
59
60 if (flat.IsOneByte()) {
61 result = StringToInt(isolate->unicode_cache(), flat.ToOneByteVector(),
62 radix32);
63 } else {
64 result =
65 StringToInt(isolate->unicode_cache(), flat.ToUC16Vector(), radix32);
66 }
67 }
68
69 return *isolate->factory()->NewNumber(result);
70 }
71
72
73 // ES6 18.2.4 parseFloat(string)
RUNTIME_FUNCTION(Runtime_StringParseFloat)74 RUNTIME_FUNCTION(Runtime_StringParseFloat) {
75 HandleScope shs(isolate);
76 DCHECK(args.length() == 1);
77 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
78
79 double value =
80 StringToDouble(isolate->unicode_cache(), subject, ALLOW_TRAILING_JUNK,
81 std::numeric_limits<double>::quiet_NaN());
82
83 return *isolate->factory()->NewNumber(value);
84 }
85
86
RUNTIME_FUNCTION(Runtime_NumberToString)87 RUNTIME_FUNCTION(Runtime_NumberToString) {
88 HandleScope scope(isolate);
89 DCHECK(args.length() == 1);
90 CONVERT_NUMBER_ARG_HANDLE_CHECKED(number, 0);
91
92 return *isolate->factory()->NumberToString(number);
93 }
94
95
RUNTIME_FUNCTION(Runtime_NumberToStringSkipCache)96 RUNTIME_FUNCTION(Runtime_NumberToStringSkipCache) {
97 HandleScope scope(isolate);
98 DCHECK(args.length() == 1);
99 CONVERT_NUMBER_ARG_HANDLE_CHECKED(number, 0);
100
101 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.
RUNTIME_FUNCTION(Runtime_NumberToSmi)107 RUNTIME_FUNCTION(Runtime_NumberToSmi) {
108 SealHandleScope shs(isolate);
109 DCHECK(args.length() == 1);
110 CONVERT_ARG_CHECKED(Object, obj, 0);
111 if (obj->IsSmi()) {
112 return obj;
113 }
114 if (obj->IsHeapNumber()) {
115 double value = HeapNumber::cast(obj)->value();
116 int int_value = FastD2I(value);
117 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
118 return Smi::FromInt(int_value);
119 }
120 }
121 return isolate->heap()->nan_value();
122 }
123
124
125 // Compare two Smis as if they were converted to strings and then
126 // compared lexicographically.
RUNTIME_FUNCTION(Runtime_SmiLexicographicCompare)127 RUNTIME_FUNCTION(Runtime_SmiLexicographicCompare) {
128 SealHandleScope shs(isolate);
129 DCHECK(args.length() == 2);
130 CONVERT_SMI_ARG_CHECKED(x_value, 0);
131 CONVERT_SMI_ARG_CHECKED(y_value, 1);
132
133 // If the integers are equal so are the string representations.
134 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 if (x_value == 0 || y_value == 0)
139 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 uint32_t x_scaled = x_value;
148 uint32_t y_scaled = y_value;
149 if (x_value < 0 || y_value < 0) {
150 if (y_value >= 0) return Smi::FromInt(LESS);
151 if (x_value >= 0) return Smi::FromInt(GREATER);
152 x_scaled = -x_value;
153 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 int x_log2 = 31 - base::bits::CountLeadingZeros32(x_scaled);
170 int x_log10 = ((x_log2 + 1) * 1233) >> 12;
171 x_log10 -= x_scaled < kPowersOf10[x_log10];
172
173 int y_log2 = 31 - base::bits::CountLeadingZeros32(y_scaled);
174 int y_log10 = ((y_log2 + 1) * 1233) >> 12;
175 y_log10 -= y_scaled < kPowersOf10[y_log10];
176
177 int tie = EQUAL;
178
179 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 x_scaled *= kPowersOf10[y_log10 - x_log10 - 1];
187 y_scaled /= 10;
188 tie = LESS;
189 } else if (y_log10 < x_log10) {
190 y_scaled *= kPowersOf10[x_log10 - y_log10 - 1];
191 x_scaled /= 10;
192 tie = GREATER;
193 }
194
195 if (x_scaled < y_scaled) return Smi::FromInt(LESS);
196 if (x_scaled > y_scaled) return Smi::FromInt(GREATER);
197 return Smi::FromInt(tie);
198 }
199
200
RUNTIME_FUNCTION(Runtime_MaxSmi)201 RUNTIME_FUNCTION(Runtime_MaxSmi) {
202 SealHandleScope shs(isolate);
203 DCHECK(args.length() == 0);
204 return Smi::FromInt(Smi::kMaxValue);
205 }
206
207
RUNTIME_FUNCTION(Runtime_IsSmi)208 RUNTIME_FUNCTION(Runtime_IsSmi) {
209 SealHandleScope shs(isolate);
210 DCHECK(args.length() == 1);
211 CONVERT_ARG_CHECKED(Object, obj, 0);
212 return isolate->heap()->ToBoolean(obj->IsSmi());
213 }
214
215
RUNTIME_FUNCTION(Runtime_GetRootNaN)216 RUNTIME_FUNCTION(Runtime_GetRootNaN) {
217 SealHandleScope shs(isolate);
218 DCHECK(args.length() == 0);
219 return isolate->heap()->nan_value();
220 }
221
222
RUNTIME_FUNCTION(Runtime_GetHoleNaNUpper)223 RUNTIME_FUNCTION(Runtime_GetHoleNaNUpper) {
224 HandleScope scope(isolate);
225 DCHECK(args.length() == 0);
226 return *isolate->factory()->NewNumberFromUint(kHoleNanUpper32);
227 }
228
229
RUNTIME_FUNCTION(Runtime_GetHoleNaNLower)230 RUNTIME_FUNCTION(Runtime_GetHoleNaNLower) {
231 HandleScope scope(isolate);
232 DCHECK(args.length() == 0);
233 return *isolate->factory()->NewNumberFromUint(kHoleNanLower32);
234 }
235
236
237 } // namespace internal
238 } // namespace v8
239