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.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 :
12 : namespace v8 {
13 : namespace internal {
14 :
15 : // -----------------------------------------------------------------------------
16 : // ES6 section 20.1 Number Objects
17 :
18 : // ES6 section 20.1.3.2 Number.prototype.toExponential ( fractionDigits )
19 14547 : BUILTIN(NumberPrototypeToExponential) {
20 : HandleScope scope(isolate);
21 : Handle<Object> value = args.at(0);
22 : Handle<Object> fraction_digits = args.atOrUndefined(isolate, 1);
23 :
24 : // Unwrap the receiver {value}.
25 4849 : if (value->IsJSValue()) {
26 : value = handle(Handle<JSValue>::cast(value)->value(), isolate);
27 : }
28 4849 : if (!value->IsNumber()) {
29 570 : THROW_NEW_ERROR_RETURN_FAILURE(
30 : isolate, NewTypeError(MessageTemplate::kNotGeneric,
31 : isolate->factory()->NewStringFromAsciiChecked(
32 : "Number.prototype.toExponential"),
33 : isolate->factory()->Number_string()));
34 : }
35 : double const value_number = value->Number();
36 :
37 : // Convert the {fraction_digits} to an integer first.
38 4659 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
39 : isolate, fraction_digits, Object::ToInteger(isolate, fraction_digits));
40 : double const fraction_digits_number = fraction_digits->Number();
41 :
42 4659 : if (std::isnan(value_number)) return isolate->heap()->NaN_string();
43 4592 : if (std::isinf(value_number)) {
44 67 : return (value_number < 0.0) ? isolate->heap()->minus_Infinity_string()
45 201 : : isolate->heap()->Infinity_string();
46 : }
47 4458 : if (fraction_digits_number < 0.0 ||
48 : fraction_digits_number > kMaxFractionDigits) {
49 300 : THROW_NEW_ERROR_RETURN_FAILURE(
50 : isolate, NewRangeError(MessageTemplate::kNumberFormatRange,
51 : isolate->factory()->NewStringFromAsciiChecked(
52 : "toExponential()")));
53 : }
54 : int const f = args.atOrUndefined(isolate, 1)->IsUndefined(isolate)
55 : ? -1
56 4358 : : static_cast<int>(fraction_digits_number);
57 4358 : char* const str = DoubleToExponentialCString(value_number, f);
58 4358 : Handle<String> result = isolate->factory()->NewStringFromAsciiChecked(str);
59 : DeleteArray(str);
60 4358 : return *result;
61 : }
62 :
63 : // ES6 section 20.1.3.3 Number.prototype.toFixed ( fractionDigits )
64 10815 : BUILTIN(NumberPrototypeToFixed) {
65 : HandleScope scope(isolate);
66 : Handle<Object> value = args.at(0);
67 : Handle<Object> fraction_digits = args.atOrUndefined(isolate, 1);
68 :
69 : // Unwrap the receiver {value}.
70 3605 : if (value->IsJSValue()) {
71 : value = handle(Handle<JSValue>::cast(value)->value(), isolate);
72 : }
73 3605 : if (!value->IsNumber()) {
74 570 : THROW_NEW_ERROR_RETURN_FAILURE(
75 : isolate, NewTypeError(MessageTemplate::kNotGeneric,
76 : isolate->factory()->NewStringFromAsciiChecked(
77 : "Number.prototype.toFixed"),
78 : isolate->factory()->Number_string()));
79 : }
80 : double const value_number = value->Number();
81 :
82 : // Convert the {fraction_digits} to an integer first.
83 3415 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
84 : isolate, fraction_digits, Object::ToInteger(isolate, fraction_digits));
85 : double const fraction_digits_number = fraction_digits->Number();
86 :
87 : // Check if the {fraction_digits} are in the supported range.
88 3415 : if (fraction_digits_number < 0.0 ||
89 : fraction_digits_number > kMaxFractionDigits) {
90 390 : THROW_NEW_ERROR_RETURN_FAILURE(
91 : isolate, NewRangeError(MessageTemplate::kNumberFormatRange,
92 : isolate->factory()->NewStringFromAsciiChecked(
93 : "toFixed() digits")));
94 : }
95 :
96 3285 : if (std::isnan(value_number)) return isolate->heap()->NaN_string();
97 3237 : if (std::isinf(value_number)) {
98 48 : return (value_number < 0.0) ? isolate->heap()->minus_Infinity_string()
99 144 : : isolate->heap()->Infinity_string();
100 : }
101 : char* const str = DoubleToFixedCString(
102 3141 : value_number, static_cast<int>(fraction_digits_number));
103 3141 : Handle<String> result = isolate->factory()->NewStringFromAsciiChecked(str);
104 : DeleteArray(str);
105 3141 : return *result;
106 : }
107 :
108 : // ES6 section 20.1.3.4 Number.prototype.toLocaleString ( [ r1 [ , r2 ] ] )
109 0 : BUILTIN(NumberPrototypeToLocaleString) {
110 : HandleScope scope(isolate);
111 : Handle<Object> value = args.at(0);
112 :
113 : // Unwrap the receiver {value}.
114 0 : if (value->IsJSValue()) {
115 : value = handle(Handle<JSValue>::cast(value)->value(), isolate);
116 : }
117 0 : if (!value->IsNumber()) {
118 0 : THROW_NEW_ERROR_RETURN_FAILURE(
119 : isolate, NewTypeError(MessageTemplate::kNotGeneric,
120 : isolate->factory()->NewStringFromAsciiChecked(
121 : "Number.prototype.toLocaleString"),
122 : isolate->factory()->Number_string()));
123 : }
124 :
125 : // Turn the {value} into a String.
126 0 : return *isolate->factory()->NumberToString(value);
127 : }
128 :
129 : // ES6 section 20.1.3.5 Number.prototype.toPrecision ( precision )
130 11028 : BUILTIN(NumberPrototypeToPrecision) {
131 : HandleScope scope(isolate);
132 : Handle<Object> value = args.at(0);
133 : Handle<Object> precision = args.atOrUndefined(isolate, 1);
134 :
135 : // Unwrap the receiver {value}.
136 3676 : if (value->IsJSValue()) {
137 : value = handle(Handle<JSValue>::cast(value)->value(), isolate);
138 : }
139 3676 : if (!value->IsNumber()) {
140 570 : THROW_NEW_ERROR_RETURN_FAILURE(
141 : isolate, NewTypeError(MessageTemplate::kNotGeneric,
142 : isolate->factory()->NewStringFromAsciiChecked(
143 : "Number.prototype.toPrecision"),
144 : isolate->factory()->Number_string()));
145 : }
146 : double const value_number = value->Number();
147 :
148 : // If no {precision} was specified, just return ToString of {value}.
149 3486 : if (precision->IsUndefined(isolate)) {
150 252 : return *isolate->factory()->NumberToString(value);
151 : }
152 :
153 : // Convert the {precision} to an integer first.
154 3360 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, precision,
155 : Object::ToInteger(isolate, precision));
156 : double const precision_number = precision->Number();
157 :
158 3360 : if (std::isnan(value_number)) return isolate->heap()->NaN_string();
159 3311 : if (std::isinf(value_number)) {
160 49 : return (value_number < 0.0) ? isolate->heap()->minus_Infinity_string()
161 147 : : isolate->heap()->Infinity_string();
162 : }
163 3213 : if (precision_number < 1.0 || precision_number > kMaxFractionDigits) {
164 218 : THROW_NEW_ERROR_RETURN_FAILURE(
165 : isolate, NewRangeError(MessageTemplate::kToPrecisionFormatRange));
166 : }
167 : char* const str = DoubleToPrecisionCString(
168 3104 : value_number, static_cast<int>(precision_number));
169 3104 : Handle<String> result = isolate->factory()->NewStringFromAsciiChecked(str);
170 : DeleteArray(str);
171 3104 : return *result;
172 : }
173 :
174 : // ES6 section 20.1.3.6 Number.prototype.toString ( [ radix ] )
175 5126334 : BUILTIN(NumberPrototypeToString) {
176 : HandleScope scope(isolate);
177 : Handle<Object> value = args.at(0);
178 : Handle<Object> radix = args.atOrUndefined(isolate, 1);
179 :
180 : // Unwrap the receiver {value}.
181 1708778 : if (value->IsJSValue()) {
182 : value = handle(Handle<JSValue>::cast(value)->value(), isolate);
183 : }
184 1708778 : if (!value->IsNumber()) {
185 600 : THROW_NEW_ERROR_RETURN_FAILURE(
186 : isolate, NewTypeError(MessageTemplate::kNotGeneric,
187 : isolate->factory()->NewStringFromAsciiChecked(
188 : "Number.prototype.toString"),
189 : isolate->factory()->Number_string()));
190 : }
191 : double const value_number = value->Number();
192 :
193 : // If no {radix} was specified, just return ToString of {value}.
194 1708578 : if (radix->IsUndefined(isolate)) {
195 3182258 : return *isolate->factory()->NumberToString(value);
196 : }
197 :
198 : // Convert the {radix} to an integer first.
199 117449 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, radix,
200 : Object::ToInteger(isolate, radix));
201 : double const radix_number = radix->Number();
202 :
203 : // If {radix} is 10, just return ToString of {value}.
204 120973 : if (radix_number == 10.0) return *isolate->factory()->NumberToString(value);
205 :
206 : // Make sure the {radix} is within the valid range.
207 113905 : if (radix_number < 2.0 || radix_number > 36.0) {
208 236 : THROW_NEW_ERROR_RETURN_FAILURE(
209 : isolate, NewRangeError(MessageTemplate::kToRadixFormatRange));
210 : }
211 :
212 : // Fast case where the result is a one character string.
213 113787 : if ((IsUint32Double(value_number) && value_number < radix_number) ||
214 : value_number == -0.0) {
215 : // Character array used for conversion.
216 : static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
217 : return *isolate->factory()->LookupSingleCharacterStringFromCode(
218 5502 : kCharTable[static_cast<uint32_t>(value_number)]);
219 : }
220 :
221 : // Slow case.
222 111036 : if (std::isnan(value_number)) return isolate->heap()->NaN_string();
223 110997 : if (std::isinf(value_number)) {
224 39 : return (value_number < 0.0) ? isolate->heap()->minus_Infinity_string()
225 117 : : isolate->heap()->Infinity_string();
226 : }
227 : char* const str =
228 110919 : DoubleToRadixCString(value_number, static_cast<int>(radix_number));
229 110919 : Handle<String> result = isolate->factory()->NewStringFromAsciiChecked(str);
230 : DeleteArray(str);
231 110919 : return *result;
232 : }
233 :
234 : } // namespace internal
235 : } // namespace v8
|