From 95d7656f60484e9815df47dbf3000f643020378d Mon Sep 17 00:00:00 2001 From: Sebastian Hengst Date: Thu, 13 Jul 2017 13:27:35 +0200 Subject: [PATCH] Backed out changeset d7a872ed8840 (bug 1379983) for failing xpcshell's toolkit/components/osfile/tests/xpcshell/test_available_free_space.js on Linux debug. r=backout --- js/src/jsstr.cpp | 238 +++++++++++++++++++++++------------------------ 1 file changed, 119 insertions(+), 119 deletions(-) diff --git a/js/src/jsstr.cpp b/js/src/jsstr.cpp index 108fef529fe0..7c0756704f36 100644 --- a/js/src/jsstr.cpp +++ b/js/src/jsstr.cpp @@ -87,125 +87,6 @@ ArgToRootedString(JSContext* cx, const CallArgs& args, unsigned argno) return str->ensureLinear(cx); } -template struct MaximumInlineLength; - -template<> struct MaximumInlineLength { - static constexpr size_t value = JSFatInlineString::MAX_LENGTH_LATIN1; -}; - -template<> struct MaximumInlineLength { - 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 -class MOZ_NON_PARAM InlineCharBuffer -{ - using CharPtr = UniquePtr; - static constexpr size_t InlineCapacity = MaximumInlineLength::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(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(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(length)) { - MOZ_ASSERT(!heapStorage, - "expected only inline storage when length fits in inline string"); - - mozilla::Range range(inlineStorage, length); - return NewInlineString(cx, range); - } - - MOZ_ASSERT(heapStorage, "heap storage was not allocated for non-inline string"); - - heapStorage.get()[length] = '\0'; // Null-terminate - JSString* res = NewStringDontDeflate(cx, heapStorage.get(), length); - if (!res) - return nullptr; - - mozilla::Unused << heapStorage.release(); - return res; - } -}; - /* * Forward declarations for URI encode/decode and helper routines */ @@ -722,6 +603,125 @@ js::SubstringKernel(JSContext* cx, HandleString str, int32_t beginInt, int32_t l return NewDependentString(cx, str, begin, len); } +template struct MaximumInlineLength; + +template<> struct MaximumInlineLength { + static constexpr size_t value = JSFatInlineString::MAX_LENGTH_LATIN1; +}; + +template<> struct MaximumInlineLength { + 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 +class MOZ_NON_PARAM InlineCharBuffer +{ + using CharPtr = UniquePtr; + static constexpr size_t InlineCapacity = MaximumInlineLength::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(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(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(length)) { + MOZ_ASSERT(!heapStorage, + "expected only inline storage when length fits in inline string"); + + mozilla::Range range(inlineStorage, length); + return NewInlineString(cx, range); + } + + MOZ_ASSERT(heapStorage, "heap storage was not allocated for non-inline string"); + + heapStorage.get()[length] = '\0'; // Null-terminate + JSString* res = NewStringDontDeflate(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: