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 JSAtom* GetWellKnownAtom(JSContext* cx, WellKnownAtomId kind) {
static JSAtom* GetWellKnownAtom(JSContext* cx, WellKnownAtomId atomId) {
#define ASSERT_OFFSET_(idpart, id, text) \
static_assert(offsetof(JSAtomState, id) == \
int32_t(WellKnownAtomId::id) * \
@ -129,7 +129,7 @@ static JSAtom* GetWellKnownAtom(JSContext* cx, WellKnownAtomId kind) {
static_assert(int32_t(WellKnownAtomId::abort) == 0,
"Unexpected order of WellKnownAtom");
return (&cx->names().abort)[int32_t(kind)];
return (&cx->names().abort)[int32_t(atomId)];
}
mozilla::GenericErrorResult<OOM> RaiseParserAtomsOOMError(JSContext* cx) {
@ -555,6 +555,33 @@ JS::Result<const ParserAtom*, OOM> ParserAtomsTable::concatAtoms(
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>
const ParserAtom* WellKnownParserAtoms::lookupChar16Seq(
const SpecificParserAtomLookup<CharT>& lookup) const {
@ -566,7 +593,7 @@ const ParserAtom* WellKnownParserAtoms::lookupChar16Seq(
}
bool WellKnownParserAtoms::initSingle(JSContext* cx, const ParserName** name,
const char* str, WellKnownAtomId kind) {
const char* str, WellKnownAtomId atomId) {
MOZ_ASSERT(name != nullptr);
unsigned int len = strlen(str);
@ -592,7 +619,7 @@ bool WellKnownParserAtoms::initSingle(JSContext* cx, const ParserName** name,
return false;
}
UniquePtr<ParserAtomEntry> entry = maybeEntry.unwrap();
entry->setWellKnownAtomId(kind);
entry->setWellKnownAtomId(atomId);
// Save name for returning after moving entry into set.
const ParserName* nm = entry.get()->asName();
@ -665,9 +692,59 @@ bool WellKnownParserAtoms::init(JSContext* cx) {
// XDR code.
namespace js {
enum class ParserAtomTag : uint32_t {
Normal = 0,
WellKnown,
Static1,
Static2,
};
template <XDRMode mode>
static XDRResult XDRParserAtomIndex(XDRState<mode>* xdr, uint32_t* index) {
static XDRResult XDRParserAtomTaggedIndex(XDRState<mode>* xdr,
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>
@ -733,21 +810,33 @@ XDRResult XDRParserAtomData(XDRState<mode>* xdr, const ParserAtom** atomp) {
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>
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) {
MOZ_ASSERT(xdr->hasAtomMap());
uint32_t atomIndex;
ParserAtomTag tag = ParserAtomTag::Normal;
if ((*atomp)->isWellKnownAtomId()) {
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 {
// Either AtomIndexKind::Unresolved or AtomIndexKind::AtomIndex.
// 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;
XDRParserAtomMap::AddPtr p = xdr->parserAtomMap().lookupForAdd(*atomp);
if (p) {
atomIndex = p->value();
@ -762,20 +851,45 @@ XDRResult XDRParserAtom(XDRState<mode>* xdr, const ParserAtom** atomp) {
return xdr->fail(JS::TranscodeResult_Throw);
}
}
MOZ_TRY(XDRParserAtomIndex(xdr, &atomIndex));
tag = ParserAtomTag::Normal;
}
MOZ_TRY(XDRParserAtomTaggedIndex(xdr, &tag, &atomIndex));
return Ok();
}
MOZ_ASSERT(mode == XDR_DECODE && xdr->hasAtomTable());
uint32_t atomIndex;
MOZ_TRY(XDRParserAtomIndex(xdr, &atomIndex));
uint32_t atomIndex = 0;
ParserAtomTag tag = ParserAtomTag::Normal;
MOZ_TRY(XDRParserAtomTaggedIndex(xdr, &tag, &atomIndex));
switch (tag) {
case ParserAtomTag::Normal:
if (atomIndex >= xdr->parserAtomTable().length()) {
return xdr->fail(JS::TranscodeResult_Failure_BadDecode);
}
const ParserAtom* atom = xdr->parserAtomTable()[atomIndex];
*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();
}

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

@ -51,6 +51,7 @@ enum class WellKnownAtomId : uint32_t {
#define ENUM_ENTRY_(name, clasp) name,
JS_FOR_EACH_PROTOTYPE(ENUM_ENTRY_)
#undef ENUM_ENTRY_
Limit,
};
// These types correspond into indices in the StaticStrings arrays.
@ -183,13 +184,36 @@ class alignas(alignof(uint32_t)) ParserAtomEntry {
template <typename CharT>
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:
void setAtomIndex(AtomIndex index) {
atomIndex_ = index;
atomIndexKind_ = AtomIndexKind::AtomIndex;
}
constexpr void setWellKnownAtomId(WellKnownAtomId kind) {
atomIndex_ = static_cast<uint32_t>(kind);
constexpr void setWellKnownAtomId(WellKnownAtomId atomId) {
atomIndex_ = static_cast<uint32_t>(atomId);
atomIndexKind_ = AtomIndexKind::WellKnown;
}
constexpr void setStaticParserString1(StaticParserString1 s) {
@ -414,7 +438,7 @@ class WellKnownParserAtoms {
bool initTinyStringAlias(JSContext* cx, const ParserName** name,
const char* str);
bool initSingle(JSContext* cx, const ParserName** name, const char* str,
WellKnownAtomId kind);
WellKnownAtomId atomId);
public:
WellKnownParserAtoms() = default;
@ -489,6 +513,10 @@ class ParserAtomsTable {
JS::Result<const ParserAtom*, OOM> concatAtoms(
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>

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

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

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

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