Skip to content

Commit c702ebd

Browse files
committed
protocol wrappers emit a frame
1 parent ce785da commit c702ebd

2 files changed

Lines changed: 19 additions & 0 deletions

File tree

Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+SwiftThunkPrinting.swift

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,19 @@ extension JNISwift2JavaGenerator {
171171
}
172172

173173
printer.printBraceBlock(function.swiftDecl.signatureString) { printer in
174+
// Push a local JNI frame so refs created during this upcall are freed on exit.
175+
// When called from a Swift async context (e.g. cooperative thread pool) there is
176+
// no enclosing JNI frame, so refs would otherwise accumulate indefinitely. When
177+
// called from a Java-initiated native call there is already a frame, but pushing
178+
// a sub-frame still frees refs earlier and prevents overflow within a single call.
179+
let paramCount = function.originalFunctionSignature.parameters.count
180+
printer.print(
181+
"""
182+
let environment$ = try! JavaVirtualMachine.shared().environment()
183+
environment$.interface.PushLocalFrame(environment$, \(paramCount * 2 + 4))
184+
defer { environment$.interface.PopLocalFrame(environment$, nil) }
185+
"""
186+
)
174187
var upcallArguments = zip(
175188
function.originalFunctionSignature.parameters,
176189
function.parameterConversions

Tests/JExtractSwiftTests/JNI/JNIProtocolTests.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,9 +315,15 @@ struct JNIProtocolTests {
315315
"""
316316
extension SwiftJavaSomeProtocolWrapper {
317317
public func method() {
318+
let environment$ = try! JavaVirtualMachine.shared().environment()
319+
environment$.interface.PushLocalFrame(environment$, 4)
320+
defer { environment$.interface.PopLocalFrame(environment$, nil) }
318321
_javaSomeProtocolInterface.method()
319322
}
320323
public func withObject(c: SomeClass) -> SomeClass {
324+
let environment$ = try! JavaVirtualMachine.shared().environment()
325+
environment$.interface.PushLocalFrame(environment$, 6)
326+
defer { environment$.interface.PopLocalFrame(environment$, nil) }
321327
let cClass = try! JavaClass<JavaSomeClass>(environment: JavaVirtualMachine.shared().environment())
322328
let cPointer = UnsafeMutablePointer<SomeClass>.allocate(capacity: 1)
323329
cPointer.initialize(to: c)

0 commit comments

Comments
 (0)