Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 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 | |
| 3 // BSD-style license that can be found in the LICENSE file. | |
| 4 | |
| 5 import 'optimizers.dart'; | |
| 6 | |
| 7 import 'dart:collection' show Queue; | |
| 8 | |
| 9 import '../closure.dart' show | |
| 10 ClosureClassElement, Identifiers; | |
| 11 import '../common/names.dart' show | |
| 12 Selectors, Identifiers; | |
| 13 import '../compiler.dart' as dart2js show | |
| 14 Compiler; | |
| 15 import '../constants/constant_system.dart'; | |
| 16 import '../constants/values.dart'; | |
| 17 import '../dart_types.dart' as types; | |
| 18 import '../diagnostics/invariant.dart' as dart2js show | |
| 19 InternalErrorFunction; | |
| 20 import '../elements/elements.dart'; | |
| 21 import '../io/source_information.dart' show SourceInformation; | |
| 22 import '../resolution/access_semantics.dart'; | |
| 23 import '../resolution/operators.dart'; | |
| 24 import '../resolution/send_structure.dart'; | |
| 25 import '../tree/tree.dart' as ast; | |
| 26 import '../types/types.dart'; | |
| 27 import '../types/constants.dart' show computeTypeMask; | |
| 28 import '../universe/universe.dart'; | |
| 29 import '../world.dart' show World; | |
| 30 import 'cps_fragment.dart'; | |
| 31 import 'cps_ir_nodes.dart'; | |
| 32 import 'cps_ir_nodes_sexpr.dart' show SExpressionStringifier; | |
| 33 | |
| 34 /** | |
| 35 * Replaces aggregates with a set of local values. Performs inlining of | |
| 36 * single-use closures to generate more replacable aggregates. | |
| 37 */ | |
| 38 class ScalarReplacer extends Pass { | |
| 39 String get passName => 'Scalar replacement'; | |
| 40 | |
| 41 final dart2js.InternalErrorFunction _internalError; | |
| 42 | |
| 43 ScalarReplacer(dart2js.Compiler compiler) | |
| 44 : _internalError = compiler.internalError; | |
| 45 | |
| 46 @override | |
| 47 void rewrite(FunctionDefinition root) { | |
| 48 // Set all parent pointers. | |
| 49 new ParentVisitor().visit(root); | |
| 50 ScalarReplacementVisitor analyzer = | |
| 51 new ScalarReplacementVisitor(_internalError); | |
| 52 analyzer.analyze(root); | |
| 53 analyzer.process(); | |
| 54 } | |
| 55 } | |
| 56 | |
| 57 /** | |
| 58 * Do scalar replacement of aggregates on instances. Since scalar replacement | |
| 59 * can create new candidiates, iterate until all scalar replacements are done. | |
| 60 */ | |
| 61 class ScalarReplacementVisitor extends RecursiveVisitor { | |
| 62 | |
| 63 final dart2js.InternalErrorFunction internalError; | |
| 64 ScalarReplacementRemovalVisitor removalVisitor; | |
| 65 | |
| 66 Primitive _current = null; | |
| 67 Set<Primitive> _allocations = new Set<Primitive>(); | |
| 68 Queue<Primitive> _queue = new Queue<Primitive>(); | |
| 69 | |
| 70 ScalarReplacementVisitor(this.internalError) { | |
| 71 removalVisitor = new ScalarReplacementRemovalVisitor(this); | |
| 72 } | |
| 73 | |
| 74 void analyze(FunctionDefinition root) { | |
| 75 visit(root); | |
| 76 } | |
| 77 | |
| 78 void process() { | |
| 79 while (_queue.isNotEmpty) { | |
| 80 Primitive allocation = _queue.removeFirst(); | |
| 81 _allocations.remove(allocation); | |
| 82 _current = allocation; | |
| 83 tryScalarReplacement(allocation); | |
| 84 } | |
| 85 } | |
| 86 | |
| 87 void tryScalarReplacement(Primitive allocation) { | |
| 88 | |
| 89 // We can do scalar replacement of an aggregate if all uses of an allocation | |
| 90 // are reads or writes. | |
| 91 for (Reference ref = allocation.firstRef; ref != null; ref = ref.next) { | |
| 92 Node use = ref.parent; | |
| 93 if (use is GetField) continue; | |
| 94 if (use is SetField && use.object == ref) continue; | |
| 95 return; | |
| 96 } | |
| 97 | |
| 98 Set<FieldElement> reads = new Set<FieldElement>(); | |
| 99 Set<FieldElement> writes = new Set<FieldElement>(); | |
| 100 for (Reference ref = allocation.firstRef; ref != null; ref = ref.next) { | |
| 101 Node use = ref.parent; | |
| 102 if (use is GetField) { | |
| 103 reads.add(use.field); | |
| 104 } else { | |
| 105 writes.add(use.field); | |
| 106 } | |
| 107 } | |
| 108 | |
| 109 // Find the initial values of the fields. A CreateBox has no initial | |
| 110 // values. CreateInstance has initial values in the order of the fields. | |
| 111 Map<FieldElement, Primitive> fieldInitialValues = | |
| 112 <FieldElement, Primitive>{}; | |
| 113 if (allocation is CreateInstance) { | |
| 114 int i = 0; | |
| 115 allocation.classElement.forEachInstanceField( | |
| 116 (ClassElement enclosingClass, FieldElement field) { | |
| 117 Primitive argument = allocation.arguments[i++].definition; | |
| 118 fieldInitialValues[field] = argument; | |
| 119 }); | |
| 120 } | |
| 121 | |
| 122 // Create [MutableVariable]s for each written field. Initialize the | |
| 123 // MutableVariable with the value from the allocator, or initialize with a | |
| 124 // `null` constant if there is not initial value. | |
| 125 Map<FieldElement, MutableVariable> cells = <FieldElement, MutableVariable>{} ; | |
|
asgerf
2015/08/31 09:57:30
long line :(
sra1
2015/09/02 01:12:57
Done.
| |
| 126 InteriorNode insertionPoint = allocation.parent; // LetPrim | |
| 127 for (FieldElement field in writes) { | |
| 128 MutableVariable variable = new MutableVariable(field); | |
| 129 cells[field] = variable; | |
| 130 Primitive initialValue = fieldInitialValues[field]; | |
| 131 if (initialValue == null) { | |
| 132 assert(allocation is CreateBox); | |
| 133 initialValue = new Constant(new NullConstantValue()); | |
| 134 LetPrim let = new LetPrim(initialValue); | |
| 135 let.primitive.parent = let; | |
| 136 insertionPoint = insertAtBody(insertionPoint, let); | |
| 137 } | |
| 138 LetMutable let = new LetMutable(variable, initialValue); | |
| 139 let.value.parent = let; | |
| 140 insertionPoint = insertAtBody(insertionPoint, let); | |
| 141 } | |
| 142 | |
| 143 // Replace references with MutableVariable operations or references to the | |
| 144 // field's value. | |
| 145 for (Reference ref = allocation.firstRef; ref != null; ref = ref.next) { | |
| 146 Node use = ref.parent; | |
| 147 if (use is GetField) { | |
| 148 GetField getField = use; | |
| 149 MutableVariable variable = cells[getField.field]; | |
| 150 if (variable != null) { | |
| 151 GetMutable getter = new GetMutable(variable); | |
| 152 getter.variable.parent = getter; | |
| 153 getter.substituteFor(getField); | |
| 154 getField.parent.primitive = getter; // Replace primitive of LetPrim. | |
| 155 deletePrimitive(getField); | |
| 156 } else { | |
| 157 Primitive value = fieldInitialValues[getField.field]; | |
| 158 value.substituteFor(getField); | |
| 159 deleteLetPrimOf(getField); | |
| 160 } | |
| 161 } else if (use is SetField && use.object == ref) { | |
| 162 SetField setField = use; | |
| 163 MutableVariable variable = cells[setField.field]; | |
| 164 Primitive value = setField.value.definition; | |
| 165 SetMutable setter = new SetMutable(variable, value); | |
| 166 setter.variable.parent = setter; | |
| 167 setter.value.parent = setter; | |
| 168 setter.substituteFor(setField); | |
| 169 setField.parent.primitive = setter; // Replace primitive of LetPrim. | |
| 170 deletePrimitive(setField); | |
| 171 } else { | |
| 172 throw 'unexpected use: $use'; | |
| 173 } | |
| 174 } | |
| 175 | |
| 176 // Delete [allocation] since that might 'free' another scalar replacement | |
| 177 // candidate by deleting the last non-field-access. | |
| 178 deleteLetPrimOf(allocation); | |
| 179 } | |
| 180 | |
| 181 InteriorNode insertAtBody(InteriorNode insertionPoint, InteriorNode let) { | |
| 182 let.parent = insertionPoint; | |
| 183 let.body = insertionPoint.body; | |
| 184 let.body.parent = let; | |
| 185 insertionPoint.body = let; | |
| 186 return let; | |
| 187 } | |
| 188 | |
| 189 void deleteLetPrimOf(Primitive primitive) { | |
| 190 assert(primitive.hasNoUses); | |
| 191 LetPrim letPrim = primitive.parent; | |
| 192 Node child = letPrim.body; | |
| 193 InteriorNode parent = letPrim.parent; | |
| 194 child.parent = parent; | |
| 195 parent.body = child; | |
| 196 | |
| 197 deletePrimitive(primitive); | |
| 198 } | |
| 199 | |
| 200 void deletePrimitive(Primitive primitive) { | |
| 201 assert(primitive.hasNoUses); | |
| 202 removalVisitor.visit(primitive); | |
| 203 } | |
| 204 | |
| 205 void reconsider(Definition node) { | |
| 206 if (node is CreateInstance || node is CreateBox) { | |
| 207 if (node == _current) return; | |
| 208 print('reconsider $node'); | |
|
asgerf
2015/08/31 09:57:30
Stray print call
sra1
2015/09/02 01:12:57
Done.
| |
| 209 enqueue(node); | |
| 210 } | |
| 211 } | |
| 212 | |
| 213 void enqueue(Primitive node) { | |
| 214 assert(node is CreateInstance || node is CreateBox); | |
| 215 if (_allocations.contains(node)) return; | |
| 216 _allocations.add(node); | |
| 217 _queue.add(node); | |
| 218 } | |
| 219 | |
| 220 // -------------------------- Visitor overrides ------------------------------ | |
| 221 void visit(Node node) { node.accept(this); } | |
|
asgerf
2015/08/31 09:57:30
The visit method is not necessary when extending R
sra1
2015/09/02 01:12:57
Done.
| |
| 222 | |
| 223 void visitCreateInstance(CreateInstance node) { | |
| 224 enqueue(node); | |
| 225 } | |
| 226 | |
| 227 void visitCreateBox(CreateBox node) { | |
| 228 enqueue(node); | |
| 229 } | |
| 230 } | |
| 231 | |
| 232 | |
| 233 /// Visit a just-deleted subterm and unlink all [Reference]s in it. Reconsider | |
| 234 /// allocations for sclara replacement. | |
|
asgerf
2015/08/31 09:57:30
sclara -> scalar
sra1
2015/09/02 01:12:57
Done.
| |
| 235 class ScalarReplacementRemovalVisitor extends RecursiveVisitor { | |
| 236 ScalarReplacementVisitor process; | |
| 237 | |
| 238 ScalarReplacementRemovalVisitor(this.process); | |
| 239 | |
| 240 processReference(Reference reference) { | |
| 241 process.reconsider(reference.definition); | |
| 242 reference.unlink(); | |
| 243 } | |
| 244 } | |
| OLD | NEW |