diff options
author | dim <dim@FreeBSD.org> | 2014-03-21 17:53:59 +0000 |
---|---|---|
committer | dim <dim@FreeBSD.org> | 2014-03-21 17:53:59 +0000 |
commit | 9cedb8bb69b89b0f0c529937247a6a80cabdbaec (patch) | |
tree | c978f0e9ec1ab92dc8123783f30b08a7fd1e2a39 /contrib/llvm/lib/Support | |
parent | 03fdc2934eb61c44c049a02b02aa974cfdd8a0eb (diff) | |
download | FreeBSD-src-9cedb8bb69b89b0f0c529937247a6a80cabdbaec.zip FreeBSD-src-9cedb8bb69b89b0f0c529937247a6a80cabdbaec.tar.gz |
MFC 261991:
Upgrade our copy of llvm/clang to 3.4 release. This version supports
all of the features in the current working draft of the upcoming C++
standard, provisionally named C++1y.
The code generator's performance is greatly increased, and the loop
auto-vectorizer is now enabled at -Os and -O2 in addition to -O3. The
PowerPC backend has made several major improvements to code generation
quality and compile time, and the X86, SPARC, ARM32, Aarch64 and SystemZ
backends have all seen major feature work.
Release notes for llvm and clang can be found here:
<http://llvm.org/releases/3.4/docs/ReleaseNotes.html>
<http://llvm.org/releases/3.4/tools/clang/docs/ReleaseNotes.html>
MFC 262121 (by emaste):
Update lldb for clang/llvm 3.4 import
This commit largely restores the lldb source to the upstream r196259
snapshot with the addition of threaded inferior support and a few bug
fixes.
Specific upstream lldb revisions restored include:
SVN git
181387 779e6ac
181703 7bef4e2
182099 b31044e
182650 f2dcf35
182683 0d91b80
183862 15c1774
183929 99447a6
184177 0b2934b
184948 4dc3761
184954 007e7bc
186990 eebd175
Sponsored by: DARPA, AFRL
MFC 262186 (by emaste):
Fix mismerge in r262121
A break statement was lost in the merge. The error had no functional
impact, but restore it to reduce the diff against upstream.
MFC 262303:
Pull in r197521 from upstream clang trunk (by rdivacky):
Use the integrated assembler by default on FreeBSD/ppc and ppc64.
Requested by: jhibbits
MFC 262611:
Pull in r196874 from upstream llvm trunk:
Fix a crash that occurs when PWD is invalid.
MCJIT needs to be able to run in hostile environments, even when PWD
is invalid. There's no need to crash MCJIT in this case.
The obvious fix is to simply leave MCContext's CompilationDir empty
when PWD can't be determined. This way, MCJIT clients,
and other clients that link with LLVM don't need a valid working directory.
If we do want to guarantee valid CompilationDir, that should be done
only for clients of getCompilationDir(). This is as simple as checking
for an empty string.
The only current use of getCompilationDir is EmitGenDwarfInfo, which
won't conceivably run with an invalid working dir. However, in the
purely hypothetically and untestable case that this happens, the
AT_comp_dir will be omitted from the compilation_unit DIE.
This should help fix assertions occurring with ports-mgmt/tinderbox,
when it is using jails, and sometimes invalidates clang's current
working directory.
Reported by: decke
MFC 262809:
Pull in r203007 from upstream clang trunk:
Don't produce an alias between destructors with different calling conventions.
Fixes pr19007.
(Please note that is an LLVM PR identifier, not a FreeBSD one.)
This should fix Firefox and/or libxul crashes (due to problems with
regparm/stdcall calling conventions) on i386.
Reported by: multiple users on freebsd-current
PR: bin/187103
MFC 263048:
Repair recognition of "CC" as an alias for the C++ compiler, since it
was silently broken by upstream for a Windows-specific use-case.
Apparently some versions of CMake still rely on this archaic feature...
Reported by: rakuco
MFC 263049:
Garbage collect the old way of adding the libstdc++ include directories
in clang's InitHeaderSearch.cpp. This has been superseded by David
Chisnall's commit in r255321.
Moreover, if libc++ is used, the libstdc++ include directories should
not be in the search path at all. These directories are now only used
if you pass -stdlib=libstdc++.
Diffstat (limited to 'contrib/llvm/lib/Support')
68 files changed, 5492 insertions, 5650 deletions
diff --git a/contrib/llvm/lib/Support/APFloat.cpp b/contrib/llvm/lib/Support/APFloat.cpp index 6182e34..676e2d4 100644 --- a/contrib/llvm/lib/Support/APFloat.cpp +++ b/contrib/llvm/lib/Support/APFloat.cpp @@ -25,7 +25,13 @@ using namespace llvm; -#define convolve(lhs, rhs) ((lhs) * 4 + (rhs)) +/// A macro used to combine two fcCategory enums into one key which can be used +/// in a switch statement to classify how the interaction of two APFloat's +/// categories affects an operation. +/// +/// TODO: If clang source code is ever allowed to use constexpr in its own +/// codebase, change this into a static inline function. +#define PackCategoriesIntoKey(_lhs, _rhs) ((_lhs) * 4 + (_rhs)) /* Assumed in hexadecimal significand parsing, and conversion to hexadecimal strings. */ @@ -38,11 +44,11 @@ namespace llvm { struct fltSemantics { /* The largest E such that 2^E is representable; this matches the definition of IEEE 754. */ - exponent_t maxExponent; + APFloat::ExponentType maxExponent; /* The smallest E such that 2^E is a normalized number; this matches the definition of IEEE 754. */ - exponent_t minExponent; + APFloat::ExponentType minExponent; /* Number of bits in the significand. This includes the integer bit. */ @@ -288,9 +294,9 @@ interpretDecimal(StringRef::iterator begin, StringRef::iterator end, } /* Adjust the exponents for any decimal point. */ - D->exponent += static_cast<exponent_t>((dot - p) - (dot > p)); + D->exponent += static_cast<APFloat::ExponentType>((dot - p) - (dot > p)); D->normalizedExponent = (D->exponent + - static_cast<exponent_t>((p - D->firstSigDigit) + static_cast<APFloat::ExponentType>((p - D->firstSigDigit) - (dot > D->firstSigDigit && dot < p))); } @@ -313,8 +319,8 @@ trailingHexadecimalFraction(StringRef::iterator p, StringRef::iterator end, else if (digitValue < 8 && digitValue > 0) return lfLessThanHalf; - /* Otherwise we need to find the first non-zero digit. */ - while (*p == '0') + // Otherwise we need to find the first non-zero digit. + while (p != end && (*p == '0' || *p == '.')) p++; assert(p != end && "Invalid trailing hexadecimal fraction!"); @@ -580,7 +586,7 @@ APFloat::initialize(const fltSemantics *ourSemantics) void APFloat::freeSignificand() { - if (partCount() > 1) + if (needsCleanup()) delete [] significand.parts; } @@ -592,14 +598,14 @@ APFloat::assign(const APFloat &rhs) sign = rhs.sign; category = rhs.category; exponent = rhs.exponent; - if (category == fcNormal || category == fcNaN) + if (isFiniteNonZero() || category == fcNaN) copySignificand(rhs); } void APFloat::copySignificand(const APFloat &rhs) { - assert(category == fcNormal || category == fcNaN); + assert(isFiniteNonZero() || category == fcNaN); assert(rhs.partCount() >= partCount()); APInt::tcAssign(significandParts(), rhs.significandParts(), @@ -679,12 +685,73 @@ APFloat::operator=(const APFloat &rhs) bool APFloat::isDenormal() const { - return isNormal() && (exponent == semantics->minExponent) && + return isFiniteNonZero() && (exponent == semantics->minExponent) && (APInt::tcExtractBit(significandParts(), semantics->precision - 1) == 0); } bool +APFloat::isSmallest() const { + // The smallest number by magnitude in our format will be the smallest + // denormal, i.e. the floating point number with exponent being minimum + // exponent and significand bitwise equal to 1 (i.e. with MSB equal to 0). + return isFiniteNonZero() && exponent == semantics->minExponent && + significandMSB() == 0; +} + +bool APFloat::isSignificandAllOnes() const { + // Test if the significand excluding the integral bit is all ones. This allows + // us to test for binade boundaries. + const integerPart *Parts = significandParts(); + const unsigned PartCount = partCount(); + for (unsigned i = 0; i < PartCount - 1; i++) + if (~Parts[i]) + return false; + + // Set the unused high bits to all ones when we compare. + const unsigned NumHighBits = + PartCount*integerPartWidth - semantics->precision + 1; + assert(NumHighBits <= integerPartWidth && "Can not have more high bits to " + "fill than integerPartWidth"); + const integerPart HighBitFill = + ~integerPart(0) << (integerPartWidth - NumHighBits); + if (~(Parts[PartCount - 1] | HighBitFill)) + return false; + + return true; +} + +bool APFloat::isSignificandAllZeros() const { + // Test if the significand excluding the integral bit is all zeros. This + // allows us to test for binade boundaries. + const integerPart *Parts = significandParts(); + const unsigned PartCount = partCount(); + + for (unsigned i = 0; i < PartCount - 1; i++) + if (Parts[i]) + return false; + + const unsigned NumHighBits = + PartCount*integerPartWidth - semantics->precision + 1; + assert(NumHighBits <= integerPartWidth && "Can not have more high bits to " + "clear than integerPartWidth"); + const integerPart HighBitMask = ~integerPart(0) >> NumHighBits; + + if (Parts[PartCount - 1] & HighBitMask) + return false; + + return true; +} + +bool +APFloat::isLargest() const { + // The largest number by magnitude in our format will be the floating point + // number with maximum exponent and with significand that is all ones. + return isFiniteNonZero() && exponent == semantics->maxExponent + && isSignificandAllOnes(); +} + +bool APFloat::bitwiseIsEqual(const APFloat &rhs) const { if (this == &rhs) return true; @@ -694,7 +761,7 @@ APFloat::bitwiseIsEqual(const APFloat &rhs) const { return false; if (category==fcZero || category==fcInfinity) return true; - else if (category==fcNormal && exponent!=rhs.exponent) + else if (isFiniteNonZero() && exponent!=rhs.exponent) return false; else { int i= partCount(); @@ -711,6 +778,7 @@ APFloat::bitwiseIsEqual(const APFloat &rhs) const { APFloat::APFloat(const fltSemantics &ourSemantics, integerPart value) { initialize(&ourSemantics); sign = 0; + category = fcNormal; zeroSignificand(); exponent = ourSemantics.precision - 1; significandParts()[0] = value; @@ -728,17 +796,6 @@ APFloat::APFloat(const fltSemantics &ourSemantics, uninitializedTag tag) { initialize(&ourSemantics); } -APFloat::APFloat(const fltSemantics &ourSemantics, - fltCategory ourCategory, bool negative) { - initialize(&ourSemantics); - category = ourCategory; - sign = negative; - if (category == fcNormal) - category = fcZero; - else if (ourCategory == fcNaN) - makeNaN(); -} - APFloat::APFloat(const fltSemantics &ourSemantics, StringRef text) { initialize(&ourSemantics); convertFromString(text, rmNearestTiesToEven); @@ -780,8 +837,6 @@ APFloat::significandParts() const integerPart * APFloat::significandParts() { - assert(category == fcNormal || category == fcNaN); - if (partCount() > 1) return significand.parts; else @@ -791,7 +846,6 @@ APFloat::significandParts() void APFloat::zeroSignificand() { - category = fcNormal; APInt::tcSet(significandParts(), 0, partCount()); } @@ -872,7 +926,21 @@ APFloat::multiplySignificand(const APFloat &rhs, const APFloat *addend) omsb = APInt::tcMSB(fullSignificand, newPartsCount) + 1; exponent += rhs.exponent; + // Assume the operands involved in the multiplication are single-precision + // FP, and the two multiplicants are: + // *this = a23 . a22 ... a0 * 2^e1 + // rhs = b23 . b22 ... b0 * 2^e2 + // the result of multiplication is: + // *this = c47 c46 . c45 ... c0 * 2^(e1+e2) + // Note that there are two significant bits at the left-hand side of the + // radix point. Move the radix point toward left by one bit, and adjust + // exponent accordingly. + exponent += 1; + if (addend) { + // The intermediate result of the multiplication has "2 * precision" + // signicant bit; adjust the addend to be consistent with mul result. + // Significand savedSignificand = significand; const fltSemantics *savedSemantics = semantics; fltSemantics extendedSemantics; @@ -880,8 +948,9 @@ APFloat::multiplySignificand(const APFloat &rhs, const APFloat *addend) unsigned int extendedPrecision; /* Normalize our MSB. */ - extendedPrecision = precision + precision - 1; + extendedPrecision = 2 * precision; if (omsb != extendedPrecision) { + assert(extendedPrecision > omsb); APInt::tcShiftLeft(fullSignificand, newPartsCount, extendedPrecision - omsb); exponent -= extendedPrecision - omsb; @@ -912,8 +981,18 @@ APFloat::multiplySignificand(const APFloat &rhs, const APFloat *addend) omsb = APInt::tcMSB(fullSignificand, newPartsCount) + 1; } - exponent -= (precision - 1); + // Convert the result having "2 * precision" significant-bits back to the one + // having "precision" significant-bits. First, move the radix point from + // poision "2*precision - 1" to "precision - 1". The exponent need to be + // adjusted by "2*precision - 1" - "precision - 1" = "precision". + exponent -= precision; + // In case MSB resides at the left-hand side of radix point, shift the + // mantissa right by some amount to make sure the MSB reside right before + // the radix point (i.e. "MSB . rest-significant-bits"). + // + // Note that the result is not normalized when "omsb < precision". So, the + // caller needs to call APFloat::normalize() if normalized value is expected. if (omsb > precision) { unsigned int bits, significantParts; lostFraction lf; @@ -1035,7 +1114,7 @@ lostFraction APFloat::shiftSignificandRight(unsigned int bits) { /* Our exponent should not overflow. */ - assert((exponent_t) (exponent + bits) >= exponent); + assert((ExponentType) (exponent + bits) >= exponent); exponent += bits; @@ -1064,8 +1143,8 @@ APFloat::compareAbsoluteValue(const APFloat &rhs) const int compare; assert(semantics == rhs.semantics); - assert(category == fcNormal); - assert(rhs.category == fcNormal); + assert(isFiniteNonZero()); + assert(rhs.isFiniteNonZero()); compare = exponent - rhs.exponent; @@ -1117,7 +1196,7 @@ APFloat::roundAwayFromZero(roundingMode rounding_mode, unsigned int bit) const { /* NaNs and infinities should not have lost fractions. */ - assert(category == fcNormal || category == fcZero); + assert(isFiniteNonZero() || category == fcZero); /* Current callers never pass this so we don't handle it. */ assert(lost_fraction != lfExactlyZero); @@ -1155,7 +1234,7 @@ APFloat::normalize(roundingMode rounding_mode, unsigned int omsb; /* One, not zero, based MSB. */ int exponentChange; - if (category != fcNormal) + if (!isFiniteNonZero()) return opOK; /* Before rounding normalize the exponent of fcNormal numbers. */ @@ -1259,42 +1338,43 @@ APFloat::normalize(roundingMode rounding_mode, APFloat::opStatus APFloat::addOrSubtractSpecials(const APFloat &rhs, bool subtract) { - switch (convolve(category, rhs.category)) { + switch (PackCategoriesIntoKey(category, rhs.category)) { default: llvm_unreachable(0); - case convolve(fcNaN, fcZero): - case convolve(fcNaN, fcNormal): - case convolve(fcNaN, fcInfinity): - case convolve(fcNaN, fcNaN): - case convolve(fcNormal, fcZero): - case convolve(fcInfinity, fcNormal): - case convolve(fcInfinity, fcZero): + case PackCategoriesIntoKey(fcNaN, fcZero): + case PackCategoriesIntoKey(fcNaN, fcNormal): + case PackCategoriesIntoKey(fcNaN, fcInfinity): + case PackCategoriesIntoKey(fcNaN, fcNaN): + case PackCategoriesIntoKey(fcNormal, fcZero): + case PackCategoriesIntoKey(fcInfinity, fcNormal): + case PackCategoriesIntoKey(fcInfinity, fcZero): return opOK; - case convolve(fcZero, fcNaN): - case convolve(fcNormal, fcNaN): - case convolve(fcInfinity, fcNaN): + case PackCategoriesIntoKey(fcZero, fcNaN): + case PackCategoriesIntoKey(fcNormal, fcNaN): + case PackCategoriesIntoKey(fcInfinity, fcNaN): + sign = false; category = fcNaN; copySignificand(rhs); return opOK; - case convolve(fcNormal, fcInfinity): - case convolve(fcZero, fcInfinity): + case PackCategoriesIntoKey(fcNormal, fcInfinity): + case PackCategoriesIntoKey(fcZero, fcInfinity): category = fcInfinity; sign = rhs.sign ^ subtract; return opOK; - case convolve(fcZero, fcNormal): + case PackCategoriesIntoKey(fcZero, fcNormal): assign(rhs); sign = rhs.sign ^ subtract; return opOK; - case convolve(fcZero, fcZero): + case PackCategoriesIntoKey(fcZero, fcZero): /* Sign depends on rounding mode; handled by caller. */ return opOK; - case convolve(fcInfinity, fcInfinity): + case PackCategoriesIntoKey(fcInfinity, fcInfinity): /* Differently signed infinities can only be validly subtracted. */ if (((sign ^ rhs.sign)!=0) != subtract) { @@ -1304,7 +1384,7 @@ APFloat::addOrSubtractSpecials(const APFloat &rhs, bool subtract) return opOK; - case convolve(fcNormal, fcNormal): + case PackCategoriesIntoKey(fcNormal, fcNormal): return opDivByZero; } } @@ -1385,41 +1465,43 @@ APFloat::addOrSubtractSignificand(const APFloat &rhs, bool subtract) APFloat::opStatus APFloat::multiplySpecials(const APFloat &rhs) { - switch (convolve(category, rhs.category)) { + switch (PackCategoriesIntoKey(category, rhs.category)) { default: llvm_unreachable(0); - case convolve(fcNaN, fcZero): - case convolve(fcNaN, fcNormal): - case convolve(fcNaN, fcInfinity): - case convolve(fcNaN, fcNaN): + case PackCategoriesIntoKey(fcNaN, fcZero): + case PackCategoriesIntoKey(fcNaN, fcNormal): + case PackCategoriesIntoKey(fcNaN, fcInfinity): + case PackCategoriesIntoKey(fcNaN, fcNaN): + sign = false; return opOK; - case convolve(fcZero, fcNaN): - case convolve(fcNormal, fcNaN): - case convolve(fcInfinity, fcNaN): + case PackCategoriesIntoKey(fcZero, fcNaN): + case PackCategoriesIntoKey(fcNormal, fcNaN): + case PackCategoriesIntoKey(fcInfinity, fcNaN): + sign = false; category = fcNaN; copySignificand(rhs); return opOK; - case convolve(fcNormal, fcInfinity): - case convolve(fcInfinity, fcNormal): - case convolve(fcInfinity, fcInfinity): + case PackCategoriesIntoKey(fcNormal, fcInfinity): + case PackCategoriesIntoKey(fcInfinity, fcNormal): + case PackCategoriesIntoKey(fcInfinity, fcInfinity): category = fcInfinity; return opOK; - case convolve(fcZero, fcNormal): - case convolve(fcNormal, fcZero): - case convolve(fcZero, fcZero): + case PackCategoriesIntoKey(fcZero, fcNormal): + case PackCategoriesIntoKey(fcNormal, fcZero): + case PackCategoriesIntoKey(fcZero, fcZero): category = fcZero; return opOK; - case convolve(fcZero, fcInfinity): - case convolve(fcInfinity, fcZero): + case PackCategoriesIntoKey(fcZero, fcInfinity): + case PackCategoriesIntoKey(fcInfinity, fcZero): makeNaN(); return opInvalidOp; - case convolve(fcNormal, fcNormal): + case PackCategoriesIntoKey(fcNormal, fcNormal): return opOK; } } @@ -1427,41 +1509,40 @@ APFloat::multiplySpecials(const APFloat &rhs) APFloat::opStatus APFloat::divideSpecials(const APFloat &rhs) { - switch (convolve(category, rhs.category)) { + switch (PackCategoriesIntoKey(category, rhs.category)) { default: llvm_unreachable(0); - case convolve(fcNaN, fcZero): - case convolve(fcNaN, fcNormal): - case convolve(fcNaN, fcInfinity): - case convolve(fcNaN, fcNaN): - case convolve(fcInfinity, fcZero): - case convolve(fcInfinity, fcNormal): - case convolve(fcZero, fcInfinity): - case convolve(fcZero, fcNormal): - return opOK; - - case convolve(fcZero, fcNaN): - case convolve(fcNormal, fcNaN): - case convolve(fcInfinity, fcNaN): + case PackCategoriesIntoKey(fcZero, fcNaN): + case PackCategoriesIntoKey(fcNormal, fcNaN): + case PackCategoriesIntoKey(fcInfinity, fcNaN): category = fcNaN; copySignificand(rhs); + case PackCategoriesIntoKey(fcNaN, fcZero): + case PackCategoriesIntoKey(fcNaN, fcNormal): + case PackCategoriesIntoKey(fcNaN, fcInfinity): + case PackCategoriesIntoKey(fcNaN, fcNaN): + sign = false; + case PackCategoriesIntoKey(fcInfinity, fcZero): + case PackCategoriesIntoKey(fcInfinity, fcNormal): + case PackCategoriesIntoKey(fcZero, fcInfinity): + case PackCategoriesIntoKey(fcZero, fcNormal): return opOK; - case convolve(fcNormal, fcInfinity): + case PackCategoriesIntoKey(fcNormal, fcInfinity): category = fcZero; return opOK; - case convolve(fcNormal, fcZero): + case PackCategoriesIntoKey(fcNormal, fcZero): category = fcInfinity; return opDivByZero; - case convolve(fcInfinity, fcInfinity): - case convolve(fcZero, fcZero): + case PackCategoriesIntoKey(fcInfinity, fcInfinity): + case PackCategoriesIntoKey(fcZero, fcZero): makeNaN(); return opInvalidOp; - case convolve(fcNormal, fcNormal): + case PackCategoriesIntoKey(fcNormal, fcNormal): return opOK; } } @@ -1469,35 +1550,36 @@ APFloat::divideSpecials(const APFloat &rhs) APFloat::opStatus APFloat::modSpecials(const APFloat &rhs) { - switch (convolve(category, rhs.category)) { + switch (PackCategoriesIntoKey(category, rhs.category)) { default: llvm_unreachable(0); - case convolve(fcNaN, fcZero): - case convolve(fcNaN, fcNormal): - case convolve(fcNaN, fcInfinity): - case convolve(fcNaN, fcNaN): - case convolve(fcZero, fcInfinity): - case convolve(fcZero, fcNormal): - case convolve(fcNormal, fcInfinity): + case PackCategoriesIntoKey(fcNaN, fcZero): + case PackCategoriesIntoKey(fcNaN, fcNormal): + case PackCategoriesIntoKey(fcNaN, fcInfinity): + case PackCategoriesIntoKey(fcNaN, fcNaN): + case PackCategoriesIntoKey(fcZero, fcInfinity): + case PackCategoriesIntoKey(fcZero, fcNormal): + case PackCategoriesIntoKey(fcNormal, fcInfinity): return opOK; - case convolve(fcZero, fcNaN): - case convolve(fcNormal, fcNaN): - case convolve(fcInfinity, fcNaN): + case PackCategoriesIntoKey(fcZero, fcNaN): + case PackCategoriesIntoKey(fcNormal, fcNaN): + case PackCategoriesIntoKey(fcInfinity, fcNaN): + sign = false; category = fcNaN; copySignificand(rhs); return opOK; - case convolve(fcNormal, fcZero): - case convolve(fcInfinity, fcZero): - case convolve(fcInfinity, fcNormal): - case convolve(fcInfinity, fcInfinity): - case convolve(fcZero, fcZero): + case PackCategoriesIntoKey(fcNormal, fcZero): + case PackCategoriesIntoKey(fcInfinity, fcZero): + case PackCategoriesIntoKey(fcInfinity, fcNormal): + case PackCategoriesIntoKey(fcInfinity, fcInfinity): + case PackCategoriesIntoKey(fcZero, fcZero): makeNaN(); return opInvalidOp; - case convolve(fcNormal, fcNormal): + case PackCategoriesIntoKey(fcNormal, fcNormal): return opOK; } } @@ -1578,7 +1660,7 @@ APFloat::multiply(const APFloat &rhs, roundingMode rounding_mode) sign ^= rhs.sign; fs = multiplySpecials(rhs); - if (category == fcNormal) { + if (isFiniteNonZero()) { lostFraction lost_fraction = multiplySignificand(rhs, 0); fs = normalize(rounding_mode, lost_fraction); if (lost_fraction != lfExactlyZero) @@ -1597,7 +1679,7 @@ APFloat::divide(const APFloat &rhs, roundingMode rounding_mode) sign ^= rhs.sign; fs = divideSpecials(rhs); - if (category == fcNormal) { + if (isFiniteNonZero()) { lostFraction lost_fraction = divideSignificand(rhs); fs = normalize(rounding_mode, lost_fraction); if (lost_fraction != lfExactlyZero) @@ -1651,7 +1733,7 @@ APFloat::mod(const APFloat &rhs, roundingMode rounding_mode) opStatus fs; fs = modSpecials(rhs); - if (category == fcNormal && rhs.category == fcNormal) { + if (isFiniteNonZero() && rhs.isFiniteNonZero()) { APFloat V = *this; unsigned int origSign = sign; @@ -1697,9 +1779,9 @@ APFloat::fusedMultiplyAdd(const APFloat &multiplicand, /* If and only if all arguments are normal do we need to do an extended-precision calculation. */ - if (category == fcNormal && - multiplicand.category == fcNormal && - addend.category == fcNormal) { + if (isFiniteNonZero() && + multiplicand.isFiniteNonZero() && + addend.isFiniteNonZero()) { lostFraction lost_fraction; lost_fraction = multiplySignificand(multiplicand, &addend); @@ -1736,7 +1818,7 @@ APFloat::opStatus APFloat::roundToIntegral(roundingMode rounding_mode) { // If the exponent is large enough, we know that this value is already // integral, and the arithmetic below would potentially cause it to saturate // to +/-Inf. Bail out early instead. - if (category == fcNormal && exponent+1 >= (int)semanticsPrecision(*semantics)) + if (isFiniteNonZero() && exponent+1 >= (int)semanticsPrecision(*semantics)) return opOK; // The algorithm here is quite simple: we add 2^(p-1), where p is the @@ -1780,36 +1862,36 @@ APFloat::compare(const APFloat &rhs) const assert(semantics == rhs.semantics); - switch (convolve(category, rhs.category)) { + switch (PackCategoriesIntoKey(category, rhs.category)) { default: llvm_unreachable(0); - case convolve(fcNaN, fcZero): - case convolve(fcNaN, fcNormal): - case convolve(fcNaN, fcInfinity): - case convolve(fcNaN, fcNaN): - case convolve(fcZero, fcNaN): - case convolve(fcNormal, fcNaN): - case convolve(fcInfinity, fcNaN): + case PackCategoriesIntoKey(fcNaN, fcZero): + case PackCategoriesIntoKey(fcNaN, fcNormal): + case PackCategoriesIntoKey(fcNaN, fcInfinity): + case PackCategoriesIntoKey(fcNaN, fcNaN): + case PackCategoriesIntoKey(fcZero, fcNaN): + case PackCategoriesIntoKey(fcNormal, fcNaN): + case PackCategoriesIntoKey(fcInfinity, fcNaN): return cmpUnordered; - case convolve(fcInfinity, fcNormal): - case convolve(fcInfinity, fcZero): - case convolve(fcNormal, fcZero): + case PackCategoriesIntoKey(fcInfinity, fcNormal): + case PackCategoriesIntoKey(fcInfinity, fcZero): + case PackCategoriesIntoKey(fcNormal, fcZero): if (sign) return cmpLessThan; else return cmpGreaterThan; - case convolve(fcNormal, fcInfinity): - case convolve(fcZero, fcInfinity): - case convolve(fcZero, fcNormal): + case PackCategoriesIntoKey(fcNormal, fcInfinity): + case PackCategoriesIntoKey(fcZero, fcInfinity): + case PackCategoriesIntoKey(fcZero, fcNormal): if (rhs.sign) return cmpGreaterThan; else return cmpLessThan; - case convolve(fcInfinity, fcInfinity): + case PackCategoriesIntoKey(fcInfinity, fcInfinity): if (sign == rhs.sign) return cmpEqual; else if (sign) @@ -1817,10 +1899,10 @@ APFloat::compare(const APFloat &rhs) const else return cmpGreaterThan; - case convolve(fcZero, fcZero): + case PackCategoriesIntoKey(fcZero, fcZero): return cmpEqual; - case convolve(fcNormal, fcNormal): + case PackCategoriesIntoKey(fcNormal, fcNormal): break; } @@ -1877,8 +1959,25 @@ APFloat::convert(const fltSemantics &toSemantics, X86SpecialNan = true; } + // If this is a truncation of a denormal number, and the target semantics + // has larger exponent range than the source semantics (this can happen + // when truncating from PowerPC double-double to double format), the + // right shift could lose result mantissa bits. Adjust exponent instead + // of performing excessive shift. + if (shift < 0 && isFiniteNonZero()) { + int exponentChange = significandMSB() + 1 - fromSemantics.precision; + if (exponent + exponentChange < toSemantics.minExponent) + exponentChange = toSemantics.minExponent - exponent; + if (exponentChange < shift) + exponentChange = shift; + if (exponentChange < 0) { + shift -= exponentChange; + exponent += exponentChange; + } + } + // If this is a truncation, perform the shift before we narrow the storage. - if (shift < 0 && (category==fcNormal || category==fcNaN)) + if (shift < 0 && (isFiniteNonZero() || category==fcNaN)) lostFraction = shiftRight(significandParts(), oldPartCount, -shift); // Fix the storage so it can hold to new value. @@ -1887,14 +1986,14 @@ APFloat::convert(const fltSemantics &toSemantics, integerPart *newParts; newParts = new integerPart[newPartCount]; APInt::tcSet(newParts, 0, newPartCount); - if (category==fcNormal || category==fcNaN) + if (isFiniteNonZero() || category==fcNaN) APInt::tcAssign(newParts, significandParts(), oldPartCount); freeSignificand(); significand.parts = newParts; } else if (newPartCount == 1 && oldPartCount != 1) { // Switch to built-in storage for a single part. integerPart newPart = 0; - if (category==fcNormal || category==fcNaN) + if (isFiniteNonZero() || category==fcNaN) newPart = significandParts()[0]; freeSignificand(); significand.part = newPart; @@ -1905,10 +2004,10 @@ APFloat::convert(const fltSemantics &toSemantics, // If this is an extension, perform the shift now that the storage is // available. - if (shift > 0 && (category==fcNormal || category==fcNaN)) + if (shift > 0 && (isFiniteNonZero() || category==fcNaN)) APInt::tcShiftLeft(significandParts(), newPartCount, shift); - if (category == fcNormal) { + if (isFiniteNonZero()) { fs = normalize(rounding_mode, lostFraction); *losesInfo = (fs != opOK); } else if (category == fcNaN) { @@ -2204,56 +2303,46 @@ APFloat::opStatus APFloat::convertFromHexadecimalString(StringRef s, roundingMode rounding_mode) { lostFraction lost_fraction = lfExactlyZero; - integerPart *significand; - unsigned int bitPos, partsCount; - StringRef::iterator dot, firstSignificantDigit; + category = fcNormal; zeroSignificand(); exponent = 0; - category = fcNormal; - significand = significandParts(); - partsCount = partCount(); - bitPos = partsCount * integerPartWidth; + integerPart *significand = significandParts(); + unsigned partsCount = partCount(); + unsigned bitPos = partsCount * integerPartWidth; + bool computedTrailingFraction = false; - /* Skip leading zeroes and any (hexa)decimal point. */ + // Skip leading zeroes and any (hexa)decimal point. StringRef::iterator begin = s.begin(); StringRef::iterator end = s.end(); + StringRef::iterator dot; StringRef::iterator p = skipLeadingZeroesAndAnyDot(begin, end, &dot); - firstSignificantDigit = p; + StringRef::iterator firstSignificantDigit = p; - for (; p != end;) { + while (p != end) { integerPart hex_value; if (*p == '.') { assert(dot == end && "String contains multiple dots"); dot = p++; - if (p == end) { - break; - } + continue; } hex_value = hexDigitValue(*p); - if (hex_value == -1U) { + if (hex_value == -1U) break; - } p++; - if (p == end) { - break; - } else { - /* Store the number whilst 4-bit nibbles remain. */ - if (bitPos) { - bitPos -= 4; - hex_value <<= bitPos % integerPartWidth; - significand[bitPos / integerPartWidth] |= hex_value; - } else { - lost_fraction = trailingHexadecimalFraction(p, end, hex_value); - while (p != end && hexDigitValue(*p) != -1U) - p++; - break; - } + // Store the number while we have space. + if (bitPos) { + bitPos -= 4; + hex_value <<= bitPos % integerPartWidth; + significand[bitPos / integerPartWidth] |= hex_value; + } else if (!computedTrailingFraction) { + lost_fraction = trailingHexadecimalFraction(p, end, hex_value); + computedTrailingFraction = true; } } @@ -2316,8 +2405,8 @@ APFloat::roundSignificandWithExponent(const integerPart *decSigParts, excessPrecision = calcSemantics.precision - semantics->precision; truncatedBits = excessPrecision; - APFloat decSig(calcSemantics, fcZero, sign); - APFloat pow5(calcSemantics, fcZero, false); + APFloat decSig = APFloat::getZero(calcSemantics, sign); + APFloat pow5(calcSemantics); sigStatus = decSig.convertFromUnsignedParts(decSigParts, sigPartCount, rmNearestTiesToEven); @@ -2402,7 +2491,14 @@ APFloat::convertFromDecimalString(StringRef str, roundingMode rounding_mode) 42039/12655 < L < 28738/8651 [ numerator <= 65536 ] */ - if (decDigitValue(*D.firstSigDigit) >= 10U) { + // Test if we have a zero number allowing for strings with no null terminators + // and zero decimals with non-zero exponents. + // + // We computed firstSigDigit by ignoring all zeros and dots. Thus if + // D->firstSigDigit equals str.end(), every digit must be a zero and there can + // be at most one dot. On the other hand, if we have a zero with a non-zero + // exponent, then we know that D.firstSigDigit will be non-numeric. + if (D.firstSigDigit == str.end() || decDigitValue(*D.firstSigDigit) >= 10U) { category = fcZero; fs = opOK; @@ -2419,6 +2515,7 @@ APFloat::convertFromDecimalString(StringRef str, roundingMode rounding_mode) (D.normalizedExponent + 1) * 28738 <= 8651 * (semantics->minExponent - (int) semantics->precision)) { /* Underflow to zero and round. */ + category = fcNormal; zeroSignificand(); fs = normalize(rounding_mode, lfLessThanHalf); @@ -2485,11 +2582,40 @@ APFloat::convertFromDecimalString(StringRef str, roundingMode rounding_mode) return fs; } +bool +APFloat::convertFromStringSpecials(StringRef str) { + if (str.equals("inf") || str.equals("INFINITY")) { + makeInf(false); + return true; + } + + if (str.equals("-inf") || str.equals("-INFINITY")) { + makeInf(true); + return true; + } + + if (str.equals("nan") || str.equals("NaN")) { + makeNaN(false, false); + return true; + } + + if (str.equals("-nan") || str.equals("-NaN")) { + makeNaN(false, true); + return true; + } + + return false; +} + APFloat::opStatus APFloat::convertFromString(StringRef str, roundingMode rounding_mode) { assert(!str.empty() && "Invalid string length"); + // Handle special cases. + if (convertFromStringSpecials(str)) + return opOK; + /* Handle a leading minus sign. */ StringRef::iterator p = str.begin(); size_t slen = str.size(); @@ -2686,7 +2812,7 @@ APFloat::convertNormalToHexString(char *dst, unsigned int hexDigits, } hash_code llvm::hash_value(const APFloat &Arg) { - if (Arg.category != APFloat::fcNormal) + if (!Arg.isFiniteNonZero()) return hash_combine((uint8_t)Arg.category, // NaN has no sign, fix it at zero. Arg.isNaN() ? (uint8_t)0 : (uint8_t)Arg.sign, @@ -2717,7 +2843,7 @@ APFloat::convertF80LongDoubleAPFloatToAPInt() const uint64_t myexponent, mysignificand; - if (category==fcNormal) { + if (isFiniteNonZero()) { myexponent = exponent+16383; //bias mysignificand = significandParts()[0]; if (myexponent==1 && !(mysignificand & 0x8000000000000000ULL)) @@ -2774,7 +2900,7 @@ APFloat::convertPPCDoubleDoubleAPFloatToAPInt() const // just set the second double to zero. Otherwise, re-convert back to // the extended format and compute the difference. This now should // convert exactly to double. - if (u.category == fcNormal && losesInfo) { + if (u.isFiniteNonZero() && losesInfo) { fs = u.convert(extendedSemantics, rmNearestTiesToEven, &losesInfo); assert(fs == opOK && !losesInfo); (void)fs; @@ -2800,7 +2926,7 @@ APFloat::convertQuadrupleAPFloatToAPInt() const uint64_t myexponent, mysignificand, mysignificand2; - if (category==fcNormal) { + if (isFiniteNonZero()) { myexponent = exponent+16383; //bias mysignificand = significandParts()[0]; mysignificand2 = significandParts()[1]; @@ -2836,7 +2962,7 @@ APFloat::convertDoubleAPFloatToAPInt() const uint64_t myexponent, mysignificand; - if (category==fcNormal) { + if (isFiniteNonZero()) { myexponent = exponent+1023; //bias mysignificand = *significandParts(); if (myexponent==1 && !(mysignificand & 0x10000000000000LL)) @@ -2866,7 +2992,7 @@ APFloat::convertFloatAPFloatToAPInt() const uint32_t myexponent, mysignificand; - if (category==fcNormal) { + if (isFiniteNonZero()) { myexponent = exponent+127; //bias mysignificand = (uint32_t)*significandParts(); if (myexponent == 1 && !(mysignificand & 0x800000)) @@ -2895,7 +3021,7 @@ APFloat::convertHalfAPFloatToAPInt() const uint32_t myexponent, mysignificand; - if (category==fcNormal) { + if (isFiniteNonZero()) { myexponent = exponent+15; //bias mysignificand = (uint32_t)*significandParts(); if (myexponent == 1 && !(mysignificand & 0x400)) @@ -3018,7 +3144,7 @@ APFloat::initFromPPCDoubleDoubleAPInt(const APInt &api) (void)fs; // Unless we have a special case, add in second double. - if (category == fcNormal) { + if (isFiniteNonZero()) { APFloat v(IEEEdouble, APInt(64, i2)); fs = v.convert(PPCDoubleDouble, rmNearestTiesToEven, &losesInfo); assert(fs == opOK && !losesInfo); @@ -3211,55 +3337,75 @@ APFloat::getAllOnesValue(unsigned BitWidth, bool isIEEE) } } -APFloat APFloat::getLargest(const fltSemantics &Sem, bool Negative) { - APFloat Val(Sem, fcNormal, Negative); - +/// Make this number the largest magnitude normal number in the given +/// semantics. +void APFloat::makeLargest(bool Negative) { // We want (in interchange format): // sign = {Negative} // exponent = 1..10 // significand = 1..1 + category = fcNormal; + sign = Negative; + exponent = semantics->maxExponent; - Val.exponent = Sem.maxExponent; // unbiased + // Use memset to set all but the highest integerPart to all ones. + integerPart *significand = significandParts(); + unsigned PartCount = partCount(); + memset(significand, 0xFF, sizeof(integerPart)*(PartCount - 1)); - // 1-initialize all bits.... - Val.zeroSignificand(); - integerPart *significand = Val.significandParts(); - unsigned N = partCountForBits(Sem.precision); - for (unsigned i = 0; i != N; ++i) - significand[i] = ~((integerPart) 0); + // Set the high integerPart especially setting all unused top bits for + // internal consistency. + const unsigned NumUnusedHighBits = + PartCount*integerPartWidth - semantics->precision; + significand[PartCount - 1] = ~integerPart(0) >> NumUnusedHighBits; +} + +/// Make this number the smallest magnitude denormal number in the given +/// semantics. +void APFloat::makeSmallest(bool Negative) { + // We want (in interchange format): + // sign = {Negative} + // exponent = 0..0 + // significand = 0..01 + category = fcNormal; + sign = Negative; + exponent = semantics->minExponent; + APInt::tcSet(significandParts(), 1, partCount()); +} - // ...and then clear the top bits for internal consistency. - if (Sem.precision % integerPartWidth != 0) - significand[N-1] &= - (((integerPart) 1) << (Sem.precision % integerPartWidth)) - 1; +APFloat APFloat::getLargest(const fltSemantics &Sem, bool Negative) { + // We want (in interchange format): + // sign = {Negative} + // exponent = 1..10 + // significand = 1..1 + APFloat Val(Sem, uninitialized); + Val.makeLargest(Negative); return Val; } APFloat APFloat::getSmallest(const fltSemantics &Sem, bool Negative) { - APFloat Val(Sem, fcNormal, Negative); - // We want (in interchange format): // sign = {Negative} // exponent = 0..0 // significand = 0..01 - - Val.exponent = Sem.minExponent; // unbiased - Val.zeroSignificand(); - Val.significandParts()[0] = 1; + APFloat Val(Sem, uninitialized); + Val.makeSmallest(Negative); return Val; } APFloat APFloat::getSmallestNormalized(const fltSemantics &Sem, bool Negative) { - APFloat Val(Sem, fcNormal, Negative); + APFloat Val(Sem, uninitialized); // We want (in interchange format): // sign = {Negative} // exponent = 0..0 // significand = 10..0 - Val.exponent = Sem.minExponent; + Val.category = fcNormal; Val.zeroSignificand(); + Val.sign = Negative; + Val.exponent = Sem.minExponent; Val.significandParts()[partCountForBits(Sem.precision)-1] |= (((integerPart) 1) << ((Sem.precision - 1) % integerPartWidth)); @@ -3400,11 +3546,14 @@ void APFloat::toString(SmallVectorImpl<char> &Str, // Set FormatPrecision if zero. We want to do this before we // truncate trailing zeros, as those are part of the precision. if (!FormatPrecision) { - // It's an interesting question whether to use the nominal - // precision or the active precision here for denormals. + // We use enough digits so the number can be round-tripped back to an + // APFloat. The formula comes from "How to Print Floating-Point Numbers + // Accurately" by Steele and White. + // FIXME: Using a formula based purely on the precision is conservative; + // we can print fewer digits depending on the actual value being printed. - // FormatPrecision = ceil(significandBits / lg_2(10)) - FormatPrecision = (semantics->precision * 59 + 195) / 196; + // FormatPrecision = 2 + floor(significandBits / lg_2(10)) + FormatPrecision = 2 + semantics->precision * 59 / 196; } // Ignore trailing binary zeros. @@ -3564,7 +3713,7 @@ void APFloat::toString(SmallVectorImpl<char> &Str, bool APFloat::getExactInverse(APFloat *inv) const { // Special floats and denormals have no exact inverse. - if (category != fcNormal) + if (!isFiniteNonZero()) return false; // Check that the number is a power of two by making sure that only the @@ -3579,10 +3728,10 @@ bool APFloat::getExactInverse(APFloat *inv) const { // Avoid multiplication with a denormal, it is not safe on all platforms and // may be slower than a normal division. - if (reciprocal.significandMSB() + 1 < reciprocal.semantics->precision) + if (reciprocal.isDenormal()) return false; - assert(reciprocal.category == fcNormal && + assert(reciprocal.isFiniteNonZero() && reciprocal.significandLSB() == reciprocal.semantics->precision - 1); if (inv) @@ -3590,3 +3739,148 @@ bool APFloat::getExactInverse(APFloat *inv) const { return true; } + +bool APFloat::isSignaling() const { + if (!isNaN()) + return false; + + // IEEE-754R 2008 6.2.1: A signaling NaN bit string should be encoded with the + // first bit of the trailing significand being 0. + return !APInt::tcExtractBit(significandParts(), semantics->precision - 2); +} + +/// IEEE-754R 2008 5.3.1: nextUp/nextDown. +/// +/// *NOTE* since nextDown(x) = -nextUp(-x), we only implement nextUp with +/// appropriate sign switching before/after the computation. +APFloat::opStatus APFloat::next(bool nextDown) { + // If we are performing nextDown, swap sign so we have -x. + if (nextDown) + changeSign(); + + // Compute nextUp(x) + opStatus result = opOK; + + // Handle each float category separately. + switch (category) { + case fcInfinity: + // nextUp(+inf) = +inf + if (!isNegative()) + break; + // nextUp(-inf) = -getLargest() + makeLargest(true); + break; + case fcNaN: + // IEEE-754R 2008 6.2 Par 2: nextUp(sNaN) = qNaN. Set Invalid flag. + // IEEE-754R 2008 6.2: nextUp(qNaN) = qNaN. Must be identity so we do not + // change the payload. + if (isSignaling()) { + result = opInvalidOp; + // For consistency, propogate the sign of the sNaN to the qNaN. + makeNaN(false, isNegative(), 0); + } + break; + case fcZero: + // nextUp(pm 0) = +getSmallest() + makeSmallest(false); + break; + case fcNormal: + // nextUp(-getSmallest()) = -0 + if (isSmallest() && isNegative()) { + APInt::tcSet(significandParts(), 0, partCount()); + category = fcZero; + exponent = 0; + break; + } + + // nextUp(getLargest()) == INFINITY + if (isLargest() && !isNegative()) { + APInt::tcSet(significandParts(), 0, partCount()); + category = fcInfinity; + exponent = semantics->maxExponent + 1; + break; + } + + // nextUp(normal) == normal + inc. + if (isNegative()) { + // If we are negative, we need to decrement the significand. + + // We only cross a binade boundary that requires adjusting the exponent + // if: + // 1. exponent != semantics->minExponent. This implies we are not in the + // smallest binade or are dealing with denormals. + // 2. Our significand excluding the integral bit is all zeros. + bool WillCrossBinadeBoundary = + exponent != semantics->minExponent && isSignificandAllZeros(); + + // Decrement the significand. + // + // We always do this since: + // 1. If we are dealing with a non binade decrement, by definition we + // just decrement the significand. + // 2. If we are dealing with a normal -> normal binade decrement, since + // we have an explicit integral bit the fact that all bits but the + // integral bit are zero implies that subtracting one will yield a + // significand with 0 integral bit and 1 in all other spots. Thus we + // must just adjust the exponent and set the integral bit to 1. + // 3. If we are dealing with a normal -> denormal binade decrement, + // since we set the integral bit to 0 when we represent denormals, we + // just decrement the significand. + integerPart *Parts = significandParts(); + APInt::tcDecrement(Parts, partCount()); + + if (WillCrossBinadeBoundary) { + // Our result is a normal number. Do the following: + // 1. Set the integral bit to 1. + // 2. Decrement the exponent. + APInt::tcSetBit(Parts, semantics->precision - 1); + exponent--; + } + } else { + // If we are positive, we need to increment the significand. + + // We only cross a binade boundary that requires adjusting the exponent if + // the input is not a denormal and all of said input's significand bits + // are set. If all of said conditions are true: clear the significand, set + // the integral bit to 1, and increment the exponent. If we have a + // denormal always increment since moving denormals and the numbers in the + // smallest normal binade have the same exponent in our representation. + bool WillCrossBinadeBoundary = !isDenormal() && isSignificandAllOnes(); + + if (WillCrossBinadeBoundary) { + integerPart *Parts = significandParts(); + APInt::tcSet(Parts, 0, partCount()); + APInt::tcSetBit(Parts, semantics->precision - 1); + assert(exponent != semantics->maxExponent && + "We can not increment an exponent beyond the maxExponent allowed" + " by the given floating point semantics."); + exponent++; + } else { + incrementSignificand(); + } + } + break; + } + + // If we are performing nextDown, swap sign so we have -nextUp(-x) + if (nextDown) + changeSign(); + + return result; +} + +void +APFloat::makeInf(bool Negative) { + category = fcInfinity; + sign = Negative; + exponent = semantics->maxExponent + 1; + APInt::tcSet(significandParts(), 0, partCount()); +} + +void +APFloat::makeZero(bool Negative) { + category = fcZero; + sign = Negative; + exponent = semantics->minExponent-1; + APInt::tcSet(significandParts(), 0, partCount()); +} diff --git a/contrib/llvm/lib/Support/APInt.cpp b/contrib/llvm/lib/Support/APInt.cpp index e853475..89f96bd 100644 --- a/contrib/llvm/lib/Support/APInt.cpp +++ b/contrib/llvm/lib/Support/APInt.cpp @@ -692,14 +692,14 @@ unsigned APInt::countLeadingZerosSlowCase() const { unsigned i = getNumWords(); integerPart MSW = pVal[i-1] & MSWMask; if (MSW) - return CountLeadingZeros_64(MSW) - (APINT_BITS_PER_WORD - BitsInMSW); + return llvm::countLeadingZeros(MSW) - (APINT_BITS_PER_WORD - BitsInMSW); unsigned Count = BitsInMSW; for (--i; i > 0u; --i) { if (pVal[i-1] == 0) Count += APINT_BITS_PER_WORD; else { - Count += CountLeadingZeros_64(pVal[i-1]); + Count += llvm::countLeadingZeros(pVal[i-1]); break; } } @@ -735,13 +735,13 @@ unsigned APInt::countLeadingOnes() const { unsigned APInt::countTrailingZeros() const { if (isSingleWord()) - return std::min(unsigned(CountTrailingZeros_64(VAL)), BitWidth); + return std::min(unsigned(llvm::countTrailingZeros(VAL)), BitWidth); unsigned Count = 0; unsigned i = 0; for (; i < getNumWords() && pVal[i] == 0; ++i) Count += APINT_BITS_PER_WORD; if (i < getNumWords()) - Count += CountTrailingZeros_64(pVal[i]); + Count += llvm::countTrailingZeros(pVal[i]); return std::min(Count, BitWidth); } @@ -1512,7 +1512,7 @@ static void KnuthDiv(unsigned *u, unsigned *v, unsigned *q, unsigned* r, // and v so that its high bits are shifted to the top of v's range without // overflow. Note that this can require an extra word in u so that u must // be of length m+n+1. - unsigned shift = CountLeadingZeros_32(v[n-1]); + unsigned shift = countLeadingZeros(v[n-1]); unsigned v_carry = 0; unsigned u_carry = 0; if (shift) { @@ -2304,24 +2304,7 @@ namespace { static unsigned int partMSB(integerPart value) { - unsigned int n, msb; - - if (value == 0) - return -1U; - - n = integerPartWidth / 2; - - msb = 0; - do { - if (value >> n) { - value >>= n; - msb += n; - } - - n >>= 1; - } while (n); - - return msb; + return findLastSet(value, ZB_Max); } /* Returns the bit number of the least significant set bit of a @@ -2329,24 +2312,7 @@ namespace { static unsigned int partLSB(integerPart value) { - unsigned int n, lsb; - - if (value == 0) - return -1U; - - lsb = integerPartWidth - 1; - n = integerPartWidth / 2; - - do { - if (value << n) { - value <<= n; - lsb -= n; - } - - n >>= 1; - } while (n); - - return lsb; + return findFirstSet(value, ZB_Max); } } @@ -2888,6 +2854,20 @@ APInt::tcIncrement(integerPart *dst, unsigned int parts) return i == parts; } +/* Decrement a bignum in-place, return the borrow flag. */ +integerPart +APInt::tcDecrement(integerPart *dst, unsigned int parts) { + for (unsigned int i = 0; i < parts; i++) { + // If the current word is non-zero, then the decrement has no effect on the + // higher-order words of the integer and no borrow can occur. Exit early. + if (dst[i]--) + return 0; + } + // If every word was zero, then there is a borrow. + return 1; +} + + /* Set the least significant BITS bits of a bignum, clear the rest. */ void diff --git a/contrib/llvm/lib/Support/Allocator.cpp b/contrib/llvm/lib/Support/Allocator.cpp index 3c4191b..6e7a541 100644 --- a/contrib/llvm/lib/Support/Allocator.cpp +++ b/contrib/llvm/lib/Support/Allocator.cpp @@ -26,6 +26,10 @@ BumpPtrAllocator::BumpPtrAllocator(size_t size, size_t threshold, : SlabSize(size), SizeThreshold(std::min(size, threshold)), Allocator(allocator), CurSlab(0), BytesAllocated(0) { } +BumpPtrAllocator::BumpPtrAllocator(size_t size, size_t threshold) + : SlabSize(size), SizeThreshold(std::min(size, threshold)), + Allocator(DefaultSlabAllocator), CurSlab(0), BytesAllocated(0) { } + BumpPtrAllocator::~BumpPtrAllocator() { DeallocateSlabs(CurSlab); } @@ -167,9 +171,6 @@ void BumpPtrAllocator::PrintStats() const { << " (includes alignment, etc)\n"; } -MallocSlabAllocator BumpPtrAllocator::DefaultSlabAllocator = - MallocSlabAllocator(); - SlabAllocator::~SlabAllocator() { } MallocSlabAllocator::~MallocSlabAllocator() { } diff --git a/contrib/llvm/lib/Support/BlockFrequency.cpp b/contrib/llvm/lib/Support/BlockFrequency.cpp index 84a993e..00efe90 100644 --- a/contrib/llvm/lib/Support/BlockFrequency.cpp +++ b/contrib/llvm/lib/Support/BlockFrequency.cpp @@ -18,76 +18,94 @@ using namespace llvm; -namespace { - -/// mult96bit - Multiply FREQ by N and store result in W array. -void mult96bit(uint64_t freq, uint32_t N, uint64_t W[2]) { +/// Multiply FREQ by N and store result in W array. +static void mult96bit(uint64_t freq, uint32_t N, uint32_t W[3]) { uint64_t u0 = freq & UINT32_MAX; uint64_t u1 = freq >> 32; - // Represent 96-bit value as w[2]:w[1]:w[0]; - uint32_t w[3] = { 0, 0, 0 }; - + // Represent 96-bit value as W[2]:W[1]:W[0]; uint64_t t = u0 * N; uint64_t k = t >> 32; - w[0] = t; + W[0] = t; t = u1 * N + k; - w[1] = t; - w[2] = t >> 32; - - // W[1] - higher bits. - // W[0] - lower bits. - W[0] = w[0] + ((uint64_t) w[1] << 32); - W[1] = w[2]; + W[1] = t; + W[2] = t >> 32; } - -/// div96bit - Divide 96-bit value stored in W array by D. Return 64-bit frequency. -uint64_t div96bit(uint64_t W[2], uint32_t D) { - uint64_t y = W[0]; - uint64_t x = W[1]; - int i; - - for (i = 1; i <= 64 && x; ++i) { - uint32_t t = (int)x >> 31; - x = (x << 1) | (y >> 63); - y = y << 1; - if ((x | t) >= D) { - x -= D; - ++y; +/// Divide 96-bit value stored in W[2]:W[1]:W[0] by D. Since our word size is a +/// 32 bit unsigned integer, we can use a short division algorithm. +static uint64_t divrem96bit(uint32_t W[3], uint32_t D, uint32_t *Rout) { + // We assume that W[2] is non-zero since if W[2] is not then the user should + // just use hardware division. + assert(W[2] && "This routine assumes that W[2] is non-zero since if W[2] is " + "zero, the caller should just use 64/32 hardware."); + uint32_t Q[3] = { 0, 0, 0 }; + + // The generalized short division algorithm sets i to m + n - 1, where n is + // the number of words in the divisior and m is the number of words by which + // the divident exceeds the divisor (i.e. m + n == the length of the dividend + // in words). Due to our assumption that W[2] is non-zero, we know that the + // dividend is of length 3 implying since n is 1 that m = 2. Thus we set i to + // m + n - 1 = 2 + 1 - 1 = 2. + uint32_t R = 0; + for (int i = 2; i >= 0; --i) { + uint64_t PartialD = uint64_t(R) << 32 | W[i]; + if (PartialD == 0) { + Q[i] = 0; + R = 0; + } else if (PartialD < D) { + Q[i] = 0; + R = uint32_t(PartialD); + } else if (PartialD == D) { + Q[i] = 1; + R = 0; + } else { + Q[i] = uint32_t(PartialD / D); + R = uint32_t(PartialD - (Q[i] * D)); } } - return y << (64 - i + 1); -} + // If Q[2] is non-zero, then we overflowed. + uint64_t Result; + if (Q[2]) { + Result = UINT64_MAX; + R = D; + } else { + // Form the final uint64_t result, avoiding endianness issues. + Result = uint64_t(Q[0]) | (uint64_t(Q[1]) << 32); + } + + if (Rout) + *Rout = R; + return Result; } +uint32_t BlockFrequency::scale(uint32_t N, uint32_t D) { + assert(D != 0 && "Division by zero"); -BlockFrequency &BlockFrequency::operator*=(const BranchProbability &Prob) { - uint32_t n = Prob.getNumerator(); - uint32_t d = Prob.getDenominator(); - - assert(n <= d && "Probability must be less or equal to 1."); - - // Calculate Frequency * n. - uint64_t mulLo = (Frequency & UINT32_MAX) * n; - uint64_t mulHi = (Frequency >> 32) * n; - uint64_t mulRes = (mulHi << 32) + mulLo; - - // If there was overflow use 96-bit operations. - if (mulHi > UINT32_MAX || mulRes < mulLo) { - // 96-bit value represented as W[1]:W[0]. - uint64_t W[2]; - - // Probability is less or equal to 1 which means that results must fit - // 64-bit. - mult96bit(Frequency, n, W); - Frequency = div96bit(W, d); - return *this; + // Calculate Frequency * N. + uint64_t MulLo = (Frequency & UINT32_MAX) * N; + uint64_t MulHi = (Frequency >> 32) * N; + uint64_t MulRes = (MulHi << 32) + MulLo; + + // If the product fits in 64 bits, just use built-in division. + if (MulHi <= UINT32_MAX && MulRes >= MulLo) { + Frequency = MulRes / D; + return MulRes % D; } - Frequency = mulRes / d; + // Product overflowed, use 96-bit operations. + // 96-bit value represented as W[2]:W[1]:W[0]. + uint32_t W[3]; + uint32_t R; + mult96bit(Frequency, N, W); + Frequency = divrem96bit(W, D, &R); + return R; +} + +BlockFrequency &BlockFrequency::operator*=(const BranchProbability &Prob) { + scale(Prob.getNumerator(), Prob.getDenominator()); return *this; } @@ -98,6 +116,17 @@ BlockFrequency::operator*(const BranchProbability &Prob) const { return Freq; } +BlockFrequency &BlockFrequency::operator/=(const BranchProbability &Prob) { + scale(Prob.getDenominator(), Prob.getNumerator()); + return *this; +} + +BlockFrequency BlockFrequency::operator/(const BranchProbability &Prob) const { + BlockFrequency Freq(Frequency); + Freq /= Prob; + return Freq; +} + BlockFrequency &BlockFrequency::operator+=(const BlockFrequency &Freq) { uint64_t Before = Freq.Frequency; Frequency += Freq.Frequency; @@ -116,8 +145,21 @@ BlockFrequency::operator+(const BlockFrequency &Prob) const { return Freq; } +uint32_t BlockFrequency::scale(const BranchProbability &Prob) { + return scale(Prob.getNumerator(), Prob.getDenominator()); +} + void BlockFrequency::print(raw_ostream &OS) const { - OS << Frequency; + // Convert fixed-point number to decimal. + OS << Frequency / getEntryFrequency() << "."; + uint64_t Rem = Frequency % getEntryFrequency(); + uint64_t Eps = 1; + do { + Rem *= 10; + Eps *= 10; + OS << Rem / getEntryFrequency(); + Rem = Rem % getEntryFrequency(); + } while (Rem >= Eps/2); } namespace llvm { diff --git a/contrib/llvm/lib/Support/CommandLine.cpp b/contrib/llvm/lib/Support/CommandLine.cpp index 18d3db5..44a88d8 100644 --- a/contrib/llvm/lib/Support/CommandLine.cpp +++ b/contrib/llvm/lib/Support/CommandLine.cpp @@ -17,12 +17,14 @@ //===----------------------------------------------------------------------===// #include "llvm/Support/CommandLine.h" +#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/Twine.h" #include "llvm/Config/config.h" +#include "llvm/Support/ConvertUTF.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Host.h" @@ -58,6 +60,7 @@ TEMPLATE_INSTANTIATION(class opt<char>); TEMPLATE_INSTANTIATION(class opt<bool>); } } // end namespace llvm::cl +// Pin the vtables to this file. void GenericOptionValue::anchor() {} void OptionValue<boolOrDefault>::anchor() {} void OptionValue<std::string>::anchor() {} @@ -72,6 +75,7 @@ void parser<double>::anchor() {} void parser<float>::anchor() {} void parser<std::string>::anchor() {} void parser<char>::anchor() {} +void StringSaver::anchor() {} //===----------------------------------------------------------------------===// @@ -435,39 +439,248 @@ static bool EatsUnboundedNumberOfValues(const Option *O) { O->getNumOccurrencesFlag() == cl::OneOrMore; } -/// ParseCStringVector - Break INPUT up wherever one or more -/// whitespace characters are found, and store the resulting tokens in -/// OUTPUT. The tokens stored in OUTPUT are dynamically allocated -/// using strdup(), so it is the caller's responsibility to free() -/// them later. +static bool isWhitespace(char C) { + return strchr(" \t\n\r\f\v", C); +} + +static bool isQuote(char C) { + return C == '\"' || C == '\''; +} + +static bool isGNUSpecial(char C) { + return strchr("\\\"\' ", C); +} + +void cl::TokenizeGNUCommandLine(StringRef Src, StringSaver &Saver, + SmallVectorImpl<const char *> &NewArgv) { + SmallString<128> Token; + for (size_t I = 0, E = Src.size(); I != E; ++I) { + // Consume runs of whitespace. + if (Token.empty()) { + while (I != E && isWhitespace(Src[I])) + ++I; + if (I == E) break; + } + + // Backslashes can escape backslashes, spaces, and other quotes. Otherwise + // they are literal. This makes it much easier to read Windows file paths. + if (I + 1 < E && Src[I] == '\\' && isGNUSpecial(Src[I + 1])) { + ++I; // Skip the escape. + Token.push_back(Src[I]); + continue; + } + + // Consume a quoted string. + if (isQuote(Src[I])) { + char Quote = Src[I++]; + while (I != E && Src[I] != Quote) { + // Backslashes are literal, unless they escape a special character. + if (Src[I] == '\\' && I + 1 != E && isGNUSpecial(Src[I + 1])) + ++I; + Token.push_back(Src[I]); + ++I; + } + if (I == E) break; + continue; + } + + // End the token if this is whitespace. + if (isWhitespace(Src[I])) { + if (!Token.empty()) + NewArgv.push_back(Saver.SaveString(Token.c_str())); + Token.clear(); + continue; + } + + // This is a normal character. Append it. + Token.push_back(Src[I]); + } + + // Append the last token after hitting EOF with no whitespace. + if (!Token.empty()) + NewArgv.push_back(Saver.SaveString(Token.c_str())); +} + +/// Backslashes are interpreted in a rather complicated way in the Windows-style +/// command line, because backslashes are used both to separate path and to +/// escape double quote. This method consumes runs of backslashes as well as the +/// following double quote if it's escaped. +/// +/// * If an even number of backslashes is followed by a double quote, one +/// backslash is output for every pair of backslashes, and the last double +/// quote remains unconsumed. The double quote will later be interpreted as +/// the start or end of a quoted string in the main loop outside of this +/// function. +/// +/// * If an odd number of backslashes is followed by a double quote, one +/// backslash is output for every pair of backslashes, and a double quote is +/// output for the last pair of backslash-double quote. The double quote is +/// consumed in this case. /// -static void ParseCStringVector(std::vector<char *> &OutputVector, - const char *Input) { - // Characters which will be treated as token separators: - StringRef Delims = " \v\f\t\r\n"; - - StringRef WorkStr(Input); - while (!WorkStr.empty()) { - // If the first character is a delimiter, strip them off. - if (Delims.find(WorkStr[0]) != StringRef::npos) { - size_t Pos = WorkStr.find_first_not_of(Delims); - if (Pos == StringRef::npos) Pos = WorkStr.size(); - WorkStr = WorkStr.substr(Pos); +/// * Otherwise, backslashes are interpreted literally. +static size_t parseBackslash(StringRef Src, size_t I, SmallString<128> &Token) { + size_t E = Src.size(); + int BackslashCount = 0; + // Skip the backslashes. + do { + ++I; + ++BackslashCount; + } while (I != E && Src[I] == '\\'); + + bool FollowedByDoubleQuote = (I != E && Src[I] == '"'); + if (FollowedByDoubleQuote) { + Token.append(BackslashCount / 2, '\\'); + if (BackslashCount % 2 == 0) + return I - 1; + Token.push_back('"'); + return I; + } + Token.append(BackslashCount, '\\'); + return I - 1; +} + +void cl::TokenizeWindowsCommandLine(StringRef Src, StringSaver &Saver, + SmallVectorImpl<const char *> &NewArgv) { + SmallString<128> Token; + + // This is a small state machine to consume characters until it reaches the + // end of the source string. + enum { INIT, UNQUOTED, QUOTED } State = INIT; + for (size_t I = 0, E = Src.size(); I != E; ++I) { + // INIT state indicates that the current input index is at the start of + // the string or between tokens. + if (State == INIT) { + if (isWhitespace(Src[I])) + continue; + if (Src[I] == '"') { + State = QUOTED; + continue; + } + if (Src[I] == '\\') { + I = parseBackslash(Src, I, Token); + State = UNQUOTED; + continue; + } + Token.push_back(Src[I]); + State = UNQUOTED; continue; } - // Find position of first delimiter. - size_t Pos = WorkStr.find_first_of(Delims); - if (Pos == StringRef::npos) Pos = WorkStr.size(); + // UNQUOTED state means that it's reading a token not quoted by double + // quotes. + if (State == UNQUOTED) { + // Whitespace means the end of the token. + if (isWhitespace(Src[I])) { + NewArgv.push_back(Saver.SaveString(Token.c_str())); + Token.clear(); + State = INIT; + continue; + } + if (Src[I] == '"') { + State = QUOTED; + continue; + } + if (Src[I] == '\\') { + I = parseBackslash(Src, I, Token); + continue; + } + Token.push_back(Src[I]); + continue; + } - // Everything from 0 to Pos is the next word to copy. - char *NewStr = (char*)malloc(Pos+1); - memcpy(NewStr, WorkStr.data(), Pos); - NewStr[Pos] = 0; - OutputVector.push_back(NewStr); + // QUOTED state means that it's reading a token quoted by double quotes. + if (State == QUOTED) { + if (Src[I] == '"') { + State = UNQUOTED; + continue; + } + if (Src[I] == '\\') { + I = parseBackslash(Src, I, Token); + continue; + } + Token.push_back(Src[I]); + } + } + // Append the last token after hitting EOF with no whitespace. + if (!Token.empty()) + NewArgv.push_back(Saver.SaveString(Token.c_str())); +} - WorkStr = WorkStr.substr(Pos); +static bool ExpandResponseFile(const char *FName, StringSaver &Saver, + TokenizerCallback Tokenizer, + SmallVectorImpl<const char *> &NewArgv) { + OwningPtr<MemoryBuffer> MemBuf; + if (MemoryBuffer::getFile(FName, MemBuf)) + return false; + StringRef Str(MemBuf->getBufferStart(), MemBuf->getBufferSize()); + + // If we have a UTF-16 byte order mark, convert to UTF-8 for parsing. + ArrayRef<char> BufRef(MemBuf->getBufferStart(), MemBuf->getBufferEnd()); + std::string UTF8Buf; + if (hasUTF16ByteOrderMark(BufRef)) { + if (!convertUTF16ToUTF8String(BufRef, UTF8Buf)) + return false; + Str = StringRef(UTF8Buf); } + + // Tokenize the contents into NewArgv. + Tokenizer(Str, Saver, NewArgv); + + return true; +} + +/// \brief Expand response files on a command line recursively using the given +/// StringSaver and tokenization strategy. +bool cl::ExpandResponseFiles(StringSaver &Saver, TokenizerCallback Tokenizer, + SmallVectorImpl<const char *> &Argv) { + unsigned RspFiles = 0; + bool AllExpanded = false; + + // Don't cache Argv.size() because it can change. + for (unsigned I = 0; I != Argv.size(); ) { + const char *Arg = Argv[I]; + if (Arg[0] != '@') { + ++I; + continue; + } + + // If we have too many response files, leave some unexpanded. This avoids + // crashing on self-referential response files. + if (RspFiles++ > 20) + return false; + + // Replace this response file argument with the tokenization of its + // contents. Nested response files are expanded in subsequent iterations. + // FIXME: If a nested response file uses a relative path, is it relative to + // the cwd of the process or the response file? + SmallVector<const char *, 0> ExpandedArgv; + if (!ExpandResponseFile(Arg + 1, Saver, Tokenizer, ExpandedArgv)) { + AllExpanded = false; + continue; + } + Argv.erase(Argv.begin() + I); + Argv.insert(Argv.begin() + I, ExpandedArgv.begin(), ExpandedArgv.end()); + } + return AllExpanded; +} + +namespace { + class StrDupSaver : public StringSaver { + std::vector<char*> Dups; + public: + ~StrDupSaver() { + for (std::vector<char *>::iterator I = Dups.begin(), E = Dups.end(); + I != E; ++I) { + char *Dup = *I; + free(Dup); + } + } + const char *SaveString(const char *Str) LLVM_OVERRIDE { + char *Dup = strdup(Str); + Dups.push_back(Dup); + return Dup; + } + }; } /// ParseEnvironmentOptions - An alternative entry point to the @@ -488,56 +701,15 @@ void cl::ParseEnvironmentOptions(const char *progName, const char *envVar, // Get program's "name", which we wouldn't know without the caller // telling us. - std::vector<char*> newArgv; - newArgv.push_back(strdup(progName)); + SmallVector<const char *, 20> newArgv; + StrDupSaver Saver; + newArgv.push_back(Saver.SaveString(progName)); // Parse the value of the environment variable into a "command line" // and hand it off to ParseCommandLineOptions(). - ParseCStringVector(newArgv, envValue); + TokenizeGNUCommandLine(envValue, Saver, newArgv); int newArgc = static_cast<int>(newArgv.size()); ParseCommandLineOptions(newArgc, &newArgv[0], Overview); - - // Free all the strdup()ed strings. - for (std::vector<char*>::iterator i = newArgv.begin(), e = newArgv.end(); - i != e; ++i) - free(*i); -} - - -/// ExpandResponseFiles - Copy the contents of argv into newArgv, -/// substituting the contents of the response files for the arguments -/// of type @file. -static void ExpandResponseFiles(unsigned argc, const char*const* argv, - std::vector<char*>& newArgv) { - for (unsigned i = 1; i != argc; ++i) { - const char *arg = argv[i]; - - if (arg[0] == '@') { - sys::PathWithStatus respFile(++arg); - - // Check that the response file is not empty (mmap'ing empty - // files can be problematic). - const sys::FileStatus *FileStat = respFile.getFileStatus(); - if (FileStat && FileStat->getSize() != 0) { - - // If we could open the file, parse its contents, otherwise - // pass the @file option verbatim. - - // TODO: we should also support recursive loading of response files, - // since this is how gcc behaves. (From their man page: "The file may - // itself contain additional @file options; any such options will be - // processed recursively.") - - // Mmap the response file into memory. - OwningPtr<MemoryBuffer> respFilePtr; - if (!MemoryBuffer::getFile(respFile.c_str(), respFilePtr)) { - ParseCStringVector(newArgv, respFilePtr->getBufferStart()); - continue; - } - } - } - newArgv.push_back(strdup(arg)); - } } void cl::ParseCommandLineOptions(int argc, const char * const *argv, @@ -552,9 +724,11 @@ void cl::ParseCommandLineOptions(int argc, const char * const *argv, "No options specified!"); // Expand response files. - std::vector<char*> newArgv; - newArgv.push_back(strdup(argv[0])); - ExpandResponseFiles(argc, argv, newArgv); + SmallVector<const char *, 20> newArgv; + for (int i = 0; i != argc; ++i) + newArgv.push_back(argv[i]); + StrDupSaver Saver; + ExpandResponseFiles(Saver, TokenizeGNUCommandLine, newArgv); argv = &newArgv[0]; argc = static_cast<int>(newArgv.size()); @@ -848,12 +1022,6 @@ void cl::ParseCommandLineOptions(int argc, const char * const *argv, PositionalOpts.clear(); MoreHelp->clear(); - // Free the memory allocated by ExpandResponseFiles. - // Free all the strdup()ed strings. - for (std::vector<char*>::iterator i = newArgv.begin(), e = newArgv.end(); - i != e; ++i) - free(*i); - // If we had an error processing our arguments, don't let the program execute if (ErrorParsing) exit(1); } @@ -913,11 +1081,20 @@ size_t alias::getOptionWidth() const { return std::strlen(ArgStr)+6; } +static void printHelpStr(StringRef HelpStr, size_t Indent, + size_t FirstLineIndentedBy) { + std::pair<StringRef, StringRef> Split = HelpStr.split('\n'); + outs().indent(Indent - FirstLineIndentedBy) << " - " << Split.first << "\n"; + while (!Split.second.empty()) { + Split = Split.second.split('\n'); + outs().indent(Indent) << Split.first << "\n"; + } +} + // Print out the option for the alias. void alias::printOptionInfo(size_t GlobalWidth) const { - size_t L = std::strlen(ArgStr); outs() << " -" << ArgStr; - outs().indent(GlobalWidth-L-6) << " - " << HelpStr << "\n"; + printHelpStr(HelpStr, GlobalWidth, std::strlen(ArgStr) + 6); } //===----------------------------------------------------------------------===// @@ -946,7 +1123,7 @@ void basic_parser_impl::printOptionInfo(const Option &O, if (const char *ValName = getValueName()) outs() << "=<" << getValueStr(O, ValName) << '>'; - outs().indent(GlobalWidth-getOptionWidth(O)) << " - " << O.HelpStr << '\n'; + printHelpStr(O.HelpStr, GlobalWidth, getOptionWidth(O)); } void basic_parser_impl::printOptionName(const Option &O, @@ -1087,9 +1264,8 @@ size_t generic_parser_base::getOptionWidth(const Option &O) const { void generic_parser_base::printOptionInfo(const Option &O, size_t GlobalWidth) const { if (O.hasArgStr()) { - size_t L = std::strlen(O.ArgStr); outs() << " -" << O.ArgStr; - outs().indent(GlobalWidth-L-6) << " - " << O.HelpStr << '\n'; + printHelpStr(O.HelpStr, GlobalWidth, std::strlen(O.ArgStr) + 6); for (unsigned i = 0, e = getNumOptions(); i != e; ++i) { size_t NumSpaces = GlobalWidth-strlen(getOption(i))-8; @@ -1100,9 +1276,9 @@ void generic_parser_base::printOptionInfo(const Option &O, if (O.HelpStr[0]) outs() << " " << O.HelpStr << '\n'; for (unsigned i = 0, e = getNumOptions(); i != e; ++i) { - size_t L = std::strlen(getOption(i)); - outs() << " -" << getOption(i); - outs().indent(GlobalWidth-L-8) << " - " << getDescription(i) << '\n'; + const char *Option = getOption(i); + outs() << " -" << Option; + printHelpStr(getDescription(i), GlobalWidth, std::strlen(Option) + 8); } } } diff --git a/contrib/llvm/lib/Support/Compression.cpp b/contrib/llvm/lib/Support/Compression.cpp index fd8a874..b5ddb70 100644 --- a/contrib/llvm/lib/Support/Compression.cpp +++ b/contrib/llvm/lib/Support/Compression.cpp @@ -81,6 +81,10 @@ zlib::Status zlib::uncompress(StringRef InputBuffer, return Res; } +uint32_t zlib::crc32(StringRef Buffer) { + return ::crc32(0, (const Bytef *)Buffer.data(), Buffer.size()); +} + #else bool zlib::isAvailable() { return false; } zlib::Status zlib::compress(StringRef InputBuffer, @@ -93,5 +97,8 @@ zlib::Status zlib::uncompress(StringRef InputBuffer, size_t UncompressedSize) { return zlib::StatusUnsupported; } +uint32_t zlib::crc32(StringRef Buffer) { + llvm_unreachable("zlib::crc32 is unavailable"); +} #endif diff --git a/contrib/llvm/lib/Support/ConstantRange.cpp b/contrib/llvm/lib/Support/ConstantRange.cpp index 5c58950..265b6e9 100644 --- a/contrib/llvm/lib/Support/ConstantRange.cpp +++ b/contrib/llvm/lib/Support/ConstantRange.cpp @@ -38,13 +38,14 @@ ConstantRange::ConstantRange(uint32_t BitWidth, bool Full) { /// Initialize a range to hold the single specified value. /// -ConstantRange::ConstantRange(const APInt &V) : Lower(V), Upper(V + 1) {} +ConstantRange::ConstantRange(APIntMoveTy V) + : Lower(llvm_move(V)), Upper(Lower + 1) {} -ConstantRange::ConstantRange(const APInt &L, const APInt &U) : - Lower(L), Upper(U) { - assert(L.getBitWidth() == U.getBitWidth() && +ConstantRange::ConstantRange(APIntMoveTy L, APIntMoveTy U) + : Lower(llvm_move(L)), Upper(llvm_move(U)) { + assert(Lower.getBitWidth() == Upper.getBitWidth() && "ConstantRange with unequal bit widths"); - assert((L != U || (L.isMaxValue() || L.isMinValue())) && + assert((Lower != Upper || (Lower.isMaxValue() || Lower.isMinValue())) && "Lower == Upper, but they aren't min or max value!"); } @@ -143,9 +144,6 @@ bool ConstantRange::isSignWrappedSet() const { /// getSetSize - Return the number of elements in this set. /// APInt ConstantRange::getSetSize() const { - if (isEmptySet()) - return APInt(getBitWidth()+1, 0); - if (isFullSet()) { APInt Size(getBitWidth()+1, 0); Size.setBit(getBitWidth()); @@ -432,7 +430,7 @@ ConstantRange ConstantRange::zeroExtend(uint32_t DstTySize) const { APInt LowerExt(DstTySize, 0); if (!Upper) // special case: [X, 0) -- not really wrapping around LowerExt = Lower.zext(DstTySize); - return ConstantRange(LowerExt, APInt(DstTySize, 1).shl(SrcTySize)); + return ConstantRange(LowerExt, APInt::getOneBitSet(DstTySize, SrcTySize)); } return ConstantRange(Lower.zext(DstTySize), Upper.zext(DstTySize)); @@ -447,6 +445,11 @@ ConstantRange ConstantRange::signExtend(uint32_t DstTySize) const { unsigned SrcTySize = getBitWidth(); assert(SrcTySize < DstTySize && "Not a value extension"); + + // special case: [X, INT_MIN) -- not really wrapping around + if (Upper.isMinSignedValue()) + return ConstantRange(Lower.sext(DstTySize), Upper.zext(DstTySize)); + if (isFullSet() || isSignWrappedSet()) { return ConstantRange(APInt::getHighBitsSet(DstTySize,DstTySize-SrcTySize+1), APInt::getLowBitsSet(DstTySize, SrcTySize-1) + 1); diff --git a/contrib/llvm/lib/Support/ConvertUTFWrapper.cpp b/contrib/llvm/lib/Support/ConvertUTFWrapper.cpp index 458fbb0..e45335d 100644 --- a/contrib/llvm/lib/Support/ConvertUTFWrapper.cpp +++ b/contrib/llvm/lib/Support/ConvertUTFWrapper.cpp @@ -8,6 +8,9 @@ //===----------------------------------------------------------------------===// #include "llvm/Support/ConvertUTF.h" +#include "llvm/Support/SwapByteOrder.h" +#include <string> +#include <vector> namespace llvm { @@ -72,5 +75,57 @@ bool ConvertCodePointToUTF8(unsigned Source, char *&ResultPtr) { return true; } +bool hasUTF16ByteOrderMark(ArrayRef<char> S) { + return (S.size() >= 2 && + ((S[0] == '\xff' && S[1] == '\xfe') || + (S[0] == '\xfe' && S[1] == '\xff'))); +} + +bool convertUTF16ToUTF8String(ArrayRef<char> SrcBytes, std::string &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 (SrcBytes.empty()) + return true; + + const UTF16 *Src = reinterpret_cast<const UTF16 *>(SrcBytes.begin()); + const UTF16 *SrcEnd = reinterpret_cast<const UTF16 *>(SrcBytes.end()); + + // 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] = llvm::sys::SwapByteOrder_16(ByteSwapped[I]); + Src = &ByteSwapped[0]; + SrcEnd = &ByteSwapped[ByteSwapped.size() - 1] + 1; + } + + // Skip the BOM for conversion. + if (Src[0] == UNI_UTF16_BYTE_ORDER_MARK_NATIVE) + Src++; + + // Just allocate enough space up front. We'll shrink it later. + Out.resize(SrcBytes.size() * UNI_MAX_UTF8_BYTES_PER_CODE_POINT); + 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) { + Out.clear(); + return false; + } + + Out.resize(reinterpret_cast<char *>(Dst) - &Out[0]); + return true; +} + } // end namespace llvm diff --git a/contrib/llvm/lib/Support/CrashRecoveryContext.cpp b/contrib/llvm/lib/Support/CrashRecoveryContext.cpp index 182c362..92c370d 100644 --- a/contrib/llvm/lib/Support/CrashRecoveryContext.cpp +++ b/contrib/llvm/lib/Support/CrashRecoveryContext.cpp @@ -11,6 +11,7 @@ #include "llvm/ADT/SmallString.h" #include "llvm/Config/config.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/ManagedStatic.h" #include "llvm/Support/Mutex.h" #include "llvm/Support/ThreadLocal.h" #include <cstdio> @@ -21,27 +22,34 @@ namespace { struct CrashRecoveryContextImpl; -static sys::ThreadLocal<const CrashRecoveryContextImpl> CurrentContext; +static ManagedStatic<sys::ThreadLocal<const CrashRecoveryContextImpl> > CurrentContext; struct CrashRecoveryContextImpl { CrashRecoveryContext *CRC; std::string Backtrace; ::jmp_buf JumpBuffer; volatile unsigned Failed : 1; + unsigned SwitchedThread : 1; public: CrashRecoveryContextImpl(CrashRecoveryContext *CRC) : CRC(CRC), - Failed(false) { - CurrentContext.set(this); + Failed(false), + SwitchedThread(false) { + CurrentContext->set(this); } ~CrashRecoveryContextImpl() { - CurrentContext.erase(); + if (!SwitchedThread) + CurrentContext->erase(); } + /// \brief Called when the separate crash-recovery thread was finished, to + /// indicate that we don't need to clear the thread-local CurrentContext. + void setSwitchedThread() { SwitchedThread = true; } + void HandleCrash() { // Eliminate the current context entry, to avoid re-entering in case the // cleanup code crashes. - CurrentContext.erase(); + CurrentContext->erase(); assert(!Failed && "Crash recovery context already failed!"); Failed = true; @@ -55,10 +63,10 @@ public: } -static sys::Mutex gCrashRecoveryContexMutex; +static ManagedStatic<sys::Mutex> gCrashRecoveryContextMutex; static bool gCrashRecoveryEnabled = false; -static sys::ThreadLocal<const CrashRecoveryContextCleanup> +static ManagedStatic<sys::ThreadLocal<const CrashRecoveryContextCleanup> > tlIsRecoveringFromCrash; CrashRecoveryContextCleanup::~CrashRecoveryContextCleanup() {} @@ -66,7 +74,7 @@ CrashRecoveryContextCleanup::~CrashRecoveryContextCleanup() {} CrashRecoveryContext::~CrashRecoveryContext() { // Reclaim registered resources. CrashRecoveryContextCleanup *i = head; - tlIsRecoveringFromCrash.set(head); + tlIsRecoveringFromCrash->set(head); while (i) { CrashRecoveryContextCleanup *tmp = i; i = tmp->next; @@ -74,21 +82,21 @@ CrashRecoveryContext::~CrashRecoveryContext() { tmp->recoverResources(); delete tmp; } - tlIsRecoveringFromCrash.erase(); + tlIsRecoveringFromCrash->erase(); CrashRecoveryContextImpl *CRCI = (CrashRecoveryContextImpl *) Impl; delete CRCI; } bool CrashRecoveryContext::isRecoveringFromCrash() { - return tlIsRecoveringFromCrash.get() != 0; + return tlIsRecoveringFromCrash->get() != 0; } CrashRecoveryContext *CrashRecoveryContext::GetCurrent() { if (!gCrashRecoveryEnabled) return 0; - const CrashRecoveryContextImpl *CRCI = CurrentContext.get(); + const CrashRecoveryContextImpl *CRCI = CurrentContext->get(); if (!CRCI) return 0; @@ -147,7 +155,7 @@ CrashRecoveryContext::unregisterCleanup(CrashRecoveryContextCleanup *cleanup) { static LONG CALLBACK ExceptionHandler(PEXCEPTION_POINTERS ExceptionInfo) { // Lookup the current thread local recovery object. - const CrashRecoveryContextImpl *CRCI = CurrentContext.get(); + const CrashRecoveryContextImpl *CRCI = CurrentContext->get(); if (!CRCI) { // Something has gone horribly wrong, so let's just tell everyone @@ -175,7 +183,7 @@ static LONG CALLBACK ExceptionHandler(PEXCEPTION_POINTERS ExceptionInfo) static sys::ThreadLocal<const void> sCurrentExceptionHandle; void CrashRecoveryContext::Enable() { - sys::ScopedLock L(gCrashRecoveryContexMutex); + sys::ScopedLock L(*gCrashRecoveryContextMutex); if (gCrashRecoveryEnabled) return; @@ -191,7 +199,7 @@ void CrashRecoveryContext::Enable() { } void CrashRecoveryContext::Disable() { - sys::ScopedLock L(gCrashRecoveryContexMutex); + sys::ScopedLock L(*gCrashRecoveryContextMutex); if (!gCrashRecoveryEnabled) return; @@ -229,7 +237,7 @@ static struct sigaction PrevActions[NumSignals]; static void CrashRecoverySignalHandler(int Signal) { // Lookup the current thread local recovery object. - const CrashRecoveryContextImpl *CRCI = CurrentContext.get(); + const CrashRecoveryContextImpl *CRCI = CurrentContext->get(); if (!CRCI) { // We didn't find a crash recovery context -- this means either we got a @@ -260,7 +268,7 @@ static void CrashRecoverySignalHandler(int Signal) { } void CrashRecoveryContext::Enable() { - sys::ScopedLock L(gCrashRecoveryContexMutex); + sys::ScopedLock L(*gCrashRecoveryContextMutex); if (gCrashRecoveryEnabled) return; @@ -279,7 +287,7 @@ void CrashRecoveryContext::Enable() { } void CrashRecoveryContext::Disable() { - sys::ScopedLock L(gCrashRecoveryContexMutex); + sys::ScopedLock L(*gCrashRecoveryContextMutex); if (!gCrashRecoveryEnabled) return; @@ -342,5 +350,7 @@ bool CrashRecoveryContext::RunSafelyOnThread(void (*Fn)(void*), void *UserData, unsigned RequestedStackSize) { RunSafelyOnThreadInfo Info = { Fn, UserData, this, false }; llvm_execute_on_thread(RunSafelyOnThread_Dispatch, &Info, RequestedStackSize); + if (CrashRecoveryContextImpl *CRC = (CrashRecoveryContextImpl *)Impl) + CRC->setSwitchedThread(); return Info.Result; } diff --git a/contrib/llvm/lib/Support/DataStream.cpp b/contrib/llvm/lib/Support/DataStream.cpp index 0a02281..0bd0c68 100644 --- a/contrib/llvm/lib/Support/DataStream.cpp +++ b/contrib/llvm/lib/Support/DataStream.cpp @@ -17,6 +17,7 @@ #define DEBUG_TYPE "Data-stream" #include "llvm/Support/DataStream.h" #include "llvm/ADT/Statistic.h" +#include "llvm/Support/FileSystem.h" #include "llvm/Support/Program.h" #include "llvm/Support/system_error.h" #include <cerrno> @@ -27,7 +28,6 @@ #else #include <io.h> #endif -#include <fcntl.h> using namespace llvm; // Interface goals: @@ -66,18 +66,11 @@ public: error_code OpenFile(const std::string &Filename) { if (Filename == "-") { Fd = 0; - sys::Program::ChangeStdinToBinary(); + sys::ChangeStdinToBinary(); return error_code::success(); } - - int OpenFlags = O_RDONLY; -#ifdef O_BINARY - OpenFlags |= O_BINARY; // Open input file in binary mode on win32. -#endif - Fd = ::open(Filename.c_str(), OpenFlags); - if (Fd == -1) - return error_code(errno, posix_category()); - return error_code::success(); + + return sys::fs::openFileForRead(Filename, Fd); } }; diff --git a/contrib/llvm/lib/Support/Disassembler.cpp b/contrib/llvm/lib/Support/Disassembler.cpp index b3244fa..27df3a9 100644 --- a/contrib/llvm/lib/Support/Disassembler.cpp +++ b/contrib/llvm/lib/Support/Disassembler.cpp @@ -41,10 +41,10 @@ bool llvm::sys::hasDisassembler() std::string llvm::sys::disassembleBuffer(uint8_t* start, size_t length, uint64_t pc) { - std::stringstream res; - #if (defined (__i386__) || defined (__amd64__) || defined (__x86_64__)) \ && USE_UDIS86 + std::stringstream res; + unsigned bits; # if defined(__i386__) bits = 32; @@ -66,9 +66,9 @@ std::string llvm::sys::disassembleBuffer(uint8_t* start, size_t length, while (ud_disassemble(&ud_obj)) { res << ud_insn_off(&ud_obj) << ":\t" << ud_insn_asm(&ud_obj) << "\n"; } -#else - res << "No disassembler available. See configure help for options.\n"; -#endif return res.str(); +#else + return "No disassembler available. See configure help for options.\n"; +#endif } diff --git a/contrib/llvm/lib/Support/Dwarf.cpp b/contrib/llvm/lib/Support/Dwarf.cpp index 0a24883..c000b63 100644 --- a/contrib/llvm/lib/Support/Dwarf.cpp +++ b/contrib/llvm/lib/Support/Dwarf.cpp @@ -12,6 +12,8 @@ //===----------------------------------------------------------------------===// #include "llvm/Support/Dwarf.h" +#include "llvm/Support/ErrorHandling.h" + using namespace llvm; using namespace dwarf; @@ -59,8 +61,8 @@ const char *llvm::dwarf::TagString(unsigned Tag) { case DW_TAG_namelist_item: return "DW_TAG_namelist_item"; case DW_TAG_packed_type: return "DW_TAG_packed_type"; case DW_TAG_subprogram: return "DW_TAG_subprogram"; - case DW_TAG_template_type_parameter: return "DW_TAG_template_type_parameter"; - case DW_TAG_template_value_parameter:return "DW_TAG_template_value_parameter"; + case DW_TAG_template_type_parameter: return "DW_TAG_template_type_parameter"; + case DW_TAG_template_value_parameter: return "DW_TAG_template_value_parameter"; case DW_TAG_thrown_type: return "DW_TAG_thrown_type"; case DW_TAG_try_block: return "DW_TAG_try_block"; case DW_TAG_variant_part: return "DW_TAG_variant_part"; @@ -230,6 +232,7 @@ const char *llvm::dwarf::AttributeString(unsigned Attribute) { case DW_AT_body_end: return "DW_AT_body_end"; case DW_AT_GNU_vector: return "DW_AT_GNU_vector"; case DW_AT_GNU_template_name: return "DW_AT_GNU_template_name"; + case DW_AT_GNU_odr_signature: return "DW_AT_GNU_odr_signature"; case DW_AT_MIPS_assumed_size: return "DW_AT_MIPS_assumed_size"; case DW_AT_lo_user: return "DW_AT_lo_user"; case DW_AT_hi_user: return "DW_AT_hi_user"; @@ -723,3 +726,51 @@ const char *llvm::dwarf::CallFrameString(unsigned Encoding) { } return 0; } + +const char *llvm::dwarf::AtomTypeString(unsigned AT) { + switch (AT) { + case dwarf::DW_ATOM_null: + return "DW_ATOM_null"; + case dwarf::DW_ATOM_die_offset: + return "DW_ATOM_die_offset"; + case DW_ATOM_cu_offset: + return "DW_ATOM_cu_offset"; + case DW_ATOM_die_tag: + return "DW_ATOM_die_tag"; + case DW_ATOM_type_flags: + return "DW_ATOM_type_flags"; + } + return 0; +} + +const char *llvm::dwarf::GDBIndexEntryKindString(GDBIndexEntryKind Kind) { + switch (Kind) { + case GIEK_NONE: + return "NONE"; + case GIEK_TYPE: + return "TYPE"; + case GIEK_VARIABLE: + return "VARIABLE"; + case GIEK_FUNCTION: + return "FUNCTION"; + case GIEK_OTHER: + return "OTHER"; + case GIEK_UNUSED5: + return "UNUSED5"; + case GIEK_UNUSED6: + return "UNUSED6"; + case GIEK_UNUSED7: + return "UNUSED7"; + } + llvm_unreachable("Unknown GDBIndexEntryKind value"); +} + +const char *llvm::dwarf::GDBIndexEntryLinkageString(GDBIndexEntryLinkage Linkage) { + switch (Linkage) { + case GIEL_EXTERNAL: + return "EXTERNAL"; + case GIEL_STATIC: + return "STATIC"; + } + llvm_unreachable("Unknown GDBIndexEntryLinkage value"); +} diff --git a/contrib/llvm/lib/Support/DynamicLibrary.cpp b/contrib/llvm/lib/Support/DynamicLibrary.cpp index f14cb45..a825c68 100644 --- a/contrib/llvm/lib/Support/DynamicLibrary.cpp +++ b/contrib/llvm/lib/Support/DynamicLibrary.cpp @@ -14,39 +14,22 @@ //===----------------------------------------------------------------------===// #include "llvm/Support/DynamicLibrary.h" +#include "llvm/Support/ManagedStatic.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/StringMap.h" #include "llvm/Config/config.h" #include "llvm/Support/Mutex.h" +#include "llvm-c/Support.h" #include <cstdio> #include <cstring> // Collection of symbol name/value pairs to be searched prior to any libraries. -static llvm::StringMap<void *> *ExplicitSymbols = 0; - -namespace { - -struct ExplicitSymbolsDeleter { - ~ExplicitSymbolsDeleter() { - delete ExplicitSymbols; - } -}; - -} - -static ExplicitSymbolsDeleter Dummy; - - -static llvm::sys::SmartMutex<true>& getMutex() { - static llvm::sys::SmartMutex<true> HandlesMutex; - return HandlesMutex; -} +static llvm::ManagedStatic<llvm::StringMap<void *> > ExplicitSymbols; +static llvm::ManagedStatic<llvm::sys::SmartMutex<true> > SymbolsMutex; void llvm::sys::DynamicLibrary::AddSymbol(StringRef symbolName, void *symbolValue) { - SmartScopedLock<true> lock(getMutex()); - if (ExplicitSymbols == 0) - ExplicitSymbols = new StringMap<void*>(); + SmartScopedLock<true> lock(*SymbolsMutex); (*ExplicitSymbols)[symbolName] = symbolValue; } @@ -72,7 +55,7 @@ static DenseSet<void *> *OpenedHandles = 0; DynamicLibrary DynamicLibrary::getPermanentLibrary(const char *filename, std::string *errMsg) { - SmartScopedLock<true> lock(getMutex()); + SmartScopedLock<true> lock(*SymbolsMutex); void *handle = dlopen(filename, RTLD_LAZY|RTLD_GLOBAL); if (handle == 0) { @@ -126,10 +109,10 @@ void *SearchForAddressOfSpecialSymbol(const char* symbolName); } void* DynamicLibrary::SearchForAddressOfSymbol(const char *symbolName) { - SmartScopedLock<true> Lock(getMutex()); + SmartScopedLock<true> Lock(*SymbolsMutex); // First check symbols added via AddSymbol(). - if (ExplicitSymbols) { + if (ExplicitSymbols.isConstructed()) { StringMap<void *>::iterator i = ExplicitSymbols->find(symbolName); if (i != ExplicitSymbols->end()) @@ -187,3 +170,11 @@ void* DynamicLibrary::SearchForAddressOfSymbol(const char *symbolName) { } #endif // LLVM_ON_WIN32 + +//===----------------------------------------------------------------------===// +// C API. +//===----------------------------------------------------------------------===// + +LLVMBool LLVMLoadLibraryPermanently(const char* Filename) { + return llvm::sys::DynamicLibrary::LoadLibraryPermanently(Filename); +} diff --git a/contrib/llvm/lib/Support/Errno.cpp b/contrib/llvm/lib/Support/Errno.cpp index 730220f..1eefa3e 100644 --- a/contrib/llvm/lib/Support/Errno.cpp +++ b/contrib/llvm/lib/Support/Errno.cpp @@ -14,8 +14,6 @@ #include "llvm/Support/Errno.h" #include "llvm/Config/config.h" // Get autoconf configuration settings #include "llvm/Support/raw_ostream.h" - -#if HAVE_STRING_H #include <string.h> #if HAVE_ERRNO_H @@ -41,28 +39,27 @@ std::string StrError(int errnum) { char buffer[MaxErrStrLen]; buffer[0] = '\0'; std::string str; + if (errnum == 0) + return str; + #ifdef HAVE_STRERROR_R // strerror_r is thread-safe. - if (errnum) -# if defined(__GLIBC__) && defined(_GNU_SOURCE) - // glibc defines its own incompatible version of strerror_r - // which may not use the buffer supplied. - str = strerror_r(errnum,buffer,MaxErrStrLen-1); -# else - strerror_r(errnum,buffer,MaxErrStrLen-1); - str = buffer; -# endif +#if defined(__GLIBC__) && defined(_GNU_SOURCE) + // glibc defines its own incompatible version of strerror_r + // which may not use the buffer supplied. + str = strerror_r(errnum, buffer, MaxErrStrLen - 1); +#else + strerror_r(errnum, buffer, MaxErrStrLen - 1); + str = buffer; +#endif #elif HAVE_DECL_STRERROR_S // "Windows Secure API" - if (errnum) { - strerror_s(buffer, MaxErrStrLen - 1, errnum); - str = buffer; - } + strerror_s(buffer, MaxErrStrLen - 1, errnum); + str = buffer; #elif defined(HAVE_STRERROR) // Copy the thread un-safe result of strerror into // the buffer as fast as possible to minimize impact // of collision of strerror in multiple threads. - if (errnum) - str = strerror(errnum); + str = strerror(errnum); #else // Strange that this system doesn't even have strerror // but, oh well, just use a generic message @@ -75,5 +72,3 @@ std::string StrError(int errnum) { } // namespace sys } // namespace llvm - -#endif // HAVE_STRING_H diff --git a/contrib/llvm/lib/Support/ErrorHandling.cpp b/contrib/llvm/lib/Support/ErrorHandling.cpp index f4b591e..1eafb96 100644 --- a/contrib/llvm/lib/Support/ErrorHandling.cpp +++ b/contrib/llvm/lib/Support/ErrorHandling.cpp @@ -20,6 +20,7 @@ #include "llvm/Support/Signals.h" #include "llvm/Support/Threading.h" #include "llvm/Support/raw_ostream.h" +#include "llvm-c/Core.h" #include <cassert> #include <cstdlib> @@ -96,4 +97,25 @@ void llvm::llvm_unreachable_internal(const char *msg, const char *file, dbgs() << " at " << file << ":" << line; dbgs() << "!\n"; abort(); +#ifdef LLVM_BUILTIN_UNREACHABLE + // Windows systems and possibly others don't declare abort() to be noreturn, + // so use the unreachable builtin to avoid a Clang self-host warning. + LLVM_BUILTIN_UNREACHABLE; +#endif +} + +static void bindingsErrorHandler(void *user_data, const std::string& reason, + bool gen_crash_diag) { + LLVMFatalErrorHandler handler = + LLVM_EXTENSION reinterpret_cast<LLVMFatalErrorHandler>(user_data); + handler(reason.c_str()); +} + +void LLVMInstallFatalErrorHandler(LLVMFatalErrorHandler Handler) { + install_fatal_error_handler(bindingsErrorHandler, + LLVM_EXTENSION reinterpret_cast<void *>(Handler)); +} + +void LLVMResetFatalErrorHandler() { + remove_fatal_error_handler(); } diff --git a/contrib/llvm/lib/Support/FileOutputBuffer.cpp b/contrib/llvm/lib/Support/FileOutputBuffer.cpp index 1ee69b6..ed084fa 100644 --- a/contrib/llvm/lib/Support/FileOutputBuffer.cpp +++ b/contrib/llvm/lib/Support/FileOutputBuffer.cpp @@ -62,11 +62,16 @@ error_code FileOutputBuffer::create(StringRef FilePath, if (EC) return EC; + unsigned Mode = sys::fs::all_read | sys::fs::all_write; + // If requested, make the output file executable. + if (Flags & F_executable) + Mode |= sys::fs::all_exe; + // Create new file in same directory but with random name. SmallString<128> TempFilePath; int FD; - EC = sys::fs::unique_file(Twine(FilePath) + ".tmp%%%%%%%", - FD, TempFilePath, false, 0644); + EC = sys::fs::createUniqueFile(Twine(FilePath) + ".tmp%%%%%%%", FD, + TempFilePath, Mode); if (EC) return EC; @@ -75,26 +80,6 @@ error_code FileOutputBuffer::create(StringRef FilePath, if (EC) return EC; - // If requested, make the output file executable. - if ( Flags & F_executable ) { - sys::fs::file_status Stat2; - EC = sys::fs::status(Twine(TempFilePath), Stat2); - if (EC) - return EC; - - sys::fs::perms new_perms = Stat2.permissions(); - if ( new_perms & sys::fs::owner_read ) - new_perms |= sys::fs::owner_exe; - if ( new_perms & sys::fs::group_read ) - new_perms |= sys::fs::group_exe; - if ( new_perms & sys::fs::others_read ) - new_perms |= sys::fs::others_exe; - new_perms |= sys::fs::add_perms; - EC = sys::fs::permissions(Twine(TempFilePath), new_perms); - if (EC) - return EC; - } - Result.reset(new FileOutputBuffer(MappedFile.get(), FilePath, TempFilePath)); if (Result) MappedFile.take(); diff --git a/contrib/llvm/lib/Support/FileUtilities.cpp b/contrib/llvm/lib/Support/FileUtilities.cpp index 4d7b239..7f5d540 100644 --- a/contrib/llvm/lib/Support/FileUtilities.cpp +++ b/contrib/llvm/lib/Support/FileUtilities.cpp @@ -171,43 +171,20 @@ static bool CompareNumbers(const char *&F1P, const char *&F2P, /// error occurs, allowing the caller to distinguish between a failed diff and a /// file system error. /// -int llvm::DiffFilesWithTolerance(const sys::PathWithStatus &FileA, - const sys::PathWithStatus &FileB, +int llvm::DiffFilesWithTolerance(StringRef NameA, + StringRef NameB, double AbsTol, double RelTol, std::string *Error) { - const sys::FileStatus *FileAStat = FileA.getFileStatus(false, Error); - if (!FileAStat) - return 2; - const sys::FileStatus *FileBStat = FileB.getFileStatus(false, Error); - if (!FileBStat) - return 2; - - // Check for zero length files because some systems croak when you try to - // mmap an empty file. - size_t A_size = FileAStat->getSize(); - size_t B_size = FileBStat->getSize(); - - // If they are both zero sized then they're the same - if (A_size == 0 && B_size == 0) - return 0; - - // If only one of them is zero sized then they can't be the same - if ((A_size == 0 || B_size == 0)) { - if (Error) - *Error = "Files differ: one is zero-sized, the other isn't"; - return 1; - } - // Now its safe to mmap the files into memory because both files // have a non-zero size. OwningPtr<MemoryBuffer> F1; - if (error_code ec = MemoryBuffer::getFile(FileA.c_str(), F1)) { + if (error_code ec = MemoryBuffer::getFile(NameA, F1)) { if (Error) *Error = ec.message(); return 2; } OwningPtr<MemoryBuffer> F2; - if (error_code ec = MemoryBuffer::getFile(FileB.c_str(), F2)) { + if (error_code ec = MemoryBuffer::getFile(NameB, F2)) { if (Error) *Error = ec.message(); return 2; @@ -220,6 +197,8 @@ int llvm::DiffFilesWithTolerance(const sys::PathWithStatus &FileA, const char *File2End = F2->getBufferEnd(); const char *F1P = File1Start; const char *F2P = File2Start; + uint64_t A_size = F1->getBufferSize(); + uint64_t B_size = F2->getBufferSize(); // Are the buffers identical? Common case: Handle this efficiently. if (A_size == B_size && diff --git a/contrib/llvm/lib/Support/FormattedStream.cpp b/contrib/llvm/lib/Support/FormattedStream.cpp index 231ae48..9febf66 100644 --- a/contrib/llvm/lib/Support/FormattedStream.cpp +++ b/contrib/llvm/lib/Support/FormattedStream.cpp @@ -17,38 +17,43 @@ using namespace llvm; -/// CountColumns - Examine the given char sequence and figure out which -/// column we end up in after output. +/// UpdatePosition - Examine the given char sequence and figure out which +/// column we end up in after output, and how many line breaks are contained. /// -static unsigned CountColumns(unsigned Column, const char *Ptr, size_t Size) { - // Keep track of the current column by scanning the string for - // special characters +static void UpdatePosition(std::pair<unsigned, unsigned> &Position, const char *Ptr, size_t Size) { + unsigned &Column = Position.first; + unsigned &Line = Position.second; + // Keep track of the current column and line by scanning the string for + // special characters for (const char *End = Ptr + Size; Ptr != End; ++Ptr) { ++Column; - if (*Ptr == '\n' || *Ptr == '\r') + switch (*Ptr) { + case '\n': + Line += 1; + case '\r': Column = 0; - else if (*Ptr == '\t') + break; + case '\t': // Assumes tab stop = 8 characters. Column += (8 - (Column & 0x7)) & 0x7; + break; + } } - - return Column; } -/// ComputeColumn - Examine the current output and figure out which -/// column we end up in after output. -void formatted_raw_ostream::ComputeColumn(const char *Ptr, size_t Size) { +/// ComputePosition - Examine the current output and update line and column +/// counts. +void formatted_raw_ostream::ComputePosition(const char *Ptr, size_t Size) { // If our previous scan pointer is inside the buffer, assume we already // scanned those bytes. This depends on raw_ostream to not change our buffer // in unexpected ways. - if (Ptr <= Scanned && Scanned <= Ptr + Size) { + if (Ptr <= Scanned && Scanned <= Ptr + Size) // Scan all characters added since our last scan to determine the new // column. - ColumnScanned = CountColumns(ColumnScanned, Scanned, - Size - (Scanned - Ptr)); - } else - ColumnScanned = CountColumns(ColumnScanned, Ptr, Size); + UpdatePosition(Position, Scanned, Size - (Scanned - Ptr)); + else + UpdatePosition(Position, Ptr, Size); // Update the scanning pointer. Scanned = Ptr + Size; @@ -60,16 +65,16 @@ void formatted_raw_ostream::ComputeColumn(const char *Ptr, size_t Size) { /// formatted_raw_ostream &formatted_raw_ostream::PadToColumn(unsigned NewCol) { // Figure out what's in the buffer and add it to the column count. - ComputeColumn(getBufferStart(), GetNumBytesInBuffer()); + ComputePosition(getBufferStart(), GetNumBytesInBuffer()); // Output spaces until we reach the desired column. - indent(std::max(int(NewCol - ColumnScanned), 1)); + indent(std::max(int(NewCol - getColumn()), 1)); return *this; } void formatted_raw_ostream::write_impl(const char *Ptr, size_t Size) { // Figure out what's in the buffer and add it to the column count. - ComputeColumn(Ptr, Size); + ComputePosition(Ptr, Size); // Write the data to the underlying stream (which is unbuffered, so // the data will be immediately written out). diff --git a/contrib/llvm/lib/Support/GraphWriter.cpp b/contrib/llvm/lib/Support/GraphWriter.cpp index bff182f..85be415 100644 --- a/contrib/llvm/lib/Support/GraphWriter.cpp +++ b/contrib/llvm/lib/Support/GraphWriter.cpp @@ -14,6 +14,7 @@ #include "llvm/Support/GraphWriter.h" #include "llvm/Config/config.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" #include "llvm/Support/Program.h" using namespace llvm; @@ -64,31 +65,46 @@ StringRef llvm::DOT::getColorString(unsigned ColorNumber) { return Colors[ColorNumber % NumColors]; } +std::string llvm::createGraphFilename(const Twine &Name, int &FD) { + FD = -1; + SmallString<128> Filename; + error_code EC = sys::fs::createTemporaryFile(Name, "dot", FD, Filename); + if (EC) { + errs() << "Error: " << EC.message() << "\n"; + return ""; + } + + errs() << "Writing '" << Filename << "'... "; + return Filename.str(); +} + // Execute the graph viewer. Return true if successful. static bool LLVM_ATTRIBUTE_UNUSED -ExecGraphViewer(const sys::Path &ExecPath, std::vector<const char*> &args, - const sys::Path &Filename, bool wait, std::string &ErrMsg) { +ExecGraphViewer(StringRef ExecPath, std::vector<const char*> &args, + StringRef Filename, bool wait, std::string &ErrMsg) { if (wait) { - if (sys::Program::ExecuteAndWait(ExecPath, &args[0],0,0,0,0,&ErrMsg)) { + if (sys::ExecuteAndWait(ExecPath, &args[0],0,0,0,0,&ErrMsg)) { errs() << "Error: " << ErrMsg << "\n"; return false; } - Filename.eraseFromDisk(); + bool Existed; + sys::fs::remove(Filename, Existed); errs() << " done. \n"; } else { - sys::Program::ExecuteNoWait(ExecPath, &args[0],0,0,0,&ErrMsg); + sys::ExecuteNoWait(ExecPath, &args[0],0,0,0,&ErrMsg); errs() << "Remember to erase graph file: " << Filename.str() << "\n"; } return true; } -void llvm::DisplayGraph(const sys::Path &Filename, bool wait, +void llvm::DisplayGraph(StringRef FilenameRef, bool wait, GraphProgram::Name program) { + std::string Filename = FilenameRef; wait &= !ViewBackground; std::string ErrMsg; #if HAVE_GRAPHVIZ - sys::Path Graphviz(LLVM_PATH_GRAPHVIZ); + std::string Graphviz(LLVM_PATH_GRAPHVIZ); std::vector<const char*> args; args.push_back(Graphviz.c_str()); @@ -99,9 +115,9 @@ void llvm::DisplayGraph(const sys::Path &Filename, bool wait, if (!ExecGraphViewer(Graphviz, args, Filename, wait, ErrMsg)) return; -#elif HAVE_XDOT_PY +#elif HAVE_XDOT std::vector<const char*> args; - args.push_back(LLVM_PATH_XDOT_PY); + args.push_back(LLVM_PATH_XDOT); args.push_back(Filename.c_str()); switch (program) { @@ -115,53 +131,51 @@ void llvm::DisplayGraph(const sys::Path &Filename, bool wait, args.push_back(0); errs() << "Running 'xdot.py' program... "; - if (!ExecGraphViewer(sys::Path(LLVM_PATH_XDOT_PY), args, Filename, wait, ErrMsg)) + if (!ExecGraphViewer(LLVM_PATH_XDOT, args, Filename, wait, ErrMsg)) return; #elif (HAVE_GV && (HAVE_DOT || HAVE_FDP || HAVE_NEATO || \ HAVE_TWOPI || HAVE_CIRCO)) - sys::Path PSFilename = Filename; - PSFilename.appendSuffix("ps"); - - sys::Path prog; + std::string PSFilename = Filename + ".ps"; + std::string prog; // Set default grapher #if HAVE_CIRCO - prog = sys::Path(LLVM_PATH_CIRCO); + prog = LLVM_PATH_CIRCO; #endif #if HAVE_TWOPI - prog = sys::Path(LLVM_PATH_TWOPI); + prog = LLVM_PATH_TWOPI; #endif #if HAVE_NEATO - prog = sys::Path(LLVM_PATH_NEATO); + prog = LLVM_PATH_NEATO; #endif #if HAVE_FDP - prog = sys::Path(LLVM_PATH_FDP); + prog = LLVM_PATH_FDP; #endif #if HAVE_DOT - prog = sys::Path(LLVM_PATH_DOT); + prog = LLVM_PATH_DOT; #endif // Find which program the user wants #if HAVE_DOT if (program == GraphProgram::DOT) - prog = sys::Path(LLVM_PATH_DOT); + prog = LLVM_PATH_DOT; #endif #if (HAVE_FDP) if (program == GraphProgram::FDP) - prog = sys::Path(LLVM_PATH_FDP); + prog = LLVM_PATH_FDP; #endif #if (HAVE_NEATO) if (program == GraphProgram::NEATO) - prog = sys::Path(LLVM_PATH_NEATO); + prog = LLVM_PATH_NEATO; #endif #if (HAVE_TWOPI) if (program == GraphProgram::TWOPI) - prog = sys::Path(LLVM_PATH_TWOPI); + prog = LLVM_PATH_TWOPI; #endif #if (HAVE_CIRCO) if (program == GraphProgram::CIRCO) - prog = sys::Path(LLVM_PATH_CIRCO); + prog = LLVM_PATH_CIRCO; #endif std::vector<const char*> args; @@ -174,12 +188,12 @@ void llvm::DisplayGraph(const sys::Path &Filename, bool wait, args.push_back(PSFilename.c_str()); args.push_back(0); - errs() << "Running '" << prog.str() << "' program... "; + errs() << "Running '" << prog << "' program... "; if (!ExecGraphViewer(prog, args, Filename, wait, ErrMsg)) return; - sys::Path gv(LLVM_PATH_GV); + std::string gv(LLVM_PATH_GV); args.clear(); args.push_back(gv.c_str()); args.push_back(PSFilename.c_str()); @@ -191,7 +205,7 @@ void llvm::DisplayGraph(const sys::Path &Filename, bool wait, return; #elif HAVE_DOTTY - sys::Path dotty(LLVM_PATH_DOTTY); + std::string dotty(LLVM_PATH_DOTTY); std::vector<const char*> args; args.push_back(dotty.c_str()); @@ -205,5 +219,8 @@ void llvm::DisplayGraph(const sys::Path &Filename, bool wait, errs() << "Running 'dotty' program... "; if (!ExecGraphViewer(dotty, args, Filename, wait, ErrMsg)) return; +#else + (void)Filename; + (void)ErrMsg; #endif } diff --git a/contrib/llvm/lib/Support/Host.cpp b/contrib/llvm/lib/Support/Host.cpp index a7c7a95..6e9a5c9 100644 --- a/contrib/llvm/lib/Support/Host.cpp +++ b/contrib/llvm/lib/Support/Host.cpp @@ -52,8 +52,54 @@ using namespace llvm; /// GetX86CpuIDAndInfo - Execute the specified cpuid and return the 4 values in the /// specified arguments. If we can't run cpuid on the host, return true. -static bool GetX86CpuIDAndInfo(unsigned value, unsigned *rEAX, - unsigned *rEBX, unsigned *rECX, unsigned *rEDX) { +static bool GetX86CpuIDAndInfo(unsigned value, unsigned *rEAX, unsigned *rEBX, + unsigned *rECX, unsigned *rEDX) { +#if defined(__GNUC__) || defined(__clang__) + #if defined(__x86_64__) || defined(_M_AMD64) || defined (_M_X64) + // gcc doesn't know cpuid would clobber ebx/rbx. Preseve it manually. + asm ("movq\t%%rbx, %%rsi\n\t" + "cpuid\n\t" + "xchgq\t%%rbx, %%rsi\n\t" + : "=a" (*rEAX), + "=S" (*rEBX), + "=c" (*rECX), + "=d" (*rEDX) + : "a" (value)); + return false; + #elif defined(i386) || defined(__i386__) || defined(__x86__) || defined(_M_IX86) + asm ("movl\t%%ebx, %%esi\n\t" + "cpuid\n\t" + "xchgl\t%%ebx, %%esi\n\t" + : "=a" (*rEAX), + "=S" (*rEBX), + "=c" (*rECX), + "=d" (*rEDX) + : "a" (value)); + return false; +// pedantic #else returns to appease -Wunreachable-code (so we don't generate +// postprocessed code that looks like "return true; return false;") + #else + return true; + #endif +#elif defined(_MSC_VER) + // The MSVC intrinsic is portable across x86 and x64. + int registers[4]; + __cpuid(registers, value); + *rEAX = registers[0]; + *rEBX = registers[1]; + *rECX = registers[2]; + *rEDX = registers[3]; + return false; +#else + return true; +#endif +} + +/// GetX86CpuIDAndInfoEx - Execute the specified cpuid with subleaf and return the +/// 4 values in the specified arguments. If we can't run cpuid on the host, +/// return true. +bool GetX86CpuIDAndInfoEx(unsigned value, unsigned subleaf, unsigned *rEAX, + unsigned *rEBX, unsigned *rECX, unsigned *rEDX) { #if defined(__x86_64__) || defined(_M_AMD64) || defined (_M_X64) #if defined(__GNUC__) // gcc doesn't know cpuid would clobber ebx/rbx. Preseve it manually. @@ -64,16 +110,22 @@ static bool GetX86CpuIDAndInfo(unsigned value, unsigned *rEAX, "=S" (*rEBX), "=c" (*rECX), "=d" (*rEDX) - : "a" (value)); + : "a" (value), + "c" (subleaf)); return false; #elif defined(_MSC_VER) - int registers[4]; - __cpuid(registers, value); - *rEAX = registers[0]; - *rEBX = registers[1]; - *rECX = registers[2]; - *rEDX = registers[3]; - return false; + // __cpuidex was added in MSVC++ 9.0 SP1 + #if (_MSC_VER > 1500) || (_MSC_VER == 1500 && _MSC_FULL_VER >= 150030729) + int registers[4]; + __cpuidex(registers, value, subleaf); + *rEAX = registers[0]; + *rEBX = registers[1]; + *rECX = registers[2]; + *rEDX = registers[3]; + return false; + #else + return true; + #endif #else return true; #endif @@ -86,11 +138,13 @@ static bool GetX86CpuIDAndInfo(unsigned value, unsigned *rEAX, "=S" (*rEBX), "=c" (*rECX), "=d" (*rEDX) - : "a" (value)); + : "a" (value), + "c" (subleaf)); return false; #elif defined(_MSC_VER) __asm { mov eax,value + mov ecx,subleaf cpuid mov esi,rEAX mov dword ptr [esi],eax @@ -102,8 +156,6 @@ static bool GetX86CpuIDAndInfo(unsigned value, unsigned *rEAX, mov dword ptr [esi],edx } return false; -// pedantic #else returns to appease -Wunreachable-code (so we don't generate -// postprocessed code that looks like "return true; return false;") #else return true; #endif @@ -148,21 +200,27 @@ std::string sys::getHostCPUName() { unsigned Model = 0; DetectX86FamilyModel(EAX, Family, Model); + union { + unsigned u[3]; + char c[12]; + } text; + + GetX86CpuIDAndInfo(0, &EAX, text.u+0, text.u+2, text.u+1); + + unsigned MaxLeaf = EAX; bool HasSSE3 = (ECX & 0x1); + bool HasSSE41 = (ECX & 0x80000); // If CPUID indicates support for XSAVE, XRESTORE and AVX, and XGETBV // indicates that the AVX registers will be saved and restored on context // switch, then we have full AVX support. const unsigned AVXBits = (1 << 27) | (1 << 28); bool HasAVX = ((ECX & AVXBits) == AVXBits) && OSHasAVXSupport(); + bool HasAVX2 = HasAVX && MaxLeaf >= 0x7 && + !GetX86CpuIDAndInfoEx(0x7, 0x0, &EAX, &EBX, &ECX, &EDX) && + (EBX & 0x20); GetX86CpuIDAndInfo(0x80000001, &EAX, &EBX, &ECX, &EDX); bool Em64T = (EDX >> 29) & 0x1; - union { - unsigned u[3]; - char c[12]; - } text; - - GetX86CpuIDAndInfo(0, &EAX, text.u+0, text.u+2, text.u+1); if (memcmp(text.c, "GenuineIntel", 12) == 0) { switch (Family) { case 3: @@ -244,7 +302,8 @@ std::string sys::getHostCPUName() { // 17h. All processors are manufactured using the 45 nm process. // // 45nm: Penryn , Wolfdale, Yorkfield (XE) - return "penryn"; + // Not all Penryn processors support SSE 4.1 (such as the Pentium brand) + return HasSSE41 ? "penryn" : "core2"; case 26: // Intel Core i7 processor and Intel Xeon processor. All // processors are manufactured using the 45 nm process. @@ -269,10 +328,20 @@ std::string sys::getHostCPUName() { // Ivy Bridge: case 58: + case 62: // Ivy Bridge EP // Not all Ivy Bridge processors support AVX (such as the Pentium // versions instead of the i7 versions). return HasAVX ? "core-avx-i" : "corei7"; + // Haswell: + case 60: + case 63: + case 69: + case 70: + // Not all Haswell processors support AVX too (such as the Pentium + // versions instead of the i7 versions). + return HasAVX2 ? "core-avx2" : "corei7"; + case 28: // Most 45 nm Intel Atom processors case 38: // 45 nm Atom Lincroft case 39: // 32 nm Atom Medfield @@ -280,6 +349,12 @@ std::string sys::getHostCPUName() { case 54: // 32 nm Atom Midview return "atom"; + // Atom Silvermont codes from the Intel software optimization guide. + case 55: + case 74: + case 77: + return "slm"; + default: return (Em64T) ? "x86-64" : "i686"; } case 15: { @@ -357,9 +432,11 @@ std::string sys::getHostCPUName() { case 21: if (!HasAVX) // If the OS doesn't support AVX provide a sane fallback. return "btver1"; - if (Model > 15 && Model <= 31) - return "bdver2"; - return "bdver1"; + if (Model >= 0x30) + return "bdver3"; // 30h-3Fh: Steamroller + if (Model >= 0x10) + return "bdver2"; // 10h-1Fh: Piledriver + return "bdver1"; // 00h-0Fh: Bulldozer case 22: if (!HasAVX) // If the OS doesn't support AVX provide a sane fallback. return "btver1"; @@ -544,6 +621,48 @@ std::string sys::getHostCPUName() { return "generic"; } +#elif defined(__linux__) && defined(__s390x__) +std::string sys::getHostCPUName() { + // STIDP is a privileged operation, so use /proc/cpuinfo instead. + // Note: We cannot mmap /proc/cpuinfo here and then process the resulting + // memory buffer because the 'file' has 0 size (it can be read from only + // as a stream). + + std::string Err; + DataStreamer *DS = getDataFileStreamer("/proc/cpuinfo", &Err); + if (!DS) { + DEBUG(dbgs() << "Unable to open /proc/cpuinfo: " << Err << "\n"); + return "generic"; + } + + // The "processor 0:" line comes after a fair amount of other information, + // including a cache breakdown, but this should be plenty. + char buffer[2048]; + size_t CPUInfoSize = DS->GetBytes((unsigned char*) buffer, sizeof(buffer)); + delete DS; + + StringRef Str(buffer, CPUInfoSize); + SmallVector<StringRef, 32> Lines; + Str.split(Lines, "\n"); + for (unsigned I = 0, E = Lines.size(); I != E; ++I) { + if (Lines[I].startswith("processor ")) { + size_t Pos = Lines[I].find("machine = "); + if (Pos != StringRef::npos) { + Pos += sizeof("machine = ") - 1; + unsigned int Id; + if (!Lines[I].drop_front(Pos).getAsInteger(10, Id)) { + if (Id >= 2827) + return "zEC12"; + if (Id >= 2817) + return "z196"; + } + } + break; + } + } + + return "generic"; +} #else std::string sys::getHostCPUName() { return "generic"; @@ -570,41 +689,31 @@ bool sys::getHostCPUFeatures(StringMap<bool> &Features) { SmallVector<StringRef, 32> Lines; Str.split(Lines, "\n"); - // Look for the CPU implementer line. - StringRef Implementer; - for (unsigned I = 0, E = Lines.size(); I != E; ++I) - if (Lines[I].startswith("CPU implementer")) - Implementer = Lines[I].substr(15).ltrim("\t :"); - - if (Implementer == "0x41") { // ARM Ltd. - SmallVector<StringRef, 32> CPUFeatures; + SmallVector<StringRef, 32> CPUFeatures; - // Look for the CPU features. - for (unsigned I = 0, E = Lines.size(); I != E; ++I) - if (Lines[I].startswith("Features")) { - Lines[I].split(CPUFeatures, " "); - break; - } - - for (unsigned I = 0, E = CPUFeatures.size(); I != E; ++I) { - StringRef LLVMFeatureStr = StringSwitch<StringRef>(CPUFeatures[I]) - .Case("half", "fp16") - .Case("neon", "neon") - .Case("vfpv3", "vfp3") - .Case("vfpv3d16", "d16") - .Case("vfpv4", "vfp4") - .Case("idiva", "hwdiv-arm") - .Case("idivt", "hwdiv") - .Default(""); - - if (LLVMFeatureStr != "") - Features.GetOrCreateValue(LLVMFeatureStr).setValue(true); + // Look for the CPU features. + for (unsigned I = 0, E = Lines.size(); I != E; ++I) + if (Lines[I].startswith("Features")) { + Lines[I].split(CPUFeatures, " "); + break; } - return true; + for (unsigned I = 0, E = CPUFeatures.size(); I != E; ++I) { + StringRef LLVMFeatureStr = StringSwitch<StringRef>(CPUFeatures[I]) + .Case("half", "fp16") + .Case("neon", "neon") + .Case("vfpv3", "vfp3") + .Case("vfpv3d16", "d16") + .Case("vfpv4", "vfp4") + .Case("idiva", "hwdiv-arm") + .Case("idivt", "hwdiv") + .Default(""); + + if (LLVMFeatureStr != "") + Features.GetOrCreateValue(LLVMFeatureStr).setValue(true); } - return false; + return true; } #else bool sys::getHostCPUFeatures(StringMap<bool> &Features){ @@ -613,7 +722,7 @@ bool sys::getHostCPUFeatures(StringMap<bool> &Features){ #endif std::string sys::getProcessTriple() { - Triple PT(LLVM_HOST_TRIPLE); + Triple PT(Triple::normalize(LLVM_HOST_TRIPLE)); if (sizeof(void *) == 8 && PT.isArch32Bit()) PT = PT.get64BitArchVariant(); diff --git a/contrib/llvm/lib/Support/Locale.cpp b/contrib/llvm/lib/Support/Locale.cpp index 17b9b6c..35ddf7f 100644 --- a/contrib/llvm/lib/Support/Locale.cpp +++ b/contrib/llvm/lib/Support/Locale.cpp @@ -1,10 +1,31 @@ #include "llvm/Support/Locale.h" -#include "llvm/Config/config.h" +#include "llvm/Support/Unicode.h" -#ifdef __APPLE__ -#include "LocaleXlocale.inc" -#elif LLVM_ON_WIN32 -#include "LocaleWindows.inc" +namespace llvm { +namespace sys { +namespace locale { + +int columnWidth(StringRef Text) { +#if LLVM_ON_WIN32 + return Text.size(); #else -#include "LocaleGeneric.inc" + return llvm::sys::unicode::columnWidthUTF8(Text); #endif +} + +bool isPrint(int UCS) { +#if LLVM_ON_WIN32 + // Restrict characters that we'll try to print to the the lower part of ASCII + // except for the control characters (0x20 - 0x7E). In general one can not + // reliably output code points U+0080 and higher using narrow character C/C++ + // output functions in Windows, because the meaning of the upper 128 codes is + // determined by the active code page in the console. + return ' ' <= UCS && UCS <= '~'; +#else + return llvm::sys::unicode::isPrintable(UCS); +#endif +} + +} // namespace locale +} // namespace sys +} // namespace llvm diff --git a/contrib/llvm/lib/Support/LocaleGeneric.inc b/contrib/llvm/lib/Support/LocaleGeneric.inc deleted file mode 100644 index 278deee..0000000 --- a/contrib/llvm/lib/Support/LocaleGeneric.inc +++ /dev/null @@ -1,17 +0,0 @@ -#include <cwctype> - -namespace llvm { -namespace sys { -namespace locale { - -int columnWidth(StringRef s) { - return s.size(); -} - -bool isPrint(int c) { - return iswprint(c); -} - -} -} -} diff --git a/contrib/llvm/lib/Support/LocaleWindows.inc b/contrib/llvm/lib/Support/LocaleWindows.inc deleted file mode 100644 index 28e429c..0000000 --- a/contrib/llvm/lib/Support/LocaleWindows.inc +++ /dev/null @@ -1,15 +0,0 @@ -namespace llvm { -namespace sys { -namespace locale { - -int columnWidth(StringRef s) { - return s.size(); -} - -bool isPrint(int c) { - return ' ' <= c && c <= '~'; -} - -} -} -} diff --git a/contrib/llvm/lib/Support/LocaleXlocale.inc b/contrib/llvm/lib/Support/LocaleXlocale.inc deleted file mode 100644 index 389fe3d..0000000 --- a/contrib/llvm/lib/Support/LocaleXlocale.inc +++ /dev/null @@ -1,61 +0,0 @@ -#include "llvm/ADT/SmallString.h" -#include "llvm/ADT/SmallVector.h" -#include "llvm/Support/ManagedStatic.h" -#include <cassert> -#include <xlocale.h> - - -namespace { - struct locale_holder { - locale_holder() - : l(newlocale(LC_CTYPE_MASK,"en_US.UTF-8",LC_GLOBAL_LOCALE)) - { - assert(NULL!=l); - } - ~locale_holder() { - freelocale(l); - } - - int mbswidth(llvm::SmallString<16> s) const { - // this implementation assumes no '\0' in s - assert(s.size()==strlen(s.c_str())); - - size_t size = mbstowcs_l(NULL,s.c_str(),0,l); - assert(size!=(size_t)-1); - if (size==0) - return 0; - llvm::SmallVector<wchar_t,200> ws(size); - size = mbstowcs_l(&ws[0],s.c_str(),ws.size(),l); - assert(ws.size()==size); - return wcswidth_l(&ws[0],ws.size(),l); - } - - int isprint(int c) const { - return iswprint_l(c,l); - } - - private: - - locale_t l; - }; - - llvm::ManagedStatic<locale_holder> l; -} - -namespace llvm { -namespace sys { -namespace locale { - -int columnWidth(StringRef s) { - int width = l->mbswidth(s); - assert(width>=0); - return width; -} - -bool isPrint(int c) { - return l->isprint(c); -} - -} -} -} diff --git a/contrib/llvm/lib/Support/LockFileManager.cpp b/contrib/llvm/lib/Support/LockFileManager.cpp index 2917e27..eeec274 100644 --- a/contrib/llvm/lib/Support/LockFileManager.cpp +++ b/contrib/llvm/lib/Support/LockFileManager.cpp @@ -7,9 +7,11 @@ // //===----------------------------------------------------------------------===// #include "llvm/Support/LockFileManager.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/Support/FileSystem.h" +#include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/raw_ostream.h" -#include <fstream> #include <sys/stat.h> #include <sys/types.h> #if LLVM_ON_WIN32 @@ -35,16 +37,20 @@ LockFileManager::readLockFile(StringRef LockFileName) { // Read the owning host and PID out of the lock file. If it appears that the // owning process is dead, the lock file is invalid. - int PID = 0; - std::string Hostname; - std::ifstream Input(LockFileName.str().c_str()); - if (Input >> Hostname >> PID && PID > 0 && - processStillExecuting(Hostname, PID)) - return std::make_pair(Hostname, PID); + OwningPtr<MemoryBuffer> MB; + if (MemoryBuffer::getFile(LockFileName, MB)) + return None; + + StringRef Hostname; + StringRef PIDStr; + tie(Hostname, PIDStr) = getToken(MB->getBuffer(), " "); + PIDStr = PIDStr.substr(PIDStr.find_first_not_of(" ")); + int PID; + if (!PIDStr.getAsInteger(10, PID)) + return std::make_pair(std::string(Hostname), PID); // Delete the lock file. It's invalid anyway. - bool Existed; - sys::fs::remove(LockFileName, Existed); + sys::fs::remove(LockFileName); return None; } @@ -78,10 +84,9 @@ LockFileManager::LockFileManager(StringRef FileName) UniqueLockFileName += "-%%%%%%%%"; int UniqueLockFileID; if (error_code EC - = sys::fs::unique_file(UniqueLockFileName.str(), - UniqueLockFileID, - UniqueLockFileName, - /*makeAbsolute=*/false)) { + = sys::fs::createUniqueFile(UniqueLockFileName.str(), + UniqueLockFileID, + UniqueLockFileName)) { Error = EC; return; } diff --git a/contrib/llvm/lib/Support/MD5.cpp b/contrib/llvm/lib/Support/MD5.cpp new file mode 100644 index 0000000..514466c --- /dev/null +++ b/contrib/llvm/lib/Support/MD5.cpp @@ -0,0 +1,286 @@ +/* + * This code is derived from (original license follows): + * + * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc. + * MD5 Message-Digest Algorithm (RFC 1321). + * + * Homepage: + * http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5 + * + * Author: + * Alexander Peslyak, better known as Solar Designer <solar at openwall.com> + * + * This software was written by Alexander Peslyak in 2001. No copyright is + * claimed, and the software is hereby placed in the public domain. + * In case this attempt to disclaim copyright and place the software in the + * public domain is deemed null and void, then the software is + * Copyright (c) 2001 Alexander Peslyak and it is hereby released to the + * general public under the following terms: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + * There's ABSOLUTELY NO WARRANTY, express or implied. + * + * (This is a heavily cut-down "BSD license".) + * + * This differs from Colin Plumb's older public domain implementation in that + * no exactly 32-bit integer data type is required (any 32-bit or wider + * unsigned integer data type will do), there's no compile-time endianness + * configuration, and the function prototypes match OpenSSL's. No code from + * Colin Plumb's implementation has been reused; this comment merely compares + * the properties of the two independent implementations. + * + * The primary goals of this implementation are portability and ease of use. + * It is meant to be fast, but not as fast as possible. Some known + * optimizations are not included to reduce source code size and avoid + * compile-time configuration. + */ + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/MD5.h" +#include "llvm/Support/raw_ostream.h" +#include <cstring> + +// The basic MD5 functions. + +// F and G are optimized compared to their RFC 1321 definitions for +// architectures that lack an AND-NOT instruction, just like in Colin Plumb's +// implementation. +#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z)))) +#define G(x, y, z) ((y) ^ ((z) & ((x) ^ (y)))) +#define H(x, y, z) ((x) ^ (y) ^ (z)) +#define I(x, y, z) ((y) ^ ((x) | ~(z))) + +// The MD5 transformation for all four rounds. +#define STEP(f, a, b, c, d, x, t, s) \ + (a) += f((b), (c), (d)) + (x) + (t); \ + (a) = (((a) << (s)) | (((a) & 0xffffffff) >> (32 - (s)))); \ + (a) += (b); + +// SET reads 4 input bytes in little-endian byte order and stores them +// in a properly aligned word in host byte order. +#define SET(n) \ + (block[(n)] = \ + (MD5_u32plus) ptr[(n) * 4] | ((MD5_u32plus) ptr[(n) * 4 + 1] << 8) | \ + ((MD5_u32plus) ptr[(n) * 4 + 2] << 16) | \ + ((MD5_u32plus) ptr[(n) * 4 + 3] << 24)) +#define GET(n) (block[(n)]) + +namespace llvm { + +/// \brief This processes one or more 64-byte data blocks, but does NOT update +///the bit counters. There are no alignment requirements. +const uint8_t *MD5::body(ArrayRef<uint8_t> Data) { + const uint8_t *ptr; + MD5_u32plus a, b, c, d; + MD5_u32plus saved_a, saved_b, saved_c, saved_d; + unsigned long Size = Data.size(); + + ptr = Data.data(); + + a = this->a; + b = this->b; + c = this->c; + d = this->d; + + do { + saved_a = a; + saved_b = b; + saved_c = c; + saved_d = d; + + // Round 1 + STEP(F, a, b, c, d, SET(0), 0xd76aa478, 7) + STEP(F, d, a, b, c, SET(1), 0xe8c7b756, 12) + STEP(F, c, d, a, b, SET(2), 0x242070db, 17) + STEP(F, b, c, d, a, SET(3), 0xc1bdceee, 22) + STEP(F, a, b, c, d, SET(4), 0xf57c0faf, 7) + STEP(F, d, a, b, c, SET(5), 0x4787c62a, 12) + STEP(F, c, d, a, b, SET(6), 0xa8304613, 17) + STEP(F, b, c, d, a, SET(7), 0xfd469501, 22) + STEP(F, a, b, c, d, SET(8), 0x698098d8, 7) + STEP(F, d, a, b, c, SET(9), 0x8b44f7af, 12) + STEP(F, c, d, a, b, SET(10), 0xffff5bb1, 17) + STEP(F, b, c, d, a, SET(11), 0x895cd7be, 22) + STEP(F, a, b, c, d, SET(12), 0x6b901122, 7) + STEP(F, d, a, b, c, SET(13), 0xfd987193, 12) + STEP(F, c, d, a, b, SET(14), 0xa679438e, 17) + STEP(F, b, c, d, a, SET(15), 0x49b40821, 22) + + // Round 2 + STEP(G, a, b, c, d, GET(1), 0xf61e2562, 5) + STEP(G, d, a, b, c, GET(6), 0xc040b340, 9) + STEP(G, c, d, a, b, GET(11), 0x265e5a51, 14) + STEP(G, b, c, d, a, GET(0), 0xe9b6c7aa, 20) + STEP(G, a, b, c, d, GET(5), 0xd62f105d, 5) + STEP(G, d, a, b, c, GET(10), 0x02441453, 9) + STEP(G, c, d, a, b, GET(15), 0xd8a1e681, 14) + STEP(G, b, c, d, a, GET(4), 0xe7d3fbc8, 20) + STEP(G, a, b, c, d, GET(9), 0x21e1cde6, 5) + STEP(G, d, a, b, c, GET(14), 0xc33707d6, 9) + STEP(G, c, d, a, b, GET(3), 0xf4d50d87, 14) + STEP(G, b, c, d, a, GET(8), 0x455a14ed, 20) + STEP(G, a, b, c, d, GET(13), 0xa9e3e905, 5) + STEP(G, d, a, b, c, GET(2), 0xfcefa3f8, 9) + STEP(G, c, d, a, b, GET(7), 0x676f02d9, 14) + STEP(G, b, c, d, a, GET(12), 0x8d2a4c8a, 20) + + // Round 3 + STEP(H, a, b, c, d, GET(5), 0xfffa3942, 4) + STEP(H, d, a, b, c, GET(8), 0x8771f681, 11) + STEP(H, c, d, a, b, GET(11), 0x6d9d6122, 16) + STEP(H, b, c, d, a, GET(14), 0xfde5380c, 23) + STEP(H, a, b, c, d, GET(1), 0xa4beea44, 4) + STEP(H, d, a, b, c, GET(4), 0x4bdecfa9, 11) + STEP(H, c, d, a, b, GET(7), 0xf6bb4b60, 16) + STEP(H, b, c, d, a, GET(10), 0xbebfbc70, 23) + STEP(H, a, b, c, d, GET(13), 0x289b7ec6, 4) + STEP(H, d, a, b, c, GET(0), 0xeaa127fa, 11) + STEP(H, c, d, a, b, GET(3), 0xd4ef3085, 16) + STEP(H, b, c, d, a, GET(6), 0x04881d05, 23) + STEP(H, a, b, c, d, GET(9), 0xd9d4d039, 4) + STEP(H, d, a, b, c, GET(12), 0xe6db99e5, 11) + STEP(H, c, d, a, b, GET(15), 0x1fa27cf8, 16) + STEP(H, b, c, d, a, GET(2), 0xc4ac5665, 23) + + // Round 4 + STEP(I, a, b, c, d, GET(0), 0xf4292244, 6) + STEP(I, d, a, b, c, GET(7), 0x432aff97, 10) + STEP(I, c, d, a, b, GET(14), 0xab9423a7, 15) + STEP(I, b, c, d, a, GET(5), 0xfc93a039, 21) + STEP(I, a, b, c, d, GET(12), 0x655b59c3, 6) + STEP(I, d, a, b, c, GET(3), 0x8f0ccc92, 10) + STEP(I, c, d, a, b, GET(10), 0xffeff47d, 15) + STEP(I, b, c, d, a, GET(1), 0x85845dd1, 21) + STEP(I, a, b, c, d, GET(8), 0x6fa87e4f, 6) + STEP(I, d, a, b, c, GET(15), 0xfe2ce6e0, 10) + STEP(I, c, d, a, b, GET(6), 0xa3014314, 15) + STEP(I, b, c, d, a, GET(13), 0x4e0811a1, 21) + STEP(I, a, b, c, d, GET(4), 0xf7537e82, 6) + STEP(I, d, a, b, c, GET(11), 0xbd3af235, 10) + STEP(I, c, d, a, b, GET(2), 0x2ad7d2bb, 15) + STEP(I, b, c, d, a, GET(9), 0xeb86d391, 21) + + a += saved_a; + b += saved_b; + c += saved_c; + d += saved_d; + + ptr += 64; + } while (Size -= 64); + + this->a = a; + this->b = b; + this->c = c; + this->d = d; + + return ptr; +} + +MD5::MD5() + : a(0x67452301), b(0xefcdab89), c(0x98badcfe), d(0x10325476), hi(0), lo(0) { +} + +/// Incrementally add the bytes in \p Data to the hash. +void MD5::update(ArrayRef<uint8_t> Data) { + MD5_u32plus saved_lo; + unsigned long used, free; + const uint8_t *Ptr = Data.data(); + unsigned long Size = Data.size(); + + saved_lo = lo; + if ((lo = (saved_lo + Size) & 0x1fffffff) < saved_lo) + hi++; + hi += Size >> 29; + + used = saved_lo & 0x3f; + + if (used) { + free = 64 - used; + + if (Size < free) { + memcpy(&buffer[used], Ptr, Size); + return; + } + + memcpy(&buffer[used], Ptr, free); + Ptr = Ptr + free; + Size -= free; + body(ArrayRef<uint8_t>(buffer, 64)); + } + + if (Size >= 64) { + Ptr = body(ArrayRef<uint8_t>(Ptr, Size & ~(unsigned long) 0x3f)); + Size &= 0x3f; + } + + memcpy(buffer, Ptr, Size); +} + +/// Add the bytes in the StringRef \p Str to the hash. +// Note that this isn't a string and so this won't include any trailing NULL +// bytes. +void MD5::update(StringRef Str) { + ArrayRef<uint8_t> SVal((const uint8_t *)Str.data(), Str.size()); + update(SVal); +} + +/// \brief Finish the hash and place the resulting hash into \p result. +/// \param result is assumed to be a minimum of 16-bytes in size. +void MD5::final(MD5Result &result) { + unsigned long used, free; + + used = lo & 0x3f; + + buffer[used++] = 0x80; + + free = 64 - used; + + if (free < 8) { + memset(&buffer[used], 0, free); + body(ArrayRef<uint8_t>(buffer, 64)); + used = 0; + free = 64; + } + + memset(&buffer[used], 0, free - 8); + + lo <<= 3; + buffer[56] = lo; + buffer[57] = lo >> 8; + buffer[58] = lo >> 16; + buffer[59] = lo >> 24; + buffer[60] = hi; + buffer[61] = hi >> 8; + buffer[62] = hi >> 16; + buffer[63] = hi >> 24; + + body(ArrayRef<uint8_t>(buffer, 64)); + + result[0] = a; + result[1] = a >> 8; + result[2] = a >> 16; + result[3] = a >> 24; + result[4] = b; + result[5] = b >> 8; + result[6] = b >> 16; + result[7] = b >> 24; + result[8] = c; + result[9] = c >> 8; + result[10] = c >> 16; + result[11] = c >> 24; + result[12] = d; + result[13] = d >> 8; + result[14] = d >> 16; + result[15] = d >> 24; +} + +void MD5::stringifyResult(MD5Result &result, SmallString<32> &Str) { + raw_svector_ostream Res(Str); + for (int i = 0; i < 16; ++i) + Res << format("%.2x", result[i]); +} + +} diff --git a/contrib/llvm/lib/Support/MemoryBuffer.cpp b/contrib/llvm/lib/Support/MemoryBuffer.cpp index 7c5ab96..dcd5529 100644 --- a/contrib/llvm/lib/Support/MemoryBuffer.cpp +++ b/contrib/llvm/lib/Support/MemoryBuffer.cpp @@ -33,8 +33,7 @@ #include <unistd.h> #else #include <io.h> -// Simplistic definitinos of these macros to allow files to be read with -// MapInFilePages. +// Simplistic definitinos of these macros for use in getOpenFile. #ifndef S_ISREG #define S_ISREG(x) (1) #endif @@ -42,7 +41,6 @@ #define S_ISBLK(x) (0) #endif #endif -#include <fcntl.h> using namespace llvm; //===----------------------------------------------------------------------===// @@ -174,20 +172,12 @@ error_code MemoryBuffer::getFileOrSTDIN(StringRef Filename, return getFile(Filename, result, FileSize); } -error_code MemoryBuffer::getFileOrSTDIN(const char *Filename, - OwningPtr<MemoryBuffer> &result, - int64_t FileSize) { - if (strcmp(Filename, "-") == 0) - return getSTDIN(result); - return getFile(Filename, result, FileSize); -} - //===----------------------------------------------------------------------===// // MemoryBuffer::getFile implementation. //===----------------------------------------------------------------------===// namespace { -/// \brief Memorry maps a file descriptor using sys::fs::mapped_file_region. +/// \brief Memory maps a file descriptor using sys::fs::mapped_file_region. /// /// This handles converting the offset into a legal offset on the platform. class MemoryBufferMMapFile : public MemoryBuffer { @@ -227,7 +217,7 @@ public: }; } -static error_code getMemoryBufferForStream(int FD, +static error_code getMemoryBufferForStream(int FD, StringRef BufferName, OwningPtr<MemoryBuffer> &result) { const ssize_t ChunkSize = 4096*4; @@ -248,41 +238,36 @@ static error_code getMemoryBufferForStream(int FD, return error_code::success(); } -error_code MemoryBuffer::getFile(StringRef Filename, +static error_code getFileAux(const char *Filename, + OwningPtr<MemoryBuffer> &result, int64_t FileSize, + bool RequiresNullTerminator); + +error_code MemoryBuffer::getFile(Twine Filename, OwningPtr<MemoryBuffer> &result, int64_t FileSize, bool RequiresNullTerminator) { // Ensure the path is null terminated. - SmallString<256> PathBuf(Filename.begin(), Filename.end()); - return MemoryBuffer::getFile(PathBuf.c_str(), result, FileSize, - RequiresNullTerminator); + SmallString<256> PathBuf; + StringRef NullTerminatedName = Filename.toNullTerminatedStringRef(PathBuf); + return getFileAux(NullTerminatedName.data(), result, FileSize, + RequiresNullTerminator); } -error_code MemoryBuffer::getFile(const char *Filename, - OwningPtr<MemoryBuffer> &result, - int64_t FileSize, - bool RequiresNullTerminator) { - // FIXME: Review if this check is unnecessary on windows as well. -#ifdef LLVM_ON_WIN32 - // First check that the "file" is not a directory - bool is_dir = false; - error_code err = sys::fs::is_directory(Filename, is_dir); - if (err) - return err; - if (is_dir) - return make_error_code(errc::is_a_directory); -#endif - - int OpenFlags = O_RDONLY; -#ifdef O_BINARY - OpenFlags |= O_BINARY; // Open input file in binary mode on win32. -#endif - int FD = ::open(Filename, OpenFlags); - if (FD == -1) - return error_code(errno, posix_category()); - - error_code ret = getOpenFile(FD, Filename, result, FileSize, FileSize, - 0, RequiresNullTerminator); +static error_code getOpenFileImpl(int FD, const char *Filename, + OwningPtr<MemoryBuffer> &Result, + uint64_t FileSize, uint64_t MapSize, + int64_t Offset, bool RequiresNullTerminator); + +static error_code getFileAux(const char *Filename, + OwningPtr<MemoryBuffer> &result, int64_t FileSize, + bool RequiresNullTerminator) { + int FD; + error_code EC = sys::fs::openFileForRead(Filename, FD); + if (EC) + return EC; + + error_code ret = getOpenFileImpl(FD, Filename, result, FileSize, FileSize, 0, + RequiresNullTerminator); close(FD); return ret; } @@ -295,7 +280,7 @@ static bool shouldUseMmap(int FD, int PageSize) { // We don't use mmap for small files because this can severely fragment our // address space. - if (MapSize < 4096*4) + if (MapSize < 4 * 4096 || MapSize < (unsigned)PageSize) return false; if (!RequiresNullTerminator) @@ -307,12 +292,11 @@ static bool shouldUseMmap(int FD, // FIXME: this chunk of code is duplicated, but it avoids a fstat when // RequiresNullTerminator = false and MapSize != -1. if (FileSize == size_t(-1)) { - struct stat FileInfo; - // TODO: This should use fstat64 when available. - if (fstat(FD, &FileInfo) == -1) { - return error_code(errno, posix_category()); - } - FileSize = FileInfo.st_size; + sys::fs::file_status Status; + error_code EC = sys::fs::status(FD, Status); + if (EC) + return EC; + FileSize = Status.getSize(); } // If we need a null terminator and the end of the map is inside the file, @@ -322,6 +306,15 @@ static bool shouldUseMmap(int FD, if (End != FileSize) return false; +#if defined(_WIN32) || defined(__CYGWIN__) + // Don't peek the next page if file is multiple of *physical* pagesize(4k) + // but is not multiple of AllocationGranularity(64k), + // when a null terminator is required. + // FIXME: It's not good to hardcode 4096 here. dwPageSize shows 4096. + if ((FileSize & (4096 - 1)) == 0) + return false; +#endif + // Don't try to map files that are exactly a multiple of the system page size // if we need a null terminator. if ((FileSize & (PageSize -1)) == 0) @@ -330,11 +323,10 @@ static bool shouldUseMmap(int FD, return true; } -error_code MemoryBuffer::getOpenFile(int FD, const char *Filename, - OwningPtr<MemoryBuffer> &result, - uint64_t FileSize, uint64_t MapSize, - int64_t Offset, - bool RequiresNullTerminator) { +static error_code getOpenFileImpl(int FD, const char *Filename, + OwningPtr<MemoryBuffer> &result, + uint64_t FileSize, uint64_t MapSize, + int64_t Offset, bool RequiresNullTerminator) { static int PageSize = sys::process::get_self()->page_size(); // Default is to map the full file. @@ -342,20 +334,20 @@ error_code MemoryBuffer::getOpenFile(int FD, const char *Filename, // If we don't know the file size, use fstat to find out. fstat on an open // file descriptor is cheaper than stat on a random path. if (FileSize == uint64_t(-1)) { - struct stat FileInfo; - // TODO: This should use fstat64 when available. - if (fstat(FD, &FileInfo) == -1) { - return error_code(errno, posix_category()); - } + sys::fs::file_status Status; + error_code EC = sys::fs::status(FD, Status); + if (EC) + return EC; // If this not a file or a block device (e.g. it's a named pipe // or character device), we can't trust the size. Create the memory // buffer by copying off the stream. - if (!S_ISREG(FileInfo.st_mode) && !S_ISBLK(FileInfo.st_mode)) { + sys::fs::file_type Type = Status.type(); + if (Type != sys::fs::file_type::regular_file && + Type != sys::fs::file_type::block_file) return getMemoryBufferForStream(FD, Filename, result); - } - FileSize = FileInfo.st_size; + FileSize = Status.getSize(); } MapSize = FileSize; } @@ -411,6 +403,20 @@ error_code MemoryBuffer::getOpenFile(int FD, const char *Filename, return error_code::success(); } +error_code MemoryBuffer::getOpenFile(int FD, const char *Filename, + OwningPtr<MemoryBuffer> &Result, + uint64_t FileSize, + bool RequiresNullTerminator) { + return getOpenFileImpl(FD, Filename, Result, FileSize, FileSize, 0, + RequiresNullTerminator); +} + +error_code MemoryBuffer::getOpenFileSlice(int FD, const char *Filename, + OwningPtr<MemoryBuffer> &Result, + uint64_t MapSize, int64_t Offset) { + return getOpenFileImpl(FD, Filename, Result, -1, MapSize, Offset, false); +} + //===----------------------------------------------------------------------===// // MemoryBuffer::getSTDIN implementation. //===----------------------------------------------------------------------===// @@ -420,7 +426,7 @@ error_code MemoryBuffer::getSTDIN(OwningPtr<MemoryBuffer> &result) { // // FIXME: That isn't necessarily true, we should try to mmap stdin and // fallback if it fails. - sys::Program::ChangeStdinToBinary(); + sys::ChangeStdinToBinary(); return getMemoryBufferForStream(0, "<stdin>", result); } diff --git a/contrib/llvm/lib/Support/MemoryObject.cpp b/contrib/llvm/lib/Support/MemoryObject.cpp index b20ab89..02b5b50 100644 --- a/contrib/llvm/lib/Support/MemoryObject.cpp +++ b/contrib/llvm/lib/Support/MemoryObject.cpp @@ -15,8 +15,7 @@ MemoryObject::~MemoryObject() { int MemoryObject::readBytes(uint64_t address, uint64_t size, - uint8_t* buf, - uint64_t* copied) const { + uint8_t* buf) const { uint64_t current = address; uint64_t limit = getBase() + getExtent(); @@ -30,8 +29,5 @@ int MemoryObject::readBytes(uint64_t address, current++; } - if (copied) - *copied = current - address; - return 0; } diff --git a/contrib/llvm/lib/Support/Path.cpp b/contrib/llvm/lib/Support/Path.cpp index d070375..c869b30 100644 --- a/contrib/llvm/lib/Support/Path.cpp +++ b/contrib/llvm/lib/Support/Path.cpp @@ -1,4 +1,4 @@ -//===-- Path.cpp - Implement OS Path Concept --------------------*- C++ -*-===// +//===-- Path.cpp - Implement OS Path Concept ------------------------------===// // // The LLVM Compiler Infrastructure // @@ -7,80 +7,900 @@ // //===----------------------------------------------------------------------===// // -// This header file implements the operating system Path concept. +// This file implements the operating system Path API. // //===----------------------------------------------------------------------===// #include "llvm/Support/Path.h" -#include "llvm/Config/config.h" #include "llvm/Support/Endian.h" +#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FileSystem.h" -#include <cassert> +#include <cctype> +#include <cstdio> #include <cstring> -#include <ostream> -using namespace llvm; -using namespace sys; +#include <fcntl.h> + +#if !defined(_MSC_VER) && !defined(__MINGW32__) +#include <unistd.h> +#else +#include <io.h> +#endif + namespace { -using support::ulittle32_t; + using llvm::StringRef; + using llvm::sys::path::is_separator; + +#ifdef LLVM_ON_WIN32 + const char *separators = "\\/"; + const char prefered_separator = '\\'; +#else + const char separators = '/'; + const char prefered_separator = '/'; +#endif + + StringRef find_first_component(StringRef path) { + // Look for this first component in the following order. + // * empty (in this case we return an empty string) + // * either C: or {//,\\}net. + // * {/,\} + // * {.,..} + // * {file,directory}name + + if (path.empty()) + return path; + +#ifdef LLVM_ON_WIN32 + // C: + if (path.size() >= 2 && std::isalpha(static_cast<unsigned char>(path[0])) && + path[1] == ':') + return path.substr(0, 2); +#endif + + // //net + if ((path.size() > 2) && + is_separator(path[0]) && + path[0] == path[1] && + !is_separator(path[2])) { + // Find the next directory separator. + size_t end = path.find_first_of(separators, 2); + return path.substr(0, end); + } + + // {/,\} + if (is_separator(path[0])) + return path.substr(0, 1); + + if (path.startswith("..")) + return path.substr(0, 2); + + if (path[0] == '.') + return path.substr(0, 1); + + // * {file,directory}name + size_t end = path.find_first_of(separators); + return path.substr(0, end); + } + + size_t filename_pos(StringRef str) { + if (str.size() == 2 && + is_separator(str[0]) && + str[0] == str[1]) + return 0; + + if (str.size() > 0 && is_separator(str[str.size() - 1])) + return str.size() - 1; + + size_t pos = str.find_last_of(separators, str.size() - 1); + +#ifdef LLVM_ON_WIN32 + if (pos == StringRef::npos) + pos = str.find_last_of(':', str.size() - 2); +#endif + + if (pos == StringRef::npos || + (pos == 1 && is_separator(str[0]))) + return 0; + + return pos + 1; + } + + size_t root_dir_start(StringRef str) { + // case "c:/" +#ifdef LLVM_ON_WIN32 + if (str.size() > 2 && + str[1] == ':' && + is_separator(str[2])) + return 2; +#endif + + // case "//" + if (str.size() == 2 && + is_separator(str[0]) && + str[0] == str[1]) + return StringRef::npos; + + // case "//net" + if (str.size() > 3 && + is_separator(str[0]) && + str[0] == str[1] && + !is_separator(str[2])) { + return str.find_first_of(separators, 2); + } + + // case "/" + if (str.size() > 0 && is_separator(str[0])) + return 0; + + return StringRef::npos; + } + + size_t parent_path_end(StringRef path) { + size_t end_pos = filename_pos(path); + + bool filename_was_sep = path.size() > 0 && is_separator(path[end_pos]); + + // Skip separators except for root dir. + size_t root_dir_pos = root_dir_start(path.substr(0, end_pos)); + + while(end_pos > 0 && + (end_pos - 1) != root_dir_pos && + is_separator(path[end_pos - 1])) + --end_pos; + + if (end_pos == 1 && root_dir_pos == 0 && filename_was_sep) + return StringRef::npos; + + return end_pos; + } +} // end unnamed namespace + +enum FSEntity { + FS_Dir, + FS_File, + FS_Name +}; + +// Implemented in Unix/Path.inc and Windows/Path.inc. +static llvm::error_code +createUniqueEntity(const llvm::Twine &Model, int &ResultFD, + llvm::SmallVectorImpl<char> &ResultPath, + bool MakeAbsolute, unsigned Mode, FSEntity Type); + +namespace llvm { +namespace sys { +namespace path { + +const_iterator begin(StringRef path) { + const_iterator i; + i.Path = path; + i.Component = find_first_component(path); + i.Position = 0; + return i; } -//===----------------------------------------------------------------------===// -//=== WARNING: Implementation here must contain only TRULY operating system -//=== independent code. -//===----------------------------------------------------------------------===// +const_iterator end(StringRef path) { + const_iterator i; + i.Path = path; + i.Position = path.size(); + return i; +} + +const_iterator &const_iterator::operator++() { + assert(Position < Path.size() && "Tried to increment past end!"); + + // Increment Position to past the current component + Position += Component.size(); + + // Check for end. + if (Position == Path.size()) { + Component = StringRef(); + return *this; + } + + // Both POSIX and Windows treat paths that begin with exactly two separators + // specially. + bool was_net = Component.size() > 2 && + is_separator(Component[0]) && + Component[1] == Component[0] && + !is_separator(Component[2]); + + // Handle separators. + if (is_separator(Path[Position])) { + // Root dir. + if (was_net +#ifdef LLVM_ON_WIN32 + // c:/ + || Component.endswith(":") +#endif + ) { + Component = Path.substr(Position, 1); + return *this; + } + + // Skip extra separators. + while (Position != Path.size() && + is_separator(Path[Position])) { + ++Position; + } + + // Treat trailing '/' as a '.'. + if (Position == Path.size()) { + --Position; + Component = "."; + return *this; + } + } + + // Find next component. + size_t end_pos = Path.find_first_of(separators, Position); + Component = Path.slice(Position, end_pos); + + return *this; +} + +const_iterator &const_iterator::operator--() { + // If we're at the end and the previous char was a '/', return '.'. + if (Position == Path.size() && + Path.size() > 1 && + is_separator(Path[Position - 1]) +#ifdef LLVM_ON_WIN32 + && Path[Position - 2] != ':' +#endif + ) { + --Position; + Component = "."; + return *this; + } + + // Skip separators unless it's the root directory. + size_t root_dir_pos = root_dir_start(Path); + size_t end_pos = Position; + + while(end_pos > 0 && + (end_pos - 1) != root_dir_pos && + is_separator(Path[end_pos - 1])) + --end_pos; + + // Find next separator. + size_t start_pos = filename_pos(Path.substr(0, end_pos)); + Component = Path.slice(start_pos, end_pos); + Position = start_pos; + return *this; +} + +bool const_iterator::operator==(const const_iterator &RHS) const { + return Path.begin() == RHS.Path.begin() && + Position == RHS.Position; +} + +bool const_iterator::operator!=(const const_iterator &RHS) const { + return !(*this == RHS); +} + +ptrdiff_t const_iterator::operator-(const const_iterator &RHS) const { + return Position - RHS.Position; +} + +const StringRef root_path(StringRef path) { + const_iterator b = begin(path), + pos = b, + e = end(path); + if (b != e) { + bool has_net = b->size() > 2 && is_separator((*b)[0]) && (*b)[1] == (*b)[0]; + bool has_drive = +#ifdef LLVM_ON_WIN32 + b->endswith(":"); +#else + false; +#endif + + if (has_net || has_drive) { + if ((++pos != e) && is_separator((*pos)[0])) { + // {C:/,//net/}, so get the first two components. + return path.substr(0, b->size() + pos->size()); + } else { + // just {C:,//net}, return the first component. + return *b; + } + } + + // POSIX style root directory. + if (is_separator((*b)[0])) { + return *b; + } + } + + return StringRef(); +} + +const StringRef root_name(StringRef path) { + const_iterator b = begin(path), + e = end(path); + if (b != e) { + bool has_net = b->size() > 2 && is_separator((*b)[0]) && (*b)[1] == (*b)[0]; + bool has_drive = +#ifdef LLVM_ON_WIN32 + b->endswith(":"); +#else + false; +#endif + + if (has_net || has_drive) { + // just {C:,//net}, return the first component. + return *b; + } + } + + // No path or no name. + return StringRef(); +} + +const StringRef root_directory(StringRef path) { + const_iterator b = begin(path), + pos = b, + e = end(path); + if (b != e) { + bool has_net = b->size() > 2 && is_separator((*b)[0]) && (*b)[1] == (*b)[0]; + bool has_drive = +#ifdef LLVM_ON_WIN32 + b->endswith(":"); +#else + false; +#endif + + if ((has_net || has_drive) && + // {C:,//net}, skip to the next component. + (++pos != e) && is_separator((*pos)[0])) { + return *pos; + } + + // POSIX style root directory. + if (!has_net && is_separator((*b)[0])) { + return *b; + } + } + + // No path or no root. + return StringRef(); +} + +const StringRef relative_path(StringRef path) { + StringRef root = root_path(path); + return path.substr(root.size()); +} + +void append(SmallVectorImpl<char> &path, const Twine &a, + const Twine &b, + const Twine &c, + const Twine &d) { + SmallString<32> a_storage; + SmallString<32> b_storage; + SmallString<32> c_storage; + SmallString<32> d_storage; + + SmallVector<StringRef, 4> components; + if (!a.isTriviallyEmpty()) components.push_back(a.toStringRef(a_storage)); + if (!b.isTriviallyEmpty()) components.push_back(b.toStringRef(b_storage)); + if (!c.isTriviallyEmpty()) components.push_back(c.toStringRef(c_storage)); + if (!d.isTriviallyEmpty()) components.push_back(d.toStringRef(d_storage)); + + for (SmallVectorImpl<StringRef>::const_iterator i = components.begin(), + e = components.end(); + i != e; ++i) { + bool path_has_sep = !path.empty() && is_separator(path[path.size() - 1]); + bool component_has_sep = !i->empty() && is_separator((*i)[0]); + bool is_root_name = has_root_name(*i); + + if (path_has_sep) { + // Strip separators from beginning of component. + size_t loc = i->find_first_not_of(separators); + StringRef c = i->substr(loc); + + // Append it. + path.append(c.begin(), c.end()); + continue; + } + + if (!component_has_sep && !(path.empty() || is_root_name)) { + // Add a separator. + path.push_back(prefered_separator); + } + + path.append(i->begin(), i->end()); + } +} + +void append(SmallVectorImpl<char> &path, + const_iterator begin, const_iterator end) { + for (; begin != end; ++begin) + path::append(path, *begin); +} + +const StringRef parent_path(StringRef path) { + size_t end_pos = parent_path_end(path); + if (end_pos == StringRef::npos) + return StringRef(); + else + return path.substr(0, end_pos); +} + +void remove_filename(SmallVectorImpl<char> &path) { + size_t end_pos = parent_path_end(StringRef(path.begin(), path.size())); + if (end_pos != StringRef::npos) + path.set_size(end_pos); +} + +void replace_extension(SmallVectorImpl<char> &path, const Twine &extension) { + StringRef p(path.begin(), path.size()); + SmallString<32> ext_storage; + StringRef ext = extension.toStringRef(ext_storage); + + // Erase existing extension. + size_t pos = p.find_last_of('.'); + if (pos != StringRef::npos && pos >= filename_pos(p)) + path.set_size(pos); -bool Path::operator==(const Path &that) const { - return path == that.path; + // Append '.' if needed. + if (ext.size() > 0 && ext[0] != '.') + path.push_back('.'); + + // Append extension. + path.append(ext.begin(), ext.end()); +} + +void native(const Twine &path, SmallVectorImpl<char> &result) { + assert((!path.isSingleStringRef() || + path.getSingleStringRef().data() != result.data()) && + "path and result are not allowed to overlap!"); + // Clear result. + result.clear(); + path.toVector(result); + native(result); +} + +void native(SmallVectorImpl<char> &path) { +#ifdef LLVM_ON_WIN32 + std::replace(path.begin(), path.end(), '/', '\\'); +#endif } -bool Path::operator<(const Path& that) const { - return path < that.path; +const StringRef filename(StringRef path) { + return *(--end(path)); } -LLVMFileType -sys::IdentifyFileType(const char *magic, unsigned length) { - assert(magic && "Invalid magic number string"); - assert(length >=4 && "Invalid magic number length"); - switch ((unsigned char)magic[0]) { +const StringRef stem(StringRef path) { + StringRef fname = filename(path); + size_t pos = fname.find_last_of('.'); + if (pos == StringRef::npos) + return fname; + else + if ((fname.size() == 1 && fname == ".") || + (fname.size() == 2 && fname == "..")) + return fname; + else + return fname.substr(0, pos); +} + +const StringRef extension(StringRef path) { + StringRef fname = filename(path); + size_t pos = fname.find_last_of('.'); + if (pos == StringRef::npos) + return StringRef(); + else + if ((fname.size() == 1 && fname == ".") || + (fname.size() == 2 && fname == "..")) + return StringRef(); + else + return fname.substr(pos); +} + +bool is_separator(char value) { + switch(value) { +#ifdef LLVM_ON_WIN32 + case '\\': // fall through +#endif + case '/': return true; + default: return false; + } +} + +void system_temp_directory(bool erasedOnReboot, SmallVectorImpl<char> &result) { + result.clear(); + +#ifdef __APPLE__ + // On Darwin, use DARWIN_USER_TEMP_DIR or DARWIN_USER_CACHE_DIR. + int ConfName = erasedOnReboot? _CS_DARWIN_USER_TEMP_DIR + : _CS_DARWIN_USER_CACHE_DIR; + size_t ConfLen = confstr(ConfName, 0, 0); + if (ConfLen > 0) { + do { + result.resize(ConfLen); + ConfLen = confstr(ConfName, result.data(), result.size()); + } while (ConfLen > 0 && ConfLen != result.size()); + + if (ConfLen > 0) { + assert(result.back() == 0); + result.pop_back(); + return; + } + + result.clear(); + } +#endif + + // Check whether the temporary directory is specified by an environment + // variable. + const char *EnvironmentVariable; +#ifdef LLVM_ON_WIN32 + EnvironmentVariable = "TEMP"; +#else + EnvironmentVariable = "TMPDIR"; +#endif + if (char *RequestedDir = getenv(EnvironmentVariable)) { + result.append(RequestedDir, RequestedDir + strlen(RequestedDir)); + return; + } + + // Fall back to a system default. + const char *DefaultResult; +#ifdef LLVM_ON_WIN32 + (void)erasedOnReboot; + DefaultResult = "C:\\TEMP"; +#else + if (erasedOnReboot) + DefaultResult = "/tmp"; + else + DefaultResult = "/var/tmp"; +#endif + result.append(DefaultResult, DefaultResult + strlen(DefaultResult)); +} + +bool has_root_name(const Twine &path) { + SmallString<128> path_storage; + StringRef p = path.toStringRef(path_storage); + + return !root_name(p).empty(); +} + +bool has_root_directory(const Twine &path) { + SmallString<128> path_storage; + StringRef p = path.toStringRef(path_storage); + + return !root_directory(p).empty(); +} + +bool has_root_path(const Twine &path) { + SmallString<128> path_storage; + StringRef p = path.toStringRef(path_storage); + + return !root_path(p).empty(); +} + +bool has_relative_path(const Twine &path) { + SmallString<128> path_storage; + StringRef p = path.toStringRef(path_storage); + + return !relative_path(p).empty(); +} + +bool has_filename(const Twine &path) { + SmallString<128> path_storage; + StringRef p = path.toStringRef(path_storage); + + return !filename(p).empty(); +} + +bool has_parent_path(const Twine &path) { + SmallString<128> path_storage; + StringRef p = path.toStringRef(path_storage); + + return !parent_path(p).empty(); +} + +bool has_stem(const Twine &path) { + SmallString<128> path_storage; + StringRef p = path.toStringRef(path_storage); + + return !stem(p).empty(); +} + +bool has_extension(const Twine &path) { + SmallString<128> path_storage; + StringRef p = path.toStringRef(path_storage); + + return !extension(p).empty(); +} + +bool is_absolute(const Twine &path) { + SmallString<128> path_storage; + StringRef p = path.toStringRef(path_storage); + + bool rootDir = has_root_directory(p), +#ifdef LLVM_ON_WIN32 + rootName = has_root_name(p); +#else + rootName = true; +#endif + + return rootDir && rootName; +} + +bool is_relative(const Twine &path) { + return !is_absolute(path); +} + +} // end namespace path + +namespace fs { + +error_code getUniqueID(const Twine Path, UniqueID &Result) { + file_status Status; + error_code EC = status(Path, Status); + if (EC) + return EC; + Result = Status.getUniqueID(); + return error_code::success(); +} + +error_code createUniqueFile(const Twine &Model, int &ResultFd, + SmallVectorImpl<char> &ResultPath, unsigned Mode) { + return createUniqueEntity(Model, ResultFd, ResultPath, false, Mode, FS_File); +} + +error_code createUniqueFile(const Twine &Model, + SmallVectorImpl<char> &ResultPath) { + int Dummy; + return createUniqueEntity(Model, Dummy, ResultPath, false, 0, FS_Name); +} + +static error_code createTemporaryFile(const Twine &Model, int &ResultFD, + llvm::SmallVectorImpl<char> &ResultPath, + FSEntity Type) { + SmallString<128> Storage; + StringRef P = Model.toNullTerminatedStringRef(Storage); + assert(P.find_first_of(separators) == StringRef::npos && + "Model must be a simple filename."); + // Use P.begin() so that createUniqueEntity doesn't need to recreate Storage. + return createUniqueEntity(P.begin(), ResultFD, ResultPath, + true, owner_read | owner_write, Type); +} + +static error_code +createTemporaryFile(const Twine &Prefix, StringRef Suffix, int &ResultFD, + llvm::SmallVectorImpl<char> &ResultPath, + FSEntity Type) { + const char *Middle = Suffix.empty() ? "-%%%%%%" : "-%%%%%%."; + return createTemporaryFile(Prefix + Middle + Suffix, ResultFD, ResultPath, + Type); +} + + +error_code createTemporaryFile(const Twine &Prefix, StringRef Suffix, + int &ResultFD, + SmallVectorImpl<char> &ResultPath) { + return createTemporaryFile(Prefix, Suffix, ResultFD, ResultPath, FS_File); +} + +error_code createTemporaryFile(const Twine &Prefix, StringRef Suffix, + SmallVectorImpl<char> &ResultPath) { + int Dummy; + return createTemporaryFile(Prefix, Suffix, Dummy, ResultPath, FS_Name); +} + + +// This is a mkdtemp with a different pattern. We use createUniqueEntity mostly +// for consistency. We should try using mkdtemp. +error_code createUniqueDirectory(const Twine &Prefix, + SmallVectorImpl<char> &ResultPath) { + int Dummy; + return createUniqueEntity(Prefix + "-%%%%%%", Dummy, ResultPath, + true, 0, FS_Dir); +} + +error_code make_absolute(SmallVectorImpl<char> &path) { + StringRef p(path.data(), path.size()); + + bool rootDirectory = path::has_root_directory(p), +#ifdef LLVM_ON_WIN32 + rootName = path::has_root_name(p); +#else + rootName = true; +#endif + + // Already absolute. + if (rootName && rootDirectory) + return error_code::success(); + + // All of the following conditions will need the current directory. + SmallString<128> current_dir; + if (error_code ec = current_path(current_dir)) return ec; + + // Relative path. Prepend the current directory. + if (!rootName && !rootDirectory) { + // Append path to the current directory. + path::append(current_dir, p); + // Set path to the result. + path.swap(current_dir); + return error_code::success(); + } + + if (!rootName && rootDirectory) { + StringRef cdrn = path::root_name(current_dir); + SmallString<128> curDirRootName(cdrn.begin(), cdrn.end()); + path::append(curDirRootName, p); + // Set path to the result. + path.swap(curDirRootName); + return error_code::success(); + } + + if (rootName && !rootDirectory) { + StringRef pRootName = path::root_name(p); + StringRef bRootDirectory = path::root_directory(current_dir); + StringRef bRelativePath = path::relative_path(current_dir); + StringRef pRelativePath = path::relative_path(p); + + SmallString<128> res; + path::append(res, pRootName, bRootDirectory, bRelativePath, pRelativePath); + path.swap(res); + return error_code::success(); + } + + llvm_unreachable("All rootName and rootDirectory combinations should have " + "occurred above!"); +} + +error_code create_directories(const Twine &path, bool &existed) { + SmallString<128> path_storage; + StringRef p = path.toStringRef(path_storage); + + StringRef parent = path::parent_path(p); + if (!parent.empty()) { + bool parent_exists; + if (error_code ec = fs::exists(parent, parent_exists)) return ec; + + if (!parent_exists) + if (error_code ec = create_directories(parent, existed)) return ec; + } + + return create_directory(p, existed); +} + +bool exists(file_status status) { + return status_known(status) && status.type() != file_type::file_not_found; +} + +bool status_known(file_status s) { + return s.type() != file_type::status_error; +} + +bool is_directory(file_status status) { + return status.type() == file_type::directory_file; +} + +error_code is_directory(const Twine &path, bool &result) { + file_status st; + if (error_code ec = status(path, st)) + return ec; + result = is_directory(st); + return error_code::success(); +} + +bool is_regular_file(file_status status) { + return status.type() == file_type::regular_file; +} + +error_code is_regular_file(const Twine &path, bool &result) { + file_status st; + if (error_code ec = status(path, st)) + return ec; + result = is_regular_file(st); + return error_code::success(); +} + +bool is_symlink(file_status status) { + return status.type() == file_type::symlink_file; +} + +error_code is_symlink(const Twine &path, bool &result) { + file_status st; + if (error_code ec = status(path, st)) + return ec; + result = is_symlink(st); + return error_code::success(); +} + +bool is_other(file_status status) { + return exists(status) && + !is_regular_file(status) && + !is_directory(status) && + !is_symlink(status); +} + +void directory_entry::replace_filename(const Twine &filename, file_status st) { + SmallString<128> path(Path.begin(), Path.end()); + path::remove_filename(path); + path::append(path, filename); + Path = path.str(); + Status = st; +} + +error_code has_magic(const Twine &path, const Twine &magic, bool &result) { + SmallString<32> MagicStorage; + StringRef Magic = magic.toStringRef(MagicStorage); + SmallString<32> Buffer; + + if (error_code ec = get_magic(path, Magic.size(), Buffer)) { + if (ec == errc::value_too_large) { + // Magic.size() > file_size(Path). + result = false; + return error_code::success(); + } + return ec; + } + + result = Magic == Buffer; + return error_code::success(); +} + +/// @brief Identify the magic in magic. + file_magic identify_magic(StringRef Magic) { + if (Magic.size() < 4) + return file_magic::unknown; + switch ((unsigned char)Magic[0]) { + case 0x00: { + // COFF short import library file + if (Magic[1] == (char)0x00 && Magic[2] == (char)0xff && + Magic[3] == (char)0xff) + return file_magic::coff_import_library; + // Windows resource file + const char Expected[] = { 0, 0, 0, 0, '\x20', 0, 0, 0, '\xff' }; + if (Magic.size() >= sizeof(Expected) && + memcmp(Magic.data(), Expected, sizeof(Expected)) == 0) + return file_magic::windows_resource; + // 0x0000 = COFF unknown machine type + if (Magic[1] == 0) + return file_magic::coff_object; + break; + } case 0xDE: // 0x0B17C0DE = BC wraper - if (magic[1] == (char)0xC0 && magic[2] == (char)0x17 && - magic[3] == (char)0x0B) - return Bitcode_FileType; + if (Magic[1] == (char)0xC0 && Magic[2] == (char)0x17 && + Magic[3] == (char)0x0B) + return file_magic::bitcode; break; case 'B': - if (magic[1] == 'C' && magic[2] == (char)0xC0 && magic[3] == (char)0xDE) - return Bitcode_FileType; + if (Magic[1] == 'C' && Magic[2] == (char)0xC0 && Magic[3] == (char)0xDE) + return file_magic::bitcode; break; case '!': - if (length >= 8) - if (memcmp(magic,"!<arch>\n",8) == 0) - return Archive_FileType; + if (Magic.size() >= 8) + if (memcmp(Magic.data(),"!<arch>\n",8) == 0) + return file_magic::archive; break; case '\177': - if (magic[1] == 'E' && magic[2] == 'L' && magic[3] == 'F') { - bool Data2MSB = magic[5] == 2; + if (Magic.size() >= 18 && Magic[1] == 'E' && Magic[2] == 'L' && + Magic[3] == 'F') { + bool Data2MSB = Magic[5] == 2; unsigned high = Data2MSB ? 16 : 17; unsigned low = Data2MSB ? 17 : 16; - if (length >= 18 && magic[high] == 0) - switch (magic[low]) { + if (Magic[high] == 0) + switch (Magic[low]) { default: break; - case 1: return ELF_Relocatable_FileType; - case 2: return ELF_Executable_FileType; - case 3: return ELF_SharedObject_FileType; - case 4: return ELF_Core_FileType; + case 1: return file_magic::elf_relocatable; + case 2: return file_magic::elf_executable; + case 3: return file_magic::elf_shared_object; + case 4: return file_magic::elf_core; } } break; case 0xCA: - if (magic[1] == char(0xFE) && magic[2] == char(0xBA) && - magic[3] == char(0xBE)) { + if (Magic[1] == char(0xFE) && Magic[2] == char(0xBA) && + Magic[3] == char(0xBE)) { // This is complicated by an overlap with Java class files. // See the Mach-O section in /usr/share/file/magic for details. - if (length >= 8 && magic[7] < 43) - // FIXME: Universal Binary of any type. - return Mach_O_DynamicallyLinkedSharedLib_FileType; + if (Magic.size() >= 8 && Magic[7] < 43) + return file_magic::macho_universal_binary; } break; @@ -91,29 +911,29 @@ sys::IdentifyFileType(const char *magic, unsigned length) { case 0xCE: case 0xCF: { uint16_t type = 0; - if (magic[0] == char(0xFE) && magic[1] == char(0xED) && - magic[2] == char(0xFA) && - (magic[3] == char(0xCE) || magic[3] == char(0xCF))) { + if (Magic[0] == char(0xFE) && Magic[1] == char(0xED) && + Magic[2] == char(0xFA) && + (Magic[3] == char(0xCE) || Magic[3] == char(0xCF))) { /* Native endian */ - if (length >= 16) type = magic[14] << 8 | magic[15]; - } else if ((magic[0] == char(0xCE) || magic[0] == char(0xCF)) && - magic[1] == char(0xFA) && magic[2] == char(0xED) && - magic[3] == char(0xFE)) { + if (Magic.size() >= 16) type = Magic[14] << 8 | Magic[15]; + } else if ((Magic[0] == char(0xCE) || Magic[0] == char(0xCF)) && + Magic[1] == char(0xFA) && Magic[2] == char(0xED) && + Magic[3] == char(0xFE)) { /* Reverse endian */ - if (length >= 14) type = magic[13] << 8 | magic[12]; + if (Magic.size() >= 14) type = Magic[13] << 8 | Magic[12]; } switch (type) { default: break; - case 1: return Mach_O_Object_FileType; - case 2: return Mach_O_Executable_FileType; - case 3: return Mach_O_FixedVirtualMemorySharedLib_FileType; - case 4: return Mach_O_Core_FileType; - case 5: return Mach_O_PreloadExecutable_FileType; - case 6: return Mach_O_DynamicallyLinkedSharedLib_FileType; - case 7: return Mach_O_DynamicLinker_FileType; - case 8: return Mach_O_Bundle_FileType; - case 9: return Mach_O_DynamicallyLinkedSharedLibStub_FileType; - case 10: return Mach_O_DSYMCompanion_FileType; + case 1: return file_magic::macho_object; + case 2: return file_magic::macho_executable; + case 3: return file_magic::macho_fixed_virtual_memory_shared_lib; + case 4: return file_magic::macho_core; + case 5: return file_magic::macho_preload_executable; + case 6: return file_magic::macho_dynamically_linked_shared_lib; + case 7: return file_magic::macho_dynamic_linker; + case 8: return file_magic::macho_bundle; + case 9: return file_magic::macho_dynamic_linker; + case 10: return file_magic::macho_dsym_companion; } break; } @@ -123,170 +943,94 @@ sys::IdentifyFileType(const char *magic, unsigned length) { case 0x66: // MPS R4000 Windows case 0x50: // mc68K case 0x4c: // 80386 Windows - if (magic[1] == 0x01) - return COFF_FileType; + if (Magic[1] == 0x01) + return file_magic::coff_object; case 0x90: // PA-RISC Windows case 0x68: // mc68K Windows - if (magic[1] == 0x02) - return COFF_FileType; + if (Magic[1] == 0x02) + return file_magic::coff_object; break; case 0x4d: // Possible MS-DOS stub on Windows PE file - if (magic[1] == 0x5a) { - uint32_t off = *reinterpret_cast<const ulittle32_t *>(magic + 0x3c); + if (Magic[1] == 0x5a) { + uint32_t off = + *reinterpret_cast<const support::ulittle32_t*>(Magic.data() + 0x3c); // PE/COFF file, either EXE or DLL. - if (off < length && memcmp(magic + off, "PE\0\0",4) == 0) - return COFF_FileType; + if (off < Magic.size() && memcmp(Magic.data() + off, "PE\0\0",4) == 0) + return file_magic::pecoff_executable; } break; case 0x64: // x86-64 Windows. - if (magic[1] == char(0x86)) - return COFF_FileType; + if (Magic[1] == char(0x86)) + return file_magic::coff_object; break; default: break; } - return Unknown_FileType; + return file_magic::unknown; } -bool -Path::isArchive() const { - fs::file_magic type; - if (fs::identify_magic(str(), type)) - return false; - return type == fs::file_magic::archive; -} +error_code identify_magic(const Twine &path, file_magic &result) { + SmallString<32> Magic; + error_code ec = get_magic(path, Magic.capacity(), Magic); + if (ec && ec != errc::value_too_large) + return ec; -bool -Path::isDynamicLibrary() const { - fs::file_magic type; - if (fs::identify_magic(str(), type)) - return false; - switch (type) { - default: return false; - case fs::file_magic::macho_fixed_virtual_memory_shared_lib: - case fs::file_magic::macho_dynamically_linked_shared_lib: - case fs::file_magic::macho_dynamically_linked_shared_lib_stub: - case fs::file_magic::elf_shared_object: - case fs::file_magic::pecoff_executable: return true; - } + result = identify_magic(Magic); + return error_code::success(); } -bool -Path::isObjectFile() const { - fs::file_magic type; - if (fs::identify_magic(str(), type) || type == fs::file_magic::unknown) - return false; - return true; -} - -Path -Path::FindLibrary(std::string& name) { - std::vector<sys::Path> LibPaths; - GetSystemLibraryPaths(LibPaths); - for (unsigned i = 0; i < LibPaths.size(); ++i) { - sys::Path FullPath(LibPaths[i]); - FullPath.appendComponent("lib" + name + LTDL_SHLIB_EXT); - if (FullPath.isDynamicLibrary()) - return FullPath; - FullPath.eraseSuffix(); - FullPath.appendSuffix("a"); - if (FullPath.isArchive()) - return FullPath; +namespace { +error_code remove_all_r(StringRef path, file_type ft, uint32_t &count) { + if (ft == file_type::directory_file) { + // This code would be a lot better with exceptions ;/. + error_code ec; + directory_iterator i(path, ec); + if (ec) return ec; + for (directory_iterator e; i != e; i.increment(ec)) { + if (ec) return ec; + file_status st; + if (error_code ec = i->status(st)) return ec; + if (error_code ec = remove_all_r(i->path(), st.type(), count)) return ec; + } + bool obviously_this_exists; + if (error_code ec = remove(path, obviously_this_exists)) return ec; + assert(obviously_this_exists); + ++count; // Include the directory itself in the items removed. + } else { + bool obviously_this_exists; + if (error_code ec = remove(path, obviously_this_exists)) return ec; + assert(obviously_this_exists); + ++count; } - return sys::Path(); -} -StringRef Path::GetDLLSuffix() { - return &(LTDL_SHLIB_EXT[1]); + return error_code::success(); } +} // end unnamed namespace -void -Path::appendSuffix(StringRef suffix) { - if (!suffix.empty()) { - path.append("."); - path.append(suffix); - } -} - -bool -Path::isBitcodeFile() const { - fs::file_magic type; - if (fs::identify_magic(str(), type)) - return false; - return type == fs::file_magic::bitcode; -} - -bool Path::hasMagicNumber(StringRef Magic) const { - std::string actualMagic; - if (getMagicNumber(actualMagic, static_cast<unsigned>(Magic.size()))) - return Magic == actualMagic; - return false; -} - -static void getPathList(const char*path, std::vector<Path>& Paths) { - const char* at = path; - const char* delim = strchr(at, PathSeparator); - Path tmpPath; - while (delim != 0) { - std::string tmp(at, size_t(delim-at)); - if (tmpPath.set(tmp)) - if (tmpPath.canRead()) - Paths.push_back(tmpPath); - at = delim + 1; - delim = strchr(at, PathSeparator); - } +error_code remove_all(const Twine &path, uint32_t &num_removed) { + SmallString<128> path_storage; + StringRef p = path.toStringRef(path_storage); - if (*at != 0) - if (tmpPath.set(std::string(at))) - if (tmpPath.canRead()) - Paths.push_back(tmpPath); + file_status fs; + if (error_code ec = status(path, fs)) + return ec; + num_removed = 0; + return remove_all_r(p, fs.type(), num_removed); } -static StringRef getDirnameCharSep(StringRef path, const char *Sep) { - assert(Sep[0] != '\0' && Sep[1] == '\0' && - "Sep must be a 1-character string literal."); - if (path.empty()) - return "."; - - // If the path is all slashes, return a single slash. - // Otherwise, remove all trailing slashes. - - signed pos = static_cast<signed>(path.size()) - 1; - - while (pos >= 0 && path[pos] == Sep[0]) - --pos; - - if (pos < 0) - return path[0] == Sep[0] ? Sep : "."; - - // Any slashes left? - signed i = 0; - - while (i < pos && path[i] != Sep[0]) - ++i; - - if (i == pos) // No slashes? Return "." - return "."; - - // There is at least one slash left. Remove all trailing non-slashes. - while (pos >= 0 && path[pos] != Sep[0]) - --pos; - - // Remove any trailing slashes. - while (pos >= 0 && path[pos] == Sep[0]) - --pos; - - if (pos < 0) - return path[0] == Sep[0] ? Sep : "."; - - return path.substr(0, pos+1); +error_code directory_entry::status(file_status &result) const { + return fs::status(Path, result); } -// Include the truly platform-specific parts of this class. +} // end namespace fs +} // end namespace sys +} // end namespace llvm + +// Include the truly platform-specific parts. #if defined(LLVM_ON_UNIX) #include "Unix/Path.inc" #endif diff --git a/contrib/llvm/lib/Support/PathV2.cpp b/contrib/llvm/lib/Support/PathV2.cpp deleted file mode 100644 index ac53a9e9..0000000 --- a/contrib/llvm/lib/Support/PathV2.cpp +++ /dev/null @@ -1,949 +0,0 @@ -//===-- PathV2.cpp - Implement OS Path Concept ------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the operating system PathV2 API. -// -//===----------------------------------------------------------------------===// - -#include "llvm/Support/PathV2.h" -#include "llvm/Support/Endian.h" -#include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/FileSystem.h" -#include <cctype> -#include <cstdio> -#include <cstring> -#ifdef __APPLE__ -#include <unistd.h> -#endif - -namespace { - using llvm::StringRef; - using llvm::sys::path::is_separator; - -#ifdef LLVM_ON_WIN32 - const char *separators = "\\/"; - const char prefered_separator = '\\'; -#else - const char separators = '/'; - const char prefered_separator = '/'; -#endif - - StringRef find_first_component(StringRef path) { - // Look for this first component in the following order. - // * empty (in this case we return an empty string) - // * either C: or {//,\\}net. - // * {/,\} - // * {.,..} - // * {file,directory}name - - if (path.empty()) - return path; - -#ifdef LLVM_ON_WIN32 - // C: - if (path.size() >= 2 && std::isalpha(static_cast<unsigned char>(path[0])) && - path[1] == ':') - return path.substr(0, 2); -#endif - - // //net - if ((path.size() > 2) && - is_separator(path[0]) && - path[0] == path[1] && - !is_separator(path[2])) { - // Find the next directory separator. - size_t end = path.find_first_of(separators, 2); - return path.substr(0, end); - } - - // {/,\} - if (is_separator(path[0])) - return path.substr(0, 1); - - if (path.startswith("..")) - return path.substr(0, 2); - - if (path[0] == '.') - return path.substr(0, 1); - - // * {file,directory}name - size_t end = path.find_first_of(separators, 2); - return path.substr(0, end); - } - - size_t filename_pos(StringRef str) { - if (str.size() == 2 && - is_separator(str[0]) && - str[0] == str[1]) - return 0; - - if (str.size() > 0 && is_separator(str[str.size() - 1])) - return str.size() - 1; - - size_t pos = str.find_last_of(separators, str.size() - 1); - -#ifdef LLVM_ON_WIN32 - if (pos == StringRef::npos) - pos = str.find_last_of(':', str.size() - 2); -#endif - - if (pos == StringRef::npos || - (pos == 1 && is_separator(str[0]))) - return 0; - - return pos + 1; - } - - size_t root_dir_start(StringRef str) { - // case "c:/" -#ifdef LLVM_ON_WIN32 - if (str.size() > 2 && - str[1] == ':' && - is_separator(str[2])) - return 2; -#endif - - // case "//" - if (str.size() == 2 && - is_separator(str[0]) && - str[0] == str[1]) - return StringRef::npos; - - // case "//net" - if (str.size() > 3 && - is_separator(str[0]) && - str[0] == str[1] && - !is_separator(str[2])) { - return str.find_first_of(separators, 2); - } - - // case "/" - if (str.size() > 0 && is_separator(str[0])) - return 0; - - return StringRef::npos; - } - - size_t parent_path_end(StringRef path) { - size_t end_pos = filename_pos(path); - - bool filename_was_sep = path.size() > 0 && is_separator(path[end_pos]); - - // Skip separators except for root dir. - size_t root_dir_pos = root_dir_start(path.substr(0, end_pos)); - - while(end_pos > 0 && - (end_pos - 1) != root_dir_pos && - is_separator(path[end_pos - 1])) - --end_pos; - - if (end_pos == 1 && root_dir_pos == 0 && filename_was_sep) - return StringRef::npos; - - return end_pos; - } -} // end unnamed namespace - -namespace llvm { -namespace sys { -namespace path { - -const_iterator begin(StringRef path) { - const_iterator i; - i.Path = path; - i.Component = find_first_component(path); - i.Position = 0; - return i; -} - -const_iterator end(StringRef path) { - const_iterator i; - i.Path = path; - i.Position = path.size(); - return i; -} - -const_iterator &const_iterator::operator++() { - assert(Position < Path.size() && "Tried to increment past end!"); - - // Increment Position to past the current component - Position += Component.size(); - - // Check for end. - if (Position == Path.size()) { - Component = StringRef(); - return *this; - } - - // Both POSIX and Windows treat paths that begin with exactly two separators - // specially. - bool was_net = Component.size() > 2 && - is_separator(Component[0]) && - Component[1] == Component[0] && - !is_separator(Component[2]); - - // Handle separators. - if (is_separator(Path[Position])) { - // Root dir. - if (was_net -#ifdef LLVM_ON_WIN32 - // c:/ - || Component.endswith(":") -#endif - ) { - Component = Path.substr(Position, 1); - return *this; - } - - // Skip extra separators. - while (Position != Path.size() && - is_separator(Path[Position])) { - ++Position; - } - - // Treat trailing '/' as a '.'. - if (Position == Path.size()) { - --Position; - Component = "."; - return *this; - } - } - - // Find next component. - size_t end_pos = Path.find_first_of(separators, Position); - Component = Path.slice(Position, end_pos); - - return *this; -} - -const_iterator &const_iterator::operator--() { - // If we're at the end and the previous char was a '/', return '.'. - if (Position == Path.size() && - Path.size() > 1 && - is_separator(Path[Position - 1]) -#ifdef LLVM_ON_WIN32 - && Path[Position - 2] != ':' -#endif - ) { - --Position; - Component = "."; - return *this; - } - - // Skip separators unless it's the root directory. - size_t root_dir_pos = root_dir_start(Path); - size_t end_pos = Position; - - while(end_pos > 0 && - (end_pos - 1) != root_dir_pos && - is_separator(Path[end_pos - 1])) - --end_pos; - - // Find next separator. - size_t start_pos = filename_pos(Path.substr(0, end_pos)); - Component = Path.slice(start_pos, end_pos); - Position = start_pos; - return *this; -} - -bool const_iterator::operator==(const const_iterator &RHS) const { - return Path.begin() == RHS.Path.begin() && - Position == RHS.Position; -} - -bool const_iterator::operator!=(const const_iterator &RHS) const { - return !(*this == RHS); -} - -ptrdiff_t const_iterator::operator-(const const_iterator &RHS) const { - return Position - RHS.Position; -} - -const StringRef root_path(StringRef path) { - const_iterator b = begin(path), - pos = b, - e = end(path); - if (b != e) { - bool has_net = b->size() > 2 && is_separator((*b)[0]) && (*b)[1] == (*b)[0]; - bool has_drive = -#ifdef LLVM_ON_WIN32 - b->endswith(":"); -#else - false; -#endif - - if (has_net || has_drive) { - if ((++pos != e) && is_separator((*pos)[0])) { - // {C:/,//net/}, so get the first two components. - return path.substr(0, b->size() + pos->size()); - } else { - // just {C:,//net}, return the first component. - return *b; - } - } - - // POSIX style root directory. - if (is_separator((*b)[0])) { - return *b; - } - } - - return StringRef(); -} - -const StringRef root_name(StringRef path) { - const_iterator b = begin(path), - e = end(path); - if (b != e) { - bool has_net = b->size() > 2 && is_separator((*b)[0]) && (*b)[1] == (*b)[0]; - bool has_drive = -#ifdef LLVM_ON_WIN32 - b->endswith(":"); -#else - false; -#endif - - if (has_net || has_drive) { - // just {C:,//net}, return the first component. - return *b; - } - } - - // No path or no name. - return StringRef(); -} - -const StringRef root_directory(StringRef path) { - const_iterator b = begin(path), - pos = b, - e = end(path); - if (b != e) { - bool has_net = b->size() > 2 && is_separator((*b)[0]) && (*b)[1] == (*b)[0]; - bool has_drive = -#ifdef LLVM_ON_WIN32 - b->endswith(":"); -#else - false; -#endif - - if ((has_net || has_drive) && - // {C:,//net}, skip to the next component. - (++pos != e) && is_separator((*pos)[0])) { - return *pos; - } - - // POSIX style root directory. - if (!has_net && is_separator((*b)[0])) { - return *b; - } - } - - // No path or no root. - return StringRef(); -} - -const StringRef relative_path(StringRef path) { - StringRef root = root_path(path); - return path.substr(root.size()); -} - -void append(SmallVectorImpl<char> &path, const Twine &a, - const Twine &b, - const Twine &c, - const Twine &d) { - SmallString<32> a_storage; - SmallString<32> b_storage; - SmallString<32> c_storage; - SmallString<32> d_storage; - - SmallVector<StringRef, 4> components; - if (!a.isTriviallyEmpty()) components.push_back(a.toStringRef(a_storage)); - if (!b.isTriviallyEmpty()) components.push_back(b.toStringRef(b_storage)); - if (!c.isTriviallyEmpty()) components.push_back(c.toStringRef(c_storage)); - if (!d.isTriviallyEmpty()) components.push_back(d.toStringRef(d_storage)); - - for (SmallVectorImpl<StringRef>::const_iterator i = components.begin(), - e = components.end(); - i != e; ++i) { - bool path_has_sep = !path.empty() && is_separator(path[path.size() - 1]); - bool component_has_sep = !i->empty() && is_separator((*i)[0]); - bool is_root_name = has_root_name(*i); - - if (path_has_sep) { - // Strip separators from beginning of component. - size_t loc = i->find_first_not_of(separators); - StringRef c = i->substr(loc); - - // Append it. - path.append(c.begin(), c.end()); - continue; - } - - if (!component_has_sep && !(path.empty() || is_root_name)) { - // Add a separator. - path.push_back(prefered_separator); - } - - path.append(i->begin(), i->end()); - } -} - -void append(SmallVectorImpl<char> &path, - const_iterator begin, const_iterator end) { - for (; begin != end; ++begin) - path::append(path, *begin); -} - -const StringRef parent_path(StringRef path) { - size_t end_pos = parent_path_end(path); - if (end_pos == StringRef::npos) - return StringRef(); - else - return path.substr(0, end_pos); -} - -void remove_filename(SmallVectorImpl<char> &path) { - size_t end_pos = parent_path_end(StringRef(path.begin(), path.size())); - if (end_pos != StringRef::npos) - path.set_size(end_pos); -} - -void replace_extension(SmallVectorImpl<char> &path, const Twine &extension) { - StringRef p(path.begin(), path.size()); - SmallString<32> ext_storage; - StringRef ext = extension.toStringRef(ext_storage); - - // Erase existing extension. - size_t pos = p.find_last_of('.'); - if (pos != StringRef::npos && pos >= filename_pos(p)) - path.set_size(pos); - - // Append '.' if needed. - if (ext.size() > 0 && ext[0] != '.') - path.push_back('.'); - - // Append extension. - path.append(ext.begin(), ext.end()); -} - -void native(const Twine &path, SmallVectorImpl<char> &result) { - // Clear result. - result.clear(); -#ifdef LLVM_ON_WIN32 - SmallString<128> path_storage; - StringRef p = path.toStringRef(path_storage); - result.reserve(p.size()); - for (StringRef::const_iterator i = p.begin(), - e = p.end(); - i != e; - ++i) { - if (*i == '/') - result.push_back('\\'); - else - result.push_back(*i); - } -#else - path.toVector(result); -#endif -} - -const StringRef filename(StringRef path) { - return *(--end(path)); -} - -const StringRef stem(StringRef path) { - StringRef fname = filename(path); - size_t pos = fname.find_last_of('.'); - if (pos == StringRef::npos) - return fname; - else - if ((fname.size() == 1 && fname == ".") || - (fname.size() == 2 && fname == "..")) - return fname; - else - return fname.substr(0, pos); -} - -const StringRef extension(StringRef path) { - StringRef fname = filename(path); - size_t pos = fname.find_last_of('.'); - if (pos == StringRef::npos) - return StringRef(); - else - if ((fname.size() == 1 && fname == ".") || - (fname.size() == 2 && fname == "..")) - return StringRef(); - else - return fname.substr(pos); -} - -bool is_separator(char value) { - switch(value) { -#ifdef LLVM_ON_WIN32 - case '\\': // fall through -#endif - case '/': return true; - default: return false; - } -} - -void system_temp_directory(bool erasedOnReboot, SmallVectorImpl<char> &result) { - result.clear(); - -#ifdef __APPLE__ - // On Darwin, use DARWIN_USER_TEMP_DIR or DARWIN_USER_CACHE_DIR. - int ConfName = erasedOnReboot? _CS_DARWIN_USER_TEMP_DIR - : _CS_DARWIN_USER_CACHE_DIR; - size_t ConfLen = confstr(ConfName, 0, 0); - if (ConfLen > 0) { - do { - result.resize(ConfLen); - ConfLen = confstr(ConfName, result.data(), result.size()); - } while (ConfLen > 0 && ConfLen != result.size()); - - if (ConfLen > 0) { - assert(result.back() == 0); - result.pop_back(); - return; - } - - result.clear(); - } -#endif - - // Check whether the temporary directory is specified by an environment - // variable. - const char *EnvironmentVariable; -#ifdef LLVM_ON_WIN32 - EnvironmentVariable = "TEMP"; -#else - EnvironmentVariable = "TMPDIR"; -#endif - if (char *RequestedDir = getenv(EnvironmentVariable)) { - result.append(RequestedDir, RequestedDir + strlen(RequestedDir)); - return; - } - - // Fall back to a system default. - const char *DefaultResult; -#ifdef LLVM_ON_WIN32 - (void)erasedOnReboot; - DefaultResult = "C:\\TEMP"; -#else - if (erasedOnReboot) - DefaultResult = "/tmp"; - else - DefaultResult = "/var/tmp"; -#endif - result.append(DefaultResult, DefaultResult + strlen(DefaultResult)); -} - -bool has_root_name(const Twine &path) { - SmallString<128> path_storage; - StringRef p = path.toStringRef(path_storage); - - return !root_name(p).empty(); -} - -bool has_root_directory(const Twine &path) { - SmallString<128> path_storage; - StringRef p = path.toStringRef(path_storage); - - return !root_directory(p).empty(); -} - -bool has_root_path(const Twine &path) { - SmallString<128> path_storage; - StringRef p = path.toStringRef(path_storage); - - return !root_path(p).empty(); -} - -bool has_relative_path(const Twine &path) { - SmallString<128> path_storage; - StringRef p = path.toStringRef(path_storage); - - return !relative_path(p).empty(); -} - -bool has_filename(const Twine &path) { - SmallString<128> path_storage; - StringRef p = path.toStringRef(path_storage); - - return !filename(p).empty(); -} - -bool has_parent_path(const Twine &path) { - SmallString<128> path_storage; - StringRef p = path.toStringRef(path_storage); - - return !parent_path(p).empty(); -} - -bool has_stem(const Twine &path) { - SmallString<128> path_storage; - StringRef p = path.toStringRef(path_storage); - - return !stem(p).empty(); -} - -bool has_extension(const Twine &path) { - SmallString<128> path_storage; - StringRef p = path.toStringRef(path_storage); - - return !extension(p).empty(); -} - -bool is_absolute(const Twine &path) { - SmallString<128> path_storage; - StringRef p = path.toStringRef(path_storage); - - bool rootDir = has_root_directory(p), -#ifdef LLVM_ON_WIN32 - rootName = has_root_name(p); -#else - rootName = true; -#endif - - return rootDir && rootName; -} - -bool is_relative(const Twine &path) { - return !is_absolute(path); -} - -} // end namespace path - -namespace fs { - -error_code make_absolute(SmallVectorImpl<char> &path) { - StringRef p(path.data(), path.size()); - - bool rootDirectory = path::has_root_directory(p), -#ifdef LLVM_ON_WIN32 - rootName = path::has_root_name(p); -#else - rootName = true; -#endif - - // Already absolute. - if (rootName && rootDirectory) - return error_code::success(); - - // All of the following conditions will need the current directory. - SmallString<128> current_dir; - if (error_code ec = current_path(current_dir)) return ec; - - // Relative path. Prepend the current directory. - if (!rootName && !rootDirectory) { - // Append path to the current directory. - path::append(current_dir, p); - // Set path to the result. - path.swap(current_dir); - return error_code::success(); - } - - if (!rootName && rootDirectory) { - StringRef cdrn = path::root_name(current_dir); - SmallString<128> curDirRootName(cdrn.begin(), cdrn.end()); - path::append(curDirRootName, p); - // Set path to the result. - path.swap(curDirRootName); - return error_code::success(); - } - - if (rootName && !rootDirectory) { - StringRef pRootName = path::root_name(p); - StringRef bRootDirectory = path::root_directory(current_dir); - StringRef bRelativePath = path::relative_path(current_dir); - StringRef pRelativePath = path::relative_path(p); - - SmallString<128> res; - path::append(res, pRootName, bRootDirectory, bRelativePath, pRelativePath); - path.swap(res); - return error_code::success(); - } - - llvm_unreachable("All rootName and rootDirectory combinations should have " - "occurred above!"); -} - -error_code create_directories(const Twine &path, bool &existed) { - SmallString<128> path_storage; - StringRef p = path.toStringRef(path_storage); - - StringRef parent = path::parent_path(p); - if (!parent.empty()) { - bool parent_exists; - if (error_code ec = fs::exists(parent, parent_exists)) return ec; - - if (!parent_exists) - if (error_code ec = create_directories(parent, existed)) return ec; - } - - return create_directory(p, existed); -} - -bool exists(file_status status) { - return status_known(status) && status.type() != file_type::file_not_found; -} - -bool status_known(file_status s) { - return s.type() != file_type::status_error; -} - -bool is_directory(file_status status) { - return status.type() == file_type::directory_file; -} - -error_code is_directory(const Twine &path, bool &result) { - file_status st; - if (error_code ec = status(path, st)) - return ec; - result = is_directory(st); - return error_code::success(); -} - -bool is_regular_file(file_status status) { - return status.type() == file_type::regular_file; -} - -error_code is_regular_file(const Twine &path, bool &result) { - file_status st; - if (error_code ec = status(path, st)) - return ec; - result = is_regular_file(st); - return error_code::success(); -} - -bool is_symlink(file_status status) { - return status.type() == file_type::symlink_file; -} - -error_code is_symlink(const Twine &path, bool &result) { - file_status st; - if (error_code ec = status(path, st)) - return ec; - result = is_symlink(st); - return error_code::success(); -} - -bool is_other(file_status status) { - return exists(status) && - !is_regular_file(status) && - !is_directory(status) && - !is_symlink(status); -} - -void directory_entry::replace_filename(const Twine &filename, file_status st) { - SmallString<128> path(Path.begin(), Path.end()); - path::remove_filename(path); - path::append(path, filename); - Path = path.str(); - Status = st; -} - -error_code has_magic(const Twine &path, const Twine &magic, bool &result) { - SmallString<32> MagicStorage; - StringRef Magic = magic.toStringRef(MagicStorage); - SmallString<32> Buffer; - - if (error_code ec = get_magic(path, Magic.size(), Buffer)) { - if (ec == errc::value_too_large) { - // Magic.size() > file_size(Path). - result = false; - return error_code::success(); - } - return ec; - } - - result = Magic == Buffer; - return error_code::success(); -} - -/// @brief Identify the magic in magic. -file_magic identify_magic(StringRef magic) { - if (magic.size() < 4) - return file_magic::unknown; - switch ((unsigned char)magic[0]) { - case 0xDE: // 0x0B17C0DE = BC wraper - if (magic[1] == (char)0xC0 && magic[2] == (char)0x17 && - magic[3] == (char)0x0B) - return file_magic::bitcode; - break; - case 'B': - if (magic[1] == 'C' && magic[2] == (char)0xC0 && magic[3] == (char)0xDE) - return file_magic::bitcode; - break; - case '!': - if (magic.size() >= 8) - if (memcmp(magic.data(),"!<arch>\n",8) == 0) - return file_magic::archive; - break; - - case '\177': - if (magic[1] == 'E' && magic[2] == 'L' && magic[3] == 'F') { - bool Data2MSB = magic[5] == 2; - unsigned high = Data2MSB ? 16 : 17; - unsigned low = Data2MSB ? 17 : 16; - if (magic.size() >= 18 && magic[high] == 0) - switch (magic[low]) { - default: break; - case 1: return file_magic::elf_relocatable; - case 2: return file_magic::elf_executable; - case 3: return file_magic::elf_shared_object; - case 4: return file_magic::elf_core; - } - } - break; - - case 0xCA: - if (magic[1] == char(0xFE) && magic[2] == char(0xBA) && - magic[3] == char(0xBE)) { - // This is complicated by an overlap with Java class files. - // See the Mach-O section in /usr/share/file/magic for details. - if (magic.size() >= 8 && magic[7] < 43) - // FIXME: Universal Binary of any type. - return file_magic::macho_dynamically_linked_shared_lib; - } - break; - - // The two magic numbers for mach-o are: - // 0xfeedface - 32-bit mach-o - // 0xfeedfacf - 64-bit mach-o - case 0xFE: - case 0xCE: - case 0xCF: { - uint16_t type = 0; - if (magic[0] == char(0xFE) && magic[1] == char(0xED) && - magic[2] == char(0xFA) && - (magic[3] == char(0xCE) || magic[3] == char(0xCF))) { - /* Native endian */ - if (magic.size() >= 16) type = magic[14] << 8 | magic[15]; - } else if ((magic[0] == char(0xCE) || magic[0] == char(0xCF)) && - magic[1] == char(0xFA) && magic[2] == char(0xED) && - magic[3] == char(0xFE)) { - /* Reverse endian */ - if (magic.size() >= 14) type = magic[13] << 8 | magic[12]; - } - switch (type) { - default: break; - case 1: return file_magic::macho_object; - case 2: return file_magic::macho_executable; - case 3: return file_magic::macho_fixed_virtual_memory_shared_lib; - case 4: return file_magic::macho_core; - case 5: return file_magic::macho_preload_executabl; - case 6: return file_magic::macho_dynamically_linked_shared_lib; - case 7: return file_magic::macho_dynamic_linker; - case 8: return file_magic::macho_bundle; - case 9: return file_magic::macho_dynamic_linker; - case 10: return file_magic::macho_dsym_companion; - } - break; - } - case 0xF0: // PowerPC Windows - case 0x83: // Alpha 32-bit - case 0x84: // Alpha 64-bit - case 0x66: // MPS R4000 Windows - case 0x50: // mc68K - case 0x4c: // 80386 Windows - if (magic[1] == 0x01) - return file_magic::coff_object; - - case 0x90: // PA-RISC Windows - case 0x68: // mc68K Windows - if (magic[1] == 0x02) - return file_magic::coff_object; - break; - - case 0x4d: // Possible MS-DOS stub on Windows PE file - if (magic[1] == 0x5a) { - uint32_t off = - *reinterpret_cast<const support::ulittle32_t*>(magic.data() + 0x3c); - // PE/COFF file, either EXE or DLL. - if (off < magic.size() && memcmp(magic.data() + off, "PE\0\0",4) == 0) - return file_magic::pecoff_executable; - } - break; - - case 0x64: // x86-64 Windows. - if (magic[1] == char(0x86)) - return file_magic::coff_object; - break; - - default: - break; - } - return file_magic::unknown; -} - -error_code identify_magic(const Twine &path, file_magic &result) { - SmallString<32> Magic; - error_code ec = get_magic(path, Magic.capacity(), Magic); - if (ec && ec != errc::value_too_large) - return ec; - - result = identify_magic(Magic); - return error_code::success(); -} - -namespace { -error_code remove_all_r(StringRef path, file_type ft, uint32_t &count) { - if (ft == file_type::directory_file) { - // This code would be a lot better with exceptions ;/. - error_code ec; - directory_iterator i(path, ec); - if (ec) return ec; - for (directory_iterator e; i != e; i.increment(ec)) { - if (ec) return ec; - file_status st; - if (error_code ec = i->status(st)) return ec; - if (error_code ec = remove_all_r(i->path(), st.type(), count)) return ec; - } - bool obviously_this_exists; - if (error_code ec = remove(path, obviously_this_exists)) return ec; - assert(obviously_this_exists); - ++count; // Include the directory itself in the items removed. - } else { - bool obviously_this_exists; - if (error_code ec = remove(path, obviously_this_exists)) return ec; - assert(obviously_this_exists); - ++count; - } - - return error_code::success(); -} -} // end unnamed namespace - -error_code remove_all(const Twine &path, uint32_t &num_removed) { - SmallString<128> path_storage; - StringRef p = path.toStringRef(path_storage); - - file_status fs; - if (error_code ec = status(path, fs)) - return ec; - num_removed = 0; - return remove_all_r(p, fs.type(), num_removed); -} - -error_code directory_entry::status(file_status &result) const { - return fs::status(Path, result); -} - -} // end namespace fs -} // end namespace sys -} // end namespace llvm - -// Include the truly platform-specific parts. -#if defined(LLVM_ON_UNIX) -#include "Unix/PathV2.inc" -#endif -#if defined(LLVM_ON_WIN32) -#include "Windows/PathV2.inc" -#endif diff --git a/contrib/llvm/lib/Support/PrettyStackTrace.cpp b/contrib/llvm/lib/Support/PrettyStackTrace.cpp index 23ee5ab..722f4ca 100644 --- a/contrib/llvm/lib/Support/PrettyStackTrace.cpp +++ b/contrib/llvm/lib/Support/PrettyStackTrace.cpp @@ -15,10 +15,12 @@ #include "llvm/Support/PrettyStackTrace.h" #include "llvm/ADT/SmallString.h" #include "llvm/Config/config.h" // Get autoconf configuration settings +#include "llvm/Support/ManagedStatic.h" #include "llvm/Support/Signals.h" #include "llvm/Support/ThreadLocal.h" #include "llvm/Support/Watchdog.h" #include "llvm/Support/raw_ostream.h" +#include "llvm-c/Core.h" #ifdef HAVE_CRASHREPORTERCLIENT_H #include <CrashReporterClient.h> @@ -26,12 +28,7 @@ using namespace llvm; -namespace llvm { - bool DisablePrettyStackTrace = false; -} - -// FIXME: This should be thread local when llvm supports threads. -static sys::ThreadLocal<const PrettyStackTraceEntry> PrettyStackTraceHead; +static ManagedStatic<sys::ThreadLocal<const PrettyStackTraceEntry> > PrettyStackTraceHead; static unsigned PrintStack(const PrettyStackTraceEntry *Entry, raw_ostream &OS){ unsigned NextID = 0; @@ -49,12 +46,12 @@ static unsigned PrintStack(const PrettyStackTraceEntry *Entry, raw_ostream &OS){ /// PrintCurStackTrace - Print the current stack trace to the specified stream. static void PrintCurStackTrace(raw_ostream &OS) { // Don't print an empty trace. - if (PrettyStackTraceHead.get() == 0) return; + if (PrettyStackTraceHead->get() == 0) return; // If there are pretty stack frames registered, walk and emit them. OS << "Stack dump:\n"; - PrintStack(PrettyStackTraceHead.get(), OS); + PrintStack(PrettyStackTraceHead->get(), OS); OS.flush(); } @@ -102,26 +99,28 @@ static void CrashHandler(void *) { #endif } -static bool RegisterCrashPrinter() { - if (!DisablePrettyStackTrace) - sys::AddSignalHandler(CrashHandler, 0); - return false; -} - PrettyStackTraceEntry::PrettyStackTraceEntry() { - // The first time this is called, we register the crash printer. - static bool HandlerRegistered = RegisterCrashPrinter(); - (void)HandlerRegistered; - // Link ourselves. - NextEntry = PrettyStackTraceHead.get(); - PrettyStackTraceHead.set(this); + NextEntry = PrettyStackTraceHead->get(); + PrettyStackTraceHead->set(this); } PrettyStackTraceEntry::~PrettyStackTraceEntry() { - assert(PrettyStackTraceHead.get() == this && + // Do nothing if PrettyStackTraceHead is uninitialized. This can only happen + // if a shutdown occurred after we created the PrettyStackTraceEntry. That + // does occur in the following idiom: + // + // PrettyStackTraceProgram X(...); + // llvm_shutdown_obj Y; + // + // Without this check, we may end up removing ourselves from the stack trace + // after PrettyStackTraceHead has already been destroyed. + if (!PrettyStackTraceHead.isConstructed()) + return; + + assert(PrettyStackTraceHead->get() == this && "Pretty stack trace entry destruction is out of order"); - PrettyStackTraceHead.set(getNextEntry()); + PrettyStackTraceHead->set(getNextEntry()); } void PrettyStackTraceString::print(raw_ostream &OS) const { @@ -135,3 +134,18 @@ void PrettyStackTraceProgram::print(raw_ostream &OS) const { OS << ArgV[i] << ' '; OS << '\n'; } + +static bool RegisterCrashPrinter() { + sys::AddSignalHandler(CrashHandler, 0); + return false; +} + +void llvm::EnablePrettyStackTrace() { + // The first time this is called, we register the crash printer. + static bool HandlerRegistered = RegisterCrashPrinter(); + (void)HandlerRegistered; +} + +void LLVMEnablePrettyStackTrace() { + EnablePrettyStackTrace(); +} diff --git a/contrib/llvm/lib/Support/Process.cpp b/contrib/llvm/lib/Support/Process.cpp index 2c0d37b..d5168f0 100644 --- a/contrib/llvm/lib/Support/Process.cpp +++ b/contrib/llvm/lib/Support/Process.cpp @@ -80,6 +80,24 @@ TimeValue self_process::get_wall_time() const { #endif +#define COLOR(FGBG, CODE, BOLD) "\033[0;" BOLD FGBG CODE "m" + +#define ALLCOLORS(FGBG,BOLD) {\ + COLOR(FGBG, "0", BOLD),\ + COLOR(FGBG, "1", BOLD),\ + COLOR(FGBG, "2", BOLD),\ + COLOR(FGBG, "3", BOLD),\ + COLOR(FGBG, "4", BOLD),\ + COLOR(FGBG, "5", BOLD),\ + COLOR(FGBG, "6", BOLD),\ + COLOR(FGBG, "7", BOLD)\ + } + +static const char colorcodes[2][2][8][10] = { + { ALLCOLORS("3",""), ALLCOLORS("3","1;") }, + { ALLCOLORS("4",""), ALLCOLORS("4","1;") } +}; + // Include the platform-specific parts of this class. #ifdef LLVM_ON_UNIX #include "Unix/Process.inc" diff --git a/contrib/llvm/lib/Support/Program.cpp b/contrib/llvm/lib/Support/Program.cpp index 201d5c0..83f2ec4 100644 --- a/contrib/llvm/lib/Support/Program.cpp +++ b/contrib/llvm/lib/Support/Program.cpp @@ -22,33 +22,40 @@ using namespace sys; //=== independent code. //===----------------------------------------------------------------------===// -int -Program::ExecuteAndWait(const Path& path, - const char** args, - const char** envp, - const Path** redirects, - unsigned secondsToWait, - unsigned memoryLimit, - std::string* ErrMsg, +static bool Execute(ProcessInfo &PI, StringRef Program, const char **args, + const char **env, const StringRef **Redirects, + unsigned memoryLimit, std::string *ErrMsg); + +int sys::ExecuteAndWait(StringRef Program, const char **args, const char **envp, + const StringRef **redirects, unsigned secondsToWait, + unsigned memoryLimit, std::string *ErrMsg, bool *ExecutionFailed) { - Program prg; - if (prg.Execute(path, args, envp, redirects, memoryLimit, ErrMsg)) { - if (ExecutionFailed) *ExecutionFailed = false; - return prg.Wait(path, secondsToWait, ErrMsg); + ProcessInfo PI; + if (Execute(PI, Program, args, envp, redirects, memoryLimit, ErrMsg)) { + if (ExecutionFailed) + *ExecutionFailed = false; + ProcessInfo Result = Wait(PI, secondsToWait, true, ErrMsg); + return Result.ReturnCode; } - if (ExecutionFailed) *ExecutionFailed = true; + + if (ExecutionFailed) + *ExecutionFailed = true; + return -1; } -void -Program::ExecuteNoWait(const Path& path, - const char** args, - const char** envp, - const Path** redirects, - unsigned memoryLimit, - std::string* ErrMsg) { - Program prg; - prg.Execute(path, args, envp, redirects, memoryLimit, ErrMsg); +ProcessInfo sys::ExecuteNoWait(StringRef Program, const char **args, + const char **envp, const StringRef **redirects, + unsigned memoryLimit, std::string *ErrMsg, + bool *ExecutionFailed) { + ProcessInfo PI; + if (ExecutionFailed) + *ExecutionFailed = false; + if (!Execute(PI, Program, args, envp, redirects, memoryLimit, ErrMsg)) + if (ExecutionFailed) + *ExecutionFailed = true; + + return PI; } // Include the platform-specific parts of this class. diff --git a/contrib/llvm/lib/Support/Regex.cpp b/contrib/llvm/lib/Support/Regex.cpp index efc8b90..5413641 100644 --- a/contrib/llvm/lib/Support/Regex.cpp +++ b/contrib/llvm/lib/Support/Regex.cpp @@ -43,7 +43,7 @@ bool Regex::isValid(std::string &Error) { size_t len = llvm_regerror(error, preg, NULL, 0); - Error.resize(len); + Error.resize(len - 1); llvm_regerror(error, preg, &Error[0], len); return false; } @@ -168,3 +168,10 @@ std::string Regex::sub(StringRef Repl, StringRef String, return Res; } + +bool Regex::isLiteralERE(StringRef Str) { + // Check for regex metacharacters. This list was derived from our regex + // implementation in regcomp.c and double checked against the POSIX extended + // regular expression specification. + return Str.find_first_of("()^$|*+?.[]\\{}") == StringRef::npos; +} diff --git a/contrib/llvm/lib/Support/SmallPtrSet.cpp b/contrib/llvm/lib/Support/SmallPtrSet.cpp index f0fed77..dd417b4 100644 --- a/contrib/llvm/lib/Support/SmallPtrSet.cpp +++ b/contrib/llvm/lib/Support/SmallPtrSet.cpp @@ -202,8 +202,13 @@ void SmallPtrSetImpl::CopyFrom(const SmallPtrSetImpl &RHS) { } else if (CurArraySize != RHS.CurArraySize) { if (isSmall()) CurArray = (const void**)malloc(sizeof(void*) * RHS.CurArraySize); - else - CurArray = (const void**)realloc(CurArray, sizeof(void*)*RHS.CurArraySize); + else { + const void **T = (const void**)realloc(CurArray, + sizeof(void*) * RHS.CurArraySize); + if (!T) + free(CurArray); + CurArray = T; + } assert(CurArray && "Failed to allocate memory?"); } diff --git a/contrib/llvm/lib/Support/SourceMgr.cpp b/contrib/llvm/lib/Support/SourceMgr.cpp index fac3cad..d4b94f8 100644 --- a/contrib/llvm/lib/Support/SourceMgr.cpp +++ b/contrib/llvm/lib/Support/SourceMgr.cpp @@ -52,9 +52,9 @@ SourceMgr::~SourceMgr() { /// AddIncludeFile - Search for a file with the specified name in the current /// directory or in one of the IncludeDirs. If no file is found, this returns /// ~0, otherwise it returns the buffer ID of the stacked file. -unsigned SourceMgr::AddIncludeFile(const std::string &Filename, - SMLoc IncludeLoc, - std::string &IncludedFile) { +size_t SourceMgr::AddIncludeFile(const std::string &Filename, + SMLoc IncludeLoc, + std::string &IncludedFile) { OwningPtr<MemoryBuffer> NewBuf; IncludedFile = Filename; MemoryBuffer::getFile(IncludedFile.c_str(), NewBuf); @@ -65,7 +65,7 @@ unsigned SourceMgr::AddIncludeFile(const std::string &Filename, MemoryBuffer::getFile(IncludedFile.c_str(), NewBuf); } - if (NewBuf == 0) return ~0U; + if (!NewBuf) return ~0U; return AddNewSourceBuffer(NewBuf.take(), IncludeLoc); } @@ -211,7 +211,8 @@ SMDiagnostic SourceMgr::GetMessage(SMLoc Loc, SourceMgr::DiagKind Kind, LineStr, ColRanges, FixIts); } -void SourceMgr::PrintMessage(SMLoc Loc, SourceMgr::DiagKind Kind, +void SourceMgr::PrintMessage(raw_ostream &OS, SMLoc Loc, + SourceMgr::DiagKind Kind, const Twine &Msg, ArrayRef<SMRange> Ranges, ArrayRef<SMFixIt> FixIts, bool ShowColors) const { SMDiagnostic Diagnostic = GetMessage(Loc, Kind, Msg, Ranges, FixIts); @@ -222,8 +223,6 @@ void SourceMgr::PrintMessage(SMLoc Loc, SourceMgr::DiagKind Kind, return; } - raw_ostream &OS = errs(); - if (Loc != SMLoc()) { int CurBuf = FindBufferContainingLoc(Loc); assert(CurBuf != -1 && "Invalid or unspecified location!"); @@ -233,6 +232,12 @@ void SourceMgr::PrintMessage(SMLoc Loc, SourceMgr::DiagKind Kind, Diagnostic.print(0, OS, ShowColors); } +void SourceMgr::PrintMessage(SMLoc Loc, SourceMgr::DiagKind Kind, + const Twine &Msg, ArrayRef<SMRange> Ranges, + ArrayRef<SMFixIt> FixIts, bool ShowColors) const { + PrintMessage(llvm::errs(), Loc, Kind, Msg, Ranges, FixIts, ShowColors); +} + //===----------------------------------------------------------------------===// // SMDiagnostic Implementation //===----------------------------------------------------------------------===// @@ -465,7 +470,7 @@ void SMDiagnostic::print(const char *ProgName, raw_ostream &S, if (FixItInsertionLine.empty()) return; - for (size_t i = 0, e = FixItInsertionLine.size(), OutCol = 0; i != e; ++i) { + for (size_t i = 0, e = FixItInsertionLine.size(), OutCol = 0; i < e; ++i) { if (i >= LineContents.size() || LineContents[i] != '\t') { S << FixItInsertionLine[i]; ++OutCol; diff --git a/contrib/llvm/lib/Support/StreamableMemoryObject.cpp b/contrib/llvm/lib/Support/StreamableMemoryObject.cpp index 59e27a2..2ed7c5c 100644 --- a/contrib/llvm/lib/Support/StreamableMemoryObject.cpp +++ b/contrib/llvm/lib/Support/StreamableMemoryObject.cpp @@ -31,8 +31,7 @@ public: virtual int readByte(uint64_t address, uint8_t* ptr) const LLVM_OVERRIDE; virtual int readBytes(uint64_t address, uint64_t size, - uint8_t* buf, - uint64_t* copied) const LLVM_OVERRIDE; + uint8_t *buf) const LLVM_OVERRIDE; virtual const uint8_t *getPointer(uint64_t address, uint64_t size) const LLVM_OVERRIDE; virtual bool isValidAddress(uint64_t address) const LLVM_OVERRIDE { @@ -67,11 +66,9 @@ int RawMemoryObject::readByte(uint64_t address, uint8_t* ptr) const { int RawMemoryObject::readBytes(uint64_t address, uint64_t size, - uint8_t* buf, - uint64_t* copied) const { + uint8_t *buf) const { if (!validAddress(address) || !validAddress(address + size - 1)) return -1; memcpy(buf, (uint8_t *)(uintptr_t)(address + FirstChar), size); - if (copied) *copied = size; return size; } @@ -111,11 +108,9 @@ int StreamingMemoryObject::readByte(uint64_t address, uint8_t* ptr) const { int StreamingMemoryObject::readBytes(uint64_t address, uint64_t size, - uint8_t* buf, - uint64_t* copied) const { + uint8_t *buf) const { if (!fetchToPos(address + size - 1)) return -1; memcpy(buf, &Bytes[address + BytesSkipped], size); - if (copied) *copied = size; return 0; } diff --git a/contrib/llvm/lib/Support/StringRef.cpp b/contrib/llvm/lib/Support/StringRef.cpp index d7a0bfa..bfae754 100644 --- a/contrib/llvm/lib/Support/StringRef.cpp +++ b/contrib/llvm/lib/Support/StringRef.cpp @@ -37,20 +37,39 @@ static bool ascii_isdigit(char x) { return x >= '0' && x <= '9'; } -/// compare_lower - Compare strings, ignoring case. -int StringRef::compare_lower(StringRef RHS) const { - for (size_t I = 0, E = min(Length, RHS.Length); I != E; ++I) { - unsigned char LHC = ascii_tolower(Data[I]); - unsigned char RHC = ascii_tolower(RHS.Data[I]); +// strncasecmp() is not available on non-POSIX systems, so define an +// alternative function here. +static int ascii_strncasecmp(const char *LHS, const char *RHS, size_t Length) { + for (size_t I = 0; I < Length; ++I) { + unsigned char LHC = ascii_tolower(LHS[I]); + unsigned char RHC = ascii_tolower(RHS[I]); if (LHC != RHC) return LHC < RHC ? -1 : 1; } + return 0; +} +/// compare_lower - Compare strings, ignoring case. +int StringRef::compare_lower(StringRef RHS) const { + if (int Res = ascii_strncasecmp(Data, RHS.Data, min(Length, RHS.Length))) + return Res; if (Length == RHS.Length) return 0; return Length < RHS.Length ? -1 : 1; } +/// Check if this string starts with the given \p Prefix, ignoring case. +bool StringRef::startswith_lower(StringRef Prefix) const { + return Length >= Prefix.Length && + ascii_strncasecmp(Data, Prefix.Data, Prefix.Length) == 0; +} + +/// Check if this string ends with the given \p Suffix, ignoring case. +bool StringRef::endswith_lower(StringRef Suffix) const { + return Length >= Suffix.Length && + ascii_strncasecmp(end() - Suffix.Length, Suffix.Data, Suffix.Length) == 0; +} + /// compare_numeric - Compare strings, handle embedded numbers. int StringRef::compare_numeric(StringRef RHS) const { for (size_t I = 0, E = min(Length, RHS.Length); I != E; ++I) { @@ -85,7 +104,7 @@ int StringRef::compare_numeric(StringRef RHS) const { // Compute the edit distance between the two given strings. unsigned StringRef::edit_distance(llvm::StringRef Other, bool AllowReplacements, - unsigned MaxEditDistance) { + unsigned MaxEditDistance) const { return llvm::ComputeEditDistance( llvm::ArrayRef<char>(data(), size()), llvm::ArrayRef<char>(Other.data(), Other.size()), diff --git a/contrib/llvm/lib/Support/StringRefMemoryObject.cpp b/contrib/llvm/lib/Support/StringRefMemoryObject.cpp new file mode 100644 index 0000000..e035ed1 --- /dev/null +++ b/contrib/llvm/lib/Support/StringRefMemoryObject.cpp @@ -0,0 +1,29 @@ +//===- lib/Support/StringRefMemoryObject.cpp --------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/StringRefMemoryObject.h" + +using namespace llvm; + +int StringRefMemoryObject::readByte(uint64_t Addr, uint8_t *Byte) const { + if (Addr >= Base + getExtent() || Addr < Base) + return -1; + *Byte = Bytes[Addr - Base]; + return 0; +} + +int StringRefMemoryObject::readBytes(uint64_t Addr, + uint64_t Size, + uint8_t *Buf) const { + uint64_t Offset = Addr - Base; + if (Addr >= Base + getExtent() || Offset + Size > getExtent() || Addr < Base) + return -1; + memcpy(Buf, Bytes.data() + Offset, Size); + return 0; +} diff --git a/contrib/llvm/lib/Support/SystemUtils.cpp b/contrib/llvm/lib/Support/SystemUtils.cpp index 54b5e97..2036364 100644 --- a/contrib/llvm/lib/Support/SystemUtils.cpp +++ b/contrib/llvm/lib/Support/SystemUtils.cpp @@ -31,25 +31,3 @@ bool llvm::CheckBitcodeOutputToConsole(raw_ostream &stream_to_check, } return false; } - -/// PrependMainExecutablePath - Prepend the path to the program being executed -/// to \p ExeName, given the value of argv[0] and the address of main() -/// itself. This allows us to find another LLVM tool if it is built in the same -/// directory. An empty string is returned on error; note that this function -/// just mainpulates the path and doesn't check for executability. -/// @brief Find a named executable. -sys::Path llvm::PrependMainExecutablePath(const std::string &ExeName, - const char *Argv0, void *MainAddr) { - // Check the directory that the calling program is in. We can do - // this if ProgramPath contains at least one / character, indicating that it - // is a relative path to the executable itself. - sys::Path Result = sys::Path::GetMainExecutable(Argv0, MainAddr); - Result.eraseComponent(); - - if (!Result.isEmpty()) { - Result.appendComponent(ExeName); - Result.appendSuffix(sys::Path::GetEXESuffix()); - } - - return Result; -} diff --git a/contrib/llvm/lib/Support/TargetRegistry.cpp b/contrib/llvm/lib/Support/TargetRegistry.cpp index 9c81327..0c90c17 100644 --- a/contrib/llvm/lib/Support/TargetRegistry.cpp +++ b/contrib/llvm/lib/Support/TargetRegistry.cpp @@ -135,9 +135,9 @@ const Target *TargetRegistry::getClosestTargetForJIT(std::string &Error) { return TheTarget; } -static int TargetArraySortFn(const void *LHS, const void *RHS) { - typedef std::pair<StringRef, const Target*> pair_ty; - return ((const pair_ty*)LHS)->first.compare(((const pair_ty*)RHS)->first); +static int TargetArraySortFn(const std::pair<StringRef, const Target *> *LHS, + const std::pair<StringRef, const Target *> *RHS) { + return LHS->first.compare(RHS->first); } void TargetRegistry::printRegisteredTargetsForVersion() { diff --git a/contrib/llvm/lib/Support/ThreadLocal.cpp b/contrib/llvm/lib/Support/ThreadLocal.cpp index 0587aae..868b6ea 100644 --- a/contrib/llvm/lib/Support/ThreadLocal.cpp +++ b/contrib/llvm/lib/Support/ThreadLocal.cpp @@ -23,7 +23,7 @@ // Define all methods as no-ops if threading is explicitly disabled namespace llvm { using namespace sys; -ThreadLocalImpl::ThreadLocalImpl() { } +ThreadLocalImpl::ThreadLocalImpl() : data() { } ThreadLocalImpl::~ThreadLocalImpl() { } void ThreadLocalImpl::setInstance(const void* d) { typedef int SIZE_TOO_BIG[sizeof(d) <= sizeof(data) ? 1 : -1]; diff --git a/contrib/llvm/lib/Support/Timer.cpp b/contrib/llvm/lib/Support/Timer.cpp index 896d869..100b21e 100644 --- a/contrib/llvm/lib/Support/Timer.cpp +++ b/contrib/llvm/lib/Support/Timer.cpp @@ -66,8 +66,8 @@ raw_ostream *llvm::CreateInfoOutputFile() { // compensate for this, the test-suite Makefiles have code to delete the // info output file before running commands which write to it. std::string Error; - raw_ostream *Result = new raw_fd_ostream(OutputFilename.c_str(), - Error, raw_fd_ostream::F_Append); + raw_ostream *Result = + new raw_fd_ostream(OutputFilename.c_str(), Error, sys::fs::F_Append); if (Error.empty()) return Result; diff --git a/contrib/llvm/lib/Support/ToolOutputFile.cpp b/contrib/llvm/lib/Support/ToolOutputFile.cpp index e7ca927..5c1268a 100644 --- a/contrib/llvm/lib/Support/ToolOutputFile.cpp +++ b/contrib/llvm/lib/Support/ToolOutputFile.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "llvm/Support/ToolOutputFile.h" +#include "llvm/Support/FileSystem.h" #include "llvm/Support/Signals.h" using namespace llvm; @@ -19,25 +20,30 @@ tool_output_file::CleanupInstaller::CleanupInstaller(const char *filename) : Filename(filename), Keep(false) { // Arrange for the file to be deleted if the process is killed. if (Filename != "-") - sys::RemoveFileOnSignal(sys::Path(Filename)); + sys::RemoveFileOnSignal(Filename); } tool_output_file::CleanupInstaller::~CleanupInstaller() { // Delete the file if the client hasn't told us not to. - if (!Keep && Filename != "-") - sys::Path(Filename).eraseFromDisk(); + if (!Keep && Filename != "-") { + bool Existed; + sys::fs::remove(Filename, Existed); + } // Ok, the file is successfully written and closed, or deleted. There's no // further need to clean it up on signals. if (Filename != "-") - sys::DontRemoveFileOnSignal(sys::Path(Filename)); + sys::DontRemoveFileOnSignal(Filename); } tool_output_file::tool_output_file(const char *filename, std::string &ErrorInfo, - unsigned Flags) - : Installer(filename), - OS(filename, ErrorInfo, Flags) { + sys::fs::OpenFlags Flags) + : Installer(filename), OS(filename, ErrorInfo, Flags) { // If open fails, no cleanup is needed. if (!ErrorInfo.empty()) Installer.Keep = true; } + +tool_output_file::tool_output_file(const char *Filename, int FD) + : Installer(Filename), OS(FD, true) { +} diff --git a/contrib/llvm/lib/Support/Triple.cpp b/contrib/llvm/lib/Support/Triple.cpp index 412e34c..6c978a0 100644 --- a/contrib/llvm/lib/Support/Triple.cpp +++ b/contrib/llvm/lib/Support/Triple.cpp @@ -28,6 +28,7 @@ const char *Triple::getArchTypeName(ArchType Kind) { case mips64el:return "mips64el"; case msp430: return "msp430"; case ppc64: return "powerpc64"; + case ppc64le: return "powerpc64le"; case ppc: return "powerpc"; case r600: return "r600"; case sparc: return "sparc"; @@ -38,7 +39,6 @@ const char *Triple::getArchTypeName(ArchType Kind) { case x86: return "i386"; case x86_64: return "x86_64"; case xcore: return "xcore"; - case mblaze: return "mblaze"; case nvptx: return "nvptx"; case nvptx64: return "nvptx64"; case le32: return "le32"; @@ -61,10 +61,9 @@ const char *Triple::getArchTypePrefix(ArchType Kind) { case thumb: return "arm"; case ppc64: + case ppc64le: case ppc: return "ppc"; - case mblaze: return "mblaze"; - case mips: case mipsel: case mips64: @@ -104,6 +103,7 @@ const char *Triple::getVendorTypeName(VendorType Kind) { case BGQ: return "bgq"; case Freescale: return "fsl"; case IBM: return "ibm"; + case NVIDIA: return "nvidia"; } llvm_unreachable("Invalid VendorType!"); @@ -135,6 +135,8 @@ const char *Triple::getOSTypeName(OSType Kind) { case CNK: return "cnk"; case Bitrig: return "bitrig"; case AIX: return "aix"; + case CUDA: return "cuda"; + case NVCL: return "nvcl"; } llvm_unreachable("Invalid OSType"); @@ -168,7 +170,7 @@ Triple::ArchType Triple::getArchTypeForLLVMName(StringRef Name) { .Case("ppc64", ppc64) .Case("ppc32", ppc) .Case("ppc", ppc) - .Case("mblaze", mblaze) + .Case("ppc64le", ppc64le) .Case("r600", r600) .Case("hexagon", hexagon) .Case("sparc", sparc) @@ -198,7 +200,7 @@ const char *Triple::getArchNameForAssembler() { .Case("x86_64", "x86_64") .Case("powerpc", "ppc") .Case("powerpc64", "ppc64") - .Cases("mblaze", "microblaze", "mblaze") + .Case("powerpc64le", "ppc64le") .Case("arm", "arm") .Cases("armv4t", "thumbv4t", "armv4t") .Cases("armv5", "armv5e", "thumbv5", "thumbv5e", "armv5") @@ -219,10 +221,10 @@ static Triple::ArchType parseArch(StringRef ArchName) { .Cases("i386", "i486", "i586", "i686", Triple::x86) // FIXME: Do we need to support these? .Cases("i786", "i886", "i986", Triple::x86) - .Cases("amd64", "x86_64", Triple::x86_64) + .Cases("amd64", "x86_64", "x86_64h", Triple::x86_64) .Case("powerpc", Triple::ppc) .Cases("powerpc64", "ppu", Triple::ppc64) - .Case("mblaze", Triple::mblaze) + .Case("powerpc64le", Triple::ppc64le) .Case("aarch64", Triple::aarch64) .Cases("arm", "xscale", Triple::arm) // FIXME: It would be good to replace these with explicit names for all the @@ -239,7 +241,7 @@ static Triple::ArchType parseArch(StringRef ArchName) { .Case("hexagon", Triple::hexagon) .Case("s390x", Triple::systemz) .Case("sparc", Triple::sparc) - .Case("sparcv9", Triple::sparcv9) + .Cases("sparcv9", "sparc64", Triple::sparcv9) .Case("tce", Triple::tce) .Case("xcore", Triple::xcore) .Case("nvptx", Triple::nvptx) @@ -260,6 +262,7 @@ static Triple::VendorType parseVendor(StringRef VendorName) { .Case("bgq", Triple::BGQ) .Case("fsl", Triple::Freescale) .Case("ibm", Triple::IBM) + .Case("nvidia", Triple::NVIDIA) .Default(Triple::UnknownVendor); } @@ -287,6 +290,8 @@ static Triple::OSType parseOS(StringRef OSName) { .StartsWith("cnk", Triple::CNK) .StartsWith("bitrig", Triple::Bitrig) .StartsWith("aix", Triple::AIX) + .StartsWith("cuda", Triple::CUDA) + .StartsWith("nvcl", Triple::NVCL) .Default(Triple::UnknownOS); } @@ -672,7 +677,6 @@ static unsigned getArchPointerBitWidth(llvm::Triple::ArchType Arch) { case llvm::Triple::arm: case llvm::Triple::hexagon: case llvm::Triple::le32: - case llvm::Triple::mblaze: case llvm::Triple::mips: case llvm::Triple::mipsel: case llvm::Triple::nvptx: @@ -691,6 +695,7 @@ static unsigned getArchPointerBitWidth(llvm::Triple::ArchType Arch) { case llvm::Triple::mips64el: case llvm::Triple::nvptx64: case llvm::Triple::ppc64: + case llvm::Triple::ppc64le: case llvm::Triple::sparcv9: case llvm::Triple::systemz: case llvm::Triple::x86_64: @@ -719,6 +724,7 @@ Triple Triple::get32BitArchVariant() const { case Triple::aarch64: case Triple::msp430: case Triple::systemz: + case Triple::ppc64le: T.setArch(UnknownArch); break; @@ -727,7 +733,6 @@ Triple Triple::get32BitArchVariant() const { case Triple::arm: case Triple::hexagon: case Triple::le32: - case Triple::mblaze: case Triple::mips: case Triple::mipsel: case Triple::nvptx: @@ -760,7 +765,6 @@ Triple Triple::get64BitArchVariant() const { case Triple::arm: case Triple::hexagon: case Triple::le32: - case Triple::mblaze: case Triple::msp430: case Triple::r600: case Triple::tce: @@ -775,6 +779,7 @@ Triple Triple::get64BitArchVariant() const { case Triple::mips64el: case Triple::nvptx64: case Triple::ppc64: + case Triple::ppc64le: case Triple::sparcv9: case Triple::systemz: case Triple::x86_64: diff --git a/contrib/llvm/lib/Support/Unicode.cpp b/contrib/llvm/lib/Support/Unicode.cpp new file mode 100644 index 0000000..b719bd8 --- /dev/null +++ b/contrib/llvm/lib/Support/Unicode.cpp @@ -0,0 +1,367 @@ +//===- llvm/Support/Unicode.cpp - Unicode character properties -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements functions that allow querying certain properties of +// Unicode characters. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/Unicode.h" +#include "llvm/Support/ConvertUTF.h" +#include "llvm/Support/UnicodeCharRanges.h" + +namespace llvm { +namespace sys { +namespace unicode { + +bool isPrintable(int UCS) { + // Sorted list of non-overlapping intervals of code points that are not + // supposed to be printable. + static const UnicodeCharRange NonPrintableRanges[] = { + { 0x0000, 0x001F }, { 0x007F, 0x009F }, { 0x034F, 0x034F }, + { 0x0378, 0x0379 }, { 0x037F, 0x0383 }, { 0x038B, 0x038B }, + { 0x038D, 0x038D }, { 0x03A2, 0x03A2 }, { 0x0528, 0x0530 }, + { 0x0557, 0x0558 }, { 0x0560, 0x0560 }, { 0x0588, 0x0588 }, + { 0x058B, 0x058E }, { 0x0590, 0x0590 }, { 0x05C8, 0x05CF }, + { 0x05EB, 0x05EF }, { 0x05F5, 0x0605 }, { 0x061C, 0x061D }, + { 0x06DD, 0x06DD }, { 0x070E, 0x070F }, { 0x074B, 0x074C }, + { 0x07B2, 0x07BF }, { 0x07FB, 0x07FF }, { 0x082E, 0x082F }, + { 0x083F, 0x083F }, { 0x085C, 0x085D }, { 0x085F, 0x089F }, + { 0x08A1, 0x08A1 }, { 0x08AD, 0x08E3 }, { 0x08FF, 0x08FF }, + { 0x0978, 0x0978 }, { 0x0980, 0x0980 }, { 0x0984, 0x0984 }, + { 0x098D, 0x098E }, { 0x0991, 0x0992 }, { 0x09A9, 0x09A9 }, + { 0x09B1, 0x09B1 }, { 0x09B3, 0x09B5 }, { 0x09BA, 0x09BB }, + { 0x09C5, 0x09C6 }, { 0x09C9, 0x09CA }, { 0x09CF, 0x09D6 }, + { 0x09D8, 0x09DB }, { 0x09DE, 0x09DE }, { 0x09E4, 0x09E5 }, + { 0x09FC, 0x0A00 }, { 0x0A04, 0x0A04 }, { 0x0A0B, 0x0A0E }, + { 0x0A11, 0x0A12 }, { 0x0A29, 0x0A29 }, { 0x0A31, 0x0A31 }, + { 0x0A34, 0x0A34 }, { 0x0A37, 0x0A37 }, { 0x0A3A, 0x0A3B }, + { 0x0A3D, 0x0A3D }, { 0x0A43, 0x0A46 }, { 0x0A49, 0x0A4A }, + { 0x0A4E, 0x0A50 }, { 0x0A52, 0x0A58 }, { 0x0A5D, 0x0A5D }, + { 0x0A5F, 0x0A65 }, { 0x0A76, 0x0A80 }, { 0x0A84, 0x0A84 }, + { 0x0A8E, 0x0A8E }, { 0x0A92, 0x0A92 }, { 0x0AA9, 0x0AA9 }, + { 0x0AB1, 0x0AB1 }, { 0x0AB4, 0x0AB4 }, { 0x0ABA, 0x0ABB }, + { 0x0AC6, 0x0AC6 }, { 0x0ACA, 0x0ACA }, { 0x0ACE, 0x0ACF }, + { 0x0AD1, 0x0ADF }, { 0x0AE4, 0x0AE5 }, { 0x0AF2, 0x0B00 }, + { 0x0B04, 0x0B04 }, { 0x0B0D, 0x0B0E }, { 0x0B11, 0x0B12 }, + { 0x0B29, 0x0B29 }, { 0x0B31, 0x0B31 }, { 0x0B34, 0x0B34 }, + { 0x0B3A, 0x0B3B }, { 0x0B45, 0x0B46 }, { 0x0B49, 0x0B4A }, + { 0x0B4E, 0x0B55 }, { 0x0B58, 0x0B5B }, { 0x0B5E, 0x0B5E }, + { 0x0B64, 0x0B65 }, { 0x0B78, 0x0B81 }, { 0x0B84, 0x0B84 }, + { 0x0B8B, 0x0B8D }, { 0x0B91, 0x0B91 }, { 0x0B96, 0x0B98 }, + { 0x0B9B, 0x0B9B }, { 0x0B9D, 0x0B9D }, { 0x0BA0, 0x0BA2 }, + { 0x0BA5, 0x0BA7 }, { 0x0BAB, 0x0BAD }, { 0x0BBA, 0x0BBD }, + { 0x0BC3, 0x0BC5 }, { 0x0BC9, 0x0BC9 }, { 0x0BCE, 0x0BCF }, + { 0x0BD1, 0x0BD6 }, { 0x0BD8, 0x0BE5 }, { 0x0BFB, 0x0C00 }, + { 0x0C04, 0x0C04 }, { 0x0C0D, 0x0C0D }, { 0x0C11, 0x0C11 }, + { 0x0C29, 0x0C29 }, { 0x0C34, 0x0C34 }, { 0x0C3A, 0x0C3C }, + { 0x0C45, 0x0C45 }, { 0x0C49, 0x0C49 }, { 0x0C4E, 0x0C54 }, + { 0x0C57, 0x0C57 }, { 0x0C5A, 0x0C5F }, { 0x0C64, 0x0C65 }, + { 0x0C70, 0x0C77 }, { 0x0C80, 0x0C81 }, { 0x0C84, 0x0C84 }, + { 0x0C8D, 0x0C8D }, { 0x0C91, 0x0C91 }, { 0x0CA9, 0x0CA9 }, + { 0x0CB4, 0x0CB4 }, { 0x0CBA, 0x0CBB }, { 0x0CC5, 0x0CC5 }, + { 0x0CC9, 0x0CC9 }, { 0x0CCE, 0x0CD4 }, { 0x0CD7, 0x0CDD }, + { 0x0CDF, 0x0CDF }, { 0x0CE4, 0x0CE5 }, { 0x0CF0, 0x0CF0 }, + { 0x0CF3, 0x0D01 }, { 0x0D04, 0x0D04 }, { 0x0D0D, 0x0D0D }, + { 0x0D11, 0x0D11 }, { 0x0D3B, 0x0D3C }, { 0x0D45, 0x0D45 }, + { 0x0D49, 0x0D49 }, { 0x0D4F, 0x0D56 }, { 0x0D58, 0x0D5F }, + { 0x0D64, 0x0D65 }, { 0x0D76, 0x0D78 }, { 0x0D80, 0x0D81 }, + { 0x0D84, 0x0D84 }, { 0x0D97, 0x0D99 }, { 0x0DB2, 0x0DB2 }, + { 0x0DBC, 0x0DBC }, { 0x0DBE, 0x0DBF }, { 0x0DC7, 0x0DC9 }, + { 0x0DCB, 0x0DCE }, { 0x0DD5, 0x0DD5 }, { 0x0DD7, 0x0DD7 }, + { 0x0DE0, 0x0DF1 }, { 0x0DF5, 0x0E00 }, { 0x0E3B, 0x0E3E }, + { 0x0E5C, 0x0E80 }, { 0x0E83, 0x0E83 }, { 0x0E85, 0x0E86 }, + { 0x0E89, 0x0E89 }, { 0x0E8B, 0x0E8C }, { 0x0E8E, 0x0E93 }, + { 0x0E98, 0x0E98 }, { 0x0EA0, 0x0EA0 }, { 0x0EA4, 0x0EA4 }, + { 0x0EA6, 0x0EA6 }, { 0x0EA8, 0x0EA9 }, { 0x0EAC, 0x0EAC }, + { 0x0EBA, 0x0EBA }, { 0x0EBE, 0x0EBF }, { 0x0EC5, 0x0EC5 }, + { 0x0EC7, 0x0EC7 }, { 0x0ECE, 0x0ECF }, { 0x0EDA, 0x0EDB }, + { 0x0EE0, 0x0EFF }, { 0x0F48, 0x0F48 }, { 0x0F6D, 0x0F70 }, + { 0x0F98, 0x0F98 }, { 0x0FBD, 0x0FBD }, { 0x0FCD, 0x0FCD }, + { 0x0FDB, 0x0FFF }, { 0x10C6, 0x10C6 }, { 0x10C8, 0x10CC }, + { 0x10CE, 0x10CF }, { 0x115F, 0x1160 }, { 0x1249, 0x1249 }, + { 0x124E, 0x124F }, { 0x1257, 0x1257 }, { 0x1259, 0x1259 }, + { 0x125E, 0x125F }, { 0x1289, 0x1289 }, { 0x128E, 0x128F }, + { 0x12B1, 0x12B1 }, { 0x12B6, 0x12B7 }, { 0x12BF, 0x12BF }, + { 0x12C1, 0x12C1 }, { 0x12C6, 0x12C7 }, { 0x12D7, 0x12D7 }, + { 0x1311, 0x1311 }, { 0x1316, 0x1317 }, { 0x135B, 0x135C }, + { 0x137D, 0x137F }, { 0x139A, 0x139F }, { 0x13F5, 0x13FF }, + { 0x169D, 0x169F }, { 0x16F1, 0x16FF }, { 0x170D, 0x170D }, + { 0x1715, 0x171F }, { 0x1737, 0x173F }, { 0x1754, 0x175F }, + { 0x176D, 0x176D }, { 0x1771, 0x1771 }, { 0x1774, 0x177F }, + { 0x17B4, 0x17B5 }, { 0x17DE, 0x17DF }, { 0x17EA, 0x17EF }, + { 0x17FA, 0x17FF }, { 0x180B, 0x180D }, { 0x180F, 0x180F }, + { 0x181A, 0x181F }, { 0x1878, 0x187F }, { 0x18AB, 0x18AF }, + { 0x18F6, 0x18FF }, { 0x191D, 0x191F }, { 0x192C, 0x192F }, + { 0x193C, 0x193F }, { 0x1941, 0x1943 }, { 0x196E, 0x196F }, + { 0x1975, 0x197F }, { 0x19AC, 0x19AF }, { 0x19CA, 0x19CF }, + { 0x19DB, 0x19DD }, { 0x1A1C, 0x1A1D }, { 0x1A5F, 0x1A5F }, + { 0x1A7D, 0x1A7E }, { 0x1A8A, 0x1A8F }, { 0x1A9A, 0x1A9F }, + { 0x1AAE, 0x1AFF }, { 0x1B4C, 0x1B4F }, { 0x1B7D, 0x1B7F }, + { 0x1BF4, 0x1BFB }, { 0x1C38, 0x1C3A }, { 0x1C4A, 0x1C4C }, + { 0x1C80, 0x1CBF }, { 0x1CC8, 0x1CCF }, { 0x1CF7, 0x1CFF }, + { 0x1DE7, 0x1DFB }, { 0x1F16, 0x1F17 }, { 0x1F1E, 0x1F1F }, + { 0x1F46, 0x1F47 }, { 0x1F4E, 0x1F4F }, { 0x1F58, 0x1F58 }, + { 0x1F5A, 0x1F5A }, { 0x1F5C, 0x1F5C }, { 0x1F5E, 0x1F5E }, + { 0x1F7E, 0x1F7F }, { 0x1FB5, 0x1FB5 }, { 0x1FC5, 0x1FC5 }, + { 0x1FD4, 0x1FD5 }, { 0x1FDC, 0x1FDC }, { 0x1FF0, 0x1FF1 }, + { 0x1FF5, 0x1FF5 }, { 0x1FFF, 0x1FFF }, { 0x200B, 0x200F }, + { 0x202A, 0x202E }, { 0x2060, 0x206F }, { 0x2072, 0x2073 }, + { 0x208F, 0x208F }, { 0x209D, 0x209F }, { 0x20BB, 0x20CF }, + { 0x20F1, 0x20FF }, { 0x218A, 0x218F }, { 0x23F4, 0x23FF }, + { 0x2427, 0x243F }, { 0x244B, 0x245F }, { 0x2700, 0x2700 }, + { 0x2B4D, 0x2B4F }, { 0x2B5A, 0x2BFF }, { 0x2C2F, 0x2C2F }, + { 0x2C5F, 0x2C5F }, { 0x2CF4, 0x2CF8 }, { 0x2D26, 0x2D26 }, + { 0x2D28, 0x2D2C }, { 0x2D2E, 0x2D2F }, { 0x2D68, 0x2D6E }, + { 0x2D71, 0x2D7E }, { 0x2D97, 0x2D9F }, { 0x2DA7, 0x2DA7 }, + { 0x2DAF, 0x2DAF }, { 0x2DB7, 0x2DB7 }, { 0x2DBF, 0x2DBF }, + { 0x2DC7, 0x2DC7 }, { 0x2DCF, 0x2DCF }, { 0x2DD7, 0x2DD7 }, + { 0x2DDF, 0x2DDF }, { 0x2E3C, 0x2E7F }, { 0x2E9A, 0x2E9A }, + { 0x2EF4, 0x2EFF }, { 0x2FD6, 0x2FEF }, { 0x2FFC, 0x2FFF }, + { 0x3040, 0x3040 }, { 0x3097, 0x3098 }, { 0x3100, 0x3104 }, + { 0x312E, 0x3130 }, { 0x3164, 0x3164 }, { 0x318F, 0x318F }, + { 0x31BB, 0x31BF }, { 0x31E4, 0x31EF }, { 0x321F, 0x321F }, + { 0x32FF, 0x32FF }, { 0x4DB6, 0x4DBF }, { 0x9FCD, 0x9FFF }, + { 0xA48D, 0xA48F }, { 0xA4C7, 0xA4CF }, { 0xA62C, 0xA63F }, + { 0xA698, 0xA69E }, { 0xA6F8, 0xA6FF }, { 0xA78F, 0xA78F }, + { 0xA794, 0xA79F }, { 0xA7AB, 0xA7F7 }, { 0xA82C, 0xA82F }, + { 0xA83A, 0xA83F }, { 0xA878, 0xA87F }, { 0xA8C5, 0xA8CD }, + { 0xA8DA, 0xA8DF }, { 0xA8FC, 0xA8FF }, { 0xA954, 0xA95E }, + { 0xA97D, 0xA97F }, { 0xA9CE, 0xA9CE }, { 0xA9DA, 0xA9DD }, + { 0xA9E0, 0xA9FF }, { 0xAA37, 0xAA3F }, { 0xAA4E, 0xAA4F }, + { 0xAA5A, 0xAA5B }, { 0xAA7C, 0xAA7F }, { 0xAAC3, 0xAADA }, + { 0xAAF7, 0xAB00 }, { 0xAB07, 0xAB08 }, { 0xAB0F, 0xAB10 }, + { 0xAB17, 0xAB1F }, { 0xAB27, 0xAB27 }, { 0xAB2F, 0xABBF }, + { 0xABEE, 0xABEF }, { 0xABFA, 0xABFF }, { 0xD7A4, 0xD7AF }, + { 0xD7C7, 0xD7CA }, { 0xD7FC, 0xDFFF }, { 0xFA6E, 0xFA6F }, + { 0xFADA, 0xFAFF }, { 0xFB07, 0xFB12 }, { 0xFB18, 0xFB1C }, + { 0xFB37, 0xFB37 }, { 0xFB3D, 0xFB3D }, { 0xFB3F, 0xFB3F }, + { 0xFB42, 0xFB42 }, { 0xFB45, 0xFB45 }, { 0xFBC2, 0xFBD2 }, + { 0xFD40, 0xFD4F }, { 0xFD90, 0xFD91 }, { 0xFDC8, 0xFDEF }, + { 0xFDFE, 0xFE0F }, { 0xFE1A, 0xFE1F }, { 0xFE27, 0xFE2F }, + { 0xFE53, 0xFE53 }, { 0xFE67, 0xFE67 }, { 0xFE6C, 0xFE6F }, + { 0xFE75, 0xFE75 }, { 0xFEFD, 0xFEFF }, { 0xFF00, 0xFF00 }, + { 0xFFA0, 0xFFA0 }, { 0xFFBF, 0xFFC1 }, { 0xFFC8, 0xFFC9 }, + { 0xFFD0, 0xFFD1 }, { 0xFFD8, 0xFFD9 }, { 0xFFDD, 0xFFDF }, + { 0xFFE7, 0xFFE7 }, { 0xFFEF, 0xFFFB }, { 0xFFFE, 0xFFFF }, + { 0x1000C, 0x1000C }, { 0x10027, 0x10027 }, { 0x1003B, 0x1003B }, + { 0x1003E, 0x1003E }, { 0x1004E, 0x1004F }, { 0x1005E, 0x1007F }, + { 0x100FB, 0x100FF }, { 0x10103, 0x10106 }, { 0x10134, 0x10136 }, + { 0x1018B, 0x1018F }, { 0x1019C, 0x101CF }, { 0x101FE, 0x1027F }, + { 0x1029D, 0x1029F }, { 0x102D1, 0x102FF }, { 0x1031F, 0x1031F }, + { 0x10324, 0x1032F }, { 0x1034B, 0x1037F }, { 0x1039E, 0x1039E }, + { 0x103C4, 0x103C7 }, { 0x103D6, 0x103FF }, { 0x1049E, 0x1049F }, + { 0x104AA, 0x107FF }, { 0x10806, 0x10807 }, { 0x10809, 0x10809 }, + { 0x10836, 0x10836 }, { 0x10839, 0x1083B }, { 0x1083D, 0x1083E }, + { 0x10856, 0x10856 }, { 0x10860, 0x108FF }, { 0x1091C, 0x1091E }, + { 0x1093A, 0x1093E }, { 0x10940, 0x1097F }, { 0x109B8, 0x109BD }, + { 0x109C0, 0x109FF }, { 0x10A04, 0x10A04 }, { 0x10A07, 0x10A0B }, + { 0x10A14, 0x10A14 }, { 0x10A18, 0x10A18 }, { 0x10A34, 0x10A37 }, + { 0x10A3B, 0x10A3E }, { 0x10A48, 0x10A4F }, { 0x10A59, 0x10A5F }, + { 0x10A80, 0x10AFF }, { 0x10B36, 0x10B38 }, { 0x10B56, 0x10B57 }, + { 0x10B73, 0x10B77 }, { 0x10B80, 0x10BFF }, { 0x10C49, 0x10E5F }, + { 0x10E7F, 0x10FFF }, { 0x1104E, 0x11051 }, { 0x11070, 0x1107F }, + { 0x110BD, 0x110BD }, { 0x110C2, 0x110CF }, { 0x110E9, 0x110EF }, + { 0x110FA, 0x110FF }, { 0x11135, 0x11135 }, { 0x11144, 0x1117F }, + { 0x111C9, 0x111CF }, { 0x111DA, 0x1167F }, { 0x116B8, 0x116BF }, + { 0x116CA, 0x11FFF }, { 0x1236F, 0x123FF }, { 0x12463, 0x1246F }, + { 0x12474, 0x12FFF }, { 0x1342F, 0x167FF }, { 0x16A39, 0x16EFF }, + { 0x16F45, 0x16F4F }, { 0x16F7F, 0x16F8E }, { 0x16FA0, 0x1AFFF }, + { 0x1B002, 0x1CFFF }, { 0x1D0F6, 0x1D0FF }, { 0x1D127, 0x1D128 }, + { 0x1D173, 0x1D17A }, { 0x1D1DE, 0x1D1FF }, { 0x1D246, 0x1D2FF }, + { 0x1D357, 0x1D35F }, { 0x1D372, 0x1D3FF }, { 0x1D455, 0x1D455 }, + { 0x1D49D, 0x1D49D }, { 0x1D4A0, 0x1D4A1 }, { 0x1D4A3, 0x1D4A4 }, + { 0x1D4A7, 0x1D4A8 }, { 0x1D4AD, 0x1D4AD }, { 0x1D4BA, 0x1D4BA }, + { 0x1D4BC, 0x1D4BC }, { 0x1D4C4, 0x1D4C4 }, { 0x1D506, 0x1D506 }, + { 0x1D50B, 0x1D50C }, { 0x1D515, 0x1D515 }, { 0x1D51D, 0x1D51D }, + { 0x1D53A, 0x1D53A }, { 0x1D53F, 0x1D53F }, { 0x1D545, 0x1D545 }, + { 0x1D547, 0x1D549 }, { 0x1D551, 0x1D551 }, { 0x1D6A6, 0x1D6A7 }, + { 0x1D7CC, 0x1D7CD }, { 0x1D800, 0x1EDFF }, { 0x1EE04, 0x1EE04 }, + { 0x1EE20, 0x1EE20 }, { 0x1EE23, 0x1EE23 }, { 0x1EE25, 0x1EE26 }, + { 0x1EE28, 0x1EE28 }, { 0x1EE33, 0x1EE33 }, { 0x1EE38, 0x1EE38 }, + { 0x1EE3A, 0x1EE3A }, { 0x1EE3C, 0x1EE41 }, { 0x1EE43, 0x1EE46 }, + { 0x1EE48, 0x1EE48 }, { 0x1EE4A, 0x1EE4A }, { 0x1EE4C, 0x1EE4C }, + { 0x1EE50, 0x1EE50 }, { 0x1EE53, 0x1EE53 }, { 0x1EE55, 0x1EE56 }, + { 0x1EE58, 0x1EE58 }, { 0x1EE5A, 0x1EE5A }, { 0x1EE5C, 0x1EE5C }, + { 0x1EE5E, 0x1EE5E }, { 0x1EE60, 0x1EE60 }, { 0x1EE63, 0x1EE63 }, + { 0x1EE65, 0x1EE66 }, { 0x1EE6B, 0x1EE6B }, { 0x1EE73, 0x1EE73 }, + { 0x1EE78, 0x1EE78 }, { 0x1EE7D, 0x1EE7D }, { 0x1EE7F, 0x1EE7F }, + { 0x1EE8A, 0x1EE8A }, { 0x1EE9C, 0x1EEA0 }, { 0x1EEA4, 0x1EEA4 }, + { 0x1EEAA, 0x1EEAA }, { 0x1EEBC, 0x1EEEF }, { 0x1EEF2, 0x1EFFF }, + { 0x1F02C, 0x1F02F }, { 0x1F094, 0x1F09F }, { 0x1F0AF, 0x1F0B0 }, + { 0x1F0BF, 0x1F0C0 }, { 0x1F0D0, 0x1F0D0 }, { 0x1F0E0, 0x1F0FF }, + { 0x1F10B, 0x1F10F }, { 0x1F12F, 0x1F12F }, { 0x1F16C, 0x1F16F }, + { 0x1F19B, 0x1F1E5 }, { 0x1F203, 0x1F20F }, { 0x1F23B, 0x1F23F }, + { 0x1F249, 0x1F24F }, { 0x1F252, 0x1F2FF }, { 0x1F321, 0x1F32F }, + { 0x1F336, 0x1F336 }, { 0x1F37D, 0x1F37F }, { 0x1F394, 0x1F39F }, + { 0x1F3C5, 0x1F3C5 }, { 0x1F3CB, 0x1F3DF }, { 0x1F3F1, 0x1F3FF }, + { 0x1F43F, 0x1F43F }, { 0x1F441, 0x1F441 }, { 0x1F4F8, 0x1F4F8 }, + { 0x1F4FD, 0x1F4FF }, { 0x1F53E, 0x1F53F }, { 0x1F544, 0x1F54F }, + { 0x1F568, 0x1F5FA }, { 0x1F641, 0x1F644 }, { 0x1F650, 0x1F67F }, + { 0x1F6C6, 0x1F6FF }, { 0x1F774, 0x1FFFF }, { 0x2A6D7, 0x2A6FF }, + { 0x2B735, 0x2B73F }, { 0x2B81E, 0x2F7FF }, { 0x2FA1E, 0xF0000 }, + { 0xFFFFE, 0xFFFFF }, { 0x10FFFE, 0x10FFFF } + }; + static const UnicodeCharSet NonPrintables(NonPrintableRanges); + + return UCS >= 0 && UCS <= 0x10FFFF && !NonPrintables.contains(UCS); +} + +/// Gets the number of positions a character is likely to occupy when output +/// on a terminal ("character width"). This depends on the implementation of the +/// terminal, and there's no standard definition of character width. +/// The implementation defines it in a way that is expected to be compatible +/// with a generic Unicode-capable terminal. +/// \return Character width: +/// * ErrorNonPrintableCharacter (-1) for non-printable characters (as +/// identified by isPrintable); +/// * 0 for non-spacing and enclosing combining marks; +/// * 2 for CJK characters excluding halfwidth forms; +/// * 1 for all remaining characters. +static inline int charWidth(int UCS) +{ + if (!isPrintable(UCS)) + return ErrorNonPrintableCharacter; + + // Sorted list of non-spacing and enclosing combining mark intervals as + // defined in "3.6 Combination" of + // http://www.unicode.org/versions/Unicode6.2.0/UnicodeStandard-6.2.pdf + static const UnicodeCharRange CombiningCharacterRanges[] = { + { 0x0300, 0x036F }, { 0x0483, 0x0489 }, { 0x0591, 0x05BD }, + { 0x05BF, 0x05BF }, { 0x05C1, 0x05C2 }, { 0x05C4, 0x05C5 }, + { 0x05C7, 0x05C7 }, { 0x0610, 0x061A }, { 0x064B, 0x065F }, + { 0x0670, 0x0670 }, { 0x06D6, 0x06DC }, { 0x06DF, 0x06E4 }, + { 0x06E7, 0x06E8 }, { 0x06EA, 0x06ED }, { 0x0711, 0x0711 }, + { 0x0730, 0x074A }, { 0x07A6, 0x07B0 }, { 0x07EB, 0x07F3 }, + { 0x0816, 0x0819 }, { 0x081B, 0x0823 }, { 0x0825, 0x0827 }, + { 0x0829, 0x082D }, { 0x0859, 0x085B }, { 0x08E4, 0x08FE }, + { 0x0900, 0x0902 }, { 0x093A, 0x093A }, { 0x093C, 0x093C }, + { 0x0941, 0x0948 }, { 0x094D, 0x094D }, { 0x0951, 0x0957 }, + { 0x0962, 0x0963 }, { 0x0981, 0x0981 }, { 0x09BC, 0x09BC }, + { 0x09C1, 0x09C4 }, { 0x09CD, 0x09CD }, { 0x09E2, 0x09E3 }, + { 0x0A01, 0x0A02 }, { 0x0A3C, 0x0A3C }, { 0x0A41, 0x0A42 }, + { 0x0A47, 0x0A48 }, { 0x0A4B, 0x0A4D }, { 0x0A51, 0x0A51 }, + { 0x0A70, 0x0A71 }, { 0x0A75, 0x0A75 }, { 0x0A81, 0x0A82 }, + { 0x0ABC, 0x0ABC }, { 0x0AC1, 0x0AC5 }, { 0x0AC7, 0x0AC8 }, + { 0x0ACD, 0x0ACD }, { 0x0AE2, 0x0AE3 }, { 0x0B01, 0x0B01 }, + { 0x0B3C, 0x0B3C }, { 0x0B3F, 0x0B3F }, { 0x0B41, 0x0B44 }, + { 0x0B4D, 0x0B4D }, { 0x0B56, 0x0B56 }, { 0x0B62, 0x0B63 }, + { 0x0B82, 0x0B82 }, { 0x0BC0, 0x0BC0 }, { 0x0BCD, 0x0BCD }, + { 0x0C3E, 0x0C40 }, { 0x0C46, 0x0C48 }, { 0x0C4A, 0x0C4D }, + { 0x0C55, 0x0C56 }, { 0x0C62, 0x0C63 }, { 0x0CBC, 0x0CBC }, + { 0x0CBF, 0x0CBF }, { 0x0CC6, 0x0CC6 }, { 0x0CCC, 0x0CCD }, + { 0x0CE2, 0x0CE3 }, { 0x0D41, 0x0D44 }, { 0x0D4D, 0x0D4D }, + { 0x0D62, 0x0D63 }, { 0x0DCA, 0x0DCA }, { 0x0DD2, 0x0DD4 }, + { 0x0DD6, 0x0DD6 }, { 0x0E31, 0x0E31 }, { 0x0E34, 0x0E3A }, + { 0x0E47, 0x0E4E }, { 0x0EB1, 0x0EB1 }, { 0x0EB4, 0x0EB9 }, + { 0x0EBB, 0x0EBC }, { 0x0EC8, 0x0ECD }, { 0x0F18, 0x0F19 }, + { 0x0F35, 0x0F35 }, { 0x0F37, 0x0F37 }, { 0x0F39, 0x0F39 }, + { 0x0F71, 0x0F7E }, { 0x0F80, 0x0F84 }, { 0x0F86, 0x0F87 }, + { 0x0F8D, 0x0F97 }, { 0x0F99, 0x0FBC }, { 0x0FC6, 0x0FC6 }, + { 0x102D, 0x1030 }, { 0x1032, 0x1037 }, { 0x1039, 0x103A }, + { 0x103D, 0x103E }, { 0x1058, 0x1059 }, { 0x105E, 0x1060 }, + { 0x1071, 0x1074 }, { 0x1082, 0x1082 }, { 0x1085, 0x1086 }, + { 0x108D, 0x108D }, { 0x109D, 0x109D }, { 0x135D, 0x135F }, + { 0x1712, 0x1714 }, { 0x1732, 0x1734 }, { 0x1752, 0x1753 }, + { 0x1772, 0x1773 }, { 0x17B4, 0x17B5 }, { 0x17B7, 0x17BD }, + { 0x17C6, 0x17C6 }, { 0x17C9, 0x17D3 }, { 0x17DD, 0x17DD }, + { 0x180B, 0x180D }, { 0x18A9, 0x18A9 }, { 0x1920, 0x1922 }, + { 0x1927, 0x1928 }, { 0x1932, 0x1932 }, { 0x1939, 0x193B }, + { 0x1A17, 0x1A18 }, { 0x1A56, 0x1A56 }, { 0x1A58, 0x1A5E }, + { 0x1A60, 0x1A60 }, { 0x1A62, 0x1A62 }, { 0x1A65, 0x1A6C }, + { 0x1A73, 0x1A7C }, { 0x1A7F, 0x1A7F }, { 0x1B00, 0x1B03 }, + { 0x1B34, 0x1B34 }, { 0x1B36, 0x1B3A }, { 0x1B3C, 0x1B3C }, + { 0x1B42, 0x1B42 }, { 0x1B6B, 0x1B73 }, { 0x1B80, 0x1B81 }, + { 0x1BA2, 0x1BA5 }, { 0x1BA8, 0x1BA9 }, { 0x1BAB, 0x1BAB }, + { 0x1BE6, 0x1BE6 }, { 0x1BE8, 0x1BE9 }, { 0x1BED, 0x1BED }, + { 0x1BEF, 0x1BF1 }, { 0x1C2C, 0x1C33 }, { 0x1C36, 0x1C37 }, + { 0x1CD0, 0x1CD2 }, { 0x1CD4, 0x1CE0 }, { 0x1CE2, 0x1CE8 }, + { 0x1CED, 0x1CED }, { 0x1CF4, 0x1CF4 }, { 0x1DC0, 0x1DE6 }, + { 0x1DFC, 0x1DFF }, { 0x20D0, 0x20F0 }, { 0x2CEF, 0x2CF1 }, + { 0x2D7F, 0x2D7F }, { 0x2DE0, 0x2DFF }, { 0x302A, 0x302D }, + { 0x3099, 0x309A }, { 0xA66F, 0xA672 }, { 0xA674, 0xA67D }, + { 0xA69F, 0xA69F }, { 0xA6F0, 0xA6F1 }, { 0xA802, 0xA802 }, + { 0xA806, 0xA806 }, { 0xA80B, 0xA80B }, { 0xA825, 0xA826 }, + { 0xA8C4, 0xA8C4 }, { 0xA8E0, 0xA8F1 }, { 0xA926, 0xA92D }, + { 0xA947, 0xA951 }, { 0xA980, 0xA982 }, { 0xA9B3, 0xA9B3 }, + { 0xA9B6, 0xA9B9 }, { 0xA9BC, 0xA9BC }, { 0xAA29, 0xAA2E }, + { 0xAA31, 0xAA32 }, { 0xAA35, 0xAA36 }, { 0xAA43, 0xAA43 }, + { 0xAA4C, 0xAA4C }, { 0xAAB0, 0xAAB0 }, { 0xAAB2, 0xAAB4 }, + { 0xAAB7, 0xAAB8 }, { 0xAABE, 0xAABF }, { 0xAAC1, 0xAAC1 }, + { 0xAAEC, 0xAAED }, { 0xAAF6, 0xAAF6 }, { 0xABE5, 0xABE5 }, + { 0xABE8, 0xABE8 }, { 0xABED, 0xABED }, { 0xFB1E, 0xFB1E }, + { 0xFE00, 0xFE0F }, { 0xFE20, 0xFE26 }, { 0x101FD, 0x101FD }, + { 0x10A01, 0x10A03 }, { 0x10A05, 0x10A06 }, { 0x10A0C, 0x10A0F }, + { 0x10A38, 0x10A3A }, { 0x10A3F, 0x10A3F }, { 0x11001, 0x11001 }, + { 0x11038, 0x11046 }, { 0x11080, 0x11081 }, { 0x110B3, 0x110B6 }, + { 0x110B9, 0x110BA }, { 0x11100, 0x11102 }, { 0x11127, 0x1112B }, + { 0x1112D, 0x11134 }, { 0x11180, 0x11181 }, { 0x111B6, 0x111BE }, + { 0x116AB, 0x116AB }, { 0x116AD, 0x116AD }, { 0x116B0, 0x116B5 }, + { 0x116B7, 0x116B7 }, { 0x16F8F, 0x16F92 }, { 0x1D167, 0x1D169 }, + { 0x1D17B, 0x1D182 }, { 0x1D185, 0x1D18B }, { 0x1D1AA, 0x1D1AD }, + { 0x1D242, 0x1D244 }, { 0xE0100, 0xE01EF }, + }; + static const UnicodeCharSet CombiningCharacters(CombiningCharacterRanges); + + if (CombiningCharacters.contains(UCS)) + return 0; + + static const UnicodeCharRange DoubleWidthCharacterRanges[] = { + // Hangul Jamo + { 0x1100, 0x11FF }, + // Deprecated fullwidth angle brackets + { 0x2329, 0x232A }, + // CJK Misc, CJK Unified Ideographs, Yijing Hexagrams, Yi + // excluding U+303F (IDEOGRAPHIC HALF FILL SPACE) + { 0x2E80, 0x303E }, { 0x3040, 0xA4CF }, + // Hangul + { 0xAC00, 0xD7A3 }, { 0xD7B0, 0xD7C6 }, { 0xD7CB, 0xD7FB }, + // CJK Unified Ideographs + { 0xF900, 0xFAFF }, + // Vertical forms + { 0xFE10, 0xFE19 }, + // CJK Compatibility Forms + Small Form Variants + { 0xFE30, 0xFE6F }, + // Fullwidth forms + { 0xFF01, 0xFF60 }, { 0xFFE0, 0xFFE6 }, + // CJK Unified Ideographs + { 0x20000, 0x2A6DF }, { 0x2A700, 0x2B81F }, { 0x2F800, 0x2FA1F } + }; + static const UnicodeCharSet DoubleWidthCharacters(DoubleWidthCharacterRanges); + + if (DoubleWidthCharacters.contains(UCS)) + return 2; + return 1; +} + +int columnWidthUTF8(StringRef Text) { + unsigned ColumnWidth = 0; + unsigned Length; + for (size_t i = 0, e = Text.size(); i < e; i += Length) { + Length = getNumBytesForUTF8(Text[i]); + if (Length <= 0 || i + Length > Text.size()) + return ErrorInvalidUTF8; + UTF32 buf[1]; + const UTF8 *Start = reinterpret_cast<const UTF8 *>(Text.data() + i); + UTF32 *Target = &buf[0]; + if (conversionOK != ConvertUTF8toUTF32(&Start, Start + Length, &Target, + Target + 1, strictConversion)) + return ErrorInvalidUTF8; + int Width = charWidth(buf[0]); + if (Width < 0) + return ErrorNonPrintableCharacter; + ColumnWidth += Width; + } + return ColumnWidth; +} + +} // namespace unicode +} // namespace sys +} // namespace llvm + diff --git a/contrib/llvm/lib/Support/Unix/Memory.inc b/contrib/llvm/lib/Support/Unix/Memory.inc index 2bb9bf1..dcfd76e 100644 --- a/contrib/llvm/lib/Support/Unix/Memory.inc +++ b/contrib/llvm/lib/Support/Unix/Memory.inc @@ -32,7 +32,11 @@ # endif #endif +#ifdef __APPLE__ extern "C" void sys_icache_invalidate(const void *Addr, size_t len); +#else +extern "C" void __clear_cache(void *, void*); +#endif namespace { @@ -267,6 +271,9 @@ bool Memory::setExecutable (MemoryBlock &M, std::string *ErrMsg) { kern_return_t kr = vm_protect(mach_task_self(), (vm_address_t)M.Address, (vm_size_t)M.Size, 0, VM_PROT_READ | VM_PROT_EXECUTE | VM_PROT_COPY); return KERN_SUCCESS == kr; +#elif defined(__arm__) || defined(__aarch64__) + Memory::InvalidateInstructionCache(M.Address, M.Size); + return true; #else return true; #endif diff --git a/contrib/llvm/lib/Support/Unix/Path.inc b/contrib/llvm/lib/Support/Unix/Path.inc index 6a5ebb8..c9dc871 100644 --- a/contrib/llvm/lib/Support/Unix/Path.inc +++ b/contrib/llvm/lib/Support/Unix/Path.inc @@ -1,4 +1,4 @@ -//===- llvm/Support/Unix/Path.cpp - Unix Path Implementation -----*- C++ -*-===// +//===- llvm/Support/Unix/Path.inc - Unix Path Implementation ----*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -7,7 +7,7 @@ // //===----------------------------------------------------------------------===// // -// This file implements the Unix specific portion of the Path class. +// This file implements the Unix specific implementation of the Path API. // //===----------------------------------------------------------------------===// @@ -17,6 +17,9 @@ //===----------------------------------------------------------------------===// #include "Unix.h" +#include "llvm/Support/Process.h" +#include <limits.h> +#include <stdio.h> #if HAVE_SYS_STAT_H #include <sys/stat.h> #endif @@ -26,15 +29,6 @@ #ifdef HAVE_SYS_MMAN_H #include <sys/mman.h> #endif -#ifdef HAVE_SYS_STAT_H -#include <sys/stat.h> -#endif -#if HAVE_UTIME_H -#include <utime.h> -#endif -#if HAVE_TIME_H -#include <time.h> -#endif #if HAVE_DIRENT_H # include <dirent.h> # define NAMLEN(dirent) strlen((dirent)->d_name) @@ -52,217 +46,143 @@ # endif #endif -#if HAVE_DLFCN_H -#include <dlfcn.h> -#endif - #ifdef __APPLE__ #include <mach-o/dyld.h> #endif +// Both stdio.h and cstdio are included via different pathes and +// stdcxx's cstdio doesn't include stdio.h, so it doesn't #undef the macros +// either. +#undef ferror +#undef feof + // For GNU Hurd -#if defined(__GNU__) && !defined(MAXPATHLEN) -# define MAXPATHLEN 4096 +#if defined(__GNU__) && !defined(PATH_MAX) +# define PATH_MAX 4096 #endif -// Put in a hack for Cygwin which falsely reports that the mkdtemp function -// is available when it is not. -#ifdef __CYGWIN__ -# undef HAVE_MKDTEMP -#endif +using namespace llvm; namespace { -inline bool lastIsSlash(const std::string& path) { - return !path.empty() && path[path.length() - 1] == '/'; -} - -} + /// This class automatically closes the given file descriptor when it goes out + /// of scope. You can take back explicit ownership of the file descriptor by + /// calling take(). The destructor does not verify that close was successful. + /// Therefore, never allow this class to call close on a file descriptor that + /// has been read from or written to. + struct AutoFD { + int FileDescriptor; + + AutoFD(int fd) : FileDescriptor(fd) {} + ~AutoFD() { + if (FileDescriptor >= 0) + ::close(FileDescriptor); + } -namespace llvm { -using namespace sys; + int take() { + int ret = FileDescriptor; + FileDescriptor = -1; + return ret; + } -const char sys::PathSeparator = ':'; + operator int() const {return FileDescriptor;} + }; + + error_code TempDir(SmallVectorImpl<char> &result) { + // FIXME: Don't use TMPDIR if program is SUID or SGID enabled. + const char *dir = 0; + (dir = std::getenv("TMPDIR" )) || + (dir = std::getenv("TMP" )) || + (dir = std::getenv("TEMP" )) || + (dir = std::getenv("TEMPDIR")) || +#ifdef P_tmpdir + (dir = P_tmpdir) || +#endif + (dir = "/tmp"); -StringRef Path::GetEXESuffix() { - return StringRef(); + result.clear(); + StringRef d(dir); + result.append(d.begin(), d.end()); + return error_code::success(); + } } -Path::Path(StringRef p) - : path(p) {} - -Path::Path(const char *StrStart, unsigned StrLen) - : path(StrStart, StrLen) {} - -Path& -Path::operator=(StringRef that) { - path.assign(that.data(), that.size()); - return *this; -} +static error_code createUniqueEntity(const Twine &Model, int &ResultFD, + SmallVectorImpl<char> &ResultPath, + bool MakeAbsolute, unsigned Mode, + FSEntity Type) { + SmallString<128> ModelStorage; + Model.toVector(ModelStorage); + + if (MakeAbsolute) { + // Make model absolute by prepending a temp directory if it's not already. + bool absolute = sys::path::is_absolute(Twine(ModelStorage)); + if (!absolute) { + SmallString<128> TDir; + if (error_code ec = TempDir(TDir)) return ec; + sys::path::append(TDir, Twine(ModelStorage)); + ModelStorage.swap(TDir); + } + } -bool -Path::isValid() const { - // Empty paths are considered invalid here. - // This code doesn't check MAXPATHLEN because there's no need. Nothing in - // LLVM manipulates Paths with fixed-sizes arrays, and if the OS can't - // handle names longer than some limit, it'll report this on demand using - // ENAMETOLONG. - return !path.empty(); -} + // From here on, DO NOT modify model. It may be needed if the randomly chosen + // path already exists. + ResultPath = ModelStorage; + // Null terminate. + ResultPath.push_back(0); + ResultPath.pop_back(); + +retry_random_path: + // Replace '%' with random chars. + for (unsigned i = 0, e = ModelStorage.size(); i != e; ++i) { + if (ModelStorage[i] == '%') + ResultPath[i] = "0123456789abcdef"[sys::Process::GetRandomNumber() & 15]; + } -bool -Path::isAbsolute(const char *NameStart, unsigned NameLen) { - assert(NameStart); - if (NameLen == 0) - return false; - return NameStart[0] == '/'; -} + // Try to open + create the file. + switch (Type) { + case FS_File: { + int RandomFD = ::open(ResultPath.begin(), O_RDWR | O_CREAT | O_EXCL, Mode); + if (RandomFD == -1) { + int SavedErrno = errno; + // If the file existed, try again, otherwise, error. + if (SavedErrno == errc::file_exists) + goto retry_random_path; + return error_code(SavedErrno, system_category()); + } -bool -Path::isAbsolute() const { - if (path.empty()) - return false; - return path[0] == '/'; -} - -Path -Path::GetRootDirectory() { - Path result; - result.set("/"); - return result; -} - -Path -Path::GetTemporaryDirectory(std::string *ErrMsg) { -#if defined(HAVE_MKDTEMP) - // The best way is with mkdtemp but that's not available on many systems, - // Linux and FreeBSD have it. Others probably won't. - char pathname[] = "/tmp/llvm_XXXXXX"; - if (0 == mkdtemp(pathname)) { - MakeErrMsg(ErrMsg, - std::string(pathname) + ": can't create temporary directory"); - return Path(); - } - return Path(pathname); -#elif defined(HAVE_MKSTEMP) - // If no mkdtemp is available, mkstemp can be used to create a temporary file - // which is then removed and created as a directory. We prefer this over - // mktemp because of mktemp's inherent security and threading risks. We still - // have a slight race condition from the time the temporary file is created to - // the time it is re-created as a directoy. - char pathname[] = "/tmp/llvm_XXXXXX"; - int fd = 0; - if (-1 == (fd = mkstemp(pathname))) { - MakeErrMsg(ErrMsg, - std::string(pathname) + ": can't create temporary directory"); - return Path(); - } - ::close(fd); - ::unlink(pathname); // start race condition, ignore errors - if (-1 == ::mkdir(pathname, S_IRWXU)) { // end race condition - MakeErrMsg(ErrMsg, - std::string(pathname) + ": can't create temporary directory"); - return Path(); - } - return Path(pathname); -#elif defined(HAVE_MKTEMP) - // If a system doesn't have mkdtemp(3) or mkstemp(3) but it does have - // mktemp(3) then we'll assume that system (e.g. AIX) has a reasonable - // implementation of mktemp(3) and doesn't follow BSD 4.3's lead of replacing - // the XXXXXX with the pid of the process and a letter. That leads to only - // twenty six temporary files that can be generated. - char pathname[] = "/tmp/llvm_XXXXXX"; - char *TmpName = ::mktemp(pathname); - if (TmpName == 0) { - MakeErrMsg(ErrMsg, - std::string(TmpName) + ": can't create unique directory name"); - return Path(); - } - if (-1 == ::mkdir(TmpName, S_IRWXU)) { - MakeErrMsg(ErrMsg, - std::string(TmpName) + ": can't create temporary directory"); - return Path(); + ResultFD = RandomFD; + return error_code::success(); } - return Path(TmpName); -#else - // This is the worst case implementation. tempnam(3) leaks memory unless its - // on an SVID2 (or later) system. On BSD 4.3 it leaks. tmpnam(3) has thread - // issues. The mktemp(3) function doesn't have enough variability in the - // temporary name generated. So, we provide our own implementation that - // increments an integer from a random number seeded by the current time. This - // should be sufficiently unique that we don't have many collisions between - // processes. Generally LLVM processes don't run very long and don't use very - // many temporary files so this shouldn't be a big issue for LLVM. - static time_t num = ::time(0); - char pathname[MAXPATHLEN]; - do { - num++; - sprintf(pathname, "/tmp/llvm_%010u", unsigned(num)); - } while ( 0 == access(pathname, F_OK ) ); - if (-1 == ::mkdir(pathname, S_IRWXU)) { - MakeErrMsg(ErrMsg, - std::string(pathname) + ": can't create temporary directory"); - return Path(); - } - return Path(pathname); -#endif -} -void -Path::GetSystemLibraryPaths(std::vector<sys::Path>& Paths) { -#ifdef LTDL_SHLIBPATH_VAR - char* env_var = getenv(LTDL_SHLIBPATH_VAR); - if (env_var != 0) { - getPathList(env_var,Paths); - } -#endif - // FIXME: Should this look at LD_LIBRARY_PATH too? - Paths.push_back(sys::Path("/usr/local/lib/")); - Paths.push_back(sys::Path("/usr/X11R6/lib/")); - Paths.push_back(sys::Path("/usr/lib/")); - Paths.push_back(sys::Path("/lib/")); -} - -void -Path::GetBitcodeLibraryPaths(std::vector<sys::Path>& Paths) { - char * env_var = getenv("LLVM_LIB_SEARCH_PATH"); - if (env_var != 0) { - getPathList(env_var,Paths); - } -#ifdef LLVM_LIBDIR - { - Path tmpPath; - if (tmpPath.set(LLVM_LIBDIR)) - if (tmpPath.canRead()) - Paths.push_back(tmpPath); + case FS_Name: { + bool Exists; + error_code EC = sys::fs::exists(ResultPath.begin(), Exists); + if (EC) + return EC; + if (Exists) + goto retry_random_path; + return error_code::success(); } -#endif - GetSystemLibraryPaths(Paths); -} -Path -Path::GetUserHomeDirectory() { - const char* home = getenv("HOME"); - Path result; - if (home && result.set(home)) - return result; - result.set("/"); - return result; -} - -Path -Path::GetCurrentDirectory() { - char pathname[MAXPATHLEN]; - if (!getcwd(pathname, MAXPATHLEN)) { - assert(false && "Could not query current working directory."); - return Path(); + case FS_Dir: { + bool Existed; + error_code EC = sys::fs::create_directory(ResultPath.begin(), Existed); + if (EC) + return EC; + if (Existed) + goto retry_random_path; + return error_code::success(); } - - return Path(pathname); + } + llvm_unreachable("Invalid Type"); } +namespace llvm { +namespace sys { +namespace fs { #if defined(__FreeBSD__) || defined (__NetBSD__) || defined(__Bitrig__) || \ defined(__OpenBSD__) || defined(__minix) || defined(__FreeBSD_kernel__) || \ - defined(__linux__) || defined(__CYGWIN__) + defined(__linux__) || defined(__CYGWIN__) || defined(__DragonFly__) static int test_dir(char buf[PATH_MAX], char ret[PATH_MAX], const char *dir, const char *bin) @@ -318,7 +238,7 @@ getprogpath(char ret[PATH_MAX], const char *bin) /// GetMainExecutable - Return the path to the main executable, given the /// value of argv[0] from program startup. -Path Path::GetMainExecutable(const char *argv0, void *MainAddr) { +std::string getMainExecutable(const char *argv0, void *MainAddr) { #if defined(__APPLE__) // On OS X the executable path is saved to the stack by dyld. Reading it // from there is much faster than calling dladdr, especially for large @@ -328,14 +248,15 @@ Path Path::GetMainExecutable(const char *argv0, void *MainAddr) { if (_NSGetExecutablePath(exe_path, &size) == 0) { char link_path[MAXPATHLEN]; if (realpath(exe_path, link_path)) - return Path(link_path); + return link_path; } #elif defined(__FreeBSD__) || defined (__NetBSD__) || defined(__Bitrig__) || \ - defined(__OpenBSD__) || defined(__minix) || defined(__FreeBSD_kernel__) + defined(__OpenBSD__) || defined(__minix) || defined(__DragonFly__) || \ + defined(__FreeBSD_kernel__) char exe_path[PATH_MAX]; if (getprogpath(exe_path, argv0) != NULL) - return Path(exe_path); + return exe_path; #elif defined(__linux__) || defined(__CYGWIN__) char exe_path[MAXPATHLEN]; StringRef aPath("/proc/self/exe"); @@ -343,558 +264,534 @@ Path Path::GetMainExecutable(const char *argv0, void *MainAddr) { // /proc is not always mounted under Linux (chroot for example). ssize_t len = readlink(aPath.str().c_str(), exe_path, sizeof(exe_path)); if (len >= 0) - return Path(StringRef(exe_path, len)); + return StringRef(exe_path, len); } else { // Fall back to the classical detection. if (getprogpath(exe_path, argv0) != NULL) - return Path(exe_path); + return exe_path; } #elif defined(HAVE_DLFCN_H) // Use dladdr to get executable path if available. Dl_info DLInfo; int err = dladdr(MainAddr, &DLInfo); if (err == 0) - return Path(); + return ""; // If the filename is a symlink, we need to resolve and return the location of // the actual executable. char link_path[MAXPATHLEN]; if (realpath(DLInfo.dli_fname, link_path)) - return Path(link_path); + return link_path; #else #error GetMainExecutable is not implemented on this host yet. #endif - return Path(); + return ""; } +TimeValue file_status::getLastModificationTime() const { + TimeValue Ret; + Ret.fromEpochTime(fs_st_mtime); + return Ret; +} -StringRef Path::getDirname() const { - return getDirnameCharSep(path, "/"); +UniqueID file_status::getUniqueID() const { + return UniqueID(fs_st_dev, fs_st_ino); } -StringRef -Path::getBasename() const { - // Find the last slash - std::string::size_type slash = path.rfind('/'); - if (slash == std::string::npos) - slash = 0; - else - slash++; +error_code current_path(SmallVectorImpl<char> &result) { + result.clear(); - std::string::size_type dot = path.rfind('.'); - if (dot == std::string::npos || dot < slash) - return StringRef(path).substr(slash); - else - return StringRef(path).substr(slash, dot - slash); -} + const char *pwd = ::getenv("PWD"); + llvm::sys::fs::file_status PWDStatus, DotStatus; + if (pwd && llvm::sys::path::is_absolute(pwd) && + !llvm::sys::fs::status(pwd, PWDStatus) && + !llvm::sys::fs::status(".", DotStatus) && + PWDStatus.getUniqueID() == DotStatus.getUniqueID()) { + result.append(pwd, pwd + strlen(pwd)); + return error_code::success(); + } -StringRef -Path::getSuffix() const { - // Find the last slash - std::string::size_type slash = path.rfind('/'); - if (slash == std::string::npos) - slash = 0; - else - slash++; +#ifdef MAXPATHLEN + result.reserve(MAXPATHLEN); +#else +// For GNU Hurd + result.reserve(1024); +#endif - std::string::size_type dot = path.rfind('.'); - if (dot == std::string::npos || dot < slash) - return StringRef(); - else - return StringRef(path).substr(dot + 1); -} + while (true) { + if (::getcwd(result.data(), result.capacity()) == 0) { + // See if there was a real error. + if (errno != errc::not_enough_memory) + return error_code(errno, system_category()); + // Otherwise there just wasn't enough space. + result.reserve(result.capacity() * 2); + } else + break; + } -bool Path::getMagicNumber(std::string &Magic, unsigned len) const { - assert(len < 1024 && "Request for magic string too long"); - char Buf[1025]; - int fd = ::open(path.c_str(), O_RDONLY); - if (fd < 0) - return false; - ssize_t bytes_read = ::read(fd, Buf, len); - ::close(fd); - if (ssize_t(len) != bytes_read) - return false; - Magic.assign(Buf, len); - return true; + result.set_size(strlen(result.data())); + return error_code::success(); } -bool -Path::exists() const { - return 0 == access(path.c_str(), F_OK ); -} +error_code create_directory(const Twine &path, bool &existed) { + SmallString<128> path_storage; + StringRef p = path.toNullTerminatedStringRef(path_storage); -bool -Path::isDirectory() const { - struct stat buf; - if (0 != stat(path.c_str(), &buf)) - return false; - return ((buf.st_mode & S_IFMT) == S_IFDIR) ? true : false; -} + if (::mkdir(p.begin(), S_IRWXU | S_IRWXG) == -1) { + if (errno != errc::file_exists) + return error_code(errno, system_category()); + existed = true; + } else + existed = false; -bool -Path::isSymLink() const { - struct stat buf; - if (0 != lstat(path.c_str(), &buf)) - return false; - return S_ISLNK(buf.st_mode); + return error_code::success(); } +error_code create_hard_link(const Twine &to, const Twine &from) { + // Get arguments. + SmallString<128> from_storage; + SmallString<128> to_storage; + StringRef f = from.toNullTerminatedStringRef(from_storage); + StringRef t = to.toNullTerminatedStringRef(to_storage); -bool -Path::canRead() const { - return 0 == access(path.c_str(), R_OK); -} + if (::link(t.begin(), f.begin()) == -1) + return error_code(errno, system_category()); -bool -Path::canWrite() const { - return 0 == access(path.c_str(), W_OK); + return error_code::success(); } -bool -Path::isRegularFile() const { - // Get the status so we can determine if it's a file or directory - struct stat buf; - - if (0 != stat(path.c_str(), &buf)) - return false; +error_code create_symlink(const Twine &to, const Twine &from) { + // Get arguments. + SmallString<128> from_storage; + SmallString<128> to_storage; + StringRef f = from.toNullTerminatedStringRef(from_storage); + StringRef t = to.toNullTerminatedStringRef(to_storage); - if (S_ISREG(buf.st_mode)) - return true; + if (::symlink(t.begin(), f.begin()) == -1) + return error_code(errno, system_category()); - return false; + return error_code::success(); } -bool -Path::canExecute() const { - if (0 != access(path.c_str(), R_OK | X_OK )) - return false; +error_code remove(const Twine &path, bool &existed) { + SmallString<128> path_storage; + StringRef p = path.toNullTerminatedStringRef(path_storage); + struct stat buf; - if (0 != stat(path.c_str(), &buf)) - return false; - if (!S_ISREG(buf.st_mode)) - return false; - return true; -} + if (stat(p.begin(), &buf) != 0) { + if (errno != errc::no_such_file_or_directory) + return error_code(errno, system_category()); + existed = false; + return error_code::success(); + } -StringRef -Path::getLast() const { - // Find the last slash - size_t pos = path.rfind('/'); + // Note: this check catches strange situations. In all cases, LLVM should + // only be involved in the creation and deletion of regular files. This + // check ensures that what we're trying to erase is a regular file. It + // effectively prevents LLVM from erasing things like /dev/null, any block + // special file, or other things that aren't "regular" files. + if (!S_ISREG(buf.st_mode) && !S_ISDIR(buf.st_mode)) + return make_error_code(errc::operation_not_permitted); - // Handle the corner cases - if (pos == std::string::npos) - return path; + if (::remove(p.begin()) == -1) { + if (errno != errc::no_such_file_or_directory) + return error_code(errno, system_category()); + existed = false; + } else + existed = true; - // If the last character is a slash - if (pos == path.length()-1) { - // Find the second to last slash - size_t pos2 = path.rfind('/', pos-1); - if (pos2 == std::string::npos) - return StringRef(path).substr(0,pos); - else - return StringRef(path).substr(pos2+1,pos-pos2-1); - } - // Return everything after the last slash - return StringRef(path).substr(pos+1); + return error_code::success(); } -const FileStatus * -PathWithStatus::getFileStatus(bool update, std::string *ErrStr) const { - if (!fsIsValid || update) { - struct stat buf; - if (0 != stat(path.c_str(), &buf)) { - MakeErrMsg(ErrStr, path + ": can't get status of file"); - return 0; - } - status.fileSize = buf.st_size; - status.modTime.fromEpochTime(buf.st_mtime); - status.mode = buf.st_mode; - status.user = buf.st_uid; - status.group = buf.st_gid; - status.uniqueID = uint64_t(buf.st_ino); - status.isDir = S_ISDIR(buf.st_mode); - status.isFile = S_ISREG(buf.st_mode); - fsIsValid = true; - } - return &status; -} +error_code rename(const Twine &from, const Twine &to) { + // Get arguments. + SmallString<128> from_storage; + SmallString<128> to_storage; + StringRef f = from.toNullTerminatedStringRef(from_storage); + StringRef t = to.toNullTerminatedStringRef(to_storage); -static bool AddPermissionBits(const Path &File, int bits) { - // Get the umask value from the operating system. We want to use it - // when changing the file's permissions. Since calling umask() sets - // the umask and returns its old value, we must call it a second - // time to reset it to the user's preference. - int mask = umask(0777); // The arg. to umask is arbitrary. - umask(mask); // Restore the umask. + if (::rename(f.begin(), t.begin()) == -1) + return error_code(errno, system_category()); - // Get the file's current mode. - struct stat buf; - if (0 != stat(File.c_str(), &buf)) - return false; - // Change the file to have whichever permissions bits from 'bits' - // that the umask would not disable. - if ((chmod(File.c_str(), (buf.st_mode | (bits & ~mask)))) == -1) - return false; - return true; + return error_code::success(); } -bool Path::makeReadableOnDisk(std::string* ErrMsg) { - if (!AddPermissionBits(*this, 0444)) - return MakeErrMsg(ErrMsg, path + ": can't make file readable"); - return false; -} +error_code resize_file(const Twine &path, uint64_t size) { + SmallString<128> path_storage; + StringRef p = path.toNullTerminatedStringRef(path_storage); -bool Path::makeWriteableOnDisk(std::string* ErrMsg) { - if (!AddPermissionBits(*this, 0222)) - return MakeErrMsg(ErrMsg, path + ": can't make file writable"); - return false; -} + if (::truncate(p.begin(), size) == -1) + return error_code(errno, system_category()); -bool Path::makeExecutableOnDisk(std::string* ErrMsg) { - if (!AddPermissionBits(*this, 0111)) - return MakeErrMsg(ErrMsg, path + ": can't make file executable"); - return false; + return error_code::success(); } -bool -Path::getDirectoryContents(std::set<Path>& result, std::string* ErrMsg) const { - DIR* direntries = ::opendir(path.c_str()); - if (direntries == 0) - return MakeErrMsg(ErrMsg, path + ": can't open directory"); - - std::string dirPath = path; - if (!lastIsSlash(dirPath)) - dirPath += '/'; +error_code exists(const Twine &path, bool &result) { + SmallString<128> path_storage; + StringRef p = path.toNullTerminatedStringRef(path_storage); - result.clear(); - struct dirent* de = ::readdir(direntries); - for ( ; de != 0; de = ::readdir(direntries)) { - if (de->d_name[0] != '.') { - Path aPath(dirPath + (const char*)de->d_name); - struct stat st; - if (0 != lstat(aPath.path.c_str(), &st)) { - if (S_ISLNK(st.st_mode)) - continue; // dangling symlink -- ignore - return MakeErrMsg(ErrMsg, - aPath.path + ": can't determine file object type"); - } - result.insert(aPath); - } - } + if (::access(p.begin(), F_OK) == -1) { + if (errno != errc::no_such_file_or_directory) + return error_code(errno, system_category()); + result = false; + } else + result = true; - closedir(direntries); - return false; + return error_code::success(); } -bool -Path::set(StringRef a_path) { - if (a_path.empty()) - return false; - path = a_path; - return true; +bool can_write(const Twine &Path) { + SmallString<128> PathStorage; + StringRef P = Path.toNullTerminatedStringRef(PathStorage); + return 0 == access(P.begin(), W_OK); } -bool -Path::appendComponent(StringRef name) { - if (name.empty()) +bool can_execute(const Twine &Path) { + SmallString<128> PathStorage; + StringRef P = Path.toNullTerminatedStringRef(PathStorage); + + if (0 != access(P.begin(), R_OK | X_OK)) + return false; + struct stat buf; + if (0 != stat(P.begin(), &buf)) + return false; + if (!S_ISREG(buf.st_mode)) return false; - if (!lastIsSlash(path)) - path += '/'; - path += name; return true; } -bool -Path::eraseComponent() { - size_t slashpos = path.rfind('/',path.size()); - if (slashpos == 0 || slashpos == std::string::npos) { - path.erase(); - return true; - } - if (slashpos == path.size() - 1) - slashpos = path.rfind('/',slashpos-1); - if (slashpos == std::string::npos) { - path.erase(); - return true; - } - path.erase(slashpos); - return true; +bool equivalent(file_status A, file_status B) { + assert(status_known(A) && status_known(B)); + return A.fs_st_dev == B.fs_st_dev && + A.fs_st_ino == B.fs_st_ino; } -bool -Path::eraseSuffix() { - size_t dotpos = path.rfind('.',path.size()); - size_t slashpos = path.rfind('/',path.size()); - if (dotpos != std::string::npos) { - if (slashpos == std::string::npos || dotpos > slashpos+1) { - path.erase(dotpos, path.size()-dotpos); - return true; - } - } - return false; +error_code equivalent(const Twine &A, const Twine &B, bool &result) { + file_status fsA, fsB; + if (error_code ec = status(A, fsA)) return ec; + if (error_code ec = status(B, fsB)) return ec; + result = equivalent(fsA, fsB); + return error_code::success(); } -static bool createDirectoryHelper(char* beg, char* end, bool create_parents) { +static error_code fillStatus(int StatRet, const struct stat &Status, + file_status &Result) { + if (StatRet != 0) { + error_code ec(errno, system_category()); + if (ec == errc::no_such_file_or_directory) + Result = file_status(file_type::file_not_found); + else + Result = file_status(file_type::status_error); + return ec; + } - if (access(beg, R_OK | W_OK) == 0) - return false; + file_type Type = file_type::type_unknown; + + if (S_ISDIR(Status.st_mode)) + Type = file_type::directory_file; + else if (S_ISREG(Status.st_mode)) + Type = file_type::regular_file; + else if (S_ISBLK(Status.st_mode)) + Type = file_type::block_file; + else if (S_ISCHR(Status.st_mode)) + Type = file_type::character_file; + else if (S_ISFIFO(Status.st_mode)) + Type = file_type::fifo_file; + else if (S_ISSOCK(Status.st_mode)) + Type = file_type::socket_file; + + perms Perms = static_cast<perms>(Status.st_mode); + Result = + file_status(Type, Perms, Status.st_dev, Status.st_ino, Status.st_mtime, + Status.st_uid, Status.st_gid, Status.st_size); + + return error_code::success(); +} + +error_code status(const Twine &Path, file_status &Result) { + SmallString<128> PathStorage; + StringRef P = Path.toNullTerminatedStringRef(PathStorage); + + struct stat Status; + int StatRet = ::stat(P.begin(), &Status); + return fillStatus(StatRet, Status, Result); +} + +error_code status(int FD, file_status &Result) { + struct stat Status; + int StatRet = ::fstat(FD, &Status); + return fillStatus(StatRet, Status, Result); +} + +error_code setLastModificationAndAccessTime(int FD, TimeValue Time) { +#if defined(HAVE_FUTIMENS) + timespec Times[2]; + Times[0].tv_sec = Time.toPosixTime(); + Times[0].tv_nsec = 0; + Times[1] = Times[0]; + if (::futimens(FD, Times)) +#elif defined(HAVE_FUTIMES) + timeval Times[2]; + Times[0].tv_sec = Time.toPosixTime(); + Times[0].tv_usec = 0; + Times[1] = Times[0]; + if (::futimes(FD, Times)) +#else +#error Missing futimes() and futimens() +#endif + return error_code(errno, system_category()); + return error_code::success(); +} + +error_code mapped_file_region::init(int FD, bool CloseFD, uint64_t Offset) { + AutoFD ScopedFD(FD); + if (!CloseFD) + ScopedFD.take(); + + // Figure out how large the file is. + struct stat FileInfo; + if (fstat(FD, &FileInfo) == -1) + return error_code(errno, system_category()); + uint64_t FileSize = FileInfo.st_size; + + if (Size == 0) + Size = FileSize; + else if (FileSize < Size) { + // We need to grow the file. + if (ftruncate(FD, Size) == -1) + return error_code(errno, system_category()); + } - if (create_parents) { + int flags = (Mode == readwrite) ? MAP_SHARED : MAP_PRIVATE; + int prot = (Mode == readonly) ? PROT_READ : (PROT_READ | PROT_WRITE); +#ifdef MAP_FILE + flags |= MAP_FILE; +#endif + Mapping = ::mmap(0, Size, prot, flags, FD, Offset); + if (Mapping == MAP_FAILED) + return error_code(errno, system_category()); + return error_code::success(); +} + +mapped_file_region::mapped_file_region(const Twine &path, + mapmode mode, + uint64_t length, + uint64_t offset, + error_code &ec) + : Mode(mode) + , Size(length) + , Mapping() { + // Make sure that the requested size fits within SIZE_T. + if (length > std::numeric_limits<size_t>::max()) { + ec = make_error_code(errc::invalid_argument); + return; + } - char* c = end; + SmallString<128> path_storage; + StringRef name = path.toNullTerminatedStringRef(path_storage); + int oflags = (mode == readonly) ? O_RDONLY : O_RDWR; + int ofd = ::open(name.begin(), oflags); + if (ofd == -1) { + ec = error_code(errno, system_category()); + return; + } - for (; c != beg; --c) - if (*c == '/') { + ec = init(ofd, true, offset); + if (ec) + Mapping = 0; +} + +mapped_file_region::mapped_file_region(int fd, + bool closefd, + mapmode mode, + uint64_t length, + uint64_t offset, + error_code &ec) + : Mode(mode) + , Size(length) + , Mapping() { + // Make sure that the requested size fits within SIZE_T. + if (length > std::numeric_limits<size_t>::max()) { + ec = make_error_code(errc::invalid_argument); + return; + } - // Recurse to handling the parent directory. - *c = '\0'; - bool x = createDirectoryHelper(beg, c, create_parents); - *c = '/'; + ec = init(fd, closefd, offset); + if (ec) + Mapping = 0; +} - // Return if we encountered an error. - if (x) - return true; +mapped_file_region::~mapped_file_region() { + if (Mapping) + ::munmap(Mapping, Size); +} - break; - } - } +#if LLVM_HAS_RVALUE_REFERENCES +mapped_file_region::mapped_file_region(mapped_file_region &&other) + : Mode(other.Mode), Size(other.Size), Mapping(other.Mapping) { + other.Mapping = 0; +} +#endif - return mkdir(beg, S_IRWXU | S_IRWXG) != 0; +mapped_file_region::mapmode mapped_file_region::flags() const { + assert(Mapping && "Mapping failed but used anyway!"); + return Mode; } -bool -Path::createDirectoryOnDisk( bool create_parents, std::string* ErrMsg ) { - // Get a writeable copy of the path name - std::string pathname(path); +uint64_t mapped_file_region::size() const { + assert(Mapping && "Mapping failed but used anyway!"); + return Size; +} - // Null-terminate the last component - size_t lastchar = path.length() - 1 ; +char *mapped_file_region::data() const { + assert(Mapping && "Mapping failed but used anyway!"); + assert(Mode != readonly && "Cannot get non const data for readonly mapping!"); + return reinterpret_cast<char*>(Mapping); +} - if (pathname[lastchar] != '/') - ++lastchar; +const char *mapped_file_region::const_data() const { + assert(Mapping && "Mapping failed but used anyway!"); + return reinterpret_cast<const char*>(Mapping); +} - pathname[lastchar] = '\0'; +int mapped_file_region::alignment() { + return process::get_self()->page_size(); +} - if (createDirectoryHelper(&pathname[0], &pathname[lastchar], create_parents)) - return MakeErrMsg(ErrMsg, pathname + ": can't create directory"); +error_code detail::directory_iterator_construct(detail::DirIterState &it, + StringRef path){ + SmallString<128> path_null(path); + DIR *directory = ::opendir(path_null.c_str()); + if (directory == 0) + return error_code(errno, system_category()); - return false; + it.IterationHandle = reinterpret_cast<intptr_t>(directory); + // Add something for replace_filename to replace. + path::append(path_null, "."); + it.CurrentEntry = directory_entry(path_null.str()); + return directory_iterator_increment(it); } -bool -Path::createFileOnDisk(std::string* ErrMsg) { - // Create the file - int fd = ::creat(path.c_str(), S_IRUSR | S_IWUSR); - if (fd < 0) - return MakeErrMsg(ErrMsg, path + ": can't create file"); - ::close(fd); - return false; +error_code detail::directory_iterator_destruct(detail::DirIterState &it) { + if (it.IterationHandle) + ::closedir(reinterpret_cast<DIR *>(it.IterationHandle)); + it.IterationHandle = 0; + it.CurrentEntry = directory_entry(); + return error_code::success(); } -bool -Path::createTemporaryFileOnDisk(bool reuse_current, std::string* ErrMsg) { - // Make this into a unique file name - if (makeUnique( reuse_current, ErrMsg )) - return true; +error_code detail::directory_iterator_increment(detail::DirIterState &it) { + errno = 0; + dirent *cur_dir = ::readdir(reinterpret_cast<DIR *>(it.IterationHandle)); + if (cur_dir == 0 && errno != 0) { + return error_code(errno, system_category()); + } else if (cur_dir != 0) { + StringRef name(cur_dir->d_name, NAMLEN(cur_dir)); + if ((name.size() == 1 && name[0] == '.') || + (name.size() == 2 && name[0] == '.' && name[1] == '.')) + return directory_iterator_increment(it); + it.CurrentEntry.replace_filename(name); + } else + return directory_iterator_destruct(it); - // create the file - int fd = ::open(path.c_str(), O_WRONLY|O_CREAT|O_TRUNC, 0666); - if (fd < 0) - return MakeErrMsg(ErrMsg, path + ": can't create temporary file"); - ::close(fd); - return false; + return error_code::success(); } -bool -Path::eraseFromDisk(bool remove_contents, std::string *ErrStr) const { - // Get the status so we can determine if it's a file or directory. - struct stat buf; - if (0 != stat(path.c_str(), &buf)) { - MakeErrMsg(ErrStr, path + ": can't get status of file"); - return true; - } +error_code get_magic(const Twine &path, uint32_t len, + SmallVectorImpl<char> &result) { + SmallString<128> PathStorage; + StringRef Path = path.toNullTerminatedStringRef(PathStorage); + result.set_size(0); - // Note: this check catches strange situations. In all cases, LLVM should - // only be involved in the creation and deletion of regular files. This - // check ensures that what we're trying to erase is a regular file. It - // effectively prevents LLVM from erasing things like /dev/null, any block - // special file, or other things that aren't "regular" files. - if (S_ISREG(buf.st_mode)) { - if (unlink(path.c_str()) != 0) - return MakeErrMsg(ErrStr, path + ": can't destroy file"); - return false; - } + // Open path. + std::FILE *file = std::fopen(Path.data(), "rb"); + if (file == 0) + return error_code(errno, system_category()); - if (!S_ISDIR(buf.st_mode)) { - if (ErrStr) *ErrStr = "not a file or directory"; - return true; - } + // Reserve storage. + result.reserve(len); - if (remove_contents) { - // Recursively descend the directory to remove its contents. - std::string cmd = "/bin/rm -rf " + path; - if (system(cmd.c_str()) != 0) { - MakeErrMsg(ErrStr, path + ": failed to recursively remove directory."); - return true; + // Read magic! + size_t size = std::fread(result.data(), 1, len, file); + if (std::ferror(file) != 0) { + std::fclose(file); + return error_code(errno, system_category()); + } else if (size != len) { + if (std::feof(file) != 0) { + std::fclose(file); + result.set_size(size); + return make_error_code(errc::value_too_large); } - return false; - } - - // Otherwise, try to just remove the one directory. - std::string pathname(path); - size_t lastchar = path.length() - 1; - if (pathname[lastchar] == '/') - pathname[lastchar] = '\0'; - else - pathname[lastchar+1] = '\0'; - - if (rmdir(pathname.c_str()) != 0) - return MakeErrMsg(ErrStr, pathname + ": can't erase directory"); - return false; -} - -bool -Path::renamePathOnDisk(const Path& newName, std::string* ErrMsg) { - if (0 != ::rename(path.c_str(), newName.c_str())) - return MakeErrMsg(ErrMsg, std::string("can't rename '") + path + "' as '" + - newName.str() + "'"); - return false; -} - -bool -Path::setStatusInfoOnDisk(const FileStatus &si, std::string *ErrStr) const { - struct utimbuf utb; - utb.actime = si.modTime.toPosixTime(); - utb.modtime = utb.actime; - if (0 != ::utime(path.c_str(),&utb)) - return MakeErrMsg(ErrStr, path + ": can't set file modification time"); - if (0 != ::chmod(path.c_str(),si.mode)) - return MakeErrMsg(ErrStr, path + ": can't set mode"); - return false; -} - -bool -sys::CopyFile(const sys::Path &Dest, const sys::Path &Src, std::string* ErrMsg){ - int inFile = -1; - int outFile = -1; - inFile = ::open(Src.c_str(), O_RDONLY); - if (inFile == -1) - return MakeErrMsg(ErrMsg, Src.str() + - ": can't open source file to copy"); - - outFile = ::open(Dest.c_str(), O_WRONLY|O_CREAT, 0666); - if (outFile == -1) { - ::close(inFile); - return MakeErrMsg(ErrMsg, Dest.str() + - ": can't create destination file for copy"); } - - char Buffer[16*1024]; - while (ssize_t Amt = ::read(inFile, Buffer, 16*1024)) { - if (Amt == -1) { - if (errno != EINTR && errno != EAGAIN) { - ::close(inFile); - ::close(outFile); - return MakeErrMsg(ErrMsg, Src.str()+": can't read source file"); - } - } else { - char *BufPtr = Buffer; - while (Amt) { - ssize_t AmtWritten = ::write(outFile, BufPtr, Amt); - if (AmtWritten == -1) { - if (errno != EINTR && errno != EAGAIN) { - ::close(inFile); - ::close(outFile); - return MakeErrMsg(ErrMsg, Dest.str() + - ": can't write destination file"); - } - } else { - Amt -= AmtWritten; - BufPtr += AmtWritten; - } - } - } + std::fclose(file); + result.set_size(size); + return error_code::success(); +} + +error_code map_file_pages(const Twine &path, off_t file_offset, size_t size, + bool map_writable, void *&result) { + SmallString<128> path_storage; + StringRef name = path.toNullTerminatedStringRef(path_storage); + int oflags = map_writable ? O_RDWR : O_RDONLY; + int ofd = ::open(name.begin(), oflags); + if ( ofd == -1 ) + return error_code(errno, system_category()); + AutoFD fd(ofd); + int flags = map_writable ? MAP_SHARED : MAP_PRIVATE; + int prot = map_writable ? (PROT_READ|PROT_WRITE) : PROT_READ; +#ifdef MAP_FILE + flags |= MAP_FILE; +#endif + result = ::mmap(0, size, prot, flags, fd, file_offset); + if (result == MAP_FAILED) { + return error_code(errno, system_category()); } - ::close(inFile); - ::close(outFile); - return false; -} - -bool -Path::makeUnique(bool reuse_current, std::string* ErrMsg) { - bool Exists; - if (reuse_current && (fs::exists(path, Exists) || !Exists)) - return false; // File doesn't exist already, just use it! - - // Append an XXXXXX pattern to the end of the file for use with mkstemp, - // mktemp or our own implementation. - // This uses std::vector instead of SmallVector to avoid a dependence on - // libSupport. And performance isn't critical here. - std::vector<char> Buf; - Buf.resize(path.size()+8); - char *FNBuffer = &Buf[0]; - path.copy(FNBuffer,path.size()); - bool isdir; - if (!fs::is_directory(path, isdir) && isdir) - strcpy(FNBuffer+path.size(), "/XXXXXX"); - else - strcpy(FNBuffer+path.size(), "-XXXXXX"); + + return error_code::success(); +} -#if defined(HAVE_MKSTEMP) - int TempFD; - if ((TempFD = mkstemp(FNBuffer)) == -1) - return MakeErrMsg(ErrMsg, path + ": can't make unique filename"); +error_code unmap_file_pages(void *base, size_t size) { + if ( ::munmap(base, size) == -1 ) + return error_code(errno, system_category()); + + return error_code::success(); +} - // We don't need to hold the temp file descriptor... we will trust that no one - // will overwrite/delete the file before we can open it again. - close(TempFD); +error_code openFileForRead(const Twine &Name, int &ResultFD) { + SmallString<128> Storage; + StringRef P = Name.toNullTerminatedStringRef(Storage); + while ((ResultFD = open(P.begin(), O_RDONLY)) < 0) { + if (errno != EINTR) + return error_code(errno, system_category()); + } + return error_code::success(); +} - // Save the name - path = FNBuffer; +error_code openFileForWrite(const Twine &Name, int &ResultFD, + sys::fs::OpenFlags Flags, unsigned Mode) { + // Verify that we don't have both "append" and "excl". + assert((!(Flags & sys::fs::F_Excl) || !(Flags & sys::fs::F_Append)) && + "Cannot specify both 'excl' and 'append' file creation flags!"); - // By default mkstemp sets the mode to 0600, so update mode bits now. - AddPermissionBits (*this, 0666); -#elif defined(HAVE_MKTEMP) - // If we don't have mkstemp, use the old and obsolete mktemp function. - if (mktemp(FNBuffer) == 0) - return MakeErrMsg(ErrMsg, path + ": can't make unique filename"); + int OpenFlags = O_WRONLY | O_CREAT; - // Save the name - path = FNBuffer; -#else - // Okay, looks like we have to do it all by our lonesome. - static unsigned FCounter = 0; - // Try to initialize with unique value. - if (FCounter == 0) FCounter = ((unsigned)getpid() & 0xFFFF) << 8; - char* pos = strstr(FNBuffer, "XXXXXX"); - do { - if (++FCounter > 0xFFFFFF) { - return MakeErrMsg(ErrMsg, - path + ": can't make unique filename: too many files"); - } - sprintf(pos, "%06X", FCounter); - path = FNBuffer; - } while (exists()); - // POSSIBLE SECURITY BUG: An attacker can easily guess the name and exploit - // LLVM. -#endif - return false; -} + if (Flags & F_Append) + OpenFlags |= O_APPEND; + else + OpenFlags |= O_TRUNC; -const char *Path::MapInFilePages(int FD, size_t FileSize, off_t Offset) { - int Flags = MAP_PRIVATE; -#ifdef MAP_FILE - Flags |= MAP_FILE; -#endif - void *BasePtr = ::mmap(0, FileSize, PROT_READ, Flags, FD, Offset); - if (BasePtr == MAP_FAILED) - return 0; - return (const char*)BasePtr; -} + if (Flags & F_Excl) + OpenFlags |= O_EXCL; -void Path::UnMapFilePages(const char *BasePtr, size_t FileSize) { - const void *Addr = static_cast<const void *>(BasePtr); - ::munmap(const_cast<void *>(Addr), FileSize); + SmallString<128> Storage; + StringRef P = Name.toNullTerminatedStringRef(Storage); + while ((ResultFD = open(P.begin(), OpenFlags, Mode)) < 0) { + if (errno != EINTR) + return error_code(errno, system_category()); + } + return error_code::success(); } -} // end llvm namespace +} // end namespace fs +} // end namespace sys +} // end namespace llvm diff --git a/contrib/llvm/lib/Support/Unix/PathV2.inc b/contrib/llvm/lib/Support/Unix/PathV2.inc deleted file mode 100644 index 7e0aead..0000000 --- a/contrib/llvm/lib/Support/Unix/PathV2.inc +++ /dev/null @@ -1,693 +0,0 @@ -//===- llvm/Support/Unix/PathV2.cpp - Unix Path Implementation --*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the Unix specific implementation of the PathV2 API. -// -//===----------------------------------------------------------------------===// - -//===----------------------------------------------------------------------===// -//=== WARNING: Implementation here must contain only generic UNIX code that -//=== is guaranteed to work on *all* UNIX variants. -//===----------------------------------------------------------------------===// - -#include "Unix.h" -#include "llvm/Support/Process.h" -#if HAVE_SYS_STAT_H -#include <sys/stat.h> -#endif -#if HAVE_FCNTL_H -#include <fcntl.h> -#endif -#ifdef HAVE_SYS_MMAN_H -#include <sys/mman.h> -#endif -#if HAVE_DIRENT_H -# include <dirent.h> -# define NAMLEN(dirent) strlen((dirent)->d_name) -#else -# define dirent direct -# define NAMLEN(dirent) (dirent)->d_namlen -# if HAVE_SYS_NDIR_H -# include <sys/ndir.h> -# endif -# if HAVE_SYS_DIR_H -# include <sys/dir.h> -# endif -# if HAVE_NDIR_H -# include <ndir.h> -# endif -#endif -#if HAVE_STDIO_H -#include <stdio.h> -#endif -#if HAVE_LIMITS_H -#include <limits.h> -#endif - -// Both stdio.h and cstdio are included via different pathes and -// stdcxx's cstdio doesn't include stdio.h, so it doesn't #undef the macros -// either. -#undef ferror -#undef feof - -// For GNU Hurd -#if defined(__GNU__) && !defined(PATH_MAX) -# define PATH_MAX 4096 -#endif - -using namespace llvm; - -namespace { - /// This class automatically closes the given file descriptor when it goes out - /// of scope. You can take back explicit ownership of the file descriptor by - /// calling take(). The destructor does not verify that close was successful. - /// Therefore, never allow this class to call close on a file descriptor that - /// has been read from or written to. - struct AutoFD { - int FileDescriptor; - - AutoFD(int fd) : FileDescriptor(fd) {} - ~AutoFD() { - if (FileDescriptor >= 0) - ::close(FileDescriptor); - } - - int take() { - int ret = FileDescriptor; - FileDescriptor = -1; - return ret; - } - - operator int() const {return FileDescriptor;} - }; - - error_code TempDir(SmallVectorImpl<char> &result) { - // FIXME: Don't use TMPDIR if program is SUID or SGID enabled. - const char *dir = 0; - (dir = std::getenv("TMPDIR" )) || - (dir = std::getenv("TMP" )) || - (dir = std::getenv("TEMP" )) || - (dir = std::getenv("TEMPDIR")) || -#ifdef P_tmpdir - (dir = P_tmpdir) || -#endif - (dir = "/tmp"); - - result.clear(); - StringRef d(dir); - result.append(d.begin(), d.end()); - return error_code::success(); - } -} - -namespace llvm { -namespace sys { -namespace fs { - -error_code current_path(SmallVectorImpl<char> &result) { -#ifdef MAXPATHLEN - result.reserve(MAXPATHLEN); -#else -// For GNU Hurd - result.reserve(1024); -#endif - - while (true) { - if (::getcwd(result.data(), result.capacity()) == 0) { - // See if there was a real error. - if (errno != errc::not_enough_memory) - return error_code(errno, system_category()); - // Otherwise there just wasn't enough space. - result.reserve(result.capacity() * 2); - } else - break; - } - - result.set_size(strlen(result.data())); - return error_code::success(); -} - -error_code copy_file(const Twine &from, const Twine &to, copy_option copt) { - // Get arguments. - SmallString<128> from_storage; - SmallString<128> to_storage; - StringRef f = from.toNullTerminatedStringRef(from_storage); - StringRef t = to.toNullTerminatedStringRef(to_storage); - - const size_t buf_sz = 32768; - char buffer[buf_sz]; - int from_file = -1, to_file = -1; - - // Open from. - if ((from_file = ::open(f.begin(), O_RDONLY)) < 0) - return error_code(errno, system_category()); - AutoFD from_fd(from_file); - - // Stat from. - struct stat from_stat; - if (::stat(f.begin(), &from_stat) != 0) - return error_code(errno, system_category()); - - // Setup to flags. - int to_flags = O_CREAT | O_WRONLY; - if (copt == copy_option::fail_if_exists) - to_flags |= O_EXCL; - - // Open to. - if ((to_file = ::open(t.begin(), to_flags, from_stat.st_mode)) < 0) - return error_code(errno, system_category()); - AutoFD to_fd(to_file); - - // Copy! - ssize_t sz, sz_read = 1, sz_write; - while (sz_read > 0 && - (sz_read = ::read(from_fd, buffer, buf_sz)) > 0) { - // Allow for partial writes - see Advanced Unix Programming (2nd Ed.), - // Marc Rochkind, Addison-Wesley, 2004, page 94 - sz_write = 0; - do { - if ((sz = ::write(to_fd, buffer + sz_write, sz_read - sz_write)) < 0) { - sz_read = sz; // cause read loop termination. - break; // error. - } - sz_write += sz; - } while (sz_write < sz_read); - } - - // After all the file operations above the return value of close actually - // matters. - if (::close(from_fd.take()) < 0) sz_read = -1; - if (::close(to_fd.take()) < 0) sz_read = -1; - - // Check for errors. - if (sz_read < 0) - return error_code(errno, system_category()); - - return error_code::success(); -} - -error_code create_directory(const Twine &path, bool &existed) { - SmallString<128> path_storage; - StringRef p = path.toNullTerminatedStringRef(path_storage); - - if (::mkdir(p.begin(), S_IRWXU | S_IRWXG) == -1) { - if (errno != errc::file_exists) - return error_code(errno, system_category()); - existed = true; - } else - existed = false; - - return error_code::success(); -} - -error_code create_hard_link(const Twine &to, const Twine &from) { - // Get arguments. - SmallString<128> from_storage; - SmallString<128> to_storage; - StringRef f = from.toNullTerminatedStringRef(from_storage); - StringRef t = to.toNullTerminatedStringRef(to_storage); - - if (::link(t.begin(), f.begin()) == -1) - return error_code(errno, system_category()); - - return error_code::success(); -} - -error_code create_symlink(const Twine &to, const Twine &from) { - // Get arguments. - SmallString<128> from_storage; - SmallString<128> to_storage; - StringRef f = from.toNullTerminatedStringRef(from_storage); - StringRef t = to.toNullTerminatedStringRef(to_storage); - - if (::symlink(t.begin(), f.begin()) == -1) - return error_code(errno, system_category()); - - return error_code::success(); -} - -error_code remove(const Twine &path, bool &existed) { - SmallString<128> path_storage; - StringRef p = path.toNullTerminatedStringRef(path_storage); - - if (::remove(p.begin()) == -1) { - if (errno != errc::no_such_file_or_directory) - return error_code(errno, system_category()); - existed = false; - } else - existed = true; - - return error_code::success(); -} - -error_code rename(const Twine &from, const Twine &to) { - // Get arguments. - SmallString<128> from_storage; - SmallString<128> to_storage; - StringRef f = from.toNullTerminatedStringRef(from_storage); - StringRef t = to.toNullTerminatedStringRef(to_storage); - - if (::rename(f.begin(), t.begin()) == -1) { - // If it's a cross device link, copy then delete, otherwise return the error - if (errno == EXDEV) { - if (error_code ec = copy_file(from, to, copy_option::overwrite_if_exists)) - return ec; - bool Existed; - if (error_code ec = remove(from, Existed)) - return ec; - } else - return error_code(errno, system_category()); - } - - return error_code::success(); -} - -error_code resize_file(const Twine &path, uint64_t size) { - SmallString<128> path_storage; - StringRef p = path.toNullTerminatedStringRef(path_storage); - - if (::truncate(p.begin(), size) == -1) - return error_code(errno, system_category()); - - return error_code::success(); -} - -error_code exists(const Twine &path, bool &result) { - SmallString<128> path_storage; - StringRef p = path.toNullTerminatedStringRef(path_storage); - - if (::access(p.begin(), F_OK) == -1) { - if (errno != errc::no_such_file_or_directory) - return error_code(errno, system_category()); - result = false; - } else - result = true; - - return error_code::success(); -} - -bool equivalent(file_status A, file_status B) { - assert(status_known(A) && status_known(B)); - return A.fs_st_dev == B.fs_st_dev && - A.fs_st_ino == B.fs_st_ino; -} - -error_code equivalent(const Twine &A, const Twine &B, bool &result) { - file_status fsA, fsB; - if (error_code ec = status(A, fsA)) return ec; - if (error_code ec = status(B, fsB)) return ec; - result = equivalent(fsA, fsB); - return error_code::success(); -} - -error_code file_size(const Twine &path, uint64_t &result) { - SmallString<128> path_storage; - StringRef p = path.toNullTerminatedStringRef(path_storage); - - struct stat status; - if (::stat(p.begin(), &status) == -1) - return error_code(errno, system_category()); - if (!S_ISREG(status.st_mode)) - return make_error_code(errc::operation_not_permitted); - - result = status.st_size; - return error_code::success(); -} - -error_code status(const Twine &path, file_status &result) { - SmallString<128> path_storage; - StringRef p = path.toNullTerminatedStringRef(path_storage); - - struct stat status; - if (::stat(p.begin(), &status) != 0) { - error_code ec(errno, system_category()); - if (ec == errc::no_such_file_or_directory) - result = file_status(file_type::file_not_found); - else - result = file_status(file_type::status_error); - return ec; - } - - perms prms = static_cast<perms>(status.st_mode & perms_mask); - - if (S_ISDIR(status.st_mode)) - result = file_status(file_type::directory_file, prms); - else if (S_ISREG(status.st_mode)) - result = file_status(file_type::regular_file, prms); - else if (S_ISBLK(status.st_mode)) - result = file_status(file_type::block_file, prms); - else if (S_ISCHR(status.st_mode)) - result = file_status(file_type::character_file, prms); - else if (S_ISFIFO(status.st_mode)) - result = file_status(file_type::fifo_file, prms); - else if (S_ISSOCK(status.st_mode)) - result = file_status(file_type::socket_file, prms); - else - result = file_status(file_type::type_unknown, prms); - - result.fs_st_dev = status.st_dev; - result.fs_st_ino = status.st_ino; - - return error_code::success(); -} - -// Modifies permissions on a file. -error_code permissions(const Twine &path, perms prms) { - if ((prms & add_perms) && (prms & remove_perms)) - llvm_unreachable("add_perms and remove_perms are mutually exclusive"); - - // Get current permissions - file_status info; - if (error_code ec = status(path, info)) { - return ec; - } - - // Set updated permissions. - SmallString<128> path_storage; - StringRef p = path.toNullTerminatedStringRef(path_storage); - perms permsToSet; - if (prms & add_perms) { - permsToSet = (info.permissions() | prms) & perms_mask; - } else if (prms & remove_perms) { - permsToSet = (info.permissions() & ~prms) & perms_mask; - } else { - permsToSet = prms & perms_mask; - } - if (::chmod(p.begin(), static_cast<mode_t>(permsToSet))) { - return error_code(errno, system_category()); - } - - return error_code::success(); -} - -// Since this is most often used for temporary files, mode defaults to 0600. -error_code unique_file(const Twine &model, int &result_fd, - SmallVectorImpl<char> &result_path, - bool makeAbsolute, unsigned mode) { - SmallString<128> Model; - model.toVector(Model); - // Null terminate. - Model.c_str(); - - if (makeAbsolute) { - // Make model absolute by prepending a temp directory if it's not already. - bool absolute = path::is_absolute(Twine(Model)); - if (!absolute) { - SmallString<128> TDir; - if (error_code ec = TempDir(TDir)) return ec; - path::append(TDir, Twine(Model)); - Model.swap(TDir); - } - } - - // From here on, DO NOT modify model. It may be needed if the randomly chosen - // path already exists. - SmallString<128> RandomPath = Model; - -retry_random_path: - // Replace '%' with random chars. - for (unsigned i = 0, e = Model.size(); i != e; ++i) { - if (Model[i] == '%') - RandomPath[i] = "0123456789abcdef"[sys::Process::GetRandomNumber() & 15]; - } - - // Make sure we don't fall into an infinite loop by constantly trying - // to create the parent path. - bool TriedToCreateParent = false; - - // Try to open + create the file. -rety_open_create: - int RandomFD = ::open(RandomPath.c_str(), O_RDWR | O_CREAT | O_EXCL, mode); - if (RandomFD == -1) { - int SavedErrno = errno; - // If the file existed, try again, otherwise, error. - if (SavedErrno == errc::file_exists) - goto retry_random_path; - // If path prefix doesn't exist, try to create it. - if (SavedErrno == errc::no_such_file_or_directory && !TriedToCreateParent) { - TriedToCreateParent = true; - StringRef p(RandomPath); - SmallString<64> dir_to_create; - for (path::const_iterator i = path::begin(p), - e = --path::end(p); i != e; ++i) { - path::append(dir_to_create, *i); - bool Exists; - if (error_code ec = exists(Twine(dir_to_create), Exists)) return ec; - if (!Exists) { - // Don't try to create network paths. - if (i->size() > 2 && (*i)[0] == '/' && - (*i)[1] == '/' && - (*i)[2] != '/') - return make_error_code(errc::no_such_file_or_directory); - if (::mkdir(dir_to_create.c_str(), 0700) == -1 && - errno != errc::file_exists) - return error_code(errno, system_category()); - } - } - goto rety_open_create; - } - - return error_code(SavedErrno, system_category()); - } - - // Make the path absolute. - char real_path_buff[PATH_MAX + 1]; - if (realpath(RandomPath.c_str(), real_path_buff) == NULL) { - int error = errno; - ::close(RandomFD); - ::unlink(RandomPath.c_str()); - return error_code(error, system_category()); - } - - result_path.clear(); - StringRef d(real_path_buff); - result_path.append(d.begin(), d.end()); - - result_fd = RandomFD; - return error_code::success(); -} - -error_code mapped_file_region::init(int FD, bool CloseFD, uint64_t Offset) { - AutoFD ScopedFD(FD); - if (!CloseFD) - ScopedFD.take(); - - // Figure out how large the file is. - struct stat FileInfo; - if (fstat(FD, &FileInfo) == -1) - return error_code(errno, system_category()); - uint64_t FileSize = FileInfo.st_size; - - if (Size == 0) - Size = FileSize; - else if (FileSize < Size) { - // We need to grow the file. - if (ftruncate(FD, Size) == -1) - return error_code(errno, system_category()); - } - - int flags = (Mode == readwrite) ? MAP_SHARED : MAP_PRIVATE; - int prot = (Mode == readonly) ? PROT_READ : (PROT_READ | PROT_WRITE); -#ifdef MAP_FILE - flags |= MAP_FILE; -#endif - Mapping = ::mmap(0, Size, prot, flags, FD, Offset); - if (Mapping == MAP_FAILED) - return error_code(errno, system_category()); - return error_code::success(); -} - -mapped_file_region::mapped_file_region(const Twine &path, - mapmode mode, - uint64_t length, - uint64_t offset, - error_code &ec) - : Mode(mode) - , Size(length) - , Mapping() { - // Make sure that the requested size fits within SIZE_T. - if (length > std::numeric_limits<size_t>::max()) { - ec = make_error_code(errc::invalid_argument); - return; - } - - SmallString<128> path_storage; - StringRef name = path.toNullTerminatedStringRef(path_storage); - int oflags = (mode == readonly) ? O_RDONLY : O_RDWR; - int ofd = ::open(name.begin(), oflags); - if (ofd == -1) { - ec = error_code(errno, system_category()); - return; - } - - ec = init(ofd, true, offset); - if (ec) - Mapping = 0; -} - -mapped_file_region::mapped_file_region(int fd, - bool closefd, - mapmode mode, - uint64_t length, - uint64_t offset, - error_code &ec) - : Mode(mode) - , Size(length) - , Mapping() { - // Make sure that the requested size fits within SIZE_T. - if (length > std::numeric_limits<size_t>::max()) { - ec = make_error_code(errc::invalid_argument); - return; - } - - ec = init(fd, closefd, offset); - if (ec) - Mapping = 0; -} - -mapped_file_region::~mapped_file_region() { - if (Mapping) - ::munmap(Mapping, Size); -} - -#if LLVM_HAS_RVALUE_REFERENCES -mapped_file_region::mapped_file_region(mapped_file_region &&other) - : Mode(other.Mode), Size(other.Size), Mapping(other.Mapping) { - other.Mapping = 0; -} -#endif - -mapped_file_region::mapmode mapped_file_region::flags() const { - assert(Mapping && "Mapping failed but used anyway!"); - return Mode; -} - -uint64_t mapped_file_region::size() const { - assert(Mapping && "Mapping failed but used anyway!"); - return Size; -} - -char *mapped_file_region::data() const { - assert(Mapping && "Mapping failed but used anyway!"); - assert(Mode != readonly && "Cannot get non const data for readonly mapping!"); - return reinterpret_cast<char*>(Mapping); -} - -const char *mapped_file_region::const_data() const { - assert(Mapping && "Mapping failed but used anyway!"); - return reinterpret_cast<const char*>(Mapping); -} - -int mapped_file_region::alignment() { - return process::get_self()->page_size(); -} - -error_code detail::directory_iterator_construct(detail::DirIterState &it, - StringRef path){ - SmallString<128> path_null(path); - DIR *directory = ::opendir(path_null.c_str()); - if (directory == 0) - return error_code(errno, system_category()); - - it.IterationHandle = reinterpret_cast<intptr_t>(directory); - // Add something for replace_filename to replace. - path::append(path_null, "."); - it.CurrentEntry = directory_entry(path_null.str()); - return directory_iterator_increment(it); -} - -error_code detail::directory_iterator_destruct(detail::DirIterState &it) { - if (it.IterationHandle) - ::closedir(reinterpret_cast<DIR *>(it.IterationHandle)); - it.IterationHandle = 0; - it.CurrentEntry = directory_entry(); - return error_code::success(); -} - -error_code detail::directory_iterator_increment(detail::DirIterState &it) { - errno = 0; - dirent *cur_dir = ::readdir(reinterpret_cast<DIR *>(it.IterationHandle)); - if (cur_dir == 0 && errno != 0) { - return error_code(errno, system_category()); - } else if (cur_dir != 0) { - StringRef name(cur_dir->d_name, NAMLEN(cur_dir)); - if ((name.size() == 1 && name[0] == '.') || - (name.size() == 2 && name[0] == '.' && name[1] == '.')) - return directory_iterator_increment(it); - it.CurrentEntry.replace_filename(name); - } else - return directory_iterator_destruct(it); - - return error_code::success(); -} - -error_code get_magic(const Twine &path, uint32_t len, - SmallVectorImpl<char> &result) { - SmallString<128> PathStorage; - StringRef Path = path.toNullTerminatedStringRef(PathStorage); - result.set_size(0); - - // Open path. - std::FILE *file = std::fopen(Path.data(), "rb"); - if (file == 0) - return error_code(errno, system_category()); - - // Reserve storage. - result.reserve(len); - - // Read magic! - size_t size = std::fread(result.data(), 1, len, file); - if (std::ferror(file) != 0) { - std::fclose(file); - return error_code(errno, system_category()); - } else if (size != result.size()) { - if (std::feof(file) != 0) { - std::fclose(file); - result.set_size(size); - return make_error_code(errc::value_too_large); - } - } - std::fclose(file); - result.set_size(len); - return error_code::success(); -} - -error_code map_file_pages(const Twine &path, off_t file_offset, size_t size, - bool map_writable, void *&result) { - SmallString<128> path_storage; - StringRef name = path.toNullTerminatedStringRef(path_storage); - int oflags = map_writable ? O_RDWR : O_RDONLY; - int ofd = ::open(name.begin(), oflags); - if ( ofd == -1 ) - return error_code(errno, system_category()); - AutoFD fd(ofd); - int flags = map_writable ? MAP_SHARED : MAP_PRIVATE; - int prot = map_writable ? (PROT_READ|PROT_WRITE) : PROT_READ; -#ifdef MAP_FILE - flags |= MAP_FILE; -#endif - result = ::mmap(0, size, prot, flags, fd, file_offset); - if (result == MAP_FAILED) { - return error_code(errno, system_category()); - } - - return error_code::success(); -} - -error_code unmap_file_pages(void *base, size_t size) { - if ( ::munmap(base, size) == -1 ) - return error_code(errno, system_category()); - - return error_code::success(); -} - - -} // end namespace fs -} // end namespace sys -} // end namespace llvm diff --git a/contrib/llvm/lib/Support/Unix/Process.inc b/contrib/llvm/lib/Support/Unix/Process.inc index 9a4454f..c5778e7 100644 --- a/contrib/llvm/lib/Support/Unix/Process.inc +++ b/contrib/llvm/lib/Support/Unix/Process.inc @@ -13,6 +13,9 @@ #include "Unix.h" #include "llvm/ADT/Hashing.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Mutex.h" +#include "llvm/Support/MutexGuard.h" #include "llvm/Support/TimeValue.h" #ifdef HAVE_SYS_TIME_H #include <sys/time.h> @@ -86,13 +89,10 @@ TimeValue self_process::get_system_time() const { return getRUsageTimes().second; } +// On Cygwin, getpagesize() returns 64k(AllocationGranularity) and +// offset in mmap(3) should be aligned to the AllocationGranularity. static unsigned getPageSize() { -#if defined(__CYGWIN__) - // On Cygwin, getpagesize() returns 64k but the page size for the purposes of - // memory protection and mmap() is 4k. - // See http://www.cygwin.com/ml/cygwin/2009-01/threads.html#00492 - const int page_size = 0x1000; -#elif defined(HAVE_GETPAGESIZE) +#if defined(HAVE_GETPAGESIZE) const int page_size = ::getpagesize(); #elif defined(HAVE_SYSCONF) long page_size = ::sysconf(_SC_PAGE_SIZE); @@ -138,14 +138,6 @@ void Process::GetTimeUsage(TimeValue &elapsed, TimeValue &user_time, llvm::tie(user_time, sys_time) = getRUsageTimes(); } -int Process::GetCurrentUserId() { - return getuid(); -} - -int Process::GetCurrentGroupId() { - return getgid(); -} - #if defined(HAVE_MACH_MACH_H) && !defined(__GNU__) #include <mach/mach.h> #endif @@ -190,6 +182,22 @@ void Process::PreventCoreFiles() { #endif } +Optional<std::string> Process::GetEnv(StringRef Name) { + std::string NameStr = Name.str(); + const char *Val = ::getenv(NameStr.c_str()); + if (!Val) + return None; + return std::string(Val); +} + +error_code Process::GetArgumentVector(SmallVectorImpl<const char *> &ArgsOut, + ArrayRef<const char *> ArgsIn, + SpecificBumpPtrAllocator<char> &) { + ArgsOut.append(ArgsIn.begin(), ArgsIn.end()); + + return error_code::success(); +} + bool Process::StandardInIsUserInput() { return FileDescriptorIsDisplayed(STDIN_FILENO); } @@ -224,8 +232,6 @@ static unsigned getColumns(int FileID) { #if defined(HAVE_SYS_IOCTL_H) && defined(HAVE_TERMIOS_H) // Try to determine the width of the terminal. struct winsize ws; - // Zero-fill ws to avoid a false positive from MemorySanitizer. - memset(&ws, 0, sizeof(ws)); if (ioctl(FileID, TIOCGWINSZ, &ws) == 0) Columns = ws.ws_col; #endif @@ -247,22 +253,61 @@ unsigned Process::StandardErrColumns() { return getColumns(2); } -static bool terminalHasColors() { - if (const char *term = std::getenv("TERM")) { - // Most modern terminals support ANSI escape sequences for colors. - // We could check terminfo, or have a list of known terms that support - // colors, but that would be overkill. - // The user can always ask for no colors by setting TERM to dumb, or - // using a commandline flag. - return strcmp(term, "dumb") != 0; - } +#ifdef HAVE_TERMINFO +// We manually declare these extern functions because finding the correct +// headers from various terminfo, curses, or other sources is harder than +// writing their specs down. +extern "C" int setupterm(char *term, int filedes, int *errret); +extern "C" struct term *set_curterm(struct term *termp); +extern "C" int del_curterm(struct term *termp); +extern "C" int tigetnum(char *capname); +#endif + +static bool terminalHasColors(int fd) { +#ifdef HAVE_TERMINFO + // First, acquire a global lock because these C routines are thread hostile. + static sys::Mutex M; + MutexGuard G(M); + + int errret = 0; + if (setupterm((char *)0, fd, &errret) != 0) + // Regardless of why, if we can't get terminfo, we shouldn't try to print + // colors. + return false; + + // Test whether the terminal as set up supports color output. How to do this + // isn't entirely obvious. We can use the curses routine 'has_colors' but it + // would be nice to avoid a dependency on curses proper when we can make do + // with a minimal terminfo parsing library. Also, we don't really care whether + // the terminal supports the curses-specific color changing routines, merely + // if it will interpret ANSI color escape codes in a reasonable way. Thus, the + // strategy here is just to query the baseline colors capability and if it + // supports colors at all to assume it will translate the escape codes into + // whatever range of colors it does support. We can add more detailed tests + // here if users report them as necessary. + // + // The 'tigetnum' routine returns -2 or -1 on errors, and might return 0 if + // the terminfo says that no colors are supported. + bool HasColors = tigetnum(const_cast<char *>("colors")) > 0; + + // Now extract the structure allocated by setupterm and free its memory + // through a really silly dance. + struct term *termp = set_curterm((struct term *)0); + (void)del_curterm(termp); // Drop any errors here. + + // Return true if we found a color capabilities for the current terminal. + if (HasColors) + return true; +#endif + + // Otherwise, be conservative. return false; } bool Process::FileDescriptorHasColors(int fd) { // A file descriptor has colors if it is displayed and the terminal has // colors. - return FileDescriptorIsDisplayed(fd) && terminalHasColors(); + return FileDescriptorIsDisplayed(fd) && terminalHasColors(fd); } bool Process::StandardOutHasColors() { @@ -273,29 +318,15 @@ bool Process::StandardErrHasColors() { return FileDescriptorHasColors(STDERR_FILENO); } +void Process::UseANSIEscapeCodes(bool /*enable*/) { + // No effect. +} + bool Process::ColorNeedsFlush() { // No, we use ANSI escape sequences. return false; } -#define COLOR(FGBG, CODE, BOLD) "\033[0;" BOLD FGBG CODE "m" - -#define ALLCOLORS(FGBG,BOLD) {\ - COLOR(FGBG, "0", BOLD),\ - COLOR(FGBG, "1", BOLD),\ - COLOR(FGBG, "2", BOLD),\ - COLOR(FGBG, "3", BOLD),\ - COLOR(FGBG, "4", BOLD),\ - COLOR(FGBG, "5", BOLD),\ - COLOR(FGBG, "6", BOLD),\ - COLOR(FGBG, "7", BOLD)\ - } - -static const char colorcodes[2][2][8][10] = { - { ALLCOLORS("3",""), ALLCOLORS("3","1;") }, - { ALLCOLORS("4",""), ALLCOLORS("4","1;") } -}; - const char *Process::OutputColor(char code, bool bold, bool bg) { return colorcodes[bg?1:0][bold?1:0][code&7]; } diff --git a/contrib/llvm/lib/Support/Unix/Program.inc b/contrib/llvm/lib/Support/Unix/Program.inc index aa03d48..78b2971 100644 --- a/contrib/llvm/lib/Support/Unix/Program.inc +++ b/contrib/llvm/lib/Support/Unix/Program.inc @@ -36,6 +36,9 @@ #include <unistd.h> #endif #ifdef HAVE_POSIX_SPAWN +#ifdef __sun__ +#define _RESTRICT_KYWD +#endif #include <spawn.h> #if !defined(__APPLE__) extern char **environ; @@ -47,20 +50,16 @@ namespace llvm { using namespace sys; -Program::Program() : Data_(0) {} - -Program::~Program() {} +ProcessInfo::ProcessInfo() : Pid(0), ReturnCode(0) {} // This function just uses the PATH environment variable to find the program. -Path -Program::FindProgramByName(const std::string& progName) { +std::string +sys::FindProgramByName(const std::string& progName) { // Check some degenerate cases if (progName.length() == 0) // no program - return Path(); - Path temp; - if (!temp.set(progName)) // invalid name - return Path(); + return ""; + std::string temp = progName; // Use the given path verbatim if it contains any slashes; this matches // the behavior of sh(1) and friends. if (progName.find('/') != std::string::npos) @@ -72,7 +71,7 @@ Program::FindProgramByName(const std::string& progName) { // Get the path. If its empty, we can't do anything to find it. const char *PathStr = getenv("PATH"); if (PathStr == 0) - return Path(); + return ""; // Now we have a colon separated list of directories to search; try them. size_t PathLen = strlen(PathStr); @@ -81,12 +80,10 @@ Program::FindProgramByName(const std::string& progName) { const char *Colon = std::find(PathStr, PathStr+PathLen, ':'); // Check to see if this first directory contains the executable... - Path FilePath; - if (FilePath.set(std::string(PathStr,Colon))) { - FilePath.appendComponent(progName); - if (FilePath.canExecute()) - return FilePath; // Found the executable! - } + SmallString<128> FilePath(PathStr,Colon); + sys::path::append(FilePath, progName); + if (sys::fs::can_execute(Twine(FilePath))) + return FilePath.str(); // Found the executable! // Nope it wasn't in this directory, check the next path in the list! PathLen -= Colon-PathStr; @@ -98,23 +95,23 @@ Program::FindProgramByName(const std::string& progName) { PathLen--; } } - return Path(); + return ""; } -static bool RedirectIO(const Path *Path, int FD, std::string* ErrMsg) { +static bool RedirectIO(const StringRef *Path, int FD, std::string* ErrMsg) { if (Path == 0) // Noop return false; - const char *File; - if (Path->isEmpty()) + std::string File; + if (Path->empty()) // Redirect empty paths to /dev/null File = "/dev/null"; else - File = Path->c_str(); + File = *Path; // Open the file - int InFD = open(File, FD == 0 ? O_RDONLY : O_WRONLY|O_CREAT, 0666); + int InFD = open(File.c_str(), FD == 0 ? O_RDONLY : O_WRONLY|O_CREAT, 0666); if (InFD == -1) { - MakeErrMsg(ErrMsg, "Cannot open file '" + std::string(File) + "' for " + MakeErrMsg(ErrMsg, "Cannot open file '" + File + "' for " + (FD == 0 ? "input" : "output")); return true; } @@ -130,19 +127,20 @@ static bool RedirectIO(const Path *Path, int FD, std::string* ErrMsg) { } #ifdef HAVE_POSIX_SPAWN -static bool RedirectIO_PS(const Path *Path, int FD, std::string *ErrMsg, +static bool RedirectIO_PS(const std::string *Path, int FD, std::string *ErrMsg, posix_spawn_file_actions_t *FileActions) { if (Path == 0) // Noop return false; const char *File; - if (Path->isEmpty()) + if (Path->empty()) // Redirect empty paths to /dev/null File = "/dev/null"; else File = Path->c_str(); - if (int Err = posix_spawn_file_actions_addopen(FileActions, FD, - File, FD == 0 ? O_RDONLY : O_WRONLY|O_CREAT, 0666)) + if (int Err = posix_spawn_file_actions_addopen( + FileActions, FD, File, + FD == 0 ? O_RDONLY : O_WRONLY | O_CREAT, 0666)) return MakeErrMsg(ErrMsg, "Cannot dup2", Err); return false; } @@ -180,10 +178,18 @@ static void SetMemoryLimits (unsigned size) #endif } -bool -Program::Execute(const Path &path, const char **args, const char **envp, - const Path **redirects, unsigned memoryLimit, - std::string *ErrMsg) { +} + +static bool Execute(ProcessInfo &PI, StringRef Program, const char **args, + const char **envp, const StringRef **redirects, + unsigned memoryLimit, std::string *ErrMsg) { + if (!llvm::sys::fs::exists(Program)) { + if (ErrMsg) + *ErrMsg = std::string("Executable \"") + Program.str() + + std::string("\" doesn't exist!"); + return false; + } + // If this OS has posix_spawn and there is no memory limit being implied, use // posix_spawn. It is more efficient than fork/exec. #ifdef HAVE_POSIX_SPAWN @@ -191,18 +197,32 @@ Program::Execute(const Path &path, const char **args, const char **envp, posix_spawn_file_actions_t FileActionsStore; posix_spawn_file_actions_t *FileActions = 0; + // If we call posix_spawn_file_actions_addopen we have to make sure the + // c strings we pass to it stay alive until the call to posix_spawn, + // so we copy any StringRefs into this variable. + std::string RedirectsStorage[3]; + if (redirects) { + std::string *RedirectsStr[3] = {0, 0, 0}; + for (int I = 0; I < 3; ++I) { + if (redirects[I]) { + RedirectsStorage[I] = *redirects[I]; + RedirectsStr[I] = &RedirectsStorage[I]; + } + } + FileActions = &FileActionsStore; posix_spawn_file_actions_init(FileActions); // Redirect stdin/stdout. - if (RedirectIO_PS(redirects[0], 0, ErrMsg, FileActions) || - RedirectIO_PS(redirects[1], 1, ErrMsg, FileActions)) + if (RedirectIO_PS(RedirectsStr[0], 0, ErrMsg, FileActions) || + RedirectIO_PS(RedirectsStr[1], 1, ErrMsg, FileActions)) return false; if (redirects[1] == 0 || redirects[2] == 0 || *redirects[1] != *redirects[2]) { // Just redirect stderr - if (RedirectIO_PS(redirects[2], 2, ErrMsg, FileActions)) return false; + if (RedirectIO_PS(RedirectsStr[2], 2, ErrMsg, FileActions)) + return false; } else { // If stdout and stderr should go to the same place, redirect stderr // to the FD already open for stdout. @@ -222,7 +242,7 @@ Program::Execute(const Path &path, const char **args, const char **envp, // Explicitly initialized to prevent what appears to be a valgrind false // positive. pid_t PID = 0; - int Err = posix_spawn(&PID, path.c_str(), FileActions, /*attrp*/0, + int Err = posix_spawn(&PID, Program.str().c_str(), FileActions, /*attrp*/0, const_cast<char **>(args), const_cast<char **>(envp)); if (FileActions) @@ -231,7 +251,8 @@ Program::Execute(const Path &path, const char **args, const char **envp, if (Err) return !MakeErrMsg(ErrMsg, "posix_spawn failed", Err); - Data_ = reinterpret_cast<void*>(PID); + PI.Pid = PID; + return true; } #endif @@ -272,12 +293,13 @@ Program::Execute(const Path &path, const char **args, const char **envp, } // Execute! + std::string PathStr = Program; if (envp != 0) - execve(path.c_str(), + execve(PathStr.c_str(), const_cast<char **>(args), const_cast<char **>(envp)); else - execv(path.c_str(), + execv(PathStr.c_str(), const_cast<char **>(args)); // If the execve() failed, we should exit. Follow Unix protocol and // return 127 if the executable was not found, and 126 otherwise. @@ -293,62 +315,71 @@ Program::Execute(const Path &path, const char **args, const char **envp, break; } - Data_ = reinterpret_cast<void*>(child); + PI.Pid = child; return true; } -int -Program::Wait(const sys::Path &path, - unsigned secondsToWait, - std::string* ErrMsg) -{ +namespace llvm { + +ProcessInfo sys::Wait(const ProcessInfo &PI, unsigned SecondsToWait, + bool WaitUntilTerminates, std::string *ErrMsg) { #ifdef HAVE_SYS_WAIT_H struct sigaction Act, Old; - - if (Data_ == 0) { - MakeErrMsg(ErrMsg, "Process not started!"); - return -1; - } - - // Install a timeout handler. The handler itself does nothing, but the simple - // fact of having a handler at all causes the wait below to return with EINTR, - // unlike if we used SIG_IGN. - if (secondsToWait) { + assert(PI.Pid && "invalid pid to wait on, process not started?"); + + int WaitPidOptions = 0; + pid_t ChildPid = PI.Pid; + if (WaitUntilTerminates) { + SecondsToWait = 0; + ChildPid = -1; // mimic a wait() using waitpid() + } else if (SecondsToWait) { + // Install a timeout handler. The handler itself does nothing, but the + // simple fact of having a handler at all causes the wait below to return + // with EINTR, unlike if we used SIG_IGN. memset(&Act, 0, sizeof(Act)); Act.sa_handler = TimeOutHandler; sigemptyset(&Act.sa_mask); sigaction(SIGALRM, &Act, &Old); - alarm(secondsToWait); - } + alarm(SecondsToWait); + } else if (SecondsToWait == 0) + WaitPidOptions = WNOHANG; // Parent process: Wait for the child process to terminate. int status; - uint64_t pid = reinterpret_cast<uint64_t>(Data_); - pid_t child = static_cast<pid_t>(pid); - while (waitpid(pid, &status, 0) != child) - if (secondsToWait && errno == EINTR) { - // Kill the child. - kill(child, SIGKILL); - - // Turn off the alarm and restore the signal handler - alarm(0); - sigaction(SIGALRM, &Old, 0); - - // Wait for child to die - if (wait(&status) != child) - MakeErrMsg(ErrMsg, "Child timed out but wouldn't die"); - else - MakeErrMsg(ErrMsg, "Child timed out", 0); - - return -2; // Timeout detected - } else if (errno != EINTR) { - MakeErrMsg(ErrMsg, "Error waiting for child process"); - return -1; + ProcessInfo WaitResult; + WaitResult.Pid = waitpid(ChildPid, &status, WaitPidOptions); + if (WaitResult.Pid != PI.Pid) { + if (WaitResult.Pid == 0) { + // Non-blocking wait. + return WaitResult; + } else { + if (SecondsToWait && errno == EINTR) { + // Kill the child. + kill(PI.Pid, SIGKILL); + + // Turn off the alarm and restore the signal handler + alarm(0); + sigaction(SIGALRM, &Old, 0); + + // Wait for child to die + if (wait(&status) != ChildPid) + MakeErrMsg(ErrMsg, "Child timed out but wouldn't die"); + else + MakeErrMsg(ErrMsg, "Child timed out", 0); + + WaitResult.ReturnCode = -2; // Timeout detected + return WaitResult; + } else if (errno != EINTR) { + MakeErrMsg(ErrMsg, "Error waiting for child process"); + WaitResult.ReturnCode = -1; + return WaitResult; + } } + } // We exited normally without timeout, so turn off the timer. - if (secondsToWait) { + if (SecondsToWait && !WaitUntilTerminates) { alarm(0); sigaction(SIGALRM, &Old, 0); } @@ -358,24 +389,19 @@ Program::Wait(const sys::Path &path, int result = 0; if (WIFEXITED(status)) { result = WEXITSTATUS(status); -#ifdef HAVE_POSIX_SPAWN - // The posix_spawn child process returns 127 on any kind of error. - // Following the POSIX convention for command-line tools (which posix_spawn - // itself apparently does not), check to see if the failure was due to some - // reason other than the file not existing, and return 126 in this case. - bool Exists; - if (result == 127 && !llvm::sys::fs::exists(path.str(), Exists) && Exists) - result = 126; -#endif + WaitResult.ReturnCode = result; + if (result == 127) { if (ErrMsg) *ErrMsg = llvm::sys::StrError(ENOENT); - return -1; + WaitResult.ReturnCode = -1; + return WaitResult; } if (result == 126) { if (ErrMsg) *ErrMsg = "Program could not be executed"; - return -1; + WaitResult.ReturnCode = -1; + return WaitResult; } } else if (WIFSIGNALED(status)) { if (ErrMsg) { @@ -387,27 +413,27 @@ Program::Wait(const sys::Path &path, } // Return a special value to indicate that the process received an unhandled // signal during execution as opposed to failing to execute. - return -2; + WaitResult.ReturnCode = -2; } - return result; #else if (ErrMsg) *ErrMsg = "Program::Wait is not implemented on this platform yet!"; - return -1; + WaitResult.ReturnCode = -2; #endif + return WaitResult; } -error_code Program::ChangeStdinToBinary(){ +error_code sys::ChangeStdinToBinary(){ // Do nothing, as Unix doesn't differentiate between text and binary. return make_error_code(errc::success); } -error_code Program::ChangeStdoutToBinary(){ +error_code sys::ChangeStdoutToBinary(){ // Do nothing, as Unix doesn't differentiate between text and binary. return make_error_code(errc::success); } -error_code Program::ChangeStderrToBinary(){ +error_code sys::ChangeStderrToBinary(){ // Do nothing, as Unix doesn't differentiate between text and binary. return make_error_code(errc::success); } @@ -432,5 +458,4 @@ bool llvm::sys::argumentsFitWithinSystemLimits(ArrayRef<const char*> Args) { } return true; } - } diff --git a/contrib/llvm/lib/Support/Unix/Signals.inc b/contrib/llvm/lib/Support/Unix/Signals.inc index 64d1fc1..b4c78d6 100644 --- a/contrib/llvm/lib/Support/Unix/Signals.inc +++ b/contrib/llvm/lib/Support/Unix/Signals.inc @@ -55,8 +55,7 @@ static std::vector<std::pair<void(*)(void*), void*> > CallBacksToRun; static const int IntSigs[] = { SIGHUP, SIGINT, SIGPIPE, SIGTERM, SIGUSR1, SIGUSR2 }; -static const int *const IntSigsEnd = - IntSigs + sizeof(IntSigs) / sizeof(IntSigs[0]); +static const int *const IntSigsEnd = array_endof(IntSigs); // KillSigs - Signals that represent that we have a bug, and our prompt // termination has been ordered. @@ -75,8 +74,7 @@ static const int KillSigs[] = { , SIGEMT #endif }; -static const int *const KillSigsEnd = - KillSigs + sizeof(KillSigs) / sizeof(KillSigs[0]); +static const int *const KillSigsEnd = array_endof(KillSigs); static unsigned NumRegisteredSignals = 0; static struct { @@ -211,11 +209,11 @@ void llvm::sys::SetInterruptFunction(void (*IF)()) { } // RemoveFileOnSignal - The public API -bool llvm::sys::RemoveFileOnSignal(const sys::Path &Filename, +bool llvm::sys::RemoveFileOnSignal(StringRef Filename, std::string* ErrMsg) { SignalsMutex.acquire(); std::string *OldPtr = FilesToRemove.empty() ? 0 : &FilesToRemove[0]; - FilesToRemove.push_back(Filename.str()); + FilesToRemove.push_back(Filename); // We want to call 'c_str()' on every std::string in this vector so that if // the underlying implementation requires a re-allocation, it happens here @@ -235,10 +233,10 @@ bool llvm::sys::RemoveFileOnSignal(const sys::Path &Filename, } // DontRemoveFileOnSignal - The public API -void llvm::sys::DontRemoveFileOnSignal(const sys::Path &Filename) { +void llvm::sys::DontRemoveFileOnSignal(StringRef Filename) { SignalsMutex.acquire(); std::vector<std::string>::reverse_iterator RI = - std::find(FilesToRemove.rbegin(), FilesToRemove.rend(), Filename.str()); + std::find(FilesToRemove.rbegin(), FilesToRemove.rend(), Filename); std::vector<std::string>::iterator I = FilesToRemove.end(); if (RI != FilesToRemove.rend()) I = FilesToRemove.erase(RI.base()-1); @@ -335,7 +333,7 @@ static void PrintStackTraceSignalHandler(void *) { void llvm::sys::PrintStackTraceOnErrorSignal() { AddSignalHandler(PrintStackTraceSignalHandler, 0); -#if defined(__APPLE__) +#if defined(__APPLE__) && defined(ENABLE_CRASH_OVERRIDES) // Environment variable to disable any kind of crash dialog. if (getenv("LLVM_DISABLE_CRASH_REPORT")) { mach_port_t self = mach_task_self(); @@ -361,7 +359,7 @@ void llvm::sys::PrintStackTraceOnErrorSignal() { // the same linkage unit by just defining our own versions of the assert handler // and abort. -#ifdef __APPLE__ +#if defined(__APPLE__) && defined(ENABLE_CRASH_OVERRIDES) #include <signal.h> #include <pthread.h> diff --git a/contrib/llvm/lib/Support/Unix/ThreadLocal.inc b/contrib/llvm/lib/Support/Unix/ThreadLocal.inc index 2b4c901..f14d0fa 100644 --- a/contrib/llvm/lib/Support/Unix/ThreadLocal.inc +++ b/contrib/llvm/lib/Support/Unix/ThreadLocal.inc @@ -18,7 +18,7 @@ namespace llvm { using namespace sys; -ThreadLocalImpl::ThreadLocalImpl() { } +ThreadLocalImpl::ThreadLocalImpl() : data() { } ThreadLocalImpl::~ThreadLocalImpl() { } void ThreadLocalImpl::setInstance(const void* d) { data = const_cast<void*>(d);} const void* ThreadLocalImpl::getInstance() { return data; } diff --git a/contrib/llvm/lib/Support/Unix/TimeValue.inc b/contrib/llvm/lib/Support/Unix/TimeValue.inc index df8558b..80532b0 100644 --- a/contrib/llvm/lib/Support/Unix/TimeValue.inc +++ b/contrib/llvm/lib/Support/Unix/TimeValue.inc @@ -22,18 +22,13 @@ namespace llvm { using namespace sys; std::string TimeValue::str() const { - char buffer[32]; - - time_t ourTime = time_t(this->toEpochTime()); -#ifdef __hpux -// note that the following line needs -D_REENTRANT on HP-UX to be picked up - asctime_r(localtime(&ourTime), buffer); -#else - ::asctime_r(::localtime(&ourTime), buffer); -#endif - - std::string result(buffer); - return result.substr(0,24); + time_t OurTime = time_t(this->toEpochTime()); + struct tm Storage; + struct tm *LT = ::localtime_r(&OurTime, &Storage); + assert(LT); + char Buffer[25]; + strftime(Buffer, 25, "%b %e %H:%M %Y", LT); + return std::string(Buffer); } TimeValue TimeValue::now() { diff --git a/contrib/llvm/lib/Support/Unix/Unix.h b/contrib/llvm/lib/Support/Unix/Unix.h index 051f56f..ba688e3 100644 --- a/contrib/llvm/lib/Support/Unix/Unix.h +++ b/contrib/llvm/lib/Support/Unix/Unix.h @@ -22,28 +22,22 @@ #include "llvm/Config/config.h" // Get autoconf configuration settings #include "llvm/Support/Errno.h" #include <algorithm> +#include <assert.h> #include <cerrno> #include <cstdio> #include <cstdlib> #include <cstring> #include <string> +#include <sys/types.h> #ifdef HAVE_UNISTD_H #include <unistd.h> #endif -#ifdef HAVE_SYS_TYPES_H -#include <sys/types.h> -#endif - #ifdef HAVE_SYS_PARAM_H #include <sys/param.h> #endif -#ifdef HAVE_ASSERT_H -#include <assert.h> -#endif - #ifdef HAVE_SYS_TIME_H # include <sys/time.h> #endif @@ -53,6 +47,10 @@ # include <sys/wait.h> #endif +#ifdef HAVE_DLFCN_H +# include <dlfcn.h> +#endif + #ifndef WEXITSTATUS # define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8) #endif diff --git a/contrib/llvm/lib/Support/Windows/DynamicLibrary.inc b/contrib/llvm/lib/Support/Windows/DynamicLibrary.inc index 83da82a..5a7b219 100644 --- a/contrib/llvm/lib/Support/Windows/DynamicLibrary.inc +++ b/contrib/llvm/lib/Support/Windows/DynamicLibrary.inc @@ -71,7 +71,7 @@ extern "C" { DynamicLibrary DynamicLibrary::getPermanentLibrary(const char *filename, std::string *errMsg) { - SmartScopedLock<true> lock(getMutex()); + SmartScopedLock<true> lock(*SymbolsMutex); if (!filename) { // When no file is specified, enumerate all DLLs and EXEs in the process. @@ -83,8 +83,15 @@ DynamicLibrary DynamicLibrary::getPermanentLibrary(const char *filename, // This is mostly to ensure that the return value still shows up as "valid". return DynamicLibrary(&OpenedHandles); } + + SmallVector<wchar_t, MAX_PATH> filenameUnicode; + if (error_code ec = windows::UTF8ToUTF16(filename, filenameUnicode)) { + SetLastError(ec.value()); + MakeErrMsg(errMsg, std::string(filename) + ": Can't convert to UTF-16: "); + return DynamicLibrary(); + } - HMODULE a_handle = LoadLibrary(filename); + HMODULE a_handle = LoadLibraryW(filenameUnicode.data()); if (a_handle == 0) { MakeErrMsg(errMsg, std::string(filename) + ": Can't open : "); @@ -114,10 +121,10 @@ DynamicLibrary DynamicLibrary::getPermanentLibrary(const char *filename, #undef EXPLICIT_SYMBOL2 void* DynamicLibrary::SearchForAddressOfSymbol(const char* symbolName) { - SmartScopedLock<true> Lock(getMutex()); + SmartScopedLock<true> Lock(*SymbolsMutex); // First check symbols added via AddSymbol(). - if (ExplicitSymbols) { + if (ExplicitSymbols.isConstructed()) { StringMap<void *>::iterator i = ExplicitSymbols->find(symbolName); if (i != ExplicitSymbols->end()) diff --git a/contrib/llvm/lib/Support/Windows/Memory.inc b/contrib/llvm/lib/Support/Windows/Memory.inc index 4c5aebd..1260452 100644 --- a/contrib/llvm/lib/Support/Windows/Memory.inc +++ b/contrib/llvm/lib/Support/Windows/Memory.inc @@ -82,7 +82,7 @@ MemoryBlock Memory::allocateMappedMemory(size_t NumBytes, uintptr_t Start = NearBlock ? reinterpret_cast<uintptr_t>(NearBlock->base()) + NearBlock->size() - : NULL; + : 0; // If the requested address is not aligned to the allocation granularity, // round up to get beyond NearBlock. VirtualAlloc would have rounded down. @@ -106,7 +106,7 @@ MemoryBlock Memory::allocateMappedMemory(size_t NumBytes, MemoryBlock Result; Result.Address = PA; Result.Size = NumBlocks*Granularity; - ; + if (Flags & MF_EXEC) Memory::InvalidateInstructionCache(Result.Address, Result.Size); diff --git a/contrib/llvm/lib/Support/Windows/Path.inc b/contrib/llvm/lib/Support/Windows/Path.inc index f4898e6..0b39198 100644 --- a/contrib/llvm/lib/Support/Windows/Path.inc +++ b/contrib/llvm/lib/Support/Windows/Path.inc @@ -1,4 +1,4 @@ -//===- llvm/Support/Win32/Path.cpp - Win32 Path Implementation ---*- C++ -*-===// +//===- llvm/Support/Windows/Path.inc - Windows Path Impl --------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -7,920 +7,1116 @@ // //===----------------------------------------------------------------------===// // -// This file provides the Win32 specific implementation of the Path class. +// This file implements the Windows specific implementation of the Path API. // //===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===// -//=== WARNING: Implementation here must contain only generic Win32 code that -//=== is guaranteed to work on *all* Win32 variants. +//=== WARNING: Implementation here must contain only generic Windows code that +//=== is guaranteed to work on *all* Windows variants. //===----------------------------------------------------------------------===// +#include "llvm/ADT/STLExtras.h" #include "Windows.h" -#include <cstdio> -#include <malloc.h> +#include <fcntl.h> +#include <io.h> +#include <sys/stat.h> +#include <sys/types.h> -// We need to undo a macro defined in Windows.h, otherwise we won't compile: -#undef CopyFile -#undef GetCurrentDirectory +#undef max -// Windows happily accepts either forward or backward slashes, though any path -// returned by a Win32 API will have backward slashes. As LLVM code basically -// assumes forward slashes are used, backward slashs are converted where they -// can be introduced into a path. -// -// Another invariant is that a path ends with a slash if and only if the path -// is a root directory. Any other use of a trailing slash is stripped. Unlike -// in Unix, Windows has a rather complicated notion of a root path and this -// invariant helps simply the code. - -static void FlipBackSlashes(std::string& s) { - for (size_t i = 0; i < s.size(); i++) - if (s[i] == '\\') - s[i] = '/'; -} +// MinGW doesn't define this. +#ifndef _ERRNO_T_DEFINED +#define _ERRNO_T_DEFINED +typedef int errno_t; +#endif -namespace llvm { -namespace sys { +#ifdef _MSC_VER +# pragma comment(lib, "advapi32.lib") // This provides CryptAcquireContextW. +#endif -const char PathSeparator = ';'; +using namespace llvm; -StringRef Path::GetEXESuffix() { - return "exe"; -} +using llvm::sys::windows::UTF8ToUTF16; +using llvm::sys::windows::UTF16ToUTF8; -Path::Path(llvm::StringRef p) - : path(p) { - FlipBackSlashes(path); -} +namespace { + typedef BOOLEAN (WINAPI *PtrCreateSymbolicLinkW)( + /*__in*/ LPCWSTR lpSymlinkFileName, + /*__in*/ LPCWSTR lpTargetFileName, + /*__in*/ DWORD dwFlags); -Path::Path(const char *StrStart, unsigned StrLen) - : path(StrStart, StrLen) { - FlipBackSlashes(path); -} + PtrCreateSymbolicLinkW create_symbolic_link_api = + PtrCreateSymbolicLinkW(::GetProcAddress( + ::GetModuleHandleW(L"Kernel32.dll"), "CreateSymbolicLinkW")); -Path& -Path::operator=(StringRef that) { - path.assign(that.data(), that.size()); - FlipBackSlashes(path); - return *this; -} + error_code TempDir(SmallVectorImpl<wchar_t> &result) { + retry_temp_dir: + DWORD len = ::GetTempPathW(result.capacity(), result.begin()); -bool -Path::isValid() const { - if (path.empty()) - return false; + if (len == 0) + return windows_error(::GetLastError()); - size_t len = path.size(); - // If there is a null character, it and all its successors are ignored. - size_t pos = path.find_first_of('\0'); - if (pos != std::string::npos) - len = pos; - - // If there is a colon, it must be the second character, preceded by a letter - // and followed by something. - pos = path.rfind(':',len); - size_t rootslash = 0; - if (pos != std::string::npos) { - if (pos != 1 || !isalpha(static_cast<unsigned char>(path[0])) || len < 3) - return false; - rootslash = 2; - } + if (len > result.capacity()) { + result.reserve(len); + goto retry_temp_dir; + } - // Look for a UNC path, and if found adjust our notion of the root slash. - if (len > 3 && path[0] == '/' && path[1] == '/') { - rootslash = path.find('/', 2); - if (rootslash == std::string::npos) - rootslash = 0; + result.set_size(len); + return error_code::success(); } - // Check for illegal characters. - if (path.find_first_of("\\<>\"|\001\002\003\004\005\006\007\010\011\012" - "\013\014\015\016\017\020\021\022\023\024\025\026" - "\027\030\031\032\033\034\035\036\037") - != std::string::npos) - return false; - - // Remove trailing slash, unless it's a root slash. - if (len > rootslash+1 && path[len-1] == '/') - path.erase(--len); - - // Check each component for legality. - for (pos = 0; pos < len; ++pos) { - // A component may not end in a space. - if (path[pos] == ' ') { - if (pos+1 == len || path[pos+1] == '/' || path[pos+1] == '\0') - return false; + bool is_separator(const wchar_t value) { + switch (value) { + case L'\\': + case L'/': + return true; + default: + return false; } + } +} - // A component may not end in a period. - if (path[pos] == '.') { - if (pos+1 == len || path[pos+1] == '/') { - // Unless it is the pseudo-directory "."... - if (pos == 0 || path[pos-1] == '/' || path[pos-1] == ':') - return true; - // or "..". - if (pos > 0 && path[pos-1] == '.') { - if (pos == 1 || path[pos-2] == '/' || path[pos-2] == ':') - return true; - } - return false; +// FIXME: mode should be used here and default to user r/w only, +// it currently comes in as a UNIX mode. +static error_code createUniqueEntity(const Twine &model, int &result_fd, + SmallVectorImpl<char> &result_path, + bool makeAbsolute, unsigned mode, + FSEntity Type) { + // Use result_path as temp storage. + result_path.set_size(0); + StringRef m = model.toStringRef(result_path); + + SmallVector<wchar_t, 128> model_utf16; + if (error_code ec = UTF8ToUTF16(m, model_utf16)) return ec; + + if (makeAbsolute) { + // Make model absolute by prepending a temp directory if it's not already. + bool absolute = sys::path::is_absolute(m); + + if (!absolute) { + SmallVector<wchar_t, 64> temp_dir; + if (error_code ec = TempDir(temp_dir)) return ec; + // Handle c: by removing it. + if (model_utf16.size() > 2 && model_utf16[1] == L':') { + model_utf16.erase(model_utf16.begin(), model_utf16.begin() + 2); } + model_utf16.insert(model_utf16.begin(), temp_dir.begin(), temp_dir.end()); } } - return true; -} + // Replace '%' with random chars. From here on, DO NOT modify model. It may be + // needed if the randomly chosen path already exists. + SmallVector<wchar_t, 128> random_path_utf16; + + // Get a Crypto Provider for CryptGenRandom. + HCRYPTPROV HCPC; + if (!::CryptAcquireContextW(&HCPC, + NULL, + NULL, + PROV_RSA_FULL, + CRYPT_VERIFYCONTEXT)) + return windows_error(::GetLastError()); + ScopedCryptContext CryptoProvider(HCPC); + +retry_random_path: + random_path_utf16.set_size(0); + for (SmallVectorImpl<wchar_t>::const_iterator i = model_utf16.begin(), + e = model_utf16.end(); + i != e; ++i) { + if (*i == L'%') { + BYTE val = 0; + if (!::CryptGenRandom(CryptoProvider, 1, &val)) + return windows_error(::GetLastError()); + random_path_utf16.push_back(L"0123456789abcdef"[val & 15]); + } + else + random_path_utf16.push_back(*i); + } + // Make random_path_utf16 null terminated. + random_path_utf16.push_back(0); + random_path_utf16.pop_back(); + + HANDLE TempFileHandle = INVALID_HANDLE_VALUE; + + switch (Type) { + case FS_File: { + // Try to create + open the path. + TempFileHandle = + ::CreateFileW(random_path_utf16.begin(), GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ, NULL, + // Return ERROR_FILE_EXISTS if the file + // already exists. + CREATE_NEW, FILE_ATTRIBUTE_TEMPORARY, NULL); + if (TempFileHandle == INVALID_HANDLE_VALUE) { + // If the file existed, try again, otherwise, error. + error_code ec = windows_error(::GetLastError()); + if (ec == windows_error::file_exists) + goto retry_random_path; + + return ec; + } -void Path::makeAbsolute() { - TCHAR FullPath[MAX_PATH + 1] = {0}; - LPTSTR FilePart = NULL; + // Convert the Windows API file handle into a C-runtime handle. + int fd = ::_open_osfhandle(intptr_t(TempFileHandle), 0); + if (fd == -1) { + ::CloseHandle(TempFileHandle); + ::DeleteFileW(random_path_utf16.begin()); + // MSDN doesn't say anything about _open_osfhandle setting errno or + // GetLastError(), so just return invalid_handle. + return windows_error::invalid_handle; + } - DWORD RetLength = ::GetFullPathNameA(path.c_str(), - sizeof(FullPath)/sizeof(FullPath[0]), - FullPath, &FilePart); + result_fd = fd; + break; + } - if (0 == RetLength) { - // FIXME: Report the error GetLastError() - assert(0 && "Unable to make absolute path!"); - } else if (RetLength > MAX_PATH) { - // FIXME: Report too small buffer (needed RetLength bytes). - assert(0 && "Unable to make absolute path!"); - } else { - path = FullPath; + case FS_Name: { + DWORD attributes = ::GetFileAttributesW(random_path_utf16.begin()); + if (attributes != INVALID_FILE_ATTRIBUTES) + goto retry_random_path; + error_code EC = make_error_code(windows_error(::GetLastError())); + if (EC != windows_error::file_not_found && + EC != windows_error::path_not_found) + return EC; + break; } -} -bool -Path::isAbsolute(const char *NameStart, unsigned NameLen) { - assert(NameStart); - // FIXME: This does not handle correctly an absolute path starting from - // a drive letter or in UNC format. - switch (NameLen) { - case 0: - return false; - case 1: - case 2: - return NameStart[0] == '/'; - default: - return - (NameStart[0] == '/' || (NameStart[1] == ':' && NameStart[2] == '/')) || - (NameStart[0] == '\\' || (NameStart[1] == ':' && NameStart[2] == '\\')); + case FS_Dir: + if (!::CreateDirectoryW(random_path_utf16.begin(), NULL)) { + error_code EC = windows_error(::GetLastError()); + if (EC != windows_error::already_exists) + return EC; + goto retry_random_path; + } + break; } -} -bool -Path::isAbsolute() const { - // FIXME: This does not handle correctly an absolute path starting from - // a drive letter or in UNC format. - switch (path.length()) { - case 0: - return false; - case 1: - case 2: - return path[0] == '/'; - default: - return path[0] == '/' || (path[1] == ':' && path[2] == '/'); + // Set result_path to the utf-8 representation of the path. + if (error_code ec = UTF16ToUTF8(random_path_utf16.begin(), + random_path_utf16.size(), result_path)) { + switch (Type) { + case FS_File: + ::CloseHandle(TempFileHandle); + ::DeleteFileW(random_path_utf16.begin()); + case FS_Name: + break; + case FS_Dir: + ::RemoveDirectoryW(random_path_utf16.begin()); + break; + } + return ec; } + + return error_code::success(); } -static Path *TempDirectory; +namespace llvm { +namespace sys { +namespace fs { -Path -Path::GetTemporaryDirectory(std::string* ErrMsg) { - if (TempDirectory) { -#if defined(_MSC_VER) - // Visual Studio gets confused and emits a diagnostic about calling exists, - // even though this is the implementation for PathV1. Temporarily - // disable the deprecated warning message - #pragma warning(push) - #pragma warning(disable:4996) -#endif - assert(TempDirectory->exists() && "Who has removed TempDirectory?"); -#if defined(_MSC_VER) - #pragma warning(pop) -#endif - return *TempDirectory; - } +std::string getMainExecutable(const char *argv0, void *MainExecAddr) { + SmallVector<wchar_t, MAX_PATH> PathName; + DWORD Size = ::GetModuleFileNameW(NULL, PathName.data(), PathName.capacity()); - char pathname[MAX_PATH]; - if (!GetTempPath(MAX_PATH, pathname)) { - if (ErrMsg) - *ErrMsg = "Can't determine temporary directory"; - return Path(); - } + // A zero return value indicates a failure other than insufficient space. + if (Size == 0) + return ""; - Path result; - result.set(pathname); + // Insufficient space is determined by a return value equal to the size of + // the buffer passed in. + if (Size == PathName.capacity()) + return ""; - // Append a subdirectory based on our process id so multiple LLVMs don't - // step on each other's toes. -#ifdef __MINGW32__ - // Mingw's Win32 header files are broken. - sprintf(pathname, "LLVM_%u", unsigned(GetCurrentProcessId())); -#else - sprintf(pathname, "LLVM_%u", GetCurrentProcessId()); -#endif - result.appendComponent(pathname); - - // If there's a directory left over from a previous LLVM execution that - // happened to have the same process id, get rid of it. - result.eraseFromDisk(true); - - // And finally (re-)create the empty directory. - result.createDirectoryOnDisk(false); - TempDirectory = new Path(result); - return *TempDirectory; -} - -// FIXME: the following set of functions don't map to Windows very well. -Path -Path::GetRootDirectory() { - // This is the only notion that that Windows has of a root directory. Nothing - // is here except for drives. - return Path("file:///"); -} - -void -Path::GetSystemLibraryPaths(std::vector<sys::Path>& Paths) { - char buff[MAX_PATH]; - // Generic form of C:\Windows\System32 - HRESULT res = SHGetFolderPathA(NULL, - CSIDL_FLAG_CREATE | CSIDL_SYSTEM, - NULL, - SHGFP_TYPE_CURRENT, - buff); - if (res != S_OK) { - assert(0 && "Failed to get system directory"); - return; - } - Paths.push_back(sys::Path(buff)); - - // Reset buff. - buff[0] = 0; - // Generic form of C:\Windows - res = SHGetFolderPathA(NULL, - CSIDL_FLAG_CREATE | CSIDL_WINDOWS, - NULL, - SHGFP_TYPE_CURRENT, - buff); - if (res != S_OK) { - assert(0 && "Failed to get windows directory"); - return; - } - Paths.push_back(sys::Path(buff)); -} + // On success, GetModuleFileNameW returns the number of characters written to + // the buffer not including the NULL terminator. + PathName.set_size(Size); -void -Path::GetBitcodeLibraryPaths(std::vector<sys::Path>& Paths) { - char * env_var = getenv("LLVM_LIB_SEARCH_PATH"); - if (env_var != 0) { - getPathList(env_var,Paths); - } -#ifdef LLVM_LIBDIR - { - Path tmpPath; - if (tmpPath.set(LLVM_LIBDIR)) - if (tmpPath.canRead()) - Paths.push_back(tmpPath); - } -#endif - GetSystemLibraryPaths(Paths); -} + // Convert the result from UTF-16 to UTF-8. + SmallVector<char, MAX_PATH> PathNameUTF8; + if (UTF16ToUTF8(PathName.data(), PathName.size(), PathNameUTF8)) + return ""; -Path -Path::GetUserHomeDirectory() { - char buff[MAX_PATH]; - HRESULT res = SHGetFolderPathA(NULL, - CSIDL_FLAG_CREATE | CSIDL_APPDATA, - NULL, - SHGFP_TYPE_CURRENT, - buff); - if (res != S_OK) - assert(0 && "Failed to get user home directory"); - return Path(buff); + return std::string(PathNameUTF8.data()); } -Path -Path::GetCurrentDirectory() { - char pathname[MAX_PATH]; - ::GetCurrentDirectoryA(MAX_PATH,pathname); - return Path(pathname); +UniqueID file_status::getUniqueID() const { + // The file is uniquely identified by the volume serial number along + // with the 64-bit file identifier. + uint64_t FileID = (static_cast<uint64_t>(FileIndexHigh) << 32ULL) | + static_cast<uint64_t>(FileIndexLow); + + return UniqueID(VolumeSerialNumber, FileID); } -/// GetMainExecutable - Return the path to the main executable, given the -/// value of argv[0] from program startup. -Path Path::GetMainExecutable(const char *argv0, void *MainAddr) { - char pathname[MAX_PATH]; - DWORD ret = ::GetModuleFileNameA(NULL, pathname, MAX_PATH); - return ret != MAX_PATH ? Path(pathname) : Path(); +TimeValue file_status::getLastModificationTime() const { + ULARGE_INTEGER UI; + UI.LowPart = LastWriteTimeLow; + UI.HighPart = LastWriteTimeHigh; + + TimeValue Ret; + Ret.fromWin32Time(UI.QuadPart); + return Ret; } +error_code current_path(SmallVectorImpl<char> &result) { + SmallVector<wchar_t, MAX_PATH> cur_path; + DWORD len = MAX_PATH; -// FIXME: the above set of functions don't map to Windows very well. + do { + cur_path.reserve(len); + len = ::GetCurrentDirectoryW(cur_path.capacity(), cur_path.data()); + + // A zero return value indicates a failure other than insufficient space. + if (len == 0) + return windows_error(::GetLastError()); + // If there's insufficient space, the len returned is larger than the len + // given. + } while (len > cur_path.capacity()); -StringRef Path::getDirname() const { - return getDirnameCharSep(path, "/"); + // On success, GetCurrentDirectoryW returns the number of characters not + // including the null-terminator. + cur_path.set_size(len); + return UTF16ToUTF8(cur_path.begin(), cur_path.size(), result); } -StringRef -Path::getBasename() const { - // Find the last slash - size_t slash = path.rfind('/'); - if (slash == std::string::npos) - slash = 0; - else - slash++; +error_code create_directory(const Twine &path, bool &existed) { + SmallString<128> path_storage; + SmallVector<wchar_t, 128> path_utf16; - size_t dot = path.rfind('.'); - if (dot == std::string::npos || dot < slash) - return StringRef(path).substr(slash); - else - return StringRef(path).substr(slash, dot - slash); -} + if (error_code ec = UTF8ToUTF16(path.toStringRef(path_storage), + path_utf16)) + return ec; -StringRef -Path::getSuffix() const { - // Find the last slash - size_t slash = path.rfind('/'); - if (slash == std::string::npos) - slash = 0; - else - slash++; + if (!::CreateDirectoryW(path_utf16.begin(), NULL)) { + error_code ec = windows_error(::GetLastError()); + if (ec == windows_error::already_exists) + existed = true; + else + return ec; + } else + existed = false; - size_t dot = path.rfind('.'); - if (dot == std::string::npos || dot < slash) - return StringRef(""); - else - return StringRef(path).substr(dot + 1); + return error_code::success(); } -bool -Path::exists() const { - DWORD attr = GetFileAttributes(path.c_str()); - return attr != INVALID_FILE_ATTRIBUTES; -} +error_code create_hard_link(const Twine &to, const Twine &from) { + // Get arguments. + SmallString<128> from_storage; + SmallString<128> to_storage; + StringRef f = from.toStringRef(from_storage); + StringRef t = to.toStringRef(to_storage); + + // Convert to utf-16. + SmallVector<wchar_t, 128> wide_from; + SmallVector<wchar_t, 128> wide_to; + if (error_code ec = UTF8ToUTF16(f, wide_from)) return ec; + if (error_code ec = UTF8ToUTF16(t, wide_to)) return ec; -bool -Path::isDirectory() const { - DWORD attr = GetFileAttributes(path.c_str()); - return (attr != INVALID_FILE_ATTRIBUTES) && - (attr & FILE_ATTRIBUTE_DIRECTORY); + if (!::CreateHardLinkW(wide_from.begin(), wide_to.begin(), NULL)) + return windows_error(::GetLastError()); + + return error_code::success(); } -bool -Path::isSymLink() const { - DWORD attributes = GetFileAttributes(path.c_str()); +error_code create_symlink(const Twine &to, const Twine &from) { + // Only do it if the function is available at runtime. + if (!create_symbolic_link_api) + return make_error_code(errc::function_not_supported); - if (attributes == INVALID_FILE_ATTRIBUTES) - // There's no sane way to report this :(. - assert(0 && "GetFileAttributes returned INVALID_FILE_ATTRIBUTES"); + // Get arguments. + SmallString<128> from_storage; + SmallString<128> to_storage; + StringRef f = from.toStringRef(from_storage); + StringRef t = to.toStringRef(to_storage); - // This isn't exactly what defines a NTFS symlink, but it is only true for - // paths that act like a symlink. - return attributes & FILE_ATTRIBUTE_REPARSE_POINT; -} + // Convert to utf-16. + SmallVector<wchar_t, 128> wide_from; + SmallVector<wchar_t, 128> wide_to; + if (error_code ec = UTF8ToUTF16(f, wide_from)) return ec; + if (error_code ec = UTF8ToUTF16(t, wide_to)) return ec; -bool -Path::canRead() const { - // FIXME: take security attributes into account. - DWORD attr = GetFileAttributes(path.c_str()); - return attr != INVALID_FILE_ATTRIBUTES; -} + if (!create_symbolic_link_api(wide_from.begin(), wide_to.begin(), 0)) + return windows_error(::GetLastError()); -bool -Path::canWrite() const { - // FIXME: take security attributes into account. - DWORD attr = GetFileAttributes(path.c_str()); - return (attr != INVALID_FILE_ATTRIBUTES) && !(attr & FILE_ATTRIBUTE_READONLY); + return error_code::success(); } -bool -Path::canExecute() const { - // FIXME: take security attributes into account. - DWORD attr = GetFileAttributes(path.c_str()); - return attr != INVALID_FILE_ATTRIBUTES; +error_code remove(const Twine &path, bool &existed) { + SmallString<128> path_storage; + SmallVector<wchar_t, 128> path_utf16; + + file_status st; + error_code EC = status(path, st); + if (EC) { + if (EC == windows_error::file_not_found || + EC == windows_error::path_not_found) { + existed = false; + return error_code::success(); + } + return EC; + } + + if (error_code ec = UTF8ToUTF16(path.toStringRef(path_storage), + path_utf16)) + return ec; + + if (st.type() == file_type::directory_file) { + if (!::RemoveDirectoryW(c_str(path_utf16))) { + error_code ec = windows_error(::GetLastError()); + if (ec != windows_error::file_not_found) + return ec; + existed = false; + } else + existed = true; + } else { + if (!::DeleteFileW(c_str(path_utf16))) { + error_code ec = windows_error(::GetLastError()); + if (ec != windows_error::file_not_found) + return ec; + existed = false; + } else + existed = true; + } + + return error_code::success(); } -bool -Path::isRegularFile() const { - bool res; - if (fs::is_regular_file(path, res)) - return false; - return res; +error_code rename(const Twine &from, const Twine &to) { + // Get arguments. + SmallString<128> from_storage; + SmallString<128> to_storage; + StringRef f = from.toStringRef(from_storage); + StringRef t = to.toStringRef(to_storage); + + // Convert to utf-16. + SmallVector<wchar_t, 128> wide_from; + SmallVector<wchar_t, 128> wide_to; + if (error_code ec = UTF8ToUTF16(f, wide_from)) return ec; + if (error_code ec = UTF8ToUTF16(t, wide_to)) return ec; + + error_code ec = error_code::success(); + for (int i = 0; i < 2000; i++) { + if (::MoveFileExW(wide_from.begin(), wide_to.begin(), + MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING)) + return error_code::success(); + ec = windows_error(::GetLastError()); + if (ec != windows_error::access_denied) + break; + // Retry MoveFile() at ACCESS_DENIED. + // System scanners (eg. indexer) might open the source file when + // It is written and closed. + ::Sleep(1); + } + + return ec; } -StringRef -Path::getLast() const { - // Find the last slash - size_t pos = path.rfind('/'); +error_code resize_file(const Twine &path, uint64_t size) { + SmallString<128> path_storage; + SmallVector<wchar_t, 128> path_utf16; - // Handle the corner cases - if (pos == std::string::npos) - return path; + if (error_code ec = UTF8ToUTF16(path.toStringRef(path_storage), + path_utf16)) + return ec; - // If the last character is a slash, we have a root directory - if (pos == path.length()-1) - return path; + int fd = ::_wopen(path_utf16.begin(), O_BINARY | _O_RDWR, S_IWRITE); + if (fd == -1) + return error_code(errno, generic_category()); +#ifdef HAVE__CHSIZE_S + errno_t error = ::_chsize_s(fd, size); +#else + errno_t error = ::_chsize(fd, size); +#endif + ::close(fd); + return error_code(error, generic_category()); +} - // Return everything after the last slash - return StringRef(path).substr(pos+1); +error_code exists(const Twine &path, bool &result) { + SmallString<128> path_storage; + SmallVector<wchar_t, 128> path_utf16; + + if (error_code ec = UTF8ToUTF16(path.toStringRef(path_storage), + path_utf16)) + return ec; + + DWORD attributes = ::GetFileAttributesW(path_utf16.begin()); + + if (attributes == INVALID_FILE_ATTRIBUTES) { + // See if the file didn't actually exist. + error_code ec = make_error_code(windows_error(::GetLastError())); + if (ec != windows_error::file_not_found && + ec != windows_error::path_not_found) + return ec; + result = false; + } else + result = true; + return error_code::success(); } -const FileStatus * -PathWithStatus::getFileStatus(bool update, std::string *ErrStr) const { - if (!fsIsValid || update) { - WIN32_FILE_ATTRIBUTE_DATA fi; - if (!GetFileAttributesEx(path.c_str(), GetFileExInfoStandard, &fi)) { - MakeErrMsg(ErrStr, "getStatusInfo():" + std::string(path) + - ": Can't get status: "); - return 0; - } +bool can_write(const Twine &Path) { + // FIXME: take security attributes into account. + SmallString<128> PathStorage; + SmallVector<wchar_t, 128> PathUtf16; - status.fileSize = fi.nFileSizeHigh; - status.fileSize <<= sizeof(fi.nFileSizeHigh)*8; - status.fileSize += fi.nFileSizeLow; + if (UTF8ToUTF16(Path.toStringRef(PathStorage), PathUtf16)) + return false; - status.mode = fi.dwFileAttributes & FILE_ATTRIBUTE_READONLY ? 0555 : 0777; - status.user = 9999; // Not applicable to Windows, so... - status.group = 9999; // Not applicable to Windows, so... + DWORD Attr = ::GetFileAttributesW(PathUtf16.begin()); + return (Attr != INVALID_FILE_ATTRIBUTES) && !(Attr & FILE_ATTRIBUTE_READONLY); +} - // FIXME: this is only unique if the file is accessed by the same file path. - // How do we do this for C:\dir\file and ..\dir\file ? Unix has inode - // numbers, but the concept doesn't exist in Windows. - status.uniqueID = 0; - for (unsigned i = 0; i < path.length(); ++i) - status.uniqueID += path[i]; +bool can_execute(const Twine &Path) { + SmallString<128> PathStorage; + SmallVector<wchar_t, 128> PathUtf16; - ULARGE_INTEGER ui; - ui.LowPart = fi.ftLastWriteTime.dwLowDateTime; - ui.HighPart = fi.ftLastWriteTime.dwHighDateTime; - status.modTime.fromWin32Time(ui.QuadPart); + if (UTF8ToUTF16(Path.toStringRef(PathStorage), PathUtf16)) + return false; - status.isDir = fi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY; - fsIsValid = true; - } - return &status; + DWORD Attr = ::GetFileAttributesW(PathUtf16.begin()); + return Attr != INVALID_FILE_ATTRIBUTES; } -bool Path::makeReadableOnDisk(std::string* ErrMsg) { - // All files are readable on Windows (ignoring security attributes). - return false; +bool equivalent(file_status A, file_status B) { + assert(status_known(A) && status_known(B)); + return A.FileIndexHigh == B.FileIndexHigh && + A.FileIndexLow == B.FileIndexLow && + A.FileSizeHigh == B.FileSizeHigh && + A.FileSizeLow == B.FileSizeLow && + A.LastWriteTimeHigh == B.LastWriteTimeHigh && + A.LastWriteTimeLow == B.LastWriteTimeLow && + A.VolumeSerialNumber == B.VolumeSerialNumber; } -bool Path::makeWriteableOnDisk(std::string* ErrMsg) { - DWORD attr = GetFileAttributes(path.c_str()); +error_code equivalent(const Twine &A, const Twine &B, bool &result) { + file_status fsA, fsB; + if (error_code ec = status(A, fsA)) return ec; + if (error_code ec = status(B, fsB)) return ec; + result = equivalent(fsA, fsB); + return error_code::success(); +} - // If it doesn't exist, we're done. - if (attr == INVALID_FILE_ATTRIBUTES) - return false; +static bool isReservedName(StringRef path) { + // This list of reserved names comes from MSDN, at: + // http://msdn.microsoft.com/en-us/library/aa365247%28v=vs.85%29.aspx + static const char *sReservedNames[] = { "nul", "con", "prn", "aux", + "com1", "com2", "com3", "com4", "com5", "com6", + "com7", "com8", "com9", "lpt1", "lpt2", "lpt3", + "lpt4", "lpt5", "lpt6", "lpt7", "lpt8", "lpt9" }; + + // First, check to see if this is a device namespace, which always + // starts with \\.\, since device namespaces are not legal file paths. + if (path.startswith("\\\\.\\")) + return true; - if (attr & FILE_ATTRIBUTE_READONLY) { - if (!SetFileAttributes(path.c_str(), attr & ~FILE_ATTRIBUTE_READONLY)) { - MakeErrMsg(ErrMsg, std::string(path) + ": Can't make file writable: "); + // Then compare against the list of ancient reserved names + for (size_t i = 0; i < array_lengthof(sReservedNames); ++i) { + if (path.equals_lower(sReservedNames[i])) return true; - } } - return false; -} -bool Path::makeExecutableOnDisk(std::string* ErrMsg) { - // All files are executable on Windows (ignoring security attributes). + // The path isn't what we consider reserved. return false; } -bool -Path::getDirectoryContents(std::set<Path>& result, std::string* ErrMsg) const { - WIN32_FILE_ATTRIBUTE_DATA fi; - if (!GetFileAttributesEx(path.c_str(), GetFileExInfoStandard, &fi)) { - MakeErrMsg(ErrMsg, path + ": can't get status of file"); - return true; +static error_code getStatus(HANDLE FileHandle, file_status &Result) { + if (FileHandle == INVALID_HANDLE_VALUE) + goto handle_status_error; + + switch (::GetFileType(FileHandle)) { + default: + llvm_unreachable("Don't know anything about this file type"); + case FILE_TYPE_UNKNOWN: { + DWORD Err = ::GetLastError(); + if (Err != NO_ERROR) + return windows_error(Err); + Result = file_status(file_type::type_unknown); + return error_code::success(); + } + case FILE_TYPE_DISK: + break; + case FILE_TYPE_CHAR: + Result = file_status(file_type::character_file); + return error_code::success(); + case FILE_TYPE_PIPE: + Result = file_status(file_type::fifo_file); + return error_code::success(); } - if (!(fi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { - if (ErrMsg) - *ErrMsg = path + ": not a directory"; - return true; + BY_HANDLE_FILE_INFORMATION Info; + if (!::GetFileInformationByHandle(FileHandle, &Info)) + goto handle_status_error; + + { + file_type Type = (Info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + ? file_type::directory_file + : file_type::regular_file; + Result = + file_status(Type, Info.ftLastWriteTime.dwHighDateTime, + Info.ftLastWriteTime.dwLowDateTime, + Info.dwVolumeSerialNumber, Info.nFileSizeHigh, + Info.nFileSizeLow, Info.nFileIndexHigh, Info.nFileIndexLow); + return error_code::success(); } - result.clear(); - WIN32_FIND_DATA fd; - std::string searchpath = path; - if (path.size() == 0 || searchpath[path.size()-1] == '/') - searchpath += "*"; +handle_status_error: + error_code EC = windows_error(::GetLastError()); + if (EC == windows_error::file_not_found || + EC == windows_error::path_not_found) + Result = file_status(file_type::file_not_found); + else if (EC == windows_error::sharing_violation) + Result = file_status(file_type::type_unknown); else - searchpath += "/*"; + Result = file_status(file_type::status_error); + return EC; +} - HANDLE h = FindFirstFile(searchpath.c_str(), &fd); - if (h == INVALID_HANDLE_VALUE) { - if (GetLastError() == ERROR_FILE_NOT_FOUND) - return true; // not really an error, now is it? - MakeErrMsg(ErrMsg, path + ": Can't read directory: "); - return true; - } +error_code status(const Twine &path, file_status &result) { + SmallString<128> path_storage; + SmallVector<wchar_t, 128> path_utf16; - do { - if (fd.cFileName[0] == '.') - continue; - Path aPath(path); - aPath.appendComponent(&fd.cFileName[0]); - result.insert(aPath); - } while (FindNextFile(h, &fd)); - - DWORD err = GetLastError(); - FindClose(h); - if (err != ERROR_NO_MORE_FILES) { - SetLastError(err); - MakeErrMsg(ErrMsg, path + ": Can't read directory: "); - return true; + StringRef path8 = path.toStringRef(path_storage); + if (isReservedName(path8)) { + result = file_status(file_type::character_file); + return error_code::success(); } - return false; -} -bool -Path::set(StringRef a_path) { - if (a_path.empty()) - return false; - std::string save(path); - path = a_path; - FlipBackSlashes(path); - if (!isValid()) { - path = save; - return false; + if (error_code ec = UTF8ToUTF16(path8, path_utf16)) + return ec; + + DWORD attr = ::GetFileAttributesW(path_utf16.begin()); + if (attr == INVALID_FILE_ATTRIBUTES) + return getStatus(INVALID_HANDLE_VALUE, result); + + // Handle reparse points. + if (attr & FILE_ATTRIBUTE_REPARSE_POINT) { + ScopedFileHandle h( + ::CreateFileW(path_utf16.begin(), + 0, // Attributes only. + FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS, + 0)); + if (!h) + return getStatus(INVALID_HANDLE_VALUE, result); } - return true; + + ScopedFileHandle h( + ::CreateFileW(path_utf16.begin(), 0, // Attributes only. + FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0)); + if (!h) + return getStatus(INVALID_HANDLE_VALUE, result); + + return getStatus(h, result); } -bool -Path::appendComponent(StringRef name) { - if (name.empty()) - return false; - std::string save(path); - if (!path.empty()) { - size_t last = path.size() - 1; - if (path[last] != '/') - path += '/'; - } - path += name; - if (!isValid()) { - path = save; - return false; - } - return true; +error_code status(int FD, file_status &Result) { + HANDLE FileHandle = reinterpret_cast<HANDLE>(_get_osfhandle(FD)); + return getStatus(FileHandle, Result); } -bool -Path::eraseComponent() { - size_t slashpos = path.rfind('/',path.size()); - if (slashpos == path.size() - 1 || slashpos == std::string::npos) - return false; - std::string save(path); - path.erase(slashpos); - if (!isValid()) { - path = save; - return false; - } - return true; +error_code setLastModificationAndAccessTime(int FD, TimeValue Time) { + ULARGE_INTEGER UI; + UI.QuadPart = Time.toWin32Time(); + FILETIME FT; + FT.dwLowDateTime = UI.LowPart; + FT.dwHighDateTime = UI.HighPart; + HANDLE FileHandle = reinterpret_cast<HANDLE>(_get_osfhandle(FD)); + if (!SetFileTime(FileHandle, NULL, &FT, &FT)) + return windows_error(::GetLastError()); + return error_code::success(); } -bool -Path::eraseSuffix() { - size_t dotpos = path.rfind('.',path.size()); - size_t slashpos = path.rfind('/',path.size()); - if (dotpos != std::string::npos) { - if (slashpos == std::string::npos || dotpos > slashpos+1) { - std::string save(path); - path.erase(dotpos, path.size()-dotpos); - if (!isValid()) { - path = save; - return false; - } - return true; - } +error_code get_magic(const Twine &path, uint32_t len, + SmallVectorImpl<char> &result) { + SmallString<128> path_storage; + SmallVector<wchar_t, 128> path_utf16; + result.set_size(0); + + // Convert path to UTF-16. + if (error_code ec = UTF8ToUTF16(path.toStringRef(path_storage), + path_utf16)) + return ec; + + // Open file. + HANDLE file = ::CreateFileW(c_str(path_utf16), + GENERIC_READ, + FILE_SHARE_READ, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_READONLY, + NULL); + if (file == INVALID_HANDLE_VALUE) + return windows_error(::GetLastError()); + + // Allocate buffer. + result.reserve(len); + + // Get magic! + DWORD bytes_read = 0; + BOOL read_success = ::ReadFile(file, result.data(), len, &bytes_read, NULL); + error_code ec = windows_error(::GetLastError()); + ::CloseHandle(file); + if (!read_success || (bytes_read != len)) { + // Set result size to the number of bytes read if it's valid. + if (bytes_read <= len) + result.set_size(bytes_read); + // ERROR_HANDLE_EOF is mapped to errc::value_too_large. + return ec; } - return false; -} -inline bool PathMsg(std::string* ErrMsg, const char* pathname, const char*msg) { - if (ErrMsg) - *ErrMsg = std::string(pathname) + ": " + std::string(msg); - return true; + result.set_size(len); + return error_code::success(); } -bool -Path::createDirectoryOnDisk(bool create_parents, std::string* ErrMsg) { - // Get a writeable copy of the path name - size_t len = path.length(); - char *pathname = reinterpret_cast<char *>(_alloca(len+2)); - path.copy(pathname, len); - pathname[len] = 0; - - // Make sure it ends with a slash. - if (len == 0 || pathname[len - 1] != '/') { - pathname[len] = '/'; - pathname[++len] = 0; +error_code mapped_file_region::init(int FD, bool CloseFD, uint64_t Offset) { + FileDescriptor = FD; + // Make sure that the requested size fits within SIZE_T. + if (Size > std::numeric_limits<SIZE_T>::max()) { + if (FileDescriptor) { + if (CloseFD) + _close(FileDescriptor); + } else + ::CloseHandle(FileHandle); + return make_error_code(errc::invalid_argument); } - // Determine starting point for initial / search. - char *next = pathname; - if (pathname[0] == '/' && pathname[1] == '/') { - // Skip host name. - next = strchr(pathname+2, '/'); - if (next == NULL) - return PathMsg(ErrMsg, pathname, "badly formed remote directory"); + DWORD flprotect; + switch (Mode) { + case readonly: flprotect = PAGE_READONLY; break; + case readwrite: flprotect = PAGE_READWRITE; break; + case priv: flprotect = PAGE_WRITECOPY; break; + } - // Skip share name. - next = strchr(next+1, '/'); - if (next == NULL) - return PathMsg(ErrMsg, pathname,"badly formed remote directory"); + FileMappingHandle = + ::CreateFileMappingW(FileHandle, 0, flprotect, + (Offset + Size) >> 32, + (Offset + Size) & 0xffffffff, + 0); + if (FileMappingHandle == NULL) { + error_code ec = windows_error(GetLastError()); + if (FileDescriptor) { + if (CloseFD) + _close(FileDescriptor); + } else + ::CloseHandle(FileHandle); + return ec; + } - next++; - if (*next == 0) - return PathMsg(ErrMsg, pathname, "badly formed remote directory"); + DWORD dwDesiredAccess; + switch (Mode) { + case readonly: dwDesiredAccess = FILE_MAP_READ; break; + case readwrite: dwDesiredAccess = FILE_MAP_WRITE; break; + case priv: dwDesiredAccess = FILE_MAP_COPY; break; + } + Mapping = ::MapViewOfFile(FileMappingHandle, + dwDesiredAccess, + Offset >> 32, + Offset & 0xffffffff, + Size); + if (Mapping == NULL) { + error_code ec = windows_error(GetLastError()); + ::CloseHandle(FileMappingHandle); + if (FileDescriptor) { + if (CloseFD) + _close(FileDescriptor); + } else + ::CloseHandle(FileHandle); + return ec; + } - } else { - if (pathname[1] == ':') - next += 2; // skip drive letter - if (*next == '/') - next++; // skip root directory - } - - // If we're supposed to create intermediate directories - if (create_parents) { - // Loop through the directory components until we're done - while (*next) { - next = strchr(next, '/'); - *next = 0; - if (!CreateDirectory(pathname, NULL) && - GetLastError() != ERROR_ALREADY_EXISTS) - return MakeErrMsg(ErrMsg, - std::string(pathname) + ": Can't create directory: "); - *next++ = '/'; - } - } else { - // Drop trailing slash. - pathname[len-1] = 0; - if (!CreateDirectory(pathname, NULL) && - GetLastError() != ERROR_ALREADY_EXISTS) { - return MakeErrMsg(ErrMsg, std::string(pathname) + - ": Can't create directory: "); + if (Size == 0) { + MEMORY_BASIC_INFORMATION mbi; + SIZE_T Result = VirtualQuery(Mapping, &mbi, sizeof(mbi)); + if (Result == 0) { + error_code ec = windows_error(GetLastError()); + ::UnmapViewOfFile(Mapping); + ::CloseHandle(FileMappingHandle); + if (FileDescriptor) { + if (CloseFD) + _close(FileDescriptor); + } else + ::CloseHandle(FileHandle); + return ec; } + Size = mbi.RegionSize; } - return false; -} - -bool -Path::createFileOnDisk(std::string* ErrMsg) { - // Create the file - HANDLE h = CreateFile(path.c_str(), GENERIC_WRITE, 0, NULL, CREATE_NEW, - FILE_ATTRIBUTE_NORMAL, NULL); - if (h == INVALID_HANDLE_VALUE) - return MakeErrMsg(ErrMsg, path + ": Can't create file: "); - CloseHandle(h); - return false; + // Close all the handles except for the view. It will keep the other handles + // alive. + ::CloseHandle(FileMappingHandle); + if (FileDescriptor) { + if (CloseFD) + _close(FileDescriptor); // Also closes FileHandle. + } else + ::CloseHandle(FileHandle); + return error_code::success(); } -bool -Path::eraseFromDisk(bool remove_contents, std::string *ErrStr) const { - WIN32_FILE_ATTRIBUTE_DATA fi; - if (!GetFileAttributesEx(path.c_str(), GetFileExInfoStandard, &fi)) - return true; +mapped_file_region::mapped_file_region(const Twine &path, + mapmode mode, + uint64_t length, + uint64_t offset, + error_code &ec) + : Mode(mode) + , Size(length) + , Mapping() + , FileDescriptor() + , FileHandle(INVALID_HANDLE_VALUE) + , FileMappingHandle() { + SmallString<128> path_storage; + SmallVector<wchar_t, 128> path_utf16; + + // Convert path to UTF-16. + if ((ec = UTF8ToUTF16(path.toStringRef(path_storage), path_utf16))) + return; - if (fi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { - // If it doesn't exist, we're done. - bool Exists; - if (fs::exists(path, Exists) || !Exists) - return false; + // Get file handle for creating a file mapping. + FileHandle = ::CreateFileW(c_str(path_utf16), + Mode == readonly ? GENERIC_READ + : GENERIC_READ | GENERIC_WRITE, + Mode == readonly ? FILE_SHARE_READ + : 0, + 0, + Mode == readonly ? OPEN_EXISTING + : OPEN_ALWAYS, + Mode == readonly ? FILE_ATTRIBUTE_READONLY + : FILE_ATTRIBUTE_NORMAL, + 0); + if (FileHandle == INVALID_HANDLE_VALUE) { + ec = windows_error(::GetLastError()); + return; + } - char *pathname = reinterpret_cast<char *>(_alloca(path.length()+3)); - int lastchar = path.length() - 1 ; - path.copy(pathname, lastchar+1); - - // Make path end with '/*'. - if (pathname[lastchar] != '/') - pathname[++lastchar] = '/'; - pathname[lastchar+1] = '*'; - pathname[lastchar+2] = 0; - - if (remove_contents) { - WIN32_FIND_DATA fd; - HANDLE h = FindFirstFile(pathname, &fd); - - // It's a bad idea to alter the contents of a directory while enumerating - // its contents. So build a list of its contents first, then destroy them. - - if (h != INVALID_HANDLE_VALUE) { - std::vector<Path> list; - - do { - if (strcmp(fd.cFileName, ".") == 0) - continue; - if (strcmp(fd.cFileName, "..") == 0) - continue; - - Path aPath(path); - aPath.appendComponent(&fd.cFileName[0]); - list.push_back(aPath); - } while (FindNextFile(h, &fd)); - - DWORD err = GetLastError(); - FindClose(h); - if (err != ERROR_NO_MORE_FILES) { - SetLastError(err); - return MakeErrMsg(ErrStr, path + ": Can't read directory: "); - } - - for (std::vector<Path>::iterator I = list.begin(); I != list.end(); - ++I) { - Path &aPath = *I; - aPath.eraseFromDisk(true); - } - } else { - if (GetLastError() != ERROR_FILE_NOT_FOUND) - return MakeErrMsg(ErrStr, path + ": Can't read directory: "); - } - } + FileDescriptor = 0; + ec = init(FileDescriptor, true, offset); + if (ec) { + Mapping = FileMappingHandle = 0; + FileHandle = INVALID_HANDLE_VALUE; + FileDescriptor = 0; + } +} - pathname[lastchar] = 0; - if (!RemoveDirectory(pathname)) - return MakeErrMsg(ErrStr, - std::string(pathname) + ": Can't destroy directory: "); - return false; - } else { - // Read-only files cannot be deleted on Windows. Must remove the read-only - // attribute first. - if (fi.dwFileAttributes & FILE_ATTRIBUTE_READONLY) { - if (!SetFileAttributes(path.c_str(), - fi.dwFileAttributes & ~FILE_ATTRIBUTE_READONLY)) - return MakeErrMsg(ErrStr, path + ": Can't destroy file: "); - } +mapped_file_region::mapped_file_region(int fd, + bool closefd, + mapmode mode, + uint64_t length, + uint64_t offset, + error_code &ec) + : Mode(mode) + , Size(length) + , Mapping() + , FileDescriptor(fd) + , FileHandle(INVALID_HANDLE_VALUE) + , FileMappingHandle() { + FileHandle = reinterpret_cast<HANDLE>(_get_osfhandle(fd)); + if (FileHandle == INVALID_HANDLE_VALUE) { + if (closefd) + _close(FileDescriptor); + FileDescriptor = 0; + ec = make_error_code(errc::bad_file_descriptor); + return; + } - if (!DeleteFile(path.c_str())) - return MakeErrMsg(ErrStr, path + ": Can't destroy file: "); - return false; + ec = init(FileDescriptor, closefd, offset); + if (ec) { + Mapping = FileMappingHandle = 0; + FileHandle = INVALID_HANDLE_VALUE; + FileDescriptor = 0; } } -bool Path::getMagicNumber(std::string& Magic, unsigned len) const { - assert(len < 1024 && "Request for magic string too long"); - char* buf = reinterpret_cast<char*>(alloca(len)); +mapped_file_region::~mapped_file_region() { + if (Mapping) + ::UnmapViewOfFile(Mapping); +} + +#if LLVM_HAS_RVALUE_REFERENCES +mapped_file_region::mapped_file_region(mapped_file_region &&other) + : Mode(other.Mode) + , Size(other.Size) + , Mapping(other.Mapping) + , FileDescriptor(other.FileDescriptor) + , FileHandle(other.FileHandle) + , FileMappingHandle(other.FileMappingHandle) { + other.Mapping = other.FileMappingHandle = 0; + other.FileHandle = INVALID_HANDLE_VALUE; + other.FileDescriptor = 0; +} +#endif - HANDLE h = CreateFile(path.c_str(), - GENERIC_READ, - FILE_SHARE_READ, - NULL, - OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL, - NULL); - if (h == INVALID_HANDLE_VALUE) - return false; +mapped_file_region::mapmode mapped_file_region::flags() const { + assert(Mapping && "Mapping failed but used anyway!"); + return Mode; +} - DWORD nRead = 0; - BOOL ret = ReadFile(h, buf, len, &nRead, NULL); - CloseHandle(h); +uint64_t mapped_file_region::size() const { + assert(Mapping && "Mapping failed but used anyway!"); + return Size; +} - if (!ret || nRead != len) - return false; +char *mapped_file_region::data() const { + assert(Mode != readonly && "Cannot get non const data for readonly mapping!"); + assert(Mapping && "Mapping failed but used anyway!"); + return reinterpret_cast<char*>(Mapping); +} - Magic = std::string(buf, len); - return true; +const char *mapped_file_region::const_data() const { + assert(Mapping && "Mapping failed but used anyway!"); + return reinterpret_cast<const char*>(Mapping); } -bool -Path::renamePathOnDisk(const Path& newName, std::string* ErrMsg) { - if (!MoveFileEx(path.c_str(), newName.c_str(), MOVEFILE_REPLACE_EXISTING)) - return MakeErrMsg(ErrMsg, "Can't move '" + path + "' to '" + newName.path - + "': "); - return false; +int mapped_file_region::alignment() { + SYSTEM_INFO SysInfo; + ::GetSystemInfo(&SysInfo); + return SysInfo.dwAllocationGranularity; } -bool -Path::setStatusInfoOnDisk(const FileStatus &si, std::string *ErrMsg) const { - // FIXME: should work on directories also. - if (!si.isFile) { - return true; - } +error_code detail::directory_iterator_construct(detail::DirIterState &it, + StringRef path){ + SmallVector<wchar_t, 128> path_utf16; - HANDLE h = CreateFile(path.c_str(), - FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES, - FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, - NULL, - OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL, - NULL); - if (h == INVALID_HANDLE_VALUE) - return true; + if (error_code ec = UTF8ToUTF16(path, + path_utf16)) + return ec; - BY_HANDLE_FILE_INFORMATION bhfi; - if (!GetFileInformationByHandle(h, &bhfi)) { - DWORD err = GetLastError(); - CloseHandle(h); - SetLastError(err); - return MakeErrMsg(ErrMsg, path + ": GetFileInformationByHandle: "); - } - - ULARGE_INTEGER ui; - ui.QuadPart = si.modTime.toWin32Time(); - FILETIME ft; - ft.dwLowDateTime = ui.LowPart; - ft.dwHighDateTime = ui.HighPart; - BOOL ret = SetFileTime(h, NULL, &ft, &ft); - DWORD err = GetLastError(); - CloseHandle(h); - if (!ret) { - SetLastError(err); - return MakeErrMsg(ErrMsg, path + ": SetFileTime: "); - } - - // Best we can do with Unix permission bits is to interpret the owner - // writable bit. - if (si.mode & 0200) { - if (bhfi.dwFileAttributes & FILE_ATTRIBUTE_READONLY) { - if (!SetFileAttributes(path.c_str(), - bhfi.dwFileAttributes & ~FILE_ATTRIBUTE_READONLY)) - return MakeErrMsg(ErrMsg, path + ": SetFileAttributes: "); - } + // Convert path to the format that Windows is happy with. + if (path_utf16.size() > 0 && + !is_separator(path_utf16[path.size() - 1]) && + path_utf16[path.size() - 1] != L':') { + path_utf16.push_back(L'\\'); + path_utf16.push_back(L'*'); } else { - if (!(bhfi.dwFileAttributes & FILE_ATTRIBUTE_READONLY)) { - if (!SetFileAttributes(path.c_str(), - bhfi.dwFileAttributes | FILE_ATTRIBUTE_READONLY)) - return MakeErrMsg(ErrMsg, path + ": SetFileAttributes: "); - } + path_utf16.push_back(L'*'); } - return false; + // Get the first directory entry. + WIN32_FIND_DATAW FirstFind; + ScopedFindHandle FindHandle(::FindFirstFileW(c_str(path_utf16), &FirstFind)); + if (!FindHandle) + return windows_error(::GetLastError()); + + size_t FilenameLen = ::wcslen(FirstFind.cFileName); + while ((FilenameLen == 1 && FirstFind.cFileName[0] == L'.') || + (FilenameLen == 2 && FirstFind.cFileName[0] == L'.' && + FirstFind.cFileName[1] == L'.')) + if (!::FindNextFileW(FindHandle, &FirstFind)) { + error_code ec = windows_error(::GetLastError()); + // Check for end. + if (ec == windows_error::no_more_files) + return detail::directory_iterator_destruct(it); + return ec; + } else + FilenameLen = ::wcslen(FirstFind.cFileName); + + // Construct the current directory entry. + SmallString<128> directory_entry_name_utf8; + if (error_code ec = UTF16ToUTF8(FirstFind.cFileName, + ::wcslen(FirstFind.cFileName), + directory_entry_name_utf8)) + return ec; + + it.IterationHandle = intptr_t(FindHandle.take()); + SmallString<128> directory_entry_path(path); + path::append(directory_entry_path, directory_entry_name_utf8.str()); + it.CurrentEntry = directory_entry(directory_entry_path.str()); + + return error_code::success(); } -bool -CopyFile(const sys::Path &Dest, const sys::Path &Src, std::string* ErrMsg) { - // Can't use CopyFile macro defined in Windows.h because it would mess up the - // above line. We use the expansion it would have in a non-UNICODE build. - if (!::CopyFileA(Src.c_str(), Dest.c_str(), false)) - return MakeErrMsg(ErrMsg, "Can't copy '" + Src.str() + - "' to '" + Dest.str() + "': "); - return false; +error_code detail::directory_iterator_destruct(detail::DirIterState &it) { + if (it.IterationHandle != 0) + // Closes the handle if it's valid. + ScopedFindHandle close(HANDLE(it.IterationHandle)); + it.IterationHandle = 0; + it.CurrentEntry = directory_entry(); + return error_code::success(); } -bool -Path::makeUnique(bool reuse_current, std::string* ErrMsg) { - bool Exists; - if (reuse_current && (fs::exists(path, Exists) || !Exists)) - return false; // File doesn't exist already, just use it! - - // Reserve space for -XXXXXX at the end. - char *FNBuffer = (char*) alloca(path.size()+8); - unsigned offset = path.size(); - path.copy(FNBuffer, offset); - - // Find a numeric suffix that isn't used by an existing file. Assume there - // won't be more than 1 million files with the same prefix. Probably a safe - // bet. - static int FCounter = -1; - if (FCounter < 0) { - // Give arbitrary initial seed. - // FIXME: We should use sys::fs::unique_file() in future. - LARGE_INTEGER cnt64; - DWORD x = GetCurrentProcessId(); - x = (x << 16) | (x >> 16); - if (QueryPerformanceCounter(&cnt64)) // RDTSC - x ^= cnt64.HighPart ^ cnt64.LowPart; - FCounter = x % 1000000; +error_code detail::directory_iterator_increment(detail::DirIterState &it) { + WIN32_FIND_DATAW FindData; + if (!::FindNextFileW(HANDLE(it.IterationHandle), &FindData)) { + error_code ec = windows_error(::GetLastError()); + // Check for end. + if (ec == windows_error::no_more_files) + return detail::directory_iterator_destruct(it); + return ec; } - do { - sprintf(FNBuffer+offset, "-%06u", FCounter); - if (++FCounter > 999999) - FCounter = 0; - path = FNBuffer; - } while (!fs::exists(path, Exists) && Exists); - return false; -} -bool -Path::createTemporaryFileOnDisk(bool reuse_current, std::string* ErrMsg) { - // Make this into a unique file name - makeUnique(reuse_current, ErrMsg); + size_t FilenameLen = ::wcslen(FindData.cFileName); + if ((FilenameLen == 1 && FindData.cFileName[0] == L'.') || + (FilenameLen == 2 && FindData.cFileName[0] == L'.' && + FindData.cFileName[1] == L'.')) + return directory_iterator_increment(it); - // Now go and create it - HANDLE h = CreateFile(path.c_str(), GENERIC_WRITE, 0, NULL, CREATE_NEW, - FILE_ATTRIBUTE_NORMAL, NULL); - if (h == INVALID_HANDLE_VALUE) - return MakeErrMsg(ErrMsg, path + ": can't create file"); + SmallString<128> directory_entry_path_utf8; + if (error_code ec = UTF16ToUTF8(FindData.cFileName, + ::wcslen(FindData.cFileName), + directory_entry_path_utf8)) + return ec; - CloseHandle(h); - return false; + it.CurrentEntry.replace_filename(Twine(directory_entry_path_utf8)); + return error_code::success(); } -/// MapInFilePages - Not yet implemented on win32. -const char *Path::MapInFilePages(int FD, size_t FileSize, off_t Offset) { - return 0; +error_code map_file_pages(const Twine &path, off_t file_offset, size_t size, + bool map_writable, void *&result) { + assert(0 && "NOT IMPLEMENTED"); + return windows_error::invalid_function; } -/// MapInFilePages - Not yet implemented on win32. -void Path::UnMapFilePages(const char *Base, size_t FileSize) { +error_code unmap_file_pages(void *base, size_t size) { assert(0 && "NOT IMPLEMENTED"); + return windows_error::invalid_function; +} + +error_code openFileForRead(const Twine &Name, int &ResultFD) { + SmallString<128> PathStorage; + SmallVector<wchar_t, 128> PathUTF16; + + if (error_code EC = UTF8ToUTF16(Name.toStringRef(PathStorage), + PathUTF16)) + return EC; + + HANDLE H = ::CreateFileW(PathUTF16.begin(), GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (H == INVALID_HANDLE_VALUE) { + error_code EC = windows_error(::GetLastError()); + // Provide a better error message when trying to open directories. + // This only runs if we failed to open the file, so there is probably + // no performances issues. + if (EC != windows_error::access_denied) + return EC; + if (is_directory(Name)) + return error_code(errc::is_a_directory, posix_category()); + return EC; + } + + int FD = ::_open_osfhandle(intptr_t(H), 0); + if (FD == -1) { + ::CloseHandle(H); + return windows_error::invalid_handle; + } + + ResultFD = FD; + return error_code::success(); +} + +error_code openFileForWrite(const Twine &Name, int &ResultFD, + sys::fs::OpenFlags Flags, unsigned Mode) { + // Verify that we don't have both "append" and "excl". + assert((!(Flags & sys::fs::F_Excl) || !(Flags & sys::fs::F_Append)) && + "Cannot specify both 'excl' and 'append' file creation flags!"); + + SmallString<128> PathStorage; + SmallVector<wchar_t, 128> PathUTF16; + + if (error_code EC = UTF8ToUTF16(Name.toStringRef(PathStorage), + PathUTF16)) + return EC; + + DWORD CreationDisposition; + if (Flags & F_Excl) + CreationDisposition = CREATE_NEW; + else if (Flags & F_Append) + CreationDisposition = OPEN_ALWAYS; + else + CreationDisposition = CREATE_ALWAYS; + + HANDLE H = ::CreateFileW(PathUTF16.begin(), GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, + CreationDisposition, FILE_ATTRIBUTE_NORMAL, NULL); + + if (H == INVALID_HANDLE_VALUE) { + error_code EC = windows_error(::GetLastError()); + // Provide a better error message when trying to open directories. + // This only runs if we failed to open the file, so there is probably + // no performances issues. + if (EC != windows_error::access_denied) + return EC; + if (is_directory(Name)) + return error_code(errc::is_a_directory, posix_category()); + return EC; + } + + int OpenFlags = 0; + if (Flags & F_Append) + OpenFlags |= _O_APPEND; + + if (!(Flags & F_Binary)) + OpenFlags |= _O_TEXT; + + int FD = ::_open_osfhandle(intptr_t(H), OpenFlags); + if (FD == -1) { + ::CloseHandle(H); + return windows_error::invalid_handle; + } + + ResultFD = FD; + return error_code::success(); } +} // end namespace fs +namespace windows { +llvm::error_code UTF8ToUTF16(llvm::StringRef utf8, + llvm::SmallVectorImpl<wchar_t> &utf16) { + int len = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, + utf8.begin(), utf8.size(), + utf16.begin(), 0); + + if (len == 0) + return llvm::windows_error(::GetLastError()); + + utf16.reserve(len + 1); + utf16.set_size(len); + + len = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, + utf8.begin(), utf8.size(), + utf16.begin(), utf16.size()); + + if (len == 0) + return llvm::windows_error(::GetLastError()); + + // Make utf16 null terminated. + utf16.push_back(0); + utf16.pop_back(); + + return llvm::error_code::success(); } + +llvm::error_code UTF16ToUTF8(const wchar_t *utf16, size_t utf16_len, + llvm::SmallVectorImpl<char> &utf8) { + // Get length. + int len = ::WideCharToMultiByte(CP_UTF8, 0, + utf16, utf16_len, + utf8.begin(), 0, + NULL, NULL); + + if (len == 0) + return llvm::windows_error(::GetLastError()); + + utf8.reserve(len); + utf8.set_size(len); + + // Now do the actual conversion. + len = ::WideCharToMultiByte(CP_UTF8, 0, + utf16, utf16_len, + utf8.data(), utf8.size(), + NULL, NULL); + + if (len == 0) + return llvm::windows_error(::GetLastError()); + + // Make utf8 null terminated. + utf8.push_back(0); + utf8.pop_back(); + + return llvm::error_code::success(); } +} // end namespace windows +} // end namespace sys +} // end namespace llvm diff --git a/contrib/llvm/lib/Support/Windows/PathV2.inc b/contrib/llvm/lib/Support/Windows/PathV2.inc deleted file mode 100644 index 23f3d14..0000000 --- a/contrib/llvm/lib/Support/Windows/PathV2.inc +++ /dev/null @@ -1,1022 +0,0 @@ -//===- llvm/Support/Windows/PathV2.inc - Windows Path Impl ------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the Windows specific implementation of the PathV2 API. -// -//===----------------------------------------------------------------------===// - -//===----------------------------------------------------------------------===// -//=== WARNING: Implementation here must contain only generic Windows code that -//=== is guaranteed to work on *all* Windows variants. -//===----------------------------------------------------------------------===// - -#include "Windows.h" -#include <fcntl.h> -#include <io.h> -#include <sys/stat.h> -#include <sys/types.h> - -#undef max - -// MinGW doesn't define this. -#ifndef _ERRNO_T_DEFINED -#define _ERRNO_T_DEFINED -typedef int errno_t; -#endif - -using namespace llvm; - -namespace { - typedef BOOLEAN (WINAPI *PtrCreateSymbolicLinkW)( - /*__in*/ LPCWSTR lpSymlinkFileName, - /*__in*/ LPCWSTR lpTargetFileName, - /*__in*/ DWORD dwFlags); - - PtrCreateSymbolicLinkW create_symbolic_link_api = PtrCreateSymbolicLinkW( - ::GetProcAddress(::GetModuleHandleA("kernel32.dll"), - "CreateSymbolicLinkW")); - - error_code UTF8ToUTF16(StringRef utf8, SmallVectorImpl<wchar_t> &utf16) { - int len = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, - utf8.begin(), utf8.size(), - utf16.begin(), 0); - - if (len == 0) - return windows_error(::GetLastError()); - - utf16.reserve(len + 1); - utf16.set_size(len); - - len = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, - utf8.begin(), utf8.size(), - utf16.begin(), utf16.size()); - - if (len == 0) - return windows_error(::GetLastError()); - - // Make utf16 null terminated. - utf16.push_back(0); - utf16.pop_back(); - - return error_code::success(); - } - - error_code UTF16ToUTF8(const wchar_t *utf16, size_t utf16_len, - SmallVectorImpl<char> &utf8) { - // Get length. - int len = ::WideCharToMultiByte(CP_UTF8, 0, - utf16, utf16_len, - utf8.begin(), 0, - NULL, NULL); - - if (len == 0) - return windows_error(::GetLastError()); - - utf8.reserve(len); - utf8.set_size(len); - - // Now do the actual conversion. - len = ::WideCharToMultiByte(CP_UTF8, 0, - utf16, utf16_len, - utf8.data(), utf8.size(), - NULL, NULL); - - if (len == 0) - return windows_error(::GetLastError()); - - // Make utf8 null terminated. - utf8.push_back(0); - utf8.pop_back(); - - return error_code::success(); - } - - error_code TempDir(SmallVectorImpl<wchar_t> &result) { - retry_temp_dir: - DWORD len = ::GetTempPathW(result.capacity(), result.begin()); - - if (len == 0) - return windows_error(::GetLastError()); - - if (len > result.capacity()) { - result.reserve(len); - goto retry_temp_dir; - } - - result.set_size(len); - return error_code::success(); - } - - bool is_separator(const wchar_t value) { - switch (value) { - case L'\\': - case L'/': - return true; - default: - return false; - } - } -} - -namespace llvm { -namespace sys { -namespace fs { - -error_code current_path(SmallVectorImpl<char> &result) { - SmallVector<wchar_t, 128> cur_path; - cur_path.reserve(128); -retry_cur_dir: - DWORD len = ::GetCurrentDirectoryW(cur_path.capacity(), cur_path.data()); - - // A zero return value indicates a failure other than insufficient space. - if (len == 0) - return windows_error(::GetLastError()); - - // If there's insufficient space, the len returned is larger than the len - // given. - if (len > cur_path.capacity()) { - cur_path.reserve(len); - goto retry_cur_dir; - } - - cur_path.set_size(len); - // cur_path now holds the current directory in utf-16. Convert to utf-8. - - // Find out how much space we need. Sadly, this function doesn't return the - // size needed unless you tell it the result size is 0, which means you - // _always_ have to call it twice. - len = ::WideCharToMultiByte(CP_UTF8, 0, - cur_path.data(), cur_path.size(), - result.data(), 0, - NULL, NULL); - - if (len == 0) - return make_error_code(windows_error(::GetLastError())); - - result.reserve(len); - result.set_size(len); - // Now do the actual conversion. - len = ::WideCharToMultiByte(CP_UTF8, 0, - cur_path.data(), cur_path.size(), - result.data(), result.size(), - NULL, NULL); - if (len == 0) - return windows_error(::GetLastError()); - - return error_code::success(); -} - -error_code copy_file(const Twine &from, const Twine &to, copy_option copt) { - // Get arguments. - SmallString<128> from_storage; - SmallString<128> to_storage; - StringRef f = from.toStringRef(from_storage); - StringRef t = to.toStringRef(to_storage); - - // Convert to utf-16. - SmallVector<wchar_t, 128> wide_from; - SmallVector<wchar_t, 128> wide_to; - if (error_code ec = UTF8ToUTF16(f, wide_from)) return ec; - if (error_code ec = UTF8ToUTF16(t, wide_to)) return ec; - - // Copy the file. - BOOL res = ::CopyFileW(wide_from.begin(), wide_to.begin(), - copt != copy_option::overwrite_if_exists); - - if (res == 0) - return windows_error(::GetLastError()); - - return error_code::success(); -} - -error_code create_directory(const Twine &path, bool &existed) { - SmallString<128> path_storage; - SmallVector<wchar_t, 128> path_utf16; - - if (error_code ec = UTF8ToUTF16(path.toStringRef(path_storage), - path_utf16)) - return ec; - - if (!::CreateDirectoryW(path_utf16.begin(), NULL)) { - error_code ec = windows_error(::GetLastError()); - if (ec == windows_error::already_exists) - existed = true; - else - return ec; - } else - existed = false; - - return error_code::success(); -} - -error_code create_hard_link(const Twine &to, const Twine &from) { - // Get arguments. - SmallString<128> from_storage; - SmallString<128> to_storage; - StringRef f = from.toStringRef(from_storage); - StringRef t = to.toStringRef(to_storage); - - // Convert to utf-16. - SmallVector<wchar_t, 128> wide_from; - SmallVector<wchar_t, 128> wide_to; - if (error_code ec = UTF8ToUTF16(f, wide_from)) return ec; - if (error_code ec = UTF8ToUTF16(t, wide_to)) return ec; - - if (!::CreateHardLinkW(wide_from.begin(), wide_to.begin(), NULL)) - return windows_error(::GetLastError()); - - return error_code::success(); -} - -error_code create_symlink(const Twine &to, const Twine &from) { - // Only do it if the function is available at runtime. - if (!create_symbolic_link_api) - return make_error_code(errc::function_not_supported); - - // Get arguments. - SmallString<128> from_storage; - SmallString<128> to_storage; - StringRef f = from.toStringRef(from_storage); - StringRef t = to.toStringRef(to_storage); - - // Convert to utf-16. - SmallVector<wchar_t, 128> wide_from; - SmallVector<wchar_t, 128> wide_to; - if (error_code ec = UTF8ToUTF16(f, wide_from)) return ec; - if (error_code ec = UTF8ToUTF16(t, wide_to)) return ec; - - if (!create_symbolic_link_api(wide_from.begin(), wide_to.begin(), 0)) - return windows_error(::GetLastError()); - - return error_code::success(); -} - -error_code remove(const Twine &path, bool &existed) { - SmallString<128> path_storage; - SmallVector<wchar_t, 128> path_utf16; - - file_status st; - if (error_code ec = status(path, st)) - return ec; - - if (error_code ec = UTF8ToUTF16(path.toStringRef(path_storage), - path_utf16)) - return ec; - - if (st.type() == file_type::directory_file) { - if (!::RemoveDirectoryW(c_str(path_utf16))) { - error_code ec = windows_error(::GetLastError()); - if (ec != windows_error::file_not_found) - return ec; - existed = false; - } else - existed = true; - } else { - if (!::DeleteFileW(c_str(path_utf16))) { - error_code ec = windows_error(::GetLastError()); - if (ec != windows_error::file_not_found) - return ec; - existed = false; - } else - existed = true; - } - - return error_code::success(); -} - -error_code rename(const Twine &from, const Twine &to) { - // Get arguments. - SmallString<128> from_storage; - SmallString<128> to_storage; - StringRef f = from.toStringRef(from_storage); - StringRef t = to.toStringRef(to_storage); - - // Convert to utf-16. - SmallVector<wchar_t, 128> wide_from; - SmallVector<wchar_t, 128> wide_to; - if (error_code ec = UTF8ToUTF16(f, wide_from)) return ec; - if (error_code ec = UTF8ToUTF16(t, wide_to)) return ec; - - error_code ec = error_code::success(); - for (int i = 0; i < 2000; i++) { - if (::MoveFileExW(wide_from.begin(), wide_to.begin(), - MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING)) - return error_code::success(); - ec = windows_error(::GetLastError()); - if (ec != windows_error::access_denied) - break; - // Retry MoveFile() at ACCESS_DENIED. - // System scanners (eg. indexer) might open the source file when - // It is written and closed. - ::Sleep(1); - } - - return ec; -} - -error_code resize_file(const Twine &path, uint64_t size) { - SmallString<128> path_storage; - SmallVector<wchar_t, 128> path_utf16; - - if (error_code ec = UTF8ToUTF16(path.toStringRef(path_storage), - path_utf16)) - return ec; - - int fd = ::_wopen(path_utf16.begin(), O_BINARY | _O_RDWR, S_IWRITE); - if (fd == -1) - return error_code(errno, generic_category()); -#ifdef HAVE__CHSIZE_S - errno_t error = ::_chsize_s(fd, size); -#else - errno_t error = ::_chsize(fd, size); -#endif - ::close(fd); - return error_code(error, generic_category()); -} - -error_code exists(const Twine &path, bool &result) { - SmallString<128> path_storage; - SmallVector<wchar_t, 128> path_utf16; - - if (error_code ec = UTF8ToUTF16(path.toStringRef(path_storage), - path_utf16)) - return ec; - - DWORD attributes = ::GetFileAttributesW(path_utf16.begin()); - - if (attributes == INVALID_FILE_ATTRIBUTES) { - // See if the file didn't actually exist. - error_code ec = make_error_code(windows_error(::GetLastError())); - if (ec != windows_error::file_not_found && - ec != windows_error::path_not_found) - return ec; - result = false; - } else - result = true; - return error_code::success(); -} - -bool equivalent(file_status A, file_status B) { - assert(status_known(A) && status_known(B)); - return A.FileIndexHigh == B.FileIndexHigh && - A.FileIndexLow == B.FileIndexLow && - A.FileSizeHigh == B.FileSizeHigh && - A.FileSizeLow == B.FileSizeLow && - A.LastWriteTimeHigh == B.LastWriteTimeHigh && - A.LastWriteTimeLow == B.LastWriteTimeLow && - A.VolumeSerialNumber == B.VolumeSerialNumber; -} - -error_code equivalent(const Twine &A, const Twine &B, bool &result) { - file_status fsA, fsB; - if (error_code ec = status(A, fsA)) return ec; - if (error_code ec = status(B, fsB)) return ec; - result = equivalent(fsA, fsB); - return error_code::success(); -} - -error_code file_size(const Twine &path, uint64_t &result) { - SmallString<128> path_storage; - SmallVector<wchar_t, 128> path_utf16; - - if (error_code ec = UTF8ToUTF16(path.toStringRef(path_storage), - path_utf16)) - return ec; - - WIN32_FILE_ATTRIBUTE_DATA FileData; - if (!::GetFileAttributesExW(path_utf16.begin(), - ::GetFileExInfoStandard, - &FileData)) - return windows_error(::GetLastError()); - - result = - (uint64_t(FileData.nFileSizeHigh) << (sizeof(FileData.nFileSizeLow) * 8)) - + FileData.nFileSizeLow; - - return error_code::success(); -} - -static bool isReservedName(StringRef path) { - // This list of reserved names comes from MSDN, at: - // http://msdn.microsoft.com/en-us/library/aa365247%28v=vs.85%29.aspx - static const char *sReservedNames[] = { "nul", "con", "prn", "aux", - "com1", "com2", "com3", "com4", "com5", "com6", - "com7", "com8", "com9", "lpt1", "lpt2", "lpt3", - "lpt4", "lpt5", "lpt6", "lpt7", "lpt8", "lpt9" }; - - // First, check to see if this is a device namespace, which always - // starts with \\.\, since device namespaces are not legal file paths. - if (path.startswith("\\\\.\\")) - return true; - - // Then compare against the list of ancient reserved names - for (size_t i = 0; i < sizeof(sReservedNames) / sizeof(const char *); ++i) { - if (path.equals_lower(sReservedNames[i])) - return true; - } - - // The path isn't what we consider reserved. - return false; -} - -error_code status(const Twine &path, file_status &result) { - SmallString<128> path_storage; - SmallVector<wchar_t, 128> path_utf16; - - StringRef path8 = path.toStringRef(path_storage); - if (isReservedName(path8)) { - result = file_status(file_type::character_file); - return error_code::success(); - } - - if (error_code ec = UTF8ToUTF16(path8, path_utf16)) - return ec; - - DWORD attr = ::GetFileAttributesW(path_utf16.begin()); - if (attr == INVALID_FILE_ATTRIBUTES) - goto handle_status_error; - - // Handle reparse points. - if (attr & FILE_ATTRIBUTE_REPARSE_POINT) { - ScopedFileHandle h( - ::CreateFileW(path_utf16.begin(), - 0, // Attributes only. - FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, - NULL, - OPEN_EXISTING, - FILE_FLAG_BACKUP_SEMANTICS, - 0)); - if (!h) - goto handle_status_error; - } - - if (attr & FILE_ATTRIBUTE_DIRECTORY) - result = file_status(file_type::directory_file); - else { - result = file_status(file_type::regular_file); - ScopedFileHandle h( - ::CreateFileW(path_utf16.begin(), - 0, // Attributes only. - FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, - NULL, - OPEN_EXISTING, - FILE_FLAG_BACKUP_SEMANTICS, - 0)); - if (!h) - goto handle_status_error; - BY_HANDLE_FILE_INFORMATION Info; - if (!::GetFileInformationByHandle(h, &Info)) - goto handle_status_error; - result.FileIndexHigh = Info.nFileIndexHigh; - result.FileIndexLow = Info.nFileIndexLow; - result.FileSizeHigh = Info.nFileSizeHigh; - result.FileSizeLow = Info.nFileSizeLow; - result.LastWriteTimeHigh = Info.ftLastWriteTime.dwHighDateTime; - result.LastWriteTimeLow = Info.ftLastWriteTime.dwLowDateTime; - result.VolumeSerialNumber = Info.dwVolumeSerialNumber; - } - - return error_code::success(); - -handle_status_error: - error_code ec = windows_error(::GetLastError()); - if (ec == windows_error::file_not_found || - ec == windows_error::path_not_found) - result = file_status(file_type::file_not_found); - else if (ec == windows_error::sharing_violation) - result = file_status(file_type::type_unknown); - else { - result = file_status(file_type::status_error); - return ec; - } - - return error_code::success(); -} - - -// Modifies permissions on a file. -error_code permissions(const Twine &path, perms prms) { -#if 0 // verify code below before enabling: - // If the permissions bits are not trying to modify - // "write" permissions, there is nothing to do. - if (!(prms & (owner_write|group_write|others_write))) - return error_code::success(); - - SmallString<128> path_storage; - SmallVector<wchar_t, 128> path_utf16; - - if (error_code ec = UTF8ToUTF16(path.toStringRef(path_storage), - path_utf16)) - return ec; - - DWORD attributes = ::GetFileAttributesW(path_utf16.begin()); - - if (prms & add_perms) { - attributes &= ~FILE_ATTRIBUTE_READONLY; - } - else if (prms & remove_perms) { - attributes |= FILE_ATTRIBUTE_READONLY; - } - else { - assert(0 && "neither add_perms or remove_perms is set"); - } - - if ( ! ::SetFileAttributesW(path_utf16.begin(), attributes)) - return windows_error(::GetLastError()); -#endif - return error_code::success(); -} - - -// FIXME: mode should be used here and default to user r/w only, -// it currently comes in as a UNIX mode. -error_code unique_file(const Twine &model, int &result_fd, - SmallVectorImpl<char> &result_path, - bool makeAbsolute, unsigned mode) { - // Use result_path as temp storage. - result_path.set_size(0); - StringRef m = model.toStringRef(result_path); - - SmallVector<wchar_t, 128> model_utf16; - if (error_code ec = UTF8ToUTF16(m, model_utf16)) return ec; - - if (makeAbsolute) { - // Make model absolute by prepending a temp directory if it's not already. - bool absolute = path::is_absolute(m); - - if (!absolute) { - SmallVector<wchar_t, 64> temp_dir; - if (error_code ec = TempDir(temp_dir)) return ec; - // Handle c: by removing it. - if (model_utf16.size() > 2 && model_utf16[1] == L':') { - model_utf16.erase(model_utf16.begin(), model_utf16.begin() + 2); - } - model_utf16.insert(model_utf16.begin(), temp_dir.begin(), temp_dir.end()); - } - } - - // Replace '%' with random chars. From here on, DO NOT modify model. It may be - // needed if the randomly chosen path already exists. - SmallVector<wchar_t, 128> random_path_utf16; - - // Get a Crypto Provider for CryptGenRandom. - HCRYPTPROV HCPC; - if (!::CryptAcquireContextW(&HCPC, - NULL, - NULL, - PROV_RSA_FULL, - CRYPT_VERIFYCONTEXT)) - return windows_error(::GetLastError()); - ScopedCryptContext CryptoProvider(HCPC); - -retry_random_path: - random_path_utf16.set_size(0); - for (SmallVectorImpl<wchar_t>::const_iterator i = model_utf16.begin(), - e = model_utf16.end(); - i != e; ++i) { - if (*i == L'%') { - BYTE val = 0; - if (!::CryptGenRandom(CryptoProvider, 1, &val)) - return windows_error(::GetLastError()); - random_path_utf16.push_back("0123456789abcdef"[val & 15]); - } - else - random_path_utf16.push_back(*i); - } - // Make random_path_utf16 null terminated. - random_path_utf16.push_back(0); - random_path_utf16.pop_back(); - - // Make sure we don't fall into an infinite loop by constantly trying - // to create the parent path. - bool TriedToCreateParent = false; - - // Try to create + open the path. -retry_create_file: - HANDLE TempFileHandle = ::CreateFileW(random_path_utf16.begin(), - GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_READ, - NULL, - // Return ERROR_FILE_EXISTS if the file - // already exists. - CREATE_NEW, - FILE_ATTRIBUTE_TEMPORARY, - NULL); - if (TempFileHandle == INVALID_HANDLE_VALUE) { - // If the file existed, try again, otherwise, error. - error_code ec = windows_error(::GetLastError()); - if (ec == windows_error::file_exists) - goto retry_random_path; - // Check for non-existing parent directories. - if (ec == windows_error::path_not_found && !TriedToCreateParent) { - TriedToCreateParent = true; - - // Create the directories using result_path as temp storage. - if (error_code ec = UTF16ToUTF8(random_path_utf16.begin(), - random_path_utf16.size(), result_path)) - return ec; - StringRef p(result_path.begin(), result_path.size()); - SmallString<64> dir_to_create; - for (path::const_iterator i = path::begin(p), - e = --path::end(p); i != e; ++i) { - path::append(dir_to_create, *i); - bool Exists; - if (error_code ec = exists(Twine(dir_to_create), Exists)) return ec; - if (!Exists) { - // If c: doesn't exist, bail. - if (i->endswith(":")) - return ec; - - SmallVector<wchar_t, 64> dir_to_create_utf16; - if (error_code ec = UTF8ToUTF16(dir_to_create, dir_to_create_utf16)) - return ec; - - // Create the directory. - if (!::CreateDirectoryW(dir_to_create_utf16.begin(), NULL)) - return windows_error(::GetLastError()); - } - } - goto retry_create_file; - } - return ec; - } - - // Set result_path to the utf-8 representation of the path. - if (error_code ec = UTF16ToUTF8(random_path_utf16.begin(), - random_path_utf16.size(), result_path)) { - ::CloseHandle(TempFileHandle); - ::DeleteFileW(random_path_utf16.begin()); - return ec; - } - - // Convert the Windows API file handle into a C-runtime handle. - int fd = ::_open_osfhandle(intptr_t(TempFileHandle), 0); - if (fd == -1) { - ::CloseHandle(TempFileHandle); - ::DeleteFileW(random_path_utf16.begin()); - // MSDN doesn't say anything about _open_osfhandle setting errno or - // GetLastError(), so just return invalid_handle. - return windows_error::invalid_handle; - } - - result_fd = fd; - return error_code::success(); -} - -error_code get_magic(const Twine &path, uint32_t len, - SmallVectorImpl<char> &result) { - SmallString<128> path_storage; - SmallVector<wchar_t, 128> path_utf16; - result.set_size(0); - - // Convert path to UTF-16. - if (error_code ec = UTF8ToUTF16(path.toStringRef(path_storage), - path_utf16)) - return ec; - - // Open file. - HANDLE file = ::CreateFileW(c_str(path_utf16), - GENERIC_READ, - FILE_SHARE_READ, - NULL, - OPEN_EXISTING, - FILE_ATTRIBUTE_READONLY, - NULL); - if (file == INVALID_HANDLE_VALUE) - return windows_error(::GetLastError()); - - // Allocate buffer. - result.reserve(len); - - // Get magic! - DWORD bytes_read = 0; - BOOL read_success = ::ReadFile(file, result.data(), len, &bytes_read, NULL); - error_code ec = windows_error(::GetLastError()); - ::CloseHandle(file); - if (!read_success || (bytes_read != len)) { - // Set result size to the number of bytes read if it's valid. - if (bytes_read <= len) - result.set_size(bytes_read); - // ERROR_HANDLE_EOF is mapped to errc::value_too_large. - return ec; - } - - result.set_size(len); - return error_code::success(); -} - -error_code mapped_file_region::init(int FD, bool CloseFD, uint64_t Offset) { - FileDescriptor = FD; - // Make sure that the requested size fits within SIZE_T. - if (Size > std::numeric_limits<SIZE_T>::max()) { - if (FileDescriptor) { - if (CloseFD) - _close(FileDescriptor); - } else - ::CloseHandle(FileHandle); - return make_error_code(errc::invalid_argument); - } - - DWORD flprotect; - switch (Mode) { - case readonly: flprotect = PAGE_READONLY; break; - case readwrite: flprotect = PAGE_READWRITE; break; - case priv: flprotect = PAGE_WRITECOPY; break; - default: llvm_unreachable("invalid mapping mode"); - } - - FileMappingHandle = ::CreateFileMapping(FileHandle, - 0, - flprotect, - Size >> 32, - Size & 0xffffffff, - 0); - if (FileMappingHandle == NULL) { - error_code ec = windows_error(GetLastError()); - if (FileDescriptor) { - if (CloseFD) - _close(FileDescriptor); - } else - ::CloseHandle(FileHandle); - return ec; - } - - DWORD dwDesiredAccess; - switch (Mode) { - case readonly: dwDesiredAccess = FILE_MAP_READ; break; - case readwrite: dwDesiredAccess = FILE_MAP_WRITE; break; - case priv: dwDesiredAccess = FILE_MAP_COPY; break; - default: llvm_unreachable("invalid mapping mode"); - } - Mapping = ::MapViewOfFile(FileMappingHandle, - dwDesiredAccess, - Offset >> 32, - Offset & 0xffffffff, - Size); - if (Mapping == NULL) { - error_code ec = windows_error(GetLastError()); - ::CloseHandle(FileMappingHandle); - if (FileDescriptor) { - if (CloseFD) - _close(FileDescriptor); - } else - ::CloseHandle(FileHandle); - return ec; - } - - if (Size == 0) { - MEMORY_BASIC_INFORMATION mbi; - SIZE_T Result = VirtualQuery(Mapping, &mbi, sizeof(mbi)); - if (Result == 0) { - error_code ec = windows_error(GetLastError()); - ::UnmapViewOfFile(Mapping); - ::CloseHandle(FileMappingHandle); - if (FileDescriptor) { - if (CloseFD) - _close(FileDescriptor); - } else - ::CloseHandle(FileHandle); - return ec; - } - Size = mbi.RegionSize; - } - - // Close all the handles except for the view. It will keep the other handles - // alive. - ::CloseHandle(FileMappingHandle); - if (FileDescriptor) { - if (CloseFD) - _close(FileDescriptor); // Also closes FileHandle. - } else - ::CloseHandle(FileHandle); - return error_code::success(); -} - -mapped_file_region::mapped_file_region(const Twine &path, - mapmode mode, - uint64_t length, - uint64_t offset, - error_code &ec) - : Mode(mode) - , Size(length) - , Mapping() - , FileDescriptor() - , FileHandle(INVALID_HANDLE_VALUE) - , FileMappingHandle() { - SmallString<128> path_storage; - SmallVector<wchar_t, 128> path_utf16; - - // Convert path to UTF-16. - if ((ec = UTF8ToUTF16(path.toStringRef(path_storage), path_utf16))) - return; - - // Get file handle for creating a file mapping. - FileHandle = ::CreateFileW(c_str(path_utf16), - Mode == readonly ? GENERIC_READ - : GENERIC_READ | GENERIC_WRITE, - Mode == readonly ? FILE_SHARE_READ - : 0, - 0, - Mode == readonly ? OPEN_EXISTING - : OPEN_ALWAYS, - Mode == readonly ? FILE_ATTRIBUTE_READONLY - : FILE_ATTRIBUTE_NORMAL, - 0); - if (FileHandle == INVALID_HANDLE_VALUE) { - ec = windows_error(::GetLastError()); - return; - } - - FileDescriptor = 0; - ec = init(FileDescriptor, true, offset); - if (ec) { - Mapping = FileMappingHandle = 0; - FileHandle = INVALID_HANDLE_VALUE; - FileDescriptor = 0; - } -} - -mapped_file_region::mapped_file_region(int fd, - bool closefd, - mapmode mode, - uint64_t length, - uint64_t offset, - error_code &ec) - : Mode(mode) - , Size(length) - , Mapping() - , FileDescriptor(fd) - , FileHandle(INVALID_HANDLE_VALUE) - , FileMappingHandle() { - FileHandle = reinterpret_cast<HANDLE>(_get_osfhandle(fd)); - if (FileHandle == INVALID_HANDLE_VALUE) { - if (closefd) - _close(FileDescriptor); - FileDescriptor = 0; - ec = make_error_code(errc::bad_file_descriptor); - return; - } - - ec = init(FileDescriptor, closefd, offset); - if (ec) { - Mapping = FileMappingHandle = 0; - FileHandle = INVALID_HANDLE_VALUE; - FileDescriptor = 0; - } -} - -mapped_file_region::~mapped_file_region() { - if (Mapping) - ::UnmapViewOfFile(Mapping); -} - -#if LLVM_HAS_RVALUE_REFERENCES -mapped_file_region::mapped_file_region(mapped_file_region &&other) - : Mode(other.Mode) - , Size(other.Size) - , Mapping(other.Mapping) - , FileDescriptor(other.FileDescriptor) - , FileHandle(other.FileHandle) - , FileMappingHandle(other.FileMappingHandle) { - other.Mapping = other.FileMappingHandle = 0; - other.FileHandle = INVALID_HANDLE_VALUE; - other.FileDescriptor = 0; -} -#endif - -mapped_file_region::mapmode mapped_file_region::flags() const { - assert(Mapping && "Mapping failed but used anyway!"); - return Mode; -} - -uint64_t mapped_file_region::size() const { - assert(Mapping && "Mapping failed but used anyway!"); - return Size; -} - -char *mapped_file_region::data() const { - assert(Mode != readonly && "Cannot get non const data for readonly mapping!"); - assert(Mapping && "Mapping failed but used anyway!"); - return reinterpret_cast<char*>(Mapping); -} - -const char *mapped_file_region::const_data() const { - assert(Mapping && "Mapping failed but used anyway!"); - return reinterpret_cast<const char*>(Mapping); -} - -int mapped_file_region::alignment() { - SYSTEM_INFO SysInfo; - ::GetSystemInfo(&SysInfo); - return SysInfo.dwAllocationGranularity; -} - -error_code detail::directory_iterator_construct(detail::DirIterState &it, - StringRef path){ - SmallVector<wchar_t, 128> path_utf16; - - if (error_code ec = UTF8ToUTF16(path, - path_utf16)) - return ec; - - // Convert path to the format that Windows is happy with. - if (path_utf16.size() > 0 && - !is_separator(path_utf16[path.size() - 1]) && - path_utf16[path.size() - 1] != L':') { - path_utf16.push_back(L'\\'); - path_utf16.push_back(L'*'); - } else { - path_utf16.push_back(L'*'); - } - - // Get the first directory entry. - WIN32_FIND_DATAW FirstFind; - ScopedFindHandle FindHandle(::FindFirstFileW(c_str(path_utf16), &FirstFind)); - if (!FindHandle) - return windows_error(::GetLastError()); - - size_t FilenameLen = ::wcslen(FirstFind.cFileName); - while ((FilenameLen == 1 && FirstFind.cFileName[0] == L'.') || - (FilenameLen == 2 && FirstFind.cFileName[0] == L'.' && - FirstFind.cFileName[1] == L'.')) - if (!::FindNextFileW(FindHandle, &FirstFind)) { - error_code ec = windows_error(::GetLastError()); - // Check for end. - if (ec == windows_error::no_more_files) - return detail::directory_iterator_destruct(it); - return ec; - } else - FilenameLen = ::wcslen(FirstFind.cFileName); - - // Construct the current directory entry. - SmallString<128> directory_entry_name_utf8; - if (error_code ec = UTF16ToUTF8(FirstFind.cFileName, - ::wcslen(FirstFind.cFileName), - directory_entry_name_utf8)) - return ec; - - it.IterationHandle = intptr_t(FindHandle.take()); - SmallString<128> directory_entry_path(path); - path::append(directory_entry_path, directory_entry_name_utf8.str()); - it.CurrentEntry = directory_entry(directory_entry_path.str()); - - return error_code::success(); -} - -error_code detail::directory_iterator_destruct(detail::DirIterState &it) { - if (it.IterationHandle != 0) - // Closes the handle if it's valid. - ScopedFindHandle close(HANDLE(it.IterationHandle)); - it.IterationHandle = 0; - it.CurrentEntry = directory_entry(); - return error_code::success(); -} - -error_code detail::directory_iterator_increment(detail::DirIterState &it) { - WIN32_FIND_DATAW FindData; - if (!::FindNextFileW(HANDLE(it.IterationHandle), &FindData)) { - error_code ec = windows_error(::GetLastError()); - // Check for end. - if (ec == windows_error::no_more_files) - return detail::directory_iterator_destruct(it); - return ec; - } - - size_t FilenameLen = ::wcslen(FindData.cFileName); - if ((FilenameLen == 1 && FindData.cFileName[0] == L'.') || - (FilenameLen == 2 && FindData.cFileName[0] == L'.' && - FindData.cFileName[1] == L'.')) - return directory_iterator_increment(it); - - SmallString<128> directory_entry_path_utf8; - if (error_code ec = UTF16ToUTF8(FindData.cFileName, - ::wcslen(FindData.cFileName), - directory_entry_path_utf8)) - return ec; - - it.CurrentEntry.replace_filename(Twine(directory_entry_path_utf8)); - return error_code::success(); -} - -error_code map_file_pages(const Twine &path, off_t file_offset, size_t size, - bool map_writable, void *&result) { - assert(0 && "NOT IMPLEMENTED"); - return windows_error::invalid_function; -} - -error_code unmap_file_pages(void *base, size_t size) { - assert(0 && "NOT IMPLEMENTED"); - return windows_error::invalid_function; -} - - - -} // end namespace fs -} // end namespace sys -} // end namespace llvm diff --git a/contrib/llvm/lib/Support/Windows/Process.inc b/contrib/llvm/lib/Support/Windows/Process.inc index ad94128..f9a3db9 100644 --- a/contrib/llvm/lib/Support/Windows/Process.inc +++ b/contrib/llvm/lib/Support/Windows/Process.inc @@ -11,18 +11,25 @@ // //===----------------------------------------------------------------------===// +#include "llvm/Support/Allocator.h" + #include "Windows.h" #include <direct.h> #include <io.h> #include <malloc.h> #include <psapi.h> +#include <shellapi.h> #ifdef __MINGW32__ #if (HAVE_LIBPSAPI != 1) #error "libpsapi.a should be present" #endif + #if (HAVE_LIBSHELL32 != 1) + #error "libshell32.a should be present" + #endif #else #pragma comment(lib, "psapi.lib") + #pragma comment(lib, "shell32.lib") #endif //===----------------------------------------------------------------------===// @@ -40,7 +47,7 @@ using namespace sys; process::id_type self_process::get_id() { - return GetCurrentProcess(); + return GetCurrentProcessId(); } static TimeValue getTimeValueFromFILETIME(FILETIME Time) { @@ -83,6 +90,8 @@ static unsigned getPageSize() { // that LLVM ought to run as 64-bits on a 64-bit system, anyway. SYSTEM_INFO info; GetSystemInfo(&info); + // FIXME: FileOffset in MapViewOfFile() should be aligned to not dwPageSize, + // but dwAllocationGranularity. return static_cast<unsigned>(info.dwPageSize); } @@ -119,28 +128,89 @@ void Process::GetTimeUsage(TimeValue &elapsed, TimeValue &user_time, sys_time = getTimeValueFromFILETIME(KernelTime); } -int Process::GetCurrentUserId() -{ - return 65536; -} - -int Process::GetCurrentGroupId() -{ - return 65536; -} - // Some LLVM programs such as bugpoint produce core files as a normal part of -// their operation. To prevent the disk from filling up, this configuration item -// does what's necessary to prevent their generation. +// their operation. To prevent the disk from filling up, this configuration +// item does what's necessary to prevent their generation. void Process::PreventCoreFiles() { - // Windows doesn't do core files, but it does do modal pop-up message - // boxes. As this method is used by bugpoint, preventing these pop-ups - // is the moral equivalent of suppressing core files. + // Windows does have the concept of core files, called minidumps. However, + // disabling minidumps for a particular application extends past the lifetime + // of that application, which is the incorrect behavior for this API. + // Additionally, the APIs require elevated privileges to disable and re- + // enable minidumps, which makes this untenable. For more information, see + // WerAddExcludedApplication and WerRemoveExcludedApplication (Vista and + // later). + // + // Windows also has modal pop-up message boxes. As this method is used by + // bugpoint, preventing these pop-ups is additionally important. SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX); } +/// Returns the environment variable \arg Name's value as a string encoded in +/// UTF-8. \arg Name is assumed to be in UTF-8 encoding. +Optional<std::string> Process::GetEnv(StringRef Name) { + // Convert the argument to UTF-16 to pass it to _wgetenv(). + SmallVector<wchar_t, 128> NameUTF16; + if (error_code ec = windows::UTF8ToUTF16(Name, NameUTF16)) + return None; + + // Environment variable can be encoded in non-UTF8 encoding, and there's no + // way to know what the encoding is. The only reliable way to look up + // multibyte environment variable is to use GetEnvironmentVariableW(). + SmallVector<wchar_t, MAX_PATH> Buf; + size_t Size = MAX_PATH; + do { + Buf.reserve(Size); + Size = + GetEnvironmentVariableW(NameUTF16.data(), Buf.data(), Buf.capacity()); + if (Size == 0) + return None; + + // Try again with larger buffer. + } while (Size > Buf.capacity()); + Buf.set_size(Size); + + // Convert the result from UTF-16 to UTF-8. + SmallVector<char, MAX_PATH> Res; + if (error_code ec = windows::UTF16ToUTF8(Buf.data(), Size, Res)) + return None; + return std::string(Res.data()); +} + +error_code +Process::GetArgumentVector(SmallVectorImpl<const char *> &Args, + ArrayRef<const char *>, + SpecificBumpPtrAllocator<char> &ArgAllocator) { + int NewArgCount; + error_code ec; + + wchar_t **UnicodeCommandLine = CommandLineToArgvW(GetCommandLineW(), + &NewArgCount); + if (!UnicodeCommandLine) + return windows_error(::GetLastError()); + + Args.reserve(NewArgCount); + + for (int i = 0; i < NewArgCount; ++i) { + SmallVector<char, MAX_PATH> NewArgString; + ec = windows::UTF16ToUTF8(UnicodeCommandLine[i], + wcslen(UnicodeCommandLine[i]), + NewArgString); + if (ec) + break; + + char *Buffer = ArgAllocator.Allocate(NewArgString.size() + 1); + ::memcpy(Buffer, NewArgString.data(), NewArgString.size() + 1); + Args.push_back(Buffer); + } + LocalFree(UnicodeCommandLine); + if (ec) + return ec; + + return error_code::success(); +} + bool Process::StandardInIsUserInput() { return FileDescriptorIsDisplayed(0); } @@ -187,6 +257,11 @@ bool Process::StandardErrHasColors() { return FileDescriptorHasColors(2); } +static bool UseANSI = false; +void Process::UseANSIEscapeCodes(bool enable) { + UseANSI = enable; +} + namespace { class DefaultColors { @@ -208,10 +283,12 @@ DefaultColors defaultColors; } bool Process::ColorNeedsFlush() { - return true; + return !UseANSI; } const char *Process::OutputBold(bool bg) { + if (UseANSI) return "\033[1m"; + WORD colors = DefaultColors::GetCurrentColor(); if (bg) colors |= BACKGROUND_INTENSITY; @@ -222,6 +299,8 @@ const char *Process::OutputBold(bool bg) { } const char *Process::OutputColor(char code, bool bold, bool bg) { + if (UseANSI) return colorcodes[bg?1:0][bold?1:0][code&7]; + WORD colors; if (bg) { colors = ((code&1) ? BACKGROUND_RED : 0) | @@ -247,6 +326,8 @@ static WORD GetConsoleTextAttribute(HANDLE hConsoleOutput) { } const char *Process::OutputReverse() { + if (UseANSI) return "\033[7m"; + const WORD attributes = GetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE)); @@ -273,6 +354,7 @@ const char *Process::OutputReverse() { } const char *Process::ResetColor() { + if (UseANSI) return "\033[0m"; SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), defaultColors()); return 0; } diff --git a/contrib/llvm/lib/Support/Windows/Program.inc b/contrib/llvm/lib/Support/Windows/Program.inc index 619ae5d..dc09738 100644 --- a/contrib/llvm/lib/Support/Windows/Program.inc +++ b/contrib/llvm/lib/Support/Windows/Program.inc @@ -12,6 +12,8 @@ //===----------------------------------------------------------------------===// #include "Windows.h" +#include "llvm/ADT/OwningPtr.h" +#include "llvm/Support/FileSystem.h" #include <cstdio> #include <fcntl.h> #include <io.h> @@ -22,37 +24,17 @@ //=== and must not be UNIX code //===----------------------------------------------------------------------===// -namespace { - struct Win32ProcessInfo { - HANDLE hProcess; - DWORD dwProcessId; - }; -} - namespace llvm { using namespace sys; -Program::Program() : Data_(0) {} - -Program::~Program() { - if (Data_) { - Win32ProcessInfo* wpi = reinterpret_cast<Win32ProcessInfo*>(Data_); - CloseHandle(wpi->hProcess); - delete wpi; - Data_ = 0; - } -} +ProcessInfo::ProcessInfo() : ProcessHandle(0), Pid(0), ReturnCode(0) {} // This function just uses the PATH environment variable to find the program. -Path -Program::FindProgramByName(const std::string& progName) { - +std::string sys::FindProgramByName(const std::string &progName) { // Check some degenerate cases if (progName.length() == 0) // no program - return Path(); - Path temp; - if (!temp.set(progName)) // invalid name - return Path(); + return ""; + std::string temp = progName; // Return paths with slashes verbatim. if (progName.find('\\') != std::string::npos || progName.find('/') != std::string::npos) @@ -60,58 +42,60 @@ Program::FindProgramByName(const std::string& progName) { // At this point, the file name is valid and does not contain slashes. // Let Windows search for it. - char buffer[MAX_PATH]; - char *dummy = NULL; - DWORD len = SearchPath(NULL, progName.c_str(), ".exe", MAX_PATH, - buffer, &dummy); - - // See if it wasn't found. - if (len == 0) - return Path(); - - // See if we got the entire path. - if (len < MAX_PATH) - return Path(buffer); - - // Buffer was too small; grow and retry. - while (true) { - char *b = reinterpret_cast<char *>(_alloca(len+1)); - DWORD len2 = SearchPath(NULL, progName.c_str(), ".exe", len+1, b, &dummy); - - // It is unlikely the search failed, but it's always possible some file - // was added or removed since the last search, so be paranoid... - if (len2 == 0) - return Path(); - else if (len2 <= len) - return Path(b); - - len = len2; - } + SmallVector<wchar_t, MAX_PATH> progNameUnicode; + if (windows::UTF8ToUTF16(progName, progNameUnicode)) + return ""; + + SmallVector<wchar_t, MAX_PATH> buffer; + DWORD len = MAX_PATH; + do { + buffer.reserve(len); + len = ::SearchPathW(NULL, progNameUnicode.data(), L".exe", + buffer.capacity(), buffer.data(), NULL); + + // See if it wasn't found. + if (len == 0) + return ""; + + // Buffer was too small; grow and retry. + } while (len > buffer.capacity()); + + buffer.set_size(len); + SmallVector<char, MAX_PATH> result; + if (windows::UTF16ToUTF8(buffer.begin(), buffer.size(), result)) + return ""; + + return std::string(result.data(), result.size()); } -static HANDLE RedirectIO(const Path *path, int fd, std::string* ErrMsg) { +static HANDLE RedirectIO(const StringRef *path, int fd, std::string* ErrMsg) { HANDLE h; if (path == 0) { - DuplicateHandle(GetCurrentProcess(), (HANDLE)_get_osfhandle(fd), - GetCurrentProcess(), &h, - 0, TRUE, DUPLICATE_SAME_ACCESS); + if (!DuplicateHandle(GetCurrentProcess(), (HANDLE)_get_osfhandle(fd), + GetCurrentProcess(), &h, + 0, TRUE, DUPLICATE_SAME_ACCESS)) + return INVALID_HANDLE_VALUE; return h; } - const char *fname; - if (path->isEmpty()) + std::string fname; + if (path->empty()) fname = "NUL"; else - fname = path->c_str(); + fname = *path; SECURITY_ATTRIBUTES sa; sa.nLength = sizeof(sa); sa.lpSecurityDescriptor = 0; sa.bInheritHandle = TRUE; - h = CreateFile(fname, fd ? GENERIC_WRITE : GENERIC_READ, FILE_SHARE_READ, - &sa, fd == 0 ? OPEN_EXISTING : CREATE_ALWAYS, - FILE_ATTRIBUTE_NORMAL, NULL); + SmallVector<wchar_t, 128> fnameUnicode; + if (windows::UTF8ToUTF16(fname, fnameUnicode)) + return INVALID_HANDLE_VALUE; + + h = CreateFileW(fnameUnicode.data(), fd ? GENERIC_WRITE : GENERIC_READ, + FILE_SHARE_READ, &sa, fd == 0 ? OPEN_EXISTING : CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, NULL); if (h == INVALID_HANDLE_VALUE) { MakeErrMsg(ErrMsg, std::string(fname) + ": Can't open file for " + (fd ? "input: " : "output: ")); @@ -181,22 +165,12 @@ static unsigned int ArgLenWithQuotes(const char *Str) { return len; } +} -bool -Program::Execute(const Path& path, - const char** args, - const char** envp, - const Path** redirects, - unsigned memoryLimit, - std::string* ErrMsg) { - if (Data_) { - Win32ProcessInfo* wpi = reinterpret_cast<Win32ProcessInfo*>(Data_); - CloseHandle(wpi->hProcess); - delete wpi; - Data_ = 0; - } - - if (!path.canExecute()) { +static bool Execute(ProcessInfo &PI, StringRef Program, const char **args, + const char **envp, const StringRef **redirects, + unsigned memoryLimit, std::string *ErrMsg) { + if (!sys::fs::can_execute(Program)) { if (ErrMsg) *ErrMsg = "program not executable"; return false; @@ -213,8 +187,8 @@ Program::Execute(const Path& path, } // Now build the command line. - char *command = reinterpret_cast<char *>(_alloca(len+1)); - char *p = command; + OwningArrayPtr<char> command(new char[len+1]); + char *p = command.get(); for (unsigned i = 0; args[i]; i++) { const char *arg = args[i]; @@ -245,34 +219,28 @@ Program::Execute(const Path& path, *p = 0; // The pointer to the environment block for the new process. - char *envblock = 0; + std::vector<wchar_t> EnvBlock; if (envp) { // An environment block consists of a null-terminated block of // null-terminated strings. Convert the array of environment variables to // an environment block by concatenating them. + for (unsigned i = 0; envp[i]; ++i) { + SmallVector<wchar_t, MAX_PATH> EnvString; + if (error_code ec = windows::UTF8ToUTF16(envp[i], EnvString)) { + SetLastError(ec.value()); + MakeErrMsg(ErrMsg, "Unable to convert environment variable to UTF-16"); + return false; + } - // First, determine the length of the environment block. - len = 0; - for (unsigned i = 0; envp[i]; i++) - len += strlen(envp[i]) + 1; - - // Now build the environment block. - envblock = reinterpret_cast<char *>(_alloca(len+1)); - p = envblock; - - for (unsigned i = 0; envp[i]; i++) { - const char *ev = envp[i]; - size_t len = strlen(ev) + 1; - memcpy(p, ev, len); - p += len; + EnvBlock.insert(EnvBlock.end(), EnvString.begin(), EnvString.end()); + EnvBlock.push_back(0); } - - *p = 0; + EnvBlock.push_back(0); } // Create a child process. - STARTUPINFO si; + STARTUPINFOW si; memset(&si, 0, sizeof(si)); si.cb = sizeof(si); si.hStdInput = INVALID_HANDLE_VALUE; @@ -296,9 +264,14 @@ Program::Execute(const Path& path, if (redirects[1] && redirects[2] && *(redirects[1]) == *(redirects[2])) { // If stdout and stderr should go to the same place, redirect stderr // to the handle already open for stdout. - DuplicateHandle(GetCurrentProcess(), si.hStdOutput, - GetCurrentProcess(), &si.hStdError, - 0, TRUE, DUPLICATE_SAME_ACCESS); + if (!DuplicateHandle(GetCurrentProcess(), si.hStdOutput, + GetCurrentProcess(), &si.hStdError, + 0, TRUE, DUPLICATE_SAME_ACCESS)) { + CloseHandle(si.hStdInput); + CloseHandle(si.hStdOutput); + MakeErrMsg(ErrMsg, "can't dup stderr to stdout"); + return false; + } } else { // Just redirect stderr si.hStdError = RedirectIO(redirects[2], 2, ErrMsg); @@ -316,8 +289,27 @@ Program::Execute(const Path& path, fflush(stdout); fflush(stderr); - BOOL rc = CreateProcess(path.c_str(), command, NULL, NULL, TRUE, 0, - envblock, NULL, &si, &pi); + + SmallVector<wchar_t, MAX_PATH> ProgramUtf16; + if (error_code ec = windows::UTF8ToUTF16(Program, ProgramUtf16)) { + SetLastError(ec.value()); + MakeErrMsg(ErrMsg, + std::string("Unable to convert application name to UTF-16")); + return false; + } + + SmallVector<wchar_t, MAX_PATH> CommandUtf16; + if (error_code ec = windows::UTF8ToUTF16(command.get(), CommandUtf16)) { + SetLastError(ec.value()); + MakeErrMsg(ErrMsg, + std::string("Unable to convert command-line to UTF-16")); + return false; + } + + BOOL rc = CreateProcessW(ProgramUtf16.data(), CommandUtf16.data(), 0, 0, + TRUE, CREATE_UNICODE_ENVIRONMENT, + EnvBlock.empty() ? 0 : EnvBlock.data(), 0, &si, + &pi); DWORD err = GetLastError(); // Regardless of whether the process got created or not, we are done with @@ -330,13 +322,12 @@ Program::Execute(const Path& path, if (!rc) { SetLastError(err); MakeErrMsg(ErrMsg, std::string("Couldn't execute program '") + - path.str() + "'"); + Program.str() + "'"); return false; } - Win32ProcessInfo* wpi = new Win32ProcessInfo; - wpi->hProcess = pi.hProcess; - wpi->dwProcessId = pi.dwProcessId; - Data_ = wpi; + + PI.Pid = pi.dwProcessId; + PI.ProcessHandle = pi.hProcess; // Make sure these get closed no matter what. ScopedCommonHandle hThread(pi.hThread); @@ -344,7 +335,7 @@ Program::Execute(const Path& path, // Assign the process to a job if a memory limit is defined. ScopedJobHandle hJob; if (memoryLimit != 0) { - hJob = CreateJobObject(0, 0); + hJob = CreateJobObjectW(0, 0); bool success = false; if (hJob) { JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli; @@ -369,72 +360,84 @@ Program::Execute(const Path& path, return true; } -int -Program::Wait(const Path &path, - unsigned secondsToWait, - std::string* ErrMsg) { - if (Data_ == 0) { - MakeErrMsg(ErrMsg, "Process not started!"); - return -1; - } - - Win32ProcessInfo* wpi = reinterpret_cast<Win32ProcessInfo*>(Data_); - HANDLE hProcess = wpi->hProcess; - - // Wait for the process to terminate. - DWORD millisecondsToWait = INFINITE; - if (secondsToWait > 0) - millisecondsToWait = secondsToWait * 1000; - - if (WaitForSingleObject(hProcess, millisecondsToWait) == WAIT_TIMEOUT) { - if (!TerminateProcess(hProcess, 1)) { - MakeErrMsg(ErrMsg, "Failed to terminate timed-out program."); - // -2 indicates a crash or timeout as opposed to failure to execute. - return -2; +namespace llvm { +ProcessInfo sys::Wait(const ProcessInfo &PI, unsigned SecondsToWait, + bool WaitUntilChildTerminates, std::string *ErrMsg) { + assert(PI.Pid && "invalid pid to wait on, process not started?"); + assert(PI.ProcessHandle && + "invalid process handle to wait on, process not started?"); + DWORD milliSecondsToWait = 0; + if (WaitUntilChildTerminates) + milliSecondsToWait = INFINITE; + else if (SecondsToWait > 0) + milliSecondsToWait = SecondsToWait * 1000; + + ProcessInfo WaitResult = PI; + DWORD WaitStatus = WaitForSingleObject(PI.ProcessHandle, milliSecondsToWait); + if (WaitStatus == WAIT_TIMEOUT) { + if (SecondsToWait) { + if (!TerminateProcess(PI.ProcessHandle, 1)) { + if (ErrMsg) + MakeErrMsg(ErrMsg, "Failed to terminate timed-out program."); + + // -2 indicates a crash or timeout as opposed to failure to execute. + WaitResult.ReturnCode = -2; + CloseHandle(PI.ProcessHandle); + return WaitResult; + } + WaitForSingleObject(PI.ProcessHandle, INFINITE); + CloseHandle(PI.ProcessHandle); + } else { + // Non-blocking wait. + return ProcessInfo(); } - WaitForSingleObject(hProcess, INFINITE); } // Get its exit status. DWORD status; - BOOL rc = GetExitCodeProcess(hProcess, &status); + BOOL rc = GetExitCodeProcess(PI.ProcessHandle, &status); DWORD err = GetLastError(); + CloseHandle(PI.ProcessHandle); if (!rc) { SetLastError(err); - MakeErrMsg(ErrMsg, "Failed getting status for program."); + if (ErrMsg) + MakeErrMsg(ErrMsg, "Failed getting status for program."); + // -2 indicates a crash or timeout as opposed to failure to execute. - return -2; + WaitResult.ReturnCode = -2; + return WaitResult; } if (!status) - return 0; + return WaitResult; // Pass 10(Warning) and 11(Error) to the callee as negative value. if ((status & 0xBFFF0000U) == 0x80000000U) - return (int)status; - - if (status & 0xFF) - return status & 0x7FFFFFFF; + WaitResult.ReturnCode = static_cast<int>(status); + else if (status & 0xFF) + WaitResult.ReturnCode = status & 0x7FFFFFFF; + else + WaitResult.ReturnCode = 1; - return 1; + return WaitResult; } -error_code Program::ChangeStdinToBinary(){ +error_code sys::ChangeStdinToBinary(){ int result = _setmode( _fileno(stdin), _O_BINARY ); if (result == -1) return error_code(errno, generic_category()); return make_error_code(errc::success); } -error_code Program::ChangeStdoutToBinary(){ +error_code sys::ChangeStdoutToBinary(){ int result = _setmode( _fileno(stdout), _O_BINARY ); if (result == -1) return error_code(errno, generic_category()); return make_error_code(errc::success); } -error_code Program::ChangeStderrToBinary(){ +error_code sys::ChangeStderrToBinary(){ int result = _setmode( _fileno(stderr), _O_BINARY ); if (result == -1) return error_code(errno, generic_category()); @@ -456,5 +459,4 @@ bool llvm::sys::argumentsFitWithinSystemLimits(ArrayRef<const char*> Args) { } return true; } - } diff --git a/contrib/llvm/lib/Support/Windows/RWMutex.inc b/contrib/llvm/lib/Support/Windows/RWMutex.inc index 9593923..c431844 100644 --- a/contrib/llvm/lib/Support/Windows/RWMutex.inc +++ b/contrib/llvm/lib/Support/Windows/RWMutex.inc @@ -48,8 +48,7 @@ static bool loadSRW() { if (!sChecked) { sChecked = true; - HMODULE hLib = ::LoadLibrary(TEXT("Kernel32")); - if (hLib) { + if (HMODULE hLib = ::GetModuleHandleW(L"Kernel32.dll")) { fpInitializeSRWLock = (VOID (WINAPI *)(PSRWLOCK))::GetProcAddress(hLib, "InitializeSRWLock"); @@ -65,7 +64,6 @@ static bool loadSRW() { fpReleaseSRWLockShared = (VOID (WINAPI *)(PSRWLOCK))::GetProcAddress(hLib, "ReleaseSRWLockShared"); - ::FreeLibrary(hLib); if (fpInitializeSRWLock != NULL) { sHasSRW = true; diff --git a/contrib/llvm/lib/Support/Windows/Signals.inc b/contrib/llvm/lib/Support/Windows/Signals.inc index b18b4d1..4b40d51 100644 --- a/contrib/llvm/lib/Support/Windows/Signals.inc +++ b/contrib/llvm/lib/Support/Windows/Signals.inc @@ -11,6 +11,8 @@ // //===----------------------------------------------------------------------===// +#include "llvm/Support/FileSystem.h" + #include "Windows.h" #include <algorithm> #include <stdio.h> @@ -133,7 +135,7 @@ typedef PVOID (WINAPI *fpSymFunctionTableAccess64)(HANDLE, DWORD64); static fpSymFunctionTableAccess64 SymFunctionTableAccess64; static bool load64BitDebugHelp(void) { - HMODULE hLib = ::LoadLibrary("Dbghelp.dll"); + HMODULE hLib = ::LoadLibraryW(L"Dbghelp.dll"); if (hLib) { StackWalk64 = (fpStackWalk64) ::GetProcAddress(hLib, "StackWalk64"); @@ -158,7 +160,7 @@ static BOOL WINAPI LLVMConsoleCtrlHandler(DWORD dwCtrlType); // InterruptFunction - The function to call if ctrl-c is pressed. static void (*InterruptFunction)() = 0; -static std::vector<llvm::sys::Path> *FilesToRemove = NULL; +static std::vector<std::string> *FilesToRemove = NULL; static std::vector<std::pair<void(*)(void*), void*> > *CallBacksToRun = 0; static bool RegisteredUnhandledExceptionFilter = false; static bool CleanupExecuted = false; @@ -191,34 +193,6 @@ static int AvoidMessageBoxHook(int ReportType, char *Message, int *Return) { return TRUE; } -/// CRTReportHook - Function called on a CRT debugging event. -static int CRTReportHook(int ReportType, char *Message, int *Return) { - // Don't cause a DebugBreak() on return. - if (Return) - *Return = 0; - - switch (ReportType) { - default: - case _CRT_ASSERT: - fprintf(stderr, "CRT assert: %s\n", Message); - // FIXME: Is there a way to just crash? Perhaps throw to the unhandled - // exception code? Perhaps SetErrorMode() handles this. - _exit(3); - break; - case _CRT_ERROR: - fprintf(stderr, "CRT error: %s\n", Message); - // FIXME: Is there a way to just crash? Perhaps throw to the unhandled - // exception code? Perhaps SetErrorMode() handles this. - _exit(3); - break; - case _CRT_WARN: - fprintf(stderr, "CRT warn: %s\n", Message); - break; - } - - // Don't call _CrtDbgReport. - return TRUE; -} #endif static void RegisterHandler() { @@ -251,19 +225,10 @@ static void RegisterHandler() { OldFilter = SetUnhandledExceptionFilter(LLVMUnhandledExceptionFilter); SetConsoleCtrlHandler(LLVMConsoleCtrlHandler, TRUE); -#ifdef _MSC_VER - const char *EnableMsgbox = getenv("LLVM_ENABLE_CRT_REPORT"); - if (!EnableMsgbox || strcmp("0", EnableMsgbox) == 0) { - // Setting a report hook overrides the default behavior of popping an "abort, - // retry, or ignore" dialog. - _CrtSetReportHook(AvoidMessageBoxHook); - } -#endif - // Environment variable to disable any kind of crash dialog. if (getenv("LLVM_DISABLE_CRASH_REPORT")) { #ifdef _MSC_VER - _CrtSetReportHook(CRTReportHook); + _CrtSetReportHook(AvoidMessageBoxHook); #endif SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | @@ -276,7 +241,7 @@ static void RegisterHandler() { } // RemoveFileOnSignal - The public API -bool sys::RemoveFileOnSignal(const sys::Path &Filename, std::string* ErrMsg) { +bool sys::RemoveFileOnSignal(StringRef Filename, std::string* ErrMsg) { RegisterHandler(); if (CleanupExecuted) { @@ -286,7 +251,7 @@ bool sys::RemoveFileOnSignal(const sys::Path &Filename, std::string* ErrMsg) { } if (FilesToRemove == NULL) - FilesToRemove = new std::vector<sys::Path>; + FilesToRemove = new std::vector<std::string>; FilesToRemove->push_back(Filename); @@ -295,14 +260,14 @@ bool sys::RemoveFileOnSignal(const sys::Path &Filename, std::string* ErrMsg) { } // DontRemoveFileOnSignal - The public API -void sys::DontRemoveFileOnSignal(const sys::Path &Filename) { +void sys::DontRemoveFileOnSignal(StringRef Filename) { if (FilesToRemove == NULL) return; RegisterHandler(); FilesToRemove->push_back(Filename); - std::vector<sys::Path>::reverse_iterator I = + std::vector<std::string>::reverse_iterator I = std::find(FilesToRemove->rbegin(), FilesToRemove->rend(), Filename); if (I != FilesToRemove->rend()) FilesToRemove->erase(I.base()-1); @@ -352,7 +317,8 @@ static void Cleanup() { if (FilesToRemove != NULL) while (!FilesToRemove->empty()) { - FilesToRemove->back().eraseFromDisk(); + bool Existed; + llvm::sys::fs::remove(FilesToRemove->back(), Existed); FilesToRemove->pop_back(); } diff --git a/contrib/llvm/lib/Support/Windows/TimeValue.inc b/contrib/llvm/lib/Support/Windows/TimeValue.inc index 1227552..98b07d6 100644 --- a/contrib/llvm/lib/Support/Windows/TimeValue.inc +++ b/contrib/llvm/lib/Support/Windows/TimeValue.inc @@ -12,10 +12,11 @@ //===----------------------------------------------------------------------===// #include "Windows.h" +#include <cctype> #include <time.h> -namespace llvm { -using namespace sys; +using namespace llvm; +using namespace llvm::sys; //===----------------------------------------------------------------------===// //=== WARNING: Implementation here must contain only Win32 specific code. @@ -31,21 +32,28 @@ TimeValue TimeValue::now() { } std::string TimeValue::str() const { + struct tm *LT; #ifdef __MINGW32__ - // This ban may be lifted by either: - // (i) a future MinGW version other than 1.0 inherents the __time64_t type, or - // (ii) configure tests for either the time_t or __time64_t type. - time_t ourTime = time_t(this->toEpochTime()); - struct tm *lt = ::localtime(&ourTime); + // Old versions of mingw don't have _localtime64_s. Remove this once we drop support + // for them. + time_t OurTime = time_t(this->toEpochTime()); + LT = ::localtime(&OurTime); + assert(LT); #else - __time64_t ourTime = this->toEpochTime(); - struct tm *lt = ::_localtime64(&ourTime); + struct tm Storage; + __time64_t OurTime = this->toEpochTime(); + int Error = ::_localtime64_s(&Storage, &OurTime); + assert(!Error); + LT = &Storage; #endif - char buffer[25]; - strftime(buffer, 25, "%a %b %d %H:%M:%S %Y", lt); - return std::string(buffer); -} - - + char Buffer[25]; + // FIXME: the windows version of strftime doesn't support %e + strftime(Buffer, 25, "%b %d %H:%M %Y", LT); + assert((Buffer[3] == ' ' && isdigit(Buffer[5]) && Buffer[6] == ' ') && + "Unexpected format in strftime()!"); + // Emulate %e on %d to mute '0'. + if (Buffer[4] == '0') + Buffer[4] = ' '; + return std::string(Buffer); } diff --git a/contrib/llvm/lib/Support/Windows/Windows.h b/contrib/llvm/lib/Support/Windows/Windows.h index 5c1da0d..1f3417d 100644 --- a/contrib/llvm/lib/Support/Windows/Windows.h +++ b/contrib/llvm/lib/Support/Windows/Windows.h @@ -24,22 +24,31 @@ #define _WIN32_IE 0x0600 // MinGW at it again. #define WIN32_LEAN_AND_MEAN +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" #include "llvm/Config/config.h" // Get build system configuration settings +#include "llvm/Support/Compiler.h" +#include "llvm/Support/system_error.h" #include <windows.h> #include <wincrypt.h> -#include <shlobj.h> #include <cassert> #include <string> +#include <vector> inline bool MakeErrMsg(std::string* ErrMsg, const std::string& prefix) { if (!ErrMsg) return true; char *buffer = NULL; - FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM, - NULL, GetLastError(), 0, (LPSTR)&buffer, 1, NULL); - *ErrMsg = prefix + buffer; + DWORD R = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM, + NULL, GetLastError(), 0, (LPSTR)&buffer, 1, NULL); + if (R) + *ErrMsg = prefix + buffer; + else + *ErrMsg = prefix + "Unknown error"; + LocalFree(buffer); - return true; + return R != 0; } template <typename HandleTraits> @@ -75,7 +84,7 @@ public: } // True if Handle is valid. - operator bool() const { + LLVM_EXPLICIT operator bool() const { return HandleTraits::IsValid(Handle) ? true : false; } @@ -147,4 +156,13 @@ c_str(SmallVectorImpl<T> &str) { str.pop_back(); return str.data(); } + +namespace sys { +namespace windows { +error_code UTF8ToUTF16(StringRef utf8, + SmallVectorImpl<wchar_t> &utf16); +error_code UTF16ToUTF8(const wchar_t *utf16, size_t utf16_len, + SmallVectorImpl<char> &utf8); +} // end namespace windows +} // end namespace sys } // end namespace llvm. diff --git a/contrib/llvm/lib/Support/YAMLParser.cpp b/contrib/llvm/lib/Support/YAMLParser.cpp index 213f5e1..9495cd4 100644 --- a/contrib/llvm/lib/Support/YAMLParser.cpp +++ b/contrib/llvm/lib/Support/YAMLParser.cpp @@ -96,6 +96,15 @@ static EncodingInfo getUnicodeEncoding(StringRef Input) { namespace llvm { namespace yaml { +/// Pin the vtables to this file. +void Node::anchor() {} +void NullNode::anchor() {} +void ScalarNode::anchor() {} +void KeyValueNode::anchor() {} +void MappingNode::anchor() {} +void SequenceNode::anchor() {} +void AliasNode::anchor() {} + /// Token - A single YAML token. struct Token : ilist_node<Token> { enum TokenKind { @@ -1070,14 +1079,22 @@ bool Scanner::scanDirective() { Current = skip_while(&Scanner::skip_ns_char, Current); StringRef Name(NameStart, Current - NameStart); Current = skip_while(&Scanner::skip_s_white, Current); - + + Token T; if (Name == "YAML") { Current = skip_while(&Scanner::skip_ns_char, Current); - Token T; T.Kind = Token::TK_VersionDirective; T.Range = StringRef(Start, Current - Start); TokenQueue.push_back(T); return true; + } else if(Name == "TAG") { + Current = skip_while(&Scanner::skip_ns_char, Current); + Current = skip_while(&Scanner::skip_s_white, Current); + Current = skip_while(&Scanner::skip_ns_char, Current); + T.Kind = Token::TK_TagDirective; + T.Range = StringRef(Start, Current - Start); + TokenQueue.push_back(T); + return true; } return false; } @@ -1564,10 +1581,6 @@ void Stream::printError(Node *N, const Twine &Msg) { , Ranges); } -void Stream::handleYAMLDirective(const Token &t) { - // TODO: Ensure version is 1.x. -} - document_iterator Stream::begin() { if (CurrentDoc) report_fatal_error("Can only iterate over the stream once"); @@ -1588,14 +1601,59 @@ void Stream::skip() { i->skip(); } -Node::Node(unsigned int Type, OwningPtr<Document> &D, StringRef A) +Node::Node(unsigned int Type, OwningPtr<Document> &D, StringRef A, StringRef T) : Doc(D) , TypeID(Type) - , Anchor(A) { + , Anchor(A) + , Tag(T) { SMLoc Start = SMLoc::getFromPointer(peekNext().Range.begin()); SourceRange = SMRange(Start, Start); } +std::string Node::getVerbatimTag() const { + StringRef Raw = getRawTag(); + if (!Raw.empty() && Raw != "!") { + std::string Ret; + if (Raw.find_last_of('!') == 0) { + Ret = Doc->getTagMap().find("!")->second; + Ret += Raw.substr(1); + return llvm_move(Ret); + } else if (Raw.startswith("!!")) { + Ret = Doc->getTagMap().find("!!")->second; + Ret += Raw.substr(2); + return llvm_move(Ret); + } else { + StringRef TagHandle = Raw.substr(0, Raw.find_last_of('!') + 1); + std::map<StringRef, StringRef>::const_iterator It = + Doc->getTagMap().find(TagHandle); + if (It != Doc->getTagMap().end()) + Ret = It->second; + else { + Token T; + T.Kind = Token::TK_Tag; + T.Range = TagHandle; + setError(Twine("Unknown tag handle ") + TagHandle, T); + } + Ret += Raw.substr(Raw.find_last_of('!') + 1); + return llvm_move(Ret); + } + } + + switch (getType()) { + case NK_Null: + return "tag:yaml.org,2002:null"; + case NK_Scalar: + // TODO: Tag resolution. + return "tag:yaml.org,2002:str"; + case NK_Mapping: + return "tag:yaml.org,2002:map"; + case NK_Sequence: + return "tag:yaml.org,2002:seq"; + } + + return ""; +} + Token &Node::peekNext() { return Doc->peekNext(); } @@ -1999,6 +2057,10 @@ void SequenceNode::increment() { } Document::Document(Stream &S) : stream(S), Root(0) { + // Tag maps starts with two default mappings. + TagMap["!"] = "!"; + TagMap["!!"] = "tag:yaml.org,2002:"; + if (parseDirectives()) expectToken(Token::TK_DocumentStart); Token &T = peekNext(); @@ -2042,6 +2104,7 @@ Node *Document::parseBlockNode() { Token T = peekNext(); // Handle properties. Token AnchorInfo; + Token TagInfo; parse_property: switch (T.Kind) { case Token::TK_Alias: @@ -2056,7 +2119,11 @@ parse_property: T = peekNext(); goto parse_property; case Token::TK_Tag: - getNext(); // Skip TK_Tag. + if (TagInfo.Kind == Token::TK_Tag) { + setError("Already encountered a tag for this node!", T); + return 0; + } + TagInfo = getNext(); // Consume TK_Tag. T = peekNext(); goto parse_property; default: @@ -2070,42 +2137,49 @@ parse_property: // Don't eat the TK_BlockEntry, SequenceNode needs it. return new (NodeAllocator) SequenceNode( stream.CurrentDoc , AnchorInfo.Range.substr(1) + , TagInfo.Range , SequenceNode::ST_Indentless); case Token::TK_BlockSequenceStart: getNext(); return new (NodeAllocator) SequenceNode( stream.CurrentDoc , AnchorInfo.Range.substr(1) + , TagInfo.Range , SequenceNode::ST_Block); case Token::TK_BlockMappingStart: getNext(); return new (NodeAllocator) MappingNode( stream.CurrentDoc , AnchorInfo.Range.substr(1) + , TagInfo.Range , MappingNode::MT_Block); case Token::TK_FlowSequenceStart: getNext(); return new (NodeAllocator) SequenceNode( stream.CurrentDoc , AnchorInfo.Range.substr(1) + , TagInfo.Range , SequenceNode::ST_Flow); case Token::TK_FlowMappingStart: getNext(); return new (NodeAllocator) MappingNode( stream.CurrentDoc , AnchorInfo.Range.substr(1) + , TagInfo.Range , MappingNode::MT_Flow); case Token::TK_Scalar: getNext(); return new (NodeAllocator) ScalarNode( stream.CurrentDoc , AnchorInfo.Range.substr(1) + , TagInfo.Range , T.Range); case Token::TK_Key: // Don't eat the TK_Key, KeyValueNode expects it. return new (NodeAllocator) MappingNode( stream.CurrentDoc , AnchorInfo.Range.substr(1) + , TagInfo.Range , MappingNode::MT_Inline); case Token::TK_DocumentStart: case Token::TK_DocumentEnd: @@ -2126,10 +2200,10 @@ bool Document::parseDirectives() { while (true) { Token T = peekNext(); if (T.Kind == Token::TK_TagDirective) { - handleTagDirective(getNext()); + parseTAGDirective(); isDirective = true; } else if (T.Kind == Token::TK_VersionDirective) { - stream.handleYAMLDirective(getNext()); + parseYAMLDirective(); isDirective = true; } else break; @@ -2137,6 +2211,21 @@ bool Document::parseDirectives() { return isDirective; } +void Document::parseYAMLDirective() { + getNext(); // Eat %YAML <version> +} + +void Document::parseTAGDirective() { + Token Tag = getNext(); // %TAG <handle> <prefix> + StringRef T = Tag.Range; + // Strip %TAG + T = T.substr(T.find_first_of(" \t")).ltrim(" \t"); + std::size_t HandleEnd = T.find_first_of(" \t"); + StringRef TagHandle = T.substr(0, HandleEnd); + StringRef TagPrefix = T.substr(HandleEnd).ltrim(" \t"); + TagMap[TagHandle] = TagPrefix; +} + bool Document::expectToken(int TK) { Token T = getNext(); if (T.Kind != TK) { diff --git a/contrib/llvm/lib/Support/YAMLTraits.cpp b/contrib/llvm/lib/Support/YAMLTraits.cpp index 9da2aa7..42bff96 100644 --- a/contrib/llvm/lib/Support/YAMLTraits.cpp +++ b/contrib/llvm/lib/Support/YAMLTraits.cpp @@ -15,6 +15,7 @@ #include "llvm/Support/YAMLParser.h" #include "llvm/Support/raw_ostream.h" #include <cstring> +#include <cctype> using namespace llvm; using namespace yaml; @@ -40,32 +41,43 @@ void IO::setContext(void *Context) { // Input //===----------------------------------------------------------------------===// -Input::Input(StringRef InputContent, void *Ctxt) - : IO(Ctxt), +Input::Input(StringRef InputContent, + void *Ctxt, + SourceMgr::DiagHandlerTy DiagHandler, + void *DiagHandlerCtxt) + : IO(Ctxt), Strm(new Stream(InputContent, SrcMgr)), CurrentNode(NULL) { + if (DiagHandler) + SrcMgr.setDiagHandler(DiagHandler, DiagHandlerCtxt); DocIterator = Strm->begin(); } Input::~Input() { - } error_code Input::error() { return EC; } -void Input::setDiagHandler(SourceMgr::DiagHandlerTy Handler, void *Ctxt) { - SrcMgr.setDiagHandler(Handler, Ctxt); -} +// Pin the vtables to this file. +void Input::HNode::anchor() {} +void Input::EmptyHNode::anchor() {} +void Input::ScalarHNode::anchor() {} -bool Input::outputting() { +bool Input::outputting() const { return false; } bool Input::setCurrentDocument() { if (DocIterator != Strm->end()) { Node *N = DocIterator->getRoot(); + if (!N) { + assert(Strm->failed() && "Root is NULL iff parsing failed"); + EC = make_error_code(errc::invalid_argument); + return false; + } + if (isa<NullNode>(N)) { // Empty files are allowed and ignored ++DocIterator; @@ -82,10 +94,21 @@ void Input::nextDocument() { ++DocIterator; } +bool Input::mapTag(StringRef Tag, bool Default) { + std::string foundTag = CurrentNode->_node->getVerbatimTag(); + if (foundTag.empty()) { + // If no tag found and 'Tag' is the default, say it was found. + return Default; + } + // Return true iff found tag matches supplied tag. + return Tag.equals(foundTag); +} + void Input::beginMapping() { if (EC) return; - MapHNode *MN = dyn_cast<MapHNode>(CurrentNode); + // CurrentNode can be null if the document is empty. + MapHNode *MN = dyn_cast_or_null<MapHNode>(CurrentNode); if (MN) { MN->ValidKeys.clear(); } @@ -96,6 +119,15 @@ bool Input::preflightKey(const char *Key, bool Required, bool, bool &UseDefault, UseDefault = false; if (EC) return false; + + // CurrentNode is null for empty documents, which is an error in case required + // nodes are present. + if (!CurrentNode) { + if (Required) + EC = make_error_code(errc::invalid_argument); + return false; + } + MapHNode *MN = dyn_cast<MapHNode>(CurrentNode); if (!MN) { setError(CurrentNode, "not a mapping"); @@ -122,13 +154,14 @@ void Input::postflightKey(void *saveInfo) { void Input::endMapping() { if (EC) return; - MapHNode *MN = dyn_cast<MapHNode>(CurrentNode); + // CurrentNode can be null if the document is empty. + MapHNode *MN = dyn_cast_or_null<MapHNode>(CurrentNode); if (!MN) return; for (MapHNode::NameToNode::iterator i = MN->Mapping.begin(), End = MN->Mapping.end(); i != End; ++i) { - if (!MN->isValidKey(i->first)) { - setError(i->second, Twine("unknown key '") + i->first + "'"); + if (!MN->isValidKey(i->first())) { + setError(i->second, Twine("unknown key '") + i->first() + "'"); break; } } @@ -263,6 +296,7 @@ void Input::scalarString(StringRef &S) { } void Input::setError(HNode *hnode, const Twine &message) { + assert(hnode && "HNode must not be NULL"); this->setError(hnode->_node, message); } @@ -322,7 +356,7 @@ Input::HNode *Input::createHNodes(Node *N) { } bool Input::MapHNode::isValidKey(StringRef Key) { - for (SmallVector<const char *, 6>::iterator i = ValidKeys.begin(), + for (SmallVectorImpl<const char *>::iterator i = ValidKeys.begin(), End = ValidKeys.end(); i != End; ++i) { if (Key.equals(*i)) return true; @@ -334,6 +368,10 @@ void Input::setError(const Twine &Message) { this->setError(CurrentNode, Message); } +bool Input::canElideEmptySequence() { + return false; +} + Input::MapHNode::~MapHNode() { for (MapHNode::NameToNode::iterator i = Mapping.begin(), End = Mapping.end(); i != End; ++i) { @@ -368,7 +406,7 @@ Output::Output(raw_ostream &yout, void *context) Output::~Output() { } -bool Output::outputting() { +bool Output::outputting() const { return true; } @@ -377,6 +415,14 @@ void Output::beginMapping() { NeedsNewLine = true; } +bool Output::mapTag(StringRef Tag, bool Use) { + if (Use) { + this->output(" "); + this->output(Tag); + } + return Use; +} + void Output::endMapping() { StateStack.pop_back(); } @@ -505,9 +551,20 @@ void Output::endBitSetScalar() { } void Output::scalarString(StringRef &S) { + const char ScalarSafeChars[] = "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-/^., \t"; + this->newLineCheck(); - if (S.find('\n') == StringRef::npos) { - // No embedded new-line chars, just print string. + if (S.empty()) { + // Print '' for the empty string because leaving the field empty is not + // allowed. + this->outputUpToEndOfLine("''"); + return; + } + if (S.find_first_not_of(ScalarSafeChars) == StringRef::npos && + !isspace(S.front()) && !isspace(S.back())) { + // If the string consists only of safe characters, print it out without + // quotes. this->outputUpToEndOfLine(S); return; } @@ -532,6 +589,19 @@ void Output::scalarString(StringRef &S) { void Output::setError(const Twine &message) { } +bool Output::canElideEmptySequence() { + // Normally, with an optional key/value where the value is an empty sequence, + // the whole key/value can be not written. But, that produces wrong yaml + // if the key/value is the only thing in the map and the map is used in + // a sequence. This detects if the this sequence is the first key/value + // in map that itself is embedded in a sequnce. + if (StateStack.size() < 2) + return true; + if (StateStack.back() != inMapFirstKey) + return true; + return (StateStack[StateStack.size()-2] != inSeq); +} + void Output::output(StringRef s) { Column += s.size(); Out << s; diff --git a/contrib/llvm/lib/Support/raw_ostream.cpp b/contrib/llvm/lib/Support/raw_ostream.cpp index a433088..cb96489 100644 --- a/contrib/llvm/lib/Support/raw_ostream.cpp +++ b/contrib/llvm/lib/Support/raw_ostream.cpp @@ -18,6 +18,7 @@ #include "llvm/Config/config.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/FileSystem.h" #include "llvm/Support/Format.h" #include "llvm/Support/Process.h" #include "llvm/Support/Program.h" @@ -25,14 +26,15 @@ #include <cctype> #include <cerrno> #include <sys/stat.h> -#include <sys/types.h> -#if defined(HAVE_UNISTD_H) -# include <unistd.h> -#endif +// <fcntl.h> may provide O_BINARY. #if defined(HAVE_FCNTL_H) # include <fcntl.h> #endif + +#if defined(HAVE_UNISTD_H) +# include <unistd.h> +#endif #if defined(HAVE_SYS_UIO_H) && defined(HAVE_WRITEV) # include <sys/uio.h> #endif @@ -43,7 +45,6 @@ #if defined(_MSC_VER) #include <io.h> -#include <fcntl.h> #ifndef STDIN_FILENO # define STDIN_FILENO 0 #endif @@ -424,14 +425,9 @@ void format_object_base::home() { /// stream should be immediately destroyed; the string will be empty /// if no error occurred. raw_fd_ostream::raw_fd_ostream(const char *Filename, std::string &ErrorInfo, - unsigned Flags) - : Error(false), UseAtomicWrites(false), pos(0) -{ + sys::fs::OpenFlags Flags) + : Error(false), UseAtomicWrites(false), pos(0) { assert(Filename != 0 && "Filename is null"); - // Verify that we don't have both "append" and "excl". - assert((!(Flags & F_Excl) || !(Flags & F_Append)) && - "Cannot specify both 'excl' and 'append' file creation flags!"); - ErrorInfo.clear(); // Handle "-" as stdout. Note that when we do this, we consider ourself @@ -441,32 +437,20 @@ raw_fd_ostream::raw_fd_ostream(const char *Filename, std::string &ErrorInfo, FD = STDOUT_FILENO; // If user requested binary then put stdout into binary mode if // possible. - if (Flags & F_Binary) - sys::Program::ChangeStdoutToBinary(); + if (Flags & sys::fs::F_Binary) + sys::ChangeStdoutToBinary(); // Close stdout when we're done, to detect any output errors. ShouldClose = true; return; } - int OpenFlags = O_WRONLY|O_CREAT; -#ifdef O_BINARY - if (Flags & F_Binary) - OpenFlags |= O_BINARY; -#endif - - if (Flags & F_Append) - OpenFlags |= O_APPEND; - else - OpenFlags |= O_TRUNC; - if (Flags & F_Excl) - OpenFlags |= O_EXCL; + error_code EC = sys::fs::openFileForWrite(Filename, FD, Flags); - while ((FD = open(Filename, OpenFlags, 0664)) < 0) { - if (errno != EINTR) { - ErrorInfo = "Error opening output file '" + std::string(Filename) + "'"; - ShouldClose = false; - return; - } + if (EC) { + ErrorInfo = "Error opening output file '" + std::string(Filename) + "': " + + EC.message(); + ShouldClose = false; + return; } // Ok, we successfully opened the file, so it'll need to be closed. |