mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-10-04 22:37:29 +09:00
Issue #1691 - Part 7e: Dependencies for required to finish part 7d. https://bugzilla.mozilla.org/show_bug.cgi?id=1331662 Reimplement EvaluateString using the ExecutionContext class. https://bugzilla.mozilla.org/show_bug.cgi?id=1316078 Extract redudant code into StartOffThreadParseTask. Use an ExclusiveContext instead of a JSContext in XDR functions. Add a script decoder as a valid off-main-thread parse-task. https://bugzilla.mozilla.org/show_bug.cgi?id=900784 Add nsJSUtils functions for encoding and decoding the bytecode. https://bugzilla.mozilla.org/show_bug.cgi?id=1316081 Add XDRIncrementalEncoder to replace delazified LazyScript in the encoded XDR buffer. Add an XDRIncrementalEncoder instance on the ScriptSource. Expose a new JSAPI to incrementally encode bytecode when it is generated. https://bugzilla.mozilla.org/show_bug.cgi?id=1334091 XDR function use the sourceObject instead of the enclosingScript as argument.
(cherry picked from commit d6de9a669f4b2f5115670bd771cd53d7cfb3956a)
This commit is contained in:
parent
d5d7bb5e47
commit
993476283d
22 changed files with 1224 additions and 171 deletions
245
js/src/vm/Xdr.h
245
js/src/vm/Xdr.h
|
|
@ -16,10 +16,10 @@ namespace js {
|
|||
|
||||
class XDRBuffer {
|
||||
public:
|
||||
XDRBuffer(JSContext* cx, JS::TranscodeBuffer& buffer, size_t cursor = 0)
|
||||
XDRBuffer(ExclusiveContext* cx, JS::TranscodeBuffer& buffer, size_t cursor = 0)
|
||||
: context_(cx), buffer_(buffer), cursor_(cursor) { }
|
||||
|
||||
JSContext* cx() const {
|
||||
ExclusiveContext* cx() const {
|
||||
return context_;
|
||||
}
|
||||
|
||||
|
|
@ -42,7 +42,7 @@ class XDRBuffer {
|
|||
uint8_t* write(size_t n) {
|
||||
MOZ_ASSERT(n != 0);
|
||||
if (!buffer_.growByUninitialized(n)) {
|
||||
JS_ReportOutOfMemory(cx());
|
||||
ReportOutOfMemory(cx());
|
||||
return nullptr;
|
||||
}
|
||||
uint8_t* ptr = &buffer_[cursor_];
|
||||
|
|
@ -50,30 +50,108 @@ class XDRBuffer {
|
|||
return ptr;
|
||||
}
|
||||
|
||||
size_t cursor() const {
|
||||
return cursor_;
|
||||
}
|
||||
|
||||
private:
|
||||
JSContext* const context_;
|
||||
ExclusiveContext* const context_;
|
||||
JS::TranscodeBuffer& buffer_;
|
||||
size_t cursor_;
|
||||
};
|
||||
|
||||
class XDRCoderBase;
|
||||
class XDRIncrementalEncoder;
|
||||
|
||||
// An AutoXDRTree is used to identify section encoded by an XDRIncrementalEncoder.
|
||||
//
|
||||
// Its primary goal is to identify functions, such that we can first encode them
|
||||
// as LazyScript, and later replaced by them by their corresponding bytecode
|
||||
// once delazified.
|
||||
//
|
||||
// As a convenience, this is also used to identify the top-level of the content
|
||||
// encoded by an XDRIncrementalEncoder.
|
||||
//
|
||||
// Sections can be encoded any number of times in an XDRIncrementalEncoder, and
|
||||
// the latest encoded version would replace all the previous one.
|
||||
class MOZ_RAII AutoXDRTree
|
||||
{
|
||||
public:
|
||||
// For a JSFunction, a tree key is defined as being:
|
||||
// script()->begin << 32 | script()->end
|
||||
//
|
||||
// Based on the invariant that |begin <= end|, we can make special
|
||||
// keys, such as the top-level script.
|
||||
using Key = uint64_t;
|
||||
|
||||
AutoXDRTree(XDRCoderBase* xdr, Key key);
|
||||
~AutoXDRTree();
|
||||
|
||||
// Indicate the lack of a key for the current tree.
|
||||
static constexpr Key noKey = 0;
|
||||
|
||||
// Used to end the slices when there is no children.
|
||||
static constexpr Key noSubTree = Key(1) << 32;
|
||||
|
||||
// Used as the root key of the tree in the hash map.
|
||||
static constexpr Key topLevel = Key(2) << 32;
|
||||
|
||||
private:
|
||||
friend class XDRIncrementalEncoder;
|
||||
|
||||
Key key_;
|
||||
AutoXDRTree* parent_;
|
||||
XDRCoderBase* xdr_;
|
||||
};
|
||||
|
||||
class XDRCoderBase
|
||||
{
|
||||
protected:
|
||||
XDRCoderBase() {}
|
||||
|
||||
public:
|
||||
virtual AutoXDRTree::Key getTopLevelTreeKey() const { return AutoXDRTree::noKey; }
|
||||
virtual AutoXDRTree::Key getTreeKey(JSFunction* fun) const { return AutoXDRTree::noKey; }
|
||||
virtual void createOrReplaceSubTree(AutoXDRTree* child) {};
|
||||
virtual void endSubTree() {};
|
||||
};
|
||||
|
||||
/*
|
||||
* XDR serialization state. All data is encoded in little endian.
|
||||
*/
|
||||
template <XDRMode mode>
|
||||
class XDRState {
|
||||
class XDRState : public XDRCoderBase
|
||||
{
|
||||
public:
|
||||
XDRBuffer buf;
|
||||
private:
|
||||
JS::TranscodeResult resultCode_;
|
||||
|
||||
XDRState(JSContext* cx, JS::TranscodeBuffer& buffer, size_t cursor = 0)
|
||||
: buf(cx, buffer, cursor), resultCode_(JS::TranscodeResult_Ok) { }
|
||||
public:
|
||||
XDRState(ExclusiveContext* cx, JS::TranscodeBuffer& buffer, size_t cursor = 0)
|
||||
: buf(cx, buffer, cursor),
|
||||
resultCode_(JS::TranscodeResult_Ok)
|
||||
{
|
||||
}
|
||||
|
||||
JSContext* cx() const {
|
||||
virtual ~XDRState() {};
|
||||
|
||||
ExclusiveContext* cx() const {
|
||||
return buf.cx();
|
||||
}
|
||||
virtual LifoAlloc& lifoAlloc() const;
|
||||
|
||||
virtual bool hasOptions() const { return false; }
|
||||
virtual const ReadOnlyCompileOptions& options() {
|
||||
MOZ_CRASH("does not have options");
|
||||
}
|
||||
virtual bool hasScriptSourceObjectOut() const { return false; }
|
||||
virtual ScriptSourceObject** scriptSourceObjectOut() {
|
||||
MOZ_CRASH("does not have scriptSourceObjectOut.");
|
||||
}
|
||||
|
||||
// Record logical failures of XDR.
|
||||
void postProcessContextErrors(JSContext* cx);
|
||||
void postProcessContextErrors(ExclusiveContext* cx);
|
||||
JS::TranscodeResult resultCode() const {
|
||||
return resultCode_;
|
||||
}
|
||||
|
|
@ -87,7 +165,7 @@ class XDRState {
|
|||
if (mode == XDR_ENCODE) {
|
||||
uint8_t* ptr = buf.write(sizeof(*n));
|
||||
if (!ptr)
|
||||
return false;
|
||||
return fail(JS::TranscodeResult_Throw);
|
||||
*ptr = *n;
|
||||
} else {
|
||||
*n = *buf.read(sizeof(*n));
|
||||
|
|
@ -99,7 +177,7 @@ class XDRState {
|
|||
if (mode == XDR_ENCODE) {
|
||||
uint8_t* ptr = buf.write(sizeof(*n));
|
||||
if (!ptr)
|
||||
return false;
|
||||
return fail(JS::TranscodeResult_Throw);
|
||||
mozilla::LittleEndian::writeUint16(ptr, *n);
|
||||
} else {
|
||||
const uint8_t* ptr = buf.read(sizeof(*n));
|
||||
|
|
@ -112,7 +190,7 @@ class XDRState {
|
|||
if (mode == XDR_ENCODE) {
|
||||
uint8_t* ptr = buf.write(sizeof(*n));
|
||||
if (!ptr)
|
||||
return false;
|
||||
return fail(JS::TranscodeResult_Throw);
|
||||
mozilla::LittleEndian::writeUint32(ptr, *n);
|
||||
} else {
|
||||
const uint8_t* ptr = buf.read(sizeof(*n));
|
||||
|
|
@ -125,7 +203,7 @@ class XDRState {
|
|||
if (mode == XDR_ENCODE) {
|
||||
uint8_t* ptr = buf.write(sizeof(*n));
|
||||
if (!ptr)
|
||||
return false;
|
||||
return fail(JS::TranscodeResult_Throw);
|
||||
mozilla::LittleEndian::writeUint64(ptr, *n);
|
||||
} else {
|
||||
const uint8_t* ptr = buf.read(sizeof(*n));
|
||||
|
|
@ -188,7 +266,7 @@ class XDRState {
|
|||
if (mode == XDR_ENCODE) {
|
||||
uint8_t* ptr = buf.write(len);
|
||||
if (!ptr)
|
||||
return false;
|
||||
return fail(JS::TranscodeResult_Throw);
|
||||
memcpy(ptr, bytes, len);
|
||||
} else {
|
||||
memcpy(bytes, buf.read(len), len);
|
||||
|
|
@ -207,7 +285,7 @@ class XDRState {
|
|||
size_t n = strlen(*sp) + 1;
|
||||
uint8_t* ptr = buf.write(n);
|
||||
if (!ptr)
|
||||
return false;
|
||||
return fail(JS::TranscodeResult_Throw);
|
||||
memcpy(ptr, *sp, n);
|
||||
} else {
|
||||
*sp = buf.readCString();
|
||||
|
|
@ -218,7 +296,7 @@ class XDRState {
|
|||
bool codeChars(const JS::Latin1Char* chars, size_t nchars);
|
||||
bool codeChars(char16_t* chars, size_t nchars);
|
||||
|
||||
bool codeFunction(JS::MutableHandleFunction objp);
|
||||
bool codeFunction(JS::MutableHandleFunction objp, HandleScriptSource sourceObject = nullptr);
|
||||
bool codeScript(MutableHandleScript scriptp);
|
||||
bool codeConstValue(MutableHandleValue vp);
|
||||
};
|
||||
|
|
@ -226,6 +304,141 @@ class XDRState {
|
|||
using XDREncoder = XDRState<XDR_ENCODE>;
|
||||
using XDRDecoder = XDRState<XDR_DECODE>;
|
||||
|
||||
class XDROffThreadDecoder : public XDRDecoder
|
||||
{
|
||||
const ReadOnlyCompileOptions* options_;
|
||||
ScriptSourceObject** sourceObjectOut_;
|
||||
LifoAlloc& alloc_;
|
||||
|
||||
public:
|
||||
// Note, when providing an ExclusiveContext, where isJSContext is false,
|
||||
// then the initialization of the ScriptSourceObject would remain
|
||||
// incomplete. Thus, the sourceObjectOut must be used to finish the
|
||||
// initialization with ScriptSourceObject::initFromOptions after the
|
||||
// decoding.
|
||||
//
|
||||
// When providing a sourceObjectOut pointer, you have to ensure that it is
|
||||
// marked by the GC to avoid dangling pointers.
|
||||
XDROffThreadDecoder(ExclusiveContext* cx, LifoAlloc& alloc,
|
||||
const ReadOnlyCompileOptions* options,
|
||||
ScriptSourceObject** sourceObjectOut,
|
||||
JS::TranscodeBuffer& buffer, size_t cursor = 0)
|
||||
: XDRDecoder(cx, buffer, cursor),
|
||||
options_(options),
|
||||
sourceObjectOut_(sourceObjectOut),
|
||||
alloc_(alloc)
|
||||
{
|
||||
MOZ_ASSERT(options);
|
||||
MOZ_ASSERT(sourceObjectOut);
|
||||
MOZ_ASSERT(*sourceObjectOut == nullptr);
|
||||
}
|
||||
|
||||
LifoAlloc& lifoAlloc() const override {
|
||||
return alloc_;
|
||||
}
|
||||
|
||||
bool hasOptions() const override { return true; }
|
||||
const ReadOnlyCompileOptions& options() override {
|
||||
return *options_;
|
||||
}
|
||||
bool hasScriptSourceObjectOut() const override { return true; }
|
||||
ScriptSourceObject** scriptSourceObjectOut() override {
|
||||
return sourceObjectOut_;
|
||||
}
|
||||
};
|
||||
|
||||
class XDRIncrementalEncoder : public XDREncoder
|
||||
{
|
||||
// The incremental encoder encodes the content of scripts and functions in
|
||||
// the XDRBuffer. It can be used to encode multiple times the same AutoXDRTree,
|
||||
// and uses its key to identify which part to replace.
|
||||
//
|
||||
// Internally, this encoder keeps a tree representation of the scopes. Each
|
||||
// node is composed of a vector of slices which are interleaved by child
|
||||
// nodes.
|
||||
//
|
||||
// A slice corresponds to an index and a length within the content of the
|
||||
// slices_ buffer. The index is updated when a slice is created, and the
|
||||
// length is updated when the slice is ended, either by creating a new scope
|
||||
// child, or by closing the scope and going back to the parent.
|
||||
//
|
||||
// +---+---+---+
|
||||
// begin | | | |
|
||||
// length | | | |
|
||||
// child | . | . | . |
|
||||
// +-|-+-|-+---+
|
||||
// | |
|
||||
// +---------+ +---------+
|
||||
// | |
|
||||
// v v
|
||||
// +---+---+ +---+
|
||||
// | | | | |
|
||||
// | | | | |
|
||||
// | . | . | | . |
|
||||
// +-|-+---+ +---+
|
||||
// |
|
||||
// |
|
||||
// |
|
||||
// v
|
||||
// +---+
|
||||
// | |
|
||||
// | |
|
||||
// | . |
|
||||
// +---+
|
||||
//
|
||||
//
|
||||
// The tree key is used to identify the child nodes, and to make them
|
||||
// easily replaceable.
|
||||
//
|
||||
// The tree is rooted at the |topLevel| key.
|
||||
//
|
||||
|
||||
struct Slice {
|
||||
size_t sliceBegin;
|
||||
size_t sliceLength;
|
||||
AutoXDRTree::Key child;
|
||||
};
|
||||
|
||||
using SlicesNode = Vector<Slice, 1, SystemAllocPolicy>;
|
||||
using SlicesTree = HashMap<AutoXDRTree::Key, SlicesNode, DefaultHasher<AutoXDRTree::Key>,
|
||||
SystemAllocPolicy>;
|
||||
|
||||
// Last opened XDR-tree on the stack.
|
||||
AutoXDRTree* scope_;
|
||||
// Node corresponding to the opened scope.
|
||||
SlicesNode* node_;
|
||||
// Tree of slices.
|
||||
SlicesTree tree_;
|
||||
JS::TranscodeBuffer slices_;
|
||||
JS::TranscodeBuffer& buffer_;
|
||||
bool oom_;
|
||||
|
||||
public:
|
||||
XDRIncrementalEncoder(ExclusiveContext* cx, JS::TranscodeBuffer& buffer, size_t cursor)
|
||||
: XDREncoder(cx, slices_, 0),
|
||||
scope_(nullptr),
|
||||
node_(nullptr),
|
||||
buffer_(buffer),
|
||||
oom_(false)
|
||||
{
|
||||
MOZ_ASSERT(buffer.length() == cursor, "NYI");
|
||||
}
|
||||
|
||||
virtual ~XDRIncrementalEncoder() {}
|
||||
|
||||
AutoXDRTree::Key getTopLevelTreeKey() const override;
|
||||
AutoXDRTree::Key getTreeKey(JSFunction* fun) const override;
|
||||
|
||||
MOZ_MUST_USE bool init();
|
||||
|
||||
void createOrReplaceSubTree(AutoXDRTree* child) override;
|
||||
void endSubTree() override;
|
||||
|
||||
// In the current XDRBuffer, move replaceable-parts to form a linear
|
||||
// sequence of bytes.
|
||||
MOZ_MUST_USE bool linearize();
|
||||
};
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
#endif /* vm_Xdr_h */
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue