Java tutorial
/********************************************************************** * 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.AbstractBoundClass; import org.eclipse.objectteams.otredyn.bytecode.Method; import org.eclipse.objectteams.otredyn.transformer.names.ClassNames; import org.eclipse.objectteams.otredyn.transformer.names.ConstantMembers; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.objectweb.asm.tree.InsnNode; import org.objectweb.asm.tree.IntInsnNode; import org.objectweb.asm.tree.LdcInsnNode; import org.objectweb.asm.tree.MethodInsnNode; import org.objectweb.asm.tree.MethodNode; import org.objectweb.asm.tree.TypeInsnNode; /** * Initially prepares the method access or accessStatic as follows: <br/><br/> * <code> * int memberId = TeamManager.getMemberId(accessId, caller);<br/> * switch (memberId) {<br/> * default:<br/> * return super.access(accessId, opKind, args, caller);<br/> * }<br/> * </code> * @author Oliver Frank */ public class CreateSwitchForAccessAdapter extends CreateSwitchAdapter { private String superClassName; private AbstractBoundClass clazz; public CreateSwitchForAccessAdapter(Method method, String superClassName, AbstractBoundClass clazz) { super(method); this.superClassName = superClassName; this.clazz = clazz; } @Override protected void addPreSwitchInstructions(MethodNode method) { // put "accessId" on the stack method.instructions.add(new IntInsnNode(Opcodes.ILOAD, getFirstArgIndex())); // put "caller".getClass() on the stack method.instructions.add(new IntInsnNode(Opcodes.ALOAD, getFirstArgIndex() + 3)); method.instructions.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, "java/lang/Object", "getClass", "()Ljava/lang/Class;", false)); // call "getMemberId(accessId, callerClass) method.instructions.add(new MethodInsnNode(Opcodes.INVOKESTATIC, ClassNames.TEAM_MANAGER_SLASH, ConstantMembers.getMemberId.getName(), ConstantMembers.getMemberId.getSignature(), false)); } @Override protected void addInstructionForDefaultLabel(MethodNode method) { if (superClassName.equals("java/lang/Object")) { method.instructions.add(new TypeInsnNode(Opcodes.NEW, "org/objectteams/NoSuchMethodError")); method.instructions.add(new InsnNode(Opcodes.DUP)); method.instructions.add(new IntInsnNode(Opcodes.ILOAD, getFirstArgIndex())); // accessId method.instructions.add(new LdcInsnNode(clazz.getName())); // current class method.instructions.add(new LdcInsnNode("decapsulating access")); // access reason method.instructions.add(new MethodInsnNode(Opcodes.INVOKESPECIAL, "org/objectteams/NoSuchMethodError", "<init>", "(ILjava/lang/String;Ljava/lang/String;)V", false)); method.instructions.add(new InsnNode(Opcodes.ATHROW)); } else { Type[] args = Type.getArgumentTypes(method.desc); addInstructionsForLoadArguments(method.instructions, args, getMethod().isStatic()); int opcode = Opcodes.INVOKESPECIAL; if (getMethod().isStatic()) { opcode = Opcodes.INVOKESTATIC; } method.instructions.add( new MethodInsnNode(opcode, superClassName, getMethod().getName(), getMethod().getSignature())); method.instructions.add(new InsnNode(Opcodes.ARETURN)); } } @Override protected int getMaxStack() { return 5; } }