/* * KSet.java - This file is part of the Jakstab project. * Copyright 2007-2015 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.explicit; import java.util.Collection; import java.util.Collections; import java.util.Set; import org.jakstab.analysis.*; import org.jakstab.rtl.expressions.RTLNumber; import org.jakstab.util.FastSet; import org.jakstab.util.Logger; /** * @author Johannes Kinder */ public class KSet implements AbstractDomainElement { @SuppressWarnings("unused") private static final Logger logger = Logger.getLogger(KSet.class); private static Set<BasedNumberElement> FULL_SET = Collections.singleton(null); private static KSet TOP = new KSet(-1, FULL_SET); static KSet getTop() { return TOP; } private Set<BasedNumberElement> set; private final int bound; public KSet(int bound, BasedNumberElement element) { this(bound); this.set.add(element); } public KSet(int bound) { this(bound, new FastSet<BasedNumberElement>()); } public KSet(int bound, Set<BasedNumberElement> set) { this.bound = bound; this.set = set; } @Override public Set<RTLNumber> concretize() { // If abstract value is top, return full set if (isTop()) return RTLNumber.ALL_NUMBERS; Set<RTLNumber> result = new FastSet<RTLNumber>(); for (BasedNumberElement e : set) { Set<RTLNumber> ec = e.concretize(); for (RTLNumber c : ec) { if (c == null) return RTLNumber.ALL_NUMBERS; result.add(c); } } return result; } @Override public boolean hasUniqueConcretization() { return !isTop() && set.size() == 1 && set.iterator().next().hasUniqueConcretization(); } @Override public KSet join(LatticeElement l) { KSet other = (KSet)l; if (other.isTop() || this.isBot()) return other; if (this.isTop() || other.isBot()) return this; KSet result = new KSet(Math.max(bound, other.bound)); for (BasedNumberElement e : set) if (!result.add(e)) return result; for (BasedNumberElement e : other.set) if (!result.add(e)) return result; return result; /* Set<BasedNumberElement> resultSet = new FastSet<BasedNumberElement>(); int resultBound = Math.max(bound, other.bound); resultSet.addAll(set); resultSet.addAll(other.set); if (resultSet.size() > resultBound) { // Create new top element resultSet = FULL_SET; } KSet result = new KSet(resultBound, resultSet); return result;*/ } @Override public boolean isBot() { return set.isEmpty(); } @Override public boolean isTop() { return set == FULL_SET; } @Override public boolean lessOrEqual(LatticeElement l) { KSet other = (KSet)l; if (other.isTop() || isBot()) return true; if (other.isBot() || isTop()) return false; return other.set.containsAll(set); } @Override public AbstractDomainElement readStore(int bitWidth, PartitionedMemory<? extends AbstractDomainElement> store) { Set<BasedNumberElement> resultSet = new FastSet<BasedNumberElement>(); int k = 0; for (BasedNumberElement e : set) { KSet memVal = (KSet)store.get(e.getRegion(), e.getNumber().longValue(), bitWidth); if (!memVal.isBot() && !memVal.isTop()) { resultSet.addAll(memVal.set); k = Math.max(k, memVal.bound); } } return new KSet(k, resultSet); } @Override public Collection<? extends AbstractDomainElement> readStorePowerSet(int bitWidth, PartitionedMemory<? extends AbstractDomainElement> store) { if (isTop()) return Collections.singleton(getTop()); Set<AbstractDomainElement> result = new FastSet<AbstractDomainElement>(); for (BasedNumberElement e : set) { result.add(store.get(e.getRegion(), e.getNumber().longValue(), bitWidth)); } return result; } @Override public <A extends AbstractDomainElement> void writeStore(int bitWidth, PartitionedMemory<A> store, A value) { if (isTop()) { store.setTop(); } else if (set.size() == 1) { // Strong updates BasedNumberElement e = set.iterator().next(); e.writeStore(bitWidth, store, value); } else { // Weak updates for (BasedNumberElement e : set) { if (e.isTop()) store.setTop(); else if (e.isNumberTop()) store.setTop(e.getRegion()); else store.weakUpdate(e.getRegion(), e.getNumber().longValue(), bitWidth, value); } } } @Override public AbstractDomainElement bitExtract(int first, int last) { if (isTop() || isBot()) return this; KSet resultSet = new KSet(bound); for (BasedNumberElement e : set) { resultSet.add(e.bitExtract(first, last)); } return resultSet; } @Override public AbstractDomainElement multiply(AbstractDomainElement op) { KSet other = (KSet)op; if (isTop() || isBot()) return this; if (other.isTop() || other.isBot()) return other; KSet resultSet = new KSet(Math.max(bound, other.bound)); for (BasedNumberElement e : set) { for (BasedNumberElement ePrime : other.set) { // If defaults to TOP return TOP if (!resultSet.add(e.multiply(ePrime))) return resultSet; } } return resultSet; } @Override public AbstractDomainElement negate() { if (isTop() || isBot()) return this; KSet resultSet = new KSet(bound); for (BasedNumberElement e : set) { resultSet.add(e.negate()); } return resultSet; } @Override public AbstractDomainElement plus(AbstractDomainElement op) { KSet other = (KSet)op; if (isTop() || isBot()) return this; if (other.isTop() || other.isBot()) return other; KSet resultSet = new KSet(Math.max(bound, other.bound)); for (BasedNumberElement e : set) { for (BasedNumberElement ePrime : other.set) { // If defaults to TOP return TOP if (!resultSet.add(e.plus(ePrime))) return resultSet; } } return resultSet; } @Override public AbstractDomainElement signExtend(int first, int last) { if (isTop() || isBot()) return this; KSet resultSet = new KSet(bound); for (BasedNumberElement e : set) { resultSet.add(e.signExtend(first, last)); } return resultSet; } @Override public AbstractDomainElement zeroFill(int first, int last) { if (isTop() || isBot()) return this; KSet resultSet = new KSet(bound); for (BasedNumberElement e : set) { resultSet.add(e.zeroFill(first, last)); } return resultSet; } /** * Add an element to this KSet. If it exceeds the bound, set this * set to TOP. * @param e the element to add * @return false if the resulting set is TOP, true otherwise */ private boolean add(BasedNumberElement e) { assert e != null; // If TOP element, don't add anything if (isTop()) return false; set.add(e); // If bound exceeded, set to TOP if (set.size() > bound) { set = FULL_SET; return false; } else { return true; } } @Override public String toString() { return set.toString(); } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + bound; result = prime * result + ((set == null) ? 0 : set.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; KSet other = (KSet) obj; if (bound != other.bound) return false; if (set == null) { if (other.set != null) return false; } else if (!set.equals(other.set)) return false; return true; } }