0001: /*
0002: * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright
0003: * notice. All rights reserved.
0004: */
0005: package com.tc.object.bytecode;
0006:
0007: import com.tc.asm.ClassAdapter;
0008: import com.tc.asm.ClassVisitor;
0009: import com.tc.asm.Label;
0010: import com.tc.asm.MethodAdapter;
0011: import com.tc.asm.MethodVisitor;
0012: import com.tc.asm.Opcodes;
0013: import com.tc.asm.Type;
0014: import com.tc.asm.commons.LocalVariablesSorter;
0015: import com.tc.util.runtime.Vm;
0016:
0017: public class JavaUtilConcurrentHashMapAdapter extends ClassAdapter
0018: implements Opcodes {
0019: private final static String CONCURRENT_HASH_MAP_SLASH = "java/util/concurrent/ConcurrentHashMap";
0020: private final static String TC_REHASH_METHOD_NAME = ByteCodeUtil.TC_METHOD_PREFIX
0021: + "rehash";
0022: private final static String TC_REHASH_METHOD_DESC = "()V";
0023: private final static String TC_CLEAR_METHOD_NAME = ByteCodeUtil.TC_METHOD_PREFIX
0024: + "clear";
0025: private final static String TC_CLEAR_METHOD_DESC = "()V";
0026: private final static String TC_ORIG_GET_METHOD_NAME = ByteCodeUtil.TC_METHOD_PREFIX
0027: + "origGet";
0028: private final static String TC_ORIG_GET_METHOD_DESC = "(Ljava/lang/Object;)Ljava/lang/Object;";
0029: private final static String TC_PUT_METHOD_NAME = ByteCodeUtil.TC_METHOD_PREFIX
0030: + "put";
0031: private final static String TC_PUT_METHOD_DESC = "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;";
0032: private final static String TC_HASH_METHOD_NAME = ByteCodeUtil.TC_METHOD_PREFIX
0033: + "hash";
0034: private final static String TC_HASH_METHOD_DESC = "(Ljava/lang/Object;)I";
0035: private final static String TC_HASH_METHOD_CHECK_DESC = "(Ljava/lang/Object;Z)I";
0036: private final static String TC_IS_DSO_HASH_REQUIRED_METHOD_NAME = ByteCodeUtil.TC_METHOD_PREFIX
0037: + "isDsoHashRequired";
0038: private final static String TC_IS_DSO_HASH_REQUIRED_METHOD_DESC = "(Ljava/lang/Object;)Z";
0039: private final static String TC_FULLY_READLOCK_METHOD_NAME = ByteCodeUtil.TC_METHOD_PREFIX
0040: + "fullyReadLock";
0041: private final static String TC_FULLY_READLOCK_METHOD_DESC = "()V";
0042: private final static String TC_FULLY_READUNLOCK_METHOD_NAME = ByteCodeUtil.TC_METHOD_PREFIX
0043: + "fullyReadUnlock";
0044: private final static String TC_FULLY_READUNLOCK_METHOD_DESC = "()V";
0045: private final static String TC_APPLICATOR_PUT_METHOD_NAME = "__tc_applicator_put";
0046: private final static String TC_APPLICATOR_PUT_METHOD_DESC = "(Ljava/lang/Object;Ljava/lang/Object;)V";
0047: private final static String TC_APPLICATOR_REMOVE_METHOD_NAME = "__tc_applicator_remove";
0048: private final static String TC_APPLICATOR_REMOVE_METHOD_DESC = "(Ljava/lang/Object;)V";
0049: private final static String TC_REMOVE_LOGICAL_METHOD_NAME = "__tc_remove_logical";
0050: private final static String TC_REMOVE_LOGICAL_METHOD_DESC = "(Ljava/lang/Object;)V";
0051: private final static String HASH_METHOD_NAME = "hash";
0052:
0053: public JavaUtilConcurrentHashMapAdapter(ClassVisitor cv) {
0054: super (cv);
0055: }
0056:
0057: /**
0058: * We need to instrument the size(), isEmpty(), and containsValue() methods because the original implementation in JDK
0059: * 1.5 has an optimization which uses a volatile variable and does not require locking of the segments. It resorts to
0060: * locking only after several unsuccessful attempts. For instance, the original implementation of the size() method
0061: * looks at the count and mod_count volatile variables of each segment and makes sure that there is no update during
0062: * executing the size() method. If it detects any update while the size() method is being executed, it will resort to
0063: * locking. Since ConcurrentHashMap is supported logically, it is possible that while the application is obtaining the
0064: * size of the map while there are still pending updates. Therefore, when ConcurrentHashMap is shared, the
0065: * instrumented code will always use an locking scheme to make sure all updates are applied before returning the size.
0066: * The same is true for isEmpty() and containsValue methods().
0067: */
0068: public MethodVisitor visitMethod(int access, String name,
0069: String desc, String signature, String[] exceptions) {
0070: if ("size".equals(name) && "()I".equals(desc)) {
0071: return addWrapperMethod(access, name, desc, signature,
0072: exceptions);
0073: } else if ("isEmpty".equals(name) && "()Z".equals(desc)) {
0074: return addWrapperMethod(access, name, desc, signature,
0075: exceptions);
0076: } else if ("containsValue".equals(name)
0077: && "(Ljava/lang/Object;)Z".equals(desc)) {
0078: return addWrapperMethod(access, name, desc, signature,
0079: exceptions);
0080: }
0081:
0082: MethodVisitor mv = super .visitMethod(access, name, desc,
0083: signature, exceptions);
0084: if ("entrySet".equals(name) && "()Ljava/util/Set;".equals(desc)) {
0085: return new EntrySetMethodAdapter(mv);
0086: } else if ("segmentFor".equals(name)
0087: && "(I)Ljava/util/concurrent/ConcurrentHashMap$Segment;"
0088: .equals(desc)) {
0089: return rewriteSegmentForMethod(mv);
0090: } else if ("get".equals(name)
0091: && "(Ljava/lang/Object;)Ljava/lang/Object;"
0092: .equals(desc)) {
0093: return new MulticastMethodVisitor(new MethodVisitor[] {
0094: new OriginalGetMethodAdapter(super .visitMethod(
0095: ACC_SYNTHETIC | ACC_PUBLIC,
0096: TC_ORIG_GET_METHOD_NAME,
0097: TC_ORIG_GET_METHOD_DESC, null, null)),
0098: new ConcurrentHashMapMethodAdapter(
0099: new GetMethodAdapter(mv)) });
0100: }
0101:
0102: if ("put".equals(name)
0103: && "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"
0104: .equals(desc)) {
0105: mv = new MulticastMethodVisitor(
0106: new MethodVisitor[] {
0107: mv,
0108: new ApplicatorPutMethodAdapter(
0109: super
0110: .visitMethod(
0111: ACC_SYNTHETIC
0112: | ACC_PUBLIC,
0113: TC_APPLICATOR_PUT_METHOD_NAME,
0114: TC_APPLICATOR_PUT_METHOD_DESC,
0115: null, null)) });
0116: } else if ("containsKey".equals(name)
0117: && "(Ljava/lang/Object;)Z".equals(desc)) {
0118: mv = new ContainsKeyMethodAdapter(mv);
0119: } else if ("remove".equals(name)
0120: && "(Ljava/lang/Object;)Ljava/lang/Object;"
0121: .equals(desc)) {
0122: mv = new MulticastMethodVisitor(
0123: new MethodVisitor[] {
0124: new SimpleRemoveMethodAdapter(mv),
0125: new ApplicatorRemoveMethodAdapter(
0126: super
0127: .visitMethod(
0128: ACC_SYNTHETIC
0129: | ACC_PUBLIC,
0130: TC_APPLICATOR_REMOVE_METHOD_NAME,
0131: TC_APPLICATOR_REMOVE_METHOD_DESC,
0132: null, null)),
0133: new RemoveLogicalMethodAdapter(
0134: super
0135: .visitMethod(
0136: ACC_SYNTHETIC
0137: | ACC_PUBLIC,
0138: TC_REMOVE_LOGICAL_METHOD_NAME,
0139: TC_REMOVE_LOGICAL_METHOD_DESC,
0140: null, null)) });
0141: } else if ("remove".equals(name)
0142: && "(Ljava/lang/Object;Ljava/lang/Object;)Z"
0143: .equals(desc)) {
0144: mv = new RemoveMethodAdapter(mv);
0145: } else if ("replace".equals(name)
0146: && "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"
0147: .equals(desc)) {
0148: mv = new SimpleReplaceMethodAdapter(mv);
0149: } else if ("replace".equals(name)
0150: && "(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Z"
0151: .equals(desc)) {
0152: mv = new ReplaceMethodAdapter(mv);
0153: } else if ("writeObject".equals(name)
0154: && "(Ljava/io/ObjectOutputStream;)V".equals(desc)) {
0155: mv = new JavaUtilConcurrentHashMapLazyValuesMethodAdapter(
0156: access, desc, mv, false);
0157: }
0158:
0159: return new ConcurrentHashMapMethodAdapter(mv);
0160: }
0161:
0162: public void visitEnd() {
0163: createTCPutMethod();
0164: createTCRehashAndSupportMethods();
0165: createTCFullyReadLockMethod();
0166: createTCFullyReadUnlockMethod();
0167:
0168: super .visitEnd();
0169: }
0170:
0171: private String getNewName(String methodName) {
0172: return ByteCodeUtil.TC_METHOD_PREFIX + methodName;
0173: }
0174:
0175: private MethodVisitor addWrapperMethod(int access, String name,
0176: String desc, String signature, String[] exceptions) {
0177: createWrapperMethod(access, name, desc, signature, exceptions);
0178: return new TurnIntoReadLocksMethodAdapter(cv.visitMethod(
0179: ACC_PRIVATE, getNewName(name), desc, signature,
0180: exceptions));
0181: }
0182:
0183: private void createWrapperMethod(int access, String name,
0184: String desc, String signature, String[] exceptions) {
0185: Type[] params = Type.getArgumentTypes(desc);
0186: Type returnType = Type.getReturnType(desc);
0187:
0188: LocalVariablesSorter mv = new LocalVariablesSorter(access,
0189: desc, cv.visitMethod(access, name, desc, signature,
0190: exceptions));
0191:
0192: mv.visitCode();
0193: Label l0 = new Label();
0194: Label l1 = new Label();
0195: Label l2 = new Label();
0196: mv.visitTryCatchBlock(l0, l1, l2, null);
0197:
0198: Label l3 = new Label();
0199: mv.visitLabel(l3);
0200: mv.visitVarInsn(ALOAD, 0);
0201: mv.visitMethodInsn(INVOKESTATIC,
0202: "com/tc/object/bytecode/ManagerUtil", "isManaged",
0203: "(Ljava/lang/Object;)Z");
0204: int isManagedVar = mv.newLocal(Type.BOOLEAN_TYPE);
0205: mv.visitVarInsn(ISTORE, isManagedVar);
0206: Label l4 = new Label();
0207: mv.visitLabel(l4);
0208: mv.visitVarInsn(ILOAD, isManagedVar);
0209: mv.visitJumpInsn(IFEQ, l0);
0210: mv.visitVarInsn(ALOAD, 0);
0211: mv.visitMethodInsn(INVOKESPECIAL, CONCURRENT_HASH_MAP_SLASH,
0212: TC_FULLY_READLOCK_METHOD_NAME,
0213: TC_FULLY_READLOCK_METHOD_DESC);
0214: mv.visitLabel(l0);
0215:
0216: mv.visitVarInsn(ALOAD, 0);
0217: for (int i = 0; i < params.length; i++) {
0218: mv.visitVarInsn(params[i].getOpcode(ILOAD), i + 1);
0219: }
0220: mv.visitMethodInsn(INVOKESPECIAL, CONCURRENT_HASH_MAP_SLASH,
0221: getNewName(name), desc);
0222: int valueVar = mv.newLocal(returnType);
0223: mv.visitVarInsn(returnType.getOpcode(ISTORE), valueVar);
0224:
0225: mv.visitLabel(l1);
0226: mv.visitVarInsn(ILOAD, isManagedVar);
0227: Label l6 = new Label();
0228: mv.visitJumpInsn(IFEQ, l6);
0229: Label l7 = new Label();
0230: mv.visitLabel(l7);
0231: mv.visitVarInsn(ALOAD, 0);
0232: mv.visitMethodInsn(INVOKESPECIAL, CONCURRENT_HASH_MAP_SLASH,
0233: TC_FULLY_READUNLOCK_METHOD_NAME,
0234: TC_FULLY_READUNLOCK_METHOD_DESC);
0235: mv.visitLabel(l6);
0236: mv.visitVarInsn(returnType.getOpcode(ILOAD), valueVar);
0237: mv.visitInsn(returnType.getOpcode(IRETURN));
0238:
0239: mv.visitLabel(l2);
0240: int exceptionVar = mv.newLocal(Type
0241: .getObjectType("java/lang/Exception"));
0242: mv.visitVarInsn(ASTORE, exceptionVar);
0243: mv.visitVarInsn(ILOAD, isManagedVar);
0244: Label l9 = new Label();
0245: mv.visitJumpInsn(IFEQ, l9);
0246: mv.visitVarInsn(ALOAD, 0);
0247: mv.visitMethodInsn(INVOKESPECIAL, CONCURRENT_HASH_MAP_SLASH,
0248: TC_FULLY_READUNLOCK_METHOD_NAME,
0249: TC_FULLY_READUNLOCK_METHOD_DESC);
0250: mv.visitLabel(l9);
0251: mv.visitVarInsn(ALOAD, exceptionVar);
0252: mv.visitInsn(ATHROW);
0253: Label l11 = new Label();
0254: mv.visitLabel(l11);
0255: mv.visitLocalVariable("this",
0256: "Ljava/util/concurrent/ConcurrentHashMap;",
0257: "Ljava/util/concurrent/ConcurrentHashMap<TK;TV;>;", l3,
0258: l11, 0);
0259: mv.visitLocalVariable("value", "Ljava/lang/Object;", null, l3,
0260: l11, valueVar);
0261: mv.visitLocalVariable("isManaged", "Z", null, l4, l11,
0262: isManagedVar);
0263: mv.visitMaxs(2, 5);
0264: mv.visitEnd();
0265: }
0266:
0267: private MethodVisitor rewriteSegmentForMethod(MethodVisitor mv) {
0268: mv.visitCode();
0269: Label l0 = new Label();
0270: mv.visitLabel(l0);
0271: mv.visitVarInsn(ILOAD, 1);
0272: mv.visitMethodInsn(INVOKESTATIC, "java/lang/Math", "abs",
0273: "(I)I");
0274: mv.visitVarInsn(ISTORE, 1);
0275: Label l1 = new Label();
0276: mv.visitLabel(l1);
0277: mv.visitVarInsn(ALOAD, 0);
0278: mv.visitFieldInsn(GETFIELD, CONCURRENT_HASH_MAP_SLASH,
0279: "segments",
0280: "[Ljava/util/concurrent/ConcurrentHashMap$Segment;");
0281: mv.visitVarInsn(ILOAD, 1);
0282: mv.visitVarInsn(ALOAD, 0);
0283: mv.visitFieldInsn(GETFIELD, CONCURRENT_HASH_MAP_SLASH,
0284: "segments",
0285: "[Ljava/util/concurrent/ConcurrentHashMap$Segment;");
0286: mv.visitInsn(ARRAYLENGTH);
0287: mv.visitInsn(IREM);
0288: mv.visitInsn(AALOAD);
0289: mv.visitInsn(ARETURN);
0290: Label l2 = new Label();
0291: mv.visitLabel(l2);
0292: mv.visitMaxs(0, 0);
0293: mv.visitEnd();
0294: return null;
0295: }
0296:
0297: private void createTCFullyReadLockMethod() {
0298: MethodVisitor mv = cv.visitMethod(ACC_PRIVATE,
0299: TC_FULLY_READLOCK_METHOD_NAME,
0300: TC_FULLY_READLOCK_METHOD_DESC, null, null);
0301: mv.visitCode();
0302: Label l0 = new Label();
0303: mv.visitLabel(l0);
0304: mv.visitVarInsn(ALOAD, 0);
0305: mv.visitFieldInsn(GETFIELD, CONCURRENT_HASH_MAP_SLASH,
0306: "segments",
0307: "[Ljava/util/concurrent/ConcurrentHashMap$Segment;");
0308: mv.visitVarInsn(ASTORE, 1);
0309: Label l1 = new Label();
0310: mv.visitLabel(l1);
0311: mv.visitInsn(ICONST_0);
0312: mv.visitVarInsn(ISTORE, 2);
0313: Label l2 = new Label();
0314: mv.visitLabel(l2);
0315: Label l3 = new Label();
0316: mv.visitJumpInsn(GOTO, l3);
0317: Label l4 = new Label();
0318: mv.visitLabel(l4);
0319: mv.visitVarInsn(ALOAD, 1);
0320: mv.visitVarInsn(ILOAD, 2);
0321: mv.visitInsn(AALOAD);
0322: mv
0323: .visitMethodInsn(
0324: INVOKEVIRTUAL,
0325: JavaUtilConcurrentHashMapSegmentAdapter.CONCURRENT_HASH_MAP_SEGMENT_SLASH,
0326: JavaUtilConcurrentHashMapSegmentAdapter.TC_READLOCK_METHOD_NAME,
0327: JavaUtilConcurrentHashMapSegmentAdapter.TC_READLOCK_METHOD_DESC);
0328: mv.visitIincInsn(2, 1);
0329: mv.visitLabel(l3);
0330: mv.visitVarInsn(ILOAD, 2);
0331: mv.visitVarInsn(ALOAD, 1);
0332: mv.visitInsn(ARRAYLENGTH);
0333: mv.visitJumpInsn(IF_ICMPLT, l4);
0334: Label l6 = new Label();
0335: mv.visitLabel(l6);
0336: mv.visitInsn(RETURN);
0337: Label l7 = new Label();
0338: mv.visitLabel(l7);
0339: mv.visitLocalVariable("this",
0340: "Ljava/util/concurrent/ConcurrentHashMap;",
0341: "Ljava/util/concurrent/ConcurrentHashMap<TK;TV;>;", l0,
0342: l7, 0);
0343: mv.visitLocalVariable("segments",
0344: "[Ljava/util/concurrent/ConcurrentHashMap$Segment;",
0345: null, l1, l7, 1);
0346: mv.visitLocalVariable("i", "I", null, l2, l6, 2);
0347: mv.visitMaxs(2, 3);
0348: mv.visitEnd();
0349: }
0350:
0351: private void createTCFullyReadUnlockMethod() {
0352: MethodVisitor mv = cv.visitMethod(ACC_PRIVATE,
0353: TC_FULLY_READUNLOCK_METHOD_NAME,
0354: TC_FULLY_READUNLOCK_METHOD_DESC, null, null);
0355: mv.visitCode();
0356: Label l0 = new Label();
0357: mv.visitLabel(l0);
0358: mv.visitVarInsn(ALOAD, 0);
0359: mv.visitFieldInsn(GETFIELD, CONCURRENT_HASH_MAP_SLASH,
0360: "segments",
0361: "[Ljava/util/concurrent/ConcurrentHashMap$Segment;");
0362: mv.visitVarInsn(ASTORE, 1);
0363: Label l1 = new Label();
0364: mv.visitLabel(l1);
0365: mv.visitInsn(ICONST_0);
0366: mv.visitVarInsn(ISTORE, 2);
0367: Label l2 = new Label();
0368: mv.visitLabel(l2);
0369: Label l3 = new Label();
0370: mv.visitJumpInsn(GOTO, l3);
0371: Label l4 = new Label();
0372: mv.visitLabel(l4);
0373: mv.visitVarInsn(ALOAD, 1);
0374: mv.visitVarInsn(ILOAD, 2);
0375: mv.visitInsn(AALOAD);
0376: mv
0377: .visitMethodInsn(
0378: INVOKEVIRTUAL,
0379: JavaUtilConcurrentHashMapSegmentAdapter.CONCURRENT_HASH_MAP_SEGMENT_SLASH,
0380: JavaUtilConcurrentHashMapSegmentAdapter.TC_READUNLOCK_METHOD_NAME,
0381: JavaUtilConcurrentHashMapSegmentAdapter.TC_READUNLOCK_METHOD_DESC);
0382: mv.visitIincInsn(2, 1);
0383: mv.visitLabel(l3);
0384: mv.visitVarInsn(ILOAD, 2);
0385: mv.visitVarInsn(ALOAD, 1);
0386: mv.visitInsn(ARRAYLENGTH);
0387: mv.visitJumpInsn(IF_ICMPLT, l4);
0388: Label l6 = new Label();
0389: mv.visitLabel(l6);
0390: mv.visitInsn(RETURN);
0391: Label l7 = new Label();
0392: mv.visitLabel(l7);
0393: mv.visitLocalVariable("this",
0394: "Ljava/util/concurrent/ConcurrentHashMap;",
0395: "Ljava/util/concurrent/ConcurrentHashMap<TK;TV;>;", l0,
0396: l7, 0);
0397: mv.visitLocalVariable("segments",
0398: "[Ljava/util/concurrent/ConcurrentHashMap$Segment;",
0399: null, l1, l7, 1);
0400: mv.visitLocalVariable("i", "I", null, l2, l6, 2);
0401: mv.visitMaxs(2, 3);
0402: mv.visitEnd();
0403: }
0404:
0405: private void createTCRehashAndSupportMethods() {
0406: createTCRehashMethod();
0407: createTCClearMethod();
0408: }
0409:
0410: private void createTCRehashMethod() {
0411: int access = ACC_PUBLIC + ACC_SYNTHETIC;
0412: String name = TC_REHASH_METHOD_NAME;
0413: String desc = TC_REHASH_METHOD_DESC;
0414: MethodVisitor mv = super .visitMethod(access, name, desc, null,
0415: null);
0416: mv = new JavaUtilConcurrentHashMapLazyValuesMethodAdapter(
0417: access, desc, mv, false);
0418:
0419: mv.visitCode();
0420: Label l0 = new Label();
0421: Label l1 = new Label();
0422: mv.visitTryCatchBlock(l0, l1, l1, "java/lang/Throwable");
0423: Label l2 = new Label();
0424: mv.visitTryCatchBlock(l0, l2, l2, null);
0425: Label l3 = new Label();
0426: mv.visitLabel(l3);
0427: mv.visitVarInsn(ALOAD, 0);
0428: mv.visitMethodInsn(INVOKEVIRTUAL, CONCURRENT_HASH_MAP_SLASH,
0429: "size", "()I");
0430: Label l4 = new Label();
0431: mv.visitJumpInsn(IFLE, l4);
0432: mv.visitVarInsn(ALOAD, 0);
0433: mv.visitMethodInsn(INVOKESPECIAL, CONCURRENT_HASH_MAP_SLASH,
0434: TC_FULLY_READLOCK_METHOD_NAME,
0435: TC_FULLY_READLOCK_METHOD_DESC);
0436: mv.visitLabel(l0);
0437: mv.visitTypeInsn(NEW, "java/util/ArrayList");
0438: mv.visitInsn(DUP);
0439: mv.visitMethodInsn(INVOKESPECIAL, "java/util/ArrayList",
0440: "<init>", "()V");
0441: mv.visitVarInsn(ASTORE, 1);
0442: Label l6 = new Label();
0443: mv.visitLabel(l6);
0444: mv.visitInsn(ICONST_0);
0445: mv.visitVarInsn(ISTORE, 2);
0446: Label l7 = new Label();
0447: mv.visitLabel(l7);
0448: Label l8 = new Label();
0449: mv.visitJumpInsn(GOTO, l8);
0450: Label l9 = new Label();
0451: mv.visitLabel(l9);
0452: mv.visitVarInsn(ALOAD, 0);
0453: mv.visitFieldInsn(GETFIELD, CONCURRENT_HASH_MAP_SLASH,
0454: "segments",
0455: "[Ljava/util/concurrent/ConcurrentHashMap$Segment;");
0456: mv.visitVarInsn(ILOAD, 2);
0457: mv.visitInsn(AALOAD);
0458: mv.visitFieldInsn(GETFIELD,
0459: "java/util/concurrent/ConcurrentHashMap$Segment",
0460: "table",
0461: "[Ljava/util/concurrent/ConcurrentHashMap$HashEntry;");
0462: mv.visitVarInsn(ASTORE, 3);
0463: Label l10 = new Label();
0464: mv.visitLabel(l10);
0465: mv.visitInsn(ICONST_0);
0466: mv.visitVarInsn(ISTORE, 4);
0467: Label l11 = new Label();
0468: mv.visitLabel(l11);
0469: Label l12 = new Label();
0470: mv.visitJumpInsn(GOTO, l12);
0471: Label l13 = new Label();
0472: mv.visitLabel(l13);
0473: mv.visitVarInsn(ALOAD, 3);
0474: mv.visitVarInsn(ILOAD, 4);
0475: mv.visitInsn(AALOAD);
0476: Label l14 = new Label();
0477: mv.visitJumpInsn(IFNULL, l14);
0478: mv.visitVarInsn(ALOAD, 3);
0479: mv.visitVarInsn(ILOAD, 4);
0480: mv.visitInsn(AALOAD);
0481: mv.visitVarInsn(ASTORE, 5);
0482: Label l16 = new Label();
0483: mv.visitLabel(l16);
0484: Label l17 = new Label();
0485: mv.visitJumpInsn(GOTO, l17);
0486: Label l18 = new Label();
0487: mv.visitLabel(l18);
0488: mv.visitVarInsn(ALOAD, 1);
0489: mv.visitVarInsn(ALOAD, 5);
0490: mv.visitMethodInsn(INVOKEINTERFACE, "java/util/List", "add",
0491: "(Ljava/lang/Object;)Z");
0492: mv.visitInsn(POP);
0493: mv.visitVarInsn(ALOAD, 5);
0494: mv.visitFieldInsn(GETFIELD,
0495: "java/util/concurrent/ConcurrentHashMap$HashEntry",
0496: "next",
0497: "Ljava/util/concurrent/ConcurrentHashMap$HashEntry;");
0498: mv.visitVarInsn(ASTORE, 5);
0499: mv.visitLabel(l17);
0500: mv.visitVarInsn(ALOAD, 5);
0501: mv.visitJumpInsn(IFNONNULL, l18);
0502: mv.visitLabel(l14);
0503: mv.visitIincInsn(4, 1);
0504: mv.visitLabel(l12);
0505: mv.visitVarInsn(ILOAD, 4);
0506: mv.visitVarInsn(ALOAD, 3);
0507: mv.visitInsn(ARRAYLENGTH);
0508: mv.visitJumpInsn(IF_ICMPLT, l13);
0509: Label l20 = new Label();
0510: mv.visitLabel(l20);
0511: mv.visitIincInsn(2, 1);
0512: mv.visitLabel(l8);
0513: mv.visitVarInsn(ILOAD, 2);
0514: mv.visitVarInsn(ALOAD, 0);
0515: mv.visitFieldInsn(GETFIELD, CONCURRENT_HASH_MAP_SLASH,
0516: "segments",
0517: "[Ljava/util/concurrent/ConcurrentHashMap$Segment;");
0518: mv.visitInsn(ARRAYLENGTH);
0519: mv.visitJumpInsn(IF_ICMPLT, l9);
0520: Label l21 = new Label();
0521: mv.visitLabel(l21);
0522: mv.visitVarInsn(ALOAD, 0);
0523: mv.visitMethodInsn(INVOKEVIRTUAL, CONCURRENT_HASH_MAP_SLASH,
0524: "__tc_clear", "()V");
0525: mv.visitVarInsn(ALOAD, 1);
0526: mv.visitMethodInsn(INVOKEINTERFACE, "java/util/List",
0527: "iterator", "()Ljava/util/Iterator;");
0528: mv.visitVarInsn(ASTORE, 2);
0529: Label l23 = new Label();
0530: mv.visitLabel(l23);
0531: Label l24 = new Label();
0532: mv.visitJumpInsn(GOTO, l24);
0533: Label l25 = new Label();
0534: mv.visitLabel(l25);
0535: mv.visitVarInsn(ALOAD, 2);
0536: mv.visitMethodInsn(INVOKEINTERFACE, "java/util/Iterator",
0537: "next", "()Ljava/lang/Object;");
0538: mv.visitTypeInsn(CHECKCAST,
0539: "java/util/concurrent/ConcurrentHashMap$HashEntry");
0540: mv.visitTypeInsn(CHECKCAST,
0541: "java/util/concurrent/ConcurrentHashMap$HashEntry");
0542: mv.visitVarInsn(ASTORE, 3);
0543: Label l26 = new Label();
0544: mv.visitLabel(l26);
0545: mv.visitVarInsn(ALOAD, 3);
0546: mv.visitFieldInsn(GETFIELD,
0547: "java/util/concurrent/ConcurrentHashMap$HashEntry",
0548: "key", "Ljava/lang/Object;");
0549: mv.visitVarInsn(ASTORE, 4);
0550: Label l27 = new Label();
0551: mv.visitLabel(l27);
0552: mv.visitVarInsn(ALOAD, 3);
0553: mv.visitFieldInsn(GETFIELD,
0554: "java/util/concurrent/ConcurrentHashMap$HashEntry",
0555: "value", "Ljava/lang/Object;");
0556: mv.visitVarInsn(ASTORE, 5);
0557: Label l28 = new Label();
0558: mv.visitLabel(l28);
0559: invokeJdkHashMethod(mv, 4);
0560: mv.visitVarInsn(ISTORE, 6);
0561: Label l29 = new Label();
0562: mv.visitLabel(l29);
0563: mv.visitVarInsn(ALOAD, 0);
0564: mv.visitVarInsn(ALOAD, 0);
0565: mv.visitVarInsn(ALOAD, 4);
0566: mv.visitInsn(ICONST_0);
0567: mv.visitMethodInsn(INVOKESPECIAL, CONCURRENT_HASH_MAP_SLASH,
0568: TC_HASH_METHOD_NAME, TC_HASH_METHOD_CHECK_DESC);
0569: mv.visitMethodInsn(INVOKEVIRTUAL, CONCURRENT_HASH_MAP_SLASH,
0570: "segmentFor",
0571: "(I)Ljava/util/concurrent/ConcurrentHashMap$Segment;");
0572: mv.visitVarInsn(ALOAD, 4);
0573: mv.visitVarInsn(ILOAD, 6);
0574: mv.visitVarInsn(ALOAD, 5);
0575: mv.visitInsn(ICONST_0);
0576: mv
0577: .visitMethodInsn(
0578: INVOKEVIRTUAL,
0579: "java/util/concurrent/ConcurrentHashMap$Segment",
0580: JavaUtilConcurrentHashMapSegmentAdapter.TC_PUT_METHOD_NAME,
0581: JavaUtilConcurrentHashMapSegmentAdapter.TC_PUT_METHOD_DESC);
0582: mv.visitInsn(POP);
0583: mv.visitLabel(l24);
0584: mv.visitVarInsn(ALOAD, 2);
0585: mv.visitMethodInsn(INVOKEINTERFACE, "java/util/Iterator",
0586: "hasNext", "()Z");
0587: mv.visitJumpInsn(IFNE, l25);
0588: Label l30 = new Label();
0589: mv.visitLabel(l30);
0590: Label l31 = new Label();
0591: mv.visitJumpInsn(GOTO, l31);
0592: mv.visitLabel(l1);
0593: mv.visitVarInsn(ASTORE, 1);
0594: Label l32 = new Label();
0595: mv.visitLabel(l32);
0596: mv.visitVarInsn(ALOAD, 1);
0597: mv.visitFieldInsn(GETSTATIC, "java/lang/System", "err",
0598: "Ljava/io/PrintStream;");
0599: mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Throwable",
0600: "printStackTrace", "(Ljava/io/PrintStream;)V");
0601: Label l33 = new Label();
0602: mv.visitLabel(l33);
0603: mv.visitJumpInsn(GOTO, l31);
0604: mv.visitLabel(l2);
0605: mv.visitVarInsn(ASTORE, 7);
0606: Label l34 = new Label();
0607: mv.visitLabel(l34);
0608: mv.visitVarInsn(ALOAD, 0);
0609: mv.visitMethodInsn(INVOKESPECIAL, CONCURRENT_HASH_MAP_SLASH,
0610: TC_FULLY_READUNLOCK_METHOD_NAME,
0611: TC_FULLY_READUNLOCK_METHOD_DESC);
0612: mv.visitVarInsn(ALOAD, 7);
0613: mv.visitInsn(ATHROW);
0614: mv.visitLabel(l31);
0615: mv.visitVarInsn(ALOAD, 0);
0616: mv.visitMethodInsn(INVOKESPECIAL, CONCURRENT_HASH_MAP_SLASH,
0617: TC_FULLY_READUNLOCK_METHOD_NAME,
0618: TC_FULLY_READUNLOCK_METHOD_DESC);
0619: mv.visitLabel(l4);
0620: mv.visitInsn(RETURN);
0621: Label l36 = new Label();
0622: mv.visitLabel(l36);
0623: mv.visitLocalVariable("this",
0624: "Ljava/util/concurrent/ConcurrentHashMap;",
0625: "Ljava/util/concurrent/ConcurrentHashMap<TK;TV;>;", l3,
0626: l36, 0);
0627: mv.visitLocalVariable("entries", "Ljava/util/List;", null, l6,
0628: l1, 1);
0629: mv.visitLocalVariable("i", "I", null, l7, l21, 2);
0630: mv.visitLocalVariable("segmentEntries",
0631: "[Ljava/util/concurrent/ConcurrentHashMap$HashEntry;",
0632: null, l10, l20, 3);
0633: mv.visitLocalVariable("j", "I", null, l11, l20, 4);
0634: mv.visitLocalVariable("first",
0635: "Ljava/util/concurrent/ConcurrentHashMap$HashEntry;",
0636: null, l16, l14, 5);
0637: mv.visitLocalVariable("i", "Ljava/util/Iterator;", null, l23,
0638: l30, 2);
0639: mv.visitLocalVariable("entry",
0640: "Ljava/util/concurrent/ConcurrentHashMap$HashEntry;",
0641: null, l26, l24, 3);
0642: mv.visitLocalVariable("key", "Ljava/lang/Object;", null, l27,
0643: l24, 4);
0644: mv.visitLocalVariable("value", "Ljava/lang/Object;", null, l28,
0645: l24, 5);
0646: mv.visitLocalVariable("hash", "I", null, l29, l24, 6);
0647: mv.visitLocalVariable("t", "Ljava/lang/Throwable;", null, l32,
0648: l33, 1);
0649: mv.visitMaxs(5, 8);
0650: mv.visitEnd();
0651: }
0652:
0653: private void createTCPutMethod() {
0654: MethodVisitor mv = super .visitMethod(
0655: ACC_PUBLIC + ACC_SYNTHETIC, TC_PUT_METHOD_NAME,
0656: TC_PUT_METHOD_DESC, null, null);
0657: mv.visitCode();
0658: Label l0 = new Label();
0659: mv.visitLabel(l0);
0660: mv.visitVarInsn(ALOAD, 2);
0661: Label l1 = new Label();
0662: mv.visitJumpInsn(IFNONNULL, l1);
0663: mv.visitTypeInsn(NEW, "java/lang/NullPointerException");
0664: mv.visitInsn(DUP);
0665: mv.visitMethodInsn(INVOKESPECIAL,
0666: "java/lang/NullPointerException", "<init>", "()V");
0667: mv.visitInsn(ATHROW);
0668: mv.visitLabel(l1);
0669: invokeJdkHashMethod(mv, 1);
0670: mv.visitVarInsn(ISTORE, 3);
0671: Label l2 = new Label();
0672: mv.visitLabel(l2);
0673: mv.visitVarInsn(ALOAD, 0);
0674: mv.visitVarInsn(ALOAD, 0);
0675: mv.visitVarInsn(ALOAD, 1);
0676: mv.visitInsn(ICONST_0);
0677: mv.visitMethodInsn(INVOKESPECIAL, CONCURRENT_HASH_MAP_SLASH,
0678: TC_HASH_METHOD_NAME, TC_HASH_METHOD_CHECK_DESC);
0679: mv.visitMethodInsn(INVOKEVIRTUAL, CONCURRENT_HASH_MAP_SLASH,
0680: "segmentFor",
0681: "(I)Ljava/util/concurrent/ConcurrentHashMap$Segment;");
0682: mv.visitVarInsn(ALOAD, 1);
0683: mv.visitVarInsn(ILOAD, 3);
0684: mv.visitVarInsn(ALOAD, 2);
0685: mv.visitInsn(ICONST_0);
0686: mv
0687: .visitMethodInsn(
0688: INVOKEVIRTUAL,
0689: "java/util/concurrent/ConcurrentHashMap$Segment",
0690: JavaUtilConcurrentHashMapSegmentAdapter.TC_PUT_METHOD_NAME,
0691: JavaUtilConcurrentHashMapSegmentAdapter.TC_PUT_METHOD_DESC);
0692: mv.visitInsn(ARETURN);
0693: Label l3 = new Label();
0694: mv.visitLabel(l3);
0695: mv.visitMaxs(0, 0);
0696: mv.visitEnd();
0697: }
0698:
0699: private void createTCClearMethod() {
0700: MethodVisitor mv = super .visitMethod(ACC_PRIVATE
0701: + ACC_SYNTHETIC, TC_CLEAR_METHOD_NAME,
0702: TC_CLEAR_METHOD_DESC, null, null);
0703: mv.visitCode();
0704: Label l0 = new Label();
0705: mv.visitLabel(l0);
0706: mv.visitInsn(ICONST_0);
0707: mv.visitVarInsn(ISTORE, 1);
0708: Label l1 = new Label();
0709: mv.visitLabel(l1);
0710: Label l2 = new Label();
0711: mv.visitJumpInsn(GOTO, l2);
0712: Label l3 = new Label();
0713: mv.visitLabel(l3);
0714: mv.visitVarInsn(ALOAD, 0);
0715: mv.visitFieldInsn(GETFIELD, CONCURRENT_HASH_MAP_SLASH,
0716: "segments",
0717: "[Ljava/util/concurrent/ConcurrentHashMap$Segment;");
0718: mv.visitVarInsn(ILOAD, 1);
0719: mv.visitInsn(AALOAD);
0720: mv.visitMethodInsn(INVOKEVIRTUAL,
0721: "java/util/concurrent/ConcurrentHashMap$Segment",
0722: TC_CLEAR_METHOD_NAME, TC_CLEAR_METHOD_DESC);
0723: Label l4 = new Label();
0724: mv.visitLabel(l4);
0725: mv.visitIincInsn(1, 1);
0726: mv.visitLabel(l2);
0727: mv.visitVarInsn(ILOAD, 1);
0728: mv.visitVarInsn(ALOAD, 0);
0729: mv.visitFieldInsn(GETFIELD, CONCURRENT_HASH_MAP_SLASH,
0730: "segments",
0731: "[Ljava/util/concurrent/ConcurrentHashMap$Segment;");
0732: mv.visitInsn(ARRAYLENGTH);
0733: mv.visitJumpInsn(IF_ICMPLT, l3);
0734: Label l5 = new Label();
0735: mv.visitLabel(l5);
0736: mv.visitInsn(RETURN);
0737: Label l6 = new Label();
0738: mv.visitLabel(l6);
0739: mv.visitMaxs(0, 0);
0740: mv.visitEnd();
0741: }
0742:
0743: private static class EntrySetMethodAdapter extends MethodAdapter
0744: implements Opcodes {
0745: public EntrySetMethodAdapter(MethodVisitor mv) {
0746: super (mv);
0747: }
0748:
0749: public void visitMethodInsn(int opcode, String owner,
0750: String name, String desc) {
0751: super .visitMethodInsn(opcode, owner, name, desc);
0752:
0753: if (INVOKESPECIAL == opcode
0754: && "java/util/concurrent/ConcurrentHashMap$EntrySet"
0755: .equals(owner)
0756: && "<init>".equals(name)
0757: && "(Ljava/util/concurrent/ConcurrentHashMap;)V"
0758: .equals(desc)) {
0759: mv.visitVarInsn(ASTORE, 1);
0760: mv
0761: .visitTypeInsn(NEW,
0762: "com/tcclient/util/ConcurrentHashMapEntrySetWrapper");
0763: mv.visitInsn(DUP);
0764: mv.visitVarInsn(ALOAD, 0);
0765: mv.visitVarInsn(ALOAD, 1);
0766: mv
0767: .visitMethodInsn(
0768: INVOKESPECIAL,
0769: "com/tcclient/util/ConcurrentHashMapEntrySetWrapper",
0770: "<init>",
0771: "(Ljava/util/Map;Ljava/util/Set;)V");
0772: }
0773: }
0774: }
0775:
0776: private static class ApplicatorPutMethodAdapter extends
0777: MethodAdapter implements Opcodes {
0778: public ApplicatorPutMethodAdapter(MethodVisitor mv) {
0779: super (mv);
0780: }
0781:
0782: public void visitMethodInsn(int opcode, String owner,
0783: String name, String desc) {
0784: if (INVOKEVIRTUAL == opcode
0785: && "java/util/concurrent/ConcurrentHashMap$Segment"
0786: .equals(owner)
0787: && "put".equals(name)
0788: && JavaUtilConcurrentHashMapSegmentAdapter.TC_ORIG_PUT_METHOD_DESC
0789: .equals(desc)) {
0790: // use the un-instrumented version of the segment put method
0791: super
0792: .visitMethodInsn(
0793: opcode,
0794: owner,
0795: JavaUtilConcurrentHashMapSegmentAdapter.TC_ORIG_PUT_METHOD_NAME,
0796: desc);
0797: } else {
0798: super .visitMethodInsn(opcode, owner, name, desc);
0799: }
0800: }
0801:
0802: public void visitInsn(int opcode) {
0803: if (ARETURN == opcode) {
0804: // change the old value return to a void return and swallow the normally returned value
0805: super .visitInsn(POP);
0806: super .visitInsn(RETURN);
0807: } else {
0808: super .visitInsn(opcode);
0809: }
0810: }
0811: }
0812:
0813: private static class OriginalGetMethodAdapter extends MethodAdapter
0814: implements Opcodes {
0815: public OriginalGetMethodAdapter(MethodVisitor mv) {
0816: super (mv);
0817: }
0818:
0819: public void visitMethodInsn(int opcode, String owner,
0820: String name, String desc) {
0821: if (INVOKEVIRTUAL == opcode
0822: && "java/util/concurrent/ConcurrentHashMap$Segment"
0823: .equals(owner)
0824: && "get".equals(name)
0825: && JavaUtilConcurrentHashMapSegmentAdapter.TC_ORIG_GET_METHOD_DESC
0826: .equals(desc)) {
0827: // use the un-instrumented version of the segment 'get' method
0828: super
0829: .visitMethodInsn(
0830: opcode,
0831: owner,
0832: JavaUtilConcurrentHashMapSegmentAdapter.TC_ORIG_GET_METHOD_NAME,
0833: desc);
0834: } else {
0835: super .visitMethodInsn(opcode, owner, name, desc);
0836: }
0837: }
0838: }
0839:
0840: private static class ApplicatorRemoveMethodAdapter extends
0841: MethodAdapter implements Opcodes {
0842: public ApplicatorRemoveMethodAdapter(MethodVisitor mv) {
0843: super (mv);
0844: }
0845:
0846: public void visitMethodInsn(int opcode, String owner,
0847: String name, String desc) {
0848: if (INVOKEVIRTUAL == opcode
0849: && "java/util/concurrent/ConcurrentHashMap$Segment"
0850: .equals(owner)
0851: && "remove".equals(name)
0852: && JavaUtilConcurrentHashMapSegmentAdapter.TC_ORIG_REMOVE_METHOD_DESC
0853: .equals(desc)) {
0854: // use the un-instrumented version of the segment 'remove' method
0855: super
0856: .visitMethodInsn(
0857: opcode,
0858: owner,
0859: JavaUtilConcurrentHashMapSegmentAdapter.TC_ORIG_REMOVE_METHOD_NAME,
0860: desc);
0861: } else {
0862: super .visitMethodInsn(opcode, owner, name, desc);
0863: }
0864: }
0865:
0866: public void visitInsn(int opcode) {
0867: if (ARETURN == opcode) {
0868: // change the old value return to a void return and swallow the normally returned value
0869: super .visitInsn(POP);
0870: super .visitInsn(RETURN);
0871: } else {
0872: super .visitInsn(opcode);
0873: }
0874: }
0875: }
0876:
0877: private static class RemoveLogicalMethodAdapter extends
0878: MethodAdapter implements Opcodes {
0879: public RemoveLogicalMethodAdapter(MethodVisitor mv) {
0880: super (mv);
0881: }
0882:
0883: public void visitMethodInsn(int opcode, String owner,
0884: String name, String desc) {
0885: if (INVOKEVIRTUAL == opcode
0886: && "java/util/concurrent/ConcurrentHashMap$Segment"
0887: .equals(owner)
0888: && "remove".equals(name)
0889: && JavaUtilConcurrentHashMapSegmentAdapter.TC_NULLOLDVALUE_REMOVE_METHOD_DESC
0890: .equals(desc)) {
0891: // use the segment remove method that doesn't fault in the old values
0892: super
0893: .visitMethodInsn(
0894: opcode,
0895: owner,
0896: JavaUtilConcurrentHashMapSegmentAdapter.TC_NULLOLDVALUE_REMOVE_METHOD_NAME,
0897: desc);
0898: } else {
0899: super .visitMethodInsn(opcode, owner, name, desc);
0900: }
0901: }
0902:
0903: public void visitInsn(int opcode) {
0904: if (ARETURN == opcode) {
0905: // change the old value return to a void return and swallow the normally returned value
0906: super .visitInsn(POP);
0907: super .visitInsn(RETURN);
0908: } else {
0909: super .visitInsn(opcode);
0910: }
0911: }
0912: }
0913:
0914: private abstract static class AddCheckManagedKeyMethodAdapter
0915: extends MethodAdapter implements Opcodes {
0916: public AddCheckManagedKeyMethodAdapter(MethodVisitor mv) {
0917: super (mv);
0918: }
0919:
0920: public void visitCode() {
0921: super .visitCode();
0922: addCheckManagedKeyCode();
0923: }
0924:
0925: protected abstract void addCheckManagedKeyCode();
0926: }
0927:
0928: private static class ContainsKeyMethodAdapter extends
0929: AddCheckManagedKeyMethodAdapter {
0930: public ContainsKeyMethodAdapter(MethodVisitor mv) {
0931: super (mv);
0932: }
0933:
0934: protected void addCheckManagedKeyCode() {
0935: mv.visitVarInsn(ALOAD, 0);
0936: mv.visitVarInsn(ALOAD, 1);
0937: mv.visitMethodInsn(INVOKESPECIAL,
0938: CONCURRENT_HASH_MAP_SLASH,
0939: TC_IS_DSO_HASH_REQUIRED_METHOD_NAME,
0940: TC_IS_DSO_HASH_REQUIRED_METHOD_DESC);
0941: Label l1 = new Label();
0942: mv.visitJumpInsn(IFNE, l1);
0943: Label l2 = new Label();
0944: mv.visitLabel(l2);
0945: mv.visitInsn(ICONST_0);
0946: mv.visitInsn(IRETURN);
0947: mv.visitLabel(l1);
0948: }
0949: }
0950:
0951: private static class GetMethodAdapter extends
0952: AddCheckManagedKeyMethodAdapter {
0953: public GetMethodAdapter(MethodVisitor mv) {
0954: super (mv);
0955: }
0956:
0957: protected void addCheckManagedKeyCode() {
0958: mv.visitVarInsn(ALOAD, 0);
0959: mv.visitVarInsn(ALOAD, 1);
0960: mv.visitMethodInsn(INVOKESPECIAL,
0961: CONCURRENT_HASH_MAP_SLASH,
0962: TC_IS_DSO_HASH_REQUIRED_METHOD_NAME,
0963: TC_IS_DSO_HASH_REQUIRED_METHOD_DESC);
0964: Label l1 = new Label();
0965: mv.visitJumpInsn(IFNE, l1);
0966: Label l2 = new Label();
0967: mv.visitLabel(l2);
0968: mv.visitInsn(ACONST_NULL);
0969: mv.visitInsn(ARETURN);
0970: mv.visitLabel(l1);
0971: }
0972: }
0973:
0974: private static class SimpleRemoveMethodAdapter extends
0975: GetMethodAdapter {
0976: public SimpleRemoveMethodAdapter(MethodVisitor mv) {
0977: super (mv);
0978: }
0979: }
0980:
0981: private static class SimpleReplaceMethodAdapter extends
0982: SimpleRemoveMethodAdapter {
0983: private Label target;
0984:
0985: public SimpleReplaceMethodAdapter(MethodVisitor mv) {
0986: super (mv);
0987: }
0988:
0989: public void visitCode() {
0990: mv.visitCode();
0991: }
0992:
0993: public void visitJumpInsn(int opcode, Label label) {
0994: super .visitJumpInsn(opcode, label);
0995: if (IFNONNULL == opcode) {
0996: target = label;
0997: }
0998: }
0999:
1000: public void visitLabel(Label label) {
1001: super .visitLabel(label);
1002: if (label.equals(target)) {
1003: addCheckManagedKeyCode();
1004: }
1005: }
1006: }
1007:
1008: private static class RemoveMethodAdapter extends
1009: AddCheckManagedKeyMethodAdapter {
1010: public RemoveMethodAdapter(MethodVisitor mv) {
1011: super (mv);
1012: }
1013:
1014: protected void addCheckManagedKeyCode() {
1015: mv.visitVarInsn(ALOAD, 0);
1016: mv.visitVarInsn(ALOAD, 1);
1017: mv.visitMethodInsn(INVOKESPECIAL,
1018: CONCURRENT_HASH_MAP_SLASH,
1019: TC_IS_DSO_HASH_REQUIRED_METHOD_NAME,
1020: TC_IS_DSO_HASH_REQUIRED_METHOD_DESC);
1021: Label l1 = new Label();
1022: mv.visitJumpInsn(IFNE, l1);
1023: Label l2 = new Label();
1024: mv.visitLabel(l2);
1025: mv.visitInsn(ICONST_0);
1026: mv.visitInsn(IRETURN);
1027: mv.visitLabel(l1);
1028: }
1029: }
1030:
1031: private static class ReplaceMethodAdapter extends
1032: RemoveMethodAdapter {
1033: private Label target;
1034:
1035: public ReplaceMethodAdapter(MethodVisitor mv) {
1036: super (mv);
1037: }
1038:
1039: public void visitCode() {
1040: mv.visitCode();
1041: }
1042:
1043: public void visitJumpInsn(int opcode, Label label) {
1044: super .visitJumpInsn(opcode, label);
1045: if (IFNONNULL == opcode) {
1046: target = label;
1047: }
1048: }
1049:
1050: public void visitLabel(Label label) {
1051: super .visitLabel(label);
1052: if (label.equals(target)) {
1053: addCheckManagedKeyCode();
1054: }
1055: }
1056: }
1057:
1058: private static class ConcurrentHashMapMethodAdapter extends
1059: MethodAdapter implements Opcodes {
1060:
1061: public ConcurrentHashMapMethodAdapter(MethodVisitor mv) {
1062: super (mv);
1063: }
1064:
1065: public void visitMethodInsn(int opcode, String owner,
1066: String name, String desc) {
1067: if (INVOKEVIRTUAL == opcode
1068: && CONCURRENT_HASH_MAP_SLASH.equals(owner)
1069: && "segmentFor".equals(name)
1070: && "(I)Ljava/util/concurrent/ConcurrentHashMap$Segment;"
1071: .equals(desc)) {
1072: super .visitInsn(POP);
1073: super .visitVarInsn(ALOAD, 0);
1074: super .visitVarInsn(ALOAD, 1);
1075: super .visitMethodInsn(INVOKEVIRTUAL, owner,
1076: TC_HASH_METHOD_NAME, TC_HASH_METHOD_DESC);
1077: super .visitMethodInsn(opcode, owner, name, desc);
1078: } else if (INVOKESPECIAL == opcode
1079: && JavaUtilConcurrentHashMapSegmentAdapter.CONCURRENT_HASH_MAP_SEGMENT_SLASH
1080: .equals(owner) && "<init>".equals(name)
1081: && "(IF)V".equals(desc)) {
1082: super .visitInsn(POP);
1083: super .visitInsn(POP);
1084: super .visitVarInsn(ALOAD, 0);
1085: super .visitVarInsn(ILOAD, 7);
1086: super .visitVarInsn(FLOAD, 2);
1087: super
1088: .visitMethodInsn(
1089: opcode,
1090: owner,
1091: name,
1092: JavaUtilConcurrentHashMapSegmentAdapter.INIT_DESC);
1093: } else {
1094: super .visitMethodInsn(opcode, owner, name, desc);
1095: }
1096: }
1097: }
1098:
1099: private static class TurnIntoReadLocksMethodAdapter extends
1100: MethodAdapter implements Opcodes {
1101:
1102: public TurnIntoReadLocksMethodAdapter(MethodVisitor mv) {
1103: super (mv);
1104: }
1105:
1106: public void visitMethodInsn(int opcode, String owner,
1107: String name, String desc) {
1108: if (INVOKEVIRTUAL == opcode
1109: && JavaUtilConcurrentHashMapSegmentAdapter.CONCURRENT_HASH_MAP_SEGMENT_SLASH
1110: .equals(owner) && "()V".equals(desc)) {
1111: if ("lock".equals(name)) {
1112: name = JavaUtilConcurrentHashMapSegmentAdapter.TC_READLOCK_METHOD_NAME;
1113: } else if ("unlock".equals(name)) {
1114: name = JavaUtilConcurrentHashMapSegmentAdapter.TC_READUNLOCK_METHOD_NAME;
1115: }
1116: }
1117:
1118: super .visitMethodInsn(opcode, owner, name, desc);
1119: }
1120: }
1121:
1122: private void invokeJdkHashMethod(MethodVisitor mv,
1123: int objectVarNumber) {
1124: mv.visitVarInsn(ALOAD, objectVarNumber);
1125: if (Vm.isJDK16()) {
1126: mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object",
1127: "hashCode", "()I");
1128: mv.visitMethodInsn(INVOKESTATIC, CONCURRENT_HASH_MAP_SLASH,
1129: HASH_METHOD_NAME, "(I)I");
1130: } else {
1131: mv.visitMethodInsn(INVOKESTATIC, CONCURRENT_HASH_MAP_SLASH,
1132: HASH_METHOD_NAME, "(Ljava/lang/Object;)I");
1133: }
1134: }
1135: }
|