Bug 1730881 - Initialize CompilationSyntaxParseCache from InputScript variants. r=arai

This change clone some of the functions used to initialize the
CompilationSyntaxParseCache. These are specialized to copy the minimal set of
information needed for skipping inner functions and for iterating over
closed-over-bindings.

Unforutnately, as opposed to what this structure was initialy designed for, we
are not yet able to reuse the Stencils from the InputScript as ParseAtomIndex of
the InputScript are in the context of the InputScript and not of the
CompilationState which wraps the CompilationSyntaxParseCache. Until we are
capable of reusing the same indexes of a previous compilation, we would have to
duplicate the Stencil structures. Thus, copyScriptInfo and
copyClosedOVerBindings are copied from the original functions and adapted to
work with Stencil inputs.

Differential Revision: https://phabricator.services.mozilla.com/D128180
This commit is contained in:
Nicolas B. Pierron 2021-11-04 18:25:42 +00:00
Родитель 51e61a53c5
Коммит 7e04d0a168
2 изменённых файлов: 148 добавлений и 20 удалений

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

@ -657,7 +657,8 @@ struct CompilationInput {
// The BaseScript* is needed when instantiating a lazy function.
// See InstantiateTopLevel and FunctionsFromExistingLazy.
BaseScript* lazyOuterScript() { return lazy_.raw().as<BaseScript*>(); }
InputScript lazyOuterScript() { return lazy_; }
BaseScript* lazyOuterBaseScript() { return lazy_.raw().as<BaseScript*>(); }
// The JSFunction* is needed when instantiating a lazy function.
// See FunctionsFromExistingLazy.
@ -774,7 +775,8 @@ class CompilationSyntaxParseCache {
// used for reporting allocation errors.
[[nodiscard]] bool init(JSContext* cx, LifoAlloc& alloc,
ParserAtomsTable& parseAtoms,
CompilationAtomCache& atomCache, BaseScript* lazy);
CompilationAtomCache& atomCache,
const InputScript& lazy);
private:
// Return the script index of a given inner function.
@ -792,17 +794,25 @@ class CompilationSyntaxParseCache {
}
[[nodiscard]] bool copyFunctionInfo(JSContext* cx,
ParserAtomsTable& parseAtoms,
CompilationAtomCache& atomCache,
const InputScript& lazy);
[[nodiscard]] bool copyScriptInfo(JSContext* cx, LifoAlloc& alloc,
ParserAtomsTable& parseAtoms,
CompilationAtomCache& atomCache,
BaseScript* lazy);
[[nodiscard]] bool copyScriptInfo(JSContext* cx, LifoAlloc& alloc,
ParserAtomsTable& parseAtoms,
CompilationAtomCache& atomCache,
const ScriptStencilRef& lazy);
[[nodiscard]] bool copyClosedOverBindings(JSContext* cx, LifoAlloc& alloc,
ParserAtomsTable& parseAtoms,
CompilationAtomCache& atomCache,
BaseScript* lazy);
[[nodiscard]] bool copyClosedOverBindings(JSContext* cx, LifoAlloc& alloc,
ParserAtomsTable& parseAtoms,
CompilationAtomCache& atomCache,
BaseScript* lazy);
const ScriptStencilRef& lazy);
};
// AsmJS scripts are very rare on-average, so we use a HashMap to associate
@ -1284,7 +1294,7 @@ struct MOZ_RAII CompilationState : public ExtensibleCompilationStencil {
// gcThings is later used by the full parser initialization.
if (input.isDelazifying()) {
BaseScript* lazy = input.lazyOuterScript();
InputScript lazy = input.lazyOuterScript();
auto& atomCache = input.atomCache;
if (!previousParseCache.init(cx, alloc, parserAtoms, atomCache, lazy)) {
return false;

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

@ -860,14 +860,20 @@ void CompilationInput::trace(JSTracer* trc) {
bool CompilationSyntaxParseCache::init(JSContext* cx, LifoAlloc& alloc,
ParserAtomsTable& parseAtoms,
CompilationAtomCache& atomCache,
BaseScript* lazy) {
const InputScript& lazy) {
if (!copyFunctionInfo(cx, parseAtoms, atomCache, lazy)) {
return false;
}
if (!copyScriptInfo(cx, alloc, parseAtoms, atomCache, lazy)) {
bool success = lazy.raw().match([&](auto& ref) {
if (!copyScriptInfo(cx, alloc, parseAtoms, atomCache, ref)) {
return false;
}
if (!copyClosedOverBindings(cx, alloc, parseAtoms, atomCache, lazy)) {
if (!copyClosedOverBindings(cx, alloc, parseAtoms, atomCache, ref)) {
return false;
}
return true;
});
if (!success) {
return false;
}
#ifdef DEBUG
@ -878,20 +884,19 @@ bool CompilationSyntaxParseCache::init(JSContext* cx, LifoAlloc& alloc,
bool CompilationSyntaxParseCache::copyFunctionInfo(
JSContext* cx, ParserAtomsTable& parseAtoms,
CompilationAtomCache& atomCache, BaseScript* lazy) {
if (lazy->function()->displayAtom()) {
displayAtom_ =
parseAtoms.internJSAtom(cx, atomCache, lazy->function()->displayAtom());
CompilationAtomCache& atomCache, const InputScript& lazy) {
InputName name = lazy.displayAtom();
if (!name.isNull()) {
displayAtom_ = name.internInto(cx, parseAtoms, atomCache);
if (!displayAtom_) {
return false;
}
}
funExtra_.immutableFlags = lazy->immutableFlags();
funExtra_.extent = lazy->extent();
funExtra_.immutableFlags = lazy.immutableFlags();
funExtra_.extent = lazy.extent();
if (funExtra_.useMemberInitializers()) {
funExtra_.setMemberInitializers(
lazy->function()->baseScript()->getMemberInitializers());
funExtra_.setMemberInitializers(lazy.getMemberInitializers());
}
return true;
@ -969,6 +974,68 @@ bool CompilationSyntaxParseCache::copyScriptInfo(
return true;
}
bool CompilationSyntaxParseCache::copyScriptInfo(
JSContext* cx, LifoAlloc& alloc, ParserAtomsTable& parseAtoms,
CompilationAtomCache& atomCache, const ScriptStencilRef& lazy) {
using GCThingsSpan = mozilla::Span<TaggedScriptThingIndex>;
using ScriptDataSpan = mozilla::Span<ScriptStencil>;
using ScriptExtraSpan = mozilla::Span<ScriptStencilExtra>;
cachedGCThings_ = GCThingsSpan(nullptr);
cachedScriptData_ = ScriptDataSpan(nullptr);
cachedScriptExtra_ = ScriptExtraSpan(nullptr);
size_t offset = lazy.scriptData().gcThingsOffset.index;
size_t length = lazy.scriptData().gcThingsLength;
if (length == 0) {
return true;
}
// Reduce the length to the first element which is not a function.
for (size_t i = offset; i < offset + length; i++) {
if (!lazy.context_.gcThingData[i].isFunction()) {
length = i - offset;
break;
}
}
TaggedScriptThingIndex* gcThingsData =
alloc.newArrayUninitialized<TaggedScriptThingIndex>(length);
ScriptStencil* scriptData =
alloc.newArrayUninitialized<ScriptStencil>(length);
ScriptStencilExtra* scriptExtra =
alloc.newArrayUninitialized<ScriptStencilExtra>(length);
if (!gcThingsData || !scriptData || !scriptExtra) {
ReportOutOfMemory(cx);
return false;
}
for (size_t i = 0; i < length; i++) {
ScriptStencilRef inner{lazy.context_,
lazy.context_.gcThingData[i + offset].toFunction()};
gcThingsData[i] = TaggedScriptThingIndex(ScriptIndex(i));
new (mozilla::KnownNotNull, &scriptData[i]) ScriptStencil();
ScriptStencil& data = scriptData[i];
ScriptStencilExtra& extra = scriptExtra[i];
InputName name{inner, inner.scriptData().functionAtom};
if (!name.isNull()) {
auto displayAtom = name.internInto(cx, parseAtoms, atomCache);
if (!displayAtom) {
return false;
}
data.functionAtom = displayAtom;
}
data.functionFlags = inner.scriptData().functionFlags;
extra = inner.scriptExtra();
}
cachedGCThings_ = GCThingsSpan(gcThingsData, length);
cachedScriptData_ = ScriptDataSpan(scriptData, length);
cachedScriptExtra_ = ScriptExtraSpan(scriptExtra, length);
return true;
}
bool CompilationSyntaxParseCache::copyClosedOverBindings(
JSContext* cx, LifoAlloc& alloc, ParserAtomsTable& parseAtoms,
CompilationAtomCache& atomCache, BaseScript* lazy) {
@ -1015,6 +1082,56 @@ bool CompilationSyntaxParseCache::copyClosedOverBindings(
return true;
}
bool CompilationSyntaxParseCache::copyClosedOverBindings(
JSContext* cx, LifoAlloc& alloc, ParserAtomsTable& parseAtoms,
CompilationAtomCache& atomCache, const ScriptStencilRef& lazy) {
using ClosedOverBindingsSpan = mozilla::Span<TaggedParserAtomIndex>;
closedOverBindings_ = ClosedOverBindingsSpan(nullptr);
// The gcthings array contains the inner function list followed by the
// closed-over bindings data. Skip the inner function list, as it is already
// cached in cachedGCThings_. See also: BaseScript::CreateLazy.
size_t offset = lazy.scriptData().gcThingsOffset.index;
size_t length = lazy.scriptData().gcThingsLength;
size_t start = cachedGCThings_.Length();
MOZ_ASSERT(start <= length);
if (length - start == 0) {
return true;
}
length -= start;
start += offset;
// Atoms from the lazy.context (CompilationStencil) are not registered in the
// the parseAtoms table. Thus we create a new span which will contain all the
// interned atoms.
TaggedParserAtomIndex* closedOverBindings =
alloc.newArrayUninitialized<TaggedParserAtomIndex>(length);
if (!closedOverBindings) {
ReportOutOfMemory(cx);
return false;
}
for (size_t i = 0; i < length; i++) {
auto gcThing = lazy.context_.gcThingData[i + start];
if (gcThing.isNull()) {
closedOverBindings[i] = TaggedParserAtomIndex::null();
continue;
}
MOZ_ASSERT(gcThing.isAtom());
InputName name(lazy, gcThing.toAtom());
auto parserAtom = name.internInto(cx, parseAtoms, atomCache);
if (!parserAtom) {
return false;
}
closedOverBindings[i] = parserAtom;
}
closedOverBindings_ = ClosedOverBindingsSpan(closedOverBindings, length);
return true;
}
void CompilationAtomCache::trace(JSTracer* trc) { atoms_.trace(trc); }
void CompilationGCOutput::trace(JSTracer* trc) {
@ -1514,8 +1631,9 @@ static bool InstantiateTopLevel(JSContext* cx, CompilationInput& input,
MOZ_ASSERT(stencil.sharedData.get(CompilationStencil::TopLevelIndex));
if (!stencil.isInitialStencil()) {
MOZ_ASSERT(input.lazyOuterScript());
RootedScript script(cx, JSScript::CastFromLazy(input.lazyOuterScript()));
MOZ_ASSERT(input.lazyOuterBaseScript());
RootedScript script(cx,
JSScript::CastFromLazy(input.lazyOuterBaseScript()));
if (!JSScript::fullyInitFromStencil(cx, input.atomCache, stencil, gcOutput,
script,
CompilationStencil::TopLevelIndex)) {
@ -1713,7 +1831,7 @@ static void FunctionsFromExistingLazy(CompilationInput& input,
MOZ_ASSERT(gcOutput.functions.empty());
gcOutput.functions.infallibleAppend(input.function());
for (JS::GCCellPtr elem : input.lazyOuterScript()->gcthings()) {
for (JS::GCCellPtr elem : input.lazyOuterBaseScript()->gcthings()) {
if (!elem.is<JSObject>()) {
continue;
}