KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javassist > CtBehavior


1 /*
2  * Javassist, a Java-bytecode translator toolkit.
3  * Copyright (C) 1999-2005 Shigeru Chiba. All Rights Reserved.
4  *
5  * The contents of this file are subject to the Mozilla Public License Version
6  * 1.1 (the "License"); you may not use this file except in compliance with
7  * the License. Alternatively, the contents of this file may be used under
8  * the terms of the GNU Lesser General Public License Version 2.1 or later.
9  *
10  * Software distributed under the License is distributed on an "AS IS" basis,
11  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12  * for the specific language governing rights and limitations under the
13  * License.
14  */

15
16 package javassist;
17
18 import javassist.bytecode.*;
19 import javassist.compiler.Javac;
20 import javassist.compiler.CompileError;
21 import javassist.expr.ExprEditor;
22
23 /**
24  * <code>CtBehavior</code> represents a method, a constructor,
25  * or a static constructor (class initializer).
26  * It is the abstract super class of
27  * <code>CtMethod</code> and <code>CtConstructor</code>.
28  */

29 public abstract class CtBehavior extends CtMember {
30     protected MethodInfo methodInfo;
31
32     protected CtBehavior(CtClass clazz, MethodInfo minfo) {
33         super(clazz);
34         methodInfo = minfo;
35     }
36
37     protected void extendToString(StringBuffer JavaDoc buffer) {
38         buffer.append(' ');
39         buffer.append(getName());
40         buffer.append(' ');
41         buffer.append(methodInfo.getDescriptor());
42     }
43
44     /**
45      * Returns the MethodInfo representing this method/constructor in the
46      * class file.
47      */

48     public MethodInfo getMethodInfo() {
49         declaringClass.checkModify();
50         return methodInfo;
51     }
52
53     /**
54      * Undocumented method. Do not use; internal-use only.
55      */

56     public MethodInfo getMethodInfo2() { return methodInfo; }
57
58     /**
59      * Obtains the modifiers of the method/constructor.
60      *
61      * @return modifiers encoded with
62      * <code>javassist.Modifier</code>.
63      * @see Modifier
64      */

65     public int getModifiers() {
66         return AccessFlag.toModifier(methodInfo.getAccessFlags());
67     }
68
69     /**
70      * Sets the encoded modifiers of the method/constructor.
71      *
72      * <p>Changing the modifiers may cause a problem.
73      * For example, if a non-static method is changed to static,
74      * the method will be rejected by the bytecode verifier.
75      *
76      * @see Modifier
77      */

78     public void setModifiers(int mod) {
79         declaringClass.checkModify();
80         methodInfo.setAccessFlags(AccessFlag.of(mod));
81     }
82
83     /**
84      * Obtains parameter types of this method/constructor.
85      */

86     public CtClass[] getParameterTypes() throws NotFoundException {
87         return Descriptor.getParameterTypes(methodInfo.getDescriptor(),
88                                             declaringClass.getClassPool());
89     }
90
91     /**
92      * Obtains the type of the returned value.
93      */

94     CtClass getReturnType0() throws NotFoundException {
95         return Descriptor.getReturnType(methodInfo.getDescriptor(),
96                                         declaringClass.getClassPool());
97     }
98
99     /**
100      * Returns the character string representing the parameter types
101      * and the return type. If two methods/constructors have
102      * the same parameter types
103      * and the return type, <code>getSignature()</code> returns the
104      * same string (the return type of constructors is <code>void</code>).
105      */

106     public String JavaDoc getSignature() {
107         return methodInfo.getDescriptor();
108     }
109
110     /**
111      * Obtains exceptions that this method/constructor may throw.
112      *
113      * @return a zero-length array if there is no throws clause.
114      */

115     public CtClass[] getExceptionTypes() throws NotFoundException {
116         String JavaDoc[] exceptions;
117         ExceptionsAttribute ea = methodInfo.getExceptionsAttribute();
118         if (ea == null)
119             exceptions = null;
120         else
121             exceptions = ea.getExceptions();
122
123         return declaringClass.getClassPool().get(exceptions);
124     }
125
126     /**
127      * Sets exceptions that this method/constructor may throw.
128      */

129     public void setExceptionTypes(CtClass[] types) throws NotFoundException {
130         declaringClass.checkModify();
131         if (types == null || types.length == 0) {
132             methodInfo.removeExceptionsAttribute();
133             return;
134         }
135
136         String JavaDoc[] names = new String JavaDoc[types.length];
137         for (int i = 0; i < types.length; ++i)
138             names[i] = types[i].getName();
139
140         ExceptionsAttribute ea = methodInfo.getExceptionsAttribute();
141         if (ea == null) {
142             ea = new ExceptionsAttribute(methodInfo.getConstPool());
143             methodInfo.setExceptionsAttribute(ea);
144         }
145
146         ea.setExceptions(names);
147     }
148
149     /**
150      * Returns true if the body is empty.
151      */

152     public abstract boolean isEmpty();
153
154     /**
155      * Sets a method/constructor body.
156      *
157      * @param src the source code representing the body.
158      * It must be a single statement or block.
159      * If it is <code>null</code>, the substituted
160      * body does nothing except returning zero or null.
161      */

162     public void setBody(String JavaDoc src) throws CannotCompileException {
163         setBody(src, null, null);
164     }
165
166     /**
167      * Sets a method/constructor body.
168      *
169      * @param src the source code representing the body.
170      * It must be a single statement or block.
171      * If it is <code>null</code>, the substituted
172      * body does nothing except returning zero or null.
173      * @param delegateObj the source text specifying the object
174      * that is called on by <code>$proceed()</code>.
175      * @param delegateMethod the name of the method
176      * that is called by <code>$proceed()</code>.
177      */

178     public void setBody(String JavaDoc src,
179                         String JavaDoc delegateObj, String JavaDoc delegateMethod)
180         throws CannotCompileException
181     {
182         declaringClass.checkModify();
183         try {
184             Javac jv = new Javac(declaringClass);
185             if (delegateMethod != null)
186                 jv.recordProceed(delegateObj, delegateMethod);
187
188             Bytecode b = jv.compileBody(this, src);
189             methodInfo.setCodeAttribute(b.toCodeAttribute());
190             methodInfo.setAccessFlags(methodInfo.getAccessFlags()
191                                       & ~AccessFlag.ABSTRACT);
192         }
193         catch (CompileError e) {
194             throw new CannotCompileException(e);
195         }
196     }
197
198     static void setBody0(CtClass srcClass, MethodInfo srcInfo,
199                          CtClass destClass, MethodInfo destInfo,
200                          ClassMap map)
201         throws CannotCompileException
202     {
203         destClass.checkModify();
204
205         if (map == null)
206             map = new ClassMap();
207
208         map.put(srcClass.getName(), destClass.getName());
209         try {
210             CodeAttribute cattr = srcInfo.getCodeAttribute();
211             if (cattr != null) {
212                 ConstPool cp = destInfo.getConstPool();
213                 CodeAttribute ca = (CodeAttribute)cattr.copy(cp, map);
214                 destInfo.setCodeAttribute(ca);
215             }
216         }
217         catch (CodeAttribute.RuntimeCopyException e) {
218             /* the exception may be thrown by copy() in CodeAttribute.
219              */

220             throw new CannotCompileException(e);
221         }
222
223         destInfo.setAccessFlags(destInfo.getAccessFlags()
224                                 & ~AccessFlag.ABSTRACT);
225     }
226
227     /**
228      * Obtains an attribute with the given name.
229      * If that attribute is not found in the class file, this
230      * method returns null.
231      *
232      * @param name attribute name
233      */

234     public byte[] getAttribute(String JavaDoc name) {
235         AttributeInfo ai = methodInfo.getAttribute(name);
236         if (ai == null)
237             return null;
238         else
239             return ai.get();
240     }
241
242     /**
243      * Adds an attribute. The attribute is saved in the class file.
244      *
245      * @param name attribute name
246      * @param data attribute value
247      */

248     public void setAttribute(String JavaDoc name, byte[] data) {
249         declaringClass.checkModify();
250         methodInfo.addAttribute(new AttributeInfo(methodInfo.getConstPool(),
251                                                   name, data));
252     }
253
254     /**
255      * Declares to use <code>$cflow</code> for this method/constructor.
256      * If <code>$cflow</code> is used, the class files modified
257      * with Javassist requires a support class
258      * <code>javassist.runtime.Cflow</code> at runtime
259      * (other Javassist classes are not required at runtime).
260      *
261      * <p>Every <code>$cflow</code> variable is given a unique name.
262      * For example, if the given name is <code>"Point.paint"</code>,
263      * then the variable is indicated by <code>$cflow(Point.paint)</code>.
264      *
265      * @param name <code>$cflow</code> name. It can include
266      * alphabets, numbers, <code>_</code>,
267      * <code>$</code>, and <code>.</code> (dot).
268      *
269      * @see javassist.runtime.Cflow
270      */

271     public void useCflow(String JavaDoc name) throws CannotCompileException {
272         CtClass cc = declaringClass;
273         cc.checkModify();
274         ClassPool pool = cc.getClassPool();
275         String JavaDoc fname;
276         int i = 0;
277         while (true) {
278             fname = "_cflow$" + i++;
279             try {
280                 cc.getDeclaredField(fname);
281             }
282             catch(NotFoundException e) {
283                 break;
284             }
285         }
286
287         pool.recordCflow(name, declaringClass.getName(), fname);
288         try {
289             CtClass type = pool.get("javassist.runtime.Cflow");
290             CtField field = new CtField(type, fname, cc);
291             field.setModifiers(Modifier.PUBLIC | Modifier.STATIC);
292             cc.addField(field, CtField.Initializer.byNew(type));
293             insertBefore(fname + ".enter();");
294             String JavaDoc src = fname + ".exit();";
295             insertAfter(src, true);
296         }
297         catch (NotFoundException e) {
298             throw new CannotCompileException(e);
299         }
300     }
301
302     /**
303      * Declares a new local variable. The scope of this variable is the
304      * whole method body. The initial value of that variable is not set.
305      * The declared variable can be accessed in the code snippet inserted
306      * by <code>insertBefore()</code>, <code>insertAfter()</code>, etc.
307      *
308      * @param name the name of the variable
309      * @param type the type of the variable
310      * @see #insertBefore(String)
311      * @see #insertAfter(String)
312      */

313     public void addLocalVariable(String JavaDoc name, CtClass type)
314         throws CannotCompileException
315     {
316         declaringClass.checkModify();
317         ConstPool cp = methodInfo.getConstPool();
318         CodeAttribute ca = methodInfo.getCodeAttribute();
319         if (ca == null)
320             throw new CannotCompileException("no method body");
321
322         LocalVariableAttribute va = (LocalVariableAttribute)ca.getAttribute(
323                                                 LocalVariableAttribute.tag);
324         if (va == null) {
325             va = new LocalVariableAttribute(cp);
326             ca.getAttributes().add(va);
327         }
328
329         int maxLocals = ca.getMaxLocals();
330         String JavaDoc desc = Descriptor.of(type);
331         va.addEntry(0, ca.getCodeLength(),
332                     cp.addUtf8Info(name), cp.addUtf8Info(desc), maxLocals);
333         ca.setMaxLocals(maxLocals + Descriptor.dataSize(desc));
334     }
335
336     /**
337      * Modifies the method/constructor body.
338      *
339      * @param converter specifies how to modify.
340      */

341     public void instrument(CodeConverter converter)
342         throws CannotCompileException
343     {
344         declaringClass.checkModify();
345         ConstPool cp = methodInfo.getConstPool();
346         converter.doit(getDeclaringClass(), methodInfo, cp);
347     }
348
349     /**
350      * Modifies the method/constructor body.
351      *
352      * @param editor specifies how to modify.
353      */

354     public void instrument(ExprEditor editor)
355         throws CannotCompileException
356     {
357         // if the class is not frozen,
358
// does not turn the modified flag on.
359
if (declaringClass.isFrozen())
360             declaringClass.checkModify();
361
362         if (editor.doit(declaringClass, methodInfo))
363             declaringClass.checkModify();
364     }
365
366     /**
367      * Inserts bytecode at the beginning of the body.
368      *
369      * <p>If this object represents a constructor,
370      * the bytecode is inserted before
371      * a constructor in the super class or this class is called.
372      * Therefore, the inserted bytecode is subject to constraints described
373      * in Section 4.8.2 of The Java Virtual Machine Specification (2nd ed).
374      * For example, it cannot access instance fields or methods
375      * although it can access static fields and methods.
376      * Use <code>insertBeforeBody()</code> in <code>CtConstructor</code>.
377      *
378      * @param src the source code representing the inserted bytecode.
379      * It must be a single statement or block.
380      * @see CtConstructor#insertBeforeBody(String)
381      */

382     public void insertBefore(String JavaDoc src) throws CannotCompileException {
383         declaringClass.checkModify();
384         CodeAttribute ca = methodInfo.getCodeAttribute();
385         if (ca == null)
386             throw new CannotCompileException("no method body");
387
388         CodeIterator iterator = ca.iterator();
389         Javac jv = new Javac(declaringClass);
390         try {
391             int nvars = jv.recordParams(getParameterTypes(),
392                                         Modifier.isStatic(getModifiers()));
393             jv.recordParamNames(ca, nvars);
394             jv.recordLocalVariables(ca, 0);
395             jv.compileStmnt(src);
396             Bytecode b = jv.getBytecode();
397             int stack = b.getMaxStack();
398             int locals = b.getMaxLocals();
399
400             if (stack > ca.getMaxStack())
401                 ca.setMaxStack(stack);
402
403             if (locals > ca.getMaxLocals())
404                 ca.setMaxLocals(locals);
405
406             int pos = iterator.insertEx(b.get());
407             iterator.insert(b.getExceptionTable(), pos);
408         }
409         catch (NotFoundException e) {
410             throw new CannotCompileException(e);
411         }
412         catch (CompileError e) {
413             throw new CannotCompileException(e);
414         }
415         catch (BadBytecode e) {
416             throw new CannotCompileException(e);
417         }
418     }
419
420     /**
421      * Inserts bytecode at the end of the body.
422      * The bytecode is inserted just before every return insturction.
423      * It is not executed when an exception is thrown.
424      *
425      * @param src the source code representing the inserted bytecode.
426      * It must be a single statement or block.
427      */

428     public void insertAfter(String JavaDoc src)
429         throws CannotCompileException
430     {
431         insertAfter(src, false);
432     }
433
434     /**
435      * Inserts bytecode at the end of the body.
436      * The bytecode is inserted just before every return insturction.
437      *
438      * @param src the source code representing the inserted bytecode.
439      * It must be a single statement or block.
440      * @param asFinally true if the inserted bytecode is executed
441      * not only when the control normally returns
442      * but also when an exception is thrown.
443      */

444     public void insertAfter(String JavaDoc src, boolean asFinally)
445         throws CannotCompileException
446     {
447         declaringClass.checkModify();
448         ConstPool pool = methodInfo.getConstPool();
449         CodeAttribute ca = methodInfo.getCodeAttribute();
450         if (ca == null)
451             throw new CannotCompileException("no method body");
452
453         CodeIterator iterator = ca.iterator();
454         int retAddr = ca.getMaxLocals();
455         Bytecode b = new Bytecode(pool, 0, retAddr + 1);
456         b.setStackDepth(ca.getMaxStack() + 1);
457         Javac jv = new Javac(b, declaringClass);
458         try {
459             int nvars = jv.recordParams(getParameterTypes(),
460                                         Modifier.isStatic(getModifiers()));
461             jv.recordParamNames(ca, nvars);
462             CtClass rtype = getReturnType0();
463             int varNo = jv.recordReturnType(rtype, true);
464             jv.recordLocalVariables(ca, 0);
465
466             int handlerLen = insertAfterHandler(asFinally, b, rtype, varNo);
467
468             byte[] save = makeSaveCode(pool, rtype, varNo);
469             byte[] restore = makeRestoreCode(b, pool, rtype, varNo);
470
471             b.addAstore(retAddr);
472             jv.compileStmnt(src);
473             b.addRet(retAddr);
474             ca.setMaxStack(b.getMaxStack());
475             ca.setMaxLocals(b.getMaxLocals());
476
477             int gapPos = iterator.append(b.get());
478             iterator.append(b.getExceptionTable(), gapPos);
479
480             if (asFinally)
481                 ca.getExceptionTable().add(0, gapPos, gapPos, 0);
482
483             int gapLen = iterator.getCodeLength() - gapPos - handlerLen;
484             int subr = iterator.getCodeLength() - gapLen;
485
486             while (iterator.hasNext()) {
487                 int pos = iterator.next();
488                 if (pos >= subr)
489                     break;
490
491                 int c = iterator.byteAt(pos);
492                 if (c == Opcode.ARETURN || c == Opcode.IRETURN
493                     || c == Opcode.FRETURN || c == Opcode.LRETURN
494                     || c == Opcode.DRETURN || c == Opcode.RETURN) {
495                     insertJSR(iterator, subr, pos, save, restore);
496                     subr = iterator.getCodeLength() - gapLen;
497                 }
498             }
499         }
500         catch (NotFoundException e) {
501             throw new CannotCompileException(e);
502         }
503         catch (CompileError e) {
504             throw new CannotCompileException(e);
505         }
506         catch (BadBytecode e) {
507             throw new CannotCompileException(e);
508         }
509     }
510
511     private byte[] makeSaveCode(ConstPool cp, CtClass rtype, int varNo) {
512         Bytecode b = new Bytecode(cp, 0, 0);
513         if (rtype == CtClass.voidType) {
514             b.addOpcode(Opcode.ACONST_NULL);
515             b.addAstore(varNo);
516             return b.get();
517         }
518         else {
519             b.addStore(varNo, rtype);
520             return b.get();
521         }
522     }
523
524     private byte[] makeRestoreCode(Bytecode code, ConstPool cp,
525                                    CtClass rtype, int varNo) {
526         if (rtype == CtClass.voidType) {
527             if (code.getMaxLocals() < 1)
528                 code.setMaxLocals(1);
529
530             return new byte[0];
531         }
532         else {
533             Bytecode b = new Bytecode(cp, 0, 0);
534             b.addLoad(varNo, rtype);
535             return b.get();
536         }
537     }
538
539     private void insertJSR(CodeIterator iterator, int subr, int pos,
540                            byte[] save, byte[] restore)
541         throws BadBytecode
542     {
543         int gapSize = 5 + save.length + restore.length;
544         boolean wide = subr - pos > Short.MAX_VALUE - gapSize - 4;
545         gapSize = iterator.insertGap(pos, wide ? gapSize : gapSize - 2);
546
547         iterator.write(save, pos);
548         pos += save.length;
549         if (wide) {
550             iterator.writeByte(Opcode.JSR_W, pos);
551             iterator.write32bit(subr - pos + gapSize, pos + 1);
552             pos += 5;
553         }
554         else {
555             iterator.writeByte(Opcode.JSR, pos);
556             iterator.write16bit(subr - pos + gapSize, pos + 1);
557             pos += 3;
558         }
559
560         iterator.write(restore, pos);
561     }
562
563     private int insertAfterHandler(boolean asFinally, Bytecode b,
564                                    CtClass rtype, int returnVarNo)
565     {
566         if (!asFinally)
567             return 0;
568
569         int var = b.getMaxLocals();
570         b.incMaxLocals(1);
571         int pc = b.currentPc();
572         b.addAstore(var);
573         if (rtype.isPrimitive()) {
574             char c = ((CtPrimitiveType)rtype).getDescriptor();
575             if (c == 'D') {
576                 b.addDconst(0.0);
577                 b.addDstore(returnVarNo);
578             }
579             else if (c == 'F') {
580                 b.addFconst(0);
581                 b.addFstore(returnVarNo);
582             }
583             else if (c == 'J') {
584                 b.addLconst(0);
585                 b.addLstore(returnVarNo);
586             }
587             else if (c != 'V') { // int, boolean, char, short, ...
588
b.addIconst(0);
589                 b.addIstore(returnVarNo);
590             }
591         }
592         else {
593             b.addOpcode(Opcode.ACONST_NULL);
594             b.addAstore(returnVarNo);
595         }
596
597         b.addOpcode(Opcode.JSR);
598         int pc2 = b.currentPc();
599         b.addIndex(0); // correct later
600
b.addAload(var);
601         b.addOpcode(Opcode.ATHROW);
602         int pc3 = b.currentPc();
603         b.write16bit(pc2, pc3 - pc2 + 1);
604         return pc3 - pc;
605     }
606
607     /* -- OLD version --
608
609     public void insertAfter(String src) throws CannotCompileException {
610         declaringClass.checkModify();
611         CodeAttribute ca = methodInfo.getCodeAttribute();
612         CodeIterator iterator = ca.iterator();
613         Bytecode b = new Bytecode(methodInfo.getConstPool(),
614                                   ca.getMaxStack(), ca.getMaxLocals());
615         b.setStackDepth(ca.getMaxStack());
616         Javac jv = new Javac(b, declaringClass);
617         try {
618             jv.recordParams(getParameterTypes(),
619                             Modifier.isStatic(getModifiers()));
620             CtClass rtype = getReturnType0();
621             int varNo = jv.recordReturnType(rtype, true);
622             boolean isVoid = rtype == CtClass.voidType;
623             if (isVoid) {
624                 b.addOpcode(Opcode.ACONST_NULL);
625                 b.addAstore(varNo);
626                 jv.compileStmnt(src);
627             }
628             else {
629                 b.addStore(varNo, rtype);
630                 jv.compileStmnt(src);
631                 b.addLoad(varNo, rtype);
632             }
633
634             byte[] code = b.get();
635             ca.setMaxStack(b.getMaxStack());
636             ca.setMaxLocals(b.getMaxLocals());
637             while (iterator.hasNext()) {
638                 int pos = iterator.next();
639                 int c = iterator.byteAt(pos);
640                 if (c == Opcode.ARETURN || c == Opcode.IRETURN
641                     || c == Opcode.FRETURN || c == Opcode.LRETURN
642                     || c == Opcode.DRETURN || c == Opcode.RETURN)
643                     iterator.insert(pos, code);
644             }
645         }
646         catch (NotFoundException e) {
647             throw new CannotCompileException(e);
648         }
649         catch (CompileError e) {
650             throw new CannotCompileException(e);
651         }
652         catch (BadBytecode e) {
653             throw new CannotCompileException(e);
654         }
655     }
656     */

657
658     /**
659      * Adds a catch clause that handles an exception thrown in the
660      * body. The catch clause must end with a return or throw statement.
661      *
662      * @param src the source code representing the catch clause.
663      * It must be a single statement or block.
664      * @param exceptionType the type of the exception handled by the
665      * catch clause.
666      */

667     public void addCatch(String JavaDoc src, CtClass exceptionType)
668         throws CannotCompileException
669     {
670         addCatch(src, exceptionType, "$e");
671     }
672
673     /**
674      * Adds a catch clause that handles an exception thrown in the
675      * body. The catch clause must end with a return or throw statement.
676      *
677      * @param src the source code representing the catch clause.
678      * It must be a single statement or block.
679      * @param exceptionType the type of the exception handled by the
680      * catch clause.
681      * @param exceptionName the name of the variable containing the
682      * caught exception, for example,
683      * <code>$e</code>.
684      */

685     public void addCatch(String JavaDoc src, CtClass exceptionType,
686                          String JavaDoc exceptionName)
687         throws CannotCompileException
688     {
689         declaringClass.checkModify();
690         ConstPool cp = methodInfo.getConstPool();
691         CodeAttribute ca = methodInfo.getCodeAttribute();
692         CodeIterator iterator = ca.iterator();
693         Bytecode b = new Bytecode(cp, ca.getMaxStack(), ca.getMaxLocals());
694         b.setStackDepth(1);
695         Javac jv = new Javac(b, declaringClass);
696         try {
697             jv.recordParams(getParameterTypes(),
698                             Modifier.isStatic(getModifiers()));
699             int var = jv.recordVariable(exceptionType, exceptionName);
700             b.addAstore(var);
701             jv.compileStmnt(src);
702
703             int stack = b.getMaxStack();
704             int locals = b.getMaxLocals();
705
706             if (stack > ca.getMaxStack())
707                 ca.setMaxStack(stack);
708
709             if (locals > ca.getMaxLocals())
710                 ca.setMaxLocals(locals);
711
712             int len = iterator.getCodeLength();
713             int pos = iterator.append(b.get());
714             ca.getExceptionTable().add(getStartPosOfBody(ca), len, len,
715                                        cp.addClassInfo(exceptionType));
716             iterator.append(b.getExceptionTable(), pos);
717         }
718         catch (NotFoundException e) {
719             throw new CannotCompileException(e);
720         }
721         catch (CompileError e) {
722             throw new CannotCompileException(e);
723         }
724     }
725
726     /* CtConstructor overrides this method.
727      */

728     int getStartPosOfBody(CodeAttribute ca) throws CannotCompileException {
729         return 0;
730     }
731
732     /**
733      * Inserts bytecode at the specified line in the body.
734      * It is equivalent to:
735      *
736      * <br><code>insertAt(lineNum, true, src)</code>
737      *
738      * <br>See this method as well.
739      *
740      * @param lineNum the line number. The bytecode is inserted at the
741      * beginning of the code at the line specified by this
742      * line number.
743      * @param src the source code representing the inserted bytecode.
744      * It must be a single statement or block.
745      * @return the line number at which the bytecode has been inserted.
746      *
747      * @see CtBehavior#insertAt(int,boolean,String)
748      */

749     public int insertAt(int lineNum, String JavaDoc src)
750         throws CannotCompileException
751     {
752         return insertAt(lineNum, true, src);
753     }
754
755     /**
756      * Inserts bytecode at the specified line in the body.
757      *
758      * <p>If there is not
759      * a statement at the specified line, the bytecode might be inserted
760      * at the line including the first statement after that line specified.
761      * For example, if there is only a closing brace at that line, the
762      * bytecode would be inserted at another line below.
763      * To know exactly where the bytecode will be inserted, call with
764      * <code>modify</code> set to <code>false</code>.
765      *
766      * @param lineNum the line number. The bytecode is inserted at the
767      * beginning of the code at the line specified by this
768      * line number.
769      * @param modify if false, this method does not insert the bytecode.
770      * It instead only returns the line number at which
771      * the bytecode would be inserted.
772      * @param src the source code representing the inserted bytecode.
773      * It must be a single statement or block.
774      * If modify is false, the value of src can be null.
775      * @return the line number at which the bytecode has been inserted.
776      */

777     public int insertAt(int lineNum, boolean modify, String JavaDoc src)
778         throws CannotCompileException
779     {
780         CodeAttribute ca = methodInfo.getCodeAttribute();
781         if (ca == null)
782             throw new CannotCompileException("no method body");
783
784         LineNumberAttribute ainfo
785             = (LineNumberAttribute)ca.getAttribute(LineNumberAttribute.tag);
786         if (ainfo == null)
787             throw new CannotCompileException("no line number info");
788
789         LineNumberAttribute.Pc pc = ainfo.toNearPc(lineNum);
790         lineNum = pc.line;
791         int index = pc.index;
792         if (!modify)
793             return lineNum;
794
795         declaringClass.checkModify();
796         CodeIterator iterator = ca.iterator();
797         Javac jv = new Javac(declaringClass);
798         try {
799             jv.recordLocalVariables(ca, index);
800             jv.recordParams(getParameterTypes(),
801                             Modifier.isStatic(getModifiers()));
802             jv.compileStmnt(src);
803             Bytecode b = jv.getBytecode();
804             int stack = b.getMaxStack();
805             int locals = b.getMaxLocals();
806
807             /* We assume that there is no values in the operand stack
808              * at the position where the bytecode is inserted.
809              */

810             if (stack > ca.getMaxStack())
811                 ca.setMaxStack(stack);
812
813             if (locals > ca.getMaxLocals())
814                 ca.setMaxLocals(locals);
815
816             iterator.insert(index, b.get());
817             iterator.insert(b.getExceptionTable(), index);
818             return lineNum;
819         }
820         catch (NotFoundException e) {
821             throw new CannotCompileException(e);
822         }
823         catch (CompileError e) {
824             throw new CannotCompileException(e);
825         }
826         catch (BadBytecode e) {
827             throw new CannotCompileException(e);
828         }
829     }
830 }
831
Popular Tags