|
17 | 17 | import org.swift.swiftkit.SwiftHeapObject;
|
18 | 18 |
|
19 | 19 | import java.lang.foreign.*;
|
| 20 | +import java.lang.foreign.MemoryLayout.PathElement; |
20 | 21 | import java.lang.invoke.MethodHandle;
|
21 | 22 | import java.util.Arrays;
|
22 | 23 | import java.util.stream.Collectors;
|
23 | 24 |
|
| 25 | +import static java.lang.foreign.ValueLayout.ADDRESS; |
24 | 26 | import static java.lang.foreign.ValueLayout.JAVA_BYTE;
|
25 | 27 |
|
26 | 28 | public class SwiftKit {
|
@@ -61,6 +63,36 @@ static MemorySegment findOrThrow(String symbol) {
|
61 | 63 | .orElseThrow(() -> new UnsatisfiedLinkError("unresolved symbol: %s".formatted(symbol)));
|
62 | 64 | }
|
63 | 65 |
|
| 66 | + // ==== ------------------------------------------------------------------------------------------------------------ |
| 67 | + // free |
| 68 | + /** |
| 69 | + * Descriptor for the free C runtime function. |
| 70 | + */ |
| 71 | + public static final FunctionDescriptor free$descriptor = FunctionDescriptor.ofVoid( |
| 72 | + ValueLayout.ADDRESS |
| 73 | + ); |
| 74 | + |
| 75 | + /** |
| 76 | + * Address of the free C runtime function. |
| 77 | + */ |
| 78 | + public static final MemorySegment free$addr = findOrThrow("free"); |
| 79 | + |
| 80 | + /** |
| 81 | + * Handle for the free C runtime function. |
| 82 | + */ |
| 83 | + public static final MethodHandle free$handle = Linker.nativeLinker().downcallHandle(free$addr, free$descriptor); |
| 84 | + |
| 85 | + /** |
| 86 | + * free the given pointer |
| 87 | + */ |
| 88 | + public static void cFree(MemorySegment pointer) { |
| 89 | + try { |
| 90 | + free$handle.invokeExact(pointer); |
| 91 | + } catch (Throwable ex$) { |
| 92 | + throw new AssertionError("should not reach here", ex$); |
| 93 | + } |
| 94 | + } |
| 95 | + |
64 | 96 | // ==== ------------------------------------------------------------------------------------------------------------
|
65 | 97 | // swift_retainCount
|
66 | 98 |
|
@@ -200,7 +232,7 @@ public static MemorySegment getTypeByName(String string) {
|
200 | 232 | */
|
201 | 233 | private static class swift_getTypeByMangledNameInEnvironment {
|
202 | 234 | public static final FunctionDescriptor DESC = FunctionDescriptor.of(
|
203 |
| - /*returns=*/ValueLayout.ADDRESS, |
| 235 | + /*returns=*/SWIFT_POINTER, |
204 | 236 | ValueLayout.ADDRESS,
|
205 | 237 | ValueLayout.JAVA_INT,
|
206 | 238 | ValueLayout.ADDRESS,
|
@@ -230,4 +262,182 @@ public static MemorySegment getTypeByMangledNameInEnvironment(String string) {
|
230 | 262 | throw new AssertionError("should not reach here", ex$);
|
231 | 263 | }
|
232 | 264 | }
|
| 265 | + |
| 266 | + /** |
| 267 | + * The value layout for Swift's Int type, which is a signed type that follows |
| 268 | + * the size of a pointer (aka C's ptrdiff_t). |
| 269 | + */ |
| 270 | + public static ValueLayout SWIFT_INT = (ValueLayout.ADDRESS.byteSize() == 4) ? |
| 271 | + ValueLayout.JAVA_INT : ValueLayout.JAVA_LONG; |
| 272 | + |
| 273 | + /** |
| 274 | + * The value layout for Swift's UInt type, which is an unsigned type that follows |
| 275 | + * the size of a pointer (aka C's size_t). Java does not have unsigned integer |
| 276 | + * types in general, so we use the layout for Swift's Int. |
| 277 | + */ |
| 278 | + public static ValueLayout SWIFT_UINT = SWIFT_INT; |
| 279 | + |
| 280 | + /** |
| 281 | + * Read a Swift.Int value from memory at the given offset and translate it into a Java long. |
| 282 | + * |
| 283 | + * This function copes with the fact that a Swift.Int might be 32 or 64 bits. |
| 284 | + */ |
| 285 | + public static final long getSwiftInt(MemorySegment memorySegment, long offset) { |
| 286 | + if (SWIFT_INT == ValueLayout.JAVA_LONG) { |
| 287 | + return memorySegment.get(ValueLayout.JAVA_LONG, offset); |
| 288 | + } else { |
| 289 | + return memorySegment.get(ValueLayout.JAVA_INT, offset); |
| 290 | + } |
| 291 | + } |
| 292 | + |
| 293 | + /** |
| 294 | + * Value witness table layout. |
| 295 | + */ |
| 296 | + public static final MemoryLayout valueWitnessTableLayout = MemoryLayout.structLayout( |
| 297 | + ValueLayout.ADDRESS.withName("initializeBufferWithCopyOfBuffer"), |
| 298 | + ValueLayout.ADDRESS.withName("destroy"), |
| 299 | + ValueLayout.ADDRESS.withName("initializeWithCopy"), |
| 300 | + ValueLayout.ADDRESS.withName("assignWithCopy"), |
| 301 | + ValueLayout.ADDRESS.withName("initializeWithTake"), |
| 302 | + ValueLayout.ADDRESS.withName("assignWithTake"), |
| 303 | + ValueLayout.ADDRESS.withName("getEnumTagSinglePayload"), |
| 304 | + ValueLayout.ADDRESS.withName("storeEnumTagSinglePayload"), |
| 305 | + SwiftKit.SWIFT_INT.withName("size"), |
| 306 | + SwiftKit.SWIFT_INT.withName("stride"), |
| 307 | + SwiftKit.SWIFT_UINT.withName("flags"), |
| 308 | + SwiftKit.SWIFT_UINT.withName("extraInhabitantCount") |
| 309 | + ).withName("SwiftValueWitnessTable"); |
| 310 | + |
| 311 | + /** |
| 312 | + * Offset for the "size" field within the value witness table. |
| 313 | + */ |
| 314 | + static final long valueWitnessTable$size$offset = |
| 315 | + valueWitnessTableLayout.byteOffset(PathElement.groupElement("size")); |
| 316 | + |
| 317 | + /** |
| 318 | + * Offset for the "stride" field within the value witness table. |
| 319 | + */ |
| 320 | + static final long valueWitnessTable$stride$offset = |
| 321 | + valueWitnessTableLayout.byteOffset(PathElement.groupElement("stride")); |
| 322 | + |
| 323 | + /** |
| 324 | + * Offset for the "flags" field within the value witness table. |
| 325 | + */ |
| 326 | + static final long valueWitnessTable$flags$offset = |
| 327 | + valueWitnessTableLayout.byteOffset(PathElement.groupElement("flags")); |
| 328 | + |
| 329 | + /** |
| 330 | + * Type metadata pointer. |
| 331 | + */ |
| 332 | + public static final StructLayout fullTypeMetadataLayout = MemoryLayout.structLayout( |
| 333 | + SWIFT_POINTER.withName("vwt") |
| 334 | + ).withName("SwiftFullTypeMetadata"); |
| 335 | + |
| 336 | + /** |
| 337 | + * Offset for the "vwt" field within the full type metadata. |
| 338 | + */ |
| 339 | + static final long fullTypeMetadata$vwt$offset = |
| 340 | + fullTypeMetadataLayout.byteOffset(PathElement.groupElement("vwt")); |
| 341 | + |
| 342 | + /** |
| 343 | + * Given the address of Swift type metadata for a type, return the addres |
| 344 | + * of the "full" type metadata that can be accessed via fullTypeMetadataLayout. |
| 345 | + */ |
| 346 | + public static MemorySegment fullTypeMetadata(MemorySegment typeMetadata) { |
| 347 | + return MemorySegment.ofAddress(typeMetadata.address() - SWIFT_POINTER.byteSize()) |
| 348 | + .reinterpret(fullTypeMetadataLayout.byteSize()); |
| 349 | + } |
| 350 | + |
| 351 | + /** |
| 352 | + * Given the address of Swift type's metadata, return the address that |
| 353 | + * references the value witness table for the type. |
| 354 | + */ |
| 355 | + public static MemorySegment valueWitnessTable(MemorySegment typeMetadata) { |
| 356 | + return fullTypeMetadata(typeMetadata).get(SWIFT_POINTER, fullTypeMetadata$vwt$offset); |
| 357 | + } |
| 358 | + |
| 359 | + /** |
| 360 | + * Determine the size of a Swift type given its type metadata. |
| 361 | + */ |
| 362 | + public static long sizeOfSwiftType(MemorySegment typeMetadata) { |
| 363 | + return getSwiftInt(valueWitnessTable(typeMetadata), valueWitnessTable$size$offset); |
| 364 | + } |
| 365 | + |
| 366 | + /** |
| 367 | + * Determine the stride of a Swift type given its type metadata, which is |
| 368 | + * how many bytes are between successive elements of this type within an |
| 369 | + * array. It is >= the size. |
| 370 | + */ |
| 371 | + public static long strideOfSwiftType(MemorySegment typeMetadata) { |
| 372 | + return getSwiftInt(valueWitnessTable(typeMetadata), valueWitnessTable$stride$offset); |
| 373 | + } |
| 374 | + |
| 375 | + /** |
| 376 | + * Determine the alignment of the given Swift type. |
| 377 | + */ |
| 378 | + public static long alignmentOfSwiftType(MemorySegment typeMetadata) { |
| 379 | + long flags = getSwiftInt(valueWitnessTable(typeMetadata), valueWitnessTable$flags$offset); |
| 380 | + return (flags & 0xFF) + 1; |
| 381 | + } |
| 382 | + |
| 383 | + /** |
| 384 | + * Descriptor for the swift_getTypeName runtime function. |
| 385 | + */ |
| 386 | + public static final FunctionDescriptor swift_getTypeName$descriptor = FunctionDescriptor.of( |
| 387 | + /*returns=*/MemoryLayout.structLayout( |
| 388 | + SWIFT_POINTER.withName("utf8Chars"), |
| 389 | + SWIFT_INT.withName("length") |
| 390 | + ), |
| 391 | + ValueLayout.ADDRESS, |
| 392 | + ValueLayout.JAVA_BOOLEAN |
| 393 | + ); |
| 394 | + |
| 395 | + /** |
| 396 | + * Address of the swift_getTypeName runtime function. |
| 397 | + */ |
| 398 | + public static final MemorySegment swift_getTypeName$addr = findOrThrow("swift_getTypeName"); |
| 399 | + |
| 400 | + /** |
| 401 | + * Handle for the swift_getTypeName runtime function. |
| 402 | + */ |
| 403 | + public static final MethodHandle swift_getTypeName$handle = Linker.nativeLinker().downcallHandle(swift_getTypeName$addr, swift_getTypeName$descriptor); |
| 404 | + |
| 405 | + /** |
| 406 | + * Produce the name of the Swift type given its Swift type metadata. |
| 407 | + * |
| 408 | + * If 'qualified' is true, leave all of the qualification in place to |
| 409 | + * disambiguate the type, producing a more complete (but longer) type name. |
| 410 | + */ |
| 411 | + public static String nameOfSwiftType(MemorySegment typeMetadata, boolean qualified) { |
| 412 | + try { |
| 413 | + try (Arena arena = Arena.ofConfined()) { |
| 414 | + MemorySegment charsAndLength = (MemorySegment)swift_getTypeName$handle.invokeExact((SegmentAllocator)arena, typeMetadata, qualified); |
| 415 | + MemorySegment utf8Chars = charsAndLength.get(SWIFT_POINTER, 0); |
| 416 | + String typeName = utf8Chars.getString(0); |
| 417 | + cFree(utf8Chars); |
| 418 | + return typeName; |
| 419 | + } |
| 420 | + } catch (Throwable ex$) { |
| 421 | + throw new AssertionError("should not reach here", ex$); |
| 422 | + } |
| 423 | + } |
| 424 | + |
| 425 | + /** |
| 426 | + * Produce a layout that describes a Swift type based on its |
| 427 | + * type metadata. The resulting layout is completely opaque to Java, but |
| 428 | + * has appropriate size/alignment to model the memory associated with a |
| 429 | + * Swift type. |
| 430 | + * |
| 431 | + * In the future, this layout could be extended to provide more detail, |
| 432 | + * such as the fields of a Swift struct. |
| 433 | + */ |
| 434 | + public static MemoryLayout layoutOfSwiftType(MemorySegment typeMetadata) { |
| 435 | + long size = sizeOfSwiftType(typeMetadata); |
| 436 | + long stride = strideOfSwiftType(typeMetadata); |
| 437 | + return MemoryLayout.structLayout( |
| 438 | + MemoryLayout.sequenceLayout(size, JAVA_BYTE) |
| 439 | + .withByteAlignment(alignmentOfSwiftType(typeMetadata)), |
| 440 | + MemoryLayout.paddingLayout(stride - size) |
| 441 | + ).withName(nameOfSwiftType(typeMetadata, true)); |
| 442 | + } |
233 | 443 | }
|
0 commit comments