зеркало из https://github.com/mozilla/gecko-dev.git
Backed out 4 changesets (bug 1659104) for build bustages on StencilXdr.cpp. CLOSED TREE
Backed out changeset 145c513b9bdd (bug 1659104) Backed out changeset 2019253fda44 (bug 1659104) Backed out changeset 55f980703773 (bug 1659104) Backed out changeset ffac61e233f7 (bug 1659104)
This commit is contained in:
Родитель
c39868efbc
Коммит
d35f6aa3be
|
@ -43,8 +43,6 @@
|
|||
#ifdef DEBUG
|
||||
# include "frontend/TokenStream.h"
|
||||
#endif
|
||||
#include "frontend/BytecodeCompilation.h"
|
||||
#include "frontend/CompilationInfo.h"
|
||||
#include "gc/Allocator.h"
|
||||
#include "gc/Zone.h"
|
||||
#include "jit/BaselineJIT.h"
|
||||
|
@ -102,7 +100,6 @@
|
|||
#include "vm/PromiseObject.h" // js::PromiseObject, js::PromiseSlot_*
|
||||
#include "vm/ProxyObject.h"
|
||||
#include "vm/SavedStacks.h"
|
||||
#include "vm/ScopeKind.h"
|
||||
#include "vm/Stack.h"
|
||||
#include "vm/StringType.h"
|
||||
#include "vm/TraceLogging.h"
|
||||
|
@ -4875,122 +4872,6 @@ static bool SetLazyParsingDisabled(JSContext* cx, unsigned argc, Value* vp) {
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool ParseAndDumpStencilXDR(JSContext* cx, uint32_t argc, Value* vp) {
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
if (!args.requireAtLeast(cx, "parseAndDumpStencilXDR", 1)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
RootedString src(cx, ToString<CanGC>(cx, args[0]));
|
||||
if (!src) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const char* filename = "parseAndDumpStencilXDR-DATA.js";
|
||||
uint32_t lineno = 1;
|
||||
|
||||
/* Linearize the string to obtain a char16_t* range. */
|
||||
AutoStableStringChars linearChars(cx);
|
||||
if (!linearChars.initTwoByte(cx, src)) {
|
||||
return false;
|
||||
}
|
||||
JS::SourceText<char16_t> srcBuf;
|
||||
if (!srcBuf.init(cx, linearChars.twoByteChars(), src->length(),
|
||||
JS::SourceOwnership::Borrowed)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* TODO: StencilXDR - Add option to select between full and syntax parse. */
|
||||
/* Compile the script text to stencil. */
|
||||
CompileOptions options(cx);
|
||||
options.setFileAndLine(filename, lineno);
|
||||
options.setForceFullParse();
|
||||
|
||||
Rooted<frontend::CompilationInfo> compilationInfo(
|
||||
cx, frontend::CompilationInfo(cx, options));
|
||||
if (!compilationInfo.get().input.initForGlobal(cx)) {
|
||||
return false;
|
||||
}
|
||||
if (!frontend::CompileGlobalScriptToStencil(cx, compilationInfo.get(), srcBuf,
|
||||
ScopeKind::Global)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Serialize the stencil to XDR. */
|
||||
JS::TranscodeBuffer xdrBytes;
|
||||
if (!compilationInfo.get().serializeStencils(cx, xdrBytes)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Dump the bytes into a javascript ArrayBuffer and return a UInt8Array. */
|
||||
RootedObject arrayBuf(cx, JS::NewArrayBuffer(cx, xdrBytes.length()));
|
||||
if (!arrayBuf) {
|
||||
return false;
|
||||
}
|
||||
|
||||
{
|
||||
JS::AutoAssertNoGC nogc;
|
||||
bool isSharedMemory = false;
|
||||
uint8_t* data = JS::GetArrayBufferData(arrayBuf, &isSharedMemory, nogc);
|
||||
std::copy(xdrBytes.begin(), xdrBytes.end(), data);
|
||||
}
|
||||
|
||||
args.rval().setObject(*arrayBuf);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool LoadFromStencilXDR(JSContext* cx, uint32_t argc, Value* vp) {
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
if (!args.requireAtLeast(cx, "loadFromStencilXDR", 1)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Prepare the input byte array. */
|
||||
if (!args[0].isObject() || !args[0].toObject().is<ArrayBufferObject>()) {
|
||||
JS_ReportErrorASCII(cx, "loadFromStencilXDR: ArrayBuffer expected");
|
||||
return false;
|
||||
}
|
||||
RootedArrayBufferObject src(cx, &args[0].toObject().as<ArrayBufferObject>());
|
||||
|
||||
const char* filename = "parseAndDumpStencilXDR-DATA.js";
|
||||
uint32_t lineno = 1;
|
||||
|
||||
/* Prepare the CompilationInfo for decoding. */
|
||||
CompileOptions options(cx);
|
||||
options.setFileAndLine(filename, lineno);
|
||||
options.setForceFullParse();
|
||||
|
||||
Rooted<frontend::CompilationInfo> compilationInfo(
|
||||
cx, frontend::CompilationInfo(cx, options));
|
||||
if (!compilationInfo.get().input.initForGlobal(cx)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Deserialize the stencil from XDR. */
|
||||
JS::TranscodeRange xdrRange(src->dataPointer(), src->byteLength());
|
||||
if (!compilationInfo.get().deserializeStencils(cx, xdrRange)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Instantiate the stencil. */
|
||||
frontend::CompilationGCOutput output(cx);
|
||||
if (!compilationInfo.get().instantiateStencils(cx, output)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Obtain the JSScript, construct a scope chain, and evaluate it. */
|
||||
RootedScript script(cx, output.script);
|
||||
RootedValue retVal(cx, UndefinedValue());
|
||||
if (!JS_ExecuteScript(cx, script, &retVal)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
args.rval().set(retVal);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool SetDiscardSource(JSContext* cx, unsigned argc, Value* vp) {
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
|
@ -7307,16 +7188,6 @@ JS_FN_HELP("setDefaultLocale", SetDefaultLocale, 1, 0,
|
|||
" An empty string or undefined resets the runtime locale to its default value.\n"
|
||||
" NOTE: The input string is not fully validated, it must be a valid BCP-47 language tag."),
|
||||
|
||||
JS_FN_HELP("parseAndDumpStencilXDR", ParseAndDumpStencilXDR, 1, 0,
|
||||
"parseAndDumpStencilXDR(string)",
|
||||
" Parses the given string argument as js script, produces the stencil"
|
||||
" for it, and returns an ArrayBuf of the XDR-encoded contents."),
|
||||
|
||||
JS_FN_HELP("loadFromStencilXDR", LoadFromStencilXDR, 1, 0,
|
||||
"loadFromStencilXDR(arrayBuf)",
|
||||
" Reads the given stencil XDR and executes the top-level script defined"
|
||||
" within."),
|
||||
|
||||
JS_FS_HELP_END
|
||||
};
|
||||
// clang-format on
|
||||
|
|
|
@ -22,7 +22,6 @@
|
|||
#include "js/HashTable.h"
|
||||
#include "js/RealmOptions.h"
|
||||
#include "js/SourceText.h"
|
||||
#include "js/Transcoding.h"
|
||||
#include "js/Vector.h"
|
||||
#include "js/WasmModule.h"
|
||||
#include "vm/GlobalObject.h" // GlobalObject
|
||||
|
@ -384,11 +383,6 @@ struct CompilationInfo {
|
|||
|
||||
MOZ_MUST_USE bool instantiateStencils(JSContext* cx,
|
||||
CompilationGCOutput& gcOutput);
|
||||
MOZ_MUST_USE bool serializeStencils(JSContext* cx, JS::TranscodeBuffer& buf,
|
||||
bool* succeededOut = nullptr);
|
||||
MOZ_MUST_USE bool deserializeStencils(JSContext* cx,
|
||||
const JS::TranscodeRange& range,
|
||||
bool* succeededOut = nullptr);
|
||||
|
||||
JSAtom* liftParserAtomToJSAtom(JSContext* cx, const ParserAtom* parserAtom) {
|
||||
return parserAtom->toJSAtom(cx, *this).unwrapOr(nullptr);
|
||||
|
|
|
@ -144,8 +144,7 @@ class JSONPrinter;
|
|||
|
||||
namespace frontend {
|
||||
struct CompilationInfo;
|
||||
class StencilXDR;
|
||||
} // namespace frontend
|
||||
}
|
||||
|
||||
// Object-literal instruction opcodes. An object literal is constructed by a
|
||||
// straight-line sequence of these ops, each adding one property to the
|
||||
|
@ -260,11 +259,8 @@ struct ObjLiteralWriterBase {
|
|||
static const uint32_t INDEXED_PROP = 0x00800000;
|
||||
static const int OP_SHIFT = 24;
|
||||
|
||||
public:
|
||||
using CodeVector = Vector<uint8_t, 64, js::SystemAllocPolicy>;
|
||||
|
||||
protected:
|
||||
CodeVector code_;
|
||||
Vector<uint8_t, 64, js::SystemAllocPolicy> code_;
|
||||
|
||||
public:
|
||||
ObjLiteralWriterBase() = default;
|
||||
|
@ -323,13 +319,6 @@ struct ObjLiteralWriter : private ObjLiteralWriterBase {
|
|||
|
||||
void clear() { code_.clear(); }
|
||||
|
||||
// For XDR decoding.
|
||||
using CodeVector = typename ObjLiteralWriterBase::CodeVector;
|
||||
void initializeForXDR(CodeVector&& code, uint8_t flags) {
|
||||
code_ = std::move(code);
|
||||
flags_.deserialize(flags);
|
||||
}
|
||||
|
||||
mozilla::Span<const uint8_t> getCode() const { return code_; }
|
||||
ObjLiteralFlags getFlags() const { return flags_; }
|
||||
|
||||
|
@ -580,8 +569,7 @@ inline JSObject* InterpretObjLiteral(JSContext* cx,
|
|||
}
|
||||
|
||||
class ObjLiteralStencil {
|
||||
friend class frontend::StencilXDR;
|
||||
|
||||
private:
|
||||
ObjLiteralWriter writer_;
|
||||
ObjLiteralAtomVector atoms_;
|
||||
|
||||
|
|
|
@ -20,38 +20,6 @@
|
|||
using namespace js;
|
||||
using namespace js::frontend;
|
||||
|
||||
namespace js {
|
||||
|
||||
template <>
|
||||
class InflatedChar16Sequence<LittleEndianChars> {
|
||||
private:
|
||||
LittleEndianChars chars_;
|
||||
size_t idx_;
|
||||
size_t len_;
|
||||
|
||||
public:
|
||||
InflatedChar16Sequence(LittleEndianChars chars, size_t length)
|
||||
: chars_(chars), idx_(0), len_(length) {}
|
||||
|
||||
bool hasMore() { return idx_ < len_; }
|
||||
|
||||
char16_t next() {
|
||||
MOZ_ASSERT(hasMore());
|
||||
return chars_[idx_++];
|
||||
}
|
||||
|
||||
HashNumber computeHash() const {
|
||||
auto copy = *this;
|
||||
HashNumber hash = 0;
|
||||
while (copy.hasMore()) {
|
||||
hash = mozilla::AddToHash(hash, copy.next());
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace js
|
||||
|
||||
namespace js {
|
||||
namespace frontend {
|
||||
|
||||
|
@ -356,42 +324,6 @@ JS::Result<const ParserAtom*, OOM> ParserAtomsTable::internLatin1(
|
|||
return internLatin1Seq(cx, addPtr, latin1Ptr, length);
|
||||
}
|
||||
|
||||
JS::Result<const ParserAtom*, OOM> ParserAtomsTable::internChar16LE(
|
||||
JSContext* cx, LittleEndianChars twoByteLE, uint32_t length) {
|
||||
// Check for tiny strings which are abundant in minified code.
|
||||
if (const ParserAtom* tiny = wellKnownTable_.lookupTiny(twoByteLE, length)) {
|
||||
return tiny;
|
||||
}
|
||||
|
||||
InflatedChar16Sequence<LittleEndianChars> seq(twoByteLE, length);
|
||||
|
||||
// An XDR interning is guaranteed to be unique: there should be no
|
||||
// existing atom with the same contents, except for well-known atoms.
|
||||
//
|
||||
// However, using the existing path which checks for exiting atoms
|
||||
// is a lot simpler as it handles well-known atom checks seamlessly.
|
||||
AddPtr addPtr = lookupForAdd(cx, seq);
|
||||
if (addPtr) {
|
||||
return addPtr.get()->asAtom();
|
||||
}
|
||||
|
||||
// Compute the target encoding.
|
||||
// NOTE: Length in code-points will be same, even if we deflate to Latin1.
|
||||
bool wide = false;
|
||||
InflatedChar16Sequence<LittleEndianChars> seqCopy = seq;
|
||||
while (seqCopy.hasMore()) {
|
||||
char16_t ch = seqCopy.next();
|
||||
if (ch > MAX_LATIN1_CHAR) {
|
||||
wide = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise, add new entry.
|
||||
return wide ? internChar16Seq<char16_t>(cx, addPtr, seq, length)
|
||||
: internChar16Seq<Latin1Char>(cx, addPtr, seq, length);
|
||||
}
|
||||
|
||||
JS::Result<const ParserAtom*, OOM> ParserAtomsTable::internUtf8(
|
||||
JSContext* cx, const mozilla::Utf8Unit* utf8Ptr, uint32_t nbyte) {
|
||||
// Check for tiny strings which are abundant in minified code.
|
||||
|
@ -770,157 +702,6 @@ bool WellKnownParserAtoms::init(JSContext* cx) {
|
|||
} /* namespace frontend */
|
||||
} /* namespace js */
|
||||
|
||||
// XDR code.
|
||||
namespace js {
|
||||
|
||||
template <XDRMode mode>
|
||||
static XDRResult XDRParserAtomIndex(XDRState<mode>* xdr, uint32_t* index) {
|
||||
return xdr->codeUint32(index);
|
||||
}
|
||||
|
||||
template <XDRMode mode>
|
||||
XDRResult XDRParserAtomData(XDRState<mode>* xdr, const ParserAtom** atomp) {
|
||||
static_assert(JSString::MAX_LENGTH <= INT32_MAX,
|
||||
"String length must fit in 31 bits");
|
||||
|
||||
bool latin1 = false;
|
||||
uint32_t length = 0;
|
||||
uint32_t lengthAndEncoding = 0;
|
||||
|
||||
/* Encode/decode the length and string-data encoding (Latin1 or TwoByte). */
|
||||
|
||||
if (mode == XDR_ENCODE) {
|
||||
latin1 = (*atomp)->hasLatin1Chars();
|
||||
length = (*atomp)->length();
|
||||
lengthAndEncoding = (length << 1) | uint32_t(latin1);
|
||||
}
|
||||
|
||||
MOZ_TRY(xdr->codeUint32(&lengthAndEncoding));
|
||||
|
||||
if (mode == XDR_DECODE) {
|
||||
length = lengthAndEncoding >> 1;
|
||||
latin1 = !!(lengthAndEncoding & 0x1);
|
||||
}
|
||||
|
||||
/* Encode the character data. */
|
||||
if (mode == XDR_ENCODE) {
|
||||
return latin1
|
||||
? xdr->codeChars(
|
||||
const_cast<JS::Latin1Char*>((*atomp)->latin1Chars()),
|
||||
length)
|
||||
: xdr->codeChars(const_cast<char16_t*>((*atomp)->twoByteChars()),
|
||||
length);
|
||||
}
|
||||
|
||||
/* Decode the character data. */
|
||||
MOZ_ASSERT(mode == XDR_DECODE);
|
||||
JSContext* cx = xdr->cx();
|
||||
JS::Result<const ParserAtom*, JS::OOM> mbAtom(nullptr);
|
||||
if (latin1) {
|
||||
const Latin1Char* chars = nullptr;
|
||||
if (length) {
|
||||
const uint8_t* ptr = nullptr;
|
||||
MOZ_TRY(xdr->peekData(&ptr, length * sizeof(Latin1Char)));
|
||||
chars = reinterpret_cast<const Latin1Char*>(ptr);
|
||||
}
|
||||
mbAtom = xdr->frontendAtoms().internLatin1(cx, chars, length);
|
||||
} else {
|
||||
const uint8_t* twoByteCharsLE = nullptr;
|
||||
if (length) {
|
||||
MOZ_TRY(xdr->peekData(&twoByteCharsLE, length * sizeof(char16_t)));
|
||||
}
|
||||
LittleEndianChars leTwoByte(twoByteCharsLE);
|
||||
mbAtom = xdr->frontendAtoms().internChar16LE(cx, leTwoByte, length);
|
||||
}
|
||||
|
||||
const ParserAtom* atom = mbAtom.unwrapOr(nullptr);
|
||||
if (!atom) {
|
||||
return xdr->fail(JS::TranscodeResult_Throw);
|
||||
}
|
||||
*atomp = atom;
|
||||
return Ok();
|
||||
}
|
||||
|
||||
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());
|
||||
|
||||
// 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();
|
||||
} 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);
|
||||
}
|
||||
}
|
||||
MOZ_TRY(XDRParserAtomIndex(xdr, &atomIndex));
|
||||
return Ok();
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mode == XDR_DECODE && xdr->hasAtomTable());
|
||||
|
||||
uint32_t atomIndex;
|
||||
MOZ_TRY(XDRParserAtomIndex(xdr, &atomIndex));
|
||||
if (atomIndex >= xdr->parserAtomTable().length()) {
|
||||
return xdr->fail(JS::TranscodeResult_Failure_BadDecode);
|
||||
}
|
||||
const ParserAtom* atom = xdr->parserAtomTable()[atomIndex];
|
||||
|
||||
*atomp = atom;
|
||||
return Ok();
|
||||
}
|
||||
|
||||
template XDRResult XDRParserAtom(XDRState<XDR_ENCODE>* xdr,
|
||||
const ParserAtom** atomp);
|
||||
|
||||
template XDRResult XDRParserAtom(XDRState<XDR_DECODE>* xdr,
|
||||
const ParserAtom** atomp);
|
||||
|
||||
template <XDRMode mode>
|
||||
XDRResult XDRParserAtomOrNull(XDRState<mode>* xdr, const ParserAtom** atomp) {
|
||||
uint8_t isNull = false;
|
||||
if (mode == XDR_ENCODE) {
|
||||
if (!*atomp) {
|
||||
isNull = true;
|
||||
}
|
||||
}
|
||||
|
||||
MOZ_TRY(xdr->codeUint8(&isNull));
|
||||
|
||||
if (!isNull) {
|
||||
MOZ_TRY(XDRParserAtom(xdr, atomp));
|
||||
} else if (mode == XDR_DECODE) {
|
||||
*atomp = nullptr;
|
||||
}
|
||||
|
||||
return Ok();
|
||||
}
|
||||
|
||||
template XDRResult XDRParserAtomOrNull(XDRState<XDR_ENCODE>* xdr,
|
||||
const ParserAtom** atomp);
|
||||
|
||||
template XDRResult XDRParserAtomOrNull(XDRState<XDR_DECODE>* xdr,
|
||||
const ParserAtom** atomp);
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
bool JSRuntime::initializeParserAtoms(JSContext* cx) {
|
||||
MOZ_ASSERT(!commonParserNames);
|
||||
|
||||
|
|
|
@ -437,30 +437,23 @@ class WellKnownParserAtoms {
|
|||
const SpecificParserAtomLookup<CharT>& lookup) const;
|
||||
|
||||
// Fast-path tiny strings since they are abundant in minified code.
|
||||
template <typename CharsT>
|
||||
const ParserAtom* lookupTiny(CharsT chars, size_t length) const {
|
||||
static_assert(std::is_same_v<CharsT, const Latin1Char*> ||
|
||||
std::is_same_v<CharsT, const char16_t*> ||
|
||||
std::is_same_v<CharsT, const char*> ||
|
||||
std::is_same_v<CharsT, char16_t*> ||
|
||||
std::is_same_v<CharsT, LittleEndianChars>,
|
||||
"This assert mostly explicitly documents the calling types, "
|
||||
"and forces that to be updated if new types show up.");
|
||||
template <typename CharT>
|
||||
const ParserAtom* lookupTiny(const CharT* charPtr, uint32_t length) const {
|
||||
switch (length) {
|
||||
case 0:
|
||||
return empty;
|
||||
|
||||
case 1: {
|
||||
if (char16_t(chars[0]) < ASCII_STATIC_LIMIT) {
|
||||
return getLength1String(chars[0]);
|
||||
if (char16_t(charPtr[0]) < ASCII_STATIC_LIMIT) {
|
||||
return getLength1String(charPtr[0]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 2:
|
||||
if (StaticStrings::fitsInSmallChar(chars[0]) &&
|
||||
StaticStrings::fitsInSmallChar(chars[1])) {
|
||||
return getLength2String(chars[0], chars[1]);
|
||||
if (StaticStrings::fitsInSmallChar(charPtr[0]) &&
|
||||
StaticStrings::fitsInSmallChar(charPtr[1])) {
|
||||
return getLength2String(charPtr[0], charPtr[1]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -535,8 +528,6 @@ class ParserAtomsTable {
|
|||
uint32_t length);
|
||||
|
||||
public:
|
||||
bool empty() const { return entrySet_.empty(); }
|
||||
|
||||
JS::Result<const ParserAtom*, OOM> internAscii(JSContext* cx,
|
||||
const char* asciiPtr,
|
||||
uint32_t length);
|
||||
|
@ -551,11 +542,6 @@ class ParserAtomsTable {
|
|||
const char16_t* char16Ptr,
|
||||
uint32_t length);
|
||||
|
||||
// This only exists for XDR support.
|
||||
JS::Result<const ParserAtom*, OOM> internChar16LE(JSContext* cx,
|
||||
LittleEndianChars twoByteLE,
|
||||
uint32_t length);
|
||||
|
||||
JS::Result<const ParserAtom*, OOM> internJSAtom(
|
||||
JSContext* cx, CompilationInfo& compilationInfo, JSAtom* atom);
|
||||
|
||||
|
|
|
@ -12,12 +12,11 @@
|
|||
#include "frontend/BytecodeSection.h" // EmitScriptThingsVector
|
||||
#include "frontend/CompilationInfo.h" // CompilationInfo
|
||||
#include "frontend/SharedContext.h"
|
||||
#include "gc/AllocKind.h" // gc::AllocKind
|
||||
#include "js/CallArgs.h" // JSNative
|
||||
#include "js/RootingAPI.h" // Rooted
|
||||
#include "js/Transcoding.h" // JS::TranscodeBuffer
|
||||
#include "js/Value.h" // ObjectValue
|
||||
#include "js/WasmModule.h" // JS::WasmModule
|
||||
#include "gc/AllocKind.h" // gc::AllocKind
|
||||
#include "js/CallArgs.h" // JSNative
|
||||
#include "js/RootingAPI.h" // Rooted
|
||||
#include "js/Value.h" // ObjectValue
|
||||
#include "js/WasmModule.h" // JS::WasmModule
|
||||
#include "vm/EnvironmentObject.h"
|
||||
#include "vm/GeneratorAndAsyncKind.h" // GeneratorKind, FunctionAsyncKind
|
||||
#include "vm/JSContext.h" // JSContext
|
||||
|
@ -30,7 +29,6 @@
|
|||
#include "vm/Scope.h" // Scope, ScopeKindString
|
||||
#include "vm/StencilEnums.h" // ImmutableScriptFlagsEnum
|
||||
#include "vm/StringType.h" // JSAtom, js::CopyChars
|
||||
#include "vm/Xdr.h" // XDRMode, XDRResult, XDREncoder
|
||||
#include "wasm/AsmJS.h" // InstantiateAsmJS
|
||||
#include "wasm/WasmModule.h" // wasm::Module
|
||||
|
||||
|
@ -602,63 +600,6 @@ bool CompilationInfo::instantiateStencils(JSContext* cx,
|
|||
return true;
|
||||
}
|
||||
|
||||
bool CompilationInfo::serializeStencils(JSContext* cx, JS::TranscodeBuffer& buf,
|
||||
bool* succeededOut) {
|
||||
if (succeededOut) {
|
||||
*succeededOut = false;
|
||||
}
|
||||
XDRIncrementalStencilEncoder encoder(cx, *this);
|
||||
|
||||
XDRResult res = encoder.codeStencil(stencil);
|
||||
if (res.isErr()) {
|
||||
if (res.unwrapErr() & JS::TranscodeResult_Failure) {
|
||||
buf.clear();
|
||||
return true;
|
||||
}
|
||||
MOZ_ASSERT(res.unwrapErr() == JS::TranscodeResult_Throw);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Lineareize the endcoder, return empty buffer on failure.
|
||||
res = encoder.linearize(buf);
|
||||
if (res.isErr()) {
|
||||
buf.clear();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (succeededOut) {
|
||||
*succeededOut = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CompilationInfo::deserializeStencils(JSContext* cx,
|
||||
const JS::TranscodeRange& range,
|
||||
bool* succeededOut) {
|
||||
if (succeededOut) {
|
||||
*succeededOut = false;
|
||||
}
|
||||
MOZ_ASSERT(stencil.parserAtoms.empty());
|
||||
XDRStencilDecoder decoder(cx, &input.options, range, *this,
|
||||
stencil.parserAtoms);
|
||||
|
||||
XDRResult res = decoder.codeStencil(stencil);
|
||||
if (res.isErr()) {
|
||||
if (res.unwrapErr() & JS::TranscodeResult_Failure) {
|
||||
return true;
|
||||
}
|
||||
MOZ_ASSERT(res.unwrapErr() == JS::TranscodeResult_Throw);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (succeededOut) {
|
||||
*succeededOut = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#if defined(DEBUG) || defined(JS_JITSPEW)
|
||||
|
||||
void RegExpStencil::dump() {
|
||||
|
|
|
@ -46,7 +46,6 @@ struct CompilationGCOutput;
|
|||
class ScriptStencil;
|
||||
class RegExpStencil;
|
||||
class BigIntStencil;
|
||||
class StencilXDR;
|
||||
|
||||
using BaseParserScopeData = AbstractBaseScopeData<const ParserAtom>;
|
||||
|
||||
|
@ -85,8 +84,6 @@ FunctionFlags InitialFunctionFlags(FunctionSyntaxKind kind,
|
|||
// This owns a set of characters, previously syntax checked as a RegExp. Used
|
||||
// to avoid allocating the RegExp on the GC heap during parsing.
|
||||
class RegExpStencil {
|
||||
friend class StencilXDR;
|
||||
|
||||
UniqueTwoByteChars buf_;
|
||||
size_t length_ = 0;
|
||||
JS::RegExpFlags flags_;
|
||||
|
@ -117,8 +114,6 @@ class RegExpStencil {
|
|||
// ParseBigIntLiteral. Used to avoid allocating the BigInt on the
|
||||
// GC heap during parsing.
|
||||
class BigIntStencil {
|
||||
friend class StencilXDR;
|
||||
|
||||
UniqueTwoByteChars buf_;
|
||||
size_t length_ = 0;
|
||||
|
||||
|
@ -156,17 +151,15 @@ class BigIntStencil {
|
|||
};
|
||||
|
||||
class ScopeStencil {
|
||||
friend class StencilXDR;
|
||||
|
||||
// The enclosing scope. If Nothing, then the enclosing scope of the
|
||||
// compilation applies.
|
||||
mozilla::Maybe<ScopeIndex> enclosing_;
|
||||
|
||||
// The kind determines data_.
|
||||
ScopeKind kind_{UINT8_MAX};
|
||||
ScopeKind kind_;
|
||||
|
||||
// First frame slot to use, or LOCALNO_LIMIT if none are allowed.
|
||||
uint32_t firstFrameSlot_ = UINT32_MAX;
|
||||
uint32_t firstFrameSlot_;
|
||||
|
||||
// If Some, then an environment Shape must be created. The shape itself may
|
||||
// have no slots if the environment may be extensible later.
|
||||
|
@ -176,7 +169,7 @@ class ScopeStencil {
|
|||
mozilla::Maybe<FunctionIndex> functionIndex_;
|
||||
|
||||
// True if this is a FunctionScope for an arrow function.
|
||||
bool isArrow_ = false;
|
||||
bool isArrow_;
|
||||
|
||||
// The list of binding and scope-specific data. Note that the back pointers to
|
||||
// the owning JSFunction / ModuleObject are not set until Stencils are
|
||||
|
@ -184,9 +177,6 @@ class ScopeStencil {
|
|||
js::UniquePtr<BaseParserScopeData> data_;
|
||||
|
||||
public:
|
||||
// For XDR only.
|
||||
ScopeStencil() = default;
|
||||
|
||||
ScopeStencil(ScopeKind kind, mozilla::Maybe<ScopeIndex> enclosing,
|
||||
uint32_t firstFrameSlot,
|
||||
mozilla::Maybe<uint32_t> numEnvironmentSlots,
|
||||
|
@ -201,8 +191,6 @@ class ScopeStencil {
|
|||
isArrow_(isArrow),
|
||||
data_(data) {}
|
||||
|
||||
js::UniquePtr<BaseParserScopeData>& data() { return data_; }
|
||||
|
||||
static bool createForFunctionScope(JSContext* cx, CompilationStencil& stencil,
|
||||
ParserFunctionScopeData* dataArg,
|
||||
bool hasParameterExprs,
|
||||
|
@ -347,9 +335,6 @@ class StencilModuleEntry {
|
|||
: lineno(lineno), column(column) {}
|
||||
|
||||
public:
|
||||
// For XDR only.
|
||||
StencilModuleEntry() = default;
|
||||
|
||||
static StencilModuleEntry moduleRequest(const ParserAtom* specifier,
|
||||
uint32_t lineno, uint32_t column) {
|
||||
MOZ_ASSERT(specifier);
|
||||
|
|
|
@ -1,920 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* vim: set ts=8 sts=2 et sw=2 tw=80:
|
||||
* 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/. */
|
||||
|
||||
#include "frontend/StencilXdr.h" // StencilXDR
|
||||
|
||||
using namespace js;
|
||||
using namespace js::frontend;
|
||||
|
||||
struct ScriptThingVariantIndexMatcher {
|
||||
template <typename T>
|
||||
uint32_t operator()(TypedIndex<T>& index) {
|
||||
return index;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
uint32_t operator()(T&) {
|
||||
return UINT32_MAX;
|
||||
}
|
||||
};
|
||||
|
||||
template <XDRMode mode>
|
||||
static XDRResult XDRScriptThingVariant(XDRState<mode>* xdr,
|
||||
ScriptThingVariant& thing) {
|
||||
enum class ScriptThingKind {
|
||||
ScriptAtom, // JSAtom*
|
||||
NullScriptThing, // nothing.
|
||||
BigIntIndex, // Index.
|
||||
ObjLiteralIndex, // Index.
|
||||
RegExpIndex, // Index.
|
||||
ScopeIndex, // Index.
|
||||
FunctionIndex, // Index.
|
||||
EmptyGlobalScopeType, // Nothing
|
||||
} kind;
|
||||
|
||||
uint32_t index = UINT32_MAX;
|
||||
|
||||
struct KindMatcher {
|
||||
ScriptThingKind operator()(ScriptAtom& atom) {
|
||||
return ScriptThingKind::ScriptAtom;
|
||||
}
|
||||
ScriptThingKind operator()(NullScriptThing&) {
|
||||
return ScriptThingKind::NullScriptThing;
|
||||
}
|
||||
ScriptThingKind operator()(BigIntIndex& index) {
|
||||
return ScriptThingKind::BigIntIndex;
|
||||
}
|
||||
ScriptThingKind operator()(ObjLiteralIndex& index) {
|
||||
return ScriptThingKind::ObjLiteralIndex;
|
||||
}
|
||||
ScriptThingKind operator()(RegExpIndex& index) {
|
||||
return ScriptThingKind::RegExpIndex;
|
||||
}
|
||||
ScriptThingKind operator()(ScopeIndex& index) {
|
||||
return ScriptThingKind::ScopeIndex;
|
||||
}
|
||||
ScriptThingKind operator()(FunctionIndex& index) {
|
||||
return ScriptThingKind::FunctionIndex;
|
||||
}
|
||||
ScriptThingKind operator()(EmptyGlobalScopeType&) {
|
||||
return ScriptThingKind::EmptyGlobalScopeType;
|
||||
}
|
||||
};
|
||||
|
||||
if (mode == XDR_ENCODE) {
|
||||
kind = thing.match(KindMatcher());
|
||||
index = thing.match(ScriptThingVariantIndexMatcher());
|
||||
}
|
||||
|
||||
MOZ_TRY(xdr->codeEnum32(&kind));
|
||||
|
||||
const ParserAtom* atom = nullptr;
|
||||
if (kind == ScriptThingKind::ScriptAtom) {
|
||||
MOZ_ASSERT(index == UINT32_MAX);
|
||||
if (mode == XDR_ENCODE) {
|
||||
atom = thing.as<ScriptAtom>();
|
||||
}
|
||||
MOZ_TRY(XDRParserAtom(xdr, &atom));
|
||||
} else if (kind == ScriptThingKind::BigIntIndex ||
|
||||
kind == ScriptThingKind::ObjLiteralIndex ||
|
||||
kind == ScriptThingKind::RegExpIndex ||
|
||||
kind == ScriptThingKind::ScopeIndex ||
|
||||
kind == ScriptThingKind::FunctionIndex) {
|
||||
MOZ_TRY(xdr->codeUint32(&index));
|
||||
} else {
|
||||
MOZ_ASSERT(kind == ScriptThingKind::NullScriptThing ||
|
||||
kind == ScriptThingKind::EmptyGlobalScopeType);
|
||||
}
|
||||
|
||||
if (mode == XDR_DECODE) {
|
||||
switch (kind) {
|
||||
case ScriptThingKind::ScriptAtom:
|
||||
// `atom` is initialized above if `kind` == ScriptAtom
|
||||
MOZ_ASSERT(atom != nullptr);
|
||||
thing.emplace<ScriptAtom>(atom);
|
||||
break;
|
||||
case ScriptThingKind::NullScriptThing:
|
||||
thing.emplace<NullScriptThing>();
|
||||
break;
|
||||
case ScriptThingKind::EmptyGlobalScopeType:
|
||||
thing.emplace<EmptyGlobalScopeType>();
|
||||
break;
|
||||
case ScriptThingKind::BigIntIndex:
|
||||
thing.emplace<BigIntIndex>(index);
|
||||
break;
|
||||
case ScriptThingKind::ObjLiteralIndex:
|
||||
thing.emplace<ObjLiteralIndex>(index);
|
||||
break;
|
||||
case ScriptThingKind::RegExpIndex:
|
||||
thing.emplace<RegExpIndex>(index);
|
||||
break;
|
||||
case ScriptThingKind::ScopeIndex:
|
||||
thing.emplace<ScopeIndex>(index);
|
||||
break;
|
||||
case ScriptThingKind::FunctionIndex:
|
||||
thing.emplace<FunctionIndex>(index);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return Ok();
|
||||
}
|
||||
|
||||
template <XDRMode mode>
|
||||
static XDRResult XDRScriptStencil(XDRState<mode>* xdr, ScriptStencil& stencil) {
|
||||
enum class XdrFlags : uint8_t {
|
||||
HasMemberInitializers = 0,
|
||||
HasScopeIndex,
|
||||
IsStandaloneFunction,
|
||||
WasFunctionEmitted,
|
||||
IsSingletonFunction,
|
||||
HasImmutableScriptData
|
||||
};
|
||||
|
||||
uint8_t xdrFlags = 0;
|
||||
uint32_t immutableFlags;
|
||||
uint32_t numMemberInitializers;
|
||||
uint32_t numGcThings;
|
||||
uint16_t functionFlags;
|
||||
uint32_t scopeIndex;
|
||||
|
||||
if (mode == XDR_ENCODE) {
|
||||
immutableFlags = stencil.immutableFlags;
|
||||
|
||||
if (stencil.memberInitializers.isSome()) {
|
||||
xdrFlags |= 1 << uint8_t(XdrFlags::HasMemberInitializers);
|
||||
}
|
||||
numMemberInitializers =
|
||||
stencil.memberInitializers
|
||||
.map([](auto i) { return i.numMemberInitializers; })
|
||||
.valueOr(0);
|
||||
|
||||
numGcThings = stencil.gcThings.length();
|
||||
|
||||
if (stencil.immutableScriptData) {
|
||||
xdrFlags |= 1 << uint8_t(XdrFlags::HasImmutableScriptData);
|
||||
}
|
||||
|
||||
functionFlags = stencil.functionFlags.toRaw();
|
||||
|
||||
if (stencil.lazyFunctionEnclosingScopeIndex_.isSome()) {
|
||||
xdrFlags |= 1 << uint8_t(XdrFlags::HasScopeIndex);
|
||||
}
|
||||
scopeIndex = stencil.lazyFunctionEnclosingScopeIndex_.valueOr(ScopeIndex());
|
||||
|
||||
if (stencil.isStandaloneFunction) {
|
||||
xdrFlags |= 1 << uint8_t(XdrFlags::IsStandaloneFunction);
|
||||
}
|
||||
if (stencil.wasFunctionEmitted) {
|
||||
xdrFlags |= 1 << uint8_t(XdrFlags::WasFunctionEmitted);
|
||||
}
|
||||
if (stencil.isSingletonFunction) {
|
||||
xdrFlags |= 1 << uint8_t(XdrFlags::IsSingletonFunction);
|
||||
}
|
||||
}
|
||||
|
||||
MOZ_TRY(xdr->codeUint8(&xdrFlags));
|
||||
MOZ_TRY(xdr->codeUint32(&immutableFlags));
|
||||
MOZ_TRY(xdr->codeUint32(&numMemberInitializers));
|
||||
MOZ_TRY(xdr->codeUint32(&numGcThings));
|
||||
MOZ_TRY(xdr->codeUint16(&functionFlags));
|
||||
MOZ_TRY(xdr->codeUint32(&scopeIndex));
|
||||
MOZ_TRY(xdr->codeUint16(&stencil.nargs));
|
||||
|
||||
if (mode == XDR_DECODE) {
|
||||
stencil.immutableFlags = immutableFlags;
|
||||
|
||||
if (xdrFlags & (1 << uint8_t(XdrFlags::HasMemberInitializers))) {
|
||||
stencil.memberInitializers.emplace(numMemberInitializers);
|
||||
}
|
||||
|
||||
if (!stencil.gcThings.appendN(mozilla::AsVariant(NullScriptThing()),
|
||||
numGcThings)) {
|
||||
ReportOutOfMemory(xdr->cx());
|
||||
return xdr->fail(JS::TranscodeResult_Throw);
|
||||
}
|
||||
|
||||
stencil.functionFlags = FunctionFlags(functionFlags);
|
||||
|
||||
MOZ_ASSERT_IF((xdrFlags & (1 << uint8_t(XdrFlags::HasScopeIndex))) == 0,
|
||||
scopeIndex == 0);
|
||||
if (xdrFlags & (1 << uint8_t(XdrFlags::HasScopeIndex))) {
|
||||
stencil.lazyFunctionEnclosingScopeIndex_.emplace(scopeIndex);
|
||||
}
|
||||
|
||||
if (xdrFlags & (1 << uint8_t(XdrFlags::IsStandaloneFunction))) {
|
||||
stencil.isStandaloneFunction = true;
|
||||
}
|
||||
if (xdrFlags & (1 << uint8_t(XdrFlags::WasFunctionEmitted))) {
|
||||
stencil.wasFunctionEmitted = true;
|
||||
}
|
||||
if (xdrFlags & (1 << uint8_t(XdrFlags::IsSingletonFunction))) {
|
||||
stencil.isSingletonFunction = true;
|
||||
}
|
||||
}
|
||||
|
||||
MOZ_TRY(XDRSourceExtent(xdr, &stencil.extent));
|
||||
|
||||
if (xdrFlags & (1 << uint8_t(XdrFlags::HasImmutableScriptData))) {
|
||||
MOZ_TRY(XDRImmutableScriptData(xdr, stencil.immutableScriptData));
|
||||
}
|
||||
|
||||
for (ScriptThingVariant& thing : stencil.gcThings) {
|
||||
MOZ_TRY(XDRScriptThingVariant(xdr, thing));
|
||||
}
|
||||
|
||||
MOZ_TRY(XDRParserAtomOrNull(xdr, &stencil.functionAtom));
|
||||
|
||||
return Ok();
|
||||
};
|
||||
|
||||
template <XDRMode mode>
|
||||
static XDRResult XDRParserBindingName(XDRState<mode>* xdr,
|
||||
ParserBindingName& bnamep) {
|
||||
// We'll be encoding the binding-name flags in a byte.
|
||||
uint8_t flags = 0;
|
||||
const ParserAtom* atom = nullptr;
|
||||
|
||||
if (mode == XDR_ENCODE) {
|
||||
flags = bnamep.flagsForXDR();
|
||||
atom = bnamep.name();
|
||||
}
|
||||
|
||||
// Handle the binding name flags.
|
||||
MOZ_TRY(xdr->codeUint8(&flags));
|
||||
|
||||
// Handle the atom itself, which may be null.
|
||||
MOZ_TRY(XDRParserAtomOrNull(xdr, &atom));
|
||||
|
||||
if (mode == XDR_ENCODE) {
|
||||
return Ok();
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mode == XDR_DECODE);
|
||||
bnamep = ParserBindingName::fromXDR(atom, flags);
|
||||
return Ok();
|
||||
}
|
||||
|
||||
template <typename ScopeDataT, XDRMode mode>
|
||||
static XDRResult XDRParserTrailingNames(XDRState<mode>* xdr, ScopeDataT& data,
|
||||
uint32_t length) {
|
||||
// Handle each atom in turn.
|
||||
for (uint32_t i = 0; i < length; i++) {
|
||||
MOZ_TRY(XDRParserBindingName(xdr, data.trailingNames[i]));
|
||||
}
|
||||
|
||||
return Ok();
|
||||
}
|
||||
|
||||
template <typename ScopeT, typename InitF>
|
||||
static UniquePtr<BaseParserScopeData> NewEmptyScopeData(JSContext* cx,
|
||||
uint32_t length,
|
||||
InitF init) {
|
||||
size_t dataSize = SizeOfScopeData<ParserScopeData<ScopeT>>(length);
|
||||
uint8_t* bytes = cx->pod_malloc<uint8_t>(dataSize);
|
||||
if (!bytes) {
|
||||
return nullptr;
|
||||
}
|
||||
auto* data = new (bytes) ParserScopeData<ScopeT>(length);
|
||||
init(data);
|
||||
return UniquePtr<BaseParserScopeData>(data);
|
||||
}
|
||||
|
||||
template <XDRMode mode>
|
||||
static XDRResult XDRParserFunctionScopeData(
|
||||
XDRState<mode>* xdr, UniquePtr<BaseParserScopeData>& ownedData) {
|
||||
ParserFunctionScopeData* data =
|
||||
static_cast<ParserFunctionScopeData*>(ownedData.get());
|
||||
|
||||
uint32_t nextFrameSlot = 0;
|
||||
uint8_t hasParameterExprs = 0;
|
||||
uint16_t nonPositionalFormalStart = 0;
|
||||
uint16_t varStart = 0;
|
||||
uint32_t length = 0;
|
||||
|
||||
if (mode == XDR_ENCODE) {
|
||||
nextFrameSlot = data->nextFrameSlot;
|
||||
hasParameterExprs = data->hasParameterExprs ? 1 : 0;
|
||||
nonPositionalFormalStart = data->nonPositionalFormalStart;
|
||||
varStart = data->varStart;
|
||||
length = data->length;
|
||||
}
|
||||
|
||||
MOZ_TRY(xdr->codeUint32(&nextFrameSlot));
|
||||
MOZ_TRY(xdr->codeUint8(&hasParameterExprs));
|
||||
MOZ_TRY(xdr->codeUint16(&nonPositionalFormalStart));
|
||||
MOZ_TRY(xdr->codeUint16(&varStart));
|
||||
MOZ_TRY(xdr->codeUint32(&length));
|
||||
|
||||
// Reconstruct the scope-data object for decode.
|
||||
if (mode == XDR_DECODE) {
|
||||
MOZ_ASSERT(!ownedData);
|
||||
ownedData =
|
||||
NewEmptyScopeData<FunctionScope>(xdr->cx(), length, [&](auto data) {
|
||||
data->nextFrameSlot = nextFrameSlot;
|
||||
MOZ_ASSERT(hasParameterExprs <= 1);
|
||||
data->hasParameterExprs = hasParameterExprs;
|
||||
data->nonPositionalFormalStart = nonPositionalFormalStart;
|
||||
data->varStart = varStart;
|
||||
data->length = length;
|
||||
});
|
||||
if (!ownedData) {
|
||||
return xdr->fail(JS::TranscodeResult_Throw);
|
||||
}
|
||||
data = static_cast<ParserFunctionScopeData*>(ownedData.get());
|
||||
}
|
||||
|
||||
// Decode each name in TrailingNames.
|
||||
MOZ_TRY(XDRParserTrailingNames(xdr, *data, length));
|
||||
|
||||
return Ok();
|
||||
}
|
||||
|
||||
template <XDRMode mode>
|
||||
static XDRResult XDRParserVarScopeData(
|
||||
XDRState<mode>* xdr, UniquePtr<BaseParserScopeData>& ownedData) {
|
||||
ParserVarScopeData* data = static_cast<ParserVarScopeData*>(ownedData.get());
|
||||
|
||||
uint32_t nextFrameSlot = 0;
|
||||
uint32_t length = 0;
|
||||
|
||||
if (mode == XDR_ENCODE) {
|
||||
nextFrameSlot = data->nextFrameSlot;
|
||||
length = data->length;
|
||||
}
|
||||
|
||||
MOZ_TRY(xdr->codeUint32(&nextFrameSlot));
|
||||
MOZ_TRY(xdr->codeUint32(&length));
|
||||
|
||||
// Reconstruct the scope-data object for decode.
|
||||
if (mode == XDR_DECODE) {
|
||||
MOZ_ASSERT(!ownedData);
|
||||
ownedData = NewEmptyScopeData<VarScope>(xdr->cx(), length, [&](auto data) {
|
||||
data->nextFrameSlot = nextFrameSlot;
|
||||
data->length = length;
|
||||
});
|
||||
if (!ownedData) {
|
||||
return xdr->fail(JS::TranscodeResult_Throw);
|
||||
}
|
||||
data = static_cast<ParserVarScopeData*>(ownedData.get());
|
||||
}
|
||||
|
||||
// Decode each name in TrailingNames.
|
||||
MOZ_TRY(XDRParserTrailingNames(xdr, *data, length));
|
||||
|
||||
return Ok();
|
||||
}
|
||||
|
||||
template <XDRMode mode>
|
||||
static XDRResult XDRParserLexicalScopeData(
|
||||
XDRState<mode>* xdr, UniquePtr<BaseParserScopeData>& ownedData) {
|
||||
ParserLexicalScopeData* data =
|
||||
static_cast<ParserLexicalScopeData*>(ownedData.get());
|
||||
|
||||
uint32_t nextFrameSlot = 0;
|
||||
uint32_t constStart = 0;
|
||||
uint32_t length = 0;
|
||||
|
||||
if (mode == XDR_ENCODE) {
|
||||
nextFrameSlot = data->nextFrameSlot;
|
||||
constStart = data->constStart;
|
||||
length = data->length;
|
||||
}
|
||||
|
||||
MOZ_TRY(xdr->codeUint32(&nextFrameSlot));
|
||||
MOZ_TRY(xdr->codeUint32(&constStart));
|
||||
MOZ_TRY(xdr->codeUint32(&length));
|
||||
|
||||
// Reconstruct the scope-data object for decode.
|
||||
if (mode == XDR_DECODE) {
|
||||
MOZ_ASSERT(!ownedData);
|
||||
ownedData =
|
||||
NewEmptyScopeData<LexicalScope>(xdr->cx(), length, [&](auto data) {
|
||||
data->nextFrameSlot = nextFrameSlot;
|
||||
data->constStart = constStart;
|
||||
data->length = length;
|
||||
});
|
||||
if (!ownedData) {
|
||||
return xdr->fail(JS::TranscodeResult_Throw);
|
||||
}
|
||||
data = static_cast<ParserLexicalScopeData*>(ownedData.get());
|
||||
}
|
||||
|
||||
// Decode each name in TrailingNames.
|
||||
MOZ_TRY(XDRParserTrailingNames(xdr, *data, length));
|
||||
|
||||
return Ok();
|
||||
}
|
||||
|
||||
template <XDRMode mode>
|
||||
static XDRResult XDRParserGlobalScopeData(
|
||||
XDRState<mode>* xdr, UniquePtr<BaseParserScopeData>& ownedData) {
|
||||
ParserGlobalScopeData* data =
|
||||
static_cast<ParserGlobalScopeData*>(ownedData.get());
|
||||
|
||||
uint32_t letStart = 0;
|
||||
uint32_t constStart = 0;
|
||||
uint32_t length = 0;
|
||||
|
||||
if (mode == XDR_ENCODE) {
|
||||
letStart = data->letStart;
|
||||
constStart = data->constStart;
|
||||
length = data->length;
|
||||
}
|
||||
|
||||
MOZ_TRY(xdr->codeUint32(&letStart));
|
||||
MOZ_TRY(xdr->codeUint32(&constStart));
|
||||
MOZ_TRY(xdr->codeUint32(&length));
|
||||
|
||||
// Reconstruct the scope-data object for decode.
|
||||
if (mode == XDR_DECODE) {
|
||||
MOZ_ASSERT(!ownedData);
|
||||
ownedData =
|
||||
NewEmptyScopeData<GlobalScope>(xdr->cx(), length, [&](auto data) {
|
||||
data->letStart = letStart;
|
||||
data->constStart = constStart;
|
||||
data->length = length;
|
||||
});
|
||||
if (!ownedData) {
|
||||
return xdr->fail(JS::TranscodeResult_Throw);
|
||||
}
|
||||
data = static_cast<ParserGlobalScopeData*>(ownedData.get());
|
||||
}
|
||||
|
||||
// Decode each name in TrailingNames.
|
||||
MOZ_TRY(XDRParserTrailingNames(xdr, *data, length));
|
||||
|
||||
return Ok();
|
||||
}
|
||||
|
||||
template <XDRMode mode>
|
||||
static XDRResult XDRParserModuleScopeData(
|
||||
XDRState<mode>* xdr, UniquePtr<BaseParserScopeData>& ownedData) {
|
||||
ParserModuleScopeData* data =
|
||||
static_cast<ParserModuleScopeData*>(ownedData.get());
|
||||
|
||||
uint32_t nextFrameSlot = 0;
|
||||
uint32_t varStart = 0;
|
||||
uint32_t letStart = 0;
|
||||
uint32_t constStart = 0;
|
||||
uint32_t length = 0;
|
||||
|
||||
if (mode == XDR_ENCODE) {
|
||||
nextFrameSlot = data->nextFrameSlot;
|
||||
varStart = data->varStart;
|
||||
letStart = data->letStart;
|
||||
constStart = data->constStart;
|
||||
length = data->length;
|
||||
}
|
||||
|
||||
MOZ_TRY(xdr->codeUint32(&nextFrameSlot));
|
||||
MOZ_TRY(xdr->codeUint32(&varStart));
|
||||
MOZ_TRY(xdr->codeUint32(&letStart));
|
||||
MOZ_TRY(xdr->codeUint32(&constStart));
|
||||
MOZ_TRY(xdr->codeUint32(&length));
|
||||
|
||||
// Reconstruct the scope-data object for decode.
|
||||
if (mode == XDR_DECODE) {
|
||||
MOZ_ASSERT(!ownedData);
|
||||
ownedData =
|
||||
NewEmptyScopeData<ModuleScope>(xdr->cx(), length, [&](auto data) {
|
||||
data->nextFrameSlot = nextFrameSlot;
|
||||
data->varStart = varStart;
|
||||
data->letStart = letStart;
|
||||
data->constStart = constStart;
|
||||
data->length = length;
|
||||
});
|
||||
if (!ownedData) {
|
||||
return xdr->fail(JS::TranscodeResult_Throw);
|
||||
}
|
||||
data = static_cast<ParserModuleScopeData*>(ownedData.get());
|
||||
}
|
||||
|
||||
// Decode each name in TrailingNames.
|
||||
MOZ_TRY(XDRParserTrailingNames(xdr, *data, length));
|
||||
|
||||
return Ok();
|
||||
}
|
||||
|
||||
template <XDRMode mode>
|
||||
static XDRResult XDRParserEvalScopeData(
|
||||
XDRState<mode>* xdr, UniquePtr<BaseParserScopeData>& ownedData) {
|
||||
ParserEvalScopeData* data =
|
||||
static_cast<ParserEvalScopeData*>(ownedData.get());
|
||||
|
||||
uint32_t nextFrameSlot = 0;
|
||||
uint32_t length = 0;
|
||||
|
||||
if (mode == XDR_ENCODE) {
|
||||
nextFrameSlot = data->nextFrameSlot;
|
||||
length = data->length;
|
||||
}
|
||||
|
||||
MOZ_TRY(xdr->codeUint32(&nextFrameSlot));
|
||||
MOZ_TRY(xdr->codeUint32(&length));
|
||||
|
||||
// Reconstruct the scope-data object for decode.
|
||||
if (mode == XDR_DECODE) {
|
||||
MOZ_ASSERT(!ownedData);
|
||||
ownedData = NewEmptyScopeData<EvalScope>(xdr->cx(), length, [&](auto data) {
|
||||
data->nextFrameSlot = nextFrameSlot;
|
||||
data->length = length;
|
||||
});
|
||||
if (!ownedData) {
|
||||
return xdr->fail(JS::TranscodeResult_Throw);
|
||||
}
|
||||
data = static_cast<ParserEvalScopeData*>(ownedData.get());
|
||||
}
|
||||
|
||||
// Decode each name in TrailingNames.
|
||||
MOZ_TRY(XDRParserTrailingNames(xdr, *data, length));
|
||||
|
||||
return Ok();
|
||||
}
|
||||
|
||||
template <XDRMode mode, typename VecType, typename... ConstructArgs>
|
||||
static XDRResult XDRVector(XDRState<mode>* xdr, VecType& vec,
|
||||
ConstructArgs&&... args) {
|
||||
uint32_t length;
|
||||
|
||||
if (mode == XDR_ENCODE) {
|
||||
MOZ_ASSERT(vec.length() <= UINT32_MAX);
|
||||
length = vec.length();
|
||||
}
|
||||
|
||||
MOZ_TRY(xdr->codeUint32(&length));
|
||||
|
||||
if (mode == XDR_DECODE) {
|
||||
MOZ_ASSERT(vec.empty());
|
||||
if (!vec.reserve(length)) {
|
||||
js::ReportOutOfMemory(xdr->cx());
|
||||
return xdr->fail(JS::TranscodeResult_Throw);
|
||||
}
|
||||
for (uint64_t i = 0; i < length; ++i) {
|
||||
vec.infallibleEmplaceBack(std::forward<ConstructArgs>(args)...);
|
||||
}
|
||||
}
|
||||
|
||||
return Ok();
|
||||
}
|
||||
|
||||
template <XDRMode mode>
|
||||
static XDRResult XDRObjLiteralWriter(XDRState<mode>* xdr,
|
||||
ObjLiteralWriter& writer) {
|
||||
uint8_t flags = 0;
|
||||
uint32_t length = 0;
|
||||
|
||||
if (mode == XDR_ENCODE) {
|
||||
flags = writer.getFlags().serialize();
|
||||
length = writer.getCode().size();
|
||||
}
|
||||
|
||||
MOZ_TRY(xdr->codeUint8(&flags));
|
||||
MOZ_TRY(xdr->codeUint32(&length));
|
||||
|
||||
if (mode == XDR_ENCODE) {
|
||||
MOZ_TRY(xdr->codeBytes((void*)writer.getCode().data(), length));
|
||||
return Ok();
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mode == XDR_DECODE);
|
||||
ObjLiteralWriter::CodeVector codeVec;
|
||||
if (!codeVec.appendN(0, length)) {
|
||||
return xdr->fail(JS::TranscodeResult_Throw);
|
||||
}
|
||||
MOZ_TRY(xdr->codeBytes(codeVec.begin(), length));
|
||||
|
||||
writer.initializeForXDR(std::move(codeVec), flags);
|
||||
|
||||
return Ok();
|
||||
}
|
||||
|
||||
template <XDRMode mode>
|
||||
static XDRResult XDRStencilModuleEntryVector(
|
||||
XDRState<mode>* xdr, StencilModuleMetadata::EntryVector& vec) {
|
||||
uint64_t length;
|
||||
|
||||
if (mode == XDR_ENCODE) {
|
||||
length = vec.length();
|
||||
}
|
||||
|
||||
MOZ_TRY(xdr->codeUint64(&length));
|
||||
|
||||
if (mode == XDR_DECODE) {
|
||||
MOZ_ASSERT(vec.empty());
|
||||
if (!vec.resize(length)) {
|
||||
return xdr->fail(JS::TranscodeResult_Throw);
|
||||
}
|
||||
}
|
||||
|
||||
for (StencilModuleEntry& entry : vec) {
|
||||
MOZ_TRY(xdr->codeUint32(&entry.lineno));
|
||||
MOZ_TRY(xdr->codeUint32(&entry.column));
|
||||
|
||||
MOZ_TRY(XDRParserAtomOrNull(xdr, &entry.specifier));
|
||||
MOZ_TRY(XDRParserAtomOrNull(xdr, &entry.localName));
|
||||
MOZ_TRY(XDRParserAtomOrNull(xdr, &entry.importName));
|
||||
MOZ_TRY(XDRParserAtomOrNull(xdr, &entry.exportName));
|
||||
}
|
||||
|
||||
return Ok();
|
||||
}
|
||||
|
||||
template <XDRMode mode>
|
||||
static XDRResult XDRStencilModuleMetadata(XDRState<mode>* xdr,
|
||||
StencilModuleMetadata& stencil) {
|
||||
MOZ_TRY(XDRStencilModuleEntryVector(xdr, stencil.requestedModules));
|
||||
MOZ_TRY(XDRStencilModuleEntryVector(xdr, stencil.importEntries));
|
||||
MOZ_TRY(XDRStencilModuleEntryVector(xdr, stencil.localExportEntries));
|
||||
MOZ_TRY(XDRStencilModuleEntryVector(xdr, stencil.indirectExportEntries));
|
||||
MOZ_TRY(XDRStencilModuleEntryVector(xdr, stencil.starExportEntries));
|
||||
|
||||
{
|
||||
uint64_t length;
|
||||
|
||||
if (mode == XDR_ENCODE) {
|
||||
length = stencil.functionDecls.length();
|
||||
}
|
||||
|
||||
MOZ_TRY(xdr->codeUint64(&length));
|
||||
|
||||
if (mode == XDR_DECODE) {
|
||||
MOZ_ASSERT(stencil.functionDecls.empty());
|
||||
if (!stencil.functionDecls.resize(length)) {
|
||||
return xdr->fail(JS::TranscodeResult_Throw);
|
||||
}
|
||||
}
|
||||
|
||||
for (GCThingIndex& entry : stencil.functionDecls) {
|
||||
MOZ_TRY(xdr->codeUint32(&entry.index));
|
||||
}
|
||||
}
|
||||
|
||||
return Ok();
|
||||
}
|
||||
|
||||
template <XDRMode mode>
|
||||
/* static */ XDRResult StencilXDR::Scope(XDRState<mode>* xdr,
|
||||
ScopeStencil& stencil) {
|
||||
enum class XdrFlags {
|
||||
HasEnclosing,
|
||||
HasEnvironment,
|
||||
IsArrow,
|
||||
};
|
||||
|
||||
uint8_t xdrFlags = 0;
|
||||
uint8_t kind;
|
||||
|
||||
if (mode == XDR_ENCODE) {
|
||||
kind = static_cast<uint8_t>(stencil.kind_);
|
||||
if (stencil.enclosing_.isSome()) {
|
||||
xdrFlags |= 1 << uint8_t(XdrFlags::HasEnclosing);
|
||||
}
|
||||
if (stencil.numEnvironmentSlots_.isSome()) {
|
||||
xdrFlags |= 1 << uint8_t(XdrFlags::HasEnvironment);
|
||||
}
|
||||
if (stencil.isArrow_) {
|
||||
xdrFlags |= 1 << uint8_t(XdrFlags::IsArrow);
|
||||
}
|
||||
}
|
||||
|
||||
MOZ_TRY(xdr->codeUint8(&xdrFlags));
|
||||
MOZ_TRY(xdr->codeUint8(&kind));
|
||||
MOZ_TRY(xdr->codeUint32(&stencil.firstFrameSlot_));
|
||||
|
||||
if (mode == XDR_DECODE) {
|
||||
stencil.kind_ = static_cast<ScopeKind>(kind);
|
||||
}
|
||||
|
||||
if (xdrFlags & (1 << uint8_t(XdrFlags::HasEnclosing))) {
|
||||
if (mode == XDR_DECODE) {
|
||||
stencil.enclosing_ = mozilla::Some(ScopeIndex());
|
||||
}
|
||||
MOZ_ASSERT(stencil.enclosing_.isSome());
|
||||
MOZ_TRY(xdr->codeUint32(&stencil.enclosing_->index));
|
||||
}
|
||||
|
||||
if (xdrFlags & (1 << uint8_t(XdrFlags::HasEnvironment))) {
|
||||
if (mode == XDR_DECODE) {
|
||||
stencil.numEnvironmentSlots_ = mozilla::Some(0);
|
||||
}
|
||||
MOZ_ASSERT(stencil.numEnvironmentSlots_.isSome());
|
||||
MOZ_TRY(xdr->codeUint32(&stencil.numEnvironmentSlots_.ref()));
|
||||
}
|
||||
|
||||
if (xdrFlags & (1 << uint8_t(XdrFlags::IsArrow))) {
|
||||
if (mode == XDR_DECODE) {
|
||||
stencil.isArrow_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (stencil.kind_ == ScopeKind::Function) {
|
||||
if (mode == XDR_DECODE) {
|
||||
stencil.functionIndex_ = mozilla::Some(FunctionIndex());
|
||||
}
|
||||
MOZ_ASSERT(stencil.functionIndex_.isSome());
|
||||
MOZ_TRY(xdr->codeUint32(&stencil.functionIndex_->index));
|
||||
}
|
||||
|
||||
// In both decoding and encoding, stencil.kind_ is now known, and
|
||||
// can be assumed. This allows the encoding to write out the bytes
|
||||
// for the specialized scope-data type without needing to encode
|
||||
// a distinguishing prefix.
|
||||
switch (stencil.kind_) {
|
||||
// FunctionScope
|
||||
case ScopeKind::Function: {
|
||||
MOZ_TRY(XDRParserFunctionScopeData(xdr, stencil.data_));
|
||||
break;
|
||||
}
|
||||
|
||||
// VarScope
|
||||
case ScopeKind::FunctionBodyVar: {
|
||||
MOZ_TRY(XDRParserVarScopeData(xdr, stencil.data_));
|
||||
break;
|
||||
}
|
||||
|
||||
// LexicalScope
|
||||
case ScopeKind::Lexical:
|
||||
case ScopeKind::SimpleCatch:
|
||||
case ScopeKind::Catch:
|
||||
case ScopeKind::NamedLambda:
|
||||
case ScopeKind::StrictNamedLambda:
|
||||
case ScopeKind::FunctionLexical:
|
||||
case ScopeKind::ClassBody: {
|
||||
MOZ_TRY(XDRParserLexicalScopeData(xdr, stencil.data_));
|
||||
break;
|
||||
}
|
||||
|
||||
// WithScope
|
||||
case ScopeKind::With: {
|
||||
// With scopes carry no scope data.
|
||||
break;
|
||||
}
|
||||
|
||||
// EvalScope
|
||||
case ScopeKind::Eval:
|
||||
case ScopeKind::StrictEval: {
|
||||
MOZ_TRY(XDRParserEvalScopeData(xdr, stencil.data_));
|
||||
break;
|
||||
}
|
||||
|
||||
// GlobalScope
|
||||
case ScopeKind::Global:
|
||||
case ScopeKind::NonSyntactic: {
|
||||
MOZ_TRY(XDRParserGlobalScopeData(xdr, stencil.data_));
|
||||
break;
|
||||
}
|
||||
|
||||
// ModuleScope
|
||||
case ScopeKind::Module: {
|
||||
MOZ_TRY(XDRParserModuleScopeData(xdr, stencil.data_));
|
||||
break;
|
||||
}
|
||||
|
||||
// WasmInstanceScope & WasmFunctionScope should not appear in stencils.
|
||||
case ScopeKind::WasmInstance:
|
||||
case ScopeKind::WasmFunction:
|
||||
default:
|
||||
MOZ_ASSERT_UNREACHABLE("XDR unrecognized ScopeKind.");
|
||||
}
|
||||
|
||||
return Ok();
|
||||
}
|
||||
|
||||
template <XDRMode mode>
|
||||
/* static */ XDRResult StencilXDR::ObjLiteral(XDRState<mode>* xdr,
|
||||
ObjLiteralStencil& stencil) {
|
||||
MOZ_TRY(XDRObjLiteralWriter(xdr, stencil.writer_));
|
||||
|
||||
MOZ_TRY(XDRVector(xdr, stencil.atoms_, nullptr));
|
||||
for (const ParserAtom*& entry : stencil.atoms_) {
|
||||
MOZ_TRY(XDRParserAtom(xdr, &entry));
|
||||
}
|
||||
|
||||
return Ok();
|
||||
}
|
||||
|
||||
template <XDRMode mode>
|
||||
/* static */ XDRResult StencilXDR::BigInt(XDRState<mode>* xdr,
|
||||
BigIntStencil& stencil) {
|
||||
uint64_t length;
|
||||
|
||||
if (mode == XDR_ENCODE) {
|
||||
length = stencil.length_;
|
||||
}
|
||||
|
||||
MOZ_TRY(xdr->codeUint64(&length));
|
||||
|
||||
XDRTranscodeString<char16_t> chars;
|
||||
|
||||
if (mode == XDR_DECODE) {
|
||||
stencil.buf_ = xdr->cx()->template make_pod_array<char16_t>(length);
|
||||
if (!stencil.buf_) {
|
||||
return xdr->fail(JS::TranscodeResult_Throw);
|
||||
}
|
||||
stencil.length_ = length;
|
||||
}
|
||||
|
||||
return xdr->codeChars(stencil.buf_.get(), stencil.length_);
|
||||
}
|
||||
|
||||
template <XDRMode mode>
|
||||
/* static */ XDRResult StencilXDR::RegExp(XDRState<mode>* xdr,
|
||||
RegExpStencil& stencil) {
|
||||
uint64_t length;
|
||||
uint8_t flags;
|
||||
|
||||
if (mode == XDR_ENCODE) {
|
||||
length = stencil.length_;
|
||||
flags = stencil.flags_.value();
|
||||
}
|
||||
|
||||
MOZ_TRY(xdr->codeUint64(&length));
|
||||
MOZ_TRY(xdr->codeUint8(&flags));
|
||||
|
||||
XDRTranscodeString<char16_t> chars;
|
||||
|
||||
if (mode == XDR_DECODE) {
|
||||
stencil.buf_ = xdr->cx()->template make_pod_array<char16_t>(length);
|
||||
if (!stencil.buf_) {
|
||||
return xdr->fail(JS::TranscodeResult_Throw);
|
||||
}
|
||||
stencil.length_ = length;
|
||||
stencil.flags_ = JS::RegExpFlags(flags);
|
||||
}
|
||||
|
||||
return xdr->codeChars(stencil.buf_.get(), stencil.length_);
|
||||
}
|
||||
|
||||
namespace js {
|
||||
|
||||
template <XDRMode mode>
|
||||
XDRResult XDRCompilationStencil(XDRState<mode>* xdr,
|
||||
CompilationStencil& stencil) {
|
||||
if (!stencil.asmJS.empty()) {
|
||||
return xdr->fail(JS::TranscodeResult_Failure_AsmJSNotSupported);
|
||||
}
|
||||
|
||||
// XDR the ScriptSource
|
||||
CompilationInfo& compilationInfo = xdr->stencilCompilationInfo();
|
||||
|
||||
// Copy the options out for passing into `ScriptSource::XDR`.
|
||||
mozilla::Maybe<JS::CompileOptions> opts;
|
||||
opts.emplace(xdr->cx(), compilationInfo.input.options);
|
||||
|
||||
Rooted<ScriptSourceHolder> holder(xdr->cx());
|
||||
if (mode == XDR_ENCODE) {
|
||||
holder.get().reset(compilationInfo.input.source_.get());
|
||||
}
|
||||
MOZ_TRY(ScriptSource::XDR(xdr, opts, &holder));
|
||||
|
||||
if (mode == XDR_DECODE) {
|
||||
compilationInfo.input.source_.reset(holder.get().get());
|
||||
}
|
||||
|
||||
// All of the vector-indexed data elements referenced by the
|
||||
// main script tree must be materialized first.
|
||||
|
||||
MOZ_TRY(XDRVector(xdr, stencil.scopeData));
|
||||
for (auto& entry : stencil.scopeData) {
|
||||
MOZ_TRY(StencilXDR::Scope(xdr, entry));
|
||||
}
|
||||
|
||||
MOZ_TRY(XDRVector(xdr, stencil.regExpData));
|
||||
for (auto& entry : stencil.regExpData) {
|
||||
MOZ_TRY(StencilXDR::RegExp(xdr, entry));
|
||||
}
|
||||
|
||||
MOZ_TRY(XDRVector(xdr, stencil.bigIntData));
|
||||
for (auto& entry : stencil.bigIntData) {
|
||||
MOZ_TRY(StencilXDR::BigInt(xdr, entry));
|
||||
}
|
||||
|
||||
MOZ_TRY(XDRVector(xdr, stencil.objLiteralData));
|
||||
for (auto& entry : stencil.objLiteralData) {
|
||||
MOZ_TRY(StencilXDR::ObjLiteral(xdr, entry));
|
||||
}
|
||||
|
||||
// Now serialize the vector of ScriptStencils.
|
||||
|
||||
MOZ_TRY(XDRVector(xdr, stencil.scriptData));
|
||||
for (auto& entry : stencil.scriptData) {
|
||||
MOZ_TRY(XDRScriptStencil(xdr, entry));
|
||||
}
|
||||
|
||||
if (stencil.scriptData[CompilationInfo::TopLevelIndex].isModule()) {
|
||||
MOZ_TRY(XDRStencilModuleMetadata(xdr, stencil.moduleMetadata));
|
||||
}
|
||||
|
||||
return Ok();
|
||||
}
|
||||
template XDRResult XDRCompilationStencil(XDRState<XDR_ENCODE>* xdr,
|
||||
CompilationStencil& stencil);
|
||||
|
||||
template XDRResult XDRCompilationStencil(XDRState<XDR_DECODE>* xdr,
|
||||
CompilationStencil& stencil);
|
||||
|
||||
} // namespace js
|
|
@ -1,40 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* vim: set ts=8 sts=2 et sw=2 tw=80:
|
||||
* 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 frontend_StencilXdr_h
|
||||
#define frontend_StencilXdr_h
|
||||
|
||||
#include "frontend/CompilationInfo.h" // CompilationInfo
|
||||
#include "frontend/ObjLiteral.h" // ObjLiteralStencil
|
||||
#include "frontend/Stencil.h" // Stencil
|
||||
#include "vm/Scope.h" // Scope, ScopeKindString
|
||||
#include "vm/Xdr.h" // XDRMode, XDRResult, XDREncoder
|
||||
|
||||
namespace js {
|
||||
namespace frontend {
|
||||
|
||||
// This is just a namespace class that can be used in friend declarations,
|
||||
// so that the statically declared XDR methods within have access to the
|
||||
// relevant struct internals.
|
||||
class StencilXDR {
|
||||
public:
|
||||
template <XDRMode mode>
|
||||
static XDRResult Scope(XDRState<mode>* xdr, ScopeStencil& stencil);
|
||||
|
||||
template <XDRMode mode>
|
||||
static XDRResult ObjLiteral(XDRState<mode>* xdr, ObjLiteralStencil& stencil);
|
||||
|
||||
template <XDRMode mode>
|
||||
static XDRResult BigInt(XDRState<mode>* xdr, BigIntStencil& stencil);
|
||||
|
||||
template <XDRMode mode>
|
||||
static XDRResult RegExp(XDRState<mode>* xdr, RegExpStencil& stencil);
|
||||
};
|
||||
|
||||
} /* namespace frontend */
|
||||
} /* namespace js */
|
||||
|
||||
#endif /* frontend_StencilXdr_h */
|
|
@ -58,7 +58,6 @@ UNIFIED_SOURCES += [
|
|||
'SharedContext.cpp',
|
||||
'SourceNotes.cpp',
|
||||
'Stencil.cpp',
|
||||
'StencilXdr.cpp',
|
||||
'SwitchEmitter.cpp',
|
||||
'TDZCheckCache.cpp',
|
||||
'TokenStream.cpp',
|
||||
|
|
|
@ -16,22 +16,20 @@ BEGIN_TEST(testParserAtom_empty) {
|
|||
|
||||
ParserAtomsTable atomTable(cx->runtime());
|
||||
|
||||
constexpr size_t len = 0;
|
||||
|
||||
const char ascii[] = {};
|
||||
const JS::Latin1Char latin1[] = {};
|
||||
const mozilla::Utf8Unit utf8[] = {};
|
||||
const char16_t char16[] = {};
|
||||
|
||||
const uint8_t bytes[] = {};
|
||||
const js::LittleEndianChars leTwoByte(bytes);
|
||||
|
||||
// Check that the well-known empty atom matches for different entry points.
|
||||
const ParserAtom* ref = cx->parserNames().empty;
|
||||
CHECK(ref);
|
||||
CHECK(atomTable.internAscii(cx, ascii, 0).unwrap() == ref);
|
||||
CHECK(atomTable.internLatin1(cx, latin1, 0).unwrap() == ref);
|
||||
CHECK(atomTable.internUtf8(cx, utf8, 0).unwrap() == ref);
|
||||
CHECK(atomTable.internChar16(cx, char16, 0).unwrap() == ref);
|
||||
CHECK(atomTable.internChar16LE(cx, leTwoByte, 0).unwrap() == ref);
|
||||
CHECK(atomTable.internAscii(cx, ascii, len).unwrap() == ref);
|
||||
CHECK(atomTable.internLatin1(cx, latin1, len).unwrap() == ref);
|
||||
CHECK(atomTable.internUtf8(cx, utf8, len).unwrap() == ref);
|
||||
CHECK(atomTable.internChar16(cx, char16, len).unwrap() == ref);
|
||||
|
||||
// Check concatenation works on empty atoms.
|
||||
const ParserAtom* concat[] = {
|
||||
|
@ -58,16 +56,12 @@ BEGIN_TEST(testParserAtom_tiny1) {
|
|||
const mozilla::Utf8Unit utf8[] = {mozilla::Utf8Unit('a')};
|
||||
char16_t char16[] = {'a'};
|
||||
|
||||
const uint8_t bytes[] = {'a', 0};
|
||||
const js::LittleEndianChars leTwoByte(bytes);
|
||||
|
||||
const ParserAtom* ref = cx->parserNames().lookupTiny(&a, 1);
|
||||
CHECK(ref);
|
||||
CHECK(atomTable.internAscii(cx, ascii, 1).unwrap() == ref);
|
||||
CHECK(atomTable.internLatin1(cx, latin1, 1).unwrap() == ref);
|
||||
CHECK(atomTable.internUtf8(cx, utf8, 1).unwrap() == ref);
|
||||
CHECK(atomTable.internChar16(cx, char16, 1).unwrap() == ref);
|
||||
CHECK(atomTable.internChar16LE(cx, leTwoByte, 1).unwrap() == ref);
|
||||
|
||||
const ParserAtom* concat[] = {
|
||||
ref,
|
||||
|
@ -98,16 +92,12 @@ BEGIN_TEST(testParserAtom_tiny2) {
|
|||
mozilla::Utf8Unit('0')};
|
||||
char16_t char16[] = {'a', '0'};
|
||||
|
||||
const uint8_t bytes[] = {'a', 0, '0', 0};
|
||||
const js::LittleEndianChars leTwoByte(bytes);
|
||||
|
||||
const ParserAtom* ref = cx->parserNames().lookupTiny(ascii, 2);
|
||||
CHECK(ref);
|
||||
CHECK(atomTable.internAscii(cx, ascii, 2).unwrap() == ref);
|
||||
CHECK(atomTable.internLatin1(cx, latin1, 2).unwrap() == ref);
|
||||
CHECK(atomTable.internUtf8(cx, utf8, 2).unwrap() == ref);
|
||||
CHECK(atomTable.internChar16(cx, char16, 2).unwrap() == ref);
|
||||
CHECK(atomTable.internChar16LE(cx, leTwoByte, 2).unwrap() == ref);
|
||||
|
||||
const ParserAtom* concat[] = {
|
||||
cx->parserNames().lookupTiny(ascii + 0, 1),
|
||||
|
|
|
@ -843,8 +843,8 @@ ImmutableScriptData::ImmutableScriptData(uint32_t codeLength,
|
|||
}
|
||||
|
||||
template <XDRMode mode>
|
||||
XDRResult js::XDRImmutableScriptData(XDRState<mode>* xdr,
|
||||
UniquePtr<ImmutableScriptData>& isd) {
|
||||
static XDRResult XDRImmutableScriptData(XDRState<mode>* xdr,
|
||||
UniquePtr<ImmutableScriptData>& isd) {
|
||||
uint32_t codeLength = 0;
|
||||
uint32_t noteLength = 0;
|
||||
uint32_t numResumeOffsets = 0;
|
||||
|
@ -914,11 +914,6 @@ XDRResult js::XDRImmutableScriptData(XDRState<mode>* xdr,
|
|||
return Ok();
|
||||
}
|
||||
|
||||
template XDRResult js::XDRImmutableScriptData(
|
||||
XDRState<XDR_ENCODE>* xdr, UniquePtr<ImmutableScriptData>& isd);
|
||||
template XDRResult js::XDRImmutableScriptData(
|
||||
XDRState<XDR_DECODE>* xdr, UniquePtr<ImmutableScriptData>& isd);
|
||||
|
||||
template <XDRMode mode>
|
||||
/* static */
|
||||
XDRResult RuntimeScriptData::XDR(XDRState<mode>* xdr, HandleScript script) {
|
||||
|
|
|
@ -1966,10 +1966,6 @@ XDRResult XDRLazyScript(XDRState<mode>* xdr, HandleScope enclosingScope,
|
|||
template <XDRMode mode>
|
||||
XDRResult XDRSourceExtent(XDRState<mode>* xdr, SourceExtent* extent);
|
||||
|
||||
template <XDRMode mode>
|
||||
XDRResult XDRImmutableScriptData(XDRState<mode>* xdr,
|
||||
UniquePtr<ImmutableScriptData>& isd);
|
||||
|
||||
/*
|
||||
* Code any constant value.
|
||||
*/
|
||||
|
|
|
@ -81,7 +81,7 @@ class AbstractBindingName {
|
|||
template <typename OtherNameT>
|
||||
friend class AbstractBindingName;
|
||||
|
||||
// A JSAtom* or ParserAtom* with its low bit used as a tag for the:
|
||||
// A JSAtom* with its low bit used as a tag for the:
|
||||
// * whether it is closed over (i.e., exists in the environment shape)
|
||||
// * whether it is a top-level function binding in global or eval scope,
|
||||
// instead of var binding (both are in the same range in Scope data)
|
||||
|
|
|
@ -19,8 +19,7 @@
|
|||
|
||||
#include "builtin/ModuleObject.h"
|
||||
#include "debugger/DebugAPI.h"
|
||||
#include "frontend/ParserAtom.h" // XDRParserAtom
|
||||
#include "js/BuildId.h" // JS::BuildIdCharVector
|
||||
#include "js/BuildId.h" // JS::BuildIdCharVector
|
||||
#include "vm/JSContext.h"
|
||||
#include "vm/JSScript.h"
|
||||
#include "vm/TraceLogging.h"
|
||||
|
@ -282,22 +281,11 @@ static XDRResult AtomTable(XDRState<mode>* xdr) {
|
|||
MOZ_TRY(XDRAtomCount(xdr, &atomCount));
|
||||
MOZ_ASSERT(!xdr->hasAtomTable());
|
||||
|
||||
if (xdr->isForStencil()) {
|
||||
for (uint32_t i = 0; i < atomCount; i++) {
|
||||
const frontend::ParserAtom* atom = nullptr;
|
||||
MOZ_TRY(XDRParserAtom(xdr, &atom));
|
||||
if (!xdr->parserAtomTable().append(atom)) {
|
||||
ReportOutOfMemory(xdr->cx());
|
||||
return xdr->fail(JS::TranscodeResult_Throw);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (uint32_t i = 0; i < atomCount; i++) {
|
||||
RootedAtom atom(xdr->cx());
|
||||
MOZ_TRY(XDRAtom(xdr, &atom));
|
||||
if (!xdr->atomTable().append(atom)) {
|
||||
return xdr->fail(JS::TranscodeResult_Throw);
|
||||
}
|
||||
for (uint32_t i = 0; i < atomCount; i++) {
|
||||
RootedAtom atom(xdr->cx());
|
||||
MOZ_TRY(XDRAtom(xdr, &atom));
|
||||
if (!xdr->atomTable().append(atom)) {
|
||||
return xdr->fail(JS::TranscodeResult_Throw);
|
||||
}
|
||||
}
|
||||
xdr->finishAtomTable();
|
||||
|
@ -376,30 +364,6 @@ XDRResult XDRState<mode>::codeScript(MutableHandleScript scriptp) {
|
|||
return Ok();
|
||||
}
|
||||
|
||||
template <XDRMode mode>
|
||||
XDRResult XDRState<mode>::codeStencil(frontend::CompilationStencil& stencil) {
|
||||
#ifdef DEBUG
|
||||
auto sanityCheck = mozilla::MakeScopeExit(
|
||||
[&] { MOZ_ASSERT(validateResultCode(cx(), resultCode())); });
|
||||
#endif
|
||||
AutoXDRTree scriptTree(this, getTopLevelTreeKey());
|
||||
|
||||
// As with codeScript, use header buffer when incrementally encoding.
|
||||
bool useHeader = this->hasAtomMap();
|
||||
if (useHeader) {
|
||||
switchToHeaderBuf();
|
||||
}
|
||||
MOZ_TRY(VersionCheck(this));
|
||||
MOZ_TRY(AtomTable(this));
|
||||
if (useHeader) {
|
||||
switchToMainBuf();
|
||||
}
|
||||
MOZ_ASSERT(isMainBuf());
|
||||
MOZ_TRY(XDRCompilationStencil(this, stencil));
|
||||
|
||||
return Ok();
|
||||
}
|
||||
|
||||
template class js::XDRState<XDR_ENCODE>;
|
||||
template class js::XDRState<XDR_DECODE>;
|
||||
|
||||
|
|
105
js/src/vm/Xdr.h
105
js/src/vm/Xdr.h
|
@ -17,7 +17,6 @@
|
|||
#include "jsfriendapi.h"
|
||||
#include "NamespaceImports.h"
|
||||
|
||||
#include "frontend/ParserAtom.h"
|
||||
#include "js/CompileOptions.h"
|
||||
#include "js/Transcoding.h"
|
||||
#include "js/TypeDecls.h"
|
||||
|
@ -25,11 +24,6 @@
|
|||
|
||||
namespace js {
|
||||
|
||||
namespace frontend {
|
||||
struct CompilationStencil;
|
||||
struct CompilationInfo;
|
||||
} // namespace frontend
|
||||
|
||||
class LifoAlloc;
|
||||
|
||||
enum XDRMode { XDR_ENCODE, XDR_DECODE };
|
||||
|
@ -39,10 +33,6 @@ using XDRResult = mozilla::Result<mozilla::Ok, JS::TranscodeResult>;
|
|||
using XDRAtomTable = JS::GCVector<PreBarriered<JSAtom*>>;
|
||||
using XDRAtomMap = JS::GCHashMap<PreBarriered<JSAtom*>, uint32_t>;
|
||||
|
||||
using XDRParserAtomTable =
|
||||
Vector<const frontend::ParserAtom*, 0, SystemAllocPolicy>;
|
||||
using XDRParserAtomMap = HashMap<const frontend::ParserAtom*, uint32_t>;
|
||||
|
||||
class XDRBufferBase {
|
||||
public:
|
||||
explicit XDRBufferBase(JSContext* cx, size_t cursor = 0)
|
||||
|
@ -237,10 +227,6 @@ class XDRState : public XDRCoderBase {
|
|||
virtual ~XDRState() = default;
|
||||
|
||||
JSContext* cx() const { return mainBuf.cx(); }
|
||||
virtual bool isForStencil() const { return false; }
|
||||
virtual frontend::CompilationInfo& stencilCompilationInfo() {
|
||||
MOZ_CRASH("does not have stencil compilationInfo.");
|
||||
}
|
||||
|
||||
virtual bool hasOptions() const { return false; }
|
||||
virtual const JS::ReadOnlyCompileOptions& options() {
|
||||
|
@ -253,21 +239,10 @@ class XDRState : public XDRCoderBase {
|
|||
|
||||
virtual bool hasAtomMap() const { return false; }
|
||||
virtual XDRAtomMap& atomMap() { MOZ_CRASH("does not have atomMap"); }
|
||||
virtual XDRParserAtomMap& parserAtomMap() {
|
||||
// This accessor is only used when encoding stencils.
|
||||
MOZ_CRASH("does not have parserAtomMap");
|
||||
}
|
||||
virtual uint32_t& natoms() { MOZ_CRASH("does not have atomMap."); }
|
||||
|
||||
virtual bool hasAtomTable() const { return false; }
|
||||
virtual XDRAtomTable& atomTable() { MOZ_CRASH("does not have atomTable"); }
|
||||
virtual frontend::ParserAtomsTable& frontendAtoms() {
|
||||
MOZ_CRASH("does not have frontendAtoms");
|
||||
}
|
||||
virtual XDRParserAtomTable& parserAtomTable() {
|
||||
// This accessor is only used when encoding stencils.
|
||||
MOZ_CRASH("does not have parserAtomTable");
|
||||
}
|
||||
virtual void finishAtomTable() { MOZ_CRASH("does not have atomTable"); }
|
||||
|
||||
virtual bool isMainBuf() { return true; }
|
||||
|
@ -450,7 +425,6 @@ class XDRState : public XDRCoderBase {
|
|||
XDRResult codeFunction(JS::MutableHandleFunction objp,
|
||||
HandleScriptSourceObject sourceObject = nullptr);
|
||||
XDRResult codeScript(MutableHandleScript scriptp);
|
||||
XDRResult codeStencil(frontend::CompilationStencil& stencil);
|
||||
};
|
||||
|
||||
using XDREncoder = XDRState<XDR_ENCODE>;
|
||||
|
@ -476,47 +450,6 @@ class XDRDecoder : public XDRDecoderBase {
|
|||
bool hasFinishedAtomTable_ = false;
|
||||
};
|
||||
|
||||
/*
|
||||
* The stencil decoder accepts `options` and `range` as input, along
|
||||
* with a freshly initialized `compilationInfo` and `parserAtoms` table.
|
||||
* The decoded stencils are outputted to the default-initialized
|
||||
* `compilationInfo` parameter, and decoded atoms are interned into
|
||||
* the `parserAtoms` parameter.
|
||||
*/
|
||||
class XDRStencilDecoder : public XDRDecoderBase {
|
||||
public:
|
||||
XDRStencilDecoder(JSContext* cx, const JS::ReadOnlyCompileOptions* options,
|
||||
const JS::TranscodeRange& range,
|
||||
frontend::CompilationInfo& compilationInfo,
|
||||
frontend::ParserAtomsTable& parserAtoms)
|
||||
: XDRDecoderBase(cx, range),
|
||||
options_(options),
|
||||
compilationInfo_(compilationInfo),
|
||||
parserAtoms_(parserAtoms) {
|
||||
MOZ_ASSERT(options_);
|
||||
}
|
||||
|
||||
bool isForStencil() const override { return true; }
|
||||
frontend::CompilationInfo& stencilCompilationInfo() override {
|
||||
return compilationInfo_;
|
||||
}
|
||||
|
||||
bool hasAtomTable() const override { return hasFinishedAtomTable_; }
|
||||
frontend::ParserAtomsTable& frontendAtoms() override { return parserAtoms_; }
|
||||
XDRParserAtomTable& parserAtomTable() override { return parserAtomTable_; }
|
||||
void finishAtomTable() override { hasFinishedAtomTable_ = true; }
|
||||
|
||||
bool hasOptions() const override { return true; }
|
||||
const JS::ReadOnlyCompileOptions& options() override { return *options_; }
|
||||
|
||||
private:
|
||||
const JS::ReadOnlyCompileOptions* options_;
|
||||
XDRParserAtomTable parserAtomTable_;
|
||||
bool hasFinishedAtomTable_ = false;
|
||||
frontend::CompilationInfo& compilationInfo_;
|
||||
frontend::ParserAtomsTable& parserAtoms_;
|
||||
};
|
||||
|
||||
class XDROffThreadDecoder : public XDRDecoder {
|
||||
const JS::ReadOnlyCompileOptions* options_;
|
||||
ScriptSourceObject** sourceObjectOut_;
|
||||
|
@ -663,32 +596,6 @@ class XDRIncrementalEncoder : public XDREncoder {
|
|||
void trace(JSTracer* trc);
|
||||
};
|
||||
|
||||
class XDRIncrementalStencilEncoder : public XDRIncrementalEncoder {
|
||||
// The CompilationInfo for the compile. The main reason we keep a
|
||||
// pointer to such a high-level struct within the encoder is to
|
||||
// access the ScriptSource via `compilationInfo_.input`, as that
|
||||
// needs to be encoded/decoded for XDR.
|
||||
frontend::CompilationInfo& compilationInfo_;
|
||||
|
||||
// Map from atoms to their index in the atom buffer
|
||||
XDRParserAtomMap parserAtomMap_;
|
||||
|
||||
public:
|
||||
XDRIncrementalStencilEncoder(JSContext* cx,
|
||||
frontend::CompilationInfo& compilationInfo)
|
||||
: XDRIncrementalEncoder(cx),
|
||||
compilationInfo_(compilationInfo),
|
||||
parserAtomMap_(cx) {}
|
||||
|
||||
virtual ~XDRIncrementalStencilEncoder() = default;
|
||||
|
||||
bool isForStencil() const override { return true; }
|
||||
frontend::CompilationInfo& stencilCompilationInfo() override {
|
||||
return compilationInfo_;
|
||||
}
|
||||
XDRParserAtomMap& parserAtomMap() override { return parserAtomMap_; }
|
||||
};
|
||||
|
||||
template <XDRMode mode>
|
||||
XDRResult XDRAtomOrNull(XDRState<mode>* xdr, js::MutableHandleAtom atomp);
|
||||
|
||||
|
@ -698,18 +605,6 @@ XDRResult XDRAtom(XDRState<mode>* xdr, js::MutableHandleAtom atomp);
|
|||
template <XDRMode mode>
|
||||
XDRResult XDRAtomData(XDRState<mode>* xdr, js::MutableHandleAtom atomp);
|
||||
|
||||
template <XDRMode mode>
|
||||
XDRResult XDRParserAtom(XDRState<mode>* xdr,
|
||||
const frontend::ParserAtom** atomp);
|
||||
|
||||
template <XDRMode mode>
|
||||
XDRResult XDRParserAtomOrNull(XDRState<mode>* xdr,
|
||||
const frontend::ParserAtom** atomp);
|
||||
|
||||
template <XDRMode mode>
|
||||
XDRResult XDRCompilationStencil(XDRState<mode>* xdr,
|
||||
frontend::CompilationStencil& stencil);
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
#endif /* vm_Xdr_h */
|
||||
|
|
Загрузка…
Ссылка в новой задаче