Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEd Willink2016-07-17 16:30:44 +0000
committerEd Willink2016-07-17 16:37:44 +0000
commit68acc93a7c26870cfe88aacf270413f7b25915f4 (patch)
tree7e5beda70ba766052e5fa034178482a930bf815a
parent1bb0012014fe4978fc7e422c88132fe125090098 (diff)
downloadorg.eclipse.qvtd-ewillink/486722.tar.gz
org.eclipse.qvtd-ewillink/486722.tar.xz
org.eclipse.qvtd-ewillink/486722.zip
wip EarlyRegionMergerewillink/486722
-rw-r--r--plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvtp2qvts/AbstractScheduledRegion.java12
-rw-r--r--plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvtp2qvts/MultiRegion.java24
-rw-r--r--plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvtp2qvts/QVTp2QVTs.java165
-rw-r--r--plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvtp2qvts/RootScheduledRegion.java3
-rw-r--r--plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvts2qvts/QVTs2QVTs.java54
-rw-r--r--plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvts2qvts/merger/EarlyRegionMerger.java192
-rw-r--r--plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvts2qvts/splitter/Split.java20
-rw-r--r--plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvts2qvts/splitter/SplitterVisitor.java5
-rw-r--r--plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/utilities/CompilerUtil.java6
9 files changed, 281 insertions, 200 deletions
diff --git a/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvtp2qvts/AbstractScheduledRegion.java b/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvtp2qvts/AbstractScheduledRegion.java
index b4bc62b22..cdd2c49a1 100644
--- a/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvtp2qvts/AbstractScheduledRegion.java
+++ b/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvtp2qvts/AbstractScheduledRegion.java
@@ -22,6 +22,7 @@ import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.ocl.pivot.CompleteClass;
import org.eclipse.ocl.pivot.Property;
+import org.eclipse.ocl.pivot.utilities.ClassUtil;
import org.eclipse.qvtd.compiler.internal.qvts2qvti.QVTs2QVTiVisitor;
import org.eclipse.qvtd.compiler.internal.utilities.SymbolNameBuilder;
import org.eclipse.qvtd.pivot.qvtbase.TypedModel;
@@ -36,7 +37,7 @@ public abstract class AbstractScheduledRegion extends AbstractRegion implements
/**
* All regions within this scheduled region.
*/
- private final @NonNull List<@NonNull Region> regions = new ArrayList<@NonNull Region>();
+ private /*@LazyNonNull*/ List<@NonNull Region> regions = null;
/**
* All the connections defined in this region, but not those in nested regions.
@@ -365,7 +366,7 @@ public abstract class AbstractScheduledRegion extends AbstractRegion implements
@Override
public @NonNull List<@NonNull Region> getRegions() {
- return regions;
+ return ClassUtil.nonNullState(regions);
}
@Override
@@ -420,6 +421,13 @@ public abstract class AbstractScheduledRegion extends AbstractRegion implements
removeConnection(connection);
}
+ protected void setRegions(@NonNull Iterable<@NonNull Region> regions) {
+ this.regions = new ArrayList<>();
+ for (@NonNull Region region : regions) {
+ region.setInvokingRegion(this);
+ this.regions.add(region);
+ }
+ }
/**
* After cycles have been removed, split looped connection variables to isolate the unlooping base case, from the/each looping case.
diff --git a/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvtp2qvts/MultiRegion.java b/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvtp2qvts/MultiRegion.java
index 4dac9cd88..82ec174e6 100644
--- a/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvtp2qvts/MultiRegion.java
+++ b/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvtp2qvts/MultiRegion.java
@@ -11,12 +11,12 @@
package org.eclipse.qvtd.compiler.internal.qvtp2qvts;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.List;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.ocl.pivot.OperationCallExp;
import org.eclipse.ocl.pivot.StandardLibrary;
+import org.eclipse.ocl.pivot.utilities.ClassUtil;
import org.eclipse.qvtd.pivot.schedule.AbstractAction;
import com.google.common.collect.Iterables;
@@ -35,8 +35,8 @@ public class MultiRegion
// private final @NonNull Map<Type, Property> type2castProperty = new HashMap<>();
private final @NonNull List<@NonNull Region> allRegions = new ArrayList<>();
-
- private @NonNull List<@NonNull Region> activeRegions = Collections.emptyList();
+ // private @NonNull List<@NonNull Region> activeRegions = Collections.emptyList();
+ private /*@LazyNonNull*/ List<@NonNull SimpleMappingRegion> orderedRegions = null;
public MultiRegion(@NonNull QVTp2QVTs qvtp2qvts) {
this.qvtp2qvts = qvtp2qvts;
@@ -54,9 +54,9 @@ public class MultiRegion
return qvtp2qvts.analyzeOperation(this, operationCallExp);
}
- public @NonNull List<@NonNull Region> getActiveRegions() {
- return activeRegions;
- }
+ // public @NonNull List<@NonNull Region> getActiveRegions() {
+ // return activeRegions;
+ // }
/* public @NonNull Property getCastProperty(@NonNull Type type) {
Property castProperty = type2castProperty.get(type);
@@ -77,6 +77,10 @@ public class MultiRegion
return Iterables.filter(allRegions, OperationRegion.class);
}
+ public @NonNull List<@NonNull SimpleMappingRegion> getOrderedRegions() {
+ return ClassUtil.nonNullState(orderedRegions);
+ }
+
// public @NonNull List<@NonNull Region> getRegions() {
// return allRegions;
// }
@@ -116,7 +120,11 @@ public class MultiRegion
// return activeRegions.remove(region);
// }
- public void setActiveRegions(@NonNull Iterable<@NonNull Region> activeRegions) { // FIXME eliminate
- this.activeRegions = Lists.newArrayList(activeRegions);
+ // public void setActiveRegions(@NonNull Iterable<@NonNull Region> activeRegions) { // FIXME eliminate
+ // this.activeRegions = Lists.newArrayList(activeRegions);
+ // }
+
+ public void setOrderedRegions(@NonNull Iterable<@NonNull SimpleMappingRegion> orderedRegions) { // FIXME eliminate
+ this.orderedRegions = Lists.newArrayList(orderedRegions);
}
}
diff --git a/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvtp2qvts/QVTp2QVTs.java b/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvtp2qvts/QVTp2QVTs.java
index 0ee4753cf..622b05f24 100644
--- a/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvtp2qvts/QVTp2QVTs.java
+++ b/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvtp2qvts/QVTp2QVTs.java
@@ -14,14 +14,9 @@ import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
-import java.util.Set;
-
import org.eclipse.jdt.annotation.NonNull;
-import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.ocl.pivot.ExpressionInOCL;
import org.eclipse.ocl.pivot.LanguageExpression;
import org.eclipse.ocl.pivot.OCLExpression;
@@ -34,7 +29,6 @@ import org.eclipse.ocl.pivot.utilities.NameUtil;
import org.eclipse.ocl.pivot.utilities.ParserException;
import org.eclipse.ocl.pivot.utilities.TracingOption;
import org.eclipse.qvtd.compiler.CompilerConstants;
-import org.eclipse.qvtd.compiler.internal.qvts2qvts.Region2Depth;
import org.eclipse.qvtd.pivot.qvtbase.utilities.QVTbaseUtil;
import org.eclipse.qvtd.pivot.schedule.AbstractAction;
import org.eclipse.qvtd.pivot.schedule.ClassDatum;
@@ -121,165 +115,12 @@ public class QVTp2QVTs extends SchedulerConstants
return new ClassDatumAnalysis(this, classDatum);
}
- /**
- * Replace those orderedRegions that may be aggregated as part of a GuardedRegion decision tree by GuardedRegions.
- * orderedRegions should be naturally ordered to ensure that non-recursive dependencies are inherently satisfied.
- *
- * Returns the orderedRegions plus the new aggregates less those aggregated.
- */
- public @NonNull List<@NonNull Region> earlyRegionMerge(@NonNull List<@NonNull SimpleMappingRegion> orderedRegions) {
- Region2Depth region2depths = new Region2Depth();
- List<@NonNull Region> outputRegions = new ArrayList<@NonNull Region>();
- LinkedHashSet<@NonNull SimpleMappingRegion> residualInputRegions = new LinkedHashSet<@NonNull SimpleMappingRegion>(orderedRegions); // order preserving fast random removal
- while (!residualInputRegions.isEmpty()) {
- @NonNull Region candidateRegion = residualInputRegions.iterator().next();
- boolean isMerged = false;
- if (isEarlyMergePrimaryCandidate(candidateRegion)) {
- List<@NonNull Region> secondaryRegions = selectSecondaryRegions(candidateRegion);
- if (secondaryRegions != null) {
- Region primaryRegion = candidateRegion;
- MergedMappingRegion mergedRegion = null;
- for (@NonNull Region secondaryRegion : secondaryRegions) {
- assert secondaryRegion != null;
- if (residualInputRegions.contains(secondaryRegion)) {
- Map<@NonNull Node, @NonNull Node> secondaryNode2primaryNode = primaryRegion.canMerge(secondaryRegion, region2depths, false);
- if (secondaryNode2primaryNode != null) {
- boolean isSharedHead = isSharedHead(primaryRegion, secondaryRegion);
- if (!isSharedHead || (secondaryRegion.canMerge(primaryRegion, region2depths, false) != null)) {
- if (mergedRegion == null) {
- mergedRegion = new MergedMappingRegion((MergeableRegion)primaryRegion);
- residualInputRegions.remove(primaryRegion);
- primaryRegion = mergedRegion;
- }
- mergedRegion.mergeRegion(secondaryRegion, secondaryNode2primaryNode);
- residualInputRegions.remove(secondaryRegion);
- region2depths.addRegion(mergedRegion);
- }
- }
- }
- }
- if (mergedRegion != null) {
- // mergedRegion.resolveRecursion();
- if (QVTp2QVTs.DEBUG_GRAPHS.isActive()) {
- mergedRegion.writeDebugGraphs("2-merged");
- }
- // GuardedRegion guardedRegion = createGuardedRegion(mergedRegion, mergeableRegions);
- // outputRegions.add(guardedRegion);
- outputRegions.add(mergedRegion);
- isMerged = true;
- }
- }
- }
- if (!isMerged) {
- outputRegions.add(candidateRegion);
- }
- residualInputRegions.remove(candidateRegion);
- }
- return outputRegions;
- }
-
public @NonNull SimpleMappingRegion getMappingRegion(@NonNull AbstractAction action) {
SimpleMappingRegion mappingRegion = action2mappingRegion.get(action);
assert mappingRegion != null;
return mappingRegion;
}
- /**
- * The primary region in a GuardedRegion must be single-headed. It may be multiply-produced, e.g. recursed.
- */
- private boolean isEarlyMergePrimaryCandidate(@NonNull Region mappingRegion) {
- List<@NonNull Node> headNodes = mappingRegion.getHeadNodes();
- return headNodes.size() == 1;
- }
-
- /**
- * The secondary region in a GuardedRegion must be single-headed and at least one its head nodes must be a class in use within
- * the primary region. It may be multiply-produced, e.g. recursed.
- */
- private boolean isEarlyMergeSecondaryCandidate(@NonNull Region primaryRegion,
- @NonNull Region secondaryRegion, @NonNull Set<ClassDatumAnalysis> toOneReachableClasses) {
- List<@NonNull Node> secondaryHeadNodes = secondaryRegion.getHeadNodes();
- if (secondaryHeadNodes.size() == 1) {
- Node classNode = secondaryHeadNodes.get(0);
- ClassDatumAnalysis classDatumAnalysis = classNode.getClassDatumAnalysis();
- if (toOneReachableClasses.contains(classDatumAnalysis)) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Return true if any primaryRegion head coincides with a secondaryRegion head.
- */
- private boolean isSharedHead(@NonNull Region primaryRegion, @NonNull Region secondaryRegion) {
- for (Node primaryHead : primaryRegion.getHeadNodes()) {
- ClassDatumAnalysis primaryClassDatumAnalysis = primaryHead.getClassDatumAnalysis();
- for (Node secondaryHead : secondaryRegion.getHeadNodes()) {
- if (primaryClassDatumAnalysis == secondaryHead.getClassDatumAnalysis()) {
- return true;
- }
- }
- }
- return false;
- }
-
- /**
- * Return a list of single-headed to-one navigable regions whose head is transitively to-one reachable from the primaryRegion's head.
- */
- private @Nullable List<@NonNull Region> selectSecondaryRegions(@NonNull Region primaryRegion) {
- //
- // All regions that consume one of the primary nodes.
- //
- Set<@NonNull Region> allConsumingRegions = new HashSet<@NonNull Region>();
- allConsumingRegions.add(primaryRegion);
- //
- // All classes reachable from the primary head.
- //
- Set<@NonNull ClassDatumAnalysis> toOneReachableClasses = new HashSet<@NonNull ClassDatumAnalysis>();
- List<@NonNull Region> secondaryRegions = null;
- List<@NonNull Region> allConsumingRegionsList = new ArrayList<@NonNull Region>(allConsumingRegions); // CME-proof iterable List shadowing a mutating Set
- for (int i = 0; i < allConsumingRegionsList.size(); i++) {
- @NonNull Region secondaryRegion = allConsumingRegionsList.get(i);
- if ((i == 0) || isEarlyMergeSecondaryCandidate(primaryRegion, secondaryRegion, toOneReachableClasses)) {
- if (i > 0) {
- if (secondaryRegions == null) {
- secondaryRegions = new ArrayList<@NonNull Region>();
- }
- secondaryRegions.add(secondaryRegion);
- }
- for (@NonNull Node predicatedNode : secondaryRegion.getMatchableNodes()) {
- if (predicatedNode.isClassNode()) { // Ignore nulls, attributes
- ClassDatumAnalysis predicatedClassDatumAnalysis = predicatedNode.getClassDatumAnalysis();
- if (toOneReachableClasses.add(predicatedClassDatumAnalysis)) {
- for (@NonNull Region consumingRegion : predicatedClassDatumAnalysis.getConsumingRegions()) {
- if (allConsumingRegions.add(consumingRegion)) {
- allConsumingRegionsList.add(consumingRegion);
- }
- }
- }
- }
- }
- if (secondaryRegion instanceof SimpleMappingRegion) {
- for (@NonNull Node assignedNode : ((SimpleMappingRegion)secondaryRegion).getComputedNodes()) {
- if (assignedNode.isClassNode()) { // Ignore nulls, attributes
- ClassDatumAnalysis consumingClassDatumAnalysis = assignedNode.getClassDatumAnalysis();
- if (toOneReachableClasses.add(consumingClassDatumAnalysis)) {
- for (@NonNull Region consumingRegion : consumingClassDatumAnalysis.getConsumingRegions()) {
- if (allConsumingRegions.add(consumingRegion)) {
- allConsumingRegionsList.add(consumingRegion);
- }
- }
- }
- }
- }
- }
- }
- }
- assert allConsumingRegionsList.size() == allConsumingRegions.size(); // Check same changes to CME-proof shadow
- return secondaryRegions;
- }
-
public @NonNull MultiRegion transform() throws IOException {
MultiRegion multiRegion = new MultiRegion(this);
//
@@ -311,11 +152,7 @@ public class QVTp2QVTs extends SchedulerConstants
orderedRegions.add(mappingRegion);
mappingRegion.resolveRecursion();
}
- List<@NonNull Region> activeRegions = new ArrayList<@NonNull Region>(earlyRegionMerge(orderedRegions));
- for (@NonNull OperationRegion operationRegion : multiRegion.getOperationRegions()) {
- activeRegions.add(operationRegion);
- }
- multiRegion.setActiveRegions(activeRegions);
+ multiRegion.setOrderedRegions(orderedRegions);
return multiRegion;
}
}
diff --git a/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvtp2qvts/RootScheduledRegion.java b/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvtp2qvts/RootScheduledRegion.java
index b9f2b2ae6..2673229ea 100644
--- a/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvtp2qvts/RootScheduledRegion.java
+++ b/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvtp2qvts/RootScheduledRegion.java
@@ -715,7 +715,8 @@ public class RootScheduledRegion extends AbstractScheduledRegion
return rootContainmentRegion;
}
- public void createSchedule() {
+ public void createSchedule(@NonNull Iterable<@NonNull Region> regions) {
+ setRegions(regions);
//
// Identify the input models.
//
diff --git a/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvts2qvts/QVTs2QVTs.java b/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvts2qvts/QVTs2QVTs.java
index 4bcf0889a..dac399e7e 100644
--- a/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvts2qvts/QVTs2QVTs.java
+++ b/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvts2qvts/QVTs2QVTs.java
@@ -21,9 +21,12 @@ import org.eclipse.qvtd.compiler.internal.qvtp2qvts.ScheduledRegion;
import org.eclipse.qvtd.compiler.internal.qvtp2qvts.SimpleMappingRegion;
import org.eclipse.qvtd.compiler.CompilerConstants;
import org.eclipse.qvtd.compiler.internal.qvtp2qvts.MultiRegion;
+import org.eclipse.qvtd.compiler.internal.qvtp2qvts.OperationRegion;
import org.eclipse.qvtd.compiler.internal.qvtp2qvts.QVTp2QVTs;
+import org.eclipse.qvtd.compiler.internal.qvts2qvts.merger.EarlyRegionMerger;
import org.eclipse.qvtd.compiler.internal.qvts2qvts.splitter.Split;
import org.eclipse.qvtd.compiler.internal.qvts2qvts.splitter.Splitter;
+import org.eclipse.qvtd.compiler.internal.utilities.CompilerUtil;
import org.eclipse.qvtd.pivot.qvtimperative.evaluation.QVTiEnvironmentFactory;
import org.eclipse.qvtd.pivot.qvtimperative.utilities.QVTimperativeHelper;
@@ -49,14 +52,14 @@ public class QVTs2QVTs extends QVTimperativeHelper
this.rootName = rootName;
}
- public @NonNull RootScheduledRegion createRootRegion(@NonNull List<@NonNull Region> allRegions) {
+ public @NonNull RootScheduledRegion createRootRegion(@NonNull Iterable<@NonNull Region> allRegions) {
RootScheduledRegion rootRegion = null;
- for (@NonNull Region region : new ArrayList<@NonNull Region>(allRegions)) {
+ for (@NonNull Region region : Lists.newArrayList(allRegions)) {
if (region.getInvokingRegion() == null) {
if (rootRegion == null) {
rootRegion = new RootScheduledRegion(region.getMultiRegion(), rootName);
}
- rootRegion.addRegion(region);
+ // rootRegion.addRegion(region);
}
}
assert rootRegion != null;
@@ -99,23 +102,52 @@ public class QVTs2QVTs extends QVTimperativeHelper
}
}
- protected void splitMultiHeadedRegions(@NonNull RootScheduledRegion rootRegion) {
- for (@NonNull Region region : Lists.newArrayList(rootRegion.getRegions())) {
+ /**
+ * Merge any mappings that are locally compatible. // FIXME do/done in QVTm2QVTp
+ * Returns a pruned list of mappings.
+ */
+ protected @NonNull Iterable<@NonNull Region> earlyRegionMerge(@NonNull MultiRegion multiRegion, @NonNull List<@NonNull SimpleMappingRegion> orderedRegions) {
+ EarlyRegionMerger earlyRegionMerger = new EarlyRegionMerger(this);
+ List<@NonNull Region> earlyMergedRegions = new ArrayList<@NonNull Region>(earlyRegionMerger.earlyRegionMerge(orderedRegions));
+ for (@NonNull OperationRegion operationRegion : multiRegion.getOperationRegions()) {
+ earlyMergedRegions.add(operationRegion);
+ }
+ return earlyMergedRegions;
+ }
+
+ protected @NonNull Iterable<@NonNull Region> splitMultiHeadedRegions(@NonNull RootScheduledRegion rootRegion, @NonNull Iterable<@NonNull Region> inputRegions) {
+ List<@NonNull Region> outputRegions = new ArrayList<>();
+ for (@NonNull Region region : inputRegions) {
if (region instanceof SimpleMappingRegion) {
- Splitter splitter = new Splitter((@NonNull SimpleMappingRegion) region);
+ Splitter splitter = new Splitter((SimpleMappingRegion) region);
Split split = splitter.split();
if (split != null) {
- split.install(rootRegion);
+ CompilerUtil.addAll(outputRegions, split.install(rootRegion));
}
+ else {
+ outputRegions.add(region);
+ }
+ }
+ else {
+ outputRegions.add(region);
}
}
+ return outputRegions;
}
public @NonNull RootScheduledRegion transform(@NonNull MultiRegion multiRegion) {
- List<@NonNull Region> activeRegions = multiRegion.getActiveRegions();
- RootScheduledRegion rootRegion = createRootRegion(activeRegions);
- splitMultiHeadedRegions(rootRegion);
- rootRegion.createSchedule();
+ List<@NonNull SimpleMappingRegion> orderedRegions = multiRegion.getOrderedRegions();
+ //
+ // Merge mappings that are trivially compatible.
+ //
+ Iterable<@NonNull Region> earlyMergedRegions = earlyRegionMerge(multiRegion, orderedRegions);
+ RootScheduledRegion rootRegion = createRootRegion(earlyMergedRegions);
+ //
+ // Merge mappings that are trivially compatible.
+ //
+ Iterable<@NonNull Region> splitHeadRegions = splitMultiHeadedRegions(rootRegion, earlyMergedRegions);
+ //
+ rootRegion.createSchedule(splitHeadRegions);
createSchedule(rootRegion);
return rootRegion;
}
diff --git a/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvts2qvts/merger/EarlyRegionMerger.java b/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvts2qvts/merger/EarlyRegionMerger.java
new file mode 100644
index 000000000..47197f7b9
--- /dev/null
+++ b/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvts2qvts/merger/EarlyRegionMerger.java
@@ -0,0 +1,192 @@
+/*******************************************************************************
+ * Copyright (c) 2016 Willink Transformations and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * E.D.Willink - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.qvtd.compiler.internal.qvts2qvts.merger;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.qvtd.compiler.internal.qvtp2qvts.ClassDatumAnalysis;
+import org.eclipse.qvtd.compiler.internal.qvtp2qvts.MergeableRegion;
+import org.eclipse.qvtd.compiler.internal.qvtp2qvts.MergedMappingRegion;
+import org.eclipse.qvtd.compiler.internal.qvtp2qvts.Node;
+import org.eclipse.qvtd.compiler.internal.qvtp2qvts.QVTp2QVTs;
+import org.eclipse.qvtd.compiler.internal.qvtp2qvts.Region;
+import org.eclipse.qvtd.compiler.internal.qvtp2qvts.SimpleMappingRegion;
+import org.eclipse.qvtd.compiler.internal.qvts2qvts.QVTs2QVTs;
+import org.eclipse.qvtd.compiler.internal.qvts2qvts.Region2Depth;
+
+public class EarlyRegionMerger
+{
+ protected final @NonNull QVTs2QVTs qvts2qvts;
+
+ public EarlyRegionMerger(@NonNull QVTs2QVTs qvts2qvts) {
+ this.qvts2qvts = qvts2qvts;
+ }
+
+ /**
+ * Replace those orderedRegions that may be aggregated as part of a GuardedRegion decision tree by GuardedRegions.
+ * orderedRegions should be naturally ordered to ensure that non-recursive dependencies are inherently satisfied.
+ *
+ * Returns the orderedRegions plus the new aggregates less those aggregated.
+ */
+ public @NonNull List<@NonNull Region> earlyRegionMerge(@NonNull List<@NonNull SimpleMappingRegion> orderedRegions) {
+ Region2Depth region2depths = new Region2Depth();
+ List<@NonNull Region> outputRegions = new ArrayList<@NonNull Region>();
+ LinkedHashSet<@NonNull SimpleMappingRegion> residualInputRegions = new LinkedHashSet<@NonNull SimpleMappingRegion>(orderedRegions); // order preserving fast random removal
+ while (!residualInputRegions.isEmpty()) {
+ @NonNull Region candidateRegion = residualInputRegions.iterator().next();
+ boolean isMerged = false;
+ if (isEarlyMergePrimaryCandidate(candidateRegion)) {
+ List<@NonNull Region> secondaryRegions = selectSecondaryRegions(candidateRegion);
+ if (secondaryRegions != null) {
+ Region primaryRegion = candidateRegion;
+ MergedMappingRegion mergedRegion = null;
+ for (@NonNull Region secondaryRegion : secondaryRegions) {
+ assert secondaryRegion != null;
+ if (residualInputRegions.contains(secondaryRegion)) {
+ Map<@NonNull Node, @NonNull Node> secondaryNode2primaryNode = primaryRegion.canMerge(secondaryRegion, region2depths, false);
+ if (secondaryNode2primaryNode != null) {
+ boolean isSharedHead = isSharedHead(primaryRegion, secondaryRegion);
+ if (!isSharedHead || (secondaryRegion.canMerge(primaryRegion, region2depths, false) != null)) {
+ if (mergedRegion == null) {
+ mergedRegion = new MergedMappingRegion((MergeableRegion)primaryRegion);
+ residualInputRegions.remove(primaryRegion);
+ primaryRegion = mergedRegion;
+ }
+ mergedRegion.mergeRegion(secondaryRegion, secondaryNode2primaryNode);
+ residualInputRegions.remove(secondaryRegion);
+ region2depths.addRegion(mergedRegion);
+ }
+ }
+ }
+ }
+ if (mergedRegion != null) {
+ // mergedRegion.resolveRecursion();
+ if (QVTp2QVTs.DEBUG_GRAPHS.isActive()) {
+ mergedRegion.writeDebugGraphs("2-merged");
+ }
+ // GuardedRegion guardedRegion = createGuardedRegion(mergedRegion, mergeableRegions);
+ // outputRegions.add(guardedRegion);
+ outputRegions.add(mergedRegion);
+ isMerged = true;
+ }
+ }
+ }
+ if (!isMerged) {
+ outputRegions.add(candidateRegion);
+ }
+ residualInputRegions.remove(candidateRegion);
+ }
+ return outputRegions;
+ }
+
+ /**
+ * The primary region in a GuardedRegion must be single-headed. It may be multiply-produced, e.g. recursed.
+ */
+ private boolean isEarlyMergePrimaryCandidate(@NonNull Region mappingRegion) {
+ List<@NonNull Node> headNodes = mappingRegion.getHeadNodes();
+ return headNodes.size() == 1;
+ }
+
+ /**
+ * The secondary region in a GuardedRegion must be single-headed and at least one its head nodes must be a class in use within
+ * the primary region. It may be multiply-produced, e.g. recursed.
+ */
+ private boolean isEarlyMergeSecondaryCandidate(@NonNull Region primaryRegion,
+ @NonNull Region secondaryRegion, @NonNull Set<ClassDatumAnalysis> toOneReachableClasses) {
+ List<@NonNull Node> secondaryHeadNodes = secondaryRegion.getHeadNodes();
+ if (secondaryHeadNodes.size() == 1) {
+ Node classNode = secondaryHeadNodes.get(0);
+ ClassDatumAnalysis classDatumAnalysis = classNode.getClassDatumAnalysis();
+ if (toOneReachableClasses.contains(classDatumAnalysis)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Return true if any primaryRegion head coincides with a secondaryRegion head.
+ */
+ private boolean isSharedHead(@NonNull Region primaryRegion, @NonNull Region secondaryRegion) {
+ for (Node primaryHead : primaryRegion.getHeadNodes()) {
+ ClassDatumAnalysis primaryClassDatumAnalysis = primaryHead.getClassDatumAnalysis();
+ for (Node secondaryHead : secondaryRegion.getHeadNodes()) {
+ if (primaryClassDatumAnalysis == secondaryHead.getClassDatumAnalysis()) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Return a list of single-headed to-one navigable regions whose head is transitively to-one reachable from the primaryRegion's head.
+ */
+ private @Nullable List<@NonNull Region> selectSecondaryRegions(@NonNull Region primaryRegion) {
+ //
+ // All regions that consume one of the primary nodes.
+ //
+ Set<@NonNull Region> allConsumingRegions = new HashSet<@NonNull Region>();
+ allConsumingRegions.add(primaryRegion);
+ //
+ // All classes reachable from the primary head.
+ //
+ Set<@NonNull ClassDatumAnalysis> toOneReachableClasses = new HashSet<@NonNull ClassDatumAnalysis>();
+ List<@NonNull Region> secondaryRegions = null;
+ List<@NonNull Region> allConsumingRegionsList = new ArrayList<@NonNull Region>(allConsumingRegions); // CME-proof iterable List shadowing a mutating Set
+ for (int i = 0; i < allConsumingRegionsList.size(); i++) {
+ @NonNull Region secondaryRegion = allConsumingRegionsList.get(i);
+ if ((i == 0) || isEarlyMergeSecondaryCandidate(primaryRegion, secondaryRegion, toOneReachableClasses)) {
+ if (i > 0) {
+ if (secondaryRegions == null) {
+ secondaryRegions = new ArrayList<@NonNull Region>();
+ }
+ secondaryRegions.add(secondaryRegion);
+ }
+ for (@NonNull Node predicatedNode : secondaryRegion.getMatchableNodes()) {
+ if (predicatedNode.isClassNode()) { // Ignore nulls, attributes
+ ClassDatumAnalysis predicatedClassDatumAnalysis = predicatedNode.getClassDatumAnalysis();
+ if (toOneReachableClasses.add(predicatedClassDatumAnalysis)) {
+ for (@NonNull Region consumingRegion : predicatedClassDatumAnalysis.getConsumingRegions()) {
+ if (allConsumingRegions.add(consumingRegion)) {
+ allConsumingRegionsList.add(consumingRegion);
+ }
+ }
+ }
+ }
+ }
+ if (secondaryRegion instanceof SimpleMappingRegion) {
+ for (@NonNull Node assignedNode : ((SimpleMappingRegion)secondaryRegion).getComputedNodes()) {
+ if (assignedNode.isClassNode()) { // Ignore nulls, attributes
+ ClassDatumAnalysis consumingClassDatumAnalysis = assignedNode.getClassDatumAnalysis();
+ if (toOneReachableClasses.add(consumingClassDatumAnalysis)) {
+ for (@NonNull Region consumingRegion : consumingClassDatumAnalysis.getConsumingRegions()) {
+ if (allConsumingRegions.add(consumingRegion)) {
+ allConsumingRegionsList.add(consumingRegion);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ assert allConsumingRegionsList.size() == allConsumingRegions.size(); // Check same changes to CME-proof shadow
+ return secondaryRegions;
+ }
+}
diff --git a/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvts2qvts/splitter/Split.java b/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvts2qvts/splitter/Split.java
index 6c97d0772..0e30b83d2 100644
--- a/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvts2qvts/splitter/Split.java
+++ b/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvts2qvts/splitter/Split.java
@@ -20,7 +20,6 @@ import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.qvtd.compiler.internal.qvtp2qvts.AbstractRegion;
import org.eclipse.qvtd.compiler.internal.qvtp2qvts.Edge;
-import org.eclipse.qvtd.compiler.internal.qvtp2qvts.MultiRegion;
import org.eclipse.qvtd.compiler.internal.qvtp2qvts.Node;
import org.eclipse.qvtd.compiler.internal.qvtp2qvts.QVTp2QVTs;
import org.eclipse.qvtd.compiler.internal.qvtp2qvts.Region;
@@ -113,8 +112,9 @@ public class Split
}
}
- public void install(@NonNull RootScheduledRegion rootRegion) {
- MultiRegion multiRegion = rootRegion.getMultiRegion();
+ public @NonNull Iterable<@NonNull Region> install(@NonNull RootScheduledRegion rootRegion) {
+ List<@NonNull Region> splitRegions = new ArrayList<>();
+ //
Map<@NonNull Node, @NonNull Node> oldSourceNode2newSourceNode = new HashMap<>();
Region oldRegion = splitter.getRegion();
// Iterable<@NonNull Node> newHeadNodes = stages.get(0).getHeadNodes();
@@ -125,7 +125,7 @@ public class Split
// }
// }
int stageNumber = 0;
- Iterator<@NonNull Stage> stageIterator = stages.iterator();;
+ Iterator<@NonNull Stage> stageIterator = stages.iterator();
//
// HeadStage
//
@@ -133,8 +133,7 @@ public class Split
assert nextStage instanceof HeadStage;
SplitterVisitor visitor = new HeadSplitterVisitor(rootRegion, nextStage, ++stageNumber, oldSourceNode2newSourceNode);
AbstractRegion stageRegion = visitor.createRegion(oldRegion);
- // multiRegion.addActiveRegion(stageRegion);
- rootRegion.addRegion(stageRegion);
+ splitRegions.add(stageRegion);
nextStage = stageIterator.hasNext() ? stageIterator.next() : null;
//
@@ -154,8 +153,7 @@ public class Split
while (nextStage instanceof HeadedStage) {
visitor = new LoopSplitterVisitor(rootRegion, nextStage, ++stageNumber, oldSourceNode2newSourceNode);
stageRegion = visitor.createRegion(oldRegion);
- // multiRegion.addActiveRegion(stageRegion);
- rootRegion.addRegion(stageRegion);
+ splitRegions.add(stageRegion);
nextStage = stageIterator.hasNext() ? stageIterator.next() : null;
//
// non-hazardous LoopStages fold into HeadStage
@@ -175,14 +173,14 @@ public class Split
assert nextStage instanceof BodyStage;
visitor = new BodySplitterVisitor(rootRegion, nextStage, ++stageNumber, oldSourceNode2newSourceNode);
stageRegion = visitor.createRegion(oldRegion);
- // multiRegion.addActiveRegion(stageRegion);
- rootRegion.addRegion(stageRegion);
+ splitRegions.add(stageRegion);
if (QVTp2QVTs.DEBUG_GRAPHS.isActive()) {
stageRegion.writeDebugGraphs("4-stage");
}
assert !stageIterator.hasNext();
// multiRegion.removeActiveRegion(oldRegion);
- rootRegion.removeRegion(stageRegion);
+ //
+ return splitRegions;
}
@Override
diff --git a/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvts2qvts/splitter/SplitterVisitor.java b/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvts2qvts/splitter/SplitterVisitor.java
index 5480b3888..99e11800a 100644
--- a/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvts2qvts/splitter/SplitterVisitor.java
+++ b/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvts2qvts/splitter/SplitterVisitor.java
@@ -26,7 +26,6 @@ import org.eclipse.qvtd.compiler.internal.qvtp2qvts.BasicSimpleEdge;
import org.eclipse.qvtd.compiler.internal.qvtp2qvts.ClassDatumAnalysis;
import org.eclipse.qvtd.compiler.internal.qvtp2qvts.Edge;
import org.eclipse.qvtd.compiler.internal.qvtp2qvts.EdgeRole;
-import org.eclipse.qvtd.compiler.internal.qvtp2qvts.MultiRegion;
import org.eclipse.qvtd.compiler.internal.qvtp2qvts.Node;
import org.eclipse.qvtd.compiler.internal.qvtp2qvts.NodeConnection;
import org.eclipse.qvtd.compiler.internal.qvtp2qvts.NodeRole;
@@ -45,7 +44,7 @@ import org.eclipse.qvtd.compiler.internal.utilities.SymbolNameBuilder;
public class SplitterVisitor extends AbstractVisitor<@Nullable Visitable>
{
protected final @NonNull RootScheduledRegion rootRegion;
- protected final @NonNull MultiRegion multiRegion;
+ // protected final @NonNull MultiRegion multiRegion;
protected final @NonNull Stage stage;
protected final int stageNumber;
protected final @NonNull Map<@NonNull Node, @NonNull Node> oldSourceNode2newSourceNode;
@@ -53,7 +52,7 @@ public class SplitterVisitor extends AbstractVisitor<@Nullable Visitable>
public SplitterVisitor(@NonNull RootScheduledRegion rootRegion, @NonNull Stage stage, int stageNumber, @NonNull Map<@NonNull Node, @NonNull Node> oldSourceNode2newSourceNode) {
this.rootRegion = rootRegion;
- this.multiRegion = rootRegion.getMultiRegion();
+ // this.multiRegion = rootRegion.getMultiRegion();
this.stage = stage;
this.stageNumber = stageNumber;
this.oldSourceNode2newSourceNode = oldSourceNode2newSourceNode;
diff --git a/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/utilities/CompilerUtil.java b/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/utilities/CompilerUtil.java
index 88bdd9a7c..d21075d51 100644
--- a/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/utilities/CompilerUtil.java
+++ b/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/utilities/CompilerUtil.java
@@ -66,6 +66,12 @@ public class CompilerUtil
}
+ public static <T> void addAll(@NonNull Collection<T> addTo, @NonNull Iterable<T> elementsToAdd) {
+ for (T element : elementsToAdd) {
+ addTo.add(element);
+ }
+ }
+
public static void assertNoDiagnosticErrors(String message, XtextResource xtextResource) {
List<Diagnostic> diagnostics = xtextResource.validateConcreteSyntax();
if (diagnostics.size() > 0) {

Back to the top