Skip to content

Commit 3dbad6e

Browse files
committed
Add a runtime function to check type creation
1 parent d0a3082 commit 3dbad6e

File tree

3 files changed

+193
-0
lines changed

3 files changed

+193
-0
lines changed

include/swift/Runtime/Metadata.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1046,6 +1046,16 @@ void swift_initRawStructMetadata(StructMetadata *self,
10461046
const TypeLayout *likeType,
10471047
int32_t count);
10481048

1049+
/// Check if the given generic arguments are valid inputs for the generic type
1050+
/// context and if so call the access function to return
1051+
SWIFT_RUNTIME_STDLIB_SPI
1052+
SWIFT_CC(swift)
1053+
const Metadata *_swift_checkedCreateType(const TypeContextDescriptor *context,
1054+
const void * const *genericArgs,
1055+
size_t genericArgsSize,
1056+
const int32_t *packCounts,
1057+
size_t packCountsSize);
1058+
10491059
#pragma clang diagnostic pop
10501060

10511061
} // end namespace swift

stdlib/public/runtime/MetadataLookup.cpp

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2830,6 +2830,61 @@ swift_getOpaqueTypeConformance(const void * const *arguments,
28302830
arguments, static_cast<const OpaqueTypeDescriptor *>(descriptor), index);
28312831
}
28322832

2833+
SWIFT_RUNTIME_STDLIB_SPI
2834+
SWIFT_CC(swift)
2835+
const Metadata *swift::_swift_checkedCreateType(const TypeContextDescriptor *context,
2836+
const void * const *genericArgs,
2837+
size_t genericArgsSize,
2838+
const int32_t *packCounts,
2839+
size_t packCountsSize) {
2840+
context = swift_auth_data_non_address(
2841+
context, SpecialPointerAuthDiscriminators::ContextDescriptor);
2842+
2843+
if (!context->isGeneric()) {
2844+
return nullptr;
2845+
}
2846+
2847+
if (packCounts && genericArgsSize != packCountsSize) {
2848+
return nullptr;
2849+
}
2850+
2851+
llvm::SmallVector<MetadataOrPack, 8> fixedGenericArgs;
2852+
2853+
// Heap allocate all of the potential stack allocated pack pointers
2854+
for (size_t i = 0; i != genericArgsSize; i += 1) {
2855+
// Use -1 to indicate that this is not a pack pointer and instead just
2856+
// metadata. If we were not passed a packCount array, treat all elements as
2857+
// if they were just metadata.
2858+
if ((packCounts && packCounts[i] == -1) || !packCounts) {
2859+
fixedGenericArgs.push_back(MetadataOrPack(genericArgs[i]));
2860+
continue;
2861+
}
2862+
2863+
auto packPointer = swift_allocateMetadataPack(
2864+
reinterpret_cast<const Metadata *const *>(genericArgs[i]), packCounts[i]);
2865+
fixedGenericArgs.push_back(MetadataOrPack(packPointer));
2866+
}
2867+
2868+
DemanglerForRuntimeTypeResolution<StackAllocatedDemangler<2048>> demangler;
2869+
2870+
llvm::SmallVector<unsigned, 8> genericParamCounts;
2871+
llvm::SmallVector<const void *, 8> allGenericArgs;
2872+
2873+
auto result = _gatherGenericParameters(context, fixedGenericArgs,
2874+
/* parent */ nullptr,
2875+
genericParamCounts, allGenericArgs,
2876+
demangler);
2877+
2878+
// _gatherGenericParameters returns llvm::None on success.
2879+
if (result.hasValue()) {
2880+
return nullptr;
2881+
}
2882+
2883+
auto accessFunction = context->getAccessFunction();
2884+
2885+
return accessFunction(MetadataState::Complete, allGenericArgs).Value;
2886+
}
2887+
28332888
#if SWIFT_OBJC_INTEROP
28342889

28352890
// Return the ObjC class for the given type name.

test/Runtime/check_create_type.swift

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
// RUN: %target-run-simple-swift(-Xfrontend -disable-availability-checking)
2+
// REQUIRES: executable_test
3+
4+
// UNSUPPORTED: CPU=arm64e
5+
// UNSUPPORTED: use_os_stdlib
6+
// UNSUPPORTED: back_deployment_runtime
7+
8+
import StdlibUnittest
9+
10+
let testSuite = TestSuite("CheckedCreateType")
11+
12+
struct Variadic<each T> {
13+
struct Nested<U, each V: Equatable> {}
14+
}
15+
16+
@_silgen_name("_swift_checkedCreateType")
17+
func _checkedCreateType(
18+
_ descriptor: UnsafeRawPointer,
19+
_ genericArgs: UnsafeRawPointer,
20+
_ genericArgsSize: UInt,
21+
_ packCounts: UnsafeRawPointer?,
22+
_ packCountsSize: UInt
23+
) -> Any.Type?
24+
25+
func metaPointer(_ x: Any.Type) -> UnsafeRawPointer {
26+
unsafeBitCast(x, to: UnsafeRawPointer.self)
27+
}
28+
29+
testSuite.test("_swift_checkedCreateType non-variadic") {
30+
let dictMeta = unsafeBitCast(
31+
[Int: Int].self as Any.Type,
32+
to: UnsafeRawPointer.self
33+
)
34+
let dictDesc = dictMeta.load(
35+
fromByteOffset: MemoryLayout<Int>.size,
36+
as: UnsafeRawPointer.self
37+
)
38+
39+
let dictGenericArgs: [Any.Type] = [String.self, Double.self]
40+
41+
dictGenericArgs.withUnsafeBufferPointer {
42+
let newDict = _checkedCreateType(
43+
dictDesc,
44+
UnsafeRawPointer($0.baseAddress!),
45+
UInt($0.count),
46+
nil,
47+
0
48+
)
49+
50+
expectTrue(newDict == [String: Double].self)
51+
}
52+
}
53+
54+
testSuite.test("_swift_checkedCreateType variadic") {
55+
let variMeta = unsafeBitCast(
56+
Variadic< >.self as Any.Type,
57+
to: UnsafeRawPointer.self
58+
)
59+
let variDesc = variMeta.load(
60+
fromByteOffset: MemoryLayout<Int>.size,
61+
as: UnsafeRawPointer.self
62+
)
63+
64+
let variPack: [Any.Type] = [Int.self, Int8.self, UInt8.self]
65+
let variPackCounts: [Int32] = [3]
66+
67+
variPack.withUnsafeBufferPointer { pack in
68+
let genericArgs = [UnsafeRawPointer(pack.baseAddress!)]
69+
70+
genericArgs.withUnsafeBufferPointer { genericArgs in
71+
variPackCounts.withUnsafeBufferPointer { packCounts in
72+
let newVari = _checkedCreateType(
73+
variDesc,
74+
UnsafeRawPointer(genericArgs.baseAddress!),
75+
UInt(genericArgs.count),
76+
UnsafeRawPointer(packCounts.baseAddress!),
77+
UInt(packCounts.count)
78+
)
79+
80+
expectTrue(newVari == Variadic<Int, Int8, UInt8>.self)
81+
}
82+
}
83+
}
84+
}
85+
86+
testSuite.test("_swift_checkedCreateType variadic nested with requirements") {
87+
let nestedMeta = unsafeBitCast(
88+
Variadic< >.Nested<()>.self as Any.Type,
89+
to: UnsafeRawPointer.self
90+
)
91+
let nestedDesc = nestedMeta.load(
92+
fromByteOffset: MemoryLayout<Int>.size,
93+
as: UnsafeRawPointer.self
94+
)
95+
96+
let variPack: [Any.Type] = [String.self, [Int].self, UInt64.self]
97+
98+
let nestedPack: [Any.Type] = [Int.self, Substring.self, Bool.self]
99+
100+
nestedPack.withUnsafeBufferPointer { nestedPack in
101+
variPack.withUnsafeBufferPointer { variPack in
102+
let nestedGenericArgs = [
103+
UnsafeRawPointer(variPack.baseAddress!),
104+
metaPointer(Int16.self),
105+
UnsafeRawPointer(nestedPack.baseAddress!)
106+
]
107+
108+
nestedGenericArgs.withUnsafeBufferPointer { nestedGenericArgs in
109+
// 3 for each T, -1 for U, and 3 for each V
110+
let nestedPackCounts: [Int32] = [3, -1, 3]
111+
112+
nestedPackCounts.withUnsafeBufferPointer { nestedPackCounts in
113+
let newNested = _checkedCreateType(
114+
nestedDesc,
115+
UnsafeRawPointer(nestedGenericArgs.baseAddress!),
116+
UInt(nestedGenericArgs.count),
117+
UnsafeRawPointer(nestedPackCounts.baseAddress!),
118+
UInt(nestedPackCounts.count)
119+
)
120+
121+
expectTrue(newNested == Variadic<String, [Int], UInt64>.Nested<Int16, Int, Substring, Bool>.self)
122+
}
123+
}
124+
}
125+
}
126+
}
127+
128+
runAllTests()

0 commit comments

Comments
 (0)