otredyn: implement callout (compiler-part)
Includes improvements regarding Bug 352914 - Avoid unnecessary decapsulation accessors for callout to field
- direct callout-set
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/ast/AbstractMethodMappingDeclaration.java b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/ast/AbstractMethodMappingDeclaration.java
index d1630a9..136713f 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/ast/AbstractMethodMappingDeclaration.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/ast/AbstractMethodMappingDeclaration.java
@@ -517,7 +517,7 @@
 	protected abstract void checkThrownExceptions (MethodSpec methodSpec);
 
 	protected void checkThrownExceptions(MethodBinding provided, MethodBinding expected) {
-		if (provided.thrownExceptions != null) {
+		if (provided != null && provided.thrownExceptions != null) {
 			if (expected.thrownExceptions != null) {
 				outer: for (int i = 0; i < provided.thrownExceptions.length; i++) {
 					ReferenceBinding thrown = provided.thrownExceptions[i];
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/ast/FieldAccessSpec.java b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/ast/FieldAccessSpec.java
index aa7eceb..cb57c97 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/ast/FieldAccessSpec.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/ast/FieldAccessSpec.java
@@ -28,7 +28,6 @@
 import org.eclipse.jdt.internal.compiler.lookup.Binding;
 import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
 import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
-import org.eclipse.jdt.internal.compiler.lookup.InvocationSite;
 import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
 import org.eclipse.jdt.internal.compiler.lookup.ProblemFieldBinding;
 import org.eclipse.jdt.internal.compiler.lookup.ProblemReasons;
@@ -41,6 +40,7 @@
 import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.CallinCalloutScope;
 import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.ITeamAnchor;
 import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.RoleTypeBinding;
+import org.eclipse.objectteams.otdt.internal.core.compiler.mappings.CallinImplementorDyn;
 import org.eclipse.objectteams.otdt.internal.core.compiler.model.FieldModel;
 import org.eclipse.objectteams.otdt.internal.core.compiler.model.RoleModel;
 import org.eclipse.objectteams.otdt.internal.core.compiler.model.TeamModel;
@@ -68,7 +68,7 @@
  * @author stephan
  * @version $Id: FieldAccessSpec.java 23401 2010-02-02 23:56:05Z stephan $
  */
-public class FieldAccessSpec extends MethodSpec implements InvocationSite {
+public class FieldAccessSpec extends MethodSpec {
 
 	public int calloutModifier; // either TokenNameget or TokenNameset (from TerminalTokens).
 	public FieldBinding resolvedField; // the field in the corresponding base class
@@ -150,36 +150,41 @@
    		}
 
    		if (   !baseType.isRole()
-   			&& this.calloutModifier == TerminalTokens.TokenNameget
-   			&& this.resolvedField.canBeSeenBy(scope.enclosingReceiverType(), this, scope)) 
+   			&& this.resolvedField.canBeSeenBy(scope.enclosingReceiverType().baseclass(), this, scope)) 
    		{
-   			// no accessor method needed, signal this fact by NOT setting selector to accessorSelector 
-   			// and not setting resolvedMethod below
-   			this.parameters = Binding.NO_PARAMETERS;
+   			// no accessor method needed
+   			this.implementationStrategy = ImplementationStrategy.DIRECT;
+   			if (!this.isSetter())
+   				this.parameters = Binding.NO_PARAMETERS;
+   			else
+   				this.parameters = new TypeBinding[] { this.fieldType };
    			return;
-   		} else {
-	   		// find accessor method which might have been generated already.
-			char[] accessorSelector = getSelector();
-			MethodBinding result = null;
-			if (!this.resolvedField.isPrivate()) // don't reuse accessor to private field from super-base (see Trac #232)
-				result = baseType.getMethod(scope, accessorSelector);
-			// NOTE: could be optimized if type has no such method but exact type already has.
-			//       but the the OTRE would need to be informed..
-
-			if (   result == null
-			    || !isMethodCompatible(result))
-			{
-				// record this field access for Attribute generation:
-				RoleModel roleModel = scope.enclosingSourceType().roleModel;
-				ReferenceBinding targetClass =  roleModel.addAccessedBaseField(this.resolvedField, this.calloutModifier);
-
-				// create accessor method:
-				result = createMethod(targetClass, accessorSelector);
-				baseType.addMethod(result);
-			}
-			this.selector = accessorSelector;
-			this.resolvedMethod = result;
    		}
+
+		this.implementationStrategy = CallinImplementorDyn.DYNAMIC_WEAVING 
+				? ImplementationStrategy.DYN_ACCESS : ImplementationStrategy.DECAPS_WRAPPER;
+
+   		// find accessor method which might have been generated already.
+		char[] accessorSelector = getSelector();
+		MethodBinding result = null;
+		if (!this.resolvedField.isPrivate()) // don't reuse accessor to private field from super-base (see Trac #232)
+			result = baseType.getMethod(scope, accessorSelector);
+		// NOTE: could be optimized if type has no such method but exact type already has.
+		//       but the the OTRE would need to be informed..
+
+		if (   result == null
+		    || !isMethodCompatible(result))
+		{
+			// record this field access for Attribute generation:
+			RoleModel roleModel = scope.enclosingSourceType().roleModel;
+			ReferenceBinding targetClass =  roleModel.addAccessedBaseField(this.resolvedField, this.calloutModifier);
+
+			// create accessor method:
+			result = createMethod(targetClass, accessorSelector);
+			baseType.addMethod(result);
+		}
+		this.selector = accessorSelector;
+		this.resolvedMethod = result;
 		this.parameters = this.resolvedMethod.getSourceParameters();
     }
 
@@ -281,9 +286,8 @@
 
 	@Override
 	void checkDecapsulation(ReferenceBinding baseClass, Scope scope) {
-		baseClass= baseClass.getRealClass(); // fields are in the class!
-		if (!this.resolvedField.canBeSeenBy(baseClass, this, scope))
-   			scope.problemReporter().decapsulation(this, baseClass, scope, isSetter());
+		if (this.implementationStrategy != ImplementationStrategy.DIRECT)
+			scope.problemReporter().decapsulation(this, baseClass, scope, isSetter());
 	}
 
 	public boolean checkBaseReturnType(CallinCalloutScope scope, int bindDir)
@@ -319,7 +323,13 @@
 		int argumentPosition = 0; // safer against AIOOBE
 		if (this.resolvedField != null && !this.resolvedField.isStatic())
 			argumentPosition = 1;
-		TypeBinding accessorParamType = this.resolvedMethod.parameters[argumentPosition];
+		TypeBinding accessorParamType = null;
+		if (this.resolvedMethod != null)
+			accessorParamType = this.resolvedMethod.parameters[argumentPosition];
+		else if (this.hasSignature)
+			accessorParamType = this.arguments[0].type.resolvedType;
+		else
+			return true; // nothing to check
 		ReferenceBinding baseclass = scope.enclosingReceiverType().baseclass();
 		if (baseclass != null && baseclass.isTeam() && accessorParamType.isRole())
 			accessorParamType = TeamModel.strengthenRoleType(baseclass, accessorParamType);
@@ -370,33 +380,19 @@
 		return output;
 	}
 
-	// implement InvocationSite
-	public TypeBinding[] genericTypeArguments() {
-		return null;
-	}
-	public boolean isSuperAccess() {
-		return false;
-	}
+	// implement InvocationSite (override method from MethodSpec):
 	public boolean isTypeAccess() {
 		return this.resolvedField != null && this.resolvedField.isStatic();
 	}
-	public void setActualReceiverType(ReferenceBinding receiverType) {
-		// ignored
+
+	public boolean canBeeSeenBy(ReferenceBinding receiverType, Scope scope) {
+		if (this.resolvedField == null)
+			return false;
+		return this.resolvedField.canBeSeenBy(receiverType, this, scope);
 	}
 
-	public void setDepth(int depth) {
-		// ignored
+	public void createAccessAttribute(RoleModel roleModel) {		
+		roleModel.addAccessedBaseField(this.resolvedField, this.calloutModifier);
 	}
 
-	public void setFieldIndex(int depth) {
-		// ignored
-	}
-
-	/**
-	 * Used for generic method resolving, however, FieldAccessSpec is not an invocationSite used for invoking generic methods.
-	 * (we implement InvocationSite only for visibility checking).
-	 */
-	public TypeBinding expectedType() {
-		return null;
-	}
 }
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/ast/MethodSpec.java b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/ast/MethodSpec.java
index a1d9320..f1077e5 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/ast/MethodSpec.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/ast/MethodSpec.java
@@ -40,6 +40,7 @@
 import org.eclipse.jdt.internal.compiler.lookup.Binding;
 import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
 import org.eclipse.jdt.internal.compiler.lookup.ExtraCompilerModifiers;
+import org.eclipse.jdt.internal.compiler.lookup.InvocationSite;
 import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
 import org.eclipse.jdt.internal.compiler.lookup.ParameterizedGenericMethodBinding;
 import org.eclipse.jdt.internal.compiler.lookup.ProblemMethodBinding;
@@ -55,7 +56,9 @@
 import org.eclipse.objectteams.otdt.core.exceptions.InternalCompilerError;
 import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.AnchorMapping;
 import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.CallinCalloutScope;
+import org.eclipse.objectteams.otdt.internal.core.compiler.mappings.CallinImplementorDyn;
 import org.eclipse.objectteams.otdt.internal.core.compiler.model.MethodModel;
+import org.eclipse.objectteams.otdt.internal.core.compiler.model.RoleModel;
 import org.eclipse.objectteams.otdt.internal.core.compiler.model.TeamModel;
 import org.eclipse.objectteams.otdt.internal.core.compiler.statemachine.transformer.MethodSignatureEnhancer;
 import org.eclipse.objectteams.otdt.internal.core.compiler.util.RoleTypeCreator;
@@ -71,7 +74,7 @@
  * @author Markus Witte
  * @version $Id: MethodSpec.java 23401 2010-02-02 23:56:05Z stephan $
  */
-public class MethodSpec extends ASTNode
+public class MethodSpec extends ASTNode implements InvocationSite
 {
 	// ==== structural fields (AST): ====
 	public char[] selector;
@@ -97,6 +100,15 @@
 	public int callinID = -1;
 // SH}
 
+	public enum ImplementationStrategy {
+		/** Callout is translated to direct access to the base feature. */
+		DIRECT,
+		/** Callout uses a decapsulation wrapper generated by the (old) OTRE. */
+		DECAPS_WRAPPER,
+		/** Callout uses a generic _OT$access or _OT$accessStatic method generated by the OTREDyn. */
+		DYN_ACCESS
+	}
+	public ImplementationStrategy implementationStrategy;
 
 	/**
 	 * Parsing thought it was reading a method declaration.
@@ -469,7 +481,13 @@
 	}
 
 	void checkDecapsulation(ReferenceBinding baseClass, Scope scope) {
-		// for methods currently done using the generated wrapper, FieldAccessSpec overrides this.
+		if (!this.resolvedMethod.canBeSeenBy(baseClass, this, scope)) {
+			this.implementationStrategy = CallinImplementorDyn.DYNAMIC_WEAVING 
+					? ImplementationStrategy.DYN_ACCESS : ImplementationStrategy.DECAPS_WRAPPER;
+   			scope.problemReporter().decapsulation(this, baseClass, scope);
+		} else {
+			this.implementationStrategy = ImplementationStrategy.DIRECT;
+		}
 	}
 
 	/**
@@ -690,4 +708,47 @@
 		return this.callinID;
 	}
 // SH}
+
+	public boolean canBeeSeenBy(ReferenceBinding receiverType, Scope scope) {
+		if (this.resolvedMethod == null)
+			return false;
+		return this.resolvedMethod.canBeSeenBy(receiverType, this, scope);
+	}
+
+
+	// implement InvocationSite
+	public TypeBinding[] genericTypeArguments() {
+		return null;
+	}
+	public boolean isSuperAccess() {
+		return false;
+	}
+	
+	public boolean isTypeAccess() {
+		return this.resolvedMethod != null && this.resolvedMethod.isStatic();
+	}
+
+	public void setActualReceiverType(ReferenceBinding receiverType) {
+		// ignored		
+	}
+
+	public void setDepth(int depth) {
+		// ignored
+	}
+
+	public void setFieldIndex(int depth) {
+		// ignored		
+	}
+
+	/**
+	 * Used for generic method resolving, however, we implement InvocationSite only for visibility checking,
+	 * not for type checking.
+	 */
+	public TypeBinding expectedType() {
+		return null;
+	}
+
+	public void createAccessAttribute(RoleModel roleModel) {
+		roleModel.addInaccessibleBaseMethod(this.resolvedMethod);		
+	}
 }
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/bytecode/OTSpecialAccessAttribute.java b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/bytecode/OTSpecialAccessAttribute.java
index ee328d3..f92fe03 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/bytecode/OTSpecialAccessAttribute.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/bytecode/OTSpecialAccessAttribute.java
@@ -61,6 +61,7 @@
 	private static final int DYN_CALLOUT_FIELD_ACCESS = 5;
 	private static final int DYN_SUPER_METHOD_ACCESS = 6;
 	private static final int M_SIZE = CallinImplementorDyn.DYNAMIC_WEAVING ? 8 : 6;
+	private static final int F_SIZE = CallinImplementorDyn.DYNAMIC_WEAVING ? 8 : 7;
 
 	int nextAccessId = 0;
 	
@@ -120,6 +121,7 @@
 		FieldBinding field;
 		ReferenceBinding targetClass;
 		int flags; // use the above constants
+		private int accessId;
 		CalloutToFieldDesc(FieldBinding field, ReferenceBinding targetClass, int calloutModifier)
 		{
 			this.field = field;
@@ -128,7 +130,8 @@
 							CALLOUT_GET_FIELD : CALLOUT_SET_FIELD;
 			if (field.isStatic())
 				this.flags |= CALLOUT_STATIC_FIELD;
-
+			if (CallinImplementorDyn.DYNAMIC_WEAVING)
+				this.accessId = nextAccessId++;
 		}
 
 		public int calloutModifier() {
@@ -138,7 +141,12 @@
 		}
 
 		void write() {
-			writeByte((byte)CALLOUT_FIELD_ACCESS);
+			if (CallinImplementorDyn.DYNAMIC_WEAVING) {
+				writeByte((byte)DYN_CALLOUT_FIELD_ACCESS);
+				writeByte((byte)this.accessId);
+			} else {
+				writeByte((byte)CALLOUT_FIELD_ACCESS);
+			}
 			writeByte((byte)this.flags);
 			writeName(this.targetClass.attributeName());
 			writeName(this.field.name);
@@ -241,7 +249,7 @@
 
         int attributeSize  = 4; // initially empty, except for two counts
 		attributeSize += this._decapsulatedMethods.size() * (1+M_SIZE); // 1 byte kind, 3 names (+1 short for otredyn)
-		attributeSize += this._calloutToFields.size() * 8;     			// 1 byte kind, 1 byte flags, 3 names
+		attributeSize += this._calloutToFields.size() * (1+F_SIZE);		// 1 byte kind, 1 byte flags, 3 names (+1 byte for otredyn) 
 		attributeSize += this._superMethods.size() * 9;        			// 1 byte kind, 4 names
 		attributeSize += this._adaptedBaseclasses.size() * 3;  			// 1 name + 1 byte flag
 
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/mappings/CalloutImplementor.java b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/mappings/CalloutImplementor.java
index ac9ca14..0a39b91 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/mappings/CalloutImplementor.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/mappings/CalloutImplementor.java
@@ -38,6 +38,7 @@
 import org.eclipse.jdt.internal.compiler.ast.Expression;
 import org.eclipse.jdt.internal.compiler.ast.MessageSend;
 import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.NameReference;
 import org.eclipse.jdt.internal.compiler.ast.Statement;
 import org.eclipse.jdt.internal.compiler.ast.ThisReference;
 import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
@@ -557,41 +558,57 @@
 							CastExpression.DO_WRAP);
 
 		Expression baseAccess = null;
-		if (calloutDecl.isCalloutToField()) {
-			FieldAccessSpec fieldSpec = (FieldAccessSpec) calloutDecl.baseMethodSpec;
-			if (fieldSpec.resolvedMethod == null) {
-				// not using a decapsulation accessor but direct field access:
-				if (fieldSpec.resolvedField.isStatic())
-					baseAccess = gen.qualifiedNameReference(fieldSpec.resolvedField);
-				else
-					baseAccess = gen.qualifiedNameReference(new char[][] {IOTConstants._OT_BASE, fieldSpec.resolvedField.name });
-			}
-		} 
-		if (baseAccess == null) {
-			if (calloutDecl.baseMethodSpec.isPrivate() && baseType.isRole()) {
-	    		// tricky case: callout to a private role method (base-side)
-	    		// requires the indirection via two wrapper methods (privateBridgeMethod)
-	
-	    		// compensate weakening:
-	    		if (baseType instanceof WeakenedTypeBinding)
-	    			baseType = ((WeakenedTypeBinding)baseType).getStrongType();
-	
-	    		// generated message send refers to public bridge, report decapsulation now:
-	    		calloutDecl.scope.problemReporter().decapsulation(calloutDecl.baseMethodSpec, baseType, calloutDecl.scope);
-	
-	    		boolean isCalloutToField = calloutDecl.isCalloutToField();
-	    		MethodBinding targetMethod = calloutDecl.baseMethodSpec.resolvedMethod;
-		    	baseAccess = new PrivateRoleMethodCall(receiver, selector, arguments, isCalloutToField,
-		    										   calloutDecl.scope, baseType, targetMethod, gen);
-	    	} else {
-	    		if (calloutDecl.baseMethodSpec.isStatic() || calloutDecl.isCalloutToField())
-	    			// we thought we should use an instance
-	    			// but callout-to-static and decapsulating c-t-f (non-role-base) is sent to the base *class*
-	    			receiver = gen.baseNameReference(baseType.getRealClass());
-	
-	    		baseAccess = gen.messageSend(receiver, selector, arguments);
-	    	}
-    	}
+		if (calloutDecl.baseMethodSpec.isPrivate() && baseType.isRole()) {
+    		// tricky case: callout to a private role method (base-side)
+    		// requires the indirection via two wrapper methods (privateBridgeMethod)
+
+    		// compensate weakening:
+    		if (baseType instanceof WeakenedTypeBinding)
+    			baseType = ((WeakenedTypeBinding)baseType).getStrongType();
+
+    		// generated message send refers to public bridge, report decapsulation now:
+    		calloutDecl.scope.problemReporter().decapsulation(calloutDecl.baseMethodSpec, baseType, calloutDecl.scope);
+
+    		boolean isCalloutToField = calloutDecl.isCalloutToField();
+    		MethodBinding targetMethod = calloutDecl.baseMethodSpec.resolvedMethod;
+	    	baseAccess = new PrivateRoleMethodCall(receiver, selector, arguments, isCalloutToField,
+	    										   calloutDecl.scope, baseType, targetMethod, gen);
+    	} else {
+    		if (calloutDecl.baseMethodSpec.isStatic())
+    			// we thought we should use an instance
+    			// but callout-to-static is sent to the base *class*
+    			receiver = gen.baseNameReference(baseType.getRealClass());
+    		switch (calloutDecl.baseMethodSpec.implementationStrategy) {
+				case DIRECT:
+					if (calloutDecl.isCalloutToField()) {
+						// not using a decapsulation accessor but direct field access:
+						FieldAccessSpec fieldSpec = (FieldAccessSpec) calloutDecl.baseMethodSpec;
+						FieldBinding baseField = fieldSpec.resolvedField;
+						if (baseField.isStatic())
+							baseAccess = gen.qualifiedNameReference(baseField);
+						else
+							baseAccess = gen.qualifiedNameReference(new char[][] {IOTConstants._OT_BASE, baseField.name });
+						if (fieldSpec.isSetter()) {
+							int pos = fieldSpec.isStatic() ? 0 : 1;
+							baseAccess = gen.assignment((NameReference)baseAccess, arguments[pos]);
+							returnType = TypeBinding.VOID; // signal that no result processing is necessary
+						}
+					} else {
+		    			baseAccess = gen.messageSend(receiver, selector, arguments);
+					}
+					break;
+				case DECAPS_WRAPPER:
+					if (!calloutDecl.baseMethodSpec.isStatic() && calloutDecl.isCalloutToField())
+						// we thought we should use an instance
+						// but decapsulating c-t-f (non-role-base) is sent to the base *class*
+						receiver = gen.baseNameReference(baseType.getRealClass());
+		    		baseAccess = gen.messageSend(receiver, selector, arguments);
+		    		break;
+				case DYN_ACCESS:
+					baseAccess = CalloutImplementorDyn.baseAccessExpression(calloutDecl.scope, this._role, baseType, receiver, calloutDecl.baseMethodSpec, arguments, gen);
+					break;
+    		}			
+		}	 
 
         boolean success = true;
         ArrayList<Statement> statements = new ArrayList<Statement>(3);
@@ -644,24 +661,21 @@
 				MethodSpec baseMethodSpec)
     {
         assert (!methodMapping.hasSignature);
-        TypeBinding[] baseParams = baseMethodSpec.resolvedMethod.parameters;
         Argument[]    roleArgs   = roleMethodDecl.arguments;
 
         MethodSpec roleMethodSpec = methodMapping.roleMethodSpec;
 		AstGenerator gen = new AstGenerator(roleMethodSpec.sourceStart, roleMethodSpec.sourceEnd);
         int minArguments;
-
         Expression[] arguments = null;
 		int offset=0;
         if (baseMethodSpec instanceof FieldAccessSpec) {
         	// field access is mapped to static method with additional first parameter _OT$base:
-        	minArguments = baseParams.length; // exactly those needed by base.
-        	arguments = new Expression[minArguments];
-        	// how many of these arguments pass a value (rather than a base target instance)
-        	int valueArgCount = ((FieldAccessSpec)baseMethodSpec).isSetter() ? 1 : 0;
-        	if (minArguments > valueArgCount) { // otherwise accessing a static field: no value argument
-	        	// TODO(SH): generalize this and the corresponding statement in
-	        	//           makeWrapperCallArguments().
+        	if (((FieldAccessSpec) baseMethodSpec).isSetter())
+				minArguments = 1;
+			else
+				minArguments = 0;
+        	if (!baseMethodSpec.isStatic()) {
+        		arguments = new Expression[minArguments+1];
 	        	// cast needed against weakened _OT$base reference
         		//   and if base is a role, to go to the class type (FIXME)
 	        	gen.retargetFrom(baseMethodSpec);
@@ -670,22 +684,28 @@
 						gen.baseclassReference(this._role.getBaseTypeBinding().getRealClass()),
 						this._role.getBaseTypeBinding().isRole() ? CastExpression.NEED_CLASS : CastExpression.RAW); // FIXME(SH): change to RAW and let OTRE do the cast?
 	    		gen.retargetFrom(roleMethodSpec);
-	    		minArguments--; // one is already provided.
 	    		offset = 1;
+        	} else {
+        		arguments = new Expression[minArguments];
         	}
+        	if (((FieldAccessSpec) baseMethodSpec).isSetter())
+        		arguments[offset] = new PotentialLowerExpression(
+						gen.singleNameReference(roleArgs[0].name),
+						adjustBaseSideType(baseMethodSpec.resolvedType()));
+        	return arguments;
         } else {
+        	TypeBinding[] baseParams =  baseMethodSpec.resolvedMethod.parameters;
             minArguments = Math.min(baseParams.length, (roleArgs != null) ? roleArgs.length : 0); // (minArguments > 0) => (roleArgs != null)
             assert(minArguments == baseParams.length);
         	arguments = new Expression[minArguments];
+        	for(int i=0; i<minArguments; i++)
+        	{
+        		arguments[i+offset] = new PotentialLowerExpression(
+        				gen.singleNameReference(roleArgs[i].name),
+        				adjustBaseSideType(baseParams[i+offset]));
+        	}
+        	return arguments;
         }
-
-        for(int i=0; i<minArguments; i++)
-        {
-			arguments[i+offset] = new PotentialLowerExpression(
-										gen.singleNameReference(roleArgs[i].name),
-										adjustBaseSideType(baseParams[i+offset]));
-        }
-        return arguments;
     }
 
     private boolean transformCalloutMethodBodyResultMapping(
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/mappings/CalloutImplementorDyn.java b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/mappings/CalloutImplementorDyn.java
new file mode 100644
index 0000000..77ad3d8
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/mappings/CalloutImplementorDyn.java
@@ -0,0 +1,94 @@
+/**********************************************************************
+ * This file is part of "Object Teams Development Tooling"-Software
+ * 
+ * Copyright 2011 GK Software AG 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:
+ *		Stephan Herrmann - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.objectteams.otdt.internal.core.compiler.mappings;
+
+import org.eclipse.jdt.internal.compiler.ast.Expression;
+import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
+import org.eclipse.jdt.internal.compiler.lookup.Binding;
+import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
+import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
+import org.eclipse.jdt.internal.compiler.lookup.Scope;
+import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
+import org.eclipse.jdt.internal.compiler.lookup.TypeConstants;
+import org.eclipse.jdt.internal.compiler.parser.TerminalTokens;
+import org.eclipse.objectteams.otdt.internal.core.compiler.ast.FieldAccessSpec;
+import org.eclipse.objectteams.otdt.internal.core.compiler.ast.MethodSpec;
+import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.RoleTypeBinding;
+import org.eclipse.objectteams.otdt.internal.core.compiler.model.RoleModel;
+import org.eclipse.objectteams.otdt.internal.core.compiler.model.TeamModel;
+import org.eclipse.objectteams.otdt.internal.core.compiler.util.AstGenerator;
+
+/**
+ * This class only contains those parts of callout generation that for
+ * dynamic weaving deviated from the normal strategy.
+ * 
+ * @author stephan
+ */
+public class CalloutImplementorDyn {
+
+	// wrapper methods for decapsulating callout
+	public static final char[] ACCESS = "_OT$access".toCharArray(); //$NON-NLS-1$
+	public static final char[] ACCESS_STATIC = "_OT$accessStatic".toCharArray(); //$NON-NLS-1$
+	
+
+	public static Expression baseAccessExpression(Scope scope, RoleModel roleModel, ReferenceBinding baseType, 
+												  Expression receiver, MethodSpec baseSpec, Expression[] arguments,
+												  AstGenerator gen) 
+	{
+		baseSpec.createAccessAttribute(roleModel);
+
+		char[] selector = ensureAccessor(scope, baseType, baseSpec.isStatic());
+		TeamModel teamModel = roleModel.getTeamModel();
+		Expression memberIdArg = gen.intLiteral(teamModel.getNewCallinId(baseSpec));
+		int opKind = 0;
+		if (baseSpec instanceof FieldAccessSpec)
+			if (((FieldAccessSpec) baseSpec).calloutModifier == TerminalTokens.TokenNameset)
+				opKind = 1;
+		Expression opKindArg = gen.intLiteral(opKind);
+		Expression packagedArgs = gen.arrayAllocation(gen.qualifiedTypeReference(TypeConstants.JAVA_LANG_OBJECT), 1, arguments);
+		Expression callerArg = gen.qualifiedThisReference(gen.typeReference(teamModel.getBinding()));
+		Expression messageSend = gen.messageSend(receiver, selector, new Expression[] {memberIdArg, opKindArg, packagedArgs, callerArg});
+		if (baseSpec.resolvedType() == TypeBinding.VOID)
+			return messageSend;
+		else
+			return gen.createCastOrUnboxing(messageSend, baseSpec.resolvedType());
+	}
+
+	private static char[] ensureAccessor(Scope scope, ReferenceBinding baseType, boolean isStatic) {
+		if (baseType instanceof RoleTypeBinding)
+			baseType = baseType.getRealClass();
+		char[] selector = isStatic ? ACCESS_STATIC : ACCESS;
+		MethodBinding[] methods = baseType.getMethods(selector);
+		if (methods == null || methods.length != 1) {
+			int modifiers = ClassFileConstants.AccPublic|ClassFileConstants.AccSynthetic;
+			if (isStatic)
+				modifiers |= ClassFileConstants.AccStatic;
+			MethodBinding method = new MethodBinding(
+						modifiers,
+						selector,
+						scope.getJavaLangObject(),
+						new TypeBinding[] {
+							TypeBinding.INT, TypeBinding.INT,
+							scope.environment().createArrayType(scope.getJavaLangObject(), 1),
+							scope.getOrgObjectteamsITeam()
+						},
+						Binding.NO_EXCEPTIONS,
+						baseType);
+			baseType.addMethod(method);
+		}
+		return selector;
+	}
+}