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
9 changes: 2 additions & 7 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ let package = Package(
.library(
name: "SwiftJava",
type: .dynamic,
targets: ["SwiftJava"]
targets: ["SwiftJava", "SwiftJavaRuntimeSupport"]
),

.library(
Expand Down Expand Up @@ -226,12 +226,6 @@ let package = Package(
]
),

// Support library written in Swift for SwiftKit "Java"
.library(
name: "SwiftJavaRuntimeSupport",
targets: ["SwiftJavaRuntimeSupport"]
),

.library(
name: "SwiftRuntimeFunctions",
type: .dynamic,
Expand Down Expand Up @@ -311,6 +305,7 @@ let package = Package(
exclude: ["swift-java.config"],
swiftSettings: [
.swiftLanguageMode(.v5),
.enableUpcomingFeature("ImplicitOpenExistentials"),
Copy link
Collaborator

Choose a reason for hiding this comment

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

👍

.unsafeFlags(
["-I\(javaIncludePath)", "-I\(javaPlatformIncludePath)"],
.when(platforms: [.macOS, .linux, .windows])
Expand Down
1 change: 0 additions & 1 deletion Samples/SwiftJavaExtractJNISampleApp/Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,6 @@ let package = Package(
dependencies: [
.product(name: "SwiftJava", package: "swift-java"),
.product(name: "CSwiftJavaJNI", package: "swift-java"),
.product(name: "SwiftJavaRuntimeSupport", package: "swift-java"),
],
exclude: [
"swift-java.config"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2026 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
//
//===----------------------------------------------------------------------===//

public struct BasicStruct {
public var value: Int
public init(value: Int) {
self.value = value
}
}

public struct GenericStruct<T> {
public var value: Int
public init(value: Int) {
self.value = value
}
}

public func makeGenericStruct(value: Int) -> GenericStruct<Int> {
GenericStruct(value: value)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2026 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.openjdk.jmh.annotations.*;
import org.openjdk.jmh.infra.Blackhole;
import org.swift.swiftkit.core.ClosableSwiftArena;
import org.swift.swiftkit.core.ConfinedSwiftMemorySession;
import org.swift.swiftkit.core.SwiftArena;

import java.util.concurrent.TimeUnit;

@BenchmarkMode(Mode.AverageTime)
@Warmup(iterations = 5, time = 200, timeUnit = TimeUnit.MILLISECONDS)
@Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@Fork(value = 3, jvmArgsAppend = { "--enable-native-access=ALL-UNNAMED" })
public class GenericBenchmark {
@State(Scope.Benchmark)
public static class BenchmarkState {
ClosableSwiftArena arena;
BasicStruct basicStruct;
GenericStruct genericStruct;

@Setup(Level.Trial)
public void beforeAll() {
arena = SwiftArena.ofConfined();
basicStruct = BasicStruct.init(42, arena);
genericStruct = MySwiftLibrary.makeGenericStruct(42, arena);
}

@TearDown(Level.Trial)
public void afterAll() {
arena.close();
}
}

@Benchmark
public long basicStruct_basicGetter(BenchmarkState state, Blackhole bh) {
return state.basicStruct.getValue();
}

@Benchmark
public long genericStruct_basicGetter(BenchmarkState state, Blackhole bh) {
return state.genericStruct.getValue();
}

@Benchmark
public String basicStruct_toString(BenchmarkState state, Blackhole bh) {
// toString is internally implemented as a generic method in Swift
return state.basicStruct.toString();
}

@Benchmark
public String genericStruct_toString(BenchmarkState state, Blackhole bh) {
// toString is internally implemented as a generic method in Swift
return state.genericStruct.toString();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -993,14 +993,6 @@ extension LoweredFunctionSignature {
.joined(separator: ", ")
resultExpr = "\(callee)(\(raw: arguments))"

case .synthesizedFunction(let function):
switch function {
case .toString:
resultExpr = "String(describing: \(callee))"
case .toDebugString:
resultExpr = "String(reflecting: \(callee))"
}

case .getter:
assert(paramExprs.isEmpty)
resultExpr = callee
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ extension FFMSwift2JavaGenerator {
switch decl.apiKind {
case .getter, .subscriptGetter: decl.javaGetterName
case .setter, .subscriptSetter: decl.javaSetterName
case .function, .synthesizedFunction, .initializer, .enumCase: decl.name
case .function, .initializer, .enumCase: decl.name
}

// Signature.
Expand Down
8 changes: 1 addition & 7 deletions Sources/JExtractSwiftLib/ImportedDecls.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,8 @@ import SwiftSyntax
/// Any imported (Swift) declaration
protocol ImportedDecl: AnyObject {}

package enum SynthesizedAPI: Equatable {
case toString
case toDebugString
}

package enum SwiftAPIKind: Equatable {
case function
case synthesizedFunction(SynthesizedAPI)
case initializer
case getter
case setter
Expand Down Expand Up @@ -178,7 +172,7 @@ public final class ImportedFunc: ImportedDecl, CustomStringConvertible {
case .getter: "getter:"
case .setter: "setter:"
case .enumCase: "case:"
case .function, .synthesizedFunction, .initializer: ""
case .function, .initializer: ""
case .subscriptGetter: "subscriptGetter:"
case .subscriptSetter: "subscriptSetter:"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,20 @@ extension JNISwift2JavaGenerator {

printTypeMetadataAddressFunction(&printer, decl)
printer.println()

printer.print(
"""
public String toString() {
return SwiftObjects.toString(this.$memoryAddress(), this.$typeMetadataAddress());
}

public String toDebugString() {
return SwiftObjects.toDebugString(this.$memoryAddress(), this.$typeMetadataAddress());
}
"""
)
printer.println()

printDestroyFunction(&printer, decl)
}
}
Expand Down Expand Up @@ -394,17 +408,9 @@ extension JNISwift2JavaGenerator {
)
}

// TODO: Consider whether all of these "utility" functions can be printed using our existing printing logic.
if decl.swiftNominal.isGeneric {
printer.printBraceBlock("public Discriminator getDiscriminator()") { printer in
printer.print("return Discriminator.values()[$getDiscriminator(this.$memoryAddress(), this.$typeMetadataAddress())];")
}
printer.print("private static native int $getDiscriminator(long selfPointer, long selfTypePointer);")
} else {
printer.printBraceBlock("public Discriminator getDiscriminator()") { printer in
printer.print("return Discriminator.values()[$getDiscriminator(this.$memoryAddress())];")
}
printer.print("private static native int $getDiscriminator(long selfPointer);")
printer.printBraceBlock("public Discriminator getDiscriminator()") { printer in
printer.print("var raw = SwiftObjects.getRawDiscriminator(this.$memoryAddress(), this.$typeMetadataAddress());")
printer.print("return Discriminator.values()[raw];")
}
}

Expand Down Expand Up @@ -717,42 +723,25 @@ extension JNISwift2JavaGenerator {
}
} else {
printer.print("private static native long $typeMetadataAddressDowncall();")

let funcName = "$typeMetadataAddress"
printer.print("@Override")
printer.printBraceBlock("public long $typeMetadataAddress()") { printer in
printer.print(
"""
long self$ = this.$memoryAddress();
if (CallTraces.TRACE_DOWNCALLS) {
CallTraces.traceDowncall("\(type.swiftNominal.name).\(funcName)",
"this", this,
"self", self$);
}
"""
)
// INFO: We are omitting `CallTraces.traceDowncall` here.
// It internally calls `toString`, which in turn calls `$typeMetadataAddress`, creating an infinite loop.
printer.print("return \(type.swiftNominal.name).$typeMetadataAddressDowncall();")
}
}
}

/// Prints the destroy function for a `JNISwiftInstance`
private func printDestroyFunction(_ printer: inout CodePrinter, _ type: ImportedNominalType) {
let isGeneric = type.swiftNominal.isGeneric
if isGeneric {
printer.print("private static native void $destroy(long selfPointer, long selfTypePointer);")
} else {
printer.print("private static native void $destroy(long selfPointer);")
}

let funcName = "$createDestroyFunction"
printer.print("@Override")
printer.printBraceBlock("public Runnable \(funcName)()") { printer in
printer.print("long self$ = this.$memoryAddress();")
if isGeneric {
printer.print("long selfType$ = this.$typeMetadataAddress();")
if type.swiftNominal.isGeneric {
printer.print(
"""
long selfType$ = this.$typeMetadataAddress();
if (CallTraces.TRACE_DOWNCALLS) {
CallTraces.traceDowncall("\(type.swiftNominal.name).\(funcName)",
"this", this,
Expand All @@ -765,7 +754,7 @@ extension JNISwift2JavaGenerator {
if (CallTraces.TRACE_DOWNCALLS) {
CallTraces.traceDowncall("\(type.swiftNominal.name).$destroy", "self", self$, "selfType", selfType$);
}
\(type.swiftNominal.name).$destroy(self$, selfType$);
SwiftObjects.destroy(self$, selfType$);
}
};
"""
Expand All @@ -784,7 +773,7 @@ extension JNISwift2JavaGenerator {
if (CallTraces.TRACE_DOWNCALLS) {
CallTraces.traceDowncall("\(type.swiftNominal.name).$destroy", "self", self$);
}
\(type.swiftNominal.name).$destroy(self$);
SwiftObjects.destroy(self$, selfType$);
}
};
"""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ extension JNISwift2JavaGenerator {
switch decl.apiKind {
case .getter, .subscriptGetter: decl.javaGetterName
case .setter, .subscriptSetter: decl.javaSetterName
case .function, .synthesizedFunction, .initializer, .enumCase: decl.name
case .function, .initializer, .enumCase: decl.name
}

// Swift -> Java
Expand Down
Loading
Loading