Skip to content

Commit a00d3e9

Browse files
committed
WIP
1 parent d397700 commit a00d3e9

File tree

13 files changed

+96
-221
lines changed

13 files changed

+96
-221
lines changed

Sources/JExtractSwift/ImportedDecls.swift

Lines changed: 0 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -127,54 +127,6 @@ public final class ImportedFunc: ImportedDecl, CustomStringConvertible {
127127
}
128128
}
129129

130-
public final class ImportedVariable: ImportedDecl, CustomStringConvertible {
131-
132-
public var module: String
133-
134-
/// Parent type if this is a type member.
135-
var parentType: SwiftType
136-
137-
/// The variable name.
138-
public var name: String
139-
140-
/// The value type
141-
var type: SwiftType
142-
143-
/// The syntax of the variable
144-
public var swiftDecl: any DeclSyntaxProtocol
145-
146-
/// Function signatures for accessors.
147-
var accessors: [ImportedFunc]
148-
149-
init(
150-
module: String,
151-
parentType: SwiftType,
152-
name: String,
153-
type: SwiftType,
154-
swiftDecl: any DeclSyntaxProtocol,
155-
accessors: [ImportedFunc]
156-
) {
157-
self.module = module
158-
self.parentType = parentType
159-
self.name = name
160-
self.type = type
161-
self.swiftDecl = swiftDecl
162-
self.accessors = accessors
163-
}
164-
165-
public var description: String {
166-
"""
167-
ImportedVaraiable {
168-
module: \(module)
169-
parentType: \(parentType)
170-
name: \(name)
171-
type: \(type)
172-
signature: \(self.swiftDecl.signatureString)
173-
}
174-
"""
175-
}
176-
}
177-
178130
extension ImportedFunc: Hashable {
179131
public func hash(into hasher: inout Hasher) {
180132
hasher.combine(ObjectIdentifier(self))
@@ -183,12 +135,3 @@ extension ImportedFunc: Hashable {
183135
return lhs === rhs
184136
}
185137
}
186-
187-
extension ImportedVariable: Hashable {
188-
public func hash(into hasher: inout Hasher) {
189-
hasher.combine(ObjectIdentifier(self))
190-
}
191-
public static func == (lhs: ImportedVariable, rhs: ImportedVariable) -> Bool {
192-
return lhs === rhs
193-
}
194-
}

Sources/JExtractSwift/JavaConstants/ForeignValueLayouts.swift

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -83,9 +83,4 @@ extension ForeignValueLayout {
8383

8484
public static let SwiftFloat = Self(javaConstant: "SWIFT_FLOAT")
8585
public static let SwiftDouble = Self(javaConstant: "SWIFT_DOUBLE")
86-
87-
var isPrimitive: Bool {
88-
// FIXME: This is a hack, we need an enum to better describe this!
89-
value != "SWIFT_POINTER"
90-
}
9186
}

Sources/JExtractSwift/Swift2Java.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ public struct SwiftToJava: ParsableCommand {
9090

9191
try translator.analyze()
9292
try translator.writeSwiftThunkSources(outputDirectory: outputDirectorySwift)
93-
try translator.writeExportedJavaSources(outputDirectory: outputDirectoryJava)
93+
try translator.writeJavaBindingsSources(outputDirectory: outputDirectoryJava)
9494
print("[swift-java] Generated Java sources (\(packageName)) in: \(outputDirectoryJava)/")
9595
print("[swift-java] Imported Swift module '\(swiftModule)': " + "done.".green)
9696
}

Sources/JExtractSwift/Swift2JavaTranslator+JavaThunkPrinting.swift renamed to Sources/JExtractSwift/Swift2JavaTranslator+JavaBindingsPrinting.swift

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,11 @@
1313
//===----------------------------------------------------------------------===//
1414

1515
import Foundation
16+
import JavaTypes
1617
import SwiftBasicFormat
1718
import SwiftParser
1819
import SwiftSyntax
1920

20-
import JavaTypes
21-
2221
// ==== ---------------------------------------------------------------------------------------------------------------
2322
// MARK: File writing
2423

@@ -27,12 +26,12 @@ let PATH_SEPARATOR = "/" // TODO: Windows
2726
extension Swift2JavaTranslator {
2827

2928
/// Every imported public type becomes a public class in its own file in Java.
30-
public func writeExportedJavaSources(outputDirectory: String) throws {
29+
public func writeJavaBindingsSources(outputDirectory: String) throws {
3130
var printer = CodePrinter()
32-
try writeExportedJavaSources(outputDirectory: outputDirectory, printer: &printer)
31+
try writeJavaBindingsSources(outputDirectory: outputDirectory, printer: &printer)
3332
}
3433

35-
public func writeExportedJavaSources(outputDirectory: String, printer: inout CodePrinter) throws {
34+
public func writeJavaBindingsSources(outputDirectory: String, printer: inout CodePrinter) throws {
3635
for (_, ty) in importedTypes.sorted(by: { (lhs, rhs) in lhs.key < rhs.key }) {
3736
let filename = "\(ty.swiftNominal.name).java"
3837
log.info("Printing contents: \(filename)")
@@ -120,12 +119,12 @@ extension Swift2JavaTranslator {
120119
}
121120
"""
122121
)
123-
printer.print("")
122+
printer.println()
124123

125124
// Layout of the class
126125
printClassMemoryLayout(&printer, decl)
127126

128-
printer.print("")
127+
printer.println()
129128

130129
printer.print(
131130
"""
@@ -184,14 +183,9 @@ extension Swift2JavaTranslator {
184183
package func printNominal(
185184
_ printer: inout CodePrinter, _ decl: ImportedNominalType, body: (inout CodePrinter) -> Void
186185
) {
187-
let parentProtocol: String
188-
if decl.swiftNominal.isReferenceType {
189-
parentProtocol = " implements SwiftHeapObject"
190-
} else {
191-
parentProtocol = ""
192-
}
186+
let baseProtocol = decl.swiftNominal.isReferenceType ? "SwiftHeapObject" : "SwiftValue"
193187

194-
printer.printBraceBlock("public final class \(decl.swiftNominal.name) extends SwiftValue\(parentProtocol)") { printer in
188+
printer.printBraceBlock("public final class \(decl.swiftNominal.name) extends SwiftInstance implements \(baseProtocol)") { printer in
195189
// Constants
196190
printClassConstants(printer: &printer)
197191

Sources/JExtractSwift/SwiftTypes/SwiftSymbolTable.swift

Lines changed: 0 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -50,65 +50,6 @@ package class SwiftSymbolTable {
5050
}
5151
}
5252

53-
extension SwiftSymbolTable {
54-
func setup(_ sourceFiles: some Collection<SourceFileSyntax>) {
55-
// First, register top-level and nested nominal types to the symbol table.
56-
for sourceFile in sourceFiles {
57-
self.addNominalTypeDeclarations(sourceFile)
58-
}
59-
60-
// Register nested nominal in extensions to the symbol table.
61-
func handleExtension(_ extensionDecl: ExtensionDeclSyntax) -> Bool {
62-
// Try to resolve the type referenced by this extension declaration.
63-
// If it fails, we'll try again later.
64-
guard let extendedType = try? SwiftType(extensionDecl.extendedType, symbolTable: self) else {
65-
return false
66-
}
67-
guard let extendedNominal = extendedType.asNominalTypeDeclaration else {
68-
// Extending type was not a nominal type. Ignore it.
69-
return true
70-
}
71-
72-
// We have successfully resolved the extended type. Record it and
73-
// remove the extension from the list of unresolved extensions.
74-
self.parsedModule.addExtension(extensionDecl, extending: extendedNominal)
75-
return true
76-
}
77-
78-
// The work queue is required because, the extending type might be declared
79-
// in another extension that hasn't been processed. E.g.:
80-
//
81-
// extension Outer.Inner { struct Deeper {} }
82-
// extension Outer { struct Inner {} }
83-
// struct Outer {}
84-
//
85-
var unresolvedExtensions: [ExtensionDeclSyntax] = []
86-
for sourceFile in sourceFiles {
87-
// Find extensions.
88-
for statement in sourceFile.statements {
89-
// We only care about extensions at top-level.
90-
if case .decl(let decl) = statement.item, let extNode = decl.as(ExtensionDeclSyntax.self) {
91-
let resolved = handleExtension(extNode)
92-
if !resolved {
93-
unresolvedExtensions.append(extNode)
94-
}
95-
}
96-
}
97-
}
98-
99-
while !unresolvedExtensions.isEmpty {
100-
let numExtensionsBefore = unresolvedExtensions.count
101-
unresolvedExtensions.removeAll(where: handleExtension(_:))
102-
103-
// If we didn't resolve anything, we're done.
104-
if numExtensionsBefore == unresolvedExtensions.count {
105-
break
106-
}
107-
assert(numExtensionsBefore > unresolvedExtensions.count)
108-
}
109-
}
110-
}
111-
11253
extension SwiftSymbolTable {
11354
package func setup(_ sourceFiles: some Collection<SourceFileSyntax>) {
11455
// First, register top-level and nested nominal types to the symbol table.

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

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -48,16 +48,16 @@ public AutoSwiftMemorySession(ThreadFactory cleanerThreadFactory) {
4848
}
4949

5050
@Override
51-
public void register(SwiftValue value) {
52-
Objects.requireNonNull(value, "value");
51+
public void register(SwiftInstance instance) {
52+
Objects.requireNonNull(instance, "value");
5353

5454
// We're doing this dance to avoid keeping a strong reference to the value itself
55-
var statusDestroyedFlag = value.$statusDestroyedFlag();
55+
var statusDestroyedFlag = instance.$statusDestroyedFlag();
5656
Runnable markAsDestroyed = () -> statusDestroyedFlag.set(true);
5757

58-
MemorySegment resource = value.$memorySegment();
59-
var cleanupAction = new SwiftValueCleanup(resource, value.$swiftType(), markAsDestroyed);
60-
cleaner.register(value, cleanupAction);
58+
MemorySegment resource = instance.$memorySegment();
59+
var cleanupAction = new SwiftInstanceCleanup(resource, instance.$swiftType(), markAsDestroyed);
60+
cleaner.register(instance, cleanupAction);
6161
}
6262

6363
@Override

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,13 +61,13 @@ public void close() {
6161
}
6262

6363
@Override
64-
public void register(SwiftValue value) {
64+
public void register(SwiftInstance value) {
6565
checkValid();
6666

6767
var statusDestroyedFlag = value.$statusDestroyedFlag();
6868
Runnable markAsDestroyed = () -> statusDestroyedFlag.set(true);
6969

70-
var cleanup = new SwiftValueCleanup(
70+
var cleanup = new SwiftInstanceCleanup(
7171
value.$memorySegment(),
7272
value.$swiftType(),
7373
markAsDestroyed);

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,10 @@ static SwiftArena ofAuto() {
3636
}
3737

3838
/**
39-
* Register a struct, enum or other non-reference counted Swift object.
39+
* Register a Swift object.
4040
* Its memory should be considered managed by this arena, and be destroyed when the arena is closed.
4141
*/
42-
void register(SwiftValue value);
42+
void register(SwiftInstance value);
4343

4444
}
4545

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

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,12 @@
2020
* Represents a wrapper around a Swift heap object, e.g. a {@code class} or an {@code actor}.
2121
*/
2222
public interface SwiftHeapObject {
23-
default MemorySegment $instance() {
23+
MemorySegment $memorySegment();
24+
25+
/**
26+
* Pointer to the instance.
27+
*/
28+
public default MemorySegment $instance() {
2429
return this.$memorySegment().get(SwiftValueLayout.SWIFT_POINTER, 0);
2530
}
26-
27-
MemorySegment $memorySegment();
2831
}

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

Lines changed: 64 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -17,36 +17,87 @@
1717
import java.lang.foreign.GroupLayout;
1818
import java.lang.foreign.MemorySegment;
1919
import java.util.concurrent.atomic.AtomicBoolean;
20+
import java.util.function.Supplier;
2021

21-
public interface SwiftInstance {
22+
public abstract class SwiftInstance {
23+
/// Pointer to the "self".
24+
private final MemorySegment selfMemorySegment;
2225

2326
/**
2427
* The pointer to the instance in memory. I.e. the {@code self} of the Swift object or value.
2528
*/
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+
}
2747

2848
/**
2949
* The in memory layout of an instance of this Swift type.
3050
*/
31-
GroupLayout $layout();
51+
public abstract GroupLayout $layout();
3252

33-
SwiftAnyType $swiftType();
53+
/**
54+
* The Swift type metadata of this type.
55+
*/
56+
public abstract SwiftAnyType $swiftType();
3457

3558
/**
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.
3760
*
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.
3963
*/
40-
default boolean isReferenceType() {
41-
return this instanceof SwiftHeapObject;
64+
protected SwiftInstance(MemorySegment segment, SwiftArena arena) {
65+
this.selfMemorySegment = segment;
66+
arena.register(this);
4267
}
4368

4469
/**
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.
4684
* <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.
5088
*/
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+
}
52103
}

0 commit comments

Comments
 (0)