зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
b1dbdf1b3a
Коммит
ef55ed47f6
|
@ -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_; }
|
||||
|
|
Загрузка…
Ссылка в новой задаче