
com.feilong.lib.javassist.CtNewWrappedMethod Maven / Gradle / Ivy
/*
* 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.feilong.lib.javassist;
import java.util.Map;
import com.feilong.lib.javassist.CtMethod.ConstParameter;
import com.feilong.lib.javassist.bytecode.AccessFlag;
import com.feilong.lib.javassist.bytecode.BadBytecode;
import com.feilong.lib.javassist.bytecode.Bytecode;
import com.feilong.lib.javassist.bytecode.ClassFile;
import com.feilong.lib.javassist.bytecode.MethodInfo;
import com.feilong.lib.javassist.bytecode.Opcode;
import com.feilong.lib.javassist.bytecode.SyntheticAttribute;
import com.feilong.lib.javassist.compiler.JvstCodeGen;
class CtNewWrappedMethod{
private static final String addedWrappedMethod = "_added_m$";
public static CtMethod wrapped(
CtClass returnType,
String mname,
CtClass[] parameterTypes,
CtClass[] exceptionTypes,
CtMethod body,
ConstParameter constParam,
CtClass declaring) throws CannotCompileException{
CtMethod mt = new CtMethod(returnType, mname, parameterTypes, declaring);
mt.setModifiers(body.getModifiers());
try{
mt.setExceptionTypes(exceptionTypes);
}catch (NotFoundException e){
throw new CannotCompileException(e);
}
Bytecode code = makeBody(declaring, declaring.getClassFile2(), body, parameterTypes, returnType, constParam);
MethodInfo minfo = mt.getMethodInfo2();
minfo.setCodeAttribute(code.toCodeAttribute());
// a stack map has been already created.
return mt;
}
static Bytecode makeBody(
CtClass clazz,
ClassFile classfile,
CtMethod wrappedBody,
CtClass[] parameters,
CtClass returnType,
ConstParameter cparam) throws CannotCompileException{
boolean isStatic = Modifier.isStatic(wrappedBody.getModifiers());
Bytecode code = new 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(
CtClass clazz,
ClassFile classfile,
CtMethod wrappedBody,
boolean isStatic,
CtClass[] parameters,
CtClass returnType,
ConstParameter cparam,
Bytecode code) throws CannotCompileException{
if (!(clazz instanceof CtClassType)){
throw new 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((CtClassType) clazz, classfile, wrappedBody);
/*
* if an exception is thrown below, the method added above
* should be removed. (future work :<)
*/
}catch (BadBytecode e){
throw new CannotCompileException(e);
}
if (isStatic){
code.addInvokestatic(Bytecode.THIS, bodyname, desc);
}else{
code.addInvokespecial(Bytecode.THIS, bodyname, desc);
}
compileReturn(code, returnType); // consumes 2 stack entries
if (stacksize < stacksize2 + 2){
stacksize = stacksize2 + 2;
}
return stacksize;
}
private static void checkSignature(CtMethod wrappedBody,String descriptor) throws CannotCompileException{
if (!descriptor.equals(wrappedBody.getMethodInfo2().getDescriptor())){
throw new CannotCompileException(
"wrapped method with a bad signature: " + wrappedBody.getDeclaringClass().getName() + '.'
+ wrappedBody.getName());
}
}
private static String addBodyMethod(CtClassType clazz,ClassFile classfile,CtMethod src) throws BadBytecode,CannotCompileException{
Map bodies = clazz.getHiddenMethods();
String bodyname = bodies.get(src);
if (bodyname == null){
do{
bodyname = addedWrappedMethod + clazz.getUniqueNumber();
}while (classfile.getMethod(bodyname) != null);
ClassMap map = new ClassMap();
map.put(src.getDeclaringClass().getName(), clazz.getName());
MethodInfo body = new MethodInfo(classfile.getConstPool(), bodyname, src.getMethodInfo2(), map);
int acc = body.getAccessFlags();
body.setAccessFlags(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(Bytecode code,CtClass[] params,int regno){
return JvstCodeGen.compileParameterList(code, params, regno);
}
/*
* The produced codes cosume 1 or 2 stack entries.
*/
private static void compileReturn(Bytecode code,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(Opcode.ARETURN);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy