1 32 package net.sf.retrotranslator.transformer; 33 34 import java.util.*; 35 import static net.sf.retrotranslator.runtime.asm.Opcodes.*; 36 import net.sf.retrotranslator.runtime.asm.Type; 37 import net.sf.retrotranslator.runtime.impl.*; 38 39 42 class ReplacementLocator { 43 44 private static final ClassReplacement NULL = new ClassReplacement(); 45 46 private final boolean advanced; 47 private final List<Backport> backports; 48 private final Map<String , ClassReplacement> replacements = new Hashtable<String , ClassReplacement>(); 49 50 public ReplacementLocator(boolean advanced, List<Backport> backports) { 51 this.advanced = advanced; 52 this.backports = backports; 53 } 54 55 public ClassReplacement getReplacement(String className) { 56 if (className == null || className.length() == 0 || className.charAt(0) == '[') { 57 return null; 58 } 59 ClassReplacement replacement = replacements.get(className); 60 if (replacement == null) { 61 replacement = buildReplacement(className); 62 replacements.put(className, replacement); 63 } 64 return replacement == NULL ? null : replacement; 65 } 66 67 private ClassReplacement buildReplacement(String originalName) { 68 ClassReplacement replacement = new ClassReplacement(); 69 for (Backport backport : backports) { 70 if (replacement.getUniqueTypeName() == null && originalName.equals(backport.getOriginalName())) { 71 replacement.setUniqueTypeName(backport.getReplacementName()); 72 } 73 String originalPrefix = backport.getOriginalPrefix(); 74 if (originalPrefix == null) { 75 continue; 76 } 77 String suffix = originalName; 78 if (originalPrefix.length() > 0) { 79 if (originalName.startsWith(originalPrefix)) { 80 suffix = originalName.substring(originalPrefix.length()); 81 } else { 82 continue; 83 } 84 } 85 String prefix = backport.getReplacementPrefix(); 86 if (replacement.getUniqueTypeName() == null) { 87 replacement.setUniqueTypeName(findUniqueName(prefix, suffix)); 88 } 89 ClassDescriptor classDescriptor = getClassDescriptor(createServiceName(prefix, suffix)); 90 if (classDescriptor != null) { 91 loadFields(replacement, classDescriptor); 92 loadMethods(replacement, classDescriptor, originalName); 93 } 94 } 95 if (replacement.isEmpty()) { 96 return NULL; 97 } 98 if (replacement.getUniqueTypeName() == null) { 99 replacement.setUniqueTypeName(originalName); 100 } 101 replacement.setReferenceTypeName(replacement.getCheckCastReplacement() != null ? 102 Type.getReturnType(replacement.getCheckCastReplacement().getDesc()).getInternalName() : 103 replacement.getUniqueTypeName() 104 ); 105 return replacement; 106 } 107 108 private String findUniqueName(String prefix, String suffix) { 109 String uniqueName = prefix + suffix + "_"; 110 if (isClassAvailable(uniqueName)) { 111 return uniqueName; 112 } 113 int index = suffix.indexOf('$'); 114 if (index >= 0) { 115 uniqueName = prefix + replaceChar(suffix, index, "_$"); 116 if (isClassAvailable(uniqueName)) { 117 return uniqueName; 118 } 119 uniqueName = prefix + replaceChar(suffix, index, "_") + "_"; 120 if (isClassAvailable(uniqueName)) { 121 return uniqueName; 122 } 123 } 124 uniqueName = prefix + suffix; 125 if (isClassAvailable(uniqueName)) { 126 return uniqueName; 127 } 128 return null; 129 } 130 131 private static String replaceChar(String s, int index, String replacement) { 132 return s.substring(0, index) + replacement + s.substring(index + 1); 133 } 134 135 private void loadFields(ClassReplacement classReplacement, ClassDescriptor classDescriptor) { 136 for (FieldDescriptor fieldDescriptor : classDescriptor.getFieldDescriptors()) { 137 if (!fieldDescriptor.isAccess(ACC_PUBLIC) || !fieldDescriptor.isAccess(ACC_STATIC)) { 138 continue; 139 } 140 if (!advanced && fieldDescriptor.isAnnotationPresent(Advanced.class)) { 141 continue; 142 } 143 String fieldName = fieldDescriptor.getName(); 144 String fieldDesc = fieldDescriptor.getDesc(); 145 String key = fieldName + fieldDesc; 146 Map<String , MemberReplacement> replacements = classReplacement.getFieldReplacements(); 147 if (replacements.containsKey(key)) { 148 continue; 149 } 150 replacements.put(key, new MemberReplacement(classDescriptor.getName(), fieldName, fieldDesc)); 151 } 152 } 153 154 private void loadMethods(ClassReplacement classReplacement, ClassDescriptor classDescriptor, String originalName) { 155 for (MethodDescriptor methodDescriptor : classDescriptor.getMethodDescriptors()) { 156 if (!methodDescriptor.isAccess(ACC_PUBLIC) || !methodDescriptor.isAccess(ACC_STATIC)) { 157 continue; 158 } 159 if (!advanced && methodDescriptor.isAnnotationPresent(Advanced.class)) { 160 continue; 161 } 162 String methodName = methodDescriptor.getName(); 163 String methodDesc = methodDescriptor.getDesc(); 164 String methodKey = methodName + methodDesc; 165 if (classReplacement.getMethodReplacements().containsKey(methodKey)) { 166 continue; 167 } 168 MemberReplacement replacement = new MemberReplacement(classDescriptor.getName(), methodName, methodDesc); 169 classReplacement.getMethodReplacements().put(methodKey, replacement); 170 if (methodName.equals("convertConstructorArguments")) { 171 String converterKey = Type.getMethodDescriptor(Type.VOID_TYPE, Type.getArgumentTypes(methodDesc)); 172 if (!classReplacement.getConverterReplacements().containsKey(converterKey)) { 173 classReplacement.getConverterReplacements().put(converterKey, replacement); 174 } 175 } 176 if (classReplacement.getInstanceOfReplacement() == null && 177 methodName.equals("executeInstanceOfInstruction") && 178 methodDesc.equals(TransformerTools.descriptor(boolean.class, Object .class))) { 179 classReplacement.setInstanceOfReplacement(replacement); 180 } 181 if (classReplacement.getCheckCastReplacement() == null && 182 methodName.equals("executeCheckCastInstruction") && 183 Arrays.equals(new Type[]{Type.getType(Object .class)}, Type.getArgumentTypes(methodDesc))) { 184 classReplacement.setCheckCastReplacement(replacement); 185 } 186 if (methodName.equals("createInstanceBuilder")) { 187 loadConstructor(classReplacement.getConstructorReplacements(), replacement, originalName); 188 } 189 } 190 } 191 192 private void loadConstructor(Map<String , ConstructorReplacement> replacements, 193 MemberReplacement replacement, String originalName) { 194 String constructorDesc = Type.getMethodDescriptor(Type.VOID_TYPE, Type.getArgumentTypes(replacement.getDesc())); 195 if (replacements.containsKey(constructorDesc)) { 196 return; 197 } 198 String owner = Type.getReturnType(replacement.getDesc()).getInternalName(); 199 ClassDescriptor classDescriptor = getClassDescriptor(owner); 200 if (classDescriptor == null) { 201 throw new TypeNotPresentException (owner, null); 202 } 203 List<MemberReplacement> arguments = new ArrayList<MemberReplacement>(); 204 MemberReplacement initializer = null; 205 for (MethodDescriptor descriptor : classDescriptor.getMethodDescriptors()) { 206 if (isArgument(descriptor)) { 207 arguments.add(new MemberReplacement(owner, descriptor.getName(), descriptor.getDesc())); 208 } else if (isInitializer(descriptor, originalName)) { 209 initializer = new MemberReplacement(owner, descriptor.getName(), descriptor.getDesc()); 210 } 211 } 212 Collections.sort(arguments, new Comparator<MemberReplacement>() { 213 public int compare(MemberReplacement o1, MemberReplacement o2) { 214 return o1.getName().compareTo(o2.getName()); 215 } 216 }); 217 List<Type> types = new ArrayList<Type>(); 218 for (MemberReplacement argument : arguments) { 219 types.add(Type.getReturnType(argument.getDesc())); 220 } 221 MemberReplacement constructor = new MemberReplacement(originalName, RuntimeTools.CONSTRUCTOR_NAME, 222 Type.getMethodDescriptor(Type.VOID_TYPE, types.toArray(new Type[0]))); 223 replacements.put(constructorDesc, new ConstructorReplacement(replacement, 224 arguments.toArray(new MemberReplacement[0]), constructor, initializer)); 225 } 226 227 private static boolean isArgument(MethodDescriptor descriptor) { 228 if (!descriptor.getName().startsWith("argument")) return false; 229 if (Type.getReturnType(descriptor.getDesc()) == Type.VOID_TYPE) return false; 230 if (Type.getArgumentTypes(descriptor.getDesc()).length > 0) return false; 231 return descriptor.isAccess(ACC_PUBLIC) && !descriptor.isAccess(ACC_STATIC); 232 } 233 234 private static boolean isInitializer(MethodDescriptor descriptor, String originalName) { 235 if (!descriptor.getName().equals("initialize")) return false; 236 if (Type.getReturnType(descriptor.getDesc()) != Type.VOID_TYPE) return false; 237 Type[] types = Type.getArgumentTypes(descriptor.getDesc()); 238 if (types.length != 1) return false; 239 if (!types[0].getInternalName().equals(originalName)) return false; 240 return descriptor.isAccess(ACC_PUBLIC) && !descriptor.isAccess(ACC_STATIC); 241 } 242 243 private static String createServiceName(String prefix, String suffix) { 244 int index = suffix.lastIndexOf('/'); 245 return prefix + suffix.substring(0, index + 1) + '_' + suffix.substring(index + 1); 246 } 247 248 private boolean isClassAvailable(String internalName) { 249 return getClassDescriptor(internalName) != null; 250 } 251 252 private ClassDescriptor getClassDescriptor(String internalName) { 253 byte[] bytecode = RuntimeTools.readResourceToByteArray( 254 ReplacementLocator.class, '/' + internalName + RuntimeTools.CLASS_EXTENSION); 255 if (bytecode == null) return null; 256 ClassDescriptor descriptor = new ClassDescriptor(ReplacementLocator.class, bytecode); 257 return !advanced && descriptor.isAnnotationPresent(Advanced.class) ? null : descriptor; 258 } 259 260 } 261 | Popular Tags |