Home | History | Annotate | Download | only in mjsunit
      1 // Copyright 2011 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 // Flags: --allow-natives-syntax --harmony-proxies --es5_readonly
     29 
     30 // Different ways to create an object.
     31 
     32 function CreateFromLiteral() {
     33   return {};
     34 }
     35 
     36 function CreateFromObject() {
     37   return new Object;
     38 }
     39 
     40 function CreateDefault() {
     41   return Object.create(Object.prototype);
     42 }
     43 
     44 function CreateFromConstructor(proto) {
     45   function C() {}
     46   (new C).b = 9;  // Make sure that we can have an in-object property.
     47   C.prototype = proto;
     48   return function() { return new C; }
     49 }
     50 
     51 function CreateFromApi(proto) {
     52   return function() { return Object.create(proto); }
     53 }
     54 
     55 function CreateWithProperty(proto) {
     56   function C() { this.a = -100; }
     57   C.prototype = proto;
     58   return function() { return new C; }
     59 }
     60 
     61 var bases = [CreateFromLiteral, CreateFromObject, CreateDefault];
     62 var inherits = [CreateFromConstructor, CreateFromApi, CreateWithProperty];
     63 var constructs = [CreateFromConstructor, CreateFromApi];
     64 
     65 function TestAllCreates(f) {
     66   // The depth of the prototype chain up the.
     67   for (var depth = 0; depth < 3; ++depth) {
     68     // Introduce readonly-ness this far up the chain.
     69     for (var up = 0; up <= depth; ++up) {
     70       // Try different construction methods.
     71       for (var k = 0; k < constructs.length; ++k) {
     72         // Construct a fresh prototype chain from above functions.
     73         for (var i = 0; i < bases.length; ++i) {
     74           var p = bases[i]();
     75           // There may be a preexisting property under the insertion point...
     76           for (var j = 0; j < depth - up; ++j) {
     77             p = inherits[Math.floor(inherits.length * Math.random())](p)();
     78           }
     79           // ...but not above it.
     80           for (var j = 0; j < up; ++j) {
     81             p = constructs[Math.floor(constructs.length * Math.random())](p)();
     82           }
     83           // Create a fresh constructor.
     84           var c = constructs[k](p);
     85           f(function() {
     86             var o = c();
     87             o.up = o;
     88             for (var j = 0; j < up; ++j) o.up = Object.getPrototypeOf(o.up);
     89             return o;
     90           })
     91         }
     92       }
     93     }
     94   }
     95 }
     96 
     97 
     98 // Different ways to make a property read-only.
     99 
    100 function ReadonlyByNonwritableDataProperty(o, name) {
    101   Object.defineProperty(o, name, {value: -41, writable: false});
    102 }
    103 
    104 function ReadonlyByAccessorPropertyWithoutSetter(o, name) {
    105   Object.defineProperty(o, name, {get: function() { return -42; }});
    106 }
    107 
    108 function ReadonlyByGetter(o, name) {
    109   o.__defineGetter__("a", function() { return -43; });
    110 }
    111 
    112 function ReadonlyByFreeze(o, name) {
    113   o[name] = -44;
    114   Object.freeze(o);
    115 }
    116 
    117 function ReadonlyByProto(o, name) {
    118   var p = Object.create(o.__proto__);
    119   Object.defineProperty(p, name, {value: -45, writable: false});
    120   o.__proto__ = p;
    121 }
    122 
    123 function ReadonlyByProxy(o, name) {
    124   var p = Proxy.create({
    125     getPropertyDescriptor: function() {
    126       return {value: -46, writable: false, configurable: true};
    127     }
    128   });
    129   o.__proto__ = p;
    130 }
    131 
    132 var readonlys = [
    133   ReadonlyByNonwritableDataProperty, ReadonlyByAccessorPropertyWithoutSetter,
    134   ReadonlyByGetter, ReadonlyByFreeze, ReadonlyByProto, ReadonlyByProxy
    135 ]
    136 
    137 function TestAllReadonlys(f) {
    138   // Provide various methods to making a property read-only.
    139   for (var i = 0; i < readonlys.length; ++i) {
    140     print("  readonly =", i)
    141     f(readonlys[i]);
    142   }
    143 }
    144 
    145 
    146 // Different use scenarios.
    147 
    148 function Assign(o, x) {
    149   o.a = x;
    150 }
    151 
    152 function AssignStrict(o, x) {
    153   "use strict";
    154   o.a = x;
    155 }
    156 
    157 function TestAllModes(f) {
    158   for (var strict = 0; strict < 2; ++strict) {
    159     print(" strict =", strict);
    160     f(strict);
    161   }
    162 }
    163 
    164 function TestAllScenarios(f) {
    165   for (var t = 0; t < 100; t = 2*t + 1) {
    166     print("t =", t)
    167     f(function(strict, create, readonly) {
    168       // Make sure that the assignments are monomorphic.
    169       %DeoptimizeFunction(Assign);
    170       %DeoptimizeFunction(AssignStrict);
    171       %ClearFunctionTypeFeedback(Assign);
    172       %ClearFunctionTypeFeedback(AssignStrict);
    173       for (var i = 0; i < t; ++i) {
    174         var o = create();
    175         assertFalse("a" in o && !("a" in o.__proto__));
    176         if (strict === 0)
    177           Assign(o, i);
    178         else
    179           AssignStrict(o, i);
    180         assertEquals(i, o.a);
    181       }
    182       %OptimizeFunctionOnNextCall(Assign);
    183       %OptimizeFunctionOnNextCall(AssignStrict);
    184       var o = create();
    185       assertFalse("a" in o && !("a" in o.__proto__));
    186       readonly(o.up, "a");
    187       assertTrue("a" in o);
    188       if (strict === 0)
    189         Assign(o, t + 1);
    190       else
    191         assertThrows(function() { AssignStrict(o, t + 1) }, TypeError);
    192       assertTrue(o.a < 0);
    193     });
    194   }
    195 }
    196 
    197 
    198 // Runner.
    199 
    200 TestAllScenarios(function(scenario) {
    201   TestAllModes(function(strict) {
    202     TestAllReadonlys(function(readonly) {
    203       TestAllCreates(function(create) {
    204         scenario(strict, create, readonly);
    205       });
    206     });
    207   });
    208 });
    209 
    210 
    211 // Extra test forcing bailout.
    212 
    213 function Assign2(o, x) { o.a = x }
    214 
    215 (function() {
    216   var p = CreateFromConstructor(Object.prototype)();
    217   var c = CreateFromConstructor(p);
    218   for (var i = 0; i < 3; ++i) {
    219     var o = c();
    220     Assign2(o, i);
    221     assertEquals(i, o.a);
    222   }
    223   %OptimizeFunctionOnNextCall(Assign2);
    224   ReadonlyByNonwritableDataProperty(p, "a");
    225   var o = c();
    226   Assign2(o, 0);
    227   assertTrue(o.a < 0);
    228 })();
    229