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

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

Issue 1319303002: dart2js cps: Scalar replacement of aggregates (Closed) Base URL: https://github.com/dart-lang/sdk.git@master
Patch Set: Created 5 years, 4 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/scalar_replacement.dart
diff --git a/pkg/compiler/lib/src/cps_ir/scalar_replacement.dart b/pkg/compiler/lib/src/cps_ir/scalar_replacement.dart
new file mode 100644
index 0000000000000000000000000000000000000000..114d8a035b3fbfe4acdd1acb8cb907e39fac40e2
--- /dev/null
+++ b/pkg/compiler/lib/src/cps_ir/scalar_replacement.dart
@@ -0,0 +1,251 @@
+// Copyright (c) 2015, 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.
+
+import 'optimizers.dart';
+
+import 'dart:collection' show Queue;
+
+import '../closure.dart' show
+ ClosureClassElement, Identifiers;
+import '../common/names.dart' show
+ Selectors, Identifiers;
+import '../compiler.dart' as dart2js show
+ Compiler;
+import '../constants/constant_system.dart';
+import '../constants/values.dart';
+import '../dart_types.dart' as types;
+import '../diagnostics/invariant.dart' as dart2js show
+ InternalErrorFunction;
+import '../elements/elements.dart';
+import '../io/source_information.dart' show SourceInformation;
+import '../resolution/access_semantics.dart';
+import '../resolution/operators.dart';
+import '../resolution/send_structure.dart';
+import '../tree/tree.dart' as ast;
+import '../types/types.dart';
+import '../types/constants.dart' show computeTypeMask;
+import '../universe/universe.dart';
+import '../world.dart' show World;
+import 'cps_fragment.dart';
+import 'cps_ir_nodes.dart';
+import 'cps_ir_nodes_sexpr.dart' show SExpressionStringifier;
+
+/**
+ * Replaces aggregates with a set of local values. Performs inlining of
+ * single-use closures to generate more replacable aggregates.
+ */
+class ScalarReplacer extends Pass {
+ String get passName => 'Scalar replacement';
+
+ final dart2js.InternalErrorFunction _internalError;
+
+ ScalarReplacer(dart2js.Compiler compiler)
+ : _internalError = compiler.internalError;
+
+ @override
+ void rewrite(FunctionDefinition root) {
+ // Set all parent pointers.
+ new ParentVisitor().visit(root);
+ ScalarReplacementVisitor analyzer =
+ new ScalarReplacementVisitor(_internalError);
+ analyzer.analyze(root);
+ analyzer.process();
+ }
+}
+
+/**
+ * Do scalar replacement of aggregates on instances. Since scalar replacement
+ * can create new candidiates, iterate until all scalar replacements are done.
+ */
+class ScalarReplacementVisitor extends RecursiveVisitor {
+
+ final dart2js.InternalErrorFunction internalError;
+ ScalarReplacementRemovalVisitor removalVisitor;
+
+ Primitive _current = null;
+ Set<Primitive> _allocations = new Set<Primitive>();
+ Queue<Primitive> _queue = new Queue<Primitive>();
+
+ ScalarReplacementVisitor(this.internalError) {
+ removalVisitor = new ScalarReplacementRemovalVisitor(this);
+ }
+
+ void analyze(FunctionDefinition root) {
+ visit(root);
+ }
+
+ void process() {
+ while (_queue.isNotEmpty) {
+ Primitive allocation = _queue.removeFirst();
+ _allocations.remove(allocation);
+ _current = allocation;
+ tryScalarReplacement(allocation);
+ }
+ }
+
+ void tryScalarReplacement(Primitive allocation) {
+
+ // We can do scalar replacement of an aggregate if all uses of an allocation
+ // are reads or writes.
+ for (Reference ref = allocation.firstRef; ref != null; ref = ref.next) {
+ Node use = ref.parent;
+ if (use is GetField) continue;
+ if (use is SetField && use.object == ref) continue;
+ return;
+ }
+
+ Set<FieldElement> reads = new Set<FieldElement>();
+ Set<FieldElement> writes = new Set<FieldElement>();
+ for (Reference ref = allocation.firstRef; ref != null; ref = ref.next) {
+ Node use = ref.parent;
+ if (use is GetField) {
+ reads.add(use.field);
+ } else if (use is SetField) {
+ writes.add(use.field);
+ } else {
+ assert(false);
+ }
+ }
+
+ // Find the initial values of the fields. A CreateBox has no initial
+ // values. CreateInstance has initial values in the order of the fields.
+ Map<FieldElement, Primitive> fieldInitialValues =
+ <FieldElement, Primitive>{};
+ if (allocation is CreateInstance) {
+ int i = 0;
+ allocation.classElement.forEachInstanceField(
+ (ClassElement enclosingClass, FieldElement field) {
+ Primitive argument = allocation.arguments[i++].definition;
+ fieldInitialValues[field] = argument;
+ });
+ }
+
+ // Create [MutableVariable]s for each written field. Initialize the
+ // MutableVariable with the value from the allocator, or initialize with a
+ // `null` constant if there is not initial value.
+ Map<FieldElement, MutableVariable> cells =
+ <FieldElement, MutableVariable>{};
+ InteriorNode insertionPoint = allocation.parent; // LetPrim
+ for (FieldElement field in writes) {
+ MutableVariable variable = new MutableVariable(field);
+ cells[field] = variable;
+ Primitive initialValue = fieldInitialValues[field];
+ if (initialValue == null) {
+ assert(allocation is CreateBox);
+ initialValue = new Constant(new NullConstantValue());
+ LetPrim let = new LetPrim(initialValue);
+ let.primitive.parent = let;
+ insertionPoint = insertAtBody(insertionPoint, let);
+ }
+ LetMutable let = new LetMutable(variable, initialValue);
+ let.value.parent = let;
+ insertionPoint = insertAtBody(insertionPoint, let);
+ }
+
+ // Replace references with MutableVariable operations or references to the
+ // field's value.
+ for (Reference ref = allocation.firstRef; ref != null; ref = ref.next) {
+ Node use = ref.parent;
+ if (use is GetField) {
+ GetField getField = use;
+ MutableVariable variable = cells[getField.field];
+ if (variable != null) {
+ GetMutable getter = new GetMutable(variable);
+ getter.variable.parent = getter;
+ getter.substituteFor(getField);
+ replacePrimitive(getField, getter);
+ deletePrimitive(getField);
+ } else {
+ Primitive value = fieldInitialValues[getField.field];
+ value.substituteFor(getField);
+ deleteLetPrimOf(getField);
+ }
+ } else if (use is SetField && use.object == ref) {
+ SetField setField = use;
+ MutableVariable variable = cells[setField.field];
+ Primitive value = setField.value.definition;
+ SetMutable setter = new SetMutable(variable, value);
+ setter.variable.parent = setter;
+ setter.value.parent = setter;
+ setter.substituteFor(setField);
+ replacePrimitive(setField, setter);
+ deletePrimitive(setField);
+ } else {
+ assert(false);
+ }
+ }
+
+ // Delete [allocation] since that might 'free' another scalar replacement
+ // candidate by deleting the last non-field-access.
+ deleteLetPrimOf(allocation);
+ }
+
+ InteriorNode insertAtBody(
+ InteriorNode insertionPoint, InteriorExpression let) {
+ let.parent = insertionPoint;
+ let.body = insertionPoint.body;
+ let.body.parent = let;
+ insertionPoint.body = let;
+ return let;
+ }
+
+ /// Replaces [old] with [primitive] in [old]'s parent [LetPrim].
+ void replacePrimitive(Primitive old, Primitive primitive) {
+ LetPrim letPrim = old.parent;
+ letPrim.primitive = primitive;
+ }
+
+ void deleteLetPrimOf(Primitive primitive) {
+ assert(primitive.hasNoUses);
+ LetPrim letPrim = primitive.parent;
+ Node child = letPrim.body;
+ InteriorNode parent = letPrim.parent;
+ child.parent = parent;
+ parent.body = child;
+
+ deletePrimitive(primitive);
+ }
+
+ void deletePrimitive(Primitive primitive) {
+ assert(primitive.hasNoUses);
+ removalVisitor.visit(primitive);
+ }
+
+ void reconsider(Definition node) {
+ if (node is CreateInstance || node is CreateBox) {
+ if (node == _current) return;
+ enqueue(node);
+ }
+ }
+
+ void enqueue(Primitive node) {
+ assert(node is CreateInstance || node is CreateBox);
+ if (_allocations.contains(node)) return;
+ _allocations.add(node);
+ _queue.add(node);
+ }
+
+ // -------------------------- Visitor overrides ------------------------------
+ void visitCreateInstance(CreateInstance node) {
+ enqueue(node);
+ }
+
+ void visitCreateBox(CreateBox node) {
+ enqueue(node);
+ }
+}
+
+
+/// Visit a just-deleted subterm and unlink all [Reference]s in it. Reconsider
+/// allocations for scalar replacement.
+class ScalarReplacementRemovalVisitor extends RecursiveVisitor {
+ ScalarReplacementVisitor process;
+
+ ScalarReplacementRemovalVisitor(this.process);
+
+ processReference(Reference reference) {
+ process.reconsider(reference.definition);
+ reference.unlink();
+ }
+}
« 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