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 TransformNewClass extends Transformer {
23    private int nested;
24    private String classname, newClassName;
25    private int newClassIndex, newMethodNTIndex, newMethodIndex;
26
27    public TransformNewClass(Transformer next,
28                             String classname, String newClassName) {
29        super(next);
30        this.classname = classname;
31        this.newClassName = newClassName;
32    }
33
34    public void initialize(ConstPool cp, CodeAttribute attr) {
35        nested = 0;
36        newClassIndex = newMethodNTIndex = newMethodIndex = 0;
37    }
38
39    /**
40     * Modifies a sequence of
41     *    NEW classname
42     *    DUP
43     *    ...
44     *    INVOKESPECIAL classname:method
45     */
46    public int transform(CtClass clazz, int pos, CodeIterator iterator,
47                         ConstPool cp) throws CannotCompileException
48    {
49        int index;
50        int c = iterator.byteAt(pos);
51        if (c == NEW) {
52            index = iterator.u16bitAt(pos + 1);
53            if (cp.getClassInfo(index).equals(classname)) {
54                if (iterator.byteAt(pos + 3) != DUP)
55                    throw new CannotCompileException(
56                                "NEW followed by no DUP was found");
57
58                if (newClassIndex == 0)
59                    newClassIndex = cp.addClassInfo(newClassName);
60
61                iterator.write16bit(newClassIndex, pos + 1);
62                ++nested;
63            }
64        }
65        else if (c == INVOKESPECIAL) {
66            index = iterator.u16bitAt(pos + 1);
67            int typedesc = cp.isConstructor(classname, index);
68            if (typedesc != 0 && nested > 0) {
69                int nt = cp.getMethodrefNameAndType(index);
70                if (newMethodNTIndex != nt) {
71                    newMethodNTIndex = nt;
72                    newMethodIndex = cp.addMethodrefInfo(newClassIndex, nt);
73                }
74
75                iterator.write16bit(newMethodIndex, pos + 1);
76                --nested;
77            }
78        }
79
80        return pos;
81    }
82}
83