| // Copyright 2011 the V8 project authors. All rights reserved. | 
 | // Redistribution and use in source and binary forms, with or without | 
 | // modification, are permitted provided that the following conditions are | 
 | // met: | 
 | // | 
 | //     * Redistributions of source code must retain the above copyright | 
 | //       notice, this list of conditions and the following disclaimer. | 
 | //     * Redistributions in binary form must reproduce the above | 
 | //       copyright notice, this list of conditions and the following | 
 | //       disclaimer in the documentation and/or other materials provided | 
 | //       with the distribution. | 
 | //     * Neither the name of Google Inc. nor the names of its | 
 | //       contributors may be used to endorse or promote products derived | 
 | //       from this software without specific prior written permission. | 
 | // | 
 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 
 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 
 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | 
 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | 
 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 
 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 
 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 
 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 
 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 
 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 
 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 
 |  | 
 | // Flags: --allow-natives-syntax | 
 |  | 
 | // Different ways to create an object. | 
 |  | 
 | function CreateFromLiteral() { | 
 |   return {}; | 
 | } | 
 |  | 
 | function CreateFromObject() { | 
 |   return new Object(); | 
 | } | 
 |  | 
 | function CreateDefault() { | 
 |   return Object.create(Object.prototype); | 
 | } | 
 |  | 
 | function CreateFromConstructor(proto) { | 
 |   function C() {} | 
 |   new C().b = 9;  // Make sure that we can have an in-object property. | 
 |   C.prototype = proto; | 
 |   return function() { | 
 |     return new C(); | 
 |   }; | 
 | } | 
 |  | 
 | function CreateFromApi(proto) { | 
 |   return function() { | 
 |     return Object.create(proto); | 
 |   }; | 
 | } | 
 |  | 
 | function CreateWithProperty(proto) { | 
 |   function C() { | 
 |     this.a = -100; | 
 |   } | 
 |   C.prototype = proto; | 
 |   return function() { | 
 |     return new C(); | 
 |   }; | 
 | } | 
 |  | 
 | var bases = [CreateFromLiteral, CreateFromObject, CreateDefault]; | 
 | var inherits = [CreateFromConstructor, CreateFromApi, CreateWithProperty]; | 
 | var constructs = [CreateFromConstructor, CreateFromApi]; | 
 |  | 
 | function TestAllCreates(f) { | 
 |   // The depth of the prototype chain up the. | 
 |   for (var depth = 0; depth < 3; ++depth) { | 
 |     // Introduce readonly-ness this far up the chain. | 
 |     for (var up = 0; up <= depth; ++up) { | 
 |       // Try different construction methods. | 
 |       for (var k = 0; k < constructs.length; ++k) { | 
 |         // Construct a fresh prototype chain from above functions. | 
 |         for (var i = 0; i < bases.length; ++i) { | 
 |           var p = bases[i](); | 
 |           // There may be a preexisting property under the insertion point... | 
 |           for (var j = 0; j < depth - up; ++j) { | 
 |             p = inherits[Math.floor(inherits.length * Math.random())](p)(); | 
 |           } | 
 |           // ...but not above it. | 
 |           for (var j = 0; j < up; ++j) { | 
 |             p = constructs[Math.floor(constructs.length * Math.random())](p)(); | 
 |           } | 
 |           // Create a fresh constructor. | 
 |           var c = constructs[k](p); | 
 |           f(function() { | 
 |             var o = c(); | 
 |             o.up = o; | 
 |             for (var j = 0; j < up; ++j) o.up = Object.getPrototypeOf(o.up); | 
 |             return o; | 
 |           }); | 
 |         } | 
 |       } | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 |  | 
 | // Different ways to make a property read-only. | 
 |  | 
 | function ReadonlyByNonwritableDataProperty(o, name) { | 
 |   Object.defineProperty(o, name, {value: -41, writable: false}); | 
 | } | 
 |  | 
 | function ReadonlyByAccessorPropertyWithoutSetter(o, name) { | 
 |   Object.defineProperty(o, name, { | 
 |     get: function() { | 
 |       return -42; | 
 |     } | 
 |   }); | 
 | } | 
 |  | 
 | function ReadonlyByGetter(o, name) { | 
 |   o.__defineGetter__('a', function() { | 
 |     return -43; | 
 |   }); | 
 | } | 
 |  | 
 | function ReadonlyByFreeze(o, name) { | 
 |   o[name] = -44; | 
 |   Object.freeze(o); | 
 | } | 
 |  | 
 | function ReadonlyByProto(o, name) { | 
 |   var p = Object.create(o.__proto__); | 
 |   Object.defineProperty(p, name, {value: -45, writable: false}); | 
 |   o.__proto__ = p; | 
 | } | 
 |  | 
 | // TODO(neis,cbruni): Enable once the necessary traps work again. | 
 | // Allow Proxy to be undefined, so test can run in non-Harmony mode as well. | 
 | var global = this; | 
 |  | 
 | function ReadonlyByProxy(o, name) { | 
 |   if (!global.Proxy) return ReadonlyByFreeze(o, name);  // Dummy. | 
 |   var p = new global.Proxy({}, { | 
 |     getPropertyDescriptor: function() { | 
 |       return {value: -46, writable: false, configurable: true}; | 
 |     } | 
 |   }); | 
 |  | 
 |   o.__proto__ = p; | 
 | } | 
 |  | 
 | var readonlys = [ | 
 |   ReadonlyByNonwritableDataProperty, ReadonlyByAccessorPropertyWithoutSetter, | 
 |   ReadonlyByGetter, ReadonlyByFreeze, ReadonlyByProto  // ReadonlyByProxy | 
 | ]; | 
 |  | 
 | function TestAllReadonlys(f) { | 
 |   // Provide various methods to making a property read-only. | 
 |   for (var i = 0; i < readonlys.length; ++i) { | 
 |     print('  readonly =', i); | 
 |     f(readonlys[i]); | 
 |   } | 
 | } | 
 |  | 
 |  | 
 | // Different use scenarios. | 
 |  | 
 | function Assign(o, x) { | 
 |   o.a = x; | 
 | }; | 
 | %PrepareFunctionForOptimization(Assign); | 
 | function AssignStrict(o, x) { | 
 |   "use strict"; | 
 |   o.a = x; | 
 | }; | 
 | %PrepareFunctionForOptimization(AssignStrict); | 
 | function TestAllModes(f) { | 
 |   for (var strict = 0; strict < 2; ++strict) { | 
 |     print(" strict =", strict); | 
 |     f(strict); | 
 |   } | 
 | } | 
 |  | 
 | function TestAllScenarios(f) { | 
 |   for (var t = 0; t < 100; t = 2 * t + 1) { | 
 |     print('t =', t); | 
 |     f(function(strict, create, readonly) { | 
 |       // Make sure that the assignments are monomorphic. | 
 |       %DeoptimizeFunction(Assign); | 
 |       %DeoptimizeFunction(AssignStrict); | 
 |       %ClearFunctionFeedback(Assign); | 
 |       %ClearFunctionFeedback(AssignStrict); | 
 |       %PrepareFunctionForOptimization(Assign); | 
 |       %PrepareFunctionForOptimization(AssignStrict); | 
 |       for (var i = 0; i < t; ++i) { | 
 |         var o = create(); | 
 |         assertFalse("a" in o && !("a" in o.__proto__)); | 
 |         if (strict === 0) | 
 |           Assign(o, i); | 
 |         else | 
 |           AssignStrict(o, i); | 
 |         assertEquals(i, o.a); | 
 |       } | 
 |       %OptimizeFunctionOnNextCall(Assign); | 
 |       %OptimizeFunctionOnNextCall(AssignStrict); | 
 |       var o = create(); | 
 |       assertFalse("a" in o && !("a" in o.__proto__)); | 
 |       readonly(o.up, "a"); | 
 |       assertTrue("a" in o); | 
 |       if (strict === 0) | 
 |         Assign(o, t + 1); | 
 |       else | 
 |  | 
 |         assertThrows(function() { | 
 |           AssignStrict(o, t + 1); | 
 |         }, TypeError); | 
 |       assertTrue(o.a < 0); | 
 |     }); | 
 |   } | 
 | } | 
 |  | 
 |  | 
 | // Runner. | 
 |  | 
 | TestAllScenarios(function(scenario) { | 
 |   TestAllModes(function(strict) { | 
 |     TestAllReadonlys(function(readonly) { | 
 |       TestAllCreates(function(create) { | 
 |         scenario(strict, create, readonly); | 
 |       }); | 
 |     }); | 
 |   }); | 
 | }); | 
 |  | 
 | // Extra test forcing bailout. | 
 |  | 
 | function Assign2(o, x) { | 
 |   o.a = x; | 
 | }; | 
 | %PrepareFunctionForOptimization(Assign2); | 
 | (function() { | 
 | var p = CreateFromConstructor(Object.prototype)(); | 
 | var c = CreateFromConstructor(p); | 
 | for (var i = 0; i < 3; ++i) { | 
 |   var o = c(); | 
 |   Assign2(o, i); | 
 |   assertEquals(i, o.a); | 
 | } | 
 | %OptimizeFunctionOnNextCall(Assign2); | 
 | ReadonlyByNonwritableDataProperty(p, "a"); | 
 | var o = c(); | 
 | Assign2(o, 0); | 
 | assertTrue(o.a < 0); | 
 | })(); |