diff --git a/Sources/SwiftJavaJNICore/JavaDemanglingError.swift b/Sources/SwiftJavaJNICore/JavaDemanglingError.swift index 445957d..241cbe5 100644 --- a/Sources/SwiftJavaJNICore/JavaDemanglingError.swift +++ b/Sources/SwiftJavaJNICore/JavaDemanglingError.swift @@ -13,7 +13,7 @@ //===----------------------------------------------------------------------===// /// Describes an error that can occur when demangling a Java name. -enum JavaDemanglingError: Error { +public enum JavaDemanglingError: Error { /// This does not match the form of a Java mangled type name. case invalidMangledName(String) diff --git a/Sources/SwiftJavaJNICore/JavaEnvironment+Refs.swift b/Sources/SwiftJavaJNICore/JavaEnvironment+Refs.swift index bd9494a..f7d4628 100644 --- a/Sources/SwiftJavaJNICore/JavaEnvironment+Refs.swift +++ b/Sources/SwiftJavaJNICore/JavaEnvironment+Refs.swift @@ -59,7 +59,7 @@ extension UnsafeMutablePointer { /// pending exception — it prints the stack trace to stderr and does **not** /// clear the exception. @inline(__always) - internal func throwPushLocalFrameOOM(capacity: Int) throws -> Never { + internal func throwPushLocalFrameOOM(capacity: Int) throws(JNIError) -> Never { if describeOOMException { // Print the pending OutOfMemoryError stack trace to stderr. // ExceptionDescribe does not clear the exception. diff --git a/Sources/SwiftJavaJNICore/JavaType+JavaSource.swift b/Sources/SwiftJavaJNICore/JavaType+JavaSource.swift index 96f72be..527ca18 100644 --- a/Sources/SwiftJavaJNICore/JavaType+JavaSource.swift +++ b/Sources/SwiftJavaJNICore/JavaType+JavaSource.swift @@ -16,7 +16,7 @@ extension JavaType { /// Form a Java type based on the name that is produced by /// java.lang.Class.getName(). This can be primitive types like "int", /// class types like "java.lang.String", or arrays thereof. - public init(javaTypeName: String) throws { + public init(javaTypeName: String) throws(JavaDemanglingError) { switch javaTypeName { case "boolean": self = .boolean case "byte": self = .byte diff --git a/Sources/SwiftJavaJNICore/Mangling.swift b/Sources/SwiftJavaJNICore/Mangling.swift index 0b92911..b01b013 100644 --- a/Sources/SwiftJavaJNICore/Mangling.swift +++ b/Sources/SwiftJavaJNICore/Mangling.swift @@ -14,7 +14,7 @@ extension JavaType { /// Demangle a Java type name into a representation of the type. - public init(mangledName: String) throws { + public init(mangledName: String) throws(JavaDemanglingError) { var mangledName = mangledName[...] self = try JavaType.demangleNextType(from: &mangledName) if !mangledName.isEmpty { @@ -43,7 +43,7 @@ extension JavaType { extension MethodSignature { /// Demangle the given method Java signature. - public init(mangledName: String) throws { + public init(mangledName: String) throws(JavaDemanglingError) { // Method signatures have the form "(parameter-types)result-type". guard mangledName.starts(with: "(") else { throw JavaDemanglingError.invalidMangledName(mangledName) @@ -82,7 +82,7 @@ extension MethodSignature { extension JavaType { /// Demangle the next Java type from the given string, shrinking the input /// string and producing demangled type. - static func demangleNextType(from string: inout Substring) throws -> JavaType { + static func demangleNextType(from string: inout Substring) throws(JavaDemanglingError) -> JavaType { guard let firstChar = string.first else { throw JavaDemanglingError.invalidMangledName(String(string)) } diff --git a/Sources/SwiftJavaJNICore/VirtualMachine/JavaVirtualMachine.swift b/Sources/SwiftJavaJNICore/VirtualMachine/JavaVirtualMachine.swift index 859d269..b1be5e2 100644 --- a/Sources/SwiftJavaJNICore/VirtualMachine/JavaVirtualMachine.swift +++ b/Sources/SwiftJavaJNICore/VirtualMachine/JavaVirtualMachine.swift @@ -80,7 +80,7 @@ public final class JavaVirtualMachine: @unchecked Sendable { classpath: [String] = [], vmOptions: [String] = [], ignoreUnrecognized: Bool = false - ) throws { + ) throws(VMError) { self.classpath = classpath var jvm: JavaVMPointer? = nil var environment: JNIEnvPointer? = nil @@ -141,7 +141,7 @@ public final class JavaVirtualMachine: @unchecked Sendable { self.destroyOnDeinit = .init(initialState: true) } - public func destroyJVM() throws { + public func destroyJVM() throws(VMError) { try self.detachCurrentThread() if let error = VMError(fromJNIError: jvm.pointee!.pointee.DestroyJavaVM(jvm)) { throw error @@ -177,7 +177,7 @@ extension JavaVirtualMachine { /// - Parameter /// - asDaemon: Whether this thread should be treated as a daemon /// thread in the Java Virtual Machine. - public func environment(asDaemon: Bool = false) throws -> JNIEnvironment { + public func environment(asDaemon: Bool = false) throws(VMError) -> JNIEnvironment { // Check whether this thread is already attached. If so, return the // corresponding environment. var environment: UnsafeMutableRawPointer? = nil @@ -213,7 +213,7 @@ extension JavaVirtualMachine { /// Detach the current thread from the Java Virtual Machine. All Java /// threads waiting for this thread to die are notified. - func detachCurrentThread() throws { + func detachCurrentThread() throws(VMError) { if let resultError = VMError(fromJNIError: jvm.pointee!.pointee.DetachCurrentThread(jvm)) { throw resultError } @@ -260,13 +260,13 @@ extension JavaVirtualMachine { vmOptions: [String] = [], ignoreUnrecognized: Bool = false, replace: Bool = false - ) throws -> JavaVirtualMachine { + ) throws(VMError) -> JavaVirtualMachine { precondition( !classpath.contains(where: { $0.contains(FileManager.pathSeparator) }), "Classpath element must not contain `\(FileManager.pathSeparator)`! Split the path into elements! Was: \(classpath)" ) - return try sharedJVM.withLock { (sharedJVMPointer: inout JavaVirtualMachine?) in + return try sharedJVM.withLock { (sharedJVMPointer: inout JavaVirtualMachine?) throws(VMError) in // If we already have a JavaVirtualMachine instance, return it. if replace { print("[swift-java] Replace JVM instance!") @@ -318,6 +318,10 @@ extension JavaVirtualMachine { // through the loop again to pick up the underlying JVM pointer. wasExistingVM = true continue + } catch let error as VMError { + throw error + } catch { + fatalError("Unexpected non-VMError from JavaVirtualMachine.init: \(error)") } sharedJVMPointer = javaVirtualMachine @@ -347,7 +351,7 @@ extension JavaVirtualMachine { extension JavaVirtualMachine { /// Describes the kinds of errors that can occur when interacting with JNI. - enum VMError: Error { + public enum VMError: Error { /// There is already a Java Virtual Machine. case existingVM @@ -393,10 +397,6 @@ extension JavaVirtualMachine { } } } - - enum JavaKitError: Error { - case classpathEntryNotFound(entry: String, classpath: [String]) - } } // ==== ------------------------------------------------------------------------ @@ -459,7 +459,7 @@ func systemJavaHome() -> String? { } /// Located the shared library that includes the `JNI_GetCreatedJavaVMs` and `JNI_CreateJavaVM` entry points to the `JNINativeInterface` function table -private func loadLibJava() throws -> DylibType { +private func loadLibJava() throws(JavaVirtualMachine.VMError) -> DylibType { #if os(Android) for libname in ["libart.so", "libdvm.so", "libnativehelper.so"] { if let lib = dlopen(libname, RTLD_NOW) { diff --git a/Sources/SwiftJavaJNICore/VirtualMachine/LockedState.swift b/Sources/SwiftJavaJNICore/VirtualMachine/LockedState.swift index 745dfa5..9b55c38 100644 --- a/Sources/SwiftJavaJNICore/VirtualMachine/LockedState.swift +++ b/Sources/SwiftJavaJNICore/VirtualMachine/LockedState.swift @@ -111,26 +111,24 @@ package struct LockedState { ) } - package func withLock(_ body: @Sendable (inout State) throws -> T) rethrows -> T { + package func withLock(_ body: @Sendable (inout State) throws(E) -> T) throws(E) -> T { try withLockUnchecked(body) } - package func withLockUnchecked(_ body: (inout State) throws -> T) rethrows -> T { - try _buffer.withUnsafeMutablePointers { state, lock in - _Lock.lock(lock) - defer { _Lock.unlock(lock) } - return try body(&state.pointee) - } + package func withLockUnchecked(_ body: (inout State) throws(E) -> T) throws(E) -> T { + _buffer.withUnsafeMutablePointerToElements { _Lock.lock($0) } + defer { _buffer.withUnsafeMutablePointerToElements { _Lock.unlock($0) } } + return try body(&_buffer.header) } // Ensures the managed state outlives the locked scope. - package func withLockExtendingLifetimeOfState(_ body: @Sendable (inout State) throws -> T) rethrows -> T { - try _buffer.withUnsafeMutablePointers { state, lock in - _Lock.lock(lock) - return try withExtendedLifetime(state.pointee) { - defer { _Lock.unlock(lock) } - return try body(&state.pointee) - } + package func withLockExtendingLifetimeOfState(_ body: @Sendable (inout State) throws(E) -> T) throws(E) -> T { + _buffer.withUnsafeMutablePointerToElements { _Lock.lock($0) } + defer { _buffer.withUnsafeMutablePointerToElements { _Lock.unlock($0) } } + do { + return try body(&_buffer.header) + } catch { + throw error } } } @@ -140,10 +138,10 @@ extension LockedState where State == Void { self.init(initialState: ()) } - package func withLock(_ body: @Sendable () throws -> R) rethrows -> R { - try withLock { _ in - try body() - } + package func withLock(_ body: @Sendable () throws(E) -> R) throws(E) -> R { + _buffer.withUnsafeMutablePointerToElements { _Lock.lock($0) } + defer { _buffer.withUnsafeMutablePointerToElements { _Lock.unlock($0) } } + return try body() } package func lock() {