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(function(global, utils) { 6 7%CheckIsBootstrapping(); 8 9// ---------------------------------------------------------------------------- 10// Imports 11 12var GlobalArray = global.Array; 13var GlobalBoolean = global.Boolean; 14var GlobalNumber = global.Number; 15var GlobalObject = global.Object; 16var InternalArray = utils.InternalArray; 17var iteratorSymbol = utils.ImportNow("iterator_symbol"); 18var MakeRangeError; 19var MakeSyntaxError; 20var MakeTypeError; 21var MathAbs; 22var NaN = %GetRootNaN(); 23var ObjectToString = utils.ImportNow("object_to_string"); 24var ObserveBeginPerformSplice; 25var ObserveEndPerformSplice; 26var ObserveEnqueueSpliceRecord; 27var SameValue = utils.ImportNow("SameValue"); 28var toStringTagSymbol = utils.ImportNow("to_string_tag_symbol"); 29 30utils.Import(function(from) { 31 MakeRangeError = from.MakeRangeError; 32 MakeSyntaxError = from.MakeSyntaxError; 33 MakeTypeError = from.MakeTypeError; 34 MathAbs = from.MathAbs; 35 ObserveBeginPerformSplice = from.ObserveBeginPerformSplice; 36 ObserveEndPerformSplice = from.ObserveEndPerformSplice; 37 ObserveEnqueueSpliceRecord = from.ObserveEnqueueSpliceRecord; 38}); 39 40// ---------------------------------------------------------------------------- 41 42 43// ES6 18.2.3 isNaN(number) 44function GlobalIsNaN(number) { 45 number = TO_NUMBER(number); 46 return NUMBER_IS_NAN(number); 47} 48 49 50// ES6 18.2.2 isFinite(number) 51function GlobalIsFinite(number) { 52 number = TO_NUMBER(number); 53 return NUMBER_IS_FINITE(number); 54} 55 56 57// ES6 18.2.5 parseInt(string, radix) 58function GlobalParseInt(string, radix) { 59 if (IS_UNDEFINED(radix) || radix === 10 || radix === 0) { 60 // Some people use parseInt instead of Math.floor. This 61 // optimization makes parseInt on a Smi 12 times faster (60ns 62 // vs 800ns). The following optimization makes parseInt on a 63 // non-Smi number 9 times faster (230ns vs 2070ns). Together 64 // they make parseInt on a string 1.4% slower (274ns vs 270ns). 65 if (%_IsSmi(string)) return string; 66 if (IS_NUMBER(string) && 67 ((0.01 < string && string < 1e9) || 68 (-1e9 < string && string < -0.01))) { 69 // Truncate number. 70 return string | 0; 71 } 72 string = TO_STRING(string); 73 radix = radix | 0; 74 } else { 75 // The spec says ToString should be evaluated before ToInt32. 76 string = TO_STRING(string); 77 radix = TO_INT32(radix); 78 if (!(radix == 0 || (2 <= radix && radix <= 36))) { 79 return NaN; 80 } 81 } 82 83 if (%_HasCachedArrayIndex(string) && 84 (radix == 0 || radix == 10)) { 85 return %_GetCachedArrayIndex(string); 86 } 87 return %StringParseInt(string, radix); 88} 89 90 91// ES6 18.2.4 parseFloat(string) 92function GlobalParseFloat(string) { 93 // 1. Let inputString be ? ToString(string). 94 string = TO_STRING(string); 95 if (%_HasCachedArrayIndex(string)) return %_GetCachedArrayIndex(string); 96 return %StringParseFloat(string); 97} 98 99 100// ---------------------------------------------------------------------------- 101 102// Set up global object. 103var attributes = DONT_ENUM | DONT_DELETE | READ_ONLY; 104 105utils.InstallConstants(global, [ 106 // ES6 18.1.1 107 "Infinity", INFINITY, 108 // ES6 18.1.2 109 "NaN", NaN, 110 // ES6 18.1.3 111 "undefined", UNDEFINED, 112]); 113 114// Set up non-enumerable function on the global object. 115utils.InstallFunctions(global, DONT_ENUM, [ 116 "isNaN", GlobalIsNaN, 117 "isFinite", GlobalIsFinite, 118 "parseInt", GlobalParseInt, 119 "parseFloat", GlobalParseFloat, 120]); 121 122 123// ---------------------------------------------------------------------------- 124// Object 125 126// ES6 19.1.3.5 Object.prototype.toLocaleString([reserved1 [,reserved2]]) 127function ObjectToLocaleString() { 128 CHECK_OBJECT_COERCIBLE(this, "Object.prototype.toLocaleString"); 129 return this.toString(); 130} 131 132 133// ES6 19.1.3.7 Object.prototype.valueOf() 134function ObjectValueOf() { 135 return TO_OBJECT(this); 136} 137 138 139// ES6 7.3.11 140function ObjectHasOwnProperty(value) { 141 var name = TO_NAME(value); 142 var object = TO_OBJECT(this); 143 return %HasOwnProperty(object, name); 144} 145 146 147// ES6 19.1.3.3 Object.prototype.isPrototypeOf(V) 148function ObjectIsPrototypeOf(V) { 149 if (!IS_RECEIVER(V)) return false; 150 var O = TO_OBJECT(this); 151 return %HasInPrototypeChain(V, O); 152} 153 154 155// ES6 19.1.3.4 156function ObjectPropertyIsEnumerable(V) { 157 var P = TO_NAME(V); 158 return %PropertyIsEnumerable(TO_OBJECT(this), P); 159} 160 161 162// Extensions for providing property getters and setters. 163function ObjectDefineGetter(name, fun) { 164 var receiver = this; 165 if (IS_NULL(receiver) || IS_UNDEFINED(receiver)) { 166 receiver = %GlobalProxy(ObjectDefineGetter); 167 } 168 if (!IS_CALLABLE(fun)) { 169 throw MakeTypeError(kObjectGetterExpectingFunction); 170 } 171 var desc = new PropertyDescriptor(); 172 desc.setGet(fun); 173 desc.setEnumerable(true); 174 desc.setConfigurable(true); 175 DefineOwnProperty(TO_OBJECT(receiver), TO_NAME(name), desc, false); 176} 177 178 179function ObjectLookupGetter(name) { 180 var receiver = this; 181 if (IS_NULL(receiver) || IS_UNDEFINED(receiver)) { 182 receiver = %GlobalProxy(ObjectLookupGetter); 183 } 184 return %LookupAccessor(TO_OBJECT(receiver), TO_NAME(name), GETTER); 185} 186 187 188function ObjectDefineSetter(name, fun) { 189 var receiver = this; 190 if (IS_NULL(receiver) || IS_UNDEFINED(receiver)) { 191 receiver = %GlobalProxy(ObjectDefineSetter); 192 } 193 if (!IS_CALLABLE(fun)) { 194 throw MakeTypeError(kObjectSetterExpectingFunction); 195 } 196 var desc = new PropertyDescriptor(); 197 desc.setSet(fun); 198 desc.setEnumerable(true); 199 desc.setConfigurable(true); 200 DefineOwnProperty(TO_OBJECT(receiver), TO_NAME(name), desc, false); 201} 202 203 204function ObjectLookupSetter(name) { 205 var receiver = this; 206 if (IS_NULL(receiver) || IS_UNDEFINED(receiver)) { 207 receiver = %GlobalProxy(ObjectLookupSetter); 208 } 209 return %LookupAccessor(TO_OBJECT(receiver), TO_NAME(name), SETTER); 210} 211 212 213// ES6 6.2.4.1 214function IsAccessorDescriptor(desc) { 215 if (IS_UNDEFINED(desc)) return false; 216 return desc.hasGetter() || desc.hasSetter(); 217} 218 219 220// ES6 6.2.4.2 221function IsDataDescriptor(desc) { 222 if (IS_UNDEFINED(desc)) return false; 223 return desc.hasValue() || desc.hasWritable(); 224} 225 226 227// ES6 6.2.4.3 228function IsGenericDescriptor(desc) { 229 if (IS_UNDEFINED(desc)) return false; 230 return !(IsAccessorDescriptor(desc) || IsDataDescriptor(desc)); 231} 232 233 234function IsInconsistentDescriptor(desc) { 235 return IsAccessorDescriptor(desc) && IsDataDescriptor(desc); 236} 237 238 239// Harmony Proxies 240function FromGenericPropertyDescriptor(desc) { 241 if (IS_UNDEFINED(desc)) return desc; 242 var obj = new GlobalObject(); 243 244 if (desc.hasValue()) { 245 %AddNamedProperty(obj, "value", desc.getValue(), NONE); 246 } 247 if (desc.hasWritable()) { 248 %AddNamedProperty(obj, "writable", desc.isWritable(), NONE); 249 } 250 if (desc.hasGetter()) { 251 %AddNamedProperty(obj, "get", desc.getGet(), NONE); 252 } 253 if (desc.hasSetter()) { 254 %AddNamedProperty(obj, "set", desc.getSet(), NONE); 255 } 256 if (desc.hasEnumerable()) { 257 %AddNamedProperty(obj, "enumerable", desc.isEnumerable(), NONE); 258 } 259 if (desc.hasConfigurable()) { 260 %AddNamedProperty(obj, "configurable", desc.isConfigurable(), NONE); 261 } 262 return obj; 263} 264 265 266// ES6 6.2.4.5 267function ToPropertyDescriptor(obj) { 268 if (!IS_RECEIVER(obj)) throw MakeTypeError(kPropertyDescObject, obj); 269 270 var desc = new PropertyDescriptor(); 271 272 if ("enumerable" in obj) { 273 desc.setEnumerable(TO_BOOLEAN(obj.enumerable)); 274 } 275 276 if ("configurable" in obj) { 277 desc.setConfigurable(TO_BOOLEAN(obj.configurable)); 278 } 279 280 if ("value" in obj) { 281 desc.setValue(obj.value); 282 } 283 284 if ("writable" in obj) { 285 desc.setWritable(TO_BOOLEAN(obj.writable)); 286 } 287 288 if ("get" in obj) { 289 var get = obj.get; 290 if (!IS_UNDEFINED(get) && !IS_CALLABLE(get)) { 291 throw MakeTypeError(kObjectGetterCallable, get); 292 } 293 desc.setGet(get); 294 } 295 296 if ("set" in obj) { 297 var set = obj.set; 298 if (!IS_UNDEFINED(set) && !IS_CALLABLE(set)) { 299 throw MakeTypeError(kObjectSetterCallable, set); 300 } 301 desc.setSet(set); 302 } 303 304 if (IsInconsistentDescriptor(desc)) { 305 throw MakeTypeError(kValueAndAccessor, obj); 306 } 307 return desc; 308} 309 310// TODO(cbruni): remove once callers have been removed 311function ToCompletePropertyDescriptor(obj) { 312 var desc = ToPropertyDescriptor(obj); 313 if (IsGenericDescriptor(desc) || IsDataDescriptor(desc)) { 314 if (!desc.hasValue()) desc.setValue(UNDEFINED); 315 if (!desc.hasWritable()) desc.setWritable(false); 316 } else { 317 // Is accessor descriptor. 318 if (!desc.hasGetter()) desc.setGet(UNDEFINED); 319 if (!desc.hasSetter()) desc.setSet(UNDEFINED); 320 } 321 if (!desc.hasEnumerable()) desc.setEnumerable(false); 322 if (!desc.hasConfigurable()) desc.setConfigurable(false); 323 return desc; 324} 325 326 327function PropertyDescriptor() { 328 // Initialize here so they are all in-object and have the same map. 329 // Default values from ES5 8.6.1. 330 this.value_ = UNDEFINED; 331 this.hasValue_ = false; 332 this.writable_ = false; 333 this.hasWritable_ = false; 334 this.enumerable_ = false; 335 this.hasEnumerable_ = false; 336 this.configurable_ = false; 337 this.hasConfigurable_ = false; 338 this.get_ = UNDEFINED; 339 this.hasGetter_ = false; 340 this.set_ = UNDEFINED; 341 this.hasSetter_ = false; 342} 343 344utils.SetUpLockedPrototype(PropertyDescriptor, [ 345 "value_", 346 "hasValue_", 347 "writable_", 348 "hasWritable_", 349 "enumerable_", 350 "hasEnumerable_", 351 "configurable_", 352 "hasConfigurable_", 353 "get_", 354 "hasGetter_", 355 "set_", 356 "hasSetter_" 357], [ 358 "toString", function PropertyDescriptor_ToString() { 359 return "[object PropertyDescriptor]"; 360 }, 361 "setValue", function PropertyDescriptor_SetValue(value) { 362 this.value_ = value; 363 this.hasValue_ = true; 364 }, 365 "getValue", function PropertyDescriptor_GetValue() { 366 return this.value_; 367 }, 368 "hasValue", function PropertyDescriptor_HasValue() { 369 return this.hasValue_; 370 }, 371 "setEnumerable", function PropertyDescriptor_SetEnumerable(enumerable) { 372 this.enumerable_ = enumerable; 373 this.hasEnumerable_ = true; 374 }, 375 "isEnumerable", function PropertyDescriptor_IsEnumerable() { 376 return this.enumerable_; 377 }, 378 "hasEnumerable", function PropertyDescriptor_HasEnumerable() { 379 return this.hasEnumerable_; 380 }, 381 "setWritable", function PropertyDescriptor_SetWritable(writable) { 382 this.writable_ = writable; 383 this.hasWritable_ = true; 384 }, 385 "isWritable", function PropertyDescriptor_IsWritable() { 386 return this.writable_; 387 }, 388 "hasWritable", function PropertyDescriptor_HasWritable() { 389 return this.hasWritable_; 390 }, 391 "setConfigurable", 392 function PropertyDescriptor_SetConfigurable(configurable) { 393 this.configurable_ = configurable; 394 this.hasConfigurable_ = true; 395 }, 396 "hasConfigurable", function PropertyDescriptor_HasConfigurable() { 397 return this.hasConfigurable_; 398 }, 399 "isConfigurable", function PropertyDescriptor_IsConfigurable() { 400 return this.configurable_; 401 }, 402 "setGet", function PropertyDescriptor_SetGetter(get) { 403 this.get_ = get; 404 this.hasGetter_ = true; 405 }, 406 "getGet", function PropertyDescriptor_GetGetter() { 407 return this.get_; 408 }, 409 "hasGetter", function PropertyDescriptor_HasGetter() { 410 return this.hasGetter_; 411 }, 412 "setSet", function PropertyDescriptor_SetSetter(set) { 413 this.set_ = set; 414 this.hasSetter_ = true; 415 }, 416 "getSet", function PropertyDescriptor_GetSetter() { 417 return this.set_; 418 }, 419 "hasSetter", function PropertyDescriptor_HasSetter() { 420 return this.hasSetter_; 421 } 422]); 423 424 425// Converts an array returned from Runtime_GetOwnProperty to an actual 426// property descriptor. For a description of the array layout please 427// see the runtime.cc file. 428function ConvertDescriptorArrayToDescriptor(desc_array) { 429 if (IS_UNDEFINED(desc_array)) { 430 return UNDEFINED; 431 } 432 433 var desc = new PropertyDescriptor(); 434 // This is an accessor. 435 if (desc_array[IS_ACCESSOR_INDEX]) { 436 desc.setGet(desc_array[GETTER_INDEX]); 437 desc.setSet(desc_array[SETTER_INDEX]); 438 } else { 439 desc.setValue(desc_array[VALUE_INDEX]); 440 desc.setWritable(desc_array[WRITABLE_INDEX]); 441 } 442 desc.setEnumerable(desc_array[ENUMERABLE_INDEX]); 443 desc.setConfigurable(desc_array[CONFIGURABLE_INDEX]); 444 445 return desc; 446} 447 448 449// For Harmony proxies. 450function GetTrap(handler, name, defaultTrap) { 451 var trap = handler[name]; 452 if (IS_UNDEFINED(trap)) { 453 if (IS_UNDEFINED(defaultTrap)) { 454 throw MakeTypeError(kIllegalInvocation); 455 } 456 trap = defaultTrap; 457 } else if (!IS_CALLABLE(trap)) { 458 throw MakeTypeError(kIllegalInvocation); 459 } 460 return trap; 461} 462 463 464function CallTrap1(handler, name, defaultTrap, x) { 465 return %_Call(GetTrap(handler, name, defaultTrap), handler, x); 466} 467 468 469function CallTrap2(handler, name, defaultTrap, x, y) { 470 return %_Call(GetTrap(handler, name, defaultTrap), handler, x, y); 471} 472 473 474// ES5 section 8.12.1. 475// TODO(jkummerow): Deprecated. Migrate all callers to 476// ObjectGetOwnPropertyDescriptor and delete this. 477function GetOwnPropertyJS(obj, v) { 478 var p = TO_NAME(v); 479 if (IS_PROXY(obj)) { 480 // TODO(rossberg): adjust once there is a story for symbols vs proxies. 481 if (IS_SYMBOL(v)) return UNDEFINED; 482 483 var handler = %JSProxyGetHandler(obj); 484 var descriptor = CallTrap1( 485 handler, "getOwnPropertyDescriptor", UNDEFINED, p); 486 if (IS_UNDEFINED(descriptor)) return descriptor; 487 var desc = ToCompletePropertyDescriptor(descriptor); 488 if (!desc.isConfigurable()) { 489 throw MakeTypeError(kIllegalInvocation); 490 } 491 return desc; 492 } 493 494 // GetOwnProperty returns an array indexed by the constants 495 // defined in macros.py. 496 // If p is not a property on obj undefined is returned. 497 var props = %GetOwnProperty_Legacy(TO_OBJECT(obj), p); 498 499 return ConvertDescriptorArrayToDescriptor(props); 500} 501 502 503// ES6 7.3.9 504function GetMethod(obj, p) { 505 var func = obj[p]; 506 if (IS_NULL_OR_UNDEFINED(func)) return UNDEFINED; 507 if (IS_CALLABLE(func)) return func; 508 throw MakeTypeError(kCalledNonCallable, typeof func); 509} 510 511 512// Harmony proxies. 513function DefineProxyProperty(obj, p, attributes, should_throw) { 514 // TODO(rossberg): adjust once there is a story for symbols vs proxies. 515 if (IS_SYMBOL(p)) return false; 516 517 var handler = %JSProxyGetHandler(obj); 518 var result = CallTrap2(handler, "defineProperty", UNDEFINED, p, attributes); 519 if (!result) { 520 if (should_throw) { 521 throw MakeTypeError(kIllegalInvocation); 522 } else { 523 return false; 524 } 525 } 526 return true; 527} 528 529 530// ES6 9.1.6 [[DefineOwnProperty]](P, Desc) 531function DefineObjectProperty(obj, p, desc, should_throw) { 532 var current_array = %GetOwnProperty_Legacy(obj, TO_NAME(p)); 533 var current = ConvertDescriptorArrayToDescriptor(current_array); 534 var extensible = %object_is_extensible(obj); 535 536 if (IS_UNDEFINED(current) && !extensible) { 537 if (should_throw) { 538 throw MakeTypeError(kDefineDisallowed, p); 539 } else { 540 return false; 541 } 542 } 543 544 if (!IS_UNDEFINED(current)) { 545 if ((IsGenericDescriptor(desc) || 546 IsDataDescriptor(desc) == IsDataDescriptor(current)) && 547 (!desc.hasEnumerable() || 548 SameValue(desc.isEnumerable(), current.isEnumerable())) && 549 (!desc.hasConfigurable() || 550 SameValue(desc.isConfigurable(), current.isConfigurable())) && 551 (!desc.hasWritable() || 552 SameValue(desc.isWritable(), current.isWritable())) && 553 (!desc.hasValue() || 554 SameValue(desc.getValue(), current.getValue())) && 555 (!desc.hasGetter() || 556 SameValue(desc.getGet(), current.getGet())) && 557 (!desc.hasSetter() || 558 SameValue(desc.getSet(), current.getSet()))) { 559 return true; 560 } 561 if (!current.isConfigurable()) { 562 // Step 7 563 if (desc.isConfigurable() || 564 (desc.hasEnumerable() && 565 desc.isEnumerable() != current.isEnumerable())) { 566 if (should_throw) { 567 throw MakeTypeError(kRedefineDisallowed, p); 568 } else { 569 return false; 570 } 571 } 572 // Step 8 573 if (!IsGenericDescriptor(desc)) { 574 // Step 9a 575 if (IsDataDescriptor(current) != IsDataDescriptor(desc)) { 576 if (should_throw) { 577 throw MakeTypeError(kRedefineDisallowed, p); 578 } else { 579 return false; 580 } 581 } 582 // Step 10a 583 if (IsDataDescriptor(current) && IsDataDescriptor(desc)) { 584 var currentIsWritable = current.isWritable(); 585 if (currentIsWritable != desc.isWritable()) { 586 if (!currentIsWritable || IS_STRONG(obj)) { 587 if (should_throw) { 588 throw currentIsWritable 589 ? MakeTypeError(kStrongRedefineDisallowed, obj, p) 590 : MakeTypeError(kRedefineDisallowed, p); 591 } else { 592 return false; 593 } 594 } 595 } 596 if (!currentIsWritable && desc.hasValue() && 597 !SameValue(desc.getValue(), current.getValue())) { 598 if (should_throw) { 599 throw MakeTypeError(kRedefineDisallowed, p); 600 } else { 601 return false; 602 } 603 } 604 } 605 // Step 11 606 if (IsAccessorDescriptor(desc) && IsAccessorDescriptor(current)) { 607 if (desc.hasSetter() && 608 !SameValue(desc.getSet(), current.getSet())) { 609 if (should_throw) { 610 throw MakeTypeError(kRedefineDisallowed, p); 611 } else { 612 return false; 613 } 614 } 615 if (desc.hasGetter() && !SameValue(desc.getGet(),current.getGet())) { 616 if (should_throw) { 617 throw MakeTypeError(kRedefineDisallowed, p); 618 } else { 619 return false; 620 } 621 } 622 } 623 } 624 } 625 } 626 627 // Send flags - enumerable and configurable are common - writable is 628 // only send to the data descriptor. 629 // Take special care if enumerable and configurable is not defined on 630 // desc (we need to preserve the existing values from current). 631 var flag = NONE; 632 if (desc.hasEnumerable()) { 633 flag |= desc.isEnumerable() ? 0 : DONT_ENUM; 634 } else if (!IS_UNDEFINED(current)) { 635 flag |= current.isEnumerable() ? 0 : DONT_ENUM; 636 } else { 637 flag |= DONT_ENUM; 638 } 639 640 if (desc.hasConfigurable()) { 641 flag |= desc.isConfigurable() ? 0 : DONT_DELETE; 642 } else if (!IS_UNDEFINED(current)) { 643 flag |= current.isConfigurable() ? 0 : DONT_DELETE; 644 } else 645 flag |= DONT_DELETE; 646 647 if (IsDataDescriptor(desc) || 648 (IsGenericDescriptor(desc) && 649 (IS_UNDEFINED(current) || IsDataDescriptor(current)))) { 650 // There are 3 cases that lead here: 651 // Step 4a - defining a new data property. 652 // Steps 9b & 12 - replacing an existing accessor property with a data 653 // property. 654 // Step 12 - updating an existing data property with a data or generic 655 // descriptor. 656 657 if (desc.hasWritable()) { 658 flag |= desc.isWritable() ? 0 : READ_ONLY; 659 } else if (!IS_UNDEFINED(current)) { 660 flag |= current.isWritable() ? 0 : READ_ONLY; 661 } else { 662 flag |= READ_ONLY; 663 } 664 665 var value = UNDEFINED; // Default value is undefined. 666 if (desc.hasValue()) { 667 value = desc.getValue(); 668 } else if (!IS_UNDEFINED(current) && IsDataDescriptor(current)) { 669 value = current.getValue(); 670 } 671 672 %DefineDataPropertyUnchecked(obj, p, value, flag); 673 } else { 674 // There are 3 cases that lead here: 675 // Step 4b - defining a new accessor property. 676 // Steps 9c & 12 - replacing an existing data property with an accessor 677 // property. 678 // Step 12 - updating an existing accessor property with an accessor 679 // descriptor. 680 var getter = null; 681 if (desc.hasGetter()) { 682 getter = desc.getGet(); 683 } else if (IsAccessorDescriptor(current) && current.hasGetter()) { 684 getter = current.getGet(); 685 } 686 var setter = null; 687 if (desc.hasSetter()) { 688 setter = desc.getSet(); 689 } else if (IsAccessorDescriptor(current) && current.hasSetter()) { 690 setter = current.getSet(); 691 } 692 %DefineAccessorPropertyUnchecked(obj, p, getter, setter, flag); 693 } 694 return true; 695} 696 697 698// ES5 section 15.4.5.1. 699function DefineArrayProperty(obj, p, desc, should_throw) { 700 // Step 3 - Special handling for array index. 701 if (!IS_SYMBOL(p)) { 702 var index = TO_UINT32(p); 703 var emit_splice = false; 704 if (TO_STRING(index) == p && index != 4294967295) { 705 var length = obj.length; 706 if (index >= length && %IsObserved(obj)) { 707 emit_splice = true; 708 ObserveBeginPerformSplice(obj); 709 } 710 711 var length_desc = GetOwnPropertyJS(obj, "length"); 712 if ((index >= length && !length_desc.isWritable()) || 713 !DefineObjectProperty(obj, p, desc, true)) { 714 if (emit_splice) 715 ObserveEndPerformSplice(obj); 716 if (should_throw) { 717 throw MakeTypeError(kDefineDisallowed, p); 718 } else { 719 return false; 720 } 721 } 722 if (index >= length) { 723 obj.length = index + 1; 724 } 725 if (emit_splice) { 726 ObserveEndPerformSplice(obj); 727 ObserveEnqueueSpliceRecord(obj, length, [], index + 1 - length); 728 } 729 return true; 730 } 731 } 732 733 // Step 5 - Fallback to default implementation. 734 return DefineObjectProperty(obj, p, desc, should_throw); 735} 736 737 738// ES5 section 8.12.9, ES5 section 15.4.5.1 and Harmony proxies. 739function DefineOwnProperty(obj, p, desc, should_throw) { 740 if (IS_PROXY(obj)) { 741 // TODO(rossberg): adjust once there is a story for symbols vs proxies. 742 if (IS_SYMBOL(p)) return false; 743 744 var attributes = FromGenericPropertyDescriptor(desc); 745 return DefineProxyProperty(obj, p, attributes, should_throw); 746 } else if (IS_ARRAY(obj)) { 747 return DefineArrayProperty(obj, p, desc, should_throw); 748 } else { 749 return DefineObjectProperty(obj, p, desc, should_throw); 750 } 751} 752 753 754// ES6 section 19.1.2.9 755function ObjectGetPrototypeOf(obj) { 756 return %_GetPrototype(TO_OBJECT(obj)); 757} 758 759// ES6 section 19.1.2.18. 760function ObjectSetPrototypeOf(obj, proto) { 761 CHECK_OBJECT_COERCIBLE(obj, "Object.setPrototypeOf"); 762 763 if (proto !== null && !IS_RECEIVER(proto)) { 764 throw MakeTypeError(kProtoObjectOrNull, proto); 765 } 766 767 if (IS_RECEIVER(obj)) { 768 %SetPrototype(obj, proto); 769 } 770 771 return obj; 772} 773 774 775// ES6 section 19.1.2.6 776function ObjectGetOwnPropertyDescriptor(obj, p) { 777 return %GetOwnProperty(obj, p); 778} 779 780 781// ES5 section 15.2.3.4. 782function ObjectGetOwnPropertyNames(obj) { 783 obj = TO_OBJECT(obj); 784 return %GetOwnPropertyKeys(obj, PROPERTY_FILTER_SKIP_SYMBOLS); 785} 786 787 788// ES5 section 15.2.3.6. 789function ObjectDefineProperty(obj, p, attributes) { 790 // The new pure-C++ implementation doesn't support O.o. 791 // TODO(jkummerow): Implement missing features and remove fallback path. 792 if (%IsObserved(obj)) { 793 if (!IS_RECEIVER(obj)) { 794 throw MakeTypeError(kCalledOnNonObject, "Object.defineProperty"); 795 } 796 var name = TO_NAME(p); 797 var desc = ToPropertyDescriptor(attributes); 798 DefineOwnProperty(obj, name, desc, true); 799 return obj; 800 } 801 return %ObjectDefineProperty(obj, p, attributes); 802} 803 804 805function GetOwnEnumerablePropertyNames(object) { 806 return %GetOwnPropertyKeys(object, PROPERTY_FILTER_ONLY_ENUMERABLE); 807} 808 809 810// ES5 section 15.2.3.7. 811function ObjectDefineProperties(obj, properties) { 812 // The new pure-C++ implementation doesn't support O.o. 813 // TODO(jkummerow): Implement missing features and remove fallback path. 814 if (%IsObserved(obj)) { 815 if (!IS_RECEIVER(obj)) { 816 throw MakeTypeError(kCalledOnNonObject, "Object.defineProperties"); 817 } 818 var props = TO_OBJECT(properties); 819 var names = GetOwnEnumerablePropertyNames(props); 820 var descriptors = new InternalArray(); 821 for (var i = 0; i < names.length; i++) { 822 descriptors.push(ToPropertyDescriptor(props[names[i]])); 823 } 824 for (var i = 0; i < names.length; i++) { 825 DefineOwnProperty(obj, names[i], descriptors[i], true); 826 } 827 return obj; 828 } 829 return %ObjectDefineProperties(obj, properties); 830} 831 832 833// ES6 B.2.2.1.1 834function ObjectGetProto() { 835 return %_GetPrototype(TO_OBJECT(this)); 836} 837 838 839// ES6 B.2.2.1.2 840function ObjectSetProto(proto) { 841 CHECK_OBJECT_COERCIBLE(this, "Object.prototype.__proto__"); 842 843 if ((IS_RECEIVER(proto) || IS_NULL(proto)) && IS_RECEIVER(this)) { 844 %SetPrototype(this, proto); 845 } 846} 847 848 849// ES6 19.1.1.1 850function ObjectConstructor(x) { 851 if (GlobalObject != new.target && !IS_UNDEFINED(new.target)) { 852 return this; 853 } 854 if (IS_NULL(x) || IS_UNDEFINED(x)) return {}; 855 return TO_OBJECT(x); 856} 857 858 859// ---------------------------------------------------------------------------- 860// Object 861 862%SetNativeFlag(GlobalObject); 863%SetCode(GlobalObject, ObjectConstructor); 864 865%AddNamedProperty(GlobalObject.prototype, "constructor", GlobalObject, 866 DONT_ENUM); 867 868// Set up non-enumerable functions on the Object.prototype object. 869utils.InstallFunctions(GlobalObject.prototype, DONT_ENUM, [ 870 "toString", ObjectToString, 871 "toLocaleString", ObjectToLocaleString, 872 "valueOf", ObjectValueOf, 873 "hasOwnProperty", ObjectHasOwnProperty, 874 "isPrototypeOf", ObjectIsPrototypeOf, 875 "propertyIsEnumerable", ObjectPropertyIsEnumerable, 876 "__defineGetter__", ObjectDefineGetter, 877 "__lookupGetter__", ObjectLookupGetter, 878 "__defineSetter__", ObjectDefineSetter, 879 "__lookupSetter__", ObjectLookupSetter 880]); 881utils.InstallGetterSetter(GlobalObject.prototype, "__proto__", ObjectGetProto, 882 ObjectSetProto); 883 884// Set up non-enumerable functions in the Object object. 885utils.InstallFunctions(GlobalObject, DONT_ENUM, [ 886 // assign is added in bootstrapper.cc. 887 // keys is added in bootstrapper.cc. 888 "defineProperty", ObjectDefineProperty, 889 "defineProperties", ObjectDefineProperties, 890 "getPrototypeOf", ObjectGetPrototypeOf, 891 "setPrototypeOf", ObjectSetPrototypeOf, 892 "getOwnPropertyDescriptor", ObjectGetOwnPropertyDescriptor, 893 "getOwnPropertyNames", ObjectGetOwnPropertyNames, 894 // getOwnPropertySymbols is added in symbol.js. 895 "is", SameValue, // ECMA-262, Edition 6, section 19.1.2.10 896 // deliverChangeRecords, getNotifier, observe and unobserve are added 897 // in object-observe.js. 898]); 899 900 901// ---------------------------------------------------------------------------- 902// Boolean 903 904function BooleanConstructor(x) { 905 // TODO(bmeurer): Move this to toplevel. 906 "use strict"; 907 if (!IS_UNDEFINED(new.target)) { 908 %_SetValueOf(this, TO_BOOLEAN(x)); 909 } else { 910 return TO_BOOLEAN(x); 911 } 912} 913 914 915function BooleanToString() { 916 // NOTE: Both Boolean objects and values can enter here as 917 // 'this'. This is not as dictated by ECMA-262. 918 var b = this; 919 if (!IS_BOOLEAN(b)) { 920 if (!IS_BOOLEAN_WRAPPER(b)) { 921 throw MakeTypeError(kNotGeneric, 'Boolean.prototype.toString'); 922 } 923 b = %_ValueOf(b); 924 } 925 return b ? 'true' : 'false'; 926} 927 928 929function BooleanValueOf() { 930 // NOTE: Both Boolean objects and values can enter here as 931 // 'this'. This is not as dictated by ECMA-262. 932 if (!IS_BOOLEAN(this) && !IS_BOOLEAN_WRAPPER(this)) { 933 throw MakeTypeError(kNotGeneric, 'Boolean.prototype.valueOf'); 934 } 935 return %_ValueOf(this); 936} 937 938 939// ---------------------------------------------------------------------------- 940 941%SetCode(GlobalBoolean, BooleanConstructor); 942%FunctionSetPrototype(GlobalBoolean, new GlobalBoolean(false)); 943%AddNamedProperty(GlobalBoolean.prototype, "constructor", GlobalBoolean, 944 DONT_ENUM); 945 946utils.InstallFunctions(GlobalBoolean.prototype, DONT_ENUM, [ 947 "toString", BooleanToString, 948 "valueOf", BooleanValueOf 949]); 950 951 952// ---------------------------------------------------------------------------- 953// Number 954 955// ES6 Number.prototype.toString([ radix ]) 956function NumberToStringJS(radix) { 957 // NOTE: Both Number objects and values can enter here as 958 // 'this'. This is not as dictated by ECMA-262. 959 var number = this; 960 if (!IS_NUMBER(this)) { 961 if (!IS_NUMBER_WRAPPER(this)) { 962 throw MakeTypeError(kNotGeneric, 'Number.prototype.toString'); 963 } 964 // Get the value of this number in case it's an object. 965 number = %_ValueOf(this); 966 } 967 // Fast case: Convert number in radix 10. 968 if (IS_UNDEFINED(radix) || radix === 10) { 969 return %_NumberToString(number); 970 } 971 972 // Convert the radix to an integer and check the range. 973 radix = TO_INTEGER(radix); 974 if (radix < 2 || radix > 36) throw MakeRangeError(kToRadixFormatRange); 975 // Convert the number to a string in the given radix. 976 return %NumberToRadixString(number, radix); 977} 978 979 980// ES6 20.1.3.4 Number.prototype.toLocaleString([reserved1 [, reserved2]]) 981function NumberToLocaleString() { 982 return %_Call(NumberToStringJS, this); 983} 984 985 986// ES6 20.1.3.7 Number.prototype.valueOf() 987function NumberValueOf() { 988 // NOTE: Both Number objects and values can enter here as 989 // 'this'. This is not as dictated by ECMA-262. 990 if (!IS_NUMBER(this) && !IS_NUMBER_WRAPPER(this)) { 991 throw MakeTypeError(kNotGeneric, 'Number.prototype.valueOf'); 992 } 993 return %_ValueOf(this); 994} 995 996 997// ES6 20.1.3.3 Number.prototype.toFixed(fractionDigits) 998function NumberToFixedJS(fractionDigits) { 999 var x = this; 1000 if (!IS_NUMBER(this)) { 1001 if (!IS_NUMBER_WRAPPER(this)) { 1002 throw MakeTypeError(kIncompatibleMethodReceiver, 1003 "Number.prototype.toFixed", this); 1004 } 1005 // Get the value of this number in case it's an object. 1006 x = %_ValueOf(this); 1007 } 1008 var f = TO_INTEGER(fractionDigits); 1009 1010 if (f < 0 || f > 20) { 1011 throw MakeRangeError(kNumberFormatRange, "toFixed() digits"); 1012 } 1013 1014 if (NUMBER_IS_NAN(x)) return "NaN"; 1015 if (x == INFINITY) return "Infinity"; 1016 if (x == -INFINITY) return "-Infinity"; 1017 1018 return %NumberToFixed(x, f); 1019} 1020 1021 1022// ES6 20.1.3.2 Number.prototype.toExponential(fractionDigits) 1023function NumberToExponentialJS(fractionDigits) { 1024 var x = this; 1025 if (!IS_NUMBER(this)) { 1026 if (!IS_NUMBER_WRAPPER(this)) { 1027 throw MakeTypeError(kIncompatibleMethodReceiver, 1028 "Number.prototype.toExponential", this); 1029 } 1030 // Get the value of this number in case it's an object. 1031 x = %_ValueOf(this); 1032 } 1033 var f = IS_UNDEFINED(fractionDigits) ? UNDEFINED : TO_INTEGER(fractionDigits); 1034 1035 if (NUMBER_IS_NAN(x)) return "NaN"; 1036 if (x == INFINITY) return "Infinity"; 1037 if (x == -INFINITY) return "-Infinity"; 1038 1039 if (IS_UNDEFINED(f)) { 1040 f = -1; // Signal for runtime function that f is not defined. 1041 } else if (f < 0 || f > 20) { 1042 throw MakeRangeError(kNumberFormatRange, "toExponential()"); 1043 } 1044 return %NumberToExponential(x, f); 1045} 1046 1047 1048// ES6 20.1.3.5 Number.prototype.toPrecision(precision) 1049function NumberToPrecisionJS(precision) { 1050 var x = this; 1051 if (!IS_NUMBER(this)) { 1052 if (!IS_NUMBER_WRAPPER(this)) { 1053 throw MakeTypeError(kIncompatibleMethodReceiver, 1054 "Number.prototype.toPrecision", this); 1055 } 1056 // Get the value of this number in case it's an object. 1057 x = %_ValueOf(this); 1058 } 1059 if (IS_UNDEFINED(precision)) return TO_STRING(x); 1060 var p = TO_INTEGER(precision); 1061 1062 if (NUMBER_IS_NAN(x)) return "NaN"; 1063 if (x == INFINITY) return "Infinity"; 1064 if (x == -INFINITY) return "-Infinity"; 1065 1066 if (p < 1 || p > 21) { 1067 throw MakeRangeError(kToPrecisionFormatRange); 1068 } 1069 return %NumberToPrecision(x, p); 1070} 1071 1072 1073// Harmony isFinite. 1074function NumberIsFinite(number) { 1075 return IS_NUMBER(number) && NUMBER_IS_FINITE(number); 1076} 1077 1078 1079// Harmony isInteger 1080function NumberIsInteger(number) { 1081 return NumberIsFinite(number) && TO_INTEGER(number) == number; 1082} 1083 1084 1085// Harmony isNaN. 1086function NumberIsNaN(number) { 1087 return IS_NUMBER(number) && NUMBER_IS_NAN(number); 1088} 1089 1090 1091// Harmony isSafeInteger 1092function NumberIsSafeInteger(number) { 1093 if (NumberIsFinite(number)) { 1094 var integral = TO_INTEGER(number); 1095 if (integral == number) { 1096 return MathAbs(integral) <= kMaxSafeInteger; 1097 } 1098 } 1099 return false; 1100} 1101 1102 1103// ---------------------------------------------------------------------------- 1104 1105%FunctionSetPrototype(GlobalNumber, new GlobalNumber(0)); 1106 1107%OptimizeObjectForAddingMultipleProperties(GlobalNumber.prototype, 8); 1108// Set up the constructor property on the Number prototype object. 1109%AddNamedProperty(GlobalNumber.prototype, "constructor", GlobalNumber, 1110 DONT_ENUM); 1111 1112utils.InstallConstants(GlobalNumber, [ 1113 // ECMA-262 section 15.7.3.1. 1114 "MAX_VALUE", 1.7976931348623157e+308, 1115 // ECMA-262 section 15.7.3.2. 1116 "MIN_VALUE", 5e-324, 1117 // ECMA-262 section 15.7.3.3. 1118 "NaN", NaN, 1119 // ECMA-262 section 15.7.3.4. 1120 "NEGATIVE_INFINITY", -INFINITY, 1121 // ECMA-262 section 15.7.3.5. 1122 "POSITIVE_INFINITY", INFINITY, 1123 1124 // --- Harmony constants (no spec refs until settled.) 1125 1126 "MAX_SAFE_INTEGER", %_MathPow(2, 53) - 1, 1127 "MIN_SAFE_INTEGER", -%_MathPow(2, 53) + 1, 1128 "EPSILON", %_MathPow(2, -52) 1129]); 1130 1131// Set up non-enumerable functions on the Number prototype object. 1132utils.InstallFunctions(GlobalNumber.prototype, DONT_ENUM, [ 1133 "toString", NumberToStringJS, 1134 "toLocaleString", NumberToLocaleString, 1135 "valueOf", NumberValueOf, 1136 "toFixed", NumberToFixedJS, 1137 "toExponential", NumberToExponentialJS, 1138 "toPrecision", NumberToPrecisionJS 1139]); 1140 1141// Harmony Number constructor additions 1142utils.InstallFunctions(GlobalNumber, DONT_ENUM, [ 1143 "isFinite", NumberIsFinite, 1144 "isInteger", NumberIsInteger, 1145 "isNaN", NumberIsNaN, 1146 "isSafeInteger", NumberIsSafeInteger, 1147 "parseInt", GlobalParseInt, 1148 "parseFloat", GlobalParseFloat 1149]); 1150 1151%SetForceInlineFlag(NumberIsNaN); 1152 1153 1154// ---------------------------------------------------------------------------- 1155// Iterator related spec functions. 1156 1157// ES6 7.4.1 GetIterator(obj, method) 1158function GetIterator(obj, method) { 1159 if (IS_UNDEFINED(method)) { 1160 method = obj[iteratorSymbol]; 1161 } 1162 if (!IS_CALLABLE(method)) { 1163 throw MakeTypeError(kNotIterable, obj); 1164 } 1165 var iterator = %_Call(method, obj); 1166 if (!IS_RECEIVER(iterator)) { 1167 throw MakeTypeError(kNotAnIterator, iterator); 1168 } 1169 return iterator; 1170} 1171 1172// ---------------------------------------------------------------------------- 1173// Exports 1174 1175utils.Export(function(to) { 1176 to.GetIterator = GetIterator; 1177 to.GetMethod = GetMethod; 1178 to.IsFinite = GlobalIsFinite; 1179 to.IsNaN = GlobalIsNaN; 1180 to.NumberIsNaN = NumberIsNaN; 1181 to.ObjectDefineProperties = ObjectDefineProperties; 1182 to.ObjectDefineProperty = ObjectDefineProperty; 1183 to.ObjectHasOwnProperty = ObjectHasOwnProperty; 1184}); 1185 1186%InstallToContext([ 1187 "object_value_of", ObjectValueOf, 1188]); 1189 1190}) 1191