Skip to content

Simple step towards importing structs, add initializeWithCopy funcs #206

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jan 15, 2025
Merged
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//

public class MySwiftClass {

public var len: Int
public var cap: Int

public init(len: Int, cap: Int) {
self.len = len
self.cap = cap

p("\(MySwiftClass.self).len = \(self.len)")
p("\(MySwiftClass.self).cap = \(self.cap)")
let addr = unsafeBitCast(self, to: UInt64.self)
p("initializer done, self = 0x\(String(addr, radix: 16, uppercase: true))")
}

deinit {
let addr = unsafeBitCast(self, to: UInt64.self)
p("Deinit, self = 0x\(String(addr, radix: 16, uppercase: true))")
}

public var counter: Int32 = 0

public func voidMethod() {
p("")
}

public func takeIntMethod(i: Int) {
p("i:\(i)")
}

public func echoIntMethod(i: Int) -> Int {
p("i:\(i)")
return i
}

public func makeIntMethod() -> Int {
p("make int -> 12")
return 12
}

public func makeRandomIntMethod() -> Int {
return Int.random(in: 1..<256)
}
}
Original file line number Diff line number Diff line change
@@ -47,68 +47,18 @@ public func globalCallMeRunnable(run: () -> ()) {
run()
}

public class MySwiftClass {

public var len: Int
public var cap: Int

public init(len: Int, cap: Int) {
self.len = len
self.cap = cap

p("\(MySwiftClass.self).len = \(self.len)")
p("\(MySwiftClass.self).cap = \(self.cap)")
let addr = unsafeBitCast(self, to: UInt64.self)
p("initializer done, self = 0x\(String(addr, radix: 16, uppercase: true))")
}

deinit {
let addr = unsafeBitCast(self, to: UInt64.self)
p("Deinit, self = 0x\(String(addr, radix: 16, uppercase: true))")
}

public var counter: Int32 = 0

public func voidMethod() {
p("")
}

public func takeIntMethod(i: Int) {
p("i:\(i)")
}

public func echoIntMethod(i: Int) -> Int {
p("i:\(i)")
return i
}

public func makeIntMethod() -> Int {
p("make int -> 12")
return 12
}

public func writeString(string: String) -> Int {
p("echo -> \(string)")
return string.count
}

public func makeRandomIntMethod() -> Int {
return Int.random(in: 1..<256)
}
}

// ==== Internal helpers

private func p(_ msg: String, file: String = #fileID, line: UInt = #line, function: String = #function) {
// print("[swift][\(file):\(line)](\(function)) \(msg)")
// fflush(stdout)
func p(_ msg: String, file: String = #fileID, line: UInt = #line, function: String = #function) {
print("[swift][\(file):\(line)](\(function)) \(msg)")
fflush(stdout)
}

#if os(Linux)
// FIXME: why do we need this workaround?
@_silgen_name("_objc_autoreleaseReturnValue")
public func _objc_autoreleaseReturnValue(a: Any) {}
#if os(Linux)
// FIXME: why do we need this workaround?
@_silgen_name("_objc_autoreleaseReturnValue")
public func _objc_autoreleaseReturnValue(a: Any) {}

@_silgen_name("objc_autoreleaseReturnValue")
public func objc_autoreleaseReturnValue(a: Any) {}
#endif
@_silgen_name("objc_autoreleaseReturnValue")
public func objc_autoreleaseReturnValue(a: Any) {}
#endif
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//

public struct MySwiftStruct {

public var number: Int

public init(number: Int) {
self.number = number
}

public func voidMethod() {
p("")
}

public func takeIntMethod(i: Int) {
p("i:\(i)")
}

public func echoIntMethod(i: Int) -> Int {
p("i:\(i)")
return i
}

public func makeIntMethod() -> Int {
p("make int -> 12")
return 12
}

public func makeRandomIntMethod() -> Int {
return Int.random(in: 1..<256)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//

#if os(Linux)
// FIXME: why do we need this workaround?
@_silgen_name("_objc_autoreleaseReturnValue")
public func _objc_autoreleaseReturnValue(a: Any) {}

@_silgen_name("objc_autoreleaseReturnValue")
public func objc_autoreleaseReturnValue(a: Any) {}
#endif
Original file line number Diff line number Diff line change
@@ -52,6 +52,9 @@ static void examples() {

obj.voidMethod();
obj.takeIntMethod(42);

MySwiftStruct swiftValue = new MySwiftStruct(12);

}

System.out.println("DONE.");
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//

package com.example.swift;

import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.swift.swiftkit.SwiftArena;
import org.swift.swiftkit.SwiftKit;

import java.io.File;
import java.util.stream.Stream;

import static org.junit.jupiter.api.Assertions.assertEquals;

public class MySwiftStructTest {

@Test
void test_MySwiftClass_voidMethod() {
try (var arena = SwiftArena.ofConfined()) {
MySwiftStruct o = new MySwiftStruct(12);
// o.voidMethod();
}
}

}
Original file line number Diff line number Diff line change
@@ -70,6 +70,10 @@ public void arena_releaseClassOnClose_class_leaked() {
// The message should point out which objects "leaked":
assertTrue(ex.getMessage().contains(memorySegmentDescription));
}
}

@Test
public void arena_initializeWithCopy_struct() {

}
}
11 changes: 1 addition & 10 deletions Sources/ExampleSwiftLibrary/MySwiftLibrary.swift
Original file line number Diff line number Diff line change
@@ -97,16 +97,7 @@ public func _getTypeByMangledNameInEnvironment(

// ==== Internal helpers

private func p(_ msg: String, file: String = #fileID, line: UInt = #line, function: String = #function) {
func p(_ msg: String, file: String = #fileID, line: UInt = #line, function: String = #function) {
print("[swift][\(file):\(line)](\(function)) \(msg)")
fflush(stdout)
}

#if os(Linux)
// FIXME: why do we need this workaround?
@_silgen_name("_objc_autoreleaseReturnValue")
public func _objc_autoreleaseReturnValue(a: Any) {}

@_silgen_name("objc_autoreleaseReturnValue")
public func objc_autoreleaseReturnValue(a: Any) {}
#endif
9 changes: 9 additions & 0 deletions Sources/JExtractSwift/ImportedDecls.swift
Original file line number Diff line number Diff line change
@@ -49,6 +49,15 @@ public struct ImportedNominalType: ImportedDecl {
javaType: javaType
)
}

public var isReferenceType: Bool {
switch self.kind {
case .class, .actor:
return true
case .enum, .struct:
return false
}
}

/// The Java class name without the package.
public var javaClassName: String {
13 changes: 10 additions & 3 deletions Sources/JExtractSwift/Swift2JavaTranslator+Printing.swift
Original file line number Diff line number Diff line change
@@ -194,7 +194,7 @@ extension Swift2JavaTranslator {
printPackage(&printer)
printImports(&printer)

printClass(&printer, decl) { printer in
printNominal(&printer, decl) { printer in
// Prepare type metadata, we're going to need these when invoking e.g. initializers so cache them in a static.
// We call into source swift-java source generated accessors which give us the type of the Swift object:
// TODO: seems we no longer need the mangled name per se, so avoiding such constant and downcall
@@ -277,10 +277,17 @@ extension Swift2JavaTranslator {
printer.print("")
}

public func printClass(
public func printNominal(
_ printer: inout CodePrinter, _ decl: ImportedNominalType, body: (inout CodePrinter) -> Void
) {
printer.printTypeDecl("public final class \(decl.javaClassName) implements SwiftHeapObject") {
let parentProtocol: String
if decl.isReferenceType {
parentProtocol = "SwiftHeapObject"
} else {
parentProtocol = "SwiftValue"
}

printer.printTypeDecl("public final class \(decl.javaClassName) implements \(parentProtocol)") {
printer in
// ==== Storage of the class
printClassSelfProperty(&printer, decl)
18 changes: 18 additions & 0 deletions Sources/JExtractSwift/Swift2JavaVisitor.swift
Original file line number Diff line number Diff line change
@@ -40,6 +40,7 @@ final class Swift2JavaVisitor: SyntaxVisitor {
}

override func visit(_ node: ClassDeclSyntax) -> SyntaxVisitorContinueKind {
log.debug("Visit \(node.kind): \(node)")
guard let importedNominalType = translator.importedNominalType(node) else {
return .skipChildren
}
@@ -54,7 +55,24 @@ final class Swift2JavaVisitor: SyntaxVisitor {
currentTypeName = nil
}
}

override func visit(_ node: StructDeclSyntax) -> SyntaxVisitorContinueKind {
log.debug("Visit \(node.kind): \(node)")
guard let importedNominalType = translator.importedNominalType(node) else {
return .skipChildren
}

currentTypeName = importedNominalType.swiftTypeName
return .visitChildren
}

override func visitPost(_ node: StructDeclSyntax) {
if currentTypeName != nil {
log.debug("Completed import: \(node.kind) \(node.name)")
currentTypeName = nil
}
}

override func visit(_ node: ExtensionDeclSyntax) -> SyntaxVisitorContinueKind {
// Resolve the extended type of the extension as an imported nominal, and
// recurse if we found it.
Original file line number Diff line number Diff line change
@@ -36,7 +36,8 @@ public ConfinedSwiftMemorySession(Thread owner) {

public void checkValid() throws RuntimeException {
if (this.owner != null && this.owner != Thread.currentThread()) {
throw new WrongThreadException("ConfinedSwift arena is confined to %s but was closed from %s!".formatted(this.owner, Thread.currentThread()));
throw new WrongThreadException("ConfinedSwift arena is confined to %s but was closed from %s!"
.formatted(this.owner, Thread.currentThread()));
} else if (this.state.get() < ACTIVE) {
throw new RuntimeException("SwiftArena is already closed!");
}
Loading