com.enea.jcarder.agent.instrument.SimulateMethodSyncMethodAdapter.java Source code

Java tutorial

Introduction

Here is the source code for com.enea.jcarder.agent.instrument.SimulateMethodSyncMethodAdapter.java

Source

/*
 * 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 net.jcip.annotations.NotThreadSafe;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodAdapter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;

/**
 * This Method Adapter simulates a synchronized declaration on a method by
 * adding a MonitorEnter and MonitorExits.
 */
@NotThreadSafe
class SimulateMethodSyncMethodAdapter extends MethodAdapter {
    private final String mClassName;
    private final boolean mIsStatic;
    private final Label mTryLabel = new Label();
    private final Label mFinallyLabel = new Label();

    SimulateMethodSyncMethodAdapter(final MethodVisitor visitor, final String className, final boolean isStatic) {
        super(visitor);
        mClassName = className;
        mIsStatic = isStatic;
    }

    public void visitCode() {
        super.visitCode();
        /*
         * This MethodAdapter will only be applied to synchronized methods, and
         * constructors are not allowed to be declared synchronized. Therefore
         * we can add instructions at the beginning of the method and do not
         * have to find the place after the initial constructor byte codes:
         *
         *     ALOAD 0 : this
         *     INVOKESPECIAL Object.<init>() : void
         *
         */
        putMonitorObjectReferenceOnStack();
        mv.visitInsn(Opcodes.MONITORENTER);
        mv.visitLabel(mTryLabel);
    }

    /**
     * This method is called just after the last code in the method.
     */
    public void visitMaxs(int arg0, int arg1) {
        /*
         * This finally block is needed in order to exit the monitor even when
         * the method exits by throwing an exception.
         */
        mv.visitLabel(mFinallyLabel);
        putMonitorObjectReferenceOnStack();
        mv.visitInsn(Opcodes.MONITOREXIT);
        mv.visitInsn(Opcodes.ATHROW);
        mv.visitTryCatchBlock(mTryLabel, mFinallyLabel, mFinallyLabel, null);
        super.visitMaxs(arg0, arg1);
    }

    public void visitInsn(int inst) {
        switch (inst) {
        case Opcodes.IRETURN:
        case Opcodes.LRETURN:
        case Opcodes.FRETURN:
        case Opcodes.DRETURN:
        case Opcodes.ARETURN:
        case Opcodes.RETURN:
            putMonitorObjectReferenceOnStack();
            mv.visitInsn(Opcodes.MONITOREXIT);
            break;
        default:
            // Do nothing.
        }
        super.visitInsn(inst);
    }

    private void putMonitorObjectReferenceOnStack() {
        if (mIsStatic) {
            InstrumentationUtilities.pushClassReferenceToStack(mv, mClassName);
        } else {
            mv.visitVarInsn(Opcodes.ALOAD, 0);
        }
    }
}