Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ void protocolMethod() {
void protocolClassMethod() {
try (var arena = SwiftArena.ofConfined()) {
ProtocolA proto1 = ConcreteProtocolAB.init(10, 5, arena);
assertEquals(10, proto1.makeClass().getX());
assertEquals(10, proto1.makeClass(arena).getX());
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ extension JNISwift2JavaGenerator {
let protocolType: SwiftNominalType
let functions: [Function]
let variables: [Variable]
let importedType: ImportedNominalType

var wrapperName: String {
protocolType.nominalTypeDecl.javaInterfaceSwiftProtocolWrapperName
Expand Down Expand Up @@ -99,7 +100,8 @@ extension JNISwift2JavaGenerator {
return JavaInterfaceSwiftWrapper(
protocolType: SwiftNominalType(nominalTypeDecl: type.swiftNominal),
functions: functions,
variables: variables
variables: variables,
importedType: type
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -531,17 +531,9 @@ extension JNISwift2JavaGenerator {
// If we have enabled javaCallbacks we must emit default
// arena methods for protocols, as this is what
// Swift will call into, when you call a interface from Swift.
let shouldGenerateGlobalArenaVariation: Bool
let shouldGenerateGlobalArenaVariation = config.effectiveMemoryManagementMode.requiresGlobalArena && translatedSignature.requiresSwiftArena
let isParentProtocol = importedFunc?.parentType?.asNominalType?.isProtocol ?? false

if config.effectiveMemoryManagementMode.requiresGlobalArena && translatedSignature.requiresSwiftArena {
shouldGenerateGlobalArenaVariation = true
} else if isParentProtocol, translatedSignature.requiresSwiftArena, config.effectiveEnableJavaCallbacks {
shouldGenerateGlobalArenaVariation = true
} else {
shouldGenerateGlobalArenaVariation = false
}

if shouldGenerateGlobalArenaVariation {
if let importedFunc {
printDeclDocumentation(&printer, importedFunc)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1317,5 +1317,9 @@ extension JNISwift2JavaGenerator {

// FIXME: Remove once we support protocol variables
case protocolVariablesNotSupported

/// We cannot generate interface wrappers for
/// protocols that we unable to be jextracted.
case protocolWasNotExtracted
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -124,9 +124,9 @@ extension JNISwift2JavaGenerator {
printer.print("var \(translatedWrapper.javaInterfaceVariableName): \(translatedWrapper.javaInterfaceName) { get }")
}
printer.println()
printer.printBraceBlock("extension \(translatedWrapper.wrapperName)") { printer in
try printer.printBraceBlock("extension \(translatedWrapper.wrapperName)") { printer in
for function in translatedWrapper.functions {
printInterfaceWrapperFunctionImpl(&printer, function, inside: translatedWrapper)
try printInterfaceWrapperFunctionImpl(&printer, function, inside: translatedWrapper)
printer.println()
}

Expand All @@ -142,16 +142,29 @@ extension JNISwift2JavaGenerator {
_ printer: inout CodePrinter,
_ function: JavaInterfaceSwiftWrapper.Function,
inside wrapper: JavaInterfaceSwiftWrapper
) {
) throws {
guard let protocolMethod = wrapper.importedType.methods.first(where: { $0.functionSignature == function.originalFunctionSignature }) else {
fatalError("Failed to find protocol method")
}
guard let translatedDecl = self.translatedDecl(for: protocolMethod) else {
throw JavaTranslationError.protocolWasNotExtracted
}

printer.printBraceBlock(function.swiftDecl.signatureString) { printer in
let upcallArguments = zip(
var upcallArguments = zip(
function.originalFunctionSignature.parameters,
function.parameterConversions
).map { param, conversion in
// Wrap-java does not extract parameter names, so no labels
conversion.render(&printer, param.parameterName!)
}

// If the underlying translated method requires
// a SwiftArena, we pass in the global arena
if translatedDecl.translatedFunctionSignature.requiresSwiftArena {
upcallArguments.append("JNI.shared.globalArena")
}

let tryClause = function.originalFunctionSignature.isThrowing ? "try " : ""
let javaUpcall = "\(tryClause)\(wrapper.javaInterfaceVariableName).\(function.swiftFunctionName)(\(upcallArguments.joined(separator: ", ")))"

Expand Down
23 changes: 19 additions & 4 deletions Sources/SwiftJavaRuntimeSupport/JNI.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,28 @@
import SwiftJava
import CSwiftJavaJNI

final class JNI {
static var shared: JNI!
public final class JNI {
public fileprivate(set) static var shared: JNI!

let applicationClassLoader: JavaClassLoader
public let applicationClassLoader: JavaClassLoader
public let globalArena: JavaSwiftArena

init(fromVM javaVM: JavaVirtualMachine) {
self.applicationClassLoader = try! JavaClass<JavaThread>(environment: javaVM.environment()).currentThread().getContextClassLoader()
let environment = try! javaVM.environment()

self.applicationClassLoader = try! JavaClass<JavaThread>(environment: environment).currentThread().getContextClassLoader()

// Find global arena
let swiftMemoryClass = environment.interface.FindClass(environment, "org/swift/swiftkit/core/SwiftMemoryManagement")!
let arenaFieldID = environment.interface.GetStaticFieldID(
environment,
swiftMemoryClass,
"GLOBAL_SWIFT_JAVA_ARENA",
"Lorg/swift/swiftkit/core/SwiftArena;"
)
let localObject = environment.interface.GetStaticObjectField(environment, swiftMemoryClass, arenaFieldID)!
self.globalArena = JavaSwiftArena(javaThis: localObject, environment: environment)
environment.interface.DeleteLocalRef(environment, localObject)
}
}

Expand Down
18 changes: 18 additions & 0 deletions Sources/SwiftJavaRuntimeSupport/generated/JavaSwiftArena.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2024 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 SwiftJava

@JavaInterface("org.swift.swiftkit.core.SwiftArena")
public struct JavaSwiftArena {}
6 changes: 6 additions & 0 deletions Sources/SwiftJavaRuntimeSupport/swift-java.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"classes" : {
"org.swift.swiftkit.core.JNISwiftInstance" : "JavaJNISwiftInstance",
"org.swift.swiftkit.core.SwiftArena" : "JavaSwiftArena"
}
}
24 changes: 1 addition & 23 deletions Tests/JExtractSwiftTests/JNI/JNIProtocolTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -70,28 +70,6 @@ struct JNIProtocolTests {
])
}

@Test
func emitsDefault() throws {
try assertOutput(
input: source,
config: config,
.jni, .java,
detectChunkByInitialLines: 1,
expectedChunks: [
"""
public interface SomeProtocol {
...
public default SomeClass withObject(SomeClass c) {
return withObject(c, SwiftMemoryManagement.GLOBAL_SWIFT_JAVA_ARENA);
}
...
public SomeClass withObject(SomeClass c, SwiftArena swiftArena$);
...
}
"""
])
}

@Test
func generatesJavaClassWithExtends() throws {
try assertOutput(
Expand Down Expand Up @@ -329,7 +307,7 @@ struct JNIProtocolTests {
let cClass = try! JavaClass<JavaSomeClass>(environment: JavaVirtualMachine.shared().environment())
let cPointer = UnsafeMutablePointer<SomeClass>.allocate(capacity: 1)
cPointer.initialize(to: c)
guard let unwrapped$ = _javaSomeProtocolInterface.withObject(cClass.wrapMemoryAddressUnsafe(Int64(Int(bitPattern: cPointer)))) else {
guard let unwrapped$ = _javaSomeProtocolInterface.withObject(cClass.wrapMemoryAddressUnsafe(Int64(Int(bitPattern: cPointer))), JNI.shared.globalArena) else {
fatalError("Upcall to withObject unexpectedly returned nil")
}
let result$MemoryAddress$ = unwrapped$.as(JavaJNISwiftInstance.self)!.memoryAddress()
Expand Down
Loading