OLD | NEW |
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, 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 library dart2js.cps_ir.scalar_replacement; | 4 library dart2js.cps_ir.scalar_replacement; |
5 | 5 |
6 import 'optimizers.dart'; | 6 import 'optimizers.dart'; |
7 | 7 |
8 import 'dart:collection' show Queue; | 8 import 'dart:collection' show Queue; |
9 | 9 |
10 import '../common.dart'; | 10 import '../common.dart'; |
11 import '../compiler.dart' as dart2js show | 11 import '../compiler.dart' as dart2js show Compiler; |
12 Compiler; | |
13 import '../constants/values.dart'; | 12 import '../constants/values.dart'; |
14 import '../elements/elements.dart'; | 13 import '../elements/elements.dart'; |
15 import '../types/types.dart'; | 14 import '../types/types.dart'; |
16 import '../world.dart' show World; | 15 import '../world.dart' show World; |
17 import 'cps_ir_nodes.dart'; | 16 import 'cps_ir_nodes.dart'; |
18 | 17 |
19 /** | 18 /** |
20 * Replaces aggregates with a set of local values. Performs inlining of | 19 * Replaces aggregates with a set of local values. Performs inlining of |
21 * single-use closures to generate more replaceable aggregates. | 20 * single-use closures to generate more replaceable aggregates. |
22 */ | 21 */ |
(...skipping 14 matching lines...) Expand all Loading... |
37 analyzer.analyze(root); | 36 analyzer.analyze(root); |
38 analyzer.process(); | 37 analyzer.process(); |
39 } | 38 } |
40 } | 39 } |
41 | 40 |
42 /** | 41 /** |
43 * Do scalar replacement of aggregates on instances. Since scalar replacement | 42 * Do scalar replacement of aggregates on instances. Since scalar replacement |
44 * can create new candidates, iterate until all scalar replacements are done. | 43 * can create new candidates, iterate until all scalar replacements are done. |
45 */ | 44 */ |
46 class ScalarReplacementVisitor extends TrampolineRecursiveVisitor { | 45 class ScalarReplacementVisitor extends TrampolineRecursiveVisitor { |
47 | |
48 final InternalErrorFunction internalError; | 46 final InternalErrorFunction internalError; |
49 final World classWorld; | 47 final World classWorld; |
50 ScalarReplacementRemovalVisitor removalVisitor; | 48 ScalarReplacementRemovalVisitor removalVisitor; |
51 | 49 |
52 Primitive _current = null; | 50 Primitive _current = null; |
53 Set<Primitive> _allocations = new Set<Primitive>(); | 51 Set<Primitive> _allocations = new Set<Primitive>(); |
54 Queue<Primitive> _queue = new Queue<Primitive>(); | 52 Queue<Primitive> _queue = new Queue<Primitive>(); |
55 | 53 |
56 ScalarReplacementVisitor(this.internalError, this.classWorld) { | 54 ScalarReplacementVisitor(this.internalError, this.classWorld) { |
57 removalVisitor = new ScalarReplacementRemovalVisitor(this); | 55 removalVisitor = new ScalarReplacementRemovalVisitor(this); |
58 } | 56 } |
59 | 57 |
60 void analyze(FunctionDefinition root) { | 58 void analyze(FunctionDefinition root) { |
61 visit(root); | 59 visit(root); |
62 } | 60 } |
63 | 61 |
64 void process() { | 62 void process() { |
65 while (_queue.isNotEmpty) { | 63 while (_queue.isNotEmpty) { |
66 Primitive allocation = _queue.removeFirst(); | 64 Primitive allocation = _queue.removeFirst(); |
67 _allocations.remove(allocation); | 65 _allocations.remove(allocation); |
68 _current = allocation; | 66 _current = allocation; |
69 tryScalarReplacement(allocation); | 67 tryScalarReplacement(allocation); |
70 } | 68 } |
71 } | 69 } |
72 | 70 |
73 void tryScalarReplacement(Primitive allocation) { | 71 void tryScalarReplacement(Primitive allocation) { |
74 | |
75 // We can do scalar replacement of an aggregate if all uses of an allocation | 72 // We can do scalar replacement of an aggregate if all uses of an allocation |
76 // are reads or writes. | 73 // are reads or writes. |
77 for (Reference ref = allocation.firstRef; ref != null; ref = ref.next) { | 74 for (Reference ref = allocation.firstRef; ref != null; ref = ref.next) { |
78 Node use = ref.parent; | 75 Node use = ref.parent; |
79 if (use is GetField) continue; | 76 if (use is GetField) continue; |
80 if (use is SetField && use.objectRef == ref) continue; | 77 if (use is SetField && use.objectRef == ref) continue; |
81 return; | 78 return; |
82 } | 79 } |
83 | 80 |
84 Set<FieldElement> reads = new Set<FieldElement>(); | 81 Set<FieldElement> reads = new Set<FieldElement>(); |
85 Set<FieldElement> writes = new Set<FieldElement>(); | 82 Set<FieldElement> writes = new Set<FieldElement>(); |
86 for (Reference ref = allocation.firstRef; ref != null; ref = ref.next) { | 83 for (Reference ref = allocation.firstRef; ref != null; ref = ref.next) { |
87 Node use = ref.parent; | 84 Node use = ref.parent; |
88 if (use is GetField) { | 85 if (use is GetField) { |
89 reads.add(use.field); | 86 reads.add(use.field); |
90 } else if (use is SetField) { | 87 } else if (use is SetField) { |
91 writes.add(use.field); | 88 writes.add(use.field); |
92 } else { | 89 } else { |
93 assert(false); | 90 assert(false); |
94 } | 91 } |
95 } | 92 } |
96 | 93 |
97 // Find the initial values of the fields. A CreateBox has no initial | 94 // Find the initial values of the fields. A CreateBox has no initial |
98 // values. CreateInstance has initial values in the order of the fields. | 95 // values. CreateInstance has initial values in the order of the fields. |
99 Map<FieldElement, Primitive> fieldInitialValues = | 96 Map<FieldElement, Primitive> fieldInitialValues = |
100 <FieldElement, Primitive>{}; | 97 <FieldElement, Primitive>{}; |
101 if (allocation is CreateInstance) { | 98 if (allocation is CreateInstance) { |
102 int i = 0; | 99 int i = 0; |
103 allocation.classElement.forEachInstanceField( | 100 allocation.classElement.forEachInstanceField( |
104 (ClassElement enclosingClass, FieldElement field) { | 101 (ClassElement enclosingClass, FieldElement field) { |
105 Primitive argument = allocation.argument(i++); | 102 Primitive argument = allocation.argument(i++); |
106 fieldInitialValues[field] = argument; | 103 fieldInitialValues[field] = argument; |
107 }, | 104 }, includeSuperAndInjectedMembers: true); |
108 includeSuperAndInjectedMembers: true); | |
109 } | 105 } |
110 | 106 |
111 // Create [MutableVariable]s for each written field. Initialize the | 107 // Create [MutableVariable]s for each written field. Initialize the |
112 // MutableVariable with the value from the allocator, or initialize with a | 108 // MutableVariable with the value from the allocator, or initialize with a |
113 // `null` constant if there is not initial value. | 109 // `null` constant if there is not initial value. |
114 Map<FieldElement, MutableVariable> cells = | 110 Map<FieldElement, MutableVariable> cells = |
115 <FieldElement, MutableVariable>{}; | 111 <FieldElement, MutableVariable>{}; |
116 InteriorNode insertionPoint = allocation.parent; // LetPrim | 112 InteriorNode insertionPoint = allocation.parent; // LetPrim |
117 for (FieldElement field in writes) { | 113 for (FieldElement field in writes) { |
118 MutableVariable variable = new MutableVariable(field); | 114 MutableVariable variable = new MutableVariable(field); |
119 variable.type = new TypeMask.nonNullEmpty(); | 115 variable.type = new TypeMask.nonNullEmpty(); |
120 cells[field] = variable; | 116 cells[field] = variable; |
121 Primitive initialValue = fieldInitialValues[field]; | 117 Primitive initialValue = fieldInitialValues[field]; |
122 if (initialValue == null) { | 118 if (initialValue == null) { |
123 assert(allocation is CreateBox); | 119 assert(allocation is CreateBox); |
124 initialValue = new Constant(new NullConstantValue()); | 120 initialValue = new Constant(new NullConstantValue()); |
125 LetPrim let = new LetPrim(initialValue); | 121 LetPrim let = new LetPrim(initialValue); |
126 let.primitive.parent = let; | 122 let.primitive.parent = let; |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
207 // -------------------------- Visitor overrides ------------------------------ | 203 // -------------------------- Visitor overrides ------------------------------ |
208 void visitCreateInstance(CreateInstance node) { | 204 void visitCreateInstance(CreateInstance node) { |
209 enqueue(node); | 205 enqueue(node); |
210 } | 206 } |
211 | 207 |
212 void visitCreateBox(CreateBox node) { | 208 void visitCreateBox(CreateBox node) { |
213 enqueue(node); | 209 enqueue(node); |
214 } | 210 } |
215 } | 211 } |
216 | 212 |
217 | |
218 /// Visit a just-deleted subterm and unlink all [Reference]s in it. Reconsider | 213 /// Visit a just-deleted subterm and unlink all [Reference]s in it. Reconsider |
219 /// allocations for scalar replacement. | 214 /// allocations for scalar replacement. |
220 class ScalarReplacementRemovalVisitor extends TrampolineRecursiveVisitor { | 215 class ScalarReplacementRemovalVisitor extends TrampolineRecursiveVisitor { |
221 ScalarReplacementVisitor process; | 216 ScalarReplacementVisitor process; |
222 | 217 |
223 ScalarReplacementRemovalVisitor(this.process); | 218 ScalarReplacementRemovalVisitor(this.process); |
224 | 219 |
225 processReference(Reference reference) { | 220 processReference(Reference reference) { |
226 process.reconsider(reference.definition); | 221 process.reconsider(reference.definition); |
227 reference.unlink(); | 222 reference.unlink(); |
228 } | 223 } |
229 } | 224 } |
OLD | NEW |