KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sf > retrotranslator > transformer > GeneralReplacementVisitor


1 /***
2  * Retrotranslator: a Java bytecode transformer that translates Java classes
3  * compiled with JDK 5.0 into classes that can be run on JVM 1.4.
4  *
5  * Copyright (c) 2005 - 2007 Taras Puchko
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  * notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  * notice, this list of conditions and the following disclaimer in the
15  * documentation and/or other materials provided with the distribution.
16  * 3. Neither the name of the copyright holders nor the names of its
17  * contributors may be used to endorse or promote products derived from
18  * this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
30  * THE POSSIBILITY OF SUCH DAMAGE.
31  */

32 package net.sf.retrotranslator.transformer;
33
34 import net.sf.retrotranslator.runtime.asm.*;
35 import static net.sf.retrotranslator.runtime.asm.Opcodes.*;
36 import static net.sf.retrotranslator.runtime.impl.RuntimeTools.CONSTRUCTOR_NAME;
37
38 /**
39  * @author Taras Puchko
40  */

41 class GeneralReplacementVisitor extends GenericClassVisitor {
42
43     private static final String JavaDoc LONG_ARG_DESCRIPTOR = TransformerTools.descriptor(long.class);
44     private static final String JavaDoc DOUBLE_ARG_DESCRIPTOR = TransformerTools.descriptor(double.class);
45
46     private final ReplacementLocator locator;
47     private final NameTranslator translator;
48     private String JavaDoc currentClassName;
49     private boolean threadLocalExcluded;
50
51     public GeneralReplacementVisitor(ClassVisitor classVisitor, final ReplacementLocator locator) {
52         super(classVisitor);
53         this.locator = locator;
54         translator = new NameTranslator() {
55             protected String JavaDoc typeName(String JavaDoc s) {
56                 if (isExcluded(s)) return s;
57                 ClassReplacement replacement = locator.getReplacement(s);
58                 return replacement == null ? s : replacement.getUniqueTypeName();
59             }
60         };
61     }
62
63     protected String JavaDoc identifier(String JavaDoc s) {
64         return s == null ? null : s.replace('+', '$');
65     }
66
67     protected String JavaDoc typeName(String JavaDoc s) {
68         if (isExcluded(s)) return s;
69         ClassReplacement replacement = locator.getReplacement(s);
70         return replacement == null ? s : replacement.getReferenceTypeName();
71     }
72
73     public void visit(int version, int access, String JavaDoc name, String JavaDoc signature, String JavaDoc superName, String JavaDoc[] interfaces) {
74         currentClassName = name;
75         threadLocalExcluded = name.endsWith("ThreadLocal_$Container");
76         super.visit(version, access,
77                 translator.typeName(name),
78                 translator.declarationSignature(signature),
79                 translator.typeName(superName),
80                 translator.typeNames(interfaces));
81     }
82
83     private boolean isExcluded(String JavaDoc name) {
84         return name == null || threadLocalExcluded &&
85                 (name.equals("java/lang/ThreadLocal") || name.equals("java/lang/InheritableThreadLocal"));
86     }
87
88     protected void visitTypeInstruction(MethodVisitor visitor, int opcode, String JavaDoc desc) {
89         if (opcode == CHECKCAST || opcode == INSTANCEOF) {
90             ClassReplacement classReplacement = locator.getReplacement(desc);
91             if (classReplacement != null) {
92                 MemberReplacement memberReplacement = opcode == CHECKCAST ?
93                         classReplacement.getCheckCastReplacement() :
94                         classReplacement.getInstanceOfReplacement();
95                 if (memberReplacement != null) {
96                     visitor.visitMethodInsn(INVOKESTATIC, memberReplacement.getOwner(),
97                             memberReplacement.getName(), memberReplacement.getDesc());
98                     return;
99                 }
100             }
101         }
102         super.visitTypeInstruction(visitor, opcode, desc);
103     }
104
105     protected void visitFieldInstruction(MethodVisitor visitor, int opcode, String JavaDoc owner, String JavaDoc name, String JavaDoc desc) {
106         if (opcode == GETSTATIC || opcode == PUTSTATIC) {
107             ClassReplacement replacement = locator.getReplacement(owner);
108             if (replacement != null) {
109                 MemberReplacement field = replacement.getFieldReplacements().get(name + typeDescriptor(desc));
110                 if (field != null) {
111                     visitor.visitFieldInsn(opcode, field.getOwner(), field.getName(), field.getDesc());
112                     return;
113                 }
114             }
115         }
116         super.visitFieldInstruction(visitor, opcode, owner, name, desc);
117     }
118
119     protected void visitMethodInstruction(MethodVisitor visitor, int opcode, String JavaDoc owner, String JavaDoc name, String JavaDoc desc) {
120         ClassReplacement replacement = locator.getReplacement(owner);
121         if (replacement != null) {
122             owner = typeName(owner);
123             desc = methodDescriptor(desc);
124             if (opcode == INVOKESPECIAL && name.equals(CONSTRUCTOR_NAME)) {
125                 if (visitConstructor(replacement, visitor, owner, desc)) {
126                     return;
127                 }
128                 replacement = locator.getReplacement(owner);
129                 if (replacement != null && visitConstructor(replacement, visitor, owner, desc)) {
130                     return;
131                 }
132             } else {
133                 String JavaDoc methodKey = name + (opcode == INVOKESTATIC ? desc : prepend(owner, desc));
134                 MemberReplacement method = replacement.getMethodReplacements().get(methodKey);
135                 if (method == null) {
136                     replacement = locator.getReplacement(owner);
137                     method = replacement == null ? null : replacement.getMethodReplacements().get(methodKey);
138                 }
139                 if (method != null && !method.getOwner().equals(currentClassName)) {
140                     visitor.visitMethodInsn(INVOKESTATIC, method.getOwner(), method.getName(), method.getDesc());
141                     return;
142                 }
143             }
144         }
145         super.visitMethodInstruction(visitor, opcode, owner, name, desc);
146     }
147
148     private boolean visitConstructor(ClassReplacement replacement, MethodVisitor visitor, String JavaDoc owner, String JavaDoc desc) {
149         ConstructorReplacement constructorReplacement = replacement.getConstructorReplacements().get(desc);
150         if (constructorReplacement != null) {
151             buildInstance(visitor, constructorReplacement);
152             return true;
153         }
154         MemberReplacement converter = replacement.getConverterReplacements().get(desc);
155         if (converter != null) {
156             visitor.visitMethodInsn(INVOKESTATIC, converter.getOwner(), converter.getName(), converter.getDesc());
157             desc = Type.getMethodDescriptor(Type.VOID_TYPE, new Type[]{Type.getReturnType(converter.getDesc())});
158             visitor.visitMethodInsn(INVOKESPECIAL, owner, CONSTRUCTOR_NAME, desc);
159             return true;
160         }
161         return false;
162     }
163
164     private static String JavaDoc prepend(String JavaDoc typeName, String JavaDoc methodDesc) {
165         Type[] source = Type.getArgumentTypes(methodDesc);
166         Type[] target = new Type[source.length + 1];
167         System.arraycopy(source, 0, target, 1, source.length);
168         target[0] = TransformerTools.getTypeByInternalName(typeName);
169         return Type.getMethodDescriptor(Type.getReturnType(methodDesc), target);
170     }
171
172     private void buildInstance(MethodVisitor visitor, ConstructorReplacement replacement) {
173         MemberReplacement creator = replacement.getCreator();
174         MemberReplacement[] arguments = replacement.getArguments();
175         MemberReplacement constructor = replacement.getConstructor();
176         MemberReplacement initializer = replacement.getInitializer();
177         visitor.visitMethodInsn(INVOKESTATIC, creator.getOwner(), creator.getName(), creator.getDesc());
178         if (initializer != null) {
179             visitor.visitInsn(DUP2);
180         }
181         if (arguments.length == 0) {
182             visitor.visitInsn(POP);
183         } else {
184             pushArguments(visitor, arguments);
185         }
186         visitor.visitMethodInsn(INVOKESPECIAL, constructor.getOwner(), CONSTRUCTOR_NAME, constructor.getDesc());
187         if (initializer != null) {
188             visitor.visitInsn(SWAP);
189             visitor.visitMethodInsn(INVOKEVIRTUAL, initializer.getOwner(), initializer.getName(), initializer.getDesc());
190         }
191     }
192
193     private void pushArguments(MethodVisitor visitor, MemberReplacement[] arguments) {
194         for (int i = 0; i < arguments.length; i++) {
195             MemberReplacement argument = arguments[i];
196             boolean notLast = i + 1 < arguments.length;
197             if (notLast) {
198                 visitor.visitInsn(DUP);
199             }
200             visitor.visitMethodInsn(INVOKEVIRTUAL, argument.getOwner(), argument.getName(), argument.getDesc());
201             if (notLast) {
202                 swap(visitor, argument);
203             }
204         }
205     }
206
207     private void swap(MethodVisitor visitor, MemberReplacement argument) {
208         if (argument.getDesc().equals(LONG_ARG_DESCRIPTOR) || argument.getDesc().equals(DOUBLE_ARG_DESCRIPTOR)) {
209             visitor.visitInsn(DUP2_X1);
210             visitor.visitInsn(POP2);
211         } else {
212             visitor.visitInsn(SWAP);
213         }
214     }
215
216 }
217
Popular Tags