1 // Copyright 2012 the V8 project authors. All rights reserved. 2 // Redistribution and use in source and binary forms, with or without 3 // modification, are permitted provided that the following conditions are 4 // met: 5 // 6 // * Redistributions of source code must retain the above copyright 7 // notice, this list of conditions and the following disclaimer. 8 // * Redistributions in binary form must reproduce the above 9 // copyright notice, this list of conditions and the following 10 // disclaimer in the documentation and/or other materials provided 11 // with the distribution. 12 // * Neither the name of Google Inc. nor the names of its 13 // contributors may be used to endorse or promote products derived 14 // from this software without specific prior written permission. 15 // 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28 // Tests the object.defineProperty method - ES 15.2.3.6 29 30 // Flags: --allow-natives-syntax 31 32 // Check that an exception is thrown when null is passed as object. 33 var exception = false; 34 try { 35 Object.defineProperty(null, null, null); 36 } catch (e) { 37 exception = true; 38 assertTrue(/called on non-object/.test(e)); 39 } 40 assertTrue(exception); 41 42 // Check that an exception is thrown when undefined is passed as object. 43 exception = false; 44 try { 45 Object.defineProperty(undefined, undefined, undefined); 46 } catch (e) { 47 exception = true; 48 assertTrue(/called on non-object/.test(e)); 49 } 50 assertTrue(exception); 51 52 // Check that an exception is thrown when non-object is passed as object. 53 exception = false; 54 try { 55 Object.defineProperty(0, "foo", undefined); 56 } catch (e) { 57 exception = true; 58 assertTrue(/called on non-object/.test(e)); 59 } 60 assertTrue(exception); 61 62 // Object. 63 var obj1 = {}; 64 65 // Values. 66 var val1 = 0; 67 var val2 = 0; 68 var val3 = 0; 69 70 function setter1() {val1++; } 71 function getter1() {return val1; } 72 73 function setter2() {val2++; } 74 function getter2() {return val2; } 75 76 function setter3() {val3++; } 77 function getter3() {return val3; } 78 79 80 // Descriptors. 81 var emptyDesc = {}; 82 83 var accessorConfigurable = { 84 set: setter1, 85 get: getter1, 86 configurable: true 87 }; 88 89 var accessorNoConfigurable = { 90 set: setter2, 91 get: getter2, 92 configurable: false 93 }; 94 95 var accessorOnlySet = { 96 set: setter3, 97 configurable: true 98 }; 99 100 var accessorOnlyGet = { 101 get: getter3, 102 configurable: true 103 }; 104 105 var accessorDefault = {set: function(){} }; 106 107 var dataConfigurable = { value: 1000, configurable: true }; 108 109 var dataNoConfigurable = { value: 2000, configurable: false }; 110 111 var dataWritable = { value: 3000, writable: true}; 112 113 114 // Check that we can't add property with undefined attributes. 115 try { 116 Object.defineProperty(obj1, "foo", undefined); 117 assertTrue(false); 118 } catch (e) { 119 assertTrue(/must be an object/.test(e)); 120 } 121 122 // Make sure that we can add a property with an empty descriptor and 123 // that it has the default descriptor values. 124 Object.defineProperty(obj1, "foo", emptyDesc); 125 126 // foo should be undefined as it has no get, set or value 127 assertEquals(undefined, obj1.foo); 128 129 // We should, however, be able to retrieve the propertydescriptor which should 130 // have all default values (according to 8.6.1). 131 var desc = Object.getOwnPropertyDescriptor(obj1, "foo"); 132 assertFalse(desc.configurable); 133 assertFalse(desc.enumerable); 134 assertFalse(desc.writable); 135 assertEquals(desc.get, undefined); 136 assertEquals(desc.set, undefined); 137 assertEquals(desc.value, undefined); 138 139 // Make sure that getOwnPropertyDescriptor does not return a descriptor 140 // with default values if called with non existing property (otherwise 141 // the test above is invalid). 142 desc = Object.getOwnPropertyDescriptor(obj1, "bar"); 143 assertEquals(desc, undefined); 144 145 // Make sure that foo can't be reset (as configurable is false). 146 try { 147 Object.defineProperty(obj1, "foo", accessorConfigurable); 148 } catch (e) { 149 assertTrue(/Cannot redefine property/.test(e)); 150 } 151 152 153 // Accessor properties 154 155 Object.defineProperty(obj1, "bar", accessorConfigurable); 156 desc = Object.getOwnPropertyDescriptor(obj1, "bar"); 157 assertTrue(desc.configurable); 158 assertFalse(desc.enumerable); 159 assertEquals(desc.writable, undefined); 160 assertEquals(desc.get, accessorConfigurable.get); 161 assertEquals(desc.set, accessorConfigurable.set); 162 assertEquals(desc.value, undefined); 163 assertEquals(1, obj1.bar = 1); 164 assertEquals(1, val1); 165 assertEquals(1, obj1.bar = 1); 166 assertEquals(2, val1); 167 assertEquals(2, obj1.bar); 168 169 // Redefine bar with non configurable test 170 Object.defineProperty(obj1, "bar", accessorNoConfigurable); 171 desc = Object.getOwnPropertyDescriptor(obj1, "bar"); 172 assertFalse(desc.configurable); 173 assertFalse(desc.enumerable); 174 assertEquals(desc.writable, undefined); 175 assertEquals(desc.get, accessorNoConfigurable.get); 176 assertEquals(desc.set, accessorNoConfigurable.set); 177 assertEquals(desc.value, undefined); 178 assertEquals(1, obj1.bar = 1); 179 assertEquals(2, val1); 180 assertEquals(1, val2); 181 assertEquals(1, obj1.bar = 1) 182 assertEquals(2, val1); 183 assertEquals(2, val2); 184 assertEquals(2, obj1.bar); 185 186 // Try to redefine bar again - should fail as configurable is false. 187 try { 188 Object.defineProperty(obj1, "bar", accessorConfigurable); 189 assertTrue(false); 190 } catch(e) { 191 assertTrue(/Cannot redefine property/.test(e)); 192 } 193 194 // Try to redefine bar again using the data descriptor - should fail. 195 try { 196 Object.defineProperty(obj1, "bar", dataConfigurable); 197 assertTrue(false); 198 } catch(e) { 199 assertTrue(/Cannot redefine property/.test(e)); 200 } 201 202 // Redefine using same descriptor - should succeed. 203 Object.defineProperty(obj1, "bar", accessorNoConfigurable); 204 desc = Object.getOwnPropertyDescriptor(obj1, "bar"); 205 assertFalse(desc.configurable); 206 assertFalse(desc.enumerable); 207 assertEquals(desc.writable, undefined); 208 assertEquals(desc.get, accessorNoConfigurable.get); 209 assertEquals(desc.set, accessorNoConfigurable.set); 210 assertEquals(desc.value, undefined); 211 assertEquals(1, obj1.bar = 1); 212 assertEquals(2, val1); 213 assertEquals(3, val2); 214 assertEquals(1, obj1.bar = 1) 215 assertEquals(2, val1); 216 assertEquals(4, val2); 217 assertEquals(4, obj1.bar); 218 219 // Define an accessor that has only a setter. 220 Object.defineProperty(obj1, "setOnly", accessorOnlySet); 221 desc = Object.getOwnPropertyDescriptor(obj1, "setOnly"); 222 assertTrue(desc.configurable); 223 assertFalse(desc.enumerable); 224 assertEquals(desc.set, accessorOnlySet.set); 225 assertEquals(desc.writable, undefined); 226 assertEquals(desc.value, undefined); 227 assertEquals(desc.get, undefined); 228 assertEquals(1, obj1.setOnly = 1); 229 assertEquals(1, val3); 230 231 // Add a getter - should not touch the setter. 232 Object.defineProperty(obj1, "setOnly", accessorOnlyGet); 233 desc = Object.getOwnPropertyDescriptor(obj1, "setOnly"); 234 assertTrue(desc.configurable); 235 assertFalse(desc.enumerable); 236 assertEquals(desc.get, accessorOnlyGet.get); 237 assertEquals(desc.set, accessorOnlySet.set); 238 assertEquals(desc.writable, undefined); 239 assertEquals(desc.value, undefined); 240 assertEquals(1, obj1.setOnly = 1); 241 assertEquals(2, val3); 242 243 // The above should also work if redefining just a getter or setter on 244 // an existing property with both a getter and a setter. 245 Object.defineProperty(obj1, "both", accessorConfigurable); 246 247 Object.defineProperty(obj1, "both", accessorOnlySet); 248 desc = Object.getOwnPropertyDescriptor(obj1, "both"); 249 assertTrue(desc.configurable); 250 assertFalse(desc.enumerable); 251 assertEquals(desc.set, accessorOnlySet.set); 252 assertEquals(desc.get, accessorConfigurable.get); 253 assertEquals(desc.writable, undefined); 254 assertEquals(desc.value, undefined); 255 assertEquals(1, obj1.both = 1); 256 assertEquals(3, val3); 257 258 259 // Data properties 260 261 Object.defineProperty(obj1, "foobar", dataConfigurable); 262 desc = Object.getOwnPropertyDescriptor(obj1, "foobar"); 263 assertEquals(obj1.foobar, 1000); 264 assertEquals(desc.value, 1000); 265 assertTrue(desc.configurable); 266 assertFalse(desc.writable); 267 assertFalse(desc.enumerable); 268 assertEquals(desc.get, undefined); 269 assertEquals(desc.set, undefined); 270 //Try writing to non writable attribute - should remain 1000 271 obj1.foobar = 1001; 272 assertEquals(obj1.foobar, 1000); 273 274 275 // Redefine to writable descriptor - now writing to foobar should be allowed. 276 Object.defineProperty(obj1, "foobar", dataWritable); 277 desc = Object.getOwnPropertyDescriptor(obj1, "foobar"); 278 assertEquals(obj1.foobar, 3000); 279 assertEquals(desc.value, 3000); 280 // Note that since dataWritable does not define configurable the configurable 281 // setting from the redefined property (in this case true) is used. 282 assertTrue(desc.configurable); 283 assertTrue(desc.writable); 284 assertFalse(desc.enumerable); 285 assertEquals(desc.get, undefined); 286 assertEquals(desc.set, undefined); 287 // Writing to the property should now be allowed 288 obj1.foobar = 1001; 289 assertEquals(obj1.foobar, 1001); 290 291 292 // Redefine with non configurable data property. 293 Object.defineProperty(obj1, "foobar", dataNoConfigurable); 294 desc = Object.getOwnPropertyDescriptor(obj1, "foobar"); 295 assertEquals(obj1.foobar, 2000); 296 assertEquals(desc.value, 2000); 297 assertFalse(desc.configurable); 298 assertTrue(desc.writable); 299 assertFalse(desc.enumerable); 300 assertEquals(desc.get, undefined); 301 assertEquals(desc.set, undefined); 302 303 // Try redefine again - shold fail because configurable is now false. 304 try { 305 Object.defineProperty(obj1, "foobar", dataConfigurable); 306 assertTrue(false); 307 } catch (e) { 308 assertTrue(/Cannot redefine property/.test(e)); 309 } 310 311 // Try redefine again with accessor property - shold also fail. 312 try { 313 Object.defineProperty(obj1, "foobar", dataConfigurable); 314 assertTrue(false); 315 } catch (e) { 316 assertTrue(/Cannot redefine property/.test(e)); 317 } 318 319 320 // Redifine with the same descriptor - should succeed (step 6). 321 Object.defineProperty(obj1, "foobar", dataNoConfigurable); 322 desc = Object.getOwnPropertyDescriptor(obj1, "foobar"); 323 assertEquals(obj1.foobar, 2000); 324 assertEquals(desc.value, 2000); 325 assertFalse(desc.configurable); 326 assertTrue(desc.writable); 327 assertFalse(desc.enumerable); 328 assertEquals(desc.get, undefined); 329 assertEquals(desc.set, undefined); 330 331 332 // New object 333 var obj2 = {}; 334 335 // Make accessor - redefine to data 336 Object.defineProperty(obj2, "foo", accessorConfigurable); 337 338 // Redefine to data property 339 Object.defineProperty(obj2, "foo", dataConfigurable); 340 desc = Object.getOwnPropertyDescriptor(obj2, "foo"); 341 assertEquals(obj2.foo, 1000); 342 assertEquals(desc.value, 1000); 343 assertTrue(desc.configurable); 344 assertFalse(desc.writable); 345 assertFalse(desc.enumerable); 346 assertEquals(desc.get, undefined); 347 assertEquals(desc.set, undefined); 348 349 350 // Redefine back to accessor 351 Object.defineProperty(obj2, "foo", accessorConfigurable); 352 desc = Object.getOwnPropertyDescriptor(obj2, "foo"); 353 assertTrue(desc.configurable); 354 assertFalse(desc.enumerable); 355 assertEquals(desc.writable, undefined); 356 assertEquals(desc.get, accessorConfigurable.get); 357 assertEquals(desc.set, accessorConfigurable.set); 358 assertEquals(desc.value, undefined); 359 assertEquals(1, obj2.foo = 1); 360 assertEquals(3, val1); 361 assertEquals(4, val2); 362 assertEquals(3, obj2.foo); 363 364 // Make data - redefine to accessor 365 Object.defineProperty(obj2, "bar", dataConfigurable) 366 367 // Redefine to accessor property 368 Object.defineProperty(obj2, "bar", accessorConfigurable); 369 desc = Object.getOwnPropertyDescriptor(obj2, "bar"); 370 assertTrue(desc.configurable); 371 assertFalse(desc.enumerable); 372 assertEquals(desc.writable, undefined); 373 assertEquals(desc.get, accessorConfigurable.get); 374 assertEquals(desc.set, accessorConfigurable.set); 375 assertEquals(desc.value, undefined); 376 assertEquals(1, obj2.bar = 1); 377 assertEquals(4, val1); 378 assertEquals(4, val2); 379 assertEquals(4, obj2.foo); 380 381 // Redefine back to data property 382 Object.defineProperty(obj2, "bar", dataConfigurable); 383 desc = Object.getOwnPropertyDescriptor(obj2, "bar"); 384 assertEquals(obj2.bar, 1000); 385 assertEquals(desc.value, 1000); 386 assertTrue(desc.configurable); 387 assertFalse(desc.writable); 388 assertFalse(desc.enumerable); 389 assertEquals(desc.get, undefined); 390 assertEquals(desc.set, undefined); 391 392 393 // Redefinition of an accessor defined using __defineGetter__ and 394 // __defineSetter__. 395 function get(){return this.x} 396 function set(x){this.x=x}; 397 398 var obj3 = {x:1000}; 399 obj3.__defineGetter__("foo", get); 400 obj3.__defineSetter__("foo", set); 401 402 desc = Object.getOwnPropertyDescriptor(obj3, "foo"); 403 assertTrue(desc.configurable); 404 assertTrue(desc.enumerable); 405 assertEquals(desc.writable, undefined); 406 assertEquals(desc.get, get); 407 assertEquals(desc.set, set); 408 assertEquals(desc.value, undefined); 409 assertEquals(1, obj3.foo = 1); 410 assertEquals(1, obj3.x); 411 assertEquals(1, obj3.foo); 412 413 // Redefine to accessor property (non configurable) - note that enumerable 414 // which we do not redefine should remain the same (true). 415 Object.defineProperty(obj3, "foo", accessorNoConfigurable); 416 desc = Object.getOwnPropertyDescriptor(obj3, "foo"); 417 assertFalse(desc.configurable); 418 assertTrue(desc.enumerable); 419 assertEquals(desc.writable, undefined); 420 assertEquals(desc.get, accessorNoConfigurable.get); 421 assertEquals(desc.set, accessorNoConfigurable.set); 422 assertEquals(desc.value, undefined); 423 assertEquals(1, obj3.foo = 1); 424 assertEquals(5, val2); 425 assertEquals(5, obj3.foo); 426 427 428 obj3.__defineGetter__("bar", get); 429 obj3.__defineSetter__("bar", set); 430 431 432 // Redefine back to data property 433 Object.defineProperty(obj3, "bar", dataConfigurable); 434 desc = Object.getOwnPropertyDescriptor(obj3, "bar"); 435 assertEquals(obj3.bar, 1000); 436 assertEquals(desc.value, 1000); 437 assertTrue(desc.configurable); 438 assertFalse(desc.writable); 439 assertTrue(desc.enumerable); 440 assertEquals(desc.get, undefined); 441 assertEquals(desc.set, undefined); 442 443 444 var obj4 = {}; 445 var func = function (){return 42;}; 446 obj4.bar = func; 447 assertEquals(42, obj4.bar()); 448 449 Object.defineProperty(obj4, "bar", accessorConfigurable); 450 desc = Object.getOwnPropertyDescriptor(obj4, "bar"); 451 assertTrue(desc.configurable); 452 assertTrue(desc.enumerable); 453 assertEquals(desc.writable, undefined); 454 assertEquals(desc.get, accessorConfigurable.get); 455 assertEquals(desc.set, accessorConfigurable.set); 456 assertEquals(desc.value, undefined); 457 assertEquals(1, obj4.bar = 1); 458 assertEquals(5, val1); 459 assertEquals(5, obj4.bar); 460 461 // Make sure an error is thrown when trying to access to redefined function. 462 try { 463 obj4.bar(); 464 assertTrue(false); 465 } catch (e) { 466 assertTrue(/is not a function/.test(e)); 467 } 468 469 470 // Test runtime calls to DefineAccessorPropertyUnchecked - make sure we don't 471 // crash. 472 try { 473 %DefineAccessorPropertyUnchecked(0, 0, 0, 0, 0); 474 } catch (e) { 475 assertTrue(/illegal access/.test(e)); 476 } 477 478 try { 479 %DefineAccessorPropertyUnchecked(null, null, null, null, null); 480 } catch (e) { 481 assertTrue(/illegal access/.test(e)); 482 } 483 484 // Defining properties null should fail even when we have 485 // other allowed values 486 try { 487 %DefineAccessorPropertyUnchecked(null, 'foo', func, null, 0); 488 } catch (e) { 489 assertTrue(/illegal access/.test(e)); 490 } 491 492 // Test that all possible differences in step 6 in DefineOwnProperty are 493 // exercised, i.e., any difference in the given property descriptor and the 494 // existing properties should not return true, but throw an error if the 495 // existing configurable property is false. 496 497 var obj5 = {}; 498 // Enumerable will default to false. 499 Object.defineProperty(obj5, 'foo', accessorNoConfigurable); 500 desc = Object.getOwnPropertyDescriptor(obj5, 'foo'); 501 // First, test that we are actually allowed to set the accessor if all 502 // values are of the descriptor are the same as the existing one. 503 Object.defineProperty(obj5, 'foo', accessorNoConfigurable); 504 505 // Different setter. 506 var descDifferent = { 507 configurable:false, 508 enumerable:false, 509 set: setter1, 510 get: getter2 511 }; 512 513 try { 514 Object.defineProperty(obj5, 'foo', descDifferent); 515 assertTrue(false); 516 } catch (e) { 517 assertTrue(/Cannot redefine property/.test(e)); 518 } 519 520 // Different getter. 521 descDifferent = { 522 configurable:false, 523 enumerable:false, 524 set: setter2, 525 get: getter1 526 }; 527 528 try { 529 Object.defineProperty(obj5, 'foo', descDifferent); 530 assertTrue(false); 531 } catch (e) { 532 assertTrue(/Cannot redefine property/.test(e)); 533 } 534 535 // Different enumerable. 536 descDifferent = { 537 configurable:false, 538 enumerable:true, 539 set: setter2, 540 get: getter2 541 }; 542 543 try { 544 Object.defineProperty(obj5, 'foo', descDifferent); 545 assertTrue(false); 546 } catch (e) { 547 assertTrue(/Cannot redefine property/.test(e)); 548 } 549 550 // Different configurable. 551 descDifferent = { 552 configurable:false, 553 enumerable:true, 554 set: setter2, 555 get: getter2 556 }; 557 558 try { 559 Object.defineProperty(obj5, 'foo', descDifferent); 560 assertTrue(false); 561 } catch (e) { 562 assertTrue(/Cannot redefine property/.test(e)); 563 } 564 565 // No difference. 566 descDifferent = { 567 configurable:false, 568 enumerable:false, 569 set: setter2, 570 get: getter2 571 }; 572 // Make sure we can still redefine if all properties are the same. 573 Object.defineProperty(obj5, 'foo', descDifferent); 574 575 // Make sure that obj5 still holds the original values. 576 desc = Object.getOwnPropertyDescriptor(obj5, 'foo'); 577 assertEquals(desc.get, getter2); 578 assertEquals(desc.set, setter2); 579 assertFalse(desc.enumerable); 580 assertFalse(desc.configurable); 581 582 583 // Also exercise step 6 on data property, writable and enumerable 584 // defaults to false. 585 Object.defineProperty(obj5, 'bar', dataNoConfigurable); 586 587 // Test that redefinition with the same property descriptor is possible 588 Object.defineProperty(obj5, 'bar', dataNoConfigurable); 589 590 // Different value. 591 descDifferent = { 592 configurable:false, 593 enumerable:false, 594 writable: false, 595 value: 1999 596 }; 597 598 try { 599 Object.defineProperty(obj5, 'bar', descDifferent); 600 assertTrue(false); 601 } catch (e) { 602 assertTrue(/Cannot redefine property/.test(e)); 603 } 604 605 // Different writable. 606 descDifferent = { 607 configurable:false, 608 enumerable:false, 609 writable: true, 610 value: 2000 611 }; 612 613 try { 614 Object.defineProperty(obj5, 'bar', descDifferent); 615 assertTrue(false); 616 } catch (e) { 617 assertTrue(/Cannot redefine property/.test(e)); 618 } 619 620 621 // Different enumerable. 622 descDifferent = { 623 configurable:false, 624 enumerable:true , 625 writable:false, 626 value: 2000 627 }; 628 629 try { 630 Object.defineProperty(obj5, 'bar', descDifferent); 631 assertTrue(false); 632 } catch (e) { 633 assertTrue(/Cannot redefine property/.test(e)); 634 } 635 636 637 // Different configurable. 638 descDifferent = { 639 configurable:true, 640 enumerable:false, 641 writable:false, 642 value: 2000 643 }; 644 645 try { 646 Object.defineProperty(obj5, 'bar', descDifferent); 647 assertTrue(false); 648 } catch (e) { 649 assertTrue(/Cannot redefine property/.test(e)); 650 } 651 652 // No difference. 653 descDifferent = { 654 configurable:false, 655 enumerable:false, 656 writable:false, 657 value:2000 658 }; 659 // Make sure we can still redefine if all properties are the same. 660 Object.defineProperty(obj5, 'bar', descDifferent); 661 662 // Make sure that obj5 still holds the original values. 663 desc = Object.getOwnPropertyDescriptor(obj5, 'bar'); 664 assertEquals(desc.value, 2000); 665 assertFalse(desc.writable); 666 assertFalse(desc.enumerable); 667 assertFalse(desc.configurable); 668 669 670 // Make sure that we can't overwrite +0 with -0 and vice versa. 671 var descMinusZero = {value: -0, configurable: false}; 672 var descPlusZero = {value: +0, configurable: false}; 673 674 Object.defineProperty(obj5, 'minuszero', descMinusZero); 675 676 // Make sure we can redefine with -0. 677 Object.defineProperty(obj5, 'minuszero', descMinusZero); 678 679 exception = false; 680 try { 681 Object.defineProperty(obj5, 'minuszero', descPlusZero); 682 } catch (e) { 683 exception = true; 684 assertTrue(/Cannot redefine property/.test(e)); 685 } 686 assertTrue(exception); 687 688 689 Object.defineProperty(obj5, 'pluszero', descPlusZero); 690 691 // Make sure we can redefine with +0. 692 Object.defineProperty(obj5, 'pluszero', descPlusZero); 693 694 exception = false; 695 try { 696 Object.defineProperty(obj5, 'pluszero', descMinusZero); 697 } catch (e) { 698 exception = true; 699 assertTrue(/Cannot redefine property/.test(e)); 700 } 701 assertTrue(exception); 702 703 704 var obj6 = {}; 705 obj6[1] = 'foo'; 706 obj6[2] = 'bar'; 707 obj6[3] = '42'; 708 obj6[4] = '43'; 709 obj6[5] = '44'; 710 711 var descElement = { value: 'foobar' }; 712 var descElementNonConfigurable = { value: 'barfoo', configurable: false }; 713 var descElementNonWritable = { value: 'foofoo', writable: false }; 714 var descElementNonEnumerable = { value: 'barbar', enumerable: false }; 715 var descElementAllFalse = { value: 'foofalse', 716 configurable: false, 717 writable: false, 718 enumerable: false }; 719 720 721 // Redefine existing property. 722 Object.defineProperty(obj6, '1', descElement); 723 desc = Object.getOwnPropertyDescriptor(obj6, '1'); 724 assertEquals(desc.value, 'foobar'); 725 assertTrue(desc.writable); 726 assertTrue(desc.enumerable); 727 assertTrue(desc.configurable); 728 729 // Redefine existing property with configurable: false. 730 Object.defineProperty(obj6, '2', descElementNonConfigurable); 731 desc = Object.getOwnPropertyDescriptor(obj6, '2'); 732 assertEquals(desc.value, 'barfoo'); 733 assertTrue(desc.writable); 734 assertTrue(desc.enumerable); 735 assertFalse(desc.configurable); 736 737 // Can use defineProperty to change the value of a non 738 // configurable property. 739 try { 740 Object.defineProperty(obj6, '2', descElement); 741 desc = Object.getOwnPropertyDescriptor(obj6, '2'); 742 assertEquals(desc.value, 'foobar'); 743 } catch (e) { 744 assertUnreachable(); 745 } 746 747 // Ensure that we can't change the descriptor of a 748 // non configurable property. 749 exception = false; 750 try { 751 var descAccessor = { get: function() { return 0; } }; 752 Object.defineProperty(obj6, '2', descAccessor); 753 } catch (e) { 754 exception = true; 755 assertTrue(/Cannot redefine property/.test(e)); 756 } 757 assertTrue(exception); 758 759 Object.defineProperty(obj6, '2', descElementNonWritable); 760 desc = Object.getOwnPropertyDescriptor(obj6, '2'); 761 assertEquals(desc.value, 'foofoo'); 762 assertFalse(desc.writable); 763 assertTrue(desc.enumerable); 764 assertFalse(desc.configurable); 765 766 Object.defineProperty(obj6, '3', descElementNonWritable); 767 desc = Object.getOwnPropertyDescriptor(obj6, '3'); 768 assertEquals(desc.value, 'foofoo'); 769 assertFalse(desc.writable); 770 assertTrue(desc.enumerable); 771 assertTrue(desc.configurable); 772 773 // Redefine existing property with configurable: false. 774 Object.defineProperty(obj6, '4', descElementNonEnumerable); 775 desc = Object.getOwnPropertyDescriptor(obj6, '4'); 776 assertEquals(desc.value, 'barbar'); 777 assertTrue(desc.writable); 778 assertFalse(desc.enumerable); 779 assertTrue(desc.configurable); 780 781 // Redefine existing property with configurable: false. 782 Object.defineProperty(obj6, '5', descElementAllFalse); 783 desc = Object.getOwnPropertyDescriptor(obj6, '5'); 784 assertEquals(desc.value, 'foofalse'); 785 assertFalse(desc.writable); 786 assertFalse(desc.enumerable); 787 assertFalse(desc.configurable); 788 789 // Define non existing property - all attributes should default to false. 790 Object.defineProperty(obj6, '15', descElement); 791 desc = Object.getOwnPropertyDescriptor(obj6, '15'); 792 assertEquals(desc.value, 'foobar'); 793 assertFalse(desc.writable); 794 assertFalse(desc.enumerable); 795 assertFalse(desc.configurable); 796 797 // Make sure that we can't redefine using direct access. 798 obj6[15] ='overwrite'; 799 assertEquals(obj6[15],'foobar'); 800 801 802 // Repeat the above tests on an array. 803 var arr = new Array(); 804 arr[1] = 'foo'; 805 arr[2] = 'bar'; 806 arr[3] = '42'; 807 arr[4] = '43'; 808 arr[5] = '44'; 809 810 var descElement = { value: 'foobar' }; 811 var descElementNonConfigurable = { value: 'barfoo', configurable: false }; 812 var descElementNonWritable = { value: 'foofoo', writable: false }; 813 var descElementNonEnumerable = { value: 'barbar', enumerable: false }; 814 var descElementAllFalse = { value: 'foofalse', 815 configurable: false, 816 writable: false, 817 enumerable: false }; 818 819 820 // Redefine existing property. 821 Object.defineProperty(arr, '1', descElement); 822 desc = Object.getOwnPropertyDescriptor(arr, '1'); 823 assertEquals(desc.value, 'foobar'); 824 assertTrue(desc.writable); 825 assertTrue(desc.enumerable); 826 assertTrue(desc.configurable); 827 828 // Redefine existing property with configurable: false. 829 Object.defineProperty(arr, '2', descElementNonConfigurable); 830 desc = Object.getOwnPropertyDescriptor(arr, '2'); 831 assertEquals(desc.value, 'barfoo'); 832 assertTrue(desc.writable); 833 assertTrue(desc.enumerable); 834 assertFalse(desc.configurable); 835 836 // Can use defineProperty to change the value of a non 837 // configurable property of an array. 838 try { 839 Object.defineProperty(arr, '2', descElement); 840 desc = Object.getOwnPropertyDescriptor(arr, '2'); 841 assertEquals(desc.value, 'foobar'); 842 } catch (e) { 843 assertUnreachable(); 844 } 845 846 // Ensure that we can't change the descriptor of a 847 // non configurable property. 848 exception = false; 849 try { 850 var descAccessor = { get: function() { return 0; } }; 851 Object.defineProperty(arr, '2', descAccessor); 852 } catch (e) { 853 exception = true; 854 assertTrue(/Cannot redefine property/.test(e)); 855 } 856 assertTrue(exception); 857 858 Object.defineProperty(arr, '2', descElementNonWritable); 859 desc = Object.getOwnPropertyDescriptor(arr, '2'); 860 assertEquals(desc.value, 'foofoo'); 861 assertFalse(desc.writable); 862 assertTrue(desc.enumerable); 863 assertFalse(desc.configurable); 864 865 Object.defineProperty(arr, '3', descElementNonWritable); 866 desc = Object.getOwnPropertyDescriptor(arr, '3'); 867 assertEquals(desc.value, 'foofoo'); 868 assertFalse(desc.writable); 869 assertTrue(desc.enumerable); 870 assertTrue(desc.configurable); 871 872 // Redefine existing property with configurable: false. 873 Object.defineProperty(arr, '4', descElementNonEnumerable); 874 desc = Object.getOwnPropertyDescriptor(arr, '4'); 875 assertEquals(desc.value, 'barbar'); 876 assertTrue(desc.writable); 877 assertFalse(desc.enumerable); 878 assertTrue(desc.configurable); 879 880 // Redefine existing property with configurable: false. 881 Object.defineProperty(arr, '5', descElementAllFalse); 882 desc = Object.getOwnPropertyDescriptor(arr, '5'); 883 assertEquals(desc.value, 'foofalse'); 884 assertFalse(desc.writable); 885 assertFalse(desc.enumerable); 886 assertFalse(desc.configurable); 887 888 // Define non existing property - all attributes should default to false. 889 Object.defineProperty(arr, '15', descElement); 890 desc = Object.getOwnPropertyDescriptor(arr, '15'); 891 assertEquals(desc.value, 'foobar'); 892 assertFalse(desc.writable); 893 assertFalse(desc.enumerable); 894 assertFalse(desc.configurable); 895 896 // Define non-array property, check that .length is unaffected. 897 assertEquals(16, arr.length); 898 Object.defineProperty(arr, '0x20', descElement); 899 assertEquals(16, arr.length); 900 901 // See issue 968: http://code.google.com/p/v8/issues/detail?id=968 902 var o = { x : 42 }; 903 Object.defineProperty(o, "x", { writable: false }); 904 assertEquals(42, o.x); 905 o.x = 37; 906 assertEquals(42, o.x); 907 908 o = { x : 42 }; 909 Object.defineProperty(o, "x", {}); 910 assertEquals(42, o.x); 911 o.x = 37; 912 // Writability is preserved. 913 assertEquals(37, o.x); 914 915 var o = { }; 916 Object.defineProperty(o, "x", { writable: false }); 917 assertEquals(undefined, o.x); 918 o.x = 37; 919 assertEquals(undefined, o.x); 920 921 o = { get x() { return 87; } }; 922 Object.defineProperty(o, "x", { writable: false }); 923 assertEquals(undefined, o.x); 924 o.x = 37; 925 assertEquals(undefined, o.x); 926 927 // Ignore inherited properties. 928 o = { __proto__ : { x : 87 } }; 929 Object.defineProperty(o, "x", { writable: false }); 930 assertEquals(undefined, o.x); 931 o.x = 37; 932 assertEquals(undefined, o.x); 933 934 function testDefineProperty(obj, propertyName, desc, resultDesc) { 935 Object.defineProperty(obj, propertyName, desc); 936 var actualDesc = Object.getOwnPropertyDescriptor(obj, propertyName); 937 assertEquals(resultDesc.enumerable, actualDesc.enumerable); 938 assertEquals(resultDesc.configurable, actualDesc.configurable); 939 if (resultDesc.hasOwnProperty('value')) { 940 assertEquals(resultDesc.value, actualDesc.value); 941 assertEquals(resultDesc.writable, actualDesc.writable); 942 assertFalse(resultDesc.hasOwnProperty('get')); 943 assertFalse(resultDesc.hasOwnProperty('set')); 944 } else { 945 assertEquals(resultDesc.get, actualDesc.get); 946 assertEquals(resultDesc.set, actualDesc.set); 947 assertFalse(resultDesc.hasOwnProperty('value')); 948 assertFalse(resultDesc.hasOwnProperty('writable')); 949 } 950 } 951 952 // tests redefining existing property with a generic descriptor 953 o = { p : 42 }; 954 testDefineProperty(o, 'p', 955 { }, 956 { value : 42, writable : true, enumerable : true, configurable : true }); 957 958 o = { p : 42 }; 959 testDefineProperty(o, 'p', 960 { enumerable : true }, 961 { value : 42, writable : true, enumerable : true, configurable : true }); 962 963 o = { p : 42 }; 964 testDefineProperty(o, 'p', 965 { configurable : true }, 966 { value : 42, writable : true, enumerable : true, configurable : true }); 967 968 o = { p : 42 }; 969 testDefineProperty(o, 'p', 970 { enumerable : false }, 971 { value : 42, writable : true, enumerable : false, configurable : true }); 972 973 o = { p : 42 }; 974 testDefineProperty(o, 'p', 975 { configurable : false }, 976 { value : 42, writable : true, enumerable : true, configurable : false }); 977 978 o = { p : 42 }; 979 testDefineProperty(o, 'p', 980 { enumerable : true, configurable : true }, 981 { value : 42, writable : true, enumerable : true, configurable : true }); 982 983 o = { p : 42 }; 984 testDefineProperty(o, 'p', 985 { enumerable : false, configurable : true }, 986 { value : 42, writable : true, enumerable : false, configurable : true }); 987 988 o = { p : 42 }; 989 testDefineProperty(o, 'p', 990 { enumerable : true, configurable : false }, 991 { value : 42, writable : true, enumerable : true, configurable : false }); 992 993 o = { p : 42 }; 994 testDefineProperty(o, 'p', 995 { enumerable : false, configurable : false }, 996 { value : 42, writable : true, enumerable : false, configurable : false }); 997 998 // can make a writable, non-configurable field non-writable 999 o = { p : 42 }; 1000 Object.defineProperty(o, 'p', { configurable: false }); 1001 testDefineProperty(o, 'p', 1002 { writable: false }, 1003 { value : 42, writable : false, enumerable : true, configurable : false }); 1004 1005 // redefine of get only property with generic descriptor 1006 o = {}; 1007 Object.defineProperty(o, 'p', 1008 { get : getter1, enumerable: true, configurable: true }); 1009 testDefineProperty(o, 'p', 1010 { enumerable : false, configurable : false }, 1011 { get: getter1, set: undefined, enumerable : false, configurable : false }); 1012 1013 // redefine of get/set only property with generic descriptor 1014 o = {}; 1015 Object.defineProperty(o, 'p', 1016 { get: getter1, set: setter1, enumerable: true, configurable: true }); 1017 testDefineProperty(o, 'p', 1018 { enumerable : false, configurable : false }, 1019 { get: getter1, set: setter1, enumerable : false, configurable : false }); 1020 1021 // redefine of set only property with generic descriptor 1022 o = {}; 1023 Object.defineProperty(o, 'p', 1024 { set : setter1, enumerable: true, configurable: true }); 1025 testDefineProperty(o, 'p', 1026 { enumerable : false, configurable : false }, 1027 { get: undefined, set: setter1, enumerable : false, configurable : false }); 1028 1029 1030 // Regression test: Ensure that growing dictionaries are not ignored. 1031 o = {}; 1032 for (var i = 0; i < 1000; i++) { 1033 // Non-enumerable property forces dictionary mode. 1034 Object.defineProperty(o, i, {value: i, enumerable: false}); 1035 } 1036 assertEquals(999, o[999]); 1037 1038 1039 // Regression test: Bizzare behavior on non-strict arguments object. 1040 // TODO(yangguo): Tests disabled, needs investigation! 1041 /* 1042 (function test(arg0) { 1043 // Here arguments[0] is a fast alias on arg0. 1044 Object.defineProperty(arguments, "0", { 1045 value:1, 1046 enumerable:false 1047 }); 1048 // Here arguments[0] is a slow alias on arg0. 1049 Object.defineProperty(arguments, "0", { 1050 value:2, 1051 writable:false 1052 }); 1053 // Here arguments[0] is no alias at all. 1054 Object.defineProperty(arguments, "0", { 1055 value:3 1056 }); 1057 assertEquals(2, arg0); 1058 assertEquals(3, arguments[0]); 1059 })(0); 1060 */ 1061 1062 // Regression test: We should never observe the hole value. 1063 var objectWithGetter = {}; 1064 objectWithGetter.__defineGetter__('foo', function() {}); 1065 assertEquals(undefined, objectWithGetter.__lookupSetter__('foo')); 1066 1067 var objectWithSetter = {}; 1068 objectWithSetter.__defineSetter__('foo', function(x) {}); 1069 assertEquals(undefined, objectWithSetter.__lookupGetter__('foo')); 1070 1071 // An object with a getter on the prototype chain. 1072 function getter() { return 111; } 1073 function anotherGetter() { return 222; } 1074 1075 function testGetterOnProto(expected, o) { 1076 assertEquals(expected, o.quebec); 1077 } 1078 1079 obj1 = {}; 1080 Object.defineProperty(obj1, "quebec", { get: getter, configurable: true }); 1081 obj2 = Object.create(obj1); 1082 obj3 = Object.create(obj2); 1083 1084 testGetterOnProto(111, obj3); 1085 testGetterOnProto(111, obj3); 1086 %OptimizeFunctionOnNextCall(testGetterOnProto); 1087 testGetterOnProto(111, obj3); 1088 testGetterOnProto(111, obj3); 1089 1090 Object.defineProperty(obj1, "quebec", { get: anotherGetter }); 1091 1092 testGetterOnProto(222, obj3); 1093 testGetterOnProto(222, obj3); 1094 %OptimizeFunctionOnNextCall(testGetterOnProto); 1095 testGetterOnProto(222, obj3); 1096 testGetterOnProto(222, obj3); 1097 1098 // An object with a setter on the prototype chain. 1099 var modifyMe; 1100 function setter(x) { modifyMe = x+1; } 1101 function anotherSetter(x) { modifyMe = x+2; } 1102 1103 function testSetterOnProto(expected, o) { 1104 modifyMe = 333; 1105 o.romeo = 444; 1106 assertEquals(expected, modifyMe); 1107 } 1108 1109 obj1 = {}; 1110 Object.defineProperty(obj1, "romeo", { set: setter, configurable: true }); 1111 obj2 = Object.create(obj1); 1112 obj3 = Object.create(obj2); 1113 1114 testSetterOnProto(445, obj3); 1115 testSetterOnProto(445, obj3); 1116 %OptimizeFunctionOnNextCall(testSetterOnProto); 1117 testSetterOnProto(445, obj3); 1118 testSetterOnProto(445, obj3); 1119 1120 Object.defineProperty(obj1, "romeo", { set: anotherSetter }); 1121 1122 testSetterOnProto(446, obj3); 1123 testSetterOnProto(446, obj3); 1124 %OptimizeFunctionOnNextCall(testSetterOnProto); 1125 testSetterOnProto(446, obj3); 1126 testSetterOnProto(446, obj3); 1127 1128 // Removing a setter on the prototype chain. 1129 function testSetterOnProtoStrict(o) { 1130 "use strict"; 1131 o.sierra = 12345; 1132 } 1133 1134 obj1 = {}; 1135 Object.defineProperty(obj1, "sierra", 1136 { get: getter, set: setter, configurable: true }); 1137 obj2 = Object.create(obj1); 1138 obj3 = Object.create(obj2); 1139 1140 testSetterOnProtoStrict(obj3); 1141 testSetterOnProtoStrict(obj3); 1142 %OptimizeFunctionOnNextCall(testSetterOnProtoStrict); 1143 testSetterOnProtoStrict(obj3); 1144 testSetterOnProtoStrict(obj3); 1145 1146 Object.defineProperty(obj1, "sierra", 1147 { get: getter, set: undefined, configurable: true }); 1148 1149 exception = false; 1150 try { 1151 testSetterOnProtoStrict(obj3); 1152 } catch (e) { 1153 exception = true; 1154 assertTrue(/which has only a getter/.test(e)); 1155 } 1156 assertTrue(exception); 1157 1158 // Test assignment to a getter-only property on the prototype chain. This makes 1159 // sure that crankshaft re-checks its assumptions and doesn't rely only on type 1160 // feedback (which would be monomorphic here). 1161 1162 function Assign(o) { 1163 o.blubb = 123; 1164 } 1165 1166 function C() {} 1167 1168 Assign(new C); 1169 Assign(new C); 1170 %OptimizeFunctionOnNextCall(Assign); 1171 Object.defineProperty(C.prototype, "blubb", {get: function() { return -42; }}); 1172 Assign(new C); 1173 1174 // Test that changes to the prototype of a simple constructor are not ignored, 1175 // even after creating initial instances. 1176 function C() { 1177 this.x = 23; 1178 } 1179 assertEquals(23, new C().x); 1180 C.prototype.__defineSetter__('x', function(value) { this.y = 23; }); 1181 assertEquals(void 0, new C().x); 1182