Line data Source code
1 : // Copyright 2016 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/builtins/builtins-utils-inl.h"
6 : #include "src/builtins/builtins.h"
7 : #include "src/code-factory.h"
8 : #include "src/conversions.h"
9 : #include "src/counters.h"
10 : #include "src/objects-inl.h"
11 : #ifdef V8_INTL_SUPPORT
12 : #include "src/objects/intl-objects.h"
13 : #endif
14 :
15 : namespace v8 {
16 : namespace internal {
17 :
18 : // -----------------------------------------------------------------------------
19 : // ES6 section 20.1 Number Objects
20 :
21 : // ES6 section 20.1.3.2 Number.prototype.toExponential ( fractionDigits )
22 18432 : BUILTIN(NumberPrototypeToExponential) {
23 : HandleScope scope(isolate);
24 : Handle<Object> value = args.at(0);
25 : Handle<Object> fraction_digits = args.atOrUndefined(isolate, 1);
26 :
27 : // Unwrap the receiver {value}.
28 9216 : if (value->IsJSValue()) {
29 27 : value = handle(Handle<JSValue>::cast(value)->value(), isolate);
30 : }
31 9216 : if (!value->IsNumber()) {
32 513 : THROW_NEW_ERROR_RETURN_FAILURE(
33 : isolate, NewTypeError(MessageTemplate::kNotGeneric,
34 : isolate->factory()->NewStringFromAsciiChecked(
35 : "Number.prototype.toExponential"),
36 : isolate->factory()->Number_string()));
37 : }
38 4437 : double const value_number = value->Number();
39 :
40 : // Convert the {fraction_digits} to an integer first.
41 8874 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
42 : isolate, fraction_digits, Object::ToInteger(isolate, fraction_digits));
43 4437 : double const fraction_digits_number = fraction_digits->Number();
44 :
45 4500 : if (std::isnan(value_number)) return ReadOnlyRoots(isolate).NaN_string();
46 4374 : if (std::isinf(value_number)) {
47 : return (value_number < 0.0) ? ReadOnlyRoots(isolate).minus_Infinity_string()
48 252 : : ReadOnlyRoots(isolate).Infinity_string();
49 : }
50 4248 : if (fraction_digits_number < 0.0 ||
51 : fraction_digits_number > kMaxFractionDigits) {
52 297 : THROW_NEW_ERROR_RETURN_FAILURE(
53 : isolate, NewRangeError(MessageTemplate::kNumberFormatRange,
54 : isolate->factory()->NewStringFromAsciiChecked(
55 : "toExponential()")));
56 : }
57 8298 : int const f = args.atOrUndefined(isolate, 1)->IsUndefined(isolate)
58 : ? -1
59 4149 : : static_cast<int>(fraction_digits_number);
60 4149 : char* const str = DoubleToExponentialCString(value_number, f);
61 4149 : Handle<String> result = isolate->factory()->NewStringFromAsciiChecked(str);
62 : DeleteArray(str);
63 4149 : return *result;
64 : }
65 :
66 : // ES6 section 20.1.3.3 Number.prototype.toFixed ( fractionDigits )
67 13440 : BUILTIN(NumberPrototypeToFixed) {
68 : HandleScope scope(isolate);
69 : Handle<Object> value = args.at(0);
70 : Handle<Object> fraction_digits = args.atOrUndefined(isolate, 1);
71 :
72 : // Unwrap the receiver {value}.
73 6720 : if (value->IsJSValue()) {
74 27 : value = handle(Handle<JSValue>::cast(value)->value(), isolate);
75 : }
76 6720 : if (!value->IsNumber()) {
77 513 : THROW_NEW_ERROR_RETURN_FAILURE(
78 : isolate, NewTypeError(MessageTemplate::kNotGeneric,
79 : isolate->factory()->NewStringFromAsciiChecked(
80 : "Number.prototype.toFixed"),
81 : isolate->factory()->Number_string()));
82 : }
83 3189 : double const value_number = value->Number();
84 :
85 : // Convert the {fraction_digits} to an integer first.
86 6378 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
87 : isolate, fraction_digits, Object::ToInteger(isolate, fraction_digits));
88 3189 : double const fraction_digits_number = fraction_digits->Number();
89 :
90 : // Check if the {fraction_digits} are in the supported range.
91 3189 : if (fraction_digits_number < 0.0 ||
92 : fraction_digits_number > kMaxFractionDigits) {
93 378 : THROW_NEW_ERROR_RETURN_FAILURE(
94 : isolate, NewRangeError(MessageTemplate::kNumberFormatRange,
95 : isolate->factory()->NewStringFromAsciiChecked(
96 : "toFixed() digits")));
97 : }
98 :
99 3108 : if (std::isnan(value_number)) return ReadOnlyRoots(isolate).NaN_string();
100 3018 : if (std::isinf(value_number)) {
101 : return (value_number < 0.0) ? ReadOnlyRoots(isolate).minus_Infinity_string()
102 180 : : ReadOnlyRoots(isolate).Infinity_string();
103 : }
104 : char* const str = DoubleToFixedCString(
105 2928 : value_number, static_cast<int>(fraction_digits_number));
106 2928 : Handle<String> result = isolate->factory()->NewStringFromAsciiChecked(str);
107 : DeleteArray(str);
108 2928 : return *result;
109 : }
110 :
111 : // ES6 section 20.1.3.4 Number.prototype.toLocaleString ( [ r1 [ , r2 ] ] )
112 5256 : BUILTIN(NumberPrototypeToLocaleString) {
113 : HandleScope scope(isolate);
114 :
115 1314 : isolate->CountUsage(v8::Isolate::UseCounterFeature::kNumberToLocaleString);
116 :
117 : Handle<Object> value = args.at(0);
118 :
119 : // Unwrap the receiver {value}.
120 2628 : if (value->IsJSValue()) {
121 27 : value = handle(Handle<JSValue>::cast(value)->value(), isolate);
122 : }
123 : // 1. Let x be ? thisNumberValue(this value)
124 2628 : if (!value->IsNumber()) {
125 27 : THROW_NEW_ERROR_RETURN_FAILURE(
126 : isolate, NewTypeError(MessageTemplate::kNotGeneric,
127 : isolate->factory()->NewStringFromAsciiChecked(
128 : "Number.prototype.toLocaleString"),
129 : isolate->factory()->Number_string()));
130 : }
131 :
132 : #ifdef V8_INTL_SUPPORT
133 2619 : RETURN_RESULT_OR_FAILURE(
134 : isolate,
135 : Intl::NumberToLocaleString(isolate, value, args.atOrUndefined(isolate, 1),
136 : args.atOrUndefined(isolate, 2)));
137 : #else
138 : // Turn the {value} into a String.
139 : return *isolate->factory()->NumberToString(value);
140 : #endif // V8_INTL_SUPPORT
141 : }
142 :
143 : // ES6 section 20.1.3.5 Number.prototype.toPrecision ( precision )
144 13896 : BUILTIN(NumberPrototypeToPrecision) {
145 : HandleScope scope(isolate);
146 : Handle<Object> value = args.at(0);
147 : Handle<Object> precision = args.atOrUndefined(isolate, 1);
148 :
149 : // Unwrap the receiver {value}.
150 6948 : if (value->IsJSValue()) {
151 27 : value = handle(Handle<JSValue>::cast(value)->value(), isolate);
152 : }
153 6948 : if (!value->IsNumber()) {
154 513 : THROW_NEW_ERROR_RETURN_FAILURE(
155 : isolate, NewTypeError(MessageTemplate::kNotGeneric,
156 : isolate->factory()->NewStringFromAsciiChecked(
157 : "Number.prototype.toPrecision"),
158 : isolate->factory()->Number_string()));
159 : }
160 3303 : double const value_number = value->Number();
161 :
162 : // If no {precision} was specified, just return ToString of {value}.
163 6606 : if (precision->IsUndefined(isolate)) {
164 252 : return *isolate->factory()->NumberToString(value);
165 : }
166 :
167 : // Convert the {precision} to an integer first.
168 6354 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, precision,
169 : Object::ToInteger(isolate, precision));
170 3177 : double const precision_number = precision->Number();
171 :
172 3222 : if (std::isnan(value_number)) return ReadOnlyRoots(isolate).NaN_string();
173 3132 : if (std::isinf(value_number)) {
174 : return (value_number < 0.0) ? ReadOnlyRoots(isolate).minus_Infinity_string()
175 180 : : ReadOnlyRoots(isolate).Infinity_string();
176 : }
177 3042 : if (precision_number < 1.0 || precision_number > kMaxFractionDigits) {
178 216 : THROW_NEW_ERROR_RETURN_FAILURE(
179 : isolate, NewRangeError(MessageTemplate::kToPrecisionFormatRange));
180 : }
181 : char* const str = DoubleToPrecisionCString(
182 2934 : value_number, static_cast<int>(precision_number));
183 2934 : Handle<String> result = isolate->factory()->NewStringFromAsciiChecked(str);
184 : DeleteArray(str);
185 2934 : return *result;
186 : }
187 :
188 : // ES6 section 20.1.3.6 Number.prototype.toString ( [ radix ] )
189 6543664 : BUILTIN(NumberPrototypeToString) {
190 : HandleScope scope(isolate);
191 : Handle<Object> value = args.at(0);
192 : Handle<Object> radix = args.atOrUndefined(isolate, 1);
193 :
194 : // Unwrap the receiver {value}.
195 3271832 : if (value->IsJSValue()) {
196 3456 : value = handle(Handle<JSValue>::cast(value)->value(), isolate);
197 : }
198 3271832 : if (!value->IsNumber()) {
199 540 : THROW_NEW_ERROR_RETURN_FAILURE(
200 : isolate, NewTypeError(MessageTemplate::kNotGeneric,
201 : isolate->factory()->NewStringFromAsciiChecked(
202 : "Number.prototype.toString"),
203 : isolate->factory()->Number_string()));
204 : }
205 1635736 : double const value_number = value->Number();
206 :
207 : // If no {radix} was specified, just return ToString of {value}.
208 3271472 : if (radix->IsUndefined(isolate)) {
209 3019434 : return *isolate->factory()->NumberToString(value);
210 : }
211 :
212 : // Convert the {radix} to an integer first.
213 252047 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, radix,
214 : Object::ToInteger(isolate, radix));
215 126010 : double const radix_number = radix->Number();
216 :
217 : // If {radix} is 10, just return ToString of {value}.
218 129245 : if (radix_number == 10.0) return *isolate->factory()->NumberToString(value);
219 :
220 : // Make sure the {radix} is within the valid range.
221 122775 : if (radix_number < 2.0 || radix_number > 36.0) {
222 234 : THROW_NEW_ERROR_RETURN_FAILURE(
223 : isolate, NewRangeError(MessageTemplate::kToRadixFormatRange));
224 : }
225 :
226 : // Fast case where the result is a one character string.
227 122658 : if ((IsUint32Double(value_number) && value_number < radix_number) ||
228 : value_number == -0.0) {
229 : // Character array used for conversion.
230 : static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
231 : return *isolate->factory()->LookupSingleCharacterStringFromCode(
232 5922 : kCharTable[static_cast<uint32_t>(value_number)]);
233 : }
234 :
235 : // Slow case.
236 119733 : if (std::isnan(value_number)) return ReadOnlyRoots(isolate).NaN_string();
237 119661 : if (std::isinf(value_number)) {
238 : return (value_number < 0.0) ? ReadOnlyRoots(isolate).minus_Infinity_string()
239 144 : : ReadOnlyRoots(isolate).Infinity_string();
240 : }
241 : char* const str =
242 119589 : DoubleToRadixCString(value_number, static_cast<int>(radix_number));
243 119589 : Handle<String> result = isolate->factory()->NewStringFromAsciiChecked(str);
244 : DeleteArray(str);
245 119589 : return *result;
246 : }
247 :
248 : } // namespace internal
249 183867 : } // namespace v8
|