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.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.AbstractInsnNode; 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.MethodInsnNode; import org.objectweb.asm.tree.MethodNode; import org.objectweb.asm.tree.TypeInsnNode; /** * Create the code for the dispatch from a base class to the teams. <br/> <br/> * The code was generated as follows: <br/> * <code> * switch (boundMethodId) { // this was generated in CreateSwitchAdapter <br/> * ... <br/> * case (...): // this was generated in concrete implementations <br/> * // of this abstract class <br/> * Teams[] teams = TeamManager.getTeams(joinpointId) <br/><br/> * if (teams == null) { <br/> * break; <br/> * } <br/> * <br/> * Team t = teams[0]; <br/> * int[] callinIds = TeamManager.getCallinIds(joinpointId); <br/> * Object[] args = {arg1, ... , argn}; * return team._OT$callAllBindings(this, teams, 0, callinIds, boundMethodId, args); * } <br/> * </code> * @author Oliver Frank */ public abstract class AbstractCreateDispatchCodeAdapter extends AbstractTransformableClassNode { private boolean isStatic; public AbstractCreateDispatchCodeAdapter(boolean isStatic) { this.isStatic = isStatic; } private Type[] args; protected InsnList getDispatchCode(MethodNode method, int joinPointId, int boundMethodId) { InsnList instructions = new InsnList(); // teams = TeamManager.getTeams(joinpointId) instructions.add(createLoadIntConstant(joinPointId)); instructions.add(new MethodInsnNode(Opcodes.INVOKESTATIC, ClassNames.TEAM_MANAGER_SLASH, ConstantMembers.getTeams.getName(), ConstantMembers.getTeams.getSignature(), false)); instructions.add(createInstructionsToCheackTeams(method)); // get the first team instructions.add(new InsnNode(Opcodes.DUP)); instructions.add(new InsnNode(Opcodes.ICONST_0)); instructions.add(new InsnNode(Opcodes.AALOAD)); instructions.add(new InsnNode(Opcodes.SWAP)); if (isStatic) { instructions.add(new InsnNode(Opcodes.ACONST_NULL)); } else { // put "this" on the stack and cast it to IBoundBase2 instructions.add(new IntInsnNode(Opcodes.ALOAD, 0)); instructions.add(new TypeInsnNode(Opcodes.CHECKCAST, ClassNames.I_BOUND_BASE_SLASH)); } instructions.add(new InsnNode(Opcodes.SWAP)); // start index instructions.add(new InsnNode(Opcodes.ICONST_0)); // TeamManager.getCallinIds(joinpointId) instructions.add(createLoadIntConstant(joinPointId)); instructions.add(new MethodInsnNode(Opcodes.INVOKESTATIC, ClassNames.TEAM_MANAGER_SLASH, ConstantMembers.getCallinIds.getName(), ConstantMembers.getCallinIds.getSignature(), false)); instructions.add(createLoadIntConstant(boundMethodId)); args = Type.getArgumentTypes(method.desc); // box the arguments instructions.add(getBoxedArguments(args)); instructions.add(new MethodInsnNode(Opcodes.INVOKEINTERFACE, ClassNames.ITEAM_SLASH, ConstantMembers.callAllBindingsTeam.getName(), ConstantMembers.callAllBindingsTeam.getSignature(), true)); Type returnType = Type.getReturnType(method.desc); instructions.add(getUnboxingInstructionsForReturnValue(returnType)); return instructions; } protected InsnList createInstructionsToCheackTeams(MethodNode method) { // if (teams == null) { // break; // } InsnList instructions = new InsnList(); instructions.add(new InsnNode(Opcodes.DUP)); LabelNode label = new LabelNode(); instructions.add(new JumpInsnNode(Opcodes.IFNONNULL, label)); instructions.add(new InsnNode(Opcodes.POP)); instructions.add(new JumpInsnNode(Opcodes.GOTO, findBreakLabel(method.instructions))); instructions.add(label); return instructions; } private LabelNode findBreakLabel(InsnList instructions) { for (int i = instructions.size() - 1; i >= 0; i--) { AbstractInsnNode node = instructions.get(i); if (node.getType() == AbstractInsnNode.LABEL) { return (LabelNode) node; } } throw new RuntimeException("Can't find break label to create dispatch code"); } protected abstract InsnList getBoxedArguments(Type[] args); protected int getMaxLocals() { return args.length + 1; } protected int getMaxStack() { return 10; } }