All Downloads are FREE. Search and download functionalities are using the official Maven repository.

xapi.bytecode.CtBehavior Maven / Gradle / Ivy

Go to download

Everything needed to run a comprehensive dev environment. Just type X_ and pick a service from autocomplete; new dev modules will be added as they are built. The only dev service not included in the uber jar is xapi-dev-maven, as it includes all runtime dependencies of maven, adding ~4 seconds to build time, and 6 megabytes to the final output jar size (without xapi-dev-maven, it's ~1MB).

The newest version!
/*
 * Javassist, a Java-bytecode translator toolkit.
 * Copyright (C) 1999- Shigeru Chiba. All Rights Reserved.
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License.  Alternatively, the contents of this file may be used under
 * the terms of the GNU Lesser General Public License Version 2.1 or later,
 * or the Apache License Version 2.0.
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * MODIFIED BY James Nelson of We The Internet, 2013.
 * Repackaged to avoid conflicts with different versions of Javassist,
 * and modified Javassist APIs to make them more accessible to outside code.
 */
package xapi.bytecode;

import xapi.bytecode.annotation.AnnotationsAttribute;
import xapi.bytecode.attributes.AttributeInfo;
import xapi.bytecode.attributes.CodeAttribute;
import xapi.bytecode.attributes.ExceptionTable;
import xapi.bytecode.attributes.ExceptionsAttribute;
import xapi.bytecode.attributes.LocalVariableAttribute;
import xapi.bytecode.attributes.ParameterAnnotationsAttribute;
import xapi.bytecode.attributes.StackMap;
import xapi.bytecode.attributes.StackMapTable;
import xapi.source.X_Modifier;

public abstract class CtBehavior extends CtMember {
    protected MethodInfo methodInfo;

    protected CtBehavior(CtClass clazz, MethodInfo minfo) {
        super(clazz);
        methodInfo = minfo;
    }

    /**
     * @param isCons        true if this is a constructor.
     */
    void copy(CtBehavior src, boolean isCons, ClassMap map)
        throws CannotCompileException
    {
        CtClass declaring = declaringClass;
        MethodInfo srcInfo = src.methodInfo;
        CtClass srcClass = src.getDeclaringClass();
        ConstPool cp = declaring.getClassFile2().getConstPool();

        map = new ClassMap(map);
        map.put(srcClass.getName(), declaring.getName());
        try {
            boolean patch = false;
            CtClass srcSuper = srcClass.getSuperclass();
            CtClass destSuper = declaring.getSuperclass();
            String destSuperName = null;
            if (srcSuper != null && destSuper != null) {
                String srcSuperName = srcSuper.getName();
                destSuperName = destSuper.getName();
                if (!srcSuperName.equals(destSuperName)) {
                  if (srcSuperName.equals(CtClass.javaLangObject)) {
                    patch = true;
                  } else {
                    map.putIfNone(srcSuperName, destSuperName);
                  }
                }
            }

            // a stack map table is copied from srcInfo.
            methodInfo = new MethodInfo(cp, srcInfo.getName(), srcInfo, map);
            if (isCons && patch) {
              methodInfo.setSuperclass(destSuperName);
            }
        }
        catch (NotFoundException e) {
            throw new CannotCompileException(e);
        }
        catch (BadBytecode e) {
            throw new CannotCompileException(e);
        }
    }

    @Override
    protected void extendToString(StringBuffer buffer) {
        buffer.append(' ');
        buffer.append(getName());
        buffer.append(' ');
        buffer.append(methodInfo.getDescriptor());
    }

    /**
     * Returns the method or constructor name followed by parameter types
     * such as javassist.CtBehavior.stBody(String).
     *
     * @since 3.5
     */
    public abstract String getLongName();

    /**
     * Returns the MethodInfo representing this method/constructor in the
     * class file.
     */
    public MethodInfo getMethodInfo() {
        declaringClass.checkModify();
        return methodInfo;
    }

    /**
     * Returns the MethodInfo representing the method/constructor in the
     * class file (read only).
     * Normal applications do not need calling this method.  Use
     * getMethodInfo().
     *
     * 

The MethodInfo object obtained by this method * is read only. Changes to this object might not be reflected * on a class file generated by toBytecode(), * toClass(), etc in CtClass. * *

This method is available even if the CtClass * containing this method is frozen. However, if the class is * frozen, the MethodInfo might be also pruned. * * @see #getMethodInfo() * @see CtClass#isFrozen() * @see CtClass#prune() */ public MethodInfo getMethodInfo2() { return methodInfo; } /** * Obtains the modifiers of the method/constructor. * * @return modifiers encoded with * javassist.Modifier. * @see Modifier */ @Override public int getModifiers() { return methodInfo.getAccessFlags(); } /** * Sets the encoded modifiers of the method/constructor. * *

Changing the modifiers may cause a problem. * For example, if a non-static method is changed to static, * the method will be rejected by the bytecode verifier. * * @see Modifier */ @Override public void setModifiers(int mod) { declaringClass.checkModify(); methodInfo.setAccessFlags(mod); } /** * Returns true if the class has the specified annotation class. * * @param clz the annotation class. * @return true if the annotation is found, * otherwise false. * @since 3.11 */ @Override public boolean hasAnnotation(Class clz) { MethodInfo mi = getMethodInfo2(); AnnotationsAttribute ainfo = (AnnotationsAttribute) mi.getAttribute(AnnotationsAttribute.invisibleTag); AnnotationsAttribute ainfo2 = (AnnotationsAttribute) mi.getAttribute(AnnotationsAttribute.visibleTag); return CtClassType.hasAnnotationType(clz, getDeclaringClass().getClassPool(), ainfo, ainfo2); } /** * Returns the annotation if the class has the specified annotation class. * For example, if an annotation @Author is associated * with this method/constructor, an Author object is returned. * The member values can be obtained by calling methods on * the Author object. * * @param clz the annotation class. * @return the annotation if found, otherwise null. * @since 3.11 */ @Override public Object getAnnotation(Class clz) throws ClassNotFoundException { MethodInfo mi = getMethodInfo2(); AnnotationsAttribute ainfo = (AnnotationsAttribute) mi.getAttribute(AnnotationsAttribute.invisibleTag); AnnotationsAttribute ainfo2 = (AnnotationsAttribute) mi.getAttribute(AnnotationsAttribute.visibleTag); return CtClassType.getAnnotationType(clz, getDeclaringClass().getClassPool(), ainfo, ainfo2); } /** * Returns the annotations associated with this method or constructor. * * @return an array of annotation-type objects. * @see #getAvailableAnnotations() * @since 3.1 */ @Override public Object[] getAnnotations() throws ClassNotFoundException { return getAnnotations(false); } /** * Returns the annotations associated with this method or constructor. * If any annotations are not on the classpath, they are not included * in the returned array. * * @return an array of annotation-type objects. * @see #getAnnotations() * @since 3.3 */ @Override public Object[] getAvailableAnnotations(){ try{ return getAnnotations(true); } catch (ClassNotFoundException e){ throw new RuntimeException("Unexpected exception", e); } } private Object[] getAnnotations(boolean ignoreNotFound) throws ClassNotFoundException { MethodInfo mi = getMethodInfo2(); AnnotationsAttribute ainfo = (AnnotationsAttribute) mi.getAttribute(AnnotationsAttribute.invisibleTag); AnnotationsAttribute ainfo2 = (AnnotationsAttribute) mi.getAttribute(AnnotationsAttribute.visibleTag); return CtClassType.toAnnotationType(ignoreNotFound, getDeclaringClass().getClassPool(), ainfo, ainfo2); } /** * Returns the parameter annotations associated with this method or constructor. * * @return an array of annotation-type objects. The length of the returned array is * equal to the number of the formal parameters. If each parameter has no * annotation, the elements of the returned array are empty arrays. * * @see #getAvailableParameterAnnotations() * @see #getAnnotations() * @since 3.1 */ public Object[][] getParameterAnnotations() throws ClassNotFoundException { return getParameterAnnotations(false); } /** * Returns the parameter annotations associated with this method or constructor. * If any annotations are not on the classpath, they are not included in the * returned array. * * @return an array of annotation-type objects. The length of the returned array is * equal to the number of the formal parameters. If each parameter has no * annotation, the elements of the returned array are empty arrays. * * @see #getParameterAnnotations() * @see #getAvailableAnnotations() * @since 3.3 */ public Object[][] getAvailableParameterAnnotations(){ try { return getParameterAnnotations(true); } catch(ClassNotFoundException e) { throw new RuntimeException("Unexpected exception", e); } } Object[][] getParameterAnnotations(boolean ignoreNotFound) throws ClassNotFoundException { MethodInfo mi = getMethodInfo2(); ParameterAnnotationsAttribute ainfo = (ParameterAnnotationsAttribute) mi.getAttribute(ParameterAnnotationsAttribute.invisibleTag); ParameterAnnotationsAttribute ainfo2 = (ParameterAnnotationsAttribute) mi.getAttribute(ParameterAnnotationsAttribute.visibleTag); return CtClassType.toAnnotationType(ignoreNotFound, getDeclaringClass().getClassPool(), ainfo, ainfo2, mi); } /** * Obtains parameter types of this method/constructor. */ public CtClass[] getParameterTypes() throws NotFoundException { return Descriptor.getParameterTypes(methodInfo.getDescriptor(), declaringClass.getClassPool()); } /** * Obtains the type of the returned value. */ CtClass getReturnType0() throws NotFoundException { return Descriptor.getReturnType(methodInfo.getDescriptor(), declaringClass.getClassPool()); } /** * Returns the method signature (the parameter types * and the return type). * The method signature is represented by a character string * called method descriptor, which is defined in the JVM specification. * If two methods/constructors have * the same parameter types * and the return type, getSignature() returns the * same string (the return type of constructors is void). * *

Note that the returned string is not the type signature * contained in the SignatureAttirbute. It is * a descriptor. To obtain a type signature, call the following * methods: * *

    getMethodInfo().getAttribute(SignatureAttribute.tag)
         * 
* * @see javassist.bytecode.Descriptor * @see javassist.bytecode.SignatureAttribute */ @Override public String getSignature() { return methodInfo.getDescriptor(); } /** * Obtains exceptions that this method/constructor may throw. * * @return a zero-length array if there is no throws clause. */ public CtClass[] getExceptionTypes() throws NotFoundException { String[] exceptions; ExceptionsAttribute ea = methodInfo.getExceptionsAttribute(); if (ea == null) { exceptions = null; } else { exceptions = ea.getExceptions(); } return declaringClass.getClassPool().get(exceptions); } /** * Sets exceptions that this method/constructor may throw. * @throws NotFoundException */ public void setExceptionTypes(CtClass[] types) throws NotFoundException { declaringClass.checkModify(); if (types == null || types.length == 0) { methodInfo.removeExceptionsAttribute(); return; } String[] names = new String[types.length]; for (int i = 0; i < types.length; ++i) { names[i] = types[i].getName(); } ExceptionsAttribute ea = methodInfo.getExceptionsAttribute(); if (ea == null) { ea = new ExceptionsAttribute(methodInfo.getConstPool()); methodInfo.setExceptionsAttribute(ea); } ea.setExceptions(names); } /** * Returns true if the body is empty. */ public abstract boolean isEmpty(); // /** // * Sets a method/constructor body. // * // * @param src the source code representing the body. // * It must be a single statement or block. // * If it is null, the substituted // * body does nothing except returning zero or null. // */ // public void setBody(String src) throws CannotCompileException { // setBody(src, null, null); // } // // /** // * Sets a method/constructor body. // * // * @param src the source code representing the body. // * It must be a single statement or block. // * If it is null, the substituted // * body does nothing except returning zero or null. // * @param delegateObj the source text specifying the object // * that is called on by $proceed(). // * @param delegateMethod the name of the method // * that is called by $proceed(). // */ // public void setBody(String src, // String delegateObj, String delegateMethod) // throws CannotCompileException // { // CtClass cc = declaringClass; // cc.checkModify(); // try { // Javac jv = new Javac(cc); // if (delegateMethod != null) // jv.recordProceed(delegateObj, delegateMethod); // // Bytecode b = jv.compileBody(this, src); // methodInfo.setCodeAttribute(b.toCodeAttribute()); // methodInfo.setAccessFlags(methodInfo.getAccessFlags() // & ~AccessFlag.ABSTRACT); // methodInfo.rebuildStackMapIf6(cc.getClassPool(), cc.getClassFile2()); // declaringClass.rebuildClassFile(); // } // catch (CompileError e) { // throw new CannotCompileException(e); // } catch (BadBytecode e) { // throw new CannotCompileException(e); // } // } static void setBody0(CtClass srcClass, MethodInfo srcInfo, CtClass destClass, MethodInfo destInfo, ClassMap map) throws CannotCompileException { destClass.checkModify(); map = new ClassMap(map); map.put(srcClass.getName(), destClass.getName()); try { CodeAttribute cattr = srcInfo.getCodeAttribute(); if (cattr != null) { ConstPool cp = destInfo.getConstPool(); CodeAttribute ca = (CodeAttribute)cattr.copy(cp, map); destInfo.setCodeAttribute(ca); // a stack map table is copied to destInfo. } } catch (CodeAttribute.RuntimeCopyException e) { /* the exception may be thrown by copy() in CodeAttribute. */ throw new CannotCompileException(e); } destInfo.setAccessFlags(destInfo.getAccessFlags() & ~X_Modifier.ABSTRACT); destClass.rebuildClassFile(); } /** * Obtains an attribute with the given name. * If that attribute is not found in the class file, this * method returns null. * *

Note that an attribute is a data block specified by * the class file format. It is not an annotation. * See {@link javassist.bytecode.AttributeInfo}. * * @param name attribute name */ @Override public byte[] getAttribute(String name) { AttributeInfo ai = methodInfo.getAttribute(name); if (ai == null) { return null; } else { return ai.get(); } } /** * Adds an attribute. The attribute is saved in the class file. * *

Note that an attribute is a data block specified by * the class file format. It is not an annotation. * See {@link javassist.bytecode.AttributeInfo}. * * @param name attribute name * @param data attribute value */ @Override public void setAttribute(String name, byte[] data) { declaringClass.checkModify(); switch (name) { case CodeAttribute.tag: methodInfo.addAttribute(new CodeAttribute(methodInfo.getConstPool(), 0, 0, data, new ExceptionTable(methodInfo.getConstPool()))); break; default: methodInfo.addAttribute(new AttributeInfo(methodInfo.getConstPool(), name, data)); } } // /** // * Declares to use $cflow for this method/constructor. // * If $cflow is used, the class files modified // * with Javassist requires a support class // * javassist.runtime.Cflow at runtime // * (other Javassist classes are not required at runtime). // * // *

Every $cflow variable is given a unique name. // * For example, if the given name is "Point.paint", // * then the variable is indicated by $cflow(Point.paint). // * // * @param name $cflow name. It can include // * alphabets, numbers, _, // * $, and . (dot). // * // * @see javassist.runtime.Cflow // */ // public void useCflow(String name) throws CannotCompileException { // CtClass cc = declaringClass; // cc.checkModify(); // ClassPool pool = cc.getClassPool(); // String fname; // int i = 0; // while (true) { // fname = "_cflow$" + i++; // try { // cc.getDeclaredField(fname); // } // catch(NotFoundException e) { // break; // } // } // // pool.recordCflow(name, declaringClass.getName(), fname); // try { // CtClass type = pool.get("javassist.runtime.Cflow"); // CtField field = new CtField(type, fname, cc); // field.setModifiers(Modifier.PUBLIC | Modifier.STATIC); // cc.addField(field, CtField.Initializer.byNew(type)); // insertBefore(fname + ".enter();", false); // String src = fname + ".exit();"; // insertAfter(src, true); // } // catch (NotFoundException e) { // throw new CannotCompileException(e); // } // } /** * Declares a new local variable. The scope of this variable is the * whole method body. The initial value of that variable is not set. * The declared variable can be accessed in the code snippet inserted * by insertBefore(), insertAfter(), etc. * *

If the second parameter asFinally to * insertAfter() is true, the declared local variable * is not visible from the code inserted by insertAfter(). * * @param name the name of the variable * @param type the type of the variable * @see #insertBefore(String) * @see #insertAfter(String) */ public void addLocalVariable(String name, CtClass type) throws CannotCompileException { declaringClass.checkModify(); ConstPool cp = methodInfo.getConstPool(); CodeAttribute ca = methodInfo.getCodeAttribute(); if (ca == null) { throw new CannotCompileException("no method body"); } LocalVariableAttribute va = (LocalVariableAttribute)ca.getAttribute( LocalVariableAttribute.tag); if (va == null) { va = new LocalVariableAttribute(cp); ca.getAttributes().add(va); } int maxLocals = ca.getMaxLocals(); String desc = Descriptor.of(type); va.addEntry(0, ca.getCodeLength(), cp.addUtf8Info(name), cp.addUtf8Info(desc), maxLocals); ca.setMaxLocals(maxLocals + Descriptor.dataSize(desc)); } /** * Inserts a new parameter, which becomes the first parameter. */ public void insertParameter(CtClass type) throws CannotCompileException { declaringClass.checkModify(); String desc = methodInfo.getDescriptor(); String desc2 = Descriptor.insertParameter(type, desc); try { addParameter2(X_Modifier.isStatic(getModifiers()) ? 0 : 1, type, desc); } catch (BadBytecode e) { throw new CannotCompileException(e); } methodInfo.setDescriptor(desc2); } /** * Appends a new parameter, which becomes the last parameter. */ public void addParameter(CtClass type) throws CannotCompileException { declaringClass.checkModify(); String desc = methodInfo.getDescriptor(); String desc2 = Descriptor.appendParameter(type, desc); int offset = X_Modifier.isStatic(getModifiers()) ? 0 : 1; try { addParameter2(offset + Descriptor.paramSize(desc), type, desc); } catch (BadBytecode e) { throw new CannotCompileException(e); } methodInfo.setDescriptor(desc2); } private void addParameter2(int where, CtClass type, String desc) throws BadBytecode { CodeAttribute ca = methodInfo.getCodeAttribute(); if (ca != null) { int size = 1; char typeDesc = 'L'; int classInfo = 0; if (type.isPrimitive()) { CtPrimitiveType cpt = (CtPrimitiveType)type; size = cpt.getDataSize(); typeDesc = cpt.getDescriptor(); } else { classInfo = methodInfo.getConstPool().addClassInfo(type); } ca.insertLocalVar(where, size); LocalVariableAttribute va = (LocalVariableAttribute) ca.getAttribute(LocalVariableAttribute.tag); if (va != null) { va.shiftIndex(where, size); } StackMapTable smt = (StackMapTable)ca.getAttribute(StackMapTable.tag); if (smt != null) { smt.insertLocal(where, StackMapTable.typeTagOf(typeDesc), classInfo); } StackMap sm = (StackMap)ca.getAttribute(StackMap.tag); if (sm != null) { sm.insertLocal(where, StackMapTable.typeTagOf(typeDesc), classInfo); } } } // /** // * Modifies the method/constructor body. // * // * @param converter specifies how to modify. // */ // public void instrument(CodeConverter converter) // throws CannotCompileException // { // declaringClass.checkModify(); // ConstPool cp = methodInfo.getConstPool(); // converter.doit(getDeclaringClass(), methodInfo, cp); // } // // /** // * Modifies the method/constructor body. // * // * @param editor specifies how to modify. // */ // public void instrument(ExprEditor editor) // throws CannotCompileException // { // // if the class is not frozen, // // does not turn the modified flag on. // if (declaringClass.isFrozen()) // declaringClass.checkModify(); // // if (editor.doit(declaringClass, methodInfo)) // declaringClass.checkModify(); // } // /** // * Inserts bytecode at the beginning of the body. // * // *

If this object represents a constructor, // * the bytecode is inserted before // * a constructor in the super class or this class is called. // * Therefore, the inserted bytecode is subject to constraints described // * in Section 4.8.2 of The Java Virtual Machine Specification (2nd ed). // * For example, it cannot access instance fields or methods although // * it may assign a value to an instance field directly declared in this // * class. Accessing static fields and methods is allowed. // * Use insertBeforeBody() in CtConstructor. // * // * @param src the source code representing the inserted bytecode. // * It must be a single statement or block. // * @see CtConstructor#insertBeforeBody(String) // */ // public void insertBefore(String src) throws CannotCompileException { // insertBefore(src, true); // } // // private void insertBefore(String src, boolean rebuild) // throws CannotCompileException // { // CtClass cc = declaringClass; // cc.checkModify(); // CodeAttribute ca = methodInfo.getCodeAttribute(); // if (ca == null) // throw new CannotCompileException("no method body"); // // CodeIterator iterator = ca.iterator(); // Javac jv = new Javac(cc); // try { // int nvars = jv.recordParams(getParameterTypes(), // Modifier.isStatic(getModifiers())); // jv.recordParamNames(ca, nvars); // jv.recordLocalVariables(ca, 0); // jv.recordType(getReturnType0()); // jv.compileStmnt(src); // Bytecode b = jv.getBytecode(); // int stack = b.getMaxStack(); // int locals = b.getMaxLocals(); // // if (stack > ca.getMaxStack()) // ca.setMaxStack(stack); // // if (locals > ca.getMaxLocals()) // ca.setMaxLocals(locals); // // int pos = iterator.insertEx(b.get()); // iterator.insert(b.getExceptionTable(), pos); // if (rebuild) // methodInfo.rebuildStackMapIf6(cc.getClassPool(), cc.getClassFile2()); // } // catch (NotFoundException e) { // throw new CannotCompileException(e); // } // catch (CompileError e) { // throw new CannotCompileException(e); // } // catch (BadBytecode e) { // throw new CannotCompileException(e); // } // } // // /** // * Inserts bytecode at the end of the body. // * The bytecode is inserted just before every return insturction. // * It is not executed when an exception is thrown. // * // * @param src the source code representing the inserted bytecode. // * It must be a single statement or block. // */ // public void insertAfter(String src) // throws CannotCompileException // { // insertAfter(src, false); // } // // /** // * Inserts bytecode at the end of the body. // * The bytecode is inserted just before every return insturction. // * // * @param src the source code representing the inserted bytecode. // * It must be a single statement or block. // * @param asFinally true if the inserted bytecode is executed // * not only when the control normally returns // * but also when an exception is thrown. // * If this parameter is true, the inserted code cannot // * access local variables. // */ // public void insertAfter(String src, boolean asFinally) // throws CannotCompileException // { // CtClass cc = declaringClass; // cc.checkModify(); // ConstPool pool = methodInfo.getConstPool(); // CodeAttribute ca = methodInfo.getCodeAttribute(); // if (ca == null) // throw new CannotCompileException("no method body"); // // CodeIterator iterator = ca.iterator(); // int retAddr = ca.getMaxLocals(); // Bytecode b = new Bytecode(pool, 0, retAddr + 1); // b.setStackDepth(ca.getMaxStack() + 1); // Javac jv = new Javac(b, cc); // try { // int nvars = jv.recordParams(getParameterTypes(), // Modifier.isStatic(getModifiers())); // jv.recordParamNames(ca, nvars); // CtClass rtype = getReturnType0(); // int varNo = jv.recordReturnType(rtype, true); // jv.recordLocalVariables(ca, 0); // // // finally clause for exceptions // int handlerLen = insertAfterHandler(asFinally, b, rtype, varNo, // jv, src); // // finally clause for normal termination // insertAfterAdvice(b, jv, src, pool, rtype, varNo); // // ca.setMaxStack(b.getMaxStack()); // ca.setMaxLocals(b.getMaxLocals()); // // int gapPos = iterator.append(b.get()); // iterator.append(b.getExceptionTable(), gapPos); // // if (asFinally) // ca.getExceptionTable().add(getStartPosOfBody(ca), gapPos, gapPos, 0); // // int gapLen = iterator.getCodeLength() - gapPos - handlerLen; // int subr = iterator.getCodeLength() - gapLen; // // while (iterator.hasNext()) { // int pos = iterator.next(); // if (pos >= subr) // break; // // int c = iterator.byteAt(pos); // if (c == Opcode.ARETURN || c == Opcode.IRETURN // || c == Opcode.FRETURN || c == Opcode.LRETURN // || c == Opcode.DRETURN || c == Opcode.RETURN) { // insertGoto(iterator, subr, pos); // subr = iterator.getCodeLength() - gapLen; // } // } // // methodInfo.rebuildStackMapIf6(cc.getClassPool(), cc.getClassFile2()); // } // catch (NotFoundException e) { // throw new CannotCompileException(e); // } // catch (CompileError e) { // throw new CannotCompileException(e); // } // catch (BadBytecode e) { // throw new CannotCompileException(e); // } // } // // private void insertAfterAdvice(Bytecode code, Javac jv, String src, // ConstPool cp, CtClass rtype, int varNo) // throws CompileError // { // if (rtype == CtClass.voidType) { // code.addOpcode(Opcode.ACONST_NULL); // code.addAstore(varNo); // jv.compileStmnt(src); // code.addOpcode(Opcode.RETURN); // if (code.getMaxLocals() < 1) // code.setMaxLocals(1); // } // else { // code.addStore(varNo, rtype); // jv.compileStmnt(src); // code.addLoad(varNo, rtype); // if (rtype.isPrimitive()) // code.addOpcode(((CtPrimitiveType)rtype).getReturnOp()); // else // code.addOpcode(Opcode.ARETURN); // } // } // // /* // * assert subr > pos // */ // private void insertGoto(CodeIterator iterator, int subr, int pos) // throws BadBytecode // { // iterator.setMark(subr); // // the gap length might be a multiple of 4. // iterator.writeByte(Opcode.NOP, pos); // boolean wide = subr + 2 - pos > Short.MAX_VALUE; // pos = iterator.insertGapAt(pos, wide ? 4 : 2, false).position; // int offset = iterator.getMark() - pos; // if (wide) { // iterator.writeByte(Opcode.GOTO_W, pos); // iterator.write32bit(offset, pos + 1); // } // else if (offset <= Short.MAX_VALUE) { // iterator.writeByte(Opcode.GOTO, pos); // iterator.write16bit(offset, pos + 1); // } // else { // pos = iterator.insertGapAt(pos, 2, false).position; // iterator.writeByte(Opcode.GOTO_W, pos); // iterator.write32bit(iterator.getMark() - pos, pos + 1); // } // } // // /* insert a finally clause // */ // private int insertAfterHandler(boolean asFinally, Bytecode b, // CtClass rtype, int returnVarNo, // Javac javac, String src) // throws CompileError // { // if (!asFinally) // return 0; // // int var = b.getMaxLocals(); // b.incMaxLocals(1); // int pc = b.currentPc(); // b.addAstore(var); // store an exception // if (rtype.isPrimitive()) { // char c = ((CtPrimitiveType)rtype).getDescriptor(); // if (c == 'D') { // b.addDconst(0.0); // b.addDstore(returnVarNo); // } // else if (c == 'F') { // b.addFconst(0); // b.addFstore(returnVarNo); // } // else if (c == 'J') { // b.addLconst(0); // b.addLstore(returnVarNo); // } // else if (c == 'V') { // b.addOpcode(Opcode.ACONST_NULL); // b.addAstore(returnVarNo); // } // else { // int, boolean, char, short, ... // b.addIconst(0); // b.addIstore(returnVarNo); // } // } // else { // b.addOpcode(Opcode.ACONST_NULL); // b.addAstore(returnVarNo); // } // // javac.compileStmnt(src); // b.addAload(var); // b.addOpcode(Opcode.ATHROW); // return b.currentPc() - pc; // } // // /** // * Adds a catch clause that handles an exception thrown in the // * body. The catch clause must end with a return or throw statement. // * // * @param src the source code representing the catch clause. // * It must be a single statement or block. // * @param exceptionType the type of the exception handled by the // * catch clause. // */ // public void addCatch(String src, CtClass exceptionType) // throws CannotCompileException // { // addCatch(src, exceptionType, "$e"); // } // // /** // * Adds a catch clause that handles an exception thrown in the // * body. The catch clause must end with a return or throw statement. // * // * @param src the source code representing the catch clause. // * It must be a single statement or block. // * @param exceptionType the type of the exception handled by the // * catch clause. // * @param exceptionName the name of the variable containing the // * caught exception, for example, // * $e. // */ // public void addCatch(String src, CtClass exceptionType, // String exceptionName) // throws CannotCompileException // { // CtClass cc = declaringClass; // cc.checkModify(); // ConstPool cp = methodInfo.getConstPool(); // CodeAttribute ca = methodInfo.getCodeAttribute(); // CodeIterator iterator = ca.iterator(); // Bytecode b = new Bytecode(cp, ca.getMaxStack(), ca.getMaxLocals()); // b.setStackDepth(1); // Javac jv = new Javac(b, cc); // try { // jv.recordParams(getParameterTypes(), // Modifier.isStatic(getModifiers())); // int var = jv.recordVariable(exceptionType, exceptionName); // b.addAstore(var); // jv.compileStmnt(src); // // int stack = b.getMaxStack(); // int locals = b.getMaxLocals(); // // if (stack > ca.getMaxStack()) // ca.setMaxStack(stack); // // if (locals > ca.getMaxLocals()) // ca.setMaxLocals(locals); // // int len = iterator.getCodeLength(); // int pos = iterator.append(b.get()); // ca.getExceptionTable().add(getStartPosOfBody(ca), len, len, // cp.addClassInfo(exceptionType)); // iterator.append(b.getExceptionTable(), pos); // methodInfo.rebuildStackMapIf6(cc.getClassPool(), cc.getClassFile2()); // } // catch (NotFoundException e) { // throw new CannotCompileException(e); // } // catch (CompileError e) { // throw new CannotCompileException(e); // } catch (BadBytecode e) { // throw new CannotCompileException(e); // } // } /* CtConstructor overrides this method. */ /** * @throws CannotCompileException */ int getStartPosOfBody(CodeAttribute ca) throws CannotCompileException { return 0; } // /** // * Inserts bytecode at the specified line in the body. // * It is equivalent to: // * // *
insertAt(lineNum, true, src) // * // *
See this method as well. // * // * @param lineNum the line number. The bytecode is inserted at the // * beginning of the code at the line specified by this // * line number. // * @param src the source code representing the inserted bytecode. // * It must be a single statement or block. // * @return the line number at which the bytecode has been inserted. // * // * @see CtBehavior#insertAt(int,boolean,String) // */ // public int insertAt(int lineNum, String src) // throws CannotCompileException // { // return insertAt(lineNum, true, src); // } // // /** // * Inserts bytecode at the specified line in the body. // * // *

If there is not // * a statement at the specified line, the bytecode might be inserted // * at the line including the first statement after that line specified. // * For example, if there is only a closing brace at that line, the // * bytecode would be inserted at another line below. // * To know exactly where the bytecode will be inserted, call with // * modify set to false. // * // * @param lineNum the line number. The bytecode is inserted at the // * beginning of the code at the line specified by this // * line number. // * @param modify if false, this method does not insert the bytecode. // * It instead only returns the line number at which // * the bytecode would be inserted. // * @param src the source code representing the inserted bytecode. // * It must be a single statement or block. // * If modify is false, the value of src can be null. // * @return the line number at which the bytecode has been inserted. // */ // public int insertAt(int lineNum, boolean modify, String src) // throws CannotCompileException // { // CodeAttribute ca = methodInfo.getCodeAttribute(); // if (ca == null) // throw new CannotCompileException("no method body"); // // LineNumberAttribute ainfo // = (LineNumberAttribute)ca.getAttribute(LineNumberAttribute.tag); // if (ainfo == null) // throw new CannotCompileException("no line number info"); // // LineNumberAttribute.Pc pc = ainfo.toNearPc(lineNum); // lineNum = pc.line; // int index = pc.index; // if (!modify) // return lineNum; // // CtClass cc = declaringClass; // cc.checkModify(); // CodeIterator iterator = ca.iterator(); // Javac jv = new Javac(cc); // try { // jv.recordLocalVariables(ca, index); // jv.recordParams(getParameterTypes(), // Modifier.isStatic(getModifiers())); // jv.setMaxLocals(ca.getMaxLocals()); // jv.compileStmnt(src); // Bytecode b = jv.getBytecode(); // int locals = b.getMaxLocals(); // int stack = b.getMaxStack(); // ca.setMaxLocals(locals); // // /* We assume that there is no values in the operand stack // * at the position where the bytecode is inserted. // */ // if (stack > ca.getMaxStack()) // ca.setMaxStack(stack); // // index = iterator.insertAt(index, b.get()); // iterator.insert(b.getExceptionTable(), index); // methodInfo.rebuildStackMapIf6(cc.getClassPool(), cc.getClassFile2()); // return lineNum; // } // catch (NotFoundException e) { // throw new CannotCompileException(e); // } // catch (CompileError e) { // throw new CannotCompileException(e); // } // catch (BadBytecode e) { // throw new CannotCompileException(e); // } // } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy