OLD | NEW |
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 /// Generate code using the cps-based IR pipeline. | 5 /// Generate code using the cps-based IR pipeline. |
6 library code_generator_task; | 6 library code_generator_task; |
7 | 7 |
8 import 'glue.dart'; | 8 import 'glue.dart'; |
9 import 'codegen.dart'; | 9 import 'codegen.dart'; |
10 import 'unsugar.dart'; | 10 import 'unsugar.dart'; |
11 | 11 |
12 import '../js_backend.dart'; | 12 import '../js_backend.dart'; |
13 | 13 |
14 import '../../common.dart'; | 14 import '../../common.dart'; |
15 import '../../common/codegen.dart' show | 15 import '../../common/codegen.dart' show CodegenWorkItem; |
16 CodegenWorkItem; | 16 import '../../common/tasks.dart' show CompilerTask, GenericTask; |
17 import '../../common/tasks.dart' show | 17 import '../../compiler.dart' show Compiler; |
18 CompilerTask, | |
19 GenericTask; | |
20 import '../../compiler.dart' show | |
21 Compiler; | |
22 import '../../constants/constant_system.dart'; | 18 import '../../constants/constant_system.dart'; |
23 import '../../cps_ir/cps_ir_builder_task.dart'; | 19 import '../../cps_ir/cps_ir_builder_task.dart'; |
24 import '../../cps_ir/cps_ir_nodes.dart' as cps; | 20 import '../../cps_ir/cps_ir_nodes.dart' as cps; |
25 import '../../cps_ir/cps_ir_nodes_sexpr.dart'; | 21 import '../../cps_ir/cps_ir_nodes_sexpr.dart'; |
26 import '../../cps_ir/cps_ir_integrity.dart'; | 22 import '../../cps_ir/cps_ir_integrity.dart'; |
27 import '../../cps_ir/optimizers.dart'; | 23 import '../../cps_ir/optimizers.dart'; |
28 import '../../cps_ir/optimizers.dart' as cps_opt; | 24 import '../../cps_ir/optimizers.dart' as cps_opt; |
29 import '../../cps_ir/type_mask_system.dart'; | 25 import '../../cps_ir/type_mask_system.dart'; |
30 import '../../cps_ir/finalize.dart' show Finalize; | 26 import '../../cps_ir/finalize.dart' show Finalize; |
31 import '../../diagnostics/invariant.dart' show | 27 import '../../diagnostics/invariant.dart' show DEBUG_MODE; |
32 DEBUG_MODE; | |
33 import '../../elements/elements.dart'; | 28 import '../../elements/elements.dart'; |
34 import '../../js/js.dart' as js; | 29 import '../../js/js.dart' as js; |
35 import '../../js_backend/codegen/codegen.dart'; | 30 import '../../js_backend/codegen/codegen.dart'; |
36 import '../../io/source_information.dart' show | 31 import '../../io/source_information.dart' show SourceInformationStrategy; |
37 SourceInformationStrategy; | |
38 import '../../tree_ir/tree_ir_builder.dart' as tree_builder; | 32 import '../../tree_ir/tree_ir_builder.dart' as tree_builder; |
39 import '../../tracer.dart'; | 33 import '../../tracer.dart'; |
40 import '../../ssa/ssa.dart' as ssa; | 34 import '../../ssa/ssa.dart' as ssa; |
41 import '../../tree_ir/optimization/optimization.dart'; | 35 import '../../tree_ir/optimization/optimization.dart'; |
42 import '../../tree_ir/optimization/optimization.dart' as tree_opt; | 36 import '../../tree_ir/optimization/optimization.dart' as tree_opt; |
43 import '../../tree_ir/tree_ir_integrity.dart'; | 37 import '../../tree_ir/tree_ir_integrity.dart'; |
44 import '../../tree_ir/tree_ir_nodes.dart' as tree_ir; | 38 import '../../tree_ir/tree_ir_nodes.dart' as tree_ir; |
45 import '../../types/types.dart' show | 39 import '../../types/types.dart' |
46 FlatTypeMask, | 40 show FlatTypeMask, ForwardingTypeMask, TypeMask, UnionTypeMask; |
47 ForwardingTypeMask, | |
48 TypeMask, | |
49 UnionTypeMask; | |
50 | 41 |
51 class CpsFunctionCompiler implements FunctionCompiler { | 42 class CpsFunctionCompiler implements FunctionCompiler { |
52 final ConstantSystem constantSystem; | 43 final ConstantSystem constantSystem; |
53 // TODO(karlklose): remove the compiler. | 44 // TODO(karlklose): remove the compiler. |
54 final Compiler compiler; | 45 final Compiler compiler; |
55 final Glue glue; | 46 final Glue glue; |
56 final SourceInformationStrategy sourceInformationFactory; | 47 final SourceInformationStrategy sourceInformationFactory; |
57 | 48 |
58 // TODO(karlklose,sigurdm): remove and update dart-doc of [compile]. | 49 // TODO(karlklose,sigurdm): remove and update dart-doc of [compile]. |
59 final FunctionCompiler fallbackCompiler; | 50 final FunctionCompiler fallbackCompiler; |
60 TypeMaskSystem typeSystem; | 51 TypeMaskSystem typeSystem; |
61 | 52 |
62 Tracer get tracer => compiler.tracer; | 53 Tracer get tracer => compiler.tracer; |
63 | 54 |
64 final IrBuilderTask cpsBuilderTask; | 55 final IrBuilderTask cpsBuilderTask; |
65 final GenericTask cpsOptimizationTask; | 56 final GenericTask cpsOptimizationTask; |
66 final GenericTask treeBuilderTask; | 57 final GenericTask treeBuilderTask; |
67 final GenericTask treeOptimizationTask; | 58 final GenericTask treeOptimizationTask; |
68 | 59 |
69 Inliner inliner; | 60 Inliner inliner; |
70 | 61 |
71 CpsFunctionCompiler(Compiler compiler, JavaScriptBackend backend, | 62 CpsFunctionCompiler(Compiler compiler, JavaScriptBackend backend, |
72 SourceInformationStrategy sourceInformationFactory) | 63 SourceInformationStrategy sourceInformationFactory) |
73 : fallbackCompiler = | 64 : fallbackCompiler = |
74 new ssa.SsaFunctionCompiler(backend, sourceInformationFactory), | 65 new ssa.SsaFunctionCompiler(backend, sourceInformationFactory), |
75 cpsBuilderTask = new IrBuilderTask(compiler, sourceInformationFactory), | 66 cpsBuilderTask = new IrBuilderTask(compiler, sourceInformationFactory), |
76 sourceInformationFactory = sourceInformationFactory, | 67 sourceInformationFactory = sourceInformationFactory, |
77 constantSystem = backend.constantSystem, | 68 constantSystem = backend.constantSystem, |
78 compiler = compiler, | 69 compiler = compiler, |
79 glue = new Glue(compiler), | 70 glue = new Glue(compiler), |
80 cpsOptimizationTask = new GenericTask('CPS optimization', compiler), | 71 cpsOptimizationTask = new GenericTask('CPS optimization', compiler), |
81 treeBuilderTask = new GenericTask('Tree builder', compiler), | 72 treeBuilderTask = new GenericTask('Tree builder', compiler), |
82 treeOptimizationTask = new GenericTask('Tree optimization', compiler) { | 73 treeOptimizationTask = new GenericTask('Tree optimization', compiler) { |
83 inliner = new Inliner(this); | 74 inliner = new Inliner(this); |
84 } | 75 } |
85 | 76 |
86 String get name => 'CPS Ir pipeline'; | 77 String get name => 'CPS Ir pipeline'; |
87 | 78 |
88 JavaScriptBackend get backend => compiler.backend; | 79 JavaScriptBackend get backend => compiler.backend; |
89 | 80 |
90 DiagnosticReporter get reporter => compiler.reporter; | 81 DiagnosticReporter get reporter => compiler.reporter; |
91 | 82 |
92 /// Generates JavaScript code for `work.element`. | 83 /// Generates JavaScript code for `work.element`. |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
137 | 128 |
138 /// For debugging purposes, replace a call to [applyCpsPass] with a call | 129 /// For debugging purposes, replace a call to [applyCpsPass] with a call |
139 /// to [debugCpsPass] to check that this pass is idempotent. | 130 /// to [debugCpsPass] to check that this pass is idempotent. |
140 /// | 131 /// |
141 /// This runs [pass] followed by shrinking reductions, and then checks that | 132 /// This runs [pass] followed by shrinking reductions, and then checks that |
142 /// one more run of [pass] does not change the IR. The intermediate shrinking | 133 /// one more run of [pass] does not change the IR. The intermediate shrinking |
143 /// reductions pass is omitted if [pass] itself is shrinking reductions. | 134 /// reductions pass is omitted if [pass] itself is shrinking reductions. |
144 /// | 135 /// |
145 /// If [targetName] is given, functions whose name contains that substring | 136 /// If [targetName] is given, functions whose name contains that substring |
146 /// will be dumped out if the idempotency test fails. | 137 /// will be dumped out if the idempotency test fails. |
147 void debugCpsPass(cps_opt.Pass makePass(), | 138 void debugCpsPass(cps_opt.Pass makePass(), cps.FunctionDefinition cpsFunction, |
148 cps.FunctionDefinition cpsFunction, | 139 [String targetName]) { |
149 [String targetName]) { | |
150 String original = stringify(cpsFunction); | 140 String original = stringify(cpsFunction); |
151 cps_opt.Pass pass = makePass(); | 141 cps_opt.Pass pass = makePass(); |
152 pass.rewrite(cpsFunction); | 142 pass.rewrite(cpsFunction); |
153 assert(checkCpsIntegrity(cpsFunction, pass.passName)); | 143 assert(checkCpsIntegrity(cpsFunction, pass.passName)); |
154 if (pass is! ShrinkingReducer) { | 144 if (pass is! ShrinkingReducer) { |
155 new ShrinkingReducer().rewrite(cpsFunction); | 145 new ShrinkingReducer().rewrite(cpsFunction); |
156 } | 146 } |
157 String before = stringify(cpsFunction); | 147 String before = stringify(cpsFunction); |
158 makePass().rewrite(cpsFunction); | 148 makePass().rewrite(cpsFunction); |
159 String after = stringify(cpsFunction); | 149 String after = stringify(cpsFunction); |
160 if (before != after) { | 150 if (before != after) { |
161 print('SExpression changed for ${cpsFunction.element}'); | 151 print('SExpression changed for ${cpsFunction.element}'); |
162 if (targetName != null && '${cpsFunction.element}'.contains(targetName)) { | 152 if (targetName != null && '${cpsFunction.element}'.contains(targetName)) { |
163 print(original); | 153 print(original); |
164 print('\n-->\n'); | 154 print('\n-->\n'); |
165 print(before); | 155 print(before); |
166 print('\n-->\n'); | 156 print('\n-->\n'); |
167 print(after); | 157 print(after); |
168 compiler.outputProvider('original', 'dump')..add(original)..close(); | 158 compiler.outputProvider('original', 'dump') |
169 compiler.outputProvider('before', 'dump')..add(before)..close(); | 159 ..add(original) |
170 compiler.outputProvider('after', 'dump')..add(after)..close(); | 160 ..close(); |
| 161 compiler.outputProvider('before', 'dump') |
| 162 ..add(before) |
| 163 ..close(); |
| 164 compiler.outputProvider('after', 'dump') |
| 165 ..add(after) |
| 166 ..close(); |
171 } | 167 } |
172 } | 168 } |
173 traceGraph(pass.passName, cpsFunction); | 169 traceGraph(pass.passName, cpsFunction); |
174 dumpTypedIr(pass.passName, cpsFunction); | 170 dumpTypedIr(pass.passName, cpsFunction); |
175 } | 171 } |
176 | 172 |
177 void applyCpsPass(cps_opt.Pass pass, cps.FunctionDefinition cpsFunction) { | 173 void applyCpsPass(cps_opt.Pass pass, cps.FunctionDefinition cpsFunction) { |
178 cpsOptimizationTask.measureSubtask(pass.passName, () { | 174 cpsOptimizationTask.measureSubtask(pass.passName, () { |
179 pass.rewrite(cpsFunction); | 175 pass.rewrite(cpsFunction); |
180 }); | 176 }); |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
223 } else if (type is ForwardingTypeMask) { | 219 } else if (type is ForwardingTypeMask) { |
224 return formatTypeMask(type.forwardTo); | 220 return formatTypeMask(type.forwardTo); |
225 } | 221 } |
226 throw 'unsupported: $type'; | 222 throw 'unsupported: $type'; |
227 } | 223 } |
228 | 224 |
229 void dumpTypedIr(String passName, cps.FunctionDefinition cpsFunction) { | 225 void dumpTypedIr(String passName, cps.FunctionDefinition cpsFunction) { |
230 if (PRINT_TYPED_IR_FILTER != null && | 226 if (PRINT_TYPED_IR_FILTER != null && |
231 PRINT_TYPED_IR_FILTER.matchAsPrefix(cpsFunction.element.name) != null) { | 227 PRINT_TYPED_IR_FILTER.matchAsPrefix(cpsFunction.element.name) != null) { |
232 String printType(nodeOrRef, String s) { | 228 String printType(nodeOrRef, String s) { |
233 cps.Node node = nodeOrRef is cps.Reference | 229 cps.Node node = |
234 ? nodeOrRef.definition | 230 nodeOrRef is cps.Reference ? nodeOrRef.definition : nodeOrRef; |
235 : nodeOrRef; | |
236 return node is cps.Variable && node.type != null | 231 return node is cps.Variable && node.type != null |
237 ? '$s:${formatTypeMask(node.type)}' | 232 ? '$s:${formatTypeMask(node.type)}' |
238 : s; | 233 : s; |
239 } | 234 } |
240 DEBUG_MODE = true; | 235 DEBUG_MODE = true; |
241 print(';;; ==== After $passName ===='); | 236 print(';;; ==== After $passName ===='); |
242 print(new SExpressionStringifier(printType).visit(cpsFunction)); | 237 print(new SExpressionStringifier(printType).visit(cpsFunction)); |
243 } | 238 } |
244 } | 239 } |
245 | 240 |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
287 applyCpsPass(new UpdateRefinements(typeSystem), cpsFunction); | 282 applyCpsPass(new UpdateRefinements(typeSystem), cpsFunction); |
288 applyCpsPass(new ShrinkingReducer(), cpsFunction); | 283 applyCpsPass(new ShrinkingReducer(), cpsFunction); |
289 applyCpsPass(new OptimizeInterceptors(backend, typeSystem), cpsFunction); | 284 applyCpsPass(new OptimizeInterceptors(backend, typeSystem), cpsFunction); |
290 applyCpsPass(new BackwardNullCheckRemover(typeSystem), cpsFunction); | 285 applyCpsPass(new BackwardNullCheckRemover(typeSystem), cpsFunction); |
291 applyCpsPass(new ShrinkingReducer(), cpsFunction); | 286 applyCpsPass(new ShrinkingReducer(), cpsFunction); |
292 }); | 287 }); |
293 } | 288 } |
294 | 289 |
295 tree_ir.FunctionDefinition compileToTreeIr(cps.FunctionDefinition cpsNode) { | 290 tree_ir.FunctionDefinition compileToTreeIr(cps.FunctionDefinition cpsNode) { |
296 applyCpsPass(new Finalize(backend), cpsNode); | 291 applyCpsPass(new Finalize(backend), cpsNode); |
297 tree_builder.Builder builder = new tree_builder.Builder( | 292 tree_builder.Builder builder = |
298 reporter.internalError, glue); | 293 new tree_builder.Builder(reporter.internalError, glue); |
299 tree_ir.FunctionDefinition treeNode = | 294 tree_ir.FunctionDefinition treeNode = |
300 treeBuilderTask.measure(() => builder.buildFunction(cpsNode)); | 295 treeBuilderTask.measure(() => builder.buildFunction(cpsNode)); |
301 assert(treeNode != null); | 296 assert(treeNode != null); |
302 traceGraph('Tree builder', treeNode); | 297 traceGraph('Tree builder', treeNode); |
303 assert(checkTreeIntegrity(treeNode)); | 298 assert(checkTreeIntegrity(treeNode)); |
304 return treeNode; | 299 return treeNode; |
305 } | 300 } |
306 | 301 |
307 bool checkTreeIntegrity(tree_ir.FunctionDefinition node) { | 302 bool checkTreeIntegrity(tree_ir.FunctionDefinition node) { |
308 treeOptimizationTask.measureSubtask('Check integrity', () { | 303 treeOptimizationTask.measureSubtask('Check integrity', () { |
309 new CheckTreeIntegrity().check(node); | 304 new CheckTreeIntegrity().check(node); |
310 }); | 305 }); |
311 return true; // So this can be used from assert(). | 306 return true; // So this can be used from assert(). |
312 } | 307 } |
313 | 308 |
314 tree_ir.FunctionDefinition optimizeTreeIr(tree_ir.FunctionDefinition node) { | 309 tree_ir.FunctionDefinition optimizeTreeIr(tree_ir.FunctionDefinition node) { |
315 void applyTreePass(tree_opt.Pass pass) { | 310 void applyTreePass(tree_opt.Pass pass) { |
316 treeOptimizationTask.measureSubtask(pass.passName, () { | 311 treeOptimizationTask.measureSubtask(pass.passName, () { |
317 pass.rewrite(node); | 312 pass.rewrite(node); |
318 }); | 313 }); |
319 traceGraph(pass.passName, node); | 314 traceGraph(pass.passName, node); |
320 assert(checkTreeIntegrity(node)); | 315 assert(checkTreeIntegrity(node)); |
321 } | 316 } |
322 | 317 |
323 treeOptimizationTask.measure(() { | 318 treeOptimizationTask.measure(() { |
324 applyTreePass(new StatementRewriter()); | 319 applyTreePass(new StatementRewriter()); |
325 applyTreePass(new VariableMerger(minifying: | 320 applyTreePass( |
326 compiler.options.enableMinification)); | 321 new VariableMerger(minifying: compiler.options.enableMinification)); |
327 applyTreePass(new LoopRewriter()); | 322 applyTreePass(new LoopRewriter()); |
328 applyTreePass(new LogicalRewriter()); | 323 applyTreePass(new LogicalRewriter()); |
329 applyTreePass(new PullIntoInitializers()); | 324 applyTreePass(new PullIntoInitializers()); |
330 }); | 325 }); |
331 | 326 |
332 return node; | 327 return node; |
333 } | 328 } |
334 | 329 |
335 js.Fun compileToJavaScript(CodegenWorkItem work, | 330 js.Fun compileToJavaScript( |
336 tree_ir.FunctionDefinition definition) { | 331 CodegenWorkItem work, tree_ir.FunctionDefinition definition) { |
337 CodeGenerator codeGen = new CodeGenerator(glue, work.registry); | 332 CodeGenerator codeGen = new CodeGenerator(glue, work.registry); |
338 Element element = work.element; | 333 Element element = work.element; |
339 js.Fun code = codeGen.buildFunction(definition); | 334 js.Fun code = codeGen.buildFunction(definition); |
340 if (element is FunctionElement && element.asyncMarker != AsyncMarker.SYNC) { | 335 if (element is FunctionElement && element.asyncMarker != AsyncMarker.SYNC) { |
341 code = backend.rewriteAsync(element, code); | 336 code = backend.rewriteAsync(element, code); |
342 work.registry.registerAsyncMarker(element); | 337 work.registry.registerAsyncMarker(element); |
343 } | 338 } |
344 return attachPosition(code, element); | 339 return attachPosition(code, element); |
345 } | 340 } |
346 | 341 |
347 Iterable<CompilerTask> get tasks { | 342 Iterable<CompilerTask> get tasks { |
348 return <CompilerTask>[ | 343 return <CompilerTask>[ |
349 cpsBuilderTask, | 344 cpsBuilderTask, |
350 cpsOptimizationTask, | 345 cpsOptimizationTask, |
351 treeBuilderTask, | 346 treeBuilderTask, |
352 treeOptimizationTask] | 347 treeOptimizationTask |
353 ..addAll(fallbackCompiler.tasks); | 348 ]..addAll(fallbackCompiler.tasks); |
354 } | 349 } |
355 | 350 |
356 js.Node attachPosition(js.Node node, AstElement element) { | 351 js.Node attachPosition(js.Node node, AstElement element) { |
357 return node.withSourceInformation( | 352 return node.withSourceInformation(sourceInformationFactory |
358 sourceInformationFactory.createBuilderForContext(element) | 353 .createBuilderForContext(element) |
359 .buildDeclaration(element)); | 354 .buildDeclaration(element)); |
360 } | 355 } |
361 } | 356 } |
OLD | NEW |