1// Copyright 2012 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(function(global, utils) { 6 7%CheckIsBootstrapping(); 8 9// ---------------------------------------------------------------------------- 10// Imports 11 12var GlobalArray = global.Array; 13var GlobalNumber = global.Number; 14var GlobalObject = global.Object; 15var iteratorSymbol = utils.ImportNow("iterator_symbol"); 16var MakeRangeError; 17var MakeSyntaxError; 18var MakeTypeError; 19var MathAbs; 20var NaN = %GetRootNaN(); 21var ObjectToString = utils.ImportNow("object_to_string"); 22var toStringTagSymbol = utils.ImportNow("to_string_tag_symbol"); 23 24utils.Import(function(from) { 25 MakeRangeError = from.MakeRangeError; 26 MakeSyntaxError = from.MakeSyntaxError; 27 MakeTypeError = from.MakeTypeError; 28 MathAbs = from.MathAbs; 29}); 30 31// ---------------------------------------------------------------------------- 32 33 34// ES6 18.2.3 isNaN(number) 35function GlobalIsNaN(number) { 36 number = TO_NUMBER(number); 37 return NUMBER_IS_NAN(number); 38} 39 40 41// ES6 18.2.2 isFinite(number) 42function GlobalIsFinite(number) { 43 number = TO_NUMBER(number); 44 return NUMBER_IS_FINITE(number); 45} 46 47 48// ES6 18.2.5 parseInt(string, radix) 49function GlobalParseInt(string, radix) { 50 if (IS_UNDEFINED(radix) || radix === 10 || radix === 0) { 51 // Some people use parseInt instead of Math.floor. This 52 // optimization makes parseInt on a Smi 12 times faster (60ns 53 // vs 800ns). The following optimization makes parseInt on a 54 // non-Smi number 9 times faster (230ns vs 2070ns). Together 55 // they make parseInt on a string 1.4% slower (274ns vs 270ns). 56 if (%_IsSmi(string)) return string; 57 if (IS_NUMBER(string) && 58 ((0.01 < string && string < 1e9) || 59 (-1e9 < string && string < -0.01))) { 60 // Truncate number. 61 return string | 0; 62 } 63 string = TO_STRING(string); 64 radix = radix | 0; 65 } else { 66 // The spec says ToString should be evaluated before ToInt32. 67 string = TO_STRING(string); 68 radix = TO_INT32(radix); 69 if (!(radix == 0 || (2 <= radix && radix <= 36))) { 70 return NaN; 71 } 72 } 73 74 if (%_HasCachedArrayIndex(string) && 75 (radix == 0 || radix == 10)) { 76 return %_GetCachedArrayIndex(string); 77 } 78 return %StringParseInt(string, radix); 79} 80 81 82// ES6 18.2.4 parseFloat(string) 83function GlobalParseFloat(string) { 84 // 1. Let inputString be ? ToString(string). 85 string = TO_STRING(string); 86 if (%_HasCachedArrayIndex(string)) return %_GetCachedArrayIndex(string); 87 return %StringParseFloat(string); 88} 89 90 91// ---------------------------------------------------------------------------- 92 93// Set up global object. 94var attributes = DONT_ENUM | DONT_DELETE | READ_ONLY; 95 96utils.InstallConstants(global, [ 97 // ES6 18.1.1 98 "Infinity", INFINITY, 99 // ES6 18.1.2 100 "NaN", NaN, 101 // ES6 18.1.3 102 "undefined", UNDEFINED, 103]); 104 105// Set up non-enumerable function on the global object. 106utils.InstallFunctions(global, DONT_ENUM, [ 107 "isNaN", GlobalIsNaN, 108 "isFinite", GlobalIsFinite, 109 "parseInt", GlobalParseInt, 110 "parseFloat", GlobalParseFloat, 111]); 112 113 114// ---------------------------------------------------------------------------- 115// Object 116 117// ES6 19.1.3.5 Object.prototype.toLocaleString([reserved1 [,reserved2]]) 118function ObjectToLocaleString() { 119 CHECK_OBJECT_COERCIBLE(this, "Object.prototype.toLocaleString"); 120 return this.toString(); 121} 122 123 124// ES6 19.1.3.7 Object.prototype.valueOf() 125function ObjectValueOf() { 126 return TO_OBJECT(this); 127} 128 129 130// ES6 19.1.3.3 Object.prototype.isPrototypeOf(V) 131function ObjectIsPrototypeOf(V) { 132 if (!IS_RECEIVER(V)) return false; 133 var O = TO_OBJECT(this); 134 return %HasInPrototypeChain(V, O); 135} 136 137 138// ES6 19.1.3.4 139function ObjectPropertyIsEnumerable(V) { 140 var P = TO_NAME(V); 141 return %PropertyIsEnumerable(TO_OBJECT(this), P); 142} 143 144// ES6 7.3.9 145function GetMethod(obj, p) { 146 var func = obj[p]; 147 if (IS_NULL_OR_UNDEFINED(func)) return UNDEFINED; 148 if (IS_CALLABLE(func)) return func; 149 throw MakeTypeError(kCalledNonCallable, typeof func); 150} 151 152// ES6 section 19.1.2.18. 153function ObjectSetPrototypeOf(obj, proto) { 154 CHECK_OBJECT_COERCIBLE(obj, "Object.setPrototypeOf"); 155 156 if (proto !== null && !IS_RECEIVER(proto)) { 157 throw MakeTypeError(kProtoObjectOrNull, proto); 158 } 159 160 if (IS_RECEIVER(obj)) { 161 %SetPrototype(obj, proto); 162 } 163 164 return obj; 165} 166 167// ES6 B.2.2.1.1 168function ObjectGetProto() { 169 return %object_get_prototype_of(this); 170} 171 172 173// ES6 B.2.2.1.2 174function ObjectSetProto(proto) { 175 CHECK_OBJECT_COERCIBLE(this, "Object.prototype.__proto__"); 176 177 if ((IS_RECEIVER(proto) || IS_NULL(proto)) && IS_RECEIVER(this)) { 178 %SetPrototype(this, proto); 179 } 180} 181 182 183// ES6 19.1.1.1 184function ObjectConstructor(x) { 185 if (GlobalObject != new.target && !IS_UNDEFINED(new.target)) { 186 return this; 187 } 188 if (IS_NULL(x) || IS_UNDEFINED(x)) return {}; 189 return TO_OBJECT(x); 190} 191 192 193// ---------------------------------------------------------------------------- 194// Object 195 196%SetNativeFlag(GlobalObject); 197%SetCode(GlobalObject, ObjectConstructor); 198 199%AddNamedProperty(GlobalObject.prototype, "constructor", GlobalObject, 200 DONT_ENUM); 201 202// Set up non-enumerable functions on the Object.prototype object. 203utils.InstallFunctions(GlobalObject.prototype, DONT_ENUM, [ 204 "toString", ObjectToString, 205 "toLocaleString", ObjectToLocaleString, 206 "valueOf", ObjectValueOf, 207 "isPrototypeOf", ObjectIsPrototypeOf, 208 "propertyIsEnumerable", ObjectPropertyIsEnumerable, 209 // __defineGetter__ is added in bootstrapper.cc. 210 // __lookupGetter__ is added in bootstrapper.cc. 211 // __defineSetter__ is added in bootstrapper.cc. 212 // __lookupSetter__ is added in bootstrapper.cc. 213]); 214utils.InstallGetterSetter( 215 GlobalObject.prototype, "__proto__", ObjectGetProto, ObjectSetProto); 216 217// Set up non-enumerable functions in the Object object. 218utils.InstallFunctions(GlobalObject, DONT_ENUM, [ 219 "setPrototypeOf", ObjectSetPrototypeOf, 220 // getOwnPropertySymbols is added in symbol.js. 221 // Others are added in bootstrapper.cc. 222]); 223 224 225 226// ---------------------------------------------------------------------------- 227// Number 228 229// ES6 Number.prototype.toString([ radix ]) 230function NumberToStringJS(radix) { 231 // NOTE: Both Number objects and values can enter here as 232 // 'this'. This is not as dictated by ECMA-262. 233 var number = this; 234 if (!IS_NUMBER(this)) { 235 if (!IS_NUMBER_WRAPPER(this)) { 236 throw MakeTypeError(kNotGeneric, 'Number.prototype.toString'); 237 } 238 // Get the value of this number in case it's an object. 239 number = %_ValueOf(this); 240 } 241 // Fast case: Convert number in radix 10. 242 if (IS_UNDEFINED(radix) || radix === 10) { 243 return %_NumberToString(number); 244 } 245 246 // Convert the radix to an integer and check the range. 247 radix = TO_INTEGER(radix); 248 if (radix < 2 || radix > 36) throw MakeRangeError(kToRadixFormatRange); 249 // Convert the number to a string in the given radix. 250 return %NumberToRadixString(number, radix); 251} 252 253 254// ES6 20.1.3.4 Number.prototype.toLocaleString([reserved1 [, reserved2]]) 255function NumberToLocaleString() { 256 return %_Call(NumberToStringJS, this); 257} 258 259 260// ES6 20.1.3.7 Number.prototype.valueOf() 261function NumberValueOf() { 262 // NOTE: Both Number objects and values can enter here as 263 // 'this'. This is not as dictated by ECMA-262. 264 if (!IS_NUMBER(this) && !IS_NUMBER_WRAPPER(this)) { 265 throw MakeTypeError(kNotGeneric, 'Number.prototype.valueOf'); 266 } 267 return %_ValueOf(this); 268} 269 270 271// ES6 20.1.3.3 Number.prototype.toFixed(fractionDigits) 272function NumberToFixedJS(fractionDigits) { 273 var x = this; 274 if (!IS_NUMBER(this)) { 275 if (!IS_NUMBER_WRAPPER(this)) { 276 throw MakeTypeError(kIncompatibleMethodReceiver, 277 "Number.prototype.toFixed", this); 278 } 279 // Get the value of this number in case it's an object. 280 x = %_ValueOf(this); 281 } 282 var f = TO_INTEGER(fractionDigits); 283 284 if (f < 0 || f > 20) { 285 throw MakeRangeError(kNumberFormatRange, "toFixed() digits"); 286 } 287 288 if (NUMBER_IS_NAN(x)) return "NaN"; 289 if (x == INFINITY) return "Infinity"; 290 if (x == -INFINITY) return "-Infinity"; 291 292 return %NumberToFixed(x, f); 293} 294 295 296// ES6 20.1.3.2 Number.prototype.toExponential(fractionDigits) 297function NumberToExponentialJS(fractionDigits) { 298 var x = this; 299 if (!IS_NUMBER(this)) { 300 if (!IS_NUMBER_WRAPPER(this)) { 301 throw MakeTypeError(kIncompatibleMethodReceiver, 302 "Number.prototype.toExponential", this); 303 } 304 // Get the value of this number in case it's an object. 305 x = %_ValueOf(this); 306 } 307 var f = IS_UNDEFINED(fractionDigits) ? UNDEFINED : TO_INTEGER(fractionDigits); 308 309 if (NUMBER_IS_NAN(x)) return "NaN"; 310 if (x == INFINITY) return "Infinity"; 311 if (x == -INFINITY) return "-Infinity"; 312 313 if (IS_UNDEFINED(f)) { 314 f = -1; // Signal for runtime function that f is not defined. 315 } else if (f < 0 || f > 20) { 316 throw MakeRangeError(kNumberFormatRange, "toExponential()"); 317 } 318 return %NumberToExponential(x, f); 319} 320 321 322// ES6 20.1.3.5 Number.prototype.toPrecision(precision) 323function NumberToPrecisionJS(precision) { 324 var x = this; 325 if (!IS_NUMBER(this)) { 326 if (!IS_NUMBER_WRAPPER(this)) { 327 throw MakeTypeError(kIncompatibleMethodReceiver, 328 "Number.prototype.toPrecision", this); 329 } 330 // Get the value of this number in case it's an object. 331 x = %_ValueOf(this); 332 } 333 if (IS_UNDEFINED(precision)) return TO_STRING(x); 334 var p = TO_INTEGER(precision); 335 336 if (NUMBER_IS_NAN(x)) return "NaN"; 337 if (x == INFINITY) return "Infinity"; 338 if (x == -INFINITY) return "-Infinity"; 339 340 if (p < 1 || p > 21) { 341 throw MakeRangeError(kToPrecisionFormatRange); 342 } 343 return %NumberToPrecision(x, p); 344} 345 346 347// Harmony isFinite. 348function NumberIsFinite(number) { 349 return IS_NUMBER(number) && NUMBER_IS_FINITE(number); 350} 351 352 353// Harmony isInteger 354function NumberIsInteger(number) { 355 return NumberIsFinite(number) && TO_INTEGER(number) == number; 356} 357 358 359// Harmony isNaN. 360function NumberIsNaN(number) { 361 return IS_NUMBER(number) && NUMBER_IS_NAN(number); 362} 363 364 365// Harmony isSafeInteger 366function NumberIsSafeInteger(number) { 367 if (NumberIsFinite(number)) { 368 var integral = TO_INTEGER(number); 369 if (integral == number) { 370 return MathAbs(integral) <= kMaxSafeInteger; 371 } 372 } 373 return false; 374} 375 376 377// ---------------------------------------------------------------------------- 378 379%FunctionSetPrototype(GlobalNumber, new GlobalNumber(0)); 380 381%OptimizeObjectForAddingMultipleProperties(GlobalNumber.prototype, 8); 382// Set up the constructor property on the Number prototype object. 383%AddNamedProperty(GlobalNumber.prototype, "constructor", GlobalNumber, 384 DONT_ENUM); 385 386utils.InstallConstants(GlobalNumber, [ 387 // ECMA-262 section 15.7.3.1. 388 "MAX_VALUE", 1.7976931348623157e+308, 389 // ECMA-262 section 15.7.3.2. 390 "MIN_VALUE", 5e-324, 391 // ECMA-262 section 15.7.3.3. 392 "NaN", NaN, 393 // ECMA-262 section 15.7.3.4. 394 "NEGATIVE_INFINITY", -INFINITY, 395 // ECMA-262 section 15.7.3.5. 396 "POSITIVE_INFINITY", INFINITY, 397 398 // --- Harmony constants (no spec refs until settled.) 399 400 "MAX_SAFE_INTEGER", %_MathPow(2, 53) - 1, 401 "MIN_SAFE_INTEGER", -%_MathPow(2, 53) + 1, 402 "EPSILON", %_MathPow(2, -52) 403]); 404 405// Set up non-enumerable functions on the Number prototype object. 406utils.InstallFunctions(GlobalNumber.prototype, DONT_ENUM, [ 407 "toString", NumberToStringJS, 408 "toLocaleString", NumberToLocaleString, 409 "valueOf", NumberValueOf, 410 "toFixed", NumberToFixedJS, 411 "toExponential", NumberToExponentialJS, 412 "toPrecision", NumberToPrecisionJS 413]); 414 415// Harmony Number constructor additions 416utils.InstallFunctions(GlobalNumber, DONT_ENUM, [ 417 "isFinite", NumberIsFinite, 418 "isInteger", NumberIsInteger, 419 "isNaN", NumberIsNaN, 420 "isSafeInteger", NumberIsSafeInteger, 421 "parseInt", GlobalParseInt, 422 "parseFloat", GlobalParseFloat 423]); 424 425%SetForceInlineFlag(NumberIsNaN); 426 427 428// ---------------------------------------------------------------------------- 429// Iterator related spec functions. 430 431// ES6 7.4.1 GetIterator(obj, method) 432function GetIterator(obj, method) { 433 if (IS_UNDEFINED(method)) { 434 method = obj[iteratorSymbol]; 435 } 436 if (!IS_CALLABLE(method)) { 437 throw MakeTypeError(kNotIterable, obj); 438 } 439 var iterator = %_Call(method, obj); 440 if (!IS_RECEIVER(iterator)) { 441 throw MakeTypeError(kNotAnIterator, iterator); 442 } 443 return iterator; 444} 445 446// ---------------------------------------------------------------------------- 447// Exports 448 449utils.Export(function(to) { 450 to.GetIterator = GetIterator; 451 to.GetMethod = GetMethod; 452 to.IsNaN = GlobalIsNaN; 453 to.NumberIsNaN = NumberIsNaN; 454 to.NumberIsInteger = NumberIsInteger; 455 to.ObjectHasOwnProperty = GlobalObject.prototype.hasOwnProperty; 456}); 457 458%InstallToContext([ 459 "object_value_of", ObjectValueOf, 460]); 461 462}) 463