v8natives.js revision c7cc028aaeedbbfa11c11d0b7b243b3d9e837ed9
1// Copyright 2011 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// 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("obj_ctor_property_non_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 if (IsGenericDescriptor(desc)) { 838 // Step 12 - updating an existing accessor property with generic 839 // descriptor. Changing flags only. 840 %DefineOrRedefineAccessorProperty(obj, p, GETTER, current.getGet(), flag); 841 } else { 842 // There are 3 cases that lead here: 843 // Step 4b - defining a new accessor property. 844 // Steps 9c & 12 - replacing an existing data property with an accessor 845 // property. 846 // Step 12 - updating an existing accessor property with an accessor 847 // descriptor. 848 if (desc.hasGetter()) { 849 %DefineOrRedefineAccessorProperty(obj, p, GETTER, desc.getGet(), flag); 850 } 851 if (desc.hasSetter()) { 852 %DefineOrRedefineAccessorProperty(obj, p, SETTER, desc.getSet(), flag); 853 } 854 } 855 return true; 856} 857 858 859// ES5 section 15.4.5.1. 860function DefineArrayProperty(obj, p, desc, should_throw) { 861 // Note that the length of an array is not actually stored as part of the 862 // property, hence we use generated code throughout this function instead of 863 // DefineObjectProperty() to modify its value. 864 865 // Step 3 - Special handling for length property. 866 if (p == "length") { 867 var length = obj.length; 868 if (!desc.hasValue()) { 869 return DefineObjectProperty(obj, "length", desc, should_throw); 870 } 871 var new_length = ToUint32(desc.getValue()); 872 if (new_length != ToNumber(desc.getValue())) { 873 throw new $RangeError('defineProperty() array length out of range'); 874 } 875 var length_desc = GetOwnProperty(obj, "length"); 876 if (new_length != length && !length_desc.isWritable()) { 877 if (should_throw) { 878 throw MakeTypeError("redefine_disallowed", [p]); 879 } else { 880 return false; 881 } 882 } 883 var threw = false; 884 while (new_length < length--) { 885 if (!Delete(obj, ToString(length), false)) { 886 new_length = length + 1; 887 threw = true; 888 break; 889 } 890 } 891 // Make sure the below call to DefineObjectProperty() doesn't overwrite 892 // any magic "length" property by removing the value. 893 obj.length = new_length; 894 desc.value_ = void 0; 895 desc.hasValue_ = false; 896 if (!DefineObjectProperty(obj, "length", desc, should_throw) || threw) { 897 if (should_throw) { 898 throw MakeTypeError("redefine_disallowed", [p]); 899 } else { 900 return false; 901 } 902 } 903 return true; 904 } 905 906 // Step 4 - Special handling for array index. 907 var index = ToUint32(p); 908 if (index == ToNumber(p) && index != 4294967295) { 909 var length = obj.length; 910 var length_desc = GetOwnProperty(obj, "length"); 911 if ((index >= length && !length_desc.isWritable()) || 912 !DefineObjectProperty(obj, p, desc, true)) { 913 if (should_throw) { 914 throw MakeTypeError("define_disallowed", [p]); 915 } else { 916 return false; 917 } 918 } 919 if (index >= length) { 920 obj.length = index + 1; 921 } 922 return true; 923 } 924 925 // Step 5 - Fallback to default implementation. 926 return DefineObjectProperty(obj, p, desc, should_throw); 927} 928 929 930// ES5 section 8.12.9, ES5 section 15.4.5.1 and Harmony proxies. 931function DefineOwnProperty(obj, p, desc, should_throw) { 932 if (%IsJSProxy(obj)) { 933 var attributes = FromGenericPropertyDescriptor(desc); 934 return DefineProxyProperty(obj, p, attributes, should_throw); 935 } else if (IS_ARRAY(obj)) { 936 return DefineArrayProperty(obj, p, desc, should_throw); 937 } else { 938 return DefineObjectProperty(obj, p, desc, should_throw); 939 } 940} 941 942 943// ES5 section 15.2.3.2. 944function ObjectGetPrototypeOf(obj) { 945 if (!IS_SPEC_OBJECT(obj)) { 946 throw MakeTypeError("obj_ctor_property_non_object", ["getPrototypeOf"]); 947 } 948 return %GetPrototype(obj); 949} 950 951 952// ES5 section 15.2.3.3 953function ObjectGetOwnPropertyDescriptor(obj, p) { 954 if (!IS_SPEC_OBJECT(obj)) { 955 throw MakeTypeError("obj_ctor_property_non_object", 956 ["getOwnPropertyDescriptor"]); 957 } 958 var desc = GetOwnProperty(obj, p); 959 return FromPropertyDescriptor(desc); 960} 961 962 963// For Harmony proxies 964function ToStringArray(obj, trap) { 965 if (!IS_SPEC_OBJECT(obj)) { 966 throw MakeTypeError("proxy_non_object_prop_names", [obj, trap]); 967 } 968 var n = ToUint32(obj.length); 969 var array = new $Array(n); 970 var names = {}; // TODO(rossberg): use sets once they are ready. 971 for (var index = 0; index < n; index++) { 972 var s = ToString(obj[index]); 973 if (s in names) { 974 throw MakeTypeError("proxy_repeated_prop_name", [obj, trap, s]); 975 } 976 array[index] = s; 977 names[s] = 0; 978 } 979 return array; 980} 981 982 983// ES5 section 15.2.3.4. 984function ObjectGetOwnPropertyNames(obj) { 985 if (!IS_SPEC_OBJECT(obj)) { 986 throw MakeTypeError("obj_ctor_property_non_object", 987 ["getOwnPropertyNames"]); 988 } 989 // Special handling for proxies. 990 if (%IsJSProxy(obj)) { 991 var handler = %GetHandler(obj); 992 var names = CallTrap0(handler, "getOwnPropertyNames", void 0); 993 return ToStringArray(names, "getOwnPropertyNames"); 994 } 995 996 // Find all the indexed properties. 997 998 // Get the local element names. 999 var propertyNames = %GetLocalElementNames(obj); 1000 1001 // Get names for indexed interceptor properties. 1002 if (%GetInterceptorInfo(obj) & 1) { 1003 var indexedInterceptorNames = 1004 %GetIndexedInterceptorElementNames(obj); 1005 if (indexedInterceptorNames) { 1006 propertyNames = propertyNames.concat(indexedInterceptorNames); 1007 } 1008 } 1009 1010 // Find all the named properties. 1011 1012 // Get the local property names. 1013 propertyNames = propertyNames.concat(%GetLocalPropertyNames(obj)); 1014 1015 // Get names for named interceptor properties if any. 1016 1017 if (%GetInterceptorInfo(obj) & 2) { 1018 var namedInterceptorNames = 1019 %GetNamedInterceptorPropertyNames(obj); 1020 if (namedInterceptorNames) { 1021 propertyNames = propertyNames.concat(namedInterceptorNames); 1022 } 1023 } 1024 1025 // Property names are expected to be unique strings. 1026 var propertySet = {}; 1027 var j = 0; 1028 for (var i = 0; i < propertyNames.length; ++i) { 1029 var name = ToString(propertyNames[i]); 1030 // We need to check for the exact property value since for intrinsic 1031 // properties like toString if(propertySet["toString"]) will always 1032 // succeed. 1033 if (propertySet[name] === true) { 1034 continue; 1035 } 1036 propertySet[name] = true; 1037 propertyNames[j++] = name; 1038 } 1039 propertyNames.length = j; 1040 1041 return propertyNames; 1042} 1043 1044 1045// ES5 section 15.2.3.5. 1046function ObjectCreate(proto, properties) { 1047 if (!IS_SPEC_OBJECT(proto) && proto !== null) { 1048 throw MakeTypeError("proto_object_or_null", [proto]); 1049 } 1050 var obj = new $Object(); 1051 obj.__proto__ = proto; 1052 if (!IS_UNDEFINED(properties)) ObjectDefineProperties(obj, properties); 1053 return obj; 1054} 1055 1056 1057// ES5 section 15.2.3.6. 1058function ObjectDefineProperty(obj, p, attributes) { 1059 if (!IS_SPEC_OBJECT(obj)) { 1060 throw MakeTypeError("obj_ctor_property_non_object", ["defineProperty"]); 1061 } 1062 var name = ToString(p); 1063 if (%IsJSProxy(obj)) { 1064 // Clone the attributes object for protection. 1065 // TODO(rossberg): not spec'ed yet, so not sure if this should involve 1066 // non-own properties as it does (or non-enumerable ones, as it doesn't?). 1067 var attributesClone = {}; 1068 for (var a in attributes) { 1069 attributesClone[a] = attributes[a]; 1070 } 1071 DefineProxyProperty(obj, name, attributesClone, true); 1072 // The following would implement the spec as in the current proposal, 1073 // but after recent comments on es-discuss, is most likely obsolete. 1074 /* 1075 var defineObj = FromGenericPropertyDescriptor(desc); 1076 var names = ObjectGetOwnPropertyNames(attributes); 1077 var standardNames = 1078 {value: 0, writable: 0, get: 0, set: 0, enumerable: 0, configurable: 0}; 1079 for (var i = 0; i < names.length; i++) { 1080 var N = names[i]; 1081 if (!(%HasLocalProperty(standardNames, N))) { 1082 var attr = GetOwnProperty(attributes, N); 1083 DefineOwnProperty(descObj, N, attr, true); 1084 } 1085 } 1086 // This is really confusing the types, but it is what the proxies spec 1087 // currently requires: 1088 desc = descObj; 1089 */ 1090 } else { 1091 var desc = ToPropertyDescriptor(attributes); 1092 DefineOwnProperty(obj, name, desc, true); 1093 } 1094 return obj; 1095} 1096 1097 1098function GetOwnEnumerablePropertyNames(properties) { 1099 var names = new InternalArray(); 1100 for (var key in properties) { 1101 if (%HasLocalProperty(properties, key)) { 1102 names.push(key); 1103 } 1104 } 1105 return names; 1106} 1107 1108 1109// ES5 section 15.2.3.7. 1110function ObjectDefineProperties(obj, properties) { 1111 if (!IS_SPEC_OBJECT(obj)) { 1112 throw MakeTypeError("obj_ctor_property_non_object", ["defineProperties"]); 1113 } 1114 var props = ToObject(properties); 1115 var names = GetOwnEnumerablePropertyNames(props); 1116 var descriptors = new InternalArray(); 1117 for (var i = 0; i < names.length; i++) { 1118 descriptors.push(ToPropertyDescriptor(props[names[i]])); 1119 } 1120 for (var i = 0; i < names.length; i++) { 1121 DefineOwnProperty(obj, names[i], descriptors[i], true); 1122 } 1123 return obj; 1124} 1125 1126 1127// Harmony proxies. 1128function ProxyFix(obj) { 1129 var handler = %GetHandler(obj); 1130 var props = CallTrap0(handler, "fix", void 0); 1131 if (IS_UNDEFINED(props)) { 1132 throw MakeTypeError("handler_returned_undefined", [handler, "fix"]); 1133 } 1134 1135 if (%IsJSFunctionProxy(obj)) { 1136 var callTrap = %GetCallTrap(obj); 1137 var constructTrap = %GetConstructTrap(obj); 1138 var code = DelegateCallAndConstruct(callTrap, constructTrap); 1139 %Fix(obj); // becomes a regular function 1140 %SetCode(obj, code); 1141 // TODO(rossberg): What about length and other properties? Not specified. 1142 // We just put in some half-reasonable defaults for now. 1143 var prototype = new $Object(); 1144 $Object.defineProperty(prototype, "constructor", 1145 {value: obj, writable: true, enumerable: false, configurable: true}); 1146 // TODO(v8:1530): defineProperty does not handle prototype and length. 1147 %FunctionSetPrototype(obj, prototype); 1148 obj.length = 0; 1149 } else { 1150 %Fix(obj); 1151 } 1152 ObjectDefineProperties(obj, props); 1153} 1154 1155 1156// ES5 section 15.2.3.8. 1157function ObjectSeal(obj) { 1158 if (!IS_SPEC_OBJECT(obj)) { 1159 throw MakeTypeError("obj_ctor_property_non_object", ["seal"]); 1160 } 1161 if (%IsJSProxy(obj)) { 1162 ProxyFix(obj); 1163 } 1164 var names = ObjectGetOwnPropertyNames(obj); 1165 for (var i = 0; i < names.length; i++) { 1166 var name = names[i]; 1167 var desc = GetOwnProperty(obj, name); 1168 if (desc.isConfigurable()) { 1169 desc.setConfigurable(false); 1170 DefineOwnProperty(obj, name, desc, true); 1171 } 1172 } 1173 %PreventExtensions(obj); 1174 return obj; 1175} 1176 1177 1178// ES5 section 15.2.3.9. 1179function ObjectFreeze(obj) { 1180 if (!IS_SPEC_OBJECT(obj)) { 1181 throw MakeTypeError("obj_ctor_property_non_object", ["freeze"]); 1182 } 1183 if (%IsJSProxy(obj)) { 1184 ProxyFix(obj); 1185 } 1186 var names = ObjectGetOwnPropertyNames(obj); 1187 for (var i = 0; i < names.length; i++) { 1188 var name = names[i]; 1189 var desc = GetOwnProperty(obj, name); 1190 if (desc.isWritable() || desc.isConfigurable()) { 1191 if (IsDataDescriptor(desc)) desc.setWritable(false); 1192 desc.setConfigurable(false); 1193 DefineOwnProperty(obj, name, desc, true); 1194 } 1195 } 1196 %PreventExtensions(obj); 1197 return obj; 1198} 1199 1200 1201// ES5 section 15.2.3.10 1202function ObjectPreventExtension(obj) { 1203 if (!IS_SPEC_OBJECT(obj)) { 1204 throw MakeTypeError("obj_ctor_property_non_object", ["preventExtension"]); 1205 } 1206 if (%IsJSProxy(obj)) { 1207 ProxyFix(obj); 1208 } 1209 %PreventExtensions(obj); 1210 return obj; 1211} 1212 1213 1214// ES5 section 15.2.3.11 1215function ObjectIsSealed(obj) { 1216 if (!IS_SPEC_OBJECT(obj)) { 1217 throw MakeTypeError("obj_ctor_property_non_object", ["isSealed"]); 1218 } 1219 if (%IsJSProxy(obj)) { 1220 return false; 1221 } 1222 var names = ObjectGetOwnPropertyNames(obj); 1223 for (var i = 0; i < names.length; i++) { 1224 var name = names[i]; 1225 var desc = GetOwnProperty(obj, name); 1226 if (desc.isConfigurable()) return false; 1227 } 1228 if (!ObjectIsExtensible(obj)) { 1229 return true; 1230 } 1231 return false; 1232} 1233 1234 1235// ES5 section 15.2.3.12 1236function ObjectIsFrozen(obj) { 1237 if (!IS_SPEC_OBJECT(obj)) { 1238 throw MakeTypeError("obj_ctor_property_non_object", ["isFrozen"]); 1239 } 1240 if (%IsJSProxy(obj)) { 1241 return false; 1242 } 1243 var names = ObjectGetOwnPropertyNames(obj); 1244 for (var i = 0; i < names.length; i++) { 1245 var name = names[i]; 1246 var desc = GetOwnProperty(obj, name); 1247 if (IsDataDescriptor(desc) && desc.isWritable()) return false; 1248 if (desc.isConfigurable()) return false; 1249 } 1250 if (!ObjectIsExtensible(obj)) { 1251 return true; 1252 } 1253 return false; 1254} 1255 1256 1257// ES5 section 15.2.3.13 1258function ObjectIsExtensible(obj) { 1259 if (!IS_SPEC_OBJECT(obj)) { 1260 throw MakeTypeError("obj_ctor_property_non_object", ["isExtensible"]); 1261 } 1262 if (%IsJSProxy(obj)) { 1263 return true; 1264 } 1265 return %IsExtensible(obj); 1266} 1267 1268 1269%SetCode($Object, function(x) { 1270 if (%_IsConstructCall()) { 1271 if (x == null) return this; 1272 return ToObject(x); 1273 } else { 1274 if (x == null) return { }; 1275 return ToObject(x); 1276 } 1277}); 1278 1279%SetExpectedNumberOfProperties($Object, 4); 1280 1281// ---------------------------------------------------------------------------- 1282// Object 1283 1284function SetUpObject() { 1285 %CheckIsBootstrapping(); 1286 // Set Up non-enumerable functions on the Object.prototype object. 1287 InstallFunctions($Object.prototype, DONT_ENUM, $Array( 1288 "toString", ObjectToString, 1289 "toLocaleString", ObjectToLocaleString, 1290 "valueOf", ObjectValueOf, 1291 "hasOwnProperty", ObjectHasOwnProperty, 1292 "isPrototypeOf", ObjectIsPrototypeOf, 1293 "propertyIsEnumerable", ObjectPropertyIsEnumerable, 1294 "__defineGetter__", ObjectDefineGetter, 1295 "__lookupGetter__", ObjectLookupGetter, 1296 "__defineSetter__", ObjectDefineSetter, 1297 "__lookupSetter__", ObjectLookupSetter 1298 )); 1299 InstallFunctions($Object, DONT_ENUM, $Array( 1300 "keys", ObjectKeys, 1301 "create", ObjectCreate, 1302 "defineProperty", ObjectDefineProperty, 1303 "defineProperties", ObjectDefineProperties, 1304 "freeze", ObjectFreeze, 1305 "getPrototypeOf", ObjectGetPrototypeOf, 1306 "getOwnPropertyDescriptor", ObjectGetOwnPropertyDescriptor, 1307 "getOwnPropertyNames", ObjectGetOwnPropertyNames, 1308 "isExtensible", ObjectIsExtensible, 1309 "isFrozen", ObjectIsFrozen, 1310 "isSealed", ObjectIsSealed, 1311 "preventExtensions", ObjectPreventExtension, 1312 "seal", ObjectSeal 1313 )); 1314} 1315 1316SetUpObject(); 1317 1318// ---------------------------------------------------------------------------- 1319// Boolean 1320 1321function BooleanToString() { 1322 // NOTE: Both Boolean objects and values can enter here as 1323 // 'this'. This is not as dictated by ECMA-262. 1324 var b = this; 1325 if (!IS_BOOLEAN(b)) { 1326 if (!IS_BOOLEAN_WRAPPER(b)) { 1327 throw new $TypeError('Boolean.prototype.toString is not generic'); 1328 } 1329 b = %_ValueOf(b); 1330 } 1331 return b ? 'true' : 'false'; 1332} 1333 1334 1335function BooleanValueOf() { 1336 // NOTE: Both Boolean objects and values can enter here as 1337 // 'this'. This is not as dictated by ECMA-262. 1338 if (!IS_BOOLEAN(this) && !IS_BOOLEAN_WRAPPER(this)) { 1339 throw new $TypeError('Boolean.prototype.valueOf is not generic'); 1340 } 1341 return %_ValueOf(this); 1342} 1343 1344 1345// ---------------------------------------------------------------------------- 1346 1347 1348function SetUpBoolean () { 1349 %CheckIsBootstrapping(); 1350 InstallFunctions($Boolean.prototype, DONT_ENUM, $Array( 1351 "toString", BooleanToString, 1352 "valueOf", BooleanValueOf 1353 )); 1354} 1355 1356SetUpBoolean(); 1357 1358 1359// ---------------------------------------------------------------------------- 1360// Number 1361 1362// Set the Number function and constructor. 1363%SetCode($Number, function(x) { 1364 var value = %_ArgumentsLength() == 0 ? 0 : ToNumber(x); 1365 if (%_IsConstructCall()) { 1366 %_SetValueOf(this, value); 1367 } else { 1368 return value; 1369 } 1370}); 1371 1372%FunctionSetPrototype($Number, new $Number(0)); 1373 1374// ECMA-262 section 15.7.4.2. 1375function NumberToString(radix) { 1376 // NOTE: Both Number objects and values can enter here as 1377 // 'this'. This is not as dictated by ECMA-262. 1378 var number = this; 1379 if (!IS_NUMBER(this)) { 1380 if (!IS_NUMBER_WRAPPER(this)) { 1381 throw new $TypeError('Number.prototype.toString is not generic'); 1382 } 1383 // Get the value of this number in case it's an object. 1384 number = %_ValueOf(this); 1385 } 1386 // Fast case: Convert number in radix 10. 1387 if (IS_UNDEFINED(radix) || radix === 10) { 1388 return %_NumberToString(number); 1389 } 1390 1391 // Convert the radix to an integer and check the range. 1392 radix = TO_INTEGER(radix); 1393 if (radix < 2 || radix > 36) { 1394 throw new $RangeError('toString() radix argument must be between 2 and 36'); 1395 } 1396 // Convert the number to a string in the given radix. 1397 return %NumberToRadixString(number, radix); 1398} 1399 1400 1401// ECMA-262 section 15.7.4.3 1402function NumberToLocaleString() { 1403 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { 1404 throw MakeTypeError("called_on_null_or_undefined", 1405 ["Number.prototype.toLocaleString"]); 1406 } 1407 return this.toString(); 1408} 1409 1410 1411// ECMA-262 section 15.7.4.4 1412function NumberValueOf() { 1413 // NOTE: Both Number objects and values can enter here as 1414 // 'this'. This is not as dictated by ECMA-262. 1415 if (!IS_NUMBER(this) && !IS_NUMBER_WRAPPER(this)) { 1416 throw new $TypeError('Number.prototype.valueOf is not generic'); 1417 } 1418 return %_ValueOf(this); 1419} 1420 1421 1422// ECMA-262 section 15.7.4.5 1423function NumberToFixed(fractionDigits) { 1424 var f = TO_INTEGER(fractionDigits); 1425 if (f < 0 || f > 20) { 1426 throw new $RangeError("toFixed() digits argument must be between 0 and 20"); 1427 } 1428 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { 1429 throw MakeTypeError("called_on_null_or_undefined", 1430 ["Number.prototype.toFixed"]); 1431 } 1432 var x = ToNumber(this); 1433 return %NumberToFixed(x, f); 1434} 1435 1436 1437// ECMA-262 section 15.7.4.6 1438function NumberToExponential(fractionDigits) { 1439 var f = -1; 1440 if (!IS_UNDEFINED(fractionDigits)) { 1441 f = TO_INTEGER(fractionDigits); 1442 if (f < 0 || f > 20) { 1443 throw new $RangeError( 1444 "toExponential() argument must be between 0 and 20"); 1445 } 1446 } 1447 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { 1448 throw MakeTypeError("called_on_null_or_undefined", 1449 ["Number.prototype.toExponential"]); 1450 } 1451 var x = ToNumber(this); 1452 return %NumberToExponential(x, f); 1453} 1454 1455 1456// ECMA-262 section 15.7.4.7 1457function NumberToPrecision(precision) { 1458 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { 1459 throw MakeTypeError("called_on_null_or_undefined", 1460 ["Number.prototype.toPrecision"]); 1461 } 1462 if (IS_UNDEFINED(precision)) return ToString(%_ValueOf(this)); 1463 var p = TO_INTEGER(precision); 1464 if (p < 1 || p > 21) { 1465 throw new $RangeError("toPrecision() argument must be between 1 and 21"); 1466 } 1467 var x = ToNumber(this); 1468 return %NumberToPrecision(x, p); 1469} 1470 1471 1472// ---------------------------------------------------------------------------- 1473 1474function SetUpNumber() { 1475 %CheckIsBootstrapping(); 1476 %OptimizeObjectForAddingMultipleProperties($Number.prototype, 8); 1477 // Set up the constructor property on the Number prototype object. 1478 %SetProperty($Number.prototype, "constructor", $Number, DONT_ENUM); 1479 1480 %OptimizeObjectForAddingMultipleProperties($Number, 5); 1481 // ECMA-262 section 15.7.3.1. 1482 %SetProperty($Number, 1483 "MAX_VALUE", 1484 1.7976931348623157e+308, 1485 DONT_ENUM | DONT_DELETE | READ_ONLY); 1486 1487 // ECMA-262 section 15.7.3.2. 1488 %SetProperty($Number, "MIN_VALUE", 5e-324, 1489 DONT_ENUM | DONT_DELETE | READ_ONLY); 1490 1491 // ECMA-262 section 15.7.3.3. 1492 %SetProperty($Number, "NaN", $NaN, DONT_ENUM | DONT_DELETE | READ_ONLY); 1493 1494 // ECMA-262 section 15.7.3.4. 1495 %SetProperty($Number, 1496 "NEGATIVE_INFINITY", 1497 -1/0, 1498 DONT_ENUM | DONT_DELETE | READ_ONLY); 1499 1500 // ECMA-262 section 15.7.3.5. 1501 %SetProperty($Number, 1502 "POSITIVE_INFINITY", 1503 1/0, 1504 DONT_ENUM | DONT_DELETE | READ_ONLY); 1505 %ToFastProperties($Number); 1506 1507 // Set up non-enumerable functions on the Number prototype object. 1508 InstallFunctions($Number.prototype, DONT_ENUM, $Array( 1509 "toString", NumberToString, 1510 "toLocaleString", NumberToLocaleString, 1511 "valueOf", NumberValueOf, 1512 "toFixed", NumberToFixed, 1513 "toExponential", NumberToExponential, 1514 "toPrecision", NumberToPrecision 1515 )); 1516} 1517 1518SetUpNumber(); 1519 1520 1521// ---------------------------------------------------------------------------- 1522// Function 1523 1524$Function.prototype.constructor = $Function; 1525 1526function FunctionSourceString(func) { 1527 while (%IsJSFunctionProxy(func)) { 1528 func = %GetCallTrap(func); 1529 } 1530 1531 if (!IS_FUNCTION(func)) { 1532 throw new $TypeError('Function.prototype.toString is not generic'); 1533 } 1534 1535 var source = %FunctionGetSourceCode(func); 1536 if (!IS_STRING(source) || %FunctionIsBuiltin(func)) { 1537 var name = %FunctionGetName(func); 1538 if (name) { 1539 // Mimic what KJS does. 1540 return 'function ' + name + '() { [native code] }'; 1541 } else { 1542 return 'function () { [native code] }'; 1543 } 1544 } 1545 1546 var name = %FunctionNameShouldPrintAsAnonymous(func) 1547 ? 'anonymous' 1548 : %FunctionGetName(func); 1549 return 'function ' + name + source; 1550} 1551 1552 1553function FunctionToString() { 1554 return FunctionSourceString(this); 1555} 1556 1557 1558// ES5 15.3.4.5 1559function FunctionBind(this_arg) { // Length is 1. 1560 if (!IS_SPEC_FUNCTION(this)) { 1561 throw new $TypeError('Bind must be called on a function'); 1562 } 1563 var boundFunction = function () { 1564 // Poison .arguments and .caller, but is otherwise not detectable. 1565 "use strict"; 1566 // This function must not use any object literals (Object, Array, RegExp), 1567 // since the literals-array is being used to store the bound data. 1568 if (%_IsConstructCall()) { 1569 return %NewObjectFromBound(boundFunction); 1570 } 1571 var bindings = %BoundFunctionGetBindings(boundFunction); 1572 1573 var argc = %_ArgumentsLength(); 1574 if (argc == 0) { 1575 return %Apply(bindings[0], bindings[1], bindings, 2, bindings.length - 2); 1576 } 1577 if (bindings.length === 2) { 1578 return %Apply(bindings[0], bindings[1], arguments, 0, argc); 1579 } 1580 var bound_argc = bindings.length - 2; 1581 var argv = new InternalArray(bound_argc + argc); 1582 for (var i = 0; i < bound_argc; i++) { 1583 argv[i] = bindings[i + 2]; 1584 } 1585 for (var j = 0; j < argc; j++) { 1586 argv[i++] = %_Arguments(j); 1587 } 1588 return %Apply(bindings[0], bindings[1], argv, 0, bound_argc + argc); 1589 }; 1590 1591 %FunctionRemovePrototype(boundFunction); 1592 var new_length = 0; 1593 if (%_ClassOf(this) == "Function") { 1594 // Function or FunctionProxy. 1595 var old_length = this.length; 1596 // FunctionProxies might provide a non-UInt32 value. If so, ignore it. 1597 if ((typeof old_length === "number") && 1598 ((old_length >>> 0) === old_length)) { 1599 var argc = %_ArgumentsLength(); 1600 if (argc > 0) argc--; // Don't count the thisArg as parameter. 1601 new_length = old_length - argc; 1602 if (new_length < 0) new_length = 0; 1603 } 1604 } 1605 // This runtime function finds any remaining arguments on the stack, 1606 // so we don't pass the arguments object. 1607 var result = %FunctionBindArguments(boundFunction, this, 1608 this_arg, new_length); 1609 1610 // We already have caller and arguments properties on functions, 1611 // which are non-configurable. It therefore makes no sence to 1612 // try to redefine these as defined by the spec. The spec says 1613 // that bind should make these throw a TypeError if get or set 1614 // is called and make them non-enumerable and non-configurable. 1615 // To be consistent with our normal functions we leave this as it is. 1616 // TODO(lrn): Do set these to be thrower. 1617 return result; 1618} 1619 1620 1621function NewFunction(arg1) { // length == 1 1622 var n = %_ArgumentsLength(); 1623 var p = ''; 1624 if (n > 1) { 1625 p = new InternalArray(n - 1); 1626 for (var i = 0; i < n - 1; i++) p[i] = %_Arguments(i); 1627 p = Join(p, n - 1, ',', NonStringToString); 1628 // If the formal parameters string include ) - an illegal 1629 // character - it may make the combined function expression 1630 // compile. We avoid this problem by checking for this early on. 1631 if (p.indexOf(')') != -1) throw MakeSyntaxError('unable_to_parse',[]); 1632 } 1633 var body = (n > 0) ? ToString(%_Arguments(n - 1)) : ''; 1634 var source = '(function(' + p + ') {\n' + body + '\n})'; 1635 1636 // The call to SetNewFunctionAttributes will ensure the prototype 1637 // property of the resulting function is enumerable (ECMA262, 15.3.5.2). 1638 var f = %CompileString(source)(); 1639 %FunctionMarkNameShouldPrintAsAnonymous(f); 1640 return %SetNewFunctionAttributes(f); 1641} 1642 1643%SetCode($Function, NewFunction); 1644 1645// ---------------------------------------------------------------------------- 1646 1647function SetUpFunction() { 1648 %CheckIsBootstrapping(); 1649 InstallFunctions($Function.prototype, DONT_ENUM, $Array( 1650 "bind", FunctionBind, 1651 "toString", FunctionToString 1652 )); 1653} 1654 1655SetUpFunction(); 1656