/********************************************************************** | |
* 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; | |
} | |
} |