Bug 1667697 - Do not transcode well-known parser atoms and short atoms. r=djvj,tcampbell

Differential Revision: https://phabricator.services.mozilla.com/D91922
This commit is contained in:
Tooru Fujisawa 2020-10-05 19:00:50 +00:00
Родитель 8d1987c5dd
Коммит f542b51fae
4 изменённых файлов: 184 добавлений и 38 удалений

Просмотреть файл

@ -111,7 +111,7 @@ namespace frontend {
static JS::OOM PARSER_ATOMS_OOM; static JS::OOM PARSER_ATOMS_OOM;
static JSAtom* GetWellKnownAtom(JSContext* cx, WellKnownAtomId kind) { static JSAtom* GetWellKnownAtom(JSContext* cx, WellKnownAtomId atomId) {
#define ASSERT_OFFSET_(idpart, id, text) \ #define ASSERT_OFFSET_(idpart, id, text) \
static_assert(offsetof(JSAtomState, id) == \ static_assert(offsetof(JSAtomState, id) == \
int32_t(WellKnownAtomId::id) * \ int32_t(WellKnownAtomId::id) * \
@ -129,7 +129,7 @@ static JSAtom* GetWellKnownAtom(JSContext* cx, WellKnownAtomId kind) {
static_assert(int32_t(WellKnownAtomId::abort) == 0, static_assert(int32_t(WellKnownAtomId::abort) == 0,
"Unexpected order of WellKnownAtom"); "Unexpected order of WellKnownAtom");
return (&cx->names().abort)[int32_t(kind)]; return (&cx->names().abort)[int32_t(atomId)];
} }
mozilla::GenericErrorResult<OOM> RaiseParserAtomsOOMError(JSContext* cx) { mozilla::GenericErrorResult<OOM> RaiseParserAtomsOOMError(JSContext* cx) {
@ -555,6 +555,33 @@ JS::Result<const ParserAtom*, OOM> ParserAtomsTable::concatAtoms(
catLen); catLen);
} }
const ParserAtom* ParserAtomsTable::getWellKnown(WellKnownAtomId atomId) const {
#define ASSERT_OFFSET_(idpart, id, text) \
static_assert(offsetof(WellKnownParserAtoms, id) == \
int32_t(WellKnownAtomId::id) * sizeof(ParserAtom*));
FOR_EACH_COMMON_PROPERTYNAME(ASSERT_OFFSET_);
#undef ASSERT_OFFSET_
#define ASSERT_OFFSET_(name, clasp) \
static_assert(offsetof(WellKnownParserAtoms, name) == \
int32_t(WellKnownAtomId::name) * sizeof(ParserAtom*));
JS_FOR_EACH_PROTOTYPE(ASSERT_OFFSET_);
#undef ASSERT_OFFSET_
static_assert(int32_t(WellKnownAtomId::abort) == 0,
"Unexpected order of WellKnownAtom");
return (&wellKnownTable_.abort)[int32_t(atomId)];
}
const ParserAtom* ParserAtomsTable::getStatic1(StaticParserString1 s) const {
return WellKnownParserAtoms::rom_.length1Table[size_t(s)].asAtom();
}
const ParserAtom* ParserAtomsTable::getStatic2(StaticParserString2 s) const {
return WellKnownParserAtoms::rom_.length2Table[size_t(s)].asAtom();
}
template <typename CharT> template <typename CharT>
const ParserAtom* WellKnownParserAtoms::lookupChar16Seq( const ParserAtom* WellKnownParserAtoms::lookupChar16Seq(
const SpecificParserAtomLookup<CharT>& lookup) const { const SpecificParserAtomLookup<CharT>& lookup) const {
@ -566,7 +593,7 @@ const ParserAtom* WellKnownParserAtoms::lookupChar16Seq(
} }
bool WellKnownParserAtoms::initSingle(JSContext* cx, const ParserName** name, bool WellKnownParserAtoms::initSingle(JSContext* cx, const ParserName** name,
const char* str, WellKnownAtomId kind) { const char* str, WellKnownAtomId atomId) {
MOZ_ASSERT(name != nullptr); MOZ_ASSERT(name != nullptr);
unsigned int len = strlen(str); unsigned int len = strlen(str);
@ -592,7 +619,7 @@ bool WellKnownParserAtoms::initSingle(JSContext* cx, const ParserName** name,
return false; return false;
} }
UniquePtr<ParserAtomEntry> entry = maybeEntry.unwrap(); UniquePtr<ParserAtomEntry> entry = maybeEntry.unwrap();
entry->setWellKnownAtomId(kind); entry->setWellKnownAtomId(atomId);
// Save name for returning after moving entry into set. // Save name for returning after moving entry into set.
const ParserName* nm = entry.get()->asName(); const ParserName* nm = entry.get()->asName();
@ -665,9 +692,59 @@ bool WellKnownParserAtoms::init(JSContext* cx) {
// XDR code. // XDR code.
namespace js { namespace js {
enum class ParserAtomTag : uint32_t {
Normal = 0,
WellKnown,
Static1,
Static2,
};
template <XDRMode mode> template <XDRMode mode>
static XDRResult XDRParserAtomIndex(XDRState<mode>* xdr, uint32_t* index) { static XDRResult XDRParserAtomTaggedIndex(XDRState<mode>* xdr,
return xdr->codeUint32(index); ParserAtomTag* tag, uint32_t* index) {
// We encode 2 bit (tag) + 32 bit (index) data in the following format:
//
// index = 0bAABB'CCDD'EEFF'GGHH'IIJJ'KKLL'MMNN'OOPP
// tag = 0bTT
//
// if index < 0b0011'1111'1111'1111'1111'1111'1111'1111:
// single uint32_t = 0bBBCC'DDEE'FFGG'HHII'JJKK'LLMM'NNOO'PPTT
// else:
// two uint32_t = 0b1111'1111'1111'1111'1111'1111'1111'11TT,
// 0bAABB'CCDD'EEFF'GGHH'IIJJ'KKLL'MMNN'OOPP
constexpr uint32_t TagShift = 2;
constexpr uint32_t TagMask = 0b0011;
constexpr uint32_t TwoUnitPattern = UINT32_MAX ^ TagMask;
constexpr uint32_t CodeLimit = TwoUnitPattern >> TagShift;
MOZ_ASSERT((uint32_t(*tag) & TagMask) == uint32_t(*tag));
if (mode == XDR_ENCODE) {
if (*index < CodeLimit) {
uint32_t data = (*index) << TagShift | uint32_t(*tag);
return xdr->codeUint32(&data);
}
uint32_t data = TwoUnitPattern | uint32_t(*tag);
MOZ_TRY(xdr->codeUint32(&data));
return xdr->codeUint32(index);
}
MOZ_ASSERT(mode == XDR_DECODE);
uint32_t data;
MOZ_TRY(xdr->codeUint32(&data));
*tag = ParserAtomTag(data & TagMask);
if ((data & TwoUnitPattern) == TwoUnitPattern) {
MOZ_TRY(xdr->codeUint32(index));
} else {
*index = data >> TagShift;
}
return Ok();
} }
template <XDRMode mode> template <XDRMode mode>
@ -733,49 +810,86 @@ XDRResult XDRParserAtomData(XDRState<mode>* xdr, const ParserAtom** atomp) {
return Ok(); return Ok();
} }
template XDRResult XDRParserAtomData(XDRState<XDR_ENCODE>* xdr,
const ParserAtom** atomp);
template XDRResult XDRParserAtomData(XDRState<XDR_DECODE>* xdr,
const ParserAtom** atomp);
template <XDRMode mode> template <XDRMode mode>
XDRResult XDRParserAtom(XDRState<mode>* xdr, const ParserAtom** atomp) { XDRResult XDRParserAtom(XDRState<mode>* xdr, const ParserAtom** atomp) {
// If dedup tables aren't enabled for this XDR encoding, encode/decode
// the parser atoms inline.
if (!xdr->hasAtomMap() && !xdr->hasAtomTable()) {
return XDRParserAtomData(xdr, atomp);
}
if (mode == XDR_ENCODE) { if (mode == XDR_ENCODE) {
MOZ_ASSERT(xdr->hasAtomMap()); MOZ_ASSERT(xdr->hasAtomMap());
// Atom contents are encoded in a separate buffer, which is joined to the
// final result in XDRIncrementalEncoder::linearize. References to atoms
// are encoded as indices into the atom stream.
uint32_t atomIndex; uint32_t atomIndex;
XDRParserAtomMap::AddPtr p = xdr->parserAtomMap().lookupForAdd(*atomp); ParserAtomTag tag = ParserAtomTag::Normal;
if (p) { if ((*atomp)->isWellKnownAtomId()) {
atomIndex = p->value(); atomIndex = uint32_t((*atomp)->toWellKnownAtomId());
tag = ParserAtomTag::WellKnown;
} else if ((*atomp)->isStaticParserString1()) {
atomIndex = uint32_t((*atomp)->toStaticParserString1());
tag = ParserAtomTag::Static1;
} else if ((*atomp)->isStaticParserString2()) {
atomIndex = uint32_t((*atomp)->toStaticParserString2());
tag = ParserAtomTag::Static2;
} else { } else {
xdr->switchToAtomBuf(); // Either AtomIndexKind::Unresolved or AtomIndexKind::AtomIndex.
MOZ_TRY(XDRParserAtomData(xdr, atomp));
xdr->switchToMainBuf();
atomIndex = xdr->natoms(); // Atom contents are encoded in a separate buffer, which is joined to the
xdr->natoms() += 1; // final result in XDRIncrementalEncoder::linearize. References to atoms
if (!xdr->parserAtomMap().add(p, *atomp, atomIndex)) { // are encoded as indices into the atom stream.
return xdr->fail(JS::TranscodeResult_Throw); XDRParserAtomMap::AddPtr p = xdr->parserAtomMap().lookupForAdd(*atomp);
if (p) {
atomIndex = p->value();
} else {
xdr->switchToAtomBuf();
MOZ_TRY(XDRParserAtomData(xdr, atomp));
xdr->switchToMainBuf();
atomIndex = xdr->natoms();
xdr->natoms() += 1;
if (!xdr->parserAtomMap().add(p, *atomp, atomIndex)) {
return xdr->fail(JS::TranscodeResult_Throw);
}
} }
tag = ParserAtomTag::Normal;
} }
MOZ_TRY(XDRParserAtomIndex(xdr, &atomIndex)); MOZ_TRY(XDRParserAtomTaggedIndex(xdr, &tag, &atomIndex));
return Ok(); return Ok();
} }
MOZ_ASSERT(mode == XDR_DECODE && xdr->hasAtomTable()); MOZ_ASSERT(mode == XDR_DECODE && xdr->hasAtomTable());
uint32_t atomIndex; uint32_t atomIndex = 0;
MOZ_TRY(XDRParserAtomIndex(xdr, &atomIndex)); ParserAtomTag tag = ParserAtomTag::Normal;
if (atomIndex >= xdr->parserAtomTable().length()) { MOZ_TRY(XDRParserAtomTaggedIndex(xdr, &tag, &atomIndex));
return xdr->fail(JS::TranscodeResult_Failure_BadDecode);
} switch (tag) {
const ParserAtom* atom = xdr->parserAtomTable()[atomIndex]; case ParserAtomTag::Normal:
if (atomIndex >= xdr->parserAtomTable().length()) {
return xdr->fail(JS::TranscodeResult_Failure_BadDecode);
}
*atomp = xdr->parserAtomTable()[atomIndex];
break;
case ParserAtomTag::WellKnown:
if (atomIndex >= uint32_t(WellKnownAtomId::Limit)) {
return xdr->fail(JS::TranscodeResult_Failure_BadDecode);
}
*atomp = xdr->frontendAtoms().getWellKnown(WellKnownAtomId(atomIndex));
break;
case ParserAtomTag::Static1:
if (atomIndex >= WellKnownParserAtoms_ROM::ASCII_STATIC_LIMIT) {
return xdr->fail(JS::TranscodeResult_Failure_BadDecode);
}
*atomp = xdr->frontendAtoms().getStatic1(StaticParserString1(atomIndex));
break;
case ParserAtomTag::Static2:
if (atomIndex >= WellKnownParserAtoms_ROM::NUM_LENGTH2_ENTRIES) {
return xdr->fail(JS::TranscodeResult_Failure_BadDecode);
}
*atomp = xdr->frontendAtoms().getStatic2(StaticParserString2(atomIndex));
break;
}
*atomp = atom;
return Ok(); return Ok();
} }

Просмотреть файл

@ -51,6 +51,7 @@ enum class WellKnownAtomId : uint32_t {
#define ENUM_ENTRY_(name, clasp) name, #define ENUM_ENTRY_(name, clasp) name,
JS_FOR_EACH_PROTOTYPE(ENUM_ENTRY_) JS_FOR_EACH_PROTOTYPE(ENUM_ENTRY_)
#undef ENUM_ENTRY_ #undef ENUM_ENTRY_
Limit,
}; };
// These types correspond into indices in the StaticStrings arrays. // These types correspond into indices in the StaticStrings arrays.
@ -183,13 +184,36 @@ class alignas(alignof(uint32_t)) ParserAtomEntry {
template <typename CharT> template <typename CharT>
bool equalsSeq(HashNumber hash, InflatedChar16Sequence<CharT> seq) const; bool equalsSeq(HashNumber hash, InflatedChar16Sequence<CharT> seq) const;
WellKnownAtomId toWellKnownAtomId() const {
MOZ_ASSERT(isWellKnownAtomId());
return WellKnownAtomId(atomIndex_);
}
StaticParserString1 toStaticParserString1() const {
MOZ_ASSERT(isStaticParserString1());
return StaticParserString1(atomIndex_);
}
StaticParserString2 toStaticParserString2() const {
MOZ_ASSERT(isStaticParserString2());
return StaticParserString2(atomIndex_);
}
bool isWellKnownAtomId() const {
return atomIndexKind_ == AtomIndexKind::WellKnown;
}
bool isStaticParserString1() const {
return atomIndexKind_ == AtomIndexKind::Static1;
}
bool isStaticParserString2() const {
return atomIndexKind_ == AtomIndexKind::Static2;
}
private: private:
void setAtomIndex(AtomIndex index) { void setAtomIndex(AtomIndex index) {
atomIndex_ = index; atomIndex_ = index;
atomIndexKind_ = AtomIndexKind::AtomIndex; atomIndexKind_ = AtomIndexKind::AtomIndex;
} }
constexpr void setWellKnownAtomId(WellKnownAtomId kind) { constexpr void setWellKnownAtomId(WellKnownAtomId atomId) {
atomIndex_ = static_cast<uint32_t>(kind); atomIndex_ = static_cast<uint32_t>(atomId);
atomIndexKind_ = AtomIndexKind::WellKnown; atomIndexKind_ = AtomIndexKind::WellKnown;
} }
constexpr void setStaticParserString1(StaticParserString1 s) { constexpr void setStaticParserString1(StaticParserString1 s) {
@ -414,7 +438,7 @@ class WellKnownParserAtoms {
bool initTinyStringAlias(JSContext* cx, const ParserName** name, bool initTinyStringAlias(JSContext* cx, const ParserName** name,
const char* str); const char* str);
bool initSingle(JSContext* cx, const ParserName** name, const char* str, bool initSingle(JSContext* cx, const ParserName** name, const char* str,
WellKnownAtomId kind); WellKnownAtomId atomId);
public: public:
WellKnownParserAtoms() = default; WellKnownParserAtoms() = default;
@ -489,6 +513,10 @@ class ParserAtomsTable {
JS::Result<const ParserAtom*, OOM> concatAtoms( JS::Result<const ParserAtom*, OOM> concatAtoms(
JSContext* cx, mozilla::Range<const ParserAtom*> atoms); JSContext* cx, mozilla::Range<const ParserAtom*> atoms);
const ParserAtom* getWellKnown(WellKnownAtomId atomId) const;
const ParserAtom* getStatic1(StaticParserString1 s) const;
const ParserAtom* getStatic2(StaticParserString2 s) const;
}; };
template <typename CharT> template <typename CharT>

Просмотреть файл

@ -20,7 +20,7 @@
#include "builtin/ModuleObject.h" #include "builtin/ModuleObject.h"
#include "debugger/DebugAPI.h" #include "debugger/DebugAPI.h"
#include "frontend/CompilationInfo.h" // frontend::CompilationStencil, frontend::CompilationInfo, frontend::CompilationInfoVector #include "frontend/CompilationInfo.h" // frontend::CompilationStencil, frontend::CompilationInfo, frontend::CompilationInfoVector
#include "frontend/ParserAtom.h" // XDRParserAtom #include "frontend/ParserAtom.h" // XDRParserAtomData
#include "js/BuildId.h" // JS::BuildIdCharVector #include "js/BuildId.h" // JS::BuildIdCharVector
#include "vm/JSContext.h" #include "vm/JSContext.h"
#include "vm/JSScript.h" #include "vm/JSScript.h"
@ -318,7 +318,7 @@ static XDRResult ParserAtomTable(XDRState<mode>* xdr) {
for (uint32_t i = 0; i < atomCount; i++) { for (uint32_t i = 0; i < atomCount; i++) {
const frontend::ParserAtom* atom = nullptr; const frontend::ParserAtom* atom = nullptr;
MOZ_TRY(XDRParserAtom(xdr, &atom)); MOZ_TRY(XDRParserAtomData(xdr, &atom));
if (!xdr->parserAtomTable().append(atom)) { if (!xdr->parserAtomTable().append(atom)) {
ReportOutOfMemory(xdr->cx()); ReportOutOfMemory(xdr->cx());
return xdr->fail(JS::TranscodeResult_Throw); return xdr->fail(JS::TranscodeResult_Throw);

Просмотреть файл

@ -781,6 +781,10 @@ template <XDRMode mode>
XDRResult XDRParserAtom(XDRState<mode>* xdr, XDRResult XDRParserAtom(XDRState<mode>* xdr,
const frontend::ParserAtom** atomp); const frontend::ParserAtom** atomp);
template <XDRMode mode>
XDRResult XDRParserAtomData(XDRState<mode>* xdr,
const frontend::ParserAtom** atomp);
template <XDRMode mode> template <XDRMode mode>
XDRResult XDRParserAtomOrNull(XDRState<mode>* xdr, XDRResult XDRParserAtomOrNull(XDRState<mode>* xdr,
const frontend::ParserAtom** atomp); const frontend::ParserAtom** atomp);