Skip to content

Commit 8da01aa

Browse files
authored
Merge pull request #60087 from WANGJIEKE/cxx-interop-extract-enum-payload
[Interop][SwiftToCxx] Initial support for getting associated values from enum
2 parents dd3c90a + 0a24b2c commit 8da01aa

16 files changed

+571
-186
lines changed

lib/PrintAsClang/ClangSyntaxPrinter.cpp

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -147,13 +147,15 @@ void ClangSyntaxPrinter::printSwiftTypeMetadataAccessFunctionCall(
147147
}
148148

149149
void ClangSyntaxPrinter::printValueWitnessTableAccessSequenceFromTypeMetadata(
150-
StringRef metadataVariable) {
151-
os << " auto *vwTableAddr = ";
150+
StringRef metadataVariable, StringRef vwTableVariable, int indent) {
151+
os << std::string(indent, ' ');
152+
os << "auto *vwTableAddr = ";
152153
os << "reinterpret_cast<";
153154
printSwiftImplQualifier();
154155
os << "ValueWitnessTable **>(" << metadataVariable << "._0) - 1;\n";
155156
os << "#ifdef __arm64e__\n";
156-
os << " auto *vwTable = ";
157+
os << std::string(indent, ' ');
158+
os << "auto *" << vwTableVariable << " = ";
157159
os << "reinterpret_cast<";
158160
printSwiftImplQualifier();
159161
os << "ValueWitnessTable *>(ptrauth_auth_data(";
@@ -162,6 +164,7 @@ void ClangSyntaxPrinter::printValueWitnessTableAccessSequenceFromTypeMetadata(
162164
os << "ptrauth_blend_discriminator(vwTableAddr, "
163165
<< SpecialPointerAuthDiscriminators::ValueWitnessTable << ")));\n";
164166
os << "#else\n";
165-
os << " auto *vwTable = *vwTableAddr;\n";
167+
os << std::string(indent, ' ');
168+
os << "auto *" << vwTableVariable << " = *vwTableAddr;\n";
166169
os << "#endif\n";
167170
}

lib/PrintAsClang/ClangSyntaxPrinter.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ class ClangSyntaxPrinter {
9393
/// Print the set of statements to access the value witness table pointer
9494
/// ('vwTable') from the given type metadata variable.
9595
void printValueWitnessTableAccessSequenceFromTypeMetadata(
96-
StringRef metadataVariable);
96+
StringRef metadataVariable, StringRef vwTableVariable, int indent);
9797

9898
protected:
9999
raw_ostream &os;

lib/PrintAsClang/DeclAndTypePrinter.cpp

Lines changed: 70 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -388,11 +388,13 @@ class DeclAndTypePrinter::Implementation
388388
}
389389

390390
void visitEnumDeclCxx(EnumDecl *ED) {
391+
assert(owningPrinter.outputLang == OutputLanguageMode::Cxx);
392+
391393
// FIXME: Print enum's availability
392-
ClangValueTypePrinter printer(os, owningPrinter.prologueOS,
393-
owningPrinter.typeMapping,
394-
owningPrinter.interopContext);
395-
printer.printValueTypeDecl(ED, /*bodyPrinter=*/[&]() {
394+
ClangValueTypePrinter valueTypePrinter(os, owningPrinter.prologueOS,
395+
owningPrinter.typeMapping,
396+
owningPrinter.interopContext);
397+
valueTypePrinter.printValueTypeDecl(ED, /*bodyPrinter=*/[&]() {
396398
ClangSyntaxPrinter syntaxPrinter(os);
397399
auto elementTagMapping =
398400
owningPrinter.interopContext.getIrABIDetails().getEnumTagMapping(ED);
@@ -418,6 +420,7 @@ class DeclAndTypePrinter::Implementation
418420
os << " inline operator cases() const {\n";
419421
os << " switch (_getEnumTag()) {\n";
420422
for (const auto &pair : elementTagMapping) {
423+
// TODO: have to use global variable for resilient enum
421424
os << " case " << pair.second << ": return cases::";
422425
syntaxPrinter.printIdentifier(pair.first->getNameStr());
423426
os << ";\n";
@@ -427,7 +430,11 @@ class DeclAndTypePrinter::Implementation
427430
os << " }\n"; // switch's closing bracket
428431
os << " }\n"; // operator cases()'s closing bracket
429432

430-
// Printing predicates
433+
// Printing case-related functions
434+
DeclAndTypeClangFunctionPrinter clangFuncPrinter(
435+
os, owningPrinter.prologueOS, owningPrinter.typeMapping,
436+
owningPrinter.interopContext);
437+
431438
for (const auto &pair : elementTagMapping) {
432439
os << " inline bool is";
433440
auto name = pair.first->getNameStr().str();
@@ -436,6 +443,64 @@ class DeclAndTypePrinter::Implementation
436443
os << " return *this == cases::";
437444
syntaxPrinter.printIdentifier(pair.first->getNameStr());
438445
os << ";\n }\n";
446+
447+
if (!pair.first->hasAssociatedValues()) {
448+
continue;
449+
}
450+
451+
auto associatedValueList = pair.first->getParameterList();
452+
// TODO: add tuple type support
453+
if (associatedValueList->size() > 1) {
454+
continue;
455+
}
456+
auto firstType = associatedValueList->front()->getType();
457+
auto firstTypeDecl = firstType->getNominalOrBoundGenericNominal();
458+
OptionalTypeKind optKind;
459+
std::tie(firstType, optKind) =
460+
getObjectTypeAndOptionality(firstTypeDecl, firstType);
461+
462+
// FIXME: (tongjie) may have to forward declare return type
463+
os << " inline ";
464+
clangFuncPrinter.printClangFunctionReturnType(
465+
firstType, optKind, firstTypeDecl->getModuleContext(),
466+
owningPrinter.outputLang);
467+
os << " get" << name << "() const {\n";
468+
os << " if (!is" << name << "()) abort();\n";
469+
os << " alignas(";
470+
syntaxPrinter.printBaseName(ED);
471+
os << ") unsigned char buffer[sizeof(";
472+
syntaxPrinter.printBaseName(ED);
473+
os << ")];\n";
474+
os << " auto *thisCopy = new(buffer) ";
475+
syntaxPrinter.printBaseName(ED);
476+
os << "(*this);\n";
477+
os << " char * _Nonnull payloadFromDestruction = "
478+
"thisCopy->_destructiveProjectEnumData();\n";
479+
if (auto knownCxxType =
480+
owningPrinter.typeMapping.getKnownCxxTypeInfo(firstTypeDecl)) {
481+
os << " ";
482+
clangFuncPrinter.printClangFunctionReturnType(
483+
firstType, optKind, firstTypeDecl->getModuleContext(),
484+
owningPrinter.outputLang);
485+
os << " result;\n";
486+
os << " "
487+
"memcpy(&result, payloadFromDestruction, sizeof(result));\n";
488+
os << " return result;\n";
489+
} else {
490+
os << " return ";
491+
syntaxPrinter.printModuleNamespaceQualifiersIfNeeded(
492+
firstTypeDecl->getModuleContext(), ED->getModuleContext());
493+
os << cxx_synthesis::getCxxImplNamespaceName();
494+
os << "::";
495+
ClangValueTypePrinter::printCxxImplClassName(os, firstTypeDecl);
496+
os << "::returnNewValue([&](char * _Nonnull result) {\n";
497+
os << " " << cxx_synthesis::getCxxImplNamespaceName();
498+
os << "::";
499+
ClangValueTypePrinter::printCxxImplClassName(os, firstTypeDecl);
500+
os << "::initializeWithTake(result, payloadFromDestruction);\n";
501+
os << " });\n";
502+
}
503+
os << " }\n";
439504
}
440505
os << "\n";
441506
});

lib/PrintAsClang/PrintAsClang.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,8 @@ static void writePrologue(raw_ostream &out, ASTContext &ctx,
102102
out << "#include <cstdint>\n"
103103
"#include <cstddef>\n"
104104
"#include <cstdbool>\n"
105-
"#include <cstring>\n";
105+
"#include <cstring>\n"
106+
"#include <new>\n";
106107
out << "#include <stdlib.h>\n";
107108
out << "#if defined(_WIN32)\n#include <malloc.h>\n#endif\n";
108109
},

lib/PrintAsClang/PrintClangFunction.cpp

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,17 @@ class CFunctionSignatureTypePrinter
234234

235235
} // end namespace
236236

237+
void DeclAndTypeClangFunctionPrinter::printClangFunctionReturnType(
238+
Type ty, OptionalTypeKind optKind, ModuleDecl *moduleContext,
239+
OutputLanguageMode outputLang) {
240+
CFunctionSignatureTypePrinter typePrinter(
241+
os, cPrologueOS, typeMapping, outputLang, interopContext,
242+
CFunctionSignatureTypePrinterModifierDelegate(), moduleContext,
243+
FunctionSignatureTypeUse::ReturnType);
244+
// Param for indirect return cannot be marked as inout
245+
typePrinter.visit(ty, optKind, /*isInOutParam=*/false);
246+
}
247+
237248
void DeclAndTypeClangFunctionPrinter::printFunctionSignature(
238249
const AbstractFunctionDecl *FD, StringRef name, Type resultTy,
239250
FunctionSignatureKind kind, ArrayRef<AdditionalParam> additionalParams,
@@ -279,12 +290,7 @@ void DeclAndTypeClangFunctionPrinter::printFunctionSignature(
279290
Type objTy;
280291
std::tie(objTy, retKind) =
281292
DeclAndTypePrinter::getObjectTypeAndOptionality(FD, resultTy);
282-
CFunctionSignatureTypePrinter typePrinter(
283-
os, cPrologueOS, typeMapping, outputLang, interopContext,
284-
CFunctionSignatureTypePrinterModifierDelegate(), emittedModule,
285-
FunctionSignatureTypeUse::ReturnType);
286-
// Param for indirect return cannot be marked as inout
287-
typePrinter.visit(objTy, retKind, /*isInOutParam=*/false);
293+
printClangFunctionReturnType(objTy, retKind, emittedModule, outputLang);
288294
} else {
289295
os << "void";
290296
}

lib/PrintAsClang/PrintClangFunction.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,10 @@
1313
#ifndef SWIFT_PRINTASCLANG_PRINTCLANGFUNCTION_H
1414
#define SWIFT_PRINTASCLANG_PRINTCLANGFUNCTION_H
1515

16+
#include "OutputLanguageMode.h"
1617
#include "swift/AST/Type.h"
1718
#include "swift/Basic/LLVM.h"
19+
#include "swift/ClangImporter/ClangImporter.h"
1820
#include "llvm/ADT/ArrayRef.h"
1921
#include "llvm/ADT/Optional.h"
2022
#include "llvm/ADT/StringRef.h"
@@ -103,6 +105,11 @@ class DeclAndTypeClangFunctionPrinter {
103105
StringRef swiftSymbolName, Type resultTy,
104106
bool isDefinition);
105107

108+
/// Print Swift type as C/C++ type, as the return type of a C/C++ function.
109+
void printClangFunctionReturnType(Type ty, OptionalTypeKind optKind,
110+
ModuleDecl *moduleContext,
111+
OutputLanguageMode outputLang);
112+
106113
private:
107114
void printCxxToCFunctionParameterUse(
108115
Type type, StringRef name, const ModuleDecl *moduleContext, bool isInOut,

lib/PrintAsClang/PrintClangValueType.cpp

Lines changed: 58 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -44,14 +44,31 @@ static void printCxxTypeName(raw_ostream &os, const NominalTypeDecl *type,
4444
printer.printBaseName(type);
4545
}
4646

47-
/// Print out the C++ type name of the implementation class that provides hidden
48-
/// access to the private class APIs.
49-
static void printCxxImplClassName(raw_ostream &os,
50-
const NominalTypeDecl *type) {
47+
void ClangValueTypePrinter::printCxxImplClassName(raw_ostream &os,
48+
const NominalTypeDecl *type) {
5149
os << "_impl_";
5250
ClangSyntaxPrinter(os).printBaseName(type);
5351
}
5452

53+
void ClangValueTypePrinter::printMetadataAccessAsVariable(
54+
raw_ostream &os, StringRef metadataFuncName, int indent,
55+
StringRef varName) {
56+
ClangSyntaxPrinter printer(os);
57+
os << std::string(indent, ' ') << "auto " << varName << " = "
58+
<< cxx_synthesis::getCxxImplNamespaceName() << "::";
59+
printer.printSwiftTypeMetadataAccessFunctionCall(metadataFuncName);
60+
os << ";\n";
61+
}
62+
63+
void ClangValueTypePrinter::printValueWitnessTableAccessAsVariable(
64+
raw_ostream &os, StringRef metadataFuncName, int indent,
65+
StringRef metadataVarName, StringRef vwTableVarName) {
66+
ClangSyntaxPrinter printer(os);
67+
printMetadataAccessAsVariable(os, metadataFuncName, indent, metadataVarName);
68+
printer.printValueWitnessTableAccessSequenceFromTypeMetadata(
69+
metadataVarName, vwTableVarName, indent);
70+
}
71+
5572
static void
5673
printCValueTypeStorageStruct(raw_ostream &os, const NominalTypeDecl *typeDecl,
5774
IRABIDetailsProvider::SizeAndAlignment layout) {
@@ -111,6 +128,18 @@ void ClangValueTypePrinter::printValueTypeDecl(
111128
typeMetadataFuncName);
112129
});
113130

131+
auto printEnumVWTableVariable = [&](StringRef metadataName = "metadata",
132+
StringRef vwTableName = "vwTable",
133+
StringRef enumVWTableName =
134+
"enumVWTable") {
135+
ClangValueTypePrinter::printValueWitnessTableAccessAsVariable(
136+
os, typeMetadataFuncName);
137+
os << " const auto *" << enumVWTableName << " = reinterpret_cast<";
138+
ClangSyntaxPrinter(os).printSwiftImplQualifier();
139+
os << "EnumValueWitnessTable";
140+
os << " *>(" << vwTableName << ");\n";
141+
};
142+
114143
// Print out the C++ class itself.
115144
os << "class ";
116145
ClangSyntaxPrinter(os).printBaseName(typeDecl);
@@ -121,11 +150,8 @@ void ClangValueTypePrinter::printValueTypeDecl(
121150
os << " inline ~";
122151
printer.printBaseName(typeDecl);
123152
os << "() {\n";
124-
os << " auto metadata = " << cxx_synthesis::getCxxImplNamespaceName()
125-
<< "::";
126-
printer.printSwiftTypeMetadataAccessFunctionCall(typeMetadataFuncName);
127-
os << ";\n";
128-
printer.printValueWitnessTableAccessSequenceFromTypeMetadata("metadata");
153+
ClangValueTypePrinter::printValueWitnessTableAccessAsVariable(
154+
os, typeMetadataFuncName);
129155
os << " vwTable->destroy(_getOpaquePointer(), metadata._0);\n";
130156
os << " }\n";
131157

@@ -134,11 +160,8 @@ void ClangValueTypePrinter::printValueTypeDecl(
134160
os << "(const ";
135161
printer.printBaseName(typeDecl);
136162
os << " &other) {\n";
137-
os << " auto metadata = " << cxx_synthesis::getCxxImplNamespaceName()
138-
<< "::";
139-
printer.printSwiftTypeMetadataAccessFunctionCall(typeMetadataFuncName);
140-
os << ";\n";
141-
printer.printValueWitnessTableAccessSequenceFromTypeMetadata("metadata");
163+
ClangValueTypePrinter::printValueWitnessTableAccessAsVariable(
164+
os, typeMetadataFuncName);
142165
if (isOpaqueLayout) {
143166
os << " _storage = ";
144167
printer.printSwiftImplQualifier();
@@ -176,11 +199,8 @@ void ClangValueTypePrinter::printValueTypeDecl(
176199
os << " _make() {";
177200
if (isOpaqueLayout) {
178201
os << "\n";
179-
os << " auto metadata = " << cxx_synthesis::getCxxImplNamespaceName()
180-
<< "::";
181-
printer.printSwiftTypeMetadataAccessFunctionCall(typeMetadataFuncName);
182-
os << ";\n";
183-
printer.printValueWitnessTableAccessSequenceFromTypeMetadata("metadata");
202+
ClangValueTypePrinter::printValueWitnessTableAccessAsVariable(
203+
os, typeMetadataFuncName);
184204
os << " return ";
185205
printer.printBaseName(typeDecl);
186206
os << "(vwTable);\n }\n";
@@ -200,19 +220,17 @@ void ClangValueTypePrinter::printValueTypeDecl(
200220
os << ".getOpaquePointer()";
201221
os << "; }\n";
202222
os << "\n";
203-
// Print out helper function for getting enum tag for enum type
223+
// Print out helper function for enums
204224
if (isa<EnumDecl>(typeDecl)) {
225+
os << " inline char * _Nonnull _destructiveProjectEnumData() {\n";
226+
printEnumVWTableVariable();
227+
os << " enumVWTable->destructiveProjectEnumData(_getOpaquePointer(), "
228+
"metadata._0);\n";
229+
os << " return _getOpaquePointer();\n";
230+
os << " }\n";
205231
// FIXME: (tongjie) return type should be unsigned
206232
os << " inline int _getEnumTag() const {\n";
207-
os << " auto metadata = " << cxx_synthesis::getCxxImplNamespaceName()
208-
<< "::";
209-
printer.printSwiftTypeMetadataAccessFunctionCall(typeMetadataFuncName);
210-
os << ";\n";
211-
printer.printValueWitnessTableAccessSequenceFromTypeMetadata("metadata");
212-
os << " const auto *enumVWTable = reinterpret_cast<";
213-
ClangSyntaxPrinter(os).printSwiftImplQualifier();
214-
os << "EnumValueWitnessTable";
215-
os << " *>(vwTable);\n";
233+
printEnumVWTableVariable();
216234
os << " return enumVWTable->getEnumTag(_getOpaquePointer(), "
217235
"metadata._0);\n";
218236
os << " }\n";
@@ -259,6 +277,17 @@ void ClangValueTypePrinter::printValueTypeDecl(
259277
os << " callable(result._getOpaquePointer());\n";
260278
os << " return result;\n";
261279
os << " }\n";
280+
// Print out helper function for initializeWithTake
281+
// TODO: (tongjie) support opaque layout
282+
if (!isOpaqueLayout) {
283+
os << " static inline void initializeWithTake(char * _Nonnull "
284+
"destStorage, char * _Nonnull srcStorage) {\n";
285+
ClangValueTypePrinter::printValueWitnessTableAccessAsVariable(
286+
os, typeMetadataFuncName);
287+
os << " vwTable->initializeWithTake(destStorage, srcStorage, "
288+
"metadata._0);\n";
289+
os << " }\n";
290+
}
262291

263292
os << "};\n";
264293
});

lib/PrintAsClang/PrintClangValueType.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,24 @@ class ClangValueTypePrinter {
7676
const ModuleDecl *moduleContext,
7777
llvm::function_ref<void()> bodyPrinter);
7878

79+
/// Print out the C++ type name of the implementation class that provides
80+
/// hidden access to the private class APIs.
81+
static void printCxxImplClassName(raw_ostream &os,
82+
const NominalTypeDecl *type);
83+
84+
/// Print a variable that can be used to access type's metadata function
85+
static void printMetadataAccessAsVariable(raw_ostream &os,
86+
StringRef metadataFuncName,
87+
int indent = 4,
88+
StringRef varName = "metadata");
89+
90+
/// Print a variable that can be used to access type's metadata function and
91+
/// value witness table
92+
static void printValueWitnessTableAccessAsVariable(
93+
raw_ostream &os, StringRef metadataFuncName, int indent = 4,
94+
StringRef metadataVarName = "metadata",
95+
StringRef vwTableVarName = "vwTable");
96+
7997
private:
8098
/// Prints out the C stub name used to pass/return value directly for the
8199
/// given value type.

0 commit comments

Comments
 (0)