001: /* Copyright (C) 2004 - 2007 db4objects Inc. http://www.db4o.com
002:
003: This file is part of the db4o open source object database.
004:
005: db4o is free software; you can redistribute it and/or modify it under
006: the terms of version 2 of the GNU General Public License as published
007: by the Free Software Foundation and as clarified by db4objects' GPL
008: interpretation policy, available at
009: http://www.db4o.com/about/company/legalpolicies/gplinterpretation/
010: Alternatively you can write to db4objects, Inc., 1900 S Norfolk Street,
011: Suite 350, San Mateo, CA 94403, USA.
012:
013: db4o is distributed in the hope that it will be useful, but WITHOUT ANY
014: WARRANTY; without even the implied warranty of MERCHANTABILITY or
015: FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
016: for more details.
017:
018: You should have received a copy of the GNU General Public License along
019: with this program; if not, write to the Free Software Foundation, Inc.,
020: 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
021: package EDU.purdue.cs.bloat.file;
022:
023: import java.io.*;
024:
025: import EDU.purdue.cs.bloat.reflect.*;
026: import EDU.purdue.cs.bloat.util.*;
027:
028: /**
029: * Method represents a method in a Java classfile. A method's name and value
030: * (the types of its parameters and its return type) are modeled as indices into
031: * it class's constant pool. A method has modifiers that determine whether it is
032: * public, private, static, final, etc. Methods have a number of attributes such
033: * as their Code and any Exceptions they may throw.
034: *
035: * @see Code
036: * @see Exceptions
037: *
038: * @author Nate Nystrom (<a
039: * href="mailto:nystrom@cs.purdue.edu">nystrom@cs.purdue.edu</a>)
040: */
041: public class Method implements MethodInfo {
042: private ClassInfo classInfo;
043:
044: private int modifiers;
045:
046: private int name;
047:
048: private int type;
049:
050: private Attribute[] attrs;
051:
052: private Code code;
053:
054: private Exceptions exceptions;
055:
056: public static boolean DEBUG = Boolean.getBoolean("Method.DEBUG");
057:
058: /**
059: * Constructor for creating a <code>Method</code> from scratch
060: *
061: * @param attrs
062: * Must include <code>code</code> and <code>exceptions</code>
063: * which are themselves attributes of this method
064: */
065: Method(final ClassInfo classInfo, final int modifiers,
066: final int name, final int type, final Attribute[] attrs,
067: final Code code, final Exceptions exceptions) {
068: this .classInfo = classInfo;
069: this .modifiers = modifiers;
070: this .name = name;
071: this .type = type;
072:
073: Assert
074: .isNotNull(attrs,
075: "Every method must have at least a Code "
076: + "attribute");
077: this .attrs = attrs;
078: this .code = code;
079: this .exceptions = exceptions;
080: }
081:
082: /**
083: * Constructor. Read a method from a class file.
084: *
085: * @param in
086: * The data stream of the class file.
087: * @param classInfo
088: * The class file containing the method.
089: * @exception IOException
090: * If an error occurs while reading.
091: */
092: public Method(final DataInputStream in, final ClassInfo classInfo)
093: throws IOException {
094: this .classInfo = classInfo;
095:
096: modifiers = in.readUnsignedShort();
097:
098: name = in.readUnsignedShort();
099: type = in.readUnsignedShort();
100:
101: final int numAttributes = in.readUnsignedShort();
102:
103: attrs = new Attribute[numAttributes];
104:
105: for (int i = 0; i < numAttributes; i++) {
106: final int nameIndex = in.readUnsignedShort();
107: final int length = in.readInt();
108:
109: final Constant name = classInfo.constants()[nameIndex];
110:
111: if (name != null) {
112: if ("Code".equals(name.value())) {
113: code = new Code(classInfo, in, nameIndex, length);
114: attrs[i] = code;
115: } else if ("Exceptions".equals(name.value())) {
116: exceptions = new Exceptions(classInfo, in,
117: nameIndex, length);
118: attrs[i] = exceptions;
119: }
120: }
121:
122: if (attrs[i] == null) {
123: attrs[i] = new GenericAttribute(in, nameIndex, length);
124: }
125: }
126: }
127:
128: /**
129: * Get the class which declared the method.
130: *
131: * @return The ClassInfo of the class which declared the method.
132: */
133: public ClassInfo declaringClass() {
134: return classInfo;
135: }
136:
137: /**
138: * Set the index into the constant pool of the name of the method.
139: *
140: * @param name
141: * The index into the constant pool of the name of the method.
142: */
143: public void setNameIndex(final int name) {
144: this .name = name;
145: }
146:
147: /**
148: * Set the index into the constant pool of the type of the method.
149: *
150: * @param type
151: * The index into the constant pool of the type of the method.
152: */
153: public void setTypeIndex(final int type) {
154: this .type = type;
155: }
156:
157: /**
158: * Get the index into the constant pool of the name of the method.
159: *
160: * @return The index into the constant pool of the name of the method.
161: */
162: public int nameIndex() {
163: return name;
164: }
165:
166: /**
167: * Get the index into the constant pool of the type of the method.
168: *
169: * @return The index into the constant pool of the type of the method.
170: */
171: public int typeIndex() {
172: return type;
173: }
174:
175: /**
176: * Set the modifiers of the method. The values correspond to the constants
177: * in the Modifiers class.
178: *
179: * @param modifiers
180: * A bit vector of modifier flags for the method.
181: * @see Modifiers
182: */
183: public void setModifiers(final int modifiers) {
184: this .modifiers = modifiers;
185: }
186:
187: /**
188: * Get the modifiers of the method. The values correspond to the constants
189: * in the Modifiers class.
190: *
191: * @return A bit vector of modifier flags for the method.
192: * @see Modifiers
193: */
194: public int modifiers() {
195: return modifiers;
196: }
197:
198: /**
199: * Get the maximum height of the operand stack.
200: *
201: * @return The maximum height of the operand stack.
202: */
203: public int maxStack() {
204: if (code != null) {
205: return code.maxStack();
206: }
207: return 0;
208: }
209:
210: /**
211: * Set the maximum height of the operand stack.
212: *
213: * @param maxStack
214: * The maximum height of the operand stack.
215: */
216: public void setMaxStack(final int maxStack) {
217: if (code != null) {
218: code.setMaxStack(maxStack);
219: }
220: }
221:
222: /**
223: * Get the maximum number of locals used in the method.
224: *
225: * @return The maximum number of locals used in the method.
226: */
227: public int maxLocals() {
228: if (code != null) {
229: return code.maxLocals();
230: }
231: return 0;
232: }
233:
234: /**
235: * Set the maximum number of locals used in the method.
236: *
237: * @param maxLocals
238: * The maximum number of locals used in the method.
239: */
240: public void setMaxLocals(final int maxLocals) {
241: if (code != null) {
242: code.setMaxLocals(maxLocals);
243: }
244: }
245:
246: /**
247: * Get the byte code array of the method.
248: *
249: * @return The byte code array of the method.
250: */
251: public byte[] code() {
252: if (code != null) {
253: return code.code();
254: }
255: return new byte[0];
256: }
257:
258: /**
259: * Returns the length of the Code array.
260: */
261: public int codeLength() {
262: if (code != null) {
263: return (code.codeLength());
264: } else {
265: return (0);
266: }
267: }
268:
269: /**
270: * Set the byte code array of the method.
271: *
272: * @param bytes
273: * The byte code array of the method.
274: */
275: public void setCode(final byte[] bytes) {
276: if (code != null) {
277: code.setCode(bytes);
278: if (Method.DEBUG) {
279: System.out.println("Set code with " + bytes.length
280: + " bytes");
281: // Thread.dumpStack();
282: }
283: }
284: }
285:
286: /**
287: * Get the indices into the constant pool of the types of the exceptions
288: * thrown by the method.
289: *
290: * @return The indices into the constant pool of the types of the exceptions
291: * thrown by the method.
292: */
293: public int[] exceptionTypes() {
294: if (exceptions != null) {
295: return exceptions.exceptionTypes();
296: }
297: return new int[0];
298: }
299:
300: /**
301: * Set the line numbers of the instructions in the method.
302: *
303: * @param lineNumbers
304: * The line numbers of the instructions in the method.
305: */
306: public void setLineNumbers(final LineNumberDebugInfo[] lineNumbers) {
307: if (code != null) {
308: code.setLineNumbers(lineNumbers);
309: }
310: }
311:
312: /**
313: * Set the local variable debug info for the method.
314: *
315: * @param locals
316: * The local variable debug info for the method.
317: */
318: public void setLocals(final LocalDebugInfo[] locals) {
319: if (code != null) {
320: code.setLocals(locals);
321: }
322: }
323:
324: /**
325: * Get the line numbers of the instructions in the method.
326: *
327: * @return The line numbers of the instructions in the method.
328: */
329: public LineNumberDebugInfo[] lineNumbers() {
330: if (code != null) {
331: return code.lineNumbers();
332: }
333: return new LineNumberDebugInfo[0];
334: }
335:
336: /**
337: * Get the local variable debug info for the method.
338: *
339: * @return The local variable debug info for the method.
340: */
341: public LocalDebugInfo[] locals() {
342: if (code != null) {
343: return code.locals();
344: }
345: return new LocalDebugInfo[0];
346: }
347:
348: /**
349: * Get the exception handlers in the method.
350: *
351: * @return The exception handlers in the method.
352: */
353: public Catch[] exceptionHandlers() {
354: if (code != null) {
355: return code.exceptionHandlers();
356: }
357: return new Catch[0];
358: }
359:
360: /**
361: * Set the exception handlers in the method.
362: *
363: * @param handlers
364: * The exception handlers in the method.
365: */
366: public void setExceptionHandlers(final Catch[] handlers) {
367: if (code != null) {
368: code.setExceptionHandlers(handlers);
369: }
370: }
371:
372: /**
373: * Write the method to a class file.
374: *
375: * @param out
376: * The data stream of the class file.
377: * @exception IOException
378: * If an error occurs while writing.
379: */
380: public void write(final DataOutputStream out) throws IOException {
381: if (Method.DEBUG) {
382: System.out.println("Writing method " + this );
383: System.out.println(" Masked Modifiers: "
384: + (modifiers & 0xf000));
385: }
386:
387: out.writeShort(modifiers);
388:
389: out.writeShort(name);
390: out.writeShort(type);
391:
392: out.writeShort(attrs.length);
393:
394: for (int i = 0; i < attrs.length; i++) {
395: if (Method.DEBUG) {
396: System.out.println(" " + attrs[i]);
397: }
398: out.writeShort(attrs[i].nameIndex());
399: out.writeInt(attrs[i].length());
400: attrs[i].writeData(out);
401: }
402: }
403:
404: /**
405: * Returns a string representation of the method.
406: */
407: public String toString() {
408: String x = "";
409:
410: x += " (modifiers";
411:
412: if ((modifiers & Modifiers.PUBLIC) != 0) {
413: x += " PUBLIC";
414: }
415: if ((modifiers & Modifiers.PRIVATE) != 0) {
416: x += " PRIVATE";
417: }
418: if ((modifiers & Modifiers.PROTECTED) != 0) {
419: x += " PROTECTED";
420: }
421: if ((modifiers & Modifiers.STATIC) != 0) {
422: x += " STATIC";
423: }
424: if ((modifiers & Modifiers.FINAL) != 0) {
425: x += " FINAL";
426: }
427: if ((modifiers & Modifiers.SYNCHRONIZED) != 0) {
428: x += " SYNCHRONIZED";
429: }
430: if ((modifiers & Modifiers.VOLATILE) != 0) {
431: x += " VOLATILE";
432: }
433: if ((modifiers & Modifiers.TRANSIENT) != 0) {
434: x += " TRANSIENT";
435: }
436: if ((modifiers & Modifiers.NATIVE) != 0) {
437: x += " NATIVE";
438: }
439: if ((modifiers & Modifiers.INTERFACE) != 0) {
440: x += " INTERFACE";
441: }
442: if ((modifiers & Modifiers.ABSTRACT) != 0) {
443: x += " ABSTRACT";
444: }
445: x += ")";
446:
447: return "(method " + name + " " + type + x
448: + (code != null ? "\n " + code : "")
449: + (exceptions != null ? "\n " + exceptions : "")
450: + ")";
451: }
452:
453: /**
454: * Constructor used for cloning a <code>Method</code>
455: */
456: private Method(final ClassInfo classInfo, final int modifiers,
457: final int name, final int type, final Attribute[] attrs) {
458: this .classInfo = classInfo;
459: this .modifiers = modifiers;
460: this .name = name;
461: this .type = type;
462:
463: if (attrs != null) {
464: this .attrs = new Attribute[attrs.length];
465: for (int i = 0; i < attrs.length; i++) {
466: final Attribute attr = (Attribute) attrs[i].clone();
467: if (attr instanceof Code) {
468: this .code = (Code) attr;
469:
470: } else if (attr instanceof Exceptions) {
471: this .exceptions = (Exceptions) attr;
472: }
473: this .attrs[i] = attr;
474: }
475: }
476:
477: Assert.isTrue(code != null, "No Code in attributes");
478: Assert
479: .isTrue(exceptions != null,
480: "No Exceptions in attributes");
481: }
482:
483: /**
484: * Creates a clone of this <tt>MethodInfo</tt> except that its declaring
485: * class does not know about it.
486: */
487: public Object clone() {
488: return (new Method(this.classInfo, this.modifiers, this.name,
489: this.type, this.attrs));
490: }
491: }
|