Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStephan Herrmann2013-01-22 19:54:18 +0000
committerStephan Herrmann2013-01-22 20:06:37 +0000
commitd3be838278c26528c9a13b7d11e9d90d4629b8ca (patch)
treee6894f43f6f1ec0b04de5e26b0cfc438649f2512
parentcd75d9a352bc53c7bd43d693d1ed6f5249f544ec (diff)
downloadorg.eclipse.objectteams-d3be838278c26528c9a13b7d11e9d90d4629b8ca.tar.gz
org.eclipse.objectteams-d3be838278c26528c9a13b7d11e9d90d4629b8ca.tar.xz
org.eclipse.objectteams-d3be838278c26528c9a13b7d11e9d90d4629b8ca.zip
Initial commit of Object Teams Dynamic Runtime Environment
in accordance with CQ 7018.
-rw-r--r--plugins/org.eclipse.objectteams.otredyn/.classpath7
-rw-r--r--plugins/org.eclipse.objectteams.otredyn/.project28
-rw-r--r--plugins/org.eclipse.objectteams.otredyn/.settings/org.eclipse.jdt.core.prefs79
-rw-r--r--plugins/org.eclipse.objectteams.otredyn/META-INF/MANIFEST.MF18
-rw-r--r--plugins/org.eclipse.objectteams.otredyn/build.properties4
-rw-r--r--plugins/org.eclipse.objectteams.otredyn/plugin.properties2
-rw-r--r--plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/AbstractBoundClass.java1036
-rw-r--r--plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/AbstractTeam.java76
-rw-r--r--plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/Binding.java165
-rw-r--r--plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/BytecodeProviderFactory.java35
-rw-r--r--plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/ClassRepository.java193
-rw-r--r--plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/Field.java46
-rw-r--r--plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/IBytecodeProvider.java43
-rw-r--r--plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/IRedefineStrategy.java35
-rw-r--r--plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/InMemoryBytecodeProvider.java51
-rw-r--r--plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/Member.java95
-rw-r--r--plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/Method.java64
-rw-r--r--plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/OtreRedefineStrategy.java36
-rw-r--r--plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/RedefineStrategyFactory.java37
-rw-r--r--plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/Types.java139
-rw-r--r--plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/AbstractCreateDispatchCodeAdapter.java154
-rw-r--r--plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/AbstractTransformableClassNode.java272
-rw-r--r--plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/AddEmptyMethodAdapter.java95
-rw-r--r--plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/AddFieldAdapter.java52
-rw-r--r--plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/AddInterfaceAdapter.java49
-rw-r--r--plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/AsmBoundClass.java163
-rw-r--r--plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/AsmClassRepository.java35
-rw-r--r--plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/AsmClassVisitor.java130
-rw-r--r--plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/AsmTypeHelper.java79
-rw-r--r--plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/AsmWritableBoundClass.java432
-rw-r--r--plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/Attributes.java340
-rw-r--r--plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/CreateCallAllBindingsCallInOrgMethod.java146
-rw-r--r--plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/CreateDispatchCodeInCallAllBindingsAdapter.java76
-rw-r--r--plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/CreateDispatchCodeInOrgMethodAdapter.java100
-rw-r--r--plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/CreateFieldAccessAdapter.java130
-rw-r--r--plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/CreateMethodAccessAdapter.java121
-rw-r--r--plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/CreateSuperCallInCallOrigAdapter.java58
-rw-r--r--plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/CreateSwitchAdapter.java112
-rw-r--r--plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/CreateSwitchForAccessAdapter.java100
-rw-r--r--plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/CreateSwitchForCallAllBindingsNode.java77
-rw-r--r--plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/MoveCodeToCallOrigAdapter.java109
-rw-r--r--plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/MultiClassAdapter.java78
-rw-r--r--plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/runtime/ClassIdentifierProviderFactory.java38
-rw-r--r--plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/runtime/DefaultClassIdentifierProvider.java38
-rw-r--r--plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/runtime/IClassIdentifierProvider.java47
-rw-r--r--plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/runtime/TeamManager.java342
-rw-r--r--plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/transformer/names/ClassNames.java49
-rw-r--r--plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/transformer/names/ConstantMembers.java123
-rw-r--r--plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/util/ArrayUtil.java47
-rw-r--r--plugins/org.eclipse.objectteams.otredyn/src/org/objectteams/IBoundBase.java42
-rw-r--r--plugins/org.eclipse.objectteams.otredyn/src/org/objectteams/Team.java655
51 files changed, 6478 insertions, 0 deletions
diff --git a/plugins/org.eclipse.objectteams.otredyn/.classpath b/plugins/org.eclipse.objectteams.otredyn/.classpath
new file mode 100644
index 000000000..64c5e31b7
--- /dev/null
+++ b/plugins/org.eclipse.objectteams.otredyn/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.5"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/plugins/org.eclipse.objectteams.otredyn/.project b/plugins/org.eclipse.objectteams.otredyn/.project
new file mode 100644
index 000000000..e0a35ad69
--- /dev/null
+++ b/plugins/org.eclipse.objectteams.otredyn/.project
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.eclipse.objectteams.otredyn</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
diff --git a/plugins/org.eclipse.objectteams.otredyn/.settings/org.eclipse.jdt.core.prefs b/plugins/org.eclipse.objectteams.otredyn/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 000000000..8871fecd9
--- /dev/null
+++ b/plugins/org.eclipse.objectteams.otredyn/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,79 @@
+#Fri Jul 15 18:22:12 CEST 2011
+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.comparingIdentical=warning
+org.eclipse.jdt.core.compiler.problem.deadCode=warning
+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=warning
+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.includeNullInfoFromAsserts=disabled
+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.missingHashCodeMethod=ignore
+org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=ignore
+org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=enabled
+org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning
+org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=ignore
+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.suppressOptionalErrors=disabled
+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.unusedObjectAllocation=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
+org.eclipse.objectteams.otdt.compiler.option.pure_java=enabled
diff --git a/plugins/org.eclipse.objectteams.otredyn/META-INF/MANIFEST.MF b/plugins/org.eclipse.objectteams.otredyn/META-INF/MANIFEST.MF
new file mode 100644
index 000000000..4732fceb7
--- /dev/null
+++ b/plugins/org.eclipse.objectteams.otredyn/META-INF/MANIFEST.MF
@@ -0,0 +1,18 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: %pluginName
+Bundle-SymbolicName: org.eclipse.objectteams.otredyn
+Bundle-Version: 0.8.0.qualifier
+Bundle-Vendor: %providerName
+Bundle-Localization: plugin
+Export-Package: org.objectteams,
+ org.eclipse.objectteams.otredyn.bytecode,
+ org.eclipse.objectteams.otredyn.bytecode.asm,
+ org.eclipse.objectteams.otredyn.runtime,
+ org.eclipse.objectteams.otredyn.transformer,
+ org.eclipse.objectteams.otredyn.transformer.jplis,
+ org.eclipse.objectteams.otredyn.transformer.names,
+ org.eclipse.objectteams.otredyn.util
+Bundle-RequiredExecutionEnvironment: J2SE-1.5
+Bundle-ClassPath: .
+Require-Bundle: org.objectweb.asm;bundle-version="3.3.1"
diff --git a/plugins/org.eclipse.objectteams.otredyn/build.properties b/plugins/org.eclipse.objectteams.otredyn/build.properties
new file mode 100644
index 000000000..b5e3b75ef
--- /dev/null
+++ b/plugins/org.eclipse.objectteams.otredyn/build.properties
@@ -0,0 +1,4 @@
+source.. = src/
+bin.includes = META-INF/,\
+ .,\
+ plugin.properties
diff --git a/plugins/org.eclipse.objectteams.otredyn/plugin.properties b/plugins/org.eclipse.objectteams.otredyn/plugin.properties
new file mode 100644
index 000000000..f48715fbd
--- /dev/null
+++ b/plugins/org.eclipse.objectteams.otredyn/plugin.properties
@@ -0,0 +1,2 @@
+pluginName=Object Teams Dynamic Runtime Environment
+providerName=Eclipse.org - Object Teams
diff --git a/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/AbstractBoundClass.java b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/AbstractBoundClass.java
new file mode 100644
index 000000000..ff292ad7b
--- /dev/null
+++ b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/AbstractBoundClass.java
@@ -0,0 +1,1036 @@
+/**********************************************************************
+ * This file is part of "Object Teams Dynamic Runtime Environment"
+ *
+ * Copyright 2009, 2012 Oliver Frank and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Please visit http://www.eclipse.org/objectteams for updates and contact.
+ *
+ * Contributors:
+ * Oliver Frank - Initial API and implementation
+ * Stephan Herrmann - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.objectteams.otredyn.bytecode;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.IdentityHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.objectteams.otredyn.runtime.ClassIdentifierProviderFactory;
+import org.eclipse.objectteams.otredyn.runtime.IBinding;
+import org.eclipse.objectteams.otredyn.runtime.IBoundClass;
+import org.eclipse.objectteams.otredyn.runtime.IMethod;
+import org.eclipse.objectteams.otredyn.runtime.TeamManager;
+import org.eclipse.objectteams.otredyn.runtime.ISubclassWiringTask;
+import org.eclipse.objectteams.otredyn.transformer.jplis.ObjectTeamsTransformer;
+
+import org.objectweb.asm.Opcodes;
+
+/**
+ * This class represents a java class.
+ * It stores the information about a class parsed from the bytecode and
+ * it handles callin and decapsulation bindings for the class
+ * @author Oliver Frank
+ */
+public abstract class AbstractBoundClass implements IBoundClass {
+
+ /**
+ * A structure that is internally used to store which methods are still woven
+ * and which has to be woven.
+ */
+ private static class WeavingTask {
+ public static enum WeavingTaskType {
+ WEAVE_BINDING_OF_SUBCLASS,
+ WEAVE_BINDING,
+ WEAVE_INHERITED_BINDING,
+ WEAVE_METHOD_ACCESS,
+ WEAVE_FIELD_ACCESS,
+ WEAVE_INHERITED_MEMBER_ACCESS
+ }
+
+ private WeavingTaskType weavingTaskType;
+ private String memberName;
+ private String memberSignature;
+ private boolean doAllTransformations;
+ private boolean isHandleCovariantReturn;
+
+ public WeavingTask(WeavingTaskType weavingTaskType, String memberName, String memberSignature, boolean handleCovariantReturn) {
+ this.weavingTaskType = weavingTaskType;
+ this.memberName = memberName;
+ this.memberSignature = memberSignature;
+ this.isHandleCovariantReturn = handleCovariantReturn;
+ }
+
+ /**
+ * Returns the type of the WeavingTask
+ * @return
+ */
+ public WeavingTaskType getType() {
+ return weavingTaskType;
+ }
+
+ /**
+ * Returns the name of the member, that has to be woven
+ * @return
+ */
+ public String getMemberName() {
+ return memberName;
+ }
+
+ /**
+ * Returns the signature of the member, that has to be woven
+ * @return
+ */
+ public String getMemberSignature() {
+ return memberSignature;
+ }
+
+ /**
+ * This information is only needed for callin bindings.
+ * @return If true, all transformation has to be done, if false,
+ * only callAllBindings has to be redefined
+ */
+ public boolean doAllTransformations() {
+ return doAllTransformations;
+ }
+
+ public void setDoAllTransformations(boolean doAllTransformations) {
+ this.doAllTransformations = doAllTransformations;
+ }
+
+ public boolean isHandleCovariantReturn() {
+ return this.isHandleCovariantReturn;
+ }
+ }
+
+ // completed WeavingTasks for callin bindings mapped by the method,
+ // that was woven
+ private Map<Method, WeavingTask> completedBindingTasks;
+
+ // not completed WeavingTasks for callin bindings mapped by the method,
+ // that has to be woven
+ private Map<Method, WeavingTask> openBindingTasks;
+
+ // completed WeavingTasks for decapsulation bindings mapped by the member,
+ // that was woven
+ private Map<Member, WeavingTask> completedAccessTasks;
+
+ // open WeavingTasks for decapsulation bindings mapped by the member,
+ // that has to be woven
+ private Map<Member, WeavingTask> openAccessTasks;
+
+ private List<ISubclassWiringTask> wiringTasks;
+
+ //FQN (e.g. "foo.bar.MyClass")
+ private String name;
+
+ //internal FQN (e.g. "foo/bar/MyClass.class")
+ private String internalName;
+
+ // A globally unique identifier for the class
+ private String id;
+ private String superClassName;
+ private String internalSuperClassName;
+ private AbstractBoundClass superclass;
+ private AbstractBoundClass enclosingClass;
+ private Map<String, Method> methods;
+ private Map<String, Field> fields;
+ private Map<AbstractBoundClass, Object> subclasses;
+
+ // Is the java class, that was represented by the AbstractBoundClass
+ // already loaded by a class loader or not
+ private boolean isLoaded;
+
+ // Does this AbstractBoundClass represent a team
+ private boolean isTeam;
+ private boolean isInterface;
+
+ private int otClassFlags;
+ private int visibilityFlags;
+ private boolean implicitTeamActivationEnabled = false;
+ private Set<String> methodsForImplicitActivation;
+
+ protected ClassLoader loader;
+
+
+ /**
+ * No public constructor, beacause only the ClassRepository should
+ * create AbstractBoundClasses
+ * @param name dot-separated class name
+ * @param id unique identifier, able to differentiate same-named classes from different classloaders
+ * @param loader classloader responsible for loading this class
+ */
+ protected AbstractBoundClass(String name, String id, ClassLoader loader) {
+ if (name.indexOf('/')!= -1)
+ new RuntimeException(name).printStackTrace(System.out);
+ this.name = name;
+ this.internalName = name.replace('.', '/');
+ this.id = id;
+ this.loader = loader;
+ completedBindingTasks = new IdentityHashMap<Method, WeavingTask>();
+ openBindingTasks = new IdentityHashMap<Method, WeavingTask>();
+ openAccessTasks = new IdentityHashMap<Member, WeavingTask>();
+ completedAccessTasks = new IdentityHashMap<Member, WeavingTask>();
+ methods = new HashMap<String, Method>();
+ fields = new HashMap<String, Field>();
+ subclasses = new IdentityHashMap<AbstractBoundClass, Object>();
+
+ // don't fetch a anonymous subclass for a anonymous subclass
+ if (!name.equals(ClassRepository.ANONYMOUS_SUBCLASS_NAME)) {
+ AbstractBoundClass anonymousSubclass = ClassRepository
+ .getInstance().getAnonymousSubclass(this);
+ subclasses.put(anonymousSubclass, null);
+ }
+ }
+
+ /**
+ * Returns the name of the Class
+ * @return
+ */
+ public String getName() {
+ return name;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public boolean isAnonymous() {
+ return getName().equals(ClassRepository.ANONYMOUS_SUBCLASS_NAME);
+ }
+
+ /**
+ * Returns the classloader responsible for loading this class.
+ * @return
+ */
+ public ClassLoader getClassLoader() {
+ return this.loader;
+ }
+
+ /**
+ * Set the name of the super class of this class
+ * @param superClassName
+ */
+ public void setSuperClassName(String superClassName) {
+ if (superClassName == null) {
+ return;
+ }
+ this.superClassName = superClassName.replace('/', '.');
+ this.internalSuperClassName = superClassName.replace('.', '/');
+ }
+
+ public boolean isJavaLangObject() {
+ return this.name.equals("java.lang.Object");
+ }
+
+ /**
+ * Is the class a interface?
+ * @return
+ */
+ public boolean isInterface() {
+ parseBytecode();
+ return isInterface;
+ }
+
+ /**
+ * Mark as interface
+ * @param isInterface
+ */
+ public void setInterface(boolean isInterface) {
+ this.isInterface = isInterface;
+ }
+
+ /**
+ * Does this AbstractBoundClass represents a Team.
+ * @return if true, the method getTeam of the ClassRepository
+ * could be called to get an instance of AbstractTeam
+ */
+ public boolean isTeam() {
+ parseBytecode();
+ return isTeam;
+ }
+
+ /**
+ * Mark as team
+ * @param isTeam
+ */
+ public void setTeam(boolean isTeam) {
+ this.isTeam = isTeam;
+ }
+
+ public void setOTClassFlags(int flags) {
+ this.otClassFlags = flags;
+ }
+ public void setVisibility(int flags) {
+ this.visibilityFlags = flags;
+ }
+
+ public boolean isRole() {
+ return (this.otClassFlags & Types.ROLE_FLAG) != 0;
+ }
+
+ public boolean isProtected() {
+ return (this.visibilityFlags & Opcodes.ACC_PROTECTED) != 0;
+ }
+
+ public void enableImplicitActivation() {
+ this.implicitTeamActivationEnabled = true;
+ }
+
+ public void registerMethodForImplicitActivation(String methodNameAndDesc) {
+ if (this.methodsForImplicitActivation == null)
+ this.methodsForImplicitActivation = new HashSet<String>();
+ this.methodsForImplicitActivation.add(methodNameAndDesc);
+ }
+
+ public boolean hasMethodImplicitActivation(String methodNameAndDesc) {
+ if (this.implicitTeamActivationEnabled) // for all methods
+ return true;
+ if (this.methodsForImplicitActivation == null)
+ return false;
+ return this.methodsForImplicitActivation.contains(methodNameAndDesc);
+ }
+
+ /**
+ * Do all needed transformations needed at load time:
+ * Add the interface IBoundBase
+ * Add the empty method callOrig
+ * Add the empty method callOrigStatic
+ * Add the empty method access
+ * Add the empty method accessStatic
+ * Add the empty method callAllBindings
+ */
+ public void transformAtLoadTime() {
+ handleTaskList();
+ }
+
+ /**
+ * Mark as loaded
+ */
+ public void setLoaded() {
+ this.isLoaded = true;
+ }
+
+ /**
+ * Returns an instance of AbstractBoundClass that represents
+ * the super class of this class.
+ * It parses the bytecode, if that has not already been done
+ * @return an instance of AbstractBoundClass that represents
+ * the super class of this class
+ */
+ public synchronized AbstractBoundClass getSuperclass() {
+ parseBytecode();
+ if (superClassName != null && superclass == null) {
+ String superclassId = ClassIdentifierProviderFactory.getClassIdentifierProvider().getSuperclassIdentifier(id, internalSuperClassName);
+
+ //if superclassId is null the class could be "Object" or an interface
+ if (superclassId != null) {
+ superclass = ClassRepository.getInstance().getBoundClass(superClassName, superclassId, loader);
+ superclass.addSubclass(this);
+ // FIXME(SH): can we avoid adding all subclasses to j.l.Object?
+ }
+ }
+ return superclass;
+ }
+
+ /**
+ * Returns an instance of AbstractBoundClass that represents
+ * the enclosing class of this class.
+ * It parses the bytecode, if that has not already been done
+ * @return an instance of AbstractBoundClass that represents
+ * the enclosing class of this class
+ */
+ public synchronized AbstractBoundClass getEnclosingClass() {
+ parseBytecode();
+ int pos = this.internalName.lastIndexOf('$');
+ if (pos != -1) {
+ String enclosingClassName = this.internalName.substring(0, pos);
+ // FIXME(SH): do we need a new getEnclosingClassIdentifier?
+ String enclosingClassID = ClassIdentifierProviderFactory.getClassIdentifierProvider().getSuperclassIdentifier(id, enclosingClassName);
+
+ if (enclosingClassID != null) {
+ enclosingClass = ClassRepository.getInstance().getBoundClass(enclosingClassName, enclosingClassID, loader);
+ enclosingClass.addSubclass(this);
+ }
+ }
+ return enclosingClass;
+ }
+
+ public synchronized String getEnclosingClassName() {
+ parseBytecode();
+ int pos = this.internalName.lastIndexOf('$');
+ if (pos != -1) {
+ return this.internalName.substring(0, pos);
+ }
+ return null;
+ }
+
+ /**
+ * This method parses the bytecode, if that has not already been done
+ */
+ protected abstract void parseBytecode();
+
+ /**
+ * Returns the internal name of the super class of this class
+ * It parses the bytecode, if that has not already been done
+ * @return
+ */
+ protected String getInternalSuperClassName() {
+ parseBytecode();
+ return internalSuperClassName;
+ }
+
+ /**
+ * Returns the internal name of this class
+ * @return
+ */
+ protected String getInternalName() {
+ return internalName;
+ }
+
+ /**
+ * Returns the name of the super class of this class
+ * It parses the bytecode, if that has not already been done
+ * @return
+ */
+ public String getSuperClassName() {
+ parseBytecode();
+ return superClassName;
+ }
+
+ /**
+ * Adds a method to this class.
+ * This method is intended to be called,
+ * while parsing the bytecode
+ * @param name the name of the field
+ * @param desc the signature of the method
+ * @param isStatic is this method static
+ * @param isPrivate is this method private
+ */
+ public void addMethod(String name, String desc, boolean isStatic, int accessFlags) {
+ String methodKey = getMethodKey(name, desc);
+ Method method = methods.get(methodKey);
+ // Does this method already exists?
+ // Methods are created by getMethod, if the class is not loaded
+ if (method == null) {
+ method = new Method(name, desc, isStatic, accessFlags);
+ method.setImplemented(true);
+ methods.put(methodKey, method);
+ } else {
+ // Yes, so set additional information.
+ method.setImplemented(true);
+ method.setStatic(isStatic);
+ }
+ }
+
+ /** Method signature sauf the return type. */
+ private String getMethodKey(String name, String desc) {
+ int pos = desc.indexOf(')');
+ return name+desc.substring(0,pos+1);
+ }
+
+ /**
+ * Adds a field to this class.
+ * This method is intended to be called,
+ * while parsing the bytecode
+ * @param name the name of the field
+ * @param desc the signature of the field
+ * @param isStatic is this field static
+ * @param accessFlag ACC_PUBLIC, ACC_PROTECTED, ACC_PRIVATE or 0.
+ */
+ public void addField(String name, String desc, boolean isStatic, int accessFlags) {
+ Field field = fields.get(name);
+ if (field == null) {
+ field = new Field(name, desc, isStatic, accessFlags);
+ fields.put(name, field);
+ } else {
+ field.setStatic(isStatic);
+ }
+ }
+
+ public synchronized Method getMethod(String name, String desc, boolean allowCovariantReturn) {
+ parseBytecode();
+ String methodKey = getMethodKey(name, desc);
+ Method method = methods.get(methodKey);
+ if (!allowCovariantReturn && method != null && !method.getSignature().equals(desc))
+ method = null; // don't use this
+ if (method == null) {
+ // class was not yet loaded
+ method = new Method(name, desc);
+ methods.put(methodKey, method);
+ }
+ return method;
+ }
+
+ // same as above but specifically request a static/non-static method
+ public synchronized Method getMethod(String name, String desc, boolean allowCovariantReturn, boolean isStatic) {
+ parseBytecode();
+ String methodKey = getMethodKey(name, desc);
+ Method method = methods.get(methodKey);
+ if (!allowCovariantReturn && method != null && !method.getSignature().equals(desc))
+ method = null; // don't use this
+ if (method == null) {
+ // class was not yet loaded
+ method = new Method(name, desc);
+ method.setStatic(isStatic);
+ methods.put(methodKey, method);
+ }
+ assert method.isStatic() == isStatic : "Mismatching static/non-static methods "+getName()+'.'+name+desc;
+ return method;
+ }
+
+ public synchronized Field getField(String name, String desc) {
+ parseBytecode();
+ Field field = fields.get(name);
+ if (field == null) {
+ // class was not yet loaded
+ field = new Field(name, desc);
+ fields.put(name, field);
+ }
+ return field;
+ }
+
+
+ public String getMethodIdentifier(IMethod method) {
+ return getId() + method.getName() + method.getSignature();
+ }
+
+ /**
+ * Adds a subclass to this class
+ * @param subclass
+ */
+ protected void addSubclass(AbstractBoundClass subclass) {
+ subclasses.put(subclass, null);
+ }
+
+ /**
+ * Remove subclass from this class. It's only needed
+ * to remove a anonymous subclass, if a real subclass is loaded
+ * @param subclass
+ */
+ protected void removeSubclass(AbstractBoundClass subclass) {
+ subclasses.remove(subclass);
+ }
+
+ /**
+ * Returns all subclasses of this class,
+ * including the anonymous subclass
+ * @return
+ */
+ private Collection<AbstractBoundClass> getSubclasses() {
+ return subclasses.keySet();
+ }
+
+ /**
+ * Handle all open weaving tasks for this class.
+ * It redefines the class, if it is not called while loading
+ */
+ public synchronized void handleTaskList() {
+ Set<Map.Entry<Method, WeavingTask>> bindingEntrySet = openBindingTasks
+ .entrySet();
+
+ Set<Map.Entry<Member, WeavingTask>> accessEntrySet = openAccessTasks
+ .entrySet();
+
+ // Are there not handled callin or decapsulation bindings
+ // for this class
+ if (bindingEntrySet.size() > 0 || accessEntrySet.size() > 0) {
+ // Yes, so start the transformation, parse the bytecode
+ // and do load time transforming, if this method is called
+ // at load time
+ startTransformation();
+ parseBytecode();
+ prepareAsPossibleBaseClass();
+ prepareTeamActivation();
+ } else if (isFirstTransformation()) {
+ // No, so only do load time transforming, if this method is called
+ // at load time
+ startTransformation();
+ prepareAsPossibleBaseClass();
+ prepareTeamActivation();
+ endTransformation();
+ }
+
+ for (Map.Entry<Method, WeavingTask> entry : bindingEntrySet) {
+ WeavingTask task = entry.getValue();
+ Method method = entry.getKey();
+ switch (task.getType()) {
+ // Weave callin binding to a method of a subclass, that is not implemented
+ // in the subclass
+ case WEAVE_BINDING_OF_SUBCLASS:
+ // Is the method implemented in this class?
+ if (method.isImplemented()) {
+ // Yes, so weave this class
+ weaveBindingOfSubclass(task);
+ } else {
+ //No, so just delegate the weaving task to the superclass
+ AbstractBoundClass superclass = getSuperclass();
+ // If superclass is null, her is something wrong
+ if (superclass != null) {
+ superclass.addWeavingTask(task);
+ weaveSuperCallInCallOrig(task); // ensure we're actually calling that super version
+ }
+ }
+ break;
+ // Weave callin binding to a method of this class
+ case WEAVE_BINDING:
+ if (method.isStatic()) {
+ weaveBindingInStaticMethod(task);
+ } else {
+ // Is the method implemented in this class?
+ if (method.isImplemented()) {
+ // So redefine the method
+ weaveBindingInImplementedMethod(task);
+ } else {
+ //No, so weave this class and delegate to the super class
+ weaveBindingInNotImplementedMethod(task);
+ AbstractBoundClass superclass = getSuperclass();
+ Method superMethod = superclass.getMethod(method.getName(), method.getSignature(),
+ task.isHandleCovariantReturn());
+ WeavingTask newTask = new WeavingTask(
+ WeavingTask.WeavingTaskType.WEAVE_BINDING_OF_SUBCLASS,
+ superMethod.getName(), superMethod.getSignature(),
+ task.isHandleCovariantReturn());
+ superclass.addWeavingTask(newTask);
+ }
+
+// Original comment:
+// If this method is private, the callin binding is not
+// inherited by the subclasses
+// However, this conflicts with test415_nonexistingBaseMethod3i,
+// where an empty callAllBindings() was overriding a non-empty one.
+// see also Method.getId()
+// if (!method.isPrivate()) {
+ // Delegate the WeavingTask to the subclasses
+ for (AbstractBoundClass subclass : getSubclasses()) {
+ Method subMethod = subclass.getMethod(method.getName(), method.getSignature(),
+ task.isHandleCovariantReturn());
+ WeavingTask newTask = new WeavingTask(
+ WeavingTask.WeavingTaskType.WEAVE_INHERITED_BINDING,
+ subMethod.getName(), subMethod.getSignature(),
+ task.isHandleCovariantReturn());
+ subclass.addWeavingTask(newTask);
+ TeamManager.mergeJoinpoints(this, subclass, method, subMethod, task.isHandleCovariantReturn());
+ }
+// }
+ }
+ break;
+ // Weave Binding inherited from the superclass
+ case WEAVE_INHERITED_BINDING:
+ if (method.isImplemented()) {
+ weaveBindingInImplementedMethod(task);
+ } else {
+ weaveBindingInNotImplementedMethod(task);
+ }
+
+ // Delegate the WeavingTask to the subclasses
+ for (AbstractBoundClass subclass : getSubclasses()) {
+ Method subMethod = subclass.getMethod(method.getName(), method.getSignature(),
+ task.isHandleCovariantReturn());
+ WeavingTask newTask = new WeavingTask(
+ WeavingTask.WeavingTaskType.WEAVE_INHERITED_BINDING, subMethod
+ .getName(), subMethod.getSignature(),
+ task.isHandleCovariantReturn());
+ subclass.addWeavingTask(newTask);
+ TeamManager.mergeJoinpoints(this, subclass, method, subMethod, task.isHandleCovariantReturn());
+ }
+
+ break;
+ }
+
+ // Mark all WeavingTasks for callin bindings
+ // as completed
+ completedBindingTasks.put(method, task);
+ }
+
+ //handle all WeavinTasks for decapsulation bindings
+ for (Map.Entry<Member, WeavingTask> entry : accessEntrySet) {
+ WeavingTask task = entry.getValue();
+ Member member = entry.getKey();
+
+ switch (task.getType()) {
+ // handle decapsulation binding to a field
+ case WEAVE_FIELD_ACCESS:
+ prepareForFirstMemberAccess();
+ Field field = getField(task.getMemberName(), task
+ .getMemberSignature());
+ weaveFieldAccess(field, field.getId(this));
+ if (!field.isStatic()) {
+ // If the field is not static it could be accessed through a subclass
+ // so weave the subclass
+ for (AbstractBoundClass subclass : getSubclasses()) {
+ WeavingTask newTask = new WeavingTask(
+ WeavingTask.WeavingTaskType.WEAVE_INHERITED_MEMBER_ACCESS,
+ null, null, false/*handleCovariantReturn*/);
+ subclass.addWeavingTask(newTask);
+ }
+ }
+ break;
+ // handle decaspulation binding to a method
+ case WEAVE_METHOD_ACCESS:
+ prepareForFirstMemberAccess();
+ Method method = getMethod(task.getMemberName(), task.getMemberSignature(),
+ task.isHandleCovariantReturn());
+ weaveMethodAccess(method, method.getId(this));
+ if (!method.isStatic()) {
+ // If the method is not static it could be accessed through a subclass
+ // so weave the subclass
+ for (AbstractBoundClass subclass : getSubclasses()) {
+ WeavingTask newTask = new WeavingTask(
+ WeavingTask.WeavingTaskType.WEAVE_INHERITED_MEMBER_ACCESS,
+ null, null, false/*handleCovariantReturn*/);
+ subclass.addWeavingTask(newTask);
+ }
+ }
+ break;
+ case WEAVE_INHERITED_MEMBER_ACCESS:
+ prepareForFirstMemberAccess();
+ break;
+ }
+
+ // Mark all WeavingTasks for decapsulation bindings
+ // as completed
+ completedAccessTasks.put(member, task);
+ }
+ if (openBindingTasks.size() > 0 || openAccessTasks.size() > 0) {
+ // Weave the class, if the method is not called at load time
+ endTransformation();
+ }
+ openBindingTasks.clear();
+ openAccessTasks.clear();
+ }
+
+ public void handleAddingOfBinding(IBinding binding) {
+ WeavingTask.WeavingTaskType type = null;
+ switch (binding.getType()) {
+ case CALLIN_BINDING:
+ type = WeavingTask.WeavingTaskType.WEAVE_BINDING;
+ break;
+ case FIELD_ACCESS:
+ type = WeavingTask.WeavingTaskType.WEAVE_FIELD_ACCESS;
+ break;
+ case METHOD_ACCESS:
+ type = WeavingTask.WeavingTaskType.WEAVE_METHOD_ACCESS;
+ break;
+ default:
+ throw new RuntimeException("Unknown binding type: "
+ + binding.getType().name());
+ }
+ if ( binding.getType() == IBinding.BindingType.CALLIN_BINDING
+ && !binding.getBoundClass().equals(binding.getDeclaringBaseClassName()))
+ try {
+ // need to load the declaring base class outside the transform() callback:
+ this.loader.loadClass(binding.getDeclaringBaseClassName().replace('/', '.'));
+ } catch (ClassNotFoundException e) {
+ throw new NoClassDefFoundError(e.getMessage());
+ }
+ WeavingTask task = new WeavingTask(type, binding.getMemberName(), binding.getMemberSignature(), binding.isHandleCovariantReturn());
+ addWeavingTask(task);
+ }
+
+ private void addWeavingTask(WeavingTask task) {
+ boolean isNewTask = addWeavingTaskLazy(task);
+
+ if (this.isLoaded && isNewTask) {
+ handleTaskList();
+ }
+ }
+
+ private boolean addWeavingTaskLazy(WeavingTask task) {
+ WeavingTask.WeavingTaskType type = task.getType();
+ boolean isNewTask = false;
+ if (type == WeavingTask.WeavingTaskType.WEAVE_BINDING
+ || type == WeavingTask.WeavingTaskType.WEAVE_BINDING_OF_SUBCLASS
+ || type == WeavingTask.WeavingTaskType.WEAVE_INHERITED_BINDING) {
+ isNewTask = addBindingWeavingTask(task);
+ } else {
+ isNewTask = addAccessWeavingTask(task);
+ }
+
+ return isNewTask;
+ }
+
+ /**
+ * Handle a new WeavingTask for decapsulation and
+ * figures out if weaving is needed for this task
+ * @param task
+ * @return
+ */
+ private boolean addAccessWeavingTask(WeavingTask task) {
+ WeavingTask.WeavingTaskType type = task.getType();
+ Member member = null;
+ switch (type) {
+ case WEAVE_FIELD_ACCESS:
+ member = getField(task.getMemberName(), task.getMemberSignature());
+ break;
+ case WEAVE_METHOD_ACCESS:
+ member = getMethod(task.getMemberName(), task.getMemberSignature(), false/*covariantReturn*/);
+ break;
+ case WEAVE_INHERITED_MEMBER_ACCESS:
+ openAccessTasks.put(null, task);
+ return true;
+ }
+
+ synchronized (member) {
+ WeavingTask prevTask = completedAccessTasks.get(member);
+ // Is there a already completed task for the member?
+ if (prevTask == null) {
+ // No, so check the open tasks
+ prevTask = openAccessTasks.get(member);
+ }
+
+ // Is there a open task for the member?
+ if (prevTask == null) {
+ // No, so weaving is needed
+ openAccessTasks.put(member, task);
+ return true;
+ } else {
+ //Yes, so weaving is not needed
+ return false;
+ }
+ }
+ }
+
+ /**
+ * Handle a new WeavingTask for a callin binding and
+ * figures out if weaving is needed for this task
+ * @param task
+ * @return
+ */
+ private boolean addBindingWeavingTask(WeavingTask task) {
+ Method method = getMethod(task.getMemberName(), task.getMemberSignature(),
+ task.isHandleCovariantReturn());
+ synchronized (method) {
+ WeavingTask prevTask = completedBindingTasks.get(method);
+ // Is there a already completed task for the method?
+ if (prevTask == null) {
+ // No, so check the open tasks
+ prevTask = openBindingTasks.get(method);
+ }
+
+ // Is there a open task for the member?
+ if (prevTask == null) {
+ //No, so weaving is needed
+ task.setDoAllTransformations(true);
+ openBindingTasks.put(method, task);
+ return true;
+ }
+
+ switch (prevTask.getType()) {
+ case WEAVE_BINDING:
+ return false;
+ case WEAVE_BINDING_OF_SUBCLASS:
+ // In this case only the callAllBings was redefined.
+ if (task.getType() != WeavingTask.WeavingTaskType.WEAVE_BINDING_OF_SUBCLASS) {
+ // Do the other transformations, if the new WeavingTask is not the same
+ // as already existing
+ openBindingTasks.put(method, task);
+ return true;
+ }
+ return false;
+ case WEAVE_INHERITED_BINDING:
+ return false;
+ default:
+ throw new RuntimeException("Unknown WeavingTaskType: "
+ + prevTask.getType().name());
+ }
+ }
+ }
+
+ /**
+ * Merge tasks of two AbstractBoundClasses (this class and a other).
+ * This method is called if a currently loaded has to be merged
+ * with a anonymous subclass
+ * @param clazz
+ * @return
+ */
+ protected boolean mergeTasks(AbstractBoundClass clazz) {
+ boolean isNewTask = false;
+ for (Map.Entry<Method, WeavingTask> entry : clazz.openBindingTasks
+ .entrySet()) {
+ isNewTask |= addWeavingTaskLazy(entry.getValue());
+ }
+
+ for (Map.Entry<Member, WeavingTask> entry : clazz.openAccessTasks
+ .entrySet()) {
+ isNewTask |= addWeavingTaskLazy(entry.getValue());
+ }
+
+ return isNewTask;
+ }
+
+ private void weaveBindingInStaticMethod(WeavingTask task) {
+ prepareForFirstStaticTransformation();
+ Method method = getMethod(task.getMemberName(), task.getMemberSignature(),
+ false/*covariantReturn*/);
+ int joinpointId = TeamManager
+ .getJoinpointId(getMethodIdentifier(method));
+ int boundMethodId = method.getId(this);
+
+ moveCodeToCallOrig(method, boundMethodId);
+ createDispatchCodeInOrgMethod(method, joinpointId, boundMethodId);
+ }
+
+ /**
+ * Do all transformations for a method, that is not implemented
+ * in this class
+ * @param task
+ */
+ private void weaveBindingInNotImplementedMethod(WeavingTask task) {
+ prepareForFirstTransformation();
+ Method method = getMethod(task.getMemberName(), task.getMemberSignature(),
+ task.isHandleCovariantReturn());
+ int joinpointId = TeamManager
+ .getJoinpointId(getMethodIdentifier(method));
+ int boundMethodId = method.getId(this);
+ if (task.doAllTransformations()) {
+ createDispatchCodeInCallAllBindings(joinpointId, boundMethodId);
+ // TODO(SH): instead of iterating superclasses fetch it from the Binding
+ boolean isWeavable = true; // weavable unless we find it to be declared in an unweavable super
+ AbstractBoundClass superClass = getSuperclass();
+ while (superClass != null) {
+ if (superClass.isJavaLangObject()) {
+ isWeavable = false;
+ break;
+ }
+ Method superMethod = superClass.getMethod(task.getMemberName(), task.getMemberSignature(), task.isHandleCovariantReturn());
+ if (superMethod.isImplemented()) {
+ isWeavable = ObjectTeamsTransformer.isWeavable(superClass.getInternalName());
+ break;
+ }
+ superClass = superClass.getSuperclass();
+ }
+ if (isWeavable)
+ createSuperCallInCallOrig(boundMethodId);
+ else
+ // can't weave into the declaring class, add an override here:
+ createCallAllBindingsCallInOrgMethod(method, joinpointId, true/*needToAddMethod*/);
+ } else {
+ createDispatchCodeInCallAllBindings(joinpointId, boundMethodId);
+ }
+ }
+
+ /**
+ * While delegating a task from a sub class to the super class,
+ * ensure that the super version is actually called.
+ */
+ private void weaveSuperCallInCallOrig(WeavingTask task) {
+ prepareForFirstTransformation();
+ Method method = getMethod(task.getMemberName(), task.getMemberSignature(),
+ task.isHandleCovariantReturn());
+ int boundMethodId = method.getId(this);
+ if (task.doAllTransformations()) {
+ createSuperCallInCallOrig(boundMethodId);
+ }
+ }
+
+ /**
+ * Do all transformations for a method, that is implemented
+ * in this class
+ * @param task
+ */
+ private void weaveBindingInImplementedMethod(WeavingTask task) {
+ prepareForFirstTransformation();
+ Method method = getMethod(task.getMemberName(), task.getMemberSignature(),
+ task.isHandleCovariantReturn());
+ int joinpointId = TeamManager
+ .getJoinpointId(getMethodIdentifier(method));
+ int boundMethodId = method.getId(this);
+ if (task.doAllTransformations()) {
+ moveCodeToCallOrig(method, boundMethodId);
+ createDispatchCodeInCallAllBindings(joinpointId, boundMethodId);
+ createCallAllBindingsCallInOrgMethod(method, boundMethodId, false);
+ } else {
+ createDispatchCodeInCallAllBindings(joinpointId, joinpointId);
+ }
+ }
+
+ /**
+ * Do all transformations for a method, that is bound
+ * but not implemented in a subclass
+ * @param task
+ */
+ private void weaveBindingOfSubclass(WeavingTask task) {
+ prepareForFirstTransformation();
+ Method method = getMethod(task.getMemberName(), task.getMemberSignature(),
+ task.isHandleCovariantReturn());
+ int boundMethodId = method.getId(this);
+ moveCodeToCallOrig(method, boundMethodId);
+ createCallAllBindingsCallInOrgMethod(method, boundMethodId, false);
+
+ }
+
+ @Override
+ public String toString() {
+ return this.name+"["+this.id+"]";
+ }
+
+ // See AsmBoundClass or AsmWritableBoundClass for documentation
+
+ protected abstract void startTransformation();
+
+ protected abstract void endTransformation();
+
+ protected abstract void prepareAsPossibleBaseClass();
+
+ protected abstract void prepareTeamActivation();
+
+ protected abstract void createSuperCallInCallOrig(int boundMethodId);
+
+ protected abstract void createCallAllBindingsCallInOrgMethod(
+ Method boundMethod, int joinpointId, boolean needToAddMethod);
+
+ protected abstract void createDispatchCodeInCallAllBindings(
+ int joinpointId, int boundMethodId);
+
+ protected abstract void moveCodeToCallOrig(Method boundMethod, int boundMethodId);
+
+ protected abstract void prepareForFirstTransformation();
+
+ protected abstract void prepareForFirstStaticTransformation();
+
+ protected abstract boolean isFirstTransformation();
+
+ protected abstract void createDispatchCodeInOrgMethod(Method boundMethod,
+ int joinpointId, int boundMethodId);
+
+ protected abstract void prepareForFirstMemberAccess();
+
+ protected abstract void weaveFieldAccess(Field field, int accessId);
+
+ protected abstract void weaveMethodAccess(Method method, int accessId);
+
+ public abstract boolean isTransformationActive();
+
+ public abstract byte[] getBytecode();
+
+ public void dump(byte[] classfileBuffer, String postfix) {}
+
+ public abstract int compare(String callinLabel1, String callinLabel2);
+
+ public void addWiringTask(ISubclassWiringTask wiringTask) {
+ if (this.wiringTasks == null)
+ this.wiringTasks = new ArrayList<ISubclassWiringTask>();
+ this.wiringTasks.add(wiringTask);
+ }
+
+ public void performWiringTasks(AbstractBoundClass superclass, AbstractBoundClass subclass) {
+ if (this.wiringTasks == null)
+ return;
+ synchronized (this.wiringTasks) {
+ for (ISubclassWiringTask task : this.wiringTasks)
+ task.wire(superclass, subclass);
+ this.wiringTasks.clear();
+ }
+ }
+
+}
diff --git a/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/AbstractTeam.java b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/AbstractTeam.java
new file mode 100644
index 000000000..31504ca0a
--- /dev/null
+++ b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/AbstractTeam.java
@@ -0,0 +1,76 @@
+/**********************************************************************
+ * This file is part of "Object Teams Dynamic Runtime Environment"
+ *
+ * Copyright 2009, 2012 Oliver Frank and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Please visit http://www.eclipse.org/objectteams for updates and contact.
+ *
+ * Contributors:
+ * Oliver Frank - Initial API and implementation
+ * Stephan Herrmann - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.objectteams.otredyn.bytecode;
+
+import java.util.Collection;
+import java.util.Set;
+import java.util.TreeSet;
+
+import org.eclipse.objectteams.otredyn.runtime.IBoundTeam;
+
+/**
+ * Represents a team class and stores the bindings this team has got.
+ */
+public abstract class AbstractTeam extends AbstractBoundClass implements IBoundTeam {
+ /**
+ * All relevant bindings (callin and decapsulation) of this team.
+ * By internally using a TreeSet the set of bindings is naturally sorted
+ * based on {@link Binding#compareTo(Binding)} (see there).
+ */
+ private Set<Binding> bindings;
+ private int highestAccessId;
+
+ protected AbstractTeam(String name, String id, ClassLoader loader) {
+ super(name, id, loader);
+ bindings = new TreeSet<Binding>();
+ }
+
+ /**
+ * Adds a binding to the team.
+ * This method is intended to be called,
+ * while parsing the bytecode
+ * @param binding
+ */
+ public void addBinding(Binding binding) {
+ bindings.add(binding);
+ }
+
+ public Collection<Binding> getBindings() {
+ parseBytecode();
+ return bindings;
+ }
+
+ /**
+ * Returns the superclass of this team as AbstractTeam
+ */
+ @Override
+ public AbstractTeam getSuperclass() {
+ return (AbstractTeam) super.getSuperclass();
+ }
+
+ /**
+ * Record that this team uses the given accessId.
+ * @param accessId
+ */
+ public void recordAccessId(int accessId) {
+ this.highestAccessId = Math.max(this.highestAccessId, accessId);
+ }
+
+ public int getHighestAccessId() {
+ return highestAccessId;
+ }
+}
diff --git a/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/Binding.java b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/Binding.java
new file mode 100644
index 000000000..852e1760c
--- /dev/null
+++ b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/Binding.java
@@ -0,0 +1,165 @@
+/**********************************************************************
+ * This file is part of "Object Teams Dynamic Runtime Environment"
+ *
+ * Copyright 2009, 2012 Oliver Frank and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Please visit http://www.eclipse.org/objectteams for updates and contact.
+ *
+ * Contributors:
+ * Oliver Frank - Initial API and implementation
+ * Stephan Herrmann - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.objectteams.otredyn.bytecode;
+
+import org.eclipse.objectteams.otredyn.runtime.IBinding;
+
+/**
+ * This class represents a callin or decapsulation binding
+ * @author Oliver Frank
+ */
+public class Binding implements Comparable<Binding>, IBinding {
+
+ /** The callin modifier 'before' */
+ public static final int BEFORE = 1;
+ /** The callin modifier 'replace' */
+ public static final int REPLACE = 2;
+ /** The callin modifier 'after' */
+ public static final int AFTER = 3;
+
+ AbstractBoundClass teamClass;
+ private String callinLabel;
+ private String boundClass;
+ private String memberName;
+ private String memberSignature;
+ private String declaringBaseClassName;
+ private int callinModifier;
+ private int callinId;
+ private IBinding.BindingType type;
+ private boolean isHandleCovariantReturn;
+
+ public IBinding.BindingType getType() {
+ return type;
+ }
+
+ /**
+ * Create a callin binding.
+ */
+ public Binding(AbstractBoundClass teamClass,
+ String roleClassName, String callinLabel, String boundClassName,
+ String memberName, String memberSignature, String declaringBaseClassName,
+ int callinModifier, int callinId, boolean handleCovariantReturn)
+ {
+ this.teamClass = teamClass;
+ this.callinLabel = callinLabel;
+ this.boundClass = boundClassName;
+ this.memberName = memberName;
+ this.memberSignature = memberSignature;
+ this.declaringBaseClassName = declaringBaseClassName;
+ this.callinModifier = callinModifier;
+ this.callinId = callinId;
+ this.type = IBinding.BindingType.CALLIN_BINDING;
+ this.isHandleCovariantReturn = handleCovariantReturn;
+ }
+
+ /**
+ * Create a method or field access binding (decapsulation).
+ */
+ public Binding(AbstractBoundClass teamClass,
+ String boundClassName,
+ String memberName, String memberSignature, int callinId, IBinding.BindingType type)
+ {
+ this.teamClass = teamClass;
+ this.boundClass = boundClassName;
+ this.memberName = memberName;
+ this.memberSignature = memberSignature;
+ this.callinId = callinId;
+ this.type = type;
+ }
+
+ public String getBoundClass() {
+ return boundClass;
+ }
+
+ public String getMemberName() {
+ return memberName;
+ }
+
+ public String getMemberSignature() {
+ return memberSignature;
+ }
+
+ public int getCallinId() {
+ return callinId;
+ }
+
+ public boolean isHandleCovariantReturn() {
+ return this.isHandleCovariantReturn;
+ }
+
+ public String getDeclaringBaseClassName() {
+ return this.declaringBaseClassName;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ Binding other = (Binding) obj;
+ return boundClass.equals(other.boundClass)
+ && memberName.equals(other.memberName)
+ && memberSignature.equals(other.memberSignature)
+ && type == other.type && callinId == other.callinId;
+ }
+
+ public int compareTo(Binding other) {
+ // ordering strategy for callin bindings:
+ // - first criterion: callinModifier: before/after have higher priority than replace.
+ // - second criterion: precedence (only relevant among callins of the same callin modifier).
+ // the set AbstractTeam.bindings is sorted low-to-high.
+ // then TeamManager.handleTeamStateChange processes all bindings from low-to-high
+ // inserting each at the front of the list of active teams, such that last added
+ // will indeed have highest priority, which is in line with ordering by activation time.
+ int compare = 0;
+ if (this.callinLabel == null || other.callinLabel == null) {
+ // at least one binding is a decaps binding
+ if (this.callinLabel != null)
+ return 1;
+ else if (other.callinLabel != null)
+ return -1;
+ } else {
+ if (this.callinModifier != other.callinModifier) {
+ // replace has lower priority than before/after:
+ if (this.callinModifier == REPLACE)
+ return -1;
+ else if (other.callinModifier == REPLACE)
+ return 1;
+ }
+ // the following comparison respects precedence:
+ compare = this.teamClass.compare(this.callinLabel, other.callinLabel);
+ if (compare != 0)
+ return compare;
+ }
+ return (boundClass + memberName + memberSignature).compareTo(other.boundClass + other.memberName + other.memberSignature);
+ }
+
+ @Override
+ public String toString() {
+ StringBuffer buf = new StringBuffer();
+ switch (this.type) {
+ case CALLIN_BINDING: buf.append("callin: ");break;
+ case METHOD_ACCESS: buf.append("callout: ");break;
+ case FIELD_ACCESS: buf.append("callout-to-field: ");break;
+ }
+ buf.append('{');
+ buf.append(this.callinId);
+ buf.append("} ");
+ buf.append(this.boundClass);
+ buf.append('.');
+ buf.append(this.memberName);
+ buf.append(this.memberSignature);
+ return buf.toString();
+ }
+}
diff --git a/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/BytecodeProviderFactory.java b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/BytecodeProviderFactory.java
new file mode 100644
index 000000000..6f9a2b693
--- /dev/null
+++ b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/BytecodeProviderFactory.java
@@ -0,0 +1,35 @@
+/**********************************************************************
+ * This file is part of "Object Teams Dynamic Runtime Environment"
+ *
+ * Copyright 2009, 2012 Oliver Frank and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Please visit http://www.eclipse.org/objectteams for updates and contact.
+ *
+ * Contributors:
+ * Oliver Frank - Initial API and implementation
+ * Stephan Herrmann - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.objectteams.otredyn.bytecode;
+
+/**
+ * This class creates and provides a singleton instance of
+ * IBytecodeProvider.
+ * Actually it returns a instance of InMemeoryBytecodeProvider.
+ * In the future, this class should decides (e.g. by a system property),
+ * which BytecodeProvider should be used
+ * @author Oliver Frank
+ */
+public class BytecodeProviderFactory {
+ private static IBytecodeProvider instance;
+ public static synchronized IBytecodeProvider getBytecodeProvider() {
+ if (instance == null) {
+ instance = new InMemoryBytecodeProvider();
+ }
+ return instance;
+ }
+}
diff --git a/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/ClassRepository.java b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/ClassRepository.java
new file mode 100644
index 000000000..48bff216d
--- /dev/null
+++ b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/ClassRepository.java
@@ -0,0 +1,193 @@
+/**********************************************************************
+ * This file is part of "Object Teams Dynamic Runtime Environment"
+ *
+ * Copyright 2009, 2012 Oliver Frank and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Please visit http://www.eclipse.org/objectteams for updates and contact.
+ *
+ * Contributors:
+ * Oliver Frank - Initial API and implementation
+ * Stephan Herrmann - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.objectteams.otredyn.bytecode;
+
+import java.util.HashMap;
+import java.util.IdentityHashMap;
+import java.util.Map;
+
+import org.eclipse.objectteams.otredyn.bytecode.asm.AsmClassRepository;
+import org.eclipse.objectteams.otredyn.runtime.IClassRepository;
+import org.eclipse.objectteams.otredyn.runtime.TeamManager;
+
+/**
+ * This class creates and provides instances of
+ * AbstractBoundClass and AbstractTeam. It is the only
+ * instance that should do this. It is a singelton, thats
+ * why the constructor should not called directly.
+ * The instance is provided by getInstance.
+ * @author Oliver Frank
+ */
+public abstract class ClassRepository implements IClassRepository {
+ private static ClassRepository instance;
+
+ protected ClassRepository() {
+
+ }
+
+ /**
+ * Returns a singleton instance of the ClassRepository.
+ * @return
+ */
+ public static synchronized ClassRepository getInstance() {
+ if (instance == null) {
+ instance = new AsmClassRepository();
+ TeamManager.setup(instance);
+ }
+
+ return instance;
+ }
+
+ protected static final String ANONYMOUS_SUBCLASS_NAME = "AnonymousSubclass";
+
+ private Map<String, AbstractTeam> boundClassMap = new HashMap<String, AbstractTeam>();
+ private Map<AbstractBoundClass, AbstractBoundClass> anonymousSubclassMap = new IdentityHashMap<AbstractBoundClass, AbstractBoundClass>();
+
+ /**
+ * Returns a instance of AbstractBoundClass for the
+ * given FQN and id. If there is no instance it
+ * is created. The class have not to be loaded to get
+ * an instance of AbstractBoundClass representing this class.
+ * It guarantees, that it returns always the same
+ * instance for the same id. More formally:
+ * if id1.equals(id2) then getBoundClass(..., id1) == getBoundClass(id2)
+ * @param className the name of the class
+ * @param id a globally unique identifier for the class
+ * @return
+ */
+ public synchronized AbstractBoundClass getBoundClass(String className, String id, ClassLoader loader) {
+ AbstractTeam clazz = boundClassMap.get(id);
+ if (clazz == null) {
+ clazz = createClass(className, id, BytecodeProviderFactory.getBytecodeProvider(), loader);
+ boundClassMap.put(id, clazz);
+ }
+
+ return clazz;
+ }
+
+ /**
+ * Returns a instance of AbstractBoundClass for the
+ * given FQN and id and sets the bytecode for this class.
+ * If there is no instance it is created.
+ * This class should be called while loading the class.
+ * It guarantees, that it returns always the same
+ * instance for the same id. More formally:
+ * if id1.equals(id2) then getBoundClass(..., id1) == getBoundClass(..., id2)
+ * @param className the name of the class
+ * @param id a globally unique identifier for the class
+ * @return
+ */
+ public synchronized AbstractBoundClass getBoundClass(String className, String id, byte[] classBytes, ClassLoader loader)
+ {
+ AbstractTeam clazz = boundClassMap.get(id);
+ // set the bytecode in the BytecodeProvider
+ IBytecodeProvider bytecodeProvider = BytecodeProviderFactory.getBytecodeProvider();
+ bytecodeProvider.setBytecode(id, classBytes);
+ if (clazz == null) {
+ clazz = createClass(className, id, bytecodeProvider, loader);
+ }
+
+ boundClassMap.put(id, clazz);
+
+ clazz.setLoaded();
+
+ return clazz;
+ }
+
+ /**
+ * This method links a class with its superclass.
+ * It checks if the superclass was already loaded.
+ * If it was already loaded it merges this class with
+ * the anonymous subclass of its superclass
+ * @param clazz the subclass
+ */
+ public void linkClassWithSuperclass(AbstractBoundClass clazz) {
+ // FIXME(SH): also link with tsuper classes??
+ AbstractBoundClass superclass = clazz.getSuperclass();
+ AbstractBoundClass anonymousSubclass = null;
+ if (superclass != null) {
+ anonymousSubclass = anonymousSubclassMap.get(superclass);
+ }
+
+ //Is there an anonmous subclass, that corresponds with this class
+ if (anonymousSubclass != null) {
+ //Yes, so merge the tasks
+ AbstractBoundClass newAnonymousSubclass = createClass(ANONYMOUS_SUBCLASS_NAME,
+ ANONYMOUS_SUBCLASS_NAME,
+ BytecodeProviderFactory.getBytecodeProvider(),
+ clazz.getClassLoader());
+ superclass.removeSubclass(anonymousSubclass);
+ superclass.addSubclass(newAnonymousSubclass);
+ superclass.addSubclass(clazz);
+ newAnonymousSubclass.mergeTasks(anonymousSubclass);
+ clazz.mergeTasks(anonymousSubclass);
+ anonymousSubclass.performWiringTasks(superclass, clazz);
+ anonymousSubclassMap.put(superclass, newAnonymousSubclass);
+ }
+ }
+
+ /**
+ * Returns a instance of AbstractTeam for the
+ * given FQN and id. If there is no instance it
+ * is created.
+ * It guarantees, that it returns always the same
+ * instance for the same id. More formally:
+ * if id1.equals(id2) then getTeam(..., id1) == getTeam(..., id2).
+ * This method should only be called, if it is known
+ * that the name identifies a team and not a class.
+ * Otherwise call getBoundClass().isTeam() to check this.
+ * @param teamName the name of the team
+ * @param id a globally unique identifier for the team
+ * @return
+ */
+ public AbstractTeam getTeam(String teamName, String id, ClassLoader loader) {
+ return (AbstractTeam) getBoundClass(teamName, id, loader);
+ }
+
+ /**
+ * Returns a instance of AbstractBoundClass representing
+ * a anonymous subclass. A anonymous subclass stands for all subclasses,
+ * that are not known yet and stores the WeavingTasks inherited
+ * from the superclass. This class could not have got direct bindings.
+ * If a real subclass of its superclass is loaded all WeavingTasks are
+ * merged with the real subclass
+ * @param abstractBoundClass
+ * @return
+ */
+ protected AbstractBoundClass getAnonymousSubclass(
+ AbstractBoundClass abstractBoundClass) {
+ AbstractBoundClass anonymousSubclass = anonymousSubclassMap.get(abstractBoundClass);
+ if (anonymousSubclass == null) {
+ anonymousSubclass = createClass(ANONYMOUS_SUBCLASS_NAME,
+ ANONYMOUS_SUBCLASS_NAME,
+ BytecodeProviderFactory.getBytecodeProvider(),
+ abstractBoundClass.getClassLoader());
+ anonymousSubclass.setSuperClassName(abstractBoundClass.getName());
+ anonymousSubclassMap.put((AbstractTeam) abstractBoundClass, anonymousSubclass);
+ }
+ return anonymousSubclass;
+ }
+
+ /**
+ * Creates a instance of AbstractBoundClass and AbstracTeam
+ * @param name
+ * @param id
+ * @param bytecodeProvider
+ * @return
+ */
+ protected abstract AbstractTeam createClass(String name, String id, IBytecodeProvider bytecodeProvider, ClassLoader loader);
+}
diff --git a/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/Field.java b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/Field.java
new file mode 100644
index 000000000..617d20983
--- /dev/null
+++ b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/Field.java
@@ -0,0 +1,46 @@
+/**********************************************************************
+ * This file is part of "Object Teams Dynamic Runtime Environment"
+ *
+ * Copyright 2009, 2012 Oliver Frank and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Please visit http://www.eclipse.org/objectteams for updates and contact.
+ *
+ * Contributors:
+ * Oliver Frank - Initial API and implementation
+ * Stephan Herrmann - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.objectteams.otredyn.bytecode;
+
+import org.eclipse.objectteams.otredyn.runtime.IBoundClass;
+
+/**
+ * Represents a field of a class
+ * @author Oliver Frank
+ */
+public class Field extends Member {
+
+ public Field(String name, String signature) {
+ super(name, signature);
+ }
+
+ public Field(String name, String signature, boolean isStatic, int accessFlags) {
+ super(name, signature, isStatic, accessFlags);
+ }
+
+ /**
+ * Returns a globally unique id for the field
+ * @param clazz
+ * @return
+ */
+ @Override
+ public int getId(IBoundClass clazz) {
+ String key = null;
+ key = clazz.getId() + getName() + getSignature();
+ return getId(key);
+ }
+}
diff --git a/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/IBytecodeProvider.java b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/IBytecodeProvider.java
new file mode 100644
index 000000000..216a1f434
--- /dev/null
+++ b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/IBytecodeProvider.java
@@ -0,0 +1,43 @@
+/**********************************************************************
+ * This file is part of "Object Teams Dynamic Runtime Environment"
+ *
+ * Copyright 2009, 2012 Oliver Frank and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Please visit http://www.eclipse.org/objectteams for updates and contact.
+ *
+ * Contributors:
+ * Oliver Frank - Initial API and implementation
+ * Stephan Herrmann - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.objectteams.otredyn.bytecode;
+
+/**
+ * Interface for classes, that provide bytecode for other classes
+ * @author Oliver Frank
+ */
+public interface IBytecodeProvider {
+ /**
+ * Returns the bytecode of the class with the given id.
+ * Attention: This may be an expensive operation
+ * (e.g. if the bytecode must be read from the hard disk).
+ * @param classId
+ * @return the bytecode of the class or null, if the class
+ * was not loaded yet.
+ */
+ public byte[] getBytecode(String classId);
+
+ /**
+ * Sets the bytecode of the class with the given id
+ * in the BytecodeProvider
+ * Attention: This may be an expensive operation
+ * (e.g. if the bytecode is written to the hard disk).
+ * @param classId
+ * @param bytecode
+ */
+ public void setBytecode(String classId, byte[] bytecode);
+}
diff --git a/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/IRedefineStrategy.java b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/IRedefineStrategy.java
new file mode 100644
index 000000000..fd06f876e
--- /dev/null
+++ b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/IRedefineStrategy.java
@@ -0,0 +1,35 @@
+/**********************************************************************
+ * This file is part of "Object Teams Dynamic Runtime Environment"
+ *
+ * Copyright 2009, 2012 Oliver Frank and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Please visit http://www.eclipse.org/objectteams for updates and contact.
+ *
+ * Contributors:
+ * Oliver Frank - Initial API and implementation
+ * Stephan Herrmann - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.objectteams.otredyn.bytecode;
+
+import java.lang.instrument.UnmodifiableClassException;
+
+/**
+ * Classes that implements this interface can redefine classes at runtime.
+ * @author Oliver Frank
+ */
+public interface IRedefineStrategy {
+
+ /**
+ * Redefines a class at runtime.
+ * @param clazz the existing class instance
+ * @param bytecode the new bytecode for this class
+ * @throws ClassNotFoundException the class was not loaded yet
+ * @throws UnmodifiableClassException it is impossible to redefine the class
+ */
+ public void redefine(Class<?> clazz, byte[] bytecode) throws ClassNotFoundException, UnmodifiableClassException;
+}
diff --git a/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/InMemoryBytecodeProvider.java b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/InMemoryBytecodeProvider.java
new file mode 100644
index 000000000..57e9bb706
--- /dev/null
+++ b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/InMemoryBytecodeProvider.java
@@ -0,0 +1,51 @@
+/**********************************************************************
+ * This file is part of "Object Teams Dynamic Runtime Environment"
+ *
+ * Copyright 2009, 2012 Oliver Frank and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Please visit http://www.eclipse.org/objectteams for updates and contact.
+ *
+ * Contributors:
+ * Oliver Frank - Initial API and implementation
+ * Stephan Herrmann - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.objectteams.otredyn.bytecode;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * This class is an implementaion of IBytecodeProvider
+ * It keeps the bytecode of all classes in memory.
+ * @author Oliver Frank
+ */
+public class InMemoryBytecodeProvider implements IBytecodeProvider {
+
+ private Map<String, byte[]> bytecodeMap = new HashMap<String, byte[]>();
+
+ /**
+ * Returns the bytecode of a class with the given id.
+ * In this implementation, this is not an expensive operation.
+ * @return the bytecode of the class or null, if the class
+ * was not loaded yet.
+ */
+ public byte[] getBytecode(String className) {
+ return bytecodeMap.get(className);
+ }
+
+ /**
+ * Sets the bytecode of the class with the given id
+ * in the BytecodeProvider
+ * In this implementation, this is not an expensive operation.
+ * @param classId
+ * @param bytecode
+ */
+ public void setBytecode(String className, byte[] bytecode) {
+ bytecodeMap.put(className, bytecode);
+ }
+}
diff --git a/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/Member.java b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/Member.java
new file mode 100644
index 000000000..a017daf01
--- /dev/null
+++ b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/Member.java
@@ -0,0 +1,95 @@
+/**********************************************************************
+ * This file is part of "Object Teams Dynamic Runtime Environment"
+ *
+ * Copyright 2009, 2012 Oliver Frank and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Please visit http://www.eclipse.org/objectteams for updates and contact.
+ *
+ * Contributors:
+ * Oliver Frank - Initial API and implementation
+ * Stephan Herrmann - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.objectteams.otredyn.bytecode;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.objectteams.otredyn.runtime.IBoundClass;
+import org.eclipse.objectteams.otredyn.runtime.IMember;
+import org.objectweb.asm.Opcodes;
+
+/**
+ * Represents a member of a class.
+ * This class abstract. Instances of this class can only be created
+ * as {@link Field} or {@link Method}.
+ * @author Oliver Frank
+ */
+public abstract class Member implements IMember {
+
+ private static Map<String, Integer> idMap = new HashMap<String, Integer>();
+ private static int currentId = 0;
+
+ private String name;
+ private String signature;
+ private boolean isStatic;
+ private int accessFlags;
+
+ public Member(String name, String signature) {
+ this.name = name;
+ this.signature = signature;
+ }
+
+ public Member(String name, String signature, boolean isStatic, int accessFlags) {
+ this(name, signature);
+ this.isStatic = isStatic;
+ this.accessFlags = accessFlags;
+ }
+
+ public boolean isStatic() {
+ return isStatic;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String getSignature() {
+ return signature;
+ }
+
+ public void setStatic(boolean isStatic) {
+ this.isStatic = isStatic;
+ }
+
+ public boolean isPrivate() {
+ return (this.accessFlags & Opcodes.ACC_PRIVATE) != 0;
+ }
+
+ public int getAccessFlags() {
+ return this.accessFlags;
+ }
+
+ /**
+ * Returns a globally unique id for a given key.
+ * @param key
+ * @return
+ */
+ protected int getId(String key) {
+ Integer id = idMap.get(key);
+ if (id == null) {
+ synchronized (idMap) {
+ idMap.put(key, currentId);
+ return currentId++;
+ }
+ }
+
+ return id;
+ }
+
+ public abstract int getId(IBoundClass clazz);
+}
diff --git a/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/Method.java b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/Method.java
new file mode 100644
index 000000000..b988f511a
--- /dev/null
+++ b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/Method.java
@@ -0,0 +1,64 @@
+/**********************************************************************
+ * This file is part of "Object Teams Dynamic Runtime Environment"
+ *
+ * Copyright 2009, 2012 Oliver Frank and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Please visit http://www.eclipse.org/objectteams for updates and contact.
+ *
+ * Contributors:
+ * Oliver Frank - Initial API and implementation
+ * Stephan Herrmann - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.objectteams.otredyn.bytecode;
+
+import org.eclipse.objectteams.otredyn.runtime.IBoundClass;
+import org.eclipse.objectteams.otredyn.runtime.IMethod;
+
+
+/**
+ *
+ */
+public class Method extends Member implements IMethod {
+
+ private boolean implemented;
+
+ public Method(String name, String signature) {
+ super(name, signature);
+ }
+
+ public Method(String name, String signature, boolean isStatic, int accessFlags) {
+ super(name, signature, isStatic, accessFlags);
+ }
+
+ public boolean isImplemented() {
+ return implemented;
+ }
+
+ public void setImplemented(boolean implemented) {
+ this.implemented = implemented;
+ }
+
+ /**
+ * Returns a globally unique id for the method
+ * @param clazz
+ * @return
+ */
+ @Override
+ public int getId(IBoundClass clazz) {
+ String key = null;
+ // special treatment of private conflicts with test415_nonexistingBaseMethod3i
+ // see also AbstractBoundClass.handleTaskList()
+ if (/*isPrivate() ||*/ isStatic()) {
+ key = clazz.getId() + getName() + getSignature();
+ } else {
+ key = getName() + getSignature();
+ }
+
+ return getId(key);
+ }
+}
diff --git a/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/OtreRedefineStrategy.java b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/OtreRedefineStrategy.java
new file mode 100644
index 000000000..7f854cf7e
--- /dev/null
+++ b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/OtreRedefineStrategy.java
@@ -0,0 +1,36 @@
+/**********************************************************************
+ * This file is part of "Object Teams Dynamic Runtime Environment"
+ *
+ * Copyright 2009, 2012 Oliver Frank and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Please visit http://www.eclipse.org/objectteams for updates and contact.
+ *
+ * Contributors:
+ * Oliver Frank - Initial API and implementation
+ * Stephan Herrmann - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.objectteams.otredyn.bytecode;
+
+import java.lang.instrument.ClassDefinition;
+import java.lang.instrument.UnmodifiableClassException;
+
+import org.eclipse.objectteams.otredyn.transformer.jplis.otreAgent;
+
+/**
+ * This implementation of {@link IRedefineStrategy} uses the
+ * JPLIS agent {@link otreAgent} to redefine classes.
+ * @author Oliver Frank
+ */
+public class OtreRedefineStrategy implements IRedefineStrategy {
+
+ public void redefine(Class<?> clazz, byte[] bytecode) throws ClassNotFoundException, UnmodifiableClassException {
+ ClassDefinition arr_cd[] = { new ClassDefinition(clazz, bytecode) };
+ otreAgent.getInstrumentation().redefineClasses(arr_cd);
+ }
+
+}
diff --git a/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/RedefineStrategyFactory.java b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/RedefineStrategyFactory.java
new file mode 100644
index 000000000..93860b028
--- /dev/null
+++ b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/RedefineStrategyFactory.java
@@ -0,0 +1,37 @@
+/**********************************************************************
+ * This file is part of "Object Teams Dynamic Runtime Environment"
+ *
+ * Copyright 2009, 2012 Oliver Frank and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Please visit http://www.eclipse.org/objectteams for updates and contact.
+ *
+ * Contributors:
+ * Oliver Frank - Initial API and implementation
+ * Stephan Herrmann - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.objectteams.otredyn.bytecode;
+
+/**
+ * Provides a singleton instance of {@link IRedefineStrategy}.
+ * If no instance was set, this class returns the {@link OtreRedefineStrategy}
+ * @author Oliver Frank
+ */
+public class RedefineStrategyFactory {
+ private static IRedefineStrategy redefineStrategy;
+
+ public static IRedefineStrategy getRedefineStrategy() {
+ if (redefineStrategy == null) {
+ redefineStrategy = new OtreRedefineStrategy();
+ }
+ return redefineStrategy;
+ }
+
+ public static void setRedefineStrategy(IRedefineStrategy redefineStrategy) {
+ RedefineStrategyFactory.redefineStrategy = redefineStrategy;
+ }
+}
diff --git a/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/Types.java b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/Types.java
new file mode 100644
index 000000000..ed2435bb1
--- /dev/null
+++ b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/Types.java
@@ -0,0 +1,139 @@
+/**********************************************************************
+ * This file is part of "Object Teams Dynamic Runtime Environment"
+ *
+ * Copyright 2009, 2012 Oliver Frank and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Please visit http://www.eclipse.org/objectteams for updates and contact.
+ *
+ * Contributors:
+ * Oliver Frank - Initial API and implementation
+ * Stephan Herrmann - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.objectteams.otredyn.bytecode;
+
+/**
+ * Helper class to handle type strings used in the bytecode
+ * @author Oliver Frank
+ */
+public abstract class Types {
+ public final static int ACCESS_PACKAGE = 0; // class, field, method
+ public final static int ACCESS_PUBLIC = 1; // class, field, method
+ public final static int ACCESS_PRIVATE = 2; // class, field, method
+ public final static int ACCESS_PROTECTED = 4; // class, field, method
+ public final static int ACCESS_STATIC = 8; // field, method
+ public final static int TEAM = 0x8000;
+ public final static int ROLE_FLAG = 2; // within OTClassFlags attribute
+
+ public static final String VOID = "V";
+
+ public static final String BOOLEAN = "Z";
+
+ public static final String CHAR = "C";
+
+ public static final String BYTE = "B";
+
+ public static final String SHORT = "S";
+
+ public static final String INT = "I";
+
+ public static final String FLOAT = "F";
+
+ public static final String LONG = "J";
+
+ public static final String DOUBLE = "D";
+
+ private static final String ARRAY = "[";
+
+ public static String getAsArrayType(String className) {
+ if (className.length() == 1) {
+ return ARRAY + className;
+ }
+
+ return ARRAY + "L" + className;
+ }
+
+ public static String getAsType(String type) {
+ return "L" + type;
+ }
+
+ public static String getAsType(Class<?> clazz) {
+ String type = null;
+ if (clazz.isPrimitive()) {
+ String name = clazz.getName();
+ if (name.compareTo("void") == 0) {
+ type = VOID;
+ } else if (name.compareTo("boolean") == 0) {
+ type = BOOLEAN;
+ } else if (name.compareTo("char") == 0) {
+ type = CHAR;
+ } else if (name.compareTo("byte") == 0) {
+ type = BYTE;
+ } else if (name.compareTo("short") == 0) {
+ type = SHORT;
+ } else if (name.compareTo("int") == 0) {
+ type = INT;
+ } else if (name.compareTo("float") == 0) {
+ type = FLOAT;
+ } else if (name.compareTo("long") == 0) {
+ type = LONG;
+ } else if (name.compareTo("double") == 0) {
+ type = DOUBLE;
+ }
+ } else {
+ type = clazz.getName().replace('.', '/');
+ if (!clazz.isArray()) {
+ type = "L" + type;
+ }
+ }
+
+ return type;
+ }
+
+ public static String getTypeStringForMethod(String returnType, String[] paramTypes) {
+ String result = "(";
+ if (paramTypes != null) {
+ for (String paramType : paramTypes) {
+ result += paramType;
+ if (paramType.length() > 2) {
+ result += ";";
+ }
+ }
+ }
+ result += ")" + returnType;
+ if (returnType.length() > 2) {
+ result += ";";
+ }
+ return result;
+ }
+
+ public static String getTypeStringForMethod(Class<?> returnType, Class<?>[] paramTypes) {
+ String result = "(";
+ if (paramTypes != null) {
+ for (Class<?> paramType : paramTypes) {
+ String paramTypeString = getAsType(paramType);
+ result += paramTypeString;
+ if (!paramType.isPrimitive() && !paramType.isArray()) {
+ result += ";";
+ }
+ }
+ }
+ String returnTypeString = getAsType(returnType);
+
+ result += ")" + returnTypeString;
+ if (!returnType.isPrimitive() && !returnType.isArray()) {
+ result += ";";
+ }
+ return result;
+ }
+
+ public static String getTypeStringForField(String type) {
+ return type + ";";
+ }
+
+
+}
diff --git a/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/AbstractCreateDispatchCodeAdapter.java b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/AbstractCreateDispatchCodeAdapter.java
new file mode 100644
index 000000000..449222e98
--- /dev/null
+++ b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/AbstractCreateDispatchCodeAdapter.java
@@ -0,0 +1,154 @@
+/**********************************************************************
+ * This file is part of "Object Teams Dynamic Runtime Environment"
+ *
+ * Copyright 2009, 2012 Oliver Frank and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Please visit http://www.eclipse.org/objectteams for updates and contact.
+ *
+ * Contributors:
+ * Oliver Frank - Initial API and implementation
+ * Stephan Herrmann - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.objectteams.otredyn.bytecode.asm;
+
+import org.eclipse.objectteams.otredyn.transformer.names.ClassNames;
+import org.eclipse.objectteams.otredyn.transformer.names.ConstantMembers;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+import org.objectweb.asm.tree.AbstractInsnNode;
+import org.objectweb.asm.tree.InsnList;
+import org.objectweb.asm.tree.InsnNode;
+import org.objectweb.asm.tree.IntInsnNode;
+import org.objectweb.asm.tree.JumpInsnNode;
+import org.objectweb.asm.tree.LabelNode;
+import org.objectweb.asm.tree.MethodInsnNode;
+import org.objectweb.asm.tree.MethodNode;
+import org.objectweb.asm.tree.TypeInsnNode;
+
+/**
+ * Create the code for the dispatch from a base class to the teams. <br/> <br/>
+ * The code was generated as follows: <br/>
+ * <code>
+ * switch (boundMethodId) { // this was generated in CreateSwitchAdapter <br/>
+ * ... <br/>
+ * case (...): // this was generated in concrete implementations <br/>
+ * // of this abstract class <br/>
+ * Teams[] teams = TeamManager.getTeams(joinpointId) <br/><br/>
+ * if (teams == null) { <br/>
+ * break; <br/>
+ * } <br/>
+ * <br/>
+ * Team t = teams[0]; <br/>
+ * int[] callinIds = TeamManager.getCallinIds(joinpointId); <br/>
+ * Object[] args = {arg1, ... , argn};
+ * return team._OT$callAllBindings(this, teams, 0, callinIds, boundMethodId, args);
+ * } <br/>
+ * </code>
+ * @author Oliver Frank
+ */
+public abstract class AbstractCreateDispatchCodeAdapter extends
+ AbstractTransformableClassNode {
+
+ private boolean isStatic;
+
+ public AbstractCreateDispatchCodeAdapter(boolean isStatic) {
+ this.isStatic = isStatic;
+ }
+
+ private Type[] args;
+
+ protected InsnList getDispatchCode(MethodNode method, int joinPointId,
+ int boundMethodId) {
+ InsnList instructions = new InsnList();
+
+ // teams = TeamManager.getTeams(joinpointId)
+ instructions.add(createLoadIntConstant(joinPointId));
+
+ instructions.add(new MethodInsnNode(Opcodes.INVOKESTATIC,
+ ClassNames.TEAM_MANAGER_SLASH, ConstantMembers.getTeams.getName(),
+ ConstantMembers.getTeams.getSignature()));
+
+ instructions.add(createInstructionsToCheackTeams(method));
+
+ // get the first team
+ instructions.add(new InsnNode(Opcodes.DUP));
+ instructions.add(new InsnNode(Opcodes.ICONST_0));
+ instructions.add(new InsnNode(Opcodes.AALOAD));
+ instructions.add(new InsnNode(Opcodes.SWAP));
+ if (isStatic) {
+ instructions.add(new InsnNode(Opcodes.ACONST_NULL));
+ } else {
+ // put "this" on the stack and cast it to IBoundBase
+ instructions.add(new IntInsnNode(Opcodes.ALOAD, 0));
+ instructions.add(new TypeInsnNode(Opcodes.CHECKCAST,
+ ClassNames.I_BOUND_BASE_SLASH));
+ }
+ instructions.add(new InsnNode(Opcodes.SWAP));
+ // start index
+ instructions.add(new InsnNode(Opcodes.ICONST_0));
+
+ // TeamManager.getCallinIds(joinpointId)
+ instructions.add(createLoadIntConstant(joinPointId));
+
+ instructions
+ .add(new MethodInsnNode(Opcodes.INVOKESTATIC,
+ ClassNames.TEAM_MANAGER_SLASH,
+ ConstantMembers.getCallinIds.getName(),
+ ConstantMembers.getCallinIds.getSignature()));
+
+ instructions.add(createLoadIntConstant(boundMethodId));
+ args = Type.getArgumentTypes(method.desc);
+
+ // box the arguments
+ instructions.add(getBoxedArguments(args));
+
+ instructions.add(new MethodInsnNode(Opcodes.INVOKEINTERFACE,
+ ClassNames.ITEAM_SLASH, ConstantMembers.callAllBindingsTeam
+ .getName(), ConstantMembers.callAllBindingsTeam
+ .getSignature()));
+
+ Type returnType = Type.getReturnType(method.desc);
+ instructions.add(getUnboxingInstructionsForReturnValue(returnType));
+
+ return instructions;
+ }
+
+ protected InsnList createInstructionsToCheackTeams(MethodNode method) {
+ // if (teams == null) {
+ // break;
+ // }
+ InsnList instructions = new InsnList();
+ instructions.add(new InsnNode(Opcodes.DUP));
+ LabelNode label = new LabelNode();
+ instructions.add(new JumpInsnNode(Opcodes.IFNONNULL, label));
+ instructions.add(new InsnNode(Opcodes.POP));
+ instructions.add(new JumpInsnNode(Opcodes.GOTO, findBreakLabel(method.instructions)));
+ instructions.add(label);
+ return instructions;
+ }
+
+ private LabelNode findBreakLabel(InsnList instructions) {
+ for (int i = instructions.size() - 1; i >= 0; i--) {
+ AbstractInsnNode node = instructions.get(i);
+ if (node.getType() == AbstractInsnNode.LABEL) {
+ return (LabelNode) node;
+ }
+ }
+ throw new RuntimeException("Can't find break label to create dispatch code");
+ }
+
+ protected abstract InsnList getBoxedArguments(Type[] args);
+
+ protected int getMaxLocals() {
+ return args.length + 1;
+ }
+
+ protected int getMaxStack() {
+ return 10;
+ }
+}
diff --git a/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/AbstractTransformableClassNode.java b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/AbstractTransformableClassNode.java
new file mode 100644
index 000000000..e964657a4
--- /dev/null
+++ b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/AbstractTransformableClassNode.java
@@ -0,0 +1,272 @@
+/**********************************************************************
+ * This file is part of "Object Teams Dynamic Runtime Environment"
+ *
+ * Copyright 2009, 2012 Oliver Frank and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Please visit http://www.eclipse.org/objectteams for updates and contact.
+ *
+ * Contributors:
+ * Oliver Frank - Initial API and implementation
+ * Stephan Herrmann - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.objectteams.otredyn.bytecode.asm;
+
+import java.util.List;
+import java.util.ListIterator;
+
+import org.eclipse.objectteams.otredyn.bytecode.Method;
+import org.eclipse.objectteams.otredyn.transformer.names.ClassNames;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+import org.objectweb.asm.tree.AbstractInsnNode;
+import org.objectweb.asm.tree.ClassNode;
+import org.objectweb.asm.tree.FieldInsnNode;
+import org.objectweb.asm.tree.InsnList;
+import org.objectweb.asm.tree.InsnNode;
+import org.objectweb.asm.tree.IntInsnNode;
+import org.objectweb.asm.tree.LabelNode;
+import org.objectweb.asm.tree.LdcInsnNode;
+import org.objectweb.asm.tree.LookupSwitchInsnNode;
+import org.objectweb.asm.tree.MethodInsnNode;
+import org.objectweb.asm.tree.MethodNode;
+import org.objectweb.asm.tree.TypeInsnNode;
+
+/**
+ * Every class, that wants to manipulate the bytecode of a class
+ * with the ASM Trea API, have to inherit from this class and do
+ * the transformations in the method transform().
+ * Additionally the class provides util methods to
+ * manipulate the bytecode
+ * @author Oliver Frank
+ */
+public abstract class AbstractTransformableClassNode extends ClassNode {
+
+ /**
+ * Returns instructions, that are needed to pack all arguments of a method
+ * in an {@link Object} Array
+ * @param args The Types of the arguments
+ * @param isStatic is this method static or not
+ * @return
+ */
+ protected InsnList getBoxingInstructions(Type[] args, boolean isStatic) {
+ int firstArgIndex = 1;
+ if (isStatic) {
+ firstArgIndex = 0;
+ }
+ InsnList instructions = new InsnList();
+ instructions.add(createLoadIntConstant(args.length));
+ instructions.add(new TypeInsnNode(Opcodes.ANEWARRAY,
+ ClassNames.OBJECT_SLASH));
+ for (int i=0, slot=0; i < args.length; slot += args[i++].getSize()) {
+ instructions.add(new InsnNode(Opcodes.DUP));
+ instructions.add(createLoadIntConstant(i));
+ instructions.add(new IntInsnNode(args[i].getOpcode(Opcodes.ILOAD),
+ slot + firstArgIndex));
+ if (args[i].getSort() != Type.OBJECT
+ && args[i].getSort() != Type.ARRAY) {
+ instructions.add(AsmTypeHelper
+ .getBoxingInstructionForType(args[i]));
+ }
+ instructions.add(new InsnNode(Opcodes.AASTORE));
+ }
+
+ return instructions;
+ }
+
+ /**
+ * Returns the instructions, that are needed to convert
+ * a return value of the type {@link Object} to the real type
+ * @param returnType the real type
+ * @return
+ */
+ protected InsnList getUnboxingInstructionsForReturnValue(Type returnType) {
+ InsnList instructions = new InsnList();
+ switch (returnType.getSort()) {
+ case Type.VOID:
+ instructions.add(new InsnNode(Opcodes.POP));
+ instructions.add(new InsnNode(Opcodes.RETURN));
+ break;
+ case Type.ARRAY: // fallthrough
+ case Type.OBJECT:
+ instructions.add(new TypeInsnNode(Opcodes.CHECKCAST, returnType
+ .getInternalName()));
+ instructions.add(new InsnNode(Opcodes.ARETURN));
+ break;
+ default:
+ String objectType = AsmTypeHelper.getObjectType(returnType);
+ instructions.add(new TypeInsnNode(Opcodes.CHECKCAST, objectType));
+ instructions.add(AsmTypeHelper.getUnboxingInstructionForType(
+ returnType, objectType));
+ instructions
+ .add(new InsnNode(returnType.getOpcode(Opcodes.IRETURN)));
+ }
+ return instructions;
+ }
+
+ /**
+ * Adds a new Label to an existing switch statement
+ * @param instructions the instructions, in which the switch statement is defined
+ * @param newInstructions the instructions of the new label
+ * @param labelIndex the index of the label
+ */
+ @SuppressWarnings("unchecked")
+ protected void addNewLabelToSwitch(InsnList instructions,
+ InsnList newInstructions, int labelIndex) {
+ ListIterator<AbstractInsnNode> iter = instructions.iterator();
+ LookupSwitchInsnNode lSwitch = null;
+ while (iter.hasNext()) {
+ AbstractInsnNode node = (AbstractInsnNode) iter.next();
+ if (node.getType() == AbstractInsnNode.LOOKUPSWITCH_INSN) {
+ lSwitch = (LookupSwitchInsnNode) node;
+ LabelNode label = new LabelNode();
+ boolean labelAdded = false;
+ for (int i = 0; i < lSwitch.keys.size(); i++) {
+ Integer key = (Integer) lSwitch.keys.get(i);
+ if (key >= labelIndex) {
+ lSwitch.keys.add(i, labelIndex);
+ lSwitch.labels.add(i, label);
+ labelAdded = true;
+ break;
+ }
+ }
+ if (!labelAdded) {
+ lSwitch.labels.add(label);
+ lSwitch.keys.add(labelIndex);
+ }
+ boolean foundDefLabel = false;
+ AbstractInsnNode prevNode = node;
+ while (iter.hasNext()) {
+ node = (AbstractInsnNode) iter.next();
+ if (node.getType() == AbstractInsnNode.LABEL) {
+ if (!foundDefLabel) {
+ foundDefLabel = true;
+ } else {
+ break;
+ }
+ }
+ prevNode = node;
+ }
+ instructions.insert(prevNode, label);
+ instructions.insert(label, newInstructions);
+ }
+ }
+ if (lSwitch == null) {
+ throw new RuntimeException("No switch statement found.");
+ }
+ }
+
+ /**
+ * Returns a {@link MethodNode} for a given {@link Method} instance
+ * @param method
+ * @return the {@link MethodNode} or null if there is no such method
+ */
+ @SuppressWarnings("unchecked")
+ protected MethodNode getMethod(Method method) {
+ List<MethodNode> methodList = methods;
+ for (MethodNode methodNode : methodList) {
+ if (methodNode.name.compareTo(method.getName()) == 0
+ && methodNode.desc.compareTo(method.getSignature()) == 0) {
+ return methodNode;
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * This method could be used to generate debug outputs in the generated code in the form: <br>
+ * <code>
+ * Sytsem.out.println(message);
+ * </code>
+ * @param message
+ * @return
+ */
+ protected InsnList getInstructionsForDebugOutput(String message) {
+ InsnList instructions = new InsnList();
+ instructions.add(new FieldInsnNode(Opcodes.GETSTATIC,
+ "java/lang/System", "out", "Ljava/io/PrintStream;"));
+ instructions.add(new LdcInsnNode(message));
+ instructions.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL,
+ "java/io/PrintStream", "println", "(Ljava/lang/String;)V"));
+ return instructions;
+ }
+
+ /**
+ * Adds instructions to put all arguments of a method on the stack.
+ * @param instructions
+ * @param args
+ * @param isStatic
+ */
+ protected void addInstructionsForLoadArguments(InsnList instructions, Type[] args, boolean isStatic) {
+ int firstArgIndex = 1;
+ if (isStatic) {
+ firstArgIndex = 0;
+ }
+ // put "this" on the stack for an non-static method
+ if (!isStatic) {
+ instructions.add(new IntInsnNode(Opcodes.ALOAD, 0));
+ }
+ for (int i=0, slot=firstArgIndex; i < args.length; slot+=args[i++].getSize()) {
+ instructions.add(new IntInsnNode(args[i].getOpcode(Opcodes.ILOAD),
+ slot));
+ }
+ }
+
+ /**
+ * Replace all return statements in the given instructions with new
+ * statements that convert the real return value to {@link Object}
+ * and return this new {@link Object}
+ *
+ * @param instructions
+ * @param returnType
+ */
+ @SuppressWarnings("unchecked")
+ protected void replaceReturn(InsnList instructions, Type returnType) {
+ if (returnType.getSort() != Type.OBJECT &&
+ returnType.getSort() != Type.ARRAY &&
+ returnType.getSort() != Type.VOID) {
+ ListIterator<AbstractInsnNode> orgMethodIter = instructions.iterator();
+ while (orgMethodIter.hasNext()) {
+ AbstractInsnNode orgMethodNode = orgMethodIter.next();
+ if (orgMethodNode.getOpcode() == returnType.getOpcode(Opcodes.IRETURN)) {
+ instructions.remove(orgMethodNode);
+ instructions.add(AsmTypeHelper.getBoxingInstructionForType(returnType));
+ instructions.add(new InsnNode(Opcodes.ARETURN));
+ }
+ }
+ } else if (returnType.getSort() == Type.VOID) {
+ ListIterator<AbstractInsnNode> orgMethodIter = instructions.iterator();
+ while (orgMethodIter.hasNext()) {
+ AbstractInsnNode orgMethodNode = orgMethodIter.next();
+ if (orgMethodNode.getOpcode() == Opcodes.RETURN) {
+ instructions.remove(orgMethodNode);
+ }
+ }
+ instructions.add(new InsnNode(Opcodes.ACONST_NULL));
+ instructions.add(new InsnNode(Opcodes.ARETURN));
+ }
+ }
+
+ /**
+ * Create an instruction for loading an integer constant,
+ * using the most compact possible format.
+ */
+ protected AbstractInsnNode createLoadIntConstant(int constant) {
+ if (constant <= 5)
+ return new InsnNode(Opcodes.ICONST_0+constant);
+ else if (constant < Byte.MAX_VALUE)
+ return new IntInsnNode(Opcodes.BIPUSH, constant);
+ else
+ return new LdcInsnNode(constant);
+ }
+ /**
+ * In this method, concrete Implementations of this class
+ * can manipulate the bytecode
+ */
+ protected abstract void transform();
+}
diff --git a/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/AddEmptyMethodAdapter.java b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/AddEmptyMethodAdapter.java
new file mode 100644
index 000000000..56a2a5566
--- /dev/null
+++ b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/AddEmptyMethodAdapter.java
@@ -0,0 +1,95 @@
+/**********************************************************************
+ * This file is part of "Object Teams Dynamic Runtime Environment"
+ *
+ * Copyright 2009, 2012 Oliver Frank and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Please visit http://www.eclipse.org/objectteams for updates and contact.
+ *
+ * Contributors:
+ * Oliver Frank - Initial API and implementation
+ * Stephan Herrmann - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.objectteams.otredyn.bytecode.asm;
+
+import org.objectweb.asm.ClassAdapter;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+
+/**
+ * This class adds an method only with a return statement
+ * to the bytecode of a class with the ASM Core API
+ * @author Oliver Frank
+ */
+class AddEmptyMethodAdapter extends ClassAdapter {
+
+ private int access;
+ private String name;
+ private String desc;
+ private String signature;
+ private String[] exceptions;
+ private int maxLocals;
+
+ public AddEmptyMethodAdapter(ClassVisitor cv, String name, int access,
+ String desc, String[] exceptions, String signature,
+ int maxLocals) {
+ super(cv);
+ this.access = access;
+ this.desc = desc;
+ this.exceptions = exceptions;
+ this.name = name;
+ this.signature = signature;
+ this.maxLocals = maxLocals;
+ }
+
+ @Override
+ public void visitEnd() {
+ MethodVisitor mv = cv.visitMethod(access, name, desc, signature, exceptions);
+ if ((this.access & Opcodes.ACC_ABSTRACT) != 0) {
+ mv.visitEnd();
+ return;
+ }
+ mv.visitCode();
+ Type returnType = Type.getReturnType(this.desc);
+ switch (returnType.getSort()) {
+ case Type.VOID:
+ mv.visitInsn(Opcodes.RETURN);
+ break;
+ case Type.INT:
+ case Type.BOOLEAN:
+ case Type.CHAR:
+ case Type.BYTE:
+ case Type.SHORT:
+ mv.visitInsn(Opcodes.ICONST_1);
+ mv.visitInsn(Opcodes.IRETURN);
+ break;
+ case Type.FLOAT:
+ mv.visitInsn(Opcodes.FCONST_1);
+ mv.visitInsn(Opcodes.FRETURN);
+ break;
+ case Type.LONG:
+ mv.visitInsn(Opcodes.LCONST_1);
+ mv.visitInsn(Opcodes.LRETURN);
+ break;
+ case Type.DOUBLE:
+ case Type.OBJECT:
+ case Type.ARRAY:
+ mv.visitInsn(Opcodes.ACONST_NULL);
+ mv.visitInsn(Opcodes.ARETURN);
+ break;
+ }
+ mv.visitMaxs(1, maxLocals);
+ mv.visitEnd();
+ }
+
+ @Override
+ public MethodVisitor visitMethod(int arg0, String arg1, String arg2, String arg3, String[] arg4) {
+ return null; // also consider other visitors
+ }
+} \ No newline at end of file
diff --git a/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/AddFieldAdapter.java b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/AddFieldAdapter.java
new file mode 100644
index 000000000..cd1141e35
--- /dev/null
+++ b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/AddFieldAdapter.java
@@ -0,0 +1,52 @@
+/**********************************************************************
+ * This file is part of "Object Teams Dynamic Runtime Environment"
+ *
+ * Copyright 2009, 2012 Oliver Frank and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Please visit http://www.eclipse.org/objectteams for updates and contact.
+ *
+ * Contributors:
+ * Oliver Frank - Initial API and implementation
+ * Stephan Herrmann - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.objectteams.otredyn.bytecode.asm;
+
+import org.objectweb.asm.ClassAdapter;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.FieldVisitor;
+import org.objectweb.asm.MethodVisitor;
+
+/**
+ * Adds an field to the bytecode of a class
+ * @author Oliver Frank
+ */
+class AddFieldAdapter extends ClassAdapter {
+
+ private int access;
+ private String name;
+ private String desc;
+
+ public AddFieldAdapter(ClassVisitor cv, String name, int access,
+ String desc) {
+ super(cv);
+ this.access = access;
+ this.desc = desc;
+ this.name = name;
+ }
+
+ @Override
+ public void visitEnd() {
+ FieldVisitor fv = cv.visitField(access, name, desc, null, null);
+ fv.visitEnd();
+ }
+
+ @Override
+ public MethodVisitor visitMethod(int arg0, String arg1, String arg2, String arg3, String[] arg4) {
+ return null; // also consider other visitors
+ }
+} \ No newline at end of file
diff --git a/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/AddInterfaceAdapter.java b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/AddInterfaceAdapter.java
new file mode 100644
index 000000000..7115028a2
--- /dev/null
+++ b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/AddInterfaceAdapter.java
@@ -0,0 +1,49 @@
+/**********************************************************************
+ * This file is part of "Object Teams Dynamic Runtime Environment"
+ *
+ * Copyright 2009, 2012 Oliver Frank and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Please visit http://www.eclipse.org/objectteams for updates and contact.
+ *
+ * Contributors:
+ * Oliver Frank - Initial API and implementation
+ * Stephan Herrmann - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.objectteams.otredyn.bytecode.asm;
+
+import org.objectweb.asm.ClassAdapter;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.MethodVisitor;
+
+/**
+ * Adds an interface to the bytecode of a class
+ * @author Oliver Frank
+ *
+ */
+public class AddInterfaceAdapter extends ClassAdapter{
+ private String interfaceName;
+
+ public AddInterfaceAdapter(ClassVisitor cv, String interfaceName) {
+ super(cv);
+ this.interfaceName = interfaceName;
+ }
+
+ @Override
+ public void visit(int version, int access, String name, String signature,
+ String superName, String[] interfaces) {
+ String[] newInterfaces = new String[interfaces.length + 1];
+ System.arraycopy(interfaces, 0, newInterfaces, 0, interfaces.length);
+ newInterfaces[interfaces.length] = interfaceName;
+ super.visit(version, access, name, signature, superName, newInterfaces);
+ }
+
+ @Override
+ public MethodVisitor visitMethod(int arg0, String arg1, String arg2, String arg3, String[] arg4) {
+ return null; // also consider other visitors
+ }
+}
diff --git a/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/AsmBoundClass.java b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/AsmBoundClass.java
new file mode 100644
index 000000000..31afa82d3
--- /dev/null
+++ b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/AsmBoundClass.java
@@ -0,0 +1,163 @@
+/**********************************************************************
+ * This file is part of "Object Teams Dynamic Runtime Environment"
+ *
+ * Copyright 2009, 2012 Oliver Frank and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Please visit http://www.eclipse.org/objectteams for updates and contact.
+ *
+ * Contributors:
+ * Oliver Frank - Initial API and implementation
+ * Stephan Herrmann - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.objectteams.otredyn.bytecode.asm;
+
+import org.eclipse.objectteams.otredyn.bytecode.AbstractBoundClass;
+import org.eclipse.objectteams.otredyn.bytecode.AbstractTeam;
+import org.eclipse.objectteams.otredyn.bytecode.Binding;
+import org.eclipse.objectteams.otredyn.bytecode.IBytecodeProvider;
+import org.objectweb.asm.ClassReader;
+
+/**
+ * This class implements the bytecode parsing for {@link AbstractBoundClass}.
+ * It parses the bytecode with ASM.
+ * @author Oliver Frank
+ */
+abstract class AsmBoundClass extends AbstractTeam {
+
+ private boolean parsed;
+ private IBytecodeProvider bytecodeProvider;
+
+ /**
+ * just a temporary cache for the bytecode
+ */
+ private byte[] bytecode;
+
+ /**
+ * ordered list of qualified callin labels
+ */
+ public String[] precedences;
+
+ protected AsmBoundClass(String name, String id, IBytecodeProvider bytecodeProvider, ClassLoader loader) {
+ super(name, id, loader);
+ this.bytecodeProvider = bytecodeProvider;
+ }
+
+ /**
+ * Parses the bytecode of a class and uses the set/add... Methods (e.g. addMethod)
+ * of {@link AbstractBoundClass} to set the information
+ */
+ @Override
+ protected synchronized void parseBytecode() {
+ if (parsed) {
+ // Already parsed, nothing to do
+ return;
+ }
+
+ bytecode = bytecodeProvider.getBytecode(getId());
+ if (bytecode == null) {
+ //Class is not loaded yet.
+ return;
+ }
+
+ // Don't parse another time
+ parsed = true;
+ AsmClassVisitor cv = new AsmClassVisitor(this);
+ ClassReader cr = null;
+ cr = new ClassReader(bytecode);
+
+ cr.accept(cv, Attributes.attributes, 0);
+
+ //release the bytecode
+ bytecode = null;
+ }
+
+ /**
+ * Returns the bytecode of this class and cache it temporary.
+ * This method is only needed, if getBytecode of the {@link IBytecodeProvider}
+ * is an expensive operation.
+ * @return
+ */
+ protected byte[] allocateAndGetBytecode() {
+ if (bytecode == null) {
+ bytecode = getBytecode();
+ }
+ return bytecode;
+ }
+
+ /**
+ * Get the bytecode directly from the {@link IBytecodeProvider}.
+ * This method can be used, if getBytecode of the {@link IBytecodeProvider}
+ * is not an expensive operation.
+ * @return
+ */
+ @Override
+ public byte[] getBytecode() {
+ return bytecodeProvider.getBytecode(getId());
+ }
+
+ /**
+ * Releases the bytecode, if it's cached, an set it in the {@link IBytecodeProvider}
+ */
+ protected void releaseBytecode() {
+ bytecodeProvider.setBytecode(getId(), bytecode);
+ bytecode = null;
+ }
+
+ /**
+ * Returns the {@link IBytecodeProvider} used for this class
+ * @return
+ */
+ protected IBytecodeProvider getBytecodeProvider() {
+ return bytecodeProvider;
+ }
+
+ /**
+ * Sets the bytecode.
+ * If the bytecode is temporary cached, the cache is used.
+ * Otherwise this method give the bytecode directly to the {@link IBytecodeProvider}
+ * @param bytecode
+ */
+ protected void setBytecode(byte[] bytecode) {
+ //Is the bytecode temporary cached?
+ if (this.bytecode == null) {
+ // no, then save the bytecode directly in the bytecode provider
+ bytecodeProvider.setBytecode(getId(), bytecode);
+ } else {
+ // yes, then use the cache
+ this.bytecode = bytecode;
+ }
+ }
+
+ public int compare(String callinLabel1, String callinLabel2) {
+ boolean label1Seen = false, label2Seen = false;
+ if (this.precedences != null) {
+ for (String label : this.precedences) {
+ if (label.equals(callinLabel1)) {
+ if (label2Seen)
+ return -1; // saw two then one: one has lower priority than two
+ label1Seen = true;
+ } else if (label.equals(callinLabel2)) {
+ if (label1Seen)
+ return 1; // saw one then two: one has higher priority than two
+ label2Seen = true;
+ }
+ }
+ }
+ AbstractBoundClass enclosingClass = getEnclosingClass();
+ if (enclosingClass != null) {
+ String singleName = getInternalName();
+ int pos = singleName.lastIndexOf('$');
+ singleName = singleName.substring(pos+1);
+ if (singleName.startsWith("__OT__"))
+ singleName = singleName.substring("__OT__".length());
+ // check for precedence at outer level:
+ return enclosingClass.compare(singleName+'.'+callinLabel1, singleName+'.'+callinLabel2);
+ }
+ return callinLabel1.compareTo(callinLabel2);
+ }
+}
diff --git a/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/AsmClassRepository.java b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/AsmClassRepository.java
new file mode 100644
index 000000000..2b062ad17
--- /dev/null
+++ b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/AsmClassRepository.java
@@ -0,0 +1,35 @@
+/**********************************************************************
+ * This file is part of "Object Teams Dynamic Runtime Environment"
+ *
+ * Copyright 2009, 2012 Oliver Frank and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Please visit http://www.eclipse.org/objectteams for updates and contact.
+ *
+ * Contributors:
+ * Oliver Frank - Initial API and implementation
+ * Stephan Herrmann - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.objectteams.otredyn.bytecode.asm;
+
+import org.eclipse.objectteams.otredyn.bytecode.AbstractTeam;
+import org.eclipse.objectteams.otredyn.bytecode.ClassRepository;
+import org.eclipse.objectteams.otredyn.bytecode.IBytecodeProvider;
+
+
+/**
+ * Creates Instances of {@link AsmWritableBoundClass} as {@link AbstractTeam}
+ * @author Oliver Frank
+ */
+public class AsmClassRepository extends ClassRepository {
+
+
+ @Override
+ protected AbstractTeam createClass(String name, String id, IBytecodeProvider bytecodeProvider, ClassLoader loader) {
+ return new AsmWritableBoundClass(name, id, bytecodeProvider, loader);
+ }
+}
diff --git a/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/AsmClassVisitor.java b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/AsmClassVisitor.java
new file mode 100644
index 000000000..a54d4205c
--- /dev/null
+++ b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/AsmClassVisitor.java
@@ -0,0 +1,130 @@
+/**********************************************************************
+ * This file is part of "Object Teams Dynamic Runtime Environment"
+ *
+ * Copyright 2009, 2012 Oliver Frank and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Please visit http://www.eclipse.org/objectteams for updates and contact.
+ *
+ * Contributors:
+ * Oliver Frank - Initial API and implementation
+ * Stephan Herrmann - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.objectteams.otredyn.bytecode.asm;
+
+import org.eclipse.objectteams.otredyn.bytecode.Binding;
+import org.eclipse.objectteams.otredyn.bytecode.Types;
+import org.eclipse.objectteams.otredyn.bytecode.asm.Attributes.CallinBindingsAttribute;
+import org.eclipse.objectteams.otredyn.bytecode.asm.Attributes.OTClassFlagsAttribute;
+import org.eclipse.objectteams.otredyn.bytecode.asm.Attributes.CallinBindingsAttribute.MultiBinding;
+import org.eclipse.objectteams.otredyn.bytecode.asm.Attributes.CallinPrecedenceAttribute;
+import org.eclipse.objectteams.otredyn.bytecode.asm.Attributes.OTSpecialAccessAttribute;
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.Attribute;
+import org.objectweb.asm.FieldVisitor;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.commons.EmptyVisitor;
+
+/**
+ * This class is used to parse the bytecode of a class.
+ * It sets the informations, that are parsed, in the {@link AsmBoundClass}
+ * @author Oliver Frank
+ */
+class AsmClassVisitor extends EmptyVisitor {
+
+ private AsmBoundClass clazz;
+
+ public AsmClassVisitor(AsmBoundClass clazz) {
+ this.clazz = clazz;
+ }
+
+ /**
+ * Parses common information about the class.
+ */
+ @Override
+ public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
+ clazz.setSuperClassName(superName);
+ clazz.setTeam((access & Types.TEAM) != 0);
+ clazz.setInterface((access & Opcodes.ACC_INTERFACE) != 0);
+ clazz.setVisibility((access & (Opcodes.ACC_PRIVATE|Opcodes.ACC_PROTECTED|Opcodes.ACC_PUBLIC)));
+ }
+
+ /**
+ * Parses the methods of the class
+ */
+ @Override
+ public MethodVisitor visitMethod(int access, final String name, final String desc, String signature, String[] exceptions) {
+ clazz.addMethod(name, desc, (access & Opcodes.ACC_STATIC) != 0, (access & (Opcodes.ACC_PUBLIC|Opcodes.ACC_PROTECTED|Opcodes.ACC_PRIVATE)));
+ if (clazz.isTeam() || clazz.isRole())
+ // check for method annotation ImplicitTeamActivation:
+ return new EmptyVisitor() {
+ @Override
+ public AnnotationVisitor visitAnnotation(String annDesc, boolean visible) {
+ if (annDesc.equals(AddImplicitActivationAdapter.ANNOTATION_IMPLICIT_ACTIVATION))
+ clazz.registerMethodForImplicitActivation(name+desc);
+ return super.visitAnnotation(annDesc, visible);
+ }
+ };
+ return super.visitMethod(access, name, desc, signature, exceptions);
+ }
+
+ /**
+ * Parses the fields of the class
+ */
+ @Override
+ public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) {
+ clazz.addField(name, desc, (access & Opcodes.ACC_STATIC) != 0, (access & (Opcodes.ACC_PUBLIC|Opcodes.ACC_PROTECTED|Opcodes.ACC_PRIVATE)));
+ return super.visitField(access, name, desc, signature, value);
+ }
+
+ /**
+ * Parses the class file attributes of a class.
+ * This is only needed, if the class is a team.
+ */
+ @Override
+ public void visitAttribute(Attribute attribute) {
+ if (attribute.type.equals(Attributes.ATTRIBUTE_OT_DYN_CALLIN_BINDINGS)) {
+ CallinBindingsAttribute attr = (CallinBindingsAttribute) attribute;
+ MultiBinding[] multiBindings = attr.getBindings();
+ for (int i=multiBindings.length-1; i>=0; i--) { // reverse loop to ensure proper overwriting:
+ String roleClassName = multiBindings[i].getRoleClassName();
+ String callinLabel = multiBindings[i].getCallinLabel();
+ String baseClassName = multiBindings[i].getBaseClassName();
+ String[] baseMethodNames = multiBindings[i].getBaseMethodNames();
+ String[] baseMethodSignatures = multiBindings[i].getBaseMethodSignatures();
+ String[] declaringBaseClassNames = multiBindings[i].getDeclaringBaseClassName();
+ int callinModifier = multiBindings[i].getCallinModifier();
+ int[] callinIds = multiBindings[i].getCallinIds();
+ boolean handleCovariantReturn = multiBindings[i].isHandleCovariantReturn();
+ for (int j = 0; j < baseMethodNames.length; j++) {
+ Binding binding = new Binding(clazz, roleClassName, callinLabel, baseClassName,
+ baseMethodNames[j], baseMethodSignatures[j], declaringBaseClassNames[j],
+ callinModifier, callinIds[j], handleCovariantReturn);
+ clazz.addBinding(binding);
+ }
+ }
+ } else if (attribute.type.equals(Attributes.ATTRIBUTE_CALLIN_PRECEDENCE)) {
+ CallinPrecedenceAttribute attr = (CallinPrecedenceAttribute)attribute;
+ clazz.precedences = attr.labels;
+ } else if (attribute.type.equals(Attributes.ATTRIBUTE_OT_CLASS_FLAGS)) {
+ clazz.setOTClassFlags(((OTClassFlagsAttribute)attribute).flags);
+ } else if (attribute.type.equals(Attributes.ATTRIBUTE_OT_SPECIAL_ACCESS)) {
+ ((OTSpecialAccessAttribute)attribute).registerAt(clazz);
+ }
+ }
+
+ /**
+ * check for class annotation ImplicitTeamActivation:
+ */
+ @Override
+ public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
+ if (desc.equals(AddImplicitActivationAdapter.ANNOTATION_IMPLICIT_ACTIVATION))
+ clazz.enableImplicitActivation();
+ return super.visitAnnotation(desc, visible);
+ }
+}
diff --git a/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/AsmTypeHelper.java b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/AsmTypeHelper.java
new file mode 100644
index 000000000..5af508dfc
--- /dev/null
+++ b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/AsmTypeHelper.java
@@ -0,0 +1,79 @@
+/**********************************************************************
+ * This file is part of "Object Teams Dynamic Runtime Environment"
+ *
+ * Copyright 2009, 2012 Oliver Frank and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Please visit http://www.eclipse.org/objectteams for updates and contact.
+ *
+ * Contributors:
+ * Oliver Frank - Initial API and implementation
+ * Stephan Herrmann - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.objectteams.otredyn.bytecode.asm;
+
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+import org.objectweb.asm.tree.AbstractInsnNode;
+import org.objectweb.asm.tree.InsnNode;
+import org.objectweb.asm.tree.MethodInsnNode;
+
+/**
+ * Asm specific helper class to handle type strings used in the bytecode
+ * @author Oliver Frank
+ */
+class AsmTypeHelper {
+ public static AbstractInsnNode getUnboxingInstructionForType(Type primitiveType, String objectType) {
+ String methodName = primitiveType.getClassName() + "Value";
+ String desc = Type.getMethodDescriptor(primitiveType, new Type[] {});
+
+ return new MethodInsnNode(Opcodes.INVOKEVIRTUAL, objectType, methodName, desc);
+ }
+
+ public static String getObjectType(Type primitiveType) {
+ String className = null;
+ switch (primitiveType.getSort()) {
+ case Type.BOOLEAN:
+ className = "Boolean";
+ break;
+ case Type.BYTE:
+ className = "Byte";
+ break;
+ case Type.CHAR:
+ className = "Character";
+ break;
+ case Type.DOUBLE:
+ className = "Double";
+ break;
+ case Type.FLOAT:
+ className = "Float";
+ break;
+ case Type.INT:
+ className = "Integer";
+ break;
+ case Type.LONG:
+ className = "Long";
+ break;
+ case Type.SHORT:
+ className = "Short";
+ break;
+ default:
+ return null;
+ }
+ className = "java/lang/" + className;
+ return className;
+ }
+
+ public static AbstractInsnNode getBoxingInstructionForType(Type type) {
+ String className = getObjectType(type);
+ if (className == null)
+ return new InsnNode(Opcodes.NOP);
+
+ String desc = Type.getMethodDescriptor(Type.getObjectType(className), new Type[] {type});
+ return new MethodInsnNode(Opcodes.INVOKESTATIC, className, "valueOf", desc);
+ }
+}
diff --git a/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/AsmWritableBoundClass.java b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/AsmWritableBoundClass.java
new file mode 100644
index 000000000..694334489
--- /dev/null
+++ b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/AsmWritableBoundClass.java
@@ -0,0 +1,432 @@
+/**********************************************************************
+ * This file is part of "Object Teams Dynamic Runtime Environment"
+ *
+ * Copyright 2009, 2012 Oliver Frank and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Please visit http://www.eclipse.org/objectteams for updates and contact.
+ *
+ * Contributors:
+ * Oliver Frank - Initial API and implementation
+ * Stephan Herrmann - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.objectteams.otredyn.bytecode.asm;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.objectteams.otredyn.bytecode.AbstractBoundClass;
+import org.eclipse.objectteams.otredyn.bytecode.Field;
+import org.eclipse.objectteams.otredyn.bytecode.IBytecodeProvider;
+import org.eclipse.objectteams.otredyn.bytecode.Method;
+import org.eclipse.objectteams.otredyn.bytecode.RedefineStrategyFactory;
+import org.eclipse.objectteams.otredyn.bytecode.Types;
+import org.eclipse.objectteams.otredyn.runtime.TeamManager;
+import org.eclipse.objectteams.otredyn.transformer.names.ClassNames;
+import org.eclipse.objectteams.otredyn.transformer.names.ConstantMembers;
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassWriter;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+
+/**
+ * This class implements the bytecode manipulating part of {@link AbstractBoundClass}.
+ * It uses ASM to manipulate the bytecode.
+ * @author Oliver Frank
+ */
+class AsmWritableBoundClass extends AsmBoundClass {
+ private static boolean dumping = false;
+
+ static {
+ if(System.getProperty("ot.dump")!=null)
+ dumping = true;
+ }
+
+ private ClassWriter writer;
+ private MultiClassAdapter multiAdapter;
+ private ClassReader reader;
+ private boolean isTransformed;
+ private boolean isTransformedForMemberAccess;
+ private boolean isTransformedStatic;
+ private List<AbstractTransformableClassNode> nodes;
+ private boolean isFirstTransformation = true;
+
+ private boolean isTransformationActive;
+
+ protected AsmWritableBoundClass(String name, String id, IBytecodeProvider bytecodeProvider, ClassLoader loader) {
+ super(name, id, bytecodeProvider, loader);
+ }
+
+ /**
+ * Adds a field to the class
+ *
+ * @param field defines name and type of the field
+ * @param access access flags for the field
+ * @see AddFieldAdapter
+ */
+ private void addField(Field field, int access) {
+ assert (isTransformationActive) : "No transformation active";
+ String desc = field.getSignature();
+ multiAdapter.addVisitor(new AddFieldAdapter(writer, field.getName(), access, desc));
+ }
+
+ /**
+ * Adds an empty method to the class
+ * @param method
+ * @param access
+ * @param signature
+ * @param exceptions
+ * @see AddEmptyMethodAdapter
+ */
+ private void addEmptyMethod(Method method, int access, String signature, String[] exceptions) {
+ assert (isTransformationActive) : "No transformation active";
+ String desc = method.getSignature();
+ Type[] args = Type.getArgumentTypes(desc);
+ multiAdapter.addVisitor(new AddEmptyMethodAdapter(writer, method.getName(),
+ access, desc, exceptions, signature, args.length + 1));
+ }
+
+ /**
+ * Adds an interface to the class
+ * @see AddInterfaceAdapter
+ * @param name
+ */
+ private void addInterface(String name) {
+ assert (isTransformationActive) : "No transformation active";
+ multiAdapter.setToplevelVisitor(new AddInterfaceAdapter(writer, name));
+ }
+
+ /**
+ * This method must be called before any transformation
+ * can be done. It makes it possible to collect all transformations
+ * and transform the bytecode only one time at the end.
+ */
+ @Override
+ protected void startTransformation() {
+
+ reader = new ClassReader(allocateAndGetBytecode());
+
+ writer = new ClassWriter(reader, 0);
+ multiAdapter = new MultiClassAdapter(writer);
+ nodes = new ArrayList<AbstractTransformableClassNode>();
+ isTransformationActive = true;
+ }
+
+ /**
+ * Is the class manipulated right now.
+ */
+ @Override
+ public boolean isTransformationActive() {
+ return isTransformationActive;
+ }
+
+ /**
+ * Executes all pending transformations.
+ */
+ @Override
+ protected void endTransformation() {
+ assert (isTransformationActive) : "No transformation active";
+ // //TODO (ofra): Do everything in one transformation
+ // Do all transformation with the Core API of ASM
+ reader.accept(multiAdapter, ClassReader.SKIP_FRAMES);
+ setBytecode(writer.toByteArray());
+ //Do all transformations with the Tree API of ASM
+ for (AbstractTransformableClassNode node : nodes) {
+ reader = new ClassReader(allocateAndGetBytecode());
+ reader.accept(node, ClassReader.SKIP_FRAMES);
+ node.transform();
+ writer = new ClassWriter(reader, 0);
+ node.accept(writer);
+ setBytecode(writer.toByteArray());
+ }
+
+ dump();
+ reader = null;
+ writer = null;
+ multiAdapter = null;
+ nodes = null;
+ //Check, if this is the first transformation for this class
+ if (!this.isFirstTransformation) {
+ // It is not the first transformation, so redefine the class
+ try {
+ redefine();
+ } catch (Throwable t) {
+// t.printStackTrace(System.out);
+ // if redefinition failed (ClassCircularity?) install a runnable for deferred redefinition:
+ final Runnable previousTask = TeamManager.pendingTasks.get();
+ TeamManager.pendingTasks.set(new Runnable() {
+ public void run() {
+ if (previousTask != null)
+ previousTask.run();
+ redefine();
+ }
+ @Override
+ public String toString() {
+ return "Retry "+AsmWritableBoundClass.this.toString();
+ }
+ });
+ }
+ }
+ isTransformationActive = false;
+ isFirstTransformation = false;
+ releaseBytecode();
+ }
+
+ /**
+ * Creates the dispatch code in the original method.
+ * @see CreateDispatchCodeInOrgMethodAdapter
+ */
+ @Override
+ protected void createDispatchCodeInOrgMethod(Method boundMethod,
+ int joinPointId, int boundMethodId) {
+ assert (isTransformationActive) : "No transformation active";
+ nodes.add(new CreateDispatchCodeInOrgMethodAdapter(boundMethod,
+ joinPointId, boundMethodId));
+ }
+
+ /**
+ * Creates the dispatch code in the method callAllBindings.
+ * @see CreateDispatchCodeInCallAllBindingsAdapter
+ */
+ @Override
+ protected void createDispatchCodeInCallAllBindings(int joinpointId,
+ int boundMethodId) {
+ assert (isTransformationActive) : "No transformation active";
+ nodes.add(new CreateDispatchCodeInCallAllBindingsAdapter(joinpointId,
+ boundMethodId));
+ }
+
+ /**
+ * Moves the code of the original method to callOrig or callOrigStatic.
+ * @see MoveCodeToCallOrigAdapter
+ */
+ @Override
+ protected void moveCodeToCallOrig(Method boundMethod, int boundMethodId) {
+ assert (isTransformationActive) : "No transformation active";
+ nodes.add(new MoveCodeToCallOrigAdapter(this, boundMethod, boundMethodId));
+ }
+
+ /**
+ * Creates a super call in callOrig.
+ * @see CreateSuperCallInCallOrigAdapter
+ */
+ @Override
+ protected void createSuperCallInCallOrig(int joinpointId) {
+ assert (isTransformationActive) : "No transformation active";
+ nodes.add(new CreateSuperCallInCallOrigAdapter(
+ getInternalSuperClassName(), joinpointId));
+
+ }
+
+ /**
+ * Creates a call of callAllBindings in the original method.
+ * @see CreateCallAllBindingsCallInOrgMethod
+ */
+ @Override
+ protected void createCallAllBindingsCallInOrgMethod(Method boundMethod,
+ int boundMethodId, boolean needToAddMethod) {
+ assert (isTransformationActive) : "No transformation active";
+ if (needToAddMethod) {
+ String desc = boundMethod.getSignature();
+ Type[] args = Type.getArgumentTypes(desc);
+ multiAdapter.addVisitor(new AddEmptyMethodAdapter(writer, boundMethod.getName(),
+ boundMethod.getAccessFlags(), desc, null, boundMethod.getSignature(), args.length+1/*maxLocals*/));
+ }
+ nodes.add(new CreateCallAllBindingsCallInOrgMethod(boundMethod,
+ boundMethodId));
+
+ }
+
+ /**
+ * Prepares a the class for a decapsulation of one of its methods
+ */
+ @Override
+ protected void weaveMethodAccess(Method method, int accessId) {
+ nodes.add(new CreateMethodAccessAdapter(method, accessId));
+
+ }
+
+ /**
+ * Prepares a the class for a decapsulation of one of its fields
+ */
+ @Override
+ protected void weaveFieldAccess(Field field, int accessId) {
+ nodes.add(new CreateFieldAccessAdapter(field, accessId));
+
+ }
+
+ /**
+ * Write the bytecode in the directory ./otdyn to the hard disk,
+ * if the system property "ot.dump" is set.
+ */
+ private void dump() {
+ if (!dumping)
+ return;
+
+ FileOutputStream fos = null;
+ try {
+ String name = getName();
+ int index = name.indexOf('/');
+ if (index == -1)
+ index = name.indexOf('.');
+ File dir = new File("otdyn");
+ if (!dir.exists())
+ dir.mkdir();
+ String filename = "otdyn/" + name.substring(index + 1) + ".class";
+ fos = new FileOutputStream(filename);
+ fos.write(allocateAndGetBytecode());
+ fos.close();
+ } catch (Exception e) {
+ // TODO (ofra): Log error while dumping
+ e.printStackTrace();
+ }
+ }
+
+ private int n = 0; // counts dump files for this class
+ public void dump(byte[] bytecode, String postfix) {
+ if (!dumping)
+ return;
+
+ FileOutputStream fos = null;
+ try {
+ String name = getName();
+ int index = name.indexOf('/');
+ if (index == -1)
+ index = name.indexOf('.');
+ File dir = new File("otdyn");
+ if (!dir.exists())
+ dir.mkdir();
+ String filename = "otdyn/" + name.substring(index + 1) + postfix+".#"+(n++);
+ fos = new FileOutputStream(filename);
+ fos.write(bytecode);
+ fos.close();
+ } catch (Exception e) {
+ // TODO (ofra): Log error while dumping
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Redefines the class
+ */
+ private void redefine() {
+ try {
+ Class<?> clazz = this.loader.loadClass(this.getName()); // boot classes may have null classloader, can't be redefined anyway?
+ byte[] bytecode = allocateAndGetBytecode();
+ dump(bytecode, "redef");
+ RedefineStrategyFactory.getRedefineStrategy().redefine(clazz, bytecode);
+ } catch (Throwable t) {
+ throw new RuntimeException("Error occured while dynamically redefining class " + getName()+"\n"+t.getMessage(), t);
+ }
+ }
+
+ /**
+ * Do all transformations needed at load time
+ */
+ @Override
+ protected void prepareAsPossibleBaseClass() {
+ if (!isFirstTransformation)
+ return;
+
+ addInterface(ClassNames.I_BOUND_BASE_SLASH);
+
+ int methodModifiers = Types.ACCESS_PUBLIC;
+ if (isInterface())
+ methodModifiers |= Opcodes.ACC_ABSTRACT;
+
+ if (!isInterface())
+ addField(ConstantMembers.roleSet, Types.ACCESS_PUBLIC);
+
+ addEmptyMethod(ConstantMembers.callOrig, methodModifiers, null, null);
+ addEmptyMethod(ConstantMembers.callAllBindingsClient, methodModifiers, null, null);
+
+ // the methods callOrigStatic and accessStatic have to already exist to call it in a concrete team
+ if (!isInterface()) {
+ addEmptyMethod(getCallOrigStatic(), Types.ACCESS_PUBLIC + Types.ACCESS_STATIC, null, null);
+ addEmptyMethod(ConstantMembers.accessStatic, Types.ACCESS_PUBLIC + Types.ACCESS_STATIC, null, null);
+ }
+
+ addEmptyMethod(ConstantMembers.access, methodModifiers, null, null);
+ addEmptyMethod(ConstantMembers.addOrRemoveRole, methodModifiers, null, null);
+
+ if (!isInterface())
+ multiAdapter.addVisitor(new AddAfterClassLoadingHook(this.writer, this));
+ }
+
+ /** Get the suitable variant of _OT$callOrigStatic, respecting synth args for static role methods. */
+ Method getCallOrigStatic() {
+ if (isRole())
+ return ConstantMembers.callOrigStaticRoleVersion(getEnclosingClassName());
+ else
+ return ConstantMembers.callOrigStatic;
+ }
+
+ /**
+ * Prepares the class for implicit team activation by adding appropriate calls to
+ * _OT$implicitlyActivate(), _OT$implicitlyDeactivate() into all relevant methods.
+ */
+ @Override
+ protected void prepareTeamActivation() {
+ if (!isFirstTransformation || isInterface())
+ return;
+ if (isTeam() || isRole())
+ multiAdapter.addVisitor(new AddImplicitActivationAdapter(this.writer, this));
+ AddGlobalTeamActivationAdapter.checkAddVisitor(this.multiAdapter, this.writer);
+ }
+
+ /**
+ * Prepares the methods callAllBindings and callOrig with an empty
+ * switch statement
+ */
+ @Override
+ protected void prepareForFirstTransformation() {
+ if (!isTransformed && !isInterface()) {
+ nodes.add(new CreateSwitchAdapter(ConstantMembers.callOrig));
+ nodes.add(new CreateSwitchForCallAllBindingsNode());
+ nodes.add(new CreateAddRemoveRoleMethod());
+ isTransformed = true;
+ }
+ }
+
+ /**
+ * Prepares the method callOrigStatic with an empty
+ * switch statement
+ */
+ @Override
+ protected void prepareForFirstStaticTransformation() {
+ if (!isTransformedStatic && !isInterface()) {
+ nodes.add(new CreateSwitchAdapter(getCallOrigStatic(), isRole()));
+ isTransformedStatic = true;
+ }
+ }
+
+ /**
+ * Prepares the methods access and accessStatic with an empty
+ * switch statement
+ */
+ @Override
+ protected void prepareForFirstMemberAccess() {
+ if (!isTransformedForMemberAccess && !isInterface()) {
+ nodes.add(new CreateSwitchForAccessAdapter(ConstantMembers.access,
+ getInternalSuperClassName(), this));
+ nodes.add(new CreateSwitchForAccessAdapter(ConstantMembers.accessStatic,
+ getInternalSuperClassName(), this));
+ isTransformedForMemberAccess = true;
+ }
+
+ }
+
+ /**
+ * Was the class already transformed?
+ */
+ @Override
+ protected boolean isFirstTransformation() {
+ return isFirstTransformation;
+ }
+}
diff --git a/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/Attributes.java b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/Attributes.java
new file mode 100644
index 000000000..4c56ef3c7
--- /dev/null
+++ b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/Attributes.java
@@ -0,0 +1,340 @@
+/**********************************************************************
+ * This file is part of "Object Teams Dynamic Runtime Environment"
+ *
+ * Copyright 2009, 2012 Oliver Frank and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Please visit http://www.eclipse.org/objectteams for updates and contact.
+ *
+ * Contributors:
+ * Oliver Frank - Initial API and implementation
+ * Stephan Herrmann - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.objectteams.otredyn.bytecode.asm;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.objectteams.otredyn.bytecode.AbstractBoundClass;
+import org.eclipse.objectteams.otredyn.bytecode.Binding;
+import org.eclipse.objectteams.otredyn.bytecode.ClassRepository;
+import org.eclipse.objectteams.otredyn.runtime.ClassIdentifierProviderFactory;
+import org.eclipse.objectteams.otredyn.runtime.IBinding;
+import org.eclipse.objectteams.otredyn.runtime.IClassIdentifierProvider;
+import org.objectweb.asm.Attribute;
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.Label;
+
+/**
+ * This class contains all classes representing OT/J class file attributes
+ * @author Oliver Frank
+ */
+abstract class Attributes {
+ protected final static String ATTRIBUTE_OT_DYN_CALLIN_BINDINGS="OTDynCallinBindings";
+ protected final static String ATTRIBUTE_CALLIN_PRECEDENCE = "CallinPrecedence";
+ protected final static String ATTRIBUTE_OT_CLASS_FLAGS = "OTClassFlags";
+ protected final static String ATTRIBUTE_OT_SPECIAL_ACCESS = "OTSpecialAccess";
+
+ protected final static Attribute[] attributes = {
+ new CallinBindingsAttribute(0),
+ new CallinPrecedenceAttribute(0),
+ new OTClassFlagsAttribute(0),
+ new OTSpecialAccessAttribute()
+ };
+
+ protected static class CallinBindingsAttribute extends Attribute {
+ static final short COVARIANT_BASE_RETURN = 8;
+
+ /** Represents all base method bindings of one callin binding. */
+ protected static class MultiBinding {
+ private String roleClassName;
+ private String callinLabel;
+ private String baseClassName;
+ private String[] baseMethodNames;
+ private String[] baseMethodSignatures;
+ private String[] declaringBaseClassNames;
+ private int callinModifier;
+ private int[] callinIds;
+ private boolean isHandleCovariantReturn;
+ MultiBinding(String roleName, String callinLabel,
+ String baseClassName,
+ String[] baseMethodNames, String[] baseMethodSignatures, String[] declaringBaseClassNames,
+ int callinModifier, int[] callinIds, boolean handleCovariantReturn)
+ {
+ this.roleClassName = roleName;
+ this.callinLabel = callinLabel;
+ this.baseClassName = baseClassName;
+ this.baseMethodNames = baseMethodNames;
+ this.baseMethodSignatures = baseMethodSignatures;
+ this.declaringBaseClassNames = declaringBaseClassNames;
+ this.callinModifier = callinModifier;
+ this.callinIds = callinIds;
+ this.isHandleCovariantReturn = handleCovariantReturn;
+ }
+ protected String getRoleClassName() {
+ return roleClassName;
+ }
+
+ protected String getBaseClassName() {
+ return baseClassName;
+ }
+
+ protected String[] getBaseMethodNames() {
+ return baseMethodNames;
+ }
+
+ protected String[] getBaseMethodSignatures() {
+ return baseMethodSignatures;
+ }
+
+ protected int getCallinModifier() {
+ return this.callinModifier;
+ }
+
+ protected int[] getCallinIds() {
+ return callinIds;
+ }
+
+ protected String getCallinLabel() {
+ return callinLabel;
+ }
+ public boolean isHandleCovariantReturn() {
+ return this. isHandleCovariantReturn;
+ }
+ public String[] getDeclaringBaseClassName() {
+ return this.declaringBaseClassNames;
+ }
+ }
+
+ private MultiBinding[] bindings;
+
+ public CallinBindingsAttribute(int bindingsCount) {
+ super(ATTRIBUTE_OT_DYN_CALLIN_BINDINGS);
+ this.bindings = new MultiBinding[bindingsCount];
+ }
+
+ private void addBinding(int i, String roleName, String callinLabel,
+ String baseClassName,
+ String[] baseMethodNames, String[] baseMethodSignatures, String[] declaringBaseClassNames,
+ String callinModifierName, int[] callinIds, boolean handleCovariantReturn) {
+ int callinModifier = 0;
+ if ("before".equals(callinModifierName))
+ callinModifier = Binding.BEFORE;
+ else if ("after".equals(callinModifierName))
+ callinModifier = Binding.AFTER;
+ else
+ callinModifier = Binding.REPLACE;
+ this.bindings[i] = new MultiBinding(roleName, callinLabel,
+ baseClassName,
+ baseMethodNames, baseMethodSignatures, declaringBaseClassNames,
+ callinModifier, callinIds, handleCovariantReturn);
+ }
+
+ @Override
+ protected Attribute read(ClassReader cr, int off, int len,
+ char[] buf, int codeOff, Label[] labels)
+ {
+ int bindingsCount = cr.readShort(off); off += 2;
+ CallinBindingsAttribute attr = new CallinBindingsAttribute(bindingsCount);
+ for (int i = 0; i < bindingsCount; i++) {
+ String roleName = cr.readUTF8(off, buf); off += 2;
+ String callinLabel = cr.readUTF8(off, buf); off += 2;
+ /* skip roleSelector, roleSignature */ off += 4;
+ String callinModifier = cr.readUTF8(off, buf); off += 2;
+ int flags = cr.readByte(off); off += 1;
+ String baseClassName = cr.readUTF8(off, buf); off += 2;
+ /* skip filename & lineNumber & lineOffset */ off += 6;
+ int baseMethodsCount = cr.readShort(off); off += 2;
+ String[] baseMethodNames = new String[baseMethodsCount];
+ String[] baseMethodSignatures = new String[baseMethodsCount];
+ String[] declaringBaseClassNames = new String[baseMethodsCount];
+ int[] callinIds = new int[baseMethodsCount];
+ for (int m = 0; m < baseMethodsCount; m++) {
+ String baseMethodName = cr.readUTF8(off, buf); off += 2;
+ String baseMethodSignature = cr.readUTF8(off, buf); off += 2;
+ String declaringBaseClass = cr.readUTF8(off, buf); off += 2;
+ int callinId = cr.readInt(off); off += 4;
+ baseMethodNames[m] = baseMethodName;
+ baseMethodSignatures[m] = baseMethodSignature;
+ declaringBaseClassNames[m] = declaringBaseClass;
+ callinIds[m] = callinId;
+ /* skip baseFlags & translationFlags */ off += 3;
+ }
+ attr.addBinding(i, roleName, callinLabel,
+ baseClassName,
+ baseMethodNames, baseMethodSignatures, declaringBaseClassNames,
+ callinModifier, callinIds, ((flags & COVARIANT_BASE_RETURN) != 0));
+ }
+ return attr;
+ }
+
+ public MultiBinding[] getBindings() {
+ return this.bindings;
+ }
+
+ @Override
+ public String toString() {
+ StringBuffer buf = new StringBuffer();
+ for (MultiBinding binding : this.bindings) {
+ buf.append(binding.getBaseClassName());
+ int[] callinIds = binding.getCallinIds();
+ String[] baseMethodNames = binding.getBaseMethodNames();
+ String[] baseMethodSignatures = binding.getBaseMethodSignatures();
+ for (int i=0; i<callinIds.length; i++) {
+ buf.append("\n\t{");
+ buf.append(callinIds[i]);
+ buf.append("} ");
+ buf.append(baseMethodNames[i]);
+ buf.append(baseMethodSignatures[i]);
+ }
+ }
+ return buf.toString();
+ }
+ }
+ protected static class CallinPrecedenceAttribute extends Attribute {
+ String[] labels;
+ public CallinPrecedenceAttribute(int elementCount) {
+ super(ATTRIBUTE_CALLIN_PRECEDENCE);
+ this.labels = new String[elementCount];
+ }
+ @Override
+ protected Attribute read(ClassReader cr, int off, int len,
+ char[] buf, int codeOff, Label[] labels)
+ {
+ int elementCount = cr.readShort(off); off += 2;
+ CallinPrecedenceAttribute attr = new CallinPrecedenceAttribute(elementCount);
+ for (int i = 0; i < elementCount; i++) {
+ attr.labels[i] = cr.readUTF8(off, buf); off += 2;
+ }
+ return attr;
+ }
+ }
+ protected static class OTClassFlagsAttribute extends Attribute {
+ int flags;
+ protected OTClassFlagsAttribute(int flags) {
+ super(ATTRIBUTE_OT_CLASS_FLAGS);
+ this.flags = flags;
+ }
+ @Override
+ protected Attribute read(ClassReader cr, int off, int len, char[] buf,
+ int codeOff, Label[] labels)
+ {
+ return new OTClassFlagsAttribute(cr.readUnsignedShort(off));
+ }
+ }
+ protected static class OTSpecialAccessAttribute extends Attribute {
+ class DecapsField {
+ String accessMode;
+ boolean isStatic;
+ String baseclass, name, desc;
+ public int accessId;
+ public DecapsField(String baseclass, String name, String desc, int accessId, String accessMode, boolean isStatic) {
+ this.baseclass = baseclass;
+ this.name = name;
+ this.desc = desc;
+ this.accessId = accessId;
+ this.accessMode = accessMode;
+ this.isStatic = isStatic;
+ }
+ }
+ class DecapsMethod {
+ String baseclass, name, desc;
+ int id;
+ boolean isStatic;
+ DecapsMethod(String baseclass, String name, String desc, int id, boolean isStatic) {
+ this.baseclass = baseclass;
+ this.name = name;
+ this.desc = desc;
+ this.id = id;
+ this.isStatic = isStatic;
+ }
+ }
+ private static final int DECAPSULATION_METHOD_ACCESS= 4; // kinds are disjoint from those used by the old OTRE
+ private static final int CALLOUT_FIELD_ACCESS = 5;
+ private static final int SUPER_METHOD_ACCESS = 6;
+
+ List<DecapsMethod> methods = new ArrayList<DecapsMethod>();
+ List<DecapsField> fields = new ArrayList<DecapsField>();
+
+ protected OTSpecialAccessAttribute() {
+ super(ATTRIBUTE_OT_SPECIAL_ACCESS);
+ }
+ @Override
+ protected Attribute read(ClassReader cr, int off, int len, char[] buf,
+ int codeOff, Label[] labels)
+ {
+ OTSpecialAccessAttribute attr = new OTSpecialAccessAttribute();
+ int size = cr.readUnsignedShort(off); off+=2;
+ for (int i=0; i<size; i++) {
+ int kind = cr.readByte(off++);
+ switch (kind) {
+ case DECAPSULATION_METHOD_ACCESS:
+ attr.readMethodAccess(cr, off, buf); off+=6;
+ break;
+ case CALLOUT_FIELD_ACCESS:
+ attr.readFieldAccess(cr, off, buf); off+=8;
+ default:
+ // FIXME(SH): handle!
+ }
+ }
+ return attr;
+ }
+ private void readMethodAccess(ClassReader cr, int off, char[] buf) {
+ String className = cr.readUTF8(off, buf);
+ String encodedName = cr.readUTF8(off+2, buf);
+ String methodDesc = cr.readUTF8(off+4, buf);
+ int id = cr.readUnsignedShort(off+6);
+ boolean isStatic = false;
+ String baseClass;
+ String methodName;
+ int pos = encodedName.indexOf('?');
+ if (pos == -1) {
+ pos = encodedName.indexOf('!');
+ isStatic = true;
+ }
+ baseClass = encodedName.substring(0, pos);
+ methodName = encodedName.substring(pos+1);
+ this.methods.add(new DecapsMethod(baseClass, methodName, methodDesc, id, isStatic));
+ }
+ private void readFieldAccess(ClassReader cr, int off, char[] buf) {
+ int accessId = cr.readByte(off);
+ int flags = cr.readByte(off+1);
+ String className = cr.readUTF8(off+2, buf);
+ String fieldName = cr.readUTF8(off+4, buf);
+ String fieldDesc = cr.readUTF8(off+6, buf);
+ boolean isStatic = (flags & 2) != 0;
+ String accessMode = (flags & 1) == 1 ? "set" : "get";
+ this.fields.add(new DecapsField(className, fieldName, fieldDesc, accessId, accessMode, isStatic));
+ }
+ public void registerAt(AsmBoundClass clazz) {
+ ClassRepository repo = ClassRepository.getInstance();
+ IClassIdentifierProvider provider = ClassIdentifierProviderFactory.getClassIdentifierProvider();
+
+ for (DecapsMethod dMethod : this.methods) {
+ // FIXME(SH): the following may need adaptation for OT/Equinox or other multi-classloader settings:
+ // bypassing the identifier provider (we don't have a Class<?> yet):
+ // String boundClassIdentifier = provider.getBoundClassIdentifier(clazz, dMethod.baseclass);
+ AbstractBoundClass baseclass = repo.getBoundClass(dMethod.baseclass, dMethod.baseclass.replace('.', '/'), clazz.getClassLoader());
+ // register the target method:
+ baseclass.getMethod(dMethod.name, dMethod.desc, false/*covariantReturn*/, dMethod.isStatic);
+ clazz.recordAccessId(dMethod.id);
+ clazz.addBinding(new Binding(clazz, dMethod.baseclass, dMethod.name, dMethod.desc, dMethod.id, IBinding.BindingType.METHOD_ACCESS));
+ }
+
+ for (DecapsField dField: this.fields) {
+ // FIXME(SH): the following may need adaptation for OT/Equinox or other multi-classloader settings:
+ // bypassing the identifier provider (we don't have a Class<?> yet):
+ // String boundClassIdentifier = provider.getBoundClassIdentifier(clazz, dMethod.baseclass);
+ AbstractBoundClass baseclass = repo.getBoundClass(dField.baseclass, dField.baseclass.replace('.', '/'), clazz.getClassLoader());
+ // register the target field:
+ baseclass.getField(dField.name, dField.desc);
+ clazz.recordAccessId(dField.accessId);
+ clazz.addBinding(new Binding(clazz, dField.baseclass, dField.name, dField.desc, dField.accessId, IBinding.BindingType.FIELD_ACCESS));
+ }
+ }
+ }
+}
diff --git a/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/CreateCallAllBindingsCallInOrgMethod.java b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/CreateCallAllBindingsCallInOrgMethod.java
new file mode 100644
index 000000000..bb067c41c
--- /dev/null
+++ b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/CreateCallAllBindingsCallInOrgMethod.java
@@ -0,0 +1,146 @@
+/**********************************************************************
+ * This file is part of "Object Teams Dynamic Runtime Environment"
+ *
+ * Copyright 2009, 2012 Oliver Frank and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Please visit http://www.eclipse.org/objectteams for updates and contact.
+ *
+ * Contributors:
+ * Oliver Frank - Initial API and implementation
+ * Stephan Herrmann - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.objectteams.otredyn.bytecode.asm;
+
+import org.eclipse.objectteams.otredyn.bytecode.Method;
+import org.eclipse.objectteams.otredyn.transformer.names.ClassNames;
+import org.eclipse.objectteams.otredyn.transformer.names.ConstantMembers;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+import org.objectweb.asm.tree.InsnList;
+import org.objectweb.asm.tree.InsnNode;
+import org.objectweb.asm.tree.IntInsnNode;
+import org.objectweb.asm.tree.LabelNode;
+import org.objectweb.asm.tree.MethodInsnNode;
+import org.objectweb.asm.tree.MethodNode;
+import org.objectweb.asm.tree.TryCatchBlockNode;
+
+/**
+ * This class creates and adds the instructions, that are needed
+ * to call the method callAllBindings to a method.<br/> <br/>
+ * The instructions looks as follows:<br/>
+ * <code>
+ * Object[] args = {args1, ..., argsn};<br/>
+ * this.callAllBindings(boundMethodId, args);
+ * </code>
+ * @author Oliver Frank
+ */
+public class CreateCallAllBindingsCallInOrgMethod extends
+ AbstractTransformableClassNode {
+
+ private Method orgMethod;
+ private int boundMethodId;
+
+ public CreateCallAllBindingsCallInOrgMethod(Method orgMethod,
+ int boundMethodId) {
+ this.orgMethod = orgMethod;
+ this.boundMethodId = boundMethodId;
+ }
+
+ @Override
+ public void transform() {
+ MethodNode method = getMethod(orgMethod);
+ method.instructions.clear();
+
+ // start of try-block:
+ LabelNode start = new LabelNode();
+ method.instructions.add(start);
+
+ // put this on the stack
+ method.instructions.add(new IntInsnNode(Opcodes.ALOAD, 0));
+ // put boundMethodId on the stack
+ method.instructions.add(createLoadIntConstant(boundMethodId));
+ Type[] args = Type.getArgumentTypes(method.desc);
+ // box the arguments
+ method.instructions.add(getBoxingInstructions(args, false));
+
+ // this.callAllBindings(boundMethodId, args);
+ method.instructions.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL,
+ this.name, ConstantMembers.callAllBindingsClient.getName(),
+ ConstantMembers.callAllBindingsClient.getSignature()));
+ Type returnType = Type.getReturnType(method.desc);
+ method.instructions
+ .add(getUnboxingInstructionsForReturnValue(returnType));
+
+ // catch and unwrap SneakyException:
+ addCatchSneakyException(method, start);
+
+ int localSlots = 0;
+ int maxArgSize = 1;
+ for (Type type : args) {
+ int size = type.getSize();
+ localSlots += size;
+ if (size == 2)
+ maxArgSize = 2;
+ }
+ method.maxStack = args.length > 0 ? 5+maxArgSize : 3;
+ method.maxLocals = localSlots+1;
+ }
+
+ @SuppressWarnings("unchecked") // access to raw type List in ASM
+ void addCatchSneakyException(MethodNode method, LabelNode start) {
+ method.tryCatchBlocks.add(getCatchBlock(method.instructions, start, orgMethod));
+ }
+
+ TryCatchBlockNode getCatchBlock(InsnList instructions, LabelNode start, Method method) {
+ // end (exclusive) of try-block
+ LabelNode end = new LabelNode();
+ instructions.add(end);
+
+ // catch (SneakyException e) { e.rethrow(); }
+ LabelNode catchSneaky = new LabelNode();
+ instructions.add(catchSneaky);
+ instructions.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, ClassNames.SNEAKY_EXCEPTION_SLASH, ClassNames.RETHROW_SELECTOR, ClassNames.RETHROW_SIGNATURE));
+
+ // never reached, just to please the verifier:
+ Type returnType = Type.getReturnType(method.getSignature());
+ instructions.add(getReturnInsn(returnType));
+ return new TryCatchBlockNode(start, end, catchSneaky, ClassNames.SNEAKY_EXCEPTION_SLASH);
+ }
+
+ protected InsnList getReturnInsn(Type returnType) {
+ InsnList instructions = new InsnList();
+ switch (returnType.getSort()) {
+ case Type.VOID:
+ instructions.add(new InsnNode(Opcodes.RETURN));
+ break;
+ case Type.ARRAY:
+ case Type.OBJECT:
+ instructions.add(new InsnNode(Opcodes.ACONST_NULL));
+ instructions.add(new InsnNode(Opcodes.ARETURN));
+ break;
+ case Type.BOOLEAN:
+ case Type.CHAR:
+ case Type.BYTE:
+ case Type.INT:
+ case Type.SHORT:
+ case Type.LONG:
+ instructions.add(new InsnNode(Opcodes.ICONST_0));
+ instructions.add(new InsnNode(Opcodes.IRETURN));
+ break;
+ case Type.DOUBLE:
+ instructions.add(new InsnNode(Opcodes.DCONST_0));
+ instructions.add(new InsnNode(Opcodes.DRETURN));
+ break;
+ case Type.FLOAT:
+ instructions.add(new InsnNode(Opcodes.FCONST_0));
+ instructions.add(new InsnNode(Opcodes.FRETURN));
+ break;
+ }
+ return instructions;
+ }
+}
diff --git a/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/CreateDispatchCodeInCallAllBindingsAdapter.java b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/CreateDispatchCodeInCallAllBindingsAdapter.java
new file mode 100644
index 000000000..9b49160f1
--- /dev/null
+++ b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/CreateDispatchCodeInCallAllBindingsAdapter.java
@@ -0,0 +1,76 @@
+/**********************************************************************
+ * This file is part of "Object Teams Dynamic Runtime Environment"
+ *
+ * Copyright 2009, 2012 Oliver Frank and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Please visit http://www.eclipse.org/objectteams for updates and contact.
+ *
+ * Contributors:
+ * Oliver Frank - Initial API and implementation
+ * Stephan Herrmann - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.objectteams.otredyn.bytecode.asm;
+
+import org.eclipse.objectteams.otredyn.transformer.names.ConstantMembers;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+import org.objectweb.asm.tree.InsnList;
+import org.objectweb.asm.tree.IntInsnNode;
+import org.objectweb.asm.tree.MethodNode;
+
+/**
+ * Create the code for the dispatch from a base class to the teams
+ * in the method callAllBindings. <br/> <br/>
+ * The code was generated as follows: <br/>
+ * <code>
+ * switch (boundMethodId) { // this was generated in CreateSwitchAdapter <br/>
+ * ... <br/>
+ * case (boundMethodId): <br/>
+ * Teams[] teams = TeamManager.getTeams(joinpointId) <br/>
+ * if (teams == null) { <br/>
+ * break; <br/>
+ * } <br/>
+ * <br/>
+ * Team t = teams[0]; <br/>
+ * int[] callinIds = TeamManager.getCallinIds(joinpointId); <br/>
+ * Object[] args = {arg1, ... , argn};
+ * return team._OT$callAllBindings(this, teams, 0, callinIds, boundMethodId, args);
+ * } <br/>
+ * </code>
+ * @author Oliver Frank
+ */
+public class CreateDispatchCodeInCallAllBindingsAdapter extends
+ AbstractCreateDispatchCodeAdapter {
+
+ private int joinpointId;
+ private int boundMethodId;
+
+ public CreateDispatchCodeInCallAllBindingsAdapter(int joinpointId,
+ int boundMethodId) {
+ super(false);
+ this.joinpointId = joinpointId;
+ this.boundMethodId = boundMethodId;
+ }
+
+ @Override
+ public void transform() {
+ MethodNode callAllBindings = getMethod(ConstantMembers.callAllBindingsClient);
+ InsnList instructions = getDispatchCode(callAllBindings, joinpointId, boundMethodId);
+ addNewLabelToSwitch(callAllBindings.instructions, instructions, boundMethodId);
+ callAllBindings.maxStack = getMaxStack();
+ callAllBindings.maxLocals = getMaxLocals();
+ }
+
+ @Override
+ protected InsnList getBoxedArguments(Type[] args) {
+ InsnList instructions = new InsnList();
+ instructions.add(new IntInsnNode(Opcodes.ALOAD, 2));
+ return instructions;
+ }
+
+}
diff --git a/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/CreateDispatchCodeInOrgMethodAdapter.java b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/CreateDispatchCodeInOrgMethodAdapter.java
new file mode 100644
index 000000000..27e8cbe2e
--- /dev/null
+++ b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/CreateDispatchCodeInOrgMethodAdapter.java
@@ -0,0 +1,100 @@
+/**********************************************************************
+ * This file is part of "Object Teams Dynamic Runtime Environment"
+ *
+ * Copyright 2009, 2012 Oliver Frank and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Please visit http://www.eclipse.org/objectteams for updates and contact.
+ *
+ * Contributors:
+ * Oliver Frank - Initial API and implementation
+ * Stephan Herrmann - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.objectteams.otredyn.bytecode.asm;
+
+import org.eclipse.objectteams.otredyn.bytecode.Method;
+import org.eclipse.objectteams.otredyn.transformer.names.ConstantMembers;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+import org.objectweb.asm.tree.InsnList;
+import org.objectweb.asm.tree.InsnNode;
+import org.objectweb.asm.tree.JumpInsnNode;
+import org.objectweb.asm.tree.LabelNode;
+import org.objectweb.asm.tree.MethodInsnNode;
+import org.objectweb.asm.tree.MethodNode;
+
+/**
+ * Create the code for the dispatch from a base class to the teams
+ * in the original method. <br/> <br/>
+ * The code was generated as follows: <br/>
+ * <code>
+ * Teams[] teams = TeamManager.getTeams(joinpointId) <br/>
+ * if (teams == null) { <br/>
+ * Object args[] = {arg1, ..., argn}; <br/>
+ * return callOrig(boundMethodId, args); <br/>
+ * } <br/>
+ * <br/>
+ * Team t = teams[0]; <br/>
+ * int[] callinIds = TeamManager.getCallinIds(joinpointId); <br/>
+ * Object[] args = {arg1, ... , argn};
+ * return team._OT$callAllBindings(this, teams, 0, callinIds, boundMethodId, args);
+ * } <br/>
+ * </code>
+ * @author Oliver Frank
+ */
+public class CreateDispatchCodeInOrgMethodAdapter extends
+ AbstractCreateDispatchCodeAdapter {
+ private Method method;
+ private int joinPointId;
+ private int boundMethodId;
+
+ public CreateDispatchCodeInOrgMethodAdapter(Method method, int joinPointId, int boundMethodId) {
+ super(true);
+ this.method = method;
+ this.joinPointId = joinPointId;
+ this.boundMethodId = boundMethodId;
+ }
+
+ @Override
+ public void transform() {
+ MethodNode orgMethod = getMethod(method);
+
+ orgMethod.instructions.clear();
+ orgMethod.instructions.add(getDispatchCode(orgMethod, joinPointId, boundMethodId));
+ orgMethod.maxStack = getMaxStack();
+ orgMethod.maxLocals = getMaxLocals();
+ }
+
+ @Override
+ protected InsnList getBoxedArguments(Type[] args) {
+ return getBoxingInstructions(args, true);
+ }
+
+ @Override
+ protected InsnList createInstructionsToCheackTeams(MethodNode method) {
+ InsnList instructions = new InsnList();
+ instructions.add(new InsnNode(Opcodes.DUP));
+ LabelNode label = new LabelNode();
+ //if (teams == null) {
+ instructions.add(new JumpInsnNode(Opcodes.IFNONNULL, label));
+ instructions.add(new InsnNode(Opcodes.POP));
+ //put the boundMethodId on the stack
+ instructions.add(createLoadIntConstant(boundMethodId));
+ Type[] args = Type.getArgumentTypes(method.desc);
+ // box the arguments
+ instructions.add(getBoxingInstructions(args, (method.access & Opcodes.ACC_STATIC) != 0));
+ //callOrigStatic(boundMethodId, args);
+ instructions.add(new MethodInsnNode(Opcodes.INVOKESTATIC, name, ConstantMembers.callOrigStatic.getName(), ConstantMembers.callOrigStatic.getSignature()));
+ Type returnType = Type.getReturnType(method.desc);
+ instructions
+ .add(getUnboxingInstructionsForReturnValue(returnType));
+ instructions.add(label);
+
+ return instructions;
+ }
+
+}
diff --git a/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/CreateFieldAccessAdapter.java b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/CreateFieldAccessAdapter.java
new file mode 100644
index 000000000..2b240e36f
--- /dev/null
+++ b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/CreateFieldAccessAdapter.java
@@ -0,0 +1,130 @@
+/**********************************************************************
+ * This file is part of "Object Teams Dynamic Runtime Environment"
+ *
+ * Copyright 2009, 2012 Oliver Frank and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Please visit http://www.eclipse.org/objectteams for updates and contact.
+ *
+ * Contributors:
+ * Oliver Frank - Initial API and implementation
+ * Stephan Herrmann - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.objectteams.otredyn.bytecode.asm;
+
+import org.eclipse.objectteams.otredyn.bytecode.Field;
+import org.eclipse.objectteams.otredyn.bytecode.Method;
+import org.eclipse.objectteams.otredyn.transformer.names.ConstantMembers;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+import org.objectweb.asm.tree.FieldInsnNode;
+import org.objectweb.asm.tree.InsnList;
+import org.objectweb.asm.tree.InsnNode;
+import org.objectweb.asm.tree.IntInsnNode;
+import org.objectweb.asm.tree.JumpInsnNode;
+import org.objectweb.asm.tree.LabelNode;
+import org.objectweb.asm.tree.MethodNode;
+import org.objectweb.asm.tree.TypeInsnNode;
+
+/**
+ * Creates and adds the instructions,
+ * that are needed to access a not visible field from the team
+ * in the method access or accessStatic as follows:<br/> <br/>
+ * case (memberId) { // generated by CreateSwitchForAccessAdapter <br/>
+ * if (opKind == 0) { <br/>
+ * return field; <br/>
+ * } else { <br/>
+ * field = args[0]; <br/>
+ * } <br/>
+ * break; <br/>
+ * }
+ *
+ * @author Oliver Frank
+ */
+public class CreateFieldAccessAdapter extends AbstractTransformableClassNode {
+
+ private Field field;
+ private int accessId;
+ private Method access;
+ private int firstArgIndex;
+
+ public CreateFieldAccessAdapter(Field field, int accessId) {
+ this.field = field;
+ this.accessId = accessId;
+ if (field.isStatic()) {
+ access = ConstantMembers.accessStatic;
+ firstArgIndex = 0;
+ } else {
+ access = ConstantMembers.access;
+ firstArgIndex = 1;
+ }
+ }
+
+ @Override
+ public void transform() {
+
+ InsnList instructions = new InsnList();
+ // put accessId on the stack
+ instructions.add(new IntInsnNode(Opcodes.ILOAD, firstArgIndex + 1));
+ // read or write access
+ LabelNode writeAccess = new LabelNode();
+ instructions.add(new JumpInsnNode(Opcodes.IFNE, writeAccess));
+ // read access
+ if (field.isStatic()) {
+ // get value of field
+ instructions.add(new FieldInsnNode(Opcodes.GETSTATIC, name, field
+ .getName(), field.getSignature()));
+ } else {
+ // put "this" on the stack
+ instructions.add(new IntInsnNode(Opcodes.ALOAD, 0));
+ // get value of field
+ instructions.add(new FieldInsnNode(Opcodes.GETFIELD, name, field
+ .getName(), field.getSignature()));
+ }
+
+ //box value as "Object"
+ Type type = Type.getType(field.getSignature());
+ instructions.add(AsmTypeHelper.getBoxingInstructionForType(type));
+ instructions.add(new InsnNode(Opcodes.ARETURN));
+
+ //write access
+ instructions.add(writeAccess);
+ //put "args" on the stack
+ instructions.add(new IntInsnNode(Opcodes.ALOAD, firstArgIndex + 2));
+ //get the first element of "args"
+ instructions.add(new InsnNode(Opcodes.ICONST_0));
+ instructions.add(new InsnNode(Opcodes.AALOAD));
+ //unbox it
+ if (type.getSort() != Type.ARRAY && type.getSort() != Type.OBJECT) {
+ String objectType = AsmTypeHelper.getObjectType(type);
+ instructions.add(new TypeInsnNode(Opcodes.CHECKCAST, objectType));
+ instructions.add(AsmTypeHelper.getUnboxingInstructionForType(type, objectType));
+ } else {
+ instructions.add(new TypeInsnNode(Opcodes.CHECKCAST, type.getInternalName()));
+ }
+
+ if (field.isStatic()) {
+ //save value in field
+ instructions.add(new FieldInsnNode(Opcodes.PUTSTATIC, name, field.getName(), field.getSignature()));
+ } else {
+ //put "this" on the stack
+ instructions.add(new IntInsnNode(Opcodes.ALOAD, 0));
+ instructions.add(new InsnNode(Opcodes.SWAP));
+ //save value in field
+ instructions.add(new FieldInsnNode(Opcodes.PUTFIELD, name, field.getName(), field.getSignature()));
+ }
+
+ //dummy return
+ instructions.add(new InsnNode(Opcodes.ACONST_NULL));
+ instructions.add(new InsnNode(Opcodes.ARETURN));
+
+ //add the instructions to a new label in the existing switch
+ MethodNode method = getMethod(access);
+ addNewLabelToSwitch(method.instructions, instructions, accessId);
+ }
+
+}
diff --git a/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/CreateMethodAccessAdapter.java b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/CreateMethodAccessAdapter.java
new file mode 100644
index 000000000..acd100532
--- /dev/null
+++ b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/CreateMethodAccessAdapter.java
@@ -0,0 +1,121 @@
+/**********************************************************************
+ * This file is part of "Object Teams Dynamic Runtime Environment"
+ *
+ * Copyright 2009, 2012 Oliver Frank and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Please visit http://www.eclipse.org/objectteams for updates and contact.
+ *
+ * Contributors:
+ * Oliver Frank - Initial API and implementation
+ * Stephan Herrmann - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.objectteams.otredyn.bytecode.asm;
+
+import org.eclipse.objectteams.otredyn.bytecode.Method;
+import org.eclipse.objectteams.otredyn.transformer.names.ConstantMembers;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+import org.objectweb.asm.tree.InsnList;
+import org.objectweb.asm.tree.InsnNode;
+import org.objectweb.asm.tree.IntInsnNode;
+import org.objectweb.asm.tree.MethodInsnNode;
+import org.objectweb.asm.tree.MethodNode;
+import org.objectweb.asm.tree.TypeInsnNode;
+
+/**
+ * Creates and adds the instructions,
+ * that are needed to access a not visible method from the team
+ * in the method access or accessStatic as follows:<br/> <br/>
+ * case (memberId) { // generated by CreateSwitchForAccessAdapter <br/>
+ * return orgMethod(args[0], ..., args[args.length]); <br/>
+ * }
+ *
+ * @author Oliver Frank
+ */
+public class CreateMethodAccessAdapter extends AbstractTransformableClassNode {
+ private Method method;
+ private int accessId;
+ private Method access;
+ private int firstArgIndex;
+
+ public CreateMethodAccessAdapter(Method method, int accessId) {
+ this.method = method;
+ this.accessId = accessId;
+ if (method.isStatic()) {
+ access = ConstantMembers.accessStatic;
+ firstArgIndex = 0;
+ } else {
+ access = ConstantMembers.access;
+ firstArgIndex = 1;
+ }
+ }
+
+ @Override
+ public void transform() {
+ MethodNode methodNode = getMethod(method);
+ InsnList instructions = new InsnList();
+
+ //put "this" on the stack for a non-static method
+ if (!method.isStatic()) {
+ instructions.add(new IntInsnNode(Opcodes.ALOAD, 0));
+ }
+
+ //Unbox arguments
+ Type[] args = Type.getArgumentTypes(methodNode.desc);
+
+ if (args.length > 0) {
+ instructions.add(new IntInsnNode(Opcodes.ALOAD, firstArgIndex + 2));
+
+
+ for (int i = 0; i < args.length; i++) {
+ if (i < args.length - 1) {
+ instructions.add(new InsnNode(Opcodes.DUP));
+ }
+ instructions.add(createLoadIntConstant(i));
+ instructions.add(new InsnNode(Opcodes.AALOAD));
+ Type arg = args[i];
+ if (arg.getSort() != Type.ARRAY && arg.getSort() != Type.OBJECT) {
+ String objectType = AsmTypeHelper.getObjectType(arg);
+ instructions.add(new TypeInsnNode(Opcodes.CHECKCAST, objectType));
+ instructions.add(AsmTypeHelper.getUnboxingInstructionForType(arg, objectType));
+ } else {
+ instructions.add(new TypeInsnNode(Opcodes.CHECKCAST, arg.getInternalName()));
+ }
+ }
+ }
+
+ //call original method
+ int opcode = Opcodes.INVOKEVIRTUAL;
+ if (method.isStatic()) {
+ opcode = Opcodes.INVOKESTATIC;
+ }
+ instructions.add(new MethodInsnNode(opcode, name, method.getName(), method.getSignature()));
+
+
+ //box return value
+ Type returnType = Type.getReturnType(methodNode.desc);
+
+ if (returnType.getSort() != Type.OBJECT &&
+ returnType.getSort() != Type.ARRAY &&
+ returnType.getSort() != Type.VOID) {
+
+ instructions.add(AsmTypeHelper.getBoxingInstructionForType(returnType));
+ instructions.add(new InsnNode(Opcodes.ARETURN));
+ } else if (returnType.getSort() == Type.VOID) {
+ instructions.add(new InsnNode(Opcodes.ACONST_NULL));
+ instructions.add(new InsnNode(Opcodes.ARETURN));
+ } else {
+ instructions.add(new InsnNode(Opcodes.ARETURN));
+ }
+
+ //add the instructions to a new label in the existing switch
+ MethodNode access = getMethod(this.access);
+ addNewLabelToSwitch(access.instructions, instructions, accessId);
+ }
+
+}
diff --git a/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/CreateSuperCallInCallOrigAdapter.java b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/CreateSuperCallInCallOrigAdapter.java
new file mode 100644
index 000000000..e81bf8230
--- /dev/null
+++ b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/CreateSuperCallInCallOrigAdapter.java
@@ -0,0 +1,58 @@
+/**********************************************************************
+ * This file is part of "Object Teams Dynamic Runtime Environment"
+ *
+ * Copyright 2009, 2012 Oliver Frank and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Please visit http://www.eclipse.org/objectteams for updates and contact.
+ *
+ * Contributors:
+ * Oliver Frank - Initial API and implementation
+ * Stephan Herrmann - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.objectteams.otredyn.bytecode.asm;
+
+import org.eclipse.objectteams.otredyn.transformer.names.ConstantMembers;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+import org.objectweb.asm.tree.InsnList;
+import org.objectweb.asm.tree.InsnNode;
+import org.objectweb.asm.tree.MethodInsnNode;
+import org.objectweb.asm.tree.MethodNode;
+
+/**
+ * This class creates the instructions, that are needed
+ * to call super.callOrig(boundMethodId, args)
+ * @author Oliver Frank
+ */
+public class CreateSuperCallInCallOrigAdapter extends AbstractTransformableClassNode {
+
+ private int joinpointId;
+ private String superClassName;
+
+ public CreateSuperCallInCallOrigAdapter(String superClassName,
+ int joinpointId) {
+ this.superClassName = superClassName;
+ this.joinpointId = joinpointId;
+ }
+
+ @Override
+ public void transform() {
+ MethodNode callOrig = getMethod(ConstantMembers.callOrig);
+ InsnList instructions = new InsnList();
+
+ Type[] args = Type.getArgumentTypes(callOrig.desc);
+ addInstructionsForLoadArguments(instructions, args, false);
+
+ instructions.add(new MethodInsnNode(Opcodes.INVOKESPECIAL,
+ superClassName, ConstantMembers.callOrig.getName(),
+ ConstantMembers.callOrig.getSignature()));
+ instructions.add(new InsnNode(Opcodes.ARETURN));
+ addNewLabelToSwitch(callOrig.instructions, instructions, joinpointId);
+ callOrig.maxStack = Math.max(callOrig.maxStack, args.length + 1);
+ }
+}
diff --git a/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/CreateSwitchAdapter.java b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/CreateSwitchAdapter.java
new file mode 100644
index 000000000..dbbabcfd9
--- /dev/null
+++ b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/CreateSwitchAdapter.java
@@ -0,0 +1,112 @@
+/**********************************************************************
+ * This file is part of "Object Teams Dynamic Runtime Environment"
+ *
+ * Copyright 2009, 2012 Oliver Frank and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Please visit http://www.eclipse.org/objectteams for updates and contact.
+ *
+ * Contributors:
+ * Oliver Frank - Initial API and implementation
+ * Stephan Herrmann - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.objectteams.otredyn.bytecode.asm;
+
+import org.eclipse.objectteams.otredyn.bytecode.Method;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.tree.InsnNode;
+import org.objectweb.asm.tree.IntInsnNode;
+import org.objectweb.asm.tree.LabelNode;
+import org.objectweb.asm.tree.LookupSwitchInsnNode;
+import org.objectweb.asm.tree.MethodNode;
+
+/**
+ * This class creates an empty switch statement in a method.
+ * @author Oliver Frank
+ */
+public class CreateSwitchAdapter extends AbstractTransformableClassNode {
+ private Method method;
+
+ private int firstArgIndex;
+
+ public CreateSwitchAdapter(Method method) {
+ this.method = method;
+ if (method.isStatic()) {
+ firstArgIndex = 0;
+ } else {
+ firstArgIndex = 1;
+ }
+ }
+
+ public CreateSwitchAdapter(Method method, boolean isRoleMethod) {
+ this.method = method;
+ if (method.isStatic()) {
+ if (isRoleMethod)
+ firstArgIndex = 2;
+ else
+ firstArgIndex = 0;
+ } else {
+ firstArgIndex = 1;
+ }
+ }
+
+ @Override
+ public void transform() {
+ MethodNode methodNode = getMethod(method);
+ if (methodNode == null) return; // doesn't exist, don't transform
+ methodNode.instructions.clear();
+
+ addPreSwitchInstructions(methodNode);
+
+ LabelNode def = new LabelNode();
+ LookupSwitchInsnNode switchNode = new LookupSwitchInsnNode(def, new int[0], new LabelNode[0]);
+
+ methodNode.instructions.add(switchNode);
+ methodNode.instructions.add(def);
+ addInstructionForDefaultLabel(methodNode);
+
+ addPostSwitchInstructions(methodNode);
+ methodNode.maxStack = getMaxStack();
+ }
+
+ /**
+ * Adds instructions after the switch statement
+ * @param method
+ */
+ protected void addPostSwitchInstructions(MethodNode method) {
+ }
+
+ /**
+ * Adds instructions before the switch statement.
+ * @param method
+ */
+ protected void addPreSwitchInstructions(MethodNode method) {
+ method.instructions.add(new IntInsnNode(Opcodes.ILOAD, firstArgIndex));
+ }
+
+ /**
+ * Adds instructions for the default label.
+ * @param method
+ */
+ protected void addInstructionForDefaultLabel(MethodNode method) {
+ method.instructions.add(new InsnNode(Opcodes.ACONST_NULL));
+ method.instructions.add(new InsnNode(Opcodes.ARETURN));
+ }
+
+ protected int getMaxStack() {
+ return 1;
+ }
+
+ protected int getFirstArgIndex() {
+ return firstArgIndex;
+ }
+
+ protected Method getMethod() {
+ return method;
+ }
+
+}
diff --git a/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/CreateSwitchForAccessAdapter.java b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/CreateSwitchForAccessAdapter.java
new file mode 100644
index 000000000..adebbf265
--- /dev/null
+++ b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/CreateSwitchForAccessAdapter.java
@@ -0,0 +1,100 @@
+/**********************************************************************
+ * This file is part of "Object Teams Dynamic Runtime Environment"
+ *
+ * Copyright 2009, 2012 Oliver Frank and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Please visit http://www.eclipse.org/objectteams for updates and contact.
+ *
+ * Contributors:
+ * Oliver Frank - Initial API and implementation
+ * Stephan Herrmann - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.objectteams.otredyn.bytecode.asm;
+
+import org.eclipse.objectteams.otredyn.bytecode.AbstractBoundClass;
+import org.eclipse.objectteams.otredyn.bytecode.Method;
+import org.eclipse.objectteams.otredyn.transformer.names.ClassNames;
+import org.eclipse.objectteams.otredyn.transformer.names.ConstantMembers;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+import org.objectweb.asm.tree.InsnNode;
+import org.objectweb.asm.tree.IntInsnNode;
+import org.objectweb.asm.tree.LdcInsnNode;
+import org.objectweb.asm.tree.MethodInsnNode;
+import org.objectweb.asm.tree.MethodNode;
+import org.objectweb.asm.tree.TypeInsnNode;
+
+/**
+ * Initially prepares the method access or accessStatic as follows: <br/><br/>
+ * <code>
+ * int memberId = TeamManager.getMemberId(accessId, caller);<br/>
+ * switch (memberId) {<br/>
+ * default:<br/>
+ * return super.access(accessId, opKind, args, caller);<br/>
+ * }<br/>
+ * </code>
+ * @author Oliver Frank
+ */
+public class CreateSwitchForAccessAdapter extends CreateSwitchAdapter {
+
+ private String superClassName;
+ private AbstractBoundClass clazz;
+ public CreateSwitchForAccessAdapter(Method method, String superClassName, AbstractBoundClass clazz) {
+ super(method);
+ this.superClassName = superClassName;
+ this.clazz = clazz;
+ }
+
+ @Override
+ protected void addPreSwitchInstructions(MethodNode method) {
+ // put "accessId" on the stack
+ method.instructions.add(new IntInsnNode(Opcodes.ILOAD,
+ getFirstArgIndex()));
+ // put "caller".getClass() on the stack
+ method.instructions.add(new IntInsnNode(Opcodes.ALOAD,
+ getFirstArgIndex() + 3));
+ method.instructions.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, "java/lang/Object", "getClass", "()Ljava/lang/Class;"));
+ // call "getMemberId(accessId, callerClass)
+ method.instructions
+ .add(new MethodInsnNode(Opcodes.INVOKESTATIC,
+ ClassNames.TEAM_MANAGER_SLASH,
+ ConstantMembers.getMemberId.getName(),
+ ConstantMembers.getMemberId.getSignature()));
+ }
+
+ @Override
+ protected void addInstructionForDefaultLabel(MethodNode method) {
+ if (superClassName.equals("java/lang/Object")) {
+ method.instructions.add(new TypeInsnNode(Opcodes.NEW, "org/objectteams/NoSuchMethodError"));
+ method.instructions.add(new InsnNode(Opcodes.DUP));
+ method.instructions.add(new IntInsnNode(Opcodes.ILOAD, getFirstArgIndex())); // accessId
+ method.instructions.add(new LdcInsnNode(clazz.getName())); // current class
+ method.instructions.add(new LdcInsnNode("decapsulating access")); // access reason
+ method.instructions.add(new MethodInsnNode(Opcodes.INVOKESPECIAL, "org/objectteams/NoSuchMethodError", "<init>", "(ILjava/lang/String;Ljava/lang/String;)V"));
+ method.instructions.add(new InsnNode(Opcodes.ATHROW));
+ } else {
+ Type[] args = Type.getArgumentTypes(method.desc);
+ addInstructionsForLoadArguments(method.instructions, args, getMethod().isStatic());
+
+ int opcode = Opcodes.INVOKESPECIAL;
+ if (getMethod().isStatic()) {
+ opcode = Opcodes.INVOKESTATIC;
+ }
+ method.instructions.add(new MethodInsnNode(opcode,
+ superClassName, getMethod().getName(),
+ getMethod().getSignature()));
+ method.instructions.add(new InsnNode(Opcodes.ARETURN));
+ }
+ }
+
+ @Override
+ protected int getMaxStack() {
+ return 5;
+ }
+
+}
diff --git a/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/CreateSwitchForCallAllBindingsNode.java b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/CreateSwitchForCallAllBindingsNode.java
new file mode 100644
index 000000000..f8a850a7a
--- /dev/null
+++ b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/CreateSwitchForCallAllBindingsNode.java
@@ -0,0 +1,77 @@
+/**********************************************************************
+ * This file is part of "Object Teams Dynamic Runtime Environment"
+ *
+ * Copyright 2009, 2012 Oliver Frank and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Please visit http://www.eclipse.org/objectteams for updates and contact.
+ *
+ * Contributors:
+ * Oliver Frank - Initial API and implementation
+ * Stephan Herrmann - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.objectteams.otredyn.bytecode.asm;
+
+import org.eclipse.objectteams.otredyn.transformer.names.ConstantMembers;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+import org.objectweb.asm.tree.InsnNode;
+import org.objectweb.asm.tree.IntInsnNode;
+import org.objectweb.asm.tree.JumpInsnNode;
+import org.objectweb.asm.tree.LabelNode;
+import org.objectweb.asm.tree.MethodInsnNode;
+import org.objectweb.asm.tree.MethodNode;
+
+/**
+ * Initially prepares the method callAllBindings as follows: <br/><br/>
+ * <code>
+ * switch (boundMethodId) {<br/>
+ * default:<br/>
+ * break;<br/>
+ * }<br/>
+ * <br/>
+ * return callOrig(boundMethodId, args);<br/>
+ * </code>
+ * @author Oliver Frank
+ */
+public class CreateSwitchForCallAllBindingsNode extends CreateSwitchAdapter {
+ private Type[] args;
+ private LabelNode gotoLabel;
+
+ public CreateSwitchForCallAllBindingsNode() {
+ super(ConstantMembers.callAllBindingsClient);
+ }
+
+ @Override
+ protected void addInstructionForDefaultLabel(MethodNode method) {
+ gotoLabel = new LabelNode();
+ method.instructions.add(new JumpInsnNode(Opcodes.GOTO, gotoLabel));
+ }
+
+ @Override
+ protected void addPostSwitchInstructions(MethodNode method) {
+ method.instructions.add(gotoLabel);
+ method.instructions.add(new IntInsnNode(Opcodes.ALOAD, 0));
+
+ args = Type.getArgumentTypes(method.desc);
+ int length = args.length;
+ for (int i = 0; i < length; i++) {
+ Type arg = args[i];
+ method.instructions.add(new IntInsnNode(arg.getOpcode(Opcodes.ILOAD), i + 1));
+ }
+
+ // return callOrig(boundMethodId, args);
+ method.instructions.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, name, ConstantMembers.callOrig.getName(), ConstantMembers.callOrig.getSignature()));
+ method.instructions.add(new InsnNode(Opcodes.ARETURN));
+ }
+
+ @Override
+ protected int getMaxStack() {
+ return args.length + 1;
+ }
+
+}
diff --git a/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/MoveCodeToCallOrigAdapter.java b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/MoveCodeToCallOrigAdapter.java
new file mode 100644
index 000000000..8438da843
--- /dev/null
+++ b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/MoveCodeToCallOrigAdapter.java
@@ -0,0 +1,109 @@
+/**********************************************************************
+ * This file is part of "Object Teams Dynamic Runtime Environment"
+ *
+ * Copyright 2009, 2012 Oliver Frank and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Please visit http://www.eclipse.org/objectteams for updates and contact.
+ *
+ * Contributors:
+ * Oliver Frank - Initial API and implementation
+ * Stephan Herrmann - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.objectteams.otredyn.bytecode.asm;
+
+import org.eclipse.objectteams.otredyn.bytecode.Method;
+import org.eclipse.objectteams.otredyn.transformer.names.ConstantMembers;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+import org.objectweb.asm.tree.InsnList;
+import org.objectweb.asm.tree.InsnNode;
+import org.objectweb.asm.tree.IntInsnNode;
+import org.objectweb.asm.tree.MethodNode;
+import org.objectweb.asm.tree.TypeInsnNode;
+
+
+
+/**
+ * This class moves the code of a method to callOrig.
+ * @author Oliver Frank
+ */
+public class MoveCodeToCallOrigAdapter extends AbstractTransformableClassNode {
+ private Method method;
+ private int boundMethodId;
+ private int firstArgIndex; // slot index of the first argument (0 (static) or 1 (non-static))
+ private int argOffset; // used to skip synth args if the callOrig method itself is a statid role method
+ private Method callOrig;
+
+ public MoveCodeToCallOrigAdapter(AsmWritableBoundClass clazz, Method method, int boundMethodId) {
+ this.method = method;
+ this.boundMethodId = boundMethodId;
+ if (method.isStatic()) {
+ firstArgIndex = 0;
+ argOffset = clazz.isRole() ? 2 : 0;
+ callOrig = clazz.getCallOrigStatic();
+ } else {
+ firstArgIndex = 1;
+ callOrig = ConstantMembers.callOrig;
+ }
+ }
+
+ public void transform() {
+ MethodNode orgMethod = getMethod(method);
+ MethodNode callOrig = getMethod(this.callOrig);
+
+ Type returnType = Type.getReturnType(orgMethod.desc);
+
+
+
+ InsnList newInstructions = new InsnList();
+
+
+ //Unboxing arguments
+ Type[] args = Type.getArgumentTypes(orgMethod.desc);
+
+ if (args.length > 0) {
+ newInstructions.add(new IntInsnNode(Opcodes.ALOAD, firstArgIndex + argOffset + 1));
+
+ int slot = firstArgIndex + argOffset;
+ for (int i = argOffset; i < args.length; i++) {
+ if (i < args.length - 1) {
+ newInstructions.add(new InsnNode(Opcodes.DUP));
+ }
+ newInstructions.add(createLoadIntConstant(i));
+ newInstructions.add(new InsnNode(Opcodes.AALOAD));
+ Type arg = args[i];
+ if (arg.getSort() != Type.ARRAY && arg.getSort() != Type.OBJECT) {
+ String objectType = AsmTypeHelper.getObjectType(arg);
+ newInstructions.add(new TypeInsnNode(Opcodes.CHECKCAST, objectType));
+ newInstructions.add(AsmTypeHelper.getUnboxingInstructionForType(arg, objectType));
+ } else {
+ newInstructions.add(new TypeInsnNode(Opcodes.CHECKCAST, arg.getInternalName()));
+ }
+
+ newInstructions.add(new IntInsnNode(args[i].getOpcode(Opcodes.ISTORE), slot));
+ slot += arg.getSize();
+ }
+ }
+
+ // replace return of the original method with areturn and box the result value if needed
+ replaceReturn(orgMethod.instructions, returnType);
+
+ newInstructions.add(orgMethod.instructions);
+
+ addNewLabelToSwitch(callOrig.instructions, newInstructions, boundMethodId);
+
+ // a minimum stacksize of 3 is neede to box the arguments
+ callOrig.maxStack = Math.max(Math.max(callOrig.maxStack, orgMethod.maxStack), 3);
+
+ // we have to increment the max. stack size, because we have to put NULL on the stack
+ if (returnType.getSort() == Type.VOID) {
+ callOrig.maxStack += 1;
+ }
+ callOrig.maxLocals = Math.max(callOrig.maxLocals, orgMethod.maxLocals);
+ }
+}
diff --git a/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/MultiClassAdapter.java b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/MultiClassAdapter.java
new file mode 100644
index 000000000..0b0bcda74
--- /dev/null
+++ b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/MultiClassAdapter.java
@@ -0,0 +1,78 @@
+/**********************************************************************
+ * This file is part of "Object Teams Dynamic Runtime Environment"
+ *
+ * Copyright 2009, 2012 Oliver Frank and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Please visit http://www.eclipse.org/objectteams for updates and contact.
+ *
+ * Contributors:
+ * Oliver Frank - Initial API and implementation
+ * Stephan Herrmann - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.objectteams.otredyn.bytecode.asm;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.objectweb.asm.ClassAdapter;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.MethodVisitor;
+
+/**
+ * This class is needed to make it possible, that many
+ * ClassAdpters can manipulate the bytecode in one run.
+ * It just delegates all method calls to the concrete Adapters.
+ * @author Oliver Frank
+ */
+class MultiClassAdapter extends ClassAdapter {
+
+ private List<ClassVisitor> visitors;
+ private ClassVisitor toplevelVisitor;
+
+ public MultiClassAdapter(ClassVisitor v) {
+ super(v);
+ this.visitors = new ArrayList<ClassVisitor>();
+ }
+
+ public void addVisitor(ClassVisitor v) {
+ visitors.add(v);
+ }
+
+ /** We only support one visitor to intercept the toplevel class definition. */
+ public void setToplevelVisitor(ClassVisitor v) {
+ this.toplevelVisitor = v;
+ }
+
+ @Override
+ public void visit(int version, int access, String name, String signature,
+ String superName, String[] interfaces) {
+ if (this.toplevelVisitor != null)
+ this.toplevelVisitor.visit(version, access, name, signature, superName, interfaces);
+ else
+ super.visit(version, access, name, signature, superName, interfaces);
+ }
+ @Override
+ public void visitEnd() {
+ for (ClassVisitor visitor : visitors) {
+ visitor.visitEnd();
+ }
+ }
+
+ @Override
+ public MethodVisitor visitMethod(int access, String name, String desc,
+ String signature, String[] exceptions) {
+ MethodVisitor result = null;
+ for (ClassVisitor visitor : visitors) {
+ result = visitor.visitMethod(access, name, desc, signature, exceptions);
+ if (result != null) {
+ return result;
+ }
+ }
+ return super.visitMethod(access, name, desc, signature, exceptions);
+ }
+}
diff --git a/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/runtime/ClassIdentifierProviderFactory.java b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/runtime/ClassIdentifierProviderFactory.java
new file mode 100644
index 000000000..c9e8cbe19
--- /dev/null
+++ b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/runtime/ClassIdentifierProviderFactory.java
@@ -0,0 +1,38 @@
+/**********************************************************************
+ * This file is part of "Object Teams Dynamic Runtime Environment"
+ *
+ * Copyright 2009, 2012 Oliver Frank and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Please visit http://www.eclipse.org/objectteams for updates and contact.
+ *
+ * Contributors:
+ * Oliver Frank - Initial API and implementation
+ * Stephan Herrmann - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.objectteams.otredyn.runtime;
+
+/**
+ * Provides a singleton instance of {@link IClassIdentifierProvider}.
+ * If no instance is set, this class uses the {@link DefaultClassIdentifierProvider}.
+ * @author Oliver Frank
+ */
+public class ClassIdentifierProviderFactory {
+ private static IClassIdentifierProvider instance;
+
+ public static void setClassIdentifierProvider(IClassIdentifierProvider provider) {
+ instance = provider;
+ }
+
+ public static IClassIdentifierProvider getClassIdentifierProvider() {
+ if (instance == null) {
+ instance = new DefaultClassIdentifierProvider();
+ }
+
+ return instance;
+ }
+}
diff --git a/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/runtime/DefaultClassIdentifierProvider.java b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/runtime/DefaultClassIdentifierProvider.java
new file mode 100644
index 000000000..91b10a4bd
--- /dev/null
+++ b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/runtime/DefaultClassIdentifierProvider.java
@@ -0,0 +1,38 @@
+/**********************************************************************
+ * This file is part of "Object Teams Dynamic Runtime Environment"
+ *
+ * Copyright 2009, 2012 Oliver Frank and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Please visit http://www.eclipse.org/objectteams for updates and contact.
+ *
+ * Contributors:
+ * Oliver Frank - Initial API and implementation
+ * Stephan Herrmann - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.objectteams.otredyn.runtime;
+
+/**
+ * Default implementation of {@link IClassIdentifierProvider}, that just
+ * returns the class name as identifier. This implementation could be used
+ * in a standard java context.
+ * @author Oliver Frank
+ */
+public class DefaultClassIdentifierProvider implements IClassIdentifierProvider {
+
+ public String getBoundClassIdentifier(Class<?> teem, String boundClassname) {
+ return boundClassname;
+ }
+
+ public String getSuperclassIdentifier(String classId, String superclassName) {
+ return superclassName;
+ }
+
+ public String getClassIdentifier(Class<?> clazz) {
+ return clazz.getName().replace('.', '/');
+ }
+}
diff --git a/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/runtime/IClassIdentifierProvider.java b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/runtime/IClassIdentifierProvider.java
new file mode 100644
index 000000000..e1fb9a660
--- /dev/null
+++ b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/runtime/IClassIdentifierProvider.java
@@ -0,0 +1,47 @@
+/**********************************************************************
+ * This file is part of "Object Teams Dynamic Runtime Environment"
+ *
+ * Copyright 2009, 2012 Oliver Frank and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Please visit http://www.eclipse.org/objectteams for updates and contact.
+ *
+ * Contributors:
+ * Oliver Frank - Initial API and implementation
+ * Stephan Herrmann - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.objectteams.otredyn.runtime;
+
+/**
+ * This class provides globally unique identifiers for all classes.
+ * @author Oliver Frank
+ */
+public interface IClassIdentifierProvider {
+ /**
+ * Returns a globally unique identifier for a base class of a given team.
+ * @param teem
+ * @param boundClassname
+ * @return
+ */
+ public String getBoundClassIdentifier(Class<?> teem, String boundClassname);
+
+ /**
+ * Returns a globally unique identifier for a superclass of the class
+ * with the given id.
+ * @param classId
+ * @param superclassName
+ * @return
+ */
+ public String getSuperclassIdentifier(String classId, String superclassName);
+
+ /**
+ * Returns a globally unique identifier for a class.
+ * @param clazz
+ * @return
+ */
+ public String getClassIdentifier(Class<?> clazz);
+}
diff --git a/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/runtime/TeamManager.java b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/runtime/TeamManager.java
new file mode 100644
index 000000000..cfab9fbdb
--- /dev/null
+++ b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/runtime/TeamManager.java
@@ -0,0 +1,342 @@
+/**********************************************************************
+ * This file is part of "Object Teams Dynamic Runtime Environment"
+ *
+ * Copyright 2009, 2012 Oliver Frank and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Please visit http://www.eclipse.org/objectteams for updates and contact.
+ *
+ * Contributors:
+ * Oliver Frank - Initial API and implementation
+ * Stephan Herrmann - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.objectteams.otredyn.runtime;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.objectteams.otredyn.bytecode.AbstractBoundClass;
+import org.objectteams.ITeam;
+
+/**
+ * This class administrates the the active teams and their
+ * callin ids for all joinpoints.
+ * Teams have to register/unregister themselves at this class,
+ * while their activation/deactivation.
+ * The generated client code can call methods of this class to
+ * get the active teams and callin ids.
+ * @author Oliver Frank
+ *
+ */
+public class TeamManager {
+
+ public static enum TeamStateChange {
+ REGISTER,
+ UNREGISTER
+ }
+ // void handleTeamStateChange(ITeam t, TeamStateChange stateChange) ;
+ private static List<List<ITeam>> _teams = new ArrayList<List<ITeam>>();
+ private static List<List<Integer>> _callinIds = new ArrayList<List<Integer>>();
+ private static Map<String, Integer> joinpointMap = new HashMap<String, Integer>();
+ private static Map<Class<?>, List<Integer>> accessIdMap = new HashMap<Class<?>, List<Integer>>();
+ private static int currentJoinpointId = 0;
+ // map all original joinpoints to their inherited versions in subclasses
+ private static Map<Integer,List<Integer>> joinpointToSubJoinpoints = new HashMap<Integer, List<Integer>>();
+ private static IClassRepository classRepository;
+
+ public static void setup(IClassRepository repo) {
+ classRepository = repo;
+ }
+
+ /**
+ * Returns all active teams for joinpoint.
+ * This method is intended to be called by
+ * generated client code.
+ * @param joinpointId
+ * @return all active teams for the joinpoint or null
+ * if there are no active teams
+ */
+ public static ITeam[] getTeams(int joinpointId) {
+ List<ITeam> teams = _teams.get(joinpointId);
+ if (teams.size() == 0) {
+ return null;
+ }
+ return teams.toArray(new ITeam[teams.size()]);
+ }
+
+ /**
+ * Returns all callin ids for the active teams and the joinpoint.
+ * This method is intended to be called by
+ * generated client code.
+ * @param joinpointId
+ * @return the callin ids for the joinpoint or null
+ * if there are no active teams
+ */
+ public static int[] getCallinIds(int joinpointId) {
+ List<Integer> callinIds = _callinIds.get(joinpointId);
+ if (callinIds.size() == 0) {
+ return null;
+ }
+ int[] result = new int[callinIds.size()];
+ int i = 0;
+ for (Integer callinId : callinIds) {
+ result[i] = callinId;
+ i++;
+ }
+ return result;
+ }
+
+ /**
+ * Returns the member id for a given team and a access id
+ * used in this team.
+ * This method is intended to be called by
+ * generated client code.
+ * @param accessId
+ * @param Team
+ * @return
+ */
+ public static int getMemberId(int accessId, Class<? extends ITeam> teamClass) {
+ return accessIdMap.get(teamClass).get(accessId);
+ }
+
+ /**
+ * Returns and possibly creates a globally unique id for a
+ * joinpoint identifier. Additionally it prepares the
+ * structures needed to store the teams and callin ids for a joinpoint.
+ * @param joinpointIdentifier
+ * @return a joinpoint id
+ */
+ public synchronized static int getJoinpointId(String joinpointIdentifier) {
+ Integer joinpointId = getExistingJoinpointId(joinpointIdentifier);
+ if (joinpointId == null) {
+ joinpointMap.put(joinpointIdentifier, currentJoinpointId);
+ List<ITeam> teams = new ArrayList<ITeam>();
+ _teams.add(teams);
+ List<Integer> callinIds = new ArrayList<Integer>();
+ _callinIds.add(callinIds);
+ return currentJoinpointId++;
+ }
+ return joinpointId;
+ }
+
+ /**
+ * Returns an existing globally unique joinpoint id
+ * for a joinpoint identifier
+ * @param joinpointIdentifier
+ * @return the joinpoint id or null if a joinpoint id
+ * doesn't exist for this joinpoint identifier
+ */
+ private static Integer getExistingJoinpointId(String joinpointIdentifier) {
+ return joinpointMap.get(joinpointIdentifier);
+ }
+
+ /**
+ * Handles registration and unregistration of teams.
+ * Stores the team and the ids dependend on the joinpoints and
+ * tell the {@link AbstractBoundClass} representing the base classes
+ * of the team, that there is new Binding
+ * @param t
+ * @param stateChange
+ */
+ public static void handleTeamStateChange(ITeam t, TeamManager.TeamStateChange stateChange) {
+ IClassIdentifierProvider provider = ClassIdentifierProviderFactory.getClassIdentifierProvider();
+ Class<? extends ITeam> teamClass = t.getClass();
+ String teamId = provider.getClassIdentifier(teamClass);
+ IBoundTeam teem = classRepository.getTeam(teamClass.getName(), teamId, teamClass.getClassLoader());
+
+ for (IBinding binding : teem.getBindings()) {
+ String boundClassName = binding.getBoundClass();
+ String boundClassIdentifier = provider.getBoundClassIdentifier(teamClass, boundClassName);
+ // FIXME(SH): the following may need adaptation for OT/Equinox or other multi-classloader settings:
+ IBoundClass boundClass = classRepository.getBoundClass(boundClassName.replace('/', '.'), boundClassIdentifier, teamClass.getClassLoader());
+ // FIXME(SH): if boundClass is a role we need to find tsub roles, too!
+ switch (binding.getType()) {
+ case CALLIN_BINDING:
+ IMethod method = boundClass.getMethod(binding.getMemberName(), binding.getMemberSignature(), binding.isHandleCovariantReturn());
+ int joinpointId = getJoinpointId(boundClass
+ .getMethodIdentifier(method));
+ synchronized (method) {
+ changeTeamsForJoinpoint(t, binding.getCallinId(), joinpointId, stateChange);
+ List<Integer> subJoinpoints = joinpointToSubJoinpoints.get(joinpointId);
+ if (subJoinpoints != null)
+ for (Integer subJoinpoint : subJoinpoints)
+ changeTeamsForJoinpoint(t, binding.getCallinId(), subJoinpoint, stateChange);
+ }
+ boundClass.handleAddingOfBinding(binding); // TODO(SH): more lazy
+ break;
+ }
+
+ }
+ }
+ public static void handleTeamLoaded(Class<? extends ITeam> teamClass) {
+ if (teamClass != null)
+ handleDecapsulation(teamClass);
+ performPendingTask();
+ }
+ private static void handleDecapsulation(Class<? extends ITeam> teamClass) {
+ IClassIdentifierProvider provider = ClassIdentifierProviderFactory.getClassIdentifierProvider();
+ String teamId = provider.getClassIdentifier(teamClass);
+ IBoundTeam teem = classRepository.getTeam(teamClass.getName(), teamId, teamClass.getClassLoader());
+
+ for (IBinding binding : teem.getBindings()) {
+ String boundClassName = binding.getBoundClass();
+ String boundClassIdentifier = provider.getBoundClassIdentifier(teamClass, boundClassName.replace('.', '/'));
+ // FIXME(SH): the following may need adaptation for OT/Equinox or other multi-classloader settings:
+ IBoundClass boundClass = classRepository.getBoundClass(boundClassName.replace('/', '.'), boundClassIdentifier, teamClass.getClassLoader());
+
+ switch (binding.getType()) {
+ case FIELD_ACCESS: // fallthrough
+ case METHOD_ACCESS:
+ IMember member = null;
+ if (binding.getType() == IBinding.BindingType.FIELD_ACCESS) {
+ member = boundClass.getField(binding.getMemberName(),
+ binding.getMemberSignature());
+ } else {
+ member = boundClass.getMethod(binding.getMemberName(), binding.getMemberSignature(), false/*covariantReturn*/);
+ }
+
+ int memberId = member.getId(boundClass);
+ synchronized (member) {
+ addAccessIds(teamClass, teem, binding.getCallinId(), memberId);
+ }
+ boundClass.handleAddingOfBinding(binding);
+ break;
+ }
+ }
+ }
+ /**
+ * Stores the access ids of a team and the corresponding member ids
+ * @param t
+ * @param teem
+ * @param accessId
+ * @param memberId
+ * @param stateChange
+ */
+ private static void addAccessIds(Class<? extends ITeam> clazz, IBoundTeam teem, int accessId, int memberId) {
+ List<Integer> accessIds = accessIdMap.get(clazz);
+ if (accessIds == null) {
+ int highestAccessId = teem.getHighestAccessId() + 1;
+ accessIds = new ArrayList<Integer>(highestAccessId);
+ for (int i = 0; i <= highestAccessId; i++) {
+ accessIds.add(0);
+ }
+ accessIdMap.put(clazz, accessIds);
+ }
+ accessIds.set(accessId, memberId);
+ }
+
+ /**
+ * Stores or removes the team
+ * @param t
+ * @param callinId
+ * @param joinpointId
+ * @param stateChange
+ */
+ private static void changeTeamsForJoinpoint(ITeam t, int callinId, int joinpointId, TeamManager.TeamStateChange stateChange) {
+ switch (stateChange) {
+ case REGISTER:
+ List<ITeam> teams = _teams.get(joinpointId);
+ teams.add(0, t);
+ List<Integer> callinIds = _callinIds.get(joinpointId);
+ callinIds.add(0, callinId);
+ break;
+ case UNREGISTER:
+ teams = _teams.get(joinpointId);
+ callinIds = _callinIds.get(joinpointId);
+
+ int index = teams.indexOf(t);
+ while (index > -1) {
+ teams.remove(index);
+ callinIds.remove(index);
+ index = teams.indexOf(t);
+ }
+ break;
+ default: throw new RuntimeException("Unknown team state change: " + stateChange.name());
+ }
+ }
+
+ /**
+ * Merge the teams and callin ids of two joinpoints into the second.
+ * This is used so that activating teams for the second joinpoint (subclass)
+ * will include the effect of activation of the former (superclass).
+ * @param superClass
+ * @param subClass
+ * @param superMethod
+ * @param subMethod
+ */
+ public static void mergeJoinpoints(IBoundClass superClass,
+ IBoundClass subClass, final IMethod superMethod, IMethod subMethod, final boolean handleCovariantReturn) {
+ if (subClass.isAnonymous()) {
+ // destClass is a placeholder, schedule real merging for when a real subclass gets wired:
+ subClass.addWiringTask(new ISubclassWiringTask() {
+ public void wire(IBoundClass superClass, IBoundClass subClass) {
+ IMethod subMethod = subClass.getMethod(superMethod.getName(), superMethod.getSignature(),
+ handleCovariantReturn);
+ mergeJoinpoints(superClass, subClass, superMethod, subMethod, handleCovariantReturn);
+ }
+ });
+ return;
+ }
+ synchronized (subClass) {
+ Integer superJoinpointId = getJoinpointId(superClass.getMethodIdentifier(superMethod));
+ if (superJoinpointId != null) {
+ int subJoinpointId = getJoinpointId(subClass.getMethodIdentifier(subMethod));
+
+ List<Integer> subJoinpoints = joinpointToSubJoinpoints.get(superJoinpointId);
+ if (subJoinpoints == null) {
+ subJoinpoints = new ArrayList<Integer>();
+ joinpointToSubJoinpoints.put(superJoinpointId, subJoinpoints);
+ }
+ // already processed?
+ if (!subJoinpoints.contains(subJoinpointId)) {
+ subJoinpoints.add(subJoinpointId);
+ applyJoinpointMerge(superJoinpointId, subJoinpointId);
+ }
+ }
+ }
+ }
+
+ private synchronized static void applyJoinpointMerge(Integer srcJoinpointId, int destJoinpointId) {
+ List<ITeam> teams = _teams.get(destJoinpointId);
+ List<Integer> callinIds = _callinIds.get(destJoinpointId);
+ List<ITeam> srcTeams = _teams.get(srcJoinpointId);
+ List<Integer> srcCallins = _callinIds.get(srcJoinpointId);
+ for (int s=0; s<srcTeams.size(); s++) {
+ int d = 0; // FIXME(SH): find insertion index based on activation priority!!
+ teams.add(d, srcTeams.get(s));
+ callinIds.add(0, srcCallins.get(s));
+ }
+ _teams.set(destJoinpointId, teams);
+ _callinIds.set(destJoinpointId, callinIds);
+ }
+
+ /**
+ * A "mailbox" for pending tasks (per thread).
+ * The weaver stores redefinition tasks here that failed because the class
+ * was in a state between load-time transformation and definition.
+ */
+ public static ThreadLocal<Runnable> pendingTasks = new ThreadLocal<Runnable>();
+ /**
+ * Perform any tasks that are pending for this thread: redefinitions of a class
+ * that was in a state between load-time transformation and definition.
+ */
+ public static void performPendingTask() {
+ Runnable task = pendingTasks.get();
+ if (task != null) {
+// System.out.println("pending "+task);
+ pendingTasks.set(null);
+ try {
+ task.run();
+ } catch (Throwable t) {
+ System.err.println(t+" because "+t.getCause());
+ pendingTasks.set(task); // no success try later ??
+ }
+ }
+ }
+}
diff --git a/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/transformer/names/ClassNames.java b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/transformer/names/ClassNames.java
new file mode 100644
index 000000000..a4bb5b715
--- /dev/null
+++ b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/transformer/names/ClassNames.java
@@ -0,0 +1,49 @@
+/**********************************************************************
+ * This file is part of "Object Teams Dynamic Runtime Environment"
+ *
+ * Copyright 2009, 2012 Oliver Frank and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Please visit http://www.eclipse.org/objectteams for updates and contact.
+ *
+ * Contributors:
+ * Oliver Frank - Initial API and implementation
+ * Stephan Herrmann - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.objectteams.otredyn.transformer.names;
+
+import java.util.HashSet;
+import java.util.List;
+
+import org.eclipse.objectteams.otredyn.runtime.TeamManager;
+import org.objectteams.IBoundBase;
+import org.objectteams.ITeam;
+import org.objectteams.ImplicitTeamActivation;
+import org.objectteams.SneakyException;
+import org.objectteams.Team;
+
+/**
+ * Container for class names used in the bytecode manipulating classes
+ * @author Oliver Frank
+ */
+public abstract class ClassNames {
+ public final static String I_BOUND_BASE_SLASH = IBoundBase.class.getName().replace('.', '/');
+ public final static String OBJECT_SLASH = Object.class.getName().replace('.', '/');
+ public final static String CLASS_SLASH = Class.class.getName().replace('.', '/');
+ public final static String I_BOUND_BASE_DOT = IBoundBase.class.getName();
+ public final static String TEAM_MANAGER_SLASH = TeamManager.class.getName().replace('.', '/');
+ public final static String ITEAM_SLASH = ITeam.class.getName().replace('.', '/');
+ public final static String TEAM_SLASH = Team.class.getName().replace('.', '/');
+ public final static String LIST_SLASH = List.class.getName().replace('.', '/');
+ public final static String HASH_SET_SLASH = HashSet.class.getName().replace('.', '/');
+ public final static String IMPLICIT_ACTIVATION = ImplicitTeamActivation.class.getName().replace('.', '/');
+
+ public static final String SNEAKY_EXCEPTION_SLASH = SneakyException.class.getName().replace('.', '/');
+ // member of SneakyException:
+ public static final String RETHROW_SELECTOR = "rethrow";
+ public static final String RETHROW_SIGNATURE = "()V";
+}
diff --git a/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/transformer/names/ConstantMembers.java b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/transformer/names/ConstantMembers.java
new file mode 100644
index 000000000..72eec7343
--- /dev/null
+++ b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/transformer/names/ConstantMembers.java
@@ -0,0 +1,123 @@
+/**********************************************************************
+ * This file is part of "Object Teams Dynamic Runtime Environment"
+ *
+ * Copyright 2009, 2012 Oliver Frank and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Please visit http://www.eclipse.org/objectteams for updates and contact.
+ *
+ * Contributors:
+ * Oliver Frank - Initial API and implementation
+ * Stephan Herrmann - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.objectteams.otredyn.transformer.names;
+
+import org.eclipse.objectteams.otredyn.bytecode.Field;
+import org.eclipse.objectteams.otredyn.bytecode.Method;
+import org.eclipse.objectteams.otredyn.bytecode.Types;
+import org.objectweb.asm.Opcodes;
+
+
+
+/**
+ * Container for methods used in the bytecode manipulating classes
+ * @author Oliver Frank
+ */
+public abstract class ConstantMembers {
+
+ // predefined field:
+ public static final String OT_ROLE_SET = "_OT$roleSet";
+ public static final String HASH_SET_FIELD_TYPE = Types
+ .getTypeStringForField(Types.getAsType(ClassNames.HASH_SET_SLASH));
+ public static final Field roleSet = new Field(OT_ROLE_SET, HASH_SET_FIELD_TYPE);
+
+ // predefined methods
+ public static final Method callOrig = new Method("_OT$callOrig", Types
+ .getTypeStringForMethod(Types.getAsType(ClassNames.OBJECT_SLASH),
+ new String[] { Types.INT,
+ Types.getAsArrayType(ClassNames.OBJECT_SLASH) }));
+
+ public static final Method callOrigStatic = new Method(
+ "_OT$callOrigStatic",
+ Types.getTypeStringForMethod(Types
+ .getAsType(ClassNames.OBJECT_SLASH), new String[] {
+ Types.INT, Types.getAsArrayType(ClassNames.OBJECT_SLASH) }),
+ true, Opcodes.ACC_PUBLIC);
+
+ // this method's signature actually depends on the enclosing team class
+ // used when generating callOrigStatic method into a role class
+ // which needs two synthetic arguments.
+ public static Method callOrigStaticRoleVersion(String teamClass) {
+ return new Method(
+ "_OT$callOrigStatic",
+ Types.getTypeStringForMethod(
+ Types.getAsType(ClassNames.OBJECT_SLASH),
+ new String[] {
+ Types.INT,
+ Types.getAsType(teamClass),
+ Types.INT,
+ Types.getAsArrayType(ClassNames.OBJECT_SLASH)
+ }),
+ true, Opcodes.ACC_PUBLIC);
+ }
+
+ public static final Method callAllBindingsClient = new Method(
+ "callAllBindings", Types.getTypeStringForMethod(Types
+ .getAsType(ClassNames.OBJECT_SLASH), new String[] {
+ Types.INT, Types.getAsArrayType(ClassNames.OBJECT_SLASH) }));
+
+ public static final Method callAllBindingsTeam = new Method(
+ "_OT$callAllBindings", Types.getTypeStringForMethod(Types
+ .getAsType(ClassNames.OBJECT_SLASH), new String[] {
+ Types.getAsType(ClassNames.I_BOUND_BASE_SLASH),
+ Types.getAsArrayType(ClassNames.ITEAM_SLASH), Types.INT,
+ Types.getAsArrayType(Types.INT), Types.INT,
+ Types.getAsArrayType(ClassNames.OBJECT_SLASH) }));
+
+ public static final Method access = new Method("_OT$access", Types
+ .getTypeStringForMethod(Types.getAsType(ClassNames.OBJECT_SLASH),
+ new String[] { Types.INT, Types.INT,
+ Types.getAsArrayType(ClassNames.OBJECT_SLASH),
+ Types.getAsType(ClassNames.ITEAM_SLASH) }));
+
+ public static final Method accessStatic = new Method("_OT$accessStatic", Types
+ .getTypeStringForMethod(Types.getAsType(ClassNames.OBJECT_SLASH),
+ new String[] { Types.INT, Types.INT,
+ Types.getAsArrayType(ClassNames.OBJECT_SLASH),
+ Types.getAsType(ClassNames.ITEAM_SLASH) }), true, Opcodes.ACC_PUBLIC);
+
+ public static final Method getTeams = new Method("getTeams", Types
+ .getTypeStringForMethod(
+ Types.getAsArrayType(ClassNames.ITEAM_SLASH),
+ new String[] { Types.INT }));
+
+ public static final Method getCallinIds = new Method("getCallinIds", Types
+ .getTypeStringForMethod(Types.getAsArrayType(Types.INT),
+ new String[] { Types.INT }));
+
+ public static final Method getMemberId = new Method("getMemberId", Types
+ .getTypeStringForMethod(Types.INT, new String[] { Types.INT,
+ Types.getAsType(ClassNames.CLASS_SLASH) }));
+
+ public static final Method addOrRemoveRole = new Method("_OT$addOrRemoveRole", Types
+ .getTypeStringForMethod(Types.VOID, new String[] { Types.getAsType(ClassNames.OBJECT_SLASH), Types.BOOLEAN }));
+
+ public static boolean isReflectiveOTMethod(String methodName, String methodDescriptor) {
+ if ((methodName.equals("hasRole") && methodDescriptor.equals("(Ljava/lang/Object;)Z"))
+ || (methodName.equals("hasRole") && methodDescriptor.equals("(Ljava/lang/Object;Ljava/lang/Class;)Z"))
+ || (methodName.equals("getRole") && methodDescriptor.equals("(Ljava/lang/Object;)Ljava/lang/Object;"))
+ || (methodName.equals("getRole") && methodDescriptor.equals("(Ljava/lang/Object;Ljava/lang/Class;)Ljava/lang/Object;"))
+ || (methodName.equals("getAllRoles") && methodDescriptor.equals("()[Ljava/lang/Object;"))
+ || (methodName.equals("getAllRoles") && methodDescriptor.equals("(Ljava/lang/Class;)[Ljava/lang/Object;"))
+ || (methodName.equals("unregisterRole") && methodDescriptor.equals("(Ljava/lang/Object;)V"))
+ || (methodName.equals("unregisterRole") && methodDescriptor.equals("(Ljava/lang/Object;Ljava/lang/Class;)V"))
+ )
+ return true;
+ return false;
+ }
+
+}
diff --git a/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/util/ArrayUtil.java b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/util/ArrayUtil.java
new file mode 100644
index 000000000..7f3b84119
--- /dev/null
+++ b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/util/ArrayUtil.java
@@ -0,0 +1,47 @@
+/**********************************************************************
+ * This file is part of "Object Teams Dynamic Runtime Environment"
+ *
+ * Copyright 2009, 2012 Oliver Frank and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Please visit http://www.eclipse.org/objectteams for updates and contact.
+ *
+ * Contributors:
+ * Oliver Frank - Initial API and implementation
+ * Stephan Herrmann - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.objectteams.otredyn.util;
+
+
+public abstract class ArrayUtil {
+
+ public static String[] stringArrayPrepend(String[] array,String item) {
+
+ if (array == null) {
+ return new String[] { item } ;
+ }
+
+ int arr_len = array.length;
+ String [] new_arr = new String[array.length+1];
+ System.arraycopy(array,0,new_arr,1,arr_len);
+ new_arr[0] = item;
+ return new_arr;
+ }
+
+ public static String[] stringArrayAppend(String[] array,String item) {
+
+ if (array == null) {
+ return new String[] { item } ;
+ }
+
+ int arr_len = array.length;
+ String [] new_arr = new String[array.length+1];
+ System.arraycopy(array,0,new_arr,0,arr_len);
+ new_arr[arr_len] = item;
+ return new_arr;
+ }
+}
diff --git a/plugins/org.eclipse.objectteams.otredyn/src/org/objectteams/IBoundBase.java b/plugins/org.eclipse.objectteams.otredyn/src/org/objectteams/IBoundBase.java
new file mode 100644
index 000000000..afc892ab8
--- /dev/null
+++ b/plugins/org.eclipse.objectteams.otredyn/src/org/objectteams/IBoundBase.java
@@ -0,0 +1,42 @@
+/**********************************************************************
+ * This file is part of "Object Teams Dynamic Runtime Environment"
+ *
+ * Copyright 2007, 2012 Berlin Institute of Technology, Germany, and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Please visit http://www.eclipse.org/objectteams for updates and contact.
+ *
+ * Contributors:
+ * Berlin Institute of Technology - Initial API and implementation
+ * Oliver Frank - Initial API and Implementation
+ **********************************************************************/
+package org.objectteams;
+
+/** Super type for all bound base classes. Purely internal class, not intended for client use. */
+public interface IBoundBase {
+
+ /**
+ * Call a bound base method identified by its ID.
+ * @param boundMethod_id globally unique ID of a bound base method
+ * @param args packed arguments (incl. boxing)
+ * @return (possibly boxed) result of the bound base method.
+ */
+ Object _OT$callOrig(int boundMethod_id, Object[] args);
+
+ /**
+ * Provides access to fields and methods of a base class
+ * that have package, protected or private visbility
+ * @param accessId Unique identifier in the class for the field or method
+ * @param opKind 0 for read access, 1 for write access. only used for fields
+ * @param args arguments for a method
+ * @return
+ */
+ Object _OT$access(int accessId, int opKind, Object[] args, Team caller);
+
+ /** Method to be used by generated code, only (lifting constructor & unregisterRole()). */
+ void _OT$addOrRemoveRole(Object aRole, boolean adding);
+} \ No newline at end of file
diff --git a/plugins/org.eclipse.objectteams.otredyn/src/org/objectteams/Team.java b/plugins/org.eclipse.objectteams.otredyn/src/org/objectteams/Team.java
new file mode 100644
index 000000000..b59aaea59
--- /dev/null
+++ b/plugins/org.eclipse.objectteams.otredyn/src/org/objectteams/Team.java
@@ -0,0 +1,655 @@
+/**********************************************************************
+ * This file is part of "Object Teams Dynamic Runtime Environment"
+ *
+ * Copyright 2002, 2012 Berlin Institute of Technology, Germany, and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Please visit http://www.eclipse.org/objectteams for updates and contact.
+ *
+ * Contributors:
+ * Berlin Institute of Technology - Initial API and implementation
+ * Oliver Frank - Initial API and Implementation
+ **********************************************************************/
+package org.objectteams;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.WeakHashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+
+import org.eclipse.objectteams.otredyn.runtime.TeamManager;
+
+
+/**
+ * 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>() {
+ @Override
+ 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 (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 activation 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 final boolean isActive() {
+ return isActive(Thread.currentThread());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public final boolean isActive(Thread thread) {
+ 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) {
+ // register the team at the TeamManager
+ TeamManager.handleTeamStateChange(this, TeamManager.TeamStateChange.REGISTER);
+ _OT$registrationState = _OT$REGISTERED;
+ }
+ }
+
+ private void doUnregistration() {
+ if (_OT$registrationState == _OT$REGISTERED) {
+ // unregister the team at the TeamManager
+ TeamManager.handleTeamStateChange(this, TeamManager.TeamStateChange.UNREGISTER);
+ _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) throws IllegalArgumentException {
+ // 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) throws IllegalArgumentException {
+ // 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) throws IllegalArgumentException {
+ // 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) throws IllegalArgumentException {
+ // 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)
+
+ /**
+ * If a serializable team wishes to persist its global activation status it must
+ * call this method from its writeObject() method and correspondingly call
+ * {@link #readGlobalActivationState(ObjectInputStream)} from its readObject().
+ */
+ protected void writeGlobalActivationState(ObjectOutputStream out) throws IOException {
+ out.writeBoolean(this._OT$globalActive);
+ }
+ /**
+ * If a serializable team wishes to persist its global activation status it must
+ * call this method from its readObject() method and correspondingly call
+ * {@link #writeGlobalActivationState(ObjectOutputStream)} from its writeObject().
+ * If a team is restored that was globally active when serialized, it will be activated
+ * correspondingly during deserialization when this method is called.
+ */
+ protected void readGlobalActivationState(ObjectInputStream in) throws IOException {
+ this._OT$globalActive = in.readBoolean();
+ if (this._OT$globalActive) {
+ this._OT$lazyGlobalActiveFlag = true;
+ this.doRegistration();
+ }
+ }
+ /**
+ * Serializable teams must invoke this method once from their readObject() method
+ * in order to re-initialize internal data structures.
+ */
+ protected void restore() { /* empty; implementation will be generated for each serializable sub-class. */ }
+ /**
+ * Serializable teams must invoke this method from their readObject() method
+ * for each role that has been retrieved and shall be re-registered for this team.
+ */
+ protected void restoreRole(Class<?> clazz, Object role) { /* empty; implementation will be generated for each serializable sub-class. */ }
+
+ /**
+ * This method is the first part of the new chaining wrapper.
+ * It should be called from the generated client code.
+ *
+ * @param baze the current base object
+ * @param teams the current team objects
+ * @param idx the index of the current team in teams
+ * @param callinIds an array of ids, that are unique in the team
+ * for a base method in a base class
+ * @param boundMethodId an unique id for a base method in the base class.
+ * This id is needed for a base call.
+ * @param args packed arguments.
+ * @return possibly boxed result
+ */
+ public Object _OT$callAllBindings(IBoundBase baze, ITeam[] teams,int idx,int[] callinIds, int boundMethodId, Object[] args)
+ {
+
+
+ this._OT$callBefore(baze, callinIds[idx], boundMethodId, args);
+
+ Object res = this._OT$callReplace(baze, teams, idx, callinIds, boundMethodId, args);
+
+ this._OT$callAfter(baze, callinIds[idx], boundMethodId, args, res); // make result available to param mappings!
+
+ return res;
+ }
+
+ /**
+ * This method calls the next team or a base method,
+ * if there are no more active teams for a joinpoint
+ *
+ * @param baze the current base object
+ * @param teams the current base object
+ * @param idx the index of the current team in teams, also points into callinIds, i.e., both lists run synchroneously.
+ * @param callinIds an array of ids, that are unique in the team
+ * for a base method in a base class
+ * @param boundMethodId an unique id for a base method in the base class.
+ * This id is needed for a base call.
+ * @param args original packed arguments.
+ * @param baseCallArgs packed arguments as provided to the base call.
+ * @return possibly boxed result
+ */
+ public Object _OT$callNext(IBoundBase baze, ITeam[] teams, int idx, int[] callinIds, int boundMethodId, Object[] args, Object[] baseCallArgs)
+ {
+//System.out.println("callNext idx="+idx);
+//for (Team t : teams)
+// System.out.println("team="+t);
+ // Are there still active teams?
+ if (idx+1 < teams.length) {
+ // Yes, so call the next team/callin
+ return teams[idx+1]._OT$callAllBindings(baze, teams, idx+1, callinIds, boundMethodId, args);
+ } else {
+ //No, call the base method
+ if (baze == null) {
+ //handle base call to a static base method
+ return teams[idx]._OT$callOrigStatic(callinIds[idx], boundMethodId, args);
+ } else {
+//System.out.println("callOrig: "+boundMethodId);
+ return baze._OT$callOrig(boundMethodId, args);
+//Object result = baze.callOrig(boundMethodId, args);
+//System.out.println("->"+result);
+//return result;
+ }
+ }
+ }
+
+ /**
+ * Executes all before callins for a given callin id.
+ * Must be overridden by a team, if the team gets replace callins.
+ *
+ * @param baze the current base object
+ * @param callinId the current callin id
+ * @param boundMethodId an unique id for a base method in the base class.
+ * This id is needed for a base call.
+ * @param args packed arguments.
+ * @return possibly boxed result
+ */
+ public void _OT$callBefore(IBoundBase baze, int callinId, int boundMethodId, Object[] args) {
+ // nop; override with code from before callin bindings.
+ }
+
+ /**
+ * Executes all after callins for a given callin id.
+ * Must be overridden by a team, if the team gets replace callins.
+ *
+ * @param baze the current base object
+ * @param callinId the current callin id
+ * @param boundMethodId an unique id for a base method in the base class.
+ * This id is needed for a base call.
+ * @param args packed arguments.
+ * @param result the result of the base method. Could be used by after callins
+ */
+ public void _OT$callAfter(IBoundBase baze, int callinId, int boundMethodId, Object[] args, Object result) {
+ // nop; override with code from after callin bindings.
+ }
+
+ /**
+ * Execute replace callins of the team for the current callin id.
+ * Must be overridden by a team, if the team has got replace callins.
+ *
+ * @param baze the current base object
+ * @param teams the current base object
+ * @param idx the index of the current team in teams
+ * @param callinIds an array of ids, that are unique in the team
+ * for a base method in a base class
+ * @param boundMethodId an unique id for a base method in the base class.
+ * This id is needed for a base call.
+ * @param args packed arguments.
+ * @return possibly boxed result
+ */
+ public Object _OT$callReplace(IBoundBase baze, ITeam[] teams, int idx, int[] callinIds, int boundMethodId, Object[] args) {
+ // default; override with code from replace callin bindings.
+ return _OT$callNext(baze, teams, idx, callinIds, boundMethodId, args, null);
+ }
+
+ /**
+ * Calls the method callOrigStatic of a concrete class dependend on the
+ * given callin id.
+ * Must be overridden in a team, if the team has got base calls
+ * to static base methods
+ * @param callinId
+ * @param boundMethodId
+ * @param args
+ * @return
+ */
+ public Object _OT$callOrigStatic(int callinId, int boundMethodId, Object[] args) {
+ return null;
+ }
+}

Back to the top