1/*
2 * Javassist, a Java-bytecode translator toolkit.
3 * Copyright (C) 1999-2007 Shigeru Chiba. All Rights Reserved.
4 *
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License.  Alternatively, the contents of this file may be used under
8 * the terms of the GNU Lesser General Public License Version 2.1 or later.
9 *
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
14 */
15
16package javassist.convert;
17
18import javassist.bytecode.*;
19import javassist.CtClass;
20import javassist.CannotCompileException;
21
22final public class TransformNew extends Transformer {
23    private int nested;
24    private String classname, trapClass, trapMethod;
25
26    public TransformNew(Transformer next,
27                 String classname, String trapClass, String trapMethod) {
28        super(next);
29        this.classname = classname;
30        this.trapClass = trapClass;
31        this.trapMethod = trapMethod;
32    }
33
34    public void initialize(ConstPool cp, CodeAttribute attr) {
35        nested = 0;
36    }
37
38    /**
39     * Replace a sequence of
40     *    NEW classname
41     *    DUP
42     *    ...
43     *    INVOKESPECIAL
44     * with
45     *    NOP
46     *    NOP
47     *    ...
48     *    INVOKESTATIC trapMethod in trapClass
49     */
50    public int transform(CtClass clazz, int pos, CodeIterator iterator,
51                         ConstPool cp) throws CannotCompileException
52    {
53        int index;
54        int c = iterator.byteAt(pos);
55        if (c == NEW) {
56            index = iterator.u16bitAt(pos + 1);
57            if (cp.getClassInfo(index).equals(classname)) {
58                if (iterator.byteAt(pos + 3) != DUP)
59                    throw new CannotCompileException(
60                                "NEW followed by no DUP was found");
61
62                iterator.writeByte(NOP, pos);
63                iterator.writeByte(NOP, pos + 1);
64                iterator.writeByte(NOP, pos + 2);
65                iterator.writeByte(NOP, pos + 3);
66                ++nested;
67
68                StackMapTable smt
69                    = (StackMapTable)iterator.get().getAttribute(StackMapTable.tag);
70                if (smt != null)
71                    smt.removeNew(pos);
72
73                StackMap sm
74                    = (StackMap)iterator.get().getAttribute(StackMap.tag);
75                if (sm != null)
76                    sm.removeNew(pos);
77            }
78        }
79        else if (c == INVOKESPECIAL) {
80            index = iterator.u16bitAt(pos + 1);
81            int typedesc = cp.isConstructor(classname, index);
82            if (typedesc != 0 && nested > 0) {
83                int methodref = computeMethodref(typedesc, cp);
84                iterator.writeByte(INVOKESTATIC, pos);
85                iterator.write16bit(methodref, pos + 1);
86                --nested;
87            }
88        }
89
90        return pos;
91    }
92
93    private int computeMethodref(int typedesc, ConstPool cp) {
94        int classIndex = cp.addClassInfo(trapClass);
95        int mnameIndex = cp.addUtf8Info(trapMethod);
96        typedesc = cp.addUtf8Info(
97                Descriptor.changeReturnType(classname,
98                                            cp.getUtf8Info(typedesc)));
99        return cp.addMethodrefInfo(classIndex,
100                        cp.addNameAndTypeInfo(mnameIndex, typedesc));
101    }
102}
103