1 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 41 class GeneralReplacementVisitor extends GenericClassVisitor { 42 43 private static final String LONG_ARG_DESCRIPTOR = TransformerTools.descriptor(long.class); 44 private static final String DOUBLE_ARG_DESCRIPTOR = TransformerTools.descriptor(double.class); 45 46 private final ReplacementLocator locator; 47 private final NameTranslator translator; 48 private String 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 typeName(String 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 identifier(String s) { 64 return s == null ? null : s.replace('+', '$'); 65 } 66 67 protected String typeName(String 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 name, String signature, String superName, String [] 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 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 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 owner, String name, String 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 owner, String name, String 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 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 owner, String 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 prepend(String typeName, String 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 |