Home | History | Annotate | Download | only in mjsunit
      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: --allow-natives-syntax --smi-only-arrays --expose-gc
     29 // Flags: --track-allocation-sites --noalways-opt
     30 
     31 // Test element kind of objects.
     32 // Since --smi-only-arrays affects builtins, its default setting at compile
     33 // time sticks if built with snapshot.  If --smi-only-arrays is deactivated
     34 // by default, only a no-snapshot build actually has smi-only arrays enabled
     35 // in this test case.  Depending on whether smi-only arrays are actually
     36 // enabled, this test takes the appropriate code path to check smi-only arrays.
     37 
     38 // Reset the GC stress mode to be off. Needed because AllocationMementos only
     39 // live for one gc, so a gc that happens in certain fragile areas of the test
     40 // can break assumptions.
     41 %SetFlags("--gc-interval=-1")
     42 
     43 // support_smi_only_arrays = %HasFastSmiElements(new Array(1,2,3,4,5,6,7,8));
     44 support_smi_only_arrays = true;
     45 
     46 if (support_smi_only_arrays) {
     47   print("Tests include smi-only arrays.");
     48 } else {
     49   print("Tests do NOT include smi-only arrays.");
     50 }
     51 
     52 var elements_kind = {
     53   fast_smi_only            :  'fast smi only elements',
     54   fast                     :  'fast elements',
     55   fast_double              :  'fast double elements',
     56   dictionary               :  'dictionary elements',
     57   external_byte            :  'external byte elements',
     58   external_unsigned_byte   :  'external unsigned byte elements',
     59   external_short           :  'external short elements',
     60   external_unsigned_short  :  'external unsigned short elements',
     61   external_int             :  'external int elements',
     62   external_unsigned_int    :  'external unsigned int elements',
     63   external_float           :  'external float elements',
     64   external_double          :  'external double elements',
     65   external_pixel           :  'external pixel elements'
     66 }
     67 
     68 function getKind(obj) {
     69   if (%HasFastSmiElements(obj)) return elements_kind.fast_smi_only;
     70   if (%HasFastObjectElements(obj)) return elements_kind.fast;
     71   if (%HasFastDoubleElements(obj)) return elements_kind.fast_double;
     72   if (%HasDictionaryElements(obj)) return elements_kind.dictionary;
     73 }
     74 
     75 function isHoley(obj) {
     76   if (%HasFastHoleyElements(obj)) return true;
     77   return false;
     78 }
     79 
     80 function assertKind(expected, obj, name_opt) {
     81   if (!support_smi_only_arrays &&
     82       expected == elements_kind.fast_smi_only) {
     83     expected = elements_kind.fast;
     84   }
     85   assertEquals(expected, getKind(obj), name_opt);
     86 }
     87 
     88 if (support_smi_only_arrays) {
     89 
     90   // Test: If a call site goes megamorphic, it loses the ability to
     91   // use allocation site feedback.
     92   (function() {
     93     function bar(t, len) {
     94       return new t(len);
     95     }
     96 
     97     a = bar(Array, 10);
     98     a[0] = 3.5;
     99     b = bar(Array, 1);
    100     assertKind(elements_kind.fast_double, b);
    101     c = bar(Object, 3);
    102     b = bar(Array, 10);
    103     assertKind(elements_kind.fast_smi_only, b);
    104     b[0] = 3.5;
    105     c = bar(Array, 10);
    106     assertKind(elements_kind.fast_smi_only, c);
    107   })();
    108 
    109 
    110   // Test: ensure that crankshafted array constructor sites are deopted
    111   // if another function is used.
    112   (function() {
    113     function bar0(t) {
    114       return new t();
    115     }
    116     a = bar0(Array);
    117     a[0] = 3.5;
    118     b = bar0(Array);
    119     assertKind(elements_kind.fast_double, b);
    120     %OptimizeFunctionOnNextCall(bar0);
    121     b = bar0(Array);
    122     assertKind(elements_kind.fast_double, b);
    123     assertOptimized(bar0);
    124     // bar0 should deopt
    125     b = bar0(Object);
    126     assertUnoptimized(bar0)
    127     // When it's re-optimized, we should call through the full stub
    128     bar0(Array);
    129     %OptimizeFunctionOnNextCall(bar0);
    130     b = bar0(Array);
    131     // We also lost our ability to record kind feedback, as the site
    132     // is megamorphic now.
    133     assertKind(elements_kind.fast_smi_only, b);
    134     assertOptimized(bar0);
    135     b[0] = 3.5;
    136     c = bar0(Array);
    137     assertKind(elements_kind.fast_smi_only, c);
    138   })();
    139 
    140 
    141   // Test: Ensure that bailouts from the stub don't deopt a crankshafted
    142   // method with a call to that stub.
    143   (function() {
    144     function bar(len) {
    145       return new Array(len);
    146     }
    147     a = bar(10);
    148     a[0] = "a string";
    149     a = bar(10);
    150     assertKind(elements_kind.fast, a);
    151     %OptimizeFunctionOnNextCall(bar);
    152     a = bar(10);
    153     assertKind(elements_kind.fast, a);
    154     assertOptimized(bar);
    155     // The stub bails out, but the method call should be fine.
    156     a = bar(100000);
    157     assertOptimized(bar);
    158     assertKind(elements_kind.dictionary, a);
    159 
    160     // If the argument isn't a smi, it bails out as well
    161     a = bar("oops");
    162     assertOptimized(bar);
    163     assertKind(elements_kind.fast, a);
    164 
    165     function barn(one, two, three) {
    166       return new Array(one, two, three);
    167     }
    168 
    169     barn(1, 2, 3);
    170     barn(1, 2, 3);
    171     %OptimizeFunctionOnNextCall(barn);
    172     barn(1, 2, 3);
    173     assertOptimized(barn);
    174     a = barn(1, "oops", 3);
    175     // The stub should bail out but the method should remain optimized.
    176     assertKind(elements_kind.fast, a);
    177     assertOptimized(barn);
    178   })();
    179 
    180 
    181   // Test: When a method with array constructor is crankshafted, the type
    182   // feedback for elements kind is baked in. Verify that transitions don't
    183   // change it anymore
    184   (function() {
    185     function bar() {
    186       return new Array();
    187     }
    188     a = bar();
    189     bar();
    190     %OptimizeFunctionOnNextCall(bar);
    191     b = bar();
    192     // This only makes sense to test if we allow crankshafting
    193     if (4 != %GetOptimizationStatus(bar)) {
    194       assertOptimized(bar);
    195       %DebugPrint(3);
    196       b[0] = 3.5;
    197       c = bar();
    198       assertKind(elements_kind.fast_smi_only, c);
    199       assertOptimized(bar);
    200     }
    201   })();
    202 
    203 
    204   // Test: create arrays in two contexts, verifying that the correct
    205   // map for Array in that context will be used.
    206   (function() {
    207     function bar() { return new Array(); }
    208     bar();
    209     bar();
    210     %OptimizeFunctionOnNextCall(bar);
    211     a = bar();
    212     assertTrue(a instanceof Array);
    213 
    214     var contextB = Realm.create();
    215     Realm.eval(contextB, "function bar2() { return new Array(); };");
    216     Realm.eval(contextB, "bar2(); bar2();");
    217     Realm.eval(contextB, "%OptimizeFunctionOnNextCall(bar2);");
    218     Realm.eval(contextB, "bar2();");
    219     assertFalse(Realm.eval(contextB, "bar2();") instanceof Array);
    220     assertTrue(Realm.eval(contextB, "bar2() instanceof Array"));
    221   })();
    222 }
    223