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 if (use is SetField) { |
| 105 writes.add(use.field); |
| 106 } else { |
| 107 assert(false); |
| 108 } |
| 109 } |
| 110 |
| 111 // Find the initial values of the fields. A CreateBox has no initial |
| 112 // values. CreateInstance has initial values in the order of the fields. |
| 113 Map<FieldElement, Primitive> fieldInitialValues = |
| 114 <FieldElement, Primitive>{}; |
| 115 if (allocation is CreateInstance) { |
| 116 int i = 0; |
| 117 allocation.classElement.forEachInstanceField( |
| 118 (ClassElement enclosingClass, FieldElement field) { |
| 119 Primitive argument = allocation.arguments[i++].definition; |
| 120 fieldInitialValues[field] = argument; |
| 121 }); |
| 122 } |
| 123 |
| 124 // Create [MutableVariable]s for each written field. Initialize the |
| 125 // MutableVariable with the value from the allocator, or initialize with a |
| 126 // `null` constant if there is not initial value. |
| 127 Map<FieldElement, MutableVariable> cells = |
| 128 <FieldElement, MutableVariable>{}; |
| 129 InteriorNode insertionPoint = allocation.parent; // LetPrim |
| 130 for (FieldElement field in writes) { |
| 131 MutableVariable variable = new MutableVariable(field); |
| 132 cells[field] = variable; |
| 133 Primitive initialValue = fieldInitialValues[field]; |
| 134 if (initialValue == null) { |
| 135 assert(allocation is CreateBox); |
| 136 initialValue = new Constant(new NullConstantValue()); |
| 137 LetPrim let = new LetPrim(initialValue); |
| 138 let.primitive.parent = let; |
| 139 insertionPoint = insertAtBody(insertionPoint, let); |
| 140 } |
| 141 LetMutable let = new LetMutable(variable, initialValue); |
| 142 let.value.parent = let; |
| 143 insertionPoint = insertAtBody(insertionPoint, let); |
| 144 } |
| 145 |
| 146 // Replace references with MutableVariable operations or references to the |
| 147 // field's value. |
| 148 for (Reference ref = allocation.firstRef; ref != null; ref = ref.next) { |
| 149 Node use = ref.parent; |
| 150 if (use is GetField) { |
| 151 GetField getField = use; |
| 152 MutableVariable variable = cells[getField.field]; |
| 153 if (variable != null) { |
| 154 GetMutable getter = new GetMutable(variable); |
| 155 getter.variable.parent = getter; |
| 156 getter.substituteFor(getField); |
| 157 replacePrimitive(getField, getter); |
| 158 deletePrimitive(getField); |
| 159 } else { |
| 160 Primitive value = fieldInitialValues[getField.field]; |
| 161 value.substituteFor(getField); |
| 162 deleteLetPrimOf(getField); |
| 163 } |
| 164 } else if (use is SetField && use.object == ref) { |
| 165 SetField setField = use; |
| 166 MutableVariable variable = cells[setField.field]; |
| 167 Primitive value = setField.value.definition; |
| 168 SetMutable setter = new SetMutable(variable, value); |
| 169 setter.variable.parent = setter; |
| 170 setter.value.parent = setter; |
| 171 setter.substituteFor(setField); |
| 172 replacePrimitive(setField, setter); |
| 173 deletePrimitive(setField); |
| 174 } else { |
| 175 assert(false); |
| 176 } |
| 177 } |
| 178 |
| 179 // Delete [allocation] since that might 'free' another scalar replacement |
| 180 // candidate by deleting the last non-field-access. |
| 181 deleteLetPrimOf(allocation); |
| 182 } |
| 183 |
| 184 InteriorNode insertAtBody( |
| 185 InteriorNode insertionPoint, InteriorExpression let) { |
| 186 let.parent = insertionPoint; |
| 187 let.body = insertionPoint.body; |
| 188 let.body.parent = let; |
| 189 insertionPoint.body = let; |
| 190 return let; |
| 191 } |
| 192 |
| 193 /// Replaces [old] with [primitive] in [old]'s parent [LetPrim]. |
| 194 void replacePrimitive(Primitive old, Primitive primitive) { |
| 195 LetPrim letPrim = old.parent; |
| 196 letPrim.primitive = primitive; |
| 197 } |
| 198 |
| 199 void deleteLetPrimOf(Primitive primitive) { |
| 200 assert(primitive.hasNoUses); |
| 201 LetPrim letPrim = primitive.parent; |
| 202 Node child = letPrim.body; |
| 203 InteriorNode parent = letPrim.parent; |
| 204 child.parent = parent; |
| 205 parent.body = child; |
| 206 |
| 207 deletePrimitive(primitive); |
| 208 } |
| 209 |
| 210 void deletePrimitive(Primitive primitive) { |
| 211 assert(primitive.hasNoUses); |
| 212 removalVisitor.visit(primitive); |
| 213 } |
| 214 |
| 215 void reconsider(Definition node) { |
| 216 if (node is CreateInstance || node is CreateBox) { |
| 217 if (node == _current) return; |
| 218 enqueue(node); |
| 219 } |
| 220 } |
| 221 |
| 222 void enqueue(Primitive node) { |
| 223 assert(node is CreateInstance || node is CreateBox); |
| 224 if (_allocations.contains(node)) return; |
| 225 _allocations.add(node); |
| 226 _queue.add(node); |
| 227 } |
| 228 |
| 229 // -------------------------- Visitor overrides ------------------------------ |
| 230 void visitCreateInstance(CreateInstance node) { |
| 231 enqueue(node); |
| 232 } |
| 233 |
| 234 void visitCreateBox(CreateBox node) { |
| 235 enqueue(node); |
| 236 } |
| 237 } |
| 238 |
| 239 |
| 240 /// Visit a just-deleted subterm and unlink all [Reference]s in it. Reconsider |
| 241 /// allocations for scalar replacement. |
| 242 class ScalarReplacementRemovalVisitor extends RecursiveVisitor { |
| 243 ScalarReplacementVisitor process; |
| 244 |
| 245 ScalarReplacementRemovalVisitor(this.process); |
| 246 |
| 247 processReference(Reference reference) { |
| 248 process.reconsider(reference.definition); |
| 249 reference.unlink(); |
| 250 } |
| 251 } |
OLD | NEW |