initial contribution "Object Teams Runtime Environment" as approved in CQ 3786
diff --git a/othersrc/OTRE/.classpath b/othersrc/OTRE/.classpath
new file mode 100644
index 0000000..b98640e
--- /dev/null
+++ b/othersrc/OTRE/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.5"/>
+ <classpathentry combineaccessrules="false" kind="src" path="/bcel4-4-1"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/othersrc/OTRE/.project b/othersrc/OTRE/.project
new file mode 100644
index 0000000..9f6b831
--- /dev/null
+++ b/othersrc/OTRE/.project
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>OTRE</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
diff --git a/othersrc/OTRE/.settings/org.eclipse.jdt.core.prefs b/othersrc/OTRE/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..1aa7124
--- /dev/null
+++ b/othersrc/OTRE/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,70 @@
+#Thu Sep 18 21:57:35 CEST 2008
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.5
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.autoboxing=ignore
+org.eclipse.jdt.core.compiler.problem.deprecation=warning
+org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled
+org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled
+org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
+org.eclipse.jdt.core.compiler.problem.emptyStatement=ignore
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.problem.fallthroughCase=ignore
+org.eclipse.jdt.core.compiler.problem.fatalOptionalError=enabled
+org.eclipse.jdt.core.compiler.problem.fieldHiding=ignore
+org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning
+org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning
+org.eclipse.jdt.core.compiler.problem.forbiddenReference=error
+org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning
+org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning
+org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=ignore
+org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=ignore
+org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore
+org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning
+org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=ignore
+org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=ignore
+org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning
+org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning
+org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning
+org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore
+org.eclipse.jdt.core.compiler.problem.nullReference=warning
+org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning
+org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore
+org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=ignore
+org.eclipse.jdt.core.compiler.problem.potentialNullReference=ignore
+org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning
+org.eclipse.jdt.core.compiler.problem.redundantNullCheck=ignore
+org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=ignore
+org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled
+org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning
+org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled
+org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore
+org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning
+org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning
+org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore
+org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning
+org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore
+org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=ignore
+org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=ignore
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled
+org.eclipse.jdt.core.compiler.problem.unusedImport=warning
+org.eclipse.jdt.core.compiler.problem.unusedLabel=warning
+org.eclipse.jdt.core.compiler.problem.unusedLocal=warning
+org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore
+org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled
+org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled
+org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled
+org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning
+org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
+org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
+org.eclipse.jdt.core.compiler.source=1.5
diff --git a/othersrc/OTRE/MANIFEST.MF b/othersrc/OTRE/MANIFEST.MF
new file mode 100644
index 0000000..c759b23
--- /dev/null
+++ b/othersrc/OTRE/MANIFEST.MF
@@ -0,0 +1,5 @@
+Manifest-Version: 1.0
+Premain-Class: org.eclipse.objectteams.otre.jplis.otreAgent
+Can-Redefine-Classes: true
+Built-By: resix
+
diff --git a/othersrc/OTRE/about.html b/othersrc/OTRE/about.html
new file mode 100644
index 0000000..47048bd
--- /dev/null
+++ b/othersrc/OTRE/about.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"/>
+<title>About</title>
+</head>
+<body lang="EN-US">
+<h2>About This Content</h2>
+
+<p>Feb 3, 2010</p>
+<h3>License</h3>
+
+<p>The Eclipse Foundation makes available all content in this plug-in ("Content"). Unless otherwise
+indicated below, the Content is provided to you under the terms and conditions of the
+Eclipse Public License Version 1.0 ("EPL"). A copy of the EPL is available
+at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>.
+For purposes of the EPL, "Program" will mean the Content.</p>
+
+<p>If you did not receive this Content directly from the Eclipse Foundation, the Content is
+being redistributed by another party ("Redistributor") and different terms and conditions may
+apply to your use of any object code in the Content. Check the Redistributor's license that was
+provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise
+indicated below, the terms and conditions of the EPL still apply to any source code in the Content
+and such source code may be obtained at <a href="http://www.eclipse.org">http://www.eclipse.org</a>.</p>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/othersrc/OTRE/otre-src-jar.jardesc b/othersrc/OTRE/otre-src-jar.jardesc
new file mode 100644
index 0000000..7556776
--- /dev/null
+++ b/othersrc/OTRE/otre-src-jar.jardesc
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<jardesc>
+ <jar path="org.eclipse.objectteams.runtime/lib/otre.jar"/>
+ <options buildIfNeeded="true" compress="true" descriptionLocation="/OTRE/otre-src-jar.jardesc" exportErrors="false" exportWarnings="true" includeDirectoryEntries="false" overwrite="true" saveDescription="true" storeRefactorings="false" useSourceFolders="false"/>
+ <storedRefactorings deprecationInfo="true" structuralOnly="false"/>
+ <selectedProjects/>
+ <manifest generateManifest="true" manifestLocation="" manifestVersion="1.0" reuseManifest="false" saveManifest="false" usesManifest="true">
+ <sealing sealJar="false">
+ <packagesToSeal/>
+ <packagesToUnSeal/>
+ </sealing>
+ </manifest>
+ <selectedElements exportClassFiles="false" exportJavaFiles="true" exportOutputFolder="true">
+ <javaElement handleIdentifier="=OTRE/src"/>
+ </selectedElements>
+</jardesc>
diff --git a/othersrc/OTRE/otre_agent.jardesc b/othersrc/OTRE/otre_agent.jardesc
new file mode 100644
index 0000000..cf1515f
--- /dev/null
+++ b/othersrc/OTRE/otre_agent.jardesc
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<jardesc>
+ <jar path="org.eclipse.objectteams.otdt/lib/otre_agent.jar"/>
+ <options overwrite="false" compress="true" exportErrors="false" exportWarnings="true" saveDescription="true" descriptionLocation="/OTRE/otre_agent.jardesc" useSourceFolders="false" buildIfNeeded="true"/>
+ <manifest manifestVersion="1.0" usesManifest="true" reuseManifest="false" saveManifest="false" generateManifest="false" manifestLocation="/OTRE/MANIFEST.MF">
+ <sealing sealJar="false">
+ <packagesToSeal/>
+ <packagesToUnSeal/>
+ </sealing>
+ </manifest>
+ <selectedElements exportClassFiles="true" exportOutputFolder="false" exportJavaFiles="false">
+ <javaElement handleIdentifier="=OTRE/src<org.eclipse.objectteams.otre.jplis{otreAgent.java"/>
+ </selectedElements>
+</jardesc>
diff --git a/othersrc/OTRE/otre_min.jardesc b/othersrc/OTRE/otre_min.jardesc
new file mode 100644
index 0000000..73086e6
--- /dev/null
+++ b/othersrc/OTRE/otre_min.jardesc
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<jardesc>
+ <jar path="org.objectteams.otdt/lib/otre_min.jar"/>
+ <options buildIfNeeded="true" compress="true" descriptionLocation="/OTRE/otre_min.jardesc" exportErrors="false" exportWarnings="true" includeDirectoryEntries="false" overwrite="true" saveDescription="true" storeRefactorings="false" useSourceFolders="false"/>
+ <storedRefactorings deprecationInfo="true" structuralOnly="false"/>
+ <selectedProjects/>
+ <manifest generateManifest="false" manifestLocation="/OTRE/MANIFEST.MF" manifestVersion="1.0" reuseManifest="false" saveManifest="false" usesManifest="true">
+ <sealing sealJar="false">
+ <packagesToSeal/>
+ <packagesToUnSeal/>
+ </sealing>
+ </manifest>
+ <selectedElements exportClassFiles="true" exportJavaFiles="false" exportOutputFolder="false">
+ <javaElement handleIdentifier="=OTRE/src<org.objectteams"/>
+ </selectedElements>
+</jardesc>
diff --git a/othersrc/OTRE/src/org/eclipse/objectteams/otre/BaseCallRedirection.java b/othersrc/OTRE/src/org/eclipse/objectteams/otre/BaseCallRedirection.java
new file mode 100644
index 0000000..567a422
--- /dev/null
+++ b/othersrc/OTRE/src/org/eclipse/objectteams/otre/BaseCallRedirection.java
@@ -0,0 +1,1446 @@
+/**********************************************************************
+ * 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: BaseCallRedirection.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.classfile.*;
+import de.fub.bytecode.generic.*;
+import de.fub.bytecode.*;
+
+import java.util.*;
+
+import org.eclipse.objectteams.otre.util.*;
+
+/**
+ * for callin-role-methods with recursive method-calls (base calls) we add a
+ * method with extendend signature.
+ * Within the extendend method recursive calls are replaced by the corresponding
+ * (chaining)base-call.<p>
+ * For example:
+ * <pre>
+ * callin m1() { m1(); } -->
+ * callin m1(Team _OT$teams[], int _OT$teamIDs[],
+ * int _OT$idx, int _OT$baseMethTag){
+ * liftToRole(b1._OT$m1$chain(Team _OT$teams[],
+ * int _OT$teamIDs[],
+ * int _OT$idx,
+ * int _OT$baseMethTag));
+ * }
+ * </pre>
+ *
+ * @version $Id: BaseCallRedirection.java 23408 2010-02-03 18:07:35Z stephan $
+ * @author Christine Hundt
+ * @author Stephan Herrmann
+ */
+public class BaseCallRedirection extends ObjectTeamsTransformation {
+
+ static class IHPair {
+ private InstructionHandle _ih1, _ih2;
+ public IHPair (InstructionHandle ih1, InstructionHandle ih2) {
+ _ih1 = ih1;
+ _ih2 = ih2;
+ }
+ public InstructionHandle fst() {return _ih1; }
+ public InstructionHandle snd() {return _ih2; }
+ }
+
+ public BaseCallRedirection(SharedState state) { this(null, state); }
+ public BaseCallRedirection(ClassLoader loader, SharedState state) {
+ super(loader, state);
+ }
+
+ /**
+ * @param ce
+ * @param cg
+ */
+ public void doTransformInterface(ClassEnhancer ce, ClassGen cg) {
+ factory = new InstructionFactory(cg);
+ String class_name = cg.getClassName();
+
+ if (state.interfaceTransformedClasses.contains(class_name)) {
+ return; //already transformed!
+ }
+
+ ConstantPoolGen cpg = cg.getConstantPool();
+ checkReadClassAttributes(ce, cg, class_name, cpg);
+
+ if (!CallinBindingManager.isRole(class_name)) {
+ return;
+ }
+
+ if (!cg.isInterface()) {
+ Set<String> boundBaseMethods = CallinBindingManager.getBoundRoleMethods(class_name);
+ addBaseCallSurrogatesForReplaceBindings(ce, boundBaseMethods, cg);
+ }
+
+ Method[] methods = cg.getMethods();
+ for (int i=0; i<methods.length; i++) {
+ Method m = methods[i];
+ String method_name = m.getName();
+ String method_signature = m.getSignature();
+
+ if (candidateForImplicitActivation(m, cg, cpg)) { // TODO: check the other preconditions, like not abstact etc.
+ cg.replaceMethod(m, genImplicitActivation(m, class_name, cpg, true));
+ }
+
+ if (!isCallin(m, cg))
+ continue;
+ if (logging) printLogMessage(method_name + " in " + class_name
+ + " IS A CALLIN-METHOD!");
+ if (method_name.startsWith(OT_PREFIX)) {
+ method_name = revertToOriginalName(method_name);
+ if (logging) printLogMessage("Reverted tsuper name to " + method_name);
+ }
+ // code SHOULD contain at least one base call.
+ if(logging) printLogMessage("----->will add another method " + method_name
+ + " with enhanced signature");
+
+//{SH: retrench signature because otherwise the binding will not be found,
+// as a result an empty basecall surrogate will be generated leading to repetetive methods...
+// TODO(SH) is this the proper way to retrench??
+ String enhancedPrefix = "([Lorg/objectteams/Team;[IIII[Ljava/lang/Object;";
+ if (method_signature.startsWith(enhancedPrefix))
+ method_signature = "("+method_signature.substring(enhancedPrefix.length());
+// SH}
+
+ boolean roleMethodIsBound = CallinBindingManager.roleMethodHasBinding(class_name,
+ method_name,
+ method_signature);
+
+ //if (mbs.isEmpty()) {
+ if (!roleMethodIsBound) {
+ if (logging) printLogMessage("callin method " + method_name
+ + " was not bound in this class!!!");
+ }
+ MethodGen baseCallSurrogate = null;
+ if (!IS_COMPILER_13X_PLUS) { // since 1.3.0 this part is legacy:
+ if (!roleMethodIsBound && !methodHasCallinFlags(m, cg, OVERRIDING) && !m.isStatic()) {
+ // method not bound in current class and doesn't inherit a base call surrogate
+ baseCallSurrogate = generateEmptyBaseCallSurrogate(cg, m);
+ }
+ if (baseCallSurrogate != null)
+ ce.addMethod(baseCallSurrogate.getMethod(), cg);
+ }
+
+ }
+ state.interfaceTransformedClasses.add(class_name);
+ }
+
+ /**
+ * Generates an "empty" base call surrogate method, which just throws an 'Error'.
+ * This method should normaly never be called, but overwritten in a subclass.
+ * It has to be generated just for the wellformedness of the class file.
+ * @param cg
+ * @param m
+ * @param mbs
+ * @param baseClassName
+ * @return
+ */
+ private MethodGen generateEmptyBaseCallSurrogate(ClassGen cg, Method m/*, List mbs*/) {
+ if (m.getName().startsWith(OT_PREFIX))
+ return null; // ot-internal methods don't need this?
+
+ ConstantPoolGen cpg = cg.getConstantPool();
+ String class_name = cg.getClassName();
+ MethodGen mg = new MethodGen(m, class_name, cpg);
+
+ if (isTSuperWrapper(mg)) {
+ // tsuper wrapper do not need base call surrogates
+ return null;
+ }
+
+ // role method already was enhanced by compiler
+ Type[] enhancedArgumentTypes = mg.getArgumentTypes();
+ if (IS_COMPILER_GREATER_123) {
+ // add super flag between enhancement and real arguments:
+ int len = enhancedArgumentTypes.length;
+ Type[] newArgumentTypes = new Type[len+1];
+ System.arraycopy(enhancedArgumentTypes, 0, newArgumentTypes, 0, EXTRA_ARGS);
+ newArgumentTypes[EXTRA_ARGS] = Type.BOOLEAN;
+ System.arraycopy(enhancedArgumentTypes, EXTRA_ARGS, newArgumentTypes, EXTRA_ARGS+1, len-EXTRA_ARGS);
+ enhancedArgumentTypes = newArgumentTypes;
+ }
+ Type enhancedReturnType = mg.getReturnType();
+
+// {SH: interface method has no argument names? generate dummy names:
+ String[] argumentNames = new String[enhancedArgumentTypes.length];
+ for (int i = 0; i < argumentNames.length; i++) {
+ argumentNames[i] = "arg"+i;
+ }
+
+ // role method already was enhanced by compiler:
+ String[] enhancedArgumentNames = argumentNames;
+// }
+ InstructionList il = new InstructionList();
+ //int accessFlags = m.getAccessFlags();
+ int accessFlags = Constants.ACC_PROTECTED; // no unanticipated calls possible
+
+// {SH: interface methods must be public abstract:
+ if (cg.isInterface())
+ accessFlags = Constants.ACC_ABSTRACT|Constants.ACC_PUBLIC;
+// }
+
+ MethodGen baseCallSurrogate = new MethodGen(accessFlags,
+ enhancedReturnType,
+ enhancedArgumentTypes,
+ enhancedArgumentNames,
+ getBaseCallSurrogateName(m.getName(), m.isStatic(), class_name /*genRoleInterfaceName(class_name)*/),
+ class_name,
+ il, cpg);
+// {SH: no code for interface method:
+ if (!cg.isInterface()) {
+ // orig:
+ if (logging)
+ printLogMessage("Exception has to be thrown!");
+
+ createThrowInternalError(cpg, il, new InstructionList(new PUSH(cpg, "Binding-Error: base-call impossible!")));
+
+ il.append(InstructionFactory.createNull(enhancedReturnType));
+ il.append(InstructionFactory.createReturn(enhancedReturnType));
+
+ if (debugging)
+ baseCallSurrogate.addLineNumber(il.getStart(), STEP_OVER_LINENUMBER);
+ }
+// }
+
+ il.setPositions();
+ baseCallSurrogate.removeNOPs();
+ baseCallSurrogate.setMaxStack();
+ baseCallSurrogate.setMaxLocals();
+ return baseCallSurrogate;
+ }
+
+ /**
+ * @param mg
+ * @return
+ */
+ private static boolean isTSuperWrapper(MethodGen mg) {
+ Type[] argTypes = mg.getArgumentTypes();
+ if (argTypes.length == 0) {
+ return false; // no tsuper marker interface argument existing
+ }
+ String lastArgument = (argTypes[argTypes.length - 1]).toString();
+ return lastArgument.contains(OTDT_PREFIX);
+ }
+
+ /**
+ * Adds base call surrogate method for all role method bindings in the current role class.
+ * Thereby method bindings which are defined in super roles are accumulated and
+ * considered as well.
+ * @param ce the ClassEnhancer to which the new method has to be added
+ * @param boundRoleMethods the bound methods of the role class
+ * @param cg the ClassGen for the role class
+ */
+ private void addBaseCallSurrogatesForReplaceBindings(ClassEnhancer ce, Set<String> boundRoleMethods, ClassGen cg)
+ {
+ Iterator<String> it = boundRoleMethods.iterator();
+ while (it.hasNext()) {
+ String nameAndSignature = it.next();
+ int dotIndex = nameAndSignature.indexOf('.');
+ String methodName = nameAndSignature.substring(0, dotIndex);
+ String methodSignature = nameAndSignature.substring(dotIndex + 1);
+ List<MethodBinding> mbs = CallinBindingManager.getBindingsForRoleMethod(cg.getClassName(),
+ methodName,
+ methodSignature);
+ MethodBinding anyMethodBinding = mbs.get(0);
+ if (!anyMethodBinding.isReplace()) {
+ continue;
+ }
+ mbs.addAll(CallinBindingManager.getInheritedRoleMethodBindings(cg.getClassName(),
+ methodName,
+ methodSignature));
+
+ if (anyMethodBinding.hasStaticRoleMethod())
+ continue; // base call surrogates for static methods are generated within the enclosing team class
+ // TODO: remove this check as soon as static replace method bindings are no longer in 'CallinMethodMappings'
+ MethodGen baseCallSurrogate = genBaseCallSurrogate(cg, mbs);
+ ce.addOrReplaceMethod(baseCallSurrogate.getMethod(), cg);
+ }
+ }
+
+ /**
+ * Generates base call surrogate method for the role method for which the method bindings 'mbs' are.
+ * Thereby a switch-case for each bound base method is generated.
+ * This method is only for nonstatic role methods. Base call surrogates for static methods
+ * are generated within the enclosing team class
+ * @param cg the ClassGen for the role class
+ * @param mbs the method bindings for one role method
+ * @param baseClassName the name of the base class
+ */
+ MethodGen genBaseCallSurrogate(ClassGen cg, List<MethodBinding> mbs) {
+
+ //baseClassName would not be needed here, if I could find out the root-base-class-type...
+ ConstantPoolGen cpg = cg.getConstantPool();
+ String class_name = cg.getClassName();
+
+ MethodBinding anyBindingForRoleMethod = mbs.get(0);
+ String baseClassName = anyBindingForRoleMethod.getRootBoundBase();
+ String roleMethodSignature = anyBindingForRoleMethod.getRoleMethodSignature();
+
+ Type[] enhancedArgumentTypes;
+ {
+ Type[] argTypesTail = Type.getArgumentTypes(roleMethodSignature);
+ if (IS_COMPILER_GREATER_123) {
+ // add super flag between enhancement and real arguments:
+ int len = argTypesTail.length;
+ System.arraycopy(argTypesTail, 0, argTypesTail=new Type[len+1], 1, len);
+ argTypesTail[0] = Type.BOOLEAN;
+ }
+ enhancedArgumentTypes = enhanceArgumentTypes(argTypesTail);
+ }
+ Type enhancedReturnType = generalizeReturnType(Type.getReturnType(roleMethodSignature));
+ String methodName = anyBindingForRoleMethod.getRoleMethodName();
+ InstructionList il = new InstructionList();
+ int accessFlags = Constants.ACC_PROTECTED;
+
+ MethodGen baseCallSurrogate = new MethodGen(accessFlags,
+ enhancedReturnType,
+ enhancedArgumentTypes,
+ null, // no explicit names
+ getBaseCallSurrogateName(methodName, false,
+ genRoleInterfaceName(class_name)),
+ class_name,
+ il, cpg);
+
+ ObjectType baseClass = new ObjectType(baseClassName);
+ ObjectType outerClass;
+ {
+ String outerClassName = getOuterClassName(class_name);
+ outerClass = new ObjectType(outerClassName);
+ }
+
+ LocalVariableGen otResult = null;
+
+ otResult = baseCallSurrogate.addLocalVariable("_OT$result",
+ enhancedReturnType, null, null);
+
+ il.insert(InstructionFactory.createStore(enhancedReturnType,
+ otResult.getIndex()));
+ il.insert(new ACONST_NULL());
+ il.setPositions(); // about to retrieve instruction handles.
+
+ if (logging) printLogMessage("base-call switch has to be inserted!");
+ InstructionList loading = new InstructionList();
+ loading.append(InstructionFactory.createThis());
+ int index = 1;
+ for (int i = 0; i < enhancedArgumentTypes.length; i++) {
+ loading.append(InstructionFactory.createLoad(enhancedArgumentTypes[i],index));
+ index += enhancedArgumentTypes[i].getSize();
+ }
+
+ Type[] argumentTypes = Type.getArgumentTypes(roleMethodSignature);
+ Type returnType = Type.getReturnType(roleMethodSignature);
+
+ if (debugging) {
+ baseCallSurrogate.addLineNumber(il.getStart(), STEP_OVER_LINENUMBER);
+ }
+
+ boolean generateSuperAccess = false;
+ List<SuperMethodDescriptor> superAccesses = IS_COMPILER_GREATER_123 ? CallinBindingManager.getSuperAccesses(baseClassName) : null;
+ if (superAccesses != null) {
+ outer: for (SuperMethodDescriptor superMethod : superAccesses) {
+ for (MethodBinding methodBinding : mbs) {
+ if ( superMethod.methodName.equals(methodBinding.getBaseMethodName())
+ && superMethod.signature.equals(methodBinding.getBaseMethodSignature()))
+ {
+ generateSuperAccess = true;
+ break outer;
+ }
+ }
+ }
+ }
+
+ BranchInstruction ifSuper = new IFEQ(null);
+ GotoInstruction skipElse = new GOTO(null);
+ if (generateSuperAccess) {
+ // gen: if (isSuperAccess) { _OT$base._OT$m$super(args); } else ...
+ il.append(InstructionFactory.createLoad(Type.BOOLEAN, EXTRA_ARGS+1)); // last synthetic arg is super-flag
+ il.append(ifSuper);
+ il.append(genBaseCallSwitch(cpg, mbs, baseCallSurrogate,
+ argumentTypes,
+ outerClass, baseClass,
+ returnType,
+ otResult, loading, true));
+ il.append(skipElse);
+ }
+ InstructionList
+ basecall = genBaseCallSwitch(cpg, mbs, baseCallSurrogate,
+ argumentTypes,
+ outerClass, baseClass,
+ returnType,
+ otResult, loading, false);
+ InstructionHandle callStart = basecall.getStart(); // store handle before append eats the list
+ il.append(basecall);
+ if (generateSuperAccess) {
+ ifSuper.setTarget(callStart);
+ skipElse.setTarget(il.append(new NOP()));
+ }
+
+ il.append(InstructionFactory.createLoad(enhancedReturnType, otResult.getIndex()));
+ il.append(InstructionFactory.createReturn(enhancedReturnType));
+
+ il.setPositions();
+ baseCallSurrogate.removeNOPs();
+ baseCallSurrogate.setMaxStack();
+ baseCallSurrogate.setMaxLocals();
+ return baseCallSurrogate;
+ }
+
+/*
+ Type findBaseFieldType(JavaClass c, ConstantPoolGen cpg) {
+ Field[] fields = c.getFields();
+ for (int l=0; l<fields.length; l++) {
+ Field f = fields[l];
+ if (f.getName().equals(BASE)) {
+ FieldGen fg = new FieldGen(f, cpg);
+ return fg.getType();
+ }
+ }
+ JavaClass superClass = Repository.lookupClass(c.getSuperclassName());
+ // BCEL bug: super class of "Object" is "Object":
+ //System.err.println("Superclass of "+ c.getClassName()+" is " +c.getSuperclassName());
+ if (!superClass.getClassName().equals("java.lang.Object")) {
+ return findBaseFieldType(superClass, cpg);
+ }
+ return null;
+ }*/
+
+ /**
+ * Iterate through the instructions of a callin method.
+ * <ul>
+ * <li>Adjust local variable instructions due to inserted extra arguments.
+ * <li>Replace base-calls and calls to activate.
+ * </ul>
+ * @param cg
+ * @param m
+ * @param mbs List<MethodBinding>
+ * @return MethodGen
+ */
+ MethodGen replaceBaseCalls(ClassGen cg, Method m, List<MethodBinding> mbs) {
+
+ int indexOffset = m.isStatic() ? -1 : 0; // argument indices are decremented for static methods,
+ // because of the missing 'this'
+
+ ConstantPoolGen cpg = cg.getConstantPool();
+ String class_name = cg.getClassName();
+ String method_name = m.getName();
+
+ MethodGen mg = new MethodGen(m, class_name, cpg);
+
+ Type[] argumentTypes = mg.getArgumentTypes();
+ Type returnType = mg.getReturnType();
+
+ Type[] enhancedArgumentTypes = enhanceArgumentTypes(mg.getArgumentTypes());
+// {SH abstract methods may not have argument names??
+ String[] argumentNames;
+ if (m.isAbstract()) {
+ argumentNames = new String[argumentTypes.length];
+ int index = 0;
+ for (int i = 0; i < argumentNames.length; i++) {
+ argumentNames[i] = "arg" + index/* i */;
+ index += argumentTypes[i].getSize();
+ }
+
+/*
+// load regular arguments:
+ int index = 1;
+ for (int i=0; i<argTypes.length; i++) {
+ il.append(InstructionFactory.createLoad(argTypes[i],index));
+ index += argTypes[i].getSize();
+ }
+//*/
+
+ } else {
+ argumentNames = mg.getArgumentNames();
+ }
+ String[] enhancedArgumentNames = enhanceArgumentNames(argumentNames);
+// orig: String[] enhancedArgumentNames = enhanceArgumentNames(mg.getArgumentNames());
+// SH}
+
+ Type enhancedMethodReturnType = generalizeReturnType(m.getSignature());
+
+// {SH instruction list may be null for abstract method
+// orig: InstructionList il = mg.getInstructionList().copy();
+ InstructionList il = mg.getInstructionList();
+ if (il != null)
+ il = il.copy();
+ else
+ il = new InstructionList();
+// SH}
+
+ MethodGen enhancedMethod = new MethodGen(m.getAccessFlags(),
+ enhancedMethodReturnType,
+ enhancedArgumentTypes,
+ enhancedArgumentNames,
+ method_name, class_name,
+ il, cpg);
+ //not needed??:
+ // or not??????
+ copyLocalVariables(mg, enhancedMethod);
+ copyLineNumbers(mg, enhancedMethod);
+
+ boolean returnValueAdded = (returnType == Type.VOID)
+ && (enhancedMethodReturnType != Type.VOID);
+
+ // all exception handlers of this method, which have to be updated later.
+ CodeExceptionGen [] handlers = copyExceptionHandlers(mg, enhancedMethod, il);
+ // list of instruction handles (old and new) that are replaced in the sequel
+ ArrayList<IHPair> replacedInstructions = new ArrayList<IHPair>(); // of IHPair;
+ // set of instruction handles which signal TargetLostException during delete().
+ HashSet<InstructionHandle> targetLost = new HashSet<InstructionHandle>(); // of InstructionHandle
+
+ // create LocalVariable Object _OT$result:
+ LocalVariableGen otResult = null;
+
+ int slot = mg.getMaxLocals() + EXTRA_ARGS-indexOffset;
+ otResult = enhancedMethod.addLocalVariable("_OT$result", enhancedMethodReturnType,
+ slot, null, null);
+
+ // subtract EXTRA_ARGS since this offset will be added again below.
+ il.insert(InstructionFactory.createStore(enhancedMethodReturnType,
+ otResult.getIndex() - EXTRA_ARGS));
+
+ il.insert(new ACONST_NULL());
+ il.setPositions(); // about to retrieve instruction handles.
+
+ InstructionHandle[] ihs = il.getInstructionHandles();
+ //printLogMessage("every call of base." + method_name + "(...) will be replaced by "
+ // + liftMethodName + BASE + "."+baseChainMethodName+"(...))");
+
+ int actInstruction = 0;
+ int offset = EXTRA_ARGS;
+ while (actInstruction < ihs.length) {
+ Instruction act_instruction = ihs[actInstruction].getInstruction();
+/****************************** variable index adaption: **********************************/
+ if(act_instruction instanceof LocalVariableInstruction) {
+ // add offset to the index of every variable load or store instruction,
+ // because of the inserted EXTRA_ARGS arguments:
+ LocalVariableInstruction localVariableInstruction = (LocalVariableInstruction) act_instruction;
+ if (localVariableInstruction.getIndex() != 0 || (enhancedMethod.isStatic())) { // 'this' stays at index 0
+ if (localVariableInstruction instanceof StoreInstruction) {
+ localVariableInstruction =
+ InstructionFactory.createStore(localVariableInstruction.getType(cpg),
+ offset+localVariableInstruction.getIndex());
+ } else if (localVariableInstruction instanceof LoadInstruction) {
+ localVariableInstruction =
+ InstructionFactory.createLoad(localVariableInstruction.getType(cpg),
+ offset+localVariableInstruction.getIndex());
+ } else if (localVariableInstruction instanceof IINC) {
+ localVariableInstruction.setIndex(offset+localVariableInstruction.getIndex());
+ // TODO: check, if this is enough for all kinds of LocalVariableInstructions
+ // and if there are more instructions which use variable indizes!!
+ }
+ ihs[actInstruction].setInstruction(localVariableInstruction);
+ }
+ } else if (act_instruction instanceof RET) {
+ RET ret = (RET)act_instruction;
+ if (ret.getIndex() != 0)
+ ihs[actInstruction].setInstruction(new RET(offset + ret.getIndex()));
+
+/*************************** "super"- & "tsuper"-call enhancement: **********************************/
+ } else if (super_or_tsuper_instruction(act_instruction, method_name, cpg) ) {
+
+ InvokeInstruction ii = (InvokeInstruction)act_instruction;
+ InstructionHandle next = ihs[actInstruction+1];
+ InstructionList changedArea;
+ InstructionHandle[] delim = new InstructionHandle[2];
+ int stackDepth = computeArgumentStackDepth(cpg, ii);
+ InstructionList loading = pruneLoading(il, ihs, actInstruction,
+ stackDepth, cpg,
+ targetLost, delim, true);
+ if (loading == null) {
+ actInstruction++;
+ continue;
+ }
+
+ changedArea = genEnhancedSuperCall(cpg, ii, enhancedMethod, loading);
+ if (returnValueAdded) {
+ changedArea.append(InstructionFactory.createStore(
+ enhancedMethodReturnType, otResult.getIndex()));
+ } else {
+ InstructionHandle ih = adjustValue(changedArea, changedArea.getEnd(), enhancedMethodReturnType, returnType);
+ if (debugging && ih != null)
+ mg.addLineNumber(ih, STEP_OVER_LINENUMBER);
+ }
+ replacedInstructions.add(new IHPair(delim[0], changedArea.getStart()));
+ replacedInstructions.add(new IHPair(delim[1], changedArea.getEnd()));
+
+ il.insert(next, changedArea);
+ actInstruction++;
+ continue;
+
+/*************************** "activate" substitution and base-call generation: ************/
+ //} else if (act_instruction instanceof INVOKEVIRTUAL) {
+ // INVOKEVIRTUAL iv = (INVOKEVIRTUAL)act_instruction;
+ } else if (act_instruction instanceof InvokeInstruction) {
+ InvokeInstruction iv = (InvokeInstruction)act_instruction;
+ String iv_name = iv.getName(cpg);
+
+ // FIXME(SH): is this still needed?
+ // - activate is commented-out,
+ // - base call is now generated by the compiler.
+ if(!(iv_name.equals(method_name) ||
+ iv_name.equals("activate")))
+ {
+ actInstruction++;
+ continue;
+ }
+ InstructionHandle next = ihs[actInstruction+1];
+ InstructionList changedArea;
+ InstructionHandle[] delim = new InstructionHandle[2];
+ /*
+ if (iv_name.equals("activate")) {
+ // blank original invokevirtual:
+ ihs[actInstruction].setInstruction(new NOP());
+ Type [] ivArgTypes = iv.getArgumentTypes(cpg);
+ int activateArgCount = ivArgTypes.length;
+ InstructionList loading = null;
+ if (activateArgCount == 1)
+ loading = pruneLoading (il, ihs, actInstruction,
+ ivArgTypes[0].getSize(), cpg,
+ targetLost, delim, false);
+ changedArea = enhanceActivateCall(factory, cpg, loading, iv);
+ if (activateArgCount == 1) {
+ replacedInstructions.add(new IHPair(delim[0],
+ changedArea.getStart()));
+ replacedInstructions.add(new IHPair(delim[1],
+ changedArea.getEnd()));
+ }
+ } else*/ { // base call:
+ int stackDepth = computeArgumentStackDepth(cpg, iv);
+ boolean deleteThis = true;
+
+ if(enhancedMethod.isStatic())
+ deleteThis = false;
+
+ /*
+ if (iv.getOpcode()==Constants.INVOKESTATIC)
+ deleteThis = false;
+ */
+ InstructionList loading = pruneLoading(il, ihs, actInstruction,
+ stackDepth, cpg,
+ targetLost, delim, /*true*/deleteThis);
+ //System.err.println(loading);
+ if (loading == null) {
+ actInstruction++;
+ continue;
+ }
+
+ // insert call of base-call surrogate method:
+ String roleInterfaceName = genRoleInterfaceName(cg.getClassName());
+
+ String calleeClassName = null;
+ if(m.isStatic()) {
+ calleeClassName = extractTeamName(roleInterfaceName);
+ }
+ changedArea = genBaseCallSurrogateCall(cpg, iv, enhancedMethod, loading, extractRoleName(roleInterfaceName), calleeClassName);
+
+ if (returnValueAdded) {
+ changedArea.append(InstructionFactory.createStore(enhancedMethodReturnType,
+ otResult.getIndex()));
+ } else {
+ InstructionHandle ih = adjustValue(changedArea, changedArea.getEnd(), enhancedMethodReturnType, returnType);
+ if (debugging && ih != null)
+ mg.addLineNumber(ih, STEP_OVER_LINENUMBER);
+ }
+ replacedInstructions.add(new IHPair(delim[0], changedArea.getStart()));
+ replacedInstructions.add(new IHPair(delim[1], changedArea.getEnd()));
+
+ } // if (activate or base call)
+
+ il.insert(next, changedArea);
+
+
+/*************************** "return" enhancements: ************/
+ } else if (act_instruction instanceof ReturnInstruction) {
+ // replace return statement by result preparation and a new return statement
+ // construct back to front, to keep the insertion position!
+ InstructionHandle oldReturn = ihs[actInstruction];
+ InstructionHandle replacedPos = oldReturn;
+ il.append(oldReturn, InstructionFactory.createReturn(enhancedMethodReturnType));
+ if (returnValueAdded) {
+ // load ot_result:
+ oldReturn.setInstruction(InstructionFactory.createLoad(enhancedMethodReturnType,
+ otResult.getIndex()));
+ } else {
+ oldReturn.setInstruction(new NOP());
+ replacedPos =
+ adjustValue(il, oldReturn, returnType, enhancedMethodReturnType);
+ if (debugging && replacedPos != null)
+ mg.addLineNumber(replacedPos, STEP_OVER_LINENUMBER);
+ }
+ if (replacedPos != null)
+ replacedInstructions.add(new IHPair(oldReturn, replacedPos));
+ } // conditional over instruction types
+ actInstruction++;
+ } //end while
+
+ // tidy:
+ checkUpdate(handlers, replacedInstructions, targetLost);
+ enhancedMethod.removeNOPs();
+ il.setPositions();
+ enhancedMethod.setMaxStack();
+ enhancedMethod.setMaxLocals();
+
+ return enhancedMethod;
+ }
+
+ /**
+ * Given an invokevirtual compute the space its arguments use on the stack.
+ * @param cpg
+ * @param iv
+ * @return int stack size.
+ */
+ static int computeArgumentStackDepth(ConstantPoolGen cpg, InvokeInstruction ii) {
+ Type [] iiargs = ii.getArgumentTypes(cpg);
+ int depth=0;
+ for (int i=0; i<iiargs.length; i++)
+ depth += iiargs[i].getSize();
+ return depth;
+ }
+
+ /**
+ * Copy all local variables from <tt>src</tt> to <tt>dest</tt>.
+ * While doing so, increment their index by EXTRA_ARGS.
+ */
+ static void copyLocalVariables(MethodGen src, MethodGen dest) {
+ Type[] argumentTypes = src.getArgumentTypes();
+ LocalVariableGen[] lvgs = src.getLocalVariables();
+ for (int l=argumentTypes.length; l<lvgs.length; l++) {
+ LocalVariableGen lvg = lvgs[l];
+ if (lvg.getIndex() > 0) {
+ dest.addLocalVariable(lvg.getName(),
+ lvg.getType(),
+ lvg.getIndex()+(EXTRA_ARGS+1), // +1?????
+ null, null);
+ //System.err.println("adding:" +src.getClassName() +" "+src.getName()+" "+lvg.getName() +" " + lvg.getType() +" "+ (lvg.getIndex()+(EXTRA_ARGS+1)));
+ }
+ }
+ }
+ /** Copy all line numbers from <tt>src</tt> to <tt>dest</tt>. */
+ static void copyLineNumbers(MethodGen src, MethodGen dest) {
+ InstructionList il_dest = dest.getInstructionList();
+ il_dest.setPositions();
+ LineNumberGen[] src_lng = src.getLineNumbers();
+ for (int i=0; i<src_lng.length; i++) {
+ int position = src_lng[i].getInstruction().getPosition();
+ InstructionHandle ih = il_dest.findHandle(position);
+ dest.addLineNumber(ih, src_lng[i].getSourceLine());
+ }
+ }
+ /**
+ * Prune a invokevirtual portion from a given instruction list.
+ * Note, that arguments don't include 'this', which is not pruned but blanked
+ * (need to keep as possible jump target).
+ * @param il the source list
+ * @param ihs array of handles of this list
+ * @param idx points to a invokevirtual that shall be removed
+ * @param stackDepth size of the called method's arguments on the stack.
+ * This is how deep we need to cut into the stack.
+ * @param cpg
+ * @param targetLost set of lost InstructionHandles to be filled
+ * @param delim array of two handles, which should be filled with start and end of
+ * the pruned region.
+ * @param blankThis should the 'this' call target be overwritten?
+ * @return InstructionList a copy of the original value loading.
+ */
+ static InstructionList pruneLoading (InstructionList il, InstructionHandle[] ihs, int idx,
+ int stackDepth, ConstantPoolGen cpg,
+ HashSet<InstructionHandle> targetLost, InstructionHandle[] delim,
+ boolean blankThis)
+ {
+ InstructionList nlist = new InstructionList();
+ InstructionHandle start = ihs[idx];
+ InstructionHandle end = ihs[idx--];
+ while (stackDepth > 0) {
+ start = ihs[idx--];
+ Instruction instr = start.getInstruction();
+ stackDepth -= stackDiff(instr, cpg);
+ nlist.insert(instr);
+ }
+ if (blankThis) {
+ if (!isALoad0(ihs[idx].getInstruction()))
+ return null;
+ ihs[idx].setInstruction(new NOP()); // keep as jump target but delete 'this'
+ }
+ delim[0] = start;
+ delim[1] = end;
+ safeDelete(il, start, end, targetLost);
+ return nlist;
+ }
+
+ static boolean isALoad0(Instruction i) {
+ if (!(i instanceof ALOAD)) return false;
+ return ((ALOAD)i).getIndex() == 0;
+ }
+
+ /** Get the lenght of the longest base method signature in mbs.
+ * @param mbs List of {@link MethodBinding MethodBinding}
+ */
+// static int getMaxBaseArgLen (List mbs) {
+// int max=0;
+// Iterator it = mbs.iterator();
+// while (it.hasNext()) {
+// MethodBinding mb = (MethodBinding)it.next();
+// String sign = mb.getBaseMethodSignature();
+// int len = Type.getArgumentTypes(sign).length;
+// if (len>max) max = len;
+// }
+// return max;
+// }
+
+ /**
+ * Generate a dispatching switch statement which calls the proper base method.
+ * @param cpg
+ * @param mbs list of MethodBinding that applies to this callin method
+ * @param enhancedMethod the enhanced callin method
+ * @param roleArgumentTypes arg types of the callin method
+ * @param outerClass the Team
+ * @param baseClass the base bound to this role
+ * @param returnType the return type of the original callin method
+ * @param otResult the local variable storing the base call result
+ * @param loading an instruction list holding the original instructions for
+ * loading parameters
+ * @return InstructionList the complete replacement implementing the base call.
+ */
+ InstructionList genBaseCallSwitch (ConstantPoolGen cpg,
+ List<MethodBinding> mbs, MethodGen enhancedMethod,
+ Type[] roleArgumentTypes,
+ ObjectType outerClass, ObjectType baseClass,
+ Type returnType, LocalVariableGen otResult,
+ InstructionList loading,
+ boolean isSuperAccess)
+ {
+
+ String className = enhancedMethod.getClassName();
+ Type enhancedMethodReturnType = enhancedMethod.getReturnType();
+ boolean callinHasReturnValue = returnType != Type.VOID;
+
+ InstructionList il = new InstructionList();
+
+ // Setup a variable which holds the result of this base call.
+ // This variabel is local to this segment of code and used only
+ // to transport this result out off the switch statement.
+ int localResult = -1;
+ LocalVariableGen lg = null;
+ if (callinHasReturnValue) {
+ lg = enhancedMethod.addLocalVariable("_OT$tmpResult", returnType,
+ null, null);
+ localResult = lg.getIndex();
+ il.append(InstructionFactory.createNull (returnType));
+ il.append(InstructionFactory.createStore(returnType, localResult));
+ }
+
+ // ---- Prepare the switch: ----
+ InstructionHandle switchStart = il.append
+ (InstructionFactory.createLoad(Type.INT, BASE_METH_ARG));
+ // generated: _OT$baseMethTag
+
+ removeDuplicatedBaseMethodTags(mbs);
+
+ // one break for each case clause
+ int numberOfCases = mbs.size();
+ GOTO[] breaks = new GOTO[numberOfCases];
+ for (int i=0; i<numberOfCases; i++)
+ breaks[i] = new GOTO(null);
+
+ int[] matches = new int[numberOfCases];
+ InstructionHandle[] targets = new InstructionHandle[numberOfCases];
+ int caseCounter = 0;
+
+ Iterator<MethodBinding> it = mbs.iterator();
+ while (it.hasNext()) {
+
+ MethodBinding mb = it.next();
+
+ String wrapperName = mb.getWrapperName();
+ int[] paramPositions = CallinBindingManager.getParamPositions(outerClass.getClassName(),
+ wrapperName);
+ if (logging) printLogMessage("param pos(" + wrapperName + ")=" + paramPositions);
+
+ matches[caseCounter] = CallinBindingManager.getBaseCallTag(mb.getBaseClassName(),
+ mb.getBaseMethodName(),
+ mb.getBaseMethodSignature());
+ InstructionHandle nextBranch = il.append(new NOP());
+
+ String baseMethodName = mb.getBaseMethodName();
+ String baseMethodSignature = mb.getBaseMethodSignature();
+ Type[] baseMethodArgumentTypes = Type.getArgumentTypes(baseMethodSignature);
+ Type baseMethodReturnType = Type.getReturnType (baseMethodSignature);
+
+ String baseChainMethodName;
+ Type baseChainReturnType;
+ Type[] enhancedBaseArgumentTypes;
+ if (isSuperAccess) {
+ baseChainMethodName = OT_PREFIX+baseMethodName+"$super";
+ baseChainReturnType = returnType;
+ // base arguments are un-enhanced but have a leading base instance:
+ int len = baseMethodArgumentTypes.length;
+ System.arraycopy(baseMethodArgumentTypes, 0, enhancedBaseArgumentTypes=new Type[len+1], 1, len);
+ enhancedBaseArgumentTypes[0] = baseClass;
+ } else {
+ baseChainMethodName = genChainMethName(baseMethodName);
+ baseChainReturnType = object; // ALWAYS
+ enhancedBaseArgumentTypes = enhanceArgumentTypes(baseMethodArgumentTypes);
+ }
+
+ // --- call target: ---
+
+ // if base class type is a role type _OT$base field has role interface type:
+ {
+ String baseClassName = baseClass.toString();
+ if (baseClassName.indexOf(OTDT_PREFIX) != -1) {
+ baseClass = new ObjectType(ObjectTeamsTransformation.genRoleInterfaceName(baseClassName));
+ if(logging) printLogMessage(baseClassName + " --> " + ObjectTeamsTransformation.genRoleInterfaceName(baseClassName));
+ }
+ }
+
+ // load '_OT$base' field:
+ InstructionHandle baseCallLine = il.append(InstructionFactory.createThis());
+ il.append(factory.createFieldAccess(className, BASE, baseClass, Constants.GETFIELD));
+
+ if (!baseClass.getClassName().equals(mb.getBaseClassName())) {
+ // playedBy has been refined in the sub role;
+ // create a cast to the sub base class:
+ il.append(factory.createCast(baseClass, new ObjectType(mb.getBaseClassName())));
+ }
+
+ // --- load arguments of the new method: ---
+ // (letters refer to document parameter-passing.odg)
+
+ // (u) generate extra arguments (indices are equal at role and base):
+ if (!isSuperAccess)
+ for (int idx = 0; idx < EXTRA_ARGS; idx++)
+ il.append(InstructionFactory.createLoad(enhancedMethod.getArgumentTypes()[idx],
+ idx+1/*translating non-static*/));
+
+ // (v)(w)(x) split loading sequence and transfer source-level arguments
+ // (includes reverse-application of parameter mappings):
+
+ // Start at EXTRA_ARGS, because one set of enhancement has already been loaded,
+ // except when doing super access which only has one extra arg: base instance.
+ int start = isSuperAccess ? 1 : EXTRA_ARGS;
+ il.append(translateLoads(splitLoading(cpg,
+ loading.copy(),
+ roleArgumentTypes),
+ enhancedMethod.getArgumentTypes(),
+ enhancedBaseArgumentTypes,
+ paramPositions,
+ extractTeamName(enhancedMethod.getClassName()),
+ className,
+ new BaseMethodInfo(mb.baseMethodIsCallin(), false/*static*/, mb.getTranslationFlags()),
+ start,
+ cpg));
+ // --- done loading ---
+
+ // invoke the chaining method of the base class (base-call!):
+ il.append(factory.createInvoke(mb.getBaseClassName(),
+ baseChainMethodName,
+ baseChainReturnType,
+ enhancedBaseArgumentTypes,
+ isSuperAccess
+ ? Constants.INVOKESTATIC
+ : Constants.INVOKEVIRTUAL
+ ));
+
+ boolean resultLiftingNecessary = ((mb.getTranslationFlags()&1)!=0);
+
+ if (resultLiftingNecessary) { // call the static lift-method:
+ // STATIC_PARTS_OK: in role: lift method call
+//TODO: lift method args!
+ String liftMethodName = mb.getLiftMethodName();
+ Type liftMethodReturnType = Type.getReturnType(mb.getLiftMethodSignature());
+ Type[] liftMethodArgs = Type.getArgumentTypes(mb.getLiftMethodSignature());
+
+ il.append(factory.createCast(baseChainReturnType, baseMethodReturnType));
+ il.append(InstructionFactory.createThis());
+
+ int nestingDepth = countOccurrences(className, '$') -1;
+ il.append(factory.createGetField(className, "this$" + nestingDepth, outerClass ));
+
+ il.append(new SWAP()); // -> .., this$0, (BaseType)result
+ //il.append(new ICONST(LIFT_ARG_RES));
+
+ il.append(factory.createInvoke(outerClass.getClassName(),
+ liftMethodName,
+ liftMethodReturnType,
+ liftMethodArgs,
+ Constants.INVOKEVIRTUAL));
+ }
+
+ InstructionHandle afterBaseCallLine = il.append(new NOP());
+
+ if (baseChainReturnType != Type.VOID) {
+ // adjust the return value to the type expected by the WRAPPER:
+ il.append(new DUP()); // keep for adjustment below
+ if (!resultLiftingNecessary)
+ adjustValue(il, null, baseChainReturnType, enhancedMethodReturnType);
+ il.append(InstructionFactory.createStore(enhancedMethodReturnType,
+ otResult.getIndex())); // store "globally"
+ // this store is needed to tunnel unused results through the callin.
+
+ // adjust the return value to the type expected by the ORIGINAL CALLIN:
+ adjustValue(il, null, baseChainReturnType, returnType);
+ if (callinHasReturnValue)
+ il.append(InstructionFactory.createStore(returnType, localResult)); // store "locally"
+ // this store is useful for callins which make use of the result.
+ }
+
+ targets[caseCounter] = nextBranch;
+ il.append(breaks[caseCounter]);
+ // generated: break;
+
+ caseCounter++;
+
+ if (debugging) {
+ enhancedMethod.addLineNumber(baseCallLine, STEP_INTO_LINENUMBER);
+ enhancedMethod.addLineNumber(afterBaseCallLine, STEP_OVER_LINENUMBER);
+ }
+ }
+ // Default case: throw an exception reporting the situation:
+ // create: String msg = ("Unhandled base-call case!"+base_method_tag)
+ InstructionList messagePush = new InstructionList();
+ messagePush.append(factory.createNew(OTConstants.STRING_BUFFER_NAME));
+ messagePush.append(new DUP());
+ messagePush.append(factory.createInvoke(OTConstants.STRING_BUFFER_NAME, Constants.CONSTRUCTOR_NAME, Type.VOID, new Type[0], Constants.INVOKESPECIAL));
+ messagePush.append(new PUSH(cpg, "Unhandled base-call case: "));
+ messagePush.append(factory.createInvoke(OTConstants.STRING_BUFFER_NAME, "append", Type.STRINGBUFFER, new Type[]{Type.STRING}, Constants.INVOKEVIRTUAL));
+ messagePush.append(InstructionFactory.createLoad(Type.INT, BASE_METH_ARG));
+ messagePush.append(factory.createInvoke(OTConstants.STRING_BUFFER_NAME, "append", Type.STRINGBUFFER, new Type[]{Type.INT}, Constants.INVOKEVIRTUAL));
+ messagePush.append(factory.createInvoke(OTConstants.STRING_BUFFER_NAME, "toString", Type.STRING, new Type[0], Constants.INVOKEVIRTUAL));
+ // create: throw new OTREInternalError(msg)
+ InstructionHandle defaultCase = createThrowInternalError(cpg, il, messagePush);
+
+ InstructionHandle afterSwitch = il.append(new NOP()); // all breaks point here.
+
+ il.append(switchStart, createLookupSwitch(matches, targets, breaks,
+ defaultCase, afterSwitch));
+
+ // retrieve locally stored result:
+ if (callinHasReturnValue) {
+ il.append(InstructionFactory.createLoad(returnType, localResult));
+ lg.setStart(il.getStart()); // restrict local variable to this segment.
+ lg.setEnd(il.getEnd());
+ }
+
+ return il;
+ }
+
+ /**
+ * Removes duplicated method bindings with the same base call tag from the list, to avoid duplicated
+ * cases in the base call surrogate-switch.
+ * @param mbs
+ */
+ private static void removeDuplicatedBaseMethodTags(List<MethodBinding> mbs) {
+ if (mbs.size() < 2) // nothing to remove
+ return;
+
+ MethodBinding[] mbArray = mbs.toArray(new MethodBinding[mbs.size()]);
+
+ Comparator<MethodBinding> baseCallTagComparator = new Comparator<MethodBinding>() {
+ public int compare(MethodBinding firstMB, MethodBinding secondMB) {
+ int firstBaseTag = CallinBindingManager.getBaseCallTag(firstMB.getBaseClassName(),
+ firstMB.getBaseMethodName(),
+ firstMB.getBaseMethodSignature());
+ int secondBaseTag = CallinBindingManager.getBaseCallTag(secondMB.getBaseClassName(),
+ secondMB.getBaseMethodName(),
+ secondMB.getBaseMethodSignature());
+
+ if (firstBaseTag < secondBaseTag)
+ return -1;
+ if (firstBaseTag > secondBaseTag)
+ return 1;
+ return 0;
+ }
+ };
+ Arrays.sort(mbArray, baseCallTagComparator);
+ for (int i = 0; i + 1 < mbArray.length; i++) {
+ if (baseCallTagComparator.compare(mbArray[i], mbArray[i + 1]) == 0) {
+ mbs.remove(mbArray[i + 1]);
+ }
+ }
+ }
+
+
+ /**
+ * @param className
+ * @return
+ */
+ private static String extractTeamName(String roleClassName) {
+ int lastDollarIndex = roleClassName.lastIndexOf('$');
+ return roleClassName.substring(0, lastDollarIndex);
+ }
+
+ /**
+ * @param className
+ * @return
+ */
+ private static String extractRoleName(String roleClassName) {
+ int lastDollarIndex = roleClassName.lastIndexOf('$');
+ return roleClassName.substring(lastDollarIndex+1, roleClassName.length());
+ }
+
+ /**
+ * FIXME(SH): obsolete!
+ * @param baseMethodReturnType
+ * @param returnType
+ * @return
+ */
+// private static boolean returnTypeCompatible(Type from, Type to) {
+// System.out.println("test for " + from + "->" + to);
+// if (from.equals(to))
+// return true;
+// if (from instanceof ObjectType && to instanceof ObjectType) {// how to handle compatible basic types??
+// ObjectType otFrom = (ObjectType) from;
+// ObjectType otTo = (ObjectType) to;
+// if (otFrom.subclassOf(otTo))
+// return true;
+// }
+// return false;
+// }
+
+ /**
+ * Copy all exception handlers of a method.
+ * @param source the method from where to copy
+ * @param dest the method where to copy to
+ * @param il instructions of `dest' which must still have the same positions
+ * as the instructions in `source'.
+ * @return an array of handler generators, which still has to be maintained,
+ * whenever instructions are replaced in the methods instruction list.
+ */
+ static CodeExceptionGen[] copyExceptionHandlers(MethodGen source,
+ MethodGen dest,
+ InstructionList il) {
+ il.setPositions(); // needed to retrieve handles by position.
+ CodeExceptionGen[] excGens = source.getExceptionHandlers();
+ CodeExceptionGen[] newGens = new CodeExceptionGen[excGens.length];
+ if ((excGens != null) && excGens.length > 0) {
+ for (int hcount=0; hcount<excGens.length; hcount++) {
+ CodeExceptionGen excGen = excGens[hcount];
+ InstructionHandle excStart = il.findHandle(excGen.getStartPC().getPosition());
+ InstructionHandle excEnd = il.findHandle(excGen.getEndPC().getPosition());
+ InstructionHandle excHandler = il.findHandle(excGen.getHandlerPC().getPosition());
+ ObjectType catchType = excGen.getCatchType();
+ newGens[hcount] =
+ dest.addExceptionHandler(excStart, excEnd, excHandler, catchType);
+ }
+ }
+ return newGens;
+ }
+
+ /**
+ * Update the positions of all exception handlers.
+ * @param handlers the handlers of this method.
+ * @param replaced a pair of InstructionHandles, the first is replaced by the second.
+ */
+ static void updateHandlers (CodeExceptionGen[] handlers, IHPair replaced) {
+ InstructionHandle old = replaced.fst();
+ InstructionHandle neu = replaced.snd();
+ for (int i=0; i<handlers.length; i++) {
+ // System.out.println("handler "+handlers[i]);
+ if (handlers[i].containsTarget(old) && (old != neu)) {
+ // System.out.println("update "+old+"->"+neu);
+ handlers[i].updateTarget(old, neu);
+ }
+ }
+ }
+
+ /**
+ * Delete a range of instructions, whithout throwing TargetLostException.
+ * @param il the list to delete from
+ * @param start handle to first instruction to delete.
+ * @param end handle to last instruction to delete.
+ * @param collect a set of InstructionHandle which are still targeted.
+ */
+ static void safeDelete(InstructionList il,
+ InstructionHandle start, InstructionHandle end,
+ HashSet<InstructionHandle> collect)
+ {
+ try {
+ il.delete(start, end);
+ } catch(TargetLostException e) {
+ // System.out.print("Loosing:"+e+" ");
+ InstructionHandle [] targets = e.getTargets();
+ for (int tcount = 0; tcount < targets.length; tcount++) {
+ collect.add(targets[tcount]);
+ // System.out.println(targets[tcount]+"!!");
+ }
+ }
+ }
+
+ /**
+ * Update all exceptions handlers with respect to all instructions that were replaced.
+ * Check that this covers all instruction handles in 'lost'.
+ * @param handles the exception handlers of this method.
+ * @param replacedList list of IHPairs describing what has been modified.
+ * @param lost set of instruction handles that were still referred to when
+ * they were deleted. All these handles should be updated.
+ */
+ static void checkUpdate(CodeExceptionGen[] handlers, ArrayList<IHPair> replacedList, HashSet<InstructionHandle> lost) {
+ // System.out.println("Update "+replacedList+"/"+lost);
+ Iterator<IHPair> iter = replacedList.iterator();
+ while (iter.hasNext()) {
+ IHPair replaced = iter.next();
+ updateHandlers(handlers, replaced);
+ lost.remove(replaced.fst());
+ }
+ if (!lost.isEmpty()) {
+ System.err.println("Warning: "+lost.size()+" target(s) lost: ");
+ Iterator<InstructionHandle> it = lost.iterator();
+ while (it.hasNext())
+ System.out.println(it.next());
+ }
+ }
+
+ /**
+ * While adding extra args to an activate call:
+ * <ul>
+ * <li>Check whether an activationLevel was passed (single argument)
+ * <li>if so, insert the loading sequence for that expression.
+ * <li>also the return differs (void or int), should however be
+ * consistent between plain and enhanced version.
+ * <li>decrement "idx" so this team is the currently active in the chain.
+ * </ul>
+ * @param factory
+ * @param cpg
+ * @param loading sequence, which loads "level" argument, else null.
+ * @param iv the invokevirtual for "activate", used to inspect the
+ * original signature.
+ * @return the full sequence for loading the arguments, but not the
+ * call target (because that's the enclosing team and is kept
+ * unmodified in the original instruction list).
+ */
+// static InstructionList enhanceActivateCall (final InstructionFactory factory,
+// ConstantPoolGen cpg,
+// InstructionList loading,
+// INVOKEVIRTUAL iv) {
+// InstructionList changedArea = new InstructionList();
+//
+// // load arguments of the new method:
+// int index = 1;
+// Type[] enhancedArgumentTypes = enhanceArgumentTypes(iv.getArgumentTypes(cpg),
+// 0, false, false);
+// Type returnType = Type.VOID;
+// int kount = enhancedArgumentTypes.length;
+// if (iv.getArgumentTypes(cpg).length == 1) {
+// kount--; // "level" loaded separately via 'loading'
+// returnType = Type.INT;
+// }
+//
+// for (int k=0; k<kount; k++) {
+// changedArea.append(InstructionFactory.createLoad(enhancedArgumentTypes[k], index));
+// index += enhancedArgumentTypes[k].getSize();
+// }
+// if (loading != null)
+// changedArea.append(loading);
+//
+// // invoke the overloaded activate method:
+// changedArea.append(factory.createInvoke("org.objectteams.Team",
+// "activate",
+// returnType,
+// enhancedArgumentTypes,
+// Constants.INVOKEVIRTUAL));
+//
+// // generate: idx--;
+// changedArea.append(InstructionFactory.createLoad(Type.INT, IDX_ARG));
+// changedArea.append(new ICONST(1));
+// changedArea.append(new ISUB());
+// changedArea.append(InstructionFactory.createStore(Type.INT, IDX_ARG));
+//
+// return changedArea;
+// }
+
+ /**
+ * Generates the instructions to call the enhanced version of the 'super' respectively 'tsuper'
+ * call in a role method.
+ * @param cpg the constant pool
+ * @param ii the original invoke instruction
+ * @param enhancedMethod the enhanced role method
+ * @param loading the originally loaded arguments
+ * @return the instruction list containing the method call ingredients
+ */
+ InstructionList genEnhancedSuperCall(ConstantPoolGen cpg, InvokeInstruction ii,
+ MethodGen enhancedMethod, InstructionList loading)
+ {
+ Type returnType = enhancedMethod.getReturnType();
+ //Type[] argTypes = enhancedMethod.getArgumentTypes();
+ Type[] argTypes = enhanceArgumentTypes(ii.getArgumentTypes(cpg));
+ InstructionList il = new InstructionList();
+
+ il.append(InstructionFactory.createThis());
+ // load all additional arguments of the enhanced method (first EXTRA_ARGS):
+ int index = 1;
+ for (int i=0; i<EXTRA_ARGS; i++) {
+ il.append(InstructionFactory.createLoad(argTypes[i],index));
+ index += argTypes[i].getSize();
+ }
+ // load arguments of the originally call:
+ il.append(loading);
+
+ // call super.<enhancedMethod>:
+ short kind=0;
+ if (ii instanceof INVOKESPECIAL)
+ kind = Constants.INVOKESPECIAL;
+ else
+ kind = Constants.INVOKEVIRTUAL;
+
+ il.append(factory.createInvoke(ii.getClassName(cpg),
+ ii.getMethodName(cpg),
+ returnType,
+ argTypes,
+ kind));
+ return il;
+ }
+
+ /**
+ * Generates the instructions to call the base call surrogate method.
+ * @param cpg the constant pool
+ * @param iv the original invoke instruction
+ * @param enhancedMethod the enhanced role method
+ * @param loading the originally loaded arguments
+ * @return the instruction list containing the method call ingredients
+ */
+ InstructionList genBaseCallSurrogateCall(ConstantPoolGen cpg, InvokeInstruction/*INVOKEVIRTUAL*/ iv,
+ MethodGen enhancedMethod, InstructionList loading,
+ String roleClassName, String calleeClassName) //JU: added String roleClassName and teamClassName to the method signature
+ {
+ int indexOffset = enhancedMethod.isStatic()?-1:0; // argument indexes are decremented for static methods,
+ // because of the missing 'this'
+ // for static methods callee is 'null' -> substitute by current class (JU)
+ if(calleeClassName == null) {
+ calleeClassName = iv.getClassName(cpg);
+ }
+
+ Type returnType = enhancedMethod.getReturnType();
+ //Type[] argTypes = enhancedMethod.getArgumentTypes();
+ Type[] argTypes = enhanceArgumentTypes(iv.getArgumentTypes(cpg));
+ InstructionList il = new InstructionList();
+
+ String methodName = getBaseCallSurrogateName(enhancedMethod.getName(),
+ enhancedMethod.isStatic(),
+ roleClassName);
+ short invokeKind;
+
+ if (!enhancedMethod.isStatic()) {
+ il.append(InstructionFactory.createThis());
+ invokeKind = Constants.INVOKEVIRTUAL;
+
+ } else { // role method is static:
+ invokeKind = Constants.INVOKESTATIC;
+ }
+
+ // load all additional arguments of the enhanced method (first EXTRA_ARGS):
+ int index = 1;
+ for (int i = 0; i < argTypes.length; i++) {
+ if(i < EXTRA_ARGS){ // skip original arguments
+ il.append(InstructionFactory.createLoad(argTypes[i], index+indexOffset));
+ }
+ //calculate the next index
+ index += argTypes[i].getSize();
+ }
+ // load arguments of the originally call:
+ il.append(loading);
+
+ // call _OT$<enhancedMethod>$base():
+ il.append(factory.createInvoke(calleeClassName,
+ methodName,
+ returnType,
+ argTypes,
+ invokeKind/*Constants.INVOKEVIRTUAL*/));
+ return il;
+ }
+
+
+ /**
+ * Checks, if a given instuction is a super or a tsuper call
+ * @param instr the instruction to check
+ * @param method_name the name of the method from wich the 'inst' came
+ * @param cpg the constant pool
+ * @return true, if 'inst' is a super or tsuper call
+ */
+ private static boolean super_or_tsuper_instruction(Instruction instr, String method_name, ConstantPoolGen cpg) {
+ if (isTSuperCall(instr, method_name, cpg))
+ return true;
+ if (isSuperCall(instr, method_name, cpg))
+ return true;
+ return false;
+ }
+
+ private static boolean isTSuperCall(Instruction instr, String method_name, ConstantPoolGen cpg) {
+ if (instr instanceof INVOKEVIRTUAL) {
+ INVOKEVIRTUAL iv = (INVOKEVIRTUAL)instr;
+ String iv_name = iv.getName(cpg);
+ Type[] argTypes = iv.getArgumentTypes(cpg);
+ if (argTypes.length<1) // no tsuper marker interface parameter!
+ return false;
+ String lastArgument = (argTypes[argTypes.length-1]).toString();
+ if (iv_name.equals(method_name) && (lastArgument.indexOf(TSUPER_PREFIX)!=-1)) {
+ // if iv == <method_name>(..., TSuper__OT__<SuperTeamName>) -->
+ if(logging) printLogMessage("tsuper-call to " + iv_name + " has to be enhanced!");
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private static boolean isSuperCall(Instruction instr, String method_name, ConstantPoolGen cpg) {
+ if (instr instanceof INVOKESPECIAL) {
+ INVOKESPECIAL is = (INVOKESPECIAL)instr;
+ String is_name = is.getName(cpg);
+
+ if(is_name.equals(method_name)) {
+ if(logging) printLogMessage("super-call to " + is_name + " has to be enhanced!");
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Generates the base call surrogate name for a given method name.
+ * @param method_name the name of the role method
+ * @param staticFlag
+ * @param roleClassName the name of the role method
+ * @return the base call surrogate name
+ */
+ private static String getBaseCallSurrogateName(String method_name, boolean staticFlag, String roleClassName) {
+ //JU: for static methods the role class name should be inserted
+ if(staticFlag) {
+ return OT_PREFIX+roleClassName+"$"+method_name+"$base";
+ }
+ return OT_PREFIX+method_name+"$base";
+ }
+
+ /**
+ * Reverts a method name to its original by returning the substring after the last '$'
+ * until the end.
+ * @param method_name method name to be adjusted
+ * @return the original method name
+ */
+ private static String revertToOriginalName(String method_name) {
+ int p = method_name.lastIndexOf('$');
+ return method_name.substring(p + 1);
+ }
+
+/*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.objectteams.otre.common.ObjectTeamsTransformation#doTransformCode(de.fub.bytecode.generic.ClassGen)
+ */
+ public void doTransformCode(ClassGen cg) {
+ // nothing to do
+ }
+}
diff --git a/othersrc/OTRE/src/org/eclipse/objectteams/otre/BaseMethodTransformation.java b/othersrc/OTRE/src/org/eclipse/objectteams/otre/BaseMethodTransformation.java
new file mode 100644
index 0000000..06878cb
--- /dev/null
+++ b/othersrc/OTRE/src/org/eclipse/objectteams/otre/BaseMethodTransformation.java
@@ -0,0 +1,1861 @@
+/**********************************************************************
+ * 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: BaseMethodTransformation.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 static org.eclipse.objectteams.otre.StaticSliceBaseTransformation._OT_ACTIVE_TEAMS;
+import static org.eclipse.objectteams.otre.StaticSliceBaseTransformation._OT_ACTIVE_TEAM_IDS;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.StringTokenizer;
+import java.util.Map.Entry;
+
+import org.eclipse.objectteams.otre.util.CallinBindingManager;
+import org.eclipse.objectteams.otre.util.DebugUtil;
+import org.eclipse.objectteams.otre.util.ListValueHashMap;
+import org.eclipse.objectteams.otre.util.MethodBinding;
+import org.eclipse.objectteams.otre.util.TeamIdDispenser;
+
+import de.fub.bytecode.Constants;
+import de.fub.bytecode.classfile.Field;
+import de.fub.bytecode.classfile.LineNumber;
+import de.fub.bytecode.classfile.LineNumberTable;
+import de.fub.bytecode.classfile.Method;
+import de.fub.bytecode.generic.AASTORE;
+import de.fub.bytecode.generic.ACONST_NULL;
+import de.fub.bytecode.generic.ALOAD;
+import de.fub.bytecode.generic.ANEWARRAY;
+import de.fub.bytecode.generic.ARRAYLENGTH;
+import de.fub.bytecode.generic.ATHROW;
+import de.fub.bytecode.generic.ArrayType;
+import de.fub.bytecode.generic.BasicType;
+import de.fub.bytecode.generic.BranchInstruction;
+import de.fub.bytecode.generic.ClassGen;
+import de.fub.bytecode.generic.ConstantPoolGen;
+import de.fub.bytecode.generic.DUP;
+import de.fub.bytecode.generic.DUP_X1;
+import de.fub.bytecode.generic.FieldGen;
+import de.fub.bytecode.generic.GOTO;
+import de.fub.bytecode.generic.IADD;
+import de.fub.bytecode.generic.ICONST;
+
+import de.fub.bytecode.generic.IFNE;
+import de.fub.bytecode.generic.IFNONNULL;
+import de.fub.bytecode.generic.IF_ICMPLT;
+import de.fub.bytecode.generic.IINC;
+import de.fub.bytecode.generic.INVOKESPECIAL;
+import de.fub.bytecode.generic.Instruction;
+import de.fub.bytecode.generic.InstructionConstants;
+import de.fub.bytecode.generic.InstructionFactory;
+import de.fub.bytecode.generic.InstructionHandle;
+import de.fub.bytecode.generic.InstructionList;
+import de.fub.bytecode.generic.InvokeInstruction;
+import de.fub.bytecode.generic.LDC;
+import de.fub.bytecode.generic.LocalVariableGen;
+import de.fub.bytecode.generic.MONITOREXIT;
+import de.fub.bytecode.generic.MethodGen;
+import de.fub.bytecode.generic.NOP;
+import de.fub.bytecode.generic.ObjectType;
+import de.fub.bytecode.generic.POP;
+import de.fub.bytecode.generic.PUSH;
+import de.fub.bytecode.generic.TABLESWITCH;
+import de.fub.bytecode.generic.Type;
+
+
+/**
+ * Insert dispatch code into base methods affected by callin bindings. <p>
+ * If a loaded class contains binding declarations (transmitted by attributes)
+ * these are stored for further determination of necessity for base-method-transforming.
+ * Classes for which a callin binding exists will be transformed:
+ * (base-class)methods <i>m()</i> which are changed by a callin will be copied to
+ * <tt>_OT$<i>m</i>$orig()</tt>.
+ * Hereafter the original method <i>m()</i> will be transformend depending on the
+ * callin-modifier:
+ * <ul>
+ * <li> replace: only the (role-)callin-method is called
+ * <li> after: first the original-method <tt>_OT$<i>m</i>$orig()</tt> is called and
+ * then the callin-method
+ * <li> before: first the the callin-method is called and then original-method
+ * <tt>_OT$<i>m</i>$orig()</tt>
+ * </ul>
+ *
+ * @version $Id: BaseMethodTransformation.java 23408 2010-02-03 18:07:35Z stephan $
+ * @author Christine Hundt
+ * @author Stephan Herrmann
+ */
+
+public class BaseMethodTransformation
+ extends ObjectTeamsTransformation
+{
+ // configurability for stepping behavior of the chaining wrapper:
+ private static boolean SHOW_ORIG_CALL = true;
+ private static boolean SHOW_RECURSIVE_CALL = true;
+ private static boolean SHOW_ROLE_CALL = true;
+ static {
+ String callinStepping = System.getProperty("ot.debug.callin.stepping");
+ if (callinStepping != null) {
+ SHOW_ORIG_CALL = SHOW_RECURSIVE_CALL = SHOW_ROLE_CALL = false;
+ StringTokenizer tokens = new StringTokenizer(callinStepping, ",");
+ while (tokens.hasMoreTokens()) {
+ String token = tokens.nextToken();
+ if ("orig".equals(token))
+ SHOW_ORIG_CALL = true;
+ else if ("recurse".equals(token))
+ SHOW_RECURSIVE_CALL = true;
+ else if ("role".equals(token))
+ SHOW_ROLE_CALL = true;
+ }
+ }
+ }
+
+ // method of o.o.Team:
+ private static final String IS_ACTIVE = "isActive"; //$NON-NLS-1$
+
+ private final static int NORESULT = -1;
+
+ // FIXME(SH): once we remove JMangler support, these maps can be reduced to their RHS because then we'll consistently have one transformer per class:
+ private HashMap /* class_name -> HashSet(method_name) */<String, HashSet<String>> transformableMethods = new HashMap<String, HashSet<String>>();
+ private HashMap /* class_name -> HashSet(method_name) */<String, HashSet<String>> overridableMethods = new HashMap<String, HashSet<String>>();
+
+ public boolean useReflection = false;
+
+ public BaseMethodTransformation(SharedState state) {
+ this(null, state);
+ }
+
+ public BaseMethodTransformation(ClassLoader loader, SharedState state) {
+ super(loader, state);
+ }
+ /**
+ * The code transformer only replaces the original code with
+ * the initial wrapper.
+ */
+ public void doTransformCode(ClassGen cg) {
+ factory = new InstructionFactory(cg);
+ ConstantPoolGen cpg = cg.getConstantPool();
+ String class_name = cg.getClassName();
+
+ Method[] methods = cg.getMethods();
+ for (int i=0; i<methods.length; i++) {
+ Method m = methods[i];
+ //if (m.isNative())
+ // continue;
+ if (m.isVolatile())
+ continue; // don't touch bridge methods
+
+ String method_name = m.getName();
+
+ if (CallinBindingManager.isBoundBaseClass(class_name)
+ && !CallinBindingManager.hasBoundBaseParent(class_name)
+ && method_name.equals(Constants.CONSTRUCTOR_NAME))
+ {
+ addToConstructor(m, getInitializedRoleSet(cg.getClassName(), false), cg, cpg);
+ continue;
+ }
+
+ String method_signature = m.getSignature();
+
+ if (state.interfaceTransformedClasses.contains(class_name)) {
+ HashSet<String> transformable = transformableMethods.get(class_name);
+ HashSet<String> overridable = overridableMethods.get(class_name);
+ if (transformable.contains(method_name + '.' + method_signature))
+ cg.replaceMethod(m, m = generateInitialWrapper(m, class_name, cg.getMajor(), cpg));
+ else if (overridable.contains(method_name + '.' + method_signature))
+ cg.replaceMethod(m, m = generateSuperCall(m, cg, cpg));
+
+ Method replacement = checkReplaceWickedSuper(class_name, m, cpg);
+ if (replacement != null)
+ cg.replaceMethod(m, replacement);
+ }
+ }
+ }
+
+ /*
+ * If a base method m1 has a super-call super.m2() and if that method m2 is callin-bound
+ * we currently bypass aspect dispatch to avoid infinite recursions.
+ */
+ private Method checkReplaceWickedSuper(String className, Method m, ConstantPoolGen cpg)
+ {
+ if (m.isAbstract() || m.isNative())
+ return null;
+ MethodGen mg = new MethodGen(m, className, cpg);
+ String method_name = m.getName();
+ InstructionHandle[] ihs = mg.getInstructionList().getInstructionHandles();
+ boolean found = false;
+ for (InstructionHandle ih : ihs) {
+ if (ih.getInstruction() instanceof INVOKESPECIAL) {
+ Instruction actInstruction = ih.getInstruction();
+ INVOKESPECIAL is = (INVOKESPECIAL)actInstruction;
+ String is_name = is.getName(cpg);
+ if ( !is_name.equals(method_name) // not same method
+ && !is_name.equals("<init>")) // not ctor call
+ {
+ String superClassName = is.getClassName(cpg);
+ if ( !superClassName.equals(className) // not private method of same class
+ && CallinBindingManager.isBoundBaseMethod( // target method is callin-affected
+ superClassName,
+ is_name,
+ is.getSignature(cpg)))
+ {
+ found = true;
+ if(logging) printLogMessage("wicked super-call to " + is_name //$NON-NLS-1$
+ + " has to be redirected to the orig-version!"); //$NON-NLS-1$
+ ih.setInstruction(factory.createInvoke(superClassName,
+ "_OT$"+is_name+"$orig",
+ is.getReturnType(cpg),
+ is.getArgumentTypes(cpg),
+ Constants.INVOKESPECIAL));
+ }
+ }
+ }
+ }
+ if (found)
+ return mg.getMethod();
+ return null;
+ }
+
+ /**
+ * Main entry for this transformer.
+ */
+ public void doTransformInterface(ClassEnhancer ce, ClassGen cg) {
+ String class_name = cg.getClassName();
+ //SourceMapGeneration sourceMapGen = new SourceMapGeneration(cg);
+
+ ConstantPoolGen cpg = cg.getConstantPool();
+ factory = new InstructionFactory(cg);
+ if (CallinBindingManager.isBoundBaseClass(class_name) && !cg.isInterface()) {
+ // TODO: where to add the role set infrastructure, if only an interface is bound? Implementing classes?
+ if (cg.containsField(OTConstants.ROLE_SET) == null && !CallinBindingManager.hasBoundBaseParent(class_name)) {
+ ce.addField(generateRoleSet(cpg, class_name), cg);
+ ce.addMethod(generateAddRole(cpg, class_name), cg);
+ ce.addMethod(generateRemoveRole(cpg, class_name), cg);
+ ce.addImplements(OTConstants.IBOUND_BASE, cg);
+ }
+ }
+
+ HashSet<String> transformedMethods = transformableMethods.get(class_name);
+ if (transformedMethods == null) {
+ transformedMethods = new HashSet<String>();
+ transformableMethods.put(class_name, transformedMethods);
+ }
+ HashSet<String> renamedMethods = overridableMethods.get(class_name);
+ if (renamedMethods == null) {
+ renamedMethods = new HashSet<String>();
+ overridableMethods.put(class_name, renamedMethods);
+ }
+
+ checkReadClassAttributes(ce, cg, class_name, cpg);
+
+ //JU: change the class modifier to 'public' if decapsulation required
+ if(CallinBindingManager.checkBaseClassModifierChange(class_name) && !cg.isPublic()) {
+ cg.setAccessFlags(makePublicFlags(cg.getAccessFlags()));
+ }
+
+ Collection<MethodBinding> inheritedBindings = CallinBindingManager.getInheritedCallinBindings(class_name);
+
+// if (inheritedSigns!=null && !inheritedSigns.isEmpty()) {
+// Iterator itx = inheritedSigns.iterator();
+// while (itx.hasNext()) {
+// System.err.print(class_name+" : ");
+// String[] next = (String[])itx.next();
+// System.err.println(next[0] +" " +next[1]) ;
+// }
+// }
+ /*
+ String[] interfaceNames = cg.getInterfaceNames();
+ Collection interfaceInheritedSigns = new LinkedList();
+ //System.err.println("searching inherited bindings for: "+class_name);
+ for (int i=0; i<interfaceNames.length;i++) {
+ if (!interfaceNames[i].equals(class_name))
+ interfaceInheritedSigns.addAll(CallinBindingManager.getInterfaceInheritedCallinBindings(interfaceNames[i]));
+ }*/
+ /*
+ if (!interfaceInheritedSigns.isEmpty()) {
+ System.err.println("BMT: searching inherited bindings for: "+class_name);
+ for (Iterator iterator = interfaceInheritedSigns.iterator(); iterator.hasNext();) {
+ String[] element = (String[]) iterator.next();
+ System.err.println(element[0]+element[1]);
+ }
+ }*/
+ //inheritedSigns.addAll(interfaceInheritedSigns);
+
+ boolean haveDirectCallin =
+ CallinBindingManager.isBoundBaseClass(class_name);
+ // IMPLICIT_INHERITANCE
+ if (inheritedBindings.size() == 0 && !haveDirectCallin /*&& interfaceInheritedSigns.size()==0*/) {
+ if(logging) printLogMessage("\nCallins: nothing to do for class " + class_name); //$NON-NLS-1$
+ return; // nothing to do
+ }
+ // if class is already transformed by this transformer
+ /*
+ if (interfaceTransformedClasses.contains(class_name))
+ continue;
+ */
+
+ if(cg.isInterface()) {
+ //CallinBindingManager.addBoundBaseInterface(class_name); // <- this is to late, implementing class may be loaded before!!
+ return; // No transfomations neccessary for interfaces.
+ }
+
+ if(logging) printLogMessage("\nCallin bindings may be changing class " //$NON-NLS-1$
+ + class_name + ':');
+
+ // A field to optimize class-literal in initial wrapper:
+ if (cg.getMajor() < 49) {// pre 1.5?
+ if (cg.containsField(OTConstants.SELF_CLASS) == null)
+ ce.addField(new FieldGen(Constants.ACC_PROTECTED|Constants.ACC_STATIC,
+ classType,
+ OTConstants.SELF_CLASS,
+ cpg)
+ .getField(),
+ cg);
+ }
+
+ Method[] methods = cg.getMethods();
+ for (int i=0; i<methods.length; i++) {
+ Method m = methods[i];
+ if (m.isVolatile()) // bridge method!
+ continue;
+ String method_name = m.getName();
+ String method_signature = m.getSignature();
+
+ Collection<MethodBinding> bindingsForMethod = null;
+ // IMPLICIT_INHERITANCE
+ if (haveDirectCallin)
+ bindingsForMethod = CallinBindingManager .
+ getBindingForBaseMethod(class_name, method_name, m.getSignature());
+
+ //JU: added the following statement to determine overridden static base methods
+ //Collection inheritedCallinBindings = CallinBindingManager.getInheritedCallinBindings(class_name);
+ //CH: removed it again, because it is the same as 'inheritedSigns'!
+
+ MethodGen mg = null;
+ int firstLine = STEP_OVER_LINENUMBER;
+ String original_signature = method_signature;
+ /*if (bindingsForMethod != null || containsSign(inheritedSigns, m)*/ /*|| containsSign(interfaceInheritedSigns, m)*/ //) {
+ MethodBinding match= matchingBinding(inheritedBindings, m, false);
+ if (bindingsForMethod != null || (match!= null && !m.isStatic() && !m.isPrivate())) {
+
+ mg = new MethodGen(m, class_name, cpg);
+ Method orig_method;
+
+ String name_orig = genOrigMethName(method_name);
+ if (cg.containsMethod(name_orig, m.getSignature())!=null) {
+ continue;// method was already copied to orig-version!
+ }
+
+ if (debugging)
+ firstLine = findFirstLineNumber(m);
+
+ mg.setName(name_orig);
+
+ // TODO(SH): store this match, or keep previous?
+ if (matchingBinding(inheritedBindings, m, true) != null) // this method was adapted in a super class
+ replaceSuperCalls(mg, method_name, cpg);
+
+ orig_method = mg.getMethod();
+ ce.addMethod(orig_method, cg);
+ if(logging) printLogMessage("Method " + method_name + " was backuped as " //$NON-NLS-1$ //$NON-NLS-2$
+ + name_orig + '.');
+
+ if (match == null || method_signature.equals(match.getBaseMethodSignature()))
+ renamedMethods.add(method_name+'.'+method_signature);
+ else // override with covariant return: at the VM-level this is a *new* method.
+ transformedMethods.add(method_name+'.'+method_signature);
+ }
+
+ /*if (bindingsForMethod != null || (containsSign(inheritedSigns,m) && m.isStatic())*/ /*|| containsSign(interfaceInheritedSigns, m)*/ //) {
+ //CH: changed 'inheritedCallinBindings' to 'inheritedSigns', because it was the same.
+ if (bindingsForMethod != null) {
+ //add method '_OT$<method_name>$chain' :
+ Method chain;
+ mg = getConcretMethodGen(m, class_name, cpg);
+ chain = generateChainingWrapper(mg, method_name,
+ original_signature/*method_signature*/, class_name, cpg, cg, firstLine);
+
+ if (cg.containsMethod(chain.getName(), chain.getSignature()) == null)
+ ce.addMethod(chain, cg);
+
+ transformedMethods.add(method_name + '.' + method_signature);
+ }
+ if (mg == null)
+ if (logging) printLogMessage("No method binding (direct or inherited) found for " //$NON-NLS-1$
+ + method_name);
+ }
+ state.interfaceTransformedClasses.add(class_name);
+ }
+
+ private int findFirstLineNumber(Method m) {
+ LineNumberTable lnt = m.getLineNumberTable();
+ if (lnt != null && lnt.getTableLength() > 0) {
+ LineNumber[] lineNumberTable = lnt.getLineNumberTable();
+ for (int i=0; i<lineNumberTable.length; i++) {
+ int lineNumber = lineNumberTable[i].getLineNumber();
+ if (lineNumber != OTConstants.STEP_OVER_LINENUMBER)
+ return lineNumber;
+ }
+ return lineNumberTable[0].getLineNumber();
+ }
+ return STEP_OVER_LINENUMBER; // make it a valid line number
+ }
+
+ /**
+ * "super"-calls in callin bound base methods have to be redirected to the _OT$...$orig version, if the
+ * super-method is bound (and thus renamed to _OT$..$orig) too.
+ *
+ * @param orig_method the copied method
+ * @param method_name the prior name of the copied method
+ * @param cpg the corresponding constang pool
+ */
+ private void replaceSuperCalls(MethodGen orig_method, String method_name, ConstantPoolGen cpg) {
+ // search for super calls:
+ InstructionList il = orig_method.getInstructionList();
+ InstructionHandle[] ihs = il.getInstructionHandles();
+ int actInstrIndex = 0;
+ while (actInstrIndex < ihs.length) {
+ if (ihs[actInstrIndex].getInstruction() instanceof INVOKESPECIAL) {
+ Instruction actInstruction = ihs[actInstrIndex].getInstruction();
+ INVOKESPECIAL is = (INVOKESPECIAL)actInstruction;
+ String is_name = is.getName(cpg);
+ if(is_name.equals(method_name)) {
+ String superClassName = is.getClassName(cpg);
+ if(logging) printLogMessage("super-call to " + is_name //$NON-NLS-1$
+ + " has to be redirected to the orig-version!"); //$NON-NLS-1$
+ // generate and set an instruction calling the orig-version of the super method:
+ InvokeInstruction superOrigCall = factory.createInvoke(superClassName,
+ orig_method.getName(),
+ orig_method.getReturnType(),
+ orig_method.getArgumentTypes(),
+ Constants.INVOKESPECIAL);
+ ihs[actInstrIndex].setInstruction(superOrigCall);
+ }
+ }
+ actInstrIndex++;
+ }
+ // redirect them ( change called method name to _OT$..$orig ) if super-method has been renamed:
+ // -->
+ }
+
+ /**
+ * Is method `m' contained in `baseMethodBindings'?
+ * @param nameSigns list of MethodBinding
+ * @param m
+ * @param strict if true covariance must not be considered
+ * @return the matching binding from baseMethodBindings or null.
+ */
+ static MethodBinding matchingBinding (Collection<MethodBinding> baseMethodBindings, Method m, boolean strict)
+ {
+ for (MethodBinding binding: baseMethodBindings)
+ if (binding.matchesMethod(m.getName(), m.getSignature(), strict))
+ return binding;
+
+ return null;
+ }
+
+ /**
+ * Get a MethodGen for `m'.
+ * If `m' is abstract setup a new concrete method.
+ */
+ static MethodGen getConcretMethodGen (Method m, String class_name, ConstantPoolGen cpg) {
+ MethodGen mg;
+ String signature = m.getSignature();
+ Type[] argTypes = Type.getArgumentTypes(signature);
+ if (m.isAbstract()) {
+ Type returnType = Type.getReturnType(signature);
+ InstructionList il = new InstructionList();
+ il.append(new NOP());
+ mg = new MethodGen(m.getAccessFlags()&~Constants.ACC_ABSTRACT,
+ returnType, argTypes,
+ null, // names are unknown
+ m.getName(), class_name,
+ il, cpg);
+ } else {
+ mg = wipeMethod(m, class_name, cpg);
+ }
+ if (debugging) {
+ mg.removeLocalVariables();
+ mg.removeLocalVariableTypes();
+ int slot = 0;
+ // create local variable table for "this" and arguments:
+ if (!m.isAbstract())
+ mg.addLocalVariable("this", new ObjectType(class_name), slot++, null, null);
+ for (int i=0; i<argTypes.length; i++)
+ mg.addLocalVariable("arg"+i, argTypes[i], slot++, null, null);
+ mg.setMaxLocals();
+ }
+ return mg;
+ }
+
+ /**
+ * Generate the initial wrapper for the passed mehtod.
+ * It binds callin dispatch to Team-unaware client code.
+ * @param m the original method
+ * @param class_name the name of the appropriate class
+ * @param major
+ * @param cpg the ConstantPoolGen of the class
+ * @return the generated method
+ */
+ private Method generateInitialWrapper(Method m,
+ String class_name,
+ int major,
+ ConstantPoolGen cpg)
+ {
+ MethodGen mg = getConcretMethodGen(m, class_name, cpg);
+
+ String method_name = m.getName();
+ Type returnType = mg.getReturnType();
+ Type chainReturnType = object;
+ Type[] argTypes = mg.getArgumentTypes();
+
+ String name_chain = genChainMethName(method_name);
+
+ InstructionList il = mg.getInstructionList();
+
+ InstructionHandle startSynchronized;
+ InstructionHandle chainCall;
+ int monitor;
+ // start generating
+ {
+ LocalVariableGen lg; // used for several local variables
+
+ // Team[] _OT$teams;
+ int teams;
+ lg = mg.addLocalVariable(TEAMS, teamArray, null, null);
+ teams = lg.getIndex();
+
+ // synchronized (TopMostBoundBaseClass.class) {
+ Pair<Integer,InstructionHandle> monitorResult = addClassMonitorEnter(mg, il, CallinBindingManager.getTopmostBoundBase(class_name), major, cpg);
+ monitor = monitorResult.first;
+ if (debugging)
+ // no natural lines in this method: step-over until chain call, which has step-into: debugging => addLineNumber
+ mg.addLineNumber(monitorResult.second, STEP_OVER_LINENUMBER);
+
+ // _OT$teams= new Teams[_OT$activeTeams.length];
+ startSynchronized= // begin area protected by exception handler
+ il.append(factory.createFieldAccess(class_name, _OT_ACTIVE_TEAMS, teamArray, Constants.GETSTATIC));
+ il.append(InstructionConstants.ARRAYLENGTH);
+ il.append((Instruction)factory.createNewArray(teamType, (short) 1));
+ il.append(InstructionFactory.createStore(Type.OBJECT, teams));
+
+ // _OT$teamIDs=new int[_OT$activeTeamIDs.length];
+ int teamIDs;
+ lg = mg.addLocalVariable(TEAMIDS, intArray, null, null);
+ teamIDs = lg.getIndex();
+ il.append(factory.createFieldAccess(class_name, _OT_ACTIVE_TEAM_IDS, intArray, Constants.GETSTATIC));
+ il.append(InstructionConstants.ARRAYLENGTH);
+ il.append((Instruction)factory.createNewArray(Type.INT, (short) 1));
+ il.append(InstructionFactory.createStore(Type.OBJECT, teamIDs));
+
+ // for (int i=0; i<_OT$activeTeams.length; ...
+ int for_index;
+ lg = mg.addLocalVariable("i", Type.INT, null, null); //$NON-NLS-1$
+ for_index = lg.getIndex();
+ il.append(new PUSH(cpg, 0));
+ il.append(InstructionFactory.createStore(Type.INT, for_index));
+ InstructionHandle for_start =
+ il.append(InstructionFactory.createLoad(Type.INT, for_index));
+ il.append(factory.createFieldAccess(class_name, _OT_ACTIVE_TEAMS, teamArray, Constants.GETSTATIC));
+ il.append(InstructionConstants.ARRAYLENGTH);
+ BranchInstruction if_loop_finished =
+ InstructionFactory.createBranchInstruction(Constants.IF_ICMPGE, null);
+ il.append(if_loop_finished);
+
+ // if (!_OT$activeTeams[i].isActive()) {
+ il.append(factory.createFieldAccess(class_name, _OT_ACTIVE_TEAMS, teamArray, Constants.GETSTATIC));
+ il.append(InstructionFactory.createLoad(Type.INT, for_index));
+ il.append(InstructionConstants.AALOAD);
+ il.append(factory.createInvoke(OTConstants.teamName, IS_ACTIVE, Type.BOOLEAN, Type.NO_ARGS, Constants.INVOKEINTERFACE));
+ BranchInstruction if_team_isactive =
+ InstructionFactory.createBranchInstruction(Constants.IFNE, null);
+ il.append(if_team_isactive);
+
+ // invalidate activation of current team:
+ // _OT$teams[i]= null;
+ il.append(InstructionFactory.createLoad(Type.OBJECT, teams));
+ il.append(InstructionFactory.createLoad(Type.INT, for_index));
+ il.append(InstructionConstants.ACONST_NULL);
+ il.append(InstructionConstants.AASTORE);
+
+ // _OT$teamIDs[i]= -1;
+ il.append(InstructionFactory.createLoad(Type.OBJECT, teamIDs));
+ il.append(InstructionFactory.createLoad(Type.INT, for_index));
+ il.append(new PUSH(cpg, -1));
+ il.append(InstructionConstants.IASTORE);
+ BranchInstruction goto_continue =
+ InstructionFactory.createBranchInstruction(Constants.GOTO, null);
+ il.append(goto_continue);
+
+ // } else { adopt activation of current team:
+ // _OT$teams[i]= _OT$activeTeams[i];
+ InstructionHandle adopt_activation =
+ il.append(InstructionFactory.createLoad(Type.OBJECT, teams));
+ il.append(InstructionFactory.createLoad(Type.INT, for_index));
+ il.append(factory.createFieldAccess(class_name, _OT_ACTIVE_TEAMS, teamArray, Constants.GETSTATIC));
+ il.append(InstructionFactory.createLoad(Type.INT, for_index));
+ il.append(InstructionConstants.AALOAD);
+ il.append(InstructionConstants.AASTORE);
+
+ // _OT$teamIDs[i]= _OT$activeTeamIDs[i];
+ il.append(InstructionFactory.createLoad(Type.OBJECT, teamIDs));
+ il.append(InstructionFactory.createLoad(Type.INT, for_index));
+ il.append(factory.createFieldAccess(class_name, _OT_ACTIVE_TEAM_IDS, intArray, Constants.GETSTATIC));
+ il.append(InstructionFactory.createLoad(Type.INT, for_index));
+ il.append(InstructionConstants.IALOAD);
+ il.append(InstructionConstants.IASTORE);
+
+ // closing the above for: i++ and jump back:
+ InstructionHandle do_continue =
+ il.append(new IINC(for_index, 1));
+ il.append(InstructionFactory.createBranchInstruction(Constants.GOTO, for_start));
+
+ // link jump instructions to their targets:
+ InstructionHandle loop_finished = il.append(new NOP()); // synthetic jump target
+ if_loop_finished.setTarget(loop_finished);
+ if_team_isactive.setTarget(adopt_activation);
+ goto_continue.setTarget(do_continue);
+
+ // No more access to array fields, release monitor:
+ il.append(InstructionFactory.createLoad(Type.OBJECT, monitor));
+ il.append(new MONITOREXIT());
+
+ // load special arguments:
+ if(!m.isStatic()) { // "this" cannot be accessed by static methods
+ chainCall= il.append(InstructionFactory.createThis()); // this
+ } else {
+ chainCall= il.append(new NOP());
+ }
+
+ if (debugging)
+ mg.addLineNumber(chainCall, STEP_INTO_LINENUMBER);
+ // ih now points to end of area protected by exception handler
+
+ il.append(InstructionFactory.createLoad(teamArray, teams)); // _OT$teams
+ il.append(InstructionFactory.createLoad(intArray, teamIDs)); // _OT$teamIDs
+ il.append(new ICONST(0)); // _OT$idx = 0
+ il.append(new ICONST(0)); // _OT$bindIdx = 0
+ il.append(new ICONST(-1)); // _OT$baseMethTag is unused here
+ il.append(new ACONST_NULL()); // _OT$unusedArgs = null
+ }
+
+
+ // load regular arguments:
+ int index = m.isStatic()?0:1;
+ // chaining wrapper is always public, so never user INVOKESPECIAL:
+ short invocationKind = m.isStatic()?Constants.INVOKESTATIC:Constants.INVOKEVIRTUAL;
+
+ for (int i=0; i<argTypes.length; i++) {
+ il.append(InstructionFactory.createLoad(argTypes[i],index));
+ index += argTypes[i].getSize();
+ }
+ //
+ il.append(factory.createInvoke(class_name, name_chain,
+ chainReturnType,
+ enhanceArgumentTypes(argTypes),
+ invocationKind));
+ // generated invoke: _OT$<method_name>$chain (a1,.. aN)
+
+
+ adjustValue(il, null, chainReturnType, returnType);
+ il.append(InstructionFactory.createReturn(returnType));
+
+ // handler for exception within synchronized:
+ LocalVariableGen ex= mg.addLocalVariable("exceptionInSynchronized", Type.THROWABLE, il.getEnd(), null); //$NON-NLS-1$
+ InstructionHandle handler=
+ il.append(InstructionFactory.createStore(Type.THROWABLE, ex.getIndex()));
+ il.append(InstructionFactory.createLoad(Type.OBJECT, monitor));
+ il.append(new MONITOREXIT());
+ il.append(InstructionFactory.createLoad(Type.THROWABLE, ex.getIndex()));
+ il.append(new ATHROW());
+ mg.addExceptionHandler(startSynchronized, chainCall, handler, Type.THROWABLE);
+
+ // tidy:
+ mg.setMaxStack();
+ mg.setMaxLocals();
+ Method generatedMethod = mg.getMethod();
+ il.dispose();
+ return generatedMethod;
+ }
+
+ /**
+ * Generate a version of the passed method which only calls its super method
+ * (which will eventually call an initial-wrapper in a directly bound class).
+ * @param m the original method
+ * @param cg the ClassGen of the appropriate class
+ * @param cpg the ConstantPoolGen of the class
+ * @return the generated method
+ */
+ Method generateSuperCall (Method m,
+ ClassGen cg,
+ ConstantPoolGen cpg)
+ {
+ short invocationKind = m.isStatic() ? Constants.INVOKESTATIC : Constants.INVOKESPECIAL;
+ MethodGen mg = getConcretMethodGen(m, cg.getClassName(), cpg);
+
+ String method_name = m.getName();
+ Type returnType = mg.getReturnType();
+ Type[] argTypes = mg.getArgumentTypes();
+ InstructionList il = mg.getInstructionList();
+
+ if(logging) printLogMessage("\nReplacing with call to super: " + method_name); //$NON-NLS-1$
+ // start generating
+ if(!m.isStatic()){ //JU
+ il.append(InstructionFactory.createThis());
+ }
+ 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(), method_name,
+ returnType, argTypes,
+ invocationKind));
+ il.append(InstructionFactory.createReturn(returnType));
+ // generated invoke: return super.<method_name> (a1,.. aN)
+
+ // tidy:
+ mg.setMaxStack();
+ mg.setMaxLocals();
+ Method generatedMethod = mg.getMethod();
+ il.dispose();
+ return generatedMethod;
+ }
+
+
+ /**
+ * Generate a chaining wrapper for the original method described by the passed arguments.
+ * This includes dispatch code and the termination condition for the recursion.
+ * @param mg the MethodGen of the original method
+ * @param method_name the name of the original method
+ * @param method_signature the signature of the original method
+ * @param class_name the name of the appropriate class
+ * @param cpg the ConstantPoolGen of the class
+ * @param cg the ClassGen of the class
+ * @param firstLine the first real source line of this method
+ * @return
+ */
+ Method generateChainingWrapper(MethodGen mg,
+ String method_name,
+ String method_signature,
+ String class_name,
+ ConstantPoolGen cpg,
+ ClassGen cg,
+ int firstLine)
+ {
+ Type origReturnType = mg.getReturnType();
+ Type[] argumentTypes = mg.getArgumentTypes();
+ String[] argumentNames = mg.getArgumentNames();
+ Type[] enhancedArgumentTypes = enhanceArgumentTypes(argumentTypes);
+ String[] enhancedArgumentNames = enhanceArgumentNames(argumentNames);
+ Type enhancedReturnType = object; // ALWAYS!
+
+ InstructionList il = new InstructionList();
+
+ // the chaining wrapper has to be 'public' because it will be called by base calls:
+ int accessFlags = makePublicFlags(mg.getAccessFlags());
+
+ MethodGen chainMethod = new MethodGen(accessFlags,
+ enhancedReturnType,
+ enhancedArgumentTypes,
+ enhancedArgumentNames,
+ genChainMethName(method_name),
+ class_name,
+ il, cpg);
+
+ // All chaining calls return an Object.
+ // Need to store this in a local variable to keep the stack
+ // balanced, because each section (before, replace, after)
+ // is guarded by its own exception handler, and they don't
+ // like pending objects on the stack.
+ InstructionHandle ih;
+ int result, ot_team;
+ {
+ LocalVariableGen lg =
+ chainMethod.addLocalVariable("_OT$result", enhancedReturnType, //$NON-NLS-1$
+ null, null);
+ result = lg.getIndex();
+ ih = il.append(InstructionFactory.createNull(enhancedReturnType));
+ if (debugging)
+ chainMethod.addLineNumber(ih, STEP_OVER_LINENUMBER);
+ lg.setStart(il.append(InstructionFactory.createStore(enhancedReturnType, result)));
+ // generated: RType _OT$result = null;
+
+ lg = chainMethod.addLocalVariable("_OT$team", teamType, null, null); //$NON-NLS-1$
+ ot_team = lg.getIndex();
+ // generated: Team _OT$team;
+ }
+
+ int indexOffset = chainMethod.isStatic() ? -1 : 0; // argument indizes are decremented for static methods,
+ // because of the missing 'this'
+ short invocationKind = getInvocationType(mg);
+
+ il.append(InstructionFactory.createLoad(Type.INT, IDX_ARG + indexOffset));
+ il.append(InstructionFactory.createLoad(teamArray, TEAMS_ARG + indexOffset));
+ il.append(new ARRAYLENGTH());
+ IF_ICMPLT recursionNotYetTerminated = new IF_ICMPLT(null);
+ il.append(recursionNotYetTerminated);
+ // generated: if (_OT$teams.length < _OT$idx) {
+
+
+ // load arguments:
+ if (!chainMethod.isStatic()) {
+ ih = il.append(InstructionFactory.createThis());
+ } else {
+ ih = il.append(new NOP());
+ }
+ if (debugging)
+ chainMethod.addLineNumber(ih, SHOW_ORIG_CALL ? firstLine : STEP_INTO_LINENUMBER); // show orig call at method header ("dispatching")
+
+ int index = EXTRA_ARGS + 1;
+ for (int i = 0; i < argumentTypes.length; i++) {
+ il.append(InstructionFactory.createLoad(argumentTypes[i], index + indexOffset));
+ index += argumentTypes[i].getSize();
+ }
+ //
+ il.append(factory.createInvoke(class_name, genOrigMethName(method_name),
+ origReturnType, argumentTypes,
+ invocationKind));
+ // generated: this._OT$<method_name>$orig (a1,.., aN) for nonstatic case
+ // _OT$<method_name>$orig (a1,.., aN) for static case
+
+ if (debugging)
+ chainMethod.addLineNumber(il.append(new NOP()), STEP_OVER_LINENUMBER);
+
+ adjustValue(il, null, origReturnType, enhancedReturnType);
+ il.append(InstructionFactory.createReturn(enhancedReturnType));
+ // generated: return _OT$result;
+
+ ih = il.append(new NOP());
+ recursionNotYetTerminated.setTarget(ih);
+ // generated: ; (end of the if part)
+
+ il.append(InstructionFactory.createLoad(teamArray, TEAMS_ARG + indexOffset));
+ il.append(InstructionFactory.createLoad(Type.INT, IDX_ARG + indexOffset));
+ il.append(InstructionFactory.createArrayLoad(teamType));
+ il.append(InstructionFactory.createStore(teamType, ot_team));
+ // generated: _OT$team = _OT$teams[_OT$idx];
+
+ // ---------------------------------------------
+ createDispatchCode(chainMethod, il,
+ class_name, method_name,
+ method_signature, result, ot_team, cg, firstLine);
+ // ---------------------------------------------
+
+ ih = il.append(InstructionFactory.createLoad(enhancedReturnType, result));
+ il.append(InstructionFactory.createReturn(enhancedReturnType));
+ // generated: return _OT$result;
+ if (debugging)
+ chainMethod.addLineNumber(ih, STEP_OVER_LINENUMBER);
+
+ // tidy:
+ chainMethod.removeNOPs();
+ try { // [SH]: overcautious: I once saw this CCE with no clue, why it happened :(
+ chainMethod.setMaxStack();
+ } catch (ClassCastException cce) {
+ System.err.println(chainMethod);
+ cce.printStackTrace();
+ }
+ chainMethod.setMaxLocals();
+ //chainMethod.removeNOPs();
+ Method generated = chainMethod.getMethod();
+ il.dispose();
+ return generated;
+ }
+
+ private short getInvocationType(MethodGen chainMethod) {
+ if (chainMethod.isStatic())
+ return Constants.INVOKESTATIC;
+ if (chainMethod.isPrivate())
+ return Constants.INVOKESPECIAL;
+ else
+ return Constants.INVOKEVIRTUAL;
+ }
+
+ /**
+ * @param i
+ * @return
+ */
+ private static int makePublicFlags(int flags) {
+ if ((flags & Constants.ACC_PUBLIC) != 0) {
+ return flags;
+ }
+ if ((flags & Constants.ACC_PRIVATE) != 0) {
+ flags &= ~Constants.ACC_PRIVATE;
+ } else if ((flags & Constants.ACC_PROTECTED) != 0) {
+ flags &= ~Constants.ACC_PROTECTED;
+ }
+ flags |= Constants.ACC_PUBLIC;
+ return flags;
+ }
+
+ /**
+ * Generate the dispatch code by which a chaining wrapper invokes the
+ * callin method(s).
+ * This consists of three switch blocks: before, replace, after.
+ * @param chainMethod the chaining wrapper method
+ * @param il the InstructionList of the chaining wrapper
+ * @param class_name the name of the appropriate class
+ * @param method_name the name of the original method
+ * @param method_signature the signature of the original method
+ * @param result the index of the '_OT$result' variable
+ * @param ot_team the index of the variable containing the team currently processed by the chaining wrapper
+ * @param cg the ClassGen of the appropriate class
+ * @param firstLine the first real source line of this method
+ */
+ void createDispatchCode(MethodGen chainMethod, InstructionList il,
+ String class_name, String method_name,
+ String method_signature, int result, int ot_team, ClassGen cg, int firstLine)
+ {
+
+ // get bindings for actually modified methods and sort them by callin-modifier:
+ // modifier -> ArrayList<MethodBinding>
+ HashMap<String, ArrayList<MethodBinding>> sortedMethodBindings = new HashMap<String, ArrayList<MethodBinding>>();
+ Collection<MethodBinding> callinsForMethod;
+ callinsForMethod = CallinBindingManager.getBindingForBaseMethod(class_name,
+ method_name, method_signature);
+ //System.err.println(class_name +" : "+callinsForMethod);
+ List<MethodBinding> inheritedMethodBindings = CallinBindingManager.getInheritedBaseMethodBindings(class_name, method_name, method_signature);
+ //System.err.println(inheritedMethodBindings);
+
+ //--------------------------------------------------------------------------------------------
+ //JU: initialize callinsForMethod for overridden static base methods (begin)
+// if(chainMethod.isStatic()){
+// if(callinsForMethod == null) {
+// callinsForMethod = new LinkedList();
+// }
+//
+// Collection classesDefBindingsToStaticMethods = CallinBindingManager.getInheritedCallinBindingsForStaticMethods(class_name, method_name, method_signature);
+// Iterator classesIt = classesDefBindingsToStaticMethods.iterator();
+// while(classesIt.hasNext()){
+// String superClassName = (String) classesIt.next();
+// Collection callinsFromSuperClasses = CallinBindingManager.getBindingForBaseMethod(superClassName, method_name, method_signature);
+// callinsForMethod.addAll(callinsFromSuperClasses);
+// }
+// }
+ //JU: (end)
+ //----------------------------------------------------------------------------------------------
+ if (!chainMethod.isStatic())
+ callinsForMethod.addAll(inheritedMethodBindings);
+
+ /*
+ String[] interfaceNames = cg.getInterfaceNames();
+ Collection interfaceInheritedMethodBindings = new LinkedList();
+ for (int i=0; i<interfaceNames.length;i++) {
+ if (!interfaceNames[i].equals(class_name))
+ interfaceInheritedMethodBindings.addAll(
+ CallinBindingManager.getInterfaceInheritedMethodBindings(method_name,
+ method_signature,
+ interfaceNames[i]));
+ }
+
+ if (callinsForMethod == null)
+ callinsForMethod = new LinkedList();
+
+ callinsForMethod.addAll(interfaceInheritedMethodBindings);
+ */
+ ListValueHashMap<MethodBinding> beforeBindings = new ListValueHashMap<MethodBinding>();
+ ListValueHashMap<MethodBinding> replaceBindings = new ListValueHashMap<MethodBinding>();
+ ListValueHashMap<MethodBinding> afterBindings = new ListValueHashMap<MethodBinding>();
+
+ Iterator<MethodBinding> it = callinsForMethod.iterator();
+ while (it.hasNext()) {
+ MethodBinding methodBinding = it.next();
+ //sourceMapGen.addSourceMapInfo(methodBinding);
+ String modifier = methodBinding.getModifier();
+ ArrayList<MethodBinding> bindings = sortedMethodBindings.get(modifier);
+ if (bindings == null) {
+ bindings = new ArrayList<MethodBinding>();
+ sortedMethodBindings.put(modifier, bindings);
+ }
+ bindings.add(methodBinding);
+ // ----> added for predecedence purpose:
+ String teamName = methodBinding.getTeamClassName();
+ if (modifier.equals("before")) { //$NON-NLS-1$
+ beforeBindings.put(teamName, methodBinding);
+ } else if (modifier.equals("replace")) { //$NON-NLS-1$
+ replaceBindings.put(teamName, methodBinding);
+ } else if (modifier.equals("after")) { //$NON-NLS-1$
+ afterBindings.put(teamName, methodBinding);
+ }
+ // <---
+ }
+
+ // if any team has multiple bindings, we need to insert additional checks to avoid duplicate
+ // invocation of before/after causes during recursion.
+ boolean useBindingIdx = false;
+ for (LinkedList<MethodBinding> perTeamMethods : replaceBindings.valueSet())
+ if (perTeamMethods.size() > 1) {
+ useBindingIdx = true;
+ break;
+ }
+
+ /****************************************************************************/
+ // before callin :
+ if (sortedMethodBindings.containsKey("before")) { //$NON-NLS-1$
+ if(logging) printLogMessage("before bindings will be applied..."); //$NON-NLS-1$
+ il.append(createSwitch(
+ beforeBindings,
+ chainMethod, ot_team,
+ NORESULT, firstLine, cg.getMajor(), useBindingIdx));
+ if(logging) printLogMessage("before bindings: " //$NON-NLS-1$
+ + sortedMethodBindings.get("before")); //$NON-NLS-1$
+ }
+ /****************************************************************************/
+ // replacement callin or direct recursion :
+ if (sortedMethodBindings.containsKey("replace")) { //$NON-NLS-1$
+ if(logging) printLogMessage("recursive call and replace bindings will be applied..."); //$NON-NLS-1$
+ il.append(createSwitch(
+ replaceBindings,
+ chainMethod, ot_team,
+ result, firstLine, cg.getMajor(), useBindingIdx));
+ if(logging) printLogMessage("replace bindings: " //$NON-NLS-1$
+ + sortedMethodBindings.get("replace")); //$NON-NLS-1$
+ } else {
+ if(logging) printLogMessage("recursive chain-method call will be done..."); //$NON-NLS-1$
+ // recursive call:
+
+ createRecursiveCall(il, chainMethod, result, 1, 0, method_name, method_signature, firstLine);
+ }
+ /****************************************************************************/
+ // after callin :
+ if (sortedMethodBindings.containsKey("after")) { //$NON-NLS-1$
+ if(logging) printLogMessage("after bindings will be applied..."); //$NON-NLS-1$
+ il.append(createSwitch(
+ afterBindings,
+ chainMethod, ot_team,
+ /*NORESULT*/result, firstLine, cg.getMajor(), useBindingIdx));
+ if(logging) printLogMessage("after bindings: " //$NON-NLS-1$
+ + sortedMethodBindings.get("after")); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * Create a switch statement which contains one case for each MethodBinding
+ * in a given list.
+ * The switch block is furthermore wrapped in a try-catch block.
+ * Herein all {@link org.objectteams.LiftingVetoException LiftingVetoException}
+ * are caught, and possibly reported (if Dot.log.lift ist set).
+ * @param methodBindings hash map of team names to 'MethodBinding' lists
+ * @param mg method being generated.
+ * @param ot_team index of local variable <tt>_OT$team</tt>
+ * @param ot_result index of local variable <tt>_OT$result</tt>
+ */
+ private InstructionList createSwitch(ListValueHashMap<MethodBinding> methodBindings, MethodGen mg,
+ int ot_team, int ot_result,
+ int firstLine,
+ int major,
+ boolean useBindingIdx)
+ {
+ InstructionList il = new InstructionList();
+
+ boolean handlesReplacement = false;
+
+ int indexOffset = mg.isStatic()?-1:0; // argument indizes are decremented for static methods,
+ // because of the missing 'this'
+
+ // load value to be switched:
+ il.append(InstructionFactory.createLoad(intArray, TEAMIDS_ARG+indexOffset));
+ il.append(InstructionFactory.createLoad(Type.INT, IDX_ARG+indexOffset));
+ InstructionHandle switchStart = il.append(InstructionFactory.createArrayLoad(Type.INT));
+ // generated: _OT$teamIDs[_OT$idx]
+
+ int numberOfCases = methodBindings.size();
+
+ // one break for each case clause
+ GOTO[] breaks = new GOTO[numberOfCases];
+ for (int i = 0; i < numberOfCases; i++)
+ breaks[i] = new GOTO(null);
+
+ int[] matches = new int[numberOfCases];
+ InstructionHandle[] targets = new InstructionHandle[numberOfCases];
+
+ int caseCounter = 0;
+
+ List<MethodBinding> methodBindingsForTeam = null;
+ MethodBinding mb = null;
+ Iterator <Entry<String, LinkedList<MethodBinding>>> teamIterator = methodBindings.entrySet().iterator();
+ while (teamIterator.hasNext()) {
+ Entry<String, LinkedList<MethodBinding>> entry = teamIterator.next();
+ String teamName = entry.getKey();
+ methodBindingsForTeam = entry.getValue();
+ //System.out.println(methodBindings.get(teamName));
+
+ /*MethodBinding*/ mb = methodBindingsForTeam.get(0);
+
+ matches[caseCounter] = TeamIdDispenser.getTeamId(teamName);
+ InstructionHandle nextBranch = il.append(new NOP());
+
+ // generate (_OT$teamID == teamId) branch here:
+
+ // ========== create Cases: ==========
+ if (mb.isReplace()) { // distinct treatment of replacement:
+ handlesReplacement = true;
+ createReplaceCase(mg, il,
+ teamName, methodBindingsForTeam,
+ ot_result, ot_team, major, firstLine);
+ } else { // before or after callin:
+ BranchInstruction ifBindingIdx = null;
+ if (useBindingIdx) {
+ // only if bindingIdx == 0
+ il.append(InstructionFactory.createLoad(Type.INT, BIND_IDX_ARG+indexOffset));
+ ifBindingIdx= new IFNE(null);
+ il.append(ifBindingIdx);
+ }
+ createBeforeAfterCase(mg, il, teamName,
+ methodBindingsForTeam, ot_result, ot_team, major, firstLine);
+ if (useBindingIdx) {
+ ifBindingIdx.setTarget(il.append(new NOP()));
+ }
+ }
+
+ // ===================================
+
+ targets[caseCounter] = nextBranch;
+ /*InstructionHandle break_instr =*/ il.append(breaks[caseCounter]);
+ // generated: break;
+
+ caseCounter++;
+ } // end of while
+
+ // generate default branch here:
+ InstructionHandle defaultBranch = il.append(new NOP());
+ if (handlesReplacement)
+ createRecursiveCall(il, mg, ot_result, 1, 0, mb.getBaseMethodName(), mb.getBaseMethodSignature(), firstLine);
+
+ InstructionHandle afterSwitch = il.append(new NOP()); // all breaks point here.
+
+ // ===== assemble the switch ====
+ il.append(switchStart,
+ createLookupSwitch(matches, targets, breaks,
+ defaultBranch, afterSwitch)
+ );
+ // ==============================
+
+ // wrap everything in a try {} catch (LiftingVetoException e) {..}
+ InstructionHandle endTry = il.getEnd();
+
+ GOTO skipHdlr = null;
+ skipHdlr = new GOTO(null);
+ il.append(skipHdlr);
+ // generated: goto normal exit
+
+ InstructionHandle hdlr = il.append(new NOP());
+ il.append(DebugUtil.createReportExc(factory));
+
+ // catch: proceed with recursion if caught in a replace call
+ if (handlesReplacement)
+ createRecursiveCall(il, mg, ot_result, 1, 0, mb.getBaseMethodName(), mb.getBaseMethodSignature(), firstLine);
+
+ mg.addExceptionHandler(il.getStart(), endTry, hdlr, liftingVeto);
+
+ InstructionHandle nop = il.append(new NOP());
+ skipHdlr.setTarget(nop);
+
+ return il;
+ }
+
+ /** Create the recursice call of this chaining method.
+ * @param il insert the call into this list.
+ * @param mg this chaining method
+ * @param ot_result stack index of the _OT$result variable or NORESULT.
+ * @param idx_offset TODO
+ * @param bindIdx_offset TODO
+ * @param methodName TODO
+ * @param methodSignature TODO
+ */
+ void createRecursiveCall (InstructionList il,
+ MethodGen mg,
+ int ot_result, int idx_offset, int bindIdx_offset, String methodName, String methodSignature, int firstLine)
+ {
+ InstructionHandle ih = !mg.isStatic()
+ ? il.append(InstructionFactory.createThis())
+ : il.append(new NOP());
+ if (debugging)
+ mg.addLineNumber(ih, SHOW_RECURSIVE_CALL ? firstLine : STEP_INTO_LINENUMBER); // show recursive call at method header ("dispatching")
+
+ Type[] argTypes = mg.getArgumentTypes();
+ Type returnType = mg.getReturnType();
+ short invocationKind = getInvocationType(mg);
+
+ // arguments: no adjustment except idx++.
+ int index = 1;
+ int indexOffset = mg.isStatic()?-1:0; // argument indizes are decremented for static methods,
+ // because of the missing 'this'
+ for (int i=0; i<argTypes.length; i++) {
+ il.append(InstructionFactory.createLoad(argTypes[i], index+indexOffset));
+ if (index == OTConstants.IDX_ARG && idx_offset != 0) { // _OT$idx has to be incremented (adding idx_offset)
+ il.append(new ICONST(idx_offset));
+ il.append(new IADD());
+ } else if (index == OTConstants.BIND_IDX_ARG) { // _OT$bindIdx has to be incremented (adding bindIdx_offset)
+ if (bindIdx_offset == 0) { // bindArg argument has to be set to '0'
+ il.append(new POP()); // remove loaded _OT$bindIdx
+ il.append(new ICONST(0)); // replace it by '0'
+ } else {
+ il.append(new ICONST(bindIdx_offset));
+ il.append(new IADD());
+ }
+ }
+ index += argTypes[i].getSize();
+ }
+ il.append(factory.createInvoke(mg.getClassName(), mg.getName(),
+ returnType, argTypes,
+ invocationKind));
+
+ il.append(InstructionFactory.createStore(returnType, ot_result));
+
+ // _OT$result = _OT$<method_name>$chain(_OT$teams, _OT$teamIDs, _OT$idx+1,
+ // a1, .., aN);
+ if (debugging)
+ mg.addLineNumber(il.append(new NOP()), STEP_OVER_LINENUMBER);
+ }
+
+
+ /**
+ * Create a block for a before or after callin as a case with a surrounding switch.
+ * @param mg TODO
+ * @param il InstructionList being assembled.
+ * @param connectorClassName name of a Team which has a callin to this method.
+ * @param mbList MethodBindings describing the callins.
+ * @param ot_result index of local variable <tt>_OT$result</tt>.
+ * @param ot_team index of local variable <tt>_OT$team</tt>.l
+ * @param major
+ * @param firstLine the first real source line of this method
+ */
+ void createBeforeAfterCase(MethodGen mg,
+ InstructionList il, String connectorClassName,
+ List<MethodBinding> mbList, int ot_result, int ot_team,
+ int major, int firstLine)
+ {
+
+ MethodBinding mb = mbList.get(0);
+ ConstantPoolGen cpg = mg.getConstantPool();
+
+ mbList = CallinBindingManager.sortMethodBindings(mbList, connectorClassName);
+
+ Iterator<MethodBinding> it = mbList.iterator();
+ while (it.hasNext()) {
+ /*MethodBinding nextMethodBinding*/mb = it.next();
+
+ String baseMethodSignature = mb.getBaseMethodSignature();
+ Type[] baseArgTypes = Type.getArgumentTypes(baseMethodSignature);
+ Type baseReturnType = Type.getReturnType(baseMethodSignature);
+
+ Type[] wrapperArgTypes = Type.getArgumentTypes(mb.getWrapperSignature());
+ int argsLen = wrapperArgTypes.length - 1; // don't count base arg.
+
+ il.append(InstructionFactory.createLoad(teamType, ot_team));
+
+ int packedArgPos = 0;
+ InstructionHandle argArray = null;
+ if (useReflection) {
+ il.append(factory.createInvoke("java.lang.Object", "getClass", classType, new Type[0], Constants.INVOKEVIRTUAL));
+ il.append(new LDC(cpg.addString(mb.getWrapperName())));
+ pushTypeArray(il, wrapperArgTypes, major, cpg);
+ il.append(factory.createInvoke("java.lang.Class", "getMethod", methodType, OTConstants.getMethodSignature, Constants.INVOKEVIRTUAL));
+
+ il.append(InstructionFactory.createLoad(teamType, ot_team));
+ // generated:
+ // _OT$team.getClass().getMethod(<wrapperName>, <wrapper sign>)
+ // _OT$team
+ argArray = il.append(new ANEWARRAY(cpg.addClass(object)));
+
+ } else {
+ il.append(factory.createCast(teamType, new ObjectType(connectorClassName)));
+ // generated: (<TeamClass>)_OT$team
+ }
+
+ // first argument: base object:
+ packedArgPos = checkPackValue0(il, useReflection, packedArgPos, cpg);
+ {
+ if (!mg.isStatic())
+ il.append(InstructionFactory.createThis());
+ else
+ il.append(InstructionFactory.createNull(Type.OBJECT)); // no base object
+ }
+ checkPackValue1(il, useReflection, Type.OBJECT);
+
+ // second argument: base result (if appropriate)
+ if ( mb.isAfter() && !baseReturnType.equals(Type.VOID)) { // after callin wrapper get the base method result as second argument
+ packedArgPos = checkPackValue0(il, useReflection, packedArgPos, cpg);
+ {
+ il.append(InstructionFactory.createLoad(object, ot_result));
+ adjustValue(il, null, object, baseReturnType);
+ argsLen --; // the second (result) arg is also not part of the arg list
+ }
+ checkPackValue1(il, useReflection, baseReturnType);
+ }
+
+ // ------- load regular args: --------
+
+ // stack positions for load instructions (one-based for non-statics, since 0 == this)
+ int stackIndex = EXTRA_ARGS + (mg.isStatic() ? 0 : 1);
+ // where within baseArgTypes do source arguments start?
+ int firstArg = 0;
+
+ if (mb.baseMethodIsCallin()) {
+ // skip enhancement of this callin method (lower role).
+ firstArg += EXTRA_ARGS;
+ stackIndex += EXTRA_ARGS;
+ argsLen += EXTRA_ARGS;
+ }
+ for (int i = firstArg; i < argsLen; i++) {
+ if(logging) printLogMessage("loading " + baseArgTypes[i].toString()); //$NON-NLS-1$
+
+ packedArgPos = checkPackValue0(il, useReflection, packedArgPos, cpg);
+ {
+ il.append(InstructionFactory.createLoad(baseArgTypes[i],stackIndex));
+ }
+ checkPackValue1(il, useReflection, baseArgTypes[i]);
+
+ stackIndex += baseArgTypes[i].getSize();
+ }
+
+ InstructionHandle callinCall;
+ if (useReflection) {
+ // this information was missing above:
+ il.insert(argArray, createIntegerPush(cpg, packedArgPos));
+
+ callinCall = il.append(factory.createInvoke("java.lang.reflect.Method", "invoke", object, new Type[]{object, objectArray}, Constants.INVOKEVIRTUAL));
+ il.append(new POP()); // before/after wrappers return void
+ } else {
+ callinCall = il.append(factory.createInvoke(connectorClassName,
+ mb.getWrapperName(),
+ Type.VOID, wrapperArgTypes,
+ Constants.INVOKEVIRTUAL));
+ }
+ if (debugging) {
+ mg.addLineNumber(callinCall, SHOW_ROLE_CALL ? firstLine : STEP_INTO_LINENUMBER); // show role call at method header ("dispatching")
+ mg.addLineNumber(il.append(new NOP()), STEP_OVER_LINENUMBER);
+ }
+ }
+ }
+
+ /* this and the next method serve as a bracket for all pushes that may or may not require
+ * packing in an array, the array must already exist on the stack. */
+ private int checkPackValue0(InstructionList il, boolean doPack, int argCount, ConstantPoolGen cpg) {
+ if (doPack) {
+ il.append(new DUP());
+ il.append(createIntegerPush(cpg, argCount));
+ return argCount+1;
+ } else {
+ return argCount;
+ }
+ }
+ private void checkPackValue1(InstructionList il, boolean doPack, Type argType) {
+ if (doPack) {
+ if (argType instanceof BasicType)
+ il.append(createBoxing((BasicType)argType));
+ il.append(new AASTORE());
+ }
+ }
+ /* Push an array of Class representing the signature given by argTypes. */
+ private void pushTypeArray(InstructionList il, Type[] argTypes, int major, ConstantPoolGen cpg) {
+ il.append(createIntegerPush(cpg, argTypes.length));
+ il.append(new ANEWARRAY(cpg.addClass(classType)));
+ for (int i=0; i<argTypes.length; i++) {
+ Type type = argTypes[i];
+ il.append(new DUP());
+ il.append(createIntegerPush(cpg, i));
+ if (type instanceof BasicType) {
+ il.append(factory.createFieldAccess(toObjectTypeName((BasicType)type), "TYPE", classType, Constants.GETSTATIC));
+ } else if (type instanceof ObjectType) {
+ appendClassLiteral(il, ((ObjectType)type).getClassName(), major, cpg);
+ } else if (type instanceof ArrayType) {
+ String prefix = "";
+ while (type instanceof ArrayType) {
+ prefix += '[';
+ type = ((ArrayType)type).getElementType();
+ }
+ String elemTypeName = null;
+ if (type instanceof ObjectType)
+ elemTypeName = "L"+((ObjectType)type).getClassName()+';';
+ else if (type instanceof BasicType)
+ elemTypeName = ((BasicType)type).getSignature();
+ appendClassLiteral(il, prefix+elemTypeName, major, cpg);
+ } else {
+ throw new OTREInternalError("unsupported type in signature "+type);
+ }
+ il.append(new AASTORE());
+ }
+ }
+
+ /**
+ * Create a block for a replace callin as a case within a surrounding switch. If there are multiple bindings from the
+ * same team to this base method, the bindings are sorted according to the precedence list of this team.
+ * @param mg base method being generated.
+ * @param il instruction list being assembled.
+ * @param connectorClassName name of a Team which has a callin to this method.
+ * @param mbList list of 'MethodBinding's
+ * @param ot_result index of a local variable <tt>_OT$result</tt>.
+ * @param ot_team index of local variable <tt>_OT$team</tt>.
+ * @param major class file version
+ */
+ void createReplaceCase(MethodGen mg, InstructionList il,
+ String connectorClassName, List<MethodBinding> mbList,
+ int ot_result, int ot_team, int major, int firstLine)
+ {
+
+ int indexOffset = mg.isStatic() ? -1 : 0; // argument indizes are decremented for static methods,
+ // because of the missing 'this'
+ boolean multipleBindings = mbList.size() > 1;
+ mbList = CallinBindingManager.sortMethodBindings(mbList, connectorClassName);
+
+ MethodBinding mb = mbList.get(0); // default, if only one binding exists
+
+ LocalVariableGen unused_args_lg = mg.addLocalVariable(UNUSED, objectArray, null, null);
+ int unused_args = unused_args_lg.getIndex();
+ unused_args_lg.setStart(il.append(new NOP()));
+ if (multipleBindings) {
+ InstructionList addition = new InstructionList();
+ // load value to be switched:
+
+ InstructionHandle switchStart = addition.append(InstructionFactory.createLoad(Type.INT, BIND_IDX_ARG+indexOffset));
+ // loaded _OT$bindIdx
+
+ int numberOfCases = mbList.size();
+
+ // one break for each case clause
+ GOTO[] breaks = new GOTO[numberOfCases];
+ for (int i=0; i<numberOfCases; i++)
+ breaks[i] = new GOTO(null);
+
+ int[] matches = new int[numberOfCases];
+ InstructionHandle[] targets = new InstructionHandle[numberOfCases];
+
+ int caseCounter = 0;
+ Iterator<MethodBinding> mbIterator = mbList.iterator();
+ while (mbIterator.hasNext()) {
+ mb = mbIterator.next();
+ matches[caseCounter] = caseCounter;
+ InstructionHandle nextBranch = addition.append(new NOP());
+ // ========== create Cases: ===========
+ addition.append(createSingleReplaceCallin(mg, connectorClassName, mb, ot_result, ot_team, unused_args, multipleBindings, mg.isStatic(), major, firstLine));
+ // ==============================
+ targets[caseCounter] = nextBranch;
+ /*InstructionHandle break_instr =*/ addition.append(breaks[caseCounter]);
+ // generated: break;
+ caseCounter++;
+ }
+ // ========== create default: ===========
+ InstructionHandle defaultBranch = addition.append(new NOP());
+ createRecursiveCall(addition, mg, ot_result, 1, 0, mb.getBaseMethodName(), mb.getBaseMethodSignature(), firstLine);
+ // ==============================
+
+ InstructionHandle afterSwitch = addition.append(new NOP()); // all breaks point here.
+
+ for (int i=0; i<numberOfCases; i++)
+ breaks[i].setTarget(afterSwitch);
+
+ addition.append(switchStart, new TABLESWITCH(matches, targets, defaultBranch));
+ // wrap everything in a try {} catch (LiftingVetoException e) {..}
+ InstructionHandle endTry = addition.getEnd();
+
+ GOTO skipHdlr = null;
+ skipHdlr = new GOTO(null);
+ addition.append(skipHdlr);
+ // generated: goto normal exit
+
+ InstructionHandle hdlr = addition.append(new NOP());
+ addition.append(DebugUtil.createReportExc(factory));
+
+ // ========== create catch instructions: ===========
+ createRecursiveCall(addition, mg, ot_result, 0, 1, mb.getBaseMethodName(), mb.getBaseMethodSignature(), firstLine);
+ // =====================================
+ mg.addExceptionHandler(addition.getStart(), endTry, hdlr, liftingVeto);
+
+ InstructionHandle nop = addition.append(new NOP());
+ skipHdlr.setTarget(nop);
+ il.append(addition);
+ } else { // only a single replace callin:
+ il.append(createSingleReplaceCallin(mg, connectorClassName, mb, ot_result, ot_team, unused_args, multipleBindings, mg.isStatic(), major, firstLine));
+ }
+ unused_args_lg.setEnd(il.getEnd());
+ }
+
+ /**
+ * Creates a single replace callin call.
+ *
+ * @param mg base method being generated.
+ * @param connectorClassName name of a Team which has a callin to this method.
+ * @param mb the 'MethodBinding' for this callin.
+ * @param ot_result index of a local variable <tt>_OT$result</tt>.
+ * @param ot_team index of local variable <tt>_OT$team</tt>.
+ * @param unused_args index of local variable <tt>_OT$unused_args</tt>.
+ * @param multipleBindings flag indicating if there are multiple bindings in this case
+ * @param staticBaseMethod TODO
+ * @param major class file version
+ * @param firstLine first real source line number of this method
+ * @return instruction list for the callin call
+ */
+ private InstructionList createSingleReplaceCallin(MethodGen mg, String connectorClassName, MethodBinding mb, int ot_result, int ot_team, int unused_args, boolean multipleBindings, boolean staticBaseMethod, int major, int firstLine)
+ {
+ // Sequence of values to load is (letters refer to document parameter-passing.odg):
+ // (f) _OT$team: call target for invoking the callin-wrapper
+ // (g) baseObject: this or null
+ // (h) enhancement: [Team[IIII[Object;
+ // idxs are being manipulated here,
+ // unusedArgs[] is allocated and filled with
+ // (i) - (int,Team) if current method is static role method.
+ // (j) - enhancement arguments, if current method is callin method
+ // (k) regular arguments.
+
+ // ------------------------------------------
+ // prepare Types:
+ // ------------------------------------------
+ Type[] chainArgTypes = mg.getArgumentTypes();
+ Type[] baseArgTypes = Type.getArgumentTypes(mb.getBaseMethodSignature());
+ Type[] roleArgTypes = Type.getArgumentTypes(mb.getRoleMethodSignature());
+ roleArgTypes = enhanceArgumentTypes(roleArgTypes);
+ String wrapperName = mb.getWrapperName();
+ Type wrapperReturnType = Type.getReturnType(mb.getWrapperSignature());
+
+ Type[] wrapperArgTypes = Type.getArgumentTypes(mb.getWrapperSignature());
+
+ // calculate return type:
+ Type chainReturnType = mg.getReturnType();
+
+ ConstantPoolGen cpg = mg.getConstantPool();
+ InstructionList il = new InstructionList();
+ // (f):
+ il.append(InstructionFactory.createLoad(teamType, ot_team));
+
+ int packedArgPos = 0;
+ InstructionHandle argArray = null;
+ if (useReflection) {
+ il.append(factory.createInvoke("java.lang.Object", "getClass", classType, new Type[0], Constants.INVOKEVIRTUAL));
+ il.append(new LDC(cpg.addString(mb.getWrapperName())));
+ pushTypeArray(il, wrapperArgTypes, major, cpg);
+ il.append(factory.createInvoke("java.lang.Class", "getMethod", methodType, OTConstants.getMethodSignature, Constants.INVOKEVIRTUAL));
+
+ il.append(InstructionFactory.createLoad(teamType, ot_team));
+ // generated:
+ // _OT$team.getClass().getMethod(<wrapperName>, <wrapper sign>)
+ // _OT$team
+ argArray = il.append(new ANEWARRAY(cpg.addClass(object)));
+ } else {
+ il.append(factory.createCast(teamType, new ObjectType(connectorClassName)));
+ // generated: (<TeamClass>)_OT$team
+ }
+
+ // (g):
+ packedArgPos = checkPackValue0(il, useReflection, packedArgPos, cpg);
+ {
+ if(!staticBaseMethod)
+ il.append(InstructionFactory.createThis());
+ else
+ il.append(InstructionFactory.createNull(Type.OBJECT)); // no base object
+ }
+ checkPackValue1(il, useReflection, Type.OBJECT);
+
+ // ----------------------------------------
+ // (h) Load Extra Arguments:
+ // ----------------------------------------
+ int staticOffset = staticBaseMethod?-1:0; // argument indizes are decremented for static methods,
+ // because of the missing 'this'
+ // first 4 extra arguments: _OT$teams, _OT$teamIDs, _OT$idx, _OT$bindIdx
+ for (int i=0; i<4; i++) { // If this is called only once _OT$idx has to be incremented, else _OT$bindIdx has to be incremented
+ packedArgPos = checkPackValue0(il, useReflection, packedArgPos, cpg);
+ {
+ il.append(InstructionFactory.createLoad(chainArgTypes[i], i+1+staticOffset));
+ if (!multipleBindings && i+1+staticOffset == OTConstants.IDX_ARG+staticOffset) {// _OT$idx++:
+ il.append(new ICONST(1));
+ il.append(new IADD());
+ } else if (multipleBindings && i+1+staticOffset == OTConstants.BIND_IDX_ARG+staticOffset) {// _OT$bindIdx:
+ il.append(new ICONST(1));
+ il.append(new IADD());
+ }
+ }
+ checkPackValue1(il, useReflection, chainArgTypes[i]);
+ }
+ // _OT$baseMethTag:
+ int base_meth_tag = CallinBindingManager.getBaseCallTag(mb.getBaseClassName(),
+ mb.getBaseMethodName(),
+ mb.getBaseMethodSignature());
+// //JU: added this if-statement (begin) ----------------------------------------------
+// if(staticBaseMethod && !mg.getClassName().equals(mb.getBaseClassName())){
+// //the method binding is a dummy -> the callin wrapper is performed
+// //with an invalid base method tag value -> an exception will be thrown
+// base_meth_tag = INVALID_BASE_METHOD_TAG;
+// }
+// //JU (end) --------------------------------------------------------------------------
+
+ packedArgPos = checkPackValue0(il, useReflection, packedArgPos, cpg);
+ {
+ il.append(createIntegerPush(cpg, base_meth_tag));
+ }
+ checkPackValue1(il, useReflection, Type.INT);
+
+ // collect regular args first, insert into il later:
+ InstructionList regularArgs = new InstructionList();
+
+ // put "new Object[]" on stack, later containing unused arguments:
+ packedArgPos = checkPackValue0(il, useReflection, packedArgPos, cpg);
+ {
+ il.append(createIntegerPush(cpg, baseArgTypes.length));
+ // enough space to hold ALL base arguments
+ // Note that the callin wrapper may add more elements to this array.
+ il.append((Instruction)factory.createNewArray(object, (short)1));
+ il.append(InstructionFactory.createStore(objectArray, unused_args));
+ // generated: _OT$unusedArgs = new Object[<n_base_args>];
+
+ // ----------------------------------------
+ // handle more arguments: load regular ones, store unused arguments into the array:
+ // ----------------------------------------
+ int unusedArgsIdx = 0; // index into Object[].
+
+ int stackIdx = EXTRA_ARGS + 1 + staticOffset; // one-based, since 0 == this (unless static)
+ int regularArgsStart = EXTRA_ARGS;
+ boolean baseIsStaticCallin = mb.baseMethodIsCallin() && staticBaseMethod;
+ if (baseIsStaticCallin) {
+ // (i) need these synthetic arguments up-front: "int dummy, Team enclosingTeam"
+ storeUnusedArg(il, unused_args, 0, // constant
+ new ICONST(0),
+ Type.INT,
+ cpg);
+ storeUnusedArg(il, unused_args, 1, // constant
+ new ALOAD(regularArgsStart+1),
+ OTConstants.teamType,
+ cpg);
+
+ // consumed first two parameters into unusedArgs:
+ regularArgsStart+=2;
+ stackIdx += 2;
+ unusedArgsIdx += 2;
+ }
+ for (int i=regularArgsStart; i<chainArgTypes.length; i++) {
+ Type argType = chainArgTypes[i];
+ Instruction loadingInstruction = InstructionFactory.createLoad(argType, stackIdx);
+ if (isRegularArg(i, mb.baseMethodIsCallin(), staticBaseMethod)) {
+ // (k) collect loading instruction, for appending after _OT$unusedArgs.
+ packedArgPos = checkPackValue0(regularArgs, useReflection, packedArgPos, cpg);
+ {
+ regularArgs.append(loadingInstruction);
+ }
+ checkPackValue0(regularArgs, useReflection, packedArgPos, cpg);
+ } else {
+ // (j) store unused arg
+ storeUnusedArg(il, unused_args, unusedArgsIdx++, loadingInstruction, argType, cpg);
+ // generated: _OT$unusedArgs[<unusedArgsIdx>] = maybeBox(a<index>);
+ }
+ stackIdx += argType.getSize();
+ }
+ il.append(InstructionFactory.createLoad(objectArray, unused_args));
+ }
+ checkPackValue1(il, useReflection, objectArray);
+
+ // (k) insert previously assembled load-sequence:
+ il.append(regularArgs);
+
+ // ============= INVOKEVIRTUAL (wrapper) =============
+ InstructionHandle callinCall;
+ if (useReflection) {
+ // this information was missing above:
+ il.insert(argArray, createIntegerPush(cpg, packedArgPos));
+
+ callinCall = il.append(factory.createInvoke("java.lang.reflect.Method", "invoke", object, new Type[]{object, objectArray}, Constants.INVOKEVIRTUAL));
+ wrapperReturnType = Type.OBJECT;
+ } else {
+ callinCall = il.append(factory.createInvoke(connectorClassName, wrapperName,
+ wrapperReturnType,
+ wrapperArgTypes,
+ Constants.INVOKEVIRTUAL));
+ }
+ if (debugging) {
+ mg.addLineNumber(callinCall, SHOW_ROLE_CALL ? firstLine : STEP_INTO_LINENUMBER); // show role call at method header ("dispatching")
+ mg.addLineNumber(il.append(new NOP()), STEP_OVER_LINENUMBER);
+ }
+
+ adjustValue(il, null, wrapperReturnType, chainReturnType);
+ il.append(InstructionFactory.createStore(chainReturnType, ot_result));
+
+ return il;
+ }
+
+ /**
+ * Store an unused value (loaded by pushInstruction) into _OT$unusedArgs
+ */
+ private void storeUnusedArg(InstructionList il,
+ int unused_args,
+ int arrayIndex,
+ Instruction pushInstruction,
+ Type argType,
+ ConstantPoolGen cpg)
+ {
+ il.append(InstructionFactory.createLoad(objectArray, unused_args));
+ il.append(createIntegerPush(cpg, arrayIndex));
+ il.append(pushInstruction);
+ if (argType instanceof BasicType)
+ il.append(createBoxing((BasicType)argType));
+ il.append(InstructionFactory.createArrayStore(objectArray));
+ }
+
+ /**
+ * Is the parameter at position idx mapped (by paramPositions or implicitly)?
+ * Cut off head:
+ * - (int,Team) if present (static role method)
+ * - enhancement (possible twice)
+ * @param idx parameter index of enhanced signature
+ */
+ static boolean isRegularArg (int idx, boolean baseIsCallin, boolean baseIsStatic) {
+ if (baseIsCallin && baseIsStatic) // FIXME(SH): should be baseIsRole instead of baseIsCallin!
+ idx -= 2;
+ int firstVisible = EXTRA_ARGS + (baseIsCallin?EXTRA_ARGS:0); // skip one or two enhancements
+ return idx >= firstVisible;
+ }
+
+ /**
+ * Given an argument of type <tt>actual</tt>, must
+ * we use type <tt>formal</tt> in signatures,
+ * because it is a supertype of <tt>actual</tt>?
+ */
+ static Type checkWiden (Type actual, Type formal) {
+ if (!actual.equals(formal)
+ && actual instanceof ObjectType
+ && formal instanceof ObjectType)
+ {
+ ObjectType actualObj = (ObjectType)actual;
+ ObjectType formalObj = (ObjectType)formal;
+ if (actualObj.subclassOf(formalObj))
+ return formalObj;
+ }
+ return actual;
+ }
+
+ /**
+ * Create an instruction list for initializing the role set field on-demand.
+ * @param valueRequired should the role set be on the stack after this sequence?
+ * @param cg the ClassGen of the appropriate class
+ */
+ private InstructionList getInitializedRoleSet(String class_name, boolean valueRequired) {;
+ InstructionList il = new InstructionList();
+
+ // try to retrieve existing set:
+ il.append(new ALOAD(0));
+ il.append(factory.createGetField(class_name, OTConstants.ROLE_SET, OTConstants.roleSetType));
+ if (valueRequired)
+ il.append(new DUP()); // a spare value to keep on the stack if successful
+
+ // if (roleSet == null) ..
+ IFNONNULL branch = new IFNONNULL(null);
+ il.append(branch);
+
+ // conditionally create the set:
+ if (valueRequired)
+ il.append(new POP()); // remove useless "null", replace with DUP_X1 below
+ il.append(new ALOAD(0));
+ il.append(factory.createNew(OTConstants.roleSetType));
+ il.append(new DUP());
+ il.append(factory.createInvoke(OTConstants.roleSetType.getClassName(),
+ Constants.CONSTRUCTOR_NAME,
+ Type.VOID,
+ Type.NO_ARGS,
+ Constants.INVOKESPECIAL));
+ if (valueRequired)
+ il.append(new DUP_X1()); // push below pending "this"
+
+ // store in the field:
+ il.append(factory.createPutField(class_name, OTConstants.ROLE_SET, OTConstants.roleSetType));
+
+ // endif
+ branch.setTarget(il.append(new NOP()));
+ return il;
+ }
+
+ /**
+ * Generates the field '_OT$roleSet' which is used to store the added roles.
+ * @param cpg the ClassGen of the appropriate class
+ * @param class_name the name of the class
+ * @return the generated field
+ */
+ private Field generateRoleSet(ConstantPoolGen cpg, String class_name) {
+ FieldGen fg = new FieldGen(Constants.ACC_PROTECTED,
+ OTConstants.roleSetType,
+ OTConstants.ROLE_SET,
+ cpg);
+ return fg.getField();
+ }
+
+ /**
+ * Generates the method 'public void _OT$addRole(Object role)' which adds the passed object
+ * to the role set of this base class.
+ * @param cpg the ClassGen of the appropriate class
+ * @param class_name the name of the class
+ * @return the generated method
+ */
+ private Method generateAddRole(ConstantPoolGen cpg, String class_name) {
+
+ InstructionList il = new InstructionList();
+ MethodGen mg = new MethodGen(Constants.ACC_PUBLIC,
+ Type.VOID,
+ new Type[] { Type.OBJECT },
+ new String[] {"role"},
+ OTConstants.ADD_ROLE, class_name,
+ il, cpg);
+
+ il.append(getInitializedRoleSet(class_name, /*valueRequired*/true));
+
+ il.append(InstructionFactory.createLoad(Type.OBJECT, 1));
+ il.append(factory.createInvoke(OTConstants.roleSetType.getClassName(),
+ "add",
+ Type.BOOLEAN,
+ new Type[] {Type.OBJECT},
+ Constants.INVOKEVIRTUAL));
+ il.append(new POP());
+ il.append(InstructionFactory.createReturn(Type.VOID));
+ mg.removeNOPs();
+ mg.setMaxStack();
+ mg.setMaxLocals(2);
+ return mg.getMethod();
+ }
+
+ /**
+ * Generates the method 'public void _OT$removeRole(Object role)' which removes the passed object
+ * from the role set of this base class.
+ * @param cpg the ClassGen of the appropriate class
+ * @param class_name the name of the class
+ * @return the generated method
+ */
+ private Method generateRemoveRole(ConstantPoolGen cpg, String class_name) {
+
+ InstructionList il = new InstructionList();
+ MethodGen mg = new MethodGen(Constants.ACC_PUBLIC,
+ Type.VOID,
+ new Type[] { Type.OBJECT },
+ new String[] {"role"},
+ OTConstants.REMOVE_ROLE, class_name,
+ il, cpg);
+ il.append(new ALOAD(0));
+ il.append(factory.createGetField(class_name, OTConstants.ROLE_SET, OTConstants.roleSetType));
+ il.append(InstructionFactory.createLoad(Type.OBJECT, 1));
+ il.append(factory.createInvoke(OTConstants.roleSetType.getClassName(),
+ "remove",
+ Type.BOOLEAN,
+ new Type[] {Type.OBJECT},
+ Constants.INVOKEVIRTUAL));
+ il.append(new POP());
+ il.append(InstructionFactory.createReturn(Type.VOID));
+ mg.removeNOPs();
+ mg.setMaxStack(2);
+ mg.setMaxLocals(2);
+ return mg.getMethod();
+ }
+
+}
diff --git a/othersrc/OTRE/src/org/eclipse/objectteams/otre/BaseTagInsertion.java b/othersrc/OTRE/src/org/eclipse/objectteams/otre/BaseTagInsertion.java
new file mode 100644
index 0000000..ebbf234
--- /dev/null
+++ b/othersrc/OTRE/src/org/eclipse/objectteams/otre/BaseTagInsertion.java
@@ -0,0 +1,205 @@
+/**********************************************************************
+ * 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);
+ }
+}
diff --git a/othersrc/OTRE/src/org/eclipse/objectteams/otre/ClassEnhancer.java b/othersrc/OTRE/src/org/eclipse/objectteams/otre/ClassEnhancer.java
new file mode 100644
index 0000000..aa80c98
--- /dev/null
+++ b/othersrc/OTRE/src/org/eclipse/objectteams/otre/ClassEnhancer.java
@@ -0,0 +1,79 @@
+/**********************************************************************
+ * This file is part of the "Object Teams Runtime Environment"
+ *
+ * Copyright 2005-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: ClassEnhancer.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.classfile.Field;
+import de.fub.bytecode.classfile.Method;
+import de.fub.bytecode.generic.ClassGen;
+import de.fub.bytecode.generic.ConstantPoolGen;
+
+
+
+/**
+ * This interface is used to abstract from the BCEL external transformations.
+ *
+ * @author Christine Hundt
+ * @author Juergen Widiker
+ * @author Stephan Herrmann
+ */
+public interface ClassEnhancer {
+
+ /**
+ * Adds the interface 'interfaceName' to the implements clause of class 'cg'.
+ */
+ public void addImplements(String interfaceName, ClassGen cg);
+
+ /**
+ * Adds the method 'm' to the class represented by 'cg'.
+ * @param m the method to be added
+ * @param cg the ClassGen of the appropriate class
+ */
+ void addMethod(Method m, ClassGen cg);
+
+ /**
+ * Adds method 'm' to the class 'cg' or, if a method with the
+ * same name and signature already exists, replace that method.
+ * @param method
+ * @param cg
+ */
+ void addOrReplaceMethod(Method method, ClassGen cg);
+
+ /**
+ * Adds the field 'f' to the class represented by 'cg'.
+ * @param f
+ * @param cg
+ */
+ void addField(Field f, ClassGen cg);
+
+ /**
+ * Loads the class named 'className'.
+ * @param className the name of the class to be loaded
+ * @param client the transformer on behalf of which we are called, can be used to call checkReadClassAttributes.
+ */
+ void loadClass(String className, ObjectTeamsTransformation client);
+
+ /**
+ * Decapsulation of the method 'm'. This means that the access modifier of this method is set to 'public'.
+ * @param m the name of the method to be decapsulated
+ * @param className the name of the belonging class
+ * @param packageName the name of the belonging package
+ * @param cpg the ConstantPoolGen of the class
+ */
+ void decapsulateMethod(Method m, ClassGen cg, String packageName, ConstantPoolGen cpg);
+
+
+}
diff --git a/othersrc/OTRE/src/org/eclipse/objectteams/otre/Decapsulation.java b/othersrc/OTRE/src/org/eclipse/objectteams/otre/Decapsulation.java
new file mode 100644
index 0000000..9f74123
--- /dev/null
+++ b/othersrc/OTRE/src/org/eclipse/objectteams/otre/Decapsulation.java
@@ -0,0 +1,427 @@
+/**********************************************************************
+ * This file is part of the "Object Teams Runtime Environment"
+ *
+ * Copyright 2003, 2009 Technical University Berlin, 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: Decapsulation.java 23408 2010-02-03 18:07:35Z stephan $
+ *
+ * Please visit http://www.objectteams.org for updates and contact.
+ *
+ * Contributors:
+ * Technical University Berlin - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.objectteams.otre;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.objectteams.otre.util.CallinBindingManager;
+import org.eclipse.objectteams.otre.util.FieldDescriptor;
+import org.eclipse.objectteams.otre.util.SuperMethodDescriptor;
+
+import de.fub.bytecode.Constants;
+import de.fub.bytecode.classfile.Method;
+import de.fub.bytecode.generic.ClassGen;
+import de.fub.bytecode.generic.ConstantPoolGen;
+import de.fub.bytecode.generic.InstructionFactory;
+import de.fub.bytecode.generic.InstructionList;
+import de.fub.bytecode.generic.MethodGen;
+import de.fub.bytecode.generic.ObjectType;
+import de.fub.bytecode.generic.Type;
+
+/**
+ * For each base method that is bound by callout and has
+ * insufficient visibility, the visibility is set to public.
+ * If the corresponding JMangler-patch is installed, check
+ * whether the affected base class resides in a sealed package.
+ * In that case dissallow decapsulation by throwing an IllegalAccessError.
+ *
+ * @version $Id: Decapsulation.java 23408 2010-02-03 18:07:35Z stephan $
+ * @author Stephan Herrmann
+ */
+public class Decapsulation
+ extends ObjectTeamsTransformation
+ implements Constants
+{
+
+// HashSet modifiedPackages = new HashSet();
+
+ public static class SharedState extends ObjectTeamsTransformation.SharedState {
+ private HashMap /* class_name -> HashSet(callout accessed fields) */<String, HashSet<String>> generatedFieldCalloutAccessors
+ = new HashMap<String, HashSet<String>>();
+ private HashMap /* class_name -> HashSet(super-accessed methods (sign))*/<String, HashSet<String>> generatedSuperAccessors
+ = new HashMap<String, HashSet<String>>();
+ }
+ @Override
+ SharedState state() {
+ return (SharedState)this.state;
+ }
+
+ public Decapsulation(SharedState state) {
+ this(null, state);
+ }
+ public Decapsulation(ClassLoader loader, SharedState state) {
+ super(loader, state);
+ // FIXME(SH): can we ever release this transformer and its state?
+ synchronized(ObjectTeamsTransformation.reentrentTransformations) {
+ ObjectTeamsTransformation.reentrentTransformations.add(this);
+ }
+ }
+
+ /**
+ * Main entry for this transformer.
+ */
+// @SuppressWarnings("unchecked")
+ public void doTransformInterface(ClassEnhancer ce, ClassGen cg) {
+ String class_name = cg.getClassName();
+ ConstantPoolGen cpg = cg.getConstantPool();
+
+ // if class is already transformed by this transformer
+ if (state.interfaceTransformedClasses.contains(class_name))
+ return;
+
+ checkReadClassAttributes(ce, cg, class_name, cpg);
+
+ // next step starts to transform, so record this class now.
+ state.interfaceTransformedClasses.add(class_name);
+
+ generateFieldAccessForCallout(ce, cg, class_name, cpg);
+
+ generateSuperAccessors(ce, cg, class_name, cpg);
+
+ HashSet<String> calloutBindings = CallinBindingManager.getCalloutBindings(class_name);
+
+ if (calloutBindings == null) {
+ if(logging) printLogMessage("\nClass " + class_name
+ + " requires no callout adjustment.");
+ return;
+ }
+
+ if(logging) printLogMessage("\nCallout bindings might be changing class "
+ + class_name + ":");
+
+ HashSet<String> oldStyleBinding = new HashSet<String>();
+
+ // try new style decapsulation first (since 1.2.8):
+ for (String calloutBinding : calloutBindings) {
+ DecapsulationDescriptor desc = new DecapsulationDescriptor();
+ if (!desc.decode(calloutBinding, cg))
+ oldStyleBinding.add(calloutBinding); // old style attribute
+ else if (!desc.existsAlready)
+ ce.addMethod(desc.generate(class_name, cpg), cg);
+ }
+
+ if (oldStyleBinding.isEmpty()) return;
+
+ // --> follows: old style decapsulation for remaining bindings:
+ int pos = class_name.lastIndexOf('.');
+ String package_name = "NO_PACKAGE";
+ if (pos != -1)
+ package_name = class_name.substring(0,pos);
+
+ Method[] methods = cg.getMethods();
+ for (int i = 0; i < methods.length; i++) {
+ Method m = methods[i];
+ String method_name = m.getName();
+
+ boolean requiresAdjustment = CallinBindingManager.
+ requiresCalloutAdjustment(oldStyleBinding,
+ method_name,
+ m.getSignature());
+
+ if (requiresAdjustment) {
+ ce.decapsulateMethod(m, cg, package_name, cpg);
+ }
+ }
+ }
+ class DecapsulationDescriptor {
+ short invokeKind;
+ String targetClass;
+ String methodName;
+ String methodSign;
+ Type returnType;
+ Type[] args;
+ String accessorName;
+
+ boolean existsAlready;
+
+ /**
+ * new style encoding is
+ * targetClassName ('!' | '?') methodName '.' methodSign
+ */
+ boolean decode(String encodedBinding, ClassGen cg) {
+ int sepPos = encodedBinding.indexOf('!');
+ if (sepPos != -1) { // static method:
+ invokeKind = INVOKESTATIC;
+ } else {
+ sepPos = encodedBinding.indexOf('?');
+ if (sepPos != -1) {
+ invokeKind = INVOKEVIRTUAL;
+ } else {
+ return false; // old style
+ }
+ }
+ targetClass = encodedBinding.substring(0, sepPos);
+ int sigPos = encodedBinding.indexOf('(', sepPos);
+ methodName = encodedBinding.substring(sepPos+1, sigPos);
+ methodSign = encodedBinding.substring(sigPos);
+
+ returnType = Type.getReturnType(methodSign);
+ args = Type.getArgumentTypes(methodSign);
+
+ accessorName = "_OT$decaps$"+methodName;
+ existsAlready = cg.containsMethod(accessorName, methodSign) != null;
+ if (invokeKind == INVOKEVIRTUAL) {
+ Method existing = cg.containsMethod(methodName, methodSign);
+ if (existing != null && existing.isPrivate())
+ invokeKind = INVOKESPECIAL; // accessing private
+ }
+
+ return true;
+ }
+ Method generate(String currentClass, ConstantPoolGen cpg) {
+ InstructionList il = new InstructionList();
+ int instanceOffset = 0;
+ short flags = Constants.ACC_PUBLIC;
+ if (invokeKind != INVOKESTATIC) {
+ instanceOffset=1;
+ il.append(InstructionFactory.createThis());
+ } else {
+ flags |= Constants.ACC_STATIC;
+ }
+ int pos= 0;
+ for (int i = 0; i < args.length; i++) {
+ il.append(InstructionFactory.createLoad(args[i], pos+instanceOffset));
+ pos += args[i].getSize();
+ }
+ il.append(new InstructionFactory(cpg).createInvoke(targetClass, methodName, returnType, args, invokeKind));
+ il.append(InstructionFactory.createReturn(returnType));
+ MethodGen newMethod = new MethodGen(flags, returnType, args, /*argNames*/null, accessorName, currentClass, il, cpg);
+ newMethod.setMaxLocals();
+ newMethod.setMaxStack();
+ return newMethod.getMethod();
+ }
+ }
+
+ /**
+ * Generates getter and setter methods for all fields of the class 'class_name' which are accessed via callout.
+ * Informations are received via attributs (CallinBindingManager).
+ * @param cg the ClassGen of the appropriate class
+ * @param class_name the name of the class
+ * @param cpg the ConstantPoolGen of the class
+ * @param es the ExtensionSet to add the new access methods
+ */
+ private void generateFieldAccessForCallout(ClassEnhancer ce, ClassGen cg, String class_name, ConstantPoolGen cpg) {
+ InstructionFactory factory = null;
+
+ HashSet<String> addedAccessMethods = state().generatedFieldCalloutAccessors.get(class_name);
+
+ List<FieldDescriptor> getter = CallinBindingManager.getCalloutGetFields(class_name);
+ if (getter != null) {
+ factory = new InstructionFactory(cg);
+ Iterator<FieldDescriptor> it = getter.iterator();
+ while (it.hasNext()) {
+ FieldDescriptor fd = it.next();
+ String key = "get_" + fd.getFieldName() + fd.getFieldSignature();
+ if (logging)
+ printLogMessage("Generating getter method "+key);
+ if (addedAccessMethods == null)
+ addedAccessMethods = new HashSet<String>();
+ if (addedAccessMethods.contains(key))
+ continue; // this getter has already been created
+ ce.addMethod(generateGetter(cpg, class_name, fd, factory), cg);
+ addedAccessMethods.add(key);
+ state().generatedFieldCalloutAccessors.put(class_name, addedAccessMethods);
+ }
+ }
+
+ List<FieldDescriptor> setter = CallinBindingManager.getCalloutSetFields(class_name);
+ if (setter != null) {
+ if (factory == null)
+ factory = new InstructionFactory(cg);
+ Iterator<FieldDescriptor> it = setter.iterator();
+ while (it.hasNext()) {
+ FieldDescriptor fd = it.next();
+ String key = "set_"+fd.getFieldName()+fd.getFieldSignature();
+ if (logging)
+ printLogMessage("Generating setter method "+key);
+ if (addedAccessMethods == null)
+ addedAccessMethods = new HashSet<String>();
+ if (addedAccessMethods.contains(key))
+ continue; // this setter has already been created
+ ce.addMethod(generateSetter(cpg, class_name, fd, factory), cg);
+ addedAccessMethods.add(key);
+ state().generatedFieldCalloutAccessors.put(class_name, addedAccessMethods);
+ }
+ }
+ }
+
+
+ /**
+ * Generates a getter method for the field described by 'fd' in the class 'class_name'.
+ * @param cpg the ConstantPoolGen of the class
+ * @param class_name the name of the class
+ * @param fd the FieldDescriptor describing the affected field
+ * @param factory an InstructionFactory for this class
+ * @return the generated getter method
+ */
+ private Method generateGetter(ConstantPoolGen cpg, String class_name, FieldDescriptor fd, InstructionFactory factory) {
+ String fieldName = fd.getFieldName();
+ Type fieldType = Type.getType(fd.getFieldSignature());
+ Type baseType = new ObjectType(class_name);
+
+ InstructionList il = new InstructionList();
+ String[] argumentNames;
+ Type[] argumentTypes;
+ if (fd.isStaticField()) {
+ argumentNames = new String[0];
+ argumentTypes = new Type[0];
+ } else {
+ argumentNames = new String[] {"base_obj"};
+ argumentTypes = new Type[] {baseType};
+ }
+ MethodGen mg = new MethodGen((Constants.ACC_PUBLIC|Constants.ACC_STATIC),
+ fieldType,
+ argumentTypes,
+ argumentNames,
+ OT_PREFIX+"get$"+fieldName,
+ class_name,
+ il, cpg);
+ if (!fd.isStaticField())
+ il.append(InstructionFactory.createLoad(baseType, 0)); // first argument is at slot 0 in static methods
+ short fieldKind = fd.isStaticField()?Constants.GETSTATIC:Constants.GETFIELD;
+ il.append(factory.createFieldAccess(class_name, fieldName, fieldType, fieldKind));
+ il.append(InstructionFactory.createReturn(fieldType));
+
+ mg.removeNOPs();
+ mg.setMaxStack();
+ mg.setMaxLocals();
+ return mg.getMethod();
+ }
+
+
+ /**
+ * Generates a setter method for the field described by 'fd' in the class 'class_name'.
+ * @param cpg the ConstantPoolGen of the class
+ * @param class_name the name of the class
+ * @param fd the FieldDescriptor describing the affected field
+ * @param factory an InstructionFactory for this class
+ * @return the generated getter method
+ */
+ private Method generateSetter(ConstantPoolGen cpg, String class_name, FieldDescriptor fd, InstructionFactory factory ) {
+ String fieldName = fd.getFieldName();
+ Type fieldType = Type.getType(fd.getFieldSignature());
+ Type baseType = new ObjectType(class_name);
+
+ Type[] argumentTypes;
+ String[] argumentNames;
+ if (fd.isStaticField()) {
+ argumentTypes = new Type[] { fieldType};
+ argumentNames = new String[] {"new_value"};
+ } else {
+ argumentTypes = new Type[] {baseType, fieldType};
+ argumentNames = new String[] {"base_obj", "new_value"};
+ }
+
+ InstructionList il = new InstructionList();
+ MethodGen mg = new MethodGen((Constants.ACC_PUBLIC|Constants.ACC_STATIC),
+ Type.VOID,
+ argumentTypes,
+ argumentNames,
+ OT_PREFIX+"set$"+fieldName,
+ class_name,
+ il, cpg);
+
+ int argumentPosition; // position for the argument holding the new field value.
+ if (!fd.isStaticField()) {
+ il.append(InstructionFactory.createLoad(baseType, 0)); // first argument is at slot 0 in static methods
+ argumentPosition = 1;
+ } else {
+ argumentPosition = 0;
+ }
+ il.append(InstructionFactory.createLoad(fieldType, argumentPosition));
+ short fieldKind = fd.isStaticField()?Constants.PUTSTATIC:Constants.PUTFIELD;
+ il.append(factory.createFieldAccess(class_name, fieldName, fieldType, fieldKind));
+ il.append(InstructionFactory.createReturn(Type.VOID));
+
+ mg.removeNOPs();
+ mg.setMaxStack();
+ mg.setMaxLocals();
+ return mg.getMethod();
+ }
+
+ private void generateSuperAccessors(ClassEnhancer ce, ClassGen cg, String class_name, ConstantPoolGen cpg) {
+ InstructionFactory factory = null;
+
+ HashSet<String> addedAccessMethods = state().generatedSuperAccessors.get(class_name);
+
+ List<SuperMethodDescriptor> methods = CallinBindingManager.getSuperAccesses(class_name);
+ if (methods != null) {
+ factory = new InstructionFactory(cg);
+ for (SuperMethodDescriptor superMethod : methods) {
+ String key = superMethod.methodName+'.'+superMethod.signature;
+ if (logging)
+ printLogMessage("Generating super access method "+key);
+ if (addedAccessMethods == null)
+ addedAccessMethods = new HashSet<String>();
+ if (addedAccessMethods.contains(key))
+ continue; // this accessor has already been created
+ ce.addMethod(generateSuperAccessor(cpg, class_name, superMethod, factory), cg);
+ addedAccessMethods.add(key);
+ state().generatedSuperAccessors.put(class_name, addedAccessMethods);
+ }
+ }
+ }
+
+ private Method generateSuperAccessor(ConstantPoolGen cpg, String className, SuperMethodDescriptor superMethod, InstructionFactory factory)
+ {
+ int endPos = superMethod.signature.indexOf(')');
+ String segment = superMethod.signature.substring(1, endPos);
+ String[] typeNames = (segment.length() > 0) ? segment.split(",") : new String[0];
+ Type[] argTypes = new Type[typeNames.length];
+ for (int i = 0; i < argTypes.length; i++)
+ argTypes[i] = Type.getType(typeNames[i]);
+
+ int index = superMethod.signature.lastIndexOf(')') + 1;
+ Type returnType = Type.getType(superMethod.signature.substring(index));
+
+ Type baseType = new ObjectType(className);
+ Type[] wrapperTypes = new Type[argTypes.length+1];
+ System.arraycopy(argTypes, 0, wrapperTypes, 1, argTypes.length);
+ wrapperTypes[0] = baseType;
+ String[] argNames = new String[wrapperTypes.length];
+ for (int i = 0; i < argNames.length; i++) {
+ argNames[i] = "arg"+i;
+ }
+ InstructionList il = new InstructionList();
+ MethodGen mg = new MethodGen((Constants.ACC_PUBLIC|Constants.ACC_STATIC),
+ returnType,
+ wrapperTypes,
+ argNames,
+ OT_PREFIX+superMethod.methodName+"$super",
+ className,
+ il, cpg);
+ il.append(InstructionFactory.createLoad(baseType, 0)); // first argument is base instance
+ for (int i = 0; i < argTypes.length; i++)
+ il.append(InstructionFactory.createLoad(argTypes[i], i+1));
+
+ // if super method is also callin bound directly invoke the orig-version
+ // (to avoid that BaseMethodTransformation.checkReplaceWickedSuper() has to rewrite this code again):
+ String methodName = (CallinBindingManager.isBoundBaseMethod(superMethod.superClass, superMethod.methodName, superMethod.signature))
+ ? genOrigMethName(superMethod.methodName)
+ : superMethod.methodName;
+
+ il.append(factory.createInvoke(superMethod.superClass, methodName, returnType, argTypes, INVOKESPECIAL));
+ il.append(InstructionFactory.createReturn(returnType));
+ mg.setMaxStack();
+ mg.setMaxLocals();
+ return mg.getMethod();
+ }
+
+}
diff --git a/othersrc/OTRE/src/org/eclipse/objectteams/otre/LiftingParticipantTransformation.java b/othersrc/OTRE/src/org/eclipse/objectteams/otre/LiftingParticipantTransformation.java
new file mode 100644
index 0000000..48e949d
--- /dev/null
+++ b/othersrc/OTRE/src/org/eclipse/objectteams/otre/LiftingParticipantTransformation.java
@@ -0,0 +1,162 @@
+/**********************************************************************
+ * This file is part of the "Object Teams Runtime Environment"
+ *
+ * Copyright 2009 Stephan Herrmann
+ *
+ * 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: LiftingParticipantTransformation.java 23408 2010-02-03 18:07:35Z stephan $
+ *
+ * Please visit http://www.objectteams.org for updates and contact.
+ *
+ * Contributors:
+ * Stephan Herrmann - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.objectteams.otre;
+
+
+import org.objectteams.Team;
+
+import de.fub.bytecode.Constants;
+import de.fub.bytecode.classfile.Method;
+import de.fub.bytecode.generic.ALOAD;
+import de.fub.bytecode.generic.BranchInstruction;
+import de.fub.bytecode.generic.ClassGen;
+import de.fub.bytecode.generic.ConstantPoolGen;
+import de.fub.bytecode.generic.DUP;
+import de.fub.bytecode.generic.GOTO;
+import de.fub.bytecode.generic.IFNULL;
+import de.fub.bytecode.generic.INVOKESPECIAL;
+import de.fub.bytecode.generic.InstructionFactory;
+import de.fub.bytecode.generic.InstructionHandle;
+import de.fub.bytecode.generic.InstructionList;
+import de.fub.bytecode.generic.LDC;
+import de.fub.bytecode.generic.MethodGen;
+import de.fub.bytecode.generic.NEW;
+import de.fub.bytecode.generic.NOP;
+import de.fub.bytecode.generic.ObjectType;
+import de.fub.bytecode.generic.POP;
+import de.fub.bytecode.generic.Type;
+
+/**
+ * If the property ot.lifting.participant is set transform all lift methods and insert
+ * static calls to createRole(Team,Object,String)Object; to the registered lifting participant
+ * before creating a new role. If createRole returns non-null then that value is taken
+ * as the new role, otherwise lifting proceeds as normal, i.e., normally creates a new role.
+ *
+ * @author stephan
+ * @since 1.3.1
+ */
+public class LiftingParticipantTransformation extends ObjectTeamsTransformation {
+
+
+ private static String PARTICIPANT_NAME = System.getProperty("ot.lifting.participant");
+ private static boolean checked = false;
+
+ final private static String LIFT_PREFIX = "_OT$liftTo";
+
+ private static final String WRONG_ROLE_EXCEPTION = "org.objectteams.WrongRoleException";
+ private static final String LIFTING_FAILED_EXCEPTION = "org.objectteams.LiftingFailedException";
+ private static final String LIFTING_VETO_EXCEPTION = "org.objectteams.LiftingVetoException";
+
+ private static final ObjectType iLiftingParticipant = new ObjectType("org.objectteams.ILiftingParticipant");
+
+ private static final String CREATE_ROLE_METHOD = "createRole";
+ private static final String LIFTING_PARTICIPANT_FIELD = "_OT$liftingParticipant";
+
+ public LiftingParticipantTransformation(SharedState state) { this(null, state); }
+
+ public LiftingParticipantTransformation(ClassLoader loader, SharedState state) { super(loader, state); }
+
+ public void doTransformCode(ClassGen cg)
+ {
+ if (PARTICIPANT_NAME == null) return;
+
+ if (!classNeedsTeamExtensions(cg)) return;
+
+ synchronized (LiftingParticipantTransformation.class) {
+ if (!checked) {
+ try {
+ // install a shared instance into class Team:
+ Class<?> participantClass = loader.loadClass(PARTICIPANT_NAME);
+ Team.class.getField(LIFTING_PARTICIPANT_FIELD).set(null, participantClass.newInstance());
+ } catch (Exception e) {
+ new IllegalArgumentException("Lifting participant "+PARTICIPANT_NAME+" is invalid.", e).printStackTrace();
+ PARTICIPANT_NAME = null;
+ }
+ checked = true;
+ }
+ }
+
+ factory = new InstructionFactory(cg);
+ ConstantPoolGen cpg = cg.getConstantPool();
+ String class_name = cg.getClassName();
+
+ // FIXME(SH): evaluate inclusion/exclusion filter per className
+
+ Method[] methods = cg.getMethods();
+ for (int i=0; i<methods.length; i++) {
+ Method m = methods[i];
+ if (!m.getName().startsWith(LIFT_PREFIX))
+ continue;
+
+ cg.replaceMethod(m, m = weaveLiftingParticipant(m, class_name, cpg));
+ }
+ }
+
+ private Method weaveLiftingParticipant(Method m, String className, ConstantPoolGen cpg) {
+ MethodGen mg = new MethodGen(m, className, cpg);
+ InstructionList il = mg.getInstructionList();
+ InstructionHandle[] ihs = il.getInstructionHandles();
+ for (int i=0; i<ihs.length; i++) {
+ InstructionHandle ih = ihs[i];
+ if (ih.getInstruction() instanceof NEW)
+ {
+ NEW newInstr = (NEW) ih.getInstruction();
+ Type newType = newInstr.getType(cpg);
+ String newTypeName = newType.toString();
+
+ // don't transform creation of these exceptions:
+ if (newTypeName.equals(LIFTING_FAILED_EXCEPTION)) continue;
+ if (newTypeName.equals(LIFTING_VETO_EXCEPTION)) continue;
+ if (newTypeName.equals(WRONG_ROLE_EXCEPTION)) continue;
+
+ ih.setInstruction(new NOP()); // keep this handle for the enclosing switch
+
+ InstructionList inset = new InstructionList();
+ // fetch instance of lifting participant from Team._OT$liftingParticipant
+ inset.append(factory.createFieldAccess(teamClassType.getClassName(),
+ LIFTING_PARTICIPANT_FIELD,
+ iLiftingParticipant,
+ Constants.GETSTATIC));
+ inset.append(new ALOAD(0)); // load the team
+ inset.append(new ALOAD(1)); // load the base
+ inset.append(new LDC(cpg.addString(newTypeName))); // load the role class name
+ inset.append(factory.createInvoke(iLiftingParticipant.getClassName(), // receiver type
+ CREATE_ROLE_METHOD, // method
+ object, // return type
+ new Type[] {teamType, object, string},// arg types
+ Constants.INVOKEINTERFACE));
+ inset.append(new DUP()); // keep value after null-check
+ BranchInstruction isNull = new IFNULL(null);
+ inset.append(isNull);
+ inset.append(factory.createCast(object, newType));
+ // let goto skip: 0: new R, 1: dup, 2: aload_0, 3: aload_1, (4: cast if needed), 4: o. 5: invokespecial<init>
+ int invokeOffset = 4;
+ if (!(ihs[i+invokeOffset].getInstruction() instanceof INVOKESPECIAL))
+ invokeOffset++;
+ inset.append(new GOTO(ihs[i+invokeOffset+1])); // one past above sequence
+
+ // continue here if null, i.e., perform the original new-instruction
+ InstructionHandle goOn = inset.append(new POP()); // discard dup'ed value from above
+ isNull.setTarget(goOn);
+ inset.append(newInstr); // re-insert deleted first instruction
+
+ il.append(ih, inset);
+ }
+ }
+ return mg.getMethod();
+ }
+}
diff --git a/othersrc/OTRE/src/org/eclipse/objectteams/otre/LowerableTransformation.java b/othersrc/OTRE/src/org/eclipse/objectteams/otre/LowerableTransformation.java
new file mode 100644
index 0000000..1db8d9f
--- /dev/null
+++ b/othersrc/OTRE/src/org/eclipse/objectteams/otre/LowerableTransformation.java
@@ -0,0 +1,72 @@
+/**********************************************************************
+ * This file is part of the "Object Teams Runtime Environment"
+ *
+ * Copyright 2009 Stephan Herrmann
+ *
+ * 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: LowerableTransformation.java 23408 2010-02-03 18:07:35Z stephan $
+ *
+ * Please visit http://www.objectteams.org for updates and contact.
+ *
+ * Contributors:
+ * Stephan Herrmann - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.objectteams.otre;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import de.fub.bytecode.Constants;
+import de.fub.bytecode.generic.ClassGen;
+import de.fub.bytecode.generic.MethodGen;
+import de.fub.bytecode.generic.Type;
+
+/**
+ * This transformer helps legacy class files pre 1.3.2 to cope with changes re ILowerable.lower().
+ *
+ * @author stephan
+ * @since 1.3.2
+ */
+public class LowerableTransformation extends ObjectTeamsTransformation {
+
+ // static because checking is performed without instance context (from scanClassOTAttribrutes)
+ // using ClassGen rather than names should, however, avoid conflicts between different class loaders etc.
+ static Set<ClassGen> transformationRequests = new HashSet<ClassGen>();
+
+ public LowerableTransformation(SharedState state) { this(null, state); }
+
+ public LowerableTransformation(ClassLoader loader, SharedState state) {
+ super(loader, state);
+ }
+
+ public void doTransformInterface(ClassEnhancer ce, ClassGen cg) {
+ synchronized (transformationRequests) {
+ if (!transformationRequests.remove(cg))
+ return;
+ }
+ // yes, a change was requested, add method "public abstract Object lower();"
+ MethodGen lower = new MethodGen(Constants.ACC_PUBLIC|Constants.ACC_ABSTRACT, object, new Type[0], new String[0], "lower", cg.getClassName(), null, cg.getConstantPool());
+ ce.addMethod(lower.getMethod(), cg);
+ }
+
+ /** After reading the compiler version of a class file, check if this class is affected by the change. */
+ public static void checkRequiresAdaptation(int major, int minor, int revision, ClassGen cg) {
+ // only 1.3.1 and below:
+ if (major > 1) return;
+ if (major == 1 && minor > 3) return;
+ if (major == 1 && minor == 3 && revision > 1) return;
+ // only interfaces ...
+ if (!cg.isInterface()) return;
+ // ... implementing ILowerabel:
+ for (String superInterface : cg.getInterfaceNames()) {
+ if ("org.objectteams.Team$ILowerable".equals(superInterface))
+ synchronized(transformationRequests) {
+ transformationRequests.add(cg);
+ return;
+ }
+ }
+ }
+}
diff --git a/othersrc/OTRE/src/org/eclipse/objectteams/otre/OTConstants.java b/othersrc/OTRE/src/org/eclipse/objectteams/otre/OTConstants.java
new file mode 100644
index 0000000..d207abd
--- /dev/null
+++ b/othersrc/OTRE/src/org/eclipse/objectteams/otre/OTConstants.java
@@ -0,0 +1,178 @@
+/**********************************************************************
+ * 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: OTConstants.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.*;
+
+
+/**
+ * Constants for the Object Teams Runtime Environment
+ * @author Christine Hundt
+ * @author Stephan Herrmann
+ */
+public interface OTConstants {
+ // ------------------------------------------
+ // ---------- Types: ------------------------
+ // ------------------------------------------
+ /** Type <tt>java.lang.Object</tt> */
+ ObjectType object = new ObjectType("java.lang.Object");
+ /** Type <tt>java.lang.Object</tt> */
+ ObjectType string = new ObjectType("java.lang.String");
+ /** Type <tt>java.lang.Class</tt> */
+ ObjectType classType = new ObjectType("java.lang.Class");
+ /** Signature of java.lang.Class#getMethod(String, Class...) */
+ public static final Type[] getMethodSignature = new Type[]{string, new ArrayType(classType, 1)};
+ /** Type <tt>java.lang.reflect.Method</tt> */
+ ObjectType methodType = new ObjectType("java.lang.reflect.Method");
+ /** Type <tt>org.objectteams.Team</tt> */
+ String teamName = "org.objectteams.ITeam";
+ ObjectType teamType = new ObjectType(teamName);
+ String teamClassName = "org.objectteams.Team";
+ ObjectType teamClassType = new ObjectType(teamClassName);
+ /** Type <tt>org.objectteams.LiftingVetoException</tt> */
+ ObjectType liftingVeto = new ObjectType("org.objectteams.LiftingVetoException");
+ /** Type <tt>org.eclipse.objectteams.otre.OTREInternalError</tt> */
+ ObjectType internalError = new ObjectType("org.eclipse.objectteams.otre.OTREInternalError");
+ /** Type <tt>org.eclipse.objectteams.otre.OTREInternalError</tt> */
+ ObjectType notProvidedError = new ObjectType("org.objectteams.ResultNotProvidedError");
+ /** Type <tt>org.eclipse.objectteams.otre.UnsupportedFeatureException</tt> */
+ ObjectType unsupportedFeature = new ObjectType("org.objectteams.UnsupportedFeatureException");
+
+ ObjectType threadType = new ObjectType("java.lang.Thread");
+
+ /** Type <tt>org.objectteams.Team[]</tt> */
+ ArrayType teamArray = new ArrayType(teamType, 1);
+ /** Type <tt>int[]</tt> */
+ ArrayType intArray = new ArrayType(Type.INT, 1);
+ /** Type <tt>java.lang.Object[]</tt> */
+ ArrayType objectArray = new ArrayType(object, 1);
+
+ ObjectType roleSetType = new ObjectType("java.util.HashSet");
+
+ ObjectType nullPointerException = new ObjectType("java.lang.NullPointerException");
+
+ String STRING_BUFFER_NAME = "java.lang.StringBuffer";
+
+ // ============ VERSION: ==============
+ public static final int OT_VERSION_MAJOR = 0;
+ public static final int OT_VERSION_MINOR = 8;
+ public static final int OT_REVISION = 18;
+
+ // required compiler revision in the 0.9 stream:
+ public static final int OT09_REVISION = 26;
+
+ // required compiler revision in the 1.0 stream:
+ public static final int OT10_REVISION = 0;
+
+ // required compiler revision in the 1.1 stream:
+ public static final int OT11_REVISION = 0;
+
+ // required compiler revision in the 1.2 stream:
+ public static final int OT12_REVISION = 0;
+
+ // required compiler revision in the 1.3 stream:
+ public static final int OT13_REVISION = 0;
+
+ // required compiler revision in the 1.4 stream:
+ public static final int OT14_REVISION = 1;
+
+ // ------------------------------------------
+ // ---------- Flags and Modifiers: ----------
+ // ------------------------------------------
+ /** Bytecode encoding of modifier <tt>team</tt> */
+ final static int TEAM = 0x8000;
+
+ // 'CallinFlags':
+ final static int OVERRIDING =1; // this role method is inherited from the super role
+ final static int WRAPPER =2; // this is a role method wrapper (in a team)
+
+ // ------------------------------------------
+ // ---------- Names: ------------------------
+ // ------------------------------------------
+ /** General prefix to mark all generated names. */
+ final static String OT_PREFIX = "_OT$";
+ /** Name of the base reference of roles. */
+ final static String BASE = "_OT$base";
+ /** Name of the getBase method of roles (ifc and class). */
+ final static String GET_BASE = "_OT$getBase";
+ /** Prefix for otdt. */
+ final static String OTDT_PREFIX = "__OT__";
+ /** Tsuper marker interface prefix. */
+ final static String TSUPER_PREFIX = "TSuper__OT__";
+ /** field for storing the class object in JVM < 5 */
+ final static String SELF_CLASS = "_OT$self_class$";
+
+ // -----------------------------------------
+ // ---------- Signature enhancement --------
+ // -----------------------------------------
+
+ /** Name of synthetic parameter. */
+ final static String TEAMS = "_OT$teams";
+ /** Name of synthetic parameter. */
+ final static String TEAMIDS = "_OT$teamIDs";
+ /** Name of synthetic parameter. */
+ final static String IDX = "_OT$idx";
+ /** Name of synthetic parameter. */
+ final static String BIND_IDX = "_OT$bindIdx";
+ /** Name of synthetic parameter. */
+ final static String UNUSED = "_OT$unusedArgs";
+ /** Name of synthetic parameter. */
+ final static String BASE_METH_TAG = "_OT$baseMethTag";
+
+ /** Number of extra arguments in enhanced signatures. */
+ static final int EXTRA_ARGS = 6;
+ /** Position of generated argument. */
+ static final int TEAMS_ARG = 1;
+ /** Position of generated argument. */
+ static final int TEAMIDS_ARG = 2;
+ /** Position of generated argument. */
+ static final int IDX_ARG = 3;
+ /** Position of generated argument. */
+ static final int BIND_IDX_ARG = 4;
+ /** Position of generated argument. */
+ static final int BASE_METH_ARG = 5; // ## really const? also UNUSED?
+ /** Position of generated argument. */
+ static final int UNUSED_ARG = 6;
+
+ // ---------- Features to prevent/aid garbage collection: ----------
+ String ROLE_SET = OT_PREFIX + "roleSet"; // field HashSet _OT$roleSet;
+ String ADD_ROLE = OT_PREFIX + "addRole"; // method void _OT$addRole(Object)
+ String REMOVE_ROLE = OT_PREFIX + "removeRole"; // method void _OT$removeRole(Object)
+
+ String IBOUND_BASE = "org.objectteams.IBoundBase"; // interface comprising the above methods.
+
+
+ // -----------------------------------------
+ // ---------- Other constants --------
+ // -----------------------------------------
+ /** Marker for comment lines in the team config file. */
+ static final String COMMENT_MARKER = "#";
+ /** Constant for invalid base method tags (a method can not be relocated from a base call). */
+ static final int INVALID_BASE_METHOD_TAG = -2;
+
+ // --------------------------------------------------------------
+ // ---------- Separator for static replace binding keys ---------
+ // --------------------------------------------------------------
+ static final String STATIC_REPLACE_BINDING_SEPARATOR = "..";
+
+ // ------------------------------------------------------------------------------------
+ // ---------- Linenumbers with more information. ----------------------
+ // ---------- (semantic linenumber) For debugging purpose. ------
+ // ------------------------------------------------------------------------------------
+ static final int STEP_OVER_LINENUMBER = Short.MAX_VALUE *2;
+ static final int STEP_INTO_LINENUMBER = STEP_OVER_LINENUMBER - 1;
+}
diff --git a/othersrc/OTRE/src/org/eclipse/objectteams/otre/OTREInternalError.java b/othersrc/OTRE/src/org/eclipse/objectteams/otre/OTREInternalError.java
new file mode 100644
index 0000000..04110e2
--- /dev/null
+++ b/othersrc/OTRE/src/org/eclipse/objectteams/otre/OTREInternalError.java
@@ -0,0 +1,62 @@
+/**********************************************************************
+ * This file is part of the "Object Teams Runtime Environment"
+ *
+ * Copyright 2003-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$
+ *
+ * Please visit http://www.objectteams.org for updates and contact.
+ *
+ * Contributors:
+ * Berlin Institute of Technology - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.objectteams.otre;
+
+/**
+ * @author stephan
+ */
+public class OTREInternalError extends Error {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+ private static final String _bugmsg =
+ "An error occurred in the Object Teams runtime environment.\n"+
+ "We would appreciate if you send a bug report to bugs@ObjectTeams.org.\n"+
+ "Please include your program (if possible) and the following diagnostic\n"+
+ "in your report. -- Thank you. The OT/J developers\n";
+ /**
+ *
+ */
+ public OTREInternalError() {
+ super(_bugmsg);
+ }
+
+ /**
+ * @param message
+ */
+ public OTREInternalError(String message) {
+ super(_bugmsg+message);
+ }
+
+ /**
+ * @param cause
+ */
+ public OTREInternalError(Throwable cause) {
+ super(_bugmsg+cause.toString());
+ }
+
+ /**
+ * @param message
+ * @param cause
+ */
+ public OTREInternalError(String message, Throwable cause) {
+ super(_bugmsg+message+cause.toString());
+ }
+
+}
diff --git a/othersrc/OTRE/src/org/eclipse/objectteams/otre/ObjectTeamsTransformation.java b/othersrc/OTRE/src/org/eclipse/objectteams/otre/ObjectTeamsTransformation.java
new file mode 100644
index 0000000..7158659
--- /dev/null
+++ b/othersrc/OTRE/src/org/eclipse/objectteams/otre/ObjectTeamsTransformation.java
@@ -0,0 +1,2259 @@
+/**********************************************************************
+ * 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: ObjectTeamsTransformation.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 java.io.BufferedReader;
+import java.io.FileInputStream;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.eclipse.objectteams.otre.util.AnnotationHelper;
+import org.eclipse.objectteams.otre.util.AttributeReadingGuard;
+import org.eclipse.objectteams.otre.util.CallinBindingManager;
+import org.eclipse.objectteams.otre.util.RoleBaseBinding;
+
+import de.fub.bytecode.Constants;
+import de.fub.bytecode.Repository;
+import de.fub.bytecode.classfile.Attribute;
+import de.fub.bytecode.classfile.Constant;
+import de.fub.bytecode.classfile.ConstantUtf8;
+import de.fub.bytecode.classfile.InnerClass;
+import de.fub.bytecode.classfile.InnerClasses;
+import de.fub.bytecode.classfile.JavaClass;
+import de.fub.bytecode.classfile.LineNumberTable;
+import de.fub.bytecode.classfile.Method;
+import de.fub.bytecode.classfile.Unknown;
+import de.fub.bytecode.generic.*;
+
+/**
+ * Superclass for all transformations in this package.
+ * This class and its subclasses depends on neither JMangler nor JPLIS.
+ *
+ * Contains common fields and methods.
+ *
+ * @author Christine Hundt
+ * @author Stephan Herrmann
+ */
+public abstract class ObjectTeamsTransformation
+ implements OTConstants
+{
+
+ // ------------------------------------------
+ // ---------- Flags: ------------------------
+ // ------------------------------------------
+
+ /** Check whether <tt>flags</tt> denote a generated callin wrapper. */
+ static boolean isCallinWrapper(Method m, ClassGen cg) {
+ return methodHasCallinFlags(m, cg, WRAPPER);
+ }
+
+ /** Check whether <tt>flags</tt> denote a callin method from the source code. */
+ static boolean isCallin(Method m, ClassGen cg) {
+ return (methodHasCallinFlags(m, cg, 0) && !isCallinWrapper(m, cg));
+ }
+
+
+ // ------------------------------------------
+ // ---------- Names: ------------------------
+ // ------------------------------------------
+
+ /** Generate the name for a backup of a method. */
+ static String genOrigMethName(String methName) {
+ return "_OT$" + methName + "$orig";
+ }
+
+ /** Generate the name for a chaining wrapper. */
+ static String genChainMethName(String methName) {
+ return "_OT$" + methName + "$chain";
+ }
+
+ static ArrayList<ObjectTeamsTransformation> reentrentTransformations = new ArrayList<ObjectTeamsTransformation>();
+
+ /** Common factory for all tranformers.
+ * To be initialized once we get a class for transformation. */
+ InstructionFactory factory;
+
+ /** State shared among all instances that work for the same class loader. */
+ public static class SharedState {
+ /** ArrayList of classes whose interfaces have already been transformed by this transformer/classloader combo. */
+ ArrayList<String> interfaceTransformedClasses = new ArrayList<String>();
+ }
+ /** Reference to the shared state of transformers. */
+ final SharedState state;
+
+ SharedState state() {
+ return state;
+ }
+
+ /** Which class loader are we working for? */
+ protected ClassLoader loader;
+
+ public ObjectTeamsTransformation(SharedState state) { this(null, state); }
+
+ public ObjectTeamsTransformation(ClassLoader loader, SharedState state) {
+ this.loader = loader;
+ this.state = state;
+ }
+
+ // ------------------------------------------
+ // ---------- Logging: ----------------------
+ // ------------------------------------------
+ /** Initialized from property <tt>ot.log</tt>. */
+ static boolean logging = false;
+
+ static {
+ if(System.getProperty("ot.log") != null)
+ logging = true;
+ }
+
+ /** Print <tt>message</tt> only if <tt>logging</tt> is true. */
+ public static void printLogMessage(String message) {
+ System.out.println(message);
+ }
+
+ // ------------------------------------------
+ // ---------- use the following file as config file for additional active teams: --------
+ // ------------------------------------------
+ /** Initialized from property <tt>ot.teamconfig</tt>. */
+
+ static String TEAM_CONFIG_FILE = null;
+
+ static {
+ TEAM_CONFIG_FILE = System.getProperty("ot.teamconfig");
+ }
+
+ // ------------------------------------------
+ // ---------- Compatibility with different compiler versions: --------
+ // ------------------------------------------
+
+ // compiler 1.2.4 introduces isSuperAccess flag for basecall surrogate:
+ protected static boolean IS_COMPILER_GREATER_123 = false;
+
+ protected static boolean IS_COMPILER_13X_PLUS = false;
+
+ protected static boolean IS_COMPILER_14X_PLUS = false;
+
+ // ------------------------------------------
+ // ---------- This flag must currently be true for OT/Equinox: ----------------------
+ // ------------------------------------------
+ /** Initialized from property <tt>ot.equinox</tt>. */
+ public static boolean WORKAROUND_REPOSITORY = false;
+
+ static {
+ if(System.getProperty("ot.equinox") != null)
+ WORKAROUND_REPOSITORY = true;
+ }
+
+ // ------------------------------------------
+ // ---------- Debugging: ----------------------
+ // ------------------------------------------
+ /** Initialized from property <tt>ot.debug</tt>. */
+ static boolean debugging = false;
+
+ static {
+ if(System.getProperty("ot.debug") != null)
+ debugging = true;
+ }
+
+ // -------------------------------------------------------
+ // ---------- Modes for implicit team activateion --------
+ // -------------------------------------------------------
+ enum ImplicitActivationMode { NEVER, ANNOTATED, ALWAYS }
+ static ImplicitActivationMode implicitActivationMode = ImplicitActivationMode.ANNOTATED;
+ static {
+ String prop = System.getProperty("ot.implicit.team.activation");
+ for (ImplicitActivationMode mode : ImplicitActivationMode.values()) {
+ if (mode.name().equals(prop)) {
+ implicitActivationMode = mode;
+ break;
+ }
+ }
+ }
+
+ // -----------------------------------------
+ // ---------- Signature enhancement --------
+ // -----------------------------------------
+
+ /**
+ * Prepend hidden arguments to the signature.
+ * This methods only treats argument names.
+ * @see #enhanceArgumentTypes
+ * The arguments are:
+ * <dl>
+ * <dt><tt>Team[] _OT$teams</tt></dt>
+ * <dd>array of active Teams affecting the current base method.
+ * <dt><tt>int[] _OT$teamIDs</tt></dt>
+ * <dd>array of IDs of the above Teams.
+ * <dt><tt>int _OT$idx</tt></dt>
+ * <dd>index into above arrays: the Team currently being processed.
+ * <dt><tt>Object[] _OT$unusedArgs</tt></dt>
+ * <dd>array of arguments which are unused by the current role method.
+ * </dl>
+ * @param argumentNames array of original argument names.
+ * @return augmented array of argument names.
+ */
+ static String[] enhanceArgumentNames(String[] argumentNames) {
+ return enhanceArgumentNames(argumentNames, 0);
+ }
+
+ /**
+ * Prepend hidden arguments to the signature.
+ * This methods only treats argument names.
+ * @see #enhanceArgumentTypes
+ * The arguments are:
+ * <dl>
+ * <dt><tt>Team[] _OT$teams</tt></dt>
+ * <dd>array of active Teams affecting the current base method.
+ * <dt><tt>int[] _OT$teamIDs</tt></dt>
+ * <dd>array of IDs of the above Teams.
+ * <dt><tt>int _OT$idx</tt></dt>
+ * <dd>index into above arrays: the Team currently being processed.
+ * <dt><tt>Object[] _OT$unusedArgs</tt></dt>
+ * <dd>array of arguments which are unused by the current role method.
+ * </dl>
+ * @param argumentNames array of original argument names.
+ * @param idx position where new arguments should be inserted into
+ * <tt>originalArgumentTypes</tt>.
+ * @return augmented array of argument names.
+ */
+ static String[] enhanceArgumentNames(String[] argumentNames, int idx) {
+
+ String[] enhancedArgumentNames =
+ new String[argumentNames.length + EXTRA_ARGS];
+
+ for (int j=0; j<idx; j++)
+ enhancedArgumentNames[j] = argumentNames[j];
+
+ enhancedArgumentNames [idx + TEAMS_ARG - 1] = TEAMS;
+ enhancedArgumentNames [idx + TEAMIDS_ARG - 1] = TEAMIDS;
+ enhancedArgumentNames [idx + IDX_ARG - 1] = IDX;
+ enhancedArgumentNames [idx + BIND_IDX_ARG - 1] = BIND_IDX;
+ enhancedArgumentNames [idx + BASE_METH_ARG - 1] = BASE_METH_TAG;
+ enhancedArgumentNames [idx + UNUSED_ARG - 1] = UNUSED;
+
+ for (int j = idx; j < argumentNames.length; j++)
+ enhancedArgumentNames[j + EXTRA_ARGS] = argumentNames[j];
+
+ return enhancedArgumentNames;
+ }
+
+ /**
+ * @see #enhanceArgumentTypes(Type[])
+ * @param signature String from which to extract the argument types.
+ * @return
+ */
+ static Type[] enhanceArgumentTypes(String signature) {
+ Type[] types = Type.getArgumentTypes(signature);
+ return enhanceArgumentTypes(types);
+ }
+
+ /**
+ * Prepend hidden arguments to the signature.
+ * This methods only treats argument types.
+ * @see #enhanceArgumentNames
+ *
+ * @param originalArgumentTypes array of original argument types.
+ * @return augmented array of argument names.
+ */
+ static Type[] enhanceArgumentTypes(Type[] originalArgumentTypes) {
+ return enhanceArgumentTypes(originalArgumentTypes, 0, true);
+ }
+
+ /**
+ * Prepend hidden arguments to the signature.
+ * This methods only treats argument types.
+ * @see #enhanceArgumentNames
+ *
+ * @param originalArgumentTypes array of original argument types.
+ * @param idx position where new arguments should be inserted into
+ * <tt>originalArgumentTypes</tt>.
+ * @param createUnused should the <tt>unusedArgs</tt> argument be created?
+ * @return augmented array of argument types.
+ */
+ static Type[] enhanceArgumentTypes(Type[] originalArgumentTypes,
+ int idx,
+ boolean createUnused)
+ {
+ // creates enhanced argument type array:
+ // ..(a1,.., aN) -> ..(Team[], int[], int, Object[], a1, .., aN)
+ int offset = createUnused ? EXTRA_ARGS : EXTRA_ARGS-1;
+
+ Type[] enhancedArgumentTypes =
+ new Type[originalArgumentTypes.length+offset];
+
+ for (int j=0; j<idx; j++)
+ enhancedArgumentTypes[j] = originalArgumentTypes[j];
+
+ enhancedArgumentTypes [idx+TEAMS_ARG - 1] = teamArray;
+ enhancedArgumentTypes [idx+TEAMIDS_ARG - 1] = intArray;
+ enhancedArgumentTypes [idx+IDX_ARG - 1] = Type.INT;
+ enhancedArgumentTypes [idx+BIND_IDX_ARG - 1] = Type.INT;
+ enhancedArgumentTypes [idx+BASE_METH_ARG - 1] = Type.INT;
+ if (createUnused) {
+ enhancedArgumentTypes [idx+UNUSED_ARG - 1] = objectArray;
+ }
+
+ for (int j = idx; j < originalArgumentTypes.length; j++)
+ enhancedArgumentTypes[j + EXTRA_ARGS] = originalArgumentTypes[j];
+
+ return enhancedArgumentTypes;
+ }
+
+ /**
+ * Remove the arguments previously added by
+ * {@link #enhanceArgumentTypes enhanceArgumentTypes}.
+ *
+ * @param enhancedArgumentTypes
+ * @param staticFlag
+ * @return
+ */
+ // FIXME(SH): obsolete
+ public static Type[] _retrenchArgumentTypes(Type[] enhancedArgumentTypes, boolean staticFlag) {
+ // create retrenched argument type array:
+ // ..(Team[], int[], int, Object[], a1, .., aN) -> ..(a1,.., aN)
+
+ int offset = staticFlag? -1 : 0;
+
+ Type[] retrenchedArgumentTypes =
+ new Type[enhancedArgumentTypes.length - EXTRA_ARGS + offset];
+
+ for (int j = EXTRA_ARGS; j < enhancedArgumentTypes.length + offset; j++)
+ retrenchedArgumentTypes[j - EXTRA_ARGS] = enhancedArgumentTypes[j];
+
+ return retrenchedArgumentTypes;
+ }
+
+ // ---------------------------------------------------
+ // ---------- further type and value conversions -----
+ // ---------------------------------------------------
+
+ /**
+ * @see #generalizeReturnType(Type)
+ * @param signature String from which to extract the return type.
+ */
+ static Type generalizeReturnType (String signature) {
+ Type type = Type.getReturnType(signature);
+ return generalizeReturnType(type);
+ }
+
+ /**
+ * Given a return type, determine a reference type to which this type can be
+ * converted. "Object" if type is VOID.
+ *
+ * @param type
+ * @return
+ */
+ static Type generalizeReturnType (Type type) {
+ if (type instanceof ReferenceType) return type;
+ return object;
+ }
+
+ /**
+ * Get the generalized return type from <tt>sign1</tt>, unless
+ * <tt>sing2</tt> has void return type. In the latter case return
+ * <tt>Object</tt>.
+ *
+ * @see #generalizeReturnType(Type)
+ * @param sign1
+ * @param sign2
+ * @return
+ */
+ static Type generalizeReturnType (String sign1, String sign2) {
+ Type type = Type.getReturnType(sign2);
+ if (type == Type.VOID) return object;
+ return generalizeReturnType(sign1);
+ }
+
+ /**
+ * Assuming a value of type <tt>oldType</tt> on the stack, convert it to a
+ * value of type <tt>newType</tt>. Changes instruction list <tt>il</tt>
+ * after position <tt>ih</tt> or at its end if <tt>ih</tt> is null.
+ *
+ * @param il
+ * @param ih
+ * @param oldType
+ * @param newType
+ * @return the first inserted instruction or null if no adjustment needed
+ */
+ InstructionHandle adjustValue (InstructionList il, InstructionHandle ih,
+ Type oldType, Type newType) {
+ if (ih == null)
+ ih = il.getEnd();
+ if (oldType.equals(newType))
+ return null;
+
+ if (newType == Type.VOID)
+ return il.append(ih, new POP());
+ else if (oldType == Type.VOID)
+ return il.append(ih, InstructionFactory.ACONST_NULL);
+ else if (oldType instanceof BasicType)
+ return il.append(ih, createBoxing((BasicType)oldType));
+ else if (newType instanceof BasicType)
+ return il.append(ih, createUnboxing((BasicType)newType));
+ else
+ return il.append(ih, factory.createCast(oldType, newType));
+ }
+
+ // ------------------------------------------
+ // ---------- (Un-)Boxing: ------------------
+ // ------------------------------------------
+
+ /**
+ * Get the name of the class suitable for boxing <tt>basicType</tt>.
+ *
+ * @param basicType
+ * @return
+ */
+ static String toObjectTypeName(BasicType basicType) {
+ String result = "";
+ switch (basicType.getType()) {
+ case Constants.T_BOOLEAN : result = "java.lang.Boolean"; break;
+ case Constants.T_INT : result = "java.lang.Integer"; break;
+ case Constants.T_FLOAT : result = "java.lang.Float"; break;
+ case Constants.T_DOUBLE : result = "java.lang.Double"; break;
+ case Constants.T_SHORT : result = "java.lang.Short"; break;
+ case Constants.T_BYTE : result = "java.lang.Byte"; break;
+ case Constants.T_CHAR : result = "java.lang.Character"; break;
+ case Constants.T_LONG : result = "java.lang.Long"; break;
+ default: throw new Error("OTRE failure: Basic Type not supported!!"+basicType);
+ }
+ return result;
+ }
+
+ /**
+ * Create the instructions needed for boxing a basic type value. The value
+ * is expected on the stack an will be replaced by the boxed value.
+ *
+ * @param basicType type of the value on the stack.
+ * @return an InstructionList containing the conversion instructions.
+ */
+ InstructionList createBoxing(BasicType basicType) {
+ InstructionList il = new InstructionList();
+ String boxedTypeName = toObjectTypeName(basicType);
+ // .., result
+ il.append(factory.createNew(boxedTypeName)); // .., result, box,
+
+ if (basicType.equals(Type.DOUBLE) || basicType.equals(Type.LONG)) {
+ // 'double' and 'long' are category 2 computational type:
+ il.append(new DUP_X2()); // .., box, result, box
+ il.append(new DUP_X2()); // .., box, box, result, box
+ } else {
+ il.append(new DUP_X1()); // .., box, result, box
+ il.append(new DUP_X1()); // .., box, box, result, box
+ }
+ il.append(new POP()); // .., box, box, result
+ il.append(factory.createInvoke(boxedTypeName,
+ Constants.CONSTRUCTOR_NAME,
+ Type.VOID,
+ new Type[] { basicType },
+ Constants.INVOKESPECIAL));
+ return il;
+ }
+
+ /**
+ * Create the instructions needed for unboxing a basic type value. The value
+ * is expected on the stack an will be replaced by the unboxed value.
+ *
+ * @param basicType expected type after unboxing.
+ * @return an InstructionList containing the conversion instructions.
+ */
+ InstructionList createUnboxing(BasicType basicType) {
+ InstructionList il = new InstructionList();
+ String boxedTypeName = toObjectTypeName(basicType);
+ il.append(factory.createCast(object,
+ new ObjectType(boxedTypeName)));
+ il.append(factory.createInvoke(boxedTypeName,
+ basicType.toString() + "Value",
+ basicType,
+ Type.NO_ARGS,
+ Constants.INVOKEVIRTUAL));
+ return il;
+ }
+
+ /** Push an integer constant using the most appropriate/compact instruction. */
+ Instruction createIntegerPush(ConstantPoolGen cpg, int val) {
+ if (val <= 5)
+ return new ICONST(val);
+ if (val <= Byte.MAX_VALUE)
+ return new BIPUSH((byte)val);
+ if (val <= Short.MAX_VALUE)
+ return new SIPUSH((short)val);
+ return new LDC(cpg.addInteger(val));
+ }
+
+ /**
+ * Create a throwing instruction for an OTREInternalError.
+ *
+ * @param cpg
+ * @param il instruction list to generate into
+ * @param messagePush push sequence producing the exception message.
+ * @return handle to the first generated instruction
+ */
+ InstructionHandle createThrowInternalError(ConstantPoolGen cpg, InstructionList il, InstructionList messagePush) {
+ InstructionHandle start = il.append(factory.createNew(OTConstants.internalError));
+ il.append(new DUP());
+ il.append(messagePush);
+ il.append(factory.createInvoke(OTConstants.internalError.getClassName(),
+ Constants.CONSTRUCTOR_NAME,
+ Type.VOID,
+ new Type[] { Type.STRING },
+ Constants.INVOKESPECIAL));
+ il.append(new ATHROW());
+ return start;
+ }
+
+ /**
+ * Create a lookswitch from its constituents. Since JVM 1.4 this requires
+ * sorting of matches.
+ *
+ * @param matches
+ * @param targets
+ * @param breaks an array of breaks (GOTOs) whose target will
+ * be updated to point to <tt>afterSwitch</tt>
+ * @param defaultBranch
+ * @param afterSwitch
+ * @return the generated instruction.
+ */
+ static BranchInstruction createLookupSwitch (int[] matches,
+ InstructionHandle[] targets,
+ GOTO[] breaks,
+ InstructionHandle defaultBranch,
+ InstructionHandle afterSwitch) {
+
+ int numberOfCases = matches.length;
+ for (int i = 0; i < numberOfCases; i++)
+ breaks[i].setTarget(afterSwitch);
+
+ HashMap<Integer, InstructionHandle> match_target_mapping = new HashMap<Integer, InstructionHandle>();
+ for (int i = 0; i < numberOfCases; i++)
+ match_target_mapping.put(Integer.valueOf(matches[i]), targets[i]);
+
+ Arrays.sort(matches);
+ for (int i = 0; i < numberOfCases; i++)
+ targets[i] = match_target_mapping.get(Integer.valueOf(matches[i]));
+
+ BranchInstruction inst = new LOOKUPSWITCH(matches, targets, defaultBranch);
+ return inst;
+ }
+
+
+ /**
+ * Read all byte code attributes for a given class. Side-Effect: depending
+ * on the Referenced-Team attribute, additional classes may be scheduled for
+ * loading.
+ *
+ * @param ce
+ * @param cg
+ * @param class_name
+ * @param cpg
+ */
+ public void checkReadClassAttributes(ClassEnhancer ce,
+ ClassGen cg,
+ String class_name,
+ ConstantPoolGen cpg)
+ {
+ AttributeReadingGuard guard = AttributeReadingGuard.getInstanceForLoader(this.loader);
+ boolean addTeamInitializations = false;
+ List<String> classesToLoad;
+ synchronized (guard) {
+ if (!guard.iAmTheFirst(class_name))
+ return;
+ if (AttributeReadingGuard.isFirstLoadedClass())
+ addTeamInitializations = true;
+ // scan for attributes here, because this transformer is applied first:
+ Attribute[] attrsClass = cg.getAttributes();
+ classesToLoad = scanClassOTAttributes(attrsClass, class_name, cpg, cg);
+
+ guard.workDone(class_name);
+ }
+ if (addTeamInitializations)
+ addTeamInitializations(cg, ce);
+
+ Iterator<String> it = classesToLoad.iterator();
+ while (it.hasNext()) {
+ String next = it.next();
+ if(logging) printLogMessage("Loading of class " + next + " will be forced now!");
+ ce.loadClass(next, this);
+ }
+
+ // scan for parameter bindings:
+ Method[] possibleRoleMethods = cg.getMethods();
+ for (int i=0; i<possibleRoleMethods.length; i++) {
+ Method meth = possibleRoleMethods[i];
+ Attribute[] attrsMethod = meth.getAttributes();
+ scanMethodOTAttributes(attrsMethod, class_name, meth.getName(), cpg);
+ }
+ if(logging) printLogMessage(this.getClass().getName()
+ + " picked up the attributes for class " + class_name );
+ }
+
+ // --- helpers for adding line numbers at the front of a method ---
+ // unfortunately BCEL does not sort line numbers, but the debugger expects them sorted.
+ class Pair<F,S> {
+ F first;
+ S second;
+ Pair(F f, S s) {
+ this.first = f;
+ this.second = s;
+ }
+ }
+ @SuppressWarnings("unchecked") // can't declare array of generics
+ Pair<InstructionHandle, Integer>[] saveLineNumbers(MethodGen method, ConstantPoolGen cpg) {
+ LineNumberTable lnt = method.getLineNumberTable(cpg);
+ InstructionHandle[] ihs = method.getInstructionList().getInstructionHandles();
+ Pair<InstructionHandle, Integer>[] oldLines = new Pair[lnt.getTableLength()];
+ {
+ int cur = -1;
+ int n = 0;
+ for (int i=0; i<ihs.length; i++) {
+ int next = lnt.getSourceLine(ihs[i].getPosition());
+ if (next > cur) // reached a new source line
+ oldLines[n++] = new Pair<InstructionHandle, Integer>(ihs[i], new Integer(next));
+ cur = next;
+ }
+ }
+ return oldLines;
+ }
+ /** Append the saved line numbers to the end of the method's line number table. */
+ void restoreLineNumbers(MethodGen method, Pair<InstructionHandle, Integer>[] oldLines) {
+ for (int i=0; i<oldLines.length; i++) {
+ if (oldLines[i] == null)
+ continue;
+ InstructionHandle ih = oldLines[i].first;
+ int line = oldLines[i].second.intValue();
+ method.addLineNumber(ih, line);
+ }
+ }
+
+ /**
+ * Adds team initialization for all teams in the config file.
+ *
+ * @param cg
+ * @param ce
+ */
+ private void addTeamInitializations(ClassGen cg, ClassEnhancer ce) {
+ String main_class_name = cg.getClassName();
+ ConstantPoolGen cpg = cg.getConstantPool();
+ InstructionFactory factory = new InstructionFactory(cpg);
+ Method main = cg.containsMethod("main", "([Ljava/lang/String;)V");
+ if (main == null) {
+ // JPLIS launching may intercept system classes before the custom main.
+ // reset the guard in order to retry with subsequent classes.
+ AttributeReadingGuard.reset();
+ return; // no main method in the first loaded class...
+ }
+
+ MethodGen mainMethod = new MethodGen(main, main_class_name, cpg);
+ InstructionList il = mainMethod.getInstructionList();
+
+ int startLine = -1;
+ Pair<InstructionHandle,Integer>[] oldLines = null;
+ if (debugging) {
+ LineNumberTable lnt = mainMethod.getLineNumberTable(cpg);
+ if (lnt != null) {
+ startLine = lnt.getSourceLine(0);
+ oldLines = saveLineNumbers(mainMethod, cpg);
+ }
+ }
+
+ if (TEAM_CONFIG_FILE != null) {
+
+ InstructionList teamInitializations = new InstructionList();
+ List<String> teamsToInitialize = getTeamsFromConfigFile();
+ Iterator<String> teamIt = teamsToInitialize.iterator();
+ while (teamIt.hasNext()) {
+ String nextTeam = teamIt.next();
+ JavaClass teamClass = Repository.lookupClass(nextTeam);
+ if (teamClass == null) {
+ System.err.println("Config error: Team class '"+nextTeam+ "' in config file '"+ TEAM_CONFIG_FILE+"' can not be found!");
+ System.err.println("Main class = "+main_class_name+
+ ", class loader = "+(this.loader!=null?this.loader.getClass().getName():"null")+
+ ", transformer = "+this.getClass().getName());
+ continue;
+ }
+ ClassGen teamClassGen = new ClassGen(teamClass);
+ if (teamClassGen.containsMethod(Constants.CONSTRUCTOR_NAME, "()V") == null) {
+ System.err.println("Activation failed: Team class '"+nextTeam+ "' has no default constuctor!");
+ continue;
+ }
+ ce.loadClass(nextTeam, this);
+ if (logging)
+ printLogMessage("Adding initialization of team " + nextTeam
+ + " to main method of class " + main_class_name);
+ teamInitializations.append(factory.createNew(nextTeam));
+ teamInitializations.append(new DUP());
+ teamInitializations.append(factory.createInvoke(nextTeam,
+ Constants.CONSTRUCTOR_NAME,
+ Type.VOID,
+ Type.NO_ARGS,
+ Constants.INVOKESPECIAL));
+ teamInitializations.append(factory.createGetStatic(OTConstants.teamClassName,
+ "ALL_THREADS",
+ OTConstants.threadType));
+ teamInitializations.append(factory.createInvoke(nextTeam,
+ "activate",
+ Type.VOID,
+ new Type[] {OTConstants.threadType},
+ Constants.INVOKEVIRTUAL));
+ }
+ il.insert(teamInitializations);
+ }
+ // register main thread with TeamThreadManager:
+ InstructionHandle cursor;
+ cursor = il.insert(new ICONST(1)); // isMain=true
+ cursor = il.append(cursor, new ACONST_NULL()); // parent=null
+ cursor = il.append(cursor, factory.createInvoke("org.objectteams.TeamThreadManager",
+ "newThreadStarted",
+ Type.BOOLEAN,
+ new Type[]{Type.BOOLEAN, OTConstants.threadType},
+ Constants.INVOKESTATIC));
+ cursor = il.append(cursor, new POP()); // don't use boolean return
+
+ il.setPositions();
+ if (debugging && startLine > 0) {
+ mainMethod.removeLineNumbers(); // fresh start, to ensure correct order
+ mainMethod.addLineNumber(il.getStart(), startLine-1); // new number to the front
+ restoreLineNumbers(mainMethod, oldLines); // append old numbers
+ }
+ mainMethod.setInstructionList(il);
+ mainMethod.setMaxStack();
+ mainMethod.setMaxLocals();
+
+ cg.replaceMethod(main, mainMethod.getMethod());
+ }
+
+ /**
+ * @return a list of teams in the team initialization config file
+ */
+ private static List<String> getTeamsFromConfigFile() {
+ List<String> result = new LinkedList<String>();
+ try {
+ FileInputStream fstream = new FileInputStream(TEAM_CONFIG_FILE);
+ BufferedReader in = new BufferedReader(new InputStreamReader(fstream));
+ while (in.ready()) {
+ String nextLine = in.readLine();
+ String nextTeam = nextLine.trim();
+ if (nextTeam.startsWith(COMMENT_MARKER))
+ continue; // this is a comment line
+ if (!nextTeam.equals("")) {
+ result.add(nextTeam.trim());
+ }
+ }
+ in.close();
+ } catch (Exception e) {
+ System.err.println("File input error: config file '" + TEAM_CONFIG_FILE + "' can not be found!");
+ }
+ return result;
+ }
+
+ // -------------------------------------------------------------------------------------------------
+ // -------- store and return adapted bases for OT/Equinox --------------
+ // this data is collected by scanClassOTAttributes and must be collected by the caller
+ // before processing the next class.
+ // -------------------------------------------------------------------------------------------------
+ public HashSet<String> adaptedBases = new HashSet<String>();
+
+ /** Internal API for {@link org.eclipse.objectteams.otre.jplis.ObjectTeamsTransformer} */
+ public Collection<String> fetchAdaptedBases() {
+ HashSet<String> result;
+ result = new HashSet<String>(adaptedBases);
+ adaptedBases.clear();
+ return result;
+ }
+
+ // -------------------------------------------------------------------------------------------------
+ /**
+ * Container for base method properties
+ */
+ public static class BaseMethodInfo {
+ private String baseClassName;
+ private String baseMethodName;
+ private String baseMethodSignature;
+ boolean isCallin;
+ private boolean isRoleMethod;
+ boolean isStatic;
+ private int[] parameterPositions;
+ int translationFlags;
+
+ BaseMethodInfo(String base_class_name, String base_method_name,
+ String base_method_signature, boolean isCallin,
+ boolean isRoleMethod, boolean isStatic,
+ int[] parameter_positions, int translationFlags)
+ {
+ this.baseClassName = base_class_name;
+ this.baseMethodName = base_method_name;
+ this.baseMethodSignature = base_method_signature;
+ this.isCallin = isCallin;
+ this.isRoleMethod = isRoleMethod;
+ this.isStatic = isStatic;
+ this.parameterPositions = parameter_positions;
+ this.translationFlags = translationFlags;
+ }
+ /** Minimal version to pass some info into #translateLoads(): */
+ BaseMethodInfo(boolean isCallin, boolean isStatic, int translationFlags)
+ {
+ this.isCallin = isCallin;
+ this.isStatic = isStatic;
+ this.translationFlags = translationFlags;
+ }
+
+ public boolean isStaticRoleMethod() {
+ return this.isRoleMethod && this.isStatic;
+ }
+
+ String getBaseClassName() {
+ return baseClassName;
+ }
+
+ String getBaseMethodName() {
+ return baseMethodName;
+ }
+
+ String getBaseMethodSignature() {
+ return baseMethodSignature;
+ }
+
+ int[] getParameterPositions() {
+ return parameterPositions;
+ }
+ }
+
+ /**
+ * Scan the Attributes found in the class class_name for binding attributes
+ * and registers them in the CallinBindingManager.
+ *
+ * @param attributes the Attributes to be examined
+ * @param class_name the name of the class where the Attributes were found
+ * @param cpg the classes ConstantPoolGen
+ * @return an ArrayList containing the names of classes which have
+ * to be loaded immediately
+ */
+ ArrayList<String> scanClassOTAttributes(Attribute[] attributes,
+ String class_name,
+ ConstantPoolGen cpg,
+ ClassGen cg)
+ {
+ if(logging) printLogMessage("Inspecting " + class_name);
+ ArrayList<String> classesToLoad = new ArrayList<String>();
+ String base_class_name = null;
+ for (int k=0; k<attributes.length; k++) {
+ Attribute actAttr = attributes[k];
+ Unknown attr = isOTAttribute(actAttr);
+
+ if (attr != null) { //this is a callin attribute
+ String attrName = attr.getName();
+ if(logging) printLogMessage("CallinBindingAttribute: " + attrName);
+ byte[] indizes = attr.getBytes();
+ int count = combineTwoBytes(indizes, 0);
+ int numberOfEntries=0;
+ String [] names;
+ if (attrName.equals("OTClassFlags")) {
+ int classFlags = combineTwoBytes(indizes, 0);
+ String flagsString = "";
+ if ((classFlags & 1) != 0) {
+ flagsString = "team ";
+ // TODO: use this instead of team modifier
+ }
+ if ((classFlags & 2) != 0) {
+ flagsString += "role";
+ CallinBindingManager.addRole(class_name);
+ }
+ if (logging) {
+ printLogMessage("OTClassFlags:");
+ printLogMessage("\t" + flagsString);
+ }
+ } else if (attrName.equals("CallinRoleBaseBindings")) {
+ numberOfEntries = 2;
+ int i = 2;
+ int n = 2 * count * numberOfEntries; // n = count << 2;
+ names = new String[numberOfEntries];
+ while (i <= n) {
+ i = scanStrings(names, indizes, i, cpg);
+ String role_name = names[0];
+ String base_name = names[1];
+ if(logging) printLogMessage("**** Binding: " + role_name
+ + " playedBy " + base_name);
+
+ //set binding:
+ CallinBindingManager.addRoleBaseBinding(role_name, base_name, class_name);
+ CallinBindingManager.addTeamBaseRelation(class_name, base_name);
+
+ // [OT/Equinox] store adapted bases:
+ adaptedBases.add(base_name);
+
+ // super roles have to be loaded first for binding inheritance purpose:
+ // not necessary anymore?
+ //classesToLoad.addAll(getSuperRoles(role_name, attributes, cpg));
+ // roles themselve have to be loaded too:
+ classesToLoad.add(role_name);
+ }
+ } else if (attrName.equals("BoundClassesHierarchy")) {
+ numberOfEntries = 2;
+ int i = 2;
+ int n = 2 * count * numberOfEntries; // n = count << 2;
+ names = new String[numberOfEntries];
+ while (i <= n) {
+ i = scanStrings(names, indizes, i, cpg);
+ String sub_name = names[0];
+ String super_name = names[1];
+
+ CallinBindingManager.addBoundSuperclassLink(sub_name, super_name);
+ if(logging)printLogMessage("**** super-class link: "+sub_name
+ +" -> "+super_name);
+ }
+ } else if (attrName.equals("CallinMethodMappings")) {
+ //numberOfEntries = 6;
+ int i = 2;
+ for (int n=0; n<count;n++) {
+ // JSR-045 support:
+ names = new String[1];
+ i = scanStrings(names, indizes, i, cpg);
+ String binding_file_name = names[0];
+ int binding_line_number = combineTwoBytes(indizes, i);
+ i += 2;
+ int binding_line_offset = combineTwoBytes(indizes, i);
+ i += 2;
+ boolean is_static_role_method = false;
+ boolean covariant_base_return= false;
+ // regular stuff:
+ numberOfEntries = 3;
+ names = new String[numberOfEntries];
+ i = scanStrings(names, indizes, i, cpg);
+ String wrapper_name = null;
+ String wrapper_signature = null;
+ // first 3 names:
+ int index = 0;
+
+ String binding_label = names[index++];
+ String role_method_name = names[index++];
+ String role_method_signature = names[index++];
+
+ { // a flag:
+ int flags = combineTwoBytes(indizes, i);
+ is_static_role_method = (flags & 1) != 0;
+ // flag value 4 is "inherited"
+ covariant_base_return = (flags & 8) != 0;
+ i+=2;
+ }
+ // 3 more names
+ numberOfEntries = 3;
+ names = new String[numberOfEntries];
+ i = scanStrings(names, indizes, i, cpg);
+ index = 0;
+ //if (NEW_COMPILER_VERSION)
+ // static_role_method = see attribute
+
+ String lift_method_name = names[index++];
+ String lift_method_signature = names[index++];
+ String binding_modifier = names[index++];
+
+ int base_len = combineTwoBytes(indizes, i);
+ i += 2;
+
+ names = new String[4];
+ for (int n_base = 0; n_base < base_len; n_base++) {
+ i = scanStrings(names, indizes, i, cpg);
+ String base_method_name = names[0];
+ String base_method_signature = names[1];
+ wrapper_name = names[2];
+ wrapper_signature = names[3];
+
+ byte baseFlags = indizes[i++];
+ boolean baseIsCallin = (baseFlags & 1) != 0;
+ boolean baseIsStatic = (baseFlags & 2) != 0;
+ int translationFlags = (combineTwoBytes(indizes, i)<<16) + combineTwoBytes(indizes, i+2);
+ i += 4;
+
+ if(logging) {
+ printLogMessage("**** Binding: " + binding_label + ":"
+ + role_method_name + role_method_signature
+ + " <- " + binding_modifier + " "
+ + base_method_name + base_method_signature);
+ printLogMessage("**** Wrapper: " + wrapper_name
+ + wrapper_signature);
+ }
+ //set binding:
+ CallinBindingManager.addMethodBinding(class_name,
+ base_class_name, // previously read from PlayedBy attribute
+ binding_file_name,
+ binding_line_number,
+ binding_line_offset,
+ binding_label,
+ role_method_name,
+ role_method_signature,
+ is_static_role_method,
+ wrapper_name,
+ wrapper_signature,
+ binding_modifier,
+ base_method_name,
+ base_method_signature,
+ baseIsStatic,
+ baseIsCallin,
+ covariant_base_return,
+ translationFlags,
+ lift_method_name,
+ lift_method_signature);
+
+ }
+ }
+ } else if (attrName.equals("OTSpecialAccess")) {
+ numberOfEntries = 3;
+ int i = 2;
+ for (int j = 0; j < count; j++) {
+ short kind = indizes[i++];
+ switch (kind) {
+ case 1: // DecapsulatedMethodAccess
+ names = new String[numberOfEntries];
+ i = scanStrings(names, indizes, i, cpg);
+ if(logging) printLogMessage("**** Callout: " + names[0] + "."
+ + names[1]+ " " + names[2]);
+ CallinBindingManager.addCalloutBinding(names[0], names[1], names[2]);
+ break;
+ case 2: // CalloutFieldAccess
+ short flags = indizes[i++];
+ String accessMode = (flags & 1) == 1 ? "set" : "get";
+ boolean isStaticField = (flags & 2) != 0;
+ names = new String[numberOfEntries];
+ i = scanStrings(names, indizes, i, cpg);
+ if (logging)
+ printLogMessage("**** Callout bound field: " + accessMode+(isStaticField?" static ":" ")
+ + names[2]+ " " + names[1]);
+ CallinBindingManager.addCalloutBoundFileds(names[0], names[1], names[2], accessMode, isStaticField);
+
+ synchronized(reentrentTransformations) {
+ for (ObjectTeamsTransformation transformation : reentrentTransformations)
+ transformation.state.interfaceTransformedClasses.remove(names[0]);
+ }
+
+ break;
+ case 3: // SuperMethodAccess
+ numberOfEntries = 4;
+ names = new String[numberOfEntries];
+ i = scanStrings(names, indizes, i, cpg);
+ if(logging) printLogMessage("**** SuperAccess: " + names[0] + "."
+ + names[2]+ names[3]+" superclass "+names[1]);
+ CallinBindingManager.addSuperAccess(names[0], names[1], names[2], names[3]);
+ break;
+ }
+ }
+ // adapted baseclasses (w/ or w/o decapsulation):
+ count = combineTwoBytes(indizes, i);
+ i += 2;
+ names = new String[1];
+ for (int j=0; j<count; j++) {
+ i = scanStrings(names, indizes, i, cpg);
+ byte flag = indizes[i++];
+ if (flag == 1) {
+ CallinBindingManager.addBaseClassForModifierChange(names[0]);
+ } else {
+ CallinBindingManager.addExtraReferencedBase(class_name, names[0]);
+ // [OT/Equinox]: store adapted bases:
+ adaptedBases.add(names[0]);
+ }
+ }
+ } else if (attrName.equals("ReferencedTeams")) {
+ numberOfEntries = 1;
+ int i = 2;
+ int n = 2 * count * numberOfEntries; // n = count << 1;
+ names = new String[numberOfEntries];
+ while (i <= n) {
+ i = scanStrings(names, indizes, i, cpg);
+ String referenced_team = names[0];
+ if(logging) printLogMessage("**** found ReferencedTeams: " + referenced_team);
+ classesToLoad.add(referenced_team);
+
+ }
+ } else if (attrName.equals("BaseClassTags")) {
+ numberOfEntries = 2;
+ String baseClass = "";
+ int tag = 0;
+ HashMap<String, Integer> tagMap = new HashMap<String, Integer>();
+
+ int i = 2;
+ int n = 2 * count * numberOfEntries; //count << 2;
+ while (i <= n) {
+ for (int j = 0; j < numberOfEntries; j++) {
+ int nextIndex = combineTwoBytes(indizes, i);
+ if (j == 0) {
+ ConstantUtf8 cons = (ConstantUtf8) cpg
+ .getConstant(nextIndex);
+ baseClass = cons.getBytes();
+ } else if (j == 1) {
+ tag = nextIndex;
+ }
+ i += 2;
+ }
+ tagMap.put(baseClass, Integer.valueOf(tag));
+ if(logging) printLogMessage("**** found Base tag: " + class_name + "."
+ + baseClass + "->" + tag);
+ }
+ CallinBindingManager.addBaseTags(class_name, tagMap);
+ } else if (attrName.equals("PlayedBy")) {
+ names = new String[1];
+ scanStrings(names, indizes, 0, cpg);
+ base_class_name = names[0];
+ int langle = base_class_name.indexOf('<');
+ if (langle > -1) // it's an anchored type p.T$R<@C.o.f>, cut off everything after and including '<'.
+ base_class_name = base_class_name.substring(0, langle-1);
+ if(logging) printLogMessage("**** found PlayedBy: " + base_class_name);
+ // base_class_name is stored for later use, when method bindings are found.
+ CallinBindingManager.addSuperRoleLink(cg.getClassName(), cg.getSuperclassName());
+ // this information is NOT NEEDED at moment!
+ } else if (attrName.equals("OTCompilerVersion")) {
+ int encodedVersion = combineTwoBytes(indizes, 0);
+ int major = encodedVersion >>> 9;
+ int minor = (encodedVersion >>> 5) & 0xF;
+ int revision = encodedVersion & 0x1F;
+ if(logging) printLogMessage("**** class file was produced by compiler version "
+ + major + "." + minor + "." + revision + " ****");
+ IS_COMPILER_GREATER_123 = false; // reset, may be updated below
+ LowerableTransformation.checkRequiresAdaptation(major, minor, revision, cg);
+ // 1.4 stream:
+ if (major == 1 && minor == 4) {
+ if (revision < OT14_REVISION) {
+ if (class_name.startsWith(OTConstants.teamClassName))
+ continue; // no specific byte codes in ooTeam and its inner classes.
+ throw new InternalError("OTRE: Class " + class_name + " has unsupported revision " + revision);
+ }
+ IS_COMPILER_GREATER_123 = true;
+ IS_COMPILER_13X_PLUS = true;
+ IS_COMPILER_14X_PLUS = true;
+ // 1.3 stream:
+ } else if (major == 1 && minor == 3) {
+ if (revision < OT13_REVISION) {
+ if (class_name.startsWith(OTConstants.teamClassName))
+ continue; // no specific byte codes in ooTeam and its inner classes.
+ throw new InternalError("OTRE: Class " + class_name + " has unsupported revision " + revision);
+ }
+ IS_COMPILER_GREATER_123 = true;
+ IS_COMPILER_13X_PLUS = true;
+ // 1.2 stream:
+ } else if (major == 1 && minor == 2) {
+ if (revision < OT12_REVISION) {
+ if (class_name.startsWith(OTConstants.teamClassName))
+ continue; // no specific byte codes in ooTeam and its inner classes.
+ throw new InternalError("OTRE: Class " + class_name + " has unsupported revision " + revision);
+ }
+ if (revision > 3)
+ IS_COMPILER_GREATER_123 = true;
+ // 1.1 stream:
+ } else if (major == 1 && minor == 1) {
+ if (revision < OT11_REVISION) {
+ if (class_name.startsWith(OTConstants.teamClassName))
+ continue; // no specific byte codes in ooTeam and its inner classes.
+ throw new InternalError("OTRE: Class " + class_name + " has unsupported revision " + revision);
+ }
+ // 1.0 stream:
+ } else if (major == 1 && minor == 0) {
+ if (revision < OT10_REVISION) {
+ if (class_name.startsWith(OTConstants.teamClassName))
+ continue; // no specific byte codes in ooTeam and its inner classes.
+ throw new InternalError("OTRE: Class " + class_name + " has unsupported revision " + revision);
+ }
+ // 0.9 stream:
+ } else if (major == 0 && minor == 9) {
+ if (revision < OT09_REVISION) {
+ if (class_name.startsWith(OTConstants.teamClassName))
+ continue; // no specific byte codes in ooTeam and its inner classes.
+ throw new InternalError("OTRE: Class " + class_name + " has unsupported revision " + revision);
+ }
+ // 0.8 stream (OBSOLETE!)
+ } else {
+ if (major != OT_VERSION_MAJOR)
+ throw new InternalError("OTRE: Class " + class_name + " has unsupported major version " + major);
+ if (minor != OT_VERSION_MINOR)
+ throw new InternalError("OTRE: Class " + class_name + " has unsupported minor version " + minor);
+ if (revision < OT_REVISION)
+ throw new InternalError("OTRE: Class " + class_name + " has unsupported revision " + revision);
+ }
+ } else if (attrName.equals("CallinPrecedence")) {
+ List<String> precedenceList = new LinkedList<String>();
+ numberOfEntries = 1;
+ int i = 2;
+ int n = 2 * count * numberOfEntries; // n = count << 1;
+ names = new String[numberOfEntries];
+ while (i <= n) {
+ i = scanStrings(names, indizes, i, cpg);
+ String binding_label = names[0];
+ precedenceList.add(binding_label);
+ }
+ if(logging) printLogMessage("**** found precedence list for " + class_name + ": "
+ + precedenceList + " ****");
+ CallinBindingManager.addPrecedenceList(precedenceList, class_name);
+ }
+ }
+ }
+ return classesToLoad;
+ }
+
+ /**
+ * Read some strings from a byte array.
+ * @param entries Result array to be provided by caller.
+ * @param indizes buffer of read bytes to be provided by caller,
+ * consists if indizes into the constant pool
+ * @param i current index into indizes
+ * @param cpg the pool.
+ * @result updated value of <tt>i</tt>.
+ */
+ public static int scanStrings(String[] entries,
+ byte[] indizes,
+ int i,
+ ConstantPoolGen cpg)
+ {
+ for (int j = 0; j < entries.length; j++) {
+ int nextIndex = combineTwoBytes(indizes, i);
+ ConstantUtf8 cons = (ConstantUtf8)cpg.getConstant(nextIndex);
+ String content = cons.getBytes();
+ entries[j] = content;
+ i += 2;
+ }
+ return i;
+ }
+
+ /**
+ * Scan the Attributes found in the method <tt>method_name</tt> for binding attributes
+ * and registers them in the {@link CallinBindingManager CallinBindingManager}.
+ *
+ * @param attributes the Attributes to be examined
+ * @param class_name the name of the class where the Attributes were found
+ * @param method_name the name of the method where the Attributes were found
+ * @param cpg
+ */
+ static void scanMethodOTAttributes(Attribute[] attributes,
+ String class_name,
+ String method_name,
+ ConstantPoolGen cpg)
+ {
+ for (int k = 0; k < attributes.length; k++) {
+ Attribute actAttr = attributes[k];
+ Unknown attr = isOTAttribute(actAttr);
+ if (attr != null) { //this is an OT attribute
+ String attrName = attr.getName();
+ if(logging) printLogMessage("CallinBindingAttribute(" + method_name + ") :"
+ + attrName);
+ if (attrName.equals("CallinParamMappings")) {
+ byte[] indizes = attr.getBytes();
+ int [] positions = null;
+ if (indizes == null) throw new RuntimeException("Unexpected null attr");
+ int count = combineTwoBytes(indizes, 0);
+ positions = new int[count];
+ int p = 2;
+ for (int i = 0; i < count; i++, p += 2) {
+ positions[i] = combineTwoBytes(indizes, p);
+ // System.out.println(" "+i+"<-"+positions[i]);
+ }
+ CallinBindingManager.addParameterBinding(class_name,
+ method_name,
+ positions);
+ // Here it is correct to use the (wrapper) method name without a signature,
+ // because for overloaded methods there are separate wrappers with unique (mangled) names.
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Determines, if the given Attribute is a callin-attribute.
+ *
+ * @param attr the Attriute to be checked
+ * @return the Attribute casted to Unknown, for later use, if true
+ * null, if it is not a callin-attribute
+ */
+ static Unknown isOTAttribute(Attribute attr) {
+ if (attr instanceof Unknown) {
+ Unknown unknown = (Unknown)attr;
+ String attrName = unknown.getName();
+ if (attrName.equals("CallinRoleBaseBindings") ||
+ attrName.equals("BoundClassesHierarchy") ||
+ attrName.equals("CallinMethodMappings") ||
+ attrName.equals("CallinParamMappings") ||
+ attrName.equals("CallinFlags") ||
+ attrName.equals("OTSpecialAccess") ||
+ attrName.equals("WrappedRoleSignature") ||
+ attrName.equals("WrappedBaseSignature") ||
+ attrName.equals("ReferencedTeams") ||
+ attrName.equals("BaseClassTags") ||
+ attrName.equals("PlayedBy") ||
+ attrName.equals("Modifiers") ||
+ attrName.equals("OTCompilerVersion") ||
+ attrName.equals("OTClassFlags") ||
+ attrName.equals("OTJoinPoints") ||
+ attrName.equals("CallinPrecedence") ||
+ attrName.equals("StaticReplaceBindings"))
+ {
+ return unknown;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Combines two int's representing the higher and the lower part
+ * of a two byte number.
+ *
+ * @param first the first (higer?) byte
+ * @param second the second (lower?) byte
+ * @return the combined number
+ */
+ public static int combineTwoBytes(byte [] indizes, int start) {
+ int first = indizes[start];
+ int second = indizes[start + 1];
+ int twoBytes = 0;
+
+ twoBytes = twoBytes | (first & 0xff);
+ twoBytes = twoBytes << 8;
+ twoBytes = twoBytes | (second & 0xff);
+ return twoBytes;
+ }
+
+ /**
+ * Returns a list of names of all super classes of class 'role_name' which are inner
+ * classes of the enclosing team, what are all super roles of the
+ * role 'role_name'.
+ *
+ * @param role_name the name of the role class
+ * @param attributes the attributes of the enclosing team class
+ * @param cpg the constant pool of the enclosing team class
+ * @return the list of super role names
+ */
+ /*
+ private List getSuperRoles(String role_name, Attribute[] attributes, ConstantPoolGen cpg) {
+ LinkedList superRoleNames = new LinkedList();
+ JavaClass[] super_classes = Repository.getSuperClasses(role_name);
+ if (super_classes.length < 2) {// extends only Object, or none?
+ return superRoleNames;
+ }
+ LinkedList innerClassNames = new LinkedList();
+ for (int i=0; i<attributes.length; i++) {
+ Attribute actAttr = attributes[i];
+ if (actAttr instanceof InnerClasses) {
+ InnerClass[] inners = ((InnerClasses)actAttr).getInnerClasses();
+ for (int j=0; j<inners.length; j++) {
+ int name_index = inners[j].getInnerNameIndex();
+ Constant name_c = cpg.getConstant(name_index);
+ String name = ((ConstantUtf8)name_c).getBytes();
+ int outer_class_index = inners[j].getOuterClassIndex();
+ Constant outer_c = cpg.getConstant(outer_class_index);
+ String outerName = ((ConstantClass)outer_c).getBytes(cpg.getConstantPool());
+ outerName = outerName.replace('/', '.');
+ innerClassNames.add(outerName + "$" +name);
+ }
+ }
+ }
+ for (int i=0; i<super_classes.length; i++) {
+ String superClassName = super_classes[i].getClassName();
+ if (innerClassNames.contains(superClassName)) {
+ superRoleNames.addFirst(superClassName);
+ }
+ }
+ return superRoleNames;
+ }*/
+
+ /**
+ * Remove all contents of a method as preparation for adding a new implementation
+ *
+ * @param m The original method
+ * @param class_name The class containing the method
+ * @param cpg The class' constant pool
+ * @return An empty method generator with the same declaration as m
+ * and no implementation.
+ */
+ protected static MethodGen wipeMethod(Method m, String class_name, ConstantPoolGen cpg) {
+ MethodGen mg;
+ mg = new MethodGen(m, class_name, cpg);
+ mg.getInstructionList().dispose(); //throw away the old implementation
+ mg.removeLineNumbers();
+ mg.removeLocalVariables();
+ mg.removeLocalVariableTypes();
+ mg.removeExceptionHandlers();
+ mg.removeAttributes();
+ return mg;
+ }
+
+ /**
+ * Add instructions of InstructionList il after the super constructor call of this constuctor.
+ *
+ * @param m the constructor method
+ * @param addedCode the InstructionList containing the instructions to be added
+ * @param cg the ClassGen
+ * @param cpg the constant pool
+ */
+ static void addToConstructor(Method m, InstructionList addedCode, ClassGen cg, ConstantPoolGen cpg) {
+ String class_name = cg.getClassName();
+ MethodGen mg = new MethodGen(m, class_name, cpg);
+ InstructionList il = mg.getInstructionList().copy();
+ InstructionHandle[] ihs = il.getInstructionHandles();
+
+ MethodGen newConstructor = new MethodGen(mg.getAccessFlags(),
+ mg.getReturnType(),
+ mg.getArgumentTypes(),
+ mg.getArgumentNames(),
+ mg.getName(),
+ class_name,
+ il,
+ cpg );
+
+//[SH:]
+ updateCopiedMethod(mg, il, ihs, newConstructor);
+//[:HS]
+
+ int stackDepth = 0;
+ int actInstrIndex = 0;
+
+ boolean pauseStackCounting = false;
+ InstructionHandle gotoTarget = null;
+
+ // skip everything up to and including super() or this() call
+ while (!((ihs[actInstrIndex].getInstruction() instanceof INVOKESPECIAL)
+ && (stackDepth - (ihs[actInstrIndex].getInstruction().consumeStack(cpg))) == 0)) {
+
+ Instruction actInstruction = ihs[actInstrIndex].getInstruction();
+
+ if (gotoTarget != null && actInstruction.equals(gotoTarget.getInstruction())) {
+ pauseStackCounting = false;
+ gotoTarget = null;
+ }
+
+ if (actInstruction instanceof GotoInstruction) {
+ GotoInstruction gotoInsruction = (GotoInstruction)actInstruction;
+ gotoTarget = gotoInsruction.getTarget();
+ pauseStackCounting = true;
+ }
+ if (!pauseStackCounting) {
+ stackDepth -= actInstruction.consumeStack(cpg);
+ stackDepth += actInstruction.produceStack(cpg);
+ }
+
+ actInstrIndex++;
+ }
+
+ InstructionHandle ih = ihs[actInstrIndex];
+ INVOKESPECIAL invoke = (INVOKESPECIAL)ih.getInstruction();
+ String specialName = invoke.getName(cpg);
+ if (!specialName.equals(Constants.CONSTRUCTOR_NAME)) {
+ System.err.println("###ALERT: " + specialName);
+ return;
+ }
+
+ if (logging) printLogMessage("Adding code to " + class_name + "." + m.getName());
+
+ // calculate the length of the added code BEFORE it is inserted into the instruction list:
+//[SH:] extracted for adding further manipulation of addedCode:
+ int addedCodeLength = padCodeToAdd(addedCode);
+//[:HS]
+
+ InstructionHandle startOfAddedCode = il.append(ih, addedCode);
+
+ il.setPositions();
+
+ newConstructor.setInstructionList(il);
+ newConstructor.setMaxStack();
+ newConstructor.setMaxLocals();
+//[SH:] if an unused local variable was copied in updateCopiedMethod()
+// we have to adjust max_locals,
+// because unused locals are not found by setMaxLocals().
+ newConstructor.setMaxLocals(Math.max(newConstructor.getMaxLocals(), mg.getMaxLocals()));
+//[:HS]
+
+ copyAndAdjustLineNumbers(mg, newConstructor, addedCodeLength, startOfAddedCode);
+
+ cg.replaceMethod(m, newConstructor.getMethod());
+ }
+
+ /**
+ * Pads a given instruction list to multiples of 4 returning the padded length.
+ * Note that clients of this function must not call removeNOPs()!
+ *
+ * Rationale:
+ * switch instructions pad the lists of jmp targets to start at an offset % 4 == 0.
+ * In order to ensure that this padding will not change when inserting new bytes
+ * the added bytes have to be a multiple of 4.
+ */
+ static int padCodeToAdd(InstructionList addedCode) {
+//[orig:]
+ int addedCodeLength = 0;
+ Instruction[] instr = addedCode.getInstructions();
+ for (int i = 0; i < instr.length; i++) {
+ addedCodeLength += instr[i].getLength();
+ }
+//[:giro]
+ while (addedCodeLength % 4 > 0) {
+ addedCode.append(new NOP());
+ addedCodeLength++;
+ }
+ return addedCodeLength;
+ }
+
+//[SH:] helper methods for more complete method copying:
+
+ /** After a method (incl. its instruction list) has been copied,
+ * we need to manually copy some more properties:
+ * + local variables
+ * + declared exceptions
+ * + exception handlers.
+ */
+ static void updateCopiedMethod(MethodGen methodOrig,
+ InstructionList ilCopy,
+ InstructionHandle[] ihsCopy,
+ MethodGen methodCopy)
+ {
+ // local variables:
+ LocalVariableGen[] oldLocals = methodOrig.getLocalVariables();
+ int argLen = methodOrig.getArgumentTypes().length;
+ if (!methodOrig.isStatic())
+ argLen++; // this
+ if (oldLocals.length > argLen) {
+ InstructionList oldIL = methodOrig.getInstructionList();
+ int maxLocals = methodOrig.getMaxLocals();
+ for (int i = argLen; i<oldLocals.length; i++) {
+ LocalVariableGen var = oldLocals[i];
+ LocalVariableGen newVar =
+ methodCopy.addLocalVariable(var.getName(), var.getType(),
+ mapIH(var.getStart(), oldIL, ihsCopy),
+ mapIH(var.getEnd(), oldIL, ihsCopy));
+ newVar.setIndex(var.getIndex());
+ // reset, addLocalVariable might have changed this.
+ methodCopy.setMaxLocals(maxLocals);
+ }
+ }
+ // declared exceptions:
+ BaseCallRedirection.copyExceptionHandlers(methodOrig, methodCopy, ilCopy);
+ // exception handlers:
+ for(String excName : methodOrig.getExceptions())
+ methodCopy.addException(excName);
+ }
+
+ static InstructionHandle mapIH(InstructionHandle alienIH, InstructionList oldIL, InstructionHandle[] newIHs)
+ {
+ int position = alienIH.getPosition();
+ int[] newPositions = oldIL.getInstructionPositions();
+ for (int i=0; i<newPositions.length; i++) {
+ if (newPositions[i] == position)
+ return newIHs[i];
+ }
+ return null;
+ }
+//[:HS]
+
+ /**
+ * Copy all line numbers from <tt>src</tt> to <tt>dest</tt>.
+ * For bytecode instructions after the added code area an offset has to be added to the
+ * bytecode positions of the line numbers.
+ * If in debug modus (flag 'debugging') add 'STEP_OVER_LINENUMBER' for the added code.
+ *
+ * @param src The source method.
+ * @param dest The destination method.
+ * @param offset The offest to be added (the length of the added code list).
+ * @param startOfAddedCode InstructionHandle to the beginning of the added code.
+ */
+ static void copyAndAdjustLineNumbers(MethodGen src, MethodGen dest, int offset, InstructionHandle startOfAddedCode) {
+ InstructionList il_dest = dest.getInstructionList();
+ LineNumberGen[] src_lng = src.getLineNumbers();
+ boolean addedCodeHasLineNumber = false;
+
+ for (int i = 0; i < src_lng.length; i++) {
+ int position = src_lng[i].getInstruction().getPosition();
+ if (position == startOfAddedCode.getPosition()) { // add the line number for added code here:
+ dest.addLineNumber(startOfAddedCode, STEP_OVER_LINENUMBER);
+ addedCodeHasLineNumber = true;
+ continue;
+ }
+ if (position >= startOfAddedCode.getPosition()) // move line numbers, because of inserted code (add offset)
+ position += offset;
+ InstructionHandle ih = il_dest.findHandle(position);
+ if (ih == null) {
+ System.err.println("Handle not found!");
+ } else {
+ dest.addLineNumber(ih, src_lng[i].getSourceLine());
+ }
+ }
+ if (!addedCodeHasLineNumber) { // no custom code after added code: add line number now:
+ dest.addLineNumber(startOfAddedCode, STEP_OVER_LINENUMBER);
+ }
+ }
+
+ /**
+ * Test if a method has the given 'callin_flag'.
+ *
+ * @param m the method to search
+ * @param cg the ClassGen
+ * @param callin_flags the flags to check for; 0 means any callin flags
+ * @return true, if the method has the callin flag
+ */
+ public static boolean methodHasCallinFlags(Method m, ClassGen cg, int callin_flags) {
+ boolean found = false;
+ Attribute[] attributes = m.getAttributes();
+ for (int i = 0; i < attributes.length; i++) {
+ Attribute actAttr = attributes[i];
+ if (!(actAttr instanceof Unknown))
+ continue;
+ Unknown attr = (Unknown)actAttr;
+ if (!(attr.getName().equals("CallinFlags")))
+ continue;
+ if (callin_flags == 0)
+ return true;
+ byte [] bytes = attr.getBytes();
+ int flags = combineTwoBytes(bytes, 0);
+ if ((flags & callin_flags) != 0) {
+ if(logging) printLogMessage("Found CallinFlag " + callin_flags + " for "
+ + cg.getClassName() + "." + m.getName() + ".");
+ found = true;
+ }
+ }
+ return found;
+ }
+
+ /**
+ * A team needs to get added the team specific part, if it is a non-abstract team and
+ * not the class org.objectteams.Team itself.
+ *
+ * @param cg the class to be tested
+ * @return true if this is a team which has to be extended
+ */
+ protected static boolean classNeedsTeamExtensions(ClassGen cg) {
+ return !(( (cg.getAccessFlags() & OTConstants.TEAM) == 0)
+ || (cg.getClassName().equals(OTConstants.teamClassName))
+ || ((cg.getAccessFlags() & Constants.ACC_ABSTRACT) != 0));
+ }
+
+ /**
+ * Generates the name of the implementing role for the given role interface name.
+ * (Inserts the '__OT__' marker.)
+ *
+ * @param roleName the role interface name
+ * @return the implementing role class name
+ */
+ protected static String genImplementingRoleName(String roleName) {
+ int lastDollar = roleName.lastIndexOf('$');
+ StringBuilder sb = new StringBuilder(roleName);
+ sb.insert(lastDollar + 1, OTDT_PREFIX);
+ return sb.toString();
+ }
+
+ /**
+ * Generates the name of the role interface the given role class is implementing.
+ *(Removes the '__OT__' marker.)
+ *
+ * @param roleName the role class name
+ * @return the implemented role interface
+ */
+ public static String genRoleInterfaceName(String roleName) {
+ int lastDollar = roleName.lastIndexOf('$');
+ StringBuilder sb = new StringBuilder(roleName);
+ sb.delete(lastDollar + 1, lastDollar + 1 + OTDT_PREFIX.length());
+ return sb.toString();
+ }
+
+ protected static boolean isReflectiveOTMethod(String methodName, String methodSignature) {
+ if ((methodName.equals("hasRole") && methodSignature.equals("(Ljava/lang/Object;)Z"))
+ || (methodName.equals("hasRole") && methodSignature.equals("(Ljava/lang/Object;Ljava/lang/Class;)Z"))
+ || (methodName.equals("getRole") && methodSignature.equals("(Ljava/lang/Object;)Ljava/lang/Object;"))
+ || (methodName.equals("getRole") && methodSignature.equals("(Ljava/lang/Object;Ljava/lang/Class;)Ljava/lang/Object;"))
+ || (methodName.equals("getAllRoles") && methodSignature.equals("()[Ljava/lang/Object;"))
+ || (methodName.equals("getAllRoles") && methodSignature.equals("(Ljava/lang/Class;)[Ljava/lang/Object;"))
+ || (methodName.equals("unregisterRole") && methodSignature.equals("(Ljava/lang/Object;)V"))
+ || (methodName.equals("unregisterRole") && methodSignature.equals("(Ljava/lang/Object;Ljava/lang/Class;)V"))
+ )
+ return true;
+ return false;
+ }
+
+ /**
+ * Calculates the name of the outer class.
+ *
+ * @param className the full name of the inner class
+ * @return the name of the outer class
+ */
+ public static String getOuterClassName(String className) {
+ int dollarIndex = className.lastIndexOf('$');
+ if (dollarIndex == -1) // no outer class exists!
+ return null;
+ String outerClassName = className.substring(0, dollarIndex);
+ return outerClassName;
+ }
+
+ /**
+ * @param m
+ * @param cg
+ * @return
+ */
+ static boolean candidateForImplicitActivation(Method m, ClassGen cg, ConstantPoolGen cpg) {
+ if (!IS_COMPILER_14X_PLUS)
+ implicitActivationMode = ImplicitActivationMode.ALWAYS;
+ switch (implicitActivationMode) {
+ case NEVER:
+ return false;
+ case ANNOTATED :
+ if ( AnnotationHelper.containsImplicitActivationAttribute(m.getAttributes(), cpg)
+ || AnnotationHelper.containsImplicitActivationAttribute(cg.getAttributes(), cpg))
+ return canImplicitlyActivate(m);
+ return false;
+ case ALWAYS:
+ if (!canImplicitlyActivate(m))
+ return false;
+
+ Attribute[] attributes = m.getAttributes();
+ for(Attribute a : attributes) {
+ if (a instanceof Unknown) {
+ Unknown attr = (Unknown) a;
+ String attrName = attr.getName();
+ if ("RoleClassMethodModifiers".equals(attrName)) {
+ byte[] bytes = attr.getBytes();
+ int flags = combineTwoBytes(bytes, 0);
+ if (flags == 0 ||/* flags == 2 || */flags == 4) {
+ // 0: default, 2: private, 4: protected
+ return false;
+ }
+ }
+ }
+ }
+ if (!m.isPublic())
+ return false; // m originally wasn't public
+
+ String className = cg.getClassName();
+ return !(CallinBindingManager.isRole(className) && cg.isProtected());
+ default:
+ return false; // cannot happen switch is exhaustive.
+ }
+ }
+
+ private static boolean canImplicitlyActivate(Method m) {
+ String methodName = m.getName();
+ String methodSignature = m.getSignature();
+ boolean isCandidate =
+ (!m.isAbstract()) &&
+ (!m.isStatic()) &&
+ (!methodName.startsWith(OT_PREFIX)) &&
+ (!methodName.equals(Constants.CONSTRUCTOR_NAME)) &&
+ (!(methodName.equals("activate") && methodSignature.equals("()V"))) &&
+ (!(methodName.equals("deactivate") && methodSignature.equals("()V"))) &&
+ (!isReflectiveOTMethod(m.getName(), methodSignature));
+ return isCandidate;
+ }
+
+ /**
+ * @param s
+ * @param c
+ * @return
+ */
+ static int countOccurrences(String s, char c) {
+ int count = 0;
+ int idx = s.indexOf(c);
+ while (idx != -1) {
+ idx = s.indexOf(c, idx + 1);
+ count++;
+ }
+ return count;
+ }
+
+ /**
+ * This method performs the changes for implicit Team activation.
+ * @param m a method for which implicit activation will be enabled.
+ * @param className the class name for 'm'.
+ * @param cpg the constant pool of the class 'className'.
+ * @param activateOuter true, if the surrounding team has to be activated
+ * @return
+ */
+ Method genImplicitActivation(Method m, String className, ConstantPoolGen cpg, boolean activateOuter) {
+ String targetName = className;
+ int nestingDepth = 0;
+ ObjectType outerClass = null;
+ if (activateOuter) {
+ outerClass = new ObjectType(getOuterClassName(className));
+ nestingDepth = countOccurrences(className, '$') - 1;
+ targetName = outerClass.getClassName();
+ }
+ MethodGen mg = new MethodGen(m, className, cpg);
+ InstructionList il = mg.getInstructionList();
+ InstructionList prefix = new InstructionList();
+ InstructionHandle try_start = il.getStart();
+ // ---> new implicit activation
+ prefix.append(InstructionFactory.createThis());
+ if (activateOuter) {// this is for a role method: activate the outer team
+ // FIXME(SH): check replacing this$n with _OT$getTeam()
+ prefix.append(factory.createGetField(className, "this$" + nestingDepth, outerClass));
+ }
+ prefix.append(factory.createInvoke(targetName, "_OT$implicitlyActivate",
+ Type.VOID, Type.NO_ARGS, Constants.INVOKEVIRTUAL));
+ // <-- new implicit activation
+ if (debugging)
+ mg.addLineNumber(prefix.getStart() , STEP_OVER_LINENUMBER);
+ il.insert(prefix);
+
+ InstructionList postfix = new InstructionList();
+ // ---> new implicit deactivation
+ postfix.append(InstructionFactory.createThis());
+ if (activateOuter) {// this is for a role method: deactivate the outer team
+ postfix.append(factory.createGetField(className, "this$"+nestingDepth, outerClass));
+ }
+ postfix.append(factory.createInvoke(targetName,
+ "_OT$implicitlyDeactivate", Type.VOID, Type.NO_ARGS,
+ Constants.INVOKEVIRTUAL));
+ // <-- new implicit deactivation
+
+ FindPattern findPattern = new FindPattern(il);
+ String pat = "`ReturnInstruction'";
+ InstructionHandle ih = findPattern.search(pat);
+ while (ih != null) {
+ // insert deactivate-call before return instruction in ih:
+ InstructionList postfixCopy = postfix.copy();
+ if (debugging)
+ mg.addLineNumber(postfixCopy.getStart(), STEP_OVER_LINENUMBER);
+ InstructionHandle inserted = il.insert(ih, postfixCopy); // instruction lists can not be reused
+ il.redirectBranches(ih, inserted); // SH: retarget all jumps that targeted at the return instruction
+ if (ih.getNext() == null)
+ break; // end of instruction list reached
+ ih = findPattern.search(pat, ih.getNext());
+ }
+
+ /**
+ * **** add an exception handler which calls deactivate before throwing
+ * the exception (finaly-simulation): ***
+ */
+ ObjectType throwable = new ObjectType("java.lang.Throwable");
+ LocalVariableGen exception = mg.addLocalVariable(
+ "_OT$thrown_exception", throwable, null, null);
+ InstructionHandle try_end = il.getEnd();
+ InstructionList postfix_ex = postfix.copy();
+ if (debugging)
+ mg.addLineNumber(postfix_ex.getStart(), STEP_OVER_LINENUMBER);
+ postfix_ex.insert(InstructionFactory.createStore(throwable, exception
+ .getIndex()));
+ postfix_ex.append(InstructionFactory.createLoad(throwable, exception
+ .getIndex()));
+ postfix_ex.append(new ATHROW());
+ InstructionHandle deactivation_handler = il.append(il.getEnd(),
+ postfix_ex);
+ mg.addExceptionHandler(try_start, try_end, deactivation_handler,
+ throwable);
+ /** ******************************************************************** */
+
+ mg.setInstructionList(il);
+ mg.setMaxLocals();
+ mg.setMaxStack();
+
+ if (!debugging)
+ return mg.getMethod();
+
+ /* sorting the line numbers per start pc: */
+ Method newMethod = mg.getMethod();
+ MethodGen newMethodGen = new MethodGen(newMethod, className, cpg);
+
+ LineNumberGen[] lineNumbers = newMethodGen.getLineNumbers();
+
+ newMethodGen.removeLineNumbers();
+
+ Arrays.sort(lineNumbers, new Comparator<LineNumberGen>() {
+ public int compare(LineNumberGen ln1, LineNumberGen ln2) {
+ int firstLineNumberPC = ln1.getLineNumber().getStartPC();
+ int secondLineNumberPC = ln2.getLineNumber().getStartPC();
+
+ if (firstLineNumberPC < secondLineNumberPC)
+ return -1;
+ if (firstLineNumberPC > secondLineNumberPC)
+ return 1;
+ return 0;
+ }
+ });
+
+ for (int i = 0; i<lineNumbers.length; i++) {
+ newMethodGen.addLineNumber(lineNumbers[i].getInstruction(), lineNumbers[i].getSourceLine());
+ }
+
+ return newMethodGen.getMethod();
+ }
+
+ /**
+ * How many bytes does an instruction produce on the stack?
+ */
+ static protected int stackDiff(Instruction instr, ConstantPoolGen cpg) {
+ return instr.produceStack(cpg) - instr.consumeStack(cpg);
+ }
+
+ /**
+ * Split an instruction list that loads method arguments into
+ * one list for each argument.
+ * @param cpg
+ * @param src the original loading sequence (will be destroyed by this method).
+ * @param argumentTypes source-level argument types of the callin method.
+ * @return array of load sequences, same order as before but split into individual arguments.
+ */
+ protected InstructionList[] splitLoading(ConstantPoolGen cpg, InstructionList src, Type[] argumentTypes) {
+ int len = argumentTypes.length;
+ InstructionList[] res = new InstructionList[len];
+ // starting right _before_ an invoke instruction we loop backwards
+ // to find those values on the stack that would be passed to the method.
+ for (int idx = len-1; idx>=0; idx--) {
+ // new sub-list:
+ res[idx] = new InstructionList();
+ // how many bytes to expect on the stack:
+ int expectedArgSize = argumentTypes[idx].getSize();
+ // loop until we have a sequence that produces the expected number of bytes:
+ while (expectedArgSize > 0) {
+ InstructionHandle loadH = src.getEnd();
+ Instruction load = loadH.getInstruction();
+ expectedArgSize -= stackDiff(load, cpg);
+ try {
+ // transfer instruction from src to res[roleIdx]:
+ res[idx].insert(load);
+ src.delete(loadH);
+ } catch (TargetLostException e) {
+ throw new OTREInternalError(e);
+ }
+ }
+ }
+ return res;
+ }
+
+ /**
+ * Translate the parameter loading of a base call to the correct sequence
+ * expected by the base chaining wrapper.
+ * Treats tunneled arguments but not current enhancement args.
+ * Tasks performed:
+ * <ul>
+ * <li>pick load sequences from <tt>splitLoad</tt>
+ * <li>extract unused args from Object[]
+ * <li>insert casting or lowering if needed.
+ * </ul>
+ * More documentation is found in document parameter-passing.odg.
+ *
+ * @param splitLoad one list of load instructions for each argument, ordered as found in the bytecode.
+ * @param enhancedRoleArgumentTypes enhanced role arguments
+ * @param enhancedBaseArgumentTypes arguments of the base chaining wrapper.
+ * @param parameterPosition encoded parameter mappings.
+ * @param teamName The name of the team containing the role class.
+ * @param enclosingRoleName enclosing role class or null for static replace/base-call.
+ * @param baseIsCallin is the base method a callin method?
+ * @param baseIsStaticRoleMethod is the base method a static role method?
+ * @param one byte for each parameter, signalling if lowering is required
+ * @return a complete loading sequence for all source-level and tunneled arguments
+ */
+ protected InstructionList translateLoads(InstructionList[] splitLoad,
+ Type[] enhancedRoleArgumentTypes,
+ Type[] enhancedBaseArgumentTypes,
+ int[] parameterPositions,
+ String teamName,
+ String enclosingRoleName,
+ BaseMethodInfo baseMethod,
+ int start,
+ ConstantPoolGen cpg)
+ {
+ boolean isStatic = baseMethod.isStatic;
+ boolean baseIsStaticRoleMethod = baseMethod.isStaticRoleMethod();
+ boolean baseIsCallin = baseMethod.isCallin;
+ int translationFlags = baseMethod.translationFlags;
+
+ InstructionList il = new InstructionList();
+
+ // index into "Object[] _OT$unusedArgs" (points to first arg that has not yet been consumed):
+ int nextUnusedArg = 0;
+ // index into enhancedBaseArgumentTypes:
+ int baseIdx;
+ // source-level version of baseIdx, i.e., ignoring any enhanced arguments:
+ int baseSrcIdx;
+ // index into roleArgumentTypes:
+ int roleIdx;
+ // source-level version of roleIdx, i.e., ignoring any enhanced arguments:
+ int roleSrcIdx;
+
+ // == Note: letters (u-x) below refer to document parameter-passing.odg. ==
+ // Skip enhancements that are already loaded (given in start).
+ for (baseIdx = start; baseIdx < enhancedBaseArgumentTypes.length; baseIdx++) {
+ baseSrcIdx = baseIdx-start; // (u) skip first enhancement (already loaded)
+ if (baseIsStaticRoleMethod)
+ baseSrcIdx -= 2; // (v) not mapped but extracted from unusedArgs
+ if (baseIsCallin)
+ baseSrcIdx -= EXTRA_ARGS; // (w) not mapped but extracted from unusedArgs
+
+ // value-dispatching: where to find this parameters?
+ if (baseSrcIdx < 0) {
+ // (v) or (w)
+ roleSrcIdx = -1;
+ } else {
+ // (x) merge arguments from unused and real:
+ int numAvailableRoleArgs = enhancedRoleArgumentTypes.length-EXTRA_ARGS;
+ if (!isStatic && IS_COMPILER_GREATER_123)
+ numAvailableRoleArgs--; // don't count isSuperAccess
+ roleSrcIdx = getMappedRolePosition(baseSrcIdx, parameterPositions, numAvailableRoleArgs);
+ }
+
+ // got all information, fetch it now:
+ Type baseArgumentType = enhancedBaseArgumentTypes[baseIdx];
+ if (roleSrcIdx == -1) {
+ // not mapped, retrieve from _OT$unusedArgs:
+ retrieveFromUnusedArg(il, nextUnusedArg++, baseArgumentType, cpg);
+ } else {
+ // mapped, fetch from splitLoad:
+ roleIdx = roleSrcIdx+EXTRA_ARGS; // role always has an additional set of enhancements
+ if (IS_COMPILER_GREATER_123 && !isStatic) roleIdx++; // (+ isSuperAccess)
+ Type roleArgumentType = enhancedRoleArgumentTypes[roleIdx];
+ il.append(splitLoad[roleSrcIdx]);
+ if (!roleArgumentType.equals(baseArgumentType)) {
+ convertParamToBase(il, teamName, enclosingRoleName, roleArgumentType, baseArgumentType,
+ (translationFlags & (2<<baseSrcIdx)) != 0);
+ }
+ }
+ }
+ if (il.isEmpty())
+ il.append(new NOP()); // ensure caller receives at least one instruction handle (for line number)
+ return il;
+ }
+
+ /* Is the base arg identified by 'baseIdx' mapped to a role parameter?
+ * If so: which role position is it mapped to?
+ * If not: return -1
+ */
+ private int getMappedRolePosition(int baseSrcIdx,
+ int[] parameterPositions,
+ int numAvailableRoleArgs)
+ {
+ if (parameterPositions == null) {
+ if (baseSrcIdx < numAvailableRoleArgs) // as many as available ...
+ return baseSrcIdx; // in original order.
+ } else {
+ // search parameter mapping:
+ for (int i = 0; i < parameterPositions.length; i++) {
+ if (parameterPositions[i] == baseSrcIdx+1) // positions are one-based (base side)
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ /* Retrieve an unused (tunneled) argument from position 'unusedIdx' of the _OT$unusedArgs array. */
+ private void retrieveFromUnusedArg(InstructionList il,
+ int unusedIdx,
+ Type baseArgumentType,
+ ConstantPoolGen cpg)
+ {
+ il.append(InstructionFactory.createLoad(objectArray, /*this*/1 + (UNUSED_ARG-1))); // 'UNUSED_ARG' is one-based
+ il.append(createIntegerPush(cpg, unusedIdx));
+ il.append(InstructionFactory.createArrayLoad(objectArray));
+ if (baseArgumentType instanceof BasicType)
+ il.append(createUnboxing((BasicType) baseArgumentType));
+ else // ObjectTypes just have to be re-casted
+ il.append(factory.createCast(object, baseArgumentType));
+ }
+
+ /* May perform any of these conversions: casting, lowering, array-lowering.
+ * Conversion is generated into 'il'.
+ */
+ private void convertParamToBase(InstructionList il,
+ String teamName,
+ String enclosingRoleName,
+ Type roleArgumentType,
+ Type baseArgumentType,
+ boolean loweringFlag)
+ {
+ if (roleArgumentType instanceof ObjectType
+ && baseArgumentType instanceof ObjectType)
+ {
+ if (loweringFlag) {
+ lowerObject(il, teamName, roleArgumentType, baseArgumentType);
+ } else {
+ if(logging) printLogMessage("Try to cast " + roleArgumentType +
+ " to " + baseArgumentType);
+ il.append(factory.createCast(roleArgumentType,
+ baseArgumentType));
+ }
+ } else
+ if ( roleArgumentType instanceof BasicType
+ && baseArgumentType instanceof ObjectType)
+ {
+ il.append(createBoxing((BasicType)roleArgumentType));
+ } else
+ if ( roleArgumentType instanceof ObjectType
+ && baseArgumentType instanceof BasicType)
+ {
+ il.append(createUnboxing((BasicType)baseArgumentType));
+ } else
+ if ( roleArgumentType instanceof ArrayType
+ && baseArgumentType instanceof ArrayType)
+ {
+ lowerArray(il, teamName, enclosingRoleName, roleArgumentType, baseArgumentType);
+ } else {
+ throw new OTREInternalError("OTRE internal error:"+
+ "No way to make types conform\n"+
+ "role type "+roleArgumentType+
+ " -> "+baseArgumentType);
+ }
+ }
+
+ /* Lower one object from roleArgumentType to baseArgumentType. */
+ private void lowerObject(InstructionList il,
+ String teamName,
+ Type roleArgumentType,
+ Type baseArgumentType)
+ {
+ String roleIfcName = ((ObjectType)roleArgumentType).getClassName();
+ // use interface implementing role type for base-field access!
+ String roleClassName = ObjectTeamsTransformation.genImplementingRoleName(roleIfcName);
+
+ int dollarIdx = roleClassName.lastIndexOf('$');
+ if (dollarIdx == -1) {
+ throw new OTREInternalError("OTRE internal error:" +
+ "No way to make types conform\n" +
+ "role type " + roleArgumentType +
+ " -> " + baseArgumentType);
+ }
+ boolean isNested = dollarIdx != roleClassName.indexOf('$'); // is last == first?
+ String strengthenedRoleName = teamName + roleClassName.substring(dollarIdx);
+
+ // baseArgumentType may be imprecise due to cast in param mapping,
+ // try a RBB instead to find the exact base type
+ RoleBaseBinding rbb = CallinBindingManager.getRoleBaseBinding(strengthenedRoleName);
+ if (rbb != null)
+ baseArgumentType = new ObjectType(rbb.getBaseClassName());
+
+ if (isNested) {
+ // cannot use field access here, because role strengthening would require resolved information
+ // so use the _OT$getBase() method instead:
+ short kind = (roleIfcName.lastIndexOf('$') == roleIfcName.lastIndexOf("$__OT__")) // last segment is roleclass?
+ ? Constants.INVOKEVIRTUAL
+ : Constants.INVOKEINTERFACE;
+ il.append(factory.createInvoke(roleIfcName, GET_BASE, baseArgumentType, new Type[0], kind));
+ } else {
+ // access field via the role class:
+ il.append(factory.createCast(roleArgumentType, new ObjectType(strengthenedRoleName)));
+
+ // optimized version directly accessing the field:
+ il.append(factory.createGetField(strengthenedRoleName,
+ BASE,
+ baseArgumentType));
+ }
+ }
+
+ /* Lower from roleArgumentType[] to baseArgumentType[]. */
+ private void lowerArray(InstructionList il, String teamName, String enclosingRoleName, Type roleArgumentType, Type baseArgumentType) {
+ ArrayType array = (ArrayType)roleArgumentType;
+ String roleName =((ObjectType)array.getElementType()).getClassName();
+ int dollarIdx = roleName.lastIndexOf('$');
+ String pureRoleName = roleName.substring(dollarIdx + 1);
+ String transformMethodName = getArrayLoweringMethodName(pureRoleName, array.getDimensions());
+ if (enclosingRoleName != null) {
+ // fetch team from enclosing role:
+ il.append(InstructionFactory.createThis());
+ // FIXME(SH): is this$0 always correct (nesting!)??
+ il.append(factory.createGetField(enclosingRoleName, "this$0", new ObjectType(teamName)));
+ } else {
+ // "this" is the team:
+ il.append(InstructionFactory.createThis());
+ }
+ il.append(new SWAP()); // 'push' team instance below the role array
+ il.append(factory.createInvoke(teamName,
+ transformMethodName,
+ baseArgumentType,
+ new Type[]{roleArgumentType},
+ Constants.INVOKEVIRTUAL));
+ }
+
+ private String getArrayLoweringMethodName(String roleName, int dimensions) {
+ return "_OT$transformArray" + roleName + "_OT$" + dimensions;
+ }
+
+ public List<String> getInnerClassNames(ClassGen cg, ConstantPoolGen cpg) {
+ Attribute[] attributes = cg.getAttributes();
+ LinkedList<String> innerClassNames = new LinkedList<String>();
+ for (int i = 0; i < attributes.length; i++) {
+ Attribute actAttr = attributes[i];
+ if (actAttr instanceof InnerClasses) {
+ InnerClass[] inners = ((InnerClasses)actAttr).getInnerClasses();
+ for (int j=0; j<inners.length; j++) {
+ int name_index = inners[j].getInnerNameIndex();
+ Constant name_c = cpg.getConstant(name_index);
+ String name = ((ConstantUtf8)name_c).getBytes();
+ innerClassNames.add(name);
+ }
+ }
+ }
+ return innerClassNames;
+ }
+
+ /**
+ * Create a monitor enter using a class literal
+ * @param mg target method to which a local variable is added which holds the monitor object
+ * @param il instruction list to append to
+ * @param class_name name of the class literal to use as monitor
+ * @param major major class file version, used to determine how to translate class literals
+ * @param cpg constant pool gen
+ * @return the slot index of the monitor local variable and the handle of the first generated instruction.
+ */
+ protected Pair<Integer,InstructionHandle> addClassMonitorEnter(MethodGen mg,
+ InstructionList il,
+ String class_name,
+ int major,
+ ConstantPoolGen cpg)
+ {
+ int monitor;
+ InstructionHandle ih=
+ appendClassLiteral(il, class_name, major, cpg);
+ il.append(new DUP()); // for store and monitorenter
+ LocalVariableGen lg2=
+ mg.addLocalVariable("monitor", Type.OBJECT, il.getStart(), null); //$NON-NLS-1$
+ monitor= lg2.getIndex();
+ il.append(InstructionFactory.createStore(Type.OBJECT, monitor)); // for use by monitorexit
+ il.append(new MONITORENTER());
+ return new Pair<Integer, InstructionHandle>(monitor, ih);
+ }
+
+ /**
+ * Append an instruction sequence for loading the class literal for `class_name'.
+ * @param il instruction list to append to
+ * @param class_name class name of the class literal
+ * @param major java version as stored in the byte code.
+ * @param cpg for generating bytes
+ * @return the handle of the first instruction of the sequence.
+ */
+ protected InstructionHandle appendClassLiteral(InstructionList il,
+ String class_name,
+ int major,
+ ConstantPoolGen cpg)
+ {
+ if (major >= 49) // java 5
+ return il.append(new LDC(cpg.addClass(new ObjectType(class_name))));
+ // pre java 5, do it the hard way:
+ // if (_OT$self_class$ != null)
+ InstructionHandle start=
+ il.append(factory.createFieldAccess(class_name, OTConstants.SELF_CLASS, classType, Constants.GETSTATIC));
+ il.append(new DUP()); // keep a copy as a potential result
+ BranchInstruction checkLoaded=
+ InstructionFactory.createBranchInstruction(Constants.IFNONNULL, null);
+ il.append(checkLoaded);
+ il.append(new POP()); // discard null from above
+ // _OT$self_class$= Class.forName(<class_name>); // never fails, it is THIS class
+ il.append(new LDC(cpg.addString(class_name)));
+ il.append(factory.createInvoke("java.lang.Class",
+ "forName",
+ classType,
+ new Type[]{new ObjectType("java.lang.String")},
+ Constants.INVOKESTATIC));
+ il.append(new DUP()); // keep a copy as the result
+ il.append(factory.createFieldAccess(class_name, OTConstants.SELF_CLASS, classType, Constants.PUTSTATIC));
+
+ checkLoaded.setTarget(il.append(new NOP()));
+ return start;
+ }
+}
diff --git a/othersrc/OTRE/src/org/eclipse/objectteams/otre/StaticSliceBaseTransformation.java b/othersrc/OTRE/src/org/eclipse/objectteams/otre/StaticSliceBaseTransformation.java
new file mode 100644
index 0000000..3525912
--- /dev/null
+++ b/othersrc/OTRE/src/org/eclipse/objectteams/otre/StaticSliceBaseTransformation.java
@@ -0,0 +1,757 @@
+/**********************************************************************
+ * 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: StaticSliceBaseTransformation.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.classfile.*;
+import de.fub.bytecode.generic.*;
+import de.fub.bytecode.*;
+
+import org.eclipse.objectteams.otre.util.*;
+
+
+/**
+ * Adds to base classes with callin bindings what can be literally pasted in:
+ *
+ * Fields:
+ * protected static Team[] _OT$activeTeams;
+ * protected static int[] _OT$activeTeamIDs;
+ * Methods:
+ * public static void _OT$addTeam(Team team, in team_id)
+ * public static void _OT$removeTeam(Team team)
+ * Static initialization (adds clinit method, if not yet presented):
+ * _OT$activeTeams = new Team[0];
+ * _OT$activeTeamIDs = new int[0];
+ *
+ *
+ * @version $Id: StaticSliceBaseTransformation.java 23408 2010-02-03 18:07:35Z stephan $
+ * @author Christine Hundt
+ * @author Stephan Herrmann
+ */
+public class StaticSliceBaseTransformation
+ extends ObjectTeamsTransformation
+{
+ static final String _OT_ACTIVE_TEAMS= "_OT$activeTeams"; //$NON-NLS-1$
+ static final String _OT_ACTIVE_TEAM_IDS= "_OT$activeTeamIDs"; //$NON-NLS-1$
+
+ public StaticSliceBaseTransformation(SharedState state) { this(null, state); }
+ public StaticSliceBaseTransformation(ClassLoader loader, SharedState state) { super(loader, state); }
+
+ public void doTransformCode(ClassGen cg) {
+ if (cg.isInterface())
+ return; // can't add implementation
+ // IMPLICIT_INHERITANCE
+
+ String class_name = cg.getClassName();
+ if (!CallinBindingManager.isBoundBaseClass(class_name)
+ /*&& !CallinBindingManager.containsBoundBaseInterface(cg.getInterfaceNames())*/)
+ return; //only (base-)classes with callin bindings need this addition
+ /*// this only works if teams are only added at the root bound base class
+ if (CallinBindingManager.isBoundBaseClass(cg.getSuperclassName()))
+ continue; // team infrastructur already added by super class
+ */
+ if (CallinBindingManager.hasBoundBaseParent(class_name))
+ return; // team infrastructure already has been added to a super class
+
+ ConstantPoolGen cpg = cg.getConstantPool();
+ factory = new InstructionFactory(cpg);
+ addStaticInitializations(cg, cpg);
+ }
+
+ /**
+ * @param ce
+ * @param cg
+ */
+ public void doTransformInterface(ClassEnhancer ce, ClassGen cg) {
+ String class_name = cg.getClassName();
+ ConstantPoolGen cpg = cg.getConstantPool();
+
+ checkReadClassAttributes(ce, cg, class_name, cpg);
+
+ if (cg.isInterface())
+ return; // can't add implementation
+ if (state.interfaceTransformedClasses.contains(class_name))
+ return; // class has already been transformed by this transformer
+ // IMPLICIT_INHERITANCE
+ if (!CallinBindingManager.isBoundBaseClass(class_name)
+ /*&& !CallinBindingManager.containsBoundBaseInterface(cg.getInterfaceNames())*/)
+ return; //only (base-)classes with callin bindings need this addition
+ /*// this only works if teams are only added at the root bound base class
+ if (CallinBindingManager.isBoundBaseClass(cg.getSuperclassName()))
+ continue; // team infrastructur already added by super class
+ */
+ if (CallinBindingManager.hasBoundBaseParent(class_name))
+ return; // team infrastructure already has been added to a super class
+ if(logging) printLogMessage("StaticSliceBaseTransformer transforms "+ class_name);
+
+ if(CallinBindingManager.isRole(class_name)) {
+ addImplicitSubclassNotificationInfrastructure(ce, cg);
+ }
+
+ // addition of the fields '_OT$activeTeams' and '_OT$activeTeamIDs':
+ int accessFlags = Constants.ACC_PROTECTED | Constants.ACC_STATIC;
+
+ FieldGen activeTeamsField = new FieldGen(accessFlags, teamArray, _OT_ACTIVE_TEAMS, cpg);
+ ce.addField(activeTeamsField.getField(), cg);
+ // generated global variable: protected static Team[] _OT$activeTeams;
+
+ FieldGen activeTeamIDsField = new FieldGen(accessFlags, intArray, _OT_ACTIVE_TEAM_IDS, cpg);
+ ce.addField(activeTeamIDsField.getField(), cg);
+ // generated global variable: protected static int[] _OT$activeTeamIDs;
+
+ factory = new InstructionFactory(cpg);
+
+ // implementation of method '_OT$addTeam'
+ ce.addMethod(genAddTeam(class_name, cg.getMajor(), cpg).getMethod(), cg);
+
+ // implementation of method '_OT$removeTeam':
+ ce.addMethod(genRemoveTeam(class_name, cg.getMajor(), cpg).getMethod(), cg);
+
+ // implementation of the static class initialization method '<clinit>':
+ /* Adding static initializations requires the addition of the clinit method, if not yet presented.
+ * This requires synchronization with other transformers (TeamInterfaceImplementer)
+ * which may do the same this. This is done via 'TeamIdDispenser.clinitAdded(class_name)'.
+ */
+ Method clinit = cg.containsMethod(Constants.STATIC_INITIALIZER_NAME, "()V");
+
+ if (clinit != null || TeamIdDispenser.clinitAdded(class_name, loader)) {
+ // the clinit-Method only has to be extended by the code transformation of this transformer
+ state.interfaceTransformedClasses.add(class_name);
+ return;
+ }
+
+ InstructionList il = new InstructionList();
+ MethodGen clinitMethod = new MethodGen(Constants.ACC_STATIC,
+ Type.VOID,
+ Type.NO_ARGS,
+ new String[] { },
+ Constants.STATIC_INITIALIZER_NAME, class_name,
+ il, cpg);
+
+ il.append(InstructionFactory.createReturn(Type.VOID));
+
+ clinitMethod.setMaxStack();
+ clinitMethod.setMaxLocals();
+
+ ce.addMethod(clinitMethod.getMethod(), cg);
+
+/***********************************************************************************************************/
+ il.dispose();
+ state.interfaceTransformedClasses.add(class_name);
+ }
+
+ /* Code to be generated:
+ public static void _OT$addTeam(Team team, int teamID)
+ {
+ int l;
+ // Second part of the "if" below: Avoid duplicate entry of the same team.
+ // Assumption (see r17473): this strategy assumes that a team instance
+ // can only be duplicated directly after the first registration.
+ // Reason: registerAtBases() calling addTeam() for multiple sub-bases
+ // which share the same _OT$activateTeams et al fields from a common super-base.
+ if((l = _OT$activeTeams.length) != 0 && _OT$activeTeams[0] == team)
+ {
+ return;
+ } else
+ {
+ Team newTeams[] = new Team[l + 1];
+ int newTeamIDs[] = new int[l + 1];
+ System.arraycopy(_OT$activeTeams, 0, newTeams, 1, l);
+ System.arraycopy(_OT$activeTeamIDs, 0, newTeamIDs, 1, l);
+ _OT$activeTeams = newTeams;
+ _OT$activeTeamIDs = newTeamIDs;
+ _OT$activeTeams[0] = team;
+ _OT$activeTeamIDs[0] = teamID;
+ return;
+ }
+ }
+ */
+ private MethodGen genAddTeam(String class_name, int major, ConstantPoolGen cpg) {
+ LocalVariableGen lg;
+ InstructionList il;
+ il = new InstructionList();
+ MethodGen addTeamMethod = new MethodGen(Constants.ACC_PUBLIC | Constants.ACC_STATIC | Constants.ACC_SYNCHRONIZED,
+ Type.VOID,
+ new Type[] { teamType, Type.INT },
+ new String[] { "team", "teamID" },
+ "_OT$addTeam", class_name,
+ il, cpg);
+ // synchronized (BaseClass.class) {
+ int monitor = addClassMonitorEnter(addTeamMethod, il, class_name, major, cpg).first;
+
+ il.append(factory.createFieldAccess(class_name, _OT_ACTIVE_TEAMS, teamArray, Constants.GETSTATIC));
+ il.append(new ARRAYLENGTH());
+ lg = addTeamMethod.addLocalVariable("l", Type.INT, null, null);
+ int l = lg.getIndex();
+ il.append(new DUP());
+ lg.setStart(il.append(InstructionFactory.createStore(Type.INT, l)));
+ // generated: int l = _OT$activeTeams.length;
+
+ // add duplication check:
+ BranchHandle emptyArray =
+ il.append(new IFEQ(null));
+ il.append(factory.createFieldAccess(class_name, _OT_ACTIVE_TEAMS, teamArray, Constants.GETSTATIC));
+ il.append(new ICONST(0));
+ il.append(InstructionFactory.createArrayLoad(teamType));
+ il.append(new ALOAD(0));
+ BranchHandle noDuplication =
+ il.append(new IF_ACMPNE(null));
+ GOTO earlyExit = new GOTO(null);
+ il.append(earlyExit);
+ InstructionHandle skipReturn = il.append(new NOP());
+ emptyArray.setTarget(skipReturn);
+ noDuplication.setTarget(skipReturn);
+ // generated: if (l > 0 && _OT$activeTeams[0] == team ) return;
+
+ lg = addTeamMethod.addLocalVariable("newTeams", teamArray, null, null);
+ int newTeams = lg.getIndex();
+ il.append(InstructionFactory.createLoad(Type.INT, l));
+ il.append(new ICONST(1));
+ il.append(new IADD());
+ il.append((Instruction)factory.createNewArray(teamType, (short)1));
+ //this are very strange (but necessary!?) casts...
+ lg.setStart(il.append(InstructionFactory.createStore(teamArray, newTeams)));
+ // generated: Team[] newTeams = new Team[l+1];
+
+ lg = addTeamMethod.addLocalVariable("newTeamIDs", intArray, null, null);
+ int newTeamIDs = lg.getIndex();
+ il.append(InstructionFactory.createLoad(Type.INT, l));
+ il.append(new ICONST(1));
+ il.append(new IADD());
+ il.append((Instruction)factory.createNewArray(Type.INT, (short)1));
+ //this are very strange (but necessary!?) casts...
+ lg.setStart(il.append(InstructionFactory.createStore(intArray, newTeamIDs)));
+ // generated: int[] newTeamIDs = new int[l+1];
+
+ il.append(factory.createFieldAccess(class_name, _OT_ACTIVE_TEAMS, teamArray, Constants.GETSTATIC));
+ il.append(new ICONST(0));
+ il.append(InstructionFactory.createLoad(teamArray, newTeams));
+ il.append(new ICONST(1));
+ il.append(InstructionFactory.createLoad(Type.INT, l));
+ ObjectType object = new ObjectType("java.lang.Object");
+ il.append(factory.createInvoke("java.lang.System", "arraycopy",
+ Type.VOID,
+ new Type[] {object, Type.INT, object, Type.INT, Type.INT },
+ Constants.INVOKESTATIC));
+ // generated: System.arraycopy(_OT$activeTeams, 0, newTeams, 1, l);
+
+ il.append(factory.createFieldAccess(class_name, _OT_ACTIVE_TEAM_IDS, intArray, Constants.GETSTATIC));
+ il.append(new ICONST(0));
+ il.append(InstructionFactory.createLoad(intArray, newTeamIDs));
+ il.append(new ICONST(1));
+ il.append(InstructionFactory.createLoad(Type.INT, l));
+ il.append(factory.createInvoke("java.lang.System", "arraycopy",
+ Type.VOID,
+ new Type[] {object, Type.INT, object, Type.INT, Type.INT },
+ Constants.INVOKESTATIC));
+ // generated: System.arraycopy(_OT$activeTeamIDs, 0, newTeamIDs, 1, l);
+
+ il.append(InstructionFactory.createLoad(teamArray, newTeams));
+ il.append(factory.createFieldAccess(class_name, _OT_ACTIVE_TEAMS, teamArray, Constants.PUTSTATIC));
+ // generated: _OT$activeTeams = newTeams;
+
+ il.append(InstructionFactory.createLoad(intArray, newTeamIDs));
+ il.append(factory.createFieldAccess(class_name, _OT_ACTIVE_TEAM_IDS, intArray, Constants.PUTSTATIC));
+ // generated: _OT$activeTeamIDs = newTeamIDs;
+
+ il.append(factory.createFieldAccess(class_name, _OT_ACTIVE_TEAMS, teamArray, Constants.GETSTATIC));
+ il.append(new ICONST(0));
+ il.append(new ALOAD(0));
+ il.append(InstructionFactory.createArrayStore(teamType));
+ // generated: _OT$activeTeams[0] = team;
+
+ il.append(factory.createFieldAccess(class_name, _OT_ACTIVE_TEAM_IDS, intArray, Constants.GETSTATIC));
+ il.append(new ICONST(0));
+ il.append(new ILOAD(1));
+ il.append(InstructionFactory.createArrayStore(Type.INT));
+ // generated: _OT$activeTeamIDs[0] = teamID;
+
+ if (CallinBindingManager.isRole(class_name)) {
+ il.append(new ALOAD(0));
+ il.append(new ILOAD(1));
+ il.append(factory.createInvoke(class_name, "_OT$activateNotify", Type.VOID, new Type[] { teamType, Type.INT }, Constants.INVOKESTATIC));
+ // generated: _OT$activateNotify(team, teamID);
+ }
+
+ // No more access to array fields, release monitor:
+ InstructionHandle exitSequence =
+ il.append(InstructionFactory.createLoad(Type.OBJECT, monitor));
+ il.append(new MONITOREXIT());
+ earlyExit.setTarget(exitSequence);
+
+ il.append(InstructionFactory.createReturn(Type.VOID));
+
+ addTeamMethod.setMaxStack();
+ addTeamMethod.setMaxLocals();
+ addTeamMethod.removeNOPs();
+ return addTeamMethod;
+ }
+
+ /* Code to be generated:
+ public static void _OT$removeTeam(Team team)
+ {
+ int l;
+ if((l = _OT$activeTeams.length) == 0)
+ return;
+ boolean found = false;
+ int newLen= l-1;
+ Team newTeams[] = new Team[newLen];
+ int newTeamIDs[] = new int[newLen];
+ for(int i = 0; i < l; i++)
+ if(!found)
+ {
+ if(_OT$activeTeams[i] == team)
+ {
+ found = true;
+ } else if (i<newLen) { // coded as: jump if (newLen<=i)
+ {
+ newTeams[i] = _OT$activeTeams[i];
+ newTeamIDs[i] = _OT$activeTeamIDs[i];
+ }
+ } else
+ {
+ newTeams[i - 1] = _OT$activeTeams[i];
+ newTeamIDs[i - 1] = _OT$activeTeamIDs[i];
+ }
+
+ if(found)
+ {
+ _OT$activeTeams = newTeams;
+ _OT$activeTeamIDs = newTeamIDs;
+ }
+ }
+ */
+ private MethodGen genRemoveTeam(String class_name, int major, ConstantPoolGen cpg)
+ {
+ LocalVariableGen lg;
+ InstructionList il;
+ int l;
+ BranchHandle emptyArray;
+ int newTeams;
+ int newTeamIDs;
+ il = new InstructionList();
+ MethodGen removeTeamMethod = new MethodGen(Constants.ACC_PUBLIC | Constants.ACC_STATIC | Constants.ACC_SYNCHRONIZED,
+ Type.VOID,
+ new Type[] { teamType },
+ new String[] { "team" },
+ "_OT$removeTeam", class_name,
+ il, cpg);
+
+ // synchronized (BaseClass.class) {
+ int monitor = addClassMonitorEnter(removeTeamMethod, il, class_name, major, cpg).first;
+
+ il.append(factory.createFieldAccess(class_name, _OT_ACTIVE_TEAMS, teamArray, Constants.GETSTATIC));
+ il.append(new ARRAYLENGTH());
+ lg = removeTeamMethod.addLocalVariable("l", Type.INT, null, null);
+ //int l = lg.getIndex();
+ l = lg.getIndex();
+ il.append(new DUP());
+ lg.setStart(il.append(InstructionFactory.createStore(Type.INT, l)));
+ // generated: int l = _OT$activeTeams.length;
+
+ emptyArray = il.append(new IFNE(null));
+ GOTO earlyExit = new GOTO(null);
+ il.append(earlyExit);
+ emptyArray.setTarget(il.append(new NOP()));
+ // generated: if (l == 0) return;
+
+ lg = removeTeamMethod.addLocalVariable("found", Type.BOOLEAN, null, null);
+ int found = lg.getIndex();
+ il.append(new ICONST(0));
+ lg.setStart(il.append(InstructionFactory.createStore(Type.BOOLEAN, found)));
+ // generated: boolean found = false;
+
+ lg = removeTeamMethod.addLocalVariable("newTeams", teamArray, null, null);
+ newTeams = lg.getIndex();
+ il.append(InstructionFactory.createLoad(Type.INT, l));
+ // [SH]: variable newLen
+ LocalVariableGen lgNewLen= removeTeamMethod.addLocalVariable("newLen", Type.INT, il.getEnd(), null);
+ il.append(new ICONST(1));
+ il.append(new ISUB());
+ // [SH] store for later use:
+ il.append(new DUP());
+ il.append(InstructionFactory.createStore(Type.INT, lgNewLen.getIndex()));
+ // [HS] generated: "newLen= l-1;"
+ il.append((Instruction)factory.createNewArray(teamType, (short)1));
+ lg.setStart(il.append(InstructionFactory.createStore(teamArray, newTeams)));
+ // generated: Team[] newTeams = new Team[newLen];
+
+ lg = removeTeamMethod.addLocalVariable("newTeamIDs", intArray, null, null);
+ //int newTeamIDs = lg.getIndex();
+ newTeamIDs = lg.getIndex();
+ //[SH]:
+ il.append(InstructionFactory.createLoad(Type.INT, lgNewLen.getIndex()));
+ il.append((Instruction)factory.createNewArray(Type.INT, (short)1));
+ lg.setStart(il.append(InstructionFactory.createStore(intArray, newTeamIDs)));
+ // generated: int[] newTeamIDs = new int[newLen];
+
+ // start for-loop
+ lg = removeTeamMethod.addLocalVariable("i", Type.INT, null, null);
+ int loopCounter = lg.getIndex();
+ il.append(new ICONST(0));
+ lg.setStart(il.append(InstructionFactory.createStore(Type.INT, loopCounter)));
+ GOTO try_leave_loop = new GOTO(null);
+ il.append(try_leave_loop);
+ InstructionHandle i_lower_l = il.append(new NOP());
+ // loop body:
+ il.append(InstructionFactory.createLoad(Type.BOOLEAN, found));
+ IFNE already_found = new IFNE(null);
+ il.append(already_found);
+
+ // outer if part:
+ il.append(factory.createFieldAccess(class_name, _OT_ACTIVE_TEAMS, teamArray, Constants.GETSTATIC));
+ il.append(new ILOAD(loopCounter));
+ il.append(InstructionFactory.createArrayLoad(teamType));
+ il.append(new ALOAD(0)); //first parameter
+ IF_ACMPNE teams_not_equal = new IF_ACMPNE(null);
+ il.append(teams_not_equal);
+
+ // inner if part:
+ il.append(new ICONST(1));
+ il.append(InstructionFactory.createStore(Type.BOOLEAN, found));
+ GOTO skip_outer_else_part = new GOTO(null);
+ il.append(skip_outer_else_part);
+
+ // inner else part:
+ teams_not_equal.setTarget(il.append(new NOP()));
+
+ // [SH] sanity check:
+ il.append(InstructionFactory.createLoad(Type.INT, lgNewLen.getIndex()));
+ il.append(new ILOAD(loopCounter));
+ IF_ICMPLE if_len_le_i= new IF_ICMPLE(null);
+ il.append(if_len_le_i);
+ // [HS] generated: else if (!(newLen <= i)) {
+ il.append(new ALOAD(newTeams));
+ il.append(new ILOAD(loopCounter));
+ il.append(factory.createFieldAccess(class_name, _OT_ACTIVE_TEAMS, teamArray, Constants.GETSTATIC));
+ il.append(new ILOAD(loopCounter));
+ il.append(InstructionFactory.createArrayLoad(teamType));
+ il.append(new AASTORE());
+ // generated: newTeams[i] = _OT$activeTeams[i];
+
+ il.append(new ALOAD(newTeamIDs));
+ il.append(new ILOAD(loopCounter));
+ il.append(factory.createFieldAccess(class_name, _OT_ACTIVE_TEAM_IDS, intArray, Constants.GETSTATIC));
+ il.append(new ILOAD(loopCounter));
+ il.append(InstructionFactory.createArrayLoad(Type.INT));
+ il.append(new IASTORE());
+ // generated: newTeamIDs[i] = _OT$activeTeamIDs[i];
+
+ GOTO end_of_loop = new GOTO(null);
+ il.append(end_of_loop);
+
+ // outer else part:
+ already_found.setTarget(il.append(new NOP()));
+ il.append(new ALOAD(newTeams));
+ il.append(new ILOAD(loopCounter));
+ il.append(new ICONST(1));
+ il.append(new ISUB());
+ il.append(factory.createFieldAccess(class_name, _OT_ACTIVE_TEAMS, teamArray, Constants.GETSTATIC));
+ il.append(new ILOAD(loopCounter));
+ il.append(InstructionFactory.createArrayLoad(teamType));
+ il.append(new AASTORE());
+ // generated: newTeams[i-1] = _OT$activeTeams[i];
+
+ il.append(new ALOAD(newTeamIDs));
+ il.append(new ILOAD(loopCounter));
+ il.append(new ICONST(1));
+ il.append(new ISUB());
+ il.append(factory.createFieldAccess(class_name, _OT_ACTIVE_TEAM_IDS, intArray, Constants.GETSTATIC));
+ il.append(new ILOAD(loopCounter));
+ il.append(InstructionFactory.createArrayLoad(Type.INT));
+ il.append(new IASTORE());
+ // generated: newTeamIDs[i-1] = _OT$activeTeamIDs[i];
+
+ skip_outer_else_part.setTarget(il.append(new NOP()));
+ // [SH] connect "else if" from above:
+ if_len_le_i.setTarget(il.getEnd());
+ end_of_loop.setTarget(il.append(new IINC(loopCounter, 1)));
+ try_leave_loop.setTarget(il.append(InstructionFactory.createLoad(Type.INT, loopCounter)));
+ il.append(new ILOAD(l));
+ il.append(new IF_ICMPLT(i_lower_l));
+ // end for-loop
+
+ il.append(InstructionFactory.createLoad(Type.BOOLEAN, found));
+ BranchHandle notFound = il.append(new IFEQ(null));
+ // generated: if (found) {
+
+ il.append(InstructionFactory.createLoad(teamArray, newTeams));
+ il.append(factory.createFieldAccess(class_name, _OT_ACTIVE_TEAMS, teamArray, Constants.PUTSTATIC));
+ // generated: _OT$activeTeams = newTeams;
+
+ il.append(InstructionFactory.createLoad(intArray, newTeamIDs));
+ il.append(factory.createFieldAccess(class_name, _OT_ACTIVE_TEAM_IDS, intArray, Constants.PUTSTATIC));
+ // generated: _OT$activeTeamIDs = newTeamIDs;
+
+ if (CallinBindingManager.isRole(class_name)) {
+ il.append(new ALOAD(0));
+ il.append(factory.createInvoke(class_name, "_OT$deactivateNotify", Type.VOID, new Type[] { teamType }, Constants.INVOKESTATIC));
+ // generated: _OT$deactivateNotify(team);
+ }
+
+ // No more access to array fields, release monitor:
+ InstructionHandle exitSequence =
+ il.append(InstructionFactory.createLoad(Type.OBJECT, monitor));
+ il.append(new MONITOREXIT());
+ earlyExit.setTarget(exitSequence);
+ notFound.setTarget(exitSequence);
+
+ il.append(InstructionFactory.createReturn(Type.VOID));
+
+ removeTeamMethod.setMaxStack();
+ removeTeamMethod.setMaxLocals();
+ removeTeamMethod.removeNOPs();
+ return removeTeamMethod;
+ }
+
+ /**
+ * Add infrastructure for implicit subclasses to register and be notified. This 'observer' mechanism
+ * is necessary, because an implicit subclass does not inherit the addition/removal
+ * of a team at the implicit superclass.
+ * @param ce The ClassEnhancer object to add methods and fields.
+ * @param cg The ClassGen object representing the current class.
+ */
+ private void addImplicitSubclassNotificationInfrastructure(ClassEnhancer ce, ClassGen cg) {
+
+ ConstantPoolGen cpg = cg.getConstantPool();
+ factory = new InstructionFactory(cpg);
+ String class_name = cg.getClassName();
+ ObjectType linkedListType = new ObjectType("java.util.LinkedList");
+ int accessFlags = Constants.ACC_PROTECTED | Constants.ACC_STATIC;
+ FieldGen teamRegistrationObserversField = new FieldGen(accessFlags, linkedListType, "_OT$teamRegistrationObservers", cpg);
+ ce.addField(teamRegistrationObserversField.getField(), cg);
+
+/***********************************************************************************************************/
+
+ InstructionList il = new InstructionList();
+
+ MethodGen observerRegistrationMethod = new MethodGen(Constants.ACC_PUBLIC | Constants.ACC_STATIC,
+ Type.VOID,
+ new Type[] { classType },
+ new String[] { "implicitSubClass" },
+ "_OT$registerObserver", class_name,
+ il, cpg);
+
+ il.append(factory.createFieldAccess(class_name, "_OT$teamRegistrationObservers", linkedListType, Constants.GETSTATIC));
+ il.append(InstructionFactory.createLoad(classType, 0));
+ il.append(factory.createInvoke("java.util.LinkedList", "add", Type.BOOLEAN, new Type[] { Type.OBJECT }, Constants.INVOKEVIRTUAL));
+ il.append(new POP());
+ il.append(new RETURN());
+
+ observerRegistrationMethod.setMaxStack(2);
+ observerRegistrationMethod.setMaxLocals();
+
+ ce.addMethod(observerRegistrationMethod.getMethod(), cg);
+/***********************************************************************************************************/
+ il = new InstructionList();
+
+ MethodGen activateNotifyMethod = new MethodGen(Constants.ACC_PUBLIC | Constants.ACC_STATIC,
+ Type.VOID,
+ new Type[] { teamType, Type.INT },
+ new String[] { "team", "teamID" },
+ "_OT$activateNotify", class_name,
+ il, cpg);
+
+ createNotifyMethodImplementation(activateNotifyMethod, cpg, class_name);
+
+ ce.addMethod(activateNotifyMethod.getMethod(), cg);
+/***********************************************************************************************************/
+ il = new InstructionList();
+
+ MethodGen deactivateNotifyMethod = new MethodGen(Constants.ACC_PUBLIC | Constants.ACC_STATIC,
+ Type.VOID,
+ new Type[] { teamType },
+ new String[] { "team" },
+ "_OT$deactivateNotify", class_name,
+ il, cpg);
+ createNotifyMethodImplementation(deactivateNotifyMethod, cpg, class_name);
+
+ ce.addMethod(deactivateNotifyMethod.getMethod(), cg);
+ }
+
+
+ /**
+ * Create implementation of methods '_OT$activateNotify' and _OT$deactivateNotify'.
+ * @param notifyMethod Method which has to be implemented.
+ * @param cpg Corresponding constant pool.
+ * @param class_name Name of the class for wich to implement the method.
+ */
+ private void createNotifyMethodImplementation(MethodGen notifyMethod, ConstantPoolGen cpg, String class_name) {
+ boolean isActivateMethod = notifyMethod.getName().equals("_OT$activateNotify");
+// int methodArgs = isActivateMethod ? 2 : 1;
+
+ int iteratorIdx = isActivateMethod ? 2 : 1;
+ int curClassIdx = isActivateMethod ? 3 : 2;
+ int anotherIdx1 = isActivateMethod ? 4 : 3;
+ int anotherIdx2 = isActivateMethod ? 5 : 4;
+ String methodToInvoke = isActivateMethod ? "_OT$addTeam" : "_OT$removeTeam";
+
+ InstructionList il = notifyMethod.getInstructionList();
+ il.append(factory.createFieldAccess(class_name, "_OT$teamRegistrationObservers", new ObjectType("java.util.LinkedList"), Constants.GETSTATIC));
+ BranchInstruction ifnonnull_3 = InstructionFactory.createBranchInstruction(Constants.IFNONNULL, null);
+ il.append(ifnonnull_3);
+ il.append(InstructionFactory.createReturn(Type.VOID));
+ InstructionHandle ih_7 = il.append(factory.createFieldAccess(class_name, "_OT$teamRegistrationObservers", new ObjectType("java.util.LinkedList"), Constants.GETSTATIC));
+ il.append(factory.createInvoke("java.util.LinkedList", "iterator", new ObjectType("java.util.Iterator"), Type.NO_ARGS, Constants.INVOKEVIRTUAL));
+ il.append(InstructionFactory.createStore(Type.OBJECT,iteratorIdx));
+ InstructionHandle ih_14 = il.append(InstructionFactory.createLoad(Type.OBJECT,iteratorIdx));
+ il.append(factory.createInvoke("java.util.Iterator", "hasNext", Type.BOOLEAN, Type.NO_ARGS, Constants.INVOKEINTERFACE));
+ BranchInstruction ifeq_20 = InstructionFactory.createBranchInstruction(Constants.IFEQ, null);
+ il.append(ifeq_20);
+ il.append(InstructionFactory.createLoad(Type.OBJECT,iteratorIdx));
+ il.append(factory.createInvoke("java.util.Iterator", "next", Type.OBJECT, Type.NO_ARGS, Constants.INVOKEINTERFACE));
+ il.append(factory.createCheckCast(classType));
+ il.append(InstructionFactory.createStore(Type.OBJECT,curClassIdx));
+ il.append(InstructionConstants.ACONST_NULL);
+ il.append(InstructionFactory.createStore(Type.OBJECT,anotherIdx1));
+ InstructionHandle ih_36 = il.append(InstructionFactory.createLoad(Type.OBJECT,curClassIdx));
+ il.append(new PUSH(cpg, methodToInvoke));
+ il.append(new PUSH(cpg,iteratorIdx));
+ il.append((Instruction)factory.createNewArray(classType, (short) 1));
+ il.append(InstructionConstants.DUP);
+
+ il.append(new PUSH(cpg, 0));
+ il.append(new PUSH(cpg, OTConstants.teamName));
+ il.append(factory.createInvoke("java.lang.Class", "forName",
+ classType, new Type[] { Type.STRING },
+ Constants.INVOKESTATIC));
+
+ il.append(InstructionConstants.AASTORE);
+ if (isActivateMethod){ // add the integer argument:
+ il.append(InstructionConstants.DUP);
+ il.append(new PUSH(cpg, 1));
+ il.append(factory.createFieldAccess("java.lang.Integer", "TYPE", classType, Constants.GETSTATIC));
+ il.append(InstructionConstants.AASTORE);
+ }
+ il.append(factory.createInvoke("java.lang.Class", "getMethod", new ObjectType("java.lang.reflect.Method"), new Type[] { Type.STRING, new ArrayType(classType, 1) }, Constants.INVOKEVIRTUAL));
+ InstructionHandle ih_76 = il.append(InstructionFactory.createStore(Type.OBJECT,anotherIdx1));
+ BranchInstruction goto_78 = InstructionFactory.createBranchInstruction(Constants.GOTO, null);
+ il.append(goto_78);
+ InstructionHandle ih_81 = il.append(InstructionFactory.createStore(Type.OBJECT,anotherIdx2));
+ il.append(factory.createFieldAccess("java.lang.System", "err", new ObjectType("java.io.PrintStream"), Constants.GETSTATIC));
+ il.append(new PUSH(cpg, "activateNotifyMethod not found!"));
+ il.append(factory.createInvoke("java.io.PrintStream", "println", Type.VOID, new Type[] { Type.STRING }, Constants.INVOKEVIRTUAL));
+ InstructionHandle ih_91 = il.append(InstructionFactory.createLoad(Type.OBJECT,anotherIdx1));
+ BranchInstruction ifnull_93 = InstructionFactory.createBranchInstruction(Constants.IFNULL, null);
+ il.append(ifnull_93);
+ il.append(InstructionFactory.createLoad(Type.OBJECT,anotherIdx1));
+ il.append(InstructionConstants.ACONST_NULL);
+ il.append(new PUSH(cpg,iteratorIdx));
+ il.append((Instruction)factory.createNewArray(Type.OBJECT, (short) 1));
+ il.append(InstructionConstants.DUP);
+ il.append(new PUSH(cpg, 0));
+ il.append(InstructionFactory.createLoad(Type.OBJECT, 0));
+ il.append(InstructionConstants.AASTORE);
+
+ if (isActivateMethod) { // load the integer argument:
+ il.append(InstructionConstants.DUP);
+ il.append(new PUSH(cpg, 1));
+ il.append(factory.createNew("java.lang.Integer"));
+ il.append(InstructionConstants.DUP);
+ il.append(InstructionFactory.createLoad(Type.INT, 1));
+ il.append(factory.createInvoke("java.lang.Integer", Constants.CONSTRUCTOR_NAME, Type.VOID, new Type[] { Type.INT }, Constants.INVOKESPECIAL));
+ il.append(InstructionConstants.AASTORE);
+ }
+ il.append(factory.createInvoke("java.lang.reflect.Method", "invoke", Type.OBJECT, new Type[] { Type.OBJECT, new ArrayType(Type.OBJECT, 1) }, Constants.INVOKEVIRTUAL));
+ InstructionHandle ih_121 = il.append(InstructionConstants.POP);
+ InstructionHandle ih_122;
+ BranchInstruction goto_122 = InstructionFactory.createBranchInstruction(Constants.GOTO, ih_14);
+ ih_122 = il.append(goto_122);
+ InstructionHandle ih_125 = il.append(InstructionFactory.createStore(Type.OBJECT,anotherIdx2));
+ il.append(factory.createFieldAccess("java.lang.System", "err", new ObjectType("java.io.PrintStream"), Constants.GETSTATIC));
+ il.append(new PUSH(cpg, "Can not call activateNotifyMethod!"));
+ il.append(factory.createInvoke("java.io.PrintStream", "println", Type.VOID, new Type[] { Type.STRING }, Constants.INVOKEVIRTUAL));
+ BranchInstruction goto_135 = InstructionFactory.createBranchInstruction(Constants.GOTO, ih_14);
+ il.append(goto_135);
+ InstructionHandle ih_138 = il.append(InstructionFactory.createStore(Type.OBJECT,anotherIdx2));
+ il.append(factory.createFieldAccess("java.lang.System", "err", new ObjectType("java.io.PrintStream"), Constants.GETSTATIC));
+ il.append(new PUSH(cpg, "InvocationTargetException"));
+ il.append(factory.createInvoke("java.io.PrintStream", "println", Type.VOID, new Type[] { Type.STRING }, Constants.INVOKEVIRTUAL));
+ BranchInstruction goto_148 = InstructionFactory.createBranchInstruction(Constants.GOTO, ih_14);
+ il.append(goto_148);
+ InstructionHandle ih_151 = il.append(InstructionFactory.createReturn(Type.VOID));
+ ifnonnull_3.setTarget(ih_7);
+ ifeq_20.setTarget(ih_151);
+ goto_78.setTarget(ih_91);
+ ifnull_93.setTarget(ih_122);
+ notifyMethod.addExceptionHandler(ih_36, ih_76, ih_81, new ObjectType("java.lang.NoSuchMethodException"));
+ notifyMethod.addExceptionHandler(ih_91, ih_121, ih_125, new ObjectType("java.lang.IllegalAccessException"));
+ notifyMethod.addExceptionHandler(ih_91, ih_121, ih_138, new ObjectType("java.lang.reflect.InvocationTargetException"));
+
+ notifyMethod.setMaxStack();
+ notifyMethod.setMaxLocals();
+ }
+
+ /**
+ * Adds initialization of the team array and the team index array to the static initializer of this class.
+ * If this base class is a role at the same time, then also add initialization of the observer list.
+ * @param cg The representation of the class.
+ * @param cpg The constant pool of the class.
+ */
+ private void addStaticInitializations(ClassGen cg, ConstantPoolGen cpg) {
+ Method clinitMethod = cg.containsMethod(Constants.STATIC_INITIALIZER_NAME, "()V");
+ /* The clinit method always exists at this moment, because it has been added
+ * by the interface transformer part of this transformer if necessary.
+ */
+ MethodGen mg = new MethodGen(clinitMethod, cg.getClassName(), cpg);
+ InstructionList il = mg.getInstructionList();
+ // add static initialization for added static fields at start of the <clinit> method:
+ il.insert(inizializeStaticFields(cg.getClassName()));
+ mg.setMaxStack();
+ mg.setMaxLocals();
+ Method newClinit = mg.getMethod();
+ cg.replaceMethod(clinitMethod, newClinit);
+ il.dispose();
+ // Reuse instruction handles
+ }
+
+ /**
+ * @param class_name
+ * @return
+ */
+ private InstructionList inizializeStaticFields(String class_name) {
+ // STATIC_PARTS_TODO : in base: static initialization of team fields
+ InstructionList il = new InstructionList();
+ il.append(new ICONST(0));
+ il.append((Instruction)factory.createNewArray(teamType, (short)1));
+ //this are very strange (but necessary!?) casts...
+ il.append(factory.createFieldAccess(class_name, _OT_ACTIVE_TEAMS, teamArray, Constants.PUTSTATIC));
+ //generated: _OT$activeTeams = new Team[0];
+
+ il.append(new ICONST(0));
+ il.append((Instruction)factory.createNewArray(Type.INT, (short)1));
+ //this are very strange (but necessary!?) casts...
+ il.append(factory.createFieldAccess(class_name, _OT_ACTIVE_TEAM_IDS, intArray, Constants.PUTSTATIC));
+ //generated: _OT$activeTeamIDs = new int[0];
+
+ if (CallinBindingManager.isRole(class_name)) {
+ ObjectType linkedListType = new ObjectType("java.util.LinkedList");
+ il.append(factory.createNew(linkedListType));
+ il.append(new DUP());
+ il.append(factory.createInvoke("java.util.LinkedList",
+ Constants.CONSTRUCTOR_NAME,
+ Type.VOID, Type.NO_ARGS,
+ Constants.INVOKESPECIAL));
+
+ il.append(factory.createFieldAccess(class_name,
+ "_OT$teamRegistrationObservers",
+ linkedListType, Constants.PUTSTATIC ));
+
+ //generated: _OT$teamRegistrationObservers = new LinkedList();
+ }
+ return il;
+ }
+}
diff --git a/othersrc/OTRE/src/org/eclipse/objectteams/otre/SubBoundBaseMethodRedefinition.java b/othersrc/OTRE/src/org/eclipse/objectteams/otre/SubBoundBaseMethodRedefinition.java
new file mode 100644
index 0000000..104374d
--- /dev/null
+++ b/othersrc/OTRE/src/org/eclipse/objectteams/otre/SubBoundBaseMethodRedefinition.java
@@ -0,0 +1,175 @@
+/**********************************************************************
+ * 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: SubBoundBaseMethodRedefinition.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.classfile.*;
+import de.fub.bytecode.generic.*;
+import de.fub.bytecode.*;
+
+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(SharedState state) { this(null, state); }
+ public SubBoundBaseMethodRedefinition(ClassLoader loader, SharedState state) { super(loader, state); }
+
+ /**
+ * 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);
+
+ // if class is already transformed by this transformer
+ if (state.interfaceTransformedClasses.contains(class_name)) {
+ return;
+ }
+
+ 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);
+ state.interfaceTransformedClasses.add(class_name);
+ }
+
+ /**
+ * 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;
+ }
+}
diff --git a/othersrc/OTRE/src/org/eclipse/objectteams/otre/TeamInterfaceImplementation.java b/othersrc/OTRE/src/org/eclipse/objectteams/otre/TeamInterfaceImplementation.java
new file mode 100644
index 0000000..faa7cd1
--- /dev/null
+++ b/othersrc/OTRE/src/org/eclipse/objectteams/otre/TeamInterfaceImplementation.java
@@ -0,0 +1,1011 @@
+/**********************************************************************
+ * 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: TeamInterfaceImplementation.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.classfile.*;
+import de.fub.bytecode.generic.*;
+import de.fub.bytecode.*;
+
+import java.util.*;
+
+import org.eclipse.objectteams.otre.util.*;
+
+/**
+ * Adds the general Team infrastructure to team classes.
+ *
+ * Fields: public (static) final_OT$ID <- static if 'ot.no_static' ist set
+ * Methods: public int activate(int level) public int deactivate(int level)
+ * public int _OT$getID() Static initialization (adds clinit method, if not yet
+ * presented) OR to every constructor: <- if 'ot.no_static' is set _OT$ID =
+ * TeamIdDispenser.getTeamId(class_name)
+ *
+ * Enables implicit team activation for normal (user defined) public team-level
+ * methods. A call to 'activate' is woven at the beginning of the method. A call
+ * to 'deactivate' is woven before every return and at every thrown exception.
+ *
+ * @version $Id: TeamInterfaceImplementation.java 23408 2010-02-03 18:07:35Z stephan $
+ * @author Christine Hundt
+ * @author Stephan Herrmann
+ */
+public class TeamInterfaceImplementation
+ extends ObjectTeamsTransformation {
+
+ private boolean isJPLIS;
+
+
+ public TeamInterfaceImplementation(boolean isJPLIS, SharedState state) {
+ this(isJPLIS, null, state);
+ }
+
+ public TeamInterfaceImplementation(boolean isJPLIS, ClassLoader loader, SharedState state) {
+ super(loader, state);
+ this.isJPLIS = isJPLIS;
+ }
+
+ /**
+ * @param cg
+ */
+ public void doTransformCode(ClassGen cg) {
+ factory = new InstructionFactory(cg);
+
+ if (!classNeedsTeamExtensions(cg)) {
+ return;
+ }
+
+ ConstantPoolGen cpg = cg.getConstantPool();
+ String class_name = cg.getClassName();
+ genImplicitActivation(cg, cpg);
+
+ InstructionList implicitSuperRoleRegistrations = genImplicitSuperRegistration(cg, cpg);
+ if (!implicitSuperRoleRegistrations.isEmpty()) {
+ // add implicitSuperRoleRegistrations to the static initializer:
+ Method clinitMethod = cg.containsMethod(Constants.STATIC_INITIALIZER_NAME, "()V");
+ addToMethodStart(implicitSuperRoleRegistrations, clinitMethod, cg, cpg);
+ }
+
+ if (CallinBindingManager.getBasesPerTeam(class_name) == null) {
+ return; // this team does not adapt any base class
+ }
+
+ /**
+ * ******************* add initialization of the field '_OT$ID' to the static initializer : ******
+ */
+ int nextTeamId = TeamIdDispenser.getTeamId(class_name);
+
+ /*
+ * The clinit method always exists at this moment, because it has
+ * been added by the interface transformer part of this transformer
+ * if necessary.
+ */
+ addStaticInitializations(nextTeamId, cg, cpg);
+ }
+
+ /**
+ * Add initialization of "_OT$ID" with 'nextTeamID' to the static
+ * initializer of this team class.
+ *
+ * @param nextTeamId
+ * the id which will be associated with the currently transformed
+ * team
+ * @param cg
+ * the ClassGen for the given team class
+ * @param cpg
+ * the constant pool ot the team
+ */
+ private void addStaticInitializations(int nextTeamId, ClassGen cg,
+ ConstantPoolGen cpg) {
+ Method clinitMethod = cg.containsMethod(
+ Constants.STATIC_INITIALIZER_NAME, "()V");
+ MethodGen mg = new MethodGen(clinitMethod, cg.getClassName(), cpg);
+ InstructionList il = mg.getInstructionList();
+
+ InstructionList addedInitialization = new InstructionList();
+ addedInitialization.append(createIntegerPush(cpg, nextTeamId));
+ addedInitialization.append(factory.createFieldAccess(cg.getClassName(),
+ "_OT$ID", Type.INT, Constants.PUTSTATIC));
+ // generated: _OT$ID = <id dispensed by TeamIdDispenser>;
+
+ // add static initialization for added static field at the beginning of
+ // the <clinit> method:
+ il.insert(addedInitialization);
+ mg.setMaxStack();
+ mg.setMaxLocals();
+
+ Method newClinit = mg.getMethod();
+ cg.replaceMethod(clinitMethod, newClinit);
+
+ il.dispose(); // Reuse instruction handles
+ }
+
+ /**
+ * For all roles in the current team which have tsuper versions:
+ * Generate instruction list containig calls to registration methods
+ * the implicit super roles.
+ *
+ * @param cg The ClassGen of the current team.
+ * @param cpg The constant pool of the current team.
+ * @return The instruction list containing the registration calls.
+ */
+ private InstructionList genImplicitSuperRegistration(ClassGen cg, ConstantPoolGen cpg) {
+ InstructionList il = new InstructionList();
+ List<String> inheritedRoleNames = getInheritedRoleNames(cg, cpg);
+ if (inheritedRoleNames.isEmpty())
+ return il; // nothing to do
+ Iterator<String> iter = inheritedRoleNames.iterator();
+ while (iter.hasNext()) {
+ String roleName = iter.next();
+ String unqualifiedRoleName = roleName.substring(roleName.lastIndexOf('$') + 1);
+ if (CallinBindingManager.isBoundBaseAndRoleClass(roleName)) {
+ String potientialImplicitSuperRoleName = cg.getSuperclassName() + '$' + unqualifiedRoleName;
+
+ if (!CallinBindingManager.isBoundBaseAndRoleClass(potientialImplicitSuperRoleName)) {
+ // Only bound base classes have the infrastructure for notifying
+ // implicit subclasses about team activation!
+ continue;
+ }
+ il.append(new PUSH(cpg, roleName));
+ il.append(factory.createInvoke("java.lang.Class", "forName",
+ classType, new Type[] { Type.STRING },
+ Constants.INVOKESTATIC));
+ il.append(factory.createInvoke(potientialImplicitSuperRoleName, "_OT$registerObserver",
+ Type.VOID, new Type [] { classType },
+ Constants.INVOKESTATIC));
+ }
+ }
+ return il;
+ }
+
+ public void doTransformInterface(ClassEnhancer ce, ClassGen cg) {
+ String class_name = cg.getClassName();
+ ConstantPoolGen cpg = cg.getConstantPool();
+
+ checkReadClassAttributes(ce, cg, class_name, cpg);
+
+ if (state.interfaceTransformedClasses.contains(class_name)) {
+ return; // class has already been transformed by this transformer
+ }
+
+ if (!classNeedsTeamExtensions(cg)) {
+ return;
+ }
+
+ factory = new InstructionFactory(cg);
+
+ /**
+ * ********** empty implementation of the static class initialization method '<clinit>' ***
+ * NOTE: this is unnecessary in some cases, but checking is too complicated
+ */
+ addStaticInitializer(cg, cpg, class_name, ce);
+
+ List<String> handledBases = CallinBindingManager.getBasesPerTeam(class_name);
+ // TeamInterfaceImplementer only registers teams at bases, wich are part
+ // of a 'CallinRoleBaseBinding'-attribute of the team.
+ if (handledBases == null) {
+ return; // this team does not adapt any base class
+ }
+
+ if(logging) printLogMessage("Adding the general Team infrastructure to "
+ + class_name);
+
+ /**
+ * ******************* addition of the field '_OT$ID'
+ * **********************************
+ */
+
+ int accessFlags = Constants.ACC_PUBLIC | Constants.ACC_FINAL | Constants.ACC_STATIC;
+
+ FieldGen IDField = new FieldGen(accessFlags, Type.INT, "_OT$ID", cpg);
+ ce.addField(IDField.getField(), cg);
+ // generated global variable: public final static int _OT$ID;
+
+ factory = new InstructionFactory(cpg);
+ InstructionList il;
+
+ /**
+ * ******************* implementation of method '_OT$getID'
+ * ************************
+ */
+
+ il = new InstructionList();
+ MethodGen getIDMethod = new MethodGen(Constants.ACC_PUBLIC, Type.INT,
+ Type.NO_ARGS, new String[] {}, "_OT$getID", class_name, il, cpg);
+
+ il.append(factory.createFieldAccess(class_name, "_OT$ID", Type.INT,
+ Constants.GETSTATIC));
+ il.append(InstructionFactory.createReturn(Type.INT));
+
+ getIDMethod.setMaxStack();
+ getIDMethod.setMaxLocals();
+
+ ce.addMethod(getIDMethod.getMethod(), cg);
+
+ /**
+ * ***************** implementation of team (un)registration methods
+ * **********************
+ */
+
+ ce.addMethod(generateTeamRegistrationMethod(cpg, class_name,
+ handledBases), cg);
+
+ ce.addMethod(generateTeamUnregistrationMethod(cpg, class_name,
+ handledBases), cg);
+
+ /**
+ * ***************** implementation of base call surrogtes for static methods
+ * **********************
+ */
+ Method [] base_call_surrogates = generateStaticBaseCallSurrogates(class_name, cpg, cg);
+ for(int i=0; i<base_call_surrogates.length;i++) {
+ // perhaps the compiler already generated an empty surrogate for an unbound super-role?
+ // (see X.1.5-otjld-callin-from-static-base-method-12a)
+ ce.addOrReplaceMethod(base_call_surrogates[i], cg);
+ }
+
+ /** *************************************************************************** */
+
+ il.dispose();
+ state.interfaceTransformedClasses.add(class_name);
+ }
+
+ /**
+ * Add the given instruction list to the start of the givern method.
+ * @param additionalInstructions
+ * @param method
+ * @param cg
+ * @param cpg
+ */
+ private void addToMethodStart(InstructionList additionalInstructions, Method method, ClassGen cg, ConstantPoolGen cpg) {
+ MethodGen mg = new MethodGen(method, cg.getClassName(), cpg);
+ InstructionList il = mg.getInstructionList();
+ il.insert(additionalInstructions);
+ mg.setMaxStack();
+ mg.setMaxLocals();
+
+ Method newMethod = mg.getMethod();
+ cg.replaceMethod(method, newMethod);
+ il.dispose(); // Reuse instruction handles
+ }
+
+ /**
+ * Generate the static initializer method 'clinit'.
+ * @param cpg The constant pool
+ * @param class_name The name of the class
+ * @param cg The ClassGen for the class
+ * @return The static initialier for this class
+ */
+ void addStaticInitializer(ClassGen cg, ConstantPoolGen cpg, String class_name, ClassEnhancer ce) {
+ /*
+ * Adding static initializations requires the addition of the clinit
+ * method, if not yet presented. This requires synchronization with
+ * other transformers (TeamInterfaceImplementer) which may do the
+ * same this. This is done via 'TeamIdDispenser.clinitAdded(class_name)'.
+ */
+ Method existingClinit = cg.containsMethod(Constants.STATIC_INITIALIZER_NAME, "()V");
+ if (existingClinit == null && !TeamIdDispenser.clinitAdded(class_name, loader)) {
+ // otherwise the clinit-Method already exists and only has to be extended
+ // by the code transformation of this transformer
+ InstructionList il = new InstructionList();
+ MethodGen clinitMethodGen = new MethodGen(Constants.ACC_STATIC,
+ Type.VOID, Type.NO_ARGS, new String[] {},
+ Constants.STATIC_INITIALIZER_NAME, class_name, il, cpg);
+
+ il.append(InstructionFactory.createReturn(Type.VOID));
+
+ clinitMethodGen.setMaxStack();
+ clinitMethodGen.setMaxLocals();
+ Method clinitMethod = clinitMethodGen.getMethod();
+ ce.addMethod(clinitMethod, cg);
+ }
+ }
+
+ /**
+ * Generates the ' _OT$registerAtBases()' method. This method registers the
+ * team at every adapted base class by calling the respective 'addTeam'
+ * method.
+ *
+ * @param cpg
+ * The ConstantPoolGen of the team class.
+ * @param class_name
+ * The name of the team class.
+ * @param handledBases
+ * The list of teams adapted by (roles of) this team.
+ * @return The generated 'activate' method.
+ */
+ Method generateTeamRegistrationMethod(ConstantPoolGen cpg,
+ String class_name, List<String> handledBases)
+ {
+ InstructionList il = new InstructionList();
+ MethodGen mg = new MethodGen(Constants.ACC_PUBLIC, Type.VOID,
+ Type.NO_ARGS, null, "_OT$registerAtBases", class_name, il, cpg);
+
+ Iterator<String> it = handledBases.iterator();
+ while (it.hasNext()) {
+ String actBase = it.next();
+ //if (CallinBindingManager.hasBoundBaseParent(actBase))
+ // continue; // team was already added to a super base class
+ // problem: bound base parent could be bound to another team class!!!
+
+ //String boundBase = CallinBindingManager.getBoundBaseParent(actBase);
+ //if (boundBase != null && handledBases.contains(boundBase))
+ // continue;
+ if (CallinBindingManager.teamAdaptsSuperBase(class_name, actBase))
+ continue;
+
+ InstructionHandle startTry = il.append(new ALOAD(0));
+
+ il.append(factory.createFieldAccess(class_name, "_OT$ID", Type.INT,
+ Constants.GETSTATIC));
+ il.append(factory.createInvoke(actBase, "_OT$addTeam", Type.VOID,
+ new Type[] { teamType, Type.INT }, Constants.INVOKESTATIC));
+ // generated: <actBase>._OT$addTeam(this, _OT$ID);
+
+ addNoSuchMethodErrorHandling(startTry, il.getEnd(), getErrorMessage(class_name, actBase, "Activation"), il, mg, cpg);
+ }
+ il.append(new RETURN());
+
+ mg.setMaxStack();
+ mg.setMaxLocals();
+ return mg.getMethod();
+ }
+
+ /**
+ * Direct inverse of generateTeamRegistrationMethod(..). Generates the '
+ * _OT$unregisterFromBases' method. This method deregisters the team at
+ * every adapted base class by calling the respective 'removeTeam' method.
+ *
+ * @param cpg
+ * The ConstantPoolGen of the team class.
+ * @param class_name
+ * The name of the team class.
+ * @param handledBases
+ * The list of teams adapted by (roles of) this team.
+ * @return The generated 'deactivate' method.
+ */
+ Method generateTeamUnregistrationMethod(ConstantPoolGen cpg,
+ String class_name, List<String> handledBases) {
+
+ InstructionList il = new InstructionList();
+ MethodGen mg = new MethodGen(Constants.ACC_PUBLIC, Type.VOID,
+ Type.NO_ARGS, null, "_OT$unregisterFromBases", class_name, il,
+ cpg);
+
+ Iterator<String> it = handledBases.iterator();
+ while (it.hasNext()) {
+ String actBase = it.next();
+ //if (CallinBindingManager.hasBoundBaseParent(actBase))
+ // continue; // team was only added to a super base class
+ // problem: bound base parent could be bound to another team class!!!
+
+ // String boundBase = CallinBindingManager.getBoundBaseParent(actBase);
+ //if (boundBase != null && handledBases.contains(boundBase))
+ // continue;
+ if (CallinBindingManager.teamAdaptsSuperBase(class_name, actBase))
+ continue;
+
+ InstructionHandle startTry = il.append(new ALOAD(0));
+
+ il.append(factory.createInvoke(actBase, "_OT$removeTeam",
+ Type.VOID, new Type[] { teamType }, Constants.INVOKESTATIC));
+ // generated: <actBase>._OT$removeTeam(this, _OT$ID);
+
+ addNoSuchMethodErrorHandling(startTry, il.getEnd(), getErrorMessage(class_name, actBase, "Deactivation"), il, mg, cpg);
+ }
+ il.append(new RETURN());
+
+ mg.setMaxStack();
+ mg.setMaxLocals();
+ return mg.getMethod();
+ }
+
+ private String getErrorMessage(String teamName, String baseName, String action) {
+ String errorMessage = action+" of team '" + teamName + "' failed! Callins of this team have NOT been WOVEN into base class '" + baseName + "'!\n"
+ + "This is probably caused by a loading order problem.";
+ if (!isJPLIS)
+ errorMessage += "\nIf "+baseName+" is loaded from the bootstrap classpath launching the program in JPLIS mode may perhaps avoid this problem.";
+ return errorMessage;
+ }
+
+ /**
+ * Adds an exception handler to the given method which catches 'java.lang.NoSuchMethodError's
+ * caused by missing team registration methods in base classes. Causes the throwing of an
+ * 'org.objectteams.UnsupportedFeatureException'.
+ *
+ * @param startTry handle to the start of the try block
+ * @param endTry handle to the end of the try block
+ * @param errorMessage the error message to be printed when throwing the exception
+ * @param il instruction list of the method
+ * @param mg MethodGen of the method
+ * @param cpg corresponding ConstantPoolGen
+ */
+ private void addNoSuchMethodErrorHandling(InstructionHandle startTry, InstructionHandle endTry,
+ String errorMessage, InstructionList il, MethodGen mg,
+ ConstantPoolGen cpg) {
+ GOTO skipHdlr = null;
+ skipHdlr = new GOTO(null);
+ il.append(skipHdlr);
+ // generated: goto normal exit
+
+ // throw away the expection reference:
+ InstructionHandle hdlr = il.append(new POP());
+
+ il.append(factory.createNew(OTConstants.unsupportedFeature));
+ il.append(new DUP());
+ il.append(new PUSH(cpg, errorMessage));
+ il.append(factory.createInvoke(OTConstants.unsupportedFeature.getClassName(),
+ Constants.CONSTRUCTOR_NAME,
+ Type.VOID,
+ new Type[] { Type.STRING },
+ Constants.INVOKESPECIAL));
+ il.append(new ATHROW());
+
+ InstructionHandle nop = il.append(new NOP());
+ skipHdlr.setTarget(nop);
+ mg.addExceptionHandler(startTry, endTry, hdlr, new ObjectType("java.lang.NoSuchMethodError"));
+ }
+
+ /**
+ * Generate implicit Team activation for each "normal" public method.
+ *
+ * @param cg
+ * class for which methods are to be augmented.
+ * @param cpg
+ * the constant pool of the class 'cg'.
+ */
+ void genImplicitActivation(ClassGen cg, ConstantPoolGen cpg) {
+ Method[] methods = cg.getMethods();
+ for (int i = 0; i < methods.length; i++) {
+ Method m = methods[i];
+ if (candidateForImplicitActivation(m, cg, cpg)) {
+ if(logging) printLogMessage("Adding implicit activation to " + m.getName());
+ cg.replaceMethod(m, genImplicitActivation(m, cg.getClassName(), cpg, false));
+ }
+ }
+ }
+
+ /**
+ * Scans the team attribute StaticReplaceBinding and generates an array of base call surrogates
+ *
+ * @param class_name
+ * @param cpg
+ * @param cg
+ * @return
+ */
+ private Method [] generateStaticBaseCallSurrogates(String class_name, ConstantPoolGen cpg, ClassGen cg){
+
+ Set<String> roleMethodKeys = new HashSet<String>();
+
+ //------------------------------------------------------------------------------------------
+ // scan static replace bindings attributes
+ //------------------------------------------------------------------------------------------
+ Attribute [] attributes = cg.getAttributes();
+ for(int k=0; k<attributes.length; k++){
+
+ Unknown attr = isOTAttribute(attributes[k]);
+ if(attr == null) continue;
+
+ if(attr.getName().equals("StaticReplaceBindings")) {
+
+ byte[] indizes = attr.getBytes();
+ int count = combineTwoBytes(indizes, 0);
+ int numberOfEntries=0;
+ String [] names;
+ numberOfEntries = 5;
+ int i = 2;
+
+ for (int n=0; n<count;n++) {
+ names = new String[numberOfEntries];
+ i = scanStrings(names, indizes, i, cpg);
+ int index = 0;
+ String role_name = names[index++];
+ String role_method_name = names[index++];
+ String role_method_signature = names[index++];
+ String lift_method_name = names[index++];
+ String lift_method_signature = names[index++];
+
+ String roleMethodKey = genRoleMethodKey(class_name, role_name, role_method_name, role_method_signature, lift_method_name, lift_method_signature);
+ roleMethodKeys.add(roleMethodKey);
+
+ int base_len = combineTwoBytes(indizes, i);
+ BaseMethodInfo baseMethod;
+ i += 2;
+ names = new String[3];
+ for (int n_base = 0; n_base < base_len; n_base++) {
+ int [] positions = null;
+
+ i = scanStrings(names, indizes, i, cpg);
+
+ int flags = indizes[i++];
+ boolean baseIsCallin = (flags & 1) != 0;
+ boolean baseIsRoleMethod = (flags & 2) != 0;
+ boolean baseIsStatic = (flags & 4) != 0;
+ //parameter positions scanning
+ int pos_len = combineTwoBytes(indizes, i);
+ i+=2;
+
+ if(pos_len > 0) {
+ positions = new int[pos_len];
+ }
+
+ for(int pos = 0; pos < pos_len; pos++){
+ positions[pos] = combineTwoBytes(indizes,i);
+ i += 2;
+ }
+ int translationFlags = (combineTwoBytes(indizes, i)<<16) + combineTwoBytes(indizes, i+2);
+ i+=4;
+ baseMethod = new BaseMethodInfo(names[0], names[1], names[2],
+ baseIsCallin, baseIsRoleMethod, baseIsStatic,
+ positions, translationFlags);
+
+ CallinBindingManager.assignBaseCallTag(names[0],names[1],names[2]);
+ CallinBindingManager.addStaticReplaceBindingForRoleMethod(roleMethodKey, baseMethod);
+ }
+ }
+ break;
+ }
+ }
+
+ //------------------------------------------------------------------------------------------
+ // generate base call surrogates
+ //------------------------------------------------------------------------------------------
+ Iterator<String> roleMethodIter = roleMethodKeys.iterator();
+ int count = roleMethodKeys.size();
+ Method [] generatedSurrogates = new Method[count];
+
+ int j = 0;
+
+ while(roleMethodIter.hasNext()) {
+ String roleMethodKey = roleMethodIter.next();
+ LinkedList<BaseMethodInfo> baseMethods = CallinBindingManager.getStaticReplaceBindingsForRoleMethod(roleMethodKey);
+
+ //split the key into team class name, role class name, role method name and role method signature
+ int firstPointIndex = roleMethodKey.indexOf(STATIC_REPLACE_BINDING_SEPARATOR);
+ int secondPointIndex = roleMethodKey.indexOf(STATIC_REPLACE_BINDING_SEPARATOR, firstPointIndex+1);
+ int thirdPointIndex = roleMethodKey.indexOf(STATIC_REPLACE_BINDING_SEPARATOR, secondPointIndex+1);
+ int fourthPointIndex = roleMethodKey.indexOf(STATIC_REPLACE_BINDING_SEPARATOR, thirdPointIndex+1);
+ int fifthPointIndex = roleMethodKey.indexOf(STATIC_REPLACE_BINDING_SEPARATOR, fourthPointIndex+1);
+
+ String role_name = roleMethodKey.substring(firstPointIndex+2, secondPointIndex);
+ String role_method_name = roleMethodKey.substring(secondPointIndex+2, thirdPointIndex);
+ String role_method_signature = roleMethodKey.substring(thirdPointIndex+2, fourthPointIndex);
+ String lift_method_name = null;
+ String lift_method_signature = null;
+ // SH: without this check we get
+ // StringIndexOutOfBoundsException: String index out of range: -1
+ // I hope this patch is correct..
+ if ( fourthPointIndex + 2 <= fifthPointIndex
+ && fifthPointIndex + 2 < roleMethodKey.length())
+ {
+ lift_method_name = roleMethodKey.substring(fourthPointIndex+2, fifthPointIndex);
+ lift_method_signature = roleMethodKey.substring(fifthPointIndex+2, roleMethodKey.length());
+ }
+
+ generatedSurrogates[j] = genBaseCallSurrogate(cg, role_name, role_method_name,
+ role_method_signature,
+ lift_method_name, lift_method_signature, baseMethods);
+ j++;
+ }
+
+ return generatedSurrogates;
+ }
+
+ /**
+ * Generates a base call surrogate for a given static role method
+ * @param cg
+ * @param role_name
+ * @param role_method_name
+ * @param role_method_signature
+ * @param lift_method_name
+ * @param lift_method_signature
+ * @param base_methods
+ * @return
+ */
+ private Method genBaseCallSurrogate(ClassGen cg,
+ String role_name,
+ String role_method_name,
+ String role_method_signature,
+ String lift_method_name,
+ String lift_method_signature,
+ LinkedList<BaseMethodInfo> base_methods)
+ {
+ ConstantPoolGen cpg = cg.getConstantPool();
+ String class_name = cg.getClassName();
+
+ if (base_methods.isEmpty()) {
+ return null;
+ }
+ Type[] enhancedArgumentTypes = enhanceArgumentTypes(Type.getArgumentTypes(role_method_signature));
+ Type enhancedReturnType = generalizeReturnType(Type.getReturnType(role_method_signature));
+ String[] enhancedArgumentNames = null;
+ InstructionList il = new InstructionList();
+ int accessFlags = Constants.ACC_PROTECTED;
+
+ MethodGen baseCallSurrogate = new MethodGen(accessFlags,
+ enhancedReturnType,
+ enhancedArgumentTypes,
+ enhancedArgumentNames,
+ getBaseCallSurrogateName(role_name, role_method_name),
+ class_name,
+ il, cpg);
+
+
+ LocalVariableGen otResult = null;
+
+ /*
+ int slot = enhancedArgumentTypes.length+1;
+ otResult = baseCallSurrogate.addLocalVariable("_OT$result",
+ enhancedReturnType,
+ slot, null, null);
+ */
+ otResult = baseCallSurrogate.addLocalVariable("_OT$result",
+ enhancedReturnType, null, null);
+
+ il.insert(InstructionFactory.createStore(enhancedReturnType,
+ otResult.getIndex()));
+ il.insert(new ACONST_NULL());
+ il.setPositions(); // about to retrieve instruction handles.
+
+ if(logging) printLogMessage("base-call switch has to be inserted!");
+ InstructionList loading = new InstructionList();
+ loading.append(InstructionFactory.createThis());
+ int index = 1;
+ for (int i = 0; i < enhancedArgumentTypes.length; i++) {
+ loading.append(InstructionFactory.createLoad(enhancedArgumentTypes[i],index));
+ index += enhancedArgumentTypes[i].getSize();
+ }
+
+ Type[] argumentTypes = Type.getArgumentTypes(role_method_signature);
+ Type returnType = Type.getReturnType(role_method_signature);
+
+ if (debugging) {
+ baseCallSurrogate.addLineNumber(il.getStart(), STEP_OVER_LINENUMBER);
+ }
+
+ il.append(genBaseCallSwitch(cpg, base_methods, baseCallSurrogate,
+ argumentTypes,
+ returnType,
+ lift_method_name,
+ lift_method_signature,
+ otResult, loading, cg.getClassName()));
+
+ il.append(InstructionFactory.createLoad(enhancedReturnType, otResult.getIndex()));
+ il.append(InstructionFactory.createReturn(enhancedReturnType));
+
+ il.setPositions();
+ baseCallSurrogate.removeNOPs();
+ baseCallSurrogate.setMaxStack();
+ baseCallSurrogate.setMaxLocals();
+ return baseCallSurrogate.getMethod();
+ }
+
+ private static String getBaseCallSurrogateName(String class_name, String method_name){
+ // base call surrogate for static callin methods:
+ // name contains role class name and role method name,
+ // because its generated into the team.
+ return OT_PREFIX + class_name + "$" + method_name + "$base";
+ }
+
+ /**
+ * Generate a dispatching switch statement which calls the proper base method.
+ * @param cpg
+ * @param base_methods list of BaseMethodInfo that applies to this callin method
+ * @param enhancedMethod the enhanced callin method
+ * @param argumentTypes arg types of the callin method
+ * @param returnType the return type of the original callin method
+ * @param liftMethodSignature
+ * @param otResult the local variable storing the base call result
+ * @param loading an instruction list holding the original instructions for
+ * loading parameters
+ * @param teamName
+ * @param lift_method_name
+ * @return InstructionList the complete replacement implementing the base call.
+ */
+ InstructionList genBaseCallSwitch (ConstantPoolGen cpg,
+ LinkedList<BaseMethodInfo> base_methods, MethodGen enhancedMethod,
+ Type[] argumentTypes,
+ Type returnType, String liftMethodName, String liftMethodSignature,
+ LocalVariableGen otResult, InstructionList loading, String teamName)
+ {
+
+ short invocationKind = Constants.INVOKESTATIC;
+
+ String className = enhancedMethod.getClassName();
+ Type enhancedMethodReturnType = enhancedMethod.getReturnType();
+ boolean callinHasReturnValue = returnType != Type.VOID;
+
+ InstructionList il = new InstructionList();
+
+ // Setup a variable which holds the result of this base call.
+ // This variabel is local to this segment of code and used only
+ // to transport this result out off the switch statement.
+ int localResult = -1;
+ LocalVariableGen lg = null;
+ if (callinHasReturnValue) {
+ lg = enhancedMethod.addLocalVariable("_OT$tmpResult", returnType,
+ null, null);
+ localResult = lg.getIndex();
+ il.append(InstructionFactory.createNull (returnType));
+ il.append(InstructionFactory.createStore(returnType, localResult));
+ }
+
+ // ---- Prepare the switch: ----
+ InstructionHandle switchStart = il.append
+ (InstructionFactory.createLoad(Type.INT, BASE_METH_ARG));
+ // generated: _OT$baseMethTag
+
+ //base_methods may contain duplicates!
+ //baseMethodTags is used to determine the number of cases without duplicates
+ HashSet<Integer> baseMethodTags = new HashSet<Integer>();
+ Iterator<BaseMethodInfo> iter = base_methods.iterator();
+ while(iter.hasNext()) {
+ BaseMethodInfo baseMethod = iter.next();
+ //baseMethodTags.add(CallinBindingManager.getBaseCallTag( baseMethod.getBaseClassName(),
+ // baseMethod.getBaseMethodName(),
+ // baseMethod.getBaseMethodSignature()));
+ int baseMethodTag = CallinBindingManager.getBaseCallTag(baseMethod.getBaseClassName(),
+ baseMethod.getBaseMethodName(),
+ baseMethod.getBaseMethodSignature());
+ baseMethodTags.add(Integer.valueOf(baseMethodTag));
+ }
+
+ // one break for each case clause
+ int numberOfCases = baseMethodTags.size();
+
+ GOTO[] breaks = new GOTO[numberOfCases];
+ for (int i=0; i<numberOfCases; i++)
+ breaks[i] = new GOTO(null);
+
+ int[] matches = new int[numberOfCases];
+ InstructionHandle[] targets = new InstructionHandle[numberOfCases];
+ int caseCounter = 0;
+
+ //now baseMethodTags is used to store the handled tags
+ baseMethodTags.clear();
+
+ //JU:
+ Type[] enhancedMethodArguments = enhancedMethod.getArgumentTypes();
+ Type[] enhancedArgumentsForBaseCall = new Type[enhancedMethodArguments.length - 1];
+ System.arraycopy(enhancedMethodArguments, 0,
+ enhancedArgumentsForBaseCall, 0,
+ enhancedArgumentsForBaseCall.length);
+
+ Iterator<BaseMethodInfo> it = base_methods.iterator();
+ while (it.hasNext()) {
+
+ BaseMethodInfo baseMethod = it.next();
+ String baseClassName = baseMethod.getBaseClassName();
+ String baseMethodName = baseMethod.getBaseMethodName();
+ String baseMethodSignature = baseMethod.getBaseMethodSignature();
+ int base_method_tag = CallinBindingManager.getBaseCallTag(baseClassName, baseMethodName, baseMethodSignature);
+
+ //if the current baseMethod is a dulpicate:
+ // workaround for jdk 1.4:
+ Integer bmt = Integer.valueOf(base_method_tag);
+ //if(baseMethodTags.contains(base_method_tag)){
+ if (baseMethodTags.contains(bmt)) {
+ continue;
+ }
+
+ //baseMethodTags.add(base_method_tag);
+ baseMethodTags.add(bmt);
+
+ int [] parameterPositions = baseMethod.getParameterPositions();
+ int len = Type.getArgumentTypes(baseMethodSignature).length;
+
+ // if the base method is a callin method as well, further enhance the signature:
+ if (baseMethod.isCallin)
+ len += EXTRA_ARGS;
+
+
+ matches[caseCounter] = CallinBindingManager.getBaseCallTag(baseClassName, baseMethodName, baseMethodSignature);
+ InstructionHandle nextBranch = il.append(new NOP());
+
+ Type[] baseMethodArgumentTypes = Type.getArgumentTypes(baseMethodSignature);
+ Type baseMethodReturnType = Type.getReturnType (baseMethodSignature);
+ String baseChainMethodName = genChainMethName(baseMethodName);
+ Type baseChainReturnType = object; // ALWAYS
+ Type[] enhancedBaseArgumentTypes = enhanceArgumentTypes(baseMethodArgumentTypes);
+
+ boolean resultLiftingNecessary = false;
+
+ // TODO (SH): if both types are ObjectType we should probably use subclassOf() ??
+ // (don't lift if simple polymorphism suffices!)
+ //TODO: if the base method return type is a subtype of the role method return type no lifting has to take place!! is this allowed??
+ //if (!returnTypeCompatible(baseMethodReturnType, returnType) && callinHasReturnValue)
+ if (/*!baseMethodReturnType.equals(object) &&*/
+ !baseMethodReturnType.equals(returnType)
+ && !(baseMethodReturnType instanceof BasicType) // requires boxing not lifting
+ && !(returnType instanceof BasicType) // requires unboxing not lifting
+ && callinHasReturnValue)
+ {
+ resultLiftingNecessary = true;
+ }
+
+ // --- load arguments of the new method: ---
+ // (letters refer to document parameter-passing.odg)
+
+ // (u) generate extra arguments (indices are equal at role and base):
+ for (int idx = 0; idx < EXTRA_ARGS; idx++)
+ il.append(InstructionFactory.createLoad(enhancedMethodArguments[idx],
+ idx+1)); // first arg is "this" (enclosing team)
+
+ // (v)(w)(x) split loading sequence and transfer source-level arguments
+ // (includes reverse-application of parameter mappings):
+ InstructionHandle baseCallLine = il.append(translateLoads(splitLoading(cpg,
+ loading.copy(),
+ argumentTypes),
+ enhancedMethodArguments,
+ enhancedBaseArgumentTypes,
+ parameterPositions,
+ teamName,
+ null,
+ baseMethod,
+ EXTRA_ARGS/*start*/,
+ cpg));
+ // --- done loading ---
+
+ // invoke the chaining method of the base class (base-call!):
+ il.append(factory.createInvoke(baseClassName,
+ baseChainMethodName,
+ baseChainReturnType,
+ enhancedBaseArgumentTypes,
+ invocationKind));
+
+ // FIXME(SH): if this assert holds, remove computing of resultLiftingNecessary above.
+ assert resultLiftingNecessary == ((baseMethod.translationFlags & 1) != 0);
+
+ if (resultLiftingNecessary) { // call the lift-method:
+ Type[] liftMethodArgs = Type.getArgumentTypes(liftMethodSignature);
+ Type liftMethodReturnType = Type.getReturnType(liftMethodSignature);
+
+ // cast result of base call:
+ il.append(factory.createCast(baseChainReturnType, baseMethodReturnType));
+
+ // load the team instance at which to call the lift method:
+ il.append(InstructionFactory.createThis());
+ il.append(factory.createCast(object, new ObjectType(teamName)));
+
+ // put them in correct order:
+ il.append(new SWAP()); // -> .., this$0, (BaseType)result
+
+ il.append(factory.createInvoke(teamName,
+ liftMethodName,
+ liftMethodReturnType,
+ liftMethodArgs,
+ Constants.INVOKEVIRTUAL));
+ }
+
+ // adjust the return value to the type expected by the WRAPPER:
+ il.append(new DUP()); // keep for adjustment below
+ if (!resultLiftingNecessary)
+ adjustValue(il, null, baseChainReturnType, enhancedMethodReturnType);
+ il.append(InstructionFactory.createStore(enhancedMethodReturnType,
+ otResult.getIndex())); // store "globally"
+ // this store is needed to tunnel unused results through the callin.
+
+ InstructionHandle afterBaseCallLine = il.append(new NOP());
+
+ // adjust the return value to the type expected by the ORIGINAL CALLIN:
+ adjustValue(il, null, baseChainReturnType, returnType);
+ if (callinHasReturnValue) {
+ il.append(InstructionFactory.createStore(returnType, localResult)); // store "locally"
+ }
+ // this store is useful for callins which make use of the result.
+
+ targets[caseCounter] = nextBranch;
+ il.append(breaks[caseCounter]);
+ // generated: break;
+
+ caseCounter++;
+
+ if (debugging) {
+ enhancedMethod.addLineNumber(baseCallLine, STEP_INTO_LINENUMBER);
+ enhancedMethod.addLineNumber(afterBaseCallLine, STEP_OVER_LINENUMBER);
+ }
+ }
+
+ //JU: added the follwing part (begin) -----------------------------------------------------
+ InstructionHandle defaultBranch = il.append(new NOP());
+
+ if (logging)
+ printLogMessage("Exeption has to be thrown! Base-Call is impossible.");
+
+ il.append(factory.createNew(OTConstants.unsupportedFeature));
+ il.append(new DUP());
+ // ## FIXME: fix otld$
+ il.append(new PUSH(cpg, "Binding-Error: base-call from " + className + "." + enhancedMethod.getName()
+ + "impossible! This problem is documented in OTLD $XY."));
+ il.append(factory.createInvoke(OTConstants.unsupportedFeature.getClassName(),
+ Constants.CONSTRUCTOR_NAME,
+ Type.VOID,
+ new Type[] { Type.STRING },
+ Constants.INVOKESPECIAL));
+ il.append(new ATHROW());
+ //JU: (end) --------------------------------------------------------------------------------
+
+ InstructionHandle afterSwitch = il.append(new NOP()); // all breaks point here.
+
+ il.append(switchStart, createLookupSwitch(matches, targets, breaks,
+ defaultBranch, afterSwitch));
+
+ // retrieve locally stored result:
+ if (callinHasReturnValue) {
+ il.append(InstructionFactory.createLoad(returnType, localResult));
+ lg.setStart(il.getStart()); // restrict local variable to this segment.
+ lg.setEnd(il.getEnd());
+ }
+ return il;
+ }
+
+ /**
+ * Generates a key for the given role method parameters
+ *
+ * @param teamClassName
+ * @param roleClassName
+ * @param roleMethodName
+ * @param roleMethodSignature
+ * @param liftMethodSignature
+ * @return
+ */
+ private static String genRoleMethodKey(String teamClassName,
+ String roleClassName, String roleMethodName,
+ String roleMethodSignature, String liftMethodName,
+ String liftMethodSignature)
+ {
+ StringBuilder roleMethodKey = new StringBuilder(64);
+ roleMethodKey.append(teamClassName);
+ roleMethodKey.append(STATIC_REPLACE_BINDING_SEPARATOR);
+ roleMethodKey.append(roleClassName);
+ roleMethodKey.append(STATIC_REPLACE_BINDING_SEPARATOR);
+ roleMethodKey.append(roleMethodName);
+ roleMethodKey.append(STATIC_REPLACE_BINDING_SEPARATOR);
+ roleMethodKey.append(roleMethodSignature);
+ roleMethodKey.append(STATIC_REPLACE_BINDING_SEPARATOR);
+ roleMethodKey.append(liftMethodName);
+ roleMethodKey.append(STATIC_REPLACE_BINDING_SEPARATOR);
+ roleMethodKey.append(liftMethodSignature);
+ return roleMethodKey.toString();
+ }
+
+ /**
+ * Read the InheritedRoles attribute and return the list of inherited roles.
+ * @param cg The ClassGen of the inspected class.
+ * @param cpg The constant pool of the instpected class.
+ * @return A list of inherited role names.
+ */
+ private List<String> getInheritedRoleNames(ClassGen cg, ConstantPoolGen cpg) {
+ Attribute[] attributes = cg.getAttributes();
+ LinkedList<String> inheritedRoleNames = new LinkedList<String>();
+ for (int i = 0; i < attributes.length; i++) {
+ Attribute actAttr = attributes[i];
+ if (actAttr instanceof Unknown) {
+ Unknown attr = (Unknown)actAttr;
+ byte[] indizes = attr.getBytes();
+ int count = combineTwoBytes(indizes, 0);
+ if (attr.getName().equals("InheritedRoles")) {
+ int j = 2;
+ while (j<=2*count) {
+ String[] names = new String[1];
+ j = scanStrings(names, indizes, j, cpg);
+ String inherited_role = names[0];
+ inheritedRoleNames.add(inherited_role);
+ }
+ }
+ }
+ }
+ return inheritedRoleNames;
+ }
+}
diff --git a/othersrc/OTRE/src/org/eclipse/objectteams/otre/ThreadActivation.java b/othersrc/OTRE/src/org/eclipse/objectteams/otre/ThreadActivation.java
new file mode 100644
index 0000000..7ac2e1e
--- /dev/null
+++ b/othersrc/OTRE/src/org/eclipse/objectteams/otre/ThreadActivation.java
@@ -0,0 +1,190 @@
+/**********************************************************************
+ * 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: ThreadActivation.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 java.util.HashSet;
+
+import de.fub.bytecode.classfile.*;
+import de.fub.bytecode.generic.*;
+import de.fub.bytecode.*;
+
+
+/**
+ * This transformer inserts a notification call to the TeamThreadManager at the
+ * beginning of every run()-Method in Subtypes of java.lang.Thread or java.lang.Runnable.
+ * Thre TeamThreadManager then ensures the thread activation of the current thread
+ * for every global active team instance.
+ *
+ * @author Christine Hundt
+ * @author Stephan Herrmann
+ */
+public class ThreadActivation
+{
+ // name of a generated field that stores the thread which created a given runnable:
+ private static final String CREATION_THREAD = "_OT$creationThread";
+ HashSet<String> transformableClasses = new HashSet<String>();
+
+ private boolean shouldTransform(ClassGen cg) {
+ Method runMethode = cg.containsMethod("run", "()V");
+ if (runMethode == null || runMethode.isAbstract()) {
+ // this class contains no concrete run() method
+ return false;
+ }
+ String class_name = cg.getClassName();
+ // check if this class is a subtype of Thread or Runnable:
+ try {
+ return Repository.implementationOf(class_name, "java.lang.Runnable") || Repository.instanceOf(class_name, "java.lang.Thread");
+ } catch (NullPointerException npe) {
+ if (ObjectTeamsTransformation.WORKAROUND_REPOSITORY) {
+ return false;
+ }
+ else
+ throw npe; // rethrow
+ }
+ }
+ public void doTransformInterface(ClassEnhancer enhancer, ClassGen cg) {
+ if (!shouldTransform(cg))
+ return;
+
+ // if class is already transformed by this transformer
+ if (this.transformableClasses.contains(cg.getClassName()))
+ return;
+
+ this.transformableClasses.add(cg.getClassName());
+ FieldGen field = new FieldGen(Constants.ACC_PRIVATE, OTConstants.threadType, CREATION_THREAD, cg.getConstantPool());
+ enhancer.addField(field.getField(), cg);
+ }
+ /**
+ *
+ */
+ public void doTransformCode(ClassGen cg) {
+ if (!this.transformableClasses.contains(cg.getClassName()))
+ return;
+
+ this.transformableClasses.remove(cg.getClassName());
+
+ InstructionFactory factory = new InstructionFactory(cg);
+
+ for (Method method : cg.getMethods()) {
+ MethodGen mg = isRootCtor(method, cg);
+ if (mg != null)
+ enhanceConstructor(cg, factory, method, mg);
+ }
+
+ enhanceRunMethod(cg, factory);
+ }
+ private void enhanceRunMethod(ClassGen cg, InstructionFactory factory) {
+ String class_name = cg.getClassName();
+ ConstantPoolGen cpg = cg.getConstantPool();
+
+ Method runMethode = cg.containsMethod("run", "()V"); // existence checked in transformInterface
+
+ MethodGen mg = new MethodGen(runMethode, class_name, cpg);
+ InstructionList il = mg.getInstructionList();
+ InstructionHandle try_start = il.getStart();
+
+ /** *** Insert a call to TeamThreadManager.newThreadStarted() at the beginning of the run() method: ****** */
+ InstructionList threadActivation = new InstructionList();
+ threadActivation.append(new ICONST(0)); // isMain = false
+ threadActivation.append(InstructionConstants.ALOAD_0); // parent=this._OT$creationThread;
+ threadActivation.append(factory.createFieldAccess(class_name, CREATION_THREAD, OTConstants.threadType, Constants.GETFIELD));
+ threadActivation.append(factory.createInvoke("org.objectteams.TeamThreadManager",
+ "newThreadStarted",
+ Type.BOOLEAN,
+ new Type[]{Type.BOOLEAN, OTConstants.threadType},
+ Constants.INVOKESTATIC));
+ LocalVariableGen flag = mg.addLocalVariable("_OT$isThreadStart", Type.BOOLEAN, il.getStart(), il.getEnd());
+ threadActivation.append(new ISTORE(flag.getIndex()));
+ il.insert(threadActivation);
+
+ /** *** Insert a call to TeamThreadManager.threadEnded() before every return of the run() method: ******** */
+ InstructionList threadDeactivation = new InstructionList();
+ threadDeactivation.append(new ILOAD(flag.getIndex()));
+ BranchInstruction ifIsThreadStarted = new IFEQ(null);
+ threadDeactivation.append(ifIsThreadStarted);
+ threadDeactivation.append(factory.createInvoke("org.objectteams.TeamThreadManager",
+ "threadEnded",
+ Type.VOID,
+ Type.NO_ARGS,
+ Constants.INVOKESTATIC));
+ ifIsThreadStarted.setTarget(threadDeactivation.append(new NOP()));
+
+ FindPattern findPattern = new FindPattern(il);
+ String pat = "`ReturnInstruction'";
+ InstructionHandle ih = findPattern.search(pat);
+ while (ih != null) {
+ // insert deactivate-call before return instruction in ih:
+ InstructionList deactivationCopy = threadDeactivation.copy();
+ InstructionHandle inserted = il.insert(ih, deactivationCopy); // instruction lists can not be reused
+ il.redirectBranches(ih, inserted);// SH: retarget all jumps that targeted at the return instruction
+ if (ih.getNext() == null)
+ break; // end of instruction list reached
+ ih = findPattern.search(pat, ih.getNext());
+ }
+
+ /** **** Add an exception handler which calls TeamThreadManager.threadEnded() *****
+ * ***** before throwing the exception (finaly-simulation): */
+ ObjectType throwable = new ObjectType("java.lang.Throwable");
+ LocalVariableGen exception = mg.addLocalVariable(
+ "_OT$thrown_exception", throwable, null, null);
+ InstructionHandle try_end = il.getEnd();
+ InstructionList deactivation_ex = threadDeactivation.copy();
+ deactivation_ex.insert(InstructionFactory.createStore(throwable, exception.getIndex()));
+ deactivation_ex.append(InstructionFactory.createLoad(throwable, exception.getIndex()));
+ deactivation_ex.append(new ATHROW());
+ InstructionHandle deactivation_handler = il.append(il.getEnd(), deactivation_ex);
+ mg.addExceptionHandler(try_start, try_end, deactivation_handler, throwable);
+ /** ******************************************************************** */
+
+ mg.setMaxStack();
+ mg.setMaxLocals();
+ Method generatedMethod = mg.getMethod();
+ cg.replaceMethod(runMethode, generatedMethod);
+ threadActivation.dispose();
+ il.dispose();
+ }
+ // is method a constructor that does not invoke another this()-ctor?
+ private MethodGen isRootCtor(Method method, ClassGen cg) {
+ if (!method.getName().equals("<init>"))
+ return null;
+ String className = cg.getClassName();
+ ConstantPoolGen cpg = cg.getConstantPool();
+ MethodGen mg = new MethodGen(method, className, cpg);
+ InstructionList il = mg.getInstructionList();
+ InstructionHandle ih = il.getStart();
+ while (ih != null && ih.getInstruction().getOpcode() != Constants.INVOKESPECIAL) {
+ ih = ih.getNext();
+ }
+ if (ih == null)
+ return null;
+ if (((InvokeInstruction)ih.getInstruction()).getClassName(cpg).equals(className))
+ return null; // this-call
+ return mg;
+ }
+ // add statements to store the thread that created this runnable
+ private void enhanceConstructor(ClassGen cg, InstructionFactory factory, Method initMethod, MethodGen mg) {
+ String class_name = cg.getClassName();
+ InstructionList il = mg.getInstructionList();
+ il.insert(il.getEnd(), InstructionConstants.ALOAD_0);
+ il.insert(il.getEnd(), factory.createInvoke("java.lang.Thread", "currentThread", OTConstants.threadType, new Type[0], Constants.INVOKESTATIC));
+ il.insert(il.getEnd(), factory.createFieldAccess(class_name, CREATION_THREAD, OTConstants.threadType, Constants.PUTFIELD));
+ mg.setMaxStack();
+ mg.setMaxLocals();
+ cg.replaceMethod(initMethod, mg.getMethod());
+ il.dispose();
+ }
+}
diff --git a/othersrc/OTRE/src/org/eclipse/objectteams/otre/jplis/JPLISEnhancer.java b/othersrc/OTRE/src/org/eclipse/objectteams/otre/jplis/JPLISEnhancer.java
new file mode 100644
index 0000000..e390663
--- /dev/null
+++ b/othersrc/OTRE/src/org/eclipse/objectteams/otre/jplis/JPLISEnhancer.java
@@ -0,0 +1,143 @@
+/**********************************************************************
+ * This file is part of the "Object Teams Runtime Environment"
+ *
+ * Copyright 2005-2008 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: JPLISEnhancer.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.jplis;
+
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.eclipse.objectteams.otre.ClassEnhancer;
+import org.eclipse.objectteams.otre.OTREInternalError;
+import org.eclipse.objectteams.otre.ObjectTeamsTransformation;
+
+import de.fub.bytecode.Constants;
+import de.fub.bytecode.classfile.ClassParser;
+import de.fub.bytecode.classfile.Field;
+import de.fub.bytecode.classfile.Method;
+import de.fub.bytecode.classfile.Utility;
+import de.fub.bytecode.generic.ClassGen;
+import de.fub.bytecode.generic.ConstantPoolGen;
+import de.fub.bytecode.generic.MethodGen;
+
+
+/**
+* This class implements the ClassEnhancer interface with the JPLIS (Java5) specific behavior.
+*
+* @author Christine Hundt
+* @author Juergen Widiker
+* @author Stephan Herrmann
+*/
+
+public class JPLISEnhancer implements ClassEnhancer {
+
+ private ClassLoader loader;
+
+ public JPLISEnhancer(ClassGen cg, ClassLoader loader) {
+ this.loader = loader;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.objectteams.otre.ClassEnhancer#addImplements(java.lang.String, de.fub.bytecode.generic.ClassGen)
+ */
+ public void addImplements(String interfaceName, ClassGen cg) {
+ cg.addInterface(interfaceName);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.objectteams.otre.common.ClassEnhancer#addMethod(de.fub.bytecode.classfile.Method, de.fub.bytecode.generic.ClassGen)
+ */
+ public void addMethod(Method m, ClassGen cg) {
+ if (cg.containsMethod(m.getName(), m.getSignature()) != null)
+ new OTREInternalError("Warning: repetive adding of method "
+ + m.getName() + m.getSignature()
+ + " to class " + cg.getClassName())
+ .printStackTrace();
+ cg.addMethod(m);
+ }
+
+ public void addOrReplaceMethod(Method method, ClassGen cg) {
+ Method existingMethod = cg.containsMethod(method.getName(), method.getSignature());
+ if (existingMethod == null)
+ addMethod(method, cg);
+ else
+ cg.replaceMethod(existingMethod, method);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.objectteams.otre.common.ClassEnhancer#addField(de.fub.bytecode.classfile.Field, de.fub.bytecode.generic.ClassGen)
+ */
+ public void addField(Field f, ClassGen cg) {
+ if (cg.containsField(f.getName()) != null)
+ new OTREInternalError("Warning: repetitive adding of field "
+ + f.getName() + f.getSignature()
+ + " to class " + cg.getClassName())
+ .printStackTrace();
+ cg.addField(f);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.objectteams.otre.common.ClassEnhancer#loadClass(java.lang.String)
+ */
+ public void loadClass(String className, ObjectTeamsTransformation client) {
+ // SH: no forced class loading within OT/Equinox
+ if(System.getProperty("ot.equinox") != null)
+ return;
+ try {
+ String binaryName = className.replace('.', '/');
+ InputStream is = loader.getResourceAsStream(binaryName+".class");
+ if (is != null) {
+ ClassGen cg = new ClassGen(new ClassParser(is, className).parse());
+ client.checkReadClassAttributes(this, cg, className, cg.getConstantPool());
+ }
+ } catch (IOException ex) {
+ ex.printStackTrace();
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.objectteams.otre.common.ClassEnhancer#decapsulateMethod(de.fub.bytecode.classfile.Method, java.lang.String, de.fub.bytecode.generic.ConstantPoolGen)
+ */
+ public void decapsulateMethod(Method m, ClassGen cg, String packageName, ConstantPoolGen cpg) {
+ String className = cg.getClassName();
+ int flags = m.getAccessFlags();
+ MethodGen mg = new MethodGen(m, className, cpg);
+
+ if ((flags & Constants.ACC_PUBLIC) == 0) {
+ int newFlags = flags;
+ newFlags &= ~(Constants.ACC_PROTECTED|Constants.ACC_PRIVATE); // clear old visibility
+ newFlags |= Constants.ACC_PUBLIC; // set new visibility
+ mg.setAccessFlags(newFlags);
+ if(System.getProperty("ot.log") != null)
+ ObjectTeamsTransformation.printLogMessage("Adjusting from "
+ + Utility.accessToString(flags)
+ + " to public:\n\t"
+ + className
+ + "." + m);
+ if (!packageName.equals("NO_PACKAGE"))
+ checkSeal(packageName, className);
+ }
+ cg.replaceMethod(m, mg.getMethod());
+ }
+
+ private static void checkSeal(String package_name, String class_name) {
+ Package pckg = Package.getPackage(package_name);
+ if ( (pckg != null) && pckg.isSealed())
+ throw new IllegalAccessError(
+ "OT/J callout binding:\n"
+ +"Trying to break sealed "+pckg);
+ }
+}
diff --git a/othersrc/OTRE/src/org/eclipse/objectteams/otre/jplis/ObjectTeamsTransformer.java b/othersrc/OTRE/src/org/eclipse/objectteams/otre/jplis/ObjectTeamsTransformer.java
new file mode 100644
index 0000000..df7488b
--- /dev/null
+++ b/othersrc/OTRE/src/org/eclipse/objectteams/otre/jplis/ObjectTeamsTransformer.java
@@ -0,0 +1,287 @@
+/**********************************************************************
+ * This file is part of the "Object Teams Runtime Environment"
+ *
+ * Copyright 2005-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: ObjectTeamsTransformer.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.jplis;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.instrument.ClassFileTransformer;
+import java.lang.instrument.IllegalClassFormatException;
+import java.security.ProtectionDomain;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.objectteams.otre.BaseCallRedirection;
+import org.eclipse.objectteams.otre.BaseMethodTransformation;
+import org.eclipse.objectteams.otre.BaseTagInsertion;
+import org.eclipse.objectteams.otre.Decapsulation;
+import org.eclipse.objectteams.otre.LiftingParticipantTransformation;
+import org.eclipse.objectteams.otre.LowerableTransformation;
+import org.eclipse.objectteams.otre.OTConstants;
+import org.eclipse.objectteams.otre.ObjectTeamsTransformation;
+import org.eclipse.objectteams.otre.StaticSliceBaseTransformation;
+import org.eclipse.objectteams.otre.SubBoundBaseMethodRedefinition;
+import org.eclipse.objectteams.otre.TeamInterfaceImplementation;
+import org.eclipse.objectteams.otre.ThreadActivation;
+import org.eclipse.objectteams.otre.util.AttributeReadingGuard;
+import org.eclipse.objectteams.otre.util.CallinBindingManager;
+
+import de.fub.bytecode.Repository;
+import de.fub.bytecode.classfile.ClassParser;
+import de.fub.bytecode.classfile.JavaClass;
+import de.fub.bytecode.generic.ClassGen;
+
+
+/**
+ * Main entry into the OTRE when using JPLIS
+ *
+ * @author Christine Hundt
+ * @author Stephan Herrmann
+ */
+public class ObjectTeamsTransformer implements ClassFileTransformer {
+
+ // force loading all transformer classes to reduce risk of deadlock in class loading.
+ static Class<?>[] transformerClasses = new Class<?>[] {
+ BaseCallRedirection.class,
+ BaseMethodTransformation.class,
+ BaseTagInsertion.class,
+ Decapsulation.class,
+ LiftingParticipantTransformation.class,
+ LowerableTransformation.class,
+ StaticSliceBaseTransformation.class,
+ SubBoundBaseMethodRedefinition.class,
+ TeamInterfaceImplementation.class,
+ ThreadActivation.class
+ };
+
+ /**
+ * One instance of this class is used per class loader to ensure disjoint scopes.
+ */
+ static class StateGroup {
+ ObjectTeamsTransformation.SharedState bcrState = new ObjectTeamsTransformation.SharedState();
+ ObjectTeamsTransformation.SharedState bmtState = new ObjectTeamsTransformation.SharedState();
+ BaseTagInsertion.SharedState btiState = new BaseTagInsertion.SharedState();
+ Decapsulation.SharedState decState = new Decapsulation.SharedState();
+ ObjectTeamsTransformation.SharedState lptState = new ObjectTeamsTransformation.SharedState();
+ ObjectTeamsTransformation.SharedState lowState = new ObjectTeamsTransformation.SharedState();
+ ObjectTeamsTransformation.SharedState ssbtState = new ObjectTeamsTransformation.SharedState();
+ ObjectTeamsTransformation.SharedState sbbmrState = new ObjectTeamsTransformation.SharedState();
+ ObjectTeamsTransformation.SharedState tiiState = new ObjectTeamsTransformation.SharedState();
+ }
+ static Map<ClassLoader, StateGroup> states = new HashMap<ClassLoader, StateGroup>();
+
+ static boolean warmedUp = false;
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.instrument.ClassFileTransformer#transform(java.lang.ClassLoader,
+ * java.lang.String, java.lang.Class, java.security.ProtectionDomain,
+ * byte[])
+ */
+ public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined,
+ ProtectionDomain protectionDomain, byte[] classfileBuffer)
+ throws IllegalClassFormatException
+ {
+ if (warmedUp)
+ return internalTransform(loader, className, classBeingRedefined, protectionDomain, classfileBuffer);
+ synchronized (loader) {
+ try {
+ return internalTransform(loader, className, classBeingRedefined, protectionDomain, classfileBuffer);
+ } finally {
+ warmedUp = true;
+ }
+ }
+ }
+ public byte[] internalTransform(ClassLoader loader, String className, Class<?> classBeingRedefined,
+ ProtectionDomain protectionDomain, byte[] classfileBuffer)
+ throws IllegalClassFormatException
+ {
+ if (className.startsWith("org/objectteams/transformer")
+ || className.startsWith("org/cs3/jmangler")
+ || className.startsWith("de/fub/bytecode"))
+ {
+ // skip OTRE, BCEL and JMangler classes
+ return null;
+ }
+// if (!(className.startsWith("java") || className.startsWith("sun")))
+ // System.err.println("ObjectTeamsTransformer transforming: " + className);
+ if (classBeingRedefined != null) {
+ System.out.println("Redefinition!");
+ return null;
+ }
+
+ // state sharing among transformers:
+ StateGroup states = ObjectTeamsTransformer.states.get(loader);
+ if (states == null)
+ ObjectTeamsTransformer.states.put(loader, states = new StateGroup());
+ //
+ // One fresh instance of each transformer for a given class:
+ //
+ BaseCallRedirection baseCallRedirection
+ = new BaseCallRedirection( loader, states.bcrState);
+ BaseMethodTransformation baseMethodTransformation
+ = new BaseMethodTransformation( loader, states.bmtState);
+ BaseTagInsertion baseTagInsertion
+ = new BaseTagInsertion( states.btiState);
+ Decapsulation decapsulation
+ = new Decapsulation( loader, states.decState);
+ LiftingParticipantTransformation liftingParticipantTransformation
+ = new LiftingParticipantTransformation( loader, states.lptState);
+ LowerableTransformation lowerableTransformation
+ = new LowerableTransformation( loader, states.lowState);
+ StaticSliceBaseTransformation staticSliceBaseTransformation
+ = new StaticSliceBaseTransformation( loader, states.ssbtState);
+ SubBoundBaseMethodRedefinition subBoundBaseMethodRedefinition
+ = new SubBoundBaseMethodRedefinition( loader, states.sbbmrState);
+ TeamInterfaceImplementation teamInterfaceImplementation
+ = new TeamInterfaceImplementation(true, loader, states.tiiState);
+ ThreadActivation threadActivation
+ = new ThreadActivation();
+
+ // tell Repository about the class loader for improved lookupClass()
+ ClassLoader prevLoader= Repository.classLoaders.get();
+ Repository.classLoaders.set(loader);
+
+ InputStream is = new ByteArrayInputStream(classfileBuffer);
+ try {
+ JavaClass java_class = new ClassParser(is, className).parse();
+ //Repository.addClass(java_class);
+ ClassGen cg = new ClassGen(java_class);
+
+ JPLISEnhancer jpe = new JPLISEnhancer(cg, loader);
+
+ Collection<String> adaptedBases; // [OT/Equinox]
+ // [OT/Equinox] remember the first transformation which holds adaptedBases
+ adaptedBases= setFirstTransformation(subBoundBaseMethodRedefinition);
+ // [OT/Equinox] if class has previously been transformed fetch the list of
+ // adapted bases from the CallinBindingManager instead of reading it now.
+ if ( (cg.getAccessFlags() & OTConstants.TEAM) != 0
+ && !AttributeReadingGuard.getInstanceForLoader(loader).iAmTheFirst(cg.getClassName()))
+ {
+ List<String> basesOfTeam = CallinBindingManager.getBasesPerTeam(cg.getClassName());
+ if (basesOfTeam != null)
+ adaptedBases.addAll(basesOfTeam);
+ }
+ subBoundBaseMethodRedefinition.doTransformInterface(jpe, cg);
+ baseCallRedirection.doTransformInterface(jpe, cg);
+ decapsulation.doTransformInterface(jpe, cg);
+ try {
+ baseMethodTransformation.useReflection = (loader == null); // bootstrap classes cannot be called directly
+ baseMethodTransformation.doTransformInterface(jpe, cg);
+ } catch (Throwable t) {
+ System.err.println("Error transforming class: "+cg.getClassName());
+ t.printStackTrace();
+ }
+ baseTagInsertion.doTransformInterface(jpe, cg);
+ lowerableTransformation.doTransformInterface(jpe, cg);
+ staticSliceBaseTransformation.doTransformInterface(jpe, cg);
+ teamInterfaceImplementation.doTransformInterface(jpe, cg);
+
+// subBoundBaseMethodRedefinition.doTransformInterface(jpe, cg);
+// baseCallRedirection.doTransformInterface(jpe, cg);
+// decapsulation.doTransformInterface(jpe, cg);
+// baseMethodTransformation.doTransformInterface(jpe, cg);
+// baseTagInsertion.doTransformInterface(jpe, cg);
+// staticSliceBaseTransformation.doTransformInterface(jpe, cg);
+// teamInterfaceImplementation.doTransformInterface(jpe, cg);
+ threadActivation.doTransformInterface(jpe, cg);
+
+
+// baseCallRedirection.doTransformCode(cg); // empty method
+ baseMethodTransformation.doTransformCode(cg);
+ baseTagInsertion.doTransformCode(cg);
+ liftingParticipantTransformation.doTransformCode(cg);
+ staticSliceBaseTransformation.doTransformCode(cg);
+ teamInterfaceImplementation.doTransformCode(cg);
+ threadActivation.doTransformCode(cg);
+
+ JavaClass new_java_class = cg.getJavaClass();
+ if (dumping) {
+ new_java_class.dump("jplis_dump/" + className + ".class");
+ }
+ return new_java_class.getBytes();
+ } catch (IOException e) {
+ System.err.println("ClassFileTransformer could not parse class file buffer to JavaClass");
+ e.printStackTrace();
+ } finally {
+ // uninstall class loader:
+ Repository.classLoaders.set(prevLoader);
+ }
+ return null;
+ }
+
+ /**
+ * External API (for OT/Equinox):
+ * Destructively fetch the set of adapted base classes
+ * recorded since the last call to this method.
+ *
+ * @return
+ */
+ public Collection<String> fetchAdaptedBases() {
+ if (this.firstTransformation == null)
+ return null;
+ Collection<String>result= this.firstTransformation.fetchAdaptedBases();
+ this.firstTransformation= null;
+ return result;
+ }
+
+ /**
+ * External API (for OT/Equinox):
+ * Read the OT-Attributes of a class without loading the class.
+ * @throws IOException
+ * @throws ClassFormatError
+ */
+ public void readOTAttributes(InputStream file, String fileName, ClassLoader loader)
+ throws ClassFormatError, IOException
+ {
+ ClassParser cp = new ClassParser(file, fileName);
+ ClassGen cg = new ClassGen(cp.parse());
+ JPLISEnhancer jpe = new JPLISEnhancer(cg, /*loader (unused)*/null);
+ ClassLoader prevLoader= Repository.classLoaders.get();
+ Repository.classLoaders.set(loader);
+ try {
+ setFirstTransformation(new ObjectTeamsTransformation(loader, null) {});
+ firstTransformation.checkReadClassAttributes(jpe, cg, cg.getClassName(), cg.getConstantPool());
+ } finally {
+ Repository.classLoaders.set(prevLoader);
+ }
+ }
+
+ // helper structure for above:
+ /* The first transformation performed holds the list of adapted bases. */
+ private ObjectTeamsTransformation firstTransformation;
+
+ /* @return the collection of adapted bases currently in use. */
+ private Collection<String> setFirstTransformation(ObjectTeamsTransformation t) {
+ if (this.firstTransformation != null)
+ t.adaptedBases= this.firstTransformation.adaptedBases; // collect into existing
+ this.firstTransformation= t;
+ return t.adaptedBases;
+ }
+
+ // ------------------------------------------
+ // ---------- Class file dumping: ----------------------
+ // ------------------------------------------
+ /** Initialized from property <tt>ot.dump</tt>. */
+ static boolean dumping = false;
+ static {
+ if(System.getProperty("ot.dump")!=null)
+ dumping = true;
+ }
+}
diff --git a/othersrc/OTRE/src/org/eclipse/objectteams/otre/jplis/otreAgent.java b/othersrc/OTRE/src/org/eclipse/objectteams/otre/jplis/otreAgent.java
new file mode 100644
index 0000000..ee6077f
--- /dev/null
+++ b/othersrc/OTRE/src/org/eclipse/objectteams/otre/jplis/otreAgent.java
@@ -0,0 +1,48 @@
+/**********************************************************************
+ * This file is part of the "Object Teams Runtime Environment"
+ *
+ * Copyright 2005-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: otreAgent.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.jplis;
+
+import java.lang.instrument.Instrumentation;
+
+/**
+*
+* @version $Id: otreAgent.java 23408 2010-02-03 18:07:35Z stephan $
+* @author Christine Hundt
+*/
+public class otreAgent {
+
+ private static Instrumentation instCopy;
+// private static String optionsCopy;
+
+ private static ObjectTeamsTransformer otTransformer;
+
+ public static void premain(String options, Instrumentation inst) {
+ instCopy = inst;
+// optionsCopy = options;
+
+ // add all necessary transformers:
+ otTransformer = new ObjectTeamsTransformer();
+ instCopy.addTransformer(otTransformer);
+
+ /* All future class definitions will be seen by the transformer,
+ except definitions of classes upon which any registered transformer is dependent. */
+ }
+
+ public static Instrumentation getInstrumentation() {
+ return instCopy;
+ }
+}
diff --git a/othersrc/OTRE/src/org/eclipse/objectteams/otre/util/AnnotationHelper.java b/othersrc/OTRE/src/org/eclipse/objectteams/otre/util/AnnotationHelper.java
new file mode 100644
index 0000000..9f01412
--- /dev/null
+++ b/othersrc/OTRE/src/org/eclipse/objectteams/otre/util/AnnotationHelper.java
@@ -0,0 +1,102 @@
+/**********************************************************************
+ * This file is part of the "Object Teams Runtime Environment"
+ *
+ * Copyright 2009 Stephan Herrmann
+ *
+ * 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$
+ *
+ * Please visit http://www.objectteams.org for updates and contact.
+ *
+ * Contributors:
+ * Stephan Herrmann - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.objectteams.otre.util;
+
+import org.eclipse.objectteams.otre.ObjectTeamsTransformation;
+import org.objectteams.ImplicitTeamActivation;
+
+import de.fub.bytecode.classfile.Attribute;
+import de.fub.bytecode.classfile.Unknown;
+import de.fub.bytecode.generic.ConstantPoolGen;
+
+/**
+ * Helper class for parsing / skipping runtime visible annotations.
+ *
+ * @author stephan
+ * @since 1.4.0
+ */
+public class AnnotationHelper {
+
+ /**
+ * Does any of the given attributes contain an {@link ImplicitTeamActivation} annotation?
+ * @param attrs attributes to inspect
+ * @param cpg constant pool for string lookup
+ * @return true if an {@link ImplicitTeamActivation} annotation was found.
+ */
+ public static boolean containsImplicitActivationAttribute(Attribute[] attrs, ConstantPoolGen cpg) {
+ if (attrs != null) {
+ for (Attribute attr : attrs) {
+ if (attr instanceof Unknown && ((Unknown)attr).getName().equals("RuntimeVisibleAnnotations")) {
+ Unknown unknown = (Unknown) attr;
+ byte[] bytes = unknown.getBytes();
+ int len = ObjectTeamsTransformation.combineTwoBytes(bytes, 0);
+ int i = 2;
+ String[] names = new String[1];
+ for (int n=0; n<len; n++) {
+ i = ObjectTeamsTransformation.scanStrings(names, bytes, i, cpg);
+ if ("Lorg/objectteams/ImplicitTeamActivation;".equals(names[0]))
+ return true;
+ i = skipNameValuePairs(bytes, i, names[0], cpg);
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ private static int skipNameValuePairs(byte[] bytes, int i, String typeName, ConstantPoolGen cpg) {
+ int numPairs = ObjectTeamsTransformation.combineTwoBytes(bytes, i);
+ i+=2;
+ for (int p=0; p<numPairs; p++)
+ i = skipElementValue(bytes, i+2 /*skip name*/, typeName, cpg);
+ return i;
+ }
+
+ private static int skipElementValue(byte[] bytes, int i, String typeName, ConstantPoolGen cpg) {
+ short tag = bytes[i++];
+ switch (tag) {
+ case 'B': // byte
+ case 'C': // char
+ case 'D': // double
+ case 'F': // float
+ case 'I': // int
+ case 'J': // long
+ case 'S': // short
+ case 'Z': // boolean
+ case 's': // String
+ case 'c': // Class
+ i+=2; break;
+ case 'e': // Enum constant
+ i+=4; break;
+ case '@': // Annotation
+ String[] typeName2 = new String[1];
+ i = ObjectTeamsTransformation.scanStrings(typeName2, bytes, i, cpg); // nested annotation type
+ i = skipNameValuePairs(bytes, i, typeName2[0], cpg);
+ break;
+ case '[': // Array
+ int numArrayVals = ObjectTeamsTransformation.combineTwoBytes(bytes, i);
+ i+=2;
+ for (int j = 0; j < numArrayVals; j++)
+ i = skipElementValue(bytes, i, typeName, cpg);
+ break;
+ default:
+ throw new RuntimeException("Unexpected element value kind in annotation: " + typeName);
+ }
+ return i;
+ }
+
+}
diff --git a/othersrc/OTRE/src/org/eclipse/objectteams/otre/util/AttributeReadingGuard.java b/othersrc/OTRE/src/org/eclipse/objectteams/otre/util/AttributeReadingGuard.java
new file mode 100644
index 0000000..4d72e02
--- /dev/null
+++ b/othersrc/OTRE/src/org/eclipse/objectteams/otre/util/AttributeReadingGuard.java
@@ -0,0 +1,80 @@
+/**********************************************************************
+ * 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: AttributeReadingGuard.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.util;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author Christine Hundt
+ * @author Stephan Herrmann
+ */
+public class AttributeReadingGuard {
+
+ private static Map<ClassLoader, AttributeReadingGuard> instances = new HashMap<ClassLoader, AttributeReadingGuard>();
+ private static AttributeReadingGuard defaultInstance = new AttributeReadingGuard();
+
+ private ArrayList<String> servedClasses = new ArrayList<String>();
+
+ // this one flag is really global (concerns the one main class of the application):
+ private static boolean firstLoaded = true;
+
+ /**
+ * @param className
+ * @return
+ */
+ public boolean iAmTheFirst(String className) {
+ return !this.servedClasses.contains(className);
+ }
+
+ /**
+ * Processing the given class is done.
+ * @param className
+ */
+ public void workDone(String className) {
+ this.servedClasses.add(className);
+ }
+
+ /**
+ * @return whether this class is the first being loaded => possibly the main class.
+ */
+ public static synchronized boolean isFirstLoadedClass() {
+ if (!firstLoaded)
+ return false;
+ firstLoaded = false;
+ return true;
+ }
+
+ /** First loaded class has no main => it was a false alarm. */
+ public static void reset() {
+ firstLoaded = true;
+ }
+
+ /**
+ * Since actual data are stored in an instance, static methods need to retrieve the appropriate
+ * instance regarding the given class loader.
+ */
+ public static AttributeReadingGuard getInstanceForLoader(ClassLoader loader) {
+ if (loader == null)
+ return defaultInstance;
+
+ AttributeReadingGuard instance = instances.get(loader);
+ if (instance == null)
+ instances.put(loader, instance = new AttributeReadingGuard());
+ return instance;
+ }
+}
diff --git a/othersrc/OTRE/src/org/eclipse/objectteams/otre/util/BoundClass.java b/othersrc/OTRE/src/org/eclipse/objectteams/otre/util/BoundClass.java
new file mode 100644
index 0000000..1746be5
--- /dev/null
+++ b/othersrc/OTRE/src/org/eclipse/objectteams/otre/util/BoundClass.java
@@ -0,0 +1,80 @@
+/**********************************************************************
+ * This file is part of the "Object Teams Runtime Environment"
+ *
+ * Copyright 2004-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$
+ *
+ * Please visit http://www.objectteams.org for updates and contact.
+ *
+ * Contributors:
+ * Berlin Institute of Technology - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.objectteams.otre.util;
+
+import java.util.HashSet;
+
+import de.fub.bytecode.generic.ObjectType;
+
+/**
+ * @version $Id: BoundClass.java,v 1.8 2006-12-19 21:31:30 stephan Exp $
+ * @author Christine Hundt
+ */
+public class BoundClass {
+ private String name;
+
+ private BoundClass _super;
+ //private BoundClass _tsuper;
+ private HashSet<String> adaptingTeams = new HashSet<String>();
+
+ public BoundClass(String className, String teamName) {
+ name = className;
+ this.adaptingTeams.add(teamName);
+ _super = null;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public boolean isAdaptedByTeam(String teamName) {
+ return this.adaptingTeams.contains(teamName);
+ }
+
+ public void addAdaptingTeam(String teamName) {
+ this.adaptingTeams.add(teamName);
+ }
+
+ public void setSuper(BoundClass superClass) {
+ _super = superClass;
+ }
+
+ public BoundClass getSuper() {
+ return _super;
+ }
+
+ public boolean isSubClassOf(String anotherClass) {
+ BoundClass superClass = _super;
+ while (superClass!=null) {
+ if (superClass.getName().equals(anotherClass)) {
+ return true;
+ }
+ superClass = superClass.getSuper();
+ }
+ return false;
+ }
+
+ public void updateSuper(BoundClass newSuperBaseClass, ObjectType newSuperBaseType) {
+ // FIXME(SH): implement ;-)
+ // test if newSuperBaseType is above or below _super.
+ // also check if tsupers (i.e., more than one super) must be treated as well.
+ }
+
+// public String toString() {
+// return name;
+// }
+}
diff --git a/othersrc/OTRE/src/org/eclipse/objectteams/otre/util/BoundMethod.java b/othersrc/OTRE/src/org/eclipse/objectteams/otre/util/BoundMethod.java
new file mode 100644
index 0000000..4a4a8fb
--- /dev/null
+++ b/othersrc/OTRE/src/org/eclipse/objectteams/otre/util/BoundMethod.java
@@ -0,0 +1,48 @@
+/**********************************************************************
+ * This file is part of the "Object Teams Runtime Environment"
+ *
+ * Copyright 2004-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: BoundMethod.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.util;
+
+/**
+ * @author Christine Hundt
+ * @version $Id: BoundMethod.java 23408 2010-02-03 18:07:35Z stephan $
+ */
+public class BoundMethod {
+ private String name;
+ private String signature;
+ private boolean isCallin;
+
+// private MethodBinding binding;
+
+ public BoundMethod(String methodName, String methodSignature, boolean isCallin, MethodBinding methodBinding) {
+ name = methodName;
+ signature = methodSignature;
+ this.isCallin = isCallin;
+// binding = methodBinding;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String getSignature() {
+ return signature;
+ }
+
+ public boolean getIsCallin() {
+ return this.isCallin;
+ }
+}
diff --git a/othersrc/OTRE/src/org/eclipse/objectteams/otre/util/CallinBindingManager.java b/othersrc/OTRE/src/org/eclipse/objectteams/otre/util/CallinBindingManager.java
new file mode 100644
index 0000000..ba2330a
--- /dev/null
+++ b/othersrc/OTRE/src/org/eclipse/objectteams/otre/util/CallinBindingManager.java
@@ -0,0 +1,1429 @@
+/**********************************************************************
+ * 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: CallinBindingManager.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.util;
+
+//import de.fub.bytecode.generic.Type; // just for javadoc.
+import de.fub.bytecode.Repository;
+import de.fub.bytecode.classfile.JavaClass;
+import de.fub.bytecode.generic.ObjectType;
+
+import org.eclipse.objectteams.otre.OTREInternalError;
+import org.eclipse.objectteams.otre.ObjectTeamsTransformation;
+import org.eclipse.objectteams.otre.ObjectTeamsTransformation.BaseMethodInfo;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+import java.util.Map.Entry;
+
+/**
+ * @version $Id: CallinBindingManager.java 23408 2010-02-03 18:07:35Z stephan $
+ * @author Christine Hundt
+ */
+@SuppressWarnings("nls")
+public class CallinBindingManager {
+ // map of bindings for role classes: roleClassName -> RoleBaseBinding
+ private static HashMap<String, RoleBaseBinding> roleBindings = new HashMap<String, RoleBaseBinding>();
+
+ // map of bindings for base classes: baseClassName -> List[RoleBaseBinding]
+ private static ListValueHashMap<RoleBaseBinding> baseBindings = new ListValueHashMap<RoleBaseBinding>();
+
+ // maps a team to its handled bases: teamClassName -> List[BaseClassName]
+ private static ListValueHashMap<String> basesPerTeam = new ListValueHashMap<String>();
+
+ // maps a team to its contained roles: teamClassName -> List[RoleClassName]
+ private static ListValueHashMap<String> rolesPerTeam = new ListValueHashMap<String>();
+
+ // store sets of bases indexed by a team name,
+ // where the team adapts (decapsulates) the given bases without a direct playedBy relation
+ private static HashMap<String, HashSet<String>> extraReferencedBases = new HashMap<String, HashSet<String>>();
+
+ /**
+ * Add super-link of the BoundRole object for the RoleBaseBinding of 'className' to 'superClassName'.
+ * @param className the name of the class for which to add the super-link
+ * @param superClassName the name of the super class to be linked
+ */
+ public static void addSuperRoleLink(String className, String superClassName) {
+ if (!roleBindings.containsKey(superClassName))
+ return; // no super role class stored!
+ RoleBaseBinding rbbSuper = roleBindings.get(superClassName);
+ RoleBaseBinding rbb = roleBindings.get(className);
+ // establish link from the role to its super role class:
+ rbb.getRoleClass().setSuper(rbbSuper.getRoleClass());
+ }
+
+ /**
+ * @param baseClassName
+ */
+ private static void addSuperBaseLink(String teamClassName, String baseClassName, RoleBaseBinding rbb)
+ {
+ BoundClass baseClass = rbb.getBaseClass();
+ ObjectType baseClassType = new ObjectType(baseClassName);
+ if (!checkLookup(baseClassType.getClassName())) // TODO: workaround for classes loaded from special locations
+ return;
+ // clone the set for re-entrance:
+ Iterator<Entry<String, LinkedList<RoleBaseBinding>>> it = getBaseBindingsCloneIterator();
+ while (it.hasNext()) {
+ Entry<String, LinkedList<RoleBaseBinding>> entry = it.next();
+ String currentBaseClassName = entry.getKey();
+ if (currentBaseClassName.equals(baseClassName)) continue;
+ ObjectType currentType = new ObjectType(currentBaseClassName);
+ if (!checkLookup(currentType.getClassName())) // TODO: workaround for classes loaded from special locations
+ continue;
+ // BoundClass objects are unique per base object, so just take the first binding:
+ BoundClass currentBaseClass = entry.getValue().getFirst().getBaseClass();
+ if(baseClassType.subclassOf(currentType)) {
+ BoundClass rbbSuper = baseClass.getSuper();
+ if (rbbSuper != null) {
+ if (rbbSuper.getName().equals(currentBaseClassName))
+ continue; // no need for action: already set.
+ baseClass.updateSuper(currentBaseClass, currentType);
+ }
+ baseClass.setSuper(currentBaseClass);
+ }
+ else if (currentType.subclassOf(baseClassType)) {
+ BoundClass currentSuper = currentBaseClass.getSuper();
+ // if sub base classes may be registered before super base class,
+ // this case has to be considered too:
+ if (currentSuper != null) {
+ if (currentSuper.getName().equals(baseClassName))
+ continue; // no need for action: already set.
+ currentBaseClass.updateSuper(baseClass, baseClassType);
+ }
+ currentBaseClass.setSuper(baseClass);
+ }
+ }
+ }
+
+ /**
+ * Declare role playedBy base.
+ *
+ * @param roleClassName the name of the played role class
+ * @param baseClassName the name of the playing base class
+ */
+ public static void addRoleBaseBinding(String roleClassName, String baseClassName, String teamClassName) {
+ RoleBaseBinding rbb = roleBindings.get(roleClassName);
+ if (rbb == null) {
+ rbb = new RoleBaseBinding(roleClassName, baseClassName, teamClassName);
+ roleBindings.put(roleClassName, rbb);
+ }
+ addSuperBaseLink(teamClassName, baseClassName, rbb);
+ synchronized (baseBindings) {
+ baseBindings.put(baseClassName, rbb);
+ }
+ addTeamRoleRelation(teamClassName, roleClassName);
+ }
+
+ /**
+ * @param teamClassName
+ * @param baseClassName
+ */
+ public static void addTeamBaseRelation(String teamClassName, String baseClassName) {
+ JavaClass baseClass = Repository.lookupClass(baseClassName);
+ if (checkLookup(baseClassName) && baseClass.isInterface()) { // TODO: workaround for classes loaded from special locations
+ // TODO (SH): need to register with all implementing classes!
+ if (logging) {
+ ObjectTeamsTransformation.printLogMessage("*** Skipping base " + baseClassName + ": is an interface");
+ ObjectTeamsTransformation.printLogMessage("Classses implementing the interface " + baseClassName + " have to be transformed!");
+ }
+ addBoundBaseInterface(baseClassName);
+ } else {
+ List<String> bases = basesPerTeam.get(teamClassName);
+ if (bases==null || !bases.contains(baseClassName))
+ basesPerTeam.put(teamClassName, baseClassName);
+ }
+ }
+
+ /**
+ * @param teamClassName
+ * @return
+ */
+ public static List<String> getBasesPerTeam(String teamClassName) {
+ // (PH): return empty list instead of null when team has no bases?
+ return basesPerTeam.get(teamClassName);
+ }
+
+ /**
+ * @param teamClassName
+ * @param roleClassName
+ */
+ public static void addTeamRoleRelation(String teamClassName, String roleClassName) {
+ List<String> roles = rolesPerTeam.get(teamClassName);
+ if (roles == null || !roles.contains(roleClassName))
+ rolesPerTeam.put(teamClassName, roleClassName);
+ }
+
+ /**
+ * @param teamClassName
+ * @return
+ */
+ public static List<String> getRolePerTeam(String teamClassName) {
+ return rolesPerTeam.get(teamClassName);
+ }
+
+ private static LinkedList<String> allRoles = new LinkedList<String>();
+
+ /**
+ * @param roleName
+ */
+ public static void addRole(String roleName) {
+ allRoles.add(roleName);
+ }
+
+ /**
+ * @param roleName
+ * @return
+ */
+ public static boolean isRole(String roleName) {
+ return allRoles.contains(roleName);
+ }
+
+ public static void addExtraReferencedBase(String teamName, String baseName) {
+ HashSet<String> bases = extraReferencedBases.get(teamName);
+ if (bases == null) {
+ bases = new HashSet<String>();
+ extraReferencedBases.put(teamName, bases);
+ }
+ bases.add(baseName);
+ }
+
+ /**
+ * Get all bases adapted by a team without a direct playedBy relation.
+ * @param teamName
+ * @return non-null Set (may be empty).
+ */
+ public static Set<String> getExtraReferencedBases(String teamName) {
+ Set<String> bases = extraReferencedBases.get(teamName);
+ if (bases != null)
+ return bases;
+ return new HashSet<String>();
+ }
+
+ /**
+ * Declare binding of a pair of methods.
+ * @param roleClassName
+ * @param bindingFileName TODO
+ * @param bindingLineNumber TODO
+ * @param bindingLineOffset TODO
+ * @param roleMethodName
+ * @param roleMethodSignature signature ready for interpretation by
+ * {@link Type de.fub.bytecode.generic.Type}
+ * @param isStaticRoleMethod TODO
+ * @param modifier "before", "after" or "replace"
+ * @param baseMethodName
+ * @param baseMethodSignature
+ * @param isStaticBaseMethod is the base method static?
+ * @param baseIsCallin is the base method a callin method?
+ * @param translationFlags one bit for the result and for each argument indicating whether lifting/lowering is needed
+ * @param liftMethodName
+ * @param liftMethodSignature
+ */
+ public static void addMethodBinding(
+ String roleClassName, String baseClassName,
+ String bindingFileName, int bindingLineNumber, int bindingLineOffset,
+ String bindingLabel, String roleMethodName, String roleMethodSignature, boolean isStaticRoleMethod,
+ String wrapperName, String wrapperSignature, String modifier,
+ String baseMethodName, String baseMethodSignature,
+ boolean isStaticBaseMethod, boolean baseIsCallin, boolean covariantBaseReturn,
+ int translationFlags, String liftMethodName, String liftMethodSignature)
+ {
+ RoleBaseBinding rbb = roleBindings.get(roleClassName);
+ if (rbb == null) {
+ // no binding found, create it now:
+ if (baseClassName == null)
+ throw new OTREInternalError("PlayedBy attribute must be read before method bindings.");
+ int lastDollar = roleClassName.lastIndexOf('$');
+ String teamClassName = roleClassName.substring(0, lastDollar);
+ rbb = new RoleBaseBinding(roleClassName, baseClassName, teamClassName);
+ roleBindings.put(roleClassName, rbb);
+ }
+ //System.err.println(rbb.getRoleClass().getName()+"<-*->"+rbb.getBaseClass().getName());
+ rbb.addMethodBinding(bindingFileName, bindingLineNumber, bindingLineOffset,
+ bindingLabel, roleMethodName, roleMethodSignature, isStaticRoleMethod,
+ wrapperName, wrapperSignature, modifier,
+ baseMethodName, baseMethodSignature,
+ isStaticBaseMethod, baseIsCallin, covariantBaseReturn,
+ translationFlags,
+ liftMethodName, liftMethodSignature);
+
+ if (modifier.equals("replace"))
+ assignBaseCallTag(rbb.getBaseClassName(), baseMethodName, baseMethodSignature);
+ }
+
+ /**
+ * Get all callin bindings for a given base method.
+ * @param className the base class
+ * @param methodName the base method
+ * @return Collection of <pre>MethodBinding</pre>
+ */
+ public static Collection<MethodBinding> getBindingForBaseMethod(String baseClassName, String baseMethodName, String baseMethodSignature)
+ {
+ LinkedList<RoleBaseBinding> rbbList = baseBindings.get(baseClassName);
+ LinkedList<MethodBinding> resultList = new LinkedList<MethodBinding>();
+ if (rbbList != null) {
+ Iterator<RoleBaseBinding> it = rbbList.iterator();
+ while (it.hasNext()) {
+ RoleBaseBinding rbb = it.next();
+ List<MethodBinding> mbs = rbb.getBaseMethodBindings(baseMethodName, baseMethodSignature);
+ if (mbs != null)
+ addFiltered(resultList, mbs, baseMethodName, baseMethodSignature);
+ }
+ }
+ // IMPLICIT_INHERITANCE
+ addFiltered(resultList,
+ getImplicitlyInheritedBaseMethodBindings(baseClassName, baseMethodName, baseMethodSignature),
+ baseMethodName,
+ baseMethodSignature);
+ if (resultList.isEmpty())
+ return null;
+ return resultList;
+ }
+ /** variant of the above, optimized for computing only a boolean result instead of a complete list. */
+ public static boolean isBoundBaseMethod(String baseClassName, String baseMethodName, String baseMethodSignature)
+ {
+ LinkedList<RoleBaseBinding> rbbList = baseBindings.get(baseClassName);
+ if (rbbList != null) {
+ for (RoleBaseBinding rbb : rbbList) {
+ List<MethodBinding> mbs = rbb.getBaseMethodBindings(baseMethodName, baseMethodSignature);
+ if (mbs != null)
+ for (MethodBinding mb : mbs)
+ if (mb.matchesMethod(baseMethodName, baseMethodSignature, /* strict */ true))
+ return true;
+ }
+ }
+ // IMPLICIT_INHERITANCE
+ for (MethodBinding mb : getImplicitlyInheritedBaseMethodBindings(baseClassName, baseMethodName, baseMethodSignature))
+ if (mb.matchesMethod(baseMethodName, baseMethodSignature, /* strict */ true))
+ return true;
+ return false;
+ }
+ // add bindings from candidates to resultList, perhaps checking
+ // full signatures (i.e., if not covariantBaseReturn).
+ private static void addFiltered(Collection<MethodBinding> resultList,
+ Collection<MethodBinding> candidates,
+ String name,
+ String fullSignature)
+ {
+ for (MethodBinding methodBinding : candidates)
+ if (methodBinding.matchesMethod(name, fullSignature, /*strict*/false))
+ resultList.add(methodBinding);
+ }
+
+ /**
+ * Gets all implicitly inherited method bindings for the given base method.
+ * Note: the result can only contain elements for base classes which are
+ * roles at the same time!
+ * @param baseClassName the name of the base class
+ * @param baseMethodName the name of the base mehtod
+ * @param baseMethodSignature the descriptor or the base method signature
+ * @return a Collection with all implicitly inherited method bindings
+ */
+ private static Collection<MethodBinding> getImplicitlyInheritedBaseMethodBindings(String baseClassName, String baseMethodName, String baseMethodSignature) {
+ List<MethodBinding> resultList = new LinkedList<MethodBinding>();
+
+ if (!isRole(baseClassName))
+ return resultList; // only roles can have implicit super types
+
+ Iterator<Entry<String, LinkedList<RoleBaseBinding>>> it = getBaseBindingsCloneIterator();
+
+ while (it.hasNext()) {
+ Entry<String, LinkedList<RoleBaseBinding>> entry = it.next();
+ String have = entry.getKey();
+ // look for true superClass (not same):
+ if (have.equals(baseClassName))
+ continue;
+ if (isImplicitSubtype(baseClassName, have)) {
+ // now we have an implicit superClass:
+ if (logging)
+ ObjectTeamsTransformation.printLogMessage(baseClassName
+ + " implicitly inherits callin bindings from " + have);
+ // collect the signatures of all bound base methods:
+ List<RoleBaseBinding> rbbList = entry.getValue();
+ if (rbbList != null) {
+ Iterator<RoleBaseBinding> rbb_it = rbbList.iterator();
+ while (rbb_it.hasNext()) {
+ RoleBaseBinding rbb = rbb_it.next();
+ List<MethodBinding> mbs = rbb.getBaseMethodBindings(baseMethodName, baseMethodSignature);
+ if (mbs != null)
+ resultList.addAll(mbs);
+ }
+ }
+ }
+ }
+ //if (!resultList.isEmpty())
+ // System.err.println(resultList);
+ return resultList;
+ }
+
+ /**
+ * Get all callin bindings that a given base class may inherit from its superclass.
+ * @param className
+ * @result list of MethodBinding
+ */
+ public static Collection<MethodBinding> getInheritedCallinBindings (String className) {
+/*
+ List classBindings = baseBindings.get(className);
+ if (classBindings!=null) {
+ // any RoleBaseBinding contains the corresponding BoundClass object for the super base:
+ RoleBaseBinding anyRBB = (RoleBaseBinding)classBindings.get(0);
+ // problem: if a sub base class is not explicitly bound to a role class no corresponding
+ // BoundClass object exists. How can we access the super bindings via the
+ // super-link??
+ BoundClass bc = anyRBB.getBaseClass();
+ //System.out.println("-----------");
+ while (bc.getSuper()!=null) {
+ System.out.println(bc.getName());
+ bc = bc.getSuper();
+ }
+ //System.out.println("-----------");
+ }
+*/
+
+ List<MethodBinding> result = new LinkedList<MethodBinding>();
+ ObjectType current = new ObjectType(className);
+ if (!checkLookup(current.getClassName())) // TODO: workaround for classes loaded from special locations
+ return result;
+ // clone for re-entrance:
+ Iterator<Entry<String, LinkedList<RoleBaseBinding>>> it= getBaseBindingsCloneIterator();
+ while (it.hasNext()) {
+ Entry<String, LinkedList<RoleBaseBinding>> entry = it.next();
+ String have = entry.getKey();
+ // look for true superClass (not same):
+ if (have.equals(className)) continue;
+ ObjectType haveType = new ObjectType(have);
+ //System.err.println(current + " : "+haveType);
+ //System.err.println(de.fub.bytecode.Repository.lookupClass(have));
+ if (!checkLookup(haveType.getClassName())) // TODO: workaround for classes loaded from special locations
+ continue;
+ if (current.subclassOf(haveType)) {
+ // now we have a true superClass:
+ if (logging)
+ ObjectTeamsTransformation.printLogMessage(className
+ + " inherits callin bindings from " + have);
+ // collect the signatures of all bound base methods:
+ List<RoleBaseBinding> rbbList = entry.getValue();
+ if (rbbList != null) {
+ Iterator<RoleBaseBinding> rbb_it = rbbList.iterator();
+ while (rbb_it.hasNext()) {
+ RoleBaseBinding rbb = rbb_it.next();
+ result.addAll(rbb.getBaseMethodBindings());
+ }
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Get all super classes defining callin bindings that a given static base
+ * method may inherit.
+ *
+ * @author juerwid
+ * @param className
+ * @param methodName
+ * @param methodSignaturte
+ * @result list of <String[] {class_name}>
+ */
+ public static Collection<String> getInheritedCallinBindingsForStaticMethods(
+ String className, String methodName, String methodSignature)
+ {
+ List<String> result = new LinkedList<String>();
+ ObjectType current = new ObjectType(className);
+ if (!checkLookup(current.getClassName())) // TODO: workaround for classes loaded from special locations
+ return result;
+ // clone for re-entrance:
+ Iterator<Entry<String, LinkedList<RoleBaseBinding>>> it = getBaseBindingsCloneIterator();
+ boolean getNextClass = false;
+ while (it.hasNext()) {
+ Entry<String,LinkedList<RoleBaseBinding>> entry = it.next();
+ String have = entry.getKey();
+ // look for true superClass (not same):
+ if (have.equals(className)) continue;
+ ObjectType haveType = new ObjectType(have);
+ if (!checkLookup(haveType.getClassName())) // TODO: workaround for classes loaded from special locations
+ continue;
+ if (current.subclassOf(haveType)) {
+ // now we have a true superClass:
+ if (logging)
+ ObjectTeamsTransformation.printLogMessage(className
+ + " inherits callin bindings from " + have);
+ // collect the signatures of all bound base methods:
+ LinkedList<RoleBaseBinding> rbbList = entry.getValue();
+ if (rbbList != null) {
+ Iterator<RoleBaseBinding> rbb_it = rbbList.iterator();
+ while (rbb_it.hasNext() && !getNextClass) {
+ RoleBaseBinding rbb = rbb_it.next();
+ List<String[]> methods = rbb.getBaseSignatures();
+ Iterator<String[]> methodsIter = methods.iterator();
+ while(methodsIter.hasNext() && !getNextClass){
+ String[] aMethod = methodsIter.next();
+ if(methodName.equals(aMethod[0]) && methodSignature.equals(aMethod[1])){
+ result.add(have);
+ getNextClass = true;
+ }
+ }
+ }
+ if(getNextClass){
+ getNextClass = false;
+ continue;
+ }
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Checks if 'subType' is an implicit subtype of 'superType'.
+ * To be true the role name parts have to be equal and the
+ * team name parts have to be in a 'real' subtype relationship.
+ *
+ * @param subType the name of the potential subtype.
+ * @param superType the name of the potential supertype.
+ * @return true, if subType implicitly inherits from superType.
+ */
+ private static boolean isImplicitSubtype(String subType, String superType) {
+ //System.err.println(subType +" -?-> " + superType);
+ int dollarIdxSub = subType.lastIndexOf('$');
+ int dollarIdxSuper = superType.lastIndexOf('$');
+ if (dollarIdxSub==-1 || dollarIdxSuper==-1)
+ return false; // no roles
+ String pureSubType = subType.substring(dollarIdxSub+1, subType.length());
+ String pureSuperType = superType.substring(dollarIdxSuper+1, superType.length());
+ if (!pureSubType.equals(pureSuperType))
+ return false;// no identical role names
+
+ String subTeamName = subType.substring(0, dollarIdxSub);
+ String superTeamName = superType.substring(0,dollarIdxSuper);
+
+ if (!(checkLookup(subTeamName) && checkLookup(superTeamName)))
+ return false; // Repository can not lookup types
+ ObjectType subTeamType = new ObjectType(subTeamName);
+ ObjectType superTeamType = new ObjectType(superTeamName);
+ if (subTeamType.subclassOf(superTeamType)) {
+ if (logging)
+ ObjectTeamsTransformation.printLogMessage(subType
+ + " implicitly inherits method bindings from " + superType);
+ //System.err.println(subType + " implicitly inherits method bindings from " + superType);
+ return true;
+ }
+ return false; // no inheritance relation between teams
+ }
+
+ /**
+ * Check to avoid NullPointerExceptions caused by the Repository when classes can not be looked up (because they loaded by
+ * classloaders with special a classpath)
+ *
+ * @param current The name of the class to look up in the Repository.
+ * @return False, if the class can not be found, true else.
+ */
+ private static boolean checkLookup(String className) {
+ if (Repository.lookupClass(className) == null) {
+ if (OTEQUINOX_WARN)
+ System.err.println("Warning: Repository could not lookup class " + className + "!");
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Get all inherited method bindings for a given base method, which are
+ * bindings declared for a super base class.
+ *
+ * the actual base class has additional bindings for this method!
+ * @param baseClassName the name of the role class
+ * @param baseMethodName the name of the role method
+ * @param baseMethodSignature the signature of the role method
+ * @result a List containing all inherited bindings for the role method
+ */
+ public static List<MethodBinding> getInheritedBaseMethodBindings(String baseClassName, String baseMethodName, String baseMethodSignature) {
+
+ List<MethodBinding> inheritedMethodBindings = new LinkedList<MethodBinding>();
+ if (!isBoundBaseClass(baseClassName)) {
+ return inheritedMethodBindings;
+ }
+ LinkedList<RoleBaseBinding> baseBindingsForBase = baseBindings.get(baseClassName);
+ if (baseBindingsForBase == null)
+ return inheritedMethodBindings;
+
+ Iterator<RoleBaseBinding> it = baseBindingsForBase.iterator();
+ while (it.hasNext()) {
+ RoleBaseBinding rbb = it.next();
+ BoundClass bc = rbb.getBaseClass();
+ while (bc.getSuper() != null) {
+ bc = bc.getSuper();
+ String superRoleName = bc.getName();
+ Collection<MethodBinding> superRoleMethodBindings = CallinBindingManager.getBindingForBaseMethod(
+ superRoleName,
+ baseMethodName,
+ baseMethodSignature);
+ if (superRoleMethodBindings!=null)
+ inheritedMethodBindings.addAll(superRoleMethodBindings);
+ }
+ }
+ return inheritedMethodBindings;
+ }
+
+ /**
+ * Get all inherited method bindings for a given role method, which are
+ * bindings declared in a super role class. The actual role class has
+ * additional bindings for this method!
+ *
+ * @param roleClassName the name of the role class
+ * @param roleMethodName the name of the role method
+ * @param roleMethodSignature the signature of the role method
+ * @result a List containing all inherited bindings for the role method
+ */
+ public static List<MethodBinding> getInheritedRoleMethodBindings(String roleClassName, String roleMethodName, String roleMethodSignature) {
+ List<MethodBinding> inheritedMethodBindings = new LinkedList<MethodBinding>();
+ if (!isBoundRoleClass(roleClassName)) {
+ return inheritedMethodBindings;
+ }
+ RoleBaseBinding rbb = roleBindings.get(roleClassName);
+ BoundClass bc = rbb.getRoleClass();
+ while (bc.getSuper() != null) {
+ bc = bc.getSuper();
+ String superRoleName = bc.getName();
+ List<MethodBinding> superRoleMethodBindings = CallinBindingManager.getBindingsForRoleMethod(
+ superRoleName,
+ roleMethodName,
+ roleMethodSignature);
+ inheritedMethodBindings.addAll(superRoleMethodBindings);
+ }
+ return inheritedMethodBindings;
+ }
+
+ /**
+ * All bindings for a given role method concerning its base class.
+ *
+ * @return List of MethodBinding
+ */
+ public static List<MethodBinding> getBindingsForRoleMethod(String roleClassName,
+ String roleMethodName, String roleMethodSignature)
+ {
+ RoleBaseBinding rbb = roleBindings.get(roleClassName);
+ if (rbb==null) {
+ return new LinkedList<MethodBinding>();
+ }
+ List<MethodBinding> roleMethodBindings = rbb.getRoleMethodBindings(roleMethodName, roleMethodSignature);
+ if (roleMethodBindings == null) {
+ return new LinkedList<MethodBinding>();
+ }
+ return roleMethodBindings;
+ }
+
+ /**
+ * @param className
+ * @return
+ */
+ public static boolean isBoundBaseClass(String className) {
+ // and has at least one method binding?
+ boolean result = baseBindings.containsKey(className);
+ if (result || !isRole(className)) {
+ return result;
+ }
+ else {// bound implicit super class?
+ Iterator<String> it = getBaseBindingsKeyIterator();
+ while (it.hasNext()) {
+ String have = it.next();
+ // look for true superClass (not same):
+ if (have.equals(className))
+ continue;
+ if (isImplicitSubtype(className, have))
+ return true;
+ }
+ return result;
+ }
+ }
+
+ /**
+ * @param className
+ * @return
+ */
+ public static boolean isBoundBaseAndRoleClass(String className) {
+ // and has at least one method binding?
+ if (baseBindings.containsKey(className))
+ return true;
+ // bound implicit super class?
+ Iterator<String> it = getBaseBindingsKeyIterator();
+ while (it.hasNext()) {
+ String have = it.next();
+ // look for true superClass (not same):
+ if (have.equals(className))
+ continue;
+ if (isImplicitSubtype(className, have))
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * @param baseClassName
+ * @return
+ */
+ public static boolean hasBoundBaseParent(String baseClassName) {
+ LinkedList<RoleBaseBinding> rbbList = baseBindings.get(baseClassName);
+ if (rbbList != null) {
+ Iterator<RoleBaseBinding> it = rbbList.iterator();
+ while (it.hasNext()) {
+ RoleBaseBinding rbb = it.next();
+ if (rbb.getBaseClass().getSuper()!=null)
+ return true;
+ }
+ }
+ // IMPLICIT_INHERITANCE
+ //if (isUnboundSubBase(baseClassName))
+ // return true;
+ return false;
+ }
+
+
+ /**
+ * Returns the name of the topmost bound base class.
+ *
+ * @param baseClassName
+ * @return
+ */
+ public static String getTopmostBoundBase(String baseClassName) {
+ LinkedList<RoleBaseBinding> rbbList = baseBindings.get(baseClassName);
+ if (rbbList != null) {
+ // assumption: EVERY BoundClass object has been connected to its bound super classes.
+ RoleBaseBinding anyRBB = rbbList.get(0);
+ BoundClass bc = anyRBB.getBaseClass();
+ while (bc.getSuper() != null) {
+ bc = bc.getSuper();
+ }
+ return bc.getName();
+ }
+ return baseClassName;
+ }
+
+ /**
+ * @param baseClassName
+ * @return
+ */
+ public static String getBoundBaseParent(String baseClassName) {
+ LinkedList<RoleBaseBinding> rbbList = baseBindings.get(baseClassName);
+ if (rbbList != null) {
+ Iterator<RoleBaseBinding> it = rbbList.iterator();
+ while (it.hasNext()) {
+ RoleBaseBinding rbb = it.next();
+ BoundClass bc = rbb.getBaseClass().getSuper();
+ if (bc!=null)
+ return bc.getName();
+ }
+ }
+ // IMPLICIT_INHERITANCE
+ //if (isUnboundSubBase(baseClassName))
+ // return true;
+ return null;
+ }
+
+ /**
+ * @param teamClassName
+ * @param baseClassName
+ * @return
+ */
+ public static boolean teamAdaptsSuperBase(String teamClassName, String baseClassName) {
+ LinkedList<RoleBaseBinding> rbbList = baseBindings.get(baseClassName);
+ if (rbbList != null && !rbbList.isEmpty()) {
+ RoleBaseBinding rbb = rbbList.getFirst(); // all entries refer to the same base class.
+ BoundClass bc = rbb.getBaseClass().getSuper();
+ while (bc!=null) {
+ if (bc.isAdaptedByTeam(teamClassName))
+ return true;
+ bc = bc.getSuper();
+ }
+ }
+ return false;
+ }
+
+ /**
+ * @param baseClassName
+ * @return
+ */
+// private static boolean isUnboundSubBase(String baseClassName) {
+// ObjectType current = new ObjectType(baseClassName);
+// if (!checkLookup(current.getClassName())) // TODO: workaround for classes loaded from special locations
+// return false;
+// Iterator /* String */ it = baseBindings.keySet().iterator();
+// while (it.hasNext()) {
+// String have = (String)it.next();
+// // look for true superClass (not same):
+// if (have.equals(baseClassName)) continue;
+// ObjectType haveType = new ObjectType(have);
+// //System.err.println(current + " : "+haveType);
+// //System.err.println(de.fub.bytecode.Repository.lookupClass(have));
+// if (!checkLookup(haveType.getClassName())) // TODO: workaround for classes loaded from special locations
+// continue;
+// if (current.subclassOf(haveType)) {
+// return true;
+// }
+// }
+// return false;
+// }
+
+ /**
+ * @param className
+ * @return
+ */
+ public static boolean isBoundRoleClass(String className) {
+ return roleBindings.containsKey(className);
+ }
+
+ /**
+ * @param className
+ * @return
+ */
+ public static RoleBaseBinding getRoleBaseBinding(String roleClassName) {
+ return roleBindings.get(roleClassName);
+ }
+
+ /**
+ * @param roleClassName
+ * @return
+ */
+ public static List<MethodBinding> getMethodBindingsForRoleClass(String roleClassName)
+ {
+ RoleBaseBinding rbb = roleBindings.get(roleClassName);
+ return rbb.getRoleMethodBindings();
+ }
+
+ /**
+ * @param roleClassName
+ * @return
+ */
+ public static Set<String> getBoundRoleMethods(String roleClassName) {
+ Set<String> roleMethodKeySet = new HashSet<String>();
+ if (roleBindings.get(roleClassName) != null) {
+ RoleBaseBinding rbb = roleBindings.get(roleClassName);
+ roleMethodKeySet = rbb.getRoleMethodSignatures();
+ }
+ return roleMethodKeySet;
+ }
+
+ /**
+ * @param baseClassName
+ * @return
+ */
+ public static List<MethodBinding> getMethodBindingsForBaseClass(String baseClassName)
+ {
+ LinkedList<RoleBaseBinding> rbbList = baseBindings.get(baseClassName);
+ LinkedList<MethodBinding> resultList = new LinkedList<MethodBinding>();
+ if (rbbList != null) {
+ Iterator<RoleBaseBinding> it = rbbList.iterator();
+ while (it.hasNext()) {
+ RoleBaseBinding rbb = it.next();
+ resultList.addAll(rbb.getRoleMethodBindings());
+ }
+ }
+ return resultList;
+ }
+
+ // --------------------------------------------------
+ // discriminate base methods by tag per callin
+ // --------------------------------------------------
+ // baseClass.baseMeth.baseMethodSignature -> tag
+ private static HashMap<String, Integer> baseCallTags = new HashMap<String, Integer>();
+ // -- follow access methods for baseCallTags:
+
+ /**
+ * @param baseClass
+ * @param baseMeth
+ * @param baseMethodSignature
+ */
+ public static void assignBaseCallTag (String baseClass, String baseMeth,
+ String baseMethodSignature)
+ {
+ // every base method bound by a replace callin gets an unique tag:
+ String key = baseClass+"."+baseMeth+"."+baseMethodSignature;
+ int tag = baseCallTags.size();
+ if (!baseCallTags.containsKey(key))
+ baseCallTags.put(key, Integer.valueOf(tag));
+ }
+
+ public static int getBaseCallTag (String base_class_name,
+ String base_method_name,
+ String base_method_signature) {
+ String key = base_class_name + "." + base_method_name
+ + "." + base_method_signature;
+ return baseCallTags.get(key).intValue();
+ }
+
+ // ----------------------------------------------
+ // Map argument positions:
+ // ----------------------------------------------
+ // teamName -> callinWrapperName -> int[]
+ private static HashMap<String, HashMap<String, int[]>> paramMappings = new HashMap<String, HashMap<String, int[]>>();
+ // -- follow access methods for paramMappings:
+
+ /**
+ * @param teamName
+ * @param methodWrapper
+ * @param positions
+ */
+ public static void addParameterBinding (String teamName,
+ String methodWrapper,
+ int[] positions) {
+ HashMap<String, int[]> teamMap = paramMappings.get(teamName);
+ if (teamMap == null) {
+ teamMap = new HashMap<String, int[]>();
+ paramMappings.put(teamName, teamMap);
+ }
+ teamMap.put(methodWrapper, positions);
+ }
+
+ public static boolean hasParamMappings (String teamName, String methodWrapper)
+ {
+ HashMap<String,int[]> teamMap = paramMappings.get(teamName);
+ if (teamMap == null) return false;
+ return teamMap.containsKey(methodWrapper);
+ }
+
+ /** Get parameter positions for the given team or any super team. */
+ public static int[] getParamPositions (String teamName, String methodWrapper)
+ {
+ int[] positions = getExactParamPositions(teamName, methodWrapper);
+ if (positions != null)
+ return positions;
+ // inherit parameter mappings from super teams: -- >>
+ Iterator<String> superTeams = getSuperTeamsWithParamMappigs(teamName).iterator();
+ while (superTeams.hasNext()) {
+ positions = getExactParamPositions(superTeams.next(), methodWrapper);
+ if (positions != null) // found (the!) parameter mapping
+ return positions;
+ }
+ return null;
+ }
+ /** Get parameter positions for exactly the given team (no super teams). */
+ private static int[] getExactParamPositions(String teamName, String methodWrapper) {
+ HashMap<String,int[]>teamMap = paramMappings.get(teamName);
+ if (teamMap == null)
+ return null;
+ return teamMap.get(methodWrapper);
+ }
+
+ private static List<String> getSuperTeamsWithParamMappigs(String teamName) {
+ LinkedList<String> result = new LinkedList<String>();
+ if (!checkLookup(teamName)) // TODO: workaround for classes loaded from special locations
+ return result;
+ for (JavaClass superTeam : Repository.getSuperClasses(teamName))
+ if (paramMappings.get(superTeam.getClassName()) != null)
+ result.add(superTeam.getClassName());
+ return result;
+ }
+
+
+ // -----------------------------------------------
+ // tags for teams per base class:
+ // -----------------------------------------------
+ // baseName -> HashMap (teamName -> tag (Integer))
+ private static HashMap<String, HashMap<String, Integer>> baseTags = new HashMap<String, HashMap<String, Integer>>();
+
+ /**
+ * @param teamName
+ * @param baseToTag
+ */
+ public static void addBaseTags (String teamName, HashMap<String, Integer> baseToTag) {
+ Iterator<Entry<String, Integer>> iter = baseToTag.entrySet().iterator();
+ while (iter.hasNext()) {
+ Entry<String,Integer> entry = iter.next();
+ String baseName = entry.getKey();
+ Integer tag = entry.getValue();
+ HashMap<String, Integer> thisBaseTags = baseTags.get(baseName);
+ if (thisBaseTags == null) {
+ thisBaseTags = new HashMap<String, Integer>();
+ baseTags.put(baseName, thisBaseTags);
+ }
+ thisBaseTags.put(teamName, tag);
+ }
+ }
+
+ /**
+ * Get all tags of teams which have callins for a given base class.
+ * @param baseClassName base class name.
+ * @return HashMap: team name -> tag (Integer)
+ */
+ public static HashMap<String, Integer> getBaseTags (String baseClassName) {
+ HashMap<String, Integer> baseClassTags = baseTags.get(baseClassName);
+ if (baseClassTags == null)
+ return new HashMap<String, Integer>();
+ return baseTags.get(baseClassName);
+ }
+
+ /**
+ * Get all tags of teams which have callins for implicit super types
+ * of the given base class.
+ * Note: this is only possible if the base class is a role at the same time!
+ * @param baseClassName base class name.
+ * @return HashMap: team name -> tag (Integer)
+ */
+ public static HashMap<String, Integer> getInheritedBaseTags(String baseClassName) {
+ HashMap<String, Integer> result = new HashMap<String, Integer>();
+ // clone for re-entrance:
+ Iterator<String> it = getBaseBindingsKeyIterator();
+ while (it.hasNext()) {
+ String have = it.next();
+ // look for true superClass (not same):
+ if (have.equals(baseClassName))
+ continue;
+ if (isImplicitSubtype(baseClassName, have))
+ result.putAll(getBaseTags(have));
+ }
+ return result;
+ }
+
+ // -----------------------------------------------
+ // callout bindings that require adjustment:
+ // -----------------------------------------------
+ // baseClass -> HashSet (method_name+signature)
+ private static HashMap<String, HashSet<String>> calloutBindings = new HashMap<String, HashSet<String>>();
+
+ /**
+ * @param clazz
+ * @param meth
+ * @param sign
+ */
+ public static void addCalloutBinding(String clazz, String meth, String sign) {
+ HashSet<String> bindings = calloutBindings.get(clazz);
+ if (bindings == null) {
+ bindings = new HashSet<String>();
+ calloutBindings.put(clazz, bindings);
+ }
+ bindings.add(meth + sign);
+ }
+
+ /**
+ * @param clazz
+ * @return
+ */
+ public static HashSet<String> getCalloutBindings (String clazz) {
+ return calloutBindings.get(clazz);
+ }
+
+ /**
+ * @param bindings
+ * @param method_name
+ * @param signature
+ * @return
+ */
+ public static boolean requiresCalloutAdjustment(HashSet<String> bindings,
+ String method_name,
+ String signature)
+ {
+ return bindings.contains(method_name+signature);
+ }
+
+ // -----------------------------------------------
+ // callouts to base class fields are stored here for furher reading and get/set method generation:
+ // -----------------------------------------------
+ private static ListValueHashMap<FieldDescriptor> calloutSetFields = new ListValueHashMap<FieldDescriptor>();
+ private static ListValueHashMap<FieldDescriptor> calloutGetFields = new ListValueHashMap<FieldDescriptor>();
+
+
+ /**
+ * @param roleClassName
+ * @param fieldName
+ * @param fieldSignature
+ * @param accessMode
+ * @param isStaticField
+ */
+ public static void addCalloutBoundFileds(String baseClassName, String fieldName,
+ String fieldSignature, String accessMode, boolean isStaticField)
+ {
+ FieldDescriptor fd = new FieldDescriptor(fieldName, fieldSignature, isStaticField);
+
+ if (accessMode.equals("get")) {
+ calloutGetFields.put(baseClassName, fd);
+ } else if (accessMode.equals("set")) {
+ calloutSetFields.put(baseClassName, fd);
+ } else {
+ throw new OTREInternalError("CalloutFieldAccess attribute contains wrong access mode: "+accessMode);
+ }
+ }
+
+ /**
+ * @param baseClassName
+ * @return
+ */
+ public static List<FieldDescriptor> getCalloutGetFields(String baseClassName) {
+ return calloutGetFields.get(baseClassName);
+ }
+
+ /**
+ * @param baseClassName
+ * @return
+ */
+ public static List<FieldDescriptor> getCalloutSetFields(String baseClassName) {
+ return calloutSetFields.get(baseClassName);
+ }
+
+ // -----------------------------------------------
+ // base calls to super methods via special accessor
+ // -----------------------------------------------
+ private static ListValueHashMap<SuperMethodDescriptor> superMethods = new ListValueHashMap<SuperMethodDescriptor>();
+
+ public static void addSuperAccess(String baseClassName, String superClassName, String methodName, String signature) {
+ SuperMethodDescriptor superMethod = new SuperMethodDescriptor(methodName, baseClassName, superClassName, signature);
+ superMethods.put(baseClassName, superMethod);
+ }
+ public static List<SuperMethodDescriptor> getSuperAccesses(String class_name) {
+ return superMethods.get(class_name);
+ }
+
+ // -----------------------------------------------
+ // bound interfaces have to be registered, for implementing classes to inherit callin bindings:
+ // -----------------------------------------------
+ private static List<String> boundBaseInterfaces = new LinkedList<String>();
+
+ /**
+ * @param baseInterfaceName The name of the bound base interface.
+ */
+ public static void addBoundBaseInterface(String baseInterfaceName) {
+ if (!boundBaseInterfaces.contains(baseInterfaceName))
+ boundBaseInterfaces.add(baseInterfaceName);
+ }
+
+ /**
+ * @param interfaceName
+ * @return
+ */
+ public static Collection<String[]> getInterfaceInheritedCallinBindings(String interfaceName) {
+ List<String[]> result = new LinkedList<String[]>();
+ //System.err.println(interfaceName);
+ //System.err.println(boundBaseInterfaces);
+ if (boundBaseInterfaces.contains(interfaceName)) {
+ if (logging)
+ ObjectTeamsTransformation.printLogMessage(interfaceName
+ + " bequests callin bindings to implementing class");
+ // collect the signatures of all bound base methods:
+ LinkedList<RoleBaseBinding> rbbList = baseBindings.get(interfaceName);
+ if (rbbList != null) {
+ Iterator<RoleBaseBinding> rbb_it = rbbList.iterator();
+ while (rbb_it.hasNext()) {
+ RoleBaseBinding rbb = rbb_it.next();
+ result.addAll(rbb.getBaseSignatures());
+
+ // System.err.println("inheriting binding: "+rbb);
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * @param methodName
+ * @param methodSignature
+ * @param interfaceName
+ * @return
+ */
+ public static Collection<MethodBinding> getInterfaceInheritedMethodBindings(
+ String methodName, String methodSignature, String interfaceName) {
+ List<MethodBinding> result = new LinkedList<MethodBinding>();
+ if (boundBaseInterfaces.contains(interfaceName)) {
+ LinkedList<RoleBaseBinding> rbbList = baseBindings.get(interfaceName);
+ if (rbbList != null) {
+ Iterator<RoleBaseBinding> rbb_it = rbbList.iterator();
+ while (rbb_it.hasNext()) {
+ RoleBaseBinding rbb = rbb_it.next();
+ List<MethodBinding> mbs = rbb.getBaseMethodBindings(methodName, methodSignature);
+ if (mbs != null)
+ result.addAll(mbs);
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * @param interfaceNames
+ * @return
+ */
+ public static boolean containsBoundBaseInterface(String[] interfaceNames) {
+ for (int i = 0; i < interfaceNames.length; i++) {
+ if (boundBaseInterfaces.contains(interfaceNames[i]))
+ return true;
+ }
+ return false;
+ }
+
+ // -----------------------------------------------
+ // precedence can be set for a list of method bindings:
+ // -----------------------------------------------
+
+ private static ListValueHashMap<List<String>> precedencePerTeam = new ListValueHashMap<List<String>>();
+
+ /**
+ * Add a precedence list for the given team.
+ * @param precedenceList the list of binding labels defining their precedence
+ * @param teamName the name of the team for which the precedence list was defined
+ */
+ public static void addPrecedenceList(List<String> precedenceList, String teamName) {
+ precedencePerTeam.put(teamName, precedenceList);
+ }
+
+ /**
+ * Sorts the method binding list according to the given precedence for the team
+ * @param mbList the list of 'MethodBinding's to be sorted
+ * @param teamName the name of the corresponding team
+ * @return the sorted 'MethodBindig' list
+ */
+ public static List<MethodBinding> sortMethodBindings(List<MethodBinding> mbList, String teamName) {
+ if (mbList.size() < 2)
+ return mbList; // nothing to sort
+ String outermostTeamName;
+ int dollarIdx = teamName.indexOf('$');
+ if (dollarIdx > 0)
+ outermostTeamName = teamName.substring(0, dollarIdx);
+ else outermostTeamName = teamName;
+
+ List<List<String>> precedenceList = precedencePerTeam.get(outermostTeamName);
+ if (precedenceList==null) {
+ // mbList has to be reduced by removing overridden bindings:
+ return removeOverridden(mbList);
+ }
+
+ LinkedList<MethodBinding> sortedMethodBindings = new LinkedList<MethodBinding>();
+ Iterator<List<String>> predIt = precedenceList.iterator();
+
+ while (predIt.hasNext()) {
+ List<String> plainList = predIt.next();
+ Iterator<String> plainIt = plainList.iterator();
+
+ while (plainIt.hasNext()) {
+ boolean foundOne = false;
+ String label = plainIt.next();
+ Iterator<MethodBinding> mbIter = mbList.iterator();
+ List<MethodBinding> alreadySorted = new LinkedList<MethodBinding>();
+
+ while (mbIter.hasNext()) {
+ MethodBinding mb = mbIter.next();
+
+ if (mb.getQualifiedBindingLabel().equals(label)) { // mb exactly fits binding label:
+ alreadySorted.add(mb);
+ if (!foundOne) {
+ sortedMethodBindings.add(mb);
+ foundOne = true;
+ } else checkInheritance(sortedMethodBindings.getLast(), mb);
+
+ } else if (mb.inheritsBindingLabel(label, teamName)) { // mb inherits binding label:
+ alreadySorted.add(mb);
+ if (!foundOne) {
+ sortedMethodBindings.add(mb);
+ foundOne = true;
+ } else {// maybe it is a subtype of the already added?
+ MethodBinding lastAdded = sortedMethodBindings.getLast();
+ if (mb.overridesMethodBinding(lastAdded)) {
+ sortedMethodBindings.set(sortedMethodBindings.size()-1, mb);
+ foundOne = true;
+ } else checkInheritance(sortedMethodBindings.getLast(), mb);
+ }
+ }
+ }
+ if (foundOne) {
+ Iterator<MethodBinding> sortedIter = alreadySorted.iterator();
+ while (sortedIter.hasNext()) {
+ MethodBinding mb = sortedIter.next();
+ mbList.remove(mb);
+ }
+ }
+ }
+ }
+// if (mbList.size() > 0) {
+// System.err.println("ERROR: Unsortable method bindings: " + mbList +"!");
+// // assumption: all remaining method bindings are overridden! TODO: check assumption!
+// }
+ return sortedMethodBindings;
+ }
+
+ /**
+ * Removes overridden method bindings from the given list. Assumes that
+ * all bindings in the list are in a sub/super type relationship.
+ * @param mbList the method binding list
+ * @return the most specific method binding overriding all others
+ */
+ private static List<MethodBinding> removeOverridden(List<MethodBinding> mbList) {
+ MethodBinding mostSpecificMB = mbList.get(0);
+ Iterator<MethodBinding> mbIter = mbList.iterator();
+ while (mbIter.hasNext()) {
+ MethodBinding mb = mbIter.next();
+ if (mb.overridesMethodBinding(mostSpecificMB)) {
+ mostSpecificMB = mb;
+ } else checkInheritance(mostSpecificMB, mb);
+ }
+ List<MethodBinding> resultList = new LinkedList<MethodBinding>();
+ resultList.add(mostSpecificMB);
+ return resultList;
+ }
+
+ /**
+ * Checks if 'subMB' 'inherits' from 'superMB'. Used to check if assumptions
+ * about the precedence lists are fulfilled.
+ *
+ * @param subMB the overriding method binding
+ * @param superMB the overridden method binding
+ */
+ private static void checkInheritance(MethodBinding subMB, MethodBinding superMB) {
+ if (! (subMB.equals(superMB) || subMB.overridesMethodBinding(superMB))) {
+ //System.err.println("sub: " + subMB + "\n super: " + superMB);
+ throw new OTREInternalError("Wrong assumption! Broken precedence list possible.");
+ }
+ }
+
+ // ------------------------------------------
+ // ---------- Logging: ----------------------
+ // ------------------------------------------
+ /** Initialized from property <tt>ot.log</tt>. */
+ static boolean logging = false;
+ /** Initialized from property <tt>otequinox.debug</tt> */
+ static boolean OTEQUINOX_WARN = false;
+ static {
+ if(System.getProperty("ot.log") != null)
+ logging = true;
+ String warnlevel = System.getProperty("otequinox.debug");
+ if (warnlevel != null) {
+ warnlevel = warnlevel.toUpperCase();
+ if (warnlevel.startsWith("INFO") || warnlevel.equals("OK"))
+ OTEQUINOX_WARN = true;
+ }
+ }
+
+ // -----------------------------------------------
+ // static replace callin bindings have to be stored in the team, special treatment:
+ // -----------------------------------------------
+
+ // maps an implemented role method to its base methods: roleMethod -> List[baseMethod] // added by JU
+ private static ListValueHashMap<BaseMethodInfo> staticReplaceBindings = new ListValueHashMap<BaseMethodInfo>();
+
+ /**
+ * Adds a base method to its implemented role method (static replace bindings).
+ *
+ * @param roleMethodKey a string structured according team_class_ name.role_class_name.role_method_name.role_method_signature
+ * @param baseMethodInfo an Object contained base class name, base method name and base method signature
+ */
+ public static void addStaticReplaceBindingForRoleMethod(String roleMethodKey, BaseMethodInfo baseMethodInfo) {
+ staticReplaceBindings.put(roleMethodKey, baseMethodInfo);
+ }
+
+ /**
+ * Returns static method bindings for the given role method
+ * @param roleMethodKey
+ * @return
+ */
+ public static LinkedList<BaseMethodInfo> getStaticReplaceBindingsForRoleMethod(String roleMethodKey) {
+ return staticReplaceBindings.get(roleMethodKey);
+ }
+
+ /**
+ * @param roleClassName
+ * @param roleMethodName
+ * @param roleMethodSignature
+ * @return
+ */
+ public static boolean roleMethodHasBinding(String roleClassName, String roleMethodName, String roleMethodSignature) {
+ RoleBaseBinding rbb = roleBindings.get(roleClassName);
+ if (rbb == null) {
+ return false;
+ }
+ return rbb.hasRoleMethodBinding(roleMethodName, roleMethodSignature);
+ }
+
+ // -----------------------------------------------
+ // access modifiers of some base classes have to be changed to 'public' (decapsulation)
+ // the names of these classes are stored in baseClassesForModifierChange
+ // -----------------------------------------------
+ private static LinkedList<String> baseClassesForModifierChange = new LinkedList<String>();
+
+ /**
+ * Adds the given class name to the list of class names intended for decapsulation
+ * @param className
+ */
+ public static void addBaseClassForModifierChange(String className){
+ baseClassesForModifierChange.add(className);
+ }
+
+ /**
+ * Checks whether a class name is contained in the list of classes intended for decapsulation
+ * @param className
+ * @return
+ */
+ public static boolean checkBaseClassModifierChange(String className) {
+ Iterator<String> iter = baseClassesForModifierChange.iterator();
+ while(iter.hasNext()) {
+ if(className.equals(iter.next())){
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public static void addBoundSuperclassLink(String sub_name, String super_name) {
+ synchronized (baseBindings) {
+ bases:
+ for (RoleBaseBinding subBinding : baseBindings.getFlattenValues()) {
+ if (subBinding.getBaseClassName().equals(sub_name)) {
+ for (RoleBaseBinding superBinding : baseBindings.getFlattenValues()) {
+ if (subBinding == superBinding) continue;
+ if (superBinding.getBaseClassName().equals(super_name)) {
+ subBinding.getBaseClass().setSuper(superBinding.getBaseClass());
+ break bases;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /** Either retrieve an existing BoundClass for `className' are create a new one.
+ * If an existing one is used it is updated for the new adapting team.
+ */
+ public static BoundClass getBoundBaseClass(String className, String teamClassName) {
+ for (RoleBaseBinding subBinding : baseBindings.getFlattenValues()) {
+ if (subBinding.getBaseClassName().equals(className)) {
+ BoundClass baseClass = subBinding.getBaseClass();
+ baseClass.addAdaptingTeam(teamClassName);
+ return baseClass;
+ }
+ }
+ return new BoundClass(className, teamClassName);
+ }
+
+ // ==== HELPERS FOR RE-ENTRANCE SAFETY: ====
+
+ private static Iterator<String> getBaseBindingsKeyIterator() {
+ synchronized (baseBindings) {
+ ArrayList<String> list = new ArrayList<String>();
+ list.addAll(baseBindings.keySet());
+ Iterator<String> it = list.iterator();
+ return it;
+ }
+ }
+
+ private static Iterator<Entry<String, LinkedList<RoleBaseBinding>>> getBaseBindingsCloneIterator() {
+ synchronized (baseBindings) {
+ ArrayList<Entry<String, LinkedList<RoleBaseBinding>>> list = new ArrayList<Entry<String,LinkedList<RoleBaseBinding>>>();
+ list.addAll(baseBindings.entrySet());
+ Iterator<Entry<String, LinkedList<RoleBaseBinding>>> it = list.iterator();
+ return it;
+ }
+ }
+}
diff --git a/othersrc/OTRE/src/org/eclipse/objectteams/otre/util/DebugUtil.java b/othersrc/OTRE/src/org/eclipse/objectteams/otre/util/DebugUtil.java
new file mode 100644
index 0000000..7282185
--- /dev/null
+++ b/othersrc/OTRE/src/org/eclipse/objectteams/otre/util/DebugUtil.java
@@ -0,0 +1,155 @@
+/**********************************************************************
+ * This file is part of the "Object Teams Runtime Environment"
+ *
+ * Copyright 2003-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: DebugUtil.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.util;
+
+import de.fub.bytecode.generic.*;
+import de.fub.bytecode.Constants;
+import java.util.Enumeration;
+
+import org.eclipse.objectteams.otre.OTConstants;
+
+/**
+ * @author Stephan Herrmann
+ */
+@SuppressWarnings("nls")
+public class DebugUtil {
+
+ // -----------------------------------------
+ // -------- Development utilities ---------
+ // -----------------------------------------
+
+ /**
+ * Creates an the instructions necessary to "System.out.println"
+ * the given string.
+ *
+ * @param cpg the constant pool of the class where this instructions
+ * will be inserted
+ * @param string the String to be printed
+ * @return an InstructionList containing the necessary instructions
+ */
+ public static InstructionList createPrintln(ConstantPoolGen cpg,
+ InstructionFactory factory,
+ String string)
+ {
+ InstructionList il = new InstructionList();
+ ObjectType p_stream = new ObjectType("java.io.PrintStream");
+
+ il.append(factory.createFieldAccess("java.lang.System", "out",
+ p_stream,
+ Constants.GETSTATIC));
+ il.append(new PUSH(cpg, string + "\n"));
+ il.append(factory.createInvoke("java.io.PrintStream", "print",
+ Type.VOID,
+ new Type[] { Type.STRING },
+ Constants.INVOKEVIRTUAL));
+ return il;
+ }
+
+ /**
+ * Create a <tt>System.out.println</tt> call for an <tt>Object</tt>
+ * argument. The argument is assumed to be on the stack and will not
+ * be consumed.
+ */
+ public static InstructionList createPrintlnObj(InstructionFactory factory) {
+ InstructionList il = new InstructionList();
+ ObjectType p_stream = new ObjectType("java.io.PrintStream");
+
+ il.append(new DUP());
+ il.append(factory.createFieldAccess("java.lang.System", "out",
+ p_stream,
+ Constants.GETSTATIC));
+ il.append(new SWAP());
+ il.append(factory.createInvoke("java.io.PrintStream", "print",
+ Type.VOID,
+ new Type[] { OTConstants.object },
+ Constants.INVOKEVIRTUAL));
+ return il;
+ }
+
+ /**
+ * Create a <tt>System.out.println</tt> call for an <tt>Exception</tt>
+ * argument. The argument is assumed to be on the stack and _will_
+ * be consumed. This effect is however only performed, if
+ * the property ot.log.lift is set.
+ */
+ public static InstructionList createReportExc(InstructionFactory factory) {
+ InstructionList il = new InstructionList();
+ if (System.getProperty("ot.log.lift") == null) {
+ il.append(new POP());
+ } else {
+ ObjectType p_stream = new ObjectType("java.io.PrintStream");
+
+ il.append(factory.createFieldAccess("java.lang.System", "out",
+ p_stream,
+ Constants.GETSTATIC));
+ il.append(new SWAP());
+ il.append(factory.createInvoke("java.io.PrintStream", "println",
+ Type.VOID,
+ new Type[] { OTConstants.object },
+ Constants.INVOKEVIRTUAL));
+ }
+ return il;
+ }
+
+ /**
+ * Create a <tt>System.out.println</tt> call for an <tt>int</tt>
+ * argument. The argument is assumed to be on the stack and will not
+ * be consumed.
+ */
+ public static InstructionList createPrintlnInt(InstructionFactory factory) {
+ InstructionList il = new InstructionList();
+ ObjectType p_stream = new ObjectType("java.io.PrintStream");
+
+ il.append(new DUP());
+ il.append(factory.createFieldAccess("java.lang.System", "out",
+ p_stream,
+ Constants.GETSTATIC));
+ il.append(new SWAP());
+ il.append(factory.createInvoke("java.io.PrintStream", "print",
+ Type.VOID,
+ new Type[] { Type.INT },
+ Constants.INVOKEVIRTUAL));
+ return il;
+ }
+
+ public static InstructionList createPrintlnBool(ConstantPoolGen cp) {
+ InstructionList il= new InstructionList();
+ int out = cp.addFieldref("java.lang.System", "out",
+ "Ljava/io/PrintStream;");
+ int println = cp.addMethodref("java.io.PrintStream", "println",
+ "(Z)V");
+ il.append(new DUP());
+ il.append(new GETSTATIC(out));
+ il.append(new SWAP());
+ il.append(new INVOKEVIRTUAL(println));
+ return il;
+ }
+
+ @SuppressWarnings("unchecked")
+ public static void printIL (InstructionList il, ConstantPoolGen cpg) {
+ int off = 0;
+ Enumeration en = il.elements();
+ while(en.hasMoreElements()) {
+ Instruction i = ((InstructionHandle)en.nextElement()).getInstruction();
+ off += i.produceStack(cpg);
+ off -= i.consumeStack(cpg);
+ System.out.print(off);
+ System.out.println(" = "+i);
+ }
+ }
+
+}
diff --git a/othersrc/OTRE/src/org/eclipse/objectteams/otre/util/FieldDescriptor.java b/othersrc/OTRE/src/org/eclipse/objectteams/otre/util/FieldDescriptor.java
new file mode 100644
index 0000000..30a3dd0
--- /dev/null
+++ b/othersrc/OTRE/src/org/eclipse/objectteams/otre/util/FieldDescriptor.java
@@ -0,0 +1,53 @@
+/**********************************************************************
+ * This file is part of the "Object Teams Runtime Environment"
+ *
+ * Copyright 2004-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: FieldDescriptor.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.util;
+
+/**
+ * @author resix
+ */
+public class FieldDescriptor {
+ private String fieldName;
+ private String fieldSignature;
+ private boolean isStaticField;
+
+ public FieldDescriptor(String name, String signature, boolean is_static) {
+ fieldName = name;
+ fieldSignature = signature;
+ isStaticField = is_static;
+ }
+
+ /**
+ * @return Returns the fieldName.
+ */
+ public String getFieldName() {
+ return fieldName;
+ }
+
+ /**
+ * @return Returns the fieldSignature.
+ */
+ public String getFieldSignature() {
+ return fieldSignature;
+ }
+
+ /**
+ * @return Returns the isStaticField.
+ */
+ public boolean isStaticField() {
+ return isStaticField;
+ }
+}
diff --git a/othersrc/OTRE/src/org/eclipse/objectteams/otre/util/ListValueHashMap.java b/othersrc/OTRE/src/org/eclipse/objectteams/otre/util/ListValueHashMap.java
new file mode 100644
index 0000000..665ee5f
--- /dev/null
+++ b/othersrc/OTRE/src/org/eclipse/objectteams/otre/util/ListValueHashMap.java
@@ -0,0 +1,103 @@
+/**********************************************************************
+ * This file is part of the "Object Teams Runtime Environment"
+ *
+ * Copyright 2004-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: ListValueHashMap.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.util;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+import java.util.Map.Entry;
+
+/**
+ * @author resix
+ */
+public class ListValueHashMap<ValueType> {
+ private HashMap<String, LinkedList<ValueType>> hashMap = new HashMap<String, LinkedList<ValueType>>();
+ //redundant structure for faster access:
+ private LinkedList<ValueType> flattenValues = new LinkedList<ValueType>();
+
+ /**
+ * @param key
+ * @param value
+ */
+ public void put(String key, ValueType value) {
+ LinkedList<ValueType> list;
+ if (!hashMap.containsKey(key)) {
+ list = new LinkedList<ValueType>();
+ } else {
+ list = hashMap.get(key);
+ }
+ list.add(value);
+ hashMap.put(key, list);
+ flattenValues.add(value);
+ }
+
+ /**
+ * @return
+ */
+ public List<ValueType> getFlattenValues() {
+ return flattenValues;
+ }
+
+ /**
+ * @param key
+ * @return
+ */
+ public LinkedList<ValueType> get(String key) {
+ if (!hashMap.containsKey(key)) {
+ return null;
+ }
+ return hashMap.get(key);
+ }
+
+ public boolean containsKey(Object o) {
+ return hashMap.containsKey(o);
+ }
+
+ public Set<String> keySet() {
+ return hashMap.keySet();
+ }
+
+ public Set<Entry<String, LinkedList<ValueType>>> entrySet() {
+ return hashMap.entrySet();
+ }
+
+ public int size() {
+ return hashMap.size();
+ }
+
+ public String toString() {
+ StringBuilder result = new StringBuilder(32);
+ Iterator it = hashMap.entrySet().iterator();
+ while (it.hasNext()) {
+ Entry entry = (Entry) it.next();
+ result.append(entry.getKey());
+ result.append(": ");
+ result.append(entry.getValue().toString());
+ result.append("\n");
+ }
+ if (result.length() == 0)
+ return super.toString();
+ return result.toString();
+ }
+
+ public Collection<LinkedList<ValueType>> valueSet() {
+ return hashMap.values();
+ }
+}
diff --git a/othersrc/OTRE/src/org/eclipse/objectteams/otre/util/MethodBinding.java b/othersrc/OTRE/src/org/eclipse/objectteams/otre/util/MethodBinding.java
new file mode 100644
index 0000000..ecc5436
--- /dev/null
+++ b/othersrc/OTRE/src/org/eclipse/objectteams/otre/util/MethodBinding.java
@@ -0,0 +1,395 @@
+/**********************************************************************
+ * 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: MethodBinding.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.util;
+
+import org.eclipse.objectteams.otre.OTConstants;
+
+/**
+ * @version $Id: MethodBinding.java 23408 2010-02-03 18:07:35Z stephan $
+ * @author Christine Hundt
+ */
+public class MethodBinding {
+
+ private String bindingFileName;
+ private int bindingLineNumber;
+ private int bindingLineOffset;
+
+ private String bindingLabel;
+
+ private BoundMethod baseMethod;
+ private BoundMethod roleMethod;
+
+ private boolean isStaticBaseMethod;
+ private boolean isStaticRoleMethod;
+ private boolean covariantBaseReturn;
+
+ private int translationFlags;
+
+ private String wrapperName;
+ private String wrapperSignature;
+
+ private String modifier;
+ private String liftMethodName;
+ private String liftMethodSignature;
+
+ private String roleClassName;
+
+ // back reference for the class binding containing this method binding.
+ private RoleBaseBinding classBinding;
+
+ /**
+ *
+ */
+ public MethodBinding() {}
+
+ /**
+ * @param bindingFileName
+ * @param bindingLineNumber
+ * @param bindingLineOffest
+ * @param bindingLabel
+ * @param roleMethodName
+ * @param roleMethodSignature
+ * @param isStaticRoleMethod
+ * @param wrapperName
+ * @param wrapperSignature
+ * @param modifier
+ * @param baseMethodName
+ * @param baseMethodSignature
+ * @param isStaticBaseMethod
+ * @param baseIsCallin
+ * @param liftMethodName
+ * @param liftMethodSignature
+ * @param classBinding
+ */
+ public MethodBinding(
+ String bindingFileName, int bindingLineNumber, int bindingLineOffest,
+ String bindingLabel, String roleMethodName, String roleMethodSignature, boolean isStaticRoleMethod,
+ String wrapperName, String wrapperSignature, String modifier,
+ String baseMethodName, String baseMethodSignature,
+ boolean isStaticBaseMethod, boolean baseIsCallin, boolean covariantBaseReturn,
+ int translationFlags,
+ String liftMethodName, String liftMethodSignature, RoleBaseBinding classBinding)
+ {
+ this.bindingFileName = bindingFileName;
+ this.bindingLineNumber = bindingLineNumber;
+ this.bindingLineOffset = bindingLineOffest;
+
+ this.bindingLabel = bindingLabel;
+ roleMethod = new BoundMethod(roleMethodName, roleMethodSignature, false, this);
+ baseMethod = new BoundMethod(baseMethodName, baseMethodSignature, baseIsCallin, this);
+ // BoundMethod object for one method is not unique!
+ // but if it would be unique the 'binding' link would not be unique
+ this.isStaticRoleMethod = isStaticRoleMethod;
+ this.isStaticBaseMethod = isStaticBaseMethod;
+ this.covariantBaseReturn = covariantBaseReturn;
+ this.translationFlags = translationFlags;
+ this.wrapperName = wrapperName;
+ this.wrapperSignature = wrapperSignature;
+ this.modifier = modifier;
+ this.liftMethodName = liftMethodName;
+ this.liftMethodSignature = liftMethodSignature;
+ this.classBinding = classBinding;
+ this.roleClassName = classBinding.getRoleClassName();
+ }
+
+ /**
+ * @return
+ */
+ public String getRoleClassName() {
+ return roleClassName;
+ }
+
+ /**
+ * @return
+ */
+ public String getBindingFileName() {
+ return bindingFileName;
+ }
+
+ /**
+ * @return
+ */
+ public int getBindingLineNumber() {
+ return bindingLineNumber;
+ }
+
+ /**
+ * @return
+ */
+ public int getBindingLineOffset() {
+ return bindingLineOffset;
+ }
+
+ /**
+ * @return
+ */
+ public String getBindingLabel() {
+ return bindingLabel;
+ }
+
+ /**
+ * @return
+ */
+ public String getQualifiedBindingLabel() {
+ String result = roleClassName;
+ // remove the outermost team (use the '$' to distinguish pack1.Team1$Role from Team1$__OT__Team2$Role):
+ result = result.substring(result.indexOf('$') + 1);
+ // replace "$" by "." in the role class name:
+ result = result.replace('$', '.');
+ // remove "__OT__" prefixes in role class names:
+ result = result.replace(OTConstants.OTDT_PREFIX, ""); //$NON-NLS-1$
+ // add the binding label and return:
+ return result + '.' + bindingLabel;
+ }
+
+ /**
+ * @return
+ */
+ public String getRoleMethodName() {
+ return roleMethod.getName();
+ }
+
+ /**
+ * @return
+ */
+ public String getRoleMethodSignature() {
+ return roleMethod.getSignature();
+ }
+
+ /**
+ * @return
+ */
+ public String getWrapperName() {
+ return wrapperName;
+ }
+
+ /**
+ * @return
+ */
+ public String getWrapperSignature() {
+ return wrapperSignature;
+ }
+
+ /**
+ * @return
+ */
+ public String getBaseClassName() {
+ return classBinding.getBaseClassName();
+ }
+
+ /**
+ * @return
+ */
+ public String getBaseMethodName() {
+ return baseMethod.getName();
+ }
+
+ /**
+ * @return
+ */
+ public String getBaseMethodSignature() {
+ return baseMethod.getSignature();
+ }
+
+ /**
+ * @return
+ */
+ public boolean baseMethodIsCallin() {
+ return baseMethod.getIsCallin();
+ }
+
+ /**
+ * @return
+ */
+ public String getModifier() {
+ return modifier;
+ }
+
+ /**
+ * @return
+ */
+ public boolean isReplace() {
+ return modifier.equals("replace");
+ }
+
+ /**
+ * @return
+ */
+ public boolean isAfter() {
+ return modifier.equals("after");
+ }
+
+ /**
+ * @return
+ */
+ public boolean isBefore() {
+ return modifier.equals("before");
+ }
+
+ /**
+ * @return Returns the liftMethodName.
+ */
+ public String getLiftMethodName() {
+ return liftMethodName;
+ }
+
+ /**
+ * @return Returns the liftMethodSignature.
+ */
+ public String getLiftMethodSignature() {
+ return liftMethodSignature;
+ }
+
+ /**
+ * @return Returns the corresponding class binding.
+ */
+ public RoleBaseBinding getClassBinding() {
+ return classBinding;
+ }
+
+ /**
+ * Returns the most super bound base class of the base class belonging to
+ * this MethodBinding. Note: only consider base classes bound by roles of
+ * the corresponding team!
+ *
+ * @return the most super bound base class
+ */
+ public String getRootBoundBase() {
+ BoundClass bc = classBinding.getRoleClass();
+ while (bc.getSuper() != null && CallinBindingManager.isBoundRoleClass(bc.getSuper().getName()) ) {
+ bc = bc.getSuper();
+ }
+ RoleBaseBinding rbb = CallinBindingManager.getRoleBaseBinding(bc.getName());
+ return rbb.getBaseClassName();
+ }
+
+ /**
+ * Returns the name of the team surrounding the role class of this binding.
+ *
+ * @return the name of the corresponding team
+ */
+ public String getTeamClassName() {
+ int dollarIndex = roleClassName.lastIndexOf('$');
+ // return everything before the last '$', because for nested teams there are more than one:
+ return roleClassName.substring(0, dollarIndex);
+ }
+
+ /**
+ * @param anotherMB
+ * @return
+ */
+ public boolean overridesMethodBinding(MethodBinding anotherMB) {
+ if (anotherMB == null)
+ return false;
+ if (!bindingLabel.equals(anotherMB.getBindingLabel()))
+ return false;
+ return classBinding.getRoleClass().isSubClassOf(anotherMB.getClassBinding().getRoleClassName());
+ }
+
+ /**
+ * @param bindingLabel
+ * @param teamName
+ * @return
+ */
+ public boolean inheritsBindingLabel(String bindingLabel, String teamName) {
+ String prefix = teamName + "$__OT__";
+ int dotIndex = bindingLabel.lastIndexOf('.');
+ String classOfLabel = prefix + bindingLabel.substring(0, dotIndex);
+ if (!bindingLabel.substring(dotIndex + 1).equals(this.bindingLabel))
+ return false;
+
+ if (classBinding.getRoleClass().isSubClassOf(classOfLabel))
+ return true;
+ return false;
+ }
+
+ /**
+ * @param mb
+ * @return
+ */
+ public boolean equals(MethodBinding mb) {
+ return roleMethod.getName().equals(mb.getRoleMethodName())
+ && roleMethod.getSignature().equals(mb.getRoleMethodSignature())
+ && classBinding.getBaseClassName().equals(mb.getBaseClassName())
+ && baseMethod.getName().equals(mb.getBaseMethodName())
+ && baseMethod.getSignature().equals(mb.getBaseMethodSignature())
+ && modifier.equals(mb.getModifier());
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#toString()
+ */
+ public String toString() {
+ StringBuilder result = new StringBuilder(32);
+ result.append("\t");
+ result.append(getQualifiedBindingLabel());
+ result.append(": ");
+ result.append(roleMethod.getName());
+ result.append(roleMethod.getSignature());
+ result.append(" <-> ");
+ result.append(modifier);
+ result.append(" ");
+ result.append(baseMethod.getName());
+ result.append(baseMethod.getSignature());
+ if (this.covariantBaseReturn)
+ result.append('+');
+ return result.toString();
+ }
+
+ /**
+ * @return
+ */
+ public boolean hasStaticRoleMethod() {
+ return isStaticRoleMethod;
+ }
+
+ /**
+ * @return
+ */
+ public boolean hasStaticBaseMethod() {
+ return isStaticBaseMethod;
+ }
+
+ public int getTranslationFlags() {
+ return this.translationFlags;
+ }
+
+ /** For base methods provide a key without the trailing return type to cater for covariance. */
+ static String getBaseMethodKey(String baseMethodName, String baseMethodSignature) {
+ int pos= baseMethodSignature.lastIndexOf(')');
+ String baseMethodKey = baseMethodName + '.' + baseMethodSignature.substring(0, pos+1);
+ return baseMethodKey;
+ }
+
+ /**
+ * Is the method specified by mName and mSig a match for this method binding?
+ * @param mName method name
+ * @param mSig full method signature
+ * @param strict if true covariance is not supported
+ */
+ public boolean matchesMethod(String mName, String mSig, boolean strict) {
+ String baseMethodName = getBaseMethodName();
+ String baseMethodSignature = getBaseMethodSignature();
+ if (this.covariantBaseReturn && !strict) {
+ return getBaseMethodKey(mName, mSig).equals(
+ getBaseMethodKey(baseMethodName, baseMethodSignature));
+ } else {
+ return mName.equals(baseMethodName)
+ && mSig.equals(baseMethodSignature);
+ }
+ }
+}
diff --git a/othersrc/OTRE/src/org/eclipse/objectteams/otre/util/RoleBaseBinding.java b/othersrc/OTRE/src/org/eclipse/objectteams/otre/util/RoleBaseBinding.java
new file mode 100644
index 0000000..172c0ae
--- /dev/null
+++ b/othersrc/OTRE/src/org/eclipse/objectteams/otre/util/RoleBaseBinding.java
@@ -0,0 +1,228 @@
+/**********************************************************************
+ * 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: RoleBaseBinding.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.util;
+
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * @version $Id: RoleBaseBinding.java 23408 2010-02-03 18:07:35Z stephan $
+ * @author Christine Hundt
+ */
+public class RoleBaseBinding {
+
+ private BoundClass roleClass;
+ private BoundClass baseClass;
+
+ private ListValueHashMap<MethodBinding> roleMethodBindings = new ListValueHashMap<MethodBinding>();
+ private ListValueHashMap<MethodBinding> baseMethodBindings = new ListValueHashMap<MethodBinding>();
+
+ /**
+ *
+ */
+ public RoleBaseBinding() {
+ }
+
+ /**
+ * @param _roleClassName
+ * @param _baseClassName
+ * @param teamClassName
+ */
+ public RoleBaseBinding(String _roleClassName, String _baseClassName, String teamClassName) {
+ roleClass = new BoundClass(_roleClassName, teamClassName);
+ baseClass = CallinBindingManager.getBoundBaseClass(_baseClassName, teamClassName);
+ }
+
+ /**
+ * @param bindingFileName
+ * @param bindingLineNumber
+ * @param bindingLineOffset
+ * @param bindingLabel
+ * @param roleMethodName
+ * @param roleMethodSignature
+ * @param isStaticRoleMethod
+ * @param wrapperName
+ * @param wrapperSignature
+ * @param modifier
+ * @param baseMethodName
+ * @param baseMethodSignature
+ * @param isStaticBaseMethod
+ * @param baseIsCallin
+ * @param translationFlags
+ * @param liftMethodName
+ * @param liftMethodSignature
+ */
+ public void addMethodBinding(
+ String bindingFileName, int bindingLineNumber, int bindingLineOffset,
+ String bindingLabel, String roleMethodName, String roleMethodSignature,
+ boolean isStaticRoleMethod, String wrapperName, String wrapperSignature, String modifier,
+ String baseMethodName, String baseMethodSignature,
+ boolean isStaticBaseMethod, boolean baseIsCallin, boolean covariantBaseReturn,
+ int translationFlags, String liftMethodName, String liftMethodSignature)
+ {
+ MethodBinding mb = new MethodBinding(bindingFileName, bindingLineNumber, bindingLineOffset,
+ bindingLabel, roleMethodName, roleMethodSignature, isStaticRoleMethod,
+ wrapperName, wrapperSignature, modifier,
+ baseMethodName, baseMethodSignature,
+ isStaticBaseMethod, baseIsCallin, covariantBaseReturn,
+ translationFlags,
+ liftMethodName,
+ liftMethodSignature, this);
+ // TODO: check, if the key has to include the 'binding_label'
+ String baseMethodKey = MethodBinding.getBaseMethodKey(baseMethodName, baseMethodSignature);
+ String roleMethodKey = roleMethodName + '.' + roleMethodSignature;
+ roleMethodBindings.put(roleMethodKey, mb);
+ baseMethodBindings.put(baseMethodKey, mb);
+ }
+
+ /**
+ * @return
+ */
+ public List<MethodBinding> getBaseMethodBindings() {
+ return baseMethodBindings.getFlattenValues();
+ }
+
+ /**
+ * @param baseMethodName
+ * @param baseMethodSignature
+ * @return
+ */
+ public List<MethodBinding> getBaseMethodBindings(String baseMethodName, String baseMethodSignature) {
+ String baseMethodKey = MethodBinding.getBaseMethodKey(baseMethodName, baseMethodSignature);
+ return baseMethodBindings.get(baseMethodKey);
+ }
+
+ /**
+ * @return
+ */
+ public List<MethodBinding> getRoleMethodBindings() {
+ return roleMethodBindings.getFlattenValues();
+ }
+
+ /**
+ * @param roleMethodName
+ * @param roleMethodSignature
+ * @return
+ */
+ public List<MethodBinding> getRoleMethodBindings(String roleMethodName, String roleMethodSignature) {
+ String roleMethodKey = roleMethodName + '.' + roleMethodSignature;
+ return roleMethodBindings.get(roleMethodKey);
+ }
+
+ /**
+ * @param roleMethodName
+ * @param roleMethodSignature
+ * @return
+ */
+ public boolean hasRoleMethodBinding(String roleMethodName, String roleMethodSignature) {
+ String signatureWithoutReturnType = roleMethodSignature.substring(0, roleMethodSignature.lastIndexOf(')') + 1);
+ Set<String> bindingKeys = roleMethodBindings.keySet();
+ Iterator<String> it = bindingKeys.iterator();
+ while (it.hasNext()) {
+ String key = it.next();
+ String keyWithoutReturnType = key.substring(0, key.lastIndexOf(')') + 1);
+ if (keyWithoutReturnType.equals(roleMethodName + '.'
+ + signatureWithoutReturnType))
+ return true;
+ }
+ return false;
+ }
+
+ public Set<String> getRoleMethodSignatures() {
+ return roleMethodBindings.keySet();
+ }
+
+ /**
+ * @return
+ */
+ public BoundClass getRoleClass() {
+ return roleClass;
+ }
+
+ /**
+ * @return
+ */
+ public BoundClass getBaseClass() {
+ return baseClass;
+ }
+
+ /**
+ * @return
+ */
+ public String getRoleClassName() {
+ return roleClass.getName();
+ }
+
+ /**
+ * @return
+ */
+ public String getBaseClassName() {
+ return baseClass.getName();
+ }
+
+ /**
+ * Collect all base method signatures for this role-base pair.
+ * @result List <String[] {name, signature}>
+ */
+ public List<String[]> getBaseSignatures () {
+ List<String[]> result = new LinkedList<String[]>();
+ List<MethodBinding> baseMethodBindingList = getBaseMethodBindings();
+ Iterator<MethodBinding> it = baseMethodBindingList.iterator();
+ while (it.hasNext()) {
+ MethodBinding mb = it.next();
+ result.add(new String [] {
+ mb.getBaseMethodName(),
+ mb.getBaseMethodSignature()
+ });
+ }
+ return result;
+ }
+
+ /**
+ * @param rbb
+ * @return
+ */
+ public boolean equals(RoleBaseBinding rbb) {
+ return roleClass.getName().equals(rbb.getRoleClassName())
+ && baseClass.getName().equals(rbb.getBaseClassName());
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#toString()
+ */
+ public String toString() {
+ StringBuilder out = new StringBuilder(64);
+ out.append(roleClass.getName());
+ out.append(" <-> ");
+ out.append(baseClass.getName());
+ out.append("\nmethod bindings:\n");
+ List mbsList = getBaseMethodBindings();
+ Iterator it = mbsList.iterator();
+ while (it.hasNext()) {
+ MethodBinding mb = (MethodBinding)it.next();
+ out.append("\n");
+ out.append(mb.getBaseMethodName());
+ out.append(".");
+ out.append(mb.getBaseMethodSignature());
+ out.append(":");
+ out.append(mb.toString());
+ }
+ return out.toString();
+ }
+}
diff --git a/othersrc/OTRE/src/org/eclipse/objectteams/otre/util/SuperMethodDescriptor.java b/othersrc/OTRE/src/org/eclipse/objectteams/otre/util/SuperMethodDescriptor.java
new file mode 100644
index 0000000..02b9c04
--- /dev/null
+++ b/othersrc/OTRE/src/org/eclipse/objectteams/otre/util/SuperMethodDescriptor.java
@@ -0,0 +1,33 @@
+/**********************************************************************
+ * This file is part of the "Object Teams Runtime Environment"
+ *
+ * Copyright 2008 Technical University Berlin, 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: SuperMethodDescriptor.java 23408 2010-02-03 18:07:35Z stephan $
+ *
+ * Please visit http://www.objectteams.org for updates and contact.
+ *
+ * Contributors:
+ * Technical University Berlin - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.objectteams.otre.util;
+
+/** Representation of a base-super method call, requiring a special access method. */
+public class SuperMethodDescriptor {
+ public String methodName;
+ public String declaringClass;
+ public String superClass;
+ public String signature;
+ public SuperMethodDescriptor(String methodName, String declaringClass,
+ String superClass, String signature) {
+ super();
+ this.methodName = methodName;
+ this.declaringClass = declaringClass;
+ this.superClass = superClass;
+ this.signature = signature;
+ }
+}
diff --git a/othersrc/OTRE/src/org/eclipse/objectteams/otre/util/TeamIdDispenser.java b/othersrc/OTRE/src/org/eclipse/objectteams/otre/util/TeamIdDispenser.java
new file mode 100644
index 0000000..100a0a1
--- /dev/null
+++ b/othersrc/OTRE/src/org/eclipse/objectteams/otre/util/TeamIdDispenser.java
@@ -0,0 +1,69 @@
+/**********************************************************************
+ * 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: TeamIdDispenser.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.util;
+import java.util.*;
+
+public class TeamIdDispenser {
+
+ private static Map<ClassLoader, TeamIdDispenser> instances = new HashMap<ClassLoader, TeamIdDispenser>();
+ private static TeamIdDispenser defaultInstance = new TeamIdDispenser();
+
+ static int lastDispensedId = 0;
+ private static HashMap<String, Integer> teamIDs = new HashMap<String, Integer>();
+
+// @SuppressWarnings("unchecked")
+ private static int produceNextTeamId(String team_name) {
+ lastDispensedId++;
+ Integer teamId = Integer.valueOf(lastDispensedId);
+ teamIDs.put(team_name, teamId);
+ return lastDispensedId;
+ }
+
+ public static int getTeamId(String class_name) {
+ Integer teamId = teamIDs.get(class_name);
+ if (teamId != null)
+ // the team <class_name> already has a team-id assigned
+ return teamId.intValue();
+ else return produceNextTeamId(class_name);
+ }
+
+ // Data shared among different transformers of the same class loader:
+ // REFACTOR: move the following to a better place:
+ private ArrayList<String> clinitAddedClasses = new ArrayList<String>();
+ public static boolean clinitAdded(String class_name, ClassLoader loader) {
+ TeamIdDispenser instance = getInstanceForLoader(loader);
+ if (instance.clinitAddedClasses.contains(class_name))
+ return true;
+
+ instance.clinitAddedClasses.add(class_name);
+ return false;
+ }
+
+ /**
+ * Since actual data are stored in an instance, static methods need to retrieve the appropriate
+ * instance regarding the given class loader.
+ */
+ private static TeamIdDispenser getInstanceForLoader(ClassLoader loader) {
+ if (loader == null)
+ return defaultInstance;
+
+ TeamIdDispenser instance = instances.get(loader);
+ if (instance == null)
+ instances.put(loader, instance = new TeamIdDispenser());
+ return instance;
+ }
+}
diff --git a/othersrc/OTRE/src/org/objectteams/DoublyWeakHashMap.java b/othersrc/OTRE/src/org/objectteams/DoublyWeakHashMap.java
new file mode 100644
index 0000000..4b72f1e
--- /dev/null
+++ b/othersrc/OTRE/src/org/objectteams/DoublyWeakHashMap.java
@@ -0,0 +1,96 @@
+/**********************************************************************
+ * This file is part of the "Object Teams Runtime Environment"
+ *
+ * Copyright 2010 Stephan Herrmann.
+ *
+ * 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$
+ *
+ * Please visit http://www.eclipse.org/objectteams for updates and contact.
+ *
+ * Contributors:
+ * Stephan Herrmann - Initial API and implementation
+ **********************************************************************/
+package org.objectteams;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Map;
+import java.util.Set;
+import java.util.WeakHashMap;
+
+/**
+ * This class defines hash maps where both key and value are weak references.
+ * It is implemented by delegating to a WeakHashMap and additionally
+ * wrapping the value in a WeakReference.
+ *
+ * @author stephan
+ * @since 0.7.0
+ * @param <K>
+ * @param <V>
+ */
+public class DoublyWeakHashMap<K,V> implements Map<K,V> {
+
+ private WeakHashMap<K, WeakReference<V>> map;
+
+ public DoublyWeakHashMap() {
+ this.map = new WeakHashMap<K, WeakReference<V>>();
+ }
+ public int size() {
+ return this.map.size();
+ }
+
+ public boolean isEmpty() {
+ return this.map.isEmpty();
+ }
+
+ public boolean containsKey(Object key) {
+ return this.map.containsKey(key);
+ }
+
+ public boolean containsValue(Object value) {
+ return this.map.containsValue(value);
+ }
+
+ public V get(Object key) {
+ return this.map.get(key).get();
+ }
+
+ public V put(K key, V value) {
+ this.map.put(key, new WeakReference<V>(value));
+ return value;
+ }
+
+ public V remove(Object key) {
+ WeakReference<V> value = this.map.remove(key);
+ return (value == null) ? null : value.get();
+ }
+
+ public void putAll(Map<? extends K, ? extends V> t) {
+ for (Entry<? extends K, ? extends V> entry : t.entrySet())
+ this.map.put(entry.getKey(), new WeakReference<V>(entry.getValue()));
+ }
+
+ public void clear() {
+ this.map.clear();
+ }
+
+ public Set<K> keySet() {
+ return this.map.keySet();
+ }
+
+ public Collection<V> values() {
+ ArrayList<V> result = new ArrayList<V>(this.map.size());
+ for (WeakReference<V> valRef : this.map.values())
+ result.add(valRef.get());
+ return result;
+ }
+
+ public Set<java.util.Map.Entry<K, V>> entrySet() {
+ throw new UnsupportedFeatureException("Method entrySet is not implemented for DoublyWeakHashMap");
+ }
+}
diff --git a/othersrc/OTRE/src/org/objectteams/DuplicateRoleException.java b/othersrc/OTRE/src/org/objectteams/DuplicateRoleException.java
new file mode 100644
index 0000000..ae3e851
--- /dev/null
+++ b/othersrc/OTRE/src/org/objectteams/DuplicateRoleException.java
@@ -0,0 +1,48 @@
+/**********************************************************************
+ * This file is part of the "Object Teams Runtime Environment"
+ *
+ * Copyright 2004-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: DuplicateRoleException.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.objectteams;
+
+/**
+ * Signal a violation of OTJLD 2.4.1(c).
+ * Also Team.getRole(Object) may throw a DuplicateRoleException if
+ * more than one role is found for the given base object
+ * (in that case those roles are found in different role-caches).
+ *
+ *
+ * @author stephan
+ * @version $Id: DuplicateRoleException.java 23408 2010-02-03 18:07:35Z stephan $
+ */
+public class DuplicateRoleException extends RuntimeException {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * @param message
+ */
+ public DuplicateRoleException(String roleClassName) {
+ super("Failed to create a role instance of type "+roleClassName+"\n"+
+ "A role for the given base object already exists (OTJLD 2.4.1(c)).");
+ }
+
+ public DuplicateRoleException(String roleName1, String roleName2) {
+ super("Ambiguous role instances: found a role in hierarchies "+
+ roleName1+" and "+roleName2);
+ }
+}
diff --git a/othersrc/OTRE/src/org/objectteams/IBaseMigratable.java b/othersrc/OTRE/src/org/objectteams/IBaseMigratable.java
new file mode 100644
index 0000000..edc9202
--- /dev/null
+++ b/othersrc/OTRE/src/org/objectteams/IBaseMigratable.java
@@ -0,0 +1,35 @@
+/**********************************************************************
+ * This file is part of the "Object Teams Runtime Environment"
+ *
+ * Copyright 2008 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: IBaseMigratable.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.objectteams;
+
+/**
+ * Marker interface: if a role declares to implement this interface
+ * the compiler will generate the method defined herein, and prepare
+ * the role so that the migration will indeed be possible.
+ *
+ * @author stephan
+ * @since 1.2.5
+ */
+public interface IBaseMigratable {
+ /**
+ * Migrate the current role to the otherBase.
+ *
+ * @param otherBase new base that this role should adapt, must
+ * be of a valid base type for the current role.
+ */
+ <B> void migrateToBase(B otherBase);
+}
diff --git a/othersrc/OTRE/src/org/objectteams/IBoundBase.java b/othersrc/OTRE/src/org/objectteams/IBoundBase.java
new file mode 100644
index 0000000..9f196bf
--- /dev/null
+++ b/othersrc/OTRE/src/org/objectteams/IBoundBase.java
@@ -0,0 +1,28 @@
+/**********************************************************************
+ * This file is part of the "Object Teams Runtime Environment"
+ *
+ * Copyright 2007-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: IBoundBase.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.objectteams;
+
+/**
+ * Super type for all bound base classes. Purely internal class, not intended for client use.
+ * @author Stephan Herrmann
+ */
+public interface IBoundBase {
+ /** Method to be used by generated code, only (lifting constructor). */
+ void _OT$addRole(Object aRole);
+ /** Method to be used by generated code, only (unregisterRole()). */
+ void _OT$removeRole(Object aRole);
+}
\ No newline at end of file
diff --git a/othersrc/OTRE/src/org/objectteams/IConfined.java b/othersrc/OTRE/src/org/objectteams/IConfined.java
new file mode 100644
index 0000000..8ead4b4
--- /dev/null
+++ b/othersrc/OTRE/src/org/objectteams/IConfined.java
@@ -0,0 +1,24 @@
+/**********************************************************************
+ * This file is part of the "Object Teams Runtime Environment"
+ *
+ * Copyright 2004 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: IConfined.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.objectteams;
+
+/**
+ * Special interface that does not extend Object
+ *
+ * @author stephan
+ */
+public interface IConfined {}
\ No newline at end of file
diff --git a/othersrc/OTRE/src/org/objectteams/ILiftingParticipant.java b/othersrc/OTRE/src/org/objectteams/ILiftingParticipant.java
new file mode 100644
index 0000000..408d087
--- /dev/null
+++ b/othersrc/OTRE/src/org/objectteams/ILiftingParticipant.java
@@ -0,0 +1,40 @@
+/**********************************************************************
+ * This file is part of the "Object Teams Runtime Environment"
+ *
+ * Copyright 2009 Stephan Herrmann
+ *
+ * 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: ILiftingParticipant.java 23408 2010-02-03 18:07:35Z stephan $
+ *
+ * Please visit http://www.objectteams.org for updates and contact.
+ *
+ * Contributors:
+ * Stephan Herrmann - Initial API and implementation
+ **********************************************************************/
+package org.objectteams;
+
+/**
+ * A lifting participant hooks into the lifting process.
+ *
+ * @author stephan
+ * @since 1.3.1
+ */
+public interface ILiftingParticipant {
+ /**
+ * This method is called when lifting does not find a suitable role within the
+ * team's internal role cache. If this method returns a non-null value,
+ * this value is considered by the runtime as being the desired role
+ * (i.e., it must be castable to that role type), and no new role is created.
+ * If this method returns null, lifting proceeds as normal, i.e.,
+ * a fresh role is created using the default lifting constructor.
+ *
+ * @param teamInstance
+ * @param baseInstance
+ * @param roleClassName
+ * @return either null or an instance of the class specified by roleClassName
+ */
+ Object createRole(ITeam teamInstance, Object baseInstance, String roleClassName);
+}
diff --git a/othersrc/OTRE/src/org/objectteams/ITeam.java b/othersrc/OTRE/src/org/objectteams/ITeam.java
new file mode 100644
index 0000000..84b1cd0
--- /dev/null
+++ b/othersrc/OTRE/src/org/objectteams/ITeam.java
@@ -0,0 +1,204 @@
+/**********************************************************************
+ * This file is part of the "Object Teams Runtime Environment"
+ *
+ * Copyright 2010 Stephan Herrmann.
+ *
+ * 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: ITeam.java 23408 2010-02-03 18:07:35Z stephan $
+ *
+ * Please visit http://www.objectteams.org for updates and contact.
+ *
+ * Contributors:
+ * Stephan Herrmann - Initial API and implementation
+ **********************************************************************/
+package org.objectteams;
+
+/**
+ * Public interface of all team classes.
+ */
+public interface ITeam {
+
+ /**
+ * Interface for all role classes that should allow explicit lowering.
+ * The interface provides a phantom method <pre><B> B lower()</pre>
+ * where B is the bound base class of the implementing role class.
+ * There is no need to implement the method lower, since this is done by the compiler.
+ */
+ public interface ILowerable {
+ // internal method needed for cast and instanceof
+ ITeam _OT$getTeam();
+ }
+
+ /**
+ * This role interface has no properties not even those of java.lang.Object.
+ */
+ public interface IConfined extends org.objectteams.IConfined {
+ // internal method needed for cast and instanceof
+ ITeam _OT$getTeam();
+ }
+
+
+ /**
+ * Activates the team and therefore all of its callin bindings.
+ * This activation applies to the current thread only.
+ */
+ public abstract void activate();
+
+ /**
+ * Deactivates the team and therefore all of its callin bindings.
+ * This deactivation applies to the current thread only.
+ */
+ public abstract void deactivate();
+
+ /**
+ * Activates the team and therefore all of its callin bindings for passed thread.
+ * If the constant 'Team.ALL_THREADS' is passed, this activation globally applies to all threads.
+ */
+ public abstract void activate(Thread thread);
+
+ /**
+ * Deactivates the team and therefore all of its callin bindings for passed thread.
+ * If the constant 'Team.ALL_THREADS' is passed, this deactivation globally applies to all threads.
+ */
+ public abstract void deactivate(Thread thread);
+
+ /**
+ * Checks, if the team instance is active for the current thread.
+ * @return true, if the team is active, false else.
+ */
+ public abstract boolean isActive();
+
+ /**
+ * Checks, if the team instance is active for the 'thread'.
+ * @param thread The thread for which to check activity.
+ * @return true, if the team is active for 'thread', false else.
+ */
+ public abstract boolean isActive(Thread thread);
+
+ /**
+ * Does given base object have a role in this team?
+ * This method will consider roles of any type.
+ *
+ * @param aBase any object, i.e., no checks are performed whether the base object's
+ * class is bound by any role class in this team.
+ * @return
+ */
+ public abstract boolean hasRole(Object aBase);
+
+ /**
+ * Does given base object have a role in this team?
+ * The role must be an instance of the specified role type.
+ *
+ * @param aBase any object, i.e., no checks are performed whether the base object's
+ * class is bound by any role class in this team.
+ * @param roleClass Class instance specifying the required role type.
+ * If this does not specify an existing role class an IllegalArgumentException will be thrown.
+ * TODO (SH): is it legal to pass an unbound role class?
+ * @return
+ */
+ public abstract boolean hasRole(Object aBase, Class<?> roleType);
+
+ /**
+ * Retrieve a role for a given base object.
+ * If more than one role exists, a DuplicateRoleException is thrown.
+ *
+ * @param aBase
+ * @return
+ */
+ public abstract Object getRole(Object aBase);
+
+ /**
+ * Retrieve a role for a given base object.
+ * The role must be an instance of the specified role type.
+ *
+ * @param aBase any object, i.e., no checks are performed whether the base object's
+ * class is bound by any role class in this team.
+ * @param roleClass Class instance specifying the required role type.
+ * If this does not specify an existing role class an IllegalArgumentException will be thrown.
+ * @return
+ */
+ public abstract <T> T getRole(Object aBase, Class<T> roleType);
+
+ /**
+ * Retrieve all bound roles registered in the current team.
+ *
+ * This method uses internal structures of weak references.
+ * For that reason it may return role instances which were about to be reclaimed
+ * by the garbage collector.
+ * If performance permits, it is thus advisable to always call System.gc()
+ * prior to calling getAllRoles() in order to achieve deterministic results
+ *
+ * @return a non-null array.
+ */
+ public abstract Object[] getAllRoles();
+
+ /**
+ * Retrieve all bound roles registered in the current team that
+ * are instance of roleType or a subtype thereof.
+ *
+ * This method uses internal structures of weak references.
+ * For that reason it may return role instances which were about to be reclaimed
+ * by the garbage collector.
+ * If performance permits, it is thus advisable to always call System.gc()
+ * prior to calling getAllRoles() in order to achieve deterministic results
+ *
+ * @param roleType must be a top-most bound role of this team.
+ * @return a non-null array.
+ */
+ public abstract <T> T[] getAllRoles(Class<T> roleType);
+
+ /**
+ * Query whether any role instance of this team instance is currently executing a
+ * method due to a callin binding.
+ * @return
+ */
+ public abstract boolean isExecutingCallin();
+
+ /**
+ * Remove a role from the internal registry, which means that the role will no longer be
+ * considered during lifting.
+ *
+ * @param aRole
+ */
+ public abstract void unregisterRole(Object aRole);
+
+ /**
+ * Remove a role from the internal registry, which means that the role will no longer be
+ * considered during lifting.
+ *
+ * @param aRole
+ * @param roleType
+ */
+ public abstract void unregisterRole(Object aRole, Class<?> roleType);
+
+ /**
+ * Not API.
+ * This method saves the activation state of the team for the current thread.
+ * If active, it also saves, if the activation was explicit or implicit.
+ * This method has to be called by the generated code when entering a within block,
+ * before the activation.
+ */
+ public int _OT$saveActivationState();
+
+ /**
+ * Not API.
+ * This method restores the former saved activation state of the team for the current thread.
+ * If active, it also restores, if the activation was explicit or implicit.
+ * This method has to be called by the generated code when leaving a within block
+ * (in the finally block).
+ */
+ public void _OT$restoreActivationState(int old_state);
+
+ /**
+ * Not API, for use by TeamThreadManager, only.
+ */
+ public boolean internalIsActiveSpecificallyFor(Thread t);
+
+ /**
+ * Not API, for use by TeamThreadManager, only.
+ */
+ public void deactivateForEndedThread(Thread thread);
+}
\ No newline at end of file
diff --git a/othersrc/OTRE/src/org/objectteams/ITeamMigratable.java b/othersrc/OTRE/src/org/objectteams/ITeamMigratable.java
new file mode 100644
index 0000000..39be566
--- /dev/null
+++ b/othersrc/OTRE/src/org/objectteams/ITeamMigratable.java
@@ -0,0 +1,36 @@
+/**********************************************************************
+ * This file is part of the "Object Teams Runtime Environment"
+ *
+ * Copyright 2008 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: ITeamMigratable.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.objectteams;
+
+/**
+ * Marker interface: if a role declares to implement this interface
+ * the compiler will generate the method defined herein, and prepare
+ * the role so that the migration will indeed be possible.
+ * Note, that a migratable role does not obey the family guarantee.
+ *
+ * @author stephan
+ * @since 1.2.5
+ */
+public interface ITeamMigratable {
+ /**
+ * Migrate the current role to the otherTeam.
+ *
+ * @param otherTeam new team that should adopt this role
+ * @return the migrated (and re-typed) role (actually of type R<@otherTeam>). FIXME(SH)
+ */
+ <R> R migrateToTeam(final ITeam otherTeam);
+}
diff --git a/othersrc/OTRE/src/org/objectteams/IllegalRoleCreationException.java b/othersrc/OTRE/src/org/objectteams/IllegalRoleCreationException.java
new file mode 100644
index 0000000..f745d73
--- /dev/null
+++ b/othersrc/OTRE/src/org/objectteams/IllegalRoleCreationException.java
@@ -0,0 +1,35 @@
+/**********************************************************************
+ * This file is part of the "Object Teams Runtime Environment"
+ *
+ * Copyright 2007-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: IllegalRoleCreationException.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.objectteams;
+
+/**
+ * Exception to be thrown when a bound role is being instantiated but
+ * the constructor does not assign a base object.
+ *
+ * @author stephan
+ */
+@SuppressWarnings("serial")
+public class IllegalRoleCreationException extends RuntimeException {
+ public IllegalRoleCreationException() {
+ super();
+ }
+
+ @Override
+ public String getMessage() {
+ return "Cannot instantiate a bound role using a default constructor of its tsuper class";
+ }
+}
diff --git a/othersrc/OTRE/src/org/objectteams/ImplicitTeamActivation.java b/othersrc/OTRE/src/org/objectteams/ImplicitTeamActivation.java
new file mode 100644
index 0000000..09eda96
--- /dev/null
+++ b/othersrc/OTRE/src/org/objectteams/ImplicitTeamActivation.java
@@ -0,0 +1,45 @@
+/**********************************************************************
+ * This file is part of the "Object Teams Runtime Environment"
+ *
+ * Copyright 2009 Stephan Herrmann
+ *
+ * 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$
+ *
+ * Please visit http://www.objectteams.org for updates and contact.
+ *
+ * Contributors:
+ * Stephan Herrmann - Initial API and implementation
+ **********************************************************************/
+package org.objectteams;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * This marker annotation enables implicit team activation for the annotated element:
+ * <ul>
+ * <li>If attached to a method the effect is that each call to this method implicitly
+ * activates the enclosing team.</li>
+ * <li>If attached to a class it has the same effect as annotating all contained methods.</li>
+ * </ul>
+ * See <a href="http://www.objectteams.org/def/1.3/s5.html#s5.3">OTJLD § 5.3</a>.
+ * <p>
+ * This annotation is only evaluated if the property <code>ot.implicit.team.activation</code>
+ * is set to the string <code>ANNOTATED</code>.
+ * </p>
+ * @author stephan
+ * @since 1.4.0
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD, ElementType.TYPE})
+public @interface ImplicitTeamActivation {
+ /* no members, pure marker annotation. */
+}
diff --git a/othersrc/OTRE/src/org/objectteams/LiftingFailedException.java b/othersrc/OTRE/src/org/objectteams/LiftingFailedException.java
new file mode 100644
index 0000000..99f2dd2
--- /dev/null
+++ b/othersrc/OTRE/src/org/objectteams/LiftingFailedException.java
@@ -0,0 +1,46 @@
+/**********************************************************************
+ * This file is part of the "Object Teams Runtime Environment"
+ *
+ * Copyright 2003-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: LiftingFailedException.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.objectteams;
+
+/**
+ * This exception signals that lifting failed due to unresolved
+ * binding ambiguity.
+ */
+public class LiftingFailedException extends RuntimeException {
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+ private Object base;
+ private String roleType;
+
+ /**
+ * @param base the object that should be lifted
+ * @param roleType the name of the role type for which
+ * lifting was attempted.
+ */
+ public LiftingFailedException(Object base, String roleType) {
+ this.base = base;
+ this.roleType = roleType;
+ }
+
+ public String getMessage() {
+ return "\nFailed to lift '" + base + "' of " + base.getClass()
+ + " to type '" + roleType
+ + "'\n(See OT/J definition para. 2.3.4(c)).";
+ }
+}
diff --git a/othersrc/OTRE/src/org/objectteams/LiftingVetoException.java b/othersrc/OTRE/src/org/objectteams/LiftingVetoException.java
new file mode 100644
index 0000000..3a9b83a
--- /dev/null
+++ b/othersrc/OTRE/src/org/objectteams/LiftingVetoException.java
@@ -0,0 +1,45 @@
+/**********************************************************************
+ * This file is part of the "Object Teams Runtime Environment"
+ *
+ * Copyright 2003-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: LiftingVetoException.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.objectteams;
+
+/**
+ * This exception is used by the language implementation
+ * to signal a failed lifting due to a guard predicate that evaluated to false.
+ * @author Stephan Herrmann
+ */
+public class LiftingVetoException extends RuntimeException {
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+ ITeam aTeam = null;
+ Object base = null;
+
+ public LiftingVetoException(ITeam aTeam, Object base) {
+ this.aTeam = aTeam;
+ this.base = base;
+ }
+
+ public LiftingVetoException() {
+ super("");
+ }
+
+ public String toString() {
+ return "Team " + aTeam + " refuses to lift " + base
+ + "\n(this exception should not be seen in applications).";
+ }
+}
diff --git a/othersrc/OTRE/src/org/objectteams/ResultNotProvidedException.java b/othersrc/OTRE/src/org/objectteams/ResultNotProvidedException.java
new file mode 100644
index 0000000..b6baccb
--- /dev/null
+++ b/othersrc/OTRE/src/org/objectteams/ResultNotProvidedException.java
@@ -0,0 +1,61 @@
+/**********************************************************************
+ * This file is part of the "Object Teams Runtime Environment"
+ *
+ * Copyright 2004-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: ResultNotProvidedException.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.objectteams;
+
+/**
+ * @author resix
+ */
+public class ResultNotProvidedException extends RuntimeException {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+ private static final String _bugmsg =
+ "\nNo base call executed! Result value was uninitialized!\n(see OT/J language definition para. 4.3(e)).";
+
+ /**
+ *
+ */
+ public ResultNotProvidedException() {
+ super(_bugmsg);
+ }
+
+ /**
+ * @param message
+ */
+ public ResultNotProvidedException(String message) {
+ super(_bugmsg + "\n" + message);
+ StackTraceElement[] ste = new StackTraceElement[0];
+ setStackTrace(ste);
+ }
+
+ /**
+ * @param cause
+ */
+ public ResultNotProvidedException(Throwable cause) {
+ super(_bugmsg + cause.toString());
+ }
+
+ /**
+ * @param message
+ * @param cause
+ */
+ public ResultNotProvidedException(String message, Throwable cause) {
+ super(_bugmsg + message/* +cause.toString() */);
+ }
+}
diff --git a/othersrc/OTRE/src/org/objectteams/RoleCastException.java b/othersrc/OTRE/src/org/objectteams/RoleCastException.java
new file mode 100644
index 0000000..f6608c9
--- /dev/null
+++ b/othersrc/OTRE/src/org/objectteams/RoleCastException.java
@@ -0,0 +1,39 @@
+/**********************************************************************
+ * This file is part of the "Object Teams Runtime Environment"
+ *
+ * Copyright 2004-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: RoleCastException.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.objectteams;
+
+/**
+ * This exception is thrown if a cast to a role class fails due to
+ * different enclosing team instances.
+ * @author Stephan Herrmann
+ */
+public class RoleCastException extends ClassCastException {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+ private static final String MSG =
+ "Different enclosing team instances (see OT/J language definition para. 1.2.4(b)).";
+
+ /* (non-Javadoc)
+ * @see java.lang.Throwable#getMessage()
+ */
+ public String getMessage() {
+ return MSG;
+ }
+}
\ No newline at end of file
diff --git a/othersrc/OTRE/src/org/objectteams/Team.java b/othersrc/OTRE/src/org/objectteams/Team.java
new file mode 100644
index 0000000..c6c5f33
--- /dev/null
+++ b/othersrc/OTRE/src/org/objectteams/Team.java
@@ -0,0 +1,490 @@
+/**********************************************************************
+ * This file is part of the "Object Teams Runtime Environment"
+ *
+ * Copyright 2002-2007 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: Team.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.objectteams;
+
+import java.awt.EventQueue;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.WeakHashMap;
+
+/**
+ * This is the root class of all team definitions.
+ * Any class with the <tt>team</tt> modifier implicitly
+ * inherits from this class.
+ *
+ */
+public /* team */ class Team implements ITeam {
+ // Technical note: comments starting with //$Debug are intended
+ // for a standalone tool that generates an interface
+ // which the debugger needs in order to know about line numbers in this class.
+
+ /*
+ * Synchronization: This class supports two levels of synchronization:
+ * <ul>
+ * <li>Fields of <code>Team</code> are synchronized
+ * using <code>this</code> as the monitor.
+ * <li>Those calls that (un)register a team at its base classes are synchronized
+ * via <code>registrationLock</code>
+ * </ul>
+ * This allows releasing the lock on <code>this</code> before calling to the base class.
+ * Note, that the synchronized portion of each initial-wrapper is also synchronized
+ * (against <code>_OT$addTeam/_OT$removeTeam</code>) and that it calls back to
+ * the registered teams (method <code>isActive()</code>).
+ * Without <code>registrationLock</code> this situation could easily deadlock:
+ * Thread1: <pre>t.activate() -> Base._OT$addTeam()</pre>: owns t, waits for Base.
+ * Thread2: <pre>b.bm() (initial wrapper) -> t.isActive()</pre>: owns Base, waits for t.
+ */
+
+ /**
+ * Internal field used by the runtime to install a lifting participant if one is configured.
+ */
+ public static ILiftingParticipant _OT$liftingParticipant = null;
+
+ /**
+ * Default constructor for debugging purpose.
+ */
+ public Team() {} //$Debug(TeamConstructor)
+
+ /*
+ * manual copy-inheritance of a role interface from ITeam.
+ */
+ public interface ILowerable extends ITeam.ILowerable {}
+
+ /*
+ * manual copy-inheritance of a role interface from ITeam.
+ */
+ public interface IConfined extends ITeam.IConfined {}
+
+ /**
+ * Special role type that<ul>
+ * <li> does not extend java.lang.Object
+ * <li> may not leak references outside the team.
+ * </ul>
+ */
+ protected interface Confined {
+ /* internal method needed for cast and instanceof
+ * (this method will be generated for role classes) */
+ ITeam _OT$getTeam();
+ }
+
+ /**
+ * This class would have been generated by the OT-compiler.
+ * Don't explicitly use it in client code!
+ */
+ protected class __OT__Confined implements Confined {
+ // internal method needed for cast and instanceof
+ public ITeam _OT$getTeam() {
+ return Team.this; //$Debug(ConfinedGetTeam)
+ }
+ }
+
+ /**
+ * Internal function for identifying a Team.
+ * Should not be called by client code.
+ */
+ public int _OT$getID () {return -1;}
+
+ /**
+ * The constant <code>ALL_THREADS</code> is used for global team (de-)activation.
+ */
+ public static final Thread ALL_THREADS = new Thread();
+
+ private static final int _OT$UNREGISTERED = 0;
+ private static final int _OT$REGISTERED = 1;
+ private int _OT$registrationState = _OT$UNREGISTERED;
+
+ private boolean _OT$globalActive = false;
+
+ private ThreadLocal<Integer> _OT$implicitActivationsPerThread = new ThreadLocal<Integer>() {
+ protected synchronized Integer initialValue() {
+ return Integer.valueOf(0);
+ }
+ };
+
+ private boolean _OT$lazyGlobalActiveFlag = false;
+
+ /**
+ * <code>_OT$activatedThreads</code> contains all threads for which this team instance is active.
+ * key = activated thread
+ * value = Boolean(true) for explicit activation | Boolean(false) for implicit activation.
+ */
+ private WeakHashMap<Thread, Boolean> _OT$activatedThreads = new WeakHashMap<Thread, Boolean>();
+
+ /** This lock is used to protect activate/deactivate methods <strong>including</strong>
+ * the calls to doRegistration/doUnregistration.
+ */
+ private Object _OT$registrationLock= new Object();
+
+ /**
+ * {@inheritDoc}
+ */
+ public void activate() {
+ activate(Thread.currentThread());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void deactivate() {
+ deactivate(Thread.currentThread());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void activate(Thread thread) {
+ // acquire both locks to avoid incomplete execution:
+ synchronized (this._OT$registrationLock) {
+ synchronized (this) {
+ if (thread.equals(ALL_THREADS)) {
+ _OT$globalActive = true;
+ _OT$lazyGlobalActiveFlag = true;
+ TeamThreadManager.addGlobalActiveTeam(this);
+ } else { // activation only for 'thread':
+ // register 'thread' as active:
+ _OT$activatedThreads.put(thread, Boolean.TRUE);
+ }
+ } // release this before calling synchronized base class methods
+ doRegistration(); //$Debug(ActivateMethod)
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void deactivate(Thread thread) {
+ // acquire both locks to avoid incomplete execution:
+ synchronized (this._OT$registrationLock) {
+ boolean shouldUnregister= false;
+ synchronized(this) {
+ if (_OT$globalActive && EventQueue.isDispatchThread()) {
+ System.err.println("Warning: Deactivation for the AWT-Event-Thread is not effective right now!");
+ }
+ if (thread.equals(ALL_THREADS)) {
+ _OT$globalActive = false;
+ TeamThreadManager.removeGlobalActiveTeam(this);
+ // unregister all threads:
+ _OT$activatedThreads.clear();
+ shouldUnregister= true;
+ } else { // deactivation only for 'thread':
+ if (_OT$lazyGlobalActiveFlag) {
+ // be eager now: activate for all (other) threads:
+ _OT$activateForAllThreads();
+ }
+ // deactivate for 'thread', no longer active:
+ _OT$activatedThreads.remove(thread);
+ if (!_OT$lazyGlobalActiveFlag && _OT$activatedThreads.isEmpty()) {
+ shouldUnregister= true;
+ }
+ }
+ _OT$lazyGlobalActiveFlag = false;
+ } // release this before calling synchronized base class methods
+ if (shouldUnregister) //$Debug(DeactivateMethod)
+ doUnregistration();
+ }
+ }
+
+ public void deactivateForEndedThread(Thread thread) {
+ synchronized (_OT$registrationLock) {
+ boolean shouldUnregister= false;
+ synchronized (this) {
+ _OT$activatedThreads.remove(thread);
+ if (!_OT$lazyGlobalActiveFlag && _OT$activatedThreads.isEmpty())
+ shouldUnregister= true;
+ }
+ if (shouldUnregister)
+ doUnregistration();
+ }
+ }
+
+ private void _OT$activateForAllThreads() {
+ HashSet threads = TeamThreadManager.getExistingThreads();
+ Iterator it = threads.iterator();
+ while (it.hasNext()) {
+ Thread a_thread = (Thread) it.next();
+ activate(a_thread); // use smaller activate version (no ALL_THREADS, no registerAtBases,...
+ }
+ }
+
+ /**
+ * This method is used for implicit activation in team-level methods.
+ * Implicit activation only applies to the current thread.
+ * Don't call it from client code.
+ */
+ public void _OT$implicitlyActivate() {
+ synchronized (this._OT$registrationLock) {
+ boolean shouldRegister= false;
+ synchronized (this) {
+ // this method is used for debugging purpose (team monitor)
+ Thread currentThread = Thread.currentThread();
+ if (!_OT$activatedThreads.containsKey(currentThread)) {
+ // register 'thread' as active:
+ _OT$activatedThreads.put(currentThread, Boolean.FALSE);
+ shouldRegister= true;
+ }
+ // increment thread local implicit activaion counter:
+ int implActCount = (_OT$implicitActivationsPerThread.get()).intValue();
+ _OT$implicitActivationsPerThread.set(Integer.valueOf(implActCount + 1 ));
+ }
+ if (shouldRegister) //$Debug(ImplicitActivateMethod)
+ doRegistration();
+ }
+ }
+
+ /**
+ * This method is used for implicitly deactivation in team-level methods.
+ * It respects explicit activation changes and nested calls to team-level methods.
+ * Implicit deactivation only applies to the current thread.
+ * Don't call it from client code.
+ */
+ public void _OT$implicitlyDeactivate() {
+ synchronized (this._OT$registrationLock) {
+ boolean shouldUnregister= false;
+ synchronized(this) {
+ // this method is used for debugging purpose (team monitor)
+ Thread currentThread = Thread.currentThread();
+ boolean explicitlyActivated = false;
+ if (_OT$activatedThreads.containsKey(currentThread)) {
+ explicitlyActivated = ((Boolean) _OT$activatedThreads.get(currentThread)).booleanValue();
+ }
+ if (!explicitlyActivated
+ && !_OT$lazyGlobalActiveFlag // no explicit activation overriding the implicit one
+ && ((_OT$implicitActivationsPerThread.get()).intValue() == 1)) // this is the last implicit activation
+ {
+ _OT$activatedThreads.remove(currentThread);
+ if (_OT$activatedThreads.isEmpty()) // there are not other threads for which this theam is active
+ {
+ shouldUnregister= true;
+ }
+ }
+ // decrement thread local implicit activaion counter:
+ int implActCount = (_OT$implicitActivationsPerThread.get()).intValue();
+ _OT$implicitActivationsPerThread.set(Integer.valueOf(implActCount - 1));
+ }
+ if (shouldUnregister) //$Debug(ImplicitDeactivateMethod)
+ doUnregistration();
+ }
+ }
+
+ /**
+ * Define whether per-thread activation of this team should be inheritable
+ * such that the team will be activated automatically for any new threads
+ * that are spawned from a thread for which the team is already active at that time.
+ *
+ * @param inheritable whether or not activation should be inheritable to new threads
+ */
+ public void setInheritableActivation(boolean inheritable) {
+ if (inheritable)
+ TeamThreadManager.registerTeamForActivationInheritance(this);
+ else
+ TeamThreadManager.unRegisterTeamForActivationInheritance(this);
+ }
+
+ // not API (for use by the TeamThreadManager)
+ public boolean internalIsActiveSpecificallyFor(Thread t) {
+ return this._OT$activatedThreads.containsKey(t);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isActive() {
+ return isActive(Thread.currentThread());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isActive(Thread thread) {
+ if (_OT$globalActive && EventQueue.isDispatchThread())
+ return true;
+ if (thread.equals(ALL_THREADS)) {
+ return _OT$globalActive;
+ }
+ if (_OT$lazyGlobalActiveFlag) {
+ return true;
+ } else {
+ //if (!TeamThreadManager.getExistingThreads().contains(thread)) { // this thread is already finished!
+ if (!thread.isAlive()) { // this thread is already finished!
+ throw new IllegalThreadStateException("Called 'isActive(...)' for a thread which is no longer running!");
+ }
+ return _OT$activatedThreads.containsKey(thread);
+ }
+ }
+
+// ***** for restoring the activation state after a within block: ---->*****
+ private static final int _OT$INACTIVE = 0;
+ private static final int _OT$IMPLICIT_ACTIVE = 1;
+ private static final int _OT$EXPLICIT_ACTIVE = 2;
+
+ /**
+ * {@inheritDoc}
+ */
+ public synchronized int _OT$saveActivationState() {
+ int old_state = _OT$INACTIVE;
+ if (_OT$lazyGlobalActiveFlag) {
+ old_state = _OT$EXPLICIT_ACTIVE;
+ } else {
+ Thread current_thread = Thread.currentThread();
+ if (_OT$activatedThreads.containsKey(current_thread)) {
+ old_state = _OT$IMPLICIT_ACTIVE;
+ if (((Boolean)_OT$activatedThreads.get(current_thread)).booleanValue()) {
+ old_state = _OT$EXPLICIT_ACTIVE;
+ }
+ }
+ }
+ return old_state;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void _OT$restoreActivationState(int old_state) {
+ synchronized (_OT$registrationLock) {
+ if (old_state == _OT$INACTIVE) // team was inactive before:
+ deactivate();
+ else { // team was active before: has to be reactivated:
+ boolean explicit = (old_state == _OT$EXPLICIT_ACTIVE);
+ synchronized (this) {
+ _OT$activatedThreads.put(Thread.currentThread(), Boolean.valueOf(explicit));
+ }
+ doRegistration();
+ }
+ }
+ }
+// ***** <----for restoring the activation state after a within block. *****
+
+
+ private void doRegistration() {
+ if (_OT$registrationState == _OT$UNREGISTERED) {
+ _OT$registerAtBases();
+ _OT$registrationState = _OT$REGISTERED;
+ }
+ }
+
+ private void doUnregistration() {
+ if (_OT$registrationState == _OT$REGISTERED) {
+ _OT$unregisterFromBases();
+ _OT$registrationState = _OT$UNREGISTERED;
+ }
+ }
+
+ /**
+ * This method will be implemented by generated code in subteams.
+ * It registers the team at every base playing one of its roles.
+ * Don't call it from client code.
+ */
+ public void _OT$registerAtBases() {}
+
+ /**
+ * This method will be implemented by generated code in subteams.
+ * It unregisters the team from every base playing one of its roles.
+ * Don't call it from client code.
+ */
+ public void _OT$unregisterFromBases() {}
+
+ //public int _OT$activationState = -1; // TODO: remove usage of this from generated code
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean hasRole(Object aBase) {
+ // overriding method to be generated by the compiler for each team with bound roles.
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean hasRole(Object aBase, Class<?> roleType) {
+ // overriding method to be generated by the compiler for each team with bound roles.
+ throw new IllegalArgumentException("No such bound role type in this team: "+roleType.getName());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Object getRole(Object aBase) {
+ // overriding method to be generated by the compiler for each team with bound roles.
+ return null;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public <T> T getRole(Object aBase, Class<T> roleType) {
+ // overriding method to be generated by the compiler for each team with bound roles.
+ return null;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Object[] getAllRoles() {
+ // overriding method to be generated by the compiler for each team with bound roles.
+ return new Object[0];
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public <T> T[] getAllRoles(Class<T> roleType) {
+ // overriding method to be generated by the compiler for each team with bound roles.
+ throw new IllegalArgumentException("Class org.objectteams.Team has no bound roles.");
+ }
+
+ /** Internal variable to be set from generated code. */
+ private boolean _OT$isExecutingCallin = false;
+
+ /**
+ * Method only for internal use by generated code.
+ */
+ public boolean _OT$setExecutingCallin(boolean newFlag) {
+ boolean oldVal = _OT$isExecutingCallin;
+ _OT$isExecutingCallin = newFlag;
+ return oldVal;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isExecutingCallin() {
+ return _OT$isExecutingCallin;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void unregisterRole(Object aRole) {
+ // overriding method to be generated by the compiler for each team with bound roles.
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void unregisterRole(Object aRole, Class<?> roleType) {
+ // overriding method to be generated by the compiler for each team with bound roles.
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ // nop, hook for the debugger
+ @SuppressWarnings("unused")
+ int i= 2+3; // Note: body must not be empty for debuggger to be able to stop.
+ } // $Debug(FinalizeMethod)
+}
diff --git a/othersrc/OTRE/src/org/objectteams/TeamThreadManager.java b/othersrc/OTRE/src/org/objectteams/TeamThreadManager.java
new file mode 100644
index 0000000..ce1b174
--- /dev/null
+++ b/othersrc/OTRE/src/org/objectteams/TeamThreadManager.java
@@ -0,0 +1,97 @@
+/**********************************************************************
+ * This file is part of the "Object Teams Runtime Environment"
+ *
+ * Copyright 2006-2008 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: TeamThreadManager.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.objectteams;
+
+import java.util.HashSet;
+import java.util.WeakHashMap;
+
+
+/**
+ * This class is for internal use, only.
+ *
+ * Maintain information about existing threads as to manage
+ * team activation per thread vs. globally.
+ *
+ * @author Chistine Hundt
+ * @author Stephan Herrmann
+ */
+public class TeamThreadManager {
+
+ private static Object token = new Object();
+
+ private static HashSet<ITeam> globalActiveTeams = new HashSet<ITeam>();
+ private static WeakHashMap<ITeam,Object> teamsWithActivationInheritance = new WeakHashMap<ITeam,Object>();
+ private static HashSet<Thread> existingThreads = new HashSet<Thread>();
+
+ public static boolean newThreadStarted(boolean isMain, Thread parent) {
+ if (!isMain && (new Exception().getStackTrace().length > 3))
+ return false;
+ // workaround for application hang on Mac OS with Apple JVM:
+ Thread currentThread = Thread.currentThread();
+ if (System.getProperty("os.name").startsWith("Mac"))
+ if (currentThread.getName().equals("AWT-Shutdown"))
+ return false;
+
+ ITeam[] globalTeams;
+ ITeam[] inheritableTeams;
+ synchronized (TeamThreadManager.class) {
+ existingThreads.add(currentThread);
+
+ globalTeams = globalActiveTeams.toArray(new ITeam[globalActiveTeams.size()]);
+ inheritableTeams = teamsWithActivationInheritance.keySet().toArray(new ITeam[teamsWithActivationInheritance.size()]);
+ }
+ // activate teams outside synchronized block:
+ for (ITeam t : globalTeams)
+ t.activate(currentThread); // small version? global -> already registered...!
+ if (parent != null)
+ for (ITeam t : inheritableTeams)
+ if (t.internalIsActiveSpecificallyFor(parent))
+ t.activate(currentThread); // pass activation from parent to child thread
+ return true;
+ }
+ public static void threadEnded() {
+ ITeam[] teamsToDeactivate = internalThreadEnded();
+ // + remove per thread activation:
+ for (ITeam t : teamsToDeactivate)
+ //t.deactivate(Thread.currentThread()); // small version?
+ t.deactivateForEndedThread(Thread.currentThread());
+ }
+ private synchronized static ITeam[] internalThreadEnded() {
+ existingThreads.remove(Thread.currentThread());
+ // fetch all global active teams for deactivation:
+ return globalActiveTeams.toArray(new ITeam[globalActiveTeams.size()]);
+ }
+
+ public synchronized static void addGlobalActiveTeam(ITeam t) {
+ globalActiveTeams.add(t);
+ }
+
+ public synchronized static void removeGlobalActiveTeam(ITeam t) {
+ globalActiveTeams.remove(t);
+ }
+
+ public static HashSet<Thread> getExistingThreads() {
+ return existingThreads;
+ }
+ public static void registerTeamForActivationInheritance(ITeam aTeam) {
+ teamsWithActivationInheritance.put(aTeam,token);
+ }
+ public static void unRegisterTeamForActivationInheritance(ITeam aTeam) {
+ teamsWithActivationInheritance.remove(aTeam);
+ }
+
+}
diff --git a/othersrc/OTRE/src/org/objectteams/UnsupportedFeatureException.java b/othersrc/OTRE/src/org/objectteams/UnsupportedFeatureException.java
new file mode 100644
index 0000000..9b1c1ff
--- /dev/null
+++ b/othersrc/OTRE/src/org/objectteams/UnsupportedFeatureException.java
@@ -0,0 +1,60 @@
+/**********************************************************************
+ * This file is part of the "Object Teams Runtime Environment"
+ *
+ * Copyright 2004-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: UnsupportedFeatureException.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.objectteams;
+
+/**
+ * @author resix
+ */
+public class UnsupportedFeatureException extends RuntimeException {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+ private static final String _bugmsg = "\nThe program encountered an unsupported situation! ";
+
+ /**
+ *
+ */
+ public UnsupportedFeatureException() {
+ super(_bugmsg);
+ }
+
+ /**
+ * @param message
+ */
+ public UnsupportedFeatureException(String message) {
+ super(_bugmsg + "\n" + message);
+ StackTraceElement[] ste = new StackTraceElement[0];
+ setStackTrace(ste);
+ }
+
+ /**
+ * @param cause
+ */
+ public UnsupportedFeatureException(Throwable cause) {
+ super(_bugmsg + cause.toString());
+ }
+
+ /**
+ * @param message