001 package net.sourceforge.retroweaver.translator;
002
003 import java.util.HashSet;
004 import java.util.Set;
005
006 import org.objectweb.asm.AnnotationVisitor;
007 import org.objectweb.asm.ClassAdapter;
008 import org.objectweb.asm.ClassVisitor;
009 import org.objectweb.asm.FieldVisitor;
010 import org.objectweb.asm.Label;
011 import org.objectweb.asm.MethodAdapter;
012 import org.objectweb.asm.MethodVisitor;
013 import org.objectweb.asm.Opcodes;
014 import org.objectweb.asm.Type;
015 import org.objectweb.asm.signature.SignatureReader;
016 import org.objectweb.asm.signature.SignatureWriter;
017
018 public class NameTranslatorClassVisitor extends ClassAdapter {
019
020 private final NameTranslator translator;
021
022 public NameTranslatorClassVisitor(final ClassVisitor classVisitor, final NameTranslator translator) {
023 super(classVisitor);
024 this.translator = translator;
025 }
026
027 private Set<String> visitedMethods;
028
029 private String className;
030
031 private String translateSignature(final String signature, boolean type) {
032 if (signature == null) {
033 return null;
034 }
035 SignatureReader r = new SignatureReader(signature);
036 SignatureWriter w = new SignatureWriter() {
037 public void visitClassType(final String name) {
038 String n = translator.getClassMirrorTranslation(name);
039 super.visitClassType(n);
040 }
041 };
042
043 if (type) {
044 r.acceptType(w);
045 } else {
046 r.accept(w);
047 }
048 return w.toString();
049 }
050
051 public void visit(final int version, final int access, final String name,
052 final String signature, final String superName,
053 final String[] interfaces) {
054 final String newSuperName = translator.getClassMirrorTranslation(superName);
055
056 String newInterfaces[] = new String[interfaces.length];
057 for (int i = 0; i < interfaces.length; i++) {
058 newInterfaces[i] = translator.getClassMirrorTranslation(interfaces[i]);
059 }
060
061 className = name;
062 visitedMethods = new HashSet<String>();
063
064 super.visit(version, access, name, translateSignature(signature, false), newSuperName, newInterfaces);
065 }
066
067 public FieldVisitor visitField(final int access, final String name,
068 final String desc, final String signature, final Object value) {
069 return super.visitField(access, name,
070 translator.getClassMirrorTranslationDescriptor(desc),
071 translateSignature(signature, true), value);
072 }
073
074 public MethodVisitor visitMethod(final int access, final String name,
075 final String desc, final String signature, final String[] exceptions) {
076
077 final String newDesc = translator.translateMethodDescriptor(desc);
078 final String fullDesc = name + newDesc;
079 if (visitedMethods.contains(fullDesc)) {
080 throw new TranslatorException(
081 "Duplicate method after name translation in class "
082 + className + ": " + name + ' ' + newDesc);
083 }
084 visitedMethods.add(fullDesc);
085
086 MethodVisitor mv = super.visitMethod(access, name, newDesc,
087 translateSignature(signature, false), exceptions);
088 return (mv == null)?null:new MethodTranslator(mv);
089 }
090
091 public AnnotationVisitor visitAnnotation(final String desc, final boolean visible) {
092 final String newDesc = translateAnnotationDescriptor(desc);
093 return new AnnotationTranslator(cv.visitAnnotation(newDesc, visible));
094 }
095
096 private String translateAnnotationDescriptor(final String name) {
097 if ((name == null) || (name.length() == 0)) {
098 return name;
099 }
100
101 if ((name.charAt(0) != 'L') || (name.charAt(name.length()-1) != ';')) {
102 return name;
103 }
104
105 return translator.translateDescriptor(name);
106 }
107
108 private class MethodTranslator extends MethodAdapter {
109 MethodTranslator(MethodVisitor methodVisitor) {
110 super(methodVisitor);
111 }
112
113 public void visitTypeInsn(final int opcode, final String desc) {
114 super.visitTypeInsn(opcode, translator.getClassMirrorTranslationDescriptor(desc));
115 }
116
117 public void visitFieldInsn(final int opcode, final String owner,
118 final String name, final String desc) {
119
120 String newDesc = translator.getClassMirrorTranslationDescriptor(desc);
121
122 if (opcode == Opcodes.GETSTATIC) {
123 final Mirror mirror = translator.getMirror(owner);
124 if (mirror.hasStaticField(name, newDesc)) {
125 super.visitFieldInsn(opcode,
126 translator.translate(owner), name, newDesc);
127
128 return;
129 }
130 }
131 super.visitFieldInsn(opcode,
132 translator.getClassMirrorTranslation(owner),
133 name, newDesc);
134 }
135
136 public void visitMethodInsn(final int opcode, final String owner,
137 final String name, final String desc) {
138
139 // Special case method invocations for name translation.
140 // Specifically to deal with methods mirrors.
141 String newOwner = owner;
142 int newOpcode = opcode;
143 String newDesc = desc;
144
145 String lookupOwner = owner;
146 while (lookupOwner.startsWith("[")) {
147 lookupOwner = lookupOwner.substring(1);
148 }
149 final Mirror mirror = translator.getMirror(lookupOwner);
150
151 if (mirror.isClassMirror()) {
152 newOwner = translator.translate(owner);
153 } else if ("<init>".equals(name)&&(opcode == Opcodes.INVOKESPECIAL)) {
154 /* Look for an equivalent constructor. For instance,
155 * INVOKESPECIAL, "java/math/BigDecimal", "<init>", "(I)V")
156 * will be transformed as
157 * INVOKESTATIC, "../BigDecimal_", "BigDecimal", "(I)Ljava/math/BigDecimal;"
158 *
159 * the previously constructed object was on top of the stack and the mirror
160 * function has put its result on top, so a SWAP and POP are issued to
161 * discard the previously constructed object and store the new one instead.
162 */
163 String constructorDesc = desc.substring(0, desc.length()-1) + 'L' + owner + ';';
164 String constructorName;
165 int i = owner.lastIndexOf('/');
166 if (i == -1) {
167 constructorName = owner;
168 } else {
169 constructorName = owner.substring(i+1);
170 }
171 if (mirror.hasMethod(owner, constructorName, constructorDesc, Opcodes.INVOKESPECIAL)) {
172 newOwner = translator.translate(owner);
173
174 super.visitMethodInsn(Opcodes.INVOKESTATIC, newOwner, constructorName,
175 constructorDesc);
176
177 super.visitInsn(Opcodes.SWAP);
178 super.visitInsn(Opcodes.POP);
179 super.visitInsn(Opcodes.SWAP);
180 super.visitInsn(Opcodes.POP);
181 return;
182 }
183 } else if (mirror.hasMethod(owner, name, desc, opcode)) {
184 newOwner = translator.translate(owner);
185 newOpcode = Opcodes.INVOKESTATIC;
186
187 // We have to insert the owner into the arguments of the
188 // descriptor
189 if (opcode == Opcodes.INVOKEVIRTUAL) {
190 final Type[] argTypes = Type.getArgumentTypes(desc);
191 final Type[] newArgTypes = new Type[argTypes.length + 1];
192 newArgTypes[0] = Type.getType("L" + owner + ";");
193 System.arraycopy(argTypes, 0, newArgTypes, 1, argTypes.length);
194 newDesc = Type.getMethodDescriptor(
195 Type.getReturnType(desc), newArgTypes);
196 }
197 }
198
199 super.visitMethodInsn(newOpcode, newOwner, name,
200 translator.translateMethodDescriptor(newDesc));
201 }
202
203 public void visitTryCatchBlock(final Label start, final Label end,
204 final Label handler, final String type) {
205 super.visitTryCatchBlock(start, end, handler, translator.translate(type));
206 }
207
208 public void visitLocalVariable(final String name, final String desc,
209 final String signature, final Label start, final Label end,
210 final int index) {
211 super.visitLocalVariable(name, translator.translateDescriptor(desc),
212 translateSignature(signature, true), start, end, index);
213 }
214
215 public AnnotationVisitor visitAnnotationDefault() {
216 return new AnnotationTranslator(mv.visitAnnotationDefault());
217 }
218
219 public AnnotationVisitor visitAnnotation(
220 final String desc,
221 final boolean visible)
222 {
223 return new AnnotationTranslator(mv.visitAnnotation(desc, visible));
224 }
225
226 public AnnotationVisitor visitParameterAnnotation(
227 final int parameter,
228 final String desc,
229 final boolean visible)
230 {
231 return new AnnotationTranslator(mv.visitParameterAnnotation(parameter, desc, visible));
232 }
233
234 }
235
236 private class AnnotationTranslator implements AnnotationVisitor {
237
238 private final AnnotationVisitor av;
239
240 AnnotationTranslator(final AnnotationVisitor av) {
241 this.av = av;
242 }
243
244 public void visit(final String name, final Object value) {
245 final String newName = translateAnnotationDescriptor(name);
246 av.visit(newName, value);
247 }
248
249 public void visitEnum(final String name, final String desc, final String value) {
250 final String newName = translateAnnotationDescriptor(name);
251 final String newDesc = translateAnnotationDescriptor(desc);
252 av.visitEnum(newName, newDesc, value);
253 }
254
255 public AnnotationVisitor visitAnnotation(final String name, final String desc) {
256 final String newName = translateAnnotationDescriptor(name);
257 return new AnnotationTranslator(av.visitAnnotation(newName, desc));
258 }
259
260 public AnnotationVisitor visitArray(final String name) {
261 final String newName = translateAnnotationDescriptor(name);
262 return new AnnotationTranslator(av.visitArray(newName));
263 }
264
265 public void visitEnd() {
266 av.visitEnd();
267 }
268
269 }
270 }