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