Issue #2155 - Move NestableControl classes except ForOfLoopControl to BytecodeControlStructures.{cpp.h}

Based-on: m-c 1460489/3
This commit is contained in:
Martok 2023-03-24 00:47:36 +01:00 committed by roytam1
commit a8ac1cac3d
5 changed files with 277 additions and 237 deletions

View file

@ -0,0 +1,84 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "frontend/BytecodeControlStructures.h"
#include "frontend/BytecodeEmitter.h"
#include "frontend/EmitterScope.h"
using namespace js;
using namespace js::frontend;
NestableControl::NestableControl(BytecodeEmitter* bce, StatementKind kind)
: Nestable<NestableControl>(&bce->innermostNestableControl),
kind_(kind),
emitterScope_(bce->innermostEmitterScopeNoCheck())
{}
BreakableControl::BreakableControl(BytecodeEmitter* bce, StatementKind kind)
: NestableControl(bce, kind)
{
MOZ_ASSERT(is<BreakableControl>());
}
bool
BreakableControl::patchBreaks(BytecodeEmitter* bce)
{
return bce->emitJumpTargetAndPatch(breaks);
}
LabelControl::LabelControl(BytecodeEmitter* bce, JSAtom* label, ptrdiff_t startOffset)
: BreakableControl(bce, StatementKind::Label),
label_(bce->cx, label),
startOffset_(startOffset)
{}
LoopControl::LoopControl(BytecodeEmitter* bce, StatementKind loopKind)
: BreakableControl(bce, loopKind),
tdzCache_(bce),
continueTarget({ -1 })
{
MOZ_ASSERT(is<LoopControl>());
LoopControl* enclosingLoop = findNearest<LoopControl>(enclosing());
stackDepth_ = bce->stackDepth;
loopDepth_ = enclosingLoop ? enclosingLoop->loopDepth_ + 1 : 1;
int loopSlots;
if (loopKind == StatementKind::Spread || loopKind == StatementKind::ForOfLoop)
loopSlots = 3;
else if (loopKind == StatementKind::ForInLoop)
loopSlots = 2;
else
loopSlots = 0;
MOZ_ASSERT(loopSlots <= stackDepth_);
if (enclosingLoop) {
canIonOsr_ = (enclosingLoop->canIonOsr_ &&
stackDepth_ == enclosingLoop->stackDepth_ + loopSlots);
} else {
canIonOsr_ = stackDepth_ == loopSlots;
}
}
bool
LoopControl::patchBreaksAndContinues(BytecodeEmitter* bce)
{
MOZ_ASSERT(continueTarget.offset != -1);
if (!patchBreaks(bce))
return false;
bce->patchJumpsToTarget(continues, continueTarget);
return true;
}
TryFinallyControl::TryFinallyControl(BytecodeEmitter* bce, StatementKind kind)
: NestableControl(bce, kind),
emittingSubroutine_(false)
{
MOZ_ASSERT(is<TryFinallyControl>());
}

View file

@ -0,0 +1,175 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef frontend_BytecodeControlStructures_h
#define frontend_BytecodeControlStructures_h
#include "mozilla/Attributes.h"
#include <stddef.h>
#include <stdint.h>
#include "ds/Nestable.h"
#include "frontend/JumpList.h"
#include "frontend/SharedContext.h"
#include "frontend/TDZCheckCache.h"
#include "gc/Rooting.h"
#include "vm/String.h"
namespace js {
namespace frontend {
struct BytecodeEmitter;
class EmitterScope;
class NestableControl : public Nestable<NestableControl>
{
StatementKind kind_;
// The innermost scope when this was pushed.
EmitterScope* emitterScope_;
protected:
NestableControl(BytecodeEmitter* bce, StatementKind kind);
public:
using Nestable<NestableControl>::enclosing;
using Nestable<NestableControl>::findNearest;
StatementKind kind() const {
return kind_;
}
EmitterScope* emitterScope() const {
return emitterScope_;
}
template <typename T>
bool is() const;
template <typename T>
T& as() {
MOZ_ASSERT(this->is<T>());
return static_cast<T&>(*this);
}
};
class BreakableControl : public NestableControl
{
public:
// Offset of the last break.
JumpList breaks;
BreakableControl(BytecodeEmitter* bce, StatementKind kind);
MOZ_MUST_USE bool patchBreaks(BytecodeEmitter* bce);
};
template <>
inline bool
NestableControl::is<BreakableControl>() const
{
return StatementKindIsUnlabeledBreakTarget(kind_) || kind_ == StatementKind::Label;
}
class LabelControl : public BreakableControl
{
RootedAtom label_;
// The code offset when this was pushed. Used for effectfulness checking.
ptrdiff_t startOffset_;
public:
LabelControl(BytecodeEmitter* bce, JSAtom* label, ptrdiff_t startOffset);
HandleAtom label() const {
return label_;
}
ptrdiff_t startOffset() const {
return startOffset_;
}
};
template <>
inline bool
NestableControl::is<LabelControl>() const
{
return kind_ == StatementKind::Label;
}
class LoopControl : public BreakableControl
{
// Loops' children are emitted in dominance order, so they can always
// have a TDZCheckCache.
TDZCheckCache tdzCache_;
// Stack depth when this loop was pushed on the control stack.
int32_t stackDepth_;
// The loop nesting depth. Used as a hint to Ion.
uint32_t loopDepth_;
// Can we OSR into Ion from here? True unless there is non-loop state on the stack.
bool canIonOsr_;
public:
// The target of continue statement jumps, e.g., the update portion of a
// for(;;) loop.
JumpTarget continueTarget;
// Offset of the last continue in the loop.
JumpList continues;
LoopControl(BytecodeEmitter* bce, StatementKind loopKind);
uint32_t loopDepth() const {
return loopDepth_;
}
bool canIonOsr() const {
return canIonOsr_;
}
MOZ_MUST_USE bool patchBreaksAndContinues(BytecodeEmitter* bce);
};
template <>
inline bool
NestableControl::is<LoopControl>() const
{
return StatementKindIsLoop(kind_);
}
class TryFinallyControl : public NestableControl
{
bool emittingSubroutine_;
public:
// The subroutine when emitting a finally block.
JumpList gosubs;
// Offset of the last catch guard, if any.
JumpList guardJump;
TryFinallyControl(BytecodeEmitter* bce, StatementKind kind);
void setEmittingSubroutine() {
emittingSubroutine_ = true;
}
bool emittingSubroutine() const {
return emittingSubroutine_;
}
};
template <>
inline bool
NestableControl::is<TryFinallyControl>() const
{
return kind_ == StatementKind::Try || kind_ == StatementKind::Finally;
}
} /* namespace frontend */
} /* namespace js */
#endif /* frontend_BytecodeControlStructures_h */

View file

@ -28,6 +28,7 @@
#include "jsutil.h"
#include "ds/Nestable.h"
#include "frontend/BytecodeControlStructures.h"
#include "frontend/CallOrNewEmitter.h"
#include "frontend/ElemOpEmitter.h"
#include "frontend/EmitterScope.h"
@ -62,11 +63,6 @@ using mozilla::NumberIsInt32;
using mozilla::PodCopy;
using mozilla::Some;
class BreakableControl;
class LabelControl;
class LoopControl;
class ForOfLoopControl;
class TryFinallyControl;
class OptionalEmitter;
static bool
@ -89,222 +85,6 @@ GetCallArgsAndCount(ParseNode* callNode, ParseNode** argumentNode)
return callNode->pn_count - 1;
}
class BytecodeEmitter::NestableControl : public Nestable<BytecodeEmitter::NestableControl>
{
StatementKind kind_;
// The innermost scope when this was pushed.
EmitterScope* emitterScope_;
protected:
NestableControl(BytecodeEmitter* bce, StatementKind kind)
: Nestable<NestableControl>(&bce->innermostNestableControl),
kind_(kind),
emitterScope_(bce->innermostEmitterScopeNoCheck())
{ }
public:
using Nestable<NestableControl>::enclosing;
using Nestable<NestableControl>::findNearest;
StatementKind kind() const {
return kind_;
}
EmitterScope* emitterScope() const {
return emitterScope_;
}
template <typename T>
bool is() const;
template <typename T>
T& as() {
MOZ_ASSERT(this->is<T>());
return static_cast<T&>(*this);
}
};
// Template specializations are disallowed in different namespaces; specialize
// all the NestableControl subtypes up front.
namespace js {
namespace frontend {
template <>
bool
BytecodeEmitter::NestableControl::is<BreakableControl>() const
{
return StatementKindIsUnlabeledBreakTarget(kind_) || kind_ == StatementKind::Label;
}
template <>
bool
BytecodeEmitter::NestableControl::is<LabelControl>() const
{
return kind_ == StatementKind::Label;
}
template <>
bool
BytecodeEmitter::NestableControl::is<LoopControl>() const
{
return StatementKindIsLoop(kind_);
}
template <>
bool
BytecodeEmitter::NestableControl::is<ForOfLoopControl>() const
{
return kind_ == StatementKind::ForOfLoop;
}
template <>
bool
BytecodeEmitter::NestableControl::is<TryFinallyControl>() const
{
return kind_ == StatementKind::Try || kind_ == StatementKind::Finally;
}
} // namespace frontend
} // namespace js
class BreakableControl : public BytecodeEmitter::NestableControl
{
public:
// Offset of the last break.
JumpList breaks;
BreakableControl(BytecodeEmitter* bce, StatementKind kind)
: NestableControl(bce, kind)
{
MOZ_ASSERT(is<BreakableControl>());
}
MOZ_MUST_USE bool patchBreaks(BytecodeEmitter* bce) {
return bce->emitJumpTargetAndPatch(breaks);
}
};
class LabelControl : public BreakableControl
{
RootedAtom label_;
// The code offset when this was pushed. Used for effectfulness checking.
ptrdiff_t startOffset_;
public:
LabelControl(BytecodeEmitter* bce, JSAtom* label, ptrdiff_t startOffset)
: BreakableControl(bce, StatementKind::Label),
label_(bce->cx, label),
startOffset_(startOffset)
{ }
HandleAtom label() const {
return label_;
}
ptrdiff_t startOffset() const {
return startOffset_;
}
};
class LoopControl : public BreakableControl
{
// Loops' children are emitted in dominance order, so they can always
// have a TDZCheckCache.
TDZCheckCache tdzCache_;
// Stack depth when this loop was pushed on the control stack.
int32_t stackDepth_;
// The loop nesting depth. Used as a hint to Ion.
uint32_t loopDepth_;
// Can we OSR into Ion from here? True unless there is non-loop state on the stack.
bool canIonOsr_;
public:
// The target of continue statement jumps, e.g., the update portion of a
// for(;;) loop.
JumpTarget continueTarget;
// Offset of the last continue in the loop.
JumpList continues;
LoopControl(BytecodeEmitter* bce, StatementKind loopKind)
: BreakableControl(bce, loopKind),
tdzCache_(bce),
continueTarget({ -1 })
{
MOZ_ASSERT(is<LoopControl>());
LoopControl* enclosingLoop = findNearest<LoopControl>(enclosing());
stackDepth_ = bce->stackDepth;
loopDepth_ = enclosingLoop ? enclosingLoop->loopDepth_ + 1 : 1;
int loopSlots;
if (loopKind == StatementKind::Spread || loopKind == StatementKind::ForOfLoop)
loopSlots = 3;
else if (loopKind == StatementKind::ForInLoop)
loopSlots = 2;
else
loopSlots = 0;
MOZ_ASSERT(loopSlots <= stackDepth_);
if (enclosingLoop) {
canIonOsr_ = (enclosingLoop->canIonOsr_ &&
stackDepth_ == enclosingLoop->stackDepth_ + loopSlots);
} else {
canIonOsr_ = stackDepth_ == loopSlots;
}
}
uint32_t loopDepth() const {
return loopDepth_;
}
bool canIonOsr() const {
return canIonOsr_;
}
MOZ_MUST_USE bool patchBreaksAndContinues(BytecodeEmitter* bce) {
MOZ_ASSERT(continueTarget.offset != -1);
if (!patchBreaks(bce))
return false;
bce->patchJumpsToTarget(continues, continueTarget);
return true;
}
};
class TryFinallyControl : public BytecodeEmitter::NestableControl
{
bool emittingSubroutine_;
public:
// The subroutine when emitting a finally block.
JumpList gosubs;
// Offset of the last catch guard, if any.
JumpList guardJump;
TryFinallyControl(BytecodeEmitter* bce, StatementKind kind)
: NestableControl(bce, kind),
emittingSubroutine_(false)
{
MOZ_ASSERT(is<TryFinallyControl>());
}
void setEmittingSubroutine() {
emittingSubroutine_ = true;
}
bool emittingSubroutine() const {
return emittingSubroutine_;
}
};
class MOZ_STACK_CLASS TryEmitter
{
public:
@ -898,6 +678,19 @@ class ForOfLoopControl : public LoopControl
}
};
namespace js {
namespace frontend {
template <>
bool
NestableControl::is<ForOfLoopControl>() const
{
return kind_ == StatementKind::ForOfLoop;
}
} // namespace frontend
} // namespace js
BytecodeEmitter::BytecodeEmitter(BytecodeEmitter* parent,
Parser<FullParseHandler>* parser, SharedContext* sc,
HandleScript script, Handle<LazyScript*> lazyScript,
@ -958,13 +751,6 @@ BytecodeEmitter::init()
return atomIndices.acquire(cx);
}
template <typename Predicate /* (NestableControl*) -> bool */>
BytecodeEmitter::NestableControl*
BytecodeEmitter::findInnermostNestableControl(Predicate predicate) const
{
return NestableControl::findNearest(innermostNestableControl, predicate);
}
template <typename T>
T*
BytecodeEmitter::findInnermostNestableControl() const
@ -1463,7 +1249,7 @@ class NonLocalExitControl
bce_->stackDepth = savedDepth_;
}
MOZ_MUST_USE bool prepareForNonLocalJump(BytecodeEmitter::NestableControl* target);
MOZ_MUST_USE bool prepareForNonLocalJump(NestableControl* target);
MOZ_MUST_USE bool prepareForNonLocalJumpToOutermost() {
return prepareForNonLocalJump(nullptr);
@ -1494,10 +1280,8 @@ NonLocalExitControl::leaveScope(EmitterScope* es)
* Emit additional bytecode(s) for non-local jumps.
*/
bool
NonLocalExitControl::prepareForNonLocalJump(BytecodeEmitter::NestableControl* target)
NonLocalExitControl::prepareForNonLocalJump(NestableControl* target)
{
using NestableControl = BytecodeEmitter::NestableControl;
EmitterScope* es = bce_->innermostEmitterScope();
int npops = 0;

View file

@ -123,13 +123,12 @@ typedef Vector<jssrcnote, 64> SrcNotesVector;
class CallOrNewEmitter;
class ElemOpEmitter;
class EmitterScope;
class NestableControl;
class PropOpEmitter;
class TDZCheckCache;
struct MOZ_STACK_CLASS BytecodeEmitter
{
class NestableControl;
SharedContext* const sc; /* context shared between parsing and bytecode generation */
ExclusiveContext* const cx;
@ -257,9 +256,6 @@ struct MOZ_STACK_CLASS BytecodeEmitter
MOZ_MUST_USE bool init();
template <typename Predicate /* (NestableControl*) -> bool */>
NestableControl* findInnermostNestableControl(Predicate predicate) const;
template <typename T>
T* findInnermostNestableControl() const;

View file

@ -139,6 +139,7 @@ UNIFIED_SOURCES += [
'ds/LifoAlloc.cpp',
'ds/MemoryProtectionExceptionHandler.cpp',
'frontend/BytecodeCompiler.cpp',
'frontend/BytecodeControlStructures.cpp',
'frontend/BytecodeEmitter.cpp',
'frontend/CallOrNewEmitter.cpp',
'frontend/ElemOpEmitter.cpp',