/*
* DualCompositeState.java - This file is part of the Jakstab project.
* Copyright 2007-2012 Johannes Kinder <jk@jakstab.org>
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, see <http://www.gnu.org/licenses/>.
*/
package org.jakstab.analysis.composite;
import java.util.Collections;
import java.util.Set;
import org.jakstab.analysis.AbstractState;
import org.jakstab.analysis.UnderApproximateState;
import org.jakstab.rtl.expressions.RTLExpression;
import org.jakstab.rtl.expressions.RTLNumber;
import org.jakstab.util.FastSet;
import org.jakstab.util.Logger;
import org.jakstab.util.Tuple;
/**
* A composite state containing both over- and under-approximate states.
*
* @author Johannes Kinder
*
*/
public class DualCompositeState extends CompositeState {
@SuppressWarnings("unused")
private static final Logger logger = Logger.getLogger(DualCompositeState.class);
public DualCompositeState(AbstractState[] components) {
super(components);
}
public Set<Tuple<RTLNumber>> projection(RTLExpression... expressions) {
Set<Tuple<RTLNumber>> result = new FastSet<Tuple<RTLNumber>>();
for (int i=0; i<components.length; i++) {
if (!(components[i] instanceof UnderApproximateState))
continue;
// Concretize this component state and then take the union with existing ones
Set<Tuple<RTLNumber>> concreteTuples = components[i].projectionFromConcretization(expressions);
//logger.info(concreteTuples);
/* Return value of null here represents the bottom element, so it has no effect in union */
if (concreteTuples == null) continue;
/* Else take the union */
else {
result.addAll(concreteTuples);
}
}
//logger.debug("Under-approximation projects " + Arrays.toString(expressions) + " to " + result);
assert result != null;
return result;
}
@Override
public Set<Tuple<RTLNumber>> projectionFromConcretization(
RTLExpression... expressions) {
Set<Tuple<RTLNumber>> result = null;
for (int i=0; i<components.length; i++) {
if (components[i] instanceof UnderApproximateState)
continue;
// Concretize this component state and then intersect it with existing ones
Set<Tuple<RTLNumber>> concreteTuples = components[i].projectionFromConcretization(expressions);
//logger.info(concreteTuples);
/* Return value of null represents the whole set of tuples of numbers (usually b/c the function
* is not implemented), so intersection has no effect */
if (concreteTuples == null) continue;
/* If we are currently at the whole set, the new tuple set is the intersection */
else if (result == null) result = concreteTuples;
/* Else intersect */
else {
// result.retainAll(concreteTuples);
// intersect manually b/c of possible null components (wildcards for more tuples)
// Note: A tuple with a null component expands to a set of tuples
// with all possible values for that component
//
Set<Tuple<RTLNumber>> newResult = new FastSet<Tuple<RTLNumber>>();
// for all tuples in result
for (Tuple<RTLNumber> rTuple : result) {
// for all tuples we got from the current substate
cTuplesLoop: for (Tuple<RTLNumber> cTuple : concreteTuples) {
// array for building new tuple
RTLNumber[] numbers = new RTLNumber[expressions.length];
// match components of both tuples against each other
for (int j=0; j<expressions.length; j++) {
RTLNumber cNumber = cTuple.get(j);
RTLNumber rNumber = rTuple.get(j);
// if the component is no wildcard and not equal, don't match, try next new tuple for match
if (cNumber != RTLNumber.WILDCARD && rNumber != null && !cNumber.equals(rNumber)) {
continue cTuplesLoop;
} else {
// handle wildcards on both sides:
if (rNumber == RTLNumber.WILDCARD) numbers[j] = cNumber;
else numbers[j] = rNumber;
}
}
// We passed all components - so add matching tuple
newResult.add(Tuple.create(numbers));
// We still need to continue with the next tuple, since wildcards
// could allow more possibilities
}
// cTuplesLoop finished without finding a match
}
result = newResult;
}
}
//logger.info("Project " + Arrays.toString(expressions) + " to " + result);
//assert result != null;
// result can be null when using DummyAnalysis.
if (result == null) result = Collections.emptySet();
return result;
}
}