Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(84)

Unified Diff: pkg/compiler/lib/src/cps_ir/use_field_initializers.dart

Issue 1671073002: dart2js cps: Pull SetFields into field initializer arguments. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « pkg/compiler/lib/src/cps_ir/optimizers.dart ('k') | pkg/compiler/lib/src/js_backend/codegen/task.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pkg/compiler/lib/src/cps_ir/use_field_initializers.dart
diff --git a/pkg/compiler/lib/src/cps_ir/use_field_initializers.dart b/pkg/compiler/lib/src/cps_ir/use_field_initializers.dart
new file mode 100644
index 0000000000000000000000000000000000000000..99c1ef88fa88aefef8a2f11fd254b2491c1011bf
--- /dev/null
+++ b/pkg/compiler/lib/src/cps_ir/use_field_initializers.dart
@@ -0,0 +1,180 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+library dart2js.cps_ir.use_field_initializers;
+
+import 'cps_ir_nodes.dart';
+import 'optimizers.dart';
+import '../elements/elements.dart';
+
+/// Eliminates [SetField] instructions when the value can instead be passed into
+/// the field initializer of a [CreateInstance] instruction.
+///
+/// This compensates for a somewhat common pattern where fields are initialized
+/// in the constructor body instead of using intializers. For example:
+///
+/// class Foo {
+/// var x, y;
+/// Foo(x, y) {
+/// this.x = x;
+/// this.y = y;
+/// }
+/// }
+///
+/// ==> (IR for Foo constructor)
+///
+/// foo = new D.Foo(null, null);
+/// foo.x = 'a';
+/// foo.y = 'b';
+///
+/// ==> (after this pass)
+///
+/// foo = new D.Foo('a', 'b');
+//
+// TODO(asgerf): Store forwarding and load elimination could most likely
+// handle this more generally.
+//
+class UseFieldInitializers extends BlockVisitor implements Pass {
+ String get passName => 'Use field initializers';
+
+ final Set<CreateInstance> unescaped = new Set<CreateInstance>();
+
+ /// Continuation bindings separating the current traversal position from an
+ /// unescaped [CreateInstance]. When [CreateInstance] is sunk, these
+ /// continuations must sink as well to ensure the object remains in scope
+ /// inside the bound continuations.
+ final List<LetCont> letConts = <LetCont>[];
+
+ /// If non-null, the bindings in [letConts] should sink to immediately below
+ /// this node.
+ InteriorNode letContSinkTarget = null;
+ EscapeVisitor escapeVisitor;
+
+ void rewrite(FunctionDefinition node) {
+ escapeVisitor = new EscapeVisitor(this);
+ BlockVisitor.traverseInPreOrder(node, this);
+ }
+
+ void escape(Reference ref) {
+ Definition def = ref.definition;
+ if (def is CreateInstance) {
+ unescaped.remove(def);
+ }
+ }
+
+ void visitLetCont(LetCont node) {
+ if (unescaped.isNotEmpty) {
+ letConts.add(node);
+ }
+ }
+
+ void visitContinuation(Continuation node) {
+ endBasicBlock();
+ }
+ void visitLetHandler(LetHandler node) {
+ endBasicBlock();
+ }
+ void visitInvokeContinuation(InvokeContinuation node) {
+ endBasicBlock();
+ }
+ void visitBranch(Branch node) {
+ endBasicBlock();
+ }
+ void visitRethrow(Rethrow node) {
+ endBasicBlock();
+ }
+ void visitThrow(Throw node) {
+ endBasicBlock();
+ }
+ void visitUnreachable(Unreachable node) {
+ endBasicBlock();
+ }
+
+ void visitLetMutable(LetMutable node) {
+ escape(node.value);
+ }
+
+ void endBasicBlock() {
+ if (letContSinkTarget != null) {
+ for (LetCont letCont in letConts.reversed) {
+ letCont..remove()..insertBelow(letContSinkTarget);
+ }
+ }
+ unescaped.clear();
+ letConts.clear();
+ letContSinkTarget = null;
+ }
+
+ void visitLetPrim(LetPrim node) {
+ Primitive prim = node.primitive;
+ if (prim is CreateInstance) {
+ unescaped.add(prim);
+ prim.arguments.forEach(escape);
+ return;
+ }
+ if (unescaped.isEmpty) return;
+ if (prim is SetField) {
+ escape(prim.value);
+ Primitive object = prim.object.definition;
+ if (object is CreateInstance && unescaped.contains(object)) {
+ // Replace the field initializer with the new value. There are no uses
+ // 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.
+ int index = getFieldIndex(object.classElement, prim.field);
+ object.arguments[index].changeTo(prim.value.definition);
+ prim.destroy();
+ // The right-hand side might not be in scope at the CreateInstance.
+ // Sink the creation down to this point.
+ rebindCreateInstanceAt(object, node);
+ letContSinkTarget = node;
+ }
+ return;
+ }
+ if (prim is GetField) {
+ // When reading the field of a newly created object, just use the initial
+ // value and destroy the GetField. This can unblock the other optimization
+ // since we remove a use of the object.
+ Primitive object = prim.object.definition;
+ if (object is CreateInstance && unescaped.contains(object)) {
+ int index = getFieldIndex(object.classElement, prim.field);
+ prim.replaceUsesWith(object.arguments[index].definition);
+ prim.destroy();
+ node.remove();
+ }
+ return;
+ }
+ escapeVisitor.visit(node.primitive);
+ }
+
+ void rebindCreateInstanceAt(CreateInstance prim, LetPrim newBinding) {
+ removeBinding(prim);
+ newBinding.primitive = prim;
+ prim.parent = newBinding;
+ }
+
+ int getFieldIndex(ClassElement classElement, FieldElement field) {
+ // There is no stored map from a field to its index in a given class, so we
+ // have to iterate over all instance fields until we find it.
+ int current = -1, index = -1;
+ classElement.forEachInstanceField((host, currentField) {
+ ++current;
+ if (currentField == field) {
+ index = current;
+ }
+ }, includeSuperAndInjectedMembers: true);
+ return index;
+ }
+
+ void removeBinding(Primitive prim) {
+ LetPrim node = prim.parent;
+ node.remove();
+ }
+}
+
+class EscapeVisitor extends DeepRecursiveVisitor {
+ final UseFieldInitializers main;
+ EscapeVisitor(this.main);
+
+ processReference(Reference ref) {
+ main.escape(ref);
+ }
+}
« no previous file with comments | « pkg/compiler/lib/src/cps_ir/optimizers.dart ('k') | pkg/compiler/lib/src/js_backend/codegen/task.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698