blob: c73dd5dc63dba7f8de3df5a91fc9bc921360e13e [file] [log] [blame]
/**********************************************************************
* This file is part of "Object Teams Dynamic Runtime Environment"
*
* Copyright 2009, 2014 Oliver Frank and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0 *
* 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.JumpInsnNode;
import org.objectweb.asm.tree.LabelNode;
import org.objectweb.asm.tree.MethodInsnNode;
import org.objectweb.asm.tree.MethodNode;
/**
* Create the code for the dispatch from a base class to the teams
* in the original method. <br/> <br/>
* The code was generated as follows: <br/>
* <code>
* Teams[] teams = TeamManager.getTeams(joinpointId) <br/>
* if (teams == null) { <br/>
* Object args[] = {arg1, ..., argn}; <br/>
* return callOrig(boundMethodId, args); <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 class CreateDispatchCodeInOrgMethodAdapter extends
AbstractCreateDispatchCodeAdapter {
private Method method;
private int joinPointId;
private int boundMethodId;
public CreateDispatchCodeInOrgMethodAdapter(Method method, int joinPointId, int boundMethodId) {
super(true, computeLocals(method.getSignature()));
this.method = method;
this.joinPointId = joinPointId;
this.boundMethodId = boundMethodId;
}
static int computeLocals(String signature) {
Type[] params = Type.getArgumentTypes(signature);
int locals = 0;
for (Type param : params)
locals += param.getSize();
return locals;
}
@Override
public boolean transform() {
MethodNode orgMethod = getMethod(method);
if ((orgMethod.access & Opcodes.ACC_ABSTRACT) != 0) return false;
orgMethod.instructions.clear();
orgMethod.instructions.add(getDispatchCode(orgMethod, joinPointId, boundMethodId));
addLocals(orgMethod);
orgMethod.maxStack = getMaxStack();
orgMethod.maxLocals = getMaxLocals();
return true;
}
@Override
protected InsnList getBoxedArguments(Type[] args) {
return getBoxingInstructions(args, true);
}
@Override
protected InsnList createInstructionsToCheckTeams(MethodNode method) {
InsnList instructions = new InsnList();
instructions.add(new InsnNode(Opcodes.DUP));
LabelNode label = new LabelNode();
//if (teams == null) {
instructions.add(new JumpInsnNode(Opcodes.IFNONNULL, label));
instructions.add(new InsnNode(Opcodes.POP));
//put the boundMethodId on the stack
instructions.add(createLoadIntConstant(boundMethodId));
Type[] args = Type.getArgumentTypes(method.desc);
// box the arguments
instructions.add(getBoxingInstructions(args, (method.access & Opcodes.ACC_STATIC) != 0));
//callOrigStatic(boundMethodId, args);
instructions.add(new MethodInsnNode(Opcodes.INVOKESTATIC, name, ConstantMembers.callOrigStatic.getName(), ConstantMembers.callOrigStatic.getSignature(), false));
Type returnType = Type.getReturnType(method.desc);
instructions
.add(getUnboxingInstructionsForReturnValue(returnType));
instructions.add(label);
return instructions;
}
}