diff options
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. |