forked from mirrors/gecko-dev
Bug 1576076 - Part 2: Support Latin1Char in JSExternalString. r=sfink
Adds: * JS_NewExternalStringLatin1 * JS_NewMaybeExternalStringLatin1 * IsExternalStringLatin1 * latin1 methods for JSExternalStringCallbacks Differential Revision: https://phabricator.services.mozilla.com/D194673
This commit is contained in:
parent
7cc22c161b
commit
8101d8a476
11 changed files with 313 additions and 40 deletions
|
|
@ -556,9 +556,11 @@ using JSHostCleanupFinalizationRegistryCallback =
|
|||
*/
|
||||
struct JSExternalStringCallbacks {
|
||||
/**
|
||||
* Finalizes external strings created by JS_NewExternalUCString. The finalizer
|
||||
* can be called off the main thread.
|
||||
* Finalizes external strings created by JS_NewExternalStringLatin1 or
|
||||
* JS_NewExternalUCString. The finalizer can be called off the main
|
||||
* thread.
|
||||
*/
|
||||
virtual void finalize(JS::Latin1Char* chars) const = 0;
|
||||
virtual void finalize(char16_t* chars) const = 0;
|
||||
|
||||
/**
|
||||
|
|
@ -569,6 +571,8 @@ struct JSExternalStringCallbacks {
|
|||
*
|
||||
* Implementations of this callback MUST NOT do anything that can cause GC.
|
||||
*/
|
||||
virtual size_t sizeOfBuffer(const JS::Latin1Char* chars,
|
||||
mozilla::MallocSizeOf mallocSizeOf) const = 0;
|
||||
virtual size_t sizeOfBuffer(const char16_t* chars,
|
||||
mozilla::MallocSizeOf mallocSizeOf) const = 0;
|
||||
};
|
||||
|
|
@ -1269,6 +1273,9 @@ extern JS_PUBLIC_API void JS_SetGCParametersBasedOnAvailableMemory(
|
|||
* Create a new JSString whose chars member refers to external memory, i.e.,
|
||||
* memory requiring application-specific finalization.
|
||||
*/
|
||||
extern JS_PUBLIC_API JSString* JS_NewExternalStringLatin1(
|
||||
JSContext* cx, const JS::Latin1Char* chars, size_t length,
|
||||
const JSExternalStringCallbacks* callbacks);
|
||||
extern JS_PUBLIC_API JSString* JS_NewExternalUCString(
|
||||
JSContext* cx, const char16_t* chars, size_t length,
|
||||
const JSExternalStringCallbacks* callbacks);
|
||||
|
|
@ -1280,13 +1287,17 @@ extern JS_PUBLIC_API JSString* JS_NewExternalUCString(
|
|||
* external string allocated by a previous call and |*allocatedExternal| is set
|
||||
* to false. If |*allocatedExternal| is false, |fin| won't be called.
|
||||
*/
|
||||
extern JS_PUBLIC_API JSString* JS_NewMaybeExternalStringLatin1(
|
||||
JSContext* cx, const JS::Latin1Char* chars, size_t length,
|
||||
const JSExternalStringCallbacks* callbacks, bool* allocatedExternal);
|
||||
extern JS_PUBLIC_API JSString* JS_NewMaybeExternalUCString(
|
||||
JSContext* cx, const char16_t* chars, size_t length,
|
||||
const JSExternalStringCallbacks* callbacks, bool* allocatedExternal);
|
||||
|
||||
/**
|
||||
* Return the 'callbacks' arg passed to JS_NewExternalUCString or
|
||||
* JS_NewMaybeExternalUCString.
|
||||
* Return the 'callbacks' arg passed to JS_NewExternalStringLatin1,
|
||||
* JS_NewExternalUCString, JS_NewMaybeExternalStringLatin1,
|
||||
* or JS_NewMaybeExternalUCString.
|
||||
*/
|
||||
extern JS_PUBLIC_API const JSExternalStringCallbacks*
|
||||
JS_GetExternalStringCallbacks(JSString* str);
|
||||
|
|
|
|||
|
|
@ -392,17 +392,37 @@ MOZ_ALWAYS_INLINE JSLinearString* AtomToLinearString(JSAtom* atom) {
|
|||
}
|
||||
|
||||
/**
|
||||
* If the provided string uses externally-managed storage, return true and set
|
||||
* |*callbacks| to the external-string callbacks used to create it and |*chars|
|
||||
* to a pointer to its two-byte storage. (These pointers remain valid as long
|
||||
* as the provided string is kept alive.)
|
||||
* If the provided string uses externally-managed latin-1 storage, return true
|
||||
* and set |*callbacks| to the external-string callbacks used to create it and
|
||||
* |*chars| to a pointer to its latin1 storage. (These pointers remain valid
|
||||
* as long as the provided string is kept alive.)
|
||||
*/
|
||||
MOZ_ALWAYS_INLINE bool IsExternalStringLatin1(
|
||||
JSString* str, const JSExternalStringCallbacks** callbacks,
|
||||
const JS::Latin1Char** chars) {
|
||||
shadow::String* s = shadow::AsShadowString(str);
|
||||
|
||||
if (!s->isExternal() || !s->hasLatin1Chars()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*callbacks = s->externalCallbacks;
|
||||
*chars = s->nonInlineCharsLatin1;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the provided string uses externally-managed two-byte storage, return true
|
||||
* and set |*callbacks| to the external-string callbacks used to create it and
|
||||
* |*chars| to a pointer to its two-byte storage. (These pointers remain valid
|
||||
* as long as the provided string is kept alive.)
|
||||
*/
|
||||
MOZ_ALWAYS_INLINE bool IsExternalUCString(
|
||||
JSString* str, const JSExternalStringCallbacks** callbacks,
|
||||
const char16_t** chars) {
|
||||
shadow::String* s = shadow::AsShadowString(str);
|
||||
|
||||
if (!s->isExternal()) {
|
||||
if (!s->isExternal() || s->hasLatin1Chars()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3419,7 +3419,12 @@ static bool AddWatchtowerTarget(JSContext* cx, unsigned argc, Value* vp) {
|
|||
}
|
||||
|
||||
struct TestExternalString : public JSExternalStringCallbacks {
|
||||
void finalize(JS::Latin1Char* chars) const override { js_free(chars); }
|
||||
void finalize(char16_t* chars) const override { js_free(chars); }
|
||||
size_t sizeOfBuffer(const JS::Latin1Char* chars,
|
||||
mozilla::MallocSizeOf mallocSizeOf) const override {
|
||||
return mallocSizeOf(chars);
|
||||
}
|
||||
size_t sizeOfBuffer(const char16_t* chars,
|
||||
mozilla::MallocSizeOf mallocSizeOf) const override {
|
||||
return mallocSizeOf(chars);
|
||||
|
|
|
|||
|
|
@ -92,13 +92,25 @@ class MOZ_NON_TEMPORARY_CLASS ExternalStringCache {
|
|||
inlineEntries_ = {};
|
||||
}
|
||||
|
||||
MOZ_ALWAYS_INLINE JSExternalString* lookupExternal(
|
||||
const JS::Latin1Char* chars, size_t len) const;
|
||||
MOZ_ALWAYS_INLINE JSExternalString* lookupExternal(const char16_t* chars,
|
||||
size_t len) const;
|
||||
MOZ_ALWAYS_INLINE void putExternal(JSExternalString* s);
|
||||
|
||||
MOZ_ALWAYS_INLINE JSInlineString* lookupInline(const JS::Latin1Char* chars,
|
||||
size_t len) const;
|
||||
MOZ_ALWAYS_INLINE JSInlineString* lookupInline(const char16_t* chars,
|
||||
size_t len) const;
|
||||
MOZ_ALWAYS_INLINE void putInline(JSInlineString* s);
|
||||
|
||||
private:
|
||||
template <typename CharT>
|
||||
MOZ_ALWAYS_INLINE JSExternalString* lookupExternalImpl(const CharT* chars,
|
||||
size_t len) const;
|
||||
template <typename CharT>
|
||||
MOZ_ALWAYS_INLINE JSInlineString* lookupInlineImpl(const CharT* chars,
|
||||
size_t len) const;
|
||||
};
|
||||
|
||||
class MOZ_NON_TEMPORARY_CLASS FunctionToStringCache {
|
||||
|
|
|
|||
|
|
@ -8,28 +8,48 @@
|
|||
static const char16_t arr[] = u"hi, don't delete me";
|
||||
static const size_t arrlen = js_strlen(arr);
|
||||
|
||||
static const char arr2[] = "hi, don't delete me";
|
||||
static const size_t arrlen2 = js_strlen(arr2);
|
||||
|
||||
static int finalized1 = 0;
|
||||
static int finalized2 = 0;
|
||||
static int finalized3 = 0;
|
||||
static int finalized4 = 0;
|
||||
|
||||
struct ExternalStringCallbacks : public JSExternalStringCallbacks {
|
||||
int* finalizedCount = nullptr;
|
||||
bool isTwoBytes = false;
|
||||
|
||||
explicit ExternalStringCallbacks(int* finalizedCount)
|
||||
: finalizedCount(finalizedCount) {}
|
||||
explicit ExternalStringCallbacks(int* finalizedCount, bool isTwoBytes)
|
||||
: finalizedCount(finalizedCount), isTwoBytes(isTwoBytes) {}
|
||||
|
||||
void finalize(JS::Latin1Char* chars) const override {
|
||||
MOZ_ASSERT(!isTwoBytes);
|
||||
MOZ_ASSERT(chars == (JS::Latin1Char*)arr2);
|
||||
(*finalizedCount)++;
|
||||
}
|
||||
|
||||
void finalize(char16_t* chars) const override {
|
||||
MOZ_ASSERT(isTwoBytes);
|
||||
MOZ_ASSERT(chars == arr);
|
||||
(*finalizedCount)++;
|
||||
}
|
||||
|
||||
size_t sizeOfBuffer(const JS::Latin1Char* chars,
|
||||
mozilla::MallocSizeOf mallocSizeOf) const override {
|
||||
MOZ_CRASH("Unexpected call");
|
||||
}
|
||||
|
||||
size_t sizeOfBuffer(const char16_t* chars,
|
||||
mozilla::MallocSizeOf mallocSizeOf) const override {
|
||||
MOZ_CRASH("Unexpected call");
|
||||
}
|
||||
};
|
||||
|
||||
static const ExternalStringCallbacks callbacks1(&finalized1);
|
||||
static const ExternalStringCallbacks callbacks2(&finalized2);
|
||||
static const ExternalStringCallbacks callbacks1(&finalized1, true);
|
||||
static const ExternalStringCallbacks callbacks2(&finalized2, true);
|
||||
static const ExternalStringCallbacks callbacks3(&finalized3, false);
|
||||
static const ExternalStringCallbacks callbacks4(&finalized4, false);
|
||||
|
||||
BEGIN_TEST(testExternalStrings) {
|
||||
const unsigned N = 1000;
|
||||
|
|
@ -37,15 +57,18 @@ BEGIN_TEST(testExternalStrings) {
|
|||
for (unsigned i = 0; i < N; ++i) {
|
||||
CHECK(JS_NewExternalUCString(cx, arr, arrlen, &callbacks1));
|
||||
CHECK(JS_NewExternalUCString(cx, arr, arrlen, &callbacks2));
|
||||
CHECK(JS_NewExternalStringLatin1(cx, (JS::Latin1Char*)arr2, arrlen2,
|
||||
&callbacks3));
|
||||
CHECK(JS_NewExternalStringLatin1(cx, (JS::Latin1Char*)arr2, arrlen2,
|
||||
&callbacks4));
|
||||
}
|
||||
|
||||
JS_GC(cx);
|
||||
|
||||
// a generous fudge factor to account for strings rooted by conservative gc
|
||||
const unsigned epsilon = 10;
|
||||
|
||||
CHECK((N - finalized1) < epsilon);
|
||||
CHECK((N - finalized2) < epsilon);
|
||||
CHECK((N - finalized1) == 0);
|
||||
CHECK((N - finalized2) == 0);
|
||||
CHECK((N - finalized3) == 0);
|
||||
CHECK((N - finalized4) == 0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1463,6 +1463,14 @@ JS_PUBLIC_API void JS_SetGCParametersBasedOnAvailableMemory(
|
|||
}
|
||||
}
|
||||
|
||||
JS_PUBLIC_API JSString* JS_NewExternalStringLatin1(
|
||||
JSContext* cx, const Latin1Char* chars, size_t length,
|
||||
const JSExternalStringCallbacks* callbacks) {
|
||||
AssertHeapIsIdle();
|
||||
CHECK_THREAD(cx);
|
||||
return JSExternalString::new_(cx, chars, length, callbacks);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API JSString* JS_NewExternalUCString(
|
||||
JSContext* cx, const char16_t* chars, size_t length,
|
||||
const JSExternalStringCallbacks* callbacks) {
|
||||
|
|
@ -1471,6 +1479,15 @@ JS_PUBLIC_API JSString* JS_NewExternalUCString(
|
|||
return JSExternalString::new_(cx, chars, length, callbacks);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API JSString* JS_NewMaybeExternalStringLatin1(
|
||||
JSContext* cx, const JS::Latin1Char* chars, size_t length,
|
||||
const JSExternalStringCallbacks* callbacks, bool* allocatedExternal) {
|
||||
AssertHeapIsIdle();
|
||||
CHECK_THREAD(cx);
|
||||
return NewMaybeExternalString(cx, chars, length, callbacks,
|
||||
allocatedExternal);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API JSString* JS_NewMaybeExternalUCString(
|
||||
JSContext* cx, const char16_t* chars, size_t length,
|
||||
const JSExternalStringCallbacks* callbacks, bool* allocatedExternal) {
|
||||
|
|
|
|||
|
|
@ -589,17 +589,29 @@ inline JSExternalString::JSExternalString(
|
|||
d.s.u3.externalCallbacks = callbacks;
|
||||
}
|
||||
|
||||
MOZ_ALWAYS_INLINE JSExternalString* JSExternalString::new_(
|
||||
JSContext* cx, const char16_t* chars, size_t length,
|
||||
inline JSExternalString::JSExternalString(
|
||||
const JS::Latin1Char* chars, size_t length,
|
||||
const JSExternalStringCallbacks* callbacks) {
|
||||
MOZ_ASSERT(callbacks);
|
||||
setLengthAndFlags(length, EXTERNAL_FLAGS | LATIN1_CHARS_BIT);
|
||||
d.s.u2.nonInlineCharsLatin1 = chars;
|
||||
d.s.u3.externalCallbacks = callbacks;
|
||||
}
|
||||
|
||||
template <typename CharT>
|
||||
/* static */
|
||||
MOZ_ALWAYS_INLINE JSExternalString* JSExternalString::newImpl(
|
||||
JSContext* cx, const CharT* chars, size_t length,
|
||||
const JSExternalStringCallbacks* callbacks) {
|
||||
if (MOZ_UNLIKELY(!validateLength(cx, length))) {
|
||||
return nullptr;
|
||||
}
|
||||
auto* str = cx->newCell<JSExternalString>(chars, length, callbacks);
|
||||
|
||||
if (!str) {
|
||||
return nullptr;
|
||||
}
|
||||
size_t nbytes = length * sizeof(char16_t);
|
||||
size_t nbytes = length * sizeof(CharT);
|
||||
|
||||
MOZ_ASSERT(str->isTenured());
|
||||
js::AddCellMemory(str, nbytes, js::MemoryUse::StringContents);
|
||||
|
|
@ -607,6 +619,20 @@ MOZ_ALWAYS_INLINE JSExternalString* JSExternalString::new_(
|
|||
return str;
|
||||
}
|
||||
|
||||
/* static */
|
||||
MOZ_ALWAYS_INLINE JSExternalString* JSExternalString::new_(
|
||||
JSContext* cx, const JS::Latin1Char* chars, size_t length,
|
||||
const JSExternalStringCallbacks* callbacks) {
|
||||
return newImpl(cx, chars, length, callbacks);
|
||||
}
|
||||
|
||||
/* static */
|
||||
MOZ_ALWAYS_INLINE JSExternalString* JSExternalString::new_(
|
||||
JSContext* cx, const char16_t* chars, size_t length,
|
||||
const JSExternalStringCallbacks* callbacks) {
|
||||
return newImpl(cx, chars, length, callbacks);
|
||||
}
|
||||
|
||||
inline js::NormalAtom::NormalAtom(size_t length, JS::Latin1Char** chars,
|
||||
js::HashNumber hash)
|
||||
: hash_(hash) {
|
||||
|
|
@ -725,10 +751,17 @@ inline void js::FatInlineAtom::finalize(JS::GCContext* gcx) {
|
|||
inline void JSExternalString::finalize(JS::GCContext* gcx) {
|
||||
MOZ_ASSERT(JSString::isExternal());
|
||||
|
||||
size_t nbytes = length() * sizeof(char16_t);
|
||||
gcx->removeCellMemory(this, nbytes, js::MemoryUse::StringContents);
|
||||
if (hasLatin1Chars()) {
|
||||
size_t nbytes = length() * sizeof(JS::Latin1Char);
|
||||
gcx->removeCellMemory(this, nbytes, js::MemoryUse::StringContents);
|
||||
|
||||
callbacks()->finalize(const_cast<char16_t*>(rawTwoByteChars()));
|
||||
callbacks()->finalize(const_cast<JS::Latin1Char*>(rawLatin1Chars()));
|
||||
} else {
|
||||
size_t nbytes = length() * sizeof(char16_t);
|
||||
gcx->removeCellMemory(this, nbytes, js::MemoryUse::StringContents);
|
||||
|
||||
callbacks()->finalize(const_cast<char16_t*>(rawTwoByteChars()));
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* vm_StringType_inl_h */
|
||||
|
|
|
|||
|
|
@ -86,8 +86,14 @@ size_t JSString::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) {
|
|||
if (isExternal()) {
|
||||
// Our callback isn't supposed to cause GC.
|
||||
JS::AutoSuppressGCAnalysis nogc;
|
||||
return asExternal().callbacks()->sizeOfBuffer(asExternal().twoByteChars(),
|
||||
mallocSizeOf);
|
||||
JSExternalString& external = asExternal();
|
||||
if (external.hasLatin1Chars()) {
|
||||
return asExternal().callbacks()->sizeOfBuffer(external.latin1Chars(),
|
||||
mallocSizeOf);
|
||||
} else {
|
||||
return asExternal().callbacks()->sizeOfBuffer(external.twoByteChars(),
|
||||
mallocSizeOf);
|
||||
}
|
||||
}
|
||||
|
||||
// JSExtensibleString: count the full capacity, not just the used space.
|
||||
|
|
@ -1550,6 +1556,11 @@ JSLinearString* js::NewDependentString(JSContext* cx, JSString* baseArg,
|
|||
return JSDependentString::new_(cx, base, start, length, heap);
|
||||
}
|
||||
|
||||
static constexpr bool CanStoreCharsAsLatin1(const JS::Latin1Char* s,
|
||||
size_t length) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool CanStoreCharsAsLatin1(const char16_t* s, size_t length) {
|
||||
return IsUtf16Latin1(Span(s, length));
|
||||
}
|
||||
|
|
@ -1890,8 +1901,9 @@ JSLinearString* NewStringCopyUTF8N(JSContext* cx, const JS::UTF8Chars utf8,
|
|||
return NewString<js::CanGC>(cx, std::move(utf16), length, heap);
|
||||
}
|
||||
|
||||
MOZ_ALWAYS_INLINE JSExternalString* ExternalStringCache::lookupExternal(
|
||||
const char16_t* chars, size_t len) const {
|
||||
template <typename CharT>
|
||||
MOZ_ALWAYS_INLINE JSExternalString* ExternalStringCache::lookupExternalImpl(
|
||||
const CharT* chars, size_t len) const {
|
||||
AutoCheckCannotGC nogc;
|
||||
|
||||
for (size_t i = 0; i < NumEntries; i++) {
|
||||
|
|
@ -1900,7 +1912,17 @@ MOZ_ALWAYS_INLINE JSExternalString* ExternalStringCache::lookupExternal(
|
|||
continue;
|
||||
}
|
||||
|
||||
const char16_t* strChars = str->nonInlineTwoByteChars(nogc);
|
||||
if constexpr (std::is_same_v<CharT, JS::Latin1Char>) {
|
||||
if (!str->hasLatin1Chars()) {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
if (!str->hasTwoByteChars()) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
const CharT* strChars = str->nonInlineChars<CharT>(nogc);
|
||||
if (chars == strChars) {
|
||||
// Note that we don't need an incremental barrier here or below.
|
||||
// The cache is purged on GC so any string we get from the cache
|
||||
|
|
@ -1919,16 +1941,25 @@ MOZ_ALWAYS_INLINE JSExternalString* ExternalStringCache::lookupExternal(
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
MOZ_ALWAYS_INLINE JSExternalString* ExternalStringCache::lookupExternal(
|
||||
const JS::Latin1Char* chars, size_t len) const {
|
||||
return lookupExternalImpl(chars, len);
|
||||
}
|
||||
MOZ_ALWAYS_INLINE JSExternalString* ExternalStringCache::lookupExternal(
|
||||
const char16_t* chars, size_t len) const {
|
||||
return lookupExternalImpl(chars, len);
|
||||
}
|
||||
|
||||
MOZ_ALWAYS_INLINE void ExternalStringCache::putExternal(JSExternalString* str) {
|
||||
MOZ_ASSERT(str->hasTwoByteChars());
|
||||
for (size_t i = NumEntries - 1; i > 0; i--) {
|
||||
externalEntries_[i] = externalEntries_[i - 1];
|
||||
}
|
||||
externalEntries_[0] = str;
|
||||
}
|
||||
|
||||
MOZ_ALWAYS_INLINE JSInlineString* ExternalStringCache::lookupInline(
|
||||
const char16_t* chars, size_t len) const {
|
||||
template <typename CharT>
|
||||
MOZ_ALWAYS_INLINE JSInlineString* ExternalStringCache::lookupInlineImpl(
|
||||
const CharT* chars, size_t len) const {
|
||||
MOZ_ASSERT(CanStoreCharsAsLatin1(chars, len));
|
||||
MOZ_ASSERT(JSThinInlineString::lengthFits<Latin1Char>(len));
|
||||
|
||||
|
|
@ -1949,6 +1980,15 @@ MOZ_ALWAYS_INLINE JSInlineString* ExternalStringCache::lookupInline(
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
MOZ_ALWAYS_INLINE JSInlineString* ExternalStringCache::lookupInline(
|
||||
const JS::Latin1Char* chars, size_t len) const {
|
||||
return lookupInlineImpl(chars, len);
|
||||
}
|
||||
MOZ_ALWAYS_INLINE JSInlineString* ExternalStringCache::lookupInline(
|
||||
const char16_t* chars, size_t len) const {
|
||||
return lookupInlineImpl(chars, len);
|
||||
}
|
||||
|
||||
MOZ_ALWAYS_INLINE void ExternalStringCache::putInline(JSInlineString* str) {
|
||||
MOZ_ASSERT(str->hasLatin1Chars());
|
||||
|
||||
|
|
@ -1958,7 +1998,26 @@ MOZ_ALWAYS_INLINE void ExternalStringCache::putInline(JSInlineString* str) {
|
|||
inlineEntries_[0] = str;
|
||||
}
|
||||
|
||||
JSString* NewMaybeExternalString(JSContext* cx, const char16_t* s, size_t n,
|
||||
} /* namespace js */
|
||||
|
||||
template <AllowGC allowGC>
|
||||
static MOZ_ALWAYS_INLINE JSInlineString* NewInlineStringMaybeDeflated(
|
||||
JSContext* cx, const mozilla::Range<const JS::Latin1Char>& chars,
|
||||
gc::Heap heap = gc::Heap::Default) {
|
||||
return NewInlineString<allowGC>(cx, chars, heap);
|
||||
}
|
||||
|
||||
template <AllowGC allowGC>
|
||||
static MOZ_ALWAYS_INLINE JSInlineString* NewInlineStringMaybeDeflated(
|
||||
JSContext* cx, const mozilla::Range<const char16_t>& chars,
|
||||
gc::Heap heap = gc::Heap::Default) {
|
||||
return NewInlineStringDeflated<allowGC>(cx, chars, heap);
|
||||
}
|
||||
|
||||
namespace js {
|
||||
|
||||
template <typename CharT>
|
||||
JSString* NewMaybeExternalString(JSContext* cx, const CharT* s, size_t n,
|
||||
const JSExternalStringCallbacks* callbacks,
|
||||
bool* allocatedExternal, gc::Heap heap) {
|
||||
if (JSString* str = TryEmptyOrStaticString(cx, s, n)) {
|
||||
|
|
@ -1974,8 +2033,8 @@ JSString* NewMaybeExternalString(JSContext* cx, const char16_t* s, size_t n,
|
|||
if (JSInlineString* str = cache.lookupInline(s, n)) {
|
||||
return str;
|
||||
}
|
||||
JSInlineString* str = NewInlineStringDeflated<AllowGC::CanGC>(
|
||||
cx, mozilla::Range<const char16_t>(s, n), heap);
|
||||
JSInlineString* str = NewInlineStringMaybeDeflated<AllowGC::CanGC>(
|
||||
cx, mozilla::Range<const CharT>(s, n), heap);
|
||||
if (!str) {
|
||||
return nullptr;
|
||||
}
|
||||
|
|
@ -1998,6 +2057,16 @@ JSString* NewMaybeExternalString(JSContext* cx, const char16_t* s, size_t n,
|
|||
return str;
|
||||
}
|
||||
|
||||
template JSString* NewMaybeExternalString(
|
||||
JSContext* cx, const JS::Latin1Char* s, size_t n,
|
||||
const JSExternalStringCallbacks* callbacks, bool* allocatedExternal,
|
||||
gc::Heap heap);
|
||||
|
||||
template JSString* NewMaybeExternalString(
|
||||
JSContext* cx, const char16_t* s, size_t n,
|
||||
const JSExternalStringCallbacks* callbacks, bool* allocatedExternal,
|
||||
gc::Heap heap);
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
#if defined(DEBUG) || defined(JS_JITSPEW) || defined(JS_CACHEIR_SPEW)
|
||||
|
|
@ -2029,9 +2098,17 @@ void JSLinearString::dumpRepresentation(js::GenericPrinter& out,
|
|||
#endif
|
||||
|
||||
struct RepresentativeExternalString : public JSExternalStringCallbacks {
|
||||
void finalize(JS::Latin1Char* chars) const override {
|
||||
// Constant chars, nothing to do.
|
||||
}
|
||||
void finalize(char16_t* chars) const override {
|
||||
// Constant chars, nothing to do.
|
||||
}
|
||||
size_t sizeOfBuffer(const JS::Latin1Char* chars,
|
||||
mozilla::MallocSizeOf mallocSizeOf) const override {
|
||||
// This string's buffer is not heap-allocated, so its malloc size is 0.
|
||||
return 0;
|
||||
}
|
||||
size_t sizeOfBuffer(const char16_t* chars,
|
||||
mozilla::MallocSizeOf mallocSizeOf) const override {
|
||||
// This string's buffer is not heap-allocated, so its malloc size is 0.
|
||||
|
|
@ -2131,7 +2208,6 @@ static bool FillWithRepresentatives(JSContext* cx, Handle<ArrayObject*> array,
|
|||
}
|
||||
MOZ_ASSERT(extensible->isExtensible());
|
||||
|
||||
// External. Note that we currently only support TwoByte external strings.
|
||||
RootedString external1(cx), external2(cx);
|
||||
if constexpr (std::is_same_v<CharT, char16_t>) {
|
||||
external1 = JS_NewExternalUCString(cx, (const char16_t*)chars, len,
|
||||
|
|
@ -2147,6 +2223,22 @@ static bool FillWithRepresentatives(JSContext* cx, Handle<ArrayObject*> array,
|
|||
return false;
|
||||
}
|
||||
MOZ_ASSERT(external2->isExternal());
|
||||
} else {
|
||||
external1 =
|
||||
JS_NewExternalStringLatin1(cx, (const Latin1Char*)chars, len,
|
||||
&RepresentativeExternalStringCallbacks);
|
||||
if (!external1 || !AppendString(cx, array, index, external1)) {
|
||||
return false;
|
||||
}
|
||||
MOZ_ASSERT(external1->isExternal());
|
||||
|
||||
external2 =
|
||||
JS_NewExternalStringLatin1(cx, (const Latin1Char*)chars, 2,
|
||||
&RepresentativeExternalStringCallbacks);
|
||||
if (!external2 || !AppendString(cx, array, index, external2)) {
|
||||
return false;
|
||||
}
|
||||
MOZ_ASSERT(external2->isExternal());
|
||||
}
|
||||
|
||||
// Assert the strings still have the types we expect after creating the
|
||||
|
|
@ -2167,8 +2259,8 @@ static bool FillWithRepresentatives(JSContext* cx, Handle<ArrayObject*> array,
|
|||
MOZ_ASSERT(rope->isRope());
|
||||
MOZ_ASSERT(dep->isDependent());
|
||||
MOZ_ASSERT(extensible->isExtensible());
|
||||
MOZ_ASSERT_IF(external1, external1->isExternal());
|
||||
MOZ_ASSERT_IF(external2, external2->isExternal());
|
||||
MOZ_ASSERT(external1->isExternal());
|
||||
MOZ_ASSERT(external2->isExternal());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -2215,7 +2307,27 @@ bool JSString::fillWithRepresentatives(JSContext* cx,
|
|||
return false;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(index == 40);
|
||||
#ifdef DEBUG
|
||||
// * Normal atom
|
||||
// * Inline atom.
|
||||
// * Fat inline atom.
|
||||
// * Normal linear string
|
||||
// * Inline string
|
||||
// * Fat inline string
|
||||
// * Rope; maybe nursery.
|
||||
// * Dependent
|
||||
// * Extensible
|
||||
// * External with original len
|
||||
// * External with len==2
|
||||
static constexpr uint32_t StringTypes = 11;
|
||||
// * Latin1
|
||||
// * TwoByte
|
||||
static constexpr uint32_t CharTypes = 2;
|
||||
// * Tenured
|
||||
// * Default
|
||||
static constexpr uint32_t HeapType = 2;
|
||||
MOZ_ASSERT(index == StringTypes * CharTypes * HeapType);
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1258,6 +1258,8 @@ static_assert(sizeof(JSFatInlineString) % js::gc::CellAlignBytes == 0,
|
|||
class JSExternalString : public JSLinearString {
|
||||
friend class js::gc::CellAllocator;
|
||||
|
||||
JSExternalString(const JS::Latin1Char* chars, size_t length,
|
||||
const JSExternalStringCallbacks* callbacks);
|
||||
JSExternalString(const char16_t* chars, size_t length,
|
||||
const JSExternalStringCallbacks* callbacks);
|
||||
|
||||
|
|
@ -1265,7 +1267,15 @@ class JSExternalString : public JSLinearString {
|
|||
bool isExternal() const = delete;
|
||||
JSExternalString& asExternal() const = delete;
|
||||
|
||||
template <typename CharT>
|
||||
static inline JSExternalString* newImpl(
|
||||
JSContext* cx, const CharT* chars, size_t length,
|
||||
const JSExternalStringCallbacks* callbacks);
|
||||
|
||||
public:
|
||||
static inline JSExternalString* new_(
|
||||
JSContext* cx, const JS::Latin1Char* chars, size_t length,
|
||||
const JSExternalStringCallbacks* callbacks);
|
||||
static inline JSExternalString* new_(
|
||||
JSContext* cx, const char16_t* chars, size_t length,
|
||||
const JSExternalStringCallbacks* callbacks);
|
||||
|
|
@ -1277,6 +1287,7 @@ class JSExternalString : public JSLinearString {
|
|||
|
||||
// External chars are never allocated inline or in the nursery, so we can
|
||||
// safely expose this without requiring an AutoCheckCannotGC argument.
|
||||
const JS::Latin1Char* latin1Chars() const { return rawLatin1Chars(); }
|
||||
const char16_t* twoByteChars() const { return rawTwoByteChars(); }
|
||||
|
||||
// Only called by the GC for strings with the AllocKind::EXTERNAL_STRING
|
||||
|
|
@ -1627,7 +1638,8 @@ inline JSLinearString* NewStringCopyUTF8Z(
|
|||
cx, JS::UTF8Chars(utf8.c_str(), strlen(utf8.c_str())), heap);
|
||||
}
|
||||
|
||||
JSString* NewMaybeExternalString(JSContext* cx, const char16_t* s, size_t n,
|
||||
template <typename CharT>
|
||||
JSString* NewMaybeExternalString(JSContext* cx, const CharT* s, size_t n,
|
||||
const JSExternalStringCallbacks* callbacks,
|
||||
bool* allocatedExternal,
|
||||
js::gc::Heap heap = js::gc::Heap::Default);
|
||||
|
|
|
|||
|
|
@ -32,22 +32,44 @@ const XPCStringConvert::LiteralExternalString
|
|||
const XPCStringConvert::DOMStringExternalString
|
||||
XPCStringConvert::sDOMStringExternalString;
|
||||
|
||||
void XPCStringConvert::LiteralExternalString::finalize(
|
||||
JS::Latin1Char* aChars) const {
|
||||
MOZ_CRASH("Unexpected");
|
||||
}
|
||||
|
||||
void XPCStringConvert::LiteralExternalString::finalize(char16_t* aChars) const {
|
||||
// Nothing to do.
|
||||
}
|
||||
|
||||
size_t XPCStringConvert::LiteralExternalString::sizeOfBuffer(
|
||||
const JS::Latin1Char* aChars, mozilla::MallocSizeOf aMallocSizeOf) const {
|
||||
MOZ_CRASH("Unexpected");
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t XPCStringConvert::LiteralExternalString::sizeOfBuffer(
|
||||
const char16_t* aChars, mozilla::MallocSizeOf aMallocSizeOf) const {
|
||||
// This string's buffer is not heap-allocated, so its malloc size is 0.
|
||||
return 0;
|
||||
}
|
||||
|
||||
void XPCStringConvert::DOMStringExternalString::finalize(
|
||||
JS::Latin1Char* aChars) const {
|
||||
MOZ_CRASH("Unexpected");
|
||||
}
|
||||
|
||||
void XPCStringConvert::DOMStringExternalString::finalize(
|
||||
char16_t* aChars) const {
|
||||
nsStringBuffer* buf = nsStringBuffer::FromData(aChars);
|
||||
buf->Release();
|
||||
}
|
||||
|
||||
size_t XPCStringConvert::DOMStringExternalString::sizeOfBuffer(
|
||||
const JS::Latin1Char* aChars, mozilla::MallocSizeOf aMallocSizeOf) const {
|
||||
MOZ_CRASH("Unexpected");
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t XPCStringConvert::DOMStringExternalString::sizeOfBuffer(
|
||||
const char16_t* aChars, mozilla::MallocSizeOf aMallocSizeOf) const {
|
||||
// We promised the JS engine we would not GC. Enforce that:
|
||||
|
|
|
|||
|
|
@ -309,12 +309,18 @@ class XPCStringConvert {
|
|||
|
||||
private:
|
||||
struct LiteralExternalString : public JSExternalStringCallbacks {
|
||||
void finalize(JS::Latin1Char* aChars) const override;
|
||||
void finalize(char16_t* aChars) const override;
|
||||
size_t sizeOfBuffer(const JS::Latin1Char* aChars,
|
||||
mozilla::MallocSizeOf aMallocSizeOf) const override;
|
||||
size_t sizeOfBuffer(const char16_t* aChars,
|
||||
mozilla::MallocSizeOf aMallocSizeOf) const override;
|
||||
};
|
||||
struct DOMStringExternalString : public JSExternalStringCallbacks {
|
||||
void finalize(JS::Latin1Char* aChars) const override;
|
||||
void finalize(char16_t* aChars) const override;
|
||||
size_t sizeOfBuffer(const JS::Latin1Char* aChars,
|
||||
mozilla::MallocSizeOf aMallocSizeOf) const override;
|
||||
size_t sizeOfBuffer(const char16_t* aChars,
|
||||
mozilla::MallocSizeOf aMallocSizeOf) const override;
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in a new issue