/// <summary>
		/// Initializes a new instance of the AdapterBuilderContext class.
		/// </summary>
		/// <param name="originalObject"></param>
		/// <param name="classEmitter"></param>
		/// <param name="adaptedObjectRef"></param>
		public AdapterBuilderStageContext(Type originalObject, ClassEmitter classEmitter, FieldReference adaptedObjectRef, MethodInfo originalMethod)
		{
			OriginalObject = originalObject;
			ClassEmitter = classEmitter;
			AdaptedObjectRef = adaptedObjectRef;
			OriginalMethod = originalMethod;
		}
		protected void ImplementProxyTargetAccessor(ClassEmitter emitter, FieldReference interceptorsField)
		{
			var dynProxyGetTarget = emitter.CreateMethod("DynProxyGetTarget", typeof(object));

			dynProxyGetTarget.CodeBuilder.AddStatement(
				new ReturnStatement(new ConvertExpression(typeof(object), targetType, GetTargetReferenceExpression(emitter))));

			var getInterceptors = emitter.CreateMethod("GetInterceptors", typeof(IInterceptor[]));

			getInterceptors.CodeBuilder.AddStatement(
				new ReturnStatement(interceptorsField));
		}
        /// <summary>
        /// Creates an intercepted property named __metadata, which only has a setter, which is used to deserialize
        /// the document metadata.  Since there is no getter, it won't be serialized back to the data store.
        /// </summary>
        private void CreateMetadataProperty(ClassEmitter emitter, FieldReference interceptorsField)
        {
            var propertyBuilder = emitter.TypeBuilder.DefineProperty("__metadata", PropertyAttributes.None, CallingConventions.HasThis,
                typeof (DocumentMetadata), null, null, null, null, null);

            var methodBuilder = emitter.TypeBuilder.DefineMethod("set___metadata", MethodAttributes.Public | MethodAttributes.SpecialName);
            methodBuilder.SetParameters(typeof (DocumentMetadata));

            var codeBuilder = methodBuilder.GetILGenerator();
            codeBuilder.Emit(OpCodes.Ldarg_0);
            codeBuilder.Emit(OpCodes.Ldfld, interceptorsField.Fieldbuilder);
            codeBuilder.Emit(OpCodes.Ldc_I4_0);
            codeBuilder.Emit(OpCodes.Ldelem, typeof(IInterceptor));
            codeBuilder.Emit(OpCodes.Castclass, typeof(DocumentProxyInterceptor));
            codeBuilder.Emit(OpCodes.Ldarg_1);
            codeBuilder.Emit(OpCodes.Call, SetMetadata);
            codeBuilder.Emit(OpCodes.Ret);

            propertyBuilder.SetSetMethod(methodBuilder);
        }
		protected MethodEmitter ImplementProxiedMethod(
			Type targetType,
			MethodEmitter methodEmitter,
			MethodInfo method,
			ClassEmitter emitter,
			NestedClassEmitter invocationImpl,
			FieldReference interceptorsField,
			Reference targetRef,
			ConstructorVersion version,
			MethodInfo methodOnTarget)
		{
			CheckNotGenericTypeDefinition(targetType, "targetType");

			methodEmitter.CopyParametersAndReturnTypeFrom(method, emitter);

			TypeReference[] dereferencedArguments = IndirectReference.WrapIfByRef(methodEmitter.Arguments);

			Type iinvocation = invocationImpl.TypeBuilder;

			Trace.Assert(method.IsGenericMethod == iinvocation.IsGenericTypeDefinition);
			bool isGenericInvocationClass = false;
			Type[] genericMethodArgs = new Type[0];
			if (method.IsGenericMethod)
			{
				// bind generic method arguments to invocation's type arguments
				genericMethodArgs = methodEmitter.MethodBuilder.GetGenericArguments();
				iinvocation = iinvocation.MakeGenericType(genericMethodArgs);
				isGenericInvocationClass = true;
			}

			LocalReference invocationImplLocal = methodEmitter.CodeBuilder.DeclareLocal(iinvocation);

			// TODO: Initialize iinvocation instance 
			// with ordinary arguments and in and out arguments

			Expression interceptors;

			// if (useSelector)
			{
				// TODO: Generate code that checks the return of selector
				// if no interceptors is returned, should we invoke the base.Method directly?
			}
			// else
			{
				interceptors = interceptorsField.ToExpression();
			}

			Expression typeTokenFieldExp = typeTokenField.ToExpression();
			Expression methodInfoTokenExp;

			if (method2TokenField.ContainsKey(method)) // Token is in the cache
			{
				methodInfoTokenExp = ((FieldReference) method2TokenField[method]).ToExpression();
			}
			else
			{
				// Not in the cache: generic method

				methodInfoTokenExp = new MethodTokenExpression(method.MakeGenericMethod(genericMethodArgs));
			}

			ConstructorInfo constructor = invocationImpl.Constructors[0].ConstructorBuilder;

			if (isGenericInvocationClass)
			{
				constructor = TypeBuilder.GetConstructor(iinvocation, invocationImpl.Constructors[0].ConstructorBuilder);
			}

			NewInstanceExpression newInvocImpl;

			if (version == ConstructorVersion.WithTargetMethod)
			{
				Expression methodOnTargetTokenExp;

				if (method2TokenField.ContainsKey(methodOnTarget)) // Token is in the cache
				{
					methodOnTargetTokenExp = ((FieldReference) method2TokenField[methodOnTarget]).ToExpression();
				}
				else
				{
					// Not in the cache: generic method

					methodOnTargetTokenExp = new MethodTokenExpression(methodOnTarget.MakeGenericMethod(genericMethodArgs));
				}

				newInvocImpl =
					new NewInstanceExpression(constructor,
					                          targetRef.ToExpression(),
					                          interceptors,
					                          typeTokenFieldExp,
					                          methodOnTargetTokenExp,
					                          methodInfoTokenExp,
					                          new ReferencesToObjectArrayExpression(dereferencedArguments),
					                          SelfReference.Self.ToExpression());
			}
			else
			{
				newInvocImpl =
					new NewInstanceExpression(constructor,
					                          targetRef.ToExpression(),
					                          interceptors,
					                          typeTokenFieldExp,
					                          methodInfoTokenExp,
					                          new ReferencesToObjectArrayExpression(dereferencedArguments),
					                          SelfReference.Self.ToExpression());
			}

			methodEmitter.CodeBuilder.AddStatement(new AssignStatement(invocationImplLocal, newInvocImpl));

			if (method.ContainsGenericParameters)
			{
				EmitLoadGenricMethodArguments(methodEmitter, method.MakeGenericMethod(genericMethodArgs), invocationImplLocal);
			}

			methodEmitter.CodeBuilder.AddStatement(
				new ExpressionStatement(new MethodInvocationExpression(invocationImplLocal, Constants.AbstractInvocationProceed)));

			CopyOutAndRefParameters(dereferencedArguments, invocationImplLocal, method, methodEmitter);

			if (method.ReturnType != typeof(void))
			{
				// Emit code to return with cast from ReturnValue
				MethodInvocationExpression getRetVal =
					new MethodInvocationExpression(invocationImplLocal, typeof(AbstractInvocation).GetMethod("get_ReturnValue"));

				methodEmitter.CodeBuilder.AddStatement(
					new ReturnStatement(new ConvertExpression(methodEmitter.ReturnType, getRetVal)));
			}
			else
			{
				methodEmitter.CodeBuilder.AddStatement(new ReturnStatement());
			}

			return methodEmitter;
		}
		protected void ImplementBlankInterface(
			Type targetType,
			Type _interface,
			ClassEmitter emitter,
			FieldReference interceptorsField,
			ConstructorEmitter typeInitializerConstructor)
		{
			CheckNotGenericTypeDefinition(targetType, "targetType");
			CheckNotGenericTypeDefinition(_interface, "_interface");

			PropertyToGenerate[] propsToGenerate;
			EventToGenerate[] eventsToGenerate;
			MethodInfo[] methods =
				CollectMethodsAndProperties(emitter, _interface, false, out propsToGenerate, out eventsToGenerate);

			Dictionary<MethodInfo, NestedClassEmitter> method2Invocation = new Dictionary<MethodInfo, NestedClassEmitter>();

			foreach(MethodInfo method in methods)
			{
				AddFieldToCacheMethodTokenAndStatementsToInitialize(method, typeInitializerConstructor, emitter);

				method2Invocation[method] =
					BuildInvocationNestedType(emitter,
					                          targetType,
					                          emitter.TypeBuilder,
					                          method,
					                          null,
					                          ConstructorVersion.WithoutTargetMethod);
			}

			foreach(MethodInfo method in methods)
			{
				if (method.IsSpecialName && (method.Name.StartsWith("get_") || method.Name.StartsWith("set_")))
				{
					continue;
				}

				NestedClassEmitter nestedClass = method2Invocation[method];

				MethodEmitter newProxiedMethod =
					CreateProxiedMethod(targetType,
					                    method,
					                    emitter,
					                    nestedClass,
					                    interceptorsField,
					                    SelfReference.Self,
					                    ConstructorVersion.WithoutTargetMethod,
					                    null);

				ReplicateNonInheritableAttributes(method, newProxiedMethod);
			}

			foreach(PropertyToGenerate propToGen in propsToGenerate)
			{
				if (propToGen.CanRead)
				{
					NestedClassEmitter nestedClass = method2Invocation[propToGen.GetMethod];

					MethodAttributes atts = ObtainMethodAttributes(propToGen.GetMethod);

					MethodEmitter getEmitter = propToGen.Emitter.CreateGetMethod(atts);

					ImplementProxiedMethod(targetType,
					                       getEmitter,
					                       propToGen.GetMethod,
					                       emitter,
					                       nestedClass,
					                       interceptorsField,
					                       SelfReference.Self,
					                       ConstructorVersion.WithoutTargetMethod,
					                       null);

					ReplicateNonInheritableAttributes(propToGen.GetMethod, getEmitter);
				}

				if (propToGen.CanWrite)
				{
					NestedClassEmitter nestedClass = method2Invocation[propToGen.SetMethod];

					MethodAttributes atts = ObtainMethodAttributes(propToGen.SetMethod);

					MethodEmitter setEmitter = propToGen.Emitter.CreateSetMethod(atts);

					ImplementProxiedMethod(targetType,
					                       setEmitter,
					                       propToGen.SetMethod,
					                       emitter,
					                       nestedClass,
					                       interceptorsField,
					                       SelfReference.Self,
					                       ConstructorVersion.WithoutTargetMethod,
					                       null);

					ReplicateNonInheritableAttributes(propToGen.SetMethod, setEmitter);
				}
			}

			foreach(EventToGenerate eventToGenerate in eventsToGenerate)
			{
				NestedClassEmitter add_nestedClass = method2Invocation[eventToGenerate.AddMethod];

				MethodAttributes add_atts = ObtainMethodAttributes(eventToGenerate.AddMethod);

				MethodEmitter addEmitter = eventToGenerate.Emitter.CreateAddMethod(add_atts);

				ImplementProxiedMethod(targetType,
				                       addEmitter,
				                       eventToGenerate.AddMethod,
				                       emitter,
				                       add_nestedClass,
				                       interceptorsField,
				                       SelfReference.Self,
				                       ConstructorVersion.WithoutTargetMethod,
				                       null);

				ReplicateNonInheritableAttributes(eventToGenerate.AddMethod, addEmitter);

				NestedClassEmitter remove_nestedClass = method2Invocation[eventToGenerate.RemoveMethod];

				MethodAttributes remove_atts = ObtainMethodAttributes(eventToGenerate.RemoveMethod);

				MethodEmitter removeEmitter = eventToGenerate.Emitter.CreateRemoveMethod(remove_atts);

				ImplementProxiedMethod(targetType,
				                       removeEmitter,
				                       eventToGenerate.RemoveMethod,
				                       emitter,
				                       remove_nestedClass,
				                       interceptorsField,
				                       SelfReference.Self,
				                       ConstructorVersion.WithoutTargetMethod,
				                       null);

				ReplicateNonInheritableAttributes(eventToGenerate.RemoveMethod, removeEmitter);
			}
		}
		private void CreateFields(ClassEmitter emitter, Type proxyTargetType)
		{
			base.CreateFields(emitter);
			targetField = emitter.CreateField("__target", proxyTargetType);

			emitter.DefineCustomAttributeFor<XmlIgnoreAttribute>(targetField);
		}
		public Type GenerateCode(Type proxyTargetType, Type[] interfaces, ProxyGenerationOptions options)
		{
			// make sure ProxyGenerationOptions is initialized
			options.Initialize();

			CheckNotGenericTypeDefinition(proxyTargetType, "proxyTargetType");
			CheckNotGenericTypeDefinitions(interfaces, "interfaces");
			Type generatedType;

			ReaderWriterLock rwlock = Scope.RWLock;

			rwlock.AcquireReaderLock(-1);

			CacheKey cacheKey = new CacheKey(proxyTargetType, targetType, interfaces, options);

			Type cacheType = GetFromCache(cacheKey);

			if (cacheType != null)
			{
				rwlock.ReleaseReaderLock();

				return cacheType;
			}

			rwlock.UpgradeToWriterLock(-1);

			try
			{
				cacheType = GetFromCache(cacheKey);

				if (cacheType != null)
				{
					return cacheType;
				}

				SetGenerationOptions (options);

				String newName = targetType.Name + "Proxy" + Guid.NewGuid().ToString("N");

				// Add Interfaces that the proxy implements 

				ArrayList interfaceList = new ArrayList();

				interfaceList.Add(targetType);

				if (interfaces != null)
				{
					interfaceList.AddRange(interfaces);
				}
				if (!interfaceList.Contains(typeof(ISerializable)))
					interfaceList.Add(typeof(ISerializable));

				AddMixinInterfaces(interfaceList);
				AddDefaultInterfaces(interfaceList);

				Type baseType = options.BaseTypeForInterfaceProxy;

				ClassEmitter emitter = BuildClassEmitter(newName, baseType, interfaceList);
				CreateOptionsField (emitter);

				emitter.DefineCustomAttribute(new XmlIncludeAttribute(targetType));
				emitter.DefineCustomAttribute(new SerializableAttribute());

				// Custom attributes
				ReplicateNonInheritableAttributes(targetType, emitter);

				// Fields generations

				FieldReference interceptorsField = emitter.CreateField("__interceptors", typeof(IInterceptor[]));
				targetField = emitter.CreateField("__target", proxyTargetType);

				emitter.DefineCustomAttributeFor(interceptorsField, new XmlIgnoreAttribute());
				emitter.DefineCustomAttributeFor(targetField, new XmlIgnoreAttribute());

				// Implement builtin Interfaces
				ImplementProxyTargetAccessor(targetType, emitter,interceptorsField);
				
				// Collect methods

				PropertyToGenerate[] propsToGenerate;
				EventToGenerate[] eventToGenerates;
				MethodInfo[] methods = CollectMethodsAndProperties(emitter, targetType, out propsToGenerate, out eventToGenerates);

				if (interfaces != null && interfaces.Length != 0)
				{
					ArrayList tmpInterfaces = new ArrayList(interfaces);

					foreach(Type inter in interfaces)
					{
						if (inter.IsAssignableFrom(proxyTargetType))
						{
							PropertyToGenerate[] tempPropsToGenerate;
							EventToGenerate[] tempEventToGenerates;
							MethodInfo[] methodsTemp =
								CollectMethodsAndProperties(emitter, inter, out tempPropsToGenerate, out tempEventToGenerates);

							PropertyToGenerate[] newPropsToGenerate =
								new PropertyToGenerate[tempPropsToGenerate.Length + propsToGenerate.Length];
							MethodInfo[] newMethods = new MethodInfo[methodsTemp.Length + methods.Length];
							EventToGenerate[] newEvents = new EventToGenerate[eventToGenerates.Length + tempEventToGenerates.Length];

							Array.Copy(methods, newMethods, methods.Length);
							Array.Copy(methodsTemp, 0, newMethods, methods.Length, methodsTemp.Length);

							Array.Copy(propsToGenerate, newPropsToGenerate, propsToGenerate.Length);
							Array.Copy(tempPropsToGenerate, 0, newPropsToGenerate, propsToGenerate.Length, tempPropsToGenerate.Length);

							Array.Copy(eventToGenerates, newEvents, eventToGenerates.Length);
							Array.Copy(tempEventToGenerates, 0, newEvents, eventToGenerates.Length, tempEventToGenerates.Length);

							methods = newMethods;
							propsToGenerate = newPropsToGenerate;
							eventToGenerates = newEvents;

							tmpInterfaces.Remove(inter);
						}
					}

					interfaces = (Type[]) tmpInterfaces.ToArray(typeof(Type));
				}

				RegisterMixinMethodsAndProperties(emitter, ref methods, ref propsToGenerate, ref eventToGenerates);

				options.Hook.MethodsInspected();

				// Constructor

				ConstructorEmitter typeInitializer = GenerateStaticConstructor(emitter);

				if (!proxyTargetType.IsInterface)
				{
					CacheMethodTokens(emitter, MethodFinder.GetAllInstanceMethods(proxyTargetType,
					                                                              BindingFlags.Public | BindingFlags.Instance),
					                  typeInitializer);
				}

				CreateInitializeCacheMethodBody(proxyTargetType, methods, emitter, typeInitializer);
				FieldReference[] mixinFields = AddMixinFields(emitter);
				List<FieldReference> fields = new List<FieldReference>(mixinFields);
				fields.Add(interceptorsField);
				fields.Add(targetField);
				GenerateConstructors(emitter, baseType, fields.ToArray());
				// GenerateParameterlessConstructor(emitter, interceptorsField, baseType);

				// Implement interfaces

				if (interfaces != null && interfaces.Length != 0)
				{
					foreach(Type inter in interfaces)
					{
						ImplementBlankInterface(targetType, inter, emitter, interceptorsField, typeInitializer);
					}
				}

				// Create invocation types

				foreach(MethodInfo method in methods)
				{
					CreateInvocationForMethod(emitter, method, proxyTargetType);
				}

				// Create methods overrides

				Dictionary<MethodInfo, MethodEmitter> method2Emitter = new Dictionary<MethodInfo, MethodEmitter>();

				foreach(MethodInfo method in methods)
				{
					if (method.IsSpecialName &&
					    (method.Name.StartsWith("get_") || method.Name.StartsWith("set_") ||
					     method.Name.StartsWith("add_") || method.Name.StartsWith("remove_")) ||
					    methodsToSkip.Contains(method))
					{
						continue;
					}

					NestedClassEmitter nestedClass = (NestedClassEmitter) method2Invocation[method];

					MethodEmitter newProxiedMethod = CreateProxiedMethod(
						targetType, method, emitter, nestedClass, interceptorsField, GetTargetRef(method, mixinFields, targetField),
						ConstructorVersion.WithTargetMethod, (MethodInfo) method2methodOnTarget[method]);

					ReplicateNonInheritableAttributes(method, newProxiedMethod);

					method2Emitter[method] = newProxiedMethod;
				}

				foreach(PropertyToGenerate propToGen in propsToGenerate)
				{
					if (propToGen.CanRead)
					{
						NestedClassEmitter nestedClass = (NestedClassEmitter) method2Invocation[propToGen.GetMethod];

						MethodAttributes atts = ObtainMethodAttributes(propToGen.GetMethod);

						MethodEmitter getEmitter = propToGen.Emitter.CreateGetMethod(atts);

						ImplementProxiedMethod(targetType, getEmitter,
						                       propToGen.GetMethod, emitter,
											   nestedClass, interceptorsField, GetTargetRef(propToGen.GetMethod, mixinFields, targetField),
						                       ConstructorVersion.WithTargetMethod,
						                       (MethodInfo) method2methodOnTarget[propToGen.GetMethod]);

						ReplicateNonInheritableAttributes(propToGen.GetMethod, getEmitter);

						// emitter.TypeBuilder.DefineMethodOverride(getEmitter.MethodBuilder, propToGen.GetMethod);
					}

					if (propToGen.CanWrite)
					{
						NestedClassEmitter nestedClass = (NestedClassEmitter) method2Invocation[propToGen.SetMethod];

						MethodAttributes atts = ObtainMethodAttributes(propToGen.SetMethod);

						MethodEmitter setEmitter = propToGen.Emitter.CreateSetMethod(atts);

						ImplementProxiedMethod(targetType, setEmitter,
						                       propToGen.SetMethod, emitter,
											   nestedClass, interceptorsField, GetTargetRef(propToGen.SetMethod, mixinFields, targetField),
						                       ConstructorVersion.WithTargetMethod,
						                       (MethodInfo) method2methodOnTarget[propToGen.SetMethod]);

						ReplicateNonInheritableAttributes(propToGen.SetMethod, setEmitter);

						// emitter.TypeBuilder.DefineMethodOverride(setEmitter.MethodBuilder, propToGen.SetMethod);
					}
				}


				foreach(EventToGenerate eventToGenerate in eventToGenerates)
				{
					NestedClassEmitter add_nestedClass = (NestedClassEmitter) method2Invocation[eventToGenerate.AddMethod];

					MethodAttributes add_atts = ObtainMethodAttributes(eventToGenerate.AddMethod);

					MethodEmitter addEmitter = eventToGenerate.Emitter.CreateAddMethod(add_atts);

					ImplementProxiedMethod(targetType, addEmitter,
					                       eventToGenerate.AddMethod, emitter,
										   add_nestedClass, interceptorsField, GetTargetRef(eventToGenerate.AddMethod, mixinFields, targetField),
					                       ConstructorVersion.WithTargetMethod,
					                       (MethodInfo) method2methodOnTarget[eventToGenerate.AddMethod]);

					ReplicateNonInheritableAttributes(eventToGenerate.AddMethod, addEmitter);


					NestedClassEmitter remove_nestedClass = (NestedClassEmitter) method2Invocation[eventToGenerate.RemoveMethod];

					MethodAttributes remove_atts = ObtainMethodAttributes(eventToGenerate.RemoveMethod);

					MethodEmitter removeEmitter = eventToGenerate.Emitter.CreateRemoveMethod(remove_atts);

					ImplementProxiedMethod(targetType, removeEmitter,
					                       eventToGenerate.RemoveMethod, emitter,
										   remove_nestedClass, interceptorsField, GetTargetRef(eventToGenerate.RemoveMethod, mixinFields, targetField),
					                       ConstructorVersion.WithTargetMethod,
					                       (MethodInfo) method2methodOnTarget[eventToGenerate.RemoveMethod]);

					ReplicateNonInheritableAttributes(eventToGenerate.RemoveMethod, removeEmitter);
				}

				ImplementGetObjectData(emitter, interceptorsField, mixinFields, interfaces);

				// Complete Initialize 

				CompleteInitCacheMethod(typeInitializer.CodeBuilder);

				// Crosses fingers and build type

				generatedType = emitter.BuildType();
				InitializeStaticFields (generatedType);

				/*foreach (MethodInfo m in TypeFinder.GetMethods(generatedType, BindingFlags.Instance | BindingFlags.Public))
				{
					ParameterInfo[] parameters = m.GetParameters();

					// Console.WriteLine(m.Name);

					for (int i = 0; i < parameters.Length; i++)
					{
						ParameterInfo paramInfo = parameters[i];

						// Console.WriteLine("{0} {1} {2} {3}", paramInfo.Name, paramInfo.ParameterType, paramInfo.Attributes, paramInfo.Position);
						// Console.WriteLine("{0} {1} {2} {3}", paramInfo2.Name, paramInfo2.ParameterType, paramInfo2.Attributes, paramInfo2.Position);
					}
				}
				*/

				AddToCache(cacheKey, generatedType);
			}
			finally
			{
				rwlock.ReleaseWriterLock();
			}

			return generatedType;
		}
		/// <summary>
		/// Generates the constructor for the nested class that extends
		/// <see cref="AbstractInvocation"/>
		/// </summary>
		/// <param name="targetFieldType"></param>
		/// <param name="nested"></param>
		/// <param name="targetField"></param>
		/// <param name="version"></param>
		protected void CreateIInvocationConstructor(
			Type targetFieldType, NestedClassEmitter nested, FieldReference targetField, ConstructorVersion version)
		{
			ArgumentReference cArg0 = new ArgumentReference(targetFieldType);
			ArgumentReference cArg1 = new ArgumentReference(typeof(IInterceptor[]));
			ArgumentReference cArg2 = new ArgumentReference(typeof(Type));
			ArgumentReference cArg3 = new ArgumentReference(typeof(MethodInfo));
			ArgumentReference cArg4 = null;
			ArgumentReference cArg6 = new ArgumentReference(typeof(object));

			if (version == ConstructorVersion.WithTargetMethod)
			{
				cArg4 = new ArgumentReference(typeof(MethodInfo));
			}

			ArgumentReference cArg5 = new ArgumentReference(typeof(object[]));

			ConstructorEmitter constructor;

			if (cArg4 == null)
			{
				constructor = nested.CreateConstructor(cArg0, cArg1, cArg2, cArg3, cArg5, cArg6);
			}
			else
			{
				constructor = nested.CreateConstructor(cArg0, cArg1, cArg2, cArg3, cArg4, cArg5, cArg6);
			}

			constructor.CodeBuilder.AddStatement(new AssignStatement(targetField, cArg0.ToExpression()));

			if (cArg4 == null)
			{
				constructor.CodeBuilder.InvokeBaseConstructor(Constants.AbstractInvocationConstructorWithoutTargetMethod,
				                                              cArg0,
				                                              cArg6,
				                                              cArg1,
				                                              cArg2,
				                                              cArg3,
				                                              cArg5);
			}
			else
			{
				constructor.CodeBuilder.InvokeBaseConstructor(Constants.AbstractInvocationConstructorWithTargetMethod,
				                                              cArg0,
				                                              cArg6,
				                                              cArg1,
				                                              cArg2,
				                                              cArg3,
				                                              cArg4,
				                                              cArg5);
			}

			constructor.CodeBuilder.AddStatement(new ReturnStatement());
		}
        protected void GenerateSerializationConstructor(ClassEmitter emitter, FieldReference interceptorField,
		                                                bool delegateToBaseGetObjectData)
        {
            ArgumentReference arg1 = new ArgumentReference(typeof(SerializationInfo));
            ArgumentReference arg2 = new ArgumentReference(typeof(StreamingContext));

            ConstructorEmitter constr = emitter.CreateConstructor(arg1, arg2);

            constr.CodeBuilder.AddStatement(
                new ConstructorInvocationStatement(serializationConstructor,
                                                   arg1.ToExpression(), arg2.ToExpression()));

            Type[] object_arg = new Type[] {typeof(String), typeof(Type)};
            MethodInfo getValueMethod = typeof(SerializationInfo).GetMethod("GetValue", object_arg);

            MethodInvocationExpression getInterceptorInvocation =
                new MethodInvocationExpression(arg1, getValueMethod,
                                               new ConstReference("__interceptors").ToExpression(),
                                               new TypeTokenExpression(typeof(IInterceptor[])));

            constr.CodeBuilder.AddStatement(new AssignStatement(
                                                interceptorField,
                                                new ConvertExpression(typeof(IInterceptor[]), typeof(object),
                                                                      getInterceptorInvocation)));

            constr.CodeBuilder.AddStatement(new ReturnStatement());
        }
Beispiel #10
0
		protected void CreateOptionsField(ClassEmitter emitter)
		{
			proxyGenerationOptionsField = emitter.CreateStaticField("proxyGenerationOptions", typeof(ProxyGenerationOptions));
		}
Beispiel #11
0
		protected Reference GetTargetRef(MethodInfo method, FieldReference[] mixinFields, Reference targetRef)
		{
			if (IsMixinMethod(method))
			{
				Type interfaceType = method2MixinType[method];
				int mixinIndex = ProxyGenerationOptions.MixinData.MixinInterfacesAndPositions[interfaceType];
				targetRef = mixinFields[mixinIndex];
			}
			return targetRef;
		}
Beispiel #12
0
		protected MethodEmitter ImplementProxiedMethod(
			Type targetType,
			MethodEmitter methodEmitter,
			MethodInfo method,
			ClassEmitter emitter,
			NestedClassEmitter invocationImpl,
			FieldReference interceptorsField,
			Reference targetRef,
			ConstructorVersion version,
			MethodInfo methodOnTarget)
		{
			CheckNotGenericTypeDefinition(targetType, "targetType");

			methodEmitter.CopyParametersAndReturnTypeFrom(method, emitter);

			TypeReference[] dereferencedArguments = IndirectReference.WrapIfByRef(methodEmitter.Arguments);

			Type iinvocation = invocationImpl.TypeBuilder;

			Trace.Assert(method.IsGenericMethod == iinvocation.IsGenericTypeDefinition);
			bool isGenericInvocationClass = false;
			Type[] genericMethodArgs = new Type[0];
			if (method.IsGenericMethod)
			{
				// bind generic method arguments to invocation's type arguments
				genericMethodArgs = methodEmitter.MethodBuilder.GetGenericArguments();
				iinvocation = iinvocation.MakeGenericType(genericMethodArgs);
				isGenericInvocationClass = true;
			}

			Expression typeTokenFieldExp = typeTokenField.ToExpression();
			Expression methodInfoTokenExp;

			string tokenFieldName;
			if (method2TokenField.ContainsKey(method)) // Token is in the cache
			{
				FieldReference methodTokenField = method2TokenField[method];
				tokenFieldName = methodTokenField.Reference.Name;
				methodInfoTokenExp = methodTokenField.ToExpression();
			}
			else
			{
				// Not in the cache: generic method
				MethodInfo genericMethod = method.MakeGenericMethod(genericMethodArgs);

				// Need random suffix added to the name, so that we don't end up with duplicate field names for
				// methods with the same name, but different generic parameters
				tokenFieldName = string.Format("{0}_{1}_{2}", genericMethod.Name, genericMethodArgs.Length,
				                               Guid.NewGuid().ToString("N"));
				methodInfoTokenExp = new MethodTokenExpression(genericMethod);
			}

			LocalReference invocationImplLocal = methodEmitter.CodeBuilder.DeclareLocal(iinvocation);

			// TODO: Initialize iinvocation instance with ordinary arguments and in and out arguments

			Expression interceptors = interceptorsField.ToExpression();

			// Create the field to store the selected interceptors for this method if an InterceptorSelector is specified
			FieldReference methodInterceptors = null;
			if (proxyGenerationOptions.Selector != null)
			{
				// If no interceptors are returned, should we invoke the base.Method directly? Looks like we should not.
				methodInterceptors = emitter.CreateField(string.Format("{0}_interceptors", tokenFieldName), typeof(IInterceptor[]));
			}

			ConstructorInfo constructor = invocationImpl.Constructors[0].ConstructorBuilder;
			if (isGenericInvocationClass)
			{
				constructor = TypeBuilder.GetConstructor(iinvocation, constructor);
			}

			NewInstanceExpression newInvocImpl;

			if (version == ConstructorVersion.WithTargetMethod)
			{
				Expression methodOnTargetTokenExp;

				if (method2TokenField.ContainsKey(methodOnTarget)) // Token is in the cache
				{
					methodOnTargetTokenExp = method2TokenField[methodOnTarget].ToExpression();
				}
				else
				{
					// Not in the cache: generic method

					methodOnTargetTokenExp = new MethodTokenExpression(methodOnTarget.MakeGenericMethod(genericMethodArgs));
				}
				if (methodInterceptors == null)
				{
					newInvocImpl = //actual contructor call
						new NewInstanceExpression(constructor,
						                          targetRef.ToExpression(),
						                          interceptors,
						                          typeTokenFieldExp,
						                          methodOnTargetTokenExp,
						                          methodInfoTokenExp,
						                          new ReferencesToObjectArrayExpression(dereferencedArguments),
						                          SelfReference.Self.ToExpression());
				}
				else
				{
					MethodInvocationExpression methodInvocationExpression =
						new MethodInvocationExpression(proxyGenerationOptionsField, proxyGenerationOptions_Selector);
					methodInvocationExpression.VirtualCall = true;

					newInvocImpl = //actual contructor call
						new NewInstanceExpression(constructor,
						                          targetRef.ToExpression(),
						                          interceptors,
						                          typeTokenFieldExp,
						                          methodOnTargetTokenExp,
						                          methodInfoTokenExp,
						                          new ReferencesToObjectArrayExpression(dereferencedArguments),
						                          SelfReference.Self.ToExpression(),
						                          methodInvocationExpression,
						                          new AddressOfReferenceExpression(methodInterceptors));
				}
			}
			else
			{
				if (methodInterceptors == null)
				{
					newInvocImpl =
						new NewInstanceExpression(constructor,
						                          targetRef.ToExpression(),
						                          interceptors,
						                          typeTokenFieldExp,
						                          methodInfoTokenExp,
						                          new ReferencesToObjectArrayExpression(dereferencedArguments),
						                          SelfReference.Self.ToExpression());
				}
				else
				{
					MethodInvocationExpression methodInvocationExpression =
						new MethodInvocationExpression(proxyGenerationOptionsField, proxyGenerationOptions_Selector);
					methodInvocationExpression.VirtualCall = true;

					newInvocImpl =
						new NewInstanceExpression(constructor,
						                          targetRef.ToExpression(),
						                          interceptors,
						                          typeTokenFieldExp,
						                          methodInfoTokenExp,
						                          new ReferencesToObjectArrayExpression(dereferencedArguments),
						                          SelfReference.Self.ToExpression(),
						                          methodInvocationExpression,
						                          new AddressOfReferenceExpression(methodInterceptors));
				}
			}

			methodEmitter.CodeBuilder.AddStatement(new AssignStatement(invocationImplLocal, newInvocImpl));

			if (method.ContainsGenericParameters)
			{
				EmitLoadGenricMethodArguments(methodEmitter, method.MakeGenericMethod(genericMethodArgs), invocationImplLocal);
			}

			methodEmitter.CodeBuilder.AddStatement(
				new ExpressionStatement(new MethodInvocationExpression(invocationImplLocal, Constants.AbstractInvocationProceed)));

			CopyOutAndRefParameters(dereferencedArguments, invocationImplLocal, method, methodEmitter);

			if (method.ReturnType != typeof(void))
			{
				// Emit code to return with cast from ReturnValue
				MethodInvocationExpression getRetVal =
					new MethodInvocationExpression(invocationImplLocal, typeof(AbstractInvocation).GetMethod("get_ReturnValue"));

				methodEmitter.CodeBuilder.AddStatement(
					new ReturnStatement(new ConvertExpression(methodEmitter.ReturnType, getRetVal)));
			}
			else
			{
				methodEmitter.CodeBuilder.AddStatement(new ReturnStatement());
			}

			return methodEmitter;
		}
Beispiel #13
0
		protected void ImplementBlankInterface(
			Type targetType,
			Type _interface,
			ClassEmitter emitter,
			FieldReference interceptorsField,
			ConstructorEmitter typeInitializerConstructor)
		{
			ImplementBlankInterface(targetType, _interface, emitter, interceptorsField, typeInitializerConstructor, false);
		}
		private void CreateFields(ClassEmitter emitter, Type proxyTargetType)
		{
			base.CreateFields(emitter);
			targetField = emitter.CreateField("__target", proxyTargetType);

#if SILVERLIGHT
#warning XmlIncludeAttribute is in silverlight, do we want to explore this?
#else
			emitter.DefineCustomAttributeFor<XmlIgnoreAttribute>(targetField);
#endif
		}
		public void DefineCustomAttributeFor(FieldReference field, Attribute attribute)
		{
			CustomAttributeBuilder customAttributeBuilder = CustomAttributeUtil.CreateCustomAttribute(attribute);
			if (customAttributeBuilder == null)
				return;
			field.Reference.SetCustomAttribute(customAttributeBuilder);
		}
		protected void SetGenerationOptions (ProxyGenerationOptions options, ClassEmitter emitter)
		{
			if (proxyGenerationOptions != null)
			{
				throw new InvalidOperationException ("ProxyGenerationOptions can only be set once.");
			}
			proxyGenerationOptions = options;
			proxyGenerationOptionsField = emitter.CreateStaticField ("proxyGenerationOptions", typeof (ProxyGenerationOptions));
		}
		protected void CreateIInvocationInvokeOnTarget(
			ClassEmitter targetTypeEmitter,
			NestedClassEmitter nested,
			ParameterInfo[] parameters,
			FieldReference targetField,
			MethodInfo callbackMethod)
		{
			const MethodAttributes methodAtts = MethodAttributes.Public | MethodAttributes.Final | MethodAttributes.Virtual;

			MethodEmitter method =
				nested.CreateMethod ("InvokeMethodOnTarget", methodAtts, typeof (void));

			Expression[] args = new Expression[parameters.Length];

			// Idea: instead of grab parameters one by one
			// we should grab an array
			Hashtable byRefArguments = new Hashtable();

			for(int i = 0; i < parameters.Length; i++)
			{
				ParameterInfo param = parameters[i];

				Type paramType = param.ParameterType;

				if (HasGenericParameters(paramType))
				{
					paramType = paramType.GetGenericTypeDefinition().MakeGenericType(nested.GetGenericArgumentsFor(paramType));
				}
				else if (paramType.IsGenericParameter)
				{
					paramType = nested.GetGenericArgument(paramType.Name);
				}

				if (paramType.IsByRef)
				{
					LocalReference localReference = method.CodeBuilder.DeclareLocal(paramType.GetElementType());
					method.CodeBuilder.AddStatement(
						new AssignStatement(localReference,
						                    new ConvertExpression(paramType.GetElementType(),
						                                          new MethodInvocationExpression(SelfReference.Self,
						                                                                         typeof(AbstractInvocation).GetMethod(
						                                                                         	"GetArgumentValue"),
						                                                                         new LiteralIntExpression(i)))));
					ByRefReference byRefReference = new ByRefReference(localReference);
					args[i] = new ReferenceExpression(byRefReference);
					byRefArguments[i] = localReference;
				}
				else
				{
					args[i] =
						new ConvertExpression(paramType,
						                      new MethodInvocationExpression(SelfReference.Self,
						                                                     typeof(AbstractInvocation).GetMethod("GetArgumentValue"),
						                                                     new LiteralIntExpression(i)));
				}
			}

			MethodInvocationExpression baseMethodInvExp;

			if (callbackMethod.IsGenericMethod)
			{
				callbackMethod = callbackMethod.MakeGenericMethod(nested.GetGenericArgumentsFor(callbackMethod));
			}

			baseMethodInvExp = new MethodInvocationExpression(targetField, callbackMethod, args);
			baseMethodInvExp.VirtualCall = true;

			LocalReference ret_local = null;

			if (callbackMethod.ReturnType != typeof(void))
			{
				if (callbackMethod.ReturnType.IsGenericParameter)
				{
					ret_local = method.CodeBuilder.DeclareLocal(nested.GetGenericArgument(callbackMethod.ReturnType.Name));
				}
				else if (HasGenericParameters(callbackMethod.ReturnType))
				{
					ret_local =
						method.CodeBuilder.DeclareLocal(
							callbackMethod.ReturnType.GetGenericTypeDefinition().MakeGenericType(
								nested.GetGenericArgumentsFor(callbackMethod.ReturnType)));
				}
				else
				{
					ret_local = method.CodeBuilder.DeclareLocal(callbackMethod.ReturnType);
				}

				method.CodeBuilder.AddStatement(new AssignStatement(ret_local, baseMethodInvExp));
			}
			else
			{
				method.CodeBuilder.AddStatement(new ExpressionStatement(baseMethodInvExp));
			}

			foreach(DictionaryEntry byRefArgument in byRefArguments)
			{
				int index = (int) byRefArgument.Key;
				LocalReference localReference = (LocalReference) byRefArgument.Value;
				method.CodeBuilder.AddStatement(
					new ExpressionStatement(
						new MethodInvocationExpression(SelfReference.Self,
						                               typeof(AbstractInvocation).GetMethod("SetArgumentValue"),
						                               new LiteralIntExpression(index),
						                               new ConvertExpression(typeof(object), localReference.Type,
						                                                     new ReferenceExpression(localReference)))
						));
			}

			if (callbackMethod.ReturnType != typeof(void))
			{
				MethodInvocationExpression setRetVal =
					new MethodInvocationExpression(SelfReference.Self,
					                               typeof(AbstractInvocation).GetMethod("set_ReturnValue"),
					                               new ConvertExpression(typeof(object), ret_local.Type, ret_local.ToExpression()));

				method.CodeBuilder.AddStatement(new ExpressionStatement(setRetVal));
			}

			method.CodeBuilder.AddStatement(new ReturnStatement());
		}
		private void CreateFields(ClassEmitter emitter, Type proxyTargetType)
		{
			base.CreateFields(emitter);
			targetField = emitter.CreateField("__target", proxyTargetType);
#if FEATURE_SERIALIZATION
			emitter.DefineCustomAttributeFor<XmlIgnoreAttribute>(targetField);
#endif
		}
		protected virtual void AddAddValueInvocation(ArgumentReference serializationInfo, MethodEmitter getObjectData,
		                                             FieldReference field)
		{
			getObjectData.CodeBuilder.AddStatement(
				new ExpressionStatement(
					new MethodInvocationExpression(
						serializationInfo,
						SerializationInfoMethods.AddValue_Object,
						new ConstReference(field.Reference.Name).ToExpression(),
						field.ToExpression())));
			return;
		}
		/// <summary>
		/// Improvement: this cache should be static. We should generate a
		/// type constructor instead
		/// </summary>
		protected void CreateInitializeCacheMethodBody(
			Type targetType, MethodInfo[] methods, ClassEmitter classEmitter, ConstructorEmitter typeInitializerConstructor)
		{
			typeTokenField = classEmitter.CreateStaticField("typeTokenCache", typeof(Type));

			typeInitializerConstructor.CodeBuilder.AddStatement(
				new AssignStatement(typeTokenField, new TypeTokenExpression(targetType)));

			CacheMethodTokens(classEmitter, methods, typeInitializerConstructor);
		}
		protected override void AddAddValueInvocation(ArgumentReference serializationInfo, MethodEmitter getObjectData,
		                                              FieldReference field)
		{
			serializedFields.Add(field);
			base.AddAddValueInvocation(serializationInfo, getObjectData, field);
		}
		protected void ImplementProxyTargetAccessor(Type targetType, ClassEmitter emitter, FieldReference interceptorsField)
		{
			MethodAttributes attributes = MethodAttributes.Virtual | MethodAttributes.Public;

			MethodEmitter DynProxyGetTarget =
				emitter.CreateMethod("DynProxyGetTarget", attributes, typeof (object));

			DynProxyGetTarget.CodeBuilder.AddStatement(
				new ReturnStatement(new ConvertExpression(typeof (object), targetType, GetProxyTargetReference().ToExpression())));

			MethodEmitter GetInterceptors =
				emitter.CreateMethod("GetInterceptors", attributes, typeof (IInterceptor[]));

			GetInterceptors.CodeBuilder.AddStatement(
				new ReturnStatement(interceptorsField)
				);
			
		}
		protected virtual Type Init(string typeName, out ClassEmitter emitter, Type proxyTargetType, out FieldReference interceptorsField, IEnumerable<Type> interfaces)
		{
			Type baseType = ProxyGenerationOptions.BaseTypeForInterfaceProxy;

			emitter = BuildClassEmitter(typeName, baseType, interfaces);

			CreateFields(emitter, proxyTargetType);
			CreateTypeAttributes(emitter);

			interceptorsField = emitter.GetField("__interceptors");
			return baseType;
		}
		protected virtual void ImplementGetObjectData(ClassEmitter emitter, FieldReference interceptorsField,
		                                              Type[] interfaces)
		{
			if (interfaces == null)
			{
				interfaces = new Type[0];
			}

			Type[] get_type_args = new Type[] {typeof(String), typeof(bool), typeof(bool)};
			Type[] key_and_object = new Type[] {typeof(String), typeof(Object)};
			MethodInfo addValueMethod = typeof(SerializationInfo).GetMethod("AddValue", key_and_object);

			ArgumentReference arg1 = new ArgumentReference(typeof(SerializationInfo));
			ArgumentReference arg2 = new ArgumentReference(typeof(StreamingContext));
			MethodEmitter getObjectData = emitter.CreateMethod("GetObjectData",
			                                                   typeof(void), arg1, arg2);

			LocalReference typeLocal = getObjectData.CodeBuilder.DeclareLocal(typeof(Type));

			getObjectData.CodeBuilder.AddStatement(new AssignStatement(
			                                       	typeLocal,
			                                       	new MethodInvocationExpression(null,
			                                       	                               typeof(Type).GetMethod("GetType",
			                                       	                                                      get_type_args),
			                                       	                               new ConstReference(
			                                       	                               	typeof(ProxyObjectReference).
			                                       	                               		AssemblyQualifiedName).ToExpression(),
			                                       	                               new ConstReference(1).ToExpression(),
			                                       	                               new ConstReference(0).ToExpression())));

			getObjectData.CodeBuilder.AddStatement(new ExpressionStatement(
			                                       	new MethodInvocationExpression(
			                                       		arg1, typeof(SerializationInfo).GetMethod("SetType"),
			                                       		typeLocal.ToExpression())));

			getObjectData.CodeBuilder.AddStatement(new ExpressionStatement(
			                                       	new MethodInvocationExpression(arg1, addValueMethod,
			                                       	                               new ConstReference("__interceptors").
			                                       	                               	ToExpression(),
			                                       	                               interceptorsField.ToExpression())));

			LocalReference interfacesLocal =
				getObjectData.CodeBuilder.DeclareLocal(typeof(String[]));

			getObjectData.CodeBuilder.AddStatement(
				new AssignStatement(interfacesLocal,
				                    new NewArrayExpression(interfaces.Length, typeof(String))));

			for(int i = 0; i < interfaces.Length; i++)
			{
				getObjectData.CodeBuilder.AddStatement(new AssignArrayStatement(
				                                       	interfacesLocal, i,
				                                       	new ConstReference(interfaces[i].AssemblyQualifiedName).ToExpression()));
			}

			getObjectData.CodeBuilder.AddStatement(new ExpressionStatement(
			                                       	new MethodInvocationExpression(arg1, addValueMethod,
			                                       	                               new ConstReference("__interfaces").
			                                       	                               	ToExpression(),
			                                       	                               interfacesLocal.ToExpression())));

			getObjectData.CodeBuilder.AddStatement(new ExpressionStatement(
			                                       	new MethodInvocationExpression(arg1, addValueMethod,
			                                       	                               new ConstReference("__baseType").
			                                       	                               	ToExpression(),
			                                       	                               new ConstReference (emitter.BaseType.AssemblyQualifiedName).ToExpression())));

			getObjectData.CodeBuilder.AddStatement(new ExpressionStatement(
			                                       	new MethodInvocationExpression(arg1, addValueMethod,
			                                       	                               new ConstReference("__proxyGenerationOptions").
			                                       	                               	ToExpression(),
			                                       	                               proxyGenerationOptionsField.ToExpression())));

			CustomizeGetObjectData(getObjectData.CodeBuilder, arg1, arg2);

			getObjectData.CodeBuilder.AddStatement(new ReturnStatement());
		}
		/// <summary>
		/// Generates a parameters constructor that initializes the proxy
		/// state with <see cref="StandardInterceptor"/> just to make it non-null.
		/// <para>
		/// This constructor is important to allow proxies to be XML serializable
		/// </para>
		/// </summary>
		protected void GenerateParameterlessConstructor(ClassEmitter emitter, Type baseClass, FieldReference interceptorField)
		{
			// Check if the type actually has a default constructor
			ConstructorInfo defaultConstructor = baseClass.GetConstructor(BindingFlags.Public | BindingFlags.Instance, null, Type.EmptyTypes, null);

			if (defaultConstructor == null)
			{
				defaultConstructor = baseClass.GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, Type.EmptyTypes, null);

				if (defaultConstructor == null || defaultConstructor.IsPrivate)
				{
					return;
				}
			}

			ConstructorEmitter constructor = emitter.CreateConstructor();

			// initialize fields with an empty interceptor

			constructor.CodeBuilder.AddStatement(new AssignStatement(interceptorField,
			                                                         new NewArrayExpression(1, typeof (IInterceptor))));
			constructor.CodeBuilder.AddStatement(
				new AssignArrayStatement(interceptorField, 0, new NewInstanceExpression(typeof(StandardInterceptor), new Type[0])));

			// Invoke base constructor

			constructor.CodeBuilder.InvokeBaseConstructor(defaultConstructor);

			constructor.CodeBuilder.AddStatement(new ReturnStatement());
		}
		protected MethodEmitter CreateProxiedMethod(
			Type targetType,
			MethodInfo method,
			ClassEmitter emitter,
			NestedClassEmitter invocationImpl,
			FieldReference interceptorsField,
			Reference targetRef,
			ConstructorVersion version,
			MethodInfo methodOnTarget)
		{
			CheckNotGenericTypeDefinition(targetType, "targetType");

			MethodAttributes atts = ObtainMethodAttributes(method);
			MethodEmitter methodEmitter = emitter.CreateMethod(method.Name, atts);

			return
				ImplementProxiedMethod(targetType,
				                       methodEmitter,
				                       method,
				                       emitter,
				                       invocationImpl,
				                       interceptorsField,
				                       targetRef,
				                       version,
				                       methodOnTarget);
		}