Skip to content

Commit 67c20f7

Browse files
authored
Fix JNI caching for native threads (#464)
1 parent eea0638 commit 67c20f7

File tree

7 files changed

+302
-17
lines changed

7 files changed

+302
-17
lines changed

Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+SwiftThunkPrinting.swift

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,8 @@ extension JNISwift2JavaGenerator {
119119
private func printGlobalSwiftThunkSources(_ printer: inout CodePrinter) throws {
120120
printHeader(&printer)
121121

122+
printJNIOnLoad(&printer)
123+
122124
for decl in analysis.importedGlobalFuncs {
123125
printSwiftFunctionThunk(&printer, decl)
124126
printer.println()
@@ -130,6 +132,18 @@ extension JNISwift2JavaGenerator {
130132
}
131133
}
132134

135+
private func printJNIOnLoad(_ printer: inout CodePrinter) {
136+
printer.print(
137+
"""
138+
@_cdecl("JNI_OnLoad")
139+
func JNI_OnLoad(javaVM: JavaVMPointer, reserved: UnsafeMutableRawPointer) -> jint {
140+
SwiftJavaRuntimeSupport._JNI_OnLoad(javaVM, reserved)
141+
return JNI_VERSION_1_6
142+
}
143+
"""
144+
)
145+
}
146+
133147
private func printNominalTypeThunks(_ printer: inout CodePrinter, _ type: ImportedNominalType) throws {
134148
printHeader(&printer)
135149

@@ -222,7 +236,7 @@ extension JNISwift2JavaGenerator {
222236
let methodSignature = MethodSignature(resultType: .void, parameterTypes: enumCase.parameterConversions.map(\.native.javaType))
223237
let methods = #"[.init(name: "<init>", signature: "\#(methodSignature.mangledName)")]"#
224238

225-
return #"_JNIMethodIDCache(environment: try! JavaVirtualMachine.shared().environment(), className: "\#(nativeParametersClassName)", methods: \#(methods))"#
239+
return #"_JNIMethodIDCache(className: "\#(nativeParametersClassName)", methods: \#(methods))"#
226240
}
227241

228242
private func printEnumGetAsCaseThunk(
Lines changed: 229 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,229 @@
1+
// Auto-generated by Java-to-Swift wrapper generator.
2+
import CSwiftJavaJNI
3+
4+
@JavaClass("java.lang.Thread")
5+
open class JavaThread: JavaObject {
6+
@JavaMethod
7+
@_nonoverride public convenience init(_ arg0: String, environment: JNIEnvironment? = nil)
8+
9+
@JavaMethod
10+
@_nonoverride public convenience init(environment: JNIEnvironment? = nil)
11+
12+
@JavaMethod
13+
open func getName() -> String
14+
15+
@JavaMethod
16+
open func run()
17+
18+
@JavaMethod
19+
open func interrupt()
20+
21+
@JavaMethod
22+
open override func toString() -> String
23+
24+
@JavaMethod
25+
open override func clone() throws -> JavaObject!
26+
27+
@JavaMethod
28+
open func join(_ arg0: Int64, _ arg1: Int32) throws
29+
30+
@JavaMethod
31+
open func join() throws
32+
33+
@JavaMethod
34+
open func join(_ arg0: Int64) throws
35+
36+
@JavaMethod
37+
open func setContextClassLoader(_ arg0: JavaClassLoader?)
38+
39+
@JavaMethod
40+
open func setPriority(_ arg0: Int32)
41+
42+
@JavaMethod
43+
open func setDaemon(_ arg0: Bool)
44+
45+
@JavaMethod
46+
open func start()
47+
48+
@JavaMethod
49+
open func getPriority() -> Int32
50+
51+
@JavaMethod
52+
open func isDaemon() -> Bool
53+
54+
@JavaMethod
55+
open func getContextClassLoader() -> JavaClassLoader!
56+
57+
@JavaMethod
58+
open func isVirtual() -> Bool
59+
60+
@JavaMethod
61+
open func isAlive() -> Bool
62+
63+
@JavaMethod
64+
open func threadId() -> Int64
65+
66+
@JavaMethod
67+
open func getUncaughtExceptionHandler() -> JavaThread.UncaughtExceptionHandler!
68+
69+
@JavaMethod
70+
open func stop()
71+
72+
@JavaMethod
73+
open func isInterrupted() -> Bool
74+
75+
@JavaMethod
76+
open func setName(_ arg0: String)
77+
78+
@JavaMethod
79+
open func checkAccess()
80+
81+
@JavaMethod
82+
open func getId() -> Int64
83+
84+
@JavaMethod
85+
open func setUncaughtExceptionHandler(_ arg0: JavaThread.UncaughtExceptionHandler?)
86+
}
87+
extension JavaThread {
88+
@JavaInterface("java.lang.Thread$Builder")
89+
public struct Builder {
90+
@JavaMethod
91+
public func name(_ arg0: String) -> JavaThread.Builder!
92+
93+
@JavaMethod
94+
public func name(_ arg0: String, _ arg1: Int64) -> JavaThread.Builder!
95+
96+
@JavaMethod
97+
public func uncaughtExceptionHandler(_ arg0: JavaThread.UncaughtExceptionHandler?) -> JavaThread.Builder!
98+
99+
@JavaMethod
100+
public func inheritInheritableThreadLocals(_ arg0: Bool) -> JavaThread.Builder!
101+
}
102+
}
103+
extension JavaThread.Builder {
104+
@JavaInterface("java.lang.Thread$Builder$OfPlatform", extends: JavaThread.Builder.self)
105+
public struct OfPlatform {
106+
@JavaMethod
107+
public func name(_ arg0: String, _ arg1: Int64) -> JavaThread.Builder!
108+
109+
@JavaMethod
110+
public func name(_ arg0: String, _ arg1: Int64) -> JavaThread.Builder.OfPlatform!
111+
112+
@JavaMethod
113+
public func name(_ arg0: String) -> JavaThread.Builder!
114+
115+
@JavaMethod
116+
public func name(_ arg0: String) -> JavaThread.Builder.OfPlatform!
117+
118+
@JavaMethod
119+
public func priority(_ arg0: Int32) -> JavaThread.Builder.OfPlatform!
120+
121+
@JavaMethod
122+
public func daemon() -> JavaThread.Builder.OfPlatform!
123+
124+
@JavaMethod
125+
public func daemon(_ arg0: Bool) -> JavaThread.Builder.OfPlatform!
126+
127+
@JavaMethod
128+
public func uncaughtExceptionHandler(_ arg0: JavaThread.UncaughtExceptionHandler?) -> JavaThread.Builder.OfPlatform!
129+
130+
@JavaMethod
131+
public func uncaughtExceptionHandler(_ arg0: JavaThread.UncaughtExceptionHandler?) -> JavaThread.Builder!
132+
133+
@JavaMethod
134+
public func stackSize(_ arg0: Int64) -> JavaThread.Builder.OfPlatform!
135+
136+
@JavaMethod
137+
public func inheritInheritableThreadLocals(_ arg0: Bool) -> JavaThread.Builder.OfPlatform!
138+
139+
@JavaMethod
140+
public func inheritInheritableThreadLocals(_ arg0: Bool) -> JavaThread.Builder!
141+
}
142+
}
143+
extension JavaThread.Builder {
144+
@JavaInterface("java.lang.Thread$Builder$OfVirtual", extends: JavaThread.Builder.self)
145+
public struct OfVirtual {
146+
@JavaMethod
147+
public func name(_ arg0: String, _ arg1: Int64) -> JavaThread.Builder!
148+
149+
@JavaMethod
150+
public func name(_ arg0: String, _ arg1: Int64) -> JavaThread.Builder.OfVirtual!
151+
152+
@JavaMethod
153+
public func name(_ arg0: String) -> JavaThread.Builder!
154+
155+
@JavaMethod
156+
public func name(_ arg0: String) -> JavaThread.Builder.OfVirtual!
157+
158+
@JavaMethod
159+
public func uncaughtExceptionHandler(_ arg0: JavaThread.UncaughtExceptionHandler?) -> JavaThread.Builder!
160+
161+
@JavaMethod
162+
public func uncaughtExceptionHandler(_ arg0: JavaThread.UncaughtExceptionHandler?) -> JavaThread.Builder.OfVirtual!
163+
164+
@JavaMethod
165+
public func inheritInheritableThreadLocals(_ arg0: Bool) -> JavaThread.Builder.OfVirtual!
166+
167+
@JavaMethod
168+
public func inheritInheritableThreadLocals(_ arg0: Bool) -> JavaThread.Builder!
169+
}
170+
}
171+
extension JavaThread {
172+
@JavaInterface("java.lang.Thread$UncaughtExceptionHandler")
173+
public struct UncaughtExceptionHandler {
174+
@JavaMethod
175+
public func uncaughtException(_ arg0: JavaThread?, _ arg1: Throwable?)
176+
}
177+
}
178+
extension JavaClass<JavaThread> {
179+
@JavaStaticField(isFinal: true)
180+
public var MIN_PRIORITY: Int32
181+
182+
@JavaStaticField(isFinal: true)
183+
public var NORM_PRIORITY: Int32
184+
185+
@JavaStaticField(isFinal: true)
186+
public var MAX_PRIORITY: Int32
187+
188+
@JavaStaticMethod
189+
public func currentThread() -> JavaThread!
190+
191+
@JavaStaticMethod
192+
public func onSpinWait()
193+
194+
@JavaStaticMethod
195+
public func holdsLock(_ arg0: JavaObject?) -> Bool
196+
197+
@JavaStaticMethod
198+
public func interrupted() -> Bool
199+
200+
@JavaStaticMethod
201+
public func activeCount() -> Int32
202+
203+
@JavaStaticMethod
204+
public func enumerate(_ arg0: [JavaThread?]) -> Int32
205+
206+
@JavaStaticMethod
207+
public func yield()
208+
209+
@JavaStaticMethod
210+
public func sleep(_ arg0: Int64) throws
211+
212+
@JavaStaticMethod
213+
public func sleep(_ arg0: Int64, _ arg1: Int32) throws
214+
215+
@JavaStaticMethod
216+
public func ofPlatform() -> JavaThread.Builder.OfPlatform!
217+
218+
@JavaStaticMethod
219+
public func ofVirtual() -> JavaThread.Builder.OfVirtual!
220+
221+
@JavaStaticMethod
222+
public func dumpStack()
223+
224+
@JavaStaticMethod
225+
public func setDefaultUncaughtExceptionHandler(_ arg0: JavaThread.UncaughtExceptionHandler?)
226+
227+
@JavaStaticMethod
228+
public func getDefaultUncaughtExceptionHandler() -> JavaThread.UncaughtExceptionHandler!
229+
}

Sources/SwiftJava/swift-java.config

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
"java.lang.Void" : "JavaVoid",
2424
"java.lang.CharSequence": "CharSequence",
2525
"java.lang.Appendable": "Appendable",
26+
"java.lang.Thread": "JavaThread",
2627
"java.util.Optional": "JavaOptional",
2728
"java.util.OptionalDouble": "JavaOptionalDouble",
2829
"java.util.OptionalInt": "JavaOptionalInt",
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2025 Apple Inc. and the Swift.org project authors
6+
// Licensed under Apache License v2.0
7+
//
8+
// See LICENSE.txt for license information
9+
// See CONTRIBUTORS.txt for the list of Swift.org project authors
10+
//
11+
// SPDX-License-Identifier: Apache-2.0
12+
//
13+
//===----------------------------------------------------------------------===//
14+
15+
import SwiftJava
16+
import CSwiftJavaJNI
17+
18+
final class JNI {
19+
static var shared: JNI!
20+
21+
let applicationClassLoader: JavaClassLoader
22+
23+
init(fromVM javaVM: JavaVirtualMachine) {
24+
self.applicationClassLoader = try! JavaClass<JavaThread>(environment: javaVM.environment()).currentThread().getContextClassLoader()
25+
}
26+
}
27+
28+
// Called by generated code, and not automatically by Java.
29+
public func _JNI_OnLoad(_ javaVM: JavaVMPointer, _ reserved: UnsafeMutableRawPointer) {
30+
JNI.shared = JNI(fromVM: JavaVirtualMachine(adoptingJVM: javaVM))
31+
}

Sources/SwiftJavaRuntimeSupport/JNIMethodIDCaches.swift

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ extension _JNIMethodIDCache {
2727
)
2828

2929
private static let cache = _JNIMethodIDCache(
30-
environment: try! JavaVirtualMachine.shared().environment(),
3130
className: "java/util/concurrent/CompletableFuture",
3231
methods: [completeMethod, completeExceptionallyMethod]
3332
)
@@ -59,7 +58,6 @@ extension _JNIMethodIDCache {
5958
)
6059

6160
private static let cache = _JNIMethodIDCache(
62-
environment: try! JavaVirtualMachine.shared().environment(),
6361
className: "org/swift/swiftkit/core/SimpleCompletableFuture",
6462
methods: [completeMethod, completeExceptionallyMethod]
6563
)
@@ -81,7 +79,6 @@ extension _JNIMethodIDCache {
8179
private static let messageConstructor = Method(name: "<init>", signature: "(Ljava/lang/String;)V")
8280

8381
private static let cache = _JNIMethodIDCache(
84-
environment: try! JavaVirtualMachine.shared().environment(),
8582
className: "java/lang/Exception",
8683
methods: [messageConstructor]
8784
)

Sources/SwiftJavaRuntimeSupport/_JNIBoxedConversions.swift

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,47 +26,39 @@ public enum _JNIBoxedConversions {
2626
private static let doubleMethod = _JNIMethodIDCache.Method(name: "valueOf", signature: "(D)Ljava/lang/Double;", isStatic: true)
2727

2828
private static let booleanCache = _JNIMethodIDCache(
29-
environment: try! JavaVirtualMachine.shared().environment(),
3029
className: "java/lang/Boolean",
3130
methods: [booleanMethod]
3231
)
3332

3433
private static let byteCache = _JNIMethodIDCache(
35-
environment: try! JavaVirtualMachine.shared().environment(),
3634
className: "java/lang/Byte",
3735
methods: [byteMethod]
3836
)
3937
private static let charCache = _JNIMethodIDCache(
40-
environment: try! JavaVirtualMachine.shared().environment(),
4138
className: "java/lang/Character",
4239
methods: [charMethod]
4340
)
4441

4542
private static let shortCache = _JNIMethodIDCache(
46-
environment: try! JavaVirtualMachine.shared().environment(),
4743
className: "java/lang/Short",
4844
methods: [shortMethod]
4945
)
5046
private static let intCache = _JNIMethodIDCache(
51-
environment: try! JavaVirtualMachine.shared().environment(),
5247
className: "java/lang/Integer",
5348
methods: [intMethod]
5449
)
5550

5651
private static let longCache = _JNIMethodIDCache(
57-
environment: try! JavaVirtualMachine.shared().environment(),
5852
className: "java/lang/Long",
5953
methods: [longMethod]
6054
)
6155

6256
private static let floatCache = _JNIMethodIDCache(
63-
environment: try! JavaVirtualMachine.shared().environment(),
6457
className: "java/lang/Float",
6558
methods: [floatMethod]
6659
)
6760

6861
private static let doubleCache = _JNIMethodIDCache(
69-
environment: try! JavaVirtualMachine.shared().environment(),
7062
className: "java/lang/Double",
7163
methods: [doubleMethod]
7264
)

0 commit comments

Comments
 (0)