blob: 2b240e36f737a897752267deec8996ec519e6925 [file] [log] [blame]
/**********************************************************************
* This file is part of "Object Teams Dynamic Runtime Environment"
*
* Copyright 2009, 2012 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 void 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);
}
}