Merge mozilla-inbound to mozilla-central. a=merge

This commit is contained in:
Daniel Varga 2019-04-11 00:54:55 +03:00
Родитель f2b514eaaa dc64e9d9b7
Коммит d0d4b7058d
64 изменённых файлов: 785 добавлений и 421 удалений

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

@ -33,7 +33,7 @@ class SVGViewportElement;
class UserSpaceMetrics {
public:
virtual ~UserSpaceMetrics() {}
virtual ~UserSpaceMetrics() = default;
virtual float GetEmLength() const = 0;
virtual float GetExLength() const = 0;

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

@ -42,7 +42,7 @@ class SVGAnimatedLengthList {
friend class dom::DOMSVGLengthList;
public:
SVGAnimatedLengthList() {}
SVGAnimatedLengthList() = default;
/**
* Because it's so important that mBaseVal and its DOMSVGLengthList wrapper

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

@ -44,7 +44,7 @@ class SVGAnimatedPathSegList final {
friend class DOMSVGPathSegList;
public:
SVGAnimatedPathSegList() {}
SVGAnimatedPathSegList() = default;
/**
* Because it's so important that mBaseVal and its DOMSVGPathSegList wrapper

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

@ -43,7 +43,7 @@ class SVGAnimatedPointList {
friend class DOMSVGPointList;
public:
SVGAnimatedPointList() {}
SVGAnimatedPointList() = default;
/**
* Because it's so important that mBaseVal and its DOMSVGPointList wrapper

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

@ -34,7 +34,7 @@ class SVGComponentTransferFunctionElement
already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo)
: SVGComponentTransferFunctionElementBase(std::move(aNodeInfo)) {}
virtual ~SVGComponentTransferFunctionElement() {}
virtual ~SVGComponentTransferFunctionElement() = default;
public:
typedef gfx::ComponentTransferAttributes ComponentTransferAttributes;

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

@ -55,7 +55,7 @@ class SVGFE : public SVGFEBase {
explicit SVGFE(already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo)
: SVGFEBase(std::move(aNodeInfo)) {}
virtual ~SVGFE() {}
virtual ~SVGFE() = default;
public:
typedef mozilla::gfx::PrimitiveAttributes PrimitiveAttributes;
@ -183,7 +183,7 @@ class SVGFELightingElement : public SVGFELightingElementBase {
already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo)
: SVGFELightingElementBase(std::move(aNodeInfo)) {}
virtual ~SVGFELightingElement() {}
virtual ~SVGFELightingElement() = default;
public:
// interfaces:

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

@ -20,7 +20,7 @@ namespace dom {
class SVGIRect : public nsISupports, public nsWrapperCache {
public:
virtual ~SVGIRect() {}
virtual ~SVGIRect() = default;
JSObject* WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aGivenProto) override {

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

@ -41,7 +41,7 @@ class SVGIntegerPairSMILType : public SMILType {
private:
// Private constructor: prevent instances beyond my singleton.
constexpr SVGIntegerPairSMILType() {}
constexpr SVGIntegerPairSMILType() = default;
};
} // namespace mozilla

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

@ -39,8 +39,8 @@ class SVGLengthList {
friend class SVGAnimatedLengthList;
public:
SVGLengthList() {}
~SVGLengthList() {}
SVGLengthList() = default;
~SVGLengthList() = default;
// Only methods that don't make/permit modification to this list are public.
// Only our friend classes can access methods that may change us.

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

@ -91,7 +91,7 @@ class SVGLengthListSMILType : public SMILType {
private:
// Private constructor: prevent instances beyond my singleton.
constexpr SVGLengthListSMILType() {}
constexpr SVGLengthListSMILType() = default;
};
} // namespace mozilla

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

@ -63,7 +63,7 @@ class SVGMatrix final : public nsWrapperCache {
* Ctors for SVGMatrix objects created independently of a DOMSVGTransform.
*/
// Default ctor for gfxMatrix will produce identity mx
SVGMatrix() {}
SVGMatrix() = default;
explicit SVGMatrix(const gfxMatrix& aMatrix) : mMatrix(aMatrix) {}
@ -103,7 +103,7 @@ class SVGMatrix final : public nsWrapperCache {
already_AddRefed<SVGMatrix> SkewY(float angle, ErrorResult& rv);
private:
~SVGMatrix() {}
~SVGMatrix() = default;
void SetMatrix(const gfxMatrix& aMatrix) {
if (mTransform) {

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

@ -71,7 +71,7 @@ class SVGMotionSMILType : public SMILType {
private:
// Private constructor: prevent instances beyond my singleton.
constexpr SVGMotionSMILType() {}
constexpr SVGMotionSMILType() = default;
};
} // namespace mozilla

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

@ -37,8 +37,8 @@ class SVGNumberList {
friend class SVGAnimatedNumberList;
public:
SVGNumberList() {}
~SVGNumberList() {}
SVGNumberList() = default;
~SVGNumberList() = default;
// Only methods that don't make/permit modification to this list are public.
// Only our friend classes can access methods that may change us.

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

@ -45,7 +45,7 @@ class SVGNumberListSMILType : public SMILType {
private:
// Private constructor: prevent instances beyond my singleton.
constexpr SVGNumberListSMILType() {}
constexpr SVGNumberListSMILType() = default;
};
} // namespace mozilla

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

@ -38,7 +38,7 @@ class SVGNumberPairSMILType : public SMILType {
private:
// Private constructor: prevent instances beyond my singleton.
constexpr SVGNumberPairSMILType() {}
constexpr SVGNumberPairSMILType() = default;
};
} // namespace mozilla

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

@ -58,7 +58,7 @@ class SVGOrientSMILType : public SMILType {
private:
// Private constructor: prevent instances beyond my singleton.
constexpr SVGOrientSMILType() {}
constexpr SVGOrientSMILType() = default;
};
} // namespace mozilla

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

@ -91,8 +91,8 @@ class SVGPathData {
public:
typedef const float* const_iterator;
SVGPathData() {}
~SVGPathData() {}
SVGPathData() = default;
~SVGPathData() = default;
// Only methods that don't make/permit modification to this list are public.
// Only our friend classes can access methods that may change us.

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

@ -48,7 +48,7 @@ class SVGPathSegListSMILType : public SMILType {
private:
// Private constructor: prevent instances beyond my singleton.
constexpr SVGPathSegListSMILType() {}
constexpr SVGPathSegListSMILType() = default;
};
} // namespace mozilla

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

@ -73,7 +73,7 @@ struct SVGPathTraversalState {
*/
class SVGPathSegUtils {
private:
SVGPathSegUtils() {} // private to prevent instances
SVGPathSegUtils() = default; // private to prevent instances
public:
static void GetValueAsString(const float* aSeg, nsAString& aValue);

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

@ -37,8 +37,8 @@ class SVGPointList {
friend class DOMSVGPoint;
public:
SVGPointList() {}
~SVGPointList() {}
SVGPointList() = default;
~SVGPointList() = default;
// Only methods that don't make/permit modification to this list are public.
// Only our friend classes can access methods that may change us.

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

@ -45,7 +45,7 @@ class SVGPointListSMILType : public SMILType {
private:
// Private constructor: prevent instances beyond my singleton.
constexpr SVGPointListSMILType() {}
constexpr SVGPointListSMILType() = default;
};
} // namespace mozilla

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

@ -46,7 +46,7 @@ class SVGRect final : public SVGIRect {
virtual nsIContent* GetParentObject() const override { return mParent; }
protected:
~SVGRect() {}
~SVGRect() = default;
nsCOMPtr<nsIContent> mParent;
float mX, mY, mWidth, mHeight;

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

@ -65,7 +65,7 @@ class DOMSVGTranslatePoint final : public nsISVGPoint {
RefPtr<SVGSVGElement> mElement;
private:
~DOMSVGTranslatePoint() {}
~DOMSVGTranslatePoint() = default;
};
typedef SVGViewportElement SVGSVGElementBase;

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

@ -22,7 +22,7 @@ class SVGStringList {
public:
SVGStringList() : mIsSet(false), mIsCommaSeparated(false) {}
~SVGStringList() {}
~SVGStringList() = default;
void SetIsCommaSeparated(bool aIsCommaSeparated) {
mIsCommaSeparated = aIsCommaSeparated;

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

@ -105,7 +105,7 @@ class SVGTests : public nsISupports {
}
protected:
virtual ~SVGTests() {}
virtual ~SVGTests() = default;
private:
enum { FEATURES, EXTENSIONS, LANGUAGE };

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

@ -32,8 +32,8 @@ class SVGTransformList {
friend class dom::DOMSVGTransform;
public:
SVGTransformList() {}
~SVGTransformList() {}
SVGTransformList() = default;
~SVGTransformList() = default;
// Only methods that don't make/permit modification to this list are public.
// Only our friend classes can access methods that may change us.

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

@ -116,7 +116,7 @@ class SVGTransformListSMILType : public SMILType {
private:
// Private constructor: prevent instances beyond my singleton.
constexpr SVGTransformListSMILType() {}
constexpr SVGTransformListSMILType() = default;
};
} // end namespace mozilla

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

@ -27,7 +27,7 @@ class SVGTransformableElement : public SVGElement {
public:
explicit SVGTransformableElement(already_AddRefed<dom::NodeInfo>&& aNodeInfo)
: SVGElement(std::move(aNodeInfo)) {}
virtual ~SVGTransformableElement() {}
virtual ~SVGTransformableElement() = default;
virtual nsresult Clone(dom::NodeInfo*, nsINode** aResult) const override = 0;

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

@ -38,7 +38,7 @@ class SVGViewBoxSMILType : public SMILType {
private:
// Private constructor: prevent instances beyond my singleton.
constexpr SVGViewBoxSMILType() {}
constexpr SVGViewBoxSMILType() = default;
};
} // namespace mozilla

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

@ -25,9 +25,9 @@ class nsSVGViewportFrame;
namespace mozilla {
class AutoPreserveAspectRatioOverride;
class DOMSVGAnimatedPreserveAspectRatio;
namespace dom {
class DOMSVGAnimatedPreserveAspectRatio;
class SVGAnimatedRect;
class SVGViewElement;
class SVGViewportElement;

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

@ -923,6 +923,7 @@ void gfxPlatform::Init() {
#else
# error "No gfxPlatform implementation available"
#endif
gPlatform->PopulateScreenInfo();
gPlatform->InitAcceleration();
gPlatform->InitWebRenderConfig();
// When using WebRender, we defer initialization of the D3D11 devices until
@ -960,7 +961,6 @@ void gfxPlatform::Init() {
InitLayersIPC();
gPlatform->PopulateScreenInfo();
gPlatform->ComputeTileSize();
#ifdef MOZ_ENABLE_FREETYPE
@ -2511,7 +2511,7 @@ static bool CalculateWrQualifiedPrefValue() {
}
static FeatureState& WebRenderHardwareQualificationStatus(
bool aHasBattery, nsCString& aOutFailureId) {
const IntSize& aScreenSize, bool aHasBattery, nsCString& aOutFailureId) {
FeatureState& featureWebRenderQualified =
gfxConfig::GetFeature(Feature::WEBRENDER_QUALIFIED);
featureWebRenderQualified.EnableByDefault();
@ -2576,7 +2576,8 @@ static FeatureState& WebRenderHardwareQualificationStatus(
FeatureStatus::Blocked, "Device too old",
NS_LITERAL_CSTRING("FEATURE_FAILURE_DEVICE_TOO_OLD"));
}
} else if (adapterVendorID == u"0x8086") { // Intel
} else if (adapterVendorID == u"0x8086" ||
adapterVendorID == u"mesa/i965") { // Intel
const uint16_t supportedDevices[] = {
0x191d, // HD Graphics P530
0x192d, // Iris Pro Graphics P555
@ -2605,6 +2606,18 @@ static FeatureState& WebRenderHardwareQualificationStatus(
featureWebRenderQualified.Disable(
FeatureStatus::Blocked, "Device too old",
NS_LITERAL_CSTRING("FEATURE_FAILURE_DEVICE_TOO_OLD"));
} else if (adapterVendorID == u"mesa/i965") {
const int32_t maxPixels = 3440 * 1440; // UWQHD
int32_t pixels = aScreenSize.width * aScreenSize.height;
if (pixels > maxPixels) {
featureWebRenderQualified.Disable(
FeatureStatus::Blocked, "Screen size too large",
NS_LITERAL_CSTRING("FEATURE_FAILURE_SCREEN_SIZE_TOO_LARGE"));
} else if (pixels <= 0) {
featureWebRenderQualified.Disable(
FeatureStatus::Blocked, "Screen size unknown",
NS_LITERAL_CSTRING("FEATURE_FAILURE_SCREEN_SIZE_UNKNOWN"));
}
}
#endif
} else {
@ -2653,7 +2666,8 @@ void gfxPlatform::InitWebRenderConfig() {
nsCString failureId;
FeatureState& featureWebRenderQualified =
WebRenderHardwareQualificationStatus(HasBattery(), failureId);
WebRenderHardwareQualificationStatus(GetScreenSize(), HasBattery(),
failureId);
FeatureState& featureWebRender = gfxConfig::GetFeature(Feature::WEBRENDER);
featureWebRender.DisableByDefault(
@ -2748,6 +2762,16 @@ void gfxPlatform::InitWebRenderConfig() {
WebRenderDebugPrefChangeCallback, WR_DEBUG_PREF);
}
}
#if defined(XP_LINUX) && !defined(MOZ_WIDGET_ANDROID)
else if (gfxConfig::IsEnabled(Feature::HW_COMPOSITING)) {
// Hardware compositing should be disabled by default if we aren't using
// WebRender. We had to check if it is enabled at all, because it may
// already have been forced disabled (e.g. safe mode, headless). It may
// still be forced on by the user, and if so, this should have no effect.
gfxConfig::Disable(Feature::HW_COMPOSITING, FeatureStatus::Blocked,
"Acceleration blocked by platform");
}
#endif
#ifdef XP_WIN
if (Preferences::GetBool("gfx.webrender.dcomp-win.enabled", false)) {

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

@ -736,7 +736,7 @@ class gfxPlatform : public mozilla::layers::MemoryPressureListener {
gfxPlatform();
virtual ~gfxPlatform();
virtual bool HasBattery() { return true; }
virtual bool HasBattery() { return false; }
virtual void InitAcceleration();
virtual void InitWebRenderConfig();

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

@ -330,7 +330,7 @@ uint32_t gfxPlatformGtk::MaxGenericSubstitions() {
}
bool gfxPlatformGtk::AccelerateLayersByDefault() {
return gfxPrefs::WebRenderAll();
return true;
}
void gfxPlatformGtk::GetPlatformCMSOutputProfile(void*& mem, size_t& size) {

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

@ -307,6 +307,14 @@ typedef enum JSGCParamKey {
*/
JSGC_MIN_NURSERY_BYTES = 31,
/*
* The minimum time to allow between triggering last ditch GCs in seconds.
*
* Default: 60 seconds
* Pref: None
*/
JSGC_MIN_LAST_DITCH_GC_PERIOD = 32,
} JSGCParamKey;
/*

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

@ -488,7 +488,8 @@ static bool MinorGC(JSContext* cx, unsigned argc, Value* vp) {
_("allocationThreshold", JSGC_ALLOCATION_THRESHOLD, true) \
_("minEmptyChunkCount", JSGC_MIN_EMPTY_CHUNK_COUNT, true) \
_("maxEmptyChunkCount", JSGC_MAX_EMPTY_CHUNK_COUNT, true) \
_("compactingEnabled", JSGC_COMPACTING_ENABLED, true)
_("compactingEnabled", JSGC_COMPACTING_ENABLED, true) \
_("minLastDitchGCPeriod", JSGC_MIN_LAST_DITCH_GC_PERIOD, true)
static const struct ParamInfo {
const char* name;

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

@ -41,7 +41,7 @@ LoopControl::LoopControl(BytecodeEmitter* bce, StatementKind loopKind)
LoopControl* enclosingLoop = findNearest<LoopControl>(enclosing());
stackDepth_ = bce->stackDepth;
stackDepth_ = bce->bytecodeSection().stackDepth();
loopDepth_ = enclosingLoop ? enclosingLoop->loopDepth_ + 1 : 1;
int loopSlots;
@ -81,7 +81,7 @@ bool LoopControl::emitContinueTarget(BytecodeEmitter* bce) {
bool LoopControl::emitSpecialBreakForDone(BytecodeEmitter* bce) {
// This doesn't pop stack values, nor handle any other controls.
// Should be called on the toplevel of the loop.
MOZ_ASSERT(bce->stackDepth == stackDepth_);
MOZ_ASSERT(bce->bytecodeSection().stackDepth() == stackDepth_);
MOZ_ASSERT(bce->innermostNestableControl == this);
if (!bce->newSrcNote(SRC_BREAK)) {
@ -109,7 +109,7 @@ bool LoopControl::emitLoopHead(BytecodeEmitter* bce,
}
}
head_ = {bce->offset()};
head_ = {bce->bytecodeSection().offset()};
ptrdiff_t off;
if (!bce->emitJumpTargetOp(JSOP_LOOPHEAD, &off)) {
return false;
@ -126,7 +126,7 @@ bool LoopControl::emitLoopEntry(BytecodeEmitter* bce,
}
}
JumpTarget entry = {bce->offset()};
JumpTarget entry = {bce->bytecodeSection().offset()};
bce->patchJumpsToTarget(entryJump_, entry);
MOZ_ASSERT(loopDepth_ > 0);
@ -135,7 +135,8 @@ bool LoopControl::emitLoopEntry(BytecodeEmitter* bce,
if (!bce->emitJumpTargetOp(JSOP_LOOPENTRY, &off)) {
return false;
}
SetLoopEntryDepthHintAndFlags(bce->code(off), loopDepth_, canIonOsr_);
SetLoopEntryDepthHintAndFlags(bce->bytecodeSection().code(off), loopDepth_,
canIonOsr_);
return true;
}

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

@ -91,6 +91,24 @@ static bool ParseNodeRequiresSpecialLineNumberNotes(ParseNode* pn) {
kind == ParseNodeKind::Function;
}
BytecodeEmitter::BytecodeSection::BytecodeSection(JSContext* cx,
uint32_t lineNum)
: code_(cx),
notes_(cx),
tryNoteList_(cx),
scopeNoteList_(cx),
resumeOffsetList_(cx),
currentLine_(lineNum) {}
BytecodeEmitter::PerScriptData::PerScriptData(JSContext* cx)
: scopeList_(cx),
numberList_(cx),
atomIndices_(cx->frontendCollectionPool()) {}
bool BytecodeEmitter::PerScriptData::init(JSContext* cx) {
return atomIndices_.acquire(cx);
}
BytecodeEmitter::BytecodeEmitter(
BytecodeEmitter* parent, SharedContext* sc, HandleScript script,
Handle<LazyScript*> lazyScript, uint32_t lineNum, EmitterMode emitterMode,
@ -100,23 +118,17 @@ BytecodeEmitter::BytecodeEmitter(
parent(parent),
script(cx, script),
lazyScript(cx, lazyScript),
code_(cx),
notes_(cx),
currentLine_(lineNum),
bytecodeSection_(cx, lineNum),
perScriptData_(cx),
fieldInitializers_(fieldInitializers),
atomIndices(cx->frontendCollectionPool()),
firstLine(lineNum),
numberList(cx),
scopeList(cx),
tryNoteList(cx),
scopeNoteList(cx),
resumeOffsetList(cx),
emitterMode(emitterMode) {
MOZ_ASSERT_IF(emitterMode == LazyFunction, lazyScript);
if (sc->isFunctionBox()) {
// Functions have IC entries for type monitoring |this| and arguments.
numICEntries = sc->asFunctionBox()->function()->nargs() + 1;
bytecodeSection().setNumICEntries(sc->asFunctionBox()->function()->nargs() +
1);
}
}
@ -148,7 +160,7 @@ void BytecodeEmitter::initFromBodyPosition(TokenPos bodyPosition) {
setFunctionBodyEndPos(bodyPosition.end);
}
bool BytecodeEmitter::init() { return atomIndices.acquire(cx); }
bool BytecodeEmitter::init() { return perScriptData_.init(cx); }
template <typename T>
T* BytecodeEmitter::findInnermostNestableControl() const {
@ -194,9 +206,7 @@ bool BytecodeEmitter::markStepBreakpoint() {
// We track the location of the most recent separator for use in
// markSimpleBreakpoint. Note that this means that the position must already
// be set before markStepBreakpoint is called.
lastSeparatorOffet_ = code().length();
lastSeparatorLine_ = currentLine_;
lastSeparatorColumn_ = lastColumn_;
bytecodeSection().updateSeparatorPosition();
return true;
}
@ -210,10 +220,7 @@ bool BytecodeEmitter::markSimpleBreakpoint() {
// expression start, we need to skip marking it breakable in order to avoid
// having two breakpoints with the same line/column position.
// Note: This assumes that the position for the call has already been set.
bool isDuplicateLocation =
lastSeparatorLine_ == currentLine_ && lastSeparatorColumn_ == lastColumn_;
if (!isDuplicateLocation) {
if (!bytecodeSection().isDuplicateLocation()) {
if (!newSrcNote(SRC_BREAKPOINT)) {
return false;
}
@ -223,9 +230,9 @@ bool BytecodeEmitter::markSimpleBreakpoint() {
}
bool BytecodeEmitter::emitCheck(JSOp op, ptrdiff_t delta, ptrdiff_t* offset) {
*offset = code().length();
*offset = bytecodeSection().code().length();
if (!code().growByUninitialized(delta)) {
if (!bytecodeSection().code().growByUninitialized(delta)) {
ReportOutOfMemory(cx);
return false;
}
@ -233,30 +240,30 @@ bool BytecodeEmitter::emitCheck(JSOp op, ptrdiff_t delta, ptrdiff_t* offset) {
// If op is JOF_TYPESET (see the type barriers comment in TypeInference.h),
// reserve a type set to store its result.
if (CodeSpec[op].format & JOF_TYPESET) {
if (typesetCount < JSScript::MaxBytecodeTypeSets) {
typesetCount++;
if (bytecodeSection().typesetCount() < JSScript::MaxBytecodeTypeSets) {
bytecodeSection().addTypesetCount();
}
}
if (BytecodeOpHasIC(op)) {
numICEntries++;
bytecodeSection().addNumICEntries();
}
return true;
}
void BytecodeEmitter::updateDepth(ptrdiff_t target) {
void BytecodeEmitter::BytecodeSection::updateDepth(ptrdiff_t target) {
jsbytecode* pc = code(target);
int nuses = StackUses(pc);
int ndefs = StackDefs(pc);
stackDepth -= nuses;
MOZ_ASSERT(stackDepth >= 0);
stackDepth += ndefs;
stackDepth_ -= nuses;
MOZ_ASSERT(stackDepth_ >= 0);
stackDepth_ += ndefs;
if ((uint32_t)stackDepth > maxStackDepth) {
maxStackDepth = stackDepth;
if ((uint32_t)stackDepth_ > maxStackDepth_) {
maxStackDepth_ = stackDepth_;
}
}
@ -280,9 +287,9 @@ bool BytecodeEmitter::emit1(JSOp op) {
return false;
}
jsbytecode* code = this->code(offset);
jsbytecode* code = bytecodeSection().code(offset);
code[0] = jsbytecode(op);
updateDepth(offset);
bytecodeSection().updateDepth(offset);
return true;
}
@ -294,10 +301,10 @@ bool BytecodeEmitter::emit2(JSOp op, uint8_t op1) {
return false;
}
jsbytecode* code = this->code(offset);
jsbytecode* code = bytecodeSection().code(offset);
code[0] = jsbytecode(op);
code[1] = jsbytecode(op1);
updateDepth(offset);
bytecodeSection().updateDepth(offset);
return true;
}
@ -313,11 +320,11 @@ bool BytecodeEmitter::emit3(JSOp op, jsbytecode op1, jsbytecode op2) {
return false;
}
jsbytecode* code = this->code(offset);
jsbytecode* code = bytecodeSection().code(offset);
code[0] = jsbytecode(op);
code[1] = op1;
code[2] = op2;
updateDepth(offset);
bytecodeSection().updateDepth(offset);
return true;
}
@ -330,7 +337,7 @@ bool BytecodeEmitter::emitN(JSOp op, size_t extra, ptrdiff_t* offset) {
return false;
}
jsbytecode* code = this->code(off);
jsbytecode* code = bytecodeSection().code(off);
code[0] = jsbytecode(op);
/* The remaining |extra| bytes are set by the caller */
@ -339,7 +346,7 @@ bool BytecodeEmitter::emitN(JSOp op, size_t extra, ptrdiff_t* offset) {
* operand yet to be stored in the extra bytes after op.
*/
if (CodeSpec[op].nuses >= 0) {
updateDepth(off);
bytecodeSection().updateDepth(off);
}
if (offset) {
@ -351,7 +358,7 @@ bool BytecodeEmitter::emitN(JSOp op, size_t extra, ptrdiff_t* offset) {
bool BytecodeEmitter::emitJumpTargetOp(JSOp op, ptrdiff_t* off) {
MOZ_ASSERT(BytecodeIsJumpTarget(op));
size_t numEntries = numICEntries;
size_t numEntries = bytecodeSection().numICEntries();
if (MOZ_UNLIKELY(numEntries > UINT32_MAX)) {
reportError(nullptr, JSMSG_NEED_DIET, js_script_str);
return false;
@ -361,21 +368,22 @@ bool BytecodeEmitter::emitJumpTargetOp(JSOp op, ptrdiff_t* off) {
return false;
}
SET_ICINDEX(code(*off), numEntries);
SET_ICINDEX(bytecodeSection().code(*off), numEntries);
return true;
}
bool BytecodeEmitter::emitJumpTarget(JumpTarget* target) {
ptrdiff_t off = offset();
ptrdiff_t off = bytecodeSection().offset();
// Alias consecutive jump targets.
if (off == lastTarget.offset + ptrdiff_t(JSOP_JUMPTARGET_LENGTH)) {
target->offset = lastTarget.offset;
if (off == bytecodeSection().lastTargetOffset() +
ptrdiff_t(JSOP_JUMPTARGET_LENGTH)) {
target->offset = bytecodeSection().lastTargetOffset();
return true;
}
target->offset = off;
lastTarget.offset = off;
bytecodeSection().setLastTargetOffset(off);
ptrdiff_t opOff;
return emitJumpTargetOp(JSOP_JUMPTARGET, &opOff);
@ -387,11 +395,11 @@ bool BytecodeEmitter::emitJumpNoFallthrough(JSOp op, JumpList* jump) {
return false;
}
jsbytecode* code = this->code(offset);
jsbytecode* code = bytecodeSection().code(offset);
code[0] = jsbytecode(op);
MOZ_ASSERT(-1 <= jump->offset && jump->offset < offset);
jump->push(this->code(0), offset);
updateDepth(offset);
jump->push(bytecodeSection().code(0), offset);
bytecodeSection().updateDepth(offset);
return true;
}
@ -425,11 +433,12 @@ bool BytecodeEmitter::emitBackwardJump(JSOp op, JumpTarget target,
}
void BytecodeEmitter::patchJumpsToTarget(JumpList jump, JumpTarget target) {
MOZ_ASSERT(-1 <= jump.offset && jump.offset <= offset());
MOZ_ASSERT(0 <= target.offset && target.offset <= offset());
MOZ_ASSERT_IF(jump.offset != -1 && target.offset + 4 <= offset(),
BytecodeIsJumpTarget(JSOp(*code(target.offset))));
jump.patchAll(code(0), target);
MOZ_ASSERT(-1 <= jump.offset && jump.offset <= bytecodeSection().offset());
MOZ_ASSERT(0 <= target.offset && target.offset <= bytecodeSection().offset());
MOZ_ASSERT_IF(
jump.offset != -1 && target.offset + 4 <= bytecodeSection().offset(),
BytecodeIsJumpTarget(JSOp(*bytecodeSection().code(target.offset))));
jump.patchAll(bytecodeSection().code(0), target);
}
bool BytecodeEmitter::emitJumpTargetAndPatch(JumpList jump) {
@ -459,7 +468,7 @@ bool BytecodeEmitter::emitCall(JSOp op, uint16_t argc, ParseNode* pn) {
}
bool BytecodeEmitter::emitDupAt(unsigned slotFromTop) {
MOZ_ASSERT(slotFromTop < unsigned(stackDepth));
MOZ_ASSERT(slotFromTop < unsigned(bytecodeSection().stackDepth()));
if (slotFromTop == 0) {
return emit1(JSOP_DUP);
@ -475,7 +484,7 @@ bool BytecodeEmitter::emitDupAt(unsigned slotFromTop) {
return false;
}
jsbytecode* pc = code(off);
jsbytecode* pc = bytecodeSection().code(off);
SET_UINT24(pc, slotFromTop);
return true;
}
@ -516,14 +525,14 @@ bool BytecodeEmitter::updateLineNumberNotes(uint32_t offset) {
ErrorReporter* er = &parser->errorReporter();
bool onThisLine;
if (!er->isOnThisLine(offset, currentLine(), &onThisLine)) {
if (!er->isOnThisLine(offset, bytecodeSection().currentLine(), &onThisLine)) {
er->errorNoOffset(JSMSG_OUT_OF_MEMORY);
return false;
}
if (!onThisLine) {
unsigned line = er->lineAt(offset);
unsigned delta = line - currentLine();
unsigned delta = line - bytecodeSection().currentLine();
/*
* Encode any change in the current source line number by using
@ -536,7 +545,7 @@ bool BytecodeEmitter::updateLineNumberNotes(uint32_t offset) {
* unsigned delta_ wrap to a very large number, which triggers a
* SRC_SETLINE.
*/
setCurrentLine(line);
bytecodeSection().setCurrentLine(line);
if (delta >= LengthOfSetLine(line)) {
if (!newSrcNote2(SRC_SETLINE, ptrdiff_t(line))) {
return false;
@ -549,7 +558,7 @@ bool BytecodeEmitter::updateLineNumberNotes(uint32_t offset) {
} while (--delta != 0);
}
updateSeparatorPosition();
bytecodeSection().updateSeparatorPositionIfPresent();
}
return true;
}
@ -566,7 +575,8 @@ bool BytecodeEmitter::updateSourceCoordNotes(uint32_t offset) {
}
uint32_t columnIndex = parser->errorReporter().columnAt(offset);
ptrdiff_t colspan = ptrdiff_t(columnIndex) - ptrdiff_t(lastColumn_);
ptrdiff_t colspan =
ptrdiff_t(columnIndex) - ptrdiff_t(bytecodeSection().lastColumn());
if (colspan != 0) {
// If the column span is so large that we can't store it, then just
// discard this information. This can happen with minimized or otherwise
@ -579,20 +589,12 @@ bool BytecodeEmitter::updateSourceCoordNotes(uint32_t offset) {
if (!newSrcNote2(SRC_COLSPAN, SN_COLSPAN_TO_OFFSET(colspan))) {
return false;
}
lastColumn_ = columnIndex;
updateSeparatorPosition();
bytecodeSection().setLastColumn(columnIndex);
bytecodeSection().updateSeparatorPositionIfPresent();
}
return true;
}
/* Updates the last separator position, if present */
void BytecodeEmitter::updateSeparatorPosition() {
if (!inPrologue() && lastSeparatorOffet_ == code().length()) {
lastSeparatorLine_ = currentLine_;
lastSeparatorColumn_ = lastColumn_;
}
}
Maybe<uint32_t> BytecodeEmitter::getOffsetForLoop(ParseNode* nextpn) {
if (!nextpn) {
return Nothing();
@ -626,7 +628,7 @@ bool BytecodeEmitter::emitUint32Operand(JSOp op, uint32_t operand) {
if (!emitN(op, 4, &off)) {
return false;
}
SET_UINT32(code(off), operand);
SET_UINT32(bytecodeSection().code(off), operand);
return true;
}
@ -663,17 +665,18 @@ class NonLocalExitControl {
public:
NonLocalExitControl(BytecodeEmitter* bce, Kind kind)
: bce_(bce),
savedScopeNoteIndex_(bce->scopeNoteList.length()),
savedDepth_(bce->stackDepth),
savedScopeNoteIndex_(bce->bytecodeSection().scopeNoteList().length()),
savedDepth_(bce->bytecodeSection().stackDepth()),
openScopeNoteIndex_(bce->innermostEmitterScope()->noteIndex()),
kind_(kind) {}
~NonLocalExitControl() {
for (uint32_t n = savedScopeNoteIndex_; n < bce_->scopeNoteList.length();
n++) {
bce_->scopeNoteList.recordEnd(n, bce_->offset());
for (uint32_t n = savedScopeNoteIndex_;
n < bce_->bytecodeSection().scopeNoteList().length(); n++) {
bce_->bytecodeSection().scopeNoteList().recordEnd(
n, bce_->bytecodeSection().offset());
}
bce_->stackDepth = savedDepth_;
bce_->bytecodeSection().setStackDepth(savedDepth_);
}
MOZ_MUST_USE bool prepareForNonLocalJump(NestableControl* target);
@ -695,11 +698,12 @@ bool NonLocalExitControl::leaveScope(EmitterScope* es) {
if (es->enclosingInFrame()) {
enclosingScopeIndex = es->enclosingInFrame()->index();
}
if (!bce_->scopeNoteList.append(enclosingScopeIndex, bce_->offset(),
if (!bce_->bytecodeSection().scopeNoteList().append(
enclosingScopeIndex, bce_->bytecodeSection().offset(),
openScopeNoteIndex_)) {
return false;
}
openScopeNoteIndex_ = bce_->scopeNoteList.length() - 1;
openScopeNoteIndex_ = bce_->bytecodeSection().scopeNoteList().length() - 1;
return true;
}
@ -838,7 +842,7 @@ bool NonLocalExitControl::prepareForNonLocalJump(NestableControl* target) {
}
// Close FOR_OF_ITERCLOSE trynotes.
ptrdiff_t end = bce_->offset();
ptrdiff_t end = bce_->bytecodeSection().offset();
for (ptrdiff_t start : forOfIterCloseScopeStarts) {
if (!bce_->addTryNote(JSTRY_FOR_OF_ITERCLOSE, 0, start, end)) {
return false;
@ -884,10 +888,10 @@ bool BytecodeEmitter::emitIndex32(JSOp op, uint32_t index) {
return false;
}
jsbytecode* code = this->code(offset);
jsbytecode* code = bytecodeSection().code(offset);
code[0] = jsbytecode(op);
SET_UINT32_INDEX(code, index);
updateDepth(offset);
bytecodeSection().updateDepth(offset);
return true;
}
@ -902,10 +906,10 @@ bool BytecodeEmitter::emitIndexOp(JSOp op, uint32_t index) {
return false;
}
jsbytecode* code = this->code(offset);
jsbytecode* code = bytecodeSection().code(offset);
code[0] = jsbytecode(op);
SET_UINT32_INDEX(code, index);
updateDepth(offset);
bytecodeSection().updateDepth(offset);
return true;
}
@ -940,24 +944,24 @@ bool BytecodeEmitter::emitAtomOp(uint32_t atomIndex, JSOp op) {
bool BytecodeEmitter::emitInternedScopeOp(uint32_t index, JSOp op) {
MOZ_ASSERT(JOF_OPTYPE(op) == JOF_SCOPE);
MOZ_ASSERT(index < scopeList.length());
MOZ_ASSERT(index < perScriptData().scopeList().length());
return emitIndex32(op, index);
}
bool BytecodeEmitter::emitInternedObjectOp(uint32_t index, JSOp op) {
MOZ_ASSERT(JOF_OPTYPE(op) == JOF_OBJECT);
MOZ_ASSERT(index < objectList.length);
MOZ_ASSERT(index < perScriptData().objectList().length);
return emitIndex32(op, index);
}
bool BytecodeEmitter::emitObjectOp(ObjectBox* objbox, JSOp op) {
return emitInternedObjectOp(objectList.add(objbox), op);
return emitInternedObjectOp(perScriptData().objectList().add(objbox), op);
}
bool BytecodeEmitter::emitObjectPairOp(ObjectBox* objbox1, ObjectBox* objbox2,
JSOp op) {
uint32_t index = objectList.add(objbox1);
objectList.add(objbox2);
uint32_t index = perScriptData().objectList().add(objbox1);
perScriptData().objectList().add(objbox2);
return emitInternedObjectOp(index, op);
}
@ -974,7 +978,7 @@ bool BytecodeEmitter::emitLocalOp(JSOp op, uint32_t slot) {
return false;
}
SET_LOCALNO(code(off), slot);
SET_LOCALNO(bytecodeSection().code(off), slot);
return true;
}
@ -985,7 +989,7 @@ bool BytecodeEmitter::emitArgOp(JSOp op, uint16_t slot) {
return false;
}
SET_ARGNO(code(off), slot);
SET_ARGNO(bytecodeSection().code(off), slot);
return true;
}
@ -1000,7 +1004,7 @@ bool BytecodeEmitter::emitEnvCoordOp(JSOp op, EnvironmentCoordinate ec) {
return false;
}
jsbytecode* pc = code(off);
jsbytecode* pc = bytecodeSection().code(off);
SET_ENVCOORD_HOPS(pc, ec.hops());
pc += ENVCOORD_HOPS_LEN;
SET_ENVCOORD_SLOT(pc, ec.slot());
@ -1680,13 +1684,13 @@ bool BytecodeEmitter::emitNewInit() {
return false;
}
jsbytecode* code = this->code(offset);
jsbytecode* code = bytecodeSection().code(offset);
code[0] = JSOP_NEWINIT;
code[1] = 0;
code[2] = 0;
code[3] = 0;
code[4] = 0;
updateDepth(offset);
bytecodeSection().updateDepth(offset);
return true;
}
@ -1716,7 +1720,7 @@ bool BytecodeEmitter::iteratorResultShape(unsigned* shape) {
return false;
}
*shape = objectList.add(objbox);
*shape = perScriptData().objectList().add(objbox);
return true;
}
@ -2017,10 +2021,10 @@ bool BytecodeEmitter::emitDouble(double d) {
return false;
}
jsbytecode* code = this->code(offset);
jsbytecode* code = bytecodeSection().code(offset);
code[0] = jsbytecode(JSOP_DOUBLE);
SET_INLINE_VALUE(code, DoubleValue(d));
updateDepth(offset);
bytecodeSection().updateDepth(offset);
return true;
}
@ -2047,13 +2051,13 @@ bool BytecodeEmitter::emitNumberOp(double dval) {
if (!emitN(JSOP_UINT24, 3, &off)) {
return false;
}
SET_UINT24(code(off), u);
SET_UINT24(bytecodeSection().code(off), u);
} else {
ptrdiff_t off;
if (!emitN(JSOP_INT32, 4, &off)) {
return false;
}
SET_INT32(code(off), ival);
SET_INT32(bytecodeSection().code(off), ival);
}
return true;
}
@ -2254,13 +2258,13 @@ bool BytecodeEmitter::allocateResumeIndex(ptrdiff_t offset,
"resumeIndex * sizeof(uintptr_t) must fit in an int32. JIT code relies "
"on this when loading resume entries from BaselineScript");
*resumeIndex = resumeOffsetList.length();
*resumeIndex = bytecodeSection().resumeOffsetList().length();
if (*resumeIndex > MaxResumeIndex) {
reportError(nullptr, JSMSG_TOO_MANY_RESUME_INDEXES);
return false;
}
return resumeOffsetList.append(offset);
return bytecodeSection().resumeOffsetList().append(offset);
}
bool BytecodeEmitter::allocateResumeIndexRange(mozilla::Span<ptrdiff_t> offsets,
@ -2293,15 +2297,15 @@ bool BytecodeEmitter::emitYieldOp(JSOp op) {
}
if (op == JSOP_INITIALYIELD || op == JSOP_YIELD) {
numYields++;
bytecodeSection().addNumYields();
}
uint32_t resumeIndex;
if (!allocateResumeIndex(offset(), &resumeIndex)) {
if (!allocateResumeIndex(bytecodeSection().offset(), &resumeIndex)) {
return false;
}
SET_RESUMEINDEX(code(off), resumeIndex);
SET_RESUMEINDEX(bytecodeSection().code(off), resumeIndex);
return emit1(JSOP_DEBUGAFTERYIELD);
}
@ -2569,7 +2573,7 @@ bool BytecodeEmitter::emitDestructuringLHSRef(ParseNode* target,
}
#ifdef DEBUG
int depth = stackDepth;
int depth = bytecodeSection().stackDepth();
#endif
switch (target->getKind()) {
@ -2647,7 +2651,7 @@ bool BytecodeEmitter::emitDestructuringLHSRef(ParseNode* target,
MOZ_CRASH("emitDestructuringLHSRef: bad lhs kind");
}
MOZ_ASSERT(stackDepth == depth + int(*emitted));
MOZ_ASSERT(bytecodeSection().stackDepth() == depth + int(*emitted));
return true;
}
@ -2810,7 +2814,7 @@ bool BytecodeEmitter::emitIteratorNext(
"can run user-modifiable iteration code");
// [stack] ... NEXT ITER
MOZ_ASSERT(this->stackDepth >= 2);
MOZ_ASSERT(bytecodeSection().stackDepth() >= 2);
if (!emitCall(JSOP_CALL, 0, callSourceCoordOffset)) {
// [stack] ... RESULT
@ -2833,7 +2837,7 @@ bool BytecodeEmitter::emitIteratorNext(
bool BytecodeEmitter::emitPushNotUndefinedOrNull() {
// [stack] V
MOZ_ASSERT(this->stackDepth > 0);
MOZ_ASSERT(bytecodeSection().stackDepth() > 0);
if (!emit1(JSOP_DUP)) {
// [stack] V V
@ -3081,7 +3085,7 @@ bool BytecodeEmitter::emitIteratorCloseInScope(
template <typename InnerEmitter>
bool BytecodeEmitter::wrapWithDestructuringTryNote(int32_t iterDepth,
InnerEmitter emitter) {
MOZ_ASSERT(this->stackDepth >= iterDepth);
MOZ_ASSERT(bytecodeSection().stackDepth() >= iterDepth);
// Pad a nop at the beginning of the bytecode covered by the trynote so
// that when unwinding environments, we may unwind to the scope
@ -3092,11 +3096,11 @@ bool BytecodeEmitter::wrapWithDestructuringTryNote(int32_t iterDepth,
return false;
}
ptrdiff_t start = offset();
ptrdiff_t start = bytecodeSection().offset();
if (!emitter(this)) {
return false;
}
ptrdiff_t end = offset();
ptrdiff_t end = bytecodeSection().offset();
if (start != end) {
return addTryNote(JSTRY_DESTRUCTURING, iterDepth, start, end);
}
@ -3202,7 +3206,7 @@ bool BytecodeEmitter::emitInitializer(ParseNode* initializer,
bool BytecodeEmitter::emitDestructuringOpsArray(ListNode* pattern,
DestructuringFlavor flav) {
MOZ_ASSERT(pattern->isKind(ParseNodeKind::ArrayExpr));
MOZ_ASSERT(this->stackDepth != 0);
MOZ_ASSERT(bytecodeSection().stackDepth() != 0);
// Here's pseudo code for |let [a, b, , c=y, ...d] = x;|
//
@ -3326,7 +3330,7 @@ bool BytecodeEmitter::emitDestructuringOpsArray(ListNode* pattern,
// JSTRY_DESTRUCTURING expects the iterator and the done value
// to be the second to top and the top of the stack, respectively.
// IteratorClose is called upon exception only if done is false.
int32_t tryNoteDepth = stackDepth;
int32_t tryNoteDepth = bytecodeSection().stackDepth();
for (ParseNode* member : pattern->contents()) {
bool isFirst = member == pattern->head();
@ -3635,7 +3639,7 @@ bool BytecodeEmitter::emitDestructuringOpsObject(ListNode* pattern,
MOZ_ASSERT(pattern->isKind(ParseNodeKind::ObjectExpr));
// [stack] ... RHS
MOZ_ASSERT(this->stackDepth > 0);
MOZ_ASSERT(bytecodeSection().stackDepth() > 0);
if (!emit1(JSOP_CHECKOBJCOERCIBLE)) {
// [stack] ... RHS
@ -3815,7 +3819,7 @@ bool BytecodeEmitter::emitDestructuringObjRestExclusionSet(ListNode* pattern) {
MOZ_ASSERT(pattern->isKind(ParseNodeKind::ObjectExpr));
MOZ_ASSERT(pattern->last()->isKind(ParseNodeKind::Spread));
ptrdiff_t offset = this->offset();
ptrdiff_t offset = bytecodeSection().offset();
if (!emitNewInit()) {
return false;
}
@ -4690,11 +4694,11 @@ MOZ_MUST_USE bool BytecodeEmitter::emitGoSub(JumpList* jump) {
}
uint32_t resumeIndex;
if (!allocateResumeIndex(offset(), &resumeIndex)) {
if (!allocateResumeIndex(bytecodeSection().offset(), &resumeIndex)) {
return false;
}
SET_RESUMEINDEX(code(off), resumeIndex);
SET_RESUMEINDEX(bytecodeSection().code(off), resumeIndex);
return true;
}
@ -4899,7 +4903,7 @@ bool BytecodeEmitter::emitWith(BinaryNode* withNode) {
}
bool BytecodeEmitter::emitCopyDataProperties(CopyOption option) {
DebugOnly<int32_t> depth = this->stackDepth;
DebugOnly<int32_t> depth = bytecodeSection().stackDepth();
uint32_t argc;
if (option == CopyOption::Filtered) {
@ -4954,15 +4958,15 @@ bool BytecodeEmitter::emitCopyDataProperties(CopyOption option) {
return false;
}
MOZ_ASSERT(depth - int(argc) == this->stackDepth);
MOZ_ASSERT(depth - int(argc) == bytecodeSection().stackDepth());
return true;
}
bool BytecodeEmitter::emitBigIntOp(BigInt* bigint) {
if (!numberList.append(BigIntValue(bigint))) {
if (!perScriptData().numberList().append(BigIntValue(bigint))) {
return false;
}
return emitIndex32(JSOP_BIGINT, numberList.length() - 1);
return emitIndex32(JSOP_BIGINT, perScriptData().numberList().length() - 1);
}
bool BytecodeEmitter::emitIterator() {
@ -5145,11 +5149,11 @@ bool BytecodeEmitter::emitSpread(bool allowSelfHosted) {
// when we reach this point on the loop backedge (if spreading produces at
// least one value), we've additionally pushed a RESULT iteration value.
// Increment manually to reflect this.
this->stackDepth++;
bytecodeSection().setStackDepth(bytecodeSection().stackDepth() + 1);
{
#ifdef DEBUG
auto loopDepth = this->stackDepth;
auto loopDepth = bytecodeSection().stackDepth();
#endif
// Emit code to assign result.value to the iteration variable.
@ -5162,7 +5166,7 @@ bool BytecodeEmitter::emitSpread(bool allowSelfHosted) {
return false;
}
MOZ_ASSERT(this->stackDepth == loopDepth - 1);
MOZ_ASSERT(bytecodeSection().stackDepth() == loopDepth - 1);
// Spread operations can't contain |continue|, so don't bother setting loop
// and enclosing "update" offsets, as we do with for-loops.
@ -5199,7 +5203,7 @@ bool BytecodeEmitter::emitSpread(bool allowSelfHosted) {
return false;
}
MOZ_ASSERT(this->stackDepth == loopDepth);
MOZ_ASSERT(bytecodeSection().stackDepth() == loopDepth);
}
// Let Ion know where the closing jump of this loop is.
@ -5212,8 +5216,8 @@ bool BytecodeEmitter::emitSpread(bool allowSelfHosted) {
MOZ_ASSERT(loopInfo.breaks.offset == -1);
MOZ_ASSERT(loopInfo.continues.offset == -1);
if (!addTryNote(JSTRY_FOR_OF, stackDepth, loopInfo.headOffset(),
loopInfo.breakTargetOffset())) {
if (!addTryNote(JSTRY_FOR_OF, bytecodeSection().stackDepth(),
loopInfo.headOffset(), loopInfo.breakTargetOffset())) {
return false;
}
@ -5234,7 +5238,7 @@ bool BytecodeEmitter::emitInitializeForInOrOfTarget(TernaryNode* forHead) {
MOZ_ASSERT(forHead->isKind(ParseNodeKind::ForIn) ||
forHead->isKind(ParseNodeKind::ForOf));
MOZ_ASSERT(this->stackDepth >= 1,
MOZ_ASSERT(bytecodeSection().stackDepth() >= 1,
"must have a per-iteration value for initializing");
ParseNode* target = forHead->kid1();
@ -5282,14 +5286,14 @@ bool BytecodeEmitter::emitInitializeForInOrOfTarget(TernaryNode* forHead) {
// iteration value *before* initializing. Thus the initializing
// value may be buried under a bind-specific value on the stack.
// Swap it to the top of the stack.
MOZ_ASSERT(stackDepth >= 2);
MOZ_ASSERT(bytecodeSection().stackDepth() >= 2);
if (!emit1(JSOP_SWAP)) {
return false;
}
} else {
// In cases of emitting a frame slot or environment slot,
// nothing needs be done.
MOZ_ASSERT(stackDepth >= 1);
MOZ_ASSERT(bytecodeSection().stackDepth() >= 1);
}
if (!noe.emitAssignment()) {
return false;
@ -5967,7 +5971,7 @@ bool BytecodeEmitter::emitReturn(UnaryNode* returnNode) {
* In this case we mutate JSOP_RETURN into JSOP_SETRVAL and add an
* extra JSOP_RETRVAL after the fixups.
*/
ptrdiff_t top = offset();
ptrdiff_t top = bytecodeSection().offset();
bool needsFinalYield =
sc->isFunctionBox() && sc->asFunctionBox()->needsFinalYield();
@ -6028,12 +6032,13 @@ bool BytecodeEmitter::emitReturn(UnaryNode* returnNode) {
return false;
}
} else if (isDerivedClassConstructor) {
MOZ_ASSERT(code()[top] == JSOP_SETRVAL);
MOZ_ASSERT(bytecodeSection().code()[top] == JSOP_SETRVAL);
if (!emit1(JSOP_RETRVAL)) {
return false;
}
} else if (top + static_cast<ptrdiff_t>(JSOP_RETURN_LENGTH) != offset()) {
code()[top] = JSOP_SETRVAL;
} else if (top + static_cast<ptrdiff_t>(JSOP_RETURN_LENGTH) !=
bytecodeSection().offset()) {
bytecodeSection().code()[top] = JSOP_SETRVAL;
if (!emit1(JSOP_RETRVAL)) {
return false;
}
@ -6213,7 +6218,7 @@ bool BytecodeEmitter::emitYieldStar(ParseNode* iter) {
}
int32_t savedDepthTemp;
int32_t startDepth = stackDepth;
int32_t startDepth = bytecodeSection().stackDepth();
MOZ_ASSERT(startDepth >= 3);
TryEmitter tryCatch(this, TryEmitter::Kind::TryCatchFinally,
@ -6245,7 +6250,7 @@ bool BytecodeEmitter::emitYieldStar(ParseNode* iter) {
return false;
}
MOZ_ASSERT(this->stackDepth == startDepth);
MOZ_ASSERT(bytecodeSection().stackDepth() == startDepth);
// Step 7.a.vi.
// Step 7.b.ii.7.
@ -6278,7 +6283,7 @@ bool BytecodeEmitter::emitYieldStar(ParseNode* iter) {
return false;
}
MOZ_ASSERT(stackDepth == startDepth);
MOZ_ASSERT(bytecodeSection().stackDepth() == startDepth);
if (!emit1(JSOP_EXCEPTION)) {
// [stack] NEXT ITER RESULT EXCEPTION
@ -6297,7 +6302,7 @@ bool BytecodeEmitter::emitYieldStar(ParseNode* iter) {
return false;
}
savedDepthTemp = stackDepth;
savedDepthTemp = bytecodeSection().stackDepth();
InternalIfEmitter ifThrowMethodIsNotDefined(this);
if (!emitPushNotUndefinedOrNull()) {
// [stack] NEXT ITER RESULT EXCEPTION ITER THROW
@ -6348,7 +6353,7 @@ bool BytecodeEmitter::emitYieldStar(ParseNode* iter) {
// [stack] NEXT ITER RESULT
return false;
}
MOZ_ASSERT(this->stackDepth == startDepth);
MOZ_ASSERT(bytecodeSection().stackDepth() == startDepth);
JumpList checkResult;
// Note that there is no GOSUB to the finally block here. If the iterator has
@ -6359,7 +6364,7 @@ bool BytecodeEmitter::emitYieldStar(ParseNode* iter) {
return false;
}
stackDepth = savedDepthTemp;
bytecodeSection().setStackDepth(savedDepthTemp);
if (!ifThrowMethodIsNotDefined.emitElse()) {
// [stack] NEXT ITER RESULT EXCEPTION ITER THROW
return false;
@ -6384,12 +6389,12 @@ bool BytecodeEmitter::emitYieldStar(ParseNode* iter) {
return false;
}
stackDepth = savedDepthTemp;
bytecodeSection().setStackDepth(savedDepthTemp);
if (!ifThrowMethodIsNotDefined.emitEnd()) {
return false;
}
stackDepth = startDepth;
bytecodeSection().setStackDepth(startDepth);
if (!tryCatch.emitFinally()) {
return false;
}
@ -6516,7 +6521,7 @@ bool BytecodeEmitter::emitYieldStar(ParseNode* iter) {
// [stack] NEXT ITER OLDRESULT FTYPE FVALUE
return false;
}
savedDepthTemp = this->stackDepth;
savedDepthTemp = bytecodeSection().stackDepth();
if (!ifReturnDone.emitElse()) {
// [stack] NEXT ITER OLDRESULT FTYPE FVALUE RESULT
return false;
@ -6538,7 +6543,7 @@ bool BytecodeEmitter::emitYieldStar(ParseNode* iter) {
return false;
}
}
this->stackDepth = savedDepthTemp;
bytecodeSection().setStackDepth(savedDepthTemp);
if (!ifReturnDone.emitEnd()) {
return false;
}
@ -6613,7 +6618,7 @@ bool BytecodeEmitter::emitYieldStar(ParseNode* iter) {
// [stack] NEXT ITER RESULT
return false;
}
MOZ_ASSERT(this->stackDepth == startDepth);
MOZ_ASSERT(bytecodeSection().stackDepth() == startDepth);
// Steps 7.a.iv-v.
// Steps 7.b.ii.5-6.
@ -6658,7 +6663,7 @@ bool BytecodeEmitter::emitYieldStar(ParseNode* iter) {
return false;
}
MOZ_ASSERT(this->stackDepth == startDepth - 2);
MOZ_ASSERT(bytecodeSection().stackDepth() == startDepth - 2);
return true;
}
@ -6707,7 +6712,7 @@ bool BytecodeEmitter::emitExpressionStatement(UnaryNode* exprStmt) {
if (innermostNestableControl &&
innermostNestableControl->is<LabelControl>() &&
innermostNestableControl->as<LabelControl>().startOffset() >=
offset()) {
bytecodeSection().offset()) {
useful = true;
}
}
@ -8182,8 +8187,8 @@ bool BytecodeEmitter::replaceNewInitWithNewObject(JSObject* obj,
JSOP_NEWINIT_LENGTH == JSOP_NEWOBJECT_LENGTH,
"newinit and newobject must have equal length to edit in-place");
uint32_t index = objectList.add(objbox);
jsbytecode* code = this->code(offset);
uint32_t index = perScriptData().objectList().add(objbox);
jsbytecode* code = bytecodeSection().code(offset);
MOZ_ASSERT(code[0] == JSOP_NEWINIT);
code[0] = JSOP_NEWOBJECT;
@ -9233,7 +9238,8 @@ bool BytecodeEmitter::emitTree(
break;
case ParseNodeKind::RegExpExpr:
if (!emitRegExp(objectList.add(pn->as<RegExpLiteral>().objbox()))) {
if (!emitRegExp(perScriptData().objectList().add(
pn->as<RegExpLiteral>().objbox()))) {
return false;
}
break;
@ -9334,11 +9340,13 @@ static bool AllocSrcNote(JSContext* cx, SrcNotesVector& notes,
bool BytecodeEmitter::addTryNote(JSTryNoteKind kind, uint32_t stackDepth,
size_t start, size_t end) {
MOZ_ASSERT(!inPrologue());
return tryNoteList.append(kind, stackDepth, start, end);
return bytecodeSection().tryNoteList().append(kind, stackDepth, start, end);
}
bool BytecodeEmitter::newSrcNote(SrcNoteType type, unsigned* indexp) {
SrcNotesVector& notes = this->notes();
// Prologue shouldn't have source notes.
MOZ_ASSERT(!inPrologue());
SrcNotesVector& notes = bytecodeSection().notes();
unsigned index;
if (!AllocSrcNote(cx, notes, &index)) {
return false;
@ -9348,9 +9356,9 @@ bool BytecodeEmitter::newSrcNote(SrcNoteType type, unsigned* indexp) {
* Compute delta from the last annotated bytecode's offset. If it's too
* big to fit in sn, allocate one or more xdelta notes and reset sn.
*/
ptrdiff_t offset = this->offset();
ptrdiff_t delta = offset - lastNoteOffset();
lastNoteOffset_ = offset;
ptrdiff_t offset = bytecodeSection().offset();
ptrdiff_t delta = offset - bytecodeSection().lastNoteOffset();
bytecodeSection().setLastNoteOffset(offset);
if (delta >= SN_DELTA_LIMIT) {
do {
ptrdiff_t xdelta = Min(delta, SN_XDELTA_MASK);
@ -9420,7 +9428,7 @@ bool BytecodeEmitter::setSrcNoteOffset(unsigned index, unsigned which,
return false;
}
SrcNotesVector& notes = this->notes();
SrcNotesVector& notes = bytecodeSection().notes();
/* Find the offset numbered which (i.e., skip exactly which offsets). */
jssrcnote* sn = &notes[index];
@ -9458,10 +9466,10 @@ bool BytecodeEmitter::setSrcNoteOffset(unsigned index, unsigned which,
}
void BytecodeEmitter::copySrcNotes(jssrcnote* destination, uint32_t nsrcnotes) {
unsigned count = notes_.length();
unsigned count = bytecodeSection().notes().length();
// nsrcnotes includes SN_MAKE_TERMINATOR in addition to the srcnotes.
MOZ_ASSERT(nsrcnotes == count + 1);
PodCopy(destination, notes_.begin(), count);
PodCopy(destination, bytecodeSection().notes().begin(), count);
SN_MAKE_TERMINATOR(&destination[count]);
}

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

@ -124,29 +124,249 @@ struct MOZ_STACK_CLASS BytecodeEmitter {
Rooted<LazyScript*> lazyScript;
private:
BytecodeVector code_; /* bytecode */
SrcNotesVector notes_; /* source notes, see below */
// Bytecode and all data directly associated with specific opcode/index inside
// bytecode is stored in this class.
class BytecodeSection {
public:
BytecodeSection(JSContext* cx, uint32_t lineNum);
// ---- Bytecode ----
BytecodeVector& code() { return code_; }
const BytecodeVector& code() const { return code_; }
jsbytecode* code(ptrdiff_t offset) { return code_.begin() + offset; }
ptrdiff_t offset() const { return code_.end() - code_.begin(); }
// ---- Source notes ----
SrcNotesVector& notes() { return notes_; }
const SrcNotesVector& notes() const { return notes_; }
ptrdiff_t lastNoteOffset() const { return lastNoteOffset_; }
void setLastNoteOffset(ptrdiff_t offset) { lastNoteOffset_ = offset; }
// ---- Jump ----
ptrdiff_t lastTargetOffset() const { return lastTarget_.offset; }
void setLastTargetOffset(ptrdiff_t offset) { lastTarget_.offset = offset; }
// Check if the last emitted opcode is a jump target.
bool lastOpcodeIsJumpTarget() const {
return offset() - lastTarget_.offset == ptrdiff_t(JSOP_JUMPTARGET_LENGTH);
}
// JumpTarget should not be part of the emitted statement, as they can be
// aliased by multiple statements. If we included the jump target as part of
// the statement we might have issues where the enclosing statement might
// not contain all the opcodes of the enclosed statements.
ptrdiff_t lastNonJumpTargetOffset() const {
return lastOpcodeIsJumpTarget() ? lastTarget_.offset : offset();
}
// ---- Stack ----
int32_t stackDepth() const { return stackDepth_; }
void setStackDepth(int32_t depth) { stackDepth_ = depth; }
uint32_t maxStackDepth() const { return maxStackDepth_; }
void updateDepth(ptrdiff_t target);
// ---- Try notes ----
CGTryNoteList& tryNoteList() { return tryNoteList_; };
const CGTryNoteList& tryNoteList() const { return tryNoteList_; };
// ---- Scope ----
CGScopeNoteList& scopeNoteList() { return scopeNoteList_; };
const CGScopeNoteList& scopeNoteList() const { return scopeNoteList_; };
// ---- Generator ----
CGResumeOffsetList& resumeOffsetList() { return resumeOffsetList_; }
const CGResumeOffsetList& resumeOffsetList() const {
return resumeOffsetList_;
}
uint32_t numYields() const { return numYields_; }
void addNumYields() { numYields_++; }
// ---- Line and column ----
uint32_t currentLine() const { return currentLine_; }
uint32_t lastColumn() const { return lastColumn_; }
void setCurrentLine(uint32_t line) {
currentLine_ = line;
lastColumn_ = 0;
}
void setLastColumn(uint32_t column) { lastColumn_ = column; }
void updateSeparatorPosition() {
lastSeparatorOffet_ = code().length();
lastSeparatorLine_ = currentLine_;
lastSeparatorColumn_ = lastColumn_;
}
void updateSeparatorPositionIfPresent() {
if (lastSeparatorOffet_ == code().length()) {
lastSeparatorLine_ = currentLine_;
lastSeparatorColumn_ = lastColumn_;
}
}
bool isDuplicateLocation() const {
return lastSeparatorLine_ == currentLine_ &&
lastSeparatorColumn_ == lastColumn_;
}
// ---- JIT ----
size_t numICEntries() const { return numICEntries_; }
void addNumICEntries() { numICEntries_++; }
void setNumICEntries(size_t entries) { numICEntries_ = entries; }
uint16_t typesetCount() const { return typesetCount_; }
void addTypesetCount() { typesetCount_++; }
private:
// ---- Bytecode ----
// Bytecode.
BytecodeVector code_;
// ---- Source notes ----
// Source notes
SrcNotesVector notes_;
// Code offset for last source note
ptrdiff_t lastNoteOffset_ = 0;
// ---- Jump ----
// Last jump target emitted.
JumpTarget lastTarget_ = {-1 - ptrdiff_t(JSOP_JUMPTARGET_LENGTH)};
// ---- Stack ----
// Maximum number of expression stack slots so far.
uint32_t maxStackDepth_ = 0;
// Current stack depth in script frame.
int32_t stackDepth_ = 0;
// ---- Try notes ----
// List of emitted try notes.
CGTryNoteList tryNoteList_;
// ---- Scope ----
// List of emitted block scope notes.
CGScopeNoteList scopeNoteList_;
// ---- Generator ----
// Certain ops (yield, await, gosub) have an entry in the script's
// resumeOffsets list. This can be used to map from the op's resumeIndex to
// the bytecode offset of the next pc. This indirection makes it easy to
// resume in the JIT (because BaselineScript stores a resumeIndex => native
// code array).
CGResumeOffsetList resumeOffsetList_;
// Number of yield instructions emitted. Does not include JSOP_AWAIT.
uint32_t numYields_ = 0;
// ---- Line and column ----
// Line number for srcnotes.
//
// WARNING: If this becomes out of sync with already-emitted srcnotes,
// we can get undefined behavior.
uint32_t currentLine_ = 0;
uint32_t currentLine_;
// Zero-based column index on currentLine of last SRC_COLSPAN-annotated
// Zero-based column index on currentLine_ of last SRC_COLSPAN-annotated
// opcode.
//
// WARNING: If this becomes out of sync with already-emitted srcnotes,
// we can get undefined behavior.
uint32_t lastColumn_ = 0;
// The offset, line and column numbers of the last opcode for the
// breakpoint for step execution.
uint32_t lastSeparatorOffet_ = 0;
uint32_t lastSeparatorLine_ = 0;
uint32_t lastSeparatorColumn_ = 0;
// ---- JIT ----
// Number of JOF_IC opcodes emitted.
size_t numICEntries_ = 0;
// Number of JOF_TYPESET opcodes generated.
uint16_t typesetCount_ = 0;
};
BytecodeSection bytecodeSection_;
public:
BytecodeSection& bytecodeSection() { return bytecodeSection_; }
const BytecodeSection& bytecodeSection() const { return bytecodeSection_; }
private:
// Data that is not directly associated with specific opcode/index inside
// bytecode, but referred from bytecode is stored in this class.
class PerScriptData {
public:
explicit PerScriptData(JSContext* cx);
MOZ_MUST_USE bool init(JSContext* cx);
// ---- Scope ----
CGScopeList& scopeList() { return scopeList_; }
const CGScopeList& scopeList() const { return scopeList_; }
// ---- Literals ----
CGNumberList& numberList() { return numberList_; }
const CGNumberList& numberList() const { return numberList_; }
CGObjectList& objectList() { return objectList_; }
const CGObjectList& objectList() const { return objectList_; }
PooledMapPtr<AtomIndexMap>& atomIndices() { return atomIndices_; }
const PooledMapPtr<AtomIndexMap>& atomIndices() const {
return atomIndices_;
}
private:
// ---- Scope ----
// List of emitted scopes.
CGScopeList scopeList_;
// ---- Literals ----
// List of double and bigint values used by script.
CGNumberList numberList_;
// List of emitted objects.
CGObjectList objectList_;
// Map from atom to index.
PooledMapPtr<AtomIndexMap> atomIndices_;
};
PerScriptData perScriptData_;
public:
PerScriptData& perScriptData() { return perScriptData_; }
const PerScriptData& perScriptData() const { return perScriptData_; }
private:
// switchToMain sets this to the bytecode offset of the main section.
mozilla::Maybe<uint32_t> mainOffset_ = {};
@ -154,22 +374,14 @@ struct MOZ_STACK_CLASS BytecodeEmitter {
const FieldInitializers fieldInitializers_;
public:
// Last jump target emitted.
JumpTarget lastTarget = {-1 - ptrdiff_t(JSOP_JUMPTARGET_LENGTH)};
// Private storage for parser wrapper. DO NOT REFERENCE INTERNALLY. May not be
// initialized. Use |parser| instead.
mozilla::Maybe<EitherParser> ep_ = {};
BCEParserHandle* parser = nullptr;
PooledMapPtr<AtomIndexMap> atomIndices; /* literals indexed for mapping */
unsigned firstLine = 0; /* first line, for JSScript::initFromEmitter */
uint32_t maxFixedSlots = 0; /* maximum number of fixed frame slots so far */
uint32_t maxStackDepth =
0; /* maximum number of expression stack slots so far */
int32_t stackDepth = 0; /* current stack depth in script frame */
uint32_t bodyScopeIndex =
UINT32_MAX; /* index into scopeList of the body scope */
@ -195,28 +407,6 @@ struct MOZ_STACK_CLASS BytecodeEmitter {
return innermostEmitterScope_;
}
CGNumberList numberList; /* double and bigint values used by script */
CGObjectList objectList; /* list of emitted objects */
CGScopeList scopeList; /* list of emitted scopes */
CGTryNoteList tryNoteList; /* list of emitted try notes */
CGScopeNoteList scopeNoteList; /* list of emitted block scope notes */
// Certain ops (yield, await, gosub) have an entry in the script's
// resumeOffsets list. This can be used to map from the op's resumeIndex to
// the bytecode offset of the next pc. This indirection makes it easy to
// resume in the JIT (because BaselineScript stores a resumeIndex => native
// code array).
CGResumeOffsetList resumeOffsetList;
// Number of JOF_IC opcodes emitted.
size_t numICEntries = 0;
// Number of yield instructions emitted. Does not include JSOP_AWAIT.
uint32_t numYields = 0;
// Number of JOF_TYPESET opcodes generated.
uint16_t typesetCount = 0;
// Script contains singleton initializer JSOP_OBJECT.
bool hasSingletons = false;
@ -360,24 +550,26 @@ struct MOZ_STACK_CLASS BytecodeEmitter {
varEmitterScope = emitterScope;
}
Scope* outermostScope() const { return scopeList.vector[0]; }
Scope* outermostScope() const {
return perScriptData().scopeList().vector[0];
}
Scope* innermostScope() const;
Scope* bodyScope() const {
MOZ_ASSERT(bodyScopeIndex < scopeList.length());
return scopeList.vector[bodyScopeIndex];
MOZ_ASSERT(bodyScopeIndex < perScriptData().scopeList().length());
return perScriptData().scopeList().vector[bodyScopeIndex];
}
MOZ_ALWAYS_INLINE
MOZ_MUST_USE bool makeAtomIndex(JSAtom* atom, uint32_t* indexp) {
MOZ_ASSERT(atomIndices);
AtomIndexMap::AddPtr p = atomIndices->lookupForAdd(atom);
MOZ_ASSERT(perScriptData().atomIndices());
AtomIndexMap::AddPtr p = perScriptData().atomIndices()->lookupForAdd(atom);
if (p) {
*indexp = p->value();
return true;
}
uint32_t index = atomIndices->count();
if (!atomIndices->add(p, atom, index)) {
uint32_t index = perScriptData().atomIndices()->count();
if (!perScriptData().atomIndices()->add(p, atom, index)) {
ReportOutOfMemory(cx);
return false;
}
@ -400,45 +592,13 @@ struct MOZ_STACK_CLASS BytecodeEmitter {
void tellDebuggerAboutCompiledScript(JSContext* cx);
BytecodeVector& code() { return code_; }
const BytecodeVector& code() const { return code_; }
jsbytecode* code(ptrdiff_t offset) { return code_.begin() + offset; }
ptrdiff_t offset() const { return code_.end() - code_.begin(); }
uint32_t mainOffset() const { return *mainOffset_; }
bool inPrologue() const { return mainOffset_.isNothing(); }
void switchToMain() {
MOZ_ASSERT(inPrologue());
mainOffset_.emplace(code_.length());
}
SrcNotesVector& notes() {
// Prologue shouldn't have source notes.
MOZ_ASSERT(!inPrologue());
return notes_;
}
ptrdiff_t lastNoteOffset() const { return lastNoteOffset_; }
unsigned currentLine() const { return currentLine_; }
void setCurrentLine(uint32_t line) {
currentLine_ = line;
lastColumn_ = 0;
}
// Check if the last emitted opcode is a jump target.
bool lastOpcodeIsJumpTarget() const {
return offset() - lastTarget.offset == ptrdiff_t(JSOP_JUMPTARGET_LENGTH);
}
// JumpTarget should not be part of the emitted statement, as they can be
// aliased by multiple statements. If we included the jump target as part of
// the statement we might have issues where the enclosing statement might
// not contain all the opcodes of the enclosed statements.
ptrdiff_t lastNonJumpTargetOffset() const {
return lastOpcodeIsJumpTarget() ? lastTarget.offset : offset();
mainOffset_.emplace(bytecodeSection().code().length());
}
void setFunctionBodyEndPos(uint32_t pos) {
@ -509,12 +669,10 @@ struct MOZ_STACK_CLASS BytecodeEmitter {
MOZ_MUST_USE bool emitFunctionScript(FunctionNode* funNode,
TopLevelFunction isTopLevel);
void updateDepth(ptrdiff_t target);
MOZ_MUST_USE bool markStepBreakpoint();
MOZ_MUST_USE bool markSimpleBreakpoint();
MOZ_MUST_USE bool updateLineNumberNotes(uint32_t offset);
MOZ_MUST_USE bool updateSourceCoordNotes(uint32_t offset);
void updateSeparatorPosition();
JSOp strictifySetNameOp(JSOp op);

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

@ -75,7 +75,7 @@ bool CForEmitter::emitBody(Cond cond, const Maybe<uint32_t>& bodyPos) {
return false;
}
biasedTop_ = bce_->offset();
biasedTop_ = bce_->bytecodeSection().offset();
if (cond_ == Cond::Present) {
// Goto the loop condition, which branches back to iterate.
@ -163,11 +163,11 @@ bool CForEmitter::emitCond(const Maybe<uint32_t>& forPos,
// Restore the absolute line number for source note readers.
if (endPos) {
uint32_t lineNum = bce_->parser->errorReporter().lineAt(*endPos);
if (bce_->currentLine() != lineNum) {
if (bce_->bytecodeSection().currentLine() != lineNum) {
if (!bce_->newSrcNote2(SRC_SETLINE, ptrdiff_t(lineNum))) {
return false;
}
bce_->setCurrentLine(lineNum);
bce_->bytecodeSection().setCurrentLine(lineNum);
}
}
}
@ -176,7 +176,7 @@ bool CForEmitter::emitCond(const Maybe<uint32_t>& forPos,
tdzCache_.reset();
}
condOffset_ = bce_->offset();
condOffset_ = bce_->bytecodeSection().offset();
if (cond_ == Cond::Present) {
if (!loopInfo_->emitLoopEntry(bce_, condPos)) {
@ -228,7 +228,8 @@ bool CForEmitter::emitEnd() {
return false;
}
if (!bce_->addTryNote(JSTRY_LOOP, bce_->stackDepth, loopInfo_->headOffset(),
if (!bce_->addTryNote(JSTRY_LOOP, bce_->bytecodeSection().stackDepth(),
loopInfo_->headOffset(),
loopInfo_->breakTargetOffset())) {
return false;
}

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

@ -75,7 +75,8 @@ bool DoWhileEmitter::emitEnd() {
return false;
}
if (!bce_->addTryNote(JSTRY_LOOP, bce_->stackDepth, loopInfo_->headOffset(),
if (!bce_->addTryNote(JSTRY_LOOP, bce_->bytecodeSection().stackDepth(),
loopInfo_->headOffset(),
loopInfo_->breakTargetOffset())) {
return false;
}

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

@ -342,8 +342,8 @@ bool EmitterScope::internScope(BytecodeEmitter* bce, ScopeCreator createScope) {
return false;
}
hasEnvironment_ = scope->hasEnvironment();
scopeIndex_ = bce->scopeList.length();
return bce->scopeList.append(scope);
scopeIndex_ = bce->perScriptData().scopeList().length();
return bce->perScriptData().scopeList().append(scope);
}
template <typename ScopeCreator>
@ -351,17 +351,17 @@ bool EmitterScope::internBodyScope(BytecodeEmitter* bce,
ScopeCreator createScope) {
MOZ_ASSERT(bce->bodyScopeIndex == UINT32_MAX,
"There can be only one body scope");
bce->bodyScopeIndex = bce->scopeList.length();
bce->bodyScopeIndex = bce->perScriptData().scopeList().length();
return internScope(bce, createScope);
}
bool EmitterScope::appendScopeNote(BytecodeEmitter* bce) {
MOZ_ASSERT(ScopeKindIsInBody(scope(bce)->kind()) && enclosingInFrame(),
"Scope notes are not needed for body-level scopes.");
noteIndex_ = bce->scopeNoteList.length();
return bce->scopeNoteList.append(index(), bce->offset(),
enclosingInFrame()
? enclosingInFrame()->noteIndex()
noteIndex_ = bce->bytecodeSection().scopeNoteList().length();
return bce->bytecodeSection().scopeNoteList().append(
index(), bce->bytecodeSection().offset(),
enclosingInFrame() ? enclosingInFrame()->noteIndex()
: ScopeNote::NoScopeNoteIndex);
}
@ -1057,9 +1057,10 @@ bool EmitterScope::leave(BytecodeEmitter* bce, bool nonLocal) {
if (ScopeKindIsInBody(kind)) {
// The extra function var scope is never popped once it's pushed,
// so its scope note extends until the end of any possible code.
uint32_t offset =
kind == ScopeKind::FunctionBodyVar ? UINT32_MAX : bce->offset();
bce->scopeNoteList.recordEnd(noteIndex_, offset);
uint32_t offset = kind == ScopeKind::FunctionBodyVar
? UINT32_MAX
: bce->bytecodeSection().offset();
bce->bytecodeSection().scopeNoteList().recordEnd(noteIndex_, offset);
}
}
@ -1067,7 +1068,7 @@ bool EmitterScope::leave(BytecodeEmitter* bce, bool nonLocal) {
}
Scope* EmitterScope::scope(const BytecodeEmitter* bce) const {
return bce->scopeList.vector[index()];
return bce->perScriptData().scopeList().vector[index()];
}
NameLocation EmitterScope::lookup(BytecodeEmitter* bce, JSAtom* name) {

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

@ -29,7 +29,7 @@ bool ExpressionStatementEmitter::prepareForExpr(
}
#ifdef DEBUG
depth_ = bce_->stackDepth;
depth_ = bce_->bytecodeSection().stackDepth();
state_ = State::Expr;
#endif
return true;
@ -37,7 +37,7 @@ bool ExpressionStatementEmitter::prepareForExpr(
bool ExpressionStatementEmitter::emitEnd() {
MOZ_ASSERT(state_ == State::Expr);
MOZ_ASSERT(bce_->stackDepth == depth_ + 1);
MOZ_ASSERT(bce_->bytecodeSection().stackDepth() == depth_ + 1);
// [stack] VAL

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

@ -94,7 +94,7 @@ bool ForInEmitter::emitInitialize() {
}
#ifdef DEBUG
loopDepth_ = bce_->stackDepth;
loopDepth_ = bce_->bytecodeSection().stackDepth();
#endif
MOZ_ASSERT(loopDepth_ >= 2);
@ -112,7 +112,7 @@ bool ForInEmitter::emitInitialize() {
bool ForInEmitter::emitBody() {
MOZ_ASSERT(state_ == State::Initialize);
MOZ_ASSERT(bce_->stackDepth == loopDepth_,
MOZ_ASSERT(bce_->bytecodeSection().stackDepth() == loopDepth_,
"iterator and iterval must be left on the stack");
#ifdef DEBUG
@ -124,7 +124,7 @@ bool ForInEmitter::emitBody() {
bool ForInEmitter::emitEnd(const Maybe<uint32_t>& forPos) {
MOZ_ASSERT(state_ == State::Body);
loopInfo_->setContinueTarget(bce_->offset());
loopInfo_->setContinueTarget(bce_->bytecodeSection().offset());
if (forPos) {
// Make sure this code is attributed to the "for".
@ -171,8 +171,9 @@ bool ForInEmitter::emitEnd(const Maybe<uint32_t>& forPos) {
return false;
}
if (!bce_->addTryNote(JSTRY_FOR_IN, bce_->stackDepth, loopInfo_->headOffset(),
bce_->offset())) {
if (!bce_->addTryNote(JSTRY_FOR_IN, bce_->bytecodeSection().stackDepth(),
loopInfo_->headOffset(),
bce_->bytecodeSection().offset())) {
return false;
}

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

@ -58,7 +58,7 @@ bool ForOfEmitter::emitInitialize(const Maybe<uint32_t>& forPos) {
}
}
int32_t iterDepth = bce_->stackDepth;
int32_t iterDepth = bce_->bytecodeSection().stackDepth();
// For-of loops have the iterator next method, the iterator itself, and
// the result.value on the stack.
@ -111,7 +111,7 @@ bool ForOfEmitter::emitInitialize(const Maybe<uint32_t>& forPos) {
}
#ifdef DEBUG
loopDepth_ = bce_->stackDepth;
loopDepth_ = bce_->bytecodeSection().stackDepth();
#endif
// Make sure this code is attributed to the "for".
@ -195,7 +195,7 @@ bool ForOfEmitter::emitInitialize(const Maybe<uint32_t>& forPos) {
bool ForOfEmitter::emitBody() {
MOZ_ASSERT(state_ == State::Initialize);
MOZ_ASSERT(bce_->stackDepth == loopDepth_,
MOZ_ASSERT(bce_->bytecodeSection().stackDepth() == loopDepth_,
"the stack must be balanced around the initializing "
"operation");
@ -218,14 +218,14 @@ bool ForOfEmitter::emitBody() {
bool ForOfEmitter::emitEnd(const Maybe<uint32_t>& iteratedPos) {
MOZ_ASSERT(state_ == State::Body);
MOZ_ASSERT(bce_->stackDepth == loopDepth_,
MOZ_ASSERT(bce_->bytecodeSection().stackDepth() == loopDepth_,
"the stack must be balanced around the for-of body");
if (!loopInfo_->emitEndCodeNeedingIteratorClose(bce_)) {
return false;
}
loopInfo_->setContinueTarget(bce_->offset());
loopInfo_->setContinueTarget(bce_->bytecodeSection().offset());
// We use the iterated value's position to attribute JSOP_LOOPENTRY,
// which corresponds to the iteration protocol.
@ -244,7 +244,7 @@ bool ForOfEmitter::emitEnd(const Maybe<uint32_t>& iteratedPos) {
return false;
}
MOZ_ASSERT(bce_->stackDepth == loopDepth_);
MOZ_ASSERT(bce_->bytecodeSection().stackDepth() == loopDepth_);
// Let Ion know where the closing jump of this loop is.
if (!bce_->setSrcNoteOffset(noteIndex_, SrcNote::ForOf::BackJumpOffset,
@ -256,7 +256,8 @@ bool ForOfEmitter::emitEnd(const Maybe<uint32_t>& iteratedPos) {
return false;
}
if (!bce_->addTryNote(JSTRY_FOR_OF, bce_->stackDepth, loopInfo_->headOffset(),
if (!bce_->addTryNote(JSTRY_FOR_OF, bce_->bytecodeSection().stackDepth(),
loopInfo_->headOffset(),
loopInfo_->breakTargetOffset())) {
return false;
}

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

@ -30,7 +30,7 @@ bool ForOfLoopControl::emitBeginCodeNeedingIteratorClose(BytecodeEmitter* bce) {
}
MOZ_ASSERT(numYieldsAtBeginCodeNeedingIterClose_ == UINT32_MAX);
numYieldsAtBeginCodeNeedingIterClose_ = bce->numYields;
numYieldsAtBeginCodeNeedingIterClose_ = bce->bytecodeSection().numYields();
return true;
}
@ -45,7 +45,7 @@ bool ForOfLoopControl::emitEndCodeNeedingIteratorClose(BytecodeEmitter* bce) {
// [stack] ITER ... EXCEPTION
return false;
}
unsigned slotFromTop = bce->stackDepth - iterDepth_;
unsigned slotFromTop = bce->bytecodeSection().stackDepth() - iterDepth_;
if (!bce->emitDupAt(slotFromTop)) {
// [stack] ITER ... EXCEPTION ITER
return false;
@ -69,7 +69,8 @@ bool ForOfLoopControl::emitEndCodeNeedingIteratorClose(BytecodeEmitter* bce) {
return false;
}
MOZ_ASSERT(slotFromTop == unsigned(bce->stackDepth - iterDepth_));
MOZ_ASSERT(slotFromTop ==
unsigned(bce->bytecodeSection().stackDepth() - iterDepth_));
if (!bce->emitDupAt(slotFromTop)) {
// [stack] ITER ... EXCEPTION ITER
return false;
@ -92,7 +93,7 @@ bool ForOfLoopControl::emitEndCodeNeedingIteratorClose(BytecodeEmitter* bce) {
// If any yields were emitted, then this for-of loop is inside a star
// generator and must handle the case of Generator.return. Like in
// yield*, it is handled with a finally block.
uint32_t numYieldsEmitted = bce->numYields;
uint32_t numYieldsEmitted = bce->bytecodeSection().numYields();
if (numYieldsEmitted > numYieldsAtBeginCodeNeedingIterClose_) {
if (!tryCatch_->emitFinally()) {
return false;
@ -135,12 +136,12 @@ bool ForOfLoopControl::emitEndCodeNeedingIteratorClose(BytecodeEmitter* bce) {
bool ForOfLoopControl::emitIteratorCloseInInnermostScopeWithTryNote(
BytecodeEmitter* bce,
CompletionKind completionKind /* = CompletionKind::Normal */) {
ptrdiff_t start = bce->offset();
ptrdiff_t start = bce->bytecodeSection().offset();
if (!emitIteratorCloseInScope(bce, *bce->innermostEmitterScope(),
completionKind)) {
return false;
}
ptrdiff_t end = bce->offset();
ptrdiff_t end = bce->bytecodeSection().offset();
return bce->addTryNote(JSTRY_FOR_OF_ITERCLOSE, 0, start, end);
}
@ -193,7 +194,7 @@ bool ForOfLoopControl::emitPrepareForNonLocalJumpFromScope(
return false;
}
*tryNoteStart = bce->offset();
*tryNoteStart = bce->bytecodeSection().offset();
if (!emitIteratorCloseInScope(bce, currentScope, CompletionKind::Normal)) {
// [stack] UNDEF
return false;

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

@ -220,7 +220,7 @@ bool FunctionEmitter::emitAsmJSModule() {
bool FunctionEmitter::emitFunction() {
// Make the function object a literal in the outer script's pool.
unsigned index = bce_->objectList.add(funbox_);
unsigned index = bce_->perScriptData().objectList().add(funbox_);
// [stack]

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

@ -41,10 +41,10 @@ bool BranchEmitterBase::emitThenInternal(SrcNoteType type) {
// To restore stack depth in else part, save depth of the then part.
#ifdef DEBUG
// If DEBUG, this is also necessary to calculate |pushed_|.
thenDepth_ = bce_->stackDepth;
thenDepth_ = bce_->bytecodeSection().stackDepth();
#else
if (type == SRC_COND || type == SRC_IF_ELSE) {
thenDepth_ = bce_->stackDepth;
thenDepth_ = bce_->bytecodeSection().stackDepth();
}
#endif
@ -59,10 +59,10 @@ bool BranchEmitterBase::emitThenInternal(SrcNoteType type) {
void BranchEmitterBase::calculateOrCheckPushed() {
#ifdef DEBUG
if (!calculatedPushed_) {
pushed_ = bce_->stackDepth - thenDepth_;
pushed_ = bce_->bytecodeSection().stackDepth() - thenDepth_;
calculatedPushed_ = true;
} else {
MOZ_ASSERT(pushed_ == bce_->stackDepth - thenDepth_);
MOZ_ASSERT(pushed_ == bce_->bytecodeSection().stackDepth() - thenDepth_);
}
#endif
}
@ -92,7 +92,7 @@ bool BranchEmitterBase::emitElseInternal() {
jumpAroundThen_ = JumpList();
// Restore stack depth of the then part.
bce_->stackDepth = thenDepth_;
bce_->bytecodeSection().setStackDepth(thenDepth_);
// Enclose else-branch with TDZCheckCache.
if (kind_ == Kind::MayContainLexicalAccessInBranch) {

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

@ -27,7 +27,7 @@ bool LabelEmitter::emitLabel(JSAtom* name) {
return false;
}
controlInfo_.emplace(bce_, name, bce_->offset());
controlInfo_.emplace(bce_, name, bce_->bytecodeSection().offset());
#ifdef DEBUG
state_ = State::Label;
@ -39,8 +39,8 @@ bool LabelEmitter::emitEnd() {
MOZ_ASSERT(state_ == State::Label);
// Patch the JSOP_LABEL offset.
jsbytecode* labelpc = bce_->code(top_);
int32_t offset = bce_->lastNonJumpTargetOffset() - top_;
jsbytecode* labelpc = bce_->bytecodeSection().code(top_);
int32_t offset = bce_->bytecodeSection().lastNonJumpTargetOffset() - top_;
MOZ_ASSERT(*labelpc == JSOP_LABEL);
SET_CODE_OFFSET(labelpc, offset);

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

@ -412,7 +412,7 @@ bool ObjectEmitter::emitObject(size_t propertyCount) {
// Emit code for {p:a, '%q':b, 2:c} that is equivalent to constructing
// a new object and defining (in source order) each property on the object
// (or mutating the object's [[Prototype]], in the case of __proto__).
top_ = bce_->offset();
top_ = bce_->bytecodeSection().offset();
if (!bce_->emitNewInit()) {
// [stack] OBJ
return false;

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

@ -151,7 +151,7 @@ bool SwitchEmitter::emitCond() {
// After entering the scope if necessary, push the switch control.
controlInfo_.emplace(bce_, StatementKind::Switch);
top_ = bce_->offset();
top_ = bce_->bytecodeSection().offset();
if (!caseOffsets_.resize(caseCount_)) {
ReportOutOfMemory(bce_->cx);
@ -164,7 +164,7 @@ bool SwitchEmitter::emitCond() {
return false;
}
MOZ_ASSERT(top_ == bce_->offset());
MOZ_ASSERT(top_ == bce_->bytecodeSection().offset());
if (!bce_->emitN(JSOP_CONDSWITCH, 0)) {
return false;
}
@ -181,7 +181,7 @@ bool SwitchEmitter::emitTable(const TableGenerator& tableGen) {
// After entering the scope if necessary, push the switch control.
controlInfo_.emplace(bce_, StatementKind::Switch);
top_ = bce_->offset();
top_ = bce_->bytecodeSection().offset();
// The note has one offset that tells total switch code length.
if (!bce_->newSrcNote2(SRC_TABLESWITCH, 0, &noteIndex_)) {
@ -193,14 +193,14 @@ bool SwitchEmitter::emitTable(const TableGenerator& tableGen) {
return false;
}
MOZ_ASSERT(top_ == bce_->offset());
MOZ_ASSERT(top_ == bce_->bytecodeSection().offset());
if (!bce_->emitN(JSOP_TABLESWITCH,
JSOP_TABLESWITCH_LENGTH - sizeof(jsbytecode))) {
return false;
}
// Skip default offset.
jsbytecode* pc = bce_->code(top_ + JUMP_OFFSET_LEN);
jsbytecode* pc = bce_->bytecodeSection().code(top_ + JUMP_OFFSET_LEN);
// Fill in switch bounds, which we know fit in 16-bit offsets.
SET_JUMP_OFFSET(pc, tableGen.low());
@ -223,9 +223,9 @@ bool SwitchEmitter::emitCaseOrDefaultJump(uint32_t caseIndex, bool isDefault) {
if (caseIndex > 0) {
// Link the last JSOP_CASE's SRC_NEXTCASE to current JSOP_CASE for the
// benefit of IonBuilder.
if (!bce_->setSrcNoteOffset(caseNoteIndex_,
SrcNote::NextCase::NextCaseOffset,
bce_->offset() - lastCaseOffset_)) {
if (!bce_->setSrcNoteOffset(
caseNoteIndex_, SrcNote::NextCase::NextCaseOffset,
bce_->bytecodeSection().offset() - lastCaseOffset_)) {
return false;
}
}
@ -243,11 +243,12 @@ bool SwitchEmitter::emitCaseOrDefaultJump(uint32_t caseIndex, bool isDefault) {
if (caseIndex == 0) {
// Switch note's second offset is to first JSOP_CASE.
unsigned noteCount = bce_->notes().length();
unsigned noteCount = bce_->bytecodeSection().notes().length();
if (!bce_->setSrcNoteOffset(noteIndex_, 1, lastCaseOffset_ - top_)) {
return false;
}
unsigned noteCountDelta = bce_->notes().length() - noteCount;
unsigned noteCountDelta =
bce_->bytecodeSection().notes().length() - noteCount;
if (noteCountDelta != 0) {
caseNoteIndex_ += noteCountDelta;
}
@ -398,7 +399,7 @@ bool SwitchEmitter::emitEnd() {
defaultJumpTargetOffset_);
} else {
// Fill in the default jump target.
pc = bce_->code(top_);
pc = bce_->bytecodeSection().code(top_);
SET_JUMP_OFFSET(pc, defaultJumpTargetOffset_.offset - top_);
pc += JUMP_OFFSET_LEN;
}
@ -408,8 +409,9 @@ bool SwitchEmitter::emitEnd() {
static_assert(unsigned(SrcNote::TableSwitch::EndOffset) ==
unsigned(SrcNote::CondSwitch::EndOffset),
"{TableSwitch,CondSwitch}::EndOffset should be same");
if (!bce_->setSrcNoteOffset(noteIndex_, SrcNote::TableSwitch::EndOffset,
bce_->lastNonJumpTargetOffset() - top_)) {
if (!bce_->setSrcNoteOffset(
noteIndex_, SrcNote::TableSwitch::EndOffset,
bce_->bytecodeSection().lastNonJumpTargetOffset() - top_)) {
return false;
}

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

@ -53,7 +53,7 @@ bool TryEmitter::emitTry() {
// For that we store in a try note associated with the catch or
// finally block the stack depth upon the try entry. The interpreter
// uses this depth to properly unwind the stack and the scope chain.
depth_ = bce_->stackDepth;
depth_ = bce_->bytecodeSection().stackDepth();
// Record the try location, then emit the try block.
if (!bce_->newSrcNote(SRC_TRY, &noteIndex_)) {
@ -62,7 +62,7 @@ bool TryEmitter::emitTry() {
if (!bce_->emit1(JSOP_TRY)) {
return false;
}
tryStart_ = bce_->offset();
tryStart_ = bce_->bytecodeSection().offset();
#ifdef DEBUG
state_ = State::Try;
@ -72,7 +72,7 @@ bool TryEmitter::emitTry() {
bool TryEmitter::emitTryEnd() {
MOZ_ASSERT(state_ == State::Try);
MOZ_ASSERT(depth_ == bce_->stackDepth);
MOZ_ASSERT(depth_ == bce_->bytecodeSection().stackDepth());
// GOSUB to finally, if present.
if (hasFinally() && controlInfo_) {
@ -82,8 +82,9 @@ bool TryEmitter::emitTryEnd() {
}
// Source note points to the jump at the end of the try block.
if (!bce_->setSrcNoteOffset(noteIndex_, SrcNote::Try::EndOfTryJumpOffset,
bce_->offset() - tryStart_ + JSOP_TRY_LENGTH)) {
if (!bce_->setSrcNoteOffset(
noteIndex_, SrcNote::Try::EndOfTryJumpOffset,
bce_->bytecodeSection().offset() - tryStart_ + JSOP_TRY_LENGTH)) {
return false;
}
@ -105,7 +106,7 @@ bool TryEmitter::emitCatch() {
return false;
}
MOZ_ASSERT(bce_->stackDepth == depth_);
MOZ_ASSERT(bce_->bytecodeSection().stackDepth() == depth_);
if (controlKind_ == ControlKind::Syntactic) {
// Clear the frame's return value that might have been set by the
@ -138,7 +139,7 @@ bool TryEmitter::emitCatchEnd() {
if (!bce_->emitGoSub(&controlInfo_->gosubs)) {
return false;
}
MOZ_ASSERT(bce_->stackDepth == depth_);
MOZ_ASSERT(bce_->bytecodeSection().stackDepth() == depth_);
// Jump over the finally block.
if (!bce_->emitJump(JSOP_GOTO, &catchAndFinallyJump_)) {
@ -177,7 +178,7 @@ bool TryEmitter::emitFinally(
}
}
MOZ_ASSERT(bce_->stackDepth == depth_);
MOZ_ASSERT(bce_->bytecodeSection().stackDepth() == depth_);
if (!bce_->emitJumpTarget(&finallyStart_)) {
return false;
@ -253,7 +254,7 @@ bool TryEmitter::emitEnd() {
}
}
MOZ_ASSERT(bce_->stackDepth == depth_);
MOZ_ASSERT(bce_->bytecodeSection().stackDepth() == depth_);
// ReconstructPCStack needs a NOP here to mark the end of the last
// catch block.

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

@ -100,7 +100,8 @@ bool WhileEmitter::emitEnd() {
return false;
}
if (!bce_->addTryNote(JSTRY_LOOP, bce_->stackDepth, loopInfo_->headOffset(),
if (!bce_->addTryNote(JSTRY_LOOP, bce_->bytecodeSection().stackDepth(),
loopInfo_->headOffset(),
loopInfo_->breakTargetOffset())) {
return false;
}

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

@ -7,6 +7,7 @@
#include "gc/Allocator.h"
#include "mozilla/DebugOnly.h"
#include "mozilla/TimeStamp.h"
#include "gc/GCInternals.h"
#include "gc/GCTrace.h"
@ -22,6 +23,9 @@
#include "gc/PrivateIterators-inl.h"
#include "vm/JSObject-inl.h"
using mozilla::TimeDuration;
using mozilla::TimeStamp;
using namespace js;
using namespace gc;
@ -268,20 +272,17 @@ T* GCRuntime::tryNewTenuredThing(JSContext* cx, AllocKind kind,
// chunks available it may also allocate new memory directly.
t = reinterpret_cast<T*>(refillFreeListFromAnyThread(cx, kind));
if (MOZ_UNLIKELY(!t && allowGC)) {
if (!cx->helperThread()) {
// We have no memory available for a new chunk; perform an
// all-compartments, non-incremental, shrinking GC and wait for
// sweeping to finish.
JS::PrepareForFullGC(cx);
cx->runtime()->gc.gc(GC_SHRINK, JS::GCReason::LAST_DITCH);
cx->runtime()->gc.waitBackgroundSweepOrAllocEnd();
if (MOZ_UNLIKELY(!t)) {
if (allowGC) {
cx->runtime()->gc.attemptLastDitchGC(cx);
t = tryNewTenuredThing<T, NoGC>(cx, kind, thingSize);
}
if (!t) {
if (allowGC) {
ReportOutOfMemory(cx);
}
return nullptr;
}
}
}
@ -294,6 +295,28 @@ T* GCRuntime::tryNewTenuredThing(JSContext* cx, AllocKind kind,
return t;
}
void GCRuntime::attemptLastDitchGC(JSContext* cx) {
// Either there was no memory available for a new chunk or the heap hit its
// size limit. Try to perform an all-compartments, non-incremental, shrinking
// GC and wait for it to finish.
if (cx->helperThread()) {
return;
}
if (!lastLastDitchTime.IsNull() &&
TimeStamp::Now() - lastLastDitchTime <= tunables.minLastDitchGCPeriod()) {
return;
}
JS::PrepareForFullGC(cx);
gc(GC_SHRINK, JS::GCReason::LAST_DITCH);
waitBackgroundAllocEnd();
waitBackgroundFreeEnd();
lastLastDitchTime = mozilla::TimeStamp::Now();
}
template <AllowGC allowGC>
bool GCRuntime::checkAllocatorState(JSContext* cx, AllocKind kind) {
if (allowGC) {

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

@ -364,6 +364,9 @@ static const float PretenureThreshold = 0.6f;
/* JSGC_PRETENURE_GROUP_THRESHOLD */
static const float PretenureGroupThreshold = 3000;
/* JSGC_MIN_LAST_DITCH_GC_PERIOD */
static const TimeDuration MinLastDitchGCPeriod = TimeDuration::FromSeconds(60);
} // namespace TuningDefaults
} // namespace gc
} // namespace js
@ -1521,6 +1524,9 @@ bool GCSchedulingTunables::setParameter(JSGCParamKey key, uint32_t value,
}
pretenureGroupThreshold_ = value;
break;
case JSGC_MIN_LAST_DITCH_GC_PERIOD:
minLastDitchGCPeriod_ = TimeDuration::FromSeconds(value);
break;
default:
MOZ_CRASH("Unknown GC parameter.");
}
@ -1613,7 +1619,8 @@ GCSchedulingTunables::GCSchedulingTunables()
nurseryFreeThresholdForIdleCollectionFraction_(
TuningDefaults::NurseryFreeThresholdForIdleCollectionFraction),
pretenureThreshold_(TuningDefaults::PretenureThreshold),
pretenureGroupThreshold_(TuningDefaults::PretenureGroupThreshold) {}
pretenureGroupThreshold_(TuningDefaults::PretenureGroupThreshold),
minLastDitchGCPeriod_(TuningDefaults::MinLastDitchGCPeriod) {}
void GCRuntime::resetParameter(JSGCParamKey key, AutoLockGC& lock) {
switch (key) {
@ -1708,6 +1715,9 @@ void GCSchedulingTunables::resetParameter(JSGCParamKey key,
case JSGC_PRETENURE_GROUP_THRESHOLD:
pretenureGroupThreshold_ = TuningDefaults::PretenureGroupThreshold;
break;
case JSGC_MIN_LAST_DITCH_GC_PERIOD:
minLastDitchGCPeriod_ = TuningDefaults::MinLastDitchGCPeriod;
break;
default:
MOZ_CRASH("Unknown GC parameter.");
}
@ -1783,6 +1793,8 @@ uint32_t GCRuntime::getParameter(JSGCParamKey key, const AutoLockGC& lock) {
return uint32_t(tunables.pretenureThreshold() * 100);
case JSGC_PRETENURE_GROUP_THRESHOLD:
return tunables.pretenureGroupThreshold();
case JSGC_MIN_LAST_DITCH_GC_PERIOD:
return tunables.minLastDitchGCPeriod().ToSeconds();
default:
MOZ_CRASH("Unknown parameter key");
}

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

@ -310,8 +310,7 @@ class GCRuntime {
bool isForegroundSweeping() const { return state() == State::Sweep; }
bool isBackgroundSweeping() { return sweepTask.isRunning(); }
void waitBackgroundSweepEnd();
void waitBackgroundSweepOrAllocEnd() {
waitBackgroundSweepEnd();
void waitBackgroundAllocEnd() {
allocTask.cancelAndWait();
}
void waitBackgroundFreeEnd();
@ -535,6 +534,7 @@ class GCRuntime {
AllocKind thingKind);
static TenuredCell* refillFreeListFromHelperThread(JSContext* cx,
AllocKind thingKind);
void attemptLastDitchGC(JSContext* cx);
/*
* Return the list of chunks that can be released outside the GC lock.
@ -1045,6 +1045,8 @@ class GCRuntime {
minorGC(reason, gcstats::PhaseKind::EVICT_NURSERY);
}
mozilla::TimeStamp lastLastDitchTime;
friend class MarkingValidator;
friend class AutoEnterIteration;
};

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

@ -456,6 +456,14 @@ class GCSchedulingTunables {
*/
UnprotectedData<uint32_t> pretenureGroupThreshold_;
/*
* JSGC_MIN_LAST_DITCH_GC_PERIOD
*
* Last ditch GC is skipped if allocation failure occurs less than this many
* seconds from the previous one.
*/
MainThreadData<mozilla::TimeDuration> minLastDitchGCPeriod_;
public:
GCSchedulingTunables();
@ -502,6 +510,10 @@ class GCSchedulingTunables {
float pretenureThreshold() const { return pretenureThreshold_; }
uint32_t pretenureGroupThreshold() const { return pretenureGroupThreshold_; }
mozilla::TimeDuration minLastDitchGCPeriod() const {
return minLastDitchGCPeriod_;
}
MOZ_MUST_USE bool setParameter(JSGCParamKey key, uint32_t value,
const AutoLockGC& lock);
void resetParameter(JSGCParamKey key, const AutoLockGC& lock);

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

@ -789,8 +789,14 @@ bool js::gc::CheckWeakMapEntryMarking(const WeakMapBase* map, Cell* key,
}
CellColor keyColor = GetCellColor(key);
CellColor valueColor =
valueZone->isGCMarking() ? GetCellColor(value) : CellColor::Black;
// Values belonging to other runtimes or in uncollected zones are treated as
// black.
CellColor valueColor = CellColor::Black;
if (value->runtimeFromAnyThread() == zone->runtimeFromAnyThread() &&
valueZone->isGCMarking()) {
valueColor = GetCellColor(value);
}
if (valueColor < Min(mapColor, keyColor)) {
fprintf(stderr, "WeakMap value is less marked than map and key\n");

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

@ -0,0 +1,45 @@
// Test that we don't repeatedly trigger last-ditch GCs.
function allocUntilFail() {
gc();
let initGCNumber = gcparam("gcNumber");
let error;
try {
let a = [];
while (true) {
a.push(Symbol()); // Symbols are tenured.
}
} catch(err) {
error = err;
}
let finalGCNumber = gcparam("gcNumber");
gc();
assertEq(error, "out of memory");
return finalGCNumber - initGCNumber;
}
// Turn of any zeal which will disrupt GC number checks.
gczeal(0);
// Set a small heap limit.
gcparam("maxBytes", 1024 * 1024);
// Set the time limit for skipping last ditch GCs to 5 seconds.
gcparam("minLastDitchGCPeriod", 5);
assertEq(gcparam("minLastDitchGCPeriod"), 5);
// Allocate up to the heap limit. This triggers a last ditch GC.
let gcCount = allocUntilFail();
assertEq(gcCount, 1)
// Allocate up to the limit again. The second time we fail without
// triggering a GC.
gcCount = allocUntilFail();
assertEq(gcCount, 0)
// Wait for time limit to expire.
sleep(6);
// Check we trigger a GC again.
gcCount = allocUntilFail();
assertEq(gcCount, 1)

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

@ -0,0 +1,11 @@
// |jit-test| skip-if: helperThreadCount() === 0
gczeal(0);
evalInWorker(`
var sym4 = Symbol.match;
function basicSweeping() {};
var wm1 = new WeakMap();
wm1.set(basicSweeping, sym4);
startgc(100000, 'shrinking');
`);
gczeal(2);
var d1 = newGlobal({});

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

@ -39,6 +39,8 @@ class ProgressBar(object):
self.limit_digits = int(math.ceil(math.log10(self.limit)))
# datetime: The start time.
self.t0 = datetime.now()
# datetime: Optional, the last time update() ran.
self.last_update_time = None
# Compute the width of the counters and build the format string.
self.counters_width = 1 # [
@ -79,7 +81,8 @@ class ProgressBar(object):
sys.stdout.write(bar + '|')
# Update the bar.
dt = datetime.now() - self.t0
now = datetime.now()
dt = now - self.t0
dt = dt.seconds + dt.microseconds * 1e-6
sys.stdout.write('{:6.1f}s'.format(dt))
Terminal.clear_right()
@ -87,9 +90,13 @@ class ProgressBar(object):
# Force redisplay, since we didn't write a \n.
sys.stdout.flush()
self.last_update_time = now
def poke(self):
if not self.prior:
return
if datetime.now() - self.last_update_time < self.update_granularity():
return
self.update(*self.prior)
def finish(self, complete=True):

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

@ -508,9 +508,10 @@ JS_PUBLIC_API bool JS::CloneAndExecuteScript(JSContext* cx,
return ExecuteScript(cx, envChain, script, rval.address());
}
template <typename Unit>
static bool Evaluate(JSContext* cx, ScopeKind scopeKind, HandleObject env,
const ReadOnlyCompileOptions& optionsArg,
SourceText<char16_t>& srcBuf, MutableHandleValue rval) {
SourceText<Unit>& srcBuf, MutableHandleValue rval) {
CompileOptions options(cx, optionsArg);
MOZ_ASSERT(!cx->zone()->isAtomsZone());
AssertHeapIsIdle();
@ -548,14 +549,8 @@ static bool Evaluate(JSContext* cx, HandleObjectVector envChain,
extern JS_PUBLIC_API bool JS::EvaluateUtf8(
JSContext* cx, const ReadOnlyCompileOptions& options, const char* bytes,
size_t length, MutableHandle<Value> rval) {
auto chars = UniqueTwoByteChars(
UTF8CharsToNewTwoByteCharsZ(cx, UTF8Chars(bytes, length), &length).get());
if (!chars) {
return false;
}
SourceText<char16_t> srcBuf;
if (!srcBuf.init(cx, std::move(chars), length)) {
SourceText<Utf8Unit> srcBuf;
if (!srcBuf.init(cx, bytes, length, SourceOwnership::Borrowed)) {
return false;
}
@ -594,7 +589,19 @@ JS_PUBLIC_API bool JS::EvaluateUtf8Path(
CompileOptions options(cx, optionsArg);
options.setFileAndLine(filename, 1);
return EvaluateUtf8(cx, options,
reinterpret_cast<const char*>(buffer.begin()),
buffer.length(), rval);
auto contents = reinterpret_cast<const char*>(buffer.begin());
size_t length = buffer.length();
auto chars = UniqueTwoByteChars(
UTF8CharsToNewTwoByteCharsZ(cx, UTF8Chars(contents, length), &length)
.get());
if (!chars) {
return false;
}
SourceText<char16_t> srcBuf;
if (!srcBuf.init(cx, std::move(chars), length)) {
return false;
}
return Evaluate(cx, options, srcBuf, rval);
}

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

@ -3238,12 +3238,12 @@ PrivateScriptData* PrivateScriptData::new_(JSContext* cx, uint32_t nscopes,
/* static */ bool PrivateScriptData::InitFromEmitter(
JSContext* cx, js::HandleScript script, frontend::BytecodeEmitter* bce) {
uint32_t nscopes = bce->scopeList.length();
uint32_t nconsts = bce->numberList.length();
uint32_t nobjects = bce->objectList.length;
uint32_t ntrynotes = bce->tryNoteList.length();
uint32_t nscopenotes = bce->scopeNoteList.length();
uint32_t nresumeoffsets = bce->resumeOffsetList.length();
uint32_t nscopes = bce->perScriptData().scopeList().length();
uint32_t nconsts = bce->perScriptData().numberList().length();
uint32_t nobjects = bce->perScriptData().objectList().length;
uint32_t ntrynotes = bce->bytecodeSection().tryNoteList().length();
uint32_t nscopenotes = bce->bytecodeSection().scopeNoteList().length();
uint32_t nresumeoffsets = bce->bytecodeSection().resumeOffsetList().length();
// Create and initialize PrivateScriptData
if (!JSScript::createPrivateScriptData(cx, script, nscopes, nconsts, nobjects,
@ -3254,22 +3254,22 @@ PrivateScriptData* PrivateScriptData::new_(JSContext* cx, uint32_t nscopes,
js::PrivateScriptData* data = script->data_;
if (nscopes) {
bce->scopeList.finish(data->scopes());
bce->perScriptData().scopeList().finish(data->scopes());
}
if (nconsts) {
bce->numberList.finish(data->consts());
bce->perScriptData().numberList().finish(data->consts());
}
if (nobjects) {
bce->objectList.finish(data->objects());
bce->perScriptData().objectList().finish(data->objects());
}
if (ntrynotes) {
bce->tryNoteList.finish(data->tryNotes());
bce->bytecodeSection().tryNoteList().finish(data->tryNotes());
}
if (nscopenotes) {
bce->scopeNoteList.finish(data->scopeNotes());
bce->bytecodeSection().scopeNoteList().finish(data->scopeNotes());
}
if (nresumeoffsets) {
bce->resumeOffsetList.finish(data->resumeOffsets());
bce->bytecodeSection().resumeOffsetList().finish(data->resumeOffsets());
}
return true;
@ -3565,11 +3565,12 @@ bool JSScript::fullyInitFromEmitter(JSContext* cx, HandleScript script,
mozilla::MakeScopeExit([&] { script->freeScriptData(); });
/* The counts of indexed things must be checked during code generation. */
MOZ_ASSERT(bce->atomIndices->count() <= INDEX_LIMIT);
MOZ_ASSERT(bce->objectList.length <= INDEX_LIMIT);
MOZ_ASSERT(bce->perScriptData().atomIndices()->count() <= INDEX_LIMIT);
MOZ_ASSERT(bce->perScriptData().objectList().length <= INDEX_LIMIT);
uint64_t nslots =
bce->maxFixedSlots + static_cast<uint64_t>(bce->maxStackDepth);
bce->maxFixedSlots +
static_cast<uint64_t>(bce->bytecodeSection().maxStackDepth());
if (nslots > UINT32_MAX) {
bce->reportError(nullptr, JSMSG_NEED_DIET, js_script_str);
return false;
@ -3581,7 +3582,7 @@ bool JSScript::fullyInitFromEmitter(JSContext* cx, HandleScript script,
script->nfixed_ = bce->maxFixedSlots;
script->nslots_ = nslots;
script->bodyScopeIndex_ = bce->bodyScopeIndex;
script->numBytecodeTypeSets_ = bce->typesetCount;
script->numBytecodeTypeSets_ = bce->bytecodeSection().typesetCount();
// Initialize script flags from BytecodeEmitter
script->setFlag(ImmutableFlags::Strict, bce->sc->strict());
@ -3628,7 +3629,7 @@ bool JSScript::fullyInitFromEmitter(JSContext* cx, HandleScript script,
// Part of the parse result – the scope containing each inner function – must
// be stored in the inner function itself. Do this now that compilation is
// complete and can no longer fail.
bce->objectList.finishInnerFunctions();
bce->perScriptData().objectList().finishInnerFunctions();
#ifdef JS_STRUCTURED_SPEW
// We want this to happen after line number initialization to allow filtering
@ -4522,12 +4523,12 @@ bool JSScript::hasBreakpointsAt(jsbytecode* pc) {
/* static */ bool SharedScriptData::InitFromEmitter(
JSContext* cx, js::HandleScript script, frontend::BytecodeEmitter* bce) {
uint32_t natoms = bce->atomIndices->count();
uint32_t codeLength = bce->code().length();
uint32_t natoms = bce->perScriptData().atomIndices()->count();
uint32_t codeLength = bce->bytecodeSection().code().length();
// The + 1 is to account for the final SN_MAKE_TERMINATOR that is appended
// when the notes are copied to their final destination by copySrcNotes.
uint32_t noteLength = bce->notes().length() + 1;
uint32_t noteLength = bce->bytecodeSection().notes().length() + 1;
// Create and initialize SharedScriptData
if (!script->createSharedScriptData(cx, codeLength, noteLength, natoms)) {
@ -4537,9 +4538,9 @@ bool JSScript::hasBreakpointsAt(jsbytecode* pc) {
js::SharedScriptData* data = script->scriptData_;
// Initialize trailing arrays
std::copy_n(bce->code().begin(), codeLength, data->code());
std::copy_n(bce->bytecodeSection().code().begin(), codeLength, data->code());
bce->copySrcNotes(data->notes(), noteLength);
InitAtomMap(*bce->atomIndices, data->atoms());
InitAtomMap(*bce->perScriptData().atomIndices(), data->atoms());
return true;
}

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

@ -307,6 +307,34 @@ const nsTArray<GfxDriverInfo> &GfxInfo::GetGfxDriverInfo() {
GfxDriverInfo::allDevices, GfxDriverInfo::allFeatures,
nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION, DRIVER_LESS_THAN,
V(13, 15, 100, 1), "FEATURE_FAILURE_OLD_FGLRX", "fglrx 13.15.100.1");
////////////////////////////////////
// FEATURE_WEBRENDER
// Mesa baseline (chosen arbitrarily as that which ships with
// Ubuntu 18.04 LTS).
APPEND_TO_DRIVER_BLOCKLIST(
OperatingSystem::Linux,
(nsAString &)GfxDriverInfo::GetDeviceVendor(VendorMesaAll),
GfxDriverInfo::allDevices, nsIGfxInfo::FEATURE_WEBRENDER,
nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION, DRIVER_LESS_THAN,
V(18, 2, 8, 0), "FEATURE_FAILURE_WEBRENDER_OLD_MESA", "Mesa 18.2.8.0");
// Disable on all NVIDIA devices for now.
APPEND_TO_DRIVER_BLOCKLIST(
OperatingSystem::Linux,
(nsAString &)GfxDriverInfo::GetDeviceVendor(VendorNVIDIA),
GfxDriverInfo::allDevices, nsIGfxInfo::FEATURE_WEBRENDER,
nsIGfxInfo::FEATURE_BLOCKED_DEVICE, DRIVER_COMPARISON_IGNORED,
V(0, 0, 0, 0), "FEATURE_FAILURE_WEBRENDER_NO_LINUX_NVIDIA", "");
// Disable on all ATI devices for now.
APPEND_TO_DRIVER_BLOCKLIST(
OperatingSystem::Linux,
(nsAString &)GfxDriverInfo::GetDeviceVendor(VendorATI),
GfxDriverInfo::allDevices, nsIGfxInfo::FEATURE_WEBRENDER,
nsIGfxInfo::FEATURE_BLOCKED_DEVICE, DRIVER_COMPARISON_IGNORED,
V(0, 0, 0, 0), "FEATURE_FAILURE_WEBRENDER_NO_LINUX_ATI", "");
}
return *sDriverInfo;
}

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

@ -1602,9 +1602,9 @@ const nsTArray<GfxDriverInfo>& GfxInfo::GetGfxDriverInfo() {
////////////////////////////////////
// FEATURE_WEBRENDER
// We are blocking all non-Nvidia cards in gfxPlatform.cpp where we check
// for the WEBRENDER_QUALIFIED feature. However we also want to block some
// specific Nvidia cards for being too low-powered, so we do that here.
// We are blocking most hardware explicitly in gfxPlatform.cpp where we
// check for the WEBRENDER_QUALIFIED feature. However we also want to block
// some specific Nvidia cards for being too low-powered, so we do that here.
APPEND_TO_DRIVER_BLOCKLIST2(
OperatingSystem::Windows10,
(nsAString&)GfxDriverInfo::GetDeviceVendor(VendorNVIDIA),