Bug 1539605 - add fast paths for integer formatting on nsTSubstring; r=erahm

This way we don't have to go through a bunch of printf nonsense, and we
ought to be able to arrive at optimized routines that take advantage of
constant radices, etc.

Differential Revision: https://phabricator.services.mozilla.com/D25141

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Nathan Froyd 2019-03-29 19:38:53 +00:00
parent 20b6a59a5e
commit dc25b5a9dc
4 changed files with 173 additions and 18 deletions

View File

@ -72,6 +72,9 @@ typedef mozilla::Vector<NumArgState, 20, mozilla::MallocAllocPolicy>
#define FLAG_ZEROS 0x8
#define FLAG_NEG 0x10
static const char hex[] = "0123456789abcdef";
static const char HEX[] = "0123456789ABCDEF";
// Fill into the buffer using the data in src
bool mozilla::PrintfTarget::fill2(const char* src, int srclen, int width,
int flags) {
@ -167,6 +170,55 @@ bool mozilla::PrintfTarget::fill_n(const char* src, int srclen, int width,
return true;
}
// All that the cvt_* functions care about as far as the TYPE_* constants is
// that the low bit is set to indicate unsigned, or unset to indicate signed.
// So we don't try to hard to ensure that the passed TYPE_* constant lines
// up with the actual size of the number being printed here. The main printf
// code, below, does have to care so that the correct bits are extracted from
// the varargs list.
bool mozilla::PrintfTarget::appendIntDec(int32_t num) {
int flags = 0;
long n = num;
if (n < 0) {
n = -n;
flags |= FLAG_NEG;
}
return cvt_l(n, -1, -1, 10, TYPE_INTN, flags, hex);
}
bool mozilla::PrintfTarget::appendIntDec(uint32_t num) {
return cvt_l(num, -1, -1, 10, TYPE_UINTN, 0, hex);
}
bool mozilla::PrintfTarget::appendIntOct(uint32_t num) {
return cvt_l(num, -1, -1, 8, TYPE_UINTN, 0, hex);
}
bool mozilla::PrintfTarget::appendIntHex(uint32_t num) {
return cvt_l(num, -1, -1, 16, TYPE_UINTN, 0, hex);
}
bool mozilla::PrintfTarget::appendIntDec(int64_t num) {
int flags = 0;
if (num < 0) {
num = -num;
flags |= FLAG_NEG;
}
return cvt_ll(num, -1, -1, 10, TYPE_INTN, flags, hex);
}
bool mozilla::PrintfTarget::appendIntDec(uint64_t num) {
return cvt_ll(num, -1, -1, 10, TYPE_UINTN, 0, hex);
}
bool mozilla::PrintfTarget::appendIntOct(uint64_t num) {
return cvt_ll(num, -1, -1, 8, TYPE_UINTN, 0, hex);
}
bool mozilla::PrintfTarget::appendIntHex(uint64_t num) {
return cvt_ll(num, -1, -1, 16, TYPE_UINTN, 0, hex);
}
/* Convert a long into its printable form. */
bool mozilla::PrintfTarget::cvt_l(long num, int width, int prec, int radix,
int type, int flags, const char* hexp) {
@ -562,8 +614,6 @@ bool mozilla::PrintfTarget::vprint(const char* fmt, va_list ap) {
#endif
} u;
const char* fmt0;
static const char hex[] = "0123456789abcdef";
static const char HEX[] = "0123456789ABCDEF";
const char* hexp;
int i;
char pattern[20];

View File

@ -76,6 +76,18 @@ class PrintfTarget {
/* The Vprintf-like interface. */
bool MFBT_API vprint(const char* format, va_list) MOZ_FORMAT_PRINTF(2, 0);
/* Fast paths for formatting integers as though by %d, %o, %u, or %x.
Since octal and hex formatting always treat numbers as unsigned, there
are no signed overloads for AppendInt{Oct,Hex}. */
bool MFBT_API appendIntDec(int32_t);
bool MFBT_API appendIntDec(uint32_t);
bool MFBT_API appendIntOct(uint32_t);
bool MFBT_API appendIntHex(uint32_t);
bool MFBT_API appendIntDec(int64_t);
bool MFBT_API appendIntDec(uint64_t);
bool MFBT_API appendIntOct(uint64_t);
bool MFBT_API appendIntHex(uint64_t);
protected:
MFBT_API PrintfTarget();
virtual ~PrintfTarget() {}

View File

@ -1221,6 +1221,78 @@ void nsTSubstring<T>::AppendPrintf(const char* aFormat, va_list aAp) {
}
}
template <typename T>
void nsTSubstring<T>::AppendIntDec(int32_t aInteger) {
PrintfAppend<T> appender(this);
bool r = appender.appendIntDec(aInteger);
if (MOZ_UNLIKELY(!r)) {
MOZ_CRASH("Allocation or other failure while appending integers");
}
}
template <typename T>
void nsTSubstring<T>::AppendIntDec(uint32_t aInteger) {
PrintfAppend<T> appender(this);
bool r = appender.appendIntDec(aInteger);
if (MOZ_UNLIKELY(!r)) {
MOZ_CRASH("Allocation or other failure while appending integers");
}
}
template <typename T>
void nsTSubstring<T>::AppendIntOct(uint32_t aInteger) {
PrintfAppend<T> appender(this);
bool r = appender.appendIntOct(aInteger);
if (MOZ_UNLIKELY(!r)) {
MOZ_CRASH("Allocation or other failure while appending integers");
}
}
template <typename T>
void nsTSubstring<T>::AppendIntHex(uint32_t aInteger) {
PrintfAppend<T> appender(this);
bool r = appender.appendIntHex(aInteger);
if (MOZ_UNLIKELY(!r)) {
MOZ_CRASH("Allocation or other failure while appending integers");
}
}
template <typename T>
void nsTSubstring<T>::AppendIntDec(int64_t aInteger) {
PrintfAppend<T> appender(this);
bool r = appender.appendIntDec(aInteger);
if (MOZ_UNLIKELY(!r)) {
MOZ_CRASH("Allocation or other failure while appending integers");
}
}
template <typename T>
void nsTSubstring<T>::AppendIntDec(uint64_t aInteger) {
PrintfAppend<T> appender(this);
bool r = appender.appendIntDec(aInteger);
if (MOZ_UNLIKELY(!r)) {
MOZ_CRASH("Allocation or other failure while appending integers");
}
}
template <typename T>
void nsTSubstring<T>::AppendIntOct(uint64_t aInteger) {
PrintfAppend<T> appender(this);
bool r = appender.appendIntOct(aInteger);
if (MOZ_UNLIKELY(!r)) {
MOZ_CRASH("Allocation or other failure while appending integers");
}
}
template <typename T>
void nsTSubstring<T>::AppendIntHex(uint64_t aInteger) {
PrintfAppend<T> appender(this);
bool r = appender.appendIntHex(aInteger);
if (MOZ_UNLIKELY(!r)) {
MOZ_CRASH("Allocation or other failure while appending integers");
}
}
// Returns the length of the formatted aDouble in aBuf.
static int FormatWithoutTrailingZeros(char (&aBuf)[40], double aDouble,
int aPrecision) {

View File

@ -656,37 +656,58 @@ class nsTSubstring : public mozilla::detail::nsTStringRepr<T> {
*/
void AppendPrintf(const char* aFormat, ...) MOZ_FORMAT_PRINTF(2, 3);
void AppendPrintf(const char* aFormat, va_list aAp) MOZ_FORMAT_PRINTF(2, 0);
void AppendInt(int32_t aInteger) { AppendPrintf("%" PRId32, aInteger); }
void AppendInt(int32_t aInteger) { AppendIntDec(aInteger); }
void AppendInt(int32_t aInteger, int aRadix) {
if (aRadix == 10) {
AppendPrintf("%" PRId32, aInteger);
AppendIntDec(aInteger);
} else if (aRadix == 8) {
AppendIntOct(static_cast<uint32_t>(aInteger));
} else {
AppendPrintf(aRadix == 8 ? "%" PRIo32 : "%" PRIx32,
static_cast<uint32_t>(aInteger));
AppendIntHex(static_cast<uint32_t>(aInteger));
}
}
void AppendInt(uint32_t aInteger) { AppendPrintf("%" PRIu32, aInteger); }
void AppendInt(uint32_t aInteger) { AppendIntDec(aInteger); }
void AppendInt(uint32_t aInteger, int aRadix) {
AppendPrintf(
aRadix == 10 ? "%" PRIu32 : aRadix == 8 ? "%" PRIo32 : "%" PRIx32,
aInteger);
if (aRadix == 10) {
AppendIntDec(aInteger);
} else if (aRadix == 8) {
AppendIntOct(aInteger);
} else {
AppendIntHex(aInteger);
}
}
void AppendInt(int64_t aInteger) { AppendPrintf("%" PRId64, aInteger); }
void AppendInt(int64_t aInteger) { AppendIntDec(aInteger); }
void AppendInt(int64_t aInteger, int aRadix) {
if (aRadix == 10) {
AppendPrintf("%" PRId64, aInteger);
AppendIntDec(aInteger);
} else if (aRadix == 8) {
AppendIntOct(static_cast<uint64_t>(aInteger));
} else {
AppendPrintf(aRadix == 8 ? "%" PRIo64 : "%" PRIx64,
static_cast<uint64_t>(aInteger));
AppendIntHex(static_cast<uint64_t>(aInteger));
}
}
void AppendInt(uint64_t aInteger) { AppendPrintf("%" PRIu64, aInteger); }
void AppendInt(uint64_t aInteger) { AppendIntDec(aInteger); }
void AppendInt(uint64_t aInteger, int aRadix) {
AppendPrintf(
aRadix == 10 ? "%" PRIu64 : aRadix == 8 ? "%" PRIo64 : "%" PRIx64,
aInteger);
if (aRadix == 10) {
AppendIntDec(aInteger);
} else if (aRadix == 8) {
AppendIntOct(aInteger);
} else {
AppendIntHex(aInteger);
}
}
private:
void AppendIntDec(int32_t);
void AppendIntDec(uint32_t);
void AppendIntOct(uint32_t);
void AppendIntHex(uint32_t);
void AppendIntDec(int64_t);
void AppendIntDec(uint64_t);
void AppendIntOct(uint64_t);
void AppendIntHex(uint64_t);
public:
/**
* Append the given float to this string
*/