Skip to content

Commit 0685f55

Browse files
authored
make SwiftJava a dynamic lib and add class lookup fallbacks (#493)
1 parent 4fb6ca2 commit 0685f55

File tree

18 files changed

+99
-59
lines changed

18 files changed

+99
-59
lines changed

Package.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ let package = Package(
100100
// ==== SwiftJava (i.e. calling Java directly Swift utilities)
101101
.library(
102102
name: "SwiftJava",
103+
type: .dynamic,
103104
targets: ["SwiftJava"]
104105
),
105106

Samples/SwiftAndJavaJarSampleLib/Package.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,9 @@ let package = Package(
6363
.target(
6464
name: "MySwiftLibrary",
6565
dependencies: [
66-
.product(name: "SwiftRuntimeFunctions", package: "swift-java"),
66+
.product(name: "SwiftJava", package: "swift-java"),
67+
.product(name: "CSwiftJavaJNI", package: "swift-java"),
68+
.product(name: "SwiftRuntimeFunctions", package: "swift-java")
6769
],
6870
exclude: [
6971
"swift-java.config",

Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,7 @@ extension FFMSwift2JavaGenerator {
195195
private static final boolean INITIALIZED_LIBS = initializeLibs();
196196
static boolean initializeLibs() {
197197
System.loadLibrary(SwiftLibraries.LIB_NAME_SWIFT_CORE);
198+
System.loadLibrary(SwiftLibraries.LIB_NAME_SWIFT_JAVA);
198199
System.loadLibrary(SwiftLibraries.LIB_NAME_SWIFT_RUNTIME_FUNCTIONS);
199200
System.loadLibrary(LIB_NAME);
200201
return true;
@@ -345,6 +346,7 @@ extension FFMSwift2JavaGenerator {
345346
private static SymbolLookup getSymbolLookup() {
346347
if (SwiftLibraries.AUTO_LOAD_LIBS) {
347348
System.loadLibrary(SwiftLibraries.LIB_NAME_SWIFT_CORE);
349+
System.loadLibrary(SwiftLibraries.LIB_NAME_SWIFT_JAVA);
348350
System.loadLibrary(SwiftLibraries.LIB_NAME_SWIFT_RUNTIME_FUNCTIONS);
349351
System.loadLibrary(LIB_NAME);
350352
}

Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+JavaBindingsPrinting.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ extension JNISwift2JavaGenerator {
9999
static final String LIB_NAME = "\(swiftModuleName)";
100100
101101
static {
102+
System.loadLibrary(SwiftLibraries.LIB_NAME_SWIFT_JAVA);
102103
System.loadLibrary(LIB_NAME);
103104
}
104105
"""
@@ -169,6 +170,7 @@ extension JNISwift2JavaGenerator {
169170
@SuppressWarnings("unused")
170171
private static final boolean INITIALIZED_LIBS = initializeLibs();
171172
static boolean initializeLibs() {
173+
System.loadLibrary(SwiftLibraries.LIB_NAME_SWIFT_JAVA);
172174
System.loadLibrary(LIB_NAME);
173175
return true;
174176
}

Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+SwiftThunkPrinting.swift

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ extension JNISwift2JavaGenerator {
162162
// If the underlying translated method requires
163163
// a SwiftArena, we pass in the global arena
164164
if translatedDecl.translatedFunctionSignature.requiresSwiftArena {
165-
upcallArguments.append("JNI.shared.defaultAutoArena")
165+
upcallArguments.append("JavaSwiftArena.defaultAutoArena")
166166
}
167167

168168
let tryClause = function.originalFunctionSignature.isThrowing ? "try " : ""
@@ -201,8 +201,6 @@ extension JNISwift2JavaGenerator {
201201
private func printGlobalSwiftThunkSources(_ printer: inout CodePrinter) throws {
202202
printHeader(&printer)
203203

204-
printJNIOnLoad(&printer)
205-
206204
for decl in analysis.importedGlobalFuncs {
207205
printSwiftFunctionThunk(&printer, decl)
208206
printer.println()
@@ -214,18 +212,6 @@ extension JNISwift2JavaGenerator {
214212
}
215213
}
216214

217-
private func printJNIOnLoad(_ printer: inout CodePrinter) {
218-
printer.print(
219-
"""
220-
@_cdecl("JNI_OnLoad")
221-
func JNI_OnLoad(javaVM: JavaVMPointer, reserved: UnsafeMutableRawPointer) -> jint {
222-
SwiftJavaRuntimeSupport._JNI_OnLoad(javaVM, reserved)
223-
return JNI_VERSION_1_6
224-
}
225-
"""
226-
)
227-
}
228-
229215
private func printNominalTypeThunks(_ printer: inout CodePrinter, _ type: ImportedNominalType) throws {
230216
printHeader(&printer)
231217

Sources/SwiftJava/AnyJavaObject.swift

Lines changed: 34 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -102,23 +102,41 @@ extension AnyJavaObject {
102102
in environment: JNIEnvironment,
103103
_ body: (jclass) throws -> Result
104104
) throws -> Result {
105-
let resolvedClass = try environment.translatingJNIExceptions {
106-
environment.interface.FindClass(
107-
environment,
108-
fullJavaClassNameWithSlashes
109-
)
110-
}!
111-
return try body(resolvedClass)
105+
do {
106+
let resolvedClass = try environment.translatingJNIExceptions {
107+
environment.interface.FindClass(
108+
environment,
109+
fullJavaClassNameWithSlashes
110+
)
111+
}!
112+
return try body(resolvedClass)
113+
} catch {
114+
// If we are in a Java environment where we have loaded
115+
// SwiftJava dynamically, we have access to the application class loader
116+
// so lets try that as as a fallback
117+
if let applicationClassLoader = JNI.shared?.applicationClassLoader {
118+
return try _withJNIClassFromCustomClassLoader(
119+
applicationClassLoader,
120+
in: environment
121+
) { applicationLoadedClass in
122+
return try body(applicationLoadedClass)
123+
}
124+
} else {
125+
throw error
126+
}
127+
}
112128
}
113129

114130
/// Retrieve the Java class for this type using a specific class loader.
115131
private static func _withJNIClassFromCustomClassLoader<Result>(
116132
_ classLoader: JavaClassLoader,
117133
in environment: JNIEnvironment,
118-
_ body: (jclass?) throws -> Result
134+
_ body: (jclass) throws -> Result
119135
) throws -> Result {
120-
let resolvedClass = try? classLoader.findClass(fullJavaClassName)
121-
return try body(resolvedClass?.javaThis)
136+
let resolvedClass = try classLoader.findClass(fullJavaClassName)
137+
// OK to force unwrap, as classLoader will throw ClassNotFoundException
138+
// if the class cannot be found.
139+
return try body(resolvedClass!.javaThis)
122140
}
123141

124142
/// Retrieve the Java class for this type and execute body().
@@ -129,16 +147,15 @@ extension AnyJavaObject {
129147
) throws -> Result {
130148
if let AnyJavaObjectWithCustomClassLoader = self as? AnyJavaObjectWithCustomClassLoader.Type,
131149
let customClassLoader = try AnyJavaObjectWithCustomClassLoader.getJavaClassLoader(in: environment) {
132-
try _withJNIClassFromCustomClassLoader(customClassLoader, in: environment) { clazz in
133-
guard let clazz else {
134-
// If the custom class loader did not find the class
135-
// let's look in the default class loader.
136-
return try _withJNIClassFromDefaultClassLoader(in: environment, body)
150+
do {
151+
return try _withJNIClassFromCustomClassLoader(customClassLoader, in: environment) { clazz in
152+
return try body(clazz)
137153
}
138-
return try body(clazz)
154+
} catch {
155+
return try _withJNIClassFromDefaultClassLoader(in: environment, body)
139156
}
140157
} else {
141-
try _withJNIClassFromDefaultClassLoader(in: environment, body)
158+
return try _withJNIClassFromDefaultClassLoader(in: environment, body)
142159
}
143160
}
144161
}
Lines changed: 13 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
//
1313
//===----------------------------------------------------------------------===//
1414

15-
import SwiftJava
1615
import CSwiftJavaJNI
1716

1817
/// A type that represents the shared JNI environment
@@ -21,36 +20,28 @@ import CSwiftJavaJNI
2120
/// This is initialized when the `JNI_OnLoad` is triggered,
2221
/// which happens when you call `System.loadLibrary(...)`
2322
/// from Java.
24-
public final class JNI {
23+
package final class JNI {
2524
/// The shared JNI object, initialized by `JNI_OnLoad`
26-
public fileprivate(set) static var shared: JNI!
25+
///
26+
/// This may be `nil` in the case where `SwiftJava` is not loaded as a dynamic lib
27+
/// by the Java sources.
28+
package fileprivate(set) static var shared: JNI?
2729

2830
/// The default application class loader
29-
public let applicationClassLoader: JavaClassLoader
30-
31-
/// The default auto arena of SwiftKitCore
32-
public let defaultAutoArena: JavaSwiftArena
31+
package let applicationClassLoader: JavaClassLoader
3332

3433
init(fromVM javaVM: JavaVirtualMachine) {
34+
// Update the global JavaVM
35+
JavaVirtualMachine.sharedJVM.withLock {
36+
$0 = javaVM
37+
}
3538
let environment = try! javaVM.environment()
36-
3739
self.applicationClassLoader = try! JavaClass<JavaThread>(environment: environment).currentThread().getContextClassLoader()
38-
39-
// Find global arena
40-
let swiftMemoryClass = environment.interface.FindClass(environment, "org/swift/swiftkit/core/SwiftMemoryManagement")!
41-
let arenaFieldID = environment.interface.GetStaticFieldID(
42-
environment,
43-
swiftMemoryClass,
44-
"DEFAULT_SWIFT_JAVA_AUTO_ARENA",
45-
JavaSwiftArena.mangledName
46-
)
47-
let localObject = environment.interface.GetStaticObjectField(environment, swiftMemoryClass, arenaFieldID)!
48-
self.defaultAutoArena = JavaSwiftArena(javaThis: localObject, environment: environment)
49-
environment.interface.DeleteLocalRef(environment, localObject)
5040
}
5141
}
5242

53-
// Called by generated code, and not automatically by Java.
54-
public func _JNI_OnLoad(_ javaVM: JavaVMPointer, _ reserved: UnsafeMutableRawPointer) {
43+
@_cdecl("JNI_OnLoad")
44+
func SwiftJava_JNI_OnLoad(javaVM: JavaVMPointer, reserved: UnsafeMutableRawPointer) -> jint {
5545
JNI.shared = JNI(fromVM: JavaVirtualMachine(adoptingJVM: javaVM))
46+
return JNI_VERSION_1_6
5647
}

Sources/SwiftJava/JVM/JavaVirtualMachine.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,7 @@ extension JavaVirtualMachine {
220220
/// TODO: If the use of the lock itself ends up being slow, we could
221221
/// use an atomic here instead because our access pattern is fairly
222222
/// simple.
223-
private static let sharedJVM: LockedState<JavaVirtualMachine?> = .init(initialState: nil)
223+
static let sharedJVM: LockedState<JavaVirtualMachine?> = .init(initialState: nil)
224224

225225
/// Access the shared Java Virtual Machine instance.
226226
///

Sources/SwiftJavaRuntimeSupport/_JNIMethodIDCache.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,8 @@ public final class _JNIMethodIDCache: Sendable {
5555
// Clear any ClassNotFound exceptions from FindClass
5656
environment.interface.ExceptionClear(environment)
5757

58-
if let javaClass = try? JNI.shared.applicationClassLoader.loadClass(
58+
// OK to force unwrap, we are in a jextract environment.
59+
if let javaClass = try? JNI.shared!.applicationClassLoader.loadClass(
5960
className.replacingOccurrences(of: "/", with: ".")
6061
) {
6162
clazz = javaClass.javaThis

Sources/SwiftJavaRuntimeSupport/generated/JavaJNISwiftInstance.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ public struct JavaJNISwiftInstance: AnyJavaObjectWithCustomClassLoader {
2020
public func memoryAddress() -> Int64
2121

2222
public static func getJavaClassLoader(in environment: JNIEnvironment) throws -> JavaClassLoader! {
23-
JNI.shared.applicationClassLoader
23+
// OK to force unwrap, we are in a jextract environment.
24+
JNI.shared!.applicationClassLoader
2425
}
2526
}

0 commit comments

Comments
 (0)