View Javadoc

1   /*
2    * @(#) MethodDescriptor.java Jan 10, 2004
3    * 
4    * Copyright (c) 2003 Delft University of Technology Jaffalaan 5, 2628 BX Delft,
5    * the Netherlands All rights reserved.
6    * 
7    * This software is proprietary information of Delft University of Technology
8    * The code is published under the General Public License
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 		//We skip the access_flag
260 		dataInput.skipBytes(2);
261 
262 		//We resolve the name of the method
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 		//The attributes
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 				//unknown attribute. Let's skip the rest
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 		//We skip the length
297 		dataInput.skipBytes(4);
298 
299 		this.maxStack = dataInput.readUnsignedShort();
300 		this.localVariableTable = new LocalVariableDescriptor[dataInput
301 				.readUnsignedShort()];
302 
303 		//Let's parse the actual code
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 		//Now we convert the lists to arrays.
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 		//Now we parse the exceptionTable
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 		//The attributes
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 				//unknown attribute. Let's skip the rest
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 		//We skip the length(u4)
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 		//We skip the length(u4)
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 }