Skip to content

Commit f42a663

Browse files
authored
more local frames (#645)
1 parent ce0aa88 commit f42a663

1 file changed

Lines changed: 42 additions & 25 deletions

File tree

Sources/SwiftJava/JavaObject+MethodCalls.swift

Lines changed: 42 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -153,15 +153,16 @@ extension AnyJavaObject {
153153
method: jmethodID,
154154
args: repeat each Param
155155
) throws -> Result {
156-
// Retrieve the method that performs this call, then package the values and
157-
// call it.
156+
// Wrap arg creation, the call, and result conversion in a local frame so
157+
// that jstring/jarray local refs created by getJValues are freed on exit.
158158
let jniMethod = Result.jniMethodCall(in: environment)
159-
let jniArgs = getJValues(repeat each args, in: environment)
160-
let jniResult = try environment.translatingJNIExceptions {
161-
jniMethod(environment, this, method, jniArgs)
159+
return try environment.withLocalFrame(capacity: countArgs(repeat each args) + 1) {
160+
let jniArgs = getJValues(repeat each args, in: environment)
161+
let jniResult = try environment.translatingJNIExceptions {
162+
jniMethod(environment, this, method, jniArgs)
163+
}
164+
return Result(fromJNI: jniResult, in: environment)
162165
}
163-
164-
return Result(fromJNI: jniResult, in: environment)
165166
}
166167

167168
/// Call a Java method with the given name and arguments, which must be of the correct
@@ -219,12 +220,14 @@ extension AnyJavaObject {
219220
method: jmethodID,
220221
args: repeat each Param
221222
) throws {
222-
// Retrieve the method that performs this call, then package the arguments
223-
// and call it.
223+
// Wrap arg creation and the call in a local frame so that jstring/jarray
224+
// local refs created by getJValues are freed on exit.
224225
let jniMethod = environment.interface.CallVoidMethodA!
225-
let jniArgs = getJValues(repeat each args, in: environment)
226-
try environment.translatingJNIExceptions {
227-
jniMethod(environment, this, method, jniArgs)
226+
try environment.withLocalFrame(capacity: countArgs(repeat each args) + 1) {
227+
let jniArgs = getJValues(repeat each args, in: environment)
228+
try environment.translatingJNIExceptions {
229+
jniMethod(environment, this, method, jniArgs)
230+
}
228231
}
229232
}
230233

@@ -271,9 +274,16 @@ extension AnyJavaObject {
271274
in: environment
272275
)
273276

274-
let jniArgs = getJValues(repeat each arguments, in: environment)
275-
return try environment.translatingJNIExceptions {
276-
environment.interface.NewObjectA!(environment, thisClass, methodID, jniArgs)
277+
// Wrap arg creation and the constructor call in a local frame, promoting
278+
// the new object's local ref to the outer frame so the caller can wrap
279+
// it in a JavaObjectHolder (which will then delete that promoted ref).
280+
return try environment.withLocalFramePromotingResult(
281+
capacity: countArgs(repeat each arguments) + 1
282+
) {
283+
let jniArgs = getJValues(repeat each arguments, in: environment)
284+
return try environment.translatingJNIExceptions {
285+
environment.interface.NewObjectA!(environment, thisClass, methodID, jniArgs)
286+
}!
277287
}!
278288
}
279289
}
@@ -308,7 +318,9 @@ extension AnyJavaObject {
308318

309319
let fieldID = getJNIFieldID(fieldName, fieldType: fieldType)!
310320
let jniMethod = FieldType.jniFieldSet(in: environment)
311-
jniMethod(environment, javaThis, fieldID, newValue.getJNIValue(in: environment))
321+
try! environment.withLocalFrame(capacity: 1) {
322+
jniMethod(environment, javaThis, fieldID, newValue.getJNIValue(in: environment))
323+
}
312324
}
313325
}
314326
}
@@ -340,12 +352,13 @@ extension JavaClass {
340352
}!
341353

342354
let jniMethod = Result.jniStaticMethodCall(in: environment)
343-
let jniArgs = getJValues(repeat each arguments, in: environment)
344-
let jniResult = try environment.translatingJNIExceptions {
345-
jniMethod(environment, thisClass, methodID, jniArgs)
355+
return try environment.withLocalFrame(capacity: countArgs(repeat each arguments) + 1) {
356+
let jniArgs = getJValues(repeat each arguments, in: environment)
357+
let jniResult = try environment.translatingJNIExceptions {
358+
jniMethod(environment, thisClass, methodID, jniArgs)
359+
}
360+
return Result(fromJNI: jniResult, in: environment)
346361
}
347-
348-
return Result(fromJNI: jniResult, in: environment)
349362
}
350363

351364
/// Call a Java static method with the given name and arguments, which must be
@@ -373,9 +386,11 @@ extension JavaClass {
373386
}!
374387

375388
let jniMethod = environment.interface.CallStaticVoidMethodA
376-
let jniArgs = getJValues(repeat each arguments, in: environment)
377-
try environment.translatingJNIExceptions {
378-
jniMethod!(environment, thisClass, methodID, jniArgs)
389+
try environment.withLocalFrame(capacity: countArgs(repeat each arguments) + 1) {
390+
let jniArgs = getJValues(repeat each arguments, in: environment)
391+
try environment.translatingJNIExceptions {
392+
jniMethod!(environment, thisClass, methodID, jniArgs)
393+
}
379394
}
380395
}
381396

@@ -403,7 +418,9 @@ extension JavaClass {
403418

404419
let fieldID = getJNIStaticFieldID(fieldName, fieldType: fieldType)!
405420
let jniMethod = FieldType.jniStaticFieldSet(in: environment)
406-
jniMethod(environment, javaThis, fieldID, newValue.getJNIValue(in: environment))
421+
try! environment.withLocalFrame(capacity: 1) {
422+
jniMethod(environment, javaThis, fieldID, newValue.getJNIValue(in: environment))
423+
}
407424
}
408425
}
409426
}

0 commit comments

Comments
 (0)