1 // Copyright 2012 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: --optimize-for-in --allow-natives-syntax 29 // Flags: --no-concurrent-osr 30 31 // Test for-in support in Crankshaft. For simplicity this tests assumes certain 32 // fixed iteration order for properties and will have to be adjusted if V8 33 // stops following insertion order. 34 35 36 function a(t) { 37 var result = []; 38 for (var i in t) { 39 result.push(i + t[i]); 40 } 41 return result.join(''); 42 } 43 44 // Check that we correctly deoptimize on map check. 45 function b(t) { 46 var result = []; 47 for (var i in t) { 48 result.push(i + t[i]); 49 delete t[i]; 50 } 51 return result.join(''); 52 } 53 54 // Check that we correctly deoptimize during preparation step. 55 function c(t) { 56 var result = []; 57 for (var i in t) { 58 result.push(i + t[i]); 59 } 60 return result.join(''); 61 } 62 63 // Check that we deoptimize to the place after side effect in the right state. 64 function d(t) { 65 var result = []; 66 var o; 67 for (var i in (o = t())) { 68 result.push(i + o[i]); 69 } 70 return result.join(''); 71 } 72 73 // Check that we correctly deoptimize on map check inserted for fused load. 74 function e(t) { 75 var result = []; 76 for (var i in t) { 77 delete t[i]; 78 t[i] = i; 79 result.push(i + t[i]); 80 } 81 return result.join(''); 82 } 83 84 // Nested for-in loops. 85 function f(t) { 86 var result = []; 87 for (var i in t) { 88 for (var j in t) { 89 result.push(i + j + t[i] + t[j]); 90 } 91 } 92 return result.join(''); 93 } 94 95 // Deoptimization from the inner for-in loop. 96 function g(t) { 97 var result = []; 98 for (var i in t) { 99 for (var j in t) { 100 result.push(i + j + t[i] + t[j]); 101 var v = t[i]; 102 delete t[i]; 103 t[i] = v; 104 } 105 } 106 return result.join(''); 107 } 108 109 110 // Break from the inner for-in loop. 111 function h(t, deopt) { 112 var result = []; 113 for (var i in t) { 114 for (var j in t) { 115 result.push(i + j + t[i] + t[j]); 116 break; 117 } 118 } 119 deopt.deopt; 120 return result.join(''); 121 } 122 123 // Continue in the inner loop. 124 function j(t, deopt) { 125 var result = []; 126 for (var i in t) { 127 for (var j in t) { 128 result.push(i + j + t[i] + t[j]); 129 continue; 130 } 131 } 132 deopt.deopt; 133 return result.join(''); 134 } 135 136 // Continue of the outer loop. 137 function k(t, deopt) { 138 var result = []; 139 outer: for (var i in t) { 140 for (var j in t) { 141 result.push(i + j + t[i] + t[j]); 142 continue outer; 143 } 144 } 145 deopt.deopt; 146 return result.join(''); 147 } 148 149 // Break of the outer loop. 150 function l(t, deopt) { 151 var result = []; 152 outer: for (var i in t) { 153 for (var j in t) { 154 result.push(i + j + t[i] + t[j]); 155 break outer; 156 } 157 } 158 deopt.deopt; 159 return result.join(''); 160 } 161 162 // Test deoptimization from inlined frame (currently it is not inlined). 163 function m0(t, deopt) { 164 for (var i in t) { 165 for (var j in t) { 166 deopt.deopt; 167 return i + j + t[i] + t[j]; 168 } 169 } 170 } 171 172 function m(t, deopt) { 173 return m0(t, deopt); 174 } 175 176 177 function tryFunction(s, mkT, f) { 178 var d = {deopt: false}; 179 assertEquals(s, f(mkT(), d)); 180 assertEquals(s, f(mkT(), d)); 181 assertEquals(s, f(mkT(), d)); 182 %OptimizeFunctionOnNextCall(f); 183 assertEquals(s, f(mkT(), d)); 184 assertEquals(s, f(mkT(), {})); 185 } 186 187 var s = "a1b2c3d4"; 188 function mkTable() { return { a: "1", b: "2", c: "3", d: "4" }; } 189 190 191 tryFunction(s, mkTable, a); 192 tryFunction(s, mkTable, b); 193 tryFunction("0a1b2c3d", function () { return "abcd"; }, c); 194 tryFunction("0a1b2c3d", function () { 195 var cnt = false; 196 return function () { 197 cnt = true; 198 return "abcd"; 199 } 200 }, d); 201 tryFunction("aabbccdd", mkTable, e); 202 203 function mkSmallTable() { return { a: "1", b: "2" }; } 204 205 tryFunction("aa11ab12ba21bb22", mkSmallTable, f); 206 tryFunction("aa11ab12bb22ba21", mkSmallTable, g); 207 tryFunction("aa11ba21", mkSmallTable, h); 208 tryFunction("aa11ab12ba21bb22", mkSmallTable, j); 209 tryFunction("aa11ba21", mkSmallTable, h); 210 tryFunction("aa11ba21", mkSmallTable, k); 211 tryFunction("aa11", mkSmallTable, l); 212 tryFunction("aa11", mkSmallTable, m); 213 214 // Test handling of null. 215 tryFunction("", function () { 216 return function () { return null; } 217 }, function (t) { 218 for (var i in t()) { return i; } 219 return ""; 220 }); 221 222 // Test smis. 223 tryFunction("", function () { 224 return function () { return 11; } 225 }, function (t) { 226 for (var i in t()) { return i; } 227 return ""; 228 }); 229 230 // Test LoadFieldByIndex for out of object properties. 231 function O() { this.a = 1; } 232 for (var i = 0; i < 10; i++) new O(); 233 tryFunction("a1b2c3d4e5f6", function () { 234 var o = new O(); 235 o.b = 2; 236 o.c = 3; 237 o.d = 4; 238 o.e = 5; 239 o.f = 6; 240 return o; 241 }, function (t) { 242 var r = []; 243 for (var i in t) r.push(i + t[i]); 244 return r.join(''); 245 }); 246 247 // Test OSR inside for-in. 248 function osr_inner(t, limit) { 249 var r = 1; 250 for (var x in t) { 251 if (t.hasOwnProperty(x)) { 252 for (var i = 0; i < t[x].length; i++) { 253 r += t[x][i]; 254 if (i === limit) { 255 %OptimizeFunctionOnNextCall(osr_inner, "osr"); 256 } 257 } 258 r += x; 259 } 260 } 261 return r; 262 } 263 264 function osr_outer(t, osr_after) { 265 var r = 1; 266 for (var x in t) { 267 for (var i = 0; i < t[x].length; i++) { 268 r += t[x][i]; 269 } 270 if (x === osr_after) { 271 %OptimizeFunctionOnNextCall(osr_outer, "osr"); 272 } 273 r += x; 274 } 275 return r; 276 } 277 278 function osr_outer_and_deopt(t, osr_after) { 279 var r = 1; 280 for (var x in t) { 281 r += x; 282 if (x == osr_after) { 283 %OptimizeFunctionOnNextCall(osr_outer_and_deopt, "osr"); 284 } 285 } 286 return r; 287 } 288 289 function test_osr() { 290 with ({}) {} // Disable optimizations of this function. 291 var arr = new Array(20); 292 for (var i = 0; i < arr.length; i++) { 293 arr[i] = i + 1; 294 } 295 arr.push(":"); // Force deopt at the end of the loop. 296 assertEquals("211:x1234567891011121314151617181920:y", osr_inner({x: arr, y: arr}, (arr.length / 2) | 0)); 297 assertEquals("7x456y", osr_outer({x: [1,2,3], y: [4,5,6]}, "x")); 298 assertEquals("101234567", osr_outer_and_deopt([1,2,3,4,5,6,7,8], "5")); 299 } 300 301 test_osr(); 302