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 --max-opt-count=100 --noalways-opt 29// Flags: --nocollect-maps 30 31// We specify max-opt-count because we opt/deopt the same function many 32// times. 33 34// We specify nocollect-maps because in gcstress we can end up deoptimizing 35// a function in a gc in the stack guard at the beginning of the (optimized) 36// function due to leftover map clearing work that results in deoptimizing 37// dependent code from those maps. The choice is to insert strategic gc() 38// calls or specify this flag. 39 40// It's nice to run this in other browsers too. 41var standalone = false; 42if (standalone) { 43 assertTrue = function(val) { 44 if (val != true) { 45 print("FAILURE"); 46 } 47 } 48 49 assertFalse = function(val) { 50 if (val != false) { 51 print("FAILURE"); 52 } 53 } 54 55 assertEquals = function(expected, val) { 56 if (expected !== val) { 57 print("FAILURE"); 58 } 59 } 60 61 empty_func = function(name) { } 62 assertUnoptimized = empty_func; 63 assertOptimized = empty_func; 64 65 optimize = empty_func; 66 clearFunctionTypeFeedback = empty_func; 67 deoptimizeFunction = empty_func; 68} else { 69 optimize = function(name) { 70 %OptimizeFunctionOnNextCall(name); 71 } 72 clearFunctionTypeFeedback = function(name) { 73 %ClearFunctionTypeFeedback(name); 74 } 75 deoptimizeFunction = function(name) { 76 %DeoptimizeFunction(name); 77 } 78} 79 80function base_getter_test(create_func) { 81 var calls = 0; 82 83 // Testcase: setter in prototype chain 84 foo = function(a) { var x = a[0]; return x + 3; } 85 var a = create_func(); 86 var ap = []; 87 ap.__defineGetter__(0, function() { calls++; return 0; }); 88 89 foo(a); 90 foo(a); 91 foo(a); 92 delete a[0]; 93 94 assertEquals(0, calls); 95 a.__proto__ = ap; 96 foo(a); 97 assertEquals(1, calls); 98 optimize(foo); 99 foo(a); 100 assertEquals(2, calls); 101 assertOptimized(foo); 102 103 // Testcase: getter "deep" in prototype chain. 104 clearFunctionTypeFeedback(foo); 105 deoptimizeFunction(foo); 106 clearFunctionTypeFeedback(foo); 107 calls = 0; 108 109 a = create_func(); 110 var ap2 = []; 111 a.__proto__ = ap2; 112 foo(a); 113 foo(a); 114 foo(a); 115 delete a[0]; 116 117 assertEquals(0, calls); 118 119 ap2.__proto__ = ap; // "sneak" in a callback. 120 // The sneak case should be caught by unoptimized code too. 121 assertUnoptimized(foo); 122 foo(a); 123 foo(a); 124 foo(a); 125 assertEquals(3, calls); 126 127 // Testcase: getter added after optimization (feedback is monomorphic) 128 clearFunctionTypeFeedback(foo); 129 deoptimizeFunction(foo); 130 clearFunctionTypeFeedback(foo); 131 calls = 0; 132 133 a = create_func(); 134 ap2 = []; 135 a.__proto__ = ap2; 136 foo(a); 137 foo(a); 138 foo(a); 139 optimize(foo); 140 foo(a); 141 assertOptimized(foo); 142 delete a[0]; 143 ap2.__proto__ = ap; 144 foo(a); 145 assertOptimized(foo); // getters don't require deopt on shape change. 146 assertEquals(1, calls); 147 148 // Testcase: adding additional getters to a prototype chain that already has 149 // one shouldn't deopt anything. 150 clearFunctionTypeFeedback(foo); 151 calls = 0; 152 153 a = create_func(); 154 a.__proto__ = ap2; 155 bar = function(a) { return a[3] + 600; } 156 bar(a); 157 bar(a); 158 bar(a); 159 optimize(bar); 160 bar(a); 161 assertOptimized(bar); 162 assertEquals(0, calls); 163 delete a[3]; 164 ap2.__defineGetter__(3, function() { calls++; return 0; }); 165 bar(a); 166 assertOptimized(bar); 167 assertEquals(1, calls); 168} 169 170// Verify that map transitions don't confuse us. 171create_func_smi = function() { return [,,,,,,5]; } 172create_func_double = function() { return [,,,,,,5.5]; } 173create_func_fast = function() { return [,,,,,,true]; } 174 175var cf = [create_func_smi, 176 create_func_double, 177 create_func_fast]; 178 179for(var c = 0; c < 3; c++) { 180 base_getter_test(cf[c]); 181} 182 183// A special test for LoadKeyedHoleMode. Ensure that optimized is generated 184// which sets ALLOW_RETURN_HOLE, then add a setter on the prototype that should 185// cause the function to deoptimize. 186 187var a = [3.5,,,3.5]; 188fun = function(a) { return a[0] + 5.5; } 189fun(a); 190fun(a); 191fun(a); // should have a monomorphic KeyedLoadIC. 192optimize(fun); 193fun(a); 194assertOptimized(fun); 195 196// returning undefined shouldn't phase us. 197delete a[0]; 198fun(a); 199assertOptimized(fun); 200 201// but messing up the prototype chain will. 202a.__proto__ = []; 203fun(a); 204assertUnoptimized(fun); 205 206// Construct a non-trivial prototype chain. 207var a = [3.5,,,,3.5]; 208var ap = [,,3.5]; 209ap.__proto__ = a.__proto__; 210a.__proto__ = ap; 211fun(a); 212optimize(fun); 213fun(a); 214assertOptimized(fun); 215 216var calls = 0; 217delete a[0]; 218ap.__defineGetter__(0, function() { calls++; return 0; }); 219fun(a); 220assertEquals(1, calls); 221assertUnoptimized(fun); 222