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 | CompilationInfo::kTypingEnabled;
     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(const CallInterfaceDescriptor& descriptor, Handle<Code> code)
     46       : isolate(main_isolate()),
     47         function(
     48             (FLAG_allow_natives_syntax = true,
     49              NewFunction(BuildFunctionFromDescriptor(descriptor).c_str()))),
     50         flags_(0) {
     51     Compile(function);
     52     function->ReplaceCode(*code);
     53   }
     54 
     55   Isolate* isolate;
     56   Handle<JSFunction> function;
     57 
     58   MaybeHandle<Object> Call() {
     59     return Execution::Call(isolate, function, undefined(), 0, nullptr);
     60   }
     61 
     62   MaybeHandle<Object> Call(Handle<Object> a, Handle<Object> b) {
     63     Handle<Object> args[] = {a, b};
     64     return Execution::Call(isolate, function, undefined(), 2, args);
     65   }
     66 
     67   MaybeHandle<Object> Call(Handle<Object> a, Handle<Object> b, Handle<Object> c,
     68                            Handle<Object> d) {
     69     Handle<Object> args[] = {a, b, c, d};
     70     return Execution::Call(isolate, function, undefined(), 4, args);
     71   }
     72 
     73   void CheckThrows(Handle<Object> a, Handle<Object> b) {
     74     TryCatch try_catch(reinterpret_cast<v8::Isolate*>(isolate));
     75     MaybeHandle<Object> no_result = Call(a, b);
     76     CHECK(isolate->has_pending_exception());
     77     CHECK(try_catch.HasCaught());
     78     CHECK(no_result.is_null());
     79     isolate->OptionalRescheduleException(true);
     80   }
     81 
     82   v8::Local<v8::Message> CheckThrowsReturnMessage(Handle<Object> a,
     83                                                   Handle<Object> b) {
     84     TryCatch try_catch(reinterpret_cast<v8::Isolate*>(isolate));
     85     MaybeHandle<Object> no_result = Call(a, b);
     86     CHECK(isolate->has_pending_exception());
     87     CHECK(try_catch.HasCaught());
     88     CHECK(no_result.is_null());
     89     isolate->OptionalRescheduleException(true);
     90     CHECK(!try_catch.Message().IsEmpty());
     91     return try_catch.Message();
     92   }
     93 
     94   void CheckCall(Handle<Object> expected, Handle<Object> a, Handle<Object> b) {
     95     Handle<Object> result = Call(a, b).ToHandleChecked();
     96     CHECK(expected->SameValue(*result));
     97   }
     98 
     99   void CheckCall(Handle<Object> expected, Handle<Object> a) {
    100     CheckCall(expected, a, undefined());
    101   }
    102 
    103   void CheckCall(Handle<Object> expected) {
    104     CheckCall(expected, undefined(), undefined());
    105   }
    106 
    107   void CheckCall(double expected, double a, double b) {
    108     CheckCall(Val(expected), Val(a), Val(b));
    109   }
    110 
    111   void CheckTrue(Handle<Object> a, Handle<Object> b) {
    112     CheckCall(true_value(), a, b);
    113   }
    114 
    115   void CheckTrue(Handle<Object> a) { CheckCall(true_value(), a, undefined()); }
    116 
    117   void CheckTrue(double a, double b) {
    118     CheckCall(true_value(), Val(a), Val(b));
    119   }
    120 
    121   void CheckFalse(Handle<Object> a, Handle<Object> b) {
    122     CheckCall(false_value(), a, b);
    123   }
    124 
    125   void CheckFalse(Handle<Object> a) {
    126     CheckCall(false_value(), a, undefined());
    127   }
    128 
    129   void CheckFalse(double a, double b) {
    130     CheckCall(false_value(), Val(a), Val(b));
    131   }
    132 
    133   Handle<JSFunction> NewFunction(const char* source) {
    134     return Handle<JSFunction>::cast(v8::Utils::OpenHandle(
    135         *v8::Local<v8::Function>::Cast(CompileRun(source))));
    136   }
    137 
    138   Handle<JSObject> NewObject(const char* source) {
    139     return Handle<JSObject>::cast(v8::Utils::OpenHandle(
    140         *v8::Local<v8::Object>::Cast(CompileRun(source))));
    141   }
    142 
    143   Handle<String> Val(const char* string) {
    144     return isolate->factory()->InternalizeUtf8String(string);
    145   }
    146 
    147   Handle<Object> Val(double value) {
    148     return isolate->factory()->NewNumber(value);
    149   }
    150 
    151   Handle<Object> infinity() { return isolate->factory()->infinity_value(); }
    152 
    153   Handle<Object> minus_infinity() { return Val(-V8_INFINITY); }
    154 
    155   Handle<Object> nan() { return isolate->factory()->nan_value(); }
    156 
    157   Handle<Object> undefined() { return isolate->factory()->undefined_value(); }
    158 
    159   Handle<Object> null() { return isolate->factory()->null_value(); }
    160 
    161   Handle<Object> true_value() { return isolate->factory()->true_value(); }
    162 
    163   Handle<Object> false_value() { return isolate->factory()->false_value(); }
    164 
    165   Handle<JSFunction> Compile(Handle<JSFunction> function) {
    166 // TODO(titzer): make this method private.
    167     Zone zone;
    168     ParseInfo parse_info(&zone, function);
    169     CompilationInfo info(&parse_info);
    170     info.MarkAsDeoptimizationEnabled();
    171 
    172     CHECK(Parser::ParseStatic(info.parse_info()));
    173     info.SetOptimizing(BailoutId::None(), Handle<Code>(function->code()));
    174     if (flags_ & CompilationInfo::kFunctionContextSpecializing) {
    175       info.MarkAsFunctionContextSpecializing();
    176     }
    177     if (flags_ & CompilationInfo::kInliningEnabled) {
    178       info.MarkAsInliningEnabled();
    179     }
    180     if (flags_ & CompilationInfo::kTypingEnabled) {
    181       info.MarkAsTypingEnabled();
    182     }
    183     CHECK(Compiler::Analyze(info.parse_info()));
    184     CHECK(Compiler::EnsureDeoptimizationSupport(&info));
    185 
    186     Pipeline pipeline(&info);
    187     Handle<Code> code = pipeline.GenerateCode();
    188     CHECK(!code.is_null());
    189     info.dependencies()->Commit(code);
    190     info.context()->native_context()->AddOptimizedCode(*code);
    191     function->ReplaceCode(*code);
    192     return function;
    193   }
    194 
    195   static Handle<JSFunction> ForMachineGraph(Graph* graph, int param_count) {
    196     JSFunction* p = NULL;
    197     {  // because of the implicit handle scope of FunctionTester.
    198       FunctionTester f(graph, param_count);
    199       p = *f.function;
    200     }
    201     return Handle<JSFunction>(p);  // allocated in outer handle scope.
    202   }
    203 
    204  private:
    205   uint32_t flags_;
    206 
    207   std::string BuildFunction(int param_count) {
    208     std::string function_string = "(function(";
    209     if (param_count > 0) {
    210       char next = 'a';
    211       function_string += next;
    212       while (param_count-- > 0) {
    213         function_string += ',';
    214         function_string += ++next;
    215       }
    216     }
    217     function_string += "){})";
    218     return function_string;
    219   }
    220 
    221   std::string BuildFunctionFromDescriptor(
    222       const CallInterfaceDescriptor& descriptor) {
    223     return BuildFunction(descriptor.GetParameterCount());
    224   }
    225 
    226   // Compile the given machine graph instead of the source of the function
    227   // and replace the JSFunction's code with the result.
    228   Handle<JSFunction> CompileGraph(Graph* graph) {
    229     Zone zone;
    230     ParseInfo parse_info(&zone, function);
    231     CompilationInfo info(&parse_info);
    232 
    233     CHECK(Parser::ParseStatic(info.parse_info()));
    234     info.SetOptimizing(BailoutId::None(),
    235                        Handle<Code>(function->shared()->code()));
    236     CHECK(Compiler::Analyze(info.parse_info()));
    237     CHECK(Compiler::EnsureDeoptimizationSupport(&info));
    238 
    239     Handle<Code> code = Pipeline::GenerateCodeForTesting(&info, graph);
    240     CHECK(!code.is_null());
    241     function->ReplaceCode(*code);
    242     return function;
    243   }
    244 };
    245 }  // namespace compiler
    246 }  // namespace internal
    247 }  // namespace v8
    248 
    249 #endif  // V8_CCTEST_COMPILER_FUNCTION_TESTER_H_
    250