KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > org > apache > bcel > internal > generic > MethodGen


1 package com.sun.org.apache.bcel.internal.generic;
2
3 /* ====================================================================
4  * The Apache Software License, Version 1.1
5  *
6  * Copyright (c) 2001 The Apache Software Foundation. All rights
7  * reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  *
13  * 1. Redistributions of source code must retain the above copyright
14  * notice, this list of conditions and the following disclaimer.
15  *
16  * 2. Redistributions in binary form must reproduce the above copyright
17  * notice, this list of conditions and the following disclaimer in
18  * the documentation and/or other materials provided with the
19  * distribution.
20  *
21  * 3. The end-user documentation included with the redistribution,
22  * if any, must include the following acknowledgment:
23  * "This product includes software developed by the
24  * Apache Software Foundation (http://www.apache.org/)."
25  * Alternately, this acknowledgment may appear in the software itself,
26  * if and wherever such third-party acknowledgments normally appear.
27  *
28  * 4. The names "Apache" and "Apache Software Foundation" and
29  * "Apache BCEL" must not be used to endorse or promote products
30  * derived from this software without prior written permission. For
31  * written permission, please contact apache@apache.org.
32  *
33  * 5. Products derived from this software may not be called "Apache",
34  * "Apache BCEL", nor may "Apache" appear in their name, without
35  * prior written permission of the Apache Software Foundation.
36  *
37  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
38  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
39  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
40  * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
41  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
42  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
43  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
44  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
45  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
46  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
47  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
48  * SUCH DAMAGE.
49  * ====================================================================
50  *
51  * This software consists of voluntary contributions made by many
52  * individuals on behalf of the Apache Software Foundation. For more
53  * information on the Apache Software Foundation, please see
54  * <http://www.apache.org/>.
55  */

56
57 import com.sun.org.apache.bcel.internal.Constants;
58 import com.sun.org.apache.bcel.internal.classfile.*;
59 import java.util.*;
60
61 /**
62  * Template class for building up a method. This is done by defining exception
63  * handlers, adding thrown exceptions, local variables and attributes, whereas
64  * the `LocalVariableTable' and `LineNumberTable' attributes will be set
65  * automatically for the code. Use stripAttributes() if you don't like this.
66  *
67  * While generating code it may be necessary to insert NOP operations. You can
68  * use the `removeNOPs' method to get rid off them.
69  * The resulting method object can be obtained via the `getMethod()' method.
70  *
71  * @version $Id: MethodGen.java,v 1.1.1.1 2001/10/29 20:00:24 jvanzyl Exp $
72  * @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A>
73  * @author <A HREF="http://www.vmeng.com/beard">Patrick C. Beard</A>
74  * @see InstructionList
75  * @see Method
76  */

77 public class MethodGen extends FieldGenOrMethodGen {
78   private String JavaDoc class_name;
79   private Type[] arg_types;
80   private String JavaDoc[] arg_names;
81   private int max_locals;
82   private int max_stack;
83   private InstructionList il;
84   private boolean strip_attributes;
85
86   private ArrayList variable_vec = new ArrayList();
87   private ArrayList line_number_vec = new ArrayList();
88   private ArrayList exception_vec = new ArrayList();
89   private ArrayList throws_vec = new ArrayList();
90   private ArrayList code_attrs_vec = new ArrayList();
91
92   /**
93    * Declare method. If the method is non-static the constructor
94    * automatically declares a local variable `$this' in slot 0. The
95    * actual code is contained in the `il' parameter, which may further
96    * manipulated by the user. But he must take care not to remove any
97    * instruction (handles) that are still referenced from this object.
98    *
99    * For example one may not add a local variable and later remove the
100    * instructions it refers to without causing havoc. It is safe
101    * however if you remove that local variable, too.
102    *
103    * @param access_flags access qualifiers
104    * @param return_type method type
105    * @param arg_types argument types
106    * @param arg_names argument names (if this is null, default names will be provided
107    * for them)
108    * @param method_name name of method
109    * @param class_name class name containing this method (may be null, if you don't care)
110    * @param il instruction list associated with this method, may be null only for
111    * abstract or native methods
112    * @param cp constant pool
113    */

114   public MethodGen(int access_flags, Type return_type, Type[] arg_types,
115            String JavaDoc[] arg_names, String JavaDoc method_name, String JavaDoc class_name,
116            InstructionList il, ConstantPoolGen cp) {
117     setAccessFlags(access_flags);
118     setType(return_type);
119     setArgumentTypes(arg_types);
120     setArgumentNames(arg_names);
121     setName(method_name);
122     setClassName(class_name);
123     setInstructionList(il);
124     setConstantPool(cp);
125
126     if((access_flags & (Constants.ACC_ABSTRACT | Constants.ACC_NATIVE)) == 0) {
127       InstructionHandle start = il.getStart();
128       InstructionHandle end = il.getEnd();
129
130       /* Add local variables, namely the implicit `this' and the arguments
131        */

132       if(!isStatic() && (class_name != null)) // Instance method -> `this' is local var 0
133
addLocalVariable("this", new ObjectType(class_name), start, end);
134
135       if(arg_types != null) {
136     int size = arg_types.length;
137     
138     if(arg_names != null) { // Names for variables provided?
139
if(size != arg_names.length)
140         throw new ClassGenException("Mismatch in argument array lengths: " +
141                     size + " vs. " + arg_names.length);
142     } else { // Give them dummy names
143
arg_names = new String JavaDoc[size];
144
145       for(int i=0; i < size; i++)
146         arg_names[i] = "arg" + i;
147
148       setArgumentNames(arg_names);
149     }
150
151     for(int i=0; i < size; i++)
152       addLocalVariable(arg_names[i], arg_types[i], start, end);
153       }
154     }
155   }
156
157   /**
158    * Instantiate from existing method.
159    *
160    * @param m method
161    * @param class_name class name containing this method
162    * @param cp constant pool
163    */

164   public MethodGen(Method m, String JavaDoc class_name, ConstantPoolGen cp) {
165     this(m.getAccessFlags(), Type.getReturnType(m.getSignature()),
166      Type.getArgumentTypes(m.getSignature()), null /* may be overridden anyway */,
167      m.getName(), class_name,
168      ((m.getAccessFlags() & (Constants.ACC_ABSTRACT | Constants.ACC_NATIVE)) == 0)?
169      new InstructionList(m.getCode().getCode()) : null,
170      cp);
171
172     Attribute[] attributes = m.getAttributes();
173     for(int i=0; i < attributes.length; i++) {
174       Attribute a = attributes[i];
175
176       if(a instanceof Code) {
177     Code c = (Code)a;
178     setMaxStack(c.getMaxStack());
179     setMaxLocals(c.getMaxLocals());
180     
181     CodeException[] ces = c.getExceptionTable();
182     
183     if(ces != null) {
184       for(int j=0; j < ces.length; j++) {
185             CodeException ce = ces[j];
186             int type = ce.getCatchType();
187             ObjectType c_type = null;
188
189         if(type > 0) {
190           String JavaDoc cen = m.getConstantPool().getConstantString(type, Constants.CONSTANT_Class);
191           c_type = new ObjectType(cen);
192         }
193
194         int end_pc = ce.getEndPC();
195         int length = m.getCode().getCode().length;
196         
197         InstructionHandle end;
198
199         if(length == end_pc) { // May happen, because end_pc is exclusive
200
end = il.getEnd();
201         } else {
202           end = il.findHandle(end_pc);
203           end = end.getPrev(); // Make it inclusive
204
}
205
206         addExceptionHandler(il.findHandle(ce.getStartPC()), end,
207                 il.findHandle(ce.getHandlerPC()), c_type);
208       }
209     }
210
211     Attribute[] c_attributes = c.getAttributes();
212     for(int j=0; j < c_attributes.length; j++) {
213       a = c_attributes[j];
214
215       if(a instanceof LineNumberTable) {
216         LineNumber[] ln = ((LineNumberTable)a).getLineNumberTable();
217         for(int k=0; k < ln.length; k++) {
218           LineNumber l = ln[k];
219           addLineNumber(il.findHandle(l.getStartPC()), l.getLineNumber());
220         }
221       } else if(a instanceof LocalVariableTable) {
222         LocalVariable[] lv = ((LocalVariableTable)a).getLocalVariableTable();
223         for(int k=0; k < lv.length; k++) {
224           LocalVariable l = lv[k];
225           InstructionHandle start = il.findHandle(l.getStartPC());
226           InstructionHandle end = il.findHandle(l.getStartPC() + l.getLength());
227
228           // Repair malformed handles
229
if(start == null)
230         start = il.getStart();
231           if(end == null)
232         end = il.getEnd();
233
234           addLocalVariable(l.getName(), Type.getType(l.getSignature()),
235                    l.getIndex(), start, end);
236         }
237       } else
238         addCodeAttribute(a);
239     }
240       } else if(a instanceof ExceptionTable) {
241     String JavaDoc[] names = ((ExceptionTable)a).getExceptionNames();
242     for(int j=0; j < names.length; j++)
243       addException(names[j]);
244       } else
245     addAttribute(a);
246     }
247   }
248
249   /**
250    * Adds a local variable to this method.
251    *
252    * @param name variable name
253    * @param type variable type
254    * @param slot the index of the local variable, if type is long or double, the next available
255    * index is slot+2
256    * @param start from where the variable is valid
257    * @param end until where the variable is valid
258    * @return new local variable object
259    * @see LocalVariable
260    */

261   public LocalVariableGen addLocalVariable(String JavaDoc name, Type type, int slot,
262                        InstructionHandle start,
263                        InstructionHandle end) {
264     byte t = type.getType();
265     int add = type.getSize();
266     
267     if(slot + add > max_locals)
268       max_locals = slot + add;
269
270     LocalVariableGen l = new LocalVariableGen(slot, name, type, start, end);
271     int i;
272
273     if((i = variable_vec.indexOf(l)) >= 0) // Overwrite if necessary
274
variable_vec.set(i, l);
275     else
276       variable_vec.add(l);
277     return l;
278   }
279
280   /**
281    * Adds a local variable to this method and assigns an index automatically.
282    *
283    * @param name variable name
284    * @param type variable type
285    * @param start from where the variable is valid, if this is null,
286    * it is valid from the start
287    * @param end until where the variable is valid, if this is null,
288    * it is valid to the end
289    * @return new local variable object
290    * @see LocalVariable
291    */

292   public LocalVariableGen addLocalVariable(String JavaDoc name, Type type,
293                        InstructionHandle start,
294                        InstructionHandle end) {
295     return addLocalVariable(name, type, max_locals, start, end);
296   }
297
298   /**
299    * Remove a local variable, its slot will not be reused, if you do not use addLocalVariable
300    * with an explicit index argument.
301    */

302   public void removeLocalVariable(LocalVariableGen l) {
303     variable_vec.remove(l);
304   }
305
306   /**
307    * Remove all local variables.
308    */

309   public void removeLocalVariables() {
310     variable_vec.clear();
311   }
312
313   /**
314    * Sort local variables by index
315    */

316   private static final void sort(LocalVariableGen[] vars, int l, int r) {
317     int i = l, j = r;
318     int m = vars[(l + r) / 2].getIndex();
319     LocalVariableGen h;
320
321     do {
322       while(vars[i].getIndex() < m) i++;
323       while(m < vars[j].getIndex()) j--;
324
325       if(i <= j) {
326         h=vars[i]; vars[i]=vars[j]; vars[j]=h; // Swap elements
327
i++; j--;
328       }
329     } while(i <= j);
330
331     if(l < j) sort(vars, l, j);
332     if(i < r) sort(vars, i, r);
333   }
334
335   /*
336    * If the range of the variable has not been set yet, it will be set to be valid from
337    * the start to the end of the instruction list.
338    *
339    * @return array of declared local variables sorted by index
340    */

341   public LocalVariableGen[] getLocalVariables() {
342     int size = variable_vec.size();
343     LocalVariableGen[] lg = new LocalVariableGen[size];
344     variable_vec.toArray(lg);
345     
346     for(int i=0; i < size; i++) {
347       if(lg[i].getStart() == null)
348     lg[i].setStart(il.getStart());
349
350       if(lg[i].getEnd() == null)
351     lg[i].setEnd(il.getEnd());
352     }
353
354     if(size > 1)
355       sort(lg, 0, size - 1);
356
357     return lg;
358   }
359
360   /**
361    * @return `LocalVariableTable' attribute of all the local variables of this method.
362    */

363   public LocalVariableTable getLocalVariableTable(ConstantPoolGen cp) {
364     LocalVariableGen[] lg = getLocalVariables();
365     int size = lg.length;
366     LocalVariable[] lv = new LocalVariable[size];
367
368     for(int i=0; i < size; i++)
369       lv[i] = lg[i].getLocalVariable(cp);
370
371     return new LocalVariableTable(cp.addUtf8("LocalVariableTable"),
372                   2 + lv.length * 10, lv, cp.getConstantPool());
373   }
374
375   /**
376    * Give an instruction a line number corresponding to the source code line.
377    *
378    * @param ih instruction to tag
379    * @return new line number object
380    * @see LineNumber
381    */

382   public LineNumberGen addLineNumber(InstructionHandle ih, int src_line) {
383     LineNumberGen l = new LineNumberGen(ih, src_line);
384     line_number_vec.add(l);
385     return l;
386   }
387
388   /**
389    * Remove a line number.
390    */

391   public void removeLineNumber(LineNumberGen l) {
392     line_number_vec.remove(l);
393   }
394
395   /**
396    * Remove all line numbers.
397    */

398   public void removeLineNumbers() {
399     line_number_vec.clear();
400   }
401
402   /*
403    * @return array of line numbers
404    */

405   public LineNumberGen[] getLineNumbers() {
406     LineNumberGen[] lg = new LineNumberGen[line_number_vec.size()];
407     line_number_vec.toArray(lg);
408     return lg;
409   }
410
411   /**
412    * @return `LineNumberTable' attribute of all the local variables of this method.
413    */

414   public LineNumberTable getLineNumberTable(ConstantPoolGen cp) {
415     int size = line_number_vec.size();
416     LineNumber[] ln = new LineNumber[size];
417
418     try {
419       for(int i=0; i < size; i++)
420     ln[i] = ((LineNumberGen)line_number_vec.get(i)).getLineNumber();
421     } catch(ArrayIndexOutOfBoundsException JavaDoc e) {} // Never occurs
422

423     return new LineNumberTable(cp.addUtf8("LineNumberTable"),
424                    2 + ln.length * 4, ln, cp.getConstantPool());
425   }
426
427   /**
428    * Add an exception handler, i.e., specify region where a handler is active and an
429    * instruction where the actual handling is done.
430    *
431    * @param start_pc Start of region (inclusive)
432    * @param end_pc End of region (inclusive)
433    * @param handler_pc Where handling is done
434    * @param catch_type fully qualified class name of handled exception or null if any
435    * exception is handled
436    * @return new exception handler object
437    */

438   public CodeExceptionGen addExceptionHandler(InstructionHandle start_pc,
439                           InstructionHandle end_pc,
440                           InstructionHandle handler_pc,
441                           ObjectType catch_type) {
442     if((start_pc == null) || (end_pc == null) || (handler_pc == null))
443       throw new ClassGenException("Exception handler target is null instruction");
444     
445     CodeExceptionGen c = new CodeExceptionGen(start_pc, end_pc,
446                           handler_pc, catch_type);
447     exception_vec.add(c);
448     return c;
449   }
450
451   /**
452    * Remove an exception handler.
453    */

454   public void removeExceptionHandler(CodeExceptionGen c) {
455     exception_vec.remove(c);
456   }
457
458   /**
459    * Remove all line numbers.
460    */

461   public void removeExceptionHandlers() {
462     exception_vec.clear();
463   }
464
465   /*
466    * @return array of declared exception handlers
467    */

468   public CodeExceptionGen[] getExceptionHandlers() {
469     CodeExceptionGen[] cg = new CodeExceptionGen[exception_vec.size()];
470     exception_vec.toArray(cg);
471     return cg;
472   }
473
474   /**
475    * @return code exceptions for `Code' attribute
476    */

477   private CodeException[] getCodeExceptions() {
478     int size = exception_vec.size();
479     CodeException[] c_exc = new CodeException[size];
480
481     try {
482       for(int i=0; i < size; i++) {
483     CodeExceptionGen c = (CodeExceptionGen)exception_vec.get(i);
484     c_exc[i] = c.getCodeException(cp);
485       }
486     } catch(ArrayIndexOutOfBoundsException JavaDoc e) {}
487     
488     return c_exc;
489   }
490
491   /**
492    * Add an exception possibly thrown by this method.
493    *
494    * @param class_name (fully qualified) name of exception
495    */

496   public void addException(String JavaDoc class_name) {
497     throws_vec.add(class_name);
498   }
499
500   /**
501    * Remove an exception.
502    */

503   public void removeException(String JavaDoc c) {
504     throws_vec.remove(c);
505   }
506
507   /**
508    * Remove all exceptions.
509    */

510   public void removeExceptions() {
511     throws_vec.clear();
512   }
513
514   /*
515    * @return array of thrown exceptions
516    */

517   public String JavaDoc[] getExceptions() {
518     String JavaDoc[] e = new String JavaDoc[throws_vec.size()];
519     throws_vec.toArray(e);
520     return e;
521   }
522
523   /**
524    * @return `Exceptions' attribute of all the exceptions thrown by this method.
525    */

526   private ExceptionTable getExceptionTable(ConstantPoolGen cp) {
527     int size = throws_vec.size();
528     int[] ex = new int[size];
529       
530     try {
531       for(int i=0; i < size; i++)
532     ex[i] = cp.addClass((String JavaDoc)throws_vec.get(i));
533     } catch(ArrayIndexOutOfBoundsException JavaDoc e) {}
534     
535     return new ExceptionTable(cp.addUtf8("Exceptions"),
536                   2 + 2 * size, ex, cp.getConstantPool());
537   }
538
539   /**
540    * Add an attribute to the code. Currently, the JVM knows about the
541    * LineNumberTable, LocalVariableTable and StackMap attributes,
542    * where the former two will be generated automatically and the
543    * latter is used for the MIDP only. Other attributes will be
544    * ignored by the JVM but do no harm.
545    *
546    * @param a attribute to be added
547    */

548   public void addCodeAttribute(Attribute a) { code_attrs_vec.add(a); }
549
550   /**
551    * Remove a code attribute.
552    */

553   public void removeCodeAttribute(Attribute a) { code_attrs_vec.remove(a); }
554   
555   /**
556    * Remove all code attributes.
557    */

558   public void removeCodeAttributes() {
559     code_attrs_vec.clear();
560   }
561
562   /**
563    * @return all attributes of this method.
564    */

565   public Attribute[] getCodeAttributes() {
566     Attribute[] attributes = new Attribute[code_attrs_vec.size()];
567     code_attrs_vec.toArray(attributes);
568     return attributes;
569   }
570
571   /**
572    * Get method object. Never forget to call setMaxStack() or setMaxStack(max), respectively,
573    * before calling this method (the same applies for max locals).
574    *
575    * @return method object
576    */

577   public Method getMethod() {
578     String JavaDoc signature = getSignature();
579     int name_index = cp.addUtf8(name);
580     int signature_index = cp.addUtf8(signature);
581
582     /* Also updates positions of instructions, i.e., their indices
583      */

584     byte[] byte_code = null;
585
586     if(il != null)
587       byte_code = il.getByteCode();
588
589     
590     LineNumberTable lnt = null;
591     LocalVariableTable lvt = null;
592
593     /* Create LocalVariableTable and LineNumberTable attributes (for debuggers, e.g.)
594      */

595     if((variable_vec.size() > 0) && !strip_attributes)
596       addCodeAttribute(lvt = getLocalVariableTable(cp));
597
598     if((line_number_vec.size() > 0) && !strip_attributes)
599       addCodeAttribute(lnt = getLineNumberTable(cp));
600
601     Attribute[] code_attrs = getCodeAttributes();
602
603     /* Each attribute causes 6 additional header bytes
604      */

605     int attrs_len = 0;
606     for(int i=0; i < code_attrs.length; i++)
607       attrs_len += (code_attrs[i].getLength() + 6);
608
609     CodeException[] c_exc = getCodeExceptions();
610     int exc_len = c_exc.length * 8; // Every entry takes 8 bytes
611

612     Code code = null;
613     if((il != null) && !isAbstract()) {
614       code = new Code(cp.addUtf8("Code"),
615               8 + byte_code.length + // prologue byte code
616
2 + exc_len + // exceptions
617
2 + attrs_len, // attributes
618
max_stack, max_locals,
619               byte_code, c_exc,
620               code_attrs,
621               cp.getConstantPool());
622       
623       addAttribute(code);
624     }
625
626     ExceptionTable et = null;
627     
628     if(throws_vec.size() > 0)
629       addAttribute(et = getExceptionTable(cp)); // Add `Exceptions' if there are "throws" clauses
630

631     Method m = new Method(access_flags, name_index, signature_index,
632               getAttributes(), cp.getConstantPool());
633
634     // Undo effects of adding attributes
635
if(lvt != null) removeCodeAttribute(lvt);
636     if(lnt != null) removeCodeAttribute(lnt);
637     if(code != null) removeAttribute(code);
638     if(et != null) removeAttribute(et);
639
640     return m;
641   }
642
643   /**
644    * Remove all NOPs from the instruction list (if possible) and update every
645    * object refering to them, i.e., branch instructions, local variables and
646    * exception handlers.
647    */

648   public void removeNOPs() {
649     if(il != null) {
650       InstructionHandle next;
651       /* Check branch instructions.
652        */

653       for(InstructionHandle ih = il.getStart(); ih != null; ih = next) {
654     next = ih.next;
655
656     if((next != null) && (ih.getInstruction() instanceof NOP)) {
657       try {
658         il.delete(ih);
659       } catch(TargetLostException e) {
660         InstructionHandle[] targets = e.getTargets();
661         
662         for(int i=0; i < targets.length; i++) {
663           InstructionTargeter[] targeters = targets[i].getTargeters();
664           
665           for(int j=0; j < targeters.length; j++)
666         targeters[j].updateTarget(targets[i], next);
667         }
668       }
669     }
670       }
671     }
672   }
673
674   /**
675    * Set maximum number of local variables.
676    */

677   public void setMaxLocals(int m) { max_locals = m; }
678   public int getMaxLocals() { return max_locals; }
679
680   /**
681    * Set maximum stack size for this method.
682    */

683   public void setMaxStack(int m) { max_stack = m; }
684   public int getMaxStack() { return max_stack; }
685
686   /** @return class that contains this method
687    */

688   public String JavaDoc getClassName() { return class_name; }
689   public void setClassName(String JavaDoc class_name) { this.class_name = class_name; }
690
691   public void setReturnType(Type return_type) { setType(return_type); }
692   public Type getReturnType() { return getType(); }
693
694   public void setArgumentTypes(Type[] arg_types) { this.arg_types = arg_types; }
695   public Type[] getArgumentTypes() { return (Type[])arg_types.clone(); }
696   public void setArgumentType(int i, Type type) { arg_types[i] = type; }
697   public Type getArgumentType(int i) { return arg_types[i]; }
698
699   public void setArgumentNames(String JavaDoc[] arg_names) { this.arg_names = arg_names; }
700   public String JavaDoc[] getArgumentNames() { return (String JavaDoc[])arg_names.clone(); }
701   public void setArgumentName(int i, String JavaDoc name) { arg_names[i] = name; }
702   public String JavaDoc getArgumentName(int i) { return arg_names[i]; }
703
704   public InstructionList getInstructionList() { return il; }
705   public void setInstructionList(InstructionList il) { this.il = il; }
706
707   public String JavaDoc getSignature() {
708     return Type.getMethodSignature(type, arg_types);
709   }
710
711   /**
712    * Computes max. stack size by performing control flow analysis.
713    * @author <A HREF="http://www.vmeng.com/beard">Patrick C. Beard</A>
714    */

715   public void setMaxStack() {
716     if(il != null)
717       max_stack = getMaxStack(cp, il, getExceptionHandlers());
718     else
719       max_stack = 0;
720   }
721
722   /**
723    * Compute maximum number of local variables.
724    */

725   public void setMaxLocals() {
726     if(il != null) {
727       int max = isStatic()? 0 : 1;
728
729       if(arg_types != null)
730     for(int i=0; i < arg_types.length; i++)
731       max += arg_types[i].getSize();
732
733       for(InstructionHandle ih = il.getStart(); ih != null; ih = ih.getNext()) {
734     Instruction ins = ih.getInstruction();
735
736     if((ins instanceof LocalVariableInstruction) ||
737        (ins instanceof RET) || (ins instanceof IINC))
738     {
739       int index = ((IndexedInstruction)ins).getIndex() +
740         ((TypedInstruction)ins).getType(cp).getSize();
741
742       if(index > max)
743         max = index;
744     }
745       }
746
747       max_locals = max;
748     } else
749       max_locals = 0;
750   }
751
752   /** Do not/Do produce attributes code attributesLineNumberTable and
753    * LocalVariableTable, like javac -O
754    */

755   public void stripAttributes(boolean flag) { strip_attributes = flag; }
756
757   static final class BranchTarget {
758     InstructionHandle target;
759     int stackDepth;
760         
761     BranchTarget(InstructionHandle target, int stackDepth) {
762       this.target = target;
763       this.stackDepth = stackDepth;
764     }
765   }
766     
767   static final class BranchStack {
768     Stack branchTargets = new Stack();
769     Hashtable visitedTargets = new Hashtable();
770
771     public void push(InstructionHandle target, int stackDepth) {
772       if(visited(target))
773     return;
774
775       branchTargets.push(visit(target, stackDepth));
776     }
777         
778     public BranchTarget pop() {
779       if(!branchTargets.empty()) {
780     BranchTarget bt = (BranchTarget) branchTargets.pop();
781     return bt;
782       }
783
784       return null;
785     }
786         
787     private final BranchTarget visit(InstructionHandle target, int stackDepth) {
788       BranchTarget bt = new BranchTarget(target, stackDepth);
789       visitedTargets.put(target, bt);
790
791       return bt;
792     }
793         
794     private final boolean visited(InstructionHandle target) {
795       return (visitedTargets.get(target) != null);
796     }
797   }
798
799   /**
800    * Computes stack usage of an instruction list by performing control flow analysis.
801    *
802    * @return maximum stack depth used by method
803    */

804   public static int getMaxStack(ConstantPoolGen cp, InstructionList il, CodeExceptionGen[] et) {
805     BranchStack branchTargets = new BranchStack();
806         
807     /* Initially, populate the branch stack with the exception
808      * handlers, because these aren't (necessarily) branched to
809      * explicitly. in each case, the stack will have depth 1,
810      * containing the exception object.
811      */

812     for (int i = 0; i < et.length; i++) {
813       InstructionHandle handler_pc = et[i].getHandlerPC();
814       if (handler_pc != null)
815     branchTargets.push(handler_pc, 1);
816     }
817         
818     int stackDepth = 0, maxStackDepth = 0;
819     InstructionHandle ih = il.getStart();
820
821     while(ih != null) {
822       Instruction instruction = ih.getInstruction();
823       short opcode = instruction.getOpcode();
824       int delta = instruction.produceStack(cp) - instruction.consumeStack(cp);
825
826       stackDepth += delta;
827       if(stackDepth > maxStackDepth)
828     maxStackDepth = stackDepth;
829
830       // choose the next instruction based on whether current is a branch.
831
if(instruction instanceof BranchInstruction) {
832     BranchInstruction branch = (BranchInstruction) instruction;
833     if(instruction instanceof Select) {
834       // explore all of the select's targets. the default target is handled below.
835
Select select = (Select) branch;
836       InstructionHandle[] targets = select.getTargets();
837       for (int i = 0; i < targets.length; i++)
838         branchTargets.push(targets[i], stackDepth);
839       // nothing to fall through to.
840
ih = null;
841     } else if(!(branch instanceof IfInstruction)) {
842       // if an instruction that comes back to following PC,
843
// push next instruction, with stack depth reduced by 1.
844
if(opcode == Constants.JSR || opcode == Constants.JSR_W)
845         branchTargets.push(ih.getNext(), stackDepth - 1);
846       ih = null;
847     }
848     // for all branches, the target of the branch is pushed on the branch stack.
849
// conditional branches have a fall through case, selects don't, and
850
// jsr/jsr_w return to the next instruction.
851
branchTargets.push(branch.getTarget(), stackDepth);
852       } else {
853     // check for instructions that terminate the method.
854
if(opcode == Constants.ATHROW || opcode == Constants.RET ||
855        (opcode >= Constants.IRETURN && opcode <= Constants.RETURN))
856       ih = null;
857       }
858       // normal case, go to the next instruction.
859
if(ih != null)
860     ih = ih.getNext();
861       // if we have no more instructions, see if there are any deferred branches to explore.
862
if(ih == null) {
863     BranchTarget bt = branchTargets.pop();
864     if (bt != null) {
865       ih = bt.target;
866       stackDepth = bt.stackDepth;
867     }
868       }
869     }
870
871     return maxStackDepth;
872   }
873
874   private ArrayList observers;
875
876   /** Add observer for this object.
877    */

878   public void addObserver(MethodObserver o) {
879     if(observers == null)
880       observers = new ArrayList();
881
882     observers.add(o);
883   }
884
885   /** Remove observer for this object.
886    */

887   public void removeObserver(MethodObserver o) {
888     if(observers != null)
889       observers.remove(o);
890   }
891
892   /** Call notify() method on all observers. This method is not called
893    * automatically whenever the state has changed, but has to be
894    * called by the user after he has finished editing the object.
895    */

896   public void update() {
897     if(observers != null)
898       for(Iterator e = observers.iterator(); e.hasNext(); )
899     ((MethodObserver)e.next()).notify(this);
900   }
901
902   /**
903    * Return string representation close to declaration format,
904    * `public static void main(String[]) throws IOException', e.g.
905    *
906    * @return String representation of the method.
907    */

908   public final String JavaDoc toString() {
909     String JavaDoc access = Utility.accessToString(access_flags);
910     String JavaDoc signature = Type.getMethodSignature(type, arg_types);
911
912     signature = Utility.methodSignatureToString(signature, name, access,
913                         true, getLocalVariableTable(cp));
914
915     StringBuffer JavaDoc buf = new StringBuffer JavaDoc(signature);
916
917     if(throws_vec.size() > 0) {
918       for(Iterator e = throws_vec.iterator(); e.hasNext(); )
919     buf.append("\n\t\tthrows " + e.next());
920     }
921  
922     return buf.toString();
923   }
924
925   /** @return deep copy of this method
926    */

927   public MethodGen copy(String JavaDoc class_name, ConstantPoolGen cp) {
928     Method m = ((MethodGen)clone()).getMethod();
929     MethodGen mg = new MethodGen(m, class_name, this.cp);
930
931     if(this.cp != cp) {
932       mg.setConstantPool(cp);
933       mg.getInstructionList().replaceConstantPool(this.cp, cp);
934     }
935
936     return mg;
937   }
938 }
939
Popular Tags