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
23namespace v8 {
24namespace internal {
25namespace compiler {
26
27class 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 = 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
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
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
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
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
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
120  void CheckCall(Handle<Object> expected, Handle<Object> a) {
121    CheckCall(expected, a, undefined());
122  }
123
124  void CheckCall(Handle<Object> expected) {
125    CheckCall(expected, undefined(), undefined());
126  }
127
128  void CheckCall(double expected, double a, double b) {
129    CheckCall(Val(expected), Val(a), Val(b));
130  }
131
132  void CheckTrue(Handle<Object> a, Handle<Object> b) {
133    CheckCall(true_value(), a, b);
134  }
135
136  void CheckTrue(Handle<Object> a) { CheckCall(true_value(), a, undefined()); }
137
138  void CheckTrue(double a, double b) {
139    CheckCall(true_value(), Val(a), Val(b));
140  }
141
142  void CheckFalse(Handle<Object> a, Handle<Object> b) {
143    CheckCall(false_value(), a, b);
144  }
145
146  void CheckFalse(Handle<Object> a) {
147    CheckCall(false_value(), a, undefined());
148  }
149
150  void CheckFalse(double a, double b) {
151    CheckCall(false_value(), Val(a), Val(b));
152  }
153
154  Handle<JSFunction> NewFunction(const char* source) {
155    return v8::Utils::OpenHandle(
156        *v8::Handle<v8::Function>::Cast(CompileRun(source)));
157  }
158
159  Handle<JSObject> NewObject(const char* source) {
160    return v8::Utils::OpenHandle(
161        *v8::Handle<v8::Object>::Cast(CompileRun(source)));
162  }
163
164  Handle<String> Val(const char* string) {
165    return isolate->factory()->InternalizeUtf8String(string);
166  }
167
168  Handle<Object> Val(double value) {
169    return isolate->factory()->NewNumber(value);
170  }
171
172  Handle<Object> infinity() { return isolate->factory()->infinity_value(); }
173
174  Handle<Object> minus_infinity() { return Val(-V8_INFINITY); }
175
176  Handle<Object> nan() { return isolate->factory()->nan_value(); }
177
178  Handle<Object> undefined() { return isolate->factory()->undefined_value(); }
179
180  Handle<Object> null() { return isolate->factory()->null_value(); }
181
182  Handle<Object> true_value() { return isolate->factory()->true_value(); }
183
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