Home | History | Annotate | Download | only in mjsunit
      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