1    
2    /*
3    
4      The author of this software is Ian Kaplan
5      Bear Products International
6      www.bearcave.com
7      iank@bearcave.com
8    
9      Copyright (c) Ian Kaplan, 1999, 2000
10   
11     See copyright file for usage and licensing
12   
13   */
14   
15   package attr;
16   
17   import java.util.Vector;
18   import java.io.*;
19   import util.*;
20   import jconst.*;
21   
22   
23   /**
24   
25   <p>
26      This object represents the local variable table.  The local
27      variable table is an attribute that may be in the attribute table
28      of the code attribute (codeAttr object).  This attribute is
29      generated by the Java compiler when debug is turned on (-g).
30   <p>
31      The JVM Spec. states:
32   
33   <blockquote>
34        It may be used by debuggers to determine the value of a given
35        local variable during the execution of a method. If
36        LocalVariableTable attributes are present in the attributes table
37        of a given Code attribute, then they may appear in any
38        order. There may be no more than one LocalVariableTable attribute
39        per local variable in the Code attribute. (JVM 4.7.9)
40   </blockquote>
41   
42   <p>
43      This is rather misleading.  The local variable table contains
44      information about the local variable declarations.  There is one
45      entry for each local variable (the table includes the class
46      reference variable "this").
47   <p>
48      The LocalVariableTable attribute has the format
49   
50   <pre>
51       LocalVariableTable_attribute {
52   
53           u2 attribute_name_index;
54           u4 attribute_length;
55           u2 local_variable_table_length;
56           localVarEnt local_variable_table[local_variable_table_length];
57       }
58   </pre>
59   
60   <p>
61      The attribute_name_index and attribute length are read by the
62      attrFactory.allocAttr method.  These values are passed into the
63      class constructor.
64   <p>
65      The localVarEnt is
66   
67   <pre>
68       localVarEnt {  
69           u2 start_pc;
70   	u2 length;
71   	u2 name_index;
72   	u2 descriptor_index;
73   	u2 index;
74       }
75   </pre>
76   
77   <p>
78      There is one localVarEnt structure for each local variable.
79   
80   <p>
81      The JVM Spec (4.7.9) states:
82   
83   <blockquote>
84         The given local variable must have a value at indices into the
85         code array in the interval [start_pc, start_pc+length], that is,
86         between start_pc and start_pc+length inclusive. The value of
87         start_pc must be a valid index into the code array of this Code
88         attribute of the opcode of an instruction. The value of
89         start_pc+length must be either a valid index into the code array
90         of this Code attribute of the opcode of an instruction, or the
91         first index beyond the end of that code array.
92   </blockquote>
93   
94   <p>
95      So the byte code from start_pc to start_pc+length seems to indicate
96      the live range for the variable.  That is, the variable is assigned
97      a value at the start of the range and may be assigned other values
98      through out the range.  The range ends with the last reference to
99      the variable.
100  <p>
101     If an optimizing compiler generated the code and the variable is
102     "dead" at a point in the source where a a debugger asks for its
103     value or attempts to write the value then the debugger can report
104     that the value is unavailable.
105  <p>
106     The start_pc (the offset into the code array) is 16-bits.  However,
107     the size of the code array is 32-bits.  In theory this means that
108     there may be indices that can't be referenced.  In practice the
109     size of Java objects seems to be limited (at least up through
110     release 1.2).
111  <p>
112     The name_index is an index into the constant table for the
113     constUtf8 object for the variable name.
114  <p>
115     The descriptor_index is an index into the constant table for the
116     constUtf8 object for the variable descriptor that describes the
117     object.
118  <p>
119     The index field is the frame offset location for the local
120     variable.
121  <p>
122     The JVM Spec states for the index:
123  
124  <blockquote>
125       The given local variable must be at index in its method's local
126       variables. If the local variable at index is a two-word type
127       (double or long), it occupies both index and index+1.
128  </blockquote>
129  
130  <p>
131     By local variables, the JVM Spec is referring to the local frame.
132     Note that frames are not necessarily allocated on the stack.
133  
134    @author Ian Kaplan
135  
136   */
137  class localVarlocalVarTabAttr attrInfo {
138    localVarEnt localVarTab[];
139  
140    /**
141  
142       Local variable entry in the local variable table.
143  
144     */
145    class localVarEnt {
146      int start_pc;
147      int length;
148      constUtf8 memberName = null;
149      constUtf8 memberDesc = null;
150      int index;
151  
152      localVarEnt( DataInputStream dStream, constPool constPoolSec ) {
153        int name_index;
154        int descriptor_index;
155        constBase obj;
156  
157        start_pc = readU2( dStream );
158        length = readU2( dStream );
159        name_index = readU2( dStream );
160        descriptor_index = readU2( dStream );
161        index = readU2( dStream );
162  
163        if (name_index > 0) {
164  	obj = constPoolSec.constPoolElem( name_index );
165  	if (obj != null && obj instanceof constUtf8) {
166  	  memberName = (constUtf8)obj;
167  	}
168        }
169  
170        if (descriptor_index > 0) {
171  	obj = constPoolSec.constPoolElem( descriptor_index );
172  	if (obj != null && obj instanceof constUtf8) {
173  	  memberDesc = (constUtf8)obj;
174  	}
175        }
176      } // localVarEnt class constructor
177  
178  
179      /**
180        Return a String for the local variable declaration or
181        null if memberDesc or member name are null.
182  
183       */
184      String getLocalVarDecl() {
185        String localDecl = null;
186  
187        if (memberDesc != null && memberName != null) {
188  	String type;
189  	String name;
190  	
191  	type = typeDesc.decodeFieldDesc( memberDesc.getString() );
192  	name = memberName.getString();
193  	localDecl = type + " " + name + ";" + " // index = " + index;
194        }
195  
196        return localDecl;
197      } // getLocalVarDecl
198  
199      
200    } // localVarEnt class
201  
202  
203    localVarTabAttr( String name, int length, 
204  		   DataInputStream dStream, constPool constPoolSec ) {
205      super( name, length );
206      int numVarEnt = readU2( dStream );
207  
208      if (numVarEnt > 0) {
209        localVarTab = new localVarEnt[ numVarEnt ];
210  
211        for (int i = 0; i < numVarEnt; i++) {
212  	localVarTab[i] = new localVarEnt( dStream, constPoolSec );
213        }
214      }
215    }
216  
217  
218    public Vector getLocalVarVec() {
219      Vector localVarVec = null;
220      String localDecl;
221  
222      if (localVarTab != null) {
223        for (int i = 0; i < localVarTab.length; i++) {
224  	if (localVarVec == null)
225  	  localVarVec = new Vector();
226  	
227  	localDecl = localVarTab[i].getLocalVarDecl();
228  	localVarVec.addElement( localDecl );
229        }
230      }
231      return localVarVec;
232    } // getLocalVarVec
233  
234  
235  } // localVarTabAttr
236