author | Phil Ringnalda <philringnalda@gmail.com> |
Sat, 28 Jun 2014 17:39:03 -0700 | |
changeset 212150 | afa67a2f790564db49e3ccd9ad9d2d91c9524302 |
parent 212078 | 6ee5583b0fa6b4d6326205450370fea6bcbeea50 (current diff) |
parent 212149 | 5c88c5b4fe0791233b30ba503739894aaea7ebf5 (diff) |
child 212160 | 613ac64b87fe14560a7ecd21f501c6f44356f974 |
child 212201 | 5a63232687d10d0774032472ad8b0f5ee06885f4 |
child 212214 | 60468194f3d8b94df5c644b982621ba2948974e4 |
push id | 3857 |
push user | raliiev@mozilla.com |
push date | Tue, 02 Sep 2014 16:39:23 +0000 |
treeherder | mozilla-beta@5638b907b505 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | merge |
milestone | 33.0a1 |
first release with | nightly linux32
afa67a2f7905
/
33.0a1
/
20140629030206
/
files
nightly linux64
afa67a2f7905
/
33.0a1
/
20140629030206
/
files
nightly mac
afa67a2f7905
/
33.0a1
/
20140629030206
/
files
nightly win32
afa67a2f7905
/
33.0a1
/
20140629030206
/
files
nightly win64
afa67a2f7905
/
33.0a1
/
20140629030206
/
files
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
releases | nightly linux32
33.0a1
/
20140629030206
/
pushlog to previous
nightly linux64
33.0a1
/
20140629030206
/
pushlog to previous
nightly mac
33.0a1
/
20140629030206
/
pushlog to previous
nightly win32
33.0a1
/
20140629030206
/
pushlog to previous
nightly win64
33.0a1
/
20140629030206
/
pushlog to previous
|
dom/interfaces/xpath/nsIDOMNSXPathExpression.idl | file | annotate | diff | comparison | revisions | |
dom/interfaces/xpath/nsIDOMXPathExpression.idl | file | annotate | diff | comparison | revisions | |
dom/xslt/xpath/nsXPathExpression.cpp | file | annotate | diff | comparison | revisions | |
dom/xslt/xpath/nsXPathExpression.h | file | annotate | diff | comparison | revisions |
--- a/.hgignore +++ b/.hgignore @@ -66,8 +66,12 @@ # git checkout of libstagefright ^media/libstagefright/android$ # Tag files generated by GNU Global GTAGS GRTAGS GSYMS GPATH + +# Unit tests for Loop +^browser/components/loop/standalone/content/config\.js$ +^browser/components/loop/standalone/node_modules/
--- a/content/base/public/nsIDocument.h +++ b/content/base/public/nsIDocument.h @@ -46,17 +46,16 @@ class nsIDocShell; class nsIDocumentEncoder; class nsIDocumentObserver; class nsIDOMDocument; class nsIDOMDocumentFragment; class nsIDOMDocumentType; class nsIDOMElement; class nsIDOMNodeFilter; class nsIDOMNodeList; -class nsIDOMXPathExpression; class nsIDOMXPathNSResolver; class nsIHTMLCollection; class nsILayoutHistoryState; class nsILoadContext; class nsIObjectLoadingContent; class nsIObserver; class nsIPresShell; class nsIPrincipal; @@ -117,16 +116,17 @@ class NodeIterator; class ProcessingInstruction; class StyleSheetList; class SVGDocument; class Touch; class TouchList; class TreeWalker; class UndoManager; class XPathEvaluator; +class XPathExpression; class XPathResult; template<typename> class OwningNonNull; template<typename> class Sequence; template<typename, typename> class CallbackObjectHolder; typedef CallbackObjectHolder<NodeFilter, nsIDOMNodeFilter> NodeFilterHolder; } // namespace dom } // namespace mozilla @@ -2264,17 +2264,17 @@ public: // QuerySelector and QuerySelectorAll already defined on nsINode nsINodeList* GetAnonymousNodes(Element& aElement); Element* GetAnonymousElementByAttribute(Element& aElement, const nsAString& aAttrName, const nsAString& aAttrValue); Element* GetBindingParent(nsINode& aNode); void LoadBindingDocument(const nsAString& aURI, mozilla::ErrorResult& rv); - already_AddRefed<nsIDOMXPathExpression> + mozilla::dom::XPathExpression* CreateExpression(const nsAString& aExpression, nsIDOMXPathNSResolver* aResolver, mozilla::ErrorResult& rv); already_AddRefed<nsIDOMXPathNSResolver> CreateNSResolver(nsINode* aNodeResolver, mozilla::ErrorResult& rv); already_AddRefed<mozilla::dom::XPathResult> Evaluate(JSContext* aCx, const nsAString& aExpression, nsINode* aContextNode, nsIDOMXPathNSResolver* aResolver, uint16_t aType,
--- a/content/base/src/nsCSPParser.cpp +++ b/content/base/src/nsCSPParser.cpp @@ -325,17 +325,17 @@ nsCSPParser::subHost() uint32_t charCounter = 0; while (!atEnd() && !peek(COLON) && !peek(SLASH)) { ++charCounter; while (hostChar()) { /* consume */ ++charCounter; } - if (accept(DOT) && !accept(isCharacterToken)) { + if (accept(DOT) && !hostChar()) { return false; } if (charCounter > kSubHostPathCharacterCutoff) { return false; } } return true; } @@ -361,18 +361,18 @@ nsCSPParser::host() if (!accept(DOT)) { const char16_t* params[] = { mCurToken.get() }; logWarningErrorToConsole(nsIScriptError::warningFlag, "couldntParseInvalidHost", params, ArrayLength(params)); return nullptr; } } - // Expecting at least one Character - if (!accept(isCharacterToken)) { + // Expecting at least one host-char + if (!hostChar()) { const char16_t* params[] = { mCurToken.get() }; logWarningErrorToConsole(nsIScriptError::warningFlag, "couldntParseInvalidHost", params, ArrayLength(params)); return nullptr; } // There might be several sub hosts defined. if (!subHost()) { @@ -679,16 +679,17 @@ nsCSPParser::sourceList(nsTArray<nsCSPBa { bool isNone = false; // remember, srcs start at index 1 for (uint32_t i = 1; i < mCurDir.Length(); i++) { // mCurToken is only set here and remains the current token // to be processed, which avoid passing arguments between functions. mCurToken = mCurDir[i]; + resetCurValue(); CSPPARSERLOG(("nsCSPParser::sourceList, mCurToken: %s, mCurValue: %s", NS_ConvertUTF16toUTF8(mCurToken).get(), NS_ConvertUTF16toUTF8(mCurValue).get())); // Special case handling for none: // Ignore 'none' if any other src is available. // (See http://www.w3.org/TR/CSP11/#parsing)
--- a/content/base/src/nsCSPUtils.cpp +++ b/content/base/src/nsCSPUtils.cpp @@ -766,18 +766,19 @@ nsCSPPolicy::permits(nsContentPolicyType if (defaultDir) { if (!defaultDir->permits(aUri, aNonce)) { defaultDir->toString(outViolatedDirective); return false; } return true; } - // Didn't find a directive, load is not allowed. - return false; + // unspecified default-src should default to no restrictions + // see bug 764937 + return true; } bool nsCSPPolicy::allows(nsContentPolicyType aContentType, enum CSPKeyword aKeyword, const nsAString& aHashOrNonce) const { CSPUTILSLOG(("nsCSPPolicy::allows, aKeyWord: %s, a HashOrNonce: %s",
--- a/content/base/src/nsDOMCaretPosition.cpp +++ b/content/base/src/nsDOMCaretPosition.cpp @@ -46,17 +46,17 @@ nsDOMCaretPosition::GetClientRect() cons mOffset, getter_AddRefs<nsRange>(domRange)); if (!NS_SUCCEEDED(creationRv)) { return nullptr; } NS_ASSERTION(domRange, "unable to retrieve valid dom range from CaretPosition"); - rect = domRange->GetBoundingClientRect(); + rect = domRange->GetBoundingClientRect(false); return rect.forget(); } JSObject* nsDOMCaretPosition::WrapObject(JSContext *aCx) { return mozilla::dom::CaretPositionBinding::Wrap(aCx, this);
--- a/content/base/src/nsDocument.cpp +++ b/content/base/src/nsDocument.cpp @@ -97,17 +97,16 @@ // for radio group stuff #include "nsIDOMHTMLInputElement.h" #include "nsIRadioVisitor.h" #include "nsIFormControl.h" #include "nsBidiUtils.h" #include "nsIDOMUserDataHandler.h" -#include "nsIDOMXPathExpression.h" #include "nsIDOMXPathNSResolver.h" #include "nsIParserService.h" #include "nsContentCreatorFunctions.h" #include "nsIScriptContext.h" #include "nsBindingManager.h" #include "nsIDOMHTMLDocument.h" #include "nsHTMLDocument.h" @@ -12036,17 +12035,17 @@ nsIDocument::Constructor(const GlobalObj } nsCOMPtr<nsIDocument> doc = do_QueryInterface(document); doc->SetReadyStateInternal(nsIDocument::READYSTATE_COMPLETE); return doc.forget(); } -already_AddRefed<nsIDOMXPathExpression> +XPathExpression* nsIDocument::CreateExpression(const nsAString& aExpression, nsIDOMXPathNSResolver* aResolver, ErrorResult& rv) { return XPathEvaluator()->CreateExpression(aExpression, aResolver, rv); } already_AddRefed<nsIDOMXPathNSResolver> @@ -12062,24 +12061,16 @@ nsIDocument::Evaluate(JSContext* aCx, co uint16_t aType, JS::Handle<JSObject*> aResult, ErrorResult& rv) { return XPathEvaluator()->Evaluate(aCx, aExpression, aContextNode, aResolver, aType, aResult, rv); } NS_IMETHODIMP -nsDocument::CreateExpression(const nsAString& aExpression, - nsIDOMXPathNSResolver* aResolver, - nsIDOMXPathExpression** aResult) -{ - return XPathEvaluator()->CreateExpression(aExpression, aResolver, aResult); -} - -NS_IMETHODIMP nsDocument::CreateNSResolver(nsIDOMNode* aNodeResolver, nsIDOMXPathNSResolver** aResult) { return XPathEvaluator()->CreateNSResolver(aNodeResolver, aResult); } NS_IMETHODIMP nsDocument::Evaluate(const nsAString& aExpression, nsIDOMNode* aContextNode,
--- a/content/base/src/nsRange.cpp +++ b/content/base/src/nsRange.cpp @@ -2720,27 +2720,33 @@ nsRange::CreateContextualFragment(const } return nsContentUtils::CreateContextualFragment(mStartParent, aFragment, false, aRv); } static void ExtractRectFromOffset(nsIFrame* aFrame, const nsIFrame* aRelativeTo, - const int32_t aOffset, nsRect* aR, bool aKeepLeft) + const int32_t aOffset, nsRect* aR, bool aKeepLeft, + bool aClampToEdge) { nsPoint point; aFrame->GetPointFromOffset(aOffset, &point); point += aFrame->GetOffsetTo(aRelativeTo); - //given a point.x, extract left or right portion of rect aR - //point.x has to be within this rect - NS_ASSERTION(aR->x <= point.x && point.x <= aR->XMost(), - "point.x should not be outside of rect r"); + if (!aClampToEdge && !aR->Contains(point)) { + aR->width = 0; + aR->x = point.x; + return; + } + + if (aClampToEdge) { + point = aR->ClampPoint(point); + } if (aKeepLeft) { aR->width = point.x - aR->x; } else { aR->width = aR->XMost() - point.x; aR->x = point.x; } } @@ -2757,50 +2763,52 @@ GetTextFrameForContent(nsIContent* aCont if (frame && frame->GetType() == nsGkAtoms::textFrame) { return static_cast<nsTextFrame*>(frame); } } return nullptr; } static nsresult GetPartialTextRect(nsLayoutUtils::RectCallback* aCallback, - nsIContent* aContent, int32_t aStartOffset, int32_t aEndOffset) + nsIContent* aContent, int32_t aStartOffset, + int32_t aEndOffset, bool aClampToEdge) { nsTextFrame* textFrame = GetTextFrameForContent(aContent); if (textFrame) { nsIFrame* relativeTo = nsLayoutUtils::GetContainingBlockForClientRect(textFrame); for (nsTextFrame* f = textFrame; f; f = static_cast<nsTextFrame*>(f->GetNextContinuation())) { int32_t fstart = f->GetContentOffset(), fend = f->GetContentEnd(); if (fend <= aStartOffset || fstart >= aEndOffset) continue; // overlapping with the offset we want f->EnsureTextRun(nsTextFrame::eInflated); NS_ENSURE_TRUE(f->GetTextRun(nsTextFrame::eInflated), NS_ERROR_OUT_OF_MEMORY); bool rtl = f->GetTextRun(nsTextFrame::eInflated)->IsRightToLeft(); nsRect r(f->GetOffsetTo(relativeTo), f->GetSize()); if (fstart < aStartOffset) { // aStartOffset is within this frame - ExtractRectFromOffset(f, relativeTo, aStartOffset, &r, rtl); + ExtractRectFromOffset(f, relativeTo, aStartOffset, &r, rtl, aClampToEdge); } if (fend > aEndOffset) { // aEndOffset is in the middle of this frame - ExtractRectFromOffset(f, relativeTo, aEndOffset, &r, !rtl); + ExtractRectFromOffset(f, relativeTo, aEndOffset, &r, !rtl, aClampToEdge); } aCallback->AddRect(r); } } return NS_OK; } /* static */ void nsRange::CollectClientRects(nsLayoutUtils::RectCallback* aCollector, nsRange* aRange, nsINode* aStartParent, int32_t aStartOffset, - nsINode* aEndParent, int32_t aEndOffset) + nsINode* aEndParent, int32_t aEndOffset, + bool aClampToEdge) { // Hold strong pointers across the flush nsCOMPtr<nsINode> startContainer = aStartParent; nsCOMPtr<nsINode> endContainer = aEndParent; // Flush out layout so our frames are up to date. if (!aStartParent->IsInDoc()) { return; @@ -2827,17 +2835,17 @@ nsRange::CollectClientRects(nsLayoutUtil int32_t outOffset; nsIFrame* outFrame; textFrame->GetChildFrameContainingOffset(aStartOffset, false, &outOffset, &outFrame); if (outFrame) { nsIFrame* relativeTo = nsLayoutUtils::GetContainingBlockForClientRect(outFrame); nsRect r(outFrame->GetOffsetTo(relativeTo), outFrame->GetSize()); - ExtractRectFromOffset(outFrame, relativeTo, aStartOffset, &r, false); + ExtractRectFromOffset(outFrame, relativeTo, aStartOffset, &r, false, aClampToEdge); r.width = 0; aCollector->AddRect(r); } } } return; } @@ -2846,78 +2854,78 @@ nsRange::CollectClientRects(nsLayoutUtil iter.Next(); nsCOMPtr<nsIContent> content = do_QueryInterface(node); if (!content) continue; if (content->IsNodeOfType(nsINode::eTEXT)) { if (node == startContainer) { int32_t offset = startContainer == endContainer ? aEndOffset : content->GetText()->GetLength(); - GetPartialTextRect(aCollector, content, aStartOffset, offset); + GetPartialTextRect(aCollector, content, aStartOffset, offset, aClampToEdge); continue; } else if (node == endContainer) { - GetPartialTextRect(aCollector, content, 0, aEndOffset); + GetPartialTextRect(aCollector, content, 0, aEndOffset, aClampToEdge); continue; } } nsIFrame* frame = content->GetPrimaryFrame(); if (frame) { nsLayoutUtils::GetAllInFlowRects(frame, nsLayoutUtils::GetContainingBlockForClientRect(frame), aCollector); } } while (!iter.IsDone()); } NS_IMETHODIMP nsRange::GetBoundingClientRect(nsIDOMClientRect** aResult) { - *aResult = GetBoundingClientRect().take(); + *aResult = GetBoundingClientRect(true).take(); return NS_OK; } already_AddRefed<DOMRect> -nsRange::GetBoundingClientRect() +nsRange::GetBoundingClientRect(bool aClampToEdge) { nsRefPtr<DOMRect> rect = new DOMRect(ToSupports(this)); if (!mStartParent) { return rect.forget(); } nsLayoutUtils::RectAccumulator accumulator; CollectClientRects(&accumulator, this, mStartParent, mStartOffset, - mEndParent, mEndOffset); + mEndParent, mEndOffset, aClampToEdge); nsRect r = accumulator.mResultRect.IsEmpty() ? accumulator.mFirstRect : accumulator.mResultRect; rect->SetLayoutRect(r); return rect.forget(); } NS_IMETHODIMP nsRange::GetClientRects(nsIDOMClientRectList** aResult) { - *aResult = GetClientRects().take(); + *aResult = GetClientRects(true).take(); return NS_OK; } already_AddRefed<DOMRectList> -nsRange::GetClientRects() +nsRange::GetClientRects(bool aClampToEdge) { if (!mStartParent) { return nullptr; } nsRefPtr<DOMRectList> rectList = new DOMRectList(static_cast<nsIDOMRange*>(this)); nsLayoutUtils::RectListBuilder builder(rectList); CollectClientRects(&builder, this, mStartParent, mStartOffset, - mEndParent, mEndOffset); + mEndParent, mEndOffset, aClampToEdge); return rectList.forget(); } NS_IMETHODIMP nsRange::GetUsedFontFaces(nsIDOMFontFaceList** aResult) { *aResult = nullptr;
--- a/content/base/src/nsRange.h +++ b/content/base/src/nsRange.h @@ -212,18 +212,18 @@ public: void SelectNodeContents(nsINode& aNode, ErrorResult& aErr); void SetEnd(nsINode& aNode, uint32_t aOffset, ErrorResult& aErr); void SetEndAfter(nsINode& aNode, ErrorResult& aErr); void SetEndBefore(nsINode& aNode, ErrorResult& aErr); void SetStart(nsINode& aNode, uint32_t aOffset, ErrorResult& aErr); void SetStartAfter(nsINode& aNode, ErrorResult& aErr); void SetStartBefore(nsINode& aNode, ErrorResult& aErr); void SurroundContents(nsINode& aNode, ErrorResult& aErr); - already_AddRefed<DOMRect> GetBoundingClientRect(); - already_AddRefed<DOMRectList> GetClientRects(); + already_AddRefed<DOMRect> GetBoundingClientRect(bool aClampToEdge = true); + already_AddRefed<DOMRectList> GetClientRects(bool aClampToEdge = true); nsINode* GetParentObject() const { return mOwner; } virtual JSObject* WrapObject(JSContext* cx) MOZ_OVERRIDE MOZ_FINAL; private: // no copy's or assigns nsRange(const nsRange&); nsRange& operator=(const nsRange&); @@ -254,17 +254,18 @@ public: bool *outNodeAfter); static bool IsNodeSelected(nsINode* aNode, uint32_t aStartOffset, uint32_t aEndOffset); static void CollectClientRects(nsLayoutUtils::RectCallback* aCollector, nsRange* aRange, nsINode* aStartParent, int32_t aStartOffset, - nsINode* aEndParent, int32_t aEndOffset); + nsINode* aEndParent, int32_t aEndOffset, + bool aClampToEdge); typedef nsTHashtable<nsPtrHashKey<nsRange> > RangeHashTable; protected: void RegisterCommonAncestor(nsINode* aNode); void UnregisterCommonAncestor(nsINode* aNode); nsINode* IsValidBoundary(nsINode* aNode); // CharacterDataChanged set aNotInsertedYet to true to disable an assertion
--- a/content/base/test/TestCSPParser.cpp +++ b/content/base/test/TestCSPParser.cpp @@ -390,16 +390,24 @@ nsresult TestSimplePolicies() { { " ; ; ; ; default-src abc ; ; ; ;", "default-src http://abc" }, { "script-src 'none' 'none' 'none';", "script-src 'none'" }, { "script-src http://www.example.com/path-1//", "script-src http://www.example.com" }, { "script-src http://www.example.com/path-1//path_2", "script-src http://www.example.com" }, + { "default-src 127.0.0.1", + "default-src http://127.0.0.1" }, + { "default-src 127.0.0.1:*", + "default-src http://127.0.0.1:*" }, + { "default-src -; ", + "default-src http://-" }, + { "script-src 1", + "script-src http://1" } }; uint32_t policyCount = sizeof(policies) / sizeof(PolicyTest); return runTestSuite(policies, policyCount, 1); } // ============================= TestPoliciesThatLogWarning ======================== @@ -427,18 +435,16 @@ nsresult TestBadPolicies() { { "default-src 'self", "" }, { "script-sr 'self", "" }, { "default-src 'unsafe-inlin' ", "" }, { "default-src */", "" }, { "default-src", "" }, { "", "" }, { "; ; ; ; ; ; ;", "" }, { "defaut-src asdf", "" }, - { "default-src -; ", "" }, - { "script-src 1", "" }, { "default-src: aaa", "" }, { "default-src 'unsafe-inlin' ", "" }, { "default-src :88", "" }, { "script-src abc::::::88", "" }, { "asdf http://test.com", ""}, { "script-src *.*:*", "" }, { "img-src *::88", "" }, { "object-src http://localhost:", "" },
--- a/content/base/test/mochitest.ini +++ b/content/base/test/mochitest.ini @@ -533,16 +533,17 @@ skip-if = (buildapp == 'b2g' && toolkit [test_bug811701.xhtml] [test_bug813919.html] [test_bug814576.html] [test_bug819051.html] [test_bug820909.html] [test_bug827160.html] skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s #needs plugin support # b2g(needs plugin support) b2g-debug(debug-only failure) b2g-desktop(needs plugin support) [test_bug840098.html] +[test_bug864595.html] [test_bug868999.html] [test_bug869000.html] [test_bug869002.html] [test_bug869006.html] [test_bug876282.html] [test_bug890580.html] [test_bug891952.html] [test_bug894874.html]
new file mode 100644 --- /dev/null +++ b/content/base/test/test_bug864595.html @@ -0,0 +1,34 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=864595 +--> +<head> + <title>Test for Bug 864595</title> + <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=864595">Mozilla Bug 864595</a> +<div id='editable' style='display:inline-block;'>abcd </div> +<script type="application/javascript"> +/** Test for Bug 864595 **/ +var range = document.createRange(); +var elt = document.getElementById('editable'); +var eltRect = elt.getBoundingClientRect(); + +var txtNode = elt.childNodes[0]; +range.setStart(txtNode, 0); +range.setEnd(txtNode, 5); +var rect = range.getBoundingClientRect(); +ok(rect.left >= eltRect.left && rect.right <= eltRect.right, "rect.left >= eltRect.left && rect.right <= eltRect.right"); + +/* Put caret in the space */ +var caretPosX = rect.right + 10; +var caretPosY = (rect.top + rect.bottom ) / 2; +var caretRect = document.caretPositionFromPoint(caretPosX, caretPosY).getClientRect(); +ok(caretRect.right >= rect.right, "caretRect.right >= rect.right"); + +</script> +</body> +</html>
--- a/content/media/fmp4/wmf/WMFMediaDataDecoder.h +++ b/content/media/fmp4/wmf/WMFMediaDataDecoder.h @@ -8,17 +8,19 @@ #define WMFMediaDataDecoder_h_ #include "WMF.h" #include "MP4Reader.h" #include "MFTDecoder.h" #include "mozilla/RefPtr.h" -class mp4_demuxer::MP4Sample; +namespace mp4_demuxer { +class MP4Sample; +} namespace mozilla { // Encapsulates the initialization of the MFTDecoder appropriate for decoding // a given stream, and the process of converting the IMFSample produced // by the MFT into a MediaData object. class WMFOutputSource { public:
--- a/content/xul/templates/src/nsXMLBinding.cpp +++ b/content/xul/templates/src/nsXMLBinding.cpp @@ -7,73 +7,45 @@ #include "nsXULTemplateResultXML.h" #include "nsXMLBinding.h" #include "mozilla/ErrorResult.h" #include "mozilla/dom/XPathResult.h" using namespace mozilla; using namespace mozilla::dom; -NS_IMPL_CYCLE_COLLECTING_NATIVE_ADDREF(nsXMLBindingSet) -NS_IMPL_CYCLE_COLLECTING_NATIVE_RELEASE(nsXMLBindingSet) - -NS_IMPL_CYCLE_COLLECTION_CLASS(nsXMLBindingSet) - -NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsXMLBindingSet) - nsXMLBinding* binding = tmp->mFirst; - while (binding) { - binding->mExpr = nullptr; - binding = binding->mNext; - } -NS_IMPL_CYCLE_COLLECTION_UNLINK_END - -NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsXMLBindingSet) - nsXMLBinding* binding = tmp->mFirst; - while (binding) { - NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "nsXMLBinding::mExpr"); - cb.NoteXPCOMChild(binding->mExpr); - binding = binding->mNext; - } -NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END - -NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(nsXMLBindingSet, AddRef) -NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(nsXMLBindingSet, Release) - nsXMLBindingSet::~nsXMLBindingSet() {} -nsresult -nsXMLBindingSet::AddBinding(nsIAtom* aVar, nsIDOMXPathExpression* aExpr) +void +nsXMLBindingSet::AddBinding(nsIAtom* aVar, nsAutoPtr<XPathExpression>&& aExpr) { - nsAutoPtr<nsXMLBinding> newbinding(new nsXMLBinding(aVar, aExpr)); - NS_ENSURE_TRUE(newbinding, NS_ERROR_OUT_OF_MEMORY); + nsAutoPtr<nsXMLBinding> newbinding(new nsXMLBinding(aVar, Move(aExpr))); if (mFirst) { nsXMLBinding* binding = mFirst; while (binding) { // if the target variable is already used in a binding, ignore it // since it won't be useful for anything if (binding->mVar == aVar) - return NS_OK; + return; // add the binding at the end of the list if (!binding->mNext) { binding->mNext = newbinding; - break; + return; } binding = binding->mNext; } } else { mFirst = newbinding; } - - return NS_OK; } int32_t nsXMLBindingSet::LookupTargetIndex(nsIAtom* aTargetVariable, nsXMLBinding** aBinding) { int32_t idx = 0; nsXMLBinding* binding = mFirst; @@ -97,49 +69,40 @@ nsXMLBindingValues::GetAssignmentFor(nsX int32_t aIndex, uint16_t aType) { XPathResult* value = mValues.SafeElementAt(aIndex); if (value) { return value; } - nsCOMPtr<nsIDOMNode> contextNode; - aResult->GetNode(getter_AddRefs(contextNode)); + nsINode* contextNode = aResult->Node(); if (!contextNode) { return nullptr; } mValues.EnsureLengthAtLeast(aIndex + 1); - nsCOMPtr<nsISupports> resultsupports; - aBinding->mExpr->Evaluate(contextNode, aType, - nullptr, getter_AddRefs(resultsupports)); - - mValues.ReplaceElementAt(aIndex, XPathResult::FromSupports(resultsupports)); + ErrorResult ignored; + mValues[aIndex] = aBinding->mExpr->Evaluate(*contextNode, aType, nullptr, + ignored); return mValues[aIndex]; } -void +nsINode* nsXMLBindingValues::GetNodeAssignmentFor(nsXULTemplateResultXML* aResult, nsXMLBinding* aBinding, - int32_t aIndex, - nsIDOMNode** aNode) + int32_t aIndex) { XPathResult* result = GetAssignmentFor(aResult, aBinding, aIndex, XPathResult::FIRST_ORDERED_NODE_TYPE); - nsINode* node; ErrorResult rv; - if (result && (node = result->GetSingleNodeValue(rv))) { - CallQueryInterface(node, aNode); - } else { - *aNode = nullptr; - } + return result ? result->GetSingleNodeValue(rv) : nullptr; } void nsXMLBindingValues::GetStringAssignmentFor(nsXULTemplateResultXML* aResult, nsXMLBinding* aBinding, int32_t aIndex, nsAString& aValue) {
--- a/content/xul/templates/src/nsXMLBinding.h +++ b/content/xul/templates/src/nsXMLBinding.h @@ -3,19 +3,20 @@ * 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 nsXMLBinding_h__ #define nsXMLBinding_h__ #include "nsAutoPtr.h" #include "nsIAtom.h" -#include "nsCycleCollectionParticipant.h" #include "mozilla/Attributes.h" +#include "mozilla/dom/XPathExpression.h" +class nsINode; class nsXULTemplateResultXML; class nsXMLBindingValues; namespace mozilla { namespace dom { class XPathResult; } } @@ -23,21 +24,21 @@ class XPathResult; * Classes related to storing bindings for XML handling. */ /** * a <binding> description */ struct nsXMLBinding { nsCOMPtr<nsIAtom> mVar; - nsCOMPtr<nsIDOMXPathExpression> mExpr; + nsAutoPtr<mozilla::dom::XPathExpression> mExpr; nsAutoPtr<nsXMLBinding> mNext; - nsXMLBinding(nsIAtom* aVar, nsIDOMXPathExpression* aExpr) + nsXMLBinding(nsIAtom* aVar, nsAutoPtr<mozilla::dom::XPathExpression>&& aExpr) : mVar(aVar), mExpr(aExpr), mNext(nullptr) { MOZ_COUNT_CTOR(nsXMLBinding); } ~nsXMLBinding() { MOZ_COUNT_DTOR(nsXMLBinding); @@ -48,36 +49,26 @@ struct nsXMLBinding { * a collection of <binding> descriptors. This object is refcounted by * nsXMLBindingValues objects and the query processor. */ class nsXMLBindingSet MOZ_FINAL { ~nsXMLBindingSet(); public: - - // results hold a reference to a binding set in their - // nsXMLBindingValues fields - nsCycleCollectingAutoRefCnt mRefCnt; - // pointer to the first binding in a linked list nsAutoPtr<nsXMLBinding> mFirst; -public: - - NS_METHOD_(MozExternalRefCountType) AddRef(); - NS_METHOD_(MozExternalRefCountType) Release(); - NS_DECL_OWNINGTHREAD - NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(nsXMLBindingSet) + NS_INLINE_DECL_REFCOUNTING(nsXMLBindingSet); /** * Add a binding to the set */ - nsresult - AddBinding(nsIAtom* aVar, nsIDOMXPathExpression* aExpr); + void + AddBinding(nsIAtom* aVar, nsAutoPtr<mozilla::dom::XPathExpression>&& aExpr); /** * The nsXMLBindingValues class stores an array of values, one for each * target symbol that could be set by the bindings in the set. * LookupTargetIndex determines the index into the array for a given * target symbol. */ int32_t @@ -126,21 +117,20 @@ public: * aType the type of result expected */ mozilla::dom::XPathResult* GetAssignmentFor(nsXULTemplateResultXML* aResult, nsXMLBinding* aBinding, int32_t idx, uint16_t type); - void + nsINode* GetNodeAssignmentFor(nsXULTemplateResultXML* aResult, nsXMLBinding* aBinding, - int32_t idx, - nsIDOMNode** aValue); + int32_t idx); void GetStringAssignmentFor(nsXULTemplateResultXML* aResult, nsXMLBinding* aBinding, int32_t idx, nsAString& aValue); };
--- a/content/xul/templates/src/nsXULTemplateQueryProcessorXML.cpp +++ b/content/xul/templates/src/nsXULTemplateQueryProcessorXML.cpp @@ -16,20 +16,21 @@ #include "nsGkAtoms.h" #include "nsIURI.h" #include "nsIArray.h" #include "nsIScriptContext.h" #include "nsArrayUtils.h" #include "nsPIDOMWindow.h" #include "nsXULContentUtils.h" #include "nsXMLHttpRequest.h" - +#include "mozilla/dom/XPathEvaluator.h" #include "nsXULTemplateQueryProcessorXML.h" #include "nsXULTemplateResultXML.h" #include "nsXULSortService.h" +#include "mozilla/dom/Element.h" using namespace mozilla; using namespace mozilla::dom; NS_IMPL_ISUPPORTS(nsXMLQuery, nsXMLQuery) //---------------------------------------------------------------------- // @@ -48,25 +49,23 @@ nsXULTemplateResultSetXML::HasMoreElemen *aResult = !rv.Failed() && mPosition < length; return NS_OK; } NS_IMETHODIMP nsXULTemplateResultSetXML::GetNext(nsISupports **aResult) { ErrorResult rv; - nsCOMPtr<nsIDOMNode> node = - do_QueryInterface(mResults->SnapshotItem(mPosition, rv)); + nsINode* node = mResults->SnapshotItem(mPosition, rv); if (rv.Failed()) { return rv.ErrorCode(); } nsXULTemplateResultXML* result = - new nsXULTemplateResultXML(mQuery, node, mBindingSet); - NS_ENSURE_TRUE(result, NS_ERROR_OUT_OF_MEMORY); + new nsXULTemplateResultXML(mQuery, node->AsContent(), mBindingSet); ++mPosition; *aResult = result; NS_ADDREF(result); return NS_OK; } @@ -77,18 +76,16 @@ nsXULTemplateResultSetXML::GetNext(nsISu static PLDHashOperator TraverseRuleToBindingsMap(nsISupports* aKey, nsXMLBindingSet* aMatch, void* aContext) { nsCycleCollectionTraversalCallback *cb = static_cast<nsCycleCollectionTraversalCallback*>(aContext); NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb, "mRuleToBindingsMap key"); cb->NoteXPCOMChild(aKey); - NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb, "mRuleToBindingsMap value"); - cb->NoteNativeChild(aMatch, NS_CYCLE_COLLECTION_PARTICIPANT(nsXMLBindingSet)); return PL_DHASH_NEXT; } NS_IMPL_CYCLE_COLLECTION_CLASS(nsXULTemplateQueryProcessorXML) NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsXULTemplateQueryProcessorXML) tmp->mRuleToBindingsMap.Clear(); NS_IMPL_CYCLE_COLLECTION_UNLINK(mRoot) @@ -205,25 +202,24 @@ NS_IMETHODIMP nsXULTemplateQueryProcessorXML::InitializeForBuilding(nsISupports* aDatasource, nsIXULTemplateBuilder* aBuilder, nsIDOMNode* aRootNode) { if (mGenerationStarted) return NS_ERROR_UNEXPECTED; // the datasource is either a document or a DOM element - nsCOMPtr<nsIDOMDocument> doc = do_QueryInterface(aDatasource); + nsCOMPtr<nsIDocument> doc = do_QueryInterface(aDatasource); if (doc) - doc->GetDocumentElement(getter_AddRefs(mRoot)); + mRoot = doc->GetDocumentElement(); else mRoot = do_QueryInterface(aDatasource); NS_ENSURE_STATE(mRoot); - mEvaluator = do_CreateInstance("@mozilla.org/dom/xpath-evaluator;1"); - NS_ENSURE_TRUE(mEvaluator, NS_ERROR_OUT_OF_MEMORY); + mEvaluator = new XPathEvaluator(); return NS_OK; } NS_IMETHODIMP nsXULTemplateQueryProcessorXML::Done() { mGenerationStarted = false; @@ -235,76 +231,70 @@ nsXULTemplateQueryProcessorXML::Done() NS_IMETHODIMP nsXULTemplateQueryProcessorXML::CompileQuery(nsIXULTemplateBuilder* aBuilder, nsIDOMNode* aQueryNode, nsIAtom* aRefVariable, nsIAtom* aMemberVariable, nsISupports** _retval) { - nsresult rv = NS_OK; - *_retval = nullptr; nsCOMPtr<nsIContent> content = do_QueryInterface(aQueryNode); nsAutoString expr; content->GetAttr(kNameSpaceID_None, nsGkAtoms::expr, expr); // if an expression is not specified, then the default is to // just take all of the children if (expr.IsEmpty()) expr.Assign('*'); - nsCOMPtr<nsIDOMXPathExpression> compiledexpr; - rv = CreateExpression(expr, aQueryNode, getter_AddRefs(compiledexpr)); - if (NS_FAILED(rv)) { + ErrorResult rv; + nsAutoPtr<XPathExpression> compiledexpr; + compiledexpr = CreateExpression(expr, content, rv); + if (rv.Failed()) { nsXULContentUtils::LogTemplateError(ERROR_TEMPLATE_BAD_XPATH); - return rv; + return rv.ErrorCode(); } nsRefPtr<nsXMLQuery> query = - new nsXMLQuery(this, aMemberVariable, compiledexpr); - NS_ENSURE_TRUE(query, NS_ERROR_OUT_OF_MEMORY); + new nsXMLQuery(this, aMemberVariable, Move(compiledexpr)); for (nsIContent* condition = content->GetFirstChild(); condition; condition = condition->GetNextSibling()) { if (condition->NodeInfo()->Equals(nsGkAtoms::assign, kNameSpaceID_XUL)) { nsAutoString var; condition->GetAttr(kNameSpaceID_None, nsGkAtoms::var, var); nsAutoString expr; condition->GetAttr(kNameSpaceID_None, nsGkAtoms::expr, expr); // ignore assignments without a variable or an expression if (!var.IsEmpty() && !expr.IsEmpty()) { - nsCOMPtr<nsIDOMNode> conditionNode = - do_QueryInterface(condition); - rv = CreateExpression(expr, conditionNode, - getter_AddRefs(compiledexpr)); - if (NS_FAILED(rv)) { + compiledexpr = CreateExpression(expr, condition, rv); + if (rv.Failed()) { nsXULContentUtils::LogTemplateError(ERROR_TEMPLATE_BAD_ASSIGN_XPATH); - return rv; + return rv.ErrorCode(); } nsCOMPtr<nsIAtom> varatom = do_GetAtom(var); - rv = query->AddBinding(varatom, compiledexpr); - NS_ENSURE_SUCCESS(rv, rv); + query->AddBinding(varatom, Move(compiledexpr)); } } } *_retval = query; NS_ADDREF(*_retval); - return rv; + return NS_OK; } NS_IMETHODIMP nsXULTemplateQueryProcessorXML::GenerateResults(nsISupports* aDatasource, nsIXULTemplateResult* aRef, nsISupports* aQuery, nsISimpleEnumerator** aResults) { @@ -313,39 +303,39 @@ nsXULTemplateQueryProcessorXML::Generate mGenerationStarted = true; nsCOMPtr<nsXMLQuery> xmlquery = do_QueryInterface(aQuery); if (!xmlquery) return NS_ERROR_INVALID_ARG; nsCOMPtr<nsISupports> supports; - nsCOMPtr<nsIDOMNode> context; + nsCOMPtr<nsINode> context; if (aRef) aRef->GetBindingObjectFor(xmlquery->GetMemberVariable(), getter_AddRefs(supports)); context = do_QueryInterface(supports); if (!context) context = mRoot; - nsIDOMXPathExpression* expr = xmlquery->GetResultsExpression(); + XPathExpression* expr = xmlquery->GetResultsExpression(); if (!expr) return NS_ERROR_FAILURE; - nsCOMPtr<nsISupports> exprsupportsresults; - nsresult rv = expr->Evaluate(context, - XPathResult::ORDERED_NODE_SNAPSHOT_TYPE, - nullptr, getter_AddRefs(exprsupportsresults)); - NS_ENSURE_SUCCESS(rv, rv); + ErrorResult rv; + nsRefPtr<XPathResult> exprresults = + expr->Evaluate(*context, XPathResult::ORDERED_NODE_SNAPSHOT_TYPE, + nullptr, rv); + if (rv.Failed()) { + return rv.ErrorCode(); + } - XPathResult* exprresults = XPathResult::FromSupports(exprsupportsresults); nsXULTemplateResultSetXML* results = - new nsXULTemplateResultSetXML(xmlquery, exprresults, + new nsXULTemplateResultSetXML(xmlquery, exprresults.forget(), xmlquery->GetBindingSet()); - NS_ENSURE_TRUE(results, NS_ERROR_OUT_OF_MEMORY); *aResults = results; NS_ADDREF(*aResults); return NS_OK; } NS_IMETHODIMP @@ -358,52 +348,51 @@ nsXULTemplateQueryProcessorXML::AddBindi return NS_ERROR_FAILURE; nsRefPtr<nsXMLBindingSet> bindings = mRuleToBindingsMap.GetWeak(aRuleNode); if (!bindings) { bindings = new nsXMLBindingSet(); mRuleToBindingsMap.Put(aRuleNode, bindings); } - nsCOMPtr<nsIDOMXPathExpression> compiledexpr; - nsresult rv = - CreateExpression(aExpr, aRuleNode, getter_AddRefs(compiledexpr)); - if (NS_FAILED(rv)) { + nsCOMPtr<nsINode> ruleNode = do_QueryInterface(aRuleNode); + + ErrorResult rv; + nsAutoPtr<XPathExpression> compiledexpr; + compiledexpr = CreateExpression(aExpr, ruleNode, rv); + if (rv.Failed()) { nsXULContentUtils::LogTemplateError(ERROR_TEMPLATE_BAD_BINDING_XPATH); return NS_OK; } // aRef isn't currently used for XML query processors - return bindings->AddBinding(aVar, compiledexpr); + bindings->AddBinding(aVar, Move(compiledexpr)); + return NS_OK; } NS_IMETHODIMP nsXULTemplateQueryProcessorXML::TranslateRef(nsISupports* aDatasource, const nsAString& aRefString, nsIXULTemplateResult** aRef) { *aRef = nullptr; // the datasource is either a document or a DOM element - nsCOMPtr<nsIDOMElement> rootElement; - nsCOMPtr<nsIDOMDocument> doc = do_QueryInterface(aDatasource); + nsCOMPtr<Element> rootElement; + nsCOMPtr<nsIDocument> doc = do_QueryInterface(aDatasource); if (doc) - doc->GetDocumentElement(getter_AddRefs(rootElement)); + rootElement = doc->GetRootElement(); else rootElement = do_QueryInterface(aDatasource); // if no root element, just return. The document may not have loaded yet if (!rootElement) return NS_OK; - nsXULTemplateResultXML* result = - new nsXULTemplateResultXML(nullptr, rootElement, nullptr); - NS_ENSURE_TRUE(result, NS_ERROR_OUT_OF_MEMORY); - - *aRef = result; + *aRef = new nsXULTemplateResultXML(nullptr, rootElement, nullptr); NS_ADDREF(*aRef); return NS_OK; } NS_IMETHODIMP nsXULTemplateQueryProcessorXML::CompareResults(nsIXULTemplateResult* aLeft, @@ -429,34 +418,28 @@ nsXULTemplateQueryProcessorXML::CompareR } nsXMLBindingSet* nsXULTemplateQueryProcessorXML::GetOptionalBindingsForRule(nsIDOMNode* aRuleNode) { return mRuleToBindingsMap.GetWeak(aRuleNode); } -nsresult +XPathExpression* nsXULTemplateQueryProcessorXML::CreateExpression(const nsAString& aExpr, - nsIDOMNode* aNode, - nsIDOMXPathExpression** aCompiledExpr) + nsINode* aNode, + ErrorResult& aRv) { - nsCOMPtr<nsIDOMXPathNSResolver> nsResolver; - - nsCOMPtr<nsIDOMDocument> doc; - aNode->GetOwnerDocument(getter_AddRefs(doc)); - - nsCOMPtr<nsIDOMXPathEvaluator> eval = do_QueryInterface(doc); - if (eval) { - nsresult rv = - eval->CreateNSResolver(aNode, getter_AddRefs(nsResolver)); - NS_ENSURE_SUCCESS(rv, rv); + nsCOMPtr<nsIDOMXPathNSResolver> nsResolver = + aNode->OwnerDoc()->CreateNSResolver(aNode, aRv); + if (aRv.Failed()) { + return nullptr; } - return mEvaluator->CreateExpression(aExpr, nsResolver, aCompiledExpr); + return mEvaluator->CreateExpression(aExpr, nsResolver, aRv); } NS_IMETHODIMP nsXULTemplateQueryProcessorXML::HandleEvent(nsIDOMEvent* aEvent) { NS_PRECONDITION(aEvent, "aEvent null"); nsAutoString eventType; aEvent->GetType(eventType);
--- a/content/xul/templates/src/nsXULTemplateQueryProcessorXML.h +++ b/content/xul/templates/src/nsXULTemplateQueryProcessorXML.h @@ -8,24 +8,24 @@ #include "nsIXULTemplateBuilder.h" #include "nsIXULTemplateQueryProcessor.h" #include "nsISimpleEnumerator.h" #include "nsString.h" #include "nsCOMArray.h" #include "nsRefPtrHashtable.h" -#include "nsIDOMElement.h" #include "nsIDOMEventListener.h" -#include "nsIDOMXPathExpression.h" #include "nsIDOMXPathEvaluator.h" #include "nsXMLBinding.h" #include "nsCycleCollectionParticipant.h" #include "nsIXMLHttpRequest.h" #include "mozilla/Attributes.h" +#include "mozilla/dom/Element.h" +#include "mozilla/dom/XPathEvaluator.h" #include "mozilla/dom/XPathResult.h" class nsXULTemplateQueryProcessorXML; #define NS_IXMLQUERY_IID \ {0x0358d692, 0xccce, 0x4a97, \ { 0xb2, 0x51, 0xba, 0x8f, 0x17, 0x0f, 0x3b, 0x6f }} @@ -38,49 +38,49 @@ class nsXMLQuery MOZ_FINAL : public nsIS // return a weak reference to the processor the query was created from nsXULTemplateQueryProcessorXML* Processor() { return mProcessor; } // return a weak reference t the member variable for the query nsIAtom* GetMemberVariable() { return mMemberVariable; } // return a weak reference to the expression used to generate results - nsIDOMXPathExpression* GetResultsExpression() { return mResultsExpr; } + mozilla::dom::XPathExpression* GetResultsExpression() + { return mResultsExpr; } // return a weak reference to the additional required bindings nsXMLBindingSet* GetBindingSet() { return mRequiredBindings; } // add a required binding for the query - nsresult - AddBinding(nsIAtom* aVar, nsIDOMXPathExpression* aExpr) + void + AddBinding(nsIAtom* aVar, nsAutoPtr<mozilla::dom::XPathExpression>&& aExpr) { if (!mRequiredBindings) { mRequiredBindings = new nsXMLBindingSet(); - NS_ENSURE_TRUE(mRequiredBindings, NS_ERROR_OUT_OF_MEMORY); } - return mRequiredBindings->AddBinding(aVar, aExpr); + mRequiredBindings->AddBinding(aVar, mozilla::Move(aExpr)); } nsXMLQuery(nsXULTemplateQueryProcessorXML* aProcessor, - nsIAtom* aMemberVariable, - nsIDOMXPathExpression* aResultsExpr) + nsIAtom* aMemberVariable, + nsAutoPtr<mozilla::dom::XPathExpression>&& aResultsExpr) : mProcessor(aProcessor), mMemberVariable(aMemberVariable), mResultsExpr(aResultsExpr) { } protected: ~nsXMLQuery() {} nsXULTemplateQueryProcessorXML* mProcessor; nsCOMPtr<nsIAtom> mMemberVariable; - nsCOMPtr<nsIDOMXPathExpression> mResultsExpr; + nsAutoPtr<mozilla::dom::XPathExpression> mResultsExpr; nsRefPtr<nsXMLBindingSet> mRequiredBindings; }; NS_DEFINE_STATIC_IID_ACCESSOR(nsXMLQuery, NS_IXMLQUERY_IID) class nsXULTemplateResultSetXML MOZ_FINAL : public nsISimpleEnumerator { @@ -104,17 +104,17 @@ public: // nsISupports interface NS_DECL_ISUPPORTS // nsISimpleEnumerator interface NS_DECL_NSISIMPLEENUMERATOR nsXULTemplateResultSetXML(nsXMLQuery* aQuery, - mozilla::dom::XPathResult* aResults, + already_AddRefed<mozilla::dom::XPathResult> aResults, nsXMLBindingSet* aBindingSet) : mQuery(aQuery), mBindingSet(aBindingSet), mResults(aResults), mPosition(0) {} }; @@ -138,32 +138,32 @@ public: // nsIDOMEventListener interface NS_DECL_NSIDOMEVENTLISTENER nsXMLBindingSet* GetOptionalBindingsForRule(nsIDOMNode* aRuleNode); // create an XPath expression from aExpr, using aNode for // resolving namespaces - nsresult + mozilla::dom::XPathExpression* CreateExpression(const nsAString& aExpr, - nsIDOMNode* aNode, - nsIDOMXPathExpression** aCompiledExpr); + nsINode* aNode, + mozilla::ErrorResult& aRv); private: ~nsXULTemplateQueryProcessorXML() {} bool mGenerationStarted; nsRefPtrHashtable<nsISupportsHashKey, nsXMLBindingSet> mRuleToBindingsMap; - nsCOMPtr<nsIDOMElement> mRoot; + nsCOMPtr<mozilla::dom::Element> mRoot; - nsCOMPtr<nsIDOMXPathEvaluator> mEvaluator; + nsRefPtr<mozilla::dom::XPathEvaluator> mEvaluator; nsCOMPtr<nsIXULTemplateBuilder> mTemplateBuilder; nsCOMPtr<nsIXMLHttpRequest> mRequest; }; #endif // nsXULTemplateQueryProcessorXML_h__
--- a/content/xul/templates/src/nsXULTemplateResultXML.cpp +++ b/content/xul/templates/src/nsXULTemplateResultXML.cpp @@ -13,27 +13,25 @@ #include "nsXULTemplateResultXML.h" #include "nsXMLBinding.h" static uint32_t sTemplateId = 0; NS_IMPL_ISUPPORTS(nsXULTemplateResultXML, nsIXULTemplateResult) nsXULTemplateResultXML::nsXULTemplateResultXML(nsXMLQuery* aQuery, - nsIDOMNode* aNode, + nsIContent* aNode, nsXMLBindingSet* aBindings) : mQuery(aQuery), mNode(aNode) { - nsCOMPtr<nsIContent> content = do_QueryInterface(mNode); - // If the node has an id, create the uri from it. Otherwise, there isn't // anything to identify the node with so just use a somewhat random number. - nsCOMPtr<nsIAtom> id = content->GetID(); + nsCOMPtr<nsIAtom> id = mNode->GetID(); if (id) { - nsCOMPtr<nsIURI> uri = content->GetBaseURI(); + nsCOMPtr<nsIURI> uri = mNode->GetBaseURI(); nsAutoCString spec; uri->GetSpec(spec); mId = NS_ConvertUTF8toUTF16(spec); nsAutoString idstr; id->ToString(idstr); mId += NS_LITERAL_STRING("#") + idstr; @@ -47,20 +45,17 @@ nsXULTemplateResultXML::nsXULTemplateRes if (aBindings) mRequiredValues.SetBindingSet(aBindings); } NS_IMETHODIMP nsXULTemplateResultXML::GetIsContainer(bool* aIsContainer) { // a node is considered a container if it has children - if (mNode) - mNode->HasChildNodes(aIsContainer); - else - *aIsContainer = false; + *aIsContainer = mNode && mNode->HasChildNodes(); return NS_OK; } NS_IMETHODIMP nsXULTemplateResultXML::GetIsEmpty(bool* aIsEmpty) { // a node is considered empty if it has no elements as children nsCOMPtr<nsIContent> content = do_QueryInterface(mNode); @@ -143,38 +138,35 @@ nsXULTemplateResultXML::GetBindingFor(ns } NS_IMETHODIMP nsXULTemplateResultXML::GetBindingObjectFor(nsIAtom* aVar, nsISupports** aValue) { NS_ENSURE_ARG_POINTER(aVar); nsXMLBinding* binding; - nsCOMPtr<nsIDOMNode> node; + nsCOMPtr<nsISupports> node; if (mQuery && aVar == mQuery->GetMemberVariable()) { node = mNode; } else { int32_t idx = mRequiredValues.LookupTargetIndex(aVar, &binding); if (idx > 0) { - mRequiredValues.GetNodeAssignmentFor(this, binding, idx, - getter_AddRefs(node)); + node = mRequiredValues.GetNodeAssignmentFor(this, binding, idx); } else { idx = mOptionalValues.LookupTargetIndex(aVar, &binding); if (idx > 0) { - mOptionalValues.GetNodeAssignmentFor(this, binding, idx, - getter_AddRefs(node)); + node = mOptionalValues.GetNodeAssignmentFor(this, binding, idx); } } } - *aValue = node; - NS_IF_ADDREF(*aValue); + node.forget(aValue); return NS_OK; } NS_IMETHODIMP nsXULTemplateResultXML::RuleMatched(nsISupports* aQueryNode, nsIDOMNode* aRuleNode) { // when a rule matches, set the bindings that must be used. @@ -190,15 +182,8 @@ nsXULTemplateResultXML::RuleMatched(nsIS return NS_OK; } NS_IMETHODIMP nsXULTemplateResultXML::HasBeenRemoved() { return NS_OK; } - -void -nsXULTemplateResultXML::GetNode(nsIDOMNode** aNode) -{ - *aNode = mNode; - NS_IF_ADDREF(*aNode); -}
--- a/content/xul/templates/src/nsXULTemplateResultXML.h +++ b/content/xul/templates/src/nsXULTemplateResultXML.h @@ -2,16 +2,17 @@ /* 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 nsXULTemplateResultXML_h__ #define nsXULTemplateResultXML_h__ #include "nsCOMPtr.h" +#include "nsIContent.h" #include "nsIURI.h" #include "nsIRDFResource.h" #include "nsXULTemplateQueryProcessorXML.h" #include "nsIXULTemplateResult.h" #include "mozilla/Attributes.h" /** * An single result of an query @@ -19,36 +20,39 @@ class nsXULTemplateResultXML MOZ_FINAL : public nsIXULTemplateResult { public: NS_DECL_ISUPPORTS NS_DECL_NSIXULTEMPLATERESULT nsXULTemplateResultXML(nsXMLQuery* aQuery, - nsIDOMNode* aNode, + nsIContent* aNode, nsXMLBindingSet* aBindings); - void GetNode(nsIDOMNode** aNode); + nsIContent* Node() + { + return mNode; + } protected: ~nsXULTemplateResultXML() {} // ID used for persisting data. It is constructed using the mNode's // base uri plus the node's id to form 'baseuri#id'. If the node has no // id, then an id of the form 'row<some number>' is generated. In the // latter case, persistence will not work as there won't be a unique id. nsAutoString mId; // query that generated the result nsCOMPtr<nsXMLQuery> mQuery; // context node in datasource - nsCOMPtr<nsIDOMNode> mNode; + nsCOMPtr<nsIContent> mNode; // assignments in query nsXMLBindingValues mRequiredValues; // extra assignments made by rules (<binding> tags) nsXMLBindingValues mOptionalValues; };
--- a/dom/base/nsDOMClassInfo.cpp +++ b/dom/base/nsDOMClassInfo.cpp @@ -106,18 +106,16 @@ #include "nsIBoxObject.h" #ifdef MOZ_XUL #include "nsITreeSelection.h" #include "nsITreeContentView.h" #include "nsITreeView.h" #include "nsIXULTemplateBuilder.h" #include "nsITreeColumns.h" #endif -#include "nsIDOMXPathExpression.h" -#include "nsIDOMNSXPathExpression.h" #include "nsIDOMXPathNSResolver.h" // Storage includes #include "nsIDOMStorage.h" #include "nsPIDOMStorage.h" // Drag and drop #include "nsIDOMFile.h" @@ -339,18 +337,16 @@ static nsDOMClassInfoData sClassInfoData DOM_DEFAULT_SCRIPTABLE_FLAGS) NS_DEFINE_CLASSINFO_DATA(CSSSupportsRule, nsDOMGenericSH, DOM_DEFAULT_SCRIPTABLE_FLAGS) NS_DEFINE_CLASSINFO_DATA(XSLTProcessor, nsDOMGenericSH, DOM_DEFAULT_SCRIPTABLE_FLAGS) - NS_DEFINE_CLASSINFO_DATA(XPathExpression, nsDOMGenericSH, - DOM_DEFAULT_SCRIPTABLE_FLAGS) NS_DEFINE_CLASSINFO_DATA(XPathNSResolver, nsDOMGenericSH, DOM_DEFAULT_SCRIPTABLE_FLAGS) // WhatWG Storage // mrbkap says we don't need WANT_ADDPROPERTY on Storage objects // since a call to addProperty() is always followed by a call to // setProperty(), except in the case when a getter or setter is set @@ -937,21 +933,16 @@ nsDOMClassInfo::Init() DOM_CLASSINFO_MAP_ENTRY(nsIDOMCSSSupportsRule) DOM_CLASSINFO_MAP_END DOM_CLASSINFO_MAP_BEGIN(XSLTProcessor, nsIXSLTProcessor) DOM_CLASSINFO_MAP_ENTRY(nsIXSLTProcessor) DOM_CLASSINFO_MAP_ENTRY(nsIXSLTProcessorPrivate) DOM_CLASSINFO_MAP_END - DOM_CLASSINFO_MAP_BEGIN(XPathExpression, nsIDOMXPathExpression) - DOM_CLASSINFO_MAP_ENTRY(nsIDOMXPathExpression) - DOM_CLASSINFO_MAP_ENTRY(nsIDOMNSXPathExpression) - DOM_CLASSINFO_MAP_END - DOM_CLASSINFO_MAP_BEGIN(XPathNSResolver, nsIDOMXPathNSResolver) DOM_CLASSINFO_MAP_ENTRY(nsIDOMXPathNSResolver) DOM_CLASSINFO_MAP_END DOM_CLASSINFO_MAP_BEGIN(Storage, nsIDOMStorage) DOM_CLASSINFO_MAP_ENTRY(nsIDOMStorage) DOM_CLASSINFO_MAP_END
--- a/dom/base/nsDOMClassInfoClasses.h +++ b/dom/base/nsDOMClassInfoClasses.h @@ -41,17 +41,16 @@ DOMCI_CLASS(TreeColumn) DOMCI_CLASS(CSSMozDocumentRule) DOMCI_CLASS(CSSSupportsRule) // XSLTProcessor DOMCI_CLASS(XSLTProcessor) // DOM Level 3 XPath objects -DOMCI_CLASS(XPathExpression) DOMCI_CLASS(XPathNSResolver) // WhatWG WebApps Objects DOMCI_CLASS(Storage) DOMCI_CLASS(Blob) DOMCI_CLASS(File)
--- a/dom/bindings/Bindings.conf +++ b/dom/bindings/Bindings.conf @@ -1667,16 +1667,21 @@ DOMInterfaces = { 'XPathEvaluator': { 'wrapperCache': False }, 'XPathResult': { 'resultNotAddRefed': ['singleNodeValue', 'iterateNext', 'snapshotItem'] }, +'XPathExpression': { + 'wrapperCache': False, + 'nativeOwnership': 'owned', +}, + 'XULDocument': { 'headerFile': 'XULDocument.h' }, 'XULElement': { 'nativeType': 'nsXULElement', 'resultNotAddRefed': [ 'controllers', 'style' ] }, @@ -2006,11 +2011,10 @@ addExternalIface('OutputStream', nativeT notflattened=True) addExternalIface('Principal', nativeType='nsIPrincipal', headerFile='nsIPrincipal.h', notflattened=True) addExternalIface('StackFrame', nativeType='nsIStackFrame', headerFile='nsIException.h', notflattened=True) addExternalIface('URI', nativeType='nsIURI', headerFile='nsIURI.h', notflattened=True) addExternalIface('UserDataHandler') -addExternalIface('XPathExpression') addExternalIface('XPathNSResolver') addExternalIface('XULCommandDispatcher')
--- a/dom/interfaces/xpath/moz.build +++ b/dom/interfaces/xpath/moz.build @@ -1,16 +1,14 @@ # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- # vim: set filetype=python: # 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/. XPIDL_SOURCES += [ - 'nsIDOMNSXPathExpression.idl', 'nsIDOMXPathEvaluator.idl', - 'nsIDOMXPathExpression.idl', 'nsIDOMXPathNSResolver.idl', 'nsIDOMXPathResult.idl', ] XPIDL_MODULE = 'dom_xpath'
deleted file mode 100644 --- a/dom/interfaces/xpath/nsIDOMNSXPathExpression.idl +++ /dev/null @@ -1,34 +0,0 @@ -/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* 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 "domstubs.idl" - -interface XPathException; - -/** - * Interface for Mozilla specific XPathExpression functions. - */ -[scriptable, uuid(ce600ca8-e98a-4419-ad61-2f6d0cb0ecc8)] -interface nsIDOMNSXPathExpression : nsISupports -{ - /** - * Evaluate the expression with the given context. Similar to - * nsIDOMXPathExpression::evaluate(), except that this takes the context - * position and size too. - * - * @param contextNode The context node - * @param contextPosition The context position - * @param contextSize The context size - * @param type The needed result type - * @param result The result - */ - nsISupports evaluateWithContext(in nsIDOMNode contextNode, - in unsigned long contextPosition, - in unsigned long contextSize, - in unsigned short type, - in nsISupports result) - raises(XPathException, - DOMException); -};
--- a/dom/interfaces/xpath/nsIDOMXPathEvaluator.idl +++ b/dom/interfaces/xpath/nsIDOMXPathEvaluator.idl @@ -5,26 +5,21 @@ /** * Corresponds to http://www.w3.org/TR/2002/WD-DOM-Level-3-XPath-20020208 */ #include "domstubs.idl" interface nsIDOMXPathNSResolver; -interface nsIDOMXPathExpression; interface XPathException; -[uuid(75506f8a-b504-11d5-a7f2-ca108ab8b6fc)] +[uuid(89a0fe71-c1d9-46bd-b76b-47f51fd935ff)] interface nsIDOMXPathEvaluator : nsISupports { - nsIDOMXPathExpression createExpression(in DOMString expression, - in nsIDOMXPathNSResolver resolver) - raises(XPathException, - DOMException); nsIDOMXPathNSResolver createNSResolver(in nsIDOMNode nodeResolver); nsISupports evaluate(in DOMString expression, in nsIDOMNode contextNode, in nsIDOMXPathNSResolver resolver, in unsigned short type, in nsISupports result) raises(XPathException, DOMException);
deleted file mode 100644 --- a/dom/interfaces/xpath/nsIDOMXPathExpression.idl +++ /dev/null @@ -1,22 +0,0 @@ -/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* 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/. */ - -/** - * Corresponds to http://www.w3.org/TR/2002/WD-DOM-Level-3-XPath-20020208 - */ - -#include "domstubs.idl" - -interface XPathException; - -[scriptable, uuid(75506f82-b504-11d5-a7f2-ca108ab8b6fc)] -interface nsIDOMXPathExpression : nsISupports -{ - nsISupports evaluate(in nsIDOMNode contextNode, - in unsigned short type, - in nsISupports result) - raises(XPathException, - DOMException); -};
--- a/dom/webidl/XPathEvaluator.webidl +++ b/dom/webidl/XPathEvaluator.webidl @@ -1,15 +1,14 @@ /* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* 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/. */ -interface XPathExpression; interface XPathNSResolver; [Constructor] interface XPathEvaluator { // Based on nsIDOMXPathEvaluator [NewObject, Throws] XPathExpression createExpression(DOMString expression, XPathNSResolver? resolver);
new file mode 100644 --- /dev/null +++ b/dom/webidl/XPathExpression.webidl @@ -0,0 +1,22 @@ +/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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/. + */ + +interface XPathExpression { + // The result specifies a specific result object which may be reused and + // returned by this method. If this is specified as null or it's not an + // XPathResult object, a new result object will be constructed and returned. + [Throws] + XPathResult evaluate(Node contextNode, unsigned short type, object? result); + + // The result specifies a specific result object which may be reused and + // returned by this method. If this is specified as null or it's not an + // XPathResult object, a new result object will be constructed and returned. + [Throws, ChromeOnly] + XPathResult evaluateWithContext(Node contextNode, + unsigned long contextPosition, + unsigned long contextSize, + unsigned short type, object? result); +};
--- a/dom/webidl/moz.build +++ b/dom/webidl/moz.build @@ -476,16 +476,17 @@ WEBIDL_FILES = [ 'WorkerNavigator.webidl', 'XMLDocument.webidl', 'XMLHttpRequest.webidl', 'XMLHttpRequestEventTarget.webidl', 'XMLHttpRequestUpload.webidl', 'XMLSerializer.webidl', 'XMLStylesheetProcessingInstruction.webidl', 'XPathEvaluator.webidl', + 'XPathExpression.webidl', 'XPathResult.webidl', 'XULCommandEvent.webidl', 'XULDocument.webidl', 'XULElement.webidl', ] if CONFIG['MOZ_AUDIO_CHANNEL_MANAGER']: WEBIDL_FILES += [
--- a/dom/workers/RuntimeService.cpp +++ b/dom/workers/RuntimeService.cpp @@ -16,16 +16,17 @@ #include "nsIScriptContext.h" #include "nsIScriptSecurityManager.h" #include "nsISupportsPriority.h" #include "nsITimer.h" #include "nsIURI.h" #include "nsPIDOMWindow.h" #include <algorithm> +#include "BackgroundChild.h" #include "GeckoProfiler.h" #include "js/OldDebugAPI.h" #include "jsfriendapi.h" #include "mozilla/ArrayUtils.h" #include "mozilla/CycleCollectedJSRuntime.h" #include "mozilla/dom/asmjscache/AsmJSCache.h" #include "mozilla/dom/AtomList.h" #include "mozilla/dom/BindingUtils.h" @@ -34,16 +35,17 @@ #include "mozilla/dom/MessageEventBinding.h" #include "mozilla/dom/WorkerBinding.h" #include "mozilla/DebugOnly.h" #include "mozilla/Preferences.h" #include "mozilla/dom/Navigator.h" #include "nsContentUtils.h" #include "nsCycleCollector.h" #include "nsDOMJSUtils.h" +#include "nsIIPCBackgroundChildCreateCallback.h" #include "nsISupportsImpl.h" #include "nsLayoutStatics.h" #include "nsNetUtil.h" #include "nsServiceManagerUtils.h" #include "nsThread.h" #include "nsThreadUtils.h" #include "nsXPCOM.h" #include "nsXPCOMPrivate.h" @@ -58,16 +60,22 @@ #include "nsThreadManager.h" #endif #include "ServiceWorker.h" #include "SharedWorker.h" #include "WorkerPrivate.h" #include "WorkerRunnable.h" +#ifdef ENABLE_TESTS +#include "BackgroundChildImpl.h" +#include "mozilla/ipc/PBackgroundChild.h" +#include "prrng.h" +#endif + using namespace mozilla; using namespace mozilla::dom; USING_WORKERS_NAMESPACE using mozilla::MutexAutoLock; using mozilla::MutexAutoUnlock; using mozilla::Preferences; @@ -155,16 +163,20 @@ const JS::ContextOptions kRequiredContex uint32_t gMaxWorkersPerDomain = MAX_WORKERS_PER_DOMAIN; // Does not hold an owning reference. RuntimeService* gRuntimeService = nullptr; // Only non-null during the call to Init. RuntimeService* gRuntimeServiceDuringInit = nullptr; +#ifdef ENABLE_TESTS +bool gTestPBackground = false; +#endif // ENABLE_TESTS + enum { ID_Worker = 0, ID_ChromeWorker, ID_Event, ID_MessageEvent, ID_ErrorEvent, ID_COUNT @@ -899,16 +911,47 @@ public: nsCycleCollector_collect(nullptr); } } private: WorkerPrivate* mWorkerPrivate; }; +class WorkerBackgroundChildCallback MOZ_FINAL : + public nsIIPCBackgroundChildCreateCallback +{ + bool* mDone; + +public: + WorkerBackgroundChildCallback(bool* aDone) + : mDone(aDone) + { + MOZ_ASSERT(mDone); + } + + NS_DECL_ISUPPORTS + +private: + ~WorkerBackgroundChildCallback() + { } + + virtual void + ActorCreated(PBackgroundChild* aActor) MOZ_OVERRIDE + { + *mDone = true; + } + + virtual void + ActorFailed() MOZ_OVERRIDE + { + *mDone = true; + } +}; + class WorkerThreadPrimaryRunnable MOZ_FINAL : public nsRunnable { WorkerPrivate* mWorkerPrivate; nsRefPtr<RuntimeService::WorkerThread> mThread; JSRuntime* mParentRuntime; class FinishedRunnable MOZ_FINAL : public nsRunnable { @@ -941,16 +984,19 @@ public: } NS_DECL_ISUPPORTS_INHERITED private: ~WorkerThreadPrimaryRunnable() { } + nsresult + SynchronouslyCreatePBackground(); + NS_DECL_NSIRUNNABLE }; class WorkerTaskRunnable MOZ_FINAL : public WorkerRunnable { nsRefPtr<WorkerTask> mTask; public: @@ -1040,16 +1086,38 @@ public: void SetAcceptingNonWorkerRunnables(bool aAcceptingNonWorkerRunnables) { MutexAutoLock lock(mLock); mAcceptingNonWorkerRunnables = aAcceptingNonWorkerRunnables; } #endif +#ifdef ENABLE_TESTS + void + TestPBackground() + { + using namespace mozilla::ipc; + if (gTestPBackground) { + // Randomize value to validate workers are not cross-posting messages. + uint32_t testValue; + PRSize randomSize = PR_GetRandomNoise(&testValue, sizeof(testValue)); + MOZ_RELEASE_ASSERT(randomSize == sizeof(testValue)); + nsCString testStr; + testStr.AppendInt(testValue); + testStr.AppendInt(reinterpret_cast<int64_t>(PR_GetCurrentThread())); + PBackgroundChild* existingBackgroundChild = + BackgroundChild::GetForCurrentThread(); + MOZ_RELEASE_ASSERT(existingBackgroundChild); + bool ok = existingBackgroundChild->SendPBackgroundTestConstructor(testStr); + MOZ_RELEASE_ASSERT(ok); + } + } +#endif // #ENABLE_TESTS + private: WorkerThread() : nsThread(nsThread::NOT_MAIN_THREAD, WORKER_STACK_SIZE), mWorkerPrivate(nullptr) #ifdef DEBUG , mAcceptingNonWorkerRunnables(true) #endif { } @@ -1243,16 +1311,20 @@ RuntimeService::GetOrCreateService() if (!gRuntimeService) { nsRefPtr<RuntimeService> service = new RuntimeService(); if (NS_FAILED(service->Init())) { NS_WARNING("Failed to initialize!"); service->Cleanup(); return nullptr; } +#ifdef ENABLE_TESTS + gTestPBackground = mozilla::Preferences::GetBool("pbackground.testing", false); +#endif // ENABLE_TESTS + // The observer service now owns us until shutdown. gRuntimeService = service; } return gRuntimeService; } // static @@ -1532,20 +1604,16 @@ RuntimeService::ScheduleWorker(JSContext nsCOMPtr<nsIRunnable> runnable = new WorkerThreadPrimaryRunnable(aWorkerPrivate, thread, JS_GetParentRuntime(aCx)); if (NS_FAILED(thread->Dispatch(runnable, NS_DISPATCH_NORMAL))) { UnregisterWorker(aCx, aWorkerPrivate); JS_ReportError(aCx, "Could not dispatch to thread!"); return false; } -#ifdef DEBUG - thread->SetAcceptingNonWorkerRunnables(false); -#endif - return true; } // static void RuntimeService::ShutdownIdleThreads(nsITimer* aTimer, void* /* aClosure */) { AssertIsOnMainThread(); @@ -2487,18 +2555,30 @@ RuntimeService::WorkerThread::Observer:: } NS_IMETHODIMP RuntimeService::WorkerThread::Observer::OnProcessNextEvent( nsIThreadInternal* /* aThread */, bool aMayWait, uint32_t aRecursionDepth) { + using mozilla::ipc::BackgroundChild; + mWorkerPrivate->AssertIsOnWorkerThread(); - MOZ_ASSERT(!aMayWait); + + // If the PBackground child is not created yet, then we must permit + // blocking event processing to support SynchronouslyCreatePBackground(). + // If this occurs then we are spinning on the event queue at the start of + // PrimaryWorkerRunnable::Run() and don't want to process the event in + // mWorkerPrivate yet. + if (aMayWait) { + MOZ_ASSERT(aRecursionDepth == 2); + MOZ_ASSERT(!BackgroundChild::GetForCurrentThread()); + return NS_OK; + } mWorkerPrivate->OnProcessNextEvent(aRecursionDepth); return NS_OK; } NS_IMETHODIMP RuntimeService::WorkerThread::Observer::AfterProcessNextEvent( nsIThreadInternal* /* aThread */, @@ -2532,21 +2612,25 @@ LogViolationDetailsRunnable::Run() nsRefPtr<MainThreadStopSyncLoopRunnable> response = new MainThreadStopSyncLoopRunnable(mWorkerPrivate, mSyncLoopTarget.forget(), true); MOZ_ALWAYS_TRUE(response->Dispatch(nullptr)); return NS_OK; } +NS_IMPL_ISUPPORTS(WorkerBackgroundChildCallback, nsIIPCBackgroundChildCreateCallback) + NS_IMPL_ISUPPORTS_INHERITED0(WorkerThreadPrimaryRunnable, nsRunnable) NS_IMETHODIMP WorkerThreadPrimaryRunnable::Run() { + using mozilla::ipc::BackgroundChild; + #ifdef MOZ_NUWA_PROCESS if (IsNuwaProcess()) { NS_ASSERTION(NuwaMarkCurrentThread != nullptr, "NuwaMarkCurrentThread is undefined!"); NuwaMarkCurrentThread(nullptr, nullptr); NuwaFreezeCurrentThread(); } #endif @@ -2555,16 +2639,29 @@ WorkerThreadPrimaryRunnable::Run() nsAutoCString threadName; threadName.AssignLiteral("WebWorker '"); threadName.Append(NS_LossyConvertUTF16toASCII(mWorkerPrivate->ScriptURL())); threadName.Append('\''); profiler_register_thread(threadName.get(), &stackBaseGuess); + // Note: SynchronouslyCreatePBackground() must be called prior to + // mThread->SetWorker() in order to avoid accidentally consuming + // worker messages here. + nsresult rv = SynchronouslyCreatePBackground(); + if (NS_WARN_IF(NS_FAILED(rv))) { + // XXX need to fire an error at parent. + return rv; + } + +#ifdef ENABLE_TESTS + mThread->TestPBackground(); +#endif + mThread->SetWorker(mWorkerPrivate); mWorkerPrivate->AssertIsOnWorkerThread(); { nsCycleCollector_startup(); WorkerJSRuntime runtime(mParentRuntime, mWorkerPrivate); @@ -2588,16 +2685,22 @@ WorkerThreadPrimaryRunnable::Run() { JSAutoRequest ar(cx); mWorkerPrivate->DoRunLoop(cx); JS_ReportPendingException(cx); } +#ifdef ENABLE_TESTS + mThread->TestPBackground(); +#endif + + BackgroundChild::CloseForCurrentThread(); + #ifdef MOZ_ENABLE_PROFILER_SPS if (stack) { stack->sampleRuntime(nullptr); } #endif } // Destroy the main context. This will unroot the main worker global and @@ -2626,16 +2729,48 @@ WorkerThreadPrimaryRunnable::Run() new FinishedRunnable(mThread.forget()); MOZ_ALWAYS_TRUE(NS_SUCCEEDED(mainThread->Dispatch(finishedRunnable, NS_DISPATCH_NORMAL))); profiler_unregister_thread(); return NS_OK; } +nsresult +WorkerThreadPrimaryRunnable::SynchronouslyCreatePBackground() +{ + using mozilla::ipc::BackgroundChild; + + MOZ_ASSERT(!BackgroundChild::GetForCurrentThread()); + + bool done = false; + nsCOMPtr<nsIIPCBackgroundChildCreateCallback> callback = + new WorkerBackgroundChildCallback(&done); + + if (NS_WARN_IF(!BackgroundChild::GetOrCreateForCurrentThread(callback))) { + return NS_ERROR_FAILURE; + } + + while (!done) { + if (NS_WARN_IF(!NS_ProcessNextEvent(mThread, true /* aMayWay */))) { + return NS_ERROR_FAILURE; + } + } + + if (NS_WARN_IF(!BackgroundChild::GetForCurrentThread())) { + return NS_ERROR_FAILURE; + } + +#ifdef DEBUG + mThread->SetAcceptingNonWorkerRunnables(false); +#endif + + return NS_OK; +} + NS_IMPL_ISUPPORTS_INHERITED0(WorkerThreadPrimaryRunnable::FinishedRunnable, nsRunnable) NS_IMETHODIMP WorkerThreadPrimaryRunnable::FinishedRunnable::Run() { AssertIsOnMainThread();
--- a/dom/xslt/xpath/XPathEvaluator.cpp +++ b/dom/xslt/xpath/XPathEvaluator.cpp @@ -2,29 +2,30 @@ /* 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 "mozilla/dom/XPathEvaluator.h" #include "mozilla/Move.h" #include "nsCOMPtr.h" #include "nsIAtom.h" -#include "nsXPathExpression.h" +#include "mozilla/dom/XPathExpression.h" #include "nsXPathNSResolver.h" #include "XPathResult.h" #include "nsContentCID.h" #include "txExpr.h" #include "txExprParser.h" #include "nsError.h" #include "txURIUtils.h" #include "nsIDocument.h" #include "nsIDOMDocument.h" #include "nsDOMString.h" #include "nsNameSpaceManager.h" #include "nsContentUtils.h" +#include "txIXPathContext.h" #include "mozilla/dom/XPathEvaluatorBinding.h" #include "mozilla/dom/BindingUtils.h" extern nsresult TX_ResolveFunctionCallXPCOM(const nsCString &aContractID, int32_t aNamespaceID, nsIAtom *aName, nsISupports *aState, FunctionCall **aFunction); @@ -89,64 +90,66 @@ XPathEvaluator::CreateNSResolver(nsIDOMN NS_IMETHODIMP XPathEvaluator::Evaluate(const nsAString & aExpression, nsIDOMNode *aContextNode, nsIDOMXPathNSResolver *aResolver, uint16_t aType, nsISupports *aInResult, nsISupports **aResult) { - nsCOMPtr<nsIDOMXPathExpression> expression; - nsresult rv = CreateExpression(aExpression, aResolver, - getter_AddRefs(expression)); - NS_ENSURE_SUCCESS(rv, rv); + ErrorResult rv; + nsAutoPtr<XPathExpression> expression(CreateExpression(aExpression, + aResolver, rv)); + if (rv.Failed()) { + return rv.ErrorCode(); + } + + nsCOMPtr<nsINode> node = do_QueryInterface(aContextNode); + if (!node) { + return NS_ERROR_FAILURE; + } - return expression->Evaluate(aContextNode, aType, aInResult, aResult); + nsCOMPtr<nsIXPathResult> inResult = do_QueryInterface(aInResult); + nsRefPtr<XPathResult> result = + expression->Evaluate(*node, aType, + static_cast<XPathResult*>(inResult.get()), rv); + if (rv.Failed()) { + return rv.ErrorCode(); + } + + *aResult = ToSupports(result.forget().take()); + + return NS_OK; } -NS_IMETHODIMP +XPathExpression* XPathEvaluator::CreateExpression(const nsAString & aExpression, nsIDOMXPathNSResolver *aResolver, - nsIDOMXPathExpression **aResult) + ErrorResult& aRv) { - nsresult rv; if (!mRecycler) { - nsRefPtr<txResultRecycler> recycler = new txResultRecycler; - NS_ENSURE_TRUE(recycler, NS_ERROR_OUT_OF_MEMORY); - - rv = recycler->init(); - NS_ENSURE_SUCCESS(rv, rv); - - mRecycler = recycler; + mRecycler = new txResultRecycler; } nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocument); XPathEvaluatorParseContext pContext(aResolver, !(doc && doc->IsHTML())); nsAutoPtr<Expr> expression; - rv = txExprParser::createExpr(PromiseFlatString(aExpression), &pContext, - getter_Transfers(expression)); - if (NS_FAILED(rv)) { - if (rv == NS_ERROR_DOM_NAMESPACE_ERR) { - return NS_ERROR_DOM_NAMESPACE_ERR; + aRv = txExprParser::createExpr(PromiseFlatString(aExpression), &pContext, + getter_Transfers(expression)); + if (aRv.Failed()) { + if (aRv.ErrorCode() != NS_ERROR_DOM_NAMESPACE_ERR) { + aRv.Throw(NS_ERROR_DOM_INVALID_EXPRESSION_ERR); } - return NS_ERROR_DOM_INVALID_EXPRESSION_ERR; + return nullptr; } - nsCOMPtr<nsIDOMDocument> document = do_QueryReferent(mDocument); - - *aResult = new nsXPathExpression(Move(expression), mRecycler, document); - if (!*aResult) { - return NS_ERROR_OUT_OF_MEMORY; - } - - NS_ADDREF(*aResult); - return NS_OK; + return new XPathExpression(Move(expression), mRecycler, doc); } JSObject* XPathEvaluator::WrapObject(JSContext* aCx) { return dom::XPathEvaluatorBinding::Wrap(aCx, this); } @@ -154,26 +157,16 @@ XPathEvaluator::WrapObject(JSContext* aC already_AddRefed<XPathEvaluator> XPathEvaluator::Constructor(const GlobalObject& aGlobal, ErrorResult& rv) { nsRefPtr<XPathEvaluator> newObj = new XPathEvaluator(nullptr); return newObj.forget(); } -already_AddRefed<nsIDOMXPathExpression> -XPathEvaluator::CreateExpression(const nsAString& aExpression, - nsIDOMXPathNSResolver* aResolver, - ErrorResult& rv) -{ - nsCOMPtr<nsIDOMXPathExpression> expr; - rv = CreateExpression(aExpression, aResolver, getter_AddRefs(expr)); - return expr.forget(); -} - already_AddRefed<nsIDOMXPathNSResolver> XPathEvaluator::CreateNSResolver(nsINode* aNodeResolver, ErrorResult& rv) { nsCOMPtr<nsIDOMNode> nodeResolver = do_QueryInterface(aNodeResolver); nsCOMPtr<nsIDOMXPathNSResolver> res; rv = CreateNSResolver(nodeResolver, getter_AddRefs(res)); return res.forget();
--- a/dom/xslt/xpath/XPathEvaluator.h +++ b/dom/xslt/xpath/XPathEvaluator.h @@ -16,16 +16,17 @@ class nsINode; class txResultRecycler; namespace mozilla { namespace dom { class GlobalObject; +class XPathExpression; class XPathResult; /** * A class for evaluating an XPath expression string */ class XPathEvaluator MOZ_FINAL : public nsIDOMXPathEvaluator { ~XPathEvaluator(); @@ -42,17 +43,17 @@ public: JSObject* WrapObject(JSContext* aCx); nsIDocument* GetParentObject() { nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocument); return doc; } static already_AddRefed<XPathEvaluator> Constructor(const GlobalObject& aGlobal, ErrorResult& rv); - already_AddRefed<nsIDOMXPathExpression> + XPathExpression* CreateExpression(const nsAString& aExpression, nsIDOMXPathNSResolver* aResolver, ErrorResult& rv); already_AddRefed<nsIDOMXPathNSResolver> CreateNSResolver(nsINode* aNodeResolver, ErrorResult& rv); already_AddRefed<XPathResult> Evaluate(JSContext* aCx, const nsAString& aExpression, nsINode* aContextNode, nsIDOMXPathNSResolver* aResolver,
rename from dom/xslt/xpath/nsXPathExpression.cpp rename to dom/xslt/xpath/XPathExpression.cpp --- a/dom/xslt/xpath/nsXPathExpression.cpp +++ b/dom/xslt/xpath/XPathExpression.cpp @@ -1,124 +1,162 @@ /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* 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 "mozilla/Move.h" -#include "nsXPathExpression.h" +#include "XPathExpression.h" #include "txExpr.h" #include "txExprResult.h" +#include "txIXPathContext.h" #include "nsError.h" #include "nsIDOMCharacterData.h" #include "nsDOMClassInfoID.h" #include "nsIDOMDocument.h" #include "XPathResult.h" #include "txURIUtils.h" #include "txXPathTreeWalker.h" +#include "mozilla/dom/BindingUtils.h" +#include "mozilla/dom/XPathResultBinding.h" -using namespace mozilla::dom; using mozilla::Move; -NS_IMPL_CYCLE_COLLECTION(nsXPathExpression, mDocument) +namespace mozilla { +namespace dom { -NS_IMPL_CYCLE_COLLECTING_ADDREF(nsXPathExpression) -NS_IMPL_CYCLE_COLLECTING_RELEASE(nsXPathExpression) - -DOMCI_DATA(XPathExpression, nsXPathExpression) +class EvalContextImpl : public txIEvalContext +{ +public: + EvalContextImpl(const txXPathNode& aContextNode, + uint32_t aContextPosition, uint32_t aContextSize, + txResultRecycler* aRecycler) + : mContextNode(aContextNode), + mContextPosition(aContextPosition), + mContextSize(aContextSize), + mLastError(NS_OK), + mRecycler(aRecycler) + { + } -NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsXPathExpression) - NS_INTERFACE_MAP_ENTRY(nsIDOMXPathExpression) - NS_INTERFACE_MAP_ENTRY(nsIDOMNSXPathExpression) - NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMXPathExpression) - NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(XPathExpression) -NS_INTERFACE_MAP_END + nsresult getError() + { + return mLastError; + } + + TX_DECL_EVAL_CONTEXT; -nsXPathExpression::nsXPathExpression(nsAutoPtr<Expr>&& aExpression, - txResultRecycler* aRecycler, - nsIDOMDocument *aDocument) +private: + const txXPathNode& mContextNode; + uint32_t mContextPosition; + uint32_t mContextSize; + nsresult mLastError; + nsRefPtr<txResultRecycler> mRecycler; +}; + +XPathExpression::XPathExpression(nsAutoPtr<Expr>&& aExpression, + txResultRecycler* aRecycler, + nsIDocument *aDocument) : mExpression(Move(aExpression)), mRecycler(aRecycler), - mDocument(aDocument) + mDocument(do_GetWeakReference(aDocument)), + mCheckDocument(aDocument != nullptr) +{ +} + +XPathExpression::~XPathExpression() { } -NS_IMETHODIMP -nsXPathExpression::Evaluate(nsIDOMNode *aContextNode, - uint16_t aType, - nsISupports *aInResult, - nsISupports **aResult) +already_AddRefed<XPathResult> +XPathExpression::EvaluateWithContext(JSContext* aCx, + nsINode& aContextNode, + uint32_t aContextPosition, + uint32_t aContextSize, + uint16_t aType, + JS::Handle<JSObject*> aInResult, + ErrorResult& aRv) { - return EvaluateWithContext(aContextNode, 1, 1, aType, aInResult, aResult); -} - -NS_IMETHODIMP -nsXPathExpression::EvaluateWithContext(nsIDOMNode *aContextNode, - uint32_t aContextPosition, - uint32_t aContextSize, - uint16_t aType, - nsISupports *aInResult, - nsISupports **aResult) -{ - nsCOMPtr<nsINode> context = do_QueryInterface(aContextNode); - NS_ENSURE_ARG(context); - - if (aContextPosition > aContextSize) - return NS_ERROR_FAILURE; - - if (!nsContentUtils::CanCallerAccess(aContextNode)) - return NS_ERROR_DOM_SECURITY_ERR; - - if (mDocument && mDocument != aContextNode) { - nsCOMPtr<nsIDOMDocument> contextDocument; - aContextNode->GetOwnerDocument(getter_AddRefs(contextDocument)); - - if (mDocument != contextDocument) { - return NS_ERROR_DOM_WRONG_DOCUMENT_ERR; + XPathResult* inResult = nullptr; + if (aInResult) { + nsresult rv = UNWRAP_OBJECT(XPathResult, aInResult, inResult); + if (NS_FAILED(rv) && rv != NS_ERROR_XPC_BAD_CONVERT_JS) { + aRv.Throw(rv); + return nullptr; } } - uint16_t nodeType = context->NodeType(); + return EvaluateWithContext(aContextNode, aContextPosition, aContextSize, + aType, inResult, aRv); +} + +already_AddRefed<XPathResult> +XPathExpression::EvaluateWithContext(nsINode& aContextNode, + uint32_t aContextPosition, + uint32_t aContextSize, + uint16_t aType, + XPathResult* aInResult, + ErrorResult& aRv) +{ + if (aContextPosition > aContextSize) { + aRv.Throw(NS_ERROR_FAILURE); + return nullptr; + } + + if (!nsContentUtils::CanCallerAccess(&aContextNode)) { + aRv.Throw(NS_ERROR_DOM_SECURITY_ERR); + return nullptr; + } + + if (mCheckDocument) { + nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocument); + if (doc != aContextNode.OwnerDoc()) { + aRv.Throw(NS_ERROR_DOM_WRONG_DOCUMENT_ERR); + return nullptr; + } + } + + uint16_t nodeType = aContextNode.NodeType(); if (nodeType == nsIDOMNode::TEXT_NODE || nodeType == nsIDOMNode::CDATA_SECTION_NODE) { - nsCOMPtr<nsIDOMCharacterData> textNode = do_QueryInterface(aContextNode); - NS_ENSURE_TRUE(textNode, NS_ERROR_FAILURE); + nsCOMPtr<nsIDOMCharacterData> textNode = + do_QueryInterface(&aContextNode); + if (!textNode) { + aRv.Throw(NS_ERROR_FAILURE); + return nullptr; + } - if (textNode) { - uint32_t textLength; - textNode->GetLength(&textLength); - if (textLength == 0) - return NS_ERROR_DOM_NOT_SUPPORTED_ERR; + uint32_t textLength; + textNode->GetLength(&textLength); + if (textLength == 0) { + aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR); + return nullptr; } // XXX Need to get logical XPath text node for CDATASection // and Text nodes. } else if (nodeType != nsIDOMNode::DOCUMENT_NODE && nodeType != nsIDOMNode::ELEMENT_NODE && nodeType != nsIDOMNode::ATTRIBUTE_NODE && nodeType != nsIDOMNode::COMMENT_NODE && nodeType != nsIDOMNode::PROCESSING_INSTRUCTION_NODE) { - return NS_ERROR_DOM_NOT_SUPPORTED_ERR; + aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR); + return nullptr; } - NS_ENSURE_ARG(aResult); - *aResult = nullptr; - - nsAutoPtr<txXPathNode> contextNode(txXPathNativeNode::createXPathNode(aContextNode)); - if (!contextNode) { - return NS_ERROR_OUT_OF_MEMORY; - } - + nsAutoPtr<txXPathNode> contextNode(txXPathNativeNode::createXPathNode(&aContextNode)); EvalContextImpl eContext(*contextNode, aContextPosition, aContextSize, mRecycler); nsRefPtr<txAExprResult> exprResult; - nsresult rv = mExpression->evaluate(&eContext, getter_AddRefs(exprResult)); - NS_ENSURE_SUCCESS(rv, rv); + aRv = mExpression->evaluate(&eContext, getter_AddRefs(exprResult)); + if (aRv.Failed()) { + return nullptr; + } uint16_t resultType = aType; if (aType == XPathResult::ANY_TYPE) { short exprResultType = exprResult->getResultType(); switch (exprResultType) { case txAExprResult::NUMBER: resultType = XPathResult::NUMBER_TYPE; break; @@ -127,76 +165,83 @@ nsXPathExpression::EvaluateWithContext(n break; case txAExprResult::BOOLEAN: resultType = XPathResult::BOOLEAN_TYPE; break; case txAExprResult::NODESET: resultType = XPathResult::UNORDERED_NODE_ITERATOR_TYPE; break; case txAExprResult::RESULT_TREE_FRAGMENT: - NS_ERROR("Can't return a tree fragment!"); - return NS_ERROR_FAILURE; + aRv.Throw(NS_ERROR_FAILURE); + return nullptr; } } - // We need a result object and it must be our implementation. - nsCOMPtr<nsIXPathResult> xpathResult = do_QueryInterface(aInResult); + nsRefPtr<XPathResult> xpathResult = aInResult; if (!xpathResult) { - // Either no aInResult or not one of ours. - xpathResult = new XPathResult(context); + xpathResult = new XPathResult(&aContextNode); } - rv = xpathResult->SetExprResult(exprResult, resultType, context); - NS_ENSURE_SUCCESS(rv, rv); - return CallQueryInterface(xpathResult, aResult); + aRv = xpathResult->SetExprResult(exprResult, resultType, &aContextNode); + + return xpathResult.forget(); } /* - * Implementation of the txIEvalContext private to nsXPathExpression + * Implementation of the txIEvalContext private to XPathExpression * EvalContextImpl bases on only one context node and no variables */ nsresult -nsXPathExpression::EvalContextImpl::getVariable(int32_t aNamespace, - nsIAtom* aLName, - txAExprResult*& aResult) +EvalContextImpl::getVariable(int32_t aNamespace, + nsIAtom* aLName, + txAExprResult*& aResult) { aResult = 0; return NS_ERROR_INVALID_ARG; } -bool nsXPathExpression::EvalContextImpl::isStripSpaceAllowed(const txXPathNode& aNode) +bool +EvalContextImpl::isStripSpaceAllowed(const txXPathNode& aNode) { return false; } -void* nsXPathExpression::EvalContextImpl::getPrivateContext() +void* +EvalContextImpl::getPrivateContext() { // we don't have a private context here. return nullptr; } -txResultRecycler* nsXPathExpression::EvalContextImpl::recycler() +txResultRecycler* +EvalContextImpl::recycler() { return mRecycler; } -void nsXPathExpression::EvalContextImpl::receiveError(const nsAString& aMsg, - nsresult aRes) +void +EvalContextImpl::receiveError(const nsAString& aMsg, nsresult aRes) { mLastError = aRes; // forward aMsg to console service? } -const txXPathNode& nsXPathExpression::EvalContextImpl::getContextNode() +const txXPathNode& +EvalContextImpl::getContextNode() { return mContextNode; } -uint32_t nsXPathExpression::EvalContextImpl::size() +uint32_t +EvalContextImpl::size() { return mContextSize; } -uint32_t nsXPathExpression::EvalContextImpl::position() +uint32_t +EvalContextImpl::position() { return mContextPosition; } + +} // namespace dom +} // namespace mozilla
rename from dom/xslt/xpath/nsXPathExpression.h rename to dom/xslt/xpath/XPathExpression.h --- a/dom/xslt/xpath/nsXPathExpression.h +++ b/dom/xslt/xpath/XPathExpression.h @@ -1,78 +1,75 @@ /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* 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 nsXPathExpression_h__ -#define nsXPathExpression_h__ +#ifndef mozilla_dom_XPathExpression_h +#define mozilla_dom_XPathExpression_h -#include "nsIDOMXPathExpression.h" -#include "nsIDOMNSXPathExpression.h" -#include "txIXPathContext.h" -#include "txResultRecycler.h" #include "nsAutoPtr.h" #include "nsCycleCollectionParticipant.h" +#include "nsIWeakReferenceUtils.h" #include "mozilla/Attributes.h" +#include "mozilla/dom/NonRefcountedDOMObject.h" +#include "mozilla/dom/XPathExpressionBinding.h" class Expr; +class nsIDocument; +class nsINode; +class txResultRecycler; class txXPathNode; +namespace mozilla { +namespace dom { + +class XPathResult; + /** * A class for evaluating an XPath expression string */ -class nsXPathExpression MOZ_FINAL : public nsIDOMXPathExpression, - public nsIDOMNSXPathExpression +class XPathExpression MOZ_FINAL : public NonRefcountedDOMObject { public: - nsXPathExpression(nsAutoPtr<Expr>&& aExpression, txResultRecycler* aRecycler, - nsIDOMDocument *aDocument); + XPathExpression(nsAutoPtr<Expr>&& aExpression, txResultRecycler* aRecycler, + nsIDocument *aDocument); + ~XPathExpression(); + + JSObject* WrapObject(JSContext* aCx, bool* aTookOwnership) + { + return XPathExpressionBinding::Wrap(aCx, this, aTookOwnership); + } - // nsISupports interface - NS_DECL_CYCLE_COLLECTING_ISUPPORTS - NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsXPathExpression, - nsIDOMXPathExpression) - - // nsIDOMXPathExpression interface - NS_DECL_NSIDOMXPATHEXPRESSION - - // nsIDOMNSXPathExpression interface - NS_DECL_NSIDOMNSXPATHEXPRESSION + already_AddRefed<XPathResult> + Evaluate(JSContext* aCx, nsINode& aContextNode, uint16_t aType, + JS::Handle<JSObject*> aInResult, ErrorResult& aRv) + { + return EvaluateWithContext(aCx, aContextNode, 1, 1, aType, aInResult, + aRv); + } + already_AddRefed<XPathResult> + EvaluateWithContext(JSContext* aCx, nsINode& aContextNode, + uint32_t aContextPosition, uint32_t aContextSize, + uint16_t aType, JS::Handle<JSObject*> aInResult, + ErrorResult& aRv); + already_AddRefed<XPathResult> + Evaluate(nsINode& aContextNode, uint16_t aType, XPathResult* aInResult, + ErrorResult& aRv) + { + return EvaluateWithContext(aContextNode, 1, 1, aType, aInResult, aRv); + } + already_AddRefed<XPathResult> + EvaluateWithContext(nsINode& aContextNode, uint32_t aContextPosition, + uint32_t aContextSize, uint16_t aType, + XPathResult* aInResult, ErrorResult& aRv); private: - ~nsXPathExpression() {} - nsAutoPtr<Expr> mExpression; nsRefPtr<txResultRecycler> mRecycler; - nsCOMPtr<nsIDOMDocument> mDocument; - - class EvalContextImpl : public txIEvalContext - { - public: - EvalContextImpl(const txXPathNode& aContextNode, - uint32_t aContextPosition, uint32_t aContextSize, - txResultRecycler* aRecycler) - : mContextNode(aContextNode), - mContextPosition(aContextPosition), - mContextSize(aContextSize), - mLastError(NS_OK), - mRecycler(aRecycler) - { - } - - nsresult getError() - { - return mLastError; - } - - TX_DECL_EVAL_CONTEXT; - - private: - const txXPathNode& mContextNode; - uint32_t mContextPosition; - uint32_t mContextSize; - nsresult mLastError; - nsRefPtr<txResultRecycler> mRecycler; - }; + nsWeakPtr mDocument; + bool mCheckDocument; }; -#endif +} // namespace dom +} // namespace mozilla + +#endif /* mozilla_dom_XPathExpression_h */
--- a/dom/xslt/xpath/moz.build +++ b/dom/xslt/xpath/moz.build @@ -1,21 +1,21 @@ # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- # vim: set filetype=python: # 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/. EXPORTS.mozilla.dom += [ 'XPathEvaluator.h', + 'XPathExpression.h', 'XPathResult.h', ] UNIFIED_SOURCES += [ - 'nsXPathExpression.cpp', 'nsXPathNSResolver.cpp', 'txBooleanExpr.cpp', 'txBooleanResult.cpp', 'txCoreFunctionCall.cpp', 'txErrorExpr.cpp', 'txExpr.cpp', 'txExprLexer.cpp', 'txExprParser.cpp', @@ -42,16 +42,17 @@ UNIFIED_SOURCES += [ 'txStringResult.cpp', 'txUnaryExpr.cpp', 'txUnionExpr.cpp', 'txUnionNodeTest.cpp', 'txVariableRefExpr.cpp', 'txXPathOptimizer.cpp', 'txXPCOMExtensionFunction.cpp', 'XPathEvaluator.cpp', + 'XPathExpression.cpp', 'XPathResult.cpp', ] FAIL_ON_WARNINGS = True LOCAL_INCLUDES += [ '../base', '../xml',
--- a/dom/xslt/xpath/txResultRecycler.cpp +++ b/dom/xslt/xpath/txResultRecycler.cpp @@ -3,19 +3,19 @@ * 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 "txResultRecycler.h" #include "txExprResult.h" #include "txNodeSet.h" txResultRecycler::txResultRecycler() - : mEmptyStringResult(nullptr), - mTrueResult(nullptr), - mFalseResult(nullptr) + : mEmptyStringResult(new StringResult(nullptr)), + mTrueResult(new BooleanResult(true)), + mFalseResult(new BooleanResult(false)) { } txResultRecycler::~txResultRecycler() { txStackIterator stringIter(&mStringResults); while (stringIter.hasNext()) { delete static_cast<StringResult*>(stringIter.next()); @@ -23,44 +23,16 @@ txResultRecycler::~txResultRecycler() txStackIterator nodesetIter(&mNodeSetResults); while (nodesetIter.hasNext()) { delete static_cast<txNodeSet*>(nodesetIter.next()); } txStackIterator numberIter(&mNumberResults); while (numberIter.hasNext()) { delete static_cast<NumberResult*>(numberIter.next()); } - - NS_IF_RELEASE(mEmptyStringResult); - NS_IF_RELEASE(mTrueResult); - NS_IF_RELEASE(mFalseResult); -} - - -nsresult -txResultRecycler::init() -{ - NS_ASSERTION(!mEmptyStringResult && !mTrueResult && !mFalseResult, - "Already inited"); - mEmptyStringResult = new StringResult(nullptr); - NS_ENSURE_TRUE(mEmptyStringResult, NS_ERROR_OUT_OF_MEMORY); - - NS_ADDREF(mEmptyStringResult); - - mTrueResult = new BooleanResult(true); - NS_ENSURE_TRUE(mTrueResult, NS_ERROR_OUT_OF_MEMORY); - - NS_ADDREF(mTrueResult); - - mFalseResult = new BooleanResult(false); - NS_ENSURE_TRUE(mFalseResult, NS_ERROR_OUT_OF_MEMORY); - - NS_ADDREF(mFalseResult); - - return NS_OK; } void txResultRecycler::recycle(txAExprResult* aResult) { NS_ASSERTION(aResult->mRefCnt == 0, "In-use txAExprResult recycled"); nsRefPtr<txResultRecycler> kungFuDeathGrip;
--- a/dom/xslt/xpath/txResultRecycler.h +++ b/dom/xslt/xpath/txResultRecycler.h @@ -2,31 +2,31 @@ /* 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 txResultRecycler_h__ #define txResultRecycler_h__ #include "nsCOMPtr.h" +#include "nsAutoPtr.h" #include "txStack.h" class txAExprResult; class StringResult; class txNodeSet; class txXPathNode; class NumberResult; class BooleanResult; class txResultRecycler { public: txResultRecycler(); ~txResultRecycler(); - nsresult init(); void AddRef() { ++mRefCnt; NS_LOG_ADDREF(this, mRefCnt, "txResultRecycler", sizeof(*this)); } void Release() { @@ -67,14 +67,14 @@ public: */ nsresult getNonSharedNodeSet(txNodeSet* aNodeSet, txNodeSet** aResult); private: nsAutoRefCnt mRefCnt; txStack mStringResults; txStack mNodeSetResults; txStack mNumberResults; - StringResult* mEmptyStringResult; - BooleanResult* mTrueResult; - BooleanResult* mFalseResult; + nsRefPtr<StringResult> mEmptyStringResult; + nsRefPtr<BooleanResult> mTrueResult; + nsRefPtr<BooleanResult> mFalseResult; }; #endif //txResultRecycler_h__
--- a/dom/xslt/xpath/txXPathOptimizer.cpp +++ b/dom/xslt/xpath/txXPathOptimizer.cpp @@ -75,21 +75,16 @@ txXPathOptimizer::optimize(Expr* aInExpr nsresult rv = NS_OK; // First check if the expression will produce the same result // under any context. Expr::ExprType exprType = aInExpr->getType(); if (exprType != Expr::LITERAL_EXPR && !aInExpr->isSensitiveTo(Expr::ANY_CONTEXT)) { nsRefPtr<txResultRecycler> recycler = new txResultRecycler; - NS_ENSURE_TRUE(recycler, NS_ERROR_OUT_OF_MEMORY); - - rv = recycler->init(); - NS_ENSURE_SUCCESS(rv, rv); - txEarlyEvalContext context(recycler); nsRefPtr<txAExprResult> exprRes; // Don't throw if this fails since it could be that the expression // is or contains an error-expression. rv = aInExpr->evaluate(&context, getter_AddRefs(exprRes)); if (NS_SUCCEEDED(rv)) { *aOutExpr = new txLiteralExpr(exprRes);
--- a/dom/xslt/xslt/txExecutionState.cpp +++ b/dom/xslt/xslt/txExecutionState.cpp @@ -120,20 +120,16 @@ txExecutionState::init(const txXPathNode // Set up loaded-documents-hash mLoadedDocuments.init(txXPathNodeUtils::getOwnerDocument(aNode)); // Init members rv = mKeyHash.init(); NS_ENSURE_SUCCESS(rv, rv); mRecycler = new txResultRecycler; - NS_ENSURE_TRUE(mRecycler, NS_ERROR_OUT_OF_MEMORY); - - rv = mRecycler->init(); - NS_ENSURE_SUCCESS(rv, rv); // The actual value here doesn't really matter since noone should use this // value. But lets put something errorlike in just in case mGlobalVarPlaceholderValue = new StringResult(NS_LITERAL_STRING("Error"), nullptr); NS_ENSURE_TRUE(mGlobalVarPlaceholderValue, NS_ERROR_OUT_OF_MEMORY); // Initiate first instruction. This has to be done last since findTemplate // might use us.
--- a/dom/xslt/xslt/txMozillaXSLTProcessor.cpp +++ b/dom/xslt/xslt/txMozillaXSLTProcessor.cpp @@ -465,20 +465,16 @@ txMozillaXSLTProcessor::AddXSLTParam(con // Set up context nsAutoPtr<txXPathNode> contextNode( txXPathNativeNode::createXPathNode(aContext)); NS_ENSURE_TRUE(contextNode, NS_ERROR_OUT_OF_MEMORY); if (!mRecycler) { mRecycler = new txResultRecycler; - NS_ENSURE_TRUE(mRecycler, NS_ERROR_OUT_OF_MEMORY); - - rv = mRecycler->init(); - NS_ENSURE_SUCCESS(rv, rv); } txXSLTParamContext paramContext(&mParamNamespaceMap, *contextNode, mRecycler); // Parse nsAutoPtr<Expr> expr; rv = txExprParser::createExpr(aSelect, ¶mContext,
--- a/gfx/layers/ipc/ISurfaceAllocator.cpp +++ b/gfx/layers/ipc/ISurfaceAllocator.cpp @@ -173,17 +173,20 @@ ISurfaceAllocator::DestroySharedSurface( NS_RUNTIMEABORT("surface type not implemented!"); } *aSurface = SurfaceDescriptor(); } // XXX - We should actually figure out the minimum shmem allocation size on // a certain platform and use that. const uint32_t sShmemPageSize = 4096; + +#ifdef DEBUG const uint32_t sSupportedBlockSize = 4; +#endif enum AllocationStatus { STATUS_ALLOCATED, STATUS_FREED }; struct ShmemSectionHeapHeader @@ -319,10 +322,10 @@ ISurfaceAllocator::AllocGrallocBuffer(co } void ISurfaceAllocator::DeallocGrallocBuffer(MaybeMagicGrallocBufferHandle* aHandle) { SharedBufferManagerChild::GetSingleton()->DeallocGrallocBuffer(*aHandle); } -} // namespace -} // namespace +} // namespace layers +} // namespace mozilla
--- a/gfx/layers/opengl/CompositorOGL.cpp +++ b/gfx/layers/opengl/CompositorOGL.cpp @@ -54,18 +54,16 @@ #include "GeckoProfiler.h" #if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17 #include "libdisplay/GonkDisplay.h" // for GonkDisplay #include <ui/Fence.h> #endif -#define BUFFER_OFFSET(i) ((char *)nullptr + (i)) - namespace mozilla { using namespace std; using namespace gfx; namespace layers { using namespace mozilla::gl; @@ -401,21 +399,23 @@ SetRects(int n, { if (flip_y) { std::swap(ty0, ty1); } aLayerRects[n] = Rect(x0, y0, x1 - x0, y1 - y0); aTextureRects[n] = Rect(tx0, ty0, tx1 - tx0, ty1 - ty0); } +#ifdef DEBUG static inline bool FuzzyEqual(float a, float b) { return fabs(a - b) < 0.0001f; } +#endif static int DecomposeIntoNoRepeatRects(const Rect& aRect, const Rect& aTexCoordRect, Rect* aLayerRects, Rect* aTextureRects) { Rect texCoordRect = aTexCoordRect;
--- a/gfx/src/nsFontMetrics.cpp +++ b/gfx/src/nsFontMetrics.cpp @@ -157,23 +157,25 @@ nscoord nsFontMetrics::XHeight() { return ROUND_TO_TWIPS(GetMetrics().xHeight); } nscoord nsFontMetrics::SuperscriptOffset() { - return ROUND_TO_TWIPS(GetMetrics().superscriptOffset); + return ROUND_TO_TWIPS(GetMetrics().emHeight * + NS_FONT_SUPERSCRIPT_OFFSET_RATIO); } nscoord nsFontMetrics::SubscriptOffset() { - return ROUND_TO_TWIPS(GetMetrics().subscriptOffset); + return ROUND_TO_TWIPS(GetMetrics().emHeight * + NS_FONT_SUBSCRIPT_OFFSET_RATIO); } void nsFontMetrics::GetStrikeout(nscoord& aOffset, nscoord& aSize) { aOffset = ROUND_TO_TWIPS(GetMetrics().strikeoutOffset); aSize = ROUND_TO_TWIPS(GetMetrics().strikeoutSize); }
--- a/gfx/tests/gtest/TestAsyncPanZoomController.cpp +++ b/gfx/tests/gtest/TestAsyncPanZoomController.cpp @@ -8,16 +8,17 @@ #include "mozilla/Attributes.h" #include "mozilla/layers/AsyncCompositionManager.h" // for ViewTransform #include "mozilla/layers/AsyncPanZoomController.h" #include "mozilla/layers/LayerManagerComposite.h" #include "mozilla/layers/GeckoContentController.h" #include "mozilla/layers/CompositorParent.h" #include "mozilla/layers/APZCTreeManager.h" +#include "mozilla/Preferences.h" #include "base/task.h" #include "Layers.h" #include "TestLayers.h" #include "gfxPrefs.h" using namespace mozilla; using namespace mozilla::gfx; using namespace mozilla::layers; @@ -53,16 +54,34 @@ public: MOCK_METHOD3(HandleDoubleTap, void(const CSSPoint&, int32_t, const ScrollableLayerGuid&)); MOCK_METHOD3(HandleSingleTap, void(const CSSPoint&, int32_t, const ScrollableLayerGuid&)); MOCK_METHOD3(HandleLongTap, void(const CSSPoint&, int32_t, const ScrollableLayerGuid&)); MOCK_METHOD3(HandleLongTapUp, void(const CSSPoint&, int32_t, const ScrollableLayerGuid&)); MOCK_METHOD3(SendAsyncScrollDOMEvent, void(bool aIsRoot, const CSSRect &aContentRect, const CSSSize &aScrollableSize)); MOCK_METHOD2(PostDelayedTask, void(Task* aTask, int aDelayMs)); }; +class TestScopedBoolPref { +public: + TestScopedBoolPref(const char* aPref, bool aVal) + : mPref(aPref) + { + mOldVal = Preferences::GetBool(aPref); + Preferences::SetBool(aPref, aVal); + } + + ~TestScopedBoolPref() { + Preferences::SetBool(mPref, mOldVal); + } + +private: + const char* mPref; + bool mOldVal; +}; + class MockContentControllerDelayed : public MockContentController { public: MockContentControllerDelayed() { } void PostDelayedTask(Task* aTask, int aDelayMs) { mTaskQueue.AppendElement(aTask); @@ -879,40 +898,100 @@ TEST_F(AsyncPanZoomControllerTester, Fli DoFlingStopTest(false); } TEST_F(AsyncPanZoomControllerTester, FlingStopTap) { DoFlingStopTest(true); } TEST_F(AsyncPanZoomControllerTester, OverScrollPanning) { + TestScopedBoolPref overscrollEnabledPref("apz.overscroll.enabled", true); + TimeStamp testStartTime = TimeStamp::Now(); AsyncPanZoomController::SetFrameTime(testStartTime); nsRefPtr<MockContentController> mcc = new NiceMock<MockContentController>(); nsRefPtr<TestAPZCTreeManager> tm = new TestAPZCTreeManager(); nsRefPtr<TestAsyncPanZoomController> apzc = new TestAsyncPanZoomController(0, mcc, tm); apzc->SetFrameMetrics(TestFrameMetrics()); apzc->NotifyLayersUpdated(TestFrameMetrics(), true); - EXPECT_CALL(*mcc, SendAsyncScrollDOMEvent(_,_,_)).Times(AtLeast(1)); - EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(1); + // Pan sufficiently to hit overscroll behavior + int time = 0; + int touchStart = 500; + int touchEnd = 10; + ApzcPan(apzc, tm, time, touchStart, touchEnd); + EXPECT_TRUE(apzc->IsOverscrolled()); + + // Note that in the calls to SampleContentTransformForFrame below, the time + // increment used is sufficiently large for the animation to have completed. However, + // any single call to SampleContentTransformForFrame will not finish an animation + // *and* also proceed through the following animation, if there is one. + // Therefore the minimum number of calls to go from an overscroll-inducing pan + // to a reset state is 3; these are documented further below. + + ScreenPoint pointOut; + ViewTransform viewTransformOut; + + // This sample will run to the end of the non-overscrolling fling animation + // and will schedule the overscrolling fling animation. + apzc->SampleContentTransformForFrame(testStartTime + TimeDuration::FromMilliseconds(10000), &viewTransformOut, pointOut); + EXPECT_EQ(ScreenPoint(0, 90), pointOut); + EXPECT_TRUE(apzc->IsOverscrolled()); + + // This sample will run to the end of the overscrolling fling animation and + // will schedule the snapback animation. + apzc->SampleContentTransformForFrame(testStartTime + TimeDuration::FromMilliseconds(20000), &viewTransformOut, pointOut); + EXPECT_EQ(ScreenPoint(0, 90), pointOut); + EXPECT_TRUE(apzc->IsOverscrolled()); + + // This sample will run to the end of the snapback animation and reset the state. + apzc->SampleContentTransformForFrame(testStartTime + TimeDuration::FromMilliseconds(30000), &viewTransformOut, pointOut); + EXPECT_EQ(ScreenPoint(0, 90), pointOut); + EXPECT_FALSE(apzc->IsOverscrolled()); + + apzc->AssertStateIsReset(); + apzc->Destroy(); +} + +TEST_F(AsyncPanZoomControllerTester, OverScrollAbort) { + TestScopedBoolPref overscrollEnabledPref("apz.overscroll.enabled", true); + + TimeStamp testStartTime = TimeStamp::Now(); + AsyncPanZoomController::SetFrameTime(testStartTime); + + nsRefPtr<MockContentController> mcc = new NiceMock<MockContentController>(); + nsRefPtr<TestAPZCTreeManager> tm = new TestAPZCTreeManager(); + nsRefPtr<TestAsyncPanZoomController> apzc = new TestAsyncPanZoomController(0, mcc, tm); + + apzc->SetFrameMetrics(TestFrameMetrics()); + apzc->NotifyLayersUpdated(TestFrameMetrics(), true); // Pan sufficiently to hit overscroll behavior int time = 0; int touchStart = 500; int touchEnd = 10; + ApzcPan(apzc, tm, time, touchStart, touchEnd); + EXPECT_TRUE(apzc->IsOverscrolled()); + ScreenPoint pointOut; ViewTransform viewTransformOut; - // Pan down - ApzcPan(apzc, tm, time, touchStart, touchEnd); - apzc->SampleContentTransformForFrame(testStartTime+TimeDuration::FromMilliseconds(1000), &viewTransformOut, pointOut); - EXPECT_EQ(ScreenPoint(0, 90), pointOut); + // This sample call will run to the end of the non-overscrolling fling animation + // and will schedule the overscrolling fling animation (see comment in OverScrollPanning + // above for more explanation). + apzc->SampleContentTransformForFrame(testStartTime + TimeDuration::FromMilliseconds(10000), &viewTransformOut, pointOut); + EXPECT_TRUE(apzc->IsOverscrolled()); + + // At this point, we have an active overscrolling fling animation. + // Check that cancelling the animation clears the overscroll. + apzc->CancelAnimation(); + EXPECT_FALSE(apzc->IsOverscrolled()); + apzc->AssertStateIsReset(); apzc->Destroy(); } TEST_F(AsyncPanZoomControllerTester, ShortPress) { nsRefPtr<MockContentControllerDelayed> mcc = new NiceMock<MockContentControllerDelayed>(); nsRefPtr<TestAPZCTreeManager> tm = new TestAPZCTreeManager(); nsRefPtr<TestAsyncPanZoomController> apzc = new TestAsyncPanZoomController(
--- a/gfx/thebes/gfxDWriteFonts.cpp +++ b/gfx/thebes/gfxDWriteFonts.cpp @@ -2,19 +2,17 @@ * 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 "gfxDWriteFonts.h" #include "mozilla/MemoryReporting.h" -#include "gfxHarfBuzzShaper.h" #include <algorithm> -#include "gfxGraphiteShaper.h" #include "gfxDWriteFontList.h" #include "gfxContext.h" #include <dwrite.h> #include "harfbuzz/hb.h" // Chosen this as to resemble DWrite's own oblique face style. #define OBLIQUE_SKEW_FACTOR 0.3 @@ -101,24 +99,16 @@ gfxDWriteFont::gfxDWriteFont(gfxFontEntr rv = fe->CreateFontFace(getter_AddRefs(mFontFace), sims); if (NS_FAILED(rv)) { mIsValid = false; return; } ComputeMetrics(anAAOption); - - if (FontCanSupportGraphite()) { - mGraphiteShaper = new gfxGraphiteShaper(this); - } - - if (FontCanSupportHarfBuzz()) { - mHarfBuzzShaper = new gfxHarfBuzzShaper(this); - } } gfxDWriteFont::~gfxDWriteFont() { if (mCairoFontFace) { cairo_font_face_destroy(mCairoFontFace); } if (mScaledFont) { @@ -129,42 +119,16 @@ gfxDWriteFont::~gfxDWriteFont() gfxFont* gfxDWriteFont::CopyWithAntialiasOption(AntialiasOption anAAOption) { return new gfxDWriteFont(static_cast<gfxDWriteFontEntry*>(mFontEntry.get()), &mStyle, mNeedsBold, anAAOption); } -bool -gfxDWriteFont::ShapeText(gfxContext *aContext, - const char16_t *aText, - uint32_t aOffset, - uint32_t aLength, - int32_t aScript, - gfxShapedText *aShapedText, - bool aPreferPlatformShaping) -{ - bool ok = false; - - if (mGraphiteShaper && gfxPlatform::GetPlatform()->UseGraphiteShaping()) { - ok = mGraphiteShaper->ShapeText(aContext, aText, aOffset, aLength, - aScript, aShapedText); - } - - if (!ok && mHarfBuzzShaper) { - ok = mHarfBuzzShaper->ShapeText(aContext, aText, aOffset, aLength, - aScript, aShapedText); - } - - PostShapingFixup(aContext, aText, aOffset, aLength, aShapedText); - - return ok; -} - const gfxFont::Metrics& gfxDWriteFont::GetMetrics() { return *mMetrics; } bool gfxDWriteFont::GetFakeMetricsForArialBlack(DWRITE_FONT_METRICS *aFontMetrics) @@ -311,32 +275,29 @@ gfxDWriteFont::ComputeMetrics(AntialiasO mMetrics->underlineOffset = fontMetrics.underlinePosition * mFUnitsConvFactor; mMetrics->underlineSize = fontMetrics.underlineThickness * mFUnitsConvFactor; mMetrics->strikeoutOffset = fontMetrics.strikethroughPosition * mFUnitsConvFactor; mMetrics->strikeoutSize = fontMetrics.strikethroughThickness * mFUnitsConvFactor; - mMetrics->superscriptOffset = 0; - mMetrics->subscriptOffset = 0; SanitizeMetrics(mMetrics, GetFontEntry()->mIsBadUnderlineFont); #if 0 printf("Font: %p (%s) size: %f\n", this, NS_ConvertUTF16toUTF8(GetName()).get(), mStyle.size); printf(" emHeight: %f emAscent: %f emDescent: %f\n", mMetrics->emHeight, mMetrics->emAscent, mMetrics->emDescent); printf(" maxAscent: %f maxDescent: %f maxAdvance: %f\n", mMetrics->maxAscent, mMetrics->maxDescent, mMetrics->maxAdvance); printf(" internalLeading: %f externalLeading: %f\n", mMetrics->internalLeading, mMetrics->externalLeading); printf(" spaceWidth: %f aveCharWidth: %f zeroOrAve: %f xHeight: %f\n", mMetrics->spaceWidth, mMetrics->aveCharWidth, mMetrics->zeroOrAveCharWidth, mMetrics->xHeight); - printf(" uOff: %f uSize: %f stOff: %f stSize: %f supOff: %f subOff: %f\n", - mMetrics->underlineOffset, mMetrics->underlineSize, mMetrics->strikeoutOffset, mMetrics->strikeoutSize, - mMetrics->superscriptOffset, mMetrics->subscriptOffset); + printf(" uOff: %f uSize: %f stOff: %f stSize: %f\n", + mMetrics->underlineOffset, mMetrics->underlineSize, mMetrics->strikeoutOffset, mMetrics->strikeoutSize); #endif } using namespace mozilla; // for AutoSwap_* types struct EBLCHeader { AutoSwap_PRUint32 version; AutoSwap_PRUint32 numSizes;
--- a/gfx/thebes/gfxDWriteFonts.h +++ b/gfx/thebes/gfxDWriteFonts.h @@ -66,24 +66,16 @@ public: virtual FontType GetType() const { return FONT_TYPE_DWRITE; } virtual mozilla::TemporaryRef<mozilla::gfx::ScaledFont> GetScaledFont(mozilla::gfx::DrawTarget *aTarget); virtual cairo_scaled_font_t *GetCairoScaledFont(); protected: - virtual bool ShapeText(gfxContext *aContext, - const char16_t *aText, - uint32_t aOffset, - uint32_t aLength, - int32_t aScript, - gfxShapedText *aShapedText, - bool aPreferPlatformShaping = false); - bool GetFakeMetricsForArialBlack(DWRITE_FONT_METRICS *aFontMetrics); void ComputeMetrics(AntialiasOption anAAOption); bool HasBitmapStrikeForSize(uint32_t aSize); cairo_font_face_t *CairoFontFace();
--- a/gfx/thebes/gfxFT2FontBase.cpp +++ b/gfx/thebes/gfxFT2FontBase.cpp @@ -128,17 +128,17 @@ gfxFT2FontBase::GetMetrics() // printf("font name: %s %f\n", NS_ConvertUTF16toUTF8(GetName()).get(), GetStyle()->size); // printf ("pango font %s\n", pango_font_description_to_string (pango_font_describe (font))); fprintf (stderr, "Font: %s\n", NS_ConvertUTF16toUTF8(GetName()).get()); fprintf (stderr, " emHeight: %f emAscent: %f emDescent: %f\n", mMetrics.emHeight, mMetrics.emAscent, mMetrics.emDescent); fprintf (stderr, " maxAscent: %f maxDescent: %f\n", mMetrics.maxAscent, mMetrics.maxDescent); fprintf (stderr, " internalLeading: %f externalLeading: %f\n", mMetrics.externalLeading, mMetrics.internalLeading); fprintf (stderr, " spaceWidth: %f aveCharWidth: %f xHeight: %f\n", mMetrics.spaceWidth, mMetrics.aveCharWidth, mMetrics.xHeight); - fprintf (stderr, " uOff: %f uSize: %f stOff: %f stSize: %f suOff: %f suSize: %f\n", mMetrics.underlineOffset, mMetrics.underlineSize, mMetrics.strikeoutOffset, mMetrics.strikeoutSize, mMetrics.superscriptOffset, mMetrics.subscriptOffset); + fprintf (stderr, " uOff: %f uSize: %f stOff: %f stSize: %f\n", mMetrics.underlineOffset, mMetrics.underlineSize, mMetrics.strikeoutOffset, mMetrics.strikeoutSize); #endif mHasMetrics = true; return mMetrics; } // Get the glyphID of a space uint32_t
--- a/gfx/thebes/gfxFT2Fonts.cpp +++ b/gfx/thebes/gfxFT2Fonts.cpp @@ -19,18 +19,16 @@ #endif #include "gfxTypes.h" #include "gfxFT2Fonts.h" #include "gfxFT2FontBase.h" #include "gfxFT2Utils.h" #include "gfxFT2FontList.h" #include <locale.h> -#include "gfxHarfBuzzShaper.h" -#include "gfxGraphiteShaper.h" #include "nsGkAtoms.h" #include "nsTArray.h" #include "nsUnicodeRange.h" #include "nsCRT.h" #include "nsXULAppAPI.h" #include "prlog.h" #include "prinit.h" @@ -39,52 +37,30 @@ #include "mozilla/Preferences.h" #include "mozilla/gfx/2D.h" /** * gfxFT2Font */ bool -gfxFT2Font::ShapeText(gfxContext *aContext, +gfxFT2Font::ShapeText(gfxContext *aContext, const char16_t *aText, - uint32_t aOffset, - uint32_t aLength, - int32_t aScript, - gfxShapedText *aShapedText, - bool aPreferPlatformShaping) + uint32_t aOffset, + uint32_t aLength, + int32_t aScript, + gfxShapedText *aShapedText) { - bool ok = false; - - if (FontCanSupportGraphite()) { - if (gfxPlatform::GetPlatform()->UseGraphiteShaping()) { - if (!mGraphiteShaper) { - mGraphiteShaper = new gfxGraphiteShaper(this); - } - ok = mGraphiteShaper->ShapeText(aContext, aText, - aOffset, aLength, - aScript, aShapedText); - } + if (!gfxFont::ShapeText(aContext, aText, aOffset, aLength, aScript, + aShapedText)) { + // harfbuzz must have failed(?!), just render raw glyphs + AddRange(aText, aOffset, aLength, aShapedText); + PostShapingFixup(aContext, aText, aOffset, aLength, aShapedText); } - if (!ok && gfxPlatform::GetPlatform()->UseHarfBuzzForScript(aScript)) { - if (!mHarfBuzzShaper) { - mHarfBuzzShaper = new gfxHarfBuzzShaper(this); - } - ok = mHarfBuzzShaper->ShapeText(aContext, aText, - aOffset, aLength, - aScript, aShapedText); - } - - if (!ok) { - AddRange(aText, aOffset, aLength, aShapedText); - } - - PostShapingFixup(aContext, aText, aOffset, aLength, aShapedText); - return true; } void gfxFT2Font::AddRange(const char16_t *aText, uint32_t aOffset, uint32_t aLength, gfxShapedText *aShapedText) { const uint32_t appUnitsPerDevUnit = aShapedText->GetAppUnitsPerDevUnit();
--- a/gfx/thebes/gfxFT2Fonts.h +++ b/gfx/thebes/gfxFT2Fonts.h @@ -72,18 +72,17 @@ public: // new functions #endif protected: virtual bool ShapeText(gfxContext *aContext, const char16_t *aText, uint32_t aOffset, uint32_t aLength, int32_t aScript, - gfxShapedText *aShapedText, - bool aPreferPlatformShaping); + gfxShapedText *aShapedText); void FillGlyphDataForChar(uint32_t ch, CachedGlyphData *gd); void AddRange(const char16_t *aText, uint32_t aOffset, uint32_t aLength, gfxShapedText *aShapedText);
--- a/gfx/thebes/gfxFT2Utils.cpp +++ b/gfx/thebes/gfxFT2Utils.cpp @@ -62,18 +62,16 @@ gfxFT2LockedFace::GetMetrics(gfxFont::Me aMetrics->externalLeading = 0.2 * emHeight; const gfxFloat spaceWidth = 0.5 * emHeight; aMetrics->spaceWidth = spaceWidth; aMetrics->maxAdvance = spaceWidth; aMetrics->aveCharWidth = spaceWidth; aMetrics->zeroOrAveCharWidth = spaceWidth; const gfxFloat xHeight = 0.5 * emHeight; aMetrics->xHeight = xHeight; - aMetrics->superscriptOffset = xHeight; - aMetrics->subscriptOffset = xHeight; const gfxFloat underlineSize = emHeight / 14.0; aMetrics->underlineSize = underlineSize; aMetrics->underlineOffset = -underlineSize; aMetrics->strikeoutOffset = 0.25 * emHeight; aMetrics->strikeoutSize = underlineSize; *aSpaceGlyph = 0; return; @@ -238,34 +236,16 @@ gfxFT2LockedFace::GetMetrics(gfxFont::Me } else { // No strikeout info. aMetrics->strikeoutSize = aMetrics->underlineSize; // Use OpenType spec's suggested position for Roman font. aMetrics->strikeoutOffset = emHeight * 409.0 / 2048.0 + 0.5 * aMetrics->strikeoutSize; } SnapLineToPixels(aMetrics->strikeoutOffset, aMetrics->strikeoutSize); - if (os2 && os2->ySuperscriptYOffset) { - gfxFloat val = ScaleRoundDesignUnits(os2->ySuperscriptYOffset, - ftMetrics.y_scale); - aMetrics->superscriptOffset = std::max(1.0, val); - } else { - aMetrics->superscriptOffset = aMetrics->xHeight; - } - - if (os2 && os2->ySubscriptYOffset) { - gfxFloat val = ScaleRoundDesignUnits(os2->ySubscriptYOffset, - ftMetrics.y_scale); - // some fonts have the incorrect sign. - val = fabs(val); - aMetrics->subscriptOffset = std::max(1.0, val); - } else { - aMetrics->subscriptOffset = aMetrics->xHeight; - } - aMetrics->maxHeight = aMetrics->maxAscent + aMetrics->maxDescent; // Make the line height an integer number of pixels so that lines will be // equally spaced (rather than just being snapped to pixels, some up and // some down). Layout calculates line height from the emHeight + // internalLeading + externalLeading, but first each of these is rounded // to layout units. To ensure that the result is an integer number of // pixels, round each of the components to pixels.
--- a/gfx/thebes/gfxFont.cpp +++ b/gfx/thebes/gfxFont.cpp @@ -18,16 +18,17 @@ #include "gfxFont.h" #include "gfxPlatform.h" #include "nsGkAtoms.h" #include "gfxTypes.h" #include "gfxContext.h" #include "gfxFontMissingGlyphs.h" +#include "gfxGraphiteShaper.h" #include "gfxHarfBuzzShaper.h" #include "gfxUserFontSet.h" #include "gfxPlatformFontList.h" #include "gfxScriptItemizer.h" #include "nsSpecialCasingData.h" #include "nsTextRunTransformations.h" #include "nsUnicodeProperties.h" #include "nsMathUtils.h" @@ -4069,61 +4070,57 @@ gfxFont::CacheHashEntry::KeyEquals(const } bool gfxFont::ShapeText(gfxContext *aContext, const uint8_t *aText, uint32_t aOffset, uint32_t aLength, int32_t aScript, - gfxShapedText *aShapedText, - bool aPreferPlatformShaping) + gfxShapedText *aShapedText) { nsDependentCSubstring ascii((const char*)aText, aLength); nsAutoString utf16; AppendASCIItoUTF16(ascii, utf16); if (utf16.Length() != aLength) { return false; } return ShapeText(aContext, utf16.BeginReading(), aOffset, aLength, - aScript, aShapedText, aPreferPlatformShaping); + aScript, aShapedText); } bool gfxFont::ShapeText(gfxContext *aContext, const char16_t *aText, uint32_t aOffset, uint32_t aLength, int32_t aScript, - gfxShapedText *aShapedText, - bool aPreferPlatformShaping) + gfxShapedText *aShapedText) { bool ok = false; - if (mGraphiteShaper && gfxPlatform::GetPlatform()->UseGraphiteShaping()) { - ok = mGraphiteShaper->ShapeText(aContext, aText, aOffset, aLength, - aScript, aShapedText); - } - - if (!ok && mHarfBuzzShaper && !aPreferPlatformShaping) { - if (gfxPlatform::GetPlatform()->UseHarfBuzzForScript(aScript)) { - ok = mHarfBuzzShaper->ShapeText(aContext, aText, aOffset, aLength, + if (FontCanSupportGraphite()) { + if (gfxPlatform::GetPlatform()->UseGraphiteShaping()) { + if (!mGraphiteShaper) { + mGraphiteShaper = new gfxGraphiteShaper(this); + } + ok = mGraphiteShaper->ShapeText(aContext, aText, aOffset, aLength, aScript, aShapedText); } } if (!ok) { - if (!mPlatformShaper) { - CreatePlatformShaper(); - } - if (mPlatformShaper) { - ok = mPlatformShaper->ShapeText(aContext, aText, aOffset, aLength, - aScript, aShapedText); - } - } + if (!mHarfBuzzShaper) { + mHarfBuzzShaper = new gfxHarfBuzzShaper(this); + } + ok = mHarfBuzzShaper->ShapeText(aContext, aText, aOffset, aLength, + aScript, aShapedText); + } + + NS_WARN_IF_FALSE(ok, "shaper failed, expect scrambled or missing text"); PostShapingFixup(aContext, aText, aOffset, aLength, aShapedText); return ok; } void gfxFont::PostShapingFixup(gfxContext *aContext, @@ -4592,18 +4589,16 @@ gfxFont::InitMetricsFromSfntTables(Metri // version 2 and later includes the x-height field SET_SIGNED(xHeight, os2->sxHeight); // Abs because of negative xHeight seen in Kokonor (Tibetan) font aMetrics.xHeight = Abs(aMetrics.xHeight); } // this should always be present in any valid OS/2 of any version if (len >= offsetof(OS2Table, sTypoLineGap) + sizeof(int16_t)) { SET_SIGNED(aveCharWidth, os2->xAvgCharWidth); - SET_SIGNED(subscriptOffset, os2->ySubscriptYOffset); - SET_SIGNED(superscriptOffset, os2->ySuperscriptYOffset); SET_SIGNED(strikeoutSize, os2->yStrikeoutSize); SET_SIGNED(strikeoutOffset, os2->yStrikeoutPosition); // for fonts with USE_TYPO_METRICS set in the fsSelection field, // and for all OpenType math fonts (having a 'MATH' table), // let the OS/2 sTypo* metrics override those from the hhea table // (see http://www.microsoft.com/typography/otspec/os2.htm#fss) const uint16_t kUseTypoMetricsMask = 1 << 7; @@ -4655,23 +4650,16 @@ void gfxFont::CalculateDerivedMetrics(Me if (GetFontEntry()->IsFixedPitch()) { // Some Quartz fonts are fixed pitch, but there's some glyph with a bigger // advance than the average character width... this forces // those fonts to be recognized like fixed pitch fonts by layout. aMetrics.maxAdvance = aMetrics.aveCharWidth; } - if (!aMetrics.subscriptOffset) { - aMetrics.subscriptOffset = aMetrics.xHeight; - } - if (!aMetrics.superscriptOffset) { - aMetrics.superscriptOffset = aMetrics.xHeight; - } - if (!aMetrics.strikeoutOffset) { aMetrics.strikeoutOffset = aMetrics.xHeight * 0.5; } if (!aMetrics.strikeoutSize) { aMetrics.strikeoutSize = aMetrics.underlineSize; } } @@ -4680,29 +4668,16 @@ gfxFont::SanitizeMetrics(gfxFont::Metric { // Even if this font size is zero, this font is created with non-zero size. // However, for layout and others, we should return the metrics of zero size font. if (mStyle.size == 0.0) { memset(aMetrics, 0, sizeof(gfxFont::Metrics)); return; } - // MS (P)Gothic and MS (P)Mincho are not having suitable values in their super script offset. - // If the values are not suitable, we should use x-height instead of them. - // See https://bugzilla.mozilla.org/show_bug.cgi?id=353632 - if (aMetrics->superscriptOffset <= 0 || - aMetrics->superscriptOffset >= aMetrics->maxAscent) { - aMetrics->superscriptOffset = aMetrics->xHeight; - } - // And also checking the case of sub script offset. The old gfx for win has checked this too. - if (aMetrics->subscriptOffset <= 0 || - aMetrics->subscriptOffset >= aMetrics->maxAscent) { - aMetrics->subscriptOffset = aMetrics->xHeight; - } - aMetrics->underlineSize = std::max(1.0, aMetrics->underlineSize); aMetrics->strikeoutSize = std::max(1.0, aMetrics->strikeoutSize); aMetrics->underlineOffset = std::min(aMetrics->underlineOffset, -1.0); if (aMetrics->maxAscent < 1.0) { // We cannot draw strikeout line and overline in the ascent... aMetrics->underlineSize = 0;
--- a/gfx/thebes/gfxFont.h +++ b/gfx/thebes/gfxFont.h @@ -1474,22 +1474,22 @@ public: NS_ASSERTION(aFont, "shaper requires a valid font!"); } virtual ~gfxFontShaper() { } // Shape a piece of text and store the resulting glyph data into // aShapedText. Parameters aOffset/aLength indicate the range of // aShapedText to be updated; aLength is also the length of aText. - virtual bool ShapeText(gfxContext *aContext, + virtual bool ShapeText(gfxContext *aContext, const char16_t *aText, - uint32_t aOffset, - uint32_t aLength, - int32_t aScript, - gfxShapedText *aShapedText) = 0; + uint32_t aOffset, + uint32_t aLength, + int32_t aScript, + gfxShapedText *aShapedText) = 0; gfxFont *GetFont() const { return mFont; } // returns true if features exist in output, false otherwise static bool MergeFontFeatures(const gfxFontStyle *aStyle, const nsTArray<gfxFontFeature>& aFontFeatures, bool aDisableLigatures, @@ -1653,18 +1653,16 @@ public: virtual mozilla::TemporaryRef<mozilla::gfx::GlyphRenderingOptions> GetGlyphRenderingOptions() { return nullptr; } gfxFloat SynthesizeSpaceWidth(uint32_t aCh); // Font metrics struct Metrics { gfxFloat xHeight; - gfxFloat superscriptOffset; - gfxFloat subscriptOffset; gfxFloat strikeoutSize; gfxFloat strikeoutOffset; gfxFloat underlineSize; gfxFloat underlineOffset; gfxFloat internalLeading; gfxFloat externalLeading; @@ -1993,28 +1991,26 @@ protected: bool SpaceMayParticipateInShaping(int32_t aRunScript); // For 8-bit text, expand to 16-bit and then call the following method. bool ShapeText(gfxContext *aContext, const uint8_t *aText, uint32_t aOffset, // dest offset in gfxShapedText uint32_t aLength, int32_t aScript, - gfxShapedText *aShapedText, // where to store the result - bool aPreferPlatformShaping = false); + gfxShapedText *aShapedText); // where to store the result // Call the appropriate shaper to generate glyphs for aText and store // them into aShapedText. virtual bool ShapeText(gfxContext *aContext, const char16_t *aText, uint32_t aOffset, uint32_t aLength, int32_t aScript, - gfxShapedText *aShapedText, - bool aPreferPlatformShaping = false); + gfxShapedText *aShapedText); // Helper to adjust for synthetic bold and set character-type flags // in the shaped text; implementations of ShapeText should call this // after glyph shaping has been completed. void PostShapingFixup(gfxContext *aContext, const char16_t *aText, uint32_t aOffset, // position within aShapedText uint32_t aLength, @@ -2163,29 +2159,24 @@ protected: // the AA setting requested for this font - may affect glyph bounds AntialiasOption mAntialiasOption; // a copy of the font without antialiasing, if needed for separate // measurement by mathml code nsAutoPtr<gfxFont> mNonAAFont; - // we may switch between these shapers on the fly, based on the script - // of the text run being shaped - nsAutoPtr<gfxFontShaper> mPlatformShaper; + // we create either or both of these shapers when needed, depending + // whether the font has graphite tables, and whether graphite shaping + // is actually enabled nsAutoPtr<gfxFontShaper> mHarfBuzzShaper; nsAutoPtr<gfxFontShaper> mGraphiteShaper; mozilla::RefPtr<mozilla::gfx::ScaledFont> mAzureScaledFont; - // Create a default platform text shaper for this font. - // (TODO: This should become pure virtual once all font backends have - // been updated.) - virtual void CreatePlatformShaper() { } - // Helper for subclasses that want to initialize standard metrics from the // tables of sfnt (TrueType/OpenType) fonts. // This will use mFUnitsConvFactor if it is already set, else compute it // from mAdjustedSize and the unitsPerEm in the font's 'head' table. // Returns TRUE and sets mIsValid=TRUE if successful; // Returns TRUE but leaves mIsValid=FALSE if the font seems to be broken. // Returns FALSE if the font does not appear to be an sfnt at all, // and should be handled (if possible) using other APIs.
--- a/gfx/thebes/gfxFontConstants.h +++ b/gfx/thebes/gfxFontConstants.h @@ -191,9 +191,13 @@ enum { #define NS_FONT_VARIANT_NUMERIC_FRACTION_MASK \ NS_FONT_VARIANT_NUMERIC_DIAGONAL_FRACTIONS | \ NS_FONT_VARIANT_NUMERIC_STACKED_FRACTIONS #define NS_FONT_VARIANT_POSITION_NORMAL 0 #define NS_FONT_VARIANT_POSITION_SUPER 1 #define NS_FONT_VARIANT_POSITION_SUB 2 +// based on fixed offset values used within WebKit +#define NS_FONT_SUBSCRIPT_OFFSET_RATIO (0.20) +#define NS_FONT_SUPERSCRIPT_OFFSET_RATIO (0.34) + #endif
--- a/gfx/thebes/gfxGDIFont.cpp +++ b/gfx/thebes/gfxGDIFont.cpp @@ -3,19 +3,17 @@ * 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 "gfxGDIFont.h" #include "mozilla/MemoryReporting.h" #include "mozilla/WindowsVersion.h" -#include "gfxHarfBuzzShaper.h" #include <algorithm> -#include "gfxGraphiteShaper.h" #include "gfxWindowsPlatform.h" #include "gfxContext.h" #include "mozilla/Preferences.h" #include "nsUnicodeProperties.h" #include "gfxFontConstants.h" #include "cairo-win32.h" @@ -47,20 +45,16 @@ gfxGDIFont::gfxGDIFont(GDIFontEntry *aFo : gfxFont(aFontEntry, aFontStyle, anAAOption), mFont(nullptr), mFontFace(nullptr), mMetrics(nullptr), mSpaceGlyph(0), mNeedsBold(aNeedsBold), mScriptCache(nullptr) { - if (FontCanSupportGraphite()) { - mGraphiteShaper = new gfxGraphiteShaper(this); - } - mHarfBuzzShaper = new gfxHarfBuzzShaper(this); } gfxGDIFont::~gfxGDIFont() { if (mScaledFont) { cairo_scaled_font_destroy(mScaledFont); } if (mFontFace) { @@ -78,23 +72,22 @@ gfxGDIFont::~gfxGDIFont() gfxFont* gfxGDIFont::CopyWithAntialiasOption(AntialiasOption anAAOption) { return new gfxGDIFont(static_cast<GDIFontEntry*>(mFontEntry.get()), &mStyle, mNeedsBold, anAAOption); } bool -gfxGDIFont::ShapeText(gfxContext *aContext, +gfxGDIFont::ShapeText(gfxContext *aContext, const char16_t *aText, - uint32_t aOffset, - uint32_t aLength, - int32_t aScript, - gfxShapedText *aShapedText, - bool aPreferPlatformShaping) + uint32_t aOffset, + uint32_t aLength, + int32_t aScript, + gfxShapedText *aShapedText) { if (!mMetrics) { Initialize(); } if (!mIsValid) { NS_WARNING("invalid font! expect incorrect text rendering"); return false; } @@ -103,17 +96,17 @@ gfxGDIFont::ShapeText(gfxContext *a // creating a "toy" font internally (see bug 544617). // We must check that this succeeded, otherwise we risk cairo creating the // wrong kind of font internally as a fallback (bug 744480). if (!SetupCairoFont(aContext)) { return false; } return gfxFont::ShapeText(aContext, aText, aOffset, aLength, aScript, - aShapedText, aPreferPlatformShaping); + aShapedText); } const gfxFont::Metrics& gfxGDIFont::GetMetrics() { if (!mMetrics) { Initialize(); } @@ -242,19 +235,16 @@ gfxGDIFont::Initialize() // Get font metrics if size > 0 if (mAdjustedSize > 0.0) { OUTLINETEXTMETRIC oMetrics; TEXTMETRIC& metrics = oMetrics.otmTextMetrics; if (0 < GetOutlineTextMetrics(dc.GetDC(), sizeof(oMetrics), &oMetrics)) { - mMetrics->superscriptOffset = (double)oMetrics.otmptSuperscriptOffset.y; - // Some fonts have wrong sign on their subscript offset, bug 410917. - mMetrics->subscriptOffset = fabs((double)oMetrics.otmptSubscriptOffset.y); mMetrics->strikeoutSize = (double)oMetrics.otmsStrikeoutSize; mMetrics->strikeoutOffset = (double)oMetrics.otmsStrikeoutPosition; mMetrics->underlineSize = (double)oMetrics.otmsUnderscoreSize; mMetrics->underlineOffset = (double)oMetrics.otmsUnderscorePosition; const MAT2 kIdentityMatrix = { {0, 1}, {0, 0}, {0, 0}, {0, 1} }; GLYPHMETRICS gm; DWORD len = GetGlyphOutlineW(dc.GetDC(), char16_t('x'), GGO_METRICS, &gm, 0, nullptr, &kIdentityMatrix); @@ -283,18 +273,16 @@ gfxGDIFont::Initialize() NS_WARNING("Missing or corrupt font data, fasten your seatbelt"); mIsValid = false; memset(mMetrics, 0, sizeof(*mMetrics)); return; } mMetrics->xHeight = ROUND((float)metrics.tmAscent * DEFAULT_XHEIGHT_FACTOR); - mMetrics->superscriptOffset = mMetrics->xHeight; - mMetrics->subscriptOffset = mMetrics->xHeight; mMetrics->strikeoutSize = 1; mMetrics->strikeoutOffset = ROUND(mMetrics->xHeight * 0.5f); // 50% of xHeight mMetrics->underlineSize = 1; mMetrics->underlineOffset = -ROUND((float)metrics.tmDescent * 0.30f); // 30% of descent mMetrics->emHeight = metrics.tmHeight - metrics.tmInternalLeading; mMetrics->emAscent = metrics.tmAscent - metrics.tmInternalLeading; mMetrics->emDescent = metrics.tmDescent; } @@ -389,19 +377,18 @@ gfxGDIFont::Initialize() #if 0 printf("Font: %p (%s) size: %f adjusted size: %f valid: %s\n", this, NS_ConvertUTF16toUTF8(GetName()).get(), mStyle.size, mAdjustedSize, (mIsValid ? "yes" : "no")); printf(" emHeight: %f emAscent: %f emDescent: %f\n", mMetrics->emHeight, mMetrics->emAscent, mMetrics->emDescent); printf(" maxAscent: %f maxDescent: %f maxAdvance: %f\n", mMetrics->maxAscent, mMetrics->maxDescent, mMetrics->maxAdvance); printf(" internalLeading: %f externalLeading: %f\n", mMetrics->internalLeading, mMetrics->externalLeading); printf(" spaceWidth: %f aveCharWidth: %f xHeight: %f\n", mMetrics->spaceWidth, mMetrics->aveCharWidth, mMetrics->xHeight); - printf(" uOff: %f uSize: %f stOff: %f stSize: %f supOff: %f subOff: %f\n", - mMetrics->underlineOffset, mMetrics->underlineSize, mMetrics->strikeoutOffset, mMetrics->strikeoutSize, - mMetrics->superscriptOffset, mMetrics->subscriptOffset); + printf(" uOff: %f uSize: %f stOff: %f stSize: %f\n", + mMetrics->underlineOffset, mMetrics->underlineSize, mMetrics->strikeoutOffset, mMetrics->strikeoutSize); #endif } void gfxGDIFont::FillLogFont(LOGFONTW& aLogFont, gfxFloat aSize, bool aUseGDIFakeItalic) { GDIFontEntry *fe = static_cast<GDIFontEntry*>(GetFontEntry());
--- a/gfx/thebes/gfxGDIFont.h +++ b/gfx/thebes/gfxGDIFont.h @@ -67,23 +67,22 @@ public: FontCacheSizes* aSizes) const; virtual void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf, FontCacheSizes* aSizes) const; virtual FontType GetType() const { return FONT_TYPE_GDI; } protected: /* override to ensure the cairo font is set up properly */ - virtual bool ShapeText(gfxContext *aContext, + virtual bool ShapeText(gfxContext *aContext, const char16_t *aText, - uint32_t aOffset, - uint32_t aLength, - int32_t aScript, - gfxShapedText *aShapedText, - bool aPreferPlatformShaping); + uint32_t aOffset, + uint32_t aLength, + int32_t aScript, + gfxShapedText *aShapedText); void Initialize(); // creates metrics and Cairo fonts // Fill the given LOGFONT record according to our style, but don't adjust // the lfItalic field if we're going to use a cairo transform for fake // italics. void FillLogFont(LOGFONTW& aLogFont, gfxFloat aSize, bool aUseGDIFakeItalic);
--- a/gfx/thebes/gfxMacFont.cpp +++ b/gfx/thebes/gfxMacFont.cpp @@ -3,19 +3,17 @@ * 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 "gfxMacFont.h" #include "mozilla/MemoryReporting.h" #include "gfxCoreTextShaper.h" -#include "gfxHarfBuzzShaper.h" #include <algorithm> -#include "gfxGraphiteShaper.h" #include "gfxPlatformMac.h" #include "gfxContext.h" #include "gfxFontUtils.h" #include "gfxMacPlatformFontList.h" #include "gfxFontConstants.h" #include "cairo-quartz.h" @@ -102,59 +100,54 @@ gfxMacFont::gfxMacFont(MacOSFontEntry *a mIsValid = false; #ifdef DEBUG char warnBuf[1024]; sprintf(warnBuf, "Failed to create scaled font: %s status: %d", NS_ConvertUTF16toUTF8(GetName()).get(), cairoerr); NS_WARNING(warnBuf); #endif } - - if (FontCanSupportGraphite()) { - mGraphiteShaper = new gfxGraphiteShaper(this); - } - if (FontCanSupportHarfBuzz()) { - mHarfBuzzShaper = new gfxHarfBuzzShaper(this); - } } gfxMacFont::~gfxMacFont() { if (mScaledFont) { cairo_scaled_font_destroy(mScaledFont); } if (mFontFace) { cairo_font_face_destroy(mFontFace); } } bool -gfxMacFont::ShapeText(gfxContext *aContext, +gfxMacFont::ShapeText(gfxContext *aContext, const char16_t *aText, - uint32_t aOffset, - uint32_t aLength, - int32_t aScript, - gfxShapedText *aShapedText, - bool aPreferPlatformShaping) + uint32_t aOffset, + uint32_t aLength, + int32_t aScript, + gfxShapedText *aShapedText) { if (!mIsValid) { NS_WARNING("invalid font! expect incorrect text rendering"); return false; } - bool requiresAAT = - static_cast<MacOSFontEntry*>(GetFontEntry())->RequiresAATLayout(); - return gfxFont::ShapeText(aContext, aText, aOffset, aLength, - aScript, aShapedText, requiresAAT); -} + if (static_cast<MacOSFontEntry*>(GetFontEntry())->RequiresAATLayout()) { + if (!mCoreTextShaper) { + mCoreTextShaper = new gfxCoreTextShaper(this); + } + if (mCoreTextShaper->ShapeText(aContext, aText, aOffset, aLength, + aScript, aShapedText)) { + PostShapingFixup(aContext, aText, aOffset, aLength, aShapedText); + return true; + } + } -void -gfxMacFont::CreatePlatformShaper() -{ - mPlatformShaper = new gfxCoreTextShaper(this); + return gfxFont::ShapeText(aContext, aText, aOffset, aLength, aScript, + aShapedText); } bool gfxMacFont::SetupCairoFont(gfxContext *aContext) { if (cairo_scaled_font_status(mScaledFont) != CAIRO_STATUS_SUCCESS) { // Don't cairo_set_scaled_font as that would propagate the error to // the cairo_t, precluding any further drawing. @@ -327,17 +320,17 @@ gfxMacFont::InitMetrics() #if 0 fprintf (stderr, "Font: %p (%s) size: %f\n", this, NS_ConvertUTF16toUTF8(GetName()).get(), mStyle.size); // fprintf (stderr, " fbounds.origin.x %f y %f size.width %f height %f\n", fbounds.origin.x, fbounds.origin.y, fbounds.size.width, fbounds.size.height); fprintf (stderr, " emHeight: %f emAscent: %f emDescent: %f\n", mMetrics.emHeight, mMetrics.emAscent, mMetrics.emDescent); fprintf (stderr, " maxAscent: %f maxDescent: %f maxAdvance: %f\n", mMetrics.maxAscent, mMetrics.maxDescent, mMetrics.maxAdvance); fprintf (stderr, " internalLeading: %f externalLeading: %f\n", mMetrics.internalLeading, mMetrics.externalLeading); fprintf (stderr, " spaceWidth: %f aveCharWidth: %f xHeight: %f\n", mMetrics.spaceWidth, mMetrics.aveCharWidth, mMetrics.xHeight); - fprintf (stderr, " uOff: %f uSize: %f stOff: %f stSize: %f supOff: %f subOff: %f\n", mMetrics.underlineOffset, mMetrics.underlineSize, mMetrics.strikeoutOffset, mMetrics.strikeoutSize, mMetrics.superscriptOffset, mMetrics.subscriptOffset); + fprintf (stderr, " uOff: %f uSize: %f stOff: %f stSize: %f\n", mMetrics.underlineOffset, mMetrics.underlineSize, mMetrics.strikeoutOffset, mMetrics.strikeoutSize); #endif } gfxFloat gfxMacFont::GetCharWidth(CFDataRef aCmap, char16_t aUniChar, uint32_t *aGlyphID, gfxFloat aConvFactor) { CGGlyph glyph = 0;
--- a/gfx/thebes/gfxMacFont.h +++ b/gfx/thebes/gfxMacFont.h @@ -46,38 +46,37 @@ public: virtual void AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf, FontCacheSizes* aSizes) const; virtual void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf, FontCacheSizes* aSizes) const; virtual FontType GetType() const { return FONT_TYPE_MAC; } protected: - virtual void CreatePlatformShaper(); - // override to prefer CoreText shaping with fonts that depend on AAT - virtual bool ShapeText(gfxContext *aContext, + virtual bool ShapeText(gfxContext *aContext, const char16_t *aText, - uint32_t aOffset, - uint32_t aLength, - int32_t aScript, - gfxShapedText *aShapedText, - bool aPreferPlatformShaping = false); + uint32_t aOffset, + uint32_t aLength, + int32_t aScript, + gfxShapedText *aShapedText); void InitMetrics(); void InitMetricsFromPlatform(); // Get width and glyph ID for a character; uses aConvFactor // to convert font units as returned by CG to actual dimensions gfxFloat GetCharWidth(CFDataRef aCmap, char16_t aUniChar, uint32_t *aGlyphID, gfxFloat aConvFactor); // a weak reference to the CoreGraphics font: this is owned by the // MacOSFontEntry, it is not retained or released by gfxMacFont CGFontRef mCGFont; cairo_font_face_t *mFontFace; + nsAutoPtr<gfxFontShaper> mCoreTextShaper; + Metrics mMetrics; uint32_t mSpaceGlyph; }; #endif /* GFX_MACFONT_H */
--- a/gfx/thebes/gfxPangoFonts.cpp +++ b/gfx/thebes/gfxPangoFonts.cpp @@ -15,18 +15,16 @@ #ifdef MOZ_WIDGET_QT #include "gfxQtPlatform.h" #endif #include "gfxPangoFonts.h" #include "gfxFT2FontBase.h" #include "gfxFT2Utils.h" #include "harfbuzz/hb.h" #include "harfbuzz/hb-ot.h" -#include "gfxHarfBuzzShaper.h" -#include "gfxGraphiteShaper.h" #include "nsUnicodeProperties.h" #include "nsUnicodeScriptCodes.h" #include "gfxFontconfigUtils.h" #include "gfxUserFontSet.h" #include "gfxFontConstants.h" #include <cairo.h> #include <cairo-ft.h> @@ -658,24 +656,16 @@ public: #ifdef USE_SKIA virtual mozilla::TemporaryRef<mozilla::gfx::GlyphRenderingOptions> GetGlyphRenderingOptions(); #endif protected: virtual already_AddRefed<gfxFont> GetSmallCapsFont(); - virtual bool ShapeText(gfxContext *aContext, - const char16_t *aText, - uint32_t aOffset, - uint32_t aLength, - int32_t aScript, - gfxShapedText *aShapedText, - bool aPreferPlatformShaping); - private: gfxFcFont(cairo_scaled_font_t *aCairoFont, gfxFcFontEntry *aFontEntry, const gfxFontStyle *aFontStyle); // key for locating a gfxFcFont corresponding to a cairo_scaled_font static cairo_user_data_key_t sGfxFontKey; }; @@ -1559,52 +1549,16 @@ gfxFcFont::GetSmallCapsFont() font = new gfxFcFont(smallFont, fe, &style); gfxFontCache::GetCache()->AddNew(font); cairo_scaled_font_destroy(smallFont); return font.forget(); } -bool -gfxFcFont::ShapeText(gfxContext *aContext, - const char16_t *aText, - uint32_t aOffset, - uint32_t aLength, - int32_t aScript, - gfxShapedText *aShapedText, - bool aPreferPlatformShaping) -{ - bool ok = false; - - if (FontCanSupportGraphite()) { - if (gfxPlatform::GetPlatform()->UseGraphiteShaping()) { - if (!mGraphiteShaper) { - mGraphiteShaper = new gfxGraphiteShaper(this); - } - ok = mGraphiteShaper->ShapeText(aContext, aText, aOffset, aLength, - aScript, aShapedText); - } - } - - if (!ok) { - if (!mHarfBuzzShaper) { - mHarfBuzzShaper = new gfxHarfBuzzShaper(this); - } - ok = mHarfBuzzShaper->ShapeText(aContext, aText, aOffset, aLength, - aScript, aShapedText); - } - - NS_WARN_IF_FALSE(ok, "shaper failed, expect scrambled or missing text"); - - PostShapingFixup(aContext, aText, aOffset, aLength, aShapedText); - - return ok; -} - /* static */ void gfxPangoFontGroup::Shutdown() { // Resetting gFTLibrary in case this is wanted again after a // cairo_debug_reset_static_data. gFTLibrary = nullptr; }
--- a/gfx/thebes/gfxPlatform.cpp +++ b/gfx/thebes/gfxPlatform.cpp @@ -140,18 +140,16 @@ public: NS_DECL_ISUPPORTS NS_DECL_NSIOBSERVER }; NS_IMPL_ISUPPORTS(SRGBOverrideObserver, nsIObserver, nsISupportsWeakReference) #define GFX_DOWNLOADABLE_FONTS_ENABLED "gfx.downloadable_fonts.enabled" -#define GFX_PREF_HARFBUZZ_SCRIPTS "gfx.font_rendering.harfbuzz.scripts" -#define HARFBUZZ_SCRIPTS_DEFAULT mozilla::unicode::SHAPING_DEFAULT #define GFX_PREF_FALLBACK_USE_CMAPS "gfx.font_rendering.fallback.always_use_cmaps" #define GFX_PREF_OPENTYPE_SVG "gfx.font_rendering.opentype_svg.enabled" #define GFX_PREF_WORD_CACHE_CHARLIMIT "gfx.font_rendering.wordcache.charlimit" #define GFX_PREF_WORD_CACHE_MAXENTRIES "gfx.font_rendering.wordcache.maxentries" #define GFX_PREF_GRAPHITE_SHAPING "gfx.font_rendering.graphite.enabled" @@ -261,17 +259,16 @@ static const char *gPrefLangNames[] = { "x-tibt", "x-unicode", }; gfxPlatform::gfxPlatform() : mAzureCanvasBackendCollector(MOZ_THIS_IN_INITIALIZER_LIST(), &gfxPlatform::GetAzureBackendInfo) { - mUseHarfBuzzScripts = UNINITIALIZED_VALUE; mAllowDownloadableFonts = UNINITIALIZED_VALUE; mFallbackUsesCmaps = UNINITIALIZED_VALUE; mWordCacheCharLimit = UNINITIALIZED_VALUE; mWordCacheMaxEntries = UNINITIALIZED_VALUE; mGraphiteShapingEnabled = UNINITIALIZED_VALUE; mOpenTypeSVGEnabled = UNINITIALIZED_VALUE; mBidiNumeralOption = UNINITIALIZED_VALUE; @@ -1129,28 +1126,16 @@ gfxPlatform::UseGraphiteShaping() if (mGraphiteShapingEnabled == UNINITIALIZED_VALUE) { mGraphiteShapingEnabled = Preferences::GetBool(GFX_PREF_GRAPHITE_SHAPING, false); } return mGraphiteShapingEnabled; } -bool -gfxPlatform::UseHarfBuzzForScript(int32_t aScriptCode) -{ - if (mUseHarfBuzzScripts == UNINITIALIZED_VALUE) { - mUseHarfBuzzScripts = Preferences::GetInt(GFX_PREF_HARFBUZZ_SCRIPTS, HARFBUZZ_SCRIPTS_DEFAULT); - } - - int32_t shapingType = mozilla::unicode::ScriptShapingType(aScriptCode); - - return (mUseHarfBuzzScripts & shapingType) != 0; -} - gfxFontEntry* gfxPlatform::MakePlatformFont(const gfxProxyFontEntry *aProxyEntry, const uint8_t *aFontData, uint32_t aLength) { // Default implementation does not handle activating downloaded fonts; // just free the data and return. // Platforms that support @font-face must override this, @@ -1875,19 +1860,16 @@ gfxPlatform::FontsPrefsChanged(const cha mWordCacheCharLimit = UNINITIALIZED_VALUE; FlushFontAndWordCaches(); } else if (!strcmp(GFX_PREF_WORD_CACHE_MAXENTRIES, aPref)) { mWordCacheMaxEntries = UNINITIALIZED_VALUE; FlushFontAndWordCaches(); } else if (!strcmp(GFX_PREF_GRAPHITE_SHAPING, aPref)) { mGraphiteShapingEnabled = UNINITIALIZED_VALUE; FlushFontAndWordCaches(); - } else if (!strcmp(GFX_PREF_HARFBUZZ_SCRIPTS, aPref)) { - mUseHarfBuzzScripts = UNINITIALIZED_VALUE; - FlushFontAndWordCaches(); } else if (!strcmp(BIDI_NUMERAL_PREF, aPref)) { mBidiNumeralOption = UNINITIALIZED_VALUE; } else if (!strcmp(GFX_PREF_OPENTYPE_SVG, aPref)) { mOpenTypeSVGEnabled = UNINITIALIZED_VALUE; gfxFontCache::GetCache()->AgeAllGenerations(); } }
--- a/gfx/thebes/gfxPlatform.h +++ b/gfx/thebes/gfxPlatform.h @@ -384,23 +384,16 @@ public: uint32_t WordCacheMaxEntries(); /** * Whether to use the SIL Graphite rendering engine * (for fonts that include Graphite tables) */ bool UseGraphiteShaping(); - /** - * Whether to use the harfbuzz shaper (depending on script complexity). - * - * This allows harfbuzz to be enabled selectively via the preferences. - */ - bool UseHarfBuzzForScript(int32_t aScriptCode); - // check whether format is supported on a platform or not (if unclear, returns true) virtual bool IsFontFormatSupported(nsIURI *aFontURI, uint32_t aFormatFlags) { return false; } void GetPrefFonts(nsIAtom *aLanguage, nsString& array, bool aAppendUnicode = true); // in some situations, need to make decisions about ambiguous characters, may need to look at multiple pref langs void GetLangPrefs(eFontPrefLang aPrefLangs[], uint32_t &aLen, eFontPrefLang aCharLang, eFontPrefLang aPageLang); @@ -605,19 +598,16 @@ protected: int8_t mOpenTypeSVGEnabled; int8_t mBidiNumeralOption; // whether to always search font cmaps globally // when doing system font fallback int8_t mFallbackUsesCmaps; - // which scripts should be shaped with harfbuzz - int32_t mUseHarfBuzzScripts; - // max character limit for words in word cache int32_t mWordCacheCharLimit; // max number of entries in word cache int32_t mWordCacheMaxEntries; private: /**
--- a/image/public/imgIContainer.idl +++ b/image/public/imgIContainer.idl @@ -39,35 +39,37 @@ struct Orientation; %} [ptr] native gfxContext(gfxContext); [ref] native gfxMatrix(gfxMatrix); [ref] native gfxRect(gfxRect); native gfxGraphicsFilter(GraphicsFilter); [ref] native nsIntRect(nsIntRect); +native nsIntRectByVal(nsIntRect); [ref] native nsIntSize(nsIntSize); native nsSize(nsSize); [ptr] native nsIFrame(nsIFrame); [ptr] native ImageContainer(mozilla::layers::ImageContainer); [ptr] native LayerManager(mozilla::layers::LayerManager); native Orientation(mozilla::image::Orientation); [ref] native TimeStamp(mozilla::TimeStamp); [ptr] native SVGImageContext(mozilla::SVGImageContext); native TempRefSourceSurface(mozilla::TemporaryRef<mozilla::gfx::SourceSurface>); +native TempRefImgIContainer(already_AddRefed<imgIContainer>); /** * imgIContainer is the interface that represents an image. It allows * access to frames as Thebes surfaces. It also allows drawing of images * onto Thebes contexts. * * Internally, imgIContainer also manages animation of images. */ -[scriptable, builtinclass, uuid(503a830c-734d-4362-91f6-73f83ac59646)] +[scriptable, builtinclass, uuid(c9bd1257-45fb-4ea6-a669-6da212479191)] interface imgIContainer : nsISupports { /** * The width of the container rectangle. In the case of any error, * zero is returned, and an exception will be thrown. */ readonly attribute int32_t width; @@ -343,9 +345,24 @@ interface imgIContainer : nsISupports * This has no effect if the image isn't animated or it has started animating * already; it also has no effect if the image format doesn't care about * animation start time. * * In all cases, animation does not actually begin until startAnimation(), * resetAnimation(), or requestRefresh() is called for the first time. */ [notxpcom] void setAnimationStartTime([const] in TimeStamp aTime); + + /* + * Given an invalidation rect in the coordinate system used by the decoder, + * returns an invalidation rect in image space. + * + * This is the identity transformation in most cases, but the result can + * differ if the image is wrapped by an ImageWrapper that changes its size + * or orientation. + */ + [notxpcom] nsIntRectByVal getImageSpaceInvalidationRect([const] in nsIntRect aRect); + + /* + * Removes any ImageWrappers and returns the unwrapped base image. + */ + [notxpcom, nostdcall] TempRefImgIContainer unwrap(); };
--- a/image/src/ClippedImage.cpp +++ b/image/src/ClippedImage.cpp @@ -419,10 +419,23 @@ ClippedImage::RequestDiscard() NS_IMETHODIMP_(Orientation) ClippedImage::GetOrientation() { // XXX(seth): This should not actually be here; this is just to work around a // what appears to be a bug in MSVC's linker. return InnerImage()->GetOrientation(); } +NS_IMETHODIMP_(nsIntRect) +ClippedImage::GetImageSpaceInvalidationRect(const nsIntRect& aRect) +{ + if (!ShouldClip()) { + return InnerImage()->GetImageSpaceInvalidationRect(aRect); + } + + nsIntRect rect(InnerImage()->GetImageSpaceInvalidationRect(aRect)); + rect = rect.Intersect(mClip); + rect.MoveBy(-mClip.x, -mClip.y); + return rect; +} + } // namespace image } // namespace mozilla
--- a/image/src/ClippedImage.h +++ b/image/src/ClippedImage.h @@ -47,16 +47,17 @@ public: const gfxRect& aFill, const nsIntRect& aSubimage, const nsIntSize& aViewportSize, const SVGImageContext* aSVGContext, uint32_t aWhichFrame, uint32_t aFlags) MOZ_OVERRIDE; NS_IMETHOD RequestDiscard() MOZ_OVERRIDE; NS_IMETHOD_(Orientation) GetOrientation() MOZ_OVERRIDE; + NS_IMETHOD_(nsIntRect) GetImageSpaceInvalidationRect(const nsIntRect& aRect) MOZ_OVERRIDE; protected: ClippedImage(Image* aImage, nsIntRect aClip); virtual ~ClippedImage(); private: mozilla::TemporaryRef<SourceSurface>
--- a/image/src/ImageWrapper.cpp +++ b/image/src/ImageWrapper.cpp @@ -312,10 +312,22 @@ ImageWrapper::GetFirstFrameDelay() } NS_IMETHODIMP_(void) ImageWrapper::SetAnimationStartTime(const mozilla::TimeStamp& aTime) { mInnerImage->SetAnimationStartTime(aTime); } +NS_IMETHODIMP_(nsIntRect) +ImageWrapper::GetImageSpaceInvalidationRect(const nsIntRect& aRect) +{ + return mInnerImage->GetImageSpaceInvalidationRect(aRect); +} + +already_AddRefed<imgIContainer> +ImageWrapper::Unwrap() +{ + return mInnerImage->Unwrap(); +} + } // namespace image } // namespace mozilla
--- a/image/src/OrientedImage.cpp +++ b/image/src/OrientedImage.cpp @@ -245,10 +245,37 @@ OrientedImage::Draw(gfxContext* aContext swap(viewportSize.width, viewportSize.height); } return InnerImage()->Draw(aContext, aFilter, userSpaceToImageSpace, aFill, subimage, viewportSize, aSVGContext, aWhichFrame, aFlags); } +NS_IMETHODIMP_(nsIntRect) +OrientedImage::GetImageSpaceInvalidationRect(const nsIntRect& aRect) +{ + nsIntRect rect(InnerImage()->GetImageSpaceInvalidationRect(aRect)); + + if (mOrientation.IsIdentity()) { + return rect; + } + + int32_t width, height; + nsresult rv = InnerImage()->GetWidth(&width); + rv = NS_FAILED(rv) ? rv : InnerImage()->GetHeight(&height); + if (NS_FAILED(rv)) { + // Fall back to identity if the width and height aren't available. + return rect; + } + + // Transform the invalidation rect into the correct orientation. + gfxMatrix matrix(OrientationMatrix(nsIntSize(width, height)).Invert()); + gfxRect invalidRect(matrix.TransformBounds(gfxRect(rect.x, rect.y, + rect.width, rect.height))); + invalidRect.RoundOut(); + + return nsIntRect(invalidRect.x, invalidRect.y, + invalidRect.width, invalidRect.height); +} + } // namespace image } // namespace mozilla
--- a/image/src/OrientedImage.h +++ b/image/src/OrientedImage.h @@ -42,16 +42,17 @@ public: GraphicsFilter aFilter, const gfxMatrix& aUserSpaceToImageSpace, const gfxRect& aFill, const nsIntRect& aSubimage, const nsIntSize& aViewportSize, const SVGImageContext* aSVGContext, uint32_t aWhichFrame, uint32_t aFlags) MOZ_OVERRIDE; + NS_IMETHOD_(nsIntRect) GetImageSpaceInvalidationRect(const nsIntRect& aRect) MOZ_OVERRIDE; protected: OrientedImage(Image* aImage, Orientation aOrientation) : ImageWrapper(aImage) , mOrientation(aOrientation) { } virtual ~OrientedImage() { }
--- a/image/src/RasterImage.cpp +++ b/image/src/RasterImage.cpp @@ -1596,16 +1596,22 @@ RasterImage::SetLoopCount(int32_t aLoopC return; if (mAnim) { // No need to set this if we're not an animation mFrameBlender.SetLoopCount(aLoopCount); } } +NS_IMETHODIMP_(nsIntRect) +RasterImage::GetImageSpaceInvalidationRect(const nsIntRect& aRect) +{ + return aRect; +} + nsresult RasterImage::AddSourceData(const char *aBuffer, uint32_t aCount) { ReentrantMonitorAutoEnter lock(mDecodingMonitor); if (mError) return NS_ERROR_FAILURE; @@ -3155,16 +3161,23 @@ RasterImage::FinishedSomeDecoding(eShutd diff = mStatusDiff; mStatusDiff = ImageStatusDiff::NoChange(); } } return RequestDecodeIfNeeded(rv, aIntent, done, wasSize); } +already_AddRefed<imgIContainer> +RasterImage::Unwrap() +{ + nsCOMPtr<imgIContainer> self(this); + return self.forget(); +} + NS_IMPL_ISUPPORTS(RasterImage::DecodePool, nsIObserver) /* static */ RasterImage::DecodePool* RasterImage::DecodePool::Singleton() { if (!sSingleton) { MOZ_ASSERT(NS_IsMainThread());
--- a/image/src/VectorImage.cpp +++ b/image/src/VectorImage.cpp @@ -565,16 +565,22 @@ VectorImage::SendInvalidationNotificatio if (mStatusTracker) { SurfaceCache::Discard(this); mStatusTracker->FrameChanged(&nsIntRect::GetMaxSizedIntRect()); mStatusTracker->OnStopFrame(); } } +NS_IMETHODIMP_(nsIntRect) +VectorImage::GetImageSpaceInvalidationRect(const nsIntRect& aRect) +{ + return aRect; +} + //****************************************************************************** /* readonly attribute int32_t height; */ NS_IMETHODIMP VectorImage::GetHeight(int32_t* aHeight) { if (mError || !mIsFullyLoaded) { *aHeight = 0; return NS_ERROR_FAILURE; @@ -1203,10 +1209,17 @@ VectorImage::InvalidateObserversOnNextRe { if (mHaveAnimations) { mHasPendingInvalidation = true; } else { SendInvalidationNotifications(); } } +already_AddRefed<imgIContainer> +VectorImage::Unwrap() +{ + nsCOMPtr<imgIContainer> self(this); + return self.forget(); +} + } // namespace image } // namespace mozilla
--- a/image/src/imgLoader.cpp +++ b/image/src/imgLoader.cpp @@ -594,16 +594,17 @@ static nsresult NewImageChannel(nsIChann } // Pass in a nullptr loadgroup because this is the underlying network // request. This request may be referenced by several proxy image requests // (possibly in different documents). // If all of the proxy requests are canceled then this request should be // canceled too. // + aLoadFlags |= nsIChannel::LOAD_CLASSIFY_URI; rv = NS_NewChannel(aResult, aURI, // URI nullptr, // Cached IOService nullptr, // LoadGroup callbacks, // Notification Callbacks aLoadFlags, aPolicy); if (NS_FAILED(rv))
--- a/image/test/unit/image_load_helpers.js +++ b/image/test/unit/image_load_helpers.js @@ -11,16 +11,19 @@ const DATA_AVAILABLE = 0x04; // One bit per callback that imageListener below implements. Stored in // ImageListener.state. const SIZE_AVAILABLE = 0x01; const FRAME_UPDATE = 0x02; const FRAME_COMPLETE = 0x04; const LOAD_COMPLETE = 0x08; const DECODE_COMPLETE = 0x10; +// Safebrowsing requires that the profile dir is set. +do_get_profile(); + // An implementation of imgIScriptedNotificationObserver with the ability to // call specified functions on onStartRequest and onStopRequest. function ImageListener(start_callback, stop_callback) { this.sizeAvailable = function onSizeAvailable(aRequest) { do_check_false(this.synchronous);
--- a/intl/unicharutil/util/nsUnicodeProperties.cpp +++ b/intl/unicharutil/util/nsUnicodeProperties.cpp @@ -244,74 +244,16 @@ bool IsClusterExtender(uint32_t aCh, uint8_t aCategory) { return ((aCategory >= HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK && aCategory <= HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) || (aCh >= 0x200c && aCh <= 0x200d) || // ZWJ, ZWNJ (aCh >= 0xff9e && aCh <= 0xff9f)); // katakana sound marks } -// TODO: replace this with a properties file or similar; -// expect this to evolve as harfbuzz shaping support matures. -// -// The "shaping type" of each script run, as returned by this -// function, is compared to the bits set in the -// gfx.font_rendering.harfbuzz.scripts -// preference to decide whether to use the harfbuzz shaper. -// -int32_t -ScriptShapingType(int32_t aScriptCode) -{ - switch (aScriptCode) { - default: - return SHAPING_DEFAULT; // scripts not explicitly listed here are - // assumed to just use default shaping - - case MOZ_SCRIPT_ARABIC: - case MOZ_SCRIPT_SYRIAC: - case MOZ_SCRIPT_NKO: - case MOZ_SCRIPT_MANDAIC: - return SHAPING_ARABIC; // bidi scripts with Arabic-style shaping - - case MOZ_SCRIPT_HEBREW: - return SHAPING_HEBREW; - - case MOZ_SCRIPT_HANGUL: - return SHAPING_HANGUL; - - case MOZ_SCRIPT_MONGOLIAN: // to be supported by the Arabic shaper? - return SHAPING_MONGOLIAN; - - case MOZ_SCRIPT_THAI: // no complex OT features, but MS engines like to do - // sequence checking - return SHAPING_THAI; - - case MOZ_SCRIPT_BENGALI: - case MOZ_SCRIPT_DEVANAGARI: - case MOZ_SCRIPT_GUJARATI: - case MOZ_SCRIPT_GURMUKHI: - case MOZ_SCRIPT_KANNADA: - case MOZ_SCRIPT_MALAYALAM: - case MOZ_SCRIPT_ORIYA: - case MOZ_SCRIPT_SINHALA: - case MOZ_SCRIPT_TAMIL: - case MOZ_SCRIPT_TELUGU: - case MOZ_SCRIPT_KHMER: - case MOZ_SCRIPT_LAO: - case MOZ_SCRIPT_TIBETAN: - case MOZ_SCRIPT_NEW_TAI_LUE: - case MOZ_SCRIPT_TAI_LE: - case MOZ_SCRIPT_MYANMAR: - case MOZ_SCRIPT_PHAGS_PA: - case MOZ_SCRIPT_BATAK: - case MOZ_SCRIPT_BRAHMI: - return SHAPING_INDIC; // scripts that require Indic or other "special" shaping - } -} - void ClusterIterator::Next() { if (AtEnd()) { NS_WARNING("ClusterIterator has already reached the end"); return; }
--- a/intl/unicharutil/util/nsUnicodeProperties.h +++ b/intl/unicharutil/util/nsUnicodeProperties.h @@ -114,28 +114,16 @@ inline HSType GetHangulSyllableType(uint // Case mappings for the full Unicode range; // note that it may be worth testing for ASCII chars and taking // a separate fast-path before calling these, in perf-critical places uint32_t GetUppercase(uint32_t aCh); uint32_t GetLowercase(uint32_t aCh); uint32_t GetTitlecaseForLower(uint32_t aCh); // maps LC to titlecase, UC unchanged uint32_t GetTitlecaseForAll(uint32_t aCh); // maps both UC and LC to titlecase -enum ShapingType { - SHAPING_DEFAULT = 0x0001, - SHAPING_ARABIC = 0x0002, - SHAPING_HEBREW = 0x0004, - SHAPING_HANGUL = 0x0008, - SHAPING_MONGOLIAN = 0x0010, - SHAPING_INDIC = 0x0020, - SHAPING_THAI = 0x0040 -}; - -int32_t ScriptShapingType(int32_t aScriptCode); - // A simple iterator for a string of char16_t codepoints that advances // by Unicode grapheme clusters class ClusterIterator { public: ClusterIterator(const char16_t* aText, uint32_t aLength) : mPos(aText), mLimit(aText + aLength) #ifdef DEBUG
--- a/ipc/glue/BackgroundChild.h +++ b/ipc/glue/BackgroundChild.h @@ -32,16 +32,21 @@ class PBackgroundChild; // // Creation of PBackground is asynchronous. GetForCurrentThread() will return // null until the sequence is complete. GetOrCreateForCurrentThread() will start // the creation sequence and will call back via the // nsIIPCBackgroundChildCreateCallback interface when completed. Thereafter // (assuming success) GetForCurrentThread() will return the same actor every // time. // +// CloseForCurrentThread() will close the current PBackground actor. Subsequent +// calls to GetForCurrentThread will return null. CloseForCurrentThread() may +// only be called exactly once per thread. Currently it is illegal to call this +// before the PBackground actor has been created. +// // The PBackgroundChild actor and all its sub-protocol actors will be // automatically destroyed when its designated thread completes. class BackgroundChild MOZ_FINAL { friend class mozilla::dom::ContentChild; friend class mozilla::dom::ContentParent; typedef base::ProcessId ProcessId; @@ -51,16 +56,20 @@ public: // See above. static PBackgroundChild* GetForCurrentThread(); // See above. static bool GetOrCreateForCurrentThread(nsIIPCBackgroundChildCreateCallback* aCallback); + // See above. + static void + CloseForCurrentThread(); + private: // Only called by ContentChild or ContentParent. static void Startup(); // Only called by ContentChild. static PBackgroundChild* Alloc(Transport* aTransport, ProcessId aOtherProcess);
--- a/ipc/glue/BackgroundImpl.cpp +++ b/ipc/glue/BackgroundImpl.cpp @@ -345,16 +345,18 @@ class ChildImpl MOZ_FINAL : public Backg static bool sShutdownHasStarted; #ifdef RELEASE_BUILD DebugOnly<nsIThread*> mBoundThread; #else nsIThread* mBoundThread; #endif + DebugOnly<bool> mActorDestroyed; + public: static bool OpenProtocolOnMainThread(nsIEventTarget* aEventTarget); static void Shutdown(); void @@ -367,18 +369,25 @@ public: #else bool current; #endif THREADSAFETY_ASSERT( NS_SUCCEEDED(mBoundThread->IsOnCurrentThread(¤t))); THREADSAFETY_ASSERT(current); } + void + AssertActorDestroyed() + { + MOZ_ASSERT(mActorDestroyed, "ChildImpl::ActorDestroy not called in time"); + } + ChildImpl() : mBoundThread(nullptr) + , mActorDestroyed(false) { AssertIsOnMainThread(); } NS_INLINE_DECL_REFCOUNTING(ChildImpl) private: // Forwarded from BackgroundChild. @@ -392,39 +401,56 @@ private: // Forwarded from BackgroundChild. static PBackgroundChild* GetForCurrentThread(); // Forwarded from BackgroundChild. static bool GetOrCreateForCurrentThread(nsIIPCBackgroundChildCreateCallback* aCallback); + // Forwarded from BackgroundChild. + static void + CloseForCurrentThread(); + // Forwarded from BackgroundChildImpl. static BackgroundChildImpl::ThreadLocal* GetThreadLocalForCurrentThread(); static void ThreadLocalDestructor(void* aThreadLocal) { auto threadLocalInfo = static_cast<ThreadLocalInfo*>(aThreadLocal); if (threadLocalInfo) { if (threadLocalInfo->mActor) { threadLocalInfo->mActor->Close(); + threadLocalInfo->mActor->AssertActorDestroyed(); + // Since the actor is created on the main thread it must only + // be released on the main thread as well. + if (!NS_IsMainThread()) { + ChildImpl* actor; + threadLocalInfo->mActor.forget(&actor); + + nsCOMPtr<nsIRunnable> releaser = + NS_NewNonOwningRunnableMethod(actor, &ChildImpl::Release); + MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(releaser))); + } } delete threadLocalInfo; } } static void DispatchFailureCallback(nsIEventTarget* aEventTarget); // This class is reference counted. ~ChildImpl() - { } + { + AssertActorDestroyed(); + } void SetBoundThread() { THREADSAFETY_ASSERT(!mBoundThread); #if defined(DEBUG) || !defined(RELEASE_BUILD) mBoundThread = NS_GetCurrentThread(); @@ -830,16 +856,23 @@ BackgroundChild::GetForCurrentThread() // static bool BackgroundChild::GetOrCreateForCurrentThread( nsIIPCBackgroundChildCreateCallback* aCallback) { return ChildImpl::GetOrCreateForCurrentThread(aCallback); } +// static +void +BackgroundChild::CloseForCurrentThread() +{ + ChildImpl::CloseForCurrentThread(); +} + // ----------------------------------------------------------------------------- // BackgroundChildImpl Public Methods // ----------------------------------------------------------------------------- // static BackgroundChildImpl::ThreadLocal* BackgroundChildImpl::GetThreadLocalForCurrentThread() { @@ -1573,17 +1606,21 @@ ChildImpl::Alloc(Transport* aTransport, PBackgroundChild* ChildImpl::GetForCurrentThread() { MOZ_ASSERT(sThreadLocalIndex != kBadThreadLocalIndex); auto threadLocalInfo = static_cast<ThreadLocalInfo*>(PR_GetThreadPrivate(sThreadLocalIndex)); - return threadLocalInfo ? threadLocalInfo->mActor : nullptr; + if (!threadLocalInfo) { + return nullptr; + } + + return threadLocalInfo->mActor; } // static bool ChildImpl::GetOrCreateForCurrentThread( nsIIPCBackgroundChildCreateCallback* aCallback) { MOZ_ASSERT(aCallback); @@ -1638,16 +1675,41 @@ ChildImpl::GetOrCreateForCurrentThread( CRASH_IN_CHILD_PROCESS("Failed to dispatch to main thread!"); return false; } return true; } // static +void +ChildImpl::CloseForCurrentThread() +{ + MOZ_ASSERT(sThreadLocalIndex != kBadThreadLocalIndex, + "BackgroundChild::Startup() was never called!"); + auto threadLocalInfo = + static_cast<ThreadLocalInfo*>(PR_GetThreadPrivate(sThreadLocalIndex)); + + // If we don't have a thread local we are in one of these conditions: + // 1) Startup has not completed and we are racing + // 2) We were called again after a previous close or shutdown + // For now, these should not happen, so crash. We can add extra complexity + // in the future if it turns out we need to support these cases. + if (!threadLocalInfo) { + MOZ_CRASH("Attempting to close a non-existent PBackground actor!"); + } + + if (threadLocalInfo->mActor) { + threadLocalInfo->mActor->FlushPendingInterruptQueue(); + } + DebugOnly<PRStatus> status = PR_SetThreadPrivate(sThreadLocalIndex, nullptr); + MOZ_ASSERT(status == PR_SUCCESS); +} + +// static BackgroundChildImpl::ThreadLocal* ChildImpl::GetThreadLocalForCurrentThread() { MOZ_ASSERT(sThreadLocalIndex != kBadThreadLocalIndex, "BackgroundChild::Startup() was never called!"); auto threadLocalInfo = static_cast<ThreadLocalInfo*>(PR_GetThreadPrivate(sThreadLocalIndex)); @@ -1941,16 +2003,17 @@ ChildImpl::DispatchFailureCallback(nsIEv } } void ChildImpl::ActorDestroy(ActorDestroyReason aWhy) { AssertIsOnBoundThread(); + mActorDestroyed = true; BackgroundChildImpl::ActorDestroy(aWhy); } NS_IMPL_ISUPPORTS(ChildImpl::ShutdownObserver, nsIObserver) NS_IMETHODIMP ChildImpl::ShutdownObserver::Observe(nsISupports* aSubject, const char* aTopic,
--- a/ipc/glue/MessagePump.cpp +++ b/ipc/glue/MessagePump.cpp @@ -2,21 +2,23 @@ * 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 "MessagePump.h" #include "nsIRunnable.h" #include "nsIThread.h" #include "nsITimer.h" +#include "nsICancelableRunnable.h" #include "base/basictypes.h" #include "base/logging.h" #include "base/scoped_nsautorelease_pool.h" #include "mozilla/Assertions.h" +#include "mozilla/AutoRestore.h" #include "mozilla/DebugOnly.h" #include "nsComponentManagerUtils.h" #include "nsDebug.h" #include "nsServiceManagerUtils.h" #include "nsString.h" #include "nsThreadUtils.h" #include "nsTimerImpl.h" #include "nsXULAppAPI.h" @@ -35,35 +37,40 @@ using namespace mozilla::ipc; NS_DEFINE_NAMED_CID(NS_TIMER_CID); static mozilla::DebugOnly<MessagePump::Delegate*> gFirstDelegate; namespace mozilla { namespace ipc { -class DoWorkRunnable MOZ_FINAL : public nsIRunnable, +class DoWorkRunnable MOZ_FINAL : public nsICancelableRunnable, public nsITimerCallback { public: DoWorkRunnable(MessagePump* aPump) : mPump(aPump) + , mCanceled(false) + , mCallingRunWhileCanceled(false) { MOZ_ASSERT(aPump); } NS_DECL_THREADSAFE_ISUPPORTS NS_DECL_NSIRUNNABLE NS_DECL_NSITIMERCALLBACK + NS_DECL_NSICANCELABLERUNNABLE private: ~DoWorkRunnable() { } MessagePump* mPump; + bool mCanceled; + bool mCallingRunWhileCanceled; }; } /* namespace ipc */ } /* namespace mozilla */ MessagePump::MessagePump() : mThread(nullptr) { @@ -206,21 +213,27 @@ void MessagePump::DoDelayedWork(base::MessagePump::Delegate* aDelegate) { aDelegate->DoDelayedWork(&delayed_work_time_); if (!delayed_work_time_.is_null()) { ScheduleDelayedWork(delayed_work_time_); } } -NS_IMPL_ISUPPORTS(DoWorkRunnable, nsIRunnable, nsITimerCallback) +NS_IMPL_ISUPPORTS(DoWorkRunnable, nsIRunnable, nsITimerCallback, + nsICancelableRunnable) NS_IMETHODIMP DoWorkRunnable::Run() { + MOZ_ASSERT(!mCanceled || mCallingRunWhileCanceled); + if (mCanceled && !mCallingRunWhileCanceled) { + return NS_OK; + } + MessageLoop* loop = MessageLoop::current(); MOZ_ASSERT(loop); bool nestableTasksAllowed = loop->NestableTasksAllowed(); // MessageLoop::RunTask() disallows nesting, but our Frankenventloop will // always dispatch DoWork() below from what looks to MessageLoop like a nested // context. So we unconditionally allow nesting here. @@ -237,16 +250,33 @@ DoWorkRunnable::Notify(nsITimer* aTimer) MessageLoop* loop = MessageLoop::current(); MOZ_ASSERT(loop); mPump->DoDelayedWork(loop); return NS_OK; } +NS_IMETHODIMP +DoWorkRunnable::Cancel() +{ + MOZ_ASSERT(!mCanceled); + MOZ_ASSERT(!mCallingRunWhileCanceled); + + // Workers require cancelable runnables, but we can't really cancel cleanly + // here. If we don't process all of these then we will leave something + // unprocessed in the chromium queue. Therefore, eagerly complete our work + // instead by immediately calling Run(). + mCanceled = true; + mozilla::AutoRestore<bool> guard(mCallingRunWhileCanceled); + mCallingRunWhileCanceled = true; + Run(); + return NS_OK; +} + void MessagePumpForChildProcess::Run(base::MessagePump::Delegate* aDelegate) { if (mFirstRun) { MOZ_ASSERT(aDelegate && !gFirstDelegate); gFirstDelegate = aDelegate; mFirstRun = false;
--- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -2712,21 +2712,29 @@ Parser<ParseHandler>::matchLabel(Mutable } else { label.set(nullptr); } return true; } template <typename ParseHandler> bool -Parser<ParseHandler>::reportRedeclaration(Node pn, bool isConst, JSAtom *atom) -{ - JSAutoByteString name; - if (AtomToPrintableString(context, atom, &name)) - report(ParseError, false, pn, JSMSG_REDECLARED_VAR, isConst ? "const" : "variable", name.ptr()); +Parser<ParseHandler>::reportRedeclaration(Node pn, bool isConst, HandlePropertyName name) +{ + JSAutoByteString printable; + if (!AtomToPrintableString(context, name, &printable)) + return false; + + StmtInfoPC *stmt = LexicalLookup(pc, name, nullptr, (StmtInfoPC *)nullptr); + if (stmt && stmt->type == STMT_CATCH) { + report(ParseError, false, pn, JSMSG_REDECLARED_CATCH_IDENTIFIER, printable.ptr()); + } else { + report(ParseError, false, pn, JSMSG_REDECLARED_VAR, isConst ? "const" : "variable", + printable.ptr()); + } return false; } /* * Define a let-variable in a block, let-expression, or comprehension scope. pc * must already be in such a scope. * * Throw a SyntaxError if 'atom' is an invalid name. Otherwise create a @@ -2995,30 +3003,36 @@ Parser<ParseHandler>::bindVarOrConst(Bin if (isConstDecl) { parser->report(ParseError, false, pn, JSMSG_REDECLARED_PARAM, bytes.ptr()); return false; } if (!parser->report(ParseExtraWarning, false, pn, JSMSG_VAR_HIDES_ARG, bytes.ptr())) return false; } else { + bool inCatchBody = (stmt && stmt->type == STMT_CATCH); bool error = (isConstDecl || dn_kind == Definition::CONST || (dn_kind == Definition::LET && - (stmt->type != STMT_CATCH || OuterLet(pc, stmt, name)))); + (!inCatchBody || OuterLet(pc, stmt, name)))); if (parser->options().extraWarningsOption ? data->op != JSOP_DEFVAR || dn_kind != Definition::VAR : error) { JSAutoByteString bytes; + if (!AtomToPrintableString(cx, name, &bytes)) + return false; + ParseReportKind reporter = error ? ParseError : ParseExtraWarning; - if (!AtomToPrintableString(cx, name, &bytes) || - !parser->report(reporter, false, pn, JSMSG_REDECLARED_VAR, - Definition::kindString(dn_kind), bytes.ptr())) + if (!(inCatchBody + ? parser->report(reporter, false, pn, + JSMSG_REDECLARED_CATCH_IDENTIFIER, bytes.ptr()) + : parser->report(reporter, false, pn, JSMSG_REDECLARED_VAR, + Definition::kindString(dn_kind), bytes.ptr()))) { return false; } } } parser->handler.linkUseToDef(pn, dn); return true; @@ -3604,16 +3618,35 @@ Parser<FullParseHandler>::letDeclaration return null(); } if (stmt && stmt->isBlockScope) { JS_ASSERT(pc->staticScope == stmt->staticScope); } else { if (pc->atBodyLevel()) { /* + * When bug 589199 is fixed, let variables will be stored in + * the slots of a new scope chain object, encountered just + * before the global object in the overall chain. This extra + * object is present in the scope chain for all code in that + * global, including self-hosted code. But self-hosted code + * must be usable against *any* global object, including ones + * with other let variables -- variables possibly placed in + * conflicting slots. Forbid top-level let declarations to + * prevent such conflicts from ever occurring. + */ + if (options().selfHostingMode && + !pc->sc->isFunctionBox() && + stmt == pc->topScopeStmt) + { + report(ParseError, false, null(), JSMSG_SELFHOSTED_TOP_LEVEL_LET); + return null(); + } + + /* * ES4 specifies that let at top level and at body-block scope * does not shadow var, so convert back to var. */ pn = variables(PNK_VAR); if (!pn) return null(); pn->pn_xflags |= PNX_POPVAR; break;
--- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -637,17 +637,17 @@ class Parser : private JS::AutoGCRooter, HandlePropertyName name, Parser<ParseHandler> *parser); static bool bindVarOrConst(BindData<ParseHandler> *data, HandlePropertyName name, Parser<ParseHandler> *parser); static Node null() { return ParseHandler::null(); } - bool reportRedeclaration(Node pn, bool isConst, JSAtom *atom); + bool reportRedeclaration(Node pn, bool isConst, HandlePropertyName name); bool reportBadReturn(Node pn, ParseReportKind kind, unsigned errnum, unsigned anonerrnum); bool checkFinalReturn(Node pn); DefinitionNode getOrCreateLexicalDependency(ParseContext<ParseHandler> *pc, JSAtom *atom); bool leaveFunction(Node fn, ParseContext<ParseHandler> *outerpc, FunctionSyntaxKind kind = Expression); TokenPos pos() const { return tokenStream.currentToken().pos; }
--- a/js/src/jit-test/tests/asm.js/testFFI.js +++ b/js/src/jit-test/tests/asm.js/testFFI.js @@ -93,53 +93,55 @@ var recurse = function(i,j) { if (i == 0 var f = asmLink(asmCompile('glob', 'imp', USE_ASM + 'var ffi=imp.ffi; function g(i,j,k) { i=i|0;j=+j;k=k|0; if (!(k|0)) ffi(i|0,j)|0; else g(i, j+1.0, (k-1)|0) } function f(i,j) { i=i|0;j=+j; g(i,j,4) } return f'), null, {ffi:recurse}); assertThrowsValue(function() { f(0,2.4) }, 2.4+4); assertThrowsValue(function() { f(1,2.4) }, 2.4+8); assertThrowsValue(function() { f(8,2.4) }, 2.4+36); assertEq(asmLink(asmCompile('glob', 'imp', USE_ASM + 'var identity=imp.identity; function g(x) { x=+x; return +identity(x) } return g'), null, imp)(13.37), 13.37); // Test asm.js => ion paths -setJitCompilerOption("ion.usecount.trigger", 20); +setJitCompilerOption("ion.usecount.trigger", 10); +setJitCompilerOption("baseline.usecount.trigger", 0); +setJitCompilerOption("offthread-compilation.enable", 0); // In registers on x64 and ARM, on the stack for x86 function ffiIntFew(a,b,c,d) { return d+1 } var f = asmLink(asmCompile('glob', 'imp', USE_ASM + 'var ffi=imp.ffi; function f(i) { i=i|0; return ffi(i|0,(i+1)|0,(i+2)|0,(i+3)|0)|0 } return f'), null, {ffi:ffiIntFew}); for (var i = 0; i < 40; i++) assertEq(f(i), i+4); // Stack and registers for x64 and ARM, stack for x86 function ffiIntMany(a,b,c,d,e,f,g,h,i,j) { return j+1 } var f = asmLink(asmCompile('glob', 'imp', USE_ASM + 'var ffi=imp.ffi; function f(i) { i=i|0; return ffi(i|0,(i+1)|0,(i+2)|0,(i+3)|0,(i+4)|0,(i+5)|0,(i+6)|0,(i+7)|0,(i+8)|0,(i+9)|0)|0 } return f'), null, {ffi:ffiIntMany}); -for (var i = 0; i < 40; i++) +for (var i = 0; i < 15; i++) assertEq(f(i), i+10); // In registers on x64 and ARM, on the stack for x86 function ffiDoubleFew(a,b,c,d) { return d+1 } var f = asmLink(asmCompile('glob', 'imp', USE_ASM + 'var ffi=imp.ffi; function f(i) { i=+i; return +ffi(i,i+1.0,i+2.0,i+3.0) } return f'), null, {ffi:ffiDoubleFew}); -for (var i = 0; i < 40; i++) +for (var i = 0; i < 15; i++) assertEq(f(i), i+4); // Stack and registers for x64 and ARM, stack for x86 function ffiDoubleMany(a,b,c,d,e,f,g,h,i,j) { return j+1 } var f = asmLink(asmCompile('glob', 'imp', USE_ASM + 'var ffi=imp.ffi; function f(i) { i=+i; return +ffi(i,i+1.0,i+2.0,i+3.0,i+4.0,i+5.0,i+6.0,i+7.0,i+8.0,i+9.0) } return f'), null, {ffi:ffiDoubleMany}); -for (var i = 0; i < 40; i++) +for (var i = 0; i < 15; i++) assertEq(f(i), i+10); // Test the throw path -function ffiThrow(n) { if (n == 38) throw 'yolo'; } +function ffiThrow(n) { if (n == 14) throw 'yolo'; } var f = asmLink(asmCompile('glob', 'imp', USE_ASM + 'var ffi=imp.ffi; function f(i) { i=i|0; ffi(i >> 0); } return f'), null, {ffi:ffiThrow}); var i = 0; try { - for (; i < 40; i++) + for (; i < 15; i++) f(i); throw 'assume unreachable'; } catch (e) { assertEq(e, 'yolo'); - assertEq(i, 38); + assertEq(i, 14); } // OOL conversion paths var INT32_MAX = Math.pow(2, 31) - 1; function ffiOOLConvertInt(n) { if (n == 40) return INT32_MAX + 1; return 42; } var f = asmLink(asmCompile('glob', 'imp', USE_ASM + 'var ffi=imp.ffi; function f(i) { i=i|0; return ffi(i >> 0) | 0; } return f'), null, {ffi:ffiOOLConvertInt}); for (var i = 0; i < 40; i++) assertEq(f(i), 42);
--- a/js/src/jit-test/tests/asm.js/testStackWalking.js +++ b/js/src/jit-test/tests/asm.js/testStackWalking.js @@ -12,20 +12,24 @@ function matchStack(stackString, stackAr } var stack; function dumpStack() { stack = new Error().stack } +setJitCompilerOption("ion.usecount.trigger", 10); +setJitCompilerOption("baseline.usecount.trigger", 0); +setJitCompilerOption("offthread-compilation.enable", 0); + var callFFI = asmCompile('global', 'ffis', USE_ASM + "var ffi=ffis.ffi; function f() { return ffi()|0 } return f"); var f = asmLink(callFFI, null, {ffi:dumpStack}); -for (var i = 0; i < 5000; i++) { +for (var i = 0; i < 15; i++) { stack = null; f(); matchStack(stack, ['dumpStack', 'f']); } if (isAsmJSCompilationAvailable() && isCachingEnabled()) { var callFFI = asmCompile('global', 'ffis', USE_ASM + "var ffi=ffis.ffi; function f() { return ffi()|0 } return f"); assertEq(isAsmJSModuleLoadedFromCache(callFFI), true); @@ -37,17 +41,17 @@ if (isAsmJSCompilationAvailable() && isC var f1 = asmLink(callFFI, null, {ffi:dumpStack}); var f2 = asmLink(callFFI, null, {ffi:function middle() { f1() }}); stack = null; (function outer() { f2() })(); matchStack(stack, ["dumpStack", "f", "middle", "f"]); function returnStackDumper() { return { valueOf:function() { stack = new Error().stack } } } var f = asmLink(callFFI, null, {ffi:returnStackDumper}); -for (var i = 0; i < 5000; i++) { +for (var i = 0; i < 15; i++) { stack = null; f(); matchStack(stack, ['valueOf', 'f']); } var caught = false; try { stack = null;
--- a/js/src/jit/AsmJS.cpp +++ b/js/src/jit/AsmJS.cpp @@ -11,17 +11,16 @@ #ifdef MOZ_VTUNE # include "vtune/VTuneWrapper.h" #endif #include "jsmath.h" #include "jsprf.h" #include "prmjtime.h" -#include "assembler/assembler/MacroAssembler.h" #include "frontend/Parser.h" #include "jit/AsmJSLink.h" #include "jit/AsmJSModule.h" #include "jit/AsmJSSignalHandlers.h" #include "jit/CodeGenerator.h" #include "jit/CompileWrappers.h" #include "jit/MIR.h" #include "jit/MIRGraph.h" @@ -1404,19 +1403,16 @@ class MOZ_STACK_CLASS ModuleCompiler if (p) { *exitIndex = p->value(); return true; } if (!module_->addExit(ffiIndex, exitIndex)) return false; return exits_.add(p, Move(exitDescriptor), *exitIndex); } - bool addFunctionName(PropertyName *name, uint32_t *index) { - return module_->addFunctionName(name, index); - } // Note a constraint on the minimum size of the heap. The heap size is // constrained when linking to be at least the maximum of all such constraints. void requireHeapLengthToBeAtLeast(uint32_t len) { module_->requireHeapLengthToBeAtLeast(len); } uint32_t minHeapLength() const { return module_->minHeapLength(); @@ -1438,16 +1434,21 @@ class MOZ_STACK_CLASS ModuleCompiler masm_.resetForNewCodeGenerator(mir.alloc()); masm_.align(CodeAlignment); masm_.bind(func.code()); } bool finishGeneratingFunction(Func &func, MIRGenerator &mir, CodeGenerator &codegen) { JS_ASSERT(func.defined() && func.code()->bound()); + uint32_t beginOffset = func.code()->offset(); + uint32_t endOffset = masm_.currentOffset(); + if (!module_->addFunctionCodeRange(func.name(), beginOffset, endOffset)) + return false; + jit::IonScriptCounts *counts = codegen.extractScriptCounts(); if (counts && !module_->addFunctionCounts(counts)) { js_delete(counts); return false; } #if defined(MOZ_VTUNE) || defined(JS_ION_PERF) unsigned line = 0, column = 0; @@ -1475,25 +1476,29 @@ class MOZ_STACK_CLASS ModuleCompiler void finishFunctionBodies() { JS_ASSERT(!finishedFunctionBodies_); masm_.align(AsmJSPageSize); finishedFunctionBodies_ = true; module_->finishFunctionBodies(masm_.currentOffset()); } + void startGeneratingEntry(unsigned exportIndex) { + module_->exportedFunction(exportIndex).initCodeOffset(masm_.currentOffset()); + } + bool finishGeneratingEntry(unsigned exportIndex) { + return module_->addEntryCodeRange(exportIndex, masm_.currentOffset()); + } + void setInterpExitOffset(unsigned exitIndex) { module_->exit(exitIndex).initInterpOffset(masm_.currentOffset()); } void setIonExitOffset(unsigned exitIndex) { module_->exit(exitIndex).initIonOffset(masm_.currentOffset()); } - void setEntryOffset(unsigned exportIndex) { - module_->exportedFunction(exportIndex).initCodeOffset(masm_.currentOffset()); - } void buildCompilationTimeReport(bool storedInCache, ScopedJSFreePtr<char> *out) { ScopedJSFreePtr<char> slowFuns; #ifndef JS_MORE_DETERMINISTIC int64_t usecAfter = PRMJ_Now(); int msTotal = (usecAfter - usecBefore_) / PRMJ_USEC_PER_MSEC; if (!slowFunctions_.empty()) { slowFuns.reset(JS_smprintf("; %d functions compiled slowly: ", slowFunctions_.length())); @@ -1803,17 +1808,16 @@ class FunctionCompiler typedef Vector<TypedValue> VarInitializerVector; typedef HashMap<PropertyName*, BlockVector> LabeledBlockMap; typedef HashMap<ParseNode*, BlockVector> UnlabeledBlockMap; typedef Vector<ParseNode*, 4> NodeStack; ModuleCompiler & m_; LifoAlloc & lifo_; ParseNode * fn_; - uint32_t functionNameIndex_; LocalMap locals_; VarInitializerVector varInitializers_; Maybe<RetType> alreadyReturned_; TempAllocator * alloc_; MIRGraph * graph_; CompileInfo * info_; @@ -1824,25 +1828,21 @@ class FunctionCompiler NodeStack loopStack_; NodeStack breakableStack_; UnlabeledBlockMap unlabeledBreaks_; UnlabeledBlockMap unlabeledContinues_; LabeledBlockMap labeledBreaks_; LabeledBlockMap labeledContinues_; - static const uint32_t NO_FUNCTION_NAME_INDEX = UINT32_MAX; - JS_STATIC_ASSERT(NO_FUNCTION_NAME_INDEX > CallSiteDesc::FUNCTION_NAME_INDEX_MAX); - public: FunctionCompiler(ModuleCompiler &m, ParseNode *fn, LifoAlloc &lifo) : m_(m), lifo_(lifo), fn_(fn), - functionNameIndex_(NO_FUNCTION_NAME_INDEX), locals_(m.cx()), varInitializers_(m.cx()), alloc_(nullptr), graph_(nullptr), info_(nullptr), mirGen_(nullptr), curBlock_(nullptr), loopStack_(m.cx()), @@ -2274,22 +2274,17 @@ class FunctionCompiler if (inDeadCode()) { *def = nullptr; return true; } uint32_t line, column; m_.tokenStream().srcCoords.lineNumAndColumnIndex(call.node_->pn_pos.begin, &line, &column); - if (functionNameIndex_ == NO_FUNCTION_NAME_INDEX) { - if (!m_.addFunctionName(FunctionName(fn_), &functionNameIndex_)) - return false; - } - - CallSiteDesc desc(line, column, functionNameIndex_); + CallSiteDesc desc(line, column); MAsmJSCall *ins = MAsmJSCall::New(alloc(), desc, callee, call.regArgs_, returnType, call.spIncrement_); if (!ins) return false; curBlock_->add(ins); *def = ins; return true; @@ -5950,17 +5945,17 @@ GenerateEntry(ModuleCompiler &m, const A // In constrast to the system ABI, the Ion convention is that all registers // are clobbered by calls. Thus, we must save the caller's non-volatile // registers. // // NB: GenerateExits assumes that masm.framePushed() == 0 before // PushRegsInMask(NonVolatileRegs). masm.setFramePushed(0); - // See AsmJSFrameSize comment in Assembler-*.h. + // See AsmJSFrameSize comment in Assembler-shared.h. #if defined(JS_CODEGEN_ARM) masm.push(lr); #endif // JS_CODEGEN_ARM #if defined(JS_CODEGEN_MIPS) masm.push(ra); #endif masm.PushRegsInMask(NonVolatileRegs); @@ -6025,17 +6020,17 @@ GenerateEntry(ModuleCompiler &m, const A masm.storeDouble(ScratchDoubleReg, Address(StackPointer, iter->offsetFromArgBase())); } break; } } // Call into the real function. AssertStackAlignment(masm); - masm.call(CallSiteDesc::Entry(), func.code()); + masm.call(func.code()); // Pop the stack and recover the original 'argv' argument passed to the // trampoline (which was pushed on the stack). masm.freeStack(stackDec); masm.Pop(argv); // Store the return value in argv[0] switch (func.sig().retType().which()) { @@ -6209,24 +6204,28 @@ static void GenerateFFIInterpreterExit(ModuleCompiler &m, const ModuleCompiler::ExitDescriptor &exit, unsigned exitIndex, Label *throwLabel) { MacroAssembler &masm = m.masm(); masm.align(CodeAlignment); m.setInterpExitOffset(exitIndex); masm.setFramePushed(0); - // See AsmJSFrameSize comment in Assembler-*.h. + // See AsmJSFrameSize comment in Assembler-shared.h. #if defined(JS_CODEGEN_ARM) masm.push(lr); -#endif -#if defined(JS_CODEGEN_MIPS) +#elif defined(JS_CODEGEN_MIPS) masm.push(ra); #endif + // Store the frame pointer in AsmJSActivation::exitFP for stack unwinding. + Register activation = ABIArgGenerator::NonArgReturnVolatileReg0; + LoadAsmJSActivationIntoRegister(masm, activation); + masm.storePtr(StackPointer, Address(activation, AsmJSActivation::offsetOfExitFP())); + MIRType typeArray[] = { MIRType_Pointer, // cx MIRType_Pointer, // exitDatum MIRType_Int32, // argc MIRType_Pointer }; // argv MIRTypeVector invokeArgTypes(m.cx()); invokeArgTypes.infallibleAppend(typeArray, ArrayLength(typeArray)); // At the point of the call, the stack layout shall be (sp grows to the left): @@ -6235,26 +6234,21 @@ GenerateFFIInterpreterExit(ModuleCompile // sp is aligned. unsigned offsetToArgv = AlignBytes(StackArgBytes(invokeArgTypes) + MaybeRetAddr, StackAlignment); unsigned argvBytes = Max<size_t>(1, exit.sig().args().length()) * sizeof(Value); unsigned stackDec = StackDecrementForCall(masm, offsetToArgv + argvBytes); masm.reserveStack(stackDec); // Fill the argument array. unsigned offsetToCallerStackArgs = AsmJSFrameSize + masm.framePushed(); - Register scratch = ABIArgGenerator::NonArgReturnVolatileReg0; + Register scratch = ABIArgGenerator::NonArgReturnVolatileReg1; FillArgumentArray(m, exit.sig().args(), offsetToArgv, offsetToCallerStackArgs, scratch); // Prepare the arguments for the call to InvokeFromAsmJS_*. ABIArgMIRTypeIter i(invokeArgTypes); - Register activation = ABIArgGenerator::NonArgReturnVolatileReg1; - LoadAsmJSActivationIntoRegister(masm, activation); - - // Record sp in the AsmJSActivation for stack-walking. - masm.storePtr(StackPointer, Address(activation, AsmJSActivation::offsetOfExitSP())); // argument 0: cx if (i->kind() == ABIArg::GPR) { LoadJSContextFromActivation(masm, activation, i->gpr()); } else { LoadJSContextFromActivation(masm, activation, scratch); masm.storePtr(scratch, Address(StackPointer, i->offsetFromArgBase())); } @@ -6285,37 +6279,42 @@ GenerateFFIInterpreterExit(ModuleCompile } i++; JS_ASSERT(i.done()); // Make the call, test whether it succeeded, and extract the return value. AssertStackAlignment(masm); switch (exit.sig().retType().which()) { case RetType::Void: - masm.callExit(AsmJSImmPtr(AsmJSImm_InvokeFromAsmJS_Ignore), i.stackBytesConsumedSoFar()); + masm.call(AsmJSImmPtr(AsmJSImm_InvokeFromAsmJS_Ignore)); masm.branchTest32(Assembler::Zero, ReturnReg, ReturnReg, throwLabel); break; case RetType::Signed: - masm.callExit(AsmJSImmPtr(AsmJSImm_InvokeFromAsmJS_ToInt32), i.stackBytesConsumedSoFar()); + masm.call(AsmJSImmPtr(AsmJSImm_InvokeFromAsmJS_ToInt32)); masm.branchTest32(Assembler::Zero, ReturnReg, ReturnReg, throwLabel); masm.unboxInt32(argv, ReturnReg); break; case RetType::Double: - masm.callExit(AsmJSImmPtr(AsmJSImm_InvokeFromAsmJS_ToNumber), i.stackBytesConsumedSoFar()); + masm.call(AsmJSImmPtr(AsmJSImm_InvokeFromAsmJS_ToNumber)); masm.branchTest32(Assembler::Zero, ReturnReg, ReturnReg, throwLabel); masm.loadDouble(argv, ReturnDoubleReg); break; case RetType::Float: MOZ_ASSUME_UNREACHABLE("Float32 shouldn't be returned from a FFI"); break; } // Note: the caller is IonMonkey code which means there are no non-volatile // registers to restore. masm.freeStack(stackDec); + + // Clear exitFP before the frame is destroyed. + LoadAsmJSActivationIntoRegister(masm, activation); + masm.storePtr(ImmWord(0), Address(activation, AsmJSActivation::offsetOfExitFP())); + masm.ret(); } static void GenerateOOLConvert(ModuleCompiler &m, RetType retType, Label *throwLabel) { MacroAssembler &masm = m.masm(); @@ -6330,19 +6329,16 @@ GenerateOOLConvert(ModuleCompiler &m, Re // Store value unsigned offsetToArgv = StackArgBytes(callArgTypes) + MaybeRetAddr; masm.storeValue(JSReturnOperand, Address(StackPointer, offsetToArgv)); Register scratch = ABIArgGenerator::NonArgReturnVolatileReg0; Register activation = ABIArgGenerator::NonArgReturnVolatileReg1; LoadAsmJSActivationIntoRegister(masm, activation); - // Record sp in the AsmJSActivation for stack-walking. - masm.storePtr(StackPointer, Address(activation, AsmJSActivation::offsetOfExitSP())); - // Store real arguments ABIArgMIRTypeIter i(callArgTypes); // argument 0: cx if (i->kind() == ABIArg::GPR) { LoadJSContextFromActivation(masm, activation, i->gpr()); } else { LoadJSContextFromActivation(masm, activation, scratch); @@ -6360,22 +6356,22 @@ GenerateOOLConvert(ModuleCompiler &m, Re } i++; JS_ASSERT(i.done()); // Call AssertStackAlignment(masm); switch (retType.which()) { case RetType::Signed: - masm.callExit(AsmJSImmPtr(AsmJSImm_CoerceInPlace_ToInt32), i.stackBytesConsumedSoFar()); + masm.call(AsmJSImmPtr(AsmJSImm_CoerceInPlace_ToInt32)); masm.branchTest32(Assembler::Zero, ReturnReg, ReturnReg, throwLabel); masm.unboxInt32(Address(StackPointer, offsetToArgv), ReturnReg); break; case RetType::Double: - masm.callExit(AsmJSImmPtr(AsmJSImm_CoerceInPlace_ToNumber), i.stackBytesConsumedSoFar()); + masm.call(AsmJSImmPtr(AsmJSImm_CoerceInPlace_ToNumber)); masm.branchTest32(Assembler::Zero, ReturnReg, ReturnReg, throwLabel); masm.loadDouble(Address(StackPointer, offsetToArgv), ReturnDoubleReg); break; default: MOZ_ASSUME_UNREACHABLE("Unsupported convert type"); } } @@ -6383,29 +6379,32 @@ static void GenerateFFIIonExit(ModuleCompiler &m, const ModuleCompiler::ExitDescriptor &exit, unsigned exitIndex, Label *throwLabel) { MacroAssembler &masm = m.masm(); masm.align(CodeAlignment); m.setIonExitOffset(exitIndex); masm.setFramePushed(0); - // See AsmJSFrameSize comment in Assembler-*.h. + // See AsmJSFrameSize comment in Assembler-shared.h. +#if defined(JS_CODEGEN_ARM) + masm.push(lr); +#elif defined(JS_CODEGEN_MIPS) + masm.push(ra); +#endif + + // Store the frame pointer in AsmJSActivation::exitFP for stack unwinding. + Register activation = ABIArgGenerator::NonArgReturnVolatileReg0; + LoadAsmJSActivationIntoRegister(masm, activation); + masm.storePtr(StackPointer, Address(activation, AsmJSActivation::offsetOfExitFP())); + + // Ion does not preserve nonvolatile registers, so we have to preserve them. #if defined(JS_CODEGEN_X64) masm.Push(HeapReg); -#elif defined(JS_CODEGEN_ARM) - masm.push(lr); - - // The GlobalReg (r10) and HeapReg (r11) also need to be restored before - // returning to asm.js code. - // The NANReg also needs to be restored, but is a constant and is reloaded before - // returning to asm.js code. - masm.PushRegsInMask(GeneralRegisterSet((1<<GlobalReg.code()) | (1<<HeapReg.code()))); -#elif defined(JS_CODEGEN_MIPS) - masm.push(ra); +#elif defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS) masm.PushRegsInMask(GeneralRegisterSet((1<<GlobalReg.code()) | (1<<HeapReg.code()))); #endif // The stack frame is used for the call into Ion and also for calls into C for OOL // conversion of the result. A frame large enough for both is allocated. // // Arguments to the Ion function are in the following order on the stack: // | return address | descriptor | callee | argc | this | arg1 | arg2 | ... @@ -6493,42 +6492,30 @@ GenerateFFIIonExit(ModuleCompiler &m, co // This sequence requires four registers, and needs to preserve the 'callee' // register, so there are five live registers. JS_ASSERT(callee == AsmJSIonExitRegCallee); Register reg0 = AsmJSIonExitRegE0; Register reg1 = AsmJSIonExitRegE1; Register reg2 = AsmJSIonExitRegE2; Register reg3 = AsmJSIonExitRegE3; - LoadAsmJSActivationIntoRegister(masm, reg0); - - // Record sp in the AsmJSActivation for stack-walking. -#if defined(JS_CODEGEN_MIPS) - // Add a flag to indicate to AsmJSFrameIterator that we are calling - // into Ion, since the offset from SP to the return address is - // different when calling Ion vs. the native ABI. - masm.ma_or(reg1, StackPointer, Imm32(0x1)); - masm.storePtr(reg1, Address(reg0, AsmJSActivation::offsetOfExitSP())); -#else - masm.storePtr(StackPointer, Address(reg0, AsmJSActivation::offsetOfExitSP())); -#endif - // The following is inlined: // JSContext *cx = activation->cx(); // Activation *act = cx->mainThread().activation(); // act.active_ = true; // act.prevJitTop_ = cx->mainThread().jitTop; // act.prevJitJSContext_ = cx->mainThread().jitJSContext; // cx->mainThread().jitJSContext = cx; // On the ARM store8() uses the secondScratchReg (lr) as a temp. size_t offsetOfActivation = offsetof(JSRuntime, mainThread) + PerThreadData::offsetOfActivation(); size_t offsetOfJitTop = offsetof(JSRuntime, mainThread) + offsetof(PerThreadData, jitTop); size_t offsetOfJitJSContext = offsetof(JSRuntime, mainThread) + offsetof(PerThreadData, jitJSContext); + LoadAsmJSActivationIntoRegister(masm, reg0); masm.loadPtr(Address(reg0, AsmJSActivation::offsetOfContext()), reg3); masm.loadPtr(Address(reg3, JSContext::offsetOfRuntime()), reg0); masm.loadPtr(Address(reg0, offsetOfActivation), reg1); masm.store8(Imm32(1), Address(reg1, JitActivation::offsetOfActiveUint8())); masm.loadPtr(Address(reg0, offsetOfJitTop), reg2); masm.storePtr(reg2, Address(reg1, JitActivation::offsetOfPrevJitTop())); masm.loadPtr(Address(reg0, offsetOfJitJSContext), reg2); masm.storePtr(reg2, Address(reg1, JitActivation::offsetOfPrevJitJSContext())); @@ -6590,23 +6577,29 @@ GenerateFFIIonExit(ModuleCompiler &m, co break; case RetType::Float: MOZ_ASSUME_UNREACHABLE("Float shouldn't be returned from a FFI"); break; } masm.bind(&done); masm.freeStack(stackDec); + + // Restore non-volatile registers saved in the prologue. #if defined(JS_CODEGEN_X64) masm.Pop(HeapReg); -#endif -#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS) +#elif defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS) masm.loadConstantDouble(GenericNaN(), NANReg); masm.PopRegsInMask(GeneralRegisterSet((1<<GlobalReg.code()) | (1<<HeapReg.code()))); #endif + + // Clear exitFP before the frame is destroyed. + LoadAsmJSActivationIntoRegister(masm, activation); + masm.storePtr(ImmWord(0), Address(activation, AsmJSActivation::offsetOfExitFP())); + masm.ret(); JS_ASSERT(masm.framePushed() == 0); // oolConvert if (oolConvert.used()) { masm.bind(&oolConvert); masm.setFramePushed(oolConvertFramePushed); GenerateOOLConvert(m, exit.sig().retType(), throwLabel); @@ -6637,43 +6630,49 @@ GenerateFFIExit(ModuleCompiler &m, const // all the frames. static bool GenerateStackOverflowExit(ModuleCompiler &m, Label *throwLabel) { MacroAssembler &masm = m.masm(); masm.align(CodeAlignment); masm.bind(&m.stackOverflowLabel()); + // The stack-overflow is checked before bumping the stack. + masm.setFramePushed(0); + + // Store the frame pointer in AsmJSActivation::exitFP for stack unwinding. + Register activation = ABIArgGenerator::NonArgReturnVolatileReg0; + LoadAsmJSActivationIntoRegister(masm, activation); + masm.storePtr(StackPointer, Address(activation, AsmJSActivation::offsetOfExitFP())); + MIRTypeVector argTypes(m.cx()); argTypes.infallibleAppend(MIRType_Pointer); // cx unsigned stackDec = StackDecrementForCall(masm, argTypes, MaybeRetAddr); masm.reserveStack(stackDec); - Register activation = ABIArgGenerator::NonArgReturnVolatileReg0; - LoadAsmJSActivationIntoRegister(masm, activation); - - // Record sp in the AsmJSActivation for stack-walking. - masm.storePtr(StackPointer, Address(activation, AsmJSActivation::offsetOfExitSP())); - ABIArgMIRTypeIter i(argTypes); // argument 0: cx if (i->kind() == ABIArg::GPR) { LoadJSContextFromActivation(masm, activation, i->gpr()); } else { LoadJSContextFromActivation(masm, activation, activation); masm.storePtr(activation, Address(StackPointer, i->offsetFromArgBase())); } i++; JS_ASSERT(i.done()); AssertStackAlignment(masm); - masm.callExit(AsmJSImmPtr(AsmJSImm_ReportOverRecursed), i.stackBytesConsumedSoFar()); + masm.call(AsmJSImmPtr(AsmJSImm_ReportOverRecursed)); + + // Clear exitFP before the frame is destroyed. + LoadAsmJSActivationIntoRegister(masm, activation); + masm.storePtr(ImmWord(0), Address(activation, AsmJSActivation::offsetOfExitFP())); // Don't worry about restoring the stack; throwLabel will pop everything. masm.jump(throwLabel); return !masm.oom(); } static const RegisterSet AllRegsExceptSP = RegisterSet(GeneralRegisterSet(Registers::AllMask & @@ -6862,20 +6861,20 @@ GenerateThrowExit(ModuleCompiler &m, Lab return !masm.oom(); } static bool GenerateStubs(ModuleCompiler &m) { for (unsigned i = 0; i < m.module().numExportedFunctions(); i++) { - m.setEntryOffset(i); + m.startGeneratingEntry(i); if (!GenerateEntry(m, m.module().exportedFunction(i))) return false; - if (m.masm().oom()) + if (m.masm().oom() || !m.finishGeneratingEntry(i)) return false; } Label throwLabel; // The order of the iterations here is non-deterministic, since // m.allExits() is a hash keyed by pointer values! for (ModuleCompiler::ExitMap::Range r = m.allExits(); !r.empty(); r.popFront()) {
new file mode 100644 --- /dev/null +++ b/js/src/jit/AsmJSFrameIterator.cpp @@ -0,0 +1,75 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sts=4 et sw=4 tw=99: + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "jit/AsmJSFrameIterator.h" + +#include "jit/AsmJS.h" +#include "jit/AsmJSModule.h" + +using namespace js; +using namespace js::jit; + +static void * +ReturnAddressFromFP(uint8_t *fp) +{ + // In asm.js code, the "frame" consists of a single word: the saved + // return address of the caller. + static_assert(AsmJSFrameSize == sizeof(void*), "Frame size mismatch"); + return *(uint8_t**)fp; +} + +AsmJSFrameIterator::AsmJSFrameIterator(const AsmJSActivation &activation) + : module_(&activation.module()), + fp_(activation.exitFP()) +{ + if (!fp_) + return; + settle(ReturnAddressFromFP(fp_)); +} + +void +AsmJSFrameIterator::operator++() +{ + JS_ASSERT(!done()); + fp_ += callsite_->stackDepth(); + settle(ReturnAddressFromFP(fp_)); +} + +void +AsmJSFrameIterator::settle(void *returnAddress) +{ + const AsmJSModule::CodeRange *codeRange = module_->lookupCodeRange(ReturnAddressFromFP(fp_)); + JS_ASSERT(codeRange); + codeRange_ = codeRange; + + switch (codeRange->kind()) { + case AsmJSModule::CodeRange::Entry: + fp_ = nullptr; + JS_ASSERT(done()); + return; + case AsmJSModule::CodeRange::Function: + callsite_ = module_->lookupCallSite(returnAddress); + JS_ASSERT(callsite_); + break; + } +} + +JSAtom * +AsmJSFrameIterator::functionDisplayAtom() const +{ + JS_ASSERT(!done()); + return reinterpret_cast<const AsmJSModule::CodeRange*>(codeRange_)->functionName(*module_); +} + +unsigned +AsmJSFrameIterator::computeLine(uint32_t *column) const +{ + JS_ASSERT(!done()); + if (column) + *column = callsite_->column(); + return callsite_->line(); +} +
new file mode 100644 --- /dev/null +++ b/js/src/jit/AsmJSFrameIterator.h @@ -0,0 +1,46 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sts=4 et sw=4 tw=99: + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef jit_AsmJSFrameIterator_h +#define jit_AsmJSFrameIterator_h + +#include "mozilla/NullPtr.h" + +#include <stdint.h> + +class JSAtom; + +namespace js { + +class AsmJSActivation; +class AsmJSModule; +namespace jit { struct CallSite; } + +// Iterates over the frames of a single AsmJSActivation. +class AsmJSFrameIterator +{ + const AsmJSModule *module_; + const jit::CallSite *callsite_; + uint8_t *fp_; + + // Really, a const AsmJSModule::CodeRange*, but no forward declarations of + // nested classes, so use void* to avoid pulling in all of AsmJSModule.h. + const void *codeRange_; + + void settle(void *returnAddress); + + public: + explicit AsmJSFrameIterator() : module_(nullptr) {} + explicit AsmJSFrameIterator(const AsmJSActivation &activation); + void operator++(); + bool done() const { return !fp_; } + JSAtom *functionDisplayAtom() const; + unsigned computeLine(uint32_t *column) const; +}; + +} // namespace js + +#endif // jit_AsmJSFrameIterator_h
--- a/js/src/jit/AsmJSLink.cpp +++ b/js/src/jit/AsmJSLink.cpp @@ -29,111 +29,16 @@ #include "jsobjinlines.h" using namespace js; using namespace js::jit; using mozilla::IsNaN; using mozilla::PodZero; -static uint8_t * -ReturnAddressForExitCall(uint8_t **psp) -{ - uint8_t *sp = *psp; -#if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64) - // For calls to Ion/C++ on x86/x64, the exitSP is the SP right before the call - // to C++. Since the call instruction pushes the return address, we know - // that the return address is 1 word below exitSP. - return *(uint8_t**)(sp - sizeof(void*)); -#elif defined(JS_CODEGEN_ARM) - // For calls to Ion/C++ on ARM, the *caller* pushes the return address on - // the stack. For Ion, this is just part of the ABI. For C++, the return - // address is explicitly pushed before the call since we cannot expect the - // callee to immediately push lr. This means that exitSP points to the - // return address. - return *(uint8_t**)sp; -#elif defined(JS_CODEGEN_MIPS) - // On MIPS we have two cases: an exit to C++ will store the return address - // at ShadowStackSpace above sp; an exit to Ion will store the return - // address at sp. To distinguish the two cases, the low bit of sp (which is - // aligned and therefore zero) is set for Ion exits. - if (uintptr_t(sp) & 0x1) { - sp = *psp -= 0x1; // Clear the low bit - return *(uint8_t**)sp; - } - return *(uint8_t**)(sp + ShadowStackSpace); -#else -# error "Unknown architecture!" -#endif -} - -static uint8_t * -ReturnAddressForJitCall(uint8_t *sp) -{ - // Once inside JIT code, sp always points to the word before the return - // address. - return *(uint8_t**)(sp - sizeof(void*)); -} - -AsmJSFrameIterator::AsmJSFrameIterator(const AsmJSActivation *activation) - : module_(nullptr) -{ - if (!activation || activation->isInterruptedSP()) - return; - - module_ = &activation->module(); - sp_ = activation->exitSP(); - - settle(ReturnAddressForExitCall(&sp_)); -} - -void -AsmJSFrameIterator::operator++() -{ - settle(ReturnAddressForJitCall(sp_)); -} - -void -AsmJSFrameIterator::settle(uint8_t *returnAddress) -{ - callsite_ = module_->lookupCallSite(returnAddress); - if (!callsite_ || callsite_->isEntry()) { - module_ = nullptr; - return; - } - - if (callsite_->isEntry()) { - module_ = nullptr; - return; - } - - sp_ += callsite_->stackDepth(); - - if (callsite_->isExit()) - return settle(ReturnAddressForJitCall(sp_)); - - JS_ASSERT(callsite_->isNormal()); -} - -JSAtom * -AsmJSFrameIterator::functionDisplayAtom() const -{ - JS_ASSERT(!done()); - return module_->functionName(callsite_->functionNameIndex()); -} - -unsigned -AsmJSFrameIterator::computeLine(uint32_t *column) const -{ - JS_ASSERT(!done()); - if (column) - *column = callsite_->column(); - return callsite_->line(); -} - static bool CloneModule(JSContext *cx, MutableHandle<AsmJSModuleObject*> moduleObj) { ScopedJSDeletePtr<AsmJSModule> module; if (!moduleObj->module().clone(cx, &module)) return false; module->staticallyLink(cx);
--- a/js/src/jit/AsmJSLink.h +++ b/js/src/jit/AsmJSLink.h @@ -4,41 +4,18 @@ * 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_AsmJSLink_h #define jit_AsmJSLink_h #include "NamespaceImports.h" -class JSAtom; - namespace js { -class AsmJSActivation; -class AsmJSModule; -namespace jit { struct CallSite; } - -// Iterates over the frames of a single AsmJSActivation. -class AsmJSFrameIterator -{ - const AsmJSModule *module_; - const jit::CallSite *callsite_; - uint8_t *sp_; - - void settle(uint8_t *returnAddress); - - public: - explicit AsmJSFrameIterator(const AsmJSActivation *activation); - void operator++(); - bool done() const { return !module_; } - JSAtom *functionDisplayAtom() const; - unsigned computeLine(uint32_t *column) const; -}; - #ifdef JS_ION // Create a new JSFunction to replace originalFun as the representation of the // function defining the succesfully-validated module 'moduleObj'. extern JSFunction * NewAsmJSModuleFunction(ExclusiveContext *cx, JSFunction *originalFun, HandleObject moduleObj); // Return whether this is the js::Native returned by NewAsmJSModuleFunction.
--- a/js/src/jit/AsmJSModule.cpp +++ b/js/src/jit/AsmJSModule.cpp @@ -162,16 +162,17 @@ AsmJSModule::addSizeOfMisc(mozilla::Mall size_t *asmJSModuleData) { *asmJSModuleCode += pod.totalBytes_; *asmJSModuleData += mallocSizeOf(this) + globals_.sizeOfExcludingThis(mallocSizeOf) + exits_.sizeOfExcludingThis(mallocSizeOf) + exports_.sizeOfExcludingThis(mallocSizeOf) + callSites_.sizeOfExcludingThis(mallocSizeOf) + + codeRanges_.sizeOfExcludingThis(mallocSizeOf) + functionNames_.sizeOfExcludingThis(mallocSizeOf) + heapAccesses_.sizeOfExcludingThis(mallocSizeOf) + functionCounts_.sizeOfExcludingThis(mallocSizeOf) + #if defined(MOZ_VTUNE) || defined(JS_ION_PERF) profiledFunctions_.sizeOfExcludingThis(mallocSizeOf) + #endif #if defined(JS_ION_PERF) perfProfiledBlocksFunctions_.sizeOfExcludingThis(mallocSizeOf) + @@ -184,47 +185,86 @@ struct CallSiteRetAddrOffset const CallSiteVector &callSites; explicit CallSiteRetAddrOffset(const CallSiteVector &callSites) : callSites(callSites) {} uint32_t operator[](size_t index) const { return callSites[index].returnAddressOffset(); } }; const CallSite * -AsmJSModule::lookupCallSite(uint8_t *returnAddress) const +AsmJSModule::lookupCallSite(void *returnAddress) const { JS_ASSERT(isFinished()); - uint32_t target = returnAddress - code_; + uint32_t target = ((uint8_t*)returnAddress) - code_; size_t lowerBound = 0; size_t upperBound = callSites_.length(); size_t match; if (!BinarySearch(CallSiteRetAddrOffset(callSites_), lowerBound, upperBound, target, &match)) return nullptr; return &callSites_[match]; } +namespace js { + +// Create an ordering on CodeRange and pc offsets suitable for BinarySearch. +// Stick these in the same namespace as AsmJSModule so that argument-dependent +// lookup will find it. +bool +operator==(size_t pcOffset, const AsmJSModule::CodeRange &rhs) +{ + return pcOffset >= rhs.beginOffset() && pcOffset < rhs.endOffset(); +} +bool +operator<=(const AsmJSModule::CodeRange &lhs, const AsmJSModule::CodeRange &rhs) +{ + return lhs.beginOffset() <= rhs.beginOffset(); +} +bool +operator<(size_t pcOffset, const AsmJSModule::CodeRange &rhs) +{ + return pcOffset < rhs.beginOffset(); +} + +} // namespace js + +const AsmJSModule::CodeRange * +AsmJSModule::lookupCodeRange(void *pc) const +{ + JS_ASSERT(isFinished()); + + uint32_t target = ((uint8_t*)pc) - code_; + size_t lowerBound = 0; + size_t upperBound = codeRanges_.length(); + + size_t match; + if (!BinarySearch(codeRanges_, lowerBound, upperBound, target, &match)) + return nullptr; + + return &codeRanges_[match]; +} + struct HeapAccessOffset { const AsmJSHeapAccessVector &accesses; explicit HeapAccessOffset(const AsmJSHeapAccessVector &accesses) : accesses(accesses) {} uintptr_t operator[](size_t index) const { return accesses[index].offset(); } }; const AsmJSHeapAccess * -AsmJSModule::lookupHeapAccess(uint8_t *pc) const +AsmJSModule::lookupHeapAccess(void *pc) const { JS_ASSERT(isFinished()); JS_ASSERT(containsPC(pc)); - uint32_t target = pc - code_; + uint32_t target = ((uint8_t*)pc) - code_; size_t lowerBound = 0; size_t upperBound = heapAccesses_.length(); size_t match; if (!BinarySearch(HeapAccessOffset(heapAccesses_), lowerBound, upperBound, target, &match)) return nullptr; return &heapAccesses_[match]; @@ -288,16 +328,21 @@ AsmJSModule::finish(ExclusiveContext *cx for (unsigned i = 0; i < numExportedFunctions(); i++) exportedFunction(i).updateCodeOffset(masm); for (unsigned i = 0; i < numExits(); i++) exit(i).updateOffsets(masm); for (size_t i = 0; i < callSites_.length(); i++) { CallSite &c = callSites_[i]; c.setReturnAddressOffset(masm.actualOffset(c.returnAddressOffset())); } + for (size_t i = 0; i < codeRanges_.length(); i++) { + CodeRange &c = codeRanges_[i]; + c.beginOffset_ = masm.actualOffset(c.beginOffset_); + c.endOffset_ = masm.actualOffset(c.endOffset_); + } #endif JS_ASSERT(pod.functionBytes_ % AsmJSPageSize == 0); // Absolute link metadata: absolute addresses that refer to some fixed // address in the address space. for (size_t i = 0; i < masm.numAsmJSAbsoluteLinks(); i++) { AsmJSAbsoluteLink src = masm.asmJSAbsoluteLink(i); AbsoluteLink link; @@ -1079,16 +1124,17 @@ AsmJSModule::serializedSize() const pod.codeBytes_ + SerializedNameSize(globalArgumentName_) + SerializedNameSize(importArgumentName_) + SerializedNameSize(bufferArgumentName_) + SerializedVectorSize(globals_) + SerializedVectorSize(exits_) + SerializedVectorSize(exports_) + SerializedPodVectorSize(callSites_) + + SerializedPodVectorSize(codeRanges_) + SerializedVectorSize(functionNames_) + SerializedPodVectorSize(heapAccesses_) + #if defined(MOZ_VTUNE) || defined(JS_ION_PERF) SerializedVectorSize(profiledFunctions_) + #endif staticLinkData_.serializedSize(); } @@ -1099,16 +1145,17 @@ AsmJSModule::serialize(uint8_t *cursor) cursor = WriteBytes(cursor, code_, pod.codeBytes_); cursor = SerializeName(cursor, globalArgumentName_); cursor = SerializeName(cursor, importArgumentName_); cursor = SerializeName(cursor, bufferArgumentName_); cursor = SerializeVector(cursor, globals_); cursor = SerializeVector(cursor, exits_); cursor = SerializeVector(cursor, exports_); cursor = SerializePodVector(cursor, callSites_); + cursor = SerializePodVector(cursor, codeRanges_); cursor = SerializeVector(cursor, functionNames_); cursor = SerializePodVector(cursor, heapAccesses_); #if defined(MOZ_VTUNE) || defined(JS_ION_PERF) cursor = SerializeVector(cursor, profiledFunctions_); #endif cursor = staticLinkData_.serialize(cursor); return cursor; } @@ -1125,16 +1172,17 @@ AsmJSModule::deserialize(ExclusiveContex (cursor = ReadBytes(cursor, code_, pod.codeBytes_)) && (cursor = DeserializeName(cx, cursor, &globalArgumentName_)) && (cursor = DeserializeName(cx, cursor, &importArgumentName_)) && (cursor = DeserializeName(cx, cursor, &bufferArgumentName_)) && (cursor = DeserializeVector(cx, cursor, &globals_)) && (cursor = DeserializeVector(cx, cursor, &exits_)) && (cursor = DeserializeVector(cx, cursor, &exports_)) && (cursor = DeserializePodVector(cx, cursor, &callSites_)) && + (cursor = DeserializePodVector(cx, cursor, &codeRanges_)) && (cursor = DeserializeVector(cx, cursor, &functionNames_)) && (cursor = DeserializePodVector(cx, cursor, &heapAccesses_)) && #if defined(MOZ_VTUNE) || defined(JS_ION_PERF) (cursor = DeserializeVector(cx, cursor, &profiledFunctions_)) && #endif (cursor = staticLinkData_.deserialize(cx, cursor)); loadedFromCache_ = true; @@ -1195,16 +1243,17 @@ AsmJSModule::clone(JSContext *cx, Scoped out.globalArgumentName_ = globalArgumentName_; out.importArgumentName_ = importArgumentName_; out.bufferArgumentName_ = bufferArgumentName_; if (!CloneVector(cx, globals_, &out.globals_) || !CloneVector(cx, exits_, &out.exits_) || !CloneVector(cx, exports_, &out.exports_) || !ClonePodVector(cx, callSites_, &out.callSites_) || + !ClonePodVector(cx, codeRanges_, &out.codeRanges_) || !CloneVector(cx, functionNames_, &out.functionNames_) || !ClonePodVector(cx, heapAccesses_, &out.heapAccesses_) || !staticLinkData_.clone(cx, &out.staticLinkData_)) { return false; } out.loadedFromCache_ = loadedFromCache_;
--- a/js/src/jit/AsmJSModule.h +++ b/js/src/jit/AsmJSModule.h @@ -308,16 +308,43 @@ class AsmJSModule } size_t serializedSize() const; uint8_t *serialize(uint8_t *cursor) const; const uint8_t *deserialize(ExclusiveContext *cx, const uint8_t *cursor); bool clone(ExclusiveContext *cx, ExportedFunction *out) const; }; + class CodeRange + { + public: + enum Kind { Entry, Function }; + + private: + Kind kind_; + uint32_t beginOffset_; + uint32_t endOffset_; + uint32_t functionNameIndex_; + + friend class AsmJSModule; + CodeRange(Kind kind, uint32_t beginOffset, uint32_t endOffset) + : kind_(kind), beginOffset_(beginOffset), endOffset_(endOffset) + {} + + public: + CodeRange() {} + Kind kind() const { return kind_; } + uint32_t beginOffset() const { return beginOffset_; } + uint32_t endOffset() const { return endOffset_; } + PropertyName *functionName(const AsmJSModule &module) const { + JS_ASSERT(kind_ == Function); + return module.functionNames_[functionNameIndex_].name(); + } + }; + class Name { PropertyName *name_; public: Name() : name_(nullptr) {} MOZ_IMPLICIT Name(PropertyName *name) : name_(name) {} PropertyName *name() const { return name_; } PropertyName *&name() { return name_; } @@ -474,16 +501,17 @@ class AsmJSModule // respect to caching. const uint32_t funcStart_; const uint32_t offsetToEndOfUseAsm_; Vector<Global, 0, SystemAllocPolicy> globals_; Vector<Exit, 0, SystemAllocPolicy> exits_; Vector<ExportedFunction, 0, SystemAllocPolicy> exports_; Vector<jit::CallSite, 0, SystemAllocPolicy> callSites_; + Vector<CodeRange, 0, SystemAllocPolicy> codeRanges_; Vector<Name, 0, SystemAllocPolicy> functionNames_; Vector<jit::AsmJSHeapAccess, 0, SystemAllocPolicy> heapAccesses_; Vector<jit::IonScriptCounts*, 0, SystemAllocPolicy> functionCounts_; #if defined(MOZ_VTUNE) || defined(JS_ION_PERF) Vector<ProfiledFunction, 0, SystemAllocPolicy> profiledFunctions_; #endif #if defined(JS_ION_PERF) Vector<ProfiledBlocksFunction, 0, SystemAllocPolicy> perfProfiledBlocksFunctions_; @@ -661,27 +689,31 @@ class AsmJSModule /*************************************************************************/ // These functions are called while parsing/compiling function bodies: void requireHeapLengthToBeAtLeast(uint32_t len) { JS_ASSERT(isFinishedWithModulePrologue() && !isFinishedWithFunctionBodies()); if (len > pod.minHeapLength_) pod.minHeapLength_ = len; } - bool addFunctionName(PropertyName *name, uint32_t *nameIndex) { + bool addFunctionCodeRange(PropertyName *name, uint32_t beginOffset, uint32_t endOffset) { JS_ASSERT(isFinishedWithModulePrologue() && !isFinishedWithFunctionBodies()); JS_ASSERT(name->isTenured()); - if (functionNames_.length() > jit::CallSiteDesc::FUNCTION_NAME_INDEX_MAX) + JS_ASSERT(beginOffset <= endOffset); + JS_ASSERT_IF(!codeRanges_.empty(), codeRanges_.back().endOffset() <= beginOffset); + if (functionNames_.length() >= UINT32_MAX) return false; - *nameIndex = functionNames_.length(); - return functionNames_.append(name); + CodeRange codeRange(CodeRange::Function, beginOffset, endOffset); + codeRange.functionNameIndex_ = functionNames_.length(); + return functionNames_.append(name) && codeRanges_.append(codeRange); } - PropertyName *functionName(uint32_t i) const { - JS_ASSERT(isFinished()); - return functionNames_[i].name(); + bool addEntryCodeRange(unsigned exportIndex, uint32_t endOffset) { + uint32_t beginOffset = exports_[exportIndex].pod.codeOffset_; + CodeRange codeRange(CodeRange::Entry, beginOffset, endOffset); + return codeRanges_.append(codeRange); } bool addExit(unsigned ffiIndex, unsigned *exitIndex) { JS_ASSERT(isFinishedWithModulePrologue() && !isFinishedWithFunctionBodies()); if (SIZE_MAX - pod.funcPtrTableAndExitBytes_ < sizeof(ExitDatum)) return false; uint32_t globalDataOffset = globalDataBytes(); JS_STATIC_ASSERT(sizeof(ExitDatum) % sizeof(void*) == 0); pod.funcPtrTableAndExitBytes_ += sizeof(ExitDatum); @@ -847,21 +879,25 @@ class AsmJSModule uint8_t *ionExitTrampoline(const Exit &exit) const { JS_ASSERT(isFinished()); JS_ASSERT(exit.ionCodeOffset_); return code_ + exit.ionCodeOffset_; } // Lookup a callsite by the return pc (from the callee to the caller). // Return null if no callsite was found. - const jit::CallSite *lookupCallSite(uint8_t *returnAddress) const; + const jit::CallSite *lookupCallSite(void *returnAddress) const; + + // Lookup the name the code range containing the given pc. Return null if no + // code range was found. + const CodeRange *lookupCodeRange(void *pc) const; // Lookup a heap access site by the pc which performs the access. Return // null if no heap access was found. - const jit::AsmJSHeapAccess *lookupHeapAccess(uint8_t *pc) const; + const jit::AsmJSHeapAccess *lookupHeapAccess(void *pc) const; // The global data section is placed after the executable code (i.e., at // offset codeBytes_) in the module's linear allocation. The global data // are laid out in this order: // 0. a pointer (padded up to 8 bytes to ensure double-alignment of // globals) for the heap that was linked to the module. // 1. global variable state (elements are sizeof(uint64_t)) // 2. interleaved function-pointer tables and exits. These are allocated
--- a/js/src/jit/AsmJSSignalHandlers.cpp +++ b/js/src/jit/AsmJSSignalHandlers.cpp @@ -351,17 +351,17 @@ HandleSimulatorInterrupt(JSRuntime *rt, // simulator could be in the middle of an instruction. On ARM, the signal // handlers are currently only used for Odin code, see bug 964258. #if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR) const AsmJSModule &module = activation->module(); if (module.containsPC((void *)rt->mainThread.simulator()->get_pc()) && module.containsPC(faultingAddress)) { - activation->setInterrupted(nullptr); + activation->setResumePC(nullptr); int32_t nextpc = int32_t(module.interruptExit()); rt->mainThread.simulator()->set_resume_pc(nextpc); return true; } #endif return false; } @@ -460,17 +460,17 @@ HandleException(PEXCEPTION_POINTERS exce return false; // If we faulted trying to execute code in 'module', this must be an // interrupt callback (see RequestInterruptForAsmJSCode). Redirect // execution to a trampoline which will call js::HandleExecutionInterrupt. // The trampoline will jump to activation->resumePC if execution isn't // interrupted. if (module.containsPC(faultingAddress)) { - activation->setInterrupted(pc); + activation->setResumePC(pc); *ppc = module.interruptExit(); JSRuntime::AutoLockForInterrupt lock(rt); module.unprotectCode(rt); return true; } # if defined(JS_CODEGEN_X64) @@ -663,17 +663,17 @@ HandleMachException(JSRuntime *rt, const return false; // If we faulted trying to execute code in 'module', this must be an // interrupt callback (see RequestInterruptForAsmJSCode). Redirect // execution to a trampoline which will call js::HandleExecutionInterrupt. // The trampoline will jump to activation->resumePC if execution isn't // interrupted. if (module.containsPC(faultingAddress)) { - activation->setInterrupted(pc); + activation->setResumePC(pc); *ppc = module.interruptExit(); JSRuntime::AutoLockForInterrupt lock(rt); module.unprotectCode(rt); // Update the thread state with the new pc. kret = thread_set_state(rtThread, x86_THREAD_STATE, (thread_state_t)&state, x86_THREAD_STATE_COUNT); return kret == KERN_SUCCESS; @@ -913,17 +913,17 @@ HandleSignal(int signum, siginfo_t *info return false; // If we faulted trying to execute code in 'module', this must be an // interrupt callback (see RequestInterruptForAsmJSCode). Redirect // execution to a trampoline which will call js::HandleExecutionInterrupt. // The trampoline will jump to activation->resumePC if execution isn't // interrupted. if (module.containsPC(faultingAddress)) { - activation->setInterrupted(pc); + activation->setResumePC(pc); *ppc = module.interruptExit(); JSRuntime::AutoLockForInterrupt lock(rt); module.unprotectCode(rt); return true; } # if defined(JS_CODEGEN_X64)
--- a/js/src/jit/Bailouts.cpp +++ b/js/src/jit/Bailouts.cpp @@ -17,16 +17,18 @@ #include "jit/JitFrameIterator-inl.h" #include "vm/Probes-inl.h" #include "vm/Stack-inl.h" using namespace js; using namespace js::jit; +using mozilla::IsInRange; + // These constructor are exactly the same except for the type of the iterator // which is given to the SnapshotIterator constructor. Doing so avoid the // creation of virtual functions for the IonIterator but may introduce some // weirdness as IonInlineIterator is using a JitFrameIterator reference. // // If a function relies on ionScript() or to use OsiIndex(), due to the // lack of virtual, these functions will use the JitFrameIterator reference // contained in the InlineFrameIterator and thus are not able to recover @@ -71,18 +73,18 @@ IonBailoutIterator::dump() const uint32_t jit::Bailout(BailoutStack *sp, BaselineBailoutInfo **bailoutInfo) { JSContext *cx = GetJSContextFromJitCode(); JS_ASSERT(bailoutInfo); // We don't have an exit frame. - MOZ_ASSERT(size_t(FAKE_JIT_TOP_FOR_BAILOUT + sizeof(IonCommonFrameLayout)) < 0x1000 && - size_t(FAKE_JIT_TOP_FOR_BAILOUT) >= 0, + MOZ_ASSERT(IsInRange(FAKE_JIT_TOP_FOR_BAILOUT, 0, 0x1000) && + IsInRange(FAKE_JIT_TOP_FOR_BAILOUT + sizeof(IonCommonFrameLayout), 0, 0x1000), "Fake jitTop pointer should be within the first page."); cx->mainThread().jitTop = FAKE_JIT_TOP_FOR_BAILOUT; gc::AutoSuppressGC suppress(cx); JitActivationIterator jitActivations(cx->runtime()); IonBailoutIterator iter(jitActivations, sp); JitActivation *activation = jitActivations->asJit();
--- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -8568,17 +8568,17 @@ CodeGenerator::visitAsmJSCall(LAsmJSCall switch (callee.which()) { case MAsmJSCall::Callee::Internal: masm.call(mir->desc(), callee.internal()); break; case MAsmJSCall::Callee::Dynamic: masm.call(mir->desc(), ToRegister(ins->getOperand(mir->dynamicCalleeOperandIndex()))); break; case MAsmJSCall::Callee::Builtin: - masm.call(mir->desc(), AsmJSImmPtr(callee.builtin())); + masm.call(AsmJSImmPtr(callee.builtin())); break; } if (mir->spIncrement()) masm.reserveStack(mir->spIncrement()); postAsmJSCall(ins); return true;
--- a/js/src/jit/ParallelFunctions.cpp +++ b/js/src/jit/ParallelFunctions.cpp @@ -13,16 +13,18 @@ #include "vm/ArrayObject.h" #include "jsgcinlines.h" #include "jsobjinlines.h" using namespace js; using namespace jit; +using mozilla::IsInRange; + using JS::AutoCheckCannotGC; using parallel::Spew; using parallel::SpewOps; using parallel::SpewBailouts; // Load the current thread context. ForkJoinContext * @@ -519,18 +521,18 @@ jit::UrshValuesPar(ForkJoinContext *cx, void jit::BailoutPar(BailoutStack *sp, uint8_t **entryFramePointer) { parallel::Spew(parallel::SpewBailouts, "Bailing"); ForkJoinContext *cx = ForkJoinContext::current(); // We don't have an exit frame. - MOZ_ASSERT(size_t(FAKE_JIT_TOP_FOR_BAILOUT + sizeof(IonCommonFrameLayout)) < 0x1000 && - size_t(FAKE_JIT_TOP_FOR_BAILOUT) >= 0, + MOZ_ASSERT(IsInRange(FAKE_JIT_TOP_FOR_BAILOUT, 0, 0x1000) && + IsInRange(FAKE_JIT_TOP_FOR_BAILOUT + sizeof(IonCommonFrameLayout), 0, 0x1000), "Fake jitTop pointer should be within the first page."); cx->perThreadData->jitTop = FAKE_JIT_TOP_FOR_BAILOUT; JitActivationIterator jitActivations(cx->perThreadData); IonBailoutIterator frameIter(jitActivations, sp); SnapshotIterator snapIter(frameIter); cx->bailoutRecord->setIonBailoutKind(snapIter.bailoutKind());
--- a/js/src/jit/arm/Architecture-arm.h +++ b/js/src/jit/arm/Architecture-arm.h @@ -432,22 +432,27 @@ uint32_t GetARMFlags(); bool HasMOVWT(); bool HasVFPv3(); bool HasVFP(); bool Has32DP(); bool HasIDIV(); // Arm/D32 has double registers that can NOT be treated as float32 // and this requires some dances in lowering. -inline bool hasUnaliasedDouble() { +inline bool +hasUnaliasedDouble() +{ return Has32DP(); } + // On ARM, Dn aliases both S2n and S2n+1, so if you need to convert a float32 // to a double as a temporary, you need a temporary double register. -inline bool hasMultiAlias() { +inline bool +hasMultiAlias() +{ return true; } bool ParseARMHwCapFlags(const char *armHwCap); // If the simulator is used then the ABI choice is dynamic. Otherwise the ABI is static // and useHardFpABI is inlined so that unused branches can be optimized away. #if defined(JS_ARM_SIMULATOR)
--- a/js/src/jit/arm/Assembler-arm.h +++ b/js/src/jit/arm/Assembler-arm.h @@ -136,22 +136,16 @@ static MOZ_CONSTEXPR_VAR FloatRegister d // ldrd/strd (dual-register load/store) operate in a single cycle // when the address they are dealing with is 8 byte aligned. // Also, the ARM abi wants the stack to be 8 byte aligned at // function boundaries. I'm trying to make sure this is always true. static const uint32_t StackAlignment = 8; static const uint32_t CodeAlignment = 8; static const bool StackKeptAligned = true; -// As an invariant across architectures, within asm.js code: -// $sp % StackAlignment = (AsmJSFrameSize + masm.framePushed) % StackAlignment -// To achieve this on ARM, the first instruction of the asm.js prologue pushes -// lr without incrementing masm.framePushed. -static const uint32_t AsmJSFrameSize = sizeof(void*); - static const Scale ScalePointer = TimesFour; class Instruction; class InstBranchImm; uint32_t RM(Register r); uint32_t RS(Register r); uint32_t RD(Register r); uint32_t RT(Register r);
--- a/js/src/jit/arm/CodeGenerator-arm.cpp +++ b/js/src/jit/arm/CodeGenerator-arm.cpp @@ -48,17 +48,17 @@ CodeGeneratorARM::generatePrologue() return true; } bool CodeGeneratorARM::generateAsmJSPrologue(Label *stackOverflowLabel) { JS_ASSERT(gen->compilingAsmJS()); - // See comment in Assembler-arm.h about AsmJSFrameSize. + // See comment in Assembler-shared.h about AsmJSFrameSize. masm.push(lr); // The asm.js over-recursed handler wants to be able to assume that SP // points to the return address, so perform the check after pushing lr but // before pushing frameDepth. if (!omitOverRecursedCheck()) { masm.branchPtr(Assembler::AboveOrEqual, AsmJSAbsoluteAddress(AsmJSImm_StackLimit),
--- a/js/src/jit/arm/MacroAssembler-arm.cpp +++ b/js/src/jit/arm/MacroAssembler-arm.cpp @@ -1785,16 +1785,27 @@ MacroAssemblerARMCompat::callIon(Registe ma_callIonHalfPush(callee); } else { adjustFrame(sizeof(void*)); ma_callIon(callee); } } void +MacroAssemblerARMCompat::callIonFromAsmJS(Register callee) +{ + ma_callIonNoPush(callee); + + // The Ion ABI has the callee pop the return address off the stack. + // The asm.js caller assumes that the call leaves sp unchanged, so bump + // the stack. + subPtr(Imm32(sizeof(void*)), sp); +} + +void MacroAssemblerARMCompat::reserveStack(uint32_t amount) { if (amount) ma_sub(Imm32(amount), sp); adjustFrame(amount); } void MacroAssemblerARMCompat::freeStack(uint32_t amount) @@ -3620,29 +3631,16 @@ MacroAssemblerARM::ma_call(ImmPtr dest) else rs = L_LDR; ma_movPatchable(dest, CallReg, Always, rs); as_blx(CallReg); } void -MacroAssemblerARM::ma_callAndStoreRet(const Register r, uint32_t stackArgBytes) -{ - // Note: this function stores the return address to sp[0]. The caller must - // anticipate this by pushing additional space on the stack. The ABI does - // not provide space for a return address so this function may only be - // called if no argument are passed. - JS_ASSERT(stackArgBytes == 0); - AutoForbidPools afp(this); - as_dtr(IsStore, 32, Offset, pc, DTRAddr(sp, DtrOffImm(0))); - as_blx(r); -} - -void MacroAssemblerARMCompat::breakpoint() { as_bkpt(); } void MacroAssemblerARMCompat::ensureDouble(const ValueOperand &source, FloatRegister dest, Label *failure) {
--- a/js/src/jit/arm/MacroAssembler-arm.h +++ b/js/src/jit/arm/MacroAssembler-arm.h @@ -392,19 +392,16 @@ class MacroAssemblerARM : public Assembl void ma_callIon(const Register reg); // callso an Ion function, assuming that sp has already been decremented void ma_callIonNoPush(const Register reg); // calls an ion function, assuming that the stack is currently not 8 byte aligned void ma_callIonHalfPush(const Register reg); void ma_call(ImmPtr dest); - // calls reg, storing the return address into sp[0] - void ma_callAndStoreRet(const Register reg, uint32_t stackArgBytes); - // Float registers can only be loaded/stored in continuous runs // when using vstm/vldm. // This function breaks set into continuous runs and loads/stores // them at [rm]. rm will be modified and left in a state logically // suitable for the next load/store. // Returns the offset from [dm] for the logical next load/store. int32_t transferMultipleByRuns(FloatRegisterSet set, LoadStore ls, Register rm, DTMMode mode) @@ -561,48 +558,23 @@ class MacroAssemblerARMCompat : public M if (HasMOVWT()) rs = L_MOVWT; else rs = L_LDR; ma_movPatchable(ImmPtr(c->raw()), ScratchRegister, Always, rs); ma_callIonHalfPush(ScratchRegister); } - - void appendCallSite(const CallSiteDesc &desc) { - // Add an extra sizeof(void*) to include the return address that was - // pushed by the call instruction (see CallSite::stackDepth). - enoughMemory_ &= append(CallSite(desc, currentOffset(), framePushed_ + AsmJSFrameSize)); - } - void call(const CallSiteDesc &desc, const Register reg) { call(reg); - appendCallSite(desc); + enoughMemory_ &= append(desc, currentOffset(), framePushed_); } void call(const CallSiteDesc &desc, Label *label) { call(label); - appendCallSite(desc); - } - void call(const CallSiteDesc &desc, AsmJSImmPtr imm) { - call(imm); - appendCallSite(desc); - } - void callExit(AsmJSImmPtr imm, uint32_t stackArgBytes) { - movePtr(imm, CallReg); - ma_callAndStoreRet(CallReg, stackArgBytes); - appendCallSite(CallSiteDesc::Exit()); - } - void callIonFromAsmJS(const Register reg) { - ma_callIonNoPush(reg); - appendCallSite(CallSiteDesc::Exit()); - - // The Ion ABI has the callee pop the return address off the stack. - // The asm.js caller assumes that the call leaves sp unchanged, so bump - // the stack. - subPtr(Imm32(sizeof(void*)), sp); + enoughMemory_ &= append(desc, currentOffset(), framePushed_); } void branch(JitCode *c) { BufferOffset bo = m_buffer.nextOffset(); addPendingJump(bo, ImmPtr(c->raw()), Relocation::JITCODE); RelocStyle rs; if (HasMOVWT()) rs = L_MOVWT; @@ -1282,16 +1254,17 @@ class MacroAssemblerARMCompat : public M bool buildFakeExitFrame(Register scratch, uint32_t *offset); void callWithExitFrame(JitCode *target); void callWithExitFrame(JitCode *target, Register dynStack); // Makes an Ion call using the only two methods that it is sane for // indep code to make a call void callIon(Register callee); + void callIonFromAsmJS(Register callee); void reserveStack(uint32_t amount); void freeStack(uint32_t amount); void freeStack(Register amount); void add32(Register src, Register dest); void add32(Imm32 imm, Register dest); void add32(Imm32 imm, const Address &dest);
--- a/js/src/jit/arm/Simulator-arm.cpp +++ b/js/src/jit/arm/Simulator-arm.cpp @@ -4065,17 +4065,17 @@ Simulator::execute() } else { SimInstruction *instr = reinterpret_cast<SimInstruction *>(program_counter); instructionDecode(instr); icount_++; int32_t rpc = resume_pc_; if (MOZ_UNLIKELY(rpc != 0)) { // AsmJS signal handler ran and we have to adjust the pc. - activation->setInterrupted((void *)get_pc()); + activation->setResumePC((void *)get_pc()); set_pc(rpc); resume_pc_ = 0; } } program_counter = get_pc(); } }
--- a/js/src/jit/mips/Assembler-mips.h +++ b/js/src/jit/mips/Assembler-mips.h @@ -147,22 +147,16 @@ static MOZ_CONSTEXPR_VAR FloatRegister f static MOZ_CONSTEXPR_VAR FloatRegister f30 = {FloatRegisters::f30}; // MIPS CPUs can only load multibyte data that is "naturally" // four-byte-aligned, sp register should be eight-byte-aligned. static const uint32_t StackAlignment = 8; static const uint32_t CodeAlignment = 4; static const bool StackKeptAligned = true; -// As an invariant across architectures, within asm.js code: -// $sp % StackAlignment = (AsmJSFrameSize + masm.framePushed) % StackAlignment -// To achieve this on MIPS, the first instruction of the asm.js prologue pushes -// ra without incrementing masm.framePushed. -static const uint32_t AsmJSFrameSize = sizeof(void*); - static const Scale ScalePointer = TimesFour; // MIPS instruction types // +---------------------------------------------------------------+ // | 6 | 5 | 5 | 5 | 5 | 6 | // +---------------------------------------------------------------+ // Register type | Opcode | Rs | Rt | Rd | Sa | Function | // +---------------------------------------------------------------+
--- a/js/src/jit/mips/CodeGenerator-mips.cpp +++ b/js/src/jit/mips/CodeGenerator-mips.cpp @@ -47,17 +47,17 @@ CodeGeneratorMIPS::generatePrologue() return true; } bool CodeGeneratorMIPS::generateAsmJSPrologue(Label *stackOverflowLabel) { JS_ASSERT(gen->compilingAsmJS()); - // See comment in Assembler-mips.h about AsmJSFrameSize. + // See comment in Assembler-shared.h about AsmJSFrameSize. masm.push(ra); // The asm.js over-recursed handler wants to be able to assume that SP // points to the return address, so perform the check after pushing ra but // before pushing frameDepth. if (!omitOverRecursedCheck()) { masm.branchPtr(Assembler::AboveOrEqual, AsmJSAbsoluteAddress(AsmJSImm_StackLimit),
--- a/js/src/jit/mips/MacroAssembler-mips.cpp +++ b/js/src/jit/mips/MacroAssembler-mips.cpp @@ -1520,16 +1520,26 @@ MacroAssemblerMIPSCompat::callIon(Regist MOZ_ASSERT((framePushed() & 3) == 0); if ((framePushed() & 7) == 4) { ma_callIonHalfPush(callee); } else { adjustFrame(sizeof(uint32_t)); ma_callIon(callee); } } +void +MacroAssemblerMIPSCompat::callIonFromAsmJS(Register callee) +{ + ma_callIonNoPush(reg); + + // The Ion ABI has the callee pop the return address off the stack. + // The asm.js caller assumes that the call leaves sp unchanged, so bump + // the stack. + subPtr(Imm32(sizeof(void*)), StackPointer); +} void MacroAssemblerMIPSCompat::reserveStack(uint32_t amount) { if (amount) ma_subu(StackPointer, StackPointer, Imm32(amount)); adjustFrame(amount); } @@ -2956,31 +2966,16 @@ MacroAssemblerMIPS::ma_callIonHalfPush(c { // This is a MIPS hack to push return address during jalr delay slot. as_addiu(StackPointer, StackPointer, -sizeof(intptr_t)); as_jalr(r); as_sw(ra, StackPointer, 0); } void -MacroAssemblerMIPS::ma_callAndStoreRet(const Register r, uint32_t stackArgBytes) -{ - // Note: this function stores the return address to sp[16]. The caller - // must anticipate this by reserving additional space on the stack. - // The ABI does not provide space for a return address so this function - // stores 'ra' before any ABI arguments. - // This function may only be called if there are 4 or less arguments. - JS_ASSERT(stackArgBytes == 4 * sizeof(uintptr_t)); - - // This is a MIPS hack to push return address during jalr delay slot. - as_jalr(r); - as_sw(ra, StackPointer, 4 * sizeof(uintptr_t)); -} - -void MacroAssemblerMIPS::ma_call(ImmPtr dest) { ma_liPatchable(CallReg, dest); as_jalr(CallReg); as_nop(); } void
--- a/js/src/jit/mips/MacroAssembler-mips.h +++ b/js/src/jit/mips/MacroAssembler-mips.h @@ -296,19 +296,16 @@ class MacroAssemblerMIPS : public Assemb public: // calls an Ion function, assumes that the stack is untouched (8 byte alinged) void ma_callIon(const Register reg); // callso an Ion function, assuming that sp has already been decremented void ma_callIonNoPush(const Register reg); // calls an ion function, assuming that the stack is currently not 8 byte aligned void ma_callIonHalfPush(const Register reg); - // calls reg, storing the return address into sp[stackArgBytes] - void ma_callAndStoreRet(const Register reg, uint32_t stackArgBytes); - void ma_call(ImmPtr dest); void ma_jump(ImmPtr dest); void ma_cmp_set(Register dst, Register lhs, Register rhs, Condition c); void ma_cmp_set(Register dst, Register lhs, Imm32 imm, Condition c); void ma_cmp_set(Register dst, Register lhs, ImmPtr imm, Condition c) { ma_cmp_set(dst, lhs, Imm32(uint32_t(imm.value)), c); @@ -410,48 +407,23 @@ class MacroAssemblerMIPSCompat : public call(CallReg); } void call(JitCode *c) { BufferOffset bo = m_buffer.nextOffset(); addPendingJump(bo, ImmPtr(c->raw()), Relocation::JITCODE); ma_liPatchable(ScratchRegister, Imm32((uint32_t)c->raw())); ma_callIonHalfPush(ScratchRegister); } - - void appendCallSite(const CallSiteDesc &desc) { - // Add an extra sizeof(void*) to include the return address that was - // pushed by the call instruction (see CallSite::stackDepth). - enoughMemory_ &= append(CallSite(desc, currentOffset(), framePushed_ + AsmJSFrameSize)); - } - void call(const CallSiteDesc &desc, const Register reg) { call(reg); - appendCallSite(desc); + enoughMemory_ &= append(desc, currentOffset(), framePushed_); } void call(const CallSiteDesc &desc, Label *label) { call(label); - appendCallSite(desc); - } - void call(const CallSiteDesc &desc, AsmJSImmPtr imm) { - call(imm); - appendCallSite(desc); - } - void callExit(AsmJSImmPtr imm, uint32_t stackArgBytes) { - movePtr(imm, CallReg); - ma_callAndStoreRet(CallReg, stackArgBytes); - appendCallSite(CallSiteDesc::Exit()); - } - void callIonFromAsmJS(const Register reg) { - ma_callIonNoPush(reg); - appendCallSite(CallSiteDesc::Exit()); - - // The Ion ABI has the callee pop the return address off the stack. - // The asm.js caller assumes that the call leaves sp unchanged, so bump - // the stack. - subPtr(Imm32(sizeof(void*)), StackPointer); + enoughMemory_ &= append(desc, currentOffset(), framePushed_); } void branch(JitCode *c) { BufferOffset bo = m_buffer.nextOffset(); addPendingJump(bo, ImmPtr(c->raw()), Relocation::JITCODE); ma_liPatchable(ScratchRegister, Imm32((uint32_t)c->raw())); as_jr(ScratchRegister); as_nop(); @@ -988,16 +960,17 @@ public: bool buildFakeExitFrame(Register scratch, uint32_t *offset); void callWithExitFrame(JitCode *target); void callWithExitFrame(JitCode *target, Register dynStack); // Makes an Ion call using the only two methods that it is sane for // indep code to make a call void callIon(Register callee); + void callIonFromAsmJS(Register callee); void reserveStack(uint32_t amount); void freeStack(uint32_t amount); void freeStack(Register amount); void add32(Register src, Register dest); void add32(Imm32 imm, Register dest); void add32(Imm32 imm, const Address &dest);
--- a/js/src/jit/shared/Assembler-shared.h +++ b/js/src/jit/shared/Assembler-shared.h @@ -572,58 +572,29 @@ class CodeLocationLabel return raw_; } uint8_t *offset() const { JS_ASSERT(state_ == Relative); return raw_; } }; -// Describes the user-visible properties of a callsite. -// -// A few general notes about the stack-walking supported by CallSite(Desc): -// - This information facilitates stack-walking performed by FrameIter which -// is used by Error.stack and other user-visible stack-walking functions. -// - Ion/asm.js calling conventions do not maintain a frame-pointer so -// stack-walking must lookup the stack depth based on the PC. -// - Stack-walking only occurs from C++ after a synchronous calls (JS-to-JS and -// JS-to-C++). Thus, we do not need to map arbitrary PCs to stack-depths, -// just the return address at callsites. -// - An exception to the above rule is the interrupt callback which can happen -// at arbitrary PCs. In such cases, we drop frames from the stack-walk. In -// the future when a full PC->stack-depth map is maintained, we handle this -// case. +// While the frame-pointer chain allows the stack to be unwound without +// metadata, Error.stack still needs to know the line/column of every call in +// the chain. A CallSiteDesc describes the line/column of a single callsite. +// A CallSiteDesc is created by callers of MacroAssembler. class CallSiteDesc { uint32_t line_; uint32_t column_; - uint32_t functionNameIndex_; - - static const uint32_t sEntryTrampoline = UINT32_MAX; - static const uint32_t sExit = UINT32_MAX - 1; - public: - static const uint32_t FUNCTION_NAME_INDEX_MAX = UINT32_MAX - 2; - CallSiteDesc() {} - - CallSiteDesc(uint32_t line, uint32_t column, uint32_t functionNameIndex) - : line_(line), column_(column), functionNameIndex_(functionNameIndex) - {} - - static CallSiteDesc Entry() { return CallSiteDesc(0, 0, sEntryTrampoline); } - static CallSiteDesc Exit() { return CallSiteDesc(0, 0, sExit); } - - bool isEntry() const { return functionNameIndex_ == sEntryTrampoline; } - bool isExit() const { return functionNameIndex_ == sExit; } - bool isNormal() const { return !(isEntry() || isExit()); } - - uint32_t line() const { JS_ASSERT(isNormal()); return line_; } - uint32_t column() const { JS_ASSERT(isNormal()); return column_; } - uint32_t functionNameIndex() const { JS_ASSERT(isNormal()); return functionNameIndex_; } + CallSiteDesc(uint32_t line, uint32_t column) : line_(line), column_(column) {} + uint32_t line() const { return line_; } + uint32_t column() const { return column_; } }; // Adds to CallSiteDesc the metadata necessary to walk the stack given an // initial stack-pointer. struct CallSite : public CallSiteDesc { uint32_t returnAddressOffset_; uint32_t stackDepth_; @@ -636,23 +607,31 @@ struct CallSite : public CallSiteDesc returnAddressOffset_(returnAddressOffset), stackDepth_(stackDepth) { } void setReturnAddressOffset(uint32_t r) { returnAddressOffset_ = r; } uint32_t returnAddressOffset() const { return returnAddressOffset_; } // The stackDepth measures the amount of stack space pushed since the - // function was called. In particular, this includes the word pushed by the - // call instruction on x86/x64. - uint32_t stackDepth() const { JS_ASSERT(!isEntry()); return stackDepth_; } + // function was called. In particular, this includes the pushed return + // address on all archs (whether or not the call instruction pushes the + // return address (x86/x64) or the prologue does (ARM/MIPS). + uint32_t stackDepth() const { return stackDepth_; } }; typedef Vector<CallSite, 0, SystemAllocPolicy> CallSiteVector; +// As an invariant across architectures, within asm.js code: +// $sp % StackAlignment = (AsmJSFrameSize + masm.framePushed) % StackAlignment +// AsmJSFrameSize is 1 word, for the return address pushed by the call (or, in +// the case of ARM/MIPS, by the first instruction of the prologue). This means +// masm.framePushed never includes the pushed return address. +static const uint32_t AsmJSFrameSize = sizeof(void*); + // Summarizes a heap access made by asm.js code that needs to be patched later // and/or looked up by the asm.js signal handlers. Different architectures need // to know different things (x64: offset and length, ARM: where to patch in // heap length, x86: where to patch in heap length and base) hence the massive // #ifdefery. class AsmJSHeapAccess { uint32_t offset_; @@ -816,17 +795,21 @@ class AssemblerShared void propagateOOM(bool success) { enoughMemory_ &= success; } bool oom() const { return !enoughMemory_; } - bool append(CallSite callsite) { return callsites_.append(callsite); } + bool append(const CallSiteDesc &desc, size_t currentOffset, size_t framePushed) { + // framePushed does not include AsmJSFrameSize, so add it in here (see + // CallSite::stackDepth). + return callsites_.append(CallSite(desc, currentOffset, framePushed + AsmJSFrameSize)); + } CallSiteVector &&extractCallSites() { return Move(callsites_); } bool append(AsmJSHeapAccess access) { return asmJSHeapAccesses_.append(access); } AsmJSHeapAccessVector &&extractAsmJSHeapAccesses() { return Move(asmJSHeapAccesses_); } bool append(AsmJSGlobalAccess access) { return asmJSGlobalAccesses_.append(access); } size_t numAsmJSGlobalAccesses() const { return asmJSGlobalAccesses_.length(); } AsmJSGlobalAccess asmJSGlobalAccess(size_t i) const { return asmJSGlobalAccesses_[i]; }
--- a/js/src/jit/shared/MacroAssembler-x86-shared.h +++ b/js/src/jit/shared/MacroAssembler-x86-shared.h @@ -662,36 +662,33 @@ class MacroAssemblerX86Shared : public A lea(Operand(address), dest); } // Builds an exit frame on the stack, with a return address to an internal // non-function. Returns offset to be passed to markSafepointAt(). bool buildFakeExitFrame(Register scratch, uint32_t *offset); void callWithExitFrame(JitCode *target); + void call(const CallSiteDesc &desc, Label *label) { + call(label); + enoughMemory_ &= append(desc, currentOffset(), framePushed_); + } + void call(const CallSiteDesc &desc, Register reg) { + call(reg); + enoughMemory_ &= append(desc, currentOffset(), framePushed_); + } void callIon(Register callee) { call(callee); } - - void appendCallSite(const CallSiteDesc &desc) { - // Add an extra sizeof(void*) to include the return address that was - // pushed by the call instruction (see CallSite::stackDepth). - enoughMemory_ &= append(CallSite(desc, currentOffset(), framePushed_ + AsmJSFrameSize)); + void callIonFromAsmJS(Register callee) { + call(callee); } - - void call(const CallSiteDesc &desc, Label *label) { - call(label); - appendCallSite(desc); - } - void call(const CallSiteDesc &desc, Register reg) { - call(reg); - appendCallSite(desc); - } - void callIonFromAsmJS(Register reg) { - call(CallSiteDesc::Exit(), reg); + void call(AsmJSImmPtr target) { + mov(target, eax); + call(eax); } void checkStackAlignment() { // Exists for ARM compatibility. } CodeOffsetLabel labelForPatch() { return CodeOffsetLabel(size());
--- a/js/src/jit/x64/Architecture-x64.h +++ b/js/src/jit/x64/Architecture-x64.h @@ -236,21 +236,26 @@ struct FloatRegister { static uint32_t GetSizeInBytes(const TypedRegisterSet<FloatRegister> &s); static uint32_t GetPushSizeInBytes(const TypedRegisterSet<FloatRegister> &s); uint32_t getRegisterDumpOffsetInBytes(); }; // Arm/D32 has double registers that can NOT be treated as float32 // and this requires some dances in lowering. -inline bool hasUnaliasedDouble() { +inline bool +hasUnaliasedDouble() +{ return false; } + // On ARM, Dn aliases both S2n and S2n+1, so if you need to convert a float32 // to a double as a temporary, you need a temporary double register. -inline bool hasMultiAlias() { +inline bool +hasMultiAlias() +{ return false; } } // namespace jit } // namespace js #endif /* jit_x64_Architecture_x64_h */
--- a/js/src/jit/x64/Assembler-x64.h +++ b/js/src/jit/x64/Assembler-x64.h @@ -180,23 +180,16 @@ static MOZ_CONSTEXPR_VAR Register OsrFra static MOZ_CONSTEXPR_VAR Register PreBarrierReg = rdx; // GCC stack is aligned on 16 bytes, but we don't maintain the invariant in // jitted code. static const uint32_t StackAlignment = 16; static const bool StackKeptAligned = false; static const uint32_t CodeAlignment = 8; -// As an invariant across architectures, within asm.js code: -// $sp % StackAlignment = (AsmJSFrameSize + masm.framePushed) % StackAlignment -// On x64, this naturally falls out of the fact that the 'call' instruction -// pushes the return address on the stack and masm.framePushed = 0 at the first -// instruction of the prologue. -static const uint32_t AsmJSFrameSize = sizeof(void*); - static const Scale ScalePointer = TimesEight; } // namespace jit } // namespace js #include "jit/shared/Assembler-x86-shared.h" namespace js {
--- a/js/src/jit/x64/MacroAssembler-x64.h +++ b/js/src/jit/x64/MacroAssembler-x64.h @@ -95,28 +95,16 @@ class MacroAssemblerX64 : public MacroAs ///////////////////////////////////////////////////////////////// void call(ImmWord target) { mov(target, rax); call(rax); } void call(ImmPtr target) { call(ImmWord(uintptr_t(target.value))); } - void call(AsmJSImmPtr target) { - mov(target, rax); - call(rax); - } - - void call(const CallSiteDesc &desc, AsmJSImmPtr target) { - call(target); - appendCallSite(desc); - } - void callExit(AsmJSImmPtr target, uint32_t stackArgBytes) { - call(CallSiteDesc::Exit(), target); - } // Refers to the upper 32 bits of a 64-bit Value operand. // On x86_64, the upper 32 bits do not necessarily only contain the type. Operand ToUpper32(Operand base) { switch (base.kind()) { case Operand::MEM_REG_DISP: return Operand(Register::FromCode(base.base()), base.disp() + 4);
--- a/js/src/jit/x86/Architecture-x86.h +++ b/js/src/jit/x86/Architecture-x86.h @@ -213,22 +213,26 @@ struct FloatRegister { static uint32_t GetPushSizeInBytes(const TypedRegisterSet<FloatRegister> &s); uint32_t getRegisterDumpOffsetInBytes(); }; // Arm/D32 has double registers that can NOT be treated as float32 // and this requires some dances in lowering. -inline bool hasUnaliasedDouble() { +inline bool +hasUnaliasedDouble() +{ return false; } // On ARM, Dn aliases both S2n and S2n+1, so if you need to convert a float32 // to a double as a temporary, you need a temporary double register. -inline bool hasMultiAlias() { +inline bool +hasMultiAlias() +{ return false; } } // namespace jit } // namespace js #endif /* jit_x86_Architecture_x86_h */
--- a/js/src/jit/x86/Assembler-x86.h +++ b/js/src/jit/x86/Assembler-x86.h @@ -108,23 +108,16 @@ static MOZ_CONSTEXPR_VAR Register AsmJSI #if defined(__GNUC__) static const uint32_t StackAlignment = 16; #else static const uint32_t StackAlignment = 4; #endif static const bool StackKeptAligned = false; static const uint32_t CodeAlignment = 8; -// As an invariant across architectures, within asm.js code: -// $sp % StackAlignment = (AsmJSFrameSize + masm.framePushed) % StackAlignment -// On x86, this naturally falls out of the fact that the 'call' instruction -// pushes the return address on the stack and masm.framePushed = 0 at the first -// instruction of the prologue. -static const uint32_t AsmJSFrameSize = sizeof(void*); - struct ImmTag : public Imm32 { ImmTag(JSValueTag mask) : Imm32(int32_t(mask)) { } }; struct ImmType : public ImmTag @@ -377,23 +370,16 @@ class Assembler : public AssemblerX86Sha } void call(ImmWord target) { call(ImmPtr((void*)target.value)); } void call(ImmPtr target) { JmpSrc src = masm.call(); addPendingJump(src, target, Relocation::HARDCODED); } - void call(AsmJSImmPtr target) { - // Moving to a register is suboptimal. To fix (use a single - // call-immediate instruction) we'll need to distinguish a new type of - // relative patch to an absolute address in AsmJSAbsoluteLink. - mov(target, eax); - call(eax); - } // Emit a CALL or CMP (nop) instruction. ToggleCall can be used to patch // this instruction. CodeOffsetLabel toggledCall(JitCode *target, bool enabled) { CodeOffsetLabel offset(size()); JmpSrc src = enabled ? masm.call() : masm.cmp_eax(); addPendingJump(src, ImmPtr(target->raw()), Relocation::JITCODE); JS_ASSERT(size() - offset.offset() == ToggledCallSize());
--- a/js/src/jit/x86/MacroAssembler-x86.h +++ b/js/src/jit/x86/MacroAssembler-x86.h @@ -1109,23 +1109,16 @@ class MacroAssemblerX86 : public MacroAs } void callWithExitFrame(JitCode *target, Register dynStack) { addPtr(Imm32(framePushed()), dynStack); makeFrameDescriptor(dynStack, JitFrame_IonJS); Push(dynStack); call(target); } - void call(const CallSiteDesc &desc, AsmJSImmPtr target) { - call(target); - appendCallSite(desc); - } - void callExit(AsmJSImmPtr target, uint32_t stackArgBytes) { - call(CallSiteDesc::Exit(), target); - } #ifdef JSGC_GENERATIONAL void branchPtrInNurseryRange(Condition cond, Register ptr, Register temp, Label *label); void branchValueIsNurseryObject(Condition cond, ValueOperand value, Register temp, Label *label); #endif }; typedef MacroAssemblerX86 MacroAssemblerSpecific;
--- a/js/src/js.msg +++ b/js/src/js.msg @@ -237,21 +237,21 @@ MSG_DEF(JSMSG_SC_NOT_TRANSFERABLE, 18 MSG_DEF(JSMSG_SC_DUP_TRANSFERABLE, 184, 0, JSEXN_TYPEERR, "duplicate transferable for structured clone") MSG_DEF(JSMSG_CANT_REPORT_AS_NON_EXTENSIBLE, 185, 0, JSEXN_TYPEERR, "proxy can't report an extensible object as non-extensible") MSG_DEF(JSMSG_SYMBOL_TO_STRING, 186, 0, JSEXN_TYPEERR, "can't convert symbol to string") MSG_DEF(JSMSG_UNUSED187, 187, 0, JSEXN_NONE, "") MSG_DEF(JSMSG_INCOMPATIBLE_METHOD, 188, 3, JSEXN_TYPEERR, "{0} {1} called on incompatible {2}") MSG_DEF(JSMSG_SYMBOL_TO_PRIMITIVE, 189, 0, JSEXN_TYPEERR, "can't convert symbol object to primitive") MSG_DEF(JSMSG_UNUSED190, 190, 0, JSEXN_NONE, "") MSG_DEF(JSMSG_BAD_INDEX, 191, 0, JSEXN_RANGEERR, "invalid or out-of-range index") -MSG_DEF(JSMSG_UNUSED192, 192, 0, JSEXN_NONE, "") +MSG_DEF(JSMSG_SELFHOSTED_TOP_LEVEL_LET,192,0, JSEXN_SYNTAXERR, "self-hosted code cannot contain top-level 'let' declarations") MSG_DEF(JSMSG_BAD_FOR_EACH_LOOP, 193, 0, JSEXN_SYNTAXERR, "invalid for each loop") MSG_DEF(JSMSG_OBJECT_WATCH_DEPRECATED,194, 0, JSEXN_NONE, "Object.prototype.watch and unwatch are very slow, non-standard, and deprecated; use a getter/setter instead") MSG_DEF(JSMSG_TYPE_ERR_BAD_ARGS, 195, 0, JSEXN_TYPEERR, "invalid arguments") -MSG_DEF(JSMSG_UNUSED196, 196, 0, JSEXN_NONE, "") +MSG_DEF(JSMSG_REDECLARED_CATCH_IDENTIFIER, 196, 1, JSEXN_TYPEERR, "redeclaration of identifier '{0}' in catch") MSG_DEF(JSMSG_INTERNAL_INTL_ERROR, 197, 0, JSEXN_ERR, "internal error while computing Intl data") MSG_DEF(JSMSG_DEFAULT_LOCALE_ERROR, 198, 0, JSEXN_ERR, "internal error getting the default locale") MSG_DEF(JSMSG_TOO_MANY_LOCALS, 199, 0, JSEXN_SYNTAXERR, "too many local variables") MSG_DEF(JSMSG_ARRAY_INIT_TOO_BIG, 200, 0, JSEXN_INTERNALERR, "array initialiser too large") MSG_DEF(JSMSG_REGEXP_TOO_COMPLEX, 201, 0, JSEXN_INTERNALERR, "regular expression too complex") MSG_DEF(JSMSG_BUFFER_TOO_SMALL, 202, 0, JSEXN_INTERNALERR, "buffer too small") MSG_DEF(JSMSG_BAD_SURROGATE_CHAR, 203, 1, JSEXN_TYPEERR, "bad surrogate character {0}") MSG_DEF(JSMSG_UTF8_CHAR_TOO_LARGE, 204, 1, JSEXN_TYPEERR, "UTF-8 character {0} too large")
--- a/js/src/jsapi-tests/testArrayBuffer.cpp +++ b/js/src/jsapi-tests/testArrayBuffer.cpp @@ -51,26 +51,26 @@ BEGIN_TEST(testArrayBuffer_bug720949_ste CHECK_SAME(v, INT_TO_JSVAL(MAGIC_VALUE_2)); // Steal the contents void *contents = JS_StealArrayBufferContents(cx, obj); CHECK(contents != nullptr); CHECK(data != nullptr); // Check that the original ArrayBuffer is neutered - CHECK_EQUAL(JS_GetArrayBufferByteLength(obj), 0); + CHECK_EQUAL(JS_GetArrayBufferByteLength(obj), 0u); CHECK(JS_GetProperty(cx, obj, "byteLength", &v)); CHECK_SAME(v, INT_TO_JSVAL(0)); CHECK(JS_GetProperty(cx, view, "byteLength", &v)); CHECK_SAME(v, INT_TO_JSVAL(0)); CHECK(JS_GetProperty(cx, view, "byteOffset", &v)); CHECK_SAME(v, INT_TO_JSVAL(0)); CHECK(JS_GetProperty(cx, view, "length", &v)); CHECK_SAME(v, INT_TO_JSVAL(0)); - CHECK_EQUAL(JS_GetArrayBufferByteLength(obj), 0); + CHECK_EQUAL(JS_GetArrayBufferByteLength(obj), 0u); v = JSVAL_VOID; JS_GetElement(cx, obj, 0, &v); CHECK_SAME(v, JSVAL_VOID); // Transfer to a new ArrayBuffer JS::RootedObject dst(cx, JS_NewArrayBufferWithContents(cx, size, contents)); CHECK(JS_IsArrayBufferObject(dst)); data = JS_GetStableArrayBufferData(cx, obj);
--- a/js/src/jsapi-tests/testGCOutOfMemory.cpp +++ b/js/src/jsapi-tests/testGCOutOfMemory.cpp @@ -29,30 +29,30 @@ BEGIN_TEST(testGCOutOfMemory) " array.push({});" " array = []; array.push(0);" "})();"; bool ok = JS_EvaluateScript(cx, global, source, strlen(source), "", 1, &root); /* Check that we get OOM. */ CHECK(!ok); CHECK(!JS_IsExceptionPending(cx)); - CHECK_EQUAL(errorCount, 1); + CHECK_EQUAL(errorCount, 1u); JS_GC(rt); // Temporarily disabled to reopen the tree. Bug 847579. return true; EVAL("(function() {" " var array = [];" " for (var i = max >> 2; i != 0;) {" " --i;" " array.push({});" " }" "})();", &root); - CHECK_EQUAL(errorCount, 1); + CHECK_EQUAL(errorCount, 1u); return true; } virtual JSRuntime * createRuntime() { JSRuntime *rt = JS_NewRuntime(768 * 1024); if (!rt) return nullptr; setNativeStackQuota(rt);
--- a/js/src/jsapi-tests/testMappedArrayBuffer.cpp +++ b/js/src/jsapi-tests/testMappedArrayBuffer.cpp @@ -67,33 +67,33 @@ JSObject *CreateNewObject(const int offs JSObject *obj = JS_NewMappedArrayBufferWithContents(cx, length, ptr); if (!obj) { JS_ReleaseMappedArrayBufferContents(ptr, length); return nullptr; } return obj; } -bool VerifyObject(JS::HandleObject obj, const int offset, const int length, const bool mapped) +bool VerifyObject(JS::HandleObject obj, uint32_t offset, uint32_t length, const bool mapped) { CHECK(obj); CHECK(JS_IsArrayBufferObject(obj)); CHECK_EQUAL(JS_GetArrayBufferByteLength(obj), length); if (mapped) CHECK(JS_IsMappedArrayBufferObject(obj)); else CHECK(!JS_IsMappedArrayBufferObject(obj)); const char *data = reinterpret_cast<const char *>(JS_GetArrayBufferData(obj)); CHECK(data); CHECK(memcmp(data, test_data + offset, length) == 0); return true; } -bool TestCreateObject(const int offset, const int length) +bool TestCreateObject(uint32_t offset, uint32_t length) { JS::RootedObject obj(cx, CreateNewObject(offset, length)); CHECK(VerifyObject(obj, offset, length, true)); return true; } bool TestReleaseContents()
--- a/js/src/jsapi-tests/testNewObject.cpp +++ b/js/src/jsapi-tests/testNewObject.cpp @@ -64,26 +64,26 @@ BEGIN_TEST(testNewObject_1) // With no arguments. JS::RootedObject obj(cx, JS_New(cx, Array, JS::HandleValueArray::empty())); CHECK(obj); JS::RootedValue rt(cx, JS::ObjectValue(*obj)); CHECK(JS_IsArrayObject(cx, obj)); uint32_t len; CHECK(JS_GetArrayLength(cx, obj, &len)); - CHECK_EQUAL(len, 0); + CHECK_EQUAL(len, 0u); // With one argument. argv[0].setInt32(4); obj = JS_New(cx, Array, JS::HandleValueArray::subarray(argv, 0, 1)); CHECK(obj); rt = OBJECT_TO_JSVAL(obj); CHECK(JS_IsArrayObject(cx, obj)); CHECK(JS_GetArrayLength(cx, obj, &len)); - CHECK_EQUAL(len, 4); + CHECK_EQUAL(len, 4u); // With N arguments. for (size_t i = 0; i < N; i++) argv[i].setInt32(i); obj = JS_New(cx, Array, JS::HandleValueArray::subarray(argv, 0, N)); CHECK(obj); rt = OBJECT_TO_JSVAL(obj); CHECK(JS_IsArrayObject(cx, obj));
--- a/js/src/jsapi-tests/testRegExp.cpp +++ b/js/src/jsapi-tests/testRegExp.cpp @@ -22,17 +22,17 @@ END_TEST(testObjectIsRegExp) BEGIN_TEST(testGetRegExpFlags) { JS::RootedValue val(cx); JS::RootedObject obj(cx); EVAL("/foopy/", &val); obj = val.toObjectOrNull(); - CHECK_EQUAL(JS_GetRegExpFlags(cx, obj), 0); + CHECK_EQUAL(JS_GetRegExpFlags(cx, obj), 0u); EVAL("/foopy/g", &val); obj = val.toObjectOrNull(); CHECK_EQUAL(JS_GetRegExpFlags(cx, obj), JSREG_GLOB); EVAL("/foopy/gi", &val); obj = val.toObjectOrNull(); CHECK_EQUAL(JS_GetRegExpFlags(cx, obj), (JSREG_FOLD | JSREG_GLOB));
--- a/js/src/jsapi-tests/testResolveRecursion.cpp +++ b/js/src/jsapi-tests/testResolveRecursion.cpp @@ -57,18 +57,18 @@ BEGIN_TEST(testResolveRecursion) obj2 = nullptr; JS::RemoveObjectRoot(cx, &obj1); JS::RemoveObjectRoot(cx, &obj2); return true; } JS::Heap<JSObject *> obj1; JS::Heap<JSObject *> obj2; -unsigned resolveEntryCount; -unsigned resolveExitCount; +int resolveEntryCount; +int resolveExitCount; struct AutoIncrCounters { explicit AutoIncrCounters(cls_testResolveRecursion *t) : t(t) { t->resolveEntryCount++; } ~AutoIncrCounters() {
--- a/js/src/jsapi-tests/testScriptInfo.cpp +++ b/js/src/jsapi-tests/testScriptInfo.cpp @@ -32,17 +32,17 @@ BEGIN_TEST(testScriptInfo) JS::RootedScript script(cx, JS_CompileScript(cx, global, code, strlen(code), options)); CHECK(script); jsbytecode *start = JS_LineNumberToPC(cx, script, startLine); CHECK_EQUAL(JS_GetScriptBaseLineNumber(cx, script), startLine); CHECK_EQUAL(JS_PCToLineNumber(cx, script, start), startLine); - CHECK_EQUAL(JS_GetScriptLineExtent(cx, script), 11); + CHECK_EQUAL(JS_GetScriptLineExtent(cx, script), 11u); CHECK(strcmp(JS_GetScriptFilename(script), __FILE__) == 0); const jschar *sourceMap = JS_GetScriptSourceMap(cx, script); CHECK(sourceMap); CHECK(CharsMatch(sourceMap, "http://example.com/path/to/source-map.json")); return true; } static bool
--- a/js/src/jsapi-tests/testTypedArrays.cpp +++ b/js/src/jsapi-tests/testTypedArrays.cpp @@ -67,18 +67,18 @@ TestPlainTypedArray(JSContext *cx) RootedObject array(cx, Create(cx, 7)); CHECK(JS_IsTypedArrayObject(array)); RootedObject proto(cx); JS_GetPrototype(cx, array, &proto); CHECK(!JS_IsTypedArrayObject(proto)); RootedObject dummy(cx, JS_GetParent(proto)); CHECK(!JS_IsTypedArrayObject(dummy)); - CHECK_EQUAL(JS_GetTypedArrayLength(array), 7); - CHECK_EQUAL(JS_GetTypedArrayByteOffset(array), 0); + CHECK_EQUAL(JS_GetTypedArrayLength(array), 7u); + CHECK_EQUAL(JS_GetTypedArrayByteOffset(array), 0u); CHECK_EQUAL(JS_GetTypedArrayByteLength(array), sizeof(Element) * 7); Element *data; CHECK(data = GetData(array)); *data = 13; RootedValue v(cx); CHECK(JS_GetElement(cx, array, 0, &v)); CHECK_SAME(v, INT_TO_JSVAL(13)); @@ -102,31 +102,31 @@ TestArrayFromBuffer(JSContext *cx) { RootedObject notArray(cx, CreateWithBuffer(cx, buffer, UINT32_MAX, -1)); CHECK(!notArray); } RootedObject array(cx, CreateWithBuffer(cx, buffer, 0, -1)); CHECK_EQUAL(JS_GetTypedArrayLength(array), elts); - CHECK_EQUAL(JS_GetTypedArrayByteOffset(array), 0); + CHECK_EQUAL(JS_GetTypedArrayByteOffset(array), 0u); CHECK_EQUAL(JS_GetTypedArrayByteLength(array), nbytes); CHECK_EQUAL(JS_GetArrayBufferViewBuffer(cx, array), (JSObject*) buffer); Element *data; CHECK(data = GetData(array)); CHECK(bufdata = JS_GetStableArrayBufferData(cx, buffer)); CHECK_EQUAL((void*) data, (void*) bufdata); - CHECK_EQUAL(*bufdata, 1); - CHECK_EQUAL(*reinterpret_cast<uint8_t*>(data), 1); + CHECK_EQUAL(*bufdata, 1u); + CHECK_EQUAL(*reinterpret_cast<uint8_t*>(data), 1u); RootedObject shortArray(cx, CreateWithBuffer(cx, buffer, 0, elts / 2)); CHECK_EQUAL(JS_GetTypedArrayLength(shortArray), elts / 2); - CHECK_EQUAL(JS_GetTypedArrayByteOffset(shortArray), 0); + CHECK_EQUAL(JS_GetTypedArrayByteOffset(shortArray), 0u); CHECK_EQUAL(JS_GetTypedArrayByteLength(shortArray), nbytes / 2); RootedObject ofsArray(cx, CreateWithBuffer(cx, buffer, nbytes / 2, -1)); CHECK_EQUAL(JS_GetTypedArrayLength(ofsArray), elts / 2); CHECK_EQUAL(JS_GetTypedArrayByteOffset(ofsArray), nbytes / 2); CHECK_EQUAL(JS_GetTypedArrayByteLength(ofsArray), nbytes / 2); // Make sure all 3 views reflect the same buffer at the expected locations
--- a/js/src/jsapi-tests/tests.h +++ b/js/src/jsapi-tests/tests.h @@ -2,16 +2,18 @@ * 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 jsapi_tests_tests_h #define jsapi_tests_tests_h +#include "mozilla/TypeTraits.h" + #include <errno.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include "jsalloc.h" #include "jscntxt.h" #include "jsgc.h" @@ -156,17 +158,22 @@ class JSAPITest } // Note that in some still-supported GCC versions (we think anything before // GCC 4.6), this template does not work when the second argument is // nullptr. It infers type U = long int. Use CHECK_NULL instead. template <typename T, typename U> bool checkEqual(const T &actual, const U &expected, const char *actualExpr, const char *expectedExpr, - const char *filename, int lineno) { + const char *filename, int lineno) + { + static_assert(mozilla::IsSigned<T>::value == mozilla::IsSigned<U>::value, + "using CHECK_EQUAL with different-signed inputs triggers compiler warnings"); + static_assert(mozilla::IsUnsigned<T>::value == mozilla::IsUnsigned<U>::value, + "using CHECK_EQUAL with different-signed inputs triggers compiler warnings"); return (actual == expected) || fail(JSAPITestString("CHECK_EQUAL failed: expected (") + expectedExpr + ") = " + toSource(expected) + ", got (" + actualExpr + ") = " + toSource(actual), filename, lineno); } #define CHECK_EQUAL(actual, expected) \ do { \
--- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -4655,20 +4655,20 @@ JS_ObjectIsDate(JSContext *cx, JS::Handl extern JS_PUBLIC_API(void) JS_ClearDateCaches(JSContext *cx); /************************************************************************/ /* * Regular Expressions. */ -#define JSREG_FOLD 0x01 /* fold uppercase to lowercase */ -#define JSREG_GLOB 0x02 /* global exec, creates array of matches */ -#define JSREG_MULTILINE 0x04 /* treat ^ and $ as begin and end of line */ -#define JSREG_STICKY 0x08 /* only match starting at lastIndex */ +#define JSREG_FOLD 0x01u /* fold uppercase to lowercase */ +#define JSREG_GLOB 0x02u /* global exec, creates array of matches */ +#define JSREG_MULTILINE 0x04u /* treat ^ and $ as begin and end of line */ +#define JSREG_STICKY 0x08u /* only match starting at lastIndex */ extern JS_PUBLIC_API(JSObject *) JS_NewRegExpObject(JSContext *cx, JS::HandleObject obj, char *bytes, size_t length, unsigned flags); extern JS_PUBLIC_API(JSObject *) JS_NewUCRegExpObject(JSContext *cx, JS::HandleObject obj, jschar *chars, size_t length, unsigned flags);
--- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -49,18 +49,16 @@ using namespace js; using namespace js::gc; using namespace js::types; using namespace js::frontend; using mozilla::ArrayLength; using mozilla::PodCopy; -using mozilla::Range; -using mozilla::RangedPtr; static bool fun_getProperty(JSContext *cx, HandleObject obj_, HandleId id, MutableHandleValue vp) { RootedObject obj(cx, obj_); while (!obj->is<JSFunction>()) { if (!JSObject::getProto(cx, obj, &obj)) return false; @@ -760,17 +758,17 @@ js::FindBody(JSContext *cx, HandleFuncti options.setVersion(fun->nonLazyScript()->getVersion()); AutoKeepAtoms keepAtoms(cx->perThreadData); AutoStableStringChars stableChars(cx); if (!stableChars.initTwoByte(cx, src)) return false; - const Range<const jschar> srcChars = stableChars.twoByteRange(); + const mozilla::Range<const jschar> srcChars = stableChars.twoByteRange(); TokenStream ts(cx, options, srcChars.start().get(), srcChars.length(), nullptr); int nest = 0; bool onward = true; // Skip arguments list. do { switch (ts.getToken()) { case TOK_NAME: case TOK_YIELD: @@ -796,17 +794,17 @@ js::FindBody(JSContext *cx, HandleFuncti tt = ts.getToken(); if (tt == TOK_ERROR) return false; bool braced = tt == TOK_LC; JS_ASSERT_IF(fun->isExprClosure(), !braced); *bodyStart = ts.currentToken().pos.begin; if (braced) *bodyStart += 1; - RangedPtr<const jschar> end = srcChars.end(); + mozilla::RangedPtr<const jschar> end = srcChars.end(); if (end[-1] == '}') { end--; } else { JS_ASSERT(!braced); for (; unicode::IsSpaceOrBOM2(end[-1]); end--) ; } *bodyEnd = end - srcChars.start(); @@ -1736,17 +1734,17 @@ FunctionConstructor(JSContext *cx, unsig if (hasRest) fun->setHasRest(); AutoStableStringChars stableChars(cx); if (!stableChars.initTwoByte(cx, str)) return false; - Range<const jschar> chars = stableChars.twoByteRange(); + mozilla::Range<const jschar> chars = stableChars.twoByteRange(); SourceBufferHolder::Ownership ownership = stableChars.maybeGiveOwnershipToCaller() ? SourceBufferHolder::GiveOwnership : SourceBufferHolder::NoOwnership; bool ok; SourceBufferHolder srcBuf(chars.start().get(), chars.length(), ownership); if (isStarGenerator) ok = frontend::CompileStarGeneratorBody(cx, &fun, options, formals, srcBuf); else
--- a/js/src/jsiter.cpp +++ b/js/src/jsiter.cpp @@ -232,17 +232,17 @@ struct SortComparatorIds if (JSID_IS_SYMBOL(a)) { MOZ_ASSERT(JSID_IS_SYMBOL(b)); JS::SymbolCode ca = JSID_TO_SYMBOL(a)->code(); JS::SymbolCode cb = JSID_TO_SYMBOL(b)->code(); if (ca != cb) { *lessOrEqualp = uint32_t(ca) <= uint32_t(cb); return true; } - JS_ASSERT(ca == JS::SymbolCode::InSymbolRegistry || ca == JS::SymbolCode::Unique); + JS_ASSERT(ca == JS::SymbolCode::InSymbolRegistry || ca == JS::SymbolCode::UniqueSymbol); astr = JSID_TO_SYMBOL(a)->description(); bstr = JSID_TO_SYMBOL(b)->description(); if (!astr || !bstr) { *lessOrEqualp = !astr; return true; } // Fall through to string comparison on the descriptions. The sort
--- a/js/src/moz.build +++ b/js/src/moz.build @@ -242,16 +242,17 @@ if CONFIG['ENABLE_TRACE_LOGGING']: 'vm/TraceLogging.cpp', ] if CONFIG['ENABLE_ION']: UNIFIED_SOURCES += [ 'irregexp/NativeRegExpMacroAssembler.cpp', 'jit/AliasAnalysis.cpp', 'jit/AsmJS.cpp', + 'jit/AsmJSFrameIterator.cpp', 'jit/AsmJSLink.cpp', 'jit/AsmJSModule.cpp', 'jit/AsmJSSignalHandlers.cpp', 'jit/BacktrackingAllocator.cpp', 'jit/Bailouts.cpp', 'jit/BaselineBailouts.cpp', 'jit/BaselineCompiler.cpp', 'jit/BaselineDebugModeOSR.cpp',
--- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -2953,17 +2953,17 @@ EvalInWorker(JSContext *cx, unsigned arg if (!args[0].toString()->ensureLinear(cx)) return false; JSLinearString *str = &args[0].toString()->asLinear(); jschar *chars = (jschar *) js_malloc(str->length() * sizeof(jschar)); if (!chars) return false; - PodCopy(chars, str->chars(), str->length()); + CopyChars(chars, *str); WorkerInput *input = js_new<WorkerInput>(cx->runtime(), chars, str->length()); if (!input) return false; PRThread *thread = PR_CreateThread(PR_USER_THREAD, WorkerMain, input, PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0); if (!thread || !workerThreads.append(thread)) @@ -4523,16 +4523,21 @@ static bool ToLatin1(JSContext *cx, unsigned argc, Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); if (!args.get(0).isString() || !args[0].toString()->isLinear()) { args.rval().setUndefined(); return true; } + if (args[0].toString()->hasLatin1Chars()) { + args.rval().set(args[0]); + return true; + } + JSLinearString *s = &args[0].toString()->asLinear(); s->debugUnsafeConvertToLatin1(); args.rval().setString(s); return true; } static const JSFunctionSpecWithHelp shell_functions[] = { JS_FN_HELP("version", Version, 0, 0, @@ -6306,16 +6311,17 @@ main(int argc, char **argv, char **envp) || !op.addBoolOption('\0', "no-fpu", "Pretend CPU does not support floating-point operations " "to test JIT codegen (no-op on platforms other than x86).") || !op.addBoolOption('\0', "no-sse3", "Pretend CPU does not support SSE3 instructions and above " "to test JIT codegen (no-op on platforms other than x86 and x64).") || !op.addBoolOption('\0', "no-sse4", "Pretend CPU does not support SSE4 instructions" "to test JIT codegen (no-op on platforms other than x86 and x64).") || !op.addBoolOption('\0', "fuzzing-safe", "Don't expose functions that aren't safe for " "fuzzers to call") + || !op.addBoolOption('\0', "latin1-strings", "Enable Latin1 strings (default: off)") #ifdef DEBUG || !op.addBoolOption('\0', "dump-entrained-variables", "Print variables which are " "unnecessarily entrained by inner functions") #endif #ifdef JSGC_GENERATIONAL || !op.addBoolOption('\0', "no-ggc", "Disable Generational GC") #endif || !op.addIntOption('\0', "available-memory", "SIZE", @@ -6378,16 +6384,21 @@ main(int argc, char **argv, char **envp) if (op.getBoolOption("no-sse4")) { JSC::MacroAssembler::SetSSE4Disabled(); PropagateFlagToNestedShells("--no-sse4"); } #endif #endif // DEBUG + // Set this option before initializing the JSRuntime, so that Latin1 strings + // are used for strings allocated during initialization. + if (op.getBoolOption("latin1-strings")) + js::EnableLatin1Strings = true; + #ifdef JS_THREADSAFE // The fake thread count must be set before initializing the Runtime, // which spins up the thread pool. int32_t threadCount = op.getIntOption("thread-count"); if (threadCount >= 0) SetFakeCPUCount(threadCount); #endif /* JS_THREADSAFE */
new file mode 100644 --- /dev/null +++ b/js/src/tests/js1_8_5/extensions/redeclaration-of-catch-warning.js @@ -0,0 +1,37 @@ +// |reftest| skip-if(!xulRuntime.shell) +// +// Any copyright is dedicated to the Public Domain. +// http://creativecommons.org/licenses/publicdomain/ + +//----------------------------------------------------------------------------- +var BUGNUMBER = 622646; +var summary = "Shadowing an exception identifier in a catch block with a " + + "|const| or |let| declaration should throw an error"; + +print(BUGNUMBER + ": " + summary); + +/************** + * BEGIN TEST * + **************/ + +options("strict"); + +function assertRedeclarationErrorThrown(expression) +{ + try + { + evaluate(expression); + throw new Error("Redeclaration error wasn't thrown"); + } + catch(e) + { + assertEq(e.message.indexOf("catch") > 0, true, + "wrong error, got " + e.message); + } +} + +assertRedeclarationErrorThrown("try {} catch(e) { const e; }"); +assertRedeclarationErrorThrown("try {} catch(e) { let e; }"); + +if (typeof reportCompare === "function") + reportCompare(true, true);
--- a/js/src/tests/lib/tests.py +++ b/js/src/tests/lib/tests.py @@ -9,17 +9,17 @@ from threading import Thread from results import TestOutput # When run on tbpl, we run each test multiple times with the following arguments. TBPL_FLAGS = [ [], # no flags, normal baseline and ion ['--ion-eager', '--ion-offthread-compile=off'], # implies --baseline-eager ['--ion-eager', '--ion-offthread-compile=off', '--ion-check-range-analysis', '--no-sse3'], - ['--baseline-eager'], + ['--baseline-eager', '--latin1-strings'], ['--baseline-eager', '--no-fpu'], ['--no-baseline', '--no-ion'], ] def do_run_cmd(cmd): l = [ None, None ] th_run_cmd(cmd, l) return l[1]
--- a/js/src/vm/OldDebugAPI.cpp +++ b/js/src/vm/OldDebugAPI.cpp @@ -1050,17 +1050,17 @@ FormatFrame(JSContext *cx, const NonBuil unsigned lineno = PCToLineNumber(script, pc); RootedFunction fun(cx, iter.maybeCallee()); RootedString funname(cx); if (fun) funname = fun->atom(); RootedValue thisVal(cx); AutoPropertyDescArray thisProps(cx); - if (iter.computeThis(cx)) { + if (iter.hasUsableAbstractFramePtr() && iter.computeThis(cx)) { thisVal = iter.computedThisValue(); if (showThisProps && thisVal.isObject()) { RootedObject thisObj(cx, &thisVal.toObject()); thisProps.fetch(thisObj); } } // print the frame number and function name
--- a/js/src/vm/Stack.cpp +++ b/js/src/vm/Stack.cpp @@ -581,17 +581,17 @@ FrameIter::settleOnActivation() } nextJitFrame(); data_.state_ = JIT; return; } if (activation->isAsmJS()) { - data_.asmJSFrames_ = AsmJSFrameIterator(data_.activations_->asAsmJS()); + data_.asmJSFrames_ = AsmJSFrameIterator(*data_.activations_->asAsmJS()); if (data_.asmJSFrames_.done()) { ++data_.activations_; continue; } data_.state_ = ASMJS; return; @@ -633,17 +633,17 @@ FrameIter::Data::Data(ThreadSafeContext contextOption_(contextOption), principals_(principals), pc_(nullptr), interpFrames_(nullptr), activations_(cx->perThreadData) #ifdef JS_ION , jitFrames_((uint8_t *)nullptr, SequentialExecution) , ionInlineFrameNo_(0) - , asmJSFrames_(nullptr) + , asmJSFrames_() #endif { } FrameIter::Data::Data(const FrameIter::Data &other) : cx_(other.cx_), savedOption_(other.savedOption_), contextOption_(other.contextOption_), @@ -1678,17 +1678,17 @@ jit::JitActivation::markRematerializedFr #endif // JS_ION AsmJSActivation::AsmJSActivation(JSContext *cx, AsmJSModule &module) : Activation(cx, AsmJS), module_(module), errorRejoinSP_(nullptr), profiler_(nullptr), resumePC_(nullptr), - exitSP_(nullptr) + exitFP_(nullptr) { if (cx->runtime()->spsProfiler.enabled()) { // Use a profiler string that matches jsMatch regex in // browser/devtools/profiler/cleopatra/js/parserWorker.js. // (For now use a single static string to avoid further slowing down // calls into asm.js.) profiler_ = &cx->runtime()->spsProfiler; profiler_->enterNative("asm.js code :0", this);
--- a/js/src/vm/Stack.h +++ b/js/src/vm/Stack.h @@ -7,17 +7,17 @@ #ifndef vm_Stack_h #define vm_Stack_h #include "mozilla/MemoryReporting.h" #include "jsfun.h" #include "jsscript.h" -#include "jit/AsmJSLink.h" +#include "jit/AsmJSFrameIterator.h" #include "jit/JitFrameIterator.h" #ifdef CHECK_OSIPOINT_REGISTERS #include "jit/Registers.h" // for RegisterDump #endif #include "js/OldDebugAPI.h" struct JSCompartment; struct JSGenerator; @@ -1506,44 +1506,44 @@ class InterpreterFrameIterator // all kinds of jit code. class AsmJSActivation : public Activation { AsmJSModule &module_; AsmJSActivation *prevAsmJS_; void *errorRejoinSP_; SPSProfiler *profiler_; void *resumePC_; - uint8_t *exitSP_; - - static const intptr_t InterruptedSP = -1; + uint8_t *exitFP_; public: AsmJSActivation(JSContext *cx, AsmJSModule &module); ~AsmJSActivation(); inline JSContext *cx(); AsmJSModule &module() const { return module_; } AsmJSActivation *prevAsmJS() const { return prevAsmJS_; } // Read by JIT code: static unsigned offsetOfContext() { return offsetof(AsmJSActivation, cx_); } static unsigned offsetOfResumePC() { return offsetof(AsmJSActivation, resumePC_); } // Initialized by JIT code: static unsigned offsetOfErrorRejoinSP() { return offsetof(AsmJSActivation, errorRejoinSP_); } - static unsigned offsetOfExitSP() { return offsetof(AsmJSActivation, exitSP_); } + static unsigned offsetOfExitFP() { return offsetof(AsmJSActivation, exitFP_); } // Set from SIGSEGV handler: - void setInterrupted(void *pc) { resumePC_ = pc; exitSP_ = (uint8_t*)InterruptedSP; } - bool isInterruptedSP() const { return exitSP_ == (uint8_t*)InterruptedSP; } + void setResumePC(void *pc) { resumePC_ = pc; } - // Note: exitSP is the sp right before the call instruction. On x86, this - // means before the return address is pushed on the stack, on ARM, this - // means after. - uint8_t *exitSP() const { JS_ASSERT(!isInterruptedSP()); return exitSP_; } + // If pc is in C++/Ion code, exitFP points to the innermost asm.js frame + // (the one that called into C++). While in asm.js code, exitFP is either + // null or points to the innermost asm.js frame. Thus, it is always valid to + // unwind a non-null exitFP. The only way C++ can observe a null exitFP is + // asychronous interruption of asm.js execution (viz., via the profiler, + // a signal handler, or the interrupt exit). + uint8_t *exitFP() const { return exitFP_; } }; // A FrameIter walks over the runtime's stack of JS script activations, // abstracting over whether the JS scripts were running in the interpreter or // different modes of compiled code. // // FrameIter is parameterized by what it includes in the stack iteration: // - The SavedOption controls whether FrameIter stops when it finds an
--- a/js/src/vm/String.cpp +++ b/js/src/vm/String.cpp @@ -860,16 +860,18 @@ AutoStableStringChars::initTwoByte(JSCon chars[s_->length()] = 0; state_ = TwoByte; ownsChars_ = true; twoByteChars_ = chars; return true; } +bool js::EnableLatin1Strings = false; + #ifdef DEBUG void JSAtom::dump() { fprintf(stderr, "JSAtom* (%p) = ", (void *) this); this->JSString::dump(); } #endif /* DEBUG */
--- a/js/src/vm/String.h +++ b/js/src/vm/String.h @@ -514,19 +514,16 @@ class JSString : public js::gc::Barriere } private: JSString() MOZ_DELETE; JSString(const JSString &other) MOZ_DELETE; void operator=(const JSString &other) MOZ_DELETE; }; -/* Temporary flag to enable Latin1 strings (bug 998392). */ -static const bool EnableLatin1Strings = false; - class JSRope : public JSString { template <typename CharT> bool copyCharsInternal(js::ThreadSafeContext *cx, js::ScopedJSFreePtr<CharT> &out, bool nullTerminate) const; enum UsingBarrier { WithIncrementalBarrier, NoBarrier }; @@ -997,16 +994,19 @@ class JSAtom : public JSFlatString void dump(); #endif }; JS_STATIC_ASSERT(sizeof(JSAtom) == sizeof(JSString)); namespace js { +/* Temporary flag to enable Latin1 strings (bug 998392). */ +extern bool EnableLatin1Strings; + /* * Thread safe RAII wrapper for inspecting the contents of JSStrings. The * thread safe operations such as |getCharsNonDestructive| require allocation * of a char array. This allocation is not always required, such as when the * string is already linear. This wrapper makes dealing with this detail more * convenient by encapsulating the allocation logic. * * As the name suggests, this class is scoped. Return values from chars() and
--- a/js/xpconnect/src/dom_quickstubs.qsconf +++ b/js/xpconnect/src/dom_quickstubs.qsconf @@ -36,19 +36,17 @@ members = [ 'nsIDOMStorage.setItem', 'nsIDOMStorage.length', 'nsIDOMStorage.getItem', 'nsIDOMStorage.key', 'nsIDOMStorage.removeItem', 'nsIDOMStorage.clear', # dom/interfaces/xpath - 'nsIDOMXPathExpression.evaluate', 'nsIDOMXPathNSResolver.lookupNamespaceURI', - 'nsIDOMNSXPathExpression.evaluateWithContext', # layout/xul/base/public 'nsIBoxObject.x', 'nsIBoxObject.y', 'nsIBoxObject.screenX', 'nsIBoxObject.screenY', 'nsIBoxObject.width', 'nsIBoxObject.height',
--- a/layout/base/SelectionCarets.cpp +++ b/layout/base/SelectionCarets.cpp @@ -377,17 +377,17 @@ SelectionCarets::UpdateSelectionCarets() if (range->Collapsed()) { SetVisibility(false); return; } nsLayoutUtils::FirstAndLastRectCollector collector; nsRange::CollectClientRects(&collector, range, range->GetStartParent(), range->StartOffset(), - range->GetEndParent(), range->EndOffset()); + range->GetEndParent(), range->EndOffset(), true); nsIFrame* canvasFrame = mPresShell->GetCanvasFrame(); nsIFrame* rootFrame = mPresShell->GetRootFrame(); if (!canvasFrame || !rootFrame) { SetVisibility(false); return; }
--- a/layout/generic/nsImageFrame.cpp +++ b/layout/generic/nsImageFrame.cpp @@ -211,17 +211,43 @@ nsImageFrame::DestroyFrom(nsIFrame* aDes // If we were displaying an icon, take ourselves off the list if (mDisplayingIcon) gIconLoad->RemoveIconObserver(this); nsSplittableFrame::DestroyFrom(aDestructRoot); } +void +nsImageFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext) +{ + ImageFrameSuper::DidSetStyleContext(aOldStyleContext); + if (!mImage) { + // We'll pick this change up whenever we do get an image. + return; + } + + nsStyleImageOrientation newOrientation = StyleVisibility()->mImageOrientation; + + // We need to update our orientation either if we had no style context before + // because this is the first time it's been set, or if the image-orientation + // property changed from its previous value. + bool shouldUpdateOrientation = + !aOldStyleContext || + aOldStyleContext->StyleVisibility()->mImageOrientation != newOrientation; + + if (shouldUpdateOrientation) { + nsCOMPtr<imgIContainer> image(mImage->Unwrap()); + mImage = nsLayoutUtils::OrientImage(image, newOrientation); + + UpdateIntrinsicSize(mImage); + UpdateIntrinsicRatio(mImage); + } +} void nsImageFrame::Init(nsIContent* aContent, nsContainerFrame* aParent, nsIFrame* aPrevInFlow) { nsSplittableFrame::Init(aContent, aParent, aPrevInFlow); @@ -599,26 +625,29 @@ nsImageFrame::OnDataAvailable(imgIReques return NS_OK; } if (IsPendingLoad(aRequest)) { // We don't care return NS_OK; } + nsIntRect rect = mImage ? mImage->GetImageSpaceInvalidationRect(*aRect) + : *aRect; + #ifdef DEBUG_decode printf("Source rect (%d,%d,%d,%d)\n", aRect->x, aRect->y, aRect->width, aRect->height); #endif - if (aRect->IsEqualInterior(nsIntRect::GetMaxSizedIntRect())) { + if (rect.IsEqualInterior(nsIntRect::GetMaxSizedIntRect())) { InvalidateFrame(nsDisplayItem::TYPE_IMAGE); InvalidateFrame(nsDisplayItem::TYPE_ALT_FEEDBACK); } else { - nsRect invalid = SourceRectToDest(*aRect); + nsRect invalid = SourceRectToDest(rect); InvalidateFrameWithRect(invalid, nsDisplayItem::TYPE_IMAGE); InvalidateFrameWithRect(invalid, nsDisplayItem::TYPE_ALT_FEEDBACK); } return NS_OK; } nsresult
--- a/layout/generic/nsImageFrame.h +++ b/layout/generic/nsImageFrame.h @@ -68,16 +68,18 @@ public: NS_DECL_FRAMEARENA_HELPERS nsImageFrame(nsStyleContext* aContext); NS_DECL_QUERYFRAME_TARGET(nsImageFrame) NS_DECL_QUERYFRAME virtual void DestroyFrom(nsIFrame* aDestructRoot) MOZ_OVERRIDE; + virtual void DidSetStyleContext(nsStyleContext* aOldStyleContext) MOZ_OVERRIDE; + virtual void Init(nsIContent* aContent, nsContainerFrame* aParent, nsIFrame* aPrevInFlow) MOZ_OVERRIDE; virtual void BuildDisplayList(nsDisplayListBuilder* aBuilder, const nsRect& aDirtyRect, const nsDisplayListSet& aLists) MOZ_OVERRIDE; virtual nscoord GetMinWidth(nsRenderingContext *aRenderingContext) MOZ_OVERRIDE; virtual nscoord GetPrefWidth(nsRenderingContext *aRenderingContext) MOZ_OVERRIDE;
new file mode 100644 --- /dev/null +++ b/layout/reftests/image/image-orientation-dynamic-ref.html @@ -0,0 +1,2 @@ +<!DOCTYPE html> +<img src="big.png" style="image-orientation: 90deg">
new file mode 100644 --- /dev/null +++ b/layout/reftests/image/image-orientation-dynamic.html @@ -0,0 +1,10 @@ +<!DOCTYPE html> +<html class="reftest-wait"> + <img src="big.png"> + <script> + document.addEventListener("MozReftestInvalidate", function() { + document.querySelector("img").style.imageOrientation = "90deg"; + document.documentElement.className = ""; + }); + </script> +</html>
--- a/layout/reftests/image/reftest.list +++ b/layout/reftests/image/reftest.list @@ -86,8 +86,9 @@ fuzzy(1,1) == image-orientation-backgrou != image-orientation-generated-content-ref.html?0 image-orientation-generated-content-ref.html?270 != image-orientation-generated-content-ref.html?90 image-orientation-generated-content-ref.html?180 != image-orientation-generated-content-ref.html?90 image-orientation-generated-content-ref.html?270 != image-orientation-generated-content-ref.html?180 image-orientation-generated-content-ref.html?270 != image-orientation-generated-content-ref.html?0 image-orientation-generated-content-ref.html?0&flip != image-orientation-generated-content-ref.html?90 image-orientation-generated-content-ref.html?90&flip != image-orientation-generated-content-ref.html?180 image-orientation-generated-content-ref.html?180&flip != image-orientation-generated-content-ref.html?270 image-orientation-generated-content-ref.html?270&flip +== image-orientation-dynamic.html image-orientation-dynamic-ref.html
--- a/layout/reftests/indic-shaping/reftest.list +++ b/layout/reftests/indic-shaping/reftest.list @@ -1,22 +1,22 @@ -skip-if(B2G) pref(gfx.font_rendering.harfbuzz.scripts,-1) HTTP(..) == devanagari-1a.html devanagari-1-ref.html -pref(gfx.font_rendering.harfbuzz.scripts,-1) HTTP(..) != devanagari-1b.html devanagari-1-ref.html -pref(gfx.font_rendering.harfbuzz.scripts,-1) HTTP(..) == devanagari-2.html devanagari-2-ref.html -pref(gfx.font_rendering.harfbuzz.scripts,-1) HTTP(..) != devanagari-3a.html devanagari-3-ref.html -pref(gfx.font_rendering.harfbuzz.scripts,-1) HTTP(..) == devanagari-3b.html devanagari-3-ref.html -pref(gfx.font_rendering.harfbuzz.scripts,-1) HTTP(..) != devanagari-4.html devanagari-4-notref.html +skip-if(B2G) HTTP(..) == devanagari-1a.html devanagari-1-ref.html +HTTP(..) != devanagari-1b.html devanagari-1-ref.html +HTTP(..) == devanagari-2.html devanagari-2-ref.html +HTTP(..) != devanagari-3a.html devanagari-3-ref.html +HTTP(..) == devanagari-3b.html devanagari-3-ref.html +HTTP(..) != devanagari-4.html devanagari-4-notref.html -pref(gfx.font_rendering.harfbuzz.scripts,-1) HTTP(..) == gujarati-1a.html gujarati-1-ref.html -pref(gfx.font_rendering.harfbuzz.scripts,-1) HTTP(..) != gujarati-1b.html gujarati-1-ref.html -pref(gfx.font_rendering.harfbuzz.scripts,-1) HTTP(..) == gujarati-2.html gujarati-2-ref.html -pref(gfx.font_rendering.harfbuzz.scripts,-1) HTTP(..) != gujarati-3a.html gujarati-3-ref.html -skip-if(B2G) pref(gfx.font_rendering.harfbuzz.scripts,-1) HTTP(..) == gujarati-3b.html gujarati-3-ref.html -pref(gfx.font_rendering.harfbuzz.scripts,-1) HTTP(..) != gujarati-4.html gujarati-4-notref.html +HTTP(..) == gujarati-1a.html gujarati-1-ref.html +HTTP(..) != gujarati-1b.html gujarati-1-ref.html +HTTP(..) == gujarati-2.html gujarati-2-ref.html +HTTP(..) != gujarati-3a.html gujarati-3-ref.html +skip-if(B2G) HTTP(..) == gujarati-3b.html gujarati-3-ref.html +HTTP(..) != gujarati-4.html gujarati-4-notref.html -skip-if(B2G) pref(gfx.font_rendering.harfbuzz.scripts,-1) HTTP(..) == bengali-1a.html bengali-1-ref.html -pref(gfx.font_rendering.harfbuzz.scripts,-1) HTTP(..) != bengali-1b.html bengali-1-ref.html -pref(gfx.font_rendering.harfbuzz.scripts,-1) HTTP(..) != bengali-2a.html bengali-2-ref.html -pref(gfx.font_rendering.harfbuzz.scripts,-1) HTTP(..) != bengali-2b.html bengali-2-ref.html -skip-if(B2G) pref(gfx.font_rendering.harfbuzz.scripts,-1) HTTP(..) == bengali-3a.html bengali-3-ref.html -pref(gfx.font_rendering.harfbuzz.scripts,-1) HTTP(..) != bengali-3b.html bengali-3-ref.html -pref(gfx.font_rendering.harfbuzz.scripts,-1) HTTP(..) != bengali-3c.html bengali-3-ref.html -pref(gfx.font_rendering.harfbuzz.scripts,-1) HTTP(..) != bengali-3c.html bengali-3b.html +skip-if(B2G) HTTP(..) == bengali-1a.html bengali-1-ref.html +HTTP(..) != bengali-1b.html bengali-1-ref.html +HTTP(..) != bengali-2a.html bengali-2-ref.html +HTTP(..) != bengali-2b.html bengali-2-ref.html +skip-if(B2G) HTTP(..) == bengali-3a.html bengali-3-ref.html +HTTP(..) != bengali-3b.html bengali-3-ref.html +HTTP(..) != bengali-3c.html bengali-3-ref.html +HTTP(..) != bengali-3c.html bengali-3b.html
--- a/layout/style/nsStyleStruct.cpp +++ b/layout/style/nsStyleStruct.cpp @@ -2649,16 +2649,17 @@ nsChangeHint nsStyleVisibility::CalcDiff { nsChangeHint hint = nsChangeHint(0); if (mDirection != aOther.mDirection || mWritingMode != aOther.mWritingMode) { NS_UpdateHint(hint, nsChangeHint_ReconstructFrame); } else { if ((mImageOrientation != aOther.mImageOrientation)) { NS_UpdateHint(hint, nsChangeHint_AllReflowHints); + NS_UpdateHint(hint, nsChangeHint_RepaintFrame); } if (mVisible != aOther.mVisible) { if ((NS_STYLE_VISIBILITY_COLLAPSE == mVisible) || (NS_STYLE_VISIBILITY_COLLAPSE == aOther.mVisible)) { NS_UpdateHint(hint, NS_STYLE_HINT_REFLOW); } else { NS_UpdateHint(hint, NS_STYLE_HINT_VISUAL); }
--- a/layout/tools/reftest/remotereftest.py +++ b/layout/tools/reftest/remotereftest.py @@ -66,20 +66,16 @@ class RemoteOptions(ReftestOptions): help = "Port for https traffic to the web server") defaults["sslPort"] = automation.DEFAULT_SSL_PORT self.add_option("--remote-logfile", action="store", type = "string", dest = "remoteLogFile", help = "Name of log file on the device relative to device root. PLEASE USE ONLY A FILENAME.") defaults["remoteLogFile"] = None - self.add_option("--enable-privilege", action="store_true", dest = "enablePrivilege", - help = "add webserver and port to the user.js file for remote script access and universalXPConnect") - defaults["enablePrivilege"] = False - self.add_option("--pidfile", action = "store", type = "string", dest = "pidFile", help = "name of the pidfile to generate") defaults["pidFile"] = "" self.add_option("--bootstrap", action="store_true", dest = "bootstrap", help = "test with a bootstrap addon required for native Fennec") defaults["bootstrap"] = False
--- a/media/webrtc/signaling/src/media-conduit/WebrtcOMXH264VideoCodec.cpp +++ b/media/webrtc/signaling/src/media-conduit/WebrtcOMXH264VideoCodec.cpp @@ -278,17 +278,21 @@ public: mWidth = aWidth; mHeight = aHeight; sp<Surface> surface = nullptr; mNativeWindow = new GonkNativeWindow(); if (mNativeWindow.get()) { // listen to buffers queued by MediaCodec::RenderOutputBufferAndRelease(). mNativeWindow->setNewFrameCallback(this); - surface = new Surface(mNativeWindow->getBufferQueue()); + // XXX remove buffer changes after a better solution lands - bug 1009420 + sp<GonkBufferQueue> bq = mNativeWindow->getBufferQueue(); + // More spare buffers to avoid OMX decoder waiting for native window + bq->setMaxAcquiredBufferCount(WEBRTC_OMX_H264_MIN_DECODE_BUFFERS); + surface = new Surface(bq); } status_t result = mCodec->configure(config, surface, nullptr, 0); if (result == OK) { CODEC_LOGD("OMX:%p decoder configured", this); result = Start(); } return result; }
--- a/media/webrtc/signaling/src/media-conduit/WebrtcOMXH264VideoCodec.h +++ b/media/webrtc/signaling/src/media-conduit/WebrtcOMXH264VideoCodec.h @@ -19,16 +19,19 @@ namespace android { class OMXVideoEncoder; } namespace mozilla { class WebrtcOMXDecoder; class OMXOutputDrain; +// XXX see if we can reduce this +#define WEBRTC_OMX_H264_MIN_DECODE_BUFFERS 10 + class WebrtcOMXH264VideoEncoder : public WebrtcVideoEncoder { public: WebrtcOMXH264VideoEncoder(); virtual ~WebrtcOMXH264VideoEncoder(); // Implement VideoEncoder interface.
--- a/mfbt/ArrayUtils.h +++ b/mfbt/ArrayUtils.h @@ -13,17 +13,19 @@ #include "mozilla/Assertions.h" #include "mozilla/Attributes.h" #include <stddef.h> #ifdef __cplusplus +#include "mozilla/Alignment.h" #include "mozilla/Array.h" +#include "mozilla/TypeTraits.h" namespace mozilla { /* * Safely subtract two pointers when it is known that aEnd >= aBegin. This * avoids the common compiler bug that if (size_t(aEnd) - size_t(aBegin)) has * the MSB set, the unsigned subtraction followed by right shift will produce * -1, or size_t(-1), instead of the real difference. @@ -79,16 +81,79 @@ template<typename T, size_t N> MOZ_CONSTEXPR const T* ArrayEnd(const Array<T, N>& aArr) { return &aArr[0] + ArrayLength(aArr); } namespace detail { +template<typename AlignType, typename Pointee> +struct AlignedChecker +{ + static void + test(Pointee* aPtr) + { + MOZ_ASSERT((uintptr_t(aPtr) % MOZ_ALIGNOF(AlignType)) == 0, + "performing a range-check with a misaligned pointer"); + } +}; + +template<typename Pointee> +struct AlignedChecker<void, Pointee> +{ + static void + test(Pointee* aPtr) + { + } +}; + +} // namespace detail + +/** + * Determines whether |aPtr| points at an object in the range [aBegin, aEnd). + * + * |aPtr| must have the same alignment as |aBegin| and |aEnd|. This usually + * should be achieved by ensuring |aPtr| points at a |U|, not just that it + * points at a |T|. + * + * It is a usage error for any argument to be misaligned. + * + * It's okay for T* to be void*, and if so U* may also be void*. In the latter + * case no argument is required to be aligned (obviously, as void* implies no + * particular alignment). + */ +template<typename T, typename U> +inline typename EnableIf<IsSame<T, U>::value || + IsBaseOf<T, U>::value || + IsVoid<T>::value, + bool>::Type +IsInRange(T* aPtr, U* aBegin, U* aEnd) +{ + MOZ_ASSERT(aBegin <= aEnd); + detail::AlignedChecker<U, T>::test(aPtr); + detail::AlignedChecker<U, U>::test(aBegin); + detail::AlignedChecker<U, U>::test(aEnd); + return aBegin <= static_cast<U*>(aPtr) && static_cast<U*>(aPtr) < aEnd; +} + +/** + * Convenience version of the above method when the valid range is specified as + * uintptr_t values. As above, |aPtr| must be aligned, and |aBegin| and |aEnd| + * must be aligned with respect to |T|. + */ +template<typename T> +inline bool +IsInRange(T* aPtr, uintptr_t aBegin, uintptr_t aEnd) +{ + return IsInRange(aPtr, reinterpret_cast<T*>(aBegin), reinterpret_cast<T*>(aEnd)); +} + +namespace detail { + /* * Helper for the MOZ_ARRAY_LENGTH() macro to make the length a typesafe * compile-time constant even on compilers lacking constexpr support. */ template <typename T, size_t N> char (&ArrayLengthHelper(T (&array)[N]))[N]; } /* namespace detail */
--- a/mfbt/BinarySearch.h +++ b/mfbt/BinarySearch.h @@ -36,17 +36,20 @@ BinarySearch(const Container& aContainer T aTarget, size_t* aMatchOrInsertionPoint) { MOZ_ASSERT(aBegin <= aEnd); size_t low = aBegin; size_t high = aEnd; while (low != high) { size_t middle = low + (high - low) / 2; - const T& middleValue = aContainer[middle]; + + // Allow any intermediate type so long as it provides a suitable ordering + // relation. + const auto& middleValue = aContainer[middle]; MOZ_ASSERT(aContainer[low] <= aContainer[middle]); MOZ_ASSERT(aContainer[middle] <= aContainer[high - 1]); MOZ_ASSERT(aContainer[low] <= aContainer[high - 1]); if (aTarget == middleValue) { *aMatchOrInsertionPoint = middle; return true;
new file mode 100644 --- /dev/null +++ b/mfbt/Pair.h @@ -0,0 +1,182 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=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/. */ + +/* A class holding a pair of objects that tries to conserve storage space. */ + +#ifndef mozilla_Pair_h +#define mozilla_Pair_h + +#include "mozilla/Attributes.h" +#include "mozilla/Move.h" +#include "mozilla/TypeTraits.h" + +namespace mozilla { + +namespace detail { + +enum StorageType { AsBase, AsMember }; + +// Optimize storage using the Empty Base Optimization -- that empty base classes +// don't take up space -- to optimize size when one or the other class is +// stateless and can be used as a base class. +// +// The extra conditions on storage for B are necessary so that PairHelper won't +// ambiguously inherit from either A or B, such that one or the other base class +// would be inaccessible. +template<typename A, typename B, + detail::StorageType = + IsEmpty<A>::value ? detail::AsBase : detail::AsMember, + detail::StorageType = + IsEmpty<B>::value && !IsBaseOf<A, B>::value && !IsBaseOf<B, A>::value + ? detail::AsBase + : detail::AsMember> +struct PairHelper; + +template<typename A, typename B> +struct PairHelper<A, B, AsMember, AsMember> +{ + protected: + template<typename AArg, typename BArg> + PairHelper(AArg&& a, BArg&& b) + : firstA(Forward<AArg>(a)), + secondB(Forward<BArg>(b)) + {} + + A& first() { return firstA; } + const A& first() const { return firstA; } + B& second() { return secondB; } + const B& second() const { return secondB; } + + void swap(PairHelper& other) { + Swap(firstA, other.firstA); + Swap(secondB, other.secondB); + } + + private: + A firstA; + B secondB; +}; + +template<typename A, typename B> +struct PairHelper<A, B, AsMember, AsBase> : private B +{ + protected: + template<typename AArg, typename BArg> + PairHelper(AArg&& a, BArg&& b) + : B(Forward<BArg>(b)), + firstA(Forward<AArg>(a)) + {} + + A& first() { return firstA; } + const A& first() const { return firstA; } + B& second() { return *this; } + const B& second() const { return *this; } + + void swap(PairHelper& other) { + Swap(firstA, other.firstA); + Swap(static_cast<B&>(*this), static_cast<B&>(other)); + } + + private: + A firstA; +}; + +template<typename A, typename B> +struct PairHelper<A, B, AsBase, AsMember> : private A +{ + protected: + template<typename AArg, typename BArg> + PairHelper(AArg&& a, BArg&& b) + : A(Forward<AArg>(a)), + secondB(Forward<BArg>(b)) + {} + + A& first() { return *this; } + const A& first() const { return *this; } + B& second() { return secondB; } + const B& second() const { return secondB; } + + void swap(PairHelper& other) { + Swap(static_cast<A&>(*this), static_cast<A&>(other)); + Swap(secondB, other.secondB); + } + + private: + B secondB; +}; + +template<typename A, typename B> +struct PairHelper<A, B, AsBase, AsBase> : private A, private B +{ + protected: + template<typename AArg, typename BArg> + PairHelper(AArg&& a, BArg&& b) + : A(Forward<AArg>(a)), + B(Forward<BArg>(b)) + {} + + A& first() { return static_cast<A&>(*this); } + const A& first() const { return static_cast<A&>(*this); } + B& second() { return static_cast<B&>(*this); } + const B& second() const { return static_cast<B&>(*this); } + + void swap(PairHelper& other) { + Swap(static_cast<A&>(*this), static_cast<A&>(other)); + Swap(static_cast<B&>(*this), static_cast<B&>(other)); + } +}; + +} // namespace detail + +/** + * Pair is the logical concatenation of an instance of A with an instance B. + * Space is conserved when possible. Neither A nor B may be a final class. + * + * It's typically clearer to have individual A and B member fields. Except if + * you want the space-conserving qualities of Pair, you're probably better off + * not using this! + * + * No guarantees are provided about the memory layout of A and B, the order of + * initialization or destruction of A and B, and so on. (This is approximately + * required to optimize space usage.) The first/second names are merely + * conceptual! + */ +template<typename A, typename B> +struct Pair + : private detail::PairHelper<A, B> +{ + typedef typename detail::PairHelper<A, B> Base; + + public: + template<typename AArg, typename BArg> + Pair(AArg&& a, BArg&& b) + : Base(Forward<AArg>(a), Forward<BArg>(b)) + {} + + /** The A instance. */ + using Base::first; + /** The B instance. */ + using Base::second; + + /** Swap this pair with another pair. */ + void swap(Pair& other) { + Base::swap(other); + } + + private: + Pair(const Pair&) MOZ_DELETE; +}; + +template<typename A, class B> +void +Swap(Pair<A, B>& x, Pair<A, B>& y) +{ + x.swap(y); +} + +} // namespace mozilla + +#endif /* mozilla_Pair_h */
--- a/mfbt/TypeTraits.h +++ b/mfbt/TypeTraits.h @@ -412,69 +412,76 @@ template<typename T> struct IsEmpty : detail::IsEmptyHelper<typename RemoveCV<T>::Type> {}; namespace detail { template<typename T, bool = IsFloatingPoint<T>::value, + bool = IsIntegral<T>::value, typename NoCV = typename RemoveCV<T>::Type> struct IsSignedHelper; +// Floating point is signed. template<typename T, typename NoCV> -struct IsSignedHelper<T, true, NoCV> : TrueType {}; +struct IsSignedHelper<T, true, false, NoCV> : TrueType {}; +// Integral is conditionally signed. template<typename T, typename NoCV> -struct IsSignedHelper<T, false, NoCV> - : IntegralConstant<bool, IsArithmetic<T>::value && NoCV(-1) < NoCV(1)> +struct IsSignedHelper<T, false, true, NoCV> + : IntegralConstant<bool, bool(NoCV(-1) < NoCV(1))> {}; +// Non-floating point, non-integral is not signed. +template<typename T, typename NoCV> +struct IsSignedHelper<T, false, false, NoCV> : FalseType {}; + } // namespace detail /** * IsSigned determines whether a type is a signed arithmetic type. |char| is * considered a signed type if it has the same representation as |signed char|. * - * Don't use this if the type might be user-defined! You might or might not get - * a compile error, depending. - * * mozilla::IsSigned<int>::value is true; * mozilla::IsSigned<const unsigned int>::value is false; * mozilla::IsSigned<unsigned char>::value is false; * mozilla::IsSigned<float>::value is true. */ template<typename T> struct IsSigned : detail::IsSignedHelper<T> {}; namespace detail { template<typename T, bool = IsFloatingPoint<T>::value, + bool = IsIntegral<T>::value, typename NoCV = typename RemoveCV<T>::Type> struct IsUnsignedHelper; +// Floating point is not unsigned. template<typename T, typename NoCV> -struct IsUnsignedHelper<T, true, NoCV> : FalseType {}; +struct IsUnsignedHelper<T, true, false, NoCV> : FalseType {}; +// Integral is conditionally unsigned. template<typename T, typename NoCV> -struct IsUnsignedHelper<T, false, NoCV> +struct IsUnsignedHelper<T, false, true, NoCV> : IntegralConstant<bool, - IsArithmetic<T>::value && - (IsSame<NoCV, bool>::value || NoCV(1) < NoCV(-1))> + (IsSame<NoCV, bool>::value || bool(NoCV(1) < NoCV(-1)))> {}; +// Non-floating point, non-integral is not unsigned. +template<typename T, typename NoCV> +struct IsUnsignedHelper<T, false, false, NoCV> : FalseType {}; + } // namespace detail /** * IsUnsigned determines whether a type is an unsigned arithmetic type. * - * Don't use this if the type might be user-defined! You might or might not get - * a compile error, depending. - * * mozilla::IsUnsigned<int>::value is false; * mozilla::IsUnsigned<const unsigned int>::value is true; * mozilla::IsUnsigned<unsigned char>::value is true; * mozilla::IsUnsigned<float>::value is false. */ template<typename T> struct IsUnsigned : detail::IsUnsignedHelper<T> {};
--- a/mfbt/moz.build +++ b/mfbt/moz.build @@ -43,16 +43,17 @@ EXPORTS.mozilla = [ 'Maybe.h', 'MaybeOneOf.h', 'MemoryChecking.h', 'MemoryReporting.h', 'Move.h', 'MSIntTypes.h', 'NullPtr.h', 'NumericLimits.h', + 'Pair.h', 'PodOperations.h', 'Poison.h', 'Range.h', 'RangedPtr.h', 'RefCountType.h', 'ReentrancyGuard.h', 'RefPtr.h', 'RollingMean.h',
new file mode 100644 --- /dev/null +++ b/mfbt/tests/TestArrayUtils.cpp @@ -0,0 +1,307 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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 "mozilla/ArrayUtils.h" +#include "mozilla/Assertions.h" +#include "mozilla/NullPtr.h" + +using mozilla::IsInRange; + +static void +TestIsInRangeNonClass() +{ + void* nul = nullptr; + int* intBegin = nullptr; + int* intEnd = intBegin + 1; + int* intEnd2 = intBegin + 2; + + MOZ_RELEASE_ASSERT(IsInRange(nul, intBegin, intEnd)); + MOZ_RELEASE_ASSERT(!IsInRange(nul, intEnd, intEnd2)); + + MOZ_RELEASE_ASSERT(IsInRange(intBegin, intBegin, intEnd)); + MOZ_RELEASE_ASSERT(!IsInRange(intEnd, intBegin, intEnd)); + + MOZ_RELEASE_ASSERT(IsInRange(intBegin, intBegin, intEnd2)); + MOZ_RELEASE_ASSERT(IsInRange(intEnd, intBegin, intEnd2)); + MOZ_RELEASE_ASSERT(!IsInRange(intEnd2, intBegin, intEnd2)); + + uintptr_t uintBegin = uintptr_t(intBegin); + uintptr_t uintEnd = uintptr_t(intEnd); + uintptr_t uintEnd2 = uintptr_t(intEnd2); + + MOZ_RELEASE_ASSERT(IsInRange(nul, uintBegin, uintEnd)); + MOZ_RELEASE_ASSERT(!IsInRange(nul, uintEnd, uintEnd2)); + + MOZ_RELEASE_ASSERT(IsInRange(intBegin, uintBegin, uintEnd)); + MOZ_RELEASE_ASSERT(!IsInRange(intEnd, uintBegin, uintEnd)); + + MOZ_RELEASE_ASSERT(IsInRange(intBegin, uintBegin, uintEnd2)); + MOZ_RELEASE_ASSERT(IsInRange(intEnd, uintBegin, uintEnd2)); + MOZ_RELEASE_ASSERT(!IsInRange(intEnd2, uintBegin, uintEnd2)); +} + +static void +TestIsInRangeVoid() +{ + int* intBegin = nullptr; + int* intEnd = intBegin + 1; + int* intEnd2 = intBegin + 2; + + void* voidBegin = intBegin; + void* voidEnd = intEnd; + void* voidEnd2 = intEnd2; + + MOZ_RELEASE_ASSERT(IsInRange(voidBegin, intBegin, intEnd)); + MOZ_RELEASE_ASSERT(!IsInRange(voidEnd, intBegin, intEnd)); + + MOZ_RELEASE_ASSERT(IsInRange(voidBegin, voidBegin, voidEnd)); + MOZ_RELEASE_ASSERT(!IsInRange(voidEnd, voidBegin, voidEnd)); + + MOZ_RELEASE_ASSERT(IsInRange(voidBegin, intBegin, intEnd2)); + MOZ_RELEASE_ASSERT(IsInRange(voidEnd, intBegin, intEnd2)); + MOZ_RELEASE_ASSERT(!IsInRange(voidEnd2, intBegin, intEnd2)); + + MOZ_RELEASE_ASSERT(IsInRange(voidBegin, voidBegin, voidEnd2)); + MOZ_RELEASE_ASSERT(IsInRange(voidEnd, voidBegin, voidEnd2)); + MOZ_RELEASE_ASSERT(!IsInRange(voidEnd2, voidBegin, voidEnd2)); + + uintptr_t uintBegin = uintptr_t(intBegin); + uintptr_t uintEnd = uintptr_t(intEnd); + uintptr_t uintEnd2 = uintptr_t(intEnd2); + + MOZ_RELEASE_ASSERT(IsInRange(voidBegin, uintBegin, uintEnd)); + MOZ_RELEASE_ASSERT(!IsInRange(voidEnd, uintBegin, uintEnd)); + + MOZ_RELEASE_ASSERT(IsInRange(voidBegin, uintBegin, uintEnd2)); + MOZ_RELEASE_ASSERT(IsInRange(voidEnd, uintBegin, uintEnd2)); + MOZ_RELEASE_ASSERT(!IsInRange(voidEnd2, uintBegin, uintEnd2)); +} + +struct Base { int x; }; + +static void +TestIsInRangeClass() +{ + void* nul = nullptr; + Base* baseBegin = nullptr; + Base* baseEnd = baseBegin + 1; + Base* baseEnd2 = baseBegin + 2; + + MOZ_RELEASE_ASSERT(IsInRange(nul, baseBegin, baseEnd)); + MOZ_RELEASE_ASSERT(!IsInRange(nul, baseEnd, baseEnd2)); + + MOZ_RELEASE_ASSERT(IsInRange(baseBegin, baseBegin, baseEnd)); + MOZ_RELEASE_ASSERT(!IsInRange(baseEnd, baseBegin, baseEnd)); + + MOZ_RELEASE_ASSERT(IsInRange(baseBegin, baseBegin, baseEnd2)); + MOZ_RELEASE_ASSERT(IsInRange(baseEnd, baseBegin, baseEnd2)); + MOZ_RELEASE_ASSERT(!IsInRange(baseEnd2, baseBegin, baseEnd2)); + + uintptr_t ubaseBegin = uintptr_t(baseBegin); + uintptr_t ubaseEnd = uintptr_t(baseEnd); + uintptr_t ubaseEnd2 = uintptr_t(baseEnd2); + + MOZ_RELEASE_ASSERT(IsInRange(nul, ubaseBegin, ubaseEnd)); + MOZ_RELEASE_ASSERT(!IsInRange(nul, ubaseEnd, ubaseEnd2)); + + MOZ_RELEASE_ASSERT(IsInRange(baseBegin, ubaseBegin, ubaseEnd)); + MOZ_RELEASE_ASSERT(!IsInRange(baseEnd, ubaseBegin, ubaseEnd)); + + MOZ_RELEASE_ASSERT(IsInRange(baseBegin, ubaseBegin, ubaseEnd2)); + MOZ_RELEASE_ASSERT(IsInRange(baseEnd, ubaseBegin, ubaseEnd2)); + MOZ_RELEASE_ASSERT(!IsInRange(baseEnd2, ubaseBegin, ubaseEnd2)); +} + +struct EmptyBase {}; + +static void +TestIsInRangeEmptyClass() +{ + void* nul = nullptr; + EmptyBase* baseBegin = nullptr; + EmptyBase* baseEnd = baseBegin + 1; + EmptyBase* baseEnd2 = baseBegin + 2; + + MOZ_RELEASE_ASSERT(IsInRange(nul, baseBegin, baseEnd)); + MOZ_RELEASE_ASSERT(!IsInRange(nul, baseEnd, baseEnd2)); + + MOZ_RELEASE_ASSERT(IsInRange(baseBegin, baseBegin, baseEnd)); + MOZ_RELEASE_ASSERT(!IsInRange(baseEnd, baseBegin, baseEnd)); + + MOZ_RELEASE_ASSERT(IsInRange(baseBegin, baseBegin, baseEnd2)); + MOZ_RELEASE_ASSERT(IsInRange(baseEnd, baseBegin, baseEnd2)); + MOZ_RELEASE_ASSERT(!IsInRange(baseEnd2, baseBegin, baseEnd2)); + + uintptr_t ubaseBegin = uintptr_t(baseBegin); + uintptr_t ubaseEnd = uintptr_t(baseEnd); + uintptr_t ubaseEnd2 = uintptr_t(baseEnd2); + + MOZ_RELEASE_ASSERT(IsInRange(nul, ubaseBegin, ubaseEnd)); + MOZ_RELEASE_ASSERT(!IsInRange(nul, ubaseEnd, ubaseEnd2)); + + MOZ_RELEASE_ASSERT(IsInRange(baseBegin, ubaseBegin, ubaseEnd)); + MOZ_RELEASE_ASSERT(!IsInRange(baseEnd, ubaseBegin, ubaseEnd)); + + MOZ_RELEASE_ASSERT(IsInRange(baseBegin, ubaseBegin, ubaseEnd2)); + MOZ_RELEASE_ASSERT(IsInRange(baseEnd, ubaseBegin, ubaseEnd2)); + MOZ_RELEASE_ASSERT(!IsInRange(baseEnd2, ubaseBegin, ubaseEnd2)); +} + +struct Derived : Base {}; + +static void +TestIsInRangeClassDerived() +{ + void* nul = nullptr; + Derived* derivedBegin = nullptr; + Derived* derivedEnd = derivedBegin + 1; + Derived* derivedEnd2 = derivedBegin + 2; + + Base* baseBegin = static_cast<Base*>(derivedBegin); + Base* baseEnd = static_cast<Base*>(derivedEnd); + Base* baseEnd2 = static_cast<Base*>(derivedEnd2); + + MOZ_RELEASE_ASSERT(IsInRange(nul, derivedBegin, derivedEnd)); + MOZ_RELEASE_ASSERT(!IsInRange(nul, derivedEnd, derivedEnd2)); + + MOZ_RELEASE_ASSERT(IsInRange(baseBegin, derivedBegin, derivedEnd)); + MOZ_RELEASE_ASSERT(!IsInRange(baseEnd, derivedBegin, derivedEnd)); + + MOZ_RELEASE_ASSERT(IsInRange(baseBegin, derivedBegin, derivedEnd2)); + MOZ_RELEASE_ASSERT(IsInRange(baseEnd, derivedBegin, derivedEnd2)); + MOZ_RELEASE_ASSERT(!IsInRange(baseEnd2, derivedBegin, derivedEnd2)); + + uintptr_t uderivedBegin = uintptr_t(derivedBegin); + uintptr_t uderivedEnd = uintptr_t(derivedEnd); + uintptr_t uderivedEnd2 = uintptr_t(derivedEnd2); + + MOZ_RELEASE_ASSERT(IsInRange(derivedBegin, uderivedBegin, uderivedEnd)); + MOZ_RELEASE_ASSERT(!IsInRange(derivedEnd, uderivedBegin, uderivedEnd)); + + MOZ_RELEASE_ASSERT(IsInRange(derivedBegin, uderivedBegin, uderivedEnd2)); + MOZ_RELEASE_ASSERT(IsInRange(derivedEnd, uderivedBegin, uderivedEnd2)); + MOZ_RELEASE_ASSERT(!IsInRange(derivedEnd2, uderivedBegin, uderivedEnd2)); +} + +struct DerivedEmpty : EmptyBase {}; + +static void +TestIsInRangeClassDerivedEmpty() +{ + void* nul = nullptr; + DerivedEmpty* derivedEmptyBegin = nullptr; + DerivedEmpty* derivedEmptyEnd = derivedEmptyBegin + 1; + DerivedEmpty* derivedEmptyEnd2 = derivedEmptyBegin + 2; + + EmptyBase* baseBegin = static_cast<EmptyBase*>(derivedEmptyBegin); + EmptyBase* baseEnd = static_cast<EmptyBase*>(derivedEmptyEnd); + EmptyBase* baseEnd2 = static_cast<EmptyBase*>(derivedEmptyEnd2); + + MOZ_RELEASE_ASSERT(IsInRange(nul, derivedEmptyBegin, derivedEmptyEnd)); + MOZ_RELEASE_ASSERT(!IsInRange(nul, derivedEmptyEnd, derivedEmptyEnd2)); + + MOZ_RELEASE_ASSERT(IsInRange(baseBegin, derivedEmptyBegin, derivedEmptyEnd)); + MOZ_RELEASE_ASSERT(!IsInRange(baseEnd, derivedEmptyBegin, derivedEmptyEnd)); + + MOZ_RELEASE_ASSERT(IsInRange(baseBegin, derivedEmptyBegin, derivedEmptyEnd2)); + MOZ_RELEASE_ASSERT(IsInRange(baseEnd, derivedEmptyBegin, derivedEmptyEnd2)); + MOZ_RELEASE_ASSERT(!IsInRange(baseEnd2, derivedEmptyBegin, derivedEmptyEnd2)); + + uintptr_t uderivedEmptyBegin = uintptr_t(derivedEmptyBegin); + uintptr_t uderivedEmptyEnd = uintptr_t(derivedEmptyEnd); + uintptr_t uderivedEmptyEnd2 = uintptr_t(derivedEmptyEnd2); + + MOZ_RELEASE_ASSERT(IsInRange(derivedEmptyBegin, uderivedEmptyBegin, uderivedEmptyEnd)); + MOZ_RELEASE_ASSERT(!IsInRange(derivedEmptyEnd, uderivedEmptyBegin, uderivedEmptyEnd)); + + MOZ_RELEASE_ASSERT(IsInRange(derivedEmptyBegin, uderivedEmptyBegin, uderivedEmptyEnd2)); + MOZ_RELEASE_ASSERT(IsInRange(derivedEmptyEnd, uderivedEmptyBegin, uderivedEmptyEnd2)); + MOZ_RELEASE_ASSERT(!IsInRange(derivedEmptyEnd2, uderivedEmptyBegin, uderivedEmptyEnd2)); +} + +struct ExtraDerived : Base { int y; }; + +static void +TestIsInRangeClassExtraDerived() +{ + void* nul = nullptr; + ExtraDerived* derivedBegin = nullptr; + ExtraDerived* derivedEnd = derivedBegin + 1; + ExtraDerived* derivedEnd2 = derivedBegin + 2; + + Base* baseBegin = static_cast<Base*>(derivedBegin); + Base* baseEnd = static_cast<Base*>(derivedEnd); + Base* baseEnd2 = static_cast<Base*>(derivedEnd2); + + MOZ_RELEASE_ASSERT(IsInRange(nul, derivedBegin, derivedEnd)); + MOZ_RELEASE_ASSERT(!IsInRange(nul, derivedEnd, derivedEnd2)); + + MOZ_RELEASE_ASSERT(IsInRange(baseBegin, derivedBegin, derivedEnd)); + MOZ_RELEASE_ASSERT(!IsInRange(baseEnd, derivedBegin, derivedEnd)); + + MOZ_RELEASE_ASSERT(IsInRange(baseBegin, derivedBegin, derivedEnd2)); + MOZ_RELEASE_ASSERT(IsInRange(baseEnd, derivedBegin, derivedEnd2)); + MOZ_RELEASE_ASSERT(!IsInRange(baseEnd2, derivedBegin, derivedEnd2)); + + uintptr_t uderivedBegin = uintptr_t(derivedBegin); + uintptr_t uderivedEnd = uintptr_t(derivedEnd); + uintptr_t uderivedEnd2 = uintptr_t(derivedEnd2); + + MOZ_RELEASE_ASSERT(IsInRange(derivedBegin, uderivedBegin, uderivedEnd)); + MOZ_RELEASE_ASSERT(!IsInRange(derivedEnd, uderivedBegin, uderivedEnd)); + + MOZ_RELEASE_ASSERT(IsInRange(derivedBegin, uderivedBegin, uderivedEnd2)); + MOZ_RELEASE_ASSERT(IsInRange(derivedEnd, uderivedBegin, uderivedEnd2)); + MOZ_RELEASE_ASSERT(!IsInRange(derivedEnd2, uderivedBegin, uderivedEnd2)); +} + +struct ExtraDerivedEmpty : EmptyBase { int y; }; + +static void +TestIsInRangeClassExtraDerivedEmpty() +{ + void* nul = nullptr; + ExtraDerivedEmpty* derivedBegin = nullptr; + ExtraDerivedEmpty* derivedEnd = derivedBegin + 1; + ExtraDerivedEmpty* derivedEnd2 = derivedBegin + 2; + + EmptyBase* baseBegin = static_cast<EmptyBase*>(derivedBegin); + EmptyBase* baseEnd = static_cast<EmptyBase*>(derivedEnd); + EmptyBase* baseEnd2 = static_cast<EmptyBase*>(derivedEnd2); + + MOZ_RELEASE_ASSERT(IsInRange(nul, derivedBegin, derivedEnd)); + MOZ_RELEASE_ASSERT(!IsInRange(nul, derivedEnd, derivedEnd2)); + + MOZ_RELEASE_ASSERT(IsInRange(baseBegin, derivedBegin, derivedEnd)); + MOZ_RELEASE_ASSERT(!IsInRange(baseEnd, derivedBegin, derivedEnd)); + + MOZ_RELEASE_ASSERT(IsInRange(baseBegin, derivedBegin, derivedEnd2)); + MOZ_RELEASE_ASSERT(IsInRange(baseEnd, derivedBegin, derivedEnd2)); + MOZ_RELEASE_ASSERT(!IsInRange(baseEnd2, derivedBegin, derivedEnd2)); + + uintptr_t uderivedBegin = uintptr_t(derivedBegin); + uintptr_t uderivedEnd = uintptr_t(derivedEnd); + uintptr_t uderivedEnd2 = uintptr_t(derivedEnd2); + + MOZ_RELEASE_ASSERT(IsInRange(derivedBegin, uderivedBegin, uderivedEnd)); + MOZ_RELEASE_ASSERT(!IsInRange(derivedEnd, uderivedBegin, uderivedEnd)); + + MOZ_RELEASE_ASSERT(IsInRange(derivedBegin, uderivedBegin, uderivedEnd2)); + MOZ_RELEASE_ASSERT(IsInRange(derivedEnd, uderivedBegin, uderivedEnd2)); + MOZ_RELEASE_ASSERT(!IsInRange(derivedEnd2, uderivedBegin, uderivedEnd2)); +} + +int main() +{ + TestIsInRangeNonClass(); + TestIsInRangeVoid(); + TestIsInRangeClass(); + TestIsInRangeEmptyClass(); + TestIsInRangeClassDerived(); + TestIsInRangeClassDerivedEmpty(); + TestIsInRangeClassExtraDerived(); + TestIsInRangeClassExtraDerivedEmpty(); + return 0; +}
new file mode 100644 --- /dev/null +++ b/mfbt/tests/TestPair.cpp @@ -0,0 +1,61 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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 "mozilla/Pair.h" + +using mozilla::Pair; + +// Sizes aren't part of the guaranteed Pair interface, but we want to verify our +// attempts at compactness through EBO are moderately functional, *somewhere*. +#define INSTANTIATE(T1, T2, name, size) \ + Pair<T1, T2> name##_1(T1(0), T2(0)); \ + static_assert(sizeof(name##_1.first()) > 0, \ + "first method should work on Pair<" #T1 ", " #T2 ">"); \ + static_assert(sizeof(name##_1.second()) > 0, \ + "second method should work on Pair<" #T1 ", " #T2 ">"); \ + static_assert(sizeof(name##_1) == (size), \ + "Pair<" #T1 ", " #T2 "> has an unexpected size"); \ + Pair<T2, T1> name##_2(T2(0), T1(0)); \ + static_assert(sizeof(name##_2.first()) > 0, \ + "first method should work on Pair<" #T2 ", " #T1 ">"); \ + static_assert(sizeof(name##_2.second()) > 0, \ + "second method should work on Pair<" #T2 ", " #T1 ">"); \ + static_assert(sizeof(name##_2) == (size), \ + "Pair<" #T2 ", " #T1 "> has an unexpected size"); + +INSTANTIATE(int, int, prim1, 2 * sizeof(int)); +INSTANTIATE(int, long, prim2, 2 * sizeof(long)); + +struct EmptyClass { EmptyClass(int) {} }; +struct NonEmpty { char c; NonEmpty(int) {} }; + +INSTANTIATE(int, EmptyClass, both1, sizeof(int)); +INSTANTIATE(int, NonEmpty, both2, 2 * sizeof(int)); +INSTANTIATE(EmptyClass, NonEmpty, both3, 1); + +struct A { char dummy; A(int) {} }; +struct B : A { B(int i) : A(i) {} }; + +INSTANTIATE(A, A, class1, 2); +INSTANTIATE(A, B, class2, 2); +INSTANTIATE(A, EmptyClass, class3, 1); + +struct OtherEmpty : EmptyClass { OtherEmpty(int i) : EmptyClass(i) {} }; + +// C++11 requires distinct objects of the same type, within the same "most +// derived object", to have different addresses. Pair allocates its elements as +// two bases, a base and a member, or two members. If the two elements have +// non-zero size or are unrelated, no big deal. But if they're both empty and +// related, something -- possibly both -- must be inflated. Exactly which are +// inflated depends which PairHelper specialization is used. We could +// potentially assert something about size for this case, but whatever we could +// assert would be very finicky. Plus it's two empty classes -- hardly likely. +// So don't bother trying to assert anything about this case. +//INSTANTIATE(EmptyClass, OtherEmpty, class4, ...something finicky...); + +int +main() +{ +}
--- a/mfbt/tests/TestTypeTraits.cpp +++ b/mfbt/tests/TestTypeTraits.cpp @@ -148,16 +148,26 @@ static_assert(!IsUnsigned<volatile doubl static_assert(IsSigned<long double>::value, "long double should be signed"); static_assert(!IsUnsigned<long double>::value, "long double shouldn't be unsigned"); static_assert(IsSigned<const volatile long double>::value, "const volatile long double should be signed"); static_assert(!IsUnsigned<const volatile long double>::value, "const volatile long double shouldn't be unsigned"); +class NotIntConstructible +{ + NotIntConstructible(int) MOZ_DELETE; +}; + +static_assert(!IsSigned<NotIntConstructible>::value, + "non-arithmetic types are not signed"); +static_assert(!IsUnsigned<NotIntConstructible>::value, + "non-arithmetic types are not unsigned"); + namespace CPlusPlus11IsBaseOf { // Adapted from C++11 § 20.9.6. struct B {}; struct B1 : B {}; struct B2 : B {}; struct D : private B1, private B2 {};
--- a/mfbt/tests/moz.build +++ b/mfbt/tests/moz.build @@ -1,29 +1,31 @@ # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- # vim: set filetype=python: # 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/. CPP_UNIT_TESTS += [ + 'TestArrayUtils.cpp', 'TestAtomics.cpp', 'TestBinarySearch.cpp', 'TestBloomFilter.cpp', 'TestCasting.cpp', 'TestCeilingFloor.cpp', 'TestCheckedInt.cpp', 'TestCountPopulation.cpp', 'TestCountZeroes.cpp', 'TestEndian.cpp', 'TestEnumSet.cpp', 'TestFloatingPoint.cpp', 'TestIntegerPrintfMacros.cpp', 'TestMacroArgs.cpp', 'TestMacroForEach.cpp', + 'TestPair.cpp', 'TestRollingMean.cpp', 'TestSHA1.cpp', 'TestTypedEnum.cpp', 'TestTypeTraits.cpp', 'TestWeakPtr.cpp', ] if not CONFIG['MOZ_ASAN']:
--- a/modules/libpref/src/init/all.js +++ b/modules/libpref/src/init/all.js @@ -443,33 +443,16 @@ pref("gfx.font_rendering.fallback.always // cache shaped word results pref("gfx.font_rendering.wordcache.charlimit", 32); // cache shaped word results pref("gfx.font_rendering.wordcache.maxentries", 10000); pref("gfx.font_rendering.graphite.enabled", true); -// Check intl/unicharutil/util/nsUnicodeProperties.h for definitions of script bits -// in the ShapingType enumeration -// Currently-defined bits: -// SHAPING_DEFAULT = 0x0001, -// SHAPING_ARABIC = 0x0002, -// SHAPING_HEBREW = 0x0004, -// SHAPING_HANGUL = 0x0008, -// SHAPING_MONGOLIAN = 0x0010, -// SHAPING_INDIC = 0x0020, -// SHAPING_THAI = 0x0040 -// (see http://mxr.mozilla.org/mozilla-central/ident?i=ShapingType) -// Scripts not listed are grouped in the default category. -// Set the pref to 255 to have all text shaped via the harfbuzz backend. -// Default setting: -// We use harfbuzz for all scripts (except when using AAT fonts on OS X). -pref("gfx.font_rendering.harfbuzz.scripts", 255); - #ifdef XP_WIN pref("gfx.font_rendering.directwrite.enabled", false); pref("gfx.font_rendering.directwrite.use_gdi_table_loading", true); #endif pref("gfx.font_rendering.opentype_svg.enabled", true); #ifdef XP_WIN
--- a/netwerk/protocol/http/Http2Session.cpp +++ b/netwerk/protocol/http/Http2Session.cpp @@ -93,16 +93,18 @@ Http2Session::Http2Session(nsISocketTran , mServerInitialStreamWindow(kDefaultRwin) , mLocalSessionWindow(kDefaultRwin) , mServerSessionWindow(kDefaultRwin) , mOutputQueueSize(kDefaultQueueSize) , mOutputQueueUsed(0) , mOutputQueueSent(0) , mLastReadEpoch(PR_IntervalNow()) , mPingSentEpoch(0) + , mWaitingForSettingsAck(false) + , mGoAwayOnPush(false) { MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread); static uint64_t sSerial; mSerial = ++sSerial; LOG3(("Http2Session::Http2Session %p serial=0x%X\n", this, mSerial)); @@ -803,16 +805,18 @@ Http2Session::SendHello() // set ENABLE_PUSH to 0 CopyAsNetwork16(packet + 8 + (6 * numberOfEntries), SETTINGS_TYPE_ENABLE_PUSH); // The value portion of the setting pair is already initialized to 0 numberOfEntries++; CopyAsNetwork16(packet + 8 + (6 * numberOfEntries), SETTINGS_TYPE_MAX_CONCURRENT); // The value portion of the setting pair is already initialized to 0 numberOfEntries++; + + mWaitingForSettingsAck = true; } // Advertise the Push RWIN for the session, and on each new pull stream // send a window update with END_FLOW_CONTROL CopyAsNetwork16(packet + 8 + (6 * numberOfEntries), SETTINGS_TYPE_INITIAL_WINDOW); CopyAsNetwork32(packet + 8 + (6 * numberOfEntries) + 2, mPushAllowance); numberOfEntries++; @@ -1354,18 +1358,21 @@ Http2Session::RecvSettings(Http2Session default: break; } } self->ResetDownstreamState(); - if (!(self->mInputFrameFlags & kFlag_ACK)) + if (!(self->mInputFrameFlags & kFlag_ACK)) { self->GenerateSettingsAck(); + } else if (self->mWaitingForSettingsAck) { + self->mGoAwayOnPush = true; + } return NS_OK; } nsresult Http2Session::RecvPushPromise(Http2Session *self) { MOZ_ASSERT(self->mInputFrameType == FRAME_TYPE_PUSH_PROMISE); @@ -1439,18 +1446,22 @@ Http2Session::RecvPushPromise(Http2Sessi bool resetStream = true; SpdyPushCache *cache = nullptr; if (self->mShouldGoAway) { LOG3(("Http2Session::RecvPushPromise %p push while in GoAway " "mode refused.\n", self)); self->GenerateRstStream(REFUSED_STREAM_ERROR, promisedID); } else if (!gHttpHandler->AllowPush()) { - // MAX_CONCURRENT_STREAMS of 0 in settings disabled push + // ENABLE_PUSH and MAX_CONCURRENT_STREAMS of 0 in settings disabled push LOG3(("Http2Session::RecvPushPromise Push Recevied when Disabled\n")); + if (self->mGoAwayOnPush) { + LOG3(("Http2Session::RecvPushPromise sending GOAWAY")); + RETURN_SESSION_ERROR(self, PROTOCOL_ERROR); + } self->GenerateRstStream(REFUSED_STREAM_ERROR, promisedID); } else if (!(self->mInputFrameFlags & kFlag_END_PUSH_PROMISE)) { LOG3(("Http2Session::RecvPushPromise no support for multi frame push\n")); self->GenerateRstStream(REFUSED_STREAM_ERROR, promisedID); } else if (!associatedStream) { LOG3(("Http2Session::RecvPushPromise %p lookup associated ID failed.\n", self)); self->GenerateRstStream(PROTOCOL_ERROR, promisedID); } else {
--- a/netwerk/protocol/http/Http2Session.h +++ b/netwerk/protocol/http/Http2Session.h @@ -436,16 +436,23 @@ private: // used as a temporary buffer while enumerating the stream hash during GoAway nsDeque mGoAwayStreamsToRestart; // Each session gets a unique serial number because the push cache is correlated // by the load group and the serial number can be used as part of the cache key // to make sure streams aren't shared across sessions. uint64_t mSerial; + // If push is disabled, we want to be able to send PROTOCOL_ERRORs if we + // receive a PUSH_PROMISE, but we have to wait for the SETTINGS ACK before + // we can actually tell the other end to go away. These help us keep track + // of that state so we can behave appropriately. + bool mWaitingForSettingsAck; + bool mGoAwayOnPush; + private: /// connect tunnels void DispatchOnTunnel(nsAHttpTransaction *, nsIInterfaceRequestor *); void RegisterTunnel(Http2Stream *); void UnRegisterTunnel(Http2Stream *); uint32_t FindTunnelCount(nsHttpConnectionInfo *); nsDataHashtable<nsCStringHashKey, uint32_t> mTunnelHash;
--- a/netwerk/sctp/datachannel/DataChannel.cpp +++ b/netwerk/sctp/datachannel/DataChannel.cpp @@ -675,22 +675,22 @@ DataChannelConnection::SctpDtlsInput(Tra } } #endif // Pass the data to SCTP usrsctp_conninput(static_cast<void *>(this), data, len, 0); } int -DataChannelConnection::SendPacket(const unsigned char *data, size_t len, bool release) +DataChannelConnection::SendPacket(unsigned char data[], size_t len, bool release) { //LOG(("%p: SCTP/DTLS sent %ld bytes", this, len)); int res = mTransportFlow->SendPacket(data, len) < 0 ? 1 : 0; if (release) - delete data; + delete [] data; return res; } /* static */ int DataChannelConnection::SctpDtlsOutput(void *addr, void *buffer, size_t length, uint8_t tos, uint8_t set_df) {
--- a/netwerk/sctp/datachannel/DataChannel.h +++ b/netwerk/sctp/datachannel/DataChannel.h @@ -195,17 +195,17 @@ protected: // Use from main thread only as WeakPtr is not threadsafe WeakPtr<DataConnectionListener> mListener; private: friend class DataChannelConnectRunnable; #ifdef SCTP_DTLS_SUPPORTED static void DTLSConnectThread(void *data); - int SendPacket(const unsigned char* data, size_t len, bool release); + int SendPacket(unsigned char data[], size_t len, bool release); void SctpDtlsInput(TransportFlow *flow, const unsigned char *data, size_t len); static int SctpDtlsOutput(void *addr, void *buffer, size_t length, uint8_t tos, uint8_t set_df); #endif DataChannel* FindChannelByStream(uint16_t stream); uint16_t FindFreeStream(); bool RequestMoreStreams(int32_t aNeeded = 16); int32_t SendControlMessage(void *msg, uint32_t len, uint16_t stream); int32_t SendOpenRequestMessage(const nsACString& label, const nsACString& protocol,
--- a/parser/html/nsHtml5Module.cpp +++ b/parser/html/nsHtml5Module.cpp @@ -98,16 +98,18 @@ class nsHtml5ParserThreadTerminator MOZ_ "Unexpected topic"); if (mThread) { mThread->Shutdown(); mThread = nullptr; } return NS_OK; } private: + ~nsHtml5ParserThreadTerminator() {} + nsCOMPtr<nsIThread> mThread; }; NS_IMPL_ISUPPORTS(nsHtml5ParserThreadTerminator, nsIObserver) // static nsIThread* nsHtml5Module::GetStreamParserThread()
--- a/parser/html/nsHtml5Parser.h +++ b/parser/html/nsHtml5Parser.h @@ -32,17 +32,16 @@ class nsHtml5Parser : public nsIParser, { public: NS_DECL_AND_IMPL_ZEROING_OPERATOR_NEW NS_DECL_CYCLE_COLLECTING_ISUPPORTS NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsHtml5Parser, nsIParser) nsHtml5Parser(); - virtual ~nsHtml5Parser(); /* Start nsIParser */ /** * No-op for backwards compat. */ NS_IMETHOD_(void) SetContentSink(nsIContentSink* aSink); /** @@ -261,16 +260,18 @@ class nsHtml5Parser : public nsIParser, /** * Parse until pending data is exhausted or a script blocks the parser */ void ParseUntilBlocked(); private: + virtual ~nsHtml5Parser(); + // State variables /** * Whether the last character tokenized was a carriage return (for CRLF) */ bool mLastWasCR; /**
--- a/parser/html/nsHtml5StreamListener.h +++ b/parser/html/nsHtml5StreamListener.h @@ -28,27 +28,28 @@ * threads, so there is no need to have a mutex around nsHtml5RefPtr to * prevent it from double-releasing nsHtml5StreamParser. */ class nsHtml5StreamListener : public nsIStreamListener, public nsIThreadRetargetableStreamListener { public: nsHtml5StreamListener(nsHtml5StreamParser* aDelegate); - virtual ~nsHtml5StreamListener(); NS_DECL_THREADSAFE_ISUPPORTS NS_DECL_NSIREQUESTOBSERVER NS_DECL_NSISTREAMLISTENER NS_DECL_NSITHREADRETARGETABLESTREAMLISTENER inline nsHtml5StreamParser* GetDelegate() { return mDelegate; } void DropDelegate(); private: + virtual ~nsHtml5StreamListener(); + nsHtml5RefPtr<nsHtml5StreamParser> mDelegate; }; #endif // nsHtml5StreamListener_h
--- a/parser/html/nsHtml5StreamParser.h +++ b/parser/html/nsHtml5StreamParser.h @@ -112,18 +112,16 @@ class nsHtml5StreamParser : public nsICh NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsHtml5StreamParser, nsICharsetDetectionObserver) static void InitializeStatics(); nsHtml5StreamParser(nsHtml5TreeOpExecutor* aExecutor, nsHtml5Parser* aOwner, eParserMode aMode); - - virtual ~nsHtml5StreamParser(); // Methods that nsHtml5StreamListener calls nsresult CheckListenerChain(); nsresult OnStartRequest(nsIRequest* aRequest, nsISupports* aContext); nsresult OnDataAvailable(nsIRequest* aRequest, nsISupports* aContext, @@ -204,16 +202,17 @@ class nsHtml5StreamParser : public nsICh /** * Sets the URL for View Source title in case this parser ends up being * used for View Source. If aURL is a view-source: URL, takes the inner * URL. data: URLs are shown with an ellipsis instead of the actual data. */ void SetViewSourceTitle(nsIURI* aURL); private: + virtual ~nsHtml5StreamParser(); #ifdef DEBUG bool IsParserThread() { bool ret; mThread->IsOnCurrentThread(&ret); return ret; } #endif
--- a/parser/html/nsHtml5StringParser.h +++ b/parser/html/nsHtml5StringParser.h @@ -20,17 +20,16 @@ class nsHtml5StringParser : public nsPar NS_DECL_ISUPPORTS /** * Constructor for use ONLY by nsContentUtils. Others, please call the * nsContentUtils statics that wrap this. */ nsHtml5StringParser(); - virtual ~nsHtml5StringParser(); /** * Invoke the fragment parsing algorithm (innerHTML). * DO NOT CALL from outside nsContentUtils.cpp. * * @param aSourceBuffer the string being set as innerHTML * @param aTargetNode the target container * @param aContextLocalName local name of context node @@ -53,16 +52,18 @@ class nsHtml5StringParser : public nsPar * */ nsresult ParseDocument(const nsAString& aSourceBuffer, nsIDocument* aTargetDoc, bool aScriptingEnabledForNoscriptParsing); private: + virtual ~nsHtml5StringParser(); + nsresult Tokenize(const nsAString& aSourceBuffer, nsIDocument* aDocument, bool aScriptingEnabledForNoscriptParsing); /** * The tree operation executor */ nsRefPtr<nsHtml5OplessBuilder> mBuilder;
--- a/parser/html/nsParserUtils.h +++ b/parser/html/nsParserUtils.h @@ -8,15 +8,16 @@ #include "nsIScriptableUnescapeHTML.h" #include "nsIParserUtils.h" #include "mozilla/Attributes.h" class nsParserUtils MOZ_FINAL : public nsIScriptableUnescapeHTML, public nsIParserUtils { + ~nsParserUtils() {} public: NS_DECL_ISUPPORTS NS_DECL_NSISCRIPTABLEUNESCAPEHTML NS_DECL_NSIPARSERUTILS }; #endif // nsParserUtils_h
--- a/parser/htmlparser/src/CNavDTD.h +++ b/parser/htmlparser/src/CNavDTD.h @@ -19,19 +19,20 @@ class nsIHTMLContentSink; #endif class CNavDTD : public nsIDTD { #ifdef _MSC_VER #pragma warning( default : 4275 ) #endif + virtual ~CNavDTD(); + public: CNavDTD(); - virtual ~CNavDTD(); NS_DECL_ISUPPORTS NS_DECL_NSIDTD }; #endif
--- a/parser/htmlparser/src/nsExpatDriver.h +++ b/parser/htmlparser/src/nsExpatDriver.h @@ -18,24 +18,25 @@ class nsIExpatSink; class nsIExtendedExpatSink; struct nsCatalogData; class nsExpatDriver : public nsIDTD, public nsITokenizer { + virtual ~nsExpatDriver(); + public: NS_DECL_CYCLE_COLLECTING_ISUPPORTS NS_DECL_NSIDTD NS_DECL_NSITOKENIZER NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsExpatDriver, nsIDTD) nsExpatDriver(); - virtual ~nsExpatDriver(); int HandleExternalEntityRef(const char16_t *aOpenEntityNames, const char16_t *aBase, const char16_t *aSystemId, const char16_t *aPublicId); nsresult HandleStartElement(const char16_t *aName, const char16_t **aAtts); nsresult HandleEndElement(const char16_t *aName); nsresult HandleCharacterData(const char16_t *aCData, const uint32_t aLength);
--- a/parser/htmlparser/src/nsHTMLTokenizer.h +++ b/parser/htmlparser/src/nsHTMLTokenizer.h @@ -17,18 +17,19 @@ #include "nsISupports.h" #include "nsITokenizer.h" #ifdef _MSC_VER #pragma warning( disable : 4275 ) #endif class nsHTMLTokenizer MOZ_FINAL : public nsITokenizer { + ~nsHTMLTokenizer() {} + public: - NS_DECL_ISUPPORTS NS_DECL_NSITOKENIZER nsHTMLTokenizer(); }; #endif
--- a/parser/htmlparser/src/nsParser.h +++ b/parser/htmlparser/src/nsParser.h @@ -61,16 +61,22 @@ class nsIRunnable; #pragma warning( disable : 4275 ) #endif class nsParser : public nsIParser, public nsIStreamListener, public nsSupportsWeakReference { + /** + * Destructor + * @update gess5/11/98 + */ + virtual ~nsParser(); + public: /** * Called on module init */ static nsresult Init(); /** * Called on module shutdown @@ -82,22 +88,16 @@ class nsParser : public nsIParser, /** * default constructor * @update gess5/11/98 */ nsParser(); /** - * Destructor - * @update gess5/11/98 - */ - virtual ~nsParser(); - - /** * Select given content sink into parser for parser output * @update gess5/11/98 * @param aSink is the new sink to be used by parser * @return old sink, or nullptr */ NS_IMETHOD_(void) SetContentSink(nsIContentSink* aSink); /**
--- a/parser/htmlparser/src/nsParserService.h +++ b/parser/htmlparser/src/nsParserService.h @@ -9,19 +9,20 @@ #include "nsIParserService.h" extern "C" int MOZ_XMLIsLetter(const char* ptr); extern "C" int MOZ_XMLIsNCNameChar(const char* ptr); extern "C" int MOZ_XMLTranslateEntity(const char* ptr, const char* end, const char** next, char16_t* result); class nsParserService : public nsIParserService { + virtual ~nsParserService(); + public: nsParserService(); - virtual ~nsParserService(); NS_DECL_ISUPPORTS int32_t HTMLAtomTagToId(nsIAtom* aAtom) const; int32_t HTMLCaseSensitiveAtomTagToId(nsIAtom* aAtom) const; int32_t HTMLStringTagToId(const nsAString& aTag) const;
--- a/parser/xml/src/nsSAXAttributes.h +++ b/parser/xml/src/nsSAXAttributes.h @@ -31,12 +31,13 @@ struct SAXAttr class nsSAXAttributes MOZ_FINAL : public nsISAXMutableAttributes { public: NS_DECL_ISUPPORTS NS_DECL_NSISAXATTRIBUTES NS_DECL_NSISAXMUTABLEATTRIBUTES private: + ~nsSAXAttributes() {} nsTArray<SAXAttr> mAttrs; }; #endif // nsSAXAttributes_h__
--- a/parser/xml/src/nsSAXLocator.h +++ b/parser/xml/src/nsSAXLocator.h @@ -23,15 +23,17 @@ public: NS_DECL_NSISAXLOCATOR nsSAXLocator(nsString& aPublicId, nsString& aSystemId, int32_t aLineNumber, int32_t aColumnNumber); private: + ~nsSAXLocator() {} + nsString mPublicId; nsString mSystemId; int32_t mLineNumber; int32_t mColumnNumber; }; #endif //nsSAXLocator_h__
--- a/parser/xml/src/nsSAXXMLReader.h +++ b/parser/xml/src/nsSAXXMLReader.h @@ -70,16 +70,18 @@ public: } virtual nsISupports *GetTarget() { return nullptr; } private: + ~nsSAXXMLReader() {} + nsCOMPtr<nsISAXContentHandler> mContentHandler; nsCOMPtr<nsISAXDTDHandler> mDTDHandler; nsCOMPtr<nsISAXErrorHandler> mErrorHandler; nsCOMPtr<nsISAXLexicalHandler> mLexicalHandler; nsCOMPtr<nsIMozSAXXMLDeclarationHandler> mDeclarationHandler; nsCOMPtr<nsIURI> mBaseURI; nsCOMPtr<nsIStreamListener> mListener; nsCOMPtr<nsIRequestObserver> mParserObserver;
--- a/security/pkix/test/gtest/pkixcheck_CheckKeyUsage_tests.cpp +++ b/security/pkix/test/gtest/pkixcheck_CheckKeyUsage_tests.cpp @@ -129,16 +129,50 @@ TEST(pkixchekc_CheckKeyusage, tooManyUnu siBuffer, twoValueBytesData, sizeof(twoValueBytesData) }; ASSERT_BAD(CheckKeyUsage(EndEntityOrCA::MustBeEndEntity, &twoValueBytes, KeyUsage::digitalSignature)); } +TEST(pkixcheck_CheckKeyUsage, NoValueBytes_NoPaddingBits) +{ + static const uint8_t DER_BYTES[] = { + 0x03/*BIT STRING*/, 0x01/*LENGTH=1*/, 0/*unused bits*/ + }; + static const SECItem DER = { + siBuffer, + const_cast<uint8_t*>(DER_BYTES), + sizeof(DER_BYTES) + }; + + ASSERT_BAD(CheckKeyUsage(EndEntityOrCA::MustBeEndEntity, &DER, + KeyUsage::digitalSignature)); + ASSERT_BAD(CheckKeyUsage(EndEntityOrCA::MustBeCA, &DER, + KeyUsage::keyCertSign)); +} + +TEST(pkixcheck_CheckKeyUsage, NoValueBytes_7PaddingBits) +{ + static const uint8_t DER_BYTES[] = { + 0x03/*BIT STRING*/, 0x01/*LENGTH=1*/, 7/*unused bits*/ + }; + static const SECItem DER = { + siBuffer, + const_cast<uint8_t*>(DER_BYTES), + sizeof(DER_BYTES) + }; + + ASSERT_BAD(CheckKeyUsage(EndEntityOrCA::MustBeEndEntity, &DER, + KeyUsage::digitalSignature)); + ASSERT_BAD(CheckKeyUsage(EndEntityOrCA::MustBeCA, &DER, + KeyUsage::keyCertSign)); +} + void ASSERT_SimpleCase(uint8_t unusedBits, uint8_t bits, KeyUsage usage) { // Test that only the right bit is accepted for the usage for both EE and CA // certs. NAMED_SIMPLE_KU(good, unusedBits, bits); ASSERT_Success(CheckKeyUsage(EndEntityOrCA::MustBeEndEntity, &good, usage)); ASSERT_Success(CheckKeyUsage(EndEntityOrCA::MustBeCA, &good, usage));
--- a/toolkit/components/downloads/ApplicationReputation.cpp +++ b/toolkit/components/downloads/ApplicationReputation.cpp @@ -975,22 +975,27 @@ PendingLookup::OnStopRequestInternal(nsI safe_browsing::ClientDownloadResponse response; if (!response.ParseFromString(buf)) { NS_WARNING("Could not parse protocol buffer"); Accumulate(mozilla::Telemetry::APPLICATION_REPUTATION_SERVER, SERVER_RESPONSE_INVALID); return NS_ERROR_CANNOT_CONVERT_DATA; } - // There are several more verdicts, but we only respect one for now and treat - // everything else as SAFE. + // There are several more verdicts, but we only respect DANGEROUS and + // DANGEROUS_HOST for now and treat everything else as SAFE. Accumulate(mozilla::Telemetry::APPLICATION_REPUTATION_SERVER, SERVER_RESPONSE_VALID); - if (response.verdict() == safe_browsing::ClientDownloadResponse::DANGEROUS) { - *aShouldBlock = true; + switch(response.verdict()) { + case safe_browsing::ClientDownloadResponse::DANGEROUS: + case safe_browsing::ClientDownloadResponse::DANGEROUS_HOST: + *aShouldBlock = true; + break; + default: + break; } return NS_OK; } NS_IMPL_ISUPPORTS(ApplicationReputationService, nsIApplicationReputationService)
--- a/toolkit/components/downloads/csd.pb.cc +++ b/toolkit/components/downloads/csd.pb.cc @@ -8,1565 +8,70 @@ #include <google/protobuf/stubs/once.h> #include <google/protobuf/io/coded_stream.h> #include <google/protobuf/wire_format_lite_inl.h> // @@protoc_insertion_point(includes) namespace safe_browsing { void protobuf_ShutdownFile_csd_2eproto() { - delete ClientPhishingRequest::default_instance_; - delete ClientPhishingRequest_Feature::default_instance_; - delete ClientPhishingResponse::default_instance_; - delete ClientMalwareRequest::default_instance_; - delete ClientMalwareRequest_Feature::default_instance_; - delete ClientMalwareResponse::default_instance_; delete ClientDownloadRequest::default_instance_; delete ClientDownloadRequest_Digests::default_instance_; delete ClientDownloadRequest_Resource::default_instance_; delete ClientDownloadRequest_CertificateChain::default_instance_; delete ClientDownloadRequest_CertificateChain_Element::default_instance_; delete ClientDownloadRequest_SignatureInfo::default_instance_; + delete ClientDownloadRequest_PEImageHeaders::default_instance_; + delete ClientDownloadRequest_PEImageHeaders_DebugData::default_instance_; + delete ClientDownloadRequest_ImageHeaders::default_instance_; delete ClientDownloadResponse::default_instance_; delete ClientDownloadResponse_MoreInfo::default_instance_; - delete ClientDownloadReport::default_instance_; - delete ClientDownloadReport_UserInformation::default_instance_; - delete ClientUploadResponse::default_instance_; } void protobuf_AddDesc_csd_2eproto() { static bool already_here = false; if (already_here) return; already_here = true; GOOGLE_PROTOBUF_VERIFY_VERSION; - ClientPhishingRequest::default_instance_ = new ClientPhishingRequest(); - ClientPhishingRequest_Feature::default_instance_ = new ClientPhishingRequest_Feature(); - ClientPhishingResponse::default_instance_ = new ClientPhishingResponse(); - ClientMalwareRequest::default_instance_ = new ClientMalwareRequest(); - ClientMalwareRequest_Feature::default_instance_ = new ClientMalwareRequest_Feature(); - ClientMalwareResponse::default_instance_ = new ClientMalwareResponse(); ClientDownloadRequest::default_instance_ = new ClientDownloadRequest(); ClientDownloadRequest_Digests::default_instance_ = new ClientDownloadRequest_Digests(); ClientDownloadRequest_Resource::default_instance_ = new ClientDownloadRequest_Resource(); ClientDownloadRequest_CertificateChain::default_instance_ = new ClientDownloadRequest_CertificateChain(); ClientDownloadRequest_CertificateChain_Element::default_instance_ = new ClientDownloadRequest_CertificateChain_Element(); ClientDownloadRequest_SignatureInfo::default_instance_ = new ClientDownloadRequest_SignatureInfo(); + ClientDownloadRequest_PEImageHeaders::default_instance_ = new ClientDownloadRequest_PEImageHeaders(); + ClientDownloadRequest_PEImageHeaders_DebugData::default_instance_ = new ClientDownloadRequest_PEImageHeaders_DebugData(); + ClientDownloadRequest_ImageHeaders::default_instance_ = new ClientDownloadRequest_ImageHeaders(); ClientDownloadResponse::default_instance_ = new ClientDownloadResponse(); ClientDownloadResponse_MoreInfo::default_instance_ = new ClientDownloadResponse_MoreInfo(); - ClientDownloadReport::default_instance_ = new ClientDownloadReport(); - ClientDownloadReport_UserInformation::default_instance_ = new ClientDownloadReport_UserInformation(); - ClientUploadResponse::default_instance_ = new ClientUploadResponse(); - ClientPhishingRequest::default_instance_->InitAsDefaultInstance(); - ClientPhishingRequest_Feature::default_instance_->InitAsDefaultInstance(); - ClientPhishingResponse::default_instance_->InitAsDefaultInstance(); - ClientMalwareRequest::default_instance_->InitAsDefaultInstance(); - ClientMalwareRequest_Feature::default_instance_->InitAsDefaultInstance(); - ClientMalwareResponse::default_instance_->InitAsDefaultInstance(); ClientDownloadRequest::default_instance_->InitAsDefaultInstance(); ClientDownloadRequest_Digests::default_instance_->InitAsDefaultInstance(); ClientDownloadRequest_Resource::default_instance_->InitAsDefaultInstance(); ClientDownloadRequest_CertificateChain::default_instance_->InitAsDefaultInstance(); ClientDownloadRequest_CertificateChain_Element::default_instance_->InitAsDefaultInstance(); ClientDownloadRequest_SignatureInfo::default_instance_->InitAsDefaultInstance(); + ClientDownloadRequest_PEImageHeaders::default_instance_->InitAsDefaultInstance(); + ClientDownloadRequest_PEImageHeaders_DebugData::default_instance_->InitAsDefaultInstance(); + ClientDownloadRequest_ImageHeaders::default_instance_->InitAsDefaultInstance(); ClientDownloadResponse::default_instance_->InitAsDefaultInstance(); ClientDownloadResponse_MoreInfo::default_instance_->InitAsDefaultInstance(); - ClientDownloadReport::default_instance_->InitAsDefaultInstance(); - ClientDownloadReport_UserInformation::default_instance_->InitAsDefaultInstance(); - ClientUploadResponse::default_instance_->InitAsDefaultInstance(); ::google::protobuf::internal::OnShutdown(&protobuf_ShutdownFile_csd_2eproto); } // Force AddDescriptors() to be called at static initialization time. struct StaticDescriptorInitializer_csd_2eproto { StaticDescriptorInitializer_csd_2eproto() { protobuf_AddDesc_csd_2eproto(); } } static_descriptor_initializer_csd_2eproto_; // =================================================================== -#ifndef _MSC_VER -const int ClientPhishingRequest_Feature::kNameFieldNumber; -const int ClientPhishingRequest_Feature::kValueFieldNumber; -#endif // !_MSC_VER - -ClientPhishingRequest_Feature::ClientPhishingRequest_Feature() - : ::google::protobuf::MessageLite() { - SharedCtor(); -} - -void ClientPhishingRequest_Feature::InitAsDefaultInstance() { -} - -ClientPhishingRequest_Feature::ClientPhishingRequest_Feature(const ClientPhishingRequest_Feature& from) - : ::google::protobuf::MessageLite() { - SharedCtor(); - MergeFrom(from); -} - -void ClientPhishingRequest_Feature::SharedCtor() { - _cached_size_ = 0; - name_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); - value_ = 0; - ::memset(_has_bits_, 0, sizeof(_has_bits_)); -} - -ClientPhishingRequest_Feature::~ClientPhishingRequest_Feature() { - SharedDtor(); -} - -void ClientPhishingRequest_Feature::SharedDtor() { - if (name_ != &::google::protobuf::internal::kEmptyString) { - delete name_; - } - if (this != default_instance_) { - } -} - -void ClientPhishingRequest_Feature::SetCachedSize(int size) const { - GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); - _cached_size_ = size; - GOOGLE_SAFE_CONCURRENT_WRITES_END(); -} -const ClientPhishingRequest_Feature& ClientPhishingRequest_Feature::default_instance() { - if (default_instance_ == NULL) protobuf_AddDesc_csd_2eproto(); return *default_instance_; -} - -ClientPhishingRequest_Feature* ClientPhishingRequest_Feature::default_instance_ = NULL; - -ClientPhishingRequest_Feature* ClientPhishingRequest_Feature::New() const { - return new ClientPhishingRequest_Feature; -} - -void ClientPhishingRequest_Feature::Clear() { - if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) { - if (has_name()) { - if (name_ != &::google::protobuf::internal::kEmptyString) { - name_->clear(); - } - } - value_ = 0; - } - ::memset(_has_bits_, 0, sizeof(_has_bits_)); -} - -bool ClientPhishingRequest_Feature::MergePartialFromCodedStream( - ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) return false - ::google::protobuf::uint32 tag; - while ((tag = input->ReadTag()) != 0) { - switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { - // required string name = 1; - case 1: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == - ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { - DO_(::google::protobuf::internal::WireFormatLite::ReadString( - input, this->mutable_name())); - } else { - goto handle_uninterpreted; - } - if (input->ExpectTag(17)) goto parse_value; - break; - } - - // required double value = 2; - case 2: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == - ::google::protobuf::internal::WireFormatLite::WIRETYPE_FIXED64) { - parse_value: - DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< - double, ::google::protobuf::internal::WireFormatLite::TYPE_DOUBLE>( - input, &value_))); - set_has_value(); - } else { - goto handle_uninterpreted; - } - if (input->ExpectAtEnd()) return true; - break; - } - - default: { - handle_uninterpreted: - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == - ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) { - return true; - } - DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag)); - break; - } - } - } - return true; -#undef DO_ -} - -void ClientPhishingRequest_Feature::SerializeWithCachedSizes( - ::google::protobuf::io::CodedOutputStream* output) const { - // required string name = 1; - if (has_name()) { - ::google::protobuf::internal::WireFormatLite::WriteString( - 1, this->name(), output); - } - - // required double value = 2; - if (has_value()) { - ::google::protobuf::internal::WireFormatLite::WriteDouble(2, this->value(), output); - } - -} - -int ClientPhishingRequest_Feature::ByteSize() const { - int total_size = 0; - - if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) { - // required string name = 1; - if (has_name()) { - total_size += 1 + - ::google::protobuf::internal::WireFormatLite::StringSize( - this->name()); - } - - // required double value = 2; - if (has_value()) { - total_size += 1 + 8; - } - - } - GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); - _cached_size_ = total_size; - GOOGLE_SAFE_CONCURRENT_WRITES_END(); - return total_size; -} - -void ClientPhishingRequest_Feature::CheckTypeAndMergeFrom( - const ::google::protobuf::MessageLite& from) { - MergeFrom(*::google::protobuf::down_cast<const ClientPhishingRequest_Feature*>(&from)); -} - -void ClientPhishingRequest_Feature::MergeFrom(const ClientPhishingRequest_Feature& from) { - GOOGLE_CHECK_NE(&from, this); - if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) { - if (from.has_name()) { - set_name(from.name()); - } - if (from.has_value()) { - set_value(from.value()); - } - } -} - -void ClientPhishingRequest_Feature::CopyFrom(const ClientPhishingRequest_Feature& from) { - if (&from == this) return; - Clear(); - MergeFrom(from); -} - -bool ClientPhishingRequest_Feature::IsInitialized() const { - if ((_has_bits_[0] & 0x00000003) != 0x00000003) return false; - - return true; -} - -void ClientPhishingRequest_Feature::Swap(ClientPhishingRequest_Feature* other) { - if (other != this) { - std::swap(name_, other->name_); - std::swap(value_, other->value_); - std::swap(_has_bits_[0], other->_has_bits_[0]); - std::swap(_cached_size_, other->_cached_size_); - } -} - -::std::string ClientPhishingRequest_Feature::GetTypeName() const { - return "safe_browsing.ClientPhishingRequest.Feature"; -} - - -// ------------------------------------------------------------------- - -#ifndef _MSC_VER -const int ClientPhishingRequest::kUrlFieldNumber; -const int ClientPhishingRequest::kOBSOLETEHashPrefixFieldNumber; -const int ClientPhishingRequest::kClientScoreFieldNumber; -const int ClientPhishingRequest::kIsPhishingFieldNumber; -const int ClientPhishingRequest::kFeatureMapFieldNumber; -const int ClientPhishingRequest::kModelVersionFieldNumber; -const int ClientPhishingRequest::kNonModelFeatureMapFieldNumber; -const int ClientPhishingRequest::kOBSOLETEReferrerUrlFieldNumber; -#endif // !_MSC_VER - -ClientPhishingRequest::ClientPhishingRequest() - : ::google::protobuf::MessageLite() { - SharedCtor(); -} - -void ClientPhishingRequest::InitAsDefaultInstance() { -} - -ClientPhishingRequest::ClientPhishingRequest(const ClientPhishingRequest& from) - : ::google::protobuf::MessageLite() { - SharedCtor(); - MergeFrom(from); -} - -void ClientPhishingRequest::SharedCtor() { - _cached_size_ = 0; - url_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); - obsolete_hash_prefix_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); - client_score_ = 0; - is_phishing_ = false; - model_version_ = 0; - obsolete_referrer_url_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); - ::memset(_has_bits_, 0, sizeof(_has_bits_)); -} - -ClientPhishingRequest::~ClientPhishingRequest() { - SharedDtor(); -} - -void ClientPhishingRequest::SharedDtor() { - if (url_ != &::google::protobuf::internal::kEmptyString) { - delete url_; - } - if (obsolete_hash_prefix_ != &::google::protobuf::internal::kEmptyString) { - delete obsolete_hash_prefix_; - } - if (obsolete_referrer_url_ != &::google::protobuf::internal::kEmptyString) { - delete obsolete_referrer_url_; - } - if (this != default_instance_) { - } -} - -void ClientPhishingRequest::SetCachedSize(int size) const { - GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); - _cached_size_ = size; - GOOGLE_SAFE_CONCURRENT_WRITES_END(); -} -const ClientPhishingRequest& ClientPhishingRequest::default_instance() { - if (default_instance_ == NULL) protobuf_AddDesc_csd_2eproto(); return *def