KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > tc > object > bytecode > DuplicateMethodAdapter


1 /*
2  * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright notice. All rights reserved.
3  */

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 JavaDoc;
15 import java.lang.reflect.Method JavaDoc;
16 import java.lang.reflect.Modifier JavaDoc;
17 import java.lang.reflect.Proxy JavaDoc;
18 import java.util.Collections JavaDoc;
19 import java.util.HashSet JavaDoc;
20 import java.util.Set JavaDoc;
21
22 public class DuplicateMethodAdapter extends ClassAdapter implements Opcodes {
23
24   public static final String JavaDoc MANAGED_PREFIX = "_managed_";
25   public static final String JavaDoc UNMANAGED_PREFIX = ByteCodeUtil.TC_METHOD_PREFIX + "unmanaged_";
26
27   private final Set JavaDoc dontDupe;
28   private String JavaDoc ownerSlashes;
29   private String JavaDoc superClass;
30
31   public DuplicateMethodAdapter(ClassVisitor cv) {
32     this(cv, Collections.EMPTY_SET);
33   }
34
35   public DuplicateMethodAdapter(ClassVisitor cv, Set JavaDoc dontDupe) {
36     super(cv);
37     this.dontDupe = new HashSet JavaDoc(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 JavaDoc name, String JavaDoc signature, String JavaDoc superName, String JavaDoc[] 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 JavaDoc name, String JavaDoc desc, String JavaDoc signature, String JavaDoc[] exceptions) {
49     if (name.startsWith(MANAGED_PREFIX) || name.startsWith(UNMANAGED_PREFIX)) {
50       // make formatter sane
51
return super.visitMethod(access, name, desc, signature, exceptions);
52     }
53
54     if ("<init>".equals(name) || "<clinit>".equals(name)) {
55       // don't need any special indirection on initializers
56
return super.visitMethod(access, name, desc, signature, exceptions);
57     }
58
59     if (Modifier.isStatic(access) || Modifier.isNative(access) || Modifier.isAbstract(access)) {
60       // make formatter sane
61
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 JavaDoc[] { ownerSlashes,
70         superClass }, MANAGED_PREFIX);
71     MethodVisitor unmanaged = new RewriteSelfTypeCalls(super.visitMethod(access, UNMANAGED_PREFIX + name, desc,
72                                                                          signature, exceptions), new String JavaDoc[] {
73         ownerSlashes, superClass }, UNMANAGED_PREFIX);
74
75     return (MethodVisitor) Proxy
76         .newProxyInstance(getClass().getClassLoader(), new Class JavaDoc[] { MethodVisitor.class },
77                           new MulticastMethodVisitor(new MethodVisitor[] { managed, unmanaged }));
78   }
79
80   private void createSwitchMethod(int access, String JavaDoc name, String JavaDoc desc, String JavaDoc signature, String JavaDoc[] 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 JavaDoc[] types;
114     private final String JavaDoc prefix;
115
116     public RewriteSelfTypeCalls(MethodVisitor mv, String JavaDoc[] types, String JavaDoc prefix) {
117       super(mv);
118       this.types = types;
119       this.prefix = prefix;
120     }
121
122     public void visitMethodInsn(int opcode, String JavaDoc owner, String JavaDoc name, String JavaDoc 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 JavaDoc {
152
153     private final MethodVisitor[] targets;
154
155     MulticastMethodVisitor(MethodVisitor targets[]) {
156       this.targets = targets;
157     }
158
159     public Object JavaDoc invoke(Object JavaDoc proxy, Method JavaDoc method, Object JavaDoc[] args) throws Throwable JavaDoc {
160       Object JavaDoc 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