org.eclipse.objectteams.otredyn.bytecode.asm.AddImplicitActivationAdapter.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.objectteams.otredyn.bytecode.asm.AddImplicitActivationAdapter.java

Source

/**********************************************************************
 * This file is part of "Object Teams Dynamic Runtime Environment"
 * 
 * Copyright 2011, 2014 GK Software AG.
 * 
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 * 
 * Please visit http://www.eclipse.org/objectteams for updates and contact.
 * 
 * Contributors:
 *      Stephan Herrmann - Initial API and implementation
 **********************************************************************/
package org.eclipse.objectteams.otredyn.bytecode.asm;

import static org.eclipse.objectteams.otredyn.bytecode.asm.AsmBoundClass.ASM_API;

import org.eclipse.objectteams.otredyn.transformer.names.ClassNames;
import org.eclipse.objectteams.otredyn.transformer.names.ConstantMembers;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.commons.AdviceAdapter;

/**
 * This visitor adds calls to _OT$implicitlyActivate and _OT$implicitlyDeactivate
 * into all relevant methods as configured by
 * <ul>
 * <li>system property <code>ot.implicit.team.activation</code>
 * <li>annotation {@link org.objectteams.ImplicitTeamActivation}.
 * </ul>
 */
public class AddImplicitActivationAdapter extends ClassVisitor {

    public static final Object ANNOTATION_IMPLICIT_ACTIVATION = 'L' + ClassNames.IMPLICIT_ACTIVATION + ';';

    protected static final String TARGET_CLASS_NAME = ClassNames.ITEAM_SLASH;
    protected static final String IMPLICIT_ACTIVATE_METHOD_NAME = "_OT$implicitlyActivate";
    protected static final String IMPLICIT_DEACTIVATE_METHOD_NAME = "_OT$implicitlyDeactivate";
    protected static final String METHOD_DESC = "()V";

    // -------------------------------------------------------
    // ---------- Modes for implicit team activation --------
    // -------------------------------------------------------
    private enum ImplicitActivationMode {
        NEVER, ANNOTATED, ALWAYS
    }

    private static ImplicitActivationMode implicitActivationMode = ImplicitActivationMode.ANNOTATED;
    static {
        String prop = System.getProperty("ot.implicit.team.activation");
        for (ImplicitActivationMode mode : ImplicitActivationMode.values()) {
            if (mode.name().equals(prop)) {
                implicitActivationMode = mode;
                break;
            }
        }
    }

    private AsmBoundClass clazz;

    public AddImplicitActivationAdapter(ClassVisitor cv, AsmBoundClass clazz) {
        super(ASM_API, cv);
        this.clazz = clazz;
    }

    @Override
    public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
        if (isCandidateForImplicitActivation(name, desc, access)) {
            final MethodVisitor methodVisitor = cv.visitMethod(access, name, desc, null, null);
            final String enclTeamDesc = clazz.isRole()
                    ? 'L' + clazz.getEnclosingClass().getName().replace('.', '/') + ';'
                    : null;
            final int nesting = clazz.nestingDepth() - 1;
            return new AdviceAdapter(this.api, methodVisitor, access, name, desc) {
                @Override
                protected void onMethodEnter() {
                    if (clazz.isTeam()) {
                        methodVisitor.visitIntInsn(Opcodes.ALOAD, 0);
                        methodVisitor.visitMethodInsn(INVOKEINTERFACE, TARGET_CLASS_NAME,
                                IMPLICIT_ACTIVATE_METHOD_NAME, METHOD_DESC, true);
                    }
                    if (clazz.isRole()) {
                        // TODO(SH): respect nesting depth (this$n)
                        methodVisitor.visitIntInsn(Opcodes.ALOAD, 0);
                        methodVisitor.visitFieldInsn(Opcodes.GETFIELD, clazz.getName().replace('.', '/'),
                                "this$" + nesting, enclTeamDesc);
                        methodVisitor.visitMethodInsn(INVOKEINTERFACE, TARGET_CLASS_NAME,
                                IMPLICIT_ACTIVATE_METHOD_NAME, METHOD_DESC, true);
                    }
                }

                @Override
                protected void onMethodExit(int opcode) {
                    if (clazz.isTeam()) {
                        methodVisitor.visitIntInsn(Opcodes.ALOAD, 0);
                        methodVisitor.visitMethodInsn(INVOKEINTERFACE, TARGET_CLASS_NAME,
                                IMPLICIT_DEACTIVATE_METHOD_NAME, METHOD_DESC, true);
                    }
                    if (clazz.isRole()) {
                        // TODO(SH): respect nesting depth (this$n)
                        methodVisitor.visitIntInsn(Opcodes.ALOAD, 0);
                        methodVisitor.visitFieldInsn(Opcodes.GETFIELD, clazz.getName().replace('.', '/'),
                                "this$" + nesting, enclTeamDesc);
                        methodVisitor.visitMethodInsn(INVOKEINTERFACE, TARGET_CLASS_NAME,
                                IMPLICIT_DEACTIVATE_METHOD_NAME, METHOD_DESC, true);
                    }
                }

                @Override
                public void endMethod() {
                    if (clazz.isTeam() || clazz.isRole())
                        methodVisitor.visitMaxs(0, 0);
                }
            };
        }
        return null;
    }

    private boolean isCandidateForImplicitActivation(String methName, String methDesc, int accessFlags) {
        if (clazz.isTeam()) {
            if ((accessFlags & Opcodes.ACC_PRIVATE) != 0)
                return false;
        } else if (clazz.isRole()) {
            if (clazz.isProtected() || (accessFlags & Opcodes.ACC_PUBLIC) == 0)
                return false;
        } else {
            return false;
        }
        switch (implicitActivationMode) {
        case NEVER:
            return false;
        case ANNOTATED:
            if (!clazz.hasMethodImplicitActivation(methName + methDesc))
                return false;
            //$FALL-THROUGH$
        case ALWAYS:
            // TODO: respect RoleClassMethodModifiers attribute
            return canImplicitlyActivate(accessFlags, methName, methDesc);
        }
        return false;
    }

    private static boolean canImplicitlyActivate(int methFlags, String methName, String methDesc) {
        boolean isCandidate = ((methFlags & (Opcodes.ACC_ABSTRACT | Opcodes.ACC_STATIC)) == 0)
                && (!methName.startsWith("_OT$")) && (!methName.equals("<init>"))
                && (!(methName.equals("activate") && methDesc.equals("()V")))
                && (!(methName.equals("deactivate") && methDesc.equals("()V")))
                && (!ConstantMembers.isReflectiveOTMethod(methName, methDesc));
        return isCandidate;
    }

}