Bug 1713022 - Part 3: Atomize from chars directly when deserializing structured clone data r=sfink

Depends on D184003

Differential Revision: https://phabricator.services.mozilla.com/D184019
This commit is contained in:
Jon Coppeard 2023-07-19 18:31:39 +00:00
parent 615e1c153f
commit d32351d502
2 changed files with 61 additions and 51 deletions

View File

@ -7,6 +7,8 @@
#ifndef vm_InlineCharBuffer_inl_h
#define vm_InlineCharBuffer_inl_h
#include "vm/JSAtomUtils.h"
#include "vm/StringType-inl.h"
namespace js {
@ -151,6 +153,11 @@ class MOZ_NON_PARAM InlineCharBuffer {
return NewString<CanGC>(cx, std::move(heapStorage), length, heap);
}
JSAtom* toAtom(JSContext* cx, size_t length) {
MOZ_ASSERT(length == lastRequestedLength);
return AtomizeChars(cx, get(), length);
}
};
} /* namespace js */

View File

@ -434,9 +434,14 @@ struct JSStructuredCloneReader {
[[nodiscard]] bool readUint32(uint32_t* num);
enum ShouldAtomizeStrings : bool {
DontAtomizeStrings = false,
AtomizeStrings = true
};
template <typename CharT>
JSString* readStringImpl(uint32_t nchars, gc::Heap heap);
JSString* readString(uint32_t data, gc::Heap heap = gc::Heap::Default);
JSString* readStringImpl(uint32_t nchars, ShouldAtomizeStrings atomize);
JSString* readString(uint32_t data, ShouldAtomizeStrings atomize);
BigInt* readBigInt(uint32_t data);
@ -471,8 +476,9 @@ struct JSStructuredCloneReader {
[[nodiscard]] bool readObjectField(HandleObject obj, HandleValue key);
[[nodiscard]] bool startRead(MutableHandleValue vp,
gc::Heap strHeap = gc::Heap::Default);
[[nodiscard]] bool startRead(
MutableHandleValue vp,
ShouldAtomizeStrings atomizeStrings = DontAtomizeStrings);
static void NurseryCollectionCallback(JSContext* cx,
JS::GCNurseryProgress progress,
@ -2478,32 +2484,34 @@ void JSStructuredCloneReader::NurseryCollectionCallback(
}
template <typename CharT>
JSString* JSStructuredCloneReader::readStringImpl(uint32_t nchars,
gc::Heap heap) {
if (nchars > JSString::MAX_LENGTH) {
JS_ReportErrorNumberASCII(context(), GetErrorMessage, nullptr,
JSMSG_SC_BAD_SERIALIZED_DATA, "string length");
return nullptr;
}
JSString* JSStructuredCloneReader::readStringImpl(
uint32_t nchars, ShouldAtomizeStrings atomize) {
InlineCharBuffer<CharT> chars;
if (!chars.maybeAlloc(context(), nchars) ||
!in.readChars(chars.get(), nchars)) {
return nullptr;
}
if (gcHeap == gc::Heap::Tenured) {
heap = gc::Heap::Tenured;
if (atomize) {
return chars.toAtom(context(), nchars);
}
return chars.toStringDontDeflate(context(), nchars, heap);
return chars.toStringDontDeflate(context(), nchars, gcHeap);
}
JSString* JSStructuredCloneReader::readString(uint32_t data, gc::Heap heap) {
JSString* JSStructuredCloneReader::readString(uint32_t data,
ShouldAtomizeStrings atomize) {
uint32_t nchars = data & BitMask(31);
bool latin1 = data & (1 << 31);
return latin1 ? readStringImpl<Latin1Char>(nchars, heap)
: readStringImpl<char16_t>(nchars, heap);
if (nchars > JSString::MAX_LENGTH) {
JS_ReportErrorNumberASCII(context(), GetErrorMessage, nullptr,
JSMSG_SC_BAD_SERIALIZED_DATA, "string length");
return nullptr;
}
return latin1 ? readStringImpl<Latin1Char>(nchars, atomize)
: readStringImpl<char16_t>(nchars, atomize);
}
[[nodiscard]] bool JSStructuredCloneReader::readUint32(uint32_t* num) {
@ -2892,7 +2900,7 @@ static bool PrimitiveToObject(JSContext* cx, MutableHandleValue vp) {
}
bool JSStructuredCloneReader::startRead(MutableHandleValue vp,
gc::Heap strHeap) {
ShouldAtomizeStrings atomizeStrings) {
uint32_t tag, data;
bool alreadAppended = false;
@ -2925,7 +2933,7 @@ bool JSStructuredCloneReader::startRead(MutableHandleValue vp,
case SCTAG_STRING:
case SCTAG_STRING_OBJECT: {
JSString* str = readString(data, strHeap);
JSString* str = readString(data, atomizeStrings);
if (!str) {
return false;
}
@ -2999,15 +3007,12 @@ bool JSStructuredCloneReader::startRead(MutableHandleValue vp,
return false;
}
JSString* str = readString(stringData, gc::Heap::Tenured);
JSString* str = readString(stringData, AtomizeStrings);
if (!str) {
return false;
}
Rooted<JSAtom*> atom(context(), AtomizeString(context(), str));
if (!atom) {
return false;
}
Rooted<JSAtom*> atom(context(), &str->asAtom());
NewObjectKind kind =
gcHeap == gc::Heap::Tenured ? TenuredObject : GenericObject;
@ -3434,12 +3439,12 @@ JSObject* JSStructuredCloneReader::readSavedFrameHeader(
// The |mutedErrors| boolean is present in all new structured-clone data,
// but in older data it will be absent and only the |source| string will be
// found.
if (!startRead(&mutedErrors)) {
if (!startRead(&mutedErrors, AtomizeStrings)) {
return nullptr;
}
if (mutedErrors.isBoolean()) {
if (!startRead(&source, gc::Heap::Tenured) || !source.isString()) {
if (!startRead(&source, AtomizeStrings) || !source.isString()) {
return nullptr;
}
} else if (mutedErrors.isString()) {
@ -3456,11 +3461,7 @@ JSObject* JSStructuredCloneReader::readSavedFrameHeader(
savedFrame->initPrincipalsAlreadyHeldAndMutedErrors(principals,
mutedErrors.toBoolean());
auto atomSource = AtomizeString(context(), source.toString());
if (!atomSource) {
return nullptr;
}
savedFrame->initSource(atomSource);
savedFrame->initSource(&source.toString()->asAtom());
RootedValue lineVal(context());
uint32_t line;
@ -3481,7 +3482,7 @@ JSObject* JSStructuredCloneReader::readSavedFrameHeader(
savedFrame->initSourceId(0);
RootedValue name(context());
if (!startRead(&name, gc::Heap::Tenured)) {
if (!startRead(&name, AtomizeStrings)) {
return nullptr;
}
if (!(name.isString() || name.isNull())) {
@ -3492,16 +3493,13 @@ JSObject* JSStructuredCloneReader::readSavedFrameHeader(
}
JSAtom* atomName = nullptr;
if (name.isString()) {
atomName = AtomizeString(context(), name.toString());
if (!atomName) {
return nullptr;
}
atomName = &name.toString()->asAtom();
}
savedFrame->initFunctionDisplayName(atomName);
RootedValue cause(context());
if (!startRead(&cause, gc::Heap::Tenured)) {
if (!startRead(&cause, AtomizeStrings)) {
return nullptr;
}
if (!(cause.isString() || cause.isNull())) {
@ -3512,10 +3510,7 @@ JSObject* JSStructuredCloneReader::readSavedFrameHeader(
}
JSAtom* atomCause = nullptr;
if (cause.isString()) {
atomCause = AtomizeString(context(), cause.toString());
if (!atomCause) {
return nullptr;
}
atomCause = &cause.toString()->asAtom();
}
savedFrame->initAsyncCause(atomCause);
@ -3702,11 +3697,6 @@ bool JSStructuredCloneReader::readMapField(Handle<MapObject*> mapObj,
// value.
bool JSStructuredCloneReader::readObjectField(HandleObject obj,
HandleValue key) {
RootedValue val(context());
if (!startRead(&val)) {
return false;
}
if (!key.isString() && !key.isInt32()) {
JS_ReportErrorNumberASCII(context(), GetErrorMessage, nullptr,
JSMSG_SC_BAD_SERIALIZED_DATA,
@ -3714,6 +3704,11 @@ bool JSStructuredCloneReader::readObjectField(HandleObject obj,
return false;
}
RootedValue val(context());
if (!startRead(&val)) {
return false;
}
RootedId id(context());
if (!PrimitiveValueToId<CanGC>(context(), key, &id)) {
return false;
@ -3809,13 +3804,19 @@ bool JSStructuredCloneReader::read(MutableHandleValue vp, size_t nbytes) {
//
// Note that this means the ordering in the stream is a little funky for
// things like Map. See the comment above traverseMap() for an example.
bool expectKeyValuePairs =
!(obj->is<MapObject>() || obj->is<SetObject>() ||
obj->is<SavedFrame>() || obj->is<ErrorObject>());
RootedValue key(context());
if (!startRead(&key)) {
ShouldAtomizeStrings atomize =
expectKeyValuePairs ? AtomizeStrings : DontAtomizeStrings;
if (!startRead(&key, atomize)) {
return false;
}
if (key.isNull() && !(obj->is<MapObject>() || obj->is<SetObject>() ||
obj->is<SavedFrame>() || obj->is<ErrorObject>())) {
if (key.isNull() && expectKeyValuePairs) {
// Backwards compatibility: Null formerly indicated the end of
// object properties.
@ -3856,6 +3857,7 @@ bool JSStructuredCloneReader::read(MutableHandleValue vp, size_t nbytes) {
}
objState[objStateIdx].second() = state;
} else {
MOZ_ASSERT(expectKeyValuePairs);
// Everything else uses a series of key,value,key,value,... Value
// objects.
if (!readObjectField(obj, key)) {
@ -4073,7 +4075,8 @@ JS_PUBLIC_API bool JS_ReadString(JSStructuredCloneReader* r,
}
if (tag == SCTAG_STRING) {
if (JSString* s = r->readString(data)) {
if (JSString* s =
r->readString(data, JSStructuredCloneReader::DontAtomizeStrings)) {
str.set(s);
return true;
}