From 55c83e3a422e088827a6837fefb44e6d4ea196ef Mon Sep 17 00:00:00 2001 From: Sam Gammon Date: Fri, 7 Jun 2024 18:43:00 -0700 Subject: [PATCH] fix: jna os info on linux/macos - fix: jna/oshi reflection and proxy metadata - fix: no stacktrace for host-side error causes in native mode - chore: cpu test script - chore: update `graalvm` module pin / detekt baseline Fixes and closes elide-dev/elide#990 Signed-off-by: Sam Gammon --- .../AbstractStaticNativeLibraryFeature.kt | 4 +- packages/runtime/build.gradle.kts | 9 +- packages/runtime/detekt-baseline.xml | 5 +- .../tool/cli/cmd/repl/ToolShellCommand.kt | 15 ++- .../META-INF/native-image/jni-config.json | 21 +++- .../META-INF/native-image/proxy-config.json | 14 ++- .../META-INF/native-image/reflect-config.json | 114 +++++++++++++++++- tools/scripts/cpu.js | 3 + 8 files changed, 173 insertions(+), 12 deletions(-) create mode 100644 tools/scripts/cpu.js diff --git a/packages/graalvm/src/main/kotlin/elide/runtime/feature/engine/AbstractStaticNativeLibraryFeature.kt b/packages/graalvm/src/main/kotlin/elide/runtime/feature/engine/AbstractStaticNativeLibraryFeature.kt index a6502f164..2626d2cca 100644 --- a/packages/graalvm/src/main/kotlin/elide/runtime/feature/engine/AbstractStaticNativeLibraryFeature.kt +++ b/packages/graalvm/src/main/kotlin/elide/runtime/feature/engine/AbstractStaticNativeLibraryFeature.kt @@ -171,7 +171,9 @@ public abstract class AbstractStaticNativeLibraryFeature : NativeLibraryFeature if (it.registerJni) (access as BeforeAnalysisAccessImpl).nativeLibraries.let { nativeLibraries -> when (it.type) { STATIC -> nativeLibraries.addStaticJniLibrary(it.name) - SHARED -> error("Dynamic native libraries not supported yet: $it") + SHARED -> if (it.registerJni) { /* Dynamic JNI libraries use JNI to load. */ } else { + nativeLibraries.addDynamicNonJniLibrary(it.name) + } } } if (it.eager) { diff --git a/packages/runtime/build.gradle.kts b/packages/runtime/build.gradle.kts index 121d7b39c..33b41c049 100644 --- a/packages/runtime/build.gradle.kts +++ b/packages/runtime/build.gradle.kts @@ -649,7 +649,7 @@ val commonNativeArgs = listOfNotNull( "--install-exit-handlers", "--enable-url-protocols=jar", "--macro:truffle-svm", - "--enable-native-access=ALL-UNNAMED", + "--enable-native-access=com.sun.jna,ALL-UNNAMED", "-J--add-exports=org.graalvm.nativeimage.builder/com.oracle.svm.core.jdk=ALL-UNNAMED", "-J--add-exports=org.graalvm.nativeimage.builder/com.oracle.svm.hosted=ALL-UNNAMED", "-J--add-exports=org.graalvm.nativeimage.builder/com.oracle.svm.hosted.c=ALL-UNNAMED", @@ -668,6 +668,10 @@ val commonNativeArgs = listOfNotNull( "-J-Delide.staticJni=$enableStaticJni", "-Delide.natives=$nativesPath", "-J-Delide.natives=$nativesPath", + "-Djna.library.path=$nativesPath", + "-J-Djna.library.path=$nativesPath", + "-Djna.boot.library.path=$nativesPath", + "-J-Djna.boot.library.path=$nativesPath", "-Dorg.sqlite.lib.path=$nativesPath", "-J-Dorg.sqlite.lib.path=$nativesPath", "-Dorg.sqlite.lib.exportPath=$nativesPath", @@ -799,6 +803,8 @@ val releaseFlags: List = listOf( val jvmDefs = mapOf( "elide.natives" to nativesPath, + "jna.library.path" to nativesPath, + "jna.boot.library.path" to nativesPath, "elide.nativeTransport.v2" to enableNativeTransportV2.toString(), "io.netty.allocator.type" to "unpooled", "io.netty.native.deleteLibAfterLoading" to "false", @@ -857,6 +863,7 @@ val initializeAtRuntime: List = listOfNotNull( // --- JNA ----- + "com.sun.jna.Native", "com.sun.jna.Structure${'$'}FFIType", "com.sun.jna.platform.mac.IOKit", "com.sun.jna.platform.mac.IOKitUtil", diff --git a/packages/runtime/detekt-baseline.xml b/packages/runtime/detekt-baseline.xml index 2b1304a85..cbe0c04bb 100644 --- a/packages/runtime/detekt-baseline.xml +++ b/packages/runtime/detekt-baseline.xml @@ -10,7 +10,7 @@ CyclomaticComplexMethod:ToolShellCommand.kt$ToolShellCommand$override fun PolyglotEngineConfiguration.configureEngine() CyclomaticComplexMethod:ToolShellCommand.kt$ToolShellCommand$override suspend fun CommandContext.invoke(state: ToolContext<ToolState>): CommandResult CyclomaticComplexMethod:ToolShellCommand.kt$ToolShellCommand$private fun beginInteractiveSession( languages: EnumSet<GuestLanguage>, primaryLanguage: GuestLanguage, engine: PolyglotEngine, ctx: PolyglotContext, ) - CyclomaticComplexMethod:ToolShellCommand.kt$ToolShellCommand$private fun displayFormattedError( exc: Throwable, message: String, advice: String? = null, internal: Boolean = false, stacktrace: Boolean = internal, ) + CyclomaticComplexMethod:ToolShellCommand.kt$ToolShellCommand$private fun displayFormattedError( exc: Throwable, message: String, advice: String? = null, internal: Boolean = false, stacktrace: Boolean = internal, withCause: Boolean = true, ) FunctionParameterNaming:Statics.kt$Statics$`in`: InputStream LargeClass:ToolShellCommand.kt$ToolShellCommand : AbstractSubcommand LoopWithTooManyJumpStatements:ToolShellCommand.kt$ToolShellCommand$while @@ -29,12 +29,9 @@ NestedBlockDepth:SelfTestCommand.kt$SelfTestCommand$override suspend fun CommandContext.invoke(state: ToolContext<ToolState>): CommandResult ObjectPropertyNaming:Statics.kt$Statics$val `in`: InputStream get() = delegatedInStream.get() ?: System.`in` ReturnCount:ExecutionController.kt$ExecutionController$private fun toHost(polyglotException: PolyglotException): Throwable - ReturnCount:NativeSQLiteFeature.kt$NativeSQLiteFeature$override fun unpackNatives(access: BeforeAnalysisAccess): List<UnpackedNative> ReturnCount:NativeUtil.kt$NativeUtil$@JvmStatic internal fun loadOrCopy( workdir: File, path: String, libName: String, loader: ClassLoader, forceCopy: Boolean = false, forceLoad: Boolean = false, loadFromPath: Boolean = true, ): Pair<Boolean, Boolean> ReturnCount:RuntimeWorkdirManager.kt$RuntimeWorkdirManager$private fun nearestDirectoryWithAnyOfTheseFiles( files: SortedSet<String>, base: File? = null, depth: Int? = null, ): File? SpreadOperator:Elide.kt$Elide.Companion$(*args) - SpreadOperator:NativeSQLiteFeature.kt$NativeSQLiteFeature$(*fields( NativeDB::class.java, "pointer", "busyHandler", "commitListener", "updateListener", "progressHandler", )) - SpreadOperator:NativeSQLiteFeature.kt$NativeSQLiteFeature$(*this.fields(Function::class.java, "context", "value", "args")) SwallowedException:DefaultProjectManager.kt$DefaultProjectManager.Companion$ioe: IOException SwallowedException:DefaultProjectManager.kt$DefaultProjectManager.Companion$thr: Throwable SwallowedException:Elide.kt$Elide.Companion$uoe: UnsupportedOperationException diff --git a/packages/runtime/src/main/kotlin/elide/tool/cli/cmd/repl/ToolShellCommand.kt b/packages/runtime/src/main/kotlin/elide/tool/cli/cmd/repl/ToolShellCommand.kt index 7051f279d..0eac3c5e8 100644 --- a/packages/runtime/src/main/kotlin/elide/tool/cli/cmd/repl/ToolShellCommand.kt +++ b/packages/runtime/src/main/kotlin/elide/tool/cli/cmd/repl/ToolShellCommand.kt @@ -1107,10 +1107,11 @@ import elide.tool.project.ProjectManager advice: String? = null, internal: Boolean = false, stacktrace: Boolean = internal, + withCause: Boolean = true, ) { + if (exc !is PolyglotException) return val term = terminal.get() val reader = lineReader.get() - if (exc !is PolyglotException) return // begin calculating with source context val middlePrefix = "║ " @@ -1146,6 +1147,16 @@ import elide.tool.project.ProjectManager val stackString = StringWriter() val stackPrinter = PrintWriter(stackString) exc.printStackTrace(stackPrinter) + when (val cause = exc.cause ?: if (exc.isHostException) exc.asHostException() else null) { + null -> {} + else -> if (withCause) { + stackString.append("\nCause stacktrace: ") + cause.printStackTrace(stackPrinter) + } else if (exc.isHostException) { + stackString.append("\nCause: ${cause.message}") + stackString.append(" Failed to gather stacktrace for host exception of type ${cause::class.simpleName}.") + } + } stackPrinter.flush() stackString.toString() } else { @@ -1275,7 +1286,7 @@ import elide.tool.project.ProjectManager exc.isHostException || exc.message?.contains("HostException: ") == true -> displayFormattedError( exc, - exc.message ?: "An runtime error was thrown", + exc.message ?: "A runtime error was thrown", advice = "This is an error in Elide. Please report this to the Elide Team with `elide bug`", stacktrace = true, internal = true, diff --git a/packages/runtime/src/main/resources/META-INF/native-image/jni-config.json b/packages/runtime/src/main/resources/META-INF/native-image/jni-config.json index c69ce6fff..4a32e9262 100644 --- a/packages/runtime/src/main/resources/META-INF/native-image/jni-config.json +++ b/packages/runtime/src/main/resources/META-INF/native-image/jni-config.json @@ -71,7 +71,17 @@ "allPublicMethods":true, "allDeclaredConstructors":true, "allPublicConstructors":true, - "methods":[{"name":"dispose","parameterTypes":[] }, {"name":"fromNative","parameterTypes":["com.sun.jna.FromNativeConverter","java.lang.Object","java.lang.reflect.Method"] }, {"name":"fromNative","parameterTypes":["java.lang.Class","java.lang.Object"] }, {"name":"fromNative","parameterTypes":["java.lang.reflect.Method","java.lang.Object"] }, {"name":"nativeType","parameterTypes":["java.lang.Class"] }, {"name":"toNative","parameterTypes":["com.sun.jna.ToNativeConverter","java.lang.Object"] }] + "methods":[ + {"name":"dispose","parameterTypes":[] }, + {"name":"fromNative","parameterTypes":["com.sun.jna.FromNativeConverter","java.lang.Object","java.lang.reflect.Method"] }, + {"name":"fromNative","parameterTypes":["java.lang.Class","java.lang.Object"] }, + {"name":"fromNative","parameterTypes":["java.lang.reflect.Method","java.lang.Object"] }, + {"name":"nativeType","parameterTypes":["java.lang.Class"] }, + {"name":"toNative","parameterTypes":["com.sun.jna.ToNativeConverter","java.lang.Object"]}, + {"name":"open","parameterTypes":["java.lang.String","java.lang.Integer"]}, + {"name":"close","parameterTypes":["java.lang.Long"]}, + {"name":"findSymbol","parameterTypes":["java.lang.Long","java.lang.String"]} + ] }, { "name":"com.sun.jna.Native$ffi_callback", @@ -159,6 +169,13 @@ "allDeclaredConstructors":true, "allPublicConstructors":true }, +{ + "name":"com.sun.jna.platform.mac.CoreFoundation$CFStringRef", + "allDeclaredMethods":true, + "allPublicMethods":true, + "allDeclaredConstructors":true, + "allPublicConstructors":true +}, { "name":"com.sun.management.internal.DiagnosticCommandArgumentInfo", "methods":[{"name":"","parameterTypes":["java.lang.String","java.lang.String","java.lang.String","java.lang.String","boolean","boolean","boolean","int"] }] @@ -561,4 +578,4 @@ "name":"sun.nio.ch.FileChannelImpl", "fields":[{"name":"fd"}] } -] \ No newline at end of file +] diff --git a/packages/runtime/src/main/resources/META-INF/native-image/proxy-config.json b/packages/runtime/src/main/resources/META-INF/native-image/proxy-config.json index 43026c1dc..1eb28a0e2 100644 --- a/packages/runtime/src/main/resources/META-INF/native-image/proxy-config.json +++ b/packages/runtime/src/main/resources/META-INF/native-image/proxy-config.json @@ -16,5 +16,17 @@ }, { "interfaces":["oshi.jna.platform.linux.LinuxLibc"] + }, + { + "interfaces":["com.sun.jna.platform.mac.SystemB"] + }, + { + "interfaces":["oshi.jna.platform.mac.SystemB"] + }, + { + "interfaces":["com.sun.jna.platform.mac.IOKit"] + }, + { + "interfaces":["com.sun.jna.platform.mac.CoreFoundation"] } -] \ No newline at end of file +] diff --git a/packages/runtime/src/main/resources/META-INF/native-image/reflect-config.json b/packages/runtime/src/main/resources/META-INF/native-image/reflect-config.json index adfd90aa8..bbd5aaa61 100644 --- a/packages/runtime/src/main/resources/META-INF/native-image/reflect-config.json +++ b/packages/runtime/src/main/resources/META-INF/native-image/reflect-config.json @@ -7420,5 +7420,117 @@ { "name":"sun.security.x509.SubjectKeyIdentifierExtension", "methods":[{"name":"","parameterTypes":["java.lang.Boolean","java.lang.Object"] }] +}, +{ + "name":"oshi.jna.ByRef$CloseableSizeTByReference", + "methods":[{"name":"","parameterTypes":[] }], + "allDeclaredMethods":true, + "allPublicMethods":true, + "allDeclaredConstructors":true, + "allPublicConstructors":true +}, +{ + "name":"oshi.jna.ByRef$CloseableIntByReference", + "methods":[{"name":"","parameterTypes":[] }], + "allDeclaredMethods":true, + "allPublicMethods":true, + "allDeclaredConstructors":true, + "allPublicConstructors":true +}, +{ + "name":"oshi.jna.ByRef$CloseableLongByReference", + "methods":[{"name":"","parameterTypes":[] }], + "allDeclaredMethods":true, + "allPublicMethods":true, + "allDeclaredConstructors":true, + "allPublicConstructors":true +}, +{ + "name":"oshi.jna.ByRef$CloseableNativeLongByReference", + "methods":[{"name":"","parameterTypes":[] }], + "allDeclaredMethods":true, + "allPublicMethods":true, + "allDeclaredConstructors":true, + "allPublicConstructors":true +}, +{ + "name":"com.sun.jna.platform.unix.LibCAPI$size_t", + "methods":[{"name":"","parameterTypes":[] }], + "allDeclaredMethods":true, + "allPublicMethods":true, + "allDeclaredConstructors":true, + "allPublicConstructors":true +}, +{ + "name":"com.sun.jna.platform.mac.CoreFoundation$CFMutableDictionaryRef", + "methods":[{"name":"","parameterTypes":[] }], + "allDeclaredMethods":true, + "allPublicMethods":true, + "allDeclaredConstructors":true, + "allPublicConstructors":true +}, +{ + "name":"com.sun.jna.platform.mac.IOKit$IOIterator", + "methods":[{"name":"","parameterTypes":[] }], + "allDeclaredMethods":true, + "allPublicMethods":true, + "allDeclaredConstructors":true, + "allPublicConstructors":true +}, +{ + "name":"com.sun.jna.platform.mac.IOKit$IORegistryEntry", + "methods":[{"name":"","parameterTypes":[] }], + "allDeclaredMethods":true, + "allPublicMethods":true, + "allDeclaredConstructors":true, + "allPublicConstructors":true +}, +{ + "name":"com.sun.jna.platform.mac.CoreFoundation$CFStringRef", + "methods":[{"name":"","parameterTypes":[] }], + "allDeclaredMethods":true, + "allPublicMethods":true, + "allDeclaredConstructors":true, + "allPublicConstructors":true +}, +{ + "name":"com.sun.jna.platform.mac.CoreFoundation$CFTypeID", + "methods":[{"name":"","parameterTypes":[] }], + "allDeclaredMethods":true, + "allPublicMethods":true, + "allDeclaredConstructors":true, + "allPublicConstructors":true +}, +{ + "name":"com.sun.jna.platform.mac.CoreFoundation$CFIndex", + "methods":[{"name":"","parameterTypes":[] }], + "allDeclaredMethods":true, + "allPublicMethods":true, + "allDeclaredConstructors":true, + "allPublicConstructors":true +}, +{ + "name":"com.sun.jna.platform.mac.CoreFoundation$CFAllocatorRef", + "methods":[{"name":"","parameterTypes":[] }], + "allDeclaredMethods":true, + "allPublicMethods":true, + "allDeclaredConstructors":true, + "allPublicConstructors":true +}, +{ + "name":"com.sun.jna.platform.mac.CoreFoundation$CFTypeRef", + "methods":[{"name":"","parameterTypes":[] }], + "allDeclaredMethods":true, + "allPublicMethods":true, + "allDeclaredConstructors":true, + "allPublicConstructors":true +}, +{ + "name":"com.sun.jna.platform.mac.CoreFoundation$CFDataRef", + "methods":[{"name":"","parameterTypes":[] }], + "allDeclaredMethods":true, + "allPublicMethods":true, + "allDeclaredConstructors":true, + "allPublicConstructors":true } -] \ No newline at end of file +] diff --git a/tools/scripts/cpu.js b/tools/scripts/cpu.js new file mode 100644 index 000000000..c296ab902 --- /dev/null +++ b/tools/scripts/cpu.js @@ -0,0 +1,3 @@ +const os = require("node:os"); +const cpus = os.cpus(); +console.log("CPU info: " + JSON.stringify(cpus, null, 2));