• 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 | CompilationInfo::kTypingEnabled;
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(const CallInterfaceDescriptor & descriptor,Handle<Code> code)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 
Call()58   MaybeHandle<Object> Call() {
59     return Execution::Call(isolate, function, undefined(), 0, nullptr);
60   }
61 
Call(Handle<Object> a,Handle<Object> b)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 
Call(Handle<Object> a,Handle<Object> b,Handle<Object> c,Handle<Object> d)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 
CheckThrows(Handle<Object> a,Handle<Object> b)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 
CheckThrowsReturnMessage(Handle<Object> a,Handle<Object> b)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 
CheckCall(Handle<Object> expected,Handle<Object> a,Handle<Object> b)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 
CheckCall(Handle<Object> expected,Handle<Object> a)99   void CheckCall(Handle<Object> expected, Handle<Object> a) {
100     CheckCall(expected, a, undefined());
101   }
102 
CheckCall(Handle<Object> expected)103   void CheckCall(Handle<Object> expected) {
104     CheckCall(expected, undefined(), undefined());
105   }
106 
CheckCall(double expected,double a,double b)107   void CheckCall(double expected, double a, double b) {
108     CheckCall(Val(expected), Val(a), Val(b));
109   }
110 
CheckTrue(Handle<Object> a,Handle<Object> b)111   void CheckTrue(Handle<Object> a, Handle<Object> b) {
112     CheckCall(true_value(), a, b);
113   }
114 
CheckTrue(Handle<Object> a)115   void CheckTrue(Handle<Object> a) { CheckCall(true_value(), a, undefined()); }
116 
CheckTrue(double a,double b)117   void CheckTrue(double a, double b) {
118     CheckCall(true_value(), Val(a), Val(b));
119   }
120 
CheckFalse(Handle<Object> a,Handle<Object> b)121   void CheckFalse(Handle<Object> a, Handle<Object> b) {
122     CheckCall(false_value(), a, b);
123   }
124 
CheckFalse(Handle<Object> a)125   void CheckFalse(Handle<Object> a) {
126     CheckCall(false_value(), a, undefined());
127   }
128 
CheckFalse(double a,double b)129   void CheckFalse(double a, double b) {
130     CheckCall(false_value(), Val(a), Val(b));
131   }
132 
NewFunction(const char * source)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 
NewObject(const char * source)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 
Val(const char * string)143   Handle<String> Val(const char* string) {
144     return isolate->factory()->InternalizeUtf8String(string);
145   }
146 
Val(double value)147   Handle<Object> Val(double value) {
148     return isolate->factory()->NewNumber(value);
149   }
150 
infinity()151   Handle<Object> infinity() { return isolate->factory()->infinity_value(); }
152 
minus_infinity()153   Handle<Object> minus_infinity() { return Val(-V8_INFINITY); }
154 
nan()155   Handle<Object> nan() { return isolate->factory()->nan_value(); }
156 
undefined()157   Handle<Object> undefined() { return isolate->factory()->undefined_value(); }
158 
null()159   Handle<Object> null() { return isolate->factory()->null_value(); }
160 
true_value()161   Handle<Object> true_value() { return isolate->factory()->true_value(); }
162 
false_value()163   Handle<Object> false_value() { return isolate->factory()->false_value(); }
164 
Compile(Handle<JSFunction> function)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 
ForMachineGraph(Graph * graph,int param_count)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 
BuildFunction(int param_count)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 
BuildFunctionFromDescriptor(const CallInterfaceDescriptor & descriptor)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.
CompileGraph(Graph * graph)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