1 32 package net.sf.retrotranslator.transformer; 33 34 import java.util.*; 35 import net.sf.retrotranslator.runtime.asm.*; 36 import static net.sf.retrotranslator.runtime.asm.Opcodes.*; 37 38 41 class ClassLiteralVisitor extends ClassAdapter { 42 43 private static final Map<Integer , Integer > primitiveTypes = getPrimitiveTypes(); 44 45 private Set<String > currentFieldNames = new HashSet<String >(); 46 private Set<String > syntheticFieldNames = new HashSet<String >(); 47 private String currentClassName; 48 private boolean isInterface; 49 50 public ClassLiteralVisitor(final ClassVisitor cv) { 51 super(cv); 52 } 53 54 public void visit(final int version, final int access, final String name, final String signature, final String superName, final String [] interfaces) { 55 currentClassName = name; 56 isInterface = (access & ACC_INTERFACE) != 0; 57 super.visit(version, access, name, signature, superName, interfaces); 58 } 59 60 public void visitEnd() { 61 for (String fieldName : syntheticFieldNames) { 62 if (!currentFieldNames.contains(fieldName)) { 63 cv.visitField(ACC_STATIC + ACC_SYNTHETIC, fieldName, Type.getDescriptor(Class .class), null, null).visitEnd(); 64 } 65 } 66 super.visitEnd(); 67 } 68 69 public FieldVisitor visitField(final int access, final String name, final String desc, final String signature, final Object value) { 70 currentFieldNames.add(name); 71 return super.visitField(access, name, desc, signature, value); 72 } 73 74 public MethodVisitor visitMethod(final int access, final String name, final String desc, final String signature, final String [] exceptions) { 75 MethodVisitor visitor = super.visitMethod(access, name, desc, signature, exceptions); 76 return visitor == null ? null : new MethodAdapter(visitor) { 77 78 public void visitLdcInsn(final Object cst) { 79 if (cst instanceof Type) { 80 visitClassLiteral((Type) cst); 81 } else { 82 super.visitLdcInsn(cst); 83 } 84 } 85 86 private void visitClassLiteral(Type type) { 87 if (isInterface) { 88 loadClassLiteral(type); 89 return; 90 } 91 String fieldName = getFieldName(type); 92 syntheticFieldNames.add(fieldName); 93 mv.visitFieldInsn(GETSTATIC, currentClassName, fieldName, Type.getDescriptor(Class .class)); 94 mv.visitInsn(DUP); 95 Label label = new Label(); 96 visitJumpInsn(IFNONNULL, label); 97 mv.visitInsn(POP); 98 loadClassLiteral(type); 99 mv.visitInsn(DUP); 100 visitFieldInsn(PUTSTATIC, currentClassName, fieldName, Type.getDescriptor(Class .class)); 101 visitLabel(label); 102 } 103 104 private void loadClassLiteral(Type type) { 105 mv.visitInsn(ICONST_0); 106 visitNewArray(type); 107 mv.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(Object .class), 108 "getClass", TransformerTools.descriptor(Class .class)); 109 if (type.getSort() != Type.ARRAY) { 110 mv.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(Class .class), 111 "getComponentType", TransformerTools.descriptor(Class .class)); 112 } 113 } 114 115 private void visitNewArray(Type type) { 116 if (type.getSort() != Type.ARRAY) { 117 mv.visitTypeInsn(ANEWARRAY, type.getInternalName()); 118 } else if (type.getDimensions() != 1) { 119 mv.visitTypeInsn(ANEWARRAY, type.toString().substring(1)); 120 } else { 121 Type elementType = type.getElementType(); 122 if (elementType.getSort() == Type.OBJECT) { 123 mv.visitTypeInsn(ANEWARRAY, elementType.getInternalName()); 124 } else { 125 mv.visitIntInsn(NEWARRAY, primitiveTypes.get(elementType.getSort())); 126 } 127 } 128 } 129 130 }; 131 } 132 133 private static String getFieldName(Type type) { 134 String var = type.getDescriptor(); 135 if (var.startsWith("L")) { 136 var = "class$" + var.substring(1); 137 } else if (var.startsWith("[")) { 138 var = "array$" + var.substring(1); 139 } 140 if (var.endsWith(";")) { 141 var = var.substring(0, var.length() - 1); 142 } 143 return var.replace('[', '$').replace('/', '$'); 144 } 145 146 private static Map<Integer , Integer > getPrimitiveTypes() { 147 Map<Integer , Integer > types = new HashMap<Integer , Integer >(); 148 types.put(Type.BOOLEAN, T_BOOLEAN); 149 types.put(Type.CHAR, T_CHAR); 150 types.put(Type.FLOAT, T_FLOAT); 151 types.put(Type.DOUBLE, T_DOUBLE); 152 types.put(Type.BYTE, T_BYTE); 153 types.put(Type.SHORT, T_SHORT); 154 types.put(Type.INT, T_INT); 155 types.put(Type.LONG, T_LONG); 156 return types; 157 } 158 } 159 | Popular Tags |