Home | History | Annotate | Download | only in compiler
      1 // Copyright 2014 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 #ifndef V8_CCTEST_COMPILER_FUNCTION_TESTER_H_
      6 #define V8_CCTEST_COMPILER_FUNCTION_TESTER_H_
      7 
      8 #include "src/ast/ast-numbering.h"
      9 #include "src/ast/scopes.h"
     10 #include "src/compiler.h"
     11 #include "src/compiler/linkage.h"
     12 #include "src/compiler/pipeline.h"
     13 #include "src/execution.h"
     14 #include "src/full-codegen/full-codegen.h"
     15 #include "src/handles.h"
     16 #include "src/objects-inl.h"
     17 #include "src/parsing/parser.h"
     18 #include "src/parsing/rewriter.h"
     19 #include "test/cctest/cctest.h"
     20 
     21 namespace v8 {
     22 namespace internal {
     23 namespace compiler {
     24 
     25 class FunctionTester : public InitializedHandleScope {
     26  public:
     27   explicit FunctionTester(const char* source, uint32_t flags = 0)
     28       : isolate(main_isolate()),
     29         function((FLAG_allow_natives_syntax = true, NewFunction(source))),
     30         flags_(flags) {
     31     Compile(function);
     32     const uint32_t supported_flags =
     33         CompilationInfo::kFunctionContextSpecializing |
     34         CompilationInfo::kInliningEnabled;
     35     CHECK_EQ(0u, flags_ & ~supported_flags);
     36   }
     37 
     38   FunctionTester(Graph* graph, int param_count)
     39       : isolate(main_isolate()),
     40         function(NewFunction(BuildFunction(param_count).c_str())),
     41         flags_(0) {
     42     CompileGraph(graph);
     43   }
     44 
     45   FunctionTester(Handle<Code> code, int param_count)
     46       : isolate(main_isolate()),
     47         function((FLAG_allow_natives_syntax = true,
     48                   NewFunction(BuildFunction(param_count).c_str()))),
     49         flags_(0) {
     50     Compile(function);
     51     function->ReplaceCode(*code);
     52   }
     53 
     54   FunctionTester(const CallInterfaceDescriptor& descriptor, Handle<Code> code)
     55       : FunctionTester(code, descriptor.GetParameterCount()) {}
     56 
     57   Isolate* isolate;
     58   Handle<JSFunction> function;
     59 
     60   MaybeHandle<Object> Call() {
     61     return Execution::Call(isolate, function, undefined(), 0, nullptr);
     62   }
     63 
     64   MaybeHandle<Object> Call(Handle<Object> a) {
     65     Handle<Object> args[] = {a};
     66     return Execution::Call(isolate, function, undefined(), 1, args);
     67   }
     68 
     69   MaybeHandle<Object> Call(Handle<Object> a, Handle<Object> b) {
     70     Handle<Object> args[] = {a, b};
     71     return Execution::Call(isolate, function, undefined(), 2, args);
     72   }
     73 
     74   MaybeHandle<Object> Call(Handle<Object> a, Handle<Object> b,
     75                            Handle<Object> c) {
     76     Handle<Object> args[] = {a, b, c};
     77     return Execution::Call(isolate, function, undefined(), 3, args);
     78   }
     79 
     80   MaybeHandle<Object> Call(Handle<Object> a, Handle<Object> b, Handle<Object> c,
     81                            Handle<Object> d) {
     82     Handle<Object> args[] = {a, b, c, d};
     83     return Execution::Call(isolate, function, undefined(), 4, args);
     84   }
     85 
     86   void CheckThrows(Handle<Object> a, Handle<Object> b) {
     87     TryCatch try_catch(reinterpret_cast<v8::Isolate*>(isolate));
     88     MaybeHandle<Object> no_result = Call(a, b);
     89     CHECK(isolate->has_pending_exception());
     90     CHECK(try_catch.HasCaught());
     91     CHECK(no_result.is_null());
     92     isolate->OptionalRescheduleException(true);
     93   }
     94 
     95   v8::Local<v8::Message> CheckThrowsReturnMessage(Handle<Object> a,
     96                                                   Handle<Object> b) {
     97     TryCatch try_catch(reinterpret_cast<v8::Isolate*>(isolate));
     98     MaybeHandle<Object> no_result = Call(a, b);
     99     CHECK(isolate->has_pending_exception());
    100     CHECK(try_catch.HasCaught());
    101     CHECK(no_result.is_null());
    102     isolate->OptionalRescheduleException(true);
    103     CHECK(!try_catch.Message().IsEmpty());
    104     return try_catch.Message();
    105   }
    106 
    107   void CheckCall(Handle<Object> expected, Handle<Object> a, Handle<Object> b,
    108                  Handle<Object> c, Handle<Object> d) {
    109     Handle<Object> result = Call(a, b, c, d).ToHandleChecked();
    110     CHECK(expected->SameValue(*result));
    111   }
    112 
    113   void CheckCall(Handle<Object> expected, Handle<Object> a, Handle<Object> b,
    114                  Handle<Object> c) {
    115     return CheckCall(expected, a, b, c, undefined());
    116   }
    117 
    118   void CheckCall(Handle<Object> expected, Handle<Object> a, Handle<Object> b) {
    119     return CheckCall(expected, a, b, undefined());
    120   }
    121 
    122   void CheckCall(Handle<Object> expected, Handle<Object> a) {
    123     CheckCall(expected, a, undefined());
    124   }
    125 
    126   void CheckCall(Handle<Object> expected) { CheckCall(expected, undefined()); }
    127 
    128   void CheckCall(double expected, double a, double b) {
    129     CheckCall(Val(expected), Val(a), Val(b));
    130   }
    131 
    132   void CheckTrue(Handle<Object> a) { CheckCall(true_value(), a); }
    133 
    134   void CheckTrue(Handle<Object> a, Handle<Object> b) {
    135     CheckCall(true_value(), a, b);
    136   }
    137 
    138   void CheckTrue(Handle<Object> a, Handle<Object> b, Handle<Object> c) {
    139     CheckCall(true_value(), a, b, c);
    140   }
    141 
    142   void CheckTrue(Handle<Object> a, Handle<Object> b, Handle<Object> c,
    143                  Handle<Object> d) {
    144     CheckCall(true_value(), a, b, c, d);
    145   }
    146 
    147   void CheckTrue(double a, double b) {
    148     CheckCall(true_value(), Val(a), Val(b));
    149   }
    150 
    151   void CheckFalse(Handle<Object> a) { CheckCall(false_value(), a); }
    152 
    153   void CheckFalse(Handle<Object> a, Handle<Object> b) {
    154     CheckCall(false_value(), a, b);
    155   }
    156 
    157   void CheckFalse(double a, double b) {
    158     CheckCall(false_value(), Val(a), Val(b));
    159   }
    160 
    161   Handle<JSFunction> NewFunction(const char* source) {
    162     return Handle<JSFunction>::cast(v8::Utils::OpenHandle(
    163         *v8::Local<v8::Function>::Cast(CompileRun(source))));
    164   }
    165 
    166   Handle<JSObject> NewObject(const char* source) {
    167     return Handle<JSObject>::cast(v8::Utils::OpenHandle(
    168         *v8::Local<v8::Object>::Cast(CompileRun(source))));
    169   }
    170 
    171   Handle<String> Val(const char* string) {
    172     return isolate->factory()->InternalizeUtf8String(string);
    173   }
    174 
    175   Handle<Object> Val(double value) {
    176     return isolate->factory()->NewNumber(value);
    177   }
    178 
    179   Handle<Object> infinity() { return isolate->factory()->infinity_value(); }
    180 
    181   Handle<Object> minus_infinity() { return Val(-V8_INFINITY); }
    182 
    183   Handle<Object> nan() { return isolate->factory()->nan_value(); }
    184 
    185   Handle<Object> undefined() { return isolate->factory()->undefined_value(); }
    186 
    187   Handle<Object> null() { return isolate->factory()->null_value(); }
    188 
    189   Handle<Object> true_value() { return isolate->factory()->true_value(); }
    190 
    191   Handle<Object> false_value() { return isolate->factory()->false_value(); }
    192 
    193   static Handle<JSFunction> ForMachineGraph(Graph* graph, int param_count) {
    194     JSFunction* p = NULL;
    195     {  // because of the implicit handle scope of FunctionTester.
    196       FunctionTester f(graph, param_count);
    197       p = *f.function;
    198     }
    199     return Handle<JSFunction>(p);  // allocated in outer handle scope.
    200   }
    201 
    202  private:
    203   uint32_t flags_;
    204 
    205   Handle<JSFunction> Compile(Handle<JSFunction> function) {
    206     Zone zone(function->GetIsolate()->allocator());
    207     ParseInfo parse_info(&zone, function);
    208     CompilationInfo info(&parse_info, function);
    209     info.MarkAsDeoptimizationEnabled();
    210 
    211     CHECK(Parser::ParseStatic(info.parse_info()));
    212     info.SetOptimizing();
    213     if (flags_ & CompilationInfo::kFunctionContextSpecializing) {
    214       info.MarkAsFunctionContextSpecializing();
    215     }
    216     if (flags_ & CompilationInfo::kInliningEnabled) {
    217       info.MarkAsInliningEnabled();
    218     }
    219     if (FLAG_turbo_from_bytecode && function->shared()->HasBytecodeArray()) {
    220       info.MarkAsOptimizeFromBytecode();
    221     } else {
    222       CHECK(Compiler::Analyze(info.parse_info()));
    223       CHECK(Compiler::EnsureDeoptimizationSupport(&info));
    224     }
    225     JSFunction::EnsureLiterals(function);
    226 
    227     Handle<Code> code = Pipeline::GenerateCodeForTesting(&info);
    228     CHECK(!code.is_null());
    229     info.dependencies()->Commit(code);
    230     info.context()->native_context()->AddOptimizedCode(*code);
    231     function->ReplaceCode(*code);
    232     return function;
    233   }
    234 
    235   std::string BuildFunction(int param_count) {
    236     std::string function_string = "(function(";
    237     if (param_count > 0) {
    238       function_string += 'a';
    239       for (int i = 1; i < param_count; i++) {
    240         function_string += ',';
    241         function_string += static_cast<char>('a' + i);
    242       }
    243     }
    244     function_string += "){})";
    245     return function_string;
    246   }
    247 
    248   // Compile the given machine graph instead of the source of the function
    249   // and replace the JSFunction's code with the result.
    250   Handle<JSFunction> CompileGraph(Graph* graph) {
    251     Zone zone(function->GetIsolate()->allocator());
    252     ParseInfo parse_info(&zone, function);
    253     CompilationInfo info(&parse_info, function);
    254 
    255     CHECK(Parser::ParseStatic(info.parse_info()));
    256     info.SetOptimizing();
    257 
    258     Handle<Code> code = Pipeline::GenerateCodeForTesting(&info, graph);
    259     CHECK(!code.is_null());
    260     function->ReplaceCode(*code);
    261     return function;
    262   }
    263 };
    264 }  // namespace compiler
    265 }  // namespace internal
    266 }  // namespace v8
    267 
    268 #endif  // V8_CCTEST_COMPILER_FUNCTION_TESTER_H_
    269