Start outline storage support: Add swift_allocBox/deallocBox

Code using the outline heap storage path will crash and burn because
support is incomplete. But at least inline storage existential
inhabitants should compile and run.
This commit is contained in:
Arnold Schwaighofer
2025-11-11 15:28:19 -08:00
parent 93bc84e8e0
commit eda5eadfd4
3 changed files with 102 additions and 0 deletions

View File

@@ -83,6 +83,51 @@ static inline void _swift_embedded_set_heap_object_metadata_pointer(void *object
((EmbeddedHeapObject *)object)->metadata = metadata;
}
typedef struct {
void *initializeBufferWithCopyOfBufferFn;
#if __has_feature(ptrauth_calls)
void (* __ptrauth(0, 1, 0x04f8) destroyFn)(void *, void*);
#else
void (*destroyFn)(void *, void*);
#endif
#if __has_feature(ptrauth_calls)
void* (* __ptrauth(0, 1, 0xe3ba) initializeWithCopyFn)(void*, void*, void*);
#else
void* (*initializeWithCopyFn)(void*, void*, void*);
#endif
void *assignWithCopyFn;
void *initializeWithTakeFn;
void *assignWithTakeFn;
void *getEnumTagSinglePayloadFn;
void *storeEnumTagSinglePayload;
__swift_size_t size;
__swift_size_t stride;
unsigned flags;
} EmbeddedValueWitnessTable;
typedef struct {
#if __has_feature(ptrauth_calls)
EmbeddedValueWitnessTable * __ptrauth(2, 1, 0x2e3f) vwt;
#else
EmbeddedValueWitnessTable *vwt;
#endif
} EmbeddedMetaDataPrefix;
static inline __swift_size_t _swift_embedded_metadata_get_size(void *metadata) {
EmbeddedMetaDataPrefix *fullmeta = (EmbeddedMetaDataPrefix*)&((void **)metadata)[-1];
return fullmeta->vwt->size;
}
static inline __swift_size_t _swift_embedded_metadata_get_align_mask(void *metadata) {
EmbeddedMetaDataPrefix *fullmeta = (EmbeddedMetaDataPrefix*)&((void **)metadata)[-1];
unsigned flags = fullmeta->vwt->flags;
unsigned embeddedValueWitnessTableFlagsMask = 0xFF;
return flags & embeddedValueWitnessTableFlagsMask;
}
#ifdef __cplusplus
} // extern "C"
#endif

View File

@@ -262,6 +262,34 @@ public func swift_allocEmptyBox() -> Builtin.RawPointer {
}
@_silgen_name("swift_allocBox")
public func swift_allocBox(metadata: Builtin.RawPointer) -> (Builtin.RawPointer, Builtin.RawPointer) {
let alignMask = Int(unsafe _swift_embedded_metadata_get_align_mask(UnsafeMutableRawPointer(metadata)))
let size = Int(unsafe _swift_embedded_metadata_get_size(UnsafeMutableRawPointer(metadata)))
let headerSize = unsafe MemoryLayout<Int>.size + MemoryLayout<UnsafeRawPointer>.size
let headerAlignMask = unsafe MemoryLayout<UnsafeRawPointer>.alignment - 1
let startOfBoxedValue = ((headerSize + alignMask) & ~alignMask)
let requiredSize: Int = startOfBoxedValue + size
let requiredAlignmentMask: Int = alignMask | headerAlignMask
let p = unsafe swift_slowAlloc(requiredSize, requiredAlignmentMask)!
let object = unsafe p.assumingMemoryBound(to: HeapObject.self)
unsafe _swift_embedded_set_heap_object_metadata_pointer(object, UnsafeMutableRawPointer(metadata))
unsafe object.pointee.refcount = 1
let boxedValueAddr = unsafe UnsafeMutableRawPointer(p).advanced(by: startOfBoxedValue)
return (object._rawValue, boxedValueAddr._rawValue)
}
@_cdecl("swift_deallocBox")
public func swift_deallocBox(object: Builtin.RawPointer) {
unsafe free(UnsafeMutableRawPointer(object))
}
/// Refcounting
func isValidPointerForNativeRetain(object: Builtin.RawPointer) -> Bool {

View File

@@ -117,6 +117,33 @@ func test2(_ p: any Derived) {
p.b()
}
protocol ValuePrinter {
func printValue()
}
protocol WithAssoc {
associatedtype Assoc : ValuePrinter
func a() -> Assoc
}
extension Int : ValuePrinter {
func printValue() {
print("my value: \(self)")
}
}
struct ConformWithAssoc : WithAssoc {
var x = 1
func a() -> Int {
return x
}
}
func test3(_ p: any WithAssoc) {
let x = p.a()
x.printValue()
}
@main
struct Main {
static func main() {
@@ -131,9 +158,11 @@ struct Main {
// OUTPUT: a MyEnum
// OUTPUT: 5
// OUTPUT: b MyEnum
// OUTPUT: my value: 1
test2(Implementor())
test2(5)
test2(MyStruct())
test2(MyEnum.b(5))
test3(ConformWithAssoc())
}
}