Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright (c) 2016, 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 library dart2js.cps_ir.use_field_initializers; | |
| 5 | |
| 6 import 'cps_ir_nodes.dart'; | |
| 7 import 'optimizers.dart'; | |
| 8 import '../elements/elements.dart'; | |
| 9 | |
| 10 /// Eliminates [SetField] instructions when the value can instead be passed into | |
| 11 /// the field initializer of a [CreateInstance] instruction. | |
| 12 /// | |
| 13 /// This compensates for a somewhat common pattern where fields are initialized | |
| 14 /// in the constructor body instead of using intializers. For example: | |
| 15 /// | |
| 16 /// class Foo { | |
| 17 /// var x, y; | |
| 18 /// Foo(x, y) { | |
| 19 /// this.x = x; | |
| 20 /// this.y = y; | |
| 21 /// } | |
| 22 /// } | |
| 23 /// | |
| 24 /// ==> (IR for Foo constructor) | |
| 25 /// | |
| 26 /// foo = new D.Foo(null, null); | |
| 27 /// foo.x = 'a'; | |
| 28 /// foo.y = 'b'; | |
| 29 /// | |
| 30 /// ==> (after this pass) | |
| 31 /// | |
| 32 /// foo = new D.Foo('a', 'b'); | |
| 33 // | |
| 34 // TODO(asgerf): Store forwarding and load elimination could most likely | |
| 35 // handle this more generally. | |
| 36 // | |
| 37 class UseFieldInitializers extends BlockVisitor implements Pass { | |
| 38 String get passName => 'Use field initializers'; | |
| 39 | |
| 40 final Set<CreateInstance> unescaped = new Set<CreateInstance>(); | |
| 41 | |
| 42 /// Continuation bindings separating the current traversal position from an | |
| 43 /// unescaped [CreateInstance]. When [CreateInstance] is sunk, these | |
| 44 /// continuations must sink as well to ensure the object remains in scope | |
| 45 /// inside the bound continuations. | |
| 46 final List<LetCont> letConts = <LetCont>[]; | |
| 47 | |
| 48 /// If non-null, the bindings in [letConts] should sink to immediately below | |
| 49 /// this node. | |
| 50 InteriorNode letContSinkTarget = null; | |
| 51 EscapeVisitor escapeVisitor; | |
| 52 | |
| 53 void rewrite(FunctionDefinition node) { | |
| 54 escapeVisitor = new EscapeVisitor(this); | |
| 55 BlockVisitor.traverseInPreOrder(node, this); | |
| 56 } | |
| 57 | |
| 58 void escape(Reference ref) { | |
| 59 Definition def = ref.definition; | |
| 60 if (def is CreateInstance) { | |
| 61 unescaped.remove(def); | |
| 62 } | |
| 63 } | |
| 64 | |
| 65 void visitLetCont(LetCont node) { | |
| 66 if (unescaped.isNotEmpty) { | |
| 67 letConts.add(node); | |
| 68 } | |
| 69 } | |
| 70 | |
| 71 void visitContinuation(Continuation node) { | |
| 72 endBasicBlock(); | |
| 73 } | |
| 74 void visitLetHandler(LetHandler node) { | |
| 75 endBasicBlock(); | |
| 76 } | |
| 77 void visitInvokeContinuation(InvokeContinuation node) { | |
| 78 endBasicBlock(); | |
| 79 } | |
| 80 void visitBranch(Branch node) { | |
| 81 endBasicBlock(); | |
| 82 } | |
| 83 void visitRethrow(Rethrow node) { | |
| 84 endBasicBlock(); | |
| 85 } | |
| 86 void visitThrow(Throw node) { | |
| 87 endBasicBlock(); | |
| 88 } | |
| 89 void visitUnreachable(Unreachable node) { | |
| 90 endBasicBlock(); | |
| 91 } | |
| 92 | |
| 93 void visitLetMutable(LetMutable node) { | |
| 94 escape(node.value); | |
| 95 } | |
| 96 | |
| 97 void endBasicBlock() { | |
| 98 if (letContSinkTarget != null) { | |
| 99 for (LetCont letCont in letConts.reversed) { | |
| 100 letCont..remove()..insertBelow(letContSinkTarget); | |
| 101 } | |
| 102 } | |
| 103 unescaped.clear(); | |
| 104 letConts.clear(); | |
| 105 letContSinkTarget = null; | |
| 106 } | |
| 107 | |
| 108 void visitLetPrim(LetPrim node) { | |
| 109 Primitive prim = node.primitive; | |
| 110 if (prim is CreateInstance) { | |
| 111 unescaped.add(prim); | |
| 112 prim.arguments.forEach(escape); | |
| 113 return; | |
| 114 } | |
| 115 if (unescaped.isEmpty) return; | |
| 116 if (prim is SetField) { | |
| 117 escape(prim.value); | |
| 118 Primitive object = prim.object.definition; | |
| 119 if (object is CreateInstance && unescaped.contains(object)) { | |
| 120 // Replace the field initializer with the new value. There are no uses | |
| 121 // of the object before this, so the old value cannot have been seen. | |
|
Siggi Cherem (dart-lang)
2016/02/05 18:46:39
I'm assuming it doesn't matter if the old value is
asgerf
2016/02/08 18:46:46
That's right.
| |
| 122 int index = getFieldIndex(object.classElement, prim.field); | |
| 123 object.arguments[index].changeTo(prim.value.definition); | |
| 124 prim.destroy(); | |
| 125 // The right-hand side might not be in scope at the CreateInstance. | |
| 126 // Sink the creation down to this point. | |
| 127 rebindCreateInstanceAt(object, node); | |
| 128 letContSinkTarget = node; | |
| 129 } | |
| 130 return; | |
| 131 } | |
| 132 if (prim is GetField) { | |
| 133 // When reading the field of a newly created object, just use the initial | |
| 134 // value and destroy the GetField. This can unblock the other optimization | |
| 135 // since we remove a use of the object. | |
| 136 Primitive object = prim.object.definition; | |
| 137 if (object is CreateInstance && unescaped.contains(object)) { | |
| 138 int index = getFieldIndex(object.classElement, prim.field); | |
| 139 prim.replaceUsesWith(object.arguments[index].definition); | |
| 140 prim.destroy(); | |
| 141 node.remove(); | |
| 142 } | |
| 143 return; | |
| 144 } | |
| 145 escapeVisitor.visit(node.primitive); | |
| 146 } | |
| 147 | |
| 148 void rebindCreateInstanceAt(CreateInstance prim, LetPrim newBinding) { | |
| 149 removeBinding(prim); | |
| 150 newBinding.primitive = prim; | |
| 151 prim.parent = newBinding; | |
| 152 } | |
| 153 | |
| 154 int getFieldIndex(ClassElement classElement, FieldElement field) { | |
| 155 // There is no stored map from a field to its index in a given class, so we | |
| 156 // have to iterate over all instance fields until we find it. | |
| 157 int current = -1, index = -1; | |
| 158 classElement.forEachInstanceField((host, currentField) { | |
| 159 ++current; | |
| 160 if (currentField == field) { | |
| 161 index = current; | |
| 162 } | |
| 163 }, includeSuperAndInjectedMembers: true); | |
| 164 return index; | |
| 165 } | |
| 166 | |
| 167 void removeBinding(Primitive prim) { | |
| 168 LetPrim node = prim.parent; | |
| 169 node.remove(); | |
| 170 } | |
| 171 } | |
| 172 | |
| 173 class EscapeVisitor extends DeepRecursiveVisitor { | |
| 174 final UseFieldInitializers main; | |
| 175 EscapeVisitor(this.main); | |
| 176 | |
| 177 processReference(Reference ref) { | |
| 178 main.escape(ref); | |
| 179 } | |
| 180 } | |
| OLD | NEW |