Skip to content

Commit 04a3bef

Browse files
authored
Merge pull request #9432 from eeckstein/archive-attrs
Archive attributes and runtime support for it
2 parents d92a8a9 + 48f7502 commit 04a3bef

23 files changed

+700
-17
lines changed

include/swift/AST/Attr.def

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,19 @@ DECL_ATTR(_implements, Implements,
273273
| NotSerialized | UserInaccessible,
274274
/* Not serialized */ 67)
275275

276+
DECL_ATTR(NSKeyedArchiveLegacy, NSKeyedArchiveLegacy,
277+
OnClass | NotSerialized | LongAttribute,
278+
/*Not serialized */ 68)
279+
280+
SIMPLE_DECL_ATTR(_staticInitializeObjCMetadata, StaticInitializeObjCMetadata,
281+
OnClass | NotSerialized | LongAttribute | UserInaccessible,
282+
/*Not serialized */ 69)
283+
284+
SIMPLE_DECL_ATTR(NSKeyedArchiveSubclassesOnly,
285+
NSKeyedArchiveSubclassesOnly,
286+
OnClass | NotSerialized | LongAttribute,
287+
/*Not serialized */ 70)
288+
276289
#undef TYPE_ATTR
277290
#undef DECL_ATTR_ALIAS
278291
#undef SIMPLE_DECL_ATTR

include/swift/AST/Attr.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1158,6 +1158,24 @@ class ImplementsAttr : public DeclAttribute {
11581158
}
11591159
};
11601160

1161+
/// Defines the @NSKeyedArchiveLegacyAttr attribute.
1162+
class NSKeyedArchiveLegacyAttr : public DeclAttribute {
1163+
public:
1164+
NSKeyedArchiveLegacyAttr(StringRef Name, SourceLoc AtLoc, SourceRange Range, bool Implicit)
1165+
: DeclAttribute(DAK_NSKeyedArchiveLegacy, AtLoc, Range, Implicit),
1166+
Name(Name) {}
1167+
1168+
NSKeyedArchiveLegacyAttr(StringRef Name, bool Implicit)
1169+
: NSKeyedArchiveLegacyAttr(Name, SourceLoc(), SourceRange(), /*Implicit=*/true) {}
1170+
1171+
/// The legacy mangled name.
1172+
const StringRef Name;
1173+
1174+
static bool classof(const DeclAttribute *DA) {
1175+
return DA->getKind() == DAK_NSKeyedArchiveLegacy;
1176+
}
1177+
};
1178+
11611179
/// \brief Attributes that may be applied to declarations.
11621180
class DeclAttributes {
11631181
/// Linked list of declaration attributes.

include/swift/AST/DiagnosticsSema.def

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1212,6 +1212,28 @@ ERROR(pattern_binds_no_variables,none,
12121212
"variables",
12131213
(unsigned))
12141214

1215+
ERROR(nscoding_unstable_mangled_name,none,
1216+
"%select{private|fileprivate|nested|local|generic}0 class %1 has an "
1217+
"unstable name when archiving via 'NSCoding'",
1218+
(unsigned, Type))
1219+
WARNING(nscoding_unstable_mangled_name_warn,none,
1220+
"%select{private|fileprivate|nested|local|generic}0 class %1 has an "
1221+
"unstable name when archiving via 'NSCoding'",
1222+
(unsigned, Type))
1223+
NOTE(unstable_mangled_name_add_objc,none,
1224+
"for new classes, add '@objc' to specify a unique, prefixed Objective-C "
1225+
"runtime name", ())
1226+
NOTE(unstable_mangled_name_add_nskeyedarchivelegacy,none,
1227+
"for compatibility with existing archives, use '@NSKeyedArchiveLegacy' "
1228+
"to record the Swift 3 mangled name", ())
1229+
NOTE(add_nskeyedarchivesubclassesonly_attr,none,
1230+
"generic classes should not be archived directly; "
1231+
"add @NSKeyedArchiveSubclassesOnly "
1232+
"and only archive specific subclasses of this class", (Type))
1233+
1234+
ERROR(attr_nskeyedarchivelegacy_generic,none,
1235+
"'@NSKeyedArchiveLegacy' cannot be applied to generic class %0",
1236+
(Type))
12151237

12161238
// Generic types
12171239
ERROR(unsupported_type_nested_in_generic_function,none,

include/swift/Runtime/RuntimeFunctions.def

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1217,6 +1217,14 @@ FUNCTION(GetKeyPath, swift_getKeyPath, C_CC,
12171217
ARGS(Int8PtrTy, Int8PtrTy),
12181218
ATTRS(NoUnwind))
12191219

1220+
// func _registerClassNameForArchiving(_ nameOrNull: UnsafePointer<CChar>?,
1221+
// _ c: AnyClass)
1222+
FUNCTION(RegisterClassNameForArchiving, swift_registerClassNameForArchiving,
1223+
SwiftCC,
1224+
RETURNS(VoidTy),
1225+
ARGS(Int8PtrTy, TypeMetadataPtrTy),
1226+
ATTRS(NoUnwind))
1227+
12201228
#if SWIFT_OBJC_INTEROP || !defined(SWIFT_RUNTIME_GENERATE_GLOBAL_SYMBOLS)
12211229

12221230
// Put here all definitions of runtime functions which are:

include/swift/Serialization/ModuleFormat.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1314,6 +1314,8 @@ namespace decls_block {
13141314
using SynthesizedProtocolDeclAttrLayout
13151315
= BCRecordLayout<SynthesizedProtocol_DECL_ATTR>;
13161316
using ImplementsDeclAttrLayout = BCRecordLayout<Implements_DECL_ATTR>;
1317+
using NSKeyedArchiveLegacyDeclAttrLayout
1318+
= BCRecordLayout<NSKeyedArchiveLegacy_DECL_ATTR>;
13171319

13181320
using InlineDeclAttrLayout = BCRecordLayout<
13191321
Inline_DECL_ATTR,

lib/AST/ASTDumper.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -855,6 +855,8 @@ namespace {
855855

856856
void visitClassDecl(ClassDecl *CD) {
857857
printCommon(CD, "class_decl");
858+
if (CD->getAttrs().hasAttribute<StaticInitializeObjCMetadataAttr>())
859+
OS << " @_staticInitializeObjCMetadata";
858860
printInherited(CD->getInherited());
859861
for (Decl *D : CD->getMembers()) {
860862
OS << '\n';

lib/AST/Attr.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -493,6 +493,19 @@ bool DeclAttribute::printImpl(ASTPrinter &Printer, const PrintOptions &Options,
493493
break;
494494
}
495495

496+
case DAK_NSKeyedArchiveLegacy: {
497+
Printer.printAttrName("@NSKeyedArchiveLegacy");
498+
Printer << "(";
499+
auto *attr = cast<NSKeyedArchiveLegacyAttr>(this);
500+
Printer << "\"" << attr->Name << "\"";
501+
Printer << ")";
502+
break;
503+
}
504+
505+
case DAK_StaticInitializeObjCMetadata:
506+
Printer.printAttrName("@_staticInitializeObjCMetadata");
507+
break;
508+
496509
case DAK_Count:
497510
llvm_unreachable("exceed declaration attribute kinds");
498511

@@ -609,6 +622,8 @@ StringRef DeclAttribute::getAttrName() const {
609622
return "_specialize";
610623
case DAK_Implements:
611624
return "_implements";
625+
case DAK_NSKeyedArchiveLegacy:
626+
return "NSKeyedArchiveLegacy";
612627
}
613628
llvm_unreachable("bad DeclAttrKind");
614629
}

lib/IRGen/GenClass.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -960,6 +960,9 @@ void IRGenModule::emitClassDecl(ClassDecl *D) {
960960
emitClassMetadata(*this, D,
961961
classTI.getLayout(*this, selfType),
962962
classTI.getClassLayout(*this, selfType));
963+
964+
IRGen.addClassForArchiveNameRegistration(D);
965+
963966
emitNestedTypeDecls(D->getMembers());
964967
emitFieldMetadataRecord(D);
965968
}

lib/IRGen/GenDecl.cpp

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,11 @@
4141
#include "llvm/IR/Module.h"
4242
#include "llvm/IR/TypeBuilder.h"
4343
#include "llvm/IR/Value.h"
44+
#include "llvm/IR/InlineAsm.h"
4445
#include "llvm/Support/Compiler.h"
4546
#include "llvm/Support/ConvertUTF.h"
4647
#include "llvm/Support/Path.h"
48+
#include "llvm/Transforms/Utils/ModuleUtils.h"
4749

4850
#include "ConstantBuilder.h"
4951
#include "Explosion.h"
@@ -947,6 +949,56 @@ void IRGenerator::emitLazyDefinitions() {
947949
}
948950
}
949951

952+
void IRGenerator::emitNSArchiveClassNameRegistration() {
953+
if (ClassesForArchiveNameRegistration.empty())
954+
return;
955+
956+
// Emit the register function in the primary module.
957+
IRGenModule *IGM = getPrimaryIGM();
958+
959+
llvm::Function *RegisterFn = llvm::Function::Create(
960+
llvm::FunctionType::get(IGM->VoidTy, false),
961+
llvm::GlobalValue::InternalLinkage,
962+
"_swift_register_class_names_for_archives");
963+
IRGenFunction RegisterIGF(*IGM, RegisterFn);
964+
RegisterFn->setAttributes(IGM->constructInitialAttributes());
965+
IGM->Module.getFunctionList().push_back(RegisterFn);
966+
RegisterFn->setCallingConv(IGM->DefaultCC);
967+
968+
for (ClassDecl *CD : ClassesForArchiveNameRegistration) {
969+
Type Ty = CD->getDeclaredType();
970+
llvm::Value *MetaData = RegisterIGF.emitTypeMetadataRef(getAsCanType(Ty));
971+
if (auto *LegacyAttr = CD->getAttrs().
972+
getAttribute<NSKeyedArchiveLegacyAttr>()) {
973+
// Register the name for the class in the NSKeyed(Un)Archiver.
974+
llvm::Value *NameStr = IGM->getAddrOfGlobalString(LegacyAttr->Name);
975+
RegisterIGF.Builder.CreateCall(IGM->getRegisterClassNameForArchivingFn(),
976+
{NameStr, MetaData});
977+
} else {
978+
assert(CD->getAttrs().hasAttribute<StaticInitializeObjCMetadataAttr>());
979+
980+
// In this case we don't add a name mapping, but just get the metadata
981+
// to make sure that the class is registered. But: we need to add a use
982+
// (empty inline asm instruction) for the metadata. Otherwise
983+
// llvm would optimize the metadata accessor call away because it's
984+
// defined as "readnone".
985+
llvm::FunctionType *asmFnTy =
986+
llvm::FunctionType::get(IGM->VoidTy, {MetaData->getType()},
987+
false /* = isVarArg */);
988+
llvm::InlineAsm *inlineAsm =
989+
llvm::InlineAsm::get(asmFnTy, "", "r", true /* = SideEffects */);
990+
RegisterIGF.Builder.CreateCall(inlineAsm, MetaData);
991+
}
992+
}
993+
RegisterIGF.Builder.CreateRetVoid();
994+
995+
// Add the registration function as a static initializer. We use a priority
996+
// slightly lower than used for C++ global constructors, so that the code is
997+
// executed before C++ global constructors (in case someone uses archives
998+
// from a C++ global constructor).
999+
llvm::appendToGlobalCtors(IGM->Module, RegisterFn, 60000, nullptr);
1000+
}
1001+
9501002
/// Emit symbols for eliminated dead methods, which can still be referenced
9511003
/// from other modules. This happens e.g. if a public class contains a (dead)
9521004
/// private method.

lib/IRGen/IRGen.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -715,6 +715,7 @@ static std::unique_ptr<llvm::Module> performIRGeneration(IRGenOptions &Opts,
715715
IGM.emitTypeMetadataRecords();
716716
IGM.emitBuiltinReflectionMetadata();
717717
IGM.emitReflectionMetadataVersion();
718+
irgen.emitNSArchiveClassNameRegistration();
718719
}
719720

720721
// Emit symbols for eliminated dead methods.
@@ -893,6 +894,8 @@ static void performParallelIRGeneration(IRGenOptions &Opts,
893894

894895
irgen.emitReflectionMetadataVersion();
895896

897+
irgen.emitNSArchiveClassNameRegistration();
898+
896899
// Emit reflection metadata for builtin and imported types.
897900
irgen.emitBuiltinReflectionMetadata();
898901

lib/IRGen/IRGenModule.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -559,6 +559,9 @@ llvm::Constant *swift::getWrapperFn(llvm::Module &Module,
559559
#define FUNCTION_FOR_CONV_C_CC(ID, NAME, CC, RETURNS, ARGS, ATTRS) \
560560
FUNCTION_IMPL(ID, NAME, CC, QUOTE(RETURNS), QUOTE(ARGS), QUOTE(ATTRS))
561561

562+
#define FUNCTION_FOR_CONV_SwiftCC(ID, NAME, CC, RETURNS, ARGS, ATTRS) \
563+
FUNCTION_IMPL(ID, NAME, CC, QUOTE(RETURNS), QUOTE(ARGS), QUOTE(ATTRS))
564+
562565
#define FUNCTION_FOR_CONV_RegisterPreservingCC(ID, NAME, CC, RETURNS, ARGS, \
563566
ATTRS) \
564567
FUNCTION_WITH_GLOBAL_SYMBOL_IMPL(ID, NAME, SWIFT_RT_ENTRY_REF(NAME), CC, \
@@ -749,6 +752,26 @@ void IRGenerator::addLazyWitnessTable(const ProtocolConformance *Conf) {
749752
}
750753
}
751754

755+
void IRGenerator::addClassForArchiveNameRegistration(ClassDecl *ClassDecl) {
756+
757+
// Those two attributes are interesting to us
758+
if (!ClassDecl->getAttrs().hasAttribute<NSKeyedArchiveLegacyAttr>() &&
759+
!ClassDecl->getAttrs().hasAttribute<StaticInitializeObjCMetadataAttr>())
760+
return;
761+
762+
// Exclude some classes where those attributes make no sense but could be set
763+
// for some reason. Just to be on the safe side.
764+
Type ClassTy = ClassDecl->getDeclaredType();
765+
if (ClassTy->is<UnboundGenericType>())
766+
return;
767+
if (ClassTy->hasArchetype())
768+
return;
769+
if (ClassDecl->hasClangNode())
770+
return;
771+
772+
ClassesForArchiveNameRegistration.push_back(ClassDecl);
773+
}
774+
752775
llvm::AttributeSet IRGenModule::getAllocAttrs() {
753776
if (AllocAttrs.isEmpty()) {
754777
AllocAttrs = llvm::AttributeSet::get(LLVMContext,

lib/IRGen/IRGenModule.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,8 @@ class IRGenerator {
222222
/// The queue of lazy witness tables to emit.
223223
llvm::SmallVector<SILWitnessTable *, 4> LazyWitnessTables;
224224

225+
llvm::SmallVector<ClassDecl *, 4> ClassesForArchiveNameRegistration;
226+
225227
/// The order in which all the SIL function definitions should
226228
/// appear in the translation unit.
227229
llvm::DenseMap<SILFunction*, unsigned> FunctionOrder;
@@ -296,6 +298,8 @@ class IRGenerator {
296298
/// Emit a symbol identifying the reflection metadata version.
297299
void emitReflectionMetadataVersion();
298300

301+
void emitNSArchiveClassNameRegistration();
302+
299303
/// Checks if the metadata of \p Nominal can be emitted lazily.
300304
///
301305
/// If yes, \p Nominal is added to eligibleLazyMetadata and true is returned.
@@ -333,7 +337,9 @@ class IRGenerator {
333337
{fieldTypes.begin(), fieldTypes.end()},
334338
fn, IGM});
335339
}
336-
340+
341+
void addClassForArchiveNameRegistration(ClassDecl *ClassDecl);
342+
337343
unsigned getFunctionOrder(SILFunction *F) {
338344
auto it = FunctionOrder.find(F);
339345
assert(it != FunctionOrder.end() &&

lib/Parse/ParseDecl.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -743,7 +743,8 @@ bool Parser::parseNewDeclAttribute(DeclAttributes &Attributes, SourceLoc AtLoc,
743743
}
744744

745745
case DAK_CDecl:
746-
case DAK_SILGenName: {
746+
case DAK_SILGenName:
747+
case DAK_NSKeyedArchiveLegacy: {
747748
if (!consumeIf(tok::l_paren)) {
748749
diagnose(Loc, diag::attr_expected_lparen, AttrName,
749750
DeclAttribute::isDeclModifier(DK));
@@ -786,6 +787,10 @@ bool Parser::parseNewDeclAttribute(DeclAttributes &Attributes, SourceLoc AtLoc,
786787
else if (DK == DAK_CDecl)
787788
Attributes.add(new (Context) CDeclAttr(AsmName.getValue(), AtLoc,
788789
AttrRange, /*Implicit=*/false));
790+
else if (DK == DAK_NSKeyedArchiveLegacy)
791+
Attributes.add(new (Context) NSKeyedArchiveLegacyAttr(
792+
AsmName.getValue(), AtLoc,
793+
AttrRange, /*Implicit=*/false));
789794
else
790795
llvm_unreachable("out of sync with switch");
791796
}

0 commit comments

Comments
 (0)