From c41bfb0dac67fffc7f7a198686b966e62198dc98 Mon Sep 17 00:00:00 2001 From: Rintaro Ishizaki Date: Tue, 15 Jul 2025 16:30:26 -0700 Subject: [PATCH 01/13] [SwiftKit] Move 'selfPointer' to 'JNISwiftInstance' `FFMSwiftInstance` doesn't need it. --- .../org/swift/swiftkit/core/JNISwiftInstance.java | 13 ++++++++++++- .../java/org/swift/swiftkit/core/SwiftInstance.java | 12 +----------- .../org/swift/swiftkit/ffm/FFMSwiftInstance.java | 2 +- 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/SwiftKitCore/src/main/java/org/swift/swiftkit/core/JNISwiftInstance.java b/SwiftKitCore/src/main/java/org/swift/swiftkit/core/JNISwiftInstance.java index f9966793..a63a27f4 100644 --- a/SwiftKitCore/src/main/java/org/swift/swiftkit/core/JNISwiftInstance.java +++ b/SwiftKitCore/src/main/java/org/swift/swiftkit/core/JNISwiftInstance.java @@ -17,6 +17,16 @@ import java.util.concurrent.atomic.AtomicBoolean; public abstract class JNISwiftInstance extends SwiftInstance { + /// Pointer to the "self". + private final long selfPointer; + + /** + * The pointer to the instance in memory. I.e. the {@code self} of the Swift object or value. + */ + public final long pointer() { + return this.selfPointer; + } + /** * The designated constructor of any imported Swift types. * @@ -24,7 +34,8 @@ public abstract class JNISwiftInstance extends SwiftInstance { * @param arena the arena this object belongs to. When the arena goes out of scope, this value is destroyed. */ protected JNISwiftInstance(long pointer, SwiftArena arena) { - super(pointer, arena); + super(arena); + this.selfPointer = pointer; } /** diff --git a/SwiftKitCore/src/main/java/org/swift/swiftkit/core/SwiftInstance.java b/SwiftKitCore/src/main/java/org/swift/swiftkit/core/SwiftInstance.java index 638cb8be..6d65c043 100644 --- a/SwiftKitCore/src/main/java/org/swift/swiftkit/core/SwiftInstance.java +++ b/SwiftKitCore/src/main/java/org/swift/swiftkit/core/SwiftInstance.java @@ -17,15 +17,6 @@ import java.util.concurrent.atomic.AtomicBoolean; public abstract class SwiftInstance { - /// Pointer to the "self". - private final long selfPointer; - - /** - * The pointer to the instance in memory. I.e. the {@code self} of the Swift object or value. - */ - public final long pointer() { - return this.selfPointer; - } /** * Called when the arena has decided the value should be destroyed. @@ -55,8 +46,7 @@ public final long pointer() { * @param pointer a pointer to the memory containing the value * @param arena the arena this object belongs to. When the arena goes out of scope, this value is destroyed. */ - protected SwiftInstance(long pointer, SwiftArena arena) { - this.selfPointer = pointer; + protected SwiftInstance(SwiftArena arena) { arena.register(this); } diff --git a/SwiftKitFFM/src/main/java/org/swift/swiftkit/ffm/FFMSwiftInstance.java b/SwiftKitFFM/src/main/java/org/swift/swiftkit/ffm/FFMSwiftInstance.java index f4a01aa4..d6d8a8d6 100644 --- a/SwiftKitFFM/src/main/java/org/swift/swiftkit/ffm/FFMSwiftInstance.java +++ b/SwiftKitFFM/src/main/java/org/swift/swiftkit/ffm/FFMSwiftInstance.java @@ -41,7 +41,7 @@ public abstract class FFMSwiftInstance extends SwiftInstance { * @param arena the arena this object belongs to. When the arena goes out of scope, this value is destroyed. */ protected FFMSwiftInstance(MemorySegment segment, AllocatingSwiftArena arena) { - super(segment.address(), arena); + super(arena); this.memorySegment = segment; } From e44470018f8cc362b460230a62ef35d6a0447ddf Mon Sep 17 00:00:00 2001 From: Konrad 'ktoso' Malawski Date: Wed, 16 Jul 2025 09:21:41 +0900 Subject: [PATCH 02/13] keep long returning memory address func in base SwiftInstance --- .../swift/swiftkit/core/JNISwiftInstance.java | 5 ++++ .../swift/swiftkit/core/SwiftInstance.java | 30 ++++++++++++------- .../swift/swiftkit/ffm/FFMSwiftInstance.java | 26 +++++++++------- 3 files changed, 40 insertions(+), 21 deletions(-) diff --git a/SwiftKitCore/src/main/java/org/swift/swiftkit/core/JNISwiftInstance.java b/SwiftKitCore/src/main/java/org/swift/swiftkit/core/JNISwiftInstance.java index a63a27f4..4b19f6fd 100644 --- a/SwiftKitCore/src/main/java/org/swift/swiftkit/core/JNISwiftInstance.java +++ b/SwiftKitCore/src/main/java/org/swift/swiftkit/core/JNISwiftInstance.java @@ -38,6 +38,11 @@ protected JNISwiftInstance(long pointer, SwiftArena arena) { this.selfPointer = pointer; } + @Override + public long $memoryAddress() { + return selfPointer; + } + /** * Creates a function that will be called when the value should be destroyed. * This will be code-generated to call a native method to do deinitialization and deallocation. diff --git a/SwiftKitCore/src/main/java/org/swift/swiftkit/core/SwiftInstance.java b/SwiftKitCore/src/main/java/org/swift/swiftkit/core/SwiftInstance.java index 6d65c043..1f0a9a33 100644 --- a/SwiftKitCore/src/main/java/org/swift/swiftkit/core/SwiftInstance.java +++ b/SwiftKitCore/src/main/java/org/swift/swiftkit/core/SwiftInstance.java @@ -18,6 +18,24 @@ public abstract class SwiftInstance { + /** + * The designated constructor of any imported Swift types. + * + * @param arena the arena this object belongs to. When the arena goes out of scope, this value is destroyed. + */ + protected SwiftInstance(SwiftArena arena) { + arena.register(this); + } + + /** + * Pointer to the {@code self} of the underlying Swift object or value. + * + * @apiNote When using this pointer one must ensure that the underlying object + * is kept alive using some means (e.g. a class remains retained), as + * this function does not ensure safety of the address in any way. + */ + public abstract long $memoryAddress(); + /** * Called when the arena has decided the value should be destroyed. *

@@ -34,22 +52,12 @@ public abstract class SwiftInstance { *

* This is exposing the object, rather than performing the action because we don't want to accidentally * form a strong reference to the {@code SwiftInstance} which could prevent the cleanup from running, - * if using an GC managed instance (e.g. using an {@link AutoSwiftMemorySession}. + * if using an GC managed instance (e.g. using an {@code AutoSwiftMemorySession}. */ public final AtomicBoolean $statusDestroyedFlag() { return this.$state$destroyed; } - /** - * The designated constructor of any imported Swift types. - * - * @param pointer a pointer to the memory containing the value - * @param arena the arena this object belongs to. When the arena goes out of scope, this value is destroyed. - */ - protected SwiftInstance(SwiftArena arena) { - arena.register(this); - } - /** * Ensures that this instance has not been destroyed. *

diff --git a/SwiftKitFFM/src/main/java/org/swift/swiftkit/ffm/FFMSwiftInstance.java b/SwiftKitFFM/src/main/java/org/swift/swiftkit/ffm/FFMSwiftInstance.java index d6d8a8d6..5e157f0e 100644 --- a/SwiftKitFFM/src/main/java/org/swift/swiftkit/ffm/FFMSwiftInstance.java +++ b/SwiftKitFFM/src/main/java/org/swift/swiftkit/ffm/FFMSwiftInstance.java @@ -22,6 +22,17 @@ public abstract class FFMSwiftInstance extends SwiftInstance { private final MemorySegment memorySegment; + /** + * The designated constructor of any imported Swift types. + * + * @param segment the memory segment. + * @param arena the arena this object belongs to. When the arena goes out of scope, this value is destroyed. + */ + protected FFMSwiftInstance(MemorySegment segment, AllocatingSwiftArena arena) { + super(arena); + this.memorySegment = segment; + } + /** * The pointer to the instance in memory. I.e. the {@code self} of the Swift object or value. */ @@ -29,21 +40,16 @@ public abstract class FFMSwiftInstance extends SwiftInstance { return this.memorySegment; } + @Override + public long $memoryAddress() { + return $memorySegment().address(); + } + /** * The Swift type metadata of this type. */ public abstract SwiftAnyType $swiftType(); - /** - * The designated constructor of any imported Swift types. - * - * @param segment the memory segment. - * @param arena the arena this object belongs to. When the arena goes out of scope, this value is destroyed. - */ - protected FFMSwiftInstance(MemorySegment segment, AllocatingSwiftArena arena) { - super(arena); - this.memorySegment = segment; - } @Override public SwiftInstanceCleanup createCleanupAction() { From 21e409d1d751049e159427054afbaa78125ff6ac Mon Sep 17 00:00:00 2001 From: Konrad 'ktoso' Malawski Date: Wed, 16 Jul 2025 16:31:17 +0900 Subject: [PATCH 03/13] Add CallTraces to swiftkit core and use it while downcalling --- .../com/example/swift/HelloJava2Swift.java | 25 ++++---- ...t2JavaGenerator+JavaBindingsPrinting.swift | 4 +- ...t2JavaGenerator+JavaBindingsPrinting.swift | 16 ++++- .../org/swift/swiftkit/core/CallTraces.java | 61 +++++++++++++++++++ .../swift/swiftkit/core/SwiftLibraries.java | 3 +- .../org/swift/swiftkit/core/SwiftObjects.java | 26 ++++++++ .../org/swift/swiftkit/ffm/SwiftRuntime.java | 40 +++--------- .../JExtractSwiftTests/DataImportTests.swift | 24 ++++---- .../FuncCallbackImportTests.swift | 12 ++-- .../FunctionDescriptorImportTests.swift | 20 +++--- .../StringPassingTests.swift | 4 +- .../VariableImportTests.swift | 8 +-- 12 files changed, 157 insertions(+), 86 deletions(-) create mode 100644 SwiftKitCore/src/main/java/org/swift/swiftkit/core/CallTraces.java create mode 100644 SwiftKitCore/src/main/java/org/swift/swiftkit/core/SwiftObjects.java diff --git a/Samples/SwiftKitSampleApp/src/main/java/com/example/swift/HelloJava2Swift.java b/Samples/SwiftKitSampleApp/src/main/java/com/example/swift/HelloJava2Swift.java index 3b083cc0..cecb1231 100644 --- a/Samples/SwiftKitSampleApp/src/main/java/com/example/swift/HelloJava2Swift.java +++ b/Samples/SwiftKitSampleApp/src/main/java/com/example/swift/HelloJava2Swift.java @@ -18,6 +18,7 @@ // Import javakit/swiftkit support libraries +import org.swift.swiftkit.core.CallTraces; import org.swift.swiftkit.core.SwiftLibraries; import org.swift.swiftkit.ffm.AllocatingSwiftArena; import org.swift.swiftkit.ffm.SwiftRuntime; @@ -43,30 +44,30 @@ static void examples() { long cnt = MySwiftLibrary.globalWriteString("String from Java"); - SwiftRuntime.trace("count = " + cnt); + CallTraces.trace("count = " + cnt); MySwiftLibrary.globalCallMeRunnable(() -> { - SwiftRuntime.trace("running runnable"); + CallTraces.trace("running runnable"); }); - SwiftRuntime.trace("getGlobalBuffer().byteSize()=" + MySwiftLibrary.getGlobalBuffer().byteSize()); + CallTraces.trace("getGlobalBuffer().byteSize()=" + MySwiftLibrary.getGlobalBuffer().byteSize()); MySwiftLibrary.withBuffer((buf) -> { - SwiftRuntime.trace("withBuffer{$0.byteSize()}=" + buf.byteSize()); + CallTraces.trace("withBuffer{$0.byteSize()}=" + buf.byteSize()); }); // Example of using an arena; MyClass.deinit is run at end of scope try (var arena = AllocatingSwiftArena.ofConfined()) { MySwiftClass obj = MySwiftClass.init(2222, 7777, arena); // just checking retains/releases work - SwiftRuntime.trace("retainCount = " + SwiftRuntime.retainCount(obj)); + CallTraces.trace("retainCount = " + SwiftRuntime.retainCount(obj)); SwiftRuntime.retain(obj); - SwiftRuntime.trace("retainCount = " + SwiftRuntime.retainCount(obj)); + CallTraces.trace("retainCount = " + SwiftRuntime.retainCount(obj)); SwiftRuntime.release(obj); - SwiftRuntime.trace("retainCount = " + SwiftRuntime.retainCount(obj)); + CallTraces.trace("retainCount = " + SwiftRuntime.retainCount(obj)); obj.setCounter(12); - SwiftRuntime.trace("obj.counter = " + obj.getCounter()); + CallTraces.trace("obj.counter = " + obj.getCounter()); obj.voidMethod(); obj.takeIntMethod(42); @@ -75,9 +76,9 @@ static void examples() { otherObj.voidMethod(); MySwiftStruct swiftValue = MySwiftStruct.init(2222, 1111, arena); - SwiftRuntime.trace("swiftValue.capacity = " + swiftValue.getCapacity()); + CallTraces.trace("swiftValue.capacity = " + swiftValue.getCapacity()); swiftValue.withCapLen((cap, len) -> { - SwiftRuntime.trace("withCapLenCallback: cap=" + cap + ", len=" + len); + CallTraces.trace("withCapLenCallback: cap=" + cap + ", len=" + len); }); } @@ -85,12 +86,12 @@ static void examples() { try (var arena = AllocatingSwiftArena.ofConfined()) { var origBytes = arena.allocateFrom("foobar"); var origDat = Data.init(origBytes, origBytes.byteSize(), arena); - SwiftRuntime.trace("origDat.count = " + origDat.getCount()); + CallTraces.trace("origDat.count = " + origDat.getCount()); var retDat = MySwiftLibrary.globalReceiveReturnData(origDat, arena); retDat.withUnsafeBytes((retBytes) -> { var str = retBytes.getString(0); - SwiftRuntime.trace("retStr=" + str); + CallTraces.trace("retStr=" + str); }); } diff --git a/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+JavaBindingsPrinting.swift b/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+JavaBindingsPrinting.swift index 13230a32..28b3aba1 100644 --- a/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+JavaBindingsPrinting.swift +++ b/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+JavaBindingsPrinting.swift @@ -116,8 +116,8 @@ extension FFMSwift2JavaGenerator { """ public static \(returnTy) call(\(paramsStr)) { try { - if (SwiftRuntime.TRACE_DOWNCALLS) { - SwiftRuntime.traceDowncall(\(argsStr)); + if (CallTraces.TRACE_DOWNCALLS) { + CallTraces.traceDowncall(\(argsStr)); } \(maybeReturn)HANDLE.invokeExact(\(argsStr)); } catch (Throwable ex$) { diff --git a/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+JavaBindingsPrinting.swift b/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+JavaBindingsPrinting.swift index 80b47760..fa07aa84 100644 --- a/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+JavaBindingsPrinting.swift +++ b/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+JavaBindingsPrinting.swift @@ -262,15 +262,25 @@ extension JNISwift2JavaGenerator { private func printDestroyFunction(_ printer: inout CodePrinter, _ type: ImportedNominalType) { printer.print("private static native void $destroy(long selfPointer);") + let funcName = "$createDestroyFunction" printer.print("@Override") - printer.printBraceBlock("protected Runnable $createDestroyFunction()") { printer in + printer.printBraceBlock("protected Runnable \(funcName)()") { printer in printer.print( """ - long $selfPointer = this.pointer(); + if (CallTraces.TRACE_DOWNCALLS) { + CallTraces.traceDowncall("\(type.swiftNominal.name).\(funcName)", + "this", this, + "this.$memoryAddress()", this.$memoryAddress()); + } + long self$ = this.$memoryAddress(); + assert(self$ > 0); return new Runnable() { @Override public void run() { - \(type.swiftNominal.name).$destroy($selfPointer); + if (CallTraces.TRACE_DOWNCALLS) { + CallTraces.traceDowncall("\(type.swiftNominal.name).$destroy(" + self$ + ")"); + } + \(type.swiftNominal.name).$destroy(self$); } }; """ diff --git a/SwiftKitCore/src/main/java/org/swift/swiftkit/core/CallTraces.java b/SwiftKitCore/src/main/java/org/swift/swiftkit/core/CallTraces.java new file mode 100644 index 00000000..358205ff --- /dev/null +++ b/SwiftKitCore/src/main/java/org/swift/swiftkit/core/CallTraces.java @@ -0,0 +1,61 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2024 Apple Inc. and the Swift.org project authors +// Licensed under Apache License v2.0 +// +// See LICENSE.txt for license information +// See CONTRIBUTORS.txt for the list of Swift.org project authors +// +// SPDX-License-Identifier: Apache-2.0 +// +//===----------------------------------------------------------------------===// + +package org.swift.swiftkit.core; + +public class CallTraces { + public static final boolean TRACE_DOWNCALLS = + Boolean.getBoolean("jextract.trace.downcalls"); + + // Used to manually debug with complete backtraces on every traceDowncall + public static final boolean TRACE_DOWNCALLS_FULL = false; + + public static void traceDowncall(Object... args) { + RuntimeException ex = new RuntimeException(); + + String traceArgs = joinArgs(args); + System.err.printf("[java][%s:%d] Downcall: %s.%s(%s)\n", + ex.getStackTrace()[1].getFileName(), + ex.getStackTrace()[1].getLineNumber(), + ex.getStackTrace()[1].getClassName(), + ex.getStackTrace()[1].getMethodName(), + traceArgs); + if (TRACE_DOWNCALLS_FULL) { + ex.printStackTrace(); + } + } + + public static void trace(Object... args) { + RuntimeException ex = new RuntimeException(); + + String traceArgs = joinArgs(args); + System.err.printf("[java][%s:%d] %s: %s\n", + ex.getStackTrace()[1].getFileName(), + ex.getStackTrace()[1].getLineNumber(), + ex.getStackTrace()[1].getMethodName(), + traceArgs); + } + + private static String joinArgs(Object[] args) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < args.length; i++) { + if (i > 0) { + sb.append(", "); + } + sb.append(args[i].toString()); + } + return sb.toString(); + } + +} diff --git a/SwiftKitCore/src/main/java/org/swift/swiftkit/core/SwiftLibraries.java b/SwiftKitCore/src/main/java/org/swift/swiftkit/core/SwiftLibraries.java index 2abdaff5..3230e52a 100644 --- a/SwiftKitCore/src/main/java/org/swift/swiftkit/core/SwiftLibraries.java +++ b/SwiftKitCore/src/main/java/org/swift/swiftkit/core/SwiftLibraries.java @@ -26,7 +26,6 @@ public final class SwiftLibraries { public static final String STDLIB_DYLIB_NAME = "swiftCore"; public static final String SWIFTKITSWIFT_DYLIB_NAME = "SwiftKitSwift"; - public static final boolean TRACE_DOWNCALLS = Boolean.getBoolean("jextract.trace.downcalls"); private static final String STDLIB_MACOS_DYLIB_PATH = "/usr/lib/swift/libswiftCore.dylib"; @@ -57,7 +56,7 @@ public static void loadLibrary(String libname) { public static void loadResourceLibrary(String libname) { String resourceName = PlatformUtils.dynamicLibraryName(libname); - if (SwiftLibraries.TRACE_DOWNCALLS) { + if (CallTraces.TRACE_DOWNCALLS) { System.out.println("[swift-java] Loading resource library: " + resourceName); } diff --git a/SwiftKitCore/src/main/java/org/swift/swiftkit/core/SwiftObjects.java b/SwiftKitCore/src/main/java/org/swift/swiftkit/core/SwiftObjects.java new file mode 100644 index 00000000..c508e90e --- /dev/null +++ b/SwiftKitCore/src/main/java/org/swift/swiftkit/core/SwiftObjects.java @@ -0,0 +1,26 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2024 Apple Inc. and the Swift.org project authors +// Licensed under Apache License v2.0 +// +// See LICENSE.txt for license information +// See CONTRIBUTORS.txt for the list of Swift.org project authors +// +// SPDX-License-Identifier: Apache-2.0 +// +//===----------------------------------------------------------------------===// + +package org.swift.swiftkit.core; + +/** + * Utility functions, similar to @{link java.util.Objects} + */ +public class SwiftObjects { + public static void requireNonZero(long number, String name) { + if (number == 0) { + throw new IllegalArgumentException(String.format("'%s' must not be zero!", name)); + } + } +} diff --git a/SwiftKitFFM/src/main/java/org/swift/swiftkit/ffm/SwiftRuntime.java b/SwiftKitFFM/src/main/java/org/swift/swiftkit/ffm/SwiftRuntime.java index dc18b445..eca6be82 100644 --- a/SwiftKitFFM/src/main/java/org/swift/swiftkit/ffm/SwiftRuntime.java +++ b/SwiftKitFFM/src/main/java/org/swift/swiftkit/ffm/SwiftRuntime.java @@ -15,6 +15,7 @@ package org.swift.swiftkit.ffm; import org.swift.swiftkit.core.SwiftInstance; +import org.swift.swiftkit.core.CallTraces; import org.swift.swiftkit.core.util.PlatformUtils; import java.lang.foreign.*; @@ -24,6 +25,7 @@ import java.util.*; import java.util.stream.Collectors; +import static org.swift.swiftkit.core.CallTraces.traceDowncall; import static org.swift.swiftkit.core.util.StringUtils.stripPrefix; import static org.swift.swiftkit.core.util.StringUtils.stripSuffix; @@ -31,7 +33,6 @@ public class SwiftRuntime { public static final String STDLIB_DYLIB_NAME = "swiftCore"; public static final String SWIFTKITSWIFT_DYLIB_NAME = "SwiftKitSwift"; - public static final boolean TRACE_DOWNCALLS = Boolean.getBoolean("jextract.trace.downcalls"); private static final String STDLIB_MACOS_DYLIB_PATH = "/usr/lib/swift/libswiftCore.dylib"; @@ -65,33 +66,6 @@ private static SymbolLookup getSymbolLookup() { public SwiftRuntime() { } - public static void traceDowncall(Object... args) { - var ex = new RuntimeException(); - - String traceArgs = Arrays.stream(args) - .map(Object::toString) - .collect(Collectors.joining(", ")); - System.out.printf("[java][%s:%d] Downcall: %s.%s(%s)\n", - ex.getStackTrace()[1].getFileName(), - ex.getStackTrace()[1].getLineNumber(), - ex.getStackTrace()[1].getClassName(), - ex.getStackTrace()[1].getMethodName(), - traceArgs); - } - - public static void trace(Object... args) { - var ex = new RuntimeException(); - - String traceArgs = Arrays.stream(args) - .map(Object::toString) - .collect(Collectors.joining(", ")); - System.out.printf("[java][%s:%d] %s: %s\n", - ex.getStackTrace()[1].getFileName(), - ex.getStackTrace()[1].getLineNumber(), - ex.getStackTrace()[1].getMethodName(), - traceArgs); - } - static MemorySegment findOrThrow(String symbol) { return SYMBOL_LOOKUP.find(symbol) .orElseThrow(() -> new UnsatisfiedLinkError("unresolved symbol: %s".formatted(symbol))); @@ -152,7 +126,7 @@ private static class swift_retainCount { public static long retainCount(MemorySegment object) { var mh$ = swift_retainCount.HANDLE; try { - if (TRACE_DOWNCALLS) { + if (CallTraces.TRACE_DOWNCALLS) { traceDowncall("swift_retainCount", object); } return (long) mh$.invokeExact(object); @@ -182,7 +156,7 @@ private static class swift_retain { public static void retain(MemorySegment object) { var mh$ = swift_retain.HANDLE; try { - if (TRACE_DOWNCALLS) { + if (CallTraces.TRACE_DOWNCALLS) { traceDowncall("swift_retain", object); } mh$.invokeExact(object); @@ -212,7 +186,7 @@ private static class swift_release { public static void release(MemorySegment object) { var mh$ = swift_release.HANDLE; try { - if (TRACE_DOWNCALLS) { + if (CallTraces.TRACE_DOWNCALLS) { traceDowncall("swift_release", object); } mh$.invokeExact(object); @@ -248,7 +222,7 @@ private static class swift_getTypeByName { public static MemorySegment getTypeByName(String string) { var mh$ = swift_getTypeByName.HANDLE; try { - if (TRACE_DOWNCALLS) { + if (CallTraces.TRACE_DOWNCALLS) { traceDowncall("_typeByName"); } // TODO: A bit annoying to generate, we need an arena for the conversion... @@ -303,7 +277,7 @@ public static Optional getTypeByMangledNameInEnvironment(String ma // contain this, but we don't need it for type lookup mangledName = stripSuffix(mangledName, "Ma"); mangledName = stripSuffix(mangledName, "CN"); - if (TRACE_DOWNCALLS) { + if (CallTraces.TRACE_DOWNCALLS) { traceDowncall("swift_getTypeByMangledNameInEnvironment", mangledName); } try (Arena arena = Arena.ofConfined()) { diff --git a/Tests/JExtractSwiftTests/DataImportTests.swift b/Tests/JExtractSwiftTests/DataImportTests.swift index 104f7f0e..1bd12cbc 100644 --- a/Tests/JExtractSwiftTests/DataImportTests.swift +++ b/Tests/JExtractSwiftTests/DataImportTests.swift @@ -108,8 +108,8 @@ final class DataImportTests { private static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC); public static void call(java.lang.foreign.MemorySegment dat) { try { - if (SwiftRuntime.TRACE_DOWNCALLS) { - SwiftRuntime.traceDowncall(dat); + if (CallTraces.TRACE_DOWNCALLS) { + CallTraces.traceDowncall(dat); } HANDLE.invokeExact(dat); } catch (Throwable ex$) { @@ -146,8 +146,8 @@ final class DataImportTests { private static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC); public static void call(java.lang.foreign.MemorySegment _result) { try { - if (SwiftRuntime.TRACE_DOWNCALLS) { - SwiftRuntime.traceDowncall(_result); + if (CallTraces.TRACE_DOWNCALLS) { + CallTraces.traceDowncall(_result); } HANDLE.invokeExact(_result); } catch (Throwable ex$) { @@ -189,8 +189,8 @@ final class DataImportTests { private static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC); public static void call(java.lang.foreign.MemorySegment bytes, long count, java.lang.foreign.MemorySegment _result) { try { - if (SwiftRuntime.TRACE_DOWNCALLS) { - SwiftRuntime.traceDowncall(bytes, count, _result); + if (CallTraces.TRACE_DOWNCALLS) { + CallTraces.traceDowncall(bytes, count, _result); } HANDLE.invokeExact(bytes, count, _result); } catch (Throwable ex$) { @@ -230,8 +230,8 @@ final class DataImportTests { private static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC); public static long call(java.lang.foreign.MemorySegment self) { try { - if (SwiftRuntime.TRACE_DOWNCALLS) { - SwiftRuntime.traceDowncall(self); + if (CallTraces.TRACE_DOWNCALLS) { + CallTraces.traceDowncall(self); } return (long) HANDLE.invokeExact(self); } catch (Throwable ex$) { @@ -270,8 +270,8 @@ final class DataImportTests { private static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC); public static void call(java.lang.foreign.MemorySegment body, java.lang.foreign.MemorySegment self) { try { - if (SwiftRuntime.TRACE_DOWNCALLS) { - SwiftRuntime.traceDowncall(body, self); + if (CallTraces.TRACE_DOWNCALLS) { + CallTraces.traceDowncall(body, self); } HANDLE.invokeExact(body, self); } catch (Throwable ex$) { @@ -377,8 +377,8 @@ final class DataImportTests { private static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC); public static void call(java.lang.foreign.MemorySegment dat) { try { - if (SwiftRuntime.TRACE_DOWNCALLS) { - SwiftRuntime.traceDowncall(dat); + if (CallTraces.TRACE_DOWNCALLS) { + CallTraces.traceDowncall(dat); } HANDLE.invokeExact(dat); } catch (Throwable ex$) { diff --git a/Tests/JExtractSwiftTests/FuncCallbackImportTests.swift b/Tests/JExtractSwiftTests/FuncCallbackImportTests.swift index 5f80dd28..1678f91f 100644 --- a/Tests/JExtractSwiftTests/FuncCallbackImportTests.swift +++ b/Tests/JExtractSwiftTests/FuncCallbackImportTests.swift @@ -77,8 +77,8 @@ final class FuncCallbackImportTests { private static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC); public static void call(java.lang.foreign.MemorySegment callback) { try { - if (SwiftRuntime.TRACE_DOWNCALLS) { - SwiftRuntime.traceDowncall(callback); + if (CallTraces.TRACE_DOWNCALLS) { + CallTraces.traceDowncall(callback); } HANDLE.invokeExact(callback); } catch (Throwable ex$) { @@ -167,8 +167,8 @@ final class FuncCallbackImportTests { private static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC); public static void call(java.lang.foreign.MemorySegment callback, java.lang.foreign.MemorySegment fn) { try { - if (SwiftRuntime.TRACE_DOWNCALLS) { - SwiftRuntime.traceDowncall(callback, fn); + if (CallTraces.TRACE_DOWNCALLS) { + CallTraces.traceDowncall(callback, fn); } HANDLE.invokeExact(callback, fn); } catch (Throwable ex$) { @@ -281,8 +281,8 @@ final class FuncCallbackImportTests { private static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC); public static void call(java.lang.foreign.MemorySegment body) { try { - if (SwiftRuntime.TRACE_DOWNCALLS) { - SwiftRuntime.traceDowncall(body); + if (CallTraces.TRACE_DOWNCALLS) { + CallTraces.traceDowncall(body); } HANDLE.invokeExact(body); } catch (Throwable ex$) { diff --git a/Tests/JExtractSwiftTests/FunctionDescriptorImportTests.swift b/Tests/JExtractSwiftTests/FunctionDescriptorImportTests.swift index a714367e..6854b260 100644 --- a/Tests/JExtractSwiftTests/FunctionDescriptorImportTests.swift +++ b/Tests/JExtractSwiftTests/FunctionDescriptorImportTests.swift @@ -66,8 +66,8 @@ final class FunctionDescriptorTests { private static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC); public static void call(long i) { try { - if (SwiftRuntime.TRACE_DOWNCALLS) { - SwiftRuntime.traceDowncall(i); + if (CallTraces.TRACE_DOWNCALLS) { + CallTraces.traceDowncall(i); } HANDLE.invokeExact(i); } catch (Throwable ex$) { @@ -102,8 +102,8 @@ final class FunctionDescriptorTests { private static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC); public static void call(long l, int i32) { try { - if (SwiftRuntime.TRACE_DOWNCALLS) { - SwiftRuntime.traceDowncall(l, i32); + if (CallTraces.TRACE_DOWNCALLS) { + CallTraces.traceDowncall(l, i32); } HANDLE.invokeExact(l, i32); } catch (Throwable ex$) { @@ -138,8 +138,8 @@ final class FunctionDescriptorTests { private static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC); public static long call(long i) { try { - if (SwiftRuntime.TRACE_DOWNCALLS) { - SwiftRuntime.traceDowncall(i); + if (CallTraces.TRACE_DOWNCALLS) { + CallTraces.traceDowncall(i); } return (long) HANDLE.invokeExact(i); } catch (Throwable ex$) { @@ -174,8 +174,8 @@ final class FunctionDescriptorTests { private static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC); public static int call(java.lang.foreign.MemorySegment self) { try { - if (SwiftRuntime.TRACE_DOWNCALLS) { - SwiftRuntime.traceDowncall(self); + if (CallTraces.TRACE_DOWNCALLS) { + CallTraces.traceDowncall(self); } return (int) HANDLE.invokeExact(self); } catch (Throwable ex$) { @@ -209,8 +209,8 @@ final class FunctionDescriptorTests { private static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC); public static void call(int newValue, java.lang.foreign.MemorySegment self) { try { - if (SwiftRuntime.TRACE_DOWNCALLS) { - SwiftRuntime.traceDowncall(newValue, self); + if (CallTraces.TRACE_DOWNCALLS) { + CallTraces.traceDowncall(newValue, self); } HANDLE.invokeExact(newValue, self); } catch (Throwable ex$) { diff --git a/Tests/JExtractSwiftTests/StringPassingTests.swift b/Tests/JExtractSwiftTests/StringPassingTests.swift index 6a5c1c80..ea81ac84 100644 --- a/Tests/JExtractSwiftTests/StringPassingTests.swift +++ b/Tests/JExtractSwiftTests/StringPassingTests.swift @@ -45,8 +45,8 @@ final class StringPassingTests { private static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC); public static long call(java.lang.foreign.MemorySegment string) { try { - if (SwiftRuntime.TRACE_DOWNCALLS) { - SwiftRuntime.traceDowncall(string); + if (CallTraces.TRACE_DOWNCALLS) { + CallTraces.traceDowncall(string); } return (long) HANDLE.invokeExact(string); } catch (Throwable ex$) { diff --git a/Tests/JExtractSwiftTests/VariableImportTests.swift b/Tests/JExtractSwiftTests/VariableImportTests.swift index e0a6678c..da0c1afa 100644 --- a/Tests/JExtractSwiftTests/VariableImportTests.swift +++ b/Tests/JExtractSwiftTests/VariableImportTests.swift @@ -51,8 +51,8 @@ final class VariableImportTests { private static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC); public static long call(java.lang.foreign.MemorySegment self) { try { - if (SwiftRuntime.TRACE_DOWNCALLS) { - SwiftRuntime.traceDowncall(self); + if (CallTraces.TRACE_DOWNCALLS) { + CallTraces.traceDowncall(self); } return (long) HANDLE.invokeExact(self); } catch (Throwable ex$) { @@ -84,8 +84,8 @@ final class VariableImportTests { private static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC); public static void call(long newValue, java.lang.foreign.MemorySegment self) { try { - if (SwiftRuntime.TRACE_DOWNCALLS) { - SwiftRuntime.traceDowncall(newValue, self); + if (CallTraces.TRACE_DOWNCALLS) { + CallTraces.traceDowncall(newValue, self); } HANDLE.invokeExact(newValue, self); } catch (Throwable ex$) { From f20c1039543dc1bd1dd238fba204ecbd2c1c50b2 Mon Sep 17 00:00:00 2001 From: Konrad 'ktoso' Malawski Date: Wed, 16 Jul 2025 16:39:42 +0900 Subject: [PATCH 04/13] Change pointer() to $memoryAddress --- ...t2JavaGenerator+JavaBindingsPrinting.swift | 2 +- .../JNI/JNIClassTests.swift | 8 ++--- .../JNI/JNIVariablesTests.swift | 36 +++++++++---------- 3 files changed, 23 insertions(+), 23 deletions(-) diff --git a/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+JavaBindingsPrinting.swift b/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+JavaBindingsPrinting.swift index fa07aa84..ae0f5902 100644 --- a/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+JavaBindingsPrinting.swift +++ b/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+JavaBindingsPrinting.swift @@ -212,7 +212,7 @@ extension JNISwift2JavaGenerator { printer.print( """ - long selfPointer = this.pointer(); + long self$ = this.$memoryAddress(); \(returnKeyword)\(translatedDecl.parentName).$\(translatedDecl.name)(\(arguments.joined(separator: ", "))); """ ) diff --git a/Tests/JExtractSwiftTests/JNI/JNIClassTests.swift b/Tests/JExtractSwiftTests/JNI/JNIClassTests.swift index 41802e55..03bd8bb2 100644 --- a/Tests/JExtractSwiftTests/JNI/JNIClassTests.swift +++ b/Tests/JExtractSwiftTests/JNI/JNIClassTests.swift @@ -70,11 +70,11 @@ struct JNIClassTests { """ @Override protected Runnable $createDestroyFunction() { - long $selfPointer = this.pointer(); + long $self = this.$memoryAddress(); return new Runnable() { @Override public void run() { - MyClass.$destroy($selfPointer); + MyClass.$destroy($self); } }; } @@ -224,8 +224,8 @@ struct JNIClassTests { * } */ public void doSomething(long x) { - long selfPointer = this.pointer(); - MyClass.$doSomething(x, selfPointer); + long self$ = this.$memoryAddress(); + MyClass.$doSomething(x, self$); } """, """ diff --git a/Tests/JExtractSwiftTests/JNI/JNIVariablesTests.swift b/Tests/JExtractSwiftTests/JNI/JNIVariablesTests.swift index f09789d4..a1ba818b 100644 --- a/Tests/JExtractSwiftTests/JNI/JNIVariablesTests.swift +++ b/Tests/JExtractSwiftTests/JNI/JNIVariablesTests.swift @@ -48,8 +48,8 @@ struct JNIVariablesTests { * } */ public long getConstant() { - long selfPointer = this.pointer(); - return MyClass.$getConstant(selfPointer); + long self$ = this.$memoryAddress(); + return MyClass.$getConstant(self$); } """, """ @@ -94,8 +94,8 @@ struct JNIVariablesTests { * } */ public long getMutable() { - long selfPointer = this.pointer(); - return MyClass.$getMutable(selfPointer); + long self$ = this.$memoryAddress(); + return MyClass.$getMutable(self$); } """, """ @@ -106,8 +106,8 @@ struct JNIVariablesTests { * } */ public void setMutable(long newValue) { - long selfPointer = this.pointer(); - MyClass.$setMutable(newValue, selfPointer); + long self$ = this.$memoryAddress(); + MyClass.$setMutable(newValue, self$); } """, """ @@ -163,8 +163,8 @@ struct JNIVariablesTests { * } */ public long getComputed() { - long selfPointer = this.pointer(); - return MyClass.$getComputed(selfPointer); + long self$ = this.$memoryAddress(); + return MyClass.$getComputed(self$); } """, """ @@ -210,8 +210,8 @@ struct JNIVariablesTests { * } */ public long getComputedThrowing() throws Exception { - long selfPointer = this.pointer(); - return MyClass.$getComputedThrowing(selfPointer); + long self$ = this.$memoryAddress(); + return MyClass.$getComputedThrowing(self$); } """, """ @@ -262,8 +262,8 @@ struct JNIVariablesTests { * } */ public long getGetterAndSetter() { - long selfPointer = this.pointer(); - return MyClass.$getGetterAndSetter(selfPointer); + long self$ = this.$memoryAddress(); + return MyClass.$getGetterAndSetter(self$); } """, """ @@ -274,8 +274,8 @@ struct JNIVariablesTests { * } */ public void setGetterAndSetter(long newValue) { - long selfPointer = this.pointer(); - MyClass.$setGetterAndSetter(newValue, selfPointer); + long self$ = this.$memoryAddress(); + MyClass.$setGetterAndSetter(newValue, self$); } """, """ @@ -331,8 +331,8 @@ struct JNIVariablesTests { * } */ public boolean isSomeBoolean() { - long selfPointer = this.pointer(); - return MyClass.$isSomeBoolean(selfPointer); + long self$ = this.$memoryAddress(); + return MyClass.$isSomeBoolean(self$); } """, """ @@ -343,8 +343,8 @@ struct JNIVariablesTests { * } */ public void setSomeBoolean(boolean newValue) { - long selfPointer = this.pointer(); - MyClass.$setSomeBoolean(newValue, selfPointer); + long self$ = this.$memoryAddress(); + MyClass.$setSomeBoolean(newValue, self$); } """, """ From 7ca6bc9790260368fb88fb128890108adbe34c40 Mon Sep 17 00:00:00 2001 From: Konrad 'ktoso' Malawski Date: Wed, 16 Jul 2025 16:41:27 +0900 Subject: [PATCH 05/13] Centralize the printing of long -> "self$" unsafe pointer in JNI printing --- ...t2JavaGenerator+JavaBindingsPrinting.swift | 4 +- ...ift2JavaGenerator+SwiftThunkPrinting.swift | 52 ++++++++++++++----- .../swift/swiftkit/core/JNISwiftInstance.java | 27 +++++----- .../swiftkit/ffm/FFMSwiftInstanceCleanup.java | 2 +- .../JNI/JNIClassTests.swift | 26 +++++----- 5 files changed, 66 insertions(+), 45 deletions(-) diff --git a/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+JavaBindingsPrinting.swift b/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+JavaBindingsPrinting.swift index ae0f5902..2e92dc99 100644 --- a/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+JavaBindingsPrinting.swift +++ b/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+JavaBindingsPrinting.swift @@ -235,8 +235,8 @@ extension JNISwift2JavaGenerator { let initArguments = translatedDecl.translatedFunctionSignature.parameters.map(\.name) printer.print( """ - long selfPointer = \(type.qualifiedName).allocatingInit(\(initArguments.joined(separator: ", "))); - return new \(type.qualifiedName)(selfPointer, swiftArena$); + long self$ = \(type.qualifiedName).allocatingInit(\(initArguments.joined(separator: ", "))); + return new \(type.qualifiedName)(self$, swiftArena$); """ ) } diff --git a/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+SwiftThunkPrinting.swift b/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+SwiftThunkPrinting.swift index 30db69d1..9e1b239c 100644 --- a/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+SwiftThunkPrinting.swift +++ b/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+SwiftThunkPrinting.swift @@ -138,9 +138,9 @@ extension JNISwift2JavaGenerator { // TODO: Throwing initializers printer.print( """ - let selfPointer = UnsafeMutablePointer<\(typeName)>.allocate(capacity: 1) - selfPointer.initialize(to: \(typeName)(\(downcallArguments))) - return Int64(Int(bitPattern: selfPointer)).getJNIValue(in: environment) + let self$ = UnsafeMutablePointer<\(typeName)>.allocate(capacity: 1) + self$.initialize(to: \(typeName)(\(downcallArguments))) + return Int64(Int(bitPattern: self$)).getJNIValue(in: environment) """ ) } @@ -184,22 +184,20 @@ extension JNISwift2JavaGenerator { let translatedDecl = self.translatedDecl(for: decl)! // We will only call this method if can translate the decl. let swiftParentName = decl.parentType!.asNominalTypeDeclaration!.qualifiedName + let selfPointerParam = JavaParameter(name: "selfPointer", type: .long) printCDecl( &printer, javaMethodName: "$\(translatedDecl.name)", parentName: translatedDecl.parentName, parameters: translatedDecl.translatedFunctionSignature.parameters + [ - JavaParameter(name: "selfPointer", type: .long) + selfPointerParam ], isStatic: true, resultType: translatedDecl.translatedFunctionSignature.resultType ) { printer in - printer.print( - """ - let self$ = UnsafeMutablePointer<\(swiftParentName)>(bitPattern: Int(Int64(fromJNI: selfPointer, in: environment!)))! - """ - ) - self.printFunctionDowncall(&printer, decl, calleeName: "self$.pointee") + let selfVar = self.printSelfJLongToUnsafeMutablePointer(&printer, + swiftParentName: swiftParentName, selfPointerParam) + self.printFunctionDowncall(&printer, decl, calleeName: "\(selfVar).pointee") } } @@ -320,28 +318,54 @@ extension JNISwift2JavaGenerator { /// Prints the implementation of the destroy function. private func printDestroyFunctionThunk(_ printer: inout CodePrinter, _ type: ImportedNominalType) { + let selfPointerParam = JavaParameter(name: "selfPointer", type: .long) printCDecl( &printer, javaMethodName: "$destroy", parentName: type.swiftNominal.name, parameters: [ - JavaParameter(name: "selfPointer", type: .long) + selfPointerParam ], isStatic: true, resultType: .void ) { printer in + let parentName = type.qualifiedName + let selfVar = self.printSelfJLongToUnsafeMutablePointer(&printer, swiftParentName: parentName, selfPointerParam) // Deinitialize the pointer allocated (which will call the VWT destroy method) // then deallocate the memory. printer.print( """ - let pointer = UnsafeMutablePointer<\(type.qualifiedName)>(bitPattern: Int(Int64(fromJNI: selfPointer, in: environment!)))! - pointer.deinitialize(count: 1) - pointer.deallocate() + \(selfVar).deinitialize(count: 1) + \(selfVar).deallocate() """ ) } } + /// Print the necessary conversion logic to go from a `jlong` to a `UnsafeMutablePointer` + /// + /// - Returns: name of the created "self" variable + private func printSelfJLongToUnsafeMutablePointer( + _ printer: inout CodePrinter, + swiftParentName: String, _ selfPointerParam: JavaParameter) -> String { + let newSelfParamName = "self$" + printer.print( + """ + guard let env$ = environment else { + fatalError("Missing JNIEnv in downcall to \\(#function)") + } + assert(\(selfPointerParam.name) != 0, "\(selfPointerParam.name) memory address was null") + let selfBits$ = Int(Int64(fromJNI: \(selfPointerParam.name), in: env$)) + assert(selfBits$ != 0, "$self memory address was null: \(selfPointerParam.name) = \\(\(selfPointerParam.name))" ) + guard let \(newSelfParamName) = UnsafeMutablePointer<\(swiftParentName)>(bitPattern: selfBits$) else { + fatalError("Missing self pointer in call to \\(#function)!") + } + """ + ) + return newSelfParamName + } + + /// Renders the arguments for making a downcall private func renderDowncallArguments( swiftFunctionSignature: SwiftFunctionSignature, diff --git a/SwiftKitCore/src/main/java/org/swift/swiftkit/core/JNISwiftInstance.java b/SwiftKitCore/src/main/java/org/swift/swiftkit/core/JNISwiftInstance.java index 4b19f6fd..6b30ed2f 100644 --- a/SwiftKitCore/src/main/java/org/swift/swiftkit/core/JNISwiftInstance.java +++ b/SwiftKitCore/src/main/java/org/swift/swiftkit/core/JNISwiftInstance.java @@ -14,33 +14,30 @@ package org.swift.swiftkit.core; +import java.util.Objects; import java.util.concurrent.atomic.AtomicBoolean; public abstract class JNISwiftInstance extends SwiftInstance { - /// Pointer to the "self". - private final long selfPointer; - - /** - * The pointer to the instance in memory. I.e. the {@code self} of the Swift object or value. - */ - public final long pointer() { - return this.selfPointer; - } + // Pointer to the "self". + protected final long selfPointer; /** * The designated constructor of any imported Swift types. * - * @param pointer a pointer to the memory containing the value + * @param selfPointer a pointer to the memory containing the value * @param arena the arena this object belongs to. When the arena goes out of scope, this value is destroyed. */ - protected JNISwiftInstance(long pointer, SwiftArena arena) { - super(arena); - this.selfPointer = pointer; + protected JNISwiftInstance(long selfPointer, SwiftArena arena) { + SwiftObjects.requireNonZero(selfPointer, "selfPointer"); + this.selfPointer = selfPointer; + + // Only register once we have fully initialized the object since this will need the object pointer. + arena.register(this); } @Override public long $memoryAddress() { - return selfPointer; + return this.selfPointer; } /** @@ -58,7 +55,7 @@ protected JNISwiftInstance(long pointer, SwiftArena arena) { protected abstract Runnable $createDestroyFunction(); @Override - public SwiftInstanceCleanup createCleanupAction() { + public SwiftInstanceCleanup $createCleanup() { final AtomicBoolean statusDestroyedFlag = $statusDestroyedFlag(); Runnable markAsDestroyed = new Runnable() { @Override diff --git a/SwiftKitFFM/src/main/java/org/swift/swiftkit/ffm/FFMSwiftInstanceCleanup.java b/SwiftKitFFM/src/main/java/org/swift/swiftkit/ffm/FFMSwiftInstanceCleanup.java index a5d0829a..2fd3037e 100644 --- a/SwiftKitFFM/src/main/java/org/swift/swiftkit/ffm/FFMSwiftInstanceCleanup.java +++ b/SwiftKitFFM/src/main/java/org/swift/swiftkit/ffm/FFMSwiftInstanceCleanup.java @@ -36,7 +36,7 @@ public void run() { // Allow null pointers just for AutoArena tests. if (selfType != null && selfPointer != null) { System.out.println("[debug] Destroy swift value [" + selfType.getSwiftName() + "]: " + selfPointer); - SwiftValueWitnessTable.destroy(selfType, selfPointer); + SwiftValueWitnessTable.destroy(selfType, self$); } } } diff --git a/Tests/JExtractSwiftTests/JNI/JNIClassTests.swift b/Tests/JExtractSwiftTests/JNI/JNIClassTests.swift index 03bd8bb2..9aa85f45 100644 --- a/Tests/JExtractSwiftTests/JNI/JNIClassTests.swift +++ b/Tests/JExtractSwiftTests/JNI/JNIClassTests.swift @@ -135,8 +135,8 @@ struct JNIClassTests { * } */ public static MyClass init(long x, long y, SwiftArena swiftArena$) { - long selfPointer = MyClass.allocatingInit(x, y); - return new MyClass(selfPointer, swiftArena$); + long self$ = MyClass.allocatingInit(x, y); + return new MyClass(self$, swiftArena$); } """, """ @@ -147,8 +147,8 @@ struct JNIClassTests { * } */ public static MyClass init(SwiftArena swiftArena$) { - long selfPointer = MyClass.allocatingInit(); - return new MyClass(selfPointer, swiftArena$); + long self$ = MyClass.allocatingInit(); + return new MyClass(self$, swiftArena$); } """, """ @@ -172,17 +172,17 @@ struct JNIClassTests { """ @_cdecl("Java_com_example_swift_MyClass_allocatingInit__") func Java_com_example_swift_MyClass_allocatingInit__(environment: UnsafeMutablePointer!, thisClass: jclass) -> jlong { - let selfPointer = UnsafeMutablePointer.allocate(capacity: 1) - selfPointer.initialize(to: MyClass()) - return Int64(Int(bitPattern: selfPointer)).getJNIValue(in: environment) + let self$ = UnsafeMutablePointer.allocate(capacity: 1) + self$.initialize(to: MyClass()) + return Int64(Int(bitPattern: self$)).getJNIValue(in: environment) } """, """ @_cdecl("Java_com_example_swift_MyClass_allocatingInit__JJ") func Java_com_example_swift_MyClass_allocatingInit__JJ(environment: UnsafeMutablePointer!, thisClass: jclass, x: jlong, y: jlong) -> jlong { - let selfPointer = UnsafeMutablePointer.allocate(capacity: 1) - selfPointer.initialize(to: MyClass(x: Int64(fromJNI: x, in: environment!), y: Int64(fromJNI: y, in: environment!))) - return Int64(Int(bitPattern: selfPointer)).getJNIValue(in: environment) + let self$ = UnsafeMutablePointer.allocate(capacity: 1) + self$.initialize(to: MyClass(x: Int64(fromJNI: x, in: environment!), y: Int64(fromJNI: y, in: environment!))) + return Int64(Int(bitPattern: self$)).getJNIValue(in: environment) } """ ] @@ -200,9 +200,9 @@ struct JNIClassTests { """ @_cdecl("Java_com_example_swift_MyClass__00024destroy__J") func Java_com_example_swift_MyClass__00024destroy__J(environment: UnsafeMutablePointer!, thisClass: jclass, selfPointer: jlong) { - let pointer = UnsafeMutablePointer(bitPattern: Int(Int64(fromJNI: selfPointer, in: environment!)))! - pointer.deinitialize(count: 1) - pointer.deallocate() + let self$ = UnsafeMutablePointer(bitPattern: Int(Int64(fromJNI: selfPointer, in: environment!)))! + self$.deinitialize(count: 1) + self$.deallocate() } """ ] From 17197e2276a9b883b74b868692cd5d4330c017c1 Mon Sep 17 00:00:00 2001 From: Konrad 'ktoso' Malawski Date: Wed, 16 Jul 2025 16:43:33 +0900 Subject: [PATCH 06/13] rename cleanup create function to $ func as well --- .../org/swift/swiftkit/core/ConfinedSwiftMemorySession.java | 2 +- .../main/java/org/swift/swiftkit/core/SwiftInstance.java | 6 +----- .../swiftkit/ffm/AllocatingAutoSwiftMemorySession.java | 2 +- .../main/java/org/swift/swiftkit/ffm/FFMSwiftInstance.java | 2 +- 4 files changed, 4 insertions(+), 8 deletions(-) diff --git a/SwiftKitCore/src/main/java/org/swift/swiftkit/core/ConfinedSwiftMemorySession.java b/SwiftKitCore/src/main/java/org/swift/swiftkit/core/ConfinedSwiftMemorySession.java index 1b6821ca..7c6e80fb 100644 --- a/SwiftKitCore/src/main/java/org/swift/swiftkit/core/ConfinedSwiftMemorySession.java +++ b/SwiftKitCore/src/main/java/org/swift/swiftkit/core/ConfinedSwiftMemorySession.java @@ -60,7 +60,7 @@ public void close() { public void register(SwiftInstance instance) { checkValid(); - SwiftInstanceCleanup cleanup = instance.createCleanupAction(); + SwiftInstanceCleanup cleanup = instance.$createCleanup(); this.resources.add(cleanup); } diff --git a/SwiftKitCore/src/main/java/org/swift/swiftkit/core/SwiftInstance.java b/SwiftKitCore/src/main/java/org/swift/swiftkit/core/SwiftInstance.java index 1f0a9a33..59240f95 100644 --- a/SwiftKitCore/src/main/java/org/swift/swiftkit/core/SwiftInstance.java +++ b/SwiftKitCore/src/main/java/org/swift/swiftkit/core/SwiftInstance.java @@ -41,11 +41,7 @@ protected SwiftInstance(SwiftArena arena) { *

* Warning: The cleanup action must not capture {@code this}. */ - public abstract SwiftInstanceCleanup createCleanupAction(); - - // TODO: make this a flagset integer and/or use a field updater - /** Used to track additional state of the underlying object, e.g. if it was explicitly destroyed. */ - private final AtomicBoolean $state$destroyed = new AtomicBoolean(false); + public abstract SwiftInstanceCleanup $createCleanup(); /** * Exposes a boolean value which can be used to indicate if the object was destroyed. diff --git a/SwiftKitFFM/src/main/java/org/swift/swiftkit/ffm/AllocatingAutoSwiftMemorySession.java b/SwiftKitFFM/src/main/java/org/swift/swiftkit/ffm/AllocatingAutoSwiftMemorySession.java index fecd5202..7063fefb 100644 --- a/SwiftKitFFM/src/main/java/org/swift/swiftkit/ffm/AllocatingAutoSwiftMemorySession.java +++ b/SwiftKitFFM/src/main/java/org/swift/swiftkit/ffm/AllocatingAutoSwiftMemorySession.java @@ -56,7 +56,7 @@ public void register(SwiftInstance instance) { // We make sure we don't capture `instance` in the // cleanup action, so we can ignore the warning below. - var cleanupAction = instance.createCleanupAction(); + var cleanupAction = instance.$createCleanup(); cleaner.register(instance, cleanupAction); } diff --git a/SwiftKitFFM/src/main/java/org/swift/swiftkit/ffm/FFMSwiftInstance.java b/SwiftKitFFM/src/main/java/org/swift/swiftkit/ffm/FFMSwiftInstance.java index 5e157f0e..7b7b7982 100644 --- a/SwiftKitFFM/src/main/java/org/swift/swiftkit/ffm/FFMSwiftInstance.java +++ b/SwiftKitFFM/src/main/java/org/swift/swiftkit/ffm/FFMSwiftInstance.java @@ -52,7 +52,7 @@ protected FFMSwiftInstance(MemorySegment segment, AllocatingSwiftArena arena) { @Override - public SwiftInstanceCleanup createCleanupAction() { + public SwiftInstanceCleanup $createCleanup() { var statusDestroyedFlag = $statusDestroyedFlag(); Runnable markAsDestroyed = () -> statusDestroyedFlag.set(true); From 4092f367516dbd366c0affc95b354b7009c14573 Mon Sep 17 00:00:00 2001 From: Konrad 'ktoso' Malawski Date: Wed, 16 Jul 2025 16:44:04 +0900 Subject: [PATCH 07/13] reorder fields in SwiftInstance, fields before methods --- .../java/org/swift/swiftkit/core/SwiftInstance.java | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/SwiftKitCore/src/main/java/org/swift/swiftkit/core/SwiftInstance.java b/SwiftKitCore/src/main/java/org/swift/swiftkit/core/SwiftInstance.java index 59240f95..44955cc6 100644 --- a/SwiftKitCore/src/main/java/org/swift/swiftkit/core/SwiftInstance.java +++ b/SwiftKitCore/src/main/java/org/swift/swiftkit/core/SwiftInstance.java @@ -18,14 +18,9 @@ public abstract class SwiftInstance { - /** - * The designated constructor of any imported Swift types. - * - * @param arena the arena this object belongs to. When the arena goes out of scope, this value is destroyed. - */ - protected SwiftInstance(SwiftArena arena) { - arena.register(this); - } + // TODO: make this a flagset integer and/or use a field updater + /** Used to track additional state of the underlying object, e.g. if it was explicitly destroyed. */ + private final AtomicBoolean $state$destroyed = new AtomicBoolean(false); /** * Pointer to the {@code self} of the underlying Swift object or value. From 4dffc5f1e320cdf827d62386c7493bb5b54b5a9e Mon Sep 17 00:00:00 2001 From: Konrad 'ktoso' Malawski Date: Wed, 16 Jul 2025 16:44:25 +0900 Subject: [PATCH 08/13] fix bug in that we must initialize pointer before registering cleanup --- .../main/java/org/swift/swiftkit/ffm/FFMSwiftInstance.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/SwiftKitFFM/src/main/java/org/swift/swiftkit/ffm/FFMSwiftInstance.java b/SwiftKitFFM/src/main/java/org/swift/swiftkit/ffm/FFMSwiftInstance.java index 7b7b7982..1236bad2 100644 --- a/SwiftKitFFM/src/main/java/org/swift/swiftkit/ffm/FFMSwiftInstance.java +++ b/SwiftKitFFM/src/main/java/org/swift/swiftkit/ffm/FFMSwiftInstance.java @@ -29,8 +29,10 @@ public abstract class FFMSwiftInstance extends SwiftInstance { * @param arena the arena this object belongs to. When the arena goes out of scope, this value is destroyed. */ protected FFMSwiftInstance(MemorySegment segment, AllocatingSwiftArena arena) { - super(arena); this.memorySegment = segment; + + // Only register once we have fully initialized the object since this will need the object pointer. + arena.register(this); } /** From 602a6acef5b23444d23f3173d8cdc83802aaf9d4 Mon Sep 17 00:00:00 2001 From: Konrad 'ktoso' Malawski Date: Wed, 16 Jul 2025 18:56:15 +0900 Subject: [PATCH 09/13] fix tests after thunk body refactors --- ...t2JavaGenerator+JavaBindingsPrinting.swift | 13 ++++---- .../JNI/JNIClassTests.swift | 33 ++++++++++++++++--- 2 files changed, 35 insertions(+), 11 deletions(-) diff --git a/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+JavaBindingsPrinting.swift b/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+JavaBindingsPrinting.swift index 2e92dc99..4f4ad4d8 100644 --- a/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+JavaBindingsPrinting.swift +++ b/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+JavaBindingsPrinting.swift @@ -206,13 +206,15 @@ extension JNISwift2JavaGenerator { printDeclDocumentation(&printer, decl) printer.printBraceBlock("public \(renderFunctionSignature(decl))") { printer in var arguments = translatedDecl.translatedFunctionSignature.parameters.map(\.name) - arguments.append("selfPointer") + + let selfVarName = "self$" + arguments.append(selfVarName) let returnKeyword = translatedDecl.translatedFunctionSignature.resultType.isVoid ? "" : "return " printer.print( """ - long self$ = this.$memoryAddress(); + long \(selfVarName) = this.$memoryAddress(); \(returnKeyword)\(translatedDecl.parentName).$\(translatedDecl.name)(\(arguments.joined(separator: ", "))); """ ) @@ -267,18 +269,17 @@ extension JNISwift2JavaGenerator { printer.printBraceBlock("protected Runnable \(funcName)()") { printer in printer.print( """ + long self$ = this.$memoryAddress(); if (CallTraces.TRACE_DOWNCALLS) { CallTraces.traceDowncall("\(type.swiftNominal.name).\(funcName)", "this", this, - "this.$memoryAddress()", this.$memoryAddress()); + "self", self$); } - long self$ = this.$memoryAddress(); - assert(self$ > 0); return new Runnable() { @Override public void run() { if (CallTraces.TRACE_DOWNCALLS) { - CallTraces.traceDowncall("\(type.swiftNominal.name).$destroy(" + self$ + ")"); + CallTraces.traceDowncall("\(type.swiftNominal.name).$destroy", "self", self$); } \(type.swiftNominal.name).$destroy(self$); } diff --git a/Tests/JExtractSwiftTests/JNI/JNIClassTests.swift b/Tests/JExtractSwiftTests/JNI/JNIClassTests.swift index 9aa85f45..235f1003 100644 --- a/Tests/JExtractSwiftTests/JNI/JNIClassTests.swift +++ b/Tests/JExtractSwiftTests/JNI/JNIClassTests.swift @@ -70,14 +70,21 @@ struct JNIClassTests { """ @Override protected Runnable $createDestroyFunction() { - long $self = this.$memoryAddress(); + long self$ = this.$memoryAddress(); + if (CallTraces.TRACE_DOWNCALLS) { + CallTraces.traceDowncall("MyClass.$createDestroyFunction", + "this", this, + "self", self$); + } return new Runnable() { @Override public void run() { - MyClass.$destroy($self); + if (CallTraces.TRACE_DOWNCALLS) { + CallTraces.traceDowncall("MyClass.$destroy", "self", self$); + } + MyClass.$destroy(self$); } }; - } """ ]) } @@ -200,7 +207,15 @@ struct JNIClassTests { """ @_cdecl("Java_com_example_swift_MyClass__00024destroy__J") func Java_com_example_swift_MyClass__00024destroy__J(environment: UnsafeMutablePointer!, thisClass: jclass, selfPointer: jlong) { - let self$ = UnsafeMutablePointer(bitPattern: Int(Int64(fromJNI: selfPointer, in: environment!)))! + guard let env$ = environment else { + fatalError("Missing JNIEnv in downcall to \\(#function)") + } + assert(selfPointer != 0, "selfPointer memory address was null") + let selfBits$ = Int(Int64(fromJNI: selfPointer, in: env$)) + assert(selfBits$ != 0, "$self memory address was null: selfPointer = \\(selfPointer)" ) + guard let self$ = UnsafeMutablePointer(bitPattern: selfBits$) else { + fatalError("Missing self pointer in call to \\(#function)!") + } self$.deinitialize(count: 1) self$.deallocate() } @@ -246,7 +261,15 @@ struct JNIClassTests { """ @_cdecl("Java_com_example_swift_MyClass__00024doSomething__JJ") func Java_com_example_swift_MyClass__00024doSomething__JJ(environment: UnsafeMutablePointer!, thisClass: jclass, x: jlong, selfPointer: jlong) { - let self$ = UnsafeMutablePointer(bitPattern: Int(Int64(fromJNI: selfPointer, in: environment!)))! + guard let env$ = environment else { + fatalError("Missing JNIEnv in downcall to \\(#function)") + } + assert(selfPointer != 0, "selfPointer memory address was null") + let selfBits$ = Int(Int64(fromJNI: selfPointer, in: env$)) + assert(selfBits$ != 0, "$self memory address was null: selfPointer = \\(selfPointer)" ) + guard let self$ = UnsafeMutablePointer(bitPattern: selfBits$) else { + fatalError("Missing self pointer in call to \\(#function)!") + } self$.pointee.doSomething(x: Int64(fromJNI: x, in: environment!)) } """, From 49e95c68adf25883b08a67eea3755d3d526964c7 Mon Sep 17 00:00:00 2001 From: Konrad 'ktoso' Malawski Date: Wed, 16 Jul 2025 20:02:38 +0900 Subject: [PATCH 10/13] update tests --- .../swiftkit/ffm/FFMSwiftInstanceCleanup.java | 16 ++-- .../Asserts/TextAssertions.swift | 1 + .../JNI/JNIClassTests.swift | 12 +-- .../JNI/JNIVariablesTests.swift | 94 +++++++++++++++++-- 4 files changed, 100 insertions(+), 23 deletions(-) diff --git a/SwiftKitFFM/src/main/java/org/swift/swiftkit/ffm/FFMSwiftInstanceCleanup.java b/SwiftKitFFM/src/main/java/org/swift/swiftkit/ffm/FFMSwiftInstanceCleanup.java index 2fd3037e..c3a9beb6 100644 --- a/SwiftKitFFM/src/main/java/org/swift/swiftkit/ffm/FFMSwiftInstanceCleanup.java +++ b/SwiftKitFFM/src/main/java/org/swift/swiftkit/ffm/FFMSwiftInstanceCleanup.java @@ -19,13 +19,13 @@ import java.lang.foreign.MemorySegment; public class FFMSwiftInstanceCleanup implements SwiftInstanceCleanup { - private final MemorySegment selfPointer; - private final SwiftAnyType selfType; + private final MemorySegment memoryAddress; + private final SwiftAnyType type; private final Runnable markAsDestroyed; - public FFMSwiftInstanceCleanup(MemorySegment selfPointer, SwiftAnyType selfType, Runnable markAsDestroyed) { - this.selfPointer = selfPointer; - this.selfType = selfType; + public FFMSwiftInstanceCleanup(MemorySegment memoryAddress, SwiftAnyType type, Runnable markAsDestroyed) { + this.memoryAddress = memoryAddress; + this.type = type; this.markAsDestroyed = markAsDestroyed; } @@ -34,9 +34,9 @@ public void run() { markAsDestroyed.run(); // Allow null pointers just for AutoArena tests. - if (selfType != null && selfPointer != null) { - System.out.println("[debug] Destroy swift value [" + selfType.getSwiftName() + "]: " + selfPointer); - SwiftValueWitnessTable.destroy(selfType, self$); + if (type != null && memoryAddress != null) { + System.out.println("[debug] Destroy swift value [" + type.getSwiftName() + "]: " + memoryAddress); + SwiftValueWitnessTable.destroy(type, memoryAddress); } } } diff --git a/Tests/JExtractSwiftTests/Asserts/TextAssertions.swift b/Tests/JExtractSwiftTests/Asserts/TextAssertions.swift index 3c4ad56a..1d6e19af 100644 --- a/Tests/JExtractSwiftTests/Asserts/TextAssertions.swift +++ b/Tests/JExtractSwiftTests/Asserts/TextAssertions.swift @@ -112,6 +112,7 @@ func assertOutput( print("==== ---------------------------------------------------------------") #expect(output.contains(expected), sourceLocation: sourceLocation) + fatalError("Failed: \(filePath):\(line)") continue } diff --git a/Tests/JExtractSwiftTests/JNI/JNIClassTests.swift b/Tests/JExtractSwiftTests/JNI/JNIClassTests.swift index 235f1003..2100233a 100644 --- a/Tests/JExtractSwiftTests/JNI/JNIClassTests.swift +++ b/Tests/JExtractSwiftTests/JNI/JNIClassTests.swift @@ -213,7 +213,7 @@ struct JNIClassTests { assert(selfPointer != 0, "selfPointer memory address was null") let selfBits$ = Int(Int64(fromJNI: selfPointer, in: env$)) assert(selfBits$ != 0, "$self memory address was null: selfPointer = \\(selfPointer)" ) - guard let self$ = UnsafeMutablePointer(bitPattern: selfBits$) else { + guard let self$ = UnsafeMutablePointer(bitPattern: selfBits$) else { fatalError("Missing self pointer in call to \\(#function)!") } self$.deinitialize(count: 1) @@ -233,11 +233,11 @@ struct JNIClassTests { expectedChunks: [ """ /** - * Downcall to Swift: - * {@snippet lang=swift : - * public func doSomething(x: Int64) - * } - */ + * Downcall to Swift: + * {@snippet lang=swift : + * public func doSomething(x: Int64) + * } + */ public void doSomething(long x) { long self$ = this.$memoryAddress(); MyClass.$doSomething(x, self$); diff --git a/Tests/JExtractSwiftTests/JNI/JNIVariablesTests.swift b/Tests/JExtractSwiftTests/JNI/JNIVariablesTests.swift index a1ba818b..663ae48f 100644 --- a/Tests/JExtractSwiftTests/JNI/JNIVariablesTests.swift +++ b/Tests/JExtractSwiftTests/JNI/JNIVariablesTests.swift @@ -69,7 +69,15 @@ struct JNIVariablesTests { """ @_cdecl("Java_com_example_swift_MyClass__00024getConstant__J") func Java_com_example_swift_MyClass__00024getConstant__J(environment: UnsafeMutablePointer!, thisClass: jclass, selfPointer: jlong) -> jlong { - let self$ = UnsafeMutablePointer(bitPattern: Int(Int64(fromJNI: selfPointer, in: environment!)))! + guard let env$ = environment else { + fatalError("Missing JNIEnv in downcall to \\(#function)") + } + assert(selfPointer != 0, "selfPointer memory address was null") + let selfBits$ = Int(Int64(fromJNI: selfPointer, in: env$)) + assert(selfBits$ != 0, "$self memory address was null: selfPointer = \\(selfPointer)" ) + guard let self$ = UnsafeMutablePointer(bitPattern: selfBits$) else { + fatalError("Missing self pointer in call to \\(#function)!") + } let result = self$.pointee.constant return result.getJNIValue(in: environment) } @@ -131,7 +139,15 @@ struct JNIVariablesTests { """ @_cdecl("Java_com_example_swift_MyClass__00024getMutable__J") func Java_com_example_swift_MyClass__00024getMutable__J(environment: UnsafeMutablePointer!, thisClass: jclass, selfPointer: jlong) -> jlong { - let self$ = UnsafeMutablePointer(bitPattern: Int(Int64(fromJNI: selfPointer, in: environment!)))! + guard let env$ = environment else { + fatalError("Missing JNIEnv in downcall to \\(#function)") + } + assert(selfPointer != 0, "selfPointer memory address was null") + let selfBits$ = Int(Int64(fromJNI: selfPointer, in: env$)) + assert(selfBits$ != 0, "$self memory address was null: selfPointer = \\(selfPointer)" ) + guard let self$ = UnsafeMutablePointer(bitPattern: selfBits$) else { + fatalError("Missing self pointer in call to \\(#function)!") + } let result = self$.pointee.mutable return result.getJNIValue(in: environment) } @@ -139,7 +155,15 @@ struct JNIVariablesTests { """ @_cdecl("Java_com_example_swift_MyClass__00024setMutable__JJ") func Java_com_example_swift_MyClass__00024setMutable__JJ(environment: UnsafeMutablePointer!, thisClass: jclass, newValue: jlong, selfPointer: jlong) { - let self$ = UnsafeMutablePointer(bitPattern: Int(Int64(fromJNI: selfPointer, in: environment!)))! + guard let env$ = environment else { + fatalError("Missing JNIEnv in downcall to \\(#function)") + } + assert(selfPointer != 0, "selfPointer memory address was null") + let selfBits$ = Int(Int64(fromJNI: selfPointer, in: env$)) + assert(selfBits$ != 0, "$self memory address was null: selfPointer = \\(selfPointer)" ) + guard let self$ = UnsafeMutablePointer(bitPattern: selfBits$) else { + fatalError("Missing self pointer in call to \\(#function)!") + } self$.pointee.mutable = Int64(fromJNI: newValue, in: environment!) } """ @@ -185,7 +209,16 @@ struct JNIVariablesTests { """ @_cdecl("Java_com_example_swift_MyClass__00024getComputed__J") func Java_com_example_swift_MyClass__00024getComputed__J(environment: UnsafeMutablePointer!, thisClass: jclass, selfPointer: jlong) -> jlong { - let self$ = UnsafeMutablePointer(bitPattern: Int(Int64(fromJNI: selfPointer, in: environment!)))! + guard let env$ = environment else { + fatalError("Missing JNIEnv in downcall to \\(#function)") + } + assert(selfPointer != 0, "selfPointer memory address was null") + let selfBits$ = Int(Int64(fromJNI: selfPointer, in: env$)) + assert(selfBits$ != 0, "$self memory address was null: selfPointer = \\(selfPointer)" ) + guard let self$ = UnsafeMutablePointer(bitPattern: selfBits$) else { + fatalError("Missing self pointer in call to \\(#function)!") + } + let result = self$.pointee.computed return result.getJNIValue(in: environment) } @@ -232,7 +265,16 @@ struct JNIVariablesTests { """ @_cdecl("Java_com_example_swift_MyClass__00024getComputedThrowing__J") func Java_com_example_swift_MyClass__00024getComputedThrowing__J(environment: UnsafeMutablePointer!, thisClass: jclass, selfPointer: jlong) -> jlong { - let self$ = UnsafeMutablePointer(bitPattern: Int(Int64(fromJNI: selfPointer, in: environment!)))! + guard let env$ = environment else { + fatalError("Missing JNIEnv in downcall to \\(#function)") + } + assert(selfPointer != 0, "selfPointer memory address was null") + let selfBits$ = Int(Int64(fromJNI: selfPointer, in: env$)) + assert(selfBits$ != 0, "$self memory address was null: selfPointer = \\(selfPointer)" ) + guard let self$ = UnsafeMutablePointer(bitPattern: selfBits$) else { + fatalError("Missing self pointer in call to \\(#function)!") + } + do { let result = try self$.pointee.computedThrowing return result.getJNIValue(in: environment) @@ -299,7 +341,16 @@ struct JNIVariablesTests { """ @_cdecl("Java_com_example_swift_MyClass__00024getGetterAndSetter__J") func Java_com_example_swift_MyClass__00024getGetterAndSetter__J(environment: UnsafeMutablePointer!, thisClass: jclass, selfPointer: jlong) -> jlong { - let self$ = UnsafeMutablePointer(bitPattern: Int(Int64(fromJNI: selfPointer, in: environment!)))! + guard let env$ = environment else { + fatalError("Missing JNIEnv in downcall to \\(#function)") + } + assert(selfPointer != 0, "selfPointer memory address was null") + let selfBits$ = Int(Int64(fromJNI: selfPointer, in: env$)) + assert(selfBits$ != 0, "$self memory address was null: selfPointer = \\(selfPointer)" ) + guard let self$ = UnsafeMutablePointer(bitPattern: selfBits$) else { + fatalError("Missing self pointer in call to \\(#function)!") + } + let result = self$.pointee.getterAndSetter return result.getJNIValue(in: environment) } @@ -307,7 +358,16 @@ struct JNIVariablesTests { """ @_cdecl("Java_com_example_swift_MyClass__00024setGetterAndSetter__JJ") func Java_com_example_swift_MyClass__00024setGetterAndSetter__JJ(environment: UnsafeMutablePointer!, thisClass: jclass, newValue: jlong, selfPointer: jlong) { - let self$ = UnsafeMutablePointer(bitPattern: Int(Int64(fromJNI: selfPointer, in: environment!)))! + guard let env$ = environment else { + fatalError("Missing JNIEnv in downcall to \\(#function)") + } + assert(selfPointer != 0, "selfPointer memory address was null") + let selfBits$ = Int(Int64(fromJNI: selfPointer, in: env$)) + assert(selfBits$ != 0, "$self memory address was null: selfPointer = \\(selfPointer)" ) + guard let self$ = UnsafeMutablePointer(bitPattern: selfBits$) else { + fatalError("Missing self pointer in call to \\(#function)!") + } + self$.pointee.getterAndSetter = Int64(fromJNI: newValue, in: environment!) } """ @@ -368,7 +428,15 @@ struct JNIVariablesTests { """ @_cdecl("Java_com_example_swift_MyClass__00024isSomeBoolean__J") func Java_com_example_swift_MyClass__00024isSomeBoolean__J(environment: UnsafeMutablePointer!, thisClass: jclass, selfPointer: jlong) -> jboolean { - let self$ = UnsafeMutablePointer(bitPattern: Int(Int64(fromJNI: selfPointer, in: environment!)))! + guard let env$ = environment else { + fatalError("Missing JNIEnv in downcall to \\(#function)") + } + assert(selfPointer != 0, "selfPointer memory address was null") + let selfBits$ = Int(Int64(fromJNI: selfPointer, in: env$)) + assert(selfBits$ != 0, "$self memory address was null: selfPointer = \\(selfPointer)" ) + guard let self$ = UnsafeMutablePointer(bitPattern: selfBits$) else { + fatalError("Missing self pointer in call to \\(#function)!") + } let result = self$.pointee.someBoolean return result.getJNIValue(in: environment) } @@ -376,7 +444,15 @@ struct JNIVariablesTests { """ @_cdecl("Java_com_example_swift_MyClass__00024setSomeBoolean__ZJ") func Java_com_example_swift_MyClass__00024setSomeBoolean__ZJ(environment: UnsafeMutablePointer!, thisClass: jclass, newValue: jboolean, selfPointer: jlong) { - let self$ = UnsafeMutablePointer(bitPattern: Int(Int64(fromJNI: selfPointer, in: environment!)))! + guard let env$ = environment else { + fatalError("Missing JNIEnv in downcall to \\(#function)") + } + assert(selfPointer != 0, "selfPointer memory address was null") + let selfBits$ = Int(Int64(fromJNI: selfPointer, in: env$)) + assert(selfBits$ != 0, "$self memory address was null: selfPointer = \\(selfPointer)" ) + guard let self$ = UnsafeMutablePointer(bitPattern: selfBits$) else { + fatalError("Missing self pointer in call to \\(#function)!") + } self$.pointee.someBoolean = Bool(fromJNI: newValue, in: environment!) } """ From e7c0635fdb14123df8d29828c007fb83919d4d29 Mon Sep 17 00:00:00 2001 From: Konrad 'ktoso' Malawski Date: Wed, 16 Jul 2025 23:13:43 +0900 Subject: [PATCH 11/13] fix: test harness would incorrectly match less than "detect" size chunks --- ...ift2JavaGenerator+SwiftThunkPrinting.swift | 1 + .../Asserts/TextAssertions.swift | 19 +++++++++++-------- .../JExtractSwiftTests/DataImportTests.swift | 2 +- .../OptionalImportTests.swift | 12 ++++++------ 4 files changed, 19 insertions(+), 15 deletions(-) diff --git a/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+SwiftThunkPrinting.swift b/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+SwiftThunkPrinting.swift index d717255d..10dab4b9 100644 --- a/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+SwiftThunkPrinting.swift +++ b/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+SwiftThunkPrinting.swift @@ -131,6 +131,7 @@ extension FFMSwift2JavaGenerator { } printer.print("import \(module)") } + printer.println() } } diff --git a/Tests/JExtractSwiftTests/Asserts/TextAssertions.swift b/Tests/JExtractSwiftTests/Asserts/TextAssertions.swift index 1d6e19af..5b70f68a 100644 --- a/Tests/JExtractSwiftTests/Asserts/TextAssertions.swift +++ b/Tests/JExtractSwiftTests/Asserts/TextAssertions.swift @@ -28,7 +28,7 @@ func assertOutput( _ mode: JExtractGenerationMode, _ renderKind: RenderKind, swiftModuleName: String = "SwiftModule", - detectChunkByInitialLines: Int = 4, + detectChunkByInitialLines _detectChunkByInitialLines: Int = 4, expectedChunks: [String], fileID: String = #fileID, filePath: String = #filePath, @@ -79,19 +79,22 @@ func assertOutput( let gotLines = output.split(separator: "\n").filter { l in l.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines).count > 0 } - for expected in expectedChunks { - let expectedLines = expected.split(separator: "\n") + for expectedChunk in expectedChunks { + let expectedLines = expectedChunk.split(separator: "\n") + let detectChunkByInitialLines = min(expectedLines.count, _detectChunkByInitialLines) + precondition(detectChunkByInitialLines > 0, "Chunk size to detect cannot be zero lines!") var matchingOutputOffset: Int? = nil let expectedInitialMatchingLines = expectedLines[0.. (offset+detectChunkByInitialLines) { - let textLinesAtOffset = gotLines[offset.. (lineOffset+detectChunkByInitialLines) { + let textLinesAtOffset = gotLines[lineOffset.. Date: Thu, 17 Jul 2025 12:06:28 +0900 Subject: [PATCH 12/13] fix tests since we changed how we get env --- .../JNI/JNIStructTests.swift | 51 ++++++++++++++----- .../MethodImportTests.swift | 3 -- 2 files changed, 37 insertions(+), 17 deletions(-) diff --git a/Tests/JExtractSwiftTests/JNI/JNIStructTests.swift b/Tests/JExtractSwiftTests/JNI/JNIStructTests.swift index 0a883ed1..6bb94c6d 100644 --- a/Tests/JExtractSwiftTests/JNI/JNIStructTests.swift +++ b/Tests/JExtractSwiftTests/JNI/JNIStructTests.swift @@ -63,11 +63,19 @@ struct JNIStructTests { """ @Override protected Runnable $createDestroyFunction() { - long $selfPointer = this.pointer(); + long self$ = this.$memoryAddress(); + if (CallTraces.TRACE_DOWNCALLS) { + CallTraces.traceDowncall("MyStruct.$createDestroyFunction", + "this", this, + "self", self$); + } return new Runnable() { @Override public void run() { - MyStruct.$destroy($selfPointer); + if (CallTraces.TRACE_DOWNCALLS) { + CallTraces.traceDowncall("MyStruct.$destroy", "self", self$); + } + MyStruct.$destroy(self$); } }; } @@ -90,8 +98,8 @@ struct JNIStructTests { * } */ public static MyStruct init(long x, long y, SwiftArena swiftArena$) { - long selfPointer = MyStruct.allocatingInit(x, y); - return new MyStruct(selfPointer, swiftArena$); + long self$ = MyStruct.allocatingInit(x, y); + return new MyStruct(self$, swiftArena$); } """, """ @@ -112,9 +120,9 @@ struct JNIStructTests { """ @_cdecl("Java_com_example_swift_MyStruct_allocatingInit__JJ") func Java_com_example_swift_MyStruct_allocatingInit__JJ(environment: UnsafeMutablePointer!, thisClass: jclass, x: jlong, y: jlong) -> jlong { - let selfPointer = UnsafeMutablePointer.allocate(capacity: 1) - selfPointer.initialize(to: MyStruct(x: Int64(fromJNI: x, in: environment!), y: Int64(fromJNI: y, in: environment!))) - return Int64(Int(bitPattern: selfPointer)).getJNIValue(in: environment) + let self$ = UnsafeMutablePointer.allocate(capacity: 1) + self$.initialize(to: MyStruct(x: Int64(fromJNI: x, in: environment!), y: Int64(fromJNI: y, in: environment!))) + return Int64(Int(bitPattern: self$)).getJNIValue(in: environment) } """ ] @@ -127,14 +135,21 @@ struct JNIStructTests { input: source, .jni, .swift, - detectChunkByInitialLines: 1, expectedChunks: [ """ @_cdecl("Java_com_example_swift_MyStruct__00024destroy__J") func Java_com_example_swift_MyStruct__00024destroy__J(environment: UnsafeMutablePointer!, thisClass: jclass, selfPointer: jlong) { - let pointer = UnsafeMutablePointer(bitPattern: Int(Int64(fromJNI: selfPointer, in: environment!)))! - pointer.deinitialize(count: 1) - pointer.deallocate() + guard let env$ = environment else { + fatalError("Missing JNIEnv in downcall to \\(#function)") + } + assert(selfPointer != 0, "selfPointer memory address was null") + let selfBits$ = Int(Int64(fromJNI: selfPointer, in: env$)) + assert(selfBits$ != 0, "$self memory address was null: selfPointer = \\(selfPointer)" ) + guard let self$ = UnsafeMutablePointer(bitPattern: selfBits$) else { + fatalError("Missing self pointer in call to \\(#function)!") + } + self$.deinitialize(count: 1) + self$.deallocate() } """ ] @@ -156,8 +171,8 @@ struct JNIStructTests { * } */ public void doSomething(long x) { - long selfPointer = this.pointer(); - MyStruct.$doSomething(x, selfPointer); + long self$ = this.$memoryAddress(); + MyStruct.$doSomething(x, self$); } """, """ @@ -178,7 +193,15 @@ struct JNIStructTests { """ @_cdecl("Java_com_example_swift_MyStruct__00024doSomething__JJ") func Java_com_example_swift_MyStruct__00024doSomething__JJ(environment: UnsafeMutablePointer!, thisClass: jclass, x: jlong, selfPointer: jlong) { - let self$ = UnsafeMutablePointer(bitPattern: Int(Int64(fromJNI: selfPointer, in: environment!)))! + guard let env$ = environment else { + fatalError("Missing JNIEnv in downcall to \\(#function)") + } + assert(selfPointer != 0, "selfPointer memory address was null") + let selfBits$ = Int(Int64(fromJNI: selfPointer, in: env$)) + assert(selfBits$ != 0, "$self memory address was null: selfPointer = \\(selfPointer)" ) + guard let self$ = UnsafeMutablePointer(bitPattern: selfBits$) else { + fatalError("Missing self pointer in call to \\(#function)!") + } self$.pointee.doSomething(x: Int64(fromJNI: x, in: environment!)) } """, diff --git a/Tests/JExtractSwiftTests/MethodImportTests.swift b/Tests/JExtractSwiftTests/MethodImportTests.swift index 118ca789..73357d6b 100644 --- a/Tests/JExtractSwiftTests/MethodImportTests.swift +++ b/Tests/JExtractSwiftTests/MethodImportTests.swift @@ -168,7 +168,6 @@ final class MethodImportTests { } assertOutput( - dump: true, output, expected: """ @@ -212,7 +211,6 @@ final class MethodImportTests { } assertOutput( - dump: true, output, expected: """ @@ -256,7 +254,6 @@ final class MethodImportTests { } assertOutput( - dump: true, output, expected: """ From b9fd0a442867fc117f57ed631127b9d8f7f21677 Mon Sep 17 00:00:00 2001 From: Konrad 'ktoso' Malawski Date: Thu, 17 Jul 2025 12:30:16 +0900 Subject: [PATCH 13/13] review followup: assertion message --- ...ift2JavaGenerator+SwiftThunkPrinting.swift | 3 +-- .../JNI/JNIClassTests.swift | 6 ++--- .../JNI/JNIStructTests.swift | 6 ++--- .../JNI/JNIVariablesTests.swift | 27 +++++++------------ 4 files changed, 14 insertions(+), 28 deletions(-) diff --git a/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+SwiftThunkPrinting.swift b/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+SwiftThunkPrinting.swift index 9e1b239c..38d4ff79 100644 --- a/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+SwiftThunkPrinting.swift +++ b/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+SwiftThunkPrinting.swift @@ -356,9 +356,8 @@ extension JNISwift2JavaGenerator { } assert(\(selfPointerParam.name) != 0, "\(selfPointerParam.name) memory address was null") let selfBits$ = Int(Int64(fromJNI: \(selfPointerParam.name), in: env$)) - assert(selfBits$ != 0, "$self memory address was null: \(selfPointerParam.name) = \\(\(selfPointerParam.name))" ) guard let \(newSelfParamName) = UnsafeMutablePointer<\(swiftParentName)>(bitPattern: selfBits$) else { - fatalError("Missing self pointer in call to \\(#function)!") + fatalError("self memory address was null in call to \\(#function)!") } """ ) diff --git a/Tests/JExtractSwiftTests/JNI/JNIClassTests.swift b/Tests/JExtractSwiftTests/JNI/JNIClassTests.swift index 2100233a..5970e7a0 100644 --- a/Tests/JExtractSwiftTests/JNI/JNIClassTests.swift +++ b/Tests/JExtractSwiftTests/JNI/JNIClassTests.swift @@ -212,9 +212,8 @@ struct JNIClassTests { } assert(selfPointer != 0, "selfPointer memory address was null") let selfBits$ = Int(Int64(fromJNI: selfPointer, in: env$)) - assert(selfBits$ != 0, "$self memory address was null: selfPointer = \\(selfPointer)" ) guard let self$ = UnsafeMutablePointer(bitPattern: selfBits$) else { - fatalError("Missing self pointer in call to \\(#function)!") + fatalError("self memory address was null in call to \\(#function)!") } self$.deinitialize(count: 1) self$.deallocate() @@ -266,9 +265,8 @@ struct JNIClassTests { } assert(selfPointer != 0, "selfPointer memory address was null") let selfBits$ = Int(Int64(fromJNI: selfPointer, in: env$)) - assert(selfBits$ != 0, "$self memory address was null: selfPointer = \\(selfPointer)" ) guard let self$ = UnsafeMutablePointer(bitPattern: selfBits$) else { - fatalError("Missing self pointer in call to \\(#function)!") + fatalError("self memory address was null in call to \\(#function)!") } self$.pointee.doSomething(x: Int64(fromJNI: x, in: environment!)) } diff --git a/Tests/JExtractSwiftTests/JNI/JNIStructTests.swift b/Tests/JExtractSwiftTests/JNI/JNIStructTests.swift index 6bb94c6d..47b1c4dc 100644 --- a/Tests/JExtractSwiftTests/JNI/JNIStructTests.swift +++ b/Tests/JExtractSwiftTests/JNI/JNIStructTests.swift @@ -144,9 +144,8 @@ struct JNIStructTests { } assert(selfPointer != 0, "selfPointer memory address was null") let selfBits$ = Int(Int64(fromJNI: selfPointer, in: env$)) - assert(selfBits$ != 0, "$self memory address was null: selfPointer = \\(selfPointer)" ) guard let self$ = UnsafeMutablePointer(bitPattern: selfBits$) else { - fatalError("Missing self pointer in call to \\(#function)!") + fatalError("self memory address was null in call to \\(#function)!") } self$.deinitialize(count: 1) self$.deallocate() @@ -198,9 +197,8 @@ struct JNIStructTests { } assert(selfPointer != 0, "selfPointer memory address was null") let selfBits$ = Int(Int64(fromJNI: selfPointer, in: env$)) - assert(selfBits$ != 0, "$self memory address was null: selfPointer = \\(selfPointer)" ) guard let self$ = UnsafeMutablePointer(bitPattern: selfBits$) else { - fatalError("Missing self pointer in call to \\(#function)!") + fatalError("self memory address was null in call to \\(#function)!") } self$.pointee.doSomething(x: Int64(fromJNI: x, in: environment!)) } diff --git a/Tests/JExtractSwiftTests/JNI/JNIVariablesTests.swift b/Tests/JExtractSwiftTests/JNI/JNIVariablesTests.swift index 663ae48f..3f65bd97 100644 --- a/Tests/JExtractSwiftTests/JNI/JNIVariablesTests.swift +++ b/Tests/JExtractSwiftTests/JNI/JNIVariablesTests.swift @@ -74,9 +74,8 @@ struct JNIVariablesTests { } assert(selfPointer != 0, "selfPointer memory address was null") let selfBits$ = Int(Int64(fromJNI: selfPointer, in: env$)) - assert(selfBits$ != 0, "$self memory address was null: selfPointer = \\(selfPointer)" ) guard let self$ = UnsafeMutablePointer(bitPattern: selfBits$) else { - fatalError("Missing self pointer in call to \\(#function)!") + fatalError("self memory address was null in call to \\(#function)!") } let result = self$.pointee.constant return result.getJNIValue(in: environment) @@ -144,9 +143,8 @@ struct JNIVariablesTests { } assert(selfPointer != 0, "selfPointer memory address was null") let selfBits$ = Int(Int64(fromJNI: selfPointer, in: env$)) - assert(selfBits$ != 0, "$self memory address was null: selfPointer = \\(selfPointer)" ) guard let self$ = UnsafeMutablePointer(bitPattern: selfBits$) else { - fatalError("Missing self pointer in call to \\(#function)!") + fatalError("self memory address was null in call to \\(#function)!") } let result = self$.pointee.mutable return result.getJNIValue(in: environment) @@ -160,9 +158,8 @@ struct JNIVariablesTests { } assert(selfPointer != 0, "selfPointer memory address was null") let selfBits$ = Int(Int64(fromJNI: selfPointer, in: env$)) - assert(selfBits$ != 0, "$self memory address was null: selfPointer = \\(selfPointer)" ) guard let self$ = UnsafeMutablePointer(bitPattern: selfBits$) else { - fatalError("Missing self pointer in call to \\(#function)!") + fatalError("self memory address was null in call to \\(#function)!") } self$.pointee.mutable = Int64(fromJNI: newValue, in: environment!) } @@ -214,9 +211,8 @@ struct JNIVariablesTests { } assert(selfPointer != 0, "selfPointer memory address was null") let selfBits$ = Int(Int64(fromJNI: selfPointer, in: env$)) - assert(selfBits$ != 0, "$self memory address was null: selfPointer = \\(selfPointer)" ) guard let self$ = UnsafeMutablePointer(bitPattern: selfBits$) else { - fatalError("Missing self pointer in call to \\(#function)!") + fatalError("self memory address was null in call to \\(#function)!") } let result = self$.pointee.computed @@ -270,9 +266,8 @@ struct JNIVariablesTests { } assert(selfPointer != 0, "selfPointer memory address was null") let selfBits$ = Int(Int64(fromJNI: selfPointer, in: env$)) - assert(selfBits$ != 0, "$self memory address was null: selfPointer = \\(selfPointer)" ) guard let self$ = UnsafeMutablePointer(bitPattern: selfBits$) else { - fatalError("Missing self pointer in call to \\(#function)!") + fatalError("self memory address was null in call to \\(#function)!") } do { @@ -346,9 +341,8 @@ struct JNIVariablesTests { } assert(selfPointer != 0, "selfPointer memory address was null") let selfBits$ = Int(Int64(fromJNI: selfPointer, in: env$)) - assert(selfBits$ != 0, "$self memory address was null: selfPointer = \\(selfPointer)" ) guard let self$ = UnsafeMutablePointer(bitPattern: selfBits$) else { - fatalError("Missing self pointer in call to \\(#function)!") + fatalError("self memory address was null in call to \\(#function)!") } let result = self$.pointee.getterAndSetter @@ -363,9 +357,8 @@ struct JNIVariablesTests { } assert(selfPointer != 0, "selfPointer memory address was null") let selfBits$ = Int(Int64(fromJNI: selfPointer, in: env$)) - assert(selfBits$ != 0, "$self memory address was null: selfPointer = \\(selfPointer)" ) guard let self$ = UnsafeMutablePointer(bitPattern: selfBits$) else { - fatalError("Missing self pointer in call to \\(#function)!") + fatalError("self memory address was null in call to \\(#function)!") } self$.pointee.getterAndSetter = Int64(fromJNI: newValue, in: environment!) @@ -433,9 +426,8 @@ struct JNIVariablesTests { } assert(selfPointer != 0, "selfPointer memory address was null") let selfBits$ = Int(Int64(fromJNI: selfPointer, in: env$)) - assert(selfBits$ != 0, "$self memory address was null: selfPointer = \\(selfPointer)" ) guard let self$ = UnsafeMutablePointer(bitPattern: selfBits$) else { - fatalError("Missing self pointer in call to \\(#function)!") + fatalError("self memory address was null in call to \\(#function)!") } let result = self$.pointee.someBoolean return result.getJNIValue(in: environment) @@ -449,9 +441,8 @@ struct JNIVariablesTests { } assert(selfPointer != 0, "selfPointer memory address was null") let selfBits$ = Int(Int64(fromJNI: selfPointer, in: env$)) - assert(selfBits$ != 0, "$self memory address was null: selfPointer = \\(selfPointer)" ) guard let self$ = UnsafeMutablePointer(bitPattern: selfBits$) else { - fatalError("Missing self pointer in call to \\(#function)!") + fatalError("self memory address was null in call to \\(#function)!") } self$.pointee.someBoolean = Bool(fromJNI: newValue, in: environment!) }