All Downloads are FREE. Search and download functionalities are using the official Maven repository.

sync.pds.solver.SyncPDSSolver Maven / Gradle / Ivy

There is a newer version: 3.2.2
Show newest version
/**
 * ***************************************************************************** Copyright (c) 2018
 * Fraunhofer IEM, Paderborn, Germany. This program and the accompanying materials are made
 * available under the terms of the Eclipse Public License 2.0 which is available at
 * http://www.eclipse.org/legal/epl-2.0.
 *
 * 

SPDX-License-Identifier: EPL-2.0 * *

Contributors: Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package sync.pds.solver; import com.google.common.base.Objects; import com.google.common.collect.HashMultimap; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multimap; import com.google.common.collect.Sets; import java.util.AbstractMap; import java.util.Collection; import java.util.HashSet; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import org.slf4j.LoggerFactory; import sync.pds.solver.nodes.ExclusionNode; import sync.pds.solver.nodes.GeneratedState; import sync.pds.solver.nodes.INode; import sync.pds.solver.nodes.Node; import sync.pds.solver.nodes.NodeWithLocation; import sync.pds.solver.nodes.PopNode; import sync.pds.solver.nodes.PushNode; import sync.pds.solver.nodes.SingleNode; import wpds.impl.NestedAutomatonListener; import wpds.impl.NestedWeightedPAutomatons; import wpds.impl.NormalRule; import wpds.impl.PopRule; import wpds.impl.PushRule; import wpds.impl.Rule; import wpds.impl.Transition; import wpds.impl.Weight; import wpds.impl.WeightedPAutomaton; import wpds.impl.WeightedPushdownSystem; import wpds.interfaces.Location; import wpds.interfaces.State; import wpds.interfaces.WPAStateListener; import wpds.interfaces.WPAUpdateListener; public abstract class SyncPDSSolver< Stmt extends Location, Fact, Field extends Location, W extends Weight> { public enum PDSSystem { FIELDS, CALLS } private static final org.slf4j.Logger logger = LoggerFactory.getLogger(SyncPDSSolver.class); private static final boolean FieldSensitive = true; private static final boolean ContextSensitive = true; protected final WeightedPushdownSystem, W> callingPDS = new WeightedPushdownSystem, W>() { public String toString() { return "Call " + SyncPDSSolver.this.toString(); } ; }; protected final WeightedPushdownSystem>, W> fieldPDS = new WeightedPushdownSystem>, W>() { public String toString() { return "Field " + SyncPDSSolver.this.toString(); } ; }; private final Set> reachedStates = Sets.newHashSet(); private final Set> callingContextReachable = Sets.newHashSet(); private final Set> fieldContextReachable = Sets.newHashSet(); private final Set> updateListeners = Sets.newHashSet(); private final Multimap, SyncStatePDSUpdateListener> reachedStateUpdateListeners = HashMultimap.create(); protected final WeightedPAutomaton>, W> fieldAutomaton; protected final WeightedPAutomaton, W> callAutomaton; protected boolean preventFieldTransitionAdd( Transition>> trans, W weight) { return false; } protected boolean preventCallTransitionAdd(Transition> trans, W weight) { return false; } public SyncPDSSolver( final boolean useCallSummaries, NestedWeightedPAutomatons, W> callSummaries, final boolean useFieldSummaries, NestedWeightedPAutomatons>, W> fieldSummaries, int maxCallDepth, int maxFieldDepth, int maxUnbalancedCallDepth) { fieldAutomaton = new WeightedPAutomaton>, W>() { @Override public INode> createState(INode> d, Field loc) { if (loc.equals(emptyField())) return d; return generateFieldState(d, loc); } @Override public Field epsilon() { return epsilonField(); } @Override public boolean nested() { return useFieldSummaries; } ; @Override public W getOne() { return getFieldWeights().getOne(); } @Override public int getMaxDepth() { return maxFieldDepth; } public boolean addWeightForTransition( Transition>> trans, W weight) { if (preventFieldTransitionAdd(trans, weight)) return false; logger.trace("Adding field transition {} with weight {}", trans, weight); return super.addWeightForTransition(trans, weight); } ; @Override public boolean isGeneratedState(INode> d) { return d instanceof GeneratedState; } }; callAutomaton = new WeightedPAutomaton, W>() { @Override public INode createState(INode d, Stmt loc) { return generateCallState(d, loc); } @Override public Stmt epsilon() { return epsilonStmt(); } @Override public boolean nested() { return useCallSummaries; } ; @Override public W getOne() { return getCallWeights().getOne(); } public boolean addWeightForTransition(Transition> trans, W weight) { if (preventCallTransitionAdd(trans, weight)) return false; logger.trace("Adding call transition {} with weight {}", trans, weight); return super.addWeightForTransition(trans, weight); } ; @Override public boolean isGeneratedState(INode d) { return d instanceof GeneratedState; } @Override public int getMaxDepth() { return maxCallDepth; } @Override public int getMaxUnbalancedDepth() { return maxUnbalancedCallDepth; } }; callAutomaton.registerListener(new CallAutomatonListener()); fieldAutomaton.registerListener(new FieldUpdateListener()); if (callAutomaton.nested()) callAutomaton.registerNestedAutomatonListener(new CallSummaryListener()); // if(fieldAutomaton.nested()) // fieldAutomaton.registerNestedAutomatonListener(new FieldSummaryListener()); callingPDS.poststar(callAutomaton, callSummaries); fieldPDS.poststar(fieldAutomaton, fieldSummaries); } private class FieldSummaryListener implements NestedAutomatonListener>, W> { @Override public void nestedAutomaton( final WeightedPAutomaton>, W> parent, final WeightedPAutomaton>, W> child) { for (INode> s : child.getInitialStates()) { child.registerListener(new FieldAddEpsilonToInitialStateListener(s, parent)); } } } private class FieldAddEpsilonToInitialStateListener extends WPAStateListener>, W> { private WeightedPAutomaton>, W> parent; public FieldAddEpsilonToInitialStateListener( INode> state, WeightedPAutomaton>, W> parent) { super(state); this.parent = parent; } @Override public void onOutTransitionAdded( Transition>> t, W w, WeightedPAutomaton>, W> weightedPAutomaton) {} @Override public void onInTransitionAdded( final Transition>> nestedT, W w, WeightedPAutomaton>, W> weightedPAutomaton) { if (nestedT.getLabel().equals(fieldAutomaton.epsilon())) { parent.registerListener( new FieldOnOutTransitionAddToStateListener(this.getState(), nestedT)); } } @Override public int hashCode() { final int prime = 31; int result = super.hashCode(); result = prime * result + getOuterType().hashCode(); result = prime * result + ((parent == null) ? 0 : parent.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (!super.equals(obj)) return false; if (getClass() != obj.getClass()) return false; FieldAddEpsilonToInitialStateListener other = (FieldAddEpsilonToInitialStateListener) obj; if (!getOuterType().equals(other.getOuterType())) return false; if (parent == null) { if (other.parent != null) return false; } else if (!parent.equals(other.parent)) return false; return true; } private SyncPDSSolver getOuterType() { return SyncPDSSolver.this; } } private class FieldOnOutTransitionAddToStateListener extends WPAStateListener>, W> { private Transition>> nestedT; public FieldOnOutTransitionAddToStateListener( INode> state, Transition>> nestedT) { super(state); this.nestedT = nestedT; } @Override public void onOutTransitionAdded( Transition>> t, W w, WeightedPAutomaton>, W> weightedPAutomaton) { setFieldContextReachable(nestedT.getStart().fact()); } @Override public void onInTransitionAdded( Transition>> t, W w, WeightedPAutomaton>, W> weightedPAutomaton) {} @Override public int hashCode() { final int prime = 31; int result = super.hashCode(); result = prime * result + getOuterType().hashCode(); result = prime * result + ((nestedT == null) ? 0 : nestedT.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (!super.equals(obj)) return false; if (getClass() != obj.getClass()) return false; FieldOnOutTransitionAddToStateListener other = (FieldOnOutTransitionAddToStateListener) obj; if (!getOuterType().equals(other.getOuterType())) return false; if (nestedT == null) { if (other.nestedT != null) return false; } else if (!nestedT.equals(other.nestedT)) return false; return true; } private SyncPDSSolver getOuterType() { return SyncPDSSolver.this; } } private class CallSummaryListener implements NestedAutomatonListener, W> { @Override public void nestedAutomaton( final WeightedPAutomaton, W> parent, final WeightedPAutomaton, W> child) { for (INode s : child.getInitialStates()) { child.registerListener(new AddEpsilonToInitialStateListener(s, parent)); } } } private class AddEpsilonToInitialStateListener extends WPAStateListener, W> { private WeightedPAutomaton, W> parent; public AddEpsilonToInitialStateListener( INode state, WeightedPAutomaton, W> parent) { super(state); this.parent = parent; } @Override public void onOutTransitionAdded( Transition> t, W w, WeightedPAutomaton, W> weightedPAutomaton) {} @Override public void onInTransitionAdded( final Transition> nestedT, W w, WeightedPAutomaton, W> weightedPAutomaton) { if (nestedT.getLabel().equals(callAutomaton.epsilon())) { parent.registerListener(new OnOutTransitionAddToStateListener(this.getState(), nestedT)); } } @Override public int hashCode() { final int prime = 31; int result = super.hashCode(); result = prime * result + getOuterType().hashCode(); result = prime * result + ((parent == null) ? 0 : parent.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (!super.equals(obj)) return false; if (getClass() != obj.getClass()) return false; AddEpsilonToInitialStateListener other = (AddEpsilonToInitialStateListener) obj; if (!getOuterType().equals(other.getOuterType())) return false; if (parent == null) { if (other.parent != null) return false; } else if (!parent.equals(other.parent)) return false; return true; } private SyncPDSSolver getOuterType() { return SyncPDSSolver.this; } } private class OnOutTransitionAddToStateListener extends WPAStateListener, W> { private Transition> nestedT; public OnOutTransitionAddToStateListener( INode state, Transition> nestedT) { super(state); this.nestedT = nestedT; } @Override public void onOutTransitionAdded( Transition> t, W w, WeightedPAutomaton, W> weightedPAutomaton) { Node returningNode = new Node(t.getLabel(), nestedT.getStart().fact()); setCallingContextReachable(returningNode); } @Override public void onInTransitionAdded( Transition> t, W w, WeightedPAutomaton, W> weightedPAutomaton) {} @Override public int hashCode() { final int prime = 31; int result = super.hashCode(); result = prime * result + getOuterType().hashCode(); result = prime * result + ((nestedT == null) ? 0 : nestedT.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (!super.equals(obj)) return false; if (getClass() != obj.getClass()) return false; OnOutTransitionAddToStateListener other = (OnOutTransitionAddToStateListener) obj; if (!getOuterType().equals(other.getOuterType())) return false; if (nestedT == null) { if (other.nestedT != null) return false; } else if (!nestedT.equals(other.nestedT)) return false; return true; } private SyncPDSSolver getOuterType() { return SyncPDSSolver.this; } } private class CallAutomatonListener implements WPAUpdateListener, W> { @Override public void onWeightAdded( Transition> t, W w, WeightedPAutomaton, W> aut) { if (!(t.getStart() instanceof GeneratedState) && !t.getLabel().equals(callAutomaton.epsilon())) { Node node = new Node(t.getLabel(), t.getStart().fact()); setCallingContextReachable(node); } } } public void solve( Node curr, Field field, INode> fieldTarget, Stmt stmt, INode callTarget, W weight) { fieldAutomaton.addInitialState(fieldTarget); callAutomaton.addInitialState(callTarget); INode> start = asFieldFact(curr); if (!field.equals(emptyField())) { INode> generateFieldState = generateFieldState(start, field); Transition>> fieldTrans = new Transition<>(start, field, generateFieldState); fieldAutomaton.addTransition(fieldTrans); Transition>> fieldTransToInitial = new Transition<>(generateFieldState, emptyField(), fieldTarget); fieldAutomaton.addTransition(fieldTransToInitial); } else { Transition>> fieldTrans = new Transition<>(start, emptyField(), fieldTarget); fieldAutomaton.addTransition(fieldTrans); } Transition> callTrans = new Transition<>(wrap(curr.fact()), curr.stmt(), callTarget); callAutomaton.addWeightForTransition(callTrans, weight); processNode(curr); } public void solve( Node curr, Field field, INode> fieldTarget, Stmt stmt, INode callTarget) { solve(curr, field, fieldTarget, stmt, callTarget, getCallWeights().getOne()); } public void processNode(Node curr) { if (!addReachableState(curr)) return; computeSuccessor(curr); } public void propagate(Node curr, State s) { if (s instanceof Node) { Node succ = (Node) s; if (succ instanceof PushNode) { PushNode pushNode = (PushNode) succ; PDSSystem system = pushNode.system(); Location location = pushNode.location(); processPush(curr, location, pushNode, system); } else { processNormal(curr, succ); } } else if (s instanceof PopNode) { PopNode popNode = (PopNode) s; processPop(curr, popNode); } } private boolean addReachableState(Node curr) { if (reachedStates.contains(curr)) return false; reachedStates.add(curr); for (SyncPDSUpdateListener l : Lists.newLinkedList(updateListeners)) { l.onReachableNodeAdded(curr); } for (SyncStatePDSUpdateListener l : Lists.newLinkedList(reachedStateUpdateListeners.get(curr))) { l.reachable(); } return true; } public void processNormal(Node curr, Node succ) { addNormalFieldFlow(curr, succ); addNormalCallFlow(curr, succ); } public void addNormalCallFlow(Node curr, Node succ) { addCallRule( new NormalRule<>( wrap(curr.fact()), curr.stmt(), wrap(succ.fact()), succ.stmt(), getCallWeights().normal(curr, succ))); } public void addNormalFieldFlow(final Node curr, final Node succ) { if (succ instanceof ExclusionNode) { ExclusionNode exNode = (ExclusionNode) succ; addFieldRule( new NormalRule<>( asFieldFact(curr), fieldWildCard(), asFieldFact(succ), exclusionFieldWildCard(exNode.exclusion()), getFieldWeights().normal(curr, succ))); return; } addFieldRule( new NormalRule<>( asFieldFact(curr), fieldWildCard(), asFieldFact(succ), fieldWildCard(), getFieldWeights().normal(curr, succ))); } public INode> asFieldFact(Node node) { return new SingleNode<>(new Node<>(node.stmt(), node.fact())); } public void processPop(Node curr, PopNode popNode) { PDSSystem system = popNode.system(); Object location = popNode.location(); if (system.equals(PDSSystem.FIELDS)) { NodeWithLocation node = (NodeWithLocation) location; if (FieldSensitive) { addFieldRule( new PopRule<>( asFieldFact(curr), node.location(), asFieldFact(node.fact()), getFieldWeights().pop(curr))); } else { addNormalFieldFlow(curr, node.fact()); } addNormalCallFlow(curr, node.fact()); } else if (system.equals(PDSSystem.CALLS)) { if (ContextSensitive) { addCallRule( new PopRule<>( wrap(curr.fact()), curr.stmt(), wrap((Fact) location), getCallWeights().pop(curr))); } } } private void applyCallSummary(Stmt callSite, Fact factInCallee, Stmt spInCallee) { callAutomaton.addSummaryListener( t -> { GeneratedState genSt = ((GeneratedState) t.getTarget()); Stmt sp = genSt.location(); Fact v = genSt.node().fact(); Stmt exitStmt = t.getLabel(); Fact returnedFact = t.getStart().fact(); if (spInCallee.equals(sp) && factInCallee.equals(v)) { if (summaries.add( new Summary(callSite, factInCallee, spInCallee, exitStmt, returnedFact))) { for (OnAddedSummaryListener s : Lists.newArrayList(summaryListeners)) { s.apply(callSite, factInCallee, spInCallee, exitStmt, returnedFact); } } // TODO can be removed and applyCallSummary(callSite, factInCallee, spInCallee, exitStmt, returnedFact); } }); } Set

summaries = Sets.newHashSet(); Set summaryListeners = Sets.newHashSet(); public void addApplySummaryListener(OnAddedSummaryListener l) { if (summaryListeners.add(l)) { for (Summary s : Lists.newArrayList(summaries)) { l.apply(s.callSite, s.factInCallee, s.spInCallee, s.exitStmt, s.returnedFact); } } } public interface OnAddedSummaryListener { void apply(Stmt callSite, Fact factInCallee, Stmt spInCallee, Stmt exitStmt, Fact returnedFact); } private class Summary { private final Stmt callSite; private final Fact factInCallee; private final Stmt spInCallee; private final Stmt exitStmt; private final Fact returnedFact; private Summary( Stmt callSite, Fact factInCallee, Stmt spInCallee, Stmt exitStmt, Fact returnedFact) { this.callSite = callSite; this.factInCallee = factInCallee; this.spInCallee = spInCallee; this.exitStmt = exitStmt; this.returnedFact = returnedFact; } @Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } Summary summary = (Summary) o; return Objects.equal(callSite, summary.callSite) && Objects.equal(factInCallee, summary.factInCallee) && Objects.equal(spInCallee, summary.spInCallee) && Objects.equal(exitStmt, summary.exitStmt) && Objects.equal(returnedFact, summary.returnedFact); } @Override public int hashCode() { return Objects.hashCode(callSite, factInCallee, spInCallee, exitStmt, returnedFact); } } public abstract void applyCallSummary( Stmt callSite, Fact factInCallee, Stmt spInCallee, Stmt exitStmt, Fact returnedFact); public void processPush( Node curr, Location location, PushNode succ, PDSSystem system) { if (system.equals(PDSSystem.FIELDS)) { if (FieldSensitive) { addFieldRule( new PushRule<>( asFieldFact(curr), fieldWildCard(), asFieldFact(succ), (Field) location, fieldWildCard(), getFieldWeights().push(curr, succ, (Field) location))); } else { addNormalFieldFlow(curr, succ); } addNormalCallFlow(curr, succ); } else if (system.equals(PDSSystem.CALLS)) { addNormalFieldFlow(curr, succ); if (ContextSensitive) { addCallRule( new PushRule<>( wrap(curr.fact()), curr.stmt(), wrap(succ.fact()), succ.stmt(), (Stmt) location, getCallWeights().push(curr, succ, (Stmt) location))); } else { addNormalCallFlow(curr, succ); } applyCallSummary((Stmt) location, succ.fact(), succ.stmt()); } } public void addCallRule(Rule, W> rule) { callingPDS.addRule(rule); } public void addFieldRule(Rule>, W> rule) { fieldPDS.addRule(rule); } public abstract WeightFunctions getFieldWeights(); public abstract WeightFunctions getCallWeights(); private class FieldUpdateListener implements WPAUpdateListener>, W> { @Override public void onWeightAdded( Transition>> t, W w, WeightedPAutomaton>, W> aut) { INode> n = t.getStart(); if (!(n instanceof GeneratedState) && !t.getLabel().equals(fieldAutomaton.epsilon())) { Node fact = n.fact(); Node node = new Node(fact.stmt(), fact.fact()); setFieldContextReachable(node); } } } private void setCallingContextReachable(Node node) { if (!callingContextReachable.add(node)) return; if (fieldContextReachable.contains(node)) { processNode(node); } } private void setFieldContextReachable(Node node) { if (!fieldContextReachable.add(node)) { return; } if (callingContextReachable.contains(node)) { processNode(node); } } public void registerListener(SyncPDSUpdateListener listener) { if (!updateListeners.add(listener)) { return; } for (Node reachableNode : Lists.newArrayList(reachedStates)) { listener.onReachableNodeAdded(reachableNode); } } public void registerListener(SyncStatePDSUpdateListener listener) { if (!reachedStateUpdateListeners.put(listener.getNode(), listener)) { return; } if (reachedStates.contains(listener.getNode())) { listener.reachable(); } } protected INode wrap(Fact variable) { return new SingleNode(variable); } protected Map, Stmt>, INode> generatedCallState = Maps.newHashMap(); public INode generateCallState(final INode d, final Stmt loc) { Entry, Stmt> e = new AbstractMap.SimpleEntry<>(d, loc); if (!generatedCallState.containsKey(e)) { generatedCallState.put(e, new GeneratedState(d, loc)); } return generatedCallState.get(e); } Map>, Field>, INode>> generatedFieldState = Maps.newHashMap(); public INode> generateFieldState( final INode> d, final Field loc) { Entry>, Field> e = new AbstractMap.SimpleEntry<>(d, loc); if (!generatedFieldState.containsKey(e)) { generatedFieldState.put(e, new GeneratedState, Field>(d, loc)); } return generatedFieldState.get(e); } public void addGeneratedFieldState(GeneratedState, Field> state) { Entry>, Field> e = new AbstractMap.SimpleEntry<>(state.node(), state.location()); generatedFieldState.put(e, state); } public abstract void computeSuccessor(Node node); public abstract Field epsilonField(); public abstract Field emptyField(); public abstract Stmt epsilonStmt(); public abstract Field exclusionFieldWildCard(Field exclusion); public abstract Field fieldWildCard(); public Set> getReachedStates() { return Sets.newHashSet(reachedStates); } public void debugOutput() { logger.debug(this.getClass().toString()); logger.debug("All reachable states"); prettyPrintSet(getReachedStates()); HashSet> notFieldReachable = Sets.newHashSet(callingContextReachable); notFieldReachable.removeAll(getReachedStates()); HashSet> notCallingContextReachable = Sets.newHashSet(fieldContextReachable); notCallingContextReachable.removeAll(getReachedStates()); if (!notFieldReachable.isEmpty()) { logger.debug("Calling context reachable"); prettyPrintSet(notFieldReachable); } if (!notCallingContextReachable.isEmpty()) { logger.debug("Field matching reachable"); prettyPrintSet(notCallingContextReachable); } logger.debug(fieldPDS.toString()); logger.debug(fieldAutomaton.toDotString()); logger.debug(callingPDS.toString()); logger.debug(callAutomaton.toDotString()); logger.debug("===== end === " + this.getClass()); } private void prettyPrintSet(Collection set) { int j = 0; String s = ""; for (Object reachableState : set) { s += reachableState; s += "\t"; if (j++ > 5) { s += "\n"; j = 0; } } logger.debug(s); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy