Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / v8 / test / cctest / compiler / test-codegen-deopt.cc
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 #include "src/v8.h"
6 #include "test/cctest/cctest.h"
7
8 #include "src/compiler/code-generator.h"
9 #include "src/compiler/common-operator.h"
10 #include "src/compiler/graph.h"
11 #include "src/compiler/instruction-selector.h"
12 #include "src/compiler/machine-operator.h"
13 #include "src/compiler/node.h"
14 #include "src/compiler/operator.h"
15 #include "src/compiler/raw-machine-assembler.h"
16 #include "src/compiler/register-allocator.h"
17 #include "src/compiler/schedule.h"
18
19 #include "src/full-codegen.h"
20 #include "src/parser.h"
21 #include "src/rewriter.h"
22
23 #include "test/cctest/compiler/c-signature.h"
24 #include "test/cctest/compiler/function-tester.h"
25
26 using namespace v8::internal;
27 using namespace v8::internal::compiler;
28
29
30 #if V8_TURBOFAN_TARGET
31
32 typedef RawMachineAssembler::Label MLabel;
33
34 static Handle<JSFunction> NewFunction(const char* source) {
35   return v8::Utils::OpenHandle(
36       *v8::Handle<v8::Function>::Cast(CompileRun(source)));
37 }
38
39
40 class DeoptCodegenTester {
41  public:
42   explicit DeoptCodegenTester(HandleAndZoneScope* scope, const char* src)
43       : scope_(scope),
44         function(NewFunction(src)),
45         info(function, scope->main_zone()),
46         bailout_id(-1) {
47     CHECK(Parser::Parse(&info));
48     info.SetOptimizing(BailoutId::None(), Handle<Code>(function->code()));
49     CHECK(Rewriter::Rewrite(&info));
50     CHECK(Scope::Analyze(&info));
51     CHECK(Compiler::EnsureDeoptimizationSupport(&info));
52
53     DCHECK(info.shared_info()->has_deoptimization_support());
54
55     graph = new (scope_->main_zone()) Graph(scope_->main_zone());
56   }
57
58   virtual ~DeoptCodegenTester() { delete code; }
59
60   void GenerateCodeFromSchedule(Schedule* schedule) {
61     OFStream os(stdout);
62     if (FLAG_trace_turbo) {
63       os << *schedule;
64     }
65
66     // Initialize the codegen and generate code.
67     Linkage* linkage = new (scope_->main_zone()) Linkage(&info);
68     code = new v8::internal::compiler::InstructionSequence(linkage, graph,
69                                                            schedule);
70     SourcePositionTable source_positions(graph);
71     InstructionSelector selector(code, &source_positions);
72     selector.SelectInstructions();
73
74     if (FLAG_trace_turbo) {
75       os << "----- Instruction sequence before register allocation -----\n"
76          << *code;
77     }
78
79     RegisterAllocator allocator(code);
80     CHECK(allocator.Allocate());
81
82     if (FLAG_trace_turbo) {
83       os << "----- Instruction sequence after register allocation -----\n"
84          << *code;
85     }
86
87     compiler::CodeGenerator generator(code);
88     result_code = generator.GenerateCode();
89
90 #ifdef OBJECT_PRINT
91     if (FLAG_print_opt_code || FLAG_trace_turbo) {
92       result_code->Print();
93     }
94 #endif
95   }
96
97   Zone* zone() { return scope_->main_zone(); }
98
99   HandleAndZoneScope* scope_;
100   Handle<JSFunction> function;
101   CompilationInfo info;
102   BailoutId bailout_id;
103   Handle<Code> result_code;
104   v8::internal::compiler::InstructionSequence* code;
105   Graph* graph;
106 };
107
108
109 class TrivialDeoptCodegenTester : public DeoptCodegenTester {
110  public:
111   explicit TrivialDeoptCodegenTester(HandleAndZoneScope* scope)
112       : DeoptCodegenTester(scope,
113                            "function foo() { deopt(); return 42; }; foo") {}
114
115   void GenerateCode() {
116     GenerateCodeFromSchedule(BuildGraphAndSchedule(graph));
117   }
118
119   Schedule* BuildGraphAndSchedule(Graph* graph) {
120     CommonOperatorBuilder common(zone());
121
122     // Manually construct a schedule for the function below:
123     // function foo() {
124     //   deopt();
125     // }
126
127     CSignature1<Object*, Object*> sig;
128     RawMachineAssembler m(graph, &sig);
129
130     Handle<JSFunction> deopt_function =
131         NewFunction("function deopt() { %DeoptimizeFunction(foo); }; deopt");
132     Unique<Object> deopt_fun_constant =
133         Unique<Object>::CreateUninitialized(deopt_function);
134     Node* deopt_fun_node = m.NewNode(common.HeapConstant(deopt_fun_constant));
135
136     Handle<Context> caller_context(function->context(), CcTest::i_isolate());
137     Unique<Object> caller_context_constant =
138         Unique<Object>::CreateUninitialized(caller_context);
139     Node* caller_context_node =
140         m.NewNode(common.HeapConstant(caller_context_constant));
141
142     bailout_id = GetCallBailoutId();
143     Node* parameters = m.NewNode(common.StateValues(1), m.UndefinedConstant());
144     Node* locals = m.NewNode(common.StateValues(0));
145     Node* stack = m.NewNode(common.StateValues(0));
146
147     Node* state_node = m.NewNode(
148         common.FrameState(JS_FRAME, bailout_id, kIgnoreOutput), parameters,
149         locals, stack, caller_context_node, m.UndefinedConstant());
150
151     Handle<Context> context(deopt_function->context(), CcTest::i_isolate());
152     Unique<Object> context_constant =
153         Unique<Object>::CreateUninitialized(context);
154     Node* context_node = m.NewNode(common.HeapConstant(context_constant));
155
156     m.CallJS0(deopt_fun_node, m.UndefinedConstant(), context_node, state_node);
157
158     m.Return(m.UndefinedConstant());
159
160     // Schedule the graph:
161     Schedule* schedule = m.Export();
162
163     return schedule;
164   }
165
166   BailoutId GetCallBailoutId() {
167     ZoneList<Statement*>* body = info.function()->body();
168     for (int i = 0; i < body->length(); i++) {
169       if (body->at(i)->IsExpressionStatement() &&
170           body->at(i)->AsExpressionStatement()->expression()->IsCall()) {
171         return body->at(i)->AsExpressionStatement()->expression()->id();
172       }
173     }
174     CHECK(false);
175     return BailoutId(-1);
176   }
177 };
178
179
180 TEST(TurboTrivialDeoptCodegen) {
181   HandleAndZoneScope scope;
182   InitializedHandleScope handles;
183
184   FLAG_allow_natives_syntax = true;
185   FLAG_turbo_deoptimization = true;
186
187   TrivialDeoptCodegenTester t(&scope);
188   t.GenerateCode();
189
190   DeoptimizationInputData* data =
191       DeoptimizationInputData::cast(t.result_code->deoptimization_data());
192
193   // TODO(jarin) Find a way to test the safepoint.
194
195   // Check that we deoptimize to the right AST id.
196   CHECK_EQ(1, data->DeoptCount());
197   CHECK_EQ(t.bailout_id.ToInt(), data->AstId(0).ToInt());
198 }
199
200
201 TEST(TurboTrivialDeoptCodegenAndRun) {
202   HandleAndZoneScope scope;
203   InitializedHandleScope handles;
204
205   FLAG_allow_natives_syntax = true;
206   FLAG_turbo_deoptimization = true;
207
208   TrivialDeoptCodegenTester t(&scope);
209   t.GenerateCode();
210
211   t.function->ReplaceCode(*t.result_code);
212   t.info.context()->native_context()->AddOptimizedCode(*t.result_code);
213
214   Isolate* isolate = scope.main_isolate();
215   Handle<Object> result;
216   bool has_pending_exception =
217       !Execution::Call(isolate, t.function,
218                        isolate->factory()->undefined_value(), 0, NULL,
219                        false).ToHandle(&result);
220   CHECK(!has_pending_exception);
221   CHECK(result->SameValue(Smi::FromInt(42)));
222 }
223
224
225 class TrivialRuntimeDeoptCodegenTester : public DeoptCodegenTester {
226  public:
227   explicit TrivialRuntimeDeoptCodegenTester(HandleAndZoneScope* scope)
228       : DeoptCodegenTester(
229             scope,
230             "function foo() { %DeoptimizeFunction(foo); return 42; }; foo") {}
231
232   void GenerateCode() {
233     GenerateCodeFromSchedule(BuildGraphAndSchedule(graph));
234   }
235
236   Schedule* BuildGraphAndSchedule(Graph* graph) {
237     CommonOperatorBuilder common(zone());
238
239     // Manually construct a schedule for the function below:
240     // function foo() {
241     //   %DeoptimizeFunction(foo);
242     // }
243
244     CSignature1<Object*, Object*> sig;
245     RawMachineAssembler m(graph, &sig);
246
247     Unique<Object> this_fun_constant =
248         Unique<Object>::CreateUninitialized(function);
249     Node* this_fun_node = m.NewNode(common.HeapConstant(this_fun_constant));
250
251     Handle<Context> context(function->context(), CcTest::i_isolate());
252     Unique<Object> context_constant =
253         Unique<Object>::CreateUninitialized(context);
254     Node* context_node = m.NewNode(common.HeapConstant(context_constant));
255
256     bailout_id = GetCallBailoutId();
257     Node* parameters = m.NewNode(common.StateValues(1), m.UndefinedConstant());
258     Node* locals = m.NewNode(common.StateValues(0));
259     Node* stack = m.NewNode(common.StateValues(0));
260
261     Node* state_node = m.NewNode(
262         common.FrameState(JS_FRAME, bailout_id, kIgnoreOutput), parameters,
263         locals, stack, context_node, m.UndefinedConstant());
264
265     m.CallRuntime1(Runtime::kDeoptimizeFunction, this_fun_node, context_node,
266                    state_node);
267
268     m.Return(m.UndefinedConstant());
269
270     // Schedule the graph:
271     Schedule* schedule = m.Export();
272
273     return schedule;
274   }
275
276   BailoutId GetCallBailoutId() {
277     ZoneList<Statement*>* body = info.function()->body();
278     for (int i = 0; i < body->length(); i++) {
279       if (body->at(i)->IsExpressionStatement() &&
280           body->at(i)->AsExpressionStatement()->expression()->IsCallRuntime()) {
281         return body->at(i)->AsExpressionStatement()->expression()->id();
282       }
283     }
284     CHECK(false);
285     return BailoutId(-1);
286   }
287 };
288
289
290 TEST(TurboTrivialRuntimeDeoptCodegenAndRun) {
291   HandleAndZoneScope scope;
292   InitializedHandleScope handles;
293
294   FLAG_allow_natives_syntax = true;
295   FLAG_turbo_deoptimization = true;
296
297   TrivialRuntimeDeoptCodegenTester t(&scope);
298   t.GenerateCode();
299
300   t.function->ReplaceCode(*t.result_code);
301   t.info.context()->native_context()->AddOptimizedCode(*t.result_code);
302
303   Isolate* isolate = scope.main_isolate();
304   Handle<Object> result;
305   bool has_pending_exception =
306       !Execution::Call(isolate, t.function,
307                        isolate->factory()->undefined_value(), 0, NULL,
308                        false).ToHandle(&result);
309   CHECK(!has_pending_exception);
310   CHECK(result->SameValue(Smi::FromInt(42)));
311 }
312
313 #endif