|
17 | 17 | import java.lang.foreign.GroupLayout; |
18 | 18 | import java.lang.foreign.MemorySegment; |
19 | 19 | import java.util.concurrent.atomic.AtomicBoolean; |
| 20 | +import java.util.function.Supplier; |
20 | 21 |
|
21 | | -public interface SwiftInstance { |
| 22 | +public abstract class SwiftInstance { |
| 23 | + /// Pointer to the "self". |
| 24 | + private final MemorySegment selfMemorySegment; |
22 | 25 |
|
23 | 26 | /** |
24 | 27 | * The pointer to the instance in memory. I.e. the {@code self} of the Swift object or value. |
25 | 28 | */ |
26 | | - MemorySegment $memorySegment(); |
| 29 | + public final MemorySegment $memorySegment() { |
| 30 | + return this.selfMemorySegment; |
| 31 | + } |
| 32 | + |
| 33 | + // TODO: make this a flagset integer and/or use a field updater |
| 34 | + /** Used to track additional state of the underlying object, e.g. if it was explicitly destroyed. */ |
| 35 | + private final AtomicBoolean $state$destroyed = new AtomicBoolean(false); |
| 36 | + |
| 37 | + /** |
| 38 | + * Exposes a boolean value which can be used to indicate if the object was destroyed. |
| 39 | + * <p/> |
| 40 | + * This is exposing the object, rather than performing the action because we don't want to accidentally |
| 41 | + * form a strong reference to the {@code SwiftInstance} which could prevent the cleanup from running, |
| 42 | + * if using an GC managed instance (e.g. using an {@link AutoSwiftMemorySession}. |
| 43 | + */ |
| 44 | + public final AtomicBoolean $statusDestroyedFlag() { |
| 45 | + return this.$state$destroyed; |
| 46 | + } |
27 | 47 |
|
28 | 48 | /** |
29 | 49 | * The in memory layout of an instance of this Swift type. |
30 | 50 | */ |
31 | | - GroupLayout $layout(); |
| 51 | + public abstract GroupLayout $layout(); |
32 | 52 |
|
33 | | - SwiftAnyType $swiftType(); |
| 53 | + /** |
| 54 | + * The Swift type metadata of this type. |
| 55 | + */ |
| 56 | + public abstract SwiftAnyType $swiftType(); |
34 | 57 |
|
35 | 58 | /** |
36 | | - * Returns `true` if this swift instance is a reference type, i.e. a `class` or (`distributed`) `actor`. |
| 59 | + * The designated constructor of any imported Swift types. |
37 | 60 | * |
38 | | - * @return `true` if this instance is a reference type, `false` otherwise. |
| 61 | + * @param segment the memory segment. |
| 62 | + * @param arena the arena this object belongs to. When the arena goes out of scope, this value is destroyed. |
39 | 63 | */ |
40 | | - default boolean isReferenceType() { |
41 | | - return this instanceof SwiftHeapObject; |
| 64 | + protected SwiftInstance(MemorySegment segment, SwiftArena arena) { |
| 65 | + this.selfMemorySegment = segment; |
| 66 | + arena.register(this); |
42 | 67 | } |
43 | 68 |
|
44 | 69 | /** |
45 | | - * Exposes a boolean value which can be used to indicate if the object was destroyed. |
| 70 | + * Convenience constructor subclasses can call like: |
| 71 | + * {@snippet : |
| 72 | + * super(() -> { ...; return segment; }, swiftArena$) |
| 73 | + * } |
| 74 | + * |
| 75 | + * @param segmentSupplier Should return the memory segment of the value |
| 76 | + * @param arena the arena where the supplied segment belongs to. When the arena goes out of scope, this value is destroyed. |
| 77 | + */ |
| 78 | + protected SwiftInstance(Supplier<MemorySegment> segmentSupplier, SwiftArena arena) { |
| 79 | + this(segmentSupplier.get(), arena); |
| 80 | + } |
| 81 | + |
| 82 | + /** |
| 83 | + * Ensures that this instance has not been destroyed. |
46 | 84 | * <p/> |
47 | | - * This is exposing the object, rather than performing the action because we don't want to accidentally |
48 | | - * form a strong reference to the {@code SwiftInstance} which could prevent the cleanup from running, |
49 | | - * if using an GC managed instance (e.g. using an {@link AutoSwiftMemorySession}. |
| 85 | + * If this object has been destroyed, calling this method will cause an {@link IllegalStateException} |
| 86 | + * to be thrown. This check should be performed before accessing {@code $memorySegment} to prevent |
| 87 | + * use-after-free errors. |
50 | 88 | */ |
51 | | - AtomicBoolean $statusDestroyedFlag(); |
| 89 | + protected final void $ensureAlive() { |
| 90 | + if (this.$state$destroyed.get()) { |
| 91 | + throw new IllegalStateException("Attempted to call method on already destroyed instance of " + getClass().getSimpleName() + "!"); |
| 92 | + } |
| 93 | + } |
| 94 | + |
| 95 | + /** |
| 96 | + * Returns `true` if this swift instance is a reference type, i.e. a `class` or (`distributed`) `actor`. |
| 97 | + * |
| 98 | + * @return `true` if this instance is a reference type, `false` otherwise. |
| 99 | + */ |
| 100 | + public boolean isReferenceType() { |
| 101 | + return this instanceof SwiftHeapObject; |
| 102 | + } |
52 | 103 | } |
0 commit comments