зеркало из https://github.com/mozilla/gecko-dev.git
Merge mozilla-inbound to mozilla-central. a=merge
This commit is contained in:
Коммит
d0d4b7058d
|
@ -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(),
|
||||
openScopeNoteIndex_)) {
|
||||
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 = ¬es[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);
|
||||
|
||||
// Code offset for last source note
|
||||
ptrdiff_t lastNoteOffset_ = 0;
|
||||
// ---- Bytecode ----
|
||||
|
||||
// Line number for srcnotes.
|
||||
//
|
||||
// WARNING: If this becomes out of sync with already-emitted srcnotes,
|
||||
// we can get undefined behavior.
|
||||
uint32_t currentLine_ = 0;
|
||||
BytecodeVector& code() { return code_; }
|
||||
const BytecodeVector& code() const { return code_; }
|
||||
|
||||
// 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;
|
||||
jsbytecode* code(ptrdiff_t offset) { return code_.begin() + offset; }
|
||||
ptrdiff_t offset() const { return code_.end() - code_.begin(); }
|
||||
|
||||
uint32_t lastSeparatorOffet_ = 0;
|
||||
uint32_t lastSeparatorLine_ = 0;
|
||||
uint32_t lastSeparatorColumn_ = 0;
|
||||
// ---- 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_;
|
||||
|
||||
// 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,18 +351,18 @@ 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()
|
||||
: ScopeNote::NoScopeNoteIndex);
|
||||
noteIndex_ = bce->bytecodeSection().scopeNoteList().length();
|
||||
return bce->bytecodeSection().scopeNoteList().append(
|
||||
index(), bce->bytecodeSection().offset(),
|
||||
enclosingInFrame() ? enclosingInFrame()->noteIndex()
|
||||
: ScopeNote::NoScopeNoteIndex);
|
||||
}
|
||||
|
||||
bool EmitterScope::deadZoneFrameSlotRange(BytecodeEmitter* bce,
|
||||
|
@ -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, ¬eIndex_)) {
|
||||
|
@ -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, ¬eIndex_)) {
|
||||
|
@ -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,19 +272,16 @@ 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) {
|
||||
ReportOutOfMemory(cx);
|
||||
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),
|
||||
|
|
Загрузка…
Ссылка в новой задаче