| /******************************************************************************* |
| * Copyright (c) 2018, 2019 Willink Transformations and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v2.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v20.html |
| * |
| * Contributors: |
| * E.D.Willink - Initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.qvtd.compiler.internal.qvts2qvts.partitioner; |
| |
| import java.util.ArrayList; |
| import java.util.HashSet; |
| 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.CompleteClass; |
| import org.eclipse.ocl.pivot.Property; |
| import org.eclipse.qvtd.compiler.internal.qvts2qvts.ConnectionManager; |
| import org.eclipse.qvtd.compiler.internal.qvts2qvts.RegionAnalysis; |
| import org.eclipse.qvtd.compiler.internal.qvts2qvts.utilities.ReachabilityForest; |
| import org.eclipse.qvtd.pivot.qvtbase.TypedModel; |
| import org.eclipse.qvtd.pivot.qvtschedule.ClassDatum; |
| import org.eclipse.qvtd.pivot.qvtschedule.Edge; |
| import org.eclipse.qvtd.pivot.qvtschedule.EdgeConnection; |
| import org.eclipse.qvtd.pivot.qvtschedule.IteratedEdge; |
| import org.eclipse.qvtd.pivot.qvtschedule.MappingPartition; |
| import org.eclipse.qvtd.pivot.qvtschedule.NavigableEdge; |
| import org.eclipse.qvtd.pivot.qvtschedule.NavigationEdge; |
| import org.eclipse.qvtd.pivot.qvtschedule.Node; |
| import org.eclipse.qvtd.pivot.qvtschedule.NodeConnection; |
| import org.eclipse.qvtd.pivot.qvtschedule.Partition; |
| import org.eclipse.qvtd.pivot.qvtschedule.PropertyDatum; |
| import org.eclipse.qvtd.pivot.qvtschedule.Region; |
| import org.eclipse.qvtd.pivot.qvtschedule.Role; |
| import org.eclipse.qvtd.pivot.qvtschedule.SuccessEdge; |
| import org.eclipse.qvtd.pivot.qvtschedule.utilities.QVTscheduleConstants; |
| import org.eclipse.qvtd.pivot.qvtschedule.utilities.QVTscheduleUtil; |
| |
| import com.google.common.collect.Iterables; |
| |
| public abstract class MappingPartitionAnalysis<P extends MappingPartition> extends AbstractPartitionAnalysis<P> |
| { |
| /** |
| * The trace nodes and their corresponding global success node. |
| * |
| * There should normally be exactly one trace node. |
| * |
| * There is no trace node for Adolfo's prematurely folded middle optimization and for manual partitionings |
| * such as attributeColumns in testQVTcCompiler_SimpleUML2RDBMS_CG. |
| * |
| * There could be multiple trace nodes after an early merge results. Work in progress. |
| * |
| private final @NonNull Map<@NonNull Node, @Nullable SuccessEdge> traceNode2globalSuccessEdge = new HashMap<>(); */ |
| |
| /** |
| * The trace nodes and their corresponding local success node. |
| * |
| * There should normally be exactly one trace node. |
| * |
| * There is no trace node for Adolfo's prematurely folded middle optimization and for manual partitionings |
| * such as attributeColumns in testQVTcCompiler_SimpleUML2RDBMS_CG. |
| * |
| * There could be multiple trace nodes after an early merge results. Work in progress. |
| * |
| private final @NonNull Map<@NonNull Node, @Nullable SuccessEdge> traceNode2localSuccessEdge = new HashMap<>(); */ |
| |
| /** |
| * The map from node to the trace edge by which the node may be located by lookup in a trace node once its trace edge is realized.. |
| * |
| private final @NonNull Map<@NonNull Node, @NonNull Edge> node2traceEdge = new HashMap<>(); */ |
| |
| /** |
| * The override dispatch node if needed. |
| */ |
| private @Nullable Node dispatchNode = null; |
| |
| /** |
| * The constant nodes that require no computation from other nodes. |
| */ |
| private final @NonNull List<@NonNull Node> constantInputNodes = new ArrayList<>(); |
| |
| /** |
| * The constant nodes that impose a check on a computation from other nodes. |
| */ |
| private final @NonNull List<@NonNull Node> constantOutputNodes = new ArrayList<>(); |
| |
| /** |
| * properties that are directly realized from a middle object provided all predicates are satisfied. |
| */ |
| private final @NonNull Set<@NonNull NavigableEdge> oldPrimaryNavigableEdges = new HashSet<>(); |
| private final @NonNull List<@NonNull Node> loadedInputNodes = new ArrayList<>(); |
| private final @NonNull List<@NonNull Edge> predicatedEdges = new ArrayList<>(); |
| private final @NonNull List<@NonNull NavigableEdge> predicatedMiddleEdges = new ArrayList<>(); |
| private final @NonNull List<@NonNull Node> predicatedMiddleNodes = new ArrayList<>(); |
| private final @NonNull List<@NonNull NavigableEdge> predicatedOutputEdges = new ArrayList<>(); |
| private final @NonNull List<@NonNull Node> predicatedOutputNodes = new ArrayList<>(); |
| private final @NonNull Set<@NonNull NavigableEdge> realizedEdges = new HashSet<>(); |
| private final @NonNull List<@NonNull NavigableEdge> realizedMiddleEdges = new ArrayList<>(); |
| private final @NonNull List<@NonNull Node> realizedMiddleNodes = new ArrayList<>(); |
| private final @NonNull List<@NonNull NavigableEdge> realizedOutputEdges = new ArrayList<>(); |
| private final @NonNull List<@NonNull Node> realizedOutputNodes = new ArrayList<>(); |
| private final @NonNull Set<@NonNull SuccessEdge> successEdges = new HashSet<>(); // FIXME redundant wrt traceNode2successEdge.values() |
| |
| /** |
| * The trace node(s). |
| */ |
| private final @NonNull List<@NonNull Node> traceNodes = new ArrayList<>(); |
| |
| /** |
| * The TraceClassAnalysis instances that are consumed by this MappingPartitioner. |
| */ |
| private @Nullable List<@NonNull TraceClassPartitionAnalysis> consumedTraceClassAnalyses = null; |
| |
| /** |
| * The TracePropertyAnalysis instances that are consumed by this MappingPartitioner. |
| */ |
| private @Nullable List<@NonNull TracePropertyPartitionAnalysis> consumedTracePropertyAnalyses = null; |
| |
| /** |
| * The TraceClassAnalysis instances that are produced by this MappingPartitioner. |
| */ |
| private @Nullable List<@NonNull TraceClassPartitionAnalysis> producedTraceClassAnalyses = null; |
| |
| /** |
| * The TracePropertyAnalysis instances that are produced by this MappingPartitioner. |
| */ |
| private @Nullable List<@NonNull TracePropertyPartitionAnalysis> producedTracePropertyAnalyses = null; |
| |
| /** |
| * The TraceClassAnalysis instances and super instances that are produced by this MappingPartitioner. |
| */ |
| private @Nullable Set<@NonNull TraceClassPartitionAnalysis> superProducedTraceClassAnalyses = null; |
| |
| protected MappingPartitionAnalysis(@NonNull PartitionedTransformationAnalysis partitionedTransformationAnalysis, @NonNull P partition) { |
| super(partitionedTransformationAnalysis, partition); |
| } |
| |
| private void addCheckedEdge(@NonNull NavigableEdge checkedEdge) { |
| Role role = partition.getRole(checkedEdge); |
| assert (role != null) && role.isChecked(); |
| ClassDatum classDatum = QVTscheduleUtil.getClassDatum(checkedEdge.getEdgeSource()); |
| TypedModel typedModel = QVTscheduleUtil.getReferredTypedModel(classDatum); |
| partition.addCheckedEdge(typedModel, checkedEdge); |
| QVTscheduleConstants.POLLED_PROPERTIES.println(" checked " + checkedEdge.getProperty() + |
| " at " + partition.getPassRangeText() + " in " + typedModel + " for " + partition); |
| } |
| |
| private void addConstantNode(@NonNull Node node) { |
| assert isConstant(node); |
| for (@NonNull Edge edge : QVTscheduleUtil.getIncomingEdges(node)) { |
| if (edge.isComputation() || ((edge.isCast() || edge.isNavigation()) && !isRealized(edge))) { |
| constantOutputNodes.add(node); |
| return; |
| } |
| } |
| constantInputNodes.add(node); |
| } |
| |
| private void addConsumptionOfEdge(@NonNull PartitionedTransformationAnalysis partitionedTransformationAnalysis, @NonNull NavigableEdge edge) { |
| Property property = QVTscheduleUtil.getProperty(edge); |
| if (property == scheduleManager.getStandardLibraryHelper().getOclContainerProperty()) { |
| Node targetNode = QVTscheduleUtil.getSourceNode(edge); |
| Node castTarget = targetNode; |
| ClassDatum classDatum = QVTscheduleUtil.getClassDatum(castTarget); |
| for (@NonNull PropertyDatum propertyDatum : scheduleManager.getOclContainerPropertyDatums(classDatum)) { |
| addConsumptionOfPropertyDatum(partitionedTransformationAnalysis, propertyDatum); |
| } |
| } |
| else { |
| PropertyDatum propertyDatum = scheduleManager.getPropertyDatum(edge); |
| addConsumptionOfPropertyDatum(partitionedTransformationAnalysis, propertyDatum); |
| } |
| } |
| |
| private void addConsumptionOfInputNode(@NonNull PartitionedTransformationAnalysis partitionedTransformationAnalysis, @NonNull Node node) { |
| if (node.isClass() && !loadedInputNodes.contains(node)) { // DataTypes are consumed by their edge |
| loadedInputNodes.add(node); |
| addConsumptionOfNode(partitionedTransformationAnalysis, node); |
| } |
| } |
| |
| private void addConsumptionOfMiddleEdge(@NonNull PartitionedTransformationAnalysis partitionedTransformationAnalysis, @NonNull NavigableEdge edge) { |
| if (!predicatedMiddleEdges.contains(edge)) { |
| predicatedMiddleEdges.add(edge); |
| addConsumptionOfEdge(partitionedTransformationAnalysis, edge); |
| } |
| } |
| |
| private void addConsumptionOfMiddleNode(@NonNull PartitionedTransformationAnalysis partitionedTransformationAnalysis, @NonNull Node node) { |
| if (!predicatedMiddleNodes.contains(node)) { |
| predicatedMiddleNodes.add(node); |
| addConsumptionOfNode(partitionedTransformationAnalysis, node); |
| } |
| } |
| |
| private void addConsumptionOfNode(@NonNull PartitionedTransformationAnalysis partitionedTransformationAnalysis, @NonNull Node node) { |
| Node castNode = QVTscheduleUtil.getCastTarget(node); |
| TraceClassPartitionAnalysis consumedTraceAnalysis = partitionedTransformationAnalysis.addConsumer(QVTscheduleUtil.getClassDatum(castNode), this); |
| List<@NonNull TraceClassPartitionAnalysis> consumedTraceClassAnalyses2 = consumedTraceClassAnalyses; |
| if (consumedTraceClassAnalyses2 == null) { |
| consumedTraceClassAnalyses = consumedTraceClassAnalyses2 = new ArrayList<>(); |
| } |
| if (!consumedTraceClassAnalyses2.contains(consumedTraceAnalysis)) { |
| consumedTraceClassAnalyses2.add(consumedTraceAnalysis); |
| } |
| } |
| |
| private void addConsumptionOfOutputEdge(@NonNull PartitionedTransformationAnalysis partitionedTransformationAnalysis, @NonNull NavigableEdge edge) { |
| if (!predicatedOutputEdges.contains(edge)) { |
| predicatedOutputEdges.add(edge); |
| addConsumptionOfEdge(partitionedTransformationAnalysis, edge); // FIXME gives 'should have realized' for 3*QVTc UML2RDBMS CollectionPartEdge |
| } |
| } |
| |
| private void addConsumptionOfOutputNode(@NonNull PartitionedTransformationAnalysis partitionedTransformationAnalysis, @NonNull Node node) { |
| if (!predicatedOutputNodes.contains(node)) { |
| predicatedOutputNodes.add(node); |
| addConsumptionOfNode(partitionedTransformationAnalysis, node); |
| } |
| } |
| |
| private void addConsumptionOfPropertyDatum(@NonNull PartitionedTransformationAnalysis partitionedTransformationAnalysis, @NonNull PropertyDatum propertyDatum) { |
| TracePropertyPartitionAnalysis consumedTraceAnalysis = partitionedTransformationAnalysis.addConsumer(propertyDatum, this); |
| List<@NonNull TracePropertyPartitionAnalysis> consumedTracePropertyAnalyses2 = consumedTracePropertyAnalyses; |
| if (consumedTracePropertyAnalyses2 == null) { |
| consumedTracePropertyAnalyses = consumedTracePropertyAnalyses2 = new ArrayList<>(); |
| } |
| if (!consumedTracePropertyAnalyses2.contains(consumedTraceAnalysis)) { |
| consumedTracePropertyAnalyses2.add(consumedTraceAnalysis); |
| } |
| } |
| |
| @Override |
| public void addEnforcedEdge(@NonNull NavigableEdge realizedEdge) { |
| Role role = partition.getRole(realizedEdge); |
| assert (role != null) && role.isRealized(); |
| ClassDatum classDatum = QVTscheduleUtil.getClassDatum(realizedEdge.getEdgeSource()); |
| TypedModel typedModel = QVTscheduleUtil.getReferredTypedModel(classDatum); |
| Property asProperty = partition.addEnforcedEdge(typedModel, realizedEdge); |
| QVTscheduleConstants.POLLED_PROPERTIES.println(" enforced " + asProperty + |
| " at " + partition.getPassRangeText() + |
| " in " + typedModel + " for " + partition); |
| } |
| |
| private void addProductionOfEdge(@NonNull PartitionedTransformationAnalysis partitionedTransformationAnalysis, @NonNull NavigableEdge edge) { |
| assert isNew(edge); |
| Property property = QVTscheduleUtil.getProperty(edge); |
| assert property != scheduleManager.getStandardLibraryHelper().getOclContainerProperty(); // oclContainer is not assignable |
| PropertyDatum propertyDatum = scheduleManager.getPropertyDatum(edge); |
| TracePropertyPartitionAnalysis producedTraceAnalysis = partitionedTransformationAnalysis.addProducer(propertyDatum, this); |
| List<@NonNull TracePropertyPartitionAnalysis> producedTracePropertyAnalyses2 = producedTracePropertyAnalyses; |
| if (producedTracePropertyAnalyses2 == null) { |
| producedTracePropertyAnalyses = producedTracePropertyAnalyses2 = new ArrayList<>(); |
| } |
| if (!producedTracePropertyAnalyses2.contains(producedTraceAnalysis)) { |
| producedTracePropertyAnalyses2.add(producedTraceAnalysis); |
| } |
| PropertyDatum oppositePropertyDatum = propertyDatum.getOpposite(); |
| if (oppositePropertyDatum != null) { |
| TracePropertyPartitionAnalysis oppositeProducedTraceAnalysis = partitionedTransformationAnalysis.addProducer(oppositePropertyDatum, this); |
| if (!producedTracePropertyAnalyses2.contains(oppositeProducedTraceAnalysis)) { |
| producedTracePropertyAnalyses2.add(oppositeProducedTraceAnalysis); |
| } |
| } |
| } |
| |
| private void addProductionOfMiddleEdge(@NonNull PartitionedTransformationAnalysis partitionedTransformationAnalysis, @NonNull NavigableEdge edge) { |
| if (isRealized(edge) && !realizedMiddleEdges.contains(edge)) { |
| realizedMiddleEdges.add(edge); |
| addProductionOfEdge(partitionedTransformationAnalysis, edge); |
| } |
| } |
| |
| private void addProductionOfMiddleNode(@NonNull PartitionedTransformationAnalysis partitionedTransformationAnalysis, @NonNull Node node) { |
| if (isRealized(node) && !realizedMiddleNodes.contains(node)) { |
| realizedMiddleNodes.add(node); |
| addProductionOfNode(partitionedTransformationAnalysis, node); |
| } |
| } |
| |
| private void addProductionOfNode(@NonNull PartitionedTransformationAnalysis partitionedTransformationAnalysis, @NonNull Node node) { |
| assert isNew(node); |
| TraceClassPartitionAnalysis consumedTraceAnalysis = partitionedTransformationAnalysis.addProducer(QVTscheduleUtil.getClassDatum(node), this); |
| List<@NonNull TraceClassPartitionAnalysis> producedTraceClassAnalyses2 = producedTraceClassAnalyses; |
| if (producedTraceClassAnalyses2 == null) { |
| producedTraceClassAnalyses = producedTraceClassAnalyses2 = new ArrayList<>(); |
| } |
| if (!producedTraceClassAnalyses2.contains(consumedTraceAnalysis)) { |
| producedTraceClassAnalyses2.add(consumedTraceAnalysis); |
| } |
| } |
| |
| private void addProductionOfOutputEdge(@NonNull PartitionedTransformationAnalysis partitionedTransformationAnalysis, @NonNull NavigableEdge edge) { |
| if (isRealized(edge) && !realizedOutputEdges.contains(edge)) { |
| realizedOutputEdges.add(edge); |
| addProductionOfEdge(partitionedTransformationAnalysis, edge); |
| } |
| } |
| |
| private void addProductionOfOutputNode(@NonNull PartitionedTransformationAnalysis partitionedTransformationAnalysis, @NonNull Node node) { |
| if (isRealized(node) && !realizedOutputNodes.contains(node)) { |
| realizedOutputNodes.add(node); |
| addProductionOfNode(partitionedTransformationAnalysis, node); |
| } |
| } |
| |
| private void analyzeEdges(@NonNull PartitionedTransformationAnalysis partitionedTransformationAnalysis) { |
| for (@NonNull Edge edge : partition.getPartialEdges()) { |
| if (!edge.isSecondary()) { |
| if (isPredicated(edge)) { |
| predicatedEdges.add(edge); |
| } |
| if (edge instanceof NavigableEdge) { |
| NavigableEdge navigableEdge = (NavigableEdge)edge; |
| if (navigableEdge.isSuccess()) { |
| successEdges.add((SuccessEdge) navigableEdge); |
| } |
| if (isRealized(navigableEdge)) { |
| realizedEdges.add(navigableEdge); |
| } |
| else { |
| oldPrimaryNavigableEdges.add(navigableEdge); |
| } |
| if (!isRealized(navigableEdge) && navigableEdge.isMatched() && !navigableEdge.isCast()) { // FIXME is this totally obsolete |
| assert !navigableEdge.isExpression(); |
| assert !navigableEdge.isComputation(); |
| } |
| Node sourceNode = navigableEdge.getEdgeSource(); |
| // Node targetNode = navigableEdge.getEdgeTarget(); |
| if (scheduleManager.isMiddle(sourceNode)) { // || scheduleManager.isMiddle(targetNode)) { |
| if (isChecked(navigableEdge)) { |
| addConsumptionOfMiddleEdge(partitionedTransformationAnalysis, navigableEdge); |
| } |
| else if (isRealized(navigableEdge)) { |
| addProductionOfMiddleEdge(partitionedTransformationAnalysis, navigableEdge); |
| } |
| else { |
| throw new IllegalStateException("middle edge must be predicated or realized : " + navigableEdge); |
| } |
| } |
| else { // || scheduleManager.isOutput(targetNode)) { |
| if (isLoaded(navigableEdge) || isConstant(navigableEdge)) {} |
| else if (isChecked(navigableEdge)) { // || isSpeculated(navigableEdge)) { |
| if (!navigableEdge.isCast()) { |
| addConsumptionOfOutputEdge(partitionedTransformationAnalysis, navigableEdge); |
| } |
| } |
| else if (isRealized(navigableEdge)) { |
| addProductionOfOutputEdge(partitionedTransformationAnalysis, navigableEdge); |
| } |
| else { |
| throw new IllegalStateException("other edge must be predicated or realized : " + navigableEdge); |
| } |
| } |
| } |
| else if (edge.isExpression()) {} |
| else if (edge instanceof IteratedEdge) {} |
| else if (edge.isDependency()) {} |
| else { |
| throw new IllegalStateException("unsupported analyzeEdge : " + edge); |
| } |
| } |
| } |
| } |
| |
| /* private void analyzeGlobalSuccessEdge(@NonNull Node traceNode) { |
| SuccessEdge globalSuccessEdge = null; |
| Property globalSuccessProperty = scheduleManager.basicGetGlobalSuccessProperty(traceNode); |
| if (globalSuccessProperty != null) { |
| NavigationEdge statusNavigationEdge = QVTscheduleUtil.basicGetNavigationEdge(traceNode, globalSuccessProperty); |
| if (statusNavigationEdge != null) { |
| globalSuccessEdge = (SuccessEdge) statusNavigationEdge; |
| } |
| else { // Never needed |
| /* if (!(region instanceof DispatchRegion) && !(region instanceof VerdictRegion)) { |
| RegionHelper<@NonNull MappingRegion> regionHelper = new RegionHelper<>(scheduleManager, (MappingRegion)region); |
| successEdge = regionHelper.createRealizedSuccess(traceNode, successProperty, null); // FIXME This creates a premature success in a speculation |
| Node successNode = QVTscheduleUtil.getTargetNode(successEdge); |
| successNode.setUtility(Node.Utility.STRONGLY_MATCHED); // FIXME is this really neded |
| } * / |
| } |
| } |
| traceNode2globalSuccessEdge.put(traceNode, globalSuccessEdge); |
| } */ |
| |
| /* private void analyzeLocalSuccessEdge(@NonNull Node traceNode) { |
| SuccessEdge localSuccessEdge = null; |
| Property localSuccessProperty = scheduleManager.basicGetLocalSuccessProperty(traceNode); |
| if (localSuccessProperty != null) { |
| NavigationEdge statusNavigationEdge = QVTscheduleUtil.basicGetNavigationEdge(traceNode, localSuccessProperty); |
| if (statusNavigationEdge != null) { |
| localSuccessEdge = (SuccessEdge) statusNavigationEdge; |
| } |
| else { // Never needed |
| /* if (!(region instanceof DispatchRegion) && !(region instanceof VerdictRegion)) { |
| RegionHelper<@NonNull MappingRegion> regionHelper = new RegionHelper<>(scheduleManager, (MappingRegion)region); |
| successEdge = regionHelper.createRealizedSuccess(traceNode, successProperty, null); // FIXME This creates a premature success in a speculation |
| Node successNode = QVTscheduleUtil.getTargetNode(successEdge); |
| successNode.setUtility(Node.Utility.STRONGLY_MATCHED); // FIXME is this really neded |
| } * / |
| } |
| } |
| traceNode2localSuccessEdge.put(traceNode, localSuccessEdge); |
| } */ |
| |
| private void analyzeNodes(@NonNull PartitionedTransformationAnalysis partitionedTransformationAnalysis) { |
| for (@NonNull Node node : partition.getPartialNodes()) { |
| if (node.isNullLiteral()) { |
| addConstantNode(node); |
| } |
| else if (node.isOperation()) { |
| if (isConstant(node)) { |
| addConstantNode(node); |
| } |
| else if (isRealized(node)) { |
| // FIXME addProductionOfOutputNode(node); |
| // realizedOutputNodes.add(node); |
| } |
| } |
| else if (node.isPattern()) { |
| if (isConstant(node)) {} |
| else if (isLoaded(node)) { |
| addConsumptionOfInputNode(partitionedTransformationAnalysis, node); |
| } |
| else if (scheduleManager.isMiddle(node)) { |
| if (node.isDispatch()) { |
| if (dispatchNode != null) { |
| throw new IllegalStateException(); // Dual dispatcher |
| } |
| dispatchNode = node; |
| } |
| else if (node.isTrace()) { |
| traceNodes.add(node); |
| } |
| if (isPredicated(node)) { |
| addConsumptionOfMiddleNode(partitionedTransformationAnalysis, node); |
| } |
| else if (isSpeculated(node)) { |
| if (!node.isHead()) { // Don't create a self-consumption cycle |
| addConsumptionOfMiddleNode(partitionedTransformationAnalysis, node); |
| } |
| } |
| else if (isSpeculation(node)) { |
| addProductionOfMiddleNode(partitionedTransformationAnalysis, node); |
| } |
| else if (isRealized(node)) { |
| addProductionOfMiddleNode(partitionedTransformationAnalysis, node); |
| } |
| else { |
| throw new IllegalStateException("middle node must be predicated or realized : " + node); |
| } |
| } |
| else { // scheduleManager.isOutput(node) |
| if (isPredicated(node)) { |
| addConsumptionOfOutputNode(partitionedTransformationAnalysis, node); |
| } |
| else if (isRealized(node)) { |
| addProductionOfOutputNode(partitionedTransformationAnalysis, node); |
| } |
| else { |
| throw new IllegalStateException("other node must be predicated or realized : " + node); |
| } |
| } |
| } |
| else if (node.isDependency()) { |
| addConsumptionOfOutputNode(partitionedTransformationAnalysis, node); |
| } |
| else if (node.isIterator()) {} |
| else { |
| throw new IllegalStateException("unsupported analyzeNode : " + node); |
| } |
| } |
| } |
| |
| @Override |
| public void analyzePartition() { |
| analyzeNodes(partitionedTransformationAnalysis); |
| analyzeEdges(partitionedTransformationAnalysis); |
| } |
| |
| @Override |
| public void analyzePartitionEdges() { |
| for (@NonNull Edge edge : partition.getPartialEdges()) { |
| if (edge.isNavigation()) { |
| NavigationEdge navigationEdge = (NavigationEdge) edge; |
| Node sourceNode = navigationEdge.getEdgeSource(); |
| ClassDatum classDatum = QVTscheduleUtil.getClassDatum(sourceNode); |
| TypedModel typedModel = QVTscheduleUtil.getReferredTypedModel(classDatum); |
| if (isPredicated(edge)) { |
| assert !navigationEdge.isCast(); |
| partitionedTransformationAnalysis.addCheckedEdge(typedModel, navigationEdge); |
| } |
| else if (isRealized(edge)) { |
| partitionedTransformationAnalysis.addRealizedEdge(typedModel, navigationEdge); |
| } |
| } |
| } |
| partition.initTypedModelAnalysis(); |
| } |
| |
| /* private void analyzeTraceEdges(@NonNull Node traceNode) { |
| for (@NonNull Edge edge : QVTscheduleUtil.getOutgoingEdges(traceNode)) { |
| if (((edge.isCast() || edge.isNavigation()) && partition.isRealized(edge))) { |
| Node tracedNode = QVTscheduleUtil.getTargetNode(edge); |
| node2traceEdge.put(tracedNode, edge); |
| } |
| } |
| } */ |
| |
| /* private @NonNull Iterable<@NonNull Node> analyzeTraceNodes() { |
| /* if (realizedMiddleNodes.size() == 0) { |
| return Collections.emptyList(); |
| } |
| if (realizedMiddleNodes.size() == 1) { |
| return Collections.singletonList(realizedMiddleNodes.get(0)); |
| } |
| Iterable<@NonNull Node> headNodes = RuleHeadAnalysis.computeRealizedHeadNodes(region, realizedMiddleNodes); |
| if (Iterables.size(headNodes) == 0) { |
| return Collections.emptyList(); |
| } |
| else { |
| return Collections.singletonList(headNodes.iterator().next()); |
| } * / |
| return Iterables.concat(getPredicatedMiddleNodes(), getRealizedMiddleNodes()); |
| } */ |
| |
| public @Nullable Node basicGetDispatchNode() { |
| return dispatchNode; |
| } |
| |
| /* public @Nullable SuccessEdge basicGetGlobalSuccessEdge(@NonNull Node traceNode) { |
| return traceNode2globalSuccessEdge.get(traceNode); |
| } |
| |
| public @Nullable Node basicGetGlobalSuccessNode(@NonNull Node traceNode) { |
| SuccessEdge successEdge = traceNode2globalSuccessEdge.get(traceNode); |
| return successEdge != null ? successEdge.getTargetNode() : null; |
| } |
| |
| public @Nullable SuccessEdge basicGetLocalSuccessEdge(@NonNull Node traceNode) { |
| return traceNode2localSuccessEdge.get(traceNode); |
| } |
| |
| public @Nullable Node basicGetLocalSuccessNode(@NonNull Node traceNode) { |
| SuccessEdge successEdge = traceNode2localSuccessEdge.get(traceNode); |
| return successEdge != null ? successEdge.getTargetNode() : null; |
| } */ |
| |
| @Override |
| public void computeCheckedOrEnforcedEdges() { |
| // String name = getName(); |
| boolean doDebug = QVTscheduleConstants.POLLED_PROPERTIES.isActive(); |
| if (doDebug) { |
| QVTscheduleConstants.POLLED_PROPERTIES.println("analyzing " + this + " (" + partition.getPassRangeText() + ")"); |
| } |
| ConnectionManager connectionManager = scheduleManager.getConnectionManager(); |
| for (@NonNull Edge edge : partition.getPartialEdges()) { |
| if (edge.isNavigation() && isChecked(edge)) { |
| NavigationEdge checkedEdge = (NavigationEdge) edge; |
| assert !checkedEdge.isCast(); |
| Property property = checkedEdge.getProperty(); |
| if (doDebug) { |
| QVTscheduleConstants.POLLED_PROPERTIES.println(" analyzing " + checkedEdge.getEdgeSource().getName() + "::" + property.getName() + " : " + checkedEdge.getEdgeSource().getCompleteClass()); |
| } |
| EdgeConnection edgeConnection = checkedEdge.getIncomingConnection(); |
| if (edgeConnection != null) { |
| boolean isChecked = false; |
| for (@NonNull Partition usedPartition : edgeConnection.getSourcePartitions()) { |
| if (usedPartition.getLastPass() >= partition.getFirstPass()) { |
| addCheckedEdge(checkedEdge); |
| isChecked = true; |
| } |
| } |
| if (isChecked) { |
| for (@NonNull NavigableEdge usedEdge : QVTscheduleUtil.getSourceEnds(edgeConnection)) { |
| Region sourceRegion = QVTscheduleUtil.getOwningRegion(usedEdge); |
| RegionAnalysis sourceRegionAnalysis = scheduleManager.getRegionAnalysis(sourceRegion); |
| for (@NonNull PartitionAnalysis sourcePartitionAnalysis : sourceRegionAnalysis.getPartitionAnalyses()) { |
| Role sourceRole = sourcePartitionAnalysis.getPartition().getRole(usedEdge); |
| if ((sourceRole != null) && !sourceRole.isChecked()) { |
| sourcePartitionAnalysis.addEnforcedEdge(usedEdge); |
| } |
| } |
| } |
| } |
| } |
| |
| Node laterNode = checkedEdge.getEdgeSource(); |
| Node predicatedSourceNode = checkedEdge.getEdgeSource(); |
| Node predicatedTargetNode = checkedEdge.getEdgeTarget(); |
| NodeConnection usedConnection = connectionManager.getIncomingUsedConnection(predicatedTargetNode); |
| if (usedConnection != null) { |
| for (@NonNull Partition usedPartition : usedConnection.getSourcePartitions()) { |
| if (usedPartition.getLastPass() >= partition.getFirstPass()) { // FIXME = |
| CompleteClass predicatedSourceType = predicatedSourceNode.getCompleteClass(); |
| CompleteClass predicatedTargetType = predicatedTargetNode.getCompleteClass(); |
| ClassDatum classDatum = QVTscheduleUtil.getClassDatum(laterNode); |
| TypedModel typedModel = QVTscheduleUtil.getReferredTypedModel(classDatum); |
| Map<@NonNull Property, @NonNull List<@NonNull NavigableEdge>> property2realizedEdges = partitionedTransformationAnalysis.getProperty2RealizedEdges(typedModel); |
| assert property2realizedEdges != null; |
| Property oclContainerProperty = scheduleManager.getStandardLibraryHelper().getOclContainerProperty(); |
| if (property == oclContainerProperty) { |
| // Node containerNode = predicatedEdge.getTarget(); |
| // Node containedNode = predicatedEdge.getSource(); |
| // CompleteClass containerType = containerNode.getCompleteClass(); |
| // CompleteClass containedType = containedNode.getCompleteClass(); |
| for (@NonNull Property candidateProperty : property2realizedEdges.keySet()) { |
| if (candidateProperty.isIsComposite()) { |
| // CompleteClass candidateContainerType = completeModel.getCompleteClass(candidateProperty.getOwningClass()); |
| // CompleteClass candidateContainedType = completeModel.getCompleteClass(candidateProperty.getType()); |
| // if (candidateContainerType.conformsTo(containerType) && containedType.conformsTo(candidateContainedType)) { |
| List<@NonNull NavigableEdge> realizedEdges = property2realizedEdges.get(candidateProperty); |
| assert realizedEdges != null; |
| for (@NonNull NavigableEdge realizedEdge : realizedEdges) { |
| // FIXME recheck for narrower types ?? |
| // String isNotHazardous; |
| // if (region == earlierRegion) { |
| // isNotHazardous = "same region"; // FIXME must handle recursion |
| // } |
| // else if (earlierRegion.getLatestIndex() < getEarliestIndex()) { |
| // isNotHazardous = "later";// FIXME must handle any possible reads of any possible write |
| // } |
| // else { |
| Node realizedSourceNode = realizedEdge.getEdgeSource(); |
| Node realizedTargetNode = realizedEdge.getEdgeTarget(); |
| CompleteClass realizedSourceType = realizedSourceNode.getCompleteClass(); |
| CompleteClass realizedTargetType = realizedTargetNode.getCompleteClass(); |
| if (realizedSourceType.conformsTo(predicatedSourceType) && realizedTargetType.conformsTo(predicatedTargetType)) { |
| assert partition.getLastPass() >= usedPartition.getFirstPass(); |
| // isNotHazardous = null; |
| } |
| else { |
| // isNotHazardous = "incompatible"; |
| } |
| assert partition.getLastPass() >= usedPartition.getFirstPass(); |
| // isNotHazardous = null; |
| // } |
| // if (isNotHazardous == null) { |
| addCheckedEdge(checkedEdge); |
| AbstractPartitionAnalysis<?> usedPartitionAnalysis = partitionedTransformationAnalysis.getPartitionAnalysis(usedPartition); |
| usedPartitionAnalysis.addEnforcedEdge(realizedEdge); |
| // } |
| // else if (doDebug) { |
| // QVTs2QVTiVisitor.POLLED_PROPERTIES.println(" ignored " + region + "::" + laterNode.getName() + "(" + getEarliestIndex() + ".." + getLatestIndex() + ")" + |
| // " " + isNotHazardous + " (" + earlierRegion.getEarliestIndex() + ".." + earlierRegion.getLatestIndex() + ")" + earlierRegion + "::" + realizedEdge.getSource().getName()); |
| // } |
| // } |
| } |
| } |
| } |
| } |
| else { |
| assert property2realizedEdges != null : "No realized typed model for " + typedModel; |
| List<@NonNull NavigableEdge> realizedEdges = property2realizedEdges.get(property); |
| if (realizedEdges == null) { |
| System.err.println("No realized edges for " + typedModel + "!" + property + " in " + this); |
| } |
| else { |
| for (@NonNull NavigableEdge realizedEdge : realizedEdges) { |
| // Region earlierRegion = QVTscheduleUtil.getOwningRegion(realizedEdge); |
| String checkIsHazardFreeBecause; |
| String enforceIsHazardFreeBecause; |
| Node realizedSourceNode = realizedEdge.getEdgeSource(); |
| Node realizedTargetNode = realizedEdge.getEdgeTarget(); |
| CompleteClass realizedSourceType = realizedSourceNode.getCompleteClass(); |
| CompleteClass realizedTargetType = realizedTargetNode.getCompleteClass(); |
| if (!realizedSourceType.conformsTo(predicatedSourceType)) { |
| checkIsHazardFreeBecause = "incompatible-source"; |
| enforceIsHazardFreeBecause = "incompatible-source"; |
| } |
| else if (!QVTscheduleUtil.conformsToClassOrBehavioralClass(realizedTargetType, predicatedTargetType)) { |
| checkIsHazardFreeBecause = "incompatible-target"; |
| enforceIsHazardFreeBecause = "incompatible-target"; |
| } |
| // else if (region == earlierRegion) { // FIXME old commented out code for partitions |
| // checkIsHazardFreeBecause = null; // Same region requires inter-recursion check |
| // enforceIsHazardFreeBecause = null; // Same region requires inter-recursion enforce to be available for check |
| // } |
| else if (usedPartition.getLastPass() < partition.getFirstPass()) { |
| checkIsHazardFreeBecause = "later"; |
| enforceIsHazardFreeBecause = null; // Enforce required for later check |
| } |
| else { |
| // The QVTi AS has insufficient precision to identify which of multiple references is hazardous |
| checkIsHazardFreeBecause = null; |
| enforceIsHazardFreeBecause = null; |
| } |
| if (checkIsHazardFreeBecause == null) { |
| addCheckedEdge(checkedEdge); |
| } |
| else if (doDebug) { |
| QVTscheduleConstants.POLLED_PROPERTIES.println(" ignored check for " + this + "::" + laterNode.getName() + "(" + partition.getPassRangeText() + ")" + |
| " " + checkIsHazardFreeBecause + " (" + usedPartition.getPassRangeText() + ")" + usedPartition + "::" + realizedEdge.getEdgeSource().getName()); |
| } |
| if (enforceIsHazardFreeBecause == null) { |
| AbstractPartitionAnalysis<?> usedPartitionAnalysis = partitionedTransformationAnalysis.getPartitionAnalysis(usedPartition); |
| usedPartitionAnalysis.addEnforcedEdge(realizedEdge); |
| } |
| else if (doDebug) { |
| QVTscheduleConstants.POLLED_PROPERTIES.println(" ignored enforce " + this + "::" + laterNode.getName() + "(" + partition.getPassRangeText() + ")" + |
| " " + enforceIsHazardFreeBecause + " (" + usedPartition.getPassRangeText() + ")" + usedPartition + "::" + realizedEdge.getEdgeSource().getName()); |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| public @NonNull Iterable<@NonNull Node> getConstantInputNodes() { |
| return constantInputNodes; |
| } |
| |
| public @NonNull Iterable<@NonNull Node> getConstantOutputNodes() { |
| return constantOutputNodes; |
| } |
| |
| // @Override |
| @Override |
| public @Nullable Iterable<@NonNull TraceClassPartitionAnalysis> getConsumedTraceClassAnalyses() { |
| return consumedTraceClassAnalyses; |
| } |
| |
| // @Override |
| @Override |
| public @Nullable Iterable<@NonNull TracePropertyPartitionAnalysis> getConsumedTracePropertyAnalyses() { |
| return consumedTracePropertyAnalyses; |
| } |
| |
| /* public @NonNull SuccessEdge getGlobalSuccessEdge(@NonNull Node traceNode) { |
| return ClassUtil.nonNullState(traceNode2globalSuccessEdge.get(traceNode)); |
| } |
| |
| public @NonNull Node getGlobalSuccessNode(@NonNull Node traceNode) { |
| SuccessEdge successEdge = ClassUtil.nonNullState(traceNode2globalSuccessEdge.get(traceNode)); |
| return QVTscheduleUtil.getTargetNode(successEdge); |
| } |
| |
| public @NonNull SuccessEdge getLocalSuccessEdge(@NonNull Node traceNode) { |
| return ClassUtil.nonNullState(traceNode2localSuccessEdge.get(traceNode)); |
| } |
| |
| public @NonNull Node getLocalSuccessNode(@NonNull Node traceNode) { |
| SuccessEdge successEdge = ClassUtil.nonNullState(traceNode2localSuccessEdge.get(traceNode)); |
| return QVTscheduleUtil.getTargetNode(successEdge); |
| } */ |
| |
| public @NonNull Iterable<@NonNull NavigableEdge> getOldPrimaryNavigableEdges() { |
| return oldPrimaryNavigableEdges; |
| } |
| |
| public @NonNull Iterable<@NonNull Edge> getPredicatedEdges() { |
| return predicatedEdges; |
| } |
| |
| public @NonNull Iterable<@NonNull Node> getPredicatedMiddleNodes() { |
| return predicatedMiddleNodes; |
| } |
| |
| public @NonNull Iterable<@NonNull Node> getPredicatedOutputNodes() { |
| return predicatedOutputNodes; |
| } |
| |
| @Override |
| public @Nullable Iterable<@NonNull TraceClassPartitionAnalysis> getProducedTraceClassAnalyses() { |
| return producedTraceClassAnalyses; |
| } |
| |
| @Override |
| public @Nullable Iterable<@NonNull TracePropertyPartitionAnalysis> getProducedTracePropertyAnalyses() { |
| return producedTracePropertyAnalyses; |
| } |
| |
| public abstract @NonNull ReachabilityForest getReachabilityForest(); |
| |
| public @NonNull Iterable<@NonNull NavigableEdge> getRealizedEdges() { |
| return realizedEdges; |
| } |
| |
| public @NonNull Iterable<@NonNull Node> getRealizedMiddleNodes() { |
| return realizedMiddleNodes; |
| } |
| |
| public @NonNull Iterable<@NonNull NavigableEdge> getRealizedOutputEdges() { |
| return realizedOutputEdges; |
| } |
| |
| public @NonNull Iterable<@NonNull Node> getRealizedOutputNodes() { |
| return realizedOutputNodes; |
| } |
| |
| public @NonNull Iterable<@NonNull SuccessEdge> getSuccessEdges() { |
| return successEdges; |
| } |
| |
| @Override |
| public @Nullable Iterable<@NonNull TraceClassPartitionAnalysis> getSuperProducedTraceClassAnalyses() { |
| List<@NonNull TraceClassPartitionAnalysis> producedTraceClassAnalyses2 = producedTraceClassAnalyses; |
| if (producedTraceClassAnalyses2 != null) { |
| Set<@NonNull TraceClassPartitionAnalysis> superProducedTraceClassAnalyses2 = superProducedTraceClassAnalyses; |
| if (superProducedTraceClassAnalyses2 == null) { |
| superProducedTraceClassAnalyses = superProducedTraceClassAnalyses2 = new HashSet<>(); |
| } |
| for (@NonNull TraceClassPartitionAnalysis producedTraceClassAnalysis : producedTraceClassAnalyses2) { |
| Iterables.addAll(superProducedTraceClassAnalyses2, producedTraceClassAnalysis.getSuperTraceClassAnalyses()); |
| } |
| } |
| return superProducedTraceClassAnalyses; |
| } |
| |
| /* public @Nullable Edge getTraceEdge(@NonNull Node node) { |
| return node2traceEdge.get(node); |
| } */ |
| |
| @Override |
| public @NonNull List<@NonNull Node> getTraceNodes() { |
| return traceNodes; |
| } |
| |
| protected boolean isConstant(@NonNull Edge edge) { |
| Role role = partition.getRole(edge); |
| assert role != null; |
| return role.isConstant(); |
| } |
| |
| protected boolean isConstant(@NonNull Node node) { |
| Role role = partition.getRole(node); |
| assert role != null; |
| return role.isConstant(); |
| } |
| |
| protected boolean isLoaded(@NonNull Edge edge) { |
| Role role = partition.getRole(edge); |
| assert role != null; |
| return role.isLoaded(); |
| } |
| |
| protected boolean isLoaded(@NonNull Node node) { |
| Role role = partition.getRole(node); |
| assert role != null; |
| return role.isLoaded(); |
| } |
| |
| protected boolean isNew(@NonNull Edge edge) { |
| Role role = partition.getRole(edge); |
| assert role != null; |
| return role.isNew(); |
| } |
| |
| protected boolean isNew(@NonNull Node node) { |
| Role role = partition.getRole(node); |
| assert role != null; |
| return role.isNew(); |
| } |
| |
| protected boolean isOld(@NonNull Edge edge) { |
| Role role = partition.getRole(edge); |
| assert role != null; |
| return role.isOld(); |
| } |
| |
| protected boolean isPredicated(@NonNull Edge edge) { |
| Role role = partition.getRole(edge); |
| assert role != null; |
| return role.isPredicated(); |
| } |
| |
| protected boolean isPredicated(@NonNull Node node) { |
| Role role = partition.getRole(node); |
| assert role != null; |
| return role.isPredicated(); |
| } |
| |
| protected boolean isRealized(@NonNull Edge edge) { |
| Role role = partition.getRole(edge); |
| assert role != null; |
| return role.isRealized(); |
| } |
| |
| protected boolean isRealized(@NonNull Node node) { |
| Role role = partition.getRole(node); |
| assert role != null; |
| return role.isRealized(); |
| } |
| |
| protected boolean isSpeculated(@NonNull Edge edge) { |
| Role role = partition.getRole(edge); |
| assert role != null; |
| return role.isSpeculated(); |
| } |
| |
| protected boolean isSpeculated(@NonNull Node node) { |
| Role role = partition.getRole(node); |
| assert role != null; |
| return role.isSpeculated(); |
| } |
| |
| protected boolean isSpeculation(@NonNull Node node) { |
| Role role = partition.getRole(node); |
| assert role != null; |
| return role.isSpeculation(); |
| } |
| } |