You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
199 lines
9.1 KiB
199 lines
9.1 KiB
/* |
|
* 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. |
|
*/ |
|
|
|
package com.fr.third.javassist; |
|
|
|
import com.fr.third.javassist.bytecode.SyntheticAttribute; |
|
import com.fr.third.javassist.compiler.JvstCodeGen; |
|
import java.util.Hashtable; |
|
import com.fr.third.javassist.CtMethod.ConstParameter; |
|
|
|
class CtNewWrappedMethod { |
|
|
|
private static final String addedWrappedMethod = "_added_m$"; |
|
|
|
public static com.fr.third.javassist.CtMethod wrapped(com.fr.third.javassist.CtClass returnType, String mname, |
|
com.fr.third.javassist.CtClass[] parameterTypes, |
|
com.fr.third.javassist.CtClass[] exceptionTypes, |
|
com.fr.third.javassist.CtMethod body, ConstParameter constParam, |
|
com.fr.third.javassist.CtClass declaring) |
|
throws com.fr.third.javassist.CannotCompileException |
|
{ |
|
com.fr.third.javassist.CtMethod mt = new com.fr.third.javassist.CtMethod(returnType, mname, parameterTypes, |
|
declaring); |
|
mt.setModifiers(body.getModifiers()); |
|
try { |
|
mt.setExceptionTypes(exceptionTypes); |
|
} |
|
catch (NotFoundException e) { |
|
throw new com.fr.third.javassist.CannotCompileException(e); |
|
} |
|
|
|
com.fr.third.javassist.bytecode.Bytecode code = makeBody(declaring, declaring.getClassFile2(), body, |
|
parameterTypes, returnType, constParam); |
|
com.fr.third.javassist.bytecode.MethodInfo minfo = mt.getMethodInfo2(); |
|
minfo.setCodeAttribute(code.toCodeAttribute()); |
|
// a stack map has been already created. |
|
return mt; |
|
} |
|
|
|
static com.fr.third.javassist.bytecode.Bytecode makeBody(com.fr.third.javassist.CtClass clazz, com.fr.third.javassist.bytecode.ClassFile classfile, |
|
com.fr.third.javassist.CtMethod wrappedBody, |
|
com.fr.third.javassist.CtClass[] parameters, |
|
com.fr.third.javassist.CtClass returnType, |
|
ConstParameter cparam) |
|
throws com.fr.third.javassist.CannotCompileException |
|
{ |
|
boolean isStatic = Modifier.isStatic(wrappedBody.getModifiers()); |
|
com.fr.third.javassist.bytecode.Bytecode code = new com.fr.third.javassist.bytecode.Bytecode(classfile.getConstPool(), 0, 0); |
|
int stacksize = makeBody0(clazz, classfile, wrappedBody, isStatic, |
|
parameters, returnType, cparam, code); |
|
code.setMaxStack(stacksize); |
|
code.setMaxLocals(isStatic, parameters, 0); |
|
return code; |
|
} |
|
|
|
/* The generated method body does not need a stack map table |
|
* because it does not contain a branch instruction. |
|
*/ |
|
protected static int makeBody0(com.fr.third.javassist.CtClass clazz, com.fr.third.javassist.bytecode.ClassFile classfile, |
|
com.fr.third.javassist.CtMethod wrappedBody, |
|
boolean isStatic, com.fr.third.javassist.CtClass[] parameters, |
|
com.fr.third.javassist.CtClass returnType, ConstParameter cparam, |
|
com.fr.third.javassist.bytecode.Bytecode code) |
|
throws com.fr.third.javassist.CannotCompileException |
|
{ |
|
if (!(clazz instanceof com.fr.third.javassist.CtClassType)) |
|
throw new com.fr.third.javassist.CannotCompileException("bad declaring class" |
|
+ clazz.getName()); |
|
|
|
if (!isStatic) |
|
code.addAload(0); |
|
|
|
int stacksize = compileParameterList(code, parameters, |
|
(isStatic ? 0 : 1)); |
|
int stacksize2; |
|
String desc; |
|
if (cparam == null) { |
|
stacksize2 = 0; |
|
desc = ConstParameter.defaultDescriptor(); |
|
} |
|
else { |
|
stacksize2 = cparam.compile(code); |
|
desc = cparam.descriptor(); |
|
} |
|
|
|
checkSignature(wrappedBody, desc); |
|
|
|
String bodyname; |
|
try { |
|
bodyname = addBodyMethod((com.fr.third.javassist.CtClassType)clazz, classfile, |
|
wrappedBody); |
|
/* if an exception is thrown below, the method added above |
|
* should be removed. (future work :<) |
|
*/ |
|
} |
|
catch (com.fr.third.javassist.bytecode.BadBytecode e) { |
|
throw new com.fr.third.javassist.CannotCompileException(e); |
|
} |
|
|
|
if (isStatic) |
|
code.addInvokestatic(com.fr.third.javassist.bytecode.Bytecode.THIS, bodyname, desc); |
|
else |
|
code.addInvokespecial(com.fr.third.javassist.bytecode.Bytecode.THIS, bodyname, desc); |
|
|
|
compileReturn(code, returnType); // consumes 2 stack entries |
|
|
|
if (stacksize < stacksize2 + 2) |
|
stacksize = stacksize2 + 2; |
|
|
|
return stacksize; |
|
} |
|
|
|
private static void checkSignature(com.fr.third.javassist.CtMethod wrappedBody, |
|
String descriptor) |
|
throws com.fr.third.javassist.CannotCompileException |
|
{ |
|
if (!descriptor.equals(wrappedBody.getMethodInfo2().getDescriptor())) |
|
throw new com.fr.third.javassist.CannotCompileException( |
|
"wrapped method with a bad signature: " |
|
+ wrappedBody.getDeclaringClass().getName() |
|
+ '.' + wrappedBody.getName()); |
|
} |
|
|
|
private static String addBodyMethod(com.fr.third.javassist.CtClassType clazz, |
|
com.fr.third.javassist.bytecode.ClassFile classfile, |
|
com.fr.third.javassist.CtMethod src) |
|
throws com.fr.third.javassist.bytecode.BadBytecode, CannotCompileException |
|
{ |
|
Hashtable bodies = clazz.getHiddenMethods(); |
|
String bodyname = (String)bodies.get(src); |
|
if (bodyname == null) { |
|
do { |
|
bodyname = addedWrappedMethod + clazz.getUniqueNumber(); |
|
} while (classfile.getMethod(bodyname) != null); |
|
com.fr.third.javassist.ClassMap map = new ClassMap(); |
|
map.put(src.getDeclaringClass().getName(), clazz.getName()); |
|
com.fr.third.javassist.bytecode.MethodInfo body = new com.fr.third.javassist.bytecode.MethodInfo(classfile.getConstPool(), |
|
bodyname, src.getMethodInfo2(), |
|
map); |
|
int acc = body.getAccessFlags(); |
|
body.setAccessFlags(com.fr.third.javassist.bytecode.AccessFlag.setPrivate(acc)); |
|
body.addAttribute(new SyntheticAttribute(classfile.getConstPool())); |
|
// a stack map is copied. rebuilding it is not needed. |
|
classfile.addMethod(body); |
|
bodies.put(src, bodyname); |
|
CtMember.Cache cache = clazz.hasMemberCache(); |
|
if (cache != null) |
|
cache.addMethod(new CtMethod(body, clazz)); |
|
} |
|
|
|
return bodyname; |
|
} |
|
|
|
/* compileParameterList() returns the stack size used |
|
* by the produced code. |
|
* |
|
* @param regno the index of the local variable in which |
|
* the first argument is received. |
|
* (0: static method, 1: regular method.) |
|
*/ |
|
static int compileParameterList(com.fr.third.javassist.bytecode.Bytecode code, |
|
com.fr.third.javassist.CtClass[] params, int regno) { |
|
return JvstCodeGen.compileParameterList(code, params, regno); |
|
} |
|
|
|
/* |
|
* The produced codes cosume 1 or 2 stack entries. |
|
*/ |
|
private static void compileReturn(com.fr.third.javassist.bytecode.Bytecode code, com.fr.third.javassist.CtClass type) { |
|
if (type.isPrimitive()) { |
|
CtPrimitiveType pt = (CtPrimitiveType)type; |
|
if (pt != CtClass.voidType) { |
|
String wrapper = pt.getWrapperName(); |
|
code.addCheckcast(wrapper); |
|
code.addInvokevirtual(wrapper, pt.getGetMethodName(), |
|
pt.getGetMethodDescriptor()); |
|
} |
|
|
|
code.addOpcode(pt.getReturnOp()); |
|
} |
|
else { |
|
code.addCheckcast(type); |
|
code.addOpcode(com.fr.third.javassist.bytecode.Bytecode.ARETURN); |
|
} |
|
} |
|
}
|
|
|