diff options
author | Reid Kleckner <reid@kleckner.net> | 2013-09-10 20:14:30 +0000 |
---|---|---|
committer | Reid Kleckner <reid@kleckner.net> | 2013-09-10 20:14:30 +0000 |
commit | d8110b6558ad111a1c1c1542c12122900791311e (patch) | |
tree | f33978db28811dcedd14fcba833b925738598b84 /clang/lib/AST | |
parent | 1cee407a9b5cec3251157378e9d44dacae51b68d (diff) | |
download | bcm5719-llvm-d8110b6558ad111a1c1c1542c12122900791311e.tar.gz bcm5719-llvm-d8110b6558ad111a1c1c1542c12122900791311e.zip |
[ms-cxxabi] Implement guard variables for static initialization
Static locals requiring initialization are not thread safe on Windows.
Unfortunately, it's possible to create static locals that are actually
externally visible with inline functions and templates. As a result, we
have to implement an initialization guard scheme that is compatible with
TUs built by MSVC, which makes thread safety prohibitively difficult.
MSVC's scheme is that every function that requires a guard gets an i32
bitfield. Each static local is assigned a bit that indicates if it has
been initialized, up to 32 bits, at which point a new bitfield is
created. MSVC rejects inline functions with more than 32 static locals,
and the externally visible mangling (?_B) only allows for one guard
variable per function.
On Eli's recommendation, I used MangleNumberingContext to track which
bit each static corresponds to.
Implements PR16888.
Reviewers: rjmccall, eli.friedman
Differential Revision: http://llvm-reviews.chandlerc.com/D1416
llvm-svn: 190427
Diffstat (limited to 'clang/lib/AST')
-rw-r--r-- | clang/lib/AST/ASTContext.cpp | 17 | ||||
-rw-r--r-- | clang/lib/AST/CXXABI.h | 8 | ||||
-rw-r--r-- | clang/lib/AST/ItaniumCXXABI.cpp | 18 | ||||
-rw-r--r-- | clang/lib/AST/ItaniumMangle.cpp | 18 | ||||
-rw-r--r-- | clang/lib/AST/MangleNumberingContext.cpp | 5 | ||||
-rw-r--r-- | clang/lib/AST/MicrosoftCXXABI.cpp | 21 | ||||
-rw-r--r-- | clang/lib/AST/MicrosoftMangle.cpp | 41 |
7 files changed, 113 insertions, 15 deletions
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 85ac734a45c..4ab987d844f 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -25,6 +25,7 @@ #include "clang/AST/ExprCXX.h" #include "clang/AST/ExternalASTSource.h" #include "clang/AST/Mangle.h" +#include "clang/AST/MangleNumberingContext.h" #include "clang/AST/RecordLayout.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/TypeLoc.h" @@ -766,6 +767,12 @@ ASTContext::~ASTContext() { AEnd = DeclAttrs.end(); A != AEnd; ++A) A->second->~AttrVec(); + + for (llvm::DenseMap<const DeclContext *, MangleNumberingContext *>::iterator + I = MangleNumberingContexts.begin(), + E = MangleNumberingContexts.end(); + I != E; ++I) + delete I->second; } void ASTContext::AddDeallocation(void (*Callback)(void*), void *Data) { @@ -8037,7 +8044,15 @@ unsigned ASTContext::getManglingNumber(const NamedDecl *ND) const { MangleNumberingContext & ASTContext::getManglingNumberContext(const DeclContext *DC) { - return MangleNumberingContexts[DC]; + assert(LangOpts.CPlusPlus); // We don't need mangling numbers for plain C. + MangleNumberingContext *&MCtx = MangleNumberingContexts[DC]; + if (!MCtx) + MCtx = createMangleNumberingContext(); + return *MCtx; +} + +MangleNumberingContext *ASTContext::createMangleNumberingContext() const { + return ABI->createMangleNumberingContext(); } void ASTContext::setParameterIndex(const ParmVarDecl *D, unsigned int index) { diff --git a/clang/lib/AST/CXXABI.h b/clang/lib/AST/CXXABI.h index 6d67d9a12b5..89203f18ca7 100644 --- a/clang/lib/AST/CXXABI.h +++ b/clang/lib/AST/CXXABI.h @@ -21,6 +21,7 @@ namespace clang { class ASTContext; class MemberPointerType; +class MangleNumberingContext; /// Implements C++ ABI-specific semantic analysis functions. class CXXABI { @@ -34,9 +35,12 @@ public: /// Returns the default calling convention for C++ methods. virtual CallingConv getDefaultMethodCallConv(bool isVariadic) const = 0; - // Returns whether the given class is nearly empty, with just virtual pointers - // and no data except possibly virtual bases. + /// Returns whether the given class is nearly empty, with just virtual + /// pointers and no data except possibly virtual bases. virtual bool isNearlyEmpty(const CXXRecordDecl *RD) const = 0; + + /// Returns a new mangling number context for this C++ ABI. + virtual MangleNumberingContext *createMangleNumberingContext() const = 0; }; /// Creates an instance of a C++ ABI class. diff --git a/clang/lib/AST/ItaniumCXXABI.cpp b/clang/lib/AST/ItaniumCXXABI.cpp index 894eb3bff5f..578466028ce 100644 --- a/clang/lib/AST/ItaniumCXXABI.cpp +++ b/clang/lib/AST/ItaniumCXXABI.cpp @@ -20,6 +20,7 @@ #include "CXXABI.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclCXX.h" +#include "clang/AST/MangleNumberingContext.h" #include "clang/AST/RecordLayout.h" #include "clang/AST/Type.h" #include "clang/Basic/TargetInfo.h" @@ -27,6 +28,19 @@ using namespace clang; namespace { + +/// \brief Keeps track of the mangled names of lambda expressions and block +/// literals within a particular context. +class ItaniumNumberingContext : public MangleNumberingContext { + llvm::DenseMap<IdentifierInfo*, unsigned> VarManglingNumbers; + +public: + /// Variable decls are numbered by identifier. + virtual unsigned getManglingNumber(const VarDecl *VD) { + return ++VarManglingNumbers[VD->getIdentifier()]; + } +}; + class ItaniumCXXABI : public CXXABI { protected: ASTContext &Context; @@ -61,6 +75,10 @@ public: Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(0)); return Layout.getNonVirtualSize() == PointerSize; } + + virtual MangleNumberingContext *createMangleNumberingContext() const { + return new ItaniumNumberingContext(); + } }; class ARMCXXABI : public ItaniumCXXABI { diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp index c3121c0b53c..1d8a311c614 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -152,7 +152,8 @@ public: void mangleCXXDtor(const CXXDestructorDecl *D, CXXDtorType Type, raw_ostream &); - void mangleItaniumGuardVariable(const VarDecl *D, raw_ostream &); + void mangleStaticGuardVariable(const VarDecl *D, raw_ostream &); + void mangleDynamicAtExitDestructor(const VarDecl *D, raw_ostream &Out); void mangleItaniumThreadLocalInit(const VarDecl *D, raw_ostream &); void mangleItaniumThreadLocalWrapper(const VarDecl *D, raw_ostream &); @@ -3691,8 +3692,8 @@ ItaniumMangleContext::mangleCXXDtorThunk(const CXXDestructorDecl *DD, /// mangleGuardVariable - Returns the mangled name for a guard variable /// for the passed in VarDecl. -void ItaniumMangleContext::mangleItaniumGuardVariable(const VarDecl *D, - raw_ostream &Out) { +void ItaniumMangleContext::mangleStaticGuardVariable(const VarDecl *D, + raw_ostream &Out) { // <special-name> ::= GV <object name> # Guard variable for one-time // # initialization CXXNameMangler Mangler(*this, Out); @@ -3700,6 +3701,17 @@ void ItaniumMangleContext::mangleItaniumGuardVariable(const VarDecl *D, Mangler.mangleName(D); } +void ItaniumMangleContext::mangleDynamicAtExitDestructor(const VarDecl *D, + raw_ostream &Out) { + // Prefix the mangling of D with __dtor_. + CXXNameMangler Mangler(*this, Out); + Mangler.getStream() << "__dtor_"; + if (shouldMangleDeclName(D)) + Mangler.mangle(D); + else + Mangler.getStream() << D->getName(); +} + void ItaniumMangleContext::mangleItaniumThreadLocalInit(const VarDecl *D, raw_ostream &Out) { // <special-name> ::= TH <object name> diff --git a/clang/lib/AST/MangleNumberingContext.cpp b/clang/lib/AST/MangleNumberingContext.cpp index 4e9006ec24a..91ef0e2240d 100644 --- a/clang/lib/AST/MangleNumberingContext.cpp +++ b/clang/lib/AST/MangleNumberingContext.cpp @@ -38,11 +38,6 @@ MangleNumberingContext::getManglingNumber(const BlockDecl *BD) { } unsigned -MangleNumberingContext::getManglingNumber(const VarDecl *VD) { - return ++VarManglingNumbers[VD->getIdentifier()]; -} - -unsigned MangleNumberingContext::getManglingNumber(const TagDecl *TD) { return ++TagManglingNumbers[TD->getIdentifier()]; } diff --git a/clang/lib/AST/MicrosoftCXXABI.cpp b/clang/lib/AST/MicrosoftCXXABI.cpp index fd932f7330a..4a93ea1f417 100644 --- a/clang/lib/AST/MicrosoftCXXABI.cpp +++ b/clang/lib/AST/MicrosoftCXXABI.cpp @@ -16,6 +16,7 @@ #include "clang/AST/Attr.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclCXX.h" +#include "clang/AST/MangleNumberingContext.h" #include "clang/AST/RecordLayout.h" #include "clang/AST/Type.h" #include "clang/Basic/TargetInfo.h" @@ -23,6 +24,22 @@ using namespace clang; namespace { + +/// \brief Numbers things which need to correspond across multiple TUs. +/// Typically these are things like static locals, lambdas, or blocks. +class MicrosoftNumberingContext : public MangleNumberingContext { + unsigned NumStaticLocals; + +public: + MicrosoftNumberingContext() : NumStaticLocals(0) { } + + /// Static locals are numbered by source order. + virtual unsigned getManglingNumber(const VarDecl *VD) { + assert(VD->isStaticLocal()); + return ++NumStaticLocals; + } +}; + class MicrosoftCXXABI : public CXXABI { ASTContext &Context; public: @@ -51,6 +68,10 @@ public: return Layout.getNonVirtualSize() == PointerSize || Layout.getNonVirtualSize() == PointerSize * 2; } + + MangleNumberingContext *createMangleNumberingContext() const { + return new MicrosoftNumberingContext(); + } }; } diff --git a/clang/lib/AST/MicrosoftMangle.cpp b/clang/lib/AST/MicrosoftMangle.cpp index 78fa543979b..7e3d6c21395 100644 --- a/clang/lib/AST/MicrosoftMangle.cpp +++ b/clang/lib/AST/MicrosoftMangle.cpp @@ -92,6 +92,7 @@ public: QualifierMangleMode QMM = QMM_Mangle); void mangleFunctionType(const FunctionType *T, const FunctionDecl *D, bool IsStructor, bool IsInstMethod); + void manglePostfix(const DeclContext *DC, bool NoFunction = false); private: void disableBackReferences() { UseNameBackReferences = false; } @@ -100,7 +101,6 @@ private: } void mangleUnqualifiedName(const NamedDecl *ND, DeclarationName Name); void mangleSourceName(const IdentifierInfo *II); - void manglePostfix(const DeclContext *DC, bool NoFunction=false); void mangleOperatorName(OverloadedOperatorKind OO, SourceLocation Loc); void mangleCXXDtorType(CXXDtorType T); void mangleQualifiers(Qualifiers Quals, bool IsMember); @@ -168,8 +168,10 @@ public: raw_ostream &); virtual void mangleCXXDtor(const CXXDestructorDecl *D, CXXDtorType Type, raw_ostream &); - virtual void mangleReferenceTemporary(const clang::VarDecl *, - raw_ostream &); + virtual void mangleReferenceTemporary(const VarDecl *, raw_ostream &); + virtual void mangleStaticGuardVariable(const VarDecl *D, raw_ostream &Out); + virtual void mangleDynamicAtExitDestructor(const VarDecl *D, + raw_ostream &Out); }; } @@ -1912,13 +1914,44 @@ void MicrosoftMangleContext::mangleCXXDtor(const CXXDestructorDecl *D, MicrosoftCXXNameMangler mangler(*this, Out, D, Type); mangler.mangle(D); } -void MicrosoftMangleContext::mangleReferenceTemporary(const clang::VarDecl *VD, +void MicrosoftMangleContext::mangleReferenceTemporary(const VarDecl *VD, raw_ostream &) { unsigned DiagID = getDiags().getCustomDiagID(DiagnosticsEngine::Error, "cannot mangle this reference temporary yet"); getDiags().Report(VD->getLocation(), DiagID); } +void MicrosoftMangleContext::mangleStaticGuardVariable(const VarDecl *VD, + raw_ostream &Out) { + // <guard-name> ::= ?_B <postfix> @51 + // ::= ?$S <guard-num> @ <postfix> @4IA + + // The first mangling is what MSVC uses to guard static locals in inline + // functions. It uses a different mangling in external functions to support + // guarding more than 32 variables. MSVC rejects inline functions with more + // than 32 static locals. We don't fully implement the second mangling + // because those guards are not externally visible, and instead use LLVM's + // default renaming when creating a new guard variable. + MicrosoftCXXNameMangler Mangler(*this, Out); + + bool Visible = VD->isExternallyVisible(); + // <operator-name> ::= ?_B # local static guard + Mangler.getStream() << (Visible ? "\01??_B" : "\01?$S1@"); + Mangler.manglePostfix(VD->getDeclContext()); + Mangler.getStream() << (Visible ? "@51" : "@4IA"); +} + +void MicrosoftMangleContext::mangleDynamicAtExitDestructor(const VarDecl *D, + raw_ostream &Out) { + // <destructor-name> ::= ?__F <postfix> YAXXZ + MicrosoftCXXNameMangler Mangler(*this, Out); + Mangler.getStream() << "\01??__F"; + Mangler.mangleName(D); + // This is the mangling of the function type of the stub, which is a global, + // non-variadic, cdecl function that returns void and takes no args. + Mangler.getStream() << "YAXXZ"; +} + MangleContext *clang::createMicrosoftMangleContext(ASTContext &Context, DiagnosticsEngine &Diags) { return new MicrosoftMangleContext(Context, Diags); |