diff --git a/build-tools/Java.Interop.BootstrapTasks/Java.Interop.BootstrapTasks.targets b/build-tools/Java.Interop.BootstrapTasks/Java.Interop.BootstrapTasks.targets index b84077bf8..54db188c7 100644 --- a/build-tools/Java.Interop.BootstrapTasks/Java.Interop.BootstrapTasks.targets +++ b/build-tools/Java.Interop.BootstrapTasks/Java.Interop.BootstrapTasks.targets @@ -1,93 +1,5 @@ - - - <_MonoInfoLine Include="<Project>" /> - <_MonoInfoLine Include=" <Choose>" /> - <_MonoInfoLine Include=" <When Condition=" %27%24(MonoFrameworkPath)%27 == %27%27 ">" /> - <_MonoInfoLine Include=" <PropertyGroup>" /> - <_MonoInfoLine Include=" <MonoFrameworkPath>$(_MonoFrameworkPath)</MonoFrameworkPath>" /> - <_MonoInfoLine Include=" <MonoLibs >$(_MonoLibs)</MonoLibs>" /> - <_MonoInfoLine Include=" </PropertyGroup>" /> - <_MonoInfoLine Include=" <ItemGroup>" /> - <_MonoInfoLine Include=" <MonoIncludePath Include="$(_MonoIncludePath)" />" /> - <_MonoInfoLine Include=" </ItemGroup>" /> - <_MonoInfoLine Include=" </When>" /> - <_MonoInfoLine Include=" </Choose>" /> - <_MonoInfoLine Include="</Project>" /> - - - - - - - - <_MonoMkLine Include="JI_MONO_LIB_PATH=$(_MonoLibPath)" /> - - - - - - - - - - - - - - - - - - - - <_MonoLibPath>$([System.IO.Path]::GetDirectoryName($(_MonoPath)))/../lib/ - <_MonoFrameworkPath>$(_MonoPkgConfigLibdir)/libmonosgen-2.0.so - <_MonoIncludePath>$(_MonoPkgConfigIncludedir) - <_MonoLibs>-L "$(_MonoPkgConfigLibdir)" -lmonosgen-2.0 - - - - - - <_MonoBase>/Library/Frameworks/Mono.framework/ - <_MonoLibPath>$(_MonoBase)Libraries/ - <_MonoFrameworkPath>$(_MonoLibPath)libmonosgen-2.0.1.dylib - <_MonoIncludePath>$(_MonoBase)Headers/mono-2.0 - <_MonoLibs>-L "$(_MonoLibPath)" -lmonosgen-2.0 - - - - - $(OutputPath)$(AssemblyName).jar + $(AssemblyName).jar @@ -32,7 +32,7 @@ @@ -43,8 +43,16 @@ <_JavaManagedBindingDir>$(_JavaIntermediateDir)mcw\ <_JavaJcwClassesDir>$(_JavaIntermediateDir)classes\ <_JavaJcwSourcesDir>$(_JavaIntermediateDir)java\ + <_JavaOutputJarPath>$(_JavaIntermediateDir)$(JavaOutputJarName) + + + + <_JavaCompileForBindingInputs @@ -169,8 +177,8 @@ @@ -184,7 +192,7 @@ <_Output>-o "$(_JavaJcwSourcesDir)." <_Libpath>@(_RefAsmDirs->'-L "%(Identity)"', ' ') - + @@ -197,7 +205,7 @@ + Outputs="$(_JavaOutputJarPath)"> @@ -215,7 +223,11 @@ /> - + + + + + diff --git a/samples/Hello-Java.Base/Program.cs b/samples/Hello-Java.Base/Program.cs index 733590374..ea23ff85e 100644 --- a/samples/Hello-Java.Base/Program.cs +++ b/samples/Hello-Java.Base/Program.cs @@ -17,16 +17,18 @@ class App public static void Main (string[] args) { - string? jvmPath = global::Java.InteropTests.TestJVM.GetJvmLibraryPath (); + var logger = (Action?) null; + string? jvmPath = null; bool createMultipleVMs = false; bool reportTiming = false; bool showHelp = false; + int verbosity = 0; var options = new OptionSet () { "Using the JVM from C#!", "", "Options:", { "jvm=", - $"{{PATH}} to JVM to use. Default is:\n {jvmPath}", + $"{{PATH}} to JVM to use. Default is:\n{Java.InteropTests.TestJVM.GetJvmLibraryPath (logger)}", v => jvmPath = v }, { "m", "Create multiple Java VMs. This will likely crash.", @@ -34,6 +36,15 @@ public static void Main (string[] args) { "t", $"Timing; invoke Object.hashCode() {N} times, print average.", v => reportTiming = v != null }, + { "v|verbosity:", + $"Set console log verbosity to {{LEVEL}}. Default is 0.", + (int? v) => { + verbosity = v.HasValue ? v.Value : verbosity + 1; + if (verbosity > 0) { + logger = CreateConsoleLogger (); + } + } + }, { "h|help", "Show this message and exit.", v => showHelp = v != null }, @@ -45,7 +56,7 @@ public static void Main (string[] args) } var builder = new JreRuntimeOptions () { JniAddNativeMethodRegistrationAttributePresent = true, - JvmLibraryPath = jvmPath, + JvmLibraryPath = jvmPath ?? global::Java.InteropTests.TestJVM.GetJvmLibraryPath (logger), ClassPath = { Path.Combine (Path.GetDirectoryName (typeof (App).Assembly.Location)!, "Hello-Java.Base.jar"), }, @@ -70,6 +81,13 @@ public static void Main (string[] args) CreateJLO (); } + static Action CreateConsoleLogger () + { + return (level, message) => { + Console.WriteLine ($"# {level}: {message}"); + }; + } + static void CreateJLO () { var jlo = new MyJLO (); diff --git a/src/Java.Interop/Java.Interop/JniRuntime.cs b/src/Java.Interop/Java.Interop/JniRuntime.cs index 5b9f0ed1f..6af5e5c1a 100644 --- a/src/Java.Interop/Java.Interop/JniRuntime.cs +++ b/src/Java.Interop/Java.Interop/JniRuntime.cs @@ -445,8 +445,9 @@ public virtual void OnEnterMarshalMethod () public virtual void OnUserUnhandledException (ref JniTransition transition, Exception e) { transition.SetPendingException (e); - +#if NET9_0_OR_GREATER Debugger.BreakForUserUnhandledException (e); +#endif // NET9_0_OR_GREATER } public virtual void RaisePendingException (Exception pendingException) diff --git a/src/Java.Runtime.Environment/Java.Interop/JreRuntime.cs b/src/Java.Runtime.Environment/Java.Interop/JreRuntime.cs index 8da7d8909..dd0912bf4 100644 --- a/src/Java.Runtime.Environment/Java.Interop/JreRuntime.cs +++ b/src/Java.Runtime.Environment/Java.Interop/JreRuntime.cs @@ -91,8 +91,9 @@ static unsafe JreRuntimeOptions CreateJreVM (JreRuntimeOptions builder) builder.TypeManager ??= new JreTypeManager (builder.typeMappings); #endif // NET - bool onMono = Type.GetType ("Mono.Runtime", throwOnError: false) != null; + bool onMono = Type.GetType ("Mono.RuntimeStructs", throwOnError: false) != null; if (onMono) { + Console.WriteLine ($"MonoVM support enabled"); builder.ValueManager = builder.ValueManager ?? new MonoRuntimeValueManager (); builder.ObjectReferenceManager = builder.ObjectReferenceManager ?? new MonoRuntimeObjectReferenceManager (); } diff --git a/src/java-interop/.gitignore b/src/java-interop/.gitignore index b44e02a75..dd69cf665 100644 --- a/src/java-interop/.gitignore +++ b/src/java-interop/.gitignore @@ -1,2 +1,3 @@ +coreclr.exp jni.c jni.g.cs diff --git a/src/java-interop/CMakeLists.txt b/src/java-interop/CMakeLists.txt index 5ab5e2a6c..e5c70c813 100644 --- a/src/java-interop/CMakeLists.txt +++ b/src/java-interop/CMakeLists.txt @@ -1,4 +1,4 @@ -set(CMAKE_OSX_ARCHITECTURES x86_64 arm64) +cmake_minimum_required(VERSION 3.10.2) project( java-interop @@ -14,8 +14,9 @@ set(CMAKE_CXX_EXTENSIONS OFF) set(CMAKE_CXX_VISIBILITY_PRESET hidden) option(ENABLE_MONO_INTEGRATION "Require Mono runtime" OFF) +option(ENABLE_OSX_ARCHITECTURES "macOS architectures" "") -cmake_minimum_required(VERSION 3.10.2) +set(CMAKE_OSX_ARCHITECTURES ${ENABLE_OSX_ARCHITECTURES}) set(JAVA_INTEROP_CORE_SOURCES java-interop-dlfcn.cc @@ -44,7 +45,6 @@ if(ENABLE_MONO_INTEGRATION) include_directories(${dir}) endforeach() list(APPEND LINK_FLAGS ${MONO_LINK_FLAGS}) - list(APPEND LINK_FLAGS "-Wl,-undefined -Wl,suppress -Wl,-flat_namespace") set(JAVA_INTEROP_SOURCES ${JAVA_INTEROP_CORE_SOURCES} ${JAVA_INTEROP_MONO_SOURCES}) else() set(JAVA_INTEROP_SOURCES ${JAVA_INTEROP_CORE_SOURCES}) diff --git a/src/java-interop/coreclr.def b/src/java-interop/coreclr.def new file mode 100644 index 000000000..6eb946c9e --- /dev/null +++ b/src/java-interop/coreclr.def @@ -0,0 +1,20 @@ +LIBRARY CORECLR + +EXPORTS + mono_class_from_mono_type + mono_class_get_field_from_name + mono_class_get_name + mono_class_get_namespace + mono_class_is_subclass_of + mono_class_vtable + mono_domain_get + mono_field_get_value + mono_field_set_value + mono_field_static_set_value + mono_gc_register_bridge_callbacks + mono_gc_wait_for_bridge_processing + mono_object_get_class + mono_thread_attach + mono_thread_current + mono_thread_get_managed_id + mono_thread_get_name_utf8 diff --git a/src/java-interop/coreclr.lib b/src/java-interop/coreclr.lib new file mode 100644 index 000000000..aa421bc7b Binary files /dev/null and b/src/java-interop/coreclr.lib differ diff --git a/src/java-interop/java-interop-gc-bridge-mono.cc b/src/java-interop/java-interop-gc-bridge-mono.cc index 7d8588432..aca306c60 100644 --- a/src/java-interop/java-interop-gc-bridge-mono.cc +++ b/src/java-interop/java-interop-gc-bridge-mono.cc @@ -3,7 +3,6 @@ #include #include #include -#include #include #include "java-interop.h" @@ -12,6 +11,7 @@ #include "java-interop-util.h" #ifdef _WINDOWS +#include #include #endif @@ -530,13 +530,21 @@ get_object_ref_type (JNIEnv *env, jobject handle) static int gref_inc (JavaInteropGCBridge *bridge) { +#if _WINDOWS + return InterlockedIncrement ((LONG volatile*) &bridge->gc_gref_count); +#else // !_WINDOWS return __sync_add_and_fetch (&bridge->gc_gref_count, 1); +#endif // _!WINDOWS } static int gref_dec (JavaInteropGCBridge *bridge) { +#if _WINDOWS + return InterlockedDecrement ((LONG volatile*) &bridge->gc_gref_count); +#else // !_WINDOWS return __sync_sub_and_fetch (&bridge->gc_gref_count, 1); +#endif // _!WINDOWS } #if defined (ANDROID) diff --git a/src/java-interop/java-interop-mono.h b/src/java-interop/java-interop-mono.h index 4cfb6a3a1..16ec344a5 100644 --- a/src/java-interop/java-interop-mono.h +++ b/src/java-interop/java-interop-mono.h @@ -4,6 +4,7 @@ #include "java-interop.h" #include +#include #include #include #include diff --git a/src/java-interop/java-interop.csproj b/src/java-interop/java-interop.csproj index 4ca20ea66..99d8d778f 100644 --- a/src/java-interop/java-interop.csproj +++ b/src/java-interop/java-interop.csproj @@ -28,7 +28,18 @@ - + + + + 8.0.13 + + + + + diff --git a/src/java-interop/java-interop.targets b/src/java-interop/java-interop.targets index eaefe2c11..9d35aaa47 100644 --- a/src/java-interop/java-interop.targets +++ b/src/java-interop/java-interop.targets @@ -8,25 +8,10 @@ <_JavaInteropLibName Condition=" $([MSBuild]::IsOSPlatform ('windows')) ">java-interop.dll - - <_JavaInteropNativeLib Include="CMakeLists.txt"> - x86_amd64 - win-x64\ - - <_JavaInteropNativeLib Include="CMakeLists.txt"> - x86 - win-x86\ - - - - - <_JavaInteropNativeLib Include="CMakeLists.txt" /> - - - + PreserveNewest - %(Dir)$(_JavaInteropLibName) + $(_JavaInteropLibName) @@ -39,42 +24,54 @@ - - - - + + + <_PrepareArch Condition=" '$(NETCoreSdkRuntimeIdentifier)' == 'win-x64' ">x86_amd64 + - - - <_MonoDirs>"-DMONO_INCLUDE_LIST=@(MonoIncludePath, ';')" - <_MonoLib>"-DMONO_LINK_FLAGS=$(MonoLibs)" - <_EnableMono>-DENABLE_MONO_INTEGRATION=ON + + <_CmakeOsxArch Condition=" '$(NETCoreSdkRuntimeIdentifier)' == 'osx-x64' ">x86_64 + <_CmakeOsxArch Condition=" '$(NETCoreSdkRuntimeIdentifier)' == 'osx-arm64' ">arm64 + - <_JdkDirs>"-DJDK_INCLUDE_LIST=@(JdkIncludePath, ';')" - <_Jni_c>"-DJNI_C_PATH=$(MSBuildThisFileDirectory)$(IntermediateOutputPath)jni.c" - <_ExtraArgs>$([MSBuild]::Escape('$(_JdkDirs) $(_Jni_c) $(_EnableMono) $(_MonoDirs) $(_MonoLib)')) + <_MonoNativePath>$(NuGetPackageRoot)microsoft.netcore.app.runtime.mono.$(NETCoreSdkRuntimeIdentifier)/$(DotNetRuntimePacksVersion)/runtimes/$(NETCoreSdkRuntimeIdentifier)/native/ + <_MonoIncludePath>$(_MonoNativePath)include/mono-2.0 + <_DEnableMono>-DENABLE_MONO_INTEGRATION=ON + <_DEnableOsxArchitectures Condition=" $([MSBuild]::IsOSPlatform ('osx')) ">"-DENABLE_OSX_ARCHITECTURES=$(_CmakeOsxArch)" + <_DMonoDirs>"-DMONO_INCLUDE_LIST=$(_MonoIncludePath)" + <_DJdkDirs>"-DJDK_INCLUDE_LIST=@(JdkIncludePath, ';')" + <_DJni_c>"-DJNI_C_PATH=$(MSBuildThisFileDirectory)$(IntermediateOutputPath)jni.c" + <_MonoLinkFlags Condition=" $([MSBuild]::IsOSPlatform ('windows')) " >$(MSBuildThisFileDirectory)coreclr.lib + <_MonoLinkFlags Condition=" !$([MSBuild]::IsOSPlatform ('windows')) ">-L $(_MonoNativePath) -lcoreclr + <_DMonoLinkFlags>"-DMONO_LINK_FLAGS=$(_MonoLinkFlags)" + <_ExtraArgs>$([MSBuild]::Escape('$(_DJdkDirs) $(_DJni_c) $(_DEnableMono) $(_DMonoDirs) $(_DMonoLinkFlags) $(_DEnableOsxArchitectures)')) + + + + + - + DependsOnTargets="GetNativeBuildCommands;_BuildJni_c;_GetJavaInteropBuildInfo;_UpdateCoreCLRLib" + AfterTargets="ResolveReferences" + Inputs="CMakeLists.txt;$(MSBuildThisFileFullPath);java-interop.csproj;@(ClInclude);@(ClCompile);coreclr.lib" + Outputs="$(IntermediateOutputPath)$(_JavaInteropLibName)"> + <_Cmake Condition=" '$(PrepareNativeToolchain)' != '' " - Include="PrepareNativeToolchain=$(PrepareNativeToolchain) %(_JavaInteropNativeLib.Arch)" + Include="PrepareNativeToolchain=$(PrepareNativeToolchain) $(_PrepareArch)" /> <_Cmake Include="CmakePath=$(CmakePath)" /> <_Cmake Include="CmakeGenerator=$(CmakeGenerator)" /> <_Cmake Include="CmakeSourceDir=$(MSBuildThisFileDirectory)" /> - <_Cmake Include="CmakeBuildDir=$(MSBuildThisFileDirectory)$(IntermediateOutputPath)%(_JavaInteropNativeLib.Dir)" /> + <_Cmake Include="CmakeBuildDir=$(MSBuildThisFileDirectory)$(IntermediateOutputPath)" /> <_Cmake Include="CmakeExtraArgs=$(_ExtraArgs)" /> - - <_Libs Include="$(IntermediateOutputPath)%(_JavaInteropNativeLib.Dir)$(_JavaInteropLibName)*" /> + - - + + + + $(TestOutputFullPath) - $(OutputPath)java.base-tests.jar + java.base-tests.jar diff --git a/tests/NativeTiming/CMakeLists.txt b/tests/NativeTiming/CMakeLists.txt index a98557ebe..0d4e50d8f 100644 --- a/tests/NativeTiming/CMakeLists.txt +++ b/tests/NativeTiming/CMakeLists.txt @@ -1,9 +1,9 @@ +cmake_minimum_required(VERSION 3.10.2) + set(CMAKE_OSX_ARCHITECTURES x86_64 arm64) project(NativeTiming C) -cmake_minimum_required(VERSION 3.10.2) - foreach(dir in ${JDK_INCLUDE_LIST}) include_directories(${dir}) endforeach() diff --git a/tests/TestJVM/TestJVM.cs b/tests/TestJVM/TestJVM.cs index 0272b7142..2ff1e0715 100644 --- a/tests/TestJVM/TestJVM.cs +++ b/tests/TestJVM/TestJVM.cs @@ -79,39 +79,28 @@ static string GetOutputDirectoryName () return new StreamWriter (path, append: false, encoding: new UTF8Encoding (encoderShouldEmitUTF8Identifier: false)); } - public static string? GetJvmLibraryPath () => GetJdkInfo ().JdkJvmPath; + public static string? GetJvmLibraryPath (Action? logger = null) => GetJdkInfo (logger).JdkJvmPath; - static (JdkInfo? JdkInfo, string? JdkJvmPath) GetJdkInfo () + static (JdkInfo? JdkInfo, string? JdkJvmPath) GetJdkInfo (Action? logger = null) { - var info = ReadJavaSdkDirectoryFromJdkInfoProps (); + var info = ReadJavaSdkDirectoryFromJdkInfoProps (logger); if (info.JdkJvmPath != null) { return (JdkInfo: info.JavaSdkDirectory == null ? null : new JdkInfo (info.JavaSdkDirectory), JdkJvmPath: info.JdkJvmPath); } - var jdk = JdkInfo.GetKnownSystemJdkInfos () + var jdk = JdkInfo.GetKnownSystemJdkInfos (logger) .FirstOrDefault (); return (jdk, jdk?.JdkJvmPath); } - static (string? JavaSdkDirectory, string? JdkJvmPath) ReadJavaSdkDirectoryFromJdkInfoProps () + static (string? JavaSdkDirectory, string? JdkJvmPath) ReadJavaSdkDirectoryFromJdkInfoProps (Action? logger) { - var location = typeof (TestJVM).Assembly.Location; - var binDir = Path.GetDirectoryName (Path.GetDirectoryName (location)) ?? Environment.CurrentDirectory; - var testDir = Path.GetFileName (Path.GetDirectoryName (location)); - if (testDir == null) { - return (null, null); - } - if (!testDir.StartsWith ("Test", StringComparison.OrdinalIgnoreCase)) { - return (null, null); - } - var buildName = testDir.Replace ("Test", "Build"); - if (buildName.Contains ('-')) { - buildName = buildName.Substring (0, buildName.IndexOf ('-')); - } - var jdkPropFile = Path.Combine (binDir, buildName, "JdkInfo.props"); + var jdkPropFile = TryProbeForJdkInfoProps (logger); + logger?.Invoke (TraceLevel.Verbose, $"TestJVM: jdkPropFile? {jdkPropFile}"); if (!File.Exists (jdkPropFile)) { return (null, null); } + logger?.Invoke (TraceLevel.Verbose, $"TestJVM: Extracting $(JdkJvmPath) from: {jdkPropFile}"); var msbuild = XNamespace.Get ("http://schemas.microsoft.com/developer/msbuild/2003"); var jdkProps = XDocument.Load (jdkPropFile); @@ -129,9 +118,47 @@ static string GetOutputDirectoryName () .Elements (msbuild + "JavaSdkDirectory") .FirstOrDefault (); + logger?.Invoke (TraceLevel.Verbose, $"TestJVM: $(JavaSdkDirectory)={jdkPath?.Value}; $(JdkJvmPath)={jdkJvmPath.Value}"); return (JavaSdkDirectory: jdkPath?.Value, JdkJvmPath: jdkJvmPath.Value); } + static string? TryProbeForJdkInfoProps (Action? logger) + { + for (var probing = Path.GetDirectoryName (typeof (TestJVM).Assembly.Location); probing != null; probing = Path.GetDirectoryName (probing)) { + logger?.Invoke (TraceLevel.Verbose, $"TestJVM: probing for JdkInfo.props around {probing}"); + if (File.Exists (Path.Combine (probing, "Java.Interop.sln"))) { + // we've hit the root of the repo checkout + return ProbeFromRootDir (probing); + } + + var dirName = Path.GetFileName (probing); + if (dirName.StartsWith ("Test", StringComparison.OrdinalIgnoreCase)) { + var buildName = dirName.Replace ("Test", "Build"); + if (buildName.Contains ('-')) { + buildName = buildName.Substring (0, buildName.IndexOf ('-')); + } + return Path.Combine (Path.GetDirectoryName (probing)!, buildName, "JdkInfo.props"); + } + } + return null; + + string ProbeFromRootDir (string location) + { + var buildDebug = Path.Combine (location, "bin", "BuildDebug"); + var buildRelease = Path.Combine (location, "bin", "BuildRelease"); + if (Directory.Exists (buildDebug) && !Directory.Exists (buildRelease)) { + return Path.Combine (buildDebug, "JdkInfo.props"); + } + if (Directory.Exists (buildRelease) && !Directory.Exists (buildDebug)) { + return Path.Combine (buildRelease, "JdkInfo.props"); + } + var dir = Directory.GetLastWriteTime (buildDebug) > Directory.GetLastWriteTime (buildRelease) + ? buildDebug + : buildRelease; + return Path.Combine (dir, "JdkInfo.props"); + } + } + public TestJVM (string[]? jars = null, Dictionary? typeMappings = null) : this (CreateOptions (jars, Assembly.GetCallingAssembly (), typeMappings)) {