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 --es5-readonly 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 DefineOrRedefineDataProperty and 471 // DefineOrRedefineAccessorProperty - make sure we don't 472 // crash. 473 try { 474 %DefineOrRedefineAccessorProperty(0, 0, 0, 0, 0); 475 } catch (e) { 476 assertTrue(/illegal access/.test(e)); 477 } 478 479 try { 480 %DefineOrRedefineDataProperty(0, 0, 0, 0); 481 } catch (e) { 482 assertTrue(/illegal access/.test(e)); 483 } 484 485 try { 486 %DefineOrRedefineDataProperty(null, null, null, null); 487 } catch (e) { 488 assertTrue(/illegal access/.test(e)); 489 } 490 491 try { 492 %DefineOrRedefineAccessorProperty(null, null, null, null, null); 493 } catch (e) { 494 assertTrue(/illegal access/.test(e)); 495 } 496 497 try { 498 %DefineOrRedefineDataProperty({}, null, null, null); 499 } catch (e) { 500 assertTrue(/illegal access/.test(e)); 501 } 502 503 // Defining properties null should fail even when we have 504 // other allowed values 505 try { 506 %DefineOrRedefineAccessorProperty(null, 'foo', func, null, 0); 507 } catch (e) { 508 assertTrue(/illegal access/.test(e)); 509 } 510 511 try { 512 %DefineOrRedefineDataProperty(null, 'foo', 0, 0); 513 } catch (e) { 514 assertTrue(/illegal access/.test(e)); 515 } 516 517 // Test that all possible differences in step 6 in DefineOwnProperty are 518 // exercised, i.e., any difference in the given property descriptor and the 519 // existing properties should not return true, but throw an error if the 520 // existing configurable property is false. 521 522 var obj5 = {}; 523 // Enumerable will default to false. 524 Object.defineProperty(obj5, 'foo', accessorNoConfigurable); 525 desc = Object.getOwnPropertyDescriptor(obj5, 'foo'); 526 // First, test that we are actually allowed to set the accessor if all 527 // values are of the descriptor are the same as the existing one. 528 Object.defineProperty(obj5, 'foo', accessorNoConfigurable); 529 530 // Different setter. 531 var descDifferent = { 532 configurable:false, 533 enumerable:false, 534 set: setter1, 535 get: getter2 536 }; 537 538 try { 539 Object.defineProperty(obj5, 'foo', descDifferent); 540 assertTrue(false); 541 } catch (e) { 542 assertTrue(/Cannot redefine property/.test(e)); 543 } 544 545 // Different getter. 546 descDifferent = { 547 configurable:false, 548 enumerable:false, 549 set: setter2, 550 get: getter1 551 }; 552 553 try { 554 Object.defineProperty(obj5, 'foo', descDifferent); 555 assertTrue(false); 556 } catch (e) { 557 assertTrue(/Cannot redefine property/.test(e)); 558 } 559 560 // Different enumerable. 561 descDifferent = { 562 configurable:false, 563 enumerable:true, 564 set: setter2, 565 get: getter2 566 }; 567 568 try { 569 Object.defineProperty(obj5, 'foo', descDifferent); 570 assertTrue(false); 571 } catch (e) { 572 assertTrue(/Cannot redefine property/.test(e)); 573 } 574 575 // Different configurable. 576 descDifferent = { 577 configurable:false, 578 enumerable:true, 579 set: setter2, 580 get: getter2 581 }; 582 583 try { 584 Object.defineProperty(obj5, 'foo', descDifferent); 585 assertTrue(false); 586 } catch (e) { 587 assertTrue(/Cannot redefine property/.test(e)); 588 } 589 590 // No difference. 591 descDifferent = { 592 configurable:false, 593 enumerable:false, 594 set: setter2, 595 get: getter2 596 }; 597 // Make sure we can still redefine if all properties are the same. 598 Object.defineProperty(obj5, 'foo', descDifferent); 599 600 // Make sure that obj5 still holds the original values. 601 desc = Object.getOwnPropertyDescriptor(obj5, 'foo'); 602 assertEquals(desc.get, getter2); 603 assertEquals(desc.set, setter2); 604 assertFalse(desc.enumerable); 605 assertFalse(desc.configurable); 606 607 608 // Also exercise step 6 on data property, writable and enumerable 609 // defaults to false. 610 Object.defineProperty(obj5, 'bar', dataNoConfigurable); 611 612 // Test that redefinition with the same property descriptor is possible 613 Object.defineProperty(obj5, 'bar', dataNoConfigurable); 614 615 // Different value. 616 descDifferent = { 617 configurable:false, 618 enumerable:false, 619 writable: false, 620 value: 1999 621 }; 622 623 try { 624 Object.defineProperty(obj5, 'bar', descDifferent); 625 assertTrue(false); 626 } catch (e) { 627 assertTrue(/Cannot redefine property/.test(e)); 628 } 629 630 // Different writable. 631 descDifferent = { 632 configurable:false, 633 enumerable:false, 634 writable: true, 635 value: 2000 636 }; 637 638 try { 639 Object.defineProperty(obj5, 'bar', descDifferent); 640 assertTrue(false); 641 } catch (e) { 642 assertTrue(/Cannot redefine property/.test(e)); 643 } 644 645 646 // Different enumerable. 647 descDifferent = { 648 configurable:false, 649 enumerable:true , 650 writable:false, 651 value: 2000 652 }; 653 654 try { 655 Object.defineProperty(obj5, 'bar', descDifferent); 656 assertTrue(false); 657 } catch (e) { 658 assertTrue(/Cannot redefine property/.test(e)); 659 } 660 661 662 // Different configurable. 663 descDifferent = { 664 configurable:true, 665 enumerable:false, 666 writable:false, 667 value: 2000 668 }; 669 670 try { 671 Object.defineProperty(obj5, 'bar', descDifferent); 672 assertTrue(false); 673 } catch (e) { 674 assertTrue(/Cannot redefine property/.test(e)); 675 } 676 677 // No difference. 678 descDifferent = { 679 configurable:false, 680 enumerable:false, 681 writable:false, 682 value:2000 683 }; 684 // Make sure we can still redefine if all properties are the same. 685 Object.defineProperty(obj5, 'bar', descDifferent); 686 687 // Make sure that obj5 still holds the original values. 688 desc = Object.getOwnPropertyDescriptor(obj5, 'bar'); 689 assertEquals(desc.value, 2000); 690 assertFalse(desc.writable); 691 assertFalse(desc.enumerable); 692 assertFalse(desc.configurable); 693 694 695 // Make sure that we can't overwrite +0 with -0 and vice versa. 696 var descMinusZero = {value: -0, configurable: false}; 697 var descPlusZero = {value: +0, configurable: false}; 698 699 Object.defineProperty(obj5, 'minuszero', descMinusZero); 700 701 // Make sure we can redefine with -0. 702 Object.defineProperty(obj5, 'minuszero', descMinusZero); 703 704 exception = false; 705 try { 706 Object.defineProperty(obj5, 'minuszero', descPlusZero); 707 } catch (e) { 708 exception = true; 709 assertTrue(/Cannot redefine property/.test(e)); 710 } 711 assertTrue(exception); 712 713 714 Object.defineProperty(obj5, 'pluszero', descPlusZero); 715 716 // Make sure we can redefine with +0. 717 Object.defineProperty(obj5, 'pluszero', descPlusZero); 718 719 exception = false; 720 try { 721 Object.defineProperty(obj5, 'pluszero', descMinusZero); 722 } catch (e) { 723 exception = true; 724 assertTrue(/Cannot redefine property/.test(e)); 725 } 726 assertTrue(exception); 727 728 729 var obj6 = {}; 730 obj6[1] = 'foo'; 731 obj6[2] = 'bar'; 732 obj6[3] = '42'; 733 obj6[4] = '43'; 734 obj6[5] = '44'; 735 736 var descElement = { value: 'foobar' }; 737 var descElementNonConfigurable = { value: 'barfoo', configurable: false }; 738 var descElementNonWritable = { value: 'foofoo', writable: false }; 739 var descElementNonEnumerable = { value: 'barbar', enumerable: false }; 740 var descElementAllFalse = { value: 'foofalse', 741 configurable: false, 742 writable: false, 743 enumerable: false }; 744 745 746 // Redefine existing property. 747 Object.defineProperty(obj6, '1', descElement); 748 desc = Object.getOwnPropertyDescriptor(obj6, '1'); 749 assertEquals(desc.value, 'foobar'); 750 assertTrue(desc.writable); 751 assertTrue(desc.enumerable); 752 assertTrue(desc.configurable); 753 754 // Redefine existing property with configurable: false. 755 Object.defineProperty(obj6, '2', descElementNonConfigurable); 756 desc = Object.getOwnPropertyDescriptor(obj6, '2'); 757 assertEquals(desc.value, 'barfoo'); 758 assertTrue(desc.writable); 759 assertTrue(desc.enumerable); 760 assertFalse(desc.configurable); 761 762 // Can use defineProperty to change the value of a non 763 // configurable property. 764 try { 765 Object.defineProperty(obj6, '2', descElement); 766 desc = Object.getOwnPropertyDescriptor(obj6, '2'); 767 assertEquals(desc.value, 'foobar'); 768 } catch (e) { 769 assertUnreachable(); 770 } 771 772 // Ensure that we can't change the descriptor of a 773 // non configurable property. 774 exception = false; 775 try { 776 var descAccessor = { get: function() { return 0; } }; 777 Object.defineProperty(obj6, '2', descAccessor); 778 } catch (e) { 779 exception = true; 780 assertTrue(/Cannot redefine property/.test(e)); 781 } 782 assertTrue(exception); 783 784 Object.defineProperty(obj6, '2', descElementNonWritable); 785 desc = Object.getOwnPropertyDescriptor(obj6, '2'); 786 assertEquals(desc.value, 'foofoo'); 787 assertFalse(desc.writable); 788 assertTrue(desc.enumerable); 789 assertFalse(desc.configurable); 790 791 Object.defineProperty(obj6, '3', descElementNonWritable); 792 desc = Object.getOwnPropertyDescriptor(obj6, '3'); 793 assertEquals(desc.value, 'foofoo'); 794 assertFalse(desc.writable); 795 assertTrue(desc.enumerable); 796 assertTrue(desc.configurable); 797 798 // Redefine existing property with configurable: false. 799 Object.defineProperty(obj6, '4', descElementNonEnumerable); 800 desc = Object.getOwnPropertyDescriptor(obj6, '4'); 801 assertEquals(desc.value, 'barbar'); 802 assertTrue(desc.writable); 803 assertFalse(desc.enumerable); 804 assertTrue(desc.configurable); 805 806 // Redefine existing property with configurable: false. 807 Object.defineProperty(obj6, '5', descElementAllFalse); 808 desc = Object.getOwnPropertyDescriptor(obj6, '5'); 809 assertEquals(desc.value, 'foofalse'); 810 assertFalse(desc.writable); 811 assertFalse(desc.enumerable); 812 assertFalse(desc.configurable); 813 814 // Define non existing property - all attributes should default to false. 815 Object.defineProperty(obj6, '15', descElement); 816 desc = Object.getOwnPropertyDescriptor(obj6, '15'); 817 assertEquals(desc.value, 'foobar'); 818 assertFalse(desc.writable); 819 assertFalse(desc.enumerable); 820 assertFalse(desc.configurable); 821 822 // Make sure that we can't redefine using direct access. 823 obj6[15] ='overwrite'; 824 assertEquals(obj6[15],'foobar'); 825 826 827 // Repeat the above tests on an array. 828 var arr = new Array(); 829 arr[1] = 'foo'; 830 arr[2] = 'bar'; 831 arr[3] = '42'; 832 arr[4] = '43'; 833 arr[5] = '44'; 834 835 var descElement = { value: 'foobar' }; 836 var descElementNonConfigurable = { value: 'barfoo', configurable: false }; 837 var descElementNonWritable = { value: 'foofoo', writable: false }; 838 var descElementNonEnumerable = { value: 'barbar', enumerable: false }; 839 var descElementAllFalse = { value: 'foofalse', 840 configurable: false, 841 writable: false, 842 enumerable: false }; 843 844 845 // Redefine existing property. 846 Object.defineProperty(arr, '1', descElement); 847 desc = Object.getOwnPropertyDescriptor(arr, '1'); 848 assertEquals(desc.value, 'foobar'); 849 assertTrue(desc.writable); 850 assertTrue(desc.enumerable); 851 assertTrue(desc.configurable); 852 853 // Redefine existing property with configurable: false. 854 Object.defineProperty(arr, '2', descElementNonConfigurable); 855 desc = Object.getOwnPropertyDescriptor(arr, '2'); 856 assertEquals(desc.value, 'barfoo'); 857 assertTrue(desc.writable); 858 assertTrue(desc.enumerable); 859 assertFalse(desc.configurable); 860 861 // Can use defineProperty to change the value of a non 862 // configurable property of an array. 863 try { 864 Object.defineProperty(arr, '2', descElement); 865 desc = Object.getOwnPropertyDescriptor(arr, '2'); 866 assertEquals(desc.value, 'foobar'); 867 } catch (e) { 868 assertUnreachable(); 869 } 870 871 // Ensure that we can't change the descriptor of a 872 // non configurable property. 873 exception = false; 874 try { 875 var descAccessor = { get: function() { return 0; } }; 876 Object.defineProperty(arr, '2', descAccessor); 877 } catch (e) { 878 exception = true; 879 assertTrue(/Cannot redefine property/.test(e)); 880 } 881 assertTrue(exception); 882 883 Object.defineProperty(arr, '2', descElementNonWritable); 884 desc = Object.getOwnPropertyDescriptor(arr, '2'); 885 assertEquals(desc.value, 'foofoo'); 886 assertFalse(desc.writable); 887 assertTrue(desc.enumerable); 888 assertFalse(desc.configurable); 889 890 Object.defineProperty(arr, '3', descElementNonWritable); 891 desc = Object.getOwnPropertyDescriptor(arr, '3'); 892 assertEquals(desc.value, 'foofoo'); 893 assertFalse(desc.writable); 894 assertTrue(desc.enumerable); 895 assertTrue(desc.configurable); 896 897 // Redefine existing property with configurable: false. 898 Object.defineProperty(arr, '4', descElementNonEnumerable); 899 desc = Object.getOwnPropertyDescriptor(arr, '4'); 900 assertEquals(desc.value, 'barbar'); 901 assertTrue(desc.writable); 902 assertFalse(desc.enumerable); 903 assertTrue(desc.configurable); 904 905 // Redefine existing property with configurable: false. 906 Object.defineProperty(arr, '5', descElementAllFalse); 907 desc = Object.getOwnPropertyDescriptor(arr, '5'); 908 assertEquals(desc.value, 'foofalse'); 909 assertFalse(desc.writable); 910 assertFalse(desc.enumerable); 911 assertFalse(desc.configurable); 912 913 // Define non existing property - all attributes should default to false. 914 Object.defineProperty(arr, '15', descElement); 915 desc = Object.getOwnPropertyDescriptor(arr, '15'); 916 assertEquals(desc.value, 'foobar'); 917 assertFalse(desc.writable); 918 assertFalse(desc.enumerable); 919 assertFalse(desc.configurable); 920 921 // Define non-array property, check that .length is unaffected. 922 assertEquals(16, arr.length); 923 Object.defineProperty(arr, '0x20', descElement); 924 assertEquals(16, arr.length); 925 926 // See issue 968: http://code.google.com/p/v8/issues/detail?id=968 927 var o = { x : 42 }; 928 Object.defineProperty(o, "x", { writable: false }); 929 assertEquals(42, o.x); 930 o.x = 37; 931 assertEquals(42, o.x); 932 933 o = { x : 42 }; 934 Object.defineProperty(o, "x", {}); 935 assertEquals(42, o.x); 936 o.x = 37; 937 // Writability is preserved. 938 assertEquals(37, o.x); 939 940 var o = { }; 941 Object.defineProperty(o, "x", { writable: false }); 942 assertEquals(undefined, o.x); 943 o.x = 37; 944 assertEquals(undefined, o.x); 945 946 o = { get x() { return 87; } }; 947 Object.defineProperty(o, "x", { writable: false }); 948 assertEquals(undefined, o.x); 949 o.x = 37; 950 assertEquals(undefined, o.x); 951 952 // Ignore inherited properties. 953 o = { __proto__ : { x : 87 } }; 954 Object.defineProperty(o, "x", { writable: false }); 955 assertEquals(undefined, o.x); 956 o.x = 37; 957 assertEquals(undefined, o.x); 958 959 function testDefineProperty(obj, propertyName, desc, resultDesc) { 960 Object.defineProperty(obj, propertyName, desc); 961 var actualDesc = Object.getOwnPropertyDescriptor(obj, propertyName); 962 assertEquals(resultDesc.enumerable, actualDesc.enumerable); 963 assertEquals(resultDesc.configurable, actualDesc.configurable); 964 if (resultDesc.hasOwnProperty('value')) { 965 assertEquals(resultDesc.value, actualDesc.value); 966 assertEquals(resultDesc.writable, actualDesc.writable); 967 assertFalse(resultDesc.hasOwnProperty('get')); 968 assertFalse(resultDesc.hasOwnProperty('set')); 969 } else { 970 assertEquals(resultDesc.get, actualDesc.get); 971 assertEquals(resultDesc.set, actualDesc.set); 972 assertFalse(resultDesc.hasOwnProperty('value')); 973 assertFalse(resultDesc.hasOwnProperty('writable')); 974 } 975 } 976 977 // tests redefining existing property with a generic descriptor 978 o = { p : 42 }; 979 testDefineProperty(o, 'p', 980 { }, 981 { value : 42, writable : true, enumerable : true, configurable : true }); 982 983 o = { p : 42 }; 984 testDefineProperty(o, 'p', 985 { enumerable : true }, 986 { value : 42, writable : true, enumerable : true, configurable : true }); 987 988 o = { p : 42 }; 989 testDefineProperty(o, 'p', 990 { configurable : true }, 991 { value : 42, writable : true, enumerable : true, configurable : true }); 992 993 o = { p : 42 }; 994 testDefineProperty(o, 'p', 995 { enumerable : false }, 996 { value : 42, writable : true, enumerable : false, configurable : true }); 997 998 o = { p : 42 }; 999 testDefineProperty(o, 'p', 1000 { configurable : false }, 1001 { value : 42, writable : true, enumerable : true, configurable : false }); 1002 1003 o = { p : 42 }; 1004 testDefineProperty(o, 'p', 1005 { enumerable : true, configurable : true }, 1006 { value : 42, writable : true, enumerable : true, configurable : true }); 1007 1008 o = { p : 42 }; 1009 testDefineProperty(o, 'p', 1010 { enumerable : false, configurable : true }, 1011 { value : 42, writable : true, enumerable : false, configurable : true }); 1012 1013 o = { p : 42 }; 1014 testDefineProperty(o, 'p', 1015 { enumerable : true, configurable : false }, 1016 { value : 42, writable : true, enumerable : true, configurable : false }); 1017 1018 o = { p : 42 }; 1019 testDefineProperty(o, 'p', 1020 { enumerable : false, configurable : false }, 1021 { value : 42, writable : true, enumerable : false, configurable : false }); 1022 1023 // can make a writable, non-configurable field non-writable 1024 o = { p : 42 }; 1025 Object.defineProperty(o, 'p', { configurable: false }); 1026 testDefineProperty(o, 'p', 1027 { writable: false }, 1028 { value : 42, writable : false, enumerable : true, configurable : false }); 1029 1030 // redefine of get only property with generic descriptor 1031 o = {}; 1032 Object.defineProperty(o, 'p', 1033 { get : getter1, enumerable: true, configurable: true }); 1034 testDefineProperty(o, 'p', 1035 { enumerable : false, configurable : false }, 1036 { get: getter1, set: undefined, enumerable : false, configurable : false }); 1037 1038 // redefine of get/set only property with generic descriptor 1039 o = {}; 1040 Object.defineProperty(o, 'p', 1041 { get: getter1, set: setter1, enumerable: true, configurable: true }); 1042 testDefineProperty(o, 'p', 1043 { enumerable : false, configurable : false }, 1044 { get: getter1, set: setter1, enumerable : false, configurable : false }); 1045 1046 // redefine of set only property with generic descriptor 1047 o = {}; 1048 Object.defineProperty(o, 'p', 1049 { set : setter1, enumerable: true, configurable: true }); 1050 testDefineProperty(o, 'p', 1051 { enumerable : false, configurable : false }, 1052 { get: undefined, set: setter1, enumerable : false, configurable : false }); 1053 1054 1055 // Regression test: Ensure that growing dictionaries are not ignored. 1056 o = {}; 1057 for (var i = 0; i < 1000; i++) { 1058 // Non-enumerable property forces dictionary mode. 1059 Object.defineProperty(o, i, {value: i, enumerable: false}); 1060 } 1061 assertEquals(999, o[999]); 1062 1063 1064 // Regression test: Bizzare behavior on non-strict arguments object. 1065 // TODO(yangguo): Tests disabled, needs investigation! 1066 /* 1067 (function test(arg0) { 1068 // Here arguments[0] is a fast alias on arg0. 1069 Object.defineProperty(arguments, "0", { 1070 value:1, 1071 enumerable:false 1072 }); 1073 // Here arguments[0] is a slow alias on arg0. 1074 Object.defineProperty(arguments, "0", { 1075 value:2, 1076 writable:false 1077 }); 1078 // Here arguments[0] is no alias at all. 1079 Object.defineProperty(arguments, "0", { 1080 value:3 1081 }); 1082 assertEquals(2, arg0); 1083 assertEquals(3, arguments[0]); 1084 })(0); 1085 */ 1086 1087 // Regression test: We should never observe the hole value. 1088 var objectWithGetter = {}; 1089 objectWithGetter.__defineGetter__('foo', function() {}); 1090 assertEquals(undefined, objectWithGetter.__lookupSetter__('foo')); 1091 1092 var objectWithSetter = {}; 1093 objectWithSetter.__defineSetter__('foo', function(x) {}); 1094 assertEquals(undefined, objectWithSetter.__lookupGetter__('foo')); 1095 1096 // An object with a getter on the prototype chain. 1097 function getter() { return 111; } 1098 function anotherGetter() { return 222; } 1099 1100 function testGetterOnProto(expected, o) { 1101 assertEquals(expected, o.quebec); 1102 } 1103 1104 obj1 = {}; 1105 Object.defineProperty(obj1, "quebec", { get: getter, configurable: true }); 1106 obj2 = Object.create(obj1); 1107 obj3 = Object.create(obj2); 1108 1109 testGetterOnProto(111, obj3); 1110 testGetterOnProto(111, obj3); 1111 %OptimizeFunctionOnNextCall(testGetterOnProto); 1112 testGetterOnProto(111, obj3); 1113 testGetterOnProto(111, obj3); 1114 1115 Object.defineProperty(obj1, "quebec", { get: anotherGetter }); 1116 1117 testGetterOnProto(222, obj3); 1118 testGetterOnProto(222, obj3); 1119 %OptimizeFunctionOnNextCall(testGetterOnProto); 1120 testGetterOnProto(222, obj3); 1121 testGetterOnProto(222, obj3); 1122 1123 // An object with a setter on the prototype chain. 1124 var modifyMe; 1125 function setter(x) { modifyMe = x+1; } 1126 function anotherSetter(x) { modifyMe = x+2; } 1127 1128 function testSetterOnProto(expected, o) { 1129 modifyMe = 333; 1130 o.romeo = 444; 1131 assertEquals(expected, modifyMe); 1132 } 1133 1134 obj1 = {}; 1135 Object.defineProperty(obj1, "romeo", { set: setter, configurable: true }); 1136 obj2 = Object.create(obj1); 1137 obj3 = Object.create(obj2); 1138 1139 testSetterOnProto(445, obj3); 1140 testSetterOnProto(445, obj3); 1141 %OptimizeFunctionOnNextCall(testSetterOnProto); 1142 testSetterOnProto(445, obj3); 1143 testSetterOnProto(445, obj3); 1144 1145 Object.defineProperty(obj1, "romeo", { set: anotherSetter }); 1146 1147 testSetterOnProto(446, obj3); 1148 testSetterOnProto(446, obj3); 1149 %OptimizeFunctionOnNextCall(testSetterOnProto); 1150 testSetterOnProto(446, obj3); 1151 testSetterOnProto(446, obj3); 1152 1153 // Removing a setter on the prototype chain. 1154 function testSetterOnProtoStrict(o) { 1155 "use strict"; 1156 o.sierra = 12345; 1157 } 1158 1159 obj1 = {}; 1160 Object.defineProperty(obj1, "sierra", 1161 { get: getter, set: setter, configurable: true }); 1162 obj2 = Object.create(obj1); 1163 obj3 = Object.create(obj2); 1164 1165 testSetterOnProtoStrict(obj3); 1166 testSetterOnProtoStrict(obj3); 1167 %OptimizeFunctionOnNextCall(testSetterOnProtoStrict); 1168 testSetterOnProtoStrict(obj3); 1169 testSetterOnProtoStrict(obj3); 1170 1171 Object.defineProperty(obj1, "sierra", 1172 { get: getter, set: undefined, configurable: true }); 1173 1174 exception = false; 1175 try { 1176 testSetterOnProtoStrict(obj3); 1177 } catch (e) { 1178 exception = true; 1179 assertTrue(/which has only a getter/.test(e)); 1180 } 1181 assertTrue(exception); 1182 1183 // Test assignment to a getter-only property on the prototype chain. This makes 1184 // sure that crankshaft re-checks its assumptions and doesn't rely only on type 1185 // feedback (which would be monomorphic here). 1186 1187 function Assign(o) { 1188 o.blubb = 123; 1189 } 1190 1191 function C() {} 1192 1193 Assign(new C); 1194 Assign(new C); 1195 %OptimizeFunctionOnNextCall(Assign); 1196 Object.defineProperty(C.prototype, "blubb", {get: function() { return -42; }}); 1197 Assign(new C); 1198 1199 // Test that changes to the prototype of a simple constructor are not ignored, 1200 // even after creating initial instances. 1201 function C() { 1202 this.x = 23; 1203 } 1204 assertEquals(23, new C().x); 1205 C.prototype.__defineSetter__('x', function(value) { this.y = 23; }); 1206 assertEquals(void 0, new C().x); 1207