Bug 1644536 - Cleanup FieldInitializers initialization. r=mgaudet

FieldInitializers is only defined for functions that have a compiled
enclosing script. We should avoid setting the value when it is not defined.
Update initFromLazyFunction so that fieldInitializers are only read for the
function being delazified. Fix XDR to not track fieldInitializers for lazy
functions with lazy parent functions by checking for exisitance of an
enclosingScope.

Also ensure fieldInitializers are set correctly when cloning scripts. In
practice, we delazify entire script tree before cloning but this is a footgun
none the less.

Differential Revision: https://phabricator.services.mozilla.com/D79282
This commit is contained in:
Ted Campbell 2020-06-15 19:48:28 +00:00
Родитель b1dbdf1b3a
Коммит ef55ed47f6
6 изменённых файлов: 43 добавлений и 6 удалений

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

@ -5654,6 +5654,8 @@ MOZ_NEVER_INLINE bool BytecodeEmitter::emitFunction(
// NOTE: For a lazy function, this will be applied to any existing function
// in FunctionBox::finish().
if (classContentsIfConstructor) {
MOZ_ASSERT(funbox->fieldInitializers.isNothing(),
"FieldInitializers should only be set once");
funbox->fieldInitializers = setupFieldInitializers(
classContentsIfConstructor, FieldPlacement::Instance);
if (!funbox->fieldInitializers) {

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

@ -3214,6 +3214,10 @@ FunctionNode* Parser<FullParseHandler, Unit>::standaloneLazyFunction(
funbox->initWithEnclosingScope(this->getCompilationInfo().scopeContext,
fun->enclosingScope(), fun->flags(),
syntaxKind);
if (fun->isClassConstructor()) {
funbox->fieldInitializers =
mozilla::Some(fun->baseScript()->getFieldInitializers());
}
Directives newDirectives = directives;
SourceParseContext funpc(this, funbox, &newDirectives);

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

@ -283,10 +283,6 @@ void FunctionBox::initFromLazyFunction(JSFunction* fun) {
BaseScript* lazy = fun->baseScript();
immutableFlags_ = lazy->immutableFlags();
extent = lazy->extent();
if (fun->isClassConstructor()) {
fieldInitializers = mozilla::Some(lazy->getFieldInitializers());
}
}
void FunctionBox::initWithEnclosingParseContext(ParseContext* enclosing,

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

@ -9,3 +9,28 @@ evalWithCache(test, { assertEqBytecode : true });
var test = "new class { method() { super.toString(); } }().method()";
evalWithCache(test, { assertEqBytecode : true });
// Test class constructor in lazy function
var test = `
function f(delazify) {
function inner1() {
class Y {
constructor() {}
}
}
function inner2() {
class Y {
constructor() {}
field1 = "";
}
}
if (delazify) {
inner1();
inner2();
}
}
f(generation > 0);
`;
evalWithCache(test, {});

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

@ -714,6 +714,8 @@ XDRResult js::PrivateScriptData::XDR(XDRState<mode>* xdr, HandleScript script,
// Code the field initilizer data.
if (funOrMod && funOrMod->is<JSFunction>() &&
funOrMod->as<JSFunction>().isClassConstructor()) {
MOZ_ASSERT(scriptEnclosingScope);
uint32_t numFieldInitializers;
if (mode == XDR_ENCODE) {
numFieldInitializers = data->getFieldInitializers().numFieldInitializers;
@ -1218,7 +1220,9 @@ XDRResult js::XDRLazyScript(XDRState<mode>* xdr, HandleScope enclosingScope,
}
}
bool hasFieldInitializers = fun->isClassConstructor();
// FieldInitializer data is defined for class constructors, but only once
// their enclosing script has been compiled.
bool hasFieldInitializers = fun->isClassConstructor() && enclosingScope;
MOZ_TRY(BaseScript::XDRLazyScriptData(xdr, sourceObject, lazy,
hasFieldInitializers));
@ -4789,8 +4793,10 @@ bool PrivateScriptData::Clone(JSContext* cx, HandleScript src, HandleScript dst,
if (!JSScript::createPrivateScriptData(cx, dst, ngcthings)) {
return false;
}
PrivateScriptData* dstData = dst->data_;
dstData->fieldInitializers_ = srcData->fieldInitializers_;
{
auto array = dstData->gcthings();
for (uint32_t i = 0; i < ngcthings; ++i) {

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

@ -1417,6 +1417,8 @@ class alignas(uintptr_t) PrivateScriptData final : public TrailingArray {
private:
uint32_t ngcthings = 0;
// Note: This is only defined for scripts with an enclosing scope. This
// excludes lazy scripts with lazy parents.
js::FieldInitializers fieldInitializers_ = js::FieldInitializers::Invalid();
// End of fields.
@ -1444,6 +1446,8 @@ class alignas(uintptr_t) PrivateScriptData final : public TrailingArray {
}
void setFieldInitializers(FieldInitializers fieldInitializers) {
MOZ_ASSERT(fieldInitializers_.valid == false,
"Only init FieldInitializers once");
fieldInitializers_ = fieldInitializers;
}
const FieldInitializers& getFieldInitializers() { return fieldInitializers_; }