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/compiler.h"
12 #include "src/compiler/pipeline.h"
13 #include "src/execution.h"
14 #include "src/full-codegen.h"
15 #include "src/handles.h"
16 #include "src/objects-inl.h"
17 #include "src/parser.h"
18 #include "src/rewriter.h"
19 #include "src/scopes.h"
20 
21 #define USE_CRANKSHAFT 0
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)
isolate(main_isolate ())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 = CompilationInfo::kContextSpecializing |
35                                      CompilationInfo::kInliningEnabled |
36                                      CompilationInfo::kTypingEnabled;
37     CHECK_EQ(0, flags_ & ~supported_flags);
38   }
39 
40   Isolate* isolate;
41   Handle<JSFunction> function;
42 
Compile(Handle<JSFunction> function)43   Handle<JSFunction> Compile(Handle<JSFunction> function) {
44 #if V8_TURBOFAN_TARGET
45     CompilationInfoWithZone info(function);
46 
47     CHECK(Parser::Parse(&info));
48     info.SetOptimizing(BailoutId::None(), Handle<Code>(function->code()));
49     if (flags_ & CompilationInfo::kContextSpecializing) {
50       info.MarkAsContextSpecializing();
51     }
52     if (flags_ & CompilationInfo::kInliningEnabled) {
53       info.MarkAsInliningEnabled();
54     }
55     if (flags_ & CompilationInfo::kTypingEnabled) {
56       info.MarkAsTypingEnabled();
57     }
58     CHECK(Rewriter::Rewrite(&info));
59     CHECK(Scope::Analyze(&info));
60     CHECK(Compiler::EnsureDeoptimizationSupport(&info));
61 
62     Pipeline pipeline(&info);
63     Handle<Code> code = pipeline.GenerateCode();
64     if (FLAG_turbo_deoptimization) {
65       info.context()->native_context()->AddOptimizedCode(*code);
66     }
67 
68     CHECK(!code.is_null());
69     function->ReplaceCode(*code);
70 #elif USE_CRANKSHAFT
71     Handle<Code> unoptimized = Handle<Code>(function->code());
72     Handle<Code> code = Compiler::GetOptimizedCode(function, unoptimized,
73                                                    Compiler::NOT_CONCURRENT);
74     CHECK(!code.is_null());
75 #if ENABLE_DISASSEMBLER
76     if (FLAG_print_opt_code) {
77       CodeTracer::Scope tracing_scope(isolate->GetCodeTracer());
78       code->Disassemble("test code", tracing_scope.file());
79     }
80 #endif
81     function->ReplaceCode(*code);
82 #endif
83     return function;
84   }
85 
Call(Handle<Object> a,Handle<Object> b)86   MaybeHandle<Object> Call(Handle<Object> a, Handle<Object> b) {
87     Handle<Object> args[] = {a, b};
88     return Execution::Call(isolate, function, undefined(), 2, args, false);
89   }
90 
CheckThrows(Handle<Object> a,Handle<Object> b)91   void CheckThrows(Handle<Object> a, Handle<Object> b) {
92     TryCatch try_catch;
93     MaybeHandle<Object> no_result = Call(a, b);
94     CHECK(isolate->has_pending_exception());
95     CHECK(try_catch.HasCaught());
96     CHECK(no_result.is_null());
97     // TODO(mstarzinger): Temporary workaround for issue chromium:362388.
98     isolate->OptionalRescheduleException(true);
99   }
100 
CheckThrowsReturnMessage(Handle<Object> a,Handle<Object> b)101   v8::Handle<v8::Message> CheckThrowsReturnMessage(Handle<Object> a,
102                                                    Handle<Object> b) {
103     TryCatch try_catch;
104     MaybeHandle<Object> no_result = Call(a, b);
105     CHECK(isolate->has_pending_exception());
106     CHECK(try_catch.HasCaught());
107     CHECK(no_result.is_null());
108     // TODO(mstarzinger): Calling OptionalRescheduleException is a dirty hack,
109     // it's the only way to make Message() not to assert because an external
110     // exception has been caught by the try_catch.
111     isolate->OptionalRescheduleException(true);
112     return try_catch.Message();
113   }
114 
CheckCall(Handle<Object> expected,Handle<Object> a,Handle<Object> b)115   void CheckCall(Handle<Object> expected, Handle<Object> a, Handle<Object> b) {
116     Handle<Object> result = Call(a, b).ToHandleChecked();
117     CHECK(expected->SameValue(*result));
118   }
119 
CheckCall(Handle<Object> expected,Handle<Object> a)120   void CheckCall(Handle<Object> expected, Handle<Object> a) {
121     CheckCall(expected, a, undefined());
122   }
123 
CheckCall(Handle<Object> expected)124   void CheckCall(Handle<Object> expected) {
125     CheckCall(expected, undefined(), undefined());
126   }
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,Handle<Object> b)132   void CheckTrue(Handle<Object> a, Handle<Object> b) {
133     CheckCall(true_value(), a, b);
134   }
135 
CheckTrue(Handle<Object> a)136   void CheckTrue(Handle<Object> a) { CheckCall(true_value(), a, undefined()); }
137 
CheckTrue(double a,double b)138   void CheckTrue(double a, double b) {
139     CheckCall(true_value(), Val(a), Val(b));
140   }
141 
CheckFalse(Handle<Object> a,Handle<Object> b)142   void CheckFalse(Handle<Object> a, Handle<Object> b) {
143     CheckCall(false_value(), a, b);
144   }
145 
CheckFalse(Handle<Object> a)146   void CheckFalse(Handle<Object> a) {
147     CheckCall(false_value(), a, undefined());
148   }
149 
CheckFalse(double a,double b)150   void CheckFalse(double a, double b) {
151     CheckCall(false_value(), Val(a), Val(b));
152   }
153 
NewFunction(const char * source)154   Handle<JSFunction> NewFunction(const char* source) {
155     return v8::Utils::OpenHandle(
156         *v8::Handle<v8::Function>::Cast(CompileRun(source)));
157   }
158 
NewObject(const char * source)159   Handle<JSObject> NewObject(const char* source) {
160     return v8::Utils::OpenHandle(
161         *v8::Handle<v8::Object>::Cast(CompileRun(source)));
162   }
163 
Val(const char * string)164   Handle<String> Val(const char* string) {
165     return isolate->factory()->InternalizeUtf8String(string);
166   }
167 
Val(double value)168   Handle<Object> Val(double value) {
169     return isolate->factory()->NewNumber(value);
170   }
171 
infinity()172   Handle<Object> infinity() { return isolate->factory()->infinity_value(); }
173 
minus_infinity()174   Handle<Object> minus_infinity() { return Val(-V8_INFINITY); }
175 
nan()176   Handle<Object> nan() { return isolate->factory()->nan_value(); }
177 
undefined()178   Handle<Object> undefined() { return isolate->factory()->undefined_value(); }
179 
null()180   Handle<Object> null() { return isolate->factory()->null_value(); }
181 
true_value()182   Handle<Object> true_value() { return isolate->factory()->true_value(); }
183 
false_value()184   Handle<Object> false_value() { return isolate->factory()->false_value(); }
185 
186  private:
187   uint32_t flags_;
188 };
189 }
190 }
191 }  // namespace v8::internal::compiler
192 
193 #endif  // V8_CCTEST_COMPILER_FUNCTION_TESTER_H_
194