Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: jreversepro/runtime/JSymbolTable.java


1   /*
2   * @(#)JSymbolTableImpl.java
3   *
4   * JReversePro - Java Decompiler / Disassembler.
5   * Copyright (C) 2000 2001 Karthik Kumar.
6   * EMail: akkumar@users.sourceforge.net
7   *
8   * This program is free software; you can redistribute it and/or modify
9   * it , under the terms of the GNU General Public License as published
10  * by the Free Software Foundation; either version 2 of the License,
11  * or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16  * See the GNU General Public License for more details.
17  * You should have received a copy of the GNU General Public License
18  * along with this program.If not, write to
19  *  The Free Software Foundation, Inc.,
20  *  59 Temple Place - Suite 330,
21  *  Boston, MA 02111-1307, USA.
22  **/
23  package jreversepro.runtime;
24  
25  import jreversepro.common.KeyWords;
26  import jreversepro.common.Helper;
27  
28  import jreversepro.reflect.JMethod;
29  import jreversepro.reflect.JImport;
30  import jreversepro.reflect.JInstruction;
31  
32  import jreversepro.revengine.RevEngineException;
33  
34  import java.util.HashMap;
35  import java.util.Map;
36  import java.util.List;
37  import java.util.Vector;
38  import java.util.Collections;
39  import java.util.Enumeration;
40  import java.util.Iterator;
41  
42  /**
43   * JSymbolTable  - Symbol Table of a method containing local variables only.
44   * @author Karthik Kumar
45   **/
46  public class JSymbolTable implements KeyWords {
47  
48      /**
49       * Map of the Symbols -
50       * Key - local variable index - java.lang.Integer
51       * Value - List of JLocalEntry.
52       *   since for the same localvariable index more than one
53       *   datatype may exist.
54       **/
55      Map symbols;
56  
57  
58      /**
59       * Key - Symbol Name
60       * Value - JLocalEntry.
61       **/
62      Map symNames;
63  
64      /**
65       * List of keywords in the language
66       **/
67      static List keywords;
68  
69      /**
70       * Maximum number of symbols that can be in the table at any given
71       * time
72       **/
73      int maxSymbols;
74  
75      /**
76       * Maximum args in that symbol count mentioned in maxSymbols
77       **/
78      int maxArgs;
79  
80      /**
81       * basicIndex here.
82       **/
83      int basicIndex;
84  
85      /**
86       *  Imported Classes here.
87       **/
88      JImport imports;
89  
90      /**
91       * Index of the argument into the symbol table.
92       **/
93      public static final int ARG_INDEX  = -1;
94  
95      /**
96       * Static initializers - Keywords
97       **/
98      static {
99          keywords = getKeyWordsList();
100     }
101 
102     /**
103      * @param rhsMethod Method for which this symbol table
104      * is generated and used.
105      * @param imports ImportedClasses by this class.
106      **/
107     public JSymbolTable(JMethod rhsMethod,
108                            JImport imports) {
109 
110         this.imports = imports;
111         List args = rhsMethod.getArgList();
112         int startIndex = 1;
113 
114         maxSymbols = rhsMethod.getMaxLocals();
115         maxArgs =  args.size();
116 
117         //Symbols = new HashSet();
118         symbols = new HashMap();
119         symNames = new HashMap();
120 
121         basicIndex  = (int) ('i');
122         //Starts with variable 'i'.
123 
124 
125         if (!rhsMethod.isStatic()) {
126             startIndex = 1;
127             addEntry(0, -1, THISCLASS, true);
128             //Load the first entry for this pointer.
129             //Current class reference.
130         } else {
131             maxArgs--;
132             startIndex = 0;
133         }
134 
135         //Loads the Arguments onto symbol table.
136         loadSymbols(args, startIndex);
137     }
138 
139     /**
140      * @return Get the maximum number of symbols
141      * available in the scope of the current method.
142      **/
143     public int getMaxSymbols() {
144         return maxSymbols;
145     }
146 
147    /**
148     * @param aArgs List of arguments containing the argument
149     * types.
150     * @param startIndex Initial Start Index of the variable count.
151     **/
152     private void loadSymbols(List aArgs, int startIndex) {
153         int symIndex = startIndex;
154         for (int i = 0 ; i < aArgs.size(); i++) {
155             String argType =  (String) aArgs.get(i);
156             addEntry(symIndex++, ARG_INDEX, argType, true);
157             if (argType.equals(LONG)
158               || argType.equals(DOUBLE)) {
159                //Since both long and double take two entries.
160                //increment the symbol table count
161                symIndex++;
162             }
163         }
164     }
165 
166     /**
167      * Adds a new datatype to the symboltable
168      * dynamically .
169      * Parameters  required are the
170      * @param aVarIndex variable index ,
171      * @param aDatatype Datatype
172      * @param aVarStore variable store index.
173      * @param aDeclared If variable is declared.
174      **/
175     public void assignDataType(int aVarIndex, String aDatatype,
176                                int aVarStore, boolean aDeclared) {
177 
178         if ((aVarIndex > JInstruction.INVALID_VAR_INDEX
179             &&   aVarIndex <= maxArgs)) {
180             return;
181             //No reassignment of data types for arguments.
182         }
183         JLocalEntry ent  = getMatchingEntry(aVarIndex, aVarStore);
184         if (ent != null) {
185             if (aDatatype.equals(REFERENCE)) {
186                 return;
187             }
188         } else {
189             if (aDatatype.equals(REFERENCE)) {
190                 aDatatype = LANG_OBJECT;
191             }
192         }
193         addEntry(aVarIndex, aVarStore, aDatatype, aDeclared);
194     }
195 
196     /**
197      * This method primarily keeps track of the last line
198      * that references the variable represented by
199      * aVarIndex and the datatype aDataType.
200      * Please note that this referencing is essential to define the
201      * variables correctly, neither too early, nor too late.
202      * Also this is not necessary for arguments, but more
203      * necessary for localvariables whose declarations are
204      * inside the method code block.
205      * @param aVarIndex variable index ,
206      * @param aDatatype Datatype
207      * @param aIndex Refernced index.
208      **/
209     public void addReference(int aVarIndex, String aDatatype,
210                                     int aIndex) {
211 
212         if ((aVarIndex > JInstruction.INVALID_VAR_INDEX
213                 && aVarIndex <= maxArgs)) {
214             return;
215             //Not necessary to keep track of referenced line numbers.
216             //Since the variable is an argument.
217         }
218         List currentList = (List) symbols.get(new Integer(aVarIndex));
219         JLocalEntry createEntry = new JLocalEntry(
220                                         -1, //VarIndex irrelevant
221                                         -1, //StoreIndex irrelevant.
222                                         aDatatype,
223                                         "", //Name irrelevant
224                                        false); //Declared irrelevant
225         int objIndex = currentList.indexOf(createEntry);
226         if (objIndex != -1) {
227             JLocalEntry ent = (JLocalEntry) currentList.get(objIndex);
228             ent.setLastReferredIndex(aIndex);
229         } else {
230             //Helper.log("Something seriously wrong");
231         }
232     }
233 
234     /**
235      * Given the endOfBranch of a branch, this method
236      * returns a List of strings, of the form
237      * <DataType> <VarName>
238      * They represent the variables that are to be
239      * declared before we enter into the branch
240      * whose endOfBranch is given as argument.
241      * @param endOfBranch PC when branch ends.
242      * @return Returns a List containing Strings in the above mentioned
243      * format.
244      **/
245     public List defineVariable(int endOfBranch) {
246         List result = new Vector();
247         Enumeration enum = Collections.enumeration(symbols.values());
248         while (enum.hasMoreElements()) {
249             List list = (List) enum.nextElement();
250             for (int i = 0; i < list.size(); i++) {
251                 JLocalEntry ent = (JLocalEntry) list.get(i);
252                 if (!ent.isDeclared()
253                     && ent.getLastReferredIndex() > endOfBranch) {
254 
255                     String type = imports.getClassName(
256                                        Helper.getJavaDataType(
257                                             ent.getDeclarationType(),
258                                             false));
259                     result.add(type + " " + ent.getName());
260                     ent.declareVariable();
261                 }
262             }
263         }
264         return result;
265     }
266 
267 
268     /**
269      * Touch variable is basically assigning a new datatype
270      * in place of the old one.
271      * This arises especially in the following case:
272      * Say, we see
273      *    List list = new Vector();
274      *    list.add("sz");
275      * On seeing new Vector() we conclude the var type is of
276      * type Vector.
277      * On seeing list.add("sz") we 'touch' it saying that
278      * the type is now List and not Vector.
279      * @param aVarName Variable name
280      * @param aNewType New Datatype
281      **/
282     public void touchVariable(String aVarName, String aNewType) {
283         Object obj = symNames.get(aVarName);
284         if (obj != null) {
285            JLocalEntry ent = (JLocalEntry) obj;
286             if (!ent.isDeclared()) {
287                 String oldType = ent.getDeclarationType();
288                 if (!oldType.equals(aNewType)) {
289                     String newName = genName(aNewType,
290                                             ent.getVarIndex());
291                     ent.setName(newName);//Rename it again.
292                     ent.setDeclarationType(aNewType);
293 
294                     //Modify the map of names again.
295                     symNames.remove(aVarName);
296                     symNames.put(newName, ent);
297                 }
298            }
299 
300         } else {
301             //Helper.log("touchVariable: DANGEROUS ");
302         }
303     }
304 
305     /**
306      * @param aVarIndex Index of local variable into symbol table.
307      * @param aInsIndex Index of instruction into bytecode array
308      * of method.
309      * @return Returns a name of the variable given the
310      * variable index and the instruction index.
311      * @throws RevEngineException Thrown in case of any problem.
312      **/
313     public  String getName(int aVarIndex, int aInsIndex)
314                         throws RevEngineException {
315         return  getMatchingEntry(aVarIndex, aInsIndex).getName();
316     }
317 
318     /**
319      * @param aVarIndex Index of local variable into symbol table.
320      * @param aInsIndex Index of instruction into bytecode array
321      * of method.
322      * @return Returns a dataType of the variable given the
323      * variable index and the instruction index.
324      * @throws RevEngineException Thrown in case of any problem.
325      **/
326     public  String getDataType(int aVarIndex, int aInsIndex)
327                         throws RevEngineException {
328         return getMatchingEntry(aVarIndex, aInsIndex).
329                                             getDeclarationType();
330     }
331 
332     /**
333      * Declares a variable represented by aVarIndex and
334      * aInsIndex and returns its  datatype.
335      * @param aVarIndex Index of local variable into symbol table.
336      * @param aInsIndex Index of instruction into bytecode array
337      * of method.
338      * @return Returns a String containing type.
339      * @throws RevEngineException Thrown in case of any problem.
340      **/
341     public final String declare(int aVarIndex, int aInsIndex)
342                     throws RevEngineException {
343         if (aVarIndex <= maxArgs) {
344             return null;
345         }
346         JLocalEntry ent = getMatchingEntry(aVarIndex, aInsIndex);
347         if (!ent.isDeclared()) {
348             String declareType = ent.getDeclarationType();
349             ent.declareVariable();
350             return imports.getClassName(
351                     Helper.getJavaDataType(declareType, false));
352         } else {
353             return null;
354         }
355     }
356 
357     /**
358      * @param aVarIndex Index of local variable into symbol table.
359      * @param aInsIndex Index of instruction into bytecode array
360      * of method.
361      * @return Returns a matching LocalTable entry
362      * given the variable index and the instruction index.
363      **/
364     private JLocalEntry getMatchingEntry(int aVarIndex, int aInsIndex)  {
365         Object obj = symbols.get(new Integer(aVarIndex));
366         if (obj != null) {
367             List currentList = (List) obj;
368             for (int i = currentList.size() - 1; i >= 0; i--) {
369                 JLocalEntry ent = (JLocalEntry) currentList.get(i);
370                 if (aInsIndex >=  ent.getStoreIndex())  {
371                     return ent;
372                 }
373             }
374         }
375         return null;
376     }
377 
378 
379     /**
380      * Adds a new entry to the localsymboltable.
381      * @param aVarIndex Index of local variable into symbol table.
382      * @param aStoreIndex Index when the variable is first initialized/
383      * stored.
384      * @param aDatatype Datatype of the local variable entry.
385      * @param aDeclared If the local variable mentioned in declared or not.
386      **/
387     private void addEntry(int aVarIndex, int aStoreIndex,
388                       String aDatatype, boolean aDeclared) {
389 
390         Helper.log("Adding entry " + aVarIndex);
391         aDeclared |= (aDatatype.indexOf("<") != -1);
392 
393         Object obj = symbols.get(new Integer(aVarIndex));
394 
395         List currentList;
396         if (obj == null) {
397             currentList = new Vector();
398             symbols.put(new Integer(aVarIndex), currentList);
399         } else {
400             currentList = (List) obj;
401         }
402         String name = genName(aDatatype, aVarIndex);
403         JLocalEntry ent = new JLocalEntry(
404                              aVarIndex, aStoreIndex,
405                              aDatatype,
406                              name, aDeclared);
407         if (!currentList.contains(ent)) {
408             currentList.add(ent);
409             symNames.put(name, ent);
410         }
411     }
412 
413     /**
414      * Generates an name for the type and the
415      * variableIndex.
416      * @param aType type of the variable.
417      * @param aVarIndex Variable Index to symbol table.
418      * @return Returns a name generated for the variable.
419      **/
420     private String genName(String aType, int aVarIndex) {
421         int lastArrIndex = aType.lastIndexOf("[");
422         String name;
423         boolean arrType = false;
424         if (lastArrIndex != -1) {
425             arrType = true;
426             aType = aType.substring(lastArrIndex + 1);
427         }
428         boolean basicType = Helper.isBasicType(aType);
429         aType = imports.getClassName(
430                     Helper.getJavaDataType(aType, true));
431         if (basicType) {
432             name =  new Character((char) (basicIndex)).toString();
433             basicIndex++;
434         } else if (aType.compareTo(THISCLASS) == 0) {
435             name  = THIS;
436         } else {
437             name = aType.toLowerCase();
438         }
439         if (arrType) {
440             name += "Arr";
441         }
442         if (symNames.get(name) != null || keywords.contains(name)) {
443             name = genUniqueName(name, aVarIndex);
444         }
445         return name;
446     }
447 
448     /**
449      * Generate Unique name for the variables.
450      * @param name Name of the variable.
451      * @param aVarIndex variable index for which the name is to be
452      * generated.
453      * @return Returns a new unique name in the scope of this symbol
454      * table.
455      **/
456     private String genUniqueName(String name, int aVarIndex) {
457         StringBuffer sb =  new StringBuffer(name);
458         sb.append(aVarIndex);
459         return sb.toString();
460     }
461 
462     /**
463      * @return Returns a list containing the keywords of the
464      * java language. All the individual members are String.
465      **/
466     public static List getKeyWordsList() {
467         List keywordList  = new Vector();
468         keywordList.add("abstract");
469         keywordList.add("double");
470         keywordList.add("int");
471         keywordList.add("strictfp");
472         keywordList.add("boolean");
473         keywordList.add("else");
474         keywordList.add("interface");
475         keywordList.add("super");
476         keywordList.add("synchronized");
477         keywordList.add("break");
478         keywordList.add("extends");
479         keywordList.add("long");
480         keywordList.add("switch");
481         keywordList.add("byte");
482         keywordList.add("final");
483         keywordList.add("native");
484         keywordList.add("case");
485         keywordList.add("finally");
486         keywordList.add("new");
487 //      keywordList.add("this");
488         keywordList.add("catch");
489         keywordList.add("float");
490         keywordList.add("package");
491         keywordList.add("throw");
492         keywordList.add("char");
493         keywordList.add("for");
494         keywordList.add("private");
495         keywordList.add("throws");
496         keywordList.add("class");
497         keywordList.add("goto");
498         keywordList.add("protected");
499         keywordList.add("transient");
500         keywordList.add("const");
501         keywordList.add("if");
502         keywordList.add("public");
503         keywordList.add("try");
504         keywordList.add("continue");
505         keywordList.add("implements");
506         keywordList.add("return");
507         keywordList.add("void");
508         keywordList.add("default");
509         keywordList.add("import");
510         keywordList.add("short");
511         keywordList.add("volatile");
512         keywordList.add("do");
513         keywordList.add("instanceof");
514         keywordList.add("static");
515         keywordList.add("while");
516         return keywordList;
517     }
518 
519     /**
520      * @return Returns Stringified form of this class
521      **/
522     public String toString() {
523         StringBuffer sb = new StringBuffer("");
524         if (symbols != null) {
525             Iterator i1 = symbols.keySet().iterator();
526             while (i1.hasNext()) {
527                 Integer k1 = (Integer) i1.next();
528                 Iterator i2 = ((List) symbols.get(k1)).iterator();
529                 if (i2.hasNext()) {
530                     sb.append(k1 + " = ");
531                     while (i2.hasNext()) {
532                         sb.append(i2.next());
533                     }
534                 }
535             }
536         }
537         return sb.toString();
538     }
539 }