001: /*
002: * Javassist, a Java-bytecode translator toolkit.
003: * Copyright (C) 1999-2006 Shigeru Chiba. All Rights Reserved.
004: *
005: * The contents of this file are subject to the Mozilla Public License Version
006: * 1.1 (the "License"); you may not use this file except in compliance with
007: * the License. Alternatively, the contents of this file may be used under
008: * the terms of the GNU Lesser General Public License Version 2.1 or later.
009: *
010: * Software distributed under the License is distributed on an "AS IS" basis,
011: * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
012: * for the specific language governing rights and limitations under the
013: * License.
014: */
015:
016: package javassist;
017:
018: import javassist.bytecode.*;
019: import javassist.compiler.JvstCodeGen;
020: import java.util.Hashtable;
021: import javassist.CtMethod.ConstParameter;
022:
023: class CtNewWrappedMethod {
024:
025: private static final String addedWrappedMethod = "_added_m$";
026:
027: public static CtMethod wrapped(CtClass returnType, String mname,
028: CtClass[] parameterTypes, CtClass[] exceptionTypes,
029: CtMethod body, ConstParameter constParam, CtClass declaring)
030: throws CannotCompileException {
031: CtMethod mt = new CtMethod(returnType, mname, parameterTypes,
032: declaring);
033: mt.setModifiers(body.getModifiers());
034: try {
035: mt.setExceptionTypes(exceptionTypes);
036: } catch (NotFoundException e) {
037: throw new CannotCompileException(e);
038: }
039:
040: Bytecode code = makeBody(declaring, declaring.getClassFile2(),
041: body, parameterTypes, returnType, constParam);
042: mt.getMethodInfo2().setCodeAttribute(code.toCodeAttribute());
043: return mt;
044: }
045:
046: static Bytecode makeBody(CtClass clazz, ClassFile classfile,
047: CtMethod wrappedBody, CtClass[] parameters,
048: CtClass returnType, ConstParameter cparam)
049: throws CannotCompileException {
050: boolean isStatic = Modifier
051: .isStatic(wrappedBody.getModifiers());
052: Bytecode code = new Bytecode(classfile.getConstPool(), 0, 0);
053: int stacksize = makeBody0(clazz, classfile, wrappedBody,
054: isStatic, parameters, returnType, cparam, code);
055: code.setMaxStack(stacksize);
056: code.setMaxLocals(isStatic, parameters, 0);
057: return code;
058: }
059:
060: protected static int makeBody0(CtClass clazz, ClassFile classfile,
061: CtMethod wrappedBody, boolean isStatic,
062: CtClass[] parameters, CtClass returnType,
063: ConstParameter cparam, Bytecode code)
064: throws CannotCompileException {
065: if (!(clazz instanceof CtClassType))
066: throw new CannotCompileException("bad declaring class"
067: + clazz.getName());
068:
069: if (!isStatic)
070: code.addAload(0);
071:
072: int stacksize = compileParameterList(code, parameters,
073: (isStatic ? 0 : 1));
074: int stacksize2;
075: String desc;
076: if (cparam == null) {
077: stacksize2 = 0;
078: desc = ConstParameter.defaultDescriptor();
079: } else {
080: stacksize2 = cparam.compile(code);
081: desc = cparam.descriptor();
082: }
083:
084: checkSignature(wrappedBody, desc);
085:
086: String bodyname;
087: try {
088: bodyname = addBodyMethod((CtClassType) clazz, classfile,
089: wrappedBody);
090: /* if an exception is thrown below, the method added above
091: * should be removed. (future work :<)
092: */
093: } catch (BadBytecode e) {
094: throw new CannotCompileException(e);
095: }
096:
097: if (isStatic)
098: code.addInvokestatic(Bytecode.THIS, bodyname, desc);
099: else
100: code.addInvokespecial(Bytecode.THIS, bodyname, desc);
101:
102: compileReturn(code, returnType); // consumes 2 stack entries
103:
104: if (stacksize < stacksize2 + 2)
105: stacksize = stacksize2 + 2;
106:
107: return stacksize;
108: }
109:
110: private static void checkSignature(CtMethod wrappedBody,
111: String descriptor) throws CannotCompileException {
112: if (!descriptor.equals(wrappedBody.getMethodInfo2()
113: .getDescriptor()))
114: throw new CannotCompileException(
115: "wrapped method with a bad signature: "
116: + wrappedBody.getDeclaringClass().getName()
117: + '.' + wrappedBody.getName());
118: }
119:
120: private static String addBodyMethod(CtClassType clazz,
121: ClassFile classfile, CtMethod src) throws BadBytecode,
122: CannotCompileException {
123: Hashtable bodies = clazz.getHiddenMethods();
124: String bodyname = (String) bodies.get(src);
125: if (bodyname == null) {
126: do {
127: bodyname = addedWrappedMethod + clazz.getUniqueNumber();
128: } while (classfile.getMethod(bodyname) != null);
129: ClassMap map = new ClassMap();
130: map.put(src.getDeclaringClass().getName(), clazz.getName());
131: MethodInfo body = new MethodInfo(classfile.getConstPool(),
132: bodyname, src.getMethodInfo2(), map);
133: int acc = body.getAccessFlags();
134: body.setAccessFlags(AccessFlag.setPrivate(acc));
135: classfile.addMethod(body);
136: bodies.put(src, bodyname);
137: }
138:
139: return bodyname;
140: }
141:
142: /* compileParameterList() returns the stack size used
143: * by the produced code.
144: *
145: * @param regno the index of the local variable in which
146: * the first argument is received.
147: * (0: static method, 1: regular method.)
148: */
149: static int compileParameterList(Bytecode code, CtClass[] params,
150: int regno) {
151: return JvstCodeGen.compileParameterList(code, params, regno);
152: }
153:
154: /*
155: * The produced codes cosume 1 or 2 stack entries.
156: */
157: private static void compileReturn(Bytecode code, CtClass type) {
158: if (type.isPrimitive()) {
159: CtPrimitiveType pt = (CtPrimitiveType) type;
160: if (pt != CtClass.voidType) {
161: String wrapper = pt.getWrapperName();
162: code.addCheckcast(wrapper);
163: code.addInvokevirtual(wrapper, pt.getGetMethodName(),
164: pt.getGetMethodDescriptor());
165: }
166:
167: code.addOpcode(pt.getReturnOp());
168: } else {
169: code.addCheckcast(type);
170: code.addOpcode(Bytecode.ARETURN);
171: }
172: }
173: }
|