From 7079f05f59dd39501c10d6bc12a473083633bc06 Mon Sep 17 00:00:00 2001 From: Amr Hesham Date: Mon, 13 Jul 2026 19:26:08 +0200 Subject: [PATCH 1/3] jextract: Organize java known functional interfaces --- ...t2JavaGenerator+JavaBindingsPrinting.swift | 22 ++++++------- ...wift2JavaGenerator+NativeTranslation.swift | 2 +- .../KnownFunctionalInterfaces.swift | 31 +++++++++++++++++++ 3 files changed, 41 insertions(+), 14 deletions(-) create mode 100644 Sources/JExtractSwiftLib/KnownFunctionalInterfaces.swift diff --git a/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+JavaBindingsPrinting.swift b/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+JavaBindingsPrinting.swift index 37ce8ce9c..47854ee44 100644 --- a/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+JavaBindingsPrinting.swift +++ b/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+JavaBindingsPrinting.swift @@ -255,21 +255,17 @@ extension FFMSwift2JavaGenerator { } printFunctionDescriptorDefinition(&printer, cResultType, cParams) - if cParameterTypes.isEmpty && cResultType.isVoid { - printer.print( - """ - private static final MethodHandle HANDLE = SwiftRuntime.upcallHandle(java.lang.Runnable.class, "run", DESC); - private static MemorySegment toUpcallStub(java.lang.Runnable fi, Arena arena) { - return Linker.nativeLinker().upcallStub(HANDLE.bindTo(fi), DESC, arena); - } - """ - ) - return - } + let (interfaceName, methodName) = + if cParameterTypes.isEmpty && cResultType.isVoid { + (KnownFunctionalInterface.runnable.javaType.description, KnownFunctionalInterface.runnable.method) + } else { + ("Function", "apply") + } + printer.print( """ - private static final MethodHandle HANDLE = SwiftRuntime.upcallHandle(Function.class, "apply", DESC); - private static MemorySegment toUpcallStub(Function fi, Arena arena) { + private static final MethodHandle HANDLE = SwiftRuntime.upcallHandle(\(interfaceName).class, "\(methodName)", DESC); + private static MemorySegment toUpcallStub(\(interfaceName) fi, Arena arena) { return Linker.nativeLinker().upcallStub(HANDLE.bindTo(fi), DESC, arena); } """ diff --git a/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+NativeTranslation.swift b/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+NativeTranslation.swift index f3fa65512..7e281f8ea 100644 --- a/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+NativeTranslation.swift +++ b/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+NativeTranslation.swift @@ -1691,7 +1691,7 @@ extension JNISwift2JavaGenerator { let methodName = if parameters.isEmpty && nativeResult.javaType.isVoid { - "run" + KnownFunctionalInterface.runnable.method } else { "apply" } diff --git a/Sources/JExtractSwiftLib/KnownFunctionalInterfaces.swift b/Sources/JExtractSwiftLib/KnownFunctionalInterfaces.swift new file mode 100644 index 000000000..54d434b50 --- /dev/null +++ b/Sources/JExtractSwiftLib/KnownFunctionalInterfaces.swift @@ -0,0 +1,31 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +import SwiftJavaJNICore + +enum KnownFunctionalInterface { + case runnable + + var javaType: JavaType { + switch self { + case .runnable: return JavaType.javaLangRunnable + } + } + + var method: String { + switch self { + case .runnable: return "run" + } + } +} From f2c1a8140f4db3249c07b0cb834445b2e8d4b955 Mon Sep 17 00:00:00 2001 From: Amr Hesham Date: Tue, 14 Jul 2026 17:15:30 +0200 Subject: [PATCH 2/3] Address code review comments --- .../FFMSwift2JavaGenerator+JavaBindingsPrinting.swift | 4 ++-- .../JNI/JNISwift2JavaGenerator+NativeTranslation.swift | 5 +++-- Sources/JExtractSwiftLib/KnownFunctionalInterfaces.swift | 9 +++++++++ 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+JavaBindingsPrinting.swift b/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+JavaBindingsPrinting.swift index 47854ee44..b26928593 100644 --- a/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+JavaBindingsPrinting.swift +++ b/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+JavaBindingsPrinting.swift @@ -256,8 +256,8 @@ extension FFMSwift2JavaGenerator { printFunctionDescriptorDefinition(&printer, cResultType, cParams) let (interfaceName, methodName) = - if cParameterTypes.isEmpty && cResultType.isVoid { - (KnownFunctionalInterface.runnable.javaType.description, KnownFunctionalInterface.runnable.method) + if let known = KnownFunctionalInterface(cParameterTypes.map { $0.javaType }, cResultType.javaType) { + (known.javaType.description, known.method) } else { ("Function", "apply") } diff --git a/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+NativeTranslation.swift b/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+NativeTranslation.swift index 7e281f8ea..7474b8373 100644 --- a/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+NativeTranslation.swift +++ b/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+NativeTranslation.swift @@ -1689,9 +1689,10 @@ extension JNISwift2JavaGenerator { $0.conversion.render(&printer, $0.parameters.first!.name) } + let methodName = - if parameters.isEmpty && nativeResult.javaType.isVoid { - KnownFunctionalInterface.runnable.method + if let known = KnownFunctionalInterface(methodSignature.parameterTypes, methodSignature.resultType) { + known.method } else { "apply" } diff --git a/Sources/JExtractSwiftLib/KnownFunctionalInterfaces.swift b/Sources/JExtractSwiftLib/KnownFunctionalInterfaces.swift index 54d434b50..5b94745a6 100644 --- a/Sources/JExtractSwiftLib/KnownFunctionalInterfaces.swift +++ b/Sources/JExtractSwiftLib/KnownFunctionalInterfaces.swift @@ -17,6 +17,15 @@ import SwiftJavaJNICore enum KnownFunctionalInterface { case runnable + init?(_ parameters: [JavaType], _ result: JavaType) { + switch (parameters, result) { + case ([], .void): + self = .runnable + default: + return nil + } + } + var javaType: JavaType { switch self { case .runnable: return JavaType.javaLangRunnable From 0bfa7b245106b65e34d3c585993afc066f87e678 Mon Sep 17 00:00:00 2001 From: Konrad Malawski Date: Wed, 15 Jul 2026 12:08:46 +0900 Subject: [PATCH 3/3] minor change in how we express Known types --- ...t2JavaGenerator+JavaBindingsPrinting.swift | 2 +- ...wift2JavaGenerator+NativeTranslation.swift | 2 +- .../KnownFunctionalInterfaces.swift | 50 ++++++++++++------- 3 files changed, 34 insertions(+), 20 deletions(-) diff --git a/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+JavaBindingsPrinting.swift b/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+JavaBindingsPrinting.swift index b26928593..fc7d25620 100644 --- a/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+JavaBindingsPrinting.swift +++ b/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+JavaBindingsPrinting.swift @@ -256,7 +256,7 @@ extension FFMSwift2JavaGenerator { printFunctionDescriptorDefinition(&printer, cResultType, cParams) let (interfaceName, methodName) = - if let known = KnownFunctionalInterface(cParameterTypes.map { $0.javaType }, cResultType.javaType) { + if let known = KnownJavaFunctionalInterface.find(parameters: cParameterTypes, result: cResultType) { (known.javaType.description, known.method) } else { ("Function", "apply") diff --git a/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+NativeTranslation.swift b/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+NativeTranslation.swift index 7474b8373..8a54532c5 100644 --- a/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+NativeTranslation.swift +++ b/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+NativeTranslation.swift @@ -1691,7 +1691,7 @@ extension JNISwift2JavaGenerator { let methodName = - if let known = KnownFunctionalInterface(methodSignature.parameterTypes, methodSignature.resultType) { + if let known = KnownJavaFunctionalInterface.find(methodSignature) { known.method } else { "apply" diff --git a/Sources/JExtractSwiftLib/KnownFunctionalInterfaces.swift b/Sources/JExtractSwiftLib/KnownFunctionalInterfaces.swift index 5b94745a6..fb0c784b0 100644 --- a/Sources/JExtractSwiftLib/KnownFunctionalInterfaces.swift +++ b/Sources/JExtractSwiftLib/KnownFunctionalInterfaces.swift @@ -14,27 +14,41 @@ import SwiftJavaJNICore -enum KnownFunctionalInterface { - case runnable - - init?(_ parameters: [JavaType], _ result: JavaType) { - switch (parameters, result) { - case ([], .void): - self = .runnable - default: - return nil - } +/// Describes a known functional interface such as `Runnable.run()` and similar. +struct KnownJavaFunctionalInterface: Sendable { + let javaType: JavaType + let method: String + let parameters: [JavaType] + let result: JavaType + + static let runnable = KnownJavaFunctionalInterface( + JavaType.javaLangRunnable, + method: "run", + parameters: [], + result: .void + ) + + static let all: [KnownJavaFunctionalInterface] = [ + .runnable + ] + + static func find(parameters: [JavaType], result: JavaType) -> KnownJavaFunctionalInterface? { + all.first { $0.parameters == parameters && $0.result == result } } - var javaType: JavaType { - switch self { - case .runnable: return JavaType.javaLangRunnable - } + static func find(parameters: [CType], result: CType) -> KnownJavaFunctionalInterface? { + find(parameters: parameters.map(\.javaType), result: result.javaType) } - var method: String { - switch self { - case .runnable: return "run" - } + static func find(_ methodSignature: MethodSignature) -> KnownJavaFunctionalInterface? { + find(parameters: methodSignature.parameterTypes, result: methodSignature.resultType) } + + init(_ javaType: JavaType, method: String, parameters: [JavaType], result: JavaType) { + self.javaType = javaType + self.method = method + self.parameters = parameters + self.result = result + } + }