From 3dbad6e1fd6ac4b0944f147bcb2ade1656fdf644 Mon Sep 17 00:00:00 2001 From: Alejandro Alonso Date: Wed, 6 Sep 2023 11:32:22 -0700 Subject: [PATCH 1/2] Add a runtime function to check type creation --- include/swift/Runtime/Metadata.h | 10 ++ stdlib/public/runtime/MetadataLookup.cpp | 55 ++++++++++ test/Runtime/check_create_type.swift | 128 +++++++++++++++++++++++ 3 files changed, 193 insertions(+) create mode 100644 test/Runtime/check_create_type.swift diff --git a/include/swift/Runtime/Metadata.h b/include/swift/Runtime/Metadata.h index e53deac6390e4..164d3de5ec918 100644 --- a/include/swift/Runtime/Metadata.h +++ b/include/swift/Runtime/Metadata.h @@ -1046,6 +1046,16 @@ void swift_initRawStructMetadata(StructMetadata *self, const TypeLayout *likeType, int32_t count); +/// Check if the given generic arguments are valid inputs for the generic type +/// context and if so call the access function to return +SWIFT_RUNTIME_STDLIB_SPI +SWIFT_CC(swift) +const Metadata *_swift_checkedCreateType(const TypeContextDescriptor *context, + const void * const *genericArgs, + size_t genericArgsSize, + const int32_t *packCounts, + size_t packCountsSize); + #pragma clang diagnostic pop } // end namespace swift diff --git a/stdlib/public/runtime/MetadataLookup.cpp b/stdlib/public/runtime/MetadataLookup.cpp index 6c63fccd8cd25..fe97691955d16 100644 --- a/stdlib/public/runtime/MetadataLookup.cpp +++ b/stdlib/public/runtime/MetadataLookup.cpp @@ -2830,6 +2830,61 @@ swift_getOpaqueTypeConformance(const void * const *arguments, arguments, static_cast(descriptor), index); } +SWIFT_RUNTIME_STDLIB_SPI +SWIFT_CC(swift) +const Metadata *swift::_swift_checkedCreateType(const TypeContextDescriptor *context, + const void * const *genericArgs, + size_t genericArgsSize, + const int32_t *packCounts, + size_t packCountsSize) { + context = swift_auth_data_non_address( + context, SpecialPointerAuthDiscriminators::ContextDescriptor); + + if (!context->isGeneric()) { + return nullptr; + } + + if (packCounts && genericArgsSize != packCountsSize) { + return nullptr; + } + + llvm::SmallVector fixedGenericArgs; + + // Heap allocate all of the potential stack allocated pack pointers + for (size_t i = 0; i != genericArgsSize; i += 1) { + // Use -1 to indicate that this is not a pack pointer and instead just + // metadata. If we were not passed a packCount array, treat all elements as + // if they were just metadata. + if ((packCounts && packCounts[i] == -1) || !packCounts) { + fixedGenericArgs.push_back(MetadataOrPack(genericArgs[i])); + continue; + } + + auto packPointer = swift_allocateMetadataPack( + reinterpret_cast(genericArgs[i]), packCounts[i]); + fixedGenericArgs.push_back(MetadataOrPack(packPointer)); + } + + DemanglerForRuntimeTypeResolution> demangler; + + llvm::SmallVector genericParamCounts; + llvm::SmallVector allGenericArgs; + + auto result = _gatherGenericParameters(context, fixedGenericArgs, + /* parent */ nullptr, + genericParamCounts, allGenericArgs, + demangler); + + // _gatherGenericParameters returns llvm::None on success. + if (result.hasValue()) { + return nullptr; + } + + auto accessFunction = context->getAccessFunction(); + + return accessFunction(MetadataState::Complete, allGenericArgs).Value; +} + #if SWIFT_OBJC_INTEROP // Return the ObjC class for the given type name. diff --git a/test/Runtime/check_create_type.swift b/test/Runtime/check_create_type.swift new file mode 100644 index 0000000000000..f385dca57ab4a --- /dev/null +++ b/test/Runtime/check_create_type.swift @@ -0,0 +1,128 @@ +// RUN: %target-run-simple-swift(-Xfrontend -disable-availability-checking) +// REQUIRES: executable_test + +// UNSUPPORTED: CPU=arm64e +// UNSUPPORTED: use_os_stdlib +// UNSUPPORTED: back_deployment_runtime + +import StdlibUnittest + +let testSuite = TestSuite("CheckedCreateType") + +struct Variadic { + struct Nested {} +} + +@_silgen_name("_swift_checkedCreateType") +func _checkedCreateType( + _ descriptor: UnsafeRawPointer, + _ genericArgs: UnsafeRawPointer, + _ genericArgsSize: UInt, + _ packCounts: UnsafeRawPointer?, + _ packCountsSize: UInt +) -> Any.Type? + +func metaPointer(_ x: Any.Type) -> UnsafeRawPointer { + unsafeBitCast(x, to: UnsafeRawPointer.self) +} + +testSuite.test("_swift_checkedCreateType non-variadic") { + let dictMeta = unsafeBitCast( + [Int: Int].self as Any.Type, + to: UnsafeRawPointer.self + ) + let dictDesc = dictMeta.load( + fromByteOffset: MemoryLayout.size, + as: UnsafeRawPointer.self + ) + + let dictGenericArgs: [Any.Type] = [String.self, Double.self] + + dictGenericArgs.withUnsafeBufferPointer { + let newDict = _checkedCreateType( + dictDesc, + UnsafeRawPointer($0.baseAddress!), + UInt($0.count), + nil, + 0 + ) + + expectTrue(newDict == [String: Double].self) + } +} + +testSuite.test("_swift_checkedCreateType variadic") { + let variMeta = unsafeBitCast( + Variadic< >.self as Any.Type, + to: UnsafeRawPointer.self + ) + let variDesc = variMeta.load( + fromByteOffset: MemoryLayout.size, + as: UnsafeRawPointer.self + ) + + let variPack: [Any.Type] = [Int.self, Int8.self, UInt8.self] + let variPackCounts: [Int32] = [3] + + variPack.withUnsafeBufferPointer { pack in + let genericArgs = [UnsafeRawPointer(pack.baseAddress!)] + + genericArgs.withUnsafeBufferPointer { genericArgs in + variPackCounts.withUnsafeBufferPointer { packCounts in + let newVari = _checkedCreateType( + variDesc, + UnsafeRawPointer(genericArgs.baseAddress!), + UInt(genericArgs.count), + UnsafeRawPointer(packCounts.baseAddress!), + UInt(packCounts.count) + ) + + expectTrue(newVari == Variadic.self) + } + } + } +} + +testSuite.test("_swift_checkedCreateType variadic nested with requirements") { + let nestedMeta = unsafeBitCast( + Variadic< >.Nested<()>.self as Any.Type, + to: UnsafeRawPointer.self + ) + let nestedDesc = nestedMeta.load( + fromByteOffset: MemoryLayout.size, + as: UnsafeRawPointer.self + ) + + let variPack: [Any.Type] = [String.self, [Int].self, UInt64.self] + + let nestedPack: [Any.Type] = [Int.self, Substring.self, Bool.self] + + nestedPack.withUnsafeBufferPointer { nestedPack in + variPack.withUnsafeBufferPointer { variPack in + let nestedGenericArgs = [ + UnsafeRawPointer(variPack.baseAddress!), + metaPointer(Int16.self), + UnsafeRawPointer(nestedPack.baseAddress!) + ] + + nestedGenericArgs.withUnsafeBufferPointer { nestedGenericArgs in + // 3 for each T, -1 for U, and 3 for each V + let nestedPackCounts: [Int32] = [3, -1, 3] + + nestedPackCounts.withUnsafeBufferPointer { nestedPackCounts in + let newNested = _checkedCreateType( + nestedDesc, + UnsafeRawPointer(nestedGenericArgs.baseAddress!), + UInt(nestedGenericArgs.count), + UnsafeRawPointer(nestedPackCounts.baseAddress!), + UInt(nestedPackCounts.count) + ) + + expectTrue(newNested == Variadic.Nested.self) + } + } + } + } +} + +runAllTests() From 80187e8096fc6354a4cdee5e2cb0e20714a69204 Mon Sep 17 00:00:00 2001 From: Alejandro Alonso Date: Wed, 6 Sep 2023 12:02:13 -0700 Subject: [PATCH 2/2] Expect caller heap pack and rename Fix comment --- include/swift/Runtime/Metadata.h | 14 +++-- stdlib/public/runtime/MetadataLookup.cpp | 34 +++-------- test/Runtime/check_create_type.swift | 75 ++++++++++++------------ 3 files changed, 53 insertions(+), 70 deletions(-) diff --git a/include/swift/Runtime/Metadata.h b/include/swift/Runtime/Metadata.h index 164d3de5ec918..763469260fb69 100644 --- a/include/swift/Runtime/Metadata.h +++ b/include/swift/Runtime/Metadata.h @@ -1047,14 +1047,16 @@ void swift_initRawStructMetadata(StructMetadata *self, int32_t count); /// Check if the given generic arguments are valid inputs for the generic type -/// context and if so call the access function to return +/// context and if so call the metadata access function and return the metadata. +/// +/// Note: This expects the caller to heap allocate all pack pointers within the +/// generic arguments via 'swift_allocateMetadataPack'. SWIFT_RUNTIME_STDLIB_SPI SWIFT_CC(swift) -const Metadata *_swift_checkedCreateType(const TypeContextDescriptor *context, - const void * const *genericArgs, - size_t genericArgsSize, - const int32_t *packCounts, - size_t packCountsSize); +const Metadata *_swift_instantiateCheckedGenericMetadata( + const TypeContextDescriptor *context, + const void * const *genericArgs, + size_t genericArgsSize); #pragma clang diagnostic pop diff --git a/stdlib/public/runtime/MetadataLookup.cpp b/stdlib/public/runtime/MetadataLookup.cpp index fe97691955d16..32232a3860207 100644 --- a/stdlib/public/runtime/MetadataLookup.cpp +++ b/stdlib/public/runtime/MetadataLookup.cpp @@ -2832,11 +2832,10 @@ swift_getOpaqueTypeConformance(const void * const *arguments, SWIFT_RUNTIME_STDLIB_SPI SWIFT_CC(swift) -const Metadata *swift::_swift_checkedCreateType(const TypeContextDescriptor *context, - const void * const *genericArgs, - size_t genericArgsSize, - const int32_t *packCounts, - size_t packCountsSize) { +const Metadata *swift::_swift_instantiateCheckedGenericMetadata( + const TypeContextDescriptor *context, + const void * const *genericArgs, + size_t genericArgsSize) { context = swift_auth_data_non_address( context, SpecialPointerAuthDiscriminators::ContextDescriptor); @@ -2844,33 +2843,14 @@ const Metadata *swift::_swift_checkedCreateType(const TypeContextDescriptor *con return nullptr; } - if (packCounts && genericArgsSize != packCountsSize) { - return nullptr; - } - - llvm::SmallVector fixedGenericArgs; - - // Heap allocate all of the potential stack allocated pack pointers - for (size_t i = 0; i != genericArgsSize; i += 1) { - // Use -1 to indicate that this is not a pack pointer and instead just - // metadata. If we were not passed a packCount array, treat all elements as - // if they were just metadata. - if ((packCounts && packCounts[i] == -1) || !packCounts) { - fixedGenericArgs.push_back(MetadataOrPack(genericArgs[i])); - continue; - } - - auto packPointer = swift_allocateMetadataPack( - reinterpret_cast(genericArgs[i]), packCounts[i]); - fixedGenericArgs.push_back(MetadataOrPack(packPointer)); - } - DemanglerForRuntimeTypeResolution> demangler; + llvm::ArrayRef genericArgsRef( + reinterpret_cast(genericArgs), genericArgsSize); llvm::SmallVector genericParamCounts; llvm::SmallVector allGenericArgs; - auto result = _gatherGenericParameters(context, fixedGenericArgs, + auto result = _gatherGenericParameters(context, genericArgsRef, /* parent */ nullptr, genericParamCounts, allGenericArgs, demangler); diff --git a/test/Runtime/check_create_type.swift b/test/Runtime/check_create_type.swift index f385dca57ab4a..147a36249de5a 100644 --- a/test/Runtime/check_create_type.swift +++ b/test/Runtime/check_create_type.swift @@ -13,13 +13,17 @@ struct Variadic { struct Nested {} } -@_silgen_name("_swift_checkedCreateType") -func _checkedCreateType( +@_silgen_name("swift_allocateMetadataPack") +func allocateMetadataPack( + _ packPointer: UnsafeRawPointer, + _ packCount: UInt +) -> UnsafeRawPointer + +@_silgen_name("_swift_instantiateCheckedGenericMetadata") +func _instantiateCheckedGenericMetadata( _ descriptor: UnsafeRawPointer, _ genericArgs: UnsafeRawPointer, - _ genericArgsSize: UInt, - _ packCounts: UnsafeRawPointer?, - _ packCountsSize: UInt + _ genericArgsSize: UInt ) -> Any.Type? func metaPointer(_ x: Any.Type) -> UnsafeRawPointer { @@ -39,12 +43,10 @@ testSuite.test("_swift_checkedCreateType non-variadic") { let dictGenericArgs: [Any.Type] = [String.self, Double.self] dictGenericArgs.withUnsafeBufferPointer { - let newDict = _checkedCreateType( + let newDict = _instantiateCheckedGenericMetadata( dictDesc, UnsafeRawPointer($0.baseAddress!), - UInt($0.count), - nil, - 0 + UInt($0.count) ) expectTrue(newDict == [String: Double].self) @@ -62,23 +64,22 @@ testSuite.test("_swift_checkedCreateType variadic") { ) let variPack: [Any.Type] = [Int.self, Int8.self, UInt8.self] - let variPackCounts: [Int32] = [3] variPack.withUnsafeBufferPointer { pack in - let genericArgs = [UnsafeRawPointer(pack.baseAddress!)] + let packPointer = allocateMetadataPack( + UnsafeRawPointer(pack.baseAddress!), + UInt(pack.count) + ) + let genericArgs = [packPointer] genericArgs.withUnsafeBufferPointer { genericArgs in - variPackCounts.withUnsafeBufferPointer { packCounts in - let newVari = _checkedCreateType( - variDesc, - UnsafeRawPointer(genericArgs.baseAddress!), - UInt(genericArgs.count), - UnsafeRawPointer(packCounts.baseAddress!), - UInt(packCounts.count) - ) + let newVari = _instantiateCheckedGenericMetadata( + variDesc, + UnsafeRawPointer(genericArgs.baseAddress!), + UInt(genericArgs.count) + ) - expectTrue(newVari == Variadic.self) - } + expectTrue(newVari == Variadic.self) } } } @@ -100,26 +101,26 @@ testSuite.test("_swift_checkedCreateType variadic nested with requirements") { nestedPack.withUnsafeBufferPointer { nestedPack in variPack.withUnsafeBufferPointer { variPack in let nestedGenericArgs = [ - UnsafeRawPointer(variPack.baseAddress!), + allocateMetadataPack( + UnsafeRawPointer(variPack.baseAddress!), + UInt(variPack.count) + ), metaPointer(Int16.self), - UnsafeRawPointer(nestedPack.baseAddress!) + allocateMetadataPack( + UnsafeRawPointer(nestedPack.baseAddress!), + UInt(nestedPack.count) + ) ] nestedGenericArgs.withUnsafeBufferPointer { nestedGenericArgs in - // 3 for each T, -1 for U, and 3 for each V - let nestedPackCounts: [Int32] = [3, -1, 3] - - nestedPackCounts.withUnsafeBufferPointer { nestedPackCounts in - let newNested = _checkedCreateType( - nestedDesc, - UnsafeRawPointer(nestedGenericArgs.baseAddress!), - UInt(nestedGenericArgs.count), - UnsafeRawPointer(nestedPackCounts.baseAddress!), - UInt(nestedPackCounts.count) - ) - - expectTrue(newNested == Variadic.Nested.self) - } + + let newNested = _instantiateCheckedGenericMetadata( + nestedDesc, + UnsafeRawPointer(nestedGenericArgs.baseAddress!), + UInt(nestedGenericArgs.count) + ) + + expectTrue(newNested == Variadic.Nested.self) } } }