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.Label;
010: import com.tc.asm.MethodAdapter;
011: import com.tc.asm.MethodVisitor;
012: import com.tc.asm.Opcodes;
013: import com.tc.asm.Type;
014: import com.tc.object.SerializationUtil;
015:
016: public class JavaUtilConcurrentHashMapSegmentAdapter extends
017: ClassAdapter implements Opcodes {
018: private final static String PARENT_CONCURRENT_HASH_MAP_FIELD_TYPE = "Ljava/util/concurrent/ConcurrentHashMap;";
019:
020: private final static String PARENT_CONCURRENT_HASH_MAP_FIELD_NAME = "parentMap";
021:
022: public final static String TC_ORIG_GET_METHOD_NAME = ByteCodeUtil.TC_METHOD_PREFIX
023: + "origGet";
024: public final static String TC_ORIG_GET_METHOD_DESC = "(Ljava/lang/Object;I)Ljava/lang/Object;";
025:
026: public final static String TC_PUT_METHOD_NAME = ByteCodeUtil.TC_METHOD_PREFIX
027: + "put";
028: public final static String TC_PUT_METHOD_DESC = "(Ljava/lang/Object;ILjava/lang/Object;Z)Ljava/lang/Object;";
029:
030: public final static String TC_ORIG_PUT_METHOD_NAME = ByteCodeUtil.TC_METHOD_PREFIX
031: + "origPut";
032: public final static String TC_ORIG_PUT_METHOD_DESC = "(Ljava/lang/Object;ILjava/lang/Object;Z)Ljava/lang/Object;";
033:
034: public final static String TC_ORIG_REMOVE_METHOD_NAME = ByteCodeUtil.TC_METHOD_PREFIX
035: + "origRemove";
036: public final static String TC_ORIG_REMOVE_METHOD_DESC = "(Ljava/lang/Object;ILjava/lang/Object;)Ljava/lang/Object;";
037:
038: public final static String TC_NULLOLDVALUE_REMOVE_METHOD_NAME = ByteCodeUtil.TC_METHOD_PREFIX
039: + "nulloldvalueRemove";
040: public final static String TC_NULLOLDVALUE_REMOVE_METHOD_DESC = "(Ljava/lang/Object;ILjava/lang/Object;)Ljava/lang/Object;";
041:
042: private final static String TC_CLEAR_METHOD_NAME = ByteCodeUtil.TC_METHOD_PREFIX
043: + "clear";
044: private final static String TC_CLEAR_METHOD_DESC = "()V";
045:
046: public final static String TC_READLOCK_METHOD_NAME = ByteCodeUtil.TC_METHOD_PREFIX
047: + "readLock";
048: public final static String TC_READLOCK_METHOD_DESC = "()V";
049:
050: public final static String TC_READUNLOCK_METHOD_NAME = ByteCodeUtil.TC_METHOD_PREFIX
051: + "readUnlock";
052: public final static String TC_READUNLOCK_METHOD_DESC = "()V";
053:
054: public final static String INITIAL_TABLE_METHOD_NAME = "initTable";
055: public final static String INITIAL_TABLE_METHOD_DESC = "(I)V";
056:
057: public final static String CONCURRENT_HASH_MAP_SEGMENT_SLASH = "java/util/concurrent/ConcurrentHashMap$Segment";
058: public final static String INIT_DESC = "("
059: + PARENT_CONCURRENT_HASH_MAP_FIELD_TYPE + "IF)V";
060:
061: public JavaUtilConcurrentHashMapSegmentAdapter(ClassVisitor cv) {
062: super (cv);
063: }
064:
065: public void visit(int version, int access, String name,
066: String signature, String super Name, String[] interfaces) {
067: super .visit(version, access, name, signature,
068: "java/util/concurrent/locks/ReentrantReadWriteLock",
069: interfaces);
070: }
071:
072: public MethodVisitor visitMethod(int access, String name,
073: String desc, String signature, String[] exceptions) {
074: if ("get".equals(name)
075: && "(Ljava/lang/Object;I)Ljava/lang/Object;"
076: .equals(desc)) {
077: return new MulticastMethodVisitor(
078: new MethodVisitor[] {
079: // rename the original, totally un-instrumented get method
080: super
081: .visitMethod(ACC_SYNTHETIC,
082: TC_ORIG_GET_METHOD_NAME,
083: TC_ORIG_GET_METHOD_DESC,
084: null, null),
085: // adapt the get method
086: new JavaUtilConcurrentHashMapLazyValuesMethodAdapter(
087: access, desc, addWrapperMethod(
088: access, name, desc,
089: signature, exceptions),
090: true) });
091: } else if ("containsValue".equals(name)
092: && "(Ljava/lang/Object;)Z".equals(desc)) {
093: return new JavaUtilConcurrentHashMapLazyValuesMethodAdapter(
094: access, desc, super .visitMethod(access, name, desc,
095: signature, exceptions), true);
096: } else if ("containsKey".equals(name)
097: && "(Ljava/lang/Object;I)Z".equals(desc)) {
098: return new JavaUtilConcurrentHashMapLazyValuesMethodAdapter(
099: access, desc, addWrapperMethod(access, name, desc,
100: signature, exceptions), false);
101: } else {
102: String description = desc;
103: if ("<init>".equals(name) && "(IF)V".equals(desc)) {
104: description = INIT_DESC;
105: }
106:
107: MethodVisitor mv = super .visitMethod(access, name,
108: description, signature, exceptions);
109: if ("put".equals(name)
110: && "(Ljava/lang/Object;ILjava/lang/Object;Z)Ljava/lang/Object;"
111: .equals(desc)) {
112: return new MulticastMethodVisitor(
113: new MethodVisitor[] {
114: // rename the original, totally un-instrumented put method so that it can be used by the CHM applicator
115: super .visitMethod(ACC_SYNTHETIC,
116: TC_ORIG_PUT_METHOD_NAME,
117: TC_ORIG_PUT_METHOD_DESC, null,
118: null),
119: // adapt the put method
120: new JavaUtilConcurrentHashMapLazyValuesMethodAdapter(
121: access, desc,
122: new PutMethodAdapter(mv), false),
123: // This creates the identical copy of the put() method of Segments except that it does not lock and does
124: // not invoke the instrumented version of the logicalInvoke(). The reason that it does not require
125: // locking is because it is called from the __tc_rehash() instrumented method and the lock is grabbed
126: // at the __tc_rehash() method already.
127: new JavaUtilConcurrentHashMapLazyValuesMethodAdapter(
128: access,
129: desc,
130: new RemoveLockUnlockMethodAdapter(
131: super
132: .visitMethod(
133: ACC_SYNTHETIC,
134: TC_PUT_METHOD_NAME,
135: TC_PUT_METHOD_DESC,
136: null,
137: null)),
138: false) });
139: } else if ("remove".equals(name)
140: && "(Ljava/lang/Object;ILjava/lang/Object;)Ljava/lang/Object;"
141: .equals(desc)) {
142: return new MulticastMethodVisitor(
143: new MethodVisitor[] {
144: // rename the original, totally un-instrumented remove method so that it can be used by the CHM applicator
145: super .visitMethod(ACC_SYNTHETIC,
146: TC_ORIG_REMOVE_METHOD_NAME,
147: TC_ORIG_REMOVE_METHOD_DESC,
148: null, null),
149: // create an adapted remove method that returns nulls for the old values and thus doesn't fault them in
150: new RemoveNullOldValueMethodAdapter(
151: new JavaUtilConcurrentHashMapLazyValuesMethodAdapter(
152: access,
153: desc,
154: new RemoveMethodAdapter(
155: super
156: .visitMethod(
157: ACC_SYNTHETIC,
158: TC_NULLOLDVALUE_REMOVE_METHOD_NAME,
159: TC_NULLOLDVALUE_REMOVE_METHOD_DESC,
160: null,
161: null)),
162: false)),
163: // adapt the remove method
164: new JavaUtilConcurrentHashMapLazyValuesMethodAdapter(
165: access, desc,
166: new RemoveMethodAdapter(mv),
167: false) });
168: }
169:
170: final MethodVisitor visitor;
171: if ("clear".equals(name) && "()V".equals(desc)) {
172: visitor = new MulticastMethodVisitor(
173: new MethodVisitor[] {
174: new ClearMethodAdapter(mv),
175: // Again, this method does not require locking as it is called by __tc_rehash() which grabs the lock already.
176: new RemoveLockUnlockMethodAdapter(super
177: .visitMethod(ACC_SYNTHETIC,
178: TC_CLEAR_METHOD_NAME,
179: TC_CLEAR_METHOD_DESC,
180: null, null)) });
181: } else if ("replace".equals(name)
182: && "(Ljava/lang/Object;ILjava/lang/Object;)Ljava/lang/Object;"
183: .equals(desc)) {
184: visitor = new ReplaceMethodAdapter(mv);
185: } else if ("replace".equals(name)
186: && "(Ljava/lang/Object;ILjava/lang/Object;Ljava/lang/Object;)Z"
187: .equals(desc)) {
188: visitor = new ReplaceIfValueEqualMethodAdapter(mv);
189: } else if ("<init>".equals(name) && "(IF)V".equals(desc)) {
190: visitor = new InitMethodAdapter(mv);
191: } else if ("readValueUnderLock".equals(name)
192: && "(Ljava/util/concurrent/ConcurrentHashMap$HashEntry;)Ljava/lang/Object;"
193: .equals(desc)) {
194: visitor = new ReadValueUnderLockMethodAdapter(mv);
195: } else {
196: visitor = mv;
197: }
198:
199: return new JavaUtilConcurrentHashMapLazyValuesMethodAdapter(
200: access, desc, visitor, false);
201: }
202: }
203:
204: private String getNewName(String methodName) {
205: return ByteCodeUtil.TC_METHOD_PREFIX + methodName;
206: }
207:
208: private MethodVisitor addWrapperMethod(int access, String name,
209: String desc, String signature, String[] exceptions) {
210: createWrapperMethod(access, name, desc, signature, exceptions);
211: return cv.visitMethod(ACC_PRIVATE, getNewName(name), desc,
212: signature, exceptions);
213: }
214:
215: private void createWrapperMethod(int access, String name,
216: String desc, String signature, String[] exceptions) {
217: Type[] params = Type.getArgumentTypes(desc);
218: Type returnType = Type.getReturnType(desc);
219:
220: MethodVisitor mv = cv.visitMethod(access, name, desc,
221: signature, exceptions);
222: mv.visitCode();
223: Label l0 = new Label();
224: Label l1 = new Label();
225: Label l2 = new Label();
226: mv.visitTryCatchBlock(l0, l1, l2, null);
227: Label l3 = new Label();
228: mv.visitLabel(l3);
229: mv.visitLineNumber(280, l3);
230: mv.visitVarInsn(ALOAD, 0);
231: mv.visitMethodInsn(INVOKESTATIC,
232: "com/tc/object/bytecode/ManagerUtil", "isManaged",
233: "(Ljava/lang/Object;)Z");
234: mv.visitVarInsn(ISTORE, 3);
235: Label l4 = new Label();
236: mv.visitLabel(l4);
237: mv.visitLineNumber(281, l4);
238: mv.visitVarInsn(ILOAD, 3);
239: mv.visitJumpInsn(IFEQ, l0);
240: mv.visitVarInsn(ALOAD, 0);
241: mv.visitMethodInsn(INVOKEVIRTUAL,
242: CONCURRENT_HASH_MAP_SEGMENT_SLASH,
243: TC_READLOCK_METHOD_NAME, TC_READLOCK_METHOD_DESC);
244: mv.visitLabel(l0);
245: mv.visitLineNumber(283, l0);
246: mv.visitVarInsn(ALOAD, 0);
247: for (int i = 0; i < params.length; i++) {
248: mv.visitVarInsn(params[i].getOpcode(ILOAD), i + 1);
249: }
250: mv.visitMethodInsn(INVOKESPECIAL,
251: CONCURRENT_HASH_MAP_SEGMENT_SLASH, getNewName(name),
252: desc);
253: mv.visitVarInsn(returnType.getOpcode(ISTORE), 5);
254: mv.visitLabel(l1);
255: mv.visitLineNumber(285, l1);
256: mv.visitVarInsn(ILOAD, 3);
257: Label l5 = new Label();
258: mv.visitJumpInsn(IFEQ, l5);
259: mv.visitVarInsn(ALOAD, 0);
260: mv.visitMethodInsn(INVOKEVIRTUAL,
261: CONCURRENT_HASH_MAP_SEGMENT_SLASH,
262: TC_READUNLOCK_METHOD_NAME, TC_READUNLOCK_METHOD_DESC);
263: mv.visitLabel(l5);
264: mv.visitLineNumber(283, l5);
265: mv.visitVarInsn(returnType.getOpcode(ILOAD), 5);
266: mv.visitInsn(returnType.getOpcode(IRETURN));
267: mv.visitLabel(l2);
268: mv.visitLineNumber(284, l2);
269: mv.visitVarInsn(ASTORE, 4);
270: Label l6 = new Label();
271: mv.visitLabel(l6);
272: mv.visitLineNumber(285, l6);
273: mv.visitVarInsn(ILOAD, 3);
274: Label l7 = new Label();
275: mv.visitJumpInsn(IFEQ, l7);
276: mv.visitVarInsn(ALOAD, 0);
277: mv.visitMethodInsn(INVOKEVIRTUAL,
278: CONCURRENT_HASH_MAP_SEGMENT_SLASH,
279: TC_READUNLOCK_METHOD_NAME, TC_READUNLOCK_METHOD_DESC);
280: mv.visitLabel(l7);
281: mv.visitLineNumber(286, l7);
282: mv.visitVarInsn(ALOAD, 4);
283: mv.visitInsn(ATHROW);
284: Label l8 = new Label();
285: mv.visitLabel(l8);
286: mv.visitMaxs(0, 0);
287: mv.visitEnd();
288: }
289:
290: public void visitEnd() {
291: createDefaultConstructor();
292: createInitTableMethod();
293: createLockMethod();
294: createUnlockMethod();
295: createTCReadLockMethod();
296: createTCReadUnlockMethod();
297:
298: super .visitField(ACC_FINAL + ACC_SYNTHETIC,
299: PARENT_CONCURRENT_HASH_MAP_FIELD_NAME,
300: "Ljava/util/concurrent/ConcurrentHashMap;", null, null);
301: super .visitEnd();
302: }
303:
304: private void createDefaultConstructor() {
305: MethodVisitor mv = cv.visitMethod(0, "<init>", "()V", null,
306: null);
307: mv.visitCode();
308: Label l0 = new Label();
309: mv.visitLabel(l0);
310: mv.visitLineNumber(232, l0);
311: mv.visitVarInsn(ALOAD, 0);
312: mv.visitMethodInsn(INVOKESPECIAL,
313: "java/util/concurrent/locks/ReentrantReadWriteLock",
314: "<init>", "()V");
315: Label l1 = new Label();
316: mv.visitLabel(l1);
317: mv.visitLineNumber(233, l1);
318: mv.visitVarInsn(ALOAD, 0);
319: mv.visitInsn(ICONST_1);
320: mv.visitTypeInsn(ANEWARRAY,
321: "java/util/concurrent/ConcurrentHashMap$HashEntry");
322: mv
323: .visitMethodInsn(INVOKEVIRTUAL,
324: CONCURRENT_HASH_MAP_SEGMENT_SLASH, "setTable",
325: "([Ljava/util/concurrent/ConcurrentHashMap$HashEntry;)V");
326: Label l2 = new Label();
327: mv.visitLabel(l2);
328: mv.visitLineNumber(234, l2);
329: mv.visitVarInsn(ALOAD, 0);
330: mv.visitInsn(FCONST_0);
331: mv.visitFieldInsn(PUTFIELD, CONCURRENT_HASH_MAP_SEGMENT_SLASH,
332: "loadFactor", "F");
333: Label l3 = new Label();
334: mv.visitLabel(l3);
335: mv.visitLineNumber(235, l3);
336: mv.visitVarInsn(ALOAD, 0);
337: mv.visitInsn(ACONST_NULL);
338: mv
339: .visitFieldInsn(PUTFIELD,
340: CONCURRENT_HASH_MAP_SEGMENT_SLASH, "parentMap",
341: "Ljava/util/concurrent/ConcurrentHashMap;");
342: Label l4 = new Label();
343: mv.visitLabel(l4);
344: mv.visitLineNumber(236, l4);
345: mv.visitInsn(RETURN);
346: Label l5 = new Label();
347: mv.visitLabel(l5);
348: mv
349: .visitLocalVariable(
350: "this",
351: "Ljava/util/concurrent/ConcurrentHashMap$Segment;",
352: "Ljava/util/concurrent/ConcurrentHashMap<TK;TV;>.Segment<TK;TV;>;",
353: l0, l5, 0);
354: mv.visitMaxs(2, 1);
355: mv.visitEnd();
356: }
357:
358: private void createLockMethod() {
359: MethodVisitor mv = cv.visitMethod(ACC_PUBLIC, "lock", "()V",
360: null, null);
361: mv.visitCode();
362: mv.visitVarInsn(ALOAD, 0);
363: mv
364: .visitMethodInsn(INVOKEVIRTUAL,
365: CONCURRENT_HASH_MAP_SEGMENT_SLASH, "writeLock",
366: "()Ljava/util/concurrent/locks/ReentrantReadWriteLock$WriteLock;");
367: mv
368: .visitMethodInsn(
369: INVOKEVIRTUAL,
370: "java/util/concurrent/locks/ReentrantReadWriteLock$WriteLock",
371: "lock", "()V");
372: mv.visitInsn(RETURN);
373: mv.visitMaxs(1, 1);
374: mv.visitEnd();
375: }
376:
377: private void createUnlockMethod() {
378: MethodVisitor mv = cv.visitMethod(ACC_PUBLIC, "unlock", "()V",
379: null, null);
380: mv.visitCode();
381: mv.visitVarInsn(ALOAD, 0);
382: mv
383: .visitMethodInsn(INVOKEVIRTUAL,
384: CONCURRENT_HASH_MAP_SEGMENT_SLASH, "writeLock",
385: "()Ljava/util/concurrent/locks/ReentrantReadWriteLock$WriteLock;");
386: mv
387: .visitMethodInsn(
388: INVOKEVIRTUAL,
389: "java/util/concurrent/locks/ReentrantReadWriteLock$WriteLock",
390: "unlock", "()V");
391: mv.visitInsn(RETURN);
392: mv.visitMaxs(1, 1);
393: mv.visitEnd();
394: }
395:
396: private void createTCReadLockMethod() {
397: MethodVisitor mv = cv.visitMethod(ACC_PUBLIC,
398: TC_READLOCK_METHOD_NAME, TC_READLOCK_METHOD_DESC, null,
399: null);
400: mv.visitCode();
401: mv.visitVarInsn(ALOAD, 0);
402: mv
403: .visitMethodInsn(INVOKEVIRTUAL,
404: CONCURRENT_HASH_MAP_SEGMENT_SLASH, "readLock",
405: "()Ljava/util/concurrent/locks/ReentrantReadWriteLock$ReadLock;");
406: mv
407: .visitMethodInsn(
408: INVOKEVIRTUAL,
409: "java/util/concurrent/locks/ReentrantReadWriteLock$ReadLock",
410: "lock", "()V");
411: mv.visitInsn(RETURN);
412: mv.visitMaxs(1, 1);
413: mv.visitEnd();
414: }
415:
416: private void createTCReadUnlockMethod() {
417: MethodVisitor mv = cv.visitMethod(ACC_PUBLIC,
418: TC_READUNLOCK_METHOD_NAME, TC_READUNLOCK_METHOD_DESC,
419: null, null);
420: mv.visitCode();
421: mv.visitVarInsn(ALOAD, 0);
422: mv
423: .visitMethodInsn(INVOKEVIRTUAL,
424: CONCURRENT_HASH_MAP_SEGMENT_SLASH, "readLock",
425: "()Ljava/util/concurrent/locks/ReentrantReadWriteLock$ReadLock;");
426: mv
427: .visitMethodInsn(
428: INVOKEVIRTUAL,
429: "java/util/concurrent/locks/ReentrantReadWriteLock$ReadLock",
430: "unlock", "()V");
431: mv.visitInsn(RETURN);
432: mv.visitMaxs(1, 1);
433: mv.visitEnd();
434: }
435:
436: private void createInitTableMethod() {
437: MethodVisitor mv = super .visitMethod(ACC_PRIVATE + ACC_FINAL
438: + ACC_SYNTHETIC, INITIAL_TABLE_METHOD_NAME,
439: INITIAL_TABLE_METHOD_DESC, null, null);
440: mv.visitCode();
441: ByteCodeUtil.pushThis(mv);
442: mv.visitVarInsn(ILOAD, 1);
443: mv.visitTypeInsn(ANEWARRAY,
444: "java/util/concurrent/ConcurrentHashMap$HashEntry");
445: mv
446: .visitMethodInsn(INVOKEVIRTUAL,
447: CONCURRENT_HASH_MAP_SEGMENT_SLASH, "setTable",
448: "([Ljava/util/concurrent/ConcurrentHashMap$HashEntry;)V");
449: mv.visitInsn(RETURN);
450: mv.visitMaxs(0, 0);
451: mv.visitEnd();
452: }
453:
454: private static class InitMethodAdapter extends MethodAdapter
455: implements Opcodes {
456: public InitMethodAdapter(MethodVisitor mv) {
457: super (mv);
458: }
459:
460: public void visitInsn(int opcode) {
461: if (RETURN == opcode) {
462: ByteCodeUtil.pushThis(mv);
463: mv.visitVarInsn(ALOAD, 1);
464: mv.visitFieldInsn(PUTFIELD,
465: CONCURRENT_HASH_MAP_SEGMENT_SLASH,
466: PARENT_CONCURRENT_HASH_MAP_FIELD_NAME,
467: "Ljava/util/concurrent/ConcurrentHashMap;");
468:
469: }
470: super .visitInsn(opcode);
471: }
472:
473: public void visitVarInsn(int opcode, int var) {
474: if (var == 1) {
475: var = 2;
476: } else if (var == 2) {
477: var = 3;
478: }
479: super .visitVarInsn(opcode, var);
480: }
481:
482: public void visitMethodInsn(int opcode, String owner,
483: String name, String desc) {
484: if (INVOKESPECIAL == opcode
485: && "java/util/concurrent/locks/ReentrantLock"
486: .equals(owner) && "<init>".equals(name)
487: && "()V".equals(desc)) {
488: owner = "java/util/concurrent/locks/ReentrantReadWriteLock";
489: }
490:
491: super .visitMethodInsn(opcode, owner, name, desc);
492: }
493: }
494:
495: private static class PutMethodAdapter extends MethodAdapter
496: implements Opcodes {
497: public PutMethodAdapter(MethodVisitor mv) {
498: super (mv);
499: }
500:
501: public void visitFieldInsn(int opcode, String owner,
502: String name, String desc) {
503: super .visitFieldInsn(opcode, owner, name, desc);
504:
505: if (PUTFIELD == opcode
506: && "java/util/concurrent/ConcurrentHashMap$HashEntry"
507: .equals(owner) && "value".equals(name)
508: && "Ljava/lang/Object;".equals(desc)) {
509: addFoundLogicalInvokePutMethodCall();
510: } else if (PUTFIELD == opcode
511: && CONCURRENT_HASH_MAP_SEGMENT_SLASH.equals(owner)
512: && "count".equals(name) && "I".equals(desc)) {
513: addNotFoundLogicalInvokePutMethodCall();
514: }
515: }
516:
517: private void addFoundLogicalInvokePutMethodCall() {
518: Label notManaged = new Label();
519: Label logicalInvokeLabel = new Label();
520:
521: mv.visitLabel(logicalInvokeLabel);
522:
523: ByteCodeUtil.pushThis(mv);
524: mv.visitFieldInsn(GETFIELD,
525: CONCURRENT_HASH_MAP_SEGMENT_SLASH,
526: PARENT_CONCURRENT_HASH_MAP_FIELD_NAME,
527: "Ljava/util/concurrent/ConcurrentHashMap;");
528: mv.visitMethodInsn(INVOKESTATIC,
529: "com/tc/object/bytecode/ManagerUtil", "isManaged",
530: "(Ljava/lang/Object;)Z");
531: mv.visitJumpInsn(IFEQ, notManaged);
532: ByteCodeUtil.pushThis(mv);
533: mv.visitFieldInsn(GETFIELD,
534: CONCURRENT_HASH_MAP_SEGMENT_SLASH,
535: PARENT_CONCURRENT_HASH_MAP_FIELD_NAME,
536: "Ljava/util/concurrent/ConcurrentHashMap;");
537: mv.visitLdcInsn(SerializationUtil.PUT_SIGNATURE);
538: mv.visitInsn(ICONST_2);
539: mv.visitTypeInsn(ANEWARRAY, "java/lang/Object");
540: mv.visitInsn(DUP);
541: mv.visitInsn(ICONST_0);
542: mv.visitVarInsn(ALOAD, 9);
543: mv.visitFieldInsn(GETFIELD,
544: "java/util/concurrent/ConcurrentHashMap$HashEntry",
545: "key", "Ljava/lang/Object;");
546: mv.visitInsn(AASTORE);
547: mv.visitInsn(DUP);
548: mv.visitInsn(ICONST_1);
549: mv.visitVarInsn(ALOAD, 3);
550: mv.visitInsn(AASTORE);
551: mv
552: .visitMethodInsn(INVOKESTATIC,
553: "com/tc/object/bytecode/ManagerUtil",
554: "logicalInvoke",
555: "(Ljava/lang/Object;Ljava/lang/String;[Ljava/lang/Object;)V");
556: mv.visitLabel(notManaged);
557: }
558:
559: private void addNotFoundLogicalInvokePutMethodCall() {
560: Label endBlock = new Label();
561: Label logicalInvokeLabel = new Label();
562:
563: mv.visitLabel(logicalInvokeLabel);
564:
565: ByteCodeUtil.pushThis(mv);
566: mv.visitFieldInsn(GETFIELD,
567: CONCURRENT_HASH_MAP_SEGMENT_SLASH,
568: PARENT_CONCURRENT_HASH_MAP_FIELD_NAME,
569: "Ljava/util/concurrent/ConcurrentHashMap;");
570: mv.visitMethodInsn(INVOKESTATIC,
571: "com/tc/object/bytecode/ManagerUtil", "isManaged",
572: "(Ljava/lang/Object;)Z");
573: mv.visitJumpInsn(IFEQ, endBlock);
574: mv.visitVarInsn(ILOAD, 4);
575: Label l0 = new Label();
576: mv.visitJumpInsn(IFEQ, l0);
577: ByteCodeUtil.pushThis(mv);
578: mv.visitFieldInsn(GETFIELD,
579: CONCURRENT_HASH_MAP_SEGMENT_SLASH,
580: PARENT_CONCURRENT_HASH_MAP_FIELD_NAME,
581: "Ljava/util/concurrent/ConcurrentHashMap;");
582: mv.visitLdcInsn(SerializationUtil.PUT_SIGNATURE);
583: mv.visitInsn(ICONST_2);
584: mv.visitTypeInsn(ANEWARRAY, "java/lang/Object");
585: mv.visitInsn(DUP);
586: mv.visitInsn(ICONST_0);
587: mv.visitVarInsn(ALOAD, 1);
588: mv.visitInsn(AASTORE);
589: mv.visitInsn(DUP);
590: mv.visitInsn(ICONST_1);
591: mv.visitVarInsn(ALOAD, 3);
592: mv.visitInsn(AASTORE);
593: mv
594: .visitMethodInsn(INVOKESTATIC,
595: "com/tc/object/bytecode/ManagerUtil",
596: "logicalInvoke",
597: "(Ljava/lang/Object;Ljava/lang/String;[Ljava/lang/Object;)V");
598: mv.visitJumpInsn(GOTO, endBlock);
599: mv.visitLabel(l0);
600: ByteCodeUtil.pushThis(mv);
601: mv.visitFieldInsn(GETFIELD,
602: CONCURRENT_HASH_MAP_SEGMENT_SLASH,
603: PARENT_CONCURRENT_HASH_MAP_FIELD_NAME,
604: "Ljava/util/concurrent/ConcurrentHashMap;");
605: mv.visitLdcInsn(SerializationUtil.PUT_SIGNATURE);
606: mv.visitInsn(ICONST_2);
607: mv.visitTypeInsn(ANEWARRAY, "java/lang/Object");
608: mv.visitInsn(DUP);
609: mv.visitInsn(ICONST_0);
610: mv.visitVarInsn(ALOAD, 1);
611: mv.visitInsn(AASTORE);
612: mv.visitInsn(DUP);
613: mv.visitInsn(ICONST_1);
614: mv.visitVarInsn(ALOAD, 3);
615: mv.visitInsn(AASTORE);
616: mv
617: .visitMethodInsn(INVOKESTATIC,
618: "com/tc/object/bytecode/ManagerUtil",
619: "logicalInvoke",
620: "(Ljava/lang/Object;Ljava/lang/String;[Ljava/lang/Object;)V");
621: mv.visitLabel(endBlock);
622: }
623: }
624:
625: private static class RemoveLockUnlockMethodAdapter extends
626: MethodAdapter implements Opcodes {
627: public RemoveLockUnlockMethodAdapter(MethodVisitor mv) {
628: super (mv);
629: }
630:
631: public void visitMethodInsn(int opcode, String owner,
632: String name, String desc) {
633: if (CONCURRENT_HASH_MAP_SEGMENT_SLASH.equals(owner)
634: && ("lock".equals(name) || "unlock".equals(name))
635: && "()V".equals(desc)) {
636: // insert a POP insertion instead, so that the reference to
637: // 'this' is removed from the stack
638: mv.visitInsn(POP);
639: } else {
640: super .visitMethodInsn(opcode, owner, name, desc);
641: }
642: }
643: }
644:
645: private static class ReplaceMethodAdapter extends MethodAdapter
646: implements Opcodes {
647: public ReplaceMethodAdapter(MethodVisitor mv) {
648: super (mv);
649: }
650:
651: public void visitFieldInsn(int opcode, String owner,
652: String name, String desc) {
653: super .visitFieldInsn(opcode, owner, name, desc);
654: if (PUTFIELD == opcode
655: && "java/util/concurrent/ConcurrentHashMap$HashEntry"
656: .equals(owner) && "value".equals(name)
657: && "Ljava/lang/Object;".equals(desc)) {
658: addLogicalInvokeReplaceMethodCall();
659: }
660: }
661:
662: public void addLogicalInvokeReplaceMethodCall() {
663: Label notManaged = new Label();
664: ByteCodeUtil.pushThis(this );
665: mv.visitFieldInsn(GETFIELD,
666: CONCURRENT_HASH_MAP_SEGMENT_SLASH,
667: PARENT_CONCURRENT_HASH_MAP_FIELD_NAME,
668: "Ljava/util/concurrent/ConcurrentHashMap;");
669: mv.visitMethodInsn(INVOKESTATIC,
670: "com/tc/object/bytecode/ManagerUtil", "isManaged",
671: "(Ljava/lang/Object;)Z");
672: mv.visitJumpInsn(IFEQ, notManaged);
673: mv.visitVarInsn(ALOAD, 0);
674: mv.visitFieldInsn(GETFIELD,
675: CONCURRENT_HASH_MAP_SEGMENT_SLASH,
676: PARENT_CONCURRENT_HASH_MAP_FIELD_NAME,
677: "Ljava/util/concurrent/ConcurrentHashMap;");
678: mv.visitLdcInsn(SerializationUtil.PUT_SIGNATURE);
679: mv.visitInsn(ICONST_2);
680: mv.visitTypeInsn(ANEWARRAY, "java/lang/Object");
681: mv.visitInsn(DUP);
682: mv.visitInsn(ICONST_0);
683: mv.visitVarInsn(ALOAD, 4);
684: mv.visitFieldInsn(GETFIELD,
685: "java/util/concurrent/ConcurrentHashMap$HashEntry",
686: "key", "Ljava/lang/Object;");
687: mv.visitInsn(AASTORE);
688: mv.visitInsn(DUP);
689: mv.visitInsn(ICONST_1);
690: mv.visitVarInsn(ALOAD, 3);
691: mv.visitInsn(AASTORE);
692: mv
693: .visitMethodInsn(INVOKESTATIC,
694: "com/tc/object/bytecode/ManagerUtil",
695: "logicalInvoke",
696: "(Ljava/lang/Object;Ljava/lang/String;[Ljava/lang/Object;)V");
697: mv.visitLabel(notManaged);
698: }
699: }
700:
701: private static class ReplaceIfValueEqualMethodAdapter extends
702: MethodAdapter implements Opcodes {
703: public ReplaceIfValueEqualMethodAdapter(MethodVisitor mv) {
704: super (mv);
705: }
706:
707: public void visitFieldInsn(int opcode, String owner,
708: String name, String desc) {
709: if (PUTFIELD == opcode
710: && "java/util/concurrent/ConcurrentHashMap$HashEntry"
711: .equals(owner) && "value".equals(name)
712: && "Ljava/lang/Object;".equals(desc)) {
713: addLogicalInvokeReplaceMethodCall();
714: }
715: super .visitFieldInsn(opcode, owner, name, desc);
716: }
717:
718: public void addLogicalInvokeReplaceMethodCall() {
719: Label notManaged = new Label();
720: ByteCodeUtil.pushThis(mv);
721: mv.visitFieldInsn(GETFIELD,
722: CONCURRENT_HASH_MAP_SEGMENT_SLASH,
723: PARENT_CONCURRENT_HASH_MAP_FIELD_NAME,
724: "Ljava/util/concurrent/ConcurrentHashMap;");
725: mv.visitMethodInsn(INVOKESTATIC,
726: "com/tc/object/bytecode/ManagerUtil", "isManaged",
727: "(Ljava/lang/Object;)Z");
728: mv.visitJumpInsn(IFEQ, notManaged);
729: ByteCodeUtil.pushThis(mv);
730: mv.visitFieldInsn(GETFIELD,
731: CONCURRENT_HASH_MAP_SEGMENT_SLASH,
732: PARENT_CONCURRENT_HASH_MAP_FIELD_NAME,
733: "Ljava/util/concurrent/ConcurrentHashMap;");
734: mv.visitLdcInsn(SerializationUtil.PUT_SIGNATURE);
735: mv.visitInsn(ICONST_2);
736: mv.visitTypeInsn(ANEWARRAY, "java/lang/Object");
737: mv.visitInsn(DUP);
738: mv.visitInsn(ICONST_0);
739: mv.visitVarInsn(ALOAD, 5);
740: mv.visitFieldInsn(GETFIELD,
741: "java/util/concurrent/ConcurrentHashMap$HashEntry",
742: "key", "Ljava/lang/Object;");
743: mv.visitInsn(AASTORE);
744: mv.visitInsn(DUP);
745: mv.visitInsn(ICONST_1);
746: mv.visitVarInsn(ALOAD, 4);
747: mv.visitInsn(AASTORE);
748: mv
749: .visitMethodInsn(INVOKESTATIC,
750: "com/tc/object/bytecode/ManagerUtil",
751: "logicalInvoke",
752: "(Ljava/lang/Object;Ljava/lang/String;[Ljava/lang/Object;)V");
753: mv.visitLabel(notManaged);
754: }
755: }
756:
757: private static class RemoveMethodAdapter extends MethodAdapter
758: implements Opcodes {
759: public RemoveMethodAdapter(MethodVisitor mv) {
760: super (mv);
761: }
762:
763: public void visitFieldInsn(int opcode, String owner,
764: String name, String desc) {
765: super .visitFieldInsn(opcode, owner, name, desc);
766: if (PUTFIELD == opcode
767: && CONCURRENT_HASH_MAP_SEGMENT_SLASH.equals(owner)
768: && "count".equals(name) && "I".equals(desc)) {
769: addLogicalInvokeRemoveMethodCall();
770: }
771: }
772:
773: public void addLogicalInvokeRemoveMethodCall() {
774: Label notManaged = new Label();
775: Label logicalInvokeLabel = new Label();
776:
777: mv.visitLabel(logicalInvokeLabel);
778:
779: ByteCodeUtil.pushThis(mv);
780: mv.visitFieldInsn(GETFIELD,
781: CONCURRENT_HASH_MAP_SEGMENT_SLASH,
782: PARENT_CONCURRENT_HASH_MAP_FIELD_NAME,
783: "Ljava/util/concurrent/ConcurrentHashMap;");
784: mv.visitMethodInsn(INVOKESTATIC,
785: "com/tc/object/bytecode/ManagerUtil", "isManaged",
786: "(Ljava/lang/Object;)Z");
787: mv.visitJumpInsn(IFEQ, notManaged);
788: mv.visitVarInsn(ALOAD, 0);
789: mv.visitFieldInsn(GETFIELD,
790: CONCURRENT_HASH_MAP_SEGMENT_SLASH,
791: PARENT_CONCURRENT_HASH_MAP_FIELD_NAME,
792: "Ljava/util/concurrent/ConcurrentHashMap;");
793: mv.visitLdcInsn(SerializationUtil.REMOVE_SIGNATURE);
794: mv.visitInsn(ICONST_1);
795: mv.visitTypeInsn(ANEWARRAY, "java/lang/Object");
796: mv.visitInsn(DUP);
797: mv.visitInsn(ICONST_0);
798: mv.visitVarInsn(ALOAD, 8);
799: mv.visitFieldInsn(GETFIELD,
800: "java/util/concurrent/ConcurrentHashMap$HashEntry",
801: "key", "Ljava/lang/Object;");
802: mv.visitInsn(AASTORE);
803: mv
804: .visitMethodInsn(INVOKESTATIC,
805: "com/tc/object/bytecode/ManagerUtil",
806: "logicalInvoke",
807: "(Ljava/lang/Object;Ljava/lang/String;[Ljava/lang/Object;)V");
808: mv.visitLabel(notManaged);
809: }
810: }
811:
812: private static class RemoveNullOldValueMethodAdapter extends
813: MethodAdapter implements Opcodes {
814: public RemoveNullOldValueMethodAdapter(MethodVisitor mv) {
815: super (mv);
816: }
817:
818: public void visitFieldInsn(int opcode, String owner,
819: String name, String desc) {
820: if (GETFIELD == opcode
821: && "java/util/concurrent/ConcurrentHashMap$HashEntry"
822: .equals(owner) && "value".equals(name)
823: && "Ljava/lang/Object;".equals(desc)) {
824: super .visitInsn(POP);
825: super .visitInsn(ACONST_NULL);
826: } else {
827: super .visitFieldInsn(opcode, owner, name, desc);
828: }
829: }
830: }
831:
832: private static class ClearMethodAdapter extends MethodAdapter
833: implements Opcodes {
834: public ClearMethodAdapter(MethodVisitor mv) {
835: super (mv);
836: }
837:
838: public void visitMethodInsn(int opcode, String owner,
839: String name, String desc) {
840: super .visitMethodInsn(opcode, owner, name, desc);
841: if ("lock".equals(name) && "()V".equals(desc)) {
842: addLogicalInvokeMethodCall();
843: }
844: }
845:
846: public void addLogicalInvokeMethodCall() {
847: ByteCodeUtil.pushThis(mv);
848: mv.visitFieldInsn(GETFIELD,
849: CONCURRENT_HASH_MAP_SEGMENT_SLASH,
850: PARENT_CONCURRENT_HASH_MAP_FIELD_NAME,
851: "Ljava/util/concurrent/ConcurrentHashMap;");
852: mv.visitLdcInsn(SerializationUtil.CLEAR_SIGNATURE);
853:
854: mv.visitLdcInsn(new Integer(0));
855: mv.visitTypeInsn(ANEWARRAY, "java/lang/Object");
856:
857: mv
858: .visitMethodInsn(INVOKESTATIC,
859: "com/tc/object/bytecode/ManagerUtil",
860: "logicalInvoke",
861: "(Ljava/lang/Object;Ljava/lang/String;[Ljava/lang/Object;)V");
862: }
863: }
864:
865: private static class ReadValueUnderLockMethodAdapter extends
866: MethodAdapter implements Opcodes {
867: public ReadValueUnderLockMethodAdapter(MethodVisitor mv) {
868: super (mv);
869: }
870:
871: public void visitMethodInsn(int opcode, String owner,
872: String name, String desc) {
873: if ("lock".equals(name) && "()V".equals(desc)) {
874: name = TC_READLOCK_METHOD_NAME;
875: } else if ("unlock".equals(name) && "()V".equals(desc)) {
876: name = TC_READUNLOCK_METHOD_NAME;
877: }
878: super.visitMethodInsn(opcode, owner, name, desc);
879: }
880: }
881: }
|