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 %ToFastProperties(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 if ("configurable" in obj) { 337 desc.setConfigurable(ToBoolean(obj.configurable)); 338 } 339 340 if ("value" in obj) { 341 desc.setValue(obj.value); 342 } 343 344 if ("writable" in obj) { 345 desc.setWritable(ToBoolean(obj.writable)); 346 } 347 348 if ("get" in obj) { 349 var get = obj.get; 350 if (!IS_UNDEFINED(get) && !IS_FUNCTION(get)) { 351 throw MakeTypeError("getter_must_be_callable", [get]); 352 } 353 desc.setGet(get); 354 } 355 356 if ("set" in obj) { 357 var set = obj.set; 358 if (!IS_UNDEFINED(set) && !IS_FUNCTION(set)) { 359 throw MakeTypeError("setter_must_be_callable", [set]); 360 } 361 desc.setSet(set); 362 } 363 364 if (IsInconsistentDescriptor(desc)) { 365 throw MakeTypeError("value_and_accessor", [obj]); 366 } 367 return desc; 368} 369 370 371function PropertyDescriptor() { 372 // Initialize here so they are all in-object and have the same map. 373 // Default values from ES5 8.6.1. 374 this.value_ = void 0; 375 this.hasValue_ = false; 376 this.writable_ = false; 377 this.hasWritable_ = false; 378 this.enumerable_ = false; 379 this.hasEnumerable_ = false; 380 this.configurable_ = false; 381 this.hasConfigurable_ = false; 382 this.get_ = void 0; 383 this.hasGetter_ = false; 384 this.set_ = void 0; 385 this.hasSetter_ = false; 386} 387 388 389PropertyDescriptor.prototype.setValue = function(value) { 390 this.value_ = value; 391 this.hasValue_ = true; 392} 393 394 395PropertyDescriptor.prototype.getValue = function() { 396 return this.value_; 397} 398 399 400PropertyDescriptor.prototype.hasValue = function() { 401 return this.hasValue_; 402} 403 404 405PropertyDescriptor.prototype.setEnumerable = function(enumerable) { 406 this.enumerable_ = enumerable; 407 this.hasEnumerable_ = true; 408} 409 410 411PropertyDescriptor.prototype.isEnumerable = function () { 412 return this.enumerable_; 413} 414 415 416PropertyDescriptor.prototype.hasEnumerable = function() { 417 return this.hasEnumerable_; 418} 419 420 421PropertyDescriptor.prototype.setWritable = function(writable) { 422 this.writable_ = writable; 423 this.hasWritable_ = true; 424} 425 426 427PropertyDescriptor.prototype.isWritable = function() { 428 return this.writable_; 429} 430 431 432PropertyDescriptor.prototype.setConfigurable = function(configurable) { 433 this.configurable_ = configurable; 434 this.hasConfigurable_ = true; 435} 436 437 438PropertyDescriptor.prototype.hasConfigurable = function() { 439 return this.hasConfigurable_; 440} 441 442 443PropertyDescriptor.prototype.isConfigurable = function() { 444 return this.configurable_; 445} 446 447 448PropertyDescriptor.prototype.setGet = function(get) { 449 this.get_ = get; 450 this.hasGetter_ = true; 451} 452 453 454PropertyDescriptor.prototype.getGet = function() { 455 return this.get_; 456} 457 458 459PropertyDescriptor.prototype.hasGetter = function() { 460 return this.hasGetter_; 461} 462 463 464PropertyDescriptor.prototype.setSet = function(set) { 465 this.set_ = set; 466 this.hasSetter_ = true; 467} 468 469 470PropertyDescriptor.prototype.getSet = function() { 471 return this.set_; 472} 473 474 475PropertyDescriptor.prototype.hasSetter = function() { 476 return this.hasSetter_; 477} 478 479 480 481// ES5 section 8.12.1. 482function GetOwnProperty(obj, p) { 483 var desc = new PropertyDescriptor(); 484 485 // An array with: 486 // obj is a data property [false, value, Writeable, Enumerable, Configurable] 487 // obj is an accessor [true, Get, Set, Enumerable, Configurable] 488 var props = %GetOwnProperty(ToObject(obj), ToString(p)); 489 490 if (IS_UNDEFINED(props)) return void 0; 491 492 // This is an accessor 493 if (props[0]) { 494 desc.setGet(props[1]); 495 desc.setSet(props[2]); 496 } else { 497 desc.setValue(props[1]); 498 desc.setWritable(props[2]); 499 } 500 desc.setEnumerable(props[3]); 501 desc.setConfigurable(props[4]); 502 503 return desc; 504} 505 506 507// ES5 section 8.12.2. 508function GetProperty(obj, p) { 509 var prop = GetOwnProperty(obj); 510 if (!IS_UNDEFINED(prop)) return prop; 511 var proto = obj.__proto__; 512 if (IS_NULL(proto)) return void 0; 513 return GetProperty(proto, p); 514} 515 516 517// ES5 section 8.12.6 518function HasProperty(obj, p) { 519 var desc = GetProperty(obj, p); 520 return IS_UNDEFINED(desc) ? false : true; 521} 522 523 524// ES5 8.12.9. 525function DefineOwnProperty(obj, p, desc, should_throw) { 526 var current = GetOwnProperty(obj, p); 527 var extensible = %IsExtensible(ToObject(obj)); 528 529 // Error handling according to spec. 530 // Step 3 531 if (IS_UNDEFINED(current) && !extensible) 532 throw MakeTypeError("define_disallowed", ["defineProperty"]); 533 534 if (!IS_UNDEFINED(current) && !current.isConfigurable()) { 535 // Step 7 536 if (desc.isConfigurable() || desc.isEnumerable() != current.isEnumerable()) 537 throw MakeTypeError("redefine_disallowed", ["defineProperty"]); 538 // Step 9 539 if (IsDataDescriptor(current) != IsDataDescriptor(desc)) 540 throw MakeTypeError("redefine_disallowed", ["defineProperty"]); 541 // Step 10 542 if (IsDataDescriptor(current) && IsDataDescriptor(desc)) { 543 if (!current.isWritable() && desc.isWritable()) 544 throw MakeTypeError("redefine_disallowed", ["defineProperty"]); 545 if (!current.isWritable() && desc.hasValue() && 546 !SameValue(desc.getValue(), current.getValue())) { 547 throw MakeTypeError("redefine_disallowed", ["defineProperty"]); 548 } 549 } 550 // Step 11 551 if (IsAccessorDescriptor(desc) && IsAccessorDescriptor(current)) { 552 if (desc.hasSetter() && !SameValue(desc.getSet(), current.getSet())){ 553 throw MakeTypeError("redefine_disallowed", ["defineProperty"]); 554 } 555 if (desc.hasGetter() && !SameValue(desc.getGet(),current.getGet())) 556 throw MakeTypeError("redefine_disallowed", ["defineProperty"]); 557 } 558 } 559 560 // Send flags - enumerable and configurable are common - writable is 561 // only send to the data descriptor. 562 // Take special care if enumerable and configurable is not defined on 563 // desc (we need to preserve the existing values from current). 564 var flag = NONE; 565 if (desc.hasEnumerable()) { 566 flag |= desc.isEnumerable() ? 0 : DONT_ENUM; 567 } else if (!IS_UNDEFINED(current)) { 568 flag |= current.isEnumerable() ? 0 : DONT_ENUM; 569 } else { 570 flag |= DONT_ENUM; 571 } 572 573 if (desc.hasConfigurable()) { 574 flag |= desc.isConfigurable() ? 0 : DONT_DELETE; 575 } else if (!IS_UNDEFINED(current)) { 576 flag |= current.isConfigurable() ? 0 : DONT_DELETE; 577 } else 578 flag |= DONT_DELETE; 579 580 if (IsDataDescriptor(desc) || IsGenericDescriptor(desc)) { 581 flag |= desc.isWritable() ? 0 : READ_ONLY; 582 %DefineOrRedefineDataProperty(obj, p, desc.getValue(), flag); 583 } else { 584 if (desc.hasGetter() && IS_FUNCTION(desc.getGet())) { 585 %DefineOrRedefineAccessorProperty(obj, p, GETTER, desc.getGet(), flag); 586 } 587 if (desc.hasSetter() && IS_FUNCTION(desc.getSet())) { 588 %DefineOrRedefineAccessorProperty(obj, p, SETTER, desc.getSet(), flag); 589 } 590 } 591 return true; 592} 593 594 595// ES5 section 15.2.3.2. 596function ObjectGetPrototypeOf(obj) { 597 if ((!IS_OBJECT(obj) || IS_NULL_OR_UNDEFINED(obj)) && !IS_FUNCTION(obj)) 598 throw MakeTypeError("obj_ctor_property_non_object", ["getPrototypeOf"]); 599 return obj.__proto__; 600} 601 602 603// ES5 section 15.2.3.3 604function ObjectGetOwnPropertyDescriptor(obj, p) { 605 if ((!IS_OBJECT(obj) || IS_NULL_OR_UNDEFINED(obj)) && !IS_FUNCTION(obj)) 606 throw MakeTypeError("obj_ctor_property_non_object", ["getOwnPropertyDescriptor"]); 607 var desc = GetOwnProperty(obj, p); 608 return FromPropertyDescriptor(desc); 609} 610 611 612// ES5 section 15.2.3.4. 613function ObjectGetOwnPropertyNames(obj) { 614 if ((!IS_OBJECT(obj) || IS_NULL_OR_UNDEFINED(obj)) && !IS_FUNCTION(obj)) 615 throw MakeTypeError("obj_ctor_property_non_object", ["getOwnPropertyNames"]); 616 617 // Find all the indexed properties. 618 619 // Get the local element names. 620 var propertyNames = %GetLocalElementNames(obj); 621 622 // Get names for indexed interceptor properties. 623 if (%GetInterceptorInfo(obj) & 1) { 624 var indexedInterceptorNames = 625 %GetIndexedInterceptorElementNames(obj); 626 if (indexedInterceptorNames) 627 propertyNames = propertyNames.concat(indexedInterceptorNames); 628 } 629 630 // Find all the named properties. 631 632 // Get the local property names. 633 propertyNames = propertyNames.concat(%GetLocalPropertyNames(obj)); 634 635 // Get names for named interceptor properties if any. 636 637 if (%GetInterceptorInfo(obj) & 2) { 638 var namedInterceptorNames = 639 %GetNamedInterceptorPropertyNames(obj); 640 if (namedInterceptorNames) { 641 propertyNames = propertyNames.concat(namedInterceptorNames); 642 } 643 } 644 645 // Property names are expected to be strings. 646 for (var i = 0; i < propertyNames.length; ++i) 647 propertyNames[i] = ToString(propertyNames[i]); 648 649 return propertyNames; 650} 651 652 653// ES5 section 15.2.3.5. 654function ObjectCreate(proto, properties) { 655 if (!IS_OBJECT(proto) && !IS_NULL(proto)) { 656 throw MakeTypeError("proto_object_or_null", [proto]); 657 } 658 var obj = new $Object(); 659 obj.__proto__ = proto; 660 if (!IS_UNDEFINED(properties)) ObjectDefineProperties(obj, properties); 661 return obj; 662} 663 664 665// ES5 section 15.2.3.6. 666function ObjectDefineProperty(obj, p, attributes) { 667 if ((!IS_OBJECT(obj) || IS_NULL_OR_UNDEFINED(obj)) && !IS_FUNCTION(obj)) 668 throw MakeTypeError("obj_ctor_property_non_object", ["defineProperty"]); 669 var name = ToString(p); 670 var desc = ToPropertyDescriptor(attributes); 671 DefineOwnProperty(obj, name, desc, true); 672 return obj; 673} 674 675 676// ES5 section 15.2.3.7. 677function ObjectDefineProperties(obj, properties) { 678 if ((!IS_OBJECT(obj) || IS_NULL_OR_UNDEFINED(obj)) && !IS_FUNCTION(obj)) 679 throw MakeTypeError("obj_ctor_property_non_object", ["defineProperties"]); 680 var props = ToObject(properties); 681 var key_values = []; 682 for (var key in props) { 683 if (%HasLocalProperty(props, key)) { 684 key_values.push(key); 685 var value = props[key]; 686 var desc = ToPropertyDescriptor(value); 687 key_values.push(desc); 688 } 689 } 690 for (var i = 0; i < key_values.length; i += 2) { 691 var key = key_values[i]; 692 var desc = key_values[i + 1]; 693 DefineOwnProperty(obj, key, desc, true); 694 } 695 return obj; 696} 697 698 699%SetCode($Object, function(x) { 700 if (%_IsConstructCall()) { 701 if (x == null) return this; 702 return ToObject(x); 703 } else { 704 if (x == null) return { }; 705 return ToObject(x); 706 } 707}); 708 709 710// ---------------------------------------------------------------------------- 711 712 713function SetupObject() { 714 // Setup non-enumerable functions on the Object.prototype object. 715 InstallFunctions($Object.prototype, DONT_ENUM, $Array( 716 "toString", ObjectToString, 717 "toLocaleString", ObjectToLocaleString, 718 "valueOf", ObjectValueOf, 719 "hasOwnProperty", ObjectHasOwnProperty, 720 "isPrototypeOf", ObjectIsPrototypeOf, 721 "propertyIsEnumerable", ObjectPropertyIsEnumerable, 722 "__defineGetter__", ObjectDefineGetter, 723 "__lookupGetter__", ObjectLookupGetter, 724 "__defineSetter__", ObjectDefineSetter, 725 "__lookupSetter__", ObjectLookupSetter 726 )); 727 InstallFunctions($Object, DONT_ENUM, $Array( 728 "keys", ObjectKeys, 729 "create", ObjectCreate, 730 "defineProperty", ObjectDefineProperty, 731 "defineProperties", ObjectDefineProperties, 732 "getPrototypeOf", ObjectGetPrototypeOf, 733 "getOwnPropertyDescriptor", ObjectGetOwnPropertyDescriptor, 734 "getOwnPropertyNames", ObjectGetOwnPropertyNames 735 )); 736} 737 738SetupObject(); 739 740 741// ---------------------------------------------------------------------------- 742// Boolean 743 744function BooleanToString() { 745 // NOTE: Both Boolean objects and values can enter here as 746 // 'this'. This is not as dictated by ECMA-262. 747 if (!IS_BOOLEAN(this) && !IS_BOOLEAN_WRAPPER(this)) 748 throw new $TypeError('Boolean.prototype.toString is not generic'); 749 return ToString(%_ValueOf(this)); 750} 751 752 753function BooleanValueOf() { 754 // NOTE: Both Boolean objects and values can enter here as 755 // 'this'. This is not as dictated by ECMA-262. 756 if (!IS_BOOLEAN(this) && !IS_BOOLEAN_WRAPPER(this)) 757 throw new $TypeError('Boolean.prototype.valueOf is not generic'); 758 return %_ValueOf(this); 759} 760 761 762function BooleanToJSON(key) { 763 return CheckJSONPrimitive(this.valueOf()); 764} 765 766 767// ---------------------------------------------------------------------------- 768 769 770function SetupBoolean() { 771 InstallFunctions($Boolean.prototype, DONT_ENUM, $Array( 772 "toString", BooleanToString, 773 "valueOf", BooleanValueOf, 774 "toJSON", BooleanToJSON 775 )); 776} 777 778SetupBoolean(); 779 780// ---------------------------------------------------------------------------- 781// Number 782 783// Set the Number function and constructor. 784%SetCode($Number, function(x) { 785 var value = %_ArgumentsLength() == 0 ? 0 : ToNumber(x); 786 if (%_IsConstructCall()) { 787 %_SetValueOf(this, value); 788 } else { 789 return value; 790 } 791}); 792 793%FunctionSetPrototype($Number, new $Number(0)); 794 795// ECMA-262 section 15.7.4.2. 796function NumberToString(radix) { 797 // NOTE: Both Number objects and values can enter here as 798 // 'this'. This is not as dictated by ECMA-262. 799 var number = this; 800 if (!IS_NUMBER(this)) { 801 if (!IS_NUMBER_WRAPPER(this)) 802 throw new $TypeError('Number.prototype.toString is not generic'); 803 // Get the value of this number in case it's an object. 804 number = %_ValueOf(this); 805 } 806 // Fast case: Convert number in radix 10. 807 if (IS_UNDEFINED(radix) || radix === 10) { 808 return ToString(number); 809 } 810 811 // Convert the radix to an integer and check the range. 812 radix = TO_INTEGER(radix); 813 if (radix < 2 || radix > 36) { 814 throw new $RangeError('toString() radix argument must be between 2 and 36'); 815 } 816 // Convert the number to a string in the given radix. 817 return %NumberToRadixString(number, radix); 818} 819 820 821// ECMA-262 section 15.7.4.3 822function NumberToLocaleString() { 823 return this.toString(); 824} 825 826 827// ECMA-262 section 15.7.4.4 828function NumberValueOf() { 829 // NOTE: Both Number objects and values can enter here as 830 // 'this'. This is not as dictated by ECMA-262. 831 if (!IS_NUMBER(this) && !IS_NUMBER_WRAPPER(this)) 832 throw new $TypeError('Number.prototype.valueOf is not generic'); 833 return %_ValueOf(this); 834} 835 836 837// ECMA-262 section 15.7.4.5 838function NumberToFixed(fractionDigits) { 839 var f = TO_INTEGER(fractionDigits); 840 if (f < 0 || f > 20) { 841 throw new $RangeError("toFixed() digits argument must be between 0 and 20"); 842 } 843 var x = ToNumber(this); 844 return %NumberToFixed(x, f); 845} 846 847 848// ECMA-262 section 15.7.4.6 849function NumberToExponential(fractionDigits) { 850 var f = -1; 851 if (!IS_UNDEFINED(fractionDigits)) { 852 f = TO_INTEGER(fractionDigits); 853 if (f < 0 || f > 20) { 854 throw new $RangeError("toExponential() argument must be between 0 and 20"); 855 } 856 } 857 var x = ToNumber(this); 858 return %NumberToExponential(x, f); 859} 860 861 862// ECMA-262 section 15.7.4.7 863function NumberToPrecision(precision) { 864 if (IS_UNDEFINED(precision)) return ToString(%_ValueOf(this)); 865 var p = TO_INTEGER(precision); 866 if (p < 1 || p > 21) { 867 throw new $RangeError("toPrecision() argument must be between 1 and 21"); 868 } 869 var x = ToNumber(this); 870 return %NumberToPrecision(x, p); 871} 872 873 874function CheckJSONPrimitive(val) { 875 if (!IsPrimitive(val)) 876 throw MakeTypeError('result_not_primitive', ['toJSON', val]); 877 return val; 878} 879 880 881function NumberToJSON(key) { 882 return CheckJSONPrimitive(this.valueOf()); 883} 884 885 886// ---------------------------------------------------------------------------- 887 888function SetupNumber() { 889 %OptimizeObjectForAddingMultipleProperties($Number.prototype, 8); 890 // Setup the constructor property on the Number prototype object. 891 %SetProperty($Number.prototype, "constructor", $Number, DONT_ENUM); 892 893 %OptimizeObjectForAddingMultipleProperties($Number, 5); 894 // ECMA-262 section 15.7.3.1. 895 %SetProperty($Number, 896 "MAX_VALUE", 897 1.7976931348623157e+308, 898 DONT_ENUM | DONT_DELETE | READ_ONLY); 899 900 // ECMA-262 section 15.7.3.2. 901 %SetProperty($Number, "MIN_VALUE", 5e-324, DONT_ENUM | DONT_DELETE | READ_ONLY); 902 903 // ECMA-262 section 15.7.3.3. 904 %SetProperty($Number, "NaN", $NaN, DONT_ENUM | DONT_DELETE | READ_ONLY); 905 906 // ECMA-262 section 15.7.3.4. 907 %SetProperty($Number, 908 "NEGATIVE_INFINITY", 909 -1/0, 910 DONT_ENUM | DONT_DELETE | READ_ONLY); 911 912 // ECMA-262 section 15.7.3.5. 913 %SetProperty($Number, 914 "POSITIVE_INFINITY", 915 1/0, 916 DONT_ENUM | DONT_DELETE | READ_ONLY); 917 %ToFastProperties($Number); 918 919 // Setup non-enumerable functions on the Number prototype object. 920 InstallFunctions($Number.prototype, DONT_ENUM, $Array( 921 "toString", NumberToString, 922 "toLocaleString", NumberToLocaleString, 923 "valueOf", NumberValueOf, 924 "toFixed", NumberToFixed, 925 "toExponential", NumberToExponential, 926 "toPrecision", NumberToPrecision, 927 "toJSON", NumberToJSON 928 )); 929} 930 931SetupNumber(); 932 933 934 935// ---------------------------------------------------------------------------- 936// Function 937 938$Function.prototype.constructor = $Function; 939 940function FunctionSourceString(func) { 941 if (!IS_FUNCTION(func)) { 942 throw new $TypeError('Function.prototype.toString is not generic'); 943 } 944 945 var source = %FunctionGetSourceCode(func); 946 if (!IS_STRING(source) || %FunctionIsBuiltin(func)) { 947 var name = %FunctionGetName(func); 948 if (name) { 949 // Mimic what KJS does. 950 return 'function ' + name + '() { [native code] }'; 951 } else { 952 return 'function () { [native code] }'; 953 } 954 } 955 956 var name = %FunctionGetName(func); 957 return 'function ' + name + source; 958} 959 960 961function FunctionToString() { 962 return FunctionSourceString(this); 963} 964 965 966function NewFunction(arg1) { // length == 1 967 var n = %_ArgumentsLength(); 968 var p = ''; 969 if (n > 1) { 970 p = new $Array(n - 1); 971 // Explicitly convert all parameters to strings. 972 // Array.prototype.join replaces null with empty strings which is 973 // not appropriate. 974 for (var i = 0; i < n - 1; i++) p[i] = ToString(%_Arguments(i)); 975 p = p.join(','); 976 // If the formal parameters string include ) - an illegal 977 // character - it may make the combined function expression 978 // compile. We avoid this problem by checking for this early on. 979 if (p.indexOf(')') != -1) throw MakeSyntaxError('unable_to_parse',[]); 980 } 981 var body = (n > 0) ? ToString(%_Arguments(n - 1)) : ''; 982 var source = '(function(' + p + ') {\n' + body + '\n})'; 983 984 // The call to SetNewFunctionAttributes will ensure the prototype 985 // property of the resulting function is enumerable (ECMA262, 15.3.5.2). 986 var f = %CompileString(source, false)(); 987 %FunctionSetName(f, "anonymous"); 988 return %SetNewFunctionAttributes(f); 989} 990 991%SetCode($Function, NewFunction); 992 993// ---------------------------------------------------------------------------- 994 995function SetupFunction() { 996 InstallFunctions($Function.prototype, DONT_ENUM, $Array( 997 "toString", FunctionToString 998 )); 999} 1000 1001SetupFunction(); 1002