mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-22 01:11:42 +00:00
[wpiutil] Vendor llvm and update to 13.0.0 (#4224)
This commit is contained in:
@@ -49,6 +49,7 @@
|
||||
#include "wpi/Errc.h"
|
||||
#include "wpi/Errno.h"
|
||||
#include "wpi/MappedFileRegion.h"
|
||||
#include "wpi/MathExtras.h"
|
||||
#include "wpi/SmallVector.h"
|
||||
#include "wpi/SmallVectorMemoryBuffer.h"
|
||||
#include "wpi/fs.h"
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
/*===--- ConvertUTF.c - Universal Character Names conversions ---------------===
|
||||
*
|
||||
* The LLVM Compiler Infrastructure
|
||||
*
|
||||
* This file is distributed under the University of Illinois Open Source
|
||||
* License. See LICENSE.TXT for details.
|
||||
* Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
* See https://llvm.org/LICENSE.txt for license information.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*
|
||||
*===------------------------------------------------------------------------=*/
|
||||
/*
|
||||
@@ -829,6 +828,6 @@ std::error_code UTF16ToCurCP(const wchar_t *utf16, size_t utf16_len,
|
||||
|
||||
#endif // _WIN32
|
||||
|
||||
} // namespace llvm
|
||||
} // namespace wpi
|
||||
|
||||
ConvertUTF_RESTORE_WARNINGS
|
||||
|
||||
@@ -1,19 +1,68 @@
|
||||
//===-- ConvertUTFWrapper.cpp - Wrap ConvertUTF.h with clang data types -----===
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "wpi/span.h"
|
||||
#include "wpi/ConvertUTF.h"
|
||||
#include "wpi/SmallVector.h"
|
||||
#include "wpi/ErrorHandling.h"
|
||||
#include "wpi/SwapByteOrder.h"
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
namespace wpi {
|
||||
|
||||
bool ConvertUTF8toWide(unsigned WideCharWidth, std::string_view Source,
|
||||
char *&ResultPtr, const UTF8 *&ErrorPtr) {
|
||||
assert(WideCharWidth == 1 || WideCharWidth == 2 || WideCharWidth == 4);
|
||||
ConversionResult result = conversionOK;
|
||||
// Copy the character span over.
|
||||
if (WideCharWidth == 1) {
|
||||
const UTF8 *Pos = reinterpret_cast<const UTF8*>(Source.data());
|
||||
if (!isLegalUTF8String(&Pos, reinterpret_cast<const UTF8*>(Source.data() + Source.size()))) {
|
||||
result = sourceIllegal;
|
||||
ErrorPtr = Pos;
|
||||
} else {
|
||||
memcpy(ResultPtr, Source.data(), Source.size());
|
||||
ResultPtr += Source.size();
|
||||
}
|
||||
} else if (WideCharWidth == 2) {
|
||||
const UTF8 *sourceStart = (const UTF8*)Source.data();
|
||||
// FIXME: Make the type of the result buffer correct instead of
|
||||
// using reinterpret_cast.
|
||||
UTF16 *targetStart = reinterpret_cast<UTF16*>(ResultPtr);
|
||||
ConversionFlags flags = strictConversion;
|
||||
result = ConvertUTF8toUTF16(
|
||||
&sourceStart, sourceStart + Source.size(),
|
||||
&targetStart, targetStart + Source.size(), flags);
|
||||
if (result == conversionOK)
|
||||
ResultPtr = reinterpret_cast<char*>(targetStart);
|
||||
else
|
||||
ErrorPtr = sourceStart;
|
||||
} else if (WideCharWidth == 4) {
|
||||
const UTF8 *sourceStart = (const UTF8*)Source.data();
|
||||
// FIXME: Make the type of the result buffer correct instead of
|
||||
// using reinterpret_cast.
|
||||
UTF32 *targetStart = reinterpret_cast<UTF32*>(ResultPtr);
|
||||
ConversionFlags flags = strictConversion;
|
||||
result = ConvertUTF8toUTF32(
|
||||
&sourceStart, sourceStart + Source.size(),
|
||||
&targetStart, targetStart + Source.size(), flags);
|
||||
if (result == conversionOK)
|
||||
ResultPtr = reinterpret_cast<char*>(targetStart);
|
||||
else
|
||||
ErrorPtr = sourceStart;
|
||||
}
|
||||
assert((result != targetExhausted)
|
||||
&& "ConvertUTF8toUTFXX exhausted target buffer");
|
||||
return result == conversionOK;
|
||||
}
|
||||
|
||||
bool ConvertCodePointToUTF8(unsigned Source, char *&ResultPtr) {
|
||||
const UTF32 *SourceStart = &Source;
|
||||
const UTF32 *SourceEnd = SourceStart + 1;
|
||||
@@ -35,23 +84,28 @@ bool hasUTF16ByteOrderMark(span<const char> S) {
|
||||
(S[0] == '\xfe' && S[1] == '\xff')));
|
||||
}
|
||||
|
||||
bool convertUTF16ToUTF8String(span<const UTF16> SrcUTF16,
|
||||
SmallVectorImpl<char> &DstUTF8) {
|
||||
assert(DstUTF8.empty());
|
||||
bool convertUTF16ToUTF8String(span<const char> SrcBytes, SmallVectorImpl<char> &Out) {
|
||||
assert(Out.empty());
|
||||
|
||||
// Error out on an uneven byte count.
|
||||
if (SrcBytes.size() % 2)
|
||||
return false;
|
||||
|
||||
// Avoid OOB by returning early on empty input.
|
||||
if (SrcUTF16.empty())
|
||||
if (SrcBytes.empty())
|
||||
return true;
|
||||
|
||||
const UTF16 *Src = SrcUTF16.begin();
|
||||
const UTF16 *SrcEnd = SrcUTF16.end();
|
||||
const UTF16 *Src = reinterpret_cast<const UTF16 *>(SrcBytes.begin());
|
||||
const UTF16 *SrcEnd = reinterpret_cast<const UTF16 *>(SrcBytes.end());
|
||||
|
||||
assert((uintptr_t)Src % sizeof(UTF16) == 0);
|
||||
|
||||
// Byteswap if necessary.
|
||||
std::vector<UTF16> ByteSwapped;
|
||||
if (Src[0] == UNI_UTF16_BYTE_ORDER_MARK_SWAPPED) {
|
||||
ByteSwapped.insert(ByteSwapped.end(), Src, SrcEnd);
|
||||
for (unsigned I = 0, E = ByteSwapped.size(); I != E; ++I)
|
||||
ByteSwapped[I] = (ByteSwapped[I] << 8) | (ByteSwapped[I] >> 8);
|
||||
ByteSwapped[I] = wpi::ByteSwap_16(ByteSwapped[I]);
|
||||
Src = &ByteSwapped[0];
|
||||
SrcEnd = &ByteSwapped[ByteSwapped.size() - 1] + 1;
|
||||
}
|
||||
@@ -62,25 +116,32 @@ bool convertUTF16ToUTF8String(span<const UTF16> SrcUTF16,
|
||||
|
||||
// Just allocate enough space up front. We'll shrink it later. Allocate
|
||||
// enough that we can fit a null terminator without reallocating.
|
||||
DstUTF8.resize(SrcUTF16.size() * UNI_MAX_UTF8_BYTES_PER_CODE_POINT + 1);
|
||||
UTF8 *Dst = reinterpret_cast<UTF8*>(&DstUTF8[0]);
|
||||
UTF8 *DstEnd = Dst + DstUTF8.size();
|
||||
Out.resize(SrcBytes.size() * UNI_MAX_UTF8_BYTES_PER_CODE_POINT + 1);
|
||||
UTF8 *Dst = reinterpret_cast<UTF8 *>(&Out[0]);
|
||||
UTF8 *DstEnd = Dst + Out.size();
|
||||
|
||||
ConversionResult CR =
|
||||
ConvertUTF16toUTF8(&Src, SrcEnd, &Dst, DstEnd, strictConversion);
|
||||
assert(CR != targetExhausted);
|
||||
|
||||
if (CR != conversionOK) {
|
||||
DstUTF8.clear();
|
||||
Out.clear();
|
||||
return false;
|
||||
}
|
||||
|
||||
DstUTF8.resize(reinterpret_cast<char*>(Dst) - &DstUTF8[0]);
|
||||
DstUTF8.push_back(0);
|
||||
DstUTF8.pop_back();
|
||||
Out.resize(reinterpret_cast<char *>(Dst) - &Out[0]);
|
||||
Out.push_back(0);
|
||||
Out.pop_back();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool convertUTF16ToUTF8String(span<const UTF16> Src, SmallVectorImpl<char> &Out)
|
||||
{
|
||||
return convertUTF16ToUTF8String(
|
||||
span<const char>(reinterpret_cast<const char *>(Src.data()),
|
||||
Src.size() * sizeof(UTF16)), Out);
|
||||
}
|
||||
|
||||
bool convertUTF8ToUTF16String(std::string_view SrcUTF8,
|
||||
SmallVectorImpl<UTF16> &DstUTF16) {
|
||||
assert(DstUTF16.empty());
|
||||
@@ -119,5 +180,74 @@ bool convertUTF8ToUTF16String(std::string_view SrcUTF8,
|
||||
return true;
|
||||
}
|
||||
|
||||
static_assert(sizeof(wchar_t) == 1 || sizeof(wchar_t) == 2 ||
|
||||
sizeof(wchar_t) == 4,
|
||||
"Expected wchar_t to be 1, 2, or 4 bytes");
|
||||
|
||||
template <typename TResult>
|
||||
static inline bool ConvertUTF8toWideInternal(std::string_view Source,
|
||||
TResult &Result) {
|
||||
// Even in the case of UTF-16, the number of bytes in a UTF-8 string is
|
||||
// at least as large as the number of elements in the resulting wide
|
||||
// string, because surrogate pairs take at least 4 bytes in UTF-8.
|
||||
Result.resize(Source.size() + 1);
|
||||
char *ResultPtr = reinterpret_cast<char *>(&Result[0]);
|
||||
const UTF8 *ErrorPtr;
|
||||
if (!ConvertUTF8toWide(sizeof(wchar_t), Source, ResultPtr, ErrorPtr)) {
|
||||
Result.clear();
|
||||
return false;
|
||||
}
|
||||
Result.resize(reinterpret_cast<wchar_t *>(ResultPtr) - &Result[0]);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ConvertUTF8toWide(std::string_view Source, std::wstring &Result) {
|
||||
return ConvertUTF8toWideInternal(Source, Result);
|
||||
}
|
||||
|
||||
bool ConvertUTF8toWide(const char *Source, std::wstring &Result) {
|
||||
if (!Source) {
|
||||
Result.clear();
|
||||
return true;
|
||||
}
|
||||
return ConvertUTF8toWide(std::string_view(Source), Result);
|
||||
}
|
||||
|
||||
bool convertWideToUTF8(const std::wstring &Source, SmallVectorImpl<char> &Result) {
|
||||
if (sizeof(wchar_t) == 1) {
|
||||
const UTF8 *Start = reinterpret_cast<const UTF8 *>(Source.data());
|
||||
const UTF8 *End =
|
||||
reinterpret_cast<const UTF8 *>(Source.data() + Source.size());
|
||||
if (!isLegalUTF8String(&Start, End))
|
||||
return false;
|
||||
Result.resize(Source.size());
|
||||
memcpy(&Result[0], Source.data(), Source.size());
|
||||
return true;
|
||||
} else if (sizeof(wchar_t) == 2) {
|
||||
return convertUTF16ToUTF8String(
|
||||
span<const UTF16>(reinterpret_cast<const UTF16 *>(Source.data()),
|
||||
Source.size()),
|
||||
Result);
|
||||
} else if (sizeof(wchar_t) == 4) {
|
||||
const UTF32 *Start = reinterpret_cast<const UTF32 *>(Source.data());
|
||||
const UTF32 *End =
|
||||
reinterpret_cast<const UTF32 *>(Source.data() + Source.size());
|
||||
Result.resize(UNI_MAX_UTF8_BYTES_PER_CODE_POINT * Source.size());
|
||||
UTF8 *ResultPtr = reinterpret_cast<UTF8 *>(&Result[0]);
|
||||
UTF8 *ResultEnd = reinterpret_cast<UTF8 *>(&Result[0] + Result.size());
|
||||
if (ConvertUTF32toUTF8(&Start, End, &ResultPtr, ResultEnd,
|
||||
strictConversion) == conversionOK) {
|
||||
Result.resize(reinterpret_cast<char *>(ResultPtr) - &Result[0]);
|
||||
return true;
|
||||
} else {
|
||||
Result.clear();
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
wpi_unreachable(
|
||||
"Control should never reach this point; see static_assert further up");
|
||||
}
|
||||
}
|
||||
|
||||
} // end namespace wpi
|
||||
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
//===- lib/Support/ErrorHandling.cpp - Callbacks for errors ---------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
@@ -14,10 +13,10 @@
|
||||
|
||||
#include "wpi/ErrorHandling.h"
|
||||
#include "wpi/SmallVector.h"
|
||||
#include "wpi/Errc.h"
|
||||
#include "wpi/WindowsError.h"
|
||||
#include "fmt/format.h"
|
||||
#include <cassert>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <mutex>
|
||||
#include <new>
|
||||
@@ -25,7 +24,6 @@
|
||||
#ifndef _WIN32
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#include <io.h>
|
||||
#endif
|
||||
@@ -53,7 +51,7 @@ static std::mutex ErrorHandlerMutex;
|
||||
static std::mutex BadAllocErrorHandlerMutex;
|
||||
|
||||
void wpi::install_fatal_error_handler(fatal_error_handler_t handler,
|
||||
void *user_data) {
|
||||
void *user_data) {
|
||||
std::scoped_lock Lock(ErrorHandlerMutex);
|
||||
assert(!ErrorHandler && "Error handler already registered!\n");
|
||||
ErrorHandler = handler;
|
||||
@@ -95,7 +93,7 @@ void wpi::report_fatal_error(std::string_view Reason, bool GenCrashDiag) {
|
||||
}
|
||||
|
||||
void wpi::install_bad_alloc_error_handler(fatal_error_handler_t handler,
|
||||
void *user_data) {
|
||||
void *user_data) {
|
||||
std::scoped_lock Lock(BadAllocErrorHandlerMutex);
|
||||
assert(!ErrorHandler && "Bad alloc error handler already registered!\n");
|
||||
BadAllocErrorHandler = handler;
|
||||
@@ -126,13 +124,17 @@ void wpi::report_bad_alloc_error(const char *Reason, bool GenCrashDiag) {
|
||||
|
||||
// Don't call the normal error handler. It may allocate memory. Directly write
|
||||
// an OOM to stderr and abort.
|
||||
char OOMMessage[] = "LLVM ERROR: out of memory\n";
|
||||
const char *OOMMessage = "LLVM ERROR: out of memory\n";
|
||||
const char *Newline = "\n";
|
||||
#ifdef _WIN32
|
||||
int written = ::_write(2, OOMMessage, strlen(OOMMessage));
|
||||
(void)!::_write(2, OOMMessage, strlen(OOMMessage));
|
||||
(void)!::_write(2, Reason, strlen(Reason));
|
||||
(void)!::_write(2, Newline, strlen(Newline));
|
||||
#else
|
||||
ssize_t written = ::write(2, OOMMessage, strlen(OOMMessage));
|
||||
(void)!::write(2, OOMMessage, strlen(OOMMessage));
|
||||
(void)!::write(2, Reason, strlen(Reason));
|
||||
(void)!::write(2, Newline, strlen(Newline));
|
||||
#endif
|
||||
(void)written;
|
||||
abort();
|
||||
}
|
||||
|
||||
@@ -142,28 +144,17 @@ static void out_of_memory_new_handler() {
|
||||
wpi::report_bad_alloc_error("Allocation failed");
|
||||
}
|
||||
|
||||
// Installs new handler that causes crash on allocation failure. It does not
|
||||
// need to be called explicitly, if this file is linked to application, because
|
||||
// in this case it is called during construction of 'new_handler_installer'.
|
||||
// Installs new handler that causes crash on allocation failure. It is called by
|
||||
// InitLLVM.
|
||||
void wpi::install_out_of_memory_new_handler() {
|
||||
static bool out_of_memory_new_handler_installed = false;
|
||||
if (!out_of_memory_new_handler_installed) {
|
||||
std::set_new_handler(out_of_memory_new_handler);
|
||||
out_of_memory_new_handler_installed = true;
|
||||
}
|
||||
std::new_handler old = std::set_new_handler(out_of_memory_new_handler);
|
||||
(void)old;
|
||||
assert((old == nullptr || old == out_of_memory_new_handler) &&
|
||||
"new-handler already installed");
|
||||
}
|
||||
|
||||
// Static object that causes installation of 'out_of_memory_new_handler' before
|
||||
// execution of 'main'.
|
||||
static class NewHandlerInstaller {
|
||||
public:
|
||||
NewHandlerInstaller() {
|
||||
install_out_of_memory_new_handler();
|
||||
}
|
||||
} new_handler_installer;
|
||||
|
||||
void wpi::wpi_unreachable_internal(const char *msg, const char *file,
|
||||
unsigned line) {
|
||||
unsigned line) {
|
||||
// This code intentionally doesn't call the ErrorHandler callback, because
|
||||
// wpi_unreachable is intended to be used to indicate "impossible"
|
||||
// situations, and not legitimate runtime errors.
|
||||
@@ -183,7 +174,6 @@ void wpi::wpi_unreachable_internal(const char *msg, const char *file,
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#include <system_error>
|
||||
#include <winerror.h>
|
||||
|
||||
// I'd rather not double the line count of the following.
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
//===-------------- lib/Support/Hashing.cpp -------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
//===-- ManagedStatic.cpp - Static Global wrapper -------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
@@ -18,43 +17,32 @@
|
||||
using namespace wpi;
|
||||
|
||||
static const ManagedStaticBase *StaticList = nullptr;
|
||||
static wpi::mutex *ManagedStaticMutex = nullptr;
|
||||
static std::once_flag mutex_init_flag;
|
||||
|
||||
static void initializeMutex() {
|
||||
ManagedStaticMutex = new wpi::mutex();
|
||||
}
|
||||
|
||||
static wpi::mutex* getManagedStaticMutex() {
|
||||
std::call_once(mutex_init_flag, initializeMutex);
|
||||
return ManagedStaticMutex;
|
||||
}
|
||||
|
||||
void ManagedStaticBase::RegisterManagedStatic(void* created,
|
||||
void (*Deleter)(void*)) const {
|
||||
std::scoped_lock Lock(*getManagedStaticMutex());
|
||||
|
||||
if (!Ptr.load(std::memory_order_relaxed)) {
|
||||
void *Tmp = created;
|
||||
|
||||
Ptr.store(Tmp, std::memory_order_release);
|
||||
DeleterFn = Deleter;
|
||||
|
||||
// Add to list of managed statics.
|
||||
Next = StaticList;
|
||||
StaticList = this;
|
||||
}
|
||||
static wpi::mutex *getManagedStaticMutex() {
|
||||
static wpi::mutex m;
|
||||
return &m;
|
||||
}
|
||||
|
||||
void ManagedStaticBase::RegisterManagedStatic(void *(*Creator)(),
|
||||
void (*Deleter)(void*)) const {
|
||||
assert(Creator);
|
||||
std::scoped_lock Lock(*getManagedStaticMutex());
|
||||
if (1) {
|
||||
std::scoped_lock Lock(*getManagedStaticMutex());
|
||||
|
||||
if (!Ptr.load(std::memory_order_relaxed)) {
|
||||
void *Tmp = Creator();
|
||||
if (!Ptr.load(std::memory_order_relaxed)) {
|
||||
void *Tmp = Creator();
|
||||
|
||||
Ptr.store(Tmp, std::memory_order_release);
|
||||
Ptr.store(Tmp, std::memory_order_release);
|
||||
DeleterFn = Deleter;
|
||||
|
||||
// Add to list of managed statics.
|
||||
Next = StaticList;
|
||||
StaticList = this;
|
||||
}
|
||||
} else {
|
||||
assert(!Ptr && !DeleterFn && !Next &&
|
||||
"Partially initialized ManagedStatic!?");
|
||||
Ptr = Creator();
|
||||
DeleterFn = Deleter;
|
||||
|
||||
// Add to list of managed statics.
|
||||
@@ -80,9 +68,10 @@ void ManagedStaticBase::destroy() const {
|
||||
}
|
||||
|
||||
/// wpi_shutdown - Deallocate and destroy all ManagedStatic variables.
|
||||
/// IMPORTANT: it's only safe to call wpi_shutdown() in single thread,
|
||||
/// without any other threads executing LLVM APIs.
|
||||
/// wpi_shutdown() should be the last use of LLVM APIs.
|
||||
void wpi::wpi_shutdown() {
|
||||
std::scoped_lock Lock(*getManagedStaticMutex());
|
||||
|
||||
while (StaticList)
|
||||
StaticList->destroy();
|
||||
}
|
||||
|
||||
34
wpiutil/src/main/native/cpp/llvm/MemAlloc.cpp
Normal file
34
wpiutil/src/main/native/cpp/llvm/MemAlloc.cpp
Normal file
@@ -0,0 +1,34 @@
|
||||
//===- MemAlloc.cpp - Memory allocation functions -------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "wpi/MemAlloc.h"
|
||||
|
||||
// These are out of line to have __cpp_aligned_new not affect ABI.
|
||||
|
||||
LLVM_ATTRIBUTE_RETURNS_NONNULL LLVM_ATTRIBUTE_RETURNS_NOALIAS void *
|
||||
wpi::allocate_buffer(size_t Size, size_t Alignment) {
|
||||
return ::operator new(Size
|
||||
#ifdef __cpp_aligned_new
|
||||
,
|
||||
std::align_val_t(Alignment)
|
||||
#endif
|
||||
);
|
||||
}
|
||||
|
||||
void wpi::deallocate_buffer(void *Ptr, size_t Size, size_t Alignment) {
|
||||
::operator delete(Ptr
|
||||
#ifdef __cpp_sized_deallocation
|
||||
,
|
||||
Size
|
||||
#endif
|
||||
#ifdef __cpp_aligned_new
|
||||
,
|
||||
std::align_val_t(Alignment)
|
||||
#endif
|
||||
);
|
||||
}
|
||||
@@ -1,9 +1,8 @@
|
||||
//===- llvm/ADT/SmallPtrSet.cpp - 'Normally small' pointer set ------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
@@ -14,9 +13,9 @@
|
||||
|
||||
#include "wpi/SmallPtrSet.h"
|
||||
#include "wpi/DenseMapInfo.h"
|
||||
#include "wpi/ErrorHandling.h"
|
||||
#include "wpi/MathExtras.h"
|
||||
#include "wpi/MemAlloc.h"
|
||||
#include "wpi/ErrorHandling.h"
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstdlib>
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
//===- llvm/ADT/SmallVector.cpp - 'Normally small' vectors ----------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
@@ -12,21 +11,99 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "wpi/SmallVector.h"
|
||||
#include "wpi/MemAlloc.h"
|
||||
#include <cstdint>
|
||||
#ifdef LLVM_ENABLE_EXCEPTIONS
|
||||
#include <stdexcept>
|
||||
#endif
|
||||
using namespace wpi;
|
||||
|
||||
/// grow_pod - This is an implementation of the grow() method which only works
|
||||
/// on POD-like datatypes and is out of line to reduce code duplication.
|
||||
void SmallVectorBase::grow_pod(void *FirstEl, size_t MinCapacity,
|
||||
size_t TSize) {
|
||||
// Ensure we can fit the new capacity in 32 bits.
|
||||
if (MinCapacity > UINT32_MAX)
|
||||
report_bad_alloc_error("SmallVector capacity overflow during allocation");
|
||||
// Check that no bytes are wasted and everything is well-aligned.
|
||||
namespace {
|
||||
struct Struct16B {
|
||||
alignas(16) void *X;
|
||||
};
|
||||
struct Struct32B {
|
||||
alignas(32) void *X;
|
||||
};
|
||||
}
|
||||
static_assert(sizeof(SmallVector<void *, 0>) ==
|
||||
sizeof(unsigned) * 2 + sizeof(void *),
|
||||
"wasted space in SmallVector size 0");
|
||||
static_assert(alignof(SmallVector<Struct16B, 0>) >= alignof(Struct16B),
|
||||
"wrong alignment for 16-byte aligned T");
|
||||
static_assert(alignof(SmallVector<Struct32B, 0>) >= alignof(Struct32B),
|
||||
"wrong alignment for 32-byte aligned T");
|
||||
static_assert(sizeof(SmallVector<Struct16B, 0>) >= alignof(Struct16B),
|
||||
"missing padding for 16-byte aligned T");
|
||||
static_assert(sizeof(SmallVector<Struct32B, 0>) >= alignof(Struct32B),
|
||||
"missing padding for 32-byte aligned T");
|
||||
static_assert(sizeof(SmallVector<void *, 1>) ==
|
||||
sizeof(unsigned) * 2 + sizeof(void *) * 2,
|
||||
"wasted space in SmallVector size 1");
|
||||
|
||||
size_t NewCapacity = 2 * capacity() + 1; // Always grow.
|
||||
NewCapacity =
|
||||
std::min(std::max(NewCapacity, MinCapacity), size_t(UINT32_MAX));
|
||||
/// Report that MinSize doesn't fit into this vector's size type. Throws
|
||||
/// std::length_error or calls report_fatal_error.
|
||||
LLVM_ATTRIBUTE_NORETURN
|
||||
static void report_size_overflow(size_t MinSize, size_t MaxSize);
|
||||
static void report_size_overflow(size_t MinSize, size_t MaxSize) {
|
||||
std::string Reason = "SmallVector unable to grow. Requested capacity (" +
|
||||
std::to_string(MinSize) +
|
||||
") is larger than maximum value for size type (" +
|
||||
std::to_string(MaxSize) + ")";
|
||||
#ifdef LLVM_ENABLE_EXCEPTIONS
|
||||
throw std::length_error(Reason);
|
||||
#else
|
||||
report_fatal_error(Reason);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Report that this vector is already at maximum capacity. Throws
|
||||
/// std::length_error or calls report_fatal_error.
|
||||
LLVM_ATTRIBUTE_NORETURN static void report_at_maximum_capacity(size_t MaxSize);
|
||||
static void report_at_maximum_capacity(size_t MaxSize) {
|
||||
std::string Reason =
|
||||
"SmallVector capacity unable to grow. Already at maximum size " +
|
||||
std::to_string(MaxSize);
|
||||
#ifdef LLVM_ENABLE_EXCEPTIONS
|
||||
throw std::length_error(Reason);
|
||||
#else
|
||||
report_fatal_error(Reason);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Note: Moving this function into the header may cause performance regression.
|
||||
static size_t getNewCapacity(size_t MinSize, size_t TSize, size_t OldCapacity) {
|
||||
constexpr size_t MaxSize = std::numeric_limits<unsigned>::max();
|
||||
|
||||
// Ensure we can fit the new capacity.
|
||||
// This is only going to be applicable when the capacity is 32 bit.
|
||||
if (MinSize > MaxSize)
|
||||
report_size_overflow(MinSize, MaxSize);
|
||||
|
||||
// Ensure we can meet the guarantee of space for at least one more element.
|
||||
// The above check alone will not catch the case where grow is called with a
|
||||
// default MinSize of 0, but the current capacity cannot be increased.
|
||||
// This is only going to be applicable when the capacity is 32 bit.
|
||||
if (OldCapacity == MaxSize)
|
||||
report_at_maximum_capacity(MaxSize);
|
||||
|
||||
// In theory 2*capacity can overflow if the capacity is 64 bit, but the
|
||||
// original capacity would never be large enough for this to be a problem.
|
||||
size_t NewCapacity = 2 * OldCapacity + 1; // Always grow.
|
||||
return (std::min)((std::max)(NewCapacity, MinSize), MaxSize);
|
||||
}
|
||||
|
||||
// Note: Moving this function into the header may cause performance regression.
|
||||
void *SmallVectorBase::mallocForGrow(size_t MinSize, size_t TSize,
|
||||
size_t &NewCapacity) {
|
||||
NewCapacity = getNewCapacity(MinSize, TSize, this->capacity());
|
||||
return wpi::safe_malloc(NewCapacity * TSize);
|
||||
}
|
||||
|
||||
// Note: Moving this function into the header may cause performance regression.
|
||||
void SmallVectorBase::grow_pod(void *FirstEl, size_t MinSize,
|
||||
size_t TSize) {
|
||||
size_t NewCapacity = getNewCapacity(MinSize, TSize, this->capacity());
|
||||
void *NewElts;
|
||||
if (BeginX == FirstEl) {
|
||||
NewElts = safe_malloc(NewCapacity * TSize);
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
//===--- StringMap.cpp - String Hash table map implementation -------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
@@ -15,7 +14,6 @@
|
||||
#include "wpi/StringExtras.h"
|
||||
#include "wpi/Compiler.h"
|
||||
#include "wpi/MathExtras.h"
|
||||
#include <cassert>
|
||||
|
||||
using namespace wpi;
|
||||
|
||||
@@ -65,23 +63,22 @@ StringMapImpl::StringMapImpl(unsigned InitSize, unsigned itemSize) {
|
||||
}
|
||||
|
||||
void StringMapImpl::init(unsigned InitSize) {
|
||||
assert((InitSize & (InitSize-1)) == 0 &&
|
||||
assert((InitSize & (InitSize - 1)) == 0 &&
|
||||
"Init Size must be a power of 2 or zero!");
|
||||
|
||||
unsigned NewNumBuckets = InitSize ? InitSize : 16;
|
||||
NumItems = 0;
|
||||
NumTombstones = 0;
|
||||
|
||||
TheTable = static_cast<StringMapEntryBase **>(
|
||||
safe_calloc(NewNumBuckets+1,
|
||||
sizeof(StringMapEntryBase **) + sizeof(unsigned)));
|
||||
TheTable = static_cast<StringMapEntryBase **>(safe_calloc(
|
||||
NewNumBuckets + 1, sizeof(StringMapEntryBase **) + sizeof(unsigned)));
|
||||
|
||||
// Set the member only if TheTable was successfully allocated
|
||||
NumBuckets = NewNumBuckets;
|
||||
|
||||
// Allocate one extra bucket, set it to look filled so the iterators stop at
|
||||
// end.
|
||||
TheTable[NumBuckets] = (StringMapEntryBase*)2;
|
||||
TheTable[NumBuckets] = (StringMapEntryBase *)2;
|
||||
}
|
||||
|
||||
/// LookupBucketFor - Look up the bucket that the specified string should end
|
||||
@@ -91,12 +88,12 @@ void StringMapImpl::init(unsigned InitSize) {
|
||||
/// of the string.
|
||||
unsigned StringMapImpl::LookupBucketFor(std::string_view Name) {
|
||||
unsigned HTSize = NumBuckets;
|
||||
if (HTSize == 0) { // Hash table unallocated so far?
|
||||
if (HTSize == 0) { // Hash table unallocated so far?
|
||||
init(16);
|
||||
HTSize = NumBuckets;
|
||||
}
|
||||
unsigned FullHashValue = HashString(Name);
|
||||
unsigned BucketNo = FullHashValue & (HTSize-1);
|
||||
unsigned BucketNo = FullHashValue & (HTSize - 1);
|
||||
unsigned *HashTable = (unsigned *)(TheTable + NumBuckets + 1);
|
||||
|
||||
unsigned ProbeAmt = 1;
|
||||
@@ -118,7 +115,8 @@ unsigned StringMapImpl::LookupBucketFor(std::string_view Name) {
|
||||
|
||||
if (BucketItem == getTombstoneVal()) {
|
||||
// Skip over tombstones. However, remember the first one we see.
|
||||
if (FirstTombstone == -1) FirstTombstone = BucketNo;
|
||||
if (FirstTombstone == -1)
|
||||
FirstTombstone = BucketNo;
|
||||
} else if (LLVM_LIKELY(HashTable[BucketNo] == FullHashValue)) {
|
||||
// If the full hash value matches, check deeply for a match. The common
|
||||
// case here is that we are only looking at the buckets (for item info
|
||||
@@ -127,7 +125,7 @@ unsigned StringMapImpl::LookupBucketFor(std::string_view Name) {
|
||||
|
||||
// Do the comparison like this because Name isn't necessarily
|
||||
// null-terminated!
|
||||
char *ItemStr = (char*)BucketItem+ItemSize;
|
||||
char *ItemStr = (char *)BucketItem + ItemSize;
|
||||
if (Name == std::string_view(ItemStr, BucketItem->getKeyLength())) {
|
||||
// We found a match!
|
||||
return BucketNo;
|
||||
@@ -135,7 +133,7 @@ unsigned StringMapImpl::LookupBucketFor(std::string_view Name) {
|
||||
}
|
||||
|
||||
// Okay, we didn't find the item. Probe to the next bucket.
|
||||
BucketNo = (BucketNo+ProbeAmt) & (HTSize-1);
|
||||
BucketNo = (BucketNo + ProbeAmt) & (HTSize - 1);
|
||||
|
||||
// Use quadratic probing, it has fewer clumping artifacts than linear
|
||||
// probing and has good cache behavior in the common case.
|
||||
@@ -148,9 +146,10 @@ unsigned StringMapImpl::LookupBucketFor(std::string_view Name) {
|
||||
/// This does not modify the map.
|
||||
int StringMapImpl::FindKey(std::string_view Key) const {
|
||||
unsigned HTSize = NumBuckets;
|
||||
if (HTSize == 0) return -1; // Really empty table?
|
||||
if (HTSize == 0)
|
||||
return -1; // Really empty table?
|
||||
unsigned FullHashValue = HashString(Key);
|
||||
unsigned BucketNo = FullHashValue & (HTSize-1);
|
||||
unsigned BucketNo = FullHashValue & (HTSize - 1);
|
||||
unsigned *HashTable = (unsigned *)(TheTable + NumBuckets + 1);
|
||||
|
||||
unsigned ProbeAmt = 1;
|
||||
@@ -170,7 +169,7 @@ int StringMapImpl::FindKey(std::string_view Key) const {
|
||||
|
||||
// Do the comparison like this because NameStart isn't necessarily
|
||||
// null-terminated!
|
||||
char *ItemStr = (char*)BucketItem+ItemSize;
|
||||
char *ItemStr = (char *)BucketItem + ItemSize;
|
||||
if (Key == std::string_view(ItemStr, BucketItem->getKeyLength())) {
|
||||
// We found a match!
|
||||
return BucketNo;
|
||||
@@ -178,7 +177,7 @@ int StringMapImpl::FindKey(std::string_view Key) const {
|
||||
}
|
||||
|
||||
// Okay, we didn't find the item. Probe to the next bucket.
|
||||
BucketNo = (BucketNo+ProbeAmt) & (HTSize-1);
|
||||
BucketNo = (BucketNo + ProbeAmt) & (HTSize - 1);
|
||||
|
||||
// Use quadratic probing, it has fewer clumping artifacts than linear
|
||||
// probing and has good cache behavior in the common case.
|
||||
@@ -189,7 +188,7 @@ int StringMapImpl::FindKey(std::string_view Key) const {
|
||||
/// RemoveKey - Remove the specified StringMapEntry from the table, but do not
|
||||
/// delete it. This aborts if the value isn't in the table.
|
||||
void StringMapImpl::RemoveKey(StringMapEntryBase *V) {
|
||||
const char *VStr = (char*)V + ItemSize;
|
||||
const char *VStr = (char *)V + ItemSize;
|
||||
StringMapEntryBase *V2 = RemoveKey(std::string_view(VStr, V->getKeyLength()));
|
||||
(void)V2;
|
||||
assert(V == V2 && "Didn't find key?");
|
||||
@@ -199,7 +198,8 @@ void StringMapImpl::RemoveKey(StringMapEntryBase *V) {
|
||||
/// table, returning it. If the key is not in the table, this returns null.
|
||||
StringMapEntryBase *StringMapImpl::RemoveKey(std::string_view Key) {
|
||||
int Bucket = FindKey(Key);
|
||||
if (Bucket == -1) return nullptr;
|
||||
if (Bucket == -1)
|
||||
return nullptr;
|
||||
|
||||
StringMapEntryBase *Result = TheTable[Bucket];
|
||||
TheTable[Bucket] = getTombstoneVal();
|
||||
@@ -220,7 +220,7 @@ unsigned StringMapImpl::RehashTable(unsigned BucketNo) {
|
||||
// the buckets are empty (meaning that many are filled with tombstones),
|
||||
// grow/rehash the table.
|
||||
if (LLVM_UNLIKELY(NumItems * 4 > NumBuckets * 3)) {
|
||||
NewSize = NumBuckets*2;
|
||||
NewSize = NumBuckets * 2;
|
||||
} else if (LLVM_UNLIKELY(NumBuckets - (NumItems + NumTombstones) <=
|
||||
NumBuckets / 8)) {
|
||||
NewSize = NumBuckets;
|
||||
@@ -231,11 +231,11 @@ unsigned StringMapImpl::RehashTable(unsigned BucketNo) {
|
||||
unsigned NewBucketNo = BucketNo;
|
||||
// Allocate one extra bucket which will always be non-empty. This allows the
|
||||
// iterators to stop at end.
|
||||
auto NewTableArray = static_cast<StringMapEntryBase **>(
|
||||
safe_calloc(NewSize+1, sizeof(StringMapEntryBase *) + sizeof(unsigned)));
|
||||
auto NewTableArray = static_cast<StringMapEntryBase **>(safe_calloc(
|
||||
NewSize + 1, sizeof(StringMapEntryBase *) + sizeof(unsigned)));
|
||||
|
||||
unsigned *NewHashArray = (unsigned *)(NewTableArray + NewSize + 1);
|
||||
NewTableArray[NewSize] = (StringMapEntryBase*)2;
|
||||
NewTableArray[NewSize] = (StringMapEntryBase *)2;
|
||||
|
||||
// Rehash all the items into their new buckets. Luckily :) we already have
|
||||
// the hash values available, so we don't have to rehash any strings.
|
||||
@@ -244,10 +244,10 @@ unsigned StringMapImpl::RehashTable(unsigned BucketNo) {
|
||||
if (Bucket && Bucket != getTombstoneVal()) {
|
||||
// Fast case, bucket available.
|
||||
unsigned FullHash = HashTable[I];
|
||||
unsigned NewBucket = FullHash & (NewSize-1);
|
||||
unsigned NewBucket = FullHash & (NewSize - 1);
|
||||
if (!NewTableArray[NewBucket]) {
|
||||
NewTableArray[FullHash & (NewSize-1)] = Bucket;
|
||||
NewHashArray[FullHash & (NewSize-1)] = FullHash;
|
||||
NewTableArray[FullHash & (NewSize - 1)] = Bucket;
|
||||
NewHashArray[FullHash & (NewSize - 1)] = FullHash;
|
||||
if (I == BucketNo)
|
||||
NewBucketNo = NewBucket;
|
||||
continue;
|
||||
@@ -256,7 +256,7 @@ unsigned StringMapImpl::RehashTable(unsigned BucketNo) {
|
||||
// Otherwise probe for a spot.
|
||||
unsigned ProbeSize = 1;
|
||||
do {
|
||||
NewBucket = (NewBucket + ProbeSize++) & (NewSize-1);
|
||||
NewBucket = (NewBucket + ProbeSize++) & (NewSize - 1);
|
||||
} while (NewTableArray[NewBucket]);
|
||||
|
||||
// Finally found a slot. Fill it in.
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
//===- WindowsSupport.h - Common Windows Include File -----------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
@@ -19,8 +18,8 @@
|
||||
//=== is guaranteed to work on *all* Win32 variants.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_SUPPORT_WINDOWSSUPPORT_H
|
||||
#define LLVM_SUPPORT_WINDOWSSUPPORT_H
|
||||
#ifndef WPIUTIL_WPI_WINDOWSSUPPORT_H
|
||||
#define WPIUTIL_WPI_WINDOWSSUPPORT_H
|
||||
|
||||
// mingw-w64 tends to define it as 0x0502 in its headers.
|
||||
#undef _WIN32_WINNT
|
||||
@@ -38,10 +37,10 @@
|
||||
#include "wpi/StringExtras.h"
|
||||
#include "wpi/Chrono.h"
|
||||
#include "wpi/Compiler.h"
|
||||
#include "wpi/ErrorHandling.h"
|
||||
#include "wpi/VersionTuple.h"
|
||||
#include <cassert>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <system_error>
|
||||
#define WIN32_NO_STATUS
|
||||
#include <windows.h>
|
||||
@@ -49,6 +48,9 @@
|
||||
#include <winternl.h>
|
||||
#include <ntstatus.h>
|
||||
|
||||
// Must be included after windows.h
|
||||
#include <wincrypt.h>
|
||||
|
||||
namespace wpi {
|
||||
|
||||
/// Returns the Windows version as Major.Minor.0.BuildNumber. Uses
|
||||
@@ -81,23 +83,19 @@ inline bool RunningWindows8OrGreater() {
|
||||
return GetWindowsOSVersion() >= wpi::VersionTuple(6, 2, 0, 0);
|
||||
}
|
||||
|
||||
inline bool MakeErrMsg(std::string *ErrMsg, const std::string &prefix) {
|
||||
if (!ErrMsg)
|
||||
return true;
|
||||
char *buffer = NULL;
|
||||
DWORD LastError = GetLastError();
|
||||
DWORD R = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||||
FORMAT_MESSAGE_FROM_SYSTEM |
|
||||
FORMAT_MESSAGE_MAX_WIDTH_MASK,
|
||||
NULL, LastError, 0, (LPSTR)&buffer, 1, NULL);
|
||||
if (R)
|
||||
*ErrMsg = prefix + ": " + buffer;
|
||||
else
|
||||
*ErrMsg = prefix + ": Unknown error";
|
||||
*ErrMsg += " (0x" + wpi::utohexstr(LastError) + ")";
|
||||
/// Returns the Windows version as Major.Minor.0.BuildNumber. Uses
|
||||
/// RtlGetVersion or GetVersionEx under the hood depending on what is available.
|
||||
/// GetVersionEx is deprecated, but this API exposes the build number which can
|
||||
/// be useful for working around certain kernel bugs.
|
||||
wpi::VersionTuple GetWindowsOSVersion();
|
||||
|
||||
LocalFree(buffer);
|
||||
return R != 0;
|
||||
bool MakeErrMsg(std::string *ErrMsg, const std::string &prefix);
|
||||
|
||||
// Include GetLastError() in a fatal error message.
|
||||
LLVM_ATTRIBUTE_NORETURN inline void ReportLastErrorFatal(const char *Msg) {
|
||||
std::string ErrMsg;
|
||||
MakeErrMsg(&ErrMsg, Msg);
|
||||
wpi::report_fatal_error(ErrMsg);
|
||||
}
|
||||
|
||||
template <typename HandleTraits>
|
||||
@@ -164,6 +162,22 @@ struct JobHandleTraits : CommonHandleTraits {
|
||||
}
|
||||
};
|
||||
|
||||
struct CryptContextTraits : CommonHandleTraits {
|
||||
typedef HCRYPTPROV handle_type;
|
||||
|
||||
static handle_type GetInvalid() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void Close(handle_type h) {
|
||||
::CryptReleaseContext(h, 0);
|
||||
}
|
||||
|
||||
static bool IsValid(handle_type h) {
|
||||
return h != GetInvalid();
|
||||
}
|
||||
};
|
||||
|
||||
struct RegTraits : CommonHandleTraits {
|
||||
typedef HKEY handle_type;
|
||||
|
||||
@@ -190,6 +204,7 @@ struct FileHandleTraits : CommonHandleTraits {};
|
||||
|
||||
typedef ScopedHandle<CommonHandleTraits> ScopedCommonHandle;
|
||||
typedef ScopedHandle<FileHandleTraits> ScopedFileHandle;
|
||||
typedef ScopedHandle<CryptContextTraits> ScopedCryptContext;
|
||||
typedef ScopedHandle<RegTraits> ScopedRegHandle;
|
||||
typedef ScopedHandle<FindHandleTraits> ScopedFindHandle;
|
||||
typedef ScopedHandle<JobHandleTraits> ScopedJobHandle;
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
//===--- raw_os_ostream.cpp - Implement the raw_os_ostream class ----------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
//===--- raw_ostream.cpp - Implement the raw_ostream classes --------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
@@ -21,19 +20,17 @@
|
||||
#include "wpi/StringExtras.h"
|
||||
#include "wpi/Compiler.h"
|
||||
#include "wpi/ErrorHandling.h"
|
||||
#include "wpi/MathExtras.h"
|
||||
#include "wpi/WindowsError.h"
|
||||
#include "wpi/fs.h"
|
||||
#include "wpi/MathExtras.h"
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <cerrno>
|
||||
#include <cstdio>
|
||||
#include <iterator>
|
||||
#include <sys/stat.h>
|
||||
#include <system_error>
|
||||
|
||||
// <fcntl.h> may provide O_BINARY.
|
||||
#include <fcntl.h>
|
||||
# include <fcntl.h>
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <unistd.h>
|
||||
@@ -64,6 +61,17 @@
|
||||
|
||||
using namespace wpi;
|
||||
|
||||
constexpr raw_ostream::Colors raw_ostream::BLACK;
|
||||
constexpr raw_ostream::Colors raw_ostream::RED;
|
||||
constexpr raw_ostream::Colors raw_ostream::GREEN;
|
||||
constexpr raw_ostream::Colors raw_ostream::YELLOW;
|
||||
constexpr raw_ostream::Colors raw_ostream::BLUE;
|
||||
constexpr raw_ostream::Colors raw_ostream::MAGENTA;
|
||||
constexpr raw_ostream::Colors raw_ostream::CYAN;
|
||||
constexpr raw_ostream::Colors raw_ostream::WHITE;
|
||||
constexpr raw_ostream::Colors raw_ostream::SAVEDCOLOR;
|
||||
constexpr raw_ostream::Colors raw_ostream::RESET;
|
||||
|
||||
namespace {
|
||||
// Find the length of an array.
|
||||
template <class T, std::size_t N>
|
||||
@@ -78,13 +86,10 @@ raw_ostream::~raw_ostream() {
|
||||
assert(OutBufCur == OutBufStart &&
|
||||
"raw_ostream destructor called with non-empty buffer!");
|
||||
|
||||
if (BufferMode == InternalBuffer)
|
||||
if (BufferMode == BufferKind::InternalBuffer)
|
||||
delete [] OutBufStart;
|
||||
}
|
||||
|
||||
// An out of line virtual method to provide a home for the class vtable.
|
||||
void raw_ostream::handle() {}
|
||||
|
||||
size_t raw_ostream::preferred_buffer_size() const {
|
||||
// BUFSIZ is intended to be a reasonable default.
|
||||
return BUFSIZ;
|
||||
@@ -101,14 +106,14 @@ void raw_ostream::SetBuffered() {
|
||||
|
||||
void raw_ostream::SetBufferAndMode(char *BufferStart, size_t Size,
|
||||
BufferKind Mode) {
|
||||
assert(((Mode == Unbuffered && !BufferStart && Size == 0) ||
|
||||
(Mode != Unbuffered && BufferStart && Size != 0)) &&
|
||||
assert(((Mode == BufferKind::Unbuffered && !BufferStart && Size == 0) ||
|
||||
(Mode != BufferKind::Unbuffered && BufferStart && Size != 0)) &&
|
||||
"stream must be unbuffered or have at least one byte");
|
||||
// Make sure the current buffer is free of content (we can't flush here; the
|
||||
// child buffer management logic will be in write_impl).
|
||||
assert(GetNumBytesInBuffer() == 0 && "Current buffer is non-empty!");
|
||||
|
||||
if (BufferMode == InternalBuffer)
|
||||
if (BufferMode == BufferKind::InternalBuffer)
|
||||
delete [] OutBufStart;
|
||||
OutBufStart = BufferStart;
|
||||
OutBufEnd = OutBufStart+Size;
|
||||
@@ -162,15 +167,15 @@ void raw_ostream::flush_nonempty() {
|
||||
assert(OutBufCur > OutBufStart && "Invalid call to flush_nonempty.");
|
||||
size_t Length = OutBufCur - OutBufStart;
|
||||
OutBufCur = OutBufStart;
|
||||
write_impl(OutBufStart, Length);
|
||||
flush_tied_then_write(OutBufStart, Length);
|
||||
}
|
||||
|
||||
raw_ostream &raw_ostream::write(unsigned char C) {
|
||||
// Group exceptional cases into a single branch.
|
||||
if (LLVM_UNLIKELY(OutBufCur >= OutBufEnd)) {
|
||||
if (LLVM_UNLIKELY(!OutBufStart)) {
|
||||
if (BufferMode == Unbuffered) {
|
||||
write_impl(reinterpret_cast<char*>(&C), 1);
|
||||
if (BufferMode == BufferKind::Unbuffered) {
|
||||
flush_tied_then_write(reinterpret_cast<char *>(&C), 1);
|
||||
return *this;
|
||||
}
|
||||
// Set up a buffer and start over.
|
||||
@@ -189,8 +194,8 @@ raw_ostream &raw_ostream::write(const char *Ptr, size_t Size) {
|
||||
// Group exceptional cases into a single branch.
|
||||
if (LLVM_UNLIKELY(size_t(OutBufEnd - OutBufCur) < Size)) {
|
||||
if (LLVM_UNLIKELY(!OutBufStart)) {
|
||||
if (BufferMode == Unbuffered) {
|
||||
write_impl(Ptr, Size);
|
||||
if (BufferMode == BufferKind::Unbuffered) {
|
||||
flush_tied_then_write(Ptr, Size);
|
||||
return *this;
|
||||
}
|
||||
// Set up a buffer and start over.
|
||||
@@ -206,7 +211,7 @@ raw_ostream &raw_ostream::write(const char *Ptr, size_t Size) {
|
||||
if (LLVM_UNLIKELY(OutBufCur == OutBufStart)) {
|
||||
assert(NumBytes != 0 && "undefined behavior");
|
||||
size_t BytesToWrite = Size - (Size % NumBytes);
|
||||
write_impl(Ptr, BytesToWrite);
|
||||
flush_tied_then_write(Ptr, BytesToWrite);
|
||||
size_t BytesRemaining = Size - BytesToWrite;
|
||||
if (BytesRemaining > size_t(OutBufEnd - OutBufCur)) {
|
||||
// Too much left over to copy into our buffer.
|
||||
@@ -247,6 +252,13 @@ void raw_ostream::copy_to_buffer(const char *Ptr, size_t Size) {
|
||||
OutBufCur += Size;
|
||||
}
|
||||
|
||||
void raw_ostream::flush_tied_then_write(const char *Ptr, size_t Size) {
|
||||
if (TiedStream)
|
||||
TiedStream->flush();
|
||||
write_impl(Ptr, Size);
|
||||
}
|
||||
|
||||
|
||||
template <char C>
|
||||
static raw_ostream &write_padding(raw_ostream &OS, unsigned NumChars) {
|
||||
static const char Chars[] = {C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C,
|
||||
@@ -294,8 +306,7 @@ static int getFD(std::string_view Filename, std::error_code &EC,
|
||||
// the owner of stdout and may set the "binary" flag globally based on Flags.
|
||||
if (Filename == "-") {
|
||||
EC = std::error_code();
|
||||
// If user requested binary then put stdout into binary mode if
|
||||
// possible.
|
||||
// Change stdout's text/binary mode based on the Flags.
|
||||
if (!(Flags & fs::OF_Text)) {
|
||||
#if defined(_WIN32)
|
||||
_setmode(_fileno(stdout), _O_BINARY);
|
||||
@@ -305,11 +316,10 @@ static int getFD(std::string_view Filename, std::error_code &EC,
|
||||
}
|
||||
|
||||
fs::file_t F;
|
||||
if (Access & fs::FA_Read) {
|
||||
if (Access & fs::FA_Read)
|
||||
F = fs::OpenFileForReadWrite(fs::path{std::string_view{Filename.data(), Filename.size()}}, EC, Disp, Flags);
|
||||
} else {
|
||||
else
|
||||
F = fs::OpenFileForWrite(fs::path{std::string_view{Filename.data(), Filename.size()}}, EC, Disp, Flags);
|
||||
}
|
||||
if (EC)
|
||||
return -1;
|
||||
int FD = fs::FileToFd(F, EC, Flags);
|
||||
@@ -345,13 +355,16 @@ raw_fd_ostream::raw_fd_ostream(std::string_view Filename, std::error_code &EC,
|
||||
|
||||
/// FD is the file descriptor that this writes to. If ShouldClose is true, this
|
||||
/// closes the file when the stream is destroyed.
|
||||
raw_fd_ostream::raw_fd_ostream(int fd, bool shouldClose, bool unbuffered)
|
||||
: raw_pwrite_stream(unbuffered), FD(fd), ShouldClose(shouldClose) {
|
||||
raw_fd_ostream::raw_fd_ostream(int fd, bool shouldClose, bool unbuffered,
|
||||
OStreamKind K)
|
||||
: raw_pwrite_stream(unbuffered, K), FD(fd), ShouldClose(shouldClose) {
|
||||
if (FD < 0 ) {
|
||||
ShouldClose = false;
|
||||
return;
|
||||
}
|
||||
|
||||
enable_colors(true);
|
||||
|
||||
// Do not attempt to close stdout or stderr. We used to try to maintain the
|
||||
// property that tools that support writing file to stdout should not also
|
||||
// write informational output to stdout, but in practice we were never able to
|
||||
@@ -370,7 +383,6 @@ raw_fd_ostream::raw_fd_ostream(int fd, bool shouldClose, bool unbuffered)
|
||||
// Get the starting position.
|
||||
off_t loc = ::lseek(FD, 0, SEEK_CUR);
|
||||
#ifdef _WIN32
|
||||
// MSVCRT's _lseek(SEEK_CUR) doesn't return -1 for pipes.
|
||||
SupportsSeeking = loc != (off_t)-1 && ::GetFileType(reinterpret_cast<HANDLE>(::_get_osfhandle(FD))) != FILE_TYPE_PIPE;
|
||||
#else
|
||||
SupportsSeeking = loc != (off_t)-1;
|
||||
@@ -402,7 +414,7 @@ raw_fd_ostream::~raw_fd_ostream() {
|
||||
// destructing raw_ostream objects which may have errors.
|
||||
if (has_error())
|
||||
report_fatal_error("IO failure on output stream: " + error().message(),
|
||||
/*GenCrashDiag=*/false);
|
||||
/*gen_crash_diag=*/false);
|
||||
}
|
||||
|
||||
#if defined(_WIN32)
|
||||
@@ -565,7 +577,7 @@ size_t raw_fd_ostream::preferred_buffer_size() const {
|
||||
// If this is a terminal, don't use buffering. Line buffering
|
||||
// would be a more traditional thing to do, but it's not worth
|
||||
// the complexity.
|
||||
if (S_ISCHR(statbuf.st_mode) && isatty(FD))
|
||||
if (S_ISCHR(statbuf.st_mode) && is_displayed())
|
||||
return 0;
|
||||
// Return the preferred block size.
|
||||
return statbuf.st_blksize;
|
||||
@@ -580,28 +592,45 @@ void raw_fd_ostream::anchor() {}
|
||||
// outs(), errs(), nulls()
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// outs() - This returns a reference to a raw_ostream for standard output.
|
||||
/// Use it like: outs() << "foo" << "bar";
|
||||
raw_ostream &wpi::outs() {
|
||||
raw_fd_ostream &wpi::outs() {
|
||||
// Set buffer settings to model stdout behavior.
|
||||
std::error_code EC;
|
||||
static raw_fd_ostream* S = new raw_fd_ostream("-", EC, fs::F_None);
|
||||
static raw_fd_ostream* S = new raw_fd_ostream("-", EC, fs::OF_None);
|
||||
assert(!EC);
|
||||
return *S;
|
||||
}
|
||||
|
||||
/// errs() - This returns a reference to a raw_ostream for standard error.
|
||||
/// Use it like: errs() << "foo" << "bar";
|
||||
raw_ostream &wpi::errs() {
|
||||
// Set standard error to be unbuffered by default.
|
||||
raw_fd_ostream &wpi::errs() {
|
||||
// Set standard error to be unbuffered and tied to outs() by default.
|
||||
static raw_fd_ostream* S = new raw_fd_ostream(STDERR_FILENO, false, true);
|
||||
return *S;
|
||||
}
|
||||
|
||||
/// nulls() - This returns a reference to a raw_ostream which discards output.
|
||||
raw_ostream &wpi::nulls() {
|
||||
static raw_null_ostream* S = new raw_null_ostream;
|
||||
return *S;
|
||||
static raw_null_ostream S;
|
||||
return S;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// File Streams
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
raw_fd_stream::raw_fd_stream(std::string_view Filename, std::error_code &EC)
|
||||
: raw_fd_ostream(getFD(Filename, EC, fs::CD_CreateAlways,
|
||||
fs::FA_Write | fs::FA_Read,
|
||||
fs::OF_None),
|
||||
true, false, OStreamKind::OK_FDStream) {
|
||||
if (EC)
|
||||
return;
|
||||
|
||||
// Do not support non-seekable files.
|
||||
if (!supportsSeeking())
|
||||
EC = std::make_error_code(std::errc::invalid_argument);
|
||||
}
|
||||
|
||||
bool raw_fd_stream::classof(const raw_ostream *OS) {
|
||||
return OS->get_kind() == OStreamKind::OK_FDStream;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
@@ -691,15 +720,18 @@ raw_null_ostream::~raw_null_ostream() {
|
||||
#endif
|
||||
}
|
||||
|
||||
void raw_null_ostream::write_impl(const char * /*Ptr*/, size_t /*Size*/) {}
|
||||
void raw_null_ostream::write_impl(const char *Ptr, size_t Size) {
|
||||
}
|
||||
|
||||
uint64_t raw_null_ostream::current_pos() const {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void raw_null_ostream::pwrite_impl(const char * /*Ptr*/, size_t /*Size*/,
|
||||
uint64_t /*Offset*/) {}
|
||||
void raw_null_ostream::pwrite_impl(const char *Ptr, size_t Size,
|
||||
uint64_t Offset) {}
|
||||
|
||||
void raw_pwrite_stream::anchor() {}
|
||||
|
||||
void buffer_ostream::anchor() {}
|
||||
|
||||
void buffer_unique_ostream::anchor() {}
|
||||
|
||||
Reference in New Issue
Block a user