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
     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 // Allow Proxy to be undefined, so test can run in non-Harmony mode as well.
    124 var global = this;
    125 
    126 function ReadonlyByProxy(o, name) {
    127   if (!global.Proxy) return ReadonlyByFreeze(o, name);  // Dummy.
    128   var p = global.Proxy.create({
    129     getPropertyDescriptor: function() {
    130       return {value: -46, writable: false, configurable: true};
    131     }
    132   });
    133   o.__proto__ = p;
    134 }
    135 
    136 var readonlys = [
    137   ReadonlyByNonwritableDataProperty, ReadonlyByAccessorPropertyWithoutSetter,
    138   ReadonlyByGetter, ReadonlyByFreeze, ReadonlyByProto, ReadonlyByProxy
    139 ]
    140 
    141 function TestAllReadonlys(f) {
    142   // Provide various methods to making a property read-only.
    143   for (var i = 0; i < readonlys.length; ++i) {
    144     print("  readonly =", i)
    145     f(readonlys[i]);
    146   }
    147 }
    148 
    149 
    150 // Different use scenarios.
    151 
    152 function Assign(o, x) {
    153   o.a = x;
    154 }
    155 
    156 function AssignStrict(o, x) {
    157   "use strict";
    158   o.a = x;
    159 }
    160 
    161 function TestAllModes(f) {
    162   for (var strict = 0; strict < 2; ++strict) {
    163     print(" strict =", strict);
    164     f(strict);
    165   }
    166 }
    167 
    168 function TestAllScenarios(f) {
    169   for (var t = 0; t < 100; t = 2*t + 1) {
    170     print("t =", t)
    171     f(function(strict, create, readonly) {
    172       // Make sure that the assignments are monomorphic.
    173       %DeoptimizeFunction(Assign);
    174       %DeoptimizeFunction(AssignStrict);
    175       %ClearFunctionTypeFeedback(Assign);
    176       %ClearFunctionTypeFeedback(AssignStrict);
    177       for (var i = 0; i < t; ++i) {
    178         var o = create();
    179         assertFalse("a" in o && !("a" in o.__proto__));
    180         if (strict === 0)
    181           Assign(o, i);
    182         else
    183           AssignStrict(o, i);
    184         assertEquals(i, o.a);
    185       }
    186       %OptimizeFunctionOnNextCall(Assign);
    187       %OptimizeFunctionOnNextCall(AssignStrict);
    188       var o = create();
    189       assertFalse("a" in o && !("a" in o.__proto__));
    190       readonly(o.up, "a");
    191       assertTrue("a" in o);
    192       if (strict === 0)
    193         Assign(o, t + 1);
    194       else
    195         assertThrows(function() { AssignStrict(o, t + 1) }, TypeError);
    196       assertTrue(o.a < 0);
    197     });
    198   }
    199 }
    200 
    201 
    202 // Runner.
    203 
    204 TestAllScenarios(function(scenario) {
    205   TestAllModes(function(strict) {
    206     TestAllReadonlys(function(readonly) {
    207       TestAllCreates(function(create) {
    208         scenario(strict, create, readonly);
    209       });
    210     });
    211   });
    212 });
    213 
    214 
    215 // Extra test forcing bailout.
    216 
    217 function Assign2(o, x) { o.a = x }
    218 
    219 (function() {
    220   var p = CreateFromConstructor(Object.prototype)();
    221   var c = CreateFromConstructor(p);
    222   for (var i = 0; i < 3; ++i) {
    223     var o = c();
    224     Assign2(o, i);
    225     assertEquals(i, o.a);
    226   }
    227   %OptimizeFunctionOnNextCall(Assign2);
    228   ReadonlyByNonwritableDataProperty(p, "a");
    229   var o = c();
    230   Assign2(o, 0);
    231   assertTrue(o.a < 0);
    232 })();
    233