001: /*
002: * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright
003: * notice. All rights reserved.
004: */
005: package com.tc.object.bytecode;
006:
007: import com.tc.asm.ClassAdapter;
008: import com.tc.asm.ClassVisitor;
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: public class JavaUtilWeakHashMapAdapter extends ClassAdapter implements
015: Opcodes, ClassAdapterFactory {
016: private static final String HASH_MAP_CLASS = "java/util/HashMap";
017: private static final String WEAK_HASH_MAP_CLASS = "java/util/WeakHashMap";
018:
019: private static final int SYNTHETIC_METHOD_ACCESS = ACC_PROTECTED
020: | ACC_SYNTHETIC;
021:
022: private static final String HASH_MAP_HASH_METHOD_NAME = "hash";
023:
024: private static final String TC_HASH_METHOD_NAME = ByteCodeUtil.TC_METHOD_PREFIX
025: + "hash";
026: private static final String HASH_METHOD_DESCRIPTION = "(Ljava/lang/Object;)I";
027:
028: private static final String TC_EQUAL_METHOD_NAME = ByteCodeUtil.TC_METHOD_PREFIX
029: + "equal";
030: private static final String EQ_METHOD_DESCRIPTION = "(Ljava/lang/Object;Ljava/lang/Object;)Z";
031:
032: private static final String EQ_METHOD_NAME = "eq";
033:
034: private String hashMapHashMethodDesc = null;
035:
036: public JavaUtilWeakHashMapAdapter() {
037: super (null);
038: }
039:
040: private JavaUtilWeakHashMapAdapter(ClassVisitor cv,
041: ClassLoader caller) {
042: super (cv);
043: }
044:
045: public ClassAdapter create(ClassVisitor visitor, ClassLoader loader) {
046: return new JavaUtilWeakHashMapAdapter(visitor, loader);
047: }
048:
049: public void visitEnd() {
050: generateSyntheticHashMethod();
051: generateSyntheticEqualMethod();
052: super .visitEnd();
053: }
054:
055: private void generateSyntheticHashMethod() {
056: MethodVisitor mv = super .visitMethod(SYNTHETIC_METHOD_ACCESS,
057: TC_HASH_METHOD_NAME, HASH_METHOD_DESCRIPTION, null,
058: null);
059: mv.visitCode();
060: mv.visitVarInsn(ALOAD, 1);
061:
062: if (hashMapHashMethodDesc == null) {
063: throw new AssertionError();
064: }
065: Type[] args = Type.getArgumentTypes(hashMapHashMethodDesc);
066: if (args.length != 1) {
067: throw new AssertionError(
068: "unexpected HashMap.hash() signature: "
069: + hashMapHashMethodDesc);
070: }
071:
072: if (args[0].getSort() == Type.INT) {
073: mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object",
074: "hashCode", "()I");
075: } else if (!args[0].getInternalName()
076: .equals("java/lang/Object")) {
077: throw new AssertionError("unexpected type: " + args[0]);
078: }
079:
080: mv.visitMethodInsn(INVOKESTATIC, HASH_MAP_CLASS,
081: HASH_MAP_HASH_METHOD_NAME, hashMapHashMethodDesc);
082: mv.visitInsn(IRETURN);
083: mv.visitMaxs(0, 0);
084: mv.visitEnd();
085: }
086:
087: private void generateSyntheticEqualMethod() {
088: MethodVisitor mv = super
089: .visitMethod(SYNTHETIC_METHOD_ACCESS,
090: TC_EQUAL_METHOD_NAME, EQ_METHOD_DESCRIPTION,
091: null, null);
092: mv.visitCode();
093: mv.visitVarInsn(ALOAD, 1);
094: mv.visitVarInsn(ALOAD, 2);
095: mv.visitMethodInsn(INVOKESTATIC, WEAK_HASH_MAP_CLASS,
096: EQ_METHOD_NAME, EQ_METHOD_DESCRIPTION);
097: mv.visitInsn(IRETURN);
098: mv.visitMaxs(1, 2);
099: mv.visitEnd();
100: }
101:
102: public MethodVisitor visitMethod(int access, String name,
103: String desc, String signature, String[] exceptions) {
104: MethodVisitor mv = super .visitMethod(access, name, desc,
105: signature, exceptions);
106: return new JavaUtilWeakHashMapMethodAdapter(mv);
107: }
108:
109: private class JavaUtilWeakHashMapMethodAdapter extends
110: MethodAdapter {
111: public JavaUtilWeakHashMapMethodAdapter(MethodVisitor mv) {
112: super (mv);
113: }
114:
115: public void visitMethodInsn(int opcode, String owner,
116: String name, String desc) {
117: if ((INVOKEVIRTUAL == opcode)
118: && "java/lang/Object".equals(owner)
119: && "hashCode".equals(name)) {
120: return;
121: }
122:
123: if (INVOKESTATIC == opcode && HASH_MAP_CLASS.equals(owner)
124: && HASH_MAP_HASH_METHOD_NAME.equals(name)) {
125: hashMapHashMethodDesc = desc;
126: ByteCodeUtil.pushThis(this);
127: super.visitInsn(SWAP);
128: super.visitMethodInsn(INVOKEVIRTUAL,
129: WEAK_HASH_MAP_CLASS, TC_HASH_METHOD_NAME,
130: HASH_METHOD_DESCRIPTION);
131: } else if (INVOKESTATIC == opcode
132: && WEAK_HASH_MAP_CLASS.equals(owner)
133: && EQ_METHOD_NAME.equals(name)
134: && EQ_METHOD_DESCRIPTION.equals(desc)) {
135: ByteCodeUtil.pushThis(mv);
136: super.visitInsn(SWAP);
137: super.visitInsn(DUP2_X1);
138: super.visitInsn(POP2);
139: super.visitInsn(SWAP);
140: super
141: .visitMethodInsn(INVOKEVIRTUAL,
142: WEAK_HASH_MAP_CLASS,
143: TC_EQUAL_METHOD_NAME, desc);
144: } else {
145: super.visitMethodInsn(opcode, owner, name, desc);
146: }
147: }
148: }
149: }
|