diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-06-12 05:43:14 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-06-12 05:43:14 +0000 |
commit | 8dd16259287f58f9273002717ec4d27e97127719 (patch) | |
tree | 3863e62a53829a84037444beab3abd4ed9dfc7d0 /js/src/vm/StringType.h | |
parent | Releasing progress-linux version 126.0.1-1~progress7.99u1. (diff) | |
download | firefox-8dd16259287f58f9273002717ec4d27e97127719.tar.xz firefox-8dd16259287f58f9273002717ec4d27e97127719.zip |
Merging upstream version 127.0.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | js/src/vm/StringType.h | 148 |
1 files changed, 115 insertions, 33 deletions
diff --git a/js/src/vm/StringType.h b/js/src/vm/StringType.h index 38dea85c60..4073c45c70 100644 --- a/js/src/vm/StringType.h +++ b/js/src/vm/StringType.h @@ -147,6 +147,8 @@ bool CheckStringIsIndex(const CharT* s, size_t length, uint32_t* indexp); * JSLinearString latin1Chars, twoByteChars / - * | * +-- JSDependentString base / - + * | | + * | +-- JSAtomRefString - / base points to an atom * | * +-- JSExternalString - / char array memory managed by embedding * | @@ -275,6 +277,7 @@ class JSString : public js::gc::CellWithLengthAndFlags { } u2; union { JSLinearString* base; /* JSDependentString */ + JSAtom* atom; /* JSAtomRefString */ JSString* right; /* JSRope */ size_t capacity; /* JSLinearString (extensible) */ const JSExternalStringCallbacks* @@ -317,28 +320,30 @@ class JSString : public js::gc::CellWithLengthAndFlags { * String Instance Subtype * type encoding predicate * ----------------------------------------- - * Rope 000000 000 xxxx0x xxx - * Linear 000010 000 xxxx1x xxx - * Dependent 000110 000 xxx1xx xxx - * External 100010 000 100010 xxx - * Extensible 010010 000 010010 xxx - * Inline 001010 000 xx1xxx xxx - * FatInline 011010 000 x11xxx xxx - * JSAtom - xxxxx1 xxx - * NormalAtom 000011 000 xx0xx1 xxx - * PermanentAtom 100011 000 1xxxx1 xxx - * ThinInlineAtom 001011 000 x01xx1 xxx - * FatInlineAtom 011011 000 x11xx1 xxx - * |||||| ||| - * |||||| ||\- [0] reserved (FORWARD_BIT) - * |||||| |\-- [1] reserved - * |||||| \--- [2] reserved - * |||||\----- [3] IsAtom - * ||||\------ [4] IsLinear - * |||\------- [5] IsDependent - * ||\-------- [6] IsInline - * |\--------- [7] FatInlineAtom/Extensible - * \---------- [8] External/Permanent + * Rope 0000000 000 xxxxx0x xxx + * Linear 0000010 000 xxxxx1x xxx + * Dependent 0000110 000 xxxx1xx xxx + * AtomRef 1000110 000 1xxxxxx xxx + * External 0100010 000 x100010 xxx + * Extensible 0010010 000 x010010 xxx + * Inline 0001010 000 xxx1xxx xxx + * FatInline 0011010 000 xx11xxx xxx + * JSAtom - xxxxxx1 xxx + * NormalAtom 0000011 000 xxx0xx1 xxx + * PermanentAtom 0100011 000 x1xxxx1 xxx + * ThinInlineAtom 0001011 000 xx01xx1 xxx + * FatInlineAtom 0011011 000 xx11xx1 xxx + * ||||||| ||| + * ||||||| ||\- [0] reserved (FORWARD_BIT) + * ||||||| |\-- [1] reserved + * ||||||| \--- [2] reserved + * ||||||\----- [3] IsAtom + * |||||\------ [4] IsLinear + * ||||\------- [5] IsDependent + * |||\-------- [6] IsInline + * ||\--------- [7] FatInlineAtom/Extensible + * |\---------- [8] External/Permanent + * \----------- [9] AtomRef * * Bits 0..2 are reserved for use by the GC (see * gc::CellFlagBitsReservedForGC). In particular, bit 0 is currently used for @@ -364,6 +369,8 @@ class JSString : public js::gc::CellWithLengthAndFlags { static const uint32_t LINEAR_BIT = js::Bit(4); static const uint32_t DEPENDENT_BIT = js::Bit(5); static const uint32_t INLINE_CHARS_BIT = js::Bit(6); + // Indicates a dependent string pointing to an atom + static const uint32_t ATOM_REF_BIT = js::Bit(9); static const uint32_t LINEAR_IS_EXTENSIBLE_BIT = js::Bit(7); static const uint32_t INLINE_IS_FAT_BIT = js::Bit(7); @@ -383,11 +390,19 @@ class JSString : public js::gc::CellWithLengthAndFlags { static const uint32_t INIT_ROPE_FLAGS = 0; static const uint32_t INIT_LINEAR_FLAGS = LINEAR_BIT; static const uint32_t INIT_DEPENDENT_FLAGS = LINEAR_BIT | DEPENDENT_BIT; + static const uint32_t INIT_ATOM_REF_FLAGS = + INIT_DEPENDENT_FLAGS | ATOM_REF_BIT; - static const uint32_t TYPE_FLAGS_MASK = js::BitMask(9) - js::BitMask(3); + static const uint32_t TYPE_FLAGS_MASK = js::BitMask(10) - js::BitMask(3); static_assert((TYPE_FLAGS_MASK & js::gc::HeaderWord::RESERVED_MASK) == 0, "GC reserved bits must not be used for Strings"); + // Whether this atom's characters store an uint32 index value less than or + // equal to MAX_ARRAY_INDEX. This bit means something different if the + // string is not an atom (see ATOM_REF_BIT) + // See JSLinearString::isIndex. + static const uint32_t ATOM_IS_INDEX_BIT = js::Bit(9); + // Linear strings: // - Content and representation are Latin-1 characters. // - Unmodifiable after construction. @@ -397,12 +412,7 @@ class JSString : public js::gc::CellWithLengthAndFlags { // - Flag may be cleared when the rope is changed into a dependent string. // // Also see LATIN1_CHARS_BIT description under "Flag Encoding". - static const uint32_t LATIN1_CHARS_BIT = js::Bit(9); - - // Whether this atom's characters store an uint32 index value less than or - // equal to MAX_ARRAY_INDEX. Not used for non-atomized strings. - // See JSLinearString::isIndex. - static const uint32_t ATOM_IS_INDEX_BIT = js::Bit(10); + static const uint32_t LATIN1_CHARS_BIT = js::Bit(10); static const uint32_t INDEX_VALUE_BIT = js::Bit(11); static const uint32_t INDEX_VALUE_SHIFT = 16; @@ -424,6 +434,11 @@ class JSString : public js::gc::CellWithLengthAndFlags { static const uint32_t FLATTEN_MASK = FLATTEN_VISIT_RIGHT | FLATTEN_FINISH_NODE; + // Indicates that this string is depended on by another string. A rope should + // never be depended on, and this should never be set during flattening, so + // we can reuse the FLATTEN_VISIT_RIGHT bit. + static const uint32_t DEPENDED_ON_BIT = FLATTEN_VISIT_RIGHT; + static const uint32_t PINNED_ATOM_BIT = js::Bit(15); static const uint32_t PERMANENT_ATOM_MASK = ATOM_BIT | PINNED_ATOM_BIT | ATOM_IS_PERMANENT_BIT; @@ -543,6 +558,35 @@ class JSString : public js::gc::CellWithLengthAndFlags { return flags() >> INDEX_VALUE_SHIFT; } + /* + * Whether any dependent strings point to this string's chars. This is needed + * so that we don't replace the string with a forwarded atom and free its + * buffer. + * + * NOTE: we specifically do not set this for atoms, because they are accessed + * on many threads and we don't want to mess with their flags if we don't + * have to, and it is safe because atoms will never be replaced by an atom + * ref. + */ + bool isDependedOn() const { + bool result = flags() & DEPENDED_ON_BIT; + MOZ_ASSERT_IF(result, !isRope() && !isAtom()); + return result; + } + + bool assertIsValidBase() const { + // See isDependedOn comment for why we're excluding atoms + return isAtom() || isDependedOn(); + } + + void setDependedOn() { + MOZ_ASSERT(!isRope()); + if (isAtom()) { + return; + } + setFlagBit(DEPENDED_ON_BIT); + } + inline size_t allocSize() const; /* Fallible conversions to more-derived string types. */ @@ -573,6 +617,11 @@ class JSString : public js::gc::CellWithLengthAndFlags { bool isDependent() const { return flags() & DEPENDENT_BIT; } MOZ_ALWAYS_INLINE + bool isAtomRef() const { + return (flags() & ATOM_REF_BIT) && !(flags() & ATOM_BIT); + } + + MOZ_ALWAYS_INLINE JSDependentString& asDependent() const { MOZ_ASSERT(isDependent()); return *(JSDependentString*)this; @@ -668,6 +717,8 @@ class JSString : public js::gc::CellWithLengthAndFlags { inline JSLinearString* base() const; + inline JSAtom* atom() const; + // The base may be forwarded and becomes a relocation overlay. // The return value can be a relocation overlay when the base is forwarded, // or the return value can be the actual base when it is not forwarded. @@ -678,6 +729,8 @@ class JSString : public js::gc::CellWithLengthAndFlags { // Only called by the GC during nursery collection. inline void setBase(JSLinearString* newBase); + bool tryReplaceWithAtomRef(JSAtom* atom); + void traceBase(JSTracer* trc); /* Only called by the GC for strings with the AllocKind::STRING kind. */ @@ -1182,6 +1235,20 @@ class JSDependentString : public JSLinearString { static_assert(sizeof(JSDependentString) == sizeof(JSString), "string subclasses must be binary-compatible with JSString"); +class JSAtomRefString : public JSDependentString { + friend class JSString; + friend class js::gc::CellAllocator; + friend class js::jit::MacroAssembler; + + public: + inline static size_t offsetOfAtom() { + return offsetof(JSAtomRefString, d.s.u3.atom); + } +}; + +static_assert(sizeof(JSAtomRefString) == sizeof(JSString), + "string subclasses must be binary-compatible with JSString"); + class JSExtensibleString : public JSLinearString { /* Vacuous and therefore unimplemented. */ bool isExtensible() const = delete; @@ -1737,7 +1804,9 @@ inline JSLinearString* NewStringCopy( } /* Copy a counted string and GC-allocate a descriptor for it. */ -template <js::AllowGC allowGC, typename CharT> +template < + js::AllowGC allowGC, typename CharT, + typename std::enable_if_t<!std::is_same_v<CharT, unsigned char>>* = nullptr> inline JSLinearString* NewStringCopy( JSContext* cx, std::basic_string_view<CharT> s, js::gc::Heap heap = js::gc::Heap::Default) { @@ -2030,10 +2099,19 @@ MOZ_ALWAYS_INLINE JSLinearString* JSString::ensureLinear(JSContext* cx) { inline JSLinearString* JSString::base() const { MOZ_ASSERT(hasBase()); - MOZ_ASSERT(!d.s.u3.base->isInline()); + MOZ_ASSERT_IF(!isAtomRef(), !d.s.u3.base->isInline()); + MOZ_ASSERT(d.s.u3.base->assertIsValidBase()); + if (isAtomRef()) { + return static_cast<JSLinearString*>(d.s.u3.atom); + } return d.s.u3.base; } +inline JSAtom* JSString::atom() const { + MOZ_ASSERT(isAtomRef()); + return d.s.u3.atom; +} + inline JSLinearString* JSString::nurseryBaseOrRelocOverlay() const { MOZ_ASSERT(hasBase()); return d.s.u3.base; @@ -2184,7 +2262,9 @@ MOZ_ALWAYS_INLINE bool JSAtom::lengthFitsInline<char16_t>(size_t length) { template <> MOZ_ALWAYS_INLINE void JSString::setNonInlineChars(const char16_t* chars) { // Check that the new buffer is located in the StringBufferArena - checkStringCharsArena(chars); + if (!(isAtomRef() && atom()->isInline())) { + checkStringCharsArena(chars); + } d.s.u2.nonInlineCharsTwoByte = chars; } @@ -2192,7 +2272,9 @@ template <> MOZ_ALWAYS_INLINE void JSString::setNonInlineChars( const JS::Latin1Char* chars) { // Check that the new buffer is located in the StringBufferArena - checkStringCharsArena(chars); + if (!(isAtomRef() && atom()->isInline())) { + checkStringCharsArena(chars); + } d.s.u2.nonInlineCharsLatin1 = chars; } |