public static Task <int> ExecuteAsync(string[] args) { var enableTrace = Environment.GetEnvironmentVariable("KRE_TRACE") == "1"; #if ASPNET50 // TODO: Make this pluggable and not limited to the console logger if (enableTrace) { var listener = new ConsoleTraceListener(); Trace.Listeners.Add(listener); Trace.AutoFlush = true; } #endif var app = new CommandLineApplication(throwOnUnexpectedArg: false); app.Name = "klr"; var optionLib = app.Option("--lib <LIB_PATHS>", "Paths used for library look-up", CommandOptionType.MultipleValue); app.HelpOption("-?|-h|--help"); app.VersionOption("--version", GetVersion()); app.Execute(args); // Help information was already shown because help option was specified if (app.IsShowingInformation) { return(Task.FromResult(0)); } // Show help information if no subcommand/option was specified if (!app.IsShowingInformation && !app.RemainingArguments.Any()) { app.ShowHelp(); return(Task.FromResult(2)); } // Resolve the lib paths string[] searchPaths = ResolveSearchPaths(optionLib.Values, app.RemainingArguments); Func <string, Assembly> loader = _ => null; Func <Stream, Assembly> loadStream = _ => null; Func <string, Assembly> loadFile = _ => null; Func <AssemblyName, Assembly> loaderCallback = assemblyName => { string name = assemblyName.Name; // Skip resource assemblies if (name.EndsWith(".resources")) { return(null); } // If the assembly was already loaded use it Assembly assembly; if (_assemblyCache.TryGetValue(name, out assembly)) { return(assembly); } var loadLock = _assemblyLoadLocks.GetOrAdd(name, new object()); try { // Concurrently loading the assembly might result in two distinct instances of the same assembly // being loaded. This was observed when loading via Assembly.LoadStream. Prevent this by locking on the name. lock (loadLock) { if (_assemblyCache.TryGetValue(name, out assembly)) { // This would succeed in case the thread was previously waiting on the lock when assembly // load was in progress return(assembly); } assembly = loader(name) ?? ResolveHostAssembly(loadFile, searchPaths, name); if (assembly != null) { #if ASPNETCORE50 ExtractAssemblyNeutralInterfaces(assembly, loadStream); #endif _assemblyCache[name] = assembly; } } } finally { _assemblyLoadLocks.TryRemove(name, out loadLock); } return(assembly); }; #if ASPNETCORE50 var loaderImpl = new DelegateAssemblyLoadContext(loaderCallback); loadStream = assemblyStream => loaderImpl.LoadStream(assemblyStream, assemblySymbols: null); loadFile = path => loaderImpl.LoadFile(path); AssemblyLoadContext.InitializeDefaultContext(loaderImpl); if (loaderImpl.EnableMultiCoreJit()) { loaderImpl.StartMultiCoreJitProfile("startup.prof"); } #else var loaderImpl = new LoaderEngine(); loadStream = assemblyStream => loaderImpl.LoadStream(assemblyStream, assemblySymbols: null); loadFile = path => loaderImpl.LoadFile(path); ResolveEventHandler handler = (sender, a) => { // Special case for retargetable assemblies on desktop if (a.Name.EndsWith("Retargetable=Yes")) { return(Assembly.Load(a.Name)); } return(loaderCallback(new AssemblyName(a.Name))); }; AppDomain.CurrentDomain.AssemblyResolve += handler; AppDomain.CurrentDomain.AssemblyLoad += (object sender, AssemblyLoadEventArgs loadedArgs) => { // Skip loading interfaces for dynamic assemblies if (loadedArgs.LoadedAssembly.IsDynamic) { return; } ExtractAssemblyNeutralInterfaces(loadedArgs.LoadedAssembly, loadStream); }; #endif try { var assembly = Assembly.Load(new AssemblyName("klr.host")); // Loader impl // The following code is doing: // var loaderContainer = new klr.host.LoaderContainer(); // var assemblyNeutralInterfaceCache = new klr.host.AssemblyNeutralInterfaceCache(_assemblyNeutralInterfaces); // var cachedAssemblyLoader = new klr.host.CachedAssemblyLoader(_assemblyCache); // var libLoader = new klr.host.PathBasedAssemblyLoader(searchPaths); // loaderContainer.AddLoader(cachedAssemblyLoader); // loaderContainer.AddLoader(libLoader); // var bootstrapper = new klr.host.Bootstrapper(loaderContainer, assemblyNeutralInterfaceCache); // bootstrapper.Main(bootstrapperArgs); var loaderContainerType = assembly.GetType("klr.host.LoaderContainer"); var assemblyNeutralInterfaceCacheType = assembly.GetType("klr.host.AssemblyNeutralInterfaceCache"); var cachedAssemblyLoaderType = assembly.GetType("klr.host.CachedAssemblyLoader"); var pathBasedLoaderType = assembly.GetType("klr.host.PathBasedAssemblyLoader"); var loaderContainer = Activator.CreateInstance(loaderContainerType); var assemblyNeutralInterfaceCache = Activator.CreateInstance(assemblyNeutralInterfaceCacheType, new object[] { _assemblyNeutralInterfaces }); var cachedAssemblyLoader = Activator.CreateInstance(cachedAssemblyLoaderType, new object[] { _assemblyCache }); var libLoader = Activator.CreateInstance(pathBasedLoaderType, new object[] { searchPaths }); MethodInfo addLoaderMethodInfo = loaderContainerType.GetTypeInfo().GetDeclaredMethod("AddLoader"); var disposable1 = (IDisposable)addLoaderMethodInfo.Invoke(loaderContainer, new[] { cachedAssemblyLoader }); var disposable2 = (IDisposable)addLoaderMethodInfo.Invoke(loaderContainer, new[] { libLoader }); var disposable = new CombinedDisposable(disposable1, disposable2); var loaderContainerLoadMethodInfo = loaderContainerType.GetTypeInfo().GetDeclaredMethod("Load"); loader = (Func <string, Assembly>)loaderContainerLoadMethodInfo.CreateDelegate(typeof(Func <string, Assembly>), loaderContainer); var bootstrapperType = assembly.GetType("klr.host.Bootstrapper"); var mainMethod = bootstrapperType.GetTypeInfo().GetDeclaredMethod("Main"); var bootstrapper = Activator.CreateInstance(bootstrapperType, loaderContainer, assemblyNeutralInterfaceCache); try { var bootstrapperArgs = new object[] { app.RemainingArguments.ToArray() }; var task = (Task <int>)mainMethod.Invoke(bootstrapper, bootstrapperArgs); return(task.ContinueWith(async(t, state) => { // Dispose the host ((IDisposable)state).Dispose(); #if ASPNET50 AppDomain.CurrentDomain.AssemblyResolve -= handler; #endif return await t; }, disposable).Unwrap()); } catch { // If we throw synchronously then dispose then rethtrow disposable.Dispose(); throw; } } catch { #if ASPNET50 AppDomain.CurrentDomain.AssemblyResolve -= handler; #endif throw; } }
public static Task<int> ExecuteAsync(string[] args) { var enableTrace = Environment.GetEnvironmentVariable("KRE_TRACE") == "1"; #if NET45 // TODO: Make this pluggable and not limited to the console logger if (enableTrace) { var listener = new ConsoleTraceListener(); Trace.Listeners.Add(listener); Trace.AutoFlush = true; } #endif var app = new CommandLineApplication(throwOnUnexpectedArg: false); app.Name = "klr"; var optionLib = app.Option("--lib <LIB_PATHS>", "Paths used for library look-up", CommandOptionType.MultipleValue); app.HelpOption("-?|-h|--help"); app.VersionOption("--version", GetVersion()); app.Execute(args); if (!app.IsShowingInformation && !app.RemainingArguments.Any()) { app.ShowHelp(); } if (app.IsShowingInformation) { return Task.FromResult(0); } // Resolve the lib paths string[] searchPaths = ResolveSearchPaths(optionLib.Values, app.RemainingArguments); Func<string, Assembly> loader = _ => null; Func<Stream, Assembly> loadStream = _ => null; Func<string, Assembly> loadFile = _ => null; Func<AssemblyName, Assembly> loaderCallback = assemblyName => { string name = assemblyName.Name; // Skip resource assemblies if (name.EndsWith(".resources")) { return null; } // If the assembly was already loaded use it Assembly assembly; if (_assemblyCache.TryGetValue(name, out assembly)) { return assembly; } var loadLock = _assemblyLoadLocks.GetOrAdd(name, new object()); try { // Concurrently loading the assembly might result in two distinct instances of the same assembly // being loaded. This was observed when loading via Assembly.LoadStream. Prevent this by locking on the name. lock (loadLock) { if (_assemblyCache.TryGetValue(name, out assembly)) { // This would succeed in case the thread was previously waiting on the lock when assembly // load was in progress return assembly; } assembly = loader(name) ?? ResolveHostAssembly(loadFile, searchPaths, name); if (assembly != null) { #if K10 ExtractAssemblyNeutralInterfaces(assembly, loadStream); #endif _assemblyCache[name] = assembly; } } } finally { _assemblyLoadLocks.TryRemove(name, out loadLock); } return assembly; }; #if K10 var loaderImpl = new DelegateAssemblyLoadContext(loaderCallback); loadStream = assemblyStream => loaderImpl.LoadStream(assemblyStream, pdbStream: null); loadFile = path => loaderImpl.LoadFile(path); AssemblyLoadContext.InitializeDefaultContext(loaderImpl); if (loaderImpl.EnableMultiCoreJit()) { loaderImpl.StartMultiCoreJitProfile("startup.prof"); } #else var loaderImpl = new LoaderEngine(); loadStream = assemblyStream => loaderImpl.LoadStream(assemblyStream, pdbStream: null); loadFile = path => loaderImpl.LoadFile(path); ResolveEventHandler handler = (sender, a) => { // Special case for retargetable assemblies on desktop if (a.Name.EndsWith("Retargetable=Yes")) { return Assembly.Load(a.Name); } return loaderCallback(new AssemblyName(a.Name)); }; AppDomain.CurrentDomain.AssemblyResolve += handler; AppDomain.CurrentDomain.AssemblyLoad += (object sender, AssemblyLoadEventArgs loadedArgs) => { // Skip loading interfaces for dynamic assemblies if (loadedArgs.LoadedAssembly.IsDynamic) { return; } ExtractAssemblyNeutralInterfaces(loadedArgs.LoadedAssembly, loadStream); }; #endif try { var assembly = Assembly.Load(new AssemblyName("klr.host")); // Loader impl // var loaderEngine = new DefaultLoaderEngine(loaderImpl); var loaderEngineType = assembly.GetType("klr.host.DefaultLoaderEngine"); var loaderEngine = Activator.CreateInstance(loaderEngineType, loaderImpl); // The following code is doing: // var loaderContainer = new klr.host.LoaderContainer(); // var libLoader = new klr.host.PathBasedAssemblyLoader(loaderEngine, searchPaths); // loaderContainer.AddLoader(libLoader); // var bootstrapper = new klr.host.Bootstrapper(loaderContainer, loaderEngine); // bootstrapper.Main(bootstrapperArgs); var loaderContainerType = assembly.GetType("klr.host.LoaderContainer"); var pathBasedLoaderType = assembly.GetType("klr.host.PathBasedAssemblyLoader"); var loaderContainer = Activator.CreateInstance(loaderContainerType); var libLoader = Activator.CreateInstance(pathBasedLoaderType, new object[] { loaderEngine, searchPaths }); MethodInfo addLoaderMethodInfo = loaderContainerType.GetTypeInfo().GetDeclaredMethod("AddLoader"); var disposable = (IDisposable)addLoaderMethodInfo.Invoke(loaderContainer, new[] { libLoader }); var loaderContainerLoadMethodInfo = loaderContainerType.GetTypeInfo().GetDeclaredMethod("Load"); loader = (Func<string, Assembly>)loaderContainerLoadMethodInfo.CreateDelegate(typeof(Func<string, Assembly>), loaderContainer); var bootstrapperType = assembly.GetType("klr.host.Bootstrapper"); var mainMethod = bootstrapperType.GetTypeInfo().GetDeclaredMethod("Main"); var bootstrapper = Activator.CreateInstance(bootstrapperType, loaderContainer, loaderEngine); try { var bootstrapperArgs = new object[] { app.RemainingArguments.ToArray() }; var task = (Task<int>)mainMethod.Invoke(bootstrapper, bootstrapperArgs); return task.ContinueWith(async (t, state) => { // Dispose the host ((IDisposable)state).Dispose(); #if NET45 AppDomain.CurrentDomain.AssemblyResolve -= handler; #endif return await t; }, disposable).Unwrap(); } catch { // If we throw synchronously then dispose then rethtrow disposable.Dispose(); throw; } } catch { #if NET45 AppDomain.CurrentDomain.AssemblyResolve -= handler; #endif throw; } }