Bug 1904995 - Remove redundant dispose loop in for-of loops. r=arai

Differential Revision: https://phabricator.services.mozilla.com/D224253
This commit is contained in:
Debadree Chatterjee 2024-10-02 15:08:36 +00:00
parent 1e24052171
commit 2fad34600c
6 changed files with 53 additions and 17 deletions

View File

@ -5248,7 +5248,21 @@ MOZ_NEVER_INLINE bool BytecodeEmitter::emitLexicalScope(
kind = lexicalScope->kind();
}
if (!lse.emitScope(kind, lexicalScope->scopeBindings())) {
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
EmitterScope::BlockKind blockKind = EmitterScope::BlockKind::Other;
if (body->isKind(ParseNodeKind::ForStmt) &&
body->as<ForNode>().head()->isKind(ParseNodeKind::ForOf)) {
MOZ_ASSERT(kind == ScopeKind::Lexical);
blockKind = EmitterScope::BlockKind::ForOf;
}
#endif
if (!lse.emitScope(kind, lexicalScope->scopeBindings()
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
,
blockKind
#endif
)) {
return false;
}

View File

@ -342,7 +342,7 @@ bool EmitterScope::prepareForDisposableScopeBody(BytecodeEmitter* bce) {
return false;
}
if (isSwitchBlock_ == IsSwitchBlock::Yes) {
if (blockKind_ == BlockKind::Switch) {
// If there are disposables inside the switch case
// and if an exception is thrown we would need to unwind
// to the environment right before the switch statement for that
@ -384,7 +384,7 @@ bool EmitterScope::emitSwitchBlockEndForDisposableScopeBodyEnd(
BytecodeEmitter* bce) {
MOZ_ASSERT(hasDisposables());
if (isSwitchBlock_ == IsSwitchBlock::Yes) {
if (blockKind_ == BlockKind::Switch) {
// See `JSOp::Dup` in EmitterScope::prepareForDisposableScopeBody.
if (!bce->emit1(JSOp::Pop)) {
return false;
@ -409,7 +409,11 @@ bool EmitterScope::emitDisposableScopeBodyEndForNonLocalJump(
}
bool EmitterScope::emitDisposableScopeBodyEnd(BytecodeEmitter* bce) {
if (hasDisposables()) {
// For-of loops emit the dispose loop in the different place and timing.
// (See ForOfEmitter::emitInitialize,
// ForOfLoopControl::emitPrepareForNonLocalJumpFromScope and
// ForOfLoopControl::emitEndCodeNeedingIteratorClose())
if (hasDisposables() && (blockKind_ != BlockKind::ForOf)) {
if (!usingEmitter_->emitEnd()) {
return false;
}
@ -430,7 +434,7 @@ bool EmitterScope::enterLexical(BytecodeEmitter* bce, ScopeKind kind,
LexicalScope::ParserData* bindings
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
,
IsSwitchBlock isSwitchBlock
BlockKind blockKind
#endif
) {
MOZ_ASSERT(kind != ScopeKind::NamedLambda &&
@ -499,7 +503,10 @@ bool EmitterScope::enterLexical(BytecodeEmitter* bce, ScopeKind kind,
}
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
isSwitchBlock_ = isSwitchBlock;
MOZ_ASSERT_IF(blockKind_ != BlockKind::Other, kind == ScopeKind::Lexical);
MOZ_ASSERT_IF(kind != ScopeKind::Lexical, blockKind_ == BlockKind::Other);
blockKind_ = blockKind;
if (!prepareForDisposableScopeBody(bce)) {
return false;

View File

@ -55,10 +55,10 @@ class EmitterScope : public Nestable<EmitterScope> {
mozilla::Maybe<UsingEmitter> usingEmitter_;
public:
enum class IsSwitchBlock : uint8_t { No, Yes };
enum class BlockKind : uint8_t { Switch, ForOf, Other };
private:
IsSwitchBlock isSwitchBlock_ = IsSwitchBlock::No;
BlockKind blockKind_ = BlockKind::Other;
#endif
// The number of enclosing environments. Used for error checking.
@ -134,11 +134,11 @@ class EmitterScope : public Nestable<EmitterScope> {
void dump(BytecodeEmitter* bce);
[[nodiscard]] bool enterLexical(
BytecodeEmitter* bce, ScopeKind kind, LexicalScope::ParserData* bindings
[[nodiscard]] bool enterLexical(BytecodeEmitter* bce, ScopeKind kind,
LexicalScope::ParserData* bindings
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
,
IsSwitchBlock isSwitchBlock = IsSwitchBlock::No
,
BlockKind blockKind = BlockKind::Other
#endif
);
[[nodiscard]] bool enterClassBody(BytecodeEmitter* bce, ScopeKind kind,

View File

@ -12,13 +12,23 @@ using namespace js::frontend;
LexicalScopeEmitter::LexicalScopeEmitter(BytecodeEmitter* bce) : bce_(bce) {}
bool LexicalScopeEmitter::emitScope(ScopeKind kind,
LexicalScope::ParserData* bindings) {
LexicalScope::ParserData* bindings
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
,
EmitterScope::BlockKind blockKind
#endif
) {
MOZ_ASSERT(state_ == State::Start);
MOZ_ASSERT(bindings);
tdzCache_.emplace(bce_);
emitterScope_.emplace(bce_);
if (!emitterScope_->enterLexical(bce_, kind, bindings)) {
if (!emitterScope_->enterLexical(bce_, kind, bindings
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
,
blockKind
#endif
)) {
return false;
}

View File

@ -81,8 +81,13 @@ class MOZ_STACK_CLASS LexicalScopeEmitter {
// Returns the scope object for non-empty scope.
const EmitterScope& emitterScope() const { return *emitterScope_; }
[[nodiscard]] bool emitScope(ScopeKind kind,
LexicalScope::ParserData* bindings);
[[nodiscard]] bool emitScope(
ScopeKind kind, LexicalScope::ParserData* bindings
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
,
EmitterScope::BlockKind blockKind = EmitterScope::BlockKind::Other
#endif
);
[[nodiscard]] bool emitEmptyScope();
[[nodiscard]] bool emitEnd();

View File

@ -128,7 +128,7 @@ bool SwitchEmitter::emitLexical(LexicalScope::ParserData* bindings) {
if (!emitterScope_->enterLexical(bce_, ScopeKind::Lexical, bindings
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
,
EmitterScope::IsSwitchBlock::Yes
EmitterScope::BlockKind::Switch
#endif
)) {
return false;