xapi.bytecode.CtBehavior Maven / Gradle / Ivy
Show all versions of xapi-gwt Show documentation
/*
* 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);
// }
// }
}