1// Copyright 2012 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// var $Object = global.Object; 32// var $Boolean = global.Boolean; 33// var $Number = global.Number; 34// var $Function = global.Function; 35// var $Array = global.Array; 36// var $NaN = 0/0; 37// 38// in math.js: 39// var $floor = MathFloor 40 41var $isNaN = GlobalIsNaN; 42var $isFinite = GlobalIsFinite; 43 44// ---------------------------------------------------------------------------- 45 46 47// Helper function used to install functions on objects. 48function InstallFunctions(object, attributes, functions) { 49 if (functions.length >= 8) { 50 %OptimizeObjectForAddingMultipleProperties(object, functions.length >> 1); 51 } 52 for (var i = 0; i < functions.length; i += 2) { 53 var key = functions[i]; 54 var f = functions[i + 1]; 55 %FunctionSetName(f, key); 56 %FunctionRemovePrototype(f); 57 %SetProperty(object, key, f, attributes); 58 %SetNativeFlag(f); 59 } 60 %ToFastProperties(object); 61} 62 63// Prevents changes to the prototype of a built-infunction. 64// The "prototype" property of the function object is made non-configurable, 65// and the prototype object is made non-extensible. The latter prevents 66// changing the __proto__ property. 67function SetUpLockedPrototype(constructor, fields, methods) { 68 %CheckIsBootstrapping(); 69 var prototype = constructor.prototype; 70 // Install functions first, because this function is used to initialize 71 // PropertyDescriptor itself. 72 var property_count = (methods.length >> 1) + (fields ? fields.length : 0); 73 if (property_count >= 4) { 74 %OptimizeObjectForAddingMultipleProperties(prototype, property_count); 75 } 76 if (fields) { 77 for (var i = 0; i < fields.length; i++) { 78 %SetProperty(prototype, fields[i], void 0, DONT_ENUM | DONT_DELETE); 79 } 80 } 81 for (var i = 0; i < methods.length; i += 2) { 82 var key = methods[i]; 83 var f = methods[i + 1]; 84 %SetProperty(prototype, key, f, DONT_ENUM | DONT_DELETE | READ_ONLY); 85 %SetNativeFlag(f); 86 } 87 prototype.__proto__ = null; 88 %ToFastProperties(prototype); 89} 90 91 92// ---------------------------------------------------------------------------- 93 94 95// ECMA 262 - 15.1.4 96function GlobalIsNaN(number) { 97 if (!IS_NUMBER(number)) number = NonNumberToNumber(number); 98 return NUMBER_IS_NAN(number); 99} 100 101 102// ECMA 262 - 15.1.5 103function GlobalIsFinite(number) { 104 if (!IS_NUMBER(number)) number = NonNumberToNumber(number); 105 return NUMBER_IS_FINITE(number); 106} 107 108 109// ECMA-262 - 15.1.2.2 110function GlobalParseInt(string, radix) { 111 if (IS_UNDEFINED(radix) || radix === 10 || radix === 0) { 112 // Some people use parseInt instead of Math.floor. This 113 // optimization makes parseInt on a Smi 12 times faster (60ns 114 // vs 800ns). The following optimization makes parseInt on a 115 // non-Smi number 9 times faster (230ns vs 2070ns). Together 116 // they make parseInt on a string 1.4% slower (274ns vs 270ns). 117 if (%_IsSmi(string)) return string; 118 if (IS_NUMBER(string) && 119 ((0.01 < string && string < 1e9) || 120 (-1e9 < string && string < -0.01))) { 121 // Truncate number. 122 return string | 0; 123 } 124 string = TO_STRING_INLINE(string); 125 radix = radix | 0; 126 } else { 127 // The spec says ToString should be evaluated before ToInt32. 128 string = TO_STRING_INLINE(string); 129 radix = TO_INT32(radix); 130 if (!(radix == 0 || (2 <= radix && radix <= 36))) { 131 return $NaN; 132 } 133 } 134 135 if (%_HasCachedArrayIndex(string) && 136 (radix == 0 || radix == 10)) { 137 return %_GetCachedArrayIndex(string); 138 } 139 return %StringParseInt(string, radix); 140} 141 142 143// ECMA-262 - 15.1.2.3 144function GlobalParseFloat(string) { 145 string = TO_STRING_INLINE(string); 146 if (%_HasCachedArrayIndex(string)) return %_GetCachedArrayIndex(string); 147 return %StringParseFloat(string); 148} 149 150 151function GlobalEval(x) { 152 if (!IS_STRING(x)) return x; 153 154 var global_receiver = %GlobalReceiver(global); 155 var global_is_detached = (global === global_receiver); 156 157 // For consistency with JSC we require the global object passed to 158 // eval to be the global object from which 'eval' originated. This 159 // is not mandated by the spec. 160 // We only throw if the global has been detached, since we need the 161 // receiver as this-value for the call. 162 if (global_is_detached) { 163 throw new $EvalError('The "this" value passed to eval must ' + 164 'be the global object from which eval originated'); 165 } 166 167 var f = %CompileString(x); 168 if (!IS_FUNCTION(f)) return f; 169 170 return %_CallFunction(global_receiver, f); 171} 172 173 174// ---------------------------------------------------------------------------- 175 176// Set up global object. 177function SetUpGlobal() { 178 %CheckIsBootstrapping(); 179 // ECMA 262 - 15.1.1.1. 180 %SetProperty(global, "NaN", $NaN, DONT_ENUM | DONT_DELETE | READ_ONLY); 181 182 // ECMA-262 - 15.1.1.2. 183 %SetProperty(global, "Infinity", 1/0, DONT_ENUM | DONT_DELETE | READ_ONLY); 184 185 // ECMA-262 - 15.1.1.3. 186 %SetProperty(global, "undefined", void 0, 187 DONT_ENUM | DONT_DELETE | READ_ONLY); 188 189 // Set up non-enumerable function on the global object. 190 InstallFunctions(global, DONT_ENUM, $Array( 191 "isNaN", GlobalIsNaN, 192 "isFinite", GlobalIsFinite, 193 "parseInt", GlobalParseInt, 194 "parseFloat", GlobalParseFloat, 195 "eval", GlobalEval 196 )); 197} 198 199SetUpGlobal(); 200 201// ---------------------------------------------------------------------------- 202// Boolean (first part of definition) 203 204 205%SetCode($Boolean, function(x) { 206 if (%_IsConstructCall()) { 207 %_SetValueOf(this, ToBoolean(x)); 208 } else { 209 return ToBoolean(x); 210 } 211}); 212 213%FunctionSetPrototype($Boolean, new $Boolean(false)); 214 215%SetProperty($Boolean.prototype, "constructor", $Boolean, DONT_ENUM); 216 217// ---------------------------------------------------------------------------- 218// Object 219 220$Object.prototype.constructor = $Object; 221 222// ECMA-262 - 15.2.4.2 223function ObjectToString() { 224 if (IS_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { 225 return '[object Undefined]'; 226 } 227 if (IS_NULL(this)) return '[object Null]'; 228 return "[object " + %_ClassOf(ToObject(this)) + "]"; 229} 230 231 232// ECMA-262 - 15.2.4.3 233function ObjectToLocaleString() { 234 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { 235 throw MakeTypeError("called_on_null_or_undefined", 236 ["Object.prototype.toLocaleString"]); 237 } 238 return this.toString(); 239} 240 241 242// ECMA-262 - 15.2.4.4 243function ObjectValueOf() { 244 return ToObject(this); 245} 246 247 248// ECMA-262 - 15.2.4.5 249function ObjectHasOwnProperty(V) { 250 if (%IsJSProxy(this)) { 251 var handler = %GetHandler(this); 252 return CallTrap1(handler, "hasOwn", DerivedHasOwnTrap, TO_STRING_INLINE(V)); 253 } 254 return %HasLocalProperty(TO_OBJECT_INLINE(this), TO_STRING_INLINE(V)); 255} 256 257 258// ECMA-262 - 15.2.4.6 259function ObjectIsPrototypeOf(V) { 260 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { 261 throw MakeTypeError("called_on_null_or_undefined", 262 ["Object.prototype.isPrototypeOf"]); 263 } 264 if (!IS_SPEC_OBJECT(V)) return false; 265 return %IsInPrototypeChain(this, V); 266} 267 268 269// ECMA-262 - 15.2.4.6 270function ObjectPropertyIsEnumerable(V) { 271 var P = ToString(V); 272 if (%IsJSProxy(this)) { 273 var desc = GetOwnProperty(this, P); 274 return IS_UNDEFINED(desc) ? false : desc.isEnumerable(); 275 } 276 return %IsPropertyEnumerable(ToObject(this), P); 277} 278 279 280// Extensions for providing property getters and setters. 281function ObjectDefineGetter(name, fun) { 282 var receiver = this; 283 if (receiver == null && !IS_UNDETECTABLE(receiver)) { 284 receiver = %GlobalReceiver(global); 285 } 286 if (!IS_SPEC_FUNCTION(fun)) { 287 throw new $TypeError( 288 'Object.prototype.__defineGetter__: Expecting function'); 289 } 290 var desc = new PropertyDescriptor(); 291 desc.setGet(fun); 292 desc.setEnumerable(true); 293 desc.setConfigurable(true); 294 DefineOwnProperty(ToObject(receiver), ToString(name), desc, false); 295} 296 297 298function ObjectLookupGetter(name) { 299 var receiver = this; 300 if (receiver == null && !IS_UNDETECTABLE(receiver)) { 301 receiver = %GlobalReceiver(global); 302 } 303 return %LookupAccessor(ToObject(receiver), ToString(name), GETTER); 304} 305 306 307function ObjectDefineSetter(name, fun) { 308 var receiver = this; 309 if (receiver == null && !IS_UNDETECTABLE(receiver)) { 310 receiver = %GlobalReceiver(global); 311 } 312 if (!IS_SPEC_FUNCTION(fun)) { 313 throw new $TypeError( 314 'Object.prototype.__defineSetter__: Expecting function'); 315 } 316 var desc = new PropertyDescriptor(); 317 desc.setSet(fun); 318 desc.setEnumerable(true); 319 desc.setConfigurable(true); 320 DefineOwnProperty(ToObject(receiver), ToString(name), desc, false); 321} 322 323 324function ObjectLookupSetter(name) { 325 var receiver = this; 326 if (receiver == null && !IS_UNDETECTABLE(receiver)) { 327 receiver = %GlobalReceiver(global); 328 } 329 return %LookupAccessor(ToObject(receiver), ToString(name), SETTER); 330} 331 332 333function ObjectKeys(obj) { 334 if (!IS_SPEC_OBJECT(obj)) { 335 throw MakeTypeError("called_on_non_object", ["Object.keys"]); 336 } 337 if (%IsJSProxy(obj)) { 338 var handler = %GetHandler(obj); 339 var names = CallTrap0(handler, "keys", DerivedKeysTrap); 340 return ToStringArray(names); 341 } 342 return %LocalKeys(obj); 343} 344 345 346// ES5 8.10.1. 347function IsAccessorDescriptor(desc) { 348 if (IS_UNDEFINED(desc)) return false; 349 return desc.hasGetter() || desc.hasSetter(); 350} 351 352 353// ES5 8.10.2. 354function IsDataDescriptor(desc) { 355 if (IS_UNDEFINED(desc)) return false; 356 return desc.hasValue() || desc.hasWritable(); 357} 358 359 360// ES5 8.10.3. 361function IsGenericDescriptor(desc) { 362 if (IS_UNDEFINED(desc)) return false; 363 return !(IsAccessorDescriptor(desc) || IsDataDescriptor(desc)); 364} 365 366 367function IsInconsistentDescriptor(desc) { 368 return IsAccessorDescriptor(desc) && IsDataDescriptor(desc); 369} 370 371 372// ES5 8.10.4 373function FromPropertyDescriptor(desc) { 374 if (IS_UNDEFINED(desc)) return desc; 375 376 if (IsDataDescriptor(desc)) { 377 return { value: desc.getValue(), 378 writable: desc.isWritable(), 379 enumerable: desc.isEnumerable(), 380 configurable: desc.isConfigurable() }; 381 } 382 // Must be an AccessorDescriptor then. We never return a generic descriptor. 383 return { get: desc.getGet(), 384 set: desc.getSet(), 385 enumerable: desc.isEnumerable(), 386 configurable: desc.isConfigurable() }; 387} 388 389 390// Harmony Proxies 391function FromGenericPropertyDescriptor(desc) { 392 if (IS_UNDEFINED(desc)) return desc; 393 var obj = new $Object(); 394 395 if (desc.hasValue()) { 396 %IgnoreAttributesAndSetProperty(obj, "value", desc.getValue(), NONE); 397 } 398 if (desc.hasWritable()) { 399 %IgnoreAttributesAndSetProperty(obj, "writable", desc.isWritable(), NONE); 400 } 401 if (desc.hasGetter()) { 402 %IgnoreAttributesAndSetProperty(obj, "get", desc.getGet(), NONE); 403 } 404 if (desc.hasSetter()) { 405 %IgnoreAttributesAndSetProperty(obj, "set", desc.getSet(), NONE); 406 } 407 if (desc.hasEnumerable()) { 408 %IgnoreAttributesAndSetProperty(obj, "enumerable", 409 desc.isEnumerable(), NONE); 410 } 411 if (desc.hasConfigurable()) { 412 %IgnoreAttributesAndSetProperty(obj, "configurable", 413 desc.isConfigurable(), NONE); 414 } 415 return obj; 416} 417 418 419// ES5 8.10.5. 420function ToPropertyDescriptor(obj) { 421 if (!IS_SPEC_OBJECT(obj)) { 422 throw MakeTypeError("property_desc_object", [obj]); 423 } 424 var desc = new PropertyDescriptor(); 425 426 if ("enumerable" in obj) { 427 desc.setEnumerable(ToBoolean(obj.enumerable)); 428 } 429 430 if ("configurable" in obj) { 431 desc.setConfigurable(ToBoolean(obj.configurable)); 432 } 433 434 if ("value" in obj) { 435 desc.setValue(obj.value); 436 } 437 438 if ("writable" in obj) { 439 desc.setWritable(ToBoolean(obj.writable)); 440 } 441 442 if ("get" in obj) { 443 var get = obj.get; 444 if (!IS_UNDEFINED(get) && !IS_SPEC_FUNCTION(get)) { 445 throw MakeTypeError("getter_must_be_callable", [get]); 446 } 447 desc.setGet(get); 448 } 449 450 if ("set" in obj) { 451 var set = obj.set; 452 if (!IS_UNDEFINED(set) && !IS_SPEC_FUNCTION(set)) { 453 throw MakeTypeError("setter_must_be_callable", [set]); 454 } 455 desc.setSet(set); 456 } 457 458 if (IsInconsistentDescriptor(desc)) { 459 throw MakeTypeError("value_and_accessor", [obj]); 460 } 461 return desc; 462} 463 464 465// For Harmony proxies. 466function ToCompletePropertyDescriptor(obj) { 467 var desc = ToPropertyDescriptor(obj); 468 if (IsGenericDescriptor(desc) || IsDataDescriptor(desc)) { 469 if (!desc.hasValue()) desc.setValue(void 0); 470 if (!desc.hasWritable()) desc.setWritable(false); 471 } else { 472 // Is accessor descriptor. 473 if (!desc.hasGetter()) desc.setGet(void 0); 474 if (!desc.hasSetter()) desc.setSet(void 0); 475 } 476 if (!desc.hasEnumerable()) desc.setEnumerable(false); 477 if (!desc.hasConfigurable()) desc.setConfigurable(false); 478 return desc; 479} 480 481 482function PropertyDescriptor() { 483 // Initialize here so they are all in-object and have the same map. 484 // Default values from ES5 8.6.1. 485 this.value_ = void 0; 486 this.hasValue_ = false; 487 this.writable_ = false; 488 this.hasWritable_ = false; 489 this.enumerable_ = false; 490 this.hasEnumerable_ = false; 491 this.configurable_ = false; 492 this.hasConfigurable_ = false; 493 this.get_ = void 0; 494 this.hasGetter_ = false; 495 this.set_ = void 0; 496 this.hasSetter_ = false; 497} 498 499SetUpLockedPrototype(PropertyDescriptor, $Array( 500 "value_", 501 "hasValue_", 502 "writable_", 503 "hasWritable_", 504 "enumerable_", 505 "hasEnumerable_", 506 "configurable_", 507 "hasConfigurable_", 508 "get_", 509 "hasGetter_", 510 "set_", 511 "hasSetter_" 512 ), $Array( 513 "toString", function() { 514 return "[object PropertyDescriptor]"; 515 }, 516 "setValue", function(value) { 517 this.value_ = value; 518 this.hasValue_ = true; 519 }, 520 "getValue", function() { 521 return this.value_; 522 }, 523 "hasValue", function() { 524 return this.hasValue_; 525 }, 526 "setEnumerable", function(enumerable) { 527 this.enumerable_ = enumerable; 528 this.hasEnumerable_ = true; 529 }, 530 "isEnumerable", function () { 531 return this.enumerable_; 532 }, 533 "hasEnumerable", function() { 534 return this.hasEnumerable_; 535 }, 536 "setWritable", function(writable) { 537 this.writable_ = writable; 538 this.hasWritable_ = true; 539 }, 540 "isWritable", function() { 541 return this.writable_; 542 }, 543 "hasWritable", function() { 544 return this.hasWritable_; 545 }, 546 "setConfigurable", function(configurable) { 547 this.configurable_ = configurable; 548 this.hasConfigurable_ = true; 549 }, 550 "hasConfigurable", function() { 551 return this.hasConfigurable_; 552 }, 553 "isConfigurable", function() { 554 return this.configurable_; 555 }, 556 "setGet", function(get) { 557 this.get_ = get; 558 this.hasGetter_ = true; 559 }, 560 "getGet", function() { 561 return this.get_; 562 }, 563 "hasGetter", function() { 564 return this.hasGetter_; 565 }, 566 "setSet", function(set) { 567 this.set_ = set; 568 this.hasSetter_ = true; 569 }, 570 "getSet", function() { 571 return this.set_; 572 }, 573 "hasSetter", function() { 574 return this.hasSetter_; 575 })); 576 577 578// Converts an array returned from Runtime_GetOwnProperty to an actual 579// property descriptor. For a description of the array layout please 580// see the runtime.cc file. 581function ConvertDescriptorArrayToDescriptor(desc_array) { 582 if (desc_array === false) { 583 throw 'Internal error: invalid desc_array'; 584 } 585 586 if (IS_UNDEFINED(desc_array)) { 587 return void 0; 588 } 589 590 var desc = new PropertyDescriptor(); 591 // This is an accessor. 592 if (desc_array[IS_ACCESSOR_INDEX]) { 593 desc.setGet(desc_array[GETTER_INDEX]); 594 desc.setSet(desc_array[SETTER_INDEX]); 595 } else { 596 desc.setValue(desc_array[VALUE_INDEX]); 597 desc.setWritable(desc_array[WRITABLE_INDEX]); 598 } 599 desc.setEnumerable(desc_array[ENUMERABLE_INDEX]); 600 desc.setConfigurable(desc_array[CONFIGURABLE_INDEX]); 601 602 return desc; 603} 604 605 606// For Harmony proxies. 607function GetTrap(handler, name, defaultTrap) { 608 var trap = handler[name]; 609 if (IS_UNDEFINED(trap)) { 610 if (IS_UNDEFINED(defaultTrap)) { 611 throw MakeTypeError("handler_trap_missing", [handler, name]); 612 } 613 trap = defaultTrap; 614 } else if (!IS_SPEC_FUNCTION(trap)) { 615 throw MakeTypeError("handler_trap_must_be_callable", [handler, name]); 616 } 617 return trap; 618} 619 620 621function CallTrap0(handler, name, defaultTrap) { 622 return %_CallFunction(handler, GetTrap(handler, name, defaultTrap)); 623} 624 625 626function CallTrap1(handler, name, defaultTrap, x) { 627 return %_CallFunction(handler, x, GetTrap(handler, name, defaultTrap)); 628} 629 630 631function CallTrap2(handler, name, defaultTrap, x, y) { 632 return %_CallFunction(handler, x, y, GetTrap(handler, name, defaultTrap)); 633} 634 635 636// ES5 section 8.12.1. 637function GetOwnProperty(obj, v) { 638 var p = ToString(v); 639 if (%IsJSProxy(obj)) { 640 var handler = %GetHandler(obj); 641 var descriptor = CallTrap1(handler, "getOwnPropertyDescriptor", void 0, p); 642 if (IS_UNDEFINED(descriptor)) return descriptor; 643 var desc = ToCompletePropertyDescriptor(descriptor); 644 if (!desc.isConfigurable()) { 645 throw MakeTypeError("proxy_prop_not_configurable", 646 [handler, "getOwnPropertyDescriptor", p, descriptor]); 647 } 648 return desc; 649 } 650 651 // GetOwnProperty returns an array indexed by the constants 652 // defined in macros.py. 653 // If p is not a property on obj undefined is returned. 654 var props = %GetOwnProperty(ToObject(obj), ToString(v)); 655 656 // A false value here means that access checks failed. 657 if (props === false) return void 0; 658 659 return ConvertDescriptorArrayToDescriptor(props); 660} 661 662 663// ES5 section 8.12.7. 664function Delete(obj, p, should_throw) { 665 var desc = GetOwnProperty(obj, p); 666 if (IS_UNDEFINED(desc)) return true; 667 if (desc.isConfigurable()) { 668 %DeleteProperty(obj, p, 0); 669 return true; 670 } else if (should_throw) { 671 throw MakeTypeError("define_disallowed", [p]); 672 } else { 673 return; 674 } 675} 676 677 678// Harmony proxies. 679function DefineProxyProperty(obj, p, attributes, should_throw) { 680 var handler = %GetHandler(obj); 681 var result = CallTrap2(handler, "defineProperty", void 0, p, attributes); 682 if (!ToBoolean(result)) { 683 if (should_throw) { 684 throw MakeTypeError("handler_returned_false", 685 [handler, "defineProperty"]); 686 } else { 687 return false; 688 } 689 } 690 return true; 691} 692 693 694// ES5 8.12.9. 695function DefineObjectProperty(obj, p, desc, should_throw) { 696 var current_or_access = %GetOwnProperty(ToObject(obj), ToString(p)); 697 // A false value here means that access checks failed. 698 if (current_or_access === false) return void 0; 699 700 var current = ConvertDescriptorArrayToDescriptor(current_or_access); 701 var extensible = %IsExtensible(ToObject(obj)); 702 703 // Error handling according to spec. 704 // Step 3 705 if (IS_UNDEFINED(current) && !extensible) { 706 if (should_throw) { 707 throw MakeTypeError("define_disallowed", [p]); 708 } else { 709 return false; 710 } 711 } 712 713 if (!IS_UNDEFINED(current)) { 714 // Step 5 and 6 715 if ((IsGenericDescriptor(desc) || 716 IsDataDescriptor(desc) == IsDataDescriptor(current)) && 717 (!desc.hasEnumerable() || 718 SameValue(desc.isEnumerable(), current.isEnumerable())) && 719 (!desc.hasConfigurable() || 720 SameValue(desc.isConfigurable(), current.isConfigurable())) && 721 (!desc.hasWritable() || 722 SameValue(desc.isWritable(), current.isWritable())) && 723 (!desc.hasValue() || 724 SameValue(desc.getValue(), current.getValue())) && 725 (!desc.hasGetter() || 726 SameValue(desc.getGet(), current.getGet())) && 727 (!desc.hasSetter() || 728 SameValue(desc.getSet(), current.getSet()))) { 729 return true; 730 } 731 if (!current.isConfigurable()) { 732 // Step 7 733 if (desc.isConfigurable() || 734 (desc.hasEnumerable() && 735 desc.isEnumerable() != current.isEnumerable())) { 736 if (should_throw) { 737 throw MakeTypeError("redefine_disallowed", [p]); 738 } else { 739 return false; 740 } 741 } 742 // Step 8 743 if (!IsGenericDescriptor(desc)) { 744 // Step 9a 745 if (IsDataDescriptor(current) != IsDataDescriptor(desc)) { 746 if (should_throw) { 747 throw MakeTypeError("redefine_disallowed", [p]); 748 } else { 749 return false; 750 } 751 } 752 // Step 10a 753 if (IsDataDescriptor(current) && IsDataDescriptor(desc)) { 754 if (!current.isWritable() && desc.isWritable()) { 755 if (should_throw) { 756 throw MakeTypeError("redefine_disallowed", [p]); 757 } else { 758 return false; 759 } 760 } 761 if (!current.isWritable() && desc.hasValue() && 762 !SameValue(desc.getValue(), current.getValue())) { 763 if (should_throw) { 764 throw MakeTypeError("redefine_disallowed", [p]); 765 } else { 766 return false; 767 } 768 } 769 } 770 // Step 11 771 if (IsAccessorDescriptor(desc) && IsAccessorDescriptor(current)) { 772 if (desc.hasSetter() && !SameValue(desc.getSet(), current.getSet())) { 773 if (should_throw) { 774 throw MakeTypeError("redefine_disallowed", [p]); 775 } else { 776 return false; 777 } 778 } 779 if (desc.hasGetter() && !SameValue(desc.getGet(),current.getGet())) { 780 if (should_throw) { 781 throw MakeTypeError("redefine_disallowed", [p]); 782 } else { 783 return false; 784 } 785 } 786 } 787 } 788 } 789 } 790 791 // Send flags - enumerable and configurable are common - writable is 792 // only send to the data descriptor. 793 // Take special care if enumerable and configurable is not defined on 794 // desc (we need to preserve the existing values from current). 795 var flag = NONE; 796 if (desc.hasEnumerable()) { 797 flag |= desc.isEnumerable() ? 0 : DONT_ENUM; 798 } else if (!IS_UNDEFINED(current)) { 799 flag |= current.isEnumerable() ? 0 : DONT_ENUM; 800 } else { 801 flag |= DONT_ENUM; 802 } 803 804 if (desc.hasConfigurable()) { 805 flag |= desc.isConfigurable() ? 0 : DONT_DELETE; 806 } else if (!IS_UNDEFINED(current)) { 807 flag |= current.isConfigurable() ? 0 : DONT_DELETE; 808 } else 809 flag |= DONT_DELETE; 810 811 if (IsDataDescriptor(desc) || 812 (IsGenericDescriptor(desc) && 813 (IS_UNDEFINED(current) || IsDataDescriptor(current)))) { 814 // There are 3 cases that lead here: 815 // Step 4a - defining a new data property. 816 // Steps 9b & 12 - replacing an existing accessor property with a data 817 // property. 818 // Step 12 - updating an existing data property with a data or generic 819 // descriptor. 820 821 if (desc.hasWritable()) { 822 flag |= desc.isWritable() ? 0 : READ_ONLY; 823 } else if (!IS_UNDEFINED(current)) { 824 flag |= current.isWritable() ? 0 : READ_ONLY; 825 } else { 826 flag |= READ_ONLY; 827 } 828 829 var value = void 0; // Default value is undefined. 830 if (desc.hasValue()) { 831 value = desc.getValue(); 832 } else if (!IS_UNDEFINED(current) && IsDataDescriptor(current)) { 833 value = current.getValue(); 834 } 835 836 %DefineOrRedefineDataProperty(obj, p, value, flag); 837 } else { 838 // There are 3 cases that lead here: 839 // Step 4b - defining a new accessor property. 840 // Steps 9c & 12 - replacing an existing data property with an accessor 841 // property. 842 // Step 12 - updating an existing accessor property with an accessor 843 // descriptor. 844 var getter = desc.hasGetter() ? desc.getGet() : null; 845 var setter = desc.hasSetter() ? desc.getSet() : null; 846 %DefineOrRedefineAccessorProperty(obj, p, getter, setter, flag); 847 } 848 return true; 849} 850 851 852// ES5 section 15.4.5.1. 853function DefineArrayProperty(obj, p, desc, should_throw) { 854 // Note that the length of an array is not actually stored as part of the 855 // property, hence we use generated code throughout this function instead of 856 // DefineObjectProperty() to modify its value. 857 858 // Step 3 - Special handling for length property. 859 if (p == "length") { 860 var length = obj.length; 861 if (!desc.hasValue()) { 862 return DefineObjectProperty(obj, "length", desc, should_throw); 863 } 864 var new_length = ToUint32(desc.getValue()); 865 if (new_length != ToNumber(desc.getValue())) { 866 throw new $RangeError('defineProperty() array length out of range'); 867 } 868 var length_desc = GetOwnProperty(obj, "length"); 869 if (new_length != length && !length_desc.isWritable()) { 870 if (should_throw) { 871 throw MakeTypeError("redefine_disallowed", [p]); 872 } else { 873 return false; 874 } 875 } 876 var threw = false; 877 while (new_length < length--) { 878 if (!Delete(obj, ToString(length), false)) { 879 new_length = length + 1; 880 threw = true; 881 break; 882 } 883 } 884 // Make sure the below call to DefineObjectProperty() doesn't overwrite 885 // any magic "length" property by removing the value. 886 obj.length = new_length; 887 desc.value_ = void 0; 888 desc.hasValue_ = false; 889 if (!DefineObjectProperty(obj, "length", desc, should_throw) || threw) { 890 if (should_throw) { 891 throw MakeTypeError("redefine_disallowed", [p]); 892 } else { 893 return false; 894 } 895 } 896 return true; 897 } 898 899 // Step 4 - Special handling for array index. 900 var index = ToUint32(p); 901 if (index == ToNumber(p) && index != 4294967295) { 902 var length = obj.length; 903 var length_desc = GetOwnProperty(obj, "length"); 904 if ((index >= length && !length_desc.isWritable()) || 905 !DefineObjectProperty(obj, p, desc, true)) { 906 if (should_throw) { 907 throw MakeTypeError("define_disallowed", [p]); 908 } else { 909 return false; 910 } 911 } 912 if (index >= length) { 913 obj.length = index + 1; 914 } 915 return true; 916 } 917 918 // Step 5 - Fallback to default implementation. 919 return DefineObjectProperty(obj, p, desc, should_throw); 920} 921 922 923// ES5 section 8.12.9, ES5 section 15.4.5.1 and Harmony proxies. 924function DefineOwnProperty(obj, p, desc, should_throw) { 925 if (%IsJSProxy(obj)) { 926 var attributes = FromGenericPropertyDescriptor(desc); 927 return DefineProxyProperty(obj, p, attributes, should_throw); 928 } else if (IS_ARRAY(obj)) { 929 return DefineArrayProperty(obj, p, desc, should_throw); 930 } else { 931 return DefineObjectProperty(obj, p, desc, should_throw); 932 } 933} 934 935 936// ES5 section 15.2.3.2. 937function ObjectGetPrototypeOf(obj) { 938 if (!IS_SPEC_OBJECT(obj)) { 939 throw MakeTypeError("called_on_non_object", ["Object.getPrototypeOf"]); 940 } 941 return %GetPrototype(obj); 942} 943 944 945// ES5 section 15.2.3.3 946function ObjectGetOwnPropertyDescriptor(obj, p) { 947 if (!IS_SPEC_OBJECT(obj)) { 948 throw MakeTypeError("called_on_non_object", 949 ["Object.getOwnPropertyDescriptor"]); 950 } 951 var desc = GetOwnProperty(obj, p); 952 return FromPropertyDescriptor(desc); 953} 954 955 956// For Harmony proxies 957function ToStringArray(obj, trap) { 958 if (!IS_SPEC_OBJECT(obj)) { 959 throw MakeTypeError("proxy_non_object_prop_names", [obj, trap]); 960 } 961 var n = ToUint32(obj.length); 962 var array = new $Array(n); 963 var names = {}; // TODO(rossberg): use sets once they are ready. 964 for (var index = 0; index < n; index++) { 965 var s = ToString(obj[index]); 966 if (s in names) { 967 throw MakeTypeError("proxy_repeated_prop_name", [obj, trap, s]); 968 } 969 array[index] = s; 970 names[s] = 0; 971 } 972 return array; 973} 974 975 976// ES5 section 15.2.3.4. 977function ObjectGetOwnPropertyNames(obj) { 978 if (!IS_SPEC_OBJECT(obj)) { 979 throw MakeTypeError("called_on_non_object", ["Object.getOwnPropertyNames"]); 980 } 981 // Special handling for proxies. 982 if (%IsJSProxy(obj)) { 983 var handler = %GetHandler(obj); 984 var names = CallTrap0(handler, "getOwnPropertyNames", void 0); 985 return ToStringArray(names, "getOwnPropertyNames"); 986 } 987 988 // Find all the indexed properties. 989 990 // Get the local element names. 991 var propertyNames = %GetLocalElementNames(obj); 992 993 // Get names for indexed interceptor properties. 994 if (%GetInterceptorInfo(obj) & 1) { 995 var indexedInterceptorNames = 996 %GetIndexedInterceptorElementNames(obj); 997 if (indexedInterceptorNames) { 998 propertyNames = propertyNames.concat(indexedInterceptorNames); 999 } 1000 } 1001 1002 // Find all the named properties. 1003 1004 // Get the local property names. 1005 propertyNames = propertyNames.concat(%GetLocalPropertyNames(obj)); 1006 1007 // Get names for named interceptor properties if any. 1008 1009 if (%GetInterceptorInfo(obj) & 2) { 1010 var namedInterceptorNames = 1011 %GetNamedInterceptorPropertyNames(obj); 1012 if (namedInterceptorNames) { 1013 propertyNames = propertyNames.concat(namedInterceptorNames); 1014 } 1015 } 1016 1017 // Property names are expected to be unique strings. 1018 var propertySet = {}; 1019 var j = 0; 1020 for (var i = 0; i < propertyNames.length; ++i) { 1021 var name = ToString(propertyNames[i]); 1022 // We need to check for the exact property value since for intrinsic 1023 // properties like toString if(propertySet["toString"]) will always 1024 // succeed. 1025 if (propertySet[name] === true) { 1026 continue; 1027 } 1028 propertySet[name] = true; 1029 propertyNames[j++] = name; 1030 } 1031 propertyNames.length = j; 1032 1033 return propertyNames; 1034} 1035 1036 1037// ES5 section 15.2.3.5. 1038function ObjectCreate(proto, properties) { 1039 if (!IS_SPEC_OBJECT(proto) && proto !== null) { 1040 throw MakeTypeError("proto_object_or_null", [proto]); 1041 } 1042 var obj = new $Object(); 1043 obj.__proto__ = proto; 1044 if (!IS_UNDEFINED(properties)) ObjectDefineProperties(obj, properties); 1045 return obj; 1046} 1047 1048 1049// ES5 section 15.2.3.6. 1050function ObjectDefineProperty(obj, p, attributes) { 1051 if (!IS_SPEC_OBJECT(obj)) { 1052 throw MakeTypeError("called_on_non_object", ["Object.defineProperty"]); 1053 } 1054 var name = ToString(p); 1055 if (%IsJSProxy(obj)) { 1056 // Clone the attributes object for protection. 1057 // TODO(rossberg): not spec'ed yet, so not sure if this should involve 1058 // non-own properties as it does (or non-enumerable ones, as it doesn't?). 1059 var attributesClone = {}; 1060 for (var a in attributes) { 1061 attributesClone[a] = attributes[a]; 1062 } 1063 DefineProxyProperty(obj, name, attributesClone, true); 1064 // The following would implement the spec as in the current proposal, 1065 // but after recent comments on es-discuss, is most likely obsolete. 1066 /* 1067 var defineObj = FromGenericPropertyDescriptor(desc); 1068 var names = ObjectGetOwnPropertyNames(attributes); 1069 var standardNames = 1070 {value: 0, writable: 0, get: 0, set: 0, enumerable: 0, configurable: 0}; 1071 for (var i = 0; i < names.length; i++) { 1072 var N = names[i]; 1073 if (!(%HasLocalProperty(standardNames, N))) { 1074 var attr = GetOwnProperty(attributes, N); 1075 DefineOwnProperty(descObj, N, attr, true); 1076 } 1077 } 1078 // This is really confusing the types, but it is what the proxies spec 1079 // currently requires: 1080 desc = descObj; 1081 */ 1082 } else { 1083 var desc = ToPropertyDescriptor(attributes); 1084 DefineOwnProperty(obj, name, desc, true); 1085 } 1086 return obj; 1087} 1088 1089 1090function GetOwnEnumerablePropertyNames(properties) { 1091 var names = new InternalArray(); 1092 for (var key in properties) { 1093 if (%HasLocalProperty(properties, key)) { 1094 names.push(key); 1095 } 1096 } 1097 return names; 1098} 1099 1100 1101// ES5 section 15.2.3.7. 1102function ObjectDefineProperties(obj, properties) { 1103 if (!IS_SPEC_OBJECT(obj)) { 1104 throw MakeTypeError("called_on_non_object", ["Object.defineProperties"]); 1105 } 1106 var props = ToObject(properties); 1107 var names = GetOwnEnumerablePropertyNames(props); 1108 var descriptors = new InternalArray(); 1109 for (var i = 0; i < names.length; i++) { 1110 descriptors.push(ToPropertyDescriptor(props[names[i]])); 1111 } 1112 for (var i = 0; i < names.length; i++) { 1113 DefineOwnProperty(obj, names[i], descriptors[i], true); 1114 } 1115 return obj; 1116} 1117 1118 1119// Harmony proxies. 1120function ProxyFix(obj) { 1121 var handler = %GetHandler(obj); 1122 var props = CallTrap0(handler, "fix", void 0); 1123 if (IS_UNDEFINED(props)) { 1124 throw MakeTypeError("handler_returned_undefined", [handler, "fix"]); 1125 } 1126 1127 if (%IsJSFunctionProxy(obj)) { 1128 var callTrap = %GetCallTrap(obj); 1129 var constructTrap = %GetConstructTrap(obj); 1130 var code = DelegateCallAndConstruct(callTrap, constructTrap); 1131 %Fix(obj); // becomes a regular function 1132 %SetCode(obj, code); 1133 // TODO(rossberg): What about length and other properties? Not specified. 1134 // We just put in some half-reasonable defaults for now. 1135 var prototype = new $Object(); 1136 $Object.defineProperty(prototype, "constructor", 1137 {value: obj, writable: true, enumerable: false, configurable: true}); 1138 // TODO(v8:1530): defineProperty does not handle prototype and length. 1139 %FunctionSetPrototype(obj, prototype); 1140 obj.length = 0; 1141 } else { 1142 %Fix(obj); 1143 } 1144 ObjectDefineProperties(obj, props); 1145} 1146 1147 1148// ES5 section 15.2.3.8. 1149function ObjectSeal(obj) { 1150 if (!IS_SPEC_OBJECT(obj)) { 1151 throw MakeTypeError("called_on_non_object", ["Object.seal"]); 1152 } 1153 if (%IsJSProxy(obj)) { 1154 ProxyFix(obj); 1155 } 1156 var names = ObjectGetOwnPropertyNames(obj); 1157 for (var i = 0; i < names.length; i++) { 1158 var name = names[i]; 1159 var desc = GetOwnProperty(obj, name); 1160 if (desc.isConfigurable()) { 1161 desc.setConfigurable(false); 1162 DefineOwnProperty(obj, name, desc, true); 1163 } 1164 } 1165 %PreventExtensions(obj); 1166 return obj; 1167} 1168 1169 1170// ES5 section 15.2.3.9. 1171function ObjectFreeze(obj) { 1172 if (!IS_SPEC_OBJECT(obj)) { 1173 throw MakeTypeError("called_on_non_object", ["Object.freeze"]); 1174 } 1175 if (%IsJSProxy(obj)) { 1176 ProxyFix(obj); 1177 } 1178 var names = ObjectGetOwnPropertyNames(obj); 1179 for (var i = 0; i < names.length; i++) { 1180 var name = names[i]; 1181 var desc = GetOwnProperty(obj, name); 1182 if (desc.isWritable() || desc.isConfigurable()) { 1183 if (IsDataDescriptor(desc)) desc.setWritable(false); 1184 desc.setConfigurable(false); 1185 DefineOwnProperty(obj, name, desc, true); 1186 } 1187 } 1188 %PreventExtensions(obj); 1189 return obj; 1190} 1191 1192 1193// ES5 section 15.2.3.10 1194function ObjectPreventExtension(obj) { 1195 if (!IS_SPEC_OBJECT(obj)) { 1196 throw MakeTypeError("called_on_non_object", ["Object.preventExtension"]); 1197 } 1198 if (%IsJSProxy(obj)) { 1199 ProxyFix(obj); 1200 } 1201 %PreventExtensions(obj); 1202 return obj; 1203} 1204 1205 1206// ES5 section 15.2.3.11 1207function ObjectIsSealed(obj) { 1208 if (!IS_SPEC_OBJECT(obj)) { 1209 throw MakeTypeError("called_on_non_object", ["Object.isSealed"]); 1210 } 1211 if (%IsJSProxy(obj)) { 1212 return false; 1213 } 1214 var names = ObjectGetOwnPropertyNames(obj); 1215 for (var i = 0; i < names.length; i++) { 1216 var name = names[i]; 1217 var desc = GetOwnProperty(obj, name); 1218 if (desc.isConfigurable()) return false; 1219 } 1220 if (!ObjectIsExtensible(obj)) { 1221 return true; 1222 } 1223 return false; 1224} 1225 1226 1227// ES5 section 15.2.3.12 1228function ObjectIsFrozen(obj) { 1229 if (!IS_SPEC_OBJECT(obj)) { 1230 throw MakeTypeError("called_on_non_object", ["Object.isFrozen"]); 1231 } 1232 if (%IsJSProxy(obj)) { 1233 return false; 1234 } 1235 var names = ObjectGetOwnPropertyNames(obj); 1236 for (var i = 0; i < names.length; i++) { 1237 var name = names[i]; 1238 var desc = GetOwnProperty(obj, name); 1239 if (IsDataDescriptor(desc) && desc.isWritable()) return false; 1240 if (desc.isConfigurable()) return false; 1241 } 1242 if (!ObjectIsExtensible(obj)) { 1243 return true; 1244 } 1245 return false; 1246} 1247 1248 1249// ES5 section 15.2.3.13 1250function ObjectIsExtensible(obj) { 1251 if (!IS_SPEC_OBJECT(obj)) { 1252 throw MakeTypeError("called_on_non_object", ["Object.isExtensible"]); 1253 } 1254 if (%IsJSProxy(obj)) { 1255 return true; 1256 } 1257 return %IsExtensible(obj); 1258} 1259 1260 1261// Harmony egal. 1262function ObjectIs(obj1, obj2) { 1263 if (obj1 === obj2) { 1264 return (obj1 !== 0) || (1 / obj1 === 1 / obj2); 1265 } else { 1266 return (obj1 !== obj1) && (obj2 !== obj2); 1267 } 1268} 1269 1270 1271%SetCode($Object, function(x) { 1272 if (%_IsConstructCall()) { 1273 if (x == null) return this; 1274 return ToObject(x); 1275 } else { 1276 if (x == null) return { }; 1277 return ToObject(x); 1278 } 1279}); 1280 1281%SetExpectedNumberOfProperties($Object, 4); 1282 1283// ---------------------------------------------------------------------------- 1284// Object 1285 1286function SetUpObject() { 1287 %CheckIsBootstrapping(); 1288 // Set Up non-enumerable functions on the Object.prototype object. 1289 InstallFunctions($Object.prototype, DONT_ENUM, $Array( 1290 "toString", ObjectToString, 1291 "toLocaleString", ObjectToLocaleString, 1292 "valueOf", ObjectValueOf, 1293 "hasOwnProperty", ObjectHasOwnProperty, 1294 "isPrototypeOf", ObjectIsPrototypeOf, 1295 "propertyIsEnumerable", ObjectPropertyIsEnumerable, 1296 "__defineGetter__", ObjectDefineGetter, 1297 "__lookupGetter__", ObjectLookupGetter, 1298 "__defineSetter__", ObjectDefineSetter, 1299 "__lookupSetter__", ObjectLookupSetter 1300 )); 1301 InstallFunctions($Object, DONT_ENUM, $Array( 1302 "keys", ObjectKeys, 1303 "create", ObjectCreate, 1304 "defineProperty", ObjectDefineProperty, 1305 "defineProperties", ObjectDefineProperties, 1306 "freeze", ObjectFreeze, 1307 "getPrototypeOf", ObjectGetPrototypeOf, 1308 "getOwnPropertyDescriptor", ObjectGetOwnPropertyDescriptor, 1309 "getOwnPropertyNames", ObjectGetOwnPropertyNames, 1310 "is", ObjectIs, 1311 "isExtensible", ObjectIsExtensible, 1312 "isFrozen", ObjectIsFrozen, 1313 "isSealed", ObjectIsSealed, 1314 "preventExtensions", ObjectPreventExtension, 1315 "seal", ObjectSeal 1316 )); 1317} 1318 1319SetUpObject(); 1320 1321// ---------------------------------------------------------------------------- 1322// Boolean 1323 1324function BooleanToString() { 1325 // NOTE: Both Boolean objects and values can enter here as 1326 // 'this'. This is not as dictated by ECMA-262. 1327 var b = this; 1328 if (!IS_BOOLEAN(b)) { 1329 if (!IS_BOOLEAN_WRAPPER(b)) { 1330 throw new $TypeError('Boolean.prototype.toString is not generic'); 1331 } 1332 b = %_ValueOf(b); 1333 } 1334 return b ? 'true' : 'false'; 1335} 1336 1337 1338function BooleanValueOf() { 1339 // NOTE: Both Boolean objects and values can enter here as 1340 // 'this'. This is not as dictated by ECMA-262. 1341 if (!IS_BOOLEAN(this) && !IS_BOOLEAN_WRAPPER(this)) { 1342 throw new $TypeError('Boolean.prototype.valueOf is not generic'); 1343 } 1344 return %_ValueOf(this); 1345} 1346 1347 1348// ---------------------------------------------------------------------------- 1349 1350 1351function SetUpBoolean () { 1352 %CheckIsBootstrapping(); 1353 InstallFunctions($Boolean.prototype, DONT_ENUM, $Array( 1354 "toString", BooleanToString, 1355 "valueOf", BooleanValueOf 1356 )); 1357} 1358 1359SetUpBoolean(); 1360 1361 1362// ---------------------------------------------------------------------------- 1363// Number 1364 1365// Set the Number function and constructor. 1366%SetCode($Number, function(x) { 1367 var value = %_ArgumentsLength() == 0 ? 0 : ToNumber(x); 1368 if (%_IsConstructCall()) { 1369 %_SetValueOf(this, value); 1370 } else { 1371 return value; 1372 } 1373}); 1374 1375%FunctionSetPrototype($Number, new $Number(0)); 1376 1377// ECMA-262 section 15.7.4.2. 1378function NumberToString(radix) { 1379 // NOTE: Both Number objects and values can enter here as 1380 // 'this'. This is not as dictated by ECMA-262. 1381 var number = this; 1382 if (!IS_NUMBER(this)) { 1383 if (!IS_NUMBER_WRAPPER(this)) { 1384 throw new $TypeError('Number.prototype.toString is not generic'); 1385 } 1386 // Get the value of this number in case it's an object. 1387 number = %_ValueOf(this); 1388 } 1389 // Fast case: Convert number in radix 10. 1390 if (IS_UNDEFINED(radix) || radix === 10) { 1391 return %_NumberToString(number); 1392 } 1393 1394 // Convert the radix to an integer and check the range. 1395 radix = TO_INTEGER(radix); 1396 if (radix < 2 || radix > 36) { 1397 throw new $RangeError('toString() radix argument must be between 2 and 36'); 1398 } 1399 // Convert the number to a string in the given radix. 1400 return %NumberToRadixString(number, radix); 1401} 1402 1403 1404// ECMA-262 section 15.7.4.3 1405function NumberToLocaleString() { 1406 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { 1407 throw MakeTypeError("called_on_null_or_undefined", 1408 ["Number.prototype.toLocaleString"]); 1409 } 1410 return this.toString(); 1411} 1412 1413 1414// ECMA-262 section 15.7.4.4 1415function NumberValueOf() { 1416 // NOTE: Both Number objects and values can enter here as 1417 // 'this'. This is not as dictated by ECMA-262. 1418 if (!IS_NUMBER(this) && !IS_NUMBER_WRAPPER(this)) { 1419 throw new $TypeError('Number.prototype.valueOf is not generic'); 1420 } 1421 return %_ValueOf(this); 1422} 1423 1424 1425// ECMA-262 section 15.7.4.5 1426function NumberToFixed(fractionDigits) { 1427 var f = TO_INTEGER(fractionDigits); 1428 if (f < 0 || f > 20) { 1429 throw new $RangeError("toFixed() digits argument must be between 0 and 20"); 1430 } 1431 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { 1432 throw MakeTypeError("called_on_null_or_undefined", 1433 ["Number.prototype.toFixed"]); 1434 } 1435 var x = ToNumber(this); 1436 return %NumberToFixed(x, f); 1437} 1438 1439 1440// ECMA-262 section 15.7.4.6 1441function NumberToExponential(fractionDigits) { 1442 var f = -1; 1443 if (!IS_UNDEFINED(fractionDigits)) { 1444 f = TO_INTEGER(fractionDigits); 1445 if (f < 0 || f > 20) { 1446 throw new $RangeError( 1447 "toExponential() argument must be between 0 and 20"); 1448 } 1449 } 1450 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { 1451 throw MakeTypeError("called_on_null_or_undefined", 1452 ["Number.prototype.toExponential"]); 1453 } 1454 var x = ToNumber(this); 1455 return %NumberToExponential(x, f); 1456} 1457 1458 1459// ECMA-262 section 15.7.4.7 1460function NumberToPrecision(precision) { 1461 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { 1462 throw MakeTypeError("called_on_null_or_undefined", 1463 ["Number.prototype.toPrecision"]); 1464 } 1465 if (IS_UNDEFINED(precision)) return ToString(%_ValueOf(this)); 1466 var p = TO_INTEGER(precision); 1467 if (p < 1 || p > 21) { 1468 throw new $RangeError("toPrecision() argument must be between 1 and 21"); 1469 } 1470 var x = ToNumber(this); 1471 return %NumberToPrecision(x, p); 1472} 1473 1474 1475// Harmony isFinite. 1476function NumberIsFinite(number) { 1477 return IS_NUMBER(number) && NUMBER_IS_FINITE(number); 1478} 1479 1480 1481// Harmony isNaN. 1482function NumberIsNaN(number) { 1483 return IS_NUMBER(number) && NUMBER_IS_NAN(number); 1484} 1485 1486 1487// ---------------------------------------------------------------------------- 1488 1489function SetUpNumber() { 1490 %CheckIsBootstrapping(); 1491 %OptimizeObjectForAddingMultipleProperties($Number.prototype, 8); 1492 // Set up the constructor property on the Number prototype object. 1493 %SetProperty($Number.prototype, "constructor", $Number, DONT_ENUM); 1494 1495 %OptimizeObjectForAddingMultipleProperties($Number, 5); 1496 // ECMA-262 section 15.7.3.1. 1497 %SetProperty($Number, 1498 "MAX_VALUE", 1499 1.7976931348623157e+308, 1500 DONT_ENUM | DONT_DELETE | READ_ONLY); 1501 1502 // ECMA-262 section 15.7.3.2. 1503 %SetProperty($Number, "MIN_VALUE", 5e-324, 1504 DONT_ENUM | DONT_DELETE | READ_ONLY); 1505 1506 // ECMA-262 section 15.7.3.3. 1507 %SetProperty($Number, "NaN", $NaN, DONT_ENUM | DONT_DELETE | READ_ONLY); 1508 1509 // ECMA-262 section 15.7.3.4. 1510 %SetProperty($Number, 1511 "NEGATIVE_INFINITY", 1512 -1/0, 1513 DONT_ENUM | DONT_DELETE | READ_ONLY); 1514 1515 // ECMA-262 section 15.7.3.5. 1516 %SetProperty($Number, 1517 "POSITIVE_INFINITY", 1518 1/0, 1519 DONT_ENUM | DONT_DELETE | READ_ONLY); 1520 %ToFastProperties($Number); 1521 1522 // Set up non-enumerable functions on the Number prototype object. 1523 InstallFunctions($Number.prototype, DONT_ENUM, $Array( 1524 "toString", NumberToString, 1525 "toLocaleString", NumberToLocaleString, 1526 "valueOf", NumberValueOf, 1527 "toFixed", NumberToFixed, 1528 "toExponential", NumberToExponential, 1529 "toPrecision", NumberToPrecision 1530 )); 1531 InstallFunctions($Number, DONT_ENUM, $Array( 1532 "isFinite", NumberIsFinite, 1533 "isNaN", NumberIsNaN 1534 )); 1535} 1536 1537SetUpNumber(); 1538 1539 1540// ---------------------------------------------------------------------------- 1541// Function 1542 1543$Function.prototype.constructor = $Function; 1544 1545function FunctionSourceString(func) { 1546 while (%IsJSFunctionProxy(func)) { 1547 func = %GetCallTrap(func); 1548 } 1549 1550 if (!IS_FUNCTION(func)) { 1551 throw new $TypeError('Function.prototype.toString is not generic'); 1552 } 1553 1554 var source = %FunctionGetSourceCode(func); 1555 if (!IS_STRING(source) || %FunctionIsBuiltin(func)) { 1556 var name = %FunctionGetName(func); 1557 if (name) { 1558 // Mimic what KJS does. 1559 return 'function ' + name + '() { [native code] }'; 1560 } else { 1561 return 'function () { [native code] }'; 1562 } 1563 } 1564 1565 var name = %FunctionNameShouldPrintAsAnonymous(func) 1566 ? 'anonymous' 1567 : %FunctionGetName(func); 1568 return 'function ' + name + source; 1569} 1570 1571 1572function FunctionToString() { 1573 return FunctionSourceString(this); 1574} 1575 1576 1577// ES5 15.3.4.5 1578function FunctionBind(this_arg) { // Length is 1. 1579 if (!IS_SPEC_FUNCTION(this)) { 1580 throw new $TypeError('Bind must be called on a function'); 1581 } 1582 var boundFunction = function () { 1583 // Poison .arguments and .caller, but is otherwise not detectable. 1584 "use strict"; 1585 // This function must not use any object literals (Object, Array, RegExp), 1586 // since the literals-array is being used to store the bound data. 1587 if (%_IsConstructCall()) { 1588 return %NewObjectFromBound(boundFunction); 1589 } 1590 var bindings = %BoundFunctionGetBindings(boundFunction); 1591 1592 var argc = %_ArgumentsLength(); 1593 if (argc == 0) { 1594 return %Apply(bindings[0], bindings[1], bindings, 2, bindings.length - 2); 1595 } 1596 if (bindings.length === 2) { 1597 return %Apply(bindings[0], bindings[1], arguments, 0, argc); 1598 } 1599 var bound_argc = bindings.length - 2; 1600 var argv = new InternalArray(bound_argc + argc); 1601 for (var i = 0; i < bound_argc; i++) { 1602 argv[i] = bindings[i + 2]; 1603 } 1604 for (var j = 0; j < argc; j++) { 1605 argv[i++] = %_Arguments(j); 1606 } 1607 return %Apply(bindings[0], bindings[1], argv, 0, bound_argc + argc); 1608 }; 1609 1610 %FunctionRemovePrototype(boundFunction); 1611 var new_length = 0; 1612 if (%_ClassOf(this) == "Function") { 1613 // Function or FunctionProxy. 1614 var old_length = this.length; 1615 // FunctionProxies might provide a non-UInt32 value. If so, ignore it. 1616 if ((typeof old_length === "number") && 1617 ((old_length >>> 0) === old_length)) { 1618 var argc = %_ArgumentsLength(); 1619 if (argc > 0) argc--; // Don't count the thisArg as parameter. 1620 new_length = old_length - argc; 1621 if (new_length < 0) new_length = 0; 1622 } 1623 } 1624 // This runtime function finds any remaining arguments on the stack, 1625 // so we don't pass the arguments object. 1626 var result = %FunctionBindArguments(boundFunction, this, 1627 this_arg, new_length); 1628 1629 // We already have caller and arguments properties on functions, 1630 // which are non-configurable. It therefore makes no sence to 1631 // try to redefine these as defined by the spec. The spec says 1632 // that bind should make these throw a TypeError if get or set 1633 // is called and make them non-enumerable and non-configurable. 1634 // To be consistent with our normal functions we leave this as it is. 1635 // TODO(lrn): Do set these to be thrower. 1636 return result; 1637} 1638 1639 1640function NewFunction(arg1) { // length == 1 1641 var n = %_ArgumentsLength(); 1642 var p = ''; 1643 if (n > 1) { 1644 p = new InternalArray(n - 1); 1645 for (var i = 0; i < n - 1; i++) p[i] = %_Arguments(i); 1646 p = Join(p, n - 1, ',', NonStringToString); 1647 // If the formal parameters string include ) - an illegal 1648 // character - it may make the combined function expression 1649 // compile. We avoid this problem by checking for this early on. 1650 if (p.indexOf(')') != -1) throw MakeSyntaxError('unable_to_parse',[]); 1651 } 1652 var body = (n > 0) ? ToString(%_Arguments(n - 1)) : ''; 1653 var source = '(function(' + p + ') {\n' + body + '\n})'; 1654 1655 // The call to SetNewFunctionAttributes will ensure the prototype 1656 // property of the resulting function is enumerable (ECMA262, 15.3.5.2). 1657 var f = %CompileString(source)(); 1658 %FunctionMarkNameShouldPrintAsAnonymous(f); 1659 return %SetNewFunctionAttributes(f); 1660} 1661 1662%SetCode($Function, NewFunction); 1663 1664// ---------------------------------------------------------------------------- 1665 1666function SetUpFunction() { 1667 %CheckIsBootstrapping(); 1668 InstallFunctions($Function.prototype, DONT_ENUM, $Array( 1669 "bind", FunctionBind, 1670 "toString", FunctionToString 1671 )); 1672} 1673 1674SetUpFunction(); 1675