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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

@ -923,6 +923,7 @@ void gfxPlatform::Init() {
#else #else
# error "No gfxPlatform implementation available" # error "No gfxPlatform implementation available"
#endif #endif
gPlatform->PopulateScreenInfo();
gPlatform->InitAcceleration(); gPlatform->InitAcceleration();
gPlatform->InitWebRenderConfig(); gPlatform->InitWebRenderConfig();
// When using WebRender, we defer initialization of the D3D11 devices until // When using WebRender, we defer initialization of the D3D11 devices until
@ -960,7 +961,6 @@ void gfxPlatform::Init() {
InitLayersIPC(); InitLayersIPC();
gPlatform->PopulateScreenInfo();
gPlatform->ComputeTileSize(); gPlatform->ComputeTileSize();
#ifdef MOZ_ENABLE_FREETYPE #ifdef MOZ_ENABLE_FREETYPE
@ -2511,7 +2511,7 @@ static bool CalculateWrQualifiedPrefValue() {
} }
static FeatureState& WebRenderHardwareQualificationStatus( static FeatureState& WebRenderHardwareQualificationStatus(
bool aHasBattery, nsCString& aOutFailureId) { const IntSize& aScreenSize, bool aHasBattery, nsCString& aOutFailureId) {
FeatureState& featureWebRenderQualified = FeatureState& featureWebRenderQualified =
gfxConfig::GetFeature(Feature::WEBRENDER_QUALIFIED); gfxConfig::GetFeature(Feature::WEBRENDER_QUALIFIED);
featureWebRenderQualified.EnableByDefault(); featureWebRenderQualified.EnableByDefault();
@ -2576,7 +2576,8 @@ static FeatureState& WebRenderHardwareQualificationStatus(
FeatureStatus::Blocked, "Device too old", FeatureStatus::Blocked, "Device too old",
NS_LITERAL_CSTRING("FEATURE_FAILURE_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[] = { const uint16_t supportedDevices[] = {
0x191d, // HD Graphics P530 0x191d, // HD Graphics P530
0x192d, // Iris Pro Graphics P555 0x192d, // Iris Pro Graphics P555
@ -2605,6 +2606,18 @@ static FeatureState& WebRenderHardwareQualificationStatus(
featureWebRenderQualified.Disable( featureWebRenderQualified.Disable(
FeatureStatus::Blocked, "Device too old", FeatureStatus::Blocked, "Device too old",
NS_LITERAL_CSTRING("FEATURE_FAILURE_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 #endif
} else { } else {
@ -2653,7 +2666,8 @@ void gfxPlatform::InitWebRenderConfig() {
nsCString failureId; nsCString failureId;
FeatureState& featureWebRenderQualified = FeatureState& featureWebRenderQualified =
WebRenderHardwareQualificationStatus(HasBattery(), failureId); WebRenderHardwareQualificationStatus(GetScreenSize(), HasBattery(),
failureId);
FeatureState& featureWebRender = gfxConfig::GetFeature(Feature::WEBRENDER); FeatureState& featureWebRender = gfxConfig::GetFeature(Feature::WEBRENDER);
featureWebRender.DisableByDefault( featureWebRender.DisableByDefault(
@ -2748,6 +2762,16 @@ void gfxPlatform::InitWebRenderConfig() {
WebRenderDebugPrefChangeCallback, WR_DEBUG_PREF); 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 #ifdef XP_WIN
if (Preferences::GetBool("gfx.webrender.dcomp-win.enabled", false)) { if (Preferences::GetBool("gfx.webrender.dcomp-win.enabled", false)) {

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

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

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

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

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

@ -307,6 +307,14 @@ typedef enum JSGCParamKey {
*/ */
JSGC_MIN_NURSERY_BYTES = 31, 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; } JSGCParamKey;
/* /*

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

@ -488,7 +488,8 @@ static bool MinorGC(JSContext* cx, unsigned argc, Value* vp) {
_("allocationThreshold", JSGC_ALLOCATION_THRESHOLD, true) \ _("allocationThreshold", JSGC_ALLOCATION_THRESHOLD, true) \
_("minEmptyChunkCount", JSGC_MIN_EMPTY_CHUNK_COUNT, true) \ _("minEmptyChunkCount", JSGC_MIN_EMPTY_CHUNK_COUNT, true) \
_("maxEmptyChunkCount", JSGC_MAX_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 { static const struct ParamInfo {
const char* name; const char* name;

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

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

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

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

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

@ -124,29 +124,249 @@ struct MOZ_STACK_CLASS BytecodeEmitter {
Rooted<LazyScript*> lazyScript; Rooted<LazyScript*> lazyScript;
private: private:
BytecodeVector code_; /* bytecode */ // Bytecode and all data directly associated with specific opcode/index inside
SrcNotesVector notes_; /* source notes, see below */ // bytecode is stored in this class.
class BytecodeSection {
public:
BytecodeSection(JSContext* cx, uint32_t lineNum);
// ---- Bytecode ----
BytecodeVector& code() { return code_; }
const BytecodeVector& code() const { return code_; }
jsbytecode* code(ptrdiff_t offset) { return code_.begin() + offset; }
ptrdiff_t offset() const { return code_.end() - code_.begin(); }
// ---- Source notes ----
SrcNotesVector& notes() { return notes_; }
const SrcNotesVector& notes() const { return notes_; }
ptrdiff_t lastNoteOffset() const { return lastNoteOffset_; }
void setLastNoteOffset(ptrdiff_t offset) { lastNoteOffset_ = offset; }
// ---- Jump ----
ptrdiff_t lastTargetOffset() const { return lastTarget_.offset; }
void setLastTargetOffset(ptrdiff_t offset) { lastTarget_.offset = offset; }
// Check if the last emitted opcode is a jump target.
bool lastOpcodeIsJumpTarget() const {
return offset() - lastTarget_.offset == ptrdiff_t(JSOP_JUMPTARGET_LENGTH);
}
// JumpTarget should not be part of the emitted statement, as they can be
// aliased by multiple statements. If we included the jump target as part of
// the statement we might have issues where the enclosing statement might
// not contain all the opcodes of the enclosed statements.
ptrdiff_t lastNonJumpTargetOffset() const {
return lastOpcodeIsJumpTarget() ? lastTarget_.offset : offset();
}
// ---- Stack ----
int32_t stackDepth() const { return stackDepth_; }
void setStackDepth(int32_t depth) { stackDepth_ = depth; }
uint32_t maxStackDepth() const { return maxStackDepth_; }
void updateDepth(ptrdiff_t target);
// ---- Try notes ----
CGTryNoteList& tryNoteList() { return tryNoteList_; };
const CGTryNoteList& tryNoteList() const { return tryNoteList_; };
// ---- Scope ----
CGScopeNoteList& scopeNoteList() { return scopeNoteList_; };
const CGScopeNoteList& scopeNoteList() const { return scopeNoteList_; };
// ---- Generator ----
CGResumeOffsetList& resumeOffsetList() { return resumeOffsetList_; }
const CGResumeOffsetList& resumeOffsetList() const {
return resumeOffsetList_;
}
uint32_t numYields() const { return numYields_; }
void addNumYields() { numYields_++; }
// ---- Line and column ----
uint32_t currentLine() const { return currentLine_; }
uint32_t lastColumn() const { return lastColumn_; }
void setCurrentLine(uint32_t line) {
currentLine_ = line;
lastColumn_ = 0;
}
void setLastColumn(uint32_t column) { lastColumn_ = column; }
void updateSeparatorPosition() {
lastSeparatorOffet_ = code().length();
lastSeparatorLine_ = currentLine_;
lastSeparatorColumn_ = lastColumn_;
}
void updateSeparatorPositionIfPresent() {
if (lastSeparatorOffet_ == code().length()) {
lastSeparatorLine_ = currentLine_;
lastSeparatorColumn_ = lastColumn_;
}
}
bool isDuplicateLocation() const {
return lastSeparatorLine_ == currentLine_ &&
lastSeparatorColumn_ == lastColumn_;
}
// ---- JIT ----
size_t numICEntries() const { return numICEntries_; }
void addNumICEntries() { numICEntries_++; }
void setNumICEntries(size_t entries) { numICEntries_ = entries; }
uint16_t typesetCount() const { return typesetCount_; }
void addTypesetCount() { typesetCount_++; }
private:
// ---- Bytecode ----
// Bytecode.
BytecodeVector code_;
// ---- Source notes ----
// Source notes
SrcNotesVector notes_;
// Code offset for last source note // Code offset for last source note
ptrdiff_t lastNoteOffset_ = 0; 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. // Line number for srcnotes.
// //
// WARNING: If this becomes out of sync with already-emitted srcnotes, // WARNING: If this becomes out of sync with already-emitted srcnotes,
// we can get undefined behavior. // we can get undefined behavior.
uint32_t currentLine_ = 0; uint32_t currentLine_;
// Zero-based column index on currentLine of last SRC_COLSPAN-annotated // Zero-based column index on currentLine_ of last SRC_COLSPAN-annotated
// opcode. // opcode.
// //
// WARNING: If this becomes out of sync with already-emitted srcnotes, // WARNING: If this becomes out of sync with already-emitted srcnotes,
// we can get undefined behavior. // we can get undefined behavior.
uint32_t lastColumn_ = 0; 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 lastSeparatorOffet_ = 0;
uint32_t lastSeparatorLine_ = 0; uint32_t lastSeparatorLine_ = 0;
uint32_t lastSeparatorColumn_ = 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. // switchToMain sets this to the bytecode offset of the main section.
mozilla::Maybe<uint32_t> mainOffset_ = {}; mozilla::Maybe<uint32_t> mainOffset_ = {};
@ -154,22 +374,14 @@ struct MOZ_STACK_CLASS BytecodeEmitter {
const FieldInitializers fieldInitializers_; const FieldInitializers fieldInitializers_;
public: 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 // Private storage for parser wrapper. DO NOT REFERENCE INTERNALLY. May not be
// initialized. Use |parser| instead. // initialized. Use |parser| instead.
mozilla::Maybe<EitherParser> ep_ = {}; mozilla::Maybe<EitherParser> ep_ = {};
BCEParserHandle* parser = nullptr; BCEParserHandle* parser = nullptr;
PooledMapPtr<AtomIndexMap> atomIndices; /* literals indexed for mapping */
unsigned firstLine = 0; /* first line, for JSScript::initFromEmitter */ unsigned firstLine = 0; /* first line, for JSScript::initFromEmitter */
uint32_t maxFixedSlots = 0; /* maximum number of fixed frame slots so far */ 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_t bodyScopeIndex =
UINT32_MAX; /* index into scopeList of the body scope */ UINT32_MAX; /* index into scopeList of the body scope */
@ -195,28 +407,6 @@ struct MOZ_STACK_CLASS BytecodeEmitter {
return innermostEmitterScope_; 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. // Script contains singleton initializer JSOP_OBJECT.
bool hasSingletons = false; bool hasSingletons = false;
@ -360,24 +550,26 @@ struct MOZ_STACK_CLASS BytecodeEmitter {
varEmitterScope = emitterScope; varEmitterScope = emitterScope;
} }
Scope* outermostScope() const { return scopeList.vector[0]; } Scope* outermostScope() const {
return perScriptData().scopeList().vector[0];
}
Scope* innermostScope() const; Scope* innermostScope() const;
Scope* bodyScope() const { Scope* bodyScope() const {
MOZ_ASSERT(bodyScopeIndex < scopeList.length()); MOZ_ASSERT(bodyScopeIndex < perScriptData().scopeList().length());
return scopeList.vector[bodyScopeIndex]; return perScriptData().scopeList().vector[bodyScopeIndex];
} }
MOZ_ALWAYS_INLINE MOZ_ALWAYS_INLINE
MOZ_MUST_USE bool makeAtomIndex(JSAtom* atom, uint32_t* indexp) { MOZ_MUST_USE bool makeAtomIndex(JSAtom* atom, uint32_t* indexp) {
MOZ_ASSERT(atomIndices); MOZ_ASSERT(perScriptData().atomIndices());
AtomIndexMap::AddPtr p = atomIndices->lookupForAdd(atom); AtomIndexMap::AddPtr p = perScriptData().atomIndices()->lookupForAdd(atom);
if (p) { if (p) {
*indexp = p->value(); *indexp = p->value();
return true; return true;
} }
uint32_t index = atomIndices->count(); uint32_t index = perScriptData().atomIndices()->count();
if (!atomIndices->add(p, atom, index)) { if (!perScriptData().atomIndices()->add(p, atom, index)) {
ReportOutOfMemory(cx); ReportOutOfMemory(cx);
return false; return false;
} }
@ -400,45 +592,13 @@ struct MOZ_STACK_CLASS BytecodeEmitter {
void tellDebuggerAboutCompiledScript(JSContext* cx); 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_; } uint32_t mainOffset() const { return *mainOffset_; }
bool inPrologue() const { return mainOffset_.isNothing(); } bool inPrologue() const { return mainOffset_.isNothing(); }
void switchToMain() { void switchToMain() {
MOZ_ASSERT(inPrologue()); MOZ_ASSERT(inPrologue());
mainOffset_.emplace(code_.length()); mainOffset_.emplace(bytecodeSection().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();
} }
void setFunctionBodyEndPos(uint32_t pos) { void setFunctionBodyEndPos(uint32_t pos) {
@ -509,12 +669,10 @@ struct MOZ_STACK_CLASS BytecodeEmitter {
MOZ_MUST_USE bool emitFunctionScript(FunctionNode* funNode, MOZ_MUST_USE bool emitFunctionScript(FunctionNode* funNode,
TopLevelFunction isTopLevel); TopLevelFunction isTopLevel);
void updateDepth(ptrdiff_t target);
MOZ_MUST_USE bool markStepBreakpoint(); MOZ_MUST_USE bool markStepBreakpoint();
MOZ_MUST_USE bool markSimpleBreakpoint(); MOZ_MUST_USE bool markSimpleBreakpoint();
MOZ_MUST_USE bool updateLineNumberNotes(uint32_t offset); MOZ_MUST_USE bool updateLineNumberNotes(uint32_t offset);
MOZ_MUST_USE bool updateSourceCoordNotes(uint32_t offset); MOZ_MUST_USE bool updateSourceCoordNotes(uint32_t offset);
void updateSeparatorPosition();
JSOp strictifySetNameOp(JSOp op); JSOp strictifySetNameOp(JSOp op);

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

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

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

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

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

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

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

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

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

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

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

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

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

@ -220,7 +220,7 @@ bool FunctionEmitter::emitAsmJSModule() {
bool FunctionEmitter::emitFunction() { bool FunctionEmitter::emitFunction() {
// Make the function object a literal in the outer script's pool. // 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] // [stack]

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

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

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

@ -27,7 +27,7 @@ bool LabelEmitter::emitLabel(JSAtom* name) {
return false; return false;
} }
controlInfo_.emplace(bce_, name, bce_->offset()); controlInfo_.emplace(bce_, name, bce_->bytecodeSection().offset());
#ifdef DEBUG #ifdef DEBUG
state_ = State::Label; state_ = State::Label;
@ -39,8 +39,8 @@ bool LabelEmitter::emitEnd() {
MOZ_ASSERT(state_ == State::Label); MOZ_ASSERT(state_ == State::Label);
// Patch the JSOP_LABEL offset. // Patch the JSOP_LABEL offset.
jsbytecode* labelpc = bce_->code(top_); jsbytecode* labelpc = bce_->bytecodeSection().code(top_);
int32_t offset = bce_->lastNonJumpTargetOffset() - top_; int32_t offset = bce_->bytecodeSection().lastNonJumpTargetOffset() - top_;
MOZ_ASSERT(*labelpc == JSOP_LABEL); MOZ_ASSERT(*labelpc == JSOP_LABEL);
SET_CODE_OFFSET(labelpc, offset); 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 // 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 // a new object and defining (in source order) each property on the object
// (or mutating the object's [[Prototype]], in the case of __proto__). // (or mutating the object's [[Prototype]], in the case of __proto__).
top_ = bce_->offset(); top_ = bce_->bytecodeSection().offset();
if (!bce_->emitNewInit()) { if (!bce_->emitNewInit()) {
// [stack] OBJ // [stack] OBJ
return false; return false;

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

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

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

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

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

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

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

@ -7,6 +7,7 @@
#include "gc/Allocator.h" #include "gc/Allocator.h"
#include "mozilla/DebugOnly.h" #include "mozilla/DebugOnly.h"
#include "mozilla/TimeStamp.h"
#include "gc/GCInternals.h" #include "gc/GCInternals.h"
#include "gc/GCTrace.h" #include "gc/GCTrace.h"
@ -22,6 +23,9 @@
#include "gc/PrivateIterators-inl.h" #include "gc/PrivateIterators-inl.h"
#include "vm/JSObject-inl.h" #include "vm/JSObject-inl.h"
using mozilla::TimeDuration;
using mozilla::TimeStamp;
using namespace js; using namespace js;
using namespace gc; using namespace gc;
@ -268,20 +272,17 @@ T* GCRuntime::tryNewTenuredThing(JSContext* cx, AllocKind kind,
// chunks available it may also allocate new memory directly. // chunks available it may also allocate new memory directly.
t = reinterpret_cast<T*>(refillFreeListFromAnyThread(cx, kind)); t = reinterpret_cast<T*>(refillFreeListFromAnyThread(cx, kind));
if (MOZ_UNLIKELY(!t && allowGC)) { if (MOZ_UNLIKELY(!t)) {
if (!cx->helperThread()) { if (allowGC) {
// We have no memory available for a new chunk; perform an cx->runtime()->gc.attemptLastDitchGC(cx);
// 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();
t = tryNewTenuredThing<T, NoGC>(cx, kind, thingSize); t = tryNewTenuredThing<T, NoGC>(cx, kind, thingSize);
} }
if (!t) { if (!t) {
if (allowGC) {
ReportOutOfMemory(cx); ReportOutOfMemory(cx);
} }
return nullptr;
}
} }
} }
@ -294,6 +295,28 @@ T* GCRuntime::tryNewTenuredThing(JSContext* cx, AllocKind kind,
return t; 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> template <AllowGC allowGC>
bool GCRuntime::checkAllocatorState(JSContext* cx, AllocKind kind) { bool GCRuntime::checkAllocatorState(JSContext* cx, AllocKind kind) {
if (allowGC) { if (allowGC) {

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

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

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

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

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

@ -456,6 +456,14 @@ class GCSchedulingTunables {
*/ */
UnprotectedData<uint32_t> pretenureGroupThreshold_; 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: public:
GCSchedulingTunables(); GCSchedulingTunables();
@ -502,6 +510,10 @@ class GCSchedulingTunables {
float pretenureThreshold() const { return pretenureThreshold_; } float pretenureThreshold() const { return pretenureThreshold_; }
uint32_t pretenureGroupThreshold() const { return pretenureGroupThreshold_; } uint32_t pretenureGroupThreshold() const { return pretenureGroupThreshold_; }
mozilla::TimeDuration minLastDitchGCPeriod() const {
return minLastDitchGCPeriod_;
}
MOZ_MUST_USE bool setParameter(JSGCParamKey key, uint32_t value, MOZ_MUST_USE bool setParameter(JSGCParamKey key, uint32_t value,
const AutoLockGC& lock); const AutoLockGC& lock);
void resetParameter(JSGCParamKey key, 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 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)) { if (valueColor < Min(mapColor, keyColor)) {
fprintf(stderr, "WeakMap value is less marked than map and key\n"); 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))) self.limit_digits = int(math.ceil(math.log10(self.limit)))
# datetime: The start time. # datetime: The start time.
self.t0 = datetime.now() 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. # Compute the width of the counters and build the format string.
self.counters_width = 1 # [ self.counters_width = 1 # [
@ -79,7 +81,8 @@ class ProgressBar(object):
sys.stdout.write(bar + '|') sys.stdout.write(bar + '|')
# Update the bar. # Update the bar.
dt = datetime.now() - self.t0 now = datetime.now()
dt = now - self.t0
dt = dt.seconds + dt.microseconds * 1e-6 dt = dt.seconds + dt.microseconds * 1e-6
sys.stdout.write('{:6.1f}s'.format(dt)) sys.stdout.write('{:6.1f}s'.format(dt))
Terminal.clear_right() Terminal.clear_right()
@ -87,9 +90,13 @@ class ProgressBar(object):
# Force redisplay, since we didn't write a \n. # Force redisplay, since we didn't write a \n.
sys.stdout.flush() sys.stdout.flush()
self.last_update_time = now
def poke(self): def poke(self):
if not self.prior: if not self.prior:
return return
if datetime.now() - self.last_update_time < self.update_granularity():
return
self.update(*self.prior) self.update(*self.prior)
def finish(self, complete=True): def finish(self, complete=True):

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

@ -508,9 +508,10 @@ JS_PUBLIC_API bool JS::CloneAndExecuteScript(JSContext* cx,
return ExecuteScript(cx, envChain, script, rval.address()); return ExecuteScript(cx, envChain, script, rval.address());
} }
template <typename Unit>
static bool Evaluate(JSContext* cx, ScopeKind scopeKind, HandleObject env, static bool Evaluate(JSContext* cx, ScopeKind scopeKind, HandleObject env,
const ReadOnlyCompileOptions& optionsArg, const ReadOnlyCompileOptions& optionsArg,
SourceText<char16_t>& srcBuf, MutableHandleValue rval) { SourceText<Unit>& srcBuf, MutableHandleValue rval) {
CompileOptions options(cx, optionsArg); CompileOptions options(cx, optionsArg);
MOZ_ASSERT(!cx->zone()->isAtomsZone()); MOZ_ASSERT(!cx->zone()->isAtomsZone());
AssertHeapIsIdle(); AssertHeapIsIdle();
@ -548,14 +549,8 @@ static bool Evaluate(JSContext* cx, HandleObjectVector envChain,
extern JS_PUBLIC_API bool JS::EvaluateUtf8( extern JS_PUBLIC_API bool JS::EvaluateUtf8(
JSContext* cx, const ReadOnlyCompileOptions& options, const char* bytes, JSContext* cx, const ReadOnlyCompileOptions& options, const char* bytes,
size_t length, MutableHandle<Value> rval) { size_t length, MutableHandle<Value> rval) {
auto chars = UniqueTwoByteChars( SourceText<Utf8Unit> srcBuf;
UTF8CharsToNewTwoByteCharsZ(cx, UTF8Chars(bytes, length), &length).get()); if (!srcBuf.init(cx, bytes, length, SourceOwnership::Borrowed)) {
if (!chars) {
return false;
}
SourceText<char16_t> srcBuf;
if (!srcBuf.init(cx, std::move(chars), length)) {
return false; return false;
} }
@ -594,7 +589,19 @@ JS_PUBLIC_API bool JS::EvaluateUtf8Path(
CompileOptions options(cx, optionsArg); CompileOptions options(cx, optionsArg);
options.setFileAndLine(filename, 1); options.setFileAndLine(filename, 1);
return EvaluateUtf8(cx, options, auto contents = reinterpret_cast<const char*>(buffer.begin());
reinterpret_cast<const char*>(buffer.begin()), size_t length = buffer.length();
buffer.length(), rval); 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( /* static */ bool PrivateScriptData::InitFromEmitter(
JSContext* cx, js::HandleScript script, frontend::BytecodeEmitter* bce) { JSContext* cx, js::HandleScript script, frontend::BytecodeEmitter* bce) {
uint32_t nscopes = bce->scopeList.length(); uint32_t nscopes = bce->perScriptData().scopeList().length();
uint32_t nconsts = bce->numberList.length(); uint32_t nconsts = bce->perScriptData().numberList().length();
uint32_t nobjects = bce->objectList.length; uint32_t nobjects = bce->perScriptData().objectList().length;
uint32_t ntrynotes = bce->tryNoteList.length(); uint32_t ntrynotes = bce->bytecodeSection().tryNoteList().length();
uint32_t nscopenotes = bce->scopeNoteList.length(); uint32_t nscopenotes = bce->bytecodeSection().scopeNoteList().length();
uint32_t nresumeoffsets = bce->resumeOffsetList.length(); uint32_t nresumeoffsets = bce->bytecodeSection().resumeOffsetList().length();
// Create and initialize PrivateScriptData // Create and initialize PrivateScriptData
if (!JSScript::createPrivateScriptData(cx, script, nscopes, nconsts, nobjects, 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_; js::PrivateScriptData* data = script->data_;
if (nscopes) { if (nscopes) {
bce->scopeList.finish(data->scopes()); bce->perScriptData().scopeList().finish(data->scopes());
} }
if (nconsts) { if (nconsts) {
bce->numberList.finish(data->consts()); bce->perScriptData().numberList().finish(data->consts());
} }
if (nobjects) { if (nobjects) {
bce->objectList.finish(data->objects()); bce->perScriptData().objectList().finish(data->objects());
} }
if (ntrynotes) { if (ntrynotes) {
bce->tryNoteList.finish(data->tryNotes()); bce->bytecodeSection().tryNoteList().finish(data->tryNotes());
} }
if (nscopenotes) { if (nscopenotes) {
bce->scopeNoteList.finish(data->scopeNotes()); bce->bytecodeSection().scopeNoteList().finish(data->scopeNotes());
} }
if (nresumeoffsets) { if (nresumeoffsets) {
bce->resumeOffsetList.finish(data->resumeOffsets()); bce->bytecodeSection().resumeOffsetList().finish(data->resumeOffsets());
} }
return true; return true;
@ -3565,11 +3565,12 @@ bool JSScript::fullyInitFromEmitter(JSContext* cx, HandleScript script,
mozilla::MakeScopeExit([&] { script->freeScriptData(); }); mozilla::MakeScopeExit([&] { script->freeScriptData(); });
/* The counts of indexed things must be checked during code generation. */ /* The counts of indexed things must be checked during code generation. */
MOZ_ASSERT(bce->atomIndices->count() <= INDEX_LIMIT); MOZ_ASSERT(bce->perScriptData().atomIndices()->count() <= INDEX_LIMIT);
MOZ_ASSERT(bce->objectList.length <= INDEX_LIMIT); MOZ_ASSERT(bce->perScriptData().objectList().length <= INDEX_LIMIT);
uint64_t nslots = uint64_t nslots =
bce->maxFixedSlots + static_cast<uint64_t>(bce->maxStackDepth); bce->maxFixedSlots +
static_cast<uint64_t>(bce->bytecodeSection().maxStackDepth());
if (nslots > UINT32_MAX) { if (nslots > UINT32_MAX) {
bce->reportError(nullptr, JSMSG_NEED_DIET, js_script_str); bce->reportError(nullptr, JSMSG_NEED_DIET, js_script_str);
return false; return false;
@ -3581,7 +3582,7 @@ bool JSScript::fullyInitFromEmitter(JSContext* cx, HandleScript script,
script->nfixed_ = bce->maxFixedSlots; script->nfixed_ = bce->maxFixedSlots;
script->nslots_ = nslots; script->nslots_ = nslots;
script->bodyScopeIndex_ = bce->bodyScopeIndex; script->bodyScopeIndex_ = bce->bodyScopeIndex;
script->numBytecodeTypeSets_ = bce->typesetCount; script->numBytecodeTypeSets_ = bce->bytecodeSection().typesetCount();
// Initialize script flags from BytecodeEmitter // Initialize script flags from BytecodeEmitter
script->setFlag(ImmutableFlags::Strict, bce->sc->strict()); 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 // 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 // be stored in the inner function itself. Do this now that compilation is
// complete and can no longer fail. // complete and can no longer fail.
bce->objectList.finishInnerFunctions(); bce->perScriptData().objectList().finishInnerFunctions();
#ifdef JS_STRUCTURED_SPEW #ifdef JS_STRUCTURED_SPEW
// We want this to happen after line number initialization to allow filtering // 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( /* static */ bool SharedScriptData::InitFromEmitter(
JSContext* cx, js::HandleScript script, frontend::BytecodeEmitter* bce) { JSContext* cx, js::HandleScript script, frontend::BytecodeEmitter* bce) {
uint32_t natoms = bce->atomIndices->count(); uint32_t natoms = bce->perScriptData().atomIndices()->count();
uint32_t codeLength = bce->code().length(); uint32_t codeLength = bce->bytecodeSection().code().length();
// The + 1 is to account for the final SN_MAKE_TERMINATOR that is appended // 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. // 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 // Create and initialize SharedScriptData
if (!script->createSharedScriptData(cx, codeLength, noteLength, natoms)) { if (!script->createSharedScriptData(cx, codeLength, noteLength, natoms)) {
@ -4537,9 +4538,9 @@ bool JSScript::hasBreakpointsAt(jsbytecode* pc) {
js::SharedScriptData* data = script->scriptData_; js::SharedScriptData* data = script->scriptData_;
// Initialize trailing arrays // 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); bce->copySrcNotes(data->notes(), noteLength);
InitAtomMap(*bce->atomIndices, data->atoms()); InitAtomMap(*bce->perScriptData().atomIndices(), data->atoms());
return true; return true;
} }

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

@ -307,6 +307,34 @@ const nsTArray<GfxDriverInfo> &GfxInfo::GetGfxDriverInfo() {
GfxDriverInfo::allDevices, GfxDriverInfo::allFeatures, GfxDriverInfo::allDevices, GfxDriverInfo::allFeatures,
nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION, DRIVER_LESS_THAN, nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION, DRIVER_LESS_THAN,
V(13, 15, 100, 1), "FEATURE_FAILURE_OLD_FGLRX", "fglrx 13.15.100.1"); 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; return *sDriverInfo;
} }

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

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