| 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 |