c2b25e5547c09c2befc091076d53e2f3685d924a
[platform/upstream/v8.git] / test / cctest / compiler / function-tester.h
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/v8.h"
9 #include "test/cctest/cctest.h"
10
11 #include "src/ast-numbering.h"
12 #include "src/compiler.h"
13 #include "src/compiler/linkage.h"
14 #include "src/compiler/pipeline.h"
15 #include "src/execution.h"
16 #include "src/full-codegen/full-codegen.h"
17 #include "src/handles.h"
18 #include "src/objects-inl.h"
19 #include "src/parser.h"
20 #include "src/rewriter.h"
21 #include "src/scopes.h"
22
23 namespace v8 {
24 namespace internal {
25 namespace compiler {
26
27 class FunctionTester : public InitializedHandleScope {
28  public:
29   explicit FunctionTester(const char* source, uint32_t flags = 0)
30       : isolate(main_isolate()),
31         function((FLAG_allow_natives_syntax = true, NewFunction(source))),
32         flags_(flags) {
33     Compile(function);
34     const uint32_t supported_flags =
35         CompilationInfo::kFunctionContextSpecializing |
36         CompilationInfo::kInliningEnabled | CompilationInfo::kTypingEnabled;
37     CHECK_EQ(0u, flags_ & ~supported_flags);
38   }
39
40   // TODO(turbofan): generalize FunctionTester to work with N arguments. Now, it
41   // can handle up to four.
42   explicit FunctionTester(Graph* graph)
43       : isolate(main_isolate()),
44         function(NewFunction("(function(a,b,c,d){})")),
45         flags_(0) {
46     CompileGraph(graph);
47   }
48
49   Isolate* isolate;
50   Handle<JSFunction> function;
51
52   MaybeHandle<Object> Call(Handle<Object> a, Handle<Object> b) {
53     Handle<Object> args[] = {a, b};
54     return Execution::Call(isolate, function, undefined(), 2, args);
55   }
56
57   MaybeHandle<Object> Call(Handle<Object> a, Handle<Object> b, Handle<Object> c,
58                            Handle<Object> d) {
59     Handle<Object> args[] = {a, b, c, d};
60     return Execution::Call(isolate, function, undefined(), 4, args);
61   }
62
63   void CheckThrows(Handle<Object> a, Handle<Object> b) {
64     TryCatch try_catch(reinterpret_cast<v8::Isolate*>(isolate));
65     MaybeHandle<Object> no_result = Call(a, b);
66     CHECK(isolate->has_pending_exception());
67     CHECK(try_catch.HasCaught());
68     CHECK(no_result.is_null());
69     isolate->OptionalRescheduleException(true);
70   }
71
72   v8::Local<v8::Message> CheckThrowsReturnMessage(Handle<Object> a,
73                                                   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     CHECK(!try_catch.Message().IsEmpty());
81     return try_catch.Message();
82   }
83
84   void CheckCall(Handle<Object> expected, Handle<Object> a, Handle<Object> b) {
85     Handle<Object> result = Call(a, b).ToHandleChecked();
86     CHECK(expected->SameValue(*result));
87   }
88
89   void CheckCall(Handle<Object> expected, Handle<Object> a) {
90     CheckCall(expected, a, undefined());
91   }
92
93   void CheckCall(Handle<Object> expected) {
94     CheckCall(expected, undefined(), undefined());
95   }
96
97   void CheckCall(double expected, double a, double b) {
98     CheckCall(Val(expected), Val(a), Val(b));
99   }
100
101   void CheckTrue(Handle<Object> a, Handle<Object> b) {
102     CheckCall(true_value(), a, b);
103   }
104
105   void CheckTrue(Handle<Object> a) { CheckCall(true_value(), a, undefined()); }
106
107   void CheckTrue(double a, double b) {
108     CheckCall(true_value(), Val(a), Val(b));
109   }
110
111   void CheckFalse(Handle<Object> a, Handle<Object> b) {
112     CheckCall(false_value(), a, b);
113   }
114
115   void CheckFalse(Handle<Object> a) {
116     CheckCall(false_value(), a, undefined());
117   }
118
119   void CheckFalse(double a, double b) {
120     CheckCall(false_value(), Val(a), Val(b));
121   }
122
123   Handle<JSFunction> NewFunction(const char* source) {
124     return v8::Utils::OpenHandle(
125         *v8::Local<v8::Function>::Cast(CompileRun(source)));
126   }
127
128   Handle<JSObject> NewObject(const char* source) {
129     return v8::Utils::OpenHandle(
130         *v8::Local<v8::Object>::Cast(CompileRun(source)));
131   }
132
133   Handle<String> Val(const char* string) {
134     return isolate->factory()->InternalizeUtf8String(string);
135   }
136
137   Handle<Object> Val(double value) {
138     return isolate->factory()->NewNumber(value);
139   }
140
141   Handle<Object> infinity() { return isolate->factory()->infinity_value(); }
142
143   Handle<Object> minus_infinity() { return Val(-V8_INFINITY); }
144
145   Handle<Object> nan() { return isolate->factory()->nan_value(); }
146
147   Handle<Object> undefined() { return isolate->factory()->undefined_value(); }
148
149   Handle<Object> null() { return isolate->factory()->null_value(); }
150
151   Handle<Object> true_value() { return isolate->factory()->true_value(); }
152
153   Handle<Object> false_value() { return isolate->factory()->false_value(); }
154
155   Handle<JSFunction> Compile(Handle<JSFunction> function) {
156 // TODO(titzer): make this method private.
157     Zone zone;
158     ParseInfo parse_info(&zone, function);
159     CompilationInfo info(&parse_info);
160     info.MarkAsDeoptimizationEnabled();
161
162     CHECK(Parser::ParseStatic(info.parse_info()));
163     info.SetOptimizing(BailoutId::None(), Handle<Code>(function->code()));
164     if (flags_ & CompilationInfo::kFunctionContextSpecializing) {
165       info.MarkAsFunctionContextSpecializing();
166     }
167     if (flags_ & CompilationInfo::kInliningEnabled) {
168       info.MarkAsInliningEnabled();
169     }
170     if (flags_ & CompilationInfo::kTypingEnabled) {
171       info.MarkAsTypingEnabled();
172     }
173     CHECK(Compiler::Analyze(info.parse_info()));
174     CHECK(Compiler::EnsureDeoptimizationSupport(&info));
175
176     Pipeline pipeline(&info);
177     Handle<Code> code = pipeline.GenerateCode();
178     CHECK(!code.is_null());
179     info.context()->native_context()->AddOptimizedCode(*code);
180     function->ReplaceCode(*code);
181     return function;
182   }
183
184   static Handle<JSFunction> ForMachineGraph(Graph* graph) {
185     JSFunction* p = NULL;
186     {  // because of the implicit handle scope of FunctionTester.
187       FunctionTester f(graph);
188       p = *f.function;
189     }
190     return Handle<JSFunction>(p);  // allocated in outer handle scope.
191   }
192
193  private:
194   uint32_t flags_;
195
196   // Compile the given machine graph instead of the source of the function
197   // and replace the JSFunction's code with the result.
198   Handle<JSFunction> CompileGraph(Graph* graph) {
199     Zone zone;
200     ParseInfo parse_info(&zone, function);
201     CompilationInfo info(&parse_info);
202
203     CHECK(Parser::ParseStatic(info.parse_info()));
204     info.SetOptimizing(BailoutId::None(),
205                        Handle<Code>(function->shared()->code()));
206     CHECK(Compiler::Analyze(info.parse_info()));
207     CHECK(Compiler::EnsureDeoptimizationSupport(&info));
208
209     Handle<Code> code = Pipeline::GenerateCodeForTesting(&info, graph);
210     CHECK(!code.is_null());
211     function->ReplaceCode(*code);
212     return function;
213   }
214 };
215 }
216 }
217 }  // namespace v8::internal::compiler
218
219 #endif  // V8_CCTEST_COMPILER_FUNCTION_TESTER_H_