169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal/* 269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Javassist, a Java-bytecode translator toolkit. 369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Copyright (C) 1999-2007 Shigeru Chiba. All Rights Reserved. 469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * The contents of this file are subject to the Mozilla Public License Version 669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 1.1 (the "License"); you may not use this file except in compliance with 769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * the License. Alternatively, the contents of this file may be used under 869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * the terms of the GNU Lesser General Public License Version 2.1 or later. 969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 1069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Software distributed under the License is distributed on an "AS IS" basis, 1169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 1269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * for the specific language governing rights and limitations under the 1369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * License. 1469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */ 1569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 1669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalpackage javassist; 1769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 1869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport javassist.bytecode.*; 1969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport javassist.compiler.JvstCodeGen; 2069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport java.util.Hashtable; 2169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport javassist.CtMethod.ConstParameter; 2269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 2369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalclass CtNewWrappedMethod { 2469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 2569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal private static final String addedWrappedMethod = "_added_m$"; 2669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 2769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal public static CtMethod wrapped(CtClass returnType, String mname, 2869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal CtClass[] parameterTypes, 2969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal CtClass[] exceptionTypes, 3069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal CtMethod body, ConstParameter constParam, 3169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal CtClass declaring) 3269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal throws CannotCompileException 3369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal { 3469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal CtMethod mt = new CtMethod(returnType, mname, parameterTypes, 3569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal declaring); 3669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal mt.setModifiers(body.getModifiers()); 3769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal try { 3869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal mt.setExceptionTypes(exceptionTypes); 3969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 4069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal catch (NotFoundException e) { 4169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal throw new CannotCompileException(e); 4269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 4369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 4469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal Bytecode code = makeBody(declaring, declaring.getClassFile2(), body, 4569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal parameterTypes, returnType, constParam); 4669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal mt.getMethodInfo2().setCodeAttribute(code.toCodeAttribute()); 4769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return mt; 4869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 4969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 5069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal static Bytecode makeBody(CtClass clazz, ClassFile classfile, 5169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal CtMethod wrappedBody, 5269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal CtClass[] parameters, 5369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal CtClass returnType, 5469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal ConstParameter cparam) 5569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal throws CannotCompileException 5669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal { 5769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal boolean isStatic = Modifier.isStatic(wrappedBody.getModifiers()); 5869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal Bytecode code = new Bytecode(classfile.getConstPool(), 0, 0); 5969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal int stacksize = makeBody0(clazz, classfile, wrappedBody, isStatic, 6069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal parameters, returnType, cparam, code); 6169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal code.setMaxStack(stacksize); 6269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal code.setMaxLocals(isStatic, parameters, 0); 6369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return code; 6469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 6569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 6669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal /* The generated method body does not need a stack map table 6769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * because it does not contain a branch instruction. 6869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */ 6969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal protected static int makeBody0(CtClass clazz, ClassFile classfile, 7069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal CtMethod wrappedBody, 7169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal boolean isStatic, CtClass[] parameters, 7269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal CtClass returnType, ConstParameter cparam, 7369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal Bytecode code) 7469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal throws CannotCompileException 7569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal { 7669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal if (!(clazz instanceof CtClassType)) 7769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal throw new CannotCompileException("bad declaring class" 7869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal + clazz.getName()); 7969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 8069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal if (!isStatic) 8169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal code.addAload(0); 8269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 8369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal int stacksize = compileParameterList(code, parameters, 8469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal (isStatic ? 0 : 1)); 8569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal int stacksize2; 8669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal String desc; 8769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal if (cparam == null) { 8869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal stacksize2 = 0; 8969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal desc = ConstParameter.defaultDescriptor(); 9069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 9169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal else { 9269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal stacksize2 = cparam.compile(code); 9369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal desc = cparam.descriptor(); 9469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 9569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 9669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal checkSignature(wrappedBody, desc); 9769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 9869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal String bodyname; 9969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal try { 10069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal bodyname = addBodyMethod((CtClassType)clazz, classfile, 10169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal wrappedBody); 10269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal /* if an exception is thrown below, the method added above 10369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * should be removed. (future work :<) 10469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */ 10569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 10669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal catch (BadBytecode e) { 10769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal throw new CannotCompileException(e); 10869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 10969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 11069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal if (isStatic) 11169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal code.addInvokestatic(Bytecode.THIS, bodyname, desc); 11269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal else 11369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal code.addInvokespecial(Bytecode.THIS, bodyname, desc); 11469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 11569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal compileReturn(code, returnType); // consumes 2 stack entries 11669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 11769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal if (stacksize < stacksize2 + 2) 11869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal stacksize = stacksize2 + 2; 11969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 12069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return stacksize; 12169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 12269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 12369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal private static void checkSignature(CtMethod wrappedBody, 12469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal String descriptor) 12569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal throws CannotCompileException 12669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal { 12769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal if (!descriptor.equals(wrappedBody.getMethodInfo2().getDescriptor())) 12869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal throw new CannotCompileException( 12969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal "wrapped method with a bad signature: " 13069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal + wrappedBody.getDeclaringClass().getName() 13169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal + '.' + wrappedBody.getName()); 13269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 13369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 13469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal private static String addBodyMethod(CtClassType clazz, 13569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal ClassFile classfile, 13669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal CtMethod src) 13769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal throws BadBytecode, CannotCompileException 13869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal { 13969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal Hashtable bodies = clazz.getHiddenMethods(); 14069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal String bodyname = (String)bodies.get(src); 14169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal if (bodyname == null) { 14269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal do { 14369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal bodyname = addedWrappedMethod + clazz.getUniqueNumber(); 14469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } while (classfile.getMethod(bodyname) != null); 14569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal ClassMap map = new ClassMap(); 14669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal map.put(src.getDeclaringClass().getName(), clazz.getName()); 14769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal MethodInfo body = new MethodInfo(classfile.getConstPool(), 14869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal bodyname, src.getMethodInfo2(), 14969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal map); 15069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal int acc = body.getAccessFlags(); 15169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal body.setAccessFlags(AccessFlag.setPrivate(acc)); 15269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal body.addAttribute(new SyntheticAttribute(classfile.getConstPool())); 15369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal // a stack map is copied. rebuilding it is not needed. 15469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal classfile.addMethod(body); 15569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal bodies.put(src, bodyname); 15669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal CtMember.Cache cache = clazz.hasMemberCache(); 15769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal if (cache != null) 15869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal cache.addMethod(new CtMethod(body, clazz)); 15969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 16069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 16169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return bodyname; 16269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 16369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 16469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal /* compileParameterList() returns the stack size used 16569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * by the produced code. 16669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 16769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @param regno the index of the local variable in which 16869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * the first argument is received. 16969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * (0: static method, 1: regular method.) 17069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */ 17169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal static int compileParameterList(Bytecode code, 17269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal CtClass[] params, int regno) { 17369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return JvstCodeGen.compileParameterList(code, params, regno); 17469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 17569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 17669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal /* 17769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * The produced codes cosume 1 or 2 stack entries. 17869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */ 17969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal private static void compileReturn(Bytecode code, CtClass type) { 18069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal if (type.isPrimitive()) { 18169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal CtPrimitiveType pt = (CtPrimitiveType)type; 18269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal if (pt != CtClass.voidType) { 18369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal String wrapper = pt.getWrapperName(); 18469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal code.addCheckcast(wrapper); 18569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal code.addInvokevirtual(wrapper, pt.getGetMethodName(), 18669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal pt.getGetMethodDescriptor()); 18769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 18869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 18969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal code.addOpcode(pt.getReturnOp()); 19069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 19169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal else { 19269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal code.addCheckcast(type); 19369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal code.addOpcode(Bytecode.ARETURN); 19469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 19569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 19669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal} 197