/* * JCarder -- cards Java programs to keep threads disentangled * * Copyright (C) 2006-2007 Enea AB * Copyright (C) 2007 Ulrik Svensson * Copyright (C) 2007 Joel Rosdahl * * This program is made available under the GNU GPL version 2, with a special * exception for linking with JUnit. See the accompanying file LICENSE.txt for * details. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. */ package com.enea.jcarder.agent.instrument; import static org.objectweb.asm.Opcodes.ACC_NATIVE; import static org.objectweb.asm.Opcodes.ACC_STATIC; import static org.objectweb.asm.Opcodes.ACC_SYNCHRONIZED; import net.jcip.annotations.NotThreadSafe; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.MethodVisitor; import com.enea.jcarder.util.logging.Logger; /** * Each instance of this class is responsible for instrumenting a class. It uses * the MonitorMethodAdapter for instrumenting each method in the class. */ @NotThreadSafe class ClassAdapter extends org.objectweb.asm.ClassAdapter { private final String mClassName; private final Logger mLogger; ClassAdapter(Logger logger, ClassVisitor visitor, String className) { super(visitor); mLogger = logger; mClassName = className; mLogger.fine("Instrumenting class " + mClassName); } public void visit(int arg0, int arg1, String arg2, String arg3, String arg4, String[] arg5) { super.visit(arg0, arg1, arg2, arg3, arg4, arg5); super.visitAttribute(new InstrumentedAttribute("DeadLock")); } public MethodVisitor visitMethod(final int arg, final String methodName, final String descriptor, final String signature, final String[] exceptions) { final boolean isSynchronized = (arg & ACC_SYNCHRONIZED) != 0; final boolean isNative = (arg & ACC_NATIVE) != 0; final boolean isStatic = (arg & ACC_STATIC) != 0; final int manipulatedArg = arg & ~ACC_SYNCHRONIZED; if (isNative) { mLogger.finer("Can't instrument native method " + mClassName + "." + methodName); return super.visitMethod(arg, methodName, descriptor, signature, exceptions); } else { final MethodVisitor mv = super.visitMethod(manipulatedArg, methodName, descriptor, signature, exceptions); final MonitorEnterMethodAdapter dlma = new MonitorEnterMethodAdapter(mv, mClassName, methodName); final StackAnalyzeMethodVisitor stackAnalyzer = new StackAnalyzeMethodVisitor(mLogger, dlma, isStatic); dlma.setStackAnalyzer(stackAnalyzer); if (isSynchronized) { /* * We want to be able to get an event before a synchronized * method is entered and BEFORE it has taken the lock in order * to notice deadlocks before they actually happen. Therefore we * replace the synchronized declaration of the method with * explicit monitorEnter and monitorExit bytecodes in the * beginning of the method and at each possible exit (by normal * return and by exception) of the method. */ return new SimulateMethodSyncMethodAdapter(stackAnalyzer, mClassName, isStatic); } else { return stackAnalyzer; } } } }