0001: /*
0002: * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright
0003: * notice. All rights reserved.
0004: */
0005: package com.tc.object.bytecode;
0006:
0007: import com.tc.asm.ClassVisitor;
0008: import com.tc.asm.FieldVisitor;
0009: import com.tc.asm.Label;
0010: import com.tc.asm.MethodVisitor;
0011: import com.tc.asm.Type;
0012: import com.tc.aspectwerkz.exception.DefinitionException;
0013: import com.tc.aspectwerkz.reflect.ClassInfo;
0014: import com.tc.aspectwerkz.reflect.FieldInfo;
0015: import com.tc.aspectwerkz.reflect.MemberInfo;
0016: import com.tc.logging.TCLogger;
0017: import com.tc.logging.TCLogging;
0018: import com.tc.object.Portability;
0019: import com.tc.object.config.ConfigLockLevel;
0020: import com.tc.object.config.LockDefinition;
0021: import com.tc.object.config.TransparencyClassSpec;
0022: import com.tc.object.lockmanager.api.LockLevel;
0023: import com.tc.object.logging.InstrumentationLogger;
0024: import com.tc.text.Banner;
0025: import com.tc.util.Assert;
0026:
0027: import java.lang.reflect.Modifier;
0028: import java.util.HashSet;
0029: import java.util.Set;
0030:
0031: /**
0032: * @author steve
0033: */
0034: public class TransparencyClassAdapter extends ClassAdapterBase {
0035: private static final TCLogger logger = TCLogging
0036: .getLogger(TransparencyClassAdapter.class);
0037:
0038: private final Set doNotInstrument = new HashSet();
0039: private final PhysicalClassAdapterLogger physicalClassLogger;
0040: private final InstrumentationLogger instrumentationLogger;
0041:
0042: public TransparencyClassAdapter(ClassInfo classInfo,
0043: TransparencyClassSpec spec, final ClassVisitor cv,
0044: ManagerHelper mgrHelper,
0045: InstrumentationLogger instrumentationLogger,
0046: ClassLoader caller, Portability portability) {
0047: super (classInfo, spec, cv, mgrHelper, caller, portability);
0048: this .instrumentationLogger = instrumentationLogger;
0049: this .physicalClassLogger = new PhysicalClassAdapterLogger(
0050: logger);
0051: }
0052:
0053: protected void basicVisit(final int version, final int access,
0054: final String name, String signature,
0055: final String super ClassName, final String[] interfaces) {
0056:
0057: try {
0058: logger.debug("ADAPTING CLASS: " + name);
0059: super .basicVisit(version, access, name, signature,
0060: super ClassName, interfaces);
0061: getTransparencyClassSpec().createClassSupportMethods(cv);
0062: } catch (RuntimeException e) {
0063: handleInstrumentationException(e);
0064: throw e;
0065: } catch (Error e) {
0066: handleInstrumentationException(e);
0067: throw e;
0068: }
0069: }
0070:
0071: private void handleInstrumentationException(Throwable e) {
0072: logger.fatal(e);
0073: logger.fatal("Calling System.exit(1)");
0074: System.exit(1);
0075: }
0076:
0077: private boolean isRoot(int access, String fieldName) {
0078: try {
0079: FieldInfo fieldInfo = spec.getFieldInfo(fieldName);
0080: boolean isRoot = fieldInfo == null ? false
0081: : getTransparencyClassSpec().isRootInThisClass(
0082: fieldInfo);
0083: boolean isTransient = getTransparencyClassSpec()
0084: .isTransient(access, spec.getClassInfo(), fieldName);
0085: if (isTransient && isRoot) {
0086: if (instrumentationLogger.transientRootWarning()) {
0087: instrumentationLogger.transientRootWarning(
0088: this .spec.getClassNameDots(), fieldName);
0089: }
0090: }
0091: return isRoot;
0092: } catch (RuntimeException e) {
0093: handleInstrumentationException(e);
0094: throw e;
0095: } catch (Error e) {
0096: handleInstrumentationException(e);
0097: throw e;
0098: }
0099: }
0100:
0101: private String rootNameFor(String className, String fieldName) {
0102: try {
0103: return getTransparencyClassSpec().rootNameFor(
0104: spec.getFieldInfo(fieldName));
0105: } catch (RuntimeException e) {
0106: handleInstrumentationException(e);
0107: throw e;
0108: } catch (Error e) {
0109: handleInstrumentationException(e);
0110: throw e;
0111: }
0112: }
0113:
0114: protected FieldVisitor basicVisitField(final int access,
0115: final String name, final String desc, String signature,
0116: final Object value) {
0117:
0118: FieldVisitor fieldVisitor = null;
0119: try {
0120:
0121: if ((spec.isClassPortable() && spec.isPhysical() && !ByteCodeUtil
0122: .isTCSynthetic(name))
0123: || (spec.isClassAdaptable() && isRoot(access, name))) {
0124: // include the field, but remove final modifier for *most* fields
0125: if ((Modifier.isStatic(access) && !isRoot(access, name))
0126: || isMagicSerializationField(access, name, desc)) {
0127: fieldVisitor = cv.visitField(access, name, desc,
0128: signature, value);
0129: } else {
0130: fieldVisitor = cv.visitField(~Modifier.FINAL
0131: & access, name, desc, signature, value);
0132: }
0133: generateGettersSetters(access, name, desc, Modifier
0134: .isStatic(access));
0135: } else {
0136: fieldVisitor = cv.visitField(access, name, desc,
0137: signature, value);
0138: }
0139: } catch (RuntimeException e) {
0140: e.printStackTrace();
0141: handleInstrumentationException(e);
0142: } catch (Error e) {
0143: handleInstrumentationException(e);
0144: throw e;
0145: }
0146: return fieldVisitor;
0147: }
0148:
0149: private static boolean isStatic(int access) {
0150: return Modifier.isStatic(access);
0151: }
0152:
0153: private static boolean isFinal(int access) {
0154: return Modifier.isFinal(access);
0155: }
0156:
0157: private static boolean isPrivate(int access) {
0158: return Modifier.isPrivate(access);
0159: }
0160:
0161: private boolean isMagicSerializationField(int access,
0162: String fieldName, String fieldDesc) {
0163: // this method tests if the given field is the one the magic fields used by java serialization. If it is, we should
0164: // not change any details about this field
0165:
0166: boolean isStatic = isStatic(access);
0167: boolean isFinal = isFinal(access);
0168: boolean isPrivate = isPrivate(access);
0169:
0170: if (isStatic && isFinal) {
0171: if ("J".equals(fieldDesc)
0172: && "serialVersionUID".equals(fieldName)) {
0173: return true;
0174: }
0175: if (isPrivate && "serialPersistentFields".equals(fieldName)
0176: && "[Ljava/io/ObjectStreamField;".equals(fieldDesc)) {
0177: return true;
0178: }
0179: }
0180:
0181: return false;
0182: }
0183:
0184: private void generateGettersSetters(final int fieldAccess,
0185: final String name, final String desc, boolean isStatic) {
0186: boolean isTransient = getTransparencyClassSpec().isTransient(
0187: fieldAccess, spec.getClassInfo(), name);
0188: // Plain getter and setters are generated for transient fields as other instrumented classes might call them.
0189: boolean createPlainAccessors = isTransient && !isStatic;
0190: boolean createInstrumentedAccessors = !isTransient && !isStatic;
0191: boolean createRootAccessors = isRoot(fieldAccess, name);
0192:
0193: int methodAccess = fieldAccess & (~ACC_TRANSIENT);
0194: methodAccess &= (~ACC_FINAL); // remove final modifier since variable might be shadowed
0195: methodAccess &= (~ACC_VOLATILE);
0196: methodAccess |= ACC_SYNTHETIC;
0197:
0198: if (createRootAccessors) {
0199: createRootGetter(methodAccess, name, desc);
0200: } else if (createInstrumentedAccessors) {
0201: if (!ByteCodeUtil.isPrimitive(Type.getType(desc))) {
0202: createInstrumentedGetter(methodAccess, fieldAccess,
0203: name, desc);
0204: } else {
0205: createPlainGetter(methodAccess, fieldAccess, name, desc);
0206: }
0207: } else if (createPlainAccessors) {
0208: createPlainGetter(methodAccess, fieldAccess, name, desc);
0209: }
0210:
0211: if (createInstrumentedAccessors || createRootAccessors) {
0212: createInstrumentedSetter(methodAccess, fieldAccess, name,
0213: desc);
0214: } else if (createPlainAccessors) {
0215: createPlainSetter(methodAccess, fieldAccess, name, desc);
0216: }
0217: }
0218:
0219: private boolean isPrimitive(Type t) {
0220: return ByteCodeUtil.isPrimitive(t);
0221: }
0222:
0223: private MethodVisitor ignoreMethodIfNeeded(int access, String name,
0224: final String desc, String signature,
0225: final String[] exceptions, MemberInfo memberInfo) {
0226: if (name.startsWith(ByteCodeUtil.TC_METHOD_PREFIX)
0227: || doNotInstrument.contains(name + desc)
0228: || getTransparencyClassSpec().doNotInstrument(name)) {
0229: if (!getTransparencyClassSpec().hasCustomMethodAdapter(
0230: memberInfo)) {
0231: physicalClassLogger.logVisitMethodIgnoring(name, desc);
0232: return cv.visitMethod(access, name, desc, signature,
0233: exceptions);
0234: }
0235: }
0236: return null;
0237: }
0238:
0239: protected MethodVisitor basicVisitMethod(int access, String name,
0240: final String desc, String signature,
0241: final String[] exceptions) {
0242: String originalName = name;
0243: MethodVisitor mv = null;
0244:
0245: try {
0246: physicalClassLogger.logVisitMethodBegin(access, name, desc,
0247: signature, exceptions);
0248:
0249: MemberInfo memberInfo = getInstrumentationSpec()
0250: .getMethodInfo(access, name, desc);
0251:
0252: mv = ignoreMethodIfNeeded(access, name, desc, signature,
0253: exceptions, memberInfo);
0254: if (mv != null) {
0255: return mv;
0256: }
0257:
0258: LockDefinition[] locks = getTransparencyClassSpec()
0259: .lockDefinitionsFor(memberInfo);
0260: LockDefinition ld = getTransparencyClassSpec()
0261: .getAutoLockDefinition(locks);
0262: boolean isAutolock = (ld != null);
0263: int lockLevel = -1;
0264: if (isAutolock) {
0265: lockLevel = ld.getLockLevelAsInt();
0266: if (instrumentationLogger.lockInsertion()) {
0267: instrumentationLogger.autolockInserted(this .spec
0268: .getClassNameDots(), name, desc, ld);
0269: }
0270: }
0271: boolean isAutoReadLock = isAutolock
0272: && (lockLevel == LockLevel.READ);
0273:
0274: if (isAutoSynchronized(ld) && !"<init>".equals(name)) {
0275: access |= ACC_SYNCHRONIZED;
0276: }
0277:
0278: boolean isLockMethod = isAutolock
0279: && Modifier.isSynchronized(access)
0280: && !Modifier.isStatic(access);
0281: physicalClassLogger.logVisitMethodCheckIsLockMethod();
0282:
0283: if (!isLockMethod || spec.isClassAdaptable()) {
0284: isLockMethod = (getTransparencyClassSpec()
0285: .getNonAutoLockDefinition(locks) != null);
0286: }
0287:
0288: // handle lock method by re-writing the original method as a wrapper method and rename the original method.
0289: if (isLockMethod && !"<init>".equals(name)) {
0290: physicalClassLogger
0291: .logVisitMethodCreateLockMethod(name);
0292: // This method is a lock method.
0293: Assert.assertNotNull(locks);
0294: Assert.eval(locks.length > 0 || isLockMethod);
0295: createLockMethod(access, name, desc, signature,
0296: exceptions, locks, isAutoReadLock);
0297:
0298: logCustomerLockMethod(name, desc, locks);
0299: name = ByteCodeUtil.METHOD_RENAME_PREFIX + name;
0300: access |= ACC_PRIVATE;
0301: access &= (~ACC_PUBLIC);
0302: access &= (~ACC_PROTECTED);
0303: if (isAutoReadLock) {
0304: access &= (~ACC_SYNCHRONIZED);
0305: }
0306: } else {
0307: physicalClassLogger.logVisitMethodNotALockMethod(
0308: access, this .spec.getClassNameDots(), name,
0309: desc, exceptions);
0310: }
0311:
0312: // Visit the original method by either using a custom adapter or a TransparencyCodeAdapter or both.
0313: if (getTransparencyClassSpec().hasCustomMethodAdapter(
0314: memberInfo)) {
0315: MethodAdapter ma = getTransparencyClassSpec()
0316: .customMethodAdapterFor(
0317: spec.getManagerHelper(), access, name,
0318: originalName, desc, signature,
0319: exceptions, instrumentationLogger,
0320: memberInfo);
0321: mv = ma.adapt(cv);
0322:
0323: if (!ma.doesOriginalNeedAdapting())
0324: return mv;
0325: }
0326:
0327: if (mv == null) {
0328: mv = cv.visitMethod(access, name, desc, signature,
0329: exceptions);
0330: }
0331:
0332: return mv == null ? null : new TransparencyCodeAdapter(
0333: spec, isAutolock, lockLevel, mv, memberInfo,
0334: originalName);
0335: } catch (RuntimeException e) {
0336: handleInstrumentationException(e);
0337: throw e;
0338: } catch (Error e) {
0339: handleInstrumentationException(e);
0340: throw e;
0341: }
0342: }
0343:
0344: private boolean isAutoSynchronized(LockDefinition ld) {
0345: if (ld == null) {
0346: return false;
0347: }
0348:
0349: ConfigLockLevel lockLevel = ld.getLockLevel();
0350: return ConfigLockLevel.AUTO_SYNCHRONIZED_READ.equals(lockLevel)
0351: || ConfigLockLevel.AUTO_SYNCHRONIZED_WRITE
0352: .equals(lockLevel)
0353: || ConfigLockLevel.AUTO_SYNCHRONIZED_CONCURRENT
0354: .equals(lockLevel)
0355: || ConfigLockLevel.AUTO_SYNCHRONIZED_SYNCHRONOUS_WRITE
0356: .equals(lockLevel);
0357: }
0358:
0359: // protected void basicVisitEnd() {
0360: // // if adaptee has DMI
0361: // boolean hasCustomMethodAdapter = getTransparencyClassSpec().hasCustomMethodAdapter(access, originalName, desc,
0362: // exceptions);
0363: // super.basicVisitEnd();
0364: // }
0365:
0366: private void logCustomerLockMethod(String name, final String desc,
0367: LockDefinition[] locks) {
0368: if (instrumentationLogger.lockInsertion()) {
0369: instrumentationLogger.lockInserted(this .spec
0370: .getClassNameDots(), name, desc, locks);
0371: }
0372: }
0373:
0374: private void createLockMethod(int access, String name, String desc,
0375: String signature, final String[] exceptions,
0376: LockDefinition[] locks, boolean skipLocalJVMLock) {
0377: try {
0378: physicalClassLogger.logCreateLockMethodBegin(access, name,
0379: desc, signature, exceptions, locks);
0380: doNotInstrument.add(name + desc);
0381: recreateMethod(access, name, desc, signature, exceptions,
0382: locks, skipLocalJVMLock);
0383: if (skipLocalJVMLock) {
0384: access |= ACC_PRIVATE;
0385: access &= (~ACC_PUBLIC);
0386: access &= (~ACC_PROTECTED);
0387:
0388: createSyncMethod(access, name, desc, signature,
0389: exceptions);
0390: }
0391:
0392: } catch (RuntimeException e) {
0393: handleInstrumentationException(e);
0394: throw e;
0395: } catch (Error e) {
0396: handleInstrumentationException(e);
0397: throw e;
0398: }
0399: }
0400:
0401: private String getTCSyncMethodName(String name) {
0402: return ByteCodeUtil.SYNC_METHOD_RENAME_PREFIX + name;
0403: }
0404:
0405: private void createSyncMethod(int access, String name, String desc,
0406: String signature, final String[] exceptions) {
0407: Type returnType = Type.getReturnType(desc);
0408: // access should have the synchronized modifier
0409: MethodVisitor mv = cv.visitMethod(access,
0410: getTCSyncMethodName(name), desc, signature, exceptions);
0411: mv.visitCode();
0412: Label l0 = new Label();
0413: mv.visitLabel(l0);
0414: callRenamedMethod(access & (~Modifier.SYNCHRONIZED), name,
0415: desc, mv);
0416: Label l1 = new Label();
0417: mv.visitLabel(l1);
0418: mv.visitInsn(returnType.getOpcode(IRETURN));
0419: Label l2 = new Label();
0420: mv.visitLabel(l2);
0421: mv.visitLocalVariable("this", "L" + spec.getClassNameSlashes()
0422: + ";", null, l0, l2, 0);
0423: mv.visitMaxs(1, 1);
0424: mv.visitEnd();
0425: }
0426:
0427: private void recreateMethod(int access, String name, String desc,
0428: String signature, final String[] exceptions,
0429: LockDefinition[] locks, boolean skipLocalJVMLock) {
0430: Type returnType = Type.getReturnType(desc);
0431: physicalClassLogger.logCreateLockMethodVoidBegin(access, name,
0432: desc, signature, exceptions, locks);
0433: MethodVisitor c = cv.visitMethod(access
0434: & (~Modifier.SYNCHRONIZED), name, desc, signature,
0435: exceptions);
0436:
0437: Label l1 = new Label();
0438: if (skipLocalJVMLock) {
0439: ByteCodeUtil.pushThis(c);
0440: c.visitMethodInsn(INVOKESTATIC,
0441: "com/tc/object/bytecode/ManagerUtil",
0442: "isDsoMonitored", "(Ljava/lang/Object;)Z");
0443: c.visitJumpInsn(IFEQ, l1);
0444: }
0445:
0446: if (returnType.getSort() == Type.VOID) {
0447: addDsoLockMethodInsnVoid(access, name, desc, signature,
0448: exceptions, locks, c);
0449: } else {
0450: addDsoLockMethodInsnReturn(access, name, desc, signature,
0451: exceptions, locks, returnType, c);
0452: }
0453:
0454: if (skipLocalJVMLock) {
0455: c.visitLabel(l1);
0456: // access should have the synchronized modifier
0457: callRenamedMethod(access, "sync" + "_" + name, desc, c);
0458:
0459: c.visitInsn(returnType.getOpcode(IRETURN));
0460: }
0461:
0462: c.visitMaxs(0, 0);
0463: c.visitEnd();
0464: }
0465:
0466: private int addBooleanLocalVariablesIfMoreThanOneLock(int access,
0467: String desc, LockDefinition[] locks, MethodVisitor c,
0468: int[] localBooleanVariables) {
0469: int nextLocalVariable = ByteCodeUtil
0470: .getFirstLocalVariableOffset(access, desc);
0471: if (locks.length > 1) {
0472: for (int i = 0; i < locks.length; i++) {
0473: localBooleanVariables[i] = nextLocalVariable;
0474: ByteCodeUtil.pushDefaultValue(localBooleanVariables[i],
0475: c, Type.BOOLEAN_TYPE);
0476: nextLocalVariable += Type.BOOLEAN_TYPE.getSize();
0477: }
0478: }
0479: return nextLocalVariable;
0480: }
0481:
0482: private void startDsoLockTryBlock(int access, String name,
0483: String desc, LockDefinition[] locks, MethodVisitor c,
0484: int[] localBooleanVariables, Label startTryBlockLabel) {
0485: if (locks.length > 1) {
0486: c.visitLabel(startTryBlockLabel);
0487: callTCBeginWithLocks(access, name, desc, locks, c,
0488: localBooleanVariables);
0489: } else {
0490: callTCBeginWithLocks(access, name, desc, locks, c,
0491: localBooleanVariables);
0492: c.visitLabel(startTryBlockLabel);
0493: }
0494: }
0495:
0496: /**
0497: * Creates a tc lock method for the given method that returns void.
0498: */
0499: private void addDsoLockMethodInsnVoid(int access, String name,
0500: String desc, String signature, final String[] exceptions,
0501: LockDefinition[] locks, MethodVisitor c) {
0502: int[] localBooleanVariables = new int[locks.length];
0503: int localVariableOffset = addBooleanLocalVariablesIfMoreThanOneLock(
0504: access, desc, locks, c, localBooleanVariables);
0505:
0506: try {
0507:
0508: Label l0 = new Label();
0509: startDsoLockTryBlock(access, name, desc, locks, c,
0510: localBooleanVariables, l0);
0511: callRenamedMethod(access, name, desc, c);
0512: // This label creation has something to do with try/finally
0513: Label l1 = new Label();
0514: c.visitJumpInsn(GOTO, l1);
0515: Label l2 = new Label();
0516: c.visitLabel(l2);
0517: c.visitVarInsn(ASTORE, 1 + localVariableOffset);
0518: Label l3 = new Label();
0519: c.visitJumpInsn(JSR, l3);
0520: c.visitVarInsn(ALOAD, 1 + localVariableOffset);
0521: c.visitInsn(ATHROW);
0522: c.visitLabel(l3);
0523: c.visitVarInsn(ASTORE, 0 + localVariableOffset);
0524: callTCCommit(access, name, desc, locks, c,
0525: localBooleanVariables);
0526: c.visitVarInsn(RET, 0 + localVariableOffset);
0527: c.visitLabel(l1);
0528: c.visitJumpInsn(JSR, l3);
0529: Label l4 = new Label();
0530: c.visitLabel(l4);
0531: c.visitInsn(RETURN);
0532: c.visitTryCatchBlock(l0, l2, l2, null);
0533: c.visitTryCatchBlock(l1, l4, l2, null);
0534: } catch (RuntimeException e) {
0535: handleInstrumentationException(e);
0536: } catch (Error e) {
0537: handleInstrumentationException(e);
0538: throw e;
0539: }
0540: }
0541:
0542: private void handleInstrumentationException(RuntimeException e) {
0543: // XXX: Yucky.
0544: if (e instanceof DefinitionException) {
0545: logger.fatal(e.getLocalizedMessage());
0546: } else {
0547: logger.fatal(e);
0548: }
0549:
0550: e.printStackTrace(System.err);
0551: System.err.flush();
0552: String msg = "Error detected -- Calling System.exit(1)";
0553: Banner.errorBanner(msg);
0554:
0555: logger.fatal(msg);
0556: System.exit(1);
0557: }
0558:
0559: private void callRenamedMethod(int callingMethodModifier,
0560: String name, String desc, MethodVisitor c) {
0561: // Call the renamed original method.
0562: ByteCodeUtil.prepareStackForMethodCall(callingMethodModifier,
0563: desc, c);
0564: if (Modifier.isStatic(callingMethodModifier)) {
0565: c.visitMethodInsn(INVOKESTATIC, spec.getClassNameSlashes(),
0566: ByteCodeUtil.METHOD_RENAME_PREFIX + name, desc);
0567: } else {
0568: c.visitMethodInsn(INVOKESPECIAL,
0569: spec.getClassNameSlashes(),
0570: ByteCodeUtil.METHOD_RENAME_PREFIX + name, desc);
0571: }
0572: }
0573:
0574: /**
0575: * Creates a tc lock method for the given method that returns a value (doesn't return void).
0576: */
0577: private void addDsoLockMethodInsnReturn(int access, String name,
0578: String desc, String signature, final String[] exceptions,
0579: LockDefinition[] locks, Type returnType, MethodVisitor c) {
0580: int[] localBooleanVariables = new int[locks.length];
0581: int localVariableOffset = addBooleanLocalVariablesIfMoreThanOneLock(
0582: access, desc, locks, c, localBooleanVariables);
0583:
0584: try {
0585: Label l0 = new Label();
0586: startDsoLockTryBlock(access, name, desc, locks, c,
0587: localBooleanVariables, l0);
0588: callRenamedMethod(access, name, desc, c);
0589: c.visitVarInsn(returnType.getOpcode(ISTORE),
0590: 2 + localVariableOffset);
0591: Label l1 = new Label();
0592: c.visitJumpInsn(JSR, l1);
0593: Label l2 = new Label();
0594: c.visitLabel(l2);
0595: c.visitVarInsn(returnType.getOpcode(ILOAD),
0596: 2 + localVariableOffset);
0597: c.visitInsn(returnType.getOpcode(IRETURN));
0598: Label l3 = new Label();
0599: c.visitLabel(l3);
0600: c.visitVarInsn(ASTORE, 1 + localVariableOffset);
0601: c.visitJumpInsn(JSR, l1);
0602: c.visitVarInsn(ALOAD, 1 + localVariableOffset);
0603: c.visitInsn(ATHROW);
0604: c.visitLabel(l1);
0605: c.visitVarInsn(ASTORE, 0 + localVariableOffset);
0606: callTCCommit(access, name, desc, locks, c,
0607: localBooleanVariables);
0608: c.visitVarInsn(RET, 0 + localVariableOffset);
0609: c.visitTryCatchBlock(l0, l2, l3, null);
0610: // c.visitMaxs(0, 0);
0611: } catch (RuntimeException e) {
0612: handleInstrumentationException(e);
0613: } catch (Error e) {
0614: handleInstrumentationException(e);
0615: throw e;
0616: }
0617:
0618: }
0619:
0620: private void callTCBeginWithLocks(int access, String name,
0621: String desc, LockDefinition[] locks, MethodVisitor c,
0622: int[] localBooleanVariables) {
0623: physicalClassLogger.logCallTCBeginWithLocksStart(access, name,
0624: desc, locks, c);
0625: for (int i = 0; i < locks.length; i++) {
0626: LockDefinition lock = locks[i];
0627: if (lock.isAutolock() && spec.isClassPortable()) {
0628: physicalClassLogger.logCallTCBeginWithLocksAutolock();
0629: if (Modifier.isSynchronized(access)
0630: && !Modifier.isStatic(access)) {
0631: physicalClassLogger
0632: .logCallTCBeginWithLocksAutolockSynchronized(
0633: name, desc);
0634: callTCMonitorEnter(access, locks[i], c);
0635: } else {
0636: physicalClassLogger
0637: .logCallTCBeginWithLocksAutolockNotSynchronized(
0638: name, desc);
0639: }
0640: } else if (!lock.isAutolock()) {
0641: physicalClassLogger
0642: .logCallTCBeginWithLocksNoAutolock(lock);
0643: callTCBeginWithLock(lock, c);
0644: }
0645: if (locks.length > 1) {
0646: c.visitInsn(ICONST_1);
0647: c.visitVarInsn(ISTORE, localBooleanVariables[i]);
0648: }
0649: }
0650: }
0651:
0652: private void callTCCommit(int access, String name, String desc,
0653: LockDefinition[] locks, MethodVisitor c,
0654: int[] localBooleanVariables) {
0655: physicalClassLogger.logCallTCCommitBegin(access, name, desc,
0656: locks, c);
0657: Label returnLabel = new Label();
0658: for (int i = 0; i < locks.length; i++) {
0659: if (locks.length > 1) {
0660: c.visitVarInsn(ILOAD, localBooleanVariables[i]);
0661: c.visitJumpInsn(IFEQ, returnLabel);
0662: }
0663: LockDefinition lock = locks[i];
0664: if (lock.isAutolock() && spec.isClassPortable()) {
0665: if (Modifier.isSynchronized(access)
0666: && !Modifier.isStatic(access)) {
0667: callTCMonitorExit(access, c);
0668: }
0669: } else if (!lock.isAutolock()) {
0670: c.visitLdcInsn(ByteCodeUtil.generateNamedLockName(lock
0671: .getLockName()));
0672: spec.getManagerHelper().callManagerMethod("commitLock",
0673: c);
0674: }
0675: }
0676: c.visitLabel(returnLabel);
0677: }
0678:
0679: private void callTCCommitWithLockName(String lockName,
0680: MethodVisitor mv) {
0681: mv.visitLdcInsn(lockName);
0682: spec.getManagerHelper().callManagerMethod("commitLock", mv);
0683: }
0684:
0685: private void callTCBeginWithLock(LockDefinition lock,
0686: MethodVisitor c) {
0687: c.visitLdcInsn(ByteCodeUtil.generateNamedLockName(lock
0688: .getLockName()));
0689: c.visitLdcInsn(new Integer(lock.getLockLevelAsInt()));
0690: spec.getManagerHelper().callManagerMethod("beginLock", c);
0691: }
0692:
0693: private void callTCBeginWithLockName(String lockName,
0694: int lockLevel, MethodVisitor mv) {
0695: mv.visitLdcInsn(lockName);
0696: mv.visitLdcInsn(new Integer(lockLevel));
0697: spec.getManagerHelper().callManagerMethod("beginLock", mv);
0698: }
0699:
0700: private void callVolatileBegin(String fieldName, int lockLevel,
0701: MethodVisitor mv) {
0702: getManaged(mv);
0703: mv.visitLdcInsn(fieldName);
0704: mv.visitIntInsn(BIPUSH, lockLevel);
0705: spec.getManagerHelper().callManagerMethod("beginVolatile", mv);
0706: }
0707:
0708: private void callVolatileCommit(String fieldName, MethodVisitor mv) {
0709: getManaged(mv);
0710: mv.visitLdcInsn(fieldName);
0711: spec.getManagerHelper().callManagerMethod("commitVolatile", mv);
0712: }
0713:
0714: private void createPlainGetter(int methodAccess, int fieldAccess,
0715: String name, String desc) {
0716: boolean isVolatile = isVolatile(fieldAccess, name);
0717:
0718: String gDesc = "()" + desc;
0719: MethodVisitor gv = this .visitMethod(methodAccess, ByteCodeUtil
0720: .fieldGetterMethod(name), gDesc, null, null);
0721: Type t = Type.getType(desc);
0722:
0723: Label l4 = new Label();
0724:
0725: if (isVolatile) {
0726: getManaged(gv);
0727: gv.visitInsn(DUP);
0728: gv.visitVarInsn(ASTORE, 2);
0729: gv.visitJumpInsn(IFNULL, l4);
0730:
0731: Label l0 = new Label();
0732: Label l1 = new Label();
0733: Label l2 = new Label();
0734: gv.visitTryCatchBlock(l0, l1, l2, null);
0735: gv.visitLabel(l0);
0736:
0737: callVolatileBegin(spec.getClassNameDots() + "." + name,
0738: LockLevel.READ, gv);
0739:
0740: Label l6 = new Label();
0741: gv.visitJumpInsn(JSR, l6);
0742: gv.visitLabel(l1);
0743: ByteCodeUtil.pushThis(gv);
0744: gv.visitFieldInsn(GETFIELD, spec.getClassNameSlashes(),
0745: name, desc);
0746: gv.visitInsn(t.getOpcode(IRETURN));
0747: gv.visitLabel(l2);
0748: gv.visitVarInsn(ASTORE, 2);
0749: gv.visitJumpInsn(JSR, l6);
0750: gv.visitVarInsn(ALOAD, 2);
0751: gv.visitInsn(ATHROW);
0752: gv.visitLabel(l6);
0753: gv.visitVarInsn(ASTORE, 1);
0754:
0755: callVolatileCommit(spec.getClassNameDots() + "." + name, gv);
0756: gv.visitVarInsn(RET, 1);
0757: }
0758:
0759: gv.visitLabel(l4);
0760: ByteCodeUtil.pushThis(gv);
0761: gv.visitFieldInsn(GETFIELD, spec.getClassNameSlashes(), name,
0762: desc);
0763: gv.visitInsn(t.getOpcode(IRETURN));
0764:
0765: gv.visitMaxs(0, 0);
0766: }
0767:
0768: private void checkReturnObjectType(String fieldName,
0769: String rootName, String targetType, int loadVariableNumber,
0770: Label matchLabel, MethodVisitor mv) {
0771: mv.visitVarInsn(ALOAD, loadVariableNumber);
0772: mv.visitTypeInsn(INSTANCEOF, targetType);
0773: mv.visitJumpInsn(IFNE, matchLabel);
0774: mv.visitTypeInsn(NEW, "java/lang/ClassCastException");
0775: mv.visitInsn(DUP);
0776: mv.visitTypeInsn(NEW, "java/lang/StringBuffer");
0777: mv.visitInsn(DUP);
0778: mv.visitLdcInsn("The field '");
0779: mv.visitMethodInsn(INVOKESPECIAL, "java/lang/StringBuffer",
0780: "<init>", "(Ljava/lang/String;)V");
0781: mv.visitLdcInsn(fieldName);
0782: mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuffer",
0783: "append",
0784: "(Ljava/lang/String;)Ljava/lang/StringBuffer;");
0785: mv.visitLdcInsn("' with root name '");
0786: mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuffer",
0787: "append",
0788: "(Ljava/lang/String;)Ljava/lang/StringBuffer;");
0789: mv.visitLdcInsn(rootName);
0790: mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuffer",
0791: "append",
0792: "(Ljava/lang/String;)Ljava/lang/StringBuffer;");
0793: mv.visitLdcInsn("' cannot be assigned to a variable of type ");
0794: mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuffer",
0795: "append",
0796: "(Ljava/lang/String;)Ljava/lang/StringBuffer;");
0797: mv.visitLdcInsn(targetType);
0798: mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuffer",
0799: "append",
0800: "(Ljava/lang/String;)Ljava/lang/StringBuffer;");
0801: mv.visitLdcInsn(". This root has a type ");
0802: mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuffer",
0803: "append",
0804: "(Ljava/lang/String;)Ljava/lang/StringBuffer;");
0805: mv.visitVarInsn(ALOAD, loadVariableNumber);
0806: mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object",
0807: "getClass", "()Ljava/lang/Class;");
0808: mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", "getName",
0809: "()Ljava/lang/String;");
0810: mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuffer",
0811: "append",
0812: "(Ljava/lang/String;)Ljava/lang/StringBuffer;");
0813: mv.visitLdcInsn(". ");
0814: mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuffer",
0815: "append",
0816: "(Ljava/lang/String;)Ljava/lang/StringBuffer;");
0817: mv
0818: .visitLdcInsn("Perhaps you have the same root name assigned more than once to variables of different types.");
0819: mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuffer",
0820: "append",
0821: "(Ljava/lang/String;)Ljava/lang/StringBuffer;");
0822: mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuffer",
0823: "toString", "()Ljava/lang/String;");
0824: mv.visitMethodInsn(INVOKESPECIAL,
0825: "java/lang/ClassCastException", "<init>",
0826: "(Ljava/lang/String;)V");
0827: mv.visitInsn(ATHROW);
0828:
0829: }
0830:
0831: private void createRootGetter(int methodAccess, String name,
0832: String desc) {
0833: Type t = Type.getType(desc);
0834: boolean isPrimitive = isPrimitive(t);
0835: boolean isDSOFinal = isRootDSOFinal(name);
0836:
0837: String rootName = rootNameFor(spec.getClassNameSlashes(), name);
0838: String targetType = isPrimitive ? ByteCodeUtil
0839: .sortToWrapperName(t.getSort())
0840: : convertToCheckCastDesc(desc);
0841:
0842: boolean isStatic = Modifier.isStatic(methodAccess);
0843:
0844: Label l1 = new Label();
0845: Label l3 = new Label();
0846: Label l5 = new Label();
0847: Label l6 = new Label();
0848: Label l7 = new Label();
0849: Label l8 = new Label();
0850:
0851: try {
0852: MethodVisitor mv = cv.visitMethod(methodAccess,
0853: ByteCodeUtil.fieldGetterMethod(name), "()" + desc,
0854: null, null);
0855:
0856: if (isDSOFinal) {
0857: callGetFieldInsn(isStatic, name, desc, mv);
0858: if (isPrimitive) {
0859: addPrimitiveTypeZeroCompare(mv, t, l1);
0860: } else {
0861: mv.visitJumpInsn(IFNONNULL, l1);
0862: }
0863: }
0864:
0865: callTCBeginWithLockName(rootName, LockLevel.WRITE, mv);
0866:
0867: mv.visitLabel(l3);
0868: mv.visitLdcInsn(rootName);
0869: spec.getManagerHelper().callManagerMethod("lookupRoot", mv);
0870: mv.visitVarInsn(ASTORE, 1);
0871:
0872: mv.visitVarInsn(ALOAD, 1);
0873: mv.visitJumpInsn(IFNULL, l5);
0874:
0875: checkReturnObjectType(name, rootName, targetType, 1, l6, mv);
0876:
0877: mv.visitLabel(l6);
0878: callPutFieldInsn(isStatic, t, 1, name, desc, mv);
0879: mv.visitJumpInsn(GOTO, l5);
0880:
0881: mv.visitLabel(l7);
0882: mv.visitVarInsn(ASTORE, 3);
0883: mv.visitJumpInsn(JSR, l8);
0884: mv.visitVarInsn(ALOAD, 3);
0885: mv.visitInsn(ATHROW);
0886:
0887: mv.visitLabel(l8);
0888: mv.visitVarInsn(ASTORE, 2);
0889: callTCCommitWithLockName(rootName, mv);
0890: mv.visitVarInsn(RET, 2);
0891:
0892: mv.visitLabel(l5);
0893: mv.visitJumpInsn(JSR, l8);
0894:
0895: mv.visitLabel(l1);
0896: callGetFieldInsn(isStatic, name, desc, mv);
0897: mv.visitInsn(t.getOpcode(IRETURN));
0898: mv.visitTryCatchBlock(l3, l7, l7, null);
0899: mv.visitMaxs(0, 0);
0900: } catch (RuntimeException e) {
0901: handleInstrumentationException(e);
0902: } catch (Error e) {
0903: handleInstrumentationException(e);
0904: throw e;
0905: }
0906: }
0907:
0908: private boolean isVolatile(int access, String fieldName) {
0909: return getTransparencyClassSpec().isVolatile(access,
0910: spec.getClassInfo(), fieldName);
0911: }
0912:
0913: private void createInstrumentedGetter(int methodAccess,
0914: int fieldAccess, String name, String desc) {
0915: try {
0916: Assert.eval(!getTransparencyClassSpec().isLogical());
0917: boolean isVolatile = isVolatile(fieldAccess, name);
0918:
0919: String gDesc = "()" + desc;
0920: MethodVisitor gv = this .visitMethod(methodAccess,
0921: ByteCodeUtil.fieldGetterMethod(name), gDesc, null,
0922: null);
0923: Type t = Type.getType(desc);
0924:
0925: getManaged(gv);
0926: gv.visitInsn(DUP);
0927: gv.visitVarInsn(ASTORE, 3);
0928:
0929: Label l0 = new Label();
0930: gv.visitJumpInsn(IFNULL, l0);
0931:
0932: if (isVolatile) {
0933: callVolatileBegin(spec.getClassNameDots() + '.' + name,
0934: LockLevel.READ, gv);
0935: }
0936:
0937: gv.visitVarInsn(ALOAD, 3);
0938: gv.visitMethodInsn(INVOKEINTERFACE,
0939: "com/tc/object/TCObject", "getResolveLock",
0940: "()Ljava/lang/Object;");
0941: gv.visitInsn(DUP);
0942: gv.visitVarInsn(ASTORE, 2);
0943: gv.visitInsn(MONITORENTER);
0944:
0945: Label l1 = new Label();
0946: gv.visitLabel(l1);
0947:
0948: gv.visitVarInsn(ALOAD, 0);
0949: gv.visitFieldInsn(GETFIELD, spec.getClassNameSlashes(),
0950: name, desc);
0951: Label l5 = new Label();
0952: gv.visitJumpInsn(IFNONNULL, l5);
0953: gv.visitVarInsn(ALOAD, 3);
0954: gv.visitLdcInsn(spec.getClassNameDots() + '.' + name);
0955: gv.visitMethodInsn(INVOKEINTERFACE,
0956: "com/tc/object/TCObject", "resolveReference",
0957: "(Ljava/lang/String;)V");
0958: gv.visitLabel(l5);
0959:
0960: Label l2 = new Label();
0961:
0962: gv.visitVarInsn(ALOAD, 0);
0963: gv.visitFieldInsn(GETFIELD, spec.getClassNameSlashes(),
0964: name, desc);
0965: gv.visitVarInsn(ALOAD, 2);
0966:
0967: gv.visitInsn(MONITOREXIT);
0968: if (isVolatile) {
0969: callVolatileCommit(
0970: spec.getClassNameDots() + "." + name, gv);
0971: }
0972: gv.visitInsn(ARETURN);
0973: gv.visitJumpInsn(GOTO, l0);
0974:
0975: gv.visitLabel(l2);
0976: gv.visitVarInsn(ALOAD, 2);
0977:
0978: gv.visitInsn(MONITOREXIT);
0979: if (isVolatile) {
0980: callVolatileCommit(
0981: spec.getClassNameDots() + "." + name, gv);
0982: }
0983: gv.visitInsn(ATHROW);
0984:
0985: gv.visitLabel(l0);
0986: gv.visitVarInsn(ALOAD, 0);
0987: gv.visitFieldInsn(GETFIELD, spec.getClassNameSlashes(),
0988: name, desc);
0989: gv.visitInsn(t.getOpcode(IRETURN));
0990:
0991: gv.visitTryCatchBlock(l1, l2, l2, null);
0992:
0993: gv.visitMaxs(0, 0);
0994: } catch (RuntimeException e) {
0995: handleInstrumentationException(e);
0996: } catch (Error e) {
0997: handleInstrumentationException(e);
0998: throw e;
0999: }
1000: }
1001:
1002: private void getManaged(MethodVisitor mv) {
1003: mv.visitVarInsn(ALOAD, 0);
1004: mv.visitMethodInsn(INVOKEVIRTUAL, spec.getClassNameSlashes(),
1005: MANAGED_METHOD, "()" + MANAGED_FIELD_TYPE);
1006: }
1007:
1008: private void createPlainSetter(int methodAccess, int fieldAccess,
1009: String name, String desc) {
1010: boolean isVolatile = isVolatile(fieldAccess, name);
1011:
1012: String sDesc = "(" + desc + ")V";
1013: MethodVisitor scv = cv.visitMethod(methodAccess, ByteCodeUtil
1014: .fieldSetterMethod(name), sDesc, null, null);
1015: Type t = Type.getType(desc);
1016:
1017: Label l4 = new Label();
1018:
1019: if (isVolatile) {
1020: getManaged(scv);
1021: scv.visitInsn(DUP);
1022: scv.visitVarInsn(ASTORE, 2);
1023: scv.visitJumpInsn(IFNULL, l4);
1024:
1025: Label l0 = new Label();
1026: Label l1 = new Label();
1027: Label l2 = new Label();
1028: scv.visitTryCatchBlock(l0, l1, l2, null);
1029: scv.visitLabel(l0);
1030:
1031: callVolatileBegin(spec.getClassNameDots() + "." + name,
1032: LockLevel.WRITE, scv);
1033:
1034: Label l6 = new Label();
1035: scv.visitJumpInsn(JSR, l6);
1036: scv.visitLabel(l1);
1037: ByteCodeUtil.pushThis(scv);
1038: scv.visitVarInsn(t.getOpcode(ILOAD), 1);
1039:
1040: scv.visitFieldInsn(PUTFIELD, spec.getClassNameSlashes(),
1041: name, desc);
1042: scv.visitInsn(RETURN);
1043: scv.visitLabel(l2);
1044: scv.visitVarInsn(ASTORE, 2);
1045: scv.visitJumpInsn(JSR, l6);
1046: scv.visitVarInsn(ALOAD, 2);
1047: scv.visitInsn(ATHROW);
1048: scv.visitLabel(l6);
1049: scv.visitVarInsn(ASTORE, 1);
1050: callVolatileCommit(spec.getClassNameDots() + "." + name,
1051: scv);
1052:
1053: scv.visitVarInsn(RET, 1);
1054: }
1055:
1056: scv.visitLabel(l4);
1057: ByteCodeUtil.pushThis(scv);
1058: scv.visitVarInsn(t.getOpcode(ILOAD), 1);
1059:
1060: scv.visitFieldInsn(PUTFIELD, spec.getClassNameSlashes(), name,
1061: desc);
1062: scv.visitInsn(RETURN);
1063: scv.visitMaxs(0, 0);
1064: }
1065:
1066: private void createInstrumentedSetter(int methodAccess,
1067: int fieldAccess, String name, String desc) {
1068: try {
1069: Type t = Type.getType(desc);
1070: if (isRoot(methodAccess, name)) {
1071: createObjectSetter(methodAccess, fieldAccess, name,
1072: desc);
1073: }
1074: // if (((t.getSort() == Type.OBJECT) || (t.getSort() == Type.ARRAY)) && !isLiteral(desc)) {
1075: else if (((t.getSort() == Type.OBJECT) || (t.getSort() == Type.ARRAY))
1076: && !isPrimitive(t)) {
1077: createObjectSetter(methodAccess, fieldAccess, name,
1078: desc);
1079: } else {
1080: createLiteralSetter(methodAccess, fieldAccess, name,
1081: desc);
1082: }
1083: } catch (RuntimeException e) {
1084: handleInstrumentationException(e);
1085: } catch (Error e) {
1086: handleInstrumentationException(e);
1087: throw e;
1088: }
1089: }
1090:
1091: private void createObjectSetter(int methodAccess, int fieldAccess,
1092: String name, String desc) {
1093: try {
1094: if (isRoot(methodAccess, name)) {
1095: boolean isStaticRoot = Modifier.isStatic(methodAccess);
1096: if (instrumentationLogger.rootInsertion()) {
1097: instrumentationLogger.rootInserted(spec
1098: .getClassNameDots(), name, desc,
1099: isStaticRoot);
1100: }
1101:
1102: createRootSetter(methodAccess, name, desc, isStaticRoot);
1103: } else {
1104: createObjectFieldSetter(methodAccess, fieldAccess,
1105: name, desc);
1106: }
1107: } catch (RuntimeException e) {
1108: handleInstrumentationException(e);
1109: } catch (Error e) {
1110: handleInstrumentationException(e);
1111: throw e;
1112: }
1113: }
1114:
1115: private boolean isRootDSOFinal(String name) {
1116: return spec.getTransparencyClassSpec().isRootDSOFinal(
1117: spec.getFieldInfo(name));
1118: }
1119:
1120: private void createRootSetter(int methodAccess, String name,
1121: String desc, boolean isStatic) {
1122: Type t = Type.getType(desc);
1123: boolean isPrimitive = isPrimitive(t);
1124: boolean isDSOFinal = isRootDSOFinal(name);
1125:
1126: try {
1127: String sDesc = "(" + desc + ")V";
1128: String targetType = isPrimitive ? ByteCodeUtil
1129: .sortToWrapperName(t.getSort())
1130: : convertToCheckCastDesc(desc);
1131: MethodVisitor scv = cv.visitMethod(methodAccess,
1132: ByteCodeUtil.fieldSetterMethod(name), sDesc, null,
1133: null);
1134:
1135: Label tryStart = new Label();
1136: Label end = new Label();
1137: Label normalExit = new Label();
1138: Label finallyStart = new Label();
1139: Label exceptionHandler = new Label();
1140:
1141: final int rootInstance = isStatic ? 0 : 1;
1142:
1143: if (!isPrimitive) {
1144: scv.visitVarInsn(ALOAD, rootInstance);
1145: scv.visitJumpInsn(IFNULL, end); // Always ignore request to set roots to null
1146: }
1147:
1148: String rootName = rootNameFor(spec.getClassNameSlashes(),
1149: name);
1150: callTCBeginWithLockName(rootName, LockLevel.WRITE, scv);
1151:
1152: scv.visitLabel(tryStart);
1153:
1154: scv.visitLdcInsn(rootName);
1155: if (isPrimitive) {
1156: ByteCodeUtil.addTypeSpecificParameterLoad(scv, t,
1157: rootInstance);
1158: } else {
1159: scv.visitVarInsn(ALOAD, rootInstance);
1160: }
1161: if (isDSOFinal) {
1162: spec.getManagerHelper().callManagerMethod(
1163: "lookupOrCreateRoot", scv);
1164: } else {
1165: spec.getManagerHelper().callManagerMethod(
1166: "createOrReplaceRoot", scv);
1167: }
1168:
1169: int localVar = rootInstance + 1;
1170: scv.visitVarInsn(ASTORE, localVar);
1171:
1172: Label l0 = new Label();
1173: checkReturnObjectType(name, rootName, targetType, localVar,
1174: l0, scv);
1175:
1176: scv.visitLabel(l0);
1177: callPutFieldInsn(isStatic, t, localVar, name, desc, scv);
1178: scv.visitJumpInsn(GOTO, normalExit);
1179:
1180: scv.visitLabel(exceptionHandler);
1181: scv.visitVarInsn(ASTORE, 3);
1182: scv.visitJumpInsn(JSR, finallyStart);
1183: scv.visitVarInsn(ALOAD, 3);
1184: scv.visitInsn(ATHROW);
1185:
1186: scv.visitLabel(finallyStart);
1187: scv.visitVarInsn(ASTORE, 2);
1188: callTCCommitWithLockName(rootName, scv);
1189: scv.visitVarInsn(RET, 2);
1190:
1191: scv.visitLabel(normalExit);
1192: scv.visitJumpInsn(JSR, finallyStart);
1193: scv.visitLabel(end);
1194: scv.visitInsn(RETURN);
1195: scv.visitTryCatchBlock(tryStart, exceptionHandler,
1196: exceptionHandler, null);
1197: scv.visitMaxs(0, 0);
1198: } catch (RuntimeException e) {
1199: handleInstrumentationException(e);
1200: } catch (Error e) {
1201: handleInstrumentationException(e);
1202: throw e;
1203: }
1204: }
1205:
1206: private void callGetFieldInsn(boolean isStatic, String name,
1207: String desc, MethodVisitor mv) {
1208: int getInsn = isStatic ? GETSTATIC : GETFIELD;
1209:
1210: if (!isStatic)
1211: ByteCodeUtil.pushThis(mv);
1212: mv.visitFieldInsn(getInsn, spec.getClassNameSlashes(), name,
1213: desc);
1214: }
1215:
1216: private void callPutFieldInsn(boolean isStatic, Type targetType,
1217: int localVar, String name, String desc, MethodVisitor mv) {
1218: int putInsn = isStatic ? PUTSTATIC : PUTFIELD;
1219:
1220: if (!isStatic)
1221: ByteCodeUtil.pushThis(mv);
1222: mv.visitVarInsn(ALOAD, localVar);
1223:
1224: if (isPrimitive(targetType)) {
1225: mv.visitTypeInsn(CHECKCAST, ByteCodeUtil
1226: .sortToWrapperName(targetType.getSort()));
1227: mv.visitMethodInsn(INVOKEVIRTUAL, ByteCodeUtil
1228: .sortToWrapperName(targetType.getSort()),
1229: ByteCodeUtil.sortToPrimitiveMethodName(targetType
1230: .getSort()), "()" + desc);
1231: } else {
1232: mv.visitTypeInsn(CHECKCAST, convertToCheckCastDesc(desc));
1233: }
1234:
1235: mv.visitFieldInsn(putInsn, spec.getClassNameSlashes(), name,
1236: desc);
1237: }
1238:
1239: private void generateCodeForVolatileTransactionBegin(Label l1,
1240: Label l2, Label l3, Label l4, String fieldName,
1241: int lockLevel, MethodVisitor scv) {
1242: scv.visitTryCatchBlock(l4, l1, l1, null);
1243: scv.visitTryCatchBlock(l2, l3, l1, null);
1244: scv.visitLabel(l4);
1245: callVolatileBegin(fieldName, lockLevel, scv);
1246: }
1247:
1248: private void generateCodeForVolativeTransactionCommit(Label l1,
1249: Label l2, MethodVisitor scv, int newVar1, int newVar2,
1250: String fieldName) {
1251: scv.visitJumpInsn(GOTO, l2);
1252: scv.visitLabel(l1);
1253: scv.visitVarInsn(ASTORE, newVar2);
1254: Label l5 = new Label();
1255: scv.visitJumpInsn(JSR, l5);
1256: scv.visitVarInsn(ALOAD, newVar2);
1257: scv.visitInsn(ATHROW);
1258: scv.visitLabel(l5);
1259: scv.visitVarInsn(ASTORE, newVar1);
1260: callVolatileCommit(fieldName, scv);
1261: scv.visitVarInsn(RET, newVar1);
1262: scv.visitLabel(l2);
1263: scv.visitJumpInsn(JSR, l5);
1264: }
1265:
1266: private void createObjectFieldSetter(int methodAccess,
1267: int fieldAccess, String name, String desc) {
1268: try {
1269: boolean isVolatile = isVolatile(fieldAccess, name);
1270: Label l1 = new Label();
1271: Label l2 = new Label();
1272: Label l4 = new Label();
1273:
1274: // generates setter method
1275: String sDesc = "(" + desc + ")V";
1276: MethodVisitor scv = cv.visitMethod(methodAccess,
1277: ByteCodeUtil.fieldSetterMethod(name), sDesc, null,
1278: null);
1279: getManaged(scv);
1280: scv.visitInsn(DUP);
1281: scv.visitVarInsn(ASTORE, 2);
1282: Label l0 = new Label();
1283: scv.visitJumpInsn(IFNULL, l0);
1284:
1285: if (isVolatile) {
1286: generateCodeForVolatileTransactionBegin(l1, l2, l0, l4,
1287: spec.getClassNameDots() + "." + name,
1288: LockLevel.WRITE, scv);
1289: }
1290:
1291: scv.visitVarInsn(ALOAD, 2);
1292: scv.visitLdcInsn(spec.getClassNameDots());
1293: scv.visitLdcInsn(spec.getClassNameDots() + "." + name);
1294: scv.visitVarInsn(ALOAD, 1);
1295: scv.visitInsn(ICONST_M1);
1296: scv
1297: .visitMethodInsn(INVOKEINTERFACE,
1298: "com/tc/object/TCObject",
1299: "objectFieldChanged",
1300: "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/Object;I)V");
1301:
1302: if (isVolatile) {
1303: generateCodeForVolativeTransactionCommit(l1, l2, scv,
1304: 3, 4, spec.getClassNameDots() + "." + name);
1305: }
1306:
1307: scv.visitLabel(l0);
1308: scv.visitVarInsn(ALOAD, 0);
1309: scv.visitVarInsn(ALOAD, 1);
1310: scv.visitFieldInsn(PUTFIELD, spec.getClassNameSlashes(),
1311: name, desc);
1312: scv.visitInsn(RETURN);
1313: scv.visitMaxs(0, 0);
1314: } catch (RuntimeException e) {
1315: handleInstrumentationException(e);
1316: } catch (Error e) {
1317: handleInstrumentationException(e);
1318: throw e;
1319: }
1320: }
1321:
1322: private void createLiteralSetter(int methodAccess, int fieldAccess,
1323: String name, String desc) {
1324: try {
1325: // generates setter method
1326: boolean isVolatile = isVolatile(fieldAccess, name);
1327:
1328: Label l1 = new Label();
1329: Label l2 = new Label();
1330: Label l4 = new Label();
1331:
1332: String sDesc = "(" + desc + ")V";
1333: Type t = Type.getType(desc);
1334:
1335: MethodVisitor mv = cv.visitMethod(methodAccess,
1336: ByteCodeUtil.fieldSetterMethod(name), sDesc, null,
1337: null);
1338: getManaged(mv);
1339: mv.visitInsn(DUP);
1340: mv.visitVarInsn(ASTORE, 1 + t.getSize());
1341: Label l0 = new Label();
1342: mv.visitJumpInsn(IFNULL, l0);
1343:
1344: if (isVolatile) {
1345: generateCodeForVolatileTransactionBegin(l1, l2, l0, l4,
1346: spec.getClassNameDots() + "." + name,
1347: LockLevel.WRITE, mv);
1348: }
1349:
1350: mv.visitVarInsn(ALOAD, 1 + t.getSize());
1351: mv.visitLdcInsn(spec.getClassNameDots());
1352: mv.visitLdcInsn(spec.getClassNameDots() + "." + name);
1353: mv.visitVarInsn(t.getOpcode(ILOAD), 1);
1354: mv.visitInsn(ICONST_M1);
1355: String method = ByteCodeUtil.codeToName(desc)
1356: + "FieldChanged";
1357: mv.visitMethodInsn(INVOKEINTERFACE,
1358: "com/tc/object/TCObject", method,
1359: "(Ljava/lang/String;Ljava/lang/String;" + desc
1360: + "I)V");
1361:
1362: if (isVolatile) {
1363: generateCodeForVolativeTransactionCommit(l1, l2, mv,
1364: 2 + t.getSize(), 3 + t.getSize(), spec
1365: .getClassNameDots()
1366: + "." + name);
1367: }
1368:
1369: mv.visitLabel(l0);
1370: mv.visitVarInsn(ALOAD, 0);
1371: mv.visitVarInsn(t.getOpcode(ILOAD), 1);
1372: mv.visitFieldInsn(PUTFIELD, spec.getClassNameSlashes(),
1373: name, desc);
1374: mv.visitInsn(RETURN);
1375: mv.visitMaxs(0, 0);
1376: } catch (RuntimeException e) {
1377: handleInstrumentationException(e);
1378: } catch (Error e) {
1379: handleInstrumentationException(e);
1380: throw e;
1381: }
1382: }
1383:
1384: private void callTCMonitorExit(int callingMethodModifier,
1385: MethodVisitor c) {
1386: Assert.eval("Can't call tc monitorenter from a static method.",
1387: !Modifier.isStatic(callingMethodModifier));
1388: ByteCodeUtil.pushThis(c);
1389: spec.getManagerHelper().callManagerMethod("monitorExit", c);
1390: }
1391:
1392: private void callTCMonitorEnter(int callingMethodModifier,
1393: LockDefinition def, MethodVisitor c) {
1394: Assert.eval("Can't call tc monitorexit from a static method.",
1395: !Modifier.isStatic(callingMethodModifier));
1396: ByteCodeUtil.pushThis(c);
1397: c.visitLdcInsn(new Integer(def.getLockLevelAsInt()));
1398: spec.getManagerHelper().callManagerMethod("monitorEnter", c);
1399: }
1400:
1401: private void addPrimitiveTypeZeroCompare(MethodVisitor mv,
1402: Type type, Label notZeroLabel) {
1403: switch (type.getSort()) {
1404: case Type.LONG:
1405: mv.visitInsn(LCONST_0);
1406: mv.visitInsn(LCMP);
1407: mv.visitJumpInsn(IFNE, notZeroLabel);
1408: break;
1409: case Type.DOUBLE:
1410: mv.visitInsn(DCONST_0);
1411: mv.visitInsn(DCMPL);
1412: mv.visitJumpInsn(IFNE, notZeroLabel);
1413: break;
1414: case Type.FLOAT:
1415: mv.visitInsn(FCONST_0);
1416: mv.visitInsn(FCMPL);
1417: mv.visitJumpInsn(IFNE, notZeroLabel);
1418: break;
1419: default:
1420: mv.visitJumpInsn(IFNE, notZeroLabel);
1421: }
1422: }
1423: }
|