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

com.ibm.wala.fixedpoint.impl.AbstractFixedPointSolver Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2002 - 2006 IBM Corporation.
 * 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:
 *     IBM Corporation - initial API and implementation
 */
package com.ibm.wala.fixedpoint.impl;

import com.ibm.wala.fixpoint.AbstractOperator;
import com.ibm.wala.fixpoint.AbstractStatement;
import com.ibm.wala.fixpoint.FixedPointConstants;
import com.ibm.wala.fixpoint.IFixedPointSolver;
import com.ibm.wala.fixpoint.IFixedPointStatement;
import com.ibm.wala.fixpoint.IVariable;
import com.ibm.wala.fixpoint.UnaryOperator;
import com.ibm.wala.fixpoint.UnaryStatement;
import com.ibm.wala.util.CancelException;
import com.ibm.wala.util.MonitorUtil;
import com.ibm.wala.util.MonitorUtil.IProgressMonitor;
import com.ibm.wala.util.collections.Iterator2Iterable;
import com.ibm.wala.util.debug.VerboseAction;
import com.ibm.wala.util.graph.INodeWithNumber;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.jspecify.annotations.Nullable;

/**
 * Represents a set of {@link IFixedPointStatement}s to be solved by a {@link IFixedPointSolver}
 *
 * 

Implementation Note: * *

The set of steps and variables is internally represented as a graph. Each step and each * variable is a node in the graph. If a step produces a variable that is used by another step, the * graph has a directed edge from the producer to the consumer. Fixed-point iteration proceeds in a * topological order according to these edges. */ @SuppressWarnings("rawtypes") public abstract class AbstractFixedPointSolver> implements IFixedPointSolver, FixedPointConstants, VerboseAction { static final boolean DEBUG = false; public static final boolean verbose = "true".equals(System.getProperty("com.ibm.wala.fixedpoint.impl.verbose")); public static final int DEFAULT_VERBOSE_INTERVAL = 100000; static final boolean MORE_VERBOSE = true; public static final int DEFAULT_PERIODIC_MAINTENANCE_INTERVAL = 100000; /** * A tuning parameter; how may new IStatementDefinitionss must be added before doing a new * topological sort? TODO: Tune this empirically. */ private int minSizeForTopSort = 0; /** * A tuning parameter; by what percentage must the number of equations grow before we perform a * topological sort? */ private double topologicalGrowthFactor = 0.1; /** * A tuning parameter: how many evaluations are allowed to take place between topological * re-orderings. The idea is that many evaluations may be a sign of a bad ordering, even when few * new equations are being added. * *

A number less than zero mean infinite. */ private int maxEvalBetweenTopo = 500000; private int evaluationsAtLastOrdering = 0; /** How many equations have been added since the last topological sort? */ int topologicalCounter = 0; /** The next order number to assign to a new equation */ int nextOrderNumber = 1; /** During verbose evaluation, holds the number of dataflow equations evaluated */ private int nEvaluated = 0; /** During verbose evaluation, holds the number of dataflow equations created */ private int nCreated = 0; /** worklist for the iterative solver */ protected Worklist workList = new Worklist(); /** A boolean which is initially true, but set to false after the first call to solve(); */ private boolean firstSolve = true; protected abstract T[] makeStmtRHS(int size); /** Some setup which occurs only before the first solve */ public void initForFirstSolve() { orderStatements(); initializeVariables(); initializeWorkList(); firstSolve = false; } /** * @return true iff work list is empty */ public boolean emptyWorkList() { return workList.isEmpty(); } /** * Solve the set of dataflow graph. * *

PRECONDITION: graph is set up * * @return true iff the evaluation of some equation caused a change in the value of some variable. */ @Override @SuppressWarnings("unchecked") public boolean solve(IProgressMonitor monitor) throws CancelException { boolean globalChange = false; if (firstSolve) { initForFirstSolve(); } while (!workList.isEmpty()) { MonitorUtil.throwExceptionIfCanceled(monitor); orderStatements(); // duplicate insertion detection AbstractStatement s = workList.takeStatement(); if (DEBUG) { System.err.println(("Before evaluation " + s)); } byte code = s.evaluate(); nEvaluated++; if (verbose) { if (nEvaluated % getVerboseInterval() == 0) { performVerboseAction(); } if (nEvaluated % getPeriodicMaintainInterval() == 0) { periodicMaintenance(); } } if (DEBUG) { System.err.println(("After evaluation " + s + ' ' + isChanged(code))); } if (isChanged(code)) { globalChange = true; updateWorkList(s); } if (isFixed(code)) { removeStatement(s); } } return globalChange; } @Override public void performVerboseAction() { System.err.println("Evaluated " + nEvaluated); System.err.println("Created " + nCreated); System.err.println("Worklist " + workList.size()); if (MORE_VERBOSE) { if (!workList.isEmpty()) { AbstractStatement s = workList.takeStatement(); System.err.println("Peek " + lineBreak(s.toString(), 132)); if (s instanceof VerboseAction) { ((VerboseAction) s).performVerboseAction(); } workList.insertStatement(s); } } } public static String lineBreak(String string, int wrap) { if (string == null) { throw new IllegalArgumentException("string is null"); } if (string.length() > wrap) { StringBuilder result = new StringBuilder(); int start = 0; while (start < string.length()) { int end = Math.min(start + wrap, string.length()); result.append(string, start, end); result.append("\n "); start = end; } return result.toString(); } else { return string; } } public void removeStatement(AbstractStatement s) { getFixedPointSystem().removeStatement(s); } @Override public String toString() { StringBuilder result = new StringBuilder("Fixed Point System:\n"); for (INodeWithNumber nwn : Iterator2Iterable.make(getStatements())) { result.append(nwn).append('\n'); } return result.toString(); } public Iterator getStatements() { return getFixedPointSystem().getStatements(); } /** * Add a step to the work list. * * @param s the step to add */ public void addToWorkList(AbstractStatement s) { workList.insertStatement(s); } /** Add all to the work list. */ public void addAllStatementsToWorkList() { for (INodeWithNumber nwn : Iterator2Iterable.make(getStatements())) { AbstractStatement eq = (AbstractStatement) nwn; addToWorkList(eq); } } /** * Call this method when the contents of a variable changes. This routine adds all graph using * this variable to the set of new graph. * * @param v the variable that has changed */ public void changedVariable(T v) { for (INodeWithNumber nwn : Iterator2Iterable.make(getFixedPointSystem().getStatementsThatUse(v))) { AbstractStatement s = (AbstractStatement) nwn; addToWorkList(s); } } /** * Add a step with zero operands on the right-hand side. * *

TODO: this is a little odd, in that this equation will never fire unless explicitly added to * a work list. I think in most cases we shouldn't be creating this nullary form. * * @param lhs the variable set by this equation * @param operator the step operator * @throws IllegalArgumentException if lhs is null */ public boolean newStatement( final T lhs, final NullaryOperator operator, final boolean toWorkList, final boolean eager) { if (lhs == null) { throw new IllegalArgumentException("lhs is null"); } // add to the list of graph lhs.setOrderNumber(nextOrderNumber++); final NullaryStatement s = new BasicNullaryStatement<>(lhs, operator); if (getFixedPointSystem().containsStatement(s)) { return false; } nCreated++; getFixedPointSystem().addStatement(s); incorporateNewStatement(toWorkList, eager, s); topologicalCounter++; return true; } @SuppressWarnings("unchecked") private void incorporateNewStatement(boolean toWorkList, boolean eager, AbstractStatement s) { if (eager) { byte code = s.evaluate(); if (verbose) { nEvaluated++; if (nEvaluated % getVerboseInterval() == 0) { performVerboseAction(); } if (nEvaluated % getPeriodicMaintainInterval() == 0) { periodicMaintenance(); } } if (isChanged(code)) { updateWorkList(s); } if (isFixed(code)) { removeStatement(s); } } else if (toWorkList) { addToWorkList(s); } } /** * Add a step with one operand on the right-hand side. * * @param lhs the lattice variable set by this equation * @param operator the step's operator * @param rhs first operand on the rhs * @return true iff the system changes * @throws IllegalArgumentException if operator is null */ public boolean newStatement( @Nullable T lhs, UnaryOperator operator, T rhs, boolean toWorkList, boolean eager) { if (operator == null) { throw new IllegalArgumentException("operator is null"); } // add to the list of graph UnaryStatement s = operator.makeEquation(lhs, rhs); if (getFixedPointSystem().containsStatement(s)) { return false; } if (lhs != null) { lhs.setOrderNumber(nextOrderNumber++); } nCreated++; getFixedPointSystem().addStatement(s); incorporateNewStatement(toWorkList, eager, s); topologicalCounter++; return true; } protected class Statement extends GeneralStatement { public Statement(T lhs, AbstractOperator operator, T op1, T op2, T op3) { super(lhs, operator, op1, op2, op3); } public Statement(T lhs, AbstractOperator operator, T op1, T op2) { super(lhs, operator, op1, op2); } public Statement(T lhs, AbstractOperator operator, T[] rhs) { super(lhs, operator, rhs); } public Statement(T lhs, AbstractOperator operator) { super(lhs, operator); } @Override protected T[] makeRHS(int size) { return makeStmtRHS(size); } } /** * Add an equation with two operands on the right-hand side. * * @param lhs the lattice variable set by this equation * @param operator the equation operator * @param op1 first operand on the rhs * @param op2 second operand on the rhs */ public boolean newStatement( T lhs, AbstractOperator operator, T op1, T op2, boolean toWorkList, boolean eager) { // add to the list of graph GeneralStatement s = new Statement(lhs, operator, op1, op2); if (getFixedPointSystem().containsStatement(s)) { return false; } if (lhs != null) { lhs.setOrderNumber(nextOrderNumber++); } nCreated++; getFixedPointSystem().addStatement(s); incorporateNewStatement(toWorkList, eager, s); topologicalCounter++; return true; } /** * Add a step with three operands on the right-hand side. * * @param lhs the lattice variable set by this equation * @param operator the equation operator * @param op1 first operand on the rhs * @param op2 second operand on the rhs * @param op3 third operand on the rhs * @throws IllegalArgumentException if lhs is null */ public boolean newStatement( T lhs, AbstractOperator operator, T op1, T op2, T op3, boolean toWorkList, boolean eager) { if (lhs == null) { throw new IllegalArgumentException("lhs is null"); } // add to the list of graph lhs.setOrderNumber(nextOrderNumber++); GeneralStatement s = new Statement(lhs, operator, op1, op2, op3); if (getFixedPointSystem().containsStatement(s)) { nextOrderNumber--; return false; } nCreated++; getFixedPointSystem().addStatement(s); incorporateNewStatement(toWorkList, eager, s); topologicalCounter++; return true; } /** * Add a step to the system with an arbitrary number of operands on the right-hand side. * * @param lhs lattice variable set by this equation * @param operator the operator * @param rhs the operands on the rhs */ public boolean newStatement( T lhs, AbstractOperator operator, T[] rhs, boolean toWorkList, boolean eager) { // add to the list of graph if (lhs != null) lhs.setOrderNumber(nextOrderNumber++); GeneralStatement s = new Statement(lhs, operator, rhs); if (getFixedPointSystem().containsStatement(s)) { nextOrderNumber--; return false; } nCreated++; getFixedPointSystem().addStatement(s); incorporateNewStatement(toWorkList, eager, s); topologicalCounter++; return true; } /** Initialize all lattice vars in the system. */ protected abstract void initializeVariables(); /** Initialize the work list for iteration.j */ protected abstract void initializeWorkList(); /** * Update the worklist, assuming that a particular equation has been re-evaluated * * @param s the equation that has been re-evaluated. */ private void updateWorkList(AbstractStatement s) { // find each equation which uses this lattice cell, and // add it to the work list T v = s.getLHS(); if (v == null) { return; } changedVariable(v); } /** Number the graph in topological order. */ private void orderStatementsInternal() { if (verbose) { if (nEvaluated > 0) { System.err.println("Reorder " + nEvaluated + ' ' + nCreated); } } reorder(); if (verbose) { if (nEvaluated > 0) { System.err.println("Reorder finished " + nEvaluated + ' ' + nCreated); } } topologicalCounter = 0; evaluationsAtLastOrdering = nEvaluated; } /** */ public void orderStatements() { if (nextOrderNumber > minSizeForTopSort) { if (((double) topologicalCounter / (double) nextOrderNumber) > topologicalGrowthFactor) { orderStatementsInternal(); return; } } if ((nEvaluated - evaluationsAtLastOrdering) > maxEvalBetweenTopo) { orderStatementsInternal(); return; } } /** Re-order the step definitions. */ private void reorder() { // drain the worklist List temp = new ArrayList<>(); while (!workList.isEmpty()) { AbstractStatement eq = workList.takeStatement(); temp.add(eq); } workList = new Worklist(); // compute new ordering getFixedPointSystem().reorder(); // re-populate worklist for (AbstractStatement s : temp) { workList.insertStatement(s); } } public static boolean isChanged(byte code) { return (code & CHANGED_MASK) != 0; } public static boolean isSideEffect(byte code) { return (code & SIDE_EFFECT_MASK) != 0; } public static boolean isFixed(byte code) { return (code & FIXED_MASK) != 0; } public int getMinSizeForTopSort() { return minSizeForTopSort; } public void setMinEquationsForTopSort(int i) { minSizeForTopSort = i; } public int getMaxEvalBetweenTopo() { return maxEvalBetweenTopo; } public double getTopologicalGrowthFactor() { return topologicalGrowthFactor; } public void setMaxEvalBetweenTopo(int i) { maxEvalBetweenTopo = i; } public void setTopologicalGrowthFactor(double d) { topologicalGrowthFactor = d; } public int getNumberOfEvaluations() { return nEvaluated; } public void incNumberOfEvaluations() { nEvaluated++; } /** a method that will be called every N evaluations. subclasses should override as desired. */ protected void periodicMaintenance() {} /** subclasses should override as desired. */ protected int getVerboseInterval() { return DEFAULT_VERBOSE_INTERVAL; } /** subclasses should override as desired. */ protected int getPeriodicMaintainInterval() { return DEFAULT_PERIODIC_MAINTENANCE_INTERVAL; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy