d670031fed93d02307c317519b9b6d98a2e79c4b
[platform/upstream/coreclr.git] / src / System.Private.CoreLib / src / System / Reflection / RuntimeAssembly.cs
1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4
5 using System.Collections.Generic;
6 using System.Diagnostics;
7 using CultureInfo = System.Globalization.CultureInfo;
8 using System.Security;
9 using System.IO;
10 using StringBuilder = System.Text.StringBuilder;
11 using System.Configuration.Assemblies;
12 using StackCrawlMark = System.Threading.StackCrawlMark;
13 using System.Runtime.InteropServices;
14 using System.Runtime.CompilerServices;
15 using System.Runtime.Serialization;
16 using System.Threading;
17
18 namespace System.Reflection
19 {
20     internal class RuntimeAssembly : Assembly
21     {
22         internal RuntimeAssembly() { throw new NotSupportedException(); }
23
24         #region private data members
25         private event ModuleResolveEventHandler _ModuleResolve;
26         private string m_fullname;
27         private object m_syncRoot;   // Used to keep collectible types alive and as the syncroot for reflection.emit
28         private IntPtr m_assembly;    // slack for ptr datum on unmanaged side
29
30         #endregion
31
32         internal object SyncRoot
33         {
34             get
35             {
36                 if (m_syncRoot == null)
37                 {
38                     Interlocked.CompareExchange<object>(ref m_syncRoot, new object(), null);
39                 }
40                 return m_syncRoot;
41             }
42         }
43
44         public override event ModuleResolveEventHandler ModuleResolve
45         {
46             add
47             {
48                 _ModuleResolve += value;
49             }
50             remove
51             {
52                 _ModuleResolve -= value;
53             }
54         }
55
56         private const string s_localFilePrefix = "file:";
57
58         [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
59         private static extern void GetCodeBase(RuntimeAssembly assembly,
60                                                bool copiedName,
61                                                StringHandleOnStack retString);
62
63         internal string GetCodeBase(bool copiedName)
64         {
65             string codeBase = null;
66             GetCodeBase(GetNativeHandle(), copiedName, JitHelpers.GetStringHandleOnStack(ref codeBase));
67             return codeBase;
68         }
69
70         public override string CodeBase => GetCodeBase(false);
71
72         internal RuntimeAssembly GetNativeHandle() => this;
73
74         // If the assembly is copied before it is loaded, the codebase will be set to the
75         // actual file loaded if copiedName is true. If it is false, then the original code base
76         // is returned.
77         public override AssemblyName GetName(bool copiedName)
78         {
79             AssemblyName an = new AssemblyName();
80
81             string codeBase = GetCodeBase(copiedName);
82
83             an.Init(GetSimpleName(),
84                     GetPublicKey(),
85                     null, // public key token
86                     GetVersion(),
87                     GetLocale(),
88                     GetHashAlgorithm(),
89                     AssemblyVersionCompatibility.SameMachine,
90                     codeBase,
91                     GetFlags() | AssemblyNameFlags.PublicKey,
92                     null); // strong name key pair
93
94             Module manifestModule = ManifestModule;
95             if (manifestModule != null)
96             {
97                 if (manifestModule.MDStreamVersion > 0x10000)
98                 {
99                     ManifestModule.GetPEKind(out PortableExecutableKinds pek, out ImageFileMachine ifm);
100                     an.SetProcArchIndex(pek, ifm);
101                 }
102             }
103             return an;
104         }
105
106         [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
107         private static extern void GetFullName(RuntimeAssembly assembly, StringHandleOnStack retString);
108
109         public override string FullName
110         {
111             get
112             {
113                 // If called by Object.ToString(), return val may be NULL.
114                 if (m_fullname == null)
115                 {
116                     string s = null;
117                     GetFullName(GetNativeHandle(), JitHelpers.GetStringHandleOnStack(ref s));
118                     Interlocked.CompareExchange<string>(ref m_fullname, s, null);
119                 }
120
121                 return m_fullname;
122             }
123         }
124
125         [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
126         private static extern void GetEntryPoint(RuntimeAssembly assembly, ObjectHandleOnStack retMethod);
127
128         public override MethodInfo EntryPoint
129         {
130             get
131             {
132                 IRuntimeMethodInfo methodHandle = null;
133                 GetEntryPoint(GetNativeHandle(), JitHelpers.GetObjectHandleOnStack(ref methodHandle));
134
135                 if (methodHandle == null)
136                     return null;
137
138                 return (MethodInfo)RuntimeType.GetMethodBase(methodHandle);
139             }
140         }
141
142         [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
143         private static extern void GetType(RuntimeAssembly assembly,
144                                                         string name,
145                                                         bool throwOnError,
146                                                         bool ignoreCase,
147                                                         ObjectHandleOnStack type,
148                                                         ObjectHandleOnStack keepAlive);
149
150         public override Type GetType(string name, bool throwOnError, bool ignoreCase)
151         {
152             // throw on null strings regardless of the value of "throwOnError"
153             if (name == null)
154                 throw new ArgumentNullException(nameof(name));
155
156             RuntimeType type = null;
157             object keepAlive = null;
158             GetType(GetNativeHandle(), name, throwOnError, ignoreCase, JitHelpers.GetObjectHandleOnStack(ref type), JitHelpers.GetObjectHandleOnStack(ref keepAlive));
159             GC.KeepAlive(keepAlive);
160
161             return type;
162         }
163
164         [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
165         private static extern void GetExportedTypes(RuntimeAssembly assembly, ObjectHandleOnStack retTypes);
166
167         public override Type[] GetExportedTypes()
168         {
169             Type[] types = null;
170             GetExportedTypes(GetNativeHandle(), JitHelpers.GetObjectHandleOnStack(ref types));
171             return types;
172         }
173
174         public override IEnumerable<TypeInfo> DefinedTypes
175         {
176             get
177             {
178                 RuntimeModule[] modules = GetModulesInternal(true, false);
179                 if (modules.Length == 1)
180                 {
181                     return modules[0].GetDefinedTypes();
182                 }
183
184                 List<RuntimeType> rtTypes = new List<RuntimeType>();
185
186                 for (int i = 0; i < modules.Length; i++)
187                 {
188                     rtTypes.AddRange(modules[i].GetDefinedTypes());
189                 }
190
191                 return rtTypes.ToArray();
192             }
193         }
194
195         [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
196         [return: MarshalAs(UnmanagedType.Bool)]
197         internal static extern bool GetIsCollectible(RuntimeAssembly assembly);
198
199         public override bool IsCollectible => GetIsCollectible(GetNativeHandle());
200
201         // GetResource will return a pointer to the resources in memory.
202         [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
203         private static extern unsafe byte* GetResource(RuntimeAssembly assembly,
204                                                        string resourceName,
205                                                        out uint length);
206
207         // Load a resource based on the NameSpace of the type.
208         public override Stream GetManifestResourceStream(Type type, string name)
209         {
210             if (type == null && name == null)
211                 throw new ArgumentNullException(nameof(type));
212
213             string nameSpace = type?.Namespace;
214
215             char c = Type.Delimiter;
216             string resourceName = nameSpace != null && name != null ?
217                 string.Concat(nameSpace, new ReadOnlySpan<char>(ref c, 1), name) :
218                 string.Concat(nameSpace, name);
219
220             return GetManifestResourceStream(resourceName);
221         }
222
223         public unsafe override Stream GetManifestResourceStream(string name)
224         {
225             uint length = 0;
226             byte* pbInMemoryResource = GetResource(GetNativeHandle(), name, out length);
227
228             if (pbInMemoryResource != null)
229             {
230                 return new UnmanagedMemoryStream(pbInMemoryResource, length, length, FileAccess.Read);
231             }
232
233             return null;
234         }
235
236         // ISerializable implementation
237         public override void GetObjectData(SerializationInfo info, StreamingContext context)
238         {
239             throw new PlatformNotSupportedException();
240         }
241
242         public override Module ManifestModule
243         {
244             get
245             {
246                 // We don't need to return the "external" ModuleBuilder because
247                 // it is meant to be read-only
248                 return RuntimeAssembly.GetManifestModule(GetNativeHandle());
249             }
250         }
251
252         public override object[] GetCustomAttributes(bool inherit)
253         {
254             return CustomAttribute.GetCustomAttributes(this, typeof(object) as RuntimeType);
255         }
256
257         public override object[] GetCustomAttributes(Type attributeType, bool inherit)
258         {
259             if (attributeType == null)
260                 throw new ArgumentNullException(nameof(attributeType));
261
262             RuntimeType attributeRuntimeType = attributeType.UnderlyingSystemType as RuntimeType;
263
264             if (attributeRuntimeType == null)
265                 throw new ArgumentException(SR.Arg_MustBeType, nameof(attributeType));
266
267             return CustomAttribute.GetCustomAttributes(this, attributeRuntimeType);
268         }
269
270         public override bool IsDefined(Type attributeType, bool inherit)
271         {
272             if (attributeType == null)
273                 throw new ArgumentNullException(nameof(attributeType));
274
275             RuntimeType attributeRuntimeType = attributeType.UnderlyingSystemType as RuntimeType;
276
277             if (attributeRuntimeType == null)
278                 throw new ArgumentException(SR.Arg_MustBeType, nameof(attributeType));
279
280             return CustomAttribute.IsDefined(this, attributeRuntimeType);
281         }
282
283         public override IList<CustomAttributeData> GetCustomAttributesData()
284         {
285             return CustomAttributeData.GetCustomAttributesInternal(this);
286         }
287
288         internal static RuntimeAssembly InternalLoad(string assemblyString, ref StackCrawlMark stackMark)
289         {
290             RuntimeAssembly assembly;
291             AssemblyName an = CreateAssemblyName(assemblyString, out assembly);
292
293             if (assembly != null)
294             {
295                 // The assembly was returned from ResolveAssemblyEvent
296                 return assembly;
297             }
298
299             return InternalLoadAssemblyName(an, ref stackMark);
300         }
301
302         // Creates AssemblyName. Fills assembly if AssemblyResolve event has been raised.
303         internal static AssemblyName CreateAssemblyName(
304             string assemblyString,
305             out RuntimeAssembly assemblyFromResolveEvent)
306         {
307             if (assemblyString == null)
308                 throw new ArgumentNullException(nameof(assemblyString));
309
310             if ((assemblyString.Length == 0) ||
311                 (assemblyString[0] == '\0'))
312                 throw new ArgumentException(SR.Format_StringZeroLength);
313
314             AssemblyName an = new AssemblyName();
315
316             an.Name = assemblyString;
317             an.nInit(out assemblyFromResolveEvent, true);
318
319             return an;
320         }
321
322         internal static RuntimeAssembly InternalLoadAssemblyName(AssemblyName assemblyRef, ref StackCrawlMark stackMark, IntPtr ptrLoadContextBinder = default)
323         {
324 #if FEATURE_APPX
325             if (ApplicationModel.IsUap)
326             {
327                 if (assemblyRef.CodeBase != null)
328                 {
329                     throw new NotSupportedException(SR.Format(SR.NotSupported_AppX, "Assembly.LoadFrom"));
330                 }
331             }
332 #endif
333
334             assemblyRef = (AssemblyName)assemblyRef.Clone();
335             if (assemblyRef.ProcessorArchitecture != ProcessorArchitecture.None)
336             {
337                 // PA does not have a semantics for by-name binds for execution
338                 assemblyRef.ProcessorArchitecture = ProcessorArchitecture.None;
339             }
340
341             string codeBase = VerifyCodeBase(assemblyRef.CodeBase);
342
343             return nLoad(assemblyRef, codeBase, null, ref stackMark, true, ptrLoadContextBinder);
344         }
345
346         [MethodImplAttribute(MethodImplOptions.InternalCall)]
347         private static extern RuntimeAssembly nLoad(AssemblyName fileName,
348                                                     string codeBase,
349                                                     RuntimeAssembly assemblyContext,
350                                                     ref StackCrawlMark stackMark,
351                                                     bool throwOnFileNotFound,
352                                                     IntPtr ptrLoadContextBinder);
353
354         public override bool ReflectionOnly
355         {
356             get
357             {
358                 return false;
359             }
360         }
361
362         // Returns the module in this assembly with name 'name'
363
364         [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
365         private static extern void GetModule(RuntimeAssembly assembly, string name, ObjectHandleOnStack retModule);
366
367         public override Module GetModule(string name)
368         {
369             Module retModule = null;
370             GetModule(GetNativeHandle(), name, JitHelpers.GetObjectHandleOnStack(ref retModule));
371             return retModule;
372         }
373
374         // Returns the file in the File table of the manifest that matches the
375         // given name.  (Name should not include path.)
376         public override FileStream GetFile(string name)
377         {
378             RuntimeModule m = (RuntimeModule)GetModule(name);
379             if (m == null)
380                 return null;
381
382             return new FileStream(m.GetFullyQualifiedName(),
383                                   FileMode.Open,
384                                   FileAccess.Read, FileShare.Read, FileStream.DefaultBufferSize, false);
385         }
386
387         public override FileStream[] GetFiles(bool getResourceModules)
388         {
389             Module[] m = GetModules(getResourceModules);
390             FileStream[] fs = new FileStream[m.Length];
391
392             for (int i = 0; i < fs.Length; i++)
393             {
394                 fs[i] = new FileStream(((RuntimeModule)m[i]).GetFullyQualifiedName(),
395                                        FileMode.Open,
396                                        FileAccess.Read, FileShare.Read, FileStream.DefaultBufferSize, false);
397             }
398
399             return fs;
400         }
401
402         // Returns the names of all the resources
403         [MethodImplAttribute(MethodImplOptions.InternalCall)]
404         private static extern string[] GetManifestResourceNames(RuntimeAssembly assembly);
405
406         // Returns the names of all the resources
407         public override string[] GetManifestResourceNames()
408         {
409             return GetManifestResourceNames(GetNativeHandle());
410         }
411
412         // Returns the names of all the resources
413         [MethodImplAttribute(MethodImplOptions.InternalCall)]
414         private static extern AssemblyName[] GetReferencedAssemblies(RuntimeAssembly assembly);
415
416         public override AssemblyName[] GetReferencedAssemblies()
417         {
418             return GetReferencedAssemblies(GetNativeHandle());
419         }
420
421         [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
422         private static extern int GetManifestResourceInfo(RuntimeAssembly assembly,
423                                                           string resourceName,
424                                                           ObjectHandleOnStack assemblyRef,
425                                                           StringHandleOnStack retFileName);
426
427         public override ManifestResourceInfo GetManifestResourceInfo(string resourceName)
428         {
429             RuntimeAssembly retAssembly = null;
430             string fileName = null;
431             int location = GetManifestResourceInfo(GetNativeHandle(), resourceName,
432                                                    JitHelpers.GetObjectHandleOnStack(ref retAssembly),
433                                                    JitHelpers.GetStringHandleOnStack(ref fileName));
434
435             if (location == -1)
436                 return null;
437
438             return new ManifestResourceInfo(retAssembly, fileName,
439                                                 (ResourceLocation)location);
440         }
441
442         [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
443         private static extern void GetLocation(RuntimeAssembly assembly, StringHandleOnStack retString);
444
445         public override string Location
446         {
447             get
448             {
449                 string location = null;
450
451                 GetLocation(GetNativeHandle(), JitHelpers.GetStringHandleOnStack(ref location));
452
453                 return location;
454             }
455         }
456
457         [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
458         private static extern void GetImageRuntimeVersion(RuntimeAssembly assembly, StringHandleOnStack retString);
459
460         public override string ImageRuntimeVersion
461         {
462             get
463             {
464                 string s = null;
465                 GetImageRuntimeVersion(GetNativeHandle(), JitHelpers.GetStringHandleOnStack(ref s));
466                 return s;
467             }
468         }
469
470         public override bool GlobalAssemblyCache
471         {
472             get
473             {
474                 return false;
475             }
476         }
477
478         public override long HostContext
479         {
480             get
481             {
482                 return 0;
483             }
484         }
485
486         private static string VerifyCodeBase(string codebase)
487         {
488             if (codebase == null)
489                 return null;
490
491             int len = codebase.Length;
492             if (len == 0)
493                 return null;
494
495
496             int j = codebase.IndexOf(':');
497             // Check to see if the url has a prefix
498             if ((j != -1) &&
499                 (j + 2 < len) &&
500                 ((codebase[j + 1] == '/') || (codebase[j + 1] == '\\')) &&
501                 ((codebase[j + 2] == '/') || (codebase[j + 2] == '\\')))
502                 return codebase;
503 #if PLATFORM_WINDOWS
504             else if ((len > 2) && (codebase[0] == '\\') && (codebase[1] == '\\'))
505                 return "file://" + codebase;
506             else
507                 return "file:///" + Path.GetFullPath(codebase);
508 #else
509             else
510                 return "file://" + Path.GetFullPath(codebase);
511 #endif // PLATFORM_WINDOWS
512         }
513
514         [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
515         private static extern void GetVersion(RuntimeAssembly assembly,
516                                               out int majVer,
517                                               out int minVer,
518                                               out int buildNum,
519                                               out int revNum);
520
521         internal Version GetVersion()
522         {
523             int majorVer, minorVer, build, revision;
524             GetVersion(GetNativeHandle(), out majorVer, out minorVer, out build, out revision);
525             return new Version(majorVer, minorVer, build, revision);
526         }
527
528         [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
529         private static extern void GetLocale(RuntimeAssembly assembly, StringHandleOnStack retString);
530
531         internal CultureInfo GetLocale()
532         {
533             string locale = null;
534
535             GetLocale(GetNativeHandle(), JitHelpers.GetStringHandleOnStack(ref locale));
536
537             if (locale == null)
538                 return CultureInfo.InvariantCulture;
539
540             return new CultureInfo(locale);
541         }
542
543         [MethodImplAttribute(MethodImplOptions.InternalCall)]
544         private static extern bool FCallIsDynamic(RuntimeAssembly assembly);
545
546         public override bool IsDynamic
547         {
548             get
549             {
550                 return FCallIsDynamic(GetNativeHandle());
551             }
552         }
553
554         [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
555         private static extern void GetSimpleName(RuntimeAssembly assembly, StringHandleOnStack retSimpleName);
556
557         internal string GetSimpleName()
558         {
559             string name = null;
560             GetSimpleName(GetNativeHandle(), JitHelpers.GetStringHandleOnStack(ref name));
561             return name;
562         }
563
564         [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
565         private static extern AssemblyHashAlgorithm GetHashAlgorithm(RuntimeAssembly assembly);
566
567         private AssemblyHashAlgorithm GetHashAlgorithm()
568         {
569             return GetHashAlgorithm(GetNativeHandle());
570         }
571
572         [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
573         private static extern AssemblyNameFlags GetFlags(RuntimeAssembly assembly);
574
575         private AssemblyNameFlags GetFlags()
576         {
577             return GetFlags(GetNativeHandle());
578         }
579
580         [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
581         private static extern void GetPublicKey(RuntimeAssembly assembly, ObjectHandleOnStack retPublicKey);
582
583         internal byte[] GetPublicKey()
584         {
585             byte[] publicKey = null;
586             GetPublicKey(GetNativeHandle(), JitHelpers.GetObjectHandleOnStack(ref publicKey));
587             return publicKey;
588         }
589
590         // This method is called by the VM.
591         private RuntimeModule OnModuleResolveEvent(string moduleName)
592         {
593             ModuleResolveEventHandler moduleResolve = _ModuleResolve;
594             if (moduleResolve == null)
595                 return null;
596
597             foreach (ModuleResolveEventHandler handler in moduleResolve.GetInvocationList())
598             {
599                 RuntimeModule ret = (RuntimeModule)handler(this, new ResolveEventArgs(moduleName, this));
600                 if (ret != null)
601                     return ret;
602             }
603
604             return null;
605         }
606
607         public override Assembly GetSatelliteAssembly(CultureInfo culture)
608         {
609             return GetSatelliteAssembly(culture, null);
610         }
611
612         // Useful for binding to a very specific version of a satellite assembly
613         public override Assembly GetSatelliteAssembly(CultureInfo culture, Version version)
614         {
615             if (culture == null)
616                 throw new ArgumentNullException(nameof(culture));
617
618             return InternalGetSatelliteAssembly(culture, version, true);
619         }
620
621         [System.Security.DynamicSecurityMethod] // Methods containing StackCrawlMark local var has to be marked DynamicSecurityMethod
622         internal Assembly InternalGetSatelliteAssembly(CultureInfo culture,
623                                                        Version version,
624                                                        bool throwOnFileNotFound)
625         {
626             AssemblyName an = new AssemblyName();
627
628             an.SetPublicKey(GetPublicKey());
629             an.Flags = GetFlags() | AssemblyNameFlags.PublicKey;
630
631             if (version == null)
632                 an.Version = GetVersion();
633             else
634                 an.Version = version;
635
636             an.CultureInfo = culture;
637             an.Name = GetSimpleName() + ".resources";
638
639             // This stack crawl mark is never used because the requesting assembly is explicitly specified,
640             // so the value could be anything.
641             StackCrawlMark unused = default;
642             RuntimeAssembly retAssembly = nLoad(an, null, this, ref unused, throwOnFileNotFound, IntPtr.Zero);
643
644             if (retAssembly == this)
645             {
646                 retAssembly = null;
647             }
648
649             if (retAssembly == null && throwOnFileNotFound)
650             {
651                 throw new FileNotFoundException(string.Format(culture, SR.IO_FileNotFound_FileName, an.Name));
652             }
653
654             return retAssembly;
655         }
656
657         [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
658         private static extern void GetModules(RuntimeAssembly assembly,
659                                               bool loadIfNotFound,
660                                               bool getResourceModules,
661                                               ObjectHandleOnStack retModuleHandles);
662
663         private RuntimeModule[] GetModulesInternal(bool loadIfNotFound,
664                                      bool getResourceModules)
665         {
666             RuntimeModule[] modules = null;
667             GetModules(GetNativeHandle(), loadIfNotFound, getResourceModules, JitHelpers.GetObjectHandleOnStack(ref modules));
668             return modules;
669         }
670
671         public override Module[] GetModules(bool getResourceModules)
672         {
673             return GetModulesInternal(true, getResourceModules);
674         }
675
676         public override Module[] GetLoadedModules(bool getResourceModules)
677         {
678             return GetModulesInternal(false, getResourceModules);
679         }
680
681         [MethodImplAttribute(MethodImplOptions.InternalCall)]
682         internal static extern RuntimeModule GetManifestModule(RuntimeAssembly assembly);
683
684         [MethodImplAttribute(MethodImplOptions.InternalCall)]
685         internal static extern int GetToken(RuntimeAssembly assembly);
686
687         public sealed override Type[] GetForwardedTypes()
688         {
689             List<Type> types = new List<Type>();
690             List<Exception> exceptions = new List<Exception>();
691
692             MetadataImport scope = GetManifestModule(GetNativeHandle()).MetadataImport;
693             scope.Enum(MetadataTokenType.ExportedType, 0, out MetadataEnumResult enumResult);
694             for (int i = 0; i < enumResult.Length; i++)
695             {
696                 MetadataToken mdtExternalType = enumResult[i];
697                 Type type = null;
698                 Exception exception = null;
699                 ObjectHandleOnStack pType = JitHelpers.GetObjectHandleOnStack(ref type);
700                 try
701                 {
702                     GetForwardedType(this, mdtExternalType, pType);
703                     if (type == null)
704                         continue;  // mdtExternalType was not a forwarder entry.
705                 }
706                 catch (Exception e)
707                 {
708                     type = null;
709                     exception = e;
710                 }
711
712                 Debug.Assert((type != null) != (exception != null)); // Exactly one of these must be non-null.
713
714                 if (type != null)
715                 {
716                     types.Add(type);
717                     AddPublicNestedTypes(type, types, exceptions);
718                 }
719                 else
720                 {
721                     exceptions.Add(exception);
722                 }
723             }
724
725             if (exceptions.Count != 0)
726             {
727                 int numTypes = types.Count;
728                 int numExceptions = exceptions.Count;
729                 types.AddRange(new Type[numExceptions]); // add one null Type for each exception.
730                 exceptions.InsertRange(0, new Exception[numTypes]); // align the Exceptions with the null Types.
731                 throw new ReflectionTypeLoadException(types.ToArray(), exceptions.ToArray());
732             }
733
734             return types.ToArray();
735         }
736
737         private static void AddPublicNestedTypes(Type type, List<Type> types, List<Exception> exceptions)
738         {
739             Type[] nestedTypes;
740             try
741             {
742                 nestedTypes = type.GetNestedTypes(BindingFlags.Public);
743             }
744             catch (Exception e)
745             {
746                 exceptions.Add(e);
747                 return;
748             }
749             foreach (Type nestedType in nestedTypes)
750             {
751                 types.Add(nestedType);
752                 AddPublicNestedTypes(nestedType, types, exceptions);
753             }
754         }
755
756         [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
757         private static extern void GetForwardedType(RuntimeAssembly assembly, MetadataToken mdtExternalType, ObjectHandleOnStack type);
758     }
759 }