[lld] r287002 - Refactor symbol version assignmnt code.

Rui Ueyama via llvm-commits llvm-commits at lists.llvm.org
Tue Nov 15 10:41:52 PST 2016


Author: ruiu
Date: Tue Nov 15 12:41:52 2016
New Revision: 287002

URL: http://llvm.org/viewvc/llvm-project?rev=287002&view=rev
Log:
Refactor symbol version assignmnt code.

The code to handle symbol versions is getting tricky and hard to
understand, so it is probably time to simplify it. This patch does
the following.

 - Add `DemangledSyms` variable to SymbolTable so that we don't
   need to pass it around to findDemangled.
 - Define `initDemangledSyms` to initialize the variable lazily.
 - hasExternCpp is removed because we no longer have to initialize
   the map eagerly.
 - scanScriptVersion is split.
 - Comments are updated.

Modified:
    lld/trunk/ELF/SymbolTable.cpp
    lld/trunk/ELF/SymbolTable.h

Modified: lld/trunk/ELF/SymbolTable.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/SymbolTable.cpp?rev=287002&r1=287001&r2=287002&view=diff
==============================================================================
--- lld/trunk/ELF/SymbolTable.cpp (original)
+++ lld/trunk/ELF/SymbolTable.cpp Tue Nov 15 12:41:52 2016
@@ -484,7 +484,7 @@ template <class ELFT> SymbolBody *Symbol
   return SymVector[V.Idx]->body();
 }
 
-// Returns a list of defined symbols that match with a given regex.
+// Returns a list of defined symbols that match with a given pattern.
 template <class ELFT>
 std::vector<SymbolBody *> SymbolTable<ELFT>::findAll(const StringMatcher &M) {
   std::vector<SymbolBody *> Res;
@@ -579,6 +579,8 @@ template <class ELFT> void SymbolTable<E
       B->symbol()->ExportDynamic = true;
 }
 
+// A helper function to set a version to a symbol.
+// Essentially, assigning two different versions to the same symbol is an error.
 static void setVersionId(SymbolBody *Body, StringRef VersionName,
                          StringRef Name, uint16_t Version) {
   if (!Body || Body->isUndefined()) {
@@ -594,47 +596,50 @@ static void setVersionId(SymbolBody *Bod
   Sym->VersionId = Version;
 }
 
-// Returns a map from demangled symbols to symbol objects.
-// The relationship is 1:N instead of 1:1 because with the symbol
-// versioning, more than one symbol may have the same name.
-template <class ELFT>
-std::map<std::string, std::vector<SymbolBody *>>
-SymbolTable<ELFT>::getDemangledSyms() {
-  std::map<std::string, std::vector<SymbolBody *>> Result;
+// Initialize DemangledSyms with a map from demangled symbols to symbol
+// objects. Used to handle "extern C++" directive in version scripts.
+//
+// The map will contain all demangled symbols. That can be very large,
+// and in LLD we generally want to avoid do anything for each symbol.
+// Then, why are we doing this? Here's why.
+//
+// Users can use "extern C++ {}" directive to match against demangled
+// C++ symbols. For example, you can write a pattern such as
+// "llvm::*::foo(int, ?)". Obviously, there's no way to handle this
+// other than trying to match a pattern against all demangled symbols.
+// So, if "extern C++" feature is used, we need to demangle all known
+// symbols.
+template <class ELFT>
+void SymbolTable<ELFT>::initDemangledSyms() {
+  if (DemangledSyms)
+    return;
+  DemangledSyms.emplace();
+
   for (Symbol *Sym : SymVector) {
     SymbolBody *B = Sym->body();
-    Result[demangle(B->getName())].push_back(B);
+    (*DemangledSyms)[demangle(B->getName())].push_back(B);
   }
-  return Result;
 }
 
-static bool hasExternCpp() {
-  for (VersionDefinition &V : Config->VersionDefinitions)
-    for (SymbolVersion Ver : V.Globals)
-      if (Ver.IsExternCpp)
-        return true;
-  return false;
-}
-
-static ArrayRef<SymbolBody *>
-findDemangled(std::map<std::string, std::vector<SymbolBody *>> &D,
-              StringRef Name) {
-  auto I = D.find(Name);
-  if (I != D.end())
+template <class ELFT>
+ArrayRef<SymbolBody *> SymbolTable<ELFT>::findDemangled(StringRef Name) {
+  initDemangledSyms();
+  auto I = DemangledSyms->find(Name);
+  if (I != DemangledSyms->end())
     return I->second;
   return {};
 }
 
-static std::vector<SymbolBody *>
-findAllDemangled(const std::map<std::string, std::vector<SymbolBody *>> &D,
-                 StringMatcher &M) {
+template <class ELFT>
+std::vector<SymbolBody *>
+SymbolTable<ELFT>::findAllDemangled(const StringMatcher &M) {
+  initDemangledSyms();
   std::vector<SymbolBody *> Res;
-  for (auto &P : D) {
-    if (M.match(P.first))
+  for (auto &P : *DemangledSyms)
+    if (M.match(P.first()))
       for (SymbolBody *Body : P.second)
         if (!Body->isUndefined())
           Res.push_back(Body);
-  }
   return Res;
 }
 
@@ -661,6 +666,23 @@ template <class ELFT> void SymbolTable<E
     B->symbol()->VersionId = VER_NDX_GLOBAL;
 }
 
+template <class ELFT>
+void SymbolTable<ELFT>::assignWildcardVersion(SymbolVersion Ver,
+                                              size_t VersionId) {
+  if (!Ver.HasWildcards)
+    return;
+  StringMatcher M({Ver.Name});
+  std::vector<SymbolBody *> Syms =
+      Ver.IsExternCpp ? findAllDemangled(M) : findAll(M);
+
+  // Exact matching takes precendence over fuzzy matching,
+  // so we set a version to a symbol only if no version has been assigned
+  // to the symbol. This behavior is compatible with GNU.
+  for (SymbolBody *B : Syms)
+    if (B->symbol()->VersionId == Config->DefaultSymbolVersion)
+      B->symbol()->VersionId = VersionId;
+}
+
 // This function processes version scripts by updating VersionId
 // member of symbols.
 template <class ELFT> void SymbolTable<ELFT>::scanVersionScript() {
@@ -677,15 +699,6 @@ template <class ELFT> void SymbolTable<E
   // Each version definition has a glob pattern, and all symbols that match
   // with the pattern get that version.
 
-  // Users can use "extern C++ {}" directive to match against demangled
-  // C++ symbols. For example, you can write a pattern such as
-  // "llvm::*::foo(int, ?)". Obviously, there's no way to handle this
-  // other than trying to match a regexp against all demangled symbols.
-  // So, if "extern C++" feature is used, we demangle all known symbols.
-  std::map<std::string, std::vector<SymbolBody *>> Demangled;
-  if (hasExternCpp())
-    Demangled = getDemangledSyms();
-
   // First, we assign versions to exact matching symbols,
   // i.e. version definitions not containing any glob meta-characters.
   for (VersionDefinition &V : Config->VersionDefinitions) {
@@ -695,7 +708,7 @@ template <class ELFT> void SymbolTable<E
 
       StringRef N = Ver.Name;
       if (Ver.IsExternCpp) {
-        for (SymbolBody *B : findDemangled(Demangled, N))
+        for (SymbolBody *B : findDemangled(N))
           setVersionId(B, V.Name, N, V.Id);
         continue;
       }
@@ -712,26 +725,12 @@ template <class ELFT> void SymbolTable<E
   // i.e. version definitions containing glob meta-characters.
   // Note that because the last match takes precedence over previous matches,
   // we iterate over the definitions in the reverse order.
-  auto assignFuzzyVersion = [&](SymbolVersion &Ver, size_t Version) {
-    if (!Ver.HasWildcards)
-      return;
-    StringMatcher M({Ver.Name});
-    std::vector<SymbolBody *> Syms =
-        Ver.IsExternCpp ? findAllDemangled(Demangled, M) : findAll(M);
-    // Exact matching takes precendence over fuzzy matching,
-    // so we set a version to a symbol only if no version has been assigned
-    // to the symbol. This behavior is compatible with GNU.
-    for (SymbolBody *B : Syms)
-      if (B->symbol()->VersionId == Config->DefaultSymbolVersion)
-        B->symbol()->VersionId = Version;
-  };
-
   for (size_t I = Config->VersionDefinitions.size() - 1; I != (size_t)-1; --I) {
     VersionDefinition &V = Config->VersionDefinitions[I];
     for (SymbolVersion &Ver : V.Locals)
-      assignFuzzyVersion(Ver, VER_NDX_LOCAL);
+      assignWildcardVersion(Ver, VER_NDX_LOCAL);
     for (SymbolVersion &Ver : V.Globals)
-      assignFuzzyVersion(Ver, V.Id);
+      assignWildcardVersion(Ver, V.Id);
   }
 }
 

Modified: lld/trunk/ELF/SymbolTable.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/SymbolTable.h?rev=287002&r1=287001&r2=287002&view=diff
==============================================================================
--- lld/trunk/ELF/SymbolTable.h (original)
+++ lld/trunk/ELF/SymbolTable.h Tue Nov 15 12:41:52 2016
@@ -98,8 +98,12 @@ private:
                                    uint8_t Visibility, bool CanOmitFromDynSym,
                                    InputFile *File);
 
-  std::map<std::string, std::vector<SymbolBody *>> getDemangledSyms();
+  ArrayRef<SymbolBody *> findDemangled(StringRef Name);
+  std::vector<SymbolBody *> findAllDemangled(const StringMatcher &M);
+
+  void initDemangledSyms();
   void handleAnonymousVersion();
+  void assignWildcardVersion(SymbolVersion Ver, size_t VersionId);
 
   struct SymIndex {
     SymIndex(int Idx, bool Traced) : Idx(Idx), Traced(Traced) {}
@@ -130,6 +134,13 @@ private:
   // Set of .so files to not link the same shared object file more than once.
   llvm::DenseSet<StringRef> SoNames;
 
+  // A map from demangled symbol names to their symbol objects.
+  // This mapping is 1:N because two symbols with different versions
+  // can have the same name. We use this map to handle "extern C++ {}"
+  // directive in version scripts.
+  llvm::Optional<llvm::StringMap<std::vector<SymbolBody *>>> DemangledSyms;
+
+  // For LTO.
   std::unique_ptr<BitcodeCompiler> Lto;
 };
 




More information about the llvm-commits mailing list