From 1b51b60e7266c8ee8136265ee88484ac0b0177bf Mon Sep 17 00:00:00 2001 From: Jordan Rose Date: Sat, 30 Aug 2014 17:27:02 +0000 Subject: [PATCH] [Serialization] Preserve private discriminators through serialization. Part of rdar://problem/17632175 Swift SVN r21611 --- .../Serialization/DeclTypeRecordNodes.def | 2 ++ include/swift/Serialization/ModuleFile.h | 2 ++ include/swift/Serialization/ModuleFormat.h | 9 ++++- lib/Serialization/Deserialization.cpp | 36 +++++++++++++++---- lib/Serialization/ModuleFile.cpp | 5 +-- lib/Serialization/Serialization.cpp | 22 ++++++++++++ .../Inputs/mangling_private_helper.swift | 9 +++++ test/SILGen/mangling_private.swift | 21 +++++++++-- 8 files changed, 94 insertions(+), 12 deletions(-) create mode 100644 test/SILGen/Inputs/mangling_private_helper.swift diff --git a/include/swift/Serialization/DeclTypeRecordNodes.def b/include/swift/Serialization/DeclTypeRecordNodes.def index bc11593a64e..b66d8ba3023 100644 --- a/include/swift/Serialization/DeclTypeRecordNodes.def +++ b/include/swift/Serialization/DeclTypeRecordNodes.def @@ -160,6 +160,8 @@ TRAILING_INFO(GENERIC_PARAM) TRAILING_INFO(GENERIC_REQUIREMENT) TRAILING_INFO(LAST_GENERIC_REQUIREMENT) +OTHER(DISCRIMINATOR, 249) + OTHER(NO_CONFORMANCE, 250) OTHER(NORMAL_PROTOCOL_CONFORMANCE, 251) OTHER(SPECIALIZED_PROTOCOL_CONFORMANCE, 252) diff --git a/include/swift/Serialization/ModuleFile.h b/include/swift/Serialization/ModuleFile.h index cb2ff6fcd88..d1b40d1ad84 100644 --- a/include/swift/Serialization/ModuleFile.h +++ b/include/swift/Serialization/ModuleFile.h @@ -250,6 +250,8 @@ private: std::unique_ptr ClassMembersByName; std::unique_ptr OperatorMethodDecls; + llvm::DenseMap PrivateDiscriminatorsByValue; + TinyPtrVector ImportDecls; using DeclIDVector = SmallVector; diff --git a/include/swift/Serialization/ModuleFormat.h b/include/swift/Serialization/ModuleFormat.h index 62703350282..a1e6a0ce1d6 100644 --- a/include/swift/Serialization/ModuleFormat.h +++ b/include/swift/Serialization/ModuleFormat.h @@ -40,7 +40,7 @@ const uint16_t VERSION_MAJOR = 0; /// Serialized module format minor version number. /// /// When the format changes IN ANY WAY, this number should be incremented. -const uint16_t VERSION_MINOR = 131; +const uint16_t VERSION_MINOR = 132; using DeclID = Fixnum<31>; using DeclIDField = BCFixed<31>; @@ -947,6 +947,13 @@ namespace decls_block { BCFixed<1> // dummy >; + /// Specifies the discriminator string for a private declaration. This + /// identifies the declaration's original source file in some opaque way. + using DiscriminatorLayout = BCRecordLayout< + DISCRIMINATOR, + IdentifierIDField // discriminator string, as an identifier + >; + /// A placeholder for lack of conformance information. Conformances are /// indexed, so simply omitting one would be incorrect. using NoConformanceLayout = BCRecordLayout< diff --git a/lib/Serialization/Deserialization.cpp b/lib/Serialization/Deserialization.cpp index 472508fa2e6..eac7315948e 100644 --- a/lib/Serialization/Deserialization.cpp +++ b/lib/Serialization/Deserialization.cpp @@ -1484,6 +1484,25 @@ Decl *ModuleFile::getDecl(DeclID DID, Optional ForcedContext) { }; unsigned recordID; + class DiscriminatorRAII { + ModuleFile &moduleFile; + Serialized &declOrOffset; + + public: + Identifier discriminator; + + DiscriminatorRAII(ModuleFile &moduleFile, + Serialized &declOrOffset) + : moduleFile(moduleFile), declOrOffset(declOrOffset) {} + + ~DiscriminatorRAII() { + if (!discriminator.empty() && declOrOffset.isComplete()) + if (auto value = dyn_cast_or_null(declOrOffset.get())) + moduleFile.PrivateDiscriminatorsByValue[value] = discriminator; + } + }; + DiscriminatorRAII discriminatorRAII{*this, declOrOffset}; + while (true) { if (entry.Kind != llvm::BitstreamEntry::Record) { // We don't know how to serialize decls represented by sub-blocks. @@ -1614,15 +1633,20 @@ Decl *ModuleFile::getDecl(DeclID DID, Optional ForcedContext) { AddAttribute(Attr); - // Advance bitstream cursor to the next record. - entry = DeclTypeCursor.advance(); + } else if (recordID == decls_block::DISCRIMINATOR) { + IdentifierID discriminatorID; + decls_block::DiscriminatorLayout::readRecord(scratch, discriminatorID); + discriminatorRAII.discriminator = getIdentifier(discriminatorID); - // Prepare to read the next record. - scratch.clear(); - continue; + } else { + break; } - break; + // Advance bitstream cursor to the next record. + entry = DeclTypeCursor.advance(); + + // Prepare to read the next record. + scratch.clear(); } PrettyDeclDeserialization stackTraceEntry( diff --git a/lib/Serialization/ModuleFile.cpp b/lib/Serialization/ModuleFile.cpp index b915ec4174e..73df5d2beb7 100644 --- a/lib/Serialization/ModuleFile.cpp +++ b/lib/Serialization/ModuleFile.cpp @@ -1240,6 +1240,7 @@ Optional ModuleFile::getCommentForDeclByUSR(StringRef USR) { } Identifier ModuleFile::getDiscriminatorForPrivateValue(const ValueDecl *D) { - // FIXME: Actually implement this. - return FileContext->getParentModule()->Name; + Identifier discriminator = PrivateDiscriminatorsByValue.lookup(D); + assert(!discriminator.empty() && "no discriminator found for decl"); + return discriminator; } diff --git a/lib/Serialization/Serialization.cpp b/lib/Serialization/Serialization.cpp index 587f557f797..1af4e724737 100644 --- a/lib/Serialization/Serialization.cpp +++ b/lib/Serialization/Serialization.cpp @@ -1448,6 +1448,26 @@ void Serializer::writeDecl(const Decl *D) { writeDeclAttribute(Attr); } + if (M->Ctx.LangOpts.UsePrivateDiscriminators) { + if (auto *value = dyn_cast(D)) { + if (value->hasAccessibility() && + value->getAccessibility() == Accessibility::Private && + !value->getDeclContext()->isLocalContext()) { + // FIXME: We shouldn't need to encode this for /all/ private decls. + // In theory we can follow the same rules as mangling and only include + // the outermost private context. + auto topLevelContext = value->getDeclContext()->getModuleScopeContext(); + if (auto *enclosingFile = dyn_cast(topLevelContext)) { + Identifier discriminator = + enclosingFile->getDiscriminatorForPrivateValue(value); + unsigned abbrCode = DeclTypeAbbrCodes[DiscriminatorLayout::Code]; + DiscriminatorLayout::emitRecord(Out, ScratchRecord, abbrCode, + addIdentifierRef(discriminator)); + } + } + } + } + switch (D->getKind()) { case DeclKind::Import: llvm_unreachable("import decls should not be serialized"); @@ -2622,6 +2642,8 @@ void Serializer::writeAllDeclsAndTypes() { registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); + + registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); diff --git a/test/SILGen/Inputs/mangling_private_helper.swift b/test/SILGen/Inputs/mangling_private_helper.swift new file mode 100644 index 00000000000..a50fdfc46ba --- /dev/null +++ b/test/SILGen/Inputs/mangling_private_helper.swift @@ -0,0 +1,9 @@ +public class Base { + private func privateMethod() {} +} + +// Demonstrate the need for a vtable entry for privateMethod(). +// This isn't strictly necessary. +private class Subclass : Base { + override private func privateMethod() {} +} diff --git a/test/SILGen/mangling_private.swift b/test/SILGen/mangling_private.swift index 7ebd993aa2f..157adfc059f 100644 --- a/test/SILGen/mangling_private.swift +++ b/test/SILGen/mangling_private.swift @@ -1,11 +1,16 @@ // RUN: rm -rf %t && mkdir %t -// RUN: %swift %s -emit-silgen -enable-private-discriminators | FileCheck %s +// RUN: %swift -emit-module -o %t %S/Inputs/mangling_private_helper.swift -enable-private-discriminators +// RUN: %swift -emit-silgen %S/Inputs/mangling_private_helper.swift -enable-private-discriminators | FileCheck %s -check-prefix=CHECK-BASE + +// RUN: %swift %s -I %t -emit-silgen -enable-private-discriminators | FileCheck %s // RUN: cp %s %t -// RUN: %swift %t/mangling_private.swift -emit-silgen -enable-private-discriminators | FileCheck %s +// RUN: %swift %t/mangling_private.swift -I %t -emit-silgen -enable-private-discriminators | FileCheck %s // RUN: cp %s %t/other_name.swift -// RUN: %swift %t/other_name.swift -emit-silgen -enable-private-discriminators -module-name mangling_private | FileCheck %s -check-prefix=OTHER-NAME +// RUN: %swift %t/other_name.swift -I %t -emit-silgen -enable-private-discriminators -module-name mangling_private | FileCheck %s -check-prefix=OTHER-NAME + +import mangling_private_helper // CHECK-LABEL: sil @_TF16mangling_privateP33_713AFCDB29B710C2AB6F4DF7C1C8FEC911privateFuncFT_Si // OTHER-NAME-LABEL: sil @_TF16mangling_privateP33_AD9C6D430861F1E1D66B54DBCA7CC94B11privateFuncFT_Si @@ -49,3 +54,13 @@ extension PrivateStruct { private func extPrivateMethod() {} } + +// CHECK-LABEL: sil_vtable Sub { +class Sub : Base { + // CHECK-BASE: #Base.privateMethod!1: _TFC23mangling_private_helper4BaseP33_4EEA0BDF28CD79DFD969F8CFAF130D3813privateMethodfS0_FT_T_ + // CHECK-DAG: #Base.privateMethod!1: _TFC23mangling_private_helper4BaseP33_4EEA0BDF28CD79DFD969F8CFAF130D3813privateMethodfS0_FT_T_ + + // CHECK-DAG: #Sub.subMethod!1: _TFC16mangling_private3SubP33_713AFCDB29B710C2AB6F4DF7C1C8FEC99subMethodfS0_FT_T_ + private func subMethod() {} +} // CHECK: {{^[}]$}} +