Ejemplo n.º 1
0
        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;
            }
        }
Ejemplo n.º 2
0
        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;
            }
        }