diff --git a/lld/MachO/Arch/ARM.cpp b/lld/MachO/Arch/ARM.cpp --- a/lld/MachO/Arch/ARM.cpp +++ b/lld/MachO/Arch/ARM.cpp @@ -27,7 +27,7 @@ struct ARM : TargetInfo { ARM(uint32_t cpuSubtype); - int64_t getEmbeddedAddend(MemoryBufferRef, uint64_t offset, + int64_t getEmbeddedAddend(WritableMemoryBufferRef, uint64_t offset, const relocation_info) const override; void relocateOne(uint8_t *loc, const Reloc &, uint64_t va, uint64_t pc) const override; @@ -65,7 +65,7 @@ return relocAttrsArray[type]; } -int64_t ARM::getEmbeddedAddend(MemoryBufferRef mb, uint64_t offset, +int64_t ARM::getEmbeddedAddend(WritableMemoryBufferRef mb, uint64_t offset, relocation_info rel) const { // FIXME: implement this return 0; diff --git a/lld/MachO/Arch/ARM64Common.h b/lld/MachO/Arch/ARM64Common.h --- a/lld/MachO/Arch/ARM64Common.h +++ b/lld/MachO/Arch/ARM64Common.h @@ -22,7 +22,7 @@ struct ARM64Common : TargetInfo { template ARM64Common(LP lp) : TargetInfo(lp) {} - int64_t getEmbeddedAddend(MemoryBufferRef, uint64_t offset, + int64_t getEmbeddedAddend(llvm::WritableMemoryBufferRef, uint64_t offset, const llvm::MachO::relocation_info) const override; void relocateOne(uint8_t *loc, const Reloc &, uint64_t va, uint64_t pc) const override; diff --git a/lld/MachO/Arch/ARM64Common.cpp b/lld/MachO/Arch/ARM64Common.cpp --- a/lld/MachO/Arch/ARM64Common.cpp +++ b/lld/MachO/Arch/ARM64Common.cpp @@ -11,12 +11,14 @@ #include "lld/Common/ErrorHandler.h" #include "llvm/Support/Endian.h" +using namespace llvm; using namespace llvm::MachO; using namespace llvm::support::endian; using namespace lld; using namespace lld::macho; -int64_t ARM64Common::getEmbeddedAddend(MemoryBufferRef mb, uint64_t offset, +int64_t ARM64Common::getEmbeddedAddend(WritableMemoryBufferRef mb, + uint64_t offset, const relocation_info rel) const { if (rel.r_type != ARM64_RELOC_UNSIGNED && rel.r_type != ARM64_RELOC_SUBTRACTOR) { diff --git a/lld/MachO/Arch/X86_64.cpp b/lld/MachO/Arch/X86_64.cpp --- a/lld/MachO/Arch/X86_64.cpp +++ b/lld/MachO/Arch/X86_64.cpp @@ -15,6 +15,7 @@ #include "llvm/BinaryFormat/MachO.h" #include "llvm/Support/Endian.h" +using namespace llvm; using namespace llvm::MachO; using namespace llvm::support::endian; using namespace lld; @@ -25,7 +26,7 @@ struct X86_64 : TargetInfo { X86_64(); - int64_t getEmbeddedAddend(MemoryBufferRef, uint64_t offset, + int64_t getEmbeddedAddend(WritableMemoryBufferRef, uint64_t offset, const relocation_info) const override; void relocateOne(uint8_t *loc, const Reloc &, uint64_t va, uint64_t relocVA) const override; @@ -77,7 +78,7 @@ } } -int64_t X86_64::getEmbeddedAddend(MemoryBufferRef mb, uint64_t offset, +int64_t X86_64::getEmbeddedAddend(WritableMemoryBufferRef mb, uint64_t offset, relocation_info rel) const { auto *buf = reinterpret_cast(mb.getBufferStart()); const uint8_t *loc = buf + offset + rel.r_address; diff --git a/lld/MachO/Driver.h b/lld/MachO/Driver.h --- a/lld/MachO/Driver.h +++ b/lld/MachO/Driver.h @@ -54,7 +54,8 @@ // Check for both libfoo.dylib and libfoo.tbd (in that order). llvm::Optional resolveDylibPath(llvm::StringRef path); -DylibFile *loadDylib(llvm::MemoryBufferRef mbref, DylibFile *umbrella = nullptr, +DylibFile *loadDylib(llvm::WritableMemoryBufferRef mbref, + DylibFile *umbrella = nullptr, bool isBundleLoader = false); // Search for all possible combinations of `{root}/{name}.{extension}`. @@ -68,7 +69,8 @@ // rerooted. llvm::StringRef rerootPath(llvm::StringRef path); -llvm::Optional loadArchiveMember(MemoryBufferRef, uint32_t modTime, +llvm::Optional loadArchiveMember(llvm::WritableMemoryBufferRef, + uint32_t modTime, StringRef archiveName, bool objCOnly); diff --git a/lld/MachO/Driver.cpp b/lld/MachO/Driver.cpp --- a/lld/MachO/Driver.cpp +++ b/lld/MachO/Driver.cpp @@ -226,14 +226,15 @@ namespace { struct ArchiveMember { - MemoryBufferRef mbref; + WritableMemoryBufferRef mbref; uint32_t modTime; }; } // namespace // Returns slices of MB by parsing MB as an archive file. // Each slice consists of a member file in the archive. -static std::vector getArchiveMembers(MemoryBufferRef mb) { +static std::vector +getArchiveMembers(WritableMemoryBufferRef mb) { std::unique_ptr file = CHECK(Archive::create(mb), mb.getBufferIdentifier() + ": failed to parse archive"); @@ -247,10 +248,11 @@ bool addToTar = archive->isThin() && tar; for (const Archive::Child &c : archive->children(err)) { - MemoryBufferRef mbref = + WritableMemoryBufferRef mbref = CHECK(c.getMemoryBufferRef(), mb.getBufferIdentifier() + - ": could not get the buffer for a child of the archive"); + ": could not get the buffer for a child of the archive") + .castToWritable(); if (addToTar) tar->append(relativeToRoot(check(c.getFullName())), mbref.getBuffer()); uint32_t modTime = toTimeT( @@ -270,10 +272,10 @@ static InputFile *addFile(StringRef path, bool forceLoadArchive, bool isExplicit = true, bool isBundleLoader = false) { - Optional buffer = readFile(path); + Optional buffer = readFile(path); if (!buffer) return nullptr; - MemoryBufferRef mbref = *buffer; + WritableMemoryBufferRef mbref = *buffer; InputFile *newFile = nullptr; file_magic magic = identify_magic(mbref.getBuffer()); @@ -295,7 +297,7 @@ error(path + ": archive has no index; run ranlib to add one"); if (config->allLoad || forceLoadArchive) { - if (Optional buffer = readFile(path)) { + if (Optional buffer = readFile(path)) { for (const ArchiveMember &member : getArchiveMembers(*buffer)) { if (Optional file = loadArchiveMember( member.mbref, member.modTime, path, /*objCOnly=*/false)) { @@ -316,7 +318,7 @@ // we already found that it contains an ObjC symbol. We should also // consider creating a LazyObjFile class in order to avoid double-loading // these files here and below (as part of the ArchiveFile). - if (Optional buffer = readFile(path)) { + if (Optional buffer = readFile(path)) { for (const ArchiveMember &member : getArchiveMembers(*buffer)) { if (Optional file = loadArchiveMember( member.mbref, member.modTime, path, /*objCOnly=*/true)) { @@ -446,10 +448,10 @@ } static void addFileList(StringRef path) { - Optional buffer = readFile(path); + Optional buffer = readFile(path); if (!buffer) return; - MemoryBufferRef mbref = *buffer; + WritableMemoryBufferRef mbref = *buffer; for (StringRef path : args::getLines(mbref)) addFile(rerootPath(path), /*forceLoadArchive=*/false); } @@ -469,13 +471,13 @@ // // The file can also have line comments that start with '#'. static void parseOrderFile(StringRef path) { - Optional buffer = readFile(path); + Optional buffer = readFile(path); if (!buffer) { error("Could not read order file at " + path); return; } - MemoryBufferRef mbref = *buffer; + WritableMemoryBufferRef mbref = *buffer; size_t priority = std::numeric_limits::max(); for (StringRef line : args::getLines(mbref)) { StringRef objectFile, symbol; @@ -964,12 +966,12 @@ symbolPatterns.insert(arg->getValue()); for (const Arg *arg : args.filtered(listFileOptionCode)) { StringRef path = arg->getValue(); - Optional buffer = readFile(path); + Optional buffer = readFile(path); if (!buffer) { error("Could not read symbol file: " + path); continue; } - MemoryBufferRef mbref = *buffer; + WritableMemoryBufferRef mbref = *buffer; for (StringRef line : args::getLines(mbref)) { line = line.take_until([](char c) { return c == '#'; }).trim(); if (!line.empty()) @@ -1471,7 +1473,7 @@ StringRef segName = arg->getValue(0); StringRef sectName = arg->getValue(1); StringRef fileName = arg->getValue(2); - Optional buffer = readFile(fileName); + Optional buffer = readFile(fileName); if (buffer) inputFiles.insert(make(*buffer, segName, sectName)); } diff --git a/lld/MachO/DriverUtils.cpp b/lld/MachO/DriverUtils.cpp --- a/lld/MachO/DriverUtils.cpp +++ b/lld/MachO/DriverUtils.cpp @@ -145,7 +145,7 @@ os << "-o " << quote(path::filename(arg->getValue())) << "\n"; break; case OPT_filelist: - if (Optional buffer = readFile(arg->getValue())) + if (Optional buffer = readFile(arg->getValue())) for (StringRef path : args::getLines(*buffer)) os << quote(rewriteInputPath(path)) << "\n"; break; @@ -205,7 +205,7 @@ // especially if it's a commonly re-exported core library. static DenseMap loadedDylibs; -DylibFile *macho::loadDylib(MemoryBufferRef mbref, DylibFile *umbrella, +DylibFile *macho::loadDylib(WritableMemoryBufferRef mbref, DylibFile *umbrella, bool isBundleLoader) { CachedHashStringRef path(mbref.getBufferIdentifier()); DylibFile *&file = loadedDylibs[path]; @@ -277,7 +277,7 @@ return path; } -Optional macho::loadArchiveMember(MemoryBufferRef mb, +Optional macho::loadArchiveMember(WritableMemoryBufferRef mb, uint32_t modTime, StringRef archiveName, bool objCOnly) { diff --git a/lld/MachO/InputFiles.h b/lld/MachO/InputFiles.h --- a/lld/MachO/InputFiles.h +++ b/lld/MachO/InputFiles.h @@ -70,7 +70,7 @@ Kind kind() const { return fileKind; } StringRef getName() const { return name; } - MemoryBufferRef mb; + llvm::WritableMemoryBufferRef mb; std::vector symbols; std::vector subsections; @@ -82,7 +82,7 @@ std::string archiveName; protected: - InputFile(Kind kind, MemoryBufferRef mb) + InputFile(Kind kind, llvm::WritableMemoryBufferRef mb) : mb(mb), id(idCount++), fileKind(kind), name(mb.getBufferIdentifier()) {} InputFile(Kind, const llvm::MachO::InterfaceFile &); @@ -97,7 +97,8 @@ // .o file class ObjFile final : public InputFile { public: - ObjFile(MemoryBufferRef mb, uint32_t modTime, StringRef archiveName); + ObjFile(llvm::WritableMemoryBufferRef mb, uint32_t modTime, + StringRef archiveName); static bool classof(const InputFile *f) { return f->kind() == ObjKind; } llvm::DWARFUnit *compileUnit = nullptr; @@ -124,7 +125,8 @@ // command-line -sectcreate file class OpaqueFile final : public InputFile { public: - OpaqueFile(MemoryBufferRef mb, StringRef segName, StringRef sectName); + OpaqueFile(llvm::WritableMemoryBufferRef mb, StringRef segName, + StringRef sectName); static bool classof(const InputFile *f) { return f->kind() == OpaqueKind; } }; @@ -138,13 +140,13 @@ // the root dylib to ensure symbols in the child library are correctly bound // to the root. On the other hand, if a dylib is being directly loaded // (through an -lfoo flag), then `umbrella` should be a nullptr. - explicit DylibFile(MemoryBufferRef mb, DylibFile *umbrella, + explicit DylibFile(llvm::WritableMemoryBufferRef mb, DylibFile *umbrella, bool isBundleLoader = false); explicit DylibFile(const llvm::MachO::InterfaceFile &interface, DylibFile *umbrella = nullptr, bool isBundleLoader = false); - void parseLoadCommands(MemoryBufferRef mb); + void parseLoadCommands(llvm::WritableMemoryBufferRef mb); void parseReexports(const llvm::MachO::InterfaceFile &interface); static bool classof(const InputFile *f) { return f->kind() == DylibKind; } @@ -196,7 +198,7 @@ class BitcodeFile final : public InputFile { public: - explicit BitcodeFile(MemoryBufferRef mb); + explicit BitcodeFile(llvm::WritableMemoryBufferRef mb); static bool classof(const InputFile *f) { return f->kind() == BitcodeKind; } std::unique_ptr obj; @@ -204,7 +206,7 @@ extern llvm::SetVector inputFiles; -llvm::Optional readFile(StringRef path); +llvm::Optional readFile(StringRef path); namespace detail { diff --git a/lld/MachO/InputFiles.cpp b/lld/MachO/InputFiles.cpp --- a/lld/MachO/InputFiles.cpp +++ b/lld/MachO/InputFiles.cpp @@ -174,19 +174,20 @@ } // Open a given file path and return it as a memory-mapped file. -Optional macho::readFile(StringRef path) { - ErrorOr> mbOrErr = MemoryBuffer::getFile(path); +Optional macho::readFile(StringRef path) { + ErrorOr> mbOrErr = + WritableMemoryBuffer::getFile(path); if (std::error_code ec = mbOrErr.getError()) { error("cannot open " + path + ": " + ec.message()); return None; } - std::unique_ptr &mb = *mbOrErr; - MemoryBufferRef mbref = mb->getMemBufferRef(); + std::unique_ptr &mb = *mbOrErr; + WritableMemoryBufferRef mbref = mb->getMemBufferRef().castToWritable(); make>(std::move(mb)); // take mb ownership // If this is a regular non-fat file, return it. - const char *buf = mbref.getBufferStart(); + char *buf = mbref.getBufferStart(); const auto *hdr = reinterpret_cast(buf); if (mbref.getBufferSize() < sizeof(uint32_t) || read32be(&hdr->magic) != FAT_MAGIC) { @@ -197,7 +198,7 @@ // Object files and archive files may be fat files, which contain multiple // real files for different CPU ISAs. Here, we search for a file that matches - // with the current link target and returns it as a MemoryBufferRef. + // with the current link target and returns it as a WritableMemoryBufferRef. const auto *arch = reinterpret_cast(buf + sizeof(*hdr)); for (uint32_t i = 0, n = read32be(&hdr->nfat_arch); i < n; ++i) { @@ -217,7 +218,8 @@ error(path + ": slice extends beyond end of file"); if (tar) tar->append(relativeToRoot(path), mbref.getBuffer()); - return MemoryBufferRef(StringRef(buf + offset, size), path.copy(bAlloc)); + return WritableMemoryBufferRef(MutableArrayRef(buf + offset, size), + path.copy(bAlloc)); } error("unable to find matching architecture in " + path); @@ -357,7 +359,7 @@ template void ObjFile::parseRelocations(ArrayRef
sectionHeaders, const Section &sec, SubsectionMap &subsecMap) { - auto *buf = reinterpret_cast(mb.getBufferStart()); + auto *buf = reinterpret_cast(mb.getBufferStart()); ArrayRef relInfos( reinterpret_cast(buf + sec.reloff), sec.nreloc); @@ -405,6 +407,12 @@ bool isSubtrahend = target->hasAttr(relInfo.r_type, RelocAttrBits::SUBTRAHEND); int64_t embeddedAddend = target->getEmbeddedAddend(mb, sec.offset, relInfo); + // If we will be running ICF, zero out the embedded addend. This makes it + // easier for ICF to compare just the non-relocatable section data. + if (config->icfLevel != ICFLevel::none && embeddedAddend != 0) + writeAddress(reinterpret_cast(mb.getBufferStart()) + + sec.offset + relInfo.r_address, + 0, relInfo.r_length); assert(!(embeddedAddend && pairedAddend)); int64_t totalAddend = pairedAddend + embeddedAddend; Reloc r; @@ -715,7 +723,7 @@ } } -OpaqueFile::OpaqueFile(MemoryBufferRef mb, StringRef segName, +OpaqueFile::OpaqueFile(WritableMemoryBufferRef mb, StringRef segName, StringRef sectName) : InputFile(OpaqueKind, mb) { const auto *buf = reinterpret_cast(mb.getBufferStart()); @@ -727,7 +735,8 @@ subsections.push_back({{0, isec}}); } -ObjFile::ObjFile(MemoryBufferRef mb, uint32_t modTime, StringRef archiveName) +ObjFile::ObjFile(WritableMemoryBufferRef mb, uint32_t modTime, + StringRef archiveName) : InputFile(ObjKind, mb), modTime(modTime) { this->archiveName = std::string(archiveName); if (target->wordSize == 8) @@ -831,7 +840,7 @@ // The path can point to either a dylib or a .tbd file. static DylibFile *loadDylib(StringRef path, DylibFile *umbrella) { - Optional mbref = readFile(path); + Optional mbref = readFile(path); if (!mbref) { error("could not read dylib file at " + path); return nullptr; @@ -929,7 +938,7 @@ error("unable to locate re-export with install name " + path); } -DylibFile::DylibFile(MemoryBufferRef mb, DylibFile *umbrella, +DylibFile::DylibFile(WritableMemoryBufferRef mb, DylibFile *umbrella, bool isBundleLoader) : InputFile(DylibKind, mb), refState(RefState::Unreferenced), isBundleLoader(isBundleLoader) { @@ -991,7 +1000,7 @@ } } -void DylibFile::parseLoadCommands(MemoryBufferRef mb) { +void DylibFile::parseLoadCommands(WritableMemoryBufferRef mb) { auto *hdr = reinterpret_cast(mb.getBufferStart()); const uint8_t *p = reinterpret_cast(mb.getBufferStart()) + target->headerSize; @@ -1191,7 +1200,8 @@ } ArchiveFile::ArchiveFile(std::unique_ptr &&f) - : InputFile(ArchiveKind, f->getMemoryBufferRef()), file(std::move(f)) { + : InputFile(ArchiveKind, f->getMemoryBufferRef().castToWritable()), + file(std::move(f)) { for (const object::Archive::Symbol &sym : file->symbols()) symtab->addLazy(sym.getName(), this, sym); } @@ -1205,11 +1215,12 @@ if (!seen.insert(c.getChildOffset()).second) return; - MemoryBufferRef mb = + WritableMemoryBufferRef mb = CHECK(c.getMemoryBufferRef(), toString(this) + ": could not get the buffer for the member defining symbol " + - toMachOString(sym)); + toMachOString(sym)) + .castToWritable(); if (tar && c.getParent()->isThin()) tar->append(relativeToRoot(CHECK(c.getFullName(), this)), mb.getBuffer()); @@ -1265,7 +1276,7 @@ /*noDeadStrip=*/false); } -BitcodeFile::BitcodeFile(MemoryBufferRef mbref) +BitcodeFile::BitcodeFile(WritableMemoryBufferRef mbref) : InputFile(BitcodeKind, mbref) { obj = check(lto::InputFile::create(mbref)); diff --git a/lld/MachO/LTO.h b/lld/MachO/LTO.h --- a/lld/MachO/LTO.h +++ b/lld/MachO/LTO.h @@ -36,7 +36,7 @@ private: std::unique_ptr ltoObj; std::vector> buf; - std::vector> files; + std::vector> files; }; } // namespace macho diff --git a/lld/MachO/LTO.cpp b/lld/MachO/LTO.cpp --- a/lld/MachO/LTO.cpp +++ b/lld/MachO/LTO.cpp @@ -106,11 +106,11 @@ // specified, configure LTO to use it as the cache directory. lto::NativeObjectCache cache; if (!config->thinLTOCacheDir.empty()) - cache = check( - lto::localCache(config->thinLTOCacheDir, - [&](size_t task, std::unique_ptr mb) { - files[task] = std::move(mb); - })); + cache = check(lto::localCache( + config->thinLTOCacheDir, + [&](size_t task, std::unique_ptr mb) { + files[task] = std::move(mb); + })); checkError(ltoObj->run( [&](size_t task) { @@ -147,9 +147,10 @@ modTime = getModTime(filePath); } ret.push_back(make( - MemoryBufferRef(buf[i], saver.save(filePath.str())), modTime, "")); + WritableMemoryBufferRef(buf[i], saver.save(filePath.str())), modTime, + "")); } - for (std::unique_ptr &file : files) + for (std::unique_ptr &file : files) if (file) ret.push_back(make(*file, 0, "")); return ret; diff --git a/lld/MachO/ObjC.h b/lld/MachO/ObjC.h --- a/lld/MachO/ObjC.h +++ b/lld/MachO/ObjC.h @@ -23,7 +23,7 @@ } // namespace objc -bool hasObjCSection(llvm::MemoryBufferRef); +bool hasObjCSection(llvm::WritableMemoryBufferRef); } // namespace macho } // namespace lld diff --git a/lld/MachO/ObjC.cpp b/lld/MachO/ObjC.cpp --- a/lld/MachO/ObjC.cpp +++ b/lld/MachO/ObjC.cpp @@ -19,7 +19,7 @@ using namespace lld; using namespace lld::macho; -template static bool hasObjCSection(MemoryBufferRef mb) { +template static bool hasObjCSection(WritableMemoryBufferRef mb) { using Section = typename LP::section; auto *hdr = @@ -46,7 +46,7 @@ return false; } -bool macho::hasObjCSection(MemoryBufferRef mb) { +bool macho::hasObjCSection(WritableMemoryBufferRef mb) { if (target->wordSize == 8) return ::hasObjCSection(mb); else diff --git a/lld/MachO/Target.h b/lld/MachO/Target.h --- a/lld/MachO/Target.h +++ b/lld/MachO/Target.h @@ -43,7 +43,7 @@ // Validate the relocation structure and get its addend. virtual int64_t - getEmbeddedAddend(llvm::MemoryBufferRef, uint64_t offset, + getEmbeddedAddend(llvm::WritableMemoryBufferRef, uint64_t offset, const llvm::MachO::relocation_info) const = 0; virtual void relocateOne(uint8_t *loc, const Reloc &, uint64_t va, uint64_t relocVA) const = 0; diff --git a/llvm/include/llvm/LTO/Caching.h b/llvm/include/llvm/LTO/Caching.h --- a/llvm/include/llvm/LTO/Caching.h +++ b/llvm/include/llvm/LTO/Caching.h @@ -23,8 +23,8 @@ /// (e.g. in a cache). /// /// Buffer callbacks must be thread safe. -using AddBufferFn = - std::function MB)>; +using AddBufferFn = std::function MB)>; /// Create a local file system cache which uses the given cache directory and /// file callback. This function also creates the cache directory if it does not diff --git a/llvm/include/llvm/Support/MemoryBuffer.h b/llvm/include/llvm/Support/MemoryBuffer.h --- a/llvm/include/llvm/Support/MemoryBuffer.h +++ b/llvm/include/llvm/Support/MemoryBuffer.h @@ -200,6 +200,15 @@ static std::unique_ptr getNewMemBuffer(size_t Size, const Twine &BufferName = ""); + /// Open the specified memory range as a MemoryBuffer, copying the contents + /// and taking ownership of it. InputData does not have to be null terminated. + static std::unique_ptr + getMemBufferCopy(StringRef InputData, const Twine &BufferName = ""); + + static ErrorOr> + getOpenFile(sys::fs::file_t FD, const Twine &Filename, uint64_t FileSize, + bool RequiresNullTerminator = true, bool IsVolatile = false); + private: // Hide these base class factory function so one can't write // WritableMemoryBuffer::getXXX() @@ -207,8 +216,6 @@ using MemoryBuffer::getFileAsStream; using MemoryBuffer::getFileOrSTDIN; using MemoryBuffer::getMemBuffer; - using MemoryBuffer::getMemBufferCopy; - using MemoryBuffer::getOpenFile; using MemoryBuffer::getOpenFileSlice; using MemoryBuffer::getSTDIN; }; diff --git a/llvm/include/llvm/Support/MemoryBufferRef.h b/llvm/include/llvm/Support/MemoryBufferRef.h --- a/llvm/include/llvm/Support/MemoryBufferRef.h +++ b/llvm/include/llvm/Support/MemoryBufferRef.h @@ -13,13 +13,17 @@ #ifndef LLVM_SUPPORT_MEMORYBUFFERREF_H #define LLVM_SUPPORT_MEMORYBUFFERREF_H +#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringRef.h" namespace llvm { class MemoryBuffer; +class WritableMemoryBuffer; +class WritableMemoryBufferRef; class MemoryBufferRef { +protected: StringRef Buffer; StringRef Identifier; @@ -35,6 +39,9 @@ const char *getBufferStart() const { return Buffer.begin(); } const char *getBufferEnd() const { return Buffer.end(); } size_t getBufferSize() const { return Buffer.size(); } + // This operation is safe iff this MemoryBufferRef was initialized with a + // writable buffer. + WritableMemoryBufferRef castToWritable() const; /// Check pointer identity (not value) of identifier and data. friend bool operator==(const MemoryBufferRef &LHS, @@ -51,6 +58,19 @@ } }; +class WritableMemoryBufferRef : public MemoryBufferRef { +public: + WritableMemoryBufferRef() = default; + WritableMemoryBufferRef(const WritableMemoryBuffer &Buffer); + WritableMemoryBufferRef(MutableArrayRef Buffer, StringRef Identifier) + : MemoryBufferRef({Buffer.data(), Buffer.size()}, Identifier) {} + + // const_cast is well-defined here, because the underlying buffer is + // guaranteed to have been initialized with a mutable buffer. + char *getBufferStart() const { return const_cast(Buffer.begin()); } + char *getBufferEnd() const { return const_cast(Buffer.end()); } +}; + } // namespace llvm #endif // LLVM_SUPPORT_MEMORYBUFFERREF_H diff --git a/llvm/lib/LTO/Caching.cpp b/llvm/lib/LTO/Caching.cpp --- a/llvm/lib/LTO/Caching.cpp +++ b/llvm/lib/LTO/Caching.cpp @@ -44,10 +44,10 @@ Twine(EntryPath), sys::fs::OF_UpdateAtime, &ResultPath); std::error_code EC; if (FDOrErr) { - ErrorOr> MBOrErr = - MemoryBuffer::getOpenFile(*FDOrErr, EntryPath, - /*FileSize=*/-1, - /*RequiresNullTerminator=*/false); + ErrorOr> MBOrErr = + WritableMemoryBuffer::getOpenFile(*FDOrErr, EntryPath, + /*FileSize=*/-1, + /*RequiresNullTerminator=*/false); sys::fs::closeFile(*FDOrErr); if (MBOrErr) { AddBuffer(Task, std::move(*MBOrErr)); @@ -88,8 +88,8 @@ OS.reset(); // Open the file first to avoid racing with a cache pruner. - ErrorOr> MBOrErr = - MemoryBuffer::getOpenFile( + ErrorOr> MBOrErr = + WritableMemoryBuffer::getOpenFile( sys::fs::convertFDToNativeFile(TempFile.FD), TempFile.TmpName, /*FileSize=*/-1, /*RequiresNullTerminator=*/false); if (!MBOrErr) @@ -112,8 +112,9 @@ if (EC != errc::permission_denied) return errorCodeToError(EC); - auto MBCopy = MemoryBuffer::getMemBufferCopy((*MBOrErr)->getBuffer(), - EntryPath); + MutableArrayRef buf = (*MBOrErr)->getBuffer(); + auto MBCopy = WritableMemoryBuffer::getMemBufferCopy( + {buf.data(), buf.size()}, EntryPath); MBOrErr = std::move(MBCopy); // FIXME: should we consume the discard error? diff --git a/llvm/lib/Object/Archive.cpp b/llvm/lib/Object/Archive.cpp --- a/llvm/lib/Object/Archive.cpp +++ b/llvm/lib/Object/Archive.cpp @@ -454,7 +454,11 @@ if (!FullNameOrErr) return FullNameOrErr.takeError(); const std::string &FullName = *FullNameOrErr; - ErrorOr> Buf = MemoryBuffer::getFile(FullName); + // Create a writable buffer in case our caller wants to cast our return value + // into a WritableMemoryBuffer. (Such a cast would be safe iff this Archive + // was initialized with a WritableMemoryBuffer too.) + ErrorOr> Buf = + WritableMemoryBuffer::getFile(FullName); if (std::error_code EC = Buf.getError()) return errorCodeToError(EC); Parent->ThinBuffers.push_back(std::move(*Buf)); diff --git a/llvm/lib/Support/MemoryBuffer.cpp b/llvm/lib/Support/MemoryBuffer.cpp --- a/llvm/lib/Support/MemoryBuffer.cpp +++ b/llvm/lib/Support/MemoryBuffer.cpp @@ -135,6 +135,15 @@ std::unique_ptr MemoryBuffer::getMemBufferCopy(StringRef InputData, const Twine &BufferName) { auto Buf = getMemBufferCopyImpl(InputData, BufferName); + if (Buf) + return std::unique_ptr(std::move(*Buf)); + return nullptr; +} + +std::unique_ptr +WritableMemoryBuffer::getMemBufferCopy(StringRef InputData, + const Twine &BufferName) { + auto Buf = getMemBufferCopyImpl(InputData, BufferName); if (Buf) return std::move(*Buf); return nullptr; @@ -506,6 +515,15 @@ RequiresNullTerminator, IsVolatile); } +ErrorOr> +WritableMemoryBuffer::getOpenFile(sys::fs::file_t FD, const Twine &Filename, + uint64_t FileSize, + bool RequiresNullTerminator, + bool IsVolatile) { + return getOpenFileImpl( + FD, Filename, FileSize, FileSize, 0, RequiresNullTerminator, IsVolatile); +} + ErrorOr> MemoryBuffer::getOpenFileSlice(sys::fs::file_t FD, const Twine &Filename, uint64_t MapSize, int64_t Offset, bool IsVolatile) { diff --git a/llvm/lib/Support/MemoryBufferRef.cpp b/llvm/lib/Support/MemoryBufferRef.cpp --- a/llvm/lib/Support/MemoryBufferRef.cpp +++ b/llvm/lib/Support/MemoryBufferRef.cpp @@ -17,3 +17,13 @@ MemoryBufferRef::MemoryBufferRef(const MemoryBuffer &Buffer) : Buffer(Buffer.getBuffer()), Identifier(Buffer.getBufferIdentifier()) {} + +WritableMemoryBufferRef MemoryBufferRef::castToWritable() const { + return WritableMemoryBufferRef( + MutableArrayRef(const_cast(Buffer.data()), Buffer.size()), + Identifier); +} + +WritableMemoryBufferRef::WritableMemoryBufferRef( + const WritableMemoryBuffer &Buffer) + : MemoryBufferRef(Buffer) {}