/* * This file is part of JOP, the Java Optimized Processor * see <http://www.jopdesign.com/> * * Copyright (C) 2010, Benedikt Huber <benedikt.huber@gmail.com> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program 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 for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package com.jopdesign.dfa.analyses; import com.jopdesign.dfa.framework.BoundedSetFactory; import com.jopdesign.dfa.framework.BoundedSetFactory.BoundedSet; import org.apache.log4j.Logger; import java.io.PrintStream; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; /** * Map from locations to symbolic addresses. The special value TOP represents the upper bound * of the lattice. * @author Benedikt Huber <benedikt.huber@gmail.com> * */ public class SymbolicAddressMap { // Attention: // a.isTop() and b.isTop() does not imply a==b, but top() always returns _top @SuppressWarnings("unchecked") private static SymbolicAddressMap _top = new SymbolicAddressMap(new BoundedSetFactory(0), (HashMap)null, (HashMap) null); private BoundedSetFactory<SymbolicAddress> bsFactory; /* Invariant: obj.map == null iff obj == TOP */ private Map<Location, BoundedSet<SymbolicAddress>> mapP; private HashMap<String, BoundedSet<SymbolicAddress>> mapA; public boolean isTop() { return(this.mapP == null); } private void setTop() { this.mapP = null; this.mapA = null; } /** empty constructor */ public SymbolicAddressMap(BoundedSetFactory<SymbolicAddress> bsFactory) { this(bsFactory, new HashMap<Location,BoundedSet<SymbolicAddress>>(), new HashMap<String,BoundedSet<SymbolicAddress>>()); } /** top element */ public static SymbolicAddressMap top() { return _top; } /* full, private constructor */ private SymbolicAddressMap(BoundedSetFactory<SymbolicAddress> bsFactory, HashMap<Location, BoundedSet<SymbolicAddress>> initP, HashMap<String, BoundedSet<SymbolicAddress>> initA) { this.bsFactory = bsFactory; this.mapP = initP; this.mapA = initA; } @Override public int hashCode() { if(isTop()) return 1; else return 2 + 31 * mapP.hashCode() + mapA.hashCode(); } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; SymbolicAddressMap other = (SymbolicAddressMap) obj; if(this.isTop() || other.isTop()) return (this.isTop() && other.isTop()); return mapP.equals(other.mapP) && mapA.equals(other.mapA); } public boolean isSubset(SymbolicAddressMap other) { if(other.isTop()) return true; else if(this.isTop()) return false; else if(other == null) return false; /* Neither is \bot or \top -> pointwise subseteq */ for(Location l : this.mapP.keySet()) { BoundedSet<SymbolicAddress> thisEntry = mapP.get(l); BoundedSet<SymbolicAddress> otherEntry = other.mapP.get(l); if(otherEntry == null) return false; if(! thisEntry.isSubset(otherEntry)) return false; } for(String l : this.mapA.keySet()) { BoundedSet<SymbolicAddress> thisEntry = mapP.get(l); BoundedSet<SymbolicAddress> otherEntry = other.mapP.get(l); if(otherEntry == null) return false; if(! thisEntry.isSubset(otherEntry)) return false; } return true; } @Override protected SymbolicAddressMap clone() { if(this.isTop()) return this; return new SymbolicAddressMap(this.bsFactory, new HashMap<Location, BoundedSet<SymbolicAddress>>(this.mapP), new HashMap<String, BoundedSet<SymbolicAddress>>(this.mapA)); } /** Clone address map, but only those stack variables below {@code bound} */ public SymbolicAddressMap cloneFilterStack(int bound) { if(this.isTop()) return this; SymbolicAddressMap copy = new SymbolicAddressMap(this.bsFactory); for(Entry<Location, BoundedSet<SymbolicAddress>> entry : mapP.entrySet()) { Location loc = entry.getKey(); if(loc.isHeapLoc() || loc.stackLoc < bound) { copy.put(loc, entry.getValue()); } } return copy; } /** Clone address map, but only those stack variables with index greater than or equal to * {@code framePtr}. The stack variables are moved down to the beginning of the stack. */ public SymbolicAddressMap cloneInvoke(int framePtr) { if(this.isTop()) return this; SymbolicAddressMap copy = new SymbolicAddressMap(this.bsFactory); for(Entry<Location, BoundedSet<SymbolicAddress>> entry : mapP.entrySet()) { Location loc = entry.getKey(); if(loc.isHeapLoc()) { copy.put(loc, entry.getValue()); } else if(loc.stackLoc >= framePtr) { copy.putStack(loc.stackLoc - framePtr, entry.getValue()); } } return copy; } /** Set stack info from other other map, upto bound. * Used to restore stack frames when returning from a method */ public void addStackUpto(SymbolicAddressMap in, int bound) { if(in == null) { throw new AssertionError("addStackUpto: caller map is undefined ?"); } if(this.isTop()) return; if(in.isTop()) { setTop(); return; } for(Entry<Location, BoundedSet<SymbolicAddress>> entry : in.mapP.entrySet()) { Location loc = entry.getKey(); if(! loc.isHeapLoc() && loc.stackLoc < bound) { mapP.put(loc, in.getStack(loc.stackLoc)); } } } public void join(SymbolicAddressMap b) { if(b == null) return; joinReturned(b,0); } /** Merge in df info from returned method. */ public void joinReturned(SymbolicAddressMap returned, int framePtr) { if(returned == null) { throw new AssertionError("joinReturned: returned map is undefined ?"); } if(this.isTop()) return; else if(returned.isTop()) { setTop(); return; } for(Entry<Location, BoundedSet<SymbolicAddress>> entry : returned.mapP.entrySet()) { Location locReturnedFrame = entry.getKey(); Location locCallerFrame; if(locReturnedFrame.isHeapLoc()) { locCallerFrame = locReturnedFrame; } else { locCallerFrame = new Location(locReturnedFrame.stackLoc + framePtr); } BoundedSet<SymbolicAddress> callerSet = mapP.get(locCallerFrame); BoundedSet<SymbolicAddress> returnedSet = returned.mapP.get(locReturnedFrame); put(locCallerFrame, returnedSet.join(callerSet)); } } public void copyStack(SymbolicAddressMap in, int dst, int src) { if(in.isTop()) return; if(this.isTop()) return; Location srcLoc = new Location(src); BoundedSet<SymbolicAddress> val = in.mapP.get(srcLoc); if(val == null) return; putStack(dst, val); } public BoundedSet<SymbolicAddress> getStack(int index) { if(this.isTop()) return bsFactory.top(); Location loc = new Location(index); BoundedSet<SymbolicAddress> val = mapP.get(loc); if(val == null) { Logger.getLogger(this.getClass()).error("Undefined stack location: "+loc); for(Entry<Location, BoundedSet<SymbolicAddress>> entry : this.mapP.entrySet()) { System.err.println(" "+entry.getKey()+ " --> "+entry.getValue()); } // throw new AssertionError("Undefined stack Location"); } return val; } public void putStack(int index, BoundedSet<SymbolicAddress> bs) { this.put(new Location(index), bs); } public BoundedSet<SymbolicAddress> getHeap(String staticfield) { if(this.isTop()) return bsFactory.top(); Location loc = new Location(staticfield); BoundedSet<SymbolicAddress> val = mapP.get(loc); if(val == null) { val = bsFactory.singleton(SymbolicAddress.rootAddress(staticfield)); } return val; } public void putHeap(String staticfield, BoundedSet<SymbolicAddress> pointers) { this.put(new Location(staticfield), pointers); } public void put(Location l, BoundedSet<SymbolicAddress> bs) { if(bs == null) { throw new AssertionError("put "+l+": null"); } if(this.isTop()) return; this.mapP.put(l, bs); } public void addAlias(String ty, BoundedSet<SymbolicAddress> newAliases) { if(this.isTop()) return; BoundedSet<SymbolicAddress> oldAlias = this.mapA.get(ty); if(oldAlias == null) oldAlias = bsFactory.empty(); // FIXME: Debugging if(newAliases == null) { Logger.getLogger("Object Cache Analysis").error("Undefined alias set for "+ty); return; } oldAlias.addAll(newAliases); mapA.put(ty, newAliases); } public BoundedSet<SymbolicAddress> getAliases(String fieldType) { if(this.isTop()) return bsFactory.top(); BoundedSet<SymbolicAddress> aliases = this.mapA.get(fieldType); if(aliases == null) return bsFactory.empty(); return aliases; } /** Print results * * @param indent Indentation (amount of leading whitespace) */ public void print(PrintStream out, int indent) { StringBuffer indentstr = new StringBuffer(); for(int i = 0; i < indent; i++) indentstr.append(' '); out.print(indentstr.toString()); if(this.isTop()) { out.println("TOP"); return; } out.println("SymbolicAddressMap ("+mapP.size()+")"); indentstr.append(' '); for(Entry<Location, BoundedSet<SymbolicAddress>> entry : mapP.entrySet()) { out.print(indentstr.toString()); out.print(entry.getKey()); out.print(": "); out.print(entry.getValue().getSize()+"<="+entry.getValue().getLimit()); out.print(entry.getValue()); out.print("\n"); } for(Entry<String, BoundedSet<SymbolicAddress>> entry : mapA.entrySet()) { out.print(indentstr.toString()); out.print(entry.getKey()); out.print("~~> "); out.print(entry.getValue().getSize()+"<="+entry.getValue().getLimit()); out.print(entry.getValue()); out.print("\n"); } } @Override public String toString() { StringBuffer sb = new StringBuffer(); sb.append("SymbolicAddressMap"); if(this.isTop()) { sb.append(".TOP"); } else { sb.append("{ "); sb.append(mapP); sb.append(", "); sb.append(mapA); sb.append(" }"); } return sb.toString(); } }