// 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 --harmony-proxies --es5_readonly // 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; } function ReadonlyByProxy(o, name) { var p = Proxy.create({ 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; } function AssignStrict(o, x) { "use strict"; o.a = x; } 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); %ClearFunctionTypeFeedback(Assign); %ClearFunctionTypeFeedback(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 } (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); })();