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 22227 : 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 7409 : if (value->IsJSValue()) {
26 : value = handle(Handle<JSValue>::cast(value)->value(), isolate);
27 : }
28 7409 : if (!value->IsNumber()) {
29 855 : 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 7124 : 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 7124 : if (std::isnan(value_number)) return isolate->heap()->nan_string();
43 7022 : if (std::isinf(value_number)) {
44 102 : return (value_number < 0.0) ? isolate->heap()->minus_infinity_string()
45 306 : : isolate->heap()->infinity_string();
46 : }
47 6818 : if (fraction_digits_number < 0.0 || fraction_digits_number > 20.0) {
48 801 : THROW_NEW_ERROR_RETURN_FAILURE(
49 : isolate, NewRangeError(MessageTemplate::kNumberFormatRange,
50 : isolate->factory()->NewStringFromAsciiChecked(
51 : "toExponential()")));
52 : }
53 : int const f = args.atOrUndefined(isolate, 1)->IsUndefined(isolate)
54 : ? -1
55 6551 : : static_cast<int>(fraction_digits_number);
56 6551 : char* const str = DoubleToExponentialCString(value_number, f);
57 6551 : Handle<String> result = isolate->factory()->NewStringFromAsciiChecked(str);
58 : DeleteArray(str);
59 6551 : return *result;
60 : }
61 :
62 : // ES6 section 20.1.3.3 Number.prototype.toFixed ( fractionDigits )
63 16125 : BUILTIN(NumberPrototypeToFixed) {
64 : HandleScope scope(isolate);
65 : Handle<Object> value = args.at(0);
66 : Handle<Object> fraction_digits = args.atOrUndefined(isolate, 1);
67 :
68 : // Unwrap the receiver {value}.
69 5375 : if (value->IsJSValue()) {
70 : value = handle(Handle<JSValue>::cast(value)->value(), isolate);
71 : }
72 5375 : if (!value->IsNumber()) {
73 855 : THROW_NEW_ERROR_RETURN_FAILURE(
74 : isolate, NewTypeError(MessageTemplate::kNotGeneric,
75 : isolate->factory()->NewStringFromAsciiChecked(
76 : "Number.prototype.toFixed"),
77 : isolate->factory()->Number_string()));
78 : }
79 : double const value_number = value->Number();
80 :
81 : // Convert the {fraction_digits} to an integer first.
82 5090 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
83 : isolate, fraction_digits, Object::ToInteger(isolate, fraction_digits));
84 : double const fraction_digits_number = fraction_digits->Number();
85 :
86 : // Check if the {fraction_digits} are in the supported range.
87 5090 : if (fraction_digits_number < 0.0 || fraction_digits_number > 20.0) {
88 768 : THROW_NEW_ERROR_RETURN_FAILURE(
89 : isolate, NewRangeError(MessageTemplate::kNumberFormatRange,
90 : isolate->factory()->NewStringFromAsciiChecked(
91 : "toFixed() digits")));
92 : }
93 :
94 4834 : if (std::isnan(value_number)) return isolate->heap()->nan_string();
95 4761 : if (std::isinf(value_number)) {
96 73 : return (value_number < 0.0) ? isolate->heap()->minus_infinity_string()
97 219 : : isolate->heap()->infinity_string();
98 : }
99 : char* const str = DoubleToFixedCString(
100 4615 : value_number, static_cast<int>(fraction_digits_number));
101 4615 : Handle<String> result = isolate->factory()->NewStringFromAsciiChecked(str);
102 : DeleteArray(str);
103 4615 : return *result;
104 : }
105 :
106 : // ES6 section 20.1.3.4 Number.prototype.toLocaleString ( [ r1 [ , r2 ] ] )
107 0 : BUILTIN(NumberPrototypeToLocaleString) {
108 : HandleScope scope(isolate);
109 : Handle<Object> value = args.at(0);
110 :
111 : // Unwrap the receiver {value}.
112 0 : if (value->IsJSValue()) {
113 : value = handle(Handle<JSValue>::cast(value)->value(), isolate);
114 : }
115 0 : if (!value->IsNumber()) {
116 0 : THROW_NEW_ERROR_RETURN_FAILURE(
117 : isolate, NewTypeError(MessageTemplate::kNotGeneric,
118 : isolate->factory()->NewStringFromAsciiChecked(
119 : "Number.prototype.toLocaleString"),
120 : isolate->factory()->Number_string()));
121 : }
122 :
123 : // Turn the {value} into a String.
124 0 : return *isolate->factory()->NumberToString(value);
125 : }
126 :
127 : // ES6 section 20.1.3.5 Number.prototype.toPrecision ( precision )
128 16818 : BUILTIN(NumberPrototypeToPrecision) {
129 : HandleScope scope(isolate);
130 : Handle<Object> value = args.at(0);
131 : Handle<Object> precision = args.atOrUndefined(isolate, 1);
132 :
133 : // Unwrap the receiver {value}.
134 5606 : if (value->IsJSValue()) {
135 : value = handle(Handle<JSValue>::cast(value)->value(), isolate);
136 : }
137 5606 : if (!value->IsNumber()) {
138 855 : THROW_NEW_ERROR_RETURN_FAILURE(
139 : isolate, NewTypeError(MessageTemplate::kNotGeneric,
140 : isolate->factory()->NewStringFromAsciiChecked(
141 : "Number.prototype.toPrecision"),
142 : isolate->factory()->Number_string()));
143 : }
144 : double const value_number = value->Number();
145 :
146 : // If no {precision} was specified, just return ToString of {value}.
147 5321 : if (precision->IsUndefined(isolate)) {
148 392 : return *isolate->factory()->NumberToString(value);
149 : }
150 :
151 : // Convert the {precision} to an integer first.
152 5125 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, precision,
153 : Object::ToInteger(isolate, precision));
154 : double const precision_number = precision->Number();
155 :
156 5125 : if (std::isnan(value_number)) return isolate->heap()->nan_string();
157 5051 : if (std::isinf(value_number)) {
158 74 : return (value_number < 0.0) ? isolate->heap()->minus_infinity_string()
159 222 : : isolate->heap()->infinity_string();
160 : }
161 4903 : if (precision_number < 1.0 || precision_number > 21.0) {
162 452 : THROW_NEW_ERROR_RETURN_FAILURE(
163 : isolate, NewRangeError(MessageTemplate::kToPrecisionFormatRange));
164 : }
165 : char* const str = DoubleToPrecisionCString(
166 4677 : value_number, static_cast<int>(precision_number));
167 4677 : Handle<String> result = isolate->factory()->NewStringFromAsciiChecked(str);
168 : DeleteArray(str);
169 4677 : return *result;
170 : }
171 :
172 : // ES6 section 20.1.3.6 Number.prototype.toString ( [ radix ] )
173 7777428 : BUILTIN(NumberPrototypeToString) {
174 : HandleScope scope(isolate);
175 : Handle<Object> value = args.at(0);
176 : Handle<Object> radix = args.atOrUndefined(isolate, 1);
177 :
178 : // Unwrap the receiver {value}.
179 2592476 : if (value->IsJSValue()) {
180 : value = handle(Handle<JSValue>::cast(value)->value(), isolate);
181 : }
182 2592476 : if (!value->IsNumber()) {
183 900 : THROW_NEW_ERROR_RETURN_FAILURE(
184 : isolate, NewTypeError(MessageTemplate::kNotGeneric,
185 : isolate->factory()->NewStringFromAsciiChecked(
186 : "Number.prototype.toString"),
187 : isolate->factory()->Number_string()));
188 : }
189 : double const value_number = value->Number();
190 :
191 : // If no {radix} was specified, just return ToString of {value}.
192 2592176 : if (radix->IsUndefined(isolate)) {
193 4831248 : return *isolate->factory()->NumberToString(value);
194 : }
195 :
196 : // Convert the {radix} to an integer first.
197 176552 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, radix,
198 : Object::ToInteger(isolate, radix));
199 : double const radix_number = radix->Number();
200 :
201 : // If {radix} is 10, just return ToString of {value}.
202 181721 : if (radix_number == 10.0) return *isolate->factory()->NumberToString(value);
203 :
204 : // Make sure the {radix} is within the valid range.
205 171383 : if (radix_number < 2.0 || radix_number > 36.0) {
206 366 : THROW_NEW_ERROR_RETURN_FAILURE(
207 : isolate, NewRangeError(MessageTemplate::kToRadixFormatRange));
208 : }
209 :
210 : // Fast case where the result is a one character string.
211 171200 : if ((IsUint32Double(value_number) && value_number < radix_number) ||
212 : value_number == -0.0) {
213 : // Character array used for conversion.
214 : static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
215 : return *isolate->factory()->LookupSingleCharacterStringFromCode(
216 8282 : kCharTable[static_cast<uint32_t>(value_number)]);
217 : }
218 :
219 : // Slow case.
220 167059 : if (std::isnan(value_number)) return isolate->heap()->nan_string();
221 167000 : if (std::isinf(value_number)) {
222 59 : return (value_number < 0.0) ? isolate->heap()->minus_infinity_string()
223 177 : : isolate->heap()->infinity_string();
224 : }
225 : char* const str =
226 166882 : DoubleToRadixCString(value_number, static_cast<int>(radix_number));
227 166882 : Handle<String> result = isolate->factory()->NewStringFromAsciiChecked(str);
228 : DeleteArray(str);
229 166882 : return *result;
230 : }
231 :
232 : } // namespace internal
233 : } // namespace v8
|