001: // Copyright (c) 1997 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 {
021: private String name;
022:
023: public Type[] arg_types;
024: public Type return_type;
025:
026: int access_flags;
027: int name_index; /* Index in constant table, or 0 if un-assigned */
028: int signature_index; /* Index in constant table, or 0 if un-assigned */
029: Method next;
030: ClassType classfile;
031:
032: Attribute attributes;
033:
034: public final Attribute getAttributes() {
035: return attributes;
036: }
037:
038: public final void setAttributes(Attribute attributes) {
039: this .attributes = attributes;
040: }
041:
042: ExceptionsAttr exceptions;
043:
044: public final ExceptionsAttr getExceptionAttr() {
045: return exceptions;
046: }
047:
048: public void setExceptions(short[] exn_indices) {
049: if (exceptions == null)
050: exceptions = new ExceptionsAttr(this );
051: exceptions.setExceptions(exn_indices, classfile);
052: }
053:
054: public void setExceptions(ClassType[] exn_types) {
055: if (exceptions == null)
056: exceptions = new ExceptionsAttr(this );
057: exceptions.setExceptions(exn_types);
058: }
059:
060: CodeAttr code;
061:
062: public final CodeAttr getCode() {
063: return code;
064: }
065:
066: public final void eraseCode() {
067: if (code == null)
068: return;
069:
070: // The method must be in a dirty state, since code is not null,
071: // but it let's recover
072: if (attributes == null) {
073: code = null;
074: return;
075: }
076:
077: if (attributes == code) {
078: attributes = attributes.getNext();
079: code = null;
080: return;
081: }
082:
083: for (Attribute a = attributes; a.getNext() != null; a = a
084: .getNext())
085: if (a.getNext() == code) {
086: a.setNext(code.getNext());
087: code = null;
088: return;
089: }
090: }
091:
092: Method(ClassType clfile, int flags) {
093: if (clfile.last_method == null)
094: clfile.methods = this ;
095: else
096: clfile.last_method.next = this ;
097: clfile.last_method = this ;
098: clfile.methods_count++;
099: access_flags = flags;
100: classfile = clfile;
101: }
102:
103: /** Return the number of arguments of this method. */
104: public int getArity() {
105: return arg_types.length;
106: }
107:
108: public final void setStaticFlag(boolean is_static) {
109: if (is_static)
110: access_flags |= Access.STATIC;
111: else
112: access_flags ^= ~Access.STATIC;
113: }
114:
115: public final boolean getStaticFlag() {
116: return (access_flags & Access.STATIC) != 0;
117: }
118:
119: public final boolean isAbstract() {
120: return (access_flags & Access.ABSTRACT) != 0;
121: }
122:
123: public int getModifiers() {
124: return access_flags;
125: }
126:
127: public void setModifiers(int modifiers) {
128: access_flags = modifiers;
129: }
130:
131: public final ConstantPool getConstants() {
132: return classfile.constants;
133: }
134:
135: public Scope pushScope() {
136: prepareCode(0);
137: return code.pushScope();
138: }
139:
140: /** True if control could reach here. */
141: public boolean reachableHere() {
142: return !code.unreachable_here;
143: }
144:
145: public Scope popScope() {
146: return code.popScope();
147: }
148:
149: /**
150: * Allocate slots for a local variable (or parameter).
151: * @param local the variable we need to allocate
152: * @return the index of the (first) slot.
153: * @deprecated
154: */
155: public void allocate_local(Variable local) {
156: local.allocateLocal(code);
157: }
158:
159: /** Allocate a Code attribute, and prepare to generate code. */
160:
161: public void initCode() {
162: if (classfile.constants == null)
163: classfile.constants = new ConstantPool();
164: prepareCode(0);
165: code.pushScope();
166: }
167:
168: public void init_param_slots() {
169: initCode();
170: code.addParamLocals();
171: }
172:
173: void kill_local(Variable var) {
174: var.freeLocal(code);
175: }
176:
177: /** Method that must be called before we generate any instructions.
178: * Set so there is room for at least max_size bytes of code.
179: */
180: void prepareCode(int max_size) {
181: if (isAbstract())
182: throw new Error("generating code for an abstract method: "
183: + toString());
184:
185: if (code == null)
186: code = new CodeAttr(this );
187: code.reserve(max_size);
188: }
189:
190: // This method should be called before we generate code for
191: // an instruction (or sequence).
192: // An upper bound of the intruction length is max_size.
193: // deprecated!
194: void instruction_start_hook(int max_size) {
195: prepareCode(max_size);
196: }
197:
198: final Type pop_stack_type() {
199: return code.popType();
200: }
201:
202: final void push_stack_type(Type type) {
203: code.pushType(type);
204: }
205:
206: public void compile_checkcast(Type type) {
207: code.emitCheckcast(type);
208: }
209:
210: public void maybe_compile_checkcast(Type type) {
211: Type stack_type = code.topType();
212: if (type != stack_type) // FIXME rather simple-minded, but safe.
213: code.emitCheckcast(type);
214: }
215:
216: /**
217: * Comple code to push the contents of a local variable onto the statck.
218: * @param var The variable whose contents we want to push.
219: * @deprecated
220: */
221: public void push_var(Variable var) {
222: code.emitLoad(var);
223: }
224:
225: /**
226: * @deprecated
227: */
228: public void compile_push_value(Variable var) {
229: code.emitLoad(var);
230: }
231:
232: /**
233: * @deprecated
234: */
235: public void compile_store_value(Variable var) {
236: code.emitStore(var);
237: }
238:
239: public void compile_push_this () {
240: code.emitPushThis();
241: }
242:
243: public void compile_linenumber(String file, int linenumber) {
244: if (code == null)
245: code = new CodeAttr(this );
246: code.putLineNumber(file, linenumber);
247: }
248:
249: void write(DataOutputStream dstr, ClassType classfile)
250: throws java.io.IOException {
251:
252: if (code == null && !isAbstract())
253: throw new Error("Method " + this + " has no code");
254: //return;
255:
256: dstr.writeShort(access_flags);
257: dstr.writeShort(name_index);
258: dstr.writeShort(signature_index);
259:
260: Attribute.writeAll(this , dstr);
261: }
262:
263: private String signature;
264:
265: public String getSignature() {
266: if (signature == null) {
267: StringBuffer buf = new StringBuffer(100);
268: int args_count = arg_types.length;
269: buf.append('(');
270: for (int i = 0; i < args_count; i++)
271: buf.append(arg_types[i].getSignature());
272: buf.append(')');
273: buf.append(return_type.getSignature());
274: signature = buf.toString();
275: }
276: return signature;
277: }
278:
279: public void setSignature(String signature) {
280: int len = signature.length();
281: if (len < 3 || signature.charAt(0) != '(')
282: throw new ClassFormatError("bad method signature");
283: int pos = 1;
284: java.util.Stack types = new java.util.Stack();
285: for (;;) {
286: int arg_sig_len = Type.signatureLength(signature, pos);
287: if (arg_sig_len < 0) {
288: if (pos < len && signature.charAt(pos) == ')')
289: break;
290: throw new ClassFormatError("bad method signature");
291: }
292: Type arg_type = Type.signatureToType(signature, pos,
293: arg_sig_len);
294: types.push(arg_type);
295: pos += arg_sig_len;
296: }
297: arg_types = new Type[types.size()];
298: for (int i = types.size(); --i >= 0;)
299: arg_types[i] = (Type) types.pop();
300: return_type = Type.signatureToType(signature, pos + 1, len
301: - pos - 1);
302: }
303:
304: public void setSignature(int signature_index) {
305: CpoolUtf8 sigConstant = (CpoolUtf8) getConstants().getForced(
306: signature_index, ConstantPool.UTF8);
307: this .signature_index = signature_index;
308: setSignature(sigConstant.string);
309: }
310:
311: void assignConstants() {
312: ConstantPool constants = getConstants();
313: if (name_index == 0 && name != null)
314: name_index = constants.addUtf8(name).index;
315: if (signature_index == 0)
316: signature_index = constants.addUtf8(getSignature()).index;
317: Attribute.assignConstants(this , classfile);
318: }
319:
320: public ClassType getDeclaringClass() {
321: return classfile;
322: }
323:
324: public final Type getReturnType() {
325: return return_type;
326: }
327:
328: public final Type[] getParameterTypes() {
329: return arg_types;
330: }
331:
332: public final ClassType[] getExceptions() {
333: if (exceptions == null)
334: return null;
335: return exceptions.getExceptions();
336: }
337:
338: public final String getName() {
339: return name;
340: }
341:
342: public final void setName(String name) {
343: this .name = name;
344: }
345:
346: public final void setName(int name_index) {
347: if (name_index <= 0)
348: name = null;
349: else {
350: CpoolUtf8 nameConstant = (CpoolUtf8) getConstants()
351: .getForced(name_index, ConstantPool.UTF8);
352: name = nameConstant.string;
353: }
354: this .name_index = name_index;
355: }
356:
357: public final Method getNext() {
358: return next;
359: }
360:
361: public final boolean isConstructor() {
362: return name.equals("<init>");
363: }
364:
365: public String toString() {
366: StringBuffer sbuf = new StringBuffer(100);
367: if (isConstructor())
368: sbuf.append("new");
369: else
370: sbuf.append(return_type.getName());
371:
372: sbuf.append(" ");
373: sbuf.append(getDeclaringClass().getName());
374: if (!isConstructor()) {
375: sbuf.append('.');
376: sbuf.append(name);
377: }
378: if (arg_types != null) {
379: int args_count = arg_types.length;
380: sbuf.append('(');
381: for (int i = 0; i < args_count; i++) {
382: if (i > 0)
383: sbuf.append(',');
384: sbuf.append(arg_types[i].getName());
385: }
386: sbuf.append(')');
387: }
388: return sbuf.toString();
389: }
390:
391: /****************************************************************
392: * Generic Java / JDK 1.5
393: ****************************************************************/
394:
395: /** Holds the full signature, or "" whene there is none.
396: null before it is initialized.
397: */
398: private String fullSignature;
399:
400: private void loadSignature() {
401: Attribute sig = Attribute.get(this , "Signature");
402: if (!(sig instanceof MiscAttr)) {
403: fullSignature = "";
404: return;
405: }
406:
407: MiscAttr s = (MiscAttr) sig;
408: int index = (s.data[1] & 0xff) | ((s.data[0] & 0xff) << 8);
409: fullSignature = ((CpoolUtf8) getDeclaringClass().constants
410: .getPoolEntry(index)).getString();
411:
412: // Class type parameters can appear in bounds.
413: if (!getStaticFlag())
414: TypeVariable.scope2 = getDeclaringClass().getParameters();
415:
416: int[] pos = { 0 };
417: if (fullSignature.charAt(0) == '<')
418: typeParameters = TypeVariable.parse(fullSignature, pos);
419:
420: if (fullSignature.charAt(pos[0]++) != '(')
421: throw new Error("Bad full signature: " + fullSignature);
422:
423: TypeVariable.scope1 = typeParameters;
424:
425: // Parse argument types.
426: java.util.Stack types = new java.util.Stack();
427:
428: while (fullSignature.charAt(pos[0]) != ')') {
429: types.push(Type.fullSignatureToType(fullSignature, pos));
430: }
431:
432: // Skip the ')'
433: pos[0]++;
434:
435: fullArgTypes = new Type[types.size()];
436: for (int i = types.size(); --i >= 0;)
437: fullArgTypes[i] = (Type) types.pop();
438:
439: fullReturnType = Type.fullSignatureToType(fullSignature, pos);
440:
441: TypeVariable.scope1 = null;
442: TypeVariable.scope2 = null;
443: }
444:
445: private TypeVariable[] typeParameters;
446: private Type fullReturnType;
447: private Type[] fullArgTypes;
448:
449: public TypeVariable[] getTypeParameters() {
450: if (fullSignature == null)
451: loadSignature();
452:
453: return typeParameters;
454: }
455:
456: public Type[] getFullParameterTypes() {
457: if (fullSignature == null)
458: loadSignature();
459:
460: if (fullSignature == "")
461: return getParameterTypes();
462: else
463: return fullArgTypes;
464: }
465:
466: public Type getFullReturnType() {
467: if (fullSignature == null)
468: loadSignature();
469:
470: if (fullSignature == "")
471: return getReturnType();
472: else
473: return fullReturnType;
474: }
475: }
|