diff --git a/clang-tools-extra/clangd/index/Serialization.cpp b/clang-tools-extra/clangd/index/Serialization.cpp --- a/clang-tools-extra/clangd/index/Serialization.cpp +++ b/clang-tools-extra/clangd/index/Serialization.cpp @@ -190,10 +190,13 @@ RawTable.append(std::string(S)); RawTable.push_back(0); } - if (llvm::compression::zlib::isAvailable()) { + llvm::compression::CompressionAlgorithm *CompressionScheme = + new llvm::compression::ZlibCompressionAlgorithm(); + CompressionScheme = CompressionScheme->whenSupported(); + if (CompressionScheme->notNone()) { llvm::SmallVector Compressed; - llvm::compression::zlib::compress(llvm::arrayRefFromStringRef(RawTable), - Compressed); + CompressionScheme->compress(llvm::arrayRefFromStringRef(RawTable), + Compressed); write32(RawTable.size(), OS); OS << llvm::toStringRef(Compressed); } else { @@ -224,23 +227,29 @@ llvm::SmallVector UncompressedStorage; if (UncompressedSize == 0) // No compression Uncompressed = R.rest(); - else if (llvm::compression::zlib::isAvailable()) { - // Don't allocate a massive buffer if UncompressedSize was corrupted - // This is effective for sharded index, but not big monolithic ones, as - // once compressed size reaches 4MB nothing can be ruled out. - // Theoretical max ratio from https://zlib.net/zlib_tech.html - constexpr int MaxCompressionRatio = 1032; - if (UncompressedSize / MaxCompressionRatio > R.rest().size()) - return error("Bad stri table: uncompress {0} -> {1} bytes is implausible", - R.rest().size(), UncompressedSize); - - if (llvm::Error E = llvm::compression::zlib::uncompress( - llvm::arrayRefFromStringRef(R.rest()), UncompressedStorage, - UncompressedSize)) - return std::move(E); - Uncompressed = toStringRef(UncompressedStorage); - } else - return error("Compressed string table, but zlib is unavailable"); + else { + llvm::compression::CompressionAlgorithm *CompressionScheme = + new llvm::compression::ZlibCompressionAlgorithm(); + if (CompressionScheme->supported()) { + // Don't allocate a massive buffer if UncompressedSize was corrupted + // This is effective for sharded index, but not big monolithic ones, as + // once compressed size reaches 4MB nothing can be ruled out. + // Theoretical max ratio from https://zlib.net/zlib_tech.html + constexpr int MaxCompressionRatio = 1032; + if (UncompressedSize / MaxCompressionRatio > R.rest().size()) + return error( + "Bad stri table: uncompress {0} -> {1} bytes is implausible", + R.rest().size(), UncompressedSize); + + if (llvm::Error E = CompressionScheme->decompress( + llvm::arrayRefFromStringRef(R.rest()), UncompressedStorage, + UncompressedSize)) + return std::move(E); + Uncompressed = toStringRef(UncompressedStorage); + } else + return error("Compressed string table, but " + + (CompressionScheme->getName() + " is unavailable").str()); + } StringTableIn Table; llvm::StringSaver Saver(Table.Arena); diff --git a/clang-tools-extra/clangd/unittests/SerializationTests.cpp b/clang-tools-extra/clangd/unittests/SerializationTests.cpp --- a/clang-tools-extra/clangd/unittests/SerializationTests.cpp +++ b/clang-tools-extra/clangd/unittests/SerializationTests.cpp @@ -391,7 +391,7 @@ // Check we detect invalid string table size size without allocating it first. // If this detection fails, the test should allocate a huge array and crash. TEST(SerializationTest, NoCrashOnBadStringTableSize) { - if (!llvm::compression::zlib::isAvailable()) { + if (!llvm::compression::ZlibCompressionAlgorithm::Supported()) { log("skipping test, no zlib"); return; } diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -1139,7 +1139,7 @@ if (Value == "none") { CmdArgs.push_back("--compress-debug-sections=none"); } else if (Value == "zlib") { - if (llvm::compression::zlib::isAvailable()) { + if (llvm::compression::ZlibCompressionAlgorithm::Supported()) { CmdArgs.push_back( Args.MakeArgString("--compress-debug-sections=" + Twine(Value))); } else { diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -1462,12 +1462,17 @@ unsigned RecCode = MaybeRecCode.get(); if (RecCode == SM_SLOC_BUFFER_BLOB_COMPRESSED) { - if (!llvm::compression::zlib::isAvailable()) { - Error("zlib is not available"); + uint8_t CompressionSchemeId = static_cast( + llvm::compression::ZlibCompressionAlgorithm::AlgorithmId); + llvm::compression::CompressionAlgorithm *CompressionScheme = + llvm::compression::CompressionAlgorithmFromId(CompressionSchemeId); + if (!CompressionScheme->supported()) { + Error("compression class " + + (CompressionScheme->getName() + " is not available").str()); return nullptr; } SmallVector Uncompressed; - if (llvm::Error E = llvm::compression::zlib::uncompress( + if (llvm::Error E = CompressionScheme->decompress( llvm::arrayRefFromStringRef(Blob), Uncompressed, Record[0])) { Error("could not decompress embedded file contents: " + llvm::toString(std::move(E))); diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -2000,10 +2000,16 @@ // Compress the buffer if possible. We expect that almost all PCM // consumers will not want its contents. - SmallVector CompressedBuffer; - if (llvm::compression::zlib::isAvailable()) { - llvm::compression::zlib::compress( - llvm::arrayRefFromStringRef(Blob.drop_back(1)), CompressedBuffer); + llvm::compression::CompressionAlgorithm *CompressionScheme = + new llvm::compression::ZlibCompressionAlgorithm(); + + CompressionScheme = CompressionScheme->whenSupported(); + if (CompressionScheme->notNone()) { + + SmallVector CompressedBuffer; + + CompressionScheme->compress(llvm::arrayRefFromStringRef(Blob.drop_back(1)), + CompressedBuffer); RecordDataType Record[] = {SM_SLOC_BUFFER_BLOB_COMPRESSED, Blob.size() - 1}; Stream.EmitRecordWithBlob(SLocBufferBlobCompressedAbbrv, Record, llvm::toStringRef(CompressedBuffer)); diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -953,12 +953,15 @@ static bool getCompressDebugSections(opt::InputArgList &args) { StringRef s = args.getLastArgValue(OPT_compress_debug_sections, "none"); - if (s == "none") + if (s == "none") { return false; - if (s != "zlib") + } else if (s == "zlib") { + if (!compression::ZlibCompressionAlgorithm::Supported()) + error("--compress-debug-sections: zlib is not available"); + } else { error("unknown --compress-debug-sections value: " + s); - if (!compression::zlib::isAvailable()) - error("--compress-debug-sections: zlib is not available"); + } + return true; } diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp --- a/lld/ELF/InputSection.cpp +++ b/lld/ELF/InputSection.cpp @@ -118,7 +118,8 @@ uncompressedBuf = bAlloc().Allocate(size); } - if (Error e = compression::zlib::uncompress(rawData, uncompressedBuf, size)) + if (Error e = compression::ZlibCompressionAlgorithm().decompress( + rawData, uncompressedBuf, size)) fatal(toString(this) + ": uncompress failed: " + llvm::toString(std::move(e))); rawData = makeArrayRef(uncompressedBuf, size); @@ -208,7 +209,7 @@ auto *hdr = reinterpret_cast(rawData.data()); if (hdr->ch_type == ELFCOMPRESS_ZLIB) { - if (!compression::zlib::isAvailable()) + if (!compression::ZlibCompressionAlgorithm().supported()) error(toString(this) + " is compressed with ELFCOMPRESS_ZLIB, but lld is " "not built with zlib support"); } else { @@ -219,7 +220,6 @@ uncompressedSize = hdr->ch_size; alignment = std::max(hdr->ch_addralign, 1); - rawData = rawData.slice(sizeof(*hdr)); } InputSection *InputSectionBase::getLinkOrderDep() const { @@ -1217,10 +1217,24 @@ // If this is a compressed section, uncompress section contents directly // to the buffer. if (uncompressedSize >= 0) { + auto *hdr = reinterpret_cast(rawData.data()); size_t size = uncompressedSize; - if (Error e = compression::zlib::uncompress(rawData, buf, size)) - fatal(toString(this) + - ": uncompress failed: " + llvm::toString(std::move(e))); + if (hdr->ch_type == ELFCOMPRESS_ZLIB) { + if (!compression::ZlibCompressionAlgorithm().supported()) { + error(toString(this) + + " is compressed with ELFCOMPRESS_ZLIB, but lld is " + "not built with zlib support"); + } else { + if (Error e = compression::ZlibCompressionAlgorithm().decompress( + rawData.slice(sizeof(typename ELFT::Chdr)), buf, size)) + fatal(toString(this) + + ": uncompress failed: " + llvm::toString(std::move(e))); + } + } else { + error(toString(this) + ": unsupported compression type (" + + Twine(hdr->ch_type) + ")"); + return; + } uint8_t *bufEnd = buf + size; relocate(buf, bufEnd); return; diff --git a/llvm/include/llvm/Object/Decompressor.h b/llvm/include/llvm/Object/Decompressor.h --- a/llvm/include/llvm/Object/Decompressor.h +++ b/llvm/include/llvm/Object/Decompressor.h @@ -11,6 +11,7 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringRef.h" +#include "llvm/Support/Compression.h" #include "llvm/Support/Error.h" namespace llvm { @@ -44,10 +45,11 @@ private: Decompressor(StringRef Data); - Error consumeCompressedZLibHeader(bool Is64Bit, bool IsLittleEndian); + Error consumeCompressedSectionHeader(bool Is64Bit, bool IsLittleEndian); StringRef SectionData; uint64_t DecompressedSize; + compression::CompressionAlgorithm *CompressionScheme; }; } // end namespace object diff --git a/llvm/include/llvm/ProfileData/InstrProf.h b/llvm/include/llvm/ProfileData/InstrProf.h --- a/llvm/include/llvm/ProfileData/InstrProf.h +++ b/llvm/include/llvm/ProfileData/InstrProf.h @@ -26,6 +26,7 @@ #include "llvm/ProfileData/InstrProfData.inc" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Compiler.h" +#include "llvm/Support/Compression.h" #include "llvm/Support/Endian.h" #include "llvm/Support/Error.h" #include "llvm/Support/ErrorHandling.h" @@ -214,8 +215,9 @@ /// third field is the uncompressed strings; otherwise it is the /// compressed string. When the string compression is off, the /// second field will have value zero. -Error collectPGOFuncNameStrings(ArrayRef NameStrs, - bool doCompression, std::string &Result); +Error collectPGOFuncNameStrings( + ArrayRef NameStrs, + compression::CompressionAlgorithm *CompressionScheme, std::string &Result); /// Produce \c Result string with the same format described above. The input /// is vector of PGO function name variables that are referenced. diff --git a/llvm/include/llvm/Support/Compression.h b/llvm/include/llvm/Support/Compression.h --- a/llvm/include/llvm/Support/Compression.h +++ b/llvm/include/llvm/Support/Compression.h @@ -15,55 +15,189 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/Support/DataTypes.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/ErrorHandling.h" namespace llvm { template class SmallVectorImpl; class Error; namespace compression { -namespace zlib { -constexpr int NoCompression = 0; -constexpr int BestSpeedCompression = 1; -constexpr int DefaultCompression = 6; -constexpr int BestSizeCompression = 9; - -bool isAvailable(); - -void compress(ArrayRef Input, - SmallVectorImpl &CompressedBuffer, - int Level = DefaultCompression); - -Error uncompress(ArrayRef Input, uint8_t *UncompressedBuffer, - size_t &UncompressedSize); - -Error uncompress(ArrayRef Input, - SmallVectorImpl &UncompressedBuffer, - size_t UncompressedSize); - -} // End of namespace zlib - -namespace zstd { - -constexpr int NoCompression = -5; -constexpr int BestSpeedCompression = 1; -constexpr int DefaultCompression = 5; -constexpr int BestSizeCompression = 12; - -bool isAvailable(); - -void compress(ArrayRef Input, - SmallVectorImpl &CompressedBuffer, - int Level = DefaultCompression); - -Error uncompress(ArrayRef Input, uint8_t *UncompressedBuffer, - size_t &UncompressedSize); - -Error uncompress(ArrayRef Input, - SmallVectorImpl &UncompressedBuffer, - size_t UncompressedSize); - -} // End of namespace zstd +enum class SupportCompressionType : uint8_t { + Unknown = 255, ///< Abstract compression + None = 0, ///< No compression + Zlib = 1, ///< zlib style complession + ZStd = 2, ///< zstd style complession +}; + +// This is the base class of all compression algorithms that llvm support +// handles. +class CompressionAlgorithm { +public: + virtual SupportCompressionType getAlgorithmId() = 0; + + virtual StringRef getName() = 0; + + virtual bool supported() = 0; + + virtual int getBestSpeedLevel() = 0; + virtual int getDefaultLevel() = 0; + virtual int getBestSizeLevel() = 0; + + virtual void compress(ArrayRef Input, + SmallVectorImpl &CompressedBuffer, + int Level) = 0; + virtual void compress(ArrayRef Input, + SmallVectorImpl &CompressedBuffer) = 0; + + virtual Error decompress(ArrayRef Input, uint8_t *UncompressedBuffer, + size_t &UncompressedSize) = 0; + virtual Error decompress(ArrayRef Input, + SmallVectorImpl &UncompressedBuffer, + size_t UncompressedSize) = 0; + + virtual CompressionAlgorithm *when(bool useCompression) = 0; + virtual CompressionAlgorithm *whenSupported() = 0; + + virtual bool notNone() = 0; +}; + +template +class CompressionAlgorithmImpl : public CompressionAlgorithm { +public: + virtual SupportCompressionType getAlgorithmId() { + return CompressionAlgorithmType::AlgorithmId; + } + + virtual StringRef getName() { return CompressionAlgorithmType::Name; } + + virtual bool supported() { return CompressionAlgorithmType::Supported(); } + + virtual int getBestSpeedLevel() { + return CompressionAlgorithmType::BestSpeedCompression; + } + virtual int getDefaultLevel() { + return CompressionAlgorithmType::DefaultCompression; + } + virtual int getBestSizeLevel() { + return CompressionAlgorithmType::BestSizeCompression; + } + + virtual void compress(ArrayRef Input, + SmallVectorImpl &CompressedBuffer, int Level) { + + return CompressionAlgorithmType::Compress(Input, CompressedBuffer, Level); + } + virtual void compress(ArrayRef Input, + SmallVectorImpl &CompressedBuffer) { + return CompressionAlgorithmType::Compress( + Input, CompressedBuffer, CompressionAlgorithmType::DefaultCompression); + } + + virtual Error decompress(ArrayRef Input, uint8_t *UncompressedBuffer, + size_t &UncompressedSize) { + return CompressionAlgorithmType::Decompress(Input, UncompressedBuffer, + UncompressedSize); + } + virtual Error decompress(ArrayRef Input, + SmallVectorImpl &UncompressedBuffer, + size_t UncompressedSize) { + UncompressedBuffer.resize_for_overwrite(UncompressedSize); + Error E = CompressionAlgorithmType::Decompress( + Input, UncompressedBuffer.data(), UncompressedSize); + if (UncompressedSize < UncompressedBuffer.size()) + UncompressedBuffer.truncate(UncompressedSize); + return E; + } + + virtual CompressionAlgorithm *when(bool useCompression); + virtual CompressionAlgorithm *whenSupported() { + return this->when(CompressionAlgorithmType::Supported()); + } + + virtual bool notNone() { + return CompressionAlgorithmType::AlgorithmId != + SupportCompressionType::None; + } +}; + +class ZStdCompressionAlgorithm + : public CompressionAlgorithmImpl { +public: + constexpr static SupportCompressionType AlgorithmId = + SupportCompressionType::ZStd; + constexpr static StringRef Name = "zstd"; + constexpr static int BestSpeedCompression = 1; + constexpr static int DefaultCompression = 5; + constexpr static int BestSizeCompression = 12; + static void Compress(ArrayRef Input, + SmallVectorImpl &CompressedBuffer, int Level); + static Error Decompress(ArrayRef Input, uint8_t *UncompressedBuffer, + size_t &UncompressedSize); + static bool Supported(); + + constexpr ZStdCompressionAlgorithm(){}; +}; + +class ZlibCompressionAlgorithm + : public CompressionAlgorithmImpl { +public: + constexpr static SupportCompressionType AlgorithmId = + SupportCompressionType::Zlib; + constexpr static StringRef Name = "zlib"; + constexpr static int BestSpeedCompression = 1; + constexpr static int DefaultCompression = 6; + constexpr static int BestSizeCompression = 9; + static void Compress(ArrayRef Input, + SmallVectorImpl &CompressedBuffer, int Level); + static Error Decompress(ArrayRef Input, uint8_t *UncompressedBuffer, + size_t &UncompressedSize); + static bool Supported(); + + constexpr ZlibCompressionAlgorithm(){}; +}; + +class UnknownCompressionAlgorithm + : public CompressionAlgorithmImpl { +public: + constexpr static SupportCompressionType AlgorithmId = + SupportCompressionType::Unknown; + constexpr static StringRef Name = "unknown"; + constexpr static int BestSpeedCompression = -999; + constexpr static int DefaultCompression = -999; + constexpr static int BestSizeCompression = -999; + static void Compress(ArrayRef Input, + SmallVectorImpl &CompressedBuffer, int Level); + static Error Decompress(ArrayRef Input, uint8_t *UncompressedBuffer, + size_t &UncompressedSize); + static bool Supported(); + + constexpr UnknownCompressionAlgorithm(){}; +}; + +class NoneCompressionAlgorithm + : public CompressionAlgorithmImpl { +public: + constexpr static SupportCompressionType AlgorithmId = + SupportCompressionType::None; + constexpr static StringRef Name = "none"; + constexpr static int BestSpeedCompression = 0; + constexpr static int DefaultCompression = 0; + constexpr static int BestSizeCompression = 0; + static void Compress(ArrayRef Input, + SmallVectorImpl &CompressedBuffer, int Level); + static Error Decompress(ArrayRef Input, uint8_t *UncompressedBuffer, + size_t &UncompressedSize); + static bool Supported(); + + constexpr NoneCompressionAlgorithm(){}; +}; + +llvm::compression::CompressionAlgorithm * +CompressionAlgorithmFromId(uint8_t CompressionSchemeId); +llvm::compression::CompressionAlgorithm * +CompressionAlgorithmFromId(SupportCompressionType CompressionSchemeId); } // End of namespace compression diff --git a/llvm/lib/MC/ELFObjectWriter.cpp b/llvm/lib/MC/ELFObjectWriter.cpp --- a/llvm/lib/MC/ELFObjectWriter.cpp +++ b/llvm/lib/MC/ELFObjectWriter.cpp @@ -847,15 +847,14 @@ auto &MC = Asm.getContext(); const auto &MAI = MC.getAsmInfo(); - - bool CompressionEnabled = - MAI->compressDebugSections() != DebugCompressionType::None; + const DebugCompressionType CompressionType = MAI->compressDebugSections(); + bool CompressionEnabled = CompressionType != DebugCompressionType::None; if (!CompressionEnabled || !SectionName.startswith(".debug_")) { Asm.writeSectionData(W.OS, &Section, Layout); return; } - assert(MAI->compressDebugSections() == DebugCompressionType::Z && + assert(CompressionType == DebugCompressionType::Z && "expected zlib style compression"); SmallVector UncompressedData; @@ -864,7 +863,7 @@ SmallVector Compressed; const uint32_t ChType = ELF::ELFCOMPRESS_ZLIB; - compression::zlib::compress( + compression::ZlibCompressionAlgorithm().compress( makeArrayRef(reinterpret_cast(UncompressedData.data()), UncompressedData.size()), Compressed); diff --git a/llvm/lib/ObjCopy/ELF/ELFObject.cpp b/llvm/lib/ObjCopy/ELF/ELFObject.cpp --- a/llvm/lib/ObjCopy/ELF/ELFObject.cpp +++ b/llvm/lib/ObjCopy/ELF/ELFObject.cpp @@ -439,10 +439,25 @@ ArrayRef Compressed = Sec.OriginalData.slice(sizeof(Elf_Chdr_Impl)); SmallVector DecompressedContent; - if (Error Err = compression::zlib::uncompress(Compressed, DecompressedContent, - static_cast(Sec.Size))) - return createStringError(errc::invalid_argument, - "'" + Sec.Name + "': " + toString(std::move(Err))); + DebugCompressionType CompressionType = + reinterpret_cast *>(Sec.OriginalData.data()) + ->ch_type == ELF::ELFCOMPRESS_ZLIB + ? DebugCompressionType::Z + : DebugCompressionType::None; + + switch (CompressionType) { + case DebugCompressionType::Z: + if (Error Err1 = compression::ZlibCompressionAlgorithm().decompress( + Compressed, DecompressedContent, static_cast(Sec.Size))) { + return createStringError(errc::invalid_argument, + "'" + Sec.Name + + "': " + toString(std::move(Err1))); + } + break; + case DebugCompressionType::None: + llvm_unreachable("unexpected DebugCompressionType::None"); + break; + } uint8_t *Buf = reinterpret_cast(Out.getBufferStart()) + Sec.Offset; std::copy(DecompressedContent.begin(), DecompressedContent.end(), Buf); @@ -512,7 +527,14 @@ DebugCompressionType CompressionType) : SectionBase(Sec), CompressionType(CompressionType), DecompressedSize(Sec.OriginalData.size()), DecompressedAlign(Sec.Align) { - compression::zlib::compress(OriginalData, CompressedData); + switch (CompressionType) { + case DebugCompressionType::Z: + compression::ZlibCompressionAlgorithm().compress(OriginalData, + CompressedData); + break; + case DebugCompressionType::None: + break; + } assert(CompressionType != DebugCompressionType::None); Flags |= ELF::SHF_COMPRESSED; diff --git a/llvm/lib/Object/Decompressor.cpp b/llvm/lib/Object/Decompressor.cpp --- a/llvm/lib/Object/Decompressor.cpp +++ b/llvm/lib/Object/Decompressor.cpp @@ -19,11 +19,9 @@ Expected Decompressor::create(StringRef Name, StringRef Data, bool IsLE, bool Is64Bit) { - if (!compression::zlib::isAvailable()) - return createError("zlib is not available"); Decompressor D(Data); - if (Error Err = D.consumeCompressedZLibHeader(Is64Bit, IsLE)) + if (Error Err = D.consumeCompressedSectionHeader(Is64Bit, IsLE)) return std::move(Err); return D; } @@ -31,8 +29,8 @@ Decompressor::Decompressor(StringRef Data) : SectionData(Data), DecompressedSize(0) {} -Error Decompressor::consumeCompressedZLibHeader(bool Is64Bit, - bool IsLittleEndian) { +Error Decompressor::consumeCompressedSectionHeader(bool Is64Bit, + bool IsLittleEndian) { using namespace ELF; uint64_t HdrSize = Is64Bit ? sizeof(Elf64_Chdr) : sizeof(Elf32_Chdr); if (SectionData.size() < HdrSize) @@ -40,10 +38,15 @@ DataExtractor Extractor(SectionData, IsLittleEndian, 0); uint64_t Offset = 0; - if (Extractor.getUnsigned(&Offset, Is64Bit ? sizeof(Elf64_Word) - : sizeof(Elf32_Word)) != - ELFCOMPRESS_ZLIB) + uint64_t ELFCompressionSchemeId = Extractor.getUnsigned( + &Offset, Is64Bit ? sizeof(Elf64_Word) : sizeof(Elf32_Word)); + if (ELFCompressionSchemeId == ELFCOMPRESS_ZLIB) { + CompressionScheme = new compression::ZlibCompressionAlgorithm(); + } else { return createError("unsupported compression type"); + } + if (!CompressionScheme->supported()) + return createError(CompressionScheme->getName() + " is not available"); // Skip Elf64_Chdr::ch_reserved field. if (Is64Bit) @@ -57,6 +60,6 @@ Error Decompressor::decompress(MutableArrayRef Buffer) { size_t Size = Buffer.size(); - return compression::zlib::uncompress(arrayRefFromStringRef(SectionData), + return CompressionScheme->decompress(arrayRefFromStringRef(SectionData), Buffer.data(), Size); } diff --git a/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp b/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp --- a/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp +++ b/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp @@ -119,7 +119,7 @@ return Err; if (CompressedLen > 0) { - if (!compression::zlib::isAvailable()) + if (!compression::ZlibCompressionAlgorithm().supported()) return make_error( coveragemap_error::decompression_failed); @@ -129,7 +129,7 @@ // Read compressed filenames. StringRef CompressedFilenames = Data.substr(0, CompressedLen); Data = Data.substr(CompressedLen); - auto Err = compression::zlib::uncompress( + auto Err = compression::ZlibCompressionAlgorithm().decompress( arrayRefFromStringRef(CompressedFilenames), StorageBuf, UncompressedLen); if (Err) { diff --git a/llvm/lib/ProfileData/Coverage/CoverageMappingWriter.cpp b/llvm/lib/ProfileData/Coverage/CoverageMappingWriter.cpp --- a/llvm/lib/ProfileData/Coverage/CoverageMappingWriter.cpp +++ b/llvm/lib/ProfileData/Coverage/CoverageMappingWriter.cpp @@ -47,12 +47,18 @@ } SmallVector CompressedStr; - bool doCompression = Compress && compression::zlib::isAvailable() && - DoInstrProfNameCompression; + compression::CompressionAlgorithm *CompressionScheme = + new compression::ZlibCompressionAlgorithm(); + + CompressionScheme = + CompressionScheme->when(Compress && DoInstrProfNameCompression) + ->whenSupported(); + bool doCompression = CompressionScheme->notNone(); + if (doCompression) - compression::zlib::compress(arrayRefFromStringRef(FilenamesStr), + CompressionScheme->compress(arrayRefFromStringRef(FilenamesStr), CompressedStr, - compression::zlib::BestSizeCompression); + CompressionScheme->getBestSizeLevel()); // ::= // diff --git a/llvm/lib/ProfileData/InstrProf.cpp b/llvm/lib/ProfileData/InstrProf.cpp --- a/llvm/lib/ProfileData/InstrProf.cpp +++ b/llvm/lib/ProfileData/InstrProf.cpp @@ -435,8 +435,9 @@ return 0; } -Error collectPGOFuncNameStrings(ArrayRef NameStrs, - bool doCompression, std::string &Result) { +Error collectPGOFuncNameStrings( + ArrayRef NameStrs, + compression::CompressionAlgorithm *CompressionScheme, std::string &Result) { assert(!NameStrs.empty() && "No name data to emit"); uint8_t Header[16], *P = Header; @@ -460,14 +461,14 @@ return Error::success(); }; - if (!doCompression) { + if (CompressionScheme->getAlgorithmId() == + compression::NoneCompressionAlgorithm::AlgorithmId) { return WriteStringToResult(0, UncompressedNameStrings); } - SmallVector CompressedNameStrings; - compression::zlib::compress(arrayRefFromStringRef(UncompressedNameStrings), + CompressionScheme->compress(arrayRefFromStringRef(UncompressedNameStrings), CompressedNameStrings, - compression::zlib::BestSizeCompression); + CompressionScheme->getBestSizeLevel()); return WriteStringToResult(CompressedNameStrings.size(), toStringRef(CompressedNameStrings)); @@ -486,8 +487,11 @@ for (auto *NameVar : NameVars) { NameStrs.push_back(std::string(getPGOFuncNameVarInitializer(NameVar))); } + compression::CompressionAlgorithm *CompressionScheme = + new compression::ZlibCompressionAlgorithm(); return collectPGOFuncNameStrings( - NameStrs, compression::zlib::isAvailable() && doCompression, Result); + NameStrs, CompressionScheme->when(doCompression)->whenSupported(), + Result); } Error readPGOFuncNameStrings(StringRef NameStrings, InstrProfSymtab &Symtab) { @@ -503,10 +507,12 @@ SmallVector UncompressedNameStrings; StringRef NameStrings; if (isCompressed) { - if (!llvm::compression::zlib::isAvailable()) + compression::CompressionAlgorithm *CompressionScheme = + new compression::ZlibCompressionAlgorithm(); + if (!CompressionScheme->supported()) return make_error(instrprof_error::zlib_unavailable); - if (Error E = compression::zlib::uncompress( + if (Error E = CompressionScheme->decompress( makeArrayRef(P, CompressedSize), UncompressedNameStrings, UncompressedSize)) { consumeError(std::move(E)); diff --git a/llvm/lib/ProfileData/InstrProfCorrelator.cpp b/llvm/lib/ProfileData/InstrProfCorrelator.cpp --- a/llvm/lib/ProfileData/InstrProfCorrelator.cpp +++ b/llvm/lib/ProfileData/InstrProfCorrelator.cpp @@ -15,6 +15,7 @@ #include "llvm/DebugInfo/DWARF/DWARFLocationExpression.h" #include "llvm/DebugInfo/DWARF/DWARFUnit.h" #include "llvm/Object/MachO.h" +#include "llvm/Support/Compression.h" #include "llvm/Support/Debug.h" #define DEBUG_TYPE "correlator" @@ -148,8 +149,9 @@ return make_error( instrprof_error::unable_to_correlate_profile, "could not find any profile metadata in debug info"); - auto Result = - collectPGOFuncNameStrings(NamesVec, /*doCompression=*/false, Names); + auto Result = collectPGOFuncNameStrings( + NamesVec, + /*CompressionScheme=*/new compression::NoneCompressionAlgorithm(), Names); CounterOffsets.clear(); NamesVec.clear(); return Result; diff --git a/llvm/lib/ProfileData/SampleProfReader.cpp b/llvm/lib/ProfileData/SampleProfReader.cpp --- a/llvm/lib/ProfileData/SampleProfReader.cpp +++ b/llvm/lib/ProfileData/SampleProfReader.cpp @@ -877,12 +877,12 @@ if (std::error_code EC = CompressSize.getError()) return EC; - if (!llvm::compression::zlib::isAvailable()) + if (!llvm::compression::ZlibCompressionAlgorithm().supported()) return sampleprof_error::zlib_unavailable; uint8_t *Buffer = Allocator.Allocate(DecompressBufSize); size_t UCSize = DecompressBufSize; - llvm::Error E = compression::zlib::uncompress( + llvm::Error E = compression::ZlibCompressionAlgorithm().decompress( makeArrayRef(Data, *CompressSize), Buffer, UCSize); if (E) return sampleprof_error::uncompress_failed; diff --git a/llvm/lib/ProfileData/SampleProfWriter.cpp b/llvm/lib/ProfileData/SampleProfWriter.cpp --- a/llvm/lib/ProfileData/SampleProfWriter.cpp +++ b/llvm/lib/ProfileData/SampleProfWriter.cpp @@ -78,7 +78,9 @@ } std::error_code SampleProfileWriterExtBinaryBase::compressAndOutput() { - if (!llvm::compression::zlib::isAvailable()) + compression::CompressionAlgorithm *CompressionScheme = + new compression::ZlibCompressionAlgorithm(); + if (!CompressionScheme->supported()) return sampleprof_error::zlib_unavailable; std::string &UncompressedStrings = static_cast(LocalBufStream.get())->str(); @@ -86,9 +88,9 @@ return sampleprof_error::success; auto &OS = *OutputStream; SmallVector CompressedStrings; - compression::zlib::compress(arrayRefFromStringRef(UncompressedStrings), + CompressionScheme->compress(arrayRefFromStringRef(UncompressedStrings), CompressedStrings, - compression::zlib::BestSizeCompression); + CompressionScheme->getBestSizeLevel()); encodeULEB128(UncompressedStrings.size(), OS); encodeULEB128(CompressedStrings.size(), OS); OS << toStringRef(CompressedStrings); diff --git a/llvm/lib/Support/Compression.cpp b/llvm/lib/Support/Compression.cpp --- a/llvm/lib/Support/Compression.cpp +++ b/llvm/lib/Support/Compression.cpp @@ -27,6 +27,80 @@ using namespace llvm; using namespace llvm::compression; +template +CompressionAlgorithm * +CompressionAlgorithmImpl::when(bool useCompression) { + if (useCompression) { + return this; + } + return new NoneCompressionAlgorithm(); +} + +constexpr SupportCompressionType UnknownCompressionAlgorithm::AlgorithmId; +constexpr StringRef UnknownCompressionAlgorithm::Name; +constexpr int UnknownCompressionAlgorithm::BestSpeedCompression; +constexpr int UnknownCompressionAlgorithm::DefaultCompression; +constexpr int UnknownCompressionAlgorithm::BestSizeCompression; + +bool UnknownCompressionAlgorithm::Supported() { return false; }; + +void UnknownCompressionAlgorithm::Compress( + ArrayRef Input, SmallVectorImpl &CompressedBuffer, + int Level) { + llvm_unreachable("method:\"compress\" is unsupported for compression " + "algorithm:\"unknown\", reason:\"can't call on unknown\""); +}; +Error UnknownCompressionAlgorithm::Decompress(ArrayRef Input, + uint8_t *UncompressedBuffer, + size_t &UncompressedSize) { + llvm_unreachable("method:\"decompress\" is unsupported for compression " + "algorithm:\"unknown\", reason:\"can't call on unknown\""); +} + +constexpr SupportCompressionType NoneCompressionAlgorithm::AlgorithmId; +constexpr StringRef NoneCompressionAlgorithm::Name; +constexpr int NoneCompressionAlgorithm::BestSpeedCompression; +constexpr int NoneCompressionAlgorithm::DefaultCompression; +constexpr int NoneCompressionAlgorithm::BestSizeCompression; + +bool NoneCompressionAlgorithm::Supported() { return true; }; + +void NoneCompressionAlgorithm::Compress( + ArrayRef Input, SmallVectorImpl &CompressedBuffer, + int Level) { + unsigned long CompressedSize = Input.size(); + CompressedBuffer.resize_for_overwrite(CompressedSize); + // SmallVectorImpl() + CompressedBuffer.assign(SmallVector(Input.begin(), Input.end())); + + // Tell MemorySanitizer that zlib output buffer is fully initialized. + // This avoids a false report when running LLVM with uninstrumented ZLib. + __msan_unpoison(CompressedBuffer.data(), CompressedSize); + if (CompressedSize < CompressedBuffer.size()) + CompressedBuffer.truncate(CompressedSize); +}; +Error NoneCompressionAlgorithm::Decompress(ArrayRef Input, + uint8_t *UncompressedBuffer, + size_t &UncompressedSize) { + // Tell MemorySanitizer that zlib output buffer is fully initialized. + // This avoids a false report when running LLVM with uninstrumented ZLib. + if (UncompressedSize < Input.size()) { + return make_error("decompressed buffer target size too small", + inconvertibleErrorCode()); + } + UncompressedSize = Input.size(); + memcpy(UncompressedBuffer, Input.data(), UncompressedSize); + + __msan_unpoison(UncompressedBuffer, UncompressedSize); + return Error::success(); +} + +constexpr SupportCompressionType ZlibCompressionAlgorithm::AlgorithmId; +constexpr StringRef ZlibCompressionAlgorithm::Name; +constexpr int ZlibCompressionAlgorithm::BestSpeedCompression; +constexpr int ZlibCompressionAlgorithm::DefaultCompression; +constexpr int ZlibCompressionAlgorithm::BestSizeCompression; + #if LLVM_ENABLE_ZLIB static StringRef convertZlibCodeToString(int Code) { @@ -45,10 +119,11 @@ } } -bool zlib::isAvailable() { return true; } +bool ZlibCompressionAlgorithm::Supported() { return true; }; -void zlib::compress(ArrayRef Input, - SmallVectorImpl &CompressedBuffer, int Level) { +void ZlibCompressionAlgorithm::Compress( + ArrayRef Input, SmallVectorImpl &CompressedBuffer, + int Level) { unsigned long CompressedSize = ::compressBound(Input.size()); CompressedBuffer.resize_for_overwrite(CompressedSize); int Res = ::compress2((Bytef *)CompressedBuffer.data(), &CompressedSize, @@ -61,10 +136,10 @@ __msan_unpoison(CompressedBuffer.data(), CompressedSize); if (CompressedSize < CompressedBuffer.size()) CompressedBuffer.truncate(CompressedSize); -} - -Error zlib::uncompress(ArrayRef Input, uint8_t *UncompressedBuffer, - size_t &UncompressedSize) { +}; +Error ZlibCompressionAlgorithm::Decompress(ArrayRef Input, + uint8_t *UncompressedBuffer, + size_t &UncompressedSize) { int Res = ::uncompress((Bytef *)UncompressedBuffer, (uLongf *)&UncompressedSize, (const Bytef *)Input.data(), Input.size()); @@ -74,42 +149,41 @@ return Res ? make_error(convertZlibCodeToString(Res), inconvertibleErrorCode()) : Error::success(); -} - -Error zlib::uncompress(ArrayRef Input, - SmallVectorImpl &UncompressedBuffer, - size_t UncompressedSize) { - UncompressedBuffer.resize_for_overwrite(UncompressedSize); - Error E = - zlib::uncompress(Input, UncompressedBuffer.data(), UncompressedSize); - if (UncompressedSize < UncompressedBuffer.size()) - UncompressedBuffer.truncate(UncompressedSize); - return E; -} +}; #else -bool zlib::isAvailable() { return false; } -void zlib::compress(ArrayRef Input, - SmallVectorImpl &CompressedBuffer, int Level) { - llvm_unreachable("zlib::compress is unavailable"); -} -Error zlib::uncompress(ArrayRef Input, uint8_t *UncompressedBuffer, - size_t &UncompressedSize) { - llvm_unreachable("zlib::uncompress is unavailable"); -} -Error zlib::uncompress(ArrayRef Input, - SmallVectorImpl &UncompressedBuffer, - size_t UncompressedSize) { - llvm_unreachable("zlib::uncompress is unavailable"); -} +bool ZlibCompressionAlgorithm::Supported() { return false; }; + +void ZlibCompressionAlgorithm::Compress( + ArrayRef Input, SmallVectorImpl &CompressedBuffer, + int Level) { + llvm_unreachable( + "method:\"compress\" is unsupported for compression algorithm:\"zlib\", " + "reason:\"llvm not compiled with zlib support\""); +}; +Error ZlibCompressionAlgorithm::Decompress(ArrayRef Input, + uint8_t *UncompressedBuffer, + size_t &UncompressedSize) { + llvm_unreachable( + "method:\"decompress\" is unsupported for compression " + "algorithm:\"zlib\", reason:\"llvm not compiled with zlib support\""); +}; + #endif +constexpr SupportCompressionType ZStdCompressionAlgorithm::AlgorithmId; +constexpr StringRef ZStdCompressionAlgorithm::Name; +constexpr int ZStdCompressionAlgorithm::BestSpeedCompression; +constexpr int ZStdCompressionAlgorithm::DefaultCompression; +constexpr int ZStdCompressionAlgorithm::BestSizeCompression; + #if LLVM_ENABLE_ZSTD -bool zstd::isAvailable() { return true; } +bool ZStdCompressionAlgorithm::Supported() { return true; }; -void zstd::compress(ArrayRef Input, - SmallVectorImpl &CompressedBuffer, int Level) { +void ZStdCompressionAlgorithm::Compress( + ArrayRef Input, SmallVectorImpl &CompressedBuffer, + int Level) { unsigned long CompressedBufferSize = ::ZSTD_compressBound(Input.size()); CompressedBuffer.resize_for_overwrite(CompressedBufferSize); unsigned long CompressedSize = @@ -122,10 +196,10 @@ __msan_unpoison(CompressedBuffer.data(), CompressedSize); if (CompressedSize < CompressedBuffer.size()) CompressedBuffer.truncate(CompressedSize); -} - -Error zstd::uncompress(ArrayRef Input, uint8_t *UncompressedBuffer, - size_t &UncompressedSize) { +}; +Error ZStdCompressionAlgorithm::Decompress(ArrayRef Input, + uint8_t *UncompressedBuffer, + size_t &UncompressedSize) { const size_t Res = ::ZSTD_decompress(UncompressedBuffer, UncompressedSize, (const uint8_t *)Input.data(), Input.size()); @@ -136,32 +210,53 @@ return ZSTD_isError(Res) ? make_error(ZSTD_getErrorName(Res), inconvertibleErrorCode()) : Error::success(); -} - -Error zstd::uncompress(ArrayRef Input, - SmallVectorImpl &UncompressedBuffer, - size_t UncompressedSize) { - UncompressedBuffer.resize_for_overwrite(UncompressedSize); - Error E = - zstd::uncompress(Input, UncompressedBuffer.data(), UncompressedSize); - if (UncompressedSize < UncompressedBuffer.size()) - UncompressedBuffer.truncate(UncompressedSize); - return E; -} +}; #else -bool zstd::isAvailable() { return false; } -void zstd::compress(ArrayRef Input, - SmallVectorImpl &CompressedBuffer, int Level) { - llvm_unreachable("zstd::compress is unavailable"); -} -Error zstd::uncompress(ArrayRef Input, uint8_t *UncompressedBuffer, - size_t &UncompressedSize) { - llvm_unreachable("zstd::uncompress is unavailable"); +bool ZStdCompressionAlgorithm::Supported() { return false; }; + +void ZStdCompressionAlgorithm::Compress( + ArrayRef Input, SmallVectorImpl &CompressedBuffer, + int Level) { + llvm_unreachable( + "method:\"compress\" is unsupported for compression algorithm:\"zstd\", " + "reason:\"llvm not compiled with zstd support\""); +}; +Error ZStdCompressionAlgorithm::Decompress(ArrayRef Input, + uint8_t *UncompressedBuffer, + size_t &UncompressedSize) { + llvm_unreachable( + "method:\"decompress\" is unsupported for compression " + "algorithm:\"zstd\", reason:\"llvm not compiled with zstd support\""); +}; + +#endif + +llvm::compression::CompressionAlgorithm * +llvm::compression::CompressionAlgorithmFromId(uint8_t CompressionSchemeId) { + llvm::compression::CompressionAlgorithm *CompressionScheme = + new llvm::compression::UnknownCompressionAlgorithm(); + switch (CompressionSchemeId) { + case static_cast( + llvm::compression::NoneCompressionAlgorithm::AlgorithmId): + CompressionScheme = new llvm::compression::NoneCompressionAlgorithm(); + break; + case static_cast( + llvm::compression::ZlibCompressionAlgorithm::AlgorithmId): + CompressionScheme = new llvm::compression::ZlibCompressionAlgorithm(); + break; + case static_cast( + llvm::compression::ZStdCompressionAlgorithm::AlgorithmId): + CompressionScheme = new llvm::compression::ZStdCompressionAlgorithm(); + break; + default: + break; + } + return CompressionScheme; } -Error zstd::uncompress(ArrayRef Input, - SmallVectorImpl &UncompressedBuffer, - size_t UncompressedSize) { - llvm_unreachable("zstd::uncompress is unavailable"); + +llvm::compression::CompressionAlgorithm * +llvm::compression::CompressionAlgorithmFromId( + llvm::compression::SupportCompressionType CompressionSchemeId) { + return CompressionAlgorithmFromId(static_cast(CompressionSchemeId)); } -#endif diff --git a/llvm/tools/llvm-mc/llvm-mc.cpp b/llvm/tools/llvm-mc/llvm-mc.cpp --- a/llvm/tools/llvm-mc/llvm-mc.cpp +++ b/llvm/tools/llvm-mc/llvm-mc.cpp @@ -401,7 +401,7 @@ MAI->setRelaxELFRelocations(RelaxELFRel); if (CompressDebugSections != DebugCompressionType::None) { - if (!compression::zlib::isAvailable()) { + if (!compression::ZlibCompressionAlgorithm().supported()) { WithColor::error(errs(), ProgName) << "build tools with zlib to enable -compress-debug-sections"; return 1; diff --git a/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp b/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp --- a/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp +++ b/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp @@ -728,10 +728,16 @@ errc::invalid_argument, "invalid or unsupported --compress-debug-sections format: %s", A->getValue()); - if (!compression::zlib::isAvailable()) - return createStringError( - errc::invalid_argument, - "LLVM was not compiled with LLVM_ENABLE_ZLIB: can not compress"); + switch (Config.CompressionType) { + case DebugCompressionType::None: + break; + case DebugCompressionType::Z: + if (!compression::ZlibCompressionAlgorithm().supported()) + return createStringError( + errc::invalid_argument, + "LLVM was not compiled with LLVM_ENABLE_ZLIB: can not compress"); + break; + } } Config.AddGnuDebugLink = InputArgs.getLastArgValue(OBJCOPY_add_gnu_debuglink); @@ -993,7 +999,8 @@ "--decompress-debug-sections"); } - if (Config.DecompressDebugSections && !compression::zlib::isAvailable()) + if (Config.DecompressDebugSections && + !compression::ZlibCompressionAlgorithm().supported()) return createStringError( errc::invalid_argument, "LLVM was not compiled with LLVM_ENABLE_ZLIB: cannot decompress"); diff --git a/llvm/unittests/ProfileData/InstrProfTest.cpp b/llvm/unittests/ProfileData/InstrProfTest.cpp --- a/llvm/unittests/ProfileData/InstrProfTest.cpp +++ b/llvm/unittests/ProfileData/InstrProfTest.cpp @@ -1146,19 +1146,23 @@ for (bool DoCompression : {false, true}) { // Compressing: std::string FuncNameStrings1; - EXPECT_THAT_ERROR(collectPGOFuncNameStrings( - FuncNames1, - (DoCompression && compression::zlib::isAvailable()), - FuncNameStrings1), - Succeeded()); + EXPECT_THAT_ERROR( + collectPGOFuncNameStrings(FuncNames1, + (new compression::ZlibCompressionAlgorithm()) + ->when(DoCompression) + ->whenSupported(), + FuncNameStrings1), + Succeeded()); // Compressing: std::string FuncNameStrings2; - EXPECT_THAT_ERROR(collectPGOFuncNameStrings( - FuncNames2, - (DoCompression && compression::zlib::isAvailable()), - FuncNameStrings2), - Succeeded()); + EXPECT_THAT_ERROR( + collectPGOFuncNameStrings(FuncNames2, + (new compression::ZlibCompressionAlgorithm()) + ->when(DoCompression) + ->whenSupported(), + FuncNameStrings2), + Succeeded()); for (int Padding = 0; Padding < 2; Padding++) { // Join with paddings : diff --git a/llvm/unittests/Support/CompressionTest.cpp b/llvm/unittests/Support/CompressionTest.cpp --- a/llvm/unittests/Support/CompressionTest.cpp +++ b/llvm/unittests/Support/CompressionTest.cpp @@ -22,31 +22,43 @@ namespace { -#if LLVM_ENABLE_ZLIB -static void testZlibCompression(StringRef Input, int Level) { +static void testCompressionAlgorithm( + StringRef Input, int Level, + compression::CompressionAlgorithm *CompressionScheme, + std::string ExpectedDestinationBufferTooSmallErrorMessage) { SmallVector Compressed; SmallVector Uncompressed; - zlib::compress(arrayRefFromStringRef(Input), Compressed, Level); + CompressionScheme->compress(arrayRefFromStringRef(Input), Compressed, Level); // Check that uncompressed buffer is the same as original. - Error E = zlib::uncompress(Compressed, Uncompressed, Input.size()); + Error E = + CompressionScheme->decompress(Compressed, Uncompressed, Input.size()); consumeError(std::move(E)); EXPECT_EQ(Input, toStringRef(Uncompressed)); if (Input.size() > 0) { // Uncompression fails if expected length is too short. - E = zlib::uncompress(Compressed, Uncompressed, Input.size() - 1); - EXPECT_EQ("zlib error: Z_BUF_ERROR", llvm::toString(std::move(E))); + E = CompressionScheme->decompress(Compressed, Uncompressed, + Input.size() - 1); + EXPECT_EQ(ExpectedDestinationBufferTooSmallErrorMessage, + llvm::toString(std::move(E))); } } +#if LLVM_ENABLE_ZLIB +static void testZlibCompression(StringRef Input, int Level) { + testCompressionAlgorithm(Input, Level, new ZlibCompressionAlgorithm(), + "zlib error: Z_BUF_ERROR"); +} + TEST(CompressionTest, Zlib) { - testZlibCompression("", zlib::DefaultCompression); + compression::CompressionAlgorithm *CompressionScheme = + new compression::ZlibCompressionAlgorithm(); + testZlibCompression("", CompressionScheme->getDefaultLevel()); - testZlibCompression("hello, world!", zlib::NoCompression); - testZlibCompression("hello, world!", zlib::BestSizeCompression); - testZlibCompression("hello, world!", zlib::BestSpeedCompression); - testZlibCompression("hello, world!", zlib::DefaultCompression); + testZlibCompression("hello, world!", CompressionScheme->getBestSizeLevel()); + testZlibCompression("hello, world!", CompressionScheme->getBestSpeedLevel()); + testZlibCompression("hello, world!", CompressionScheme->getDefaultLevel()); const size_t kSize = 1024; char BinaryData[kSize]; @@ -54,38 +66,27 @@ BinaryData[i] = i & 255; StringRef BinaryDataStr(BinaryData, kSize); - testZlibCompression(BinaryDataStr, zlib::NoCompression); - testZlibCompression(BinaryDataStr, zlib::BestSizeCompression); - testZlibCompression(BinaryDataStr, zlib::BestSpeedCompression); - testZlibCompression(BinaryDataStr, zlib::DefaultCompression); + testZlibCompression(BinaryDataStr, CompressionScheme->getBestSizeLevel()); + testZlibCompression(BinaryDataStr, CompressionScheme->getBestSpeedLevel()); + testZlibCompression(BinaryDataStr, CompressionScheme->getDefaultLevel()); } #endif #if LLVM_ENABLE_ZSTD -static void testZstdCompression(StringRef Input, int Level) { - SmallVector Compressed; - SmallVector Uncompressed; - zstd::compress(arrayRefFromStringRef(Input), Compressed, Level); - // Check that uncompressed buffer is the same as original. - Error E = zstd::uncompress(Compressed, Uncompressed, Input.size()); - consumeError(std::move(E)); - - EXPECT_EQ(Input, toStringRef(Uncompressed)); - if (Input.size() > 0) { - // Uncompression fails if expected length is too short. - E = zstd::uncompress(Compressed, Uncompressed, Input.size() - 1); - EXPECT_EQ("Destination buffer is too small", llvm::toString(std::move(E))); - } +static void testZStdCompression(StringRef Input, int Level) { + testCompressionAlgorithm(Input, Level, new ZStdCompressionAlgorithm(), + "Destination buffer is too small"); } TEST(CompressionTest, Zstd) { - testZstdCompression("", zstd::DefaultCompression); + compression::CompressionAlgorithm *CompressionScheme = + new compression::ZStdCompressionAlgorithm(); + testZStdCompression("", CompressionScheme->getDefaultLevel()); - testZstdCompression("hello, world!", zstd::NoCompression); - testZstdCompression("hello, world!", zstd::BestSizeCompression); - testZstdCompression("hello, world!", zstd::BestSpeedCompression); - testZstdCompression("hello, world!", zstd::DefaultCompression); + testZStdCompression("hello, world!", CompressionScheme->getBestSizeLevel()); + testZStdCompression("hello, world!", CompressionScheme->getBestSpeedLevel()); + testZStdCompression("hello, world!", CompressionScheme->getDefaultLevel()); const size_t kSize = 1024; char BinaryData[kSize]; @@ -93,10 +94,9 @@ BinaryData[i] = i & 255; StringRef BinaryDataStr(BinaryData, kSize); - testZstdCompression(BinaryDataStr, zstd::NoCompression); - testZstdCompression(BinaryDataStr, zstd::BestSizeCompression); - testZstdCompression(BinaryDataStr, zstd::BestSpeedCompression); - testZstdCompression(BinaryDataStr, zstd::DefaultCompression); + testZStdCompression(BinaryDataStr, CompressionScheme->getBestSizeLevel()); + testZStdCompression(BinaryDataStr, CompressionScheme->getBestSpeedLevel()); + testZStdCompression(BinaryDataStr, CompressionScheme->getDefaultLevel()); } #endif }