Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(6)

Side by Side Diff: test/cctest/compiler/test-codegen-deopt.cc

Issue 426233002: Land the Fan (disabled) (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Review feedback, rebase and "git cl format" Created 6 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « test/cctest/compiler/test-branch-combine.cc ('k') | test/cctest/compiler/test-gap-resolver.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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/function-tester.h"
24
25 using namespace v8::internal;
26 using namespace v8::internal::compiler;
27
28 typedef RawMachineAssembler::Label MLabel;
29
30 static Handle<JSFunction> NewFunction(const char* source) {
31 return v8::Utils::OpenHandle(
32 *v8::Handle<v8::Function>::Cast(CompileRun(source)));
33 }
34
35
36 class DeoptCodegenTester {
37 public:
38 explicit DeoptCodegenTester(HandleAndZoneScope* scope, const char* src)
39 : scope_(scope),
40 function(NewFunction(src)),
41 info(function, scope->main_zone()),
42 bailout_id(-1) {
43 CHECK(Parser::Parse(&info));
44 StrictMode strict_mode = info.function()->strict_mode();
45 info.SetStrictMode(strict_mode);
46 info.SetOptimizing(BailoutId::None(), Handle<Code>(function->code()));
47 CHECK(Rewriter::Rewrite(&info));
48 CHECK(Scope::Analyze(&info));
49 CHECK_NE(NULL, info.scope());
50
51 FunctionTester::EnsureDeoptimizationSupport(&info);
52
53 ASSERT(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 os << *schedule;
63
64 // Initialize the codegen and generate code.
65 Linkage* linkage = new (scope_->main_zone()) Linkage(&info);
66 code = new v8::internal::compiler::InstructionSequence(linkage, graph,
67 schedule);
68 SourcePositionTable source_positions(graph);
69 InstructionSelector selector(code, &source_positions);
70 selector.SelectInstructions();
71
72 os << "----- Instruction sequence before register allocation -----\n"
73 << *code;
74
75 RegisterAllocator allocator(code);
76 CHECK(allocator.Allocate());
77
78 os << "----- Instruction sequence after register allocation -----\n"
79 << *code;
80
81 compiler::CodeGenerator generator(code);
82 result_code = generator.GenerateCode();
83
84 #ifdef DEBUG
85 result_code->Print();
86 #endif
87 }
88
89 Zone* zone() { return scope_->main_zone(); }
90
91 HandleAndZoneScope* scope_;
92 Handle<JSFunction> function;
93 CompilationInfo info;
94 BailoutId bailout_id;
95 Handle<Code> result_code;
96 v8::internal::compiler::InstructionSequence* code;
97 Graph* graph;
98 };
99
100
101 class TrivialDeoptCodegenTester : public DeoptCodegenTester {
102 public:
103 explicit TrivialDeoptCodegenTester(HandleAndZoneScope* scope)
104 : DeoptCodegenTester(scope,
105 "function foo() { deopt(); return 42; }; foo") {}
106
107 void GenerateCode() {
108 GenerateCodeFromSchedule(BuildGraphAndSchedule(graph));
109 }
110
111 Schedule* BuildGraphAndSchedule(Graph* graph) {
112 Isolate* isolate = info.isolate();
113 CommonOperatorBuilder common(zone());
114
115 // Manually construct a schedule for the function below:
116 // function foo() {
117 // deopt();
118 // }
119
120 MachineRepresentation parameter_reps[] = {kMachineTagged};
121 MachineCallDescriptorBuilder descriptor_builder(kMachineTagged, 1,
122 parameter_reps);
123
124 RawMachineAssembler m(graph, &descriptor_builder);
125
126 Handle<Object> undef_object =
127 Handle<Object>(isolate->heap()->undefined_value(), isolate);
128 PrintableUnique<Object> undef_constant =
129 PrintableUnique<Object>::CreateUninitialized(zone(), undef_object);
130 Node* undef_node = m.NewNode(common.HeapConstant(undef_constant));
131
132 Handle<JSFunction> deopt_function =
133 NewFunction("function deopt() { %DeoptimizeFunction(foo); }; deopt");
134 PrintableUnique<Object> deopt_fun_constant =
135 PrintableUnique<Object>::CreateUninitialized(zone(), deopt_function);
136 Node* deopt_fun_node = m.NewNode(common.HeapConstant(deopt_fun_constant));
137
138 MLabel deopt, cont;
139 Node* call = m.CallJS0(deopt_fun_node, undef_node, &cont, &deopt);
140
141 m.Bind(&cont);
142 m.NewNode(common.Continuation(), call);
143 m.Return(undef_node);
144
145 m.Bind(&deopt);
146 m.NewNode(common.LazyDeoptimization(), call);
147
148 bailout_id = GetCallBailoutId();
149 FrameStateDescriptor stateDescriptor(bailout_id);
150 Node* state_node = m.NewNode(common.FrameState(stateDescriptor));
151 m.Deoptimize(state_node);
152
153 // Schedule the graph:
154 Schedule* schedule = m.Export();
155
156 cont_block = cont.block();
157 deopt_block = deopt.block();
158
159 return schedule;
160 }
161
162 BailoutId GetCallBailoutId() {
163 ZoneList<Statement*>* body = info.function()->body();
164 for (int i = 0; i < body->length(); i++) {
165 if (body->at(i)->IsExpressionStatement() &&
166 body->at(i)->AsExpressionStatement()->expression()->IsCall()) {
167 return body->at(i)->AsExpressionStatement()->expression()->id();
168 }
169 }
170 CHECK(false);
171 return BailoutId(-1);
172 }
173
174 BasicBlock* cont_block;
175 BasicBlock* deopt_block;
176 };
177
178
179 TEST(TurboTrivialDeoptCodegen) {
180 HandleAndZoneScope scope;
181 InitializedHandleScope handles;
182
183 FLAG_allow_natives_syntax = true;
184 FLAG_turbo_deoptimization = true;
185
186 TrivialDeoptCodegenTester t(&scope);
187 t.GenerateCode();
188
189 DeoptimizationInputData* data =
190 DeoptimizationInputData::cast(t.result_code->deoptimization_data());
191
192 Label* cont_label = t.code->GetLabel(t.cont_block);
193 Label* deopt_label = t.code->GetLabel(t.deopt_block);
194
195 // Check the patch table. It should patch the continuation address to the
196 // deoptimization block address.
197 CHECK_EQ(1, data->ReturnAddressPatchCount());
198 CHECK_EQ(cont_label->pos(), data->ReturnAddressPc(0)->value());
199 CHECK_EQ(deopt_label->pos(), data->PatchedAddressPc(0)->value());
200
201 // Check that we deoptimize to the right AST id.
202 CHECK_EQ(1, data->DeoptCount());
203 CHECK_EQ(1, data->DeoptCount());
204 CHECK_EQ(t.bailout_id.ToInt(), data->AstId(0).ToInt());
205 }
206
207
208 TEST(TurboTrivialDeoptCodegenAndRun) {
209 HandleAndZoneScope scope;
210 InitializedHandleScope handles;
211
212 FLAG_allow_natives_syntax = true;
213 FLAG_turbo_deoptimization = true;
214
215 TrivialDeoptCodegenTester t(&scope);
216 t.GenerateCode();
217
218 t.function->ReplaceCode(*t.result_code);
219 t.info.context()->native_context()->AddOptimizedCode(*t.result_code);
220
221 Isolate* isolate = scope.main_isolate();
222 Handle<Object> result;
223 bool has_pending_exception =
224 !Execution::Call(isolate, t.function,
225 isolate->factory()->undefined_value(), 0, NULL,
226 false).ToHandle(&result);
227 CHECK(!has_pending_exception);
228 CHECK(result->SameValue(Smi::FromInt(42)));
229 }
230
231
232 class TrivialRuntimeDeoptCodegenTester : public DeoptCodegenTester {
233 public:
234 explicit TrivialRuntimeDeoptCodegenTester(HandleAndZoneScope* scope)
235 : DeoptCodegenTester(
236 scope,
237 "function foo() { %DeoptimizeFunction(foo); return 42; }; foo") {}
238
239 void GenerateCode() {
240 GenerateCodeFromSchedule(BuildGraphAndSchedule(graph));
241 }
242
243 Schedule* BuildGraphAndSchedule(Graph* graph) {
244 Isolate* isolate = info.isolate();
245 CommonOperatorBuilder common(zone());
246
247 // Manually construct a schedule for the function below:
248 // function foo() {
249 // %DeoptimizeFunction(foo);
250 // }
251
252 MachineRepresentation parameter_reps[] = {kMachineTagged};
253 MachineCallDescriptorBuilder descriptor_builder(kMachineTagged, 2,
254 parameter_reps);
255
256 RawMachineAssembler m(graph, &descriptor_builder);
257
258 Handle<Object> undef_object =
259 Handle<Object>(isolate->heap()->undefined_value(), isolate);
260 PrintableUnique<Object> undef_constant =
261 PrintableUnique<Object>::CreateUninitialized(zone(), undef_object);
262 Node* undef_node = m.NewNode(common.HeapConstant(undef_constant));
263
264 PrintableUnique<Object> this_fun_constant =
265 PrintableUnique<Object>::CreateUninitialized(zone(), function);
266 Node* this_fun_node = m.NewNode(common.HeapConstant(this_fun_constant));
267
268 MLabel deopt, cont;
269 Node* call = m.CallRuntime1(Runtime::kDeoptimizeFunction, this_fun_node,
270 &cont, &deopt);
271
272 m.Bind(&cont);
273 m.NewNode(common.Continuation(), call);
274 m.Return(undef_node);
275
276 m.Bind(&deopt);
277 m.NewNode(common.LazyDeoptimization(), call);
278
279 bailout_id = GetCallBailoutId();
280 FrameStateDescriptor stateDescriptor(bailout_id);
281 Node* state_node = m.NewNode(common.FrameState(stateDescriptor));
282 m.Deoptimize(state_node);
283
284 // Schedule the graph:
285 Schedule* schedule = m.Export();
286
287 cont_block = cont.block();
288 deopt_block = deopt.block();
289
290 return schedule;
291 }
292
293 BailoutId GetCallBailoutId() {
294 ZoneList<Statement*>* body = info.function()->body();
295 for (int i = 0; i < body->length(); i++) {
296 if (body->at(i)->IsExpressionStatement() &&
297 body->at(i)->AsExpressionStatement()->expression()->IsCallRuntime()) {
298 return body->at(i)->AsExpressionStatement()->expression()->id();
299 }
300 }
301 CHECK(false);
302 return BailoutId(-1);
303 }
304
305 BasicBlock* cont_block;
306 BasicBlock* deopt_block;
307 };
308
309
310 TEST(TurboTrivialRuntimeDeoptCodegenAndRun) {
311 HandleAndZoneScope scope;
312 InitializedHandleScope handles;
313
314 FLAG_allow_natives_syntax = true;
315 FLAG_turbo_deoptimization = true;
316
317 TrivialRuntimeDeoptCodegenTester t(&scope);
318 t.GenerateCode();
319
320 t.function->ReplaceCode(*t.result_code);
321 t.info.context()->native_context()->AddOptimizedCode(*t.result_code);
322
323 Isolate* isolate = scope.main_isolate();
324 Handle<Object> result;
325 bool has_pending_exception =
326 !Execution::Call(isolate, t.function,
327 isolate->factory()->undefined_value(), 0, NULL,
328 false).ToHandle(&result);
329 CHECK(!has_pending_exception);
330 CHECK(result->SameValue(Smi::FromInt(42)));
331 }
OLDNEW
« no previous file with comments | « test/cctest/compiler/test-branch-combine.cc ('k') | test/cctest/compiler/test-gap-resolver.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698