Bug 1379983 - Part 1: Move InlineCharBuffer to top of file. r=jandem

--HG--
extra : rebase_source : 70c989d42130ed9a65cab4fe20b438d949d58128
This commit is contained in:
André Bargull 2017-07-12 07:35:05 -07:00
Родитель f746a86c3e
Коммит 3be3eaa5d7
1 изменённых файлов: 119 добавлений и 119 удалений

Просмотреть файл

@ -87,6 +87,125 @@ ArgToRootedString(JSContext* cx, const CallArgs& args, unsigned argno)
return str->ensureLinear(cx);
}
template <typename CharT> struct MaximumInlineLength;
template<> struct MaximumInlineLength<Latin1Char> {
static constexpr size_t value = JSFatInlineString::MAX_LENGTH_LATIN1;
};
template<> struct MaximumInlineLength<char16_t> {
static constexpr size_t value = JSFatInlineString::MAX_LENGTH_TWO_BYTE;
};
// Character buffer class used for ToLowerCase and ToUpperCase operations.
//
// Case conversion operations normally return a string with the same length as
// the input string. To avoid over-allocation, we optimistically allocate an
// array with same size as the input string and only when we detect special
// casing characters, which can change the output string length, we reallocate
// the output buffer to the final string length.
//
// As a further mean to improve runtime performance, the character buffer
// contains an inline storage, so we don't need to heap-allocate an array when
// a JSInlineString will be used for the output string.
//
// Why not use mozilla::Vector instead? mozilla::Vector doesn't provide enough
// fine-grained control to avoid over-allocation when (re)allocating for exact
// buffer sizes. This led to visible performance regressions in µ-benchmarks.
template <typename CharT>
class MOZ_NON_PARAM InlineCharBuffer
{
using CharPtr = UniquePtr<CharT[], JS::FreePolicy>;
static constexpr size_t InlineCapacity = MaximumInlineLength<CharT>::value;
CharT inlineStorage[InlineCapacity];
CharPtr heapStorage;
#ifdef DEBUG
// In debug mode, we keep track of the requested string lengths to ensure
// all character buffer methods are called in the correct order and with
// the expected argument values.
size_t lastRequestedLength = 0;
void assertValidRequest(size_t expectedLastLength, size_t length) {
MOZ_ASSERT(length > expectedLastLength, "cannot shrink requested length");
MOZ_ASSERT(lastRequestedLength == expectedLastLength);
lastRequestedLength = length;
}
#else
void assertValidRequest(size_t expectedLastLength, size_t length) {}
#endif
public:
CharT* get()
{
return heapStorage ? heapStorage.get() : inlineStorage;
}
bool maybeAlloc(JSContext* cx, size_t length)
{
assertValidRequest(0, length);
if (length <= InlineCapacity)
return true;
MOZ_ASSERT(!heapStorage, "heap storage already allocated");
heapStorage = cx->make_pod_array<CharT>(length + 1);
return !!heapStorage;
}
bool maybeRealloc(JSContext* cx, size_t oldLength, size_t newLength)
{
assertValidRequest(oldLength, newLength);
if (newLength <= InlineCapacity)
return true;
if (!heapStorage) {
heapStorage = cx->make_pod_array<CharT>(newLength + 1);
if (!heapStorage)
return false;
MOZ_ASSERT(oldLength <= InlineCapacity);
PodCopy(heapStorage.get(), inlineStorage, oldLength);
return true;
}
CharT* oldChars = heapStorage.release();
CharT* newChars = cx->pod_realloc(oldChars, oldLength + 1, newLength + 1);
if (!newChars) {
js_free(oldChars);
return false;
}
heapStorage.reset(newChars);
return true;
}
JSString* toString(JSContext* cx, size_t length)
{
MOZ_ASSERT(length == lastRequestedLength);
if (JSInlineString::lengthFits<CharT>(length)) {
MOZ_ASSERT(!heapStorage,
"expected only inline storage when length fits in inline string");
mozilla::Range<const CharT> range(inlineStorage, length);
return NewInlineString<CanGC>(cx, range);
}
MOZ_ASSERT(heapStorage, "heap storage was not allocated for non-inline string");
heapStorage.get()[length] = '\0'; // Null-terminate
JSString* res = NewStringDontDeflate<CanGC>(cx, heapStorage.get(), length);
if (!res)
return nullptr;
mozilla::Unused << heapStorage.release();
return res;
}
};
/*
* Forward declarations for URI encode/decode and helper routines
*/
@ -603,125 +722,6 @@ js::SubstringKernel(JSContext* cx, HandleString str, int32_t beginInt, int32_t l
return NewDependentString(cx, str, begin, len);
}
template <typename CharT> struct MaximumInlineLength;
template<> struct MaximumInlineLength<Latin1Char> {
static constexpr size_t value = JSFatInlineString::MAX_LENGTH_LATIN1;
};
template<> struct MaximumInlineLength<char16_t> {
static constexpr size_t value = JSFatInlineString::MAX_LENGTH_TWO_BYTE;
};
// Character buffer class used for ToLowerCase and ToUpperCase operations.
//
// Case conversion operations normally return a string with the same length as
// the input string. To avoid over-allocation, we optimistically allocate an
// array with same size as the input string and only when we detect special
// casing characters, which can change the output string length, we reallocate
// the output buffer to the final string length.
//
// As a further mean to improve runtime performance, the character buffer
// contains an inline storage, so we don't need to heap-allocate an array when
// a JSInlineString will be used for the output string.
//
// Why not use mozilla::Vector instead? mozilla::Vector doesn't provide enough
// fine-grained control to avoid over-allocation when (re)allocating for exact
// buffer sizes. This led to visible performance regressions in µ-benchmarks.
template <typename CharT>
class MOZ_NON_PARAM InlineCharBuffer
{
using CharPtr = UniquePtr<CharT[], JS::FreePolicy>;
static constexpr size_t InlineCapacity = MaximumInlineLength<CharT>::value;
CharT inlineStorage[InlineCapacity];
CharPtr heapStorage;
#ifdef DEBUG
// In debug mode, we keep track of the requested string lengths to ensure
// all character buffer methods are called in the correct order and with
// the expected argument values.
size_t lastRequestedLength = 0;
void assertValidRequest(size_t expectedLastLength, size_t length) {
MOZ_ASSERT(length > expectedLastLength, "cannot shrink requested length");
MOZ_ASSERT(lastRequestedLength == expectedLastLength);
lastRequestedLength = length;
}
#else
void assertValidRequest(size_t expectedLastLength, size_t length) {}
#endif
public:
CharT* get()
{
return heapStorage ? heapStorage.get() : inlineStorage;
}
bool maybeAlloc(JSContext* cx, size_t length)
{
assertValidRequest(0, length);
if (length <= InlineCapacity)
return true;
MOZ_ASSERT(!heapStorage, "heap storage already allocated");
heapStorage = cx->make_pod_array<CharT>(length + 1);
return !!heapStorage;
}
bool maybeRealloc(JSContext* cx, size_t oldLength, size_t newLength)
{
assertValidRequest(oldLength, newLength);
if (newLength <= InlineCapacity)
return true;
if (!heapStorage) {
heapStorage = cx->make_pod_array<CharT>(newLength + 1);
if (!heapStorage)
return false;
MOZ_ASSERT(oldLength <= InlineCapacity);
PodCopy(heapStorage.get(), inlineStorage, oldLength);
return true;
}
CharT* oldChars = heapStorage.release();
CharT* newChars = cx->pod_realloc(oldChars, oldLength + 1, newLength + 1);
if (!newChars) {
js_free(oldChars);
return false;
}
heapStorage.reset(newChars);
return true;
}
JSString* toString(JSContext* cx, size_t length)
{
MOZ_ASSERT(length == lastRequestedLength);
if (JSInlineString::lengthFits<CharT>(length)) {
MOZ_ASSERT(!heapStorage,
"expected only inline storage when length fits in inline string");
mozilla::Range<const CharT> range(inlineStorage, length);
return NewInlineString<CanGC>(cx, range);
}
MOZ_ASSERT(heapStorage, "heap storage was not allocated for non-inline string");
heapStorage.get()[length] = '\0'; // Null-terminate
JSString* res = NewStringDontDeflate<CanGC>(cx, heapStorage.get(), length);
if (!res)
return nullptr;
mozilla::Unused << heapStorage.release();
return res;
}
};
/**
* U+03A3 GREEK CAPITAL LETTER SIGMA has two different lower case mappings
* depending on its context: