Issue #2142 - Handle fields in derived classes

* Don't name field initializer lambdas

Based-on: m-c 1534721, 1551454, 1542448
This commit is contained in:
Martok 2023-04-08 03:47:06 +02:00 • committed by roytam1
commit 235ca77949
13 changed files with 361 additions and 190 deletions

View file

@ -676,8 +676,13 @@ frontend::CompileLazyFunction(JSContext* cx, Handle<LazyScript*> lazy, const cha
if (lazy->hasBeenCloned()) if (lazy->hasBeenCloned())
script->setHasBeenCloned(); script->setHasBeenCloned();
FieldInitializers fieldInitializers = FieldInitializers::Invalid();
if (fun->kind() == JSFunction::FunctionKind::ClassConstructor) {
fieldInitializers = lazy->getFieldInitializers();
}
BytecodeEmitter bce(/* parent = */ nullptr, &parser, pn->as<FunctionNode>().funbox(), script, lazy, BytecodeEmitter bce(/* parent = */ nullptr, &parser, pn->as<FunctionNode>().funbox(), script, lazy,
pn->pn_pos, BytecodeEmitter::LazyFunction); pn->pn_pos, BytecodeEmitter::LazyFunction, fieldInitializers);
if (!bce.init()) if (!bce.init())
return false; return false;

View file

@ -156,7 +156,8 @@ class MOZ_RAII OptionalEmitter
BytecodeEmitter::BytecodeEmitter(BytecodeEmitter* parent, BytecodeEmitter::BytecodeEmitter(BytecodeEmitter* parent,
Parser<FullParseHandler>* parser, SharedContext* sc, Parser<FullParseHandler>* parser, SharedContext* sc,
HandleScript script, Handle<LazyScript*> lazyScript, HandleScript script, Handle<LazyScript*> lazyScript,
uint32_t lineNum, EmitterMode emitterMode) uint32_t lineNum, EmitterMode emitterMode,
FieldInitializers fieldInitializers /* = FieldInitializers::Invalid() */)
: sc(sc), : sc(sc),
cx(sc->context), cx(sc->context),
parent(parent), parent(parent),
@ -166,6 +167,7 @@ BytecodeEmitter::BytecodeEmitter(BytecodeEmitter* parent,
main(cx, lineNum), main(cx, lineNum),
current(&main), current(&main),
parser(parser), parser(parser),
fieldInitializers_(fieldInitializers),
atomIndices(cx->frontendCollectionPool()), atomIndices(cx->frontendCollectionPool()),
firstLine(lineNum), firstLine(lineNum),
maxFixedSlots(0), maxFixedSlots(0),
@ -178,10 +180,6 @@ BytecodeEmitter::BytecodeEmitter(BytecodeEmitter* parent,
innermostNestableControl(nullptr), innermostNestableControl(nullptr),
innermostEmitterScope_(nullptr), innermostEmitterScope_(nullptr),
innermostTDZCheckCache(nullptr), innermostTDZCheckCache(nullptr),
fieldInitializers_(parent
? parent->fieldInitializers_
: lazyScript ? lazyScript->getFieldInitializers()
: FieldInitializers::Invalid()),
#ifdef DEBUG #ifdef DEBUG
unstableEmitterScope(false), unstableEmitterScope(false),
#endif #endif
@ -202,10 +200,11 @@ BytecodeEmitter::BytecodeEmitter(BytecodeEmitter* parent,
BytecodeEmitter::BytecodeEmitter(BytecodeEmitter* parent, BytecodeEmitter::BytecodeEmitter(BytecodeEmitter* parent,
Parser<FullParseHandler>* parser, SharedContext* sc, Parser<FullParseHandler>* parser, SharedContext* sc,
HandleScript script, Handle<LazyScript*> lazyScript, HandleScript script, Handle<LazyScript*> lazyScript,
TokenPos bodyPosition, EmitterMode emitterMode) TokenPos bodyPosition, EmitterMode emitterMode,
FieldInitializers fieldInitializers)
: BytecodeEmitter(parent, parser, sc, script, lazyScript, : BytecodeEmitter(parent, parser, sc, script, lazyScript,
parser->tokenStream.srcCoords.lineNum(bodyPosition.begin), parser->tokenStream.srcCoords.lineNum(bodyPosition.begin),
emitterMode) emitterMode, fieldInitializers)
{ {
setScriptStartOffsetIfUnset(bodyPosition.begin); setScriptStartOffsetIfUnset(bodyPosition.begin);
setFunctionBodyEndPos(bodyPosition.end); setFunctionBodyEndPos(bodyPosition.end);
@ -2321,6 +2320,10 @@ BytecodeEmitter::emitSetThis(BinaryNode* setThisNode)
return false; return false;
} }
if (!emitInitializeInstanceFields(true)) {
return false;
}
return true; return true;
} }
@ -2399,6 +2402,9 @@ BytecodeEmitter::emitFunctionScript(FunctionNode* funNode)
ListNode* paramsBody = &funNode->body()->as<ListNode>(); ListNode* paramsBody = &funNode->body()->as<ListNode>();
FunctionBox* funbox = sc->asFunctionBox(); FunctionBox* funbox = sc->asFunctionBox();
MOZ_ASSERT(fieldInitializers_.valid == (funbox->function()->kind() ==
JSFunction::FunctionKind::ClassConstructor));
setScriptStartOffsetIfUnset(paramsBody->pn_pos.begin); setScriptStartOffsetIfUnset(paramsBody->pn_pos.begin);
// [stack] // [stack]
@ -2433,6 +2439,8 @@ BytecodeEmitter::emitFunctionScript(FunctionNode* funNode)
if (!fse.initScript()) if (!fse.initScript())
return false; return false;
script->setFieldInitializers(fieldInitializers_);
return true; return true;
} }
@ -5593,11 +5601,14 @@ BytecodeEmitter::emitComprehensionFor(ForNode* forNode)
} }
MOZ_NEVER_INLINE bool MOZ_NEVER_INLINE bool
BytecodeEmitter::emitFunction(FunctionNode* funNode, bool needsProto) BytecodeEmitter::emitFunction(FunctionNode* funNode, bool needsProto /* = false */,
ListNode* classContentsIfConstructor /* = nullptr */)
{ {
FunctionBox* funbox = funNode->funbox(); FunctionBox* funbox = funNode->funbox();
RootedFunction fun(cx, funbox->function()); RootedFunction fun(cx, funbox->function());
MOZ_ASSERT((classContentsIfConstructor != nullptr) == (funbox->function()->kind() ==
JSFunction::FunctionKind::ClassConstructor));
// [stack] // [stack]
FunctionEmitter fe(this, funbox, funNode->syntaxKind(), FunctionEmitter fe(this, funbox, funNode->syntaxKind(),
@ -5627,6 +5638,9 @@ BytecodeEmitter::emitFunction(FunctionNode* funNode, bool needsProto)
return false; return false;
} }
if (classContentsIfConstructor) {
fun->lazyScript()->setFieldInitializers(setupFieldInitializers(classContentsIfConstructor));
}
return true; return true;
} }
@ -5651,8 +5665,13 @@ BytecodeEmitter::emitFunction(FunctionNode* funNode, bool needsProto)
if (!script) if (!script)
return false; return false;
FieldInitializers fieldInitializers = FieldInitializers::Invalid();
if (classContentsIfConstructor) {
fieldInitializers = setupFieldInitializers(classContentsIfConstructor);
}
BytecodeEmitter bce2(this, parser, funbox, script, /* lazyScript = */ nullptr, BytecodeEmitter bce2(this, parser, funbox, script, /* lazyScript = */ nullptr,
funNode->pn_pos, emitterMode); funNode->pn_pos, emitterMode, fieldInitializers);
if (!bce2.init()) if (!bce2.init())
return false; return false;
@ -5660,6 +5679,8 @@ BytecodeEmitter::emitFunction(FunctionNode* funNode, bool needsProto)
if (!bce2.emitFunctionScript(funNode)) if (!bce2.emitFunctionScript(funNode))
return false; return false;
// fieldInitializers are copied to the JSScript inside BytecodeEmitter
if (funbox->isLikelyConstructorWrapper()) { if (funbox->isLikelyConstructorWrapper()) {
script->setLikelyConstructorWrapper(); script->setLikelyConstructorWrapper();
} }
@ -7932,7 +7953,7 @@ BytecodeEmitter::emitCreateFieldKeys(ListNode* obj)
bool bool
BytecodeEmitter::emitCreateFieldInitializers(ListNode* obj) BytecodeEmitter::emitCreateFieldInitializers(ListNode* obj)
{ {
const FieldInitializers& fieldInitializers = fieldInitializers_; FieldInitializers fieldInitializers = setupFieldInitializers(obj);
MOZ_ASSERT(fieldInitializers.valid); MOZ_ASSERT(fieldInitializers.valid);
size_t numFields = fieldInitializers.numFieldInitializers; size_t numFields = fieldInitializers.numFieldInitializers;
@ -7989,6 +8010,132 @@ BytecodeEmitter::emitCreateFieldInitializers(ListNode* obj)
return true; return true;
} }
const FieldInitializers&
BytecodeEmitter::findFieldInitializersForCall()
{
for (BytecodeEmitter* current = this; current; current = current->parent) {
if (current->sc->isFunctionBox()) {
FunctionBox* box = current->sc->asFunctionBox();
if (box->function()->kind() == JSFunction::FunctionKind::ClassConstructor) {
const FieldInitializers& fieldInitializers = current->getFieldInitializers();
MOZ_ASSERT(fieldInitializers.valid);
return fieldInitializers;
}
}
}
for (ScopeIter si(innermostScope()); si; si++) {
if (si.scope()->is<FunctionScope>()) {
JSFunction* fun = si.scope()->as<FunctionScope>().canonicalFunction();
if (fun->kind() == JSFunction::FunctionKind::ClassConstructor) {
const FieldInitializers& fieldInitializers = fun->isInterpretedLazy()
? fun->lazyScript()->getFieldInitializers()
: fun->nonLazyScript()->getFieldInitializers();
MOZ_ASSERT(fieldInitializers.valid);
return fieldInitializers;
}
}
}
MOZ_CRASH("Constructor for field initializers not found.");
}
bool
BytecodeEmitter::emitCopyInitializersToLocalInitializers()
{
MOZ_ASSERT(sc->asFunctionBox()->isDerivedClassConstructor());
if (getFieldInitializers().numFieldInitializers == 0)
return true;
NameOpEmitter noe(this, cx->names().dotLocalInitializers, NameOpEmitter::Kind::Initialize);
if (!noe.prepareForRhs()) {
// [stack]
return false;
}
if (!emitGetName(cx->names().dotInitializers)) {
// [stack] .initializers
return false;
}
if (!noe.emitAssignment()) {
// [stack] .initializers
return false;
}
if (!emit1(JSOP_POP)) {
// [stack]
return false;
}
return true;
}
bool
BytecodeEmitter::emitInitializeInstanceFields(bool isSuperCall)
{
const FieldInitializers& fieldInitializers = findFieldInitializersForCall();
size_t numFields = fieldInitializers.numFieldInitializers;
if (numFields == 0) {
return true;
}
if (isSuperCall) {
if (!emitGetName(cx->names().dotLocalInitializers)) {
// [stack] ARRAY
return false;
}
} else {
if (!emitGetName(cx->names().dotInitializers)) {
// [stack] ARRAY
return false;
}
}
for (size_t fieldIndex = 0; fieldIndex < numFields; fieldIndex++) {
if (fieldIndex < numFields - 1) {
// We DUP to keep the array around (it is consumed in the bytecode below)
// for next iterations of this loop, except for the last iteration, which
// avoids an extra POP at the end of the loop.
if (!emit1(JSOP_DUP)) {
// [stack] ARRAY ARRAY
return false;
}
}
if (!emitNumberOp(fieldIndex)) {
// [stack] ARRAY? ARRAY INDEX
return false;
}
// Don't use CALLELEM here, because the receiver of the call != the receiver
// of this getelem. (Specifically, the call receiver is `this`, and the
// receiver of this getelem is `.initializers`)
if (!emit1(JSOP_GETELEM)) {
// [stack] ARRAY? FUNC
return false;
}
// This is guaranteed to run after super(), so we don't need TDZ checks.
if (!emitGetName(cx->names().dotThis)) {
// [stack] ARRAY? FUNC THIS
return false;
}
if (!emitCall(JSOP_CALL_IGNORES_RV, 0)) {
// [stack] ARRAY? RVAL
return false;
}
if (!emit1(JSOP_POP)) {
// [stack] ARRAY?
return false;
}
}
return true;
}
// Using MOZ_NEVER_INLINE in here is a workaround for llvm.org/pr14047. See // Using MOZ_NEVER_INLINE in here is a workaround for llvm.org/pr14047. See
// the comment on emitSwitch. // the comment on emitSwitch.
@ -8446,20 +8593,6 @@ BytecodeEmitter::emitLexicalInitialization(JSAtom* name)
return true; return true;
} }
class AutoResetFieldInitializers
{
BytecodeEmitter* bce;
FieldInitializers oldFieldInfo;
public:
AutoResetFieldInitializers(BytecodeEmitter* bce, FieldInitializers newFieldInfo)
: bce(bce), oldFieldInfo(bce->fieldInitializers_)
{
bce->fieldInitializers_ = newFieldInfo;
}
~AutoResetFieldInitializers() { bce->fieldInitializers_ = oldFieldInfo; }
};
// This follows ES6 14.5.14 (ClassDefinitionEvaluation) and ES6 14.5.15 // This follows ES6 14.5.14 (ClassDefinitionEvaluation) and ES6 14.5.15
// (BindingClassDeclarationEvaluation). // (BindingClassDeclarationEvaluation).
@ -8485,15 +8618,11 @@ BytecodeEmitter::emitClass(ClassNode* classNode)
} }
} }
// set this->fieldInitializers_
AutoResetFieldInitializers _innermostClassAutoReset(this, setupFieldInitializers(classMembers));
// [stack] // [stack]
ClassEmitter ce(this); ClassEmitter ce(this);
RootedAtom innerName(cx); RootedAtom innerName(cx);
ClassEmitter::Kind kind = ClassEmitter::Kind::Expression; ClassEmitter::Kind kind = ClassEmitter::Kind::Expression;
if (names) { if (names) {
innerName = names->innerBinding()->as<NameNode>().atom(); innerName = names->innerBinding()->as<NameNode>().atom();
MOZ_ASSERT(innerName); MOZ_ASSERT(innerName);
@ -8503,8 +8632,10 @@ BytecodeEmitter::emitClass(ClassNode* classNode)
MOZ_ASSERT(names->outerBinding()->as<NameNode>().atom() == innerName); MOZ_ASSERT(names->outerBinding()->as<NameNode>().atom() == innerName);
kind = ClassEmitter::Kind::Declaration; kind = ClassEmitter::Kind::Declaration;
} }
}
if (!ce.emitScopeForNamedClass(classNode->scopeBindings())) { if (!classNode->isEmptyScope()) {
if (!ce.emitScope(classNode->scopeBindings(), classNode->names() != nullptr)) {
// [stack] // [stack]
return false; return false;
} }
@ -8534,7 +8665,7 @@ BytecodeEmitter::emitClass(ClassNode* classNode)
if (constructor) { if (constructor) {
bool needsHomeObject = constructor->funbox()->needsHomeObject(); bool needsHomeObject = constructor->funbox()->needsHomeObject();
// HERITAGE is consumed inside emitFunction. // HERITAGE is consumed inside emitFunction.
if (!emitFunction(constructor, isDerived)) { if (!emitFunction(constructor, isDerived, classMembers)) {
// [stack] HOMEOBJ CTOR // [stack] HOMEOBJ CTOR
return false; return false;
} }

View file

@ -181,6 +181,7 @@ struct MOZ_STACK_CLASS BytecodeEmitter
/* field info for enclosing class */ /* field info for enclosing class */
FieldInitializers fieldInitializers_; FieldInitializers fieldInitializers_;
const FieldInitializers& getFieldInitializers() { return fieldInitializers_; }
#ifdef DEBUG #ifdef DEBUG
bool unstableEmitterScope; bool unstableEmitterScope;
@ -251,13 +252,15 @@ struct MOZ_STACK_CLASS BytecodeEmitter
*/ */
BytecodeEmitter(BytecodeEmitter* parent, Parser<FullParseHandler>* parser, SharedContext* sc, BytecodeEmitter(BytecodeEmitter* parent, Parser<FullParseHandler>* parser, SharedContext* sc,
HandleScript script, Handle<LazyScript*> lazyScript, uint32_t lineNum, HandleScript script, Handle<LazyScript*> lazyScript, uint32_t lineNum,
EmitterMode emitterMode = Normal); EmitterMode emitterMode = Normal,
FieldInitializers fieldInitializers = FieldInitializers::Invalid());
// An alternate constructor that uses a TokenPos for the starting // An alternate constructor that uses a TokenPos for the starting
// line and that sets functionBodyEndPos as well. // line and that sets functionBodyEndPos as well.
BytecodeEmitter(BytecodeEmitter* parent, Parser<FullParseHandler>* parser, SharedContext* sc, BytecodeEmitter(BytecodeEmitter* parent, Parser<FullParseHandler>* parser, SharedContext* sc,
HandleScript script, Handle<LazyScript*> lazyScript, HandleScript script, Handle<LazyScript*> lazyScript,
TokenPos bodyPosition, EmitterMode emitterMode = Normal); TokenPos bodyPosition, EmitterMode emitterMode = Normal,
FieldInitializers fieldInitializers = FieldInitializers::Invalid());
MOZ_MUST_USE bool init(); MOZ_MUST_USE bool init();
@ -514,7 +517,9 @@ struct MOZ_STACK_CLASS BytecodeEmitter
MOZ_MUST_USE bool emitObjectPairOp(ObjectBox* objbox1, ObjectBox* objbox2, JSOp op); MOZ_MUST_USE bool emitObjectPairOp(ObjectBox* objbox1, ObjectBox* objbox2, JSOp op);
MOZ_MUST_USE bool emitRegExp(uint32_t index); MOZ_MUST_USE bool emitRegExp(uint32_t index);
MOZ_NEVER_INLINE MOZ_MUST_USE bool emitFunction(FunctionNode* funNode, bool needsProto = false); MOZ_NEVER_INLINE MOZ_MUST_USE bool emitFunction(FunctionNode* funNode,
bool needsProto = false,
ListNode* classContentsIfConstructor = nullptr);
MOZ_NEVER_INLINE MOZ_MUST_USE bool emitObject(ListNode* objNode); MOZ_NEVER_INLINE MOZ_MUST_USE bool emitObject(ListNode* objNode);
MOZ_MUST_USE bool replaceNewInitWithNewObject(JSObject* obj, ptrdiff_t offset); MOZ_MUST_USE bool replaceNewInitWithNewObject(JSObject* obj, ptrdiff_t offset);
@ -527,6 +532,9 @@ struct MOZ_STACK_CLASS BytecodeEmitter
FieldInitializers setupFieldInitializers(ListNode* classMembers); FieldInitializers setupFieldInitializers(ListNode* classMembers);
MOZ_MUST_USE bool emitCreateFieldKeys(ListNode* obj); MOZ_MUST_USE bool emitCreateFieldKeys(ListNode* obj);
MOZ_MUST_USE bool emitCreateFieldInitializers(ListNode* obj); MOZ_MUST_USE bool emitCreateFieldInitializers(ListNode* obj);
const FieldInitializers& findFieldInitializersForCall();
MOZ_MUST_USE bool emitCopyInitializersToLocalInitializers();
MOZ_MUST_USE bool emitInitializeInstanceFields(bool isSuperCall);
// To catch accidental misuse, emitUint16Operand/emit3 assert that they are // To catch accidental misuse, emitUint16Operand/emit3 assert that they are
// not used to unconditionally emit JSOP_GETLOCAL. Variable access should // not used to unconditionally emit JSOP_GETLOCAL. Variable access should

View file

@ -367,7 +367,9 @@ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_AS)
return literal; return literal;
} }
ClassNodeType newClass(Node name, Node heritage, Node memberBlock, const TokenPos& pos) { ClassNodeType newClass(Node name, Node heritage, LexicalScopeNodeType memberBlock,
const TokenPos& pos)
{
return new_<ClassNode>(name, heritage, memberBlock, pos); return new_<ClassNode>(name, heritage, memberBlock, pos);
} }
ListNodeType newClassMemberList(uint32_t begin) { ListNodeType newClassMemberList(uint32_t begin) {

View file

@ -477,9 +477,16 @@ bool FunctionScriptEmitter::prepareForBody()
} }
if (funbox_->function()->kind() == JSFunction::FunctionKind::ClassConstructor) { if (funbox_->function()->kind() == JSFunction::FunctionKind::ClassConstructor) {
if (!emitInitializeInstanceFields()) { if (funbox_->isDerivedClassConstructor()) {
// [stack] if (!bce_->emitCopyInitializersToLocalInitializers()) {
return false; // [stack]
return false;
}
} else {
if (!bce_->emitInitializeInstanceFields(false)) {
// [stack]
return false;
}
} }
} }
@ -551,64 +558,6 @@ bool FunctionScriptEmitter::emitExtraBodyVarScope()
return true; return true;
} }
bool FunctionScriptEmitter::emitInitializeInstanceFields()
{
MOZ_ASSERT(bce_->fieldInitializers_.valid);
size_t numFields = bce_->fieldInitializers_.numFieldInitializers;
if (numFields == 0) {
return true;
}
if (!bce_->emitGetName(bce_->cx->names().dotInitializers)) {
// [stack] ARRAY
return false;
}
for (size_t fieldIndex = 0; fieldIndex < numFields; fieldIndex++) {
if (fieldIndex < numFields - 1) {
// We DUP to keep the array around (it is consumed in the bytecode below)
// for next iterations of this loop, except for the last iteration, which
// avoids an extra POP at the end of the loop.
if (!bce_->emit1(JSOP_DUP)) {
// [stack] ARRAY ARRAY
return false;
}
}
if (!bce_->emitNumberOp(fieldIndex)) {
// [stack] ARRAY? ARRAY INDEX
return false;
}
// Don't use CALLELEM here, because the receiver of the call != the receiver
// of this getelem. (Specifically, the call receiver is `this`, and the
// receiver of this getelem is `.initializers`)
if (!bce_->emit1(JSOP_GETELEM)) {
// [stack] ARRAY? FUNC
return false;
}
// This is guaranteed to run after super(), so we don't need TDZ checks.
if (!bce_->emitGetName(bce_->cx->names().dotThis)) {
// [stack] ARRAY? FUNC THIS
return false;
}
if (!bce_->emitCall(JSOP_CALL_IGNORES_RV, 0)) {
// [stack] ARRAY? RVAL
return false;
}
if (!bce_->emit1(JSOP_POP)) {
// [stack] ARRAY?
return false;
}
}
return true;
}
bool FunctionScriptEmitter::emitEndBody() bool FunctionScriptEmitter::emitEndBody()
{ {
MOZ_ASSERT(state_ == State::Body); MOZ_ASSERT(state_ == State::Body);

View file

@ -257,7 +257,6 @@ class MOZ_STACK_CLASS FunctionScriptEmitter {
private: private:
MOZ_MUST_USE bool emitExtraBodyVarScope(); MOZ_MUST_USE bool emitExtraBodyVarScope();
MOZ_MUST_USE bool emitInitializeInstanceFields();
}; };
// Class for emitting function parameters. // Class for emitting function parameters.

View file

@ -531,14 +531,16 @@ ClassEmitter::ClassEmitter(BytecodeEmitter* bce)
isClass_ = true; isClass_ = true;
} }
bool ClassEmitter::emitScopeForNamedClass(JS::Handle<LexicalScope::Data*> scopeBindings) bool ClassEmitter::emitScope(JS::Handle<LexicalScope::Data*> scopeBindings, bool hasName)
{ {
MOZ_ASSERT(propertyState_ == PropertyState::Start); MOZ_ASSERT(propertyState_ == PropertyState::Start);
MOZ_ASSERT(classState_ == ClassState::Start); MOZ_ASSERT(classState_ == ClassState::Start);
tdzCacheForInnerName_.emplace(bce_); if (hasName)
innerNameScope_.emplace(bce_); tdzCacheForInnerName_.emplace(bce_);
if (!innerNameScope_->enterLexical(bce_, ScopeKind::Lexical, scopeBindings))
innerScope_.emplace(bce_);
if (!innerScope_->enterLexical(bce_, ScopeKind::Lexical, scopeBindings))
return false; return false;
#ifdef DEBUG #ifdef DEBUG
@ -716,7 +718,7 @@ bool ClassEmitter::emitEnd(Kind kind)
if (name_ != bce_->cx->names().empty) { if (name_ != bce_->cx->names().empty) {
MOZ_ASSERT(tdzCacheForInnerName_.isSome()); MOZ_ASSERT(tdzCacheForInnerName_.isSome());
MOZ_ASSERT(innerNameScope_.isSome()); MOZ_ASSERT(innerScope_.isSome());
if (!bce_->emitLexicalInitialization(name_)) { if (!bce_->emitLexicalInitialization(name_)) {
// [stack] CTOR // [stack] CTOR
@ -724,9 +726,9 @@ bool ClassEmitter::emitEnd(Kind kind)
} }
// Pop the inner scope. // Pop the inner scope.
if (!innerNameScope_->leave(bce_)) if (!innerScope_->leave(bce_))
return false; return false;
innerNameScope_.reset(); innerScope_.reset();
if (kind == Kind::Declaration) { if (kind == Kind::Declaration) {
if (!bce_->emitLexicalInitialization(name_)) { if (!bce_->emitLexicalInitialization(name_)) {
@ -742,9 +744,18 @@ bool ClassEmitter::emitEnd(Kind kind)
} }
tdzCacheForInnerName_.reset(); tdzCacheForInnerName_.reset();
} else { } else if (innerScope_.isSome()) {
// [stack] CTOR
MOZ_ASSERT(kind == Kind::Expression);
MOZ_ASSERT(tdzCacheForInnerName_.isNothing());
if (!innerScope_->leave(bce_))
return false;
innerScope_.reset();
}else {
// [stack] CTOR // [stack] CTOR
MOZ_ASSERT(kind == Kind::Expression);
MOZ_ASSERT(tdzCacheForInnerName_.isNothing()); MOZ_ASSERT(tdzCacheForInnerName_.isNothing());
} }

View file

@ -464,6 +464,7 @@ class MOZ_RAII AutoSaveLocalStrictMode
// //
// `class {}` // `class {}`
// ClassEmitter ce(this); // ClassEmitter ce(this);
// ce.emitScope(scopeBindings, false);
// ce.emitClass(); // ce.emitClass();
// //
// ce.emitInitDefaultConstructor(Some(offset_of_class), // ce.emitInitDefaultConstructor(Some(offset_of_class),
@ -473,6 +474,7 @@ class MOZ_RAII AutoSaveLocalStrictMode
// //
// `class { constructor() { ... } }` // `class { constructor() { ... } }`
// ClassEmitter ce(this); // ClassEmitter ce(this);
// ce.emitScope(scopeBindings, false);
// ce.emitClass(); // ce.emitClass();
// //
// emit(function_for_constructor); // emit(function_for_constructor);
@ -482,7 +484,7 @@ class MOZ_RAII AutoSaveLocalStrictMode
// //
// `class X { constructor() { ... } }` // `class X { constructor() { ... } }`
// ClassEmitter ce(this); // ClassEmitter ce(this);
// ce.emitScopeForNamedClass(scopeBindingForName); // ce.emitScope(scopeBindings, true);
// ce.emitClass(atom_of_X); // ce.emitClass(atom_of_X);
// //
// ce.emitInitDefaultConstructor(Some(offset_of_class), // ce.emitInitDefaultConstructor(Some(offset_of_class),
@ -492,7 +494,7 @@ class MOZ_RAII AutoSaveLocalStrictMode
// //
// `class X { constructor() { ... } }` // `class X { constructor() { ... } }`
// ClassEmitter ce(this); // ClassEmitter ce(this);
// ce.emitScopeForNamedClass(scopeBindingForName); // ce.emitScope(scopeBindings, true);
// ce.emitClass(atom_of_X); // ce.emitClass(atom_of_X);
// //
// emit(function_for_constructor); // emit(function_for_constructor);
@ -502,7 +504,7 @@ class MOZ_RAII AutoSaveLocalStrictMode
// //
// `class X extends Y { constructor() { ... } }` // `class X extends Y { constructor() { ... } }`
// ClassEmitter ce(this); // ClassEmitter ce(this);
// ce.emitScopeForNamedClass(scopeBindingForName); // ce.emitScope(scopeBindings, true);
// //
// emit(Y); // emit(Y);
// ce.emitDerivedClass(atom_of_X); // ce.emitDerivedClass(atom_of_X);
@ -514,7 +516,7 @@ class MOZ_RAII AutoSaveLocalStrictMode
// //
// `class X extends Y { constructor() { ... super.f(); ... } }` // `class X extends Y { constructor() { ... super.f(); ... } }`
// ClassEmitter ce(this); // ClassEmitter ce(this);
// ce.emitScopeForNamedClass(scopeBindingForName); // ce.emitScope(scopeBindings, true);
// //
// emit(Y); // emit(Y);
// ce.emitDerivedClass(atom_of_X); // ce.emitDerivedClass(atom_of_X);
@ -629,21 +631,21 @@ class MOZ_STACK_CLASS ClassEmitter : public PropertyEmitter
bool isDerived_ = false; bool isDerived_ = false;
mozilla::Maybe<TDZCheckCache> tdzCacheForInnerName_; mozilla::Maybe<TDZCheckCache> tdzCacheForInnerName_;
mozilla::Maybe<EmitterScope> innerNameScope_; mozilla::Maybe<EmitterScope> innerScope_;
AutoSaveLocalStrictMode strictMode_; AutoSaveLocalStrictMode strictMode_;
#ifdef DEBUG #ifdef DEBUG
// The state of this emitter. // The state of this emitter.
// //
// +-------+ // +-------+
// | Start |-+------------------------------------>+-+ // | Start |-+------------------------>+-+
// +-------+ | ^ | // +-------+ | ^ |
// | [named class] | | // | [has scope] | |
// | emitScopeForNamedClass +-------+ | | // | emitScope +-------+ | |
// +-------------------------->| Scope |-+ | // +-------------->| Scope |-+ |
// +-------+ | // +-------+ |
// | // |
// +-----------------------------------------------+ // +-----------------------------------+
// | // |
// | emitClass +-------+ // | emitClass +-------+
// +-+----------------->+->| Class |-+ // +-+----------------->+->| Class |-+
@ -669,7 +671,7 @@ class MOZ_STACK_CLASS ClassEmitter : public PropertyEmitter
// The initial state. // The initial state.
Start, Start,
// After calling emitScopeForNamedClass. // After calling emitScope.
Scope, Scope,
// After calling emitClass or emitDerivedClass. // After calling emitClass or emitDerivedClass.
@ -689,8 +691,7 @@ class MOZ_STACK_CLASS ClassEmitter : public PropertyEmitter
public: public:
explicit ClassEmitter(BytecodeEmitter* bce); explicit ClassEmitter(BytecodeEmitter* bce);
MOZ_MUST_USE bool emitScopeForNamedClass( MOZ_MUST_USE bool emitScope(JS::Handle<LexicalScope::Data*> scopeBindings, bool hasName);
JS::Handle<LexicalScope::Data*> scopeBindings);
// @param name // @param name
// Name of the class (nullptr if this is anonymous class) // Name of the class (nullptr if this is anonymous class)

View file

@ -252,10 +252,7 @@ IsTypeofKind(ParseNodeKind kind)
* PNK_CLASS (ClassNode) * PNK_CLASS (ClassNode)
* kid1: PNK_CLASSNAMES for class name. can be null for anonymous class. * kid1: PNK_CLASSNAMES for class name. can be null for anonymous class.
* kid2: expression after `extends`. null if no expression * kid2: expression after `extends`. null if no expression
* kid3: either of * kid3: PNK_LEXICALSCOPE which contains PNK_CLASSMEMBERLIST as scopeBody
* * PNK_CLASSMEMBERLIST, if anonymous class
* * PNK_LEXICALSCOPE which contains PNK_CLASSMEMBERLIST as scopeBody,
* if named class
* PNK_CLASSNAMES (ClassNames) * PNK_CLASSNAMES (ClassNames)
* left: Name node for outer binding, or null if the class is an expression * left: Name node for outer binding, or null if the class is an expression
* that doesn't create an outer binding * that doesn't create an outer binding
@ -2243,13 +2240,11 @@ class ClassNames : public BinaryNode
class ClassNode : public TernaryNode class ClassNode : public TernaryNode
{ {
public: public:
ClassNode(ParseNode* names, ParseNode* heritage, ParseNode* membersOrBlock, ClassNode(ParseNode* names, ParseNode* heritage, LexicalScopeNode* memberBlock,
const TokenPos& pos) const TokenPos& pos)
: TernaryNode(PNK_CLASS, JSOP_NOP, names, heritage, membersOrBlock, pos) : TernaryNode(PNK_CLASS, JSOP_NOP, names, heritage, memberBlock, pos)
{ {
MOZ_ASSERT_IF(names, names->is<ClassNames>()); MOZ_ASSERT_IF(names, names->is<ClassNames>());
MOZ_ASSERT(membersOrBlock->is<LexicalScopeNode>() ||
membersOrBlock->isKind(PNK_CLASSMEMBERLIST));
} }
static bool test(const ParseNode& node) { static bool test(const ParseNode& node) {
@ -2265,14 +2260,14 @@ class ClassNode : public TernaryNode
return kid2(); return kid2();
} }
ListNode* memberList() const { ListNode* memberList() const {
ParseNode* membersOrBlock = kid3(); ListNode* list = &kid3()->as<LexicalScopeNode>().scopeBody()->as<ListNode>();
if (membersOrBlock->isKind(PNK_CLASSMEMBERLIST))
return &membersOrBlock->as<ListNode>();
ListNode* list = &membersOrBlock->as<LexicalScopeNode>().scopeBody()->as<ListNode>();
MOZ_ASSERT(list->isKind(PNK_CLASSMEMBERLIST)); MOZ_ASSERT(list->isKind(PNK_CLASSMEMBERLIST));
return list; return list;
} }
bool isEmptyScope() const {
ParseNode* scope = kid3();
return scope->as<LexicalScopeNode>().isEmptyScope();
}
Handle<LexicalScope::Data*> scopeBindings() const { Handle<LexicalScope::Data*> scopeBindings() const {
ParseNode* scope = kid3(); ParseNode* scope = kid3();
return scope->as<LexicalScopeNode>().scopeBindings(); return scope->as<LexicalScopeNode>().scopeBindings();

View file

@ -2779,6 +2779,12 @@ Parser<ParseHandler>::functionBody(InHandling inHandling, YieldHandling yieldHan
return null(); return null();
} }
if (kind == FunctionSyntaxKind::DerivedClassConstructor) {
if (!noteDeclaredName(context->names().dotLocalInitializers,
DeclarationKind::Var, pos()))
return null();
}
return finishLexicalScope(pc->varScope(), body); return finishLexicalScope(pc->varScope(), body);
} }
@ -3600,7 +3606,11 @@ Parser<FullParseHandler>::standaloneLazyFunction(HandleFunction fun, bool strict
FunctionSyntaxKind syntaxKind = FunctionSyntaxKind::Statement; FunctionSyntaxKind syntaxKind = FunctionSyntaxKind::Statement;
if (fun->isClassConstructor()) { if (fun->isClassConstructor()) {
syntaxKind = FunctionSyntaxKind::ClassConstructor; if (fun->isDerivedClassConstructor()) {
syntaxKind = FunctionSyntaxKind::DerivedClassConstructor;
} else {
syntaxKind = FunctionSyntaxKind::ClassConstructor;
}
} else if (fun->isMethod()) { } else if (fun->isMethod()) {
syntaxKind = FunctionSyntaxKind::Method; syntaxKind = FunctionSyntaxKind::Method;
} else if (fun->isGetter()) { } else if (fun->isGetter()) {
@ -7468,7 +7478,7 @@ Parser<ParseHandler>::classMember(YieldHandling yieldHandling, DefaultHandling d
numFields++; numFields++;
FunctionNodeType initializer = fieldInitializerOpt(yieldHandling, hasHeritage, propName, FunctionNodeType initializer = fieldInitializerOpt(yieldHandling, hasHeritage,
propAtom, numFieldKeys); propAtom, numFieldKeys);
if (!initializer) if (!initializer)
return false; return false;
@ -7553,8 +7563,9 @@ Parser<ParseHandler>::classMember(YieldHandling yieldHandling, DefaultHandling d
template <typename ParseHandler> template <typename ParseHandler>
bool bool
Parser<ParseHandler>::finishClassConstructor(const ParseContext::ClassStatement& classStmt, Parser<ParseHandler>::finishClassConstructor(const ParseContext::ClassStatement& classStmt,
HandlePropertyName className, uint32_t classStartOffset, HandlePropertyName className, bool hasHeritage,
uint32_t classEndOffset, size_t numFields, uint32_t classStartOffset, uint32_t classEndOffset,
size_t numFields,
ListNodeType& classMembers) ListNodeType& classMembers)
{ {
// Fields cannot re-use the constructor obtained via JSOP_CLASSCONSTRUCTOR or // Fields cannot re-use the constructor obtained via JSOP_CLASSCONSTRUCTOR or
@ -7562,7 +7573,7 @@ Parser<ParseHandler>::finishClassConstructor(const ParseContext::ClassStatement&
// initializers in the constructor. So, synthesize a new one. // initializers in the constructor. So, synthesize a new one.
if (classStmt.constructorBox == nullptr && numFields > 0) { if (classStmt.constructorBox == nullptr && numFields > 0) {
// synthesizeConstructor assigns to classStmt.constructorBox // synthesizeConstructor assigns to classStmt.constructorBox
FunctionNodeType synthesizedCtor = synthesizeConstructor(className, classStartOffset); FunctionNodeType synthesizedCtor = synthesizeConstructor(className, classStartOffset, hasHeritage);
if (!synthesizedCtor) { if (!synthesizedCtor) {
return false; return false;
} }
@ -7600,12 +7611,6 @@ Parser<ParseHandler>::finishClassConstructor(const ParseContext::ClassStatement&
if (numFields > 0) { if (numFields > 0) {
ctorbox->function()->lazyScript()->setHasThisBinding(); ctorbox->function()->lazyScript()->setHasThisBinding();
} }
// Field initializers can be retrieved if the class and constructor are
// being compiled at the same time, but we need to stash the field
// information if the constructor is being compiled lazily.
FieldInitializers fieldInfo(numFields);
ctorbox->function()->lazyScript()->setFieldInitializers(fieldInfo);
} }
} }
@ -7724,7 +7729,7 @@ Parser<ParseHandler>::classDefinition(YieldHandling yieldHandling,
pc->innermostScope()->id())) pc->innermostScope()->id()))
return null(); return null();
if (!noteDeclaredName(context->names().dotInitializers, if (!noteDeclaredName(context->names().dotInitializers,
DeclarationKind::Var, namePos)) DeclarationKind::Let, namePos))
return null(); return null();
} }
@ -7733,8 +7738,8 @@ Parser<ParseHandler>::classDefinition(YieldHandling yieldHandling,
return null(); return null();
} }
classEndOffset = pos().end; classEndOffset = pos().end;
if (!finishClassConstructor(classStmt, className, classStartOffset, if (!finishClassConstructor(classStmt, className, hasHeritage,
classEndOffset, numFields, classMembers)) classStartOffset, classEndOffset, numFields, classMembers))
return null(); return null();
if (className) { if (className) {
@ -7779,9 +7784,10 @@ Parser<ParseHandler>::classDefinition(YieldHandling yieldHandling,
template <class ParseHandler> template <class ParseHandler>
typename ParseHandler::FunctionNodeType typename ParseHandler::FunctionNodeType
Parser<ParseHandler>::synthesizeConstructor(HandleAtom className, uint32_t classNameOffset) Parser<ParseHandler>::synthesizeConstructor(HandleAtom className, uint32_t classNameOffset, bool hasHeritage)
{ {
FunctionSyntaxKind functionSyntaxKind = FunctionSyntaxKind::ClassConstructor; FunctionSyntaxKind functionSyntaxKind = hasHeritage ? FunctionSyntaxKind::DerivedClassConstructor
: FunctionSyntaxKind::ClassConstructor;
// Create the function object. // Create the function object.
RootedFunction fun(context, newFunction(className, functionSyntaxKind, RootedFunction fun(context, newFunction(className, functionSyntaxKind,
@ -7820,6 +7826,8 @@ Parser<ParseHandler>::synthesizeConstructor(HandleAtom className, uint32_t class
funbox->function()->setArgCount(0); funbox->function()->setArgCount(0);
funbox->setStart(tokenStream); funbox->setStart(tokenStream);
pc->functionScope().useAsVarScope(pc);
// Push a LexicalScope on to the stack. // Push a LexicalScope on to the stack.
ParseContext::Scope lexicalScope(this); ParseContext::Scope lexicalScope(this);
if (!lexicalScope.init(pc)) if (!lexicalScope.init(pc))
@ -7835,10 +7843,55 @@ Parser<ParseHandler>::synthesizeConstructor(HandleAtom className, uint32_t class
// One might expect a noteUsedName(".initializers") here. See comment in // One might expect a noteUsedName(".initializers") here. See comment in
// GeneralParser<ParseHandler, Unit>::classDefinition on why it's not here. // GeneralParser<ParseHandler, Unit>::classDefinition on why it's not here.
if (hasHeritage) {
if (!noteDeclaredName(context->names().dotLocalInitializers,
DeclarationKind::Var, synthesizedBodyPos))
return null();
}
bool canSkipLazyClosedOverBindings = handler.canSkipLazyClosedOverBindings(); bool canSkipLazyClosedOverBindings = handler.canSkipLazyClosedOverBindings();
if (!declareFunctionThis(canSkipLazyClosedOverBindings)) if (!declareFunctionThis(canSkipLazyClosedOverBindings))
return null(); return null();
if (hasHeritage) {
// {Goanna} Need a different this-NameNode for SuperBase and SetThis or the recycling
// by ParseNodeAllocator runs into all sorts of problems because the
// same ParseNode gets cleaned up twice.
// Parser<ParseHandler>::memberExpr does the same.
NameNodeType thisNameBase = newThisName();
if (!thisNameBase)
return null();
UnaryNodeType superBase = handler.newSuperBase(thisNameBase, synthesizedBodyPos);
if (!superBase)
return null();
ListNodeType arguments = handler.newArguments(synthesizedBodyPos);
if (!arguments)
return null();
BinaryNodeType superCall = handler.newSuperCall(superBase, arguments, false);
if (!superCall)
return null();
NameNodeType thisName = newThisName();
if (!thisName)
return null();
BinaryNodeType setThis = handler.newSetThis(thisName, superCall);
if (!setThis)
return null();
if (!noteUsedName(context->names().dotLocalInitializers))
return null();
UnaryNodeType exprStatement = handler.newExprStatement(setThis, synthesizedBodyPos.end);
if (!exprStatement)
return null();
handler.addStatementToList(stmtList, exprStatement);
}
auto initializerBody = finishLexicalScope(lexicalScope, stmtList); auto initializerBody = finishLexicalScope(lexicalScope, stmtList);
if (!initializerBody) if (!initializerBody)
return null(); return null();
@ -7860,7 +7913,7 @@ Parser<ParseHandler>::synthesizeConstructor(HandleAtom className, uint32_t class
template <class ParseHandler> template <class ParseHandler>
typename ParseHandler::FunctionNodeType typename ParseHandler::FunctionNodeType
Parser<ParseHandler>::fieldInitializerOpt(YieldHandling yieldHandling, bool hasHeritage, Parser<ParseHandler>::fieldInitializerOpt(YieldHandling yieldHandling, bool hasHeritage,
Node propName, HandleAtom propAtom, size_t& numFieldKeys) HandleAtom propAtom, size_t& numFieldKeys)
{ {
bool hasInitializer = false; bool hasInitializer = false;
if (!tokenStream.matchToken(&hasInitializer, TOK_ASSIGN)) if (!tokenStream.matchToken(&hasInitializer, TOK_ASSIGN))
@ -7878,9 +7931,9 @@ Parser<ParseHandler>::fieldInitializerOpt(YieldHandling yieldHandling, bool hasH
firstTokenPos = TokenPos(endPos, endPos); firstTokenPos = TokenPos(endPos, endPos);
} }
// Create the function object. // Create the anonymous function object.
RootedFunction fun(context, RootedFunction fun(context,
newFunction(propAtom, FunctionSyntaxKind::Expression, newFunction(nullptr, FunctionSyntaxKind::Expression,
GeneratorKind::NotGenerator, GeneratorKind::NotGenerator,
FunctionAsyncKind::SyncFunction)); FunctionAsyncKind::SyncFunction));
if (!fun) if (!fun)
@ -7981,7 +8034,12 @@ Parser<ParseHandler>::fieldInitializerOpt(YieldHandling yieldHandling, bool hasH
if (!propAssignFieldAccess) if (!propAssignFieldAccess)
return null(); return null();
} else if (propAtom->isIndex(&indexValue)) { } else if (propAtom->isIndex(&indexValue)) {
propAssignFieldAccess = handler.newPropertyByValue(propAssignThis, propName, wholeInitializerPos.end); // {Goanna} Can't reuse propName here, see comment in synthesizeConstructor
Node indexNode = handler.newNumber(indexValue, DecimalPoint::NoDecimal, wholeInitializerPos);
if (!indexNode)
return null();
propAssignFieldAccess = handler.newPropertyByValue(propAssignThis, indexNode, wholeInitializerPos.end);
if (!propAssignFieldAccess) if (!propAssignFieldAccess)
return null(); return null();
} else { } else {
@ -9908,6 +9966,9 @@ Parser<ParseHandler>::memberExpr(YieldHandling yieldHandling, TripledotHandling
nextMember = handler.newSetThis(thisName, nextMember); nextMember = handler.newSetThis(thisName, nextMember);
if (!nextMember) if (!nextMember)
return null(); return null();
if (!noteUsedName(context->names().dotLocalInitializers))
return null();
} else { } else {
nextMember = memberCall(tt, lhs, yieldHandling, possibleError); nextMember = memberCall(tt, lhs, yieldHandling, possibleError);
if (!nextMember) if (!nextMember)

View file

@ -1498,14 +1498,15 @@ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_TYPE)
ListNodeType& classMembers, bool* done); ListNodeType& classMembers, bool* done);
MOZ_MUST_USE bool finishClassConstructor( MOZ_MUST_USE bool finishClassConstructor(
const ParseContext::ClassStatement& classStmt, const ParseContext::ClassStatement& classStmt,
HandlePropertyName className, uint32_t classStartOffset, HandlePropertyName className, bool hasHeritage,
uint32_t classEndOffset, size_t numFieldsWithInitializers, uint32_t classStartOffset, uint32_t classEndOffset,
ListNodeType& classMembers); size_t numFieldsWithInitializers, ListNodeType& classMembers);
FunctionNodeType fieldInitializerOpt(YieldHandling yieldHandling, bool hasHeritage, FunctionNodeType fieldInitializerOpt(YieldHandling yieldHandling, bool hasHeritage,
Node name, HandleAtom atom, size_t& numFieldKeys); HandleAtom atom, size_t& numFieldKeys);
FunctionNodeType synthesizeConstructor(HandleAtom className, FunctionNodeType synthesizeConstructor(HandleAtom className,
uint32_t classNameOffset); uint32_t classNameOffset,
bool hasHeritage);
bool checkLabelOrIdentifierReference(PropertyName* ident, bool checkLabelOrIdentifierReference(PropertyName* ident,
uint32_t offset, uint32_t offset,

View file

@ -704,6 +704,35 @@ class ScriptSourceObject : public NativeObject
enum GeneratorKind { NotGenerator, LegacyGenerator, StarGenerator }; enum GeneratorKind { NotGenerator, LegacyGenerator, StarGenerator };
enum FunctionAsyncKind { SyncFunction, AsyncFunction }; enum FunctionAsyncKind { SyncFunction, AsyncFunction };
struct FieldInitializers
{
#ifdef DEBUG
bool valid;
#endif
// This struct will eventually have a vector of constant values for optimizing
// field initializers.
size_t numFieldInitializers;
explicit FieldInitializers(size_t numFieldInitializers)
:
#ifdef DEBUG
valid(true),
#endif
numFieldInitializers(numFieldInitializers) {
}
static FieldInitializers Invalid() { return FieldInitializers(); }
private:
FieldInitializers()
:
#ifdef DEBUG
valid(false),
#endif
numFieldInitializers(0) {
}
};
static inline unsigned static inline unsigned
GeneratorKindAsBits(GeneratorKind generatorKind) { GeneratorKindAsBits(GeneratorKind generatorKind) {
return static_cast<unsigned>(generatorKind); return static_cast<unsigned>(generatorKind);
@ -855,6 +884,8 @@ class JSScript : public js::gc::TenuredCell
private: private:
js::SharedScriptData* scriptData_; js::SharedScriptData* scriptData_;
js::FieldInitializers fieldInitializers_ = js::FieldInitializers::Invalid();
public: public:
uint8_t* data; /* pointer to variable-length data array (see uint8_t* data; /* pointer to variable-length data array (see
comment above Create() for details) */ comment above Create() for details) */
@ -1454,6 +1485,11 @@ class JSScript : public js::gc::TenuredCell
return functionHasThisBinding_; return functionHasThisBinding_;
} }
void setFieldInitializers(js::FieldInitializers fieldInitializers) {
fieldInitializers_ = fieldInitializers;
}
const js::FieldInitializers& getFieldInitializers() const { return fieldInitializers_; }
/* /*
* Arguments access (via JSOP_*ARG* opcodes) must access the canonical * Arguments access (via JSOP_*ARG* opcodes) must access the canonical
* location for the argument. If an arguments object exists AND it's mapped * location for the argument. If an arguments object exists AND it's mapped
@ -1999,35 +2035,6 @@ static_assert(sizeof(JSScript) % js::gc::CellSize == 0,
namespace js { namespace js {
struct FieldInitializers
{
#ifdef DEBUG
bool valid;
#endif
// This struct will eventually have a vector of constant values for optimizing
// field initializers.
size_t numFieldInitializers;
explicit FieldInitializers(size_t numFieldInitializers)
:
#ifdef DEBUG
valid(true),
#endif
numFieldInitializers(numFieldInitializers) {
}
static FieldInitializers Invalid() { return FieldInitializers(); }
private:
FieldInitializers()
:
#ifdef DEBUG
valid(false),
#endif
numFieldInitializers(0) {
}
};
// Information about a script which may be (or has been) lazily compiled to // Information about a script which may be (or has been) lazily compiled to
// bytecode from its source. // bytecode from its source.
class LazyScript : public gc::TenuredCell class LazyScript : public gc::TenuredCell
@ -2330,7 +2337,7 @@ class LazyScript : public gc::TenuredCell
fieldInitializers_ = fieldInitializers; fieldInitializers_ = fieldInitializers;
} }
FieldInitializers getFieldInitializers() const { return fieldInitializers_; } const FieldInitializers& getFieldInitializers() const { return fieldInitializers_; }
const char* filename() const { const char* filename() const {
return scriptSource()->filename(); return scriptSource()->filename();

View file

@ -103,6 +103,7 @@
macro(dotGenerator, dotGenerator, ".generator") \ macro(dotGenerator, dotGenerator, ".generator") \
macro(dotThis, dotThis, ".this") \ macro(dotThis, dotThis, ".this") \
macro(dotInitializers, dotInitializers, ".initializers") \ macro(dotInitializers, dotInitializers, ".initializers") \
macro(dotLocalInitializers, dotLocalInitializers, ".localInitializers") \
macro(dotFieldKeys, dotFieldKeys, ".fieldKeys") \ macro(dotFieldKeys, dotFieldKeys, ".fieldKeys") \
macro(each, each, "each") \ macro(each, each, "each") \
macro(elementType, elementType, "elementType") \ macro(elementType, elementType, "elementType") \