Bug 1691505 - Unify CompilationStencil and CompilationStencilSet types. r=arai

Introduce a `StencilDelazificationSet` type to hold the vector of
delazification stencils. This is held as an optional UniquePtr that hangs off
the `CompilationStencil`.

Combine the different variants of prepareForInstantiation,
instantiateStencils, etc by making `gcOutputForDelazifcation` optional. If
there are delazifications present, we assert there is output.

NOTE: This rewrites the `prepareForInstantiation` logic because the existing
code seemed to mix up gcOutput and gcOutputForDelazifcation.

Differential Revision: https://phabricator.services.mozilla.com/D104460
This commit is contained in:
Ted Campbell 2021-02-09 14:52:45 +00:00
Родитель 546c109ff0
Коммит bd660428af
15 изменённых файлов: 257 добавлений и 382 удалений

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

@ -46,7 +46,7 @@
# include "frontend/TokenStream.h"
#endif
#include "frontend/BytecodeCompilation.h"
#include "frontend/CompilationStencil.h" // frontend::CompilationStencil, frontend::CompilationStencilSet
#include "frontend/CompilationStencil.h" // frontend::CompilationStencil
#include "gc/Allocator.h"
#include "gc/Zone.h"
#include "jit/BaselineJIT.h"
@ -5038,21 +5038,21 @@ static bool EvalStencilXDR(JSContext* cx, uint32_t argc, Value* vp) {
const char* filename = "compileStencilXDR-DATA.js";
uint32_t lineno = 1;
/* Prepare the CompilationStencilSet for decoding. */
/* Prepare the CompilationStencil for decoding. */
CompileOptions options(cx);
options.setFileAndLine(filename, lineno);
options.setForceFullParse();
Rooted<frontend::CompilationStencilSet> stencilSet(
cx, frontend::CompilationStencilSet(cx, options));
if (!stencilSet.get().input.initForGlobal(cx)) {
Rooted<frontend::CompilationStencil> stencil(
cx, frontend::CompilationStencil(cx, options));
if (!stencil.get().input.initForGlobal(cx)) {
return false;
}
/* Deserialize the stencil from XDR. */
JS::TranscodeRange xdrRange(src->dataPointer(), src->byteLength().get());
bool succeeded = false;
if (!stencilSet.get().deserializeStencils(cx, xdrRange, &succeeded)) {
if (!stencil.get().deserializeStencils(cx, xdrRange, &succeeded)) {
return false;
}
if (!succeeded) {
@ -5063,8 +5063,8 @@ static bool EvalStencilXDR(JSContext* cx, uint32_t argc, Value* vp) {
/* Instantiate the stencil. */
Rooted<frontend::CompilationGCOutput> output(cx);
Rooted<frontend::CompilationGCOutput> outputForDelazification(cx);
if (!stencilSet.get().instantiateStencils(cx, output.get(),
outputForDelazification.get())) {
if (!frontend::CompilationStencil::instantiateStencils(
cx, stencil.get(), output.get(), outputForDelazification.address())) {
return false;
}

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

@ -17,8 +17,8 @@
#include "jstypes.h" // JS_PUBLIC_API
#include "frontend/CompilationStencil.h" // CompilationStencil, CompilationStencilSet, CompilationGCOutput
#include "frontend/ParseContext.h" // js::frontend::UsedNameTracker
#include "frontend/CompilationStencil.h" // CompilationStencil, CompilationGCOutput
#include "frontend/ParseContext.h" // js::frontend::UsedNameTracker
#include "frontend/SharedContext.h" // js::frontend::Directives, js::frontend::{,Eval,Global}SharedContext
#include "js/CompileOptions.h" // JS::ReadOnlyCompileOptions
#include "js/RootingAPI.h" // JS::{,Mutable}Handle, JS::Rooted
@ -72,20 +72,13 @@ extern UniquePtr<CompilationStencil> CompileGlobalScriptToStencil(
// Part of InstantiateStencils can be done by calling PrepareForInstantiate.
// PrepareForInstantiate is GC-free operation that can be performed
// off-main-thread without parse global.
extern bool PrepareForInstantiate(JSContext* cx, CompilationStencil& stencil,
CompilationGCOutput& gcOutput);
extern bool PrepareForInstantiate(
JSContext* cx, CompilationStencilSet& stencilSet,
CompilationGCOutput& gcOutput,
CompilationGCOutput& gcOutputForDelazification);
JSContext* cx, CompilationStencil& stencil, CompilationGCOutput& gcOutput,
CompilationGCOutput* gcOutputForDelazification = nullptr);
extern bool InstantiateStencils(JSContext* cx, CompilationStencil& stencil,
CompilationGCOutput& gcOutput);
extern bool InstantiateStencils(JSContext* cx,
CompilationStencilSet& stencilSet,
CompilationGCOutput& gcOutput,
CompilationGCOutput& gcOutputForDelazification);
extern bool InstantiateStencils(
JSContext* cx, CompilationStencil& stencil, CompilationGCOutput& gcOutput,
CompilationGCOutput* gcOutputForDelazification = nullptr);
extern JSScript* CompileGlobalScript(JSContext* cx,
const JS::ReadOnlyCompileOptions& options,

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

@ -305,13 +305,15 @@ UniquePtr<CompilationStencil> frontend::CompileGlobalScriptToStencil(
return CompileGlobalScriptToStencilImpl(cx, options, srcBuf, scopeKind);
}
bool frontend::InstantiateStencils(JSContext* cx, CompilationStencil& stencil,
CompilationGCOutput& gcOutput) {
bool frontend::InstantiateStencils(
JSContext* cx, CompilationStencil& stencil, CompilationGCOutput& gcOutput,
CompilationGCOutput* gcOutputForDelazification) {
{
AutoGeckoProfilerEntry pseudoFrame(cx, "stencil instantiate",
JS::ProfilingCategoryPair::JS_Parsing);
if (!CompilationStencil::instantiateStencils(cx, stencil, gcOutput)) {
if (!CompilationStencil::instantiateStencils(cx, stencil, gcOutput,
gcOutputForDelazification)) {
return false;
}
}
@ -330,53 +332,14 @@ bool frontend::InstantiateStencils(JSContext* cx, CompilationStencil& stencil,
return true;
}
bool frontend::InstantiateStencils(
JSContext* cx, CompilationStencilSet& stencilSet,
CompilationGCOutput& gcOutput,
CompilationGCOutput& gcOutputForDelazification_) {
{
AutoGeckoProfilerEntry pseudoFrame(cx, "stencil instantiate",
JS::ProfilingCategoryPair::JS_Parsing);
if (!stencilSet.instantiateStencils(cx, gcOutput,
gcOutputForDelazification_)) {
return false;
}
}
// Enqueue an off-thread source compression task after finishing parsing.
if (!cx->isHelperThreadContext()) {
if (!stencilSet.input.source()->tryCompressOffThread(cx)) {
return false;
}
Rooted<JSScript*> script(cx, gcOutput.script);
if (!stencilSet.input.options.hideScriptFromDebugger) {
DebugAPI::onNewScript(cx, script);
}
}
return true;
}
bool frontend::PrepareForInstantiate(JSContext* cx, CompilationStencil& stencil,
CompilationGCOutput& gcOutput) {
AutoGeckoProfilerEntry pseudoFrame(cx, "stencil instantiate",
JS::ProfilingCategoryPair::JS_Parsing);
return CompilationStencil::prepareForInstantiate(cx, stencil, gcOutput);
}
bool frontend::PrepareForInstantiate(
JSContext* cx, CompilationStencilSet& stencilSet,
CompilationGCOutput& gcOutput,
CompilationGCOutput& gcOutputForDelazification_) {
JSContext* cx, CompilationStencil& stencil, CompilationGCOutput& gcOutput,
CompilationGCOutput* gcOutputForDelazification) {
AutoGeckoProfilerEntry pseudoFrame(cx, "stencil instantiate",
JS::ProfilingCategoryPair::JS_Parsing);
return stencilSet.prepareForInstantiate(cx, gcOutput,
gcOutputForDelazification_);
return CompilationStencil::prepareForInstantiate(cx, stencil, gcOutput,
gcOutputForDelazification);
}
template <typename Unit>

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

@ -48,6 +48,7 @@ namespace frontend {
struct CompilationInput;
struct CompilationStencil;
struct CompilationGCOutput;
struct StencilDelazificationSet;
class ScriptStencilIterable;
// ScopeContext hold information derivied from the scope and environment chains
@ -177,7 +178,6 @@ struct CompilationAtomCache {
bool hasAtomAt(ParserAtomIndex index) const;
bool setAtomAt(JSContext* cx, ParserAtomIndex index, JSAtom* atom);
bool allocate(JSContext* cx, size_t length);
bool extendIfNecessary(JSContext* cx, size_t length);
void stealBuffer(AtomCacheVector& atoms);
void releaseBuffer(AtomCacheVector& atoms);
@ -560,6 +560,10 @@ struct CompilationStencil : public BaseCompilationStencil {
// therefore only generated during initial parse.
StencilAsmJSContainer asmJS;
// A series of delazifications may also be associated with this stencil. They
// contain bytecode, scopes, etc generated by delazification.
UniquePtr<StencilDelazificationSet> delazificationSet;
// Set to true once prepareForInstantiate is called.
// NOTE: This field isn't XDR-encoded.
bool preparationIsPerformed = false;
@ -570,24 +574,23 @@ struct CompilationStencil : public BaseCompilationStencil {
CompilationStencil(JSContext* cx, const JS::ReadOnlyCompileOptions& options)
: alloc(LifoAllocChunkSize), input(options) {}
static MOZ_MUST_USE bool prepareInputAndStencilForInstantiate(
JSContext* cx, CompilationInput& input, BaseCompilationStencil& stencil);
static MOZ_MUST_USE bool prepareGCOutputForInstantiate(
JSContext* cx, BaseCompilationStencil& stencil,
CompilationGCOutput& gcOutput);
static MOZ_MUST_USE bool prepareForInstantiate(JSContext* cx,
CompilationStencil& stencil,
CompilationGCOutput& gcOutput);
static MOZ_MUST_USE bool instantiateStencils(JSContext* cx,
CompilationStencil& stencil,
CompilationGCOutput& gcOutput);
static MOZ_MUST_USE bool instantiateStencilsAfterPreparation(
static MOZ_MUST_USE bool instantiateBaseStencilAfterPreparation(
JSContext* cx, CompilationInput& input,
const BaseCompilationStencil& stencil, CompilationGCOutput& gcOutput);
static MOZ_MUST_USE bool prepareForInstantiate(
JSContext* cx, CompilationStencil& stencil, CompilationGCOutput& gcOutput,
CompilationGCOutput* gcOutputForDelazification = nullptr);
static MOZ_MUST_USE bool instantiateStencils(
JSContext* cx, CompilationStencil& stencil, CompilationGCOutput& gcOutput,
CompilationGCOutput* gcOutputForDelazification = nullptr);
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);
// Move constructor is necessary to use Rooted, but must be explicit in
// order to steal the LifoAlloc data
@ -648,44 +651,18 @@ inline const CompilationStencil& BaseCompilationStencil::asCompilationStencil()
return *static_cast<const CompilationStencil*>(this);
}
// A set of stencils, for XDR purpose.
// This contains the initial compilation, and a vector of delazification.
struct CompilationStencilSet : public CompilationStencil {
private:
// A set of stencils generated by delazifying functions. This should only be
// used by a CompilationStencil that owns this. This is primarily used for
// bytecode caching with XDR.
struct StencilDelazificationSet {
using ScriptIndexVector = Vector<ScriptIndex, 0, js::SystemAllocPolicy>;
MOZ_MUST_USE bool buildDelazificationIndices(JSContext* cx);
public:
Vector<BaseCompilationStencil, 0, js::SystemAllocPolicy> delazifications;
ScriptIndexVector delazificationIndices;
CompilationAtomCache::AtomCacheVector delazificationAtomCache;
CompilationStencilSet(JSContext* cx,
const JS::ReadOnlyCompileOptions& options)
: CompilationStencil(cx, options) {}
// Move constructor is necessary to use Rooted.
CompilationStencilSet(CompilationStencilSet&& other) = default;
// To avoid any misuses, make sure this is neither copyable or assignable.
CompilationStencilSet(const CompilationStencilSet&) = delete;
CompilationStencilSet& operator=(const CompilationStencilSet&) = delete;
CompilationStencilSet& operator=(CompilationStencilSet&&) = delete;
MOZ_MUST_USE bool prepareForInstantiate(
JSContext* cx, CompilationGCOutput& gcOutput,
CompilationGCOutput& gcOutputForDelazification);
MOZ_MUST_USE bool instantiateStencils(
JSContext* cx, CompilationGCOutput& gcOutput,
CompilationGCOutput& gcOutputForDelazification);
MOZ_MUST_USE bool instantiateStencilsAfterPreparation(
JSContext* cx, CompilationGCOutput& gcOutput,
CompilationGCOutput& gcOutputForDelazification);
MOZ_MUST_USE bool deserializeStencils(JSContext* cx,
const JS::TranscodeRange& range,
bool* succeededOut);
MOZ_MUST_USE bool buildDelazificationIndices(
JSContext* cx, const CompilationStencil& stencil);
};
// The output of GC allocation from stencil.

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

@ -15,7 +15,7 @@
#include "frontend/AbstractScopePtr.h" // ScopeIndex
#include "frontend/BytecodeCompilation.h" // CanLazilyParse
#include "frontend/BytecodeSection.h" // EmitScriptThingsVector
#include "frontend/CompilationStencil.h" // CompilationStencil, CompilationStencilSet, CompilationGCOutput
#include "frontend/CompilationStencil.h" // CompilationStencil, CompilationGCOutput
#include "frontend/SharedContext.h"
#include "gc/AllocKind.h" // gc::AllocKind
#include "gc/Rooting.h" // RootedAtom
@ -1243,21 +1243,71 @@ static void FunctionsFromExistingLazy(CompilationInput& input,
}
/* static */
bool CompilationStencil::instantiateStencils(JSContext* cx,
CompilationStencil& stencil,
CompilationGCOutput& gcOutput) {
bool CompilationStencil::instantiateStencils(
JSContext* cx, CompilationStencil& stencil, CompilationGCOutput& gcOutput,
CompilationGCOutput* gcOutputForDelazification) {
if (!stencil.preparationIsPerformed) {
if (!prepareForInstantiate(cx, stencil, gcOutput)) {
if (!prepareForInstantiate(cx, stencil, gcOutput,
gcOutputForDelazification)) {
return false;
}
}
return instantiateStencilsAfterPreparation(cx, stencil.input, stencil,
gcOutput);
if (!instantiateBaseStencilAfterPreparation(cx, stencil.input, stencil,
gcOutput)) {
return false;
}
if (stencil.delazificationSet) {
MOZ_ASSERT(gcOutputForDelazification);
CompilationAtomCache::AtomCacheVector reusableAtomCache;
stencil.input.atomCache.releaseBuffer(reusableAtomCache);
size_t numDelazifications =
stencil.delazificationSet->delazifications.length();
for (size_t i = 0; i < numDelazifications; i++) {
auto& delazification = stencil.delazificationSet->delazifications[i];
auto index = stencil.delazificationSet->delazificationIndices[i];
JSFunction* fun = gcOutput.functions[index];
MOZ_ASSERT(fun);
BaseScript* lazy = fun->baseScript();
MOZ_ASSERT(!lazy->hasBytecode());
if (!lazy->isReadyForDelazification()) {
MOZ_ASSERT(false, "Delazification target is not ready. Bad XDR?");
continue;
}
Rooted<CompilationInput> delazificationInput(
cx, CompilationInput(stencil.input.options));
delazificationInput.get().initFromLazy(lazy);
delazificationInput.get().atomCache.stealBuffer(reusableAtomCache);
if (!instantiateBaseStencilAfterPreparation(cx, delazificationInput.get(),
delazification,
*gcOutputForDelazification)) {
return false;
}
// Destroy elements, without unreserving.
gcOutputForDelazification->functions.clear();
gcOutputForDelazification->scopes.clear();
delazificationInput.get().atomCache.releaseBuffer(reusableAtomCache);
}
stencil.input.atomCache.stealBuffer(reusableAtomCache);
}
return true;
}
/* static */
bool CompilationStencil::instantiateStencilsAfterPreparation(
bool CompilationStencil::instantiateBaseStencilAfterPreparation(
JSContext* cx, CompilationInput& input,
const BaseCompilationStencil& stencil, CompilationGCOutput& gcOutput) {
// Distinguish between the initial (possibly lazy) compile and any subsequent
@ -1345,9 +1395,10 @@ bool CompilationStencil::instantiateStencilsAfterPreparation(
return true;
}
bool CompilationStencilSet::buildDelazificationIndices(JSContext* cx) {
bool StencilDelazificationSet::buildDelazificationIndices(
JSContext* cx, const CompilationStencil& stencil) {
// Standalone-functions are not supported by XDR.
MOZ_ASSERT(!scriptData[0].isFunction());
MOZ_ASSERT(!stencil.scriptData[0].isFunction());
// If no delazifications, we are done.
if (delazifications.empty()) {
@ -1372,8 +1423,9 @@ bool CompilationStencilSet::buildDelazificationIndices(JSContext* cx) {
MOZ_ASSERT(keyToIndex.count() == delazifications.length());
for (size_t i = 1; i < scriptData.size(); i++) {
auto key = BaseCompilationStencil::toFunctionKey(scriptExtra[i].extent);
for (size_t i = 1; i < stencil.scriptData.size(); i++) {
auto key =
BaseCompilationStencil::toFunctionKey(stencil.scriptExtra[i].extent);
auto ptr = keyToIndex.lookup(key);
if (!ptr) {
continue;
@ -1384,85 +1436,17 @@ bool CompilationStencilSet::buildDelazificationIndices(JSContext* cx) {
return true;
}
bool CompilationStencilSet::instantiateStencils(
JSContext* cx, CompilationGCOutput& gcOutput,
CompilationGCOutput& gcOutputForDelazification) {
if (!prepareForInstantiate(cx, gcOutput, gcOutputForDelazification)) {
return false;
}
return instantiateStencilsAfterPreparation(cx, gcOutput,
gcOutputForDelazification);
}
bool CompilationStencilSet::instantiateStencilsAfterPreparation(
JSContext* cx, CompilationGCOutput& gcOutput,
CompilationGCOutput& gcOutputForDelazification) {
if (!CompilationStencil::instantiateStencilsAfterPreparation(cx, input, *this,
gcOutput)) {
return false;
}
CompilationAtomCache::AtomCacheVector reusableAtomCache;
input.atomCache.releaseBuffer(reusableAtomCache);
for (size_t i = 0; i < delazifications.length(); i++) {
auto& delazification = delazifications[i];
auto index = delazificationIndices[i];
JSFunction* fun = gcOutput.functions[index];
MOZ_ASSERT(fun);
BaseScript* lazy = fun->baseScript();
MOZ_ASSERT(!lazy->hasBytecode());
if (!lazy->isReadyForDelazification()) {
MOZ_ASSERT(false, "Delazification target is not ready. Bad XDR?");
continue;
}
Rooted<CompilationInput> delazificationInput(
cx, CompilationInput(input.options));
delazificationInput.get().initFromLazy(lazy);
delazificationInput.get().atomCache.stealBuffer(reusableAtomCache);
if (!CompilationStencil::prepareGCOutputForInstantiate(
cx, delazification, gcOutputForDelazification)) {
return false;
}
if (!CompilationStencil::instantiateStencilsAfterPreparation(
cx, delazificationInput.get(), delazification,
gcOutputForDelazification)) {
return false;
}
// Destroy elements, without unreserving.
gcOutputForDelazification.functions.clear();
gcOutputForDelazification.scopes.clear();
delazificationInput.get().atomCache.releaseBuffer(reusableAtomCache);
}
input.atomCache.stealBuffer(reusableAtomCache);
return true;
}
/* static */
bool CompilationStencil::prepareInputAndStencilForInstantiate(
JSContext* cx, CompilationInput& input, BaseCompilationStencil& stencil) {
if (!input.atomCache.allocate(cx, stencil.parserAtomData.size())) {
return false;
}
bool CompilationStencil::prepareForInstantiate(
JSContext* cx, CompilationStencil& stencil, CompilationGCOutput& gcOutput,
CompilationGCOutput* gcOutputForDelazification) {
stencil.preparationIsPerformed = true;
return true;
}
size_t maxParserAtomDataLength = stencil.parserAtomData.size();
size_t maxScriptDataLength = 0;
size_t maxScopeDataLength = 0;
/* static */
bool CompilationStencil::prepareGCOutputForInstantiate(
JSContext* cx, BaseCompilationStencil& stencil,
CompilationGCOutput& gcOutput) {
// Reserve the `gcOutput` vectors.
if (!gcOutput.functions.reserve(stencil.scriptData.size())) {
ReportOutOfMemory(cx);
return false;
@ -1472,65 +1456,38 @@ bool CompilationStencil::prepareGCOutputForInstantiate(
return false;
}
return true;
}
// Reserve the `gcOutputForDelazification` vectors.
if (stencil.delazificationSet) {
MOZ_ASSERT(gcOutputForDelazification);
/* static */
bool CompilationStencil::prepareForInstantiate(JSContext* cx,
CompilationStencil& stencil,
CompilationGCOutput& gcOutput) {
auto& input = stencil.input;
if (!prepareInputAndStencilForInstantiate(cx, input, stencil)) {
return false;
}
if (!prepareGCOutputForInstantiate(cx, stencil, gcOutput)) {
return false;
}
stencil.preparationIsPerformed = true;
return true;
}
bool CompilationStencilSet::prepareForInstantiate(
JSContext* cx, CompilationGCOutput& gcOutput,
CompilationGCOutput& gcOutputForDelazification) {
if (!CompilationStencil::prepareForInstantiate(cx, *this, gcOutput)) {
return false;
}
size_t maxScriptDataLength = 0;
size_t maxScopeDataLength = 0;
size_t maxParserAtomDataLength = 0;
for (auto& delazification : delazifications) {
if (maxParserAtomDataLength < delazification.parserAtomData.size()) {
maxParserAtomDataLength = delazification.parserAtomData.size();
for (auto& delazification : stencil.delazificationSet->delazifications) {
if (maxParserAtomDataLength < delazification.parserAtomData.size()) {
maxParserAtomDataLength = delazification.parserAtomData.size();
}
if (maxScriptDataLength < delazification.scriptData.size()) {
maxScriptDataLength = delazification.scriptData.size();
}
if (maxScopeDataLength < delazification.scopeData.size()) {
maxScopeDataLength = delazification.scopeData.size();
}
}
if (maxScriptDataLength < delazification.scriptData.size()) {
maxScriptDataLength = delazification.scriptData.size();
if (!gcOutputForDelazification->functions.reserve(maxScriptDataLength)) {
ReportOutOfMemory(cx);
return false;
}
if (maxScopeDataLength < delazification.scopeData.size()) {
maxScopeDataLength = delazification.scopeData.size();
if (!gcOutputForDelazification->scopes.reserve(maxScopeDataLength)) {
ReportOutOfMemory(cx);
return false;
}
if (!stencil.delazificationSet->buildDelazificationIndices(cx, stencil)) {
return false;
}
}
if (!input.atomCache.extendIfNecessary(cx, maxParserAtomDataLength)) {
return false;
}
if (!gcOutput.functions.reserve(maxScriptDataLength)) {
ReportOutOfMemory(cx);
return false;
}
if (!gcOutput.scopes.reserve(maxScopeDataLength)) {
ReportOutOfMemory(cx);
return false;
}
if (!buildDelazificationIndices(cx)) {
return false;
}
return true;
// The `atomCache` is used for the base and delazification stencils.
return stencil.input.atomCache.allocate(cx, maxParserAtomDataLength);
}
bool CompilationStencil::serializeStencils(JSContext* cx,
@ -1566,9 +1523,9 @@ bool CompilationStencil::serializeStencils(JSContext* cx,
return true;
}
bool CompilationStencilSet::deserializeStencils(JSContext* cx,
const JS::TranscodeRange& range,
bool* succeededOut) {
bool CompilationStencil::deserializeStencils(JSContext* cx,
const JS::TranscodeRange& range,
bool* succeededOut) {
if (succeededOut) {
*succeededOut = false;
}
@ -2812,19 +2769,6 @@ bool CompilationAtomCache::allocate(JSContext* cx, size_t length) {
return true;
}
bool CompilationAtomCache::extendIfNecessary(JSContext* cx, size_t length) {
if (length <= atoms_.length()) {
return true;
}
if (!atoms_.resize(length)) {
ReportOutOfMemory(cx);
return false;
}
return true;
}
void CompilationAtomCache::stealBuffer(AtomCacheVector& atoms) {
atoms_ = std::move(atoms);
// Destroy elements, without unreserving.

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

@ -126,24 +126,24 @@ using ParserBindingIter = AbstractBindingIter<TaggedParserAtomIndex>;
// ...
// }
//
// struct StencilDelazificationSet {
// Span<BaseCompilationStencil> delazifications;
// ...
// }
//
// struct CompilationStencil : BaseCompilationStencil {
// LifoAlloc alloc;
// CompilationInput input;
// Span<ScriptStencilExtra> scriptExtra;
// ...
// }
//
// struct CompilationStencilSet : CompilationStencil {
// Span<BaseCompilationStencil> delazifications;
// StencilDelazifcationSet* delazificationSet;
// ...
// }
//
// When we delazify a function that was lazily parsed, we generate a new Stencil
// at the point too. These delazifications can be cached as well. When loading
// back from a cache we group these together in a `CompilationStencilSet`. Note
// that the base class we inherit from provides storage for the initial lazy
// parse and the `delazifications` field is the collection of delazified
// function data that are available.
// back from a cache we group these together in a `StencilDelazificationSet`
// structure that hangs off the `CompilationStencil`. This delazification data
// is only meaningful if we also have the initial parse stencil.
//
//
// CompilationGCOutput

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

@ -42,7 +42,7 @@
#include "builtin/Symbol.h"
#include "frontend/BytecodeCompilation.h" // frontend::CompileGlobalScriptToStencil, frontend::InstantiateStencils
#include "frontend/BytecodeCompiler.h"
#include "frontend/CompilationStencil.h" // frontend::CompilationStencilSet, frontend::CompilationGCOutput
#include "frontend/CompilationStencil.h" // frontend::CompilationStencil, frontend::CompilationGCOutput
#include "gc/FreeOp.h"
#include "gc/Marking.h"
#include "gc/Policy.h"
@ -5747,16 +5747,17 @@ JS_PUBLIC_API JS::TranscodeResult JS::DecodeScript(
return JS::TranscodeResult_Ok;
}
static JS::TranscodeResult DecodeStencil(
JSContext* cx, JS::TranscodeBuffer& buffer,
frontend::CompilationStencilSet& stencilSet, size_t cursorIndex) {
XDRStencilDecoder decoder(cx, &stencilSet.input.options, buffer, cursorIndex);
static JS::TranscodeResult DecodeStencil(JSContext* cx,
JS::TranscodeBuffer& buffer,
frontend::CompilationStencil& stencil,
size_t cursorIndex) {
XDRStencilDecoder decoder(cx, &stencil.input.options, buffer, cursorIndex);
if (!stencilSet.input.initForGlobal(cx)) {
if (!stencil.input.initForGlobal(cx)) {
return JS::TranscodeResult_Throw;
}
XDRResult res = decoder.codeStencils(stencilSet);
XDRResult res = decoder.codeStencils(stencil);
if (res.isErr()) {
return res.unwrapErr();
}
@ -5778,19 +5779,19 @@ JS_PUBLIC_API JS::TranscodeResult JS::DecodeScriptMaybeStencil(
// The buffer contains stencil.
Rooted<frontend::CompilationStencilSet> stencilSet(
cx, frontend::CompilationStencilSet(cx, options));
Rooted<frontend::CompilationStencil> stencil(
cx, frontend::CompilationStencil(cx, options));
JS::TranscodeResult res =
DecodeStencil(cx, buffer, stencilSet.get(), cursorIndex);
DecodeStencil(cx, buffer, stencil.get(), cursorIndex);
if (res != JS::TranscodeResult_Ok) {
return res;
}
Rooted<frontend::CompilationGCOutput> gcOutput(cx);
Rooted<frontend::CompilationGCOutput> gcOutputForDelazification(cx);
if (!frontend::InstantiateStencils(cx, stencilSet.get(), gcOutput.get(),
gcOutputForDelazification.get())) {
if (!frontend::InstantiateStencils(cx, stencil.get(), gcOutput.get(),
gcOutputForDelazification.address())) {
return JS::TranscodeResult_Throw;
}
@ -5823,25 +5824,25 @@ JS_PUBLIC_API JS::TranscodeResult JS::DecodeScriptAndStartIncrementalEncoding(
size_t cursorIndex) {
MOZ_DIAGNOSTIC_ASSERT(options.useStencilXDR);
Rooted<frontend::CompilationStencilSet> stencilSet(
cx, frontend::CompilationStencilSet(cx, options));
Rooted<frontend::CompilationStencil> stencil(
cx, frontend::CompilationStencil(cx, options));
JS::TranscodeResult res =
DecodeStencil(cx, buffer, stencilSet.get(), cursorIndex);
DecodeStencil(cx, buffer, stencil.get(), cursorIndex);
if (res != JS::TranscodeResult_Ok) {
return res;
}
UniquePtr<XDRIncrementalStencilEncoder> xdrEncoder;
if (!stencilSet.get().input.source()->xdrEncodeStencils(cx, stencilSet.get(),
xdrEncoder)) {
if (!stencil.get().input.source()->xdrEncodeStencils(cx, stencil.get(),
xdrEncoder)) {
return JS::TranscodeResult_Throw;
}
Rooted<frontend::CompilationGCOutput> gcOutput(cx);
Rooted<frontend::CompilationGCOutput> gcOutputForDelazification(cx);
if (!frontend::InstantiateStencils(cx, stencilSet.get(), gcOutput.get(),
gcOutputForDelazification.get())) {
if (!frontend::InstantiateStencils(cx, stencil.get(), gcOutput.get(),
gcOutputForDelazification.address())) {
return JS::TranscodeResult_Throw;
}

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

@ -20,7 +20,7 @@
#include "jsapi.h"
#include "ds/Fifo.h"
#include "frontend/CompilationStencil.h" // CompilationStencil, CompilationStencilSet, CompilationGCOutput
#include "frontend/CompilationStencil.h" // CompilationStencil, CompilationGCOutput
#include "js/CompileOptions.h"
#include "js/TypeDecls.h"
#include "threading/ConditionVariable.h"
@ -519,12 +519,10 @@ struct ParseTask : public mozilla::LinkedListElement<ParseTask>,
// Holds the ScriptSourceObjects generated for the script compilation.
GCVector<ScriptSourceObject*, 1, SystemAllocPolicy> sourceObjects;
// Holds the CompilationStencil generated for the script compilation.
// Holds the CompilationStencil generated for the script compilation or
// decoding task.
UniquePtr<frontend::CompilationStencil> stencil_;
// Holds the CompilationStencilSet generated by decoding task.
UniquePtr<frontend::CompilationStencilSet> stencilSet_;
frontend::CompilationGCOutput gcOutput_;
frontend::CompilationGCOutput gcOutputForDelazification_;

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

@ -15,7 +15,7 @@
#include <algorithm>
#include "frontend/BytecodeCompilation.h"
#include "frontend/CompilationStencil.h" // frontend::CompilationStencilSet, frontend::CompilationGCOutput
#include "frontend/CompilationStencil.h" // frontend::CompilationStencil, frontend::CompilationGCOutput
#include "frontend/ParserAtom.h" // frontend::ParserAtomsTable
#include "gc/GC.h" // gc::MergeRealms
#include "jit/IonCompileTask.h"
@ -585,9 +585,6 @@ void ParseTask::trace(JSTracer* trc) {
if (stencil_) {
stencil_->trace(trc);
}
if (stencilSet_) {
stencilSet_->trace(trc);
}
gcOutput_.trace(trc);
gcOutputForDelazification_.trace(trc);
}
@ -695,17 +692,12 @@ void ScriptParseTask<Unit>::parse(JSContext* cx) {
}
bool ParseTask::instantiateStencils(JSContext* cx) {
if (!stencil_ && !stencilSet_) {
if (!stencil_) {
return false;
}
bool result;
if (stencil_) {
result = frontend::InstantiateStencils(cx, *stencil_, gcOutput_);
} else {
result = frontend::InstantiateStencils(cx, *stencilSet_, gcOutput_,
gcOutputForDelazification_);
}
bool result = frontend::InstantiateStencils(cx, *stencil_, gcOutput_,
&gcOutputForDelazification_);
// Whatever happens to the top-level script compilation (even if it fails),
// we must finish initializing the SSO. This is because there may be valid
@ -778,29 +770,29 @@ void ScriptDecodeTask::parse(JSContext* cx) {
if (options.useStencilXDR) {
// The buffer contains stencil.
Rooted<UniquePtr<frontend::CompilationStencilSet>> stencilSet(
cx, js_new<frontend::CompilationStencilSet>(cx, options));
if (!stencilSet) {
Rooted<UniquePtr<frontend::CompilationStencil>> stencil(
cx, js_new<frontend::CompilationStencil>(cx, options));
if (!stencil) {
ReportOutOfMemory(cx);
return;
}
XDRStencilDecoder decoder(cx, &stencilSet.get()->input.options, range);
if (!stencilSet.get()->input.initForGlobal(cx)) {
XDRStencilDecoder decoder(cx, &stencil.get()->input.options, range);
if (!stencil.get()->input.initForGlobal(cx)) {
return;
}
XDRResult res = decoder.codeStencils(*stencilSet);
XDRResult res = decoder.codeStencils(*stencil);
if (!res.isOk()) {
return;
}
stencilSet_ = std::move(stencilSet.get());
stencil_ = std::move(stencil.get());
if (stencilSet_) {
if (!frontend::PrepareForInstantiate(cx, *stencilSet_, gcOutput_,
gcOutputForDelazification_)) {
stencilSet_ = nullptr;
if (stencil_) {
if (!frontend::PrepareForInstantiate(cx, *stencil_, gcOutput_,
&gcOutputForDelazification_)) {
stencil_ = nullptr;
}
}
@ -2078,7 +2070,7 @@ JSScript* GlobalHelperThreadState::finishSingleParseTask(
DebugAPI::onNewScript(cx, script);
}
} else {
MOZ_ASSERT(parseTask->stencil_.get() || parseTask->stencilSet_.get());
MOZ_ASSERT(parseTask->stencil_.get());
if (!parseTask->instantiateStencils(cx)) {
return nullptr;
@ -2096,14 +2088,8 @@ JSScript* GlobalHelperThreadState::finishSingleParseTask(
if (parseTask->stencil_.get()) {
auto* stencil = parseTask->stencil_.get();
if (!stencil->input.source()->xdrEncodeInitialStencil(cx, *stencil,
xdrEncoder)) {
return nullptr;
}
} else {
auto* stencilSet = parseTask->stencilSet_.get();
if (!stencilSet->input.source()->xdrEncodeStencils(cx, *stencilSet,
xdrEncoder)) {
if (!stencil->input.source()->xdrEncodeStencils(cx, *stencil,
xdrEncoder)) {
return nullptr;
}
}

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

@ -2725,15 +2725,17 @@ bool ScriptSource::xdrEncodeInitialStencil(
}
bool ScriptSource::xdrEncodeStencils(
JSContext* cx, frontend::CompilationStencilSet& stencilSet,
JSContext* cx, frontend::CompilationStencil& stencil,
UniquePtr<XDRIncrementalStencilEncoder>& xdrEncoder) {
if (!xdrEncodeInitialStencil(cx, stencilSet, xdrEncoder)) {
if (!xdrEncodeInitialStencil(cx, stencil, xdrEncoder)) {
return false;
}
for (auto& delazification : stencilSet.delazifications) {
if (!xdrEncodeFunctionStencilWith(cx, delazification, xdrEncoder)) {
return false;
if (stencil.delazificationSet) {
for (auto& delazification : stencil.delazificationSet->delazifications) {
if (!xdrEncodeFunctionStencilWith(cx, delazification, xdrEncoder)) {
return false;
}
}
}

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

@ -1033,8 +1033,7 @@ class ScriptSource {
// Caller is responsible for calling `setIncrementalEncoder` after
// instantiating stencil (so, corresponding canonical ScriptSourceObject
// gets created).
bool xdrEncodeStencils(JSContext* cx,
frontend::CompilationStencilSet& stencilSet,
bool xdrEncodeStencils(JSContext* cx, frontend::CompilationStencil& stencil,
UniquePtr<XDRIncrementalStencilEncoder>& xdrEncoder);
void setIncrementalEncoder(XDRIncrementalStencilEncoder* xdrEncoder);

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

@ -645,7 +645,7 @@ struct JSRuntime {
// Used internally to initialize the self-hosted global using XDR content.
bool initSelfHostingFromXDR(JSContext* cx, const JS::CompileOptions& options,
js::frontend::CompilationStencilSet& stencilSet,
js::frontend::CompilationStencil& stencil,
js::MutableHandle<JSScript*> scriptOut);
public:

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

@ -2771,10 +2771,10 @@ static bool VerifyGlobalNames(JSContext* cx, Handle<GlobalObject*> shg) {
return true;
}
bool JSRuntime::initSelfHostingFromXDR(
JSContext* cx, const CompileOptions& options,
frontend::CompilationStencilSet& stencilSet,
MutableHandle<JSScript*> scriptOut) {
bool JSRuntime::initSelfHostingFromXDR(JSContext* cx,
const CompileOptions& options,
frontend::CompilationStencil& stencil,
MutableHandle<JSScript*> scriptOut) {
MOZ_ASSERT(selfHostingGlobal_);
MOZ_ASSERT(selfHostedXDR.length() > 0);
scriptOut.set(nullptr);
@ -2782,7 +2782,7 @@ bool JSRuntime::initSelfHostingFromXDR(
// Deserialize the stencil from XDR.
JS::TranscodeRange xdrRange(selfHostedXDR);
bool decodeOk = false;
if (!stencilSet.deserializeStencils(cx, xdrRange, &decodeOk)) {
if (!stencil.deserializeStencils(cx, xdrRange, &decodeOk)) {
return false;
}
// If XDR decode failed, it's not a propagated error.
@ -2793,7 +2793,7 @@ bool JSRuntime::initSelfHostingFromXDR(
// Instantiate the stencil.
Rooted<frontend::CompilationGCOutput> output(cx);
if (!frontend::CompilationStencil::instantiateStencils(cx, stencilSet,
if (!frontend::CompilationStencil::instantiateStencils(cx, stencil,
output.get())) {
return false;
}
@ -2836,13 +2836,13 @@ bool JSRuntime::initSelfHosting(JSContext* cx) {
// Try initializing from Stencil XDR.
if (selfHostedXDR.length() > 0) {
// Initialize the compilation info that houses the stencil.
Rooted<frontend::CompilationStencilSet> stencilSet(
cx, frontend::CompilationStencilSet(cx, options));
if (!stencilSet.get().input.initForSelfHostingGlobal(cx)) {
Rooted<frontend::CompilationStencil> stencil(
cx, frontend::CompilationStencil(cx, options));
if (!stencil.get().input.initForSelfHostingGlobal(cx)) {
return false;
}
if (!initSelfHostingFromXDR(cx, options, stencilSet.get(), &script)) {
if (!initSelfHostingFromXDR(cx, options, stencil.get(), &script)) {
return false;
}
}

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

@ -19,9 +19,9 @@
#include "builtin/ModuleObject.h"
#include "debugger/DebugAPI.h"
#include "frontend/CompilationStencil.h" // frontend::BaseCompilationStencil, frontend::CompilationStencil, frontend::CompilationStencilSet
#include "frontend/ParserAtom.h" // frontend::ParserAtom
#include "js/BuildId.h" // JS::BuildIdCharVector
#include "frontend/CompilationStencil.h" // frontend::BaseCompilationStencil, frontend::CompilationStencil
#include "frontend/ParserAtom.h" // frontend::ParserAtom
#include "js/BuildId.h" // JS::BuildIdCharVector
#include "vm/JSContext.h"
#include "vm/JSScript.h"
#include "vm/SharedStencil.h" // js::SourceExtent
@ -478,45 +478,58 @@ XDRResult XDRIncrementalStencilEncoder::linearize(JS::TranscodeBuffer& buffer,
void XDRDecoder::trace(JSTracer* trc) { atomTable_.trace(trc); }
XDRResult XDRStencilDecoder::codeStencils(
frontend::CompilationStencilSet& stencilSet) {
MOZ_ASSERT(stencilSet.delazifications.length() == 0);
frontend::CompilationStencil& stencil) {
MOZ_ASSERT(!stencil.delazificationSet);
frontend::ParserAtomSpanBuilder parserAtomBuilder(cx()->runtime(),
stencilSet.parserAtomData);
stencil.parserAtomData);
parserAtomBuilder_ = &parserAtomBuilder;
stencilAlloc_ = &stencilSet.alloc;
stencilAlloc_ = &stencil.alloc;
MOZ_TRY(codeStencil(stencilSet));
MOZ_TRY(codeStencil(stencil));
if (!stencilSet.delazifications.reserve(nchunks_ - 1)) {
ReportOutOfMemory(cx());
return fail(JS::TranscodeResult_Throw);
}
// Decode any delazification stencil from XDR.
if (nchunks_ > 1) {
auto delazificationSet = MakeUnique<frontend::StencilDelazificationSet>();
if (!delazificationSet) {
ReportOutOfMemory(cx());
return fail(JS::TranscodeResult_Throw);
}
for (size_t i = 1; i < nchunks_; i++) {
stencilSet.delazifications.infallibleEmplaceBack();
auto& delazification = stencilSet.delazifications[i - 1];
if (!delazificationSet->delazifications.reserve(nchunks_ - 1)) {
ReportOutOfMemory(cx());
return fail(JS::TranscodeResult_Throw);
}
hasFinishedAtomTable_ = false;
for (size_t i = 1; i < nchunks_; i++) {
delazificationSet->delazifications.infallibleEmplaceBack();
auto& delazification = delazificationSet->delazifications[i - 1];
frontend::ParserAtomSpanBuilder parserAtomBuilder(
cx()->runtime(), delazification.parserAtomData);
parserAtomBuilder_ = &parserAtomBuilder;
hasFinishedAtomTable_ = false;
MOZ_TRY(codeFunctionStencil(delazification));
frontend::ParserAtomSpanBuilder parserAtomBuilder(
cx()->runtime(), delazification.parserAtomData);
parserAtomBuilder_ = &parserAtomBuilder;
MOZ_TRY(codeFunctionStencil(delazification));
}
stencil.delazificationSet = std::move(delazificationSet);
}
return Ok();
}
XDRResult XDRIncrementalStencilEncoder::codeStencils(
frontend::CompilationStencilSet& stencilSet) {
frontend::CompilationStencil& stencil) {
MOZ_ASSERT(encodedFunctions_.count() == 0);
MOZ_TRY(codeStencil(stencilSet));
MOZ_TRY(codeStencil(stencil));
for (auto& delazification : stencilSet.delazifications) {
MOZ_TRY(codeFunctionStencil(delazification));
if (stencil.delazificationSet) {
for (auto& delazification : stencil.delazificationSet->delazifications) {
MOZ_TRY(codeFunctionStencil(delazification));
}
}
return Ok();

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

@ -29,7 +29,6 @@ struct SourceExtent;
namespace frontend {
struct CompilationStencil;
struct CompilationStencilSet;
struct CompilationInput;
struct BaseCompilationStencil;
} // namespace frontend
@ -254,7 +253,7 @@ class XDRState : public XDRCoderBase {
virtual void finishAtomTable() { MOZ_CRASH("does not have atomTable"); }
virtual XDRResult codeDelazificationStencils(
frontend::CompilationStencilSet& stencilSet) {
frontend::CompilationStencil& stencil) {
MOZ_CRASH("cannot code delazification stencils.");
}
@ -557,7 +556,7 @@ class XDRStencilDecoder : public XDRDecoderBase {
bool hasOptions() const override { return true; }
const JS::ReadOnlyCompileOptions& options() override { return *options_; }
XDRResult codeStencils(frontend::CompilationStencilSet& stencilSet);
XDRResult codeStencils(frontend::CompilationStencil& stencil);
private:
const JS::ReadOnlyCompileOptions* options_;
@ -640,7 +639,7 @@ class XDRIncrementalStencilEncoder : public XDREncoder {
XDRResult linearize(JS::TranscodeBuffer& buffer, js::ScriptSource* ss);
XDRResult codeStencils(frontend::CompilationStencilSet& stencilSet);
XDRResult codeStencils(frontend::CompilationStencil& stencil);
private:
void switchToBuffer(XDRBuffer<XDR_ENCODE>* target) { buf = target; }