forked from OSchip/llvm-project
Re-commit r225766, r225767, r225769, r225814, r225816, r225829, and r225832.
These changes depended on r225674 and had been rolled back in r225859. Because r225674 has been re-submitted, it's safe to re-submit them. llvm-svn: 226132
This commit is contained in:
parent
8afb37e1a1
commit
80c04431ca
|
@ -49,18 +49,7 @@ public:
|
|||
typedef FileVectorT::iterator FileIterT;
|
||||
|
||||
/// \brief Initialize the inputgraph
|
||||
InputGraph() : _nextElementIndex(0), _currentInputElement(nullptr) {}
|
||||
virtual ~InputGraph();
|
||||
|
||||
/// getNextFile returns the next file that needs to be processed by
|
||||
/// the resolver. When there are no more files to be processed, an
|
||||
/// nullptr is returned.
|
||||
File *getNextFile();
|
||||
|
||||
/// Adds an observer of getNextFile(). Each time a new file is about to be
|
||||
/// returned from getNextFile(), registered observers are called with the file
|
||||
/// being returned.
|
||||
void registerObserver(std::function<void(File *)>);
|
||||
InputGraph() : _index(0) {}
|
||||
|
||||
/// \brief Adds a node into the InputGraph
|
||||
void addInputElement(std::unique_ptr<InputElement>);
|
||||
|
@ -68,34 +57,16 @@ public:
|
|||
/// \brief Adds a node at the beginning of the InputGraph
|
||||
void addInputElementFront(std::unique_ptr<InputElement>);
|
||||
|
||||
/// Normalize the InputGraph. It calls getReplacements() on each element.
|
||||
void normalize();
|
||||
|
||||
InputElementVectorT &inputElements() {
|
||||
return _inputArgs;
|
||||
}
|
||||
|
||||
// Returns the current group size if we are at an --end-group.
|
||||
// Otherwise returns 0.
|
||||
int getGroupSize();
|
||||
void skipGroup();
|
||||
InputElementVectorT &inputElements() { return _inputArgs; }
|
||||
|
||||
// \brief Returns the number of input files.
|
||||
size_t size() const { return _inputArgs.size(); }
|
||||
|
||||
/// \brief Dump the input Graph
|
||||
bool dump(raw_ostream &diagnostics = llvm::errs());
|
||||
|
||||
protected:
|
||||
// Input arguments
|
||||
InputElementVectorT _inputArgs;
|
||||
// Index of the next element to be processed
|
||||
uint32_t _nextElementIndex;
|
||||
InputElement *_currentInputElement;
|
||||
std::vector<std::function<void(File *)>> _observers;
|
||||
|
||||
private:
|
||||
InputElement *getNextInputElement();
|
||||
size_t _index;
|
||||
};
|
||||
|
||||
/// \brief This describes each element in the InputGraph. The Kind
|
||||
|
@ -125,11 +96,6 @@ public:
|
|||
/// Get the next file to be processed by the resolver
|
||||
virtual File *getNextFile() = 0;
|
||||
|
||||
/// Get the elements that we want to expand with.
|
||||
virtual bool getReplacements(InputGraph::InputElementVectorT &) {
|
||||
return false;
|
||||
}
|
||||
|
||||
protected:
|
||||
Kind _kind; // The type of the Element
|
||||
};
|
||||
|
@ -165,9 +131,13 @@ private:
|
|||
class FileNode : public InputElement {
|
||||
public:
|
||||
FileNode(StringRef path)
|
||||
: InputElement(InputElement::Kind::File), _path(path), _nextFileIndex(0) {
|
||||
: InputElement(InputElement::Kind::File), _path(path), _done(false) {
|
||||
}
|
||||
|
||||
FileNode(StringRef path, std::unique_ptr<File> f)
|
||||
: InputElement(InputElement::Kind::File), _path(path), _file(std::move(f)),
|
||||
_done(false) {}
|
||||
|
||||
virtual ErrorOr<StringRef> getPath(const LinkingContext &) const {
|
||||
return _path;
|
||||
}
|
||||
|
@ -186,36 +156,33 @@ public:
|
|||
}
|
||||
|
||||
/// \brief Get the list of files
|
||||
range<InputGraph::FileIterT> files() {
|
||||
return make_range(_files.begin(), _files.end());
|
||||
}
|
||||
File *getFile() { return _file.get(); }
|
||||
|
||||
/// \brief add a file to the list of files
|
||||
virtual void addFiles(InputGraph::FileVectorT files) {
|
||||
assert(files.size() == 1);
|
||||
assert(_files.empty());
|
||||
for (std::unique_ptr<File> &ai : files)
|
||||
_files.push_back(std::move(ai));
|
||||
assert(!_file);
|
||||
_file = std::move(files[0]);
|
||||
}
|
||||
|
||||
bool getReplacements(InputGraph::InputElementVectorT &result) override;
|
||||
|
||||
/// \brief Return the next File thats part of this node to the
|
||||
/// resolver.
|
||||
File *getNextFile() override {
|
||||
if (_nextFileIndex == _files.size())
|
||||
assert(_file);
|
||||
if (_done)
|
||||
return nullptr;
|
||||
return _files[_nextFileIndex++].get();
|
||||
_done = true;
|
||||
return _file.get();
|
||||
}
|
||||
|
||||
std::error_code parse(const LinkingContext &, raw_ostream &) override;
|
||||
|
||||
protected:
|
||||
StringRef _path; // The path of the Input file
|
||||
InputGraph::FileVectorT _files; // A vector of lld File objects
|
||||
std::unique_ptr<File> _file; // An lld File object
|
||||
|
||||
// The next file that would be processed by the resolver
|
||||
uint32_t _nextFileIndex;
|
||||
bool _done;
|
||||
};
|
||||
|
||||
/// \brief Represents Internal Input files
|
||||
|
@ -223,15 +190,13 @@ class SimpleFileNode : public FileNode {
|
|||
public:
|
||||
SimpleFileNode(StringRef path) : FileNode(path) {}
|
||||
SimpleFileNode(StringRef path, std::unique_ptr<File> f)
|
||||
: FileNode(path) {
|
||||
_files.push_back(std::move(f));
|
||||
}
|
||||
: FileNode(path, std::move(f)) {}
|
||||
|
||||
virtual ~SimpleFileNode() {}
|
||||
|
||||
/// \brief add a file to the list of files
|
||||
virtual void appendInputFile(std::unique_ptr<File> f) {
|
||||
_files.push_back(std::move(f));
|
||||
_file = std::move(f);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -55,8 +55,8 @@ public:
|
|||
private:
|
||||
typedef std::function<void(StringRef, bool)> UndefCallback;
|
||||
|
||||
bool undefinesAdded(int count);
|
||||
File *nextFile(bool &inGroup);
|
||||
bool undefinesAdded(int begin, int end);
|
||||
File *getFile(int &index, int &groupLevel);
|
||||
|
||||
/// \brief Add section group/.gnu.linkonce if it does not exist previously.
|
||||
void maybeAddSectionGroupOrGnuLinkOnce(const DefinedAtom &atom);
|
||||
|
|
|
@ -21,9 +21,7 @@ namespace lld {
|
|||
|
||||
class WrapperNode : public FileNode {
|
||||
public:
|
||||
WrapperNode(std::unique_ptr<File> file) : FileNode(file->path()) {
|
||||
_files.push_back(std::move(file));
|
||||
}
|
||||
WrapperNode(std::unique_ptr<File> f) : FileNode(f->path(), std::move(f)) {}
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -30,6 +30,28 @@ static const uint8_t DEFAULT_DOS_STUB[128] = {'M', 'Z'};
|
|||
|
||||
namespace lld {
|
||||
|
||||
namespace pecoff {
|
||||
class ResolvableSymbols {
|
||||
public:
|
||||
void add(File *file);
|
||||
|
||||
const std::set<std::string> &defined() {
|
||||
readAllSymbols();
|
||||
return _defined;
|
||||
}
|
||||
|
||||
private:
|
||||
// Files are read lazily, so that it has no runtime overhead if
|
||||
// no one accesses this class.
|
||||
void readAllSymbols();
|
||||
|
||||
std::set<std::string> _defined;
|
||||
std::set<File *> _seen;
|
||||
std::set<File *> _queue;
|
||||
std::mutex _mutex;
|
||||
};
|
||||
} // end namespace pecoff
|
||||
|
||||
class PECOFFLinkingContext : public LinkingContext {
|
||||
public:
|
||||
PECOFFLinkingContext()
|
||||
|
@ -328,6 +350,10 @@ public:
|
|||
|
||||
std::recursive_mutex &getMutex() { return _mutex; }
|
||||
|
||||
pecoff::ResolvableSymbols *getResolvableSymsFile() {
|
||||
return &_resolvableSyms;
|
||||
}
|
||||
|
||||
protected:
|
||||
/// Method to create a internal file for the entry symbol
|
||||
std::unique_ptr<File> createEntrySymbolFile() const override;
|
||||
|
@ -442,6 +468,8 @@ private:
|
|||
// Name of the temporary file for lib.exe subcommand. For debugging
|
||||
// only.
|
||||
std::string _moduleDefinitionFile;
|
||||
|
||||
pecoff::ResolvableSymbols _resolvableSyms;
|
||||
};
|
||||
|
||||
} // end namespace lld
|
||||
|
|
|
@ -13,33 +13,6 @@
|
|||
|
||||
using namespace lld;
|
||||
|
||||
InputGraph::~InputGraph() { }
|
||||
|
||||
File *InputGraph::getNextFile() {
|
||||
// Try to get the next file of _currentInputElement. If the current input
|
||||
// element points to an archive file, and there's a file left in the archive,
|
||||
// it will succeed. If not, try to get the next file in the input graph.
|
||||
for (;;) {
|
||||
if (_currentInputElement) {
|
||||
File *next = _currentInputElement->getNextFile();
|
||||
if (next) {
|
||||
for (const std::function<void(File *)> &observer : _observers)
|
||||
observer(next);
|
||||
return next;
|
||||
}
|
||||
}
|
||||
|
||||
InputElement *elt = getNextInputElement();
|
||||
if (!elt)
|
||||
return nullptr;
|
||||
_currentInputElement = elt;
|
||||
}
|
||||
}
|
||||
|
||||
void InputGraph::registerObserver(std::function<void(File *)> fn) {
|
||||
_observers.push_back(fn);
|
||||
}
|
||||
|
||||
void InputGraph::addInputElement(std::unique_ptr<InputElement> ie) {
|
||||
_inputArgs.push_back(std::move(ie));
|
||||
}
|
||||
|
@ -48,63 +21,9 @@ void InputGraph::addInputElementFront(std::unique_ptr<InputElement> ie) {
|
|||
_inputArgs.insert(_inputArgs.begin(), std::move(ie));
|
||||
}
|
||||
|
||||
bool InputGraph::dump(raw_ostream &diagnostics) {
|
||||
for (std::unique_ptr<InputElement> &ie : _inputArgs)
|
||||
if (!ie->dump(diagnostics))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// \brief Helper functions for the resolver
|
||||
InputElement *InputGraph::getNextInputElement() {
|
||||
if (_nextElementIndex >= _inputArgs.size())
|
||||
return nullptr;
|
||||
InputElement *elem = _inputArgs[_nextElementIndex++].get();
|
||||
if (isa<GroupEnd>(elem))
|
||||
return getNextInputElement();
|
||||
return elem;
|
||||
}
|
||||
|
||||
void InputGraph::normalize() {
|
||||
std::vector<std::unique_ptr<InputElement>> vec;
|
||||
for (std::unique_ptr<InputElement> &elt : _inputArgs) {
|
||||
if (elt->getReplacements(vec))
|
||||
continue;
|
||||
vec.push_back(std::move(elt));
|
||||
}
|
||||
_inputArgs = std::move(vec);
|
||||
}
|
||||
|
||||
// If we are at the end of a group, return its size (which indicates
|
||||
// how many files we need to go back in the command line).
|
||||
// Returns 0 if we are not at the end of a group.
|
||||
int InputGraph::getGroupSize() {
|
||||
if (_nextElementIndex >= _inputArgs.size())
|
||||
return 0;
|
||||
InputElement *elem = _inputArgs[_nextElementIndex].get();
|
||||
if (const GroupEnd *group = dyn_cast<GroupEnd>(elem))
|
||||
return group->getSize();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void InputGraph::skipGroup() {
|
||||
if (_nextElementIndex >= _inputArgs.size())
|
||||
return;
|
||||
if (isa<GroupEnd>(_inputArgs[_nextElementIndex].get()))
|
||||
_nextElementIndex++;
|
||||
}
|
||||
|
||||
bool FileNode::getReplacements(InputGraph::InputElementVectorT &result) {
|
||||
if (_files.size() < 2)
|
||||
return false;
|
||||
for (std::unique_ptr<File> &file : _files)
|
||||
result.push_back(llvm::make_unique<SimpleFileNode>(_path, std::move(file)));
|
||||
return true;
|
||||
}
|
||||
|
||||
std::error_code FileNode::parse(const LinkingContext &, raw_ostream &) {
|
||||
for (std::unique_ptr<File> &file : _files)
|
||||
if (std::error_code ec = file->parse())
|
||||
if (_file)
|
||||
if (std::error_code ec = _file->parse())
|
||||
return ec;
|
||||
return std::error_code();
|
||||
}
|
||||
|
|
|
@ -231,52 +231,52 @@ void Resolver::addAtoms(const std::vector<const DefinedAtom *> &newAtoms) {
|
|||
|
||||
// Returns true if at least one of N previous files has created an
|
||||
// undefined symbol.
|
||||
bool Resolver::undefinesAdded(int n) {
|
||||
for (size_t i = _fileIndex - n; i < _fileIndex; ++i)
|
||||
if (_newUndefinesAdded[_files[i]])
|
||||
return true;
|
||||
bool Resolver::undefinesAdded(int begin, int end) {
|
||||
std::vector<std::unique_ptr<InputElement>> &inputs =
|
||||
_context.getInputGraph().inputElements();
|
||||
for (int i = begin; i < end; ++i)
|
||||
if (FileNode *node = dyn_cast<FileNode>(inputs[i].get()))
|
||||
if (_newUndefinesAdded[node->getFile()])
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
File *Resolver::nextFile(bool &inGroup) {
|
||||
if (size_t groupSize = _context.getInputGraph().getGroupSize()) {
|
||||
File *Resolver::getFile(int &index, int &groupLevel) {
|
||||
std::vector<std::unique_ptr<InputElement>> &inputs
|
||||
= _context.getInputGraph().inputElements();
|
||||
if ((size_t)index >= inputs.size())
|
||||
return nullptr;
|
||||
if (GroupEnd *group = dyn_cast<GroupEnd>(inputs[index].get())) {
|
||||
// We are at the end of the current group. If one or more new
|
||||
// undefined atom has been added in the last groupSize files, we
|
||||
// reiterate over the files.
|
||||
if (undefinesAdded(groupSize))
|
||||
_fileIndex -= groupSize;
|
||||
_context.getInputGraph().skipGroup();
|
||||
return nextFile(inGroup);
|
||||
int size = group->getSize();
|
||||
if (undefinesAdded(index - size, index)) {
|
||||
index -= size;
|
||||
++groupLevel;
|
||||
return getFile(index, groupLevel);
|
||||
}
|
||||
++index;
|
||||
--groupLevel;
|
||||
return getFile(index, groupLevel);
|
||||
}
|
||||
if (_fileIndex < _files.size()) {
|
||||
// We are still in the current group.
|
||||
inGroup = true;
|
||||
return _files[_fileIndex++];
|
||||
}
|
||||
// We are not in a group. Get a new file.
|
||||
File *file = _context.getInputGraph().getNextFile();
|
||||
if (!file)
|
||||
return nullptr;
|
||||
_files.push_back(&*file);
|
||||
++_fileIndex;
|
||||
inGroup = false;
|
||||
return file;
|
||||
return cast<FileNode>(inputs[index++].get())->getFile();
|
||||
}
|
||||
|
||||
// Keep adding atoms until _context.getNextFile() returns an error. This
|
||||
// function is where undefined atoms are resolved.
|
||||
void Resolver::resolveUndefines() {
|
||||
ScopedTask task(getDefaultDomain(), "resolveUndefines");
|
||||
|
||||
int index = 0;
|
||||
int groupLevel = 0;
|
||||
for (;;) {
|
||||
bool inGroup = false;
|
||||
bool undefAdded = false;
|
||||
File *file = nextFile(inGroup);
|
||||
File *file = getFile(index, groupLevel);
|
||||
if (!file)
|
||||
return;
|
||||
switch (file->kind()) {
|
||||
case File::kindObject:
|
||||
if (inGroup)
|
||||
if (groupLevel > 0)
|
||||
break;
|
||||
assert(!file->hasOrdinal());
|
||||
file->setOrdinal(_context.getNextOrdinalAndIncrement());
|
||||
|
@ -293,7 +293,7 @@ void Resolver::resolveUndefines() {
|
|||
handleSharedLibrary(*file);
|
||||
break;
|
||||
}
|
||||
_newUndefinesAdded[&*file] = undefAdded;
|
||||
_newUndefinesAdded[file] = undefAdded;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -77,7 +77,6 @@ bool Driver::link(LinkingContext &context, raw_ostream &diagnostics) {
|
|||
InputGraph &inputGraph = context.getInputGraph();
|
||||
if (!inputGraph.size())
|
||||
return false;
|
||||
inputGraph.normalize();
|
||||
|
||||
bool fail = false;
|
||||
|
||||
|
|
|
@ -689,9 +689,6 @@ bool GnuLdDriver::parse(int argc, const char *argv[],
|
|||
}
|
||||
}
|
||||
|
||||
if (ctx->outputFileType() == LinkingContext::OutputFileType::YAML)
|
||||
inputGraph->dump(diagnostics);
|
||||
|
||||
// Validate the combination of options used.
|
||||
if (!ctx->validate(diagnostics))
|
||||
return false;
|
||||
|
|
|
@ -1416,6 +1416,7 @@ bool WinLinkDriver::parse(int argc, const char *argv[],
|
|||
if (isReadingDirectiveSection)
|
||||
if (file->parse())
|
||||
return false;
|
||||
ctx.getResolvableSymsFile()->add(file.get());
|
||||
ctx.getInputGraph().addInputElement(
|
||||
std::unique_ptr<InputElement>(new WrapperNode(std::move(file))));
|
||||
}
|
||||
|
@ -1437,6 +1438,7 @@ bool WinLinkDriver::parse(int argc, const char *argv[],
|
|||
if (isReadingDirectiveSection)
|
||||
if (file->parse())
|
||||
return false;
|
||||
ctx.getResolvableSymsFile()->add(file.get());
|
||||
ctx.addLibraryFile(
|
||||
std::unique_ptr<FileNode>(new WrapperNode(std::move(file))));
|
||||
}
|
||||
|
|
|
@ -930,9 +930,7 @@ bool MachOLinkingContext::customAtomOrderer(const DefinedAtom *left,
|
|||
|
||||
static File *getFirstFile(const std::unique_ptr<InputElement> &elem) {
|
||||
FileNode *e = dyn_cast<FileNode>(const_cast<InputElement *>(elem.get()));
|
||||
if (!e || e->files().empty())
|
||||
return nullptr;
|
||||
return e->files()[0].get();
|
||||
return e ? e->getFile() : nullptr;
|
||||
}
|
||||
|
||||
static bool isLibrary(const std::unique_ptr<InputElement> &elem) {
|
||||
|
|
|
@ -174,45 +174,6 @@ private:
|
|||
mutable llvm::BumpPtrAllocator _alloc;
|
||||
};
|
||||
|
||||
class ResolvableSymbols {
|
||||
public:
|
||||
void add(File *file) {
|
||||
std::lock_guard<std::mutex> lock(_mutex);
|
||||
if (_seen.count(file) > 0)
|
||||
return;
|
||||
_seen.insert(file);
|
||||
_queue.insert(file);
|
||||
}
|
||||
|
||||
const std::set<std::string> &defined() {
|
||||
readAllSymbols();
|
||||
return _defined;
|
||||
}
|
||||
|
||||
private:
|
||||
// Files are read lazily, so that it has no runtime overhead if
|
||||
// no one accesses this class.
|
||||
void readAllSymbols() {
|
||||
std::lock_guard<std::mutex> lock(_mutex);
|
||||
for (File *file : _queue) {
|
||||
if (auto *archive = dyn_cast<ArchiveLibraryFile>(file)) {
|
||||
for (const std::string &sym : archive->getDefinedSymbols())
|
||||
_defined.insert(sym);
|
||||
continue;
|
||||
}
|
||||
for (const DefinedAtom *atom : file->defined())
|
||||
if (!atom->name().empty())
|
||||
_defined.insert(atom->name());
|
||||
}
|
||||
_queue.clear();
|
||||
}
|
||||
|
||||
std::set<std::string> _defined;
|
||||
std::set<File *> _seen;
|
||||
std::set<File *> _queue;
|
||||
std::mutex _mutex;
|
||||
};
|
||||
|
||||
// A ExportedSymbolRenameFile is a virtual archive file for dllexported symbols.
|
||||
//
|
||||
// One usually has to specify the exact symbol name to resolve it. That's true
|
||||
|
@ -246,7 +207,7 @@ private:
|
|||
class ExportedSymbolRenameFile : public impl::VirtualArchiveLibraryFile {
|
||||
public:
|
||||
ExportedSymbolRenameFile(const PECOFFLinkingContext &ctx,
|
||||
std::shared_ptr<ResolvableSymbols> syms)
|
||||
ResolvableSymbols *syms)
|
||||
: VirtualArchiveLibraryFile("<export>"), _syms(syms),
|
||||
_ctx(const_cast<PECOFFLinkingContext *>(&ctx)) {
|
||||
for (PECOFFLinkingContext::ExportDesc &desc : _ctx->getDllExports())
|
||||
|
@ -258,7 +219,7 @@ public:
|
|||
if (_exportedSyms.count(sym) == 0)
|
||||
return nullptr;
|
||||
std::string replace;
|
||||
if (!findDecoratedSymbol(_ctx, _syms.get(), sym.str(), replace))
|
||||
if (!findDecoratedSymbol(_ctx, _syms, sym.str(), replace))
|
||||
return nullptr;
|
||||
|
||||
for (ExportDesc &exp : _ctx->getDllExports())
|
||||
|
@ -271,7 +232,7 @@ public:
|
|||
|
||||
private:
|
||||
std::set<std::string> _exportedSyms;
|
||||
std::shared_ptr<ResolvableSymbols> _syms;
|
||||
ResolvableSymbols *_syms;
|
||||
mutable llvm::BumpPtrAllocator _alloc;
|
||||
mutable PECOFFLinkingContext *_ctx;
|
||||
};
|
||||
|
@ -284,7 +245,7 @@ private:
|
|||
class EntryPointFile : public SimpleFile {
|
||||
public:
|
||||
EntryPointFile(const PECOFFLinkingContext &ctx,
|
||||
std::shared_ptr<ResolvableSymbols> syms)
|
||||
ResolvableSymbols *syms)
|
||||
: SimpleFile("<entry>"), _ctx(const_cast<PECOFFLinkingContext *>(&ctx)),
|
||||
_syms(syms), _firstTime(true) {}
|
||||
|
||||
|
@ -316,7 +277,7 @@ private:
|
|||
StringRef opt = _ctx->getEntrySymbolName();
|
||||
if (!opt.empty()) {
|
||||
std::string mangled;
|
||||
if (findDecoratedSymbol(_ctx, _syms.get(), opt, mangled))
|
||||
if (findDecoratedSymbol(_ctx, _syms, opt, mangled))
|
||||
return mangled;
|
||||
return _ctx->decorateSymbol(opt);
|
||||
}
|
||||
|
@ -341,7 +302,7 @@ private:
|
|||
if (_syms->defined().count(sym))
|
||||
return true;
|
||||
std::string ignore;
|
||||
return findDecoratedSymbol(_ctx, _syms.get(), sym, ignore);
|
||||
return findDecoratedSymbol(_ctx, _syms, sym, ignore);
|
||||
};
|
||||
|
||||
switch (_ctx->getSubsystem()) {
|
||||
|
@ -372,7 +333,7 @@ private:
|
|||
PECOFFLinkingContext *_ctx;
|
||||
atom_collection_vector<UndefinedAtom> _undefinedAtoms;
|
||||
std::mutex _mutex;
|
||||
std::shared_ptr<ResolvableSymbols> _syms;
|
||||
ResolvableSymbols *_syms;
|
||||
llvm::BumpPtrAllocator _alloc;
|
||||
bool _firstTime;
|
||||
};
|
||||
|
|
|
@ -118,9 +118,7 @@ bool PECOFFLinkingContext::createImplicitFiles(
|
|||
llvm::make_unique<pecoff::LocallyImportedSymbolFile>(*this));
|
||||
getInputGraph().addInputElement(std::move(impFileNode));
|
||||
|
||||
std::shared_ptr<pecoff::ResolvableSymbols> syms(
|
||||
new pecoff::ResolvableSymbols());
|
||||
getInputGraph().registerObserver([=](File *file) { syms->add(file); });
|
||||
pecoff::ResolvableSymbols* syms = getResolvableSymsFile();
|
||||
|
||||
// Create a file for dllexported symbols.
|
||||
auto exportNode = llvm::make_unique<SimpleFileNode>("<export>");
|
||||
|
@ -331,4 +329,27 @@ void PECOFFLinkingContext::addPasses(PassManager &pm) {
|
|||
pm.add(std::unique_ptr<Pass>(new pecoff::InferSubsystemPass(*this)));
|
||||
}
|
||||
|
||||
void pecoff::ResolvableSymbols::add(File *file) {
|
||||
std::lock_guard<std::mutex> lock(_mutex);
|
||||
if (_seen.count(file) > 0)
|
||||
return;
|
||||
_seen.insert(file);
|
||||
_queue.insert(file);
|
||||
}
|
||||
|
||||
void pecoff::ResolvableSymbols::readAllSymbols() {
|
||||
std::lock_guard<std::mutex> lock(_mutex);
|
||||
for (File *file : _queue) {
|
||||
if (auto *archive = dyn_cast<ArchiveLibraryFile>(file)) {
|
||||
for (const std::string &sym : archive->getDefinedSymbols())
|
||||
_defined.insert(sym);
|
||||
continue;
|
||||
}
|
||||
for (const DefinedAtom *atom : file->defined())
|
||||
if (!atom->name().empty())
|
||||
_defined.insert(atom->name());
|
||||
}
|
||||
_queue.clear();
|
||||
}
|
||||
|
||||
} // end namespace lld
|
||||
|
|
|
@ -4,7 +4,6 @@ add_lld_unittest(DriverTests
|
|||
DarwinLdDriverTest.cpp
|
||||
WinLinkDriverTest.cpp
|
||||
WinLinkModuleDefTest.cpp
|
||||
InputGraphTest.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(DriverTests
|
||||
|
|
|
@ -1,122 +0,0 @@
|
|||
//===- lld/unittest/InputGraphTest.cpp -----------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
///
|
||||
/// \file
|
||||
/// \brief InputGraph Tests
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "lld/Core/InputGraph.h"
|
||||
#include "lld/Core/Resolver.h"
|
||||
#include "lld/Core/Simple.h"
|
||||
|
||||
using namespace lld;
|
||||
|
||||
namespace {
|
||||
|
||||
class TestLinkingContext : public LinkingContext {
|
||||
public:
|
||||
Writer &writer() const override { llvm_unreachable("no writer!"); }
|
||||
bool validateImpl(raw_ostream &) override { return true; }
|
||||
};
|
||||
|
||||
class TestExpandFileNode : public SimpleFileNode {
|
||||
public:
|
||||
TestExpandFileNode(StringRef path) : SimpleFileNode(path) {}
|
||||
|
||||
/// Returns the elements replacing this node
|
||||
bool getReplacements(InputGraph::InputElementVectorT &result) override {
|
||||
for (std::unique_ptr<InputElement> &elt : _expandElements)
|
||||
result.push_back(std::move(elt));
|
||||
return true;
|
||||
}
|
||||
|
||||
void addElement(std::unique_ptr<InputElement> element) {
|
||||
_expandElements.push_back(std::move(element));
|
||||
}
|
||||
|
||||
private:
|
||||
InputGraph::InputElementVectorT _expandElements;
|
||||
};
|
||||
|
||||
class InputGraphTest : public testing::Test {
|
||||
public:
|
||||
InputGraphTest() {
|
||||
_ctx.setInputGraph(std::unique_ptr<InputGraph>(new InputGraph()));
|
||||
_graph = &_ctx.getInputGraph();
|
||||
}
|
||||
|
||||
StringRef getNext() {
|
||||
File *file = _graph->getNextFile();
|
||||
EXPECT_TRUE(file);
|
||||
return file->path();
|
||||
}
|
||||
|
||||
void expectEnd() {
|
||||
File *file = _graph->getNextFile();
|
||||
EXPECT_TRUE(file == nullptr);
|
||||
}
|
||||
|
||||
protected:
|
||||
TestLinkingContext _ctx;
|
||||
InputGraph *_graph;
|
||||
};
|
||||
|
||||
} // end anonymous namespace
|
||||
|
||||
static std::unique_ptr<SimpleFileNode> createFile(StringRef name) {
|
||||
std::vector<std::unique_ptr<File>> files;
|
||||
files.push_back(std::unique_ptr<SimpleFile>(new SimpleFile(name)));
|
||||
std::unique_ptr<SimpleFileNode> file(new SimpleFileNode("filenode"));
|
||||
file->addFiles(std::move(files));
|
||||
return file;
|
||||
}
|
||||
|
||||
TEST_F(InputGraphTest, Empty) {
|
||||
expectEnd();
|
||||
}
|
||||
|
||||
TEST_F(InputGraphTest, File) {
|
||||
_graph->addInputElement(createFile("file1"));
|
||||
EXPECT_EQ("file1", getNext());
|
||||
expectEnd();
|
||||
}
|
||||
|
||||
// Node expansion tests
|
||||
TEST_F(InputGraphTest, Normalize) {
|
||||
_graph->addInputElement(createFile("file1"));
|
||||
|
||||
std::unique_ptr<TestExpandFileNode> expandFile(
|
||||
new TestExpandFileNode("node"));
|
||||
expandFile->addElement(createFile("file2"));
|
||||
expandFile->addElement(createFile("file3"));
|
||||
_graph->addInputElement(std::move(expandFile));
|
||||
_graph->normalize();
|
||||
|
||||
EXPECT_EQ("file1", getNext());
|
||||
EXPECT_EQ("file2", getNext());
|
||||
EXPECT_EQ("file3", getNext());
|
||||
expectEnd();
|
||||
}
|
||||
|
||||
TEST_F(InputGraphTest, Observer) {
|
||||
std::vector<std::string> files;
|
||||
_graph->registerObserver([&](File *file) { files.push_back(file->path()); });
|
||||
|
||||
_graph->addInputElement(createFile("file1"));
|
||||
_graph->addInputElement(createFile("file2"));
|
||||
EXPECT_EQ("file1", getNext());
|
||||
EXPECT_EQ("file2", getNext());
|
||||
expectEnd();
|
||||
|
||||
EXPECT_EQ(2U, files.size());
|
||||
EXPECT_EQ("file1", files[0]);
|
||||
EXPECT_EQ("file2", files[1]);
|
||||
}
|
Loading…
Reference in New Issue