v8natives.js revision d91b9f7d46489a9ee00f9cb415630299c76a502b
1// Copyright 2006-2008 the V8 project authors. All rights reserved. 2// Redistribution and use in source and binary forms, with or without 3// modification, are permitted provided that the following conditions are 4// met: 5// 6// * Redistributions of source code must retain the above copyright 7// notice, this list of conditions and the following disclaimer. 8// * Redistributions in binary form must reproduce the above 9// copyright notice, this list of conditions and the following 10// disclaimer in the documentation and/or other materials provided 11// with the distribution. 12// * Neither the name of Google Inc. nor the names of its 13// contributors may be used to endorse or promote products derived 14// from this software without specific prior written permission. 15// 16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28// This file relies on the fact that the following declarations have been made 29// 30// in runtime.js: 31// const $Object = global.Object; 32// const $Boolean = global.Boolean; 33// const $Number = global.Number; 34// const $Function = global.Function; 35// const $Array = global.Array; 36// const $NaN = 0/0; 37// 38// in math.js: 39// const $floor = MathFloor 40 41const $isNaN = GlobalIsNaN; 42const $isFinite = GlobalIsFinite; 43 44 45// ---------------------------------------------------------------------------- 46 47 48// Helper function used to install functions on objects. 49function InstallFunctions(object, attributes, functions) { 50 if (functions.length >= 8) { 51 %OptimizeObjectForAddingMultipleProperties(object, functions.length >> 1); 52 } 53 for (var i = 0; i < functions.length; i += 2) { 54 var key = functions[i]; 55 var f = functions[i + 1]; 56 %FunctionSetName(f, key); 57 %SetProperty(object, key, f, attributes); 58 } 59 %TransformToFastProperties(object); 60} 61 62// Emulates JSC by installing functions on a hidden prototype that 63// lies above the current object/prototype. This lets you override 64// functions on String.prototype etc. and then restore the old function 65// with delete. See http://code.google.com/p/chromium/issues/detail?id=1717 66function InstallFunctionsOnHiddenPrototype(object, attributes, functions) { 67 var hidden_prototype = new $Object(); 68 %SetHiddenPrototype(object, hidden_prototype); 69 InstallFunctions(hidden_prototype, attributes, functions); 70} 71 72 73// ---------------------------------------------------------------------------- 74 75 76// ECMA 262 - 15.1.4 77function GlobalIsNaN(number) { 78 var n = ToNumber(number); 79 return NUMBER_IS_NAN(n); 80} 81 82 83// ECMA 262 - 15.1.5 84function GlobalIsFinite(number) { 85 return %NumberIsFinite(ToNumber(number)); 86} 87 88 89// ECMA-262 - 15.1.2.2 90function GlobalParseInt(string, radix) { 91 if (IS_UNDEFINED(radix)) { 92 // Some people use parseInt instead of Math.floor. This 93 // optimization makes parseInt on a Smi 12 times faster (60ns 94 // vs 800ns). The following optimization makes parseInt on a 95 // non-Smi number 9 times faster (230ns vs 2070ns). Together 96 // they make parseInt on a string 1.4% slower (274ns vs 270ns). 97 if (%_IsSmi(string)) return string; 98 if (IS_NUMBER(string) && 99 ((0.01 < string && string < 1e9) || 100 (-1e9 < string && string < -0.01))) { 101 // Truncate number. 102 return string | 0; 103 } 104 radix = 0; 105 } else { 106 radix = TO_INT32(radix); 107 if (!(radix == 0 || (2 <= radix && radix <= 36))) 108 return $NaN; 109 } 110 return %StringParseInt(ToString(string), radix); 111} 112 113 114// ECMA-262 - 15.1.2.3 115function GlobalParseFloat(string) { 116 return %StringParseFloat(ToString(string)); 117} 118 119 120function GlobalEval(x) { 121 if (!IS_STRING(x)) return x; 122 123 var global_receiver = %GlobalReceiver(global); 124 var this_is_global_receiver = (this === global_receiver); 125 var global_is_detached = (global === global_receiver); 126 127 if (!this_is_global_receiver || global_is_detached) { 128 throw new $EvalError('The "this" object passed to eval must ' + 129 'be the global object from which eval originated'); 130 } 131 132 var f = %CompileString(x, false); 133 if (!IS_FUNCTION(f)) return f; 134 135 return f.call(this); 136} 137 138 139// execScript for IE compatibility. 140function GlobalExecScript(expr, lang) { 141 // NOTE: We don't care about the character casing. 142 if (!lang || /javascript/i.test(lang)) { 143 var f = %CompileString(ToString(expr), false); 144 f.call(%GlobalReceiver(global)); 145 } 146 return null; 147} 148 149 150// ---------------------------------------------------------------------------- 151 152 153function SetupGlobal() { 154 // ECMA 262 - 15.1.1.1. 155 %SetProperty(global, "NaN", $NaN, DONT_ENUM | DONT_DELETE); 156 157 // ECMA-262 - 15.1.1.2. 158 %SetProperty(global, "Infinity", 1/0, DONT_ENUM | DONT_DELETE); 159 160 // ECMA-262 - 15.1.1.3. 161 %SetProperty(global, "undefined", void 0, DONT_ENUM | DONT_DELETE); 162 163 // Setup non-enumerable function on the global object. 164 InstallFunctions(global, DONT_ENUM, $Array( 165 "isNaN", GlobalIsNaN, 166 "isFinite", GlobalIsFinite, 167 "parseInt", GlobalParseInt, 168 "parseFloat", GlobalParseFloat, 169 "eval", GlobalEval, 170 "execScript", GlobalExecScript 171 )); 172} 173 174SetupGlobal(); 175 176 177// ---------------------------------------------------------------------------- 178// Boolean (first part of definition) 179 180 181%SetCode($Boolean, function(x) { 182 if (%_IsConstructCall()) { 183 %_SetValueOf(this, ToBoolean(x)); 184 } else { 185 return ToBoolean(x); 186 } 187}); 188 189%FunctionSetPrototype($Boolean, new $Boolean(false)); 190 191%SetProperty($Boolean.prototype, "constructor", $Boolean, DONT_ENUM); 192 193// ---------------------------------------------------------------------------- 194// Object 195 196$Object.prototype.constructor = $Object; 197 198// ECMA-262 - 15.2.4.2 199function ObjectToString() { 200 return "[object " + %_ClassOf(ToObject(this)) + "]"; 201} 202 203 204// ECMA-262 - 15.2.4.3 205function ObjectToLocaleString() { 206 return this.toString(); 207} 208 209 210// ECMA-262 - 15.2.4.4 211function ObjectValueOf() { 212 return ToObject(this); 213} 214 215 216// ECMA-262 - 15.2.4.5 217function ObjectHasOwnProperty(V) { 218 return %HasLocalProperty(ToObject(this), ToString(V)); 219} 220 221 222// ECMA-262 - 15.2.4.6 223function ObjectIsPrototypeOf(V) { 224 if (!IS_OBJECT(V) && !IS_FUNCTION(V)) return false; 225 return %IsInPrototypeChain(this, V); 226} 227 228 229// ECMA-262 - 15.2.4.6 230function ObjectPropertyIsEnumerable(V) { 231 if (this == null) return false; 232 if (!IS_OBJECT(this) && !IS_FUNCTION(this)) return false; 233 return %IsPropertyEnumerable(this, ToString(V)); 234} 235 236 237// Extensions for providing property getters and setters. 238function ObjectDefineGetter(name, fun) { 239 if (this == null) { 240 throw new $TypeError('Object.prototype.__defineGetter__: this is Null'); 241 } 242 if (!IS_FUNCTION(fun)) { 243 throw new $TypeError('Object.prototype.__defineGetter__: Expecting function'); 244 } 245 return %DefineAccessor(ToObject(this), ToString(name), GETTER, fun); 246} 247 248 249function ObjectLookupGetter(name) { 250 if (this == null) { 251 throw new $TypeError('Object.prototype.__lookupGetter__: this is Null'); 252 } 253 return %LookupAccessor(ToObject(this), ToString(name), GETTER); 254} 255 256 257function ObjectDefineSetter(name, fun) { 258 if (this == null) { 259 throw new $TypeError('Object.prototype.__defineSetter__: this is Null'); 260 } 261 if (!IS_FUNCTION(fun)) { 262 throw new $TypeError( 263 'Object.prototype.__defineSetter__: Expecting function'); 264 } 265 return %DefineAccessor(ToObject(this), ToString(name), SETTER, fun); 266} 267 268 269function ObjectLookupSetter(name) { 270 if (this == null) { 271 throw new $TypeError('Object.prototype.__lookupSetter__: this is Null'); 272 } 273 return %LookupAccessor(ToObject(this), ToString(name), SETTER); 274} 275 276 277function ObjectKeys(obj) { 278 if ((!IS_OBJECT(obj) || IS_NULL_OR_UNDEFINED(obj)) && !IS_FUNCTION(obj)) 279 throw MakeTypeError("obj_ctor_property_non_object", ["keys"]); 280 return %LocalKeys(obj); 281} 282 283 284// ES5 8.10.1. 285function IsAccessorDescriptor(desc) { 286 if (IS_UNDEFINED(desc)) return false; 287 return desc.hasGetter_ || desc.hasSetter_; 288} 289 290 291// ES5 8.10.2. 292function IsDataDescriptor(desc) { 293 if (IS_UNDEFINED(desc)) return false; 294 return desc.hasValue_ || desc.hasWritable_; 295} 296 297 298// ES5 8.10.3. 299function IsGenericDescriptor(desc) { 300 return !(IsAccessorDescriptor(desc) || IsDataDescriptor(desc)); 301} 302 303 304function IsInconsistentDescriptor(desc) { 305 return IsAccessorDescriptor(desc) && IsDataDescriptor(desc); 306} 307 308// ES5 8.10.4 309function FromPropertyDescriptor(desc) { 310 if(IS_UNDEFINED(desc)) return desc; 311 var obj = new $Object(); 312 if (IsDataDescriptor(desc)) { 313 obj.value = desc.getValue(); 314 obj.writable = desc.isWritable(); 315 } 316 if (IsAccessorDescriptor(desc)) { 317 obj.get = desc.getGet(); 318 obj.set = desc.getSet(); 319 } 320 obj.enumerable = desc.isEnumerable(); 321 obj.configurable = desc.isConfigurable(); 322 return obj; 323} 324 325// ES5 8.10.5. 326function ToPropertyDescriptor(obj) { 327 if (!IS_OBJECT(obj)) { 328 throw MakeTypeError("property_desc_object", [obj]); 329 } 330 var desc = new PropertyDescriptor(); 331 332 if ("enumerable" in obj) { 333 desc.setEnumerable(ToBoolean(obj.enumerable)); 334 } 335 336 337 if ("configurable" in obj) { 338 desc.setConfigurable(ToBoolean(obj.configurable)); 339 } 340 341 if ("value" in obj) { 342 desc.setValue(obj.value); 343 } 344 345 if ("writable" in obj) { 346 desc.setWritable(ToBoolean(obj.writable)); 347 } 348 349 if ("get" in obj) { 350 var get = obj.get; 351 if (!IS_UNDEFINED(get) && !IS_FUNCTION(get)) { 352 throw MakeTypeError("getter_must_be_callable", [get]); 353 } 354 desc.setGet(get); 355 } 356 357 if ("set" in obj) { 358 var set = obj.set; 359 if (!IS_UNDEFINED(set) && !IS_FUNCTION(set)) { 360 throw MakeTypeError("setter_must_be_callable", [set]); 361 } 362 desc.setSet(set); 363 } 364 365 if (IsInconsistentDescriptor(desc)) { 366 throw MakeTypeError("value_and_accessor", [obj]); 367 } 368 return desc; 369} 370 371 372function PropertyDescriptor() { 373 // Initialize here so they are all in-object and have the same map. 374 // Default values from ES5 8.6.1. 375 this.value_ = void 0; 376 this.hasValue_ = false; 377 this.writable_ = false; 378 this.hasWritable_ = false; 379 this.enumerable_ = false; 380 this.configurable_ = false; 381 this.get_ = void 0; 382 this.hasGetter_ = false; 383 this.set_ = void 0; 384 this.hasSetter_ = false; 385} 386 387 388PropertyDescriptor.prototype.setValue = function(value) { 389 this.value_ = value; 390 this.hasValue_ = true; 391} 392 393 394PropertyDescriptor.prototype.getValue = function() { 395 return this.value_; 396} 397 398 399PropertyDescriptor.prototype.setEnumerable = function(enumerable) { 400 this.enumerable_ = enumerable; 401} 402 403 404PropertyDescriptor.prototype.isEnumerable = function () { 405 return this.enumerable_; 406} 407 408 409PropertyDescriptor.prototype.setWritable = function(writable) { 410 this.writable_ = writable; 411 this.hasWritable_ = true; 412} 413 414 415PropertyDescriptor.prototype.isWritable = function() { 416 return this.writable_; 417} 418 419 420PropertyDescriptor.prototype.setConfigurable = function(configurable) { 421 this.configurable_ = configurable; 422} 423 424 425PropertyDescriptor.prototype.isConfigurable = function() { 426 return this.configurable_; 427} 428 429 430PropertyDescriptor.prototype.setGet = function(get) { 431 this.get_ = get; 432 this.hasGetter_ = true; 433} 434 435 436PropertyDescriptor.prototype.getGet = function() { 437 return this.get_; 438} 439 440 441PropertyDescriptor.prototype.setSet = function(set) { 442 this.set_ = set; 443 this.hasSetter_ = true; 444} 445 446 447PropertyDescriptor.prototype.getSet = function() { 448 return this.set_; 449} 450 451 452// ES5 section 8.12.1. 453function GetOwnProperty(obj, p) { 454 var desc = new PropertyDescriptor(); 455 456 // An array with: 457 // obj is a data property [false, value, Writeable, Enumerable, Configurable] 458 // obj is an accessor [true, Get, Set, Enumerable, Configurable] 459 var props = %GetOwnProperty(ToObject(obj), ToString(p)); 460 461 if (IS_UNDEFINED(props)) 462 return void 0; 463 464 // This is an accessor 465 if (props[0]) { 466 desc.setGet(props[1]); 467 desc.setSet(props[2]); 468 } else { 469 desc.setValue(props[1]); 470 desc.setWritable(props[2]); 471 } 472 desc.setEnumerable(props[3]); 473 desc.setConfigurable(props[4]); 474 475 return desc; 476} 477 478 479// ES5 8.12.9. This version cannot cope with the property p already 480// being present on obj. 481function DefineOwnProperty(obj, p, desc, should_throw) { 482 var flag = desc.isEnumerable() ? 0 : DONT_ENUM; 483 if (IsDataDescriptor(desc)) { 484 flag |= desc.isWritable() ? 0 : (DONT_DELETE | READ_ONLY); 485 %SetProperty(obj, p, desc.getValue(), flag); 486 } else { 487 if (IS_FUNCTION(desc.getGet())) %DefineAccessor(obj, p, GETTER, desc.getGet(), flag); 488 if (IS_FUNCTION(desc.getSet())) %DefineAccessor(obj, p, SETTER, desc.getSet(), flag); 489 } 490 return true; 491} 492 493 494// ES5 section 15.2.3.2. 495function ObjectGetPrototypeOf(obj) { 496 if ((!IS_OBJECT(obj) || IS_NULL_OR_UNDEFINED(obj)) && !IS_FUNCTION(obj)) 497 throw MakeTypeError("obj_ctor_property_non_object", ["getPrototypeOf"]); 498 return obj.__proto__; 499} 500 501 502// ES5 section 15.2.3.3 503function ObjectGetOwnPropertyDescriptor(obj, p) { 504 if ((!IS_OBJECT(obj) || IS_NULL_OR_UNDEFINED(obj)) && !IS_FUNCTION(obj)) 505 throw MakeTypeError("obj_ctor_property_non_object", ["getOwnPropertyDescriptor"]); 506 var desc = GetOwnProperty(obj, p); 507 return FromPropertyDescriptor(desc); 508} 509 510 511// ES5 section 15.2.3.4. 512function ObjectGetOwnPropertyNames(obj) { 513 if ((!IS_OBJECT(obj) || IS_NULL_OR_UNDEFINED(obj)) && !IS_FUNCTION(obj)) 514 throw MakeTypeError("obj_ctor_property_non_object", ["getOwnPropertyNames"]); 515 516 // Find all the indexed properties. 517 518 // Get the local element names. 519 var propertyNames = %GetLocalElementNames(obj); 520 521 // Get names for indexed interceptor properties. 522 if (%GetInterceptorInfo(obj) & 1) { 523 var indexedInterceptorNames = 524 %GetIndexedInterceptorElementNames(obj); 525 if (indexedInterceptorNames) { 526 propertyNames = propertyNames.concat(indexedInterceptorNames); 527 } 528 } 529 530 // Find all the named properties. 531 532 // Get the local property names. 533 propertyNames = propertyNames.concat(%GetLocalPropertyNames(obj)); 534 535 // Get names for named interceptor properties if any. 536 537 if (%GetInterceptorInfo(obj) & 2) { 538 var namedInterceptorNames = 539 %GetNamedInterceptorPropertyNames(obj); 540 if (namedInterceptorNames) { 541 propertyNames = propertyNames.concat(namedInterceptorNames); 542 } 543 } 544 545 return propertyNames; 546} 547 548 549// ES5 section 15.2.3.5. 550function ObjectCreate(proto, properties) { 551 if (!IS_OBJECT(proto) && !IS_NULL(proto)) { 552 throw MakeTypeError("proto_object_or_null", [proto]); 553 } 554 var obj = new $Object(); 555 obj.__proto__ = proto; 556 if (!IS_UNDEFINED(properties)) ObjectDefineProperties(obj, properties); 557 return obj; 558} 559 560 561// ES5 section 15.2.3.7. This version cannot cope with the properies already 562// being present on obj. Therefore it is not exposed as 563// Object.defineProperties yet. 564function ObjectDefineProperties(obj, properties) { 565 var props = ToObject(properties); 566 var key_values = []; 567 for (var key in props) { 568 if (%HasLocalProperty(props, key)) { 569 key_values.push(key); 570 var value = props[key]; 571 var desc = ToPropertyDescriptor(value); 572 key_values.push(desc); 573 } 574 } 575 for (var i = 0; i < key_values.length; i += 2) { 576 var key = key_values[i]; 577 var desc = key_values[i + 1]; 578 DefineOwnProperty(obj, key, desc, true); 579 } 580} 581 582 583%SetCode($Object, function(x) { 584 if (%_IsConstructCall()) { 585 if (x == null) return this; 586 return ToObject(x); 587 } else { 588 if (x == null) return { }; 589 return ToObject(x); 590 } 591}); 592 593 594// ---------------------------------------------------------------------------- 595 596 597function SetupObject() { 598 // Setup non-enumerable functions on the Object.prototype object. 599 InstallFunctions($Object.prototype, DONT_ENUM, $Array( 600 "toString", ObjectToString, 601 "toLocaleString", ObjectToLocaleString, 602 "valueOf", ObjectValueOf, 603 "hasOwnProperty", ObjectHasOwnProperty, 604 "isPrototypeOf", ObjectIsPrototypeOf, 605 "propertyIsEnumerable", ObjectPropertyIsEnumerable, 606 "__defineGetter__", ObjectDefineGetter, 607 "__lookupGetter__", ObjectLookupGetter, 608 "__defineSetter__", ObjectDefineSetter, 609 "__lookupSetter__", ObjectLookupSetter 610 )); 611 InstallFunctions($Object, DONT_ENUM, $Array( 612 "keys", ObjectKeys, 613 "create", ObjectCreate, 614 "getPrototypeOf", ObjectGetPrototypeOf, 615 "getOwnPropertyDescriptor", ObjectGetOwnPropertyDescriptor, 616 "getOwnPropertyNames", ObjectGetOwnPropertyNames 617 )); 618} 619 620SetupObject(); 621 622 623// ---------------------------------------------------------------------------- 624// Boolean 625 626function BooleanToString() { 627 // NOTE: Both Boolean objects and values can enter here as 628 // 'this'. This is not as dictated by ECMA-262. 629 if (!IS_BOOLEAN(this) && !IS_BOOLEAN_WRAPPER(this)) 630 throw new $TypeError('Boolean.prototype.toString is not generic'); 631 return ToString(%_ValueOf(this)); 632} 633 634 635function BooleanValueOf() { 636 // NOTE: Both Boolean objects and values can enter here as 637 // 'this'. This is not as dictated by ECMA-262. 638 if (!IS_BOOLEAN(this) && !IS_BOOLEAN_WRAPPER(this)) 639 throw new $TypeError('Boolean.prototype.valueOf is not generic'); 640 return %_ValueOf(this); 641} 642 643 644function BooleanToJSON(key) { 645 return CheckJSONPrimitive(this.valueOf()); 646} 647 648 649// ---------------------------------------------------------------------------- 650 651 652function SetupBoolean() { 653 InstallFunctions($Boolean.prototype, DONT_ENUM, $Array( 654 "toString", BooleanToString, 655 "valueOf", BooleanValueOf, 656 "toJSON", BooleanToJSON 657 )); 658} 659 660SetupBoolean(); 661 662// ---------------------------------------------------------------------------- 663// Number 664 665// Set the Number function and constructor. 666%SetCode($Number, function(x) { 667 var value = %_ArgumentsLength() == 0 ? 0 : ToNumber(x); 668 if (%_IsConstructCall()) { 669 %_SetValueOf(this, value); 670 } else { 671 return value; 672 } 673}); 674 675%FunctionSetPrototype($Number, new $Number(0)); 676 677// ECMA-262 section 15.7.4.2. 678function NumberToString(radix) { 679 // NOTE: Both Number objects and values can enter here as 680 // 'this'. This is not as dictated by ECMA-262. 681 var number = this; 682 if (!IS_NUMBER(this)) { 683 if (!IS_NUMBER_WRAPPER(this)) 684 throw new $TypeError('Number.prototype.toString is not generic'); 685 // Get the value of this number in case it's an object. 686 number = %_ValueOf(this); 687 } 688 // Fast case: Convert number in radix 10. 689 if (IS_UNDEFINED(radix) || radix === 10) { 690 return ToString(number); 691 } 692 693 // Convert the radix to an integer and check the range. 694 radix = TO_INTEGER(radix); 695 if (radix < 2 || radix > 36) { 696 throw new $RangeError('toString() radix argument must be between 2 and 36'); 697 } 698 // Convert the number to a string in the given radix. 699 return %NumberToRadixString(number, radix); 700} 701 702 703// ECMA-262 section 15.7.4.3 704function NumberToLocaleString() { 705 return this.toString(); 706} 707 708 709// ECMA-262 section 15.7.4.4 710function NumberValueOf() { 711 // NOTE: Both Number objects and values can enter here as 712 // 'this'. This is not as dictated by ECMA-262. 713 if (!IS_NUMBER(this) && !IS_NUMBER_WRAPPER(this)) 714 throw new $TypeError('Number.prototype.valueOf is not generic'); 715 return %_ValueOf(this); 716} 717 718 719// ECMA-262 section 15.7.4.5 720function NumberToFixed(fractionDigits) { 721 var f = TO_INTEGER(fractionDigits); 722 if (f < 0 || f > 20) { 723 throw new $RangeError("toFixed() digits argument must be between 0 and 20"); 724 } 725 var x = ToNumber(this); 726 return %NumberToFixed(x, f); 727} 728 729 730// ECMA-262 section 15.7.4.6 731function NumberToExponential(fractionDigits) { 732 var f = -1; 733 if (!IS_UNDEFINED(fractionDigits)) { 734 f = TO_INTEGER(fractionDigits); 735 if (f < 0 || f > 20) { 736 throw new $RangeError("toExponential() argument must be between 0 and 20"); 737 } 738 } 739 var x = ToNumber(this); 740 return %NumberToExponential(x, f); 741} 742 743 744// ECMA-262 section 15.7.4.7 745function NumberToPrecision(precision) { 746 if (IS_UNDEFINED(precision)) return ToString(%_ValueOf(this)); 747 var p = TO_INTEGER(precision); 748 if (p < 1 || p > 21) { 749 throw new $RangeError("toPrecision() argument must be between 1 and 21"); 750 } 751 var x = ToNumber(this); 752 return %NumberToPrecision(x, p); 753} 754 755 756function CheckJSONPrimitive(val) { 757 if (!IsPrimitive(val)) 758 throw MakeTypeError('result_not_primitive', ['toJSON', val]); 759 return val; 760} 761 762 763function NumberToJSON(key) { 764 return CheckJSONPrimitive(this.valueOf()); 765} 766 767 768// ---------------------------------------------------------------------------- 769 770function SetupNumber() { 771 %OptimizeObjectForAddingMultipleProperties($Number.prototype, 8); 772 // Setup the constructor property on the Number prototype object. 773 %SetProperty($Number.prototype, "constructor", $Number, DONT_ENUM); 774 775 %OptimizeObjectForAddingMultipleProperties($Number, 5); 776 // ECMA-262 section 15.7.3.1. 777 %SetProperty($Number, 778 "MAX_VALUE", 779 1.7976931348623157e+308, 780 DONT_ENUM | DONT_DELETE | READ_ONLY); 781 782 // ECMA-262 section 15.7.3.2. 783 %SetProperty($Number, "MIN_VALUE", 5e-324, DONT_ENUM | DONT_DELETE | READ_ONLY); 784 785 // ECMA-262 section 15.7.3.3. 786 %SetProperty($Number, "NaN", $NaN, DONT_ENUM | DONT_DELETE | READ_ONLY); 787 788 // ECMA-262 section 15.7.3.4. 789 %SetProperty($Number, 790 "NEGATIVE_INFINITY", 791 -1/0, 792 DONT_ENUM | DONT_DELETE | READ_ONLY); 793 794 // ECMA-262 section 15.7.3.5. 795 %SetProperty($Number, 796 "POSITIVE_INFINITY", 797 1/0, 798 DONT_ENUM | DONT_DELETE | READ_ONLY); 799 %TransformToFastProperties($Number); 800 801 // Setup non-enumerable functions on the Number prototype object. 802 InstallFunctions($Number.prototype, DONT_ENUM, $Array( 803 "toString", NumberToString, 804 "toLocaleString", NumberToLocaleString, 805 "valueOf", NumberValueOf, 806 "toFixed", NumberToFixed, 807 "toExponential", NumberToExponential, 808 "toPrecision", NumberToPrecision, 809 "toJSON", NumberToJSON 810 )); 811} 812 813SetupNumber(); 814 815 816 817// ---------------------------------------------------------------------------- 818// Function 819 820$Function.prototype.constructor = $Function; 821 822function FunctionSourceString(func) { 823 if (!IS_FUNCTION(func)) { 824 throw new $TypeError('Function.prototype.toString is not generic'); 825 } 826 827 var source = %FunctionGetSourceCode(func); 828 if (!IS_STRING(source) || %FunctionIsBuiltin(func)) { 829 var name = %FunctionGetName(func); 830 if (name) { 831 // Mimic what KJS does. 832 return 'function ' + name + '() { [native code] }'; 833 } else { 834 return 'function () { [native code] }'; 835 } 836 } 837 838 var name = %FunctionGetName(func); 839 return 'function ' + name + source; 840} 841 842 843function FunctionToString() { 844 return FunctionSourceString(this); 845} 846 847 848function NewFunction(arg1) { // length == 1 849 var n = %_ArgumentsLength(); 850 var p = ''; 851 if (n > 1) { 852 p = new $Array(n - 1); 853 // Explicitly convert all parameters to strings. 854 // Array.prototype.join replaces null with empty strings which is 855 // not appropriate. 856 for (var i = 0; i < n - 1; i++) p[i] = ToString(%_Arguments(i)); 857 p = p.join(','); 858 // If the formal parameters string include ) - an illegal 859 // character - it may make the combined function expression 860 // compile. We avoid this problem by checking for this early on. 861 if (p.indexOf(')') != -1) throw MakeSyntaxError('unable_to_parse',[]); 862 } 863 var body = (n > 0) ? ToString(%_Arguments(n - 1)) : ''; 864 var source = '(function(' + p + ') {\n' + body + '\n})'; 865 866 // The call to SetNewFunctionAttributes will ensure the prototype 867 // property of the resulting function is enumerable (ECMA262, 15.3.5.2). 868 var f = %CompileString(source, false)(); 869 %FunctionSetName(f, "anonymous"); 870 return %SetNewFunctionAttributes(f); 871} 872 873%SetCode($Function, NewFunction); 874 875// ---------------------------------------------------------------------------- 876 877function SetupFunction() { 878 InstallFunctions($Function.prototype, DONT_ENUM, $Array( 879 "toString", FunctionToString 880 )); 881} 882 883SetupFunction(); 884