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