Home | History | Annotate | Download | only in mjsunit
      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