• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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)
isolate(main_isolate ())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 
FunctionTester(Graph * graph,int param_count)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 
FunctionTester(Handle<Code> code,int param_count)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 
FunctionTester(const CallInterfaceDescriptor & descriptor,Handle<Code> code)54   FunctionTester(const CallInterfaceDescriptor& descriptor, Handle<Code> code)
55       : FunctionTester(code, descriptor.GetParameterCount()) {}
56 
57   Isolate* isolate;
58   Handle<JSFunction> function;
59 
Call()60   MaybeHandle<Object> Call() {
61     return Execution::Call(isolate, function, undefined(), 0, nullptr);
62   }
63 
Call(Handle<Object> a)64   MaybeHandle<Object> Call(Handle<Object> a) {
65     Handle<Object> args[] = {a};
66     return Execution::Call(isolate, function, undefined(), 1, args);
67   }
68 
Call(Handle<Object> a,Handle<Object> b)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 
Call(Handle<Object> a,Handle<Object> b,Handle<Object> c)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 
Call(Handle<Object> a,Handle<Object> b,Handle<Object> c,Handle<Object> d)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 
CheckThrows(Handle<Object> a,Handle<Object> b)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 
CheckThrowsReturnMessage(Handle<Object> a,Handle<Object> b)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 
CheckCall(Handle<Object> expected,Handle<Object> a,Handle<Object> b,Handle<Object> c,Handle<Object> d)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 
CheckCall(Handle<Object> expected,Handle<Object> a,Handle<Object> b,Handle<Object> c)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 
CheckCall(Handle<Object> expected,Handle<Object> a,Handle<Object> b)118   void CheckCall(Handle<Object> expected, Handle<Object> a, Handle<Object> b) {
119     return CheckCall(expected, a, b, undefined());
120   }
121 
CheckCall(Handle<Object> expected,Handle<Object> a)122   void CheckCall(Handle<Object> expected, Handle<Object> a) {
123     CheckCall(expected, a, undefined());
124   }
125 
CheckCall(Handle<Object> expected)126   void CheckCall(Handle<Object> expected) { CheckCall(expected, undefined()); }
127 
CheckCall(double expected,double a,double b)128   void CheckCall(double expected, double a, double b) {
129     CheckCall(Val(expected), Val(a), Val(b));
130   }
131 
CheckTrue(Handle<Object> a)132   void CheckTrue(Handle<Object> a) { CheckCall(true_value(), a); }
133 
CheckTrue(Handle<Object> a,Handle<Object> b)134   void CheckTrue(Handle<Object> a, Handle<Object> b) {
135     CheckCall(true_value(), a, b);
136   }
137 
CheckTrue(Handle<Object> a,Handle<Object> b,Handle<Object> c)138   void CheckTrue(Handle<Object> a, Handle<Object> b, Handle<Object> c) {
139     CheckCall(true_value(), a, b, c);
140   }
141 
CheckTrue(Handle<Object> a,Handle<Object> b,Handle<Object> c,Handle<Object> d)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 
CheckTrue(double a,double b)147   void CheckTrue(double a, double b) {
148     CheckCall(true_value(), Val(a), Val(b));
149   }
150 
CheckFalse(Handle<Object> a)151   void CheckFalse(Handle<Object> a) { CheckCall(false_value(), a); }
152 
CheckFalse(Handle<Object> a,Handle<Object> b)153   void CheckFalse(Handle<Object> a, Handle<Object> b) {
154     CheckCall(false_value(), a, b);
155   }
156 
CheckFalse(double a,double b)157   void CheckFalse(double a, double b) {
158     CheckCall(false_value(), Val(a), Val(b));
159   }
160 
NewFunction(const char * source)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 
NewObject(const char * source)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 
Val(const char * string)171   Handle<String> Val(const char* string) {
172     return isolate->factory()->InternalizeUtf8String(string);
173   }
174 
Val(double value)175   Handle<Object> Val(double value) {
176     return isolate->factory()->NewNumber(value);
177   }
178 
infinity()179   Handle<Object> infinity() { return isolate->factory()->infinity_value(); }
180 
minus_infinity()181   Handle<Object> minus_infinity() { return Val(-V8_INFINITY); }
182 
nan()183   Handle<Object> nan() { return isolate->factory()->nan_value(); }
184 
undefined()185   Handle<Object> undefined() { return isolate->factory()->undefined_value(); }
186 
null()187   Handle<Object> null() { return isolate->factory()->null_value(); }
188 
true_value()189   Handle<Object> true_value() { return isolate->factory()->true_value(); }
190 
false_value()191   Handle<Object> false_value() { return isolate->factory()->false_value(); }
192 
ForMachineGraph(Graph * graph,int param_count)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 
Compile(Handle<JSFunction> function)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 
BuildFunction(int param_count)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.
CompileGraph(Graph * graph)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