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