• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 )
BUILTIN(NumberPrototypeToExponential)22 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   if (value->IsJSValue()) {
29     value = handle(Handle<JSValue>::cast(value)->value(), isolate);
30   }
31   if (!value->IsNumber()) {
32     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   double const value_number = value->Number();
39 
40   // Convert the {fraction_digits} to an integer first.
41   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
42       isolate, fraction_digits, Object::ToInteger(isolate, fraction_digits));
43   double const fraction_digits_number = fraction_digits->Number();
44 
45   if (std::isnan(value_number)) return ReadOnlyRoots(isolate).NaN_string();
46   if (std::isinf(value_number)) {
47     return (value_number < 0.0) ? ReadOnlyRoots(isolate).minus_Infinity_string()
48                                 : ReadOnlyRoots(isolate).Infinity_string();
49   }
50   if (fraction_digits_number < 0.0 ||
51       fraction_digits_number > kMaxFractionDigits) {
52     THROW_NEW_ERROR_RETURN_FAILURE(
53         isolate, NewRangeError(MessageTemplate::kNumberFormatRange,
54                                isolate->factory()->NewStringFromAsciiChecked(
55                                    "toExponential()")));
56   }
57   int const f = args.atOrUndefined(isolate, 1)->IsUndefined(isolate)
58                     ? -1
59                     : static_cast<int>(fraction_digits_number);
60   char* const str = DoubleToExponentialCString(value_number, f);
61   Handle<String> result = isolate->factory()->NewStringFromAsciiChecked(str);
62   DeleteArray(str);
63   return *result;
64 }
65 
66 // ES6 section 20.1.3.3 Number.prototype.toFixed ( fractionDigits )
BUILTIN(NumberPrototypeToFixed)67 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   if (value->IsJSValue()) {
74     value = handle(Handle<JSValue>::cast(value)->value(), isolate);
75   }
76   if (!value->IsNumber()) {
77     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   double const value_number = value->Number();
84 
85   // Convert the {fraction_digits} to an integer first.
86   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
87       isolate, fraction_digits, Object::ToInteger(isolate, fraction_digits));
88   double const fraction_digits_number = fraction_digits->Number();
89 
90   // Check if the {fraction_digits} are in the supported range.
91   if (fraction_digits_number < 0.0 ||
92       fraction_digits_number > kMaxFractionDigits) {
93     THROW_NEW_ERROR_RETURN_FAILURE(
94         isolate, NewRangeError(MessageTemplate::kNumberFormatRange,
95                                isolate->factory()->NewStringFromAsciiChecked(
96                                    "toFixed() digits")));
97   }
98 
99   if (std::isnan(value_number)) return ReadOnlyRoots(isolate).NaN_string();
100   if (std::isinf(value_number)) {
101     return (value_number < 0.0) ? ReadOnlyRoots(isolate).minus_Infinity_string()
102                                 : ReadOnlyRoots(isolate).Infinity_string();
103   }
104   char* const str = DoubleToFixedCString(
105       value_number, static_cast<int>(fraction_digits_number));
106   Handle<String> result = isolate->factory()->NewStringFromAsciiChecked(str);
107   DeleteArray(str);
108   return *result;
109 }
110 
111 // ES6 section 20.1.3.4 Number.prototype.toLocaleString ( [ r1 [ , r2 ] ] )
BUILTIN(NumberPrototypeToLocaleString)112 BUILTIN(NumberPrototypeToLocaleString) {
113   HandleScope scope(isolate);
114   Handle<Object> value = args.at(0);
115 
116   // Unwrap the receiver {value}.
117   if (value->IsJSValue()) {
118     value = handle(Handle<JSValue>::cast(value)->value(), isolate);
119   }
120   // 1. Let x be ? thisNumberValue(this value)
121   if (!value->IsNumber()) {
122     THROW_NEW_ERROR_RETURN_FAILURE(
123         isolate, NewTypeError(MessageTemplate::kNotGeneric,
124                               isolate->factory()->NewStringFromAsciiChecked(
125                                   "Number.prototype.toLocaleString"),
126                               isolate->factory()->Number_string()));
127   }
128 
129 #ifdef V8_INTL_SUPPORT
130   RETURN_RESULT_OR_FAILURE(
131       isolate,
132       Intl::NumberToLocaleString(isolate, value, args.atOrUndefined(isolate, 1),
133                                  args.atOrUndefined(isolate, 2)));
134 #else
135   // Turn the {value} into a String.
136   return *isolate->factory()->NumberToString(value);
137 #endif  // V8_INTL_SUPPORT
138 }
139 
140 // ES6 section 20.1.3.5 Number.prototype.toPrecision ( precision )
BUILTIN(NumberPrototypeToPrecision)141 BUILTIN(NumberPrototypeToPrecision) {
142   HandleScope scope(isolate);
143   Handle<Object> value = args.at(0);
144   Handle<Object> precision = args.atOrUndefined(isolate, 1);
145 
146   // Unwrap the receiver {value}.
147   if (value->IsJSValue()) {
148     value = handle(Handle<JSValue>::cast(value)->value(), isolate);
149   }
150   if (!value->IsNumber()) {
151     THROW_NEW_ERROR_RETURN_FAILURE(
152         isolate, NewTypeError(MessageTemplate::kNotGeneric,
153                               isolate->factory()->NewStringFromAsciiChecked(
154                                   "Number.prototype.toPrecision"),
155                               isolate->factory()->Number_string()));
156   }
157   double const value_number = value->Number();
158 
159   // If no {precision} was specified, just return ToString of {value}.
160   if (precision->IsUndefined(isolate)) {
161     return *isolate->factory()->NumberToString(value);
162   }
163 
164   // Convert the {precision} to an integer first.
165   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, precision,
166                                      Object::ToInteger(isolate, precision));
167   double const precision_number = precision->Number();
168 
169   if (std::isnan(value_number)) return ReadOnlyRoots(isolate).NaN_string();
170   if (std::isinf(value_number)) {
171     return (value_number < 0.0) ? ReadOnlyRoots(isolate).minus_Infinity_string()
172                                 : ReadOnlyRoots(isolate).Infinity_string();
173   }
174   if (precision_number < 1.0 || precision_number > kMaxFractionDigits) {
175     THROW_NEW_ERROR_RETURN_FAILURE(
176         isolate, NewRangeError(MessageTemplate::kToPrecisionFormatRange));
177   }
178   char* const str = DoubleToPrecisionCString(
179       value_number, static_cast<int>(precision_number));
180   Handle<String> result = isolate->factory()->NewStringFromAsciiChecked(str);
181   DeleteArray(str);
182   return *result;
183 }
184 
185 // ES6 section 20.1.3.6 Number.prototype.toString ( [ radix ] )
BUILTIN(NumberPrototypeToString)186 BUILTIN(NumberPrototypeToString) {
187   HandleScope scope(isolate);
188   Handle<Object> value = args.at(0);
189   Handle<Object> radix = args.atOrUndefined(isolate, 1);
190 
191   // Unwrap the receiver {value}.
192   if (value->IsJSValue()) {
193     value = handle(Handle<JSValue>::cast(value)->value(), isolate);
194   }
195   if (!value->IsNumber()) {
196     THROW_NEW_ERROR_RETURN_FAILURE(
197         isolate, NewTypeError(MessageTemplate::kNotGeneric,
198                               isolate->factory()->NewStringFromAsciiChecked(
199                                   "Number.prototype.toString"),
200                               isolate->factory()->Number_string()));
201   }
202   double const value_number = value->Number();
203 
204   // If no {radix} was specified, just return ToString of {value}.
205   if (radix->IsUndefined(isolate)) {
206     return *isolate->factory()->NumberToString(value);
207   }
208 
209   // Convert the {radix} to an integer first.
210   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, radix,
211                                      Object::ToInteger(isolate, radix));
212   double const radix_number = radix->Number();
213 
214   // If {radix} is 10, just return ToString of {value}.
215   if (radix_number == 10.0) return *isolate->factory()->NumberToString(value);
216 
217   // Make sure the {radix} is within the valid range.
218   if (radix_number < 2.0 || radix_number > 36.0) {
219     THROW_NEW_ERROR_RETURN_FAILURE(
220         isolate, NewRangeError(MessageTemplate::kToRadixFormatRange));
221   }
222 
223   // Fast case where the result is a one character string.
224   if ((IsUint32Double(value_number) && value_number < radix_number) ||
225       value_number == -0.0) {
226     // Character array used for conversion.
227     static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
228     return *isolate->factory()->LookupSingleCharacterStringFromCode(
229         kCharTable[static_cast<uint32_t>(value_number)]);
230   }
231 
232   // Slow case.
233   if (std::isnan(value_number)) return ReadOnlyRoots(isolate).NaN_string();
234   if (std::isinf(value_number)) {
235     return (value_number < 0.0) ? ReadOnlyRoots(isolate).minus_Infinity_string()
236                                 : ReadOnlyRoots(isolate).Infinity_string();
237   }
238   char* const str =
239       DoubleToRadixCString(value_number, static_cast<int>(radix_number));
240   Handle<String> result = isolate->factory()->NewStringFromAsciiChecked(str);
241   DeleteArray(str);
242   return *result;
243 }
244 
245 }  // namespace internal
246 }  // namespace v8
247