diff --git a/Directory.Build.targets b/Directory.Build.targets index 245782faf0..d6092ffb9c 100644 --- a/Directory.Build.targets +++ b/Directory.Build.targets @@ -29,4 +29,55 @@ + + + false + none + all + false + false + %(SetTargetFramework) + %(TargetPath) + %(Properties) + + + + + + + <_PublishProjectReference Include="@(ProjectReferenceWithConfiguration)" Condition="'%(ProjectReferenceWithConfiguration.PublishTargetPath)' != ''"> + $([System.IO.Path]::GetFileNameWithoutExtension('%(Identity)')) + $([MSBuild]::EnsureTrailingSlash(%(ProjectReferenceWithConfiguration.PublishTargetPath))) + + + + + + + + + + + + + + PreserveNewest + %(_PublishProjectReferenceOutputItems.PublishTargetPath)\%(_PublishProjectReferenceOutputItems.TargetPath) + + + + + + + $(GetPublishProjectReferenceCopyToOutputDirectoryItemsDependsOn); + GetPublishProjectReferences; + GetPublishProjectReferenceOutputItems; + _GetPublishProjectReferenceCopyToOutputDirectoryItems; + + + + + + + \ No newline at end of file diff --git a/IKVM.Java/IKVM.Java.targets b/IKVM.Java/IKVM.Java.targets index c3cc5c0cc8..7e3a3efdac 100644 --- a/IKVM.Java/IKVM.Java.targets +++ b/IKVM.Java/IKVM.Java.targets @@ -279,8 +279,8 @@ - - + + @@ -725,7 +725,6 @@ <_IkvmcArgs Include="-strictfinalfieldsemantics" /> <_IkvmcArgs Include="-removeassertions" /> <_IkvmcArgs Include="-target:library" /> - <_IkvmcArgs Include="-nostdlib" /> <_IkvmcArgs Include="-sharedclassloader" /> <_IkvmcArgs Include="-nowarn:110" /> <_IkvmcArgs Include="-w4" /> diff --git a/IKVM.Reflection/Fusion.cs b/IKVM.Reflection/Fusion.cs index 69a00b9f4f..5b0979ad2f 100644 --- a/IKVM.Reflection/Fusion.cs +++ b/IKVM.Reflection/Fusion.cs @@ -98,7 +98,7 @@ internal static bool CompareAssemblyIdentityPure(string assemblyIdentity1, bool throw new ArgumentException(); } - if (name2.Name != null && name2.Name.Equals(Universe.CoreLibName, StringComparison.OrdinalIgnoreCase)) + if (name2.Name != null && name2.Name.Equals(Universe.StdLibName, StringComparison.OrdinalIgnoreCase)) { if (name1.Name != null && name1.Name.Equals(name2.Name, StringComparison.OrdinalIgnoreCase)) { diff --git a/IKVM.Reflection/Universe.cs b/IKVM.Reflection/Universe.cs index e8ec62e202..fb82836be3 100644 --- a/IKVM.Reflection/Universe.cs +++ b/IKVM.Reflection/Universe.cs @@ -24,13 +24,17 @@ Jeroen Frijters using System; using System.Collections.Generic; using System.IO; -using System.Runtime.InteropServices; +using System.Linq; using System.Security; using System.Text; using IKVM.Reflection.Emit; using IKVM.Reflection.Reader; +#if NETCOREAPP3_1_OR_GREATER +using Microsoft.Extensions.DependencyModel; +#endif + namespace IKVM.Reflection { @@ -145,44 +149,13 @@ public enum UniverseOptions public sealed class Universe : IDisposable { -#if NETCOREAPP3_1 +#if NETCOREAPP3_1_OR_GREATER - public static readonly string CoreLibName = "netstandard"; - - public static string ReferenceAssembliesDirectory - { - get - { - return BuildRefDirFrom(System.Runtime.InteropServices.RuntimeEnvironment.GetRuntimeDirectory()); - } - } - - private static string BuildRefDirFrom(string runtimeDir) - { - // transform a thing like - // C:\Program Files\dotnet\shared\Microsoft.NETCore.App\3.1.7 - // to - // C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\3.1.0\ref\netcoreapp3.1 - - var parts = runtimeDir.Split(Path.DirectorySeparatorChar); - var n = string.IsNullOrEmpty(parts[parts.Length - 1]) ? parts.Length - 2 : parts.Length - 1; - var versionDir = parts[n--]; - var frameworkDir = parts[n--]; - var newParts = new string[n + 5]; - Array.Copy(parts, newParts, n); - var suffixParts = new string[] { "packs", frameworkDir + ".Ref", "3.1.0", "ref", "netcoreapp3.1" }; - Array.Copy(suffixParts, 0, newParts, n, suffixParts.Length); - var dir = Path.Combine(newParts); - if (!Directory.Exists(dir)) - { - throw new FileNotFoundException("Reference assemblies directory: " + dir); - } - return dir; - } + public static readonly string StdLibName = "netstandard"; #elif NETFRAMEWORK || MONO - public static readonly string CoreLibName = "mscorlib"; + public static readonly string StdLibName = "mscorlib"; #endif @@ -286,7 +259,7 @@ private static bool GetUseNativeFusion() internal Assembly Mscorlib { - get { return Load(CoreLibName); } + get { return Load(StdLibName); } } private Type ImportMscorlibType(string ns, string name) @@ -567,7 +540,7 @@ internal Type System_Security_Permissions_SecurityAction internal bool HasMscorlib { - get { return GetLoadedAssembly(CoreLibName) != null; } + get { return GetLoadedAssembly(StdLibName) != null; } } public event ResolveEventHandler AssemblyResolve @@ -782,108 +755,41 @@ private Assembly GetDynamicAssembly(string refname) return null; } - public Assembly Load(string refname) + public Assembly Load(string refName) { - return Load(refname, null, true); + return Load(refName, null, true); } - internal Assembly Load(string refname, Module requestingModule, bool throwOnError) + internal Assembly Load(string refName, Module requestingModule, bool throwOnError) { - Assembly asm = GetLoadedAssembly(refname); - if (asm != null) - { - return asm; - } - if (resolvers.Count == 0) - { - asm = DefaultResolver(refname, throwOnError); - } - else - { - ResolveEventArgs args = new ResolveEventArgs(refname, requestingModule == null ? null : requestingModule.Assembly); - foreach (ResolveEventHandler evt in resolvers) - { - asm = evt(this, args); - if (asm != null) - { - break; - } - } - if (asm == null) - { - asm = GetDynamicAssembly(refname); - } - } - if (asm != null) - { - string defname = asm.FullName; - if (refname != defname) - { - assembliesByName.Add(refname, asm); - } - return asm; - } - if (throwOnError) - { - throw new FileNotFoundException(refname); - } - return null; - } + // if the assembly is already loaded, just return that + var assembly = GetLoadedAssembly(refName); + if (assembly != null) + return assembly; - private Assembly DefaultResolver(string refname, bool throwOnError) - { - Assembly asm = GetDynamicAssembly(refname); - if (asm != null) - { - return asm; - } + // dispatch a resolve event to the resolvers + var arg = new ResolveEventArgs(refName, requestingModule?.Assembly); + assembly = resolvers.Select(i => i(this, arg)).FirstOrDefault(i => i != null); + + // still not found, maybe it's a dynamic assembly? + if (assembly == null) + assembly = GetDynamicAssembly(refName); -#if NETCOREAPP3_1 - string filepath = Path.Combine(ReferenceAssembliesDirectory, GetSimpleAssemblyName(refname) + ".dll"); - if (File.Exists(filepath)) + // we did find the assembly + if (assembly != null) { - using (RawModule module = OpenRawModule(filepath)) - { - AssemblyComparisonResult result; - if (module.IsManifestModule && CompareAssemblyIdentity(refname, false, module.GetAssemblyName().FullName, false, out result)) - { - return LoadAssembly(module); - } - } + // associate the assembly with our set by name + var defName = assembly.FullName; + if (refName != defName) + assembliesByName.Add(refName, assembly); + + return assembly; } + + if (throwOnError) + throw new FileNotFoundException(refName); + return null; -#else - string fileName; - if (throwOnError) - { - try - { - fileName = System.Reflection.Assembly.ReflectionOnlyLoad(refname).Location; - } - catch (System.BadImageFormatException x) - { - throw new BadImageFormatException(x.Message, x); - } - } - else - { - try - { - fileName = System.Reflection.Assembly.ReflectionOnlyLoad(refname).Location; - } - catch (System.BadImageFormatException x) - { - throw new BadImageFormatException(x.Message, x); - } - catch (FileNotFoundException) - { - // we intentionally only swallow the FileNotFoundException, if the file exists but isn't a valid assembly, - // we should throw an exception - return null; - } - } - return LoadFile(fileName); -#endif } public Type GetType(string assemblyQualifiedTypeName) diff --git a/IKVM.Runtime/ClassFile.cs b/IKVM.Runtime/ClassFile.cs index 9752fe8301..016591943c 100644 --- a/IKVM.Runtime/ClassFile.cs +++ b/IKVM.Runtime/ClassFile.cs @@ -445,7 +445,7 @@ internal ClassFile(byte[] buf, int offset, int length, string inputClassName, Cl GetConstantPoolClass(class_index), null, null - }; + }; } else { @@ -767,16 +767,16 @@ private static object ReadAnnotationElementValue(BigEndianBinaryReader rdr, Clas ushort type_name_index = rdr.ReadUInt16(); ushort const_name_index = rdr.ReadUInt16(); return new object[] { - AnnotationDefaultAttribute.TAG_ENUM, - classFile.GetConstantPoolUtf8String(utf8_cp, type_name_index), - classFile.GetConstantPoolUtf8String(utf8_cp, const_name_index) - }; + AnnotationDefaultAttribute.TAG_ENUM, + classFile.GetConstantPoolUtf8String(utf8_cp, type_name_index), + classFile.GetConstantPoolUtf8String(utf8_cp, const_name_index) + }; } case (byte)'c': return new object[] { - AnnotationDefaultAttribute.TAG_CLASS, - classFile.GetConstantPoolUtf8String(utf8_cp, rdr.ReadUInt16()) - }; + AnnotationDefaultAttribute.TAG_CLASS, + classFile.GetConstantPoolUtf8String(utf8_cp, rdr.ReadUInt16()) + }; case (byte)'@': return ReadAnnotation(rdr, classFile, utf8_cp); case (byte)'[': @@ -1241,15 +1241,12 @@ internal string SourcePath #endif } - internal object[] Annotations - { - get - { - return annotations; - } - } + /// + /// Gets the annotations set on the class. + /// + internal object[] Annotations => annotations; - internal string GenericSignature + internal string GenericSignature { get { diff --git a/IKVM.Runtime/ClassLoaderWrapper.cs b/IKVM.Runtime/ClassLoaderWrapper.cs index 2aaa05c359..1866d383da 100644 --- a/IKVM.Runtime/ClassLoaderWrapper.cs +++ b/IKVM.Runtime/ClassLoaderWrapper.cs @@ -1109,12 +1109,12 @@ internal static TypeWrapper GetWrapperFromType(Type type) } #if STUB_GENERATOR - if(type.__IsMissing || type.__ContainsMissingType) - { - wrapper = new UnloadableTypeWrapper("Missing/" + type.Assembly.FullName); - globalTypeToTypeWrapper.Add(type, wrapper); - return wrapper; - } + if (type.__IsMissing || type.__ContainsMissingType) + { + wrapper = new UnloadableTypeWrapper("Missing/" + type.Assembly.FullName); + globalTypeToTypeWrapper.Add(type, wrapper); + return wrapper; + } #endif string remapped; if (remappedTypes.TryGetValue(type, out remapped)) diff --git a/IKVM.Runtime/TypeWrapper.cs b/IKVM.Runtime/TypeWrapper.cs index cad4cbf722..d9b6aa946d 100644 --- a/IKVM.Runtime/TypeWrapper.cs +++ b/IKVM.Runtime/TypeWrapper.cs @@ -1627,10 +1627,16 @@ internal static string[] UnescapeInvalidSurrogates(string[] str) abstract class Annotation { + #if STATIC_COMPILER + internal static Annotation LoadAssemblyCustomAttribute(ClassLoaderWrapper loader, object[] def) { - Debug.Assert(def[0].Equals(AnnotationDefaultAttribute.TAG_ANNOTATION)); + if (def.Length == 0) + throw new ArgumentException("LoadAssemblyCustomAttribute did not receive any definitions."); + if (object.Equals(def[0], AnnotationDefaultAttribute.TAG_ANNOTATION) == false) + throw new InternalException("LoadAssemblyCustomAttribute did not receive AnnotationDefaultAttribute.TAG_ANNOTATION."); + string annotationClass = (string)def[1]; if (ClassFile.IsValidFieldSig(annotationClass)) { @@ -1640,10 +1646,12 @@ internal static Annotation LoadAssemblyCustomAttribute(ClassLoaderWrapper loader } catch (RetargetableJavaException) { + } } return null; } + #endif #if !STUB_GENERATOR @@ -2006,8 +2014,9 @@ internal abstract class TypeWrapper internal TypeWrapper(TypeFlags flags, Modifiers modifiers, string name) { Profiler.Count("TypeWrapper"); - // class name should be dotted or null for primitives - Debug.Assert(name == null || name.IndexOf('/') < 0, name); + + if (name != null && name.IndexOf('/') > -1) + throw new InternalException("Class name should be dotted, or null for primitives."); this.flags = flags; this.modifiers = modifiers; diff --git a/IKVM.Runtime/vm.cs b/IKVM.Runtime/vm.cs index 07b0d7131f..b946812671 100644 --- a/IKVM.Runtime/vm.cs +++ b/IKVM.Runtime/vm.cs @@ -39,461 +39,461 @@ Jeroen Frijters #if !STATIC_COMPILER && !STUB_GENERATOR namespace IKVM.Internal { - public static class Starter - { - public static void PrepareForSaveDebugImage() - { - JVM.IsSaveDebugImage = true; - } - - public static void SaveDebugImage() - { - DynamicClassLoader.SaveDebugImages(); - } + public static class Starter + { + public static void PrepareForSaveDebugImage() + { + JVM.IsSaveDebugImage = true; + } - public static bool ClassUnloading - { + public static void SaveDebugImage() + { + DynamicClassLoader.SaveDebugImages(); + } + + public static bool ClassUnloading + { #if CLASSGC get { return JVM.classUnloading; } set { JVM.classUnloading = value; } #else - get { return false; } - set { } + get { return false; } + set { } #endif - } + } - public static bool RelaxedVerification - { - get { return JVM.relaxedVerification; } - set { JVM.relaxedVerification = value; } - } + public static bool RelaxedVerification + { + get { return JVM.relaxedVerification; } + set { JVM.relaxedVerification = value; } + } - public static bool AllowNonVirtualCalls - { - get { return JVM.AllowNonVirtualCalls; } - set { JVM.AllowNonVirtualCalls = value; } - } - } + public static bool AllowNonVirtualCalls + { + get { return JVM.AllowNonVirtualCalls; } + set { JVM.AllowNonVirtualCalls = value; } + } + } } #endif // !STATIC_COMPILER && !STUB_GENERATOR namespace IKVM.Internal { - static class JVM - { - internal const string JarClassList = "--ikvm-classes--/"; + static class JVM + { + internal const string JarClassList = "--ikvm-classes--/"; #if STATIC_COMPILER - internal const bool FinishingForDebugSave = false; - internal const bool IsSaveDebugImage = false; + internal const bool FinishingForDebugSave = false; + internal const bool IsSaveDebugImage = false; #elif !STUB_GENERATOR - private static bool finishingForDebugSave; - private static int emitSymbols; - internal static bool IsSaveDebugImage; + private static bool finishingForDebugSave; + private static int emitSymbols; + internal static bool IsSaveDebugImage; #if CLASSGC internal static bool classUnloading = true; #endif #endif // STATIC_COMPILER - private static Assembly coreAssembly; + private static Assembly coreAssembly; #if !STUB_GENERATOR - internal static bool relaxedVerification = true; - internal static bool AllowNonVirtualCalls; - internal static readonly bool DisableEagerClassLoading = SafeGetEnvironmentVariable("IKVM_DISABLE_EAGER_CLASS_LOADING") != null; + internal static bool relaxedVerification = true; + internal static bool AllowNonVirtualCalls; + internal static readonly bool DisableEagerClassLoading = SafeGetEnvironmentVariable("IKVM_DISABLE_EAGER_CLASS_LOADING") != null; #endif #if !STATIC_COMPILER && !STUB_GENERATOR && !FIRST_PASS - static JVM() - { - if (SafeGetEnvironmentVariable("IKVM_SAVE_DYNAMIC_ASSEMBLIES") != null) - { - IsSaveDebugImage = true; - java.lang.Runtime.getRuntime().addShutdownHook(new java.lang.Thread(ikvm.runtime.Delegates.toRunnable(DynamicClassLoader.SaveDebugImages))); - } - } + static JVM() + { + if (SafeGetEnvironmentVariable("IKVM_SAVE_DYNAMIC_ASSEMBLIES") != null) + { + IsSaveDebugImage = true; + java.lang.Runtime.getRuntime().addShutdownHook(new java.lang.Thread(ikvm.runtime.Delegates.toRunnable(DynamicClassLoader.SaveDebugImages))); + } + } #endif - internal static Version SafeGetAssemblyVersion(System.Reflection.Assembly asm) - { - // Assembly.GetName().Version requires FileIOPermission, - // so we parse the FullName manually :-( - string name = asm.FullName; - int start = name.IndexOf(", Version="); - if(start >= 0) - { - start += 10; - int end = name.IndexOf(',', start); - if(end >= 0) - { - return new Version(name.Substring(start, end - start)); - } - } - return new Version(); - } + internal static Version SafeGetAssemblyVersion(System.Reflection.Assembly asm) + { + // Assembly.GetName().Version requires FileIOPermission, + // so we parse the FullName manually :-( + string name = asm.FullName; + int start = name.IndexOf(", Version="); + if (start >= 0) + { + start += 10; + int end = name.IndexOf(',', start); + if (end >= 0) + { + return new Version(name.Substring(start, end - start)); + } + } + return new Version(); + } - internal static string SafeGetEnvironmentVariable(string name) - { - try - { - return Environment.GetEnvironmentVariable(name); - } - catch(SecurityException) - { - return null; - } - } + internal static string SafeGetEnvironmentVariable(string name) + { + try + { + return Environment.GetEnvironmentVariable(name); + } + catch (SecurityException) + { + return null; + } + } - internal static Assembly CoreAssembly - { - get - { + internal static Assembly CoreAssembly + { + get + { #if !STATIC_COMPILER && !STUB_GENERATOR - if(coreAssembly == null) - { + if (coreAssembly == null) + { #if FIRST_PASS throw new InvalidOperationException("This version of IKVM.Runtime.dll was compiled with FIRST_PASS defined."); #else - coreAssembly = typeof(java.lang.Object).Assembly; + coreAssembly = typeof(java.lang.Object).Assembly; #endif - } + } #endif // !STATIC_COMPILER - return coreAssembly; - } - set - { - coreAssembly = value; - } - } + return coreAssembly; + } + set + { + coreAssembly = value; + } + } #if !STATIC_COMPILER && !STUB_GENERATOR - internal static bool FinishingForDebugSave - { - get - { - return finishingForDebugSave; - } - set - { - finishingForDebugSave = value; - } - } + internal static bool FinishingForDebugSave + { + get + { + return finishingForDebugSave; + } + set + { + finishingForDebugSave = value; + } + } - internal static bool EmitSymbols - { - get - { - if (emitSymbols == 0) - { - int state; - string debug = System.Configuration.ConfigurationManager.AppSettings["ikvm-emit-symbols"]; - if (debug == null) - { - state = Debugger.IsAttached ? 1 : 2; - } - else - { - state = debug.Equals("True", StringComparison.OrdinalIgnoreCase) ? 1 : 2; - } - // make sure we only set the value once, because it isn't allowed to changed as that could cause - // the compiler to try emitting symbols into a ModuleBuilder that doesn't accept them (and would - // throw an InvalidOperationException) - Interlocked.CompareExchange(ref emitSymbols, state, 0); - } - return emitSymbols == 1; - } - } + internal static bool EmitSymbols + { + get + { + if (emitSymbols == 0) + { + int state; + string debug = System.Configuration.ConfigurationManager.AppSettings["ikvm-emit-symbols"]; + if (debug == null) + { + state = Debugger.IsAttached ? 1 : 2; + } + else + { + state = debug.Equals("True", StringComparison.OrdinalIgnoreCase) ? 1 : 2; + } + // make sure we only set the value once, because it isn't allowed to changed as that could cause + // the compiler to try emitting symbols into a ModuleBuilder that doesn't accept them (and would + // throw an InvalidOperationException) + Interlocked.CompareExchange(ref emitSymbols, state, 0); + } + return emitSymbols == 1; + } + } #endif // !STATIC_COMPILER && !STUB_GENERATOR - internal static bool IsUnix - { - get - { - return Environment.OSVersion.Platform == PlatformID.Unix; - } - } - - internal static string MangleResourceName(string name) - { - // FXBUG there really shouldn't be any need to mangle the resource names, - // but in order for ILDASM/ILASM round tripping to work reliably, we have - // to make sure that we don't produce resource names that'll cause ILDASM - // to generate invalid filenames. - StringBuilder sb = new StringBuilder("ikvm__", name.Length + 6); - foreach(char c in name) - { - if("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-+.()$#@~=&{}[]0123456789`".IndexOf(c) != -1) - { - sb.Append(c); - } - else if(c == '/') - { - sb.Append('!'); - } - else - { - sb.Append('%'); - sb.Append(string.Format("{0:X4}", (int)c)); - } - } - return sb.ToString(); - } + internal static bool IsUnix + { + get + { + return Environment.OSVersion.Platform == PlatformID.Unix; + } + } + + internal static string MangleResourceName(string name) + { + // FXBUG there really shouldn't be any need to mangle the resource names, + // but in order for ILDASM/ILASM round tripping to work reliably, we have + // to make sure that we don't produce resource names that'll cause ILDASM + // to generate invalid filenames. + StringBuilder sb = new StringBuilder("ikvm__", name.Length + 6); + foreach (char c in name) + { + if ("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-+.()$#@~=&{}[]0123456789`".IndexOf(c) != -1) + { + sb.Append(c); + } + else if (c == '/') + { + sb.Append('!'); + } + else + { + sb.Append('%'); + sb.Append(string.Format("{0:X4}", (int)c)); + } + } + return sb.ToString(); + } - // based on Bret Mulvey's C# port of Jenkins32 - // note that this algorithm cannot be changed, because we persist these hashcodes in the metadata of shared class loader assemblies - internal static int PersistableHash(string str) - { - uint key = 1; - foreach (char c in str) - { - key += c; - key += (key << 12); - key ^= (key >> 22); - key += (key << 4); - key ^= (key >> 9); - key += (key << 10); - key ^= (key >> 2); - key += (key << 7); - key ^= (key >> 12); - } - return (int)key; - } + // based on Bret Mulvey's C# port of Jenkins32 + // note that this algorithm cannot be changed, because we persist these hashcodes in the metadata of shared class loader assemblies + internal static int PersistableHash(string str) + { + uint key = 1; + foreach (char c in str) + { + key += c; + key += (key << 12); + key ^= (key >> 22); + key += (key << 4); + key ^= (key >> 9); + key += (key << 10); + key ^= (key >> 2); + key += (key << 7); + key ^= (key >> 12); + } + return (int)key; + } #if !STATIC_COMPILER - internal static void CriticalFailure(string message, Exception x) - { - try - { - Tracer.Error(Tracer.Runtime, "CRITICAL FAILURE: {0}", message); - System.Type messageBox = null; + internal static void CriticalFailure(string message, Exception x) + { + try + { + Tracer.Error(Tracer.Runtime, "CRITICAL FAILURE: {0}", message); + System.Type messageBox = null; #if !STUB_GENERATOR - // NOTE we use reflection to invoke MessageBox.Show, to make sure we run in environments where WinForms isn't available - Assembly winForms = IsUnix ? null : Assembly.Load("System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"); - if(winForms != null) - { - messageBox = winForms.GetType("System.Windows.Forms.MessageBox"); - } + // NOTE we use reflection to invoke MessageBox.Show, to make sure we run in environments where WinForms isn't available + Assembly winForms = IsUnix ? null : Assembly.Load("System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"); + if (winForms != null) + { + messageBox = winForms.GetType("System.Windows.Forms.MessageBox"); + } #endif - message = String.Format("****** Critical Failure: {1} ******{0}{0}" + - "PLEASE FILE A BUG REPORT FOR IKVM.NET WHEN YOU SEE THIS MESSAGE{0}{0}" + - (messageBox != null ? "(on Windows you can use Ctrl+C to copy the contents of this message to the clipboard){0}{0}" : "") + - "{2}{0}" + - "{3}{0}" + - "{4} {5}-bit{0}{0}" + - "{6}{0}" + - "{7}{0}" + - "{8}", - Environment.NewLine, - message, - System.Reflection.Assembly.GetExecutingAssembly().FullName, - System.Runtime.InteropServices.RuntimeEnvironment.GetRuntimeDirectory(), - Environment.Version, - IntPtr.Size * 8, - x, - x != null ? new StackTrace(x, true).ToString() : "", - new StackTrace(true)); - if(messageBox != null) - { - try - { - Version ver = SafeGetAssemblyVersion(typeof(JVM).Assembly); - messageBox.InvokeMember("Show", System.Reflection.BindingFlags.InvokeMethod | System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public, null, null, new object[] { message, "IKVM.NET " + ver + " Critical Failure" }); - } - catch - { - Console.Error.WriteLine(message); - } - } - else - { - Console.Error.WriteLine(message); - } - } - catch(Exception ex) - { - Console.Error.WriteLine(ex); - } - finally - { - Environment.Exit(666); - } - } + message = String.Format("****** Critical Failure: {1} ******{0}{0}" + + "PLEASE FILE A BUG REPORT FOR IKVM.NET WHEN YOU SEE THIS MESSAGE{0}{0}" + + (messageBox != null ? "(on Windows you can use Ctrl+C to copy the contents of this message to the clipboard){0}{0}" : "") + + "{2}{0}" + + "{3}{0}" + + "{4} {5}-bit{0}{0}" + + "{6}{0}" + + "{7}{0}" + + "{8}", + Environment.NewLine, + message, + System.Reflection.Assembly.GetExecutingAssembly().FullName, + System.Runtime.InteropServices.RuntimeEnvironment.GetRuntimeDirectory(), + Environment.Version, + IntPtr.Size * 8, + x, + x != null ? new StackTrace(x, true).ToString() : "", + new StackTrace(true)); + if (messageBox != null) + { + try + { + Version ver = SafeGetAssemblyVersion(typeof(JVM).Assembly); + messageBox.InvokeMember("Show", System.Reflection.BindingFlags.InvokeMethod | System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public, null, null, new object[] { message, "IKVM.NET " + ver + " Critical Failure" }); + } + catch + { + Console.Error.WriteLine(message); + } + } + else + { + Console.Error.WriteLine(message); + } + } + catch (Exception ex) + { + Console.Error.WriteLine(ex); + } + finally + { + Environment.Exit(666); + } + } #endif // !STATIC_COMPILER #if STATIC_COMPILER || STUB_GENERATOR - internal static Type LoadType(System.Type type) - { - return StaticCompiler.GetRuntimeType(type.FullName); - } + internal static Type LoadType(System.Type type) + { + return StaticCompiler.GetRuntimeType(type.FullName); + } #endif - // this method resolves types in IKVM.Runtime.dll - // (the version of IKVM.Runtime.dll that we're running - // with can be different from the one we're compiling against.) - internal static Type LoadType(Type type) - { + // this method resolves types in IKVM.Runtime.dll + // (the version of IKVM.Runtime.dll that we're running + // with can be different from the one we're compiling against.) + internal static Type LoadType(Type type) + { #if STATIC_COMPILER || STUB_GENERATOR - return StaticCompiler.GetRuntimeType(type.FullName); + return StaticCompiler.GetRuntimeType(type.FullName); #else - return type; + return type; #endif - } + } - internal static object Box(object val) - { + internal static object Box(object val) + { #if STATIC_COMPILER || FIRST_PASS || STUB_GENERATOR - return null; + return null; #else - if(val is byte) - { - return java.lang.Byte.valueOf((byte)val); - } - else if(val is bool) - { - return java.lang.Boolean.valueOf((bool)val); - } - else if(val is short) - { - return java.lang.Short.valueOf((short)val); - } - else if(val is char) - { - return java.lang.Character.valueOf((char)val); - } - else if(val is int) - { - return java.lang.Integer.valueOf((int)val); - } - else if(val is float) - { - return java.lang.Float.valueOf((float)val); - } - else if(val is long) - { - return java.lang.Long.valueOf((long)val); - } - else if(val is double) - { - return java.lang.Double.valueOf((double)val); - } - else - { - throw new java.lang.IllegalArgumentException(); - } + if (val is byte) + { + return java.lang.Byte.valueOf((byte)val); + } + else if (val is bool) + { + return java.lang.Boolean.valueOf((bool)val); + } + else if (val is short) + { + return java.lang.Short.valueOf((short)val); + } + else if (val is char) + { + return java.lang.Character.valueOf((char)val); + } + else if (val is int) + { + return java.lang.Integer.valueOf((int)val); + } + else if (val is float) + { + return java.lang.Float.valueOf((float)val); + } + else if (val is long) + { + return java.lang.Long.valueOf((long)val); + } + else if (val is double) + { + return java.lang.Double.valueOf((double)val); + } + else + { + throw new java.lang.IllegalArgumentException(); + } #endif - } + } - internal static object Unbox(object val) - { + internal static object Unbox(object val) + { #if STATIC_COMPILER || FIRST_PASS || STUB_GENERATOR - return null; + return null; #else - java.lang.Byte b = val as java.lang.Byte; - if(b != null) - { - return b.byteValue(); - } - java.lang.Boolean b1 = val as java.lang.Boolean; - if(b1 != null) - { - return b1.booleanValue(); - } - java.lang.Short s = val as java.lang.Short; - if(s != null) - { - return s.shortValue(); - } - java.lang.Character c = val as java.lang.Character; - if(c != null) - { - return c.charValue(); - } - java.lang.Integer i = val as java.lang.Integer; - if(i != null) - { - return i.intValue(); - } - java.lang.Float f = val as java.lang.Float; - if(f != null) - { - return f.floatValue(); - } - java.lang.Long l = val as java.lang.Long; - if(l != null) - { - return l.longValue(); - } - java.lang.Double d = val as java.lang.Double; - if(d != null) - { - return d.doubleValue(); - } - else - { - throw new java.lang.IllegalArgumentException(); - } + java.lang.Byte b = val as java.lang.Byte; + if (b != null) + { + return b.byteValue(); + } + java.lang.Boolean b1 = val as java.lang.Boolean; + if (b1 != null) + { + return b1.booleanValue(); + } + java.lang.Short s = val as java.lang.Short; + if (s != null) + { + return s.shortValue(); + } + java.lang.Character c = val as java.lang.Character; + if (c != null) + { + return c.charValue(); + } + java.lang.Integer i = val as java.lang.Integer; + if (i != null) + { + return i.intValue(); + } + java.lang.Float f = val as java.lang.Float; + if (f != null) + { + return f.floatValue(); + } + java.lang.Long l = val as java.lang.Long; + if (l != null) + { + return l.longValue(); + } + java.lang.Double d = val as java.lang.Double; + if (d != null) + { + return d.doubleValue(); + } + else + { + throw new java.lang.IllegalArgumentException(); + } #endif - } + } #if !STATIC_COMPILER && !STUB_GENERATOR - internal static object NewAnnotation(java.lang.ClassLoader classLoader, object definition) - { + internal static object NewAnnotation(java.lang.ClassLoader classLoader, object definition) + { #if !FIRST_PASS - java.lang.annotation.Annotation ann = null; - try - { - ann = (java.lang.annotation.Annotation)ikvm.@internal.AnnotationAttributeBase.newAnnotation(classLoader, definition); - } - catch (java.lang.TypeNotPresentException) { } - if (ann != null && sun.reflect.annotation.AnnotationType.getInstance(ann.annotationType()).retention() == java.lang.annotation.RetentionPolicy.RUNTIME) - { - return ann; - } + java.lang.annotation.Annotation ann = null; + try + { + ann = (java.lang.annotation.Annotation)ikvm.@internal.AnnotationAttributeBase.newAnnotation(classLoader, definition); + } + catch (java.lang.TypeNotPresentException) { } + if (ann != null && sun.reflect.annotation.AnnotationType.getInstance(ann.annotationType()).retention() == java.lang.annotation.RetentionPolicy.RUNTIME) + { + return ann; + } #endif - return null; - } + return null; + } #endif #if !STATIC_COMPILER && !STUB_GENERATOR - internal static object NewAnnotationElementValue(java.lang.ClassLoader classLoader, java.lang.Class expectedClass, object definition) - { + internal static object NewAnnotationElementValue(java.lang.ClassLoader classLoader, java.lang.Class expectedClass, object definition) + { #if FIRST_PASS return null; #else - try - { - return ikvm.@internal.AnnotationAttributeBase.decodeElementValue(definition, expectedClass, classLoader); - } - catch(java.lang.IllegalAccessException) - { - // TODO this shouldn't be here - return null; - } + try + { + return ikvm.@internal.AnnotationAttributeBase.decodeElementValue(definition, expectedClass, classLoader); + } + catch (java.lang.IllegalAccessException) + { + // TODO this shouldn't be here + return null; + } #endif - } + } #endif #if !STATIC_COMPILER && !STUB_GENERATOR - // helper for JNI (which doesn't have access to core library internals) - internal static object NewDirectByteBuffer(long address, int capacity) - { + // helper for JNI (which doesn't have access to core library internals) + internal static object NewDirectByteBuffer(long address, int capacity) + { #if FIRST_PASS return null; #else - return java.nio.DirectByteBuffer.__new(address, capacity); + return java.nio.DirectByteBuffer.__new(address, capacity); #endif - } + } #endif - internal static Type Import(System.Type type) - { + internal static Type Import(System.Type type) + { #if STATIC_COMPILER || STUB_GENERATOR - return StaticCompiler.Universe.Import(type); + return StaticCompiler.Universe.Import(type); #else - return type; + return type; #endif - } - } + } + } - static class Experimental - { - internal static readonly bool JDK_9 = JVM.SafeGetEnvironmentVariable("IKVM_EXPERIMENTAL_JDK_9") != null; - } + static class Experimental + { + internal static readonly bool JDK_9 = JVM.SafeGetEnvironmentVariable("IKVM_EXPERIMENTAL_JDK_9") != null; + } } diff --git a/IKVM.Tests.Util/IKVM.Tests.Util.csproj b/IKVM.Tests.Util/IKVM.Tests.Util.csproj new file mode 100644 index 0000000000..24858c143b --- /dev/null +++ b/IKVM.Tests.Util/IKVM.Tests.Util.csproj @@ -0,0 +1,11 @@ + + + + net461;netcoreapp3.1 + + + + + + + diff --git a/IKVM.Tests/Util/InMemoryCodeUnit.cs b/IKVM.Tests.Util/InMemoryCodeUnit.cs similarity index 93% rename from IKVM.Tests/Util/InMemoryCodeUnit.cs rename to IKVM.Tests.Util/InMemoryCodeUnit.cs index 121334dd77..d00fcb2546 100644 --- a/IKVM.Tests/Util/InMemoryCodeUnit.cs +++ b/IKVM.Tests.Util/InMemoryCodeUnit.cs @@ -1,11 +1,12 @@ using System; -namespace IKVM.Tests.JNI +namespace IKVM.Tests.Util { + /// /// Represents a unit of code to compile. /// - class InMemoryCodeUnit + public class InMemoryCodeUnit { /// diff --git a/IKVM.Tests/Util/InMemoryCompiler.cs b/IKVM.Tests.Util/InMemoryCompiler.cs similarity index 76% rename from IKVM.Tests/Util/InMemoryCompiler.cs rename to IKVM.Tests.Util/InMemoryCompiler.cs index 5902d21746..41b2718d93 100644 --- a/IKVM.Tests/Util/InMemoryCompiler.cs +++ b/IKVM.Tests.Util/InMemoryCompiler.cs @@ -1,21 +1,25 @@ using System; using System.Collections.Concurrent; +using System.IO; -namespace IKVM.Tests.JNI +namespace IKVM.Tests.Util { + /// /// Provides methods to compile a set of sources into a Java classes. /// - class InMemoryCompiler + public class InMemoryCompiler { + readonly ConcurrentDictionary classes = new(); + /// /// Captures the output files from the compilation process. /// class InMemoryForwardingJavaFileManager : global::javax.tools.ForwardingJavaFileManager { - readonly ConcurrentDictionary classes = new(); + readonly ConcurrentDictionary classes; /// /// Class loader which reads from the output class files. @@ -87,10 +91,11 @@ public InMemoryClassFileObject(ConcurrentDictionary /// - public InMemoryForwardingJavaFileManager(global::javax.tools.JavaFileManager manager) : + /// + public InMemoryForwardingJavaFileManager(global::javax.tools.JavaFileManager manager, ConcurrentDictionary classes) : base(manager) { - + this.classes = classes ?? throw new ArgumentNullException(nameof(classes)); } /// @@ -163,7 +168,7 @@ public InMemoryCompiler(InMemoryCodeUnit[] source) this.compiler = global::javax.tools.ToolProvider.getSystemJavaCompiler() ?? throw new Exception(); this.units = source ?? throw new ArgumentNullException(nameof(source)); - this.files = new InMemoryForwardingJavaFileManager(compiler.getStandardFileManager(null, null, null)); + this.files = new InMemoryForwardingJavaFileManager(compiler.getStandardFileManager(null, null, null), classes); } /// @@ -196,16 +201,66 @@ public void Compile() /// /// /// - public global::java.lang.Class getCompiledClass(string className) + public global::java.lang.Class GetClass(string className) { var cld = files.getClassLoader(null); var cls = cld.loadClass(className); if (cls == null) - throw new ClassNotFoundException("Class returned by ClassLoader was null!"); + throw new global::java.lang.ClassNotFoundException("Class returned by ClassLoader was null!"); return cls; } + /// + /// Writes the compiled classes to a JAR. + /// + /// + public void WriteJar(string path) + { + using var jar = File.OpenWrite(path); + WriteJar(jar); + } + + /// + /// Writes the compiled classes to a JAR on the given stream. + /// + /// + public void WriteJar(Stream stream) + { + // write to temporary stream + var buf = new global::java.io.ByteArrayOutputStream(); + WriteJar(buf); + stream.Write(buf.toByteArray(), 0, buf.size()); + } + + /// + /// Writes the compiled classes to a JAR on the given stream. + /// + /// + public void WriteJar(global::java.io.OutputStream stream) + { + var man = new global::java.util.jar.Manifest(); + man.getMainAttributes().put(global::java.util.jar.Attributes.Name.MANIFEST_VERSION, "1.0"); + var jar = new global::java.util.jar.JarOutputStream(stream, man); + WriteJar(jar); + jar.close(); + } + + /// + /// Writes the compiled classes to a JAR. + /// + /// + public void WriteJar(global::java.util.jar.JarOutputStream jar) + { + foreach (var i in classes) + { + var e = new global::java.util.jar.JarEntry(i.Key.Replace(".", "/") + ".class"); + jar.putNextEntry(e); + i.Value.writeTo(jar); + jar.closeEntry(); + } + } + } } diff --git a/IKVM.Tests/IKVM.Tests.csproj b/IKVM.Tests/IKVM.Tests.csproj index e3242fcd45..0347ec21f2 100644 --- a/IKVM.Tests/IKVM.Tests.csproj +++ b/IKVM.Tests/IKVM.Tests.csproj @@ -28,6 +28,7 @@ + diff --git a/IKVM.Tests/JNI/JniTests.cs b/IKVM.Tests/JNI/JniTests.cs index 2950c3395d..6657f6ecc0 100644 --- a/IKVM.Tests/JNI/JniTests.cs +++ b/IKVM.Tests/JNI/JniTests.cs @@ -3,6 +3,8 @@ using FluentAssertions; +using IKVM.Tests.Util; + using Microsoft.VisualStudio.TestTools.UnitTesting; namespace IKVM.Tests.JNI @@ -20,7 +22,7 @@ public void Can_invoke_native_method() var f = new InMemoryCodeUnit("ikvm.tests.jni.JniTests", s); var c = new InMemoryCompiler(new[] { f }); c.Compile(); - var z = c.getCompiledClass("ikvm.tests.jni.JniTests"); + var z = c.GetClass("ikvm.tests.jni.JniTests"); if (z == null) throw new Exception(); diff --git a/IKVM.artifacts.msbuildproj b/IKVM.artifacts.msbuildproj index 61a5e80577..51effedee2 100644 --- a/IKVM.artifacts.msbuildproj +++ b/IKVM.artifacts.msbuildproj @@ -37,19 +37,19 @@ $(ToolProperties);TargetFramework=netcoreapp3.1;RuntimeIdentifier=linux-x64;PublishDir=$([System.IO.Path]::Combine('$(ArtifactStagingDirectory)', 'tools\netcoreapp3.1\linux-x64')) - IKVM_Tests:Publish + IKVM_Tests:Publish;ikvmc_Tests:Publish;ikvmstub_Tests:Publish TargetFramework=net461;PublishDir=$([System.IO.Path]::Combine('$(ArtifactStagingDirectory)', 'tests\net461')) - IKVM_Tests:Publish + IKVM_Tests:Publish;ikvmc_Tests:Publish;ikvmc_Exe_Tests:Publish;ikvmstub_Tests:Publish TargetFramework=netcoreapp3.1;PublishDir=$([System.IO.Path]::Combine('$(ArtifactStagingDirectory)', 'tests\netcoreapp3.1')) - IKVM_Tests:Publish + IKVM_Tests:Publish;ikvmc_Tests:Publish;ikvmstub_Tests:Publish TargetFramework=net5.0;PublishDir=$([System.IO.Path]::Combine('$(ArtifactStagingDirectory)', 'tests\net5.0')) - IKVM_Tests:Publish + IKVM_Tests:Publish;ikvmc_Tests:Publish;ikvmstub_Tests:Publish TargetFramework=net6.0;PublishDir=$([System.IO.Path]::Combine('$(ArtifactStagingDirectory)', 'tests\net6.0')) diff --git a/IKVM.sln b/IKVM.sln index 8b84717fdc..33538d7558 100644 --- a/IKVM.sln +++ b/IKVM.sln @@ -57,220 +57,104 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ikvm-tests-native-linux", " EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ikvm-tests-native", "ikvm-tests-native", "{B6083619-C4E8-4D8E-95BD-217E3663134C}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IKVM.Tests.Util", "IKVM.Tests.Util\IKVM.Tests.Util.csproj", "{066E1713-6D64-4B40-BE1B-7C33C7ADD877}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ikvmc.Exe.Tests", "ikvmc.Exe.Tests\ikvmc.Exe.Tests.csproj", "{6B006D99-1082-44ED-8CF9-B1F1E619A6F8}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ikvmc.Tests", "ikvmc.Tests\ikvmc.Tests.csproj", "{A1982DB0-3626-4B8B-8CCA-8AF692252701}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ikvmstub.Tests", "ikvmstub.Tests\ikvmstub.Tests.csproj", "{B41CDA62-0147-4D57-9D7C-919E041B7478}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU - Debug|x64 = Debug|x64 - Debug|x86 = Debug|x86 Release|Any CPU = Release|Any CPU - Release|x64 = Release|x64 - Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {1DAD30CB-7FF9-47AC-92B2-0F46003EB6A4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {1DAD30CB-7FF9-47AC-92B2-0F46003EB6A4}.Debug|Any CPU.Build.0 = Debug|Any CPU - {1DAD30CB-7FF9-47AC-92B2-0F46003EB6A4}.Debug|x64.ActiveCfg = Debug|Any CPU - {1DAD30CB-7FF9-47AC-92B2-0F46003EB6A4}.Debug|x64.Build.0 = Debug|Any CPU - {1DAD30CB-7FF9-47AC-92B2-0F46003EB6A4}.Debug|x86.ActiveCfg = Debug|Any CPU - {1DAD30CB-7FF9-47AC-92B2-0F46003EB6A4}.Debug|x86.Build.0 = Debug|Any CPU {1DAD30CB-7FF9-47AC-92B2-0F46003EB6A4}.Release|Any CPU.ActiveCfg = Release|Any CPU {1DAD30CB-7FF9-47AC-92B2-0F46003EB6A4}.Release|Any CPU.Build.0 = Release|Any CPU - {1DAD30CB-7FF9-47AC-92B2-0F46003EB6A4}.Release|x64.ActiveCfg = Release|Any CPU - {1DAD30CB-7FF9-47AC-92B2-0F46003EB6A4}.Release|x64.Build.0 = Release|Any CPU - {1DAD30CB-7FF9-47AC-92B2-0F46003EB6A4}.Release|x86.ActiveCfg = Release|Any CPU - {1DAD30CB-7FF9-47AC-92B2-0F46003EB6A4}.Release|x86.Build.0 = Release|Any CPU {FAC669CD-03A2-4120-8B06-68D34E047C1C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {FAC669CD-03A2-4120-8B06-68D34E047C1C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {FAC669CD-03A2-4120-8B06-68D34E047C1C}.Debug|x64.ActiveCfg = Debug|Any CPU - {FAC669CD-03A2-4120-8B06-68D34E047C1C}.Debug|x64.Build.0 = Debug|Any CPU - {FAC669CD-03A2-4120-8B06-68D34E047C1C}.Debug|x86.ActiveCfg = Debug|Any CPU - {FAC669CD-03A2-4120-8B06-68D34E047C1C}.Debug|x86.Build.0 = Debug|Any CPU {FAC669CD-03A2-4120-8B06-68D34E047C1C}.Release|Any CPU.ActiveCfg = Release|Any CPU {FAC669CD-03A2-4120-8B06-68D34E047C1C}.Release|Any CPU.Build.0 = Release|Any CPU - {FAC669CD-03A2-4120-8B06-68D34E047C1C}.Release|x64.ActiveCfg = Release|Any CPU - {FAC669CD-03A2-4120-8B06-68D34E047C1C}.Release|x64.Build.0 = Release|Any CPU - {FAC669CD-03A2-4120-8B06-68D34E047C1C}.Release|x86.ActiveCfg = Release|Any CPU - {FAC669CD-03A2-4120-8B06-68D34E047C1C}.Release|x86.Build.0 = Release|Any CPU {197EF0EC-63E2-4644-AF25-054B931DDB55}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {197EF0EC-63E2-4644-AF25-054B931DDB55}.Debug|Any CPU.Build.0 = Debug|Any CPU - {197EF0EC-63E2-4644-AF25-054B931DDB55}.Debug|x64.ActiveCfg = Debug|Any CPU - {197EF0EC-63E2-4644-AF25-054B931DDB55}.Debug|x64.Build.0 = Debug|Any CPU - {197EF0EC-63E2-4644-AF25-054B931DDB55}.Debug|x86.ActiveCfg = Debug|Any CPU - {197EF0EC-63E2-4644-AF25-054B931DDB55}.Debug|x86.Build.0 = Debug|Any CPU {197EF0EC-63E2-4644-AF25-054B931DDB55}.Release|Any CPU.ActiveCfg = Release|Any CPU {197EF0EC-63E2-4644-AF25-054B931DDB55}.Release|Any CPU.Build.0 = Release|Any CPU - {197EF0EC-63E2-4644-AF25-054B931DDB55}.Release|x64.ActiveCfg = Release|Any CPU - {197EF0EC-63E2-4644-AF25-054B931DDB55}.Release|x64.Build.0 = Release|Any CPU - {197EF0EC-63E2-4644-AF25-054B931DDB55}.Release|x86.ActiveCfg = Release|Any CPU - {197EF0EC-63E2-4644-AF25-054B931DDB55}.Release|x86.Build.0 = Release|Any CPU {E4E508BF-7ADF-413F-83E2-908A3C9F7F8D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {E4E508BF-7ADF-413F-83E2-908A3C9F7F8D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E4E508BF-7ADF-413F-83E2-908A3C9F7F8D}.Debug|x64.ActiveCfg = Debug|Any CPU - {E4E508BF-7ADF-413F-83E2-908A3C9F7F8D}.Debug|x64.Build.0 = Debug|Any CPU - {E4E508BF-7ADF-413F-83E2-908A3C9F7F8D}.Debug|x86.ActiveCfg = Debug|Any CPU - {E4E508BF-7ADF-413F-83E2-908A3C9F7F8D}.Debug|x86.Build.0 = Debug|Any CPU {E4E508BF-7ADF-413F-83E2-908A3C9F7F8D}.Release|Any CPU.ActiveCfg = Release|Any CPU {E4E508BF-7ADF-413F-83E2-908A3C9F7F8D}.Release|Any CPU.Build.0 = Release|Any CPU - {E4E508BF-7ADF-413F-83E2-908A3C9F7F8D}.Release|x64.ActiveCfg = Release|Any CPU - {E4E508BF-7ADF-413F-83E2-908A3C9F7F8D}.Release|x64.Build.0 = Release|Any CPU - {E4E508BF-7ADF-413F-83E2-908A3C9F7F8D}.Release|x86.ActiveCfg = Release|Any CPU - {E4E508BF-7ADF-413F-83E2-908A3C9F7F8D}.Release|x86.Build.0 = Release|Any CPU {0A87FF49-AC9D-479A-ACBB-F4028A0BE1F7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {0A87FF49-AC9D-479A-ACBB-F4028A0BE1F7}.Debug|Any CPU.Build.0 = Debug|Any CPU - {0A87FF49-AC9D-479A-ACBB-F4028A0BE1F7}.Debug|x64.ActiveCfg = Debug|Any CPU - {0A87FF49-AC9D-479A-ACBB-F4028A0BE1F7}.Debug|x64.Build.0 = Debug|Any CPU - {0A87FF49-AC9D-479A-ACBB-F4028A0BE1F7}.Debug|x86.ActiveCfg = Debug|Any CPU - {0A87FF49-AC9D-479A-ACBB-F4028A0BE1F7}.Debug|x86.Build.0 = Debug|Any CPU {0A87FF49-AC9D-479A-ACBB-F4028A0BE1F7}.Release|Any CPU.ActiveCfg = Release|Any CPU {0A87FF49-AC9D-479A-ACBB-F4028A0BE1F7}.Release|Any CPU.Build.0 = Release|Any CPU - {0A87FF49-AC9D-479A-ACBB-F4028A0BE1F7}.Release|x64.ActiveCfg = Release|Any CPU - {0A87FF49-AC9D-479A-ACBB-F4028A0BE1F7}.Release|x64.Build.0 = Release|Any CPU - {0A87FF49-AC9D-479A-ACBB-F4028A0BE1F7}.Release|x86.ActiveCfg = Release|Any CPU - {0A87FF49-AC9D-479A-ACBB-F4028A0BE1F7}.Release|x86.Build.0 = Release|Any CPU {2F29E48C-63C3-4E47-BCBA-A7454B9119CF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {2F29E48C-63C3-4E47-BCBA-A7454B9119CF}.Debug|Any CPU.Build.0 = Debug|Any CPU - {2F29E48C-63C3-4E47-BCBA-A7454B9119CF}.Debug|x64.ActiveCfg = Debug|Any CPU - {2F29E48C-63C3-4E47-BCBA-A7454B9119CF}.Debug|x64.Build.0 = Debug|Any CPU - {2F29E48C-63C3-4E47-BCBA-A7454B9119CF}.Debug|x86.ActiveCfg = Debug|Any CPU - {2F29E48C-63C3-4E47-BCBA-A7454B9119CF}.Debug|x86.Build.0 = Debug|Any CPU {2F29E48C-63C3-4E47-BCBA-A7454B9119CF}.Release|Any CPU.ActiveCfg = Release|Any CPU {2F29E48C-63C3-4E47-BCBA-A7454B9119CF}.Release|Any CPU.Build.0 = Release|Any CPU - {2F29E48C-63C3-4E47-BCBA-A7454B9119CF}.Release|x64.ActiveCfg = Release|Any CPU - {2F29E48C-63C3-4E47-BCBA-A7454B9119CF}.Release|x64.Build.0 = Release|Any CPU - {2F29E48C-63C3-4E47-BCBA-A7454B9119CF}.Release|x86.ActiveCfg = Release|Any CPU - {2F29E48C-63C3-4E47-BCBA-A7454B9119CF}.Release|x86.Build.0 = Release|Any CPU {D13E6D52-AF13-423D-B29D-A935BA32E67C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {D13E6D52-AF13-423D-B29D-A935BA32E67C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D13E6D52-AF13-423D-B29D-A935BA32E67C}.Debug|x64.ActiveCfg = Debug|Any CPU - {D13E6D52-AF13-423D-B29D-A935BA32E67C}.Debug|x64.Build.0 = Debug|Any CPU - {D13E6D52-AF13-423D-B29D-A935BA32E67C}.Debug|x86.ActiveCfg = Debug|Any CPU - {D13E6D52-AF13-423D-B29D-A935BA32E67C}.Debug|x86.Build.0 = Debug|Any CPU {D13E6D52-AF13-423D-B29D-A935BA32E67C}.Release|Any CPU.ActiveCfg = Release|Any CPU {D13E6D52-AF13-423D-B29D-A935BA32E67C}.Release|Any CPU.Build.0 = Release|Any CPU - {D13E6D52-AF13-423D-B29D-A935BA32E67C}.Release|x64.ActiveCfg = Release|Any CPU - {D13E6D52-AF13-423D-B29D-A935BA32E67C}.Release|x64.Build.0 = Release|Any CPU - {D13E6D52-AF13-423D-B29D-A935BA32E67C}.Release|x86.ActiveCfg = Release|Any CPU - {D13E6D52-AF13-423D-B29D-A935BA32E67C}.Release|x86.Build.0 = Release|Any CPU {01A67032-A76E-400D-9DA8-A58CE10A5FCD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {01A67032-A76E-400D-9DA8-A58CE10A5FCD}.Debug|Any CPU.Build.0 = Debug|Any CPU - {01A67032-A76E-400D-9DA8-A58CE10A5FCD}.Debug|x64.ActiveCfg = Debug|Any CPU - {01A67032-A76E-400D-9DA8-A58CE10A5FCD}.Debug|x64.Build.0 = Debug|Any CPU - {01A67032-A76E-400D-9DA8-A58CE10A5FCD}.Debug|x86.ActiveCfg = Debug|Any CPU - {01A67032-A76E-400D-9DA8-A58CE10A5FCD}.Debug|x86.Build.0 = Debug|Any CPU {01A67032-A76E-400D-9DA8-A58CE10A5FCD}.Release|Any CPU.ActiveCfg = Release|Any CPU {01A67032-A76E-400D-9DA8-A58CE10A5FCD}.Release|Any CPU.Build.0 = Release|Any CPU - {01A67032-A76E-400D-9DA8-A58CE10A5FCD}.Release|x64.ActiveCfg = Release|Any CPU - {01A67032-A76E-400D-9DA8-A58CE10A5FCD}.Release|x64.Build.0 = Release|Any CPU - {01A67032-A76E-400D-9DA8-A58CE10A5FCD}.Release|x86.ActiveCfg = Release|Any CPU - {01A67032-A76E-400D-9DA8-A58CE10A5FCD}.Release|x86.Build.0 = Release|Any CPU {43BA164D-41F3-4563-BDB0-EEF56CE49309}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {43BA164D-41F3-4563-BDB0-EEF56CE49309}.Debug|Any CPU.Build.0 = Debug|Any CPU - {43BA164D-41F3-4563-BDB0-EEF56CE49309}.Debug|x64.ActiveCfg = Debug|Any CPU - {43BA164D-41F3-4563-BDB0-EEF56CE49309}.Debug|x64.Build.0 = Debug|Any CPU - {43BA164D-41F3-4563-BDB0-EEF56CE49309}.Debug|x86.ActiveCfg = Debug|Any CPU - {43BA164D-41F3-4563-BDB0-EEF56CE49309}.Debug|x86.Build.0 = Debug|Any CPU {43BA164D-41F3-4563-BDB0-EEF56CE49309}.Release|Any CPU.ActiveCfg = Release|Any CPU {43BA164D-41F3-4563-BDB0-EEF56CE49309}.Release|Any CPU.Build.0 = Release|Any CPU - {43BA164D-41F3-4563-BDB0-EEF56CE49309}.Release|x64.ActiveCfg = Release|Any CPU - {43BA164D-41F3-4563-BDB0-EEF56CE49309}.Release|x64.Build.0 = Release|Any CPU - {43BA164D-41F3-4563-BDB0-EEF56CE49309}.Release|x86.ActiveCfg = Release|Any CPU - {43BA164D-41F3-4563-BDB0-EEF56CE49309}.Release|x86.Build.0 = Release|Any CPU {01563AC3-AE6C-4297-9313-8B835B488738}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {01563AC3-AE6C-4297-9313-8B835B488738}.Debug|Any CPU.Build.0 = Debug|Any CPU - {01563AC3-AE6C-4297-9313-8B835B488738}.Debug|x64.ActiveCfg = Debug|Any CPU - {01563AC3-AE6C-4297-9313-8B835B488738}.Debug|x64.Build.0 = Debug|Any CPU - {01563AC3-AE6C-4297-9313-8B835B488738}.Debug|x86.ActiveCfg = Debug|Any CPU - {01563AC3-AE6C-4297-9313-8B835B488738}.Debug|x86.Build.0 = Debug|Any CPU {01563AC3-AE6C-4297-9313-8B835B488738}.Release|Any CPU.ActiveCfg = Release|Any CPU {01563AC3-AE6C-4297-9313-8B835B488738}.Release|Any CPU.Build.0 = Release|Any CPU - {01563AC3-AE6C-4297-9313-8B835B488738}.Release|x64.ActiveCfg = Release|Any CPU - {01563AC3-AE6C-4297-9313-8B835B488738}.Release|x64.Build.0 = Release|Any CPU - {01563AC3-AE6C-4297-9313-8B835B488738}.Release|x86.ActiveCfg = Release|Any CPU - {01563AC3-AE6C-4297-9313-8B835B488738}.Release|x86.Build.0 = Release|Any CPU {BE0445A8-947D-485D-A183-0686D2AE23F8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {BE0445A8-947D-485D-A183-0686D2AE23F8}.Debug|Any CPU.Build.0 = Debug|Any CPU - {BE0445A8-947D-485D-A183-0686D2AE23F8}.Debug|x64.ActiveCfg = Debug|Any CPU - {BE0445A8-947D-485D-A183-0686D2AE23F8}.Debug|x64.Build.0 = Debug|Any CPU - {BE0445A8-947D-485D-A183-0686D2AE23F8}.Debug|x86.ActiveCfg = Debug|Any CPU - {BE0445A8-947D-485D-A183-0686D2AE23F8}.Debug|x86.Build.0 = Debug|Any CPU {BE0445A8-947D-485D-A183-0686D2AE23F8}.Release|Any CPU.ActiveCfg = Release|Any CPU {BE0445A8-947D-485D-A183-0686D2AE23F8}.Release|Any CPU.Build.0 = Release|Any CPU - {BE0445A8-947D-485D-A183-0686D2AE23F8}.Release|x64.ActiveCfg = Release|Any CPU - {BE0445A8-947D-485D-A183-0686D2AE23F8}.Release|x64.Build.0 = Release|Any CPU - {BE0445A8-947D-485D-A183-0686D2AE23F8}.Release|x86.ActiveCfg = Release|Any CPU - {BE0445A8-947D-485D-A183-0686D2AE23F8}.Release|x86.Build.0 = Release|Any CPU {8267A3D1-2B36-471C-9E9F-2E1B0C223632}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {8267A3D1-2B36-471C-9E9F-2E1B0C223632}.Debug|Any CPU.Build.0 = Debug|Any CPU - {8267A3D1-2B36-471C-9E9F-2E1B0C223632}.Debug|x64.ActiveCfg = Debug|Any CPU - {8267A3D1-2B36-471C-9E9F-2E1B0C223632}.Debug|x64.Build.0 = Debug|Any CPU - {8267A3D1-2B36-471C-9E9F-2E1B0C223632}.Debug|x86.ActiveCfg = Debug|Any CPU - {8267A3D1-2B36-471C-9E9F-2E1B0C223632}.Debug|x86.Build.0 = Debug|Any CPU {8267A3D1-2B36-471C-9E9F-2E1B0C223632}.Release|Any CPU.ActiveCfg = Release|Any CPU {8267A3D1-2B36-471C-9E9F-2E1B0C223632}.Release|Any CPU.Build.0 = Release|Any CPU - {8267A3D1-2B36-471C-9E9F-2E1B0C223632}.Release|x64.ActiveCfg = Release|Any CPU - {8267A3D1-2B36-471C-9E9F-2E1B0C223632}.Release|x64.Build.0 = Release|Any CPU - {8267A3D1-2B36-471C-9E9F-2E1B0C223632}.Release|x86.ActiveCfg = Release|Any CPU - {8267A3D1-2B36-471C-9E9F-2E1B0C223632}.Release|x86.Build.0 = Release|Any CPU {A333BFF7-1690-486C-BD54-C99A33CE73C6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {A333BFF7-1690-486C-BD54-C99A33CE73C6}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A333BFF7-1690-486C-BD54-C99A33CE73C6}.Debug|x64.ActiveCfg = Debug|Any CPU - {A333BFF7-1690-486C-BD54-C99A33CE73C6}.Debug|x64.Build.0 = Debug|Any CPU - {A333BFF7-1690-486C-BD54-C99A33CE73C6}.Debug|x86.ActiveCfg = Debug|Any CPU - {A333BFF7-1690-486C-BD54-C99A33CE73C6}.Debug|x86.Build.0 = Debug|Any CPU {A333BFF7-1690-486C-BD54-C99A33CE73C6}.Release|Any CPU.ActiveCfg = Release|Any CPU {A333BFF7-1690-486C-BD54-C99A33CE73C6}.Release|Any CPU.Build.0 = Release|Any CPU - {A333BFF7-1690-486C-BD54-C99A33CE73C6}.Release|x64.ActiveCfg = Release|Any CPU - {A333BFF7-1690-486C-BD54-C99A33CE73C6}.Release|x64.Build.0 = Release|Any CPU - {A333BFF7-1690-486C-BD54-C99A33CE73C6}.Release|x86.ActiveCfg = Release|Any CPU - {A333BFF7-1690-486C-BD54-C99A33CE73C6}.Release|x86.Build.0 = Release|Any CPU {D8B580D1-D12B-39CD-A42B-BAEE36602AA1}.Debug|Any CPU.ActiveCfg = Debug|x64 {D8B580D1-D12B-39CD-A42B-BAEE36602AA1}.Debug|Any CPU.Build.0 = Debug|x64 - {D8B580D1-D12B-39CD-A42B-BAEE36602AA1}.Debug|x64.ActiveCfg = Debug|x64 - {D8B580D1-D12B-39CD-A42B-BAEE36602AA1}.Debug|x64.Build.0 = Debug|x64 - {D8B580D1-D12B-39CD-A42B-BAEE36602AA1}.Debug|x86.ActiveCfg = Debug|Win32 - {D8B580D1-D12B-39CD-A42B-BAEE36602AA1}.Debug|x86.Build.0 = Debug|Win32 {D8B580D1-D12B-39CD-A42B-BAEE36602AA1}.Release|Any CPU.ActiveCfg = Release|x64 {D8B580D1-D12B-39CD-A42B-BAEE36602AA1}.Release|Any CPU.Build.0 = Release|x64 - {D8B580D1-D12B-39CD-A42B-BAEE36602AA1}.Release|x64.ActiveCfg = Release|x64 - {D8B580D1-D12B-39CD-A42B-BAEE36602AA1}.Release|x64.Build.0 = Release|x64 - {D8B580D1-D12B-39CD-A42B-BAEE36602AA1}.Release|x86.ActiveCfg = Release|Win32 - {D8B580D1-D12B-39CD-A42B-BAEE36602AA1}.Release|x86.Build.0 = Release|Win32 {F2A81A31-C65F-4B4E-A6FE-B14E71515EA3}.Debug|Any CPU.ActiveCfg = Debug|x64 {F2A81A31-C65F-4B4E-A6FE-B14E71515EA3}.Debug|Any CPU.Build.0 = Debug|x64 - {F2A81A31-C65F-4B4E-A6FE-B14E71515EA3}.Debug|x64.ActiveCfg = Debug|x64 - {F2A81A31-C65F-4B4E-A6FE-B14E71515EA3}.Debug|x64.Build.0 = Debug|x64 - {F2A81A31-C65F-4B4E-A6FE-B14E71515EA3}.Debug|x86.ActiveCfg = Debug|x86 - {F2A81A31-C65F-4B4E-A6FE-B14E71515EA3}.Debug|x86.Build.0 = Debug|x86 {F2A81A31-C65F-4B4E-A6FE-B14E71515EA3}.Release|Any CPU.ActiveCfg = Release|x64 {F2A81A31-C65F-4B4E-A6FE-B14E71515EA3}.Release|Any CPU.Build.0 = Release|x64 - {F2A81A31-C65F-4B4E-A6FE-B14E71515EA3}.Release|x64.ActiveCfg = Release|x64 - {F2A81A31-C65F-4B4E-A6FE-B14E71515EA3}.Release|x64.Build.0 = Release|x64 - {F2A81A31-C65F-4B4E-A6FE-B14E71515EA3}.Release|x86.ActiveCfg = Release|x86 - {F2A81A31-C65F-4B4E-A6FE-B14E71515EA3}.Release|x86.Build.0 = Release|x86 {A275C11D-F06E-475F-AEBA-7F7A1EF8D140}.Debug|Any CPU.ActiveCfg = Debug|x64 {A275C11D-F06E-475F-AEBA-7F7A1EF8D140}.Debug|Any CPU.Build.0 = Debug|x64 - {A275C11D-F06E-475F-AEBA-7F7A1EF8D140}.Debug|x64.ActiveCfg = Debug|x64 - {A275C11D-F06E-475F-AEBA-7F7A1EF8D140}.Debug|x64.Build.0 = Debug|x64 - {A275C11D-F06E-475F-AEBA-7F7A1EF8D140}.Debug|x86.ActiveCfg = Debug|Win32 - {A275C11D-F06E-475F-AEBA-7F7A1EF8D140}.Debug|x86.Build.0 = Debug|Win32 {A275C11D-F06E-475F-AEBA-7F7A1EF8D140}.Release|Any CPU.ActiveCfg = Release|x64 {A275C11D-F06E-475F-AEBA-7F7A1EF8D140}.Release|Any CPU.Build.0 = Release|x64 - {A275C11D-F06E-475F-AEBA-7F7A1EF8D140}.Release|x64.ActiveCfg = Release|x64 - {A275C11D-F06E-475F-AEBA-7F7A1EF8D140}.Release|x64.Build.0 = Release|x64 - {A275C11D-F06E-475F-AEBA-7F7A1EF8D140}.Release|x86.ActiveCfg = Release|Win32 - {A275C11D-F06E-475F-AEBA-7F7A1EF8D140}.Release|x86.Build.0 = Release|Win32 {E566FE94-C551-43A7-843C-5E8199CA7373}.Debug|Any CPU.ActiveCfg = Debug|x64 {E566FE94-C551-43A7-843C-5E8199CA7373}.Debug|Any CPU.Build.0 = Debug|x64 - {E566FE94-C551-43A7-843C-5E8199CA7373}.Debug|x64.ActiveCfg = Debug|x64 - {E566FE94-C551-43A7-843C-5E8199CA7373}.Debug|x64.Build.0 = Debug|x64 - {E566FE94-C551-43A7-843C-5E8199CA7373}.Debug|x86.ActiveCfg = Debug|x86 - {E566FE94-C551-43A7-843C-5E8199CA7373}.Debug|x86.Build.0 = Debug|x86 {E566FE94-C551-43A7-843C-5E8199CA7373}.Release|Any CPU.ActiveCfg = Release|x64 {E566FE94-C551-43A7-843C-5E8199CA7373}.Release|Any CPU.Build.0 = Release|x64 - {E566FE94-C551-43A7-843C-5E8199CA7373}.Release|x64.ActiveCfg = Release|x64 - {E566FE94-C551-43A7-843C-5E8199CA7373}.Release|x64.Build.0 = Release|x64 - {E566FE94-C551-43A7-843C-5E8199CA7373}.Release|x86.ActiveCfg = Release|x86 - {E566FE94-C551-43A7-843C-5E8199CA7373}.Release|x86.Build.0 = Release|x86 + {066E1713-6D64-4B40-BE1B-7C33C7ADD877}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {066E1713-6D64-4B40-BE1B-7C33C7ADD877}.Debug|Any CPU.Build.0 = Debug|Any CPU + {066E1713-6D64-4B40-BE1B-7C33C7ADD877}.Release|Any CPU.ActiveCfg = Release|Any CPU + {066E1713-6D64-4B40-BE1B-7C33C7ADD877}.Release|Any CPU.Build.0 = Release|Any CPU + {6B006D99-1082-44ED-8CF9-B1F1E619A6F8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6B006D99-1082-44ED-8CF9-B1F1E619A6F8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6B006D99-1082-44ED-8CF9-B1F1E619A6F8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6B006D99-1082-44ED-8CF9-B1F1E619A6F8}.Release|Any CPU.Build.0 = Release|Any CPU + {A1982DB0-3626-4B8B-8CCA-8AF692252701}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A1982DB0-3626-4B8B-8CCA-8AF692252701}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A1982DB0-3626-4B8B-8CCA-8AF692252701}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A1982DB0-3626-4B8B-8CCA-8AF692252701}.Release|Any CPU.Build.0 = Release|Any CPU + {B41CDA62-0147-4D57-9D7C-919E041B7478}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B41CDA62-0147-4D57-9D7C-919E041B7478}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B41CDA62-0147-4D57-9D7C-919E041B7478}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B41CDA62-0147-4D57-9D7C-919E041B7478}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/ikvmc.Exe.Tests/ExeTests.cs b/ikvmc.Exe.Tests/ExeTests.cs new file mode 100644 index 0000000000..d6312d8d9f --- /dev/null +++ b/ikvmc.Exe.Tests/ExeTests.cs @@ -0,0 +1,144 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; + +using CliWrap; + +using FluentAssertions; + +using IKVM.Tests.Util; + +using Microsoft.VisualStudio.TestTools.UnitTesting; + +using System.Linq; + +#if NETCOREAPP3_1_OR_GREATER +using Microsoft.Extensions.DependencyModel; +#endif + +namespace ikvmc.Exe.Tests +{ + + [TestClass] + public class ExeTests + { + + /// + /// Describes the result of executing an exe. + /// + class ExeResult + { + + /// + /// Initializes a new instance. + /// + /// + /// + /// + public ExeResult(int exitCode, string standardOutput, string standardError) + { + ExitCode = exitCode; + StandardOutput = standardOutput; + StandardError = standardError; + } + + public int ExitCode { get; set; } + + public string StandardOutput { get; set; } + + public string StandardError { get; set; } + + } + + /// + /// Executes the IKVMC command line. + /// + /// + /// + /// + /// + async Task ExecuteIkvmc(string target, bool useNetCore, params string[] arguments) + { + var dir = Path.Combine(Path.GetDirectoryName(typeof(ExeTests).Assembly.Location), $"ikvmc-{target}"); + var cmd = useNetCore ? Cli.Wrap("dotnet").WithArguments(o => o.Add("exec").Add(Path.Combine(dir, "ikvmc.dll"))) : Cli.Wrap(Path.Combine(dir, "ikvmc.exe")); + cmd = cmd.WithArguments(o => o.Add(arguments)); + cmd = cmd.WithValidation(CommandResultValidation.None); + var stdout = new StringBuilder(); + cmd = cmd.WithStandardOutputPipe(PipeTarget.ToStringBuilder(stdout)); + var stderr = new StringBuilder(); + cmd = cmd.WithStandardErrorPipe(PipeTarget.ToStringBuilder(stderr)); + var tsk = await cmd.ExecuteAsync(); + return new ExeResult(tsk.ExitCode, stdout.ToString(), stderr.ToString()); + } + + /// + /// Can confirm we can simply execute the ikvmc executable and not have an error code. + /// + /// + /// + [DataTestMethod] + [DynamicData(nameof(GetVersionsToTest), DynamicDataSourceType.Method)] + public async Task Should_display_options_and_exit_successfully_with_no_arguments(string target, bool useNetCore) + { + var rsl = await ExecuteIkvmc(target, useNetCore); + rsl.ExitCode.Should().Be(0); + rsl.StandardError.Should().StartWith("IKVM.NET"); + rsl.StandardError.Should().Contain("Compiler Options:"); + } + + /// + /// Can confirm we can simply execute the ikvmc executable and not have an error code. + /// + /// + /// + [DataTestMethod] + [DynamicData(nameof(GetVersionsToTest), DynamicDataSourceType.Method)] + public async Task Should_convert_simple_jar(string target, bool useNetCore) + { + var s = new StreamReader(typeof(ExeTests).Assembly.GetManifestResourceStream("ikvmc.Exe.Tests.ExeTests.java")).ReadToEnd(); + var f = new InMemoryCodeUnit("ikvmc.exe.tests.ExeTests", s); + var c = new InMemoryCompiler(new[] { f }); + c.Compile(); + var j = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("n") + ".jar"); + c.WriteJar(j); + +#if NET461 + var a = new[] { $"-lib:{System.Runtime.InteropServices.RuntimeEnvironment.GetRuntimeDirectory()}" }; +#else + var a = DependencyContext.Default.CompileLibraries.SelectMany(i => i.ResolveReferencePaths()).Select(i => $"-r:{i}"); +#endif + + var asm = Path.ChangeExtension(j, ".dll"); + var rsl = await ExecuteIkvmc(target, useNetCore, a.Concat(new[] { "-assembly:ikvmc.Tests.Java", $"-out:{asm}", j }).ToArray()); + rsl.ExitCode.Should().Be(0); + rsl.StandardError.Should().StartWith("IKVM.NET"); + File.Exists(asm).Should().BeTrue(); + } + + /// + /// Gets the IKVMC builds to test based on the current test OS platform. + /// + /// + public static IEnumerable GetVersionsToTest() + { + // we test windows executables on Windows + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + yield return new object[] { "net461-win7-any", false }; + yield return new object[] { "netcoreapp3.1-win7-x64", false }; + yield return new object[] { "netcoreapp3.1-win7-x86", false }; + } + + // we test Linux executables on Linux + if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + { + yield return new object[] { "netcoreapp3.1-linux-x64", true }; + } + } + + } + +} diff --git a/ikvmc.Exe.Tests/ExeTests.java b/ikvmc.Exe.Tests/ExeTests.java new file mode 100644 index 0000000000..34d0556934 --- /dev/null +++ b/ikvmc.Exe.Tests/ExeTests.java @@ -0,0 +1,11 @@ +package ikvmc.exe.tests; + +public class ExeTests +{ + + public static String echo(String value) + { + return value; + } + +} diff --git a/ikvmc.Exe.Tests/ikvmc.Exe.Tests.csproj b/ikvmc.Exe.Tests/ikvmc.Exe.Tests.csproj new file mode 100644 index 0000000000..819d2a42a4 --- /dev/null +++ b/ikvmc.Exe.Tests/ikvmc.Exe.Tests.csproj @@ -0,0 +1,56 @@ + + + + netcoreapp3.1 + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + TargetFramework=net461 + + ikvmc-net461-win7-any + + + TargetFramework=netcoreapp3.1 + RuntimeIdentifier=win7-x64;PublishReadyToRun=true + ikvmc-netcoreapp3.1-win7-x64 + + + TargetFramework=netcoreapp3.1 + RuntimeIdentifier=win7-x86;PublishReadyToRun=true + ikvmc-netcoreapp3.1-win7-x86 + + + TargetFramework=netcoreapp3.1 + RuntimeIdentifier=linux-x64 + ikvmc-netcoreapp3.1-linux-x64 + + + + diff --git a/ikvmc.Tests/IkvmcTests.cs b/ikvmc.Tests/IkvmcTests.cs new file mode 100644 index 0000000000..f5eefa7265 --- /dev/null +++ b/ikvmc.Tests/IkvmcTests.cs @@ -0,0 +1,47 @@ +using System; +using System.IO; +using System.Linq; +using System.Runtime.InteropServices; + +using FluentAssertions; + +using IKVM.Tests.Util; + +using Microsoft.VisualStudio.TestTools.UnitTesting; + +#if NETCOREAPP3_1_OR_GREATER +using Microsoft.Extensions.DependencyModel; +#endif + +namespace ikvmc.Tests +{ + + [TestClass] + public class IkvmcTests + { + + [TestMethod] + public void Should_convert_simple_jar() + { + var s = new StreamReader(typeof(IkvmcTests).Assembly.GetManifestResourceStream("ikvmc.Tests.IkvmcTests.java")).ReadToEnd(); + var f = new InMemoryCodeUnit("ikvmc.tests.IkvmcTests", s); + var c = new InMemoryCompiler(new[] { f }); + c.Compile(); + var j = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("n") + ".jar"); + c.WriteJar(j); + +#if NET461 + var a = new[] { $"-lib:{RuntimeEnvironment.GetRuntimeDirectory()}" }; +#else + var a = DependencyContext.Default.CompileLibraries.SelectMany(i => i.ResolveReferencePaths()).Select(i => $"-r:{i}"); +#endif + + var asm = Path.ChangeExtension(j, ".dll"); + var ret = ikvmc.IkvmcCompiler.Main(a.Concat(new[] { "-assembly:ikvmc.Tests.Java", $"-out:{asm}", j }).ToArray()); + ret.Should().Be(0); + File.Exists(asm).Should().BeTrue(); + } + + } + +} diff --git a/ikvmc.Tests/IkvmcTests.java b/ikvmc.Tests/IkvmcTests.java new file mode 100644 index 0000000000..5cabed608a --- /dev/null +++ b/ikvmc.Tests/IkvmcTests.java @@ -0,0 +1,11 @@ +package ikvmc.tests; + +public class IkvmcTests +{ + + public static String echo(String value) + { + return value; + } + +} diff --git a/ikvmc.Tests/ikvmc.Tests.csproj b/ikvmc.Tests/ikvmc.Tests.csproj new file mode 100644 index 0000000000..5bb0da2630 --- /dev/null +++ b/ikvmc.Tests/ikvmc.Tests.csproj @@ -0,0 +1,33 @@ + + + + net461;netcoreapp3.1;net5.0;net6.0 + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ikvmc/IKVM/Internal/AssemblyResolver.cs b/ikvmc/IKVM/Internal/AssemblyResolver.cs index 71bd92f3d0..e3192fe72d 100644 --- a/ikvmc/IKVM/Internal/AssemblyResolver.cs +++ b/ikvmc/IKVM/Internal/AssemblyResolver.cs @@ -29,11 +29,12 @@ Jeroen Frijters namespace IKVM.Internal { + sealed class AssemblyResolver { - private readonly List libpath = new List(); - private Universe universe; - private Version mscorlibVersion; + + readonly List libpath = new List(); + Universe universe; internal enum WarningId { @@ -47,228 +48,225 @@ internal enum WarningId internal delegate void WarningEvent(WarningId warning, string message, string[] parameters); internal event WarningEvent Warning; - private void EmitWarning(WarningId warning, string message, params string[] parameters) + /// + /// Emits a warning event. + /// + /// + /// + /// + void EmitWarning(WarningId warning, string message, params string[] parameters) { if (Warning != null) - { Warning(warning, message, parameters); - } else - { Console.Error.WriteLine("Warning: " + message, parameters); - } } - internal void Init(Universe universe, bool nostdlib, IList references, IList userLibPaths) + internal void Init(Universe universe, IList references, IList userLibPaths) { this.universe = universe; - // like the C# compiler, the references are loaded from: - // current directory, CLR directory, -lib: option, %LIB% environment - // (note that, unlike the C# compiler, we don't add the CLR directory if -nostdlib has been specified) + // search in the local directory first libpath.Add(Environment.CurrentDirectory); - if (!nostdlib) - { -//#if NETCOREAPP3_1 -// libpath.Add(Universe.ReferenceAssembliesDirectory); -//#else - libpath.Add(System.Runtime.InteropServices.RuntimeEnvironment.GetRuntimeDirectory()); -//#endif - } - + // then search in directories specified by the user foreach (string str in userLibPaths) - { AddLibraryPaths(str, true); - } + // then search in the LIB environment variable AddLibraryPaths(Environment.GetEnvironmentVariable("LIB") ?? "", false); - if (nostdlib) - { - mscorlibVersion = LoadMscorlib(references).GetName().Version; - } - else - { - mscorlibVersion = universe.Load(Universe.CoreLibName).GetName().Version; - } - -#if STATIC_COMPILER - universe.AssemblyResolve += AssemblyResolve; -#else - universe.AssemblyResolve += LegacyAssemblyResolve; -#endif + // attach to the universe to handle resolution + universe.AssemblyResolve += AssemblyResolve; } + /// + /// Attempts to load the assembly from the specified path. + /// + /// + /// internal Assembly LoadFile(string path) { - string ex = null; + string msg = null; try { - using (RawModule module = universe.OpenRawModule(path)) - { - if (mscorlibVersion != null) - { - // to avoid problems (i.e. weird exceptions), we don't allow assemblies to load that reference a newer version of mscorlib - foreach (AssemblyName asmref in module.GetReferencedAssemblies()) - { - if (asmref.Name == Universe.CoreLibName && asmref.Version > mscorlibVersion) - { - Console.Error.WriteLine("Error: unable to load assembly '{0}' as it depends on a higher version of mscorlib than the one currently loaded", path); - Environment.Exit(1); - } - } - } - Assembly asm = universe.LoadAssembly(module); - if (asm.Location != module.Location && CanonicalizePath(asm.Location) != CanonicalizePath(module.Location)) - { - EmitWarning(WarningId.LocationIgnored, "assembly \"{0}\" is ignored as previously loaded assembly \"{1}\" has the same identity \"{2}\"", path, asm.Location, asm.FullName); - } - return asm; - } + using var module = universe.OpenRawModule(path); + var assembly = universe.LoadAssembly(module); + if (assembly.Location != module.Location && CanonicalizePath(assembly.Location) != CanonicalizePath(module.Location)) + EmitWarning(WarningId.LocationIgnored, "assembly \"{0}\" is ignored as previously loaded assembly \"{1}\" has the same identity \"{2}\"", path, assembly.Location, assembly.FullName); + + return assembly; } catch (IOException x) { - ex = x.Message; + msg = x.Message; } catch (UnauthorizedAccessException x) { - ex = x.Message; + msg = x.Message; } catch (IKVM.Reflection.BadImageFormatException x) { - ex = x.Message; + msg = x.Message; } - Console.Error.WriteLine("Error: unable to load assembly '{0}'" + Environment.NewLine + " ({1})", path, ex); + + Console.Error.WriteLine("Error: unable to load assembly '{0}'" + Environment.NewLine + " ({1})", path, msg); Environment.Exit(1); return null; } - private static string CanonicalizePath(string path) + /// + /// Returns the canonical path for the given path. + /// + /// + /// + static string CanonicalizePath(string path) { + if (string.IsNullOrWhiteSpace(path)) + throw new ArgumentException($"'{nameof(path)}' cannot be null or whitespace.", nameof(path)); + try { - System.IO.FileInfo fi = new System.IO.FileInfo(path); + var fi = new FileInfo(Path.GetFullPath(path)); if (fi.DirectoryName == null) - { return path.Length > 1 && path[1] == ':' ? path.ToUpper() : path; - } - string dir = CanonicalizePath(fi.DirectoryName); - string name = fi.Name; + + var dir = CanonicalizePath(fi.DirectoryName); + var name = fi.Name; try { - string[] arr = System.IO.Directory.GetFileSystemEntries(dir, name); + var arr = Directory.GetFileSystemEntries(dir, name); if (arr.Length == 1) - { name = arr[0]; - } } - catch (System.UnauthorizedAccessException) + catch (UnauthorizedAccessException) { + } - catch (System.IO.IOException) + catch (IOException) { + } - return System.IO.Path.Combine(dir, name); + + return Path.Combine(dir, name); } - catch (System.UnauthorizedAccessException) + catch (UnauthorizedAccessException) { + } - catch (System.IO.IOException) + catch (IOException) { + } catch (System.Security.SecurityException) { + } - catch (System.NotSupportedException) + catch (NotSupportedException) { + } + return path; } + /// + /// Attempts to load an assembly with a partial name. + /// + /// + /// internal Assembly LoadWithPartialName(string name) { - foreach (string path in FindAssemblyPath(name + ".dll")) - { + if (string.IsNullOrWhiteSpace(name)) + throw new ArgumentException($"'{nameof(name)}' cannot be null or whitespace.", nameof(name)); + + foreach (var path in FindAssemblyPath(name + ".dll")) return LoadFile(path); - } + return null; } - internal bool ResolveReference(Dictionary cache, ref Assembly[] references, string reference) + /// + /// Attempts to resolve the given reference, appending the discovered assembly to the references list. + /// + /// + /// + /// + /// + internal bool ResolveReference(Dictionary cache, List references, string reference) { - string[] files = new string[0]; - try - { - string path = Path.GetDirectoryName(reference); - files = Directory.GetFiles(path == "" ? "." : path, Path.GetFileName(reference)); - } - catch (ArgumentException) - { - } - catch (IOException) - { - } - if (files.Length == 0) + if (cache is null) + throw new ArgumentNullException(nameof(cache)); + if (references is null) + throw new ArgumentNullException(nameof(references)); + if (string.IsNullOrEmpty(reference)) + throw new ArgumentException($"'{nameof(reference)}' cannot be null or empty.", nameof(reference)); + + var files = new List(0); + + // attempt to find the reference in the current directory if it exists + var fullPath = Path.GetFullPath(reference); + if (File.Exists(fullPath)) + files.Add(fullPath); + + // we haven't yet found the reference + if (files.Count == 0) { - Assembly asm = null; - cache.TryGetValue(reference, out asm); - if (asm == null) + if (cache.TryGetValue(reference, out Assembly assembly) == false) { foreach (string found in FindAssemblyPath(reference)) { - asm = LoadFile(found); - cache.Add(reference, asm); + assembly = LoadFile(found); + cache.Add(reference, assembly); break; } } - if (asm == null) - { + + if (assembly == null) return false; - } - ArrayAppend(ref references, asm); + + references.Add(assembly); } else { - foreach (string file in files) + foreach (var file in files) { - Assembly asm; - if (!cache.TryGetValue(file, out asm)) - { - asm = LoadFile(file); - } - ArrayAppend(ref references, asm); + if (cache.TryGetValue(file, out Assembly assembly) == false) + assembly = LoadFile(file); + + references.Add(assembly); } } - return true; - } - private static void ArrayAppend(ref T[] array, T element) - { - if (array == null) - { - array = new T[] { element }; - } - else - { - array = ArrayUtil.Concat(array, element); - } + return true; } - private Assembly AssemblyResolve(object sender, IKVM.Reflection.ResolveEventArgs args) + /// + /// Attempts to resolve a required assembly. + /// + /// + /// + /// + Assembly AssemblyResolve(object sender, IKVM.Reflection.ResolveEventArgs args) { - AssemblyName name = new AssemblyName(args.Name); + var name = new AssemblyName(args.Name); AssemblyName previousMatch = null; int previousMatchLevel = 0; - foreach (Assembly asm in universe.GetAssemblies()) - { + + // first attempt to match the requested assembly against one that is already laoe + foreach (var asm in universe.GetAssemblies()) if (Match(asm.GetName(), name, ref previousMatch, ref previousMatchLevel)) - { return asm; - } - } + + // attempt to locate teh assembly in the search path + foreach (var file in FindAssemblyPath(name.Name + ".dll")) + if (Match(AssemblyName.GetAssemblyName(file), name, ref previousMatch, ref previousMatchLevel)) + return LoadFile(file); + + // we did not find an exact match, but we did find one that was close if (previousMatch != null) { + // match level was okay to proceed if (previousMatchLevel == 2) { #if NETFRAMEWORK @@ -276,93 +274,31 @@ private Assembly AssemblyResolve(object sender, IKVM.Reflection.ResolveEventArgs #endif return universe.Load(previousMatch.FullName); } - else if (args.RequestingAssembly != null) + + if (args.RequestingAssembly != null) { + // we found an assembly match, but it was of a lower version than that which was requested Console.Error.WriteLine("Error: Assembly '{0}' uses '{1}' which has a higher version than referenced assembly '{2}'", args.RequestingAssembly.FullName, name.FullName, previousMatch.FullName); Environment.Exit(1); return null; } else { + // an assembly was found at a lower version, but wasn't specifically requested by a dependent Console.Error.WriteLine("Error: Assembly '{0}' was requested which is a higher version than referenced assembly '{1}'", name.FullName, previousMatch.FullName); Environment.Exit(1); return null; } } - else if (args.RequestingAssembly != null) - { - return universe.CreateMissingAssembly(args.Name); - } - else - { - return null; - } - } - private Assembly LegacyAssemblyResolve(object sender, IKVM.Reflection.ResolveEventArgs args) - { - return LegacyLoad(new AssemblyName(args.Name), args.RequestingAssembly); - } + // generate a missing assembly reference, only if we had a requester + if (args.RequestingAssembly != null) + return universe.CreateMissingAssembly(args.Name); - internal Assembly LegacyLoad(AssemblyName name, Assembly requestingAssembly) - { - AssemblyName previousMatch = null; - int previousMatchLevel = 0; - foreach (Assembly asm in universe.GetAssemblies()) - { - if (Match(asm.GetName(), name, ref previousMatch, ref previousMatchLevel)) - { - return asm; - } - } - foreach (string file in FindAssemblyPath(name.Name + ".dll")) - { - if (Match(AssemblyName.GetAssemblyName(file), name, ref previousMatch, ref previousMatchLevel)) - { - return LoadFile(file); - } - } - if (requestingAssembly != null) - { - string path = Path.Combine(Path.GetDirectoryName(requestingAssembly.Location), name.Name + ".dll"); - if (File.Exists(path) && Match(AssemblyName.GetAssemblyName(path), name, ref previousMatch, ref previousMatchLevel)) - { - return LoadFile(path); - } - } - if (previousMatch != null) - { - if (previousMatchLevel == 2) - { - EmitWarning(WarningId.HigherVersion, "assuming assembly reference \"{0}\" matches \"{1}\", you may need to supply runtime policy", previousMatch.FullName, name.FullName); - return LoadFile(new Uri(previousMatch.CodeBase).LocalPath); - } - else if (requestingAssembly != null) - { - Console.Error.WriteLine("Error: Assembly '{0}' uses '{1}' which has a higher version than referenced assembly '{2}'", requestingAssembly.FullName, name.FullName, previousMatch.FullName); - } - else - { - Console.Error.WriteLine("Error: Assembly '{0}' was requested which is a higher version than referenced assembly '{1}'", name.FullName, previousMatch.FullName); - } - } - else - { -#if STUB_GENERATOR - return universe.CreateMissingAssembly(name.FullName); -#else - Console.Error.WriteLine("Error: unable to find assembly '{0}'", name.FullName); - if (requestingAssembly != null) - { - Console.Error.WriteLine(" (a dependency of '{0}')", requestingAssembly.FullName); - } -#endif - } - Environment.Exit(1); return null; } - private bool Match(AssemblyName assemblyDef, AssemblyName assemblyRef, ref AssemblyName bestMatch, ref int bestMatchLevel) + bool Match(AssemblyName assemblyDef, AssemblyName assemblyRef, ref AssemblyName bestMatch, ref int bestMatchLevel) { // Match levels: // 0 = no match @@ -405,7 +341,7 @@ private bool Match(AssemblyName assemblyDef, AssemblyName assemblyRef, ref Assem } } - private void AddLibraryPaths(string str, bool option) + void AddLibraryPaths(string str, bool option) { foreach (string dir in str.Split(Path.PathSeparator)) { @@ -427,52 +363,23 @@ private void AddLibraryPaths(string str, bool option) } } - private Assembly LoadMscorlib(IList references) - { - if (references != null) - { - foreach (string r in references) - { - try - { - if (AssemblyName.GetAssemblyName(r).Name == Universe.CoreLibName) - { - return LoadFile(r); - } - } - catch - { - } - } - } - foreach (string mscorlib in FindAssemblyPath(Universe.CoreLibName + ".dll")) - { - return LoadFile(mscorlib); - } - Console.Error.WriteLine("Error: unable to find mscorlib.dll"); - Environment.Exit(1); - return null; - } - - private IEnumerable FindAssemblyPath(string file) + IEnumerable FindAssemblyPath(string file) { if (Path.IsPathRooted(file)) { if (File.Exists(file)) - { yield return file; - } } else { - foreach (string dir in libpath) + foreach (var dir in libpath) { - string path = Path.Combine(dir, file); + // if the assembly file is found in the lib path, yield it up + var path = Path.Combine(dir, file); if (File.Exists(path)) - { yield return path; - } - // for legacy compat, we try again after appending .dll + + // it's possible the reference did not specify a dll name path = Path.Combine(dir, file + ".dll"); if (File.Exists(path)) { @@ -482,5 +389,7 @@ private IEnumerable FindAssemblyPath(string file) } } } + } + } diff --git a/ikvmc/IKVM/Internal/CompilerClassLoader.cs b/ikvmc/IKVM/Internal/CompilerClassLoader.cs index fac4f8fbe9..3400349087 100644 --- a/ikvmc/IKVM/Internal/CompilerClassLoader.cs +++ b/ikvmc/IKVM/Internal/CompilerClassLoader.cs @@ -26,6 +26,7 @@ Jeroen Frijters using System.Collections.Generic; using System.Diagnostics; using System.IO; +using System.Linq; using System.Security; using System.Security.Permissions; using System.Text; @@ -38,6 +39,7 @@ Jeroen Frijters using IKVM.Attributes; using IKVM.Reflection; using IKVM.Reflection.Emit; +using IKVM.Runtime; using ikvmc; @@ -274,138 +276,136 @@ private TypeWrapper GetTypeWrapperCompilerHook(string name) { RemapperTypeWrapper rtw; if (remapped.TryGetValue(name, out rtw)) - { return rtw; - } - else + + if (classes.TryGetValue(name, out Jar.Item itemRef)) { - Jar.Item itemRef; - if (classes.TryGetValue(name, out itemRef)) + classes.Remove(name); + ClassFile f; + try { - classes.Remove(name); - ClassFile f; - try - { - byte[] buf = itemRef.GetData(); - f = new ClassFile(buf, 0, buf.Length, name, ClassFileParseOptions, null); - } - catch (ClassFormatError x) - { - StaticCompiler.SuppressWarning(options, Message.ClassNotFound, name); - StaticCompiler.IssueMessage(options, Message.ClassFormatError, name, x.Message); - return null; - } - if (f.Name != name) - { - StaticCompiler.SuppressWarning(options, Message.ClassNotFound, name); - StaticCompiler.IssueMessage(options, Message.WrongClassName, name, f.Name); - return null; - } - if (f.IsPublic && options.privatePackages != null) + var buf = itemRef.GetData(); + f = new ClassFile(buf, 0, buf.Length, name, ClassFileParseOptions, null); + } + catch (ClassFormatError x) + { + StaticCompiler.SuppressWarning(options, Message.ClassNotFound, name); + StaticCompiler.IssueMessage(options, Message.ClassFormatError, name, x.Message); + return null; + } + + if (f.Name != name) + { + StaticCompiler.SuppressWarning(options, Message.ClassNotFound, name); + StaticCompiler.IssueMessage(options, Message.WrongClassName, name, f.Name); + return null; + } + + if (f.IsPublic && options.privatePackages.Count > 0) + { + foreach (string p in options.privatePackages) { - foreach (string p in options.privatePackages) + if (f.Name.StartsWith(p)) { - if (f.Name.StartsWith(p)) - { - f.SetInternal(); - break; - } + f.SetInternal(); + break; } } - if (f.IsPublic && options.publicPackages != null) + } + + if (f.IsPublic && options.publicPackages.Count > 0) + { + bool found = false; + foreach (string package in options.publicPackages) { - bool found = false; - foreach (string package in options.publicPackages) + if (f.Name.StartsWith(package)) { - if (f.Name.StartsWith(package)) - { - found = true; - break; - } - } - if (!found) - { - f.SetInternal(); + found = true; + break; } } - if (f.SourceFileAttribute != null) + if (!found) { - FileInfo path = itemRef.Path; - if (path != null) - { - string sourceFile = Path.GetFullPath(Path.Combine(path.DirectoryName, f.SourceFileAttribute)); - if (File.Exists(sourceFile)) - { - f.SourcePath = sourceFile; - } - } - if (f.SourcePath == null) - { - if (options.sourcepath != null) - { - string package = f.Name; - int index = package.LastIndexOf('.'); - package = index == -1 ? "" : package.Substring(0, index).Replace('.', '/'); - f.SourcePath = Path.GetFullPath(Path.Combine(options.sourcepath + "/" + package, f.SourceFileAttribute)); - } - else - { - f.SourcePath = f.SourceFileAttribute; - } - } + f.SetInternal(); } - try + } + + if (f.SourceFileAttribute != null) + { + var path = itemRef.Path; + if (path != null) + { + var sourceFile = Path.GetFullPath(Path.Combine(path.DirectoryName, f.SourceFileAttribute)); + if (File.Exists(sourceFile)) + f.SourcePath = sourceFile; + } + + if (f.SourcePath == null) { - TypeWrapper tw = DefineClass(f, null); - // we successfully created the type, so we don't need to include the class as a resource - if (options.nojarstubs) + if (options.sourcepath != null) { - itemRef.Remove(); + var package = f.Name; + var index = package.LastIndexOf('.'); + package = index == -1 ? "" : package.Substring(0, index).Replace('.', Path.DirectorySeparatorChar); + f.SourcePath = Path.GetFullPath(Path.Combine(options.sourcepath, package, f.SourceFileAttribute)); } else { - itemRef.MarkAsStub(); + f.SourcePath = f.SourceFileAttribute; } - int pos = f.Name.LastIndexOf('.'); - if (pos != -1) - { - string manifestJar = options.IsClassesJar(itemRef.Jar) ? null : itemRef.Jar.Name; - packages.DefinePackage(f.Name.Substring(0, pos), manifestJar); - } - return tw; - } - catch (ClassFormatError x) - { - StaticCompiler.IssueMessage(options, Message.ClassFormatError, name, x.Message); } - catch (IllegalAccessError x) + } + + try + { + var tw = DefineClass(f, null); + // we successfully created the type, so we don't need to include the class as a resource + if (options.nojarstubs) { - StaticCompiler.IssueMessage(options, Message.IllegalAccessError, name, x.Message); + itemRef.Remove(); } - catch (VerifyError x) + else { - StaticCompiler.IssueMessage(options, Message.VerificationError, name, x.Message); + itemRef.MarkAsStub(); } - catch (NoClassDefFoundError x) - { - if ((options.codegenoptions & CodeGenOptions.DisableDynamicBinding) != 0) - { - StaticCompiler.IssueMessage(options, Message.NoClassDefFoundError, name, x.Message); - } - StaticCompiler.IssueMessage(options, Message.ClassNotFound, x.Message); - } - catch (RetargetableJavaException x) + + int pos = f.Name.LastIndexOf('.'); + if (pos != -1) { - StaticCompiler.IssueMessage(options, Message.GenericUnableToCompileError, name, x.GetType().Name, x.Message); + string manifestJar = options.IsClassesJar(itemRef.Jar) ? null : itemRef.Jar.Name; + packages.DefinePackage(f.Name.Substring(0, pos), manifestJar); } - StaticCompiler.SuppressWarning(options, Message.ClassNotFound, name); - return null; + + return tw; } - else + catch (ClassFormatError x) { - return null; + StaticCompiler.IssueMessage(options, Message.ClassFormatError, name, x.Message); + } + catch (IllegalAccessError x) + { + StaticCompiler.IssueMessage(options, Message.IllegalAccessError, name, x.Message); + } + catch (VerifyError x) + { + StaticCompiler.IssueMessage(options, Message.VerificationError, name, x.Message); + } + catch (NoClassDefFoundError x) + { + if ((options.codegenoptions & CodeGenOptions.DisableDynamicBinding) != 0) + StaticCompiler.IssueMessage(options, Message.NoClassDefFoundError, name, x.Message); + StaticCompiler.IssueMessage(options, Message.ClassNotFound, x.Message); + } + catch (RetargetableJavaException x) + { + StaticCompiler.IssueMessage(options, Message.GenericUnableToCompileError, name, x.GetType().Name, x.Message); } + + StaticCompiler.SuppressWarning(options, Message.ClassNotFound, name); + return null; } + + return null; } // HACK when we're compiling multiple targets with -sharedclassloader, each target will have its own CompilerClassLoader, @@ -2559,11 +2559,11 @@ internal static int Compile(string runtimeAssembly, List option if (runtimeAssembly == null) { // we assume that the runtime is in the same directory as the compiler - runtimeAssembly = Path.Combine(typeof(CompilerClassLoader).Assembly.Location, ".." + Path.DirectorySeparatorChar + "IKVM.Runtime.dll"); + runtimeAssembly = Path.GetFullPath(Path.Combine(typeof(CompilerClassLoader).Assembly.Location, "..", "IKVM.Runtime.dll")); } StaticCompiler.runtimeAssembly = StaticCompiler.LoadFile(runtimeAssembly); - StaticCompiler.runtimeJniAssembly = StaticCompiler.LoadFile(Path.Combine(StaticCompiler.runtimeAssembly.Location, ".." + Path.DirectorySeparatorChar + "IKVM.Runtime.JNI.dll")); + StaticCompiler.runtimeJniAssembly = StaticCompiler.LoadFile(Path.GetFullPath(Path.Combine(StaticCompiler.runtimeAssembly.Location, "..", "IKVM.Runtime.JNI.dll"))); } catch (FileNotFoundException) { @@ -2586,27 +2586,20 @@ internal static int Compile(string runtimeAssembly, List option return rc; } compilers.Add(compiler); + if (options.sharedclassloader != null) - { options.sharedclassloader.Add(compiler); - } } + foreach (CompilerClassLoader compiler1 in compilers) - { foreach (CompilerClassLoader compiler2 in compilers) - { - if (compiler1 != compiler2 - && (compiler1.options.crossReferenceAllPeers || (compiler1.options.peerReferences != null && Array.IndexOf(compiler1.options.peerReferences, compiler2.options.assembly) != -1))) - { + if (compiler1 != compiler2 && (compiler1.options.crossReferenceAllPeers || (compiler1.options.peerReferences.IndexOf(compiler2.options.assembly) != -1))) compiler1.AddReference(compiler2); - } - } - } + foreach (CompilerClassLoader compiler in compilers) - { compiler.CompilePass0(); - } - Dictionary mainAssemblyTypes = new Dictionary(); + + var mainAssemblyTypes = new Dictionary(); foreach (CompilerClassLoader compiler in compilers) { if (compiler.options.sharedclassloader != null) @@ -2665,10 +2658,11 @@ internal static int Compile(string runtimeAssembly, List option private static int CreateCompiler(CompilerOptions options, ref CompilerClassLoader loader, ref bool compilingCoreAssembly) { Tracer.Info(Tracer.Compiler, "JVM.Compile path: {0}, assembly: {1}", options.path, options.assembly); - AssemblyName runtimeAssemblyName = StaticCompiler.runtimeAssembly.GetName(); - bool allReferencesAreStrongNamed = IsSigned(StaticCompiler.runtimeAssembly); - List references = new List(); - foreach (Assembly reference in options.references ?? new Assembly[0]) + + var runtimeAssemblyName = StaticCompiler.runtimeAssembly.GetName(); + var allReferencesAreStrongNamed = IsSigned(StaticCompiler.runtimeAssembly); + var references = new List(); + foreach (var reference in options.references ?? Enumerable.Empty()) { references.Add(reference); allReferencesAreStrongNamed &= IsSigned(reference); @@ -2704,17 +2698,14 @@ private static int CreateCompiler(CompilerOptions options, ref CompilerClassLoad foreach (Jar jar in options.jars) { if (options.IsResourcesJar(jar)) - { continue; - } + foreach (Jar.Item item in jar) { string name = item.Name; - if (name.EndsWith(".class", StringComparison.Ordinal) - && name.Length > 6 - && name.IndexOf('.') == name.Length - 6) + if (name.EndsWith(".class", StringComparison.Ordinal) && name.Length > 6 && name.IndexOf('.') == name.Length - 6) { - string className = name.Substring(0, name.Length - 6).Replace('/', '.'); + var className = name.Substring(0, name.Length - 6).Replace('/', '.'); if (h.ContainsKey(className)) { StaticCompiler.IssueMessage(Message.DuplicateClassName, className); @@ -2738,31 +2729,6 @@ private static int CreateCompiler(CompilerOptions options, ref CompilerClassLoad } } - if (options.assemblyAttributeAnnotations == null) - { - // look for "assembly" type that acts as a placeholder for assembly attributes - Jar.Item assemblyType; - if (h.TryGetValue("assembly", out assemblyType)) - { - try - { - byte[] buf = assemblyType.GetData(); - ClassFile f = new ClassFile(buf, 0, buf.Length, null, ClassFileParseOptions.None, null); - // NOTE the "assembly" type in the unnamed package is a magic type - // that acts as the placeholder for assembly attributes - if (f.Name == "assembly" && f.Annotations != null) - { - options.assemblyAttributeAnnotations = f.Annotations; - // HACK remove "assembly" type that exists only as a placeholder for assembly attributes - h.Remove(f.Name); - assemblyType.Remove(); - StaticCompiler.IssueMessage(Message.LegacyAssemblyAttributesFound); - } - } - catch (ClassFormatError) { } - } - } - // now look for a main method if (options.mainClass == null && (options.guessFileKind || options.target != PEFileKinds.Dll)) { @@ -2785,7 +2751,10 @@ private static int CreateCompiler(CompilerOptions options, ref CompilerClassLoad } } } - catch (ClassFormatError) { } + catch (ClassFormatError) + { + + } } break_outer:; } @@ -2868,8 +2837,10 @@ private static int CreateCompiler(CompilerOptions options, ref CompilerClassLoad } catch (Exception x) { + Console.WriteLine(x.StackTrace); throw new FatalCompilerErrorException(Message.ErrorReadingFile, options.remapfile, x.Message); } + try { XmlTextReader rdr = new XmlTextReader(fs); @@ -2904,16 +2875,17 @@ private static int CreateCompiler(CompilerOptions options, ref CompilerClassLoad // try to find the core assembly by looking at the assemblies that the runtime references if (JVM.CoreAssembly == null && !compilingCoreAssembly) { - foreach (AssemblyName name in StaticCompiler.runtimeAssembly.GetReferencedAssemblies()) + foreach (var name in StaticCompiler.runtimeAssembly.GetReferencedAssemblies()) { Assembly asm = null; try { - asm = LoadReferencedAssembly(StaticCompiler.runtimeAssembly.Location + "/../" + name.Name + ".dll"); + asm = LoadReferencedAssembly(Path.Combine(StaticCompiler.runtimeAssembly.Location, "..", name.Name + ".dll")); } catch (FileNotFoundException) { + } if (asm != null && IsCoreAssembly(asm)) @@ -3095,29 +3067,27 @@ private int CompilePass3() } Tracer.Info(Tracer.Compiler, "Compiling class files (2)"); WriteResources(); + if (options.externalResources != null) - { - foreach (KeyValuePair kv in options.externalResources) - { - assemblyBuilder.AddResourceFile(JVM.MangleResourceName(kv.Key), kv.Value); - } - } + foreach (var kvp in options.externalResources) + assemblyBuilder.AddResourceFile(JVM.MangleResourceName(kvp.Key), kvp.Value); + if (options.fileversion != null) { - CustomAttributeBuilder filever = new CustomAttributeBuilder(JVM.Import(typeof(System.Reflection.AssemblyFileVersionAttribute)).GetConstructor(new Type[] { Types.String }), new object[] { options.fileversion }); + var filever = new CustomAttributeBuilder(JVM.Import(typeof(System.Reflection.AssemblyFileVersionAttribute)).GetConstructor(new Type[] { Types.String }), new object[] { options.fileversion }); assemblyBuilder.SetCustomAttribute(filever); } + if (options.assemblyAttributeAnnotations != null) { foreach (object[] def in options.assemblyAttributeAnnotations) { - Annotation annotation = Annotation.LoadAssemblyCustomAttribute(this, def); + var annotation = Annotation.LoadAssemblyCustomAttribute(this, def); if (annotation != null) - { annotation.Apply(this, assemblyBuilder, def); - } } } + if (options.classLoader != null) { TypeWrapper wrapper = null; @@ -3488,10 +3458,10 @@ sealed class CompilerOptions internal ApartmentState apartment; internal PEFileKinds target; internal bool guessFileKind; - internal string[] unresolvedReferences; // only used during command line parsing + internal List unresolvedReferences = new List(); // only used during command line parsing internal Dictionary legacyStubReferences = new Dictionary(); // only used during command line parsing - internal Assembly[] references; - internal string[] peerReferences; + internal List references = new List(); + internal List peerReferences = new List(); internal bool crossReferenceAllPeers = true; internal string[] classesToExclude; // only used during command line parsing internal FileInfo remapfile; @@ -3499,8 +3469,8 @@ sealed class CompilerOptions internal bool noglobbing; internal CodeGenOptions codegenoptions; internal bool compressedResources; - internal string[] privatePackages; - internal string[] publicPackages; + internal List privatePackages = new List(); + internal List publicPackages = new List(); internal string sourcepath; internal Dictionary externalResources; internal string classLoader; @@ -3515,7 +3485,7 @@ sealed class CompilerOptions internal bool warnaserror; // treat all warnings as errors internal FileInfo writeSuppressWarningsFile; internal List proxies = new List(); - internal object[] assemblyAttributeAnnotations; + internal List assemblyAttributeAnnotations = new List(); internal bool warningLevelHigh; internal bool noParameterReflection; @@ -3664,7 +3634,7 @@ enum Message DllExportRequiresSupportedPlatform = 130, DuplicateAssemblyReference = 132, UnableToResolveType = 133, - StubsAreDeprecated = 134, + StubsAreInvalid = 134, WrongClassName = 135, ReflectionCallerClassRequiresCallerID = 136, LegacyAssemblyAttributesFound = 137, @@ -4026,8 +3996,8 @@ internal static void IssueMessage(CompilerOptions options, Message msgId, params case Message.UnableToResolveType: msg = "Reference in \"{0}\" to type \"{1}\" claims it is defined in \"{2}\", but it could not be found"; break; - case Message.StubsAreDeprecated: - msg = "Compiling stubs is deprecated. Please add a reference to assembly \"{0}\" instead."; + case Message.StubsAreInvalid: + msg = "Compiling stubs is not supported. Please add a reference to assembly \"{0}\" instead."; break; case Message.WrongClassName: msg = "Unable to compile \"{0}\" (wrong name: \"{1}\")"; diff --git a/ikvmc/IKVM/Internal/FatalCompilerErrorException.cs b/ikvmc/IKVM/Internal/FatalCompilerErrorException.cs index 2743f926ab..44c87cc6de 100644 --- a/ikvmc/IKVM/Internal/FatalCompilerErrorException.cs +++ b/ikvmc/IKVM/Internal/FatalCompilerErrorException.cs @@ -23,141 +23,101 @@ Jeroen Frijters */ using System; -using IKVM.Internal; - -sealed class FatalCompilerErrorException : Exception +namespace IKVM.Internal { - internal FatalCompilerErrorException(Message id, params object[] args) - : base(string.Format("fatal error IKVMC{0}: {1}", (int)id, args.Length == 0 ? GetMessage(id) : string.Format(GetMessage(id), args))) - { - } - private static string GetMessage(Message id) + /// + /// Describes a fatal compiler error. + /// + sealed class FatalCompilerErrorException : Exception { - switch (id) + + /// + /// Initializes a new instance. + /// + /// + /// + internal FatalCompilerErrorException(Message id, params object[] args) : + base($"fatal error IKVMC{(int)id}: {(args.Length == 0 ? GetMessage(id) : string.Format(GetMessage(id), args))}") { - case IKVM.Internal.Message.ResponseFileDepthExceeded: - return "Response file nesting depth exceeded"; - case IKVM.Internal.Message.ErrorReadingFile: - return "Unable to read file: {0}\n\t({1})"; - case IKVM.Internal.Message.NoTargetsFound: - return "No targets found"; - case IKVM.Internal.Message.FileFormatLimitationExceeded: - return "File format limitation exceeded: {0}"; - case IKVM.Internal.Message.CannotSpecifyBothKeyFileAndContainer: - return "You cannot specify both a key file and container"; - case IKVM.Internal.Message.DelaySignRequiresKey: - return "You cannot delay sign without a key file or container"; - case IKVM.Internal.Message.InvalidStrongNameKeyPair: - return "Invalid key {0} specified.\n\t(\"{1}\")"; - case IKVM.Internal.Message.ReferenceNotFound: - return "Reference not found: {0}"; - case IKVM.Internal.Message.OptionsMustPreceedChildLevels: - return "You can only specify options before any child levels"; - case IKVM.Internal.Message.UnrecognizedTargetType: - return "Invalid value '{0}' for -target option"; - case IKVM.Internal.Message.UnrecognizedPlatform: - return "Invalid value '{0}' for -platform option"; - case IKVM.Internal.Message.UnrecognizedApartment: - return "Invalid value '{0}' for -apartment option"; - case IKVM.Internal.Message.MissingFileSpecification: - return "Missing file specification for '{0}' option"; - case IKVM.Internal.Message.PathTooLong: - return "Path too long: {0}"; - case IKVM.Internal.Message.PathNotFound: - return "Path not found: {0}"; - case IKVM.Internal.Message.InvalidPath: - return "Invalid path: {0}"; - case IKVM.Internal.Message.InvalidOptionSyntax: - return "Invalid option: {0}"; - case IKVM.Internal.Message.ExternalResourceNotFound: - return "External resource file does not exist: {0}"; - case IKVM.Internal.Message.ExternalResourceNameInvalid: - return "External resource file may not include path specification: {0}"; - case IKVM.Internal.Message.InvalidVersionFormat: - return "Invalid version specified: {0}"; - case IKVM.Internal.Message.InvalidFileAlignment: - return "Invalid value '{0}' for -filealign option"; - case IKVM.Internal.Message.ErrorWritingFile: - return "Unable to write file: {0}\n\t({1})"; - case IKVM.Internal.Message.UnrecognizedOption: - return "Unrecognized option: {0}"; - case IKVM.Internal.Message.NoOutputFileSpecified: - return "No output file specified"; - case IKVM.Internal.Message.SharedClassLoaderCannotBeUsedOnModuleTarget: - return "Incompatible options: -target:module and -sharedclassloader cannot be combined"; - case IKVM.Internal.Message.RuntimeNotFound: - return "Unable to load runtime assembly"; - case IKVM.Internal.Message.MainClassRequiresExe: - return "Main class cannot be specified for library or module"; - case IKVM.Internal.Message.ExeRequiresMainClass: - return "No main method found"; - case IKVM.Internal.Message.PropertiesRequireExe: - return "Properties cannot be specified for library or module"; - case IKVM.Internal.Message.ModuleCannotHaveClassLoader: - return "Cannot specify assembly class loader for modules"; - case IKVM.Internal.Message.ErrorParsingMapFile: - return "Unable to parse remap file: {0}\n\t({1})"; - case IKVM.Internal.Message.BootstrapClassesMissing: - return "Bootstrap classes missing and core assembly not found"; - case IKVM.Internal.Message.StrongNameRequiresStrongNamedRefs: - return "All referenced assemblies must be strong named, to be able to sign the output assembly"; - case IKVM.Internal.Message.MainClassNotFound: - return "Main class not found"; - case IKVM.Internal.Message.MainMethodNotFound: - return "Main method not found"; - case IKVM.Internal.Message.UnsupportedMainMethod: - return "Redirected main method not supported"; - case IKVM.Internal.Message.ExternalMainNotAccessible: - return "External main method must be public and in a public class"; - case IKVM.Internal.Message.ClassLoaderNotFound: - return "Custom assembly class loader class not found"; - case IKVM.Internal.Message.ClassLoaderNotAccessible: - return "Custom assembly class loader class is not accessible"; - case IKVM.Internal.Message.ClassLoaderIsAbstract: - return "Custom assembly class loader class is abstract"; - case IKVM.Internal.Message.ClassLoaderNotClassLoader: - return "Custom assembly class loader class does not extend java.lang.ClassLoader"; - case IKVM.Internal.Message.ClassLoaderConstructorMissing: - return "Custom assembly class loader constructor is missing"; - case IKVM.Internal.Message.MapFileTypeNotFound: - return "Type '{0}' referenced in remap file was not found"; - case IKVM.Internal.Message.MapFileClassNotFound: - return "Class '{0}' referenced in remap file was not found"; - case IKVM.Internal.Message.MaximumErrorCountReached: - return "Maximum error count reached"; - case IKVM.Internal.Message.LinkageError: - return "Link error: {0}"; - case IKVM.Internal.Message.RuntimeMismatch: - return "Referenced assembly {0} was compiled with an incompatible IKVM.Runtime version\n" + - "\tCurrent runtime: {1}\n" + - "\tReferenced assembly runtime: {2}"; - case IKVM.Internal.Message.CoreClassesMissing: - return "Failed to find core classes in core library"; - case IKVM.Internal.Message.CriticalClassNotFound: - return "Unable to load critical class '{0}'"; - case IKVM.Internal.Message.AssemblyContainsDuplicateClassNames: - return "Type '{0}' and '{1}' both map to the same name '{2}'\n" + - "\t({3})"; - case IKVM.Internal.Message.CallerIDRequiresHasCallerIDAnnotation: - return "CallerID.getCallerID() requires a HasCallerID annotation"; - case IKVM.Internal.Message.UnableToResolveInterface: - return "Unable to resolve interface '{0}' on type '{1}'"; - case IKVM.Internal.Message.MissingBaseType: - return "The base class or interface '{0}' in assembly '{1}' referenced by type '{2}' in '{3}' could not be resolved"; - case IKVM.Internal.Message.MissingBaseTypeReference: - return "The type '{0}' is defined in an assembly that is not referenced. You must add a reference to assembly '{1}'"; - case IKVM.Internal.Message.FileNotFound: - return "File not found: {0}"; - case IKVM.Internal.Message.RuntimeMethodMissing: - return "Runtime method '{0}' not found"; - case IKVM.Internal.Message.MapFileFieldNotFound: - return "Field '{0}' referenced in remap file was not found in class '{1}'"; - case IKVM.Internal.Message.GhostInterfaceMethodMissing: - return "Remapped class '{0}' does not implement ghost interface method\n" + - "\t({1}.{2}{3})"; - default: - return "Missing Error Message. Please file a bug."; + } + + /// + /// Initializes a new instance. + /// + /// + /// + /// + internal FatalCompilerErrorException(Message id, Exception innerException, params object[] args) : + base($"fatal error IKVMC{(int)id}: {(args.Length == 0 ? GetMessage(id) : string.Format(GetMessage(id), args))}", innerException) + { + + } + + static string GetMessage(Message id) => id switch + { + IKVM.Internal.Message.ResponseFileDepthExceeded => "Response file nesting depth exceeded", + IKVM.Internal.Message.ErrorReadingFile => "Unable to read file: {0}\n\t({1})", + IKVM.Internal.Message.NoTargetsFound => "No targets found", + IKVM.Internal.Message.FileFormatLimitationExceeded => "File format limitation exceeded: {0}", + IKVM.Internal.Message.CannotSpecifyBothKeyFileAndContainer => "You cannot specify both a key file and container", + IKVM.Internal.Message.DelaySignRequiresKey => "You cannot delay sign without a key file or container", + IKVM.Internal.Message.InvalidStrongNameKeyPair => "Invalid key {0} specified.\n\t(\"{1}\")", + IKVM.Internal.Message.ReferenceNotFound => "Reference not found: {0}", + IKVM.Internal.Message.OptionsMustPreceedChildLevels => "You can only specify options before any child levels", + IKVM.Internal.Message.UnrecognizedTargetType => "Invalid value '{0}' for -target option", + IKVM.Internal.Message.UnrecognizedPlatform => "Invalid value '{0}' for -platform option", + IKVM.Internal.Message.UnrecognizedApartment => "Invalid value '{0}' for -apartment option", + IKVM.Internal.Message.MissingFileSpecification => "Missing file specification for '{0}' option", + IKVM.Internal.Message.PathTooLong => "Path too long: {0}", + IKVM.Internal.Message.PathNotFound => "Path not found: {0}", + IKVM.Internal.Message.InvalidPath => "Invalid path: {0}", + IKVM.Internal.Message.InvalidOptionSyntax => "Invalid option: {0}", + IKVM.Internal.Message.ExternalResourceNotFound => "External resource file does not exist: {0}", + IKVM.Internal.Message.ExternalResourceNameInvalid => "External resource file may not include path specification: {0}", + IKVM.Internal.Message.InvalidVersionFormat => "Invalid version specified: {0}", + IKVM.Internal.Message.InvalidFileAlignment => "Invalid value '{0}' for -filealign option", + IKVM.Internal.Message.ErrorWritingFile => "Unable to write file: {0}\n\t({1})", + IKVM.Internal.Message.UnrecognizedOption => "Unrecognized option: {0}", + IKVM.Internal.Message.NoOutputFileSpecified => "No output file specified", + IKVM.Internal.Message.SharedClassLoaderCannotBeUsedOnModuleTarget => "Incompatible options: -target:module and -sharedclassloader cannot be combined", + IKVM.Internal.Message.RuntimeNotFound => "Unable to load runtime assembly", + IKVM.Internal.Message.MainClassRequiresExe => "Main class cannot be specified for library or module", + IKVM.Internal.Message.ExeRequiresMainClass => "No main method found", + IKVM.Internal.Message.PropertiesRequireExe => "Properties cannot be specified for library or module", + IKVM.Internal.Message.ModuleCannotHaveClassLoader => "Cannot specify assembly class loader for modules", + IKVM.Internal.Message.ErrorParsingMapFile => "Unable to parse remap file: {0}\n\t({1})", + IKVM.Internal.Message.BootstrapClassesMissing => "Bootstrap classes missing and core assembly not found", + IKVM.Internal.Message.StrongNameRequiresStrongNamedRefs => "All referenced assemblies must be strong named, to be able to sign the output assembly", + IKVM.Internal.Message.MainClassNotFound => "Main class not found", + IKVM.Internal.Message.MainMethodNotFound => "Main method not found", + IKVM.Internal.Message.UnsupportedMainMethod => "Redirected main method not supported", + IKVM.Internal.Message.ExternalMainNotAccessible => "External main method must be public and in a public class", + IKVM.Internal.Message.ClassLoaderNotFound => "Custom assembly class loader class not found", + IKVM.Internal.Message.ClassLoaderNotAccessible => "Custom assembly class loader class is not accessible", + IKVM.Internal.Message.ClassLoaderIsAbstract => "Custom assembly class loader class is abstract", + IKVM.Internal.Message.ClassLoaderNotClassLoader => "Custom assembly class loader class does not extend java.lang.ClassLoader", + IKVM.Internal.Message.ClassLoaderConstructorMissing => "Custom assembly class loader constructor is missing", + IKVM.Internal.Message.MapFileTypeNotFound => "Type '{0}' referenced in remap file was not found", + IKVM.Internal.Message.MapFileClassNotFound => "Class '{0}' referenced in remap file was not found", + IKVM.Internal.Message.MaximumErrorCountReached => "Maximum error count reached", + IKVM.Internal.Message.LinkageError => "Link error: {0}", + IKVM.Internal.Message.RuntimeMismatch => "Referenced assembly {0} was compiled with an incompatible IKVM.Runtime version\n" + "\tCurrent runtime: {1}\n" + "\tReferenced assembly runtime: {2}", + IKVM.Internal.Message.CoreClassesMissing => "Failed to find core classes in core library", + IKVM.Internal.Message.CriticalClassNotFound => "Unable to load critical class '{0}'", + IKVM.Internal.Message.AssemblyContainsDuplicateClassNames => "Type '{0}' and '{1}' both map to the same name '{2}'\n" + "\t({3})", + IKVM.Internal.Message.CallerIDRequiresHasCallerIDAnnotation => "CallerID.getCallerID() requires a HasCallerID annotation", + IKVM.Internal.Message.UnableToResolveInterface => "Unable to resolve interface '{0}' on type '{1}'", + IKVM.Internal.Message.MissingBaseType => "The base class or interface '{0}' in assembly '{1}' referenced by type '{2}' in '{3}' could not be resolved", + IKVM.Internal.Message.MissingBaseTypeReference => "The type '{0}' is defined in an assembly that is not referenced. You must add a reference to assembly '{1}'", + IKVM.Internal.Message.FileNotFound => "File not found: {0}", + IKVM.Internal.Message.RuntimeMethodMissing => "Runtime method '{0}' not found", + IKVM.Internal.Message.MapFileFieldNotFound => "Field '{0}' referenced in remap file was not found in class '{1}'", + IKVM.Internal.Message.GhostInterfaceMethodMissing => "Remapped class '{0}' does not implement ghost interface method\n" + "\t({1}.{2}{3})", + _ => "Missing Error Message. Please file a bug.", + }; + } -} + +} \ No newline at end of file diff --git a/ikvmc/IKVM/Internal/MapXml/Redirect.cs b/ikvmc/IKVM/Internal/MapXml/Redirect.cs index 923bcc614d..89f0d32494 100644 --- a/ikvmc/IKVM/Internal/MapXml/Redirect.cs +++ b/ikvmc/IKVM/Internal/MapXml/Redirect.cs @@ -68,7 +68,7 @@ internal void Emit(ClassLoaderWrapper loader, CodeEmitter ilgen) if (Class.IndexOf(',') >= 0) { #if NETCOREAPP - Class = Class.Replace("mscorlib", Universe.CoreLibName); + Class = Class.Replace("mscorlib", Universe.StdLibName); #endif Type type = StaticCompiler.Universe.GetType(Class, true); MethodInfo mi = type.GetMethod(Name, redirParamTypes); diff --git a/ikvmc/IkvmcCompiler.cs b/ikvmc/IkvmcCompiler.cs index 2f9efe1fca..c3cbf6711d 100644 --- a/ikvmc/IkvmcCompiler.cs +++ b/ikvmc/IkvmcCompiler.cs @@ -33,8 +33,6 @@ Jeroen Frijters using IKVM.Reflection; using IKVM.Reflection.Emit; -using Type = IKVM.Reflection.Type; - namespace ikvmc { @@ -46,7 +44,6 @@ public sealed class IkvmcCompiler private string defaultAssemblyName; private static bool time; private static string runtimeAssembly; - private static bool nostdlib; private static bool nonDeterministicOutput; private static readonly List libpaths = new List(); internal static readonly AssemblyResolver resolver = new AssemblyResolver(); @@ -80,6 +77,7 @@ private static void AddArg(List arglist, string s, int depth) } catch (Exception x) { + Console.WriteLine(x.StackTrace); throw new FatalCompilerErrorException(Message.ErrorReadingFile, s.Substring(1), x.Message); } } @@ -174,7 +172,7 @@ static int Compile(string[] args) comp.ParseCommandLine(argList.GetEnumerator(), targets, toplevel); StaticCompiler.Init(nonDeterministicOutput); resolver.Warning += loader_Warning; - resolver.Init(StaticCompiler.Universe, nostdlib, toplevel.unresolvedReferences, libpaths); + resolver.Init(StaticCompiler.Universe, toplevel.unresolvedReferences, libpaths); ResolveReferences(targets); ResolveStrongNameKeys(targets); if (targets.Count == 0) @@ -274,6 +272,7 @@ internal static byte[] ReadAllBytes(FileInfo path) } catch (Exception x) { + Console.WriteLine(x.StackTrace); throw new FatalCompilerErrorException(Message.ErrorReadingFile, path.ToString(), x.Message); } } @@ -379,7 +378,6 @@ private static void PrintHelp() Console.Error.WriteLine("-baseaddress:
Base address for the library to be built"); Console.Error.WriteLine("-filealign: Specify the alignment used for output file"); Console.Error.WriteLine("-nopeercrossreference Do not automatically cross reference all peers"); - Console.Error.WriteLine("-nostdlib Do not reference standard libraries"); Console.Error.WriteLine("-lib: Additional directories to search for references"); Console.Error.WriteLine("-highentropyva Enable high entropy ASLR"); Console.Error.WriteLine("-static Disable dynamic binding"); @@ -551,12 +549,11 @@ void ContinueParseCommandLine(IEnumerator arglist, List } else if (s.StartsWith("-reference:") || s.StartsWith("-r:")) { - string r = s.Substring(s.IndexOf(':') + 1); + var r = s.Substring(s.IndexOf(':') + 1); if (r == "") - { throw new FatalCompilerErrorException(Message.MissingFileSpecification, s); - } - ArrayAppend(ref options.unresolvedReferences, r); + + options.unresolvedReferences.Add(r); } else if (s.StartsWith("-recurse:")) { @@ -712,12 +709,12 @@ void ContinueParseCommandLine(IEnumerator arglist, List else if (s.StartsWith("-privatepackage:")) { string prefix = s.Substring(16); - ArrayAppend(ref options.privatePackages, prefix); + options.privatePackages.Add(prefix); } else if (s.StartsWith("-publicpackage:")) { string prefix = s.Substring(15); - ArrayAppend(ref options.publicPackages, prefix); + options.publicPackages.Add(prefix); } else if (s.StartsWith("-nowarn:")) { @@ -800,11 +797,6 @@ void ContinueParseCommandLine(IEnumerator arglist, List { options.crossReferenceAllPeers = false; } - else if (s == "-nostdlib") - { - // this is a global option - nostdlib = true; - } else if (s.StartsWith("-lib:")) { // this is a global option @@ -858,7 +850,7 @@ void ContinueParseCommandLine(IEnumerator arglist, List } else if (s.StartsWith("-assemblyattributes:", StringComparison.Ordinal)) { - ProcessAttributeAnnotationsClass(ref options.assemblyAttributeAnnotations, s.Substring(20)); + ProcessAttributeAnnotationsClass(options.assemblyAttributeAnnotations, s.Substring(20)); } else if (s == "-w4") // undocumented option to always warn if a class isn't found { @@ -1055,8 +1047,8 @@ static void SetStrongNameKeyPair(ref StrongNameKeyPair strongNameKeyPair, FileIn static void ResolveReferences(List targets) { - Dictionary cache = new Dictionary(); - foreach (CompilerOptions target in targets) + var cache = new Dictionary(); + foreach (var target in targets) { if (target.unresolvedReferences != null) { @@ -1066,15 +1058,15 @@ static void ResolveReferences(List targets) { if (peer.assembly.Equals(reference, StringComparison.OrdinalIgnoreCase)) { - ArrayAppend(ref target.peerReferences, peer.assembly); + target.peerReferences.Add(peer.assembly); goto next_reference; } } - if (!resolver.ResolveReference(cache, ref target.references, reference)) - { + + if (!resolver.ResolveReference(cache, target.references, reference)) throw new FatalCompilerErrorException(Message.ReferenceNotFound, reference); - } - next_reference:; + + next_reference:; } } } @@ -1083,64 +1075,20 @@ static void ResolveReferences(List targets) { if (target.references != null) { - foreach (Assembly asm in target.references) + foreach (var asm in target.references) { - Type forwarder = asm.GetType("__"); + var forwarder = asm.GetType("__"); if (forwarder != null && forwarder.Assembly != asm) - { StaticCompiler.IssueMessage(Message.NonPrimaryAssemblyReference, asm.Location, forwarder.Assembly.GetName().Name); - } } } } - // add legacy references (from stub files) - foreach (CompilerOptions target in targets) - { - foreach (string assemblyName in target.legacyStubReferences.Keys) - { - ArrayAppend(ref target.references, resolver.LegacyLoad(new AssemblyName(assemblyName), null)); - } - } - // now pre-load the secondary assemblies of any shared class loader groups foreach (CompilerOptions target in targets) - { if (target.references != null) - { foreach (Assembly asm in target.references) - { AssemblyClassLoader.PreloadExportedAssemblies(asm); - } - } - } - } - - private static void ArrayAppend(ref T[] array, T element) - { - if (array == null) - { - array = new T[] { element }; - } - else - { - array = ArrayUtil.Concat(array, element); - } - } - - private static void ArrayAppend(ref T[] array, T[] append) - { - if (array == null) - { - array = append; - } - else if (append != null) - { - T[] tmp = new T[array.Length + append.Length]; - Array.Copy(array, tmp, array.Length); - Array.Copy(append, 0, tmp, array.Length, append.Length); - array = tmp; - } } private static byte[] ReadFromZip(ZipFile zf, ZipEntry ze) @@ -1155,7 +1103,13 @@ private static byte[] ReadFromZip(ZipFile zf, ZipEntry ze) return buf; } - private static bool EmitStubWarning(CompilerOptions options, byte[] buf) + /// + /// Emits a warning if the the class file is a stub. + /// + /// + /// + /// + static bool EmitStubWarning(CompilerOptions options, byte[] buf) { ClassFile cf; try @@ -1166,56 +1120,62 @@ private static bool EmitStubWarning(CompilerOptions options, byte[] buf) { return false; } + if (cf.IKVMAssemblyAttribute == null) - { return false; - } + if (cf.IKVMAssemblyAttribute.StartsWith("[[")) { - Regex r = new Regex(@"\[([^\[\]]+)\]"); - MatchCollection mc = r.Matches(cf.IKVMAssemblyAttribute); + var r = new Regex(@"\[([^\[\]]+)\]"); + var mc = r.Matches(cf.IKVMAssemblyAttribute); foreach (Match m in mc) { options.legacyStubReferences[m.Groups[1].Value] = null; - StaticCompiler.IssueMessage(options, Message.StubsAreDeprecated, m.Groups[1].Value); + StaticCompiler.IssueMessage(options, Message.StubsAreInvalid, m.Groups[1].Value); } } else { options.legacyStubReferences[cf.IKVMAssemblyAttribute] = null; - StaticCompiler.IssueMessage(options, Message.StubsAreDeprecated, cf.IKVMAssemblyAttribute); + StaticCompiler.IssueMessage(options, Message.StubsAreInvalid, cf.IKVMAssemblyAttribute); } + return true; } - private static bool IsExcludedOrStubLegacy(CompilerOptions options, ZipEntry ze, byte[] data) + /// + /// Returns true if the class file is excluded from compilation, or a stub file. + /// + /// + /// + /// + /// + static bool IsExcludedOrStub(CompilerOptions options, ZipEntry ze, byte[] data) { if (ze.Name.EndsWith(".class", StringComparison.OrdinalIgnoreCase)) { try { - bool stub; - string name = ClassFile.GetClassName(data, 0, data.Length, out stub); + var name = ClassFile.GetClassName(data, 0, data.Length, out bool stub); if (options.IsExcludedClass(name) || (stub && EmitStubWarning(options, data))) - { - // we use stubs to add references, but otherwise ignore them return true; - } } catch (ClassFormatError) { + } } + return false; } - private void ProcessManifest(CompilerOptions options, ZipFile zf, ZipEntry ze) + void ProcessManifest(CompilerOptions options, ZipFile zf, ZipEntry ze) { if (manifestMainClass == null) { // read main class from manifest // TODO find out if we can use other information from manifest - StreamReader rdr = new StreamReader(zf.GetInputStream(ze)); + var rdr = new StreamReader(zf.GetInputStream(ze)); string line; while ((line = rdr.ReadLine()) != null) { @@ -1235,7 +1195,7 @@ private void ProcessManifest(CompilerOptions options, ZipFile zf, ZipEntry ze) } } - private bool ProcessZipFile(CompilerOptions options, string file, Predicate filter) + bool ProcessZipFile(CompilerOptions options, string file, Predicate filter) { try { @@ -1254,7 +1214,7 @@ private bool ProcessZipFile(CompilerOptions options, string file, Predicate annotations, string filename) { try { - byte[] buf = File.ReadAllBytes(filename); - ClassFile cf = new ClassFile(buf, 0, buf.Length, null, ClassFileParseOptions.None, null); - ArrayAppend(ref annotations, cf.Annotations); + var buf = File.ReadAllBytes(filename); + var cf = new ClassFile(buf, 0, buf.Length, null, ClassFileParseOptions.None, null); + annotations.AddRange(cf.Annotations); } catch (Exception x) { + Console.WriteLine(x.StackTrace); throw new FatalCompilerErrorException(Message.ErrorReadingFile, filename, x.Message); } } diff --git a/ikvmc/ikvmc.csproj b/ikvmc/ikvmc.csproj index 503d6f7903..4fd5e33c28 100644 --- a/ikvmc/ikvmc.csproj +++ b/ikvmc/ikvmc.csproj @@ -9,7 +9,6 @@ JVM for .NET $(DefineConstants);STATIC_COMPILER;EMITTERS true - true diff --git a/ikvmstub.Tests/IkvmstubTests.cs b/ikvmstub.Tests/IkvmstubTests.cs new file mode 100644 index 0000000000..5be54f025d --- /dev/null +++ b/ikvmstub.Tests/IkvmstubTests.cs @@ -0,0 +1,39 @@ +using System.IO; +using System.Linq; +using System.Runtime.InteropServices; + +using FluentAssertions; + +using Microsoft.VisualStudio.TestTools.UnitTesting; + +#if NETCOREAPP3_1_OR_GREATER +using Microsoft.Extensions.DependencyModel; +#endif + +namespace ikvmstub.Tests +{ + + [TestClass] + public class IkvmstubTests + { + + [TestMethod] + public void Can_stub_system_runtime() + { +#if NET461 + var a = new[] { $"-lib:{RuntimeEnvironment.GetRuntimeDirectory()}" }; + var j = Path.Combine(RuntimeEnvironment.GetRuntimeDirectory(), "mscorlib.dll"); +#else + var a = DependencyContext.Default.CompileLibraries.SelectMany(i => i.ResolveReferencePaths()).Select(i => $"-r:{i}"); + var j = DependencyContext.Default.CompileLibraries.Where(i => i.Name == "netstandard").SelectMany(i => i.ResolveReferencePaths()).FirstOrDefault(); +#endif + + var jar = Path.Combine(Path.GetTempPath(), Path.GetFileName(Path.ChangeExtension(j, ".jar"))); + var ret = Program.Main(a.Concat(new[] { "-bootstrap", $"-r:{Path.Combine(Path.GetDirectoryName(typeof(IkvmstubTests).Assembly.Location), "IKVM.Runtime.dll")}", $"-out:{jar}", j }).ToArray()); + ret.Should().Be(0); + File.Exists(jar).Should().BeTrue(); + } + + } + +} diff --git a/ikvmstub.Tests/ikvmstub.Tests.csproj b/ikvmstub.Tests/ikvmstub.Tests.csproj new file mode 100644 index 0000000000..8277a7b923 --- /dev/null +++ b/ikvmstub.Tests/ikvmstub.Tests.csproj @@ -0,0 +1,22 @@ + + + + net461;netcoreapp3.1;net5.0;net6.0 + true + + + + + + + + + + + + + + + + + diff --git a/ikvmstub/ikvmstub.cs b/ikvmstub/ikvmstub.cs index 413d48b32c..25710b8cdc 100644 --- a/ikvmstub/ikvmstub.cs +++ b/ikvmstub/ikvmstub.cs @@ -34,592 +34,589 @@ Jeroen Frijters using Type = IKVM.Reflection.Type; -public static class NetExp +namespace IKVM.Internal { - private static int zipCount; - private static ZipOutputStream zipFile; - private static Dictionary done = new Dictionary(); - private static Dictionary todo = new Dictionary(); - private static FileInfo file; - private static bool includeSerialVersionUID; - private static bool includeNonPublicInterfaces; - private static bool includeNonPublicMembers; - private static bool includeParameterNames; - private static List namespaces = new List(); - - public static int Main(string[] args) + + static class Intrinsics { - IKVM.Internal.Tracer.EnableTraceConsoleListener(); - IKVM.Internal.Tracer.EnableTraceForDebug(); - string assemblyNameOrPath = null; - bool continueOnError = false; - bool autoLoadSharedClassLoaderAssemblies = false; - List references = new List(); - List libpaths = new List(); - bool nostdlib = false; - bool bootstrap = false; - string outputFile = null; - bool forwarders = false; - foreach (string s in args) + + internal static bool IsIntrinsic(MethodWrapper methodWrapper) { - if (s.StartsWith("-") || assemblyNameOrPath != null) - { - if (s == "-serialver") - { - Console.Error.WriteLine("The -serialver option is deprecated and will be removed in the future. Use -japi instead."); - includeSerialVersionUID = true; - } - else if (s == "-japi") - { - includeSerialVersionUID = true; - includeNonPublicInterfaces = true; - includeNonPublicMembers = true; - } - else if (s == "-skiperror") - { - continueOnError = true; - } - else if (s == "-shared") - { - autoLoadSharedClassLoaderAssemblies = true; - } - else if (s.StartsWith("-r:") || s.StartsWith("-reference:")) - { - references.Add(s.Substring(s.IndexOf(':') + 1)); - } - else if (s == "-nostdlib") - { - nostdlib = true; - } - else if (s.StartsWith("-lib:")) - { - libpaths.Add(s.Substring(5)); - } - else if (s == "-bootstrap") - { - bootstrap = true; - } - else if (s.StartsWith("-out:")) - { - outputFile = s.Substring(5); - } - else if (s.StartsWith("-namespace:")) - { - namespaces.Add(s.Substring(11) + "."); - } - else if (s == "-forwarders") - { - forwarders = true; - } - else if (s == "-parameters") - { - includeParameterNames = true; - } - else - { - // unrecognized option, or multiple assemblies, print usage message and exit - assemblyNameOrPath = null; - break; - } - } - else - { - assemblyNameOrPath = s; - } + return false; } - if (assemblyNameOrPath == null) + + } + + static class StaticCompiler + { + + internal static readonly Universe Universe = new Universe(UniverseOptions.EnableFunctionPointers); + internal static readonly AssemblyResolver Resolver = new AssemblyResolver(); + internal static Assembly runtimeAssembly; + + internal static Type GetRuntimeType(string typeName) { - Console.Error.WriteLine(GetVersionAndCopyrightInfo()); - Console.Error.WriteLine(); - Console.Error.WriteLine("usage: ikvmstub [-options] "); - Console.Error.WriteLine(); - Console.Error.WriteLine("options:"); - Console.Error.WriteLine(" -out: Specify the output filename"); - Console.Error.WriteLine(" -reference: Reference an assembly (short form -r:)"); - Console.Error.WriteLine(" -japi Generate jar suitable for comparison with japitools"); - Console.Error.WriteLine(" -skiperror Continue when errors are encountered"); - Console.Error.WriteLine(" -shared Process all assemblies in shared group"); - Console.Error.WriteLine(" -nostdlib Do not reference standard libraries"); - Console.Error.WriteLine(" -lib: Additional directories to search for references"); - Console.Error.WriteLine(" -namespace: Only include types from specified namespace"); - Console.Error.WriteLine(" -forwarders Export forwarded types too"); - Console.Error.WriteLine(" -parameters Emit Java 8 classes with parameter names"); - return 1; + return runtimeAssembly.GetType(typeName, true); } - if (File.Exists(assemblyNameOrPath) && nostdlib) + internal static Assembly LoadFile(string fileName) { - // Add the target assembly to the references list, to allow it to be considered as "mscorlib". - // This allows "ikvmstub -nostdlib \...\mscorlib.dll" to work. - references.Add(assemblyNameOrPath); + return Resolver.LoadFile(fileName); } - StaticCompiler.Resolver.Warning += new AssemblyResolver.WarningEvent(Resolver_Warning); - StaticCompiler.Resolver.Init(StaticCompiler.Universe, nostdlib, references, libpaths); - Dictionary cache = new Dictionary(); - foreach (string reference in references) + internal static Assembly Load(string name) { - Assembly[] dummy = null; - if (!StaticCompiler.Resolver.ResolveReference(cache, ref dummy, reference)) - { - Console.Error.WriteLine("Error: reference not found {0}", reference); - return 1; - } + return Universe.Load(name); + } + } + + static class FakeTypes + { + private static readonly Type genericType; + + class Holder { } + + static FakeTypes() + { + genericType = StaticCompiler.Universe.Import(typeof(Holder<>)); + } + + internal static Type GetAttributeType(Type type) + { + return genericType.MakeGenericType(type); + } + + internal static Type GetAttributeReturnValueType(Type type) + { + return genericType.MakeGenericType(type); + } + + internal static Type GetAttributeMultipleType(Type type) + { + return genericType.MakeGenericType(type); + } + + internal static Type GetDelegateType(Type type) + { + return genericType.MakeGenericType(type); + } + + internal static Type GetEnumType(Type type) + { + return genericType.MakeGenericType(type); } - Assembly assembly = null; - try + } + + sealed class BootstrapBootstrapClassLoader : ClassLoaderWrapper + { + + internal BootstrapBootstrapClassLoader() + : base(CodeGenOptions.None, null) { - file = new FileInfo(assemblyNameOrPath); + var javaLangObject = new StubTypeWrapper(Modifiers.Public, "java.lang.Object", null, true); + SetRemappedType(JVM.Import(typeof(object)), javaLangObject); + SetRemappedType(JVM.Import(typeof(string)), new StubTypeWrapper(Modifiers.Public | Modifiers.Final, "java.lang.String", javaLangObject, true)); + SetRemappedType(JVM.Import(typeof(Exception)), new StubTypeWrapper(Modifiers.Public, "java.lang.Throwable", javaLangObject, true)); + SetRemappedType(JVM.Import(typeof(IComparable)), new StubTypeWrapper(Modifiers.Public | Modifiers.Abstract | Modifiers.Interface, "java.lang.Comparable", null, true)); + var tw = new StubTypeWrapper(Modifiers.Public | Modifiers.Abstract | Modifiers.Interface, "java.lang.AutoCloseable", null, true); + tw.SetMethods(new MethodWrapper[] { new SimpleCallMethodWrapper(tw, "close", "()V", JVM.Import(typeof(IDisposable)).GetMethod("Dispose"), PrimitiveTypeWrapper.VOID, TypeWrapper.EmptyArray, Modifiers.Public | Modifiers.Abstract, MemberFlags.None, SimpleOpCode.Callvirt, SimpleOpCode.Callvirt) }); + SetRemappedType(JVM.Import(typeof(IDisposable)), tw); + + RegisterInitiatingLoader(new StubTypeWrapper(Modifiers.Public, "java.lang.Enum", javaLangObject, false)); + RegisterInitiatingLoader(new StubTypeWrapper(Modifiers.Public | Modifiers.Abstract | Modifiers.Interface, "java.lang.annotation.Annotation", null, false)); + RegisterInitiatingLoader(new StubTypeWrapper(Modifiers.Public | Modifiers.Final, "java.lang.Class", javaLangObject, false)); + RegisterInitiatingLoader(new StubTypeWrapper(Modifiers.Public | Modifiers.Abstract, "java.lang.invoke.MethodHandle", javaLangObject, false)); } - catch (System.Exception x) + + } + + sealed class StubTypeWrapper : TypeWrapper + { + private readonly bool remapped; + private readonly TypeWrapper baseWrapper; + + internal StubTypeWrapper(Modifiers modifiers, string name, TypeWrapper baseWrapper, bool remapped) + : base(TypeFlags.None, modifiers, name) { - Console.Error.WriteLine("Error: unable to load \"{0}\"\n {1}", assemblyNameOrPath, x.Message); - return 1; + this.remapped = remapped; + this.baseWrapper = baseWrapper; } - if (file != null && file.Exists) + + internal override TypeWrapper BaseTypeWrapper { - assembly = StaticCompiler.LoadFile(assemblyNameOrPath); + get { return baseWrapper; } } - else + + internal override ClassLoaderWrapper GetClassLoader() + { + return ClassLoaderWrapper.GetBootstrapClassLoader(); + } + + internal override Type TypeAsTBD { - assembly = StaticCompiler.Resolver.LoadWithPartialName(assemblyNameOrPath); + get { throw new NotSupportedException(); } } - int rc = 0; - if (assembly == null) + + internal override bool IsRemapped { - Console.Error.WriteLine("Error: Assembly \"{0}\" not found", assemblyNameOrPath); + get { return remapped; } } - else + } + +} + +namespace ikvmstub +{ + + public static class Program + { + + private static int zipCount; + private static ZipOutputStream zipFile; + private static Dictionary done = new Dictionary(); + private static Dictionary todo = new Dictionary(); + private static FileInfo file; + private static bool includeSerialVersionUID; + private static bool includeNonPublicInterfaces; + private static bool includeNonPublicMembers; + private static bool includeParameterNames; + private static List namespaces = new List(); + + public static int Main(string[] args) { - if (bootstrap) + + IKVM.Internal.Tracer.EnableTraceConsoleListener(); + IKVM.Internal.Tracer.EnableTraceForDebug(); + string assemblyNameOrPath = null; + bool continueOnError = false; + bool autoLoadSharedClassLoaderAssemblies = false; + List references = new List(); + List libpaths = new List(); + bool bootstrap = false; + string outputFile = null; + bool forwarders = false; + foreach (string s in args) { - StaticCompiler.runtimeAssembly = StaticCompiler.LoadFile(typeof(NetExp).Assembly.Location); - ClassLoaderWrapper.SetBootstrapClassLoader(new BootstrapBootstrapClassLoader()); + if (s.StartsWith("-") || assemblyNameOrPath != null) + { + if (s == "-serialver") + { + Console.Error.WriteLine("The -serialver option is deprecated and will be removed in the future. Use -japi instead."); + includeSerialVersionUID = true; + } + else if (s == "-japi") + { + includeSerialVersionUID = true; + includeNonPublicInterfaces = true; + includeNonPublicMembers = true; + } + else if (s == "-skiperror") + { + continueOnError = true; + } + else if (s == "-shared") + { + autoLoadSharedClassLoaderAssemblies = true; + } + else if (s.StartsWith("-r:") || s.StartsWith("-reference:")) + { + references.Add(s.Substring(s.IndexOf(':') + 1)); + } + else if (s.StartsWith("-lib:")) + { + libpaths.Add(s.Substring(5)); + } + else if (s == "-bootstrap") + { + bootstrap = true; + } + else if (s.StartsWith("-out:")) + { + outputFile = s.Substring(5); + } + else if (s.StartsWith("-namespace:")) + { + namespaces.Add(s.Substring(11) + "."); + } + else if (s == "-forwarders") + { + forwarders = true; + } + else if (s == "-parameters") + { + includeParameterNames = true; + } + else + { + // unrecognized option, or multiple assemblies, print usage message and exit + assemblyNameOrPath = null; + break; + } + } + else + { + assemblyNameOrPath = s; + } } - else + if (assemblyNameOrPath == null) { - StaticCompiler.LoadFile(typeof(NetExp).Assembly.Location); - StaticCompiler.runtimeAssembly = StaticCompiler.LoadFile(Path.GetFullPath(Path.Combine(typeof(NetExp).Assembly.Location, "../IKVM.Runtime.dll"))); - JVM.CoreAssembly = StaticCompiler.LoadFile(Path.GetFullPath(Path.Combine(typeof(NetExp).Assembly.Location, "../IKVM.Java.dll"))); + Console.Error.WriteLine(GetVersionAndCopyrightInfo()); + Console.Error.WriteLine(); + Console.Error.WriteLine("usage: ikvmstub [-options] "); + Console.Error.WriteLine(); + Console.Error.WriteLine("options:"); + Console.Error.WriteLine(" -out: Specify the output filename"); + Console.Error.WriteLine(" -reference: Reference an assembly (short form -r:)"); + Console.Error.WriteLine(" -japi Generate jar suitable for comparison with japitools"); + Console.Error.WriteLine(" -skiperror Continue when errors are encountered"); + Console.Error.WriteLine(" -shared Process all assemblies in shared group"); + Console.Error.WriteLine(" -lib: Additional directories to search for references"); + Console.Error.WriteLine(" -namespace: Only include types from specified namespace"); + Console.Error.WriteLine(" -forwarders Export forwarded types too"); + Console.Error.WriteLine(" -parameters Emit Java 8 classes with parameter names"); + return 1; } - if (AttributeHelper.IsJavaModule(assembly.ManifestModule)) + + if (File.Exists(assemblyNameOrPath)) + references.Add(assemblyNameOrPath); + + StaticCompiler.Resolver.Warning += new AssemblyResolver.WarningEvent(Resolver_Warning); + StaticCompiler.Resolver.Init(StaticCompiler.Universe, references, libpaths); + Dictionary cache = new Dictionary(); + foreach (string reference in references) { - Console.Error.WriteLine("Warning: Running ikvmstub on ikvmc compiled assemblies is not supported."); + var dummy = new List(); + if (!StaticCompiler.Resolver.ResolveReference(cache, dummy, reference)) + { + Console.Error.WriteLine("Error: reference not found {0}", reference); + return 1; + } } - if (outputFile == null) + Assembly assembly = null; + try { - outputFile = assembly.GetName().Name + ".jar"; + file = new FileInfo(assemblyNameOrPath); } - try + catch (System.Exception x) { - using (zipFile = new ZipOutputStream(new FileStream(outputFile, FileMode.Create))) + Console.Error.WriteLine("Error: unable to load \"{0}\"\n {1}", assemblyNameOrPath, x.Message); + return 1; + } + if (file != null && file.Exists) + { + assembly = StaticCompiler.LoadFile(assemblyNameOrPath); + } + else + { + assembly = StaticCompiler.Resolver.LoadWithPartialName(assemblyNameOrPath); + } + int rc = 0; + if (assembly == null) + { + Console.Error.WriteLine("Error: Assembly \"{0}\" not found", assemblyNameOrPath); + } + else + { + if (bootstrap) { - zipFile.SetComment(GetVersionAndCopyrightInfo()); - try + StaticCompiler.runtimeAssembly = StaticCompiler.LoadFile(typeof(Program).Assembly.Location); + ClassLoaderWrapper.SetBootstrapClassLoader(new BootstrapBootstrapClassLoader()); + } + else + { + StaticCompiler.LoadFile(typeof(Program).Assembly.Location); + StaticCompiler.runtimeAssembly = StaticCompiler.LoadFile(Path.GetFullPath(Path.Combine(typeof(Program).Assembly.Location, "..", "IKVM.Runtime.dll"))); + JVM.CoreAssembly = StaticCompiler.LoadFile(Path.GetFullPath(Path.Combine(typeof(Program).Assembly.Location, "..", "IKVM.Java.dll"))); + } + if (AttributeHelper.IsJavaModule(assembly.ManifestModule)) + { + Console.Error.WriteLine("Warning: Running ikvmstub on ikvmc compiled assemblies is not supported."); + } + if (outputFile == null) + { + outputFile = assembly.GetName().Name + ".jar"; + } + try + { + using (zipFile = new ZipOutputStream(new FileStream(outputFile, FileMode.Create))) { - List assemblies = new List(); - assemblies.Add(assembly); - if (autoLoadSharedClassLoaderAssemblies) - { - LoadSharedClassLoaderAssemblies(assembly, assemblies); - } - foreach (Assembly asm in assemblies) + zipFile.SetComment(GetVersionAndCopyrightInfo()); + try { - if (ProcessTypes(asm.GetTypes(), continueOnError) != 0) + List assemblies = new List(); + assemblies.Add(assembly); + if (autoLoadSharedClassLoaderAssemblies) { - rc = 1; - if (!continueOnError) - { - break; - } + LoadSharedClassLoaderAssemblies(assembly, assemblies); } - if (forwarders && ProcessTypes(asm.ManifestModule.__GetExportedTypes(), continueOnError) != 0) + foreach (Assembly asm in assemblies) { - rc = 1; - if (!continueOnError) + if (ProcessTypes(asm.GetTypes(), continueOnError) != 0) { - break; + rc = 1; + if (!continueOnError) + { + break; + } + } + if (forwarders && ProcessTypes(asm.ManifestModule.__GetExportedTypes(), continueOnError) != 0) + { + rc = 1; + if (!continueOnError) + { + break; + } } } } - } - catch (System.Exception x) - { - Console.Error.WriteLine(x); - - if (!continueOnError) + catch (System.Exception x) { - Console.Error.WriteLine("Warning: Assembly reflection encountered an error. Resultant JAR may be incomplete."); - } + Console.Error.WriteLine(x); - rc = 1; + if (!continueOnError) + { + Console.Error.WriteLine("Warning: Assembly reflection encountered an error. Resultant JAR may be incomplete."); + } + + rc = 1; + } } } - } - catch (ZipException x) - { - rc = 1; - if (zipCount == 0) + catch (ZipException x) { - Console.Error.WriteLine("Error: Assembly contains no public IKVM.NET compatible types"); - } - else - { - Console.Error.WriteLine("Error: {0}", x.Message); + rc = 1; + if (zipCount == 0) + { + Console.Error.WriteLine("Error: Assembly contains no public IKVM.NET compatible types"); + } + else + { + Console.Error.WriteLine("Error: {0}", x.Message); + } } } + return rc; } - return rc; - } - static void Resolver_Warning(AssemblyResolver.WarningId warning, string message, string[] parameters) - { - if (warning != AssemblyResolver.WarningId.HigherVersion) + static void Resolver_Warning(AssemblyResolver.WarningId warning, string message, string[] parameters) { - Console.Error.WriteLine("Warning: " + message, parameters); + if (warning != AssemblyResolver.WarningId.HigherVersion) + { + Console.Error.WriteLine("Warning: " + message, parameters); + } } - } - private static string GetVersionAndCopyrightInfo() - { - System.Reflection.Assembly asm = System.Reflection.Assembly.GetEntryAssembly(); - object[] desc = asm.GetCustomAttributes(typeof(System.Reflection.AssemblyTitleAttribute), false); - if (desc.Length == 1) + static string GetVersionAndCopyrightInfo() { - object[] copyright = asm.GetCustomAttributes(typeof(System.Reflection.AssemblyCopyrightAttribute), false); - if (copyright.Length == 1) - { - return string.Format("{0} version {1}{2}{3}", // TODO: Add domain once we get one {2}http://www.ikvm.net/ - ((System.Reflection.AssemblyTitleAttribute)desc[0]).Title, - asm.GetName().Version, - Environment.NewLine, - ((System.Reflection.AssemblyCopyrightAttribute)copyright[0]).Copyright); - } + var asm = typeof(Program).Assembly; + var desc = System.Reflection.CustomAttributeExtensions.GetCustomAttribute(asm); + var copy = System.Reflection.CustomAttributeExtensions.GetCustomAttribute(asm); + var info = System.Reflection.CustomAttributeExtensions.GetCustomAttribute(asm); + return $"{desc.Title} ({info.InformationalVersion}){Environment.NewLine}{copy.Copyright}"; // TODO: Add domain once we get one {Environment.NewLine}http://www.ikvm.org/ } - return ""; - } - private static void LoadSharedClassLoaderAssemblies(Assembly assembly, List assemblies) - { - if (assembly.GetManifestResourceInfo("ikvm.exports") != null) + private static void LoadSharedClassLoaderAssemblies(Assembly assembly, List assemblies) { - using (Stream stream = assembly.GetManifestResourceStream("ikvm.exports")) + if (assembly.GetManifestResourceInfo("ikvm.exports") != null) { - BinaryReader rdr = new BinaryReader(stream); - int assemblyCount = rdr.ReadInt32(); - for (int i = 0; i < assemblyCount; i++) + using (Stream stream = assembly.GetManifestResourceStream("ikvm.exports")) { - string name = rdr.ReadString(); - int typeCount = rdr.ReadInt32(); - if (typeCount > 0) + BinaryReader rdr = new BinaryReader(stream); + int assemblyCount = rdr.ReadInt32(); + for (int i = 0; i < assemblyCount; i++) { - for (int j = 0; j < typeCount; j++) - { - rdr.ReadInt32(); - } - try + string name = rdr.ReadString(); + int typeCount = rdr.ReadInt32(); + if (typeCount > 0) { - assemblies.Add(StaticCompiler.Load(name)); - } - catch - { - Console.WriteLine("Warning: Unable to load shared class loader assembly: {0}", name); + for (int j = 0; j < typeCount; j++) + { + rdr.ReadInt32(); + } + try + { + assemblies.Add(StaticCompiler.Load(name)); + } + catch + { + Console.WriteLine("Warning: Unable to load shared class loader assembly: {0}", name); + } } } } } } - } - private static void WriteClass(TypeWrapper tw) - { - zipCount++; - MemoryStream mem = new MemoryStream(); - IKVM.StubGen.StubGenerator.WriteClass(mem, tw, includeNonPublicInterfaces, includeNonPublicMembers, includeSerialVersionUID, includeParameterNames); - ZipEntry entry = new ZipEntry(tw.Name.Replace('.', '/') + ".class"); - entry.Size = mem.Position; - entry.DateTime = new DateTime(1980, 01, 01, 0, 0, 0, DateTimeKind.Utc); - zipFile.PutNextEntry(entry); - mem.WriteTo(zipFile); - } - - private static bool ExportNamespace(Type type) - { - if (namespaces.Count == 0) + private static void WriteClass(TypeWrapper tw) { - return true; + zipCount++; + MemoryStream mem = new MemoryStream(); + IKVM.StubGen.StubGenerator.WriteClass(mem, tw, includeNonPublicInterfaces, includeNonPublicMembers, includeSerialVersionUID, includeParameterNames); + ZipEntry entry = new ZipEntry(tw.Name.Replace('.', '/') + ".class"); + entry.Size = mem.Position; + entry.DateTime = new DateTime(1980, 01, 01, 0, 0, 0, DateTimeKind.Utc); + zipFile.PutNextEntry(entry); + mem.WriteTo(zipFile); } - string name = type.FullName; - foreach (string ns in namespaces) + + private static bool ExportNamespace(Type type) { - if (name.StartsWith(ns, StringComparison.Ordinal)) + if (namespaces.Count == 0) { return true; } - } - return false; - } - - private static int ProcessTypes(Type[] types, bool continueOnError) - { - int rc = 0; - foreach (Type t in types) - { - if (t.IsPublic - && ExportNamespace(t) - && !t.IsGenericTypeDefinition - && !AttributeHelper.IsHideFromJava(t) - && (!t.IsGenericType || !AttributeHelper.IsJavaModule(t.Module))) + string name = type.FullName; + foreach (string ns in namespaces) { - TypeWrapper c; - if (ClassLoaderWrapper.IsRemappedType(t) || t.IsPrimitive || t == Types.Void) - { - c = DotNetTypeWrapper.GetWrapperFromDotNetType(t); - } - else - { - c = ClassLoaderWrapper.GetWrapperFromType(t); - } - if (c != null) + if (name.StartsWith(ns, StringComparison.Ordinal)) { - AddToExportList(c); + return true; } } + return false; } - bool keepGoing; - do + private static int ProcessTypes(Type[] types, bool continueOnError) { - keepGoing = false; - foreach (TypeWrapper c in new List(todo.Values).OrderBy(i => i.Name)) + int rc = 0; + foreach (Type t in types) { - if (!done.ContainsKey(c.Name)) + if (t.IsPublic + && ExportNamespace(t) + && !t.IsGenericTypeDefinition + && !AttributeHelper.IsHideFromJava(t) + && (!t.IsGenericType || !AttributeHelper.IsJavaModule(t.Module))) { - keepGoing = true; - done.Add(c.Name, null); - - try + TypeWrapper c; + if (ClassLoaderWrapper.IsRemappedType(t) || t.IsPrimitive || t == Types.Void) + { + c = DotNetTypeWrapper.GetWrapperFromDotNetType(t); + } + else { - ProcessClass(c); - WriteClass(c); + c = ClassLoaderWrapper.GetWrapperFromType(t); } - catch (Exception x) + if (c != null) { - if (continueOnError) + AddToExportList(c); + } + } + } + + bool keepGoing; + do + { + keepGoing = false; + foreach (TypeWrapper c in new List(todo.Values).OrderBy(i => i.Name)) + { + if (!done.ContainsKey(c.Name)) + { + keepGoing = true; + done.Add(c.Name, null); + + try { - rc = 1; - Console.WriteLine(x); + ProcessClass(c); + WriteClass(c); } - else + catch (Exception x) { - throw; + if (continueOnError) + { + rc = 1; + Console.WriteLine(x); + } + else + { + throw; + } } } } } - } - while (keepGoing); - - return rc; - } + while (keepGoing); - private static void AddToExportList(TypeWrapper c) - { - todo[c.Name] = c; - } - - private static bool IsNonVectorArray(TypeWrapper tw) - { - return !tw.IsArray && tw.TypeAsBaseType.IsArray; - } - - private static void AddToExportListIfNeeded(TypeWrapper tw) - { - while (tw.IsArray) - { - tw = tw.ElementTypeWrapper; + return rc; } - if (tw.IsUnloadable && tw.Name.StartsWith("Missing/")) - { - Console.Error.WriteLine("Error: unable to find assembly '{0}'", tw.Name.Substring(8)); - Environment.Exit(1); - return; - } - if (tw is StubTypeWrapper) - { - // skip - } - else if ((tw.TypeAsTBD != null && tw.TypeAsTBD.IsGenericType) || IsNonVectorArray(tw) || !tw.IsPublic) - { - AddToExportList(tw); - } - } - private static void AddToExportListIfNeeded(TypeWrapper[] types) - { - foreach (TypeWrapper tw in types) + private static void AddToExportList(TypeWrapper c) { - AddToExportListIfNeeded(tw); + todo[c.Name] = c; } - } - private static void ProcessClass(TypeWrapper tw) - { - TypeWrapper superclass = tw.BaseTypeWrapper; - if (superclass != null) + private static bool IsNonVectorArray(TypeWrapper tw) { - AddToExportListIfNeeded(superclass); + return !tw.IsArray && tw.TypeAsBaseType.IsArray; } - AddToExportListIfNeeded(tw.Interfaces); - TypeWrapper outerClass = tw.DeclaringTypeWrapper; - if (outerClass != null) - { - AddToExportList(outerClass); - } - foreach (TypeWrapper innerClass in tw.InnerClasses) + + private static void AddToExportListIfNeeded(TypeWrapper tw) { - if (innerClass.IsPublic) + while (tw.IsArray) { - AddToExportList(innerClass); + tw = tw.ElementTypeWrapper; + } + if (tw.IsUnloadable && tw.Name.StartsWith("Missing/")) + { + Console.Error.WriteLine("Error: unable to find assembly '{0}'", tw.Name.Substring(8)); + Environment.Exit(1); + return; + } + if (tw is StubTypeWrapper) + { + // skip + } + else if ((tw.TypeAsTBD != null && tw.TypeAsTBD.IsGenericType) || IsNonVectorArray(tw) || !tw.IsPublic) + { + AddToExportList(tw); } } - foreach (MethodWrapper mw in tw.GetMethods()) + + private static void AddToExportListIfNeeded(TypeWrapper[] types) { - if (mw.IsPublic || mw.IsProtected) + foreach (TypeWrapper tw in types) { - mw.Link(); - AddToExportListIfNeeded(mw.ReturnType); - AddToExportListIfNeeded(mw.GetParameters()); + AddToExportListIfNeeded(tw); } } - foreach (FieldWrapper fw in tw.GetFields()) + + private static void ProcessClass(TypeWrapper tw) { - if (fw.IsPublic || fw.IsProtected) + TypeWrapper superclass = tw.BaseTypeWrapper; + if (superclass != null) { - fw.Link(); - AddToExportListIfNeeded(fw.FieldTypeWrapper); + AddToExportListIfNeeded(superclass); + } + AddToExportListIfNeeded(tw.Interfaces); + TypeWrapper outerClass = tw.DeclaringTypeWrapper; + if (outerClass != null) + { + AddToExportList(outerClass); + } + foreach (TypeWrapper innerClass in tw.InnerClasses) + { + if (innerClass.IsPublic) + { + AddToExportList(innerClass); + } + } + foreach (MethodWrapper mw in tw.GetMethods()) + { + if (mw.IsPublic || mw.IsProtected) + { + mw.Link(); + AddToExportListIfNeeded(mw.ReturnType); + AddToExportListIfNeeded(mw.GetParameters()); + } + } + foreach (FieldWrapper fw in tw.GetFields()) + { + if (fw.IsPublic || fw.IsProtected) + { + fw.Link(); + AddToExportListIfNeeded(fw.FieldTypeWrapper); + } } } } -} - -static class Intrinsics -{ - internal static bool IsIntrinsic(MethodWrapper methodWrapper) - { - return false; - } -} - -static class StaticCompiler -{ - internal static readonly Universe Universe = new Universe(UniverseOptions.EnableFunctionPointers); - internal static readonly AssemblyResolver Resolver = new AssemblyResolver(); - internal static Assembly runtimeAssembly; - - internal static Type GetRuntimeType(string typeName) - { - return runtimeAssembly.GetType(typeName, true); - } - - internal static Assembly LoadFile(string fileName) - { - return Resolver.LoadFile(fileName); - } - - internal static Assembly Load(string name) - { - return Universe.Load(name); - } -} - -static class FakeTypes -{ - private static readonly Type genericType; - class Holder { } - - static FakeTypes() - { - genericType = StaticCompiler.Universe.Import(typeof(Holder<>)); - } - - internal static Type GetAttributeType(Type type) - { - return genericType.MakeGenericType(type); - } - - internal static Type GetAttributeReturnValueType(Type type) - { - return genericType.MakeGenericType(type); - } - - internal static Type GetAttributeMultipleType(Type type) - { - return genericType.MakeGenericType(type); - } - - internal static Type GetDelegateType(Type type) - { - return genericType.MakeGenericType(type); - } - - internal static Type GetEnumType(Type type) - { - return genericType.MakeGenericType(type); - } -} - -sealed class BootstrapBootstrapClassLoader : ClassLoaderWrapper -{ - internal BootstrapBootstrapClassLoader() - : base(CodeGenOptions.None, null) - { - TypeWrapper javaLangObject = new StubTypeWrapper(Modifiers.Public, "java.lang.Object", null, true); - SetRemappedType(JVM.Import(typeof(object)), javaLangObject); - SetRemappedType(JVM.Import(typeof(string)), new StubTypeWrapper(Modifiers.Public | Modifiers.Final, "java.lang.String", javaLangObject, true)); - SetRemappedType(JVM.Import(typeof(Exception)), new StubTypeWrapper(Modifiers.Public, "java.lang.Throwable", javaLangObject, true)); - SetRemappedType(JVM.Import(typeof(IComparable)), new StubTypeWrapper(Modifiers.Public | Modifiers.Abstract | Modifiers.Interface, "java.lang.Comparable", null, true)); - TypeWrapper tw = new StubTypeWrapper(Modifiers.Public | Modifiers.Abstract | Modifiers.Interface, "java.lang.AutoCloseable", null, true); - tw.SetMethods(new MethodWrapper[] { new SimpleCallMethodWrapper(tw, "close", "()V", JVM.Import(typeof(IDisposable)).GetMethod("Dispose"), PrimitiveTypeWrapper.VOID, TypeWrapper.EmptyArray, Modifiers.Public | Modifiers.Abstract, MemberFlags.None, SimpleOpCode.Callvirt, SimpleOpCode.Callvirt) }); - SetRemappedType(JVM.Import(typeof(IDisposable)), tw); - - RegisterInitiatingLoader(new StubTypeWrapper(Modifiers.Public, "java.lang.Enum", javaLangObject, false)); - RegisterInitiatingLoader(new StubTypeWrapper(Modifiers.Public | Modifiers.Abstract | Modifiers.Interface, "java.lang.annotation.Annotation", null, false)); - RegisterInitiatingLoader(new StubTypeWrapper(Modifiers.Public | Modifiers.Final, "java.lang.Class", javaLangObject, false)); - RegisterInitiatingLoader(new StubTypeWrapper(Modifiers.Public | Modifiers.Abstract, "java.lang.invoke.MethodHandle", javaLangObject, false)); - } -} - -sealed class StubTypeWrapper : TypeWrapper -{ - private readonly bool remapped; - private readonly TypeWrapper baseWrapper; - - internal StubTypeWrapper(Modifiers modifiers, string name, TypeWrapper baseWrapper, bool remapped) - : base(TypeFlags.None, modifiers, name) - { - this.remapped = remapped; - this.baseWrapper = baseWrapper; - } - - internal override TypeWrapper BaseTypeWrapper - { - get { return baseWrapper; } - } - - internal override ClassLoaderWrapper GetClassLoader() - { - return ClassLoaderWrapper.GetBootstrapClassLoader(); - } - - internal override Type TypeAsTBD - { - get { throw new NotSupportedException(); } - } - - internal override bool IsRemapped - { - get { return remapped; } - } } diff --git a/ikvmstub/ikvmstub.csproj b/ikvmstub/ikvmstub.csproj index 71aa658304..4f37e767b7 100644 --- a/ikvmstub/ikvmstub.csproj +++ b/ikvmstub/ikvmstub.csproj @@ -11,7 +11,6 @@ ikvmstub $(DefineConstants);STUB_GENERATOR true - true