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.Method; import org.eclipse.objectteams.otredyn.transformer.names.ConstantMembers; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.objectweb.asm.tree.InsnList; import org.objectweb.asm.tree.InsnNode; import org.objectweb.asm.tree.IntInsnNode; import org.objectweb.asm.tree.MethodInsnNode; 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 method from the team * in the method access or accessStatic as follows:<br/> <br/> * case (memberId) { // generated by CreateSwitchForAccessAdapter <br/> * return orgMethod(args[0], ..., args[args.length]); <br/> * } * * @author Oliver Frank */ public class CreateMethodAccessAdapter extends AbstractTransformableClassNode { private Method method; private int accessId; private Method access; private int firstArgIndex; private boolean isConstructor; public CreateMethodAccessAdapter(Method method, int accessId) { this.method = method; this.accessId = accessId; isConstructor = method.getName().equals("<init>"); if (method.isStatic() || isConstructor) { access = ConstantMembers.accessStatic; firstArgIndex = 0; } else { access = ConstantMembers.access; firstArgIndex = 1; } } @Override public boolean transform() { MethodNode methodNode = getMethod(method); InsnList instructions = new InsnList(); if (isConstructor) { // create empty object for constructor invocation: instructions.add(new TypeInsnNode(Opcodes.NEW, name)); instructions.add(new InsnNode(Opcodes.DUP)); } else if (!method.isStatic()) { //put "this" on the stack for a non-static method instructions.add(new IntInsnNode(Opcodes.ALOAD, 0)); } //Unbox arguments Type[] args = Type.getArgumentTypes(methodNode.desc); if (args.length > 0) { for (int i = 0; i < args.length; i++) { instructions.add(new IntInsnNode(Opcodes.ALOAD, firstArgIndex + 2)); instructions.add(createLoadIntConstant(i)); instructions.add(new InsnNode(Opcodes.AALOAD)); Type arg = args[i]; if (arg.getSort() != Type.ARRAY && arg.getSort() != Type.OBJECT) { String objectType = AsmTypeHelper.getObjectType(arg); instructions.add(new TypeInsnNode(Opcodes.CHECKCAST, objectType)); instructions.add(AsmTypeHelper.getUnboxingInstructionForType(arg, objectType)); } else { instructions.add(new TypeInsnNode(Opcodes.CHECKCAST, arg.getInternalName())); } } } //call original method int opcode = Opcodes.INVOKEVIRTUAL; if (method.isStatic()) { opcode = Opcodes.INVOKESTATIC; } else if (isConstructor) { opcode = Opcodes.INVOKESPECIAL; } instructions.add(new MethodInsnNode(opcode, name, method.getName(), method.getSignature())); //box return value Type returnType = Type.getReturnType(methodNode.desc); if (returnType.getSort() != Type.OBJECT && returnType.getSort() != Type.ARRAY && returnType.getSort() != Type.VOID) { instructions.add(AsmTypeHelper.getBoxingInstructionForType(returnType)); instructions.add(new InsnNode(Opcodes.ARETURN)); } else if (returnType.getSort() == Type.VOID && !isConstructor) { instructions.add(new InsnNode(Opcodes.ACONST_NULL)); instructions.add(new InsnNode(Opcodes.ARETURN)); } else { instructions.add(new InsnNode(Opcodes.ARETURN)); } //add the instructions to a new label in the existing switch MethodNode access = getMethod(this.access); addNewLabelToSwitch(access.instructions, instructions, accessId); return true; } }