Skip to content

Commit 61e484c

Browse files
committed
[interop][SwiftToCxx] correctly align allocation for opaque Swift value
1 parent f577330 commit 61e484c

File tree

5 files changed

+60
-6
lines changed

5 files changed

+60
-6
lines changed

lib/PrintAsClang/PrintAsClang.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ static void writePrologue(raw_ostream &out, ASTContext &ctx,
103103
"#include <cstddef>\n"
104104
"#include <cstdbool>\n"
105105
"#include <cstring>\n";
106+
out << "#include <cstdlib>\n";
106107
},
107108
[&] {
108109
out << "#include <stdint.h>\n"

lib/PrintAsClang/PrintSwiftToClangCoreScaffold.cpp

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -118,20 +118,40 @@ static void printTypeMetadataResponseType(SwiftToClangInteropContext &ctx,
118118
funcSig.parameterTypes[0]);
119119
}
120120

121+
static void printOpaqueAllocFee(raw_ostream &os) {
122+
os << R"text(inline void * _Nonnull opaqueAlloc(size_t size, size_t align) {
123+
if (align < sizeof(void *)) align = sizeof(void *);
124+
void *r = nullptr;
125+
int res = posix_memalign(&r, align, size);
126+
(void)res;
127+
return r;
128+
}
129+
inline void opaqueFree(void * _Nonnull p) {
130+
free(p);
131+
}
132+
)text";
133+
}
134+
121135
static void printSwiftResilientStorageClass(raw_ostream &os) {
122-
// FIXME: alignment.
136+
// FIXME: mark noexcept.
123137
auto name = cxx_synthesis::getCxxOpaqueStorageClassName();
138+
static_assert(TargetValueWitnessFlags<uint64_t>::AlignmentMask ==
139+
TargetValueWitnessFlags<uint32_t>::AlignmentMask,
140+
"alignment mask doesn't match");
124141
os << "/// Container for an opaque Swift value, like resilient struct.\n";
125142
os << "class " << name << " {\n";
126143
os << "public:\n";
127144
os << " inline " << name << "() : storage(nullptr) { }\n";
128145
os << " inline " << name
129-
<< "(ValueWitnessTable * _Nonnull vwTable) : storage(new "
130-
"char[vwTable->size]) { }\n";
146+
<< "(ValueWitnessTable * _Nonnull vwTable) : storage("
147+
"reinterpret_cast<char *>(opaqueAlloc(vwTable->size, (vwTable->flags &"
148+
<< TargetValueWitnessFlags<uint64_t>::AlignmentMask << ") + 1))) { }\n";
131149
os << " inline " << name << "(" << name
132150
<< "&& other) : storage(other.storage) { other.storage = nullptr; }\n";
133151
os << " inline " << name << "(const " << name << "&) = delete;\n";
134-
os << " inline ~" << name << "() { if (storage) { delete[] storage; } }\n";
152+
os << " inline ~" << name
153+
<< "() { if (storage) { opaqueFree(static_cast<char "
154+
"* _Nonnull>(storage)); } }\n";
135155
os << " void operator =(" << name
136156
<< "&& other) { auto temp = storage; storage = other.storage; "
137157
"other.storage = temp; }\n";
@@ -158,6 +178,8 @@ void swift::printSwiftToClangCoreScaffold(SwiftToClangInteropContext &ctx,
158178
printValueWitnessTable(os);
159179
});
160180
os << "\n";
181+
printOpaqueAllocFee(os);
182+
os << "\n";
161183
printSwiftResilientStorageClass(os);
162184
});
163185
});
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#if defined(_WIN32) || defined(WIN32)
2+
#define SDK_STDLIB_H
3+
#endif
4+
5+
#ifndef SDK_STDLIB_H
6+
#define SDK_STDLIB_H
7+
8+
#include <stdint.h>
9+
10+
typedef long ldiv_t;
11+
typedef long long lldiv_t;
12+
13+
int posix_memalign(void **, size_t, size_t);
14+
void free(void *);
15+
16+
ldiv_t ldiv(long int, long int);
17+
lldiv_t lldiv(long long int, long long int);
18+
19+
#endif // SDK_STDLIB_H

test/Interop/SwiftToCxx/core/swift-impl-defs-in-cxx.swift

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,14 +51,25 @@
5151
// CHECK-NEXT: }
5252
// CHECK-NEXT: #endif
5353
// CHECK-EMPTY:
54+
// CHECK-NEXT: inline void * _Nonnull opaqueAlloc(size_t size, size_t align) {
55+
// CHECK-NEXT: if (align < sizeof(void *)) align = sizeof(void *);
56+
// CHECK-NEXT: void *r = nullptr;
57+
// CHECK-NEXT: int res = posix_memalign(&r, align, size);
58+
// CHECK-NEXT: (void)res;
59+
// CHECK-NEXT: return r;
60+
// CHECK-NEXT: }
61+
// CHECK-NEXT: inline void opaqueFree(void * _Nonnull p) {
62+
// CHECK-NEXT: free(p);
63+
// CHECK-NEXT: }
64+
// CHECK-EMPTY:
5465
// CHECK-NEXT: /// Container for an opaque Swift value, like resilient struct.
5566
// CHECK-NEXT: class OpaqueStorage {
5667
// CHECK-NEXT: public:
5768
// CHECK-NEXT: inline OpaqueStorage() : storage(nullptr) { }
58-
// CHECK-NEXT: inline OpaqueStorage(ValueWitnessTable * _Nonnull vwTable) : storage(new char[vwTable->size]) { }
69+
// CHECK-NEXT: inline OpaqueStorage(ValueWitnessTable * _Nonnull vwTable) : storage(reinterpret_cast<char *>(opaqueAlloc(vwTable->size, (vwTable->flags &255) + 1))) { }
5970
// CHECK-NEXT: inline OpaqueStorage(OpaqueStorage&& other) : storage(other.storage) { other.storage = nullptr; }
6071
// CHECK-NEXT: inline OpaqueStorage(const OpaqueStorage&) = delete;
61-
// CHECK-NEXT: inline ~OpaqueStorage() { if (storage) { delete[] storage; } }
72+
// CHECK-NEXT: inline ~OpaqueStorage() { if (storage) { opaqueFree(static_cast<char * _Nonnull>(storage)); } }
6273
// CHECK-NEXT: void operator =(OpaqueStorage&& other) { auto temp = storage; storage = other.storage; other.storage = temp; }
6374
// CHECK-NEXT: void operator =(const OpaqueStorage&) = delete;
6475
// CHECK-NEXT: inline char * _Nonnull getOpaquePointer() { return static_cast<char * _Nonnull>(storage); }

test/PrintAsCxx/empty.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
// CHECK-NEXT: #include <cstddef>
3030
// CHECK-NEXT: #include <cstdbool>
3131
// CHECK-NEXT: #include <cstring>
32+
// CHECK-NEXT: #include <cstdlib>
3233
// CHECK-NEXT: #else
3334
// CHECK-NEXT: #include <stdint.h>
3435
// CHECK-NEXT: #include <stddef.h>

0 commit comments

Comments
 (0)