зеркало из 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);
|
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
|
* 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);
|
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
|
* U+03A3 GREEK CAPITAL LETTER SIGMA has two different lower case mappings
|
||||||
* depending on its context:
|
* depending on its context:
|
||||||
|
|
Загрузка…
Ссылка в новой задаче