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