| /********************************************************************** |
| * This file is part of "Object Teams Dynamic Runtime Environment" |
| * |
| * Copyright 2009, 2014 Oliver Frank and others. |
| * |
| * This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License 2.0 |
| * which accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 * |
| * 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.JumpInsnNode; |
| import org.objectweb.asm.tree.LabelNode; |
| import org.objectweb.asm.tree.MethodNode; |
| import org.objectweb.asm.tree.TypeInsnNode; |
| import org.objectweb.asm.tree.VarInsnNode; |
| |
| /** |
| * 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 VarInsnNode(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 VarInsnNode(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 "this" on the stack |
| if (!field.isStatic()) |
| instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); |
| |
| //put "args" on the stack |
| instructions.add(new VarInsnNode(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.getBoxingType(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 { |
| //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; |
| } |
| |
| } |