01: /*
02: * All content copyright (c) 2003-2007 Terracotta, Inc., except as may otherwise be noted in a separate copyright
03: * notice. All rights reserved.
04: */
05: package com.tc.object.bytecode;
06:
07: import com.tc.asm.ClassVisitor;
08: import com.tc.asm.MethodAdapter;
09: import com.tc.asm.MethodVisitor;
10: import com.tc.asm.Opcodes;
11:
12: public class LinkedHashMapClassAdapter extends
13: ChangeClassNameHierarchyAdapter implements Opcodes {
14:
15: private String className;
16:
17: public LinkedHashMapClassAdapter(ClassVisitor cv) {
18: super (cv);
19: }
20:
21: public final void visit(int version, int access, String name,
22: String signature, String super Name, String[] interfaces) {
23: super .visit(version, access, name, signature, super Name,
24: interfaces);
25: this .className = name;
26: }
27:
28: public final MethodVisitor visitMethod(int access, String name,
29: String desc, String signature, String[] exceptions) {
30: MethodVisitor mv = super .visitMethod(access, name, desc,
31: signature, exceptions);
32:
33: if (this .className.equals("java/util/LinkedHashMap")
34: && name.equals("addEntry")) {
35: mv = new AddEntryMethodAdapter(mv);
36: }
37:
38: return mv;
39: }
40:
41: private final static class AddEntryMethodAdapter extends
42: MethodAdapter implements Opcodes {
43: public AddEntryMethodAdapter(MethodVisitor mv) {
44: super (mv);
45: }
46:
47: /**
48: * Wraps the argument to LinkedHashMap.addEntry(Map.Entry) in a HashMapTC.EntryWrapper prior to
49: * a call to LinkedHashMap.removeEldestEntry(...) inside the method.
50: * This fixes the ClassCastException thrown when an instrumented class extends java.util.LinkedHashMap
51: * and overrides the removeEldestEntry method.
52: */
53: public final void visitMethodInsn(int opcode, String owner,
54: String name, String desc) {
55: if ((opcode == INVOKEVIRTUAL)
56: && (owner.equals("java/util/LinkedHashMap")
57: && (name.equals("removeEldestEntry")) && (desc
58: .equals("(Ljava/util/Map$Entry;)Z")))) {
59: mv.visitInsn(POP);
60: mv.visitInsn(POP);
61: mv.visitVarInsn(ALOAD, 0);
62: mv.visitTypeInsn(NEW, "java/util/HashMap$EntryWrapper");
63: mv.visitInsn(DUP);
64: mv.visitVarInsn(ALOAD, 0);
65: mv.visitVarInsn(ALOAD, 5);
66: mv.visitMethodInsn(INVOKESPECIAL,
67: "java/util/HashMap$EntryWrapper", "<init>",
68: "(Ljava/util/HashMap;Ljava/util/Map$Entry;)V");
69: }
70: super.visitMethodInsn(opcode, owner, name, desc);
71: }
72: }
73: }
|