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