Bug 1644243 - Allocate strings in the tenured heap if they will be atomized right after, and pass through InitialHeap to string allocation r=jonco

Differential Revision: https://phabricator.services.mozilla.com/D78806
This commit is contained in:
Steve Fink 2020-06-11 18:15:02 +00:00
parent 3ca8acd1fb
commit 751343a79e
10 changed files with 252 additions and 159 deletions

View File

@ -2384,7 +2384,8 @@ JSAtom* ParserBase::prefixAccessorName(PropertyType propType,
prefix = cx_->names().getPrefix;
}
RootedString str(cx_, ConcatStrings<CanGC>(cx_, prefix, propAtom));
RootedString str(
cx_, ConcatStrings<CanGC>(cx_, prefix, propAtom, js::gc::TenuredHeap));
if (!str) {
return nullptr;
}

View File

@ -6049,10 +6049,12 @@ bool CacheIRCompiler::emitCallStringConcatResult(StringOperandId lhsId,
callvm.prepare();
masm.Push(static_cast<js::jit::Imm32>(js::gc::DefaultHeap));
masm.Push(rhs);
masm.Push(lhs);
using Fn = JSString* (*)(JSContext*, HandleString, HandleString);
using Fn = JSString* (*)(JSContext*, HandleString, HandleString,
js::gc::InitialHeap);
callvm.call<Fn, ConcatStrings<CanGC>>();
return true;

View File

@ -9008,9 +9008,11 @@ void CodeGenerator::visitSameValueVM(LSameValueVM* lir) {
void CodeGenerator::emitConcat(LInstruction* lir, Register lhs, Register rhs,
Register output) {
using Fn = JSString* (*)(JSContext*, HandleString, HandleString);
using Fn = JSString* (*)(JSContext*, HandleString, HandleString,
js::gc::InitialHeap);
OutOfLineCode* ool = oolCallVM<Fn, ConcatStrings<CanGC>>(
lir, ArgList(lhs, rhs), StoreRegisterTo(output));
lir, ArgList(lhs, rhs, static_cast<Imm32>(gc::DefaultHeap)),
StoreRegisterTo(output));
const JitRealm* jitRealm = gen->realm->jitRealm();
JitCode* stringConcatStub =

View File

@ -767,7 +767,8 @@ JSLinearString* js::Int32ToString(JSContext* cx, int32_t si) {
BackfillInt32InBuffer(si, buffer, ArrayLength(buffer), &length);
mozilla::Range<const Latin1Char> chars(start, length);
JSInlineString* str = NewInlineString<allowGC>(cx, chars);
JSInlineString* str =
NewInlineString<allowGC>(cx, chars, js::gc::TenuredHeap);
if (!str) {
return nullptr;
}
@ -1549,7 +1550,8 @@ static JSString* NumberToStringWithBase(JSContext* cx, double d, int base) {
numStrLen = strlen(numStr);
}
JSLinearString* s = NewStringCopyN<allowGC>(cx, numStr, numStrLen);
JSLinearString* s =
NewStringCopyN<allowGC>(cx, numStr, numStrLen, js::gc::TenuredHeap);
if (!s) {
return nullptr;
}
@ -1627,7 +1629,7 @@ JSLinearString* js::IndexToString(JSContext* cx, uint32_t index) {
RangedPtr<Latin1Char> start = BackfillIndexInCharBuffer(index, end);
mozilla::Range<const Latin1Char> chars(start.get(), end - start);
JSInlineString* str = NewInlineString<CanGC>(cx, chars);
JSInlineString* str = NewInlineString<CanGC>(cx, chars, js::gc::TenuredHeap);
if (!str) {
return nullptr;
}

View File

@ -110,7 +110,9 @@ class MOZ_NON_PARAM InlineCharBuffer {
return true;
}
JSString* toStringDontDeflate(JSContext* cx, size_t length) {
JSString* toStringDontDeflate(
JSContext* cx, size_t length,
js::gc::InitialHeap heap = js::gc::DefaultHeap) {
MOZ_ASSERT(length == lastRequestedLength);
if (JSInlineString::lengthFits<CharT>(length)) {
@ -123,16 +125,17 @@ class MOZ_NON_PARAM InlineCharBuffer {
}
mozilla::Range<const CharT> range(inlineStorage, length);
return NewInlineString<CanGC>(cx, range);
return NewInlineString<CanGC>(cx, range, heap);
}
MOZ_ASSERT(heapStorage,
"heap storage was not allocated for non-inline string");
return NewStringDontDeflate<CanGC>(cx, std::move(heapStorage), length);
return NewStringDontDeflate<CanGC>(cx, std::move(heapStorage), length, heap);
}
JSString* toString(JSContext* cx, size_t length) {
JSString* toString(JSContext* cx, size_t length,
js::gc::InitialHeap heap = js::gc::DefaultHeap) {
MOZ_ASSERT(length == lastRequestedLength);
if (JSInlineString::lengthFits<CharT>(length)) {
@ -140,13 +143,13 @@ class MOZ_NON_PARAM InlineCharBuffer {
!heapStorage,
"expected only inline storage when length fits in inline string");
return NewStringCopyN<CanGC>(cx, inlineStorage, length);
return NewStringCopyN<CanGC>(cx, inlineStorage, length, heap);
}
MOZ_ASSERT(heapStorage,
"heap storage was not allocated for non-inline string");
return NewString<CanGC>(cx, std::move(heapStorage), length);
return NewString<CanGC>(cx, std::move(heapStorage), length, heap);
}
};

View File

@ -876,14 +876,14 @@ struct AtomizeUTF8OrWTF8CharsWrapper {
template <typename CharT>
static MOZ_ALWAYS_INLINE JSLinearString* MakeLinearStringForAtomization(
JSContext* cx, const CharT* chars, size_t length) {
return NewStringCopyN<NoGC>(cx, chars, length);
return NewStringCopyN<NoGC>(cx, chars, length, gc::TenuredHeap);
}
// MakeLinearStringForAtomization has one further variant -- a non-template
// overload accepting LittleEndianChars.
static MOZ_ALWAYS_INLINE JSLinearString* MakeLinearStringForAtomization(
JSContext* cx, LittleEndianChars chars, size_t length) {
return NewStringFromLittleEndianNoGC(cx, chars, length);
return NewStringFromLittleEndianNoGC(cx, chars, length, gc::TenuredHeap);
}
template <typename CharT, typename WrapperT>
@ -891,7 +891,8 @@ static MOZ_ALWAYS_INLINE JSLinearString* MakeUTF8AtomHelper(
JSContext* cx, const WrapperT* chars, size_t length) {
if (JSInlineString::lengthFits<CharT>(length)) {
CharT* storage;
JSInlineString* str = AllocateInlineString<NoGC>(cx, length, &storage);
JSInlineString* str =
AllocateInlineString<NoGC>(cx, length, &storage, gc::TenuredHeap);
if (!str) {
return nullptr;
}
@ -914,7 +915,8 @@ static MOZ_ALWAYS_INLINE JSLinearString* MakeUTF8AtomHelper(
InflateUTF8CharsToBufferAndTerminate(chars->utf8, newStr.get(), length,
chars->encoding);
return JSLinearString::new_<NoGC>(cx, std::move(newStr), length);
return JSLinearString::new_<NoGC>(cx, std::move(newStr), length,
gc::TenuredHeap);
}
// Another 2 variants of MakeLinearStringForAtomization.

View File

@ -27,13 +27,12 @@ namespace js {
// Allocate a thin inline string if possible, and a fat inline string if not.
template <AllowGC allowGC, typename CharT>
static MOZ_ALWAYS_INLINE JSInlineString* AllocateInlineString(JSContext* cx,
size_t len,
CharT** chars) {
static MOZ_ALWAYS_INLINE JSInlineString* AllocateInlineString(
JSContext* cx, size_t len, CharT** chars, js::gc::InitialHeap heap) {
MOZ_ASSERT(JSInlineString::lengthFits<CharT>(len));
if (JSThinInlineString::lengthFits<CharT>(len)) {
JSThinInlineString* str = JSThinInlineString::new_<allowGC>(cx);
JSThinInlineString* str = JSThinInlineString::new_<allowGC>(cx, heap);
if (!str) {
return nullptr;
}
@ -41,7 +40,7 @@ static MOZ_ALWAYS_INLINE JSInlineString* AllocateInlineString(JSContext* cx,
return str;
}
JSFatInlineString* str = JSFatInlineString::new_<allowGC>(cx);
JSFatInlineString* str = JSFatInlineString::new_<allowGC>(cx, heap);
if (!str) {
return nullptr;
}
@ -52,7 +51,8 @@ static MOZ_ALWAYS_INLINE JSInlineString* AllocateInlineString(JSContext* cx,
// Create a thin inline string if possible, and a fat inline string if not.
template <AllowGC allowGC, typename CharT>
static MOZ_ALWAYS_INLINE JSInlineString* NewInlineString(
JSContext* cx, mozilla::Range<const CharT> chars) {
JSContext* cx, mozilla::Range<const CharT> chars,
js::gc::InitialHeap heap = js::gc::DefaultHeap) {
/*
* Don't bother trying to find a static atom; measurement shows that not
* many get here (for one, Atomize is catching them).
@ -60,7 +60,7 @@ static MOZ_ALWAYS_INLINE JSInlineString* NewInlineString(
size_t len = chars.length();
CharT* storage;
JSInlineString* str = AllocateInlineString<allowGC>(cx, len, &storage);
JSInlineString* str = AllocateInlineString<allowGC>(cx, len, &storage, heap);
if (!str) {
return nullptr;
}
@ -72,11 +72,12 @@ static MOZ_ALWAYS_INLINE JSInlineString* NewInlineString(
// Create a thin inline string if possible, and a fat inline string if not.
template <typename CharT>
static MOZ_ALWAYS_INLINE JSInlineString* NewInlineString(
JSContext* cx, HandleLinearString base, size_t start, size_t length) {
JSContext* cx, HandleLinearString base, size_t start, size_t length,
js::gc::InitialHeap heap) {
MOZ_ASSERT(JSInlineString::lengthFits<CharT>(length));
CharT* chars;
JSInlineString* s = AllocateInlineString<CanGC>(cx, length, &chars);
JSInlineString* s = AllocateInlineString<CanGC>(cx, length, &chars, heap);
if (!s) {
return nullptr;
}
@ -194,7 +195,8 @@ MOZ_ALWAYS_INLINE void JSDependentString::init(JSContext* cx,
}
MOZ_ALWAYS_INLINE JSLinearString* JSDependentString::new_(
JSContext* cx, JSLinearString* baseArg, size_t start, size_t length) {
JSContext* cx, JSLinearString* baseArg, size_t start, size_t length,
js::gc::InitialHeap heap) {
/*
* Try to avoid long chains of dependent strings. We can't avoid these
* entirely, however, due to how ropes are flattened.
@ -217,8 +219,9 @@ MOZ_ALWAYS_INLINE JSLinearString* JSDependentString::new_(
if (useInline) {
js::RootedLinearString base(cx, baseArg);
return baseArg->hasLatin1Chars()
? js::NewInlineString<JS::Latin1Char>(cx, base, start, length)
: js::NewInlineString<char16_t>(cx, base, start, length);
? js::NewInlineString<JS::Latin1Char>(cx, base, start, length,
heap)
: js::NewInlineString<char16_t>(cx, base, start, length, heap);
}
JSDependentString* str =
@ -256,8 +259,8 @@ MOZ_ALWAYS_INLINE void JSLinearString::init(const JS::Latin1Char* chars,
template <js::AllowGC allowGC, typename CharT>
MOZ_ALWAYS_INLINE JSLinearString* JSLinearString::new_(
JSContext* cx, js::UniquePtr<CharT[], JS::FreePolicy> chars,
size_t length) {
JSContext* cx, js::UniquePtr<CharT[], JS::FreePolicy> chars, size_t length,
js::gc::InitialHeap heap) {
if (!validateLength(cx, length)) {
return nullptr;
}
@ -266,7 +269,7 @@ MOZ_ALWAYS_INLINE JSLinearString* JSLinearString::new_(
if (cx->zone()->isAtomsZone()) {
str = js::Allocate<js::NormalAtom, allowGC>(cx);
} else {
str = js::AllocateString<JSLinearString, allowGC>(cx, js::gc::DefaultHeap);
str = js::AllocateString<JSLinearString, allowGC>(cx, heap);
}
if (!str) {
return nullptr;
@ -310,17 +313,18 @@ inline js::PropertyName* JSLinearString::toPropertyName(JSContext* cx) {
}
template <js::AllowGC allowGC>
MOZ_ALWAYS_INLINE JSThinInlineString* JSThinInlineString::new_(JSContext* cx) {
MOZ_ALWAYS_INLINE JSThinInlineString* JSThinInlineString::new_(
JSContext* cx, js::gc::InitialHeap heap) {
if (cx->zone()->isAtomsZone()) {
return (JSThinInlineString*)(js::Allocate<js::NormalAtom, allowGC>(cx));
}
return js::AllocateString<JSThinInlineString, allowGC>(cx,
js::gc::DefaultHeap);
return js::AllocateString<JSThinInlineString, allowGC>(cx, heap);
}
template <js::AllowGC allowGC>
MOZ_ALWAYS_INLINE JSFatInlineString* JSFatInlineString::new_(JSContext* cx) {
MOZ_ALWAYS_INLINE JSFatInlineString* JSFatInlineString::new_(
JSContext* cx, js::gc::InitialHeap heap) {
if (cx->zone()->isAtomsZone()) {
return (JSFatInlineString*)(js::Allocate<js::FatInlineAtom, allowGC>(cx));
}
@ -398,7 +402,8 @@ inline JSLinearString* js::StaticStrings::getUnitStringForElement(
if (c < UNIT_STATIC_LIMIT) {
return getUnit(c);
}
return js::NewInlineString<CanGC>(cx, mozilla::Range<const char16_t>(&c, 1));
return js::NewInlineString<CanGC>(cx, mozilla::Range<const char16_t>(&c, 1),
js::gc::DefaultHeap);
}
MOZ_ALWAYS_INLINE void JSString::finalize(JSFreeOp* fop) {

View File

@ -843,7 +843,8 @@ static JSLinearString* EnsureLinear(
template <AllowGC allowGC>
JSString* js::ConcatStrings(
JSContext* cx, typename MaybeRooted<JSString*, allowGC>::HandleType left,
typename MaybeRooted<JSString*, allowGC>::HandleType right) {
typename MaybeRooted<JSString*, allowGC>::HandleType right,
gc::InitialHeap heap) {
MOZ_ASSERT_IF(!left->isAtom(), cx->isInsideCurrentZone(left));
MOZ_ASSERT_IF(!right->isAtom(), cx->isInsideCurrentZone(right));
@ -874,8 +875,9 @@ JSString* js::ConcatStrings(
Latin1Char* latin1Buf = nullptr; // initialize to silence GCC warning
char16_t* twoByteBuf = nullptr; // initialize to silence GCC warning
JSInlineString* str =
isLatin1 ? AllocateInlineString<allowGC>(cx, wholeLength, &latin1Buf)
: AllocateInlineString<allowGC>(cx, wholeLength, &twoByteBuf);
isLatin1
? AllocateInlineString<allowGC>(cx, wholeLength, &latin1Buf, heap)
: AllocateInlineString<allowGC>(cx, wholeLength, &twoByteBuf, heap);
if (!str) {
return nullptr;
}
@ -911,14 +913,16 @@ JSString* js::ConcatStrings(
return str;
}
return JSRope::new_<allowGC>(cx, left, right, wholeLength);
return JSRope::new_<allowGC>(cx, left, right, wholeLength, heap);
}
template JSString* js::ConcatStrings<CanGC>(JSContext* cx, HandleString left,
HandleString right);
HandleString right,
gc::InitialHeap heap);
template JSString* js::ConcatStrings<NoGC>(JSContext* cx, JSString* const& left,
JSString* const& right);
JSString* const& right,
gc::InitialHeap heap);
/**
* Copy |src[0..length]| to |dest[0..length]| when copying doesn't narrow and
@ -1245,7 +1249,8 @@ bool StaticStrings::init(JSContext* cx) {
for (uint32_t i = 0; i < UNIT_STATIC_LIMIT; i++) {
Latin1Char ch = Latin1Char(i);
JSLinearString* s = NewInlineString<NoGC>(cx, Latin1Range(&ch, 1));
JSLinearString* s =
NewInlineString<NoGC>(cx, Latin1Range(&ch, 1), gc::TenuredHeap);
if (!s) {
return false;
}
@ -1255,7 +1260,8 @@ bool StaticStrings::init(JSContext* cx) {
for (uint32_t i = 0; i < NUM_SMALL_CHARS * NUM_SMALL_CHARS; i++) {
Latin1Char buffer[] = {fromSmallChar(i >> 6), fromSmallChar(i & 0x3F)};
JSLinearString* s = NewInlineString<NoGC>(cx, Latin1Range(buffer, 2));
JSLinearString* s =
NewInlineString<NoGC>(cx, Latin1Range(buffer, 2), gc::TenuredHeap);
if (!s) {
return false;
}
@ -1274,7 +1280,8 @@ bool StaticStrings::init(JSContext* cx) {
Latin1Char buffer[] = {Latin1Char('0' + (i / 100)),
Latin1Char('0' + ((i / 10) % 10)),
Latin1Char('0' + (i % 10))};
JSLinearString* s = NewInlineString<NoGC>(cx, Latin1Range(buffer, 3));
JSLinearString* s =
NewInlineString<NoGC>(cx, Latin1Range(buffer, 3), gc::TenuredHeap);
if (!s) {
return false;
}
@ -1465,7 +1472,8 @@ void JSExternalString::dumpRepresentation(js::GenericPrinter& out,
#endif /* defined(DEBUG) || defined(JS_JITSPEW) */
JSLinearString* js::NewDependentString(JSContext* cx, JSString* baseArg,
size_t start, size_t length) {
size_t start, size_t length,
gc::InitialHeap heap) {
if (length == 0) {
return cx->emptyString();
}
@ -1493,7 +1501,7 @@ JSLinearString* js::NewDependentString(JSContext* cx, JSString* baseArg,
}
}
return JSDependentString::new_(cx, base, start, length);
return JSDependentString::new_(cx, base, start, length, heap);
}
static inline bool CanStoreCharsAsLatin1(const char16_t* s, size_t length) {
@ -1512,10 +1520,11 @@ static bool CanStoreCharsAsLatin1(LittleEndianChars chars, size_t length) {
template <AllowGC allowGC>
static MOZ_ALWAYS_INLINE JSInlineString* NewInlineStringDeflated(
JSContext* cx, mozilla::Range<const char16_t> chars) {
JSContext* cx, const mozilla::Range<const char16_t>& chars,
gc::InitialHeap heap = gc::DefaultHeap) {
size_t len = chars.length();
Latin1Char* storage;
JSInlineString* str = AllocateInlineString<allowGC>(cx, len, &storage);
JSInlineString* str = AllocateInlineString<allowGC>(cx, len, &storage, heap);
if (!str) {
return nullptr;
}
@ -1527,14 +1536,14 @@ static MOZ_ALWAYS_INLINE JSInlineString* NewInlineStringDeflated(
template <AllowGC allowGC>
static JSLinearString* NewStringDeflated(JSContext* cx, const char16_t* s,
size_t n) {
size_t n, gc::InitialHeap heap) {
if (JSLinearString* str = TryEmptyOrStaticString(cx, s, n)) {
return str;
}
if (JSInlineString::lengthFits<Latin1Char>(n)) {
return NewInlineStringDeflated<allowGC>(
cx, mozilla::Range<const char16_t>(s, n));
cx, mozilla::Range<const char16_t>(s, n), heap);
}
auto news = cx->make_pod_arena_array<Latin1Char>(js::StringBufferArena, n);
@ -1548,16 +1557,18 @@ static JSLinearString* NewStringDeflated(JSContext* cx, const char16_t* s,
MOZ_ASSERT(CanStoreCharsAsLatin1(s, n));
FillFromCompatible(news.get(), s, n);
return JSLinearString::new_<allowGC>(cx, std::move(news), n);
return JSLinearString::new_<allowGC>(cx, std::move(news), n, heap);
}
static JSLinearString* NewStringDeflatedFromLittleEndianNoGC(
JSContext* cx, LittleEndianChars chars, size_t length) {
JSContext* cx, LittleEndianChars chars, size_t length,
gc::InitialHeap heap) {
MOZ_ASSERT(CanStoreCharsAsLatin1(chars, length));
if (JSInlineString::lengthFits<Latin1Char>(length)) {
Latin1Char* storage;
JSInlineString* str = AllocateInlineString<NoGC>(cx, length, &storage);
JSInlineString* str =
AllocateInlineString<NoGC>(cx, length, &storage, heap);
if (!str) {
return nullptr;
}
@ -1575,12 +1586,13 @@ static JSLinearString* NewStringDeflatedFromLittleEndianNoGC(
FillFromCompatible(news.get(), chars, length);
return JSLinearString::new_<NoGC>(cx, std::move(news), length);
return JSLinearString::new_<NoGC>(cx, std::move(news), length, heap);
}
template <typename CharT>
JSLinearString* js::NewStringDontDeflate(
JSContext* cx, UniquePtr<CharT[], JS::FreePolicy> chars, size_t length) {
JSContext* cx, UniquePtr<CharT[], JS::FreePolicy> chars, size_t length,
gc::InitialHeap heap) {
if (JSLinearString* str = TryEmptyOrStaticString(cx, chars.get(), length)) {
return str;
}
@ -1592,106 +1604,118 @@ JSLinearString* js::NewStringDontDeflate(
cx, mozilla::Range<const CharT>(chars.get(), length));
}
return JSLinearString::new_<CanGC>(cx, std::move(chars), length);
return JSLinearString::new_<CanGC>(cx, std::move(chars), length, heap);
}
template JSLinearString* js::NewStringDontDeflate(JSContext* cx,
UniqueTwoByteChars chars,
size_t length);
size_t length,
gc::InitialHeap heap);
template JSLinearString* js::NewStringDontDeflate(JSContext* cx,
UniqueLatin1Chars chars,
size_t length);
size_t length,
gc::InitialHeap heap);
template <typename CharT>
JSLinearString* js::NewString(JSContext* cx,
UniquePtr<CharT[], JS::FreePolicy> chars,
size_t length) {
size_t length, gc::InitialHeap heap) {
if constexpr (std::is_same_v<CharT, char16_t>) {
if (CanStoreCharsAsLatin1(chars.get(), length)) {
// Deflating copies from |chars.get()| and lets |chars| be freed on
// return.
return NewStringDeflated<CanGC>(cx, chars.get(), length);
return NewStringDeflated<CanGC>(cx, chars.get(), length, heap);
}
}
return NewStringDontDeflate(cx, std::move(chars), length);
return NewStringDontDeflate(cx, std::move(chars), length, heap);
}
template JSLinearString* js::NewString(JSContext* cx, UniqueTwoByteChars chars,
size_t length);
size_t length, gc::InitialHeap heap);
template JSLinearString* js::NewString(JSContext* cx, UniqueLatin1Chars chars,
size_t length);
size_t length, gc::InitialHeap heap);
template <AllowGC allowGC, typename CharT>
JSLinearString* js::NewStringDontDeflate(
JSContext* cx, UniquePtr<CharT[], JS::FreePolicy> chars, size_t length) {
JSContext* cx, UniquePtr<CharT[], JS::FreePolicy> chars, size_t length,
gc::InitialHeap heap) {
if (JSLinearString* str = TryEmptyOrStaticString(cx, chars.get(), length)) {
return str;
}
if (JSInlineString::lengthFits<CharT>(length)) {
return NewInlineString<allowGC>(
cx, mozilla::Range<const CharT>(chars.get(), length));
cx, mozilla::Range<const CharT>(chars.get(), length), heap);
}
return JSLinearString::new_<allowGC>(cx, std::move(chars), length);
return JSLinearString::new_<allowGC>(cx, std::move(chars), length, heap);
}
template JSLinearString* js::NewStringDontDeflate<CanGC>(
JSContext* cx, UniqueTwoByteChars chars, size_t length);
JSContext* cx, UniqueTwoByteChars chars, size_t length,
gc::InitialHeap heap);
template JSLinearString* js::NewStringDontDeflate<NoGC>(
JSContext* cx, UniqueTwoByteChars chars, size_t length);
JSContext* cx, UniqueTwoByteChars chars, size_t length,
gc::InitialHeap heap);
template JSLinearString* js::NewStringDontDeflate<CanGC>(
JSContext* cx, UniqueLatin1Chars chars, size_t length);
JSContext* cx, UniqueLatin1Chars chars, size_t length,
gc::InitialHeap heap);
template JSLinearString* js::NewStringDontDeflate<NoGC>(JSContext* cx,
UniqueLatin1Chars chars,
size_t length);
size_t length,
gc::InitialHeap heap);
template <AllowGC allowGC, typename CharT>
JSLinearString* js::NewString(JSContext* cx,
UniquePtr<CharT[], JS::FreePolicy> chars,
size_t length) {
size_t length, gc::InitialHeap heap) {
if constexpr (std::is_same_v<CharT, char16_t>) {
if (CanStoreCharsAsLatin1(chars.get(), length)) {
return NewStringDeflated<allowGC>(cx, chars.get(), length);
return NewStringDeflated<allowGC>(cx, chars.get(), length, heap);
}
}
return NewStringDontDeflate<allowGC>(cx, std::move(chars), length);
return NewStringDontDeflate<allowGC>(cx, std::move(chars), length, heap);
}
template JSLinearString* js::NewString<CanGC>(JSContext* cx,
UniqueTwoByteChars chars,
size_t length);
size_t length,
gc::InitialHeap heap);
template JSLinearString* js::NewString<NoGC>(JSContext* cx,
UniqueTwoByteChars chars,
size_t length);
size_t length,
gc::InitialHeap heap);
template JSLinearString* js::NewString<CanGC>(JSContext* cx,
UniqueLatin1Chars chars,
size_t length);
size_t length,
gc::InitialHeap heap);
template JSLinearString* js::NewString<NoGC>(JSContext* cx,
UniqueLatin1Chars chars,
size_t length);
size_t length,
gc::InitialHeap heap);
namespace js {
template <AllowGC allowGC, typename CharT>
JSLinearString* NewStringCopyNDontDeflate(JSContext* cx, const CharT* s,
size_t n) {
size_t n, gc::InitialHeap heap) {
if (JSLinearString* str = TryEmptyOrStaticString(cx, s, n)) {
return str;
}
if (JSInlineString::lengthFits<CharT>(n)) {
return NewInlineString<allowGC>(cx, mozilla::Range<const CharT>(s, n));
return NewInlineString<allowGC>(cx, mozilla::Range<const CharT>(s, n),
heap);
}
auto news = cx->make_pod_arena_array<CharT>(js::StringBufferArena, n);
@ -1704,30 +1728,36 @@ JSLinearString* NewStringCopyNDontDeflate(JSContext* cx, const CharT* s,
FillChars(news.get(), s, n);
return JSLinearString::new_<allowGC>(cx, std::move(news), n);
return JSLinearString::new_<allowGC>(cx, std::move(news), n, heap);
}
template JSLinearString* NewStringCopyNDontDeflate<CanGC>(JSContext* cx,
const char16_t* s,
size_t n);
size_t n,
gc::InitialHeap heap);
template JSLinearString* NewStringCopyNDontDeflate<NoGC>(JSContext* cx,
const char16_t* s,
size_t n);
size_t n,
gc::InitialHeap heap);
template JSLinearString* NewStringCopyNDontDeflate<CanGC>(JSContext* cx,
const Latin1Char* s,
size_t n);
size_t n,
gc::InitialHeap heap);
template JSLinearString* NewStringCopyNDontDeflate<NoGC>(JSContext* cx,
const Latin1Char* s,
size_t n);
size_t n,
gc::InitialHeap heap);
static JSLinearString* NewUndeflatedStringFromLittleEndianNoGC(
JSContext* cx, LittleEndianChars chars, size_t length) {
JSContext* cx, LittleEndianChars chars, size_t length,
gc::InitialHeap heap) {
if (JSInlineString::lengthFits<char16_t>(length)) {
char16_t* storage;
JSInlineString* str = AllocateInlineString<NoGC>(cx, length, &storage);
JSInlineString* str =
AllocateInlineString<NoGC>(cx, length, &storage, heap);
if (!str) {
return nullptr;
}
@ -1744,57 +1774,63 @@ static JSLinearString* NewUndeflatedStringFromLittleEndianNoGC(
FillChars(news.get(), chars, length);
return JSLinearString::new_<NoGC>(cx, std::move(news), length);
return JSLinearString::new_<NoGC>(cx, std::move(news), length, heap);
}
JSLinearString* NewLatin1StringZ(JSContext* cx, UniqueChars chars) {
JSLinearString* NewLatin1StringZ(JSContext* cx, UniqueChars chars,
gc::InitialHeap heap) {
size_t length = strlen(chars.get());
UniqueLatin1Chars latin1(reinterpret_cast<Latin1Char*>(chars.release()));
return NewString<CanGC>(cx, std::move(latin1), length);
return NewString<CanGC>(cx, std::move(latin1), length, heap);
}
template <AllowGC allowGC, typename CharT>
JSLinearString* NewStringCopyN(JSContext* cx, const CharT* s, size_t n) {
JSLinearString* NewStringCopyN(JSContext* cx, const CharT* s, size_t n,
gc::InitialHeap heap) {
if constexpr (std::is_same_v<CharT, char16_t>) {
if (CanStoreCharsAsLatin1(s, n)) {
return NewStringDeflated<allowGC>(cx, s, n);
return NewStringDeflated<allowGC>(cx, s, n, heap);
}
}
return NewStringCopyNDontDeflate<allowGC>(cx, s, n);
return NewStringCopyNDontDeflate<allowGC>(cx, s, n, heap);
}
template JSLinearString* NewStringCopyN<CanGC>(JSContext* cx, const char16_t* s,
size_t n);
size_t n, gc::InitialHeap heap);
template JSLinearString* NewStringCopyN<NoGC>(JSContext* cx, const char16_t* s,
size_t n);
size_t n, gc::InitialHeap heap);
template JSLinearString* NewStringCopyN<CanGC>(JSContext* cx,
const Latin1Char* s, size_t n);
const Latin1Char* s, size_t n,
gc::InitialHeap heap);
template JSLinearString* NewStringCopyN<NoGC>(JSContext* cx,
const Latin1Char* s, size_t n);
const Latin1Char* s, size_t n,
gc::InitialHeap heap);
JSLinearString* NewStringFromLittleEndianNoGC(JSContext* cx,
LittleEndianChars chars,
size_t length) {
size_t length,
gc::InitialHeap heap) {
if (JSLinearString* str = TryEmptyOrStaticString(cx, chars, length)) {
return str;
}
if (CanStoreCharsAsLatin1(chars, length)) {
return NewStringDeflatedFromLittleEndianNoGC(cx, chars, length);
return NewStringDeflatedFromLittleEndianNoGC(cx, chars, length, heap);
}
return NewUndeflatedStringFromLittleEndianNoGC(cx, chars, length);
return NewUndeflatedStringFromLittleEndianNoGC(cx, chars, length, heap);
}
template <js::AllowGC allowGC>
JSLinearString* NewStringCopyUTF8N(JSContext* cx, const JS::UTF8Chars utf8) {
JSLinearString* NewStringCopyUTF8N(JSContext* cx, const JS::UTF8Chars utf8,
gc::InitialHeap heap) {
JS::SmallestEncoding encoding = JS::FindSmallestEncoding(utf8);
if (encoding == JS::SmallestEncoding::ASCII) {
return NewStringCopyN<allowGC>(cx, utf8.begin().get(), utf8.length());
return NewStringCopyN<allowGC>(cx, utf8.begin().get(), utf8.length(), heap);
}
size_t length;
@ -1806,7 +1842,7 @@ JSLinearString* NewStringCopyUTF8N(JSContext* cx, const JS::UTF8Chars utf8) {
return nullptr;
}
return NewString<allowGC>(cx, std::move(latin1), length);
return NewString<allowGC>(cx, std::move(latin1), length, heap);
}
MOZ_ASSERT(encoding == JS::SmallestEncoding::UTF16);
@ -1818,11 +1854,12 @@ JSLinearString* NewStringCopyUTF8N(JSContext* cx, const JS::UTF8Chars utf8) {
return nullptr;
}
return NewString<allowGC>(cx, std::move(utf16), length);
return NewString<allowGC>(cx, std::move(utf16), length, heap);
}
template JSLinearString* NewStringCopyUTF8N<CanGC>(JSContext* cx,
const JS::UTF8Chars utf8);
const JS::UTF8Chars utf8,
gc::InitialHeap heap);
MOZ_ALWAYS_INLINE JSString* ExternalStringCache::lookup(const char16_t* chars,
size_t len) const {
@ -1865,7 +1902,8 @@ MOZ_ALWAYS_INLINE void ExternalStringCache::put(JSString* str) {
JSString* NewMaybeExternalString(JSContext* cx, const char16_t* s, size_t n,
const JSExternalStringCallbacks* callbacks,
bool* allocatedExternal) {
bool* allocatedExternal,
gc::InitialHeap heap) {
if (JSString* str = TryEmptyOrStaticString(cx, s, n)) {
*allocatedExternal = false;
return str;
@ -1875,7 +1913,7 @@ JSString* NewMaybeExternalString(JSContext* cx, const char16_t* s, size_t n,
CanStoreCharsAsLatin1(s, n)) {
*allocatedExternal = false;
return NewInlineStringDeflated<AllowGC::CanGC>(
cx, mozilla::Range<const char16_t>(s, n));
cx, mozilla::Range<const char16_t>(s, n), heap);
}
ExternalStringCache& cache = cx->zone()->externalStringCache();

View File

@ -781,7 +781,7 @@ class JSLinearString : public JSString {
template <js::AllowGC allowGC, typename CharT>
static inline JSLinearString* new_(
JSContext* cx, js::UniquePtr<CharT[], JS::FreePolicy> chars,
size_t length);
size_t length, js::gc::InitialHeap heap);
template <typename CharT>
MOZ_ALWAYS_INLINE const CharT* nonInlineChars(
@ -937,7 +937,8 @@ class JSDependentString : public JSLinearString {
public:
static inline JSLinearString* new_(JSContext* cx, JSLinearString* base,
size_t start, size_t length);
size_t start, size_t length,
js::gc::InitialHeap heap);
#if defined(DEBUG) || defined(JS_JITSPEW)
void dumpRepresentation(js::GenericPrinter& out, int indent) const;
@ -1022,7 +1023,8 @@ class JSThinInlineString : public JSInlineString {
static const size_t MAX_LENGTH_TWO_BYTE = NUM_INLINE_CHARS_TWO_BYTE;
template <js::AllowGC allowGC>
static inline JSThinInlineString* new_(JSContext* cx);
static inline JSThinInlineString* new_(JSContext* cx,
js::gc::InitialHeap heap);
template <typename CharT>
inline CharT* init(size_t length);
@ -1060,7 +1062,8 @@ class JSFatInlineString : public JSInlineString {
public:
template <js::AllowGC allowGC>
static inline JSFatInlineString* new_(JSContext* cx);
static inline JSFatInlineString* new_(JSContext* cx,
js::gc::InitialHeap heap);
static const size_t MAX_LENGTH_LATIN1 =
JSString::NUM_INLINE_CHARS_LATIN1 + INLINE_EXTENSION_CHARS_LATIN1;
@ -1445,88 +1448,107 @@ static inline UniqueChars StringToNewUTF8CharsZ(JSContext* maybecx,
* Allocate a string with the given contents, potentially GCing in the process.
*/
template <typename CharT>
extern JSLinearString* NewString(JSContext* cx,
UniquePtr<CharT[], JS::FreePolicy> chars,
size_t length);
extern JSLinearString* NewString(
JSContext* cx, UniquePtr<CharT[], JS::FreePolicy> chars, size_t length,
js::gc::InitialHeap heap = js::gc::DefaultHeap);
/* Like NewString, but doesn't attempt to deflate to Latin1. */
template <typename CharT>
extern JSLinearString* NewStringDontDeflate(
JSContext* cx, UniquePtr<CharT[], JS::FreePolicy> chars, size_t length);
JSContext* cx, UniquePtr<CharT[], JS::FreePolicy> chars, size_t length,
js::gc::InitialHeap heap = js::gc::DefaultHeap);
/**
* Allocate a string with the given contents. If |allowGC == CanGC|, this may
* trigger a GC.
*/
template <js::AllowGC allowGC, typename CharT>
extern JSLinearString* NewString(JSContext* cx,
UniquePtr<CharT[], JS::FreePolicy> chars,
size_t length);
extern JSLinearString* NewString(
JSContext* cx, UniquePtr<CharT[], JS::FreePolicy> chars, size_t length,
js::gc::InitialHeap heap = js::gc::DefaultHeap);
/* Like NewString, but doesn't try to deflate to Latin1. */
template <js::AllowGC allowGC, typename CharT>
extern JSLinearString* NewStringDontDeflate(
JSContext* cx, UniquePtr<CharT[], JS::FreePolicy> chars, size_t length);
JSContext* cx, UniquePtr<CharT[], JS::FreePolicy> chars, size_t length,
js::gc::InitialHeap heap = js::gc::DefaultHeap);
extern JSLinearString* NewDependentString(JSContext* cx, JSString* base,
size_t start, size_t length);
extern JSLinearString* NewDependentString(
JSContext* cx, JSString* base, size_t start, size_t length,
js::gc::InitialHeap heap = js::gc::DefaultHeap);
/* Take ownership of an array of Latin1Chars. */
extern JSLinearString* NewLatin1StringZ(JSContext* cx, UniqueChars chars);
extern JSLinearString* NewLatin1StringZ(
JSContext* cx, UniqueChars chars,
js::gc::InitialHeap heap = js::gc::DefaultHeap);
/* Copy a counted string and GC-allocate a descriptor for it. */
template <js::AllowGC allowGC, typename CharT>
extern JSLinearString* NewStringCopyN(JSContext* cx, const CharT* s, size_t n);
extern JSLinearString* NewStringCopyN(
JSContext* cx, const CharT* s, size_t n,
js::gc::InitialHeap heap = js::gc::DefaultHeap);
template <js::AllowGC allowGC>
inline JSLinearString* NewStringCopyN(JSContext* cx, const char* s, size_t n) {
return NewStringCopyN<allowGC>(cx, reinterpret_cast<const Latin1Char*>(s), n);
inline JSLinearString* NewStringCopyN(
JSContext* cx, const char* s, size_t n,
js::gc::InitialHeap heap = js::gc::DefaultHeap) {
return NewStringCopyN<allowGC>(cx, reinterpret_cast<const Latin1Char*>(s), n,
heap);
}
/* Like NewStringCopyN, but doesn't try to deflate to Latin1. */
template <js::AllowGC allowGC, typename CharT>
extern JSLinearString* NewStringCopyNDontDeflate(JSContext* cx, const CharT* s,
size_t n);
extern JSLinearString* NewStringCopyNDontDeflate(
JSContext* cx, const CharT* s, size_t n,
js::gc::InitialHeap heap = js::gc::DefaultHeap);
/* Copy a C string and GC-allocate a descriptor for it. */
template <js::AllowGC allowGC>
inline JSLinearString* NewStringCopyZ(JSContext* cx, const char16_t* s) {
return NewStringCopyN<allowGC>(cx, s, js_strlen(s));
inline JSLinearString* NewStringCopyZ(
JSContext* cx, const char16_t* s,
js::gc::InitialHeap heap = js::gc::DefaultHeap) {
return NewStringCopyN<allowGC>(cx, s, js_strlen(s), heap);
}
template <js::AllowGC allowGC>
inline JSLinearString* NewStringCopyZ(JSContext* cx, const char* s) {
return NewStringCopyN<allowGC>(cx, s, strlen(s));
inline JSLinearString* NewStringCopyZ(
JSContext* cx, const char* s,
js::gc::InitialHeap heap = js::gc::DefaultHeap) {
return NewStringCopyN<allowGC>(cx, s, strlen(s), heap);
}
template <js::AllowGC allowGC>
extern JSLinearString* NewStringCopyUTF8N(JSContext* cx,
const JS::UTF8Chars utf8);
extern JSLinearString* NewStringCopyUTF8N(
JSContext* cx, const JS::UTF8Chars utf8,
js::gc::InitialHeap heap = js::gc::DefaultHeap);
template <js::AllowGC allowGC>
inline JSLinearString* NewStringCopyUTF8Z(JSContext* cx,
const JS::ConstUTF8CharsZ utf8) {
inline JSLinearString* NewStringCopyUTF8Z(
JSContext* cx, const JS::ConstUTF8CharsZ utf8,
js::gc::InitialHeap heap = js::gc::DefaultHeap) {
return NewStringCopyUTF8N<allowGC>(
cx, JS::UTF8Chars(utf8.c_str(), strlen(utf8.c_str())));
cx, JS::UTF8Chars(utf8.c_str(), strlen(utf8.c_str())), heap);
}
JSString* NewMaybeExternalString(JSContext* cx, const char16_t* s, size_t n,
const JSExternalStringCallbacks* callbacks,
bool* allocatedExternal);
JSString* NewMaybeExternalString(
JSContext* cx, const char16_t* s, size_t n,
const JSExternalStringCallbacks* callbacks, bool* allocatedExternal,
js::gc::InitialHeap heap = js::gc::DefaultHeap);
/**
* Allocate a new string consisting of |chars[0..length]| characters.
*/
extern JSLinearString* NewStringFromLittleEndianNoGC(JSContext* cx,
LittleEndianChars chars,
size_t length);
extern JSLinearString* NewStringFromLittleEndianNoGC(
JSContext* cx, LittleEndianChars chars, size_t length,
js::gc::InitialHeap heap = js::gc::DefaultHeap);
static_assert(sizeof(HashNumber) == 4);
template <AllowGC allowGC>
extern JSString* ConcatStrings(
JSContext* cx, typename MaybeRooted<JSString*, allowGC>::HandleType left,
typename MaybeRooted<JSString*, allowGC>::HandleType right);
typename MaybeRooted<JSString*, allowGC>::HandleType right,
js::gc::InitialHeap heap = js::gc::DefaultHeap);
/*
* Test if strings are equal. The caller can call the function even if str1

View File

@ -410,8 +410,8 @@ struct JSStructuredCloneReader {
bool readTransferMap();
template <typename CharT>
JSString* readStringImpl(uint32_t nchars);
JSString* readString(uint32_t data);
JSString* readStringImpl(uint32_t nchars, gc::InitialHeap heap);
JSString* readString(uint32_t data, gc::InitialHeap heap = gc::DefaultHeap);
BigInt* readBigInt(uint32_t data);
@ -425,7 +425,8 @@ struct JSStructuredCloneReader {
MOZ_MUST_USE bool readV1ArrayBuffer(uint32_t arrayType, uint32_t nelems,
MutableHandleValue vp);
JSObject* readSavedFrame(uint32_t principalsTag);
MOZ_MUST_USE bool startRead(MutableHandleValue vp);
MOZ_MUST_USE bool startRead(MutableHandleValue vp,
gc::InitialHeap strHeap = gc::DefaultHeap);
SCInput& in;
@ -2085,7 +2086,8 @@ bool JSStructuredCloneWriter::write(HandleValue v) {
}
template <typename CharT>
JSString* JSStructuredCloneReader::readStringImpl(uint32_t nchars) {
JSString* JSStructuredCloneReader::readStringImpl(uint32_t nchars,
gc::InitialHeap heap) {
if (nchars > JSString::MAX_LENGTH) {
JS_ReportErrorNumberASCII(context(), GetErrorMessage, nullptr,
JSMSG_SC_BAD_SERIALIZED_DATA, "string length");
@ -2097,14 +2099,15 @@ JSString* JSStructuredCloneReader::readStringImpl(uint32_t nchars) {
!in.readChars(chars.get(), nchars)) {
return nullptr;
}
return chars.toStringDontDeflate(context(), nchars);
return chars.toStringDontDeflate(context(), nchars, heap);
}
JSString* JSStructuredCloneReader::readString(uint32_t data) {
JSString* JSStructuredCloneReader::readString(uint32_t data,
gc::InitialHeap heap) {
uint32_t nchars = data & BitMask(31);
bool latin1 = data & (1 << 31);
return latin1 ? readStringImpl<Latin1Char>(nchars)
: readStringImpl<char16_t>(nchars);
return latin1 ? readStringImpl<Latin1Char>(nchars, heap)
: readStringImpl<char16_t>(nchars, heap);
}
BigInt* JSStructuredCloneReader::readBigInt(uint32_t data) {
@ -2453,7 +2456,8 @@ static bool PrimitiveToObject(JSContext* cx, MutableHandleValue vp) {
return true;
}
bool JSStructuredCloneReader::startRead(MutableHandleValue vp) {
bool JSStructuredCloneReader::startRead(MutableHandleValue vp,
gc::InitialHeap strHeap) {
uint32_t tag, data;
bool alreadAppended = false;
@ -2484,7 +2488,7 @@ bool JSStructuredCloneReader::startRead(MutableHandleValue vp) {
case SCTAG_STRING:
case SCTAG_STRING_OBJECT: {
JSString* str = readString(data);
JSString* str = readString(data, strHeap);
if (!str) {
return false;
}
@ -2558,7 +2562,7 @@ bool JSStructuredCloneReader::startRead(MutableHandleValue vp) {
return false;
}
JSString* str = readString(stringData);
JSString* str = readString(stringData, gc::TenuredHeap);
if (!str) {
return false;
}
@ -2605,7 +2609,7 @@ bool JSStructuredCloneReader::startRead(MutableHandleValue vp) {
case SCTAG_TRANSFER_MAP_HEADER:
case SCTAG_TRANSFER_MAP_PENDING_ENTRY:
// We should be past all the transfer map tags.
JS_ReportErrorNumberASCII(context(), GetErrorMessage, NULL,
JS_ReportErrorNumberASCII(context(), GetErrorMessage, nullptr,
JSMSG_SC_BAD_SERIALIZED_DATA, "invalid input");
return false;
@ -2931,7 +2935,7 @@ JSObject* JSStructuredCloneReader::readSavedFrame(uint32_t principalsTag) {
}
if (mutedErrors.isBoolean()) {
if (!startRead(&source) || !source.isString()) {
if (!startRead(&source, gc::TenuredHeap) || !source.isString()) {
return nullptr;
}
} else if (mutedErrors.isString()) {
@ -2975,7 +2979,13 @@ JSObject* JSStructuredCloneReader::readSavedFrame(uint32_t principalsTag) {
savedFrame->initSourceId(0);
RootedValue name(context());
if (!startRead(&name) || !(name.isString() || name.isNull())) {
if (!startRead(&name, gc::TenuredHeap)) {
return nullptr;
}
if (!(name.isString() || name.isNull())) {
JS_ReportErrorNumberASCII(context(), GetErrorMessage, nullptr,
JSMSG_SC_BAD_SERIALIZED_DATA,
"invalid saved frame cause");
return nullptr;
}
JSAtom* atomName = nullptr;
@ -2989,7 +2999,13 @@ JSObject* JSStructuredCloneReader::readSavedFrame(uint32_t principalsTag) {
savedFrame->initFunctionDisplayName(atomName);
RootedValue cause(context());
if (!startRead(&cause) || !(cause.isString() || cause.isNull())) {
if (!startRead(&cause, gc::TenuredHeap)) {
return nullptr;
}
if (!(cause.isString() || cause.isNull())) {
JS_ReportErrorNumberASCII(context(), GetErrorMessage, nullptr,
JSMSG_SC_BAD_SERIALIZED_DATA,
"invalid saved frame cause");
return nullptr;
}
JSAtom* atomCause = nullptr;