Skip to content

Model Swift's type metadata and value witness table for memory layout information #42

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
Show file tree
Hide file tree
Changes from 2 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 @@ -68,5 +68,12 @@ static void tests() {

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));
}
}
139 changes: 138 additions & 1 deletion JavaSwiftKitDemo/src/main/java/org/swift/javakit/SwiftKit.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import org.swift.swiftkit.SwiftHeapObject;

import java.lang.foreign.*;
import java.lang.foreign.MemoryLayout.PathElement;
import java.lang.invoke.MethodHandle;
import java.util.Arrays;
import java.util.stream.Collectors;
Expand Down Expand Up @@ -200,7 +201,7 @@ public static MemorySegment getTypeByName(String string) {
*/
private static class swift_getTypeByMangledNameInEnvironment {
public static final FunctionDescriptor DESC = FunctionDescriptor.of(
/*returns=*/ValueLayout.ADDRESS,
/*returns=*/SWIFT_POINTER,
ValueLayout.ADDRESS,
ValueLayout.JAVA_INT,
ValueLayout.ADDRESS,
Expand Down Expand Up @@ -230,4 +231,140 @@ public static MemorySegment getTypeByMangledNameInEnvironment(String string) {
throw new AssertionError("should not reach here", ex$);
}
}

/**
* The value layout for Swift's Int type, which is a signed type that follows
* the size of a pointer (aka C's ptrdiff_t).
*/
public static ValueLayout SWIFT_INT = (ValueLayout.ADDRESS.byteSize() == 4) ?
ValueLayout.JAVA_INT : ValueLayout.JAVA_LONG;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Oh nice, instead of guessing by platform. Lgtm


/**
* The value layout for Swift's UInt type, which is an unsigned type that follows
* the size of a pointer (aka C's size_t). Java does not have unsigned integer
* types in general, so we use the layout for Swift's Int.
*/
public static ValueLayout SWIFT_UINT = SWIFT_INT;

/**
* Read a Swift.Int value from memory at the given offset and translate it into a Java long.
*
* This function copes with the fact that a Swift.Int might be 32 or 64 bits.
*/
public static final long getSwiftInt(MemorySegment memorySegment, long offset) {
if (SWIFT_INT == ValueLayout.JAVA_LONG) {
return memorySegment.get(ValueLayout.JAVA_LONG, offset);
} else {
return memorySegment.get(ValueLayout.JAVA_INT, offset);
}
}

/**
* Value witness table layout.
*/
public static final MemoryLayout valueWitnessTableLayout = MemoryLayout.structLayout(
ValueLayout.ADDRESS.withName("initializeBufferWithCopyOfBuffer"),
ValueLayout.ADDRESS.withName("destroy"),
ValueLayout.ADDRESS.withName("initializeWithCopy"),
ValueLayout.ADDRESS.withName("assignWithCopy"),
ValueLayout.ADDRESS.withName("initializeWithTake"),
ValueLayout.ADDRESS.withName("assignWithTake"),
ValueLayout.ADDRESS.withName("getEnumTagSinglePayload"),
ValueLayout.ADDRESS.withName("storeEnumTagSinglePayload"),
SwiftKit.SWIFT_INT.withName("size"),
SwiftKit.SWIFT_INT.withName("stride"),
SwiftKit.SWIFT_UINT.withName("flags"),
SwiftKit.SWIFT_UINT.withName("extraInhabitantCount")
).withName("SwiftValueWitnessTable");

/**
* Offset for the "size" field within the value witness table.
*/
static final long valueWitnessTable$size$offset =
valueWitnessTableLayout.byteOffset(PathElement.groupElement("size"));

/**
* Offset for the "stride" field within the value witness table.
*/
static final long valueWitnessTable$stride$offset =
valueWitnessTableLayout.byteOffset(PathElement.groupElement("stride"));

/**
* Offset for the "flags" field within the value witness table.
*/
static final long valueWitnessTable$flags$offset =
valueWitnessTableLayout.byteOffset(PathElement.groupElement("flags"));

/**
* Type metadata pointer.
*/
public static final StructLayout fullTypeMetadataLayout = MemoryLayout.structLayout(
SWIFT_POINTER.withName("vwt")
).withName("SwiftFullTypeMetadata");

/**
* Offset for the "vwt" field within the full type metadata.
*/
static final long fullTypeMetadata$vwt$offset =
fullTypeMetadataLayout.byteOffset(PathElement.groupElement("vwt"));

/**
* Given the address of Swift type metadata for a type, return the addres
* of the "full" type metadata that can be accessed via fullTypeMetadataLayout.
*/
public static MemorySegment fullTypeMetadata(MemorySegment typeMetadata) {
return MemorySegment.ofAddress(typeMetadata.address() - SWIFT_POINTER.byteSize())
.reinterpret(fullTypeMetadataLayout.byteSize());
}

/**
* Given the address of Swift type's metadata, return the address that
* references the value witness table for the type.
*/
public static MemorySegment valueWitnessTable(MemorySegment typeMetadata) {
return fullTypeMetadata(typeMetadata).get(SWIFT_POINTER, fullTypeMetadata$vwt$offset);
}

/**
* Determine the size of a Swift type given its type metadata.
*/
public static long sizeOfSwiftType(MemorySegment typeMetadata) {
return getSwiftInt(valueWitnessTable(typeMetadata), valueWitnessTable$size$offset);
}

/**
* Determine the stride of a Swift type given its type metadata, which is
* how many bytes are between successive elements of this type within an
* array. It is >= the size.
*/
public static long strideOfSwiftType(MemorySegment typeMetadata) {
return getSwiftInt(valueWitnessTable(typeMetadata), valueWitnessTable$stride$offset);
}

/**
* Determine the alignment of the given Swift type.
*/
public static long alignmentOfSwiftType(MemorySegment typeMetadata) {
long flags = getSwiftInt(valueWitnessTable(typeMetadata), valueWitnessTable$flags$offset);
return (flags & 0xFF) + 1;
}

/**
* Produce a layout that describes a Swift type based on its
* type metadata. The resulting layout is completely opaque to Java, but
* has appropriate size/alignment to model the memory associated with a
* Swift type.
*
* In the future, this layout could be extended to provide more detail,
* such as the fields of a Swift struct.
*/
public static MemoryLayout layoutOfSwiftType(MemorySegment typeMetadata) {
long size = sizeOfSwiftType(typeMetadata);
long stride = strideOfSwiftType(typeMetadata);
return MemoryLayout.structLayout(
MemoryLayout.sequenceLayout(size, JAVA_BYTE)
.withByteAlignment(alignmentOfSwiftType(typeMetadata)),
MemoryLayout.paddingLayout(stride - size)
);
}
}
Loading