001: // Copyright (c) 1997, 2007 Per M.A. Bothner.
002: // This is free software; for terms and warranty disclaimer see ./COPYING.
003:
004: package gnu.bytecode;
005:
006: import java.io.*;
007:
008: /**
009: * Represents a method in a <code>ClassType</code>.
010: * <p>
011: * A <code>Method</code> contain a <code>CodeAttr</code> object;
012: * the interface for generating bytecode instructions is primarily
013: * in <code>CodeAttr</code>.
014: * <p>
015: * All the methods whose name start with <code>compile_</code> are
016: * deprecated, and should not be used; use the methods
017: * in <code>CodeAttr</code>instead.
018: */
019:
020: public class Method implements AttrContainer, Member {
021: private String name;
022: Type[] arg_types;
023: Type return_type;
024: int access_flags;
025: int name_index; /* Index in constant table, or 0 if un-assigned */
026: int signature_index; /* Index in constant table, or 0 if un-assigned */
027: Method next;
028: ClassType classfile;
029:
030: Attribute attributes;
031:
032: public final Attribute getAttributes() {
033: return attributes;
034: }
035:
036: public final void setAttributes(Attribute attributes) {
037: this .attributes = attributes;
038: }
039:
040: ExceptionsAttr exceptions;
041:
042: public final ExceptionsAttr getExceptionAttr() {
043: return exceptions;
044: }
045:
046: public void setExceptions(short[] exn_indices) {
047: if (exceptions == null)
048: exceptions = new ExceptionsAttr(this );
049: exceptions.setExceptions(exn_indices, classfile);
050: }
051:
052: public void setExceptions(ClassType[] exn_types) {
053: if (exceptions == null)
054: exceptions = new ExceptionsAttr(this );
055: exceptions.setExceptions(exn_types);
056: }
057:
058: CodeAttr code;
059:
060: public final CodeAttr getCode() {
061: return code;
062: }
063:
064: private Method() {
065: }
066:
067: /** Make a generic "clone" method.
068: * This is used for array types.
069: */
070: public static Method makeCloneMethod(Type returnType) {
071: Method method = new Method();
072: method.name = "clone";
073: method.access_flags = Access.PUBLIC;
074: method.arg_types = Type.typeArray0;
075: method.return_type = returnType;
076: method.classfile = Type.pointer_type;
077: return method;
078: }
079:
080: Method(ClassType clfile, int flags) {
081: if (clfile.last_method == null)
082: clfile.methods = this ;
083: else
084: clfile.last_method.next = this ;
085: clfile.last_method = this ;
086: clfile.methods_count++;
087: access_flags = flags;
088: classfile = clfile;
089: }
090:
091: public final void setStaticFlag(boolean is_static) {
092: if (is_static)
093: access_flags |= Access.STATIC;
094: else
095: access_flags ^= ~Access.STATIC;
096: }
097:
098: public final boolean getStaticFlag() {
099: return (access_flags & Access.STATIC) != 0;
100: }
101:
102: public final boolean isAbstract() {
103: return (access_flags & Access.ABSTRACT) != 0;
104: }
105:
106: public int getModifiers() {
107: return access_flags;
108: }
109:
110: public void setModifiers(int modifiers) {
111: access_flags = modifiers;
112: }
113:
114: public final ConstantPool getConstants() {
115: return classfile.constants;
116: }
117:
118: public Scope pushScope() {
119: prepareCode(0);
120: return code.pushScope();
121: }
122:
123: /** True if control could reach here. */
124: public final boolean reachableHere() {
125: return code.reachableHere();
126: }
127:
128: public Scope popScope() {
129: return code.popScope();
130: }
131:
132: /**
133: * Allocate slots for a local variable (or parameter).
134: * @param local the variable we need to allocate
135: * @deprecated
136: */
137: public void allocate_local(Variable local) {
138: local.allocateLocal(code);
139: }
140:
141: /** Allocate a Code attribute, and prepare to generate code.
142: * Most code generators should use the startCode convenience method. */
143: public void initCode() {
144: if (classfile.constants == null)
145: classfile.constants = new ConstantPool();
146: prepareCode(0);
147: code.sourceDbgExt = classfile.sourceDbgExt;
148: code.pushScope();
149: }
150:
151: /**
152: * @deprecated Use startCode instead
153: */
154: public void init_param_slots() {
155: initCode();
156: code.addParamLocals();
157: }
158:
159: /** Recommended method to create a new CodeAttr for this Method. */
160: public CodeAttr startCode() {
161: initCode();
162: code.addParamLocals();
163: return code;
164: }
165:
166: void kill_local(Variable var) {
167: var.freeLocal(code);
168: }
169:
170: /** Method that must be called before we generate any instructions.
171: * Set so there is room for at least max_size bytes of code.
172: */
173: void prepareCode(int max_size) {
174: if (code == null)
175: code = new CodeAttr(this );
176: code.reserve(max_size);
177: }
178:
179: // This method should be called before we generate code for
180: // an instruction (or sequence).
181: // An upper bound of the intruction length is max_size.
182: // deprecated!
183: void instruction_start_hook(int max_size) {
184: prepareCode(max_size);
185: }
186:
187: final Type pop_stack_type() {
188: return code.popType();
189: }
190:
191: final void push_stack_type(Type type) {
192: code.pushType(type);
193: }
194:
195: public void compile_checkcast(Type type) {
196: code.emitCheckcast(type);
197: }
198:
199: public void maybe_compile_checkcast(Type type) {
200: Type stack_type = code.topType();
201: if (type != stack_type) // FIXME rather simple-minded, but safe.
202: code.emitCheckcast(type);
203: }
204:
205: /**
206: * Comple code to push the contents of a local variable onto the statck.
207: * @param var The variable whose contents we want to push.
208: * @deprecated
209: */
210: public void push_var(Variable var) {
211: code.emitLoad(var);
212: }
213:
214: /**
215: * @deprecated
216: */
217: public void compile_push_value(Variable var) {
218: code.emitLoad(var);
219: }
220:
221: /**
222: * @deprecated
223: */
224: public void compile_store_value(Variable var) {
225: code.emitStore(var);
226: }
227:
228: public void compile_push_this () {
229: code.emitPushThis();
230: }
231:
232: void write(DataOutputStream dstr, ClassType classfile)
233: throws java.io.IOException {
234: dstr.writeShort(access_flags);
235: dstr.writeShort(name_index);
236: dstr.writeShort(signature_index);
237:
238: Attribute.writeAll(this , dstr);
239: }
240:
241: String signature;
242:
243: public String getSignature() {
244: if (signature == null) {
245: StringBuffer buf = new StringBuffer(100);
246: int args_count = arg_types.length;
247: buf.append('(');
248: for (int i = 0; i < args_count; i++)
249: buf.append(arg_types[i].getSignature());
250: buf.append(')');
251: buf.append(return_type.getSignature());
252: signature = buf.toString();
253: }
254: return signature;
255: }
256:
257: public void setSignature(String signature) {
258: int len = signature.length();
259: if (len < 3 || signature.charAt(0) != '(')
260: throw new ClassFormatError("bad method signature");
261: int pos = 1;
262: /* #ifdef JAVA5 */
263: // java.util.Stack<Type> types = new java.util.Stack<Type>();
264: /* #else */
265: java.util.Stack types = new java.util.Stack();
266: /* #endif */
267: for (;;) {
268: int arg_sig_len = Type.signatureLength(signature, pos);
269: if (arg_sig_len < 0) {
270: if (pos < len && signature.charAt(pos) == ')')
271: break;
272: throw new ClassFormatError("bad method signature");
273: }
274: Type arg_type = Type.signatureToType(signature, pos,
275: arg_sig_len);
276: types.push(arg_type);
277: pos += arg_sig_len;
278: }
279: arg_types = new Type[types.size()];
280: for (int i = types.size(); --i >= 0;)
281: arg_types[i] = (Type) types.pop();
282: return_type = Type.signatureToType(signature, pos + 1, len
283: - pos - 1);
284: }
285:
286: public void setSignature(int signature_index) {
287: CpoolUtf8 sigConstant = (CpoolUtf8) getConstants().getForced(
288: signature_index, ConstantPool.UTF8);
289: this .signature_index = signature_index;
290: setSignature(sigConstant.string);
291: }
292:
293: void assignConstants() {
294: ConstantPool constants = getConstants();
295: if (name_index == 0 && name != null)
296: name_index = constants.addUtf8(name).index;
297: if (signature_index == 0)
298: signature_index = constants.addUtf8(getSignature()).index;
299: Attribute.assignConstants(this , classfile);
300: }
301:
302: public ClassType getDeclaringClass() {
303: return classfile;
304: }
305:
306: public final Type getReturnType() {
307: return return_type;
308: }
309:
310: public final Type[] getParameterTypes() {
311: return arg_types;
312: }
313:
314: public final ClassType[] getExceptions() {
315: if (exceptions == null)
316: return null;
317: return exceptions.getExceptions();
318: }
319:
320: public final String getName() {
321: return name;
322: }
323:
324: public final void setName(String name) {
325: this .name = name;
326: }
327:
328: public final void setName(int name_index) {
329: if (name_index <= 0)
330: name = null;
331: else {
332: CpoolUtf8 nameConstant = (CpoolUtf8) getConstants()
333: .getForced(name_index, ConstantPool.UTF8);
334: name = nameConstant.string;
335: }
336: this .name_index = name_index;
337: }
338:
339: public final Method getNext() {
340: return next;
341: }
342:
343: public void listParameters(StringBuffer sbuf) {
344: int args_count = arg_types.length;
345: sbuf.append('(');
346: for (int i = 0; i < args_count; i++) {
347: if (i > 0)
348: sbuf.append(',');
349: sbuf.append(arg_types[i].getName());
350: }
351: sbuf.append(')');
352: }
353:
354: public String toString() {
355: StringBuffer sbuf = new StringBuffer(100);
356: sbuf.append(getDeclaringClass().getName());
357: sbuf.append('.');
358: sbuf.append(name);
359: if (arg_types != null) {
360: listParameters(sbuf);
361: sbuf.append(return_type.getName());
362: }
363: return sbuf.toString();
364: }
365:
366: public void cleanupAfterCompilation() {
367: attributes = null;
368: exceptions = null;
369: code = null;
370: }
371: };
|