Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
1 change: 1 addition & 0 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ let package = Package(
// ==== SwiftJava (i.e. calling Java directly Swift utilities)
.library(
name: "SwiftJava",
type: .dynamic,
targets: ["SwiftJava"]
),

Expand Down
4 changes: 3 additions & 1 deletion Samples/SwiftAndJavaJarSampleLib/Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,9 @@ let package = Package(
.target(
name: "MySwiftLibrary",
dependencies: [
.product(name: "SwiftRuntimeFunctions", package: "swift-java"),
.product(name: "SwiftJava", package: "swift-java"),
.product(name: "CSwiftJavaJNI", package: "swift-java"),
.product(name: "SwiftRuntimeFunctions", package: "swift-java")
],
exclude: [
"swift-java.config",
Expand Down
2 changes: 2 additions & 0 deletions Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,7 @@ extension FFMSwift2JavaGenerator {
private static final boolean INITIALIZED_LIBS = initializeLibs();
static boolean initializeLibs() {
System.loadLibrary(SwiftLibraries.LIB_NAME_SWIFT_CORE);
System.loadLibrary(SwiftLibraries.LIB_NAME_SWIFT_JAVA);
System.loadLibrary(SwiftLibraries.LIB_NAME_SWIFT_RUNTIME_FUNCTIONS);
System.loadLibrary(LIB_NAME);
return true;
Expand Down Expand Up @@ -345,6 +346,7 @@ extension FFMSwift2JavaGenerator {
private static SymbolLookup getSymbolLookup() {
if (SwiftLibraries.AUTO_LOAD_LIBS) {
System.loadLibrary(SwiftLibraries.LIB_NAME_SWIFT_CORE);
System.loadLibrary(SwiftLibraries.LIB_NAME_SWIFT_JAVA);
System.loadLibrary(SwiftLibraries.LIB_NAME_SWIFT_RUNTIME_FUNCTIONS);
System.loadLibrary(LIB_NAME);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ extension JNISwift2JavaGenerator {
static final String LIB_NAME = "\(swiftModuleName)";

static {
System.loadLibrary(SwiftLibraries.LIB_NAME_SWIFT_JAVA);
System.loadLibrary(LIB_NAME);
}
"""
Expand Down Expand Up @@ -169,6 +170,7 @@ extension JNISwift2JavaGenerator {
@SuppressWarnings("unused")
private static final boolean INITIALIZED_LIBS = initializeLibs();
static boolean initializeLibs() {
System.loadLibrary(SwiftLibraries.LIB_NAME_SWIFT_JAVA);
System.loadLibrary(LIB_NAME);
return true;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ extension JNISwift2JavaGenerator {
// If the underlying translated method requires
// a SwiftArena, we pass in the global arena
if translatedDecl.translatedFunctionSignature.requiresSwiftArena {
upcallArguments.append("JNI.shared.defaultAutoArena")
upcallArguments.append("JavaSwiftArena.defaultAutoArena")
}

let tryClause = function.originalFunctionSignature.isThrowing ? "try " : ""
Expand Down Expand Up @@ -201,8 +201,6 @@ extension JNISwift2JavaGenerator {
private func printGlobalSwiftThunkSources(_ printer: inout CodePrinter) throws {
printHeader(&printer)

printJNIOnLoad(&printer)

for decl in analysis.importedGlobalFuncs {
printSwiftFunctionThunk(&printer, decl)
printer.println()
Expand All @@ -214,18 +212,6 @@ extension JNISwift2JavaGenerator {
}
}

private func printJNIOnLoad(_ printer: inout CodePrinter) {
printer.print(
"""
@_cdecl("JNI_OnLoad")
func JNI_OnLoad(javaVM: JavaVMPointer, reserved: UnsafeMutableRawPointer) -> jint {
SwiftJavaRuntimeSupport._JNI_OnLoad(javaVM, reserved)
return JNI_VERSION_1_6
}
"""
)
}

private func printNominalTypeThunks(_ printer: inout CodePrinter, _ type: ImportedNominalType) throws {
printHeader(&printer)

Expand Down
51 changes: 34 additions & 17 deletions Sources/SwiftJava/AnyJavaObject.swift
Original file line number Diff line number Diff line change
Expand Up @@ -102,23 +102,41 @@ extension AnyJavaObject {
in environment: JNIEnvironment,
_ body: (jclass) throws -> Result
) throws -> Result {
let resolvedClass = try environment.translatingJNIExceptions {
environment.interface.FindClass(
environment,
fullJavaClassNameWithSlashes
)
}!
return try body(resolvedClass)
do {
let resolvedClass = try environment.translatingJNIExceptions {
environment.interface.FindClass(
environment,
fullJavaClassNameWithSlashes
)
}!
return try body(resolvedClass)
} catch {
// If we are in a Java environment where we have loaded
// SwiftJava dynamically, we have access to the application class loader
// so lets try that as as a fallback
if let applicationClassLoader = JNI.shared?.applicationClassLoader {
return try _withJNIClassFromCustomClassLoader(
applicationClassLoader,
in: environment
) { applicationLoadedClass in
return try body(applicationLoadedClass)
}
} else {
throw error
}
}
}

/// Retrieve the Java class for this type using a specific class loader.
private static func _withJNIClassFromCustomClassLoader<Result>(
_ classLoader: JavaClassLoader,
in environment: JNIEnvironment,
_ body: (jclass?) throws -> Result
_ body: (jclass) throws -> Result
) throws -> Result {
let resolvedClass = try? classLoader.findClass(fullJavaClassName)
return try body(resolvedClass?.javaThis)
let resolvedClass = try classLoader.findClass(fullJavaClassName)
// OK to force unwrap, as classLoader will throw ClassNotFoundException
// if the class cannot be found.
return try body(resolvedClass!.javaThis)
}

/// Retrieve the Java class for this type and execute body().
Expand All @@ -129,16 +147,15 @@ extension AnyJavaObject {
) throws -> Result {
if let AnyJavaObjectWithCustomClassLoader = self as? AnyJavaObjectWithCustomClassLoader.Type,
let customClassLoader = try AnyJavaObjectWithCustomClassLoader.getJavaClassLoader(in: environment) {
try _withJNIClassFromCustomClassLoader(customClassLoader, in: environment) { clazz in
guard let clazz else {
// If the custom class loader did not find the class
// let's look in the default class loader.
return try _withJNIClassFromDefaultClassLoader(in: environment, body)
do {
return try _withJNIClassFromCustomClassLoader(customClassLoader, in: environment) { clazz in
return try body(clazz)
}
return try body(clazz)
} catch {
return try _withJNIClassFromDefaultClassLoader(in: environment, body)
}
} else {
try _withJNIClassFromDefaultClassLoader(in: environment, body)
return try _withJNIClassFromDefaultClassLoader(in: environment, body)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
//
//===----------------------------------------------------------------------===//

import SwiftJava
import CSwiftJavaJNI

/// A type that represents the shared JNI environment
Expand All @@ -21,36 +20,28 @@ import CSwiftJavaJNI
/// This is initialized when the `JNI_OnLoad` is triggered,
/// which happens when you call `System.loadLibrary(...)`
/// from Java.
public final class JNI {
package final class JNI {
/// The shared JNI object, initialized by `JNI_OnLoad`
public fileprivate(set) static var shared: JNI!
///
/// This may be `nil` in the case where `SwiftJava` is not loaded as a dynamic lib
/// by the Java sources.
package fileprivate(set) static var shared: JNI?

/// The default application class loader
public let applicationClassLoader: JavaClassLoader

/// The default auto arena of SwiftKitCore
public let defaultAutoArena: JavaSwiftArena
package let applicationClassLoader: JavaClassLoader

init(fromVM javaVM: JavaVirtualMachine) {
// Update the global JavaVM
JavaVirtualMachine.sharedJVM.withLock {
$0 = javaVM
}
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,
"DEFAULT_SWIFT_JAVA_AUTO_ARENA",
JavaSwiftArena.mangledName
)
let localObject = environment.interface.GetStaticObjectField(environment, swiftMemoryClass, arenaFieldID)!
self.defaultAutoArena = JavaSwiftArena(javaThis: localObject, environment: environment)
environment.interface.DeleteLocalRef(environment, localObject)
}
}

// Called by generated code, and not automatically by Java.
public func _JNI_OnLoad(_ javaVM: JavaVMPointer, _ reserved: UnsafeMutableRawPointer) {
@_cdecl("JNI_OnLoad")
func SwiftJava_JNI_OnLoad(javaVM: JavaVMPointer, reserved: UnsafeMutableRawPointer) -> jint {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

don't we need this "lower", in a lib that does not have macros?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

note, we'll do that later

JNI.shared = JNI(fromVM: JavaVirtualMachine(adoptingJVM: javaVM))
return JNI_VERSION_1_6
}
2 changes: 1 addition & 1 deletion Sources/SwiftJava/JVM/JavaVirtualMachine.swift
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ extension JavaVirtualMachine {
/// TODO: If the use of the lock itself ends up being slow, we could
/// use an atomic here instead because our access pattern is fairly
/// simple.
private static let sharedJVM: LockedState<JavaVirtualMachine?> = .init(initialState: nil)
static let sharedJVM: LockedState<JavaVirtualMachine?> = .init(initialState: nil)

/// Access the shared Java Virtual Machine instance.
///
Expand Down
3 changes: 2 additions & 1 deletion Sources/SwiftJavaRuntimeSupport/_JNIMethodIDCache.swift
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,8 @@ public final class _JNIMethodIDCache: Sendable {
// Clear any ClassNotFound exceptions from FindClass
environment.interface.ExceptionClear(environment)

if let javaClass = try? JNI.shared.applicationClassLoader.loadClass(
// OK to force unwrap, we are in a jextract environment.
if let javaClass = try? JNI.shared!.applicationClassLoader.loadClass(
className.replacingOccurrences(of: "/", with: ".")
) {
clazz = javaClass.javaThis
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ public struct JavaJNISwiftInstance: AnyJavaObjectWithCustomClassLoader {
public func memoryAddress() -> Int64

public static func getJavaClassLoader(in environment: JNIEnvironment) throws -> JavaClassLoader! {
JNI.shared.applicationClassLoader
// OK to force unwrap, we are in a jextract environment.
JNI.shared!.applicationClassLoader
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,11 @@ import SwiftJava

@JavaInterface("org.swift.swiftkit.core.SwiftArena")
public struct JavaSwiftArena {}

extension JavaSwiftArena {
/// A cache for the default auto arena found in SwiftKitCore
public static internal(set) var defaultAutoArena: JavaSwiftArena = {
let swiftMemoryClass = try! JavaClass<SwiftJavaRuntimeSupport.JavaSwiftMemoryManagement>()
return swiftMemoryClass.defaultSwiftJavaAutoArena
}()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
//===----------------------------------------------------------------------===//
//
// 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

@JavaClass("org.swift.swiftkit.core.SwiftMemoryManagement")
public class JavaSwiftMemoryManagement: JavaObject {}

extension JavaClass<JavaSwiftMemoryManagement> {
@JavaStaticField("DEFAULT_SWIFT_JAVA_AUTO_ARENA", isFinal: true)
var defaultSwiftJavaAutoArena: JavaSwiftArena!
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ public final class SwiftLibraries {
public static final String LIB_NAME_SWIFT_CORE = "swiftCore";
public static final String LIB_NAME_SWIFT_CONCURRENCY = "swift_Concurrency";
public static final String LIB_NAME_SWIFT_RUNTIME_FUNCTIONS = "SwiftRuntimeFunctions";
public static final String LIB_NAME_SWIFT_JAVA = "SwiftJava";

/**
* Allows for configuration if jextracted types should automatically attempt to load swiftCore and the library type is from.
Expand All @@ -44,6 +45,7 @@ public final class SwiftLibraries {

public static boolean loadLibraries(boolean loadSwiftRuntimeFunctions) {
System.loadLibrary(LIB_NAME_SWIFT_CORE);
System.loadLibrary(LIB_NAME_SWIFT_JAVA);
if (loadSwiftRuntimeFunctions) {
System.loadLibrary(LIB_NAME_SWIFT_RUNTIME_FUNCTIONS);
}
Expand Down
1 change: 1 addition & 0 deletions Tests/JExtractSwiftTests/JNI/JNIClassTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ struct JNIClassTests {
@SuppressWarnings("unused")
private static final boolean INITIALIZED_LIBS = initializeLibs();
static boolean initializeLibs() {
System.loadLibrary(SwiftLibraries.LIB_NAME_SWIFT_JAVA);
System.loadLibrary(LIB_NAME);
return true;
}
Expand Down
1 change: 1 addition & 0 deletions Tests/JExtractSwiftTests/JNI/JNIEnumTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ struct JNIEnumTests {
@SuppressWarnings("unused")
private static final boolean INITIALIZED_LIBS = initializeLibs();
static boolean initializeLibs() {
System.loadLibrary(SwiftLibraries.LIB_NAME_SWIFT_JAVA);
System.loadLibrary(LIB_NAME);
return true;
}
Expand Down
1 change: 1 addition & 0 deletions Tests/JExtractSwiftTests/JNI/JNIModuleTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ struct JNIModuleTests {
static final String LIB_NAME = "SwiftModule";

static {
System.loadLibrary(SwiftLibraries.LIB_NAME_SWIFT_JAVA);
System.loadLibrary(LIB_NAME);
}
"""
Expand Down
2 changes: 1 addition & 1 deletion Tests/JExtractSwiftTests/JNI/JNIProtocolTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -307,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))), JNI.shared.defaultAutoArena) else {
guard let unwrapped$ = _javaSomeProtocolInterface.withObject(cClass.wrapMemoryAddressUnsafe(Int64(Int(bitPattern: cPointer))), JavaSwiftArena.defaultAutoArena) else {
fatalError("Upcall to withObject unexpectedly returned nil")
}
let result$MemoryAddress$ = unwrapped$.as(JavaJNISwiftInstance.self)!.memoryAddress()
Expand Down
1 change: 1 addition & 0 deletions Tests/JExtractSwiftTests/JNI/JNIStructTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ struct JNIStructTests {
@SuppressWarnings("unused")
private static final boolean INITIALIZED_LIBS = initializeLibs();
static boolean initializeLibs() {
System.loadLibrary(SwiftLibraries.LIB_NAME_SWIFT_JAVA);
System.loadLibrary(LIB_NAME);
return true;
}
Expand Down
Loading