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

Java tutorial

Introduction

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

Source

/**********************************************************************
 * This file is part of "Object Teams Dynamic Runtime Environment"
 * 
 * Copyright 2009, 2014 Oliver Frank and others.
 * 
 * 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:
 *      Oliver Frank - Initial API and implementation
 *      Stephan Herrmann - Initial API and implementation
 **********************************************************************/
package org.eclipse.objectteams.otredyn.bytecode.asm;

import org.eclipse.objectteams.otredyn.bytecode.Field;
import org.eclipse.objectteams.otredyn.bytecode.Method;
import org.eclipse.objectteams.otredyn.transformer.names.ConstantMembers;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
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.MethodNode;
import org.objectweb.asm.tree.TypeInsnNode;

/**
 * Creates and adds the instructions,
 * that are needed to access a not visible field from the team
 * in the method access or accessStatic as follows:<br/> <br/>
 * case (memberId) { // generated by CreateSwitchForAccessAdapter <br/>
 *     if (opKind == 0) { <br/>
 *         return field; <br/>
 *     } else { <br/>
 *         field = args[0]; <br/>
 *     } <br/>
 *     break; <br/>
 * }
 * 
 * @author Oliver Frank
 */
public class CreateFieldAccessAdapter extends AbstractTransformableClassNode {

    private Field field;
    private int accessId;
    private Method access;
    private int firstArgIndex;

    public CreateFieldAccessAdapter(Field field, int accessId) {
        this.field = field;
        this.accessId = accessId;
        if (field.isStatic()) {
            access = ConstantMembers.accessStatic;
            firstArgIndex = 0;
        } else {
            access = ConstantMembers.access;
            firstArgIndex = 1;
        }
    }

    @Override
    public boolean transform() {

        InsnList instructions = new InsnList();
        // put accessId on the stack
        instructions.add(new IntInsnNode(Opcodes.ILOAD, firstArgIndex + 1));
        // read or write access
        LabelNode writeAccess = new LabelNode();
        instructions.add(new JumpInsnNode(Opcodes.IFNE, writeAccess));
        // read access
        if (field.isStatic()) {
            // get value of field
            instructions.add(new FieldInsnNode(Opcodes.GETSTATIC, name, field.getName(), field.getSignature()));
        } else {
            // put "this" on the stack
            instructions.add(new IntInsnNode(Opcodes.ALOAD, 0));
            // get value of field
            instructions.add(new FieldInsnNode(Opcodes.GETFIELD, name, field.getName(), field.getSignature()));
        }

        //box value as "Object"
        Type type = Type.getType(field.getSignature());
        instructions.add(AsmTypeHelper.getBoxingInstructionForType(type));
        instructions.add(new InsnNode(Opcodes.ARETURN));

        //write access
        instructions.add(writeAccess);
        //put "args" on the stack 
        instructions.add(new IntInsnNode(Opcodes.ALOAD, firstArgIndex + 2));
        //get the first element of "args"
        instructions.add(new InsnNode(Opcodes.ICONST_0));
        instructions.add(new InsnNode(Opcodes.AALOAD));
        //unbox it
        if (type.getSort() != Type.ARRAY && type.getSort() != Type.OBJECT) {
            String objectType = AsmTypeHelper.getObjectType(type);
            instructions.add(new TypeInsnNode(Opcodes.CHECKCAST, objectType));
            instructions.add(AsmTypeHelper.getUnboxingInstructionForType(type, objectType));
        } else {
            instructions.add(new TypeInsnNode(Opcodes.CHECKCAST, type.getInternalName()));
        }

        if (field.isStatic()) {
            //save value in field
            instructions.add(new FieldInsnNode(Opcodes.PUTSTATIC, name, field.getName(), field.getSignature()));
        } else {
            //put "this" on the stack
            instructions.add(new IntInsnNode(Opcodes.ALOAD, 0));
            instructions.add(new InsnNode(Opcodes.SWAP));
            //save value in field
            instructions.add(new FieldInsnNode(Opcodes.PUTFIELD, name, field.getName(), field.getSignature()));
        }

        //dummy return 
        instructions.add(new InsnNode(Opcodes.ACONST_NULL));
        instructions.add(new InsnNode(Opcodes.ARETURN));

        //add the instructions to a new label in the existing switch
        MethodNode method = getMethod(access);
        addNewLabelToSwitch(method.instructions, instructions, accessId);

        return true;
    }

}