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