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

Java tutorial

Introduction

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

Source

/**********************************************************************
 * This file is part of "Object Teams Dynamic Runtime Environment"
 * 
 * Copyright 2009, 2015 Stephan Herrmann.
 * 
 * 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 org.eclipse.objectteams.otredyn.transformer.names.ClassNames;
import org.eclipse.objectteams.otredyn.transformer.names.ConstantMembers;
import org.objectweb.asm.Label;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.tree.FieldInsnNode;
import org.objectweb.asm.tree.InsnList;
import org.objectweb.asm.tree.InsnNode;
import org.objectweb.asm.tree.IntInsnNode;
import org.objectweb.asm.tree.JumpInsnNode;
import org.objectweb.asm.tree.LabelNode;
import org.objectweb.asm.tree.MethodInsnNode;
import org.objectweb.asm.tree.MethodNode;
import org.objectweb.asm.tree.TypeInsnNode;

/**
 * Implements the method <code>void _OT$addOrRemoveRole(Object role, boolean isAdding)</code>
 * from <code>org.objectteams.IBoundBase2</code>
 * 
 * @author stephan
 */
public class CreateAddRemoveRoleMethod extends AbstractTransformableClassNode {

    @Override
    protected boolean transform() {
        // void _OT$addRemoveRole(Object role, boolean isAdding) {
        MethodNode method = getMethod(ConstantMembers.addOrRemoveRole);
        final int ROLE_SLOT = 1, IS_ADDING_SLOT = 2;
        Label start = new Label(), end = new Label();
        method.instructions.clear();
        method.visitLabel(start);

        // set = <initialized _OT$roleSet;>
        final int SET_SLOT = 3;
        method.visitLocalVariable("set", "Ljava/util/Set;", null, start, end, SET_SLOT);
        genGetInitializedRoleSet(method.instructions, SET_SLOT);

        // if (isAdding) {
        method.instructions.add(new IntInsnNode(Opcodes.ILOAD, IS_ADDING_SLOT));
        LabelNode jumpToRemove = new LabelNode();
        method.instructions.add(new JumpInsnNode(Opcodes.IFEQ, jumpToRemove));

        // set.add(role);
        method.instructions.add(new IntInsnNode(Opcodes.ALOAD, SET_SLOT));
        method.instructions.add(new IntInsnNode(Opcodes.ALOAD, ROLE_SLOT));
        method.instructions.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, ClassNames.HASH_SET_SLASH, "add",
                "(Ljava/lang/Object;)Z", false));
        method.instructions.add(new InsnNode(Opcodes.POP));

        LabelNode jumpToEnd = new LabelNode();
        method.instructions.add(new JumpInsnNode(Opcodes.GOTO, jumpToEnd));
        // } else {
        method.instructions.add(jumpToRemove);
        // set.remove(role);
        method.instructions.add(new IntInsnNode(Opcodes.ALOAD, SET_SLOT));
        method.instructions.add(new IntInsnNode(Opcodes.ALOAD, ROLE_SLOT));
        method.instructions.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, ClassNames.HASH_SET_SLASH, "remove",
                "(Ljava/lang/Object;)Z", false));
        method.instructions.add(new InsnNode(Opcodes.POP));

        method.instructions.add(jumpToEnd);
        // }

        method.instructions.add(new InsnNode(Opcodes.RETURN));
        method.visitLabel(end);
        // }
        // maxs are computed, maxStack from flow, maxLocals from localVariable-slots
        return true;
    }

    void genGetInitializedRoleSet(InsnList instructions, int targetLocal) {
        // x = this._OT$roleSet 
        instructions.add(new IntInsnNode(Opcodes.ALOAD, 0));
        instructions.add(new FieldInsnNode(Opcodes.GETFIELD, name, ConstantMembers.OT_ROLE_SET,
                ConstantMembers.HASH_SET_FIELD_TYPE));

        instructions.add(new IntInsnNode(Opcodes.ASTORE, targetLocal));
        instructions.add(new IntInsnNode(Opcodes.ALOAD, targetLocal));

        // if (x == null) {
        LabelNode skipInstantiation = new LabelNode();
        instructions.add(new JumpInsnNode(Opcodes.IFNONNULL, skipInstantiation));

        // this._OT$roleSet = new HashSet();
        instructions.add(new IntInsnNode(Opcodes.ALOAD, 0));
        instructions.add(new TypeInsnNode(Opcodes.NEW, ClassNames.HASH_SET_SLASH));
        instructions.add(new InsnNode(Opcodes.DUP));
        instructions
                .add(new MethodInsnNode(Opcodes.INVOKESPECIAL, ClassNames.HASH_SET_SLASH, "<init>", "()V", false));

        instructions.add(new IntInsnNode(Opcodes.ASTORE, targetLocal));
        instructions.add(new IntInsnNode(Opcodes.ALOAD, targetLocal));
        instructions.add(new FieldInsnNode(Opcodes.PUTFIELD, name, ConstantMembers.OT_ROLE_SET,
                ConstantMembers.HASH_SET_FIELD_TYPE));

        instructions.add(skipInstantiation);
        // }
    }
}