[corlib] CoreRT System.Threading.Tasks (#6672)
[mono-project.git] / mcs / class / System.ComponentModel.Composition.4.5 / src / ComponentModel / System / ComponentModel / Composition / MetadataViewGenerator.cs
blobc05881e1a79ef7dc00ca24563d86671eee482f29
1 #if !FULL_AOT_RUNTIME
2 // -----------------------------------------------------------------------
3 // Copyright (c) Microsoft Corporation. All rights reserved.
4 // -----------------------------------------------------------------------
5 using System;
6 using System.Collections.Generic;
7 using System.ComponentModel;
8 using System.Globalization;
9 using System.Linq;
10 using System.Reflection;
11 using System.Threading;
12 using Microsoft.Internal;
13 using System.Reflection.Emit;
14 using System.Collections;
15 using System.Security;
16 using Lock = Microsoft.Internal.Lock;
18 namespace System.ComponentModel.Composition
20 // // Assume TMetadataView is
21 // //interface Foo
22 // //{
23 // // public typeRecord1 Record1 { get; }
24 // // public typeRecord2 Record2 { get; }
25 // // public typeRecord3 Record3 { get; }
26 // // public typeRecord4 Record4 { get; }
27 // //}
28 // // The class to be generated will look approximately like:
29 // public class __Foo__MedataViewProxy : TMetadataView
30 // {
31 // public __Foo__MedataViewProxy (IDictionary<string, object> metadata)
32 // {
33 // if(metadata == null)
34 // {
35 // throw InvalidArgumentException("metadata");
36 // }
37 // try
38 // {
39 // Record1 = (typeRecord1)Record1;
40 // Record2 = (typeRecord1)Record2;
41 // Record3 = (typeRecord1)Record3;
42 // Record4 = (typeRecord1)Record4;
43 // }
44 // catch(InvalidCastException ice)
45 // {
46 // //Annotate exception .Data with diagnostic info
47 // }
48 // catch(NulLReferenceException ice)
49 // {
50 // //Annotate exception .Data with diagnostic info
51 // }
52 // }
53 // // Interface
54 // public typeRecord1 Record1 { get; }
55 // public typeRecord2 Record2 { get; }
56 // public typeRecord3 Record3 { get; }
57 // public typeRecord4 Record4 { get; }
58 // }
59 internal static class MetadataViewGenerator
61 public const string MetadataViewType = "MetadataViewType";
62 public const string MetadataItemKey = "MetadataItemKey";
63 public const string MetadataItemTargetType = "MetadataItemTargetType";
64 public const string MetadataItemSourceType = "MetadataItemSourceType";
65 public const string MetadataItemValue = "MetadataItemValue";
67 private static Lock _lock = new Lock();
68 private static Dictionary<Type, Type> _proxies = new Dictionary<Type, Type>();
69 private static AssemblyName ProxyAssemblyName = new AssemblyName(string.Format(CultureInfo.InvariantCulture, "MetadataViewProxies_{0}", Guid.NewGuid()));
70 #if FEATURE_CAS_APTCA
71 private static ModuleBuilder criticalProxyModuleBuilder;
72 #endif //FEATURE_CAS_APTCA
73 private static ModuleBuilder transparentProxyModuleBuilder;
75 private static Type[] CtorArgumentTypes = new Type[] { typeof(IDictionary<string, object>) };
76 private static MethodInfo _mdvDictionaryTryGet = CtorArgumentTypes[0].GetMethod("TryGetValue");
77 private static readonly MethodInfo ObjectGetType = typeof(object).GetMethod("GetType", Type.EmptyTypes);
78 #if FEATURE_CAS_APTCA
79 private static CustomAttributeBuilder _securityCriticalBuilder =
80 new CustomAttributeBuilder(typeof(SecurityCriticalAttribute).GetConstructor(Type.EmptyTypes), new object[0]);
81 #endif //FEATURE_CAS_APTCA
83 private static AssemblyBuilder CreateProxyAssemblyBuilder(ConstructorInfo constructorInfo)
85 #if FEATURE_CAS_APTCA
86 object[] args = new object[0];
87 CustomAttributeBuilder accessAttribute = new CustomAttributeBuilder(constructorInfo, args);
88 CustomAttributeBuilder[] attributes = { accessAttribute };
89 return AppDomain.CurrentDomain.DefineDynamicAssembly(ProxyAssemblyName, AssemblyBuilderAccess.Run, attributes, SecurityContextSource.CurrentAppDomain);
90 #else
91 return AppDomain.CurrentDomain.DefineDynamicAssembly(ProxyAssemblyName, AssemblyBuilderAccess.Run);
92 #endif //FEATURE_CAS_APTCA
95 // Must be called with _lock held
96 private static ModuleBuilder GetProxyModuleBuilder(bool requiresCritical)
98 #if FEATURE_CAS_APTCA
99 if(requiresCritical)
101 // Needed a critical modulebuilder so find or make it
102 if (criticalProxyModuleBuilder == null)
104 var assemblyBuilder = CreateProxyAssemblyBuilder(typeof(AllowPartiallyTrustedCallersAttribute).GetConstructor(Type.EmptyTypes));
105 criticalProxyModuleBuilder = assemblyBuilder.DefineDynamicModule("MetadataViewProxiesModule");
107 return criticalProxyModuleBuilder;
109 #endif //FEATURE_CAS_APTCA
110 if (transparentProxyModuleBuilder == null)
112 // make a new assemblybuilder and modulebuilder
113 var assemblyBuilder = CreateProxyAssemblyBuilder(typeof(SecurityTransparentAttribute).GetConstructor(Type.EmptyTypes));
114 transparentProxyModuleBuilder = assemblyBuilder.DefineDynamicModule("MetadataViewProxiesModule");
117 return transparentProxyModuleBuilder;
120 public static Type GenerateView(Type viewType)
122 Assumes.NotNull(viewType);
123 Assumes.IsTrue(viewType.IsInterface);
125 Type proxyType;
126 bool foundProxy;
128 using (new ReadLock(_lock))
130 foundProxy = _proxies.TryGetValue(viewType, out proxyType);
133 // No factory exists
134 if(!foundProxy)
136 // Try again under a write lock if still none generate the proxy
137 Type generatedProxyType = GenerateInterfaceViewProxyType(viewType);
138 Assumes.NotNull(generatedProxyType);
140 using (new WriteLock(_lock))
142 if (!_proxies.TryGetValue(viewType, out proxyType))
144 proxyType = generatedProxyType;
145 _proxies.Add(viewType, proxyType);
149 return proxyType;
152 private static void GenerateLocalAssignmentFromDefaultAttribute(this ILGenerator IL, DefaultValueAttribute[] attrs, LocalBuilder local)
154 if (attrs.Length > 0)
156 DefaultValueAttribute defaultAttribute = attrs[0];
157 IL.LoadValue(defaultAttribute.Value);
158 if ((defaultAttribute.Value != null) && (defaultAttribute.Value.GetType().IsValueType))
160 IL.Emit(OpCodes.Box, defaultAttribute.Value.GetType());
162 IL.Emit(OpCodes.Stloc, local);
166 private static void GenerateFieldAssignmentFromLocalValue(this ILGenerator IL, LocalBuilder local, FieldBuilder field)
168 IL.Emit(OpCodes.Ldarg_0);
169 IL.Emit(OpCodes.Ldloc, local);
170 IL.Emit(field.FieldType.IsValueType ? OpCodes.Unbox_Any : OpCodes.Castclass, field.FieldType);
171 IL.Emit(OpCodes.Stfld, field);
174 private static void GenerateLocalAssignmentFromFlag(this ILGenerator IL, LocalBuilder local, bool flag)
176 IL.Emit(flag ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0);
177 IL.Emit(OpCodes.Stloc, local);
180 // This must be called with _readerWriterLock held for Write
181 private static Type GenerateInterfaceViewProxyType(Type viewType)
183 // View type is an interface let's cook an implementation
184 Type proxyType;
185 TypeBuilder proxyTypeBuilder;
186 Type[] interfaces = { viewType };
187 bool requiresCritical = false;
188 #if FEATURE_CAS_APTCA
189 requiresCritical = !viewType.IsSecurityTransparent;
190 #endif //FEATURE_CAS_APTCA
192 var proxyModuleBuilder = GetProxyModuleBuilder(requiresCritical);
193 proxyTypeBuilder = proxyModuleBuilder.DefineType(
194 string.Format(CultureInfo.InvariantCulture, "_proxy_{0}_{1}", viewType.FullName, Guid.NewGuid()),
195 TypeAttributes.Public,
196 typeof(object),
197 interfaces);
198 #if FEATURE_CAS_APTCA
199 if (requiresCritical)
201 proxyTypeBuilder.SetCustomAttribute(_securityCriticalBuilder);
203 #endif //FEATURE_CAS_APTCA
204 // Implement Constructor
205 ILGenerator proxyCtorIL = proxyTypeBuilder.CreateGeneratorForPublicConstructor(CtorArgumentTypes);
206 LocalBuilder exception = proxyCtorIL.DeclareLocal(typeof(Exception));
207 LocalBuilder exceptionData = proxyCtorIL.DeclareLocal(typeof(IDictionary));
208 LocalBuilder sourceType = proxyCtorIL.DeclareLocal(typeof(Type));
209 LocalBuilder value = proxyCtorIL.DeclareLocal(typeof(object));
210 LocalBuilder usesExportedMD = proxyCtorIL.DeclareLocal(typeof(bool));
212 Label tryConstructView = proxyCtorIL.BeginExceptionBlock();
214 // Implement interface properties
215 foreach (PropertyInfo propertyInfo in viewType.GetAllProperties())
217 string fieldName = string.Format(CultureInfo.InvariantCulture, "_{0}_{1}", propertyInfo.Name, Guid.NewGuid());
219 // Cache names and type for exception
220 string propertyName = string.Format(CultureInfo.InvariantCulture, "{0}", propertyInfo.Name);
222 Type[] propertyTypeArguments = new Type[] { propertyInfo.PropertyType };
223 Type[] optionalModifiers = null;
224 Type[] requiredModifiers = null;
226 #if FEATURE_ADVANCEDREFLECTION
227 // PropertyInfo does not support GetOptionalCustomModifiers and GetRequiredCustomModifiers on Silverlight
228 optionalModifiers = propertyInfo.GetOptionalCustomModifiers();
229 requiredModifiers = propertyInfo.GetRequiredCustomModifiers();
230 Array.Reverse(optionalModifiers);
231 Array.Reverse(requiredModifiers);
232 #endif //FEATURE_ADVANCEDREFLECTION
234 // Generate field
235 FieldBuilder proxyFieldBuilder = proxyTypeBuilder.DefineField(
236 fieldName,
237 propertyInfo.PropertyType,
238 FieldAttributes.Private);
240 // Generate property
241 PropertyBuilder proxyPropertyBuilder = proxyTypeBuilder.DefineProperty(
242 propertyName,
243 PropertyAttributes.None,
244 propertyInfo.PropertyType,
245 propertyTypeArguments);
247 // Generate constructor code for retrieving the metadata value and setting the field
248 Label tryCastValue = proxyCtorIL.BeginExceptionBlock();
249 Label innerTryCastValue;
251 DefaultValueAttribute[] attrs = propertyInfo.GetAttributes<DefaultValueAttribute>(false);
252 if(attrs.Length > 0)
254 innerTryCastValue = proxyCtorIL.BeginExceptionBlock();
257 // In constructor set the backing field with the value from the dictionary
258 Label doneGettingDefaultValue = proxyCtorIL.DefineLabel();
259 GenerateLocalAssignmentFromFlag(proxyCtorIL, usesExportedMD, true);
261 proxyCtorIL.Emit(OpCodes.Ldarg_1);
262 proxyCtorIL.Emit(OpCodes.Ldstr, propertyInfo.Name);
263 proxyCtorIL.Emit(OpCodes.Ldloca, value);
264 proxyCtorIL.Emit(OpCodes.Callvirt, _mdvDictionaryTryGet);
265 proxyCtorIL.Emit(OpCodes.Brtrue, doneGettingDefaultValue);
267 proxyCtorIL.GenerateLocalAssignmentFromFlag(usesExportedMD, false);
268 proxyCtorIL.GenerateLocalAssignmentFromDefaultAttribute(attrs, value);
270 proxyCtorIL.MarkLabel(doneGettingDefaultValue);
271 proxyCtorIL.GenerateFieldAssignmentFromLocalValue(value, proxyFieldBuilder);
272 proxyCtorIL.Emit(OpCodes.Leave, tryCastValue);
274 // catch blocks for innerTryCastValue start here
275 if (attrs.Length > 0)
277 proxyCtorIL.BeginCatchBlock(typeof(InvalidCastException));
279 Label notUsesExportedMd = proxyCtorIL.DefineLabel();
280 proxyCtorIL.Emit(OpCodes.Ldloc, usesExportedMD);
281 proxyCtorIL.Emit(OpCodes.Brtrue, notUsesExportedMd);
282 proxyCtorIL.Emit(OpCodes.Rethrow);
283 proxyCtorIL.MarkLabel(notUsesExportedMd);
284 proxyCtorIL.GenerateLocalAssignmentFromDefaultAttribute(attrs, value);
285 proxyCtorIL.GenerateFieldAssignmentFromLocalValue(value, proxyFieldBuilder);
287 proxyCtorIL.EndExceptionBlock();
290 // catch blocks for tryCast start here
291 proxyCtorIL.BeginCatchBlock(typeof(NullReferenceException));
293 proxyCtorIL.Emit(OpCodes.Stloc, exception);
295 proxyCtorIL.GetExceptionDataAndStoreInLocal(exception, exceptionData);
296 proxyCtorIL.AddItemToLocalDictionary(exceptionData, MetadataItemKey, propertyName);
297 proxyCtorIL.AddItemToLocalDictionary(exceptionData, MetadataItemTargetType, propertyInfo.PropertyType);
298 proxyCtorIL.Emit(OpCodes.Rethrow);
301 proxyCtorIL.BeginCatchBlock(typeof(InvalidCastException));
303 proxyCtorIL.Emit(OpCodes.Stloc, exception);
305 proxyCtorIL.GetExceptionDataAndStoreInLocal(exception, exceptionData);
306 proxyCtorIL.AddItemToLocalDictionary(exceptionData, MetadataItemKey, propertyName);
307 proxyCtorIL.AddItemToLocalDictionary(exceptionData, MetadataItemTargetType, propertyInfo.PropertyType);
308 proxyCtorIL.Emit(OpCodes.Rethrow);
311 proxyCtorIL.EndExceptionBlock();
313 if (propertyInfo.CanWrite)
315 // The MetadataView '{0}' is invalid because property '{1}' has a property set method.
316 throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture,
317 Strings.InvalidSetterOnMetadataField,
318 viewType,
319 propertyName));
321 if (propertyInfo.CanRead)
323 // Generate "get" method implementation.
324 MethodBuilder getMethodBuilder = proxyTypeBuilder.DefineMethod(
325 string.Format(CultureInfo.InvariantCulture, "get_{0}", propertyName),
326 MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.NewSlot | MethodAttributes.Virtual | MethodAttributes.Final,
327 CallingConventions.HasThis,
328 propertyInfo.PropertyType,
329 requiredModifiers,
330 optionalModifiers,
331 Type.EmptyTypes, null, null);
333 proxyTypeBuilder.DefineMethodOverride(getMethodBuilder, propertyInfo.GetGetMethod());
334 #if FEATURE_CAS_APTCA
335 if(!viewType.IsSecurityTransparent)
337 getMethodBuilder.SetCustomAttribute(_securityCriticalBuilder);
339 #endif //FEATURE_CAS_APTCA
340 ILGenerator getMethodIL = getMethodBuilder.GetILGenerator();
341 getMethodIL.Emit(OpCodes.Ldarg_0);
342 getMethodIL.Emit(OpCodes.Ldfld, proxyFieldBuilder);
343 getMethodIL.Emit(OpCodes.Ret);
345 proxyPropertyBuilder.SetGetMethod(getMethodBuilder);
349 proxyCtorIL.Emit(OpCodes.Leave, tryConstructView);
351 // catch blocks for constructView start here
352 proxyCtorIL.BeginCatchBlock(typeof(NullReferenceException));
354 proxyCtorIL.Emit(OpCodes.Stloc, exception);
356 proxyCtorIL.GetExceptionDataAndStoreInLocal(exception, exceptionData);
357 proxyCtorIL.AddItemToLocalDictionary(exceptionData, MetadataViewType, viewType);
358 proxyCtorIL.Emit(OpCodes.Rethrow);
360 proxyCtorIL.BeginCatchBlock(typeof(InvalidCastException));
362 proxyCtorIL.Emit(OpCodes.Stloc, exception);
364 proxyCtorIL.GetExceptionDataAndStoreInLocal(exception, exceptionData);
365 proxyCtorIL.Emit(OpCodes.Ldloc, value);
366 proxyCtorIL.Emit(OpCodes.Call, ObjectGetType);
367 proxyCtorIL.Emit(OpCodes.Stloc, sourceType);
368 proxyCtorIL.AddItemToLocalDictionary(exceptionData, MetadataViewType, viewType);
369 proxyCtorIL.AddLocalToLocalDictionary(exceptionData, MetadataItemSourceType, sourceType);
370 proxyCtorIL.AddLocalToLocalDictionary(exceptionData, MetadataItemValue, value);
371 proxyCtorIL.Emit(OpCodes.Rethrow);
373 proxyCtorIL.EndExceptionBlock();
375 // Finished implementing interface and constructor
376 proxyCtorIL.Emit(OpCodes.Ret);
377 proxyType = proxyTypeBuilder.CreateType();
379 return proxyType;
384 #endif