зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1379983 - Part 1: Move InlineCharBuffer to top of file. r=jandem
--HG-- extra : rebase_source : 70c989d42130ed9a65cab4fe20b438d949d58128
This commit is contained in:
Родитель
f746a86c3e
Коммит
3be3eaa5d7
238
js/src/jsstr.cpp
238
js/src/jsstr.cpp
|
@ -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:
|
||||
|
|
Загрузка…
Ссылка в новой задаче