author | Sebastian Hengst <archaeopteryx@coole-files.de> |
Tue, 10 Oct 2017 23:56:11 +0200 | |
changeset 385452 | e897e367d3bd489422d86fbdfac54925c18329d2 |
parent 385451 | f1ecd5c26948c4f62149565efbfcc28abb656fa4 (current diff) |
parent 385309 | fd1fe0931730ae57be8aee0969183be0121e2857 (diff) |
child 385453 | 95824b886c451ae21fa14c3add27c5479bc7381b |
child 385484 | 7f17361b36179c99a5d499a08310f98e2b057968 |
child 385505 | b880d53a30c74f8999c2c215e9555490f8768a99 |
push id | 96005 |
push user | archaeopteryx@coole-files.de |
push date | Tue, 10 Oct 2017 22:02:42 +0000 |
treeherder | mozilla-inbound@95824b886c45 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | merge, merge |
milestone | 58.0a1 |
first release with | nightly linux32
e897e367d3bd
/
58.0a1
/
20171010220102
/
files
nightly linux64
e897e367d3bd
/
58.0a1
/
20171010220102
/
files
nightly mac
e897e367d3bd
/
58.0a1
/
20171010220102
/
files
nightly win32
e897e367d3bd
/
58.0a1
/
20171010220102
/
files
nightly win64
e897e367d3bd
/
58.0a1
/
20171010220102
/
files
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
releases | nightly linux32
58.0a1
/
20171010220102
/
pushlog to previous
nightly linux64
58.0a1
/
20171010220102
/
pushlog to previous
nightly mac
58.0a1
/
20171010220102
/
pushlog to previous
nightly win32
58.0a1
/
20171010220102
/
pushlog to previous
nightly win64
58.0a1
/
20171010220102
/
pushlog to previous
|
--- a/build/moz.configure/toolchain.configure +++ b/build/moz.configure/toolchain.configure @@ -1198,17 +1198,17 @@ def developer_options(value): add_old_configure_assignment('DEVELOPER_OPTIONS', developer_options) set_config('DEVELOPER_OPTIONS', developer_options) # Linker detection # ============================================================== @depends(target) def build_not_win_mac(target): - if target.kernel not in ('Darwin', 'WINNT'): + if target.kernel not in ('Darwin', 'WINNT', 'SunOS'): return True option('--enable-gold', env='MOZ_FORCE_GOLD', help='Enable GNU Gold Linker when it is not already the default', when=build_not_win_mac)
--- a/dom/base/nsRange.cpp +++ b/dom/base/nsRange.cpp @@ -434,16 +434,18 @@ nsRange::RegisterCommonAncestor(nsINode* mRegisteredCommonAncestor = aNode; MarkDescendants(aNode); UniquePtr<LinkedList<nsRange>>& ranges = aNode->GetCommonAncestorRangesPtr(); if (!ranges) { ranges = MakeUnique<LinkedList<nsRange>>(); } + + MOZ_DIAGNOSTIC_ASSERT(!isInList()); ranges->insertBack(this); aNode->SetCommonAncestorForRangeInSelection(); } void nsRange::UnregisterCommonAncestor(nsINode* aNode, bool aIsUnlinking) { NS_PRECONDITION(aNode, "bad arg");
--- a/dom/svg/SVGContentUtils.cpp +++ b/dom/svg/SVGContentUtils.cpp @@ -369,27 +369,31 @@ SVGContentUtils::EstablishesViewport(nsI // Although SVG 1.1 states that <image> is an element that establishes a // viewport, this is really only for the document it references, not // for any child content, which is what this function is used for. return aContent && aContent->IsAnyOfSVGElements(nsGkAtoms::svg, nsGkAtoms::foreignObject, nsGkAtoms::symbol); } -nsSVGElement* -SVGContentUtils::GetNearestViewportElement(nsIContent *aContent) +SVGViewportElement* +SVGContentUtils::GetNearestViewportElement(const nsIContent *aContent) { nsIContent *element = aContent->GetFlattenedTreeParent(); while (element && element->IsSVGElement()) { if (EstablishesViewport(element)) { if (element->IsSVGElement(nsGkAtoms::foreignObject)) { return nullptr; } - return static_cast<nsSVGElement*>(element); + MOZ_ASSERT(element->IsAnyOfSVGElements(nsGkAtoms::svg, + nsGkAtoms::symbol), + "upcoming static_cast is only valid for " + "SVGViewportElement subclasses"); + return static_cast<SVGViewportElement*>(element); } element = element->GetFlattenedTreeParent(); } return nullptr; } static gfx::Matrix GetCTMInternal(nsSVGElement *aElement, bool aScreenCTM, bool aHaveRecursed) @@ -823,17 +827,17 @@ SVGContentUtils::CoordToFloat(nsSVGEleme case eStyleUnit_Factor: // user units return aCoord.GetFactorValue(); case eStyleUnit_Coord: return nsPresContext::AppUnitsToFloatCSSPixels(aCoord.GetCoordValue()); case eStyleUnit_Percent: { - SVGSVGElement* ctx = aContent->GetCtx(); + SVGViewportElement* ctx = aContent->GetCtx(); return ctx ? aCoord.GetPercentValue() * ctx->GetLength(SVGContentUtils::XY) : 0.0f; } default: return 0.0f; } } already_AddRefed<gfx::Path>
--- a/dom/svg/SVGContentUtils.h +++ b/dom/svg/SVGContentUtils.h @@ -27,16 +27,17 @@ class nsSVGElement; namespace mozilla { class nsSVGAnimatedTransformList; class SVGAnimatedPreserveAspectRatio; class SVGContextPaint; class SVGPreserveAspectRatio; namespace dom { class Element; class SVGSVGElement; +class SVGViewportElement; } // namespace dom } // namespace mozilla #define SVG_ZERO_LENGTH_PATH_FIX_FACTOR 512 /** * SVGTransformTypes controls the transforms that PrependLocalTransformsTo @@ -233,18 +234,18 @@ public: Rect* aBounds); /** * Check if this is one of the SVG elements that SVG 1.1 Full says * establishes a viewport: svg, symbol, image or foreignObject. */ static bool EstablishesViewport(nsIContent *aContent); - static nsSVGElement* - GetNearestViewportElement(nsIContent *aContent); + static mozilla::dom::SVGViewportElement* + GetNearestViewportElement(const nsIContent *aContent); /* enum for specifying coordinate direction for ObjectSpace/UserSpace */ enum ctxDirection { X, Y, XY }; /** * Computes sqrt((aWidth^2 + aHeight^2)/2); */ static double ComputeNormalizedHypotenuse(double aWidth, double aHeight);
--- a/dom/svg/SVGLength.cpp +++ b/dom/svg/SVGLength.cpp @@ -168,17 +168,17 @@ SVGLength::GetUserUnitsPerUnit(const nsS return std::numeric_limits<float>::quiet_NaN(); } } /* static */ float SVGLength::GetUserUnitsPerPercent(const nsSVGElement *aElement, uint8_t aAxis) { if (aElement) { - dom::SVGSVGElement *viewportElement = aElement->GetCtx(); + dom::SVGViewportElement *viewportElement = aElement->GetCtx(); if (viewportElement) { return std::max(viewportElement->GetLength(aAxis) / 100.0f, 0.0f); } } return std::numeric_limits<float>::quiet_NaN(); } // Helpers:
--- a/dom/svg/SVGMarkerElement.cpp +++ b/dom/svg/SVGMarkerElement.cpp @@ -245,17 +245,17 @@ SVGMarkerElement::UnsetAttr(int32_t aNam return nsSVGElement::UnsetAttr(aNamespaceID, aName, aNotify); } //---------------------------------------------------------------------- // nsSVGElement methods void -SVGMarkerElement::SetParentCoordCtxProvider(SVGSVGElement *aContext) +SVGMarkerElement::SetParentCoordCtxProvider(SVGViewportElement *aContext) { mCoordCtx = aContext; mViewBoxToViewportTransform = nullptr; } /* virtual */ bool SVGMarkerElement::HasValidDimensions() const {
--- a/dom/svg/SVGMarkerElement.h +++ b/dom/svg/SVGMarkerElement.h @@ -148,17 +148,17 @@ public: void SetOrientToAngle(SVGAngle& angle, ErrorResult& rv); protected: virtual bool ParseAttribute(int32_t aNameSpaceID, nsAtom* aName, const nsAString& aValue, nsAttrValue& aResult) override; - void SetParentCoordCtxProvider(SVGSVGElement *aContext); + void SetParentCoordCtxProvider(SVGViewportElement *aContext); virtual LengthAttributesInfo GetLengthInfo() override; virtual AngleAttributesInfo GetAngleInfo() override; virtual EnumAttributesInfo GetEnumInfo() override; virtual nsSVGViewBox *GetViewBox() override; virtual SVGAnimatedPreserveAspectRatio *GetPreserveAspectRatio() override; enum { REFX, REFY, MARKERWIDTH, MARKERHEIGHT }; @@ -175,16 +175,16 @@ protected: static AngleInfo sAngleInfo[1]; nsSVGViewBox mViewBox; SVGAnimatedPreserveAspectRatio mPreserveAspectRatio; // derived properties (from 'orient') handled separately nsSVGOrientType mOrientType; - SVGSVGElement *mCoordCtx; + SVGViewportElement* mCoordCtx; nsAutoPtr<gfx::Matrix> mViewBoxToViewportTransform; }; } // namespace dom } // namespace mozilla #endif // mozilla_dom_SVGMarkerElement_h
--- a/dom/svg/SVGSVGElement.h +++ b/dom/svg/SVGSVGElement.h @@ -177,25 +177,16 @@ public: int32_t GetIntrinsicWidth(); int32_t GetIntrinsicHeight(); // This services any pending notifications for the transform on on this root // <svg> node needing to be recalculated. (Only applicable in // SVG-as-an-image documents.) virtual void FlushImageTransformInvalidation(); - svgFloatSize GetViewportSize() const { - return svgFloatSize(mViewportWidth, mViewportHeight); - } - - void SetViewportSize(const svgFloatSize& aSize) { - mViewportWidth = aSize.width; - mViewportHeight = aSize.height; - } - private: // SVGViewportElement methods: virtual SVGViewElement* GetCurrentViewElement() const; virtual SVGPreserveAspectRatio GetPreserveAspectRatioWithOverride() const override; // implementation helpers:
--- a/dom/svg/SVGViewportElement.h +++ b/dom/svg/SVGViewportElement.h @@ -122,16 +122,25 @@ public: * The reason we have this method instead of overriding * GetAttributeChangeHint is because we need to act on non-attribute (e.g. * currentScale) changes in addition to attribute (e.g. viewBox) changes. */ void ChildrenOnlyTransformChanged(uint32_t aFlags = 0); gfx::Matrix GetViewBoxTransform() const; + svgFloatSize GetViewportSize() const { + return svgFloatSize(mViewportWidth, mViewportHeight); + } + + void SetViewportSize(const svgFloatSize& aSize) { + mViewportWidth = aSize.width; + mViewportHeight = aSize.height; + } + // WebIDL already_AddRefed<SVGAnimatedRect> ViewBox(); already_AddRefed<DOMSVGAnimatedPreserveAspectRatio> PreserveAspectRatio(); virtual nsSVGViewBox* GetViewBox() override; protected: // implementation helpers:
--- a/dom/svg/nsSVGElement.cpp +++ b/dom/svg/nsSVGElement.cpp @@ -1104,17 +1104,30 @@ nsSVGElement::GetOwnerSVGElement(nsIDOMS { NS_IF_ADDREF(*aOwnerSVGElement = GetOwnerSVGElement()); return NS_OK; } SVGSVGElement* nsSVGElement::GetOwnerSVGElement() { - return GetCtx(); // this may return nullptr + nsIContent* ancestor = GetFlattenedTreeParent(); + + while (ancestor && ancestor->IsSVGElement()) { + if (ancestor->IsSVGElement(nsGkAtoms::foreignObject)) { + return nullptr; + } + if (ancestor->IsSVGElement(nsGkAtoms::svg)) { + return static_cast<SVGSVGElement*>(ancestor); + } + ancestor = ancestor->GetFlattenedTreeParent(); + } + + // we don't have an ancestor <svg> element... + return nullptr; } NS_IMETHODIMP nsSVGElement::GetViewportElement(nsIDOMSVGElement * *aViewportElement) { nsSVGElement* elem = GetViewportElement(); NS_ADDREF(*aViewportElement = elem); return NS_OK; @@ -1540,33 +1553,20 @@ nsAtom* nsSVGElement::GetEventNameForAtt if (aAttr == nsGkAtoms::onrepeat) return nsGkAtoms::onrepeatEvent; if (aAttr == nsGkAtoms::onend) return nsGkAtoms::onendEvent; return aAttr; } -SVGSVGElement * +SVGViewportElement * nsSVGElement::GetCtx() const { - nsIContent* ancestor = GetFlattenedTreeParent(); - - while (ancestor && ancestor->IsSVGElement()) { - if (ancestor->IsSVGElement(nsGkAtoms::foreignObject)) { - return nullptr; - } - if (ancestor->IsSVGElement(nsGkAtoms::svg)) { - return static_cast<SVGSVGElement*>(ancestor); - } - ancestor = ancestor->GetFlattenedTreeParent(); - } - - // we don't have an ancestor <svg> element... - return nullptr; + return SVGContentUtils::GetNearestViewportElement(this); } /* virtual */ gfxMatrix nsSVGElement::PrependLocalTransformsTo( const gfxMatrix &aMatrix, SVGTransformTypes aWhich) const { return aMatrix; } @@ -1655,17 +1655,17 @@ nsSVGElement::GetAnimatedLength(const ns void nsSVGElement::GetAnimatedLengthValues(float *aFirst, ...) { LengthAttributesInfo info = GetLengthInfo(); NS_ASSERTION(info.mLengthCount > 0, "GetAnimatedLengthValues on element with no length attribs"); - SVGSVGElement *ctx = nullptr; + SVGViewportElement *ctx = nullptr; float *f = aFirst; uint32_t i = 0; va_list args; va_start(args, aFirst); while (f && i < info.mLengthCount) {
--- a/dom/svg/nsSVGElement.h +++ b/dom/svg/nsSVGElement.h @@ -39,16 +39,17 @@ class nsSVGNumberPair; class nsSVGString; class nsSVGViewBox; namespace mozilla { class DeclarationBlock; namespace dom { class SVGSVGElement; +class SVGViewportElement; static const unsigned short SVG_UNIT_TYPE_UNKNOWN = 0; static const unsigned short SVG_UNIT_TYPE_USERSPACEONUSE = 1; static const unsigned short SVG_UNIT_TYPE_OBJECTBOUNDINGBOX = 2; } // namespace dom class SVGAnimatedNumberList; @@ -140,17 +141,17 @@ public: NS_FORWARD_NSIDOMELEMENT_TO_GENERIC NS_DECL_NSIDOMSVGELEMENT NS_IMPL_FROMCONTENT(nsSVGElement, kNameSpaceID_SVG) // Gets the element that establishes the rectangular viewport against which // we should resolve percentage lengths (our "coordinate context"). Returns // nullptr for outer <svg> or SVG without an <svg> parent (invalid SVG). - mozilla::dom::SVGSVGElement* GetCtx() const; + mozilla::dom::SVGViewportElement* GetCtx() const; /** * Returns aMatrix pre-multiplied by (explicit or implicit) transforms that * are introduced by attributes on this element. * * If aWhich is eAllTransforms, then all the transforms from the coordinate * space established by this element for its children to the coordinate * space established by this element's parent element for this element, are
--- a/editor/libeditor/HTMLEditRules.cpp +++ b/editor/libeditor/HTMLEditRules.cpp @@ -3800,33 +3800,36 @@ HTMLEditRules::WillCSSIndent(Selection* rv = aSelection->Collapse(theBlock, 0); // Don't restore the selection selectionRestorer.Abort(); return rv; } // Ok, now go through all the nodes and put them in a blockquote, // or whatever is appropriate. Wohoo! - nsCOMPtr<nsINode> curParent; nsCOMPtr<Element> curList, curQuote; nsCOMPtr<nsIContent> sibling; int32_t listCount = arrayOfNodes.Length(); for (int32_t i = 0; i < listCount; i++) { // here's where we actually figure out what to do NS_ENSURE_STATE(arrayOfNodes[i]->IsContent()); nsCOMPtr<nsIContent> curNode = arrayOfNodes[i]->AsContent(); // Ignore all non-editable nodes. Leave them be. NS_ENSURE_STATE(mHTMLEditor); if (!mHTMLEditor->IsEditable(curNode)) { continue; } - curParent = curNode->GetParentNode(); - int32_t offset = curParent ? curParent->IndexOf(curNode) : -1; + int32_t offset; + nsCOMPtr<nsINode> curParent = + EditorBase::GetNodeLocation(curNode, &offset); + if (!curParent) { + continue; + } // some logic for putting list items into nested lists... if (HTMLEditUtils::IsList(curParent)) { sibling = nullptr; // Check for whether we should join a list that follows curNode. // We do this if the next element is a list, and the list is of the // same type (li/ol) as curNode was a part it. @@ -3987,33 +3990,35 @@ HTMLEditRules::WillHTMLIndent(Selection* rv = aSelection->Collapse(theBlock, 0); // Don't restore the selection selectionRestorer.Abort(); return rv; } // Ok, now go through all the nodes and put them in a blockquote, // or whatever is appropriate. Wohoo! - nsCOMPtr<nsINode> curParent; nsCOMPtr<nsIContent> sibling; nsCOMPtr<Element> curList, curQuote, indentedLI; int32_t listCount = arrayOfNodes.Length(); for (int32_t i = 0; i < listCount; i++) { // here's where we actually figure out what to do NS_ENSURE_STATE(arrayOfNodes[i]->IsContent()); nsCOMPtr<nsIContent> curNode = arrayOfNodes[i]->AsContent(); // Ignore all non-editable nodes. Leave them be. NS_ENSURE_STATE(mHTMLEditor); if (!mHTMLEditor->IsEditable(curNode)) { continue; } - curParent = curNode->GetParentNode(); - int32_t offset = curParent ? curParent->IndexOf(curNode) : -1; + int32_t offset; + nsCOMPtr<nsINode> curParent = EditorBase::GetNodeLocation(curNode, &offset); + if (!curParent) { + continue; + } // some logic for putting list items into nested lists... if (HTMLEditUtils::IsList(curParent)) { sibling = nullptr; // Check for whether we should join a list that follows curNode. // We do this if the next element is a list, and the list is of the // same type (li/ol) as curNode was a part it. @@ -4793,18 +4798,21 @@ HTMLEditRules::WillAlign(Selection& aSel if (HTMLEditUtils::SupportsAlignAttr(*curNode)) { rv = AlignBlock(*curNode->AsElement(), aAlignType, ContentsOnly::no); NS_ENSURE_SUCCESS(rv, rv); // Clear out curDiv so that we don't put nodes after this one into it curDiv = nullptr; continue; } - nsCOMPtr<nsINode> curParent = curNode->GetParentNode(); - int32_t offset = curParent ? curParent->IndexOf(curNode) : -1; + int32_t offset; + nsCOMPtr<nsINode> curParent = EditorBase::GetNodeLocation(curNode, &offset); + if (!curParent) { + continue; + } // Skip insignificant formatting text nodes to prevent unnecessary // structure splitting! bool isEmptyTextNode = false; if (curNode->GetAsText() && ((HTMLEditUtils::IsTableElement(curParent) && !HTMLEditUtils::IsTableCellOrCaption(*curParent)) || HTMLEditUtils::IsList(curParent) || @@ -8783,18 +8791,21 @@ HTMLEditRules::WillAbsolutePosition(Sele // Ignore all non-editable nodes. Leave them be. if (!htmlEditor->IsEditable(curNode)) { continue; } nsCOMPtr<nsIContent> sibling; - nsCOMPtr<nsINode> curParent = curNode->GetParentNode(); - int32_t offset = curParent ? curParent->IndexOf(curNode) : -1; + int32_t offset; + nsCOMPtr<nsINode> curParent = EditorBase::GetNodeLocation(curNode, &offset); + if (!curParent) { + continue; + } // Some logic for putting list items into nested lists... if (HTMLEditUtils::IsList(curParent)) { // Check to see if curList is still appropriate. Which it is if curNode // is still right after it in the same list. if (curList) { sibling = htmlEditor->GetPriorHTMLSibling(curNode); }
new file mode 100644 --- /dev/null +++ b/editor/libeditor/crashtests/1402904.html @@ -0,0 +1,31 @@ +<script> +function jsfuzzer() { + var option = document.getElementById("option"); + option.addEventListener("click", () => { + document.execCommand("forwardDelete", false); + }); + var li2 = document.getElementById("li2"); + li2.addEventListener("DOMNodeInserted", () => { + option.click(); + }); + var select = document.getElementById("select"); + select.parentElement.setAttribute("onpageshow", "onPageShow()"); +} + +function onPageShow() { + var li1 = document.getElementById("li1"); + li1.addEventListener("DOMSubtreeModified", () => { + document.execCommand("selectAll", false); + document.execCommand("indent", false); + }); + li1.appendChild(document.createElement("legend")); +} +</script> +<body onload=jsfuzzer()> +<select id="select"> +<option id="option"></option> +</select> +<li id="li1"></li> +<ul contenteditable="true"> +<li id="li2"></li> +<embed>a;#2
new file mode 100644 --- /dev/null +++ b/editor/libeditor/crashtests/1405747.html @@ -0,0 +1,15 @@ +<script> +function jsfuzzer() { +try { htmlvar00017.addEventListener("DOMSubtreeModified", eventhandler5); } catch(e) { } +try { htmlvar00017.align = ""; } catch(e) { } +} +function eventhandler5() { +try { document.execCommand("selectAll", false); } catch(e) { } +try { document.execCommand("justifyCenter", false); } catch(e) { } +try { document.execCommand("forwardDelete", false); } catch(e) { } +} +</script> +<body onload=jsfuzzer()> +<table contenteditable=""> +<th id="htmlvar00017"></th> +<colgroup> \ No newline at end of file
--- a/editor/libeditor/crashtests/crashtests.list +++ b/editor/libeditor/crashtests/crashtests.list @@ -76,8 +76,10 @@ needs-focus load 1343918.html load 1345015.html load 1348851.html load 1350772.html load 1366176.html load 1375131.html load 1381541.html load 1383755.html load 1402469.html +load 1402904.html +load 1405747.html
--- a/gfx/layers/D3D11ShareHandleImage.cpp +++ b/gfx/layers/D3D11ShareHandleImage.cpp @@ -123,16 +123,17 @@ D3D11ShareHandleImage::GetAsSourceSurfac if (FAILED(hr)) { NS_WARNING("Failed to create 2D staging texture."); return nullptr; } RefPtr<ID3D11DeviceContext> context; device->GetImmediateContext(getter_AddRefs(context)); if (!context) { + gfxCriticalError() << "Failed to get immediate context."; return nullptr; } RefPtr<IDXGIKeyedMutex> mutex; hr = texture->QueryInterface((IDXGIKeyedMutex**)getter_AddRefs(mutex)); if (SUCCEEDED(hr) && mutex) { hr = mutex->AcquireSync(0, 2000);
--- a/gfx/layers/D3D11YCbCrImage.cpp +++ b/gfx/layers/D3D11YCbCrImage.cpp @@ -68,16 +68,20 @@ D3D11YCbCrImage::SetData(KnowsCompositor gfxCriticalError() << "Device used not marked as multithread-safe."; return false; } D3D11MTAutoEnter mtAutoEnter(mt.forget()); RefPtr<ID3D11DeviceContext> ctx; allocator->GetDevice()->GetImmediateContext(getter_AddRefs(ctx)); + if (!ctx) { + gfxCriticalError() << "Failed to get immediate context."; + return false; + } AutoLockD3D11Texture lockY(textureY); AutoLockD3D11Texture lockCb(textureCb); AutoLockD3D11Texture lockCr(textureCr); ctx->UpdateSubresource(textureY, 0, nullptr, @@ -184,16 +188,20 @@ D3D11YCbCrImage::GetAsSourceSurface() desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; desc.Usage = D3D11_USAGE_STAGING; dev->CreateTexture2D(&desc, nullptr, getter_AddRefs(softTexCb)); dev->CreateTexture2D(&desc, nullptr, getter_AddRefs(softTexCr)); RefPtr<ID3D11DeviceContext> ctx; dev->GetImmediateContext(getter_AddRefs(ctx)); + if (!ctx) { + gfxCriticalError() << "Failed to get immediate context."; + return nullptr; + } { AutoLockD3D11Texture lockY(texY); AutoLockD3D11Texture lockCb(texCb); AutoLockD3D11Texture lockCr(texCr); ctx->CopyResource(softTexY, texY); ctx->CopyResource(softTexCb, texCb); ctx->CopyResource(softTexCr, texCr);
--- a/js/public/Utility.h +++ b/js/public/Utility.h @@ -62,16 +62,17 @@ enum ThreadType { THREAD_TYPE_ION, // 3 THREAD_TYPE_PARSE, // 4 THREAD_TYPE_COMPRESS, // 5 THREAD_TYPE_GCHELPER, // 6 THREAD_TYPE_GCPARALLEL, // 7 THREAD_TYPE_PROMISE_TASK, // 8 THREAD_TYPE_ION_FREE, // 9 THREAD_TYPE_WASM_TIER2, // 10 + THREAD_TYPE_WORKER, // 11 THREAD_TYPE_MAX // Used to check shell function arguments }; namespace oom { /* * Theads are tagged only in certain debug contexts. Notably, to make testing * OOM in certain helper threads more effective, we allow restricting the OOM
--- a/js/src/builtin/TestingFunctions.cpp +++ b/js/src/builtin/TestingFunctions.cpp @@ -1439,16 +1439,27 @@ static bool OOMThreadTypes(JSContext* cx, unsigned argc, Value* vp) { CallArgs args = CallArgsFromVp(argc, vp); args.rval().setInt32(js::THREAD_TYPE_MAX); return true; } static bool +CheckCanSimulateOOM(JSContext* cx) +{ + if (js::oom::GetThreadType() != js::THREAD_TYPE_COOPERATING) { + JS_ReportErrorASCII(cx, "Simulated OOM failure is only supported on the main thread"); + return false; + } + + return true; +} + +static bool SetupOOMFailure(JSContext* cx, bool failAlways, unsigned argc, Value* vp) { CallArgs args = CallArgsFromVp(argc, vp); if (disableOOMFunctions) { args.rval().setUndefined(); return true; } @@ -1476,16 +1487,19 @@ SetupOOMFailure(JSContext* cx, bool fail if (args.length() > 1 && !ToUint32(cx, args[1], &targetThread)) return false; if (targetThread == js::THREAD_TYPE_NONE || targetThread >= js::THREAD_TYPE_MAX) { JS_ReportErrorASCII(cx, "Invalid thread type specified"); return false; } + if (!CheckCanSimulateOOM(cx)) + return false; + js::oom::SimulateOOMAfter(count, targetThread, failAlways); args.rval().setUndefined(); return true; } static bool OOMAfterAllocations(JSContext* cx, unsigned argc, Value* vp) { @@ -1497,16 +1511,20 @@ OOMAtAllocation(JSContext* cx, unsigned { return SetupOOMFailure(cx, false, argc, vp); } static bool ResetOOMFailure(JSContext* cx, unsigned argc, Value* vp) { CallArgs args = CallArgsFromVp(argc, vp); + + if (!CheckCanSimulateOOM(cx)) + return false; + args.rval().setBoolean(js::oom::HadSimulatedOOM()); js::oom::ResetSimulatedOOM(); return true; } static size_t CountCompartments(JSContext* cx) { @@ -1532,16 +1550,19 @@ OOMTest(JSContext* cx, unsigned argc, Va return false; } if (args.length() == 2 && !args[1].isBoolean()) { JS_ReportErrorASCII(cx, "The optional second argument to oomTest() must be a boolean."); return false; } + if (!CheckCanSimulateOOM(cx)) + return false; + bool expectExceptionOnFailure = true; if (args.length() == 2) expectExceptionOnFailure = args[1].toBoolean(); // There are some places where we do fail without raising an exception, so // we can't expose this to the fuzzers by default. if (fuzzingSafe) expectExceptionOnFailure = false; @@ -4236,20 +4257,18 @@ SetRNGState(JSContext* cx, unsigned argc cx->compartment()->randomNumberGenerator.ref().setState(seed0, seed1); args.rval().setUndefined(); return true; } #endif static ModuleEnvironmentObject* -GetModuleEnvironment(JSContext* cx, HandleValue moduleValue) +GetModuleEnvironment(JSContext* cx, HandleModuleObject module) { - RootedModuleObject module(cx, &moduleValue.toObject().as<ModuleObject>()); - // Use the initial environment so that tests can check bindings exists // before they have been instantiated. RootedModuleEnvironmentObject env(cx, &module->initialEnvironment()); MOZ_ASSERT(env); MOZ_ASSERT_IF(module->environment(), module->environment() == env); return env; } @@ -4263,17 +4282,23 @@ GetModuleEnvironmentNames(JSContext* cx, return false; } if (!args[0].isObject() || !args[0].toObject().is<ModuleObject>()) { JS_ReportErrorASCII(cx, "First argument should be a ModuleObject"); return false; } - RootedModuleEnvironmentObject env(cx, GetModuleEnvironment(cx, args[0])); + RootedModuleObject module(cx, &args[0].toObject().as<ModuleObject>()); + if (module->status() == MODULE_STATUS_ERRORED) { + JS_ReportErrorASCII(cx, "Module environment unavailable"); + return false; + } + + RootedModuleEnvironmentObject env(cx, GetModuleEnvironment(cx, module)); Rooted<IdVector> ids(cx, IdVector(cx)); if (!JS_Enumerate(cx, env, &ids)) return false; uint32_t length = ids.length(); RootedArrayObject array(cx, NewDenseFullyAllocatedArray(cx, length)); if (!array) return false; @@ -4300,17 +4325,23 @@ GetModuleEnvironmentValue(JSContext* cx, return false; } if (!args[1].isString()) { JS_ReportErrorASCII(cx, "Second argument should be a string"); return false; } - RootedModuleEnvironmentObject env(cx, GetModuleEnvironment(cx, args[0])); + RootedModuleObject module(cx, &args[0].toObject().as<ModuleObject>()); + if (module->status() == MODULE_STATUS_ERRORED) { + JS_ReportErrorASCII(cx, "Module environment unavailable"); + return false; + } + + RootedModuleEnvironmentObject env(cx, GetModuleEnvironment(cx, module)); RootedString name(cx, args[1].toString()); RootedId id(cx); if (!JS_StringToId(cx, name, &id)) return false; if (!GetProperty(cx, env, env, id, args.rval())) return false;
--- a/js/src/gc/GCRuntime.h +++ b/js/src/gc/GCRuntime.h @@ -928,18 +928,19 @@ class GCRuntime ChunkPool& fullChunks(const AutoLockGC& lock) { return fullChunks_.ref(); } ChunkPool& availableChunks(const AutoLockGC& lock) { return availableChunks_.ref(); } ChunkPool& emptyChunks(const AutoLockGC& lock) { return emptyChunks_.ref(); } const ChunkPool& fullChunks(const AutoLockGC& lock) const { return fullChunks_.ref(); } const ChunkPool& availableChunks(const AutoLockGC& lock) const { return availableChunks_.ref(); } const ChunkPool& emptyChunks(const AutoLockGC& lock) const { return emptyChunks_.ref(); } typedef ChainedIter<Chunk*, ChunkPool::Iter, ChunkPool::Iter> NonEmptyChunksIter; - NonEmptyChunksIter allNonEmptyChunks() { - return NonEmptyChunksIter(ChunkPool::Iter(availableChunks_.ref()), ChunkPool::Iter(fullChunks_.ref())); + NonEmptyChunksIter allNonEmptyChunks(const AutoLockGC& lock) { + return NonEmptyChunksIter(ChunkPool::Iter(availableChunks(lock)), + ChunkPool::Iter(fullChunks(lock))); } Chunk* getOrAllocChunk(const AutoLockGC& lock, AutoMaybeStartBackgroundAllocation& maybeStartBGAlloc); void recycleChunk(Chunk* chunk, const AutoLockGC& lock); #ifdef JS_GC_ZEAL void startVerifyPreBarriers(); @@ -1181,21 +1182,21 @@ class GCRuntime GCLockData<ChunkPool> emptyChunks_; // Chunks which have had some, but not all, of their arenas allocated live // in the available chunk lists. When all available arenas in a chunk have // been allocated, the chunk is removed from the available list and moved // to the fullChunks pool. During a GC, if all arenas are free, the chunk // is moved back to the emptyChunks pool and scheduled for eventual // release. - UnprotectedData<ChunkPool> availableChunks_; + GCLockData<ChunkPool> availableChunks_; // When all arenas in a chunk are used, it is moved to the fullChunks pool // so as to reduce the cost of operations on the available lists. - UnprotectedData<ChunkPool> fullChunks_; + GCLockData<ChunkPool> fullChunks_; ActiveThreadData<RootedValueMap> rootsHash; // An incrementing id used to assign unique ids to cells that require one. mozilla::Atomic<uint64_t, mozilla::ReleaseAcquire> nextCellUniqueId_; /* * Number of the committed arenas in all GC chunks including empty chunks.
--- a/js/src/gc/Iteration.cpp +++ b/js/src/gc/Iteration.cpp @@ -70,18 +70,19 @@ js::IterateHeapUnbarrieredForZone(JSCont IterateCompartmentsArenasCellsUnbarriered(cx, zone, data, compartmentCallback, arenaCallback, cellCallback); } void js::IterateChunks(JSContext* cx, void* data, IterateChunkCallback chunkCallback) { AutoPrepareForTracing prep(cx, SkipAtoms); + AutoLockGC lock(cx->runtime()); - for (auto chunk = cx->runtime()->gc.allNonEmptyChunks(); !chunk.done(); chunk.next()) + for (auto chunk = cx->runtime()->gc.allNonEmptyChunks(lock); !chunk.done(); chunk.next()) chunkCallback(cx->runtime(), data, chunk); } void js::IterateScripts(JSContext* cx, JSCompartment* compartment, void* data, IterateScriptCallback scriptCallback) { MOZ_ASSERT(!cx->suppressGC);
--- a/js/src/gc/Verifier.cpp +++ b/js/src/gc/Verifier.cpp @@ -189,20 +189,24 @@ gc::GCRuntime::startVerifyPreBarriers() } number++; VerifyPreTracer* trc = js_new<VerifyPreTracer>(rt); if (!trc) return; - AutoPrepareForTracing prep(TlsContext.get(), WithAtoms); + JSContext* cx = TlsContext.get(); + AutoPrepareForTracing prep(cx, WithAtoms); - for (auto chunk = allNonEmptyChunks(); !chunk.done(); chunk.next()) - chunk->bitmap.clear(); + { + AutoLockGC lock(cx->runtime()); + for (auto chunk = allNonEmptyChunks(lock); !chunk.done(); chunk.next()) + chunk->bitmap.clear(); + } gcstats::AutoPhase ap(stats(), gcstats::PhaseKind::TRACE_HEAP); const size_t size = 64 * 1024 * 1024; trc->root = (VerifyNode*)js_malloc(size); if (!trc->root) goto oom; trc->edgeptr = (char*)trc->root;
new file mode 100644 --- /dev/null +++ b/js/src/jit-test/tests/modules/bug-1406452.js @@ -0,0 +1,5 @@ +// |jit-test| error: Error +let m = parseModule(`for (var x of iterator) {}`); +m.declarationInstantiation(); +try { m.evaluation(); } catch (e) {} +getModuleEnvironmentValue(m, "r");
--- a/js/src/jit/BaselineBailouts.cpp +++ b/js/src/jit/BaselineBailouts.cpp @@ -389,23 +389,23 @@ struct BaselineStackBuilder #elif defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64) || \ defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64) || \ defined(JS_CODEGEN_X64) // On X64, ARM, ARM64, and MIPS, the frame pointer save location depends on // the caller of the rectifier frame. BufferPointer<RectifierFrameLayout> priorFrame = pointerAtStackOffset<RectifierFrameLayout>(priorOffset); FrameType priorType = priorFrame->prevType(); - MOZ_ASSERT(priorType == JitFrame_WasmToJSJit || + MOZ_ASSERT(JSJitFrameIter::isEntry(priorType) || priorType == JitFrame_IonJS || priorType == JitFrame_BaselineStub); - // If the frame preceding the rectifier is an IonJS or WasmToJSJit - // entry frame, then once again the frame pointer does not matter. - if (priorType == JitFrame_IonJS || priorType == JitFrame_WasmToJSJit) + // If the frame preceding the rectifier is an IonJS or entry frame, + // then once again the frame pointer does not matter. + if (priorType == JitFrame_IonJS || JSJitFrameIter::isEntry(priorType)) return nullptr; // Otherwise, the frame preceding the rectifier is a BaselineStub frame. // let X = STACK_START_ADDR + JitFrameLayout::Size() + PREV_FRAME_SIZE // X + RectifierFrameLayout::Size() // + ((RectifierFrameLayout*) X)->prevFrameLocalSize() // - BaselineStubFrameLayout::reverseOffsetOfSavedFramePtr() size_t extraOffset = RectifierFrameLayout::Size() + priorFrame->prevFrameLocalSize() +
--- a/js/src/jit/BaselineJIT.cpp +++ b/js/src/jit/BaselineJIT.cpp @@ -188,19 +188,17 @@ EnterBaseline(JSContext* cx, EnterJitDat JitExecStatus jit::EnterBaselineMethod(JSContext* cx, RunState& state) { BaselineScript* baseline = state.script()->baselineScript(); EnterJitData data(cx); data.jitcode = baseline->method()->raw(); - Rooted<GCVector<Value>> vals(cx, GCVector<Value>(cx)); - if (!SetEnterJitData(cx, data, state, &vals)) - return JitExec_Error; + SetEnterJitData(cx, data, state); JitExecStatus status = EnterBaseline(cx, data); if (status != JitExec_Ok) return status; state.setReturnValue(data.result); return JitExec_Ok; }
--- a/js/src/jit/Ion.cpp +++ b/js/src/jit/Ion.cpp @@ -2801,94 +2801,63 @@ EnterIon(JSContext* cx, EnterJitData& da // Release temporary buffer used for OSR into Ion. cx->freeOsrTempData(); MOZ_ASSERT_IF(data.result.isMagic(), data.result.isMagic(JS_ION_ERROR)); return data.result.isMagic() ? JitExec_Error : JitExec_Ok; } -bool -jit::SetEnterJitData(JSContext* cx, EnterJitData& data, RunState& state, - MutableHandle<GCVector<Value>> vals) +void +jit::SetEnterJitData(JSContext* cx, EnterJitData& data, RunState& state) { data.osrFrame = nullptr; // Note: keep this in sync with EnterBaselineAtBranch. if (state.isInvoke()) { const CallArgs& args = state.asInvoke()->args(); unsigned numFormals = state.script()->functionNonDelazifying()->nargs(); data.constructing = state.asInvoke()->constructing(); data.numActualArgs = args.length(); - data.maxArgc = Max(args.length(), numFormals) + 1; + data.maxArgc = args.length() + 1; + data.maxArgv = args.array() - 1; // -1 to include |this| data.envChain = nullptr; data.calleeToken = CalleeToToken(&args.callee().as<JSFunction>(), data.constructing); - - if (data.numActualArgs >= numFormals) { - data.maxArgv = args.array() - 1; // -1 to include |this| - } else { - MOZ_ASSERT(vals.empty()); - unsigned numPushedArgs = Max(args.length(), numFormals); - if (!vals.reserve(numPushedArgs + 1 + data.constructing)) - return false; - - // Append |this| and any provided arguments. - for (size_t i = 1; i < args.length() + 2; ++i) - vals.infallibleAppend(args.base()[i]); - - // Pad missing arguments with |undefined|. - while (vals.length() < numFormals + 1) - vals.infallibleAppend(UndefinedValue()); - - if (data.constructing) - vals.infallibleAppend(args.newTarget()); - - MOZ_ASSERT(vals.length() >= numFormals + 1 + data.constructing); - data.maxArgv = vals.begin(); - } + if (numFormals > data.numActualArgs) + data.jitcode = cx->runtime()->jitRuntime()->getArgumentsRectifier()->raw(); } else { data.constructing = false; data.numActualArgs = 0; - data.maxArgc = 0; - data.maxArgv = nullptr; data.envChain = state.asExecute()->environmentChain(); - data.calleeToken = CalleeToToken(state.script()); - if (state.script()->isForEval() && state.script()->isDirectEvalInFunction()) { - // Push newTarget onto the stack. - if (!vals.reserve(1)) - return false; - - data.maxArgc = 1; - data.maxArgv = vals.begin(); + if (state.script()->isDirectEvalInFunction()) { if (state.asExecute()->newTarget().isNull()) { ScriptFrameIter iter(cx); - vals.infallibleAppend(iter.newTarget()); - } else { - vals.infallibleAppend(state.asExecute()->newTarget()); + state.asExecute()->setNewTarget(iter.newTarget()); } + data.maxArgc = 1; + data.maxArgv = state.asExecute()->addressOfNewTarget(); + } else { + data.maxArgc = 0; + data.maxArgv = nullptr; } } - - return true; } JitExecStatus jit::IonCannon(JSContext* cx, RunState& state) { IonScript* ion = state.script()->ionScript(); EnterJitData data(cx); data.jitcode = ion->method()->raw(); - Rooted<GCVector<Value>> vals(cx, GCVector<Value>(cx)); - if (!SetEnterJitData(cx, data, state, &vals)) - return JitExec_Error; + SetEnterJitData(cx, data, state); JitExecStatus status = EnterIon(cx, data); if (status == JitExec_Ok) state.setReturnValue(data.result); return status; }
--- a/js/src/jit/Ion.h +++ b/js/src/jit/Ion.h @@ -120,18 +120,17 @@ enum JitExecStatus static inline bool IsErrorStatus(JitExecStatus status) { return status == JitExec_Error || status == JitExec_Aborted; } struct EnterJitData; -MOZ_MUST_USE bool SetEnterJitData(JSContext* cx, EnterJitData& data, RunState& state, - MutableHandle<GCVector<Value>> vals); +void SetEnterJitData(JSContext* cx, EnterJitData& data, RunState& state); JitExecStatus IonCannon(JSContext* cx, RunState& state); // Walk the stack and invalidate active Ion frames for the invalid scripts. void Invalidate(TypeZone& types, FreeOp* fop, const RecompileInfoVector& invalid, bool resetUses = true, bool cancelOffThread = true); void Invalidate(JSContext* cx, const RecompileInfoVector& invalid, bool resetUses = true,
--- a/js/src/jit/JSJitFrameIter.cpp +++ b/js/src/jit/JSJitFrameIter.cpp @@ -650,16 +650,26 @@ JSJitProfilingFrameIterator::moveToWasmF // pass a wasm iterator the correct value of FP. returnAddressToFp_ = nullptr; fp_ = GetPreviousRawFrame<uint8_t*>(frame); type_ = JitFrame_WasmToJSJit; MOZ_ASSERT(!done()); } void +JSJitProfilingFrameIterator::moveToCppEntryFrame() +{ + // No previous frame, set to nullptr to indicate that + // JSJitProfilingFrameIterator is done(). + returnAddressToFp_ = nullptr; + fp_ = nullptr; + type_ = JitFrame_CppToJSJit; +} + +void JSJitProfilingFrameIterator::moveToNextFrame(CommonFrameLayout* frame) { /* * fp_ points to a Baseline or Ion frame. The possible call-stacks * patterns occurring between this frame and a previous Ion or Baseline * frame are as follows: * * <Baseline-Or-Ion> @@ -674,16 +684,18 @@ JSJitProfilingFrameIterator::moveToNextF * ^--- Argument Rectifier * | ^ * | | * | ^--- Ion * | | * | ^--- Baseline Stub <---- Baseline * | | * | ^--- WasmToJSJit <--- (other wasm frames) + * | | + * | ^--- CppToJSJit * | * ^--- Entry Frame (From C++) * Exit Frame (From previous JitActivation) * ^ * | * ^--- Ion * | * ^--- Baseline @@ -739,16 +751,21 @@ JSJitProfilingFrameIterator::moveToNextF return; } if (rectPrevType == JitFrame_WasmToJSJit) { moveToWasmFrame(rectFrame); return; } + if (rectPrevType == JitFrame_CppToJSJit) { + moveToCppEntryFrame(); + return; + } + MOZ_CRASH("Bad frame type prior to rectifier frame."); } if (prevType == JitFrame_IonICCall) { IonICCallFrameLayout* callFrame = GetPreviousRawFrame<IonICCallFrameLayout*>(frame); MOZ_ASSERT(callFrame->prevType() == JitFrame_IonJS); @@ -760,18 +777,14 @@ JSJitProfilingFrameIterator::moveToNextF } if (prevType == JitFrame_WasmToJSJit) { moveToWasmFrame(frame); return; } if (prevType == JitFrame_CppToJSJit) { - // No previous frame, set to null to indicate that - // JSJitProfilingFrameIterator is done(). - returnAddressToFp_ = nullptr; - fp_ = nullptr; - type_ = JitFrame_CppToJSJit; + moveToCppEntryFrame(); return; } MOZ_CRASH("Bad frame type."); }
--- a/js/src/jit/JSJitFrameIter.h +++ b/js/src/jit/JSJitFrameIter.h @@ -292,16 +292,17 @@ class JSJitProfilingFrameIterator inline JitFrameLayout* framePtr(); inline JSScript* frameScript(); MOZ_MUST_USE bool tryInitWithPC(void* pc); MOZ_MUST_USE bool tryInitWithTable(JitcodeGlobalTable* table, void* pc, JSRuntime* rt, bool forLastCallSite); void fixBaselineReturnAddress(); + void moveToCppEntryFrame(); void moveToWasmFrame(CommonFrameLayout* frame); void moveToNextFrame(CommonFrameLayout* frame); public: JSJitProfilingFrameIterator(JSContext* cx, const JS::ProfilingFrameIterator::RegisterState& state); explicit JSJitProfilingFrameIterator(void* exitFrame);
--- a/js/src/jit/MacroAssembler.cpp +++ b/js/src/jit/MacroAssembler.cpp @@ -1659,16 +1659,17 @@ MacroAssembler::assertRectifierFramePare { #ifdef DEBUG { // Check the possible previous frame types here. Label checkOk; branch32(Assembler::Equal, frameType, Imm32(JitFrame_IonJS), &checkOk); branch32(Assembler::Equal, frameType, Imm32(JitFrame_BaselineStub), &checkOk); branch32(Assembler::Equal, frameType, Imm32(JitFrame_WasmToJSJit), &checkOk); + branch32(Assembler::Equal, frameType, Imm32(JitFrame_CppToJSJit), &checkOk); assumeUnreachable("Unrecognized frame type preceding RectifierFrame."); bind(&checkOk); } #endif } void MacroAssembler::loadBaselineOrIonRaw(Register script, Register dest, Label* failure)
--- a/js/src/jit/Registers.h +++ b/js/src/jit/Registers.h @@ -130,17 +130,18 @@ Register::LiveAsIndexableSet<RegTypeName } template <> inline Register::SetType Register::AllocatableAsIndexableSet<RegTypeName::GPR>(SetType set) { return set; } -#if defined(JS_NUNBOX32) +#if JS_BITS_PER_WORD == 32 +// Note, some platform code depends on INT64LOW_OFFSET being zero. static const uint32_t INT64LOW_OFFSET = 0 * sizeof(int32_t); static const uint32_t INT64HIGH_OFFSET = 1 * sizeof(int32_t); #endif struct Register64 { #ifdef JS_PUNBOX64 Register reg;
--- a/js/src/jit/arm/MacroAssembler-arm.h +++ b/js/src/jit/arm/MacroAssembler-arm.h @@ -1003,19 +1003,18 @@ class MacroAssemblerARMCompat : public M void load16ZeroExtend(const Address& address, Register dest); void load16ZeroExtend(const BaseIndex& src, Register dest); void load32(const Address& address, Register dest); void load32(const BaseIndex& address, Register dest); void load32(AbsoluteAddress address, Register dest); void load64(const Address& address, Register64 dest) { - load32(Address(address.base, address.offset + INT64LOW_OFFSET), dest.low); - int32_t highOffset = (address.offset < 0) ? -int32_t(INT64HIGH_OFFSET) : INT64HIGH_OFFSET; - load32(Address(address.base, address.offset + highOffset), dest.high); + load32(LowWord(address), dest.low); + load32(HighWord(address), dest.high); } void loadPtr(const Address& address, Register dest); void loadPtr(const BaseIndex& src, Register dest); void loadPtr(AbsoluteAddress address, Register dest); void loadPtr(wasm::SymbolicAddress address, Register dest); void loadPrivate(const Address& address, Register dest); @@ -1075,23 +1074,23 @@ class MacroAssemblerARMCompat : public M void store32(Register src, AbsoluteAddress address); void store32(Register src, const Address& address); void store32(Register src, const BaseIndex& address); void store32(Imm32 src, const Address& address); void store32(Imm32 src, const BaseIndex& address); void store64(Register64 src, Address address) { - store32(src.low, Address(address.base, address.offset + INT64LOW_OFFSET)); - store32(src.high, Address(address.base, address.offset + INT64HIGH_OFFSET)); + store32(src.low, LowWord(address)); + store32(src.high, HighWord(address)); } void store64(Imm64 imm, Address address) { - store32(imm.low(), Address(address.base, address.offset + INT64LOW_OFFSET)); - store32(imm.hi(), Address(address.base, address.offset + INT64HIGH_OFFSET)); + store32(imm.low(), LowWord(address)); + store32(imm.hi(), HighWord(address)); } void storePtr(ImmWord imm, const Address& address); void storePtr(ImmWord imm, const BaseIndex& address); void storePtr(ImmPtr imm, const Address& address); void storePtr(ImmPtr imm, const BaseIndex& address); void storePtr(ImmGCPtr imm, const Address& address); void storePtr(ImmGCPtr imm, const BaseIndex& address);
--- a/js/src/jit/arm/Trampoline-arm.cpp +++ b/js/src/jit/arm/Trampoline-arm.cpp @@ -1282,20 +1282,20 @@ JitRuntime::generateProfilerExitFrameTai masm.storePtr(scratch2, lastProfilingFrame); masm.ret(); } // // JitFrame_Rectifier // - // The rectifier frame can be preceded by either an IonJS, a WasmToJSJit or - // a BaselineStub frame. + // The rectifier frame can be preceded by either an IonJS, a BaselineStub, + // or a CppToJSJit/WasmToJSJit frame. // - // Stack layout if caller of rectifier was Ion or WasmToJSJit: + // Stack layout if caller of rectifier was Ion or CppToJSJit/WasmToJSJit: // // Ion-Descriptor // Ion-ReturnAddr // ... ion frame data ... |- Rect-Descriptor.Size // < COMMON LAYOUT > // // Stack layout if caller of rectifier was Baseline: // @@ -1349,18 +1349,18 @@ JitRuntime::generateProfilerExitFrameTai // scratch3 := RectFrame + Rect-Descriptor.Size + RectifierFrameLayout::Size() masm.ma_add(scratch2, scratch1, scratch3); masm.add32(Imm32(RectifierFrameLayout::Size()), scratch3); masm.storePtr(scratch3, lastProfilingFrame); masm.ret(); masm.bind(¬IonFrame); - // Check for either BaselineStub or WasmToJSJit: since WasmToJSJit is - // just an entry, jump there if we see it. + // Check for either BaselineStub or a CppToJSJit/WasmToJSJit entry + // frame. masm.branch32(Assembler::NotEqual, scratch3, Imm32(JitFrame_BaselineStub), &handle_Entry); // Handle Rectifier <- BaselineStub <- BaselineJS masm.ma_add(scratch2, scratch1, scratch3); Address stubFrameReturnAddr(scratch3, RectifierFrameLayout::Size() + BaselineStubFrameLayout::offsetOfReturnAddress()); masm.loadPtr(stubFrameReturnAddr, scratch2); masm.storePtr(scratch2, lastProfilingCallSite);
--- a/js/src/jit/arm64/Trampoline-arm64.cpp +++ b/js/src/jit/arm64/Trampoline-arm64.cpp @@ -1074,20 +1074,20 @@ JitRuntime::generateProfilerExitFrameTai masm.storePtr(scratch2, lastProfilingFrame); masm.ret(); } // // JitFrame_Rectifier // - // The rectifier frame can be preceded by either an IonJS or a - // BaselineStub frame. + // The rectifier frame can be preceded by either an IonJS, a BaselineStub, + // or a CppToJSJit/WasmToJSJit frame. // - // Stack layout if caller of rectifier was Ion: + // Stack layout if caller of rectifier was Ion or CppToJSJit/WasmToJSJit: // // Ion-Descriptor // Ion-ReturnAddr // ... ion frame data ... |- Rect-Descriptor.Size // < COMMON LAYOUT > // // Stack layout if caller of rectifier was Baseline: // @@ -1114,17 +1114,17 @@ JitRuntime::generateProfilerExitFrameTai // Descriptor | // FP -----> ReturnAddr | // masm.bind(&handle_Rectifier); { // scratch2 := StackPointer + Descriptor.size*1 + JitFrameLayout::Size(); masm.addPtr(masm.getStackPointer(), scratch1, scratch2); masm.syncStackPtr(); - masm.add32(Imm32(JitFrameLayout::Size()), scratch2); + masm.addPtr(Imm32(JitFrameLayout::Size()), scratch2); masm.loadPtr(Address(scratch2, RectifierFrameLayout::offsetOfDescriptor()), scratch3); masm.rshiftPtr(Imm32(FRAMESIZE_SHIFT), scratch3, scratch1); masm.and32(Imm32((1 << FRAMETYPE_BITS) - 1), scratch3); // Now |scratch1| contains Rect-Descriptor.Size // and |scratch2| points to Rectifier frame // and |scratch3| contains Rect-Descriptor.Type @@ -1142,18 +1142,18 @@ JitRuntime::generateProfilerExitFrameTai // scratch3 := RectFrame + Rect-Descriptor.Size + RectifierFrameLayout::Size() masm.addPtr(scratch2, scratch1, scratch3); masm.add32(Imm32(RectifierFrameLayout::Size()), scratch3); masm.storePtr(scratch3, lastProfilingFrame); masm.ret(); masm.bind(¬IonFrame); - // Check for either BaselineStub or WasmToJSJit: since WasmToJSJit is - // just an entry, jump there if we see it. + // Check for either BaselineStub or a CppToJSJit/WasmToJSJit entry + // frame. masm.branch32(Assembler::NotEqual, scratch3, Imm32(JitFrame_BaselineStub), &handle_Entry); // Handle Rectifier <- BaselineStub <- BaselineJS masm.addPtr(scratch2, scratch1, scratch3); Address stubFrameReturnAddr(scratch3, RectifierFrameLayout::Size() + BaselineStubFrameLayout::offsetOfReturnAddress()); masm.loadPtr(stubFrameReturnAddr, scratch2); masm.storePtr(scratch2, lastProfilingCallSite);
--- a/js/src/jit/mips32/MacroAssembler-mips32.h +++ b/js/src/jit/mips32/MacroAssembler-mips32.h @@ -853,19 +853,18 @@ class MacroAssemblerMIPSCompat : public void load16ZeroExtend(const Address& address, Register dest); void load16ZeroExtend(const BaseIndex& src, Register dest); void load32(const Address& address, Register dest); void load32(const BaseIndex& address, Register dest); void load32(AbsoluteAddress address, Register dest); void load32(wasm::SymbolicAddress address, Register dest); void load64(const Address& address, Register64 dest) { - load32(Address(address.base, address.offset + INT64LOW_OFFSET), dest.low); - int32_t highOffset = (address.offset < 0) ? -int32_t(INT64HIGH_OFFSET) : INT64HIGH_OFFSET; - load32(Address(address.base, address.offset + highOffset), dest.high); + load32(LowWord(address), dest.low); + load32(HighWord(address), dest.high); } void loadPtr(const Address& address, Register dest); void loadPtr(const BaseIndex& src, Register dest); void loadPtr(AbsoluteAddress address, Register dest); void loadPtr(wasm::SymbolicAddress address, Register dest); void loadPrivate(const Address& address, Register dest);
--- a/js/src/jit/mips32/Trampoline-mips32.cpp +++ b/js/src/jit/mips32/Trampoline-mips32.cpp @@ -1261,20 +1261,20 @@ JitRuntime::generateProfilerExitFrameTai masm.storePtr(scratch2, lastProfilingFrame); masm.ret(); } // // JitFrame_Rectifier // - // The rectifier frame can be preceded by either an IonJS, a WasmToJSJit or - // a BaselineStub frame. + // The rectifier frame can be preceded by either an IonJS, a BaselineStub, + // or a CppToJSJit/WasmToJSJit frame. // - // Stack layout if caller of rectifier was Ion or WasmToJSJit: + // Stack layout if caller of rectifier was Ion or CppToJSJit/WasmToJSJit: // // Ion-Descriptor // Ion-ReturnAddr // ... ion frame data ... |- Rect-Descriptor.Size // < COMMON LAYOUT > // // Stack layout if caller of rectifier was Baseline: // @@ -1328,18 +1328,18 @@ JitRuntime::generateProfilerExitFrameTai // scratch3 := RectFrame + Rect-Descriptor.Size + RectifierFrameLayout::Size() masm.as_addu(scratch3, scratch2, scratch1); masm.add32(Imm32(RectifierFrameLayout::Size()), scratch3); masm.storePtr(scratch3, lastProfilingFrame); masm.ret(); masm.bind(¬IonFrame); - // Check for either BaselineStub or WasmToJSJit: since WasmToJSJit is - // just an entry, jump there if we see it. + // Check for either BaselineStub or a CppToJSJit/WasmToJSJit entry + // frame. masm.branch32(Assembler::NotEqual, scratch3, Imm32(JitFrame_BaselineStub), &handle_Entry); // Handle Rectifier <- BaselineStub <- BaselineJS masm.as_addu(scratch3, scratch2, scratch1); Address stubFrameReturnAddr(scratch3, RectifierFrameLayout::Size() + BaselineStubFrameLayout::offsetOfReturnAddress()); masm.loadPtr(stubFrameReturnAddr, scratch2); masm.storePtr(scratch2, lastProfilingCallSite);
--- a/js/src/jit/mips64/Trampoline-mips64.cpp +++ b/js/src/jit/mips64/Trampoline-mips64.cpp @@ -1202,20 +1202,20 @@ JitRuntime::generateProfilerExitFrameTai masm.storePtr(scratch2, lastProfilingFrame); masm.ret(); } // // JitFrame_Rectifier // - // The rectifier frame can be preceded by either an IonJS, a WasmToJSJit or - // a BaselineStub frame. + // The rectifier frame can be preceded by either an IonJS, a BaselineStub, + // or a CppToJSJit/WasmToJSJit frame. // - // Stack layout if caller of rectifier was Ion or WasmToJSJit: + // Stack layout if caller of rectifier was Ion or CppToJSJit/WasmToJSJit: // // Ion-Descriptor // Ion-ReturnAddr // ... ion frame data ... |- Rect-Descriptor.Size // < COMMON LAYOUT > // // Stack layout if caller of rectifier was Baseline: // @@ -1269,18 +1269,18 @@ JitRuntime::generateProfilerExitFrameTai // scratch3 := RectFrame + Rect-Descriptor.Size + RectifierFrameLayout::Size() masm.as_daddu(scratch3, scratch2, scratch1); masm.addPtr(Imm32(RectifierFrameLayout::Size()), scratch3); masm.storePtr(scratch3, lastProfilingFrame); masm.ret(); masm.bind(¬IonFrame); - // Check for either BaselineStub or WasmToJSJit: since WasmToJSJit is - // just an entry, jump there if we see it. + // Check for either BaselineStub or a CppToJSJit/WasmToJSJit entry + // frame. masm.branch32(Assembler::NotEqual, scratch3, Imm32(JitFrame_BaselineStub), &handle_Entry); // Handle Rectifier <- BaselineStub <- BaselineJS masm.as_daddu(scratch3, scratch2, scratch1); Address stubFrameReturnAddr(scratch3, RectifierFrameLayout::Size() + BaselineStubFrameLayout::offsetOfReturnAddress()); masm.loadPtr(stubFrameReturnAddr, scratch2); masm.storePtr(scratch2, lastProfilingCallSite);
--- a/js/src/jit/shared/Assembler-shared.h +++ b/js/src/jit/shared/Assembler-shared.h @@ -2,16 +2,17 @@ * vim: set ts=8 sts=4 et sw=4 tw=99: * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef jit_shared_Assembler_shared_h #define jit_shared_Assembler_shared_h +#include "mozilla/CheckedInt.h" #include "mozilla/PodOperations.h" #include <limits.h> #include "jit/AtomicOp.h" #include "jit/JitAllocPolicy.h" #include "jit/Label.h" #include "jit/Registers.h" @@ -29,16 +30,18 @@ // JS_SMALL_BRANCH means the range on a branch instruction // is smaller than the whole address space # define JS_SMALL_BRANCH #endif namespace js { namespace jit { +using mozilla::CheckedInt; + namespace Disassembler { class HeapAccess; } // namespace Disassembler static const uint32_t Simd128DataSize = 4 * sizeof(int32_t); static_assert(Simd128DataSize == 4 * sizeof(int32_t), "SIMD data should be able to contain int32x4"); static_assert(Simd128DataSize == 4 * sizeof(float), "SIMD data should be able to contain float32x4"); static_assert(Simd128DataSize == 2 * sizeof(double), "SIMD data should be able to contain float64x2"); @@ -293,32 +296,68 @@ struct Address int32_t offset; Address(Register base, int32_t offset) : base(base), offset(offset) { } Address() { mozilla::PodZero(this); } }; +#if JS_BITS_PER_WORD == 32 + +static inline Address +LowWord(const Address& address) { + CheckedInt<int32_t> offset = CheckedInt<int32_t>(address.offset) + INT64LOW_OFFSET; + MOZ_ALWAYS_TRUE(offset.isValid()); + return Address(address.base, offset.value()); +} + +static inline Address +HighWord(const Address& address) { + CheckedInt<int32_t> offset = CheckedInt<int32_t>(address.offset) + INT64HIGH_OFFSET; + MOZ_ALWAYS_TRUE(offset.isValid()); + return Address(address.base, offset.value()); +} + +#endif + // Specifies an address computed in the form of a register base, a register // index with a scale, and a constant, 32-bit offset. struct BaseIndex { Register base; Register index; Scale scale; int32_t offset; BaseIndex(Register base, Register index, Scale scale, int32_t offset = 0) : base(base), index(index), scale(scale), offset(offset) { } BaseIndex() { mozilla::PodZero(this); } }; +#if JS_BITS_PER_WORD == 32 + +static inline BaseIndex +LowWord(const BaseIndex& address) { + CheckedInt<int32_t> offset = CheckedInt<int32_t>(address.offset) + INT64LOW_OFFSET; + MOZ_ALWAYS_TRUE(offset.isValid()); + return BaseIndex(address.base, address.index, address.scale, offset.value()); +} + +static inline BaseIndex +HighWord(const BaseIndex& address) { + CheckedInt<int32_t> offset = CheckedInt<int32_t>(address.offset) + INT64HIGH_OFFSET; + MOZ_ALWAYS_TRUE(offset.isValid()); + return BaseIndex(address.base, address.index, address.scale, offset.value()); +} + +#endif + // A BaseIndex used to access Values. Note that |offset| is *not* scaled by // sizeof(Value). Use this *only* if you're indexing into a series of Values // that aren't object elements or object slots (for example, values on the // stack, values in an arguments object, &c.). If you're indexing into an // object's elements or slots, don't use this directly! Use // BaseObject{Element,Slot}Index instead. struct BaseValueIndex : BaseIndex {
--- a/js/src/jit/x64/Trampoline-x64.cpp +++ b/js/src/jit/x64/Trampoline-x64.cpp @@ -1175,20 +1175,20 @@ JitRuntime::generateProfilerExitFrameTai masm.storePtr(scratch2, lastProfilingFrame); masm.ret(); } // // JitFrame_Rectifier // - // The rectifier frame can be preceded by either an IonJS, a WasmToJSJit or - // a BaselineStub frame. + // The rectifier frame can be preceded by either an IonJS, a BaselineStub, + // or a CppToJSJit/WasmToJSJit frame. // - // Stack layout if caller of rectifier was Ion or WasmToJSJit: + // Stack layout if caller of rectifier was Ion or CppToJSJit/WasmToJSJit: // // Ion-Descriptor // Ion-ReturnAddr // ... ion frame data ... |- Rect-Descriptor.Size // < COMMON LAYOUT > // // Stack layout if caller of rectifier was Baseline: // @@ -1241,18 +1241,18 @@ JitRuntime::generateProfilerExitFrameTai // scratch3 := RectFrame + Rect-Descriptor.Size + RectifierFrameLayout::Size() masm.lea(Operand(scratch2, scratch1, TimesOne, RectifierFrameLayout::Size()), scratch3); masm.storePtr(scratch3, lastProfilingFrame); masm.ret(); masm.bind(¬IonFrame); - // Check for either BaselineStub or WasmToJSJit: since WasmToJSJit is - // just an entry, jump there if we see it. + // Check for either BaselineStub or a CppToJSJit/WasmToJSJit entry + // frame. masm.branch32(Assembler::NotEqual, scratch3, Imm32(JitFrame_BaselineStub), &handle_Entry); // Handle Rectifier <- BaselineStub <- BaselineJS BaseIndex stubFrameReturnAddr(scratch2, scratch1, TimesOne, RectifierFrameLayout::Size() + BaselineStubFrameLayout::offsetOfReturnAddress()); masm.loadPtr(stubFrameReturnAddr, scratch3); masm.storePtr(scratch3, lastProfilingCallSite);
--- a/js/src/jit/x86/Assembler-x86.h +++ b/js/src/jit/x86/Assembler-x86.h @@ -203,16 +203,34 @@ PatchJump(CodeLocationJump jump, CodeLoc X86Encoding::SetRel32(jump.raw(), label.raw()); } static inline void PatchBackedge(CodeLocationJump& jump_, CodeLocationLabel label, JitZoneGroup::BackedgeTarget target) { PatchJump(jump_, label); } +static inline Operand +LowWord(const Operand& op) { + switch (op.kind()) { + case Operand::MEM_REG_DISP: return Operand(LowWord(op.toAddress())); + case Operand::MEM_SCALE: return Operand(LowWord(op.toBaseIndex())); + default: MOZ_CRASH("Invalid operand type"); + } +} + +static inline Operand +HighWord(const Operand& op) { + switch (op.kind()) { + case Operand::MEM_REG_DISP: return Operand(HighWord(op.toAddress())); + case Operand::MEM_SCALE: return Operand(HighWord(op.toBaseIndex())); + default: MOZ_CRASH("Invalid operand type"); + } +} + // Return operand from a JS -> JS call. static const ValueOperand JSReturnOperand = ValueOperand(JSReturnReg_Type, JSReturnReg_Data); class Assembler : public AssemblerX86Shared { void writeRelocation(JmpSrc src) { jumpRelocations_.writeUnsigned(src.offset()); } @@ -763,34 +781,30 @@ class Assembler : public AssemblerX86Sha default: MOZ_CRASH("unexpected operand kind"); } return CodeOffset(masm.currentOffset()); } CodeOffset movlWithPatchLow(Register regLow, const Operand& dest) { switch (dest.kind()) { case Operand::MEM_REG_DISP: { - Address addr = dest.toAddress(); - Operand low(addr.base, addr.offset + INT64LOW_OFFSET); - return movlWithPatch(regLow, low); + return movlWithPatch(regLow, LowWord(dest)); } case Operand::MEM_ADDRESS32: { Operand low(PatchedAbsoluteAddress(uint32_t(dest.address()) + INT64LOW_OFFSET)); return movlWithPatch(regLow, low); } default: MOZ_CRASH("unexpected operand kind"); } } CodeOffset movlWithPatchHigh(Register regHigh, const Operand& dest) { switch (dest.kind()) { case Operand::MEM_REG_DISP: { - Address addr = dest.toAddress(); - Operand high(addr.base, addr.offset + INT64HIGH_OFFSET); - return movlWithPatch(regHigh, high); + return movlWithPatch(regHigh, HighWord(dest)); } case Operand::MEM_ADDRESS32: { Operand high(PatchedAbsoluteAddress(uint32_t(dest.address()) + INT64HIGH_OFFSET)); return movlWithPatch(regHigh, high); } default: MOZ_CRASH("unexpected operand kind"); }
--- a/js/src/jit/x86/MacroAssembler-x86-inl.h +++ b/js/src/jit/x86/MacroAssembler-x86-inl.h @@ -945,57 +945,57 @@ MacroAssembler::truncateFloat32ToUInt64( { Label done; loadFloat32(src, floatTemp); truncateFloat32ToInt64(src, dest, temp); // For unsigned conversion the case of [INT64, UINT64] needs to get handle seperately. - load32(Address(dest.base, dest.offset + INT64HIGH_OFFSET), temp); + load32(HighWord(dest), temp); branch32(Assembler::Condition::NotSigned, temp, Imm32(0), &done); // Move the value inside INT64 range. storeFloat32(floatTemp, dest); loadConstantFloat32(double(int64_t(0x8000000000000000)), floatTemp); vaddss(Operand(dest), floatTemp, floatTemp); storeFloat32(floatTemp, dest); truncateFloat32ToInt64(dest, dest, temp); - load32(Address(dest.base, dest.offset + INT64HIGH_OFFSET), temp); + load32(HighWord(dest), temp); orl(Imm32(0x80000000), temp); - store32(temp, Address(dest.base, dest.offset + INT64HIGH_OFFSET)); + store32(temp, HighWord(dest)); bind(&done); } void MacroAssembler::truncateDoubleToUInt64(Address src, Address dest, Register temp, FloatRegister floatTemp) { Label done; loadDouble(src, floatTemp); truncateDoubleToInt64(src, dest, temp); // For unsigned conversion the case of [INT64, UINT64] needs to get handle seperately. - load32(Address(dest.base, dest.offset + INT64HIGH_OFFSET), temp); + load32(HighWord(dest), temp); branch32(Assembler::Condition::NotSigned, temp, Imm32(0), &done); // Move the value inside INT64 range. storeDouble(floatTemp, dest); loadConstantDouble(double(int64_t(0x8000000000000000)), floatTemp); vaddsd(Operand(dest), floatTemp, floatTemp); storeDouble(floatTemp, dest); truncateDoubleToInt64(dest, dest, temp); - load32(Address(dest.base, dest.offset + INT64HIGH_OFFSET), temp); + load32(HighWord(dest), temp); orl(Imm32(0x80000000), temp); - store32(temp, Address(dest.base, dest.offset + INT64HIGH_OFFSET)); + store32(temp, HighWord(dest)); bind(&done); } // ======================================================================== // wasm support template <class L>
--- a/js/src/jit/x86/MacroAssembler-x86.cpp +++ b/js/src/jit/x86/MacroAssembler-x86.cpp @@ -763,40 +763,28 @@ MacroAssembler::wasmLoadI64(const wasm:: break; case Scalar::Uint32: movl(srcAddr, out.low); append(access, loadOffset, framePushed()); xorl(out.high, out.high); break; case Scalar::Int64: { - Operand low(eax); - Operand high(eax); - if (srcAddr.kind() == Operand::MEM_SCALE) { - BaseIndex addr = srcAddr.toBaseIndex(); - - MOZ_RELEASE_ASSERT(addr.base != out.low && addr.index != out.low); + MOZ_RELEASE_ASSERT(srcAddr.toBaseIndex().base != out.low && + srcAddr.toBaseIndex().index != out.low); + } + if (srcAddr.kind() == Operand::MEM_REG_DISP) + MOZ_RELEASE_ASSERT(srcAddr.toAddress().base != out.low); - low = Operand(addr.base, addr.index, addr.scale, addr.offset + INT64LOW_OFFSET); - high = Operand(addr.base, addr.index, addr.scale, addr.offset + INT64HIGH_OFFSET); - } else { - Address addr = srcAddr.toAddress(); - - MOZ_RELEASE_ASSERT(addr.base != out.low); - - low = Operand(addr.base, addr.offset + INT64LOW_OFFSET); - high = Operand(addr.base, addr.offset + INT64HIGH_OFFSET); - } - - movl(low, out.low); + movl(LowWord(srcAddr), out.low); append(access, loadOffset, framePushed()); loadOffset = size(); - movl(high, out.high); + movl(HighWord(srcAddr), out.high); append(access, loadOffset, framePushed()); break; } case Scalar::Float32: case Scalar::Float64: case Scalar::Float32x4: case Scalar::Int8x16: @@ -877,34 +865,22 @@ MacroAssembler::wasmStore(const wasm::Me void MacroAssembler::wasmStoreI64(const wasm::MemoryAccessDesc& access, Register64 value, Operand dstAddr) { MOZ_ASSERT(!access.isAtomic()); MOZ_ASSERT(!access.isSimd()); MOZ_ASSERT(dstAddr.kind() == Operand::MEM_REG_DISP || dstAddr.kind() == Operand::MEM_SCALE); - Operand low(eax); - Operand high(eax); - if (dstAddr.kind() == Operand::MEM_SCALE) { - BaseIndex addr = dstAddr.toBaseIndex(); - low = Operand(addr.base, addr.index, addr.scale, addr.offset + INT64LOW_OFFSET); - high = Operand(addr.base, addr.index, addr.scale, addr.offset + INT64HIGH_OFFSET); - } else { - Address addr = dstAddr.toAddress(); - low = Operand(addr.base, addr.offset + INT64LOW_OFFSET); - high = Operand(addr.base, addr.offset + INT64HIGH_OFFSET); - } - size_t storeOffset = size(); - movl(value.low, low); + movl(value.low, LowWord(dstAddr)); append(access, storeOffset, framePushed()); storeOffset = size(); - movl(value.high, high); + movl(value.high, HighWord(dstAddr)); append(access, storeOffset, framePushed()); } void MacroAssembler::wasmTruncateDoubleToUInt32(FloatRegister input, Register output, Label* oolEntry) { Label done; vcvttsd2si(input, output);
--- a/js/src/jit/x86/MacroAssembler-x86.h +++ b/js/src/jit/x86/MacroAssembler-x86.h @@ -582,20 +582,20 @@ class MacroAssemblerX86 : public MacroAs movl(Operand(address), dest); } void loadPrivate(const Address& src, Register dest) { movl(payloadOf(src), dest); } void load32(AbsoluteAddress address, Register dest) { movl(Operand(address), dest); } - void load64(const Address& address, Register64 dest) { - movl(Operand(Address(address.base, address.offset + INT64LOW_OFFSET)), dest.low); - int32_t highOffset = (address.offset < 0) ? -int32_t(INT64HIGH_OFFSET) : INT64HIGH_OFFSET; - movl(Operand(Address(address.base, address.offset + highOffset)), dest.high); + template <typename T> + void load64(const T& address, Register64 dest) { + movl(Operand(LowWord(address)), dest.low); + movl(Operand(HighWord(address)), dest.high); } template <typename T> void storePtr(ImmWord imm, T address) { movl(Imm32(imm.value), Operand(address)); } template <typename T> void storePtr(ImmPtr imm, T address) { storePtr(ImmWord(uintptr_t(imm.value)), address); @@ -617,23 +617,24 @@ class MacroAssemblerX86 : public MacroAs movl(src, Operand(address)); } void store32(Register src, AbsoluteAddress address) { movl(src, Operand(address)); } void store16(Register src, AbsoluteAddress address) { movw(src, Operand(address)); } - void store64(Register64 src, Address address) { - movl(src.low, Operand(Address(address.base, address.offset + INT64LOW_OFFSET))); - movl(src.high, Operand(Address(address.base, address.offset + INT64HIGH_OFFSET))); + template <typename T> + void store64(Register64 src, const T& address) { + movl(src.low, Operand(LowWord(address))); + movl(src.high, Operand(HighWord(address))); } void store64(Imm64 imm, Address address) { - movl(imm.low(), Operand(Address(address.base, address.offset + INT64LOW_OFFSET))); - movl(imm.hi(), Operand(Address(address.base, address.offset + INT64HIGH_OFFSET))); + movl(imm.low(), Operand(LowWord(address))); + movl(imm.hi(), Operand(HighWord(address))); } void setStackArg(Register reg, uint32_t arg) { movl(reg, Operand(esp, arg * sizeof(intptr_t))); } void boxDouble(FloatRegister src, const ValueOperand& dest, FloatRegister temp) { if (Assembler::HasSSE41()) {
--- a/js/src/jit/x86/Trampoline-x86.cpp +++ b/js/src/jit/x86/Trampoline-x86.cpp @@ -1209,20 +1209,20 @@ JitRuntime::generateProfilerExitFrameTai masm.storePtr(scratch2, lastProfilingFrame); masm.ret(); } // // JitFrame_Rectifier // - // The rectifier frame can be preceded by either an IonJS, a WasmToJSJit or - // a BaselineStub frame. + // The rectifier frame can be preceded by either an IonJS, a BaselineStub, + // or a CppToJSJit/WasmToJSJit frame. // - // Stack layout if caller of rectifier was Ion or WasmToJSJit: + // Stack layout if caller of rectifier was Ion or CppToJSJit/WasmToJSJit: // // Ion-Descriptor // Ion-ReturnAddr // ... ion frame data ... |- Rect-Descriptor.Size // < COMMON LAYOUT > // // Stack layout if caller of rectifier was Baseline: // @@ -1275,18 +1275,18 @@ JitRuntime::generateProfilerExitFrameTai // scratch3 := RectFrame + Rect-Descriptor.Size + RectifierFrameLayout::Size() masm.lea(Operand(scratch2, scratch1, TimesOne, RectifierFrameLayout::Size()), scratch3); masm.storePtr(scratch3, lastProfilingFrame); masm.ret(); masm.bind(¬IonFrame); - // Check for either BaselineStub or WasmToJSJit: since WasmToJSJit is - // just an entry, jump there if we see it. + // Check for either BaselineStub or a CppToJSJit/WasmToJSJit entry + // frame. masm.branch32(Assembler::NotEqual, scratch3, Imm32(JitFrame_BaselineStub), &handle_Entry); // Handle Rectifier <- BaselineStub <- BaselineJS BaseIndex stubFrameReturnAddr(scratch2, scratch1, TimesOne, RectifierFrameLayout::Size() + BaselineStubFrameLayout::offsetOfReturnAddress()); masm.loadPtr(stubFrameReturnAddr, scratch3); masm.storePtr(scratch3, lastProfilingCallSite);
--- a/js/src/jscntxt.cpp +++ b/js/src/jscntxt.cpp @@ -143,16 +143,21 @@ JSContext::init(ContextKind kind) JSContext* js::NewContext(uint32_t maxBytes, uint32_t maxNurseryBytes, JSRuntime* parentRuntime) { AutoNoteSingleThreadedRegion anstr; MOZ_RELEASE_ASSERT(!TlsContext.get()); +#if defined(DEBUG) || defined(JS_OOM_BREAKPOINT) + js::oom::SetThreadType(!parentRuntime ? js::THREAD_TYPE_COOPERATING + : js::THREAD_TYPE_WORKER); +#endif + JSRuntime* runtime = js_new<JSRuntime>(parentRuntime); if (!runtime) return nullptr; JSContext* cx = js_new<JSContext>(runtime, JS::ContextOptions()); if (!cx) { js_delete(runtime); return nullptr;
--- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -4501,25 +4501,28 @@ js::gc::MarkingValidator::nonIncremental return; JSRuntime* runtime = gc->rt; GCMarker* gcmarker = &gc->marker; gc->waitBackgroundSweepEnd(); /* Save existing mark bits. */ - for (auto chunk = gc->allNonEmptyChunks(); !chunk.done(); chunk.next()) { - ChunkBitmap* bitmap = &chunk->bitmap; - ChunkBitmap* entry = js_new<ChunkBitmap>(); - if (!entry) - return; - - memcpy((void*)entry->bitmap, (void*)bitmap->bitmap, sizeof(bitmap->bitmap)); - if (!map.putNew(chunk, entry)) - return; + { + AutoLockGC lock(runtime); + for (auto chunk = gc->allNonEmptyChunks(lock); !chunk.done(); chunk.next()) { + ChunkBitmap* bitmap = &chunk->bitmap; + ChunkBitmap* entry = js_new<ChunkBitmap>(); + if (!entry) + return; + + memcpy((void*)entry->bitmap, (void*)bitmap->bitmap, sizeof(bitmap->bitmap)); + if (!map.putNew(chunk, entry)) + return; + } } /* * Temporarily clear the weakmaps' mark flags for the compartments we are * collecting. */ WeakMapSet markedWeakMaps; @@ -4565,17 +4568,18 @@ js::gc::MarkingValidator::nonIncremental gcstats::AutoPhase ap(gc->stats(), gcstats::PhaseKind::UNMARK); for (GCZonesIter zone(runtime); !zone.done(); zone.next()) WeakMapBase::unmarkZone(zone); MOZ_ASSERT(gcmarker->isDrained()); gcmarker->reset(); - for (auto chunk = gc->allNonEmptyChunks(); !chunk.done(); chunk.next()) + AutoLockGC lock(runtime); + for (auto chunk = gc->allNonEmptyChunks(lock); !chunk.done(); chunk.next()) chunk->bitmap.clear(); } } { gcstats::AutoPhase ap(gc->stats(), gcstats::PhaseKind::MARK); gc->traceRuntimeForMajorGC(gcmarker, lock); @@ -4603,20 +4607,23 @@ js::gc::MarkingValidator::nonIncremental /* Restore zone state. */ for (GCZonesIter zone(runtime); !zone.done(); zone.next()) zone->changeGCState(Zone::MarkGray, Zone::Mark); MOZ_ASSERT(gc->marker.isDrained()); gc->marker.setMarkColorBlack(); } /* Take a copy of the non-incremental mark state and restore the original. */ - for (auto chunk = gc->allNonEmptyChunks(); !chunk.done(); chunk.next()) { - ChunkBitmap* bitmap = &chunk->bitmap; - ChunkBitmap* entry = map.lookup(chunk)->value(); - Swap(*entry, *bitmap); + { + AutoLockGC lock(runtime); + for (auto chunk = gc->allNonEmptyChunks(lock); !chunk.done(); chunk.next()) { + ChunkBitmap* bitmap = &chunk->bitmap; + ChunkBitmap* entry = map.lookup(chunk)->value(); + Swap(*entry, *bitmap); + } } for (GCZonesIter zone(runtime); !zone.done(); zone.next()) { WeakMapBase::unmarkZone(zone); AutoEnterOOMUnsafeRegion oomUnsafe; if (!zone->gcWeakKeys().clear()) oomUnsafe.crash("clearing weak keys table for validator"); } @@ -4641,17 +4648,18 @@ js::gc::MarkingValidator::validate() * the mark bits to those previously recorded for a non-incremental mark. */ if (!initialized) return; gc->waitBackgroundSweepEnd(); - for (auto chunk = gc->allNonEmptyChunks(); !chunk.done(); chunk.next()) { + AutoLockGC lock(gc->rt); + for (auto chunk = gc->allNonEmptyChunks(lock); !chunk.done(); chunk.next()) { BitmapMap::Ptr ptr = map.lookup(chunk); if (!ptr) continue; /* Allocated after we did the non-incremental mark. */ ChunkBitmap* bitmap = ptr->value(); ChunkBitmap* incBitmap = &chunk->bitmap; for (size_t i = 0; i < ArenasPerChunk; i++) {
--- a/js/src/vm/Initialization.cpp +++ b/js/src/vm/Initialization.cpp @@ -93,17 +93,16 @@ JS::detail::InitWithFailureDiagnostic(bo #ifdef DEBUG CheckMessageParameterCounts(); #endif RETURN_IF_FAIL(js::TlsContext.init()); #if defined(DEBUG) || defined(JS_OOM_BREAKPOINT) RETURN_IF_FAIL(js::oom::InitThreadType()); - js::oom::SetThreadType(js::THREAD_TYPE_COOPERATING); #endif RETURN_IF_FAIL(js::Mutex::Init()); RETURN_IF_FAIL(js::wasm::InitInstanceStaticData()); js::gc::InitMemorySubsystem(); // Ensure gc::SystemPageSize() works.
--- a/js/src/vm/Interpreter.cpp +++ b/js/src/vm/Interpreter.cpp @@ -433,42 +433,32 @@ js::RunScript(JSContext* cx, RunState& s } return Interpret(cx, state); } #ifdef _MSC_VER # pragma optimize("", on) #endif -struct AutoGCIfRequested -{ - JSRuntime* runtime; - explicit AutoGCIfRequested(JSRuntime* rt) : runtime(rt) {} - ~AutoGCIfRequested() { runtime->gc.gcIfRequested(); } -}; - /* * Find a function reference and its 'this' value implicit first parameter * under argc arguments on cx's stack, and call the function. Push missing * required arguments, allocate declared local variables, and pop everything * when done. Then push the return value. * * Note: This function DOES NOT call GetThisValue to munge |args.thisv()| if * necessary. The caller (usually the interpreter) must have performed * this step already! */ bool js::InternalCallOrConstruct(JSContext* cx, const CallArgs& args, MaybeConstruct construct) { MOZ_ASSERT(args.length() <= ARGS_LENGTH_MAX); MOZ_ASSERT(!cx->zone()->types.activeAnalysis); - /* Perform GC if necessary on exit from the function. */ - AutoGCIfRequested gcIfRequested(cx->runtime()); - unsigned skipForCallee = args.length() + 1 + (construct == CONSTRUCT); if (args.calleev().isPrimitive()) return ReportIsNotFunction(cx, args.calleev(), skipForCallee, construct); /* Invoke non-functions. */ if (MOZ_UNLIKELY(!args.callee().is<JSFunction>())) { MOZ_ASSERT_IF(construct, !args.callee().constructHook()); JSNative call = args.callee().callHook();
--- a/js/src/vm/Interpreter.h +++ b/js/src/vm/Interpreter.h @@ -256,17 +256,20 @@ class ExecuteState : public RunState JSObject& envChain, AbstractFramePtr evalInFrame, Value* result) : RunState(cx, Execute, script), newTargetValue_(cx, newTargetValue), envChain_(cx, &envChain), evalInFrame_(evalInFrame), result_(result) { } - Value newTarget() { return newTargetValue_; } + Value newTarget() const { return newTargetValue_; } + void setNewTarget(const Value& v) { newTargetValue_ = v; } + Value* addressOfNewTarget() { return newTargetValue_.address(); } + JSObject* environmentChain() const { return envChain_; } bool isDebuggerEval() const { return !!evalInFrame_; } virtual InterpreterFrame* pushInterpreterFrame(JSContext* cx); virtual void setReturnValue(const Value& v) { if (result_) *result_ = v;
--- a/js/src/wasm/WasmBaselineCompile.cpp +++ b/js/src/wasm/WasmBaselineCompile.cpp @@ -2516,19 +2516,19 @@ class BaseCompiler ABIArg argLoc = call.abi.next(MIRType::Int64); if (argLoc.kind() == ABIArg::Stack) { ScratchI32 scratch(*this); #if defined(JS_CODEGEN_X64) loadI64(Register64(scratch), arg); masm.movq(scratch, Operand(StackPointer, argLoc.offsetFromArgBase())); #elif defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_ARM) loadI64Low(scratch, arg); - masm.store32(scratch, Address(StackPointer, argLoc.offsetFromArgBase() + INT64LOW_OFFSET)); + masm.store32(scratch, LowWord(Address(StackPointer, argLoc.offsetFromArgBase()))); loadI64High(scratch, arg); - masm.store32(scratch, Address(StackPointer, argLoc.offsetFromArgBase() + INT64HIGH_OFFSET)); + masm.store32(scratch, HighWord(Address(StackPointer, argLoc.offsetFromArgBase()))); #else MOZ_CRASH("BaseCompiler platform hook: passArg I64"); #endif } else { loadI64(argLoc.gpr64(), arg); } break; }
--- a/js/src/wasm/WasmStubs.cpp +++ b/js/src/wasm/WasmStubs.cpp @@ -134,20 +134,20 @@ SetupABIArguments(MacroAssembler& masm, switch (type) { case MIRType::Int32: masm.load32(src, scratch); masm.storePtr(scratch, Address(masm.getStackPointer(), iter->offsetFromArgBase())); break; case MIRType::Int64: { Register sp = masm.getStackPointer(); #if JS_BITS_PER_WORD == 32 - masm.load32(Address(src.base, src.offset + INT64LOW_OFFSET), scratch); - masm.store32(scratch, Address(sp, iter->offsetFromArgBase() + INT64LOW_OFFSET)); - masm.load32(Address(src.base, src.offset + INT64HIGH_OFFSET), scratch); - masm.store32(scratch, Address(sp, iter->offsetFromArgBase() + INT64HIGH_OFFSET)); + masm.load32(LowWord(src), scratch); + masm.store32(scratch, LowWord(Address(sp, iter->offsetFromArgBase()))); + masm.load32(HighWord(src), scratch); + masm.store32(scratch, HighWord(Address(sp, iter->offsetFromArgBase()))); #else Register64 scratch64(scratch); masm.load64(src, scratch64); masm.store64(scratch64, Address(sp, iter->offsetFromArgBase())); #endif break; } case MIRType::Double: @@ -379,20 +379,20 @@ GenerateEntry(MacroAssembler& masm, cons static void StackCopy(MacroAssembler& masm, MIRType type, Register scratch, Address src, Address dst) { if (type == MIRType::Int32) { masm.load32(src, scratch); masm.store32(scratch, dst); } else if (type == MIRType::Int64) { #if JS_BITS_PER_WORD == 32 - masm.load32(Address(src.base, src.offset + INT64LOW_OFFSET), scratch); - masm.store32(scratch, Address(dst.base, dst.offset + INT64LOW_OFFSET)); - masm.load32(Address(src.base, src.offset + INT64HIGH_OFFSET), scratch); - masm.store32(scratch, Address(dst.base, dst.offset + INT64HIGH_OFFSET)); + masm.load32(LowWord(src), scratch); + masm.store32(scratch, LowWord(dst)); + masm.load32(HighWord(src), scratch); + masm.store32(scratch, HighWord(dst)); #else Register64 scratch64(scratch); masm.load64(src, scratch64); masm.store64(scratch64, dst); #endif } else if (type == MIRType::Float32) { masm.loadFloat32(src, ScratchFloat32Reg); masm.storeFloat32(ScratchFloat32Reg, dst); @@ -785,17 +785,24 @@ GenerateImportJitExit(MacroAssembler& ma // (sp + sizeof(void*)) % JitStackAlignment == 0 // But now we possibly want to call one of several different C++ functions, // so subtract the sizeof(void*) so that sp is aligned for an ABI call. static_assert(ABIStackAlignment <= JitStackAlignment, "subsumes"); masm.reserveStack(sizeOfRetAddr); unsigned nativeFramePushed = masm.framePushed(); AssertStackAlignment(masm, ABIStackAlignment); - masm.branchTestMagic(Assembler::Equal, JSReturnOperand, throwLabel); +#ifdef DEBUG + { + Label ok; + masm.branchTestMagic(Assembler::NotEqual, JSReturnOperand, &ok); + masm.breakpoint(); + masm.bind(&ok); + } +#endif Label oolConvert; switch (fi.sig().ret()) { case ExprType::Void: break; case ExprType::I32: masm.convertValueToInt32(JSReturnOperand, ReturnDoubleReg, ReturnReg, &oolConvert, /* -0 check */ false); @@ -877,25 +884,22 @@ GenerateImportJitExit(MacroAssembler& ma AssertStackAlignment(masm, ABIStackAlignment); switch (fi.sig().ret()) { case ExprType::I32: masm.call(SymbolicAddress::CoerceInPlace_ToInt32); masm.branchTest32(Assembler::Zero, ReturnReg, ReturnReg, throwLabel); masm.unboxInt32(Address(masm.getStackPointer(), offsetToCoerceArgv), ReturnReg); break; case ExprType::F64: - masm.call(SymbolicAddress::CoerceInPlace_ToNumber); - masm.branchTest32(Assembler::Zero, ReturnReg, ReturnReg, throwLabel); - masm.loadDouble(Address(masm.getStackPointer(), offsetToCoerceArgv), ReturnDoubleReg); - break; case ExprType::F32: masm.call(SymbolicAddress::CoerceInPlace_ToNumber); masm.branchTest32(Assembler::Zero, ReturnReg, ReturnReg, throwLabel); masm.loadDouble(Address(masm.getStackPointer(), offsetToCoerceArgv), ReturnDoubleReg); - masm.convertDoubleToFloat32(ReturnDoubleReg, ReturnFloat32Reg); + if (fi.sig().ret() == ExprType::F32) + masm.convertDoubleToFloat32(ReturnDoubleReg, ReturnFloat32Reg); break; default: MOZ_CRASH("Unsupported convert type"); } // Maintain the invariant that exitFP is either unset or not set to a // wasm tagged exitFP, per the jit exit contract. ClearExitFP(masm, scratch);
--- a/layout/base/nsLayoutUtils.cpp +++ b/layout/base/nsLayoutUtils.cpp @@ -116,17 +116,17 @@ #include "mozilla/Telemetry.h" #include "mozilla/EventDispatcher.h" #include "mozilla/EventStateManager.h" #include "mozilla/RuleNodeCacheConditions.h" #include "mozilla/StyleAnimationValue.h" #include "mozilla/StyleSetHandle.h" #include "mozilla/StyleSetHandleInlines.h" #include "RegionBuilder.h" -#include "SVGSVGElement.h" +#include "SVGViewportElement.h" #include "DisplayItemClip.h" #include "mozilla/layers/WebRenderLayerManager.h" #include "prenv.h" #include "TextDrawTarget.h" #include "nsDeckFrame.h" #include "nsIEffectiveTLDService.h" // for IsInStyloBlocklist #ifdef MOZ_XUL @@ -9760,17 +9760,17 @@ ComputeSVGReferenceRect(nsIFrame* aFrame nsSVGUtils::eBBoxIncludeFill | nsSVGUtils::eBBoxIncludeStroke); r = nsLayoutUtils::RoundGfxRectToAppRect(bbox, nsPresContext::AppUnitsPerCSSPixel()); break; } case StyleGeometryBox::ViewBox: { nsIContent* content = aFrame->GetContent(); nsSVGElement* element = static_cast<nsSVGElement*>(content); - SVGSVGElement* svgElement = element->GetCtx(); + SVGViewportElement* svgElement = element->GetCtx(); MOZ_ASSERT(svgElement); if (svgElement && svgElement->HasViewBoxRect()) { // If a ‘viewBox‘ attribute is specified for the SVG viewport creating // element: // 1. The reference box is positioned at the origin of the coordinate // system established by the ‘viewBox‘ attribute. // 2. The dimension of the reference box is set to the width and height
--- a/layout/reftests/svg/reftest.list +++ b/layout/reftests/svg/reftest.list @@ -526,16 +526,17 @@ fuzzy-if(skiaContent,1,100) == tspan-xy- == use-localRef-mask-01.svg use-localRef-mask-01-ref.svg == userSpaceOnUse-and-pattern-01.svg userSpaceOnUse-and-pattern-01-ref.svg == viewBox-and-pattern-01.svg pass.svg == viewBox-and-pattern-02.svg pass.svg == viewBox-and-pattern-03.svg pass.svg == viewBox-and-pattern-04.svg pass.svg +== viewBox-and-symbol-01.svg pass.svg == viewBox-invalid-01.svg pass.svg == viewBox-invalid-02.svg pass.svg == viewBox-valid-01.svg pass.svg == viewBox-valid-02.xhtml pass.svg == viewport-percent-graphic-user-01.svg pass.svg == winding-01.svg pass.svg == zero-stroke-01.svg pass.svg
new file mode 100644 --- /dev/null +++ b/layout/reftests/svg/viewBox-and-symbol-01.svg @@ -0,0 +1,14 @@ +<svg xmlns="http://www.w3.org/2000/svg"> + <defs> + <symbol id="mySymbol" viewBox="0 0 20 20"> + <rect fill="lime" x="50%" height="20px" width="3%"/> + </symbol> + </defs> + <rect width="100%" height="100%" fill="lime"/> + <svg viewBox="0 0 20 20"> + <rect fill="red" x="50%" height="20px" width="2%"/> + </svg> + <svg> + <use href="#mySymbol"/> + </svg> +</svg>
--- a/layout/svg/nsCSSClipPathInstance.cpp +++ b/layout/svg/nsCSSClipPathInstance.cpp @@ -4,17 +4,16 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // Main header first: #include "nsCSSClipPathInstance.h" #include "gfx2DGlue.h" #include "gfxContext.h" #include "gfxPlatform.h" -#include "mozilla/dom/SVGSVGElement.h" #include "mozilla/gfx/2D.h" #include "mozilla/gfx/PathHelpers.h" #include "mozilla/ShapeUtils.h" #include "nsCSSRendering.h" #include "nsIFrame.h" #include "nsLayoutUtils.h" #include "nsRuleNode.h" #include "nsSVGElement.h"
--- a/layout/svg/nsSVGImageFrame.cpp +++ b/layout/svg/nsSVGImageFrame.cpp @@ -11,17 +11,16 @@ #include "mozilla/gfx/2D.h" #include "imgIContainer.h" #include "nsContainerFrame.h" #include "nsIDOMMutationEvent.h" #include "nsIImageLoadingContent.h" #include "nsLayoutUtils.h" #include "imgINotificationObserver.h" #include "SVGObserverUtils.h" -#include "mozilla/dom/SVGSVGElement.h" #include "nsSVGUtils.h" #include "SVGContentUtils.h" #include "SVGGeometryFrame.h" #include "SVGImageContext.h" #include "mozilla/dom/SVGImageElement.h" #include "nsContentUtils.h" #include "nsIReflowCallback.h" #include "mozilla/Unused.h"
--- a/layout/svg/nsSVGImageFrame.h +++ b/layout/svg/nsSVGImageFrame.h @@ -12,17 +12,16 @@ #include "mozilla/gfx/2D.h" #include "imgIContainer.h" #include "nsContainerFrame.h" #include "nsIDOMMutationEvent.h" #include "nsIImageLoadingContent.h" #include "nsLayoutUtils.h" #include "imgINotificationObserver.h" #include "SVGObserverUtils.h" -#include "mozilla/dom/SVGSVGElement.h" #include "nsSVGUtils.h" #include "SVGContentUtils.h" #include "SVGGeometryFrame.h" #include "SVGImageContext.h" #include "mozilla/dom/SVGImageElement.h" #include "nsContentUtils.h" #include "nsIReflowCallback.h" #include "mozilla/Unused.h"
--- a/layout/svg/nsSVGMarkerFrame.cpp +++ b/layout/svg/nsSVGMarkerFrame.cpp @@ -189,17 +189,17 @@ nsSVGMarkerFrame::GetMarkBBoxContributio // We need to include zero width/height vertical/horizontal lines, so we have // to use UnionEdges. bbox.UnionEdges(child->GetBBoxContribution(tm, aFlags)); return bbox; } void -nsSVGMarkerFrame::SetParentCoordCtxProvider(SVGSVGElement *aContext) +nsSVGMarkerFrame::SetParentCoordCtxProvider(SVGViewportElement *aContext) { SVGMarkerElement *marker = static_cast<SVGMarkerElement*>(GetContent()); marker->SetParentCoordCtxProvider(aContext); } void nsSVGMarkerFrame::AppendDirectlyOwnedAnonBoxes(nsTArray<OwnedAnonBox>& aResult) { @@ -214,17 +214,17 @@ nsSVGMarkerFrame::AutoMarkerReferencer:: SVGGeometryFrame *aMarkedFrame MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL) : mFrame(aFrame) { MOZ_GUARD_OBJECT_NOTIFIER_INIT; mFrame->mInUse = true; mFrame->mMarkedFrame = aMarkedFrame; - SVGSVGElement *ctx = + SVGViewportElement *ctx = static_cast<nsSVGElement*>(aMarkedFrame->GetContent())->GetCtx(); mFrame->SetParentCoordCtxProvider(ctx); } nsSVGMarkerFrame::AutoMarkerReferencer::~AutoMarkerReferencer() { mFrame->SetParentCoordCtxProvider(nullptr);
--- a/layout/svg/nsSVGMarkerFrame.h +++ b/layout/svg/nsSVGMarkerFrame.h @@ -15,17 +15,17 @@ #include "nsSVGContainerFrame.h" #include "nsSVGUtils.h" class gfxContext; namespace mozilla { class SVGGeometryFrame; namespace dom { -class SVGSVGElement; +class SVGViewportElement; } // namespace dom } // namespace mozilla struct nsSVGMark; class nsSVGMarkerFrame final : public nsSVGContainerFrame { typedef mozilla::image::imgDrawingParams imgDrawingParams; @@ -113,17 +113,17 @@ private: MOZ_GUARD_OBJECT_NOTIFIER_PARAM); ~AutoMarkerReferencer(); private: nsSVGMarkerFrame *mFrame; MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER }; // nsSVGMarkerFrame methods: - void SetParentCoordCtxProvider(mozilla::dom::SVGSVGElement *aContext); + void SetParentCoordCtxProvider(mozilla::dom::SVGViewportElement *aContext); // recursion prevention flag bool mInUse; // second recursion prevention flag, for GetCanvasTM() bool mInUse2; };
--- a/layout/svg/nsSVGPatternFrame.cpp +++ b/layout/svg/nsSVGPatternFrame.cpp @@ -655,17 +655,17 @@ nsSVGPatternFrame::GetPatternRect(uint16 gfxMatrix nsSVGPatternFrame::ConstructCTM(const nsSVGViewBox& aViewBox, uint16_t aPatternContentUnits, uint16_t aPatternUnits, const gfxRect &callerBBox, const Matrix &callerCTM, nsIFrame *aTarget) { - SVGSVGElement *ctx = nullptr; + SVGViewportElement *ctx = nullptr; nsIContent* targetContent = aTarget->GetContent(); gfxFloat scaleX, scaleY; // The objectBoundingBox conversion must be handled in the CTM: if (IncludeBBoxScale(aViewBox, aPatternContentUnits, aPatternUnits)) { scaleX = callerBBox.Width(); scaleY = callerBBox.Height(); } else {
--- a/layout/svg/nsSVGUtils.cpp +++ b/layout/svg/nsSVGUtils.cpp @@ -44,17 +44,17 @@ #include "nsSVGLength2.h" #include "nsSVGMaskFrame.h" #include "nsSVGOuterSVGFrame.h" #include "mozilla/dom/SVGClipPathElement.h" #include "mozilla/dom/SVGPathElement.h" #include "SVGGeometryElement.h" #include "SVGGeometryFrame.h" #include "nsSVGPaintServerFrame.h" -#include "mozilla/dom/SVGSVGElement.h" +#include "mozilla/dom/SVGViewportElement.h" #include "nsTextFrame.h" #include "SVGContentUtils.h" #include "SVGTextFrame.h" #include "mozilla/Unused.h" using namespace mozilla; using namespace mozilla::dom; using namespace mozilla::gfx; @@ -285,17 +285,17 @@ nsSVGUtils::NotifyAncestorsOfFilterRegio Size nsSVGUtils::GetContextSize(const nsIFrame* aFrame) { Size size; MOZ_ASSERT(aFrame->GetContent()->IsSVGElement(), "bad cast"); const nsSVGElement* element = static_cast<nsSVGElement*>(aFrame->GetContent()); - SVGSVGElement* ctx = element->GetCtx(); + SVGViewportElement* ctx = element->GetCtx(); if (ctx) { size.width = ctx->GetLength(SVGContentUtils::X); size.height = ctx->GetLength(SVGContentUtils::Y); } return size; } float @@ -318,17 +318,17 @@ nsSVGUtils::ObjectSpace(const gfxRect &a NS_NOTREACHED("unexpected ctx type"); axis = 0.0f; break; } if (aLength->IsPercentage()) { // Multiply first to avoid precision errors: return axis * aLength->GetAnimValInSpecifiedUnits() / 100; } - return aLength->GetAnimValue(static_cast<SVGSVGElement*>(nullptr)) * axis; + return aLength->GetAnimValue(static_cast<SVGViewportElement*>(nullptr)) * axis; } float nsSVGUtils::UserSpace(nsSVGElement *aSVGElement, const nsSVGLength2 *aLength) { return aLength->GetAnimValue(aSVGElement); }
--- a/python/mozboot/mozboot/osx.py +++ b/python/mozboot/mozboot/osx.py @@ -370,17 +370,17 @@ class OSXBootstrapper(BaseBootstrapper): missing = [package for package in packages if package not in installed] if missing: print(PACKAGE_MANAGER_PACKAGES % ('MacPorts',)) self.run_as_root([self.port, '-v', 'install'] + missing) def ensure_macports_system_packages(self): packages = [ 'python27', - 'py27-readline', + 'py27-gnureadline', 'mercurial', 'autoconf213', 'gnutar', 'watchman', ] self._ensure_macports_packages(packages) self.run_as_root([self.port, 'select', '--set', 'python', 'python27'])
--- a/security/sandbox/win/src/sandboxbroker/sandboxBroker.cpp +++ b/security/sandbox/win/src/sandboxbroker/sandboxBroker.cpp @@ -2,16 +2,17 @@ /* vim: set ts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "sandboxBroker.h" #include <string> +#include <vector> #include "base/win/windows_version.h" #include "mozilla/Assertions.h" #include "mozilla/ClearOnShutdown.h" #include "mozilla/Logging.h" #include "mozilla/NSPRLogModulesParser.h" #include "mozilla/UniquePtr.h" #include "mozilla/Telemetry.h" @@ -23,20 +24,36 @@ #include "nsIProperties.h" #include "nsServiceManagerUtils.h" #include "nsString.h" #include "nsTHashtable.h" #include "sandbox/win/src/sandbox.h" #include "sandbox/win/src/security_level.h" #include "WinUtils.h" -// We're just blocking one DLL for the moment because of problems with the -// Alternate Desktop. If and when we expand this we'll make this a static list -// and add checking to see if DLL is loaded in the parent. -#define WEBROOT_DLL L"WRusr.dll" +// This list of DLLs have been found to cause instability in sandboxed child +// processes and so they will be unloaded if they attempt to load. +const std::vector<std::wstring> kDllsToUnload = { + // HitmanPro - SurfRight now part of Sophos (bug 1400637) + L"hmpalert.dll", + + // K7 Computing (bug 1400637) + L"k7pswsen.dll", + + // Symantec (bug 1400637) + L"prntm64.dll", + L"sysfer.dll", + + // Avast Antivirus (bug 1400637) + L"snxhk64.dll", + L"snxhk.dll", + + // Webroot SecureAnywhere (bug 1400637) + L"wrusr.dll", +}; namespace mozilla { sandbox::BrokerServices *SandboxBroker::sBrokerService = nullptr; // This is set to true in Initialize when our exe file name has a drive type of // DRIVE_REMOTE, so that we can tailor the sandbox policy as some settings break @@ -211,19 +228,30 @@ SandboxBroker::LaunchApp(const wchar_t * } logFileName = _wgetenv(L"NSPR_LOG_FILE"); if (logFileName) { mPolicy->AddRule(sandbox::TargetPolicy::SUBSYS_FILES, sandbox::TargetPolicy::FILES_ALLOW_ANY, logFileName); } + // Add DLLs to the policy that have been found to cause instability with the + // sandbox, so that they will be unloaded when they attempt to load. + sandbox::ResultCode result; + for (std::wstring dllToUnload : kDllsToUnload) { + // Similar to Chromium, we only add a DLL if it is loaded in this process. + if (::GetModuleHandleW(dllToUnload.c_str())) { + result = mPolicy->AddDllToUnload(dllToUnload.c_str()); + MOZ_RELEASE_ASSERT(sandbox::SBOX_ALL_OK == result, + "AddDllToUnload should never fail, what happened?"); + } + } + // Ceate the sandboxed process PROCESS_INFORMATION targetInfo = {0}; - sandbox::ResultCode result; sandbox::ResultCode last_warning = sandbox::SBOX_ALL_OK; DWORD last_error = ERROR_SUCCESS; result = sBrokerService->SpawnTarget(aPath, aArguments, mPolicy, &last_warning, &last_error, &targetInfo); if (sandbox::SBOX_ALL_OK != result) { nsAutoCString key; key.AppendASCII(XRE_ChildProcessTypeToString(aProcessType)); key.AppendLiteral("/0x"); @@ -440,22 +468,16 @@ SandboxBroker::SetSecurityLevelForConten sandbox::MITIGATION_DEP | sandbox::MITIGATION_EXTENSION_POINT_DISABLE; if (aSandboxLevel > 3) { result = mPolicy->SetAlternateDesktop(false); MOZ_RELEASE_ASSERT(sandbox::SBOX_ALL_OK == result, "Failed to create alternate desktop for sandbox."); - // Webroot SecureAnywhere causes crashes when we use an Alternate Desktop, - // so block the DLL from loading in the child process. (bug 1400637) - result = mPolicy->AddDllToUnload(WEBROOT_DLL); - MOZ_RELEASE_ASSERT(sandbox::SBOX_ALL_OK == result, - "AddDllToUnload should never fail, what happened?"); - mitigations |= sandbox::MITIGATION_IMAGE_LOAD_NO_LOW_LABEL; // If we're running from a network drive then we can't block loading from // remote locations. if (!sRunningFromNetworkDrive) { mitigations |= sandbox::MITIGATION_IMAGE_LOAD_NO_REMOTE; } } @@ -828,22 +850,16 @@ SandboxBroker::SetSecurityLevelForGMPlug result = mPolicy->SetTokenLevel(sandbox::USER_RESTRICTED_SAME_ACCESS, level); SANDBOX_ENSURE_SUCCESS(result, "SetTokenLevel should never fail with these arguments, what happened?"); result = mPolicy->SetAlternateDesktop(true); SANDBOX_ENSURE_SUCCESS(result, "Failed to create alternate desktop for sandbox."); - // Webroot SecureAnywhere causes crashes when we use an Alternate Desktop, - // so block the DLL from loading in the child process. (bug 1400637) - result = mPolicy->AddDllToUnload(WEBROOT_DLL); - MOZ_RELEASE_ASSERT(sandbox::SBOX_ALL_OK == result, - "AddDllToUnload should never fail, what happened?"); - result = mPolicy->SetIntegrityLevel(sandbox::INTEGRITY_LEVEL_LOW); MOZ_ASSERT(sandbox::SBOX_ALL_OK == result, "SetIntegrityLevel should never fail with these arguments, what happened?"); result = mPolicy->SetDelayedIntegrityLevel(sandbox::INTEGRITY_LEVEL_UNTRUSTED); SANDBOX_ENSURE_SUCCESS(result, "SetIntegrityLevel should never fail with these arguments, what happened?");