Files
Emilio Cobos Álvarez fe182cca64 Bug 2025271 - Simplify DOMString. r=smaug,nika,extension-reviewers,core-sessionstore-reviewers,dom-worker-reviewers,robwu,asuth
Make DOMString a regular nsAutoTString with some special methods for
performance in some hot getters. For that, we need to change a bit
nsTString:

 * Support for unowned buffers: Owned buffers now are represented by
   STRINGBUFFER|OWNED flags, rather than REFCOUNTED.

 * Inlining of the destructor: It showed up in profiles, it's also just
   a few instructions, so probably worth it. We could OOL the owned path
   I guess, if we wanted to.

 * Inlinling and reordering of NonVoidStringToJsval. Old code had
   special DOMString path inline with [buffer, literal, copy] paths,
   then out of line code with [literal, buffer, copy]. Instead,
   consolidate everything in a [buffer, literal, copy] inline path.
   Do the same for UTF8/Latin1 strings too for consistency.

Differential Revision: https://phabricator.services.mozilla.com/D288148
2026-04-13 09:33:54 +00:00

84 lines
3.0 KiB
C++

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_DOMString_h
#define mozilla_dom_DOMString_h
#include "nsAtom.h"
#include "nsDOMString.h"
#include "nsString.h"
namespace mozilla::dom {
// DOMString is an AutoTString with a few extra dangerous methods needed for
// performance in some cases, where we want to propagate a "weak" reference to a
// string up. See bug 2023628 for some context.
//
// Some of these methods could actually live in nsTSubString, perhaps, but
// they're hard to get right, and make assumptions about what kind of strings
// they are called with in order to save cycles.
class DOMString final : public nsAutoString {
public:
enum NullHandling { eTreatNullAsNull, eTreatNullAsEmpty, eNullNotExpected };
void SetKnownLiveAtom(nsAtom* aAtom, NullHandling aNullHandling) {
AssertSetKnownLivePrecondition();
MOZ_ASSERT(aAtom || aNullHandling != eNullNotExpected);
if (aNullHandling == eNullNotExpected || aAtom) {
// Static atoms are backed by literals, and dynamic ones by StringBuffer.
DataFlags flags = DataFlags::TERMINATED;
const char_type* data;
if (aAtom->IsStatic()) {
data = aAtom->AsStatic()->String();
flags |= DataFlags::LITERAL;
} else {
MOZ_ASSERT(aAtom->AsDynamic()->StringBuffer());
data = aAtom->AsDynamic()->String();
flags |= DataFlags::STRINGBUFFER;
}
SetData(const_cast<char_type*>(data), aAtom->GetLength(), flags);
AssertValid();
} else if (aNullHandling == eTreatNullAsNull) {
SetNull();
}
}
void SetKnownLiveString(const nsAString& aString) {
AssertSetKnownLivePrecondition();
MOZ_ASSERT(aString.IsTerminated(),
"If we are not terminated, then we need copying or so");
// NOTE: This is a bit subtle, but the data flags we copy are basically "all
// except OWNED | INLINE", which cause us to copy null-ness,
// refcounted-ness, etc.
const char_type* data = aString.Data();
SetData(
const_cast<char_type*>(data), aString.Length(),
aString.GetDataFlags() & (DataFlags::TERMINATED | DataFlags::LITERAL |
DataFlags::STRINGBUFFER | DataFlags::VOIDED));
AssertValid();
}
void SetKnownLiveStringBuffer(StringBuffer* aBuffer, LengthStorage aLen) {
AssertSetKnownLivePrecondition();
MOZ_ASSERT(aBuffer);
// NOTE: No DataFlags::OWNED.
SetData(static_cast<char_type*>(aBuffer->Data()), aLen,
DataFlags::STRINGBUFFER | DataFlags::TERMINATED);
AssertValid();
}
void SetNull() { SetIsVoid(true); }
bool IsNull() const { return IsVoid(); }
private:
void AssertSetKnownLivePrecondition() {
MOZ_ASSERT(IsEmpty(), "We rely on this being called only on empty strings");
MOZ_ASSERT(!(mDataFlags & DataFlags::OWNED), "Would leak");
}
};
} // namespace mozilla::dom
#endif // mozilla_dom_DOMString_h