blob: 0fe3ea13bc9c1e435ff95fa594c94dcf6b773f2c [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2012, 2016 CEA LIST 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(CEA LIST) - Initial API and implementation
*******************************************************************************/
package org.eclipse.ocl.examples.codegen.cse;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.ocl.examples.codegen.analyzer.CodeGenAnalyzer;
import org.eclipse.ocl.examples.codegen.analyzer.DependencyVisitor;
import org.eclipse.ocl.examples.codegen.cgmodel.CGElement;
import org.eclipse.ocl.examples.codegen.cgmodel.CGText;
import org.eclipse.ocl.examples.codegen.cgmodel.CGValuedElement;
import org.eclipse.ocl.pivot.utilities.ClassUtil;
import org.eclipse.ocl.pivot.utilities.TracingOption;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;
/**
* A ControlPlace is associated with a location in the CG AST such as the then or else (but not condition) ig a CGIfExp
* at which child nodes cannot be hoisted without violating control dependencies.
*/
public class ControlPlace extends LocalPlace
{
public static @NonNull AbstractPlace createControlPlace(@NonNull Map<@Nullable CGElement, @NonNull AbstractPlace> element2place, @NonNull CGValuedElement cgElement) {
if (cgElement.isGlobal()) {
return ClassUtil.nonNullState(element2place.get(null));
}
CGElement cgParent = cgElement.getParent();
AbstractPlace parentPlace = element2place.get(cgParent);
if (parentPlace instanceof ControlPlace) {
return parentPlace;
}
else {
return new ControlPlace(getLocalPlace(element2place, cgParent), cgElement);
}
}
public static @NonNull ControlPlace getControlPlace(@NonNull Map<@Nullable CGElement, @NonNull AbstractPlace> element2place, @NonNull CGValuedElement cgElement) {
AbstractPlace place = element2place.get(cgElement);
if (place instanceof ControlPlace) {
return (ControlPlace) place;
}
else if (place != null) {
throw new IllegalStateException("Non-ControlPlace " + place.getClass().getName() + " for " + cgElement);
}
else {
ControlPlace controlPlace;
CGElement cgParent = cgElement.getParent();
AbstractPlace parentPlace = element2place.get(cgParent);
if (parentPlace instanceof ControlPlace) {
controlPlace = (ControlPlace) parentPlace;
}
else {
controlPlace = new ControlPlace(getLocalPlace(element2place, cgParent), cgElement);
}
element2place.put(cgElement, controlPlace);
return controlPlace;
}
}
protected final @NonNull LocalPlace parentPlace;
protected final @NonNull CGValuedElement placedElement;
private /*@LazyNonNull*/ SimpleAnalysis controlAnalysis = null;
protected final @NonNull HashedAnalyses hashedAnalyses = new HashedAnalyses();
public ControlPlace(@NonNull LocalPlace parentPlace, @NonNull CGValuedElement cgElement) {
super(parentPlace.getGlobalPlace());
this.parentPlace = parentPlace;
this.placedElement = cgElement;
parentPlace.addControlPlace(this);
}
public void addAnalysis(@NonNull AbstractAnalysis anAnalysis) {
hashedAnalyses.add(anAnalysis);
}
public int getDepth() {
return controlAnalysis.getDepth();
}
public @NonNull HashedAnalyses getHashedAnalyses() {
return hashedAnalyses;
}
@Override
public @NonNull LocalPlace getParentPlace() {
return parentPlace;
}
public @NonNull SimpleAnalysis getSimpleAnalysis() {
SimpleAnalysis controlAnalysis2 = controlAnalysis;
if (controlAnalysis2 == null) {
// System.out.println(ClassUtil.debugSimpleName(placedElement));
controlAnalysis2 = globalPlace.getSimpleAnalysis(placedElement);
assert controlAnalysis2 != null;
controlAnalysis = controlAnalysis2;
}
return controlAnalysis2;
}
@Override
public @NonNull StackPlace getStackPlace() {
return parentPlace.getStackPlace();
}
@Override
public void printHierarchy(@NonNull Appendable appendable, @NonNull String indentation) {
TracingOption.println(appendable, indentation + this);
if (!hashedAnalyses.isEmpty()) {
for (AbstractAnalysis analysis : hashedAnalyses) {
TracingOption.println(appendable, indentation + " " + analysis.getStructuralHashCode() + "," + analysis);
}
}
else {
TracingOption.println(appendable, indentation + " <empty>");
}
super.printHierarchy(appendable, indentation + " ");
}
/**
* Filter the element analyses to discard non-SharedAnalysis and to return a partitioning of the results by minimum depth.
*/
@Override
public void prune() {
if (!hashedAnalyses.isEmpty()) {
List<@NonNull AbstractAnalysis> removals = null;
@SuppressWarnings("null")@NonNull Multimap<@NonNull Integer, @NonNull CommonAnalysis> depth2commonAnalyses = HashMultimap.create();
for (@NonNull AbstractAnalysis analysis : hashedAnalyses) {
if (analysis instanceof CommonAnalysis) {
CommonAnalysis commonAnalysis = (CommonAnalysis)analysis;
int depth = commonAnalysis.getMinDepth();
depth2commonAnalyses.put(depth, commonAnalysis);
}
else {
if (removals == null) {
removals = new ArrayList<>();
}
removals.add(analysis);
}
}
if (removals != null) {
for (@NonNull AbstractAnalysis removal : removals) {
hashedAnalyses.remove(removal);
}
}
}
}
@Override
public void pullUp() {
List<@NonNull AbstractAnalysis> removals = null;
for (@NonNull AbstractAnalysis analysis : hashedAnalyses) {
for (AbstractPlace localPlace = this; !((localPlace = localPlace.getParentPlace()) instanceof GlobalPlace); ) {
if (localPlace instanceof ControlPlace) {
ControlPlace controlPlace = (ControlPlace) localPlace;
HashedAnalyses controlAnalyses = controlPlace.getHashedAnalyses();
AbstractAnalysis parentAnalysis = controlAnalyses.get(analysis);
if (parentAnalysis != null) {
controlPlace.addAnalysis(analysis);
if (removals == null) {
removals = new ArrayList<>();
}
removals.add(analysis);
break;
}
}
}
}
if (removals != null) {
for (@NonNull AbstractAnalysis removal : removals) {
hashedAnalyses.remove(removal);
}
}
super.pullUp();
}
@Override
public void pushUp() {
super.pushUp();
//
// This is a pragmatic fudge to share "evaluator"
//
if (!hashedAnalyses.isEmpty()) {
List<@NonNull AbstractAnalysis> pushUps = null;
for (AbstractAnalysis analysis : hashedAnalyses) {
CGValuedElement primaryElement = analysis.getPrimaryElement();
if (primaryElement instanceof CGText) {
if (pushUps == null) {
pushUps = new ArrayList<>();
}
pushUps.add(analysis);
}
}
if (pushUps != null) {
LocalPlace parentPlace = getParentPlace();
if (parentPlace instanceof ControlPlace) {
ControlPlace controlParentPlace = (ControlPlace)parentPlace;
for (@NonNull AbstractAnalysis analysis : pushUps) {
hashedAnalyses.remove(analysis);
controlParentPlace.addAnalysis(analysis);
}
}
}
}
}
@Override
public void rewrite() {
super.rewrite();
CodeGenAnalyzer analyzer = globalPlace.getAnalyzer();
if (!hashedAnalyses.isEmpty()) {
Map<@NonNull CGValuedElement, @NonNull AbstractAnalysis> locals = new HashMap<>();
for (@NonNull AbstractAnalysis analysis : hashedAnalyses) {
locals.put(analysis.getPrimaryElement(), analysis);
}
DependencyVisitor dependencyVisitor = analyzer.getCodeGenerator().createDependencyVisitor();
HashSet<@NonNull CGValuedElement> allElements = new HashSet<>(locals.keySet());
dependencyVisitor.visitAll(allElements);
Iterable<@NonNull CGValuedElement> sortedDependencies = dependencyVisitor.getSortedDependencies(false);
for (@NonNull CGValuedElement primaryElement : sortedDependencies) {
AbstractAnalysis abstractAnalysis = locals.get(primaryElement);
if (abstractAnalysis instanceof CommonAnalysis) {
((CommonAnalysis)abstractAnalysis).rewrite(analyzer, placedElement);
}
}
}
}
@Override
public String toString() {
SimpleAnalysis controlAnalysis2 = controlAnalysis;
if (controlAnalysis2 == null) {
// System.out.println(ClassUtil.debugSimpleName(placedElement));
controlAnalysis2 = globalPlace.getSimpleAnalysis(placedElement);
}
return getClass().getSimpleName() + ": " + String.valueOf(controlAnalysis2);
}
}