Skip to content

Commit d3e4a6e

Browse files
committed
work in progress on calling destroy of a class
1 parent 9b848a9 commit d3e4a6e

File tree

11 files changed

+137
-103
lines changed

11 files changed

+137
-103
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ BuildLogic/out/
1616
**/build/
1717
lib/
1818

19+
# Ignore JVM crash logs
20+
**/*.log
21+
1922
# Ignore package resolved
2023
Package.resolved
2124

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

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import com.example.swift.generated.MySwiftClass;
1919

2020
// Import javakit/swiftkit support libraries
21+
import org.swift.swiftkit.SwiftArena;
2122
import org.swift.swiftkit.SwiftKit;
2223
import org.swift.swiftkit.SwiftValueWitnessTable;
2324

@@ -45,23 +46,22 @@ static void examples() {
4546
// obj.voidMethod();
4647
// obj.takeIntMethod(42);
4748

48-
// try (var arena = SwiftArena.ofConfined()) {
49-
var instance = new MySwiftClass(
50-
// arena,
51-
1111, 2222);
49+
MySwiftClass unsafelyEscaped = null;
50+
try (var arena = SwiftArena.ofConfined()) {
51+
var instance = new MySwiftClass(arena, 1111, 2222);
52+
unsafelyEscaped = instance;
53+
54+
var num = instance.makeIntMethod();
5255

5356
System.out.println("MySwiftClass.TYPE_MANGLED_NAME = " + MySwiftClass.TYPE_MANGLED_NAME);
54-
var swiftType = SwiftKit.getTypeByMangledNameInEnvironment(MySwiftClass.TYPE_MANGLED_NAME);
55-
System.out.println("swiftType = " + swiftType);
56-
// MemorySegment typeMetadata = SwiftValueWitnessTable.fullTypeMetadata(swiftType.$memorySegment());
57-
// System.out.println("typeMetadata = " + typeMetadata);
58-
//
59-
//
60-
// System.out.printf("size of type = %d%n", SwiftValueWitnessTable.sizeOfSwiftType(swiftType.$memorySegment()));
61-
// System.out.printf("stride of type = %d%n", SwiftValueWitnessTable.strideOfSwiftType(swiftType.$memorySegment()));
62-
// System.out.printf("alignment of type = %d%n", SwiftValueWitnessTable.alignmentOfSwiftType(swiftType.$memorySegment()));
63-
// System.out.printf("layout of type = %s%n", SwiftValueWitnessTable.layoutOfSwiftType(swiftType.$memorySegment()).toString());
57+
MemorySegment typeMetadata = SwiftValueWitnessTable.fullTypeMetadata(MySwiftClass.TYPE_METADATA.$memorySegment());
58+
System.out.println("typeMetadata = " + typeMetadata);
59+
60+
SwiftKit.release(instance);
61+
} // instance should be deallocated
62+
63+
var num = unsafelyEscaped.makeIntMethod();
6464

65-
// } // instance should be deallocated
65+
System.out.println("DONE.");
6666
}
6767
}

Sources/JExtractSwift/Swift2JavaTranslator+Printing.swift

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -113,20 +113,24 @@ extension Swift2JavaTranslator {
113113
public func printImportedClass(_ printer: inout CodePrinter, _ decl: ImportedNominalType) {
114114
printHeader(&printer)
115115
printPackage(&printer)
116-
printImports(&printer) // TODO print any imports the file may need, it we talk to other Swift modules
116+
printImports(&printer)
117117

118118
printClass(&printer, decl) { printer in
119-
// Metadata
119+
// Ensure we have loaded the library where the Swift type was declared before we attempt to resolve types in Swift
120+
printStaticLibraryLoad(&printer)
121+
122+
// Prepare type metadata, we're going to need these when invoking e.g. initializers so cache them in a static
120123
printer.print(
121124
"""
122125
public static final String TYPE_MANGLED_NAME = "\(decl.swiftMangledName ?? "")";
123-
static final MemorySegment TYPE_METADATA = SwiftKit.getTypeByMangledNameInEnvironment(TYPE_MANGLED_NAME);
126+
public static final SwiftAnyType TYPE_METADATA = SwiftKit.getTypeByMangledNameInEnvironment(TYPE_MANGLED_NAME).get();
127+
public final SwiftAnyType $swiftType() {
128+
return TYPE_METADATA;
129+
}
124130
"""
125131
)
126132
printer.print("")
127133

128-
printStaticLibraryLoad(&printer)
129-
130134
// Initializers
131135
for initDecl in decl.initializers {
132136
printClassConstructors(&printer, initDecl)
@@ -141,6 +145,9 @@ extension Swift2JavaTranslator {
141145
for funcDecl in decl.methods {
142146
printFunctionDowncallMethods(&printer, funcDecl)
143147
}
148+
149+
// Helper methods and default implementations
150+
printHeapObjectToStringMethod(&printer, decl)
144151
}
145152
}
146153

@@ -345,7 +352,6 @@ extension Swift2JavaTranslator {
345352
public static final ValueLayout.OfLong SWIFT_UINT = SWIFT_INT64;
346353
347354
public static final AddressLayout SWIFT_SELF = SWIFT_POINTER;
348-
public static final AddressLayout SWIFT_TYPE_METADATA_PTR = SWIFT_POINTER;
349355
"""
350356
)
351357
}
@@ -412,7 +418,7 @@ extension Swift2JavaTranslator {
412418
/**
413419
* Create an instance of {@code \(parentName.unqualifiedJavaTypeName)}.
414420
*
415-
* \(decl.renderCommentSnippet ?? " *")
421+
\(decl.renderCommentSnippet ?? " *")
416422
*/
417423
public \(parentName.unqualifiedJavaTypeName)(\(renderJavaParamDecls(decl, selfVariant: .wrapper))) {
418424
this(/*arena=*/null, \(renderForwardParams(decl, selfVariant: .wrapper)));
@@ -426,7 +432,7 @@ extension Swift2JavaTranslator {
426432
* Create an instance of {@code \(parentName.unqualifiedJavaTypeName)}.
427433
* This instance is managed by the passed in {@link SwiftArena} and may not outlive the arena's lifetime.
428434
*
429-
* \(decl.renderCommentSnippet ?? " *")
435+
\(decl.renderCommentSnippet ?? " *")
430436
*/
431437
public \(parentName.unqualifiedJavaTypeName)(SwiftArena arena, \(renderJavaParamDecls(decl, selfVariant: .wrapper))) {
432438
var mh$ = \(descClassIdentifier).HANDLE;
@@ -435,7 +441,7 @@ extension Swift2JavaTranslator {
435441
traceDowncall(\(renderForwardParams(decl, selfVariant: nil)));
436442
}
437443
438-
this.selfMemorySegment = (MemorySegment) mh$.invokeExact(\(renderForwardParams(decl, selfVariant: nil)), TYPE_METADATA);
444+
this.selfMemorySegment = (MemorySegment) mh$.invokeExact(\(renderForwardParams(decl, selfVariant: nil)), TYPE_METADATA.$memorySegment());
439445
if (arena != null) {
440446
arena.register(this);
441447
}
@@ -824,7 +830,7 @@ extension Swift2JavaTranslator {
824830
public func printHeapObjectToStringMethod(_ printer: inout CodePrinter, _ decl: ImportedNominalType) {
825831
printer.print(
826832
"""
827-
@Override
833+
@Override
828834
public String toString() {
829835
return getClass().getSimpleName() + "(" +
830836
SwiftKit.nameOfSwiftType($swiftType().$memorySegment(), true) +

SwiftKit/src/main/java/org/swift/swiftkit/SwiftAnyType.java

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public final class SwiftAnyType implements SwiftMemoryResource {
2424
SwiftValueLayout.SWIFT_POINTER
2525
);
2626

27-
final MemorySegment memorySegment;
27+
private final MemorySegment memorySegment;
2828

2929
public SwiftAnyType(MemorySegment memorySegment) {
3030
if (memorySegment.byteSize() == 0) {
@@ -40,11 +40,11 @@ public SwiftAnyType(SwiftHeapObject object) {
4040
}
4141

4242
String mangledName = object.$layout().name().get();
43-
var tySegment = SwiftKit.getTypeByMangledNameInEnvironment(mangledName);
44-
// if (tySegment.isEmpty()) {
45-
// throw new IllegalArgumentException("A Swift Any.Type cannot be null!");
46-
// }
47-
this.memorySegment = tySegment; //.get().memorySegment;
43+
var type = SwiftKit.getTypeByMangledNameInEnvironment(mangledName);
44+
if (type.isEmpty()) {
45+
throw new IllegalArgumentException("A Swift Any.Type cannot be null!");
46+
}
47+
this.memorySegment = type.get().memorySegment;
4848
}
4949

5050

@@ -68,7 +68,7 @@ public boolean immortal() {
6868
public String toString() {
6969
return "AnySwiftType{" +
7070
"name=" + SwiftKit.nameOfSwiftType(memorySegment, true) +
71-
"memorySegment=" + memorySegment +
71+
", memorySegment=" + memorySegment +
7272
'}';
7373
}
7474
}

SwiftKit/src/main/java/org/swift/swiftkit/SwiftArena.java

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ static SwiftArena ofConfined() {
4747

4848
final class ConfinedSwiftMemorySession implements SwiftArena {
4949

50-
final Arena underlying;
50+
// final Arena underlying;
5151
final Thread owner;
5252
final SwiftResourceList resources;
5353

@@ -58,19 +58,21 @@ final class ConfinedSwiftMemorySession implements SwiftArena {
5858

5959
public ConfinedSwiftMemorySession(Thread owner) {
6060
this.owner = owner;
61-
underlying = Arena.ofConfined();
61+
// underlying = Arena.ofConfined();
6262
resources = new ConfinedResourceList();
6363
state = new AtomicInteger(ACTIVE);
6464
}
6565

6666
@Override
6767
public MemorySegment allocate(long byteSize, long byteAlignment) {
68-
return underlying.allocate(byteSize, byteAlignment);
68+
// return underlying.allocate(byteSize, byteAlignment);
69+
return null;
6970
}
7071

7172
@Override
7273
public MemorySegment.Scope scope() {
73-
return underlying.scope();
74+
return null;
75+
// return underlying.scope();
7476
}
7577

7678
public void checkValid() throws RuntimeException {
@@ -83,13 +85,13 @@ public void checkValid() throws RuntimeException {
8385

8486
@Override
8587
public void register(SwiftHeapObject object) {
86-
SwiftKit.log.info("Registered " + object.$memorySegment() + " in " + this);
87-
this.resources.add(new SwiftHeapObjectCleanup(object.$memorySegment()));
88+
System.out.println("Registered " + object.$memorySegment() + " in " + this);
89+
this.resources.add(new SwiftHeapObjectCleanup(object));
8890
}
8991

9092
@Override
9193
public void register(SwiftValue value) {
92-
this.resources.add(new SwiftHeapObjectCleanup(value.$memorySegment()));
94+
this.resources.add(new SwiftValueCleanup(value.$memorySegment()));
9395
}
9496

9597
@Override
@@ -104,10 +106,10 @@ public void close() {
104106

105107

106108
// Those the underlying arena
107-
this.underlying.close();
109+
// this.underlying.close();
108110

109111
// After this method returns normally, the scope must be not alive anymore
110-
assert (!this.scope().isAlive());
112+
// assert (!this.scope().isAlive());
111113
}
112114

113115
/**
@@ -142,7 +144,7 @@ public void cleanup() {
142144
}
143145

144146
final class UnexpectedRetainCountException extends RuntimeException {
145-
public UnexpectedRetainCountException(MemorySegment resource, long retainCount, int expectedRetainCount) {
147+
public UnexpectedRetainCountException(Object resource, long retainCount, int expectedRetainCount) {
146148
super(("Attempting to cleanup managed memory segment %s, but it's retain count was different than [%d] (was %d)! " +
147149
"This would result in destroying a swift object that is still retained by other code somewhere."
148150
).formatted(resource, expectedRetainCount, retainCount));

SwiftKit/src/main/java/org/swift/swiftkit/SwiftHeapObject.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,5 @@
2020
* Represents a wrapper around a Swift heap object, e.g. a {@code class} or an {@code actor}.
2121
*/
2222
public interface SwiftHeapObject extends SwiftMemoryResource {
23+
SwiftAnyType $swiftType();
2324
}

SwiftKit/src/main/java/org/swift/swiftkit/SwiftKit.java

Lines changed: 22 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import java.lang.foreign.*;
2020
import java.lang.invoke.MethodHandle;
2121
import java.util.Arrays;
22+
import java.util.Optional;
2223
import java.util.logging.Logger;
2324
import java.util.stream.Collectors;
2425

@@ -33,8 +34,6 @@ public class SwiftKit {
3334
private static final Arena LIBRARY_ARENA = Arena.ofAuto();
3435
static final boolean TRACE_DOWNCALLS = Boolean.getBoolean("jextract.trace.downcalls");
3536

36-
static final Logger log = Logger.getLogger("SwiftKit");
37-
3837
static {
3938
System.loadLibrary(STDLIB_DYLIB_NAME);
4039
System.loadLibrary("SwiftKitSwift");
@@ -272,8 +271,8 @@ private static class getTypeByStringByteArray {
272271
* @param mangledName The mangled type name (often prefixed with {@code $s}).
273272
* @return the Swift Type wrapper object
274273
*/
275-
public static MemorySegment getTypeByMangledNameInEnvironment(String mangledName) {
276-
log.info("Get Any.Type for mangled name: " + mangledName);
274+
public static Optional<SwiftAnyType> getTypeByMangledNameInEnvironment(String mangledName) {
275+
System.out.println("Get Any.Type for mangled name: " + mangledName);
277276

278277
var mh$ = swift_getTypeByMangledNameInEnvironment.HANDLE;
279278
try {
@@ -289,19 +288,14 @@ public static MemorySegment getTypeByMangledNameInEnvironment(String mangledName
289288
try (Arena arena = Arena.ofConfined()) {
290289
MemorySegment stringMemorySegment = arena.allocateFrom(mangledName);
291290

292-
var ty = (MemorySegment) mh$.invokeExact(stringMemorySegment, mangledName.length(), MemorySegment.NULL, MemorySegment.NULL);
291+
var memorySegment = (MemorySegment) mh$.invokeExact(stringMemorySegment, mangledName.length(), MemorySegment.NULL, MemorySegment.NULL);
293292

294-
return ty;
295-
296-
// if (ty.address() == 0) {
297-
// return Optional.empty();
298-
// }
299-
//
300-
// var wrapper = new SwiftAnyType(ty);
301-
// log.info("Resolved type '"+mangledName+"' as: " + wrapper);
302-
//
303-
// return Optional.of(wrapper);
293+
if (memorySegment.address() == 0) {
294+
return Optional.empty();
295+
}
304296

297+
var wrapper = new SwiftAnyType(memorySegment);
298+
return Optional.of(wrapper);
305299
}
306300
} catch (Throwable ex$) {
307301
throw new AssertionError("should not reach here", ex$);
@@ -313,7 +307,7 @@ public static MemorySegment getTypeByMangledNameInEnvironment(String mangledName
313307
* <p>
314308
* This function copes with the fact that a Swift.Int might be 32 or 64 bits.
315309
*/
316-
public static final long getSwiftInt(MemorySegment memorySegment, long offset) {
310+
public static long getSwiftInt(MemorySegment memorySegment, long offset) {
317311
if (SwiftValueLayout.SWIFT_INT == ValueLayout.JAVA_LONG) {
318312
return memorySegment.get(ValueLayout.JAVA_LONG, offset);
319313
} else {
@@ -358,14 +352,18 @@ private static class swift_getTypeName {
358352
* e.g. the result of a {@link swift_getTypeByMangledNameInEnvironment} call
359353
*/
360354
public static String nameOfSwiftType(MemorySegment typeMetadata, boolean qualified) {
361-
try {
362-
try (Arena arena = Arena.ofConfined()) {
363-
MemorySegment charsAndLength = (MemorySegment) swift_getTypeName.HANDLE.invokeExact((SegmentAllocator) arena, typeMetadata, qualified);
364-
MemorySegment utf8Chars = charsAndLength.get(SwiftValueLayout.SWIFT_POINTER, 0);
365-
String typeName = utf8Chars.getString(0);
366-
cFree(utf8Chars);
367-
return typeName;
368-
}
355+
MethodHandle mh = swift_getTypeName.HANDLE;
356+
357+
try (Arena arena = Arena.ofConfined()) {
358+
MemorySegment charsAndLength = (MemorySegment) mh.invokeExact((SegmentAllocator) arena, typeMetadata, qualified);
359+
MemorySegment utf8Chars = charsAndLength.get(SwiftValueLayout.SWIFT_POINTER, 0);
360+
String typeName = utf8Chars.getString(0);
361+
362+
// FIXME: this free is not always correct:
363+
// java(80175,0x17008f000) malloc: *** error for object 0x600000362610: pointer being freed was not allocated
364+
// cFree(utf8Chars);
365+
366+
return typeName;
369367
} catch (Throwable ex$) {
370368
throw new AssertionError("should not reach here", ex$);
371369
}

SwiftKit/src/main/java/org/swift/swiftkit/SwiftMemoryResourceCleanup.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
sealed interface SwiftMemoryResourceCleanup extends Runnable {
2323
}
2424

25-
record SwiftHeapObjectCleanup(MemorySegment resource) implements SwiftMemoryResourceCleanup {
25+
record SwiftHeapObjectCleanup(SwiftHeapObject resource) implements SwiftMemoryResourceCleanup {
2626

2727
@Override
2828
public void run() throws UnexpectedRetainCountException {
@@ -31,9 +31,10 @@ public void run() throws UnexpectedRetainCountException {
3131
throw new UnexpectedRetainCountException(this.resource, retainedCount, 1);
3232
}
3333

34-
SwiftKit.log.info("Destroy heap object: " + this.resource);
34+
System.out.println("Cleanup heap object: " + this.resource);
35+
var ty = this.resource.$swiftType();
3536

36-
SwiftValueWitnessTable.destroy(this.resource);
37+
SwiftValueWitnessTable.destroy(ty, this.resource.$memorySegment());
3738
}
3839
}
3940

0 commit comments

Comments
 (0)