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: --allow-natives-syntax --inline-accessors --max-opt-count=100
     29 
     30 var accessorCallCount, setterArgument, setterValue, obj, forceDeopt;
     31 
     32 // -----------------------------------------------------------------------------
     33 // Helpers for testing inlining of getters.
     34 
     35 function TestInlinedGetter(context, obj, expected) {
     36   forceDeopt = { deopt: 0 };
     37   accessorCallCount = 0;
     38 
     39   assertEquals(expected, context(obj));
     40   assertEquals(1, accessorCallCount);
     41 
     42   assertEquals(expected, context(obj));
     43   assertEquals(2, accessorCallCount);
     44 
     45   %OptimizeFunctionOnNextCall(context);
     46   assertEquals(expected, context(obj));
     47   assertEquals(3, accessorCallCount);
     48 
     49   forceDeopt = { /* empty*/ };
     50   assertEquals(expected, context(obj));
     51   assertEquals(4, accessorCallCount);
     52 }
     53 
     54 
     55 function value_context_for_getter(obj) {
     56   return obj.getterProperty;
     57 }
     58 
     59 function test_context_for_getter(obj) {
     60   if (obj.getterProperty) {
     61     return 111;
     62   } else {
     63     return 222;
     64   }
     65 }
     66 
     67 function effect_context_for_getter(obj) {
     68   obj.getterProperty;
     69   return 5678;
     70 }
     71 
     72 function TryGetter(context, getter, obj, expected, expectException) {
     73   try {
     74     TestInlinedGetter(context, obj, expected);
     75     assertFalse(expectException);
     76   } catch (exception) {
     77     assertTrue(expectException);
     78     assertEquals(7, exception.stack.split('\n').length);
     79   }
     80   %DeoptimizeFunction(context);
     81   %ClearFunctionTypeFeedback(context);
     82   %ClearFunctionTypeFeedback(getter);
     83 }
     84 
     85 function TestGetterInAllContexts(getter, obj, expected, expectException) {
     86   TryGetter(value_context_for_getter, getter, obj, expected, expectException);
     87   TryGetter(test_context_for_getter, getter, obj, expected ? 111 : 222,
     88             expectException);
     89   TryGetter(effect_context_for_getter, getter, obj, 5678, expectException);
     90 }
     91 
     92 // -----------------------------------------------------------------------------
     93 // Test getter returning something 'true'ish in all contexts.
     94 
     95 function getter1() {
     96   assertSame(obj, this);
     97   accessorCallCount++;
     98   forceDeopt.deopt;
     99   return 1234;
    100 }
    101 
    102 function ConstrG1() { }
    103 obj = Object.defineProperty(new ConstrG1(), "getterProperty", { get: getter1 });
    104 TestGetterInAllContexts(getter1, obj, 1234, false);
    105 obj = Object.create(obj);
    106 TestGetterInAllContexts(getter1, obj, 1234, false);
    107 
    108 // -----------------------------------------------------------------------------
    109 // Test getter returning false in all contexts.
    110 
    111 function getter2() {
    112   assertSame(obj, this);
    113   accessorCallCount++;
    114   forceDeopt.deopt;
    115   return false;
    116 }
    117 
    118 function ConstrG2() { }
    119 obj = Object.defineProperty(new ConstrG2(), "getterProperty", { get: getter2 });
    120 TestGetterInAllContexts(getter2, obj, false, false);
    121 obj = Object.create(obj);
    122 TestGetterInAllContexts(getter2, obj, false, false);
    123 
    124 // -----------------------------------------------------------------------------
    125 // Test getter without a return in all contexts.
    126 
    127 function getter3() {
    128   assertSame(obj, this);
    129   accessorCallCount++;
    130   forceDeopt.deopt;
    131 }
    132 
    133 function ConstrG3() { }
    134 obj = Object.defineProperty(new ConstrG3(), "getterProperty", { get: getter3 });
    135 TestGetterInAllContexts(getter3, obj, undefined, false);
    136 obj = Object.create(obj);
    137 TestGetterInAllContexts(getter3, obj, undefined, false);
    138 
    139 // -----------------------------------------------------------------------------
    140 // Test getter with too many arguments without a return in all contexts.
    141 
    142 function getter4(a) {
    143   assertSame(obj, this);
    144   assertEquals(undefined, a);
    145   accessorCallCount++;
    146   forceDeopt.deopt;
    147 }
    148 
    149 function ConstrG4() { }
    150 obj = Object.defineProperty(new ConstrG4(), "getterProperty", { get: getter4 });
    151 TestGetterInAllContexts(getter4, obj, undefined, false);
    152 obj = Object.create(obj);
    153 TestGetterInAllContexts(getter4, obj, undefined, false);
    154 
    155 // -----------------------------------------------------------------------------
    156 // Test getter with too many arguments with a return in all contexts.
    157 
    158 function getter5(a) {
    159   assertSame(obj, this);
    160   assertEquals(undefined, a);
    161   accessorCallCount++;
    162   forceDeopt.deopt;
    163   return 9876;
    164 }
    165 
    166 function ConstrG5() { }
    167 obj = Object.defineProperty(new ConstrG5(), "getterProperty", { get: getter5 });
    168 TestGetterInAllContexts(getter5, obj, 9876, false);
    169 obj = Object.create(obj);
    170 TestGetterInAllContexts(getter5, obj, 9876, false);
    171 
    172 // -----------------------------------------------------------------------------
    173 // Test getter which throws from optimized code.
    174 
    175 function getter6() {
    176   assertSame(obj, this);
    177   accessorCallCount++;
    178   forceDeopt.deopt;
    179   if (accessorCallCount == 4) { 123 in null; }
    180   return 13579;
    181 }
    182 
    183 function ConstrG6() { }
    184 obj = Object.defineProperty(new ConstrG6(), "getterProperty", { get: getter6 });
    185 TestGetterInAllContexts(getter6, obj, 13579, true);
    186 obj = Object.create(obj);
    187 TestGetterInAllContexts(getter6, obj, 13579, true);
    188 
    189 // -----------------------------------------------------------------------------
    190 // Helpers for testing inlining of setters.
    191 
    192 function TestInlinedSetter(context, obj, value, expected) {
    193   forceDeopt = { deopt: 0 };
    194   accessorCallCount = 0;
    195   setterArgument = value;
    196 
    197   assertEquals(expected, context(obj, value));
    198   assertEquals(value, setterValue);
    199   assertEquals(1, accessorCallCount);
    200 
    201   assertEquals(expected, context(obj, value));
    202   assertEquals(value, setterValue);
    203   assertEquals(2, accessorCallCount);
    204 
    205   %OptimizeFunctionOnNextCall(context);
    206   assertEquals(expected, context(obj, value));
    207   assertEquals(value, setterValue);
    208   assertEquals(3, accessorCallCount);
    209 
    210   forceDeopt = { /* empty*/ };
    211   assertEquals(expected, context(obj, value));
    212   assertEquals(value, setterValue);
    213   assertEquals(4, accessorCallCount);
    214 }
    215 
    216 function value_context_for_setter(obj, value) {
    217   return obj.setterProperty = value;
    218 }
    219 
    220 function test_context_for_setter(obj, value) {
    221   if (obj.setterProperty = value) {
    222     return 333;
    223   } else {
    224     return 444;
    225   }
    226 }
    227 
    228 function effect_context_for_setter(obj, value) {
    229   obj.setterProperty = value;
    230   return 666;
    231 }
    232 
    233 function TrySetter(context, setter, obj, expectException, value, expected) {
    234   try {
    235     TestInlinedSetter(context, obj, value, expected);
    236     assertFalse(expectException);
    237   } catch (exception) {
    238     assertTrue(expectException);
    239     assertEquals(7, exception.stack.split('\n').length);
    240   }
    241   %DeoptimizeFunction(context);
    242   %ClearFunctionTypeFeedback(context);
    243   %ClearFunctionTypeFeedback(setter);
    244 }
    245 
    246 function TestSetterInAllContexts(setter, obj, expectException) {
    247   TrySetter(value_context_for_setter, setter, obj, expectException, 111, 111);
    248   TrySetter(test_context_for_setter, setter, obj, expectException, true, 333);
    249   TrySetter(test_context_for_setter, setter, obj, expectException, false, 444);
    250   TrySetter(effect_context_for_setter, setter, obj, expectException, 555, 666);
    251 }
    252 
    253 // -----------------------------------------------------------------------------
    254 // Test setter without a return in all contexts.
    255 
    256 function setter1(value) {
    257   assertSame(obj, this);
    258   accessorCallCount++;
    259   forceDeopt.deopt;
    260   setterValue = value;
    261 }
    262 
    263 function ConstrS1() { }
    264 obj = Object.defineProperty(new ConstrS1(), "setterProperty", { set: setter1 });
    265 TestSetterInAllContexts(setter1, obj, false);
    266 obj = Object.create(obj);
    267 TestSetterInAllContexts(setter1, obj, false);
    268 
    269 // -----------------------------------------------------------------------------
    270 // Test setter returning something different than the RHS in all contexts.
    271 
    272 function setter2(value) {
    273   assertSame(obj, this);
    274   accessorCallCount++;
    275   forceDeopt.deopt;
    276   setterValue = value;
    277   return 1000000;
    278 }
    279 
    280 function ConstrS2() { }
    281 obj = Object.defineProperty(new ConstrS2(), "setterProperty", { set: setter2 });
    282 TestSetterInAllContexts(setter2, obj, false);
    283 obj = Object.create(obj);
    284 TestSetterInAllContexts(setter2, obj, false);
    285 
    286 // -----------------------------------------------------------------------------
    287 // Test setter with too few arguments without a return in all contexts.
    288 
    289 function setter3() {
    290   assertSame(obj, this);
    291   accessorCallCount++;
    292   forceDeopt.deopt;
    293   setterValue = setterArgument;
    294 }
    295 
    296 function ConstrS3() { }
    297 obj = Object.defineProperty(new ConstrS3(), "setterProperty", { set: setter3 });
    298 TestSetterInAllContexts(setter3, obj, false);
    299 obj = Object.create(obj);
    300 TestSetterInAllContexts(setter3, obj, false);
    301 
    302 // -----------------------------------------------------------------------------
    303 // Test setter with too few arguments with a return in all contexts.
    304 
    305 function setter4() {
    306   assertSame(obj, this);
    307   accessorCallCount++;
    308   forceDeopt.deopt;
    309   setterValue = setterArgument;
    310   return 2000000;
    311 }
    312 
    313 function ConstrS4() { }
    314 obj = Object.defineProperty(new ConstrS4(), "setterProperty", { set: setter4 });
    315 TestSetterInAllContexts(setter4, obj, false);
    316 obj = Object.create(obj);
    317 TestSetterInAllContexts(setter4, obj, false);
    318 
    319 // -----------------------------------------------------------------------------
    320 // Test setter with too many arguments without a return in all contexts.
    321 
    322 function setter5(value, foo) {
    323   assertSame(obj, this);
    324   assertEquals(undefined, foo);
    325   accessorCallCount++;
    326   forceDeopt.deopt;
    327   setterValue = value;
    328 }
    329 
    330 function ConstrS5() { }
    331 obj = Object.defineProperty(new ConstrS5(), "setterProperty", { set: setter5 });
    332 TestSetterInAllContexts(setter5, obj, false);
    333 obj = Object.create(obj);
    334 TestSetterInAllContexts(setter5, obj, false);
    335 
    336 // -----------------------------------------------------------------------------
    337 // Test setter with too many arguments with a return in all contexts.
    338 
    339 function setter6(value, foo) {
    340   assertSame(obj, this);
    341   assertEquals(undefined, foo);
    342   accessorCallCount++;
    343   forceDeopt.deopt;
    344   setterValue = value;
    345   return 3000000;
    346 }
    347 
    348 function ConstrS6() { }
    349 obj = Object.defineProperty(new ConstrS6(), "setterProperty", { set: setter6 });
    350 TestSetterInAllContexts(setter6, obj, false);
    351 obj = Object.create(obj);
    352 TestSetterInAllContexts(setter6, obj, false);
    353 
    354 // -----------------------------------------------------------------------------
    355 // Test setter which throws from optimized code.
    356 
    357 function setter7(value) {
    358   accessorCallCount++;
    359   forceDeopt.deopt;
    360   if (accessorCallCount == 4) { 123 in null; }
    361   setterValue = value;
    362 }
    363 
    364 function ConstrS7() { }
    365 obj = Object.defineProperty(new ConstrS7(), "setterProperty", { set: setter7 });
    366 TestSetterInAllContexts(setter7, obj, true);
    367 obj = Object.create(obj);
    368 TestSetterInAllContexts(setter7, obj, true);
    369