1 4 package com.tc.object.bytecode; 5 6 import com.tc.asm.ClassAdapter; 7 import com.tc.asm.ClassVisitor; 8 import com.tc.asm.Label; 9 import com.tc.asm.MethodAdapter; 10 import com.tc.asm.MethodVisitor; 11 import com.tc.asm.Opcodes; 12 import com.tc.asm.Type; 13 14 import java.lang.reflect.InvocationHandler ; 15 import java.lang.reflect.Method ; 16 import java.lang.reflect.Modifier ; 17 import java.lang.reflect.Proxy ; 18 import java.util.Collections ; 19 import java.util.HashSet ; 20 import java.util.Set ; 21 22 public class DuplicateMethodAdapter extends ClassAdapter implements Opcodes { 23 24 public static final String MANAGED_PREFIX = "_managed_"; 25 public static final String UNMANAGED_PREFIX = ByteCodeUtil.TC_METHOD_PREFIX + "unmanaged_"; 26 27 private final Set dontDupe; 28 private String ownerSlashes; 29 private String superClass; 30 31 public DuplicateMethodAdapter(ClassVisitor cv) { 32 this(cv, Collections.EMPTY_SET); 33 } 34 35 public DuplicateMethodAdapter(ClassVisitor cv, Set dontDupe) { 36 super(cv); 37 this.dontDupe = new HashSet (dontDupe); 38 this.dontDupe.add("readObject(Ljava/io/ObjectInputStream;)V"); 39 this.dontDupe.add("writeObject(Ljava/io/ObjectOutputStream;)V"); 40 } 41 42 public void visit(int version, int access, String name, String signature, String superName, String [] interfaces) { 43 super.visit(version, access, name, signature, superName, interfaces); 44 this.ownerSlashes = name; 45 this.superClass = superName; 46 } 47 48 public MethodVisitor visitMethod(int access, String name, String desc, String signature, String [] exceptions) { 49 if (name.startsWith(MANAGED_PREFIX) || name.startsWith(UNMANAGED_PREFIX)) { 50 return super.visitMethod(access, name, desc, signature, exceptions); 52 } 53 54 if ("<init>".equals(name) || "<clinit>".equals(name)) { 55 return super.visitMethod(access, name, desc, signature, exceptions); 57 } 58 59 if (Modifier.isStatic(access) || Modifier.isNative(access) || Modifier.isAbstract(access)) { 60 return super.visitMethod(access, name, desc, signature, exceptions); 62 } 63 64 if (dontDupe.contains(name + desc)) { return super.visitMethod(access, name, desc, signature, exceptions); } 65 66 createSwitchMethod(access, name, desc, signature, exceptions); 67 68 MethodVisitor managed = new RewriteSelfTypeCalls(super.visitMethod(access, MANAGED_PREFIX + name, desc, signature, 69 exceptions), new String [] { ownerSlashes, 70 superClass }, MANAGED_PREFIX); 71 MethodVisitor unmanaged = new RewriteSelfTypeCalls(super.visitMethod(access, UNMANAGED_PREFIX + name, desc, 72 signature, exceptions), new String [] { 73 ownerSlashes, superClass }, UNMANAGED_PREFIX); 74 75 return (MethodVisitor) Proxy 76 .newProxyInstance(getClass().getClassLoader(), new Class [] { MethodVisitor.class }, 77 new MulticastMethodVisitor(new MethodVisitor[] { managed, unmanaged })); 78 } 79 80 private void createSwitchMethod(int access, String name, String desc, String signature, String [] exceptions) { 81 Type returnType = Type.getReturnType(desc); 82 boolean isVoid = returnType.equals(Type.VOID_TYPE); 83 MethodVisitor mv = super.visitMethod(access & (~ACC_SYNCHRONIZED), name, desc, signature, exceptions); 84 Label notManaged = new Label(); 85 Label end = new Label(); 86 mv.visitCode(); 87 mv.visitVarInsn(ALOAD, 0); 88 mv.visitMethodInsn(INVOKEVIRTUAL, ownerSlashes, ClassAdapterBase.MANAGED_METHOD, "()Lcom/tc/object/TCObject;"); 89 mv.visitJumpInsn(IFNULL, notManaged); 90 ByteCodeUtil.prepareStackForMethodCall(access, desc, mv); 91 mv.visitMethodInsn(INVOKESPECIAL, ownerSlashes, MANAGED_PREFIX + name, desc); 92 if (!isVoid) { 93 mv.visitInsn(Type.getReturnType(desc).getOpcode(IRETURN)); 94 } else { 95 mv.visitJumpInsn(GOTO, end); 96 } 97 mv.visitLabel(notManaged); 98 ByteCodeUtil.prepareStackForMethodCall(access, desc, mv); 99 mv.visitMethodInsn(INVOKESPECIAL, ownerSlashes, UNMANAGED_PREFIX + name, desc); 100 if (!isVoid) { 101 mv.visitInsn(Type.getReturnType(desc).getOpcode(IRETURN)); 102 } else { 103 mv.visitLabel(end); 104 mv.visitInsn(RETURN); 105 } 106 107 mv.visitMaxs(0, 0); 108 mv.visitEnd(); 109 } 110 111 private class RewriteSelfTypeCalls extends MethodAdapter implements Opcodes { 112 113 private final String [] types; 114 private final String prefix; 115 116 public RewriteSelfTypeCalls(MethodVisitor mv, String [] types, String prefix) { 117 super(mv); 118 this.types = types; 119 this.prefix = prefix; 120 } 121 122 public void visitMethodInsn(int opcode, String owner, String name, String desc) { 123 if ("<init>".equals(name)) { 124 super.visitMethodInsn(opcode, owner, name, desc); 125 return; 126 } 127 128 if (dontDupe.contains(name + desc)) { 129 super.visitMethodInsn(opcode, owner, name, desc); 130 return; 131 } 132 133 if (opcode != INVOKESTATIC) { 134 boolean rewrite = false; 135 for (int i = 0; i < types.length; i++) { 136 if (types[i].equals(owner)) { 137 rewrite = true; 138 break; 139 } 140 } 141 142 if (rewrite) { 143 name = prefix + name; 144 } 145 } 146 147 super.visitMethodInsn(opcode, owner, name, desc); 148 } 149 } 150 151 private static class MulticastMethodVisitor implements InvocationHandler { 152 153 private final MethodVisitor[] targets; 154 155 MulticastMethodVisitor(MethodVisitor targets[]) { 156 this.targets = targets; 157 } 158 159 public Object invoke(Object proxy, Method method, Object [] args) throws Throwable { 160 Object rv = null; 161 for (int i = 0; i < targets.length; i++) { 162 rv = method.invoke(targets[i], args); 163 } 164 return rv; 165 } 166 167 } 168 169 } 170 | Popular Tags |