| //===- lib/Core/InputGraph.cpp --------------------------------------------===// |
| // |
| // The LLVM Linker |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "lld/Core/InputGraph.h" |
| |
| #include "lld/Core/Resolver.h" |
| |
| #include <memory> |
| |
| using namespace lld; |
| |
| ErrorOr<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) { |
| ErrorOr<File &> next = _currentInputElement->getNextFile(); |
| if (next.getError() != InputGraphError::no_more_files) { |
| for (const std::function<void(File *)> &observer : _observers) |
| observer(&next.get()); |
| return std::move(next); |
| } |
| } |
| |
| ErrorOr<InputElement *> elt = getNextInputElement(); |
| if (elt.getError() == InputGraphError::no_more_elements || *elt == nullptr) |
| return make_error_code(InputGraphError::no_more_files); |
| _currentInputElement = *elt; |
| } |
| } |
| |
| void InputGraph::notifyProgress() { _currentInputElement->notifyProgress(); } |
| |
| 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)); |
| } |
| |
| bool InputGraph::dump(raw_ostream &diagnostics) { |
| for (std::unique_ptr<InputElement> &ie : _inputArgs) |
| if (!ie->dump(diagnostics)) |
| return false; |
| return true; |
| } |
| |
| /// \brief Insert element at position |
| void InputGraph::insertElementAt(std::unique_ptr<InputElement> element, |
| Position position) { |
| if (position == InputGraph::Position::BEGIN) { |
| _inputArgs.insert(_inputArgs.begin(), std::move(element)); |
| return; |
| } |
| assert(position == InputGraph::Position::END); |
| _inputArgs.push_back(std::move(element)); |
| } |
| |
| /// \brief Helper functions for the resolver |
| ErrorOr<InputElement *> InputGraph::getNextInputElement() { |
| if (_nextElementIndex >= _inputArgs.size()) |
| return make_error_code(InputGraphError::no_more_elements); |
| return _inputArgs[_nextElementIndex++].get(); |
| } |
| |
| void InputGraph::normalize() { |
| for (std::unique_ptr<InputElement> &elt : _inputArgs) |
| elt->expand(); |
| 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); |
| } |
| |
| /// \brief Read the file into _buffer. |
| std::error_code FileNode::getBuffer(StringRef filePath) { |
| // Create a memory buffer |
| ErrorOr<std::unique_ptr<MemoryBuffer>> mb = |
| MemoryBuffer::getFileOrSTDIN(filePath); |
| if (std::error_code ec = mb.getError()) |
| return ec; |
| _buffer = std::move(mb.get()); |
| return std::error_code(); |
| } |
| |
| /// \brief Return the next file that need to be processed by the resolver. |
| /// This also processes input elements depending on the resolve status |
| /// of the input elements contained in the group. |
| ErrorOr<File &> Group::getNextFile() { |
| // If there are no elements, move on to the next input element |
| if (_elements.empty()) |
| return make_error_code(InputGraphError::no_more_files); |
| |
| for (;;) { |
| // If we have processed all the elements, and have made no progress on |
| // linking, we cannot resolve any symbol from this group. Continue to the |
| // next one by returning no_more_files. |
| if (_nextElementIndex == _elements.size()) { |
| if (!_madeProgress) |
| return make_error_code(InputGraphError::no_more_files); |
| resetNextIndex(); |
| } |
| |
| _currentElementIndex = _nextElementIndex; |
| auto file = _elements[_nextElementIndex]->getNextFile(); |
| // Move on to the next element if we have finished processing all |
| // the files in the input element |
| if (file.getError() == InputGraphError::no_more_files) { |
| _nextElementIndex++; |
| continue; |
| } |
| return *file; |
| } |
| } |