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.Label;
008: import com.tc.asm.MethodVisitor;
009: import com.tc.asm.Opcodes;
010: import com.tc.asm.Type;
011: import com.tc.asm.commons.AdviceAdapter;
012: import com.tc.aspectwerkz.reflect.ClassInfo;
013: import com.tc.aspectwerkz.reflect.FieldInfo;
014: import com.tc.aspectwerkz.reflect.MemberInfo;
015: import com.tc.aspectwerkz.reflect.impl.asm.AsmClassInfo;
016: import com.tc.exception.TCInternalError;
017: import com.tc.object.config.LockDefinition;
018: import com.tc.object.config.TransparencyClassSpec;
019: import com.tc.object.config.TransparencyCodeSpec;
020: import com.tc.object.lockmanager.api.LockLevel;
021:
022: import java.util.AbstractMap;
023:
024: /**
025: * @author steve
026: */
027: public class TransparencyCodeAdapter extends AdviceAdapter implements
028: Opcodes {
029: private final boolean isAutolock;
030: private final int autoLockType;
031: private final ManagerHelper mgrHelper;
032: private final InstrumentationSpec spec;
033: private final MemberInfo memberInfo;
034: private boolean isConstructor;
035:
036: private final TransparencyCodeSpec codeSpec;
037: private final Label labelZero = new Label();
038:
039: private boolean visitInit = false;
040: private boolean logicalInitVisited = false;
041:
042: public TransparencyCodeAdapter(InstrumentationSpec spec,
043: boolean isAutolock, int autoLockType, MethodVisitor mv,
044: MemberInfo memberInfo, String originalName) {
045: super (mv, memberInfo.getModifiers(), originalName, memberInfo
046: .getSignature());
047: this .spec = spec;
048: this .isAutolock = isAutolock;
049: this .autoLockType = autoLockType;
050: this .memberInfo = memberInfo;
051:
052: this .mgrHelper = spec.getManagerHelper();
053: this .codeSpec = spec.getTransparencyClassSpec().getCodeSpec(
054: memberInfo.getName(), //
055: memberInfo.getSignature(), isAutolock);
056:
057: isConstructor = "<init>".equals(originalName);
058: if (!isConstructor) {
059: visitInit = true;
060: }
061: }
062:
063: private int[] storeStackValuesToLocalVariables(String methodInsnDesc) {
064: Type[] types = Type.getArgumentTypes(methodInsnDesc);
065: int[] localVariablesForMethodCall = new int[types.length];
066: for (int i = 0; i < types.length; i++) {
067: localVariablesForMethodCall[i] = newLocal(types[i]);
068: }
069: for (int i = types.length - 1; i >= 0; i--) {
070: super .visitVarInsn(types[i].getOpcode(ISTORE),
071: localVariablesForMethodCall[i]);
072: }
073: return localVariablesForMethodCall;
074: }
075:
076: private void loadLocalVariables(String methodInsnDesc,
077: int[] localVariablesForMethodCall) {
078: Type[] types = Type.getArgumentTypes(methodInsnDesc);
079: for (int i = 0; i < types.length; i++) {
080: super .visitVarInsn(types[i].getOpcode(ILOAD),
081: localVariablesForMethodCall[i]);
082: }
083: }
084:
085: public void visitMethodInsn(int opcode, String owner, String name,
086: String desc) {
087: if (spec.hasDelegatedToLogicalClass() && isConstructor) {
088: logicalInitVisitMethodInsn(opcode, owner, name, desc);
089: } else {
090: basicVisitMethodInsn(opcode, owner, name, desc);
091: }
092: }
093:
094: private void logicalInitVisitMethodInsn(int opcode, String owner,
095: String name, String desc) {
096: String super ClassNameSlashes = spec.getSuperClassNameSlashes();
097: if (!logicalInitVisited && INVOKESPECIAL == opcode
098: && owner.equals(super ClassNameSlashes)
099: && "<init>".equals(name)) {
100: logicalInitVisited = true;
101: int[] localVariablesForMethodCall = storeStackValuesToLocalVariables(desc);
102: loadLocalVariables(desc, localVariablesForMethodCall);
103: super .visitMethodInsn(opcode, owner, name, desc);
104: super .visitVarInsn(ALOAD, 0);
105: super .visitTypeInsn(NEW, spec.getSuperClassNameSlashes());
106: super .visitInsn(DUP);
107: loadLocalVariables(desc, localVariablesForMethodCall);
108:
109: String delegateFieldName = ClassAdapterBase
110: .getDelegateFieldName(super ClassNameSlashes);
111: super .visitMethodInsn(INVOKESPECIAL, super ClassNameSlashes,
112: "<init>", desc);
113: super .visitMethodInsn(INVOKESPECIAL, spec
114: .getClassNameSlashes(), ByteCodeUtil
115: .fieldSetterMethod(delegateFieldName), "(L"
116: + super ClassNameSlashes + ";)V");
117:
118: } else {
119: basicVisitMethodInsn(opcode, owner, name, desc);
120: }
121: }
122:
123: private void basicVisitMethodInsn(int opcode, String classname,
124: String theMethodName, String desc) {
125: if (handleSubclassOfLogicalClassMethodInsn(opcode, classname,
126: theMethodName, desc)) {
127: return;
128: }
129: if (codeSpec.isArraycopyInstrumentationReq(classname,
130: theMethodName)) {
131: rewriteArraycopy();
132: } else if (classname.equals("java/lang/Object")) {
133: handleJavaLangObjectMethodCall(opcode, classname,
134: theMethodName, desc);
135: } else {
136: super .visitMethodInsn(opcode, classname, theMethodName,
137: desc);
138: }
139: }
140:
141: private boolean handleSubclassOfLogicalClassMethodInsn(int opcode,
142: String classname, String theMethodName, String desc) {
143: if (!spec.hasDelegatedToLogicalClass()) {
144: return false;
145: }
146: String logicalExtendingClassName = spec
147: .getSuperClassNameSlashes();
148: if (INVOKESPECIAL == opcode
149: && !spec.getClassNameSlashes().equals(classname)
150: && !"<init>".equals(theMethodName)) {
151: spec.shouldProceedInstrumentation(
152: memberInfo.getModifiers(), theMethodName, desc);
153: int[] localVariablesForMethodCall = storeStackValuesToLocalVariables(desc);
154: super
155: .visitMethodInsn(
156: INVOKESPECIAL,
157: spec.getClassNameSlashes(),
158: ByteCodeUtil
159: .fieldGetterMethod(ClassAdapterBase
160: .getDelegateFieldName(logicalExtendingClassName)),
161: "()L" + logicalExtendingClassName + ";");
162: loadLocalVariables(desc, localVariablesForMethodCall);
163: super .visitMethodInsn(INVOKEVIRTUAL,
164: logicalExtendingClassName, theMethodName, desc);
165: return true;
166: }
167: return false;
168: }
169:
170: private TransparencyClassSpec getTransparencyClassSpec() {
171: return spec.getTransparencyClassSpec();
172: }
173:
174: private void rewriteArraycopy() {
175: callArrayManagerMethod("arraycopy",
176: "(Ljava/lang/Object;ILjava/lang/Object;II)V");
177: }
178:
179: private void handleJavaLangObjectMethodCall(int opcode,
180: String classname, String theMethodName, String desc) {
181: if (handleJavaLangObjectWaitNotifyCalls(opcode, classname,
182: theMethodName, desc)) {
183: return;
184: } else if (handleJavaLangObjectCloneCall(opcode, classname,
185: theMethodName, desc)) {
186: return;
187: } else {
188: super .visitMethodInsn(opcode, classname, theMethodName,
189: desc);
190: }
191: }
192:
193: /**
194: * The assumption here is that the compiler wouldn't call invokevirtual on a classname other than java.lang.Object
195: * when there is no implementation of clone() defined in that classes' hierarchy. If it does, it a bug in the compiler
196: * ;-) This adaption is needed for both PORTABLE and ADAPTABLE classes as we can have instance where Logical subclass
197: * of ADAPTABLE class calls clone() to make a copy of itself.
198: *
199: * The resolveLock needs to be held for the duration of the clone() call if the reference is to a shared object
200: *
201: * <pre>
202: * Object refToBeCloned;
203: * Object rv;
204: *
205: * TCObject tco = (refToBeCloned instanceof Manageable) ? ((Manageable) refToBeCloned).__tc_managed() : null;
206: * if (tco != null) {
207: * synchronized (tco.getResolveLock()) {
208: * tco.resolveAllReferences();
209: * rv = Util.fixTCObjectReferenceOfClonedObject(refToBeCloned, refToBeCloned.clone());
210: * }
211: * } else {
212: * rv = refToBeCloned.clone();
213: * }
214: * </pre>
215: *
216: * @see AbstractMap and HashMap
217: */
218: private boolean handleJavaLangObjectCloneCall(int opcode,
219: String classname, String theMethodName, String desc) {
220: if ("clone".equals(theMethodName)
221: && "()Ljava/lang/Object;".equals(desc)) {
222:
223: Type objectType = Type.getObjectType("java/lang/Object");
224:
225: int refToBeCloned = newLocal(objectType);
226: int ref1 = newLocal(objectType);
227: int ref2 = newLocal(objectType);
228: int ref3 = newLocal(objectType);
229:
230: super .visitVarInsn(ASTORE, refToBeCloned);
231: Label l0 = new Label();
232: Label l1 = new Label();
233: Label l2 = new Label();
234: super .visitTryCatchBlock(l0, l1, l2, null);
235: Label l3 = new Label();
236: super .visitTryCatchBlock(l2, l3, l2, null);
237: super .visitVarInsn(ALOAD, refToBeCloned);
238: super .visitTypeInsn(INSTANCEOF,
239: "com/tc/object/bytecode/Manageable");
240: Label l5 = new Label();
241: super .visitJumpInsn(IFEQ, l5);
242: super .visitVarInsn(ALOAD, refToBeCloned);
243: super .visitTypeInsn(CHECKCAST,
244: "com/tc/object/bytecode/Manageable");
245: super .visitMethodInsn(INVOKEINTERFACE,
246: "com/tc/object/bytecode/Manageable",
247: "__tc_managed", "()Lcom/tc/object/TCObject;");
248: Label l6 = new Label();
249: super .visitJumpInsn(GOTO, l6);
250: super .visitLabel(l5);
251: super .visitInsn(ACONST_NULL);
252: super .visitLabel(l6);
253: super .visitVarInsn(ASTORE, ref2);
254: super .visitVarInsn(ALOAD, ref2);
255: Label l8 = new Label();
256: super .visitJumpInsn(IFNULL, l8);
257: super .visitVarInsn(ALOAD, ref2);
258: super .visitMethodInsn(INVOKEINTERFACE,
259: "com/tc/object/TCObject", "getResolveLock",
260: "()Ljava/lang/Object;");
261: super .visitInsn(DUP);
262: super .visitVarInsn(ASTORE, ref3);
263: super .visitInsn(MONITORENTER);
264: super .visitLabel(l0);
265: super .visitVarInsn(ALOAD, ref2);
266: super .visitMethodInsn(INVOKEINTERFACE,
267: "com/tc/object/TCObject", "resolveAllReferences",
268: "()V");
269: super .visitVarInsn(ALOAD, refToBeCloned);
270: super .visitVarInsn(ALOAD, refToBeCloned);
271: super .visitMethodInsn(opcode, classname, theMethodName,
272: desc);
273: super
274: .visitMethodInsn(INVOKESTATIC,
275: "com/tc/object/bytecode/hook/impl/Util",
276: "fixTCObjectReferenceOfClonedObject",
277: "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
278: super .visitVarInsn(ASTORE, ref1);
279: super .visitVarInsn(ALOAD, ref3);
280: super .visitInsn(MONITOREXIT);
281: super .visitLabel(l1);
282: Label l12 = new Label();
283: super .visitJumpInsn(GOTO, l12);
284: super .visitLabel(l2);
285: super .visitVarInsn(ALOAD, ref3);
286: super .visitInsn(MONITOREXIT);
287: super .visitLabel(l3);
288: super .visitInsn(ATHROW);
289: super .visitLabel(l8);
290: super .visitVarInsn(ALOAD, refToBeCloned);
291: super .visitMethodInsn(opcode, classname, theMethodName,
292: desc);
293: super .visitVarInsn(ASTORE, ref1);
294: super .visitLabel(l12);
295: super .visitVarInsn(ALOAD, ref1);
296: return true;
297: }
298: return false;
299: }
300:
301: private boolean handleJavaLangObjectWaitNotifyCalls(int opcode,
302: String classname, String theMethodName, String desc) {
303: if (spec.isLogical()
304: || !codeSpec.isWaitNotifyInstrumentationReq()) {
305: return false;
306: }
307:
308: Type[] args = Type.getArgumentTypes(desc);
309:
310: if (theMethodName.equals("notify")
311: || theMethodName.equals("notifyAll")) {
312: if (args.length == 0) {
313: if (theMethodName.endsWith("All")) {
314: mgrHelper
315: .callManagerMethod("objectNotifyAll", this );
316: } else {
317: mgrHelper.callManagerMethod("objectNotify", this );
318: }
319: return true;
320: }
321: throw new TCInternalError(
322: "Unexpected java.lang.Object method signature: "
323: + theMethodName + " + " + desc);
324: } else if (theMethodName.equals("wait")) {
325:
326: switch (args.length) {
327: case 0: {
328: mgrHelper.callManagerMethod("objectWait0", this );
329: return true;
330: }
331: case 1: {
332: if (args[0].equals(Type.LONG_TYPE)) {
333: mgrHelper.callManagerMethod("objectWait1", this );
334: return true;
335: }
336: throw new TCInternalError(
337: "Unexpected java.lang.Object method signature: "
338: + theMethodName + " + " + desc);
339: }
340: case 2: {
341: if ((args[0].equals(Type.LONG_TYPE))
342: && (args[1].equals(Type.INT_TYPE))) {
343: mgrHelper.callManagerMethod("objectWait2", this );
344: return true;
345: }
346: throw new TCInternalError(
347: "Unexpected java.lang.Object method signature: "
348: + theMethodName + " + " + desc);
349: }
350: default: {
351: throw new TCInternalError(
352: "Unexpected java.lang.Object method signature: "
353: + theMethodName + " + " + desc);
354: }
355: }
356: } else { // neither wait(...) nor notify[All]()
357: return false;
358: }
359:
360: // should be unreachable
361: }
362:
363: private void callTCBeginWithLocks(MethodVisitor c) {
364: c.visitLabel(new Label());
365: LockDefinition[] defs = getTransparencyClassSpec()
366: .lockDefinitionsFor(memberInfo);
367: for (int i = 0; i < defs.length; i++) {
368: if (!defs[i].isAutolock()) {
369: callTCBeginWithLock(defs[i], c);
370: }
371: }
372: }
373:
374: private void callTCBeginWithLock(LockDefinition lock,
375: MethodVisitor c) {
376: c.visitLdcInsn(ByteCodeUtil.generateNamedLockName(lock
377: .getLockName()));
378: c.visitLdcInsn(new Integer(lock.getLockLevelAsInt()));
379: mgrHelper.callManagerMethod("beginLock", c);
380: }
381:
382: private void callTCCommit(MethodVisitor c) {
383: LockDefinition[] locks = getTransparencyClassSpec()
384: .lockDefinitionsFor(memberInfo);
385: for (int i = 0; i < locks.length; i++) {
386: if (!locks[i].isAutolock()) {
387: c.visitLdcInsn(ByteCodeUtil
388: .generateNamedLockName(locks[i].getLockName()));
389: mgrHelper.callManagerMethod("commitLock", c);
390: }
391: }
392: }
393:
394: private void visitInsnForReadLock(int opCode) {
395: switch (opCode) {
396: case MONITORENTER:
397: super .visitInsn(DUP);
398: super .visitMethodInsn(INVOKESTATIC,
399: "com/tc/object/bytecode/ManagerUtil",
400: "isDsoMonitored", "(Ljava/lang/Object;)Z");
401: Label l1 = new Label();
402: super .visitJumpInsn(IFEQ, l1);
403: super .visitLdcInsn(new Integer(autoLockType));
404: mgrHelper.callManagerMethod("monitorEnter", this );
405: Label l2 = new Label();
406: super .visitJumpInsn(GOTO, l2);
407: super .visitLabel(l1);
408: super .visitInsn(opCode);
409: super .visitLabel(l2);
410: return;
411: case MONITOREXIT:
412: super .visitInsn(DUP);
413: super .visitMethodInsn(INVOKESTATIC,
414: "com/tc/object/bytecode/ManagerUtil",
415: "isDsoMonitorEntered", "(Ljava/lang/Object;)Z");
416: Label l3 = new Label();
417: super .visitJumpInsn(IFEQ, l3);
418: mgrHelper.callManagerMethod("monitorExit", this );
419: Label l4 = new Label();
420: super .visitJumpInsn(GOTO, l4);
421: super .visitLabel(l3);
422: super .visitInsn(opCode);
423: super .visitLabel(l4);
424: return;
425: }
426: }
427:
428: public void visitInsn(int opCode) {
429: if (isMonitorInstrumentationReq(opCode)) {
430: switch (opCode) {
431: case MONITORENTER:
432: if (this .isAutolock) {
433: if (autoLockType == LockLevel.READ) {
434: visitInsnForReadLock(opCode);
435: return;
436: }
437: super .visitInsn(DUP);
438: super .visitLdcInsn(new Integer(autoLockType));
439: mgrHelper.callManagerMethod("monitorEnter", this );
440: super .visitInsn(opCode);
441: } else {
442: super .visitInsn(opCode);
443: }
444: return;
445: case MONITOREXIT:
446: if (this .isAutolock) {
447: if (autoLockType == LockLevel.READ) {
448: visitInsnForReadLock(opCode);
449: return;
450: }
451: super .visitInsn(DUP);
452: super .visitInsn(opCode);
453: mgrHelper.callManagerMethod("monitorExit", this );
454: } else {
455: super .visitInsn(opCode);
456: }
457: return;
458: }
459: }
460: if (isArrayOperatorInstrumentationReq(opCode)) {
461: switch (opCode) {
462: case AALOAD:
463: Label end = new Label();
464: Label notManaged = new Label();
465: Label noIndexException = new Label();
466: super .visitInsn(DUP2);
467: super .visitInsn(POP);
468: callArrayManagerMethod("getObject",
469: "(Ljava/lang/Object;)Lcom/tc/object/TCObject;");
470: super .visitInsn(DUP);
471: super .visitJumpInsn(IFNULL, notManaged);
472: super .visitInsn(DUP2);
473: super .visitInsn(SWAP);
474: super
475: .visitMethodInsn(INVOKEINTERFACE,
476: "com/tc/object/TCObject",
477: "checkArrayIndex",
478: "(I)Ljava/lang/ArrayIndexOutOfBoundsException;");
479: super .visitInsn(DUP);
480: super .visitJumpInsn(IFNULL, noIndexException);
481: super .visitInsn(SWAP);
482: super .visitInsn(POP);
483: super .visitInsn(SWAP);
484: super .visitInsn(POP);
485: super .visitInsn(SWAP);
486: super .visitInsn(POP);
487: super .visitInsn(ATHROW);
488: super .visitLabel(noIndexException);
489: super .visitInsn(POP);
490: super .visitInsn(DUP_X2);
491: super .visitInsn(DUP);
492: super .visitMethodInsn(INVOKEINTERFACE,
493: "com/tc/object/TCObject", "getResolveLock",
494: "()Ljava/lang/Object;");
495: super .visitInsn(MONITORENTER);
496: super .visitInsn(DUP2);
497: super .visitInsn(SWAP);
498: super .visitMethodInsn(INVOKEINTERFACE,
499: "com/tc/object/TCObject",
500: "resolveArrayReference", "(I)V");
501: super .visitInsn(POP);
502: super .visitInsn(opCode);
503: super .visitInsn(SWAP);
504: super .visitMethodInsn(INVOKEINTERFACE,
505: "com/tc/object/TCObject", "getResolveLock",
506: "()Ljava/lang/Object;");
507: super .visitInsn(MONITOREXIT);
508: super .visitJumpInsn(GOTO, end);
509: super .visitLabel(notManaged);
510: super .visitInsn(POP);
511: super .visitInsn(opCode);
512: super .visitLabel(end);
513: return;
514: case AASTORE:
515: callArrayManagerMethod("objectArrayChanged",
516: "([Ljava/lang/Object;ILjava/lang/Object;)V");
517: return;
518: case LASTORE:
519: callArrayManagerMethod("longArrayChanged", "([JIJ)V");
520: return;
521: case SASTORE:
522: callArrayManagerMethod("shortArrayChanged", "([SIS)V");
523: return;
524: case IASTORE:
525: callArrayManagerMethod("intArrayChanged", "([III)V");
526: return;
527: case DASTORE:
528: callArrayManagerMethod("doubleArrayChanged", "([DID)V");
529: return;
530: case FASTORE:
531: callArrayManagerMethod("floatArrayChanged", "([FIF)V");
532: return;
533: case BASTORE:
534: callArrayManagerMethod("byteOrBooleanArrayChanged",
535: "(Ljava/lang/Object;IB)V");
536: return;
537: case CASTORE:
538: callArrayManagerMethod("charArrayChanged", "([CIC)V");
539: return;
540: }
541: }
542: super .visitInsn(opCode);
543: }
544:
545: private boolean isArrayOperatorInstrumentationReq(int opCode) {
546: return ((opCode == AALOAD || opCode == AASTORE
547: || opCode == LASTORE || opCode == SASTORE
548: || opCode == IASTORE || opCode == DASTORE
549: || opCode == FASTORE || opCode == BASTORE || opCode == CASTORE) && codeSpec
550: .isArrayOperatorInstrumentationReq());
551: }
552:
553: private boolean isMonitorInstrumentationReq(int opCode) {
554: return ((opCode == MONITORENTER || opCode == MONITOREXIT) && codeSpec
555: .isMonitorInstrumentationReq());
556: }
557:
558: private void callArrayManagerMethod(String name, String desc) {
559: super .visitMethodInsn(INVOKESTATIC, ManagerUtil.CLASS, name,
560: desc);
561: }
562:
563: public void visitMaxs(int stack, int vars) {
564: super .visitMaxs(stack, vars + 1);
565: }
566:
567: public void visitFieldInsn(final int opcode,
568: final String classname, final String fieldName,
569: final String desc) {
570: spec.shouldProceedInstrumentation(fieldName, desc);
571:
572: if (!spec.needInstrumentFieldInsn() || !visitInit
573: || !codeSpec.isFieldInstrumentationReq(fieldName)) {
574: super .visitFieldInsn(opcode, classname, fieldName, desc);
575: return;
576: }
577:
578: if (spec.isPhysical()) {
579: // if (opcode == GETFIELD && (isRoot(classname, fieldName) || !isPrimitive(Type.getType(desc)))) {
580: if (opcode == GETFIELD) {
581: visitGetFieldInsn(classname, fieldName, desc);
582: return;
583: } else if (opcode == PUTFIELD) {
584: visitSetFieldInsn(classname, fieldName, desc);
585: return;
586: } else if (opcode == PUTSTATIC
587: && isRoot(classname, fieldName)) {
588: String sDesc = "(" + desc + ")V";
589: visitMethodInsn(INVOKESTATIC, classname, ByteCodeUtil
590: .fieldSetterMethod(fieldName), sDesc);
591: return;
592: } else if (opcode == GETSTATIC
593: && isRoot(classname, fieldName)) {
594: String gDesc = "()" + desc;
595: visitMethodInsn(INVOKESTATIC, classname, ByteCodeUtil
596: .fieldGetterMethod(fieldName), gDesc);
597: return;
598: }
599: super .visitFieldInsn(opcode, classname, fieldName, desc);
600: } else {
601: super .visitFieldInsn(opcode, classname, fieldName, desc);
602: }
603: }
604:
605: private void visitSetFieldInsn(String classname, String fieldName,
606: String desc) {
607: boolean inClassHierarchy = spec.isInClassHierarchy(classname);
608: if ((spec.isClassPortable() && inClassHierarchy)
609: || isRoot(classname, fieldName)) {
610: // If the field is a root, we assume that the class is instrumented automatically.
611: // If it is not then bad things are gonna happen anyway.
612: visitUncheckedSetFieldInsn(classname, fieldName, desc);
613: } else if (spec.isClassAdaptable() && inClassHierarchy) {
614: visitSetFieldInsnOriginal(classname, fieldName, desc);
615: } else {
616: visitCheckedSetFieldInsn(classname, fieldName, desc);
617: }
618: }
619:
620: private void visitSetFieldInsnOriginal(String classname,
621: String fieldName, String desc) {
622: // System.err.println("Original :: My class : " + spec.getClassNameSlashes() + " set on : " + classname + " field :
623: // " + fieldName);
624: super .visitFieldInsn(PUTFIELD, classname, fieldName, desc);
625: }
626:
627: private void visitUncheckedSetFieldInsn(String classname,
628: String fieldName, String desc) {
629: // System.err.println("Unchecked :: My class : " + spec.getClassNameSlashes() + " set on : " + classname + " field :
630: // " + fieldName);
631: String sDesc = "(" + desc + ")V";
632: visitMethodInsn(INVOKEVIRTUAL, classname, ByteCodeUtil
633: .fieldSetterMethod(fieldName), sDesc);
634: }
635:
636: /**
637: * This method assumes that we dont have anyinfo on the class that we are setting the field to. so we take the
638: * conservative approach.
639: */
640: private void visitCheckedSetFieldInsn(String classname,
641: String fieldName, String desc) {
642: // System.err.println("Checked :: My class : " + spec.getClassNameSlashes() + " set on : " + classname + " field : "
643: // + fieldName);
644: Type fieldType = Type.getType(desc);
645: Type reference = Type.getType("Ljava/lang/Object;");
646: String sDesc = "(" + desc + ")V";
647:
648: swap(reference, fieldType);
649: super .visitInsn(DUP);
650: Label l1 = new Label();
651: super .visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object",
652: "getClass", "()Ljava/lang/Class;");
653: mgrHelper.callManagerMethod("isPhysicallyInstrumented", this );
654: super .visitJumpInsn(IFEQ, l1);
655: swap(fieldType, reference);
656: visitMethodInsn(INVOKEVIRTUAL, classname, ByteCodeUtil
657: .fieldSetterMethod(fieldName), sDesc);
658: Label l2 = new Label();
659: super .visitJumpInsn(GOTO, l2);
660: super .visitLabel(l1);
661: swap(fieldType, reference);
662: super .visitFieldInsn(PUTFIELD, classname, fieldName, desc);
663: super .visitLabel(l2);
664: }
665:
666: private void visitGetFieldInsn(String classname, String fieldName,
667: String desc) {
668: boolean inClassHierarchy = spec.isInClassHierarchy(classname);
669: if ((spec.isClassPortable() && inClassHierarchy)
670: || isRoot(classname, fieldName)) {
671: // If the field is a root, we assume that the class is instrumented automatically.
672: // If it is not then bad things are gonna happen anyway.
673: visitUncheckedGetFieldInsn(classname, fieldName, desc);
674: } else if (spec.isClassAdaptable() && inClassHierarchy) {
675: visitGetFieldInsnOriginal(classname, fieldName, desc);
676: } else {
677: visitCheckedGetFieldInsn(classname, fieldName, desc);
678: }
679: }
680:
681: private void visitGetFieldInsnOriginal(String classname,
682: String fieldName, String desc) {
683: // System.err.println("Original :: My class : " + spec.getClassNameSlashes() + " get on : " + classname + " field :
684: // " + fieldName);
685: super .visitFieldInsn(GETFIELD, classname, fieldName, desc);
686: }
687:
688: private void visitUncheckedGetFieldInsn(String classname,
689: String fieldName, String desc) {
690: // System.err.println("Unchecked :: My class: " + spec.getClassNameSlashes() + " get on : " + classname + " field :
691: // " + fieldName);
692: String gDesc = "()" + desc;
693: visitMethodInsn(INVOKEVIRTUAL, classname, ByteCodeUtil
694: .fieldGetterMethod(fieldName), gDesc);
695: }
696:
697: /**
698: * This method assumes that we dont have anyinfo on the class that we are setting the field to. so we take the
699: * conservative approach.
700: */
701: private void visitCheckedGetFieldInsn(String classname,
702: String fieldName, String desc) {
703: String gDesc = "()" + desc;
704: super .visitInsn(DUP);
705: Label l1 = new Label();
706: super .visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object",
707: "getClass", "()Ljava/lang/Class;");
708: mgrHelper.callManagerMethod("isPhysicallyInstrumented", this );
709: super .visitJumpInsn(IFEQ, l1);
710: visitMethodInsn(INVOKEVIRTUAL, classname, ByteCodeUtil
711: .fieldGetterMethod(fieldName), gDesc);
712: Label l2 = new Label();
713: super .visitJumpInsn(GOTO, l2);
714: super .visitLabel(l1);
715: super .visitFieldInsn(GETFIELD, classname, fieldName, desc);
716: super .visitLabel(l2);
717: }
718:
719: private boolean isRoot(String classname, String fieldName) {
720: ClassInfo classInfo = AsmClassInfo.getClassInfo(classname
721: .replace('/', '.'), spec.getCaller());
722: FieldInfo[] fields = classInfo.getFields();
723: for (int i = 0; i < fields.length; i++) {
724: FieldInfo fieldInfo = fields[i];
725:
726: if (fieldName.equals(fieldInfo.getName())) {
727: if (getTransparencyClassSpec().isRoot(fieldInfo)) {
728: return true;
729: }
730: }
731: }
732:
733: return false;
734: }
735:
736: protected void onMethodEnter() {
737: if (isConstructor) {
738: visitInit = true;
739: if (getTransparencyClassSpec().isLockMethod(memberInfo)) {
740: callTCBeginWithLocks(this );
741: super .visitLabel(labelZero);
742: }
743: }
744: }
745:
746: protected void onMethodExit(int opcode) {
747: if (isConstructor
748: && getTransparencyClassSpec().isLockMethod(memberInfo)) {
749:
750: if (opcode == RETURN) {
751: callTCCommit(this );
752: } else if (opcode == ATHROW) {
753: // nothing special to do here, exception handler for method will do the commit
754: } else {
755: // <init> should not be returning with any other opcodes
756: throw new AssertionError(
757: "unexpected exit instruction: " + opcode);
758: }
759: }
760: }
761:
762: public void visitEnd() {
763: if (isConstructor
764: && getTransparencyClassSpec().isLockMethod(memberInfo)) {
765: Label labelEnd = new Label();
766: super .visitLabel(labelEnd);
767: super .visitTryCatchBlock(labelZero, labelEnd, labelEnd,
768: null);
769: int localVar = newLocal(Type
770: .getObjectType("java/lang/Object"));
771: super.visitVarInsn(ASTORE, localVar);
772: callTCCommit(mv);
773: super.visitVarInsn(ALOAD, localVar);
774: mv.visitInsn(ATHROW);
775: }
776:
777: super.visitEnd();
778: }
779:
780: }
|