mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-08 10:44:56 +00:00
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:
parent
615e1c153f
commit
d32351d502
@ -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 */
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user