1 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 46 class SpecificReplacementVisitor extends ClassAdapter { 47 48 private static final String ILLEGAL_STATE_EXCEPTION = Type.getInternalName(IllegalStateException .class); 49 private static final String ILLEGAL_ARGUMENT_EXCEPTION = Type.getInternalName(IllegalArgumentException .class); 50 private static final String SOFT_REFERENCE = Type.getInternalName(SoftReference.class); 51 private static final String WEAK_REFERENCE = Type.getInternalName(WeakReference.class); 52 53 private static final String SYSTEM_NAME = Type.getInternalName(System .class); 54 private static final String CONDITION_NAME = Type.getInternalName(Condition.class); 55 private static final String DELAY_QUEUE_NAME = Type.getInternalName(DelayQueue.class); 56 private static final String REENTRANT_READ_WRITE_LOCK_NAME = Type.getInternalName(ReentrantReadWriteLock.class); 57 58 private static final String ORIGINAL_COLLECTIONS_NAME = Type.getInternalName(java.util.Collections .class); 59 private static final String BACKPORTED_COLLECTIONS_NAME = 60 Type.getInternalName(edu.emory.mathcs.backport.java.util.Collections.class); 61 private static final String ORIGINAL_ARRAYS_NAME = Type.getInternalName(java.util.Arrays .class); 62 private static final String BACKPORTED_ARRAYS_NAME = 63 Type.getInternalName(edu.emory.mathcs.backport.java.util.Arrays.class); 64 65 private static final Set<String > ARRAYS_METHODS = getArrayMethods(); 66 private static final Set<String > COLLECTIONS_METHODS = getCollectionMethods(); 67 private static final Map<String , String > 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 name, String desc, String signature, String [] 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 owner, String name, String 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 owner, String name, String desc) { 121 if (!owner.equals(DELAY_QUEUE_NAME)) { 122 return false; 123 } 124 String fixedDesc = new NameTranslator() { 125 protected String typeName(String s) { 126 return Type.getInternalName(Delayed.class).equals(s) ? 127 Type.getInternalName(Object .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 owner, String name, String 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 owner, String name, String desc) { 154 if (!owner.equals(ORIGINAL_COLLECTIONS_NAME)) { 155 return false; 156 } 157 String 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 owner, String name, String 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 owner, String 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 .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 .class), 193 "toString", TransformerTools.descriptor(String .class)); 194 mv.visitLabel(continueLabel); 195 } else if (desc.equals(TransformerTools.descriptor(void.class, String .class, Throwable .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 .class)); 206 mv.visitMethodInsn(INVOKEVIRTUAL, owner, 207 "initCause", TransformerTools.descriptor(Throwable .class, Throwable .class)); 208 mv.visitInsn(POP); 209 return true; 210 } 211 212 private boolean fixReference(String owner, String 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 .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 .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 > getArrayMethods() { 235 Set<String > result = new HashSet<String >(); 236 for (Class arrayType : new Class []{boolean[].class, byte[].class, char[].class, 237 double[].class, float[].class, int[].class, long[].class, short[].class, Object [].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 [].class, Object [].class, int.class, Class .class)); 245 result.add("copyOfRange" + 246 TransformerTools.descriptor(Object [].class, Object [].class, int.class, int.class, Class .class)); 247 return result; 248 } 249 250 private static Set<String > getCollectionMethods() { 251 Set<String > result = new HashSet<String >(); 252 for (String method : new String []{ 253 getMethod(boolean.class, "addAll", Collection.class, Object [].class), 254 getMethod(Collection.class, "checkedCollection", Collection.class, Class .class), 255 getMethod(List.class, "checkedList", List.class, Class .class), 256 getMethod(Map.class, "checkedMap", Map.class, Class .class, Class .class), 257 getMethod(Set.class, "checkedSet", Set.class, Class .class), 258 getMethod(SortedMap.class, "checkedSortedMap", SortedMap.class, Class .class, Class .class), 259 getMethod(SortedSet.class, "checkedSortedSet", SortedSet.class, Class .class), 260 getMethod(boolean.class, "disjoint", Collection.class, Collection.class), 261 getMethod(int.class, "frequency", Collection.class, Object .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 getMethod(Class returnType, String name, Class ... parameterTypes) { 270 return name + TransformerTools.descriptor(returnType, parameterTypes); 271 } 272 273 private static Map<String , String > getCollectionFields() { 274 Map<String , String > result = new HashMap<String , String >(); 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 |