/* Shadow.java
Copyright 2003, Bil Lewis
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 2 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, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package com.lambda.Debugger;
// Shadow.java
/*
*/
import java.awt.FontMetrics;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;
public class Shadow {
public static final String BLOCKEDON = "_blockedOn";
public static final String SLEEPERS = "_sleepers";
public static final String OWNER = "_owner";
public static final String WAITERS = "_waiters";
public static final String LOCKSOWNED = "_locksOwned";
private static final Comparator comp = new Comparator() {public int compare(Object o1, Object o2) {
Field f1 = (Field) o1, f2 = (Field) o2;
String s1 = f1.getName(), s2 = f2.getName();
return s1.compareTo(s2);
}
};
static private int id_counter=0;
static private int stringLengths=0;
static private int nRemoved=0;
static private int nEntries=0;
static int wastedTripletons = 0, wastedMultitons = 0;
static private HashMapEq table = new HashMapEq(100); // 10k
static private HashMapEq tableAlternate = new HashMapEq(100); // 10k
static private HashMapEq blockedTable = new HashMapEq(100);
static private HashMapEq blockedTableAlternate = new HashMapEq(100);
static private HashMapEq sleeperTable = new HashMapEq(100);
static private HashMapEq sleeperTableAlternate = new HashMapEq(100);
static private VectorD toRemove= new VectorD();
private HistoryList[] shadowVars;
public Object obj;
private int id;
public String tostring, tostringShort;
public boolean foreign = false;
public ClassInformation classInfo;
public int creationTime;
public String gcStatus;
public void initializeEvents() {
int len = shadowVars.length;
for (int i = 0; i < len; i++) {
String varName = classInfo.getVarName(i);
HistoryList hl = shadowVars[i];
if (hl == null) continue;
hl.initializeEvents(obj, varName);
}
HistoryList hl = getBlockedHL();
if (hl != null) hl.initializeEvents(obj, "Lock");
}
public static void initializeAllEvents() {
Iterator iter = table.values().iterator();
while (iter.hasNext()) {
Shadow sh = (Shadow) iter.next();
sh.initializeEvents();
}
}
public static ArrayList getAllObjects() {
ArrayList al = new ArrayList();
Iterator iter = table.values().iterator();
while (iter.hasNext()) {
Shadow sh = (Shadow) iter.next();
if (sh.creationTime > TimeStamp.ct()) continue;
al.add(sh.obj);
}
return al;
}
public static Iterator getIterator() {
Iterator iter = table.values().iterator();
return iter;
}
static public void printStatistics() {
Iterator iter = table.values().iterator();
int nSingletons = 0, nMultitons = 0, nTripletons=0;
int[] sizes = new int[30];
int nHLists = 0;
int nHLEntries = 0;
int emptyHLs=0;
stringLengths=0;
wastedTripletons = 0;
wastedMultitons = 0;
while (iter.hasNext()) {
Shadow sh = (Shadow) iter.next();
if (sh.tostring != null) stringLengths += sh.tostring.length();
// if (sh.tostringShort != null) stringLengths += sh.tostringShort.length();
HistoryList hls[] = sh.shadowVars;
nHLists += hls.length;
for (int i = 0; i < hls.length; i++) {
HistoryList hl = hls[i];
if (hl == null) {emptyHLs++; continue;}
int size = hl.size();
nHLEntries += size;
if (hl instanceof HistoryListSingleton) nSingletons++;
if (hl instanceof HistoryListTripleton) {nTripletons++; wastedTripletons += (3-hl.size());}
if (hl instanceof HistoryListMultiple) {
nMultitons++;
HistoryListMultiple hlm = (HistoryListMultiple) hl;
wastedMultitons+=hlm.wasted();
if (size < 10)
sizes[size]++;
else
if (size < 20) sizes[10]++;
else
if (size < 30) sizes[11]++;
else
if (size < 40) sizes[12]++;
else
if (size < 50) sizes[13]++;
else
if (size < 60) sizes[14]++;
else
if (size < 100) sizes[15]++;
else
if (size < 200) sizes[16]++;
else
if (size < 500) sizes[17]++;
else
if (size < 800) sizes[18]++;
else
if (size < 1200) sizes[19]++;
else
if (size < 1600) sizes[20]++;
else
if (size < 2000) sizes[21]++;
else
if (size < 4000) sizes[22]++;
else
if (size < 8000) sizes[23]++;
else
if (size < 16000) sizes[24]++;
else
sizes[25]++;
}
}
}
System.out.println("\n -- Shadow Statistics -- ");
System.out.println("Out of " + table.size() + " Shadows with " + nHLists + " HistoryLists and " + nHLEntries +" entries...");
System.out.println(" Shadows removed: "+nRemoved );
System.out.println(" Shadow string lengths: " + stringLengths);
System.out.println(" "+emptyHLs + " empty HLs");
System.out.println(" "+nSingletons + " nSingletons");
System.out.println(" "+nTripletons + " Tripletons of which wasted: "+wastedTripletons);
System.out.println(" "+nMultitons + " nMultitons, of which wasted: "+wastedMultitons);
System.out.println(" size\tnumber");
for (int i = 0; i < 10; i++) {if (sizes[i] > 0) System.out.println(" "+ i + "\t"+sizes[i]);}
if (sizes[10] > 0) System.out.println(" <20\t"+sizes[10]);
if (sizes[11] > 0) System.out.println(" <30\t"+sizes[11]);
if (sizes[12] > 0) System.out.println(" <40\t"+sizes[12]);
if (sizes[13] > 0) System.out.println(" <50\t"+sizes[13]);
if (sizes[14] > 0) System.out.println(" <60\t"+sizes[14]);
if (sizes[15] > 0) System.out.println(" <100\t"+sizes[15]);
if (sizes[16] > 0) System.out.println(" <200\t"+sizes[16]);
if (sizes[17] > 0) System.out.println(" <400\t"+sizes[17]);
if (sizes[18] > 0) System.out.println(" <800\t"+sizes[18]);
if (sizes[19] > 0) System.out.println(" <1200\t"+sizes[19]);
if (sizes[20] > 0) System.out.println(" <1600\t"+sizes[20]);
if (sizes[21] > 0) System.out.println(" <2k\t"+sizes[21]);
if (sizes[22] > 0) System.out.println(" <4k\t"+sizes[22]);
if (sizes[23] > 0) System.out.println(" <8k\t"+sizes[23]);
if (sizes[24] > 0) System.out.println(" <16k\t"+sizes[24]);
}
static public void reset() { // Clear out all values except for the current time value. Set that to time 0
Iterator iter = table.values().iterator();
int time = TimeStamp.currentTime().time;
while (iter.hasNext()) {
Shadow sh = (Shadow) iter.next();
sh.reset(time);
}
}
public void reset(int time) {
for (int i = 0; i < size(); i++) {
HistoryList hl = shadowVars[i];
if (hl == null) continue;
hl.reset(time);
}
}
static public int nEntries() {
return nEntries;
}
static public void initialize() { // These are to allow prgmr to type in values for EvaluateExpression etc.
Shadow sh;
Object o;
sh = new Shadow(0, o=new Boolean(true), new String[0], new Object[0], "true");
table.put(o, sh);
sh = new Shadow(0, o=new Boolean(false), new String[0], new Object[0], "false");
table.put(o, sh);
sh = new Shadow(0, o=ShadowNull.NULL, new String[0], new Object[0], "null");
table.put(o, sh);
}
static public HashMapEq getTable() { // ONLY CALLED BY "CALL INTERACTIVELY" COMPLETION CODE.
return table;
}
// DUPLICATE the tables for the alternate time line, but with only 1 HL entry.
private Shadow dup(int time, Object o) {
Shadow s = new Shadow();
s.classInfo = classInfo;
s.shadowVars = dupSV(time, shadowVars);
dupSleepers(time);
dupBlocked(time);
s.obj = obj;
s.id = id;
s.tostring =s.tostringShort = tostring;// + "_Alt";
return s;
}
private void dupSleepers(int now) {
SleeperSet ss = getSleeperSet();
if (ss == null) return;
ss = ss.dup(now); // set to empty!
sleeperTableAlternate.put(obj, ss);
}
private void dupBlocked(int now) {
HistoryList hl = getBlockedHL();
if (hl == null) return;
// hl = hl.dup(now);
hl = new HistoryListSingleton();
blockedTableAlternate.put(obj, hl);
}
private HistoryList[] dupSV(int time, HistoryList[] hls) {
if (hls == null) return null;
HistoryList[] hls1 = new HistoryList[hls.length];
for (int i = 0; i < hls.length; i++) {
HistoryList hl = hls[i];
if (hl == null) continue;
hls1[i] = hl.dup(time);
}
return hls1;
}
public static Shadow getAlternate(Object o) {
Shadow s = (Shadow) table.get(o); // Shadow.switch has already been called.
return s;
}
public static void updateAll() {
Iterator iter = table.values().iterator();
while (iter.hasNext()) {
Shadow sh = (Shadow) iter.next();
update(sh.obj);
}
}
// Update the actual object to reflect the currently revert'd time.
public static void update(Object o) {
if (o instanceof MyVector) return;
if (o instanceof MyHashtable) return;
if (o instanceof MyHashMap) return;
if (o instanceof MyArrayList) return;
try {update1(o);}
catch (Exception e) {
System.out.println("While updating: " + o + " threw " + e);
Debugger.message("While updating: " + o + " threw " + e, true);
}
}
public static void update1(Object o) {
Shadow s = (Shadow) table.get(o); // Shadow.switch has already been called.
int len = s.size();
Field f;
TimeStamp ts = TimeStamp.currentTime();
// // System.out.println("Updating: " + ((s.tostring != null) ? s.tostring : o));
if (o instanceof int[]) {
int[] array = (int[]) o;
for (int i = 0; i < len; i++) {
HistoryList hl = s.shadowVars[i];
if (hl == null) continue;
Object historyValue = hl.valueOn(ts, false);
if (historyValue instanceof ShadowInt) {
ShadowInt value = (ShadowInt) historyValue;
if (array[i] == value.intValue()) continue;
array[i] = value.intValue();
// System.out.println(" Updated " + i + " to " + value.intValue());
}
else
if (historyValue instanceof Dashes) {
// System.out.println(" Object not defined yet");
return;
}
}
return;
}
if (o instanceof Object[]) {
Object[] array = (Object[]) o;
for (int i = 0; i < s.size(); i++) {
HistoryList hl = s.shadowVars[i];
if (hl == null) continue;
Object historyValue = hl.valueOn(ts, false);
if (historyValue instanceof Dashes) {
// System.out.println(" Object not defined yet");
return;
}
if (array[i] == historyValue) continue;
array[i] = historyValue;
// System.out.println(" Updated " + i + " to " + value.intValue());
}
return;
}
Class c;
if (o instanceof Class)
c = (Class) o;
else
c = o.getClass();
for (int i = 0; i < len; i++) {
HistoryList hl = s.shadowVars[i];
if (hl == null) continue;
Object historyValue = hl.valueOn(ts, false);
if (historyValue instanceof ShadowNull) historyValue = null;
String fieldName = s.classInfo.getVarName(i);
// System.out.println(" Updating " + fieldName + " to " + historyValue);
if (historyValue instanceof Dashes) {
//System.out.println(" Object not defined yet");
return;
}
try { f = c.getField(fieldName); }
catch (Exception e) {D.println(""+e); continue;} // Shouldn't ever happen
if (historyValue instanceof ShadowPrimitive) {
if (historyValue instanceof ShadowInt) {
ShadowInt si = (ShadowInt) historyValue;
int historyIntValue = si.intValue();
try {
int fieldValue = f.getInt(o);
if (fieldValue == historyIntValue) continue;
f.setInt(o, historyIntValue);
// System.out.println(" Updated " + fieldName + " to " + historyIntValue);
}
catch (IllegalAccessException e) { D.println(" Update cannot set field " + f + " in " + s.tostring + " "+e); }
catch (IllegalArgumentException e) { D.println(" Update cannot set field " + f + " in " + s.tostring + " "+e); }
}
else if (historyValue instanceof ShadowBoolean) {
ShadowBoolean si = (ShadowBoolean) historyValue;
boolean historyBooleanValue = si.booleanValue();
try {
boolean fieldValue = f.getBoolean(o);
if (fieldValue == historyBooleanValue) continue;
f.setBoolean(o, historyBooleanValue);
// System.out.println(" Updated " + fieldName + " to " + historyBooleanValue);
}
catch (IllegalAccessException e) { D.println(" Update cannot set field " + f + " in " + s.tostring + " "+e); }
catch (IllegalArgumentException e) { D.println(" Update cannot set field " + f + " in " + s.tostring + " "+e); }
}
else if (historyValue instanceof ShadowLong) {
ShadowLong si = (ShadowLong) historyValue;
long historyLongValue = si.longValue();
try {
long fieldValue = f.getLong(o);
if (fieldValue == historyLongValue) continue;
f.setLong(o, historyLongValue);
// System.out.println(" Updated " + fieldName + " to " + historyLongValue);
}
catch (IllegalAccessException e) { D.println(" Update cannot set field " + f + " in " + s.tostring + " "+e); }
catch (IllegalArgumentException e) { D.println(" Update cannot set field " + f + " in " + s.tostring + " "+e); }
}
else if (historyValue instanceof ShadowShort) {
ShadowShort si = (ShadowShort) historyValue;
short historyShortValue = si.shortValue();
try {
long fieldValue = f.getShort(o);
if (fieldValue == historyShortValue) continue;
f.setShort(o, historyShortValue);
// System.out.println(" Updated " + fieldName + " to " + historyShortValue);
}
catch (IllegalAccessException e) { D.println(" Update cannot set field " + f + " in " + s.tostring + " "+e); }
catch (IllegalArgumentException e) { D.println(" Update cannot set field " + f + " in " + s.tostring + " "+e); }
}
else if (historyValue instanceof ShadowByte) {
ShadowByte si = (ShadowByte) historyValue;
byte historyByteValue = si.byteValue();
try {
byte fieldValue = f.getByte(o);
if (fieldValue == historyByteValue) continue;
f.setByte(o, historyByteValue);
// System.out.println(" Updated " + fieldName + " to " + historyByteValue);
}
catch (IllegalAccessException e) { D.println(" Update cannot set field " + f + " in " + s.tostring + " "+e); }
catch (IllegalArgumentException e) { D.println(" Update cannot set field " + f + " in " + s.tostring + " "+e); }
}
else if (historyValue instanceof ShadowChar) {
ShadowChar si = (ShadowChar) historyValue;
char historyCharValue = si.charValue();
try {
char fieldValue = f.getChar(o);
if (fieldValue == historyCharValue) continue;
f.setChar(o, historyCharValue);
// System.out.println(" Updated " + fieldName + " to " + historyCharValue);
}
catch (IllegalAccessException e) { D.println(" Update cannot set field " + f + " in " + s.tostring + " "+e); }
catch (IllegalArgumentException e) { D.println(" Update cannot set field " + f + " in " + s.tostring + " "+e); }
}
else if (historyValue instanceof ShadowFloat) {
ShadowFloat si = (ShadowFloat) historyValue;
float historyFloatValue = si.floatValue();
try {
float fieldValue = f.getFloat(o);
if (fieldValue == historyFloatValue) continue;
f.setFloat(o, historyFloatValue);
// System.out.println(" Updated " + fieldName + " to " + historyFloatValue);
}
catch (IllegalAccessException e) { D.println(" Update cannot set field " + f + " in " + s.tostring + " "+e); }
catch (IllegalArgumentException e) { D.println(" Update cannot set field " + f + " in " + s.tostring + " "+e); }
}
else if (historyValue instanceof ShadowDouble) {
ShadowDouble si = (ShadowDouble) historyValue;
double historyDoubleValue = si.doubleValue();
try {
double fieldValue = f.getDouble(o);
if (fieldValue == historyDoubleValue) continue;
f.setDouble(o, historyDoubleValue);
// System.out.println(" Updated " + fieldName + " to " + historyDoubleValue);
}
catch (IllegalAccessException e) { D.println(" Update cannot set field " + f + " in " + s.tostring + " "+e); }
catch (IllegalArgumentException e) { D.println(" Update cannot set field " + f + " in " + s.tostring + " "+e); }
}
continue;
}
// if value is Object
try {
Object fieldValue = f.get(o);
if (fieldValue == historyValue) continue;
f.set(o, historyValue);
// System.out.println(" Updated " + fieldName + " to " + historyValue);
}
catch (IllegalAccessException e) { D.println(" Update cannot set field " + f + " in " + s.tostring + " "+e); }
catch (IllegalArgumentException e) { D.println(" Update cannot set field " + f + " in " + s.tostring + " "+e); }
continue;
}
}
public static void clear() {
table.clear();
}
private void compact(int eot) {
// System.out.println("Compacting "+this);
if (Debugger.DEBUG_DEBUGGER) if (gcStatus != "verified") throw new DebuggerException(this + " not verified " + " but " + gcStatus);
boolean dead = true, deadOne = true;
for (int i = 0; i < size(); i++) {
HistoryList hl = shadowVars[i];
if (hl != null) {
deadOne = hl.compact(eot);
if (!deadOne) dead = false; // Only dead if all are dead
}
}
if (dead) {
toRemove.add(this); // Nothing interesting left in HLs
nRemoved++;
}
if (Debugger.DEBUG_DEBUGGER) gcStatus = "compacted";
}
/*
public static void compactAll(int eot) {
toRemove = new VectorD();
Set set = table.keySet();
Set setCopy = new HashSet(set);
Iterator e = setCopy.iterator();
// System.out.println("Shadows compacting to " + table.size() + " " + set.size());
while (e.hasNext()) {
Object key = e.next();
Shadow s = (Shadow) table.get(key);
s.compact(eot);
}
if (Debugger.DEBUG_DEBUGGER) System.out.println("Shadows compacted to " + table.size());
}
*/
public static void compactAll(int eot) {
toRemove = new VectorD();
Iterator i = table.values().iterator();
while (i.hasNext()) {
Shadow s = (Shadow) i.next();
s.compact(eot);
}
if (Debugger.DEBUG_DEBUGGER) System.out.println("Shadows compacted to " + table.size());
}
public static void removeDead() {
for (int i = toRemove.size()-1; i > -1; i--) {
Shadow s = (Shadow) toRemove.elementAt(i);
//System.out.println("removing "+ s.obj);
table.remove(s.obj);
}
}
public static void clearStatus() {
Iterator iter = table.values().iterator();
while (iter.hasNext()) {
Shadow sh = (Shadow) iter.next();
if (Debugger.DEBUG_DEBUGGER) sh.gcStatus = "cleared";
}
// System.out.println("Shadows cleared to " + table.size() + " " + set.size());
}
private void verify(int eot) {
// System.out.println("Verifying "+this);
for (int i = 0; i < size(); i++) {
HistoryList hl = shadowVars[i];
if (hl != null) hl.verify(eot);
}
}
public static void verifyCollection(int eot, String status) {
Iterator iter = table.values().iterator();
System.out.println("Shadows verifing to " +eot+ " table size: "+ table.size());
while (iter.hasNext()) {
Shadow sh = (Shadow) iter.next();
if (toRemove.contains(sh.obj)) throw new DebuggerException(sh + " impossobie");
if (Debugger.DEBUG_DEBUGGER) if (sh.gcStatus != status) throw new DebuggerException(sh + " not "+status+ " but "+sh.gcStatus);
sh.verify(eot);
if (Debugger.DEBUG_DEBUGGER) sh.gcStatus = "verified";
}
System.out.println("Shadows verified to " + table.size());
}
public static void switchTimeLines(boolean clear) {
if (clear) tableAlternate.clear();
if (tableAlternate.size() == 0) {
int time = TimeStamp.currentTime().time;
Iterator iter = table.values().iterator();
while (iter.hasNext()) {
Shadow sh = (Shadow) iter.next();
tableAlternate.put(sh.obj, sh.dup(time, sh.obj));
}
}
else {
int time = TimeStamp.currentTime().time;
Iterator iter = table.values().iterator();
while (iter.hasNext()) {
Shadow sh = (Shadow) iter.next();
sh.reset(time);
}
}
HashMapEq a = table;
table = tableAlternate;
tableAlternate = a;
a = sleeperTable;
sleeperTable = sleeperTableAlternate;
sleeperTableAlternate = a;
a = blockedTable;
blockedTable = blockedTableAlternate;
blockedTableAlternate = a;
}
public static int tableSize() {
return(table.size());
}
public void dontShow(String name) {
}
public String getVarName(int i) {return classInfo.getVarName(i);}
public Class getVarType(int i) {return classInfo.getVarClass(i);}
public HistoryList getBlockedHL() {
return (HistoryList) blockedTable.get(obj);
}
static public HistoryList getBlockedHL(Thread t) {
return (HistoryList) blockedTable.get(t);
}
public SleeperSet getSleeperSet() {
return (SleeperSet) sleeperTable.get(obj);
}
static private HistoryList addBlocked(Thread tid) {
HistoryList hl = (HistoryList) blockedTable.get(tid);
if (hl == null) {
hl = new HistoryListMultiple(BLOCKEDON);
blockedTable.put(tid, hl);
}
return hl;
}
static private SleeperSet addSleeperSet(Object o, int time) {
SleeperSet ss = (SleeperSet)sleeperTable.get(o);
if (ss == null) {
ss = new SleeperSet(time);
sleeperTable.put(o, ss);
}
return ss;
}
public void threadGetting(int time, Object o, TraceLine tl) {
Thread tid = (Thread) obj;
HistoryList hl = addBlocked(tid);
hl.add(time, o);
}
public void threadGot(int time, Object o, TraceLine tl, boolean elide) {
Thread tid = (Thread) obj;
HistoryList hl = addBlocked(tid);
if (elide)
hl.removeLast();
else
hl.add(time, null);
}
public void threadReleasing(int time, Object o, TraceLine tl) { // Currently does nothing
if (!(obj instanceof Thread)) throw new DebuggerException("Shadow.threadWaitingFor() expecting a thread: " + obj);
}
public void addSleeper(int time, Thread tid, TraceLine tl) {
SleeperSet ss = addSleeperSet(obj, time);
HistoryList hl = ss.sleepers;
LocksList ll = (LocksList) hl.getLastValue();
if (ll == null) return; // Shouldn't be possible
LocksList llc = (LocksList)ll.clone();
llc.add(new LockerPair(null, tid));
hl.add(time, llc);
}
public void removeSleeperAddOwner(int time, Object o, TraceLine tl, boolean elide) {
Thread tid = tl.getThread();
SleeperSet ss = addSleeperSet(obj, time);
HistoryList shl = ss.sleepers;
HistoryList ohl = ss.owner;
// Remove sleeper
if (elide)
shl.removeLast();
else {
LocksList ll = (LocksList) shl.getLastValue();
if (ll == null) return; // Shouldn't be possible
LocksList llc = (LocksList)ll.clone();
LockerPair removed = llc.removeLP(tid);
if (removed != null) shl.add(time, llc);
}
// Add owner at depth
LockerPair locker = (LockerPair) ohl.getLastValue();
LockerPair lp = new LockerPair(locker, tid);
ohl.add(time, lp);
}
public boolean removeOwner(int time, Object o, TraceLine tl) {
Thread tid = tl.getThread();
SleeperSet ss = addSleeperSet(obj, time);
HistoryList shl = ss.sleepers;
HistoryList ohl = ss.owner;
LockerPair lp = (LockerPair) ohl.getLastValue(); // There must be an owner to get here.
if (lp == null) return true; // Only possible when unbalanced ?
LockerPair prev = lp.previous();
if (lp.getCount() == 1) {
ohl.add(time, null);
return true;
}
ohl.add(time, prev);
return false;
}
public void addWaiterRemoveOwner(int time, Thread tid, TraceLine tl) {
SleeperSet ss = addSleeperSet(obj, time);
HistoryList whl = ss.waiters;
HistoryList ohl = ss.owner;
LocksList wl = (LocksList) whl.getLastValue(); // Get the WAITERS
if (wl == null) return; // Shouldn't be possible
LocksList wlc = (LocksList)wl.clone();
LockerPair owner = (LockerPair) ohl.getLastValue(); // There must be an owner to get here.
wlc.add(owner);
whl.add(time, wlc);
ohl.add(time, null);
}
public void removeWaiterAddOwner(int time, Thread tid, TraceLine tl) {
SleeperSet ss = addSleeperSet(obj, time);
HistoryList whl = ss.waiters;
HistoryList ohl = ss.owner;
LocksList wl = (LocksList) whl.getLastValue(); // Get the WAITERS
if (wl == null) return; // Shouldn't be possible
LocksList wlc = (LocksList)wl.clone();
LockerPair lp = wlc.removeLP(tid);
whl.add(time, wlc);
ohl.add(time, lp);
}
public void addJoiner(int time, Thread tid, TraceLine tl) {
SleeperSet ss = addSleeperSet(obj, time);
HistoryList whl = ss.waiters;
LocksList wl = (LocksList) whl.getLastValue(); // Get the WAITERS
if (wl == null) return; // Shouldn't be possible
LocksList wlc = (LocksList)wl.clone();
wlc.add(new LockerPair(null, tid));
whl.add(time, wlc);
}
public void removeJoiner(int time, Thread tid, TraceLine tl) {
SleeperSet ss = addSleeperSet(obj, time);
HistoryList whl = ss.waiters;
LocksList wl = (LocksList) whl.getLastValue(); // Get the WAITERS
if (wl == null) return; // Shouldn't be possible
LocksList wlc = (LocksList)wl.clone();
LockerPair lp = wlc.removeLP(tid);
whl.add(time, wlc);
}
public void showAll() {
}
public void removeLastShadowVarValue(int i) {
HistoryList hl = shadowVars[i];
hl.removeLast();
}
public void addToShadowVar(int i, int time, Object value) {
nEntries++;
HistoryList hl = getShadowVar(i);
HistoryList hlNew = hl.add(time, value);
if (hlNew != null) shadowVars[i] = hlNew;
}
public void addToShadowVarExtend(int i, int time, Object value) {
nEntries++;
int len = shadowVars.length;
if (i >= len) {
HistoryList[] newVars = new HistoryList[len*2];
System.arraycopy(shadowVars, 0, newVars, 0, len);
shadowVars = newVars;
}
HistoryList hl = shadowVars[i];
if (hl == null) {
shadowVars[i] = new HistoryListSingleton(time, value);
return;
}
hl.add(time, value);
HistoryList hlNew = hl.add(time, value);
if (hlNew != null) shadowVars[i] = hlNew;
}
public HistoryList getShadowVar(int i) {
if (shadowVars == null) return null;
HistoryList hl = shadowVars[i];
if (hl == null) {
if (isVector()) {
MyVector array = (MyVector) obj;
int l = array.size();
hl = new HistoryListSingleton(creationTime, array.elementAt(i));
shadowVars[i] = hl;
return hl;
}
if (isArrayList()) {
MyArrayList array = (MyArrayList) obj;
int l = array.size();
hl = new HistoryListSingleton(creationTime, array.get(i));
shadowVars[i] = hl;
return hl;
}
if (isArray()) {
Class clazz = obj.getClass();
if (clazz == int[].class) {
int[] array = (int[]) obj;
hl = new HistoryListTripleton(creationTime, ShadowInt.createShadowInt(array[i]));
shadowVars[i] = hl;
return hl;
}
if (clazz == long[].class) {
long[] array = (long[]) obj;
hl = new HistoryListTripleton(creationTime, ShadowLong.createShadowLong(array[i]));
shadowVars[i] = hl;
return hl;
}
if (clazz == byte[].class) {
byte[] array = (byte[]) obj;
hl = new HistoryListTripleton(creationTime, ShadowByte.createShadowByte(array[i]));
shadowVars[i] = hl;
return hl;
}
if (clazz == boolean[].class) {
boolean[] array = (boolean[]) obj;
hl = new HistoryListTripleton(creationTime, ShadowBoolean.createShadowBoolean(array[i]));
shadowVars[i] = hl;
return hl;
}
if (clazz == char[].class) {
char[] array = (char[]) obj;
hl = new HistoryListTripleton(creationTime, ShadowChar.createShadowChar(array[i]));
shadowVars[i] = hl;
return hl;
}
if (clazz == short[].class) {
short[] array = (short[]) obj;
hl = new HistoryListTripleton(creationTime, ShadowShort.createShadowShort(array[i]));
shadowVars[i] = hl;
return hl;
}
if (clazz == float[].class) {
float[] array = (float[]) obj;
hl = new HistoryListTripleton(creationTime, ShadowFloat.createShadowFloat(array[i]));
shadowVars[i] = hl;
return hl;
}
if (clazz == double[].class) {
double[] array = (double[]) obj;
hl = new HistoryListTripleton(creationTime, ShadowDouble.createShadowDouble(array[i]));
shadowVars[i] = hl;
return hl;
}
{// Object[]
Object[] array = (Object[]) obj;
hl = new HistoryListTripleton(creationTime, array[i]);
shadowVars[i] = hl;
return hl;
}
}
Field f;
String fieldName = classInfo.getVarName(i);
try { f = classInfo.clazz.getField(fieldName); }
catch (Exception e) {D.println(""+e); f=null;} // Shouldn't ever happen
Object oldValue;
try {oldValue = f.get(obj);} // Returns new Integer() &c. FIX SOMEDAY }
catch (IllegalArgumentException e) { // NARROW!!
D.println("createShadow cannot access field in " + obj + " "+e); oldValue = "ODB Error in createShadow";
}
catch (IllegalAccessException e) { // NARROW!!
D.println("createShadow cannot access field in " + obj + " "+e); oldValue = "ODB Error in createShadow";
}
oldValue = convert(oldValue);
hl = new HistoryListTripleton(creationTime, oldValue);
shadowVars[i] = hl;
}
return(hl);
}
public void setShadowVar(int i, HistoryList hl) {
shadowVars[i]=hl;
}
public Object value() {
return(obj);
}
public TimeStamp getFirstAllVars() {
TimeStamp best = TimeStamp.eot();
int len = size();
for (int i=0; i<len; i++) {
TimeStamp ts = getShadowVar(i).getFirst(); // cannot be null
if (best.laterThan(ts))
best=ts;
}
return(best);// if no IVs, then return eot?
}
public TimeStamp getLastAllVars() {
TimeStamp best = TimeStamp.bot();
int len = size();
for (int i=0; i<len; i++) {
TimeStamp ts = getShadowVar(i).getLast(); // cannot be null
if (ts.laterThan(best))
best=ts;
}
return(best);// if no IVs, then return bot?
}
public TimeStamp getPreviousAllVars() {
TimeStamp best = TimeStamp.bot();
int len = size();
for (int i=0; i<len; i++) {
TimeStamp ts = getShadowVar(i).getPrevious();
if (ts == null) continue;
if (!best.laterThan(ts))
best=ts;
}
if (best.botp())
return(null);
else
return(best);
}
public TimeStamp getNextAllVars() {
TimeStamp best = TimeStamp.eot();
int len = size();
for (int i=0; i<len; i++) {
TimeStamp ts = getShadowVar(i).getNext();
if (ts == null) continue;
if (!ts.laterThan(best)){
best=ts;
}
}
if (best.eotp())
return(null);
else
return(best);
}
public void setForeign(boolean f) {
foreign = f;
}
public static Shadow createShadow(Object o, boolean notForeign) {
Shadow sh =(Shadow) table.get(o);
if (sh == null) {
sh = createShadowInternal(o, notForeign); // Cannot be null
table.put(o, sh);
}
else
sh.setForeign(false);// Why not notForeign??
return sh;
}
private static Shadow createShadowInternal(Object o, boolean notForeign) {
Shadow s;
int time = TimeStamp.eott();
if (!notForeign) time = 0;
Class c;
c = o.getClass();
//String className = c.getName();
s = (Shadow) table.get(o);
if (s != null) {
if (notForeign) s.setForeign(false);
//D.println("Trying to call invokespecial on an existing object: createShadow("+TimeStamp.trimToLength(o, 50)+")");
return s; // How can there already be a shadow?? THIS MAY GET CALLED INAPPROPRIATELY
}
if ((o instanceof Object[])) {
Object[] array = (Object[]) o;
s = new Shadow(TimeStamp.eott(), array, notForeign);
table.put(o, s);
return s;
} else if ((o instanceof int[])) {
int[] array = (int[]) o;
s = new Shadow(TimeStamp.eott(), array, notForeign);
table.put(o, s);
return s;
} else if ((o instanceof int[][])) {
int[][] array = (int[][]) o;
s = new Shadow(TimeStamp.eott(), array, notForeign);
table.put(o, s);
return s;
} else if ((o instanceof short[])) {
short[] array = (short[]) o;
s = new Shadow(TimeStamp.eott(), array, notForeign);
table.put(o, s);
return s;
} else if ((o instanceof byte[])) {
byte[] array = (byte[]) o;
s = new Shadow(TimeStamp.eott(), array, notForeign);
table.put(o, s);
return s;
} else if ((o instanceof char[])) {
char[] array = (char[]) o;
s = new Shadow(TimeStamp.eott(), array, notForeign);
table.put(o, s);
return s;
} else if ((o instanceof boolean[])) {
boolean[] array = (boolean[]) o;
s = new Shadow(TimeStamp.eott(), array, notForeign);
table.put(o, s);
return s;
} else if ((o instanceof long[])) {
long[] array = (long[]) o;
s = new Shadow(TimeStamp.eott(), array, notForeign);
table.put(o, s);
return s;
} else if ((o instanceof double[])) {
double[] array = (double[]) o;
s = new Shadow(TimeStamp.eott(), array, notForeign);
table.put(o, s);
return s;
} else if ((o instanceof float[])) {
float[] array = (float[]) o;
s = new Shadow(TimeStamp.eott(), array, notForeign);
table.put(o, s);
return s;
} else if ((o instanceof MyVector)) {
MyVector v = (MyVector) o;
s = new Shadow(TimeStamp.eott(), v, notForeign);
table.put(o, s);
return s;
} else if ((o instanceof MyArrayList)) {
MyArrayList v = (MyArrayList) o;
s = new Shadow(TimeStamp.eott(), v, notForeign);
table.put(o, s);
return s;
} else if ((o instanceof MyHashtable)) {
MyHashtable h = (MyHashtable) o;
s = new Shadow(TimeStamp.eott(), h, notForeign);
table.put(o, s);
return s;
} else if ((o instanceof MyHashMap)) {
MyHashMap h = (MyHashMap) o;
s = new Shadow(TimeStamp.eott(), h, notForeign);
table.put(o, s);
return s;
}
Field[] f;
int nFields = 0, index = 0;
String[] varNames;
Object[] initValues;
//D.println("Obj: " + o + " in " + c + " " + f);
if ((o instanceof Class)) { // Try to make EVERYTHING a ShadowClass?
index = 0;
try{f = ((Class)o).getFields();}
catch (NoClassDefFoundError e) {Debugger.println("Impossible: NCD "+o); return createShadow(Shadow.class, true);}
Arrays.sort(f, comp);
int len = f.length;
for (int i = 0; i< len; i++) {if (!Modifier.isStatic(f[i].getModifiers())) nFields++;}
varNames = new String[f.length-nFields];
initValues = new Object[f.length-nFields];
for (int i = 0; i< len; i++) {
if (! Modifier.isStatic(f[i].getModifiers())) continue;
//D.println("Class: " + o + " " + f[i]);
String n = f[i].getName().intern();
Class fc = f[i].getType();
Object value;
try {value = f[i].get(o);} // Returns new Integer() &c. FIX SOMEDAY }
catch (IllegalAccessException e) { // NARROW!!
D.println("createShadow cannot access field in " + o + " "+e); value = "ODB Error in createShadow";
}
value = convert(value);
varNames[index] = n;
initValues[index] = value;
index++;
//D.println("createShadow(STATIC): " + o + "." + n + " = (" + fc + ") " + value);
}
s = new Shadow(0, o, varNames, initValues, false); // All Classes (ie statics) are foreign STATICS ARE CONSIDERED TO ALWAYS EXIST
table.put(o, s);
return s;
}
else {
index = 0;
f = c.getFields();
Arrays.sort(f, comp);
int len = f.length;
for (int i = 0; i< len; i++) {if (!Modifier.isStatic(f[i].getModifiers())) nFields++;}
varNames = new String[nFields];
initValues = new Object[nFields];
for (int i = 0; i< len; i++) {
if (Modifier.isStatic(f[i].getModifiers())) continue;
//D.println("Obj: " + o + " in " + c + " " + f[i]);
String n = f[i].getName().intern();
Class fc = f[i].getType();
Object value;
try {value = f[i].get(o);} // Returns new Integer() &c. FIX SOMEDAY }
catch (IllegalAccessException e) { // NARROW!!
D.println("createShadow cannot access field: "+ f[i] +" in: " + o + " "+e); value = "ODB Error in createShadow";
}
value = convert(value);
varNames[index] = n;
initValues[index] = value;
//D.println("createShadow(DYNAMIC): " +index + " "+ c + "."+ o + "." + n + " = (" + fc + ") " + value);
index++;
}
s = new Shadow(time, o, varNames, initValues, notForeign);
table.put(o, s);
return s;
}
/*
// Now check the class is in the table
s = (Shadow) table.get(c);
if (s == null) {
index = 0;
f = c.getFields();
int len = f.length;
for (int i = 0; i< len; i++) {if (!Modifier.isStatic(f[i].getModifiers())) nFields++;}
varNames = new String[f.length-nFields];
initValues = new Object[f.length-nFields];
for (int i = 0; i< len; i++) {
//D.println("Class: " + c +" " + f[i]);
if (! Modifier.isStatic(f[i].getModifiers())) continue;
String n = f[i].getName().intern();
Class fc = f[i].getType();
Object value;
try {value = f[i].get(o);} // Returns new Integer() &c. FIX SOMEDAY }
catch (IllegalAccessException e) { // NARROW!!
D.println("createShadow cannot access field in " + o + " "+e); value = "ODB Error in createShadow";
}
value = convert(value);
varNames[index] = n;
initValues[index] = value;
index++;
//D.println("createShadow(STATIC 2): " + c + "."+ o + "." + n + " = (" + fc + ") " + value);
}
s = new Shadow(time, c, varNames, initValues, notForeign);
table.put(c, s);
return(s);
}
}
return(new Shadow(time, o, new String[0], new String[0], true));
*/
}
public static Object convert(Object value) {
if (value instanceof Integer) return(ShadowInt.createShadowInt(((Integer)value).intValue()));
if (value instanceof Boolean) return(ShadowBoolean.findShadowBoolean(((Boolean)value).booleanValue()));
if (value instanceof Byte) return(ShadowByte.createShadowByte(((Byte)value).byteValue()));
if (value instanceof Character) return(ShadowChar.createShadowChar(((Character)value).charValue()));
if (value instanceof Short) return(ShadowShort.createShadowShort(((Short)value).shortValue()));
if (value instanceof Long) return(ShadowLong.createShadowLong(((Long)value).longValue()));
if (value instanceof Float) return(new ShadowFloat(((Float)value).floatValue()));
if (value instanceof Double) return(new ShadowDouble(((Double)value).doubleValue()));
if (value == null) return ShadowNull.NULL;
return value;
}
private String userSelectedField(Object o) {
if (classInfo == null) return null;
String userSelectedField = classInfo.userSelectedField;
if (userSelectedField == null) return null;
Field[] f;
Object value="IMPOSSIBLE userSelectedField";
f = ((Class)this.obj).getFields();
Arrays.sort(f, comp);
int len = f.length;
for (int i = 0; i< len; i++) {
String n = f[i].getName().intern();
if (n.equals(userSelectedField)) {
try {value = f[i].get(o);} // Returns new Integer() &c. FIX SOMEDAY }
catch (IllegalAccessException e) { // NARROW!!
D.println("userSelectedField cannot access field in " + o + " "+e);
}
if (value == null) return "null";
return value.toString();
}
}
D.println("userSelectedField cannot find field "+userSelectedField+" in " + o);
return "IMPOSSIBLE userSelectedField";
}
// **************************************** Constructors: new Shadow(...) ****************************************
public Shadow() {}
private Shadow(int time, Object o, String[] varNames, Object[] initValues) {
this(time, o, varNames, initValues, false);
}
private Shadow(int time, Object o, String[] varNames, Object[] initValues, String tostring) {
this(time, o, varNames, initValues, false);
this.tostring = this.tostringShort = tostring;
}
private Shadow(int time, Object o, String[] varNames, Object[] initValues, boolean notForeign) {
classInfo = ClassInformation.get(o);
creationTime = time;
shadowVars = new HistoryList[varNames.length];
obj = o;
foreign = !notForeign;
id = classInfo.nextID();
}
private Shadow(int time, Object[] array, boolean notForeign) {
classInfo = ClassInformation.get(array);
obj = array;
creationTime = time;
shadowVars = new HistoryList[array.length];
foreign = !notForeign;
id = classInfo.nextID();
}
private Shadow(int time, String[] array, boolean notForeign) {
classInfo = ClassInformation.get(array);
obj = array;
creationTime = time;
shadowVars = new HistoryList[array.length];
foreign = !notForeign;
id = classInfo.nextID();
}
private Shadow(int time, int[] array, boolean notForeign) {
classInfo = ClassInformation.get(array);
creationTime = time;
obj = array;
shadowVars = new HistoryList[array.length];
foreign = !notForeign;
id = classInfo.nextID();
}
private Shadow(int time, int[][] array, boolean notForeign) {
classInfo = ClassInformation.get(array);
obj = array;
creationTime = time;
shadowVars = new HistoryList[array.length];
foreign = !notForeign;
id = classInfo.nextID();
}
private Shadow(int time, short[] array, boolean notForeign) {
classInfo = ClassInformation.get(array);
obj = array;
creationTime = time;
shadowVars = new HistoryList[array.length];
foreign = !notForeign;
id = classInfo.nextID();
}
private Shadow(int time, byte[] array, boolean notForeign) {
classInfo = ClassInformation.get(array);
obj = array;
creationTime = time;
shadowVars = new HistoryList[array.length];
foreign = !notForeign;
id = classInfo.nextID();
}
private Shadow(int time, char[] array, boolean notForeign) {
classInfo = ClassInformation.get(array);
creationTime = time;
obj = array;
shadowVars = new HistoryList[array.length];
foreign = !notForeign;
id = classInfo.nextID();
}
private Shadow(int time, boolean[] array, boolean notForeign) {
classInfo = ClassInformation.get(array);
obj = array;
creationTime = time;
shadowVars = new HistoryList[array.length];
foreign = !notForeign;
id = classInfo.nextID();
}
private Shadow(int time, long[] array, boolean notForeign) {
classInfo = ClassInformation.get(array);
obj = array;
creationTime = time;
shadowVars = new HistoryList[array.length];
foreign = !notForeign;
id = classInfo.nextID();
}
private Shadow(int time, double[] array, boolean notForeign) {
classInfo = ClassInformation.get(array);
obj = array;
creationTime = time;
shadowVars = new HistoryList[array.length];
foreign = !notForeign;
id = classInfo.nextID();
}
private Shadow(int time, float[] array, boolean notForeign) {
classInfo = ClassInformation.get(array);
obj = array;
creationTime = time;
shadowVars = new HistoryList[array.length];
foreign = !notForeign;
id = classInfo.nextID();
}
private Shadow(int time, MyVector v, boolean notForeign) {
classInfo = ClassInformation.get(v);
obj = v;
creationTime = time;
shadowVars = new HistoryList[v.size()+10];
foreign = !notForeign;
id = classInfo.nextID();
tostring = tostringShort = "<MyVector_"+id+">"; // WHY do I need this?
}
private Shadow(int time, MyArrayList v, boolean notForeign) {
classInfo = ClassInformation.get(v);
obj = v;
creationTime = time;
shadowVars = new HistoryList[v.size()+10];
foreign = !notForeign;
id = classInfo.nextID();
tostring = tostringShort = "<MyArrayList_"+id+">"; // WHY do I need this?
}
public Shadow(int time, MyHashtable v, boolean notForeign) {
classInfo = ClassInformation.get(v);
obj = v;
int i = 0;
creationTime = time;
shadowVars = new HistoryList[v.size()+10];
foreign = !notForeign;
id = classInfo.nextID();
tostring = tostringShort = "<MyHashtable_"+id+">"; // WHY do I need this?
}
public Shadow(int time, MyHashMap v, boolean notForeign) {
classInfo = ClassInformation.get(v);
obj = v;
int i = 0;
creationTime = time;
shadowVars = new HistoryList[v.size()+10];
foreign = !notForeign;
id = classInfo.nextID();
tostring = tostringShort = "<MyHashMap"+id+">"; // WHY do I need this?
}
protected boolean isArray() {
return classInfo.isArray();
}
protected boolean isVector() {
return classInfo.isVector();
}
protected boolean isArrayList() {
return classInfo.isArrayList();
}
protected boolean isHashtable() {
return classInfo.isHashtable();
}
protected boolean isHashMap() {
return classInfo.isHashMap();
}
// Used by SideEffects only
public static void record(Object o, boolean newTS) {
if (newTS) TimeStamp.addStamp(0, TimeStamp.OBJECT_IV);// This really wants to be attached to the RL (yet to be recorded!).
record(o);
}
public static void record(Object o) {
Shadow s = get(o, true);
HistoryList[] shadowVars = s.shadowVars;
int now = TimeStamp.eott();
if (o instanceof Object[]) {
Object[] array = (Object[]) o;
int l = array.length;
for (int i = 0; i < l; i++) {
HistoryList hl = s.getShadowVar(i);
if (hl.getLastValue() != array[i]) s.addToShadowVar(i, now, array[i]);
}
return;
}
if (o instanceof int[]) {
int[] array = (int[]) o;
int l = array.length;
for (int i = 0; i < l; i++) {
HistoryList hl = s.getShadowVar(i);
if (((ShadowInt)hl.getLastValue()).intValue() != array[i]) s.addToShadowVar(i, now, ShadowInt.createShadowInt(array[i]));
}
return;
}
if (o instanceof long[]) {
long[] array = (long[]) o;
int l = array.length;
for (int i = 0; i < l; i++) {
HistoryList hl = s.getShadowVar(i);
if (((ShadowLong)hl.getLastValue()).longValue() != array[i]) s.addToShadowVar(i, now, new ShadowLong(array[i]));
}
return;
}
if (o instanceof float[]) {
float[] array = (float[]) o;
int l = array.length;
for (int i = 0; i < l; i++) {
HistoryList hl = s.getShadowVar(i);
if (((ShadowFloat)hl.getLastValue()).floatValue() != array[i]) s.addToShadowVar(i, now, new ShadowFloat(array[i]));
}
return;
}
if (o instanceof double[]) {
double[] array = (double[]) o;
int l = array.length;
for (int i = 0; i < l; i++) {
HistoryList hl = s.getShadowVar(i);
if (((ShadowDouble)hl.getLastValue()).doubleValue() != array[i]) s.addToShadowVar(i, now, new ShadowDouble(array[i]));
}
return;
}
if (o instanceof byte[]) {
byte[] array = (byte[]) o;
int l = array.length;
for (int i = 0; i < l; i++) {
HistoryList hl = s.getShadowVar(i);
if (((ShadowByte)hl.getLastValue()).byteValue() != array[i]) s.addToShadowVar(i, now, ShadowByte.createShadowByte(array[i]));
}
return;
}
if (o instanceof char[]) {
char[] array = (char[]) o;
int l = array.length;
for (int i = 0; i < l; i++) {
HistoryList hl = s.getShadowVar(i);
if (((ShadowChar)hl.getLastValue()).charValue() != array[i]) s.addToShadowVar(i, now, ShadowChar.createShadowChar(array[i]));
}
return;
}
if (o instanceof short[]) {
short[] array = (short[]) o;
int l = array.length;
for (int i = 0; i < l; i++) {
HistoryList hl = s.getShadowVar(i);
if (((ShadowShort)hl.getLastValue()).shortValue() != array[i]) s.addToShadowVar(i, now, ShadowShort.createShadowShort(array[i]));
}
return;
}
if (o instanceof MyVector) {
MyVector array = (MyVector) o;
int l = array.size();
for (int i = 0; i < l; i++) {
HistoryList hl = s.getShadowVar(i);
if ((hl.getLastValue()) != array.elementAt(i)) s.addToShadowVar(i, now, array.elementAt(i));
}
return;
}
if (o instanceof MyArrayList) {
MyArrayList array = (MyArrayList) o;
int l = array.size();
for (int i = 0; i < l; i++) {
HistoryList hl = s.getShadowVar(i);
if ((hl.getLastValue()) != array.get(i)) s.addToShadowVar(i, now, array.get(i));
}
return;
}
if (o instanceof MyHashtable) {
Debugger.println("Not implmented MyHashtable");
return;
}
if (o instanceof MyHashMap) {
Debugger.println("Not implmented MyHashMap");
return;
}
Field[] f;
int nFields = 0, index = 0;
String[] varNames;
Object[] initValues;
index = 0;
Class c = o.getClass();
f = c.getFields();
Arrays.sort(f, comp);
int len = f.length;
for (int i = 0; i< len; i++) {
if (Modifier.isStatic(f[i].getModifiers())) continue;
Object value;
try {value = f[i].get(o);} // Returns new Integer() &c. FIX SOMEDAY
catch (IllegalAccessException e) { // NARROW!!
D.println("Shadow.record cannot access field in " + o + " "+e); value = "ODB Error in Shadow.record";
}
value = convert(value);
HistoryList hl = shadowVars[index];
if (!value.equals(hl.getLastValue())) hl.add(now, value); // Use equals() because convert() will call new ShadowInt, etc.
index++;
}
}
public String printString() {
return(printString(100));
}
public String printString(int len) {
if (tostring != null)
if (len < 21)
return tostringShort;
else
return tostring;
return createPrintString(len);
}
public String createPrintString(int len) {
if (obj instanceof Class) {
tostring = tostringShort = createClassPrintString(); // -> "int" "String" "int[][]"
return tostring;
}
Class c = obj.getClass();
String cs = createClassTypePrintString(); // -> "int" "String" "int"
if (c.isArray()) {
tostring = tostringShort = createArrayPrintString(cs); // -> "int[3]" "String[2][5][6]"
return tostring;
}
if (obj instanceof Thread) {
tostring = tostringShort = createThreadPrintString(); // -> "<Thread-4>"
return tostring;
}
String userSelectedField = classInfo.userSelectedField;
Object usfValue = null;
if ((userSelectedField != null) || (obj instanceof Number) || (obj instanceof Boolean) || (obj instanceof Character)) {
if (obj instanceof Number) usfValue = obj.toString();
else if (obj instanceof Character) usfValue = obj.toString() + " " + (int) ((Character)obj).charValue();
else if (obj instanceof Boolean) usfValue = obj.toString();
if (userSelectedField != null) usfValue = getLastValue(userSelectedField);
if (usfValue == null) usfValue = "null";
String usfString;
if (usfValue instanceof String)
usfString = (String) usfValue;
else {
// If not String, do something SIMPLE & reasonable. (Someday change to do recursive shadow printString())
// Today: <MyObj_23 <MyObj...>> Someday: <MyObj_23 <MyObj_44>>
if (!(usfValue instanceof Class)) {
usfValue = usfValue.getClass();
usfString = "<"+usfValue.toString()+"...>";
}
else
usfString = usfValue.toString();
}
tostring = "<" + cs + "_" + id + " " + usfString + ">"; // <MyObject_123 Jimmy>
if (tostring.length() < 21)
tostringShort = tostring;
else {
if (cs.length() > 7) cs = cs.substring(0, 6);
if (usfString.length() > 8) usfString = usfString.substring(0, 8);
tostringShort = "<" + cs + ".." + id + " " + usfString + "..>"; // <MyObje..123 Jimm..>
}
}
else {
tostring = "<" + cs + "_" + id + ">"; // <MyObject_123>
if (tostring.length() < 21)
tostringShort = tostring;
else {
if (cs.length() > 12) cs = cs.substring(0, 12);
tostringShort = "<" + cs + ".." + id + ">"; // <MyObje..123>
}
}
if (len < 21)
return tostringShort;
else
return tostring;
}
public String createClassPrintString() { // -> "int" "String" "int[][]"
String s = ((Class)obj).getName(); // "I" "[I" "[[Ljava.lang.String;"
String brackets = "";
if (s.endsWith(";")) s = s.substring(0, s.length()-1); // "I" "[I" "[[Ljava.lang.String"
while(s.startsWith("[")) {s = s.substring(1, s.length()); brackets += "[]";} // "I" "I[]" "Ljava.lang.String[][]"
if (brackets != "") {
if (s.equals("Z")) return "boolean" + brackets; // "boolean" "boolean[]"
if (s.equals("B")) return "byte" + brackets; // "byte" "byte[]"
if (s.equals("C")) return "char" + brackets; // "char" "char[]"
if (s.equals("S")) return "short" + brackets; // "short" "short[]"
if (s.equals("I")) return "int" + brackets; // "int" "int[]"
if (s.equals("J")) return "long" + brackets; // "long" "long[]"
if (s.equals("F")) return "float" + brackets; // "float" "float[]"
if (s.equals("D")) return "double" + brackets; // "double" "double[]"
}
int i = s.lastIndexOf('.');
if (i != -1) return s.substring(i+1, s.length())+brackets; // Trim off packages "Llambda.Debugger.Debugger[]" -> "Debugger[]"
if (brackets != "") return s.substring(1, s.length())+brackets; // Trim off "L" "Lcom.foo.Debugger" -> "Debugger"
return s; // Trim off "L" "LDebugger" -> "Debugger"
}
private String createClassTypePrintString() { // -> "int" "String" "int"
String s = obj.getClass().getName(); // "I" "[I" "[[Ljava.lang.String;"
String brackets = "";
if (s.endsWith(";")) s = s.substring(0, s.length()-1); // "I" "[I" "[[Ljava.lang.String"
while(s.startsWith("[")) {s = s.substring(1, s.length()); brackets += "[]";} // "I" "I[]" "Ljava.lang.String[][]"
if (brackets != "") {
if (s.equals("Z")) return "boolean";
if (s.equals("B")) return "byte";
if (s.equals("C")) return "char";
if (s.equals("S")) return "short";
if (s.equals("I")) return "int";
if (s.equals("J")) return "long";
if (s.equals("F")) return "float";
if (s.equals("D")) return "double";
}
int i = s.lastIndexOf('.');
if (i != -1) return s.substring(i+1, s.length()); // Trim off packages "Llambda.Debugger.Debugger" -> "Debugger"
if (brackets != "") return s.substring(1, s.length()); // Trim off "L" "Lcom.foo.Debugger" -> "Debugger"
return s; // Trim off "L" "LDebugger" -> "Debugger"
}
private String createArrayPrintString(String cs) { // -> "int[3]" "String[2][5][6]"
if (obj instanceof int[][]) {
int[][] array = (int[][])obj; // Try out this style.
int len2=0;
if (array.length > 0) {
int[] a1 = array[0];
len2 = (a1==null) ? 0 : a1.length;
}
tostring =tostringShort = "int[" + array.length + "]["+len2+"]_"+id;
return tostring;
}
if (obj instanceof int[]) {
int[] array = (int[])obj; // Try out this style.
tostring =tostringShort = "int[" + array.length + "]_"+id;
return tostring;
}
if (obj instanceof short[][]) {
short[][] array = (short[][])obj; // Try out this style.
int len2=0;
if (array.length > 0) {
short[] a1 = array[0];
len2 = (a1==null) ? 0 : a1.length;
}
tostring =tostringShort = "short[" + array.length + "]["+len2+"]_"+id;
return tostring;
}
if (obj instanceof short[]) {
short[] array = (short[])obj; // Try out this style.
tostring =tostringShort = "short[" + array.length + "]_"+id;
return tostring;
}
if (obj instanceof byte[][]) {
byte[][] array = (byte[][])obj; // Try out this style.
int len2=0;
if (array.length > 0) {
byte[] a1 = array[0];
len2 = (a1==null) ? 0 : a1.length;
}
tostring =tostringShort = "byte[" + array.length + "]["+len2+"]_"+id;
return tostring;
}
if (obj instanceof byte[]) {
byte[] array = (byte[])obj; // Try out this style.
tostring =tostringShort = "byte[" + array.length + "]_"+id;
return tostring;
}
if (obj instanceof char[][]) {
char[][] array = (char[][])obj; // Try out this style.
int len2=0;
if (array.length > 0) {
char[] a1 = array[0];
len2 = (a1==null) ? 0 : a1.length;
}
tostring =tostringShort = "char[" + array.length + "]["+len2+"]_"+id;
return tostring;
}
if (obj instanceof char[]) {
char[] array = (char[])obj; // Try out this style.
tostring =tostringShort = "char[" + array.length + "]_"+id;
return tostring;
}
if (obj instanceof boolean[][]) {
boolean[][] array = (boolean[][])obj; // Try out this style.
int len2=0;
if (array.length > 0) {
boolean[] a1 = array[0];
len2 = (a1==null) ? 0 : a1.length;
}
tostring =tostringShort = "boolean[" + array.length + "]["+len2+"]_"+id;
return tostring;
}
if (obj instanceof boolean[]) {
boolean[] array = (boolean[])obj; // Try out this style.
tostring =tostringShort = "boolean[" + array.length + "]_"+id;
return tostring;
}
if (obj instanceof long[][]) {
long[][] array = (long[][])obj; // Try out this style.
int len2=0;
if (array.length > 0) {
long[] a1 = array[0];
len2 = (a1==null) ? 0 : a1.length;
}
tostring =tostringShort = "long[" + array.length + "]["+len2+"]_"+id;
return tostring;
}
if (obj instanceof long[]) {
long[] array = (long[])obj; // Try out this style.
tostring =tostringShort = "long[" + array.length + "]_"+id;
return tostring;
}
if (obj instanceof double[][]) {
double[][] array = (double[][])obj; // Try out this style.
int len2=0;
if (array.length > 0) {
double[] a1 = array[0];
len2 = (a1==null) ? 0 : a1.length;
}
tostring =tostringShort = "double[" + array.length + "]["+len2+"]_"+id;
return tostring;
}
if (obj instanceof double[]) {
double[] array = (double[])obj; // Try out this style.
tostring =tostringShort = "double[" + array.length + "]_"+id;
return tostring;
}
if (obj instanceof float[][]) {
float[][] array = (float[][])obj; // Try out this style.
int len2=0;
if (array.length > 0) {
float[] a1 = array[0];
len2 = (a1==null) ? 0 : a1.length;
}
tostring =tostringShort = "float[" + array.length + "]["+len2+"]_"+id;
return tostring;
}
if (obj instanceof float[]) {
float[] array = (float[])obj; // Try out this style.
tostring =tostringShort = "float[" + array.length + "]_"+id;
return tostring;
}
if (obj instanceof Object[][]) {
Object[][] array = (Object[][])obj; // Try out this style.
int len2=0;
if (array.length > 0) {
Object[] a1 = array[0];
len2 = (a1==null) ? 0 : a1.length;
}
tostring =tostringShort = cs+"[" + array.length + "]["+len2+"]_"+id;
return tostring;
}
if (obj instanceof Object[]) { // class [Ljava.lang.Object;@49cf9f
Object[] array = (Object[])obj; // Try out this style.
tostring =tostringShort = cs+"[" + array.length + "]_"+id;
return tostring;
}
return cs+"[n][n]?";
}
private String createThreadPrintString() {
String s = ((Thread)obj).getName();
if ((s == null) || (s.length() == 0)) {s = "Unnamed Thread";}
//if (Character.isDigit(s.charAt(s.length()-1))) // Allow <Thread-2> etc.
//tostring = tostringShort = "<"+s+">";
//else
tostring = tostringShort = "<"+s+"_"+id+">";
return tostring;
}
public String toString() { // This only gets called from JList in ObjectPane & ThisPane
/* if (Debugger.NATIVE_TOSTRING)
return(TimeStamp.trimNativeToString(obj));
else
*/
if (foreign)
return(TimeStamp.trimToLength(obj, 500) + " @");
else
return(TimeStamp.trimToLength(obj, 500));
}
public Object getSelectedObject(int x, FontMetrics fm) {
/*
String str = TimeStamp.trimToLength(obj, MAX_LENGTH_DISPLAY);
if (x < fm.stringWidth(str)) return(obj);
return(null);
*/
return(obj); // Let 'em click anywhere on the line
}
public String toString(int room) {
if (obj instanceof Shadow) return "<Shadow RECURSIVE TOSTRING(n) CALL "+id+" ??!>";
return("<Shadow " + TimeStamp.trimToLength(obj, room) + " " + classInfo + " " + ">");
}
public static Shadow get(Object o) {return get(o, false);}
public static Shadow get(Object o, boolean discoveryAtZero) {
if (o == null) {o = "IMPOSSIBLE:NULL OBJECT FOR SHADOW"; Debugger.println("Shadow.get " + o);}
Shadow s = (Shadow) table.get(o);
if (s == null) {
s = createShadow(o, true); // Hack for dynamic creation
}
return s; // null is NOT legal
}
public static Shadow getNoCreation(Object o) {
if (o == null) {o = "IMPOSSIBLE:NULL OBJECT FOR SHADOW2 "; Debugger.println("Shadow.get " + o);}
Shadow s = (Shadow) table.get(o);
return s; // null is legal
}
public static Shadow getCreateNoDash(Object o) {
if (o == null) {o = "IMPOSSIBLE:NULL OBJECT FOR SHADOW22 "; Debugger.println("Shadow.get " + o);}
Shadow s = (Shadow) table.get(o);
if (s == null) {
s = createShadow(o, false);
}
return s; // null is legal
}
// ADD value TO THE HISTORYLIST OF the array[ index ] AT file:line
public int add(int slIndex, int index, Object value, TraceLine tl) {
int time = TimeStamp.addStamp(slIndex, TimeStamp.ONE_D_ARRAY, tl);
if (!legalSize(index)) {
//D.println("Attempting to save an element at an index that wasn't seen in reflection " +index +" "+this);
return time;
}
addToShadowVar(index, time, value);
return time;
}
// shadow.hashtablePut(sl, key, value);
public int hashtableRemove(int slIndex, Object key) {
int time = TimeStamp.addStamp(slIndex, TimeStamp.OBJECT_IV);
int index;
for (index = 0; index < size(); index++) {
HistoryListHashtable hlh = (HistoryListHashtable)shadowVars[index]; // Cannot be null
Object k = hlh.key;
if (k == null) {
throw new DebuggerException("htput bug " + this);
}
if (key.equals(k)) {
addToShadowVar(index, time, Dashes.DASHES);
return time;
}
}
return time; // Stupid, but possible
}
public void hashtableClear(int slIndex) {
int time = TimeStamp.addStamp(slIndex, TimeStamp.OBJECT_IV);
int len = size();
for (int index = 0; index < len; index++) {
HistoryListHashtable hlh = (HistoryListHashtable)shadowVars[index]; // Cannot be null
addToShadowVar(index, time, Dashes.DASHES);
}
}
public int hashtablePut(int slIndex, Object key, Object value) {
int time = TimeStamp.addStamp(slIndex, TimeStamp.OBJECT_IV);
int index;
for (index = 0; index < size(); index++) {
HistoryListHashtable hlh = (HistoryListHashtable)shadowVars[index]; // Cannot be null
Object k = hlh.key;
if (k == null) {
throw new DebuggerException("htput bug " + this);
}
if (key.equals(k)) {
addToShadowVar(index, time, value);
return time;
}
}
HistoryList[] newHL = new HistoryList[index+10];
for (int i = 0; i < index; i++) newHL[i] = shadowVars[i];
shadowVars = newHL;
HistoryList hl = new HistoryListHashtable(time, value, key);
setShadowVar(index, hl);
return time;
}
// ******************************** VECTORS ********************************
// ADD value TO THE HISTORYLIST OF the vector[ index ] AT file:line
public int vectorChange(int slIndex, int index, Object value) {
int time = TimeStamp.addStamp(slIndex, TimeStamp.OBJECT_IV);
if (index >= size()) record(obj);
addToShadowVar(index, time, value);
return time;
}
// ADD value TO THE HISTORYLIST OF the vector[ index ] AT file:line
public int vectorRemove(int slIndex, int index, int range) {
int time = TimeStamp.addStamp(slIndex, TimeStamp.OBJECT_IV);
int elementCount = size();
if (index >= elementCount) {
record(obj);
//Debugger.println("Impossible vectorRemove "+index);
return time;
}
for (int i = index; i < elementCount; i++) {
Object value = Dashes.DASHES;
if (i+range<elementCount) value = getShadowVar(i+range).getLastValue();
if ((value == Dashes.DASHES) && (getShadowVar(i).getLastValue() == Dashes.DASHES)) return time;
addToShadowVar(i, time, value);
}
return time;
}
// shadow.vectorInsert(sl, index, elementCount, value);
public int vectorInsert(int slIndex, int index, Object value) {
int time = TimeStamp.addStamp(slIndex, TimeStamp.OBJECT_IV);
int elementCount = size();
if (index > elementCount) {
record(obj);
// Debugger.println("Impossible vectorInsert: "+index+">"+elementCount+" "+this);
return time;
}
for (int i = elementCount; i > index; i--) {
Object v = getShadowVar(i-1).getLastValue();
if (v != Dashes.DASHES) addToShadowVarExtend(i, time, v);
}
addToShadowVarExtend(index, time, value);
return time;
}
// ******************************** ARRAYLISTS ********************************
/*
// ADD value TO THE HISTORYLIST OF the vector[ index ] AT file:line
public int arraylistChange(int slIndex, int index, Object value) {
int time = TimeStamp.addStamp(slIndex, TimeStamp.OBJECT_IV);
if (index >= size()) record(obj);
addToShadowVar(index, time, value);
return time;
}
// ADD value TO THE HISTORYLIST OF the arraylist[ index ] AT file:line
public int arraylistRemove(int slIndex, int index, int range) {
int time = TimeStamp.addStamp(slIndex, TimeStamp.OBJECT_IV);
int elementCount = ((ArrayList)obj).size()+range;
if (index >= elementCount) {Debugger.println("Impossible arraylistRemove "+index); return time;}
if (index < 0) {Debugger.println("Impossible arraylistRemove "+index); return time;}
for (int i = index; i < elementCount; i++) {
Object value = Dashes.DASHES;
if (i+range<elementCount) value = getShadowVar(i+range).getLastValue();
addToShadowVar(i, time, value);
}
return time;
}
// shadow.arraylistInsert(sl, index, elementCount, value);
public int arraylistInsert(int slIndex, int index, Object value) {
int time = TimeStamp.addStamp(slIndex, TimeStamp.OBJECT_IV);
if (index == -1) index = this.size();// Append to AL
int elementCount = ((ArrayList)obj).size()-1;
if (index > elementCount) {D.println("Impossible arraylistInsert"); return time;}// Arraylist.insert() will throw 2nd.
for (int i = elementCount; i > index; i--) {
Object v = getShadowVar(i-1).getLastValue();
addToShadowVarExtend(i, time, v);
}
addToShadowVarExtend(index, time, value);
return time;
}
*/
// Add value to the historylist of varName in 'this' at file:line
public int add(int slIndex, String varName, Object value, TraceLine tl) {
int time = TimeStamp.addStamp(slIndex, TimeStamp.OBJECT_IV, tl);
int len = size();
int i = classInfo.getVarIndex(varName);
if (i == -1) return time;
addToShadowVar(i, time, value);
return time;
}
public Object getLastValue(String varName) {
int time = TimeStamp.eott();
int len = size();
int i = classInfo.getVarIndex(varName);
if (i == -1) return null;
return(getShadowVar(i).getLastValue());
}
public Object getValue(String varName, TimeStamp ts) {
int len = size();
int i = classInfo.getVarIndex(varName);
if (i == -1) return null;
return(getShadowVar(i).valueOn(ts, foreign));
}
public boolean legalSize(int index) {
return (index < shadowVars.length);
}
public int size() {
if (isHashtable() || isHashMap() || isVector() || isArrayList()) {
for (int i = 0; i < shadowVars.length; i++) {
if (shadowVars[i] == null) return i;
}
}
return shadowVars.length;
}
public void print() {
System.out.println(this.toString(40));
/* int len = size();
for (int i=0; i<len; i++) {
System.out.println(getVarName(i) + " \t");
getShadowVar(i).print();
}
*/
}
public static void printAll() {
System.out.println("\n=====================Shadow Objects=====================");
Set set = table.entrySet();
Set setCopy = new HashSet(set);
Iterator i = setCopy.iterator(); // This will NOT cause ConcurrentModificationException
while (i.hasNext()) {
Object o = i.next();
Shadow s = (Shadow) ((Map.Entry)o).getValue();
s.print();
}
System.out.println("=====================Shadow Objects=====================\n");
}
/*
public static void main(String[] args) {
try {
Object o = new MyObj();
Class c = o.getClass();
Field f[] = c.getFields();
D.println("Obj: " + o + " in " + c + " " + f);
for (int i = 0; i< f.length; i++) {
String n = f[i].getName().intern();
Class fc = f[i].getType();
Object value = f[i].get(o);
D.println("Obj: " + o + " in " + c + " " + n + " " + fc + " " + value);
createShadow(o, true);
}
}
catch (Exception e) { D.println(e); }
String[] vars = {"m", "n", "a"};
MyObj mo1=new MyObj(), mo2=new MyObj();
D.println("----------------------Shadow----------------------\n");
int time1 = TimeStamp.addStamp("foo.x:1");
int time2 = TimeStamp.addStamp("foo.x:2");
//Shadow.shadow(ts1, mo1, vars);
//Shadow.shadow(ts2, mo2, vars);
printAll();
TimeStamp a, b, c;
String file ="/tmp/foo.java";
Shadow s1 = get(mo1);
Shadow s2 = get(mo2);
a=s1.add(file, 1, "m", "<Int 77>");
s1.add(file, 11, "m", "<Int 775>");
s1.add(file, 11, "m", "<Int 777>");
s1.add(file, 1111, "m", "<Int 778>");
s1.add(file, 12, "n", "<Int 771>");
b=s1.add(file, 122, "n", "<Int 772>");
s1.add(file, 1222, "a", "<Int 773>");
s2.add(file, 1111, "m", "<Int 778>");
s2.add(file, 12, "n", "<Int 771>");
s2.add(file, 122, "n", "<Int 772>");
c=s2.add(file, 1222, "a", "<Int 773>");
TimeStamp.setCurrentTime(a);
s1.print();
s2.print();
printAll();
TimeStamp.printAll();
D.println("First: "+s1.getFirstAllVars().toString(0));
D.println("First: "+s2.getFirstAllVars().toString(0));
D.println("Last: "+s1.getLastAllVars().toString(0));
D.println("Last: "+s2.getLastAllVars().toString(0));
TimeStamp n;
TimeStamp.setCurrentTime(a);
n = s1.getNextAllVars();
if (n == null)
D.println("Next from "+a+" --");
else
D.println("Next from "+a+" "+n.toString(0));
n = s1.getPreviousAllVars();
if (n == null)
D.println("Prev from "+a+" --");
else
D.println("Prev from "+a+" "+n.toString(0));
TimeStamp.setCurrentTime(b);
n = s1.getNextAllVars();
if (n == null)
D.println("Next from "+b+" --");
else
D.println("Next from "+b+" "+n.toString(0));
n = s1.getPreviousAllVars();
if (n == null)
D.println("Prev from "+b+" --");
else
D.println("Prev from "+b+" "+n.toString(0));
TimeStamp.setCurrentTime(c);
n = s1.getNextAllVars();
if (n == null)
D.println("Next from "+c+" --");
else
D.println("Next from "+c+" "+n.toString(0));
n = s1.getPreviousAllVars();
if (n == null)
D.println("Prev from "+c+" --");
else
D.println("Prev from "+c+" "+n.toString(0));
TimeStamp.setCurrentTime(a);
D.println("Object toString at: "+a+" " + s1 + " "+ s2);
TimeStamp.setCurrentTime(b);
D.println("Object toString at: "+b+" " + s1 + " "+ s2);
TimeStamp.setCurrentTime(c);
D.println("Object toString at: "+c+" " + s1 + " "+ s2);
D.println("----------------------Shadow----------------------\n");
}
*/
}