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/codegen/code-factory.h" 8#include "src/logging/counters.h" 9#include "src/numbers/conversions.h" 10#include "src/objects/objects-inl.h" 11#ifdef V8_INTL_SUPPORT 12#include "src/objects/intl-objects.h" 13#endif 14 15namespace v8 { 16namespace internal { 17 18// ----------------------------------------------------------------------------- 19// ES6 section 20.1 Number Objects 20 21// ES6 section 20.1.3.2 Number.prototype.toExponential ( fractionDigits ) 22BUILTIN(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->IsJSPrimitiveWrapper()) { 29 value = handle(Handle<JSPrimitiveWrapper>::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 ) 67BUILTIN(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->IsJSPrimitiveWrapper()) { 74 value = handle(Handle<JSPrimitiveWrapper>::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 ] ] ) 112BUILTIN(NumberPrototypeToLocaleString) { 113 HandleScope scope(isolate); 114 const char* method_name = "Number.prototype.toLocaleString"; 115 116 isolate->CountUsage(v8::Isolate::UseCounterFeature::kNumberToLocaleString); 117 118 Handle<Object> value = args.at(0); 119 120 // Unwrap the receiver {value}. 121 if (value->IsJSPrimitiveWrapper()) { 122 value = handle(Handle<JSPrimitiveWrapper>::cast(value)->value(), isolate); 123 } 124 // 1. Let x be ? thisNumberValue(this value) 125 if (!value->IsNumber()) { 126 THROW_NEW_ERROR_RETURN_FAILURE( 127 isolate, 128 NewTypeError(MessageTemplate::kNotGeneric, 129 isolate->factory()->NewStringFromAsciiChecked(method_name), 130 isolate->factory()->Number_string())); 131 } 132 133#ifdef V8_INTL_SUPPORT 134 RETURN_RESULT_OR_FAILURE( 135 isolate, 136 Intl::NumberToLocaleString(isolate, value, args.atOrUndefined(isolate, 1), 137 args.atOrUndefined(isolate, 2), method_name)); 138#else 139 // Turn the {value} into a String. 140 return *isolate->factory()->NumberToString(value); 141#endif // V8_INTL_SUPPORT 142} 143 144// ES6 section 20.1.3.5 Number.prototype.toPrecision ( precision ) 145BUILTIN(NumberPrototypeToPrecision) { 146 HandleScope scope(isolate); 147 Handle<Object> value = args.at(0); 148 Handle<Object> precision = args.atOrUndefined(isolate, 1); 149 150 // Unwrap the receiver {value}. 151 if (value->IsJSPrimitiveWrapper()) { 152 value = handle(Handle<JSPrimitiveWrapper>::cast(value)->value(), isolate); 153 } 154 if (!value->IsNumber()) { 155 THROW_NEW_ERROR_RETURN_FAILURE( 156 isolate, NewTypeError(MessageTemplate::kNotGeneric, 157 isolate->factory()->NewStringFromAsciiChecked( 158 "Number.prototype.toPrecision"), 159 isolate->factory()->Number_string())); 160 } 161 double const value_number = value->Number(); 162 163 // If no {precision} was specified, just return ToString of {value}. 164 if (precision->IsUndefined(isolate)) { 165 return *isolate->factory()->NumberToString(value); 166 } 167 168 // Convert the {precision} to an integer first. 169 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, precision, 170 Object::ToInteger(isolate, precision)); 171 double const precision_number = precision->Number(); 172 173 if (std::isnan(value_number)) return ReadOnlyRoots(isolate).NaN_string(); 174 if (std::isinf(value_number)) { 175 return (value_number < 0.0) ? ReadOnlyRoots(isolate).minus_Infinity_string() 176 : ReadOnlyRoots(isolate).Infinity_string(); 177 } 178 if (precision_number < 1.0 || precision_number > kMaxFractionDigits) { 179 THROW_NEW_ERROR_RETURN_FAILURE( 180 isolate, NewRangeError(MessageTemplate::kToPrecisionFormatRange)); 181 } 182 char* const str = DoubleToPrecisionCString( 183 value_number, static_cast<int>(precision_number)); 184 Handle<String> result = isolate->factory()->NewStringFromAsciiChecked(str); 185 DeleteArray(str); 186 return *result; 187} 188 189} // namespace internal 190} // namespace v8 191