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