Source Code Cross Referenced for CtBehavior.java in  » Byte-Code » Javassist » javassist » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Byte Code » Javassist » javassist 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         * Javassist, a Java-bytecode translator toolkit.
003:         * Copyright (C) 1999-2006 Shigeru Chiba. All Rights Reserved.
004:         *
005:         * The contents of this file are subject to the Mozilla Public License Version
006:         * 1.1 (the "License"); you may not use this file except in compliance with
007:         * the License.  Alternatively, the contents of this file may be used under
008:         * the terms of the GNU Lesser General Public License Version 2.1 or later.
009:         *
010:         * Software distributed under the License is distributed on an "AS IS" basis,
011:         * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
012:         * for the specific language governing rights and limitations under the
013:         * License.
014:         */
015:
016:        package javassist;
017:
018:        import javassist.bytecode.*;
019:        import javassist.compiler.Javac;
020:        import javassist.compiler.CompileError;
021:        import javassist.expr.ExprEditor;
022:
023:        /**
024:         * <code>CtBehavior</code> represents a method, a constructor,
025:         * or a static constructor (class initializer). 
026:         * It is the abstract super class of
027:         * <code>CtMethod</code> and <code>CtConstructor</code>.
028:         */
029:        public abstract class CtBehavior extends CtMember {
030:            protected MethodInfo methodInfo;
031:
032:            protected CtBehavior(CtClass clazz, MethodInfo minfo) {
033:                super (clazz);
034:                methodInfo = minfo;
035:            }
036:
037:            /**
038:             * @param isCons        true if this is a constructor.
039:             */
040:            void copy(CtBehavior src, boolean isCons, ClassMap map)
041:                    throws CannotCompileException {
042:                CtClass declaring = declaringClass;
043:                MethodInfo srcInfo = src.methodInfo;
044:                CtClass srcClass = src.getDeclaringClass();
045:                ConstPool cp = declaring.getClassFile2().getConstPool();
046:
047:                map = new ClassMap(map);
048:                map.put(srcClass.getName(), declaring.getName());
049:                try {
050:                    boolean patch = false;
051:                    CtClass srcSuper = srcClass.getSuperclass();
052:                    CtClass destSuper = declaring.getSuperclass();
053:                    String destSuperName = null;
054:                    if (srcSuper != null && destSuper != null) {
055:                        String srcSuperName = srcSuper.getName();
056:                        destSuperName = destSuper.getName();
057:                        if (!srcSuperName.equals(destSuperName))
058:                            if (srcSuperName.equals(CtClass.javaLangObject))
059:                                patch = true;
060:                            else
061:                                map.put(srcSuperName, destSuperName);
062:                    }
063:
064:                    methodInfo = new MethodInfo(cp, srcInfo.getName(), srcInfo,
065:                            map);
066:                    if (isCons && patch)
067:                        methodInfo.setSuperclass(destSuperName);
068:                } catch (NotFoundException e) {
069:                    throw new CannotCompileException(e);
070:                } catch (BadBytecode e) {
071:                    throw new CannotCompileException(e);
072:                }
073:            }
074:
075:            protected void extendToString(StringBuffer buffer) {
076:                buffer.append(' ');
077:                buffer.append(getName());
078:                buffer.append(' ');
079:                buffer.append(methodInfo.getDescriptor());
080:            }
081:
082:            /**
083:             * Returns the MethodInfo representing this method/constructor in the
084:             * class file.
085:             */
086:            public MethodInfo getMethodInfo() {
087:                declaringClass.checkModify();
088:                return methodInfo;
089:            }
090:
091:            /**
092:             * Returns the MethodInfo representing the method/constructor in the
093:             * class file (read only).
094:             * Normal applications do not need calling this method.  Use
095:             * <code>getMethodInfo()</code>.
096:             *
097:             * <p>The <code>MethodInfo</code> object obtained by this method
098:             * is read only.  Changes to this object might not be reflected
099:             * on a class file generated by <code>toBytecode()</code>,
100:             * <code>toClass()</code>, etc in <code>CtClass</code>.
101:             *
102:             * <p>This method is available even if the <code>CtClass</code>
103:             * containing this method is frozen.  However, if the class is
104:             * frozen, the <code>MethodInfo</code> might be also pruned.
105:             *
106:             * @see #getMethodInfo()
107:             * @see CtClass#isFrozen()
108:             * @see CtClass#prune()
109:             */
110:            public MethodInfo getMethodInfo2() {
111:                return methodInfo;
112:            }
113:
114:            /**
115:             * Obtains the modifiers of the method/constructor.
116:             *
117:             * @return          modifiers encoded with
118:             *                  <code>javassist.Modifier</code>.
119:             * @see Modifier
120:             */
121:            public int getModifiers() {
122:                return AccessFlag.toModifier(methodInfo.getAccessFlags());
123:            }
124:
125:            /**
126:             * Sets the encoded modifiers of the method/constructor.
127:             *
128:             * <p>Changing the modifiers may cause a problem.
129:             * For example, if a non-static method is changed to static,
130:             * the method will be rejected by the bytecode verifier.
131:             *
132:             * @see Modifier
133:             */
134:            public void setModifiers(int mod) {
135:                declaringClass.checkModify();
136:                methodInfo.setAccessFlags(AccessFlag.of(mod));
137:            }
138:
139:            /**
140:             * Returns the annotations associated with this method or constructor.
141:             *
142:             * @return an array of annotation-type objects.
143:             * @see #getAvailableAnnotations()
144:             * @since 3.1
145:             */
146:            public Object[] getAnnotations() throws ClassNotFoundException {
147:                return getAnnotations(false);
148:            }
149:
150:            /**
151:             * Returns the annotations associated with this method or constructor.
152:             * If any annotations are not on the classpath, they are not included
153:             * in the returned array.
154:             * 
155:             * @return an array of annotation-type objects.
156:             * @see #getAnnotations()
157:             * @since 3.3
158:             */
159:            public Object[] getAvailableAnnotations() {
160:                try {
161:                    return getAnnotations(true);
162:                } catch (ClassNotFoundException e) {
163:                    throw new RuntimeException("Unexpected exception", e);
164:                }
165:            }
166:
167:            private Object[] getAnnotations(boolean ignoreNotFound)
168:                    throws ClassNotFoundException {
169:                MethodInfo mi = getMethodInfo2();
170:                AnnotationsAttribute ainfo = (AnnotationsAttribute) mi
171:                        .getAttribute(AnnotationsAttribute.invisibleTag);
172:                AnnotationsAttribute ainfo2 = (AnnotationsAttribute) mi
173:                        .getAttribute(AnnotationsAttribute.visibleTag);
174:                return CtClassType.toAnnotationType(ignoreNotFound,
175:                        getDeclaringClass().getClassPool(), ainfo, ainfo2);
176:            }
177:
178:            /**
179:             * Returns the parameter annotations associated with this method or constructor.
180:             *
181:             * @return an array of annotation-type objects.  The length of the returned array is
182:             * equal to the number of the formal parameters.  If each parameter has no
183:             * annotation, the elements of the returned array are empty arrays.
184:             *
185:             * @see #getAvailableParameterAnnotations()
186:             * @see #getAnnotations()
187:             * @since 3.1
188:             */
189:            public Object[][] getParameterAnnotations()
190:                    throws ClassNotFoundException {
191:                return getParameterAnnotations(false);
192:            }
193:
194:            /**
195:             * Returns the parameter annotations associated with this method or constructor.
196:             * If any annotations are not on the classpath, they are not included in the
197:             * returned array.
198:             * 
199:             * @return an array of annotation-type objects.  The length of the returned array is
200:             * equal to the number of the formal parameters.  If each parameter has no
201:             * annotation, the elements of the returned array are empty arrays.
202:             *
203:             * @see #getParameterAnnotations()
204:             * @see #getAvailableAnnotations()
205:             * @since 3.3
206:             */
207:            public Object[][] getAvailableParameterAnnotations() {
208:                try {
209:                    return getParameterAnnotations(true);
210:                } catch (ClassNotFoundException e) {
211:                    throw new RuntimeException("Unexpected exception", e);
212:                }
213:            }
214:
215:            Object[][] getParameterAnnotations(boolean ignoreNotFound)
216:                    throws ClassNotFoundException {
217:                MethodInfo mi = getMethodInfo2();
218:                ParameterAnnotationsAttribute ainfo = (ParameterAnnotationsAttribute) mi
219:                        .getAttribute(ParameterAnnotationsAttribute.invisibleTag);
220:                ParameterAnnotationsAttribute ainfo2 = (ParameterAnnotationsAttribute) mi
221:                        .getAttribute(ParameterAnnotationsAttribute.visibleTag);
222:                return CtClassType.toAnnotationType(ignoreNotFound,
223:                        getDeclaringClass().getClassPool(), ainfo, ainfo2, mi);
224:            }
225:
226:            /**
227:             * Obtains parameter types of this method/constructor.
228:             */
229:            public CtClass[] getParameterTypes() throws NotFoundException {
230:                return Descriptor.getParameterTypes(methodInfo.getDescriptor(),
231:                        declaringClass.getClassPool());
232:            }
233:
234:            /**
235:             * Obtains the type of the returned value.
236:             */
237:            CtClass getReturnType0() throws NotFoundException {
238:                return Descriptor.getReturnType(methodInfo.getDescriptor(),
239:                        declaringClass.getClassPool());
240:            }
241:
242:            /**
243:             * Returns the method signature (the parameter types
244:             * and the return type).
245:             * The method signature is represented by a character string
246:             * called method descriptor, which is defined in the JVM specification.
247:             * If two methods/constructors have
248:             * the same parameter types
249:             * and the return type, <code>getSignature()</code> returns the
250:             * same string (the return type of constructors is <code>void</code>).
251:             *
252:             * @see javassist.bytecode.Descriptor
253:             */
254:            public String getSignature() {
255:                return methodInfo.getDescriptor();
256:            }
257:
258:            /**
259:             * Obtains exceptions that this method/constructor may throw.
260:             *
261:             * @return a zero-length array if there is no throws clause.
262:             */
263:            public CtClass[] getExceptionTypes() throws NotFoundException {
264:                String[] exceptions;
265:                ExceptionsAttribute ea = methodInfo.getExceptionsAttribute();
266:                if (ea == null)
267:                    exceptions = null;
268:                else
269:                    exceptions = ea.getExceptions();
270:
271:                return declaringClass.getClassPool().get(exceptions);
272:            }
273:
274:            /**
275:             * Sets exceptions that this method/constructor may throw.
276:             */
277:            public void setExceptionTypes(CtClass[] types)
278:                    throws NotFoundException {
279:                declaringClass.checkModify();
280:                if (types == null || types.length == 0) {
281:                    methodInfo.removeExceptionsAttribute();
282:                    return;
283:                }
284:
285:                String[] names = new String[types.length];
286:                for (int i = 0; i < types.length; ++i)
287:                    names[i] = types[i].getName();
288:
289:                ExceptionsAttribute ea = methodInfo.getExceptionsAttribute();
290:                if (ea == null) {
291:                    ea = new ExceptionsAttribute(methodInfo.getConstPool());
292:                    methodInfo.setExceptionsAttribute(ea);
293:                }
294:
295:                ea.setExceptions(names);
296:            }
297:
298:            /**
299:             * Returns true if the body is empty.
300:             */
301:            public abstract boolean isEmpty();
302:
303:            /**
304:             * Sets a method/constructor body.
305:             *
306:             * @param src       the source code representing the body.
307:             *                  It must be a single statement or block.
308:             *                  If it is <code>null</code>, the substituted
309:             *                  body does nothing except returning zero or null.
310:             */
311:            public void setBody(String src) throws CannotCompileException {
312:                setBody(src, null, null);
313:            }
314:
315:            /**
316:             * Sets a method/constructor body.
317:             *
318:             * @param src       the source code representing the body.
319:             *                  It must be a single statement or block.
320:             *                  If it is <code>null</code>, the substituted
321:             *                  body does nothing except returning zero or null.
322:             * @param delegateObj       the source text specifying the object
323:             *                          that is called on by <code>$proceed()</code>.
324:             * @param delegateMethod    the name of the method
325:             *                          that is called by <code>$proceed()</code>.
326:             */
327:            public void setBody(String src, String delegateObj,
328:                    String delegateMethod) throws CannotCompileException {
329:                declaringClass.checkModify();
330:                try {
331:                    Javac jv = new Javac(declaringClass);
332:                    if (delegateMethod != null)
333:                        jv.recordProceed(delegateObj, delegateMethod);
334:
335:                    Bytecode b = jv.compileBody(this , src);
336:                    methodInfo.setCodeAttribute(b.toCodeAttribute());
337:                    methodInfo.setAccessFlags(methodInfo.getAccessFlags()
338:                            & ~AccessFlag.ABSTRACT);
339:                } catch (CompileError e) {
340:                    throw new CannotCompileException(e);
341:                }
342:            }
343:
344:            static void setBody0(CtClass srcClass, MethodInfo srcInfo,
345:                    CtClass destClass, MethodInfo destInfo, ClassMap map)
346:                    throws CannotCompileException {
347:                destClass.checkModify();
348:
349:                map = new ClassMap(map);
350:                map.put(srcClass.getName(), destClass.getName());
351:                try {
352:                    CodeAttribute cattr = srcInfo.getCodeAttribute();
353:                    if (cattr != null) {
354:                        ConstPool cp = destInfo.getConstPool();
355:                        CodeAttribute ca = (CodeAttribute) cattr.copy(cp, map);
356:                        destInfo.setCodeAttribute(ca);
357:                    }
358:                } catch (CodeAttribute.RuntimeCopyException e) {
359:                    /* the exception may be thrown by copy() in CodeAttribute.
360:                     */
361:                    throw new CannotCompileException(e);
362:                }
363:
364:                destInfo.setAccessFlags(destInfo.getAccessFlags()
365:                        & ~AccessFlag.ABSTRACT);
366:            }
367:
368:            /**
369:             * Obtains an attribute with the given name.
370:             * If that attribute is not found in the class file, this
371:             * method returns null.
372:             *
373:             * <p>Note that an attribute is a data block specified by
374:             * the class file format.  It is not an annotation.
375:             * See {@link javassist.bytecode.AttributeInfo}.
376:             *
377:             * @param name              attribute name
378:             */
379:            public byte[] getAttribute(String name) {
380:                AttributeInfo ai = methodInfo.getAttribute(name);
381:                if (ai == null)
382:                    return null;
383:                else
384:                    return ai.get();
385:            }
386:
387:            /**
388:             * Adds an attribute. The attribute is saved in the class file.
389:             *
390:             * <p>Note that an attribute is a data block specified by
391:             * the class file format.  It is not an annotation.
392:             * See {@link javassist.bytecode.AttributeInfo}.
393:             *
394:             * @param name      attribute name
395:             * @param data      attribute value
396:             */
397:            public void setAttribute(String name, byte[] data) {
398:                declaringClass.checkModify();
399:                methodInfo.addAttribute(new AttributeInfo(methodInfo
400:                        .getConstPool(), name, data));
401:            }
402:
403:            /**
404:             * Declares to use <code>$cflow</code> for this method/constructor.
405:             * If <code>$cflow</code> is used, the class files modified
406:             * with Javassist requires a support class
407:             * <code>javassist.runtime.Cflow</code> at runtime
408:             * (other Javassist classes are not required at runtime).
409:             *
410:             * <p>Every <code>$cflow</code> variable is given a unique name.
411:             * For example, if the given name is <code>"Point.paint"</code>,
412:             * then the variable is indicated by <code>$cflow(Point.paint)</code>.
413:             *
414:             * @param name      <code>$cflow</code> name.  It can include
415:             *                  alphabets, numbers, <code>_</code>,
416:             *                  <code>$</code>, and <code>.</code> (dot).
417:             *
418:             * @see javassist.runtime.Cflow
419:             */
420:            public void useCflow(String name) throws CannotCompileException {
421:                CtClass cc = declaringClass;
422:                cc.checkModify();
423:                ClassPool pool = cc.getClassPool();
424:                String fname;
425:                int i = 0;
426:                while (true) {
427:                    fname = "_cflow$" + i++;
428:                    try {
429:                        cc.getDeclaredField(fname);
430:                    } catch (NotFoundException e) {
431:                        break;
432:                    }
433:                }
434:
435:                pool.recordCflow(name, declaringClass.getName(), fname);
436:                try {
437:                    CtClass type = pool.get("javassist.runtime.Cflow");
438:                    CtField field = new CtField(type, fname, cc);
439:                    field.setModifiers(Modifier.PUBLIC | Modifier.STATIC);
440:                    cc.addField(field, CtField.Initializer.byNew(type));
441:                    insertBefore(fname + ".enter();");
442:                    String src = fname + ".exit();";
443:                    insertAfter(src, true);
444:                } catch (NotFoundException e) {
445:                    throw new CannotCompileException(e);
446:                }
447:            }
448:
449:            /**
450:             * Declares a new local variable.  The scope of this variable is the
451:             * whole method body.  The initial value of that variable is not set.
452:             * The declared variable can be accessed in the code snippet inserted
453:             * by <code>insertBefore()</code>, <code>insertAfter()</code>, etc.
454:             *
455:             * <p>If the second parameter <code>asFinally</code> to
456:             * <code>insertAfter()</code> is true, the declared local variable
457:             * is not visible from the code inserted by <code>insertAfter()</code>.
458:             *
459:             * @param name      the name of the variable
460:             * @param type      the type of the variable
461:             * @see #insertBefore(String)
462:             * @see #insertAfter(String)
463:             */
464:            public void addLocalVariable(String name, CtClass type)
465:                    throws CannotCompileException {
466:                declaringClass.checkModify();
467:                ConstPool cp = methodInfo.getConstPool();
468:                CodeAttribute ca = methodInfo.getCodeAttribute();
469:                if (ca == null)
470:                    throw new CannotCompileException("no method body");
471:
472:                LocalVariableAttribute va = (LocalVariableAttribute) ca
473:                        .getAttribute(LocalVariableAttribute.tag);
474:                if (va == null) {
475:                    va = new LocalVariableAttribute(cp);
476:                    ca.getAttributes().add(va);
477:                }
478:
479:                int maxLocals = ca.getMaxLocals();
480:                String desc = Descriptor.of(type);
481:                va.addEntry(0, ca.getCodeLength(), cp.addUtf8Info(name), cp
482:                        .addUtf8Info(desc), maxLocals);
483:                ca.setMaxLocals(maxLocals + Descriptor.dataSize(desc));
484:            }
485:
486:            /**
487:             * Modifies the method/constructor body.
488:             *
489:             * @param converter         specifies how to modify.
490:             */
491:            public void instrument(CodeConverter converter)
492:                    throws CannotCompileException {
493:                declaringClass.checkModify();
494:                ConstPool cp = methodInfo.getConstPool();
495:                converter.doit(getDeclaringClass(), methodInfo, cp);
496:            }
497:
498:            /**
499:             * Modifies the method/constructor body.
500:             *
501:             * @param editor            specifies how to modify.
502:             */
503:            public void instrument(ExprEditor editor)
504:                    throws CannotCompileException {
505:                // if the class is not frozen,
506:                // does not turn the modified flag on.
507:                if (declaringClass.isFrozen())
508:                    declaringClass.checkModify();
509:
510:                if (editor.doit(declaringClass, methodInfo))
511:                    declaringClass.checkModify();
512:            }
513:
514:            /**
515:             * Inserts bytecode at the beginning of the body.
516:             *
517:             * <p>If this object represents a constructor,
518:             * the bytecode is inserted before
519:             * a constructor in the super class or this class is called.
520:             * Therefore, the inserted bytecode is subject to constraints described
521:             * in Section 4.8.2 of The Java Virtual Machine Specification (2nd ed).
522:             * For example, it cannot access instance fields or methods although
523:             * it may assign a value to an instance field directly declared in this
524:             * class.  Accessing static fields and methods is allowed.
525:             * Use <code>insertBeforeBody()</code> in <code>CtConstructor</code>.
526:             *
527:             * @param src       the source code representing the inserted bytecode.
528:             *                  It must be a single statement or block.
529:             * @see CtConstructor#insertBeforeBody(String)
530:             */
531:            public void insertBefore(String src) throws CannotCompileException {
532:                declaringClass.checkModify();
533:                CodeAttribute ca = methodInfo.getCodeAttribute();
534:                if (ca == null)
535:                    throw new CannotCompileException("no method body");
536:
537:                CodeIterator iterator = ca.iterator();
538:                Javac jv = new Javac(declaringClass);
539:                try {
540:                    int nvars = jv.recordParams(getParameterTypes(), Modifier
541:                            .isStatic(getModifiers()));
542:                    jv.recordParamNames(ca, nvars);
543:                    jv.recordLocalVariables(ca, 0);
544:                    jv.compileStmnt(src);
545:                    Bytecode b = jv.getBytecode();
546:                    int stack = b.getMaxStack();
547:                    int locals = b.getMaxLocals();
548:
549:                    if (stack > ca.getMaxStack())
550:                        ca.setMaxStack(stack);
551:
552:                    if (locals > ca.getMaxLocals())
553:                        ca.setMaxLocals(locals);
554:
555:                    int pos = iterator.insertEx(b.get());
556:                    iterator.insert(b.getExceptionTable(), pos);
557:                } catch (NotFoundException e) {
558:                    throw new CannotCompileException(e);
559:                } catch (CompileError e) {
560:                    throw new CannotCompileException(e);
561:                } catch (BadBytecode e) {
562:                    throw new CannotCompileException(e);
563:                }
564:            }
565:
566:            /**
567:             * Inserts bytecode at the end of the body.
568:             * The bytecode is inserted just before every return insturction.
569:             * It is not executed when an exception is thrown.
570:             *
571:             * @param src       the source code representing the inserted bytecode.
572:             *                  It must be a single statement or block.
573:             */
574:            public void insertAfter(String src) throws CannotCompileException {
575:                insertAfter(src, false);
576:            }
577:
578:            /**
579:             * Inserts bytecode at the end of the body.
580:             * The bytecode is inserted just before every return insturction.
581:             *
582:             * @param src       the source code representing the inserted bytecode.
583:             *                  It must be a single statement or block.
584:             * @param asFinally         true if the inserted bytecode is executed
585:             *                  not only when the control normally returns
586:             *                  but also when an exception is thrown.
587:             *                  If this parameter is true, the inserted code cannot
588:             *                  access local variables.
589:             */
590:            public void insertAfter(String src, boolean asFinally)
591:                    throws CannotCompileException {
592:                declaringClass.checkModify();
593:                ConstPool pool = methodInfo.getConstPool();
594:                CodeAttribute ca = methodInfo.getCodeAttribute();
595:                if (ca == null)
596:                    throw new CannotCompileException("no method body");
597:
598:                CodeIterator iterator = ca.iterator();
599:                int retAddr = ca.getMaxLocals();
600:                Bytecode b = new Bytecode(pool, 0, retAddr + 1);
601:                b.setStackDepth(ca.getMaxStack() + 1);
602:                Javac jv = new Javac(b, declaringClass);
603:                try {
604:                    int nvars = jv.recordParams(getParameterTypes(), Modifier
605:                            .isStatic(getModifiers()));
606:                    jv.recordParamNames(ca, nvars);
607:                    CtClass rtype = getReturnType0();
608:                    int varNo = jv.recordReturnType(rtype, true);
609:                    jv.recordLocalVariables(ca, 0);
610:
611:                    int handlerLen = insertAfterHandler(asFinally, b, rtype,
612:                            varNo);
613:
614:                    byte[] save = makeSaveCode(pool, rtype, varNo);
615:                    byte[] restore = makeRestoreCode(b, pool, rtype, varNo);
616:
617:                    b.addAstore(retAddr);
618:                    jv.compileStmnt(src);
619:                    b.addRet(retAddr);
620:                    ca.setMaxStack(b.getMaxStack());
621:                    ca.setMaxLocals(b.getMaxLocals());
622:
623:                    int gapPos = iterator.append(b.get());
624:                    iterator.append(b.getExceptionTable(), gapPos);
625:
626:                    if (asFinally)
627:                        ca.getExceptionTable().add(0, gapPos, gapPos, 0);
628:
629:                    int gapLen = iterator.getCodeLength() - gapPos - handlerLen;
630:                    int subr = iterator.getCodeLength() - gapLen;
631:
632:                    while (iterator.hasNext()) {
633:                        int pos = iterator.next();
634:                        if (pos >= subr)
635:                            break;
636:
637:                        int c = iterator.byteAt(pos);
638:                        if (c == Opcode.ARETURN || c == Opcode.IRETURN
639:                                || c == Opcode.FRETURN || c == Opcode.LRETURN
640:                                || c == Opcode.DRETURN || c == Opcode.RETURN) {
641:                            insertJSR(iterator, subr, pos, save, restore);
642:                            subr = iterator.getCodeLength() - gapLen;
643:                        }
644:                    }
645:                } catch (NotFoundException e) {
646:                    throw new CannotCompileException(e);
647:                } catch (CompileError e) {
648:                    throw new CannotCompileException(e);
649:                } catch (BadBytecode e) {
650:                    throw new CannotCompileException(e);
651:                }
652:            }
653:
654:            private byte[] makeSaveCode(ConstPool cp, CtClass rtype, int varNo) {
655:                Bytecode b = new Bytecode(cp, 0, 0);
656:                if (rtype == CtClass.voidType) {
657:                    b.addOpcode(Opcode.ACONST_NULL);
658:                    b.addAstore(varNo);
659:                    return b.get();
660:                } else {
661:                    b.addStore(varNo, rtype);
662:                    return b.get();
663:                }
664:            }
665:
666:            private byte[] makeRestoreCode(Bytecode code, ConstPool cp,
667:                    CtClass rtype, int varNo) {
668:                if (rtype == CtClass.voidType) {
669:                    if (code.getMaxLocals() < 1)
670:                        code.setMaxLocals(1);
671:
672:                    return new byte[0];
673:                } else {
674:                    Bytecode b = new Bytecode(cp, 0, 0);
675:                    b.addLoad(varNo, rtype);
676:                    return b.get();
677:                }
678:            }
679:
680:            private void insertJSR(CodeIterator iterator, int subr, int pos,
681:                    byte[] save, byte[] restore) throws BadBytecode {
682:                int gapSize = 5 + save.length + restore.length;
683:                boolean wide = subr - pos > Short.MAX_VALUE - gapSize - 4;
684:                gapSize = iterator.insertGap(pos, wide ? gapSize : gapSize - 2);
685:
686:                iterator.write(save, pos);
687:                pos += save.length;
688:                if (wide) {
689:                    iterator.writeByte(Opcode.JSR_W, pos);
690:                    iterator.write32bit(subr - pos + gapSize, pos + 1);
691:                    pos += 5;
692:                } else {
693:                    iterator.writeByte(Opcode.JSR, pos);
694:                    iterator.write16bit(subr - pos + gapSize, pos + 1);
695:                    pos += 3;
696:                }
697:
698:                iterator.write(restore, pos);
699:            }
700:
701:            private int insertAfterHandler(boolean asFinally, Bytecode b,
702:                    CtClass rtype, int returnVarNo) {
703:                if (!asFinally)
704:                    return 0;
705:
706:                int var = b.getMaxLocals();
707:                b.incMaxLocals(1);
708:                int pc = b.currentPc();
709:                b.addAstore(var);
710:                if (rtype.isPrimitive()) {
711:                    char c = ((CtPrimitiveType) rtype).getDescriptor();
712:                    if (c == 'D') {
713:                        b.addDconst(0.0);
714:                        b.addDstore(returnVarNo);
715:                    } else if (c == 'F') {
716:                        b.addFconst(0);
717:                        b.addFstore(returnVarNo);
718:                    } else if (c == 'J') {
719:                        b.addLconst(0);
720:                        b.addLstore(returnVarNo);
721:                    } else if (c != 'V') { // int, boolean, char, short, ...
722:                        b.addIconst(0);
723:                        b.addIstore(returnVarNo);
724:                    }
725:                } else {
726:                    b.addOpcode(Opcode.ACONST_NULL);
727:                    b.addAstore(returnVarNo);
728:                }
729:
730:                b.addOpcode(Opcode.JSR);
731:                int pc2 = b.currentPc();
732:                b.addIndex(0); // correct later
733:                b.addAload(var);
734:                b.addOpcode(Opcode.ATHROW);
735:                int pc3 = b.currentPc();
736:                b.write16bit(pc2, pc3 - pc2 + 1);
737:                return pc3 - pc;
738:            }
739:
740:            /* -- OLD version --
741:
742:            public void insertAfter(String src) throws CannotCompileException {
743:                declaringClass.checkModify();
744:                CodeAttribute ca = methodInfo.getCodeAttribute();
745:                CodeIterator iterator = ca.iterator();
746:                Bytecode b = new Bytecode(methodInfo.getConstPool(),
747:                                          ca.getMaxStack(), ca.getMaxLocals());
748:                b.setStackDepth(ca.getMaxStack());
749:                Javac jv = new Javac(b, declaringClass);
750:                try {
751:                    jv.recordParams(getParameterTypes(),
752:                                    Modifier.isStatic(getModifiers()));
753:                    CtClass rtype = getReturnType0();
754:                    int varNo = jv.recordReturnType(rtype, true);
755:                    boolean isVoid = rtype == CtClass.voidType;
756:                    if (isVoid) {
757:                        b.addOpcode(Opcode.ACONST_NULL);
758:                        b.addAstore(varNo);
759:                        jv.compileStmnt(src);
760:                    }
761:                    else {
762:                        b.addStore(varNo, rtype);
763:                        jv.compileStmnt(src);
764:                        b.addLoad(varNo, rtype);
765:                    }
766:
767:                    byte[] code = b.get();
768:                    ca.setMaxStack(b.getMaxStack());
769:                    ca.setMaxLocals(b.getMaxLocals());
770:                    while (iterator.hasNext()) {
771:                        int pos = iterator.next();
772:                        int c = iterator.byteAt(pos);
773:                        if (c == Opcode.ARETURN || c == Opcode.IRETURN
774:                            || c == Opcode.FRETURN || c == Opcode.LRETURN
775:                            || c == Opcode.DRETURN || c == Opcode.RETURN)
776:                            iterator.insert(pos, code);
777:                    }
778:                }
779:                catch (NotFoundException e) {
780:                    throw new CannotCompileException(e);
781:                }
782:                catch (CompileError e) {
783:                    throw new CannotCompileException(e);
784:                }
785:                catch (BadBytecode e) {
786:                    throw new CannotCompileException(e);
787:                }
788:            }
789:             */
790:
791:            /**
792:             * Adds a catch clause that handles an exception thrown in the
793:             * body.  The catch clause must end with a return or throw statement.
794:             *
795:             * @param src       the source code representing the catch clause.
796:             *                  It must be a single statement or block.
797:             * @param exceptionType     the type of the exception handled by the
798:             *                          catch clause.
799:             */
800:            public void addCatch(String src, CtClass exceptionType)
801:                    throws CannotCompileException {
802:                addCatch(src, exceptionType, "$e");
803:            }
804:
805:            /**
806:             * Adds a catch clause that handles an exception thrown in the
807:             * body.  The catch clause must end with a return or throw statement.
808:             *
809:             * @param src       the source code representing the catch clause.
810:             *                  It must be a single statement or block.
811:             * @param exceptionType     the type of the exception handled by the
812:             *                          catch clause.
813:             * @param exceptionName     the name of the variable containing the
814:             *                          caught exception, for example,
815:             *                          <code>$e</code>.
816:             */
817:            public void addCatch(String src, CtClass exceptionType,
818:                    String exceptionName) throws CannotCompileException {
819:                declaringClass.checkModify();
820:                ConstPool cp = methodInfo.getConstPool();
821:                CodeAttribute ca = methodInfo.getCodeAttribute();
822:                CodeIterator iterator = ca.iterator();
823:                Bytecode b = new Bytecode(cp, ca.getMaxStack(), ca
824:                        .getMaxLocals());
825:                b.setStackDepth(1);
826:                Javac jv = new Javac(b, declaringClass);
827:                try {
828:                    jv.recordParams(getParameterTypes(), Modifier
829:                            .isStatic(getModifiers()));
830:                    int var = jv.recordVariable(exceptionType, exceptionName);
831:                    b.addAstore(var);
832:                    jv.compileStmnt(src);
833:
834:                    int stack = b.getMaxStack();
835:                    int locals = b.getMaxLocals();
836:
837:                    if (stack > ca.getMaxStack())
838:                        ca.setMaxStack(stack);
839:
840:                    if (locals > ca.getMaxLocals())
841:                        ca.setMaxLocals(locals);
842:
843:                    int len = iterator.getCodeLength();
844:                    int pos = iterator.append(b.get());
845:                    ca.getExceptionTable().add(getStartPosOfBody(ca), len, len,
846:                            cp.addClassInfo(exceptionType));
847:                    iterator.append(b.getExceptionTable(), pos);
848:                } catch (NotFoundException e) {
849:                    throw new CannotCompileException(e);
850:                } catch (CompileError e) {
851:                    throw new CannotCompileException(e);
852:                }
853:            }
854:
855:            /* CtConstructor overrides this method.
856:             */
857:            int getStartPosOfBody(CodeAttribute ca)
858:                    throws CannotCompileException {
859:                return 0;
860:            }
861:
862:            /**
863:             * Inserts bytecode at the specified line in the body.
864:             * It is equivalent to:
865:             *
866:             * <br><code>insertAt(lineNum, true, src)</code>
867:             *
868:             * <br>See this method as well.
869:             *
870:             * @param lineNum   the line number.  The bytecode is inserted at the
871:             *                  beginning of the code at the line specified by this
872:             *                  line number.
873:             * @param src       the source code representing the inserted bytecode.
874:             *                  It must be a single statement or block.
875:             * @return      the line number at which the bytecode has been inserted.
876:             *
877:             * @see CtBehavior#insertAt(int,boolean,String)
878:             */
879:            public int insertAt(int lineNum, String src)
880:                    throws CannotCompileException {
881:                return insertAt(lineNum, true, src);
882:            }
883:
884:            /**
885:             * Inserts bytecode at the specified line in the body.
886:             *
887:             * <p>If there is not
888:             * a statement at the specified line, the bytecode might be inserted
889:             * at the line including the first statement after that line specified.
890:             * For example, if there is only a closing brace at that line, the
891:             * bytecode would be inserted at another line below.
892:             * To know exactly where the bytecode will be inserted, call with
893:             * <code>modify</code> set to <code>false</code>. 
894:             *
895:             * @param lineNum   the line number.  The bytecode is inserted at the
896:             *                  beginning of the code at the line specified by this
897:             *                  line number.
898:             * @param modify    if false, this method does not insert the bytecode.
899:             *                  It instead only returns the line number at which
900:             *                  the bytecode would be inserted.
901:             * @param src       the source code representing the inserted bytecode.
902:             *                  It must be a single statement or block.
903:             *                  If modify is false, the value of src can be null.
904:             * @return      the line number at which the bytecode has been inserted.
905:             */
906:            public int insertAt(int lineNum, boolean modify, String src)
907:                    throws CannotCompileException {
908:                CodeAttribute ca = methodInfo.getCodeAttribute();
909:                if (ca == null)
910:                    throw new CannotCompileException("no method body");
911:
912:                LineNumberAttribute ainfo = (LineNumberAttribute) ca
913:                        .getAttribute(LineNumberAttribute.tag);
914:                if (ainfo == null)
915:                    throw new CannotCompileException("no line number info");
916:
917:                LineNumberAttribute.Pc pc = ainfo.toNearPc(lineNum);
918:                lineNum = pc.line;
919:                int index = pc.index;
920:                if (!modify)
921:                    return lineNum;
922:
923:                declaringClass.checkModify();
924:                CodeIterator iterator = ca.iterator();
925:                Javac jv = new Javac(declaringClass);
926:                try {
927:                    jv.recordLocalVariables(ca, index);
928:                    jv.recordParams(getParameterTypes(), Modifier
929:                            .isStatic(getModifiers()));
930:                    jv.setMaxLocals(ca.getMaxLocals());
931:                    jv.compileStmnt(src);
932:                    Bytecode b = jv.getBytecode();
933:                    int locals = b.getMaxLocals();
934:                    int stack = b.getMaxStack();
935:                    ca.setMaxLocals(locals);
936:
937:                    /* We assume that there is no values in the operand stack
938:                     * at the position where the bytecode is inserted.
939:                     */
940:                    if (stack > ca.getMaxStack())
941:                        ca.setMaxStack(stack);
942:
943:                    iterator.insert(index, b.get());
944:                    iterator.insert(b.getExceptionTable(), index);
945:                    return lineNum;
946:                } catch (NotFoundException e) {
947:                    throw new CannotCompileException(e);
948:                } catch (CompileError e) {
949:                    throw new CannotCompileException(e);
950:                } catch (BadBytecode e) {
951:                    throw new CannotCompileException(e);
952:                }
953:            }
954:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.