KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jibx > binding > classes > MethodBuilder


1 /*
2 Copyright (c) 2003-2005, Dennis M. Sosnoski
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without modification,
6 are permitted provided that the following conditions are met:
7
8  * Redistributions of source code must retain the above copyright notice, this
9    list of conditions and the following disclaimer.
10  * Redistributions in binary form must reproduce the above copyright notice,
11    this list of conditions and the following disclaimer in the documentation
12    and/or other materials provided with the distribution.
13  * Neither the name of JiBX nor the names of its contributors may be used
14    to endorse or promote products derived from this software without specific
15    prior written permission.
16
17 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
21 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
24 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */

28
29 package org.jibx.binding.classes;
30
31 import java.util.ArrayList JavaDoc;
32 import java.util.HashMap JavaDoc;
33
34 import org.apache.bcel.Constants;
35 import org.apache.bcel.classfile.Method;
36 import org.apache.bcel.classfile.Utility;
37 import org.apache.bcel.generic.*;
38 import org.jibx.binding.util.StringStack;
39 import org.jibx.runtime.JiBXException;
40
41 /**
42  * Method builder. Organizes and tracks the creation of a method, providing
43  * convenience methods for common operations. This is customized for the needs
44  * of JiBX, with some predetermined settings as appropriate. It supplies hash
45  * code and equality checking based on the method signature and actual byte
46  * code of the generated method, ignoring the method name.
47  *
48  * @author Dennis M. Sosnoski
49  * @version 1.0
50  */

51
52 public abstract class MethodBuilder extends BindingMethod
53 {
54     //
55
// Constants for code generation.
56

57     public static final String JavaDoc FRAMEWORK_EXCEPTION_CLASS =
58         "org.jibx.runtime.JiBXException";
59     
60     public static final String JavaDoc EXCEPTION_CONSTRUCTOR_SIGNATURE1 =
61         "(Ljava/lang/String;)V";
62     
63     public static final String JavaDoc EXCEPTION_CONSTRUCTOR_SIGNATURE2 =
64         "(Ljava/lang/String;Ljava/lang/Throwable;)V";
65     
66     //
67
// Static data.
68

69     /** Table of argument name lists (generated as needed). */
70     protected static ArrayList JavaDoc s_argNameLists = new ArrayList JavaDoc();
71     
72     /** Zero-length string array. */
73     protected static String JavaDoc[] EMPTY_STRING_ARRAY = new String JavaDoc[0];
74     
75     //
76
// Actual instance data
77

78     /** Builder for class instructions. */
79     protected InstructionBuilder m_instructionBuilder;
80     
81     /** List of instructions in method definition. */
82     private InstructionList m_instructionList;
83     
84     /** List of types currently on stack. */
85     private StringStack m_stackState;
86     
87     /** Generator for constructing method. */
88     protected MethodGen m_generator;
89     
90     /** Actual generated method information. */
91     protected Method m_method;
92     
93     /** Method class item information. */
94     protected ClassItem m_item;
95     
96     /** Value types associated with local variable slots. */
97     private ArrayList JavaDoc m_localTypes;
98     
99     /** Exceptions needing to be handled in method (lazy create,
100      <code>null</code> if not used). */

101     protected ArrayList JavaDoc m_exceptions;
102     
103     /** Accumulated hash code from adding instructions. */
104     protected int m_hashCode;
105     
106     /** Branch to be aimed at next appended instruction. */
107     protected BranchWrapper[] m_targetBranches;
108     
109     /** Map for initialized properties (lazy create, <code>null</code> if not
110      used). */

111     protected HashMap JavaDoc m_valueMap;
112
113     /**
114      * Constructor. This sets up for constructing a method with public access.
115      *
116      * @param name method name to be built
117      * @param ret method return type
118      * @param args types of arguments
119      * @param cf owning class file information
120      * @param access flags for method access
121      * @throws JiBXException on error in constructing method
122      */

123
124     protected MethodBuilder(String JavaDoc name, Type ret, Type[] args,
125         ClassFile cf, int access) throws JiBXException {
126         super(cf);
127         
128         // make sure the dummy argument names are defined
129
if (args.length >= s_argNameLists.size()) {
130             
131             // append to end of argument names list
132
for (int i = s_argNameLists.size(); i <= args.length; i++) {
133                 String JavaDoc[] list = new String JavaDoc[i];
134                 if (i > 0) {
135                     Object JavaDoc last = s_argNameLists.get(i-1);
136                     System.arraycopy(last, 0, list, 0, i-1);
137                     list[i-1] = "arg" + i;
138                 }
139                 s_argNameLists.add(list);
140             }
141             
142         }
143         
144         // create the method generator with empty instruction list
145
String JavaDoc[] names = (String JavaDoc[])s_argNameLists.get(args.length);
146         m_instructionList = new InstructionList();
147         m_stackState = new StringStack();
148         m_instructionBuilder = cf.getInstructionBuilder();
149         m_generator = new MethodGen(access, ret, args, names, name,
150             cf.getName(), m_instructionList, cf.getConstPoolGen());
151         
152         // initialize local variables for method parameters
153
m_localTypes = new ArrayList JavaDoc();
154         if ((access & Constants.ACC_STATIC) == 0) {
155             m_localTypes.add(cf.getName());
156         }
157         for (int i = 0; i < args.length; i++) {
158             m_localTypes.add(args[i].toString());
159             if (args[i].getSize() > 1) {
160                 m_localTypes.add(null);
161             }
162         }
163     }
164
165     /**
166      * Get name of method being constructed.
167      *
168      * @return name of method being constructed
169      */

170
171     public String JavaDoc getName() {
172         return m_generator.getName();
173     }
174     
175     /**
176      * Get signature.
177      *
178      * @return signature for method
179      */

180      
181     public String JavaDoc getSignature() {
182         return m_generator.getSignature();
183     }
184     
185     /**
186      * Get access flags.
187      *
188      * @return flags for access type of method
189      */

190      
191     public int getAccessFlags() {
192         return m_generator.getAccessFlags();
193     }
194     
195     /**
196      * Set access flags.
197      *
198      * @param flags access type to be set
199      */

200      
201     public void setAccessFlags(int flags) {
202         m_generator.setAccessFlags(flags);
203     }
204     
205     /**
206      * Get the actual method. This can only be called once code generation is
207      * completed (after the {@link codeComplete} method is called).
208      *
209      * @return constructed method information
210      */

211      
212     public Method getMethod() {
213         if (m_method == null) {
214             throw new IllegalStateException JavaDoc("Method still under construction");
215         } else {
216             return m_method;
217         }
218     }
219     
220     /**
221      * Add keyed value to method definition.
222      *
223      * @param key retrieval key
224      * @param value keyed value
225      */

226      
227     public Object JavaDoc setKeyValue(Object JavaDoc key, Object JavaDoc value) {
228         if (m_valueMap == null) {
229             m_valueMap = new HashMap JavaDoc();
230         }
231         return m_valueMap.put(key, value);
232     }
233     
234     /**
235      * Add local variable for created object. The current code in the method
236      * must have the created object reference on the stack.
237      */

238      
239     public Object JavaDoc getKeyValue(Object JavaDoc key) {
240         return m_valueMap == null ? null : m_valueMap.get(key);
241     }
242
243     /**
244      * Add exception to those needing handling.
245      *
246      * @param fully qualified name of exception class
247      */

248
249     public void addException(String JavaDoc name) {
250         if (m_exceptions == null) {
251             m_exceptions = new ArrayList JavaDoc();
252         }
253         if (!m_exceptions.contains(name)) {
254             m_exceptions.add(name);
255         }
256     }
257
258     /**
259      * Add exceptions thrown by called method to those needing handling.
260      *
261      * @param method information for method to be handled
262      */

263
264     public void addMethodExceptions(ClassItem method) {
265         String JavaDoc[] excepts = method.getExceptions();
266         if (excepts != null) {
267             for (int i = 0; i < excepts.length; i++) {
268                 addException(excepts[i]);
269             }
270         }
271     }
272
273     /**
274      * Get first instruction in method.
275      *
276      * @return handle for first instruction in method
277      */

278
279     protected InstructionHandle getFirstInstruction() {
280         return m_instructionList.getStart();
281     }
282
283     /**
284      * Get last instruction in method.
285      *
286      * @return handle for last instruction in method
287      */

288
289     protected InstructionHandle getLastInstruction() {
290         return m_instructionList.getEnd();
291     }
292
293     /**
294      * Target branches if pending. This implements setting the target of
295      * branch instructions supplied using the {@link #targetNext} method.
296      *
297      * @param inst handle for appended instruction
298      */

299
300     protected final void setTarget(InstructionHandle inst) {
301         if (m_targetBranches != null) {
302             
303             // TODO: fix this ugly kludge with code rewrite
304
// adjust stack with POPs if need to match size
305
String JavaDoc[] types = m_stackState.toArray();
306             if (m_targetBranches.length > 0) {
307                 boolean match = true;
308                 int depth = m_targetBranches[0].getStackState().length;
309                 for (int i = 1; i < m_targetBranches.length; i++) {
310                     if (depth != m_targetBranches[i].getStackState().length) {
311                         match = false;
312                         break;
313                     }
314                 }
315                 if (match) {
316                     if (depth > types.length) {
317                         BranchWrapper merge = new BranchWrapper
318                             (m_instructionList.insert(inst, new GOTO(null)),
319                             types, this);
320                         String JavaDoc[] stack = m_targetBranches[0].getStackState();
321                         m_stackState = new StringStack(stack);
322                         InstructionHandle poph = m_instructionList.
323                             insert(inst, InstructionConstants.POP);
324                         for (int i = 0; i < m_targetBranches.length; i++) {
325                             m_targetBranches[i].setTarget(poph, stack, this);
326                         }
327                         m_stackState.pop();
328                         while (m_stackState.size() > types.length) {
329                             m_instructionList.insert(inst,
330                                 InstructionConstants.POP);
331                             m_stackState.pop();
332                         }
333                         merge.setTarget(inst, m_stackState.toArray(), this);
334                         m_targetBranches = null;
335                         return;
336                     } else {
337                         while (depth < types.length) {
338                             m_instructionList.insert(inst,
339                                 InstructionConstants.POP);
340                             m_stackState.pop();
341                             types = m_stackState.toArray();
342                         }
343                     }
344                 }
345             }
346             
347             // set all branch targets
348
for (int i = 0; i < m_targetBranches.length; i++) {
349                 m_targetBranches[i].setTarget(inst, types, this);
350             }
351             m_targetBranches = null;
352         }
353     }
354     
355     /**
356      * Generate description of current stack state.
357      *
358      * @return stack state description
359      */

360      
361     private String JavaDoc describeStack() {
362         StringBuffer JavaDoc buff = new StringBuffer JavaDoc();
363         String JavaDoc[] types = m_stackState.toArray();
364         for (int i = 0; i < types.length; i++) {
365             buff.append(" ");
366             buff.append(i);
367             buff.append(": ");
368             buff.append(types[i]);
369             buff.append('\n');
370         }
371         return buff.toString();
372     }
373
374     /**
375      * Verify that a pair of value types represent compatible types. This checks
376      * for equal types or downcast object types.
377      *
378      * @param type actual known type of value
379      * @param need type needed
380      */

381
382     private void verifyCompatible(String JavaDoc type, String JavaDoc need) {
383         if (!need.equals(type)) {
384             try {
385                 if ("<null>".equals(type)) {
386                     if (ClassItem.isPrimitive(need)) {
387                         throw new IllegalStateException JavaDoc
388                             ("Internal error: Expected " + need +
389                             " on stack , found null");
390                     }
391                 } else if ("java.lang.Object".equals(need)) {
392                     if (ClassItem.isPrimitive(type)) {
393                         throw new IllegalStateException JavaDoc("Internal error: " +
394                             "Expected object reference on stack, found " +
395                             type + "\n full stack:\n" + describeStack());
396                     }
397                 } else {
398                     boolean match = false;
399                     if ("int".equals(need)) {
400                         match = "boolean".equals(type) ||
401                             "short".equals(type) || "char".equals(type) ||
402                             "byte".equals(type);
403                     } else if ("int".equals(type)) {
404                         match = "boolean".equals(need) ||
405                             "short".equals(need) || "char".equals(need) ||
406                             "byte".equals(need);
407                     }
408                     if (!match && !ClassItem.isAssignable(type, need)) {
409                         throw new IllegalStateException JavaDoc
410                             ("Internal error: Expected " + need +
411                             " on stack, found " + type + "\n full stack:\n" +
412                             describeStack());
413                     }
414                 }
415             } catch (JiBXException e) {
416                 throw new RuntimeException JavaDoc
417                     ("Internal error: Attempting to compare types " + need +
418                     " and " + type);
419             }
420         }
421     }
422
423     /**
424      * Verify that at least the specified number of items are present on the
425      * stack.
426      *
427      * @param count minimum number of items required
428      */

429
430     private void verifyStackDepth(int count) {
431         if (m_stackState.size() < count) {
432             throw new IllegalStateException JavaDoc
433                 ("Internal error: Too few values on stack\n full stack:\n" +
434                 describeStack());
435         }
436     }
437
438     /**
439      * Verify the top value in the stack state resulting from the current
440      * instruction list.
441      *
442      * @param t1 expected type for top item on stack
443      */

444
445     private void verifyStack(String JavaDoc t1) {
446         verifyStackDepth(1);
447         verifyCompatible(m_stackState.peek(), t1);
448     }
449
450     /**
451      * Verify the top two values in the stack state resulting from the current
452      * instruction list.
453      *
454      * @param t1 expected type for first item on stack
455      * @param t2 expected type for second item on stack
456      */

457
458     private void verifyStack(String JavaDoc t1, String JavaDoc t2) {
459         verifyStackDepth(2);
460         verifyCompatible(m_stackState.peek(), t1);
461         verifyCompatible(m_stackState.peek(1), t2);
462     }
463
464     /**
465      * Verify the top values in the stack state resulting from the current
466      * instruction list. This form checks only the actual call parameters.
467      *
468      * @param types expected parameter types on stack
469      */

470
471     private void verifyCallStack(String JavaDoc[] types) {
472         
473         // make sure there are enough items on stack
474
int count = types.length;
475         verifyStackDepth(count);
476         
477         // verify all parameter types for call
478
for (int i = 0; i < count; i++) {
479             int slot = count - i - 1;
480             verifyCompatible(m_stackState.peek(slot), types[i]);
481         }
482     }
483
484     /**
485      * Verify the top values in the stack state resulting from the current
486      * instruction list. This form checks both the object being called and the
487      * actual call parameters.
488      *
489      * @param clas name of method class
490      * @param types expected parameter types on stack
491      */

492
493     private void verifyCallStack(String JavaDoc clas, String JavaDoc[] types) {
494         
495         // start by verifying object reference
496
int count = types.length;
497         verifyStackDepth(count+1);
498         verifyCompatible(m_stackState.peek(count), clas);
499         
500         // check values for call parameters
501
verifyCallStack(types);
502     }
503
504     /**
505      * Verify that the top value in the stack state resulting from the current
506      * instruction list is an object reference.
507      */

508
509     private void verifyStackObject() {
510         verifyStackDepth(1);
511         String JavaDoc top = m_stackState.peek();
512         if (ClassItem.isPrimitive(top)) {
513             throw new IllegalStateException JavaDoc("Internal error: " +
514                 "Expected object reference on stack , found " +
515                  m_stackState.peek() + "\n full stack:\n" + describeStack());
516         }
517     }
518
519     /**
520      * Append IFEQ branch instruction to method.
521      *
522      * @param src object responsible for generating branch
523      * @return wrapper for appended conditional branch
524      */

525
526     public BranchWrapper appendIFEQ(Object JavaDoc src) {
527         verifyStack("int");
528         BranchHandle hand = m_instructionList.append(new IFEQ(null));
529         setTarget(hand);
530         m_stackState.pop();
531         return new BranchWrapper(hand, m_stackState.toArray(), src);
532     }
533
534     /**
535      * Append IFGE branch instruction to method.
536      *
537      * @param src object responsible for generating branch
538      * @return wrapper for appended conditional branch
539      */

540
541     public BranchWrapper appendIFGE(Object JavaDoc src) {
542         verifyStack("int");
543         BranchHandle hand = m_instructionList.append(new IFGE(null));
544         setTarget(hand);
545         m_stackState.pop();
546         return new BranchWrapper(hand, m_stackState.toArray(), src);
547     }
548
549     /**
550      * Append IFNE branch instruction to method.
551      *
552      * @param src object responsible for generating branch
553      * @return wrapper for appended conditional branch
554      */

555
556     public BranchWrapper appendIFNE(Object JavaDoc src) {
557         verifyStack("int");
558         BranchHandle hand = m_instructionList.append(new IFNE(null));
559         setTarget(hand);
560         m_stackState.pop();
561         return new BranchWrapper(hand, m_stackState.toArray(), src);
562     }
563
564     /**
565      * Append IFNONNULL branch instruction to method.
566      *
567      * @param src object responsible for generating branch
568      * @return wrapper for appended conditional branch
569      */

570
571     public BranchWrapper appendIFNONNULL(Object JavaDoc src) {
572         verifyStackObject();
573         BranchHandle hand = m_instructionList.append(new IFNONNULL(null));
574         setTarget(hand);
575         m_stackState.pop();
576         return new BranchWrapper(hand, m_stackState.toArray(), src);
577     }
578
579     /**
580      * Append IFNULL branch instruction to method.
581      *
582      * @param src object responsible for generating branch
583      * @return wrapper for appended conditional branch
584      */

585
586     public BranchWrapper appendIFNULL(Object JavaDoc src) {
587         verifyStackObject();
588         BranchHandle hand = m_instructionList.append(new IFNULL(null));
589         setTarget(hand);
590         m_stackState.pop();
591         return new BranchWrapper(hand, m_stackState.toArray(), src);
592     }
593
594     /**
595      * Append IF_ICMPNE branch instruction to method.
596      *
597      * @param src object responsible for generating branch
598      * @return wrapper for appended conditional branch
599      */

600
601     public BranchWrapper appendIF_ICMPNE(Object JavaDoc src) {
602         verifyStack("int", "int");
603         BranchHandle hand = m_instructionList.append(new IF_ICMPNE(null));
604         setTarget(hand);
605         m_stackState.pop(2);
606         return new BranchWrapper(hand, m_stackState.toArray(), src);
607     }
608
609     /**
610      * Append unconditional branch instruction to method.
611      *
612      * @param src object responsible for generating branch
613      * @return wrapper for appended unconditional branch
614      */

615
616     public BranchWrapper appendUnconditionalBranch(Object JavaDoc src) {
617         BranchHandle hand = m_instructionList.append(new GOTO(null));
618         setTarget(hand);
619         BranchWrapper wrapper =
620             new BranchWrapper(hand, m_stackState.toArray(), src);
621         m_stackState = null;
622         return wrapper;
623     }
624
625     /**
626      * Append compound instruction to method.
627      *
628      * @param ins instruction to be appended
629      */

630
631     private void append(CompoundInstruction ins) {
632         setTarget(m_instructionList.append(ins));
633     }
634
635     /**
636      * Append instruction to method.
637      *
638      * @param ins instruction to be appended
639      */

640
641     private void append(Instruction ins) {
642         setTarget(m_instructionList.append(ins));
643     }
644
645     /**
646      * Create load constant instruction and append to method. Builds the most
647      * appropriate type of instruction for the value.
648      *
649      * @param value constant value to be loaded
650      */

651
652     public void appendLoadConstant(int value) {
653         append(m_instructionBuilder.createLoadConstant(value));
654         m_stackState.push("int");
655     }
656
657     /**
658      * Create load constant instruction and append to method. Loads a
659      * <code>String</code> reference from the constant pool.
660      *
661      * @param value constant value to be loaded
662      */

663
664     public void appendLoadConstant(String JavaDoc value) {
665         append(m_instructionBuilder.createLoadConstant(value));
666         m_stackState.push("java.lang.String");
667     }
668
669     /**
670      * Create load constant instruction and append to method. Loads an
671      * unwrapped primitive value from the constant pool.
672      *
673      * @param value constant value to be loaded
674      */

675
676     public void appendLoadConstant(Object JavaDoc value) {
677         append(m_instructionBuilder.createLoadConstant(value));
678         if (value instanceof Integer JavaDoc || value instanceof Character JavaDoc ||
679             value instanceof Short JavaDoc || value instanceof Boolean JavaDoc ||
680             value instanceof Byte JavaDoc) {
681             m_stackState.push("int");
682         } else if (value instanceof Long JavaDoc) {
683             m_stackState.push("long");
684         } else if (value instanceof Float JavaDoc) {
685             m_stackState.push("float");
686         } else if (value instanceof Double JavaDoc) {
687             m_stackState.push("double");
688         } else {
689             throw new IllegalArgumentException JavaDoc("Unknown argument type");
690         }
691     }
692
693     /**
694      * Create getfield instruction and append to method. Uses the target field
695      * information to generate the instruction.
696      *
697      * @param item information for field to be gotton
698      */

699
700     public void appendGetField(ClassItem item) {
701         verifyStack(item.getClassFile().getName());
702         append(m_instructionBuilder.createGetField(item));
703         m_stackState.pop();
704         m_stackState.push(item.getTypeName());
705     }
706
707     /**
708      * Create getstatic instruction and append to method. Uses the target field
709      * information to generate the instruction.
710      *
711      * @param item information for field to be set
712      */

713
714     public void appendGetStatic(ClassItem item) {
715         append(m_instructionBuilder.createGetStatic(item));
716         m_stackState.push(item.getTypeName());
717     }
718
719     /**
720      * Create get instruction and append to method. This generates either a
721      * getstatic or a getfield instruction, as appropriate.
722      *
723      * @param item information for field to be gotten
724      */

725
726     public void appendGet(ClassItem item) {
727         if (item.isStatic()) {
728             appendGetStatic(item);
729         } else {
730             appendGetField(item);
731         }
732     }
733
734     /**
735      * Create putfield instruction and append to method. Uses the target field
736      * information to generate the instruction.
737      *
738      * @param item information for field to be set
739      */

740
741     public void appendPutField(ClassItem item) {
742         String JavaDoc tname = item.getTypeName();
743         verifyStack(tname, item.getClassFile().getName());
744         append(m_instructionBuilder.createPutField(item));
745         m_stackState.pop(2);
746     }
747
748     /**
749      * Create putstatic instruction and append to method. Uses the target field
750      * information to generate the instruction.
751      *
752      * @param item information for field to be set
753      */

754
755     public void appendPutStatic(ClassItem item) {
756         verifyStack(item.getTypeName());
757         append(m_instructionBuilder.createPutStatic(item));
758         m_stackState.pop();
759     }
760
761     /**
762      * Create put instruction and append to method. This generates either a
763      * putstatic or a putfield instruction, as appropriate.
764      *
765      * @param item information for field to be gotten
766      */

767
768     public void appendPut(ClassItem item) {
769         if (item.isStatic()) {
770             appendPutStatic(item);
771         } else {
772             appendPutField(item);
773         }
774     }
775
776     /**
777      * Create invoke instruction for static, member, or interface method and
778      * append to method. Uses the target method information to generate the
779      * correct instruction.
780      *
781      * @param item information for method to be called
782      */

783
784     public void appendCall(ClassItem item) {
785         
786         // process based on call type
787
String JavaDoc[] types = item.getArgumentTypes();
788         int count = types.length;
789         if (item.getClassFile().isInterface()) {
790             
791             // process parameters and object reference for interface call
792
verifyCallStack(item.getClassFile().getName(), types);
793             append(m_instructionBuilder.createCallInterface(item));
794             m_stackState.pop(count+1);
795             
796         } else if ((item.getAccessFlags() & Constants.ACC_STATIC) != 0) {
797             
798             // process only parameters for static call
799
verifyCallStack(types);
800             append(m_instructionBuilder.createCallStatic(item));
801             if (count > 0) {
802                 m_stackState.pop(count);
803             }
804             
805         } else {
806             
807             // process parameters and object reference for normal method call
808
verifyCallStack(item.getClassFile().getName(), types);
809             append(m_instructionBuilder.createCallVirtual(item));
810             m_stackState.pop(count+1);
811         }
812         
813         // adjust stack state to reflect result of call
814
if (!"void".equals(item.getTypeName())) {
815             m_stackState.push(item.getTypeName());
816         }
817     }
818
819     /**
820      * Create invoke static method instruction from signature and append to
821      * method.
822      *
823      * @param method fully qualified class and method name
824      * @param signature method signature in standard form
825      */

826
827     public void appendCallStatic(String JavaDoc method, String JavaDoc signature) {
828         
829         // verify all call parameters on stack
830
String JavaDoc[] types = ClassItem.getParametersFromSignature(signature);
831         verifyCallStack(types);
832         
833         // generate the actual method call
834
append(m_instructionBuilder.createCallStatic(method, signature));
835         
836         // change stack state to reflect result of call
837
if (types.length > 0) {
838             m_stackState.pop(types.length);
839         }
840         String JavaDoc result = ClassItem.getTypeFromSignature(signature);
841         if (!"void".equals(result)) {
842             m_stackState.push(result);
843         }
844     }
845
846     /**
847      * Create invoke virtual method instruction from signature and append to
848      * method.
849      *
850      * @param method fully qualified class and method name
851      * @param signature method signature in standard form
852      */

853
854     public void appendCallVirtual(String JavaDoc method, String JavaDoc signature) {
855         
856         // verify all call parameters and object reference on stack
857
String JavaDoc[] types = ClassItem.getParametersFromSignature(signature);
858         int split = method.lastIndexOf('.');
859         if (split < 0) {
860             throw new IllegalArgumentException JavaDoc
861                 ("Internal error: Missing class name on method " + method);
862         }
863         verifyCallStack(method.substring(0, split), types);
864         
865         // generate the actual method call
866
append(m_instructionBuilder.createCallVirtual(method, signature));
867         
868         // change stack state to reflect result of call
869
m_stackState.pop(types.length+1);
870         String JavaDoc result = ClassItem.getTypeFromSignature(signature);
871         if (!"void".equals(result)) {
872             m_stackState.push(result);
873         }
874     }
875
876     /**
877      * Create invoke interface method instruction from signature and append to
878      * method.
879      *
880      * @param method fully qualified interface and method name
881      * @param signature method signature in standard form
882      */

883
884     public void appendCallInterface(String JavaDoc method, String JavaDoc signature) {
885         
886         // verify all call parameters and object reference on stack
887
String JavaDoc[] types = ClassItem.getParametersFromSignature(signature);
888         int split = method.lastIndexOf('.');
889         if (split < 0) {
890             throw new IllegalArgumentException JavaDoc
891                 ("Internal error: Missing class name on method " + method);
892         }
893         verifyCallStack(method.substring(0, split), types);
894         
895         // generate the actual method call
896
append(m_instructionBuilder.createCallInterface(method, signature));
897         
898         // change stack state to reflect result of call
899
m_stackState.pop(types.length+1);
900         String JavaDoc result = ClassItem.getTypeFromSignature(signature);
901         if (!"void".equals(result)) {
902             m_stackState.push(result);
903         }
904     }
905
906     /**
907      * Append instruction to create instance of class.
908      *
909      * @param name fully qualified class name
910      */

911
912     public void appendCreateNew(String JavaDoc name) {
913         append(m_instructionBuilder.createNew(name));
914         m_stackState.push(name);
915     }
916
917     /**
918      * Create invoke initializer instruction from signature and append to
919      * method.
920      *
921      * @param name fully qualified class name
922      * @param signature method signature in standard form
923      */

924
925     public void appendCallInit(String JavaDoc name, String JavaDoc signature) {
926         
927         // verify all call parameters and object reference on stack
928
String JavaDoc[] types = ClassItem.getParametersFromSignature(signature);
929         verifyCallStack(name, types);
930         
931         // generate the actual method call
932
append(m_instructionBuilder.createCallInit(name, signature));
933         
934         // change stack state to reflect result of call
935
m_stackState.pop(types.length+1);
936     }
937
938     /**
939      * Append instruction to create instance of array.
940      *
941      * @param type fully qualified type name of array elements
942      */

943
944     public void appendCreateArray(String JavaDoc type) {
945         if (ClassItem.isPrimitive(type)) {
946             String JavaDoc sig = Utility.getSignature(type);
947             append(new NEWARRAY(Utility.typeOfSignature(sig)));
948         } else {
949             append(new ANEWARRAY(m_instructionBuilder.
950                 getConstantPoolGen().addClass(type)));
951         }
952         m_stackState.pop();
953         m_stackState.push(type + "[]");
954     }
955
956     /**
957      * Append check cast instruction (if needed).
958      *
959      * @param from fully qualified name of current type
960      * @param to fully qualified name of desired type
961      */

962
963     public void appendCreateCast(String JavaDoc from, String JavaDoc to) {
964         
965         // verify current top of stack
966
verifyStack(from);
967         
968         // check if any change of type
969
if (!from.equals(to)) {
970             
971             // generate instruction and change stack state to match
972
append(m_instructionBuilder.
973                 createCast(ClassItem.typeFromName(from),
974                 ClassItem.typeFromName(to)));
975             m_stackState.pop();
976             m_stackState.push(to);
977         }
978     }
979
980     /**
981      * Append check cast instruction from object (if needed).
982      *
983      * @param to fully qualified name of desired type
984      */

985
986     public void appendCreateCast(String JavaDoc to) {
987         
988         // verify current top of stack
989
verifyStackObject();
990         
991         // check if any change of type
992
if (!m_stackState.peek().equals(to)) {
993             
994             // generate instruction and change stack state to match
995
append(m_instructionBuilder.
996                 createCast(Type.OBJECT, ClassItem.typeFromName(to)));
997             m_stackState.pop();
998             m_stackState.push(to);
999         }
1000    }
1001
1002    /**
1003     * Append instanceof check instruction.
1004     *
1005     * @param to fully qualified name of type to check
1006     */

1007
1008    public void appendInstanceOf(String JavaDoc to) {
1009        
1010        // make sure the stack has an object reference
1011
verifyStackObject();
1012        
1013        // see if anything actually needs to be checked
1014
if ("java.lang.Object".equals(to)) {
1015            append(InstructionConstants.POP);
1016            appendLoadConstant(1);
1017        } else {
1018            append(m_instructionBuilder.
1019                createInstanceOf((ObjectType)ClassItem.typeFromName(to)));
1020        }
1021        
1022        // change stack state to reflect results of added code
1023
m_stackState.pop();
1024        m_stackState.push("int");
1025    }
1026    
1027    /**
1028     * Add local variable to method. The current code in the method must have
1029     * the initial value for the variable on the stack. The scope of the
1030     * variable is defined from the last instruction to the end of the
1031     * method unless otherwise modified.
1032     *
1033     * @param name local variable name
1034     * @param type variable type
1035     */

1036     
1037    protected LocalVariableGen createLocal(String JavaDoc name, Type type) {
1038        
1039        // verify top of stack
1040
verifyStack(type.toString());
1041        
1042        // allocation local and store value
1043
LocalVariableGen var = m_generator.addLocalVariable
1044            (name, type, getLastInstruction(), null);
1045        append(InstructionFactory.createStore(type, var.getIndex()));
1046        
1047        // save type information for local variable slot
1048
int slot = var.getIndex();
1049        while (slot >= m_localTypes.size()) {
1050            m_localTypes.add(null);
1051        }
1052        m_localTypes.set(slot, type.toString());
1053        
1054        // change stack state to reflect result
1055
m_stackState.pop();
1056        return var;
1057    }
1058    
1059    /**
1060     * Add local variable to method. The current code in the method must have
1061     * the initial value for the variable on the stack. The scope of the
1062     * variable is defined from the preceding instruction to the end of the
1063     * method.
1064     *
1065     * @param name local variable name
1066     * @param type variable type
1067     * @return local variable slot number
1068     */

1069     
1070    public int addLocal(String JavaDoc name, Type type) {
1071        LocalVariableGen var = createLocal(name, type);
1072        return var.getIndex();
1073    }
1074
1075    /**
1076     * Append instruction to load local variable.
1077     *
1078     * @param slot local variable slot to load
1079     */

1080
1081    public void appendLoadLocal(int slot) {
1082        String JavaDoc type = (String JavaDoc)m_localTypes.get(slot);
1083        if (type == null) {
1084            throw new IllegalArgumentException JavaDoc
1085                ("Internal error: No variable defined at position " + slot);
1086        }
1087        append(InstructionFactory.
1088            createLoad(ClassItem.typeFromName(type), slot));
1089        m_stackState.push(type);
1090    }
1091
1092    /**
1093     * Append instruction to store local variable.
1094     *
1095     * @param slot local variable slot to store
1096     */

1097
1098    public void appendStoreLocal(int slot) {
1099        String JavaDoc type = (String JavaDoc)m_localTypes.get(slot);
1100        if (type == null) {
1101            throw new IllegalArgumentException JavaDoc
1102                ("Internal error: No variable defined at position " + slot);
1103        }
1104        verifyStack(type);
1105        append(InstructionFactory.
1106            createStore(ClassItem.typeFromName(type), slot));
1107        m_stackState.pop();
1108    }
1109
1110    /**
1111     * Append instruction to increment local integer variable.
1112     *
1113     * @param inc amount of incrment
1114     * @param slot local variable slot to load
1115     */

1116
1117    public void appendIncrementLocal(int inc, int slot) {
1118        String JavaDoc type = (String JavaDoc)m_localTypes.get(slot);
1119        if (type == null) {
1120            throw new IllegalArgumentException JavaDoc
1121                ("Internal error: No variable defined at position " + slot);
1122        } else if (!"int".equals(type)) {
1123            throw new IllegalArgumentException JavaDoc("Internal error: Variable at " +
1124                slot + " is " + type + ", not int");
1125        }
1126        append(new IINC(slot, inc));
1127    }
1128
1129    /**
1130     * Append simple return.
1131     */

1132
1133    public void appendReturn() {
1134        append(InstructionConstants.RETURN);
1135        m_stackState = null;
1136    }
1137
1138    /**
1139     * Append typed return.
1140     *
1141     * @param type returned type (may be <code>Type.VOID</code>)
1142     */

1143
1144    public void appendReturn(Type type) {
1145        
1146        // verify and return the object reference
1147
if (type != Type.VOID) {
1148            verifyStack(type.toString());
1149        }
1150        append(InstructionFactory.createReturn(type));
1151        
1152        // set open stack state for potential continuation code
1153
m_stackState = null;
1154    }
1155
1156    /**
1157     * Append typed return.
1158     *
1159     * @param type returned type (may be <code>void</code>)
1160     */

1161
1162    public void appendReturn(String JavaDoc type) {
1163        
1164        // verify stack and generate return
1165
if ("void".equals(type)) {
1166            append(InstructionConstants.RETURN);
1167        } else {
1168            verifyStack(type);
1169            if (ClassItem.isPrimitive(type)) {
1170                if ("int".equals(type) || "char".equals(type) ||
1171                    "short".equals(type) || "boolean".equals(type)) {
1172                    append(InstructionConstants.IRETURN);
1173                } else if ("long".equals(type)) {
1174                    append(InstructionConstants.LRETURN);
1175                } else if ("float".equals(type)) {
1176                    append(InstructionConstants.FRETURN);
1177                } else if ("double".equals(type)) {
1178                    append(InstructionConstants.DRETURN);
1179                } else {
1180                    throw new IllegalArgumentException JavaDoc("Unknown argument type");
1181                }
1182            } else {
1183                append(InstructionConstants.ARETURN);
1184            }
1185        }
1186        
1187        // set open stack state for potential continuation code
1188
m_stackState = null;
1189    }
1190
1191    /**
1192     * Append exception throw.
1193     */

1194
1195    public void appendThrow() {
1196        append(InstructionConstants.ATHROW);
1197        m_stackState = null;
1198    }
1199    
1200    /**
1201     * Append an AASTORE to the instruction list. Doesn't actually check the
1202     * types, just the count of items present.
1203     */

1204     
1205    public void appendAASTORE() {
1206        verifyStackDepth(3);
1207        append(InstructionConstants.AASTORE);
1208        m_stackState.pop(3);
1209    }
1210    
1211    /**
1212     * Append an ACONST_NULL to the instruction list.
1213     */

1214     
1215    public void appendACONST_NULL() {
1216        append(InstructionConstants.ACONST_NULL);
1217        m_stackState.push("<null>");
1218    }
1219    
1220    /**
1221     * Append an DCMPG to the instruction list.
1222     */

1223     
1224    public void appendDCMPG() {
1225        verifyStack("double", "double");
1226        append(InstructionConstants.DCMPG);
1227        m_stackState.pop(2);
1228        m_stackState.push("int");
1229    }
1230    
1231    /**
1232     * Append a DUP to the instruction list.
1233     */

1234     
1235    public void appendDUP() {
1236        verifyStackDepth(1);
1237        append(InstructionConstants.DUP);
1238        m_stackState.push(m_stackState.peek());
1239    }
1240    
1241    /**
1242     * Append a DUP2 to the instruction list.
1243     */

1244     
1245    public void appendDUP2() {
1246        verifyStackDepth(1);
1247        append(InstructionConstants.DUP2);
1248        m_stackState.push(m_stackState.peek());
1249    }
1250    
1251    /**
1252     * Append a DUP_X1 to the instruction list.
1253     */

1254     
1255    public void appendDUP_X1() {
1256        verifyStackDepth(2);
1257        append(InstructionConstants.DUP_X1);
1258        String JavaDoc hold0 = m_stackState.pop();
1259        String JavaDoc hold1 = m_stackState.pop();
1260        m_stackState.push(hold0);
1261        m_stackState.push(hold1);
1262        m_stackState.push(hold0);
1263    }
1264    
1265    /**
1266     * Append an FCMPG to the instruction list.
1267     */

1268     
1269    public void appendFCMPG() {
1270        verifyStack("float", "float");
1271        append(InstructionConstants.FCMPG);
1272        m_stackState.pop(2);
1273        m_stackState.push("int");
1274    }
1275    
1276    /**
1277     * Append an IASTORE to the instruction list. Doesn't actually check the
1278     * types, just the count of items present.
1279     */

1280     
1281    public void appendIASTORE() {
1282        verifyStackDepth(3);
1283        append(InstructionConstants.IASTORE);
1284        m_stackState.pop(3);
1285    }
1286    
1287    /**
1288     * Append an ICONST_0 to the instruction list.
1289     */

1290     
1291    public void appendICONST_0() {
1292        append(InstructionConstants.ICONST_0);
1293        m_stackState.push("int");
1294    }
1295    
1296    /**
1297     * Append an ICONST_1 to the instruction list.
1298     */

1299     
1300    public void appendICONST_1() {
1301        append(InstructionConstants.ICONST_1);
1302        m_stackState.push("int");
1303    }
1304    
1305    /**
1306     * Append an ISUB to the instruction list.
1307     */

1308     
1309    public void appendISUB() {
1310        verifyStack("int", "int");
1311        append(InstructionConstants.ISUB);
1312        m_stackState.pop(1);
1313    }
1314    
1315    /**
1316     * Append an IXOR to the instruction list.
1317     */

1318     
1319    public void appendIXOR() {
1320        verifyStack("int", "int");
1321        append(InstructionConstants.IXOR);
1322        m_stackState.pop(1);
1323    }
1324    
1325    /**
1326     * Append an LCMP to the instruction list.
1327     */

1328     
1329    public void appendLCMP() {
1330        verifyStack("long", "long");
1331        append(InstructionConstants.LCMP);
1332        m_stackState.pop(2);
1333        m_stackState.push("int");
1334    }
1335    
1336    /**
1337     * Append a POP to the instruction list.
1338     */

1339     
1340    public void appendPOP() {
1341        verifyStackDepth(1);
1342        String JavaDoc type = m_stackState.peek();
1343        if ("long".equals(type) || "double".equals(type)) {
1344            throw new IllegalStateException JavaDoc
1345                ("Internal error: POP splits long value");
1346        }
1347        append(InstructionConstants.POP);
1348        m_stackState.pop();
1349    }
1350    
1351    /**
1352     * Append a POP2 to the instruction list.
1353     */

1354     
1355    public void appendPOP2() {
1356        verifyStackDepth(1);
1357        String JavaDoc type = m_stackState.peek();
1358        if (!"long".equals(type) && !"double".equals(type)) {
1359            throw new IllegalStateException JavaDoc
1360                ("Internal error: POP2 requires long value");
1361        }
1362        append(InstructionConstants.POP2);
1363        m_stackState.pop();
1364    }
1365    
1366    /**
1367     * Append a SWAP to the instruction list.
1368     */

1369     
1370    public void appendSWAP() {
1371        verifyStackDepth(2);
1372        append(InstructionConstants.SWAP);
1373        String JavaDoc hold0 = m_stackState.pop();
1374        String JavaDoc hold1 = m_stackState.pop();
1375        m_stackState.push(hold0);
1376        m_stackState.push(hold1);
1377    }
1378    
1379    /**
1380     * Append a compound instruction to the list as a branch target.
1381     *
1382     * @param inst compound instruction to be appended as branch target
1383     * @return branch target information
1384     */

1385     
1386    private BranchTarget appendTargetInstruction(CompoundInstruction inst) {
1387        String JavaDoc[] types = m_stackState.toArray();
1388        InstructionHandle hand = m_instructionList.append(inst);
1389        return new BranchTarget(hand, types);
1390    }
1391    
1392    /**
1393     * Append an instruction to the list as a branch target.
1394     *
1395     * @param inst instruction to be appended as branch target
1396     * @return branch target information
1397     */

1398     
1399    private BranchTarget appendTargetInstruction(Instruction inst) {
1400        String JavaDoc[] types = m_stackState.toArray();
1401        InstructionHandle hand = m_instructionList.append(inst);
1402        return new BranchTarget(hand, types);
1403    }
1404    
1405    /**
1406     * Append a NOP to the instruction list as a branch target.
1407     *
1408     * @return branch target information
1409     */

1410     
1411    public BranchTarget appendTargetNOP() {
1412        return appendTargetInstruction(InstructionConstants.NOP);
1413    }
1414    
1415    /**
1416     * Append an ACONST_NULL to the instruction list as a branch target.
1417     *
1418     * @return branch target information
1419     */

1420     
1421    public BranchTarget appendTargetACONST_NULL() {
1422        BranchTarget target = appendTargetInstruction
1423            (InstructionConstants.ACONST_NULL);
1424        m_stackState.push("<null>");
1425        return target;
1426    }
1427    
1428    /**
1429     * Append a load constant instruction as a branch target. Builds the most
1430     * appropriate type of instruction for the value.
1431     *
1432     * @param value constant value to be loaded
1433     * @return branch target information
1434     */

1435     
1436    public BranchTarget appendTargetLoadConstant(int value) {
1437        BranchTarget target = appendTargetInstruction(m_instructionBuilder.
1438            createLoadConstant(value));
1439        m_stackState.push("int");
1440        return target;
1441    }
1442    
1443    /**
1444     * Append a load constant instruction as a branch target. Loads a
1445     * <code>String</code> reference from the constant pool.
1446     *
1447     * @param value constant value to be loaded
1448     * @return branch target information
1449     */

1450     
1451    public BranchTarget appendTargetLoadConstant(String JavaDoc value) {
1452        BranchTarget target = appendTargetInstruction(m_instructionBuilder.
1453            createLoadConstant(value));
1454        m_stackState.push("java.lang.String");
1455        return target;
1456    }
1457    
1458    /**
1459     * Append instruction to create instance of class as a branch target.
1460     *
1461     * @param name fully qualified class name
1462     * @return branch target information
1463     */

1464     
1465    public BranchTarget appendTargetCreateNew(String JavaDoc name) {
1466        BranchTarget target =
1467            appendTargetInstruction(m_instructionBuilder.createNew(name));
1468        m_stackState.push(name);
1469        return target;
1470    }
1471
1472    /**
1473     * Internal append instruction to create instance of class. This is used by
1474     * subclasses when they need access to the actual instruction handle.
1475     *
1476     * @param name fully qualified class name
1477     */

1478
1479    protected InstructionHandle internalAppendCreateNew(String JavaDoc name) {
1480        InstructionHandle handle = m_instructionList.append
1481            (m_instructionBuilder.createNew(name));
1482        m_stackState.push(name);
1483        return handle;
1484    }
1485
1486    /**
1487     * Check if top item on stack is a long value.
1488     *
1489     * @return <code>true</code> if long value, <code>false</code> if not
1490     */

1491
1492    public boolean isStackTopLong() {
1493        verifyStackDepth(1);
1494        String JavaDoc type = m_stackState.peek();
1495        return "long".equals(type) || "double".equals(type);
1496    }
1497
1498    /**
1499     * Initialize stack state to match branch source. This can be used to set
1500     * the expected stack state following an unconditional transfer of control
1501     * instruction. The principle here is that the code to be generated must be
1502     * reached by a branch, so the stack state must match that of the branch
1503     * source.
1504     *
1505     * @param branch wrapper for branch to be for stack initialization
1506     */

1507
1508    public void initStackState(BranchWrapper branch) {
1509        m_stackState = new StringStack(branch.getStackState());
1510    }
1511
1512    /**
1513     * Initialize stack state to partially match branch source. This can be used
1514     * to set the expected stack state following an unconditional transfer of
1515     * control instruction. The specified number of items are removed from the
1516     * branch stack, with the assumption that code to add these items will be
1517     * appended before the branch join point is reached.
1518     *
1519     * @param branch wrapper for branch to be for stack initialization
1520     * @param pop number of items to be removed from branch source stack state
1521     */

1522
1523    public void initStackState(BranchWrapper branch, int pop) {
1524        m_stackState = new StringStack(branch.getStackState());
1525        if (pop > 0) {
1526            m_stackState.pop(pop);
1527        }
1528    }
1529
1530    /**
1531     * Initialize stack state to array of value types. This can be used to set
1532     * the expected stack state following an unconditional transfer of control
1533     * instruction.
1534     *
1535     * @param types array of type names on stack
1536     */

1537
1538    protected void initStackState(String JavaDoc[] types) {
1539        m_stackState = new StringStack(types);
1540    }
1541
1542    /**
1543     * Set branch target as next instruction added to method. This effectively
1544     * sets up a state trigger for the next append operation. The appended
1545     * instruction is set as the target for the branch. This requires that
1546     * instructions are only appended using the methods supplied in this class.
1547     *
1548     * @branch wrapper for branch to be aimed at next instruction (may be
1549     * <code>null</code>, in which case nothing is done)
1550     * TODO: Reuse array with active length rather than copying
1551     */

1552
1553    public void targetNext(BranchWrapper branch) {
1554        if (branch != null) {
1555            if (m_targetBranches == null) {
1556                m_targetBranches = new BranchWrapper[] { branch };
1557                if (m_stackState == null) {
1558                    m_stackState = new StringStack(branch.getStackState());
1559                }
1560            } else {
1561                int length = m_targetBranches.length;
1562                BranchWrapper[] wrappers = new BranchWrapper[length+1];
1563                System.arraycopy(m_targetBranches, 0, wrappers, 0, length);
1564                wrappers[length] = branch;
1565                m_targetBranches = wrappers;
1566            }
1567        }
1568    }
1569
1570    /**
1571     * Process accumulated exceptions. Each subclass must implement this
1572     * method to perform the appropriate handling of the checked exceptions
1573     * that may be thrown in the constructed method.
1574     *
1575     * @throws JiBXException on error in exception handling
1576     */

1577
1578    protected abstract void handleExceptions() throws JiBXException;
1579
1580    /**
1581     * Complete method construction. Finalizes the instruction list and
1582     * generates the byte code for the constructed method, then computes the
1583     * hash code based on the byte code. If requested, an appropriate suffix is
1584     * tacked on the end of the supplied name in order to make sure that it will
1585     * not be duplicated (even in a superclass or subclass).
1586     *
1587     * @param suffix add suffix to make method name unique
1588     * @throws JiBXException on error in finishing method construction
1589     */

1590
1591    public void codeComplete(boolean suffix) throws JiBXException {
1592        if (m_targetBranches != null) {
1593            throw new IllegalStateException JavaDoc
1594                ("Method complete with pending branch target");
1595        }
1596        if (m_exceptions != null) {
1597            handleExceptions();
1598        }
1599        if (suffix) {
1600            m_generator.setName(getClassFile().
1601                makeUniqueMethodName(m_generator.getName()));
1602        }
1603        m_generator.setMaxStack();
1604        m_generator.setMaxLocals();
1605        m_instructionList.setPositions(true);
1606        m_method = m_generator.getMethod();
1607        m_instructionList.dispose();
1608        m_hashCode = computeMethodHash(m_method);
1609    }
1610    
1611    /**
1612     * Get the method item.
1613     *
1614     * @return method item information
1615     */

1616     
1617    public ClassItem getItem() {
1618        if (m_item == null) {
1619            throw new IllegalStateException JavaDoc("Method not added to class");
1620        } else {
1621            return m_item;
1622        }
1623    }
1624
1625    /**
1626     * Get hash code. This is based only on the byte code in the method, and
1627     * is only valid after the {@link #codeComplete} method is called.
1628     *
1629     * @return hash code based on code sequence
1630     */

1631
1632    public int hashCode() {
1633        if (m_method == null) {
1634            throw new IllegalStateException JavaDoc("Method still under construction");
1635        } else {
1636            return m_hashCode;
1637        }
1638    }
1639
1640    /**
1641     * Add constructed method to class. Makes the method callable, generating
1642     * the method information.
1643     *
1644     * @return added method information
1645     * @throws JiBXException on error in finishing method construction
1646     */

1647
1648    public ClassItem addMethod() throws JiBXException {
1649        if (m_method == null) {
1650            throw new IllegalStateException JavaDoc("Method not finalized.");
1651        } else {
1652            m_item = getClassFile().addMethod(m_method);
1653            return m_item;
1654        }
1655    }
1656}
Popular Tags