Add way to represent static archives in yaml test cases.

Add SharedLibraryFile and ArchiveLibraryFile subclasses of File.

Add command line options to lld-core to set various ResolverOptions settings
and added lots of test cases to verify the options work.

llvm-svn: 155183
diff --git a/lld/lib/Core/CMakeLists.txt b/lld/lib/Core/CMakeLists.txt
index 2e39dff..076d335 100644
--- a/lld/lib/Core/CMakeLists.txt
+++ b/lld/lib/Core/CMakeLists.txt
@@ -1,6 +1,7 @@
 add_lld_library(lldCore
   Error.cpp
   File.cpp
+  InputFiles.cpp
   NativeFileFormat.h
   NativeReader.cpp
   NativeWriter.cpp
diff --git a/lld/lib/Core/InputFiles.cpp b/lld/lib/Core/InputFiles.cpp
new file mode 100644
index 0000000..5840151
--- /dev/null
+++ b/lld/lib/Core/InputFiles.cpp
@@ -0,0 +1,84 @@
+//===- Core/InputFiles.cpp - Manages list of Files -----------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lld/Core/InputFiles.h"
+#include "lld/Core/SharedLibraryFile.h"
+#include "lld/Core/ArchiveLibraryFile.h"
+#include "lld/Core/LLVM.h"
+
+namespace lld {
+
+InputFiles::InputFiles() {
+}
+
+
+InputFiles::~InputFiles() {
+}
+
+void InputFiles::forEachInitialAtom(InputFiles::Handler &handler) const {
+  for ( const File *file : _files ) {
+    this->handleFile(file, handler);
+  }
+}
+
+void InputFiles::prependFile(const File &file) {
+  _files.insert(_files.begin(), &file);
+}
+  
+void InputFiles::appendFile(const File &file) {
+  _files.push_back(&file);
+}
+
+
+bool InputFiles::searchLibraries(StringRef name, bool searchSharedLibs,
+                               bool searchArchives, bool dataSymbolOnly,
+                               InputFiles::Handler &handler) const {
+                               
+  for ( const File *file : _files ) {
+    if ( searchSharedLibs ) {
+      if (const SharedLibraryFile *shlib = dyn_cast<SharedLibraryFile>(file)) {
+        if ( const SharedLibraryAtom* shAtom = shlib->exports(name, 
+                                                            dataSymbolOnly) ) {
+          handler.doSharedLibraryAtom(*shAtom);
+          return true;
+        }
+      }
+    }
+    if ( searchArchives ) {
+      if (const ArchiveLibraryFile *lib = dyn_cast<ArchiveLibraryFile>(file)) {
+        if ( const File *member = lib->find(name, dataSymbolOnly) ) {
+          this->handleFile(member, handler);
+          return true;
+        }
+      }
+    }
+  }
+  return false;
+}
+
+
+void InputFiles::handleFile(const File *file, 
+                            InputFiles::Handler &handler) const {
+  handler.doFile(*file);
+  for( const DefinedAtom *atom : file->defined() ) {
+    handler.doDefinedAtom(*atom);
+  }
+  for( const UndefinedAtom *undefAtom : file->undefined() ) {
+    handler.doUndefinedAtom(*undefAtom);
+  }
+  for( const SharedLibraryAtom *shlibAtom : file->sharedLibrary() ) {
+    handler.doSharedLibraryAtom(*shlibAtom);
+  }
+  for( const AbsoluteAtom *absAtom : file->absolute() ) {
+    handler.doAbsoluteAtom(*absAtom);
+  }
+}
+
+
+} // namespace lld
diff --git a/lld/lib/Core/Resolver.cpp b/lld/lib/Core/Resolver.cpp
index a758a86..f16a67a 100644
--- a/lld/lib/Core/Resolver.cpp
+++ b/lld/lib/Core/Resolver.cpp
@@ -137,7 +137,7 @@
 void Resolver::resolveUndefines() {
   const bool searchArchives =
     _options.searchArchivesToOverrideTentativeDefinitions();
-  const bool searchDylibs =
+  const bool searchSharedLibs =
     _options.searchSharedLibrariesToOverrideTentativeDefinitions();
 
   // keep looping until no more undefines were added in last loop
@@ -154,24 +154,20 @@
       }
     }
     // search libraries for overrides of common symbols
-    if (searchArchives || searchDylibs) {
-      std::vector<const Atom *> tents;
-      for ( const Atom *tent : tents ) {
-        if (const DefinedAtom* defAtom = dyn_cast<DefinedAtom>(tent)) {
-          if ( defAtom->merge() == DefinedAtom::mergeAsTentative )
-            tents.push_back(defAtom);
-        }
-      }
-      for ( const Atom *tent : tents ) {
-        // load for previous tentative may also have loaded
-        // this tentative, so check again
-        StringRef tentName = tent->name();
-        const Atom *curAtom = _symbolTable.findByName(tentName);
+    if (searchArchives || searchSharedLibs) {
+      std::vector<StringRef> tentDefNames;
+      _symbolTable.tentativeDefinitions(tentDefNames);
+      for ( StringRef tentDefName : tentDefNames ) {
+        // Load for previous tentative may also have loaded
+        // something that overrode this tentative, so always check. 
+        const Atom *curAtom = _symbolTable.findByName(tentDefName);
         assert(curAtom != nullptr);
         if (const DefinedAtom* curDefAtom = dyn_cast<DefinedAtom>(curAtom)) {
-          if (curDefAtom->merge() == DefinedAtom::mergeAsTentative )
-            _inputFiles.searchLibraries(tentName, searchDylibs,
-                                        true, true, *this);
+          if (curDefAtom->merge() == DefinedAtom::mergeAsTentative ) {
+            // Still tentative definition, so look for override.
+            _inputFiles.searchLibraries(tentDefName, searchSharedLibs,
+                                        searchArchives, true, *this);
+          }
         }
       }
     }
diff --git a/lld/lib/Core/SymbolTable.cpp b/lld/lib/Core/SymbolTable.cpp
index e22697490..0bfe6da 100644
--- a/lld/lib/Core/SymbolTable.cpp
+++ b/lld/lib/Core/SymbolTable.cpp
@@ -330,4 +330,16 @@
   }
 }
 
+void SymbolTable::tentativeDefinitions(std::vector<StringRef> &names) {
+  for (auto entry : _nameTable) {
+    const Atom *atom = entry.second;
+    StringRef name   = entry.first;
+    assert(atom != nullptr);
+    if (const DefinedAtom *defAtom = dyn_cast<DefinedAtom>(atom) ) {
+      if ( defAtom->merge() == DefinedAtom::mergeAsTentative )
+        names.push_back(name);
+    }
+  }
+}
+
 } // namespace lld
diff --git a/lld/lib/Core/YamlKeyValues.cpp b/lld/lib/Core/YamlKeyValues.cpp
index abf6f16..19abf4f 100644
--- a/lld/lib/Core/YamlKeyValues.cpp
+++ b/lld/lib/Core/YamlKeyValues.cpp
@@ -10,6 +10,7 @@
 #include "YamlKeyValues.h"
 
 #include "llvm/Support/ErrorHandling.h"
+#include "lld/Core/File.h"
 
 #include <cstring>
 
@@ -40,6 +41,9 @@
 const char* const KeyValues::fixupsOffsetKeyword    = "offset";
 const char* const KeyValues::fixupsTargetKeyword    = "target";
 const char* const KeyValues::fixupsAddendKeyword    = "addend";
+const char* const KeyValues::fileAtomsKeyword       = "atoms";
+const char* const KeyValues::fileKindKeyword        = "kind";
+const char* const KeyValues::fileMembersKeyword     = "members";
 
 
 
@@ -54,9 +58,36 @@
 const bool                            KeyValues::isThumbDefault = false;
 const bool                            KeyValues::isAliasDefault = false;
 const UndefinedAtom::CanBeNull        KeyValues::canBeNullDefault = UndefinedAtom::canBeNullNever;
+const File::Kind                      KeyValues::fileKindDefault = File::kindObject;
 
 
+struct FileKindMapping {
+  const char*       string;
+  File::Kind        value;
+};
 
+static const FileKindMapping fileKindMappings[] = {
+  { "object",         File::kindObject },
+  { "archive",        File::kindArchiveLibrary },
+  { "shared-library", File::kindSharedLibrary },
+  { nullptr,          File::kindObject }
+};
+
+ File::Kind KeyValues::fileKind(const char* str) {
+  for (const FileKindMapping* p = fileKindMappings; p->string != nullptr; ++p) {
+    if ( strcmp(p->string, str) == 0 )
+      return p->value;
+  }
+  llvm::report_fatal_error("bad file kind value");
+}
+
+const char* KeyValues::fileKind(File::Kind k) {
+  for (const FileKindMapping* p = fileKindMappings; p->string != nullptr; ++p) {
+    if ( p->value == k )
+      return p->string;
+  }
+  llvm::report_fatal_error("bad file kind value");
+}
 
 
 struct DefinitionMapping {
diff --git a/lld/lib/Core/YamlKeyValues.h b/lld/lib/Core/YamlKeyValues.h
index f474fb3..2265c5f 100644
--- a/lld/lib/Core/YamlKeyValues.h
+++ b/lld/lib/Core/YamlKeyValues.h
@@ -13,6 +13,7 @@
 #include "lld/Core/Atom.h"
 #include "lld/Core/DefinedAtom.h"
 #include "lld/Core/UndefinedAtom.h"
+#include "lld/Core/File.h"
 
 
 namespace lld {
@@ -28,6 +29,13 @@
   static const char* const                loadNameKeyword;
   static const char* const                valueKeyword;
   static const char* const                fixupsKeyword;
+  static const char* const                fileAtomsKeyword;
+  static const char* const                fileMembersKeyword;
+
+  static const char* const                fileKindKeyword;
+  static const File::Kind                 fileKindDefault;
+  static File::Kind                       fileKind(const char*);
+  static const char*                      fileKind(File::Kind);
 
   static const char* const                definitionKeyword;
   static const Atom::Definition           definitionDefault;
diff --git a/lld/lib/Core/YamlReader.cpp b/lld/lib/Core/YamlReader.cpp
index 6af7111..7f53295 100644
--- a/lld/lib/Core/YamlReader.cpp
+++ b/lld/lib/Core/YamlReader.cpp
@@ -13,6 +13,7 @@
 #include "lld/Core/AbsoluteAtom.h"
 #include "lld/Core/Error.h"
 #include "lld/Core/File.h"
+#include "lld/Core/ArchiveLibraryFile.h"
 #include "lld/Core/LLVM.h"
 #include "lld/Core/Platform.h"
 #include "lld/Core/Reference.h"
@@ -30,6 +31,7 @@
 
 #include <cstring>
 #include <vector>
+#include <set>
 
 
 
@@ -300,36 +302,47 @@
 
 class YAMLDefinedAtom;
 
-class YAMLFile : public File {
+class YAMLFile : public ArchiveLibraryFile {
 public:
   YAMLFile()
-    : File("path")
-    , _lastRefIndex(0) {}
+    : ArchiveLibraryFile("<anonymous>")
+    , _lastRefIndex(0) 
+    , _kind(File::kindObject)
+    , _inArchive(false) {
+  }
+
+  virtual File::Kind kind() const {
+    return _kind;
+  }
 
   virtual const atom_collection<DefinedAtom>& defined() const {
     return _definedAtoms;
   }
   virtual const atom_collection<UndefinedAtom>& undefined() const {
-      return _undefinedAtoms;
+    return _undefinedAtoms;
   }
   virtual const atom_collection<SharedLibraryAtom>& sharedLibrary() const {
-      return _sharedLibraryAtoms;
+    return _sharedLibraryAtoms;
   }
   virtual const atom_collection<AbsoluteAtom>& absolute() const {
-      return _absoluteAtoms;
+    return _absoluteAtoms;
   }
 
   virtual void addAtom(const Atom&) {
     assert(0 && "cannot add atoms to YAML files");
   }
 
+  virtual const File *find(StringRef name, bool dataSymbolOnly) const;
+
   void bindTargetReferences();
   void addDefinedAtom(YAMLDefinedAtom* atom, const char* refName);
   void addUndefinedAtom(UndefinedAtom* atom);
   void addSharedLibraryAtom(SharedLibraryAtom* atom);
   void addAbsoluteAtom(AbsoluteAtom* atom);
   Atom* findAtom(const char* name);
-
+  void addMember(const char*);
+  void setName(const char*);
+ 
   struct NameAtomPair {
                  NameAtomPair(const char* n, Atom* a) : name(n), atom(a) {}
     const char*  name;
@@ -342,7 +355,11 @@
   atom_collection_vector<AbsoluteAtom>        _absoluteAtoms;
   std::vector<YAMLReference>                  _references;
   std::vector<NameAtomPair>                   _nameToAtomMapping;
+  std::vector<const char*>                    _memberNames;
+  std::vector<YAMLFile*>                      _memberFiles;
   unsigned int                                _lastRefIndex;
+  File::Kind                                  _kind;
+  bool                                        _inArchive;
 };
 
 
@@ -643,6 +660,25 @@
   _nameToAtomMapping.push_back(NameAtomPair(atom->name().data(), atom));
 }
 
+void YAMLFile::addMember(const char* name) {
+  _memberNames.push_back(name);
+}
+
+void YAMLFile::setName(const char* name) {
+  _path = StringRef(name);
+}
+
+const File *YAMLFile::find(StringRef name, bool dataSymbolOnly) const {
+  for (YAMLFile *file : _memberFiles) {
+    for (const DefinedAtom *atom : file->defined() ) {
+      if ( name.equals(atom->name()) )
+        return file;
+    }
+  }
+  return NULL;
+}
+
+
 
 class YAMLAtomState {
 public:
@@ -810,17 +846,21 @@
                           , Platform& platform
                           , std::vector<const File *> &result) {
   std::vector<const YAML::Entry *> entries;
+  std::vector<YAMLFile*> allFiles;
   YAML::parse(mb, entries);
 
   YAMLFile *file = nullptr;
   YAMLAtomState atomState(platform);
   bool inAtoms       = false;
   bool inFixups      = false;
+  bool inMembers     = false;
   int depthForAtoms  = -1;
   int depthForFixups = -1;
+  int depthForMembers= -1;
   int lastDepth      = -1;
   bool haveAtom      = false;
   bool haveFixup     = false;
+  bool hasArchives = false;
 
   for (std::vector<const YAML::Entry *>::iterator it = entries.begin();
        it != entries.end(); ++it) {
@@ -833,7 +873,7 @@
           haveAtom = false;
         }
         file->bindTargetReferences();
-        result.push_back(file);
+        allFiles.push_back(file);
       }
       file = new YAMLFile();
       inAtoms = false;
@@ -853,9 +893,24 @@
     if (inFixups && (depthForFixups == -1)) {
       depthForFixups = entry->depth;
     }
-    if (strcmp(entry->key, "atoms") == 0) {
+    if (inMembers && (depthForMembers == -1)) {
+      depthForMembers = entry->depth;
+    }
+    if ( !inFixups && (strcmp(entry->key, KeyValues::fileKindKeyword) == 0) ) {
+      file->_kind = KeyValues::fileKind(entry->value);
+      if ( file->_kind == File::kindArchiveLibrary ) 
+        hasArchives = true;
+    }
+    else if (strcmp(entry->key, KeyValues::fileMembersKeyword) == 0) {
+      inMembers = true;
+    }
+    else if (strcmp(entry->key, KeyValues::fileAtomsKeyword) == 0) {
       inAtoms = true;
     }
+    else if ( !inAtoms && !inMembers 
+                       && (strcmp(entry->key, KeyValues::nameKeyword) == 0) ) {
+      file->setName(entry->value);
+    }
     if (inAtoms) {
       if (depthForAtoms == entry->depth) {
         if (entry->beginSequence) {
@@ -980,6 +1035,15 @@
         }
       }
     }
+    else if (inMembers) {
+      if (depthForMembers == entry->depth) {
+        if (entry->beginSequence) {
+          if (strcmp(entry->key, KeyValues::nameKeyword) == 0) {
+            file->addMember(entry->value);
+          }
+        }
+      }
+    }
     lastDepth = entry->depth;
   }
   if (haveAtom) {
@@ -987,8 +1051,31 @@
   }
   if (file != nullptr) {
     file->bindTargetReferences();
-    result.push_back(file);
+    allFiles.push_back(file);
   }
+  
+  // If yaml contained archive files, push members down into archives
+  if ( hasArchives ) {
+    for (YAMLFile *f : allFiles) {
+      if ( f->kind() == File::kindArchiveLibrary ) {
+        for (const char *memberName : f->_memberNames ) {
+          for (YAMLFile *f2 : allFiles) {
+            if ( f2->path().equals(memberName) ) {
+              f2->_inArchive = true;
+              f->_memberFiles.push_back(f2);
+            }
+          }
+        }
+      }
+    }
+  }
+  // Copy files that have not been pushed into archives to result.
+  for (YAMLFile *f : allFiles) {
+    if ( ! f->_inArchive ) {
+      result.push_back(f);
+    }
+  }
+  
   return make_error_code(yaml_reader_error::success);
 }