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 30 // We specify max-opt-count because we opt/deopt the same function many 31 // times. 32 33 // It's nice to run this in other browsers too. 34 var standalone = false; 35 if (standalone) { 36 assertTrue = function(val) { 37 if (val != true) { 38 print("FAILURE"); 39 } 40 } 41 42 assertFalse = function(val) { 43 if (val != false) { 44 print("FAILURE"); 45 } 46 } 47 48 assertEquals = function(expected, val) { 49 if (expected !== val) { 50 print("FAILURE"); 51 } 52 } 53 54 empty_func = function(name) { } 55 assertUnoptimized = empty_func; 56 assertOptimized = empty_func; 57 58 optimize = empty_func; 59 clearFunctionTypeFeedback = empty_func; 60 deoptimizeFunction = empty_func; 61 } else { 62 optimize = function(name) { 63 %OptimizeFunctionOnNextCall(name); 64 } 65 clearFunctionTypeFeedback = function(name) { 66 %ClearFunctionTypeFeedback(name); 67 } 68 deoptimizeFunction = function(name) { 69 %DeoptimizeFunction(name); 70 } 71 } 72 73 function base_setter_test(create_func, index, store_value) { 74 var calls = 0; 75 76 // Testcase: setter in prototype chain 77 foo = function(a) { a[index] = store_value; } 78 var a = create_func(); 79 var ap = []; 80 ap.__defineSetter__(index, function() { calls++; }); 81 82 foo(a); 83 foo(a); 84 foo(a); 85 delete a[index]; 86 87 assertEquals(0, calls); 88 a.__proto__ = ap; 89 foo(a); 90 assertEquals(1, calls); 91 optimize(foo); 92 foo(a); 93 assertEquals(2, calls); 94 assertOptimized(foo); 95 96 // Testcase: setter added on prototype chain object already in place. 97 clearFunctionTypeFeedback(foo); 98 deoptimizeFunction(foo); 99 clearFunctionTypeFeedback(foo); 100 calls = 0; 101 a = create_func(); 102 var apap = []; 103 a.__proto__ = apap; 104 foo(a); 105 foo(a); 106 foo(a); 107 delete a[index]; 108 apap.__defineSetter__(index, function() { calls++; }); 109 foo(a); 110 foo(a); 111 foo(a); 112 assertEquals(3, calls); 113 114 // Testcase: setter "deep" in prototype chain. 115 clearFunctionTypeFeedback(foo); 116 deoptimizeFunction(foo); 117 clearFunctionTypeFeedback(foo); 118 calls = 0; 119 120 a = create_func(); 121 var ap2 = []; 122 a.__proto__ = ap2; 123 foo(a); 124 foo(a); 125 foo(a); 126 delete a[index]; 127 128 assertEquals(0, calls); 129 130 ap2.__proto__ = ap; // "sneak" in a callback. 131 // The sneak case should be caught by unoptimized code too. 132 assertUnoptimized(foo); 133 foo(a); 134 foo(a); 135 foo(a); 136 assertEquals(3, calls); 137 138 // Testcase: setter added after optimization (feedback is monomorphic) 139 clearFunctionTypeFeedback(foo); 140 deoptimizeFunction(foo); 141 clearFunctionTypeFeedback(foo); 142 calls = 0; 143 144 a = create_func(); 145 ap2 = []; 146 a.__proto__ = ap2; 147 foo(a); 148 foo(a); 149 foo(a); 150 optimize(foo); 151 foo(a); 152 assertOptimized(foo); 153 delete a[index]; 154 ap2.__proto__ = ap; 155 foo(a); 156 assertUnoptimized(foo); // map shape change should deopt foo. 157 assertEquals(1, calls); 158 159 // Testcase: adding additional setters to a prototype chain that already has 160 // one shouldn't deopt anything. (ie, we aren't changing the map shape). 161 clearFunctionTypeFeedback(foo); 162 calls = 0; 163 164 a = create_func(); 165 a.__proto__ = ap2; 166 bar = function(a) { a[index+1] = store_value; } 167 bar(a); 168 bar(a); 169 bar(a); // store should be generic 170 optimize(bar); 171 bar(a); 172 assertOptimized(bar); 173 assertEquals(0, calls); 174 delete a[index+1]; 175 ap2.__defineSetter__(index+1, function() { calls++; }); 176 bar(a); 177 assertOptimized(bar); 178 assertEquals(1, calls); 179 } 180 181 // Verify that map transitions don't confuse us. 182 create_func_smi = function() { return [,,,,,,5]; } 183 create_func_double = function() { return [0,,3.2,,,,5.5]; } 184 create_func_fast = function() { return [,,,,,,true]; } 185 create_func_dictionary = function() { var a = []; a.length = 100000; return a; } 186 187 var cf = [create_func_smi, 188 create_func_double, 189 create_func_fast, 190 create_func_dictionary]; 191 192 var values = [3, 3.5, true]; 193 194 for(var c = 0; c < cf.length; c++) { 195 for(var s = 0; s < values.length; s++) { 196 base_setter_test(cf[c], 0, values[s]); 197 base_setter_test(cf[c], 1, values[s]); 198 } 199 } 200