Skip to content

Commit c0f166d

Browse files
ktosorintaro
andauthored
[SwiftKit] Move 'selfPointer' to 'JNISwiftInstance' & downcall trace logs (#322)
Co-authored-by: Rintaro Ishizaki <rishizaki@apple.com>
1 parent 19a6785 commit c0f166d

26 files changed

+451
-235
lines changed

Samples/SwiftKitSampleApp/src/main/java/com/example/swift/HelloJava2Swift.java

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
// Import javakit/swiftkit support libraries
2020

21+
import org.swift.swiftkit.core.CallTraces;
2122
import org.swift.swiftkit.core.SwiftLibraries;
2223
import org.swift.swiftkit.ffm.AllocatingSwiftArena;
2324
import org.swift.swiftkit.ffm.SwiftRuntime;
@@ -43,30 +44,30 @@ static void examples() {
4344

4445
long cnt = MySwiftLibrary.globalWriteString("String from Java");
4546

46-
SwiftRuntime.trace("count = " + cnt);
47+
CallTraces.trace("count = " + cnt);
4748

4849
MySwiftLibrary.globalCallMeRunnable(() -> {
49-
SwiftRuntime.trace("running runnable");
50+
CallTraces.trace("running runnable");
5051
});
5152

52-
SwiftRuntime.trace("getGlobalBuffer().byteSize()=" + MySwiftLibrary.getGlobalBuffer().byteSize());
53+
CallTraces.trace("getGlobalBuffer().byteSize()=" + MySwiftLibrary.getGlobalBuffer().byteSize());
5354

5455
MySwiftLibrary.withBuffer((buf) -> {
55-
SwiftRuntime.trace("withBuffer{$0.byteSize()}=" + buf.byteSize());
56+
CallTraces.trace("withBuffer{$0.byteSize()}=" + buf.byteSize());
5657
});
5758
// Example of using an arena; MyClass.deinit is run at end of scope
5859
try (var arena = AllocatingSwiftArena.ofConfined()) {
5960
MySwiftClass obj = MySwiftClass.init(2222, 7777, arena);
6061

6162
// just checking retains/releases work
62-
SwiftRuntime.trace("retainCount = " + SwiftRuntime.retainCount(obj));
63+
CallTraces.trace("retainCount = " + SwiftRuntime.retainCount(obj));
6364
SwiftRuntime.retain(obj);
64-
SwiftRuntime.trace("retainCount = " + SwiftRuntime.retainCount(obj));
65+
CallTraces.trace("retainCount = " + SwiftRuntime.retainCount(obj));
6566
SwiftRuntime.release(obj);
66-
SwiftRuntime.trace("retainCount = " + SwiftRuntime.retainCount(obj));
67+
CallTraces.trace("retainCount = " + SwiftRuntime.retainCount(obj));
6768

6869
obj.setCounter(12);
69-
SwiftRuntime.trace("obj.counter = " + obj.getCounter());
70+
CallTraces.trace("obj.counter = " + obj.getCounter());
7071

7172
obj.voidMethod();
7273
obj.takeIntMethod(42);
@@ -75,22 +76,22 @@ static void examples() {
7576
otherObj.voidMethod();
7677

7778
MySwiftStruct swiftValue = MySwiftStruct.init(2222, 1111, arena);
78-
SwiftRuntime.trace("swiftValue.capacity = " + swiftValue.getCapacity());
79+
CallTraces.trace("swiftValue.capacity = " + swiftValue.getCapacity());
7980
swiftValue.withCapLen((cap, len) -> {
80-
SwiftRuntime.trace("withCapLenCallback: cap=" + cap + ", len=" + len);
81+
CallTraces.trace("withCapLenCallback: cap=" + cap + ", len=" + len);
8182
});
8283
}
8384

8485
// Example of using 'Data'.
8586
try (var arena = AllocatingSwiftArena.ofConfined()) {
8687
var origBytes = arena.allocateFrom("foobar");
8788
var origDat = Data.init(origBytes, origBytes.byteSize(), arena);
88-
SwiftRuntime.trace("origDat.count = " + origDat.getCount());
89+
CallTraces.trace("origDat.count = " + origDat.getCount());
8990

9091
var retDat = MySwiftLibrary.globalReceiveReturnData(origDat, arena);
9192
retDat.withUnsafeBytes((retBytes) -> {
9293
var str = retBytes.getString(0);
93-
SwiftRuntime.trace("retStr=" + str);
94+
CallTraces.trace("retStr=" + str);
9495
});
9596
}
9697

Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+JavaBindingsPrinting.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -116,8 +116,8 @@ extension FFMSwift2JavaGenerator {
116116
"""
117117
public static \(returnTy) call(\(paramsStr)) {
118118
try {
119-
if (SwiftRuntime.TRACE_DOWNCALLS) {
120-
SwiftRuntime.traceDowncall(\(argsStr));
119+
if (CallTraces.TRACE_DOWNCALLS) {
120+
CallTraces.traceDowncall(\(argsStr));
121121
}
122122
\(maybeReturn)HANDLE.invokeExact(\(argsStr));
123123
} catch (Throwable ex$) {

Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+SwiftThunkPrinting.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ extension FFMSwift2JavaGenerator {
131131
}
132132
printer.print("import \(module)")
133133
}
134+
printer.println()
134135
}
135136
}
136137

Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+JavaBindingsPrinting.swift

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -206,13 +206,15 @@ extension JNISwift2JavaGenerator {
206206
printDeclDocumentation(&printer, decl)
207207
printer.printBraceBlock("public \(renderFunctionSignature(decl))") { printer in
208208
var arguments = translatedDecl.translatedFunctionSignature.parameters.map(\.name)
209-
arguments.append("selfPointer")
209+
210+
let selfVarName = "self$"
211+
arguments.append(selfVarName)
210212

211213
let returnKeyword = translatedDecl.translatedFunctionSignature.resultType.isVoid ? "" : "return "
212214

213215
printer.print(
214216
"""
215-
long selfPointer = this.pointer();
217+
long \(selfVarName) = this.$memoryAddress();
216218
\(returnKeyword)\(translatedDecl.parentName).$\(translatedDecl.name)(\(arguments.joined(separator: ", ")));
217219
"""
218220
)
@@ -235,8 +237,8 @@ extension JNISwift2JavaGenerator {
235237
let initArguments = translatedDecl.translatedFunctionSignature.parameters.map(\.name)
236238
printer.print(
237239
"""
238-
long selfPointer = \(type.qualifiedName).allocatingInit(\(initArguments.joined(separator: ", ")));
239-
return new \(type.qualifiedName)(selfPointer, swiftArena$);
240+
long self$ = \(type.qualifiedName).allocatingInit(\(initArguments.joined(separator: ", ")));
241+
return new \(type.qualifiedName)(self$, swiftArena$);
240242
"""
241243
)
242244
}
@@ -262,15 +264,24 @@ extension JNISwift2JavaGenerator {
262264
private func printDestroyFunction(_ printer: inout CodePrinter, _ type: ImportedNominalType) {
263265
printer.print("private static native void $destroy(long selfPointer);")
264266

267+
let funcName = "$createDestroyFunction"
265268
printer.print("@Override")
266-
printer.printBraceBlock("protected Runnable $createDestroyFunction()") { printer in
269+
printer.printBraceBlock("protected Runnable \(funcName)()") { printer in
267270
printer.print(
268271
"""
269-
long $selfPointer = this.pointer();
272+
long self$ = this.$memoryAddress();
273+
if (CallTraces.TRACE_DOWNCALLS) {
274+
CallTraces.traceDowncall("\(type.swiftNominal.name).\(funcName)",
275+
"this", this,
276+
"self", self$);
277+
}
270278
return new Runnable() {
271279
@Override
272280
public void run() {
273-
\(type.swiftNominal.name).$destroy($selfPointer);
281+
if (CallTraces.TRACE_DOWNCALLS) {
282+
CallTraces.traceDowncall("\(type.swiftNominal.name).$destroy", "self", self$);
283+
}
284+
\(type.swiftNominal.name).$destroy(self$);
274285
}
275286
};
276287
"""

Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+SwiftThunkPrinting.swift

Lines changed: 37 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -138,9 +138,9 @@ extension JNISwift2JavaGenerator {
138138
// TODO: Throwing initializers
139139
printer.print(
140140
"""
141-
let selfPointer = UnsafeMutablePointer<\(typeName)>.allocate(capacity: 1)
142-
selfPointer.initialize(to: \(typeName)(\(downcallArguments)))
143-
return Int64(Int(bitPattern: selfPointer)).getJNIValue(in: environment)
141+
let self$ = UnsafeMutablePointer<\(typeName)>.allocate(capacity: 1)
142+
self$.initialize(to: \(typeName)(\(downcallArguments)))
143+
return Int64(Int(bitPattern: self$)).getJNIValue(in: environment)
144144
"""
145145
)
146146
}
@@ -184,22 +184,20 @@ extension JNISwift2JavaGenerator {
184184
let translatedDecl = self.translatedDecl(for: decl)! // We will only call this method if can translate the decl.
185185
let swiftParentName = decl.parentType!.asNominalTypeDeclaration!.qualifiedName
186186

187+
let selfPointerParam = JavaParameter(name: "selfPointer", type: .long)
187188
printCDecl(
188189
&printer,
189190
javaMethodName: "$\(translatedDecl.name)",
190191
parentName: translatedDecl.parentName,
191192
parameters: translatedDecl.translatedFunctionSignature.parameters + [
192-
JavaParameter(name: "selfPointer", type: .long)
193+
selfPointerParam
193194
],
194195
isStatic: true,
195196
resultType: translatedDecl.translatedFunctionSignature.resultType
196197
) { printer in
197-
printer.print(
198-
"""
199-
let self$ = UnsafeMutablePointer<\(swiftParentName)>(bitPattern: Int(Int64(fromJNI: selfPointer, in: environment!)))!
200-
"""
201-
)
202-
self.printFunctionDowncall(&printer, decl, calleeName: "self$.pointee")
198+
let selfVar = self.printSelfJLongToUnsafeMutablePointer(&printer,
199+
swiftParentName: swiftParentName, selfPointerParam)
200+
self.printFunctionDowncall(&printer, decl, calleeName: "\(selfVar).pointee")
203201
}
204202
}
205203

@@ -320,28 +318,53 @@ extension JNISwift2JavaGenerator {
320318

321319
/// Prints the implementation of the destroy function.
322320
private func printDestroyFunctionThunk(_ printer: inout CodePrinter, _ type: ImportedNominalType) {
321+
let selfPointerParam = JavaParameter(name: "selfPointer", type: .long)
323322
printCDecl(
324323
&printer,
325324
javaMethodName: "$destroy",
326325
parentName: type.swiftNominal.name,
327326
parameters: [
328-
JavaParameter(name: "selfPointer", type: .long)
327+
selfPointerParam
329328
],
330329
isStatic: true,
331330
resultType: .void
332331
) { printer in
332+
let parentName = type.qualifiedName
333+
let selfVar = self.printSelfJLongToUnsafeMutablePointer(&printer, swiftParentName: parentName, selfPointerParam)
333334
// Deinitialize the pointer allocated (which will call the VWT destroy method)
334335
// then deallocate the memory.
335336
printer.print(
336337
"""
337-
let pointer = UnsafeMutablePointer<\(type.qualifiedName)>(bitPattern: Int(Int64(fromJNI: selfPointer, in: environment!)))!
338-
pointer.deinitialize(count: 1)
339-
pointer.deallocate()
338+
\(selfVar).deinitialize(count: 1)
339+
\(selfVar).deallocate()
340340
"""
341341
)
342342
}
343343
}
344344

345+
/// Print the necessary conversion logic to go from a `jlong` to a `UnsafeMutablePointer<Type>`
346+
///
347+
/// - Returns: name of the created "self" variable
348+
private func printSelfJLongToUnsafeMutablePointer(
349+
_ printer: inout CodePrinter,
350+
swiftParentName: String, _ selfPointerParam: JavaParameter) -> String {
351+
let newSelfParamName = "self$"
352+
printer.print(
353+
"""
354+
guard let env$ = environment else {
355+
fatalError("Missing JNIEnv in downcall to \\(#function)")
356+
}
357+
assert(\(selfPointerParam.name) != 0, "\(selfPointerParam.name) memory address was null")
358+
let selfBits$ = Int(Int64(fromJNI: \(selfPointerParam.name), in: env$))
359+
guard let \(newSelfParamName) = UnsafeMutablePointer<\(swiftParentName)>(bitPattern: selfBits$) else {
360+
fatalError("self memory address was null in call to \\(#function)!")
361+
}
362+
"""
363+
)
364+
return newSelfParamName
365+
}
366+
367+
345368
/// Renders the arguments for making a downcall
346369
private func renderDowncallArguments(
347370
swiftFunctionSignature: SwiftFunctionSignature,
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2024 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+
package org.swift.swiftkit.core;
16+
17+
public class CallTraces {
18+
public static final boolean TRACE_DOWNCALLS =
19+
Boolean.getBoolean("jextract.trace.downcalls");
20+
21+
// Used to manually debug with complete backtraces on every traceDowncall
22+
public static final boolean TRACE_DOWNCALLS_FULL = false;
23+
24+
public static void traceDowncall(Object... args) {
25+
RuntimeException ex = new RuntimeException();
26+
27+
String traceArgs = joinArgs(args);
28+
System.err.printf("[java][%s:%d] Downcall: %s.%s(%s)\n",
29+
ex.getStackTrace()[1].getFileName(),
30+
ex.getStackTrace()[1].getLineNumber(),
31+
ex.getStackTrace()[1].getClassName(),
32+
ex.getStackTrace()[1].getMethodName(),
33+
traceArgs);
34+
if (TRACE_DOWNCALLS_FULL) {
35+
ex.printStackTrace();
36+
}
37+
}
38+
39+
public static void trace(Object... args) {
40+
RuntimeException ex = new RuntimeException();
41+
42+
String traceArgs = joinArgs(args);
43+
System.err.printf("[java][%s:%d] %s: %s\n",
44+
ex.getStackTrace()[1].getFileName(),
45+
ex.getStackTrace()[1].getLineNumber(),
46+
ex.getStackTrace()[1].getMethodName(),
47+
traceArgs);
48+
}
49+
50+
private static String joinArgs(Object[] args) {
51+
StringBuilder sb = new StringBuilder();
52+
for (int i = 0; i < args.length; i++) {
53+
if (i > 0) {
54+
sb.append(", ");
55+
}
56+
sb.append(args[i].toString());
57+
}
58+
return sb.toString();
59+
}
60+
61+
}

SwiftKitCore/src/main/java/org/swift/swiftkit/core/ConfinedSwiftMemorySession.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ public void close() {
6060
public void register(SwiftInstance instance) {
6161
checkValid();
6262

63-
SwiftInstanceCleanup cleanup = instance.createCleanupAction();
63+
SwiftInstanceCleanup cleanup = instance.$createCleanup();
6464
this.resources.add(cleanup);
6565
}
6666

SwiftKitCore/src/main/java/org/swift/swiftkit/core/JNISwiftInstance.java

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,30 @@
1414

1515
package org.swift.swiftkit.core;
1616

17+
import java.util.Objects;
1718
import java.util.concurrent.atomic.AtomicBoolean;
1819

1920
public abstract class JNISwiftInstance extends SwiftInstance {
21+
// Pointer to the "self".
22+
protected final long selfPointer;
23+
2024
/**
2125
* The designated constructor of any imported Swift types.
2226
*
23-
* @param pointer a pointer to the memory containing the value
27+
* @param selfPointer a pointer to the memory containing the value
2428
* @param arena the arena this object belongs to. When the arena goes out of scope, this value is destroyed.
2529
*/
26-
protected JNISwiftInstance(long pointer, SwiftArena arena) {
27-
super(pointer, arena);
30+
protected JNISwiftInstance(long selfPointer, SwiftArena arena) {
31+
SwiftObjects.requireNonZero(selfPointer, "selfPointer");
32+
this.selfPointer = selfPointer;
33+
34+
// Only register once we have fully initialized the object since this will need the object pointer.
35+
arena.register(this);
36+
}
37+
38+
@Override
39+
public long $memoryAddress() {
40+
return this.selfPointer;
2841
}
2942

3043
/**
@@ -42,7 +55,7 @@ protected JNISwiftInstance(long pointer, SwiftArena arena) {
4255
protected abstract Runnable $createDestroyFunction();
4356

4457
@Override
45-
public SwiftInstanceCleanup createCleanupAction() {
58+
public SwiftInstanceCleanup $createCleanup() {
4659
final AtomicBoolean statusDestroyedFlag = $statusDestroyedFlag();
4760
Runnable markAsDestroyed = new Runnable() {
4861
@Override

0 commit comments

Comments
 (0)