KickJava   Java API By Example, From Geeks To Geeks.

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


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 edu.emory.mathcs.backport.java.util.concurrent.*;
35 import edu.emory.mathcs.backport.java.util.concurrent.helpers.Utils;
36 import edu.emory.mathcs.backport.java.util.concurrent.locks.*;
37 import java.lang.ref.*;
38 import java.util.*;
39 import net.sf.retrotranslator.runtime.asm.*;
40 import static net.sf.retrotranslator.runtime.asm.Opcodes.*;
41 import net.sf.retrotranslator.runtime.impl.RuntimeTools;
42
43 /**
44  * @author Taras Puchko
45  */

46 class SpecificReplacementVisitor extends ClassAdapter {
47
48     private static final String JavaDoc ILLEGAL_STATE_EXCEPTION = Type.getInternalName(IllegalStateException JavaDoc.class);
49     private static final String JavaDoc ILLEGAL_ARGUMENT_EXCEPTION = Type.getInternalName(IllegalArgumentException JavaDoc.class);
50     private static final String JavaDoc SOFT_REFERENCE = Type.getInternalName(SoftReference.class);
51     private static final String JavaDoc WEAK_REFERENCE = Type.getInternalName(WeakReference.class);
52
53     private static final String JavaDoc SYSTEM_NAME = Type.getInternalName(System JavaDoc.class);
54     private static final String JavaDoc CONDITION_NAME = Type.getInternalName(Condition.class);
55     private static final String JavaDoc DELAY_QUEUE_NAME = Type.getInternalName(DelayQueue.class);
56     private static final String JavaDoc REENTRANT_READ_WRITE_LOCK_NAME = Type.getInternalName(ReentrantReadWriteLock.class);
57
58     private static final String JavaDoc ORIGINAL_COLLECTIONS_NAME = Type.getInternalName(java.util.Collections JavaDoc.class);
59     private static final String JavaDoc BACKPORTED_COLLECTIONS_NAME =
60             Type.getInternalName(edu.emory.mathcs.backport.java.util.Collections.class);
61     private static final String JavaDoc ORIGINAL_ARRAYS_NAME = Type.getInternalName(java.util.Arrays JavaDoc.class);
62     private static final String JavaDoc BACKPORTED_ARRAYS_NAME =
63             Type.getInternalName(edu.emory.mathcs.backport.java.util.Arrays.class);
64
65     private static final Set<String JavaDoc> ARRAYS_METHODS = getArrayMethods();
66     private static final Set<String JavaDoc> COLLECTIONS_METHODS = getCollectionMethods();
67     private static final Map<String JavaDoc, String JavaDoc> COLLECTIONS_FIELDS = getCollectionFields();
68
69     private final boolean advanced;
70
71     public SpecificReplacementVisitor(ClassVisitor visitor, boolean advanced) {
72         super(visitor);
73         this.advanced = advanced;
74     }
75
76     public MethodVisitor visitMethod(int access, String JavaDoc name, String JavaDoc desc, String JavaDoc signature, String JavaDoc[] exceptions) {
77         MethodVisitor visitor = super.visitMethod(access, name, desc, signature, exceptions);
78         return visitor == null ? null : new ConstructorReplacementMethodVisitor(visitor);
79     }
80
81     private class ConstructorReplacementMethodVisitor extends MethodAdapter {
82
83         public ConstructorReplacementMethodVisitor(MethodVisitor visitor) {
84             super(visitor);
85         }
86
87         public void visitMethodInsn(int opcode, String JavaDoc owner, String JavaDoc name, String JavaDoc desc) {
88             if (opcode == INVOKESPECIAL && name.equals(RuntimeTools.CONSTRUCTOR_NAME)) {
89                 if (fixException(owner, desc)) {
90                     return;
91                 }
92                 if (fixReference(owner, desc)) {
93                     return;
94                 }
95             }
96             if (owner.equals(SYSTEM_NAME) & name.equals("nanoTime")) {
97                 mv.visitMethodInsn(opcode, Type.getInternalName(Utils.class), name, desc);
98                 return;
99             }
100             if (owner.equals(CONDITION_NAME) & name.equals("awaitNanos")) {
101                 mv.visitMethodInsn(INVOKESTATIC, Type.getInternalName(Utils.class), name,
102                         TransformerTools.descriptor(long.class, Condition.class, long.class));
103                 return;
104             }
105             if (fixDelayQueue(opcode, owner, name, desc)) {
106                 return;
107             }
108             if (fixLock(opcode, owner, name, desc)) {
109                 return;
110             }
111             if (fixCollections(opcode, owner, name, desc)) {
112                 return;
113             }
114             if (fixArrays(opcode, owner, name, desc)) {
115                 return;
116             }
117             super.visitMethodInsn(opcode, owner, name, desc);
118         }
119
120         private boolean fixDelayQueue(int opcode, String JavaDoc owner, String JavaDoc name, String JavaDoc desc) {
121             if (!owner.equals(DELAY_QUEUE_NAME)) {
122                 return false;
123             }
124             String JavaDoc fixedDesc = new NameTranslator() {
125                 protected String JavaDoc typeName(String JavaDoc s) {
126                     return Type.getInternalName(Delayed.class).equals(s) ?
127                             Type.getInternalName(Object JavaDoc.class) : s;
128                 }
129             }.methodDescriptor(desc);
130             mv.visitMethodInsn(opcode, owner, name, fixedDesc);
131             Type returnType = Type.getReturnType(desc);
132             if (returnType.equals(Type.getType(Delayed.class))) {
133                 mv.visitTypeInsn(CHECKCAST, returnType.getInternalName());
134             }
135             return true;
136         }
137
138         private boolean fixLock(int opcode, String JavaDoc owner, String JavaDoc name, String JavaDoc desc) {
139             if (!owner.equals(REENTRANT_READ_WRITE_LOCK_NAME)) {
140                 return false;
141             }
142             Type returnType = Type.getReturnType(desc);
143             if (returnType.equals(Type.getType(ReentrantReadWriteLock.ReadLock.class)) ||
144                     returnType.equals(Type.getType(ReentrantReadWriteLock.WriteLock.class))) {
145                 desc = Type.getMethodDescriptor(Type.getType(Lock.class), Type.getArgumentTypes(desc));
146                 mv.visitMethodInsn(opcode, owner, name, desc);
147                 mv.visitTypeInsn(CHECKCAST, returnType.getInternalName());
148                 return true;
149             }
150             return false;
151         }
152
153         private boolean fixCollections(int opcode, String JavaDoc owner, String JavaDoc name, String JavaDoc desc) {
154             if (!owner.equals(ORIGINAL_COLLECTIONS_NAME)) {
155                 return false;
156             }
157             String JavaDoc field = COLLECTIONS_FIELDS.get(name);
158             if (field != null) {
159                 mv.visitFieldInsn(Opcodes.GETSTATIC, ORIGINAL_COLLECTIONS_NAME,
160                         field, Type.getReturnType(desc).toString());
161                 return true;
162             }
163             if (COLLECTIONS_METHODS.contains(name + desc)) {
164                 mv.visitMethodInsn(opcode, BACKPORTED_COLLECTIONS_NAME, name, desc);
165                 return true;
166             }
167             return false;
168         }
169
170         private boolean fixArrays(int opcode, String JavaDoc owner, String JavaDoc name, String JavaDoc desc) {
171             if (owner.equals(ORIGINAL_ARRAYS_NAME) && ARRAYS_METHODS.contains(name + desc)) {
172                 mv.visitMethodInsn(opcode, BACKPORTED_ARRAYS_NAME, name, desc);
173                 return true;
174             }
175             return false;
176         }
177
178         private boolean fixException(String JavaDoc owner, String JavaDoc desc) {
179             if (!owner.equals(ILLEGAL_STATE_EXCEPTION) && !owner.equals(ILLEGAL_ARGUMENT_EXCEPTION)) {
180                 return false;
181             }
182             if (desc.equals(TransformerTools.descriptor(void.class, Throwable JavaDoc.class))) {
183                 Label toStringLabel = new Label();
184                 Label continueLabel = new Label();
185                 mv.visitInsn(DUP2);
186                 mv.visitInsn(DUP);
187                 mv.visitJumpInsn(IFNONNULL, toStringLabel);
188                 mv.visitInsn(POP);
189                 mv.visitInsn(ACONST_NULL);
190                 mv.visitJumpInsn(GOTO, continueLabel);
191                 mv.visitLabel(toStringLabel);
192                 mv.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(Throwable JavaDoc.class),
193                         "toString", TransformerTools.descriptor(String JavaDoc.class));
194                 mv.visitLabel(continueLabel);
195             } else if (desc.equals(TransformerTools.descriptor(void.class, String JavaDoc.class, Throwable JavaDoc.class))) {
196                 mv.visitInsn(DUP_X2);
197                 mv.visitInsn(POP);
198                 mv.visitInsn(SWAP);
199                 mv.visitInsn(DUP_X2);
200                 mv.visitInsn(SWAP);
201             } else {
202                 return false;
203             }
204             mv.visitMethodInsn(INVOKESPECIAL, owner,
205                     RuntimeTools.CONSTRUCTOR_NAME, TransformerTools.descriptor(void.class, String JavaDoc.class));
206             mv.visitMethodInsn(INVOKEVIRTUAL, owner,
207                     "initCause", TransformerTools.descriptor(Throwable JavaDoc.class, Throwable JavaDoc.class));
208             mv.visitInsn(POP);
209             return true;
210         }
211
212         private boolean fixReference(String JavaDoc owner, String JavaDoc desc) {
213             if (!advanced || (!owner.equals(SOFT_REFERENCE) && !owner.equals(WEAK_REFERENCE))) {
214                 return false;
215             }
216             if (!desc.equals(TransformerTools.descriptor(void.class, Object JavaDoc.class, ReferenceQueue.class))) {
217                 return false;
218             }
219             Label notNullLabel = new Label();
220             Label continueLabel = new Label();
221             mv.visitInsn(DUP);
222             mv.visitJumpInsn(IFNONNULL, notNullLabel);
223             mv.visitInsn(POP);
224             mv.visitMethodInsn(INVOKESPECIAL, owner,
225                     RuntimeTools.CONSTRUCTOR_NAME, TransformerTools.descriptor(void.class, Object JavaDoc.class));
226             mv.visitJumpInsn(GOTO, continueLabel);
227             mv.visitLabel(notNullLabel);
228             mv.visitMethodInsn(INVOKESPECIAL, owner, RuntimeTools.CONSTRUCTOR_NAME, desc);
229             mv.visitLabel(continueLabel);
230             return true;
231         }
232     }
233
234     private static Set<String JavaDoc> getArrayMethods() {
235         Set<String JavaDoc> result = new HashSet<String JavaDoc>();
236         for (Class JavaDoc arrayType : new Class JavaDoc[]{boolean[].class, byte[].class, char[].class,
237                 double[].class, float[].class, int[].class, long[].class, short[].class, Object JavaDoc[].class}) {
238             result.add("copyOf" +
239                     TransformerTools.descriptor(arrayType, arrayType, int.class));
240             result.add("copyOfRange" +
241                     TransformerTools.descriptor(arrayType, arrayType, int.class, int.class));
242         }
243         result.add("copyOf" +
244                 TransformerTools.descriptor(Object JavaDoc[].class, Object JavaDoc[].class, int.class, Class JavaDoc.class));
245         result.add("copyOfRange" +
246                 TransformerTools.descriptor(Object JavaDoc[].class, Object JavaDoc[].class, int.class, int.class, Class JavaDoc.class));
247         return result;
248     }
249
250     private static Set<String JavaDoc> getCollectionMethods() {
251         Set<String JavaDoc> result = new HashSet<String JavaDoc>();
252         for (String JavaDoc method : new String JavaDoc[]{
253                 getMethod(boolean.class, "addAll", Collection.class, Object JavaDoc[].class),
254                 getMethod(Collection.class, "checkedCollection", Collection.class, Class JavaDoc.class),
255                 getMethod(List.class, "checkedList", List.class, Class JavaDoc.class),
256                 getMethod(Map.class, "checkedMap", Map.class, Class JavaDoc.class, Class JavaDoc.class),
257                 getMethod(Set.class, "checkedSet", Set.class, Class JavaDoc.class),
258                 getMethod(SortedMap.class, "checkedSortedMap", SortedMap.class, Class JavaDoc.class, Class JavaDoc.class),
259                 getMethod(SortedSet.class, "checkedSortedSet", SortedSet.class, Class JavaDoc.class),
260                 getMethod(boolean.class, "disjoint", Collection.class, Collection.class),
261                 getMethod(int.class, "frequency", Collection.class, Object JavaDoc.class),
262                 getMethod(Comparator.class, "reverseOrder", Comparator.class),
263                 getMethod(Set.class, "newSetFromMap", Map.class)}) {
264             result.add(method);
265         }
266         return result;
267     }
268
269     private static String JavaDoc getMethod(Class JavaDoc returnType, String JavaDoc name, Class JavaDoc... parameterTypes) {
270         return name + TransformerTools.descriptor(returnType, parameterTypes);
271     }
272
273     private static Map<String JavaDoc, String JavaDoc> getCollectionFields() {
274         Map<String JavaDoc, String JavaDoc> result = new HashMap<String JavaDoc, String JavaDoc>();
275         result.put("emptyList", "EMPTY_LIST");
276         result.put("emptyMap", "EMPTY_MAP");
277         result.put("emptySet", "EMPTY_SET");
278         return result;
279     }
280
281 }
282
Popular Tags