private static MethodDefinition CreateGetResourceAssemblyStreamOrNullMethod(FieldReference dictionaryField, TypeReference moduleType, MetadataHelper helper) { // C#: // private static Stream GetResourceAssemblyStreamOrNull(AssemblyName assemblyName) // { // return EmbeddedResourceNamesByAssemblyName.TryGetValue(assemblyName.Name, out var resourceName) // ? typeof(Module).Assembly.GetManifestResourceStream(resourceName) // : null; // } var method = helper.DefineMethod( "GetResourceAssemblyStreamOrNull", MethodAttributes.Private | MethodAttributes.Static | MethodAttributes.HideBySig, returnType: "class System.IO.Stream", parameterTypes: new[] { "class System.Reflection.AssemblyName" }); var programBuilder = new ProgramBuilder(method.Body, helper); var resourceNameVariable = programBuilder.CreateLocal("string"); var successLabel = new Label(); programBuilder.Append( Ldsfld(dictionaryField), Ldarg(0), Callvirt("instance string System.Reflection.AssemblyName::get_Name()"), Ldloca(resourceNameVariable), Callvirt("instance bool class System.Collections.Generic.Dictionary`2<string, string>::TryGetValue(!0, !1&)"), Brtrue_S(successLabel), Ldnull(), Ret(), successLabel, Ldtoken(moduleType), Call("class System.Type System.Type::GetTypeFromHandle(valuetype System.RuntimeTypeHandle)"), Callvirt("instance class System.Reflection.Assembly System.Type::get_Assembly()"), Ldloc(resourceNameVariable), Callvirt("instance class System.IO.Stream System.Reflection.Assembly::GetManifestResourceStream(string)"), Ret()); programBuilder.Emit(); return(method); }
private static MethodDefinition CreateModuleInitializer( FieldReference dictionaryField, IReadOnlyDictionary <string, string> embeddedResourceNamesByAssemblyName, MethodReference assemblyResolveHandler, bool isAppDomainHandler, MetadataHelper helper) { // C#: // static <Module>() // { // EmbeddedResourceNamesByAssemblyName = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase) // { // ["Some.Assembly.Name"] = @"Some\Embedded\Resource\Path", // ["etc"] = "etc" // }; // // AppDomain.CurrentDomain.AssemblyResolve += OnAssemblyResolve; // } var moduleInitializer = helper.DefineMethod( ".cctor", MethodAttributes.Static | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName, returnType: "void"); var program = new ProgramBuilder(moduleInitializer.Body, helper); // Initialize dictionary field program.Append( Call("class System.StringComparer System.StringComparer::get_OrdinalIgnoreCase()"), Newobj(@"instance void class System.Collections.Generic.Dictionary`2<string, string>::.ctor( class System.Collections.Generic.IEqualityComparer`1<!0>)")); foreach (var entry in embeddedResourceNamesByAssemblyName) { program.Append( Dup(), Ldstr(entry.Key), Ldstr(entry.Value), Callvirt("instance void class System.Collections.Generic.Dictionary`2<string, string>::set_Item(!0, !1)")); } program.Append( Stsfld(dictionaryField)); if (isAppDomainHandler) { program.Append( Call("class System.AppDomain System.AppDomain::get_CurrentDomain()"), Ldnull(), Ldftn(assemblyResolveHandler), Newobj("instance void System.ResolveEventHandler::.ctor(object, native int)"), Callvirt("instance void System.AppDomain::add_AssemblyResolve(class System.ResolveEventHandler)")); } else { program.Append( Call(@"class [System.Runtime.Loader]System.Runtime.Loader.AssemblyLoadContext class [System.Runtime.Loader]System.Runtime.Loader.AssemblyLoadContext::get_Default()"), Ldnull(), Ldftn(assemblyResolveHandler), Newobj(@"instance void class System.Func`3< class [System.Runtime.Loader]System.Runtime.Loader.AssemblyLoadContext, class System.Reflection.AssemblyName, class System.Reflection.Assembly>::.ctor(object, native int)"), Callvirt(@"instance void class [System.Runtime.Loader]System.Runtime.Loader.AssemblyLoadContext::add_Resolving( class System.Func`3< class [System.Runtime.Loader]System.Runtime.Loader.AssemblyLoadContext, class System.Reflection.AssemblyName, class System.Reflection.Assembly>)")); } program.Append( Ret()); program.Emit(); return(moduleInitializer); }
private static MethodDefinition CreateAppDomainAssemblyResolveHandler(MethodReference getResourceAssemblyStreamOrNullMethod, MetadataHelper helper) { // C#: // private static Assembly OnAssemblyResolve(object sender, ResolveEventArgs e) // { // using (var stream = GetResourceAssemblyStreamOrNull(new AssemblyName(e.Name))) // { // if (stream is null) return null; // // using (var buffer = new MemoryStream(capacity: checked((int)stream.Length))) // { // stream.CopyTo(buffer); // return Assembly.Load(buffer.ToArray()); // } // } // } var method = helper.DefineMethod( "OnAssemblyResolve", MethodAttributes.Private | MethodAttributes.Static | MethodAttributes.HideBySig, returnType: "class System.Reflection.Assembly", parameterTypes: new[] { "object", "class System.ResolveEventArgs" }); var program = new ProgramBuilder(method.Body, helper); var streamLocal = program.CreateLocal("class System.IO.Stream"); var assemblyLocal = program.CreateLocal("class System.Reflection.Assembly"); var bufferLocal = program.CreateLocal("class System.IO.MemoryStream"); var skipReturningNullLabel = new Label(); var returnAssemblyLabel = new Label(); var skipInnerDispose = new Label(); var skipOuterDispose = new Label(); program.Append( Ldarg(1), Callvirt("instance string System.ResolveEventArgs::get_Name()"), Newobj("instance void System.Reflection.AssemblyName::.ctor(string)"), Call(getResourceAssemblyStreamOrNullMethod), Stloc(streamLocal), Try( Ldloc(streamLocal), Brtrue_S(skipReturningNullLabel), Ldnull(), Stloc(assemblyLocal), Leave_S(returnAssemblyLabel), skipReturningNullLabel, Ldloc(streamLocal), Callvirt("instance int64 System.IO.Stream::get_Length()"), Conv_Ovf_I4(), Newobj("instance void System.IO.MemoryStream::.ctor(int32)"), Stloc(bufferLocal), Try( Ldloc(streamLocal), Ldloc(bufferLocal), Callvirt("instance void System.IO.Stream::CopyTo(class System.IO.Stream)"), Ldloc(bufferLocal), Callvirt("instance unsigned int8[] System.IO.MemoryStream::ToArray()"), Call("class System.Reflection.Assembly System.Reflection.Assembly::Load(unsigned int8[])"), Stloc(assemblyLocal), Leave_S(returnAssemblyLabel)) .Finally( Ldloc(bufferLocal), Brfalse_S(skipInnerDispose), Ldloc(bufferLocal), Callvirt("instance void System.IDisposable::Dispose()"), skipInnerDispose, Endfinally())) .Finally( Ldloc(streamLocal), Brfalse_S(skipOuterDispose), Ldloc(streamLocal), Callvirt("instance void System.IDisposable::Dispose()"), skipOuterDispose, Endfinally()), returnAssemblyLabel, Ldloc(assemblyLocal), Ret()); program.Emit(); return(method); }
private static MethodDefinition CreateAssemblyLoadContextAssemblyResolveHandler(MethodReference getResourceAssemblyStreamOrNullMethod, MetadataHelper helper) { // C#: // private static Assembly Default_Resolving(AssemblyLoadContext context, AssemblyName name) // { // using (var stream = GetResourceAssemblyStreamOrNull(name)) // { // if (stream is null) return null; // return context.LoadFromStream(stream); // } // } var method = helper.DefineMethod( "OnAssemblyResolve", MethodAttributes.Private | MethodAttributes.Static | MethodAttributes.HideBySig, returnType: "class System.Reflection.Assembly", parameterTypes: new[] { "object", "class System.ResolveEventArgs" }); var program = new ProgramBuilder(method.Body, helper); var streamLocal = program.CreateLocal("class System.IO.Stream"); var assemblyLocal = program.CreateLocal("class System.Reflection.Assembly"); var skipReturningNullLabel = new Label(); var returnAssemblyLabel = new Label(); var skipDispose = new Label(); program.Append( Ldarg(1), Call(getResourceAssemblyStreamOrNullMethod), Stloc(streamLocal), Try( Ldloc(streamLocal), Brtrue_S(skipReturningNullLabel), Ldnull(), Stloc(assemblyLocal), Leave_S(returnAssemblyLabel), skipReturningNullLabel, Ldarg(0), Ldloc(streamLocal), Callvirt(@"instance class System.Reflection.Assembly class [System.Runtime.Loader]System.Runtime.Loader.AssemblyLoadContext::LoadFromStream(class System.IO.Stream)"), Stloc(assemblyLocal), Leave_S(returnAssemblyLabel)) .Finally( Ldloc(streamLocal), Brfalse_S(skipDispose), Ldloc(streamLocal), Callvirt("instance void System.IDisposable::Dispose()"), skipDispose, Endfinally()), returnAssemblyLabel, Ldloc(assemblyLocal), Ret()); program.Emit(); return(method); }