1
2
3
4
5
6
7
8
9
10 package nl.tudelft.simulation.dsol.interpreter.classfile;
11
12 import java.io.DataInput;
13 import java.io.IOException;
14 import java.io.InputStream;
15 import java.lang.reflect.AccessibleObject;
16 import java.util.ArrayList;
17 import java.util.Iterator;
18 import java.util.List;
19 import java.util.NoSuchElementException;
20 import java.util.Properties;
21
22 import nl.tudelft.simulation.dsol.interpreter.InterpreterException;
23 import nl.tudelft.simulation.dsol.interpreter.Operation;
24 import nl.tudelft.simulation.dsol.interpreter.operations.FactoryInterface;
25 import nl.tudelft.simulation.dsol.interpreter.operations.InterpreterFactory;
26 import nl.tudelft.simulation.language.reflection.MethodSignature;
27 import nl.tudelft.simulation.logger.Logger;
28
29 /***
30 * A MethodDescriptor <br>
31 * (c) copyright 2003 <a href="http://www.simulation.tudelft.nl">Delft
32 * University of Technology </a>, the Netherlands. <br>
33 * See for project information <a
34 * href="http://www.simulation.tudelft.nl">www.simulation.tudelft.nl </a> <br>
35 * License of use: <a href="http://www.gnu.org/copyleft/gpl.html">General Public
36 * License (GPL) </a>, no warranty <br>
37 *
38 * @version 1.0 Jan 10, 2004 <br>
39 * @author <a href="http://www.simulation.tudelft.nl/people/jacobs.html">Peter
40 * Jacobs </a>
41 */
42 public class MethodDescriptor
43 {
44 /*** the operationfactory to use */
45 private static FactoryInterface operationFactory = new InterpreterFactory();
46
47 /*** Let's resolve the factory to use. If we fail we use the recursiveFactory */
48 static
49 {
50 try
51 {
52 InputStream stream = MethodDescriptor.class
53 .getResourceAsStream("/interpreter.properties");
54 if (stream != null)
55 {
56 Properties properties = new Properties();
57 properties.load(stream);
58 String factoryClassName = properties
59 .getProperty("interpreter.operation.factory");
60 MethodDescriptor.operationFactory = (FactoryInterface) Class
61 .forName(factoryClassName).newInstance();
62 }
63 } catch (Exception exception)
64 {
65 Logger.warning(MethodDescriptor.class, "<clinit>", exception);
66 }
67 }
68
69 /*** bytePositions */
70 private int[] bytePositions = new int[0];
71
72 /*** the constantPool to use */
73 private Constant[] constantPool = new Constant[0];
74
75 /*** the exceptionTable */
76 private ExceptionEntry[] exceptionTable = new ExceptionEntry[0];
77
78 /*** the localVarialbes */
79 private LineNumber[] lineNumberTable = new LineNumber[0];
80
81 /*** the localVarialbes */
82 private LocalVariableDescriptor[] localVariableTable = new LocalVariableDescriptor[0];
83
84 /*** the maxStack of this method */
85 private int maxStack = -1;
86
87 /*** the method */
88 private AccessibleObject method = null;
89
90 /*** the methodSignature */
91 private MethodSignature methodSignature = null;
92
93 /*** the name of the method */
94 private String name;
95
96 /*** the operations */
97 private Operation[] operations = new Operation[0];
98
99 /***
100 * constructs a new MethodDescriptor
101 *
102 * @param dataInput the dataInput
103 * @param constantPool the constantPool
104 * @throws IOException on ioException
105 */
106 public MethodDescriptor(final DataInput dataInput,
107 final Constant[] constantPool) throws IOException
108 {
109 super();
110 this.constantPool = constantPool;
111 this.readMethod(dataInput);
112 }
113
114 /***
115 * returns the bytePosition of the operation.
116 *
117 * @param operationIndex the n-th operation
118 * @return the bytePostion
119 */
120 public int getBytePosition(final int operationIndex)
121 {
122 return this.bytePositions[operationIndex];
123 }
124
125 /***
126 * returns the exception table of the method
127 *
128 * @return the exceptiontable
129 */
130 public ExceptionEntry[] getExceptionTable()
131 {
132 return this.exceptionTable;
133 }
134
135 /***
136 * returns the linenumber table of the method
137 *
138 * @return the linenumber table
139 */
140 public LineNumber[] getLineNumberTable()
141 {
142 return this.lineNumberTable;
143 }
144
145 /***
146 * returns the localvariable descriptors
147 *
148 * @return the localvairable descriptors
149 */
150 public LocalVariableDescriptor[] getLocalVariableTable()
151 {
152 return this.localVariableTable;
153 }
154
155 /***
156 * returns the maximum stack size of this method
157 *
158 * @return int the maximum stacksize of this method
159 */
160 public int getMaxStack()
161 {
162 return this.maxStack;
163 }
164
165 /***
166 * @return Returns the method
167 */
168 public AccessibleObject getMethod()
169 {
170 return this.method;
171 }
172
173 /***
174 * @return Returns the methodSignature
175 */
176 public MethodSignature getMethodSignature()
177 {
178 return this.methodSignature;
179 }
180
181 /***
182 * returns the name of the method
183 *
184 * @return the name of the method
185 */
186 public String getName()
187 {
188 return this.name;
189 }
190
191 /***
192 * returns the operations of the method.
193 *
194 * @return the operations of the method.
195 */
196 public Operation[] getOperations()
197 {
198 return this.operations;
199 }
200
201 /***
202 * returns the index number of the operation in the operationtable of the
203 * operation starting at bytePosition
204 *
205 * @param bytePosition the bytePosition
206 * @return the number
207 */
208 public int getOperationIndex(final int bytePosition)
209 {
210 for (int i = 0; i < this.bytePositions.length; i++)
211 {
212 if (this.bytePositions[i] == bytePosition)
213 {
214 return i;
215 }
216 }
217 throw new NoSuchElementException("At bytePosition(" + bytePosition
218 + ") no operation starts");
219 }
220
221 /***
222 * returns the operation at bytePosition
223 *
224 * @param bytePosition the position to start
225 * @return the operation
226 */
227 public Operation getOperation(final int bytePosition)
228 {
229 for (int i = 0; i < this.bytePositions.length; i++)
230 {
231 if (this.bytePositions[i] == bytePosition)
232 {
233 return this.operations[i];
234 }
235 }
236 return null;
237 }
238
239 /***
240 * sets the method of this descriptor
241 *
242 * @param method the method
243 */
244 public void setMethod(final AccessibleObject method)
245 {
246 this.method = method;
247 }
248
249 /*** ******************** Private Parsing Methods ************** */
250
251 /***
252 * reads the method
253 *
254 * @param dataInput the dataInput
255 * @throws IOException on ioException
256 */
257 private void readMethod(final DataInput dataInput) throws IOException
258 {
259
260 dataInput.skipBytes(2);
261
262
263 this.name = ((ConstantUTF8) this.constantPool[dataInput
264 .readUnsignedShort()]).getValue();
265
266 this.methodSignature = new MethodSignature(
267 ((ConstantUTF8) this.constantPool[dataInput.readUnsignedShort()])
268 .getValue());
269
270
271 int attributeCount = dataInput.readUnsignedShort();
272 for (int i = 0; i < attributeCount; i++)
273 {
274 String attributeName = ((ConstantUTF8) this.constantPool[dataInput
275 .readUnsignedShort()]).getValue();
276 if (attributeName.equals("Code"))
277 {
278 this.readCodeAttribute(dataInput);
279 } else
280 {
281
282 dataInput.skipBytes(dataInput.readInt());
283 }
284 }
285 }
286
287 /***
288 * reads the codeAttribute and returns the new position
289 *
290 * @param dataInput the dataInput
291 * @throws IOException on failure
292 */
293 private void readCodeAttribute(final DataInput dataInput)
294 throws IOException
295 {
296
297 dataInput.skipBytes(4);
298
299 this.maxStack = dataInput.readUnsignedShort();
300 this.localVariableTable = new LocalVariableDescriptor[dataInput
301 .readUnsignedShort()];
302
303
304 int codeLength = dataInput.readInt();
305 List code = new ArrayList();
306 List positions = new ArrayList();
307
308 int position = 0;
309 while (position < codeLength)
310 {
311 Operation operation = MethodDescriptor.operationFactory
312 .readOperation(dataInput, position);
313 code.add(operation);
314 positions.add(new Integer(position));
315 position = position + operation.getByteLength();
316 }
317 if (position != codeLength)
318 {
319 throw new InterpreterException(" byteCode readmethod pos"
320 + position + "!= codeL" + codeLength);
321 }
322
323
324 this.operations = (Operation[]) code
325 .toArray(new Operation[code.size()]);
326 this.bytePositions = new int[positions.size()];
327
328 int line = 0;
329 for (Iterator i = positions.iterator(); i.hasNext();)
330 {
331 this.bytePositions[line] = ((Integer) i.next()).intValue();
332 line++;
333 }
334
335
336 this.exceptionTable = new ExceptionEntry[dataInput.readUnsignedShort()];
337 for (int i = 0; i < this.exceptionTable.length; i++)
338 {
339 this.exceptionTable[i] = new ExceptionEntry(dataInput,
340 this.constantPool);
341 }
342
343
344 int attributeCount = dataInput.readUnsignedShort();
345 for (int i = 0; i < attributeCount; i++)
346 {
347 String attributeName = ((ConstantUTF8) this.constantPool[dataInput
348 .readUnsignedShort()]).getValue();
349 if (attributeName.equals("LineNumberTable"))
350 {
351 this.readLineNumberTable(dataInput);
352 } else if (attributeName.equals("LocalVariableTable"))
353 {
354 this.readLocalVariableTable(dataInput);
355 } else
356 {
357
358 dataInput.skipBytes(dataInput.readInt());
359 }
360 }
361 }
362
363 /***
364 * reads the localVariableTable
365 *
366 * @param dataInput the dataInput to read
367 * @throws IOException on failure
368 */
369 private void readLineNumberTable(final DataInput dataInput)
370 throws IOException
371 {
372
373 dataInput.skipBytes(4);
374
375 this.lineNumberTable = new LineNumber[dataInput.readUnsignedShort()];
376 for (int i = 0; i < this.lineNumberTable.length; i++)
377 {
378 this.lineNumberTable[i] = new LineNumber(dataInput);
379 }
380 }
381
382 /***
383 * reads the localVariableTable
384 *
385 * @param dataInput the dataInput to read
386 * @throws IOException on failure
387 */
388 private void readLocalVariableTable(final DataInput dataInput)
389 throws IOException
390 {
391
392 dataInput.skipBytes(4);
393
394 int variables = dataInput.readUnsignedShort();
395 for (int i = 0; i < variables; i++)
396 {
397 LocalVariableDescriptor variable = new LocalVariableDescriptor(
398 dataInput, this.constantPool);
399 this.localVariableTable[variable.getIndex()] = variable;
400 }
401 }
402 }