blob: 6170fdad0d441c9e52cc09f18a029b925e0899b3 [file] [log] [blame]
/**********************************************************************
* This file is part of the "Object Teams Runtime Environment"
*
* Copyright 2002-2009 Berlin Institute of Technology, Germany.
*
* 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.objectteams.org for updates and contact.
*
* Contributors:
* Berlin Institute of Technology - Initial API and implementation
**********************************************************************/
package org.eclipse.objectteams.otre;
import org.apache.bcel.classfile.*;
import org.apache.bcel.generic.*;
import org.apache.bcel.*;
import java.util.*;
import org.eclipse.objectteams.otre.util.*;
/**
* Redefines inherited (and not redefined) base methods in subclasses with a
* call to the super method if they are bound for the subclass only. This is
* done in order to provide a place for the BaseMethodTransformer to weave in
* the callin code.
*
* @version $Id: SubBoundBaseMethodRedefinition.java 23408 2010-02-03 18:07:35Z stephan $
* @author Christine Hundt
* @author Stephan Herrmann
*/
public class SubBoundBaseMethodRedefinition
extends ObjectTeamsTransformation {
public SubBoundBaseMethodRedefinition(Object loader) { super(loader); }
/**
* Main entry for this transformer.
*/
public void doTransformInterface(ClassEnhancer ce, ClassGen cg) {
String class_name = cg.getClassName();
ConstantPoolGen cpg = cg.getConstantPool();
factory = new InstructionFactory(cg);
checkReadClassAttributes(ce, cg, class_name, cpg);
List<MethodBinding> mbsForClass = CallinBindingManager
.getMethodBindingsForBaseClass(class_name);
if (mbsForClass.isEmpty()) {
return; // no bindings for this base class
}
List<MethodBinding> inheritedBoundMethods = getInheritedBoundMethods(mbsForClass, cg);
addSubBoundMethodRedefinitions(inheritedBoundMethods, ce, cg);
}
/**
* Adds redefinitions with calls to the super method to all methods
* contained in the 'inheritedBoundMethods' list.
*
* @param inheritedBoundMethods
* The list of method bindings for inherited methods.
* @param ce
* ClassEnhancer with the extension set of this class.
* @param cg
* The ClassGen object for the transformed class.
*/
private void addSubBoundMethodRedefinitions(List<MethodBinding> inheritedBoundMethods,
ClassEnhancer ce, ClassGen cg) {
List<String> alreadyAddedRedefinitions = new LinkedList<String>();
Iterator<MethodBinding> it = inheritedBoundMethods.iterator();
while (it.hasNext()) {
MethodBinding mb = it.next();
String baseMethodKey = mb.getBaseMethodName() + "."
+ mb.getBaseMethodSignature();
if (alreadyAddedRedefinitions.contains(baseMethodKey)) {
continue;
}
Method m = genMethodRedefinition(mb, cg);
ce.addMethod(m, cg);
if(logging) printLogMessage("Added " + baseMethodKey + " to " + cg.getClassName());
alreadyAddedRedefinitions.add(baseMethodKey);
}
}
/**
* Generates a (redefining) method, which just calls its super version.
*
* @param mb
* A method binding containing the method to be redefined.
* @param cg
* The ClassGen object for the transformed class.
* @return The generated method.
*/
private Method genMethodRedefinition(MethodBinding mb, ClassGen cg) {
boolean staticMethod = mb.hasStaticBaseMethod();
short invocationKind = staticMethod ? Constants.INVOKESTATIC : Constants.INVOKESPECIAL;
String methodName = mb.getBaseMethodName();
String methodSignature = mb.getBaseMethodSignature();
String className = mb.getBaseClassName();
Type returnType = Type.getReturnType(methodSignature);
Type[] argTypes = Type.getArgumentTypes(methodSignature);
InstructionList il = new InstructionList();
int accFlags = Constants.ACC_PUBLIC;
if (staticMethod) {
accFlags = accFlags | Constants.ACC_STATIC;
}
MethodGen redefinition = new MethodGen(accFlags, returnType, argTypes,
null, methodName, className, il,
cg.getConstantPool());
if(!staticMethod){
il.append(InstructionFactory.createThis());
}
// load all arguments:
int index = 1;
for (int i = 0; i < argTypes.length; i++) {
il.append(InstructionFactory.createLoad(argTypes[i], index));
index += argTypes[i].getSize();
}
il.append(factory.createInvoke(cg.getSuperclassName(), methodName,
returnType, argTypes, invocationKind));
il.append(InstructionFactory.createReturn(returnType));
redefinition.removeNOPs();
il.setPositions();
redefinition.setMaxStack();
redefinition.setMaxLocals();
return redefinition.getMethod();
}
/**
* Selects all method bindings from the 'mbsForClass' list which methods are
* inherited only (not defined in the class itself).
*
* @param mbsForClass
* The method bindings of the transformed class.
* @param cg
* The ClassGen object for the transformed class.
* @return A sublist of 'mbsForClass' containing all bindings for methods
* which are inherited only.
*
*/
private static List<MethodBinding> getInheritedBoundMethods(List<MethodBinding> mbsForClass, ClassGen cg) {
List<MethodBinding> inheritedBoundMethod = new LinkedList<MethodBinding>();
Iterator<MethodBinding> it = mbsForClass.iterator();
while (it.hasNext()) {
MethodBinding mb = it.next();
if ((cg.containsMethod(mb.getBaseMethodName(), mb
.getBaseMethodSignature())) == null)
inheritedBoundMethod.add(mb);
}
return inheritedBoundMethod;
}
}