/* Locals.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; // Locals/Locals.java /* */ import java.util.HashMap; public abstract class Locals { static int MAX_INTERNAL = 10; static HashMap varNameTable = new HashMap(); // "com.lambda.Debugger.Debugger.main:15" // -> {"i", "j"...} static HashMap varTypeTable = new HashMap(); // "com.lambda.Debugger.Debugger.main:15" // -> {Demo, ShadowInt, ...} or the string name! static HashMap retTypeTable = new HashMap(); // "com.lambda.Debugger.Debugger.main:15" // -> Demo or the string name! static int nTripletons = 0, nSingletons = 0, nMultitons = 0, nHLists = 0, nHLEntries = 0, emptyHLs = 0; static int wastedTripletons = 0, wastedMultitons = 0, nLObjects = 0; static int nBindings = 0; static String[] defaultNames = { "var0", "var1", "var2", "var3", "var4", "var5", "var6", "var7",// Only for MyVector? "var8", "var9", "vara", "varb", "varc", "vard", "vare", "varf", "varg", "varh", "vari", "varj", "vark", "varl", "varm", "varn", "varn", "varo", "varp", "varq", "varr", "vars", "vart", "varu" }; static int[] sizes = new int[30]; public static Locals DEFAULT = createLocals(0, TraceLine.defaultTraceLine(), "unknown", 0); String methodID; // "foo.MyObj:frob:3" TraceLine tl; int creationTime; public final void setMethodID(String mid) { methodID = mid; } abstract public int getNLocals(); public void setNLocals(int nLocals) { throw new DebuggerException("Cannot change nLocals if not LocalsMore"); } public VectorD createShadowLocals() { VectorD v = new VectorD(); int nLocals = getNLocals(); for (int i = 0; i < nLocals; i++) { HistoryList hl = getHLCreate(i); if (hl == null) continue; String varName = getVarName(i); v.add(new ShadowLocal(varName, hl, i, this)); } return v; } static void appendVarNames(String methodID, String[] sa) { varNameTable.put(methodID, sa); } // 6/Mar/07 loading the type early causes out-of-order load problems. static void appendVarTypes(String methodID, String[] sa, String returnTypeString, ClassLoader cl) { Object[] varTypes = new Object[sa.length]; for (int i = 0; i < sa.length; i++) { String s = sa[i]; varTypes[i] = new Object[] { s, cl };// parseType(s, cl); } varTypeTable.put(methodID, varTypes); retTypeTable.put(methodID, new Object[] { returnTypeString, cl });// parseType(returnTypeString, // cl)); } public static Class parseType(String s0, ClassLoader cl) { Class type = null; boolean isArray = false, isArray2 = false; if (s0 == null) return null; String s = s0.replace('/', '.'); if (s.startsWith("L") && s.endsWith(";")) { s = s.substring(1, s.length() - 1); } // "Lcom.lambda.Foo;" -> "com.lambda.Foo" if (s == "I") { type = (isArray2 ? int[][].class : (isArray ? int[].class : int.class)); } else if (s == "B") { type = (isArray2 ? byte[][].class : (isArray ? byte[].class : byte.class)); } else if (s == "Z") { type = (isArray2 ? boolean[][].class : (isArray ? boolean[].class : boolean.class)); } else if (s == "C") { type = (isArray2 ? char[][].class : (isArray ? char[].class : char.class)); } else if (s == "S") { type = (isArray2 ? short[][].class : (isArray ? short[].class : short.class)); } else if (s == "J") { type = (isArray2 ? long[][].class : (isArray ? long[].class : long.class)); } else if (s == "F") { type = (isArray2 ? float[][].class : (isArray ? float[].class : float.class)); } else if (s == "D") { type = (isArray2 ? double[][].class : (isArray ? double[].class : double.class)); } else if (s == "V") { type = ShadowVoid.class; } else { if (isArray2) s = "[[L" + s + ";"; if (isArray) s = "[L" + s + ";"; // System.out.println("CL "+ // Debugger.classLoader); try { type = Class.forName(s, true, cl); } catch (Exception e) { Debugger.println("Locals.parseType() could not find " + s); } } // System.out.println(s0+" "+ s + ":\t\t "+type); return type; } public void compact(int eot) { int t = TimeStamp.forward(creationTime); if (t == -1) creationTime = 0; else creationTime = t; int len = getNLocals(); for (int i = 0; i < len; i++) { HistoryList hl = getHL(i); if (hl == null) { int varIndex = i - tl.getArgCount(); if (varIndex < 0) continue; // args are bound w/o a time int time0 = getTime(varIndex); if (time0 == -1) continue; time0 = TimeStamp.forward(time0); if (time0 == -1) time0 = 0; setTime(varIndex, time0); } else hl.compact(eot); } } public void verify(int eot) { int len = getNLocals(); for (int i = 0; i < len; i++) { HistoryList hl = getHL(i); if (hl == null) continue; hl.verify(eot); } } // constructors static public Locals createLocals(int time, TraceLine tl, String methodID, int nLocals) { int nLocals2 = nLocals - tl.getArgCount(); if (nLocals2 >= 0) // throw new DebuggerException("IMPOSSIBLE: nLocals: " + nLocals // + " nArgs: " + tl.getArgCount() + " for: "+ methodID +" on:"+tl); nLocals = nLocals2; // The correct fix is to repair the BCEL code to handle the 1.5 compiler // dumb stuff corrrectly. (The compiler generates entries for the LVT // only for the programmer's variables, not "hidden" ones. The 1.4 // compiler // did both and I wrote for that.) // This hack just allocates extra space in that case. // Are there other forms of this where nLocals2 will be > 0, but still // too small? switch (nLocals) { case 0: return new Locals0(time, tl, methodID); case 1: return new Locals1(time, tl, methodID); case 2: return new Locals2(time, tl, methodID); case 3: return new Locals3(time, tl, methodID); case 4: return new Locals4(time, tl, methodID); case 5: return new Locals5(time, tl, methodID); case 6: return new Locals6(time, tl, methodID); case 7: return new Locals7(time, tl, methodID); case 8: return new Locals8(time, tl, methodID); case 9: return new Locals9(time, tl, methodID); case 10: return new Locals10(time, tl, methodID); default: return new LocalsMore(time, tl, methodID, nLocals); } } protected Locals(int time, TraceLine tl, String methodID) { this.creationTime = time; this.tl = tl; this.methodID = methodID; } public String getVarName(int i) { String[] varNames = (String[]) varNameTable.get(methodID); if (varNames == null) varNames = defaultNames; if (varNames.length <= i) return "MISSING_VAR_NAME"; return varNames[i]; } public int getVarIndex(String varName) { String[] varNames = (String[]) varNameTable.get(methodID); if (varNames == null) return -1; for (int i = 0; i < varNames.length; i++) if (varNames[i] == varName) return i; return -1; } public String[] getVarNames() { String[] varNames = (String[]) varNameTable.get(methodID); if (varNames == null) varNames = defaultNames; return varNames; } public Class getReturnType() { Object type = (Object) retTypeTable.get(methodID); if (type instanceof Object[]) { Object[] oa = (Object[]) type; type = parseType((String) oa[0], (ClassLoader) oa[1]); retTypeTable.put(methodID, type); } return (Class) type; } public Class getVarType(int i) { Object[] varTypes = (Object[]) varTypeTable.get(methodID); if (varTypes == null) return null; if (varTypes.length <= i) return null; Object o = varTypes[i]; if (o instanceof Object[]) { Object[] oa = (Object[]) o; o = parseType((String) oa[0], (ClassLoader) oa[1]); varTypes[i] = o; } return (Class) o; } // public Class[] getVarTypes() { // Class[] varTypes = (Class[]) varTypeTable.get(methodID); // if (varTypes == null) // return null; // return varTypes; // } public String toString() { String s = "["; for (int i = 0; i < getNLocals(); i++) { s += getVarName(i) + ", "; } return ("<Locals " + methodID + " " + s + "]>"); // +" // "+trace.toString(10)+">"); } public void printAll() { for (int i = 0; i < getNLocals(); i++) { HistoryList hl = getHL(i); System.out.println(hl); } } public void add(int slIndex, int varIndex, Object value, TraceLine tl) { int time = TimeStamp.addStamp(slIndex, TimeStamp.LOCAL, tl); // LSD.record(varIndex, value, this, time); int nArgsTL = tl.getArgCount(); HistoryList hl; if (varIndex < nArgsTL) { Object o = tl.getArgActual(varIndex); if (o instanceof HistoryList) hl = (HistoryList) o; else { hl = new HistoryListTripleton(creationTime, o); // Assume we're // doing an // add(). hl.add(time, value); tl.putArg(varIndex, hl); return; } HistoryList hlNew = hl.add(time, value); if (hlNew != null) tl.putArg(varIndex, hlNew); return; } varIndex -= nArgsTL; Object v = getObject(varIndex); if (v instanceof HistoryList) { hl = (HistoryList) v; HistoryList hlNew = hl.add(time, value); if (hlNew != null) putHL(varIndex, hlNew); return; } int t = getTime(varIndex); if (t > -1) { hl = new HistoryListTripleton(t, v); // Assume we're doing an // add(). hl.add(time, value); putHL(varIndex, hl); } else { setValue(varIndex, time, value); } return; } private HistoryList getHL(int i) { // Only used for GC int nArgsTL = tl.getArgCount(); Object o; if (i < nArgsTL) o = tl.getArgActual(i); else o = getObject(i - nArgsTL); if (o instanceof HistoryList) return (HistoryList) o; return null; } public HistoryList getHLCreate(int varIndex) { int nArgsTL = tl.getArgCount(); if (varIndex < nArgsTL) { Object o = tl.getArgActual(varIndex); if (o instanceof HistoryList) return (HistoryList) o; return new HistoryListSingleton(creationTime, o); // Assume we're // doing an // ShadowLocals } varIndex = varIndex - nArgsTL; Object o = getObject(varIndex); if (o instanceof HistoryList) return (HistoryList) o; int t = getTime(varIndex); if (t > -1) return new HistoryListSingleton(t, o); return null; } public void bind(int varIndex, Object value, TraceLine tl) { int nArgsTL = tl.getArgCount(); if (varIndex < nArgsTL) throw new DebuggerException("Local var unbound IMPOSSIBLE " + varIndex + " " + value); varIndex -= nArgsTL; setValue(varIndex, creationTime, value); } abstract void setValue(int varIndex, int time, Object value); abstract void putHL(int i, HistoryList hl); abstract Object getObject(int i); abstract int getTime(int i); abstract void setTime(int varIndex, int time); public static void main(String[] args) { System.out .println("----------------------Locals----------------------\n"); System.out .println("----------------------Locals----------------------\n"); } static public void printStatistics() { nSingletons = 0; nTripletons = 0; wastedTripletons = 0; wastedMultitons = 0; nMultitons = 0; sizes = new int[30]; nHLists = 0; nHLEntries = 0; nBindings = 0; emptyHLs = 0; nLObjects = 0; TraceLine.countInstrumentedMethods(); System.out.println("\n -- Locals Statistics -- "); System.out.println("Out of " + nLObjects + " Locals with " + nHLists + " HistoryLists and " + nHLEntries + " entries..."); System.out.println(" " + emptyHLs + " empty HLs"); System.out.println(" " + nBindings + " simple bindings"); 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]); } public void countSizes() { nLObjects++; for (int i = 0; i < getNLocals(); i++) { HistoryList hl = getHL(i); nHLists++; if (hl == null) { emptyHLs++; continue; } int size = hl.size(); nHLEntries += size; nBindings += tl.getArgCount(); 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 < 400) 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]++; } } } }