001: /*
002: * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright notice. All rights reserved.
003: */
004: package com.tc.object.bytecode;
005:
006: import com.tc.asm.ClassAdapter;
007: import com.tc.asm.ClassVisitor;
008: import com.tc.asm.Label;
009: import com.tc.asm.MethodAdapter;
010: import com.tc.asm.MethodVisitor;
011: import com.tc.asm.Opcodes;
012: import com.tc.asm.Type;
013:
014: import java.lang.reflect.InvocationHandler;
015: import java.lang.reflect.Method;
016: import java.lang.reflect.Modifier;
017: import java.lang.reflect.Proxy;
018: import java.util.Collections;
019: import java.util.HashSet;
020: import java.util.Set;
021:
022: public class DuplicateMethodAdapter extends ClassAdapter implements
023: Opcodes {
024:
025: public static final String MANAGED_PREFIX = "_managed_";
026: public static final String UNMANAGED_PREFIX = ByteCodeUtil.TC_METHOD_PREFIX
027: + "unmanaged_";
028:
029: private final Set dontDupe;
030: private String ownerSlashes;
031: private String super Class;
032:
033: public DuplicateMethodAdapter(ClassVisitor cv) {
034: this (cv, Collections.EMPTY_SET);
035: }
036:
037: public DuplicateMethodAdapter(ClassVisitor cv, Set dontDupe) {
038: super (cv);
039: this .dontDupe = new HashSet(dontDupe);
040: this .dontDupe.add("readObject(Ljava/io/ObjectInputStream;)V");
041: this .dontDupe.add("writeObject(Ljava/io/ObjectOutputStream;)V");
042: }
043:
044: public void visit(int version, int access, String name,
045: String signature, String super Name, String[] interfaces) {
046: super .visit(version, access, name, signature, super Name,
047: interfaces);
048: this .ownerSlashes = name;
049: this .super Class = super Name;
050: }
051:
052: public MethodVisitor visitMethod(int access, String name,
053: String desc, String signature, String[] exceptions) {
054: if (name.startsWith(MANAGED_PREFIX)
055: || name.startsWith(UNMANAGED_PREFIX)) {
056: // make formatter sane
057: return super .visitMethod(access, name, desc, signature,
058: exceptions);
059: }
060:
061: if ("<init>".equals(name) || "<clinit>".equals(name)) {
062: // don't need any special indirection on initializers
063: return super .visitMethod(access, name, desc, signature,
064: exceptions);
065: }
066:
067: if (Modifier.isStatic(access) || Modifier.isNative(access)
068: || Modifier.isAbstract(access)) {
069: // make formatter sane
070: return super .visitMethod(access, name, desc, signature,
071: exceptions);
072: }
073:
074: if (dontDupe.contains(name + desc)) {
075: return super .visitMethod(access, name, desc, signature,
076: exceptions);
077: }
078:
079: createSwitchMethod(access, name, desc, signature, exceptions);
080:
081: MethodVisitor managed = new RewriteSelfTypeCalls(super
082: .visitMethod(access, MANAGED_PREFIX + name, desc,
083: signature, exceptions), new String[] {
084: ownerSlashes, super Class }, MANAGED_PREFIX);
085: MethodVisitor unmanaged = new RewriteSelfTypeCalls(super
086: .visitMethod(access, UNMANAGED_PREFIX + name, desc,
087: signature, exceptions), new String[] {
088: ownerSlashes, super Class }, UNMANAGED_PREFIX);
089:
090: return (MethodVisitor) Proxy.newProxyInstance(getClass()
091: .getClassLoader(), new Class[] { MethodVisitor.class },
092: new MulticastMethodVisitor(new MethodVisitor[] {
093: managed, unmanaged }));
094: }
095:
096: private void createSwitchMethod(int access, String name,
097: String desc, String signature, String[] exceptions) {
098: Type returnType = Type.getReturnType(desc);
099: boolean isVoid = returnType.equals(Type.VOID_TYPE);
100: MethodVisitor mv = super .visitMethod(access
101: & (~ACC_SYNCHRONIZED), name, desc, signature,
102: exceptions);
103: Label notManaged = new Label();
104: Label end = new Label();
105: mv.visitCode();
106: mv.visitVarInsn(ALOAD, 0);
107: mv.visitMethodInsn(INVOKEVIRTUAL, ownerSlashes,
108: ClassAdapterBase.MANAGED_METHOD,
109: "()Lcom/tc/object/TCObject;");
110: mv.visitJumpInsn(IFNULL, notManaged);
111: ByteCodeUtil.prepareStackForMethodCall(access, desc, mv);
112: mv.visitMethodInsn(INVOKESPECIAL, ownerSlashes, MANAGED_PREFIX
113: + name, desc);
114: if (!isVoid) {
115: mv.visitInsn(Type.getReturnType(desc).getOpcode(IRETURN));
116: } else {
117: mv.visitJumpInsn(GOTO, end);
118: }
119: mv.visitLabel(notManaged);
120: ByteCodeUtil.prepareStackForMethodCall(access, desc, mv);
121: mv.visitMethodInsn(INVOKESPECIAL, ownerSlashes,
122: UNMANAGED_PREFIX + name, desc);
123: if (!isVoid) {
124: mv.visitInsn(Type.getReturnType(desc).getOpcode(IRETURN));
125: } else {
126: mv.visitLabel(end);
127: mv.visitInsn(RETURN);
128: }
129:
130: mv.visitMaxs(0, 0);
131: mv.visitEnd();
132: }
133:
134: private class RewriteSelfTypeCalls extends MethodAdapter implements
135: Opcodes {
136:
137: private final String[] types;
138: private final String prefix;
139:
140: public RewriteSelfTypeCalls(MethodVisitor mv, String[] types,
141: String prefix) {
142: super (mv);
143: this .types = types;
144: this .prefix = prefix;
145: }
146:
147: public void visitMethodInsn(int opcode, String owner,
148: String name, String desc) {
149: if ("<init>".equals(name)) {
150: super .visitMethodInsn(opcode, owner, name, desc);
151: return;
152: }
153:
154: if (dontDupe.contains(name + desc)) {
155: super .visitMethodInsn(opcode, owner, name, desc);
156: return;
157: }
158:
159: if (opcode != INVOKESTATIC) {
160: boolean rewrite = false;
161: for (int i = 0; i < types.length; i++) {
162: if (types[i].equals(owner)) {
163: rewrite = true;
164: break;
165: }
166: }
167:
168: if (rewrite) {
169: name = prefix + name;
170: }
171: }
172:
173: super .visitMethodInsn(opcode, owner, name, desc);
174: }
175: }
176:
177: private static class MulticastMethodVisitor implements
178: InvocationHandler {
179:
180: private final MethodVisitor[] targets;
181:
182: MulticastMethodVisitor(MethodVisitor targets[]) {
183: this .targets = targets;
184: }
185:
186: public Object invoke(Object proxy, Method method, Object[] args)
187: throws Throwable {
188: Object rv = null;
189: for (int i = 0; i < targets.length; i++) {
190: rv = method.invoke(targets[i], args);
191: }
192: return rv;
193: }
194:
195: }
196:
197: }
|