1434263 - Refactor JSString to have an IsLinear flag instead of IsFlat.

1434263 - Refactor JSString to have an IsLinear flag instead of IsFlat. Fixes crash.
This commit is contained in:
win7-7 2026-01-06 02:36:06 +02:00 committed by wuggy
commit 49bb3e3569
6 changed files with 30 additions and 31 deletions

View file

@ -1576,10 +1576,9 @@ CreateDependentString::generate(MacroAssembler& masm, const JSAtomState& names,
// Watch for undepended strings, which have a base pointer but don't
// actually share their characters with it.
Label noBase;
masm.branchTest32(Assembler::Zero, Address(base, JSString::offsetOfFlags()),
Imm32(JSString::HAS_BASE_BIT), &noBase);
masm.branchTest32(Assembler::NonZero, Address(base, JSString::offsetOfFlags()),
Imm32(JSString::FLAT_BIT), &noBase);
masm.load32(Address(base, JSString::offsetOfFlags()), temp2);
masm.and32(Imm32(JSString::TYPE_FLAGS_MASK), temp2);
masm.branch32(Assembler::NotEqual, temp2, Imm32(JSString::DEPENDENT_FLAGS), &noBase);
masm.loadPtr(Address(base, JSDependentString::offsetOfBase()), temp2);
masm.storePtr(temp1, Address(string, JSDependentString::offsetOfBase()));
masm.bind(&noBase);
@ -7719,7 +7718,7 @@ JitCompartment::generateStringConcatStub(JSContext* cx)
// lhs and rhs flags, so we just have to clear the other flags and set
// NON_ATOM_BIT to get our rope flags (Latin1 if both lhs and rhs are
// Latin1).
static_assert(JSString::ROPE_FLAGS == JSString::NON_ATOM_BIT,
static_assert(JSString::INIT_ROPE_FLAGS == JSString::NON_ATOM_BIT,
"Rope type flags must be NON_ATOM_BIT only");
masm.and32(Imm32(JSString::LATIN1_CHARS_BIT), temp1);
masm.or32(Imm32(JSString::NON_ATOM_BIT), temp1);

View file

@ -392,8 +392,7 @@ void
MacroAssembler::branchIfRope(Register str, Label* label)
{
Address flags(str, JSString::offsetOfFlags());
static_assert(JSString::ROPE_FLAGS == JSString::NON_ATOM_BIT, "Rope type flags must be 0");
branchTest32(Assembler::Zero, flags, Imm32(JSString::TYPE_FLAGS_MASK), label);
branchTest32(Assembler::Zero, flags, Imm32(JSString::LINEAR_BIT), label);
}
void
@ -403,9 +402,7 @@ MacroAssembler::branchIfRopeOrExternal(Register str, Register temp, Label* label
move32(Imm32(JSString::TYPE_FLAGS_MASK), temp);
and32(flags, temp);
static_assert(JSString::ROPE_FLAGS == JSString::NON_ATOM_BIT, "Rope type flags must be 0");
branchTest32(Assembler::Zero, temp, temp, label);
branchTest32(Assembler::Zero, temp, Imm32(JSString::LINEAR_BIT), label);
branch32(Assembler::Equal, temp, Imm32(JSString::EXTERNAL_FLAGS), label);
}
@ -413,8 +410,7 @@ void
MacroAssembler::branchIfNotRope(Register str, Label* label)
{
Address flags(str, JSString::offsetOfFlags());
static_assert(JSString::ROPE_FLAGS == JSString::NON_ATOM_BIT, "Rope type flags must be 0");
branchTest32(Assembler::NonZero, flags, Imm32(JSString::TYPE_FLAGS_MASK), label);
branchTest32(Assembler::NonZero, flags, Imm32(JSString::LINEAR_BIT), label);
}
void

View file

@ -586,9 +586,10 @@ struct Function {
struct String
{
static const uint32_t NON_ATOM_BIT = JS_BIT(0);
static const uint32_t LINEAR_BIT = JS_BIT(1);
static const uint32_t INLINE_CHARS_BIT = JS_BIT(3);
static const uint32_t LATIN1_CHARS_BIT = JS_BIT(6);
static const uint32_t ROPE_FLAGS = NON_ATOM_BIT;
static const uint32_t EXTERNAL_FLAGS = LINEAR_BIT | NON_ATOM_BIT | JS_BIT(5);
static const uint32_t TYPE_FLAGS_MASK = JS_BIT(6) - 1;
uint32_t flags;
uint32_t length;
@ -868,7 +869,7 @@ StringToLinearString(JSContext* cx, JSString* str)
{
using shadow::String;
String* s = reinterpret_cast<String*>(str);
if (MOZ_UNLIKELY((s->flags & String::TYPE_FLAGS_MASK) == String::ROPE_FLAGS))
if (MOZ_UNLIKELY(!(s->flags & String::LINEAR_BIT)))
return StringToLinearStringSlow(cx, str);
return reinterpret_cast<JSLinearString*>(str);
}

View file

@ -103,7 +103,7 @@ MOZ_ALWAYS_INLINE void
JSRope::init(js::ExclusiveContext* cx, JSString* left, JSString* right, size_t length)
{
d.u1.length = length;
d.u1.flags = ROPE_FLAGS;
d.u1.flags = INIT_ROPE_FLAGS;
if (left->hasLatin1Chars() && right->hasLatin1Chars())
d.u1.flags |= LATIN1_CHARS_BIT;
d.s.u2.left = left;

View file

@ -194,7 +194,7 @@ JSString::dumpRepresentationHeader(FILE* fp, int indent, const char* subclass) c
// Print the string's address as an actual C++ expression, to facilitate
// copy-and-paste into a debugger.
fprintf(fp, "((%s*) %p) length: %" PRIuSIZE " flags: 0x%x", subclass, this, length(), flags);
if (flags & FLAT_BIT) fputs(" FLAT", fp);
if (flags & LINEAR_BIT) fputs(" LINEAR", fp);
if (flags & HAS_BASE_BIT) fputs(" HAS_BASE", fp);
if (flags & INLINE_CHARS_BIT) fputs(" INLINE_CHARS", fp);
if (flags & NON_ATOM_BIT) fputs(" NON_ATOM", fp);
@ -488,7 +488,10 @@ JSRope::flattenInternal(ExclusiveContext* maybecx)
}
str->setNonInlineChars(wholeChars);
pos = wholeChars + left.d.u1.length;
left.d.u1.flags ^= (EXTENSIBLE_FLAGS | DEPENDENT_FLAGS);
if (IsSame<CharT, char16_t>::value)
left.d.u1.flags = DEPENDENT_FLAGS;
else
left.d.u1.flags = DEPENDENT_FLAGS | LATIN1_CHARS_BIT;
left.d.s.u3.base = (JSLinearString*)this; /* will be true on exit */
BarrierMethods<JSString*>::postBarrier((JSString**)&left.d.s.u3.base, nullptr, this);
Nursery& nursery = zone()->group()->nursery();

View file

@ -256,24 +256,24 @@ class JSString : public js::gc::Cell
*/
static const uint32_t NON_ATOM_BIT = JS_BIT(0);
static const uint32_t FLAT_BIT = JS_BIT(1);
static const uint32_t LINEAR_BIT = JS_BIT(1);
static const uint32_t HAS_BASE_BIT = JS_BIT(2);
static const uint32_t INLINE_CHARS_BIT = JS_BIT(3);
static const uint32_t ROPE_FLAGS = NON_ATOM_BIT;
static const uint32_t DEPENDENT_FLAGS = NON_ATOM_BIT | HAS_BASE_BIT;
static const uint32_t UNDEPENDED_FLAGS = NON_ATOM_BIT | FLAT_BIT | HAS_BASE_BIT;
static const uint32_t EXTENSIBLE_FLAGS = NON_ATOM_BIT | FLAT_BIT | JS_BIT(4);
static const uint32_t EXTERNAL_FLAGS = NON_ATOM_BIT | JS_BIT(5);
static const uint32_t DEPENDENT_FLAGS = NON_ATOM_BIT | LINEAR_BIT | HAS_BASE_BIT;
static const uint32_t UNDEPENDED_FLAGS = NON_ATOM_BIT | LINEAR_BIT | HAS_BASE_BIT | JS_BIT(4);
static const uint32_t EXTENSIBLE_FLAGS = NON_ATOM_BIT | LINEAR_BIT | JS_BIT(4);
static const uint32_t EXTERNAL_FLAGS = NON_ATOM_BIT | LINEAR_BIT | JS_BIT(5);
static const uint32_t FAT_INLINE_MASK = INLINE_CHARS_BIT | JS_BIT(4);
static const uint32_t PERMANENT_ATOM_MASK = NON_ATOM_BIT | JS_BIT(5);
static const uint32_t PERMANENT_ATOM_FLAGS = JS_BIT(5);
/* Initial flags for thin inline and fat inline strings. */
static const uint32_t INIT_THIN_INLINE_FLAGS = NON_ATOM_BIT | FLAT_BIT | INLINE_CHARS_BIT;
static const uint32_t INIT_FAT_INLINE_FLAGS = NON_ATOM_BIT | FLAT_BIT | FAT_INLINE_MASK;
static const uint32_t INIT_FLAT_FLAGS = NON_ATOM_BIT | FLAT_BIT;
static const uint32_t INIT_THIN_INLINE_FLAGS = NON_ATOM_BIT | LINEAR_BIT | INLINE_CHARS_BIT;
static const uint32_t INIT_FAT_INLINE_FLAGS = NON_ATOM_BIT | LINEAR_BIT | FAT_INLINE_MASK;
static const uint32_t INIT_ROPE_FLAGS = NON_ATOM_BIT;
static const uint32_t INIT_FLAT_FLAGS = NON_ATOM_BIT | LINEAR_BIT;
static const uint32_t TYPE_FLAGS_MASK = JS_BIT(6) - 1;
@ -317,14 +317,14 @@ class JSString : public js::gc::Cell
"shadow::String inlineStorage offset must match JSString");
static_assert(NON_ATOM_BIT == String::NON_ATOM_BIT,
"shadow::String::NON_ATOM_BIT must match JSString::NON_ATOM_BIT");
static_assert(LINEAR_BIT == String::LINEAR_BIT,
"shadow::String::LINEAR_BIT must match JSString::LINEAR_BIT");
static_assert(INLINE_CHARS_BIT == String::INLINE_CHARS_BIT,
"shadow::String::INLINE_CHARS_BIT must match JSString::INLINE_CHARS_BIT");
static_assert(LATIN1_CHARS_BIT == String::LATIN1_CHARS_BIT,
"shadow::String::LATIN1_CHARS_BIT must match JSString::LATIN1_CHARS_BIT");
static_assert(TYPE_FLAGS_MASK == String::TYPE_FLAGS_MASK,
"shadow::String::TYPE_FLAGS_MASK must match JSString::TYPE_FLAGS_MASK");
static_assert(ROPE_FLAGS == String::ROPE_FLAGS,
"shadow::String::ROPE_FLAGS must match JSString::ROPE_FLAGS");
}
/* Avoid lame compile errors in JSRope::flatten */
@ -373,7 +373,7 @@ class JSString : public js::gc::Cell
MOZ_ALWAYS_INLINE
bool isRope() const {
return (d.u1.flags & TYPE_FLAGS_MASK) == ROPE_FLAGS;
return !(d.u1.flags & LINEAR_BIT);
}
MOZ_ALWAYS_INLINE
@ -384,7 +384,7 @@ class JSString : public js::gc::Cell
MOZ_ALWAYS_INLINE
bool isLinear() const {
return !isRope();
return d.u1.flags & LINEAR_BIT;
}
MOZ_ALWAYS_INLINE
@ -406,7 +406,7 @@ class JSString : public js::gc::Cell
MOZ_ALWAYS_INLINE
bool isFlat() const {
return d.u1.flags & FLAT_BIT;
return isLinear() && !isDependent() && !isExternal();
}
MOZ_ALWAYS_INLINE