帆软使用的第三方框架。
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

/*
* 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);
}
}
}