Skip to content
This repository was archived by the owner on Jul 9, 2025. It is now read-only.

Commit 5bb04f3

Browse files
committed
Bug 1706694 - Don't overwrite leftmost rope's internals at the start when reusing the leftmost child buffer in string flattening r=jandem
This is unnecessary and was causing problems. We can leave the leftmost rope to be handled in the same way as all the other ropes, and move the special case to just avoid copying the chars when reusing the leftmost buffer. The problem was that now we always barrier ropes, before overwriting the left child pointer with the parent pointer. If this happens during incremental GC we must ensure we haven't already overwritten this pointer we the buffer pointer. This patch also moves changing the leftmost string into a dependent string until the end. Depends on D113316 Differential Revision: https://phabricator.services.mozilla.com/D113503
1 parent 384fb3d commit 5bb04f3

File tree

1 file changed

+39
-46
lines changed

1 file changed

+39
-46
lines changed

js/src/vm/StringType.cpp

Lines changed: 39 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -622,15 +622,15 @@ static bool UpdateNurseryBuffersOnTransfer(js::Nursery& nursery, JSString* from,
622622
return true;
623623
}
624624

625-
static bool CanReuseLeftmostBuffer(JSRope* leftmostRope, size_t wholeLength,
625+
static bool CanReuseLeftmostBuffer(JSString* leftmostChild, size_t wholeLength,
626626
bool hasTwoByteChars) {
627-
if (!leftmostRope->leftChild()->isExtensible()) {
627+
if (!leftmostChild->isExtensible()) {
628628
return false;
629629
}
630630

631-
JSExtensibleString& leftmostChild = leftmostRope->leftChild()->asExtensible();
632-
return leftmostChild.capacity() >= wholeLength &&
633-
leftmostChild.hasTwoByteChars() == hasTwoByteChars;
631+
JSExtensibleString& str = leftmostChild->asExtensible();
632+
return str.capacity() >= wholeLength &&
633+
str.hasTwoByteChars() == hasTwoByteChars;
634634
}
635635

636636
JSLinearString* JSRope::flatten(JSContext* maybecx) {
@@ -733,49 +733,24 @@ JSLinearString* JSRope::flattenInternal(JSRope* root) {
733733
while (leftmostRope->leftChild()->isRope()) {
734734
leftmostRope = &leftmostRope->leftChild()->asRope();
735735
}
736+
JSString* leftmostChild = leftmostRope->leftChild();
736737

737738
bool reuseLeftmostBuffer = CanReuseLeftmostBuffer(
738-
leftmostRope, wholeLength, std::is_same_v<CharT, char16_t>);
739-
740-
uint32_t leftmostChildLength = 0; // Only set if we reuse leftmost buffer.
739+
leftmostChild, wholeLength, std::is_same_v<CharT, char16_t>);
741740

742741
if (reuseLeftmostBuffer) {
743-
JSExtensibleString& left = leftmostRope->leftChild()->asExtensible();
744-
size_t capacity = left.capacity();
742+
JSExtensibleString& left = leftmostChild->asExtensible();
743+
wholeCapacity = left.capacity();
745744
wholeChars = const_cast<CharT*>(left.nonInlineChars<CharT>(nogc));
746-
wholeCapacity = capacity;
747745

748746
// Nursery::registerMallocedBuffer is fallible, so attempt it first before
749747
// doing anything irreversible.
750748
if (!UpdateNurseryBuffersOnTransfer(nursery, &left, root, wholeChars,
751749
wholeCapacity * sizeof(CharT))) {
752750
return nullptr;
753751
}
754-
755-
ropeBarrierDuringFlattening<usingBarrier>(leftmostRope);
756-
leftmostRope->setNonInlineChars(wholeChars);
757-
leftmostChildLength = left.length();
758-
759-
// Remove memory association for left node we're about to make into a
760-
// dependent string.
761-
if (left.isTenured()) {
762-
RemoveCellMemory(&left, left.allocSize(), MemoryUse::StringContents);
763-
}
764-
765-
uint32_t flags = INIT_DEPENDENT_FLAGS;
766-
if (left.inStringToAtomCache()) {
767-
flags |= IN_STRING_TO_ATOM_CACHE;
768-
}
769-
left.setLengthAndFlags(leftmostChildLength,
770-
StringFlagsForCharType<CharT>(flags));
771-
left.d.s.u3.base = (JSLinearString*)root; /* will be true on exit */
772-
if (left.isTenured() && !root->isTenured()) {
773-
// leftmost child -> root is a tenured -> nursery edge.
774-
root->storeBuffer()->putWholeCell(&left);
775-
}
776752
} else {
777753
// If we can't reuse the leftmost child's buffer, allocate a new one.
778-
779754
if (!AllocChars(root, wholeLength, &wholeChars, &wholeCapacity)) {
780755
return nullptr;
781756
}
@@ -807,19 +782,16 @@ first_visit_node : {
807782
parent = nullptr;
808783
parentFlag = 0;
809784

810-
if (reuseLeftmostBuffer && str == leftmostRope) {
811-
// Left child has already been overwritten.
812-
pos += leftmostChildLength;
813-
goto visit_right_child;
814-
}
815785
if (left.isRope()) {
816786
/* Return to this node when 'left' done, then goto visit_right_child. */
817787
parent = str;
818788
parentFlag = FLATTEN_VISIT_RIGHT;
819789
str = &left;
820790
goto first_visit_node;
821791
}
822-
CopyChars(pos, left.asLinear());
792+
if (!(reuseLeftmostBuffer && &left == leftmostChild)) {
793+
CopyChars(pos, left.asLinear());
794+
}
823795
pos += left.length();
824796
}
825797

@@ -881,12 +853,33 @@ finish_node : {
881853
MOZ_ASSERT(str == root);
882854
MOZ_ASSERT(pos == wholeChars + wholeLength);
883855

884-
str->setLengthAndFlags(wholeLength,
885-
StringFlagsForCharType<CharT>(EXTENSIBLE_FLAGS));
886-
str->setNonInlineChars(wholeChars);
887-
str->d.s.u3.capacity = wholeCapacity;
888-
if (str->isTenured()) {
889-
AddCellMemory(str, str->asLinear().allocSize(), MemoryUse::StringContents);
856+
root->setLengthAndFlags(wholeLength,
857+
StringFlagsForCharType<CharT>(EXTENSIBLE_FLAGS));
858+
root->setNonInlineChars(wholeChars);
859+
root->d.s.u3.capacity = wholeCapacity;
860+
if (root->isTenured()) {
861+
AddCellMemory(root, root->asLinear().allocSize(),
862+
MemoryUse::StringContents);
863+
}
864+
865+
if (reuseLeftmostBuffer) {
866+
// Remove memory association for left node we're about to make into a
867+
// dependent string.
868+
JSString& left = *leftmostChild;
869+
if (left.isTenured()) {
870+
RemoveCellMemory(&left, left.allocSize(), MemoryUse::StringContents);
871+
}
872+
873+
uint32_t flags = INIT_DEPENDENT_FLAGS;
874+
if (left.inStringToAtomCache()) {
875+
flags |= IN_STRING_TO_ATOM_CACHE;
876+
}
877+
left.setLengthAndFlags(left.length(), StringFlagsForCharType<CharT>(flags));
878+
left.d.s.u3.base = &root->asLinear();
879+
if (left.isTenured() && !root->isTenured()) {
880+
// leftmost child -> root is a tenured -> nursery edge.
881+
root->storeBuffer()->putWholeCell(&left);
882+
}
890883
}
891884

892885
return &root->asLinear();

0 commit comments

Comments
 (0)