blob: ebbf234aab22f27543857f061bf01deae230c528 [file] [log] [blame]
/**********************************************************************
* This file is part of the "Object Teams Runtime Environment"
*
* Copyright 2002-2009 Berlin Institute of Technology, Germany.
*
* 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
* $Id: BaseTagInsertion.java 23408 2010-02-03 18:07:35Z stephan $
*
* 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 de.fub.bytecode.generic.*;
import de.fub.bytecode.*;
import java.util.*;
import org.eclipse.objectteams.otre.util.*;
/**
* This transformer inserts tag fields for all (topmost) bound base classes.
* Tag fields look like this:
* <pre>
* public short <i>TeamName</i>_OT$Tag;
* </pre>
* where <i>TeamName</i> is any team which has a callin binding for this base class.
* It also inserts initialization of this tag into every constructor.
*
* @version $Id: BaseTagInsertion.java 23408 2010-02-03 18:07:35Z stephan $
* @author Christine Hundt
* @author Stephan Herrmann
*/
public class BaseTagInsertion
{
private static boolean logging = false;
final static String tagSuffix = "_OT$Tag";
static String getTagFieldName (String teamName) {
return teamName.replace('.', '$') + tagSuffix;
}
static {
if (System.getProperty("ot.log") != null)
logging = true;
}
public static class SharedState extends ObjectTeamsTransformation.SharedState {
// Record base tags of interfaces here (String->HashMap).
// Need to be considered in all implementing classes.
// baseName -> HashMap (teamName -> tag (Integer)):
private HashMap<String, HashMap<String, Integer>> baseTagsOfInterfaces = new HashMap<String, HashMap<String, Integer>>();
}
SharedState state;
public BaseTagInsertion(SharedState state) {
this.state = state;
}
/**
* @param ce
* @param cg
*/
public void doTransformInterface(ClassEnhancer ce, ClassGen cg) {
String class_name = cg.getClassName();
ConstantPoolGen cpg = cg.getConstantPool();
/*
if (interfaceTransformedClasses.contains(class_name))
continue; // already transformed!
*/
HashMap<String, Integer> baseTags = getAllBaseTags(cg);
if (baseTags == null) return; // not a bound base
if (cg.isInterface())
state.baseTagsOfInterfaces.put(class_name, baseTags);
state.interfaceTransformedClasses.add(class_name);
if (logging)
printLogMessage("Found bound base: " + class_name);
Iterator<String> teams = baseTags.keySet().iterator();
while (teams.hasNext()) {
String teamName = teams.next();
String fieldName = getTagFieldName(teamName);//team + tagSuffix;
if (cg.containsMethod("get"+fieldName, "()S") == null)
{
if(logging)
printLogMessage("create base tag access get" + fieldName);
Integer tag = baseTags.get(teamName);
MethodGen mg = genBaseTagGetter(cpg, class_name, fieldName, tag.intValue(), cg.isInterface());
ce.addMethod(mg.getMethod(), cg);
}
}
// addedBaseTags.addAll(baseTags);
}
/**
* Collect base tags from this class and its super interfaces.
* @param cg
* @return
*/
private HashMap<String, Integer> getAllBaseTags(ClassGen cg) {
// accumulate here base tags from bound super interfaces and this class:
HashMap<String, Integer> baseTags = null;
// TODO (SH): consider all transformed super interfaces.
String superIfc = getTransformedSuperIfc(cg);
if (superIfc != null)
baseTags = state.baseTagsOfInterfaces.get(superIfc);
String class_name = cg.getClassName();
HashMap<String, Integer> classBaseTags = CallinBindingManager.getBaseTags(class_name);
if (CallinBindingManager.isRole(class_name)) {
// search for base tags inherited from the implicit super (role) class:
HashMap<String, Integer> inheritedBaseTags = CallinBindingManager.getInheritedBaseTags(class_name);
classBaseTags.putAll(inheritedBaseTags);
// search for base tags of the implementing role class:
String implementingRoleName = ObjectTeamsTransformation.genImplementingRoleName(class_name);
HashMap<String, Integer> implementingRolebaseTags = CallinBindingManager.getBaseTags(implementingRoleName);
classBaseTags.putAll(implementingRolebaseTags);
// TODO: check, if the we also need the implicitly inherited tags of the implementing role class!
}
if (baseTags == null)
baseTags = classBaseTags;
else
baseTags.putAll(classBaseTags);
return baseTags;
}
/**
* Search the interfaces implemented by the class `cg' for an interface
* that is a bound base.
* TODO (SH): should return all such interfaces!
* @param cg
* @return
*/
private String getTransformedSuperIfc(ClassGen cg) {
String[] ifcs = cg.getInterfaceNames();
for (int i=0; i<ifcs.length; i++){
if (state.interfaceTransformedClasses.contains(ifcs[i]))
return ifcs[i];
}
return null;
}
/**
* Generate a getter method for the base tag field.
* @param cpg
* @param class_name this (base-) class shall carry the new method
* @param fieldName name of the tag field.
* @param abstractFlg should the method be generated as abstract (ie., without a body)?
* @return
*/
static MethodGen genBaseTagGetter(
ConstantPoolGen cpg, String class_name,
String fieldName, int tagValue, boolean abstractFlg)
{
int accessFlags = Constants.ACC_PUBLIC;
if (abstractFlg)
accessFlags |= Constants.ACC_ABSTRACT;
InstructionList il = new InstructionList();
MethodGen mg = new MethodGen(
accessFlags,
Type.SHORT, Type.NO_ARGS, new String[]{},
"get"+fieldName, class_name,
il, cpg);
if (!abstractFlg) {
// gen: "return <constant tagValue>"
il.append(new PUSH(cpg, tagValue));
il.append(InstructionFactory.createReturn(Type.INT));
}
mg.setMaxStack();
mg.setMaxLocals();
return mg;
}
/**
* Insert tag initializations into each constructor.
*/
public void doTransformCode(ClassGen cg) {
// FIXME(SH): do not declare as CodeTransformer.
}
/**
* @param message
*/
private static void printLogMessage(String message) {
System.out.println(message);
}
}