Java tutorial
/********************************************************************** * 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; } }