Home | History | Annotate | Download | only in cctest
      1 // Copyright 2015 the V8 project authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include <stdlib.h>
      6 
      7 #include "src/v8.h"
      8 
      9 #include "src/ast/ast.h"
     10 #include "src/ast/ast-expression-visitor.h"
     11 #include "src/ast/scopes.h"
     12 #include "src/parsing/parser.h"
     13 #include "src/parsing/rewriter.h"
     14 #include "test/cctest/cctest.h"
     15 #include "test/cctest/expression-type-collector.h"
     16 #include "test/cctest/expression-type-collector-macros.h"
     17 
     18 using namespace v8::internal;
     19 
     20 namespace {
     21 
     22 static void CollectTypes(HandleAndZoneScope* handles, const char* source,
     23                          ZoneVector<ExpressionTypeEntry>* dst) {
     24   i::Isolate* isolate = CcTest::i_isolate();
     25   i::Factory* factory = isolate->factory();
     26 
     27   i::Handle<i::String> source_code =
     28       factory->NewStringFromUtf8(i::CStrVector(source)).ToHandleChecked();
     29 
     30   i::Handle<i::Script> script = factory->NewScript(source_code);
     31 
     32   i::ParseInfo info(handles->main_zone(), script);
     33   i::Parser parser(&info);
     34   parser.set_allow_harmony_sloppy(true);
     35   info.set_global();
     36   info.set_lazy(false);
     37   info.set_allow_lazy_parsing(false);
     38   info.set_toplevel(true);
     39 
     40   CHECK(i::Compiler::ParseAndAnalyze(&info));
     41 
     42   ExpressionTypeCollector(
     43       isolate,
     44       info.scope()->declarations()->at(0)->AsFunctionDeclaration()->fun(), dst)
     45       .Run();
     46 }
     47 
     48 }  // namespace
     49 
     50 
     51 TEST(VisitExpressions) {
     52   v8::V8::Initialize();
     53   HandleAndZoneScope handles;
     54   ZoneVector<ExpressionTypeEntry> types(handles.main_zone());
     55   const char test_function[] =
     56       "function GeometricMean(stdlib, foreign, buffer) {\n"
     57       "  \"use asm\";\n"
     58       "\n"
     59       "  var exp = stdlib.Math.exp;\n"
     60       "  var log = stdlib.Math.log;\n"
     61       "  var values = new stdlib.Float64Array(buffer);\n"
     62       "\n"
     63       "  function logSum(start, end) {\n"
     64       "    start = start|0;\n"
     65       "    end = end|0;\n"
     66       "\n"
     67       "    var sum = 0.0, p = 0, q = 0;\n"
     68       "\n"
     69       "    // asm.js forces byte addressing of the heap by requiring shifting "
     70       "by 3\n"
     71       "    for (p = start << 3, q = end << 3; (p|0) < (q|0); p = (p + 8)|0) {\n"
     72       "      sum = sum + +log(values[p>>3]);\n"
     73       "    }\n"
     74       "\n"
     75       "    return +sum;\n"
     76       "  }\n"
     77       "\n"
     78       " function geometricMean(start, end) {\n"
     79       "    start = start|0;\n"
     80       "    end = end|0;\n"
     81       "\n"
     82       "    return +exp(+logSum(start, end) / +((end - start)|0));\n"
     83       "  }\n"
     84       "\n"
     85       "  return { geometricMean: geometricMean };\n"
     86       "}\n";
     87 
     88   CollectTypes(&handles, test_function, &types);
     89   CHECK_TYPES_BEGIN {
     90     // function logSum
     91     CHECK_EXPR(FunctionLiteral, Bounds::Unbounded()) {
     92       CHECK_EXPR(FunctionLiteral, Bounds::Unbounded()) {
     93         CHECK_EXPR(Assignment, Bounds::Unbounded()) {
     94           CHECK_VAR(start, Bounds::Unbounded());
     95           CHECK_EXPR(BinaryOperation, Bounds::Unbounded()) {
     96             CHECK_VAR(start, Bounds::Unbounded());
     97             CHECK_EXPR(Literal, Bounds::Unbounded());
     98           }
     99         }
    100         CHECK_EXPR(Assignment, Bounds::Unbounded()) {
    101           CHECK_VAR(end, Bounds::Unbounded());
    102           CHECK_EXPR(BinaryOperation, Bounds::Unbounded()) {
    103             CHECK_VAR(end, Bounds::Unbounded());
    104             CHECK_EXPR(Literal, Bounds::Unbounded());
    105           }
    106         }
    107         CHECK_EXPR(Assignment, Bounds::Unbounded()) {
    108           CHECK_VAR(sum, Bounds::Unbounded());
    109           CHECK_EXPR(Literal, Bounds::Unbounded());
    110         }
    111         CHECK_EXPR(Assignment, Bounds::Unbounded()) {
    112           CHECK_VAR(p, Bounds::Unbounded());
    113           CHECK_EXPR(Literal, Bounds::Unbounded());
    114         }
    115         CHECK_EXPR(Assignment, Bounds::Unbounded()) {
    116           CHECK_VAR(q, Bounds::Unbounded());
    117           CHECK_EXPR(Literal, Bounds::Unbounded());
    118         }
    119         // for (p = start << 3, q = end << 3;
    120         CHECK_EXPR(BinaryOperation, Bounds::Unbounded()) {
    121           CHECK_EXPR(Assignment, Bounds::Unbounded()) {
    122             CHECK_VAR(p, Bounds::Unbounded());
    123             CHECK_EXPR(BinaryOperation, Bounds::Unbounded()) {
    124               CHECK_VAR(start, Bounds::Unbounded());
    125               CHECK_EXPR(Literal, Bounds::Unbounded());
    126             }
    127           }
    128           CHECK_EXPR(Assignment, Bounds::Unbounded()) {
    129             CHECK_VAR(q, Bounds::Unbounded());
    130             CHECK_EXPR(BinaryOperation, Bounds::Unbounded()) {
    131               CHECK_VAR(end, Bounds::Unbounded());
    132               CHECK_EXPR(Literal, Bounds::Unbounded());
    133             }
    134           }
    135         }
    136         // (p|0) < (q|0);
    137         CHECK_EXPR(CompareOperation, Bounds::Unbounded()) {
    138           CHECK_EXPR(BinaryOperation, Bounds::Unbounded()) {
    139             CHECK_VAR(p, Bounds::Unbounded());
    140             CHECK_EXPR(Literal, Bounds::Unbounded());
    141           }
    142           CHECK_EXPR(BinaryOperation, Bounds::Unbounded()) {
    143             CHECK_VAR(q, Bounds::Unbounded());
    144             CHECK_EXPR(Literal, Bounds::Unbounded());
    145           }
    146         }
    147         // p = (p + 8)|0) {\n"
    148         CHECK_EXPR(Assignment, Bounds::Unbounded()) {
    149           CHECK_VAR(p, Bounds::Unbounded());
    150           CHECK_EXPR(BinaryOperation, Bounds::Unbounded()) {
    151             CHECK_EXPR(BinaryOperation, Bounds::Unbounded()) {
    152               CHECK_VAR(p, Bounds::Unbounded());
    153               CHECK_EXPR(Literal, Bounds::Unbounded());
    154             }
    155             CHECK_EXPR(Literal, Bounds::Unbounded());
    156           }
    157         }
    158         // sum = sum + +log(values[p>>3]);
    159         CHECK_EXPR(Assignment, Bounds::Unbounded()) {
    160           CHECK_VAR(sum, Bounds::Unbounded());
    161           CHECK_EXPR(BinaryOperation, Bounds::Unbounded()) {
    162             CHECK_VAR(sum, Bounds::Unbounded());
    163             CHECK_EXPR(BinaryOperation, Bounds::Unbounded()) {
    164               CHECK_EXPR(Call, Bounds::Unbounded()) {
    165                 CHECK_VAR(log, Bounds::Unbounded());
    166                 CHECK_EXPR(Property, Bounds::Unbounded()) {
    167                   CHECK_VAR(values, Bounds::Unbounded());
    168                   CHECK_EXPR(BinaryOperation, Bounds::Unbounded()) {
    169                     CHECK_VAR(p, Bounds::Unbounded());
    170                     CHECK_EXPR(Literal, Bounds::Unbounded());
    171                   }
    172                 }
    173               }
    174               CHECK_EXPR(Literal, Bounds::Unbounded());
    175             }
    176           }
    177         }
    178         // return +sum;
    179         CHECK_EXPR(BinaryOperation, Bounds::Unbounded()) {
    180           CHECK_VAR(sum, Bounds::Unbounded());
    181           CHECK_EXPR(Literal, Bounds::Unbounded());
    182         }
    183       }
    184       // function geometricMean
    185       CHECK_EXPR(FunctionLiteral, Bounds::Unbounded()) {
    186         CHECK_EXPR(Assignment, Bounds::Unbounded()) {
    187           CHECK_VAR(start, Bounds::Unbounded());
    188           CHECK_EXPR(BinaryOperation, Bounds::Unbounded()) {
    189             CHECK_VAR(start, Bounds::Unbounded());
    190             CHECK_EXPR(Literal, Bounds::Unbounded());
    191           }
    192         }
    193         CHECK_EXPR(Assignment, Bounds::Unbounded()) {
    194           CHECK_VAR(end, Bounds::Unbounded());
    195           CHECK_EXPR(BinaryOperation, Bounds::Unbounded()) {
    196             CHECK_VAR(end, Bounds::Unbounded());
    197             CHECK_EXPR(Literal, Bounds::Unbounded());
    198           }
    199         }
    200         // return +exp(+logSum(start, end) / +((end - start)|0));
    201         CHECK_EXPR(BinaryOperation, Bounds::Unbounded()) {
    202           CHECK_EXPR(Call, Bounds::Unbounded()) {
    203             CHECK_VAR(exp, Bounds::Unbounded());
    204             CHECK_EXPR(BinaryOperation, Bounds::Unbounded()) {
    205               CHECK_EXPR(BinaryOperation, Bounds::Unbounded()) {
    206                 CHECK_EXPR(Call, Bounds::Unbounded()) {
    207                   CHECK_VAR(logSum, Bounds::Unbounded());
    208                   CHECK_VAR(start, Bounds::Unbounded());
    209                   CHECK_VAR(end, Bounds::Unbounded());
    210                 }
    211                 CHECK_EXPR(Literal, Bounds::Unbounded());
    212               }
    213               CHECK_EXPR(BinaryOperation, Bounds::Unbounded()) {
    214                 CHECK_EXPR(BinaryOperation, Bounds::Unbounded()) {
    215                   CHECK_EXPR(BinaryOperation, Bounds::Unbounded()) {
    216                     CHECK_VAR(end, Bounds::Unbounded());
    217                     CHECK_VAR(start, Bounds::Unbounded());
    218                   }
    219                   CHECK_EXPR(Literal, Bounds::Unbounded());
    220                 }
    221                 CHECK_EXPR(Literal, Bounds::Unbounded());
    222               }
    223             }
    224           }
    225           CHECK_EXPR(Literal, Bounds::Unbounded());
    226         }
    227       }
    228       // "use asm";
    229       CHECK_EXPR(Literal, Bounds::Unbounded());
    230       // var exp = stdlib.Math.exp;
    231       CHECK_EXPR(Assignment, Bounds::Unbounded()) {
    232         CHECK_VAR(exp, Bounds::Unbounded());
    233         CHECK_EXPR(Property, Bounds::Unbounded()) {
    234           CHECK_EXPR(Property, Bounds::Unbounded()) {
    235             CHECK_VAR(stdlib, Bounds::Unbounded());
    236             CHECK_EXPR(Literal, Bounds::Unbounded());
    237           }
    238           CHECK_EXPR(Literal, Bounds::Unbounded());
    239         }
    240       }
    241       // var log = stdlib.Math.log;
    242       CHECK_EXPR(Assignment, Bounds::Unbounded()) {
    243         CHECK_VAR(log, Bounds::Unbounded());
    244         CHECK_EXPR(Property, Bounds::Unbounded()) {
    245           CHECK_EXPR(Property, Bounds::Unbounded()) {
    246             CHECK_VAR(stdlib, Bounds::Unbounded());
    247             CHECK_EXPR(Literal, Bounds::Unbounded());
    248           }
    249           CHECK_EXPR(Literal, Bounds::Unbounded());
    250         }
    251       }
    252       // var values = new stdlib.Float64Array(buffer);
    253       CHECK_EXPR(Assignment, Bounds::Unbounded()) {
    254         CHECK_VAR(values, Bounds::Unbounded());
    255         CHECK_EXPR(CallNew, Bounds::Unbounded()) {
    256           CHECK_EXPR(Property, Bounds::Unbounded()) {
    257             CHECK_VAR(stdlib, Bounds::Unbounded());
    258             CHECK_EXPR(Literal, Bounds::Unbounded());
    259           }
    260           CHECK_VAR(buffer, Bounds::Unbounded());
    261         }
    262       }
    263       // return { geometricMean: geometricMean };
    264       CHECK_EXPR(ObjectLiteral, Bounds::Unbounded()) {
    265         CHECK_VAR(geometricMean, Bounds::Unbounded());
    266       }
    267     }
    268   }
    269   CHECK_TYPES_END
    270 }
    271 
    272 
    273 TEST(VisitConditional) {
    274   v8::V8::Initialize();
    275   HandleAndZoneScope handles;
    276   ZoneVector<ExpressionTypeEntry> types(handles.main_zone());
    277   // Check that traversing the ternary operator works.
    278   const char test_function[] =
    279       "function foo() {\n"
    280       "  var a, b, c;\n"
    281       "  var x = a ? b : c;\n"
    282       "}\n";
    283   CollectTypes(&handles, test_function, &types);
    284   CHECK_TYPES_BEGIN {
    285     CHECK_EXPR(FunctionLiteral, Bounds::Unbounded()) {
    286       CHECK_EXPR(Assignment, Bounds::Unbounded()) {
    287         CHECK_VAR(x, Bounds::Unbounded());
    288         CHECK_EXPR(Conditional, Bounds::Unbounded()) {
    289           CHECK_VAR(a, Bounds::Unbounded());
    290           CHECK_VAR(b, Bounds::Unbounded());
    291           CHECK_VAR(c, Bounds::Unbounded());
    292         }
    293       }
    294     }
    295   }
    296   CHECK_TYPES_END
    297 }
    298 
    299 
    300 TEST(VisitEmptyForStatment) {
    301   v8::V8::Initialize();
    302   HandleAndZoneScope handles;
    303   ZoneVector<ExpressionTypeEntry> types(handles.main_zone());
    304   // Check that traversing an empty for statement works.
    305   const char test_function[] =
    306       "function foo() {\n"
    307       "  for (;;) {}\n"
    308       "}\n";
    309   CollectTypes(&handles, test_function, &types);
    310   CHECK_TYPES_BEGIN {
    311     CHECK_EXPR(FunctionLiteral, Bounds::Unbounded()) {}
    312   }
    313   CHECK_TYPES_END
    314 }
    315 
    316 
    317 TEST(VisitSwitchStatment) {
    318   v8::V8::Initialize();
    319   HandleAndZoneScope handles;
    320   ZoneVector<ExpressionTypeEntry> types(handles.main_zone());
    321   // Check that traversing a switch with a default works.
    322   const char test_function[] =
    323       "function foo() {\n"
    324       "  switch (0) { case 1: break; default: break; }\n"
    325       "}\n";
    326   CollectTypes(&handles, test_function, &types);
    327   CHECK_TYPES_BEGIN {
    328     CHECK_EXPR(FunctionLiteral, Bounds::Unbounded()) {
    329       CHECK_EXPR(Assignment, Bounds::Unbounded()) {
    330         CHECK_VAR(.switch_tag, Bounds::Unbounded());
    331         CHECK_EXPR(Literal, Bounds::Unbounded());
    332       }
    333       CHECK_EXPR(Literal, Bounds::Unbounded());
    334       CHECK_VAR(.switch_tag, Bounds::Unbounded());
    335       CHECK_EXPR(Literal, Bounds::Unbounded());
    336     }
    337   }
    338   CHECK_TYPES_END
    339 }
    340 
    341 
    342 TEST(VisitThrow) {
    343   v8::V8::Initialize();
    344   HandleAndZoneScope handles;
    345   ZoneVector<ExpressionTypeEntry> types(handles.main_zone());
    346   // Check that traversing an empty for statement works.
    347   const char test_function[] =
    348       "function foo() {\n"
    349       "  throw 123;\n"
    350       "}\n";
    351   CollectTypes(&handles, test_function, &types);
    352   CHECK_TYPES_BEGIN {
    353     CHECK_EXPR(FunctionLiteral, Bounds::Unbounded()) {
    354       CHECK_EXPR(Throw, Bounds::Unbounded()) {
    355         CHECK_EXPR(Literal, Bounds::Unbounded());
    356       }
    357     }
    358   }
    359   CHECK_TYPES_END
    360 }
    361 
    362 
    363 TEST(VisitYield) {
    364   v8::V8::Initialize();
    365   HandleAndZoneScope handles;
    366   ZoneVector<ExpressionTypeEntry> types(handles.main_zone());
    367   // Check that traversing an empty for statement works.
    368   const char test_function[] =
    369       "function* foo() {\n"
    370       "  yield 123;\n"
    371       "}\n";
    372   CollectTypes(&handles, test_function, &types);
    373   CHECK_TYPES_BEGIN {
    374     CHECK_EXPR(FunctionLiteral, Bounds::Unbounded()) {
    375       // Generator function yields generator on entry.
    376       CHECK_EXPR(Yield, Bounds::Unbounded()) {
    377         CHECK_VAR(.generator_object, Bounds::Unbounded());
    378         CHECK_EXPR(Assignment, Bounds::Unbounded()) {
    379           CHECK_VAR(.generator_object, Bounds::Unbounded());
    380           CHECK_EXPR(CallRuntime, Bounds::Unbounded());
    381         }
    382       }
    383       // Then yields undefined.
    384       CHECK_EXPR(Yield, Bounds::Unbounded()) {
    385         CHECK_VAR(.generator_object, Bounds::Unbounded());
    386         CHECK_EXPR(Literal, Bounds::Unbounded());
    387       }
    388       // Then yields 123.
    389       CHECK_EXPR(Yield, Bounds::Unbounded()) {
    390         CHECK_VAR(.generator_object, Bounds::Unbounded());
    391         CHECK_EXPR(Literal, Bounds::Unbounded());
    392       }
    393     }
    394   }
    395   CHECK_TYPES_END
    396 }
    397 
    398 
    399 TEST(VisitSkipping) {
    400   v8::V8::Initialize();
    401   HandleAndZoneScope handles;
    402   ZoneVector<ExpressionTypeEntry> types(handles.main_zone());
    403   // Check that traversing an empty for statement works.
    404   const char test_function[] =
    405       "function foo(x) {\n"
    406       "  return (x + x) + 1;\n"
    407       "}\n";
    408   CollectTypes(&handles, test_function, &types);
    409   CHECK_TYPES_BEGIN {
    410     CHECK_EXPR(FunctionLiteral, Bounds::Unbounded()) {
    411       CHECK_EXPR(BinaryOperation, Bounds::Unbounded()) {
    412         // Skip x + x
    413         CHECK_SKIP();
    414         CHECK_EXPR(Literal, Bounds::Unbounded());
    415       }
    416     }
    417   }
    418   CHECK_TYPES_END
    419 }
    420