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 --expose-gc
     29 // Flags: --noalways-opt
     30 
     31 // Test element kind of objects.
     32 
     33 var elements_kind = {
     34   fast_smi_only            :  'fast smi only elements',
     35   fast                     :  'fast elements',
     36   fast_double              :  'fast double elements',
     37   dictionary               :  'dictionary elements',
     38   external_byte            :  'external byte elements',
     39   external_unsigned_byte   :  'external unsigned byte elements',
     40   external_short           :  'external short elements',
     41   external_unsigned_short  :  'external unsigned short elements',
     42   external_int             :  'external int elements',
     43   external_unsigned_int    :  'external unsigned int elements',
     44   external_float           :  'external float elements',
     45   external_double          :  'external double elements',
     46   external_pixel           :  'external pixel elements'
     47 }
     48 
     49 function getKind(obj) {
     50   if (%HasFastSmiElements(obj)) return elements_kind.fast_smi_only;
     51   if (%HasFastObjectElements(obj)) return elements_kind.fast;
     52   if (%HasFastDoubleElements(obj)) return elements_kind.fast_double;
     53   if (%HasDictionaryElements(obj)) return elements_kind.dictionary;
     54 }
     55 
     56 function isHoley(obj) {
     57   if (%HasFastHoleyElements(obj)) return true;
     58   return false;
     59 }
     60 
     61 function assertKind(expected, obj, name_opt) {
     62   assertEquals(expected, getKind(obj), name_opt);
     63 }
     64 
     65 // Test: If a call site goes megamorphic, it retains the ability to
     66 // use allocation site feedback (if FLAG_allocation_site_pretenuring
     67 // is on).
     68 (function() {
     69   function bar(t, len) {
     70     return new t(len);
     71   }
     72 
     73   a = bar(Array, 10);
     74   a[0] = 3.5;
     75   b = bar(Array, 1);
     76   assertKind(elements_kind.fast_double, b);
     77   c = bar(Object, 3);
     78   b = bar(Array, 10);
     79   // TODO(mvstanton): re-enable when FLAG_allocation_site_pretenuring
     80   // is on in the build.
     81   // assertKind(elements_kind.fast_double, b);
     82 })();
     83 
     84 
     85 // Test: ensure that crankshafted array constructor sites are deopted
     86 // if another function is used.
     87 (function() {
     88   function bar0(t) {
     89     return new t();
     90   }
     91   a = bar0(Array);
     92   a[0] = 3.5;
     93   b = bar0(Array);
     94   assertKind(elements_kind.fast_double, b);
     95     %OptimizeFunctionOnNextCall(bar0);
     96   b = bar0(Array);
     97   assertKind(elements_kind.fast_double, b);
     98   assertOptimized(bar0);
     99   // bar0 should deopt
    100   b = bar0(Object);
    101   assertUnoptimized(bar0)
    102   // When it's re-optimized, we should call through the full stub
    103   bar0(Array);
    104     %OptimizeFunctionOnNextCall(bar0);
    105   b = bar0(Array);
    106   // This only makes sense to test if we allow crankshafting
    107   if (4 != %GetOptimizationStatus(bar0)) {
    108     // We also lost our ability to record kind feedback, as the site
    109     // is megamorphic now.
    110     assertKind(elements_kind.fast_smi_only, b);
    111     assertOptimized(bar0);
    112     b[0] = 3.5;
    113     c = bar0(Array);
    114     assertKind(elements_kind.fast_smi_only, c);
    115   }
    116 })();
    117 
    118 
    119 // Test: Ensure that inlined array calls in crankshaft learn from deopts
    120 // based on the move to a dictionary for the array.
    121 (function() {
    122   function bar(len) {
    123     return new Array(len);
    124   }
    125   a = bar(10);
    126   a[0] = "a string";
    127   a = bar(10);
    128   assertKind(elements_kind.fast, a);
    129     %OptimizeFunctionOnNextCall(bar);
    130   a = bar(10);
    131   assertKind(elements_kind.fast, a);
    132   assertOptimized(bar);
    133   bar(100000);
    134   assertOptimized(bar);
    135 
    136   // If the argument isn't a smi, things should still work.
    137   a = bar("oops");
    138   assertOptimized(bar);
    139   assertKind(elements_kind.fast, a);
    140 
    141   function barn(one, two, three) {
    142     return new Array(one, two, three);
    143   }
    144 
    145   barn(1, 2, 3);
    146   barn(1, 2, 3);
    147     %OptimizeFunctionOnNextCall(barn);
    148   barn(1, 2, 3);
    149   assertOptimized(barn);
    150   a = barn(1, "oops", 3);
    151   assertOptimized(barn);
    152 })();
    153 
    154 
    155 // Test: When a method with array constructor is crankshafted, the type
    156 // feedback for elements kind is baked in. Verify that transitions don't
    157 // change it anymore
    158 (function() {
    159   function bar() {
    160     return new Array();
    161   }
    162   a = bar();
    163   bar();
    164     %OptimizeFunctionOnNextCall(bar);
    165   b = bar();
    166   // This only makes sense to test if we allow crankshafting
    167   if (4 != %GetOptimizationStatus(bar)) {
    168     assertOptimized(bar);
    169       %DebugPrint(3);
    170     b[0] = 3.5;
    171     c = bar();
    172     assertKind(elements_kind.fast_smi_only, c);
    173     assertOptimized(bar);
    174   }
    175 })();
    176 
    177 
    178 // Test: create arrays in two contexts, verifying that the correct
    179 // map for Array in that context will be used.
    180 (function() {
    181   function bar() { return new Array(); }
    182   bar();
    183   bar();
    184     %OptimizeFunctionOnNextCall(bar);
    185   a = bar();
    186   assertTrue(a instanceof Array);
    187 
    188   var contextB = Realm.create();
    189   Realm.eval(contextB, "function bar2() { return new Array(); };");
    190   Realm.eval(contextB, "bar2(); bar2();");
    191   Realm.eval(contextB, "%OptimizeFunctionOnNextCall(bar2);");
    192   Realm.eval(contextB, "bar2();");
    193   assertFalse(Realm.eval(contextB, "bar2();") instanceof Array);
    194   assertTrue(Realm.eval(contextB, "bar2() instanceof Array"));
    195 })();
    196 
    197 // Test: create array with packed feedback, then optimize function, which
    198 // should deal with arguments that create holey arrays.
    199 (function() {
    200   function bar(len) { return new Array(len); }
    201   bar(0);
    202   bar(0);
    203     %OptimizeFunctionOnNextCall(bar);
    204   a = bar(0);
    205   assertOptimized(bar);
    206   assertFalse(isHoley(a));
    207   a = bar(1);  // ouch!
    208   assertOptimized(bar);
    209   assertTrue(isHoley(a));
    210   a = bar(100);
    211   assertTrue(isHoley(a));
    212   a = bar(0);
    213   assertOptimized(bar);
    214   // Crankshafted functions don't use mementos, so feedback still
    215   // indicates a packed array is desired. (unless --nocrankshaft is in use).
    216   if (4 != %GetOptimizationStatus(bar)) {
    217     assertFalse(isHoley(a));
    218   }
    219 })();
    220