KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > tc > object > bytecode > JavaUtilConcurrentHashMapAdapter


1 /*
2  * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright
3  * notice. All rights reserved.
4  */

5 package com.tc.object.bytecode;
6
7 import com.tc.asm.ClassAdapter;
8 import com.tc.asm.ClassVisitor;
9 import com.tc.asm.Label;
10 import com.tc.asm.MethodAdapter;
11 import com.tc.asm.MethodVisitor;
12 import com.tc.asm.Opcodes;
13 import com.tc.asm.Type;
14 import com.tc.asm.commons.LocalVariablesSorter;
15 import com.tc.util.runtime.Vm;
16
17 public class JavaUtilConcurrentHashMapAdapter extends ClassAdapter implements Opcodes {
18   private final static String JavaDoc CONCURRENT_HASH_MAP_SLASH = "java/util/concurrent/ConcurrentHashMap";
19   private final static String JavaDoc TC_HASH_METHOD_NAME = ByteCodeUtil.TC_METHOD_PREFIX + "hash";
20   private final static String JavaDoc TC_HASH_METHOD_DESC = "(Ljava/lang/Object;)I";
21   private final static String JavaDoc TC_HASH_METHOD_CHECK_DESC = "(Ljava/lang/Object;Z)I";
22   private final static String JavaDoc TC_REHASH_METHOD_NAME = ByteCodeUtil.TC_METHOD_PREFIX + "rehash";
23   private final static String JavaDoc TC_REHASH_METHOD_DESC = "()V";
24   private final static String JavaDoc TC_CLEAR_METHOD_NAME = ByteCodeUtil.TC_METHOD_PREFIX + "clear";
25   private final static String JavaDoc TC_CLEAR_METHOD_DESC = "()V";
26   private final static String JavaDoc TC_PUT_METHOD_NAME = ByteCodeUtil.TC_METHOD_PREFIX + "put";
27   private final static String JavaDoc TC_PUT_METHOD_DESC = "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;";
28   private final static String JavaDoc SEGMENT_TC_PUT_METHOD_DESC = "(Ljava/lang/Object;ILjava/lang/Object;Z)Ljava/lang/Object;";
29   private final static String JavaDoc TC_IS_DSO_HASH_REQUIRED_METHOD_NAME = ByteCodeUtil.TC_METHOD_PREFIX + "isDsoHashRequired";
30   private final static String JavaDoc TC_IS_DSO_HASH_REQUIRED_METHOD_DESC = "(Ljava/lang/Object;)Z";
31   private final static String JavaDoc TC_FULLY_LOCK_METHOD_NAME = ByteCodeUtil.TC_METHOD_PREFIX + "fullyLock";
32   private final static String JavaDoc TC_FULLY_LOCK_METHOD_DESC = "()V";
33   private final static String JavaDoc TC_FULLY_UNLOCK_METHOD_NAME = ByteCodeUtil.TC_METHOD_PREFIX + "fullyUnLock";
34   private final static String JavaDoc TC_FULLY_UNLOCK_METHOD_DESC = "()V";
35   private final static String JavaDoc HASH_METHOD_NAME = "hash";
36
37   public JavaUtilConcurrentHashMapAdapter(ClassVisitor cv) {
38     super(cv);
39   }
40
41   /**
42    * We need to instrument the size(), isEmpty(), and containsValue() methods because the original implementation in jdk
43    * 1.5 has an optimization which uses a volatile variable and does not require locking of the segments. It resorts to
44    * locking only after several unsucessful attempts. For instance, the original implementation of the size() method
45    * looks at the count and mod_count volatile variables of each segment and makes sure that there is no update during
46    * executing the size() method. If it detects any update while the size() method is being executed, it will resort to
47    * locking. Since ConcurrentHashMap is supported logically, it is possible that while the application is obtaining the
48    * size of the map while there are still pending updates. Therefore, when ConcurrentHashMap is shared, the
49    * instrumented code will always use an locking scheme to make sure all updates are applied before returing the size.
50    * The same is true for isEmpty() and containsValue methods().
51    */

52   public MethodVisitor visitMethod(int access, String JavaDoc name, String JavaDoc desc, String JavaDoc signature, String JavaDoc[] exceptions) {
53     if ("size".equals(name) && "()I".equals(desc)) {
54       return addWrapperMethod(access, name, desc, signature, exceptions);
55     } else if ("isEmpty".equals(name) && "()Z".equals(desc)) {
56       return addWrapperMethod(access, name, desc, signature, exceptions);
57     } else if ("containsValue".equals(name) && "(Ljava/lang/Object;)Z".equals(desc)) { return addWrapperMethod(
58                                                                                                                access,
59                                                                                                                name,
60                                                                                                                desc,
61                                                                                                                signature,
62                                                                                                                exceptions); }
63
64     MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
65     if ("entrySet".equals(name) && "()Ljava/util/Set;".equals(desc)) {
66       return new EntrySetMethodAdapter(mv);
67     } else if ("segmentFor".equals(name) && "(I)Ljava/util/concurrent/ConcurrentHashMap$Segment;".equals(desc)) {
68       rewriteSegmentForMethod(mv);
69     } else if ("containsKey".equals(name) && "(Ljava/lang/Object;)Z".equals(desc)) {
70       mv = new ContainsKeyMethodAdapter(mv);
71     } else if ("get".equals(name) && "(Ljava/lang/Object;)Ljava/lang/Object;".equals(desc)) {
72       mv = new GetMethodAdapter(mv);
73     } else if ("remove".equals(name) && "(Ljava/lang/Object;)Ljava/lang/Object;".equals(desc)) {
74       mv = new SimpleRemoveMethodAdapter(mv);
75     } else if ("remove".equals(name) && "(Ljava/lang/Object;Ljava/lang/Object;)Z".equals(desc)) {
76       mv = new RemoveMethodAdapter(mv);
77     } else if ("replace".equals(name) && "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;".equals(desc)) {
78       mv = new SimpleReplaceMethodAdapter(mv);
79     } else if ("replace".equals(name) && "(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Z".equals(desc)) {
80       mv = new ReplaceMethodAdapter(mv);
81     }
82
83     return new ConcurrentHashMapMethodAdapter(access, desc, mv);
84   }
85
86   public void visitEnd() {
87     createTCPutMethod();
88     createTCSharedHashMethod();
89     createTCForcedHashMethod();
90     createTCDsoRequiredMethod();
91     createTCRehashAndSupportMethods();
92     createTCFullyLockMethod();
93     createTCFullyUnLockMethod();
94     super.visitEnd();
95   }
96
97   private String JavaDoc getNewName(String JavaDoc methodName) {
98     return ByteCodeUtil.TC_METHOD_PREFIX + methodName;
99   }
100
101   private MethodVisitor addWrapperMethod(int access, String JavaDoc name, String JavaDoc desc, String JavaDoc signature, String JavaDoc[] exceptions) {
102     createWrapperMethod(access, name, desc, signature, exceptions);
103     return cv.visitMethod(ACC_PRIVATE, getNewName(name), desc, signature, exceptions);
104   }
105
106   private void createWrapperMethod(int access, String JavaDoc name, String JavaDoc desc, String JavaDoc signature, String JavaDoc[] exceptions) {
107     Type[] params = Type.getArgumentTypes(desc);
108     Type returnType = Type.getReturnType(desc);
109
110     MethodVisitor mv = cv.visitMethod(access, name, desc, signature, exceptions);
111     mv.visitCode();
112     Label l0 = new Label();
113     Label l1 = new Label();
114     Label l2 = new Label();
115     mv.visitTryCatchBlock(l0, l1, l2, null);
116     Label l3 = new Label();
117     mv.visitLabel(l3);
118     mv.visitLineNumber(805, l3);
119     mv.visitVarInsn(ALOAD, 0);
120     mv.visitMethodInsn(INVOKESTATIC, "com/tc/object/bytecode/ManagerUtil", "isManaged", "(Ljava/lang/Object;)Z");
121     mv.visitVarInsn(ISTORE, 2);
122     Label l4 = new Label();
123     mv.visitLabel(l4);
124     mv.visitLineNumber(806, l4);
125     mv.visitVarInsn(ILOAD, 2);
126     mv.visitJumpInsn(IFEQ, l0);
127     Label l5 = new Label();
128     mv.visitLabel(l5);
129     mv.visitLineNumber(807, l5);
130     mv.visitVarInsn(ALOAD, 0);
131     mv.visitMethodInsn(INVOKESPECIAL, CONCURRENT_HASH_MAP_SLASH, TC_FULLY_LOCK_METHOD_NAME, TC_FULLY_LOCK_METHOD_DESC);
132     mv.visitLabel(l0);
133     mv.visitLineNumber(810, l0);
134     mv.visitVarInsn(ALOAD, 0);
135     for (int i = 0; i < params.length; i++) {
136       mv.visitVarInsn(params[i].getOpcode(ILOAD), i + 1);
137     }
138     mv.visitMethodInsn(INVOKESPECIAL, CONCURRENT_HASH_MAP_SLASH, getNewName(name), desc);
139     mv.visitVarInsn(returnType.getOpcode(ISTORE), 4);
140     mv.visitLabel(l1);
141     mv.visitLineNumber(812, l1);
142     mv.visitVarInsn(ILOAD, 2);
143     Label l6 = new Label();
144     mv.visitJumpInsn(IFEQ, l6);
145     Label l7 = new Label();
146     mv.visitLabel(l7);
147     mv.visitLineNumber(813, l7);
148     mv.visitVarInsn(ALOAD, 0);
149     mv.visitMethodInsn(INVOKESPECIAL, CONCURRENT_HASH_MAP_SLASH, TC_FULLY_UNLOCK_METHOD_NAME,
150                        TC_FULLY_UNLOCK_METHOD_DESC);
151     mv.visitLabel(l6);
152     mv.visitLineNumber(810, l6);
153     mv.visitVarInsn(returnType.getOpcode(ILOAD), 4);
154     mv.visitInsn(returnType.getOpcode(IRETURN));
155     mv.visitLabel(l2);
156     mv.visitLineNumber(811, l2);
157     mv.visitVarInsn(ASTORE, 3);
158     Label l8 = new Label();
159     mv.visitLabel(l8);
160     mv.visitLineNumber(812, l8);
161     mv.visitVarInsn(ILOAD, 2);
162     Label l9 = new Label();
163     mv.visitJumpInsn(IFEQ, l9);
164     Label l10 = new Label();
165     mv.visitLabel(l10);
166     mv.visitLineNumber(813, l10);
167     mv.visitVarInsn(ALOAD, 0);
168     mv.visitMethodInsn(INVOKESPECIAL, CONCURRENT_HASH_MAP_SLASH, TC_FULLY_UNLOCK_METHOD_NAME,
169                        TC_FULLY_UNLOCK_METHOD_DESC);
170     mv.visitLabel(l9);
171     mv.visitLineNumber(815, l9);
172     mv.visitVarInsn(ALOAD, 3);
173     mv.visitInsn(ATHROW);
174     Label l11 = new Label();
175     mv.visitLabel(l11);
176     mv.visitLocalVariable("this", "Ljava/util/concurrent/ConcurrentHashMap;",
177                           "Ljava/util/concurrent/ConcurrentHashMap<TK;TV;>;", l3, l11, 0);
178     mv.visitLocalVariable("value", "Ljava/lang/Object;", null, l3, l11, 1);
179     mv.visitLocalVariable("isManaged", "Z", null, l4, l11, 2);
180     mv.visitMaxs(2, 5);
181     mv.visitEnd();
182   }
183
184   private void rewriteSegmentForMethod(MethodVisitor mv) {
185     mv.visitCode();
186     Label l0 = new Label();
187     mv.visitLabel(l0);
188     mv.visitVarInsn(ILOAD, 1);
189     mv.visitMethodInsn(INVOKESTATIC, "java/lang/Math", "abs", "(I)I");
190     mv.visitVarInsn(ISTORE, 1);
191     Label l1 = new Label();
192     mv.visitLabel(l1);
193     mv.visitVarInsn(ALOAD, 0);
194     mv.visitFieldInsn(GETFIELD, CONCURRENT_HASH_MAP_SLASH, "segments",
195                       "[Ljava/util/concurrent/ConcurrentHashMap$Segment;");
196     mv.visitVarInsn(ILOAD, 1);
197     mv.visitVarInsn(ALOAD, 0);
198     mv.visitFieldInsn(GETFIELD, CONCURRENT_HASH_MAP_SLASH, "segments",
199                       "[Ljava/util/concurrent/ConcurrentHashMap$Segment;");
200     mv.visitInsn(ARRAYLENGTH);
201     mv.visitInsn(IREM);
202     mv.visitInsn(AALOAD);
203     mv.visitInsn(ARETURN);
204     Label l2 = new Label();
205     mv.visitLabel(l2);
206     mv.visitMaxs(0, 0);
207     mv.visitEnd();
208   }
209
210   private void createTCFullyLockMethod() {
211     MethodVisitor mv = cv.visitMethod(ACC_PRIVATE, TC_FULLY_LOCK_METHOD_NAME, TC_FULLY_LOCK_METHOD_DESC, null, null);
212     mv.visitCode();
213     Label l0 = new Label();
214     mv.visitLabel(l0);
215     mv.visitLineNumber(789, l0);
216     mv.visitVarInsn(ALOAD, 0);
217     mv.visitFieldInsn(GETFIELD, CONCURRENT_HASH_MAP_SLASH, "segments",
218                       "[Ljava/util/concurrent/ConcurrentHashMap$Segment;");
219     mv.visitVarInsn(ASTORE, 1);
220     Label l1 = new Label();
221     mv.visitLabel(l1);
222     mv.visitLineNumber(790, l1);
223     mv.visitInsn(ICONST_0);
224     mv.visitVarInsn(ISTORE, 2);
225     Label l2 = new Label();
226     mv.visitLabel(l2);
227     Label l3 = new Label();
228     mv.visitJumpInsn(GOTO, l3);
229     Label l4 = new Label();
230     mv.visitLabel(l4);
231     mv.visitLineNumber(791, l4);
232     mv.visitVarInsn(ALOAD, 1);
233     mv.visitVarInsn(ILOAD, 2);
234     mv.visitInsn(AALOAD);
235     mv.visitMethodInsn(INVOKEVIRTUAL, "java/util/concurrent/ConcurrentHashMap$Segment", "lock", "()V");
236     Label l5 = new Label();
237     mv.visitLabel(l5);
238     mv.visitLineNumber(790, l5);
239     mv.visitIincInsn(2, 1);
240     mv.visitLabel(l3);
241     mv.visitVarInsn(ILOAD, 2);
242     mv.visitVarInsn(ALOAD, 1);
243     mv.visitInsn(ARRAYLENGTH);
244     mv.visitJumpInsn(IF_ICMPLT, l4);
245     Label l6 = new Label();
246     mv.visitLabel(l6);
247     mv.visitLineNumber(792, l6);
248     mv.visitInsn(RETURN);
249     Label l7 = new Label();
250     mv.visitLabel(l7);
251     mv.visitLocalVariable("this", "Ljava/util/concurrent/ConcurrentHashMap;",
252                           "Ljava/util/concurrent/ConcurrentHashMap<TK;TV;>;", l0, l7, 0);
253     mv.visitLocalVariable("segments", "[Ljava/util/concurrent/ConcurrentHashMap$Segment;", null, l1, l7, 1);
254     mv.visitLocalVariable("i", "I", null, l2, l6, 2);
255     mv.visitMaxs(2, 3);
256     mv.visitEnd();
257   }
258
259   private void createTCFullyUnLockMethod() {
260     MethodVisitor mv = cv
261         .visitMethod(ACC_PRIVATE, TC_FULLY_UNLOCK_METHOD_NAME, TC_FULLY_UNLOCK_METHOD_DESC, null, null);
262     mv.visitCode();
263     Label l0 = new Label();
264     mv.visitLabel(l0);
265     mv.visitLineNumber(795, l0);
266     mv.visitVarInsn(ALOAD, 0);
267     mv.visitFieldInsn(GETFIELD, CONCURRENT_HASH_MAP_SLASH, "segments",
268                       "[Ljava/util/concurrent/ConcurrentHashMap$Segment;");
269     mv.visitVarInsn(ASTORE, 1);
270     Label l1 = new Label();
271     mv.visitLabel(l1);
272     mv.visitLineNumber(796, l1);
273     mv.visitInsn(ICONST_0);
274     mv.visitVarInsn(ISTORE, 2);
275     Label l2 = new Label();
276     mv.visitLabel(l2);
277     Label l3 = new Label();
278     mv.visitJumpInsn(GOTO, l3);
279     Label l4 = new Label();
280     mv.visitLabel(l4);
281     mv.visitLineNumber(797, l4);
282     mv.visitVarInsn(ALOAD, 1);
283     mv.visitVarInsn(ILOAD, 2);
284     mv.visitInsn(AALOAD);
285     mv.visitMethodInsn(INVOKEVIRTUAL, "java/util/concurrent/ConcurrentHashMap$Segment", "unlock", "()V");
286     Label l5 = new Label();
287     mv.visitLabel(l5);
288     mv.visitLineNumber(796, l5);
289     mv.visitIincInsn(2, 1);
290     mv.visitLabel(l3);
291     mv.visitVarInsn(ILOAD, 2);
292     mv.visitVarInsn(ALOAD, 1);
293     mv.visitInsn(ARRAYLENGTH);
294     mv.visitJumpInsn(IF_ICMPLT, l4);
295     Label l6 = new Label();
296     mv.visitLabel(l6);
297     mv.visitLineNumber(798, l6);
298     mv.visitInsn(RETURN);
299     Label l7 = new Label();
300     mv.visitLabel(l7);
301     mv.visitLocalVariable("this", "Ljava/util/concurrent/ConcurrentHashMap;",
302                           "Ljava/util/concurrent/ConcurrentHashMap<TK;TV;>;", l0, l7, 0);
303     mv.visitLocalVariable("segments", "[Ljava/util/concurrent/ConcurrentHashMap$Segment;", null, l1, l7, 1);
304     mv.visitLocalVariable("i", "I", null, l2, l6, 2);
305     mv.visitMaxs(2, 3);
306     mv.visitEnd();
307   }
308
309   private void createTCDsoRequiredMethod() {
310     MethodVisitor mv = super.visitMethod(ACC_PRIVATE, TC_IS_DSO_HASH_REQUIRED_METHOD_NAME,
311                                          TC_IS_DSO_HASH_REQUIRED_METHOD_DESC, null, null);
312     mv.visitCode();
313     Label l0 = new Label();
314     mv.visitLabel(l0);
315     mv.visitVarInsn(ALOAD, 0);
316     mv.visitMethodInsn(INVOKEVIRTUAL, CONCURRENT_HASH_MAP_SLASH, "__tc_managed", "()Lcom/tc/object/TCObject;");
317     Label l1 = new Label();
318     mv.visitJumpInsn(IFNULL, l1);
319     mv.visitVarInsn(ALOAD, 1);
320     mv.visitTypeInsn(INSTANCEOF, "com/tc/object/bytecode/Manageable");
321     Label l2 = new Label();
322     mv.visitJumpInsn(IFEQ, l2);
323     mv.visitVarInsn(ALOAD, 1);
324     mv.visitTypeInsn(CHECKCAST, "com/tc/object/bytecode/Manageable");
325     mv.visitMethodInsn(INVOKEINTERFACE, "com/tc/object/bytecode/Manageable", "__tc_managed",
326                        "()Lcom/tc/object/TCObject;");
327     mv.visitJumpInsn(IFNONNULL, l1);
328     mv.visitLabel(l2);
329     mv.visitVarInsn(ALOAD, 1);
330     mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "hashCode", "()I");
331     mv.visitVarInsn(ALOAD, 1);
332     mv.visitMethodInsn(INVOKESTATIC, "java/lang/System", "identityHashCode", "(Ljava/lang/Object;)I");
333     mv.visitJumpInsn(IF_ICMPNE, l1);
334     Label l3 = new Label();
335     mv.visitLabel(l3);
336     mv.visitInsn(ICONST_0);
337     mv.visitInsn(IRETURN);
338     mv.visitLabel(l1);
339     mv.visitInsn(ICONST_1);
340     mv.visitInsn(IRETURN);
341     Label l4 = new Label();
342     mv.visitLabel(l4);
343     mv.visitMaxs(0, 0);
344     mv.visitEnd();
345   }
346
347   private void createTCRehashAndSupportMethods() {
348     createTCRehashMethod();
349     createTCClearMethod();
350   }
351
352   private void createTCRehashMethod() {
353     MethodVisitor mv = super.visitMethod(ACC_PUBLIC + ACC_SYNTHETIC, TC_REHASH_METHOD_NAME, TC_REHASH_METHOD_DESC,
354                                          null, null);
355     mv.visitCode();
356     Label l0 = new Label();
357     Label l1 = new Label();
358     mv.visitTryCatchBlock(l0, l1, l1, "java/lang/Throwable");
359     Label l2 = new Label();
360     mv.visitTryCatchBlock(l0, l2, l2, null);
361     Label l3 = new Label();
362     mv.visitLabel(l3);
363     mv.visitLineNumber(670, l3);
364     mv.visitVarInsn(ALOAD, 0);
365     mv.visitMethodInsn(INVOKEVIRTUAL, CONCURRENT_HASH_MAP_SLASH, "size", "()I");
366     Label l4 = new Label();
367     mv.visitJumpInsn(IFLE, l4);
368     Label l5 = new Label();
369     mv.visitLabel(l5);
370     mv.visitLineNumber(671, l5);
371     mv.visitVarInsn(ALOAD, 0);
372     mv.visitMethodInsn(INVOKESPECIAL, CONCURRENT_HASH_MAP_SLASH, TC_FULLY_LOCK_METHOD_NAME, TC_FULLY_LOCK_METHOD_DESC);
373     mv.visitLabel(l0);
374     mv.visitLineNumber(673, l0);
375     mv.visitTypeInsn(NEW, "java/util/ArrayList");
376     mv.visitInsn(DUP);
377     mv.visitMethodInsn(INVOKESPECIAL, "java/util/ArrayList", "<init>", "()V");
378     mv.visitVarInsn(ASTORE, 1);
379     Label l6 = new Label();
380     mv.visitLabel(l6);
381     mv.visitLineNumber(674, l6);
382     mv.visitInsn(ICONST_0);
383     mv.visitVarInsn(ISTORE, 2);
384     Label l7 = new Label();
385     mv.visitLabel(l7);
386     Label l8 = new Label();
387     mv.visitJumpInsn(GOTO, l8);
388     Label l9 = new Label();
389     mv.visitLabel(l9);
390     mv.visitLineNumber(675, l9);
391     mv.visitVarInsn(ALOAD, 0);
392     mv.visitFieldInsn(GETFIELD, CONCURRENT_HASH_MAP_SLASH, "segments",
393                       "[Ljava/util/concurrent/ConcurrentHashMap$Segment;");
394     mv.visitVarInsn(ILOAD, 2);
395     mv.visitInsn(AALOAD);
396     mv.visitFieldInsn(GETFIELD, "java/util/concurrent/ConcurrentHashMap$Segment", "table",
397                       "[Ljava/util/concurrent/ConcurrentHashMap$HashEntry;");
398     mv.visitVarInsn(ASTORE, 3);
399     Label l10 = new Label();
400     mv.visitLabel(l10);
401     mv.visitLineNumber(676, l10);
402     mv.visitInsn(ICONST_0);
403     mv.visitVarInsn(ISTORE, 4);
404     Label l11 = new Label();
405     mv.visitLabel(l11);
406     Label l12 = new Label();
407     mv.visitJumpInsn(GOTO, l12);
408     Label l13 = new Label();
409     mv.visitLabel(l13);
410     mv.visitLineNumber(677, l13);
411     mv.visitVarInsn(ALOAD, 3);
412     mv.visitVarInsn(ILOAD, 4);
413     mv.visitInsn(AALOAD);
414     Label l14 = new Label();
415     mv.visitJumpInsn(IFNULL, l14);
416     Label l15 = new Label();
417     mv.visitLabel(l15);
418     mv.visitLineNumber(678, l15);
419     mv.visitVarInsn(ALOAD, 3);
420     mv.visitVarInsn(ILOAD, 4);
421     mv.visitInsn(AALOAD);
422     mv.visitVarInsn(ASTORE, 5);
423     Label l16 = new Label();
424     mv.visitLabel(l16);
425     mv.visitLineNumber(679, l16);
426     Label l17 = new Label();
427     mv.visitJumpInsn(GOTO, l17);
428     Label l18 = new Label();
429     mv.visitLabel(l18);
430     mv.visitLineNumber(680, l18);
431     mv.visitVarInsn(ALOAD, 1);
432     mv.visitVarInsn(ALOAD, 5);
433     mv.visitMethodInsn(INVOKEINTERFACE, "java/util/List", "add", "(Ljava/lang/Object;)Z");
434     mv.visitInsn(POP);
435     Label l19 = new Label();
436     mv.visitLabel(l19);
437     mv.visitLineNumber(681, l19);
438     mv.visitVarInsn(ALOAD, 5);
439     mv.visitFieldInsn(GETFIELD, "java/util/concurrent/ConcurrentHashMap$HashEntry", "next",
440                       "Ljava/util/concurrent/ConcurrentHashMap$HashEntry;");
441     mv.visitVarInsn(ASTORE, 5);
442     mv.visitLabel(l17);
443     mv.visitLineNumber(679, l17);
444     mv.visitVarInsn(ALOAD, 5);
445     mv.visitJumpInsn(IFNONNULL, l18);
446     mv.visitLabel(l14);
447     mv.visitLineNumber(676, l14);
448     mv.visitIincInsn(4, 1);
449     mv.visitLabel(l12);
450     mv.visitVarInsn(ILOAD, 4);
451     mv.visitVarInsn(ALOAD, 3);
452     mv.visitInsn(ARRAYLENGTH);
453     mv.visitJumpInsn(IF_ICMPLT, l13);
454     Label l20 = new Label();
455     mv.visitLabel(l20);
456     mv.visitLineNumber(674, l20);
457     mv.visitIincInsn(2, 1);
458     mv.visitLabel(l8);
459     mv.visitVarInsn(ILOAD, 2);
460     mv.visitVarInsn(ALOAD, 0);
461     mv.visitFieldInsn(GETFIELD, CONCURRENT_HASH_MAP_SLASH, "segments",
462                       "[Ljava/util/concurrent/ConcurrentHashMap$Segment;");
463     mv.visitInsn(ARRAYLENGTH);
464     mv.visitJumpInsn(IF_ICMPLT, l9);
465     Label l21 = new Label();
466     mv.visitLabel(l21);
467     mv.visitLineNumber(686, l21);
468     mv.visitVarInsn(ALOAD, 0);
469     mv.visitMethodInsn(INVOKEVIRTUAL, CONCURRENT_HASH_MAP_SLASH, "__tc_clear", "()V");
470     Label l22 = new Label();
471     mv.visitLabel(l22);
472     mv.visitLineNumber(687, l22);
473     mv.visitVarInsn(ALOAD, 1);
474     mv.visitMethodInsn(INVOKEINTERFACE, "java/util/List", "iterator", "()Ljava/util/Iterator;");
475     mv.visitVarInsn(ASTORE, 2);
476     Label l23 = new Label();
477     mv.visitLabel(l23);
478     Label l24 = new Label();
479     mv.visitJumpInsn(GOTO, l24);
480     Label l25 = new Label();
481     mv.visitLabel(l25);
482     mv.visitLineNumber(688, l25);
483     mv.visitVarInsn(ALOAD, 2);
484     mv.visitMethodInsn(INVOKEINTERFACE, "java/util/Iterator", "next", "()Ljava/lang/Object;");
485     mv.visitTypeInsn(CHECKCAST, "java/util/concurrent/ConcurrentHashMap$HashEntry");
486     mv.visitTypeInsn(CHECKCAST, "java/util/concurrent/ConcurrentHashMap$HashEntry");
487     mv.visitVarInsn(ASTORE, 3);
488     Label l26 = new Label();
489     mv.visitLabel(l26);
490     mv.visitLineNumber(689, l26);
491     mv.visitVarInsn(ALOAD, 3);
492     mv.visitFieldInsn(GETFIELD, "java/util/concurrent/ConcurrentHashMap$HashEntry", "key", "Ljava/lang/Object;");
493     mv.visitVarInsn(ASTORE, 4);
494     Label l27 = new Label();
495     mv.visitLabel(l27);
496     mv.visitLineNumber(690, l27);
497     mv.visitVarInsn(ALOAD, 3);
498     mv.visitFieldInsn(GETFIELD, "java/util/concurrent/ConcurrentHashMap$HashEntry", "value", "Ljava/lang/Object;");
499     mv.visitVarInsn(ASTORE, 5);
500     Label l28 = new Label();
501     mv.visitLabel(l28);
502     mv.visitLineNumber(691, l28);
503     invokeJdkHashMethod(mv, 4);
504     mv.visitVarInsn(ISTORE, 6);
505     Label l29 = new Label();
506     mv.visitLabel(l29);
507     mv.visitLineNumber(692, l29);
508     mv.visitVarInsn(ALOAD, 0);
509     mv.visitVarInsn(ALOAD, 0);
510     mv.visitVarInsn(ALOAD, 4);
511     mv.visitInsn(ICONST_0);
512     mv.visitMethodInsn(INVOKESPECIAL, CONCURRENT_HASH_MAP_SLASH, TC_HASH_METHOD_NAME, TC_HASH_METHOD_CHECK_DESC);
513     mv.visitMethodInsn(INVOKEVIRTUAL, CONCURRENT_HASH_MAP_SLASH, "segmentFor",
514                        "(I)Ljava/util/concurrent/ConcurrentHashMap$Segment;");
515     mv.visitVarInsn(ALOAD, 4);
516     mv.visitVarInsn(ILOAD, 6);
517     mv.visitVarInsn(ALOAD, 5);
518     mv.visitInsn(ICONST_0);
519     mv.visitMethodInsn(INVOKEVIRTUAL, "java/util/concurrent/ConcurrentHashMap$Segment", TC_PUT_METHOD_NAME,
520                        SEGMENT_TC_PUT_METHOD_DESC);
521     mv.visitInsn(POP);
522     mv.visitLabel(l24);
523     mv.visitLineNumber(687, l24);
524     mv.visitVarInsn(ALOAD, 2);
525     mv.visitMethodInsn(INVOKEINTERFACE, "java/util/Iterator", "hasNext", "()Z");
526     mv.visitJumpInsn(IFNE, l25);
527     Label l30 = new Label();
528     mv.visitLabel(l30);
529     Label l31 = new Label();
530     mv.visitJumpInsn(GOTO, l31);
531     mv.visitLabel(l1);
532     mv.visitLineNumber(694, l1);
533     mv.visitVarInsn(ASTORE, 1);
534     Label l32 = new Label();
535     mv.visitLabel(l32);
536     mv.visitLineNumber(695, l32);
537     mv.visitVarInsn(ALOAD, 1);
538     mv.visitFieldInsn(GETSTATIC, "java/lang/System", "err", "Ljava/io/PrintStream;");
539     mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Throwable", "printStackTrace", "(Ljava/io/PrintStream;)V");
540     Label l33 = new Label();
541     mv.visitLabel(l33);
542     mv.visitJumpInsn(GOTO, l31);
543     mv.visitLabel(l2);
544     mv.visitLineNumber(696, l2);
545     mv.visitVarInsn(ASTORE, 7);
546     Label l34 = new Label();
547     mv.visitLabel(l34);
548     mv.visitLineNumber(697, l34);
549     mv.visitVarInsn(ALOAD, 0);
550     mv.visitMethodInsn(INVOKESPECIAL, CONCURRENT_HASH_MAP_SLASH, TC_FULLY_UNLOCK_METHOD_NAME,
551                        TC_FULLY_UNLOCK_METHOD_DESC);
552     Label l35 = new Label();
553     mv.visitLabel(l35);
554     mv.visitLineNumber(698, l35);
555     mv.visitVarInsn(ALOAD, 7);
556     mv.visitInsn(ATHROW);
557     mv.visitLabel(l31);
558     mv.visitLineNumber(697, l31);
559     mv.visitVarInsn(ALOAD, 0);
560     mv.visitMethodInsn(INVOKESPECIAL, CONCURRENT_HASH_MAP_SLASH, "__tc_fullyUnLock", "()V");
561     mv.visitLabel(l4);
562     mv.visitLineNumber(700, l4);
563     mv.visitInsn(RETURN);
564     Label l36 = new Label();
565     mv.visitLabel(l36);
566     mv.visitLocalVariable("this", "Ljava/util/concurrent/ConcurrentHashMap;",
567                           "Ljava/util/concurrent/ConcurrentHashMap<TK;TV;>;", l3, l36, 0);
568     mv.visitLocalVariable("entries", "Ljava/util/List;", null, l6, l1, 1);
569     mv.visitLocalVariable("i", "I", null, l7, l21, 2);
570     mv.visitLocalVariable("segmentEntries", "[Ljava/util/concurrent/ConcurrentHashMap$HashEntry;", null, l10, l20, 3);
571     mv.visitLocalVariable("j", "I", null, l11, l20, 4);
572     mv.visitLocalVariable("first", "Ljava/util/concurrent/ConcurrentHashMap$HashEntry;", null, l16, l14, 5);
573     mv.visitLocalVariable("i", "Ljava/util/Iterator;", null, l23, l30, 2);
574     mv.visitLocalVariable("entry", "Ljava/util/concurrent/ConcurrentHashMap$HashEntry;", null, l26, l24, 3);
575     mv.visitLocalVariable("key", "Ljava/lang/Object;", null, l27, l24, 4);
576     mv.visitLocalVariable("value", "Ljava/lang/Object;", null, l28, l24, 5);
577     mv.visitLocalVariable("hash", "I", null, l29, l24, 6);
578     mv.visitLocalVariable("t", "Ljava/lang/Throwable;", null, l32, l33, 1);
579     mv.visitMaxs(5, 8);
580     mv.visitEnd();
581   }
582
583   private void createTCPutMethod() {
584     MethodVisitor mv = super
585         .visitMethod(ACC_PUBLIC + ACC_SYNTHETIC, TC_PUT_METHOD_NAME, TC_PUT_METHOD_DESC, null, null);
586     mv.visitCode();
587     Label l0 = new Label();
588     mv.visitLabel(l0);
589     mv.visitVarInsn(ALOAD, 2);
590     Label l1 = new Label();
591     mv.visitJumpInsn(IFNONNULL, l1);
592     mv.visitTypeInsn(NEW, "java/lang/NullPointerException");
593     mv.visitInsn(DUP);
594     mv.visitMethodInsn(INVOKESPECIAL, "java/lang/NullPointerException", "<init>", "()V");
595     mv.visitInsn(ATHROW);
596     mv.visitLabel(l1);
597     invokeJdkHashMethod(mv, 1);
598     mv.visitVarInsn(ISTORE, 3);
599     Label l2 = new Label();
600     mv.visitLabel(l2);
601     mv.visitVarInsn(ALOAD, 0);
602     mv.visitVarInsn(ALOAD, 0);
603     mv.visitVarInsn(ALOAD, 1);
604     mv.visitInsn(ICONST_0);
605     mv.visitMethodInsn(INVOKESPECIAL, CONCURRENT_HASH_MAP_SLASH, TC_HASH_METHOD_NAME, TC_HASH_METHOD_CHECK_DESC);
606     mv.visitMethodInsn(INVOKEVIRTUAL, CONCURRENT_HASH_MAP_SLASH, "segmentFor",
607                        "(I)Ljava/util/concurrent/ConcurrentHashMap$Segment;");
608     mv.visitVarInsn(ALOAD, 1);
609     mv.visitVarInsn(ILOAD, 3);
610     mv.visitVarInsn(ALOAD, 2);
611     mv.visitInsn(ICONST_0);
612     mv.visitMethodInsn(INVOKEVIRTUAL, "java/util/concurrent/ConcurrentHashMap$Segment", TC_PUT_METHOD_NAME,
613                        SEGMENT_TC_PUT_METHOD_DESC);
614     mv.visitInsn(ARETURN);
615     Label l3 = new Label();
616     mv.visitLabel(l3);
617     mv.visitMaxs(0, 0);
618     mv.visitEnd();
619   }
620
621   private void createTCClearMethod() {
622     MethodVisitor mv = super.visitMethod(ACC_PRIVATE + ACC_SYNTHETIC, TC_CLEAR_METHOD_NAME, TC_CLEAR_METHOD_DESC, null,
623                                          null);
624     mv.visitCode();
625     Label l0 = new Label();
626     mv.visitLabel(l0);
627     mv.visitInsn(ICONST_0);
628     mv.visitVarInsn(ISTORE, 1);
629     Label l1 = new Label();
630     mv.visitLabel(l1);
631     Label l2 = new Label();
632     mv.visitJumpInsn(GOTO, l2);
633     Label l3 = new Label();
634     mv.visitLabel(l3);
635     mv.visitVarInsn(ALOAD, 0);
636     mv.visitFieldInsn(GETFIELD, CONCURRENT_HASH_MAP_SLASH, "segments",
637                       "[Ljava/util/concurrent/ConcurrentHashMap$Segment;");
638     mv.visitVarInsn(ILOAD, 1);
639     mv.visitInsn(AALOAD);
640     mv.visitMethodInsn(INVOKEVIRTUAL, "java/util/concurrent/ConcurrentHashMap$Segment", TC_CLEAR_METHOD_NAME,
641                        TC_CLEAR_METHOD_DESC);
642     Label l4 = new Label();
643     mv.visitLabel(l4);
644     mv.visitIincInsn(1, 1);
645     mv.visitLabel(l2);
646     mv.visitVarInsn(ILOAD, 1);
647     mv.visitVarInsn(ALOAD, 0);
648     mv.visitFieldInsn(GETFIELD, CONCURRENT_HASH_MAP_SLASH, "segments",
649                       "[Ljava/util/concurrent/ConcurrentHashMap$Segment;");
650     mv.visitInsn(ARRAYLENGTH);
651     mv.visitJumpInsn(IF_ICMPLT, l3);
652     Label l5 = new Label();
653     mv.visitLabel(l5);
654     mv.visitInsn(RETURN);
655     Label l6 = new Label();
656     mv.visitLabel(l6);
657     mv.visitMaxs(0, 0);
658     mv.visitEnd();
659   }
660
661   /*
662    * ConcurrentHashMap uses the hashcode of the key and identify the segment to use. Each segment is an ReentrantLock.
663    * This prevents multiple threads to update the same segment at the same time. To support in DSO, we need to check if
664    * the ConcurrentHashMap is a shared object. If it is, we check if the hashcode of the key is the same as the
665    * System.identityHashCode. If it is, we will use the DSO ObjectID of the key to be the hashcode. Since the ObjectID
666    * of the key is a cluster-wide constant, different node will identify the same segment based on the ObjectID of the
667    * key. If the hashcode of the key is not the same as the System.identityHashCode, that would mean the application has
668    * defined the hashcode of the key and in this case, we could use honor the application defined hashcode of the key.
669    * The reason that we do not want to always use the ObjectID of the key is because if the application has defined the
670    * hashcode of the key, map.get(key1) and map.get(key2) will return the same object if key1 and key2 has the same
671    * application defined hashcode even though key1 and key2 has 2 different ObjectID. Using ObjectID as the hashcode in
672    * this case will prevent map.get(key1) and map.get(key2) to return the same result. If the application has not
673    * defined the hashcode of the key, key1 and key2 will have 2 different hashcode (due to the fact that they will have
674    * different System.identityHashCode). Therefore, map.get(key1) and map.get(key2) will return different objects. In
675    * this case, using ObjectID will have the proper behavior. One limitation is that if the application define the
676    * hashcode as some combination of system specific data such as a combination of System.identityHashCode() and some
677    * other data, the current support of ConcurrentHashMap does not support this scenario. Another limitation is that if
678    * the application defined hashcode of the key happens to be the same as the System.identityHashCode, the current
679    * support of ConcurrentHashMap does not support this scenario either.
680    */

681   private void createTCSharedHashMethod() {
682     MethodVisitor mv = cv
683         .visitMethod(ACC_PRIVATE + ACC_SYNTHETIC, TC_HASH_METHOD_NAME, TC_HASH_METHOD_DESC, null, null);
684     Label l0 = new Label();
685     mv.visitLabel(l0);
686     mv.visitVarInsn(ALOAD, 0);
687     mv.visitVarInsn(ALOAD, 1);
688     mv.visitInsn(ICONST_1);
689     mv.visitMethodInsn(INVOKESPECIAL, CONCURRENT_HASH_MAP_SLASH, TC_HASH_METHOD_NAME, TC_HASH_METHOD_CHECK_DESC);
690     mv.visitInsn(IRETURN);
691     Label l1 = new Label();
692     mv.visitLabel(l1);
693     mv.visitMaxs(0, 0);
694     mv.visitEnd();
695   }
696
697   private void createTCForcedHashMethod() {
698     MethodVisitor mv = super.visitMethod(ACC_PRIVATE + ACC_SYNTHETIC, TC_HASH_METHOD_NAME, TC_HASH_METHOD_CHECK_DESC,
699                                          null, null);
700     mv.visitCode();
701     Label l0 = new Label();
702     mv.visitLabel(l0);
703     mv.visitVarInsn(ALOAD, 1);
704     mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "hashCode", "()I");
705     mv.visitVarInsn(ISTORE, 3);
706     Label l1 = new Label();
707     mv.visitLabel(l1);
708     mv.visitInsn(ICONST_0);
709     mv.visitVarInsn(ISTORE, 4);
710     Label l2 = new Label();
711     mv.visitLabel(l2);
712     mv.visitVarInsn(ALOAD, 1);
713     mv.visitMethodInsn(INVOKESTATIC, "java/lang/System", "identityHashCode", "(Ljava/lang/Object;)I");
714     mv.visitVarInsn(ILOAD, 3);
715     Label l3 = new Label();
716     mv.visitJumpInsn(IF_ICMPNE, l3);
717     Label l4 = new Label();
718     mv.visitLabel(l4);
719     mv.visitVarInsn(ILOAD, 2);
720     Label l5 = new Label();
721     mv.visitJumpInsn(IFEQ, l5);
722     Label l6 = new Label();
723     mv.visitLabel(l6);
724     mv.visitVarInsn(ALOAD, 0);
725     mv.visitMethodInsn(INVOKEVIRTUAL, CONCURRENT_HASH_MAP_SLASH, "__tc_managed", "()Lcom/tc/object/TCObject;");
726     Label l7 = new Label();
727     mv.visitJumpInsn(IFNONNULL, l7);
728     mv.visitMethodInsn(INVOKESTATIC, "com/tc/object/bytecode/ManagerUtil", "isCreationInProgress", "()Z");
729     mv.visitJumpInsn(IFEQ, l3);
730     mv.visitLabel(l7);
731     mv.visitInsn(ICONST_1);
732     mv.visitVarInsn(ISTORE, 4);
733     mv.visitJumpInsn(GOTO, l3);
734     mv.visitLabel(l5);
735     mv.visitInsn(ICONST_1);
736     mv.visitVarInsn(ISTORE, 4);
737     mv.visitLabel(l3);
738     mv.visitVarInsn(ILOAD, 4);
739     Label l8 = new Label();
740     mv.visitJumpInsn(IFEQ, l8);
741     Label l9 = new Label();
742     mv.visitLabel(l9);
743     mv.visitVarInsn(ALOAD, 1);
744     mv.visitMethodInsn(INVOKESTATIC, "com/tc/object/bytecode/ManagerUtil", "shareObjectIfNecessary",
745                        "(Ljava/lang/Object;)Lcom/tc/object/TCObject;");
746     mv.visitVarInsn(ASTORE, 5);
747     Label l10 = new Label();
748     mv.visitLabel(l10);
749     mv.visitVarInsn(ALOAD, 5);
750     mv.visitJumpInsn(IFNULL, l8);
751     mv.visitVarInsn(ALOAD, 5);
752     mv.visitMethodInsn(INVOKEINTERFACE, "com/tc/object/TCObject", "getObjectID", "()Lcom/tc/object/ObjectID;");
753     mv.visitMethodInsn(INVOKEVIRTUAL, "com/tc/object/ObjectID", "hashCode", "()I");
754     mv.visitVarInsn(ISTORE, 3);
755     mv.visitLabel(l8);
756     mv.visitVarInsn(ILOAD, 3);
757     mv.visitVarInsn(ILOAD, 3);
758     mv.visitIntInsn(BIPUSH, 9);
759     mv.visitInsn(ISHL);
760     mv.visitInsn(ICONST_M1);
761     mv.visitInsn(IXOR);
762     mv.visitInsn(IADD);
763     mv.visitVarInsn(ISTORE, 3);
764     Label l11 = new Label();
765     mv.visitLabel(l11);
766     mv.visitVarInsn(ILOAD, 3);
767     mv.visitVarInsn(ILOAD, 3);
768     mv.visitIntInsn(BIPUSH, 14);
769     mv.visitInsn(IUSHR);
770     mv.visitInsn(IXOR);
771     mv.visitVarInsn(ISTORE, 3);
772     Label l12 = new Label();
773     mv.visitLabel(l12);
774     mv.visitVarInsn(ILOAD, 3);
775     mv.visitVarInsn(ILOAD, 3);
776     mv.visitInsn(ICONST_4);
777     mv.visitInsn(ISHL);
778     mv.visitInsn(IADD);
779     mv.visitVarInsn(ISTORE, 3);
780     Label l13 = new Label();
781     mv.visitLabel(l13);
782     mv.visitVarInsn(ILOAD, 3);
783     mv.visitVarInsn(ILOAD, 3);
784     mv.visitIntInsn(BIPUSH, 10);
785     mv.visitInsn(IUSHR);
786     mv.visitInsn(IXOR);
787     mv.visitVarInsn(ISTORE, 3);
788     Label l14 = new Label();
789     mv.visitLabel(l14);
790     mv.visitVarInsn(ILOAD, 3);
791     mv.visitInsn(IRETURN);
792     Label l17 = new Label();
793     mv.visitLabel(l17);
794     mv.visitMaxs(0, 0);
795     mv.visitEnd();
796   }
797
798   private static class EntrySetMethodAdapter extends MethodAdapter implements Opcodes {
799
800     public EntrySetMethodAdapter(MethodVisitor mv) {
801       super(mv);
802     }
803
804     public void visitMethodInsn(int opcode, String JavaDoc owner, String JavaDoc name, String JavaDoc desc) {
805       super.visitMethodInsn(opcode, owner, name, desc);
806
807       if ((opcode == INVOKESPECIAL) && "java/util/concurrent/ConcurrentHashMap$EntrySet".equals(owner)
808           && "<init>".equals(name) && "(Ljava/util/concurrent/ConcurrentHashMap;)V".equals(desc)) {
809         mv.visitVarInsn(ASTORE, 1);
810         mv.visitTypeInsn(NEW, "com/tcclient/util/ConcurrentHashMapEntrySetWrapper");
811         mv.visitInsn(DUP);
812         mv.visitVarInsn(ALOAD, 0);
813         mv.visitVarInsn(ALOAD, 1);
814         mv.visitMethodInsn(INVOKESPECIAL, "com/tcclient/util/ConcurrentHashMapEntrySetWrapper", "<init>",
815                            "(Ljava/util/Map;Ljava/util/Set;)V");
816       }
817     }
818   }
819
820   private abstract static class AddCheckManagedKeyMethodAdapter extends MethodAdapter implements Opcodes {
821     public AddCheckManagedKeyMethodAdapter(MethodVisitor mv) {
822       super(mv);
823     }
824
825     public void visitCode() {
826       super.visitCode();
827       addCheckManagedKeyCode();
828     }
829
830     protected abstract void addCheckManagedKeyCode();
831   }
832
833   private static class ContainsKeyMethodAdapter extends AddCheckManagedKeyMethodAdapter {
834     public ContainsKeyMethodAdapter(MethodVisitor mv) {
835       super(mv);
836     }
837
838     protected void addCheckManagedKeyCode() {
839       mv.visitVarInsn(ALOAD, 0);
840       mv.visitVarInsn(ALOAD, 1);
841       mv.visitMethodInsn(INVOKESPECIAL, CONCURRENT_HASH_MAP_SLASH, TC_IS_DSO_HASH_REQUIRED_METHOD_NAME,
842                          TC_IS_DSO_HASH_REQUIRED_METHOD_DESC);
843       Label l1 = new Label();
844       mv.visitJumpInsn(IFNE, l1);
845       Label l2 = new Label();
846       mv.visitLabel(l2);
847       mv.visitInsn(ICONST_0);
848       mv.visitInsn(IRETURN);
849       mv.visitLabel(l1);
850     }
851   }
852
853   private static class GetMethodAdapter extends AddCheckManagedKeyMethodAdapter {
854     public GetMethodAdapter(MethodVisitor mv) {
855       super(mv);
856     }
857
858     protected void addCheckManagedKeyCode() {
859       mv.visitVarInsn(ALOAD, 0);
860       mv.visitVarInsn(ALOAD, 1);
861       mv.visitMethodInsn(INVOKESPECIAL, CONCURRENT_HASH_MAP_SLASH, TC_IS_DSO_HASH_REQUIRED_METHOD_NAME,
862                          TC_IS_DSO_HASH_REQUIRED_METHOD_DESC);
863       Label l1 = new Label();
864       mv.visitJumpInsn(IFNE, l1);
865       Label l2 = new Label();
866       mv.visitLabel(l2);
867       mv.visitInsn(ACONST_NULL);
868       mv.visitInsn(ARETURN);
869       mv.visitLabel(l1);
870     }
871   }
872
873   private static class SimpleRemoveMethodAdapter extends GetMethodAdapter {
874     public SimpleRemoveMethodAdapter(MethodVisitor mv) {
875       super(mv);
876     }
877   }
878
879   private static class SimpleReplaceMethodAdapter extends SimpleRemoveMethodAdapter {
880     private Label target;
881
882     public SimpleReplaceMethodAdapter(MethodVisitor mv) {
883       super(mv);
884     }
885
886     public void visitCode() {
887       mv.visitCode();
888     }
889
890     public void visitJumpInsn(int opcode, Label label) {
891       super.visitJumpInsn(opcode, label);
892       if (IFNONNULL == opcode) {
893         target = label;
894       }
895     }
896
897     public void visitLabel(Label label) {
898       super.visitLabel(label);
899       if (label.equals(target)) {
900         addCheckManagedKeyCode();
901       }
902     }
903   }
904
905   private static class RemoveMethodAdapter extends AddCheckManagedKeyMethodAdapter {
906     public RemoveMethodAdapter(MethodVisitor mv) {
907       super(mv);
908     }
909
910     protected void addCheckManagedKeyCode() {
911       mv.visitVarInsn(ALOAD, 0);
912       mv.visitVarInsn(ALOAD, 1);
913       mv.visitMethodInsn(INVOKESPECIAL, CONCURRENT_HASH_MAP_SLASH, TC_IS_DSO_HASH_REQUIRED_METHOD_NAME,
914                          TC_IS_DSO_HASH_REQUIRED_METHOD_DESC);
915       Label l1 = new Label();
916       mv.visitJumpInsn(IFNE, l1);
917       Label l2 = new Label();
918       mv.visitLabel(l2);
919       mv.visitInsn(ICONST_0);
920       mv.visitInsn(IRETURN);
921       mv.visitLabel(l1);
922     }
923   }
924
925   private static class ReplaceMethodAdapter extends RemoveMethodAdapter {
926     private Label target;
927
928     public ReplaceMethodAdapter(MethodVisitor mv) {
929       super(mv);
930     }
931
932     public void visitCode() {
933       mv.visitCode();
934     }
935
936     public void visitJumpInsn(int opcode, Label label) {
937       super.visitJumpInsn(opcode, label);
938       if (IFNONNULL == opcode) {
939         target = label;
940       }
941     }
942
943     public void visitLabel(Label label) {
944       super.visitLabel(label);
945       if (label.equals(target)) {
946         addCheckManagedKeyCode();
947       }
948     }
949   }
950
951   private static class ConcurrentHashMapMethodAdapter extends LocalVariablesSorter implements Opcodes {
952
953     public ConcurrentHashMapMethodAdapter(int access, String JavaDoc desc, MethodVisitor mv) {
954       super(access, desc, mv);
955     }
956
957     public int newLocal(int size) {
958       return super.newLocal(size);
959     }
960
961     public void visitMethodInsn(int opcode, String JavaDoc owner, String JavaDoc name, String JavaDoc desc) {
962       if (INVOKEVIRTUAL == opcode && CONCURRENT_HASH_MAP_SLASH.equals(owner) && "segmentFor".equals(name)
963           && "(I)Ljava/util/concurrent/ConcurrentHashMap$Segment;".equals(desc)) {
964         mv.visitInsn(POP);
965         ByteCodeUtil.pushThis(mv);
966         mv.visitVarInsn(ALOAD, 1);
967         mv.visitMethodInsn(INVOKEVIRTUAL, owner, TC_HASH_METHOD_NAME, TC_HASH_METHOD_DESC);
968         super.visitMethodInsn(opcode, owner, name, desc);
969       } else if (INVOKESPECIAL == opcode
970                  && JavaUtilConcurrentHashMapSegmentAdapter.CONCURRENT_HASH_MAP_SEGMENT_SLASH.equals(owner)
971                  && "<init>".equals(name) && "(IF)V".equals(desc)) {
972         mv.visitInsn(POP);
973         mv.visitInsn(POP);
974         ByteCodeUtil.pushThis(mv);
975         mv.visitVarInsn(ILOAD, 7);
976         mv.visitVarInsn(FLOAD, 2);
977         mv.visitMethodInsn(opcode, owner, name, JavaUtilConcurrentHashMapSegmentAdapter.INIT_DESC);
978       } else {
979         super.visitMethodInsn(opcode, owner, name, desc);
980       }
981     }
982   }
983
984   private void invokeJdkHashMethod(MethodVisitor mv, int objectVarNumber) {
985     mv.visitVarInsn(ALOAD, objectVarNumber);
986     if (Vm.isJDK16()) {
987       mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "hashCode", "()I");
988       mv.visitMethodInsn(INVOKESTATIC, CONCURRENT_HASH_MAP_SLASH, HASH_METHOD_NAME, "(I)I");
989     } else {
990       mv.visitMethodInsn(INVOKESTATIC, CONCURRENT_HASH_MAP_SLASH, HASH_METHOD_NAME, "(Ljava/lang/Object;)I");
991     }
992   }
993 }
Popular Tags