Skip to content

Commit c1807bd

Browse files
committed
Merge branch 'main' into docs/resolve-command
2 parents fb96646 + 62ce866 commit c1807bd

File tree

21 files changed

+472
-50
lines changed

21 files changed

+472
-50
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ bin/
1717
BuildLogic/out/
1818
.index-build
1919
.build-vscode
20+
**/.vscode
2021

2122
# Ignore gradle build artifacts
2223
.gradle
@@ -46,3 +47,4 @@ Package.resolved
4647
*/**/*.swiftdeps
4748
*/**/*.swiftdeps~
4849
*/**/.docc-build/
50+

Samples/JExtractJNISampleApp/src/main/java/com/example/swift/HelloJava2SwiftJNI.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@
1818

1919
// Import javakit/swiftkit support libraries
2020

21+
import org.swift.swiftkit.core.SwiftArena;
2122
import org.swift.swiftkit.core.SwiftLibraries;
22-
import org.swift.swiftkit.core.ConfinedSwiftMemorySession;
2323

2424
public class HelloJava2SwiftJNI {
2525

@@ -41,7 +41,7 @@ static void examples() {
4141

4242
MySwiftClass.method();
4343

44-
try (var arena = new ConfinedSwiftMemorySession()) {
44+
try (var arena = SwiftArena.ofConfined()) {
4545
MySwiftClass myClass = MySwiftClass.init(10, 5, arena);
4646
MySwiftClass myClass2 = MySwiftClass.init(arena);
4747

Samples/JExtractJNISampleApp/src/test/java/com/example/swift/MySwiftClassTest.java

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
package com.example.swift;
1616

1717
import org.junit.jupiter.api.Test;
18-
import org.swift.swiftkit.core.ConfinedSwiftMemorySession;
18+
import org.swift.swiftkit.core.SwiftArena;
1919

2020
import java.util.Optional;
2121
import java.util.OptionalInt;
@@ -26,39 +26,39 @@
2626
public class MySwiftClassTest {
2727
@Test
2828
void init_noParameters() {
29-
try (var arena = new ConfinedSwiftMemorySession()) {
29+
try (var arena = SwiftArena.ofConfined()) {
3030
MySwiftClass c = MySwiftClass.init(arena);
3131
assertNotNull(c);
3232
}
3333
}
3434

3535
@Test
3636
void init_withParameters() {
37-
try (var arena = new ConfinedSwiftMemorySession()) {
37+
try (var arena = SwiftArena.ofConfined()) {
3838
MySwiftClass c = MySwiftClass.init(1337, 42, arena);
3939
assertNotNull(c);
4040
}
4141
}
4242

4343
@Test
4444
void sum() {
45-
try (var arena = new ConfinedSwiftMemorySession()) {
45+
try (var arena = SwiftArena.ofConfined()) {
4646
MySwiftClass c = MySwiftClass.init(20, 10, arena);
4747
assertEquals(30, c.sum());
4848
}
4949
}
5050

5151
@Test
5252
void xMultiplied() {
53-
try (var arena = new ConfinedSwiftMemorySession()) {
53+
try (var arena = SwiftArena.ofConfined()) {
5454
MySwiftClass c = MySwiftClass.init(20, 10, arena);
5555
assertEquals(200, c.xMultiplied(10));
5656
}
5757
}
5858

5959
@Test
6060
void throwingFunction() {
61-
try (var arena = new ConfinedSwiftMemorySession()) {
61+
try (var arena = SwiftArena.ofConfined()) {
6262
MySwiftClass c = MySwiftClass.init(20, 10, arena);
6363
Exception exception = assertThrows(Exception.class, () -> c.throwingFunction());
6464

@@ -68,15 +68,15 @@ void throwingFunction() {
6868

6969
@Test
7070
void constant() {
71-
try (var arena = new ConfinedSwiftMemorySession()) {
71+
try (var arena = SwiftArena.ofConfined()) {
7272
MySwiftClass c = MySwiftClass.init(20, 10, arena);
7373
assertEquals(100, c.getConstant());
7474
}
7575
}
7676

7777
@Test
7878
void mutable() {
79-
try (var arena = new ConfinedSwiftMemorySession()) {
79+
try (var arena = SwiftArena.ofConfined()) {
8080
MySwiftClass c = MySwiftClass.init(20, 10, arena);
8181
assertEquals(0, c.getMutable());
8282
c.setMutable(42);
@@ -86,15 +86,15 @@ void mutable() {
8686

8787
@Test
8888
void product() {
89-
try (var arena = new ConfinedSwiftMemorySession()) {
89+
try (var arena = SwiftArena.ofConfined()) {
9090
MySwiftClass c = MySwiftClass.init(20, 10, arena);
9191
assertEquals(200, c.getProduct());
9292
}
9393
}
9494

9595
@Test
9696
void throwingVariable() {
97-
try (var arena = new ConfinedSwiftMemorySession()) {
97+
try (var arena = SwiftArena.ofConfined()) {
9898
MySwiftClass c = MySwiftClass.init(20, 10, arena);
9999

100100
Exception exception = assertThrows(Exception.class, () -> c.getThrowingVariable());
@@ -105,7 +105,7 @@ void throwingVariable() {
105105

106106
@Test
107107
void mutableDividedByTwo() {
108-
try (var arena = new ConfinedSwiftMemorySession()) {
108+
try (var arena = SwiftArena.ofConfined()) {
109109
MySwiftClass c = MySwiftClass.init(20, 10, arena);
110110
assertEquals(0, c.getMutableDividedByTwo());
111111
c.setMutable(20);
@@ -117,15 +117,15 @@ void mutableDividedByTwo() {
117117

118118
@Test
119119
void isWarm() {
120-
try (var arena = new ConfinedSwiftMemorySession()) {
120+
try (var arena = SwiftArena.ofConfined()) {
121121
MySwiftClass c = MySwiftClass.init(20, 10, arena);
122122
assertFalse(c.isWarm());
123123
}
124124
}
125125

126126
@Test
127127
void sumWithX() {
128-
try (var arena = new ConfinedSwiftMemorySession()) {
128+
try (var arena = SwiftArena.ofConfined()) {
129129
MySwiftClass c1 = MySwiftClass.init(20, 10, arena);
130130
MySwiftClass c2 = MySwiftClass.init(50, 10, arena);
131131
assertEquals(70, c1.sumX(c2));
@@ -134,7 +134,7 @@ void sumWithX() {
134134

135135
@Test
136136
void copy() {
137-
try (var arena = new ConfinedSwiftMemorySession()) {
137+
try (var arena = SwiftArena.ofConfined()) {
138138
MySwiftClass c1 = MySwiftClass.init(20, 10, arena);
139139
MySwiftClass c2 = c1.copy(arena);
140140

@@ -146,7 +146,7 @@ void copy() {
146146

147147
@Test
148148
void addXWithJavaLong() {
149-
try (var arena = new ConfinedSwiftMemorySession()) {
149+
try (var arena = SwiftArena.ofConfined()) {
150150
MySwiftClass c1 = MySwiftClass.init(20, 10, arena);
151151
Long javaLong = 50L;
152152
assertEquals(70, c1.addXWithJavaLong(javaLong));

Samples/JExtractJNISampleApp/src/test/java/com/example/swift/MySwiftStructTest.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,14 @@
1616

1717
import org.junit.jupiter.api.Test;
1818
import org.swift.swiftkit.core.ConfinedSwiftMemorySession;
19+
import org.swift.swiftkit.core.SwiftArena;
1920

2021
import static org.junit.jupiter.api.Assertions.*;
2122

2223
public class MySwiftStructTest {
2324
@Test
2425
void init() {
25-
try (var arena = new ConfinedSwiftMemorySession()) {
26+
try (var arena = SwiftArena.ofConfined()) {
2627
MySwiftStruct s = MySwiftStruct.init(1337, 42, arena);
2728
assertEquals(1337, s.getCapacity());
2829
assertEquals(42, s.getLen());
@@ -31,7 +32,7 @@ void init() {
3132

3233
@Test
3334
void getAndSetLen() {
34-
try (var arena = new ConfinedSwiftMemorySession()) {
35+
try (var arena = SwiftArena.ofConfined()) {
3536
MySwiftStruct s = MySwiftStruct.init(1337, 42, arena);
3637
s.setLen(100);
3738
assertEquals(100, s.getLen());
@@ -40,7 +41,7 @@ void getAndSetLen() {
4041

4142
@Test
4243
void increaseCap() {
43-
try (var arena = new ConfinedSwiftMemorySession()) {
44+
try (var arena = SwiftArena.ofConfined()) {
4445
MySwiftStruct s = MySwiftStruct.init(1337, 42, arena);
4546
long newCap = s.increaseCap(10);
4647
assertEquals(1347, newCap);

Samples/JExtractJNISampleApp/src/test/java/com/example/swift/OptionalsTest.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
package com.example.swift;
1616

1717
import org.junit.jupiter.api.Test;
18-
import org.swift.swiftkit.core.ConfinedSwiftMemorySession;
18+
import org.swift.swiftkit.core.SwiftArena;
1919

2020
import java.util.Optional;
2121
import java.util.OptionalDouble;
@@ -82,7 +82,7 @@ void optionalString() {
8282

8383
@Test
8484
void optionalClass() {
85-
try (var arena = new ConfinedSwiftMemorySession()) {
85+
try (var arena = SwiftArena.ofConfined()) {
8686
MySwiftClass c = MySwiftClass.init(arena);
8787
assertEquals(Optional.empty(), MySwiftLibrary.optionalClass(Optional.empty(), arena));
8888
Optional<MySwiftClass> optionalClass = MySwiftLibrary.optionalClass(Optional.of(c), arena);
@@ -99,7 +99,7 @@ void optionalJavaKitLong() {
9999

100100
@Test
101101
void multipleOptionals() {
102-
try (var arena = new ConfinedSwiftMemorySession()) {
102+
try (var arena = SwiftArena.ofConfined()) {
103103
MySwiftClass c = MySwiftClass.init(arena);
104104
OptionalLong result = MySwiftLibrary.multipleOptionals(
105105
Optional.of((byte) 1),

Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+JavaBindingsPrinting.swift

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -247,29 +247,47 @@ extension JNISwift2JavaGenerator {
247247
guard let translatedDecl = translatedDecl(for: decl) else {
248248
fatalError("Decl was not translated, \(decl)")
249249
}
250+
let translatedSignature = translatedDecl.translatedFunctionSignature
250251

251252
var modifiers = ["public"]
253+
252254
if decl.isStatic || decl.isInitializer || !decl.hasParent {
253255
modifiers.append("static")
254256
}
255257

256-
let translatedSignature = translatedDecl.translatedFunctionSignature
257258
let resultType = translatedSignature.resultType.javaType
258-
var parameters = translatedDecl.translatedFunctionSignature.parameters.map({ $0.parameter.renderParameter() })
259-
if translatedSignature.requiresSwiftArena {
260-
parameters.append("SwiftArena swiftArena$")
261-
}
259+
var parameters = translatedDecl.translatedFunctionSignature.parameters.map { $0.parameter.renderParameter() }
262260
let throwsClause = decl.isThrowing ? " throws Exception" : ""
263261

264262
var annotationsStr = translatedSignature.annotations.map({ $0.render() }).joined(separator: "\n")
265263
if !annotationsStr.isEmpty { annotationsStr += "\n" }
266264

267-
let modifiersStr = modifiers.joined(separator: " ")
268265
let parametersStr = parameters.joined(separator: ", ")
269266

267+
// Print default global arena variation
268+
if config.effectiveMemoryManagementMode.requiresGlobalArena && translatedSignature.requiresSwiftArena {
269+
printDeclDocumentation(&printer, decl)
270+
printer.printBraceBlock(
271+
"\(annotationsStr)\(modifiers.joined(separator: " ")) \(resultType) \(translatedDecl.name)(\(parametersStr))\(throwsClause)"
272+
) { printer in
273+
let globalArenaName = "SwiftMemoryManagement.GLOBAL_SWIFT_JAVA_ARENA"
274+
let arguments = translatedDecl.translatedFunctionSignature.parameters.map(\.parameter.name) + [globalArenaName]
275+
let call = "\(translatedDecl.name)(\(arguments.joined(separator: ", ")))"
276+
if translatedDecl.translatedFunctionSignature.resultType.javaType.isVoid {
277+
printer.print("\(call);")
278+
} else {
279+
printer.print("return \(call);")
280+
}
281+
}
282+
printer.println()
283+
}
284+
285+
if translatedSignature.requiresSwiftArena {
286+
parameters.append("SwiftArena swiftArena$")
287+
}
270288
printDeclDocumentation(&printer, decl)
271289
printer.printBraceBlock(
272-
"\(annotationsStr)\(modifiersStr) \(resultType) \(translatedDecl.name)(\(parametersStr))\(throwsClause)"
290+
"\(annotationsStr)\(modifiers.joined(separator: " ")) \(resultType) \(translatedDecl.name)(\(parameters.joined(separator: ", ")))\(throwsClause)"
273291
) { printer in
274292
printDowncall(&printer, decl)
275293
}

Sources/JExtractSwiftLib/Swift2JavaVisitor.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
//
33
// This source file is part of the Swift.org open source project
44
//
5-
// Copyright (c) 2024 Apple Inc. and the Swift.org project authors
5+
// Copyright (c) 2024-2025 Apple Inc. and the Swift.org project authors
66
// Licensed under Apache License v2.0
77
//
88
// See LICENSE.txt for license information
@@ -84,7 +84,7 @@ final class Swift2JavaVisitor {
8484
}
8585

8686
func visit(extensionDecl node: ExtensionDeclSyntax, in parent: ImportedNominalType?) {
87-
guard parent != nil else {
87+
guard parent == nil else {
8888
// 'extension' in a nominal type is invalid. Ignore
8989
return
9090
}

Sources/JavaKitConfigurationShared/Configuration.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,11 @@ public struct Configuration: Codable {
5151
minimumInputAccessLevelMode ?? .default
5252
}
5353

54+
public var memoryManagementMode: JExtractMemoryManagementMode?
55+
public var effectiveMemoryManagementMode: JExtractMemoryManagementMode {
56+
memoryManagementMode ?? .default
57+
}
58+
5459
// ==== java 2 swift ---------------------------------------------------------
5560

5661
/// The Java class path that should be passed along to the swift-java tool.

Sources/JavaKitConfigurationShared/GenerationMode.swift

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,3 +76,25 @@ extension JExtractMinimumAccessLevelMode {
7676
.public
7777
}
7878
}
79+
80+
81+
/// Configures how memory should be managed by the user
82+
public enum JExtractMemoryManagementMode: String, Codable {
83+
/// Force users to provide an explicit `SwiftArena` to all calls that require them.
84+
case explicit
85+
86+
/// Provide both explicit `SwiftArena` support
87+
/// and a default global automatic `SwiftArena` that will deallocate memory when the GC decides to.
88+
case allowGlobalAutomatic
89+
90+
public static var `default`: Self {
91+
.explicit
92+
}
93+
94+
public var requiresGlobalArena: Bool {
95+
switch self {
96+
case .explicit: false
97+
case .allowGlobalAutomatic: true
98+
}
99+
}
100+
}

Sources/SwiftJavaTool/Commands/JExtractCommand.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,9 @@ extension SwiftJava {
6767
@Option(help: "The lowest access level of Swift declarations that should be extracted, defaults to 'public'.")
6868
var minimumInputAccessLevel: JExtractMinimumAccessLevelMode = .default
6969

70+
@Option(help: "The memory management mode to use for the generated code. By default, the user must explicitly provide `SwiftArena` to all calls that require it. By choosing `allow-automatic`, user can omit this parameter and a global GC-based arena will be used. `force-automatic` removes all explicit memory management.")
71+
var memoryManagementMode: JExtractMemoryManagementMode = .default
72+
7073
@Option(
7174
help: """
7275
A swift-java configuration file for a given Swift module name on which this module depends,
@@ -89,6 +92,7 @@ extension SwiftJava.JExtractCommand {
8992
config.writeEmptyFiles = writeEmptyFiles
9093
config.unsignedNumbersMode = unsignedNumbers
9194
config.minimumInputAccessLevelMode = minimumInputAccessLevel
95+
config.memoryManagementMode = memoryManagementMode
9296

9397
try checkModeCompatibility()
9498

@@ -117,6 +121,10 @@ extension SwiftJava.JExtractCommand {
117121
case .wrapGuava:
118122
() // OK
119123
}
124+
} else if self.mode == .ffm {
125+
guard self.memoryManagementMode == .explicit else {
126+
throw IllegalModeCombinationError("FFM mode does not support '\(self.memoryManagementMode)' memory management mode! \(Self.helpMessage)")
127+
}
120128
}
121129
}
122130
}
@@ -148,3 +156,4 @@ struct IllegalModeCombinationError: Error {
148156
extension JExtractGenerationMode: ExpressibleByArgument {}
149157
extension JExtractUnsignedIntegerMode: ExpressibleByArgument {}
150158
extension JExtractMinimumAccessLevelMode: ExpressibleByArgument {}
159+
extension JExtractMemoryManagementMode: ExpressibleByArgument {}

0 commit comments

Comments
 (0)