From 2e1c8d8b3a982232436ebf9364fb974712ea0dd2 Mon Sep 17 00:00:00 2001 From: Konrad Malawski Date: Wed, 3 Dec 2025 12:55:05 +0900 Subject: [PATCH 1/2] samples: move more tests from sample app to test files --- .../com/example/swift/HelloJava2Swift.java | 4 +-- .../com/example/swift/WithBufferTest.java | 36 +++++++++++++++++++ 2 files changed, 37 insertions(+), 3 deletions(-) create mode 100644 Samples/SwiftJavaExtractFFMSampleApp/src/test/java/com/example/swift/WithBufferTest.java diff --git a/Samples/SwiftJavaExtractFFMSampleApp/src/main/java/com/example/swift/HelloJava2Swift.java b/Samples/SwiftJavaExtractFFMSampleApp/src/main/java/com/example/swift/HelloJava2Swift.java index cecb1231..a1312547 100644 --- a/Samples/SwiftJavaExtractFFMSampleApp/src/main/java/com/example/swift/HelloJava2Swift.java +++ b/Samples/SwiftJavaExtractFFMSampleApp/src/main/java/com/example/swift/HelloJava2Swift.java @@ -52,9 +52,7 @@ static void examples() { CallTraces.trace("getGlobalBuffer().byteSize()=" + MySwiftLibrary.getGlobalBuffer().byteSize()); - MySwiftLibrary.withBuffer((buf) -> { - CallTraces.trace("withBuffer{$0.byteSize()}=" + buf.byteSize()); - }); + // Example of using an arena; MyClass.deinit is run at end of scope try (var arena = AllocatingSwiftArena.ofConfined()) { MySwiftClass obj = MySwiftClass.init(2222, 7777, arena); diff --git a/Samples/SwiftJavaExtractFFMSampleApp/src/test/java/com/example/swift/WithBufferTest.java b/Samples/SwiftJavaExtractFFMSampleApp/src/test/java/com/example/swift/WithBufferTest.java new file mode 100644 index 00000000..86069aae --- /dev/null +++ b/Samples/SwiftJavaExtractFFMSampleApp/src/test/java/com/example/swift/WithBufferTest.java @@ -0,0 +1,36 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2025 Apple Inc. and the Swift.org project authors +// Licensed under Apache License v2.0 +// +// See LICENSE.txt for license information +// See CONTRIBUTORS.txt for the list of Swift.org project authors +// +// SPDX-License-Identifier: Apache-2.0 +// +//===----------------------------------------------------------------------===// + +package com.example.swift; + +import org.junit.jupiter.api.Test; +import org.swift.swiftkit.core.*; +import org.swift.swiftkit.ffm.*; + +import static org.junit.jupiter.api.Assertions.*; + +import java.util.concurrent.atomic.AtomicLong; + +public class WithBufferTest { + @Test + void test_withBuffer() { + AtomicLong bufferSize = new AtomicLong(); + MySwiftLibrary.withBuffer((buf) -> { + CallTraces.trace("withBuffer{$0.byteSize()}=" + buf.byteSize()); + bufferSize.set(buf.byteSize()); + }); + + assertEquals(124, bufferSize.get()); + } +} From 7ebccdd527cc61a34c38b2497972fb38a5a58b31 Mon Sep 17 00:00:00 2001 From: Konrad Malawski Date: Wed, 3 Dec 2025 13:47:21 +0900 Subject: [PATCH 2/2] add another test that uses MemorySegment to pass an array copy to Swift (ffm) --- .../MySwiftLibrary/MySwiftLibrary.swift | 18 ++++++++++++++ .../com/example/swift/WithBufferTest.java | 24 +++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/Samples/SwiftJavaExtractFFMSampleApp/Sources/MySwiftLibrary/MySwiftLibrary.swift b/Samples/SwiftJavaExtractFFMSampleApp/Sources/MySwiftLibrary/MySwiftLibrary.swift index cdd61c12..9929f888 100644 --- a/Samples/SwiftJavaExtractFFMSampleApp/Sources/MySwiftLibrary/MySwiftLibrary.swift +++ b/Samples/SwiftJavaExtractFFMSampleApp/Sources/MySwiftLibrary/MySwiftLibrary.swift @@ -63,6 +63,24 @@ public func withBuffer(body: (UnsafeRawBufferPointer) -> Void) { body(globalBuffer) } +public func getArray() -> [UInt8] { + return [1, 2, 3] +} + +public func sumAllByteArrayElements(actuallyAnArray: UnsafeRawPointer, count: Int) -> Int { + let bufferPointer = UnsafeRawBufferPointer(start: actuallyAnArray, count: count) + let array = Array(bufferPointer) + return Int(array.reduce(0, { partialResult, element in partialResult + element })) +} + +public func sumAllByteArrayElements(array: [UInt8]) -> Int { + return Int(array.reduce(0, { partialResult, element in partialResult + element })) +} + +public func withArray(body: ([UInt8]) -> Void) { + body([1, 2, 3]) +} + public func globalReceiveSomeDataProtocol(data: some DataProtocol) -> Int { p(Array(data).description) return data.count diff --git a/Samples/SwiftJavaExtractFFMSampleApp/src/test/java/com/example/swift/WithBufferTest.java b/Samples/SwiftJavaExtractFFMSampleApp/src/test/java/com/example/swift/WithBufferTest.java index 86069aae..54206423 100644 --- a/Samples/SwiftJavaExtractFFMSampleApp/src/test/java/com/example/swift/WithBufferTest.java +++ b/Samples/SwiftJavaExtractFFMSampleApp/src/test/java/com/example/swift/WithBufferTest.java @@ -20,7 +20,10 @@ import static org.junit.jupiter.api.Assertions.*; +import java.lang.foreign.ValueLayout; +import java.util.Arrays; import java.util.concurrent.atomic.AtomicLong; +import java.util.stream.IntStream; public class WithBufferTest { @Test @@ -33,4 +36,25 @@ void test_withBuffer() { assertEquals(124, bufferSize.get()); } + + @Test + void test_sumAllByteArrayElements_throughMemorySegment() { + byte[] bytes = new byte[124]; + Arrays.fill(bytes, (byte) 1); + + try (var arena = AllocatingSwiftArena.ofConfined()) { + // NOTE: We cannot use MemorySegment.ofArray because that creates a HEAP backed segment and therefore cannot pass into native: + // java.lang.IllegalArgumentException: Heap segment not allowed: MemorySegment{ kind: heap, heapBase: [B@5b6ec132, address: 0x0, byteSize: 124 } + // MemorySegment bytesSegment = MemorySegment.ofArray(bytes); // NO COPY (!) + // MySwiftLibrary.sumAllByteArrayElements(bytesSegment, bytes.length); + + var bytesCopy = arena.allocateFrom(ValueLayout.JAVA_BYTE, bytes); + var swiftSideSum = MySwiftLibrary.sumAllByteArrayElements(bytesCopy, bytes.length); + + System.out.println("swiftSideSum = " + swiftSideSum); + + int javaSideSum = IntStream.range(0, bytes.length).map(i -> bytes[i]).sum(); + assertEquals(javaSideSum, swiftSideSum); + } + } }