Skip to content

SwiftArena and invoking destroy on objects as arena is destroyed #67

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 18 commits into from
Oct 22, 2024
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
5 changes: 4 additions & 1 deletion .github/workflows/pull_request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,10 @@ jobs:
${{ runner.os }}-swiftpm-
# run the actual build
- name: Gradle build
run: ./gradlew build --info --no-daemon
run: |
./gradlew build -x test --no-daemon # skip tests
find .
./gradlew build --info --no-daemon

test-swift:
name: Swift tests (swift:${{ matrix.swift_version }} jdk:${{matrix.jdk_vendor}} os:${{ matrix.os_version }})
Expand Down
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ BuildLogic/out/
**/build/
lib/

# Ignore JVM crash logs
**/*.log

# Ignore package resolved
Package.resolved

Expand All @@ -27,3 +30,6 @@ Package.resolved

# Cache of project
.gradletasknamecache

# Ignore files generated by jextract, we always can re-generate them
*/**/*.java
2 changes: 1 addition & 1 deletion .licenseignore
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,12 @@ docker/*
**/docker-compose.yaml
**/docker/*
**/.dockerignore
JavaSwiftKitDemo/src/main/java/com/example/swift/generated/*
Makefile
**/Makefile
**/*.html
**/CMakeLists.txt
**/*.jar
**/generated/*.java
**/generated/*.swift
gradle/wrapper/gradle-wrapper.properties
gradlew
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,54 +19,36 @@
import com.example.swift.generated.MySwiftClass;

// Import javakit/swiftkit support libraries
import org.swift.swiftkit.SwiftArena;
import org.swift.swiftkit.SwiftKit;

import org.swift.swiftkit.SwiftValueWitnessTable;
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Moved some functionality out of SwiftKit, keeping it for things end users might wanna use.


import java.lang.foreign.*;
import java.util.List;


public class HelloJava2Swift {

public static void main(String[] args) {
boolean traceDowncalls = Boolean.getBoolean("jextract.trace.downcalls");
System.out.println("Property: jextract.trace.downcalls = " + traceDowncalls);

final var dylibNames = List.of(
"swiftCore",
"JavaKitExample"
);


System.out.println("Loading libraries...");

for (var lib : dylibNames) {
System.out.printf("Loading: %s... ", lib);
System.loadLibrary(lib);
System.out.println("ok.");
}
System.out.printf("java.library.path = %s\n", System.getProperty("java.library.path"));

examples();
}

static void examples() {
ExampleSwiftLibrary.helloWorld();
ExampleSwiftLibrary.helloWorld();

ExampleSwiftLibrary.globalTakeInt(1337);
ExampleSwiftLibrary.globalTakeInt(1337);

MySwiftClass obj = new MySwiftClass(2222, 7777);
MySwiftClass obj = new MySwiftClass(2222, 7777);

SwiftKit.retain(obj.$memorySegment());
System.out.println("[java] obj ref count = " + SwiftKit.retainCount(obj.$memorySegment()));
SwiftKit.retain(obj.$memorySegment());
System.out.println("[java] obj ref count = " + SwiftKit.retainCount(obj.$memorySegment()));

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

MemorySegment swiftType = SwiftKit.getTypeByMangledNameInEnvironment("SiSg");
System.out.println("Memory layout for Swift.Int?:");
System.out.println(" size = " + SwiftKit.sizeOfSwiftType(swiftType));
System.out.println(" stride = " + SwiftKit.strideOfSwiftType(swiftType));
System.out.println(" alignment = " + SwiftKit.alignmentOfSwiftType(swiftType));
System.out.println(" Java layout = " + SwiftKit.layoutOfSwiftType(swiftType));
System.out.println("DONE.");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public final class ManualMySwiftClass extends Manual_MySwiftClass implements Man
// 000000000003f4a8 S type metadata for JavaKitExample.MySwiftSlice
// strip the _$s
// drop the N
public static final String TYPE_METADATA_NAME = "14JavaKitExample12MySwiftClassC";
public static final String TYPE_MANGLED_NAME = "14JavaKitExample12MySwiftClassC";

private final MemorySegment self;

Expand Down Expand Up @@ -167,13 +167,13 @@ static MemorySegment __allocating_init_len_cap(long len, long cap) {
if (ManualJavaKitExample.TRACE_DOWNCALLS) {
ManualJavaKitExample.traceDowncall("MySwiftClass.__allocating_init(len:cap:)", len, cap);
}
ManualJavaKitExample.trace("type name = " + TYPE_METADATA_NAME);
ManualJavaKitExample.trace("type name = " + TYPE_MANGLED_NAME);

// FIXME: problems with _getTypeByName because of the String memory repr
// final MemorySegment type = SwiftKit.getTypeByMangledNameInEnvironment(TYPE_METADATA_NAME);
// final MemorySegment type = SwiftKit.getTypeByMangledNameInEnvironment(TYPE_MANGLED_NAME);
// we must get a method we can call like this into SwiftKit:

MemorySegment type = ManualJavaKitExample.swiftkit_getTypeByStringByteArray(TYPE_METADATA_NAME);
MemorySegment type = ManualJavaKitExample.swiftkit_getTypeByStringByteArray(TYPE_MANGLED_NAME);
ManualJavaKitExample.trace("type = " + type);

var address = (MemorySegment) mh$.invokeExact(len, cap, type);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
package com.example.swift.generated;

import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.DisabledOnOs;
import org.junit.jupiter.api.condition.OS;
Expand Down Expand Up @@ -48,9 +49,10 @@ void test_MySwiftClass_makeIntMethod() {
}

@Test
@Disabled // TODO: Need var mangled names in interfaces
void test_MySwiftClass_property_len() {
MySwiftClass o = new MySwiftClass(12, 42);
var got = o.makeIntMethod();
var got = o.getLen();
assertEquals(12, got);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,17 +27,14 @@ public class MySwiftClassTest {

@BeforeAll
static void beforeAll() {
System.out.printf("java.library.path = %s\n", System.getProperty("java.library.path"));

System.loadLibrary("swiftCore");
System.loadLibrary("ExampleSwiftLibrary");

System.setProperty("jextract.trace.downcalls", "true");
System.out.printf("java.library.path = %s\n", SwiftKit.getJavaLibraryPath());
System.out.printf("jextract.trace.downcalls = %s\n", SwiftKit.getJextractTraceDowncalls());
}

@Test
void call_retain_retainCount_release() {
var obj = new MySwiftClass(1, 2);
var arena = SwiftArena.ofConfined();
var obj = new MySwiftClass(arena, 1, 2);

assertEquals(1, SwiftKit.retainCount(obj.$memorySegment()));
// TODO: test directly on SwiftHeapObject inheriting obj
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
//===----------------------------------------------------------------------===//
//
// 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 org.swift.swiftkit;

import com.example.swift.generated.MySwiftClass;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.DisabledIf;
import org.swift.swiftkit.util.PlatformUtils;

import static org.junit.jupiter.api.Assertions.*;
import static org.swift.swiftkit.SwiftKit.*;
import static org.swift.swiftkit.SwiftKit.retainCount;

public class SwiftArenaTest {

@BeforeAll
static void beforeAll() {
System.out.printf("java.library.path = %s\n", SwiftKit.getJavaLibraryPath());
System.out.printf("jextract.trace.downcalls = %s\n", SwiftKit.getJextractTraceDowncalls());
}

static boolean isAmd64() {
return PlatformUtils.isAmd64();
}

// FIXME: The destroy witness table call hangs on x86_64 platforms during the destroy witness table call
// See: https://github.com/swiftlang/swift-java/issues/97
@Test
@DisabledIf("isAmd64")
public void arena_releaseClassOnClose_class_ok() {
try (var arena = SwiftArena.ofConfined()) {
var obj = new MySwiftClass(arena,1, 2);

retain(obj.$memorySegment());
assertEquals(2, retainCount(obj.$memorySegment()));

release(obj.$memorySegment());
assertEquals(1, retainCount(obj.$memorySegment()));
}

// TODO: should we zero out the $memorySegment perhaps?
}

@Test
public void arena_releaseClassOnClose_class_leaked() {
String memorySegmentDescription = "<none>";

try {
try (var arena = SwiftArena.ofConfined()) {
var obj = new MySwiftClass(arena,1, 2);
memorySegmentDescription = obj.$memorySegment().toString();

// Pretend that we "leaked" the class, something still holds a reference to it while we try to destroy it
retain(obj.$memorySegment());
assertEquals(2, retainCount(obj.$memorySegment()));
}

fail("Expected exception to be thrown while the arena is closed!");
} catch (Exception ex) {
// The message should point out which objects "leaked":
assertTrue(ex.getMessage().contains(memorySegmentDescription));
}

}
}
9 changes: 9 additions & 0 deletions Sources/ExampleSwiftLibrary/MySwiftLibrary.swift
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,15 @@ public class MySwiftClass {
}
}

@_silgen_name("swift_getTypeByMangledNameInEnvironment")
public func _getTypeByMangledNameInEnvironment(
_ name: UnsafePointer<UInt8>,
_ nameLength: UInt,
genericEnvironment: UnsafeRawPointer?,
genericArguments: UnsafeRawPointer?)
-> Any.Type?


// ==== Internal helpers

private func p(_ msg: String, file: String = #fileID, line: UInt = #line, function: String = #function) {
Expand Down
Loading