Skip to content

Commit 67154d5

Browse files
committed
snapshot, new version of swift side for returning array
1 parent e44364a commit 67154d5

File tree

7 files changed

+266
-58
lines changed

7 files changed

+266
-58
lines changed

Samples/SwiftJavaExtractFFMSampleApp/Sources/MySwiftLibrary/MySwiftLibrary.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,16 @@ public func sumAllByteArrayElements(actuallyAnArray: UnsafeRawPointer, count: In
7676
public func sumAllByteArrayElements(array: [UInt8]) -> Int {
7777
return Int(array.reduce(0, { partialResult, element in partialResult + element }))
7878
}
79+
public func returnSwiftArray() -> [UInt8] {
80+
return [1, 2, 3, 4]
81+
}
82+
83+
// public func swiftjava_MySwiftLibrary_getArray(_ _result_initialize: (UnsafeMutablePointer<UnsafeRawPointer?>, UnsafeMutablePointer<Int>) -> ()) {
84+
// let _result = returnSwiftArray()
85+
// _result.withUnsafeBufferPointer { buf in
86+
// _result_initialize(buf.baseAddress, buf.count)
87+
// }
88+
// }
7989

8090
public func withArray(body: ([UInt8]) -> Void) {
8191
body([1, 2, 3])

Samples/SwiftJavaExtractFFMSampleApp/src/test/java/com/example/swift/WithBufferTest.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,31 @@
2020

2121
import static org.junit.jupiter.api.Assertions.*;
2222

23+
import java.lang.foreign.Arena;
24+
import java.lang.foreign.MemorySegment;
2325
import java.lang.foreign.ValueLayout;
2426
import java.util.Arrays;
2527
import java.util.concurrent.atomic.AtomicLong;
2628
import java.util.stream.IntStream;
2729

2830
public class WithBufferTest {
31+
32+
public static byte[] returnArray() {
33+
try (var arena$ = Arena.ofConfined()) {
34+
MemorySegment _result_pointer = arena$.allocate(SwiftValueLayout.SWIFT_POINTER);
35+
MemorySegment _result_count = arena$.allocate(SwiftValueLayout.SWIFT_INT64);
36+
// swiftjava_SwiftModule_returnArray.call(_result_pointer, _result_count);
37+
// return _result_pointer
38+
// .get(SwiftValueLayout.SWIFT_POINTER, 0)
39+
// .reinterpret(_result_count.get(SwiftValueLayout.SWIFT_INT64, 0));
40+
MemorySegment memorySegment = _result_pointer
41+
.get(SwiftValueLayout.SWIFT_POINTER, 0);
42+
long newSize = _result_count.get(SwiftValueLayout.SWIFT_INT64, 0);
43+
MemorySegment arraySegment = memorySegment.reinterpret(newSize);
44+
return arraySegment.toArray(ValueLayout.JAVA_BYTE);
45+
}
46+
}
47+
2948
@Test
3049
void test_withBuffer() {
3150
AtomicLong bufferSize = new AtomicLong();

Sources/JExtractSwiftLib/FFM/CDeclLowering/FFMSwift2JavaGenerator+FunctionLowering.swift

Lines changed: 54 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -363,7 +363,6 @@ struct CdeclLowering {
363363
),
364364
]
365365

366-
// Initialize a UnsafeRawBufferPointer using the 'address' and 'count'
367366
let bufferPointerInit = ConversionStep.initialize(
368367
knownTypes.unsafeRawBufferPointer,
369368
arguments: [
@@ -565,6 +564,24 @@ struct CdeclLowering {
565564
}
566565
}
567566

567+
/// Create "out" parameter names when we're returning an array-like result.
568+
fileprivate func makeBufferIndirectReturnParameters(_ outParameterName: String, isMutable: Bool) -> [SwiftParameter] {
569+
[
570+
SwiftParameter(
571+
convention: .byValue,
572+
parameterName: "\(outParameterName)_pointer",
573+
type: knownTypes.unsafeMutablePointer(
574+
.optional(isMutable ? knownTypes.unsafeMutableRawPointer : knownTypes.unsafeRawPointer)
575+
)
576+
),
577+
SwiftParameter(
578+
convention: .byValue,
579+
parameterName: "\(outParameterName)_count",
580+
type: knownTypes.unsafeMutablePointer(knownTypes.int)
581+
),
582+
]
583+
}
584+
568585
/// Lower a Swift result type to cdecl out parameters and return type.
569586
///
570587
/// - Parameters:
@@ -620,20 +637,7 @@ struct CdeclLowering {
620637
let isMutable = knownType == .unsafeMutableRawBufferPointer
621638
return LoweredResult(
622639
cdeclResultType: .void,
623-
cdeclOutParameters: [
624-
SwiftParameter(
625-
convention: .byValue,
626-
parameterName: "\(outParameterName)_pointer",
627-
type: knownTypes.unsafeMutablePointer(
628-
.optional(isMutable ? knownTypes.unsafeMutableRawPointer : knownTypes.unsafeRawPointer)
629-
)
630-
),
631-
SwiftParameter(
632-
convention: .byValue,
633-
parameterName: "\(outParameterName)_count",
634-
type: knownTypes.unsafeMutablePointer(knownTypes.int)
635-
),
636-
],
640+
cdeclOutParameters: makeBufferIndirectReturnParameters(outParameterName, isMutable: isMutable),
637641
conversion: .aggregate([
638642
.populatePointer(
639643
name: "\(outParameterName)_pointer",
@@ -712,6 +716,41 @@ struct CdeclLowering {
712716
cdeclOutParameters: parameters,
713717
conversion: .tupleExplode(conversions, name: outParameterName)
714718
)
719+
720+
case .array(let wrapped) where wrapped == knownTypes.uint8:
721+
let resultName = "_result"
722+
723+
return LoweredResult(
724+
cdeclResultType: .void, // we call into the _result_initialize instead
725+
cdeclOutParameters: [
726+
SwiftParameter(
727+
convention: .byValue,
728+
parameterName: "\(outParameterName)_initialize",
729+
type: knownTypes.functionInitializeByteBuffer
730+
)
731+
],
732+
conversion: .aggregate([
733+
.method(base: resultName, methodName: "withUnsafeBufferPointer", arguments: [
734+
.init(argument:
735+
.closureLowering(
736+
parameters: [.placeholder],
737+
result: .method(
738+
base: "\(outParameterName)_initialize",
739+
methodName: nil, // just `(...)` apply the closure
740+
arguments: [
741+
.init(label: nil, argument: .member(.constant("_0"), member: "baseAddress")),
742+
.init(label: nil, argument: .member(.constant("_0"), member: "count")),
743+
]
744+
// arguments: [
745+
// .init(label: nil, argument: .member(.placeholder, member: "baseAddress")),
746+
// .init(label: nil, argument: .member(.placeholder, member: "count")),
747+
// ]
748+
)
749+
)
750+
)
751+
])
752+
], name: resultName)
753+
)
715754

716755
case .genericParameter, .function, .optional, .existential, .opaque, .composite, .array:
717756
throw LoweringError.unhandledType(type)

Sources/JExtractSwiftLib/FFM/ConversionStep.swift

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ import SwiftSyntaxBuilder
2121
enum ConversionStep: Equatable {
2222
/// The value being lowered.
2323
case placeholder
24+
25+
/// FIXME: Workaround for picking a specific placeholder value; We should resolve how method() works with lowered closures instead
26+
case constant(String)
2427

2528
/// A reference to a component in a value that has been exploded, such as
2629
/// a tuple element or part of a buffer pointer.
@@ -60,8 +63,12 @@ enum ConversionStep: Equatable {
6063

6164
indirect case closureLowering(parameters: [ConversionStep], result: ConversionStep)
6265

66+
/// Access a member of the target, e.g. `<target>.member`
6367
indirect case member(ConversionStep, member: String)
6468

69+
/// Call a method with provided parameters.
70+
indirect case method(base: String?, methodName: String?, arguments: [LabeledArgument<ConversionStep>])
71+
6572
indirect case optionalChain(ConversionStep)
6673

6774
/// Count the number of times that the placeholder occurs within this
@@ -77,8 +84,12 @@ enum ConversionStep: Equatable {
7784
inner.placeholderCount
7885
case .initialize(_, arguments: let arguments):
7986
arguments.reduce(0) { $0 + $1.argument.placeholderCount }
87+
case .method(_, _, let arguments):
88+
arguments.reduce(0) { $0 + $1.argument.placeholderCount }
8089
case .placeholder, .tupleExplode, .closureLowering:
8190
1
91+
case .constant:
92+
0
8293
case .tuplify(let elements), .aggregate(let elements, _):
8394
elements.reduce(0) { $0 + $1.placeholderCount }
8495
}
@@ -98,6 +109,9 @@ enum ConversionStep: Equatable {
98109
case .placeholder:
99110
return "\(raw: placeholder)"
100111

112+
case .constant(let name):
113+
return "\(raw: name)"
114+
101115
case .explodedComponent(let step, component: let component):
102116
return step.asExprSyntax(placeholder: "\(placeholder)_\(component)", bodyItems: &bodyItems)
103117

@@ -162,6 +176,29 @@ enum ConversionStep: Equatable {
162176
let inner = step.asExprSyntax(placeholder: placeholder, bodyItems: &bodyItems)
163177
return "\(inner).\(raw: member)"
164178

179+
case .method(let base, let methodName, let arguments):
180+
// TODO: this is duplicated, try to dedupe it a bit
181+
let renderedArguments: [String] = arguments.map { labeledArgument in
182+
let argExpr = labeledArgument.argument.asExprSyntax(placeholder: placeholder, bodyItems: &bodyItems)
183+
return LabeledExprSyntax(label: labeledArgument.label, expression: argExpr!).description
184+
}
185+
186+
// FIXME: Should be able to use structured initializers here instead of splatting out text.
187+
let renderedArgumentList = renderedArguments.joined(separator: ", ")
188+
189+
let methodApply: String =
190+
if let methodName {
191+
".\(methodName)"
192+
} else {
193+
"" // this is equivalent to calling `base(...)`
194+
}
195+
196+
if let base {
197+
return "\(raw: base)\(raw: methodApply)(\(raw: renderedArgumentList))"
198+
} else {
199+
return "\(raw: methodApply)(\(raw: renderedArgumentList))"
200+
}
201+
165202
case .aggregate(let steps, let name):
166203
let toExplode: String
167204
if let name {

Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+JavaTranslation.swift

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -714,6 +714,33 @@ extension FFMSwift2JavaGenerator {
714714
// TODO: Implement.
715715
throw JavaTranslationError.unhandledType(swiftType)
716716

717+
case .array(let wrapped) where wrapped == knownTypes.uint8:
718+
return TranslatedResult(
719+
javaResultType:
720+
.array(.byte),
721+
annotations: [.unsigned],
722+
outParameters: [
723+
JavaParameter(name: "pointer", type: .javaForeignMemorySegment),
724+
JavaParameter(name: "count", type: .long),
725+
],
726+
conversion:
727+
.method(
728+
.method(
729+
.readMemorySegment(.explodedName(component: "pointer"), as: .javaForeignMemorySegment),
730+
methodName: "reinterpret",
731+
arguments: [
732+
.readMemorySegment(.explodedName(component: "count"), as: .long)
733+
],
734+
withArena: false
735+
),
736+
methodName: "toArray",
737+
arguments: [
738+
.constant("ValueLayout.JAVA_BYTE")
739+
],
740+
withArena: false
741+
)
742+
)
743+
717744
case .genericParameter, .optional, .function, .existential, .opaque, .composite, .array:
718745
throw JavaTranslationError.unhandledType(swiftType)
719746
}

Sources/JExtractSwiftLib/SwiftTypes/SwiftKnownTypes.swift

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,24 @@ struct SwiftKnownTypes {
3535
var unsafeRawPointer: SwiftType { .nominal(SwiftNominalType(nominalTypeDecl: symbolTable[.unsafeRawPointer])) }
3636
var unsafeRawBufferPointer: SwiftType { .nominal(SwiftNominalType(nominalTypeDecl: symbolTable[.unsafeRawBufferPointer])) }
3737
var unsafeMutableRawPointer: SwiftType { .nominal(SwiftNominalType(nominalTypeDecl: symbolTable[.unsafeMutableRawPointer])) }
38-
38+
3939
var foundationDataProtocol: SwiftType { .nominal(SwiftNominalType(nominalTypeDecl: symbolTable[.foundationDataProtocol])) }
4040
var foundationData: SwiftType { .nominal(SwiftNominalType(nominalTypeDecl: symbolTable[.foundationData])) }
4141
var essentialsDataProtocol: SwiftType { .nominal(SwiftNominalType(nominalTypeDecl: symbolTable[.essentialsDataProtocol])) }
4242
var essentialsData: SwiftType { .nominal(SwiftNominalType(nominalTypeDecl: symbolTable[.essentialsData])) }
43+
44+
/// `(UnsafeRawPointer, Long) -> ()` function type.
45+
///
46+
/// Commonly used to initialize a buffer using the passed bytes and length.
47+
var functionInitializeByteBuffer: SwiftType {
48+
.function(SwiftFunctionType(
49+
convention: .c,
50+
parameters: [
51+
SwiftParameter(convention: .byValue, parameterName: nil, type: self.unsafeRawPointer), // array base pointer
52+
SwiftParameter(convention: .byValue, parameterName: nil, type: self.int), // array length
53+
],
54+
resultType: .void))
55+
}
4356

4457
func unsafePointer(_ pointeeType: SwiftType) -> SwiftType {
4558
.nominal(

0 commit comments

Comments
 (0)