Implementation for Bug 338582 - consider optimization by avoiding the role cache
diff --git a/org.eclipse.jdt.core/.settings/.api_filters b/org.eclipse.jdt.core/.settings/.api_filters
index e97d788..1621127 100644
--- a/org.eclipse.jdt.core/.settings/.api_filters
+++ b/org.eclipse.jdt.core/.settings/.api_filters
@@ -229,6 +229,27 @@
         </filter>
     </resource>
     <resource path="compiler/org/eclipse/objectteams/otdt/core/compiler/IOTConstants.java" type="org.eclipse.objectteams.otdt.core.compiler.IOTConstants">
+        <filter comment="Create some room between JDT/Core and OTDT." id="388194388">
+            <message_arguments>
+                <message_argument value="org.eclipse.objectteams.otdt.core.compiler.IOTConstants"/>
+                <message_argument value="T_OrgObjectTeamsIBoundBase"/>
+                <message_argument value="66"/>
+            </message_arguments>
+        </filter>
+        <filter comment="Create some room between JDT/Core and OTDT." id="388194388">
+            <message_arguments>
+                <message_argument value="org.eclipse.objectteams.otdt.core.compiler.IOTConstants"/>
+                <message_argument value="T_OrgObjectTeamsITeam"/>
+                <message_argument value="64"/>
+            </message_arguments>
+        </filter>
+        <filter comment="Create some room between JDT/Core and OTDT." id="388194388">
+            <message_arguments>
+                <message_argument value="org.eclipse.objectteams.otdt.core.compiler.IOTConstants"/>
+                <message_argument value="T_OrgObjectTeamsTeam"/>
+                <message_argument value="65"/>
+            </message_arguments>
+        </filter>
         <filter id="405864542">
             <message_arguments>
                 <message_argument value="org.eclipse.objectteams.otdt.core.compiler.IOTConstants"/>
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/IProblem.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/IProblem.java
index 96ac685..d0132a5 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/IProblem.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/IProblem.java
@@ -1481,6 +1481,13 @@
 	int NoDefaultCtorInBoundRole                 = ROLE_RELATED + 3101; // 2.3.1(b)
 	int MissingEmptyCtorForLiftingCtor           = ROLE_RELATED + 3102; // 2.3.1(c)
 	int ExplicitSuperInLiftConstructor           = ROLE_RELATED + 3103; // 2.3.1(c)
+	/** @since 3.7 (OT 0.8) */
+	int InstantiationAnnotationInNonRole		 = ROLE_RELATED + 3104; // 2.3.1(d)
+	/** @since 3.7 (OT 0.8) */
+	int FieldInRoleWithInstantiationPolicy		 = ROLE_RELATED + 3105; // 2.3.1(d)
+	/** @since 3.7 (OT 0.8) */
+	int MissingEqualsHashCodeWithInstantation	 = ROLE_RELATED + 3106; // 2.3.1(d)
+
 	int DeclaredLiftingInStaticMethod            = ROLE_RELATED + 3201; // 2.3.2(a)
 	int QualifiedLiftingType 					 = ROLE_RELATED + 3202; // 2.3.2(a)
 	int LiftingTypeNotAllowedHere 				 = ROLE_RELATED + 3203; // 2.3.2(a)
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Annotation.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Annotation.java
index 6044b02..7147c2f 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Annotation.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Annotation.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * Copyright (c) 2000, 2011 IBM Corporation 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
@@ -20,6 +20,7 @@
 import org.eclipse.jdt.internal.compiler.impl.Constant;
 import org.eclipse.jdt.internal.compiler.impl.IrritantSet;
 import org.eclipse.jdt.internal.compiler.lookup.*;
+import org.eclipse.objectteams.otdt.core.compiler.IOTConstants;
 import org.eclipse.objectteams.otdt.internal.core.compiler.ast.AbstractMethodMappingDeclaration;
 import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.CallinCalloutBinding;
 
@@ -168,6 +169,11 @@
 			case TypeIds.T_JavaLangSuppressWarnings :
 				tagBits |= TagBits.AnnotationSuppressWarnings;
 				break;
+//{ObjectTeams: more standard annotations:
+			case IOTConstants.T_OrgObjectTeamsInstantiation :
+				tagBits |= TagBits.AnnotationInstantiation;
+				break;
+// SH}
 		}
 		return tagBits;
 	}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ReferenceBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ReferenceBinding.java
index ca5ee84..7903135 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ReferenceBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ReferenceBinding.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * Copyright (c) 2000, 2011 IBM Corporation 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
@@ -539,6 +539,8 @@
 					this.id = IOTConstants.T_OrgObjectTeamsTeam;
 				else if(CharOperation.equals(IOTConstants.IBOUNDBASE, this.compoundName[2]))
 					this.id = IOTConstants.T_OrgObjectTeamsIBoundBase;
+				else if(CharOperation.equals(IOTConstants.INSTANTIATION, this.compoundName[2]))
+					this.id = IOTConstants.T_OrgObjectTeamsInstantiation;
 				return;
 			}
 // SH}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SourceTypeBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SourceTypeBinding.java
index 37ddadc..2c7d3aa 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SourceTypeBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SourceTypeBinding.java
@@ -1014,8 +1014,13 @@
 		for (int i = 0, length = this.fields.length; i < length; i++) {
  */
 		for (int i = 0; i < this.fields.length; i++) {
-//SH}
-//{ObjectTeams: after compilation is finished we have no scope, can't resolve any better
+// check discouraged field in @Instantation(ALWAYS) roles:
+		  if (   this.scope != null 
+			  && (this.tagBits & TagBits.AnnotationInstantiation) != 0 
+			  && !this.fields[i].isStatic())
+			  this.scope.problemReporter().fieldInRoleWithInstantiationPolicy(this, this.fields[i]);
+			  
+// after compilation is finished we have no scope, can't resolve any better
 //   		    resolveTypeFor would NPE!
 		  int length = this.fields.length;
 		  if (   this.model!=null
@@ -1109,6 +1114,11 @@
 		}
 		if ((this.tagBits & TagBits.AnnotationDeprecated) != 0)
 			this.modifiers |= ClassFileConstants.AccDeprecated;
+//{ObjectTeams: @Instantation can only be applied to role classes		
+		if (   (this.tagBits & TagBits.AnnotationInstantiation) != 0
+			&& (!isRole() || isInterface()))
+			this.scope.problemReporter().instantiationAnnotationInNonRole(typeDecl);
+// SH}
 	}
 	return this.tagBits;
 }
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TagBits.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TagBits.java
index 86b04dd..9fa1c56 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TagBits.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TagBits.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * Copyright (c) 2000, 2011 IBM Corporation 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
@@ -125,7 +125,14 @@
 	long AnnotationInherited = ASTNode.Bit49L;
 	long AnnotationOverride = ASTNode.Bit50L;
 	long AnnotationSuppressWarnings = ASTNode.Bit51L;
-	long AllStandardAnnotationsMask = AnnotationTargetMASK | AnnotationRetentionMASK | AnnotationDeprecated | AnnotationDocumented | AnnotationInherited |  AnnotationOverride | AnnotationSuppressWarnings;
+//{ObjectTeams: one more standard annotation:
+	long AnnotationInstantiation = ASTNode.Bit21;
+// SH}
+	long AllStandardAnnotationsMask = AnnotationTargetMASK | AnnotationRetentionMASK | AnnotationDeprecated | AnnotationDocumented | AnnotationInherited |  AnnotationOverride | AnnotationSuppressWarnings
+//{ObjectTeams: one more standard annotation:
+										| AnnotationInstantiation
+// SH}
+	;
 
 	long DefaultValueResolved = ASTNode.Bit52L;
 
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java
index 5d3b75f..8dd04a9 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java
@@ -142,6 +142,7 @@
 import org.eclipse.objectteams.otdt.internal.core.compiler.ast.TSuperMessageSend;
 import org.eclipse.objectteams.otdt.internal.core.compiler.ast.TypeAnchorReference;
 import org.eclipse.objectteams.otdt.internal.core.compiler.ast.WithinStatement;
+import org.eclipse.objectteams.otdt.internal.core.compiler.lifting.Lifting.InstantiationPolicy;
 import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.CallinCalloutBinding;
 import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.DependentTypeBinding;
 import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.ITeamAnchor;
@@ -9205,6 +9206,53 @@
         constructor.constructorCall.sourceStart,
         constructor.constructorCall.sourceEnd);
 }
+public void instantiationAnnotationInNonRole(TypeDeclaration typeDecl) {
+	int start=0, end=0;
+	String[] args = {new String(IOTConstants.INSTANTIATION)};
+	for (int i = 0; i < typeDecl.annotations.length; i++) {
+		Annotation annotation = typeDecl.annotations[i];
+		if (annotation.resolvedType.id == IOTConstants.T_OrgObjectTeamsInstantiation) {
+			start = annotation.sourceStart;
+			end   = annotation.sourceEnd;
+		}
+	}
+	this.handle(IProblem.InstantiationAnnotationInNonRole, args, args, start, end);
+}
+public void fieldInRoleWithInstantiationPolicy(ReferenceBinding typeBinding, FieldBinding fieldBinding) {
+	if (CharOperation.prefixEquals(IOTConstants.OT_DOLLAR_NAME, fieldBinding.name))
+		return; // don't complain against generated fields
+	InstantiationPolicy instantiationPolicy = RoleModel.getInstantiationPolicy(typeBinding);
+	int problemId = 0;
+	int severity = 0;
+	switch (instantiationPolicy) {
+		case ONDEMAND: break; // no problem
+		case ALWAYS: 
+			problemId = IProblem.FieldInRoleWithInstantiationPolicy;
+			severity = ProblemSeverities.Warning;
+			break;
+		default:
+	}
+	if (problemId != 0) {
+		int start = 0, end = 0;
+		FieldDeclaration decl = fieldBinding.sourceField();
+		if (decl != null) {
+			start = decl.sourceStart;
+			end = decl.sourceEnd;
+		}
+		String[] args = { instantiationPolicy.name() };
+		handle(problemId, args, args, severity, start, end);
+	}
+}
+public void missingEqualsHashCodeWithInstantation(TypeDeclaration decl, InstantiationPolicy instantiationPolicy) {
+	String[] args = { instantiationPolicy.name() };
+	handle(
+		IProblem.MissingEqualsHashCodeWithInstantation,
+		args,
+		args,
+		ProblemSeverities.Warning,
+		decl.sourceStart,
+		decl.sourceEnd);
+}
 public void declaredLiftingInStaticMethod(AbstractMethodDeclaration method, Argument argument) {
 	String[] args = new String[] {new String(argument.name) };
 	this.handle(
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties
index aecb4ef..9ccba0d 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties
@@ -753,6 +753,10 @@
 1203101 = The constructor {0} is undefined. Note that bound roles per default only have a lifting constructor (OTJLD 2.3.1(b)).
 1203102 = Need custom lifting constructor, because super class has no argumentless constructor {0} (OTJLD 2.3.1(c)).
 1203103 = Lifting constructor cannot have explicit super-call (OTJLD 2.3.1(c)).
+1203104 = Annotation '@{0}' can only be applied to role classes (OTJLD 2.3.1(d)).
+1203105 = Fields are discouraged in roles with InstantiationPolicy '{0}' (OTJLD 2.3.1(d)).
+1203106 = Roles with InstantiationPolicy '{0}' should define equals() and hashCode() methods (OTJLD 2.3.1(d)).
+
 
 1203201 = Illegal type for argument {0}: declared lifting not allowed in static methods (OTJLD 2.3.2(a)).
 1203202 = Qualified type name not allowed here. Type after keyword "as" must be a role of the enclosing team {0} (OTJLD 2.3.2(a)).
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/core/compiler/IOTConstants.java b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/core/compiler/IOTConstants.java
index 6e56088..2da5f23 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/core/compiler/IOTConstants.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/core/compiler/IOTConstants.java
@@ -24,7 +24,7 @@
 
 /**
  * @author stephan
- * @version $Id: IOTConstants.java 23483 2010-02-05 20:26:47Z stephan $
+ * @noimplement This interface is not intended to be implemented by clients.
  */
 @SuppressWarnings("nls")
 public interface IOTConstants
@@ -222,7 +222,16 @@
 
 	public static final char[][] ROLE_CAST_EXCEPTION 			  = {ORG, OBJECTTEAMS,
 																	 "RoleCastException".toCharArray()};
-
+	/** 
+	 * @since 3.7 (OT 0.8)
+	 */
+	public static final char[] INSTANTIATION = "Instantiation".toCharArray();
+	/** 
+	 * @since 3.7 (OT 0.8)
+	 */
+	public static final char[][] ORG_OBJECTTEAMS_INSTANTIATION = {ORG, OBJECTTEAMS,
+		 															 INSTANTIATION};
+	
 	public static final char[][] ILLEGAL_ROLE_CREATION_EXCEPTION = {ORG, OBJECTTEAMS,
 		 															 "IllegalRoleCreationException".toCharArray()};
 	public static final char[][] ORG_OBJECTTEAMS_ITEAMMIGRATABLE = {ORG, OBJECTTEAMS,
@@ -239,9 +248,13 @@
 																	"OTREInternalError".toCharArray()};
 
 	// Type IDs (cf. type TypeIds)
-	public static final int T_OrgObjectTeamsITeam      = 64;
-	public static final int T_OrgObjectTeamsTeam       = 65;
-	public static final int T_OrgObjectTeamsIBoundBase = 66;
+	public static final int T_OrgObjectTeamsITeam      = 100;
+	public static final int T_OrgObjectTeamsTeam       = 101;
+	public static final int T_OrgObjectTeamsIBoundBase = 102;
+	/**
+	 * @since 3.7 (OT 0.8)
+	 */
+	public static final int T_OrgObjectTeamsInstantiation = 103;
 
     // special identifiers:
 	public static final char[] RESULT = "result".toCharArray();
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/control/Dependencies.java b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/control/Dependencies.java
index f90165a..c25a4fa 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/control/Dependencies.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/control/Dependencies.java
@@ -41,6 +41,8 @@
 import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
 import org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding;
 import org.eclipse.jdt.internal.compiler.lookup.TagBits;
+import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
+import org.eclipse.jdt.internal.compiler.lookup.TypeConstants;
 import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
 import org.eclipse.jdt.internal.compiler.parser.Parser;
 import org.eclipse.objectteams.otdt.core.compiler.IOTConstants;
@@ -50,6 +52,7 @@
 import org.eclipse.objectteams.otdt.internal.core.compiler.ast.RoleClassLiteralAccess;
 import org.eclipse.objectteams.otdt.internal.core.compiler.ast.RoleInitializationMethod;
 import org.eclipse.objectteams.otdt.internal.core.compiler.lifting.DeclaredLifting;
+import org.eclipse.objectteams.otdt.internal.core.compiler.lifting.Lifting.InstantiationPolicy;
 import org.eclipse.objectteams.otdt.internal.core.compiler.lifting.LiftingEnvironment;
 import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.OTClassScope;
 import org.eclipse.objectteams.otdt.internal.core.compiler.mappings.CallinImplementor;
@@ -1648,6 +1651,8 @@
 		CalloutImplementor.transformCallouts(clazz);
 		if (resolver != null)
 			resolver.resolve(false/*doCallout*/); // callins last so all methods incl. callout are already in place
+		
+		checkMissingMethods(subRole, subRoleDecl.scope);
 
         clazz.setState(STATE_METHODS_CREATED);
         return true;
@@ -1770,6 +1775,28 @@
 		return null;
 	}
 
+	// detail of STATE_METHODS_CREATED (can only check this after callouts have been transformed):
+	private static void checkMissingMethods(ReferenceBinding roleBinding, ClassScope scope) {
+		if (roleBinding.isClass() && ((roleBinding.tagBits & TagBits.AnnotationInstantiation) != 0)) {
+			InstantiationPolicy instantiationPolicy = RoleModel.getInstantiationPolicy(roleBinding);
+			if (!instantiationPolicy.isAlways())
+				return;
+			boolean missing = false;
+			MethodBinding equals = roleBinding.getExactMethod(TypeConstants.EQUALS, 
+															  new TypeBinding[] {scope.getJavaLangObject()}, scope.compilationUnitScope());
+			if (equals == null || !equals.isValidBinding() || equals.declaringClass != roleBinding) {
+				missing = true;
+			} else {
+				MethodBinding hashCode = roleBinding.getExactMethod(TypeConstants.HASHCODE, 
+						  										  	Binding.NO_PARAMETERS, scope.compilationUnitScope());
+				if (hashCode == null || !hashCode.isValidBinding() || hashCode.declaringClass != roleBinding)
+					missing = true;
+			}
+			if (missing) {
+				scope.problemReporter().missingEqualsHashCodeWithInstantation(scope.referenceContext, instantiationPolicy);
+			}
+		}
+	}
 
 	/* **** STATE_TYPES_ADJUSTED (OT/J) ****
 	 * - wrap types in signatures using RoleTypeBinding
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/lifting/Lifting.java b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/lifting/Lifting.java
index d24aeb9..1826b06 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/lifting/Lifting.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/lifting/Lifting.java
@@ -114,6 +114,12 @@
 public class Lifting extends SwitchOnBaseTypeGenerator
 					 implements TypeIds, ClassFileConstants, ExtraCompilerModifiers
 {
+	
+	public static enum InstantiationPolicy { NEVER, ONDEMAND, SINGLETON, ALWAYS, ERROR;
+		public boolean isAlways() { return this == ALWAYS; }
+		public boolean isOndemand() { return this == ONDEMAND; }
+	}
+	
     private RoleModel _boundRootRoleModel = null;
     private AstGenerator _gen = null;
 	private long _sourceLevel;
@@ -381,23 +387,28 @@
     {
         liftToConstructorDeclaration.constructorCall =
         		gen.explicitConstructorCall(ExplicitConstructorCall.Super);
-    	Statement[] statements = new Statement[4];
+        boolean useRoleCache = RoleModel.getInstantiationPolicy(roleType.binding).isOndemand();
+    	Statement[] statements = new Statement[useRoleCache ? 4 : 2];
         // _OT$base = <baseArgName>;
         SingleNameReference lhs = gen.singleNameReference(_OT_BASE);
         statements[0] = gen.assignment(lhs, gen.singleNameReference(baseArgName));
 
-    	Statement[] regStats = genRoleRegistrationStatements(
-    								  this._boundRootRoleModel.getAst().scope,
-    								  this._boundRootRoleModel,
-    								  baseClassBinding,
-    								  liftToConstructorDeclaration,
-    								  gen);
-    	System.arraycopy(regStats, 0, statements, 1, regStats.length);
+        int idx = 1;
+		if (useRoleCache) {
+	    	Statement[] regStats = genRoleRegistrationStatements(
+	    								  this._boundRootRoleModel.getAst().scope,
+	    								  this._boundRootRoleModel,
+	    								  baseClassBinding,
+	    								  liftToConstructorDeclaration,
+	    								  gen);
+	    	System.arraycopy(regStats, 0, statements, idx, regStats.length);
+	    	idx += 2;
+        }
 
         // after initializing _OT$base and storing in the cache we are ready to execute field initializers:
 
         // this._OT$InitFields();
-    	statements[3] = RoleInitializationMethod.genInvokeInitMethod(
+    	statements[idx] = RoleInitializationMethod.genInvokeInitMethod(
 									    					gen.thisReference(),
 									    					roleType.binding,
 									    					gen);
@@ -737,12 +748,14 @@
 					// conditional generation (see below)
 					maybeCreateTeamMemberCheck(baseClassBinding),
 
+					(RoleModel.getInstantiationPolicy(roleClassBinding).isOndemand()) 
 					// if(!_OT$team_param._OT$cache_OT$RootRole.containsKey(base))
-					createRoleExistentCheck(
+					? createRoleExistentCheck(
 		                roleClassBinding,
 		                baseClassBinding,
 		                teamBinding,
-		                caseObjects),
+		                caseObjects)
+		            : createCreationCascade(roleClassBinding, teamBinding, caseObjects),
 
 					// return ...
 					createReturnStatement(roleClassBinding)
@@ -809,17 +822,12 @@
         		// (!_OT$team_param._OT$cache_OT$RootRole.containsKey(base))
         		createRoleExistentCheck(baseType),
 				// (then:)
-				this._gen.block(
-					// (create a role of the best matching type:)
-					new Statement[] {
-					caseObjects.length > 0 
-						? createSwitchStatement(teamType, returnType, caseObjects, this._gen)
-						: genLiftingFailedException(BASE, returnType, this._gen)}),
+				createCreationCascade(returnType, teamType, caseObjects),
 				// (else: return existing role)
 				createElseBlock(returnType, teamType));
     }
 
-    private UnaryExpression createRoleExistentCheck(
+	private UnaryExpression createRoleExistentCheck(
         ReferenceBinding baseType)
     {
         // !_OT$team_param._OT$cache_OT$RootRole.containsKey(base)
@@ -833,7 +841,16 @@
         		OperatorIds.NOT);
     }
 
-    /*
+    private Block createCreationCascade(ReferenceBinding roleType, ReferenceBinding teamType, RoleModel[] caseObjects) {
+		return this._gen.block(
+			// (create a role of the best matching type:)
+			new Statement[] {
+			caseObjects.length > 0 
+				? createSwitchStatement(teamType, roleType, caseObjects, this._gen)
+				: genLiftingFailedException(BASE, roleType, this._gen)});
+	}
+
+	/*
 	 * see SwitchOnBaseTypeGenerator.createCaseStatement(RoleModel,AstGenerator).
 	 */
 	protected Statement createCaseStatement(RoleModel role, AstGenerator gen)
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 9704deb..bd0a73a 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
@@ -36,10 +36,12 @@
 import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
 import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader;
 import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException;
+import org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding;
 import org.eclipse.jdt.internal.compiler.lookup.BinaryTypeBinding;
 import org.eclipse.jdt.internal.compiler.lookup.Binding;
 import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
 import org.eclipse.jdt.internal.compiler.lookup.CompilationUnitScope;
+import org.eclipse.jdt.internal.compiler.lookup.ElementValuePair;
 import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
 import org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment;
 import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
@@ -64,6 +66,8 @@
 import org.eclipse.objectteams.otdt.internal.core.compiler.control.Config;
 import org.eclipse.objectteams.otdt.internal.core.compiler.control.Dependencies;
 import org.eclipse.objectteams.otdt.internal.core.compiler.control.ITranslationStates;
+import org.eclipse.objectteams.otdt.internal.core.compiler.lifting.Lifting;
+import org.eclipse.objectteams.otdt.internal.core.compiler.lifting.Lifting.InstantiationPolicy;
 import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.CallinCalloutBinding;
 import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.RoleTypeBinding;
 import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.SyntheticRoleFieldAccess;
@@ -1357,6 +1361,26 @@
 		return null;
 	}
 
+	public static Lifting.InstantiationPolicy getInstantiationPolicy(ReferenceBinding roleClassBinding) {
+		if ((roleClassBinding.getAnnotationTagBits() & TagBits.AnnotationInstantiation) != 0) {
+			for (AnnotationBinding annotation : roleClassBinding.getAnnotations()) {
+				if (annotation.getAnnotationType().id == IOTConstants.T_OrgObjectTeamsInstantiation) {
+					for (ElementValuePair pair : annotation.getElementValuePairs()) {
+						if (pair.value instanceof FieldBinding) {
+							String name = String.valueOf(((FieldBinding) pair.value).name);
+							try {
+								return InstantiationPolicy.valueOf(name);
+							} catch (IllegalArgumentException iae) {
+								return InstantiationPolicy.ERROR;
+							}
+						}
+					}
+				}
+			}
+		}
+		return InstantiationPolicy.ONDEMAND; // default
+	}
+
 	public static boolean areTypeParametersOfSameRole(TypeVariableBinding one, Binding two) {
 		if (!(two instanceof TypeVariableBinding))
 			return false;