summaryrefslogtreecommitdiffstats
path: root/js/src/vm/StringType.cpp
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-15 03:35:49 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-15 03:35:49 +0000
commitd8bbc7858622b6d9c278469aab701ca0b609cddf (patch)
treeeff41dc61d9f714852212739e6b3738b82a2af87 /js/src/vm/StringType.cpp
parentReleasing progress-linux version 125.0.3-1~progress7.99u1. (diff)
downloadfirefox-d8bbc7858622b6d9c278469aab701ca0b609cddf.tar.xz
firefox-d8bbc7858622b6d9c278469aab701ca0b609cddf.zip
Merging upstream version 126.0.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'js/src/vm/StringType.cpp')
-rw-r--r--js/src/vm/StringType.cpp60
1 files changed, 42 insertions, 18 deletions
diff --git a/js/src/vm/StringType.cpp b/js/src/vm/StringType.cpp
index 63afd8864b..b735b91b71 100644
--- a/js/src/vm/StringType.cpp
+++ b/js/src/vm/StringType.cpp
@@ -380,9 +380,13 @@ void ForEachStringFlag(const JSString* str, uint32_t flags, KnownF known,
static_assert(JSString::LINEAR_IS_EXTENSIBLE_BIT ==
JSString::INLINE_IS_FAT_BIT);
if (str->isLinear()) {
- known("EXTENSIBLE");
- } else if (str->isInline()) {
- known("FAT");
+ if (str->isInline()) {
+ known("FAT");
+ } else if (!str->isAtom()) {
+ known("EXTENSIBLE");
+ } else {
+ unknown(i);
+ }
} else {
unknown(i);
}
@@ -407,9 +411,6 @@ void ForEachStringFlag(const JSString* str, uint32_t flags, KnownF known,
case JSString::INDEX_VALUE_BIT:
known("INDEX_VALUE_BIT");
break;
- case JSString::NON_DEDUP_BIT:
- known("NON_DEDUP_BIT");
- break;
case JSString::IN_STRING_TO_ATOM_CACHE:
known("IN_STRING_TO_ATOM_CACHE");
break;
@@ -417,7 +418,7 @@ void ForEachStringFlag(const JSString* str, uint32_t flags, KnownF known,
if (str->isRope()) {
known("FLATTEN_VISIT_RIGHT");
} else {
- unknown(i);
+ known("NON_DEDUP_BIT");
}
break;
case JSString::FLATTEN_FINISH_NODE:
@@ -638,11 +639,20 @@ static MOZ_ALWAYS_INLINE JSString::OwnedChars<CharT> AllocChars(JSContext* cx,
MOZ_ASSERT(cx->nursery().isEnabled());
auto [buffer, isMalloced] = cx->nursery().allocateBuffer(
cx->zone(), length * sizeof(CharT), js::StringBufferArena);
+ if (!buffer) {
+ ReportOutOfMemory(cx);
+ return {nullptr, 0, false, false};
+ }
return {static_cast<CharT*>(buffer), length, isMalloced, isMalloced};
}
auto buffer = cx->make_pod_arena_array<CharT>(js::StringBufferArena, length);
+ if (!buffer) {
+ ReportOutOfMemory(cx);
+ return {nullptr, 0, false, false};
+ }
+
return {std::move(buffer), length, true};
}
@@ -914,6 +924,14 @@ JSLinearString* JSRope::flattenInternal(JSRope* root) {
* JSDependentStrings pointing to them already. Stealing the buffer doesn't
* change its address, only its owning JSExtensibleString, so all chars()
* pointers in the JSDependentStrings are still valid.
+ *
+ * This chain of dependent strings could be problematic if the base string
+ * moves, either because it was initially allocated in the nursery or it
+ * gets deduplicated, because you might have a dependent ->
+ * tenured dependent -> nursery base string, and the store buffer would
+ * only capture the latter edge. Prevent this case from happening by
+ * marking the root as nondeduplicatable if the extensible string
+ * optimization applied.
*/
const size_t wholeLength = root->length();
size_t wholeCapacity;
@@ -1068,8 +1086,12 @@ finish_root:
left.setLengthAndFlags(left.length(), StringFlagsForCharType<CharT>(flags));
left.d.s.u3.base = &root->asLinear();
if (left.isTenured() && !root->isTenured()) {
- // leftmost child -> root is a tenured -> nursery edge.
+ // leftmost child -> root is a tenured -> nursery edge. Put the leftmost
+ // child in the store buffer and prevent the root's chars from moving or
+ // being freed (because the leftmost child may have a tenured dependent
+ // string that cannot be updated.)
root->storeBuffer()->putWholeCell(&left);
+ root->setNonDeduplicatable();
}
}
@@ -1455,16 +1477,18 @@ uint32_t JSAtom::getIndexSlow() const {
: AtomCharsToIndex(twoByteChars(nogc), len);
}
-static void MarkStringAndBasesNonDeduplicatable(JSLinearString* s) {
- while (true) {
- if (!s->isTenured()) {
- s->setNonDeduplicatable();
- }
- if (!s->hasBase()) {
- break;
- }
+// Prevent the actual owner of the string's characters from being deduplicated
+// (and thus freeing its characters, which would invalidate the ASSC's chars
+// pointer). Intermediate dependent strings on the chain can be deduplicated,
+// since the base will be updated to the root base during tenuring anyway and
+// the intermediates won't matter.
+void PreventRootBaseDeduplication(JSLinearString* s) {
+ while (s->hasBase()) {
s = s->base();
}
+ if (!s->isTenured()) {
+ s->setNonDeduplicatable();
+ }
}
bool AutoStableStringChars::init(JSContext* cx, JSString* s) {
@@ -1492,7 +1516,7 @@ bool AutoStableStringChars::init(JSContext* cx, JSString* s) {
twoByteChars_ = linearString->rawTwoByteChars();
}
- MarkStringAndBasesNonDeduplicatable(linearString);
+ PreventRootBaseDeduplication(linearString);
s_ = linearString;
return true;
@@ -1518,7 +1542,7 @@ bool AutoStableStringChars::initTwoByte(JSContext* cx, JSString* s) {
state_ = TwoByte;
twoByteChars_ = linearString->rawTwoByteChars();
- MarkStringAndBasesNonDeduplicatable(linearString);
+ PreventRootBaseDeduplication(linearString);
s_ = linearString;
return true;