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