basic integration of decapsulation among OTREDyn and compiler (compiler-part):
- redirect decapsulating MessageSend to _OT$access{Static}
- consider return conversions (from Object)
- let generateArguments() pack and extend arguments to suite _OT$access
- assign and store accessId per decapsulated method/field and per team
- each OTSpecialAccessAttribute manages the accessIds of one team
- extend this attribute to include the accessId (OTREDyn only)
variants are distinguished by different kind-constants
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java
index d0c2a2c..707246c 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java
@@ -28,6 +28,7 @@
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
import org.eclipse.jdt.internal.compiler.impl.Constant;
import org.eclipse.jdt.internal.compiler.impl.ReferenceContext;
+import org.eclipse.jdt.internal.compiler.lookup.BaseTypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.Binding;
import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
import org.eclipse.jdt.internal.compiler.lookup.ExtraCompilerModifiers;
@@ -63,6 +64,7 @@
import org.eclipse.objectteams.otdt.internal.core.compiler.model.MethodModel;
import org.eclipse.objectteams.otdt.internal.core.compiler.model.TeamModel;
import org.eclipse.objectteams.otdt.internal.core.compiler.statemachine.transformer.StandardElementGenerator;
+import org.eclipse.objectteams.otdt.internal.core.compiler.util.AstGenerator;
import org.eclipse.objectteams.otdt.internal.core.compiler.util.RoleTypeCreator;
/**
@@ -714,10 +716,27 @@
this.binding = ((ProblemMethodBinding)this.binding).closestMatch;
if (!this.binding.declaringClass.isRole()) { // access via interface is possible anyway, no access wrapper needed.
// instruct the OTRE to generate an accessor method:
- scope.enclosingSourceType().roleModel.addInaccessibleBaseMethod(this.binding);
+ int accessId = scope.enclosingSourceType().roleModel.addInaccessibleBaseMethod(this.binding);
// pretend that accessor method were already there:
this.binding = new MethodBinding(this.binding, this.binding.declaringClass.getRealClass());
- this.binding.selector = CharOperation.concat(IOTConstants.OT_DECAPS, this.selector);
+ if (CallinImplementorDyn.DYNAMIC_WEAVING) {
+ MethodModel.recordMethodAccessId(this.binding, accessId);
+ if (this.binding.isStatic())
+ this.binding.selector = CallinImplementorDyn.OT_ACCESS_STATIC;
+ else
+ this.binding.selector = CallinImplementorDyn.OT_ACCESS;
+ TypeBinding originalReturnType = this.binding.returnType;
+ if (originalReturnType.id != TypeIds.T_void) {
+ if (originalReturnType.isBaseType()) {
+ this.valueCast = scope.getType(AstGenerator.boxTypeName((BaseTypeBinding) originalReturnType), 3);
+ computeConversion(scope, this.valueCast, originalReturnType);
+ } else {
+ this.valueCast = originalReturnType;
+ }
+ }
+ } else {
+ this.binding.selector = CharOperation.concat(IOTConstants.OT_DECAPS, this.selector);
+ }
}
this.isDecapsulation = true;
scope.problemReporter().decapsulation(this, scope);
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Statement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Statement.java
index 629a336..03866ed 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Statement.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Statement.java
@@ -19,6 +19,8 @@
import org.eclipse.jdt.internal.compiler.impl.Constant;
import org.eclipse.jdt.internal.compiler.lookup.*;
import org.eclipse.objectteams.otdt.core.compiler.IOTConstants;
+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.TeamModel;
/**
@@ -165,15 +167,49 @@
codeStream.newArray(codeGenVarArgsType); // create a mono-dimensional array
}
} else if (arguments != null) { // standard generation for method arguments
+//{ObjectTeams: decapsulation under OTREDyn requires packing into an array etc.:
+ if ( CharOperation.equals(CallinImplementorDyn.OT_ACCESS, binding.selector)
+ || CharOperation.equals(CallinImplementorDyn.OT_ACCESS_STATIC, binding.selector))
+ {
+ SourceTypeBinding roleType = currentScope.enclosingSourceType();
+ // adjust the target method binding
+ binding.parameters = new TypeBinding[] {
+ TypeBinding.INT,
+ TypeBinding.INT,
+ currentScope.createArrayType(currentScope.getJavaLangObject(), 1),
+ currentScope.getOrgObjectteamsITeam()
+ };
+ binding.returnType = currentScope.getJavaLangObject();
+ // accessId:
+ codeStream.generateInlinedValue(MethodModel.getMethodAccessId(binding));
+ // opkind (not used for method access):
+ codeStream.iconst_0();
+ // pack original arguments into a new Object[]
+ codeStream.generateInlinedValue(arguments.length);
+ codeStream.anewarray(currentScope.getJavaLangObject());
+ for (int i = 0, max = arguments.length; i < max; i++) {
+ codeStream.dup();
+ codeStream.generateInlinedValue(i);
+ arguments[i].generateCode(currentScope, codeStream, true);
+ if (arguments[i].resolvedType.isBaseType())
+ codeStream.generateBoxingConversion(arguments[i].resolvedType.id);
+ codeStream.aastore();
+ }
+ // pass enclosing team:
+ Object[] path = currentScope.getEmulationPath(roleType.enclosingType(), true, false);
+ codeStream.generateOuterAccess(path, null, roleType.enclosingType(), currentScope);
+ return;
+ }
+// SH}
for (int i = 0, max = arguments.length; i < max; i++)
//{ObjectTeams: check for need for role-ifc to plain-class cast:
{
// orig:
arguments[i].generateCode(currentScope, codeStream, true);
+// :giro
TypeBinding requiredType = checkRoleToPlainCast(arguments[i].resolvedType, binding.original().parameters[i]);
if (requiredType != null)
codeStream.checkcast(requiredType);
-// :giro
}
// SH}
}
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 7671c51..ee328d3 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
@@ -35,6 +35,7 @@
import org.eclipse.objectteams.otdt.core.compiler.IOTConstants;
import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.RoleTypeBinding;
import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.WeakenedTypeBinding;
+import org.eclipse.objectteams.otdt.internal.core.compiler.mappings.CallinImplementorDyn;
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.copyinheritance.CopyInheritance;
@@ -55,21 +56,34 @@
private static final int DECAPSULATION_METHOD_ACCESS= 1;
private static final int CALLOUT_FIELD_ACCESS = 2;
private static final int SUPER_METHOD_ACCESS = 3;
+ // OTREDyn has one more field in the attribute, use disjoint kinds:
+ private static final int DYN_DECAPSULATION_METHOD_ACCESS= 4;
+ 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;
+ int nextAccessId = 0;
+
/** Descriptor for a decapsulated base-method. */
private class DecapsulatedMethodDesc {
ReferenceBinding boundBaseclass;
MethodBinding method;
+ private int accessId;
DecapsulatedMethodDesc(ReferenceBinding boundBaseclass, MethodBinding method) {
this.boundBaseclass = boundBaseclass;
this.method = method;
if (CopyInheritance.isCreator(method))
// creator is declared in the enclosing team
this.boundBaseclass = this.boundBaseclass.enclosingType();
+ if (CallinImplementorDyn.DYNAMIC_WEAVING)
+ this.accessId = nextAccessId++;
}
void write() {
- writeByte((byte)DECAPSULATION_METHOD_ACCESS);
+ if (CallinImplementorDyn.DYNAMIC_WEAVING)
+ writeByte((byte)DYN_DECAPSULATION_METHOD_ACCESS);
+ else
+ writeByte((byte)DECAPSULATION_METHOD_ACCESS);
if (this.method.isConstructor()) { // no accessor method, old style attribute
writeName(this.method.declaringClass.attributeName());
writeName(this.method.selector);
@@ -85,6 +99,8 @@
writeName(this.boundBaseclass.attributeName()); // where to weave into
writeName(encodedName);
writeName(this.method.signature());
+ if (CallinImplementorDyn.DYNAMIC_WEAVING)
+ writeUnsignedShort(this.accessId);
}
}
@@ -185,8 +201,10 @@
this._site = site;
}
- public void addDecapsulatedMethodAccess(ReferenceBinding boundBaseclass, MethodBinding method) {
+ public int addDecapsulatedMethodAccess(ReferenceBinding boundBaseclass, MethodBinding method) {
+ int accessId = this.nextAccessId;
this._decapsulatedMethods.add(new DecapsulatedMethodDesc(boundBaseclass, method));
+ return accessId;
}
public void addCalloutFieldAccess(FieldBinding field, ReferenceBinding targetClass, int calloutModifier) {
@@ -222,10 +240,10 @@
super.write(classFile);
int attributeSize = 4; // initially empty, except for two counts
- attributeSize += this._decapsulatedMethods.size() * 7; // 1 byte kind, 3 names
- attributeSize += this._calloutToFields.size() * 8; // 1 byte kind, 1 byte flags, 3 names
- attributeSize += this._superMethods.size() * 9; // 1 byte kind, 4 names
- attributeSize += this._adaptedBaseclasses.size() * 3; // 1 name + 1 byte flag
+ 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._superMethods.size() * 9; // 1 byte kind, 4 names
+ attributeSize += this._adaptedBaseclasses.size() * 3; // 1 name + 1 byte flag
if (this._contentsOffset + 6 + attributeSize >= this._contents.length)
this._contents = classFile.getResizedContents(6 + attributeSize);
@@ -283,6 +301,9 @@
private void readElement() {
int kind = consumeByte();
switch(kind) {
+ case DYN_DECAPSULATION_METHOD_ACCESS:
+ this._readOffset += 2; // extra id
+ //$FALL-THROUGH$
case DECAPSULATION_METHOD_ACCESS:
this._readOffset += 6;
break;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/mappings/CallinImplementorDyn.java b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/mappings/CallinImplementorDyn.java
index e6aa417..ad1dbfa 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/mappings/CallinImplementorDyn.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/mappings/CallinImplementorDyn.java
@@ -74,6 +74,7 @@
public static boolean DYNAMIC_WEAVING = "dynamic".equals(System.getProperty("ot.weaving")); //$NON-NLS-1$ //$NON-NLS-2$
+
//_OT$role
static final char[] ROLE_VAR_NAME = CharOperation.concat(IOTConstants.OT_DOLLAR_NAME, IOTConstants.ROLE);
@@ -82,7 +83,10 @@
static final char[] OT_CALL_AFTER = "_OT$callAfter".toCharArray(); //$NON-NLS-1$
static final char[] OT_CALL_REPLACE = "_OT$callReplace".toCharArray(); //$NON-NLS-1$
// used for base calls:
- public static final char[] OT_CALL_NEXT = "_OT$callNext".toCharArray(); //$NON-NLS-1$
+ public static final char[] OT_CALL_NEXT = "_OT$callNext".toCharArray(); //$NON-NLS-1$
+ // for decapsulation:
+ public static final char[] OT_ACCESS = "_OT$access".toCharArray(); //$NON-NLS-1$
+ public static final char[] OT_ACCESS_STATIC = "_OT$accessStatic".toCharArray(); //$NON-NLS-1$
// variable names (arguments ...)
static final char[] TEAMS = "teams".toCharArray(); //$NON-NLS-1$
@@ -399,7 +403,7 @@
blockStatements.add(gen.localVariable(roleVar, roleType.sourceName(),
Lifting.liftCall(callMethod.scope,
gen.thisReference(),
- gen.castExpression(gen.singleNameReference(IOTConstants.BASE), gen.typeReference(roleType.baseclass()), CastExpression.RAW),
+ gen.castExpression(gen.singleNameReference(IOTConstants.BASE), gen.baseTypeReference(roleType.baseclass()), CastExpression.RAW),
callMethod.scope.getType(IOTConstants.ORG_OBJECTTEAMS_IBOUNDBASE, 3),
roleType,
false,
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/model/MethodModel.java b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/model/MethodModel.java
index 40a200f..6e414ec 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/model/MethodModel.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/model/MethodModel.java
@@ -128,6 +128,9 @@
// offset between byte code line number and source code line number
public int _lineOffset;
+ // this id is used by OTREDyn to select decapsulated method:
+ private int _accessId;
+
// for a callin method record all exceptions declared by bound base methods:
public Set<ReferenceBinding> _baseExceptions;
public void addBaseExceptions(ReferenceBinding[] exceptions) {
@@ -717,4 +720,22 @@
}
return handledRoles;
}
+ /**
+ * Record an accessId as used by OTREDyn to select a decapsulated method within _OT$access.
+ * This assumes that different teams decapsulating the same base method keep distinct
+ * method bindings for the loadtime-generated target method.
+ * @param method
+ * @param accessId
+ */
+ public static void recordMethodAccessId(MethodBinding method, int accessId) {
+ getModel(method)._accessId = accessId;
+ }
+ /**
+ * Retrieve the accessId previously recorded using {@link #recordByteCode(ClassFile, int)}.
+ * @param method
+ * @return the accessId
+ */
+ public static int getMethodAccessId(MethodBinding method) {
+ return getModel(method)._accessId;
+ }
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/model/RoleModel.java b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/model/RoleModel.java
index 68e0dd9..9704deb 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/model/RoleModel.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/model/RoleModel.java
@@ -1120,11 +1120,11 @@
* Record that the given method is only accessible using decapsulation.
* @param binding
*/
- public void addInaccessibleBaseMethod(MethodBinding binding) {
+ public int addInaccessibleBaseMethod(MethodBinding binding) {
// push out to the team to ensure early evaluation by the OTRE:
OTSpecialAccessAttribute specialAccess = getTeamModel().getSpecialAccessAttribute();
- specialAccess.addDecapsulatedMethodAccess(this._binding.baseclass(), binding);
specialAccess.addAdaptedBaseClass(binding.declaringClass);
+ return specialAccess.addDecapsulatedMethodAccess(this._binding.baseclass(), binding);
}
/**