From 05f5685990bae9649f4f29f79120103b7a1d7707 Mon Sep 17 00:00:00 2001 From: Seth Fowler Date: Fri, 6 Feb 2015 02:51:12 -0800 Subject: [PATCH 01/62] Bug 1128229 - Add fuzzy annotations to CSS image tests that depend on imgFrame::Optimize. r=me --- layout/reftests/backgrounds/reftest.list | 5 +++-- layout/reftests/bugs/reftest.list | 15 ++++++++------- layout/reftests/image-rect/reftest.list | 2 +- layout/reftests/image/reftest.list | 4 ++-- 4 files changed, 14 insertions(+), 12 deletions(-) diff --git a/layout/reftests/backgrounds/reftest.list b/layout/reftests/backgrounds/reftest.list index 9060bf5cfac9..83549179610d 100644 --- a/layout/reftests/backgrounds/reftest.list +++ b/layout/reftests/backgrounds/reftest.list @@ -155,8 +155,9 @@ fails-if(Android&&AndroidVersion==15) fuzzy-if(!Android||(Android&&AndroidVersio == attachment-local-clipping-image-1.html attachment-local-clipping-image-1-ref.html == attachment-local-clipping-image-2.html attachment-local-clipping-image-1-ref.html # Same ref as the previous test. == attachment-local-clipping-image-3.html attachment-local-clipping-image-3-ref.html -fails-if(Android&&AndroidVersion==15) == attachment-local-clipping-image-4.html attachment-local-clipping-image-4-ref.html #Bug 959165 -fails-if(Android&&AndroidVersion==15) == attachment-local-clipping-image-5.html attachment-local-clipping-image-4-ref.html # Same ref as the previous test. #Bug 959165 +# The next three tests are fuzzy due to bug 1128229. +fails-if(Android&&AndroidVersion==15) fuzzy-if(winWidget||(Android&&AndroidVersion!=15),16,69) == attachment-local-clipping-image-4.html attachment-local-clipping-image-4-ref.html #Bug 959165 +fails-if(Android&&AndroidVersion==15) fuzzy-if(winWidget||(Android&&AndroidVersion!=15),16,69) == attachment-local-clipping-image-5.html attachment-local-clipping-image-4-ref.html # Same ref as the previous test. #Bug 959165 fails-if(Android&&AndroidVersion==15) fuzzy-if(!Android||(Android&&AndroidVersion!=15),80,500) == attachment-local-clipping-image-6.html attachment-local-clipping-image-6-ref.html #Bug 959165 == background-multiple-with-border-radius.html background-multiple-with-border-radius-ref.html diff --git a/layout/reftests/bugs/reftest.list b/layout/reftests/bugs/reftest.list index dedd1eb5dae0..aca1a94d7810 100644 --- a/layout/reftests/bugs/reftest.list +++ b/layout/reftests/bugs/reftest.list @@ -55,9 +55,9 @@ fails == 25888-2r-block.html 25888-2r-ref.html # Bug 25888 fails == 25888-3l-block.html 25888-3l-ref.html # Bug 25888 fails == 25888-3r-block.html 25888-3r-ref.html # Bug 25888 skip-if(B2G) == 28811-1a.html 28811-1-ref.html -== 28811-1b.html 28811-1-ref.html +fuzzy-if(gtk2Widget,6,26200) == 28811-1b.html 28811-1-ref.html # Bug 1128229 skip-if(B2G) == 28811-2a.html 28811-2-ref.html -== 28811-2b.html 28811-2-ref.html +fuzzy-if(gtk2Widget,6,26200) == 28811-2b.html 28811-2-ref.html # Bug 1128229 == 40596-1a.html 40596-1-ref.html != 40596-1b.html 40596-1-ref.html == 40596-1c.html 40596-1-ref.html @@ -935,10 +935,10 @@ fuzzy-if(Android,13,9) == 407111-1.html 407111-1-ref.html # Bug 1128229 == 409089-1.html 409089-1-ref.html == 409089-2.html 409089-2-ref.html == 409089-3.html 409089-3-ref.html -== 409659-1a.html 409659-1-ref.html +fuzzy-if(winWidget,123,1600) == 409659-1a.html 409659-1-ref.html # Bug 1128229 != 409659-1b.html 409659-1-ref.html fails-if(Android&&AndroidVersion>=15&&smallScreen&&AndroidVersion!=17) != 409659-1c.html 409659-1-ref.html #there is no difference in the visible area of the screen -== 409659-1d.html 409659-1-ref.html +fuzzy-if(winWidget,123,1600) == 409659-1d.html 409659-1-ref.html # Bug 1128229 == 410621-1.html 410621-1-ref.html == 411059-1.html 411059-1-ref.html == 411334-1.xml 411334-1-ref.xml @@ -1196,9 +1196,10 @@ test-pref(dom.use_xbl_scopes_for_remote_xul,true) != 449149-1b.html about:blank == 455280-1.xhtml 455280-1-ref.xhtml skip-if(B2G) == 455826-1.html 455826-1-ref.html skip-if(B2G) fails-if(cocoaWidget) fails-if(Android) == 456147.xul 456147-ref.html # bug 458047 -fuzzy-if(Android,11,40) fuzzy-if(B2G,11,40) fuzzy-if(d2d&&/^Windows\x20NT\x206\.2/.test(http.oscpu),1,69) == 456219-1a.html 456219-1-ref.html # bug 853273 -fuzzy-if(Android,11,40) fuzzy-if(B2G,11,40) fuzzy-if(d2d&&/^Windows\x20NT\x206\.2/.test(http.oscpu),1,69) == 456219-1b.html 456219-1-ref.html # bug 853273 -fuzzy-if(Android,11,40) fuzzy-if(B2G,11,40) fuzzy-if(d2d&&/^Windows\x20NT\x206\.2/.test(http.oscpu),1,69) == 456219-1c.html 456219-1-ref.html # bug 853273 +# The next three tests are fuzzy due to bug 1128229. +fuzzy-if(Android||B2G,11,41) fuzzy-if(d2d&&/^Windows\x20NT\x206\.2/.test(http.oscpu),1,69) == 456219-1a.html 456219-1-ref.html # bug 853273 +fuzzy-if(Android||B2G,11,41) fuzzy-if(d2d&&/^Windows\x20NT\x206\.2/.test(http.oscpu),1,69) == 456219-1b.html 456219-1-ref.html # bug 853273 +fuzzy-if(Android||B2G,11,41) fuzzy-if(d2d&&/^Windows\x20NT\x206\.2/.test(http.oscpu),1,69) == 456219-1c.html 456219-1-ref.html # bug 853273 == 456219-2.html 456219-2-ref.html == 456330-1.gif 456330-1-ref.png == 456484-1.html 456484-1-ref.html diff --git a/layout/reftests/image-rect/reftest.list b/layout/reftests/image-rect/reftest.list index e2a091225b27..a9de1062c4fb 100644 --- a/layout/reftests/image-rect/reftest.list +++ b/layout/reftests/image-rect/reftest.list @@ -8,7 +8,7 @@ asserts(0-4) == background-draw-nothing-malformed-images.html background-draw-no == background-over-size-rect.html background-over-size-rect-ref.html == background-test-parser.html background-test-parser-ref.html fuzzy-if(Android||B2G,113,124) == background-with-other-properties.html background-with-other-properties-ref.html -== background-zoom-1.html background-zoom-1-ref.html +fuzzy-if(Android||B2G,16,22) == background-zoom-1.html background-zoom-1-ref.html # Bug 1128229 == background-zoom-2.html background-zoom-2-ref.html == background-zoom-3.html background-zoom-3-ref.html == background-zoom-4.html background-zoom-4-ref.html diff --git a/layout/reftests/image/reftest.list b/layout/reftests/image/reftest.list index 1d31b824ba82..610e1513cc62 100644 --- a/layout/reftests/image/reftest.list +++ b/layout/reftests/image/reftest.list @@ -2,7 +2,7 @@ fuzzy-if(Android,8,30) == background-image-zoom-1.html background-image-zoom-1-r == background-image-zoom-2.html about:blank == image-seam-1a.html image-seam-1-ref.html == image-seam-1b.html image-seam-1-ref.html -== image-seam-2.html image-seam-2-ref.html +fuzzy-if(Android,255,154) == image-seam-2.html image-seam-2-ref.html # Bug 1128229 skip-if(B2G&&browserIsRemote) == image-zoom-1.html image-zoom-1-ref.html skip-if(B2G&&browserIsRemote) == image-zoom-2.html image-zoom-1-ref.html == invalid-url-image-1.html invalid-url-image-1-ref.html @@ -17,7 +17,7 @@ test-pref(layout.css.object-fit-and-position.enabled,true) == image-object-fit-w test-pref(layout.css.object-fit-and-position.enabled,true) == image-object-fit-with-background-2.html image-object-fit-with-background-2-ref.html test-pref(layout.css.object-fit-and-position.enabled,true) == image-object-position-dyn-1.html image-object-position-dyn-1-ref.html test-pref(layout.css.object-fit-and-position.enabled,true) == image-object-position-with-background-1.html image-object-position-with-background-1-ref.html -test-pref(layout.css.object-fit-and-position.enabled,true) == image-object-position-with-background-2.html image-object-position-with-background-2-ref.html +test-pref(layout.css.object-fit-and-position.enabled,true) fuzzy-if(winWidget,100,198) == image-object-position-with-background-2.html image-object-position-with-background-2-ref.html # Bug 1128229 # Tests for image-orientation used with 'from-image' (note that all # image-orientation tests are fuzzy because the JPEG images do not perfectly From 51eb16263e510addc44787f6123c9efd4b812013 Mon Sep 17 00:00:00 2001 From: Seth Fowler Date: Fri, 6 Feb 2015 02:51:12 -0800 Subject: [PATCH 02/62] Bug 1125490 (Part 1) - Make sure we request discarding for images in PresShell::Destroy. r=tn --- dom/base/nsIImageLoadingContent.idl | 9 ++++++--- dom/base/nsImageLoadingContent.cpp | 9 +++++---- layout/base/nsPresShell.cpp | 26 ++++++++++++++++++-------- layout/base/nsPresShell.h | 2 +- layout/svg/SVGFEImageFrame.cpp | 2 +- 5 files changed, 31 insertions(+), 17 deletions(-) diff --git a/dom/base/nsIImageLoadingContent.idl b/dom/base/nsIImageLoadingContent.idl index 3c3594054e16..7b9bec251d8b 100644 --- a/dom/base/nsIImageLoadingContent.idl +++ b/dom/base/nsIImageLoadingContent.idl @@ -37,7 +37,7 @@ interface nsIFrame; * interface to mirror this interface when changing it. */ -[scriptable, builtinclass, uuid(ce098f6c-baca-4178-a9aa-266e8bfe509b)] +[scriptable, builtinclass, uuid(5794d12b-3195-4526-a814-a2181f6c71fe)] interface nsIImageLoadingContent : imgINotificationObserver { /** @@ -170,9 +170,12 @@ interface nsIImageLoadingContent : imgINotificationObserver /** * A visible count is stored, if it is non-zero then this image is considered - * visible. These methods increment, decrement, or return the visible coount. + * visible. These methods increment, decrement, or return the visible count. + * + * @param aRequestDiscard Whether to attempt to discard the image if its + * visibility count is now zero. */ [noscript, notxpcom] void IncrementVisibleCount(); - [noscript, notxpcom] void DecrementVisibleCount(); + [noscript, notxpcom] void DecrementVisibleCount(in boolean aRequestDiscard); [noscript, notxpcom] uint32_t GetVisibleCount(); }; diff --git a/dom/base/nsImageLoadingContent.cpp b/dom/base/nsImageLoadingContent.cpp index 3cb7700b3124..ae281ef48423 100644 --- a/dom/base/nsImageLoadingContent.cpp +++ b/dom/base/nsImageLoadingContent.cpp @@ -554,7 +554,7 @@ nsImageLoadingContent::FrameDestroyed(nsIFrame* aFrame) if (aFrame->HasAnyStateBits(NS_FRAME_IN_POPUP)) { // We assume all images in popups are visible, so this decrement balances // out the increment in FrameCreated above. - DecrementVisibleCount(); + DecrementVisibleCount(/* aRequestDiscard = */ false); } } @@ -777,14 +777,15 @@ nsImageLoadingContent::IncrementVisibleCount() } void -nsImageLoadingContent::DecrementVisibleCount() +nsImageLoadingContent::DecrementVisibleCount(bool aRequestDiscard) { NS_ASSERTION(mVisibleCount > 0, "visible count should be positive here"); mVisibleCount--; if (mVisibleCount == 0) { - UntrackImage(mCurrentRequest); - UntrackImage(mPendingRequest); + uint32_t flags = aRequestDiscard ? REQUEST_DISCARD : 0; + UntrackImage(mCurrentRequest, flags); + UntrackImage(mPendingRequest, flags); } } diff --git a/layout/base/nsPresShell.cpp b/layout/base/nsPresShell.cpp index ab7e16fa2605..9ccc72035228 100644 --- a/layout/base/nsPresShell.cpp +++ b/layout/base/nsPresShell.cpp @@ -1153,7 +1153,7 @@ PresShell::Destroy() mUpdateImageVisibilityEvent.Revoke(); - ClearVisibleImagesList(); + ClearVisibleImagesList(/* aRequestDiscard = */ true); if (mCaret) { mCaret->Terminate(); @@ -5820,7 +5820,7 @@ PresShell::MarkImagesInListVisible(const nsDisplayList& aList) static PLDHashOperator DecrementVisibleCount(nsRefPtrHashKey* aEntry, void*) { - aEntry->GetKey()->DecrementVisibleCount(); + aEntry->GetKey()->DecrementVisibleCount(/* aRequestDiscard = */ false); return PL_DHASH_NEXT; } @@ -5844,7 +5844,7 @@ PresShell::ClearImageVisibilityVisited(nsView* aView, bool aClear) if (aClear) { PresShell* presShell = static_cast(vm->GetPresShell()); if (!presShell->mImageVisibilityVisited) { - presShell->ClearVisibleImagesList(); + presShell->ClearVisibleImagesList(/* aRequestDiscard = */ false); } presShell->mImageVisibilityVisited = false; } @@ -5853,10 +5853,20 @@ PresShell::ClearImageVisibilityVisited(nsView* aView, bool aClear) } } -void -PresShell::ClearVisibleImagesList() +static PLDHashOperator +DecrementVisibleCountAndDiscard(nsRefPtrHashKey* aEntry, + void*) { - mVisibleImages.EnumerateEntries(DecrementVisibleCount, nullptr); + aEntry->GetKey()->DecrementVisibleCount(/* aRequestDiscard = */ true); + return PL_DHASH_NEXT; +} + +void +PresShell::ClearVisibleImagesList(bool aRequestDiscard) +{ + auto enumerator = aRequestDiscard ? DecrementVisibleCountAndDiscard + : DecrementVisibleCount; + mVisibleImages.EnumerateEntries(enumerator, nullptr); mVisibleImages.Clear(); } @@ -5986,7 +5996,7 @@ PresShell::UpdateImageVisibility() // call update on that frame nsIFrame* rootFrame = GetRootFrame(); if (!rootFrame) { - ClearVisibleImagesList(); + ClearVisibleImagesList(/* aRequestDiscard = */ true); return; } @@ -6145,7 +6155,7 @@ PresShell::RemoveImageFromVisibleList(nsIImageLoadingContent* aImage) mVisibleImages.RemoveEntry(aImage); if (mVisibleImages.Count() < count) { // aImage was in the hashtable, so we need to decrement its visible count - aImage->DecrementVisibleCount(); + aImage->DecrementVisibleCount(/* aRequestDiscard = */ false); } } diff --git a/layout/base/nsPresShell.h b/layout/base/nsPresShell.h index 6080435cda96..fc17e181df34 100644 --- a/layout/base/nsPresShell.h +++ b/layout/base/nsPresShell.h @@ -735,7 +735,7 @@ protected: nsRevocableEventPtr > mUpdateImageVisibilityEvent; - void ClearVisibleImagesList(); + void ClearVisibleImagesList(bool aRequestDiscard); static void ClearImageVisibilityVisited(nsView* aView, bool aClear); static void MarkImagesInListVisible(const nsDisplayList& aList); void MarkImagesInSubtreeVisible(nsIFrame* aFrame, const nsRect& aRect); diff --git a/layout/svg/SVGFEImageFrame.cpp b/layout/svg/SVGFEImageFrame.cpp index 1b14a7dbb05a..062101a68f10 100644 --- a/layout/svg/SVGFEImageFrame.cpp +++ b/layout/svg/SVGFEImageFrame.cpp @@ -82,7 +82,7 @@ SVGFEImageFrame::DestroyFrom(nsIFrame* aDestructRoot) if (imageLoader) { imageLoader->FrameDestroyed(this); - imageLoader->DecrementVisibleCount(); + imageLoader->DecrementVisibleCount(/* aRequestDiscard = */ false); } SVGFEImageFrameBase::DestroyFrom(aDestructRoot); From f852dd0b99b17fd47192cd0baa6fc26296373bc9 Mon Sep 17 00:00:00 2001 From: Seth Fowler Date: Fri, 6 Feb 2015 02:51:12 -0800 Subject: [PATCH 03/62] Bug 1125490 (Part 2) - Use an enumeration instead of a boolean to request discarding in nsIImageLoadingContent. r=tn --- dom/base/nsIImageLoadingContent.idl | 11 ++++-- dom/base/nsImageLoadingContent.cpp | 57 ++++++++++++++++------------- dom/base/nsImageLoadingContent.h | 19 ++++++---- layout/base/nsPresShell.cpp | 25 ++++++++----- layout/base/nsPresShell.h | 2 +- layout/svg/SVGFEImageFrame.cpp | 3 +- 6 files changed, 69 insertions(+), 48 deletions(-) diff --git a/dom/base/nsIImageLoadingContent.idl b/dom/base/nsIImageLoadingContent.idl index 7b9bec251d8b..f477b67ebf31 100644 --- a/dom/base/nsIImageLoadingContent.idl +++ b/dom/base/nsIImageLoadingContent.idl @@ -172,10 +172,15 @@ interface nsIImageLoadingContent : imgINotificationObserver * A visible count is stored, if it is non-zero then this image is considered * visible. These methods increment, decrement, or return the visible count. * - * @param aRequestDiscard Whether to attempt to discard the image if its - * visibility count is now zero. + * @param aNonvisibleAction What to do if the image's visibility count is now + * zero. If ON_NONVISIBLE_NO_ACTION, nothing will be + * done. If ON_NONVISIBLE_REQUEST_DISCARD, the image + * will be asked to discard its surfaces if possible. */ [noscript, notxpcom] void IncrementVisibleCount(); - [noscript, notxpcom] void DecrementVisibleCount(in boolean aRequestDiscard); + [noscript, notxpcom] void DecrementVisibleCount(in uint32_t aNonvisibleAction); [noscript, notxpcom] uint32_t GetVisibleCount(); + + const long ON_NONVISIBLE_NO_ACTION = 0; + const long ON_NONVISIBLE_REQUEST_DISCARD = 1; }; diff --git a/dom/base/nsImageLoadingContent.cpp b/dom/base/nsImageLoadingContent.cpp index ae281ef48423..c1157d3d4d48 100644 --- a/dom/base/nsImageLoadingContent.cpp +++ b/dom/base/nsImageLoadingContent.cpp @@ -105,8 +105,8 @@ nsImageLoadingContent::DestroyImageLoadingContent() { // Cancel our requests so they won't hold stale refs to us // NB: Don't ask to discard the images here. - ClearCurrentRequest(NS_BINDING_ABORTED, 0); - ClearPendingRequest(NS_BINDING_ABORTED, 0); + ClearCurrentRequest(NS_BINDING_ABORTED, ON_NONVISIBLE_NO_ACTION); + ClearPendingRequest(NS_BINDING_ABORTED, ON_NONVISIBLE_NO_ACTION); } nsImageLoadingContent::~nsImageLoadingContent() @@ -554,7 +554,7 @@ nsImageLoadingContent::FrameDestroyed(nsIFrame* aFrame) if (aFrame->HasAnyStateBits(NS_FRAME_IN_POPUP)) { // We assume all images in popups are visible, so this decrement balances // out the increment in FrameCreated above. - DecrementVisibleCount(/* aRequestDiscard = */ false); + DecrementVisibleCount(ON_NONVISIBLE_NO_ACTION); } } @@ -777,15 +777,14 @@ nsImageLoadingContent::IncrementVisibleCount() } void -nsImageLoadingContent::DecrementVisibleCount(bool aRequestDiscard) +nsImageLoadingContent::DecrementVisibleCount(uint32_t aNonvisibleAction) { NS_ASSERTION(mVisibleCount > 0, "visible count should be positive here"); mVisibleCount--; if (mVisibleCount == 0) { - uint32_t flags = aRequestDiscard ? REQUEST_DISCARD : 0; - UntrackImage(mCurrentRequest, flags); - UntrackImage(mPendingRequest, flags); + UntrackImage(mCurrentRequest, aNonvisibleAction); + UntrackImage(mPendingRequest, aNonvisibleAction); } } @@ -1097,8 +1096,8 @@ void nsImageLoadingContent::CancelImageRequests(bool aNotify) { AutoStateChanger changer(this, aNotify); - ClearPendingRequest(NS_BINDING_ABORTED, REQUEST_DISCARD); - ClearCurrentRequest(NS_BINDING_ABORTED, REQUEST_DISCARD); + ClearPendingRequest(NS_BINDING_ABORTED, ON_NONVISIBLE_REQUEST_DISCARD); + ClearCurrentRequest(NS_BINDING_ABORTED, ON_NONVISIBLE_REQUEST_DISCARD); } nsresult @@ -1110,8 +1109,8 @@ nsImageLoadingContent::UseAsPrimaryRequest(imgRequestProxy* aRequest, AutoStateChanger changer(this, aNotify); // Get rid if our existing images - ClearPendingRequest(NS_BINDING_ABORTED, REQUEST_DISCARD); - ClearCurrentRequest(NS_BINDING_ABORTED, REQUEST_DISCARD); + ClearPendingRequest(NS_BINDING_ABORTED, ON_NONVISIBLE_REQUEST_DISCARD); + ClearCurrentRequest(NS_BINDING_ABORTED, ON_NONVISIBLE_REQUEST_DISCARD); // Clone the request we were given. nsRefPtr& req = PrepareNextRequest(aImageLoadType); @@ -1228,7 +1227,7 @@ nsImageLoadingContent::SetBlockedRequest(nsIURI* aURI, int16_t aContentDecision) // reason "image source changed". However, apparently there's some abuse // over in nsImageFrame where the displaying of the "broken" icon for the // next image depends on the cancel reason of the previous image. ugh. - ClearPendingRequest(NS_ERROR_IMAGE_BLOCKED, REQUEST_DISCARD); + ClearPendingRequest(NS_ERROR_IMAGE_BLOCKED, ON_NONVISIBLE_REQUEST_DISCARD); // For the blocked case, we only want to cancel the existing current request // if size is not available. bz says the web depends on this behavior. @@ -1236,7 +1235,7 @@ nsImageLoadingContent::SetBlockedRequest(nsIURI* aURI, int16_t aContentDecision) mImageBlockingStatus = aContentDecision; uint32_t keepFlags = mCurrentRequestFlags & REQUEST_IS_IMAGESET; - ClearCurrentRequest(NS_ERROR_IMAGE_BLOCKED, REQUEST_DISCARD); + ClearCurrentRequest(NS_ERROR_IMAGE_BLOCKED, ON_NONVISIBLE_REQUEST_DISCARD); // We still want to remember what URI we were and if it was an imageset, // despite not having an actual request. These are both cleared as part of @@ -1254,7 +1253,8 @@ nsImageLoadingContent::PrepareCurrentRequest(ImageLoadType aImageLoadType) mImageBlockingStatus = nsIContentPolicy::ACCEPT; // Get rid of anything that was there previously. - ClearCurrentRequest(NS_ERROR_IMAGE_SRC_CHANGED, REQUEST_DISCARD); + ClearCurrentRequest(NS_ERROR_IMAGE_SRC_CHANGED, + ON_NONVISIBLE_REQUEST_DISCARD); if (mNewRequestsWillNeedAnimationReset) { mCurrentRequestFlags |= REQUEST_NEEDS_ANIMATION_RESET; @@ -1272,7 +1272,8 @@ nsRefPtr& nsImageLoadingContent::PreparePendingRequest(ImageLoadType aImageLoadType) { // Get rid of anything that was there previously. - ClearPendingRequest(NS_ERROR_IMAGE_SRC_CHANGED, REQUEST_DISCARD); + ClearPendingRequest(NS_ERROR_IMAGE_SRC_CHANGED, + ON_NONVISIBLE_REQUEST_DISCARD); if (mNewRequestsWillNeedAnimationReset) { mPendingRequestFlags |= REQUEST_NEEDS_ANIMATION_RESET; @@ -1337,7 +1338,7 @@ nsImageLoadingContent::MakePendingRequestCurrent() void nsImageLoadingContent::ClearCurrentRequest(nsresult aReason, - uint32_t aFlags) + uint32_t aNonvisibleAction) { if (!mCurrentRequest) { // Even if we didn't have a current request, we might have been keeping @@ -1355,7 +1356,7 @@ nsImageLoadingContent::ClearCurrentRequest(nsresult aReason, &mCurrentRequestRegistered); // Clean up the request. - UntrackImage(mCurrentRequest, aFlags); + UntrackImage(mCurrentRequest, aNonvisibleAction); mCurrentRequest->CancelAndForgetObserver(aReason); mCurrentRequest = nullptr; mCurrentRequestFlags = 0; @@ -1363,7 +1364,7 @@ nsImageLoadingContent::ClearCurrentRequest(nsresult aReason, void nsImageLoadingContent::ClearPendingRequest(nsresult aReason, - uint32_t aFlags) + uint32_t aNonvisibleAction) { if (!mPendingRequest) return; @@ -1373,7 +1374,7 @@ nsImageLoadingContent::ClearPendingRequest(nsresult aReason, nsLayoutUtils::DeregisterImageRequest(GetFramePresContext(), mPendingRequest, &mPendingRequestRegistered); - UntrackImage(mPendingRequest, aFlags); + UntrackImage(mPendingRequest, aNonvisibleAction); mPendingRequest->CancelAndForgetObserver(aReason); mPendingRequest = nullptr; mPendingRequestFlags = 0; @@ -1473,7 +1474,9 @@ nsImageLoadingContent::TrackImage(imgIRequest* aImage) } void -nsImageLoadingContent::UntrackImage(imgIRequest* aImage, uint32_t aFlags /* = 0 */) +nsImageLoadingContent::UntrackImage(imgIRequest* aImage, + uint32_t aNonvisibleAction + /* = ON_NONVISIBLE_NO_ACTION */) { if (!aImage) return; @@ -1490,9 +1493,10 @@ nsImageLoadingContent::UntrackImage(imgIRequest* aImage, uint32_t aFlags /* = 0 if (doc && (mCurrentRequestFlags & REQUEST_IS_TRACKED)) { mCurrentRequestFlags &= ~REQUEST_IS_TRACKED; doc->RemoveImage(mCurrentRequest, - (aFlags & REQUEST_DISCARD) ? nsIDocument::REQUEST_DISCARD : 0); - } - else if (aFlags & REQUEST_DISCARD) { + (aNonvisibleAction == ON_NONVISIBLE_REQUEST_DISCARD) + ? nsIDocument::REQUEST_DISCARD + : 0); + } else if (aNonvisibleAction == ON_NONVISIBLE_REQUEST_DISCARD) { // If we're not in the document we may still need to be discarded. aImage->RequestDiscard(); } @@ -1501,9 +1505,10 @@ nsImageLoadingContent::UntrackImage(imgIRequest* aImage, uint32_t aFlags /* = 0 if (doc && (mPendingRequestFlags & REQUEST_IS_TRACKED)) { mPendingRequestFlags &= ~REQUEST_IS_TRACKED; doc->RemoveImage(mPendingRequest, - (aFlags & REQUEST_DISCARD) ? nsIDocument::REQUEST_DISCARD : 0); - } - else if (aFlags & REQUEST_DISCARD) { + (aNonvisibleAction == ON_NONVISIBLE_REQUEST_DISCARD) + ? nsIDocument::REQUEST_DISCARD + : 0); + } else if (aNonvisibleAction == ON_NONVISIBLE_REQUEST_DISCARD) { // If we're not in the document we may still need to be discarded. aImage->RequestDiscard(); } diff --git a/dom/base/nsImageLoadingContent.h b/dom/base/nsImageLoadingContent.h index 97b8c54dfd67..6719ffed6f64 100644 --- a/dom/base/nsImageLoadingContent.h +++ b/dom/base/nsImageLoadingContent.h @@ -316,9 +316,12 @@ protected: /** * Cancels and nulls-out the "current" and "pending" requests if they exist. + * + * @param aNonvisibleAction An action to take if the image is no longer + * visible as a result; see |UntrackImage|. */ - void ClearCurrentRequest(nsresult aReason, uint32_t aFlags); - void ClearPendingRequest(nsresult aReason, uint32_t aFlags); + void ClearCurrentRequest(nsresult aReason, uint32_t aNonvisibleAction); + void ClearPendingRequest(nsresult aReason, uint32_t aNonvisibleAction); /** * Retrieve a pointer to the 'registered with the refresh driver' flag for @@ -347,14 +350,14 @@ protected: * * No-op if aImage is null. * - * REQUEST_DISCARD passed to UntrackImage means we request the discard of the - * decoded data of the image. + * @param aNonvisibleAction What to do if the image's visibility count is now + * zero. If ON_NONVISIBLE_NO_ACTION, nothing will be + * done. If ON_NONVISIBLE_REQUEST_DISCARD, the image + * will be asked to discard its surfaces if possible. */ void TrackImage(imgIRequest* aImage); - enum { - REQUEST_DISCARD = 0x1 - }; - void UntrackImage(imgIRequest* aImage, uint32_t aFlags = 0); + void UntrackImage(imgIRequest* aImage, + uint32_t aNonvisibleAction = ON_NONVISIBLE_NO_ACTION); /* MEMBERS */ nsRefPtr mCurrentRequest; diff --git a/layout/base/nsPresShell.cpp b/layout/base/nsPresShell.cpp index 9ccc72035228..82f389ee7d0e 100644 --- a/layout/base/nsPresShell.cpp +++ b/layout/base/nsPresShell.cpp @@ -1153,7 +1153,7 @@ PresShell::Destroy() mUpdateImageVisibilityEvent.Revoke(); - ClearVisibleImagesList(/* aRequestDiscard = */ true); + ClearVisibleImagesList(nsIImageLoadingContent::ON_NONVISIBLE_REQUEST_DISCARD); if (mCaret) { mCaret->Terminate(); @@ -5820,7 +5820,8 @@ PresShell::MarkImagesInListVisible(const nsDisplayList& aList) static PLDHashOperator DecrementVisibleCount(nsRefPtrHashKey* aEntry, void*) { - aEntry->GetKey()->DecrementVisibleCount(/* aRequestDiscard = */ false); + aEntry->GetKey()->DecrementVisibleCount( + nsIImageLoadingContent::ON_NONVISIBLE_NO_ACTION); return PL_DHASH_NEXT; } @@ -5844,7 +5845,8 @@ PresShell::ClearImageVisibilityVisited(nsView* aView, bool aClear) if (aClear) { PresShell* presShell = static_cast(vm->GetPresShell()); if (!presShell->mImageVisibilityVisited) { - presShell->ClearVisibleImagesList(/* aRequestDiscard = */ false); + presShell->ClearVisibleImagesList( + nsIImageLoadingContent::ON_NONVISIBLE_NO_ACTION); } presShell->mImageVisibilityVisited = false; } @@ -5857,15 +5859,18 @@ static PLDHashOperator DecrementVisibleCountAndDiscard(nsRefPtrHashKey* aEntry, void*) { - aEntry->GetKey()->DecrementVisibleCount(/* aRequestDiscard = */ true); + aEntry->GetKey()->DecrementVisibleCount( + nsIImageLoadingContent::ON_NONVISIBLE_REQUEST_DISCARD); return PL_DHASH_NEXT; } void -PresShell::ClearVisibleImagesList(bool aRequestDiscard) +PresShell::ClearVisibleImagesList(uint32_t aNonvisibleAction) { - auto enumerator = aRequestDiscard ? DecrementVisibleCountAndDiscard - : DecrementVisibleCount; + auto enumerator + = aNonvisibleAction == nsIImageLoadingContent::ON_NONVISIBLE_REQUEST_DISCARD + ? DecrementVisibleCountAndDiscard + : DecrementVisibleCount; mVisibleImages.EnumerateEntries(enumerator, nullptr); mVisibleImages.Clear(); } @@ -5996,7 +6001,8 @@ PresShell::UpdateImageVisibility() // call update on that frame nsIFrame* rootFrame = GetRootFrame(); if (!rootFrame) { - ClearVisibleImagesList(/* aRequestDiscard = */ true); + ClearVisibleImagesList( + nsIImageLoadingContent::ON_NONVISIBLE_REQUEST_DISCARD); return; } @@ -6155,7 +6161,8 @@ PresShell::RemoveImageFromVisibleList(nsIImageLoadingContent* aImage) mVisibleImages.RemoveEntry(aImage); if (mVisibleImages.Count() < count) { // aImage was in the hashtable, so we need to decrement its visible count - aImage->DecrementVisibleCount(/* aRequestDiscard = */ false); + aImage->DecrementVisibleCount( + nsIImageLoadingContent::ON_NONVISIBLE_NO_ACTION); } } diff --git a/layout/base/nsPresShell.h b/layout/base/nsPresShell.h index fc17e181df34..26b7fc6fcb03 100644 --- a/layout/base/nsPresShell.h +++ b/layout/base/nsPresShell.h @@ -735,7 +735,7 @@ protected: nsRevocableEventPtr > mUpdateImageVisibilityEvent; - void ClearVisibleImagesList(bool aRequestDiscard); + void ClearVisibleImagesList(uint32_t aNonvisibleAction); static void ClearImageVisibilityVisited(nsView* aView, bool aClear); static void MarkImagesInListVisible(const nsDisplayList& aList); void MarkImagesInSubtreeVisible(nsIFrame* aFrame, const nsRect& aRect); diff --git a/layout/svg/SVGFEImageFrame.cpp b/layout/svg/SVGFEImageFrame.cpp index 062101a68f10..5758ed4681ad 100644 --- a/layout/svg/SVGFEImageFrame.cpp +++ b/layout/svg/SVGFEImageFrame.cpp @@ -82,7 +82,8 @@ SVGFEImageFrame::DestroyFrom(nsIFrame* aDestructRoot) if (imageLoader) { imageLoader->FrameDestroyed(this); - imageLoader->DecrementVisibleCount(/* aRequestDiscard = */ false); + imageLoader + ->DecrementVisibleCount(nsIImageLoadingContent::ON_NONVISIBLE_NO_ACTION); } SVGFEImageFrameBase::DestroyFrom(aDestructRoot); From f66501af2321db5b97c249cc7ef88dfadba0b903 Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Fri, 6 Feb 2015 11:06:35 +0000 Subject: [PATCH 04/62] Bug 1130041 - UNIFIED_SOURCE for BroadcastChannel, r=smaug --- dom/broadcastchannel/BroadcastChannel.cpp | 14 +++++++------- dom/broadcastchannel/moz.build | 2 +- dom/events/MessageEvent.cpp | 6 ++++++ dom/events/MessageEvent.h | 5 +---- 4 files changed, 15 insertions(+), 12 deletions(-) diff --git a/dom/broadcastchannel/BroadcastChannel.cpp b/dom/broadcastchannel/BroadcastChannel.cpp index fbd103267b95..96b7c35123d8 100644 --- a/dom/broadcastchannel/BroadcastChannel.cpp +++ b/dom/broadcastchannel/BroadcastChannel.cpp @@ -195,13 +195,13 @@ private: ErrorResult& mRv; }; -class PostMessageRunnable MOZ_FINAL : public nsICancelableRunnable +class BCPostMessageRunnable MOZ_FINAL : public nsICancelableRunnable { public: NS_DECL_ISUPPORTS - PostMessageRunnable(BroadcastChannelChild* aActor, - BroadcastChannelMessage* aData) + BCPostMessageRunnable(BroadcastChannelChild* aActor, + BroadcastChannelMessage* aData) : mActor(aActor) , mData(aData) { @@ -249,13 +249,13 @@ public: } private: - ~PostMessageRunnable() {} + ~BCPostMessageRunnable() {} nsRefPtr mActor; nsRefPtr mData; }; -NS_IMPL_ISUPPORTS(PostMessageRunnable, nsICancelableRunnable, nsIRunnable) +NS_IMPL_ISUPPORTS(BCPostMessageRunnable, nsICancelableRunnable, nsIRunnable) class CloseRunnable MOZ_FINAL : public nsICancelableRunnable { @@ -559,8 +559,8 @@ void BroadcastChannel::PostMessageData(BroadcastChannelMessage* aData) { if (mActor) { - nsRefPtr runnable = - new PostMessageRunnable(mActor, aData); + nsRefPtr runnable = + new BCPostMessageRunnable(mActor, aData); if (NS_FAILED(NS_DispatchToCurrentThread(runnable))) { NS_WARNING("Failed to dispatch to the current thread!"); diff --git a/dom/broadcastchannel/moz.build b/dom/broadcastchannel/moz.build index 01c795f8743e..6ff7e04872cf 100644 --- a/dom/broadcastchannel/moz.build +++ b/dom/broadcastchannel/moz.build @@ -8,7 +8,7 @@ EXPORTS.mozilla.dom += [ 'BroadcastChannel.h', ] -SOURCES += [ +UNIFIED_SOURCES += [ 'BroadcastChannel.cpp', 'BroadcastChannelChild.cpp', 'BroadcastChannelParent.cpp', diff --git a/dom/events/MessageEvent.cpp b/dom/events/MessageEvent.cpp index b76093ddc16d..876e99b201e2 100644 --- a/dom/events/MessageEvent.cpp +++ b/dom/events/MessageEvent.cpp @@ -200,6 +200,12 @@ MessageEvent::SetPorts(MessagePortList* aPorts) mPorts = aPorts; } +void +MessageEvent::SetSource(mozilla::dom::MessagePort* aPort) +{ + mPortSource = aPort; +} + } // namespace dom } // namespace mozilla diff --git a/dom/events/MessageEvent.h b/dom/events/MessageEvent.h index 44262455c20f..2dc8e35a5c04 100644 --- a/dom/events/MessageEvent.h +++ b/dom/events/MessageEvent.h @@ -58,10 +58,7 @@ public: void SetPorts(MessagePortList* aPorts); // Non WebIDL methods - void SetSource(mozilla::dom::MessagePort* aPort) - { - mPortSource = aPort; - } + void SetSource(mozilla::dom::MessagePort* aPort); void SetSource(nsPIDOMWindow* aWindow) { From c559f50a7b25943c8877aa7f9fcafed80f482e31 Mon Sep 17 00:00:00 2001 From: Olli Pettay Date: Fri, 6 Feb 2015 02:56:30 +0200 Subject: [PATCH 05/62] Bug 676470, ensure null-checking mCurrentTarget actually works, r=masayuki --HG-- extra : rebase_source : e07cf0b42b89ea8a9236e1519c4df43c31585bd6 --- dom/events/EventStateManager.cpp | 57 +++++++++++++++++--------------- 1 file changed, 31 insertions(+), 26 deletions(-) diff --git a/dom/events/EventStateManager.cpp b/dom/events/EventStateManager.cpp index 90935dcbc96e..f040735c2009 100644 --- a/dom/events/EventStateManager.cpp +++ b/dom/events/EventStateManager.cpp @@ -481,32 +481,9 @@ EventStateManager::PreHandleEvent(nsPresContext* aPresContext, mCurrentTarget = aTargetFrame; mCurrentTargetContent = nullptr; - // Focus events don't necessarily need a frame. - if (NS_EVENT_NEEDS_FRAME(aEvent)) { - NS_ASSERTION(mCurrentTarget, "mCurrentTarget is null. this should not happen. see bug #13007"); - if (!mCurrentTarget) return NS_ERROR_NULL_POINTER; - } -#ifdef DEBUG - if (aEvent->HasDragEventMessage() && sIsPointerLocked) { - NS_ASSERTION(sIsPointerLocked, - "sIsPointerLocked is true. Drag events should be suppressed when the pointer is locked."); - } -#endif - // Store last known screenPoint and clientPoint so pointer lock - // can use these values as constants. - WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent(); - if (aEvent->mFlags.mIsTrusted && - ((mouseEvent && mouseEvent->IsReal()) || - aEvent->mClass == eWheelEventClass) && - !sIsPointerLocked) { - sLastScreenPoint = - UIEvent::CalculateScreenPoint(aPresContext, aEvent); - sLastClientPoint = - UIEvent::CalculateClientPoint(aPresContext, aEvent, nullptr); - } - // Do not take account NS_MOUSE_ENTER/EXIT so that loading a page // when user is not active doesn't change the state to active. + WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent(); if (aEvent->mFlags.mIsTrusted && ((mouseEvent && mouseEvent->IsReal() && mouseEvent->message != NS_MOUSE_ENTER && @@ -524,10 +501,38 @@ EventStateManager::PreHandleEvent(nsPresContext* aPresContext, ++gMouseOrKeyboardEventCounter; } - *aStatus = nsEventStatus_eIgnore; - WheelTransaction::OnEvent(aEvent); + // Focus events don't necessarily need a frame. + if (NS_EVENT_NEEDS_FRAME(aEvent)) { + NS_ASSERTION(mCurrentTarget, + "mCurrentTarget is null. this should not happen. " + "see bug #13007"); + if (!mCurrentTarget) { + return NS_ERROR_NULL_POINTER; + } + } +#ifdef DEBUG + if (aEvent->HasDragEventMessage() && sIsPointerLocked) { + NS_ASSERTION(sIsPointerLocked, + "sIsPointerLocked is true. Drag events should be suppressed when " + "the pointer is locked."); + } +#endif + // Store last known screenPoint and clientPoint so pointer lock + // can use these values as constants. + if (aEvent->mFlags.mIsTrusted && + ((mouseEvent && mouseEvent->IsReal()) || + aEvent->mClass == eWheelEventClass) && + !sIsPointerLocked) { + sLastScreenPoint = + UIEvent::CalculateScreenPoint(aPresContext, aEvent); + sLastClientPoint = + UIEvent::CalculateClientPoint(aPresContext, aEvent, nullptr); + } + + *aStatus = nsEventStatus_eIgnore; + switch (aEvent->message) { case NS_CONTEXTMENU: if (sIsPointerLocked) { From a8a71dcfc4c6b61761b559579e0dad0377e24e9a Mon Sep 17 00:00:00 2001 From: Olli Pettay Date: Fri, 6 Feb 2015 12:42:23 +0200 Subject: [PATCH 06/62] Bug 1126851, window object should special case only resize event dispatched to itself, r=bz --HG-- extra : rebase_source : 759588e02d8db04c1fecdf40293545011479faaf --- dom/base/nsGlobalWindow.cpp | 10 +++++-- dom/base/test/mochitest.ini | 4 ++- dom/base/test/test_bug1126851.html | 44 ++++++++++++++++++++++++++++++ 3 files changed, 55 insertions(+), 3 deletions(-) create mode 100644 dom/base/test/test_bug1126851.html diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp index 671609e4ef8e..2e18d7405728 100644 --- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -3078,8 +3078,14 @@ nsGlobalWindow::PreHandleEvent(EventChainPreVisitor& aVisitor) gEntropyCollector->RandomUpdate((void*)&(aVisitor.mEvent->time), sizeof(uint32_t)); } - } else if (msg == NS_RESIZE_EVENT) { - mIsHandlingResizeEvent = true; + } else if (msg == NS_RESIZE_EVENT && aVisitor.mEvent->mFlags.mIsTrusted) { + // QIing to window so that we can keep the old behavior also in case + // a child window is handling resize. + nsCOMPtr window = + do_QueryInterface(aVisitor.mEvent->originalTarget); + if (window) { + mIsHandlingResizeEvent = true; + } } else if (msg == NS_MOUSE_BUTTON_DOWN && aVisitor.mEvent->mFlags.mIsTrusted) { gMouseDown = true; diff --git a/dom/base/test/mochitest.ini b/dom/base/test/mochitest.ini index 4895b6c5ea1e..d84fc5cf1212 100644 --- a/dom/base/test/mochitest.ini +++ b/dom/base/test/mochitest.ini @@ -772,4 +772,6 @@ skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s [test_window_define_nonconfigurable.html] skip-if = true # bug 1107443 - code for newly-added test was disabled [test_root_iframe.html] -[test_performance_user_timing.html] \ No newline at end of file +[test_performance_user_timing.html] +[test_bug1126851.html] +skip-if = buildapp == 'mulet' || buildapp == 'b2g' \ No newline at end of file diff --git a/dom/base/test/test_bug1126851.html b/dom/base/test/test_bug1126851.html new file mode 100644 index 000000000000..d6d7bf4a2206 --- /dev/null +++ b/dom/base/test/test_bug1126851.html @@ -0,0 +1,44 @@ + + + + + + Test for Bug 1126851 + + + + + +Mozilla Bug 1126851 +

+ +
+
+ + From 66db2826273184c61a671b6b3faec8ea40093178 Mon Sep 17 00:00:00 2001 From: Olli Pettay Date: Fri, 6 Feb 2015 12:55:24 +0200 Subject: [PATCH 07/62] Bug 1013743, MutationObserver should observe only the subtree it is attached to, r=wchen --HG-- extra : rebase_source : 34de8f6cc5e0605ffad650347ecf8bf909790ec5 --- dom/base/nsDOMMutationObserver.cpp | 44 ++++++++++---- dom/base/nsDOMMutationObserver.h | 23 ++++++-- dom/base/test/test_mutationobservers.html | 72 ++++++++++++++++++++++- 3 files changed, 120 insertions(+), 19 deletions(-) diff --git a/dom/base/nsDOMMutationObserver.cpp b/dom/base/nsDOMMutationObserver.cpp index f9e4dd0a5672..d9feb8d6b2c8 100644 --- a/dom/base/nsDOMMutationObserver.cpp +++ b/dom/base/nsDOMMutationObserver.cpp @@ -60,6 +60,13 @@ NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsDOMMutationRecord, // Observer +bool +nsMutationReceiverBase::IsObservable(nsIContent* aContent) +{ + return !aContent->ChromeOnlyAccess() && + (Observer()->IsChrome() || !aContent->IsInAnonymousSubtree()); +} + NS_IMPL_ADDREF(nsMutationReceiver) NS_IMPL_RELEASE(nsMutationReceiver) @@ -107,8 +114,7 @@ nsMutationReceiver::AttributeWillChange(nsIDocument* aDocument, int32_t aModType) { if (nsAutoMutationBatch::IsBatching() || - !ObservesAttr(aElement, aNameSpaceID, aAttribute) || - aElement->ChromeOnlyAccess()) { + !ObservesAttr(RegisterTarget(), aElement, aNameSpaceID, aAttribute)) { return; } @@ -143,14 +149,16 @@ nsMutationReceiver::CharacterDataWillChange(nsIDocument *aDocument, CharacterDataChangeInfo* aInfo) { if (nsAutoMutationBatch::IsBatching() || - !CharacterData() || !(Subtree() || aContent == Target()) || - aContent->ChromeOnlyAccess()) { + !CharacterData() || + (!Subtree() && aContent != Target()) || + (Subtree() && RegisterTarget()->SubtreeRoot() != aContent->SubtreeRoot()) || + !IsObservable(aContent)) { return; } - + nsDOMMutationRecord* m = Observer()->CurrentRecord(nsGkAtoms::characterData); - + NS_ASSERTION(!m->mTarget || m->mTarget == aContent, "Wrong target!"); @@ -169,8 +177,11 @@ nsMutationReceiver::ContentAppended(nsIDocument* aDocument, int32_t aNewIndexInContainer) { nsINode* parent = NODE_FROM(aContainer, aDocument); - bool wantsChildList = ChildList() && (Subtree() || parent == Target()); - if (!wantsChildList || aFirstNewContent->ChromeOnlyAccess()) { + bool wantsChildList = + ChildList() && + ((Subtree() && RegisterTarget()->SubtreeRoot() == parent->SubtreeRoot()) || + parent == Target()); + if (!wantsChildList || !IsObservable(aFirstNewContent)) { return; } @@ -207,8 +218,11 @@ nsMutationReceiver::ContentInserted(nsIDocument* aDocument, int32_t aIndexInContainer) { nsINode* parent = NODE_FROM(aContainer, aDocument); - bool wantsChildList = ChildList() && (Subtree() || parent == Target()); - if (!wantsChildList || aChild->ChromeOnlyAccess()) { + bool wantsChildList = + ChildList() && + ((Subtree() && RegisterTarget()->SubtreeRoot() == parent->SubtreeRoot()) || + parent == Target()); + if (!wantsChildList || !IsObservable(aChild)) { return; } @@ -239,11 +253,14 @@ nsMutationReceiver::ContentRemoved(nsIDocument* aDocument, int32_t aIndexInContainer, nsIContent* aPreviousSibling) { - if (aChild->ChromeOnlyAccess()) { + if (!IsObservable(aChild)) { return; } nsINode* parent = NODE_FROM(aContainer, aDocument); + if (Subtree() && parent->SubtreeRoot() != RegisterTarget()->SubtreeRoot()) { + return; + } if (nsAutoMutationBatch::IsBatching()) { if (nsAutoMutationBatch::IsRemovalDone()) { // This can happen for example if HTML parser parses to @@ -261,7 +278,7 @@ nsMutationReceiver::ContentRemoved(nsIDocument* aDocument, } return; - } + } if (Subtree()) { // Try to avoid creating transient observer if the node @@ -607,8 +624,9 @@ nsDOMMutationObserver::Constructor(const mozilla::dom::GlobalObject& aGlobal, return nullptr; } MOZ_ASSERT(window->IsInnerWindow()); + bool isChrome = nsContentUtils::IsChromeDoc(window->GetExtantDoc()); nsRefPtr observer = - new nsDOMMutationObserver(window.forget(), aCb); + new nsDOMMutationObserver(window.forget(), aCb, isChrome); return observer.forget(); } diff --git a/dom/base/nsDOMMutationObserver.h b/dom/base/nsDOMMutationObserver.h index c49b0afca6a7..f213ae9b23a1 100644 --- a/dom/base/nsDOMMutationObserver.h +++ b/dom/base/nsDOMMutationObserver.h @@ -216,14 +216,20 @@ protected: mRegisterTarget->OwnerDoc()->SetMayHaveDOMMutationObservers(); } - bool ObservesAttr(mozilla::dom::Element* aElement, + bool IsObservable(nsIContent* aContent); + + bool ObservesAttr(nsINode* aRegisterTarget, + mozilla::dom::Element* aElement, int32_t aNameSpaceID, nsIAtom* aAttr) { if (mParent) { - return mParent->ObservesAttr(aElement, aNameSpaceID, aAttr); + return mParent->ObservesAttr(aRegisterTarget, aElement, aNameSpaceID, aAttr); } - if (!Attributes() || (!Subtree() && aElement != Target())) { + if (!Attributes() || + (!Subtree() && aElement != Target()) || + (Subtree() && aRegisterTarget->SubtreeRoot() != aElement->SubtreeRoot()) || + !IsObservable(aElement)) { return false; } if (AllAttributes()) { @@ -342,9 +348,10 @@ class nsDOMMutationObserver MOZ_FINAL : public nsISupports, { public: nsDOMMutationObserver(already_AddRefed&& aOwner, - mozilla::dom::MutationCallback& aCb) + mozilla::dom::MutationCallback& aCb, + bool aChrome) : mOwner(aOwner), mLastPendingMutation(nullptr), mPendingMutationCount(0), - mCallback(&aCb), mWaitingForRun(false), mId(++sCount) + mCallback(&aCb), mWaitingForRun(false), mIsChrome(aChrome), mId(++sCount) { } NS_DECL_CYCLE_COLLECTING_ISUPPORTS @@ -366,6 +373,11 @@ public: return mOwner; } + bool IsChrome() + { + return mIsChrome; + } + void Observe(nsINode& aTarget, const mozilla::dom::MutationObserverInit& aOptions, mozilla::ErrorResult& aRv); @@ -462,6 +474,7 @@ protected: nsRefPtr mCallback; bool mWaitingForRun; + bool mIsChrome; uint64_t mId; diff --git a/dom/base/test/test_mutationobservers.html b/dom/base/test/test_mutationobservers.html index 657b4099edc8..af9ba88c5542 100644 --- a/dom/base/test/test_mutationobservers.html +++ b/dom/base/test/test_mutationobservers.html @@ -20,6 +20,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=641821 /** Test for Bug 641821 **/ +SimpleTest.requestFlakyTimeout("requestFlakyTimeout is silly. (But make sure marquee has time to initialize itself.)"); + var div = document.createElement("div"); var M; @@ -580,7 +582,7 @@ function testExpandos() { var m2 = new M(function(records, observer) { is(observer.expandoProperty, true); observer.disconnect(); - then(); + then(testOutsideShadowDOM); }); m2.expandoProperty = true; m2.observe(div, { attributes: true }); @@ -596,6 +598,74 @@ function testExpandos() { div.setAttribute("foo", "bar2"); } +function testOutsideShadowDOM() { + var m = new M(function(records, observer) { + is(records.length, 1); + is(records[0].type, "attributes", "Should have got attributes"); + observer.disconnect(); + then(testInsideShadowDOM); + }); + m.observe(div, { + attributes: true, + childList: true, + characterData: true, + subtree: true + }) + var sr = div.createShadowRoot(); + sr.innerHTML = "text"; + sr.firstChild.setAttribute("foo", "bar"); + sr.firstChild.firstChild.data = "text2"; + sr.firstChild.appendChild(document.createElement("div")); + div.setAttribute("foo", "bar"); +} + +function testInsideShadowDOM() { + var m = new M(function(records, observer) { + is(records.length, 4); + is(records[0].type, "childList"); + is(records[1].type, "attributes"); + is(records[2].type, "characterData"); + is(records[3].type, "childList"); + observer.disconnect(); + then(testMarquee); + }); + var sr = div.createShadowRoot(); + m.observe(sr, { + attributes: true, + childList: true, + characterData: true, + subtree: true + }); + + sr.innerHTML = "text"; + sr.firstChild.setAttribute("foo", "bar"); + sr.firstChild.firstChild.data = "text2"; + sr.firstChild.appendChild(document.createElement("div")); + div.setAttribute("foo", "bar2"); + +} + +function testMarquee() { + var m = new M(function(records, observer) { + is(records.length, 1); + is(records[0].type, "attributes"); + is(records[0].attributeName, "ok"); + is(records[0].oldValue, null); + observer.disconnect(); + then(); + }); + var marquee = document.createElement("marquee"); + m.observe(marquee, { + attributes: true, + attributeOldValue: true, + childList: true, + characterData: true, + subtree: true + }); + document.body.appendChild(marquee); + setTimeout(function() {marquee.setAttribute("ok", "ok")}, 500); +} + SimpleTest.waitForExplicitFinish(); From dc9707fc46bf9324b3635d8252942d27ace84af3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kan-Ru=20Chen=20=28=E9=99=B3=E4=BE=83=E5=A6=82=29?= Date: Fri, 6 Feb 2015 16:12:04 +0800 Subject: [PATCH 08/62] Bug 1121558 - Remove message listener after test-success. r=smaug --- .../mochitest/browserElement_Alert.js | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/dom/browser-element/mochitest/browserElement_Alert.js b/dom/browser-element/mochitest/browserElement_Alert.js index 269996bb5174..3c7c507205e8 100644 --- a/dom/browser-element/mochitest/browserElement_Alert.js +++ b/dom/browser-element/mochitest/browserElement_Alert.js @@ -109,7 +109,10 @@ function test3(e) { numPendingChildTests++; onTryAgain(); - waitForPendingTests(function() { test4(); }); + waitForPendingTests(function() { + mm.removeMessageListener('test-try-again', onTryAgain); + test4(); + }); } function test4() { @@ -240,7 +243,10 @@ function test6f() { numPendingChildTests++; onTryAgain(); - waitForPendingTests(test6g); + waitForPendingTests(function() { + mm.removeMessageListener('test-try-again', onTryAgain); + test6g(); + }); } function test6g() { @@ -269,7 +275,10 @@ function test6g() { numPendingChildTests++; onTryAgain(); - waitForPendingTests(test6h); + waitForPendingTests(function() { + mm.removeMessageListener('test-try-again', onTryAgain); + test6h(); + }); } function test6h() { From 1056f2b4d22c8b7885980807aa4eec6d221eed66 Mon Sep 17 00:00:00 2001 From: Tooru Fujisawa Date: Fri, 6 Feb 2015 22:03:01 +0900 Subject: [PATCH 09/62] Bug 1130268 - Fix NameErrors in killAndGetStack in runreftest.py. r=ted.mielczarek --- layout/tools/reftest/runreftest.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/layout/tools/reftest/runreftest.py b/layout/tools/reftest/runreftest.py index 00dac3613bf6..cfe60ef27afb 100644 --- a/layout/tools/reftest/runreftest.py +++ b/layout/tools/reftest/runreftest.py @@ -24,6 +24,7 @@ sys.path.insert(0, SCRIPT_DIRECTORY) from automationutils import ( dumpScreen, environment, + printstatus, processLeakLog ) import mozcrash @@ -394,13 +395,13 @@ class RefTest(object): return else: try: - proc.kill(sig=signal.SIGABRT) + process.kill(sig=signal.SIGABRT) except OSError: # https://bugzilla.mozilla.org/show_bug.cgi?id=921509 log.info("Can't trigger Breakpad, process no longer exists") return log.info("Can't trigger Breakpad, just killing process") - proc.kill() + process.kill() ### output processing From 4f128ac3e171db7796015f0937501a63829e5ae6 Mon Sep 17 00:00:00 2001 From: Valentin Gosu Date: Fri, 6 Feb 2015 15:27:33 +0200 Subject: [PATCH 10/62] Bug 1120216 - Add telemetry for how often URLs contain !/ or !// or end with a ! r=mcmanus --- netwerk/base/nsIOService.cpp | 27 ++++++++++++++++++++ netwerk/base/nsIOService.h | 2 ++ toolkit/components/telemetry/Histograms.json | 15 +++++++++++ 3 files changed, 44 insertions(+) diff --git a/netwerk/base/nsIOService.cpp b/netwerk/base/nsIOService.cpp index d607ab509bd9..d77847db8de9 100644 --- a/netwerk/base/nsIOService.cpp +++ b/netwerk/base/nsIOService.cpp @@ -42,6 +42,7 @@ #include "nsThreadUtils.h" #include "mozilla/LoadInfo.h" #include "mozilla/net/NeckoCommon.h" +#include "mozilla/Telemetry.h" #ifdef MOZ_WIDGET_GONK #include "nsINetworkManager.h" @@ -148,6 +149,8 @@ static const char kNetworkActiveChanged[] = "network-active-changed"; uint32_t nsIOService::gDefaultSegmentSize = 4096; uint32_t nsIOService::gDefaultSegmentCount = 24; +bool nsIOService::sTelemetryEnabled = false; + NS_IMPL_ISUPPORTS(nsAppOfflineInfo, nsIAppOfflineInfo) //////////////////////////////////////////////////////////////////////////////// @@ -222,6 +225,8 @@ nsIOService::Init() else NS_WARNING("failed to get observer service"); + Preferences::AddBoolVarCache(&sTelemetryEnabled, "toolkit.telemetry.enabled", false); + gIOService = this; InitializeNetworkLinkService(); @@ -634,6 +639,28 @@ nsIOService::NewChannelFromURIWithProxyFlagsInternal(nsIURI* aURI, if (NS_FAILED(rv)) return rv; + if (sTelemetryEnabled) { + nsAutoCString path; + aURI->GetPath(path); + + bool endsInExcl = StringEndsWith(path, NS_LITERAL_CSTRING("!")); + int32_t bangSlashPos = path.Find("!/"); + + bool hasBangSlash = bangSlashPos != kNotFound; + bool hasBangDoubleSlash = false; + + if (bangSlashPos != kNotFound) { + nsDependentCSubstring substr(path, bangSlashPos); + hasBangDoubleSlash = StringBeginsWith(substr, NS_LITERAL_CSTRING("!//")); + } + + Telemetry::Accumulate(Telemetry::URL_PATH_ENDS_IN_EXCLAMATION, endsInExcl); + Telemetry::Accumulate(Telemetry::URL_PATH_CONTAINS_EXCLAMATION_SLASH, + hasBangSlash); + Telemetry::Accumulate(Telemetry::URL_PATH_CONTAINS_EXCLAMATION_DOUBLE_SLASH, + hasBangDoubleSlash); + } + nsCOMPtr handler; rv = GetProtocolHandler(scheme.get(), getter_AddRefs(handler)); if (NS_FAILED(rv)) diff --git a/netwerk/base/nsIOService.h b/netwerk/base/nsIOService.h index d91d7919dccc..23b3705437c9 100644 --- a/netwerk/base/nsIOService.h +++ b/netwerk/base/nsIOService.h @@ -154,6 +154,8 @@ private: // Hashtable of (appId, nsIAppOffineInfo::mode) pairs // that is used especially in IsAppOffline nsDataHashtable mAppsOfflineStatus; + + static bool sTelemetryEnabled; public: // Used for all default buffer sizes that necko allocates. static uint32_t gDefaultSegmentSize; diff --git a/toolkit/components/telemetry/Histograms.json b/toolkit/components/telemetry/Histograms.json index 470da09838cc..d6c7bc593b37 100644 --- a/toolkit/components/telemetry/Histograms.json +++ b/toolkit/components/telemetry/Histograms.json @@ -2431,6 +2431,21 @@ "extended_statistics_ok": true, "description": "How many speculative connections are made needlessly" }, + "URL_PATH_ENDS_IN_EXCLAMATION": { + "expires_in_version": "never", + "kind": "boolean", + "description": "The URL path ends in !" + }, + "URL_PATH_CONTAINS_EXCLAMATION_SLASH": { + "expires_in_version": "never", + "kind": "boolean", + "description": "The URL path contains !/" + }, + "URL_PATH_CONTAINS_EXCLAMATION_DOUBLE_SLASH": { + "expires_in_version": "never", + "kind": "boolean", + "description": "The URL path contains !//" + }, "FIND_PLUGINS": { "alert_emails": ["perf-telemetry-alerts@mozilla.com"], "expires_in_version": "40", From 42e9590fcf202f3c9a2c7d92a307e96e8de3360a Mon Sep 17 00:00:00 2001 From: Ryan VanderMeulen Date: Fri, 6 Feb 2015 09:07:25 -0500 Subject: [PATCH 11/62] Backed out changeset 2ad2c849f0be (bug 1013743) for Gij failures. --- dom/base/nsDOMMutationObserver.cpp | 44 ++++---------- dom/base/nsDOMMutationObserver.h | 23 ++------ dom/base/test/test_mutationobservers.html | 72 +---------------------- 3 files changed, 19 insertions(+), 120 deletions(-) diff --git a/dom/base/nsDOMMutationObserver.cpp b/dom/base/nsDOMMutationObserver.cpp index d9feb8d6b2c8..f9e4dd0a5672 100644 --- a/dom/base/nsDOMMutationObserver.cpp +++ b/dom/base/nsDOMMutationObserver.cpp @@ -60,13 +60,6 @@ NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsDOMMutationRecord, // Observer -bool -nsMutationReceiverBase::IsObservable(nsIContent* aContent) -{ - return !aContent->ChromeOnlyAccess() && - (Observer()->IsChrome() || !aContent->IsInAnonymousSubtree()); -} - NS_IMPL_ADDREF(nsMutationReceiver) NS_IMPL_RELEASE(nsMutationReceiver) @@ -114,7 +107,8 @@ nsMutationReceiver::AttributeWillChange(nsIDocument* aDocument, int32_t aModType) { if (nsAutoMutationBatch::IsBatching() || - !ObservesAttr(RegisterTarget(), aElement, aNameSpaceID, aAttribute)) { + !ObservesAttr(aElement, aNameSpaceID, aAttribute) || + aElement->ChromeOnlyAccess()) { return; } @@ -149,16 +143,14 @@ nsMutationReceiver::CharacterDataWillChange(nsIDocument *aDocument, CharacterDataChangeInfo* aInfo) { if (nsAutoMutationBatch::IsBatching() || - !CharacterData() || - (!Subtree() && aContent != Target()) || - (Subtree() && RegisterTarget()->SubtreeRoot() != aContent->SubtreeRoot()) || - !IsObservable(aContent)) { + !CharacterData() || !(Subtree() || aContent == Target()) || + aContent->ChromeOnlyAccess()) { return; } - + nsDOMMutationRecord* m = Observer()->CurrentRecord(nsGkAtoms::characterData); - + NS_ASSERTION(!m->mTarget || m->mTarget == aContent, "Wrong target!"); @@ -177,11 +169,8 @@ nsMutationReceiver::ContentAppended(nsIDocument* aDocument, int32_t aNewIndexInContainer) { nsINode* parent = NODE_FROM(aContainer, aDocument); - bool wantsChildList = - ChildList() && - ((Subtree() && RegisterTarget()->SubtreeRoot() == parent->SubtreeRoot()) || - parent == Target()); - if (!wantsChildList || !IsObservable(aFirstNewContent)) { + bool wantsChildList = ChildList() && (Subtree() || parent == Target()); + if (!wantsChildList || aFirstNewContent->ChromeOnlyAccess()) { return; } @@ -218,11 +207,8 @@ nsMutationReceiver::ContentInserted(nsIDocument* aDocument, int32_t aIndexInContainer) { nsINode* parent = NODE_FROM(aContainer, aDocument); - bool wantsChildList = - ChildList() && - ((Subtree() && RegisterTarget()->SubtreeRoot() == parent->SubtreeRoot()) || - parent == Target()); - if (!wantsChildList || !IsObservable(aChild)) { + bool wantsChildList = ChildList() && (Subtree() || parent == Target()); + if (!wantsChildList || aChild->ChromeOnlyAccess()) { return; } @@ -253,14 +239,11 @@ nsMutationReceiver::ContentRemoved(nsIDocument* aDocument, int32_t aIndexInContainer, nsIContent* aPreviousSibling) { - if (!IsObservable(aChild)) { + if (aChild->ChromeOnlyAccess()) { return; } nsINode* parent = NODE_FROM(aContainer, aDocument); - if (Subtree() && parent->SubtreeRoot() != RegisterTarget()->SubtreeRoot()) { - return; - } if (nsAutoMutationBatch::IsBatching()) { if (nsAutoMutationBatch::IsRemovalDone()) { // This can happen for example if HTML parser parses to @@ -278,7 +261,7 @@ nsMutationReceiver::ContentRemoved(nsIDocument* aDocument, } return; - } + } if (Subtree()) { // Try to avoid creating transient observer if the node @@ -624,9 +607,8 @@ nsDOMMutationObserver::Constructor(const mozilla::dom::GlobalObject& aGlobal, return nullptr; } MOZ_ASSERT(window->IsInnerWindow()); - bool isChrome = nsContentUtils::IsChromeDoc(window->GetExtantDoc()); nsRefPtr observer = - new nsDOMMutationObserver(window.forget(), aCb, isChrome); + new nsDOMMutationObserver(window.forget(), aCb); return observer.forget(); } diff --git a/dom/base/nsDOMMutationObserver.h b/dom/base/nsDOMMutationObserver.h index f213ae9b23a1..c49b0afca6a7 100644 --- a/dom/base/nsDOMMutationObserver.h +++ b/dom/base/nsDOMMutationObserver.h @@ -216,20 +216,14 @@ protected: mRegisterTarget->OwnerDoc()->SetMayHaveDOMMutationObservers(); } - bool IsObservable(nsIContent* aContent); - - bool ObservesAttr(nsINode* aRegisterTarget, - mozilla::dom::Element* aElement, + bool ObservesAttr(mozilla::dom::Element* aElement, int32_t aNameSpaceID, nsIAtom* aAttr) { if (mParent) { - return mParent->ObservesAttr(aRegisterTarget, aElement, aNameSpaceID, aAttr); + return mParent->ObservesAttr(aElement, aNameSpaceID, aAttr); } - if (!Attributes() || - (!Subtree() && aElement != Target()) || - (Subtree() && aRegisterTarget->SubtreeRoot() != aElement->SubtreeRoot()) || - !IsObservable(aElement)) { + if (!Attributes() || (!Subtree() && aElement != Target())) { return false; } if (AllAttributes()) { @@ -348,10 +342,9 @@ class nsDOMMutationObserver MOZ_FINAL : public nsISupports, { public: nsDOMMutationObserver(already_AddRefed&& aOwner, - mozilla::dom::MutationCallback& aCb, - bool aChrome) + mozilla::dom::MutationCallback& aCb) : mOwner(aOwner), mLastPendingMutation(nullptr), mPendingMutationCount(0), - mCallback(&aCb), mWaitingForRun(false), mIsChrome(aChrome), mId(++sCount) + mCallback(&aCb), mWaitingForRun(false), mId(++sCount) { } NS_DECL_CYCLE_COLLECTING_ISUPPORTS @@ -373,11 +366,6 @@ public: return mOwner; } - bool IsChrome() - { - return mIsChrome; - } - void Observe(nsINode& aTarget, const mozilla::dom::MutationObserverInit& aOptions, mozilla::ErrorResult& aRv); @@ -474,7 +462,6 @@ protected: nsRefPtr mCallback; bool mWaitingForRun; - bool mIsChrome; uint64_t mId; diff --git a/dom/base/test/test_mutationobservers.html b/dom/base/test/test_mutationobservers.html index af9ba88c5542..657b4099edc8 100644 --- a/dom/base/test/test_mutationobservers.html +++ b/dom/base/test/test_mutationobservers.html @@ -20,8 +20,6 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=641821 /** Test for Bug 641821 **/ -SimpleTest.requestFlakyTimeout("requestFlakyTimeout is silly. (But make sure marquee has time to initialize itself.)"); - var div = document.createElement("div"); var M; @@ -582,7 +580,7 @@ function testExpandos() { var m2 = new M(function(records, observer) { is(observer.expandoProperty, true); observer.disconnect(); - then(testOutsideShadowDOM); + then(); }); m2.expandoProperty = true; m2.observe(div, { attributes: true }); @@ -598,74 +596,6 @@ function testExpandos() { div.setAttribute("foo", "bar2"); } -function testOutsideShadowDOM() { - var m = new M(function(records, observer) { - is(records.length, 1); - is(records[0].type, "attributes", "Should have got attributes"); - observer.disconnect(); - then(testInsideShadowDOM); - }); - m.observe(div, { - attributes: true, - childList: true, - characterData: true, - subtree: true - }) - var sr = div.createShadowRoot(); - sr.innerHTML = "text"; - sr.firstChild.setAttribute("foo", "bar"); - sr.firstChild.firstChild.data = "text2"; - sr.firstChild.appendChild(document.createElement("div")); - div.setAttribute("foo", "bar"); -} - -function testInsideShadowDOM() { - var m = new M(function(records, observer) { - is(records.length, 4); - is(records[0].type, "childList"); - is(records[1].type, "attributes"); - is(records[2].type, "characterData"); - is(records[3].type, "childList"); - observer.disconnect(); - then(testMarquee); - }); - var sr = div.createShadowRoot(); - m.observe(sr, { - attributes: true, - childList: true, - characterData: true, - subtree: true - }); - - sr.innerHTML = "text"; - sr.firstChild.setAttribute("foo", "bar"); - sr.firstChild.firstChild.data = "text2"; - sr.firstChild.appendChild(document.createElement("div")); - div.setAttribute("foo", "bar2"); - -} - -function testMarquee() { - var m = new M(function(records, observer) { - is(records.length, 1); - is(records[0].type, "attributes"); - is(records[0].attributeName, "ok"); - is(records[0].oldValue, null); - observer.disconnect(); - then(); - }); - var marquee = document.createElement("marquee"); - m.observe(marquee, { - attributes: true, - attributeOldValue: true, - childList: true, - characterData: true, - subtree: true - }); - document.body.appendChild(marquee); - setTimeout(function() {marquee.setAttribute("ok", "ok")}, 500); -} - SimpleTest.waitForExplicitFinish(); From 51f70d5456a2cf1f852ae616306992c3389c9fc4 Mon Sep 17 00:00:00 2001 From: Ryan VanderMeulen Date: Fri, 6 Feb 2015 09:07:39 -0500 Subject: [PATCH 12/62] Backed out changeset 900bd9173e8f (bug 676470) for mochitest-other asserts. CLOSED TREE --- dom/events/EventStateManager.cpp | 57 +++++++++++++++----------------- 1 file changed, 26 insertions(+), 31 deletions(-) diff --git a/dom/events/EventStateManager.cpp b/dom/events/EventStateManager.cpp index f040735c2009..90935dcbc96e 100644 --- a/dom/events/EventStateManager.cpp +++ b/dom/events/EventStateManager.cpp @@ -481,9 +481,32 @@ EventStateManager::PreHandleEvent(nsPresContext* aPresContext, mCurrentTarget = aTargetFrame; mCurrentTargetContent = nullptr; + // Focus events don't necessarily need a frame. + if (NS_EVENT_NEEDS_FRAME(aEvent)) { + NS_ASSERTION(mCurrentTarget, "mCurrentTarget is null. this should not happen. see bug #13007"); + if (!mCurrentTarget) return NS_ERROR_NULL_POINTER; + } +#ifdef DEBUG + if (aEvent->HasDragEventMessage() && sIsPointerLocked) { + NS_ASSERTION(sIsPointerLocked, + "sIsPointerLocked is true. Drag events should be suppressed when the pointer is locked."); + } +#endif + // Store last known screenPoint and clientPoint so pointer lock + // can use these values as constants. + WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent(); + if (aEvent->mFlags.mIsTrusted && + ((mouseEvent && mouseEvent->IsReal()) || + aEvent->mClass == eWheelEventClass) && + !sIsPointerLocked) { + sLastScreenPoint = + UIEvent::CalculateScreenPoint(aPresContext, aEvent); + sLastClientPoint = + UIEvent::CalculateClientPoint(aPresContext, aEvent, nullptr); + } + // Do not take account NS_MOUSE_ENTER/EXIT so that loading a page // when user is not active doesn't change the state to active. - WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent(); if (aEvent->mFlags.mIsTrusted && ((mouseEvent && mouseEvent->IsReal() && mouseEvent->message != NS_MOUSE_ENTER && @@ -501,38 +524,10 @@ EventStateManager::PreHandleEvent(nsPresContext* aPresContext, ++gMouseOrKeyboardEventCounter; } - WheelTransaction::OnEvent(aEvent); - - // Focus events don't necessarily need a frame. - if (NS_EVENT_NEEDS_FRAME(aEvent)) { - NS_ASSERTION(mCurrentTarget, - "mCurrentTarget is null. this should not happen. " - "see bug #13007"); - if (!mCurrentTarget) { - return NS_ERROR_NULL_POINTER; - } - } -#ifdef DEBUG - if (aEvent->HasDragEventMessage() && sIsPointerLocked) { - NS_ASSERTION(sIsPointerLocked, - "sIsPointerLocked is true. Drag events should be suppressed when " - "the pointer is locked."); - } -#endif - // Store last known screenPoint and clientPoint so pointer lock - // can use these values as constants. - if (aEvent->mFlags.mIsTrusted && - ((mouseEvent && mouseEvent->IsReal()) || - aEvent->mClass == eWheelEventClass) && - !sIsPointerLocked) { - sLastScreenPoint = - UIEvent::CalculateScreenPoint(aPresContext, aEvent); - sLastClientPoint = - UIEvent::CalculateClientPoint(aPresContext, aEvent, nullptr); - } - *aStatus = nsEventStatus_eIgnore; + WheelTransaction::OnEvent(aEvent); + switch (aEvent->message) { case NS_CONTEXTMENU: if (sIsPointerLocked) { From e5332a20fd9ab479acf4a2699b693589b5ca9222 Mon Sep 17 00:00:00 2001 From: Ryan VanderMeulen Date: Fri, 6 Feb 2015 10:00:50 -0500 Subject: [PATCH 13/62] Bug 1128229 - Add more fuzz on Win8. CLOSED TREE --- layout/reftests/bugs/reftest.list | 2 +- layout/reftests/image/reftest.list | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/layout/reftests/bugs/reftest.list b/layout/reftests/bugs/reftest.list index aca1a94d7810..9cd4554068d0 100644 --- a/layout/reftests/bugs/reftest.list +++ b/layout/reftests/bugs/reftest.list @@ -938,7 +938,7 @@ fuzzy-if(Android,13,9) == 407111-1.html 407111-1-ref.html # Bug 1128229 fuzzy-if(winWidget,123,1600) == 409659-1a.html 409659-1-ref.html # Bug 1128229 != 409659-1b.html 409659-1-ref.html fails-if(Android&&AndroidVersion>=15&&smallScreen&&AndroidVersion!=17) != 409659-1c.html 409659-1-ref.html #there is no difference in the visible area of the screen -fuzzy-if(winWidget,123,1600) == 409659-1d.html 409659-1-ref.html # Bug 1128229 +fuzzy-if(winWidget,123,1900) == 409659-1d.html 409659-1-ref.html # Bug 1128229 == 410621-1.html 410621-1-ref.html == 411059-1.html 411059-1-ref.html == 411334-1.xml 411334-1-ref.xml diff --git a/layout/reftests/image/reftest.list b/layout/reftests/image/reftest.list index 610e1513cc62..23f0de52802b 100644 --- a/layout/reftests/image/reftest.list +++ b/layout/reftests/image/reftest.list @@ -17,7 +17,7 @@ test-pref(layout.css.object-fit-and-position.enabled,true) == image-object-fit-w test-pref(layout.css.object-fit-and-position.enabled,true) == image-object-fit-with-background-2.html image-object-fit-with-background-2-ref.html test-pref(layout.css.object-fit-and-position.enabled,true) == image-object-position-dyn-1.html image-object-position-dyn-1-ref.html test-pref(layout.css.object-fit-and-position.enabled,true) == image-object-position-with-background-1.html image-object-position-with-background-1-ref.html -test-pref(layout.css.object-fit-and-position.enabled,true) fuzzy-if(winWidget,100,198) == image-object-position-with-background-2.html image-object-position-with-background-2-ref.html # Bug 1128229 +test-pref(layout.css.object-fit-and-position.enabled,true) fuzzy-if(winWidget,117,242) == image-object-position-with-background-2.html image-object-position-with-background-2-ref.html # Bug 1128229 # Tests for image-orientation used with 'from-image' (note that all # image-orientation tests are fuzzy because the JPEG images do not perfectly From 7ef22b742222cf88a9e88c4f4a233fa086bf0283 Mon Sep 17 00:00:00 2001 From: Ryan VanderMeulen Date: Fri, 6 Feb 2015 10:38:00 -0500 Subject: [PATCH 14/62] Bug 1128229 - Add a bit more fuzz to image-object-position-with-background-2.html on Windows. CLOSED TREE --- layout/reftests/image/reftest.list | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/layout/reftests/image/reftest.list b/layout/reftests/image/reftest.list index 23f0de52802b..4e58605809b6 100644 --- a/layout/reftests/image/reftest.list +++ b/layout/reftests/image/reftest.list @@ -17,7 +17,7 @@ test-pref(layout.css.object-fit-and-position.enabled,true) == image-object-fit-w test-pref(layout.css.object-fit-and-position.enabled,true) == image-object-fit-with-background-2.html image-object-fit-with-background-2-ref.html test-pref(layout.css.object-fit-and-position.enabled,true) == image-object-position-dyn-1.html image-object-position-dyn-1-ref.html test-pref(layout.css.object-fit-and-position.enabled,true) == image-object-position-with-background-1.html image-object-position-with-background-1-ref.html -test-pref(layout.css.object-fit-and-position.enabled,true) fuzzy-if(winWidget,117,242) == image-object-position-with-background-2.html image-object-position-with-background-2-ref.html # Bug 1128229 +test-pref(layout.css.object-fit-and-position.enabled,true) fuzzy-if(winWidget,117,374) == image-object-position-with-background-2.html image-object-position-with-background-2-ref.html # Bug 1128229 # Tests for image-orientation used with 'from-image' (note that all # image-orientation tests are fuzzy because the JPEG images do not perfectly From 6be44da368fb869a3d3e1975f515857352a7d9fc Mon Sep 17 00:00:00 2001 From: Avi Halachmi Date: Fri, 6 Feb 2015 16:02:37 +0200 Subject: [PATCH 15/62] Bug 1120650: add telemetry probe for slow script notices. r=vladan, r=billm --- browser/modules/ProcessHangMonitor.jsm | 11 +++++++++++ dom/base/nsGlobalWindow.cpp | 4 ++++ toolkit/components/telemetry/Histograms.json | 12 ++++++++++++ 3 files changed, 27 insertions(+) diff --git a/browser/modules/ProcessHangMonitor.jsm b/browser/modules/ProcessHangMonitor.jsm index a175e1d1f6b8..c12964aaa8a9 100644 --- a/browser/modules/ProcessHangMonitor.jsm +++ b/browser/modules/ProcessHangMonitor.jsm @@ -278,6 +278,17 @@ let ProcessHangMonitor = { return; } + // On e10s this counts slow-script/hanged-plugin notice only once. + // This code is not reached on non-e10s. + if (report.hangType == report.SLOW_SCRIPT) { + // On non-e10s, SLOW_SCRIPT_NOTICE_COUNT is probed at nsGlobalWindow.cpp + Services.telemetry.getHistogramById("SLOW_SCRIPT_NOTICE_COUNT").add(); + } else if (report.hangType == report.PLUGIN_HANG) { + // On non-e10s we have sufficient plugin telemetry probes, + // so PLUGIN_HANG_NOTICE_COUNT is only probed on e10s. + Services.telemetry.getHistogramById("PLUGIN_HANG_NOTICE_COUNT").add(); + } + // Otherwise create a new timer and display the report. let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); timer.initWithCallback(this, HANG_EXPIRATION_TIME, timer.TYPE_ONE_SHOT); diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp index 2e18d7405728..cf614604dec8 100644 --- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -11024,6 +11024,10 @@ nsGlobalWindow::ShowSlowScriptDialog() return ContinueSlowScriptAndKeepNotifying; } + // Reached only on non-e10s - once per slow script dialog. + // On e10s - we probe once at ProcessHangsMonitor.jsm + Telemetry::Accumulate(Telemetry::SLOW_SCRIPT_NOTICE_COUNT, 1); + // Get the nsIPrompt interface from the docshell nsCOMPtr ds = GetDocShell(); NS_ENSURE_TRUE(ds, KillSlowScript); diff --git a/toolkit/components/telemetry/Histograms.json b/toolkit/components/telemetry/Histograms.json index d6c7bc593b37..1b1625809e25 100644 --- a/toolkit/components/telemetry/Histograms.json +++ b/toolkit/components/telemetry/Histograms.json @@ -7373,5 +7373,17 @@ "expires_in_version": "45", "kind": "count", "description": "The number of Sync 1.5 migrations completed by Android Sync." + }, + "SLOW_SCRIPT_NOTICE_COUNT": { + "alert_emails": ["perf-telemetry-alerts@mozilla.com"], + "expires_in_version": "never", + "kind": "count", + "description": "Count slow script notices" + }, + "PLUGIN_HANG_NOTICE_COUNT": { + "alert_emails": ["perf-telemetry-alerts@mozilla.com"], + "expires_in_version": "never", + "kind": "count", + "description": "Count plugin hang notices in e10s" } } From d2c796ffbe7cd644929e3d688d8fad04140ef6b8 Mon Sep 17 00:00:00 2001 From: Chris AtLee Date: Fri, 6 Feb 2015 09:31:18 -0500 Subject: [PATCH 16/62] Bug 1126944: Follow symlinks when removing .pyc from test packages r=ted --HG-- extra : rebase_source : 3b05d11cd42c7ff23e6467d6fcf2b641dcebd908 --- testing/testsuite-targets.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testing/testsuite-targets.mk b/testing/testsuite-targets.mk index 3793c3d7595a..ae6b8f402f44 100644 --- a/testing/testsuite-targets.mk +++ b/testing/testsuite-targets.mk @@ -419,7 +419,7 @@ package-tests: ifndef UNIVERSAL_BINARY $(NSINSTALL) -D $(DIST)/$(PKG_PATH) endif - find $(PKG_STAGE) -name '*.pyc' -exec rm {} \; + find -L $(PKG_STAGE) -name '*.pyc' -exec rm {} \; $(MKDIR) -p $(abspath $(DIST))/$(PKG_PATH) && \ cd $(PKG_STAGE) && \ zip -rq9D '$(abspath $(DIST))/$(PKG_PATH)$(TEST_PACKAGE)' \ From 811d8614fd9266b1694be8462541d645a939b13c Mon Sep 17 00:00:00 2001 From: Tom Schuster Date: Fri, 6 Feb 2015 15:43:20 +0100 Subject: [PATCH 17/62] Bug 1124935 - Remove LookupProperty from JS_GetPropertyDescriptor. r=efaust,bz --- dom/html/test/test_bug1081037.html | 11 +---- js/src/asmjs/AsmJSLink.cpp | 4 +- js/src/jsapi-tests/moz.build | 1 + .../jsapi-tests/testGetPropertyDescriptor.cpp | 32 ++++++++++++++ js/src/jsapi.cpp | 42 +------------------ js/src/jsiter.cpp | 4 +- js/src/jsobj.cpp | 24 +++++++++++ js/src/jsobj.h | 4 ++ js/src/proxy/DirectProxyHandler.cpp | 2 +- js/src/proxy/Proxy.cpp | 2 +- js/src/proxy/ScriptedDirectProxyHandler.cpp | 2 +- 11 files changed, 70 insertions(+), 58 deletions(-) create mode 100644 js/src/jsapi-tests/testGetPropertyDescriptor.cpp diff --git a/dom/html/test/test_bug1081037.html b/dom/html/test/test_bug1081037.html index 783e8557c561..9d878258023d 100644 --- a/dom/html/test/test_bug1081037.html +++ b/dom/html/test/test_bug1081037.html @@ -96,7 +96,6 @@ shouldThrow(function() { var getOwn = 0; var defineProp = 0; -var _has = 0; var handler2 = { getOwnPropertyDescriptor: function(target, name) { if (name == "constructor") { @@ -109,12 +108,6 @@ var handler2 = { defineProp++; } return Object.defineProperty(target, name, propertyDescriptor); - }, - has: function(target, name) { - if (name == "constructor") { - _has++; - } - return name in target; } }; var proxy2 = new Proxy({}, handler2); @@ -125,8 +118,6 @@ document.registerElement('x-proxymagic2', { is(getOwn, 1, "number of getOwnPropertyDescriptor calls from registerElement: " + getOwn); is(defineProp, 1, "number of defineProperty calls from registerElement: " + defineProp); -is(_has, 1, "number of 'has' calls from registerElement: " + _has); - @@ -139,4 +130,4 @@ is(_has, 1, "number of 'has' calls from registerElement: " + _has);
 
- \ No newline at end of file + diff --git a/js/src/asmjs/AsmJSLink.cpp b/js/src/asmjs/AsmJSLink.cpp index 42457b9a65d0..94a4cedc337a 100644 --- a/js/src/asmjs/AsmJSLink.cpp +++ b/js/src/asmjs/AsmJSLink.cpp @@ -88,9 +88,9 @@ GetDataProperty(JSContext *cx, HandleValue objVal, HandlePropertyName field, Mut if (IsScriptedProxy(obj)) return LinkFail(cx, "accessing property of a Proxy"); - Rooted desc(cx); + Rooted desc(cx); RootedId id(cx, NameToId(field)); - if (!JS_GetPropertyDescriptorById(cx, obj, id, &desc)) + if (!GetPropertyDescriptor(cx, obj, id, &desc)) return false; if (!desc.object()) diff --git a/js/src/jsapi-tests/moz.build b/js/src/jsapi-tests/moz.build index 9babe2350778..0f2c4d65ab49 100644 --- a/js/src/jsapi-tests/moz.build +++ b/js/src/jsapi-tests/moz.build @@ -43,6 +43,7 @@ UNIFIED_SOURCES += [ 'testGCNursery.cpp', 'testGCOutOfMemory.cpp', 'testGCStoreBufferRemoval.cpp', + 'testGetPropertyDescriptor.cpp', 'testHashTable.cpp', 'testHashTableInit.cpp', 'testIndexToString.cpp', diff --git a/js/src/jsapi-tests/testGetPropertyDescriptor.cpp b/js/src/jsapi-tests/testGetPropertyDescriptor.cpp new file mode 100644 index 000000000000..3cc4def91a87 --- /dev/null +++ b/js/src/jsapi-tests/testGetPropertyDescriptor.cpp @@ -0,0 +1,32 @@ +/* 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 "jsapi-tests/tests.h" + +BEGIN_TEST(test_GetPropertyDescriptor) +{ + JS::RootedValue v(cx); + EVAL("({ somename : 123 })", &v); + CHECK(v.isObject()); + + JS::RootedObject obj(cx, &v.toObject()); + JS::Rooted desc(cx); + + CHECK(JS_GetPropertyDescriptor(cx, obj, "somename", &desc)); + CHECK_EQUAL(desc.object(), obj); + CHECK_SAME(desc.value(), JS::Int32Value(123)); + + CHECK(JS_GetPropertyDescriptor(cx, obj, "not-here", &desc)); + CHECK_EQUAL(desc.object(), nullptr); + + CHECK(JS_GetPropertyDescriptor(cx, obj, "toString", &desc)); + JS::RootedObject objectProto(cx, JS_GetObjectPrototype(cx, obj)); + CHECK(objectProto); + CHECK_EQUAL(desc.object(), objectProto); + CHECK(desc.value().isObject()); + CHECK(JS::IsCallable(&desc.value().toObject())); + + return true; +} +END_TEST(test_GetPropertyDescriptor) diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 8c003eb47dbd..d8978e6ca012 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -2624,46 +2624,6 @@ JS::ParsePropertyDescriptorObject(JSContext *cx, return true; } -static bool -GetPropertyDescriptorById(JSContext *cx, HandleObject obj, HandleId id, - MutableHandle desc) -{ - RootedObject obj2(cx); - RootedShape shape(cx); - - if (!LookupProperty(cx, obj, id, &obj2, &shape)) - return false; - - desc.clear(); - if (!shape) - return true; - - desc.object().set(obj2); - if (obj2->isNative()) { - if (IsImplicitDenseOrTypedArrayElement(shape)) { - desc.setEnumerable(); - desc.value().set(obj2->as().getDenseOrTypedArrayElement(JSID_TO_INT(id))); - } else { - desc.setAttributes(shape->attributes()); - desc.setGetter(shape->getter()); - desc.setSetter(shape->setter()); - MOZ_ASSERT(desc.value().isUndefined()); - if (shape->hasSlot()) - desc.value().set(obj2->as().getSlot(shape->slot())); - } - - return true; - } - - // When we hit a proxy during lookup, the property might be - // on the prototype of the proxy, thus use getPropertyDescriptor. - if (obj2->is()) - return Proxy::getPropertyDescriptor(cx, obj2, id, desc); - - // Assume other non-natives (i.e. TypedObjects) behave in a sane way. - return GetOwnPropertyDescriptor(cx, obj2, id, desc); -} - JS_PUBLIC_API(bool) JS_GetOwnPropertyDescriptorById(JSContext *cx, HandleObject obj, HandleId id, MutableHandle desc) @@ -2689,7 +2649,7 @@ JS_PUBLIC_API(bool) JS_GetPropertyDescriptorById(JSContext *cx, HandleObject obj, HandleId id, MutableHandle desc) { - return GetPropertyDescriptorById(cx, obj, id, desc); + return GetPropertyDescriptor(cx, obj, id, desc); } JS_PUBLIC_API(bool) diff --git a/js/src/jsiter.cpp b/js/src/jsiter.cpp index 4ebc885c2844..6e8bdc3f5dd9 100644 --- a/js/src/jsiter.cpp +++ b/js/src/jsiter.cpp @@ -1173,7 +1173,7 @@ SuppressDeletedPropertyHelper(JSContext *cx, HandleObject obj, StringPredicate p return false; Rooted desc(cx); - if (!JS_GetPropertyDescriptorById(cx, proto, id, &desc)) + if (!GetPropertyDescriptor(cx, proto, id, &desc)) return false; if (desc.object()) { @@ -1183,7 +1183,7 @@ SuppressDeletedPropertyHelper(JSContext *cx, HandleObject obj, StringPredicate p } /* - * If JS_GetPropertyDescriptorById above removed a property from + * If GetPropertyDescriptorById above removed a property from * ni, start over. */ if (props_end != ni->props_end || props_cursor != ni->props_cursor) diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index 651cb9948d91..c38f81f28086 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -3338,6 +3338,30 @@ js::SetImmutablePrototype(ExclusiveContext *cx, HandleObject obj, bool *succeede return true; } +bool +js::GetPropertyDescriptor(JSContext *cx, HandleObject obj, HandleId id, + MutableHandle desc) +{ + RootedObject pobj(cx); + + for (pobj = obj; pobj;) { + if (pobj->is()) + return Proxy::getPropertyDescriptor(cx, pobj, id, desc); + + if (!GetOwnPropertyDescriptor(cx, pobj, id, desc)) + return false; + + if (desc.object()) + return true; + + if (!GetPrototype(cx, pobj, &pobj)) + return false; + } + + MOZ_ASSERT(!desc.object()); + return true; +} + bool js::ToPrimitive(JSContext *cx, HandleObject obj, JSType hint, MutableHandleValue vp) { diff --git a/js/src/jsobj.h b/js/src/jsobj.h index 90b93bb1a7c7..3ddbee62564e 100644 --- a/js/src/jsobj.h +++ b/js/src/jsobj.h @@ -925,6 +925,10 @@ DeleteElement(JSContext *cx, js::HandleObject obj, uint32_t index, bool *succeed extern bool SetImmutablePrototype(js::ExclusiveContext *cx, JS::HandleObject obj, bool *succeeded); +extern bool +GetPropertyDescriptor(JSContext *cx, HandleObject obj, HandleId id, + MutableHandle desc); + /* * Deprecated. A version of HasProperty that also returns the object on which * the property was found (but that information is unreliable for proxies), and diff --git a/js/src/proxy/DirectProxyHandler.cpp b/js/src/proxy/DirectProxyHandler.cpp index 29bd91fc9e1b..533f21a4c066 100644 --- a/js/src/proxy/DirectProxyHandler.cpp +++ b/js/src/proxy/DirectProxyHandler.cpp @@ -20,7 +20,7 @@ DirectProxyHandler::getPropertyDescriptor(JSContext *cx, HandleObject proxy, Han assertEnteredPolicy(cx, proxy, id, GET | SET | GET_PROPERTY_DESCRIPTOR); MOZ_ASSERT(!hasPrototype()); // Should never be called if there's a prototype. RootedObject target(cx, proxy->as().target()); - return JS_GetPropertyDescriptorById(cx, target, id, desc); + return GetPropertyDescriptor(cx, target, id, desc); } bool diff --git a/js/src/proxy/Proxy.cpp b/js/src/proxy/Proxy.cpp index 0093f513a23f..7ccdead5398a 100644 --- a/js/src/proxy/Proxy.cpp +++ b/js/src/proxy/Proxy.cpp @@ -111,7 +111,7 @@ Proxy::getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id, return false; if (desc.object()) return true; - INVOKE_ON_PROTOTYPE(cx, handler, proxy, JS_GetPropertyDescriptorById(cx, proto, id, desc)); + INVOKE_ON_PROTOTYPE(cx, handler, proxy, GetPropertyDescriptor(cx, proto, id, desc)); } bool diff --git a/js/src/proxy/ScriptedDirectProxyHandler.cpp b/js/src/proxy/ScriptedDirectProxyHandler.cpp index 6b9e17d25b5a..aaa43913704c 100644 --- a/js/src/proxy/ScriptedDirectProxyHandler.cpp +++ b/js/src/proxy/ScriptedDirectProxyHandler.cpp @@ -429,7 +429,7 @@ ScriptedDirectProxyHandler::getPropertyDescriptor(JSContext *cx, HandleObject pr MOZ_ASSERT(!desc.object()); return true; } - return JS_GetPropertyDescriptorById(cx, proto, id, desc); + return GetPropertyDescriptor(cx, proto, id, desc); } // ES6 (5 April 2014) 9.5.5 Proxy.[[GetOwnProperty]](P) From c2d290654c6f4379226a65d3b82fa72360fc9e6d Mon Sep 17 00:00:00 2001 From: Patrick McManus Date: Fri, 30 Jan 2015 10:55:07 -0500 Subject: [PATCH 18/62] bug 1129571 - h2/spdy coalsescing by full DNS rrset r=hurley --- netwerk/base/nsSocketTransport2.cpp | 17 ++- netwerk/base/nsSocketTransport2.h | 3 + netwerk/dns/DNSRequestChild.cpp | 7 + netwerk/dns/nsDNSService2.cpp | 40 ++++++ netwerk/dns/nsIDNSRecord.idl | 13 +- .../protocol/http/ConnectionDiagnostics.cpp | 11 +- netwerk/protocol/http/nsHttpConnectionMgr.cpp | 127 +++++++++++------- netwerk/protocol/http/nsHttpConnectionMgr.h | 8 +- 8 files changed, 168 insertions(+), 58 deletions(-) diff --git a/netwerk/base/nsSocketTransport2.cpp b/netwerk/base/nsSocketTransport2.cpp index a54fa6b3c5a0..24944b7d7f1a 100644 --- a/netwerk/base/nsSocketTransport2.cpp +++ b/netwerk/base/nsSocketTransport2.cpp @@ -1988,11 +1988,13 @@ NS_IMPL_ISUPPORTS(nsSocketTransport, nsISocketTransport, nsITransport, nsIDNSListener, - nsIClassInfo) + nsIClassInfo, + nsIInterfaceRequestor) NS_IMPL_CI_INTERFACE_GETTER(nsSocketTransport, nsISocketTransport, nsITransport, - nsIDNSListener) + nsIDNSListener, + nsIInterfaceRequestor) NS_IMETHODIMP nsSocketTransport::OpenInputStream(uint32_t flags, @@ -2419,6 +2421,17 @@ nsSocketTransport::OnLookupComplete(nsICancelable *request, return NS_OK; } +// nsIInterfaceRequestor +NS_IMETHODIMP +nsSocketTransport::GetInterface(const nsIID &iid, void **result) +{ + if (iid.Equals(NS_GET_IID(nsIDNSRecord))) { + return mDNSRecord ? + mDNSRecord->QueryInterface(iid, result) : NS_ERROR_NO_INTERFACE; + } + return this->QueryInterface(iid, result); +} + NS_IMETHODIMP nsSocketTransport::GetInterfaces(uint32_t *count, nsIID * **array) { diff --git a/netwerk/base/nsSocketTransport2.h b/netwerk/base/nsSocketTransport2.h index 4210337efb95..78cebd171821 100644 --- a/netwerk/base/nsSocketTransport2.h +++ b/netwerk/base/nsSocketTransport2.h @@ -14,6 +14,7 @@ #include "nsString.h" #include "nsCOMPtr.h" +#include "nsIInterfaceRequestor.h" #include "nsISocketTransport.h" #include "nsIAsyncInputStream.h" #include "nsIAsyncOutputStream.h" @@ -108,6 +109,7 @@ class nsSocketTransport MOZ_FINAL : public nsASocketHandler , public nsISocketTransport , public nsIDNSListener , public nsIClassInfo + , public nsIInterfaceRequestor { typedef mozilla::Mutex Mutex; @@ -117,6 +119,7 @@ public: NS_DECL_NSISOCKETTRANSPORT NS_DECL_NSIDNSLISTENER NS_DECL_NSICLASSINFO + NS_DECL_NSIINTERFACEREQUESTOR nsSocketTransport(); diff --git a/netwerk/dns/DNSRequestChild.cpp b/netwerk/dns/DNSRequestChild.cpp index 25edefa2e199..45a51c11cadf 100644 --- a/netwerk/dns/DNSRequestChild.cpp +++ b/netwerk/dns/DNSRequestChild.cpp @@ -94,6 +94,13 @@ ChildDNSRecord::GetNextAddr(uint16_t port, NetAddr *addr) return NS_OK; } +NS_IMETHODIMP +ChildDNSRecord::GetAddresses(nsTArray & aAddressArray) +{ + aAddressArray = mAddresses; + return NS_OK; +} + // shamelessly copied from nsDNSRecord NS_IMETHODIMP ChildDNSRecord::GetScriptableNextAddr(uint16_t port, nsINetAddr **result) diff --git a/netwerk/dns/nsDNSService2.cpp b/netwerk/dns/nsDNSService2.cpp index a8330c169658..849c8bae8a90 100644 --- a/netwerk/dns/nsDNSService2.cpp +++ b/netwerk/dns/nsDNSService2.cpp @@ -172,6 +172,46 @@ nsDNSRecord::GetNextAddr(uint16_t port, NetAddr *addr) return NS_OK; } +NS_IMETHODIMP +nsDNSRecord::GetAddresses(nsTArray & aAddressArray) +{ + if (mDone) { + return NS_ERROR_NOT_AVAILABLE; + } + + mHostRecord->addr_info_lock.Lock(); + if (mHostRecord->addr_info) { + for (NetAddrElement *iter = mHostRecord->addr_info->mAddresses.getFirst(); + iter; iter = iter->getNext()) { + if (mHostRecord->Blacklisted(&iter->mAddress)) { + continue; + } + NetAddr *addr = aAddressArray.AppendElement(NetAddr()); + memcpy(addr, &iter->mAddress, sizeof(NetAddr)); + if (addr->raw.family == AF_INET) { + addr->inet.port = 0; + } else if (addr->raw.family == AF_INET6) { + addr->inet6.port = 0; + } + } + mHostRecord->addr_info_lock.Unlock(); + } else { + mHostRecord->addr_info_lock.Unlock(); + + if (!mHostRecord->addr) { + return NS_ERROR_NOT_AVAILABLE; + } + NetAddr *addr = aAddressArray.AppendElement(NetAddr()); + memcpy(addr, mHostRecord->addr, sizeof(NetAddr)); + if (addr->raw.family == AF_INET) { + addr->inet.port = 0; + } else if (addr->raw.family == AF_INET6) { + addr->inet6.port = 0; + } + } + return NS_OK; +} + NS_IMETHODIMP nsDNSRecord::GetScriptableNextAddr(uint16_t port, nsINetAddr * *result) { diff --git a/netwerk/dns/nsIDNSRecord.idl b/netwerk/dns/nsIDNSRecord.idl index eb6959a0e24e..4f446d479c19 100644 --- a/netwerk/dns/nsIDNSRecord.idl +++ b/netwerk/dns/nsIDNSRecord.idl @@ -10,8 +10,10 @@ namespace net { union NetAddr; } } +template class nsTArray; %} native NetAddr(mozilla::net::NetAddr); +[ref] native nsNetAddrTArrayRef(nsTArray); interface nsINetAddr; /** @@ -22,7 +24,7 @@ interface nsINetAddr; * like an enumerator, allowing the caller to easily step through the * list of IP addresses. */ -[scriptable, uuid(95ced6f3-44b4-4427-a149-c9a1e033d852)] +[scriptable, uuid(f92228ae-c417-4188-a604-0830a95e7eb9)] interface nsIDNSRecord : nsISupports { /** @@ -45,6 +47,15 @@ interface nsIDNSRecord : nsISupports */ [noscript] NetAddr getNextAddr(in uint16_t aPort); + /** + * this function copies the value of all working members of the RR + * set into the output array. + * + * @param aAddressArray + * The result set + */ + [noscript] void getAddresses(out nsNetAddrTArrayRef aAddressArray); + /** * this function returns the value of the next IP address as a * scriptable address and increments the internal address iterator. diff --git a/netwerk/protocol/http/ConnectionDiagnostics.cpp b/netwerk/protocol/http/ConnectionDiagnostics.cpp index df490de10de3..174fa3fa25ff 100644 --- a/netwerk/protocol/http/ConnectionDiagnostics.cpp +++ b/netwerk/protocol/http/ConnectionDiagnostics.cpp @@ -70,10 +70,10 @@ nsHttpConnectionMgr::PrintDiagnosticsCB(const nsACString &key, ent->mIdleConns.Length()); self->mLogData.AppendPrintf(" Half Opens Length = %u\n", ent->mHalfOpens.Length()); - self->mLogData.AppendPrintf(" Coalescing Key = %s\n", - ent->mCoalescingKey.get()); + self->mLogData.AppendPrintf(" Coalescing Keys Length = %u\n", + ent->mCoalescingKeys.Length()); self->mLogData.AppendPrintf(" Spdy using = %d, tested = %d, preferred = %d\n", - ent->mUsingSpdy, ent->mTestedSpdy, ent->mSpdyPreferred); + ent->mUsingSpdy, ent->mTestedSpdy, ent->mInPreferredHash); self->mLogData.AppendPrintf(" pipelinestate = %d penalty = %d\n", ent->mPipelineState, ent->mPipeliningPenalty); for (i = 0; i < nsAHttpTransaction::CLASS_MAX; ++i) { @@ -96,7 +96,10 @@ nsHttpConnectionMgr::PrintDiagnosticsCB(const nsACString &key, self->mLogData.AppendPrintf(" :: Pending Transaction #%u\n", i); ent->mPendingQ[i]->PrintDiagnostics(self->mLogData); } - + for (i = 0; i < ent->mCoalescingKeys.Length(); ++i) { + self->mLogData.AppendPrintf(" :: Coalescing Key #%u %s\n", + i, ent->mCoalescingKeys[i].get()); + } return PL_DHASH_NEXT; } diff --git a/netwerk/protocol/http/nsHttpConnectionMgr.cpp b/netwerk/protocol/http/nsHttpConnectionMgr.cpp index 498fd64e4118..99ba429ab04c 100644 --- a/netwerk/protocol/http/nsHttpConnectionMgr.cpp +++ b/netwerk/protocol/http/nsHttpConnectionMgr.cpp @@ -26,6 +26,7 @@ #include "mozilla/Telemetry.h" #include "mozilla/net/DashboardTypes.h" #include "NullHttpTransaction.h" +#include "nsIDNSRecord.h" #include "nsITransport.h" #include "nsISocketTransportService.h" #include @@ -569,6 +570,46 @@ nsHttpConnectionMgr::ClearConnectionHistory() return NS_OK; } + +nsHttpConnectionMgr::nsConnectionEntry * +nsHttpConnectionMgr::LookupPreferredHash(nsHttpConnectionMgr::nsConnectionEntry *ent) +{ + nsConnectionEntry *preferred = nullptr; + uint32_t len = ent->mCoalescingKeys.Length(); + for (uint32_t i = 0; !preferred && (i < len); ++i) { + preferred = mSpdyPreferredHash.Get(ent->mCoalescingKeys[i]); + } + return preferred; +} + +void +nsHttpConnectionMgr::StorePreferredHash(nsHttpConnectionMgr::nsConnectionEntry *ent) +{ + if (ent->mCoalescingKeys.IsEmpty()) { + return; + } + + ent->mInPreferredHash = true; + uint32_t len = ent->mCoalescingKeys.Length(); + for (uint32_t i = 0; i < len; ++i) { + mSpdyPreferredHash.Put(ent->mCoalescingKeys[i], ent); + } +} + +void +nsHttpConnectionMgr::RemovePreferredHash(nsHttpConnectionMgr::nsConnectionEntry *ent) +{ + if (!ent->mInPreferredHash || ent->mCoalescingKeys.IsEmpty()) { + return; + } + + ent->mInPreferredHash = false; + uint32_t len = ent->mCoalescingKeys.Length(); + for (uint32_t i = 0; i < len; ++i) { + mSpdyPreferredHash.Remove(ent->mCoalescingKeys[i]); + } +} + // Given a nsHttpConnectionInfo find the connection entry object that // contains either the nshttpconnection or nshttptransaction parameter. // Normally this is done by the hashkey lookup of connectioninfo, @@ -587,13 +628,13 @@ nsHttpConnectionMgr::LookupConnectionEntry(nsHttpConnectionInfo *ci, // If there is no sign of coalescing (or it is disabled) then just // return the primary hash lookup - if (!ent || !ent->mUsingSpdy || ent->mCoalescingKey.IsEmpty()) + if (!ent || !ent->mUsingSpdy || ent->mCoalescingKeys.IsEmpty()) return ent; // If there is no preferred coalescing entry for this host (or the // preferred entry is the one that matched the mCT hash lookup) then // there is only option - nsConnectionEntry *preferred = mSpdyPreferredHash.Get(ent->mCoalescingKey); + nsConnectionEntry *preferred = LookupPreferredHash(ent); if (!preferred || (preferred == ent)) return ent; @@ -674,18 +715,15 @@ nsHttpConnectionMgr::ReportSpdyConnection(nsHttpConnection *conn, // lookup. Filtering on that has to be done at the time of use // rather than the time of registration (i.e. now). nsConnectionEntry *joinedConnection; - nsConnectionEntry *preferred = - mSpdyPreferredHash.Get(ent->mCoalescingKey); + nsConnectionEntry *preferred = LookupPreferredHash(ent); - LOG(("ReportSpdyConnection %s %s ent=%p preferred=%p\n", - ent->mConnInfo->Host(), ent->mCoalescingKey.get(), - ent, preferred)); + LOG(("ReportSpdyConnection %p,%s prefers %p,%s\n", + ent, ent->mConnInfo->Host(), preferred, + preferred ? preferred->mConnInfo->Host() : "")); if (!preferred) { - if (!ent->mCoalescingKey.IsEmpty()) { - mSpdyPreferredHash.Put(ent->mCoalescingKey, ent); - ent->mSpdyPreferred = true; - } + // this becomes the preferred entry + StorePreferredHash(ent); } else if ((preferred != ent) && (joinedConnection = GetSpdyPreferredEnt(ent)) && (joinedConnection != ent)) { @@ -775,11 +813,11 @@ nsHttpConnectionMgr::GetSpdyPreferredEnt(nsConnectionEntry *aOriginalEntry) { if (!gHttpHandler->IsSpdyEnabled() || !gHttpHandler->CoalesceSpdy() || - aOriginalEntry->mCoalescingKey.IsEmpty()) + aOriginalEntry->mCoalescingKeys.IsEmpty()) { return nullptr; + } - nsConnectionEntry *preferred = - mSpdyPreferredHash.Get(aOriginalEntry->mCoalescingKey); + nsConnectionEntry *preferred = LookupPreferredHash(aOriginalEntry); // if there is no redirection no cert validation is required if (preferred == aOriginalEntry) @@ -807,8 +845,7 @@ nsHttpConnectionMgr::GetSpdyPreferredEnt(nsConnectionEntry *aOriginalEntry) if (!activeSpdy) { // remove the preferred status of this entry if it cannot be // used for pooling. - preferred->mSpdyPreferred = false; - RemoveSpdyPreferredEnt(preferred->mCoalescingKey); + RemovePreferredHash(preferred); LOG(("nsHttpConnectionMgr::GetSpdyPreferredConnection " "preferred host mapping %s to %s removed due to inactivity.\n", aOriginalEntry->mConnInfo->Host(), @@ -872,15 +909,6 @@ nsHttpConnectionMgr::GetSpdyPreferredEnt(nsConnectionEntry *aOriginalEntry) return preferred; } -void -nsHttpConnectionMgr::RemoveSpdyPreferredEnt(nsACString &aHashKey) -{ - if (aHashKey.IsEmpty()) - return; - - mSpdyPreferredHash.Remove(aHashKey); -} - //----------------------------------------------------------------------------- // enumeration callbacks @@ -2749,8 +2777,7 @@ nsHttpConnectionMgr::OnMsgUpdateParam(int32_t, void *param) nsHttpConnectionMgr::nsConnectionEntry::~nsConnectionEntry() { MOZ_COUNT_DTOR(nsConnectionEntry); - if (mSpdyPreferred) - gHttpHandler->ConnMgr()->RemoveSpdyPreferredEnt(mCoalescingKey); + gHttpHandler->ConnMgr()->RemovePreferredHash(this); } void @@ -3469,32 +3496,36 @@ nsHttpConnectionMgr::nsHalfOpenSocket::OnTransportStatus(nsITransport *trans, // just completed. We can't do coalescing if using a proxy because the // ip addresses are not available to the client. - if (status == NS_NET_STATUS_CONNECTED_TO && + if (status == NS_NET_STATUS_CONNECTING_TO && gHttpHandler->IsSpdyEnabled() && gHttpHandler->CoalesceSpdy() && mEnt && mEnt->mConnInfo && mEnt->mConnInfo->EndToEndSSL() && !mEnt->mConnInfo->UsingProxy() && - mEnt->mCoalescingKey.IsEmpty()) { + mEnt->mCoalescingKeys.IsEmpty()) { - NetAddr addr; - nsresult rv = mSocketTransport->GetPeerAddr(&addr); - if (NS_SUCCEEDED(rv)) { - mEnt->mCoalescingKey.SetCapacity(kIPv6CStrBufSize + 26); - NetAddrToString(&addr, mEnt->mCoalescingKey.BeginWriting(), kIPv6CStrBufSize); - mEnt->mCoalescingKey.SetLength( - strlen(mEnt->mCoalescingKey.BeginReading())); - - if (mEnt->mConnInfo->GetAnonymous()) - mEnt->mCoalescingKey.AppendLiteral("~A:"); - else - mEnt->mCoalescingKey.AppendLiteral("~.:"); - mEnt->mCoalescingKey.AppendInt(mEnt->mConnInfo->Port()); - - LOG(("nsHttpConnectionMgr::nsHalfOpenSocket::OnTransportStatus " - "STATUS_CONNECTED_TO Established New Coalescing Key for host " - "%s [%s]", mEnt->mConnInfo->Host(), - mEnt->mCoalescingKey.get())); + nsCOMPtr dnsRecord(do_GetInterface(mSocketTransport)); + nsTArray addressSet; + nsresult rv = NS_ERROR_NOT_AVAILABLE; + if (dnsRecord) { + rv = dnsRecord->GetAddresses(addressSet); + } + if (NS_SUCCEEDED(rv) && !addressSet.IsEmpty()) { + for (uint32_t i = 0; i < addressSet.Length(); ++i) { + nsCString *newKey = mEnt->mCoalescingKeys.AppendElement(nsCString()); + newKey->SetCapacity(kIPv6CStrBufSize + 26); + NetAddrToString(&addressSet[i], newKey->BeginWriting(), kIPv6CStrBufSize); + newKey->SetLength(strlen(newKey->BeginReading())); + if (mEnt->mConnInfo->GetAnonymous()) { + newKey->AppendLiteral("~A:"); + } else { + newKey->AppendLiteral("~.:"); + } + newKey->AppendInt(mEnt->mConnInfo->Port()); + LOG(("nsHttpConnectionMgr::nsHalfOpenSocket::OnTransportStatus " + "STATUS_CONNECTING_TO Established New Coalescing Key # %d for host " + "%s [%s]", i, mEnt->mConnInfo->Host(), newKey->get())); + } gHttpHandler->ConnMgr()->ProcessSpdyPendingQ(mEnt); } } @@ -3585,7 +3616,7 @@ nsConnectionEntry::nsConnectionEntry(nsHttpConnectionInfo *ci) , mSpdyCWND(0) , mUsingSpdy(false) , mTestedSpdy(false) - , mSpdyPreferred(false) + , mInPreferredHash(false) , mPreferIPv4(false) , mPreferIPv6(false) { diff --git a/netwerk/protocol/http/nsHttpConnectionMgr.h b/netwerk/protocol/http/nsHttpConnectionMgr.h index 1fd8bff14e2a..ebecebfe8039 100644 --- a/netwerk/protocol/http/nsHttpConnectionMgr.h +++ b/netwerk/protocol/http/nsHttpConnectionMgr.h @@ -364,7 +364,7 @@ private: // mSpdyPreferred. The mapping is maintained in the connection mananger // mSpdyPreferred hash. // - nsCString mCoalescingKey; + nsTArray mCoalescingKeys; // The value of a recevied SPDY settings type 5 previously received // for this connection entry and the time it was set. @@ -382,7 +382,7 @@ private: // minimized so that we can multiplex on a single spdy connection. bool mTestedSpdy; - bool mSpdyPreferred; + bool mInPreferredHash; // Flags to remember our happy-eyeballs decision. // Reset only by Ctrl-F5 reload. @@ -589,7 +589,9 @@ private: // Manage the preferred spdy connection entry for this address nsConnectionEntry *GetSpdyPreferredEnt(nsConnectionEntry *aOriginalEntry); - void RemoveSpdyPreferredEnt(nsACString &aDottedDecimal); + nsConnectionEntry *LookupPreferredHash(nsConnectionEntry *ent); + void StorePreferredHash(nsConnectionEntry *ent); + void RemovePreferredHash(nsConnectionEntry *ent); nsHttpConnection *GetSpdyPreferredConn(nsConnectionEntry *ent); nsDataHashtable mSpdyPreferredHash; nsConnectionEntry *LookupConnectionEntry(nsHttpConnectionInfo *ci, From 41b8b6e859f8c290d05ac71e5c588de71c3847bb Mon Sep 17 00:00:00 2001 From: Olli Pettay Date: Fri, 6 Feb 2015 18:02:22 +0200 Subject: [PATCH 19/62] Bug 676470, ensure null-checking mCurrentTarget actually works, r=masayuki --- dom/events/EventStateManager.cpp | 54 +++++++++++++++++--------------- 1 file changed, 28 insertions(+), 26 deletions(-) diff --git a/dom/events/EventStateManager.cpp b/dom/events/EventStateManager.cpp index 90935dcbc96e..0d4e91df2a1c 100644 --- a/dom/events/EventStateManager.cpp +++ b/dom/events/EventStateManager.cpp @@ -481,32 +481,9 @@ EventStateManager::PreHandleEvent(nsPresContext* aPresContext, mCurrentTarget = aTargetFrame; mCurrentTargetContent = nullptr; - // Focus events don't necessarily need a frame. - if (NS_EVENT_NEEDS_FRAME(aEvent)) { - NS_ASSERTION(mCurrentTarget, "mCurrentTarget is null. this should not happen. see bug #13007"); - if (!mCurrentTarget) return NS_ERROR_NULL_POINTER; - } -#ifdef DEBUG - if (aEvent->HasDragEventMessage() && sIsPointerLocked) { - NS_ASSERTION(sIsPointerLocked, - "sIsPointerLocked is true. Drag events should be suppressed when the pointer is locked."); - } -#endif - // Store last known screenPoint and clientPoint so pointer lock - // can use these values as constants. - WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent(); - if (aEvent->mFlags.mIsTrusted && - ((mouseEvent && mouseEvent->IsReal()) || - aEvent->mClass == eWheelEventClass) && - !sIsPointerLocked) { - sLastScreenPoint = - UIEvent::CalculateScreenPoint(aPresContext, aEvent); - sLastClientPoint = - UIEvent::CalculateClientPoint(aPresContext, aEvent, nullptr); - } - // Do not take account NS_MOUSE_ENTER/EXIT so that loading a page // when user is not active doesn't change the state to active. + WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent(); if (aEvent->mFlags.mIsTrusted && ((mouseEvent && mouseEvent->IsReal() && mouseEvent->message != NS_MOUSE_ENTER && @@ -524,10 +501,35 @@ EventStateManager::PreHandleEvent(nsPresContext* aPresContext, ++gMouseOrKeyboardEventCounter; } - *aStatus = nsEventStatus_eIgnore; - WheelTransaction::OnEvent(aEvent); + // Focus events don't necessarily need a frame. + if (NS_EVENT_NEEDS_FRAME(aEvent)) { + if (!mCurrentTarget) { + return NS_ERROR_NULL_POINTER; + } + } +#ifdef DEBUG + if (aEvent->HasDragEventMessage() && sIsPointerLocked) { + NS_ASSERTION(sIsPointerLocked, + "sIsPointerLocked is true. Drag events should be suppressed when " + "the pointer is locked."); + } +#endif + // Store last known screenPoint and clientPoint so pointer lock + // can use these values as constants. + if (aEvent->mFlags.mIsTrusted && + ((mouseEvent && mouseEvent->IsReal()) || + aEvent->mClass == eWheelEventClass) && + !sIsPointerLocked) { + sLastScreenPoint = + UIEvent::CalculateScreenPoint(aPresContext, aEvent); + sLastClientPoint = + UIEvent::CalculateClientPoint(aPresContext, aEvent, nullptr); + } + + *aStatus = nsEventStatus_eIgnore; + switch (aEvent->message) { case NS_CONTEXTMENU: if (sIsPointerLocked) { From e39a10fe1d4be55c8c1b8d51ac47a1125ccdb855 Mon Sep 17 00:00:00 2001 From: James Graham Date: Wed, 4 Feb 2015 15:51:10 +0000 Subject: [PATCH 20/62] Bug 1124181 - Store local base SHA1 of last web-platform-tests update explicitly, r=ahal --- testing/web-platform/mach_commands.py | 2 +- testing/web-platform/update/__init__.py | 2 +- .../web-platform/update/updatecommandline.py | 8 +++- testing/web-platform/update/upstream.py | 46 +++++++++++++++---- 4 files changed, 45 insertions(+), 13 deletions(-) diff --git a/testing/web-platform/mach_commands.py b/testing/web-platform/mach_commands.py index 51b3bb7b604c..1c4e80344933 100644 --- a/testing/web-platform/mach_commands.py +++ b/testing/web-platform/mach_commands.py @@ -89,7 +89,7 @@ class WebPlatformTestsUpdater(MozbuildObject): if kwargs["config"] is None: kwargs["config"] = os.path.join(self.topsrcdir, 'testing', 'web-platform', 'wptrunner.ini') updatecommandline.check_args(kwargs) - logger = update.setup_logging(kwargs, {}) + logger = update.setup_logging(kwargs, {"mach": sys.stdout}) try: update.run_update(logger, **kwargs) diff --git a/testing/web-platform/update/__init__.py b/testing/web-platform/update/__init__.py index 0dbacf525df9..0cd536d4c353 100644 --- a/testing/web-platform/update/__init__.py +++ b/testing/web-platform/update/__init__.py @@ -27,7 +27,7 @@ def run_update(logger, **kwargs): if __name__ == "__main__": args = updatecommandline.parse_args() - logger = setup_logging(args, {}) + logger = setup_logging(args, {"mach": sys.stdout}) assert structuredlog.get_default_logger() is not None diff --git a/testing/web-platform/update/updatecommandline.py b/testing/web-platform/update/updatecommandline.py index 4966b5ad2a9f..e26ee5845234 100644 --- a/testing/web-platform/update/updatecommandline.py +++ b/testing/web-platform/update/updatecommandline.py @@ -6,8 +6,10 @@ def create_parser(): from wptrunner import wptcommandline parser = wptcommandline.create_parser_update() - parser.add_argument("--upstream", action="store_true", - help="Push local changes to upstream repository") + parser.add_argument("--upstream", dest="upstream", action="store_true", default=None, + help="Push local changes to upstream repository even when not syncing") + parser.add_argument("--no-upstream", dest="upstream", action="store_false", default=None, + help="Dont't push local changes to upstream repository when syncing") parser.add_argument("--token-file", action="store", type=wptcommandline.abs_path, help="Path to file containing github token") parser.add_argument("--token", action="store", help="GitHub token to use") @@ -18,6 +20,8 @@ def check_args(kwargs): from wptrunner import wptcommandline wptcommandline.set_from_config(kwargs) + kwargs["upstream"] = kwargs["upstream"] if kwargs["upstream"] is not None else kwargs["sync"] + if kwargs["upstream"]: if kwargs["rev"]: raise ValueError("Setting --rev with --upstream isn't supported") diff --git a/testing/web-platform/update/upstream.py b/testing/web-platform/update/upstream.py index d509d6ab62f3..a36daae23d9f 100644 --- a/testing/web-platform/update/upstream.py +++ b/testing/web-platform/update/upstream.py @@ -1,4 +1,5 @@ import os +import re import subprocess import sys import urlparse @@ -7,7 +8,7 @@ from wptrunner.update.sync import LoadManifest from wptrunner.update.tree import get_unique_name from wptrunner.update.base import Step, StepRunner, exit_clean, exit_unclean -from .tree import GitTree, Patch +from .tree import Commit, GitTree, Patch import github from .github import GitHub @@ -29,7 +30,7 @@ def rewrite_patch(patch, strip_dir): for line in patch.diff.split("\n"): for start in line_starts: if line.startswith(start): - new_diff.append(line.replace(strip_dir, "")) + new_diff.append(line.replace(strip_dir, "").encode("utf8")) break else: new_diff.append(line) @@ -101,14 +102,20 @@ class CheckoutBranch(Step): class GetLastSyncCommit(Step): """Find the gecko commit at which we last performed a sync with upstream.""" - provides = ["last_sync_commit"] + provides = ["last_sync_path", "last_sync_commit"] def create(self, state): self.logger.info("Looking for last sync commit") - state.last_sync_commit = state.local_tree.commits_by_message(state.test_manifest.rev, - os.path.join(state.local_tree.root, - "testing", - "web-platform"))[-1] + state.last_sync_path = os.path.join(state.metadata_path, "mozilla-sync") + with open(state.last_sync_path) as f: + last_sync_sha1 = f.read().strip() + + state.last_sync_commit = Commit(state.local_tree, last_sync_sha1) + + if not state.local_tree.contains_commit(state.last_sync_commit): + self.logger.error("Could not find last sync commit %s" % last_sync_sha1) + return exit_clean + self.logger.info("Last sync to web-platform-tests happened in %s" % state.last_sync_commit.sha1) @@ -132,14 +139,23 @@ class LoadCommits(Step): state.source_commits = state.local_tree.log(state.last_sync_commit, state.tests_path) - for i, commit in enumerate(state.source_commits): + update_regexp = re.compile("Bug \d+ - Update web-platform-tests to revision [0-9a-f]{40}") + + for i, commit in enumerate(state.source_commits[:]): + if update_regexp.match(commit.message.text): + # This is a previous update commit so ignore it + state.source_commits.remove(commit) + continue + if commit.message.backouts: #TODO: Add support for collapsing backouts raise NotImplementedError("Need to get the Git->Hg commits for backouts and remove the backed out patch") + if not commit.message.bug: self.logger.error("Commit %i (%s) doesn't have an associated bug number." % (i + 1, commit.sha1)) return exit_unclean + self.logger.debug("Source commits: %s" % state.source_commits) class MovePatches(Step): @@ -227,6 +243,17 @@ class MergeUpstream(Step): return rv state.merge_index += 1 +class UpdateLastSyncCommit(Step): + """Update the gecko commit at which we last performed a sync with upstream.""" + + provides = [] + + def create(self, state): + self.logger.info("Updating last sync commit") + with open(state.last_sync_path, "w") as f: + f.write(state.local_tree.rev) + # This gets added to the patch later on + class MergeLocalBranch(Step): """Create a local branch pointing at the commit to upstream""" @@ -305,7 +332,8 @@ class SyncToUpstreamRunner(StepRunner): MovePatches, RebaseCommits, CheckRebase, - MergeUpstream] + MergeUpstream, + UpdateLastSyncCommit] class PRMergeRunner(StepRunner): From e194e1462ef6c24220c188dbb3f97fb0a3604c41 Mon Sep 17 00:00:00 2001 From: Brian Hackett Date: Fri, 6 Feb 2015 09:13:29 -0700 Subject: [PATCH 21/62] Bug 1129226 - Refactor ObjectGroup class and accessors, r=jandem. --- js/src/builtin/Object.cpp | 3 +- js/src/builtin/Object.h | 2 + js/src/builtin/TypedObject.cpp | 8 +- js/src/frontend/BytecodeEmitter.cpp | 14 +- js/src/gc/Barrier.h | 11 +- js/src/gc/GCTrace.h | 6 +- js/src/gc/Marking.cpp | 24 +- js/src/gc/Marking.h | 2 +- js/src/gc/Nursery.cpp | 6 +- js/src/gc/Nursery.h | 8 +- js/src/gc/RootMarking.cpp | 2 +- js/src/gc/Rooting.h | 7 +- js/src/gc/Tracer.h | 6 +- js/src/jit/BaselineCompiler.cpp | 20 +- js/src/jit/BaselineIC.cpp | 18 +- js/src/jit/BaselineIC.h | 12 +- js/src/jit/BaselineInspector.cpp | 2 +- js/src/jit/BaselineInspector.h | 2 +- js/src/jit/CodeGenerator.cpp | 20 +- js/src/jit/Disassembler.h | 1 + js/src/jit/IonAnalysis.cpp | 7 +- js/src/jit/IonAnalysis.h | 2 +- js/src/jit/IonBuilder.cpp | 44 +- js/src/jit/IonCaches.cpp | 12 +- js/src/jit/MCallOptimize.cpp | 28 +- js/src/jit/MIR.cpp | 6 +- js/src/jit/MIR.h | 44 +- js/src/jit/MIRGenerator.h | 4 +- js/src/jit/MIRGraph.cpp | 2 +- js/src/jit/MacroAssembler.cpp | 8 +- js/src/jit/MacroAssembler.h | 6 +- js/src/jit/OptimizationTracking.cpp | 4 +- js/src/jit/Recover.h | 1 + js/src/jit/ScalarReplacement.cpp | 1 + js/src/jit/VMFunctions.cpp | 2 +- js/src/jit/VMFunctions.h | 4 +- .../jit/shared/CodeGenerator-x86-shared.cpp | 2 +- js/src/jsarray.cpp | 18 +- js/src/jscntxt.cpp | 4 +- js/src/jscntxt.h | 7 - js/src/jscompartment.cpp | 25 +- js/src/jscompartment.h | 13 +- js/src/jsfun.cpp | 4 +- js/src/jsgc.cpp | 24 +- js/src/jsgc.h | 2 +- js/src/jsgcinlines.h | 4 +- js/src/jshashutil.h | 2 + js/src/jsinfer.cpp | 1363 +------------- js/src/jsinfer.h | 734 +------- js/src/jsinferinlines.h | 295 +--- js/src/jsiter.cpp | 8 +- js/src/jsobj.cpp | 48 +- js/src/jsobj.h | 18 +- js/src/jsobjinlines.h | 8 +- js/src/jsscript.h | 13 - js/src/jsstr.cpp | 2 +- js/src/moz.build | 1 + js/src/vm/ArgumentsObject.cpp | 2 +- js/src/vm/ArrayBufferObject.cpp | 2 +- js/src/vm/ArrayObject-inl.h | 2 +- js/src/vm/HelperThreads.cpp | 2 +- js/src/vm/Interpreter.cpp | 39 +- js/src/vm/JSONParser.cpp | 14 +- js/src/vm/MemoryMetrics.cpp | 2 +- js/src/vm/NativeObject-inl.h | 8 +- js/src/vm/ObjectGroup.cpp | 1558 +++++++++++++++++ js/src/vm/ObjectGroup.h | 686 ++++++++ js/src/vm/ProxyObject.cpp | 2 +- js/src/vm/RegExpObject.cpp | 3 +- js/src/vm/RegExpStatics.cpp | 2 +- js/src/vm/Runtime-inl.h | 2 +- js/src/vm/Runtime.h | 6 +- js/src/vm/ScopeObject.cpp | 21 +- js/src/vm/SelfHosting.cpp | 4 +- js/src/vm/Shape.cpp | 2 +- js/src/vm/Shape.h | 2 +- js/src/vm/SharedTypedArrayObject.cpp | 15 +- js/src/vm/Stack.cpp | 2 +- js/src/vm/Stack.h | 1 + js/src/vm/TypedArrayObject.cpp | 31 +- js/src/vm/UbiNode.cpp | 24 +- js/src/vm/UnboxedObject.cpp | 2 +- js/src/vm/UnboxedObject.h | 2 +- 83 files changed, 2721 insertions(+), 2659 deletions(-) create mode 100644 js/src/vm/ObjectGroup.cpp create mode 100644 js/src/vm/ObjectGroup.h diff --git a/js/src/builtin/Object.cpp b/js/src/builtin/Object.cpp index 463dcbb6f566..1aefb09b067d 100644 --- a/js/src/builtin/Object.cpp +++ b/js/src/builtin/Object.cpp @@ -18,6 +18,7 @@ #include "jsobjinlines.h" #include "vm/NativeObject-inl.h" +#include "vm/Shape-inl.h" using namespace js; using namespace js::types; @@ -637,7 +638,7 @@ js::ObjectCreateImpl(JSContext *cx, HandleObject proto, NewObjectKind newKind, // instead. RootedObjectGroup ngroup(cx, group); if (!ngroup) { - ngroup = GetCallerInitGroup(cx, JSProto_Null); + ngroup = ObjectGroup::callingAllocationSiteGroup(cx, JSProto_Null); if (!ngroup) return nullptr; } diff --git a/js/src/builtin/Object.h b/js/src/builtin/Object.h index 6302b098d705..b3919940ee8a 100644 --- a/js/src/builtin/Object.h +++ b/js/src/builtin/Object.h @@ -9,6 +9,8 @@ #include "jsapi.h" +#include "vm/NativeObject.h" + namespace JS { class CallArgs; class Value; diff --git a/js/src/builtin/TypedObject.cpp b/js/src/builtin/TypedObject.cpp index a751aa5181aa..b6fcbb4fe952 100644 --- a/js/src/builtin/TypedObject.cpp +++ b/js/src/builtin/TypedObject.cpp @@ -1495,7 +1495,9 @@ OutlineTypedObject::createUnattachedWithClass(JSContext *cx, MOZ_ASSERT(clasp == &OutlineTransparentTypedObject::class_ || clasp == &OutlineOpaqueTypedObject::class_); - RootedObjectGroup group(cx, cx->getNewGroup(clasp, TaggedProto(&descr->typedProto()), descr)); + RootedObjectGroup group(cx, ObjectGroup::defaultNewGroup(cx, clasp, + TaggedProto(&descr->typedProto()), + descr)); if (!group) return nullptr; @@ -2131,7 +2133,9 @@ InlineTypedObject::create(JSContext *cx, HandleTypeDescr descr, gc::InitialHeap ? &InlineOpaqueTypedObject::class_ : &InlineTransparentTypedObject::class_; - RootedObjectGroup group(cx, cx->getNewGroup(clasp, TaggedProto(&descr->typedProto()), descr)); + RootedObjectGroup group(cx, ObjectGroup::defaultNewGroup(cx, clasp, + TaggedProto(&descr->typedProto()), + descr)); if (!group) return nullptr; diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index 019523839084..78d757e22436 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -4295,7 +4295,7 @@ ParseNode::getConstantValue(ExclusiveContext *cx, AllowConstantObjects allowObje } MOZ_ASSERT(idx == count); - types::FixArrayGroup(cx, obj); + ObjectGroup::fixArrayGroup(cx, obj); vp.setObject(*obj); return true; } @@ -4358,7 +4358,7 @@ ParseNode::getConstantValue(ExclusiveContext *cx, AllowConstantObjects allowObje } } - types::FixObjectGroup(cx, obj); + ObjectGroup::fixPlainObjectGroup(cx, obj); vp.setObject(*obj); return true; } @@ -7250,13 +7250,13 @@ frontend::EmitTree(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn) if (!pn->getConstantValue(cx, ParseNode::DontAllowNestedObjects, &value)) return false; if (!value.isMagic(JS_GENERIC_MAGIC)) { - // Note: the type of the template object might not yet reflect + // Note: the group of the template object might not yet reflect // that the object has copy on write elements. When the // interpreter or JIT compiler fetches the template, it should - // use types::GetOrFixupCopyOnWriteObject to make sure the type - // for the template is accurate. We don't do this here as we - // want to use types::InitObject, which requires a finished - // script. + // use ObjectGroup::getOrFixupCopyOnWriteObject to make sure the + // group for the template is accurate. We don't do this here as we + // want to use ObjectGroup::allocationSiteGroup, which requires a + // finished script. NativeObject *obj = &value.toObject().as(); if (!ObjectElements::MakeElementsCopyOnWrite(cx, obj)) return false; diff --git a/js/src/gc/Barrier.h b/js/src/gc/Barrier.h index 45645f103607..c1fedcb77b24 100644 --- a/js/src/gc/Barrier.h +++ b/js/src/gc/Barrier.h @@ -181,10 +181,7 @@ class ScopeObject; class ScriptSourceObject; class Shape; class UnownedBaseShape; - -namespace types { -struct ObjectGroup; -} +class ObjectGroup; namespace jit { class JitCode; @@ -232,7 +229,7 @@ template <> struct MapTypeToTraceKind{ static const JSG template <> struct MapTypeToTraceKind{ static const JSGCTraceKind kind = JSTRACE_OBJECT; }; template <> struct MapTypeToTraceKind { static const JSGCTraceKind kind = JSTRACE_BASE_SHAPE; }; template <> struct MapTypeToTraceKind { static const JSGCTraceKind kind = JSTRACE_JITCODE; }; -template <> struct MapTypeToTraceKind { static const JSGCTraceKind kind = JSTRACE_OBJECT_GROUP; }; +template <> struct MapTypeToTraceKind { static const JSGCTraceKind kind = JSTRACE_OBJECT_GROUP; }; // Direct value access used by the write barriers and the jits. void @@ -806,7 +803,7 @@ typedef HeapPtr HeapPtrPropertyName; typedef HeapPtr HeapPtrShape; typedef HeapPtr HeapPtrUnownedBaseShape; typedef HeapPtr HeapPtrJitCode; -typedef HeapPtr HeapPtrObjectGroup; +typedef HeapPtr HeapPtrObjectGroup; typedef PreBarriered PreBarrieredValue; typedef RelocatablePtr RelocatableValue; @@ -827,7 +824,7 @@ typedef ReadBarriered ReadBarrieredScriptSourceObject; typedef ReadBarriered ReadBarrieredShape; typedef ReadBarriered ReadBarrieredUnownedBaseShape; typedef ReadBarriered ReadBarrieredJitCode; -typedef ReadBarriered ReadBarrieredObjectGroup; +typedef ReadBarriered ReadBarrieredObjectGroup; typedef ReadBarriered ReadBarrieredAtom; typedef ReadBarriered ReadBarrieredSymbol; diff --git a/js/src/gc/GCTrace.h b/js/src/gc/GCTrace.h index a6e6e4105bcc..4339256d5a8b 100644 --- a/js/src/gc/GCTrace.h +++ b/js/src/gc/GCTrace.h @@ -11,7 +11,7 @@ namespace js { -namespace types { struct ObjectGroup; } +class ObjectGroup; namespace gc { @@ -29,7 +29,7 @@ extern void TraceMinorGCEnd(); extern void TraceMajorGCStart(); extern void TraceTenuredFinalize(Cell *thing); extern void TraceMajorGCEnd(); -extern void TraceTypeNewScript(js::types::ObjectGroup *group); +extern void TraceTypeNewScript(js::ObjectGroup *group); #else @@ -45,7 +45,7 @@ inline void TraceMinorGCEnd() {} inline void TraceMajorGCStart() {} inline void TraceTenuredFinalize(Cell *thing) {} inline void TraceMajorGCEnd() {} -inline void TraceTypeNewScript(js::types::ObjectGroup *group) {} +inline void TraceTypeNewScript(js::ObjectGroup *group) {} #endif diff --git a/js/src/gc/Marking.cpp b/js/src/gc/Marking.cpp index 302ff7a2aadb..b8e6fd0101b5 100644 --- a/js/src/gc/Marking.cpp +++ b/js/src/gc/Marking.cpp @@ -87,7 +87,7 @@ static inline void PushMarkStack(GCMarker *gcmarker, JS::Symbol *sym); static inline void -PushMarkStack(GCMarker *gcmarker, types::ObjectGroup *thing); +PushMarkStack(GCMarker *gcmarker, ObjectGroup *thing); namespace js { namespace gc { @@ -98,7 +98,7 @@ static void MarkChildren(JSTracer *trc, JSScript *script); static void MarkChildren(JSTracer *trc, LazyScript *lazy); static void MarkChildren(JSTracer *trc, Shape *shape); static void MarkChildren(JSTracer *trc, BaseShape *base); -static void MarkChildren(JSTracer *trc, types::ObjectGroup *group); +static void MarkChildren(JSTracer *trc, ObjectGroup *group); static void MarkChildren(JSTracer *trc, jit::JitCode *code); } /* namespace gc */ @@ -614,7 +614,7 @@ DeclMarkerImpl(String, JSFlatString) DeclMarkerImpl(String, JSLinearString) DeclMarkerImpl(String, PropertyName) DeclMarkerImpl(Symbol, JS::Symbol) -DeclMarkerImpl(ObjectGroup, js::types::ObjectGroup) +DeclMarkerImpl(ObjectGroup, js::ObjectGroup) } /* namespace gc */ } /* namespace js */ @@ -655,7 +655,7 @@ gc::MarkKind(JSTracer *trc, void **thingp, JSGCTraceKind kind) MarkInternal(trc, reinterpret_cast(thingp)); break; case JSTRACE_OBJECT_GROUP: - MarkInternal(trc, reinterpret_cast(thingp)); + MarkInternal(trc, reinterpret_cast(thingp)); break; default: MOZ_CRASH("Invalid trace kind in MarkKind."); @@ -796,7 +796,7 @@ gc::MarkTypeRoot(JSTracer *trc, types::Type *v, const char *name) MarkInternal(trc, &obj); *v = types::Type::ObjectType(obj); } else if (v->isGroup()) { - types::ObjectGroup *group = v->group(); + ObjectGroup *group = v->group(); MarkInternal(trc, &group); *v = types::Type::ObjectType(group); } @@ -1066,7 +1066,7 @@ PushMarkStack(GCMarker *gcmarker, JSFunction *thing) } static void -PushMarkStack(GCMarker *gcmarker, types::ObjectGroup *thing) +PushMarkStack(GCMarker *gcmarker, ObjectGroup *thing) { JS_COMPARTMENT_ASSERT(gcmarker->runtime(), thing); MOZ_ASSERT(!IsInsideNursery(thing)); @@ -1422,7 +1422,7 @@ gc::MarkCycleCollectorChildren(JSTracer *trc, Shape *shape) } static void -ScanObjectGroup(GCMarker *gcmarker, types::ObjectGroup *group) +ScanObjectGroup(GCMarker *gcmarker, ObjectGroup *group) { unsigned count = group->getPropertyCount(); for (unsigned i = 0; i < count; i++) { @@ -1450,7 +1450,7 @@ ScanObjectGroup(GCMarker *gcmarker, types::ObjectGroup *group) } static void -gc::MarkChildren(JSTracer *trc, types::ObjectGroup *group) +gc::MarkChildren(JSTracer *trc, ObjectGroup *group) { unsigned count = group->getPropertyCount(); for (unsigned i = 0; i < count; i++) { @@ -1533,7 +1533,7 @@ gc::PushArena(GCMarker *gcmarker, ArenaHeader *aheader) break; case JSTRACE_OBJECT_GROUP: - PushArenaTyped(gcmarker, aheader); + PushArenaTyped(gcmarker, aheader); break; default: @@ -1652,7 +1652,7 @@ void GCMarker::processMarkStackOther(uintptr_t tag, uintptr_t addr) { if (tag == GroupTag) { - ScanObjectGroup(this, reinterpret_cast(addr)); + ScanObjectGroup(this, reinterpret_cast(addr)); } else if (tag == SavedValueArrayTag) { MOZ_ASSERT(!(addr & CellMask)); NativeObject *obj = reinterpret_cast(addr); @@ -1802,7 +1802,7 @@ GCMarker::processMarkStackTop(SliceBudget &budget) return; } - types::ObjectGroup *group = obj->groupFromGC(); + ObjectGroup *group = obj->groupFromGC(); PushMarkStack(this, group); Shape *shape = obj->lastProperty(); @@ -1957,7 +1957,7 @@ js::TraceChildren(JSTracer *trc, void *thing, JSGCTraceKind kind) break; case JSTRACE_OBJECT_GROUP: - MarkChildren(trc, (types::ObjectGroup *)thing); + MarkChildren(trc, (ObjectGroup *)thing); break; default: diff --git a/js/src/gc/Marking.h b/js/src/gc/Marking.h index e6ab4653c6e0..8255d46aadc3 100644 --- a/js/src/gc/Marking.h +++ b/js/src/gc/Marking.h @@ -132,7 +132,7 @@ DeclMarker(String, JSFlatString) DeclMarker(String, JSLinearString) DeclMarker(String, PropertyName) DeclMarker(Symbol, JS::Symbol) -DeclMarker(ObjectGroup, types::ObjectGroup) +DeclMarker(ObjectGroup, ObjectGroup) #undef DeclMarker diff --git a/js/src/gc/Nursery.cpp b/js/src/gc/Nursery.cpp index 3c2de6192f50..ada17d475282 100644 --- a/js/src/gc/Nursery.cpp +++ b/js/src/gc/Nursery.cpp @@ -537,7 +537,7 @@ js::Nursery::forwardBufferPointer(HeapSlot **pSlotsElems) // been tenured during a minor collection. struct TenureCount { - types::ObjectGroup *group; + ObjectGroup *group; int count; }; @@ -550,8 +550,8 @@ struct Nursery::TenureCountCache TenureCountCache() { PodZero(this); } - TenureCount &findEntry(types::ObjectGroup *group) { - return entries[PointerHasher::hash(group) % ArrayLength(entries)]; + TenureCount &findEntry(ObjectGroup *group) { + return entries[PointerHasher::hash(group) % ArrayLength(entries)]; } }; diff --git a/js/src/gc/Nursery.h b/js/src/gc/Nursery.h index 6d6bf6634c82..91ab2beb242a 100644 --- a/js/src/gc/Nursery.h +++ b/js/src/gc/Nursery.h @@ -31,6 +31,8 @@ class TypedArrayObject; class ObjectElements; class NativeObject; class HeapSlot; +class ObjectGroup; + void SetGCZeal(JSRuntime *, uint8_t, uint32_t); namespace gc { @@ -39,10 +41,6 @@ class Collector; class MinorCollectionTracer; } /* namespace gc */ -namespace types { -struct ObjectGroup; -} - namespace jit { class CodeGenerator; class MacroAssembler; @@ -117,7 +115,7 @@ class Nursery /* Free a slots array. */ void freeSlots(HeapSlot *slots); - typedef Vector ObjectGroupList; + typedef Vector ObjectGroupList; /* * Do a minor collection, optionally specifying a list to store groups which diff --git a/js/src/gc/RootMarking.cpp b/js/src/gc/RootMarking.cpp index 4bac29030c66..a9d5c872aabf 100644 --- a/js/src/gc/RootMarking.cpp +++ b/js/src/gc/RootMarking.cpp @@ -103,7 +103,7 @@ MarkExactStackRootsAcrossTypes(T context, JSTracer *trc) MarkExactStackRootList(trc, context, "exact-object"); MarkExactStackRootList(trc, context, "exact-shape"); MarkExactStackRootList(trc, context, "exact-baseshape"); - MarkExactStackRootList( + MarkExactStackRootList( trc, context, "exact-objectgroup"); MarkExactStackRootList(trc, context, "exact-string"); MarkExactStackRootList(trc, context, "exact-symbol"); diff --git a/js/src/gc/Rooting.h b/js/src/gc/Rooting.h index 0df33dba79cc..ab38313521c0 100644 --- a/js/src/gc/Rooting.h +++ b/js/src/gc/Rooting.h @@ -20,14 +20,13 @@ class ArrayObject; class PlainObject; class ScriptSourceObject; class Shape; - -namespace types { struct ObjectGroup; } +class ObjectGroup; // These are internal counterparts to the public types such as HandleObject. typedef JS::Handle HandleNativeObject; typedef JS::Handle HandleShape; -typedef JS::Handle HandleObjectGroup; +typedef JS::Handle HandleObjectGroup; typedef JS::Handle HandleAtom; typedef JS::Handle HandleLinearString; typedef JS::Handle HandlePropertyName; @@ -41,7 +40,7 @@ typedef JS::MutableHandle MutableHandleNativeObject; typedef JS::Rooted RootedNativeObject; typedef JS::Rooted RootedShape; -typedef JS::Rooted RootedObjectGroup; +typedef JS::Rooted RootedObjectGroup; typedef JS::Rooted RootedAtom; typedef JS::Rooted RootedLinearString; typedef JS::Rooted RootedPropertyName; diff --git a/js/src/gc/Tracer.h b/js/src/gc/Tracer.h index eca88dc93259..9aa525f02846 100644 --- a/js/src/gc/Tracer.h +++ b/js/src/gc/Tracer.h @@ -16,15 +16,13 @@ namespace js { class NativeObject; class GCMarker; +class ObjectGroup; namespace gc { struct ArenaHeader; } namespace jit { class JitCode; } -namespace types { -struct ObjectGroup; -} static const size_t NON_INCREMENTAL_MARK_STACK_BASE_CAPACITY = 4096; static const size_t INCREMENTAL_MARK_STACK_BASE_CAPACITY = 32768; @@ -143,7 +141,7 @@ class GCMarker : public JSTracer pushTaggedPtr(ObjectTag, obj); } - void pushType(types::ObjectGroup *group) { + void pushType(ObjectGroup *group) { pushTaggedPtr(GroupTag, group); } diff --git a/js/src/jit/BaselineCompiler.cpp b/js/src/jit/BaselineCompiler.cpp index ada836df6b8e..c950926e07a4 100644 --- a/js/src/jit/BaselineCompiler.cpp +++ b/js/src/jit/BaselineCompiler.cpp @@ -1722,8 +1722,8 @@ BaselineCompiler::emit_JSOP_NEWARRAY() uint32_t length = GET_UINT24(pc); RootedObjectGroup group(cx); - if (!types::UseSingletonForInitializer(script, pc, JSProto_Array)) { - group = types::TypeScript::InitGroup(cx, script, pc, JSProto_Array); + if (!ObjectGroup::useSingletonForAllocationSite(script, pc, JSProto_Array)) { + group = ObjectGroup::allocationSiteGroup(cx, script, pc, JSProto_Array); if (!group) return false; } @@ -1753,7 +1753,7 @@ bool BaselineCompiler::emit_JSOP_NEWARRAY_COPYONWRITE() { RootedScript scriptRoot(cx, script); - JSObject *obj = types::GetOrFixupCopyOnWriteObject(cx, scriptRoot, pc); + JSObject *obj = ObjectGroup::getOrFixupCopyOnWriteObject(cx, scriptRoot, pc); if (!obj) return false; @@ -1797,8 +1797,8 @@ BaselineCompiler::emit_JSOP_NEWOBJECT() frame.syncStack(0); RootedObjectGroup group(cx); - if (!types::UseSingletonForInitializer(script, pc, JSProto_Object)) { - group = types::TypeScript::InitGroup(cx, script, pc, JSProto_Object); + if (!ObjectGroup::useSingletonForAllocationSite(script, pc, JSProto_Object)) { + group = ObjectGroup::allocationSiteGroup(cx, script, pc, JSProto_Object); if (!group) return false; } @@ -1822,8 +1822,8 @@ BaselineCompiler::emit_JSOP_NEWOBJECT() Register objReg = R0.scratchReg(); Register tempReg = R1.scratchReg(); masm.movePtr(ImmGCPtr(group), tempReg); - masm.branchTest32(Assembler::NonZero, Address(tempReg, types::ObjectGroup::offsetOfFlags()), - Imm32(types::OBJECT_FLAG_PRE_TENURE), &slowPath); + masm.branchTest32(Assembler::NonZero, Address(tempReg, ObjectGroup::offsetOfFlags()), + Imm32(OBJECT_FLAG_PRE_TENURE), &slowPath); masm.branchPtr(Assembler::NotEqual, AbsoluteAddress(cx->compartment()->addressOfMetadataCallback()), ImmWord(0), &slowPath); masm.createGCObject(objReg, tempReg, templateObject, gc::DefaultHeap, &slowPath); @@ -1848,8 +1848,8 @@ BaselineCompiler::emit_JSOP_NEWINIT() JSProtoKey key = JSProtoKey(GET_UINT8(pc)); RootedObjectGroup group(cx); - if (!types::UseSingletonForInitializer(script, pc, key)) { - group = types::TypeScript::InitGroup(cx, script, pc, key); + if (!ObjectGroup::useSingletonForAllocationSite(script, pc, key)) { + group = ObjectGroup::allocationSiteGroup(cx, script, pc, key); if (!group) return false; } @@ -3364,7 +3364,7 @@ BaselineCompiler::emit_JSOP_REST() ArrayObject *templateObject = NewDenseUnallocatedArray(cx, 0, nullptr, TenuredObject); if (!templateObject) return false; - types::FixRestArgumentsType(cx, templateObject); + ObjectGroup::fixRestArgumentsGroup(cx, templateObject); // Call IC. ICRest_Fallback::Compiler compiler(cx, templateObject); diff --git a/js/src/jit/BaselineIC.cpp b/js/src/jit/BaselineIC.cpp index 0a55cabf4152..02290db929bd 100644 --- a/js/src/jit/BaselineIC.cpp +++ b/js/src/jit/BaselineIC.cpp @@ -2062,7 +2062,7 @@ ICCompare_ObjectWithUndefined::Compiler::generateStubCode(MacroAssembler &masm) Label emulatesUndefined; Register obj = masm.extractObject(objectOperand, ExtractTemp0); masm.loadPtr(Address(obj, JSObject::offsetOfGroup()), obj); - masm.loadPtr(Address(obj, types::ObjectGroup::offsetOfClasp()), obj); + masm.loadPtr(Address(obj, ObjectGroup::offsetOfClasp()), obj); masm.branchTest32(Assembler::NonZero, Address(obj, Class::offsetOfFlags()), Imm32(JSCLASS_EMULATES_UNDEFINED), @@ -4521,7 +4521,7 @@ LoadTypedThingLength(MacroAssembler &masm, TypedThingLayout layout, Register obj case Layout_OutlineTypedObject: case Layout_InlineTypedObject: masm.loadPtr(Address(obj, JSObject::offsetOfGroup()), result); - masm.loadPtr(Address(result, types::ObjectGroup::offsetOfAddendum()), result); + masm.loadPtr(Address(result, ObjectGroup::offsetOfAddendum()), result); masm.unboxInt32(Address(result, ArrayTypeDescr::offsetOfLength()), result); break; default: @@ -8520,7 +8520,7 @@ ICSetPropNativeAddCompiler::generateStubCode(MacroAssembler &masm) // Check if the old group still has a newScript. masm.loadPtr(Address(objReg, JSObject::offsetOfGroup()), scratch); masm.branchPtr(Assembler::Equal, - Address(scratch, types::ObjectGroup::offsetOfAddendum()), + Address(scratch, ObjectGroup::offsetOfAddendum()), ImmWord(0), &noGroupChange); @@ -9049,7 +9049,7 @@ GetTemplateObjectForNative(JSContext *cx, HandleScript script, jsbytecode *pc, if (!res) return false; - types::ObjectGroup *group = types::TypeScript::InitGroup(cx, script, pc, JSProto_Array); + ObjectGroup *group = ObjectGroup::allocationSiteGroup(cx, script, pc, JSProto_Array); if (!group) return false; res->setGroup(group); @@ -9061,7 +9061,7 @@ GetTemplateObjectForNative(JSContext *cx, HandleScript script, jsbytecode *pc, if (!res) return false; - types::ObjectGroup *group = types::TypeScript::InitGroup(cx, script, pc, JSProto_Array); + ObjectGroup *group = ObjectGroup::allocationSiteGroup(cx, script, pc, JSProto_Array); if (!group) return false; res->setGroup(group); @@ -9085,7 +9085,7 @@ GetTemplateObjectForNative(JSContext *cx, HandleScript script, jsbytecode *pc, if (!res) return false; - types::ObjectGroup *group = types::TypeScript::InitGroup(cx, script, pc, JSProto_Array); + ObjectGroup *group = ObjectGroup::allocationSiteGroup(cx, script, pc, JSProto_Array); if (!group) return false; res->setGroup(group); @@ -9487,7 +9487,7 @@ DoCallFallback(JSContext *cx, BaselineFrame *frame, ICCall_Fallback *stub_, uint // Compute construcing and useNewGroup flags. bool constructing = (op == JSOP_NEW); - bool createSingleton = types::UseSingletonForNewObject(cx, script, pc); + bool createSingleton = ObjectGroup::useSingletonForNewObject(cx, script, pc); // Try attaching a call stub. if (!TryAttachCallStub(cx, stub, script, pc, op, argc, vp, constructing, false, createSingleton)) @@ -11609,7 +11609,7 @@ ICSetElem_Dense::ICSetElem_Dense(JitCode *stubCode, HandleShape shape, HandleObj group_(group) { } -ICSetElem_DenseAdd::ICSetElem_DenseAdd(JitCode *stubCode, types::ObjectGroup *group, +ICSetElem_DenseAdd::ICSetElem_DenseAdd(JitCode *stubCode, ObjectGroup *group, size_t protoChainDepth) : ICUpdatedStub(SetElem_DenseAdd, stubCode), group_(group) @@ -12123,7 +12123,7 @@ static bool DoRestFallback(JSContext *cx, ICRest_Fallback *stub, ArrayObject *obj = NewDenseCopiedArray(cx, numRest, rest, nullptr); if (!obj) return false; - types::FixRestArgumentsType(cx, obj); + ObjectGroup::fixRestArgumentsGroup(cx, obj); res.setObject(*obj); return true; } diff --git a/js/src/jit/BaselineIC.h b/js/src/jit/BaselineIC.h index 1c26077b7cf8..675782b07e91 100644 --- a/js/src/jit/BaselineIC.h +++ b/js/src/jit/BaselineIC.h @@ -3576,7 +3576,7 @@ class ICSetElem_DenseAdd : public ICUpdatedStub protected: HeapPtrObjectGroup group_; - ICSetElem_DenseAdd(JitCode *stubCode, types::ObjectGroup *group, size_t protoChainDepth); + ICSetElem_DenseAdd(JitCode *stubCode, ObjectGroup *group, size_t protoChainDepth); public: static size_t offsetOfGroup() { @@ -3611,7 +3611,7 @@ class ICSetElem_DenseAddImpl : public ICSetElem_DenseAdd static const size_t NumShapes = ProtoChainDepth + 1; mozilla::Array shapes_; - ICSetElem_DenseAddImpl(JitCode *stubCode, types::ObjectGroup *group, + ICSetElem_DenseAddImpl(JitCode *stubCode, ObjectGroup *group, const AutoShapeVector *shapes) : ICSetElem_DenseAdd(stubCode, group, ProtoChainDepth) { @@ -3622,7 +3622,7 @@ class ICSetElem_DenseAddImpl : public ICSetElem_DenseAdd public: static inline ICSetElem_DenseAddImpl *New(ICStubSpace *space, JitCode *code, - types::ObjectGroup *group, + ObjectGroup *group, const AutoShapeVector *shapes) { if (!code) @@ -4585,7 +4585,7 @@ class ICGetProp_Unboxed : public ICMonitoredStub public: Compiler(JSContext *cx, ICStub *firstMonitorStub, - types::ObjectGroup *group, uint32_t fieldOffset, JSValueType fieldType) + ObjectGroup *group, uint32_t fieldOffset, JSValueType fieldType) : ICStubCompiler(cx, ICStub::GetProp_Unboxed), firstMonitorStub_(firstMonitorStub), group_(cx, group), @@ -5545,7 +5545,7 @@ class ICSetProp_Unboxed : public ICUpdatedStub } public: - Compiler(JSContext *cx, types::ObjectGroup *group, uint32_t fieldOffset, + Compiler(JSContext *cx, ObjectGroup *group, uint32_t fieldOffset, JSValueType fieldType) : ICStubCompiler(cx, ICStub::SetProp_Unboxed), group_(cx, group), @@ -5635,7 +5635,7 @@ class ICSetProp_TypedObject : public ICUpdatedStub } public: - Compiler(JSContext *cx, Shape *shape, types::ObjectGroup *group, uint32_t fieldOffset, + Compiler(JSContext *cx, Shape *shape, ObjectGroup *group, uint32_t fieldOffset, SimpleTypeDescr *fieldDescr) : ICStubCompiler(cx, ICStub::SetProp_TypedObject), shape_(cx, shape), diff --git a/js/src/jit/BaselineInspector.cpp b/js/src/jit/BaselineInspector.cpp index c6dfef1e797c..ba09bc6509fe 100644 --- a/js/src/jit/BaselineInspector.cpp +++ b/js/src/jit/BaselineInspector.cpp @@ -99,7 +99,7 @@ BaselineInspector::maybeInfoForPropertyOp(jsbytecode *pc, ICStub *stub = entry.firstStub(); while (stub->next()) { Shape *shape = nullptr; - types::ObjectGroup *group = nullptr; + ObjectGroup *group = nullptr; if (stub->isGetProp_Native()) { shape = stub->toGetProp_Native()->shape(); } else if (stub->isSetProp_Native()) { diff --git a/js/src/jit/BaselineInspector.h b/js/src/jit/BaselineInspector.h index 6bf778da77a1..30082cfcd89a 100644 --- a/js/src/jit/BaselineInspector.h +++ b/js/src/jit/BaselineInspector.h @@ -93,7 +93,7 @@ class BaselineInspector public: typedef Vector ShapeVector; - typedef Vector ObjectGroupVector; + typedef Vector ObjectGroupVector; bool maybeInfoForPropertyOp(jsbytecode *pc, ShapeVector &nativeShapes, ObjectGroupVector &unboxedGroups); diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp index 42e9bdd6a4c4..c4450739e272 100644 --- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -723,7 +723,7 @@ CodeGenerator::visitFunctionDispatch(LFunctionDispatch *lir) for (size_t i = 0; i < casesWithFallback - 1; i++) { MOZ_ASSERT(i < mir->numCases()); LBlock *target = skipTrivialBlocks(mir->getCaseBlock(i))->lir(); - if (types::ObjectGroup *funcGroup = mir->getCaseObjectGroup(i)) { + if (ObjectGroup *funcGroup = mir->getCaseObjectGroup(i)) { masm.branchPtr(Assembler::Equal, Address(input, JSObject::offsetOfGroup()), ImmGCPtr(funcGroup), target->label()); } else { @@ -764,7 +764,7 @@ CodeGenerator::visitObjectGroupDispatch(LObjectGroupDispatch *lir) if (lastBranch.isInitialized()) lastBranch.emit(masm); - types::ObjectGroup *group = propTable->getObjectGroup(j); + ObjectGroup *group = propTable->getObjectGroup(j); lastBranch = MacroAssembler::BranchGCPtr(Assembler::Equal, temp, ImmGCPtr(group), target->label()); lastBlock = target; @@ -3680,8 +3680,8 @@ CodeGenerator::emitObjectOrStringResultChecks(LInstruction *lir, MDefinition *mi // properties become unknown, so check for this case. masm.loadPtr(Address(output, JSObject::offsetOfGroup()), temp); masm.branchTestPtr(Assembler::NonZero, - Address(temp, types::ObjectGroup::offsetOfFlags()), - Imm32(types::OBJECT_FLAG_UNKNOWN_PROPERTIES), &ok); + Address(temp, ObjectGroup::offsetOfFlags()), + Imm32(OBJECT_FLAG_UNKNOWN_PROPERTIES), &ok); masm.assumeUnreachable("MIR instruction returned object with unexpected type"); @@ -3760,8 +3760,8 @@ CodeGenerator::emitValueResultChecks(LInstruction *lir, MDefinition *mir) Register payload = masm.extractObject(output, temp1); masm.loadPtr(Address(payload, JSObject::offsetOfGroup()), temp1); masm.branchTestPtr(Assembler::NonZero, - Address(temp1, types::ObjectGroup::offsetOfFlags()), - Imm32(types::OBJECT_FLAG_UNKNOWN_PROPERTIES), &ok); + Address(temp1, ObjectGroup::offsetOfFlags()), + Imm32(OBJECT_FLAG_UNKNOWN_PROPERTIES), &ok); masm.bind(&realMiss); masm.assumeUnreachable("MIR instruction returned value with unexpected type"); @@ -3947,7 +3947,7 @@ CodeGenerator::visitNewArrayCallVM(LNewArray *lir) saveLive(lir); JSObject *templateObject = lir->mir()->templateObject(); - types::ObjectGroup *group = + ObjectGroup *group = templateObject->isSingleton() ? nullptr : templateObject->group(); pushArg(Imm32(lir->mir()->allocatingBehaviour())); @@ -4338,7 +4338,7 @@ CodeGenerator::visitSimdUnbox(LSimdUnbox *lir) // Guard that the object has the same representation as the one produced for // SIMD value-type. - Address clasp(temp, types::ObjectGroup::offsetOfClasp()); + Address clasp(temp, ObjectGroup::offsetOfClasp()); static_assert(!SimdTypeDescr::Opaque, "SIMD objects are transparent"); masm.branchPtr(Assembler::NotEqual, clasp, ImmPtr(&InlineTransparentTypedObject::class_), &bail); @@ -4346,7 +4346,7 @@ CodeGenerator::visitSimdUnbox(LSimdUnbox *lir) // obj->type()->typeDescr() // The previous class pointer comparison implies that the addendumKind is // Addendum_TypeDescr. - masm.loadPtr(Address(temp, types::ObjectGroup::offsetOfAddendum()), temp); + masm.loadPtr(Address(temp, ObjectGroup::offsetOfAddendum()), temp); // Check for the /Kind/ reserved slot of the TypeDescr. This is an Int32 // Value which is equivalent to the object class check. @@ -4810,7 +4810,7 @@ CodeGenerator::visitTypedObjectDescr(LTypedObjectDescr *lir) Register out = ToRegister(lir->output()); masm.loadPtr(Address(obj, JSObject::offsetOfGroup()), out); - masm.loadPtr(Address(out, types::ObjectGroup::offsetOfAddendum()), out); + masm.loadPtr(Address(out, ObjectGroup::offsetOfAddendum()), out); } void diff --git a/js/src/jit/Disassembler.h b/js/src/jit/Disassembler.h index c9868c8a1f7d..101dc3941d63 100644 --- a/js/src/jit/Disassembler.h +++ b/js/src/jit/Disassembler.h @@ -7,6 +7,7 @@ #ifndef jit_Disassembler_h #define jit_Disassembler_h +#include "jit/MacroAssembler.h" #include "jit/Registers.h" namespace js { diff --git a/js/src/jit/IonAnalysis.cpp b/js/src/jit/IonAnalysis.cpp index ef090e94ee21..349564a6d54b 100644 --- a/js/src/jit/IonAnalysis.cpp +++ b/js/src/jit/IonAnalysis.cpp @@ -2880,7 +2880,7 @@ jit::ConvertLinearInequality(TempAllocator &alloc, MBasicBlock *block, const Lin } static bool -AnalyzePoppedThis(JSContext *cx, types::ObjectGroup *group, +AnalyzePoppedThis(JSContext *cx, ObjectGroup *group, MDefinition *thisValue, MInstruction *ins, bool definitelyExecuted, HandlePlainObject baseobj, Vector *initializerList, @@ -2896,9 +2896,6 @@ AnalyzePoppedThis(JSContext *cx, types::ObjectGroup *group, if (setprop->object() != thisValue) return true; - // Don't use GetAtomId here, we need to watch for SETPROP on - // integer properties and bail out. We can't mark the aggregate - // JSID_VOID type property as being in a definite slot. if (setprop->name() == cx->names().prototype || setprop->name() == cx->names().proto || setprop->name() == cx->names().constructor) @@ -3016,7 +3013,7 @@ CmpInstructions(const void *a, const void *b) bool jit::AnalyzeNewScriptDefiniteProperties(JSContext *cx, JSFunction *fun, - types::ObjectGroup *group, HandlePlainObject baseobj, + ObjectGroup *group, HandlePlainObject baseobj, Vector *initializerList) { MOZ_ASSERT(cx->zone()->types.activeAnalysis); diff --git a/js/src/jit/IonAnalysis.h b/js/src/jit/IonAnalysis.h index 116d465eeac9..0a4b4bb9f28d 100644 --- a/js/src/jit/IonAnalysis.h +++ b/js/src/jit/IonAnalysis.h @@ -170,7 +170,7 @@ ConvertLinearInequality(TempAllocator &alloc, MBasicBlock *block, const LinearSu bool AnalyzeNewScriptDefiniteProperties(JSContext *cx, JSFunction *fun, - types::ObjectGroup *group, HandlePlainObject baseobj, + ObjectGroup *group, HandlePlainObject baseobj, Vector *initializerList); bool diff --git a/js/src/jit/IonBuilder.cpp b/js/src/jit/IonBuilder.cpp index 0e8a28dbcc90..09261341f6d3 100644 --- a/js/src/jit/IonBuilder.cpp +++ b/js/src/jit/IonBuilder.cpp @@ -359,7 +359,7 @@ IonBuilder::getPolyCallTargets(types::TemporaryTypeSet *calleeTypes, bool constr if (obj) { MOZ_ASSERT(obj->isSingleton()); } else { - types::ObjectGroup *group = calleeTypes->getGroup(i); + ObjectGroup *group = calleeTypes->getGroup(i); if (!group) continue; @@ -5322,7 +5322,7 @@ IonBuilder::inlineCalls(CallInfo &callInfo, const ObjectVector &targets, // // Note that guarding is on the original function pointer even // if there is a clone, since cloning occurs at the callsite. - types::ObjectGroup *funcGroup = original->isSingleton() ? nullptr : original->group(); + ObjectGroup *funcGroup = original->isSingleton() ? nullptr : original->group(); dispatch->addCase(original, funcGroup, inlineBlock); MDefinition *retVal = inlineReturnBlock->peek(-1); @@ -5543,7 +5543,7 @@ IonBuilder::createThisScriptedSingleton(JSFunction *target, MDefinition *callee) return nullptr; types::TypeSetObjectKey *templateObjectKey = types::TypeSetObjectKey::get(templateObject->group()); - if (templateObjectKey->hasFlags(constraints(), types::OBJECT_FLAG_NEW_SCRIPT_CLEARED)) + if (templateObjectKey->hasFlags(constraints(), OBJECT_FLAG_NEW_SCRIPT_CLEARED)) return nullptr; types::StackTypeSet *thisTypes = types::TypeScript::ThisTypes(target->nonLazyScript()); @@ -6250,14 +6250,14 @@ IonBuilder::jsop_newarray(uint32_t count) bool IonBuilder::jsop_newarray_copyonwrite() { - ArrayObject *templateObject = types::GetCopyOnWriteObject(script(), pc); + ArrayObject *templateObject = ObjectGroup::getCopyOnWriteObject(script(), pc); // The baseline compiler should have ensured the template object has a type // with the copy on write flag set already. During the arguments usage // analysis the baseline compiler hasn't run yet, however, though in this // case the template object's type doesn't matter. MOZ_ASSERT_IF(info().analysisMode() != Analysis_ArgumentsUsage, - templateObject->group()->hasAnyFlags(types::OBJECT_FLAG_COPY_ON_WRITE)); + templateObject->group()->hasAnyFlags(OBJECT_FLAG_COPY_ON_WRITE)); MNewArrayCopyOnWrite *ins = MNewArrayCopyOnWrite::New(alloc(), constraints(), templateObject, @@ -6326,7 +6326,7 @@ IonBuilder::jsop_initelem_array() } else { types::TypeSetObjectKey *initializer = obj->resultTypeSet()->getObject(0); if (value->type() == MIRType_MagicHole) { - if (!initializer->hasFlags(constraints(), types::OBJECT_FLAG_NON_PACKED)) + if (!initializer->hasFlags(constraints(), OBJECT_FLAG_NON_PACKED)) needStub = true; } else if (!initializer->unknownProperties()) { types::HeapTypeSetKey elemTypes = initializer->property(JSID_VOID); @@ -7629,7 +7629,7 @@ IonBuilder::checkTypedObjectIndexInBounds(int32_t elemSize, // If we are not loading the length from the object itself, only // optimize if the array buffer can't have been neutered. types::TypeSetObjectKey *globalKey = types::TypeSetObjectKey::get(&script()->global()); - if (globalKey->hasFlags(constraints(), types::OBJECT_FLAG_TYPED_OBJECT_NEUTERED)) { + if (globalKey->hasFlags(constraints(), OBJECT_FLAG_TYPED_OBJECT_NEUTERED)) { trackOptimizationOutcome(TrackedOutcome::TypedObjectNeutered); return false; } @@ -9082,7 +9082,7 @@ IonBuilder::jsop_length_fastPath() // Compute the length for array objects. if (objTypes && objTypes->getKnownClass(constraints()) == &ArrayObject::class_ && - !objTypes->hasObjectFlags(constraints(), types::OBJECT_FLAG_LENGTH_OVERFLOW)) + !objTypes->hasObjectFlags(constraints(), OBJECT_FLAG_LENGTH_OVERFLOW)) { current->pop(); MElements *elements = MElements::New(alloc(), obj); @@ -9099,7 +9099,7 @@ IonBuilder::jsop_length_fastPath() TypedObjectPrediction prediction = typedObjectPrediction(obj); if (!prediction.isUseless()) { types::TypeSetObjectKey *globalKey = types::TypeSetObjectKey::get(&script()->global()); - if (globalKey->hasFlags(constraints(), types::OBJECT_FLAG_TYPED_OBJECT_NEUTERED)) + if (globalKey->hasFlags(constraints(), OBJECT_FLAG_TYPED_OBJECT_NEUTERED)) return false; MInstruction *length; @@ -9230,7 +9230,7 @@ IonBuilder::getDefiniteSlot(types::TemporaryTypeSet *types, PropertyName *name) if (!key) continue; - if (types::ObjectGroup *group = key->maybeGroup()) { + if (ObjectGroup *group = key->maybeGroup()) { if (group->newScript() && !group->newScript()->analyzed()) { addAbortedNewScriptPropertiesGroup(group); trackOptimizationOutcome(TrackedOutcome::NoAnalysisInfo); @@ -9538,7 +9538,7 @@ IonBuilder::annotateGetPropertyCache(MDefinition *obj, MGetPropertyCache *getPro // Ensure that the relevant property typeset for each group is // is a single-object typeset containing a JSFunction for (unsigned int i = 0; i < objCount; i++) { - types::ObjectGroup *group = objTypes->getGroup(i); + ObjectGroup *group = objTypes->getGroup(i); if (!group) continue; types::TypeSetObjectKey *key = types::TypeSetObjectKey::get(group); @@ -9988,7 +9988,7 @@ IonBuilder::getPropTryScalarPropOfTypedObject(bool *emitted, MDefinition *typedO // Don't optimize if the typed object might be neutered. types::TypeSetObjectKey *globalKey = types::TypeSetObjectKey::get(&script()->global()); - if (globalKey->hasFlags(constraints(), types::OBJECT_FLAG_TYPED_OBJECT_NEUTERED)) + if (globalKey->hasFlags(constraints(), OBJECT_FLAG_TYPED_OBJECT_NEUTERED)) return true; trackOptimizationSuccess(); @@ -10010,7 +10010,7 @@ IonBuilder::getPropTryReferencePropOfTypedObject(bool *emitted, MDefinition *typ ReferenceTypeDescr::Type fieldType = fieldPrediction.referenceType(); types::TypeSetObjectKey *globalKey = types::TypeSetObjectKey::get(&script()->global()); - if (globalKey->hasFlags(constraints(), types::OBJECT_FLAG_TYPED_OBJECT_NEUTERED)) + if (globalKey->hasFlags(constraints(), OBJECT_FLAG_TYPED_OBJECT_NEUTERED)) return true; trackOptimizationSuccess(); @@ -10032,7 +10032,7 @@ IonBuilder::getPropTryComplexPropOfTypedObject(bool *emitted, { // Don't optimize if the typed object might be neutered. types::TypeSetObjectKey *globalKey = types::TypeSetObjectKey::get(&script()->global()); - if (globalKey->hasFlags(constraints(), types::OBJECT_FLAG_TYPED_OBJECT_NEUTERED)) + if (globalKey->hasFlags(constraints(), OBJECT_FLAG_TYPED_OBJECT_NEUTERED)) return true; // OK, perform the optimization @@ -10430,7 +10430,7 @@ IonBuilder::getPropTryInlineAccess(bool *emitted, MDefinition *obj, PropertyName if (nativeShapes.empty() && unboxedGroups.length() == 1) { spew("Inlining monomorphic unboxed GETPROP"); - types::ObjectGroup *group = unboxedGroups[0]; + ObjectGroup *group = unboxedGroups[0]; // Failures in this group guard should be treated the same as a shape guard failure. obj = MGuardObjectGroup::New(alloc(), obj, group, /* bailOnEquality = */ false, @@ -10604,7 +10604,7 @@ IonBuilder::tryInnerizeWindow(MDefinition *obj) // its ObjectGroup as having unknown properties. The type constraint we add // here will invalidate JIT code when this happens. types::TypeSetObjectKey *key = types::TypeSetObjectKey::get(singleton); - if (key->hasFlags(constraints(), types::OBJECT_FLAG_UNKNOWN_PROPERTIES)) + if (key->hasFlags(constraints(), OBJECT_FLAG_UNKNOWN_PROPERTIES)) return obj; obj->setImplicitlyUsedUnchecked(); @@ -10883,7 +10883,7 @@ IonBuilder::setPropTryReferencePropOfTypedObject(bool *emitted, ReferenceTypeDescr::Type fieldType = fieldPrediction.referenceType(); types::TypeSetObjectKey *globalKey = types::TypeSetObjectKey::get(&script()->global()); - if (globalKey->hasFlags(constraints(), types::OBJECT_FLAG_TYPED_OBJECT_NEUTERED)) + if (globalKey->hasFlags(constraints(), OBJECT_FLAG_TYPED_OBJECT_NEUTERED)) return true; LinearSum byteOffset(alloc()); @@ -10912,7 +10912,7 @@ IonBuilder::setPropTryScalarPropOfTypedObject(bool *emitted, // Don't optimize if the typed object might be neutered. types::TypeSetObjectKey *globalKey = types::TypeSetObjectKey::get(&script()->global()); - if (globalKey->hasFlags(constraints(), types::OBJECT_FLAG_TYPED_OBJECT_NEUTERED)) + if (globalKey->hasFlags(constraints(), OBJECT_FLAG_TYPED_OBJECT_NEUTERED)) return true; LinearSum byteOffset(alloc()); @@ -11109,7 +11109,7 @@ IonBuilder::setPropTryInlineAccess(bool *emitted, MDefinition *obj, if (nativeShapes.empty() && unboxedGroups.length() == 1) { spew("Inlining monomorphic unboxed SETPROP"); - types::ObjectGroup *group = unboxedGroups[0]; + ObjectGroup *group = unboxedGroups[0]; // Failures in this group guard should be treated the same as a shape guard failure. obj = MGuardObjectGroup::New(alloc(), obj, group, /* bailOnEquality = */ false, @@ -11244,7 +11244,7 @@ IonBuilder::jsop_regexp(RegExpObject *reobj) bool mustClone = true; types::TypeSetObjectKey *globalKey = types::TypeSetObjectKey::get(&script()->global()); - if (!globalKey->hasFlags(constraints(), types::OBJECT_FLAG_REGEXP_FLAGS_SET)) { + if (!globalKey->hasFlags(constraints(), OBJECT_FLAG_REGEXP_FLAGS_SET)) { #ifdef DEBUG // Only compare the statics if the one on script()->global() has been // instantiated. @@ -11633,7 +11633,7 @@ IonBuilder::hasStaticScopeObject(ScopeCoordinate sc, JSObject **pcall) types::TypeSetObjectKey *funKey = types::TypeSetObjectKey::get(outerScript->functionNonDelazifying()); - if (funKey->hasFlags(constraints(), types::OBJECT_FLAG_RUNONCE_INVALIDATED)) + if (funKey->hasFlags(constraints(), OBJECT_FLAG_RUNONCE_INVALIDATED)) return false; // The script this aliased var operation is accessing will run only once, @@ -12103,7 +12103,7 @@ IonBuilder::typedObjectPrediction(types::TemporaryTypeSet *types) TypedObjectPrediction out; for (uint32_t i = 0; i < types->getObjectCount(); i++) { - types::ObjectGroup *group = types->getGroup(i); + ObjectGroup *group = types->getGroup(i); if (!group || !types::TypeSetObjectKey::get(group)->hasStableClassAndProto(constraints())) return TypedObjectPrediction(); diff --git a/js/src/jit/IonCaches.cpp b/js/src/jit/IonCaches.cpp index d9f27fcbbb8a..88cd9ce87c21 100644 --- a/js/src/jit/IonCaches.cpp +++ b/js/src/jit/IonCaches.cpp @@ -488,7 +488,7 @@ GeneratePrototypeGuards(JSContext *cx, IonScript *ion, MacroAssembler &masm, JSO // Note: objectReg and scratchReg may be the same register, so we cannot // use objectReg in the rest of this function. masm.loadPtr(Address(objectReg, JSObject::offsetOfGroup()), scratchReg); - Address proto(scratchReg, types::ObjectGroup::offsetOfProto()); + Address proto(scratchReg, ObjectGroup::offsetOfProto()); masm.branchPtr(Assembler::NotEqual, proto, ImmMaybeNurseryPtr(obj->getProto()), failures); } @@ -1897,7 +1897,7 @@ CheckTypeSetForWrite(MacroAssembler &masm, JSObject *obj, jsid id, Register object, ConstantOrRegister value, Label *failure) { TypedOrValueRegister valReg = value.reg(); - types::ObjectGroup *group = obj->group(); + ObjectGroup *group = obj->group(); if (group->unknownProperties()) return; types::HeapTypeSet *propTypes = group->maybeGetProperty(id); @@ -1929,7 +1929,7 @@ GenerateSetSlot(JSContext *cx, MacroAssembler &masm, IonCache::StubAttacher &att // just guard that it's already there. // Obtain and guard on the ObjectGroup of the object. - types::ObjectGroup *group = obj->group(); + ObjectGroup *group = obj->group(); masm.branchPtr(Assembler::NotEqual, Address(object, JSObject::offsetOfGroup()), ImmGCPtr(group), &failures); @@ -2463,7 +2463,7 @@ SetPropertyIC::attachCallSetter(JSContext *cx, HandleScript outerScript, IonScri static void GenerateAddSlot(JSContext *cx, MacroAssembler &masm, IonCache::StubAttacher &attacher, - NativeObject *obj, Shape *oldShape, types::ObjectGroup *oldGroup, + NativeObject *obj, Shape *oldShape, ObjectGroup *oldGroup, Register object, ConstantOrRegister value, bool checkTypeset) { @@ -2520,7 +2520,7 @@ GenerateAddSlot(JSContext *cx, MacroAssembler &masm, IonCache::StubAttacher &att masm.push(object); masm.loadPtr(Address(object, JSObject::offsetOfGroup()), object); masm.branchPtr(Assembler::Equal, - Address(object, types::ObjectGroup::offsetOfAddendum()), + Address(object, ObjectGroup::offsetOfAddendum()), ImmWord(0), &noTypeChange); masm.pop(object); @@ -2579,7 +2579,7 @@ static bool CanInlineSetPropTypeCheck(JSObject *obj, jsid id, ConstantOrRegister val, bool *checkTypeset) { bool shouldCheck = false; - types::ObjectGroup *group = obj->group(); + ObjectGroup *group = obj->group(); if (!group->unknownProperties()) { types::HeapTypeSet *propTypes = group->maybeGetProperty(id); if (!propTypes) diff --git a/js/src/jit/MCallOptimize.cpp b/js/src/jit/MCallOptimize.cpp index 2a51d1d2e053..36b9496dc3eb 100644 --- a/js/src/jit/MCallOptimize.cpp +++ b/js/src/jit/MCallOptimize.cpp @@ -506,10 +506,10 @@ IonBuilder::inlineArrayPopShift(CallInfo &callInfo, MArrayPopShift::Mode mode) // Pop and shift are only handled for dense arrays that have never been // used in an iterator: popping elements does not account for suppressing // deleted properties in active iterators. - types::ObjectGroupFlags unhandledFlags = - types::OBJECT_FLAG_SPARSE_INDEXES | - types::OBJECT_FLAG_LENGTH_OVERFLOW | - types::OBJECT_FLAG_ITERATED; + ObjectGroupFlags unhandledFlags = + OBJECT_FLAG_SPARSE_INDEXES | + OBJECT_FLAG_LENGTH_OVERFLOW | + OBJECT_FLAG_ITERATED; MDefinition *obj = callInfo.thisArg(); types::TemporaryTypeSet *thisTypes = obj->resultTypeSet(); @@ -530,7 +530,7 @@ IonBuilder::inlineArrayPopShift(CallInfo &callInfo, MArrayPopShift::Mode mode) obj = addMaybeCopyElementsForWrite(obj); types::TemporaryTypeSet *returnTypes = getInlineReturnTypeSet(); - bool needsHoleCheck = thisTypes->hasObjectFlags(constraints(), types::OBJECT_FLAG_NON_PACKED); + bool needsHoleCheck = thisTypes->hasObjectFlags(constraints(), OBJECT_FLAG_NON_PACKED); bool maybeUndefined = returnTypes->hasType(types::Type::UndefinedType()); BarrierKind barrier = PropertyReadNeedsTypeBarrier(analysisContext, constraints(), @@ -643,8 +643,8 @@ IonBuilder::inlineArrayPush(CallInfo &callInfo) types::TemporaryTypeSet *thisTypes = callInfo.thisArg()->resultTypeSet(); if (!thisTypes || thisTypes->getKnownClass(constraints()) != &ArrayObject::class_) return InliningStatus_NotInlined; - if (thisTypes->hasObjectFlags(constraints(), types::OBJECT_FLAG_SPARSE_INDEXES | - types::OBJECT_FLAG_LENGTH_OVERFLOW)) + if (thisTypes->hasObjectFlags(constraints(), OBJECT_FLAG_SPARSE_INDEXES | + OBJECT_FLAG_LENGTH_OVERFLOW)) { trackOptimizationOutcome(TrackedOutcome::ArrayBadFlags); return InliningStatus_NotInlined; @@ -711,8 +711,8 @@ IonBuilder::inlineArrayConcat(CallInfo &callInfo) if (thisTypes->getKnownClass(constraints()) != &ArrayObject::class_) return InliningStatus_NotInlined; - if (thisTypes->hasObjectFlags(constraints(), types::OBJECT_FLAG_SPARSE_INDEXES | - types::OBJECT_FLAG_LENGTH_OVERFLOW)) + if (thisTypes->hasObjectFlags(constraints(), OBJECT_FLAG_SPARSE_INDEXES | + OBJECT_FLAG_LENGTH_OVERFLOW)) { trackOptimizationOutcome(TrackedOutcome::ArrayBadFlags); return InliningStatus_NotInlined; @@ -720,8 +720,8 @@ IonBuilder::inlineArrayConcat(CallInfo &callInfo) if (argTypes->getKnownClass(constraints()) != &ArrayObject::class_) return InliningStatus_NotInlined; - if (argTypes->hasObjectFlags(constraints(), types::OBJECT_FLAG_SPARSE_INDEXES | - types::OBJECT_FLAG_LENGTH_OVERFLOW)) + if (argTypes->hasObjectFlags(constraints(), OBJECT_FLAG_SPARSE_INDEXES | + OBJECT_FLAG_LENGTH_OVERFLOW)) { trackOptimizationOutcome(TrackedOutcome::ArrayBadFlags); return InliningStatus_NotInlined; @@ -738,7 +738,7 @@ IonBuilder::inlineArrayConcat(CallInfo &callInfo) if (thisTypes->getObjectCount() != 1) return InliningStatus_NotInlined; - types::ObjectGroup *thisGroup = thisTypes->getGroup(0); + ObjectGroup *thisGroup = thisTypes->getGroup(0); if (!thisGroup) return InliningStatus_NotInlined; types::TypeSetObjectKey *thisKey = types::TypeSetObjectKey::get(thisGroup); @@ -747,8 +747,8 @@ IonBuilder::inlineArrayConcat(CallInfo &callInfo) // Don't inline if 'this' is packed and the argument may not be packed // (the result array will reuse the 'this' type). - if (!thisTypes->hasObjectFlags(constraints(), types::OBJECT_FLAG_NON_PACKED) && - argTypes->hasObjectFlags(constraints(), types::OBJECT_FLAG_NON_PACKED)) + if (!thisTypes->hasObjectFlags(constraints(), OBJECT_FLAG_NON_PACKED) && + argTypes->hasObjectFlags(constraints(), OBJECT_FLAG_NON_PACKED)) { trackOptimizationOutcome(TrackedOutcome::ArrayBadFlags); return InliningStatus_NotInlined; diff --git a/js/src/jit/MIR.cpp b/js/src/jit/MIR.cpp index 7973d19734fd..c853014a0497 100644 --- a/js/src/jit/MIR.cpp +++ b/js/src/jit/MIR.cpp @@ -4321,14 +4321,14 @@ bool jit::ElementAccessIsPacked(types::CompilerConstraintList *constraints, MDefinition *obj) { types::TemporaryTypeSet *types = obj->resultTypeSet(); - return types && !types->hasObjectFlags(constraints, types::OBJECT_FLAG_NON_PACKED); + return types && !types->hasObjectFlags(constraints, OBJECT_FLAG_NON_PACKED); } bool jit::ElementAccessMightBeCopyOnWrite(types::CompilerConstraintList *constraints, MDefinition *obj) { types::TemporaryTypeSet *types = obj->resultTypeSet(); - return !types || types->hasObjectFlags(constraints, types::OBJECT_FLAG_COPY_ON_WRITE); + return !types || types->hasObjectFlags(constraints, OBJECT_FLAG_COPY_ON_WRITE); } bool @@ -4337,7 +4337,7 @@ jit::ElementAccessHasExtraIndexedProperty(types::CompilerConstraintList *constra { types::TemporaryTypeSet *types = obj->resultTypeSet(); - if (!types || types->hasObjectFlags(constraints, types::OBJECT_FLAG_LENGTH_OVERFLOW)) + if (!types || types->hasObjectFlags(constraints, OBJECT_FLAG_LENGTH_OVERFLOW)) return true; return types::TypeCanHaveExtraIndexedProperties(constraints, types); diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h index 921d78c18955..678c296880d0 100644 --- a/js/src/jit/MIR.h +++ b/js/src/jit/MIR.h @@ -6319,7 +6319,7 @@ class MStringSplit JSObject *templateObject() const { return &getOperand(2)->toConstant()->value().toObject(); } - types::ObjectGroup *group() const { + ObjectGroup *group() const { return templateObject()->group(); } bool possiblyCalls() const MOZ_OVERRIDE { @@ -7166,7 +7166,7 @@ struct LambdaFunctionInfo ? (gc::Cell *) fun->nonLazyScript() : (gc::Cell *) fun->lazyScript()), singletonType(fun->isSingleton()), - useSingletonForClone(types::UseSingletonForClone(fun)) + useSingletonForClone(ObjectGroup::useSingletonForClone(fun)) {} LambdaFunctionInfo(const LambdaFunctionInfo &info) @@ -7187,7 +7187,7 @@ class MLambda : MBinaryInstruction(scopeChain, cst), info_(&cst->value().toObject().as()) { setResultType(MIRType_Object); - if (!info().fun->isSingleton() && !types::UseSingletonForClone(info().fun)) + if (!info().fun->isSingleton() && !ObjectGroup::useSingletonForClone(info().fun)) setResultTypeSet(MakeSingletonTypeSet(constraints, info().fun)); } @@ -7225,7 +7225,7 @@ class MLambdaArrow : MBinaryInstruction(scopeChain, this_), info_(fun) { setResultType(MIRType_Object); - MOZ_ASSERT(!types::UseSingletonForClone(fun)); + MOZ_ASSERT(!ObjectGroup::useSingletonForClone(fun)); if (!fun->isSingleton()) setResultTypeSet(MakeSingletonTypeSet(constraints, fun)); } @@ -9201,10 +9201,10 @@ typedef Vector BoolVector; class InlinePropertyTable : public TempObject { struct Entry : public TempObject { - AlwaysTenured group; + AlwaysTenured group; AlwaysTenuredFunction func; - Entry(types::ObjectGroup *group, JSFunction *func) + Entry(ObjectGroup *group, JSFunction *func) : group(group), func(func) { } }; @@ -9232,7 +9232,7 @@ class InlinePropertyTable : public TempObject return pc_; } - bool addEntry(TempAllocator &alloc, types::ObjectGroup *group, JSFunction *func) { + bool addEntry(TempAllocator &alloc, ObjectGroup *group, JSFunction *func) { return entries_.append(new(alloc) Entry(group, func)); } @@ -9240,7 +9240,7 @@ class InlinePropertyTable : public TempObject return entries_.length(); } - types::ObjectGroup *getObjectGroup(size_t i) const { + ObjectGroup *getObjectGroup(size_t i) const { MOZ_ASSERT(i < numEntries()); return entries_[i]->group; } @@ -9380,7 +9380,7 @@ class MGetPropertyPolymorphic }; Vector nativeShapes_; - Vector unboxedGroups_; + Vector unboxedGroups_; AlwaysTenuredPropertyName name_; MGetPropertyPolymorphic(TempAllocator &alloc, MDefinition *obj, PropertyName *name) @@ -9415,7 +9415,7 @@ class MGetPropertyPolymorphic entry.shape = shape; return nativeShapes_.append(entry); } - bool addUnboxedGroup(types::ObjectGroup *group) { + bool addUnboxedGroup(ObjectGroup *group) { return unboxedGroups_.append(group); } size_t numShapes() const { @@ -9430,7 +9430,7 @@ class MGetPropertyPolymorphic size_t numUnboxedGroups() const { return unboxedGroups_.length(); } - types::ObjectGroup *unboxedGroup(size_t i) const { + ObjectGroup *unboxedGroup(size_t i) const { return unboxedGroups_[i]; } PropertyName *name() const { @@ -9462,7 +9462,7 @@ class MSetPropertyPolymorphic }; Vector nativeShapes_; - Vector unboxedGroups_; + Vector unboxedGroups_; AlwaysTenuredPropertyName name_; bool needsBarrier_; @@ -9490,7 +9490,7 @@ class MSetPropertyPolymorphic entry.shape = shape; return nativeShapes_.append(entry); } - bool addUnboxedGroup(types::ObjectGroup *group) { + bool addUnboxedGroup(ObjectGroup *group) { return unboxedGroups_.append(group); } size_t numShapes() const { @@ -9505,7 +9505,7 @@ class MSetPropertyPolymorphic size_t numUnboxedGroups() const { return unboxedGroups_.length(); } - types::ObjectGroup *unboxedGroup(size_t i) const { + ObjectGroup *unboxedGroup(size_t i) const { return unboxedGroups_[i]; } PropertyName *name() const { @@ -9539,10 +9539,10 @@ class MDispatchInstruction // If |func| has a singleton group, |funcGroup| is null. Otherwise, // |funcGroup| holds the ObjectGroup for |func|, and dispatch guards // on the group instead of directly on the function. - types::ObjectGroup *funcGroup; + ObjectGroup *funcGroup; MBasicBlock *block; - Entry(JSFunction *func, types::ObjectGroup *funcGroup, MBasicBlock *block) + Entry(JSFunction *func, ObjectGroup *funcGroup, MBasicBlock *block) : func(func), funcGroup(funcGroup), block(block) { } }; @@ -9611,7 +9611,7 @@ class MDispatchInstruction } public: - void addCase(JSFunction *func, types::ObjectGroup *funcGroup, MBasicBlock *block) { + void addCase(JSFunction *func, ObjectGroup *funcGroup, MBasicBlock *block) { map_.append(Entry(func, funcGroup, block)); } uint32_t numCases() const { @@ -9620,7 +9620,7 @@ class MDispatchInstruction JSFunction *getCase(uint32_t i) const { return map_[i].func; } - types::ObjectGroup *getCaseObjectGroup(uint32_t i) const { + ObjectGroup *getCaseObjectGroup(uint32_t i) const { return map_[i].funcGroup; } MBasicBlock *getCaseBlock(uint32_t i) const { @@ -9858,11 +9858,11 @@ class MGuardObjectGroup : public MUnaryInstruction, public SingleObjectPolicy::Data { - AlwaysTenured group_; + AlwaysTenured group_; bool bailOnEquality_; BailoutKind bailoutKind_; - MGuardObjectGroup(MDefinition *obj, types::ObjectGroup *group, bool bailOnEquality, + MGuardObjectGroup(MDefinition *obj, ObjectGroup *group, bool bailOnEquality, BailoutKind bailoutKind) : MUnaryInstruction(obj), group_(group), @@ -9877,7 +9877,7 @@ class MGuardObjectGroup public: INSTRUCTION_HEADER(GuardObjectGroup) - static MGuardObjectGroup *New(TempAllocator &alloc, MDefinition *obj, types::ObjectGroup *group, + static MGuardObjectGroup *New(TempAllocator &alloc, MDefinition *obj, ObjectGroup *group, bool bailOnEquality, BailoutKind bailoutKind) { return new(alloc) MGuardObjectGroup(obj, group, bailOnEquality, bailoutKind); } @@ -9885,7 +9885,7 @@ class MGuardObjectGroup MDefinition *obj() const { return getOperand(0); } - const types::ObjectGroup *group() const { + const ObjectGroup *group() const { return group_; } bool bailOnEquality() const { diff --git a/js/src/jit/MIRGenerator.h b/js/src/jit/MIRGenerator.h index e6dd38400780..dac1fcef865f 100644 --- a/js/src/jit/MIRGenerator.h +++ b/js/src/jit/MIRGenerator.h @@ -154,7 +154,7 @@ class MIRGenerator return modifiesFrameArguments_; } - typedef Vector ObjectGroupVector; + typedef Vector ObjectGroupVector; // When abortReason() == AbortReason_NewScriptProperties, all types which // the new script properties analysis hasn't been performed on yet. @@ -199,7 +199,7 @@ class MIRGenerator // CodeGenerator::link). ObjectVector nurseryObjects_; - void addAbortedNewScriptPropertiesGroup(types::ObjectGroup *type); + void addAbortedNewScriptPropertiesGroup(ObjectGroup *type); void setForceAbort() { shouldForceAbort_ = true; } diff --git a/js/src/jit/MIRGraph.cpp b/js/src/jit/MIRGraph.cpp index 36e3c3faca9b..49f8b187747c 100644 --- a/js/src/jit/MIRGraph.cpp +++ b/js/src/jit/MIRGraph.cpp @@ -93,7 +93,7 @@ MIRGenerator::abort(const char *message, ...) } void -MIRGenerator::addAbortedNewScriptPropertiesGroup(types::ObjectGroup *group) +MIRGenerator::addAbortedNewScriptPropertiesGroup(ObjectGroup *group) { for (size_t i = 0; i < abortedNewScriptPropertiesGroups_.length(); i++) { if (group == abortedNewScriptPropertiesGroups_[i]) diff --git a/js/src/jit/MacroAssembler.cpp b/js/src/jit/MacroAssembler.cpp index 525646870239..27e0f278a84e 100644 --- a/js/src/jit/MacroAssembler.cpp +++ b/js/src/jit/MacroAssembler.cpp @@ -60,7 +60,7 @@ class TypeWrapper { return t_.singletonNoBarrier(); return nullptr; } - inline types::ObjectGroup *getGroupNoBarrier(unsigned) const { + inline ObjectGroup *getGroupNoBarrier(unsigned) const { if (t_.isGroup()) return t_.groupNoBarrier(); return nullptr; @@ -146,8 +146,8 @@ MacroAssembler::guardTypeSet(const Source &address, const TypeSet *types, Barrie extractObject(address, scratch); loadPtr(Address(obj, JSObject::offsetOfGroup()), scratch); branchTestPtr(Assembler::NonZero, - Address(scratch, types::ObjectGroup::offsetOfFlags()), - Imm32(types::OBJECT_FLAG_UNKNOWN_PROPERTIES), &matched); + Address(scratch, ObjectGroup::offsetOfFlags()), + Imm32(OBJECT_FLAG_UNKNOWN_PROPERTIES), &matched); assumeUnreachable("Unexpected object type"); #endif @@ -210,7 +210,7 @@ MacroAssembler::guardObjectType(Register obj, const TypeSet *types, if (lastBranch.isInitialized()) lastBranch.emit(*this); - types::ObjectGroup *group = types->getGroupNoBarrier(i); + ObjectGroup *group = types->getGroupNoBarrier(i); lastBranch = BranchGCPtr(Equal, scratch, ImmGCPtr(group), &matched); } } diff --git a/js/src/jit/MacroAssembler.h b/js/src/jit/MacroAssembler.h index 2f92bfd37b90..ddb8eae3ebaa 100644 --- a/js/src/jit/MacroAssembler.h +++ b/js/src/jit/MacroAssembler.h @@ -290,12 +290,12 @@ class MacroAssembler : public MacroAssemblerSpecific } void loadObjClass(Register objReg, Register dest) { loadPtr(Address(objReg, JSObject::offsetOfGroup()), dest); - loadPtr(Address(dest, types::ObjectGroup::offsetOfClasp()), dest); + loadPtr(Address(dest, ObjectGroup::offsetOfClasp()), dest); } void branchTestObjClass(Condition cond, Register obj, Register scratch, const js::Class *clasp, Label *label) { loadPtr(Address(obj, JSObject::offsetOfGroup()), scratch); - branchPtr(cond, Address(scratch, types::ObjectGroup::offsetOfClasp()), ImmPtr(clasp), label); + branchPtr(cond, Address(scratch, ObjectGroup::offsetOfClasp()), ImmPtr(clasp), label); } void branchTestObjShape(Condition cond, Register obj, const Shape *shape, Label *label) { branchPtr(cond, Address(obj, JSObject::offsetOfShape()), ImmGCPtr(shape), label); @@ -348,7 +348,7 @@ class MacroAssembler : public MacroAssemblerSpecific void loadObjProto(Register obj, Register dest) { loadPtr(Address(obj, JSObject::offsetOfGroup()), dest); - loadPtr(Address(dest, types::ObjectGroup::offsetOfProto()), dest); + loadPtr(Address(dest, ObjectGroup::offsetOfProto()), dest); } void loadStringLength(Register str, Register dest) { diff --git a/js/src/jit/OptimizationTracking.cpp b/js/src/jit/OptimizationTracking.cpp index 7cfa5d551d9b..a5c3aed54015 100644 --- a/js/src/jit/OptimizationTracking.cpp +++ b/js/src/jit/OptimizationTracking.cpp @@ -818,7 +818,7 @@ MaybeConstructorFromType(types::Type ty) { if (ty.isUnknown() || ty.isAnyObject() || !ty.isGroup()) return nullptr; - types::ObjectGroup *obj = ty.group(); + ObjectGroup *obj = ty.group(); types::TypeNewScript *newScript = obj->newScript(); if (!newScript && obj->maybeUnboxedLayout()) newScript = obj->unboxedLayout().newScript(); @@ -954,7 +954,7 @@ jit::WriteIonTrackedOptimizationsTable(JSContext *cx, CompactBufferWriter &write } else { JSScript *script; uint32_t offset; - if (cx->findAllocationSiteForType(ty, &script, &offset)) { + if (ObjectGroup::findAllocationSiteForType(cx, ty, &script, &offset)) { if (!allTypes->append(IonTrackedTypeWithAddendum(ty, script, offset))) return false; SpewAllocationSite(ty, script, offset); diff --git a/js/src/jit/Recover.h b/js/src/jit/Recover.h index dd94f9701951..abaf68f54fc5 100644 --- a/js/src/jit/Recover.h +++ b/js/src/jit/Recover.h @@ -11,6 +11,7 @@ #include "jsarray.h" +#include "jit/MIR.h" #include "jit/Snapshots.h" struct JSContext; diff --git a/js/src/jit/ScalarReplacement.cpp b/js/src/jit/ScalarReplacement.cpp index 61bbfe36b384..6a82c13bc8ad 100644 --- a/js/src/jit/ScalarReplacement.cpp +++ b/js/src/jit/ScalarReplacement.cpp @@ -13,6 +13,7 @@ #include "jit/MIR.h" #include "jit/MIRGenerator.h" #include "jit/MIRGraph.h" +#include "vm/UnboxedObject.h" namespace js { namespace jit { diff --git a/js/src/jit/VMFunctions.cpp b/js/src/jit/VMFunctions.cpp index da87c369c33e..7f637041f910 100644 --- a/js/src/jit/VMFunctions.cpp +++ b/js/src/jit/VMFunctions.cpp @@ -1288,7 +1288,7 @@ MarkShapeFromIon(JSRuntime *rt, Shape **shapep) } void -MarkObjectGroupFromIon(JSRuntime *rt, types::ObjectGroup **groupp) +MarkObjectGroupFromIon(JSRuntime *rt, ObjectGroup **groupp) { gc::MarkObjectGroupUnbarriered(&rt->gc.marker, groupp, "write barrier"); } diff --git a/js/src/jit/VMFunctions.h b/js/src/jit/VMFunctions.h index 187846326de8..420a5765672e 100644 --- a/js/src/jit/VMFunctions.h +++ b/js/src/jit/VMFunctions.h @@ -345,7 +345,7 @@ template <> struct TypeToArgProperties { static const uint32_t result = TypeToArgProperties::result | VMFunction::ByRef; }; template <> struct TypeToArgProperties { - static const uint32_t result = TypeToArgProperties::result | VMFunction::ByRef; + static const uint32_t result = TypeToArgProperties::result | VMFunction::ByRef; }; // Convert argument type to whether or not it should be passed in a float @@ -759,7 +759,7 @@ void MarkValueFromIon(JSRuntime *rt, Value *vp); void MarkStringFromIon(JSRuntime *rt, JSString **stringp); void MarkObjectFromIon(JSRuntime *rt, JSObject **objp); void MarkShapeFromIon(JSRuntime *rt, Shape **shapep); -void MarkObjectGroupFromIon(JSRuntime *rt, types::ObjectGroup **groupp); +void MarkObjectGroupFromIon(JSRuntime *rt, ObjectGroup **groupp); // Helper for generatePreBarrier. inline void * diff --git a/js/src/jit/shared/CodeGenerator-x86-shared.cpp b/js/src/jit/shared/CodeGenerator-x86-shared.cpp index 52d4528fb8d5..c5a6f4b837cf 100644 --- a/js/src/jit/shared/CodeGenerator-x86-shared.cpp +++ b/js/src/jit/shared/CodeGenerator-x86-shared.cpp @@ -1991,7 +1991,7 @@ CodeGeneratorX86Shared::visitGuardClass(LGuardClass *guard) Register tmp = ToRegister(guard->tempInt()); masm.loadPtr(Address(obj, JSObject::offsetOfGroup()), tmp); - masm.cmpPtr(Operand(tmp, types::ObjectGroup::offsetOfClasp()), ImmPtr(guard->mir()->getClass())); + masm.cmpPtr(Operand(tmp, ObjectGroup::offsetOfClasp()), ImmPtr(guard->mir()->getClass())); bailoutIf(Assembler::NotEqual, guard->snapshot()); } diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp index 6c6e79655ebc..8f99d7f54130 100644 --- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -1247,7 +1247,7 @@ InitArrayElements(JSContext *cx, HandleObject obj, uint32_t start, uint32_t coun if (count == 0) return true; - types::ObjectGroup *group = obj->getGroup(cx); + ObjectGroup *group = obj->getGroup(cx); if (!group) return false; if (updateTypes && !InitArrayTypes(cx, group, vector, count)) @@ -2326,7 +2326,7 @@ TryReuseArrayGroup(JSObject *obj, ArrayObject *narr) * as obj. This can only be performed if the original object is an array * and has the same prototype. */ - MOZ_ASSERT(narr->getProto()->hasNewGroup(&ArrayObject::class_, narr->group())); + MOZ_ASSERT(ObjectGroup::hasDefaultNewGroup(narr->getProto(), &ArrayObject::class_, narr->group())); if (obj->is() && !obj->isSingleton() && obj->getProto() == narr->getProto()) narr->setGroup(obj->group()); @@ -2363,7 +2363,7 @@ CanOptimizeForDenseStorage(HandleObject arr, uint32_t startingIndex, uint32_t co * case can't happen, because any dense array used as the prototype of * another object is first slowified, for type inference's sake. */ - types::ObjectGroup *arrGroup = arr->getGroup(cx); + ObjectGroup *arrGroup = arr->getGroup(cx); if (MOZ_UNLIKELY(!arrGroup || arrGroup->hasAllFlags(OBJECT_FLAG_ITERATED))) return false; @@ -2982,7 +2982,7 @@ array_filter(JSContext *cx, unsigned argc, Value *vp) RootedObject arr(cx, NewDenseFullyAllocatedArray(cx, 0)); if (!arr) return false; - ObjectGroup *newGroup = GetCallerInitGroup(cx, JSProto_Array); + ObjectGroup *newGroup = ObjectGroup::callingAllocationSiteGroup(cx, JSProto_Array); if (!newGroup) return false; arr->setGroup(newGroup); @@ -3082,7 +3082,7 @@ array_of(JSContext *cx, unsigned argc, Value *vp) if (IsArrayConstructor(args.thisv()) || !IsConstructor(args.thisv())) { // IsArrayConstructor(this) will usually be true in practice. This is // the most common path. - RootedObjectGroup group(cx, GetCallerInitGroup(cx, JSProto_Array)); + RootedObjectGroup group(cx, ObjectGroup::callingAllocationSiteGroup(cx, JSProto_Array)); if (!group) return false; return ArrayFromCallArgs(cx, group, args); @@ -3189,7 +3189,7 @@ bool js_Array(JSContext *cx, unsigned argc, Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); - RootedObjectGroup group(cx, GetCallerInitGroup(cx, JSProto_Array)); + RootedObjectGroup group(cx, ObjectGroup::callingAllocationSiteGroup(cx, JSProto_Array)); if (!group) return false; @@ -3251,7 +3251,8 @@ CreateArrayPrototype(JSContext *cx, JSProtoKey key) if (!proto) return nullptr; - RootedObjectGroup group(cx, cx->getNewGroup(&ArrayObject::class_, TaggedProto(proto))); + RootedObjectGroup group(cx, ObjectGroup::defaultNewGroup(cx, &ArrayObject::class_, + TaggedProto(proto))); if (!group) return nullptr; @@ -3379,7 +3380,8 @@ NewArray(ExclusiveContext *cxArg, uint32_t length, if (!proto && !GetBuiltinPrototype(cxArg, JSProto_Array, &proto)) return nullptr; - RootedObjectGroup group(cxArg, cxArg->getNewGroup(&ArrayObject::class_, TaggedProto(proto))); + RootedObjectGroup group(cxArg, ObjectGroup::defaultNewGroup(cxArg, &ArrayObject::class_, + TaggedProto(proto))); if (!group) return nullptr; diff --git a/js/src/jscntxt.cpp b/js/src/jscntxt.cpp index 08ca0bde81a8..9e55b9481479 100644 --- a/js/src/jscntxt.cpp +++ b/js/src/jscntxt.cpp @@ -116,7 +116,7 @@ js::ExistingCloneFunctionAtCallsite(const CallsiteCloneTable &table, JSFunction { MOZ_ASSERT(fun->nonLazyScript()->shouldCloneAtCallsite()); MOZ_ASSERT(!fun->nonLazyScript()->enclosingStaticScope()); - MOZ_ASSERT(types::UseSingletonForClone(fun)); + MOZ_ASSERT(ObjectGroup::useSingletonForClone(fun)); /* * If we start allocating function objects in the nursery, then the callsite @@ -253,7 +253,7 @@ js::DestroyContext(JSContext *cx, DestroyContextMode mode) * This printing depends on atoms still existing. */ for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next()) - c->types.print(cx, false); + types::PrintTypes(cx, c, false); } if (mode == DCM_FORCE_GC) { MOZ_ASSERT(!rt->isHeapBusy()); diff --git a/js/src/jscntxt.h b/js/src/jscntxt.h index 46b9bc70c841..d155a09987c5 100644 --- a/js/src/jscntxt.h +++ b/js/src/jscntxt.h @@ -301,13 +301,6 @@ class ExclusiveContext : public ContextFriendFields, } // Zone local methods that can be used freely from an ExclusiveContext. - types::ObjectGroup *getNewGroup(const Class *clasp, TaggedProto proto, - JSObject *associated = nullptr); - types::ObjectGroup *getLazySingletonGroup(const Class *clasp, TaggedProto proto); - - // Returns false if not found. - bool findAllocationSiteForType(types::Type ty, JSScript **script, uint32_t *offset) const; - inline js::LifoAlloc &typeLifoAlloc(); // Current global. This is only safe to use within the scope of the diff --git a/js/src/jscompartment.cpp b/js/src/jscompartment.cpp index 892d6eebb5c9..40d5034edeb7 100644 --- a/js/src/jscompartment.cpp +++ b/js/src/jscompartment.cpp @@ -544,13 +544,6 @@ JSCompartment::sweepInnerViews() innerViews.sweep(runtimeFromAnyThread()); } -void -JSCompartment::sweepObjectGroupTables() -{ - sweepNewObjectGroupTable(newObjectGroups); - sweepNewObjectGroupTable(lazyObjectGroups); -} - void JSCompartment::sweepSavedStacks() { @@ -652,10 +645,9 @@ JSCompartment::sweepCrossCompartmentWrappers() void JSCompartment::fixupAfterMovingGC() { fixupGlobal(); - fixupNewObjectGroupTable(newObjectGroups); - fixupNewObjectGroupTable(lazyObjectGroups); fixupInitialShapeTable(); fixupBaseShapeTable(); + objectGroups.fixupTablesAfterMovingGC(); } void @@ -688,15 +680,11 @@ JSCompartment::clearTables() MOZ_ASSERT(enumerators->next() == enumerators); MOZ_ASSERT(regExps.empty()); - types.clearTables(); + objectGroups.clearTables(); if (baseShapes.initialized()) baseShapes.clear(); if (initialShapes.initialized()) initialShapes.clear(); - if (newObjectGroups.initialized()) - newObjectGroups.clear(); - if (lazyObjectGroups.initialized()) - lazyObjectGroups.clear(); if (savedStacks_.initialized()) savedStacks_.clear(); } @@ -816,12 +804,11 @@ JSCompartment::addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf, size_t *savedStacksSet) { *compartmentObject += mallocSizeOf(this); - types.addSizeOfExcludingThis(mallocSizeOf, tiAllocationSiteTables, - tiArrayTypeTables, tiObjectTypeTables); + objectGroups.addSizeOfExcludingThis(mallocSizeOf, tiAllocationSiteTables, + tiArrayTypeTables, tiObjectTypeTables, + compartmentTables); *compartmentTables += baseShapes.sizeOfExcludingThis(mallocSizeOf) - + initialShapes.sizeOfExcludingThis(mallocSizeOf) - + newObjectGroups.sizeOfExcludingThis(mallocSizeOf) - + lazyObjectGroups.sizeOfExcludingThis(mallocSizeOf); + + initialShapes.sizeOfExcludingThis(mallocSizeOf); *innerViewsArg += innerViews.sizeOfExcludingThis(mallocSizeOf); if (lazyArrayBuffers) *lazyArrayBuffersArg += lazyArrayBuffers->sizeOfIncludingThis(mallocSizeOf); diff --git a/js/src/jscompartment.h b/js/src/jscompartment.h index 76a9af73ad7b..4dc2dfeb5848 100644 --- a/js/src/jscompartment.h +++ b/js/src/jscompartment.h @@ -220,9 +220,6 @@ struct JSCompartment inline void initGlobal(js::GlobalObject &global); public: - /* Type information about the scripts and objects in this compartment. */ - js::types::TypeCompartment types; - void *data; private: @@ -276,14 +273,10 @@ struct JSCompartment js::InitialShapeSet initialShapes; void sweepInitialShapeTable(); - /* Set of default 'new' or lazy groups in the compartment. */ - js::types::NewObjectGroupTable newObjectGroups; - js::types::NewObjectGroupTable lazyObjectGroups; - void sweepNewObjectGroupTable(js::types::NewObjectGroupTable &table); + // Object group tables and other state in the compartment. + js::ObjectGroupCompartment objectGroups; #ifdef JSGC_HASH_TABLE_CHECKS - void checkObjectGroupTablesAfterMovingGC(); - void checkObjectGroupTableAfterMovingGC(js::types::NewObjectGroupTable &table); void checkInitialShapesTableAfterMovingGC(); void checkWrapperMapAfterMovingGC(); void checkBaseShapeTableAfterMovingGC(); @@ -386,7 +379,6 @@ struct JSCompartment void sweepInnerViews(); void sweepCrossCompartmentWrappers(); - void sweepObjectGroupTables(); void sweepSavedStacks(); void sweepGlobalObject(js::FreeOp *fop); void sweepSelfHostingScriptSource(); @@ -400,7 +392,6 @@ struct JSCompartment void clearTables(); void fixupInitialShapeTable(); - void fixupNewObjectGroupTable(js::types::NewObjectGroupTable &table); void fixupAfterMovingGC(); void fixupGlobal(); void fixupBaseShapeTable(); diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp index a07afaf6854c..909bebd67b20 100644 --- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -873,7 +873,7 @@ CreateFunctionPrototype(JSContext *cx, JSProtoKey key) return nullptr; functionProto->initScript(script); - types::ObjectGroup* protoGroup = functionProto->getGroup(cx); + ObjectGroup* protoGroup = functionProto->getGroup(cx); if (!protoGroup) return nullptr; @@ -2037,7 +2037,7 @@ js::CloneFunctionObjectUseSameScript(JSCompartment *compartment, HandleFunction { return compartment == fun->compartment() && !fun->isSingleton() && - !types::UseSingletonForClone(fun); + !ObjectGroup::useSingletonForClone(fun); } JSFunction * diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index aa7d001738b0..024e12c23f8f 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -286,7 +286,7 @@ const uint32_t Arena::ThingSizes[] = CHECK_MIN_THING_SIZE( sizeof(Shape), /* FINALIZE_SHAPE */ sizeof(AccessorShape), /* FINALIZE_ACCESSOR_SHAPE */ sizeof(BaseShape), /* FINALIZE_BASE_SHAPE */ - sizeof(types::ObjectGroup), /* FINALIZE_OBJECT_GROUP */ + sizeof(ObjectGroup), /* FINALIZE_OBJECT_GROUP */ sizeof(JSFatInlineString), /* FINALIZE_FAT_INLINE_STRING */ sizeof(JSString), /* FINALIZE_STRING */ sizeof(JSExternalString), /* FINALIZE_EXTERNAL_STRING */ @@ -317,7 +317,7 @@ const uint32_t Arena::FirstThingOffsets[] = { OFFSET(Shape), /* FINALIZE_SHAPE */ OFFSET(AccessorShape), /* FINALIZE_ACCESSOR_SHAPE */ OFFSET(BaseShape), /* FINALIZE_BASE_SHAPE */ - OFFSET(types::ObjectGroup), /* FINALIZE_OBJECT_GROUP */ + OFFSET(ObjectGroup), /* FINALIZE_OBJECT_GROUP */ OFFSET(JSFatInlineString), /* FINALIZE_FAT_INLINE_STRING */ OFFSET(JSString), /* FINALIZE_STRING */ OFFSET(JSExternalString), /* FINALIZE_EXTERNAL_STRING */ @@ -609,7 +609,7 @@ FinalizeArenas(FreeOp *fop, case FINALIZE_BASE_SHAPE: return FinalizeTypedArenas(fop, src, dest, thingKind, budget, keepArenas); case FINALIZE_OBJECT_GROUP: - return FinalizeTypedArenas(fop, src, dest, thingKind, budget, keepArenas); + return FinalizeTypedArenas(fop, src, dest, thingKind, budget, keepArenas); case FINALIZE_STRING: return FinalizeTypedArenas(fop, src, dest, thingKind, budget, keepArenas); case FINALIZE_FAT_INLINE_STRING: @@ -2226,7 +2226,7 @@ GCRuntime::sweepTypesAfterCompacting(Zone *zone) } for (ZoneCellIterUnderGC i(zone, FINALIZE_OBJECT_GROUP); !i.done(); i.next()) { - types::ObjectGroup *group = i.get(); + ObjectGroup *group = i.get(); group->maybeSweep(&oom); } @@ -2247,7 +2247,7 @@ GCRuntime::sweepZoneAfterCompacting(Zone *zone) c->sweepCrossCompartmentWrappers(); c->sweepBaseShapeTable(); c->sweepInitialShapeTable(); - c->sweepObjectGroupTables(); + c->objectGroups.sweep(fop); c->sweepRegExps(); c->sweepCallsiteClones(); c->sweepSavedStacks(); @@ -2311,7 +2311,7 @@ UpdateCellPointers(MovingTracer *trc, ArenaHeader *arena) UpdateCellPointersTyped(trc, arena, traceKind); return; case FINALIZE_OBJECT_GROUP: - UpdateCellPointersTyped(trc, arena, traceKind); + UpdateCellPointersTyped(trc, arena, traceKind); return; case FINALIZE_JITCODE: UpdateCellPointersTyped(trc, arena, traceKind); @@ -4872,7 +4872,7 @@ SweepInitialShapesTask::run() SweepObjectGroupsTask::run() { for (GCCompartmentGroupIter c(runtime); !c.done(); c.next()) - c->sweepObjectGroupTables(); + c->objectGroups.sweep(runtime->defaultFreeOp()); } /* virtual */ void @@ -5197,7 +5197,7 @@ SweepThing(JSScript *script, types::AutoClearTypeInferenceStateOnOOM *oom) } static void -SweepThing(types::ObjectGroup *group, types::AutoClearTypeInferenceStateOnOOM *oom) +SweepThing(ObjectGroup *group, types::AutoClearTypeInferenceStateOnOOM *oom) { group->maybeSweep(oom); } @@ -5250,7 +5250,7 @@ GCRuntime::sweepPhase(SliceBudget &sliceBudget) if (!SweepArenaList(&al.gcScriptArenasToUpdate, sliceBudget, &oom)) return NotFinished; - if (!SweepArenaList( + if (!SweepArenaList( &al.gcObjectGroupArenasToUpdate, sliceBudget, &oom)) { return NotFinished; @@ -6542,7 +6542,7 @@ gc::MergeCompartments(JSCompartment *source, JSCompartment *target) } for (ZoneCellIter iter(source->zone(), FINALIZE_OBJECT_GROUP); !iter.done(); iter.next()) { - types::ObjectGroup *group = iter.get(); + ObjectGroup *group = iter.get(); group->setGeneration(target->zone()->types.generation); } @@ -6967,7 +6967,7 @@ js::gc::CheckHashTablesAfterMovingGC(JSRuntime *rt) * that have been moved. */ for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next()) { - c->checkObjectGroupTablesAfterMovingGC(); + c->objectGroups.checkTablesAfterMovingGC(); c->checkInitialShapesTableAfterMovingGC(); c->checkWrapperMapAfterMovingGC(); c->checkBaseShapeTableAfterMovingGC(); @@ -7123,7 +7123,7 @@ JS::IncrementalReferenceBarrier(GCCellPtr thing) case JSTRACE_BASE_SHAPE: return BaseShape::writeBarrierPre(static_cast(thing.asCell())); case JSTRACE_OBJECT_GROUP: - return types::ObjectGroup::writeBarrierPre(static_cast(thing.asCell())); + return ObjectGroup::writeBarrierPre(static_cast(thing.asCell())); default: MOZ_CRASH("Invalid trace kind in IncrementalReferenceBarrier."); } diff --git a/js/src/jsgc.h b/js/src/jsgc.h index 575bcffebc93..2e40ad6f6fb1 100644 --- a/js/src/jsgc.h +++ b/js/src/jsgc.h @@ -68,7 +68,7 @@ template <> struct MapTypeToFinalizeKind { static const Alloc template <> struct MapTypeToFinalizeKind { static const AllocKind kind = FINALIZE_SHAPE; }; template <> struct MapTypeToFinalizeKind { static const AllocKind kind = FINALIZE_ACCESSOR_SHAPE; }; template <> struct MapTypeToFinalizeKind { static const AllocKind kind = FINALIZE_BASE_SHAPE; }; -template <> struct MapTypeToFinalizeKind { static const AllocKind kind = FINALIZE_OBJECT_GROUP; }; +template <> struct MapTypeToFinalizeKind { static const AllocKind kind = FINALIZE_OBJECT_GROUP; }; template <> struct MapTypeToFinalizeKind { static const AllocKind kind = FINALIZE_FAT_INLINE_STRING; }; template <> struct MapTypeToFinalizeKind { static const AllocKind kind = FINALIZE_STRING; }; template <> struct MapTypeToFinalizeKind { static const AllocKind kind = FINALIZE_EXTERNAL_STRING; }; diff --git a/js/src/jsgcinlines.h b/js/src/jsgcinlines.h index 7c200dd658eb..cbc37c41bd1f 100644 --- a/js/src/jsgcinlines.h +++ b/js/src/jsgcinlines.h @@ -614,10 +614,10 @@ NewJitCode(js::ExclusiveContext *cx) } inline -types::ObjectGroup * +ObjectGroup * NewObjectGroup(js::ExclusiveContext *cx) { - return gc::AllocateNonObject(cx); + return gc::AllocateNonObject(cx); } template diff --git a/js/src/jshashutil.h b/js/src/jshashutil.h index 3889c80c73e8..443b42809975 100644 --- a/js/src/jshashutil.h +++ b/js/src/jshashutil.h @@ -9,6 +9,8 @@ #include "jscntxt.h" +#include "gc/Zone.h" + namespace js { /* diff --git a/js/src/jsinfer.cpp b/js/src/jsinfer.cpp index bf61065b1956..7124c8227461 100644 --- a/js/src/jsinfer.cpp +++ b/js/src/jsinfer.cpp @@ -225,15 +225,6 @@ types::ObjectGroupString(ObjectGroup *group) return TypeString(Type::ObjectType(group)); } -unsigned JSScript::id() { - if (!id_) { - id_ = ++compartment()->types.scriptCount; - InferSpew(ISpewOps, "script #%u: %p %s:%d", - id_, this, filename() ? filename() : "", lineno()); - } - return id_; -} - void types::InferSpew(SpewChannel channel, const char *fmt, ...) { @@ -308,7 +299,7 @@ types::TypeFailure(JSContext *cx, const char *fmt, ...) JS_snprintf(msgbuf, sizeof(msgbuf), "[infer failure] %s", errbuf); /* Dump type state, even if INFERFLAGS is unset. */ - cx->compartment()->types.print(cx, true); + PrintTypes(cx, cx->compartment(), true); MOZ_ReportAssertionFailure(msgbuf, __FILE__, __LINE__); MOZ_CRASH(); @@ -2260,182 +2251,6 @@ TemporaryTypeSet::propertyNeedsBarrier(CompilerConstraintList *constraints, jsid return false; } -///////////////////////////////////////////////////////////////////// -// TypeCompartment -///////////////////////////////////////////////////////////////////// - -TypeCompartment::TypeCompartment() -{ - PodZero(this); -} - -ObjectGroup * -TypeCompartment::newObjectGroup(ExclusiveContext *cx, const Class *clasp, Handle proto, - ObjectGroupFlags initialFlags) -{ - MOZ_ASSERT_IF(proto.isObject(), cx->isInsideCurrentCompartment(proto.toObject())); - - if (cx->isJSContext()) { - if (proto.isObject() && IsInsideNursery(proto.toObject())) - initialFlags |= OBJECT_FLAG_NURSERY_PROTO; - } - - ObjectGroup *group = js::NewObjectGroup(cx); - if (!group) - return nullptr; - new(group) ObjectGroup(clasp, proto, initialFlags); - - return group; -} - -ObjectGroup * -TypeCompartment::addAllocationSiteObjectGroup(JSContext *cx, AllocationSiteKey key) -{ - AutoEnterAnalysis enter(cx); - - if (!allocationSiteTable) { - allocationSiteTable = cx->new_(); - if (!allocationSiteTable || !allocationSiteTable->init()) { - js_delete(allocationSiteTable); - allocationSiteTable = nullptr; - return nullptr; - } - } - - AllocationSiteTable::AddPtr p = allocationSiteTable->lookupForAdd(key); - MOZ_ASSERT(!p); - - ObjectGroup *res = nullptr; - - jsbytecode *pc = key.script->offsetToPC(key.offset); - RootedScript keyScript(cx, key.script); - - if (!res) { - RootedObject proto(cx); - if (key.kind != JSProto_Null && !GetBuiltinPrototype(cx, key.kind, &proto)) - return nullptr; - - Rooted tagged(cx, TaggedProto(proto)); - res = newObjectGroup(cx, GetClassForProtoKey(key.kind), tagged, OBJECT_FLAG_FROM_ALLOCATION_SITE); - if (!res) - return nullptr; - key.script = keyScript; - } - - if (JSOp(*pc) == JSOP_NEWOBJECT) { - /* - * This object is always constructed the same way and will not be - * observed by other code before all properties have been added. Mark - * all the properties as definite properties of the object. - */ - RootedObject baseobj(cx, key.script->getObject(GET_UINT32_INDEX(pc))); - - if (!res->addDefiniteProperties(cx, baseobj->lastProperty())) - return nullptr; - } - - if (!allocationSiteTable->add(p, key, res)) - return nullptr; - - return res; -} - -static inline jsid -GetAtomId(JSContext *cx, JSScript *script, const jsbytecode *pc, unsigned offset) -{ - PropertyName *name = script->getName(GET_UINT32_INDEX(pc + offset)); - return IdToTypeId(NameToId(name)); -} - -bool -types::UseSingletonForNewObject(JSContext *cx, JSScript *script, jsbytecode *pc) -{ - /* - * Make a heuristic guess at a use of JSOP_NEW that the constructed object - * should have a fresh group. We do this when the NEW is immediately - * followed by a simple assignment to an object's .prototype field. - * This is designed to catch common patterns for subclassing in JS: - * - * function Super() { ... } - * function Sub1() { ... } - * function Sub2() { ... } - * - * Sub1.prototype = new Super(); - * Sub2.prototype = new Super(); - * - * Using distinct groups for the particular prototypes of Sub1 and - * Sub2 lets us continue to distinguish the two subclasses and any extra - * properties added to those prototype objects. - */ - if (script->isGenerator()) - return false; - if (JSOp(*pc) != JSOP_NEW) - return false; - pc += JSOP_NEW_LENGTH; - if (JSOp(*pc) == JSOP_SETPROP) { - jsid id = GetAtomId(cx, script, pc, 0); - if (id == id_prototype(cx)) - return true; - } - - return false; -} - -NewObjectKind -types::UseSingletonForInitializer(JSScript *script, jsbytecode *pc, JSProtoKey key) -{ - // The return value of this method can either be tested like a boolean or - // passed to a NewObject method. - JS_STATIC_ASSERT(GenericObject == 0); - - /* - * Objects created outside loops in global and eval scripts should have - * singleton types. For now this is only done for plain objects and typed - * arrays, but not normal arrays. - */ - - if (script->functionNonDelazifying() && !script->treatAsRunOnce()) - return GenericObject; - - if (key != JSProto_Object && - !(key >= JSProto_Int8Array && key <= JSProto_Uint8ClampedArray) && - !(key >= JSProto_SharedInt8Array && key <= JSProto_SharedUint8ClampedArray)) - { - return GenericObject; - } - - /* - * All loops in the script will have a JSTRY_ITER or JSTRY_LOOP try note - * indicating their boundary. - */ - - if (!script->hasTrynotes()) - return SingletonObject; - - unsigned offset = script->pcToOffset(pc); - - JSTryNote *tn = script->trynotes()->vector; - JSTryNote *tnlimit = tn + script->trynotes()->length; - for (; tn < tnlimit; tn++) { - if (tn->kind != JSTRY_ITER && tn->kind != JSTRY_LOOP) - continue; - - unsigned startOffset = script->mainOffset() + tn->start; - unsigned endOffset = startOffset + tn->length; - - if (offset >= startOffset && offset < endOffset) - return GenericObject; - } - - return SingletonObject; -} - -NewObjectKind -types::UseSingletonForInitializer(JSScript *script, jsbytecode *pc, const Class *clasp) -{ - return UseSingletonForInitializer(script, pc, JSCLASS_CACHED_PROTO_KEY(clasp)); -} - static inline bool ClassCanHaveExtraProperties(const Class *clasp) { @@ -2485,7 +2300,7 @@ types::TypeCanHaveExtraIndexedProperties(CompilerConstraintList *constraints, if (!clasp || (ClassCanHaveExtraProperties(clasp) && !IsAnyTypedArrayClass(clasp))) return true; - if (types->hasObjectFlags(constraints, types::OBJECT_FLAG_SPARSE_INDEXES)) + if (types->hasObjectFlags(constraints, OBJECT_FLAG_SPARSE_INDEXES)) return true; JSObject *proto = types->getCommonPrototype(constraints); @@ -2554,13 +2369,13 @@ TypeZone::addPendingRecompile(JSContext *cx, JSScript *script) } void -TypeCompartment::print(JSContext *cx, bool force) +types::PrintTypes(JSContext *cx, JSCompartment *comp, bool force) { #ifdef DEBUG gc::AutoSuppressGC suppressGC(cx); JSAutoRequest request(cx); - Zone *zone = compartment()->zone(); + Zone *zone = comp->zone(); AutoEnterAnalysis enter(nullptr, zone); if (!force && !InferSpewActive(ISpewResult)) @@ -2579,397 +2394,10 @@ TypeCompartment::print(JSContext *cx, bool force) #endif } -///////////////////////////////////////////////////////////////////// -// TypeCompartment tables -///////////////////////////////////////////////////////////////////// - -/* - * The arrayTypeTable and objectTypeTable are per-compartment tables for making - * common groups to model the contents of large script singletons and JSON - * objects. These are vanilla Arrays and native Objects, so we distinguish the - * types of different ones by looking at the types of their properties. - * - * All singleton/JSON arrays which have the same prototype, are homogenous and - * of the same element type will share a group. All singleton/JSON objects - * which have the same shape and property types will also share a group. - * We don't try to collate arrays or objects that have type mismatches. - */ - -static inline bool -NumberTypes(Type a, Type b) -{ - return (a.isPrimitive(JSVAL_TYPE_INT32) || a.isPrimitive(JSVAL_TYPE_DOUBLE)) - && (b.isPrimitive(JSVAL_TYPE_INT32) || b.isPrimitive(JSVAL_TYPE_DOUBLE)); -} - -/* - * As for GetValueType, but requires object types to be non-singletons with - * their default prototype. These are the only values that should appear in - * arrays and objects whose type can be fixed. - */ -static inline Type -GetValueTypeForTable(const Value &v) -{ - Type type = GetValueType(v); - MOZ_ASSERT(!type.isSingleton()); - return type; -} - -struct types::ArrayTableKey : public DefaultHasher -{ - Type type; - JSObject *proto; - - ArrayTableKey() - : type(Type::UndefinedType()), proto(nullptr) - {} - - ArrayTableKey(Type type, JSObject *proto) - : type(type), proto(proto) - {} - - static inline uint32_t hash(const ArrayTableKey &v) { - return (uint32_t) (v.type.raw() ^ ((uint32_t)(size_t)v.proto >> 2)); - } - - static inline bool match(const ArrayTableKey &v1, const ArrayTableKey &v2) { - return v1.type == v2.type && v1.proto == v2.proto; - } - - bool operator==(const ArrayTableKey& other) { - return type == other.type && proto == other.proto; - } - - bool operator!=(const ArrayTableKey& other) { - return !(*this == other); - } -}; - -void -TypeCompartment::setTypeToHomogenousArray(ExclusiveContext *cx, - JSObject *obj, Type elementType) -{ - MOZ_ASSERT(cx->zone()->types.activeAnalysis); - - if (!arrayTypeTable) { - arrayTypeTable = cx->new_(); - if (!arrayTypeTable || !arrayTypeTable->init()) { - arrayTypeTable = nullptr; - return; - } - } - - ArrayTableKey key(elementType, obj->getProto()); - DependentAddPtr p(cx, *arrayTypeTable, key); - if (p) { - obj->setGroup(p->value()); - } else { - /* Make a new type to use for future arrays with the same elements. */ - RootedObject objProto(cx, obj->getProto()); - Rooted taggedProto(cx, TaggedProto(objProto)); - ObjectGroup *group = newObjectGroup(cx, &ArrayObject::class_, taggedProto); - if (!group) - return; - obj->setGroup(group); - - AddTypePropertyId(cx, group, JSID_VOID, elementType); - - key.proto = objProto; - (void) p.add(cx, *arrayTypeTable, key, group); - } -} - -void -TypeCompartment::fixArrayGroup(ExclusiveContext *cx, ArrayObject *obj) -{ - AutoEnterAnalysis enter(cx); - - /* - * If the array is of homogenous type, pick a group which will be - * shared with all other singleton/JSON arrays of the same type. - * If the array is heterogenous, keep the existing group, which has - * unknown properties. - */ - - unsigned len = obj->getDenseInitializedLength(); - if (len == 0) - return; - - Type type = GetValueTypeForTable(obj->getDenseElement(0)); - - for (unsigned i = 1; i < len; i++) { - Type ntype = GetValueTypeForTable(obj->getDenseElement(i)); - if (ntype != type) { - if (NumberTypes(type, ntype)) - type = Type::DoubleType(); - else - return; - } - } - - setTypeToHomogenousArray(cx, obj, type); -} - -void -types::FixRestArgumentsType(ExclusiveContext *cx, ArrayObject *obj) -{ - cx->compartment()->types.fixRestArgumentsType(cx, obj); -} - -void -TypeCompartment::fixRestArgumentsType(ExclusiveContext *cx, ArrayObject *obj) -{ - AutoEnterAnalysis enter(cx); - - /* - * Tracking element types for rest argument arrays is not worth it, but we - * still want it to be known that it's a dense array. - */ - setTypeToHomogenousArray(cx, obj, Type::UnknownType()); -} - -/* - * N.B. We could also use the initial shape of the object (before its type is - * fixed) as the key in the object table, but since all references in the table - * are weak the hash entries would usually be collected on GC even if objects - * with the new type/shape are still live. - */ -struct types::ObjectTableKey -{ - jsid *properties; - uint32_t nproperties; - uint32_t nfixed; - - struct Lookup { - IdValuePair *properties; - uint32_t nproperties; - uint32_t nfixed; - - Lookup(IdValuePair *properties, uint32_t nproperties, uint32_t nfixed) - : properties(properties), nproperties(nproperties), nfixed(nfixed) - {} - }; - - static inline HashNumber hash(const Lookup &lookup) { - return (HashNumber) (JSID_BITS(lookup.properties[lookup.nproperties - 1].id) ^ - lookup.nproperties ^ - lookup.nfixed); - } - - static inline bool match(const ObjectTableKey &v, const Lookup &lookup) { - if (lookup.nproperties != v.nproperties || lookup.nfixed != v.nfixed) - return false; - for (size_t i = 0; i < lookup.nproperties; i++) { - if (lookup.properties[i].id != v.properties[i]) - return false; - } - return true; - } -}; - -struct types::ObjectTableEntry -{ - ReadBarrieredObjectGroup group; - ReadBarrieredShape shape; - Type *types; -}; - -static inline void -UpdateObjectTableEntryTypes(ExclusiveContext *cx, ObjectTableEntry &entry, - IdValuePair *properties, size_t nproperties) -{ - if (entry.group->unknownProperties()) - return; - for (size_t i = 0; i < nproperties; i++) { - Type type = entry.types[i]; - Type ntype = GetValueTypeForTable(properties[i].value); - if (ntype == type) - continue; - if (ntype.isPrimitive(JSVAL_TYPE_INT32) && - type.isPrimitive(JSVAL_TYPE_DOUBLE)) - { - /* The property types already reflect 'int32'. */ - } else { - if (ntype.isPrimitive(JSVAL_TYPE_DOUBLE) && - type.isPrimitive(JSVAL_TYPE_INT32)) - { - /* Include 'double' in the property types to avoid the update below later. */ - entry.types[i] = Type::DoubleType(); - } - AddTypePropertyId(cx, entry.group, IdToTypeId(properties[i].id), ntype); - } - } -} - -void -TypeCompartment::fixObjectGroup(ExclusiveContext *cx, PlainObject *obj) -{ - AutoEnterAnalysis enter(cx); - - if (!objectTypeTable) { - objectTypeTable = cx->new_(); - if (!objectTypeTable || !objectTypeTable->init()) { - js_delete(objectTypeTable); - objectTypeTable = nullptr; - return; - } - } - - /* - * Use the same group for all singleton/JSON objects with the same - * base shape, i.e. the same fields written in the same order. - * - * Exclude some objects we can't readily associate common types for based on their - * shape. Objects with metadata are excluded so that the metadata does not need to - * be included in the table lookup (the metadata object might be in the nursery). - */ - if (obj->slotSpan() == 0 || obj->inDictionaryMode() || !obj->hasEmptyElements() || obj->getMetadata()) - return; - - Vector properties(cx); - if (!properties.resize(obj->slotSpan())) - return; - - Shape *shape = obj->lastProperty(); - while (!shape->isEmptyShape()) { - IdValuePair &entry = properties[shape->slot()]; - entry.id = shape->propid(); - entry.value = obj->getSlot(shape->slot()); - shape = shape->previous(); - } - - ObjectTableKey::Lookup lookup(properties.begin(), properties.length(), obj->numFixedSlots()); - ObjectTypeTable::AddPtr p = objectTypeTable->lookupForAdd(lookup); - - if (p) { - MOZ_ASSERT(obj->getProto() == p->value().group->proto().toObject()); - MOZ_ASSERT(obj->lastProperty() == p->value().shape); - - UpdateObjectTableEntryTypes(cx, p->value(), properties.begin(), properties.length()); - obj->setGroup(p->value().group); - return; - } - - /* Make a new type to use for the object and similar future ones. */ - Rooted objProto(cx, obj->getTaggedProto()); - ObjectGroup *group = newObjectGroup(cx, &PlainObject::class_, objProto); - if (!group || !group->addDefiniteProperties(cx, obj->lastProperty())) - return; - - if (obj->isIndexed()) - group->setFlags(cx, OBJECT_FLAG_SPARSE_INDEXES); - - ScopedJSFreePtr ids(group->zone()->pod_calloc(properties.length())); - if (!ids) - return; - - ScopedJSFreePtr types(group->zone()->pod_calloc(properties.length())); - if (!types) - return; - - for (size_t i = 0; i < properties.length(); i++) { - ids[i] = properties[i].id; - types[i] = GetValueTypeForTable(obj->getSlot(i)); - AddTypePropertyId(cx, group, IdToTypeId(ids[i]), types[i]); - } - - ObjectTableKey key; - key.properties = ids; - key.nproperties = properties.length(); - key.nfixed = obj->numFixedSlots(); - MOZ_ASSERT(ObjectTableKey::match(key, lookup)); - - ObjectTableEntry entry; - entry.group.set(group); - entry.shape.set(obj->lastProperty()); - entry.types = types; - - obj->setGroup(group); - - p = objectTypeTable->lookupForAdd(lookup); - if (objectTypeTable->add(p, key, entry)) { - ids.forget(); - types.forget(); - } -} - -JSObject * -TypeCompartment::newTypedObject(JSContext *cx, IdValuePair *properties, size_t nproperties) -{ - AutoEnterAnalysis enter(cx); - - if (!objectTypeTable) { - objectTypeTable = cx->new_(); - if (!objectTypeTable || !objectTypeTable->init()) { - js_delete(objectTypeTable); - objectTypeTable = nullptr; - return nullptr; - } - } - - /* - * Use the object group table to allocate an object with the specified - * properties, filling in its final type and shape and failing if no cache - * entry could be found for the properties. - */ - - /* - * Filter out a few cases where we don't want to use the object group table. - * Note that if the properties contain any duplicates or dense indexes, - * the lookup below will fail as such arrays of properties cannot be stored - * in the object group table --- fixObjectGroup populates the table with - * properties read off its input object, which cannot be duplicates, and - * ignores objects with dense indexes. - */ - if (!nproperties || nproperties >= PropertyTree::MAX_HEIGHT) - return nullptr; - - gc::AllocKind allocKind = gc::GetGCObjectKind(nproperties); - size_t nfixed = gc::GetGCKindSlots(allocKind, &PlainObject::class_); - - ObjectTableKey::Lookup lookup(properties, nproperties, nfixed); - ObjectTypeTable::AddPtr p = objectTypeTable->lookupForAdd(lookup); - - if (!p) - return nullptr; - - RootedPlainObject obj(cx, NewBuiltinClassInstance(cx, allocKind)); - if (!obj) { - cx->clearPendingException(); - return nullptr; - } - MOZ_ASSERT(obj->getProto() == p->value().group->proto().toObject()); - - RootedShape shape(cx, p->value().shape); - if (!NativeObject::setLastProperty(cx, obj, shape)) { - cx->clearPendingException(); - return nullptr; - } - - UpdateObjectTableEntryTypes(cx, p->value(), properties, nproperties); - - for (size_t i = 0; i < nproperties; i++) - obj->setSlot(i, properties[i].value); - - obj->setGroup(p->value().group); - return obj; -} - ///////////////////////////////////////////////////////////////////// // ObjectGroup ///////////////////////////////////////////////////////////////////// -void -ObjectGroup::setProto(JSContext *cx, TaggedProto proto) -{ - MOZ_ASSERT(singleton()); - - if (proto.isObject() && IsInsideNursery(proto.toObject())) - addFlags(OBJECT_FLAG_NURSERY_PROTO); - - setProtoUnchecked(proto); -} - static inline void UpdatePropertyType(ExclusiveContext *cx, HeapTypeSet *types, NativeObject *obj, Shape *shape, bool indexed) @@ -3311,12 +2739,8 @@ ObjectGroup::detachNewScript(bool writeBarrier) MOZ_ASSERT(newScript); if (newScript->analyzed()) { - NewObjectGroupTable &newObjectGroups = newScript->function()->compartment()->newObjectGroups; - NewObjectGroupTable::Ptr p = - newObjectGroups.lookup(NewObjectGroupTable::Lookup(nullptr, proto(), newScript->function())); - MOZ_ASSERT(p->group == this); - - newObjectGroups.remove(p); + newScript->function()->compartment()->objectGroups.removeDefaultNewGroup(nullptr, proto(), + newScript->function()); } if (this->newScript()) @@ -3636,50 +3060,6 @@ types::FillBytecodeTypeMap(JSScript *script, uint32_t *bytecodeMap) MOZ_ASSERT(added == script->nTypeSets()); } -ArrayObject * -types::GetOrFixupCopyOnWriteObject(JSContext *cx, HandleScript script, jsbytecode *pc) -{ - // Make sure that the template object for script/pc has a type indicating - // that the object and its copies have copy on write elements. - RootedArrayObject obj(cx, &script->getObject(GET_UINT32_INDEX(pc))->as()); - MOZ_ASSERT(obj->denseElementsAreCopyOnWrite()); - - if (obj->group()->fromAllocationSite()) { - MOZ_ASSERT(obj->group()->hasAnyFlags(OBJECT_FLAG_COPY_ON_WRITE)); - return obj; - } - - RootedObjectGroup group(cx, TypeScript::InitGroup(cx, script, pc, JSProto_Array)); - if (!group) - return nullptr; - - group->addFlags(OBJECT_FLAG_COPY_ON_WRITE); - - // Update type information in the initializer object group. - MOZ_ASSERT(obj->slotSpan() == 0); - for (size_t i = 0; i < obj->getDenseInitializedLength(); i++) { - const Value &v = obj->getDenseElement(i); - AddTypePropertyId(cx, group, JSID_VOID, v); - } - - obj->setGroup(group); - return obj; -} - -ArrayObject * -types::GetCopyOnWriteObject(JSScript *script, jsbytecode *pc) -{ - // GetOrFixupCopyOnWriteObject should already have been called for - // script/pc, ensuring that the template object has a group with the - // COPY_ON_WRITE flag. We don't assert this here, due to a corner case - // where this property doesn't hold. See jsop_newarray_copyonwrite in - // IonBuilder. - ArrayObject *obj = &script->getObject(GET_UINT32_INDEX(pc))->as(); - MOZ_ASSERT(obj->denseElementsAreCopyOnWrite()); - - return obj; -} - void types::TypeMonitorResult(JSContext *cx, JSScript *script, jsbytecode *pc, const js::Value &rval) { @@ -3697,66 +3077,11 @@ types::TypeMonitorResult(JSContext *cx, JSScript *script, jsbytecode *pc, const if (types->hasType(type)) return; - InferSpew(ISpewOps, "bytecodeType: #%u:%05u: %s", - script->id(), script->pcToOffset(pc), TypeString(type)); + InferSpew(ISpewOps, "bytecodeType: %p %05u: %s", + script, script->pcToOffset(pc), TypeString(type)); types->addType(cx, type); } -bool -types::UseSingletonForClone(JSFunction *fun) -{ - if (!fun->isInterpreted()) - return false; - - if (fun->hasScript() && fun->nonLazyScript()->shouldCloneAtCallsite()) - return true; - - if (fun->isArrow()) - return false; - - if (fun->isSingleton()) - return false; - - /* - * When a function is being used as a wrapper for another function, it - * improves precision greatly to distinguish between different instances of - * the wrapper; otherwise we will conflate much of the information about - * the wrapped functions. - * - * An important example is the Class.create function at the core of the - * Prototype.js library, which looks like: - * - * var Class = { - * create: function() { - * return function() { - * this.initialize.apply(this, arguments); - * } - * } - * }; - * - * Each instance of the innermost function will have a different wrapped - * initialize method. We capture this, along with similar cases, by looking - * for short scripts which use both .apply and arguments. For such scripts, - * whenever creating a new instance of the function we both give that - * instance a singleton type and clone the underlying script. - */ - - uint32_t begin, end; - if (fun->hasScript()) { - if (!fun->nonLazyScript()->usesArgumentsApplyAndThis()) - return false; - begin = fun->nonLazyScript()->sourceStart(); - end = fun->nonLazyScript()->sourceEnd(); - } else { - if (!fun->lazyScript()->usesArgumentsApplyAndThis()) - return false; - begin = fun->lazyScript()->begin(); - end = fun->lazyScript()->end(); - } - - return end - begin <= 100; -} - ///////////////////////////////////////////////////////////////////// // TypeScript ///////////////////////////////////////////////////////////////////// @@ -3781,20 +3106,20 @@ JSScript::makeTypes(JSContext *cx) #ifdef DEBUG StackTypeSet *typeArray = typeScript->typeArray(); for (unsigned i = 0; i < nTypeSets(); i++) { - InferSpew(ISpewOps, "typeSet: %sT%p%s bytecode%u #%u", + InferSpew(ISpewOps, "typeSet: %sT%p%s bytecode%u %p", InferSpewColor(&typeArray[i]), &typeArray[i], InferSpewColorReset(), - i, id()); + i, this); } TypeSet *thisTypes = TypeScript::ThisTypes(this); - InferSpew(ISpewOps, "typeSet: %sT%p%s this #%u", + InferSpew(ISpewOps, "typeSet: %sT%p%s this %p", InferSpewColor(thisTypes), thisTypes, InferSpewColorReset(), - id()); + this); unsigned nargs = functionNonDelazifying() ? functionNonDelazifying()->nargs() : 0; for (unsigned i = 0; i < nargs; i++) { TypeSet *types = TypeScript::ArgTypes(this, i); - InferSpew(ISpewOps, "typeSet: %sT%p%s arg%u #%u", + InferSpew(ISpewOps, "typeSet: %sT%p%s arg%u %p", InferSpewColor(types), types, InferSpewColorReset(), - i, id()); + i, this); } #endif @@ -3811,8 +3136,8 @@ JSFunction::setTypeForScriptedFunction(ExclusiveContext *cx, HandleFunction fun, } else { RootedObject funProto(cx, fun->getProto()); Rooted taggedProto(cx, TaggedProto(funProto)); - ObjectGroup *group = - cx->compartment()->types.newObjectGroup(cx, &JSFunction::class_, taggedProto); + ObjectGroup *group = ObjectGroupCompartment::makeGroup(cx, &JSFunction::class_, + taggedProto); if (!group) return false; @@ -4212,8 +3537,8 @@ TypeNewScript::maybeAnalyze(JSContext *cx, ObjectGroup *group, bool *regenerate, ObjectGroupFlags initialFlags = group->flags() & OBJECT_FLAG_DYNAMIC_MASK; Rooted protoRoot(cx, group->proto()); - ObjectGroup *initialGroup = - cx->compartment()->types.newObjectGroup(cx, group->clasp(), protoRoot, initialFlags); + ObjectGroup *initialGroup = ObjectGroupCompartment::makeGroup(cx, group->clasp(), protoRoot, + initialFlags); if (!initialGroup) return false; @@ -4222,12 +3547,8 @@ TypeNewScript::maybeAnalyze(JSContext *cx, ObjectGroup *group, bool *regenerate, if (!group->addDefiniteProperties(cx, prefixShape)) return false; - NewObjectGroupTable &table = cx->compartment()->newObjectGroups; - NewObjectGroupTable::Lookup lookup(nullptr, group->proto(), function()); - - MOZ_ASSERT(table.lookup(lookup)->group == group); - table.remove(lookup); - table.putNew(lookup, NewObjectGroupEntry(initialGroup, function())); + cx->compartment()->objectGroups.replaceDefaultNewGroup(nullptr, group->proto(), function(), + initialGroup); templateObject()->setGroup(initialGroup); @@ -4367,381 +3688,6 @@ TypeNewScript::sweep() preliminaryObjects->sweep(); } -///////////////////////////////////////////////////////////////////// -// JSObject -///////////////////////////////////////////////////////////////////// - -bool -JSObject::shouldSplicePrototype(JSContext *cx) -{ - /* - * During bootstrapping, if inference is enabled we need to make sure not - * to splice a new prototype in for Function.prototype or the global - * object if their __proto__ had previously been set to null, as this - * will change the prototype for all other objects with the same type. - */ - if (getProto() != nullptr) - return false; - return isSingleton(); -} - -bool -JSObject::splicePrototype(JSContext *cx, const Class *clasp, Handle proto) -{ - MOZ_ASSERT(cx->compartment() == compartment()); - - RootedObject self(cx, this); - - /* - * For singleton groups representing only a single JSObject, the proto - * can be rearranged as needed without destroying type information for - * the old or new types. - */ - MOZ_ASSERT(self->isSingleton()); - - // Inner objects may not appear on prototype chains. - MOZ_ASSERT_IF(proto.isObject(), !proto.toObject()->getClass()->ext.outerObject); - - if (proto.isObject() && !proto.toObject()->setDelegate(cx)) - return false; - - // Force type instantiation when splicing lazy group. - RootedObjectGroup group(cx, self->getGroup(cx)); - if (!group) - return false; - RootedObjectGroup protoGroup(cx, nullptr); - if (proto.isObject()) { - protoGroup = proto.toObject()->getGroup(cx); - if (!protoGroup) - return false; - } - - group->setClasp(clasp); - group->setProto(cx, proto); - return true; -} - -/* static */ ObjectGroup * -JSObject::makeLazyGroup(JSContext *cx, HandleObject obj) -{ - MOZ_ASSERT(obj->hasLazyGroup()); - MOZ_ASSERT(cx->compartment() == obj->compartment()); - - /* De-lazification of functions can GC, so we need to do it up here. */ - if (obj->is() && obj->as().isInterpretedLazy()) { - RootedFunction fun(cx, &obj->as()); - if (!fun->getOrCreateScript(cx)) - return nullptr; - } - - // Find flags which need to be specified immediately on the object. - // Don't track whether singletons are packed. - ObjectGroupFlags initialFlags = OBJECT_FLAG_NON_PACKED; - - if (obj->lastProperty()->hasObjectFlag(BaseShape::ITERATED_SINGLETON)) - initialFlags |= OBJECT_FLAG_ITERATED; - - if (obj->isIndexed()) - initialFlags |= OBJECT_FLAG_SPARSE_INDEXES; - - if (obj->is() && obj->as().length() > INT32_MAX) - initialFlags |= OBJECT_FLAG_LENGTH_OVERFLOW; - - Rooted proto(cx, obj->getTaggedProto()); - ObjectGroup *group = cx->compartment()->types.newObjectGroup(cx, obj->getClass(), proto, - initialFlags); - if (!group) - return nullptr; - - AutoEnterAnalysis enter(cx); - - /* Fill in the type according to the state of this object. */ - - group->initSingleton(obj); - - if (obj->is() && obj->as().isInterpreted()) - group->setInterpretedFunction(&obj->as()); - - obj->group_ = group; - - return group; -} - -/* static */ inline HashNumber -NewObjectGroupEntry::hash(const Lookup &lookup) -{ - return PointerHasher::hash(lookup.hashProto.raw()) ^ - PointerHasher::hash(lookup.clasp) ^ - PointerHasher::hash(lookup.associated); -} - -/* static */ inline bool -NewObjectGroupEntry::match(const NewObjectGroupEntry &key, const Lookup &lookup) -{ - return key.group->proto() == lookup.matchProto && - (!lookup.clasp || key.group->clasp() == lookup.clasp) && - key.associated == lookup.associated; -} - -#ifdef DEBUG -bool -JSObject::hasNewGroup(const Class *clasp, ObjectGroup *group) -{ - NewObjectGroupTable &table = compartment()->newObjectGroups; - - if (!table.initialized()) - return false; - - NewObjectGroupTable::Ptr p = - table.lookup(NewObjectGroupTable::Lookup(clasp, TaggedProto(this), nullptr)); - return p && p->group == group; -} -#endif /* DEBUG */ - -/* static */ bool -JSObject::setNewGroupUnknown(JSContext *cx, const Class *clasp, HandleObject obj) -{ - if (!obj->setFlag(cx, js::BaseShape::NEW_GROUP_UNKNOWN)) - return false; - - // If the object already has a new group, mark that group as unknown. - NewObjectGroupTable &table = cx->compartment()->newObjectGroups; - if (table.initialized()) { - Rooted taggedProto(cx, TaggedProto(obj)); - NewObjectGroupTable::Ptr p = - table.lookup(NewObjectGroupTable::Lookup(clasp, taggedProto, nullptr)); - if (p) - MarkObjectGroupUnknownProperties(cx, p->group); - } - - return true; -} - -/* - * This class is used to add a post barrier on the newObjectGroups set, as the - * key is calculated from a prototype object which may be moved by generational - * GC. - */ -class NewObjectGroupsSetRef : public BufferableRef -{ - NewObjectGroupTable *set; - const Class *clasp; - JSObject *proto; - JSObject *associated; - - public: - NewObjectGroupsSetRef(NewObjectGroupTable *s, const Class *clasp, JSObject *proto, JSObject *associated) - : set(s), clasp(clasp), proto(proto), associated(associated) - {} - - void mark(JSTracer *trc) { - JSObject *prior = proto; - trc->setTracingLocation(&*prior); - Mark(trc, &proto, "newObjectGroups set prototype"); - if (prior == proto) - return; - - NewObjectGroupTable::Ptr p = - set->lookup(NewObjectGroupTable::Lookup(clasp, TaggedProto(prior), TaggedProto(proto), - associated)); - if (!p) - return; - - set->rekeyAs(NewObjectGroupTable::Lookup(clasp, TaggedProto(prior), TaggedProto(proto), associated), - NewObjectGroupTable::Lookup(clasp, TaggedProto(proto), associated), *p); - } -}; - -static void -ObjectGroupTablePostBarrier(ExclusiveContext *cx, NewObjectGroupTable *table, - const Class *clasp, TaggedProto proto, JSObject *associated) -{ - MOZ_ASSERT_IF(associated, !IsInsideNursery(associated)); - - if (!proto.isObject()) - return; - - if (!cx->isJSContext()) { - MOZ_ASSERT(!IsInsideNursery(proto.toObject())); - return; - } - - if (IsInsideNursery(proto.toObject())) { - StoreBuffer &sb = cx->asJSContext()->runtime()->gc.storeBuffer; - sb.putGeneric(NewObjectGroupsSetRef(table, clasp, proto.toObject(), associated)); - } -} - -ObjectGroup * -ExclusiveContext::getNewGroup(const Class *clasp, TaggedProto proto, JSObject *associated) -{ - MOZ_ASSERT_IF(associated, proto.isObject()); - MOZ_ASSERT_IF(associated, associated->is() || associated->is()); - MOZ_ASSERT_IF(proto.isObject(), isInsideCurrentCompartment(proto.toObject())); - - // A null lookup clasp is used for 'new' groups with an associated - // function. The group starts out as a plain object but might mutate into an - // unboxed plain object. - MOZ_ASSERT(!clasp == (associated && associated->is())); - - NewObjectGroupTable &newObjectGroups = compartment()->newObjectGroups; - - if (!newObjectGroups.initialized() && !newObjectGroups.init()) - return nullptr; - - if (associated && associated->is()) { - MOZ_ASSERT(!clasp); - - // Canonicalize new functions to use the original one associated with its script. - JSFunction *fun = &associated->as(); - if (fun->hasScript()) - associated = fun->nonLazyScript()->functionNonDelazifying(); - else if (fun->isInterpretedLazy() && !fun->isSelfHostedBuiltin()) - associated = fun->lazyScript()->functionNonDelazifying(); - else - associated = nullptr; - - // If we have previously cleared the 'new' script information for this - // function, don't try to construct another one. - if (associated && associated->wasNewScriptCleared()) - associated = nullptr; - - if (!associated) - clasp = &PlainObject::class_; - } - - NewObjectGroupTable::AddPtr p = - newObjectGroups.lookupForAdd(NewObjectGroupTable::Lookup(clasp, proto, associated)); - if (p) { - ObjectGroup *group = p->group; - MOZ_ASSERT_IF(clasp, group->clasp() == clasp); - MOZ_ASSERT_IF(!clasp, group->clasp() == &PlainObject::class_ || - group->clasp() == &UnboxedPlainObject::class_); - MOZ_ASSERT(group->proto() == proto); - return group; - } - - AutoEnterAnalysis enter(this); - - if (proto.isObject() && !proto.toObject()->setDelegate(this)) - return nullptr; - - ObjectGroupFlags initialFlags = 0; - if (!proto.isObject() || proto.toObject()->isNewGroupUnknown()) - initialFlags = OBJECT_FLAG_DYNAMIC_MASK; - - Rooted protoRoot(this, proto); - ObjectGroup *group = compartment()->types.newObjectGroup(this, - clasp ? clasp : &PlainObject::class_, - protoRoot, initialFlags); - if (!group) - return nullptr; - - if (!newObjectGroups.add(p, NewObjectGroupEntry(group, associated))) - return nullptr; - - ObjectGroupTablePostBarrier(this, &newObjectGroups, clasp, proto, associated); - - if (proto.isObject()) { - RootedObject obj(this, proto.toObject()); - - if (associated) { - if (associated->is()) - TypeNewScript::make(asJSContext(), group, &associated->as()); - else - group->setTypeDescr(&associated->as()); - } - - /* - * Some builtin objects have slotful native properties baked in at - * creation via the Shape::{insert,get}initialShape mechanism. Since - * these properties are never explicitly defined on new objects, update - * the type information for them here. - */ - - if (obj->is()) { - AddTypePropertyId(this, group, NameToId(names().source), Type::StringType()); - AddTypePropertyId(this, group, NameToId(names().global), Type::BooleanType()); - AddTypePropertyId(this, group, NameToId(names().ignoreCase), Type::BooleanType()); - AddTypePropertyId(this, group, NameToId(names().multiline), Type::BooleanType()); - AddTypePropertyId(this, group, NameToId(names().sticky), Type::BooleanType()); - AddTypePropertyId(this, group, NameToId(names().lastIndex), Type::Int32Type()); - } - - if (obj->is()) - AddTypePropertyId(this, group, NameToId(names().length), Type::Int32Type()); - - if (obj->is()) { - AddTypePropertyId(this, group, NameToId(names().fileName), Type::StringType()); - AddTypePropertyId(this, group, NameToId(names().lineNumber), Type::Int32Type()); - AddTypePropertyId(this, group, NameToId(names().columnNumber), Type::Int32Type()); - AddTypePropertyId(this, group, NameToId(names().stack), Type::StringType()); - } - } - - return group; -} - -ObjectGroup * -ExclusiveContext::getLazySingletonGroup(const Class *clasp, TaggedProto proto) -{ - MOZ_ASSERT_IF(proto.isObject(), compartment() == proto.toObject()->compartment()); - - AutoEnterAnalysis enter(this); - - NewObjectGroupTable &table = compartment()->lazyObjectGroups; - - if (!table.initialized() && !table.init()) - return nullptr; - - NewObjectGroupTable::AddPtr p = table.lookupForAdd(NewObjectGroupTable::Lookup(clasp, proto, nullptr)); - if (p) { - ObjectGroup *group = p->group; - MOZ_ASSERT(group->lazy()); - - return group; - } - - Rooted protoRoot(this, proto); - ObjectGroup *group = compartment()->types.newObjectGroup(this, clasp, protoRoot); - if (!group) - return nullptr; - - if (!table.add(p, NewObjectGroupEntry(group, nullptr))) - return nullptr; - - ObjectGroupTablePostBarrier(this, &table, clasp, proto, nullptr); - - group->initSingleton((JSObject *) ObjectGroup::LAZY_SINGLETON); - MOZ_ASSERT(group->singleton(), "created group must be a proper singleton"); - - return group; -} - -bool -ExclusiveContext::findAllocationSiteForType(Type type, JSScript **script, uint32_t *offset) const -{ - *script = nullptr; - *offset = 0; - - if (type.isUnknown() || type.isAnyObject() || !type.isGroup()) - return false; - ObjectGroup *obj = type.group(); - - const AllocationSiteTable *table = compartment()->types.allocationSiteTable; - if (!table) - return false; - - for (AllocationSiteTable::Range r = table->all(); !r.empty(); r.popFront()) { - if (obj == r.front().value()) { - *script = r.front().key().script; - *offset = r.front().key().offset; - return true; - } - } - return false; -} - ///////////////////////////////////////////////////////////////////// // Tracing ///////////////////////////////////////////////////////////////////// @@ -4955,209 +3901,6 @@ ObjectGroup::maybeSweep(AutoClearTypeInferenceStateOnOOM *oom) } } -void -TypeCompartment::clearTables() -{ - if (allocationSiteTable && allocationSiteTable->initialized()) - allocationSiteTable->clear(); - if (arrayTypeTable && arrayTypeTable->initialized()) - arrayTypeTable->clear(); - if (objectTypeTable && objectTypeTable->initialized()) - objectTypeTable->clear(); -} - -void -TypeCompartment::sweep(FreeOp *fop) -{ - /* - * Iterate through the array/object group tables and remove all entries - * referencing collected data. These tables only hold weak references. - */ - - if (arrayTypeTable) { - for (ArrayTypeTable::Enum e(*arrayTypeTable); !e.empty(); e.popFront()) { - ArrayTableKey key = e.front().key(); - MOZ_ASSERT(key.type.isUnknown() || !key.type.isSingleton()); - - bool remove = false; - if (!key.type.isUnknown() && key.type.isGroup()) { - ObjectGroup *group = key.type.groupNoBarrier(); - if (IsObjectGroupAboutToBeFinalized(&group)) - remove = true; - else - key.type = Type::ObjectType(group); - } - if (key.proto && key.proto != TaggedProto::LazyProto && - IsObjectAboutToBeFinalized(&key.proto)) - { - remove = true; - } - if (IsObjectGroupAboutToBeFinalized(e.front().value().unsafeGet())) - remove = true; - - if (remove) - e.removeFront(); - else if (key != e.front().key()) - e.rekeyFront(key); - } - } - - if (objectTypeTable) { - for (ObjectTypeTable::Enum e(*objectTypeTable); !e.empty(); e.popFront()) { - const ObjectTableKey &key = e.front().key(); - ObjectTableEntry &entry = e.front().value(); - - bool remove = false; - if (IsObjectGroupAboutToBeFinalized(entry.group.unsafeGet())) - remove = true; - if (IsShapeAboutToBeFinalized(entry.shape.unsafeGet())) - remove = true; - for (unsigned i = 0; !remove && i < key.nproperties; i++) { - if (JSID_IS_STRING(key.properties[i])) { - JSString *str = JSID_TO_STRING(key.properties[i]); - if (IsStringAboutToBeFinalized(&str)) - remove = true; - MOZ_ASSERT(AtomToId((JSAtom *)str) == key.properties[i]); - } else if (JSID_IS_SYMBOL(key.properties[i])) { - JS::Symbol *sym = JSID_TO_SYMBOL(key.properties[i]); - if (IsSymbolAboutToBeFinalized(&sym)) - remove = true; - } - - MOZ_ASSERT(!entry.types[i].isSingleton()); - ObjectGroup *group = nullptr; - if (entry.types[i].isGroup()) { - group = entry.types[i].groupNoBarrier(); - if (IsObjectGroupAboutToBeFinalized(&group)) - remove = true; - else if (group != entry.types[i].groupNoBarrier()) - entry.types[i] = Type::ObjectType(group); - } - } - - if (remove) { - js_free(key.properties); - js_free(entry.types); - e.removeFront(); - } - } - } - - if (allocationSiteTable) { - for (AllocationSiteTable::Enum e(*allocationSiteTable); !e.empty(); e.popFront()) { - AllocationSiteKey key = e.front().key(); - bool keyDying = IsScriptAboutToBeFinalized(&key.script); - bool valDying = IsObjectGroupAboutToBeFinalized(e.front().value().unsafeGet()); - if (keyDying || valDying) - e.removeFront(); - else if (key.script != e.front().key().script) - e.rekeyFront(key); - } - } -} - -void -JSCompartment::sweepNewObjectGroupTable(NewObjectGroupTable &table) -{ - MOZ_ASSERT(zone()->runtimeFromAnyThread()->isHeapCollecting()); - if (table.initialized()) { - for (NewObjectGroupTable::Enum e(table); !e.empty(); e.popFront()) { - NewObjectGroupEntry entry = e.front(); - if (IsObjectGroupAboutToBeFinalizedFromAnyThread(entry.group.unsafeGet()) || - (entry.associated && IsObjectAboutToBeFinalizedFromAnyThread(&entry.associated))) - { - e.removeFront(); - } else { - /* Any rekeying necessary is handled by fixupNewObjectGroupTable() below. */ - MOZ_ASSERT(entry.group.unbarrieredGet() == e.front().group.unbarrieredGet()); - MOZ_ASSERT(entry.associated == e.front().associated); - } - } - } -} - -void -JSCompartment::fixupNewObjectGroupTable(NewObjectGroupTable &table) -{ - /* - * Each entry's hash depends on the object's prototype and we can't tell - * whether that has been moved or not in sweepNewObjectGroupTable(). - */ - MOZ_ASSERT(zone()->isCollecting()); - if (table.initialized()) { - for (NewObjectGroupTable::Enum e(table); !e.empty(); e.popFront()) { - NewObjectGroupEntry entry = e.front(); - bool needRekey = false; - if (IsForwarded(entry.group.get())) { - entry.group.set(Forwarded(entry.group.get())); - needRekey = true; - } - TaggedProto proto = entry.group->proto(); - if (proto.isObject() && IsForwarded(proto.toObject())) { - proto = TaggedProto(Forwarded(proto.toObject())); - needRekey = true; - } - if (entry.associated && IsForwarded(entry.associated)) { - entry.associated = Forwarded(entry.associated); - needRekey = true; - } - if (needRekey) { - const Class *clasp = entry.group->clasp(); - if (entry.associated && entry.associated->is()) - clasp = nullptr; - NewObjectGroupTable::Lookup lookup(clasp, proto, entry.associated); - e.rekeyFront(lookup, entry); - } - } - } -} - -#ifdef JSGC_HASH_TABLE_CHECKS - -void -JSCompartment::checkObjectGroupTablesAfterMovingGC() -{ - checkObjectGroupTableAfterMovingGC(newObjectGroups); - checkObjectGroupTableAfterMovingGC(lazyObjectGroups); -} - -void -JSCompartment::checkObjectGroupTableAfterMovingGC(NewObjectGroupTable &table) -{ - /* - * Assert that nothing points into the nursery or needs to be relocated, and - * that the hash table entries are discoverable. - */ - if (!table.initialized()) - return; - - for (NewObjectGroupTable::Enum e(table); !e.empty(); e.popFront()) { - NewObjectGroupEntry entry = e.front(); - CheckGCThingAfterMovingGC(entry.group.get()); - TaggedProto proto = entry.group->proto(); - if (proto.isObject()) - CheckGCThingAfterMovingGC(proto.toObject()); - CheckGCThingAfterMovingGC(entry.associated); - - const Class *clasp = entry.group->clasp(); - if (entry.associated && entry.associated->is()) - clasp = nullptr; - - NewObjectGroupTable::Lookup lookup(clasp, proto, entry.associated); - NewObjectGroupTable::Ptr ptr = table.lookup(lookup); - MOZ_ASSERT(ptr.found() && &*ptr == &e.front()); - } -} - -#endif // JSGC_HASH_TABLE_CHECKS - -TypeCompartment::~TypeCompartment() -{ - js_delete(arrayTypeTable); - js_delete(objectTypeTable); - js_delete(allocationSiteTable); -} - /* static */ void JSScript::maybeSweepTypes(AutoClearTypeInferenceStateOnOOM *oom) { @@ -5221,45 +3964,6 @@ Zone::addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf, } } -void -TypeCompartment::addSizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf, - size_t *allocationSiteTables, - size_t *arrayTypeTables, - size_t *objectTypeTables) -{ - if (allocationSiteTable) - *allocationSiteTables += allocationSiteTable->sizeOfIncludingThis(mallocSizeOf); - - if (arrayTypeTable) - *arrayTypeTables += arrayTypeTable->sizeOfIncludingThis(mallocSizeOf); - - if (objectTypeTable) { - *objectTypeTables += objectTypeTable->sizeOfIncludingThis(mallocSizeOf); - - for (ObjectTypeTable::Enum e(*objectTypeTable); - !e.empty(); - e.popFront()) - { - const ObjectTableKey &key = e.front().key(); - const ObjectTableEntry &value = e.front().value(); - - /* key.ids and values.types have the same length. */ - *objectTypeTables += mallocSizeOf(key.properties) + mallocSizeOf(value.types); - } - } -} - -size_t -ObjectGroup::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const -{ - size_t n = 0; - if (TypeNewScript *newScript = newScriptDontCheckGeneration()) - n += newScript->sizeOfIncludingThis(mallocSizeOf); - if (UnboxedLayout *layout = maybeUnboxedLayoutDontCheckGeneration()) - n += layout->sizeOfIncludingThis(mallocSizeOf); - return n; -} - TypeZone::TypeZone(Zone *zone) : zone_(zone), typeLifoAlloc(TYPE_LIFO_ALLOC_PRIMARY_CHUNK_SIZE), @@ -5325,9 +4029,6 @@ TypeZone::beginSweep(FreeOp *fop, bool releaseTypes, AutoClearTypeInferenceState // compiler outputs list later during the sweep. Don't worry about overflow // here, since stale indexes will persist only until the sweep finishes. generation++; - - for (CompartmentsInZoneIter comp(zone()); !comp.done(); comp.next()) - comp->types.sweep(fop); } void @@ -5379,7 +4080,7 @@ TypeScript::printTypes(JSContext *cx, HandleScript script) const fprintf(stderr, "Eval"); else fprintf(stderr, "Main"); - fprintf(stderr, " #%u %s:%d ", script->id(), script->filename(), (int) script->lineno()); + fprintf(stderr, " %p %s:%d ", script.get(), script->filename(), (int) script->lineno()); if (script->functionNonDelazifying()) { if (js::PropertyName *name = script->functionNonDelazifying()->name()) @@ -5400,7 +4101,7 @@ TypeScript::printTypes(JSContext *cx, HandleScript script) const for (jsbytecode *pc = script->code(); pc < script->codeEnd(); pc += GetBytecodeLength(pc)) { { - fprintf(stderr, "#%u:", script->id()); + fprintf(stderr, "%p:", script.get()); Sprinter sprinter(cx); if (!sprinter.init()) return; @@ -5419,23 +4120,3 @@ TypeScript::printTypes(JSContext *cx, HandleScript script) const fprintf(stderr, "\n"); } #endif /* DEBUG */ - -void -ObjectGroup::setAddendum(AddendumKind kind, void *addendum, bool writeBarrier /* = true */) -{ - MOZ_ASSERT(!needsSweep()); - MOZ_ASSERT(kind <= (OBJECT_FLAG_ADDENDUM_MASK >> OBJECT_FLAG_ADDENDUM_SHIFT)); - - if (writeBarrier) { - // Manually trigger barriers if we are clearing a TypeNewScript. Other - // kinds of addendums are immutable. - if (newScript()) - TypeNewScript::writeBarrierPre(newScript()); - else - MOZ_ASSERT(addendumKind() == Addendum_None || addendumKind() == kind); - } - - flags_ &= ~OBJECT_FLAG_ADDENDUM_MASK; - flags_ |= kind << OBJECT_FLAG_ADDENDUM_SHIFT; - addendum_ = addendum; -} diff --git a/js/src/jsinfer.h b/js/src/jsinfer.h index 406e12a3a21c..a90c49e6c876 100644 --- a/js/src/jsinfer.h +++ b/js/src/jsinfer.h @@ -23,100 +23,10 @@ #include "js/UbiNode.h" #include "js/Utility.h" #include "js/Vector.h" +#include "vm/ObjectGroup.h" namespace js { -class TypeDescr; -class UnboxedLayout; - -class TaggedProto -{ - public: - static JSObject * const LazyProto; - - TaggedProto() : proto(nullptr) {} - explicit TaggedProto(JSObject *proto) : proto(proto) {} - - uintptr_t toWord() const { return uintptr_t(proto); } - - bool isLazy() const { - return proto == LazyProto; - } - bool isObject() const { - /* Skip nullptr and LazyProto. */ - return uintptr_t(proto) > uintptr_t(TaggedProto::LazyProto); - } - JSObject *toObject() const { - MOZ_ASSERT(isObject()); - return proto; - } - JSObject *toObjectOrNull() const { - MOZ_ASSERT(!proto || isObject()); - return proto; - } - JSObject *raw() const { return proto; } - - bool operator ==(const TaggedProto &other) { return proto == other.proto; } - bool operator !=(const TaggedProto &other) { return proto != other.proto; } - - private: - JSObject *proto; -}; - -template <> -struct RootKind -{ - static ThingRootKind rootKind() { return THING_ROOT_OBJECT; } -}; - -template <> struct GCMethods -{ - static TaggedProto initial() { return TaggedProto(); } - static bool poisoned(const TaggedProto &v) { return IsPoisonedPtr(v.raw()); } -}; - -template <> struct GCMethods -{ - static TaggedProto initial() { return TaggedProto(); } - static bool poisoned(const TaggedProto &v) { return IsPoisonedPtr(v.raw()); } -}; - -template -class TaggedProtoOperations -{ - const TaggedProto *value() const { - return static_cast(this)->extract(); - } - - public: - uintptr_t toWord() const { return value()->toWord(); } - inline bool isLazy() const { return value()->isLazy(); } - inline bool isObject() const { return value()->isObject(); } - inline JSObject *toObject() const { return value()->toObject(); } - inline JSObject *toObjectOrNull() const { return value()->toObjectOrNull(); } - JSObject *raw() const { return value()->raw(); } -}; - -template <> -class HandleBase : public TaggedProtoOperations > -{ - friend class TaggedProtoOperations >; - const TaggedProto * extract() const { - return static_cast*>(this)->address(); - } -}; - -template <> -class RootedBase : public TaggedProtoOperations > -{ - friend class TaggedProtoOperations >; - const TaggedProto *extract() const { - return static_cast *>(this)->address(); - } -}; - -class CallObject; - namespace jit { struct IonScript; class JitAllocPolicy; @@ -351,85 +261,6 @@ enum : uint32_t { }; typedef uint32_t TypeFlags; -/* Flags and other state stored in ObjectGroup::flags */ -enum : uint32_t { - /* Whether this group is associated with some allocation site. */ - OBJECT_FLAG_FROM_ALLOCATION_SITE = 0x1, - - /* - * If set, the object's prototype might be in the nursery and can't be - * used during Ion compilation (which may be occurring off thread). - */ - OBJECT_FLAG_NURSERY_PROTO = 0x2, - - /* Mask/shift for the number of properties in propertySet */ - OBJECT_FLAG_PROPERTY_COUNT_MASK = 0xfff8, - OBJECT_FLAG_PROPERTY_COUNT_SHIFT = 3, - OBJECT_FLAG_PROPERTY_COUNT_LIMIT = - OBJECT_FLAG_PROPERTY_COUNT_MASK >> OBJECT_FLAG_PROPERTY_COUNT_SHIFT, - - /* Whether any objects this represents may have sparse indexes. */ - OBJECT_FLAG_SPARSE_INDEXES = 0x00010000, - - /* Whether any objects this represents may not have packed dense elements. */ - OBJECT_FLAG_NON_PACKED = 0x00020000, - - /* - * Whether any objects this represents may be arrays whose length does not - * fit in an int32. - */ - OBJECT_FLAG_LENGTH_OVERFLOW = 0x00040000, - - /* Whether any objects have been iterated over. */ - OBJECT_FLAG_ITERATED = 0x00080000, - - /* For a global object, whether flags were set on the RegExpStatics. */ - OBJECT_FLAG_REGEXP_FLAGS_SET = 0x00100000, - - /* - * For the function on a run-once script, whether the function has actually - * run multiple times. - */ - OBJECT_FLAG_RUNONCE_INVALIDATED = 0x00200000, - - /* - * For a global object, whether any array buffers in this compartment with - * typed object views have been neutered. - */ - OBJECT_FLAG_TYPED_OBJECT_NEUTERED = 0x00400000, - - /* - * Whether objects with this type should be allocated directly in the - * tenured heap. - */ - OBJECT_FLAG_PRE_TENURE = 0x00800000, - - /* Whether objects with this type might have copy on write elements. */ - OBJECT_FLAG_COPY_ON_WRITE = 0x01000000, - - /* Whether this type has had its 'new' script cleared in the past. */ - OBJECT_FLAG_NEW_SCRIPT_CLEARED = 0x02000000, - - /* - * Whether all properties of this object are considered unknown. - * If set, all other flags in DYNAMIC_MASK will also be set. - */ - OBJECT_FLAG_UNKNOWN_PROPERTIES = 0x04000000, - - /* Flags which indicate dynamic properties of represented objects. */ - OBJECT_FLAG_DYNAMIC_MASK = 0x07ff0000, - - // Mask/shift for the kind of addendum attached to this group. - OBJECT_FLAG_ADDENDUM_MASK = 0x38000000, - OBJECT_FLAG_ADDENDUM_SHIFT = 27, - - // Mask/shift for this group's generation. If out of sync with the - // TypeZone's generation, this group hasn't been swept yet. - OBJECT_FLAG_GENERATION_MASK = 0x40000000, - OBJECT_FLAG_GENERATION_SHIFT = 30, -}; -typedef uint32_t ObjectGroupFlags; - class StackTypeSet; class HeapTypeSet; class TemporaryTypeSet; @@ -647,8 +478,6 @@ class HeapTypeSet : public ConstraintTypeSet inline void setNonConstantProperty(ExclusiveContext *cx); }; -class CompilerConstraintList; - CompilerConstraintList * NewCompilerConstraintList(jit::TempAllocator &alloc); @@ -773,30 +602,6 @@ bool AddClearDefiniteFunctionUsesInScript(JSContext *cx, ObjectGroup *group, JSScript *script, JSScript *calleeScript); -/* Is this a reasonable PC to be doing inlining on? */ -inline bool isInlinableCall(jsbytecode *pc); - -/* Type information about a property. */ -struct Property -{ - /* Identifier for this property, JSID_VOID for the aggregate integer index property. */ - HeapId id; - - /* Possible types for this property, including types inherited from prototypes. */ - HeapTypeSet types; - - explicit Property(jsid id) - : id(id) - {} - - Property(const Property &o) - : id(o.id.get()), types(o.types) - {} - - static uint32_t keyBits(jsid id) { return uint32_t(JSID_BITS(id)); } - static jsid getKey(Property *p) { return p->id; } -}; - // For types where only a small number of objects have been allocated, this // structure keeps track of all objects with the type in existence. Once // COUNT objects have been allocated, this structure is cleared and the objects @@ -964,420 +769,68 @@ class TypeNewScript size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const; }; -/* - * Lazy object groups overview. - * - * Object groups which represent at most one JS object are constructed lazily. - * These include groups for native functions, standard classes, scripted - * functions defined at the top level of global/eval scripts, and in some - * other cases. Typical web workloads often create many windows (and many - * copies of standard natives) and many scripts, with comparatively few - * non-singleton groups. - * - * We can recover the type information for the object from examining it, - * so don't normally track the possible types of its properties as it is - * updated. Property type sets for the object are only constructed when an - * analyzed script attaches constraints to it: the script is querying that - * property off the object or another which delegates to it, and the analysis - * information is sensitive to changes in the property's type. Future changes - * to the property (whether those uncovered by analysis or those occurring - * in the VM) will treat these properties like those of any other object group. - */ - -/* Type information about an object accessed by a script. */ -struct ObjectGroup : public gc::TenuredCell -{ - private: - /* Class shared by objects in this group. */ - const Class *clasp_; - - /* Prototype shared by objects in this group. */ - HeapPtrObject proto_; - - /* - * Whether there is a singleton JS object with this group. That JS object - * must appear in type sets instead of this; we include the back reference - * here to allow reverting the JS object to a lazy group. - */ - HeapPtrObject singleton_; - - public: - - const Class *clasp() const { - return clasp_; - } - - void setClasp(const Class *clasp) { - clasp_ = clasp; - } - - TaggedProto proto() const { - return TaggedProto(proto_); - } - - JSObject *singleton() const { - return singleton_; - } - - // For use during marking, don't call otherwise. - HeapPtrObject &protoRaw() { return proto_; } - HeapPtrObject &singletonRaw() { return singleton_; } - - void setProto(JSContext *cx, TaggedProto proto); - void setProtoUnchecked(TaggedProto proto) { - proto_ = proto.raw(); - } - - void initSingleton(JSObject *singleton) { - singleton_ = singleton; - } - - /* - * Value held by singleton if this is a standin group for a singleton JS - * object whose group has not been constructed yet. - */ - static const size_t LAZY_SINGLETON = 1; - bool lazy() const { return singleton() == (JSObject *) LAZY_SINGLETON; } - - private: - /* Flags for this group. */ - ObjectGroupFlags flags_; - - // Kinds of addendums which can be attached to ObjectGroups. - enum AddendumKind { - Addendum_None, - - // When used by interpreted function, the addendum stores the - // canonical JSFunction object. - Addendum_InterpretedFunction, - - // When used by the 'new' group when constructing an interpreted - // function, the addendum stores a TypeNewScript. - Addendum_NewScript, - - // When objects in this group have an unboxed representation, the - // addendum stores an UnboxedLayout (which might have a TypeNewScript - // as well, if the group is also constructed using 'new'). - Addendum_UnboxedLayout, - - // When used by typed objects, the addendum stores a TypeDescr. - Addendum_TypeDescr - }; - - // If non-null, holds additional information about this object, whose - // format is indicated by the object's addendum kind. - void *addendum_; - - void setAddendum(AddendumKind kind, void *addendum, bool writeBarrier = true); - - AddendumKind addendumKind() const { - return (AddendumKind) - ((flags_ & OBJECT_FLAG_ADDENDUM_MASK) >> OBJECT_FLAG_ADDENDUM_SHIFT); - } - - TypeNewScript *newScriptDontCheckGeneration() const { - if (addendumKind() == Addendum_NewScript) - return reinterpret_cast(addendum_); - return nullptr; - } - - UnboxedLayout *maybeUnboxedLayoutDontCheckGeneration() const { - if (addendumKind() == Addendum_UnboxedLayout) - return reinterpret_cast(addendum_); - return nullptr; - } - - TypeNewScript *anyNewScript(); - void detachNewScript(bool writeBarrier); - - public: - - ObjectGroupFlags flags() { - maybeSweep(nullptr); - return flags_; - } - - void addFlags(ObjectGroupFlags flags) { - maybeSweep(nullptr); - flags_ |= flags; - } - - void clearFlags(ObjectGroupFlags flags) { - maybeSweep(nullptr); - flags_ &= ~flags; - } - - TypeNewScript *newScript() { - maybeSweep(nullptr); - return newScriptDontCheckGeneration(); - } - - void setNewScript(TypeNewScript *newScript) { - setAddendum(Addendum_NewScript, newScript); - } - - UnboxedLayout *maybeUnboxedLayout() { - maybeSweep(nullptr); - return maybeUnboxedLayoutDontCheckGeneration(); - } - - UnboxedLayout &unboxedLayout() { - MOZ_ASSERT(addendumKind() == Addendum_UnboxedLayout); - return *maybeUnboxedLayout(); - } - - void setUnboxedLayout(UnboxedLayout *layout) { - setAddendum(Addendum_UnboxedLayout, layout); - } - - TypeDescr *maybeTypeDescr() { - // Note: there is no need to sweep when accessing the type descriptor - // of an object, as it is strongly held and immutable. - if (addendumKind() == Addendum_TypeDescr) - return reinterpret_cast(addendum_); - return nullptr; - } - - TypeDescr &typeDescr() { - MOZ_ASSERT(addendumKind() == Addendum_TypeDescr); - return *maybeTypeDescr(); - } - - void setTypeDescr(TypeDescr *descr) { - setAddendum(Addendum_TypeDescr, descr); - } - - JSFunction *maybeInterpretedFunction() { - // Note: as with type descriptors, there is no need to sweep when - // accessing the interpreted function associated with an object. - if (addendumKind() == Addendum_InterpretedFunction) - return reinterpret_cast(addendum_); - return nullptr; - } - - void setInterpretedFunction(JSFunction *fun) { - setAddendum(Addendum_InterpretedFunction, fun); - } - - private: - /* - * Properties of this object. This may contain JSID_VOID, representing the - * types of all integer indexes of the object, and/or JSID_EMPTY, holding - * constraints listening to changes to the object's state. - * - * The type sets in the properties of a group describe the possible values - * that can be read out of that property in actual JS objects. In native - * objects, property types account for plain data properties (those with a - * slot and no getter or setter hook) and dense elements. In typed objects - * and unboxed objects, property types account for object and value - * properties and elements in the object. - * - * For accesses on these properties, the correspondence is as follows: - * - * 1. If the group has unknownProperties(), the possible properties and - * value types for associated JSObjects are unknown. - * - * 2. Otherwise, for any |obj| in |group|, and any |id| which is a property - * in |obj|, before obj->getProperty(id) the property in |group| for - * |id| must reflect the result of the getProperty. - * - * There are several exceptions to this: - * - * 1. For properties of global JS objects which are undefined at the point - * where the property was (lazily) generated, the property type set will - * remain empty, and the 'undefined' type will only be added after a - * subsequent assignment or deletion. After these properties have been - * assigned a defined value, the only way they can become undefined - * again is after such an assign or deletion. - * - * 2. Array lengths are special cased by the compiler and VM and are not - * reflected in property types. - * - * 3. In typed objects (but not unboxed objects), the initial values of - * properties (null pointers and undefined values) are not reflected in - * the property types. These values are always possible when reading the - * property. - * - * We establish these by using write barriers on calls to setProperty and - * defineProperty which are on native properties, and on any jitcode which - * might update the property with a new type. - */ - Property **propertySet; - public: - - inline ObjectGroup(const Class *clasp, TaggedProto proto, ObjectGroupFlags initialFlags); - - bool hasAnyFlags(ObjectGroupFlags flags) { - MOZ_ASSERT((flags & OBJECT_FLAG_DYNAMIC_MASK) == flags); - return !!(this->flags() & flags); - } - bool hasAllFlags(ObjectGroupFlags flags) { - MOZ_ASSERT((flags & OBJECT_FLAG_DYNAMIC_MASK) == flags); - return (this->flags() & flags) == flags; - } - - bool unknownProperties() { - MOZ_ASSERT_IF(flags() & OBJECT_FLAG_UNKNOWN_PROPERTIES, - hasAllFlags(OBJECT_FLAG_DYNAMIC_MASK)); - return !!(flags() & OBJECT_FLAG_UNKNOWN_PROPERTIES); - } - - bool shouldPreTenure() { - return hasAnyFlags(OBJECT_FLAG_PRE_TENURE) && !unknownProperties(); - } - - bool hasTenuredProto() { - return !(flags() & OBJECT_FLAG_NURSERY_PROTO); - } - - gc::InitialHeap initialHeap(CompilerConstraintList *constraints); - - bool canPreTenure() { - return !unknownProperties(); - } - - bool fromAllocationSite() { - return flags() & OBJECT_FLAG_FROM_ALLOCATION_SITE; - } - - void setShouldPreTenure(ExclusiveContext *cx) { - MOZ_ASSERT(canPreTenure()); - setFlags(cx, OBJECT_FLAG_PRE_TENURE); - } - - /* - * Get or create a property of this object. Only call this for properties which - * a script accesses explicitly. - */ - inline HeapTypeSet *getProperty(ExclusiveContext *cx, jsid id); - - /* Get a property only if it already exists. */ - inline HeapTypeSet *maybeGetProperty(jsid id); - - inline unsigned getPropertyCount(); - inline Property *getProperty(unsigned i); - - /* Helpers */ - - void updateNewPropertyTypes(ExclusiveContext *cx, jsid id, HeapTypeSet *types); - bool addDefiniteProperties(ExclusiveContext *cx, Shape *shape); - bool matchDefiniteProperties(HandleObject obj); - void markPropertyNonData(ExclusiveContext *cx, jsid id); - void markPropertyNonWritable(ExclusiveContext *cx, jsid id); - void markStateChange(ExclusiveContext *cx); - void setFlags(ExclusiveContext *cx, ObjectGroupFlags flags); - void markUnknown(ExclusiveContext *cx); - void maybeClearNewScriptOnOOM(); - void clearNewScript(ExclusiveContext *cx); - bool isPropertyNonData(jsid id); - bool isPropertyNonWritable(jsid id); - - void print(); - - inline void clearProperties(); - void maybeSweep(AutoClearTypeInferenceStateOnOOM *oom); - - private: -#ifdef DEBUG - bool needsSweep(); -#endif - - uint32_t generation() { - return (flags_ & OBJECT_FLAG_GENERATION_MASK) >> OBJECT_FLAG_GENERATION_SHIFT; - } - - public: - void setGeneration(uint32_t generation) { - MOZ_ASSERT(generation <= (OBJECT_FLAG_GENERATION_MASK >> OBJECT_FLAG_GENERATION_SHIFT)); - flags_ &= ~OBJECT_FLAG_GENERATION_MASK; - flags_ |= generation << OBJECT_FLAG_GENERATION_SHIFT; - } - - size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const; - - inline void finalize(FreeOp *fop); - void fixupAfterMovingGC() {} - - static inline ThingRootKind rootKind() { return THING_ROOT_OBJECT_GROUP; } - - static inline uint32_t offsetOfClasp() { - return offsetof(ObjectGroup, clasp_); - } - - static inline uint32_t offsetOfProto() { - return offsetof(ObjectGroup, proto_); - } - - static inline uint32_t offsetOfAddendum() { - return offsetof(ObjectGroup, addendum_); - } - - static inline uint32_t offsetOfFlags() { - return offsetof(ObjectGroup, flags_); - } - - private: - inline uint32_t basePropertyCount(); - inline void setBasePropertyCount(uint32_t count); - - static void staticAsserts() { - JS_STATIC_ASSERT(offsetof(ObjectGroup, proto_) == offsetof(js::shadow::ObjectGroup, proto)); - } -}; +/* Is this a reasonable PC to be doing inlining on? */ +inline bool isInlinableCall(jsbytecode *pc); /* - * Entries for the per-compartment set of groups which are the default - * types to use for some prototype. An optional associated object is used which - * allows multiple groups to be created with the same prototype. The - * associated object may be a function (for types constructed with 'new') or a - * type descriptor (for typed objects). These entries are also used for the set - * of lazy groups in the compartment, which use a null associated object - * (though there are only a few of these per compartment). + * Type information about a property. + * + * The type sets in the properties of a group describe the possible values + * that can be read out of that property in actual JS objects. In native + * objects, property types account for plain data properties (those with a + * slot and no getter or setter hook) and dense elements. In typed objects + * and unboxed objects, property types account for object and value + * properties and elements in the object. + * + * For accesses on these properties, the correspondence is as follows: + * + * 1. If the group has unknownProperties(), the possible properties and + * value types for associated JSObjects are unknown. + * + * 2. Otherwise, for any |obj| in |group|, and any |id| which is a property + * in |obj|, before obj->getProperty(id) the property in |group| for + * |id| must reflect the result of the getProperty. + * + * There are several exceptions to this: + * + * 1. For properties of global JS objects which are undefined at the point + * where the property was (lazily) generated, the property type set will + * remain empty, and the 'undefined' type will only be added after a + * subsequent assignment or deletion. After these properties have been + * assigned a defined value, the only way they can become undefined + * again is after such an assign or deletion. + * + * 2. Array lengths are special cased by the compiler and VM and are not + * reflected in property types. + * + * 3. In typed objects (but not unboxed objects), the initial values of + * properties (null pointers and undefined values) are not reflected in + * the property types. These values are always possible when reading the + * property. + * + * We establish these by using write barriers on calls to setProperty and + * defineProperty which are on native properties, and on any jitcode which + * might update the property with a new type. */ -struct NewObjectGroupEntry +struct Property { - ReadBarrieredObjectGroup group; + /* Identifier for this property, JSID_VOID for the aggregate integer index property. */ + HeapId id; - // Note: This pointer is only used for equality and does not need a read barrier. - JSObject *associated; + /* Possible types for this property, including types inherited from prototypes. */ + HeapTypeSet types; - NewObjectGroupEntry(ObjectGroup *group, JSObject *associated) - : group(group), associated(associated) + explicit Property(jsid id) + : id(id) {} - struct Lookup { - const Class *clasp; - TaggedProto hashProto; - TaggedProto matchProto; - JSObject *associated; + Property(const Property &o) + : id(o.id.get()), types(o.types) + {} - Lookup(const Class *clasp, TaggedProto proto, JSObject *associated) - : clasp(clasp), hashProto(proto), matchProto(proto), associated(associated) - {} - - /* - * For use by generational post barriers only. Look up an entry whose - * proto has been moved, but was hashed with the original value. - */ - Lookup(const Class *clasp, TaggedProto hashProto, TaggedProto matchProto, JSObject *associated) - : clasp(clasp), hashProto(hashProto), matchProto(matchProto), associated(associated) - {} - - }; - - static inline HashNumber hash(const Lookup &lookup); - static inline bool match(const NewObjectGroupEntry &key, const Lookup &lookup); - static void rekey(NewObjectGroupEntry &k, const NewObjectGroupEntry& newKey) { k = newKey; } + static uint32_t keyBits(jsid id) { return uint32_t(JSID_BITS(id)); } + static jsid getKey(Property *p) { return p->id; } }; -typedef HashSet NewObjectGroupTable; - -// Whether to make a singleton when calling 'new' at script/pc. -bool -UseSingletonForNewObject(JSContext *cx, JSScript *script, jsbytecode *pc); - -// Whether to make a deep cloned singleton when cloning fun. -bool -UseSingletonForClone(JSFunction *fun); /* * Whether Array.prototype, or an object on its proto chain, has an @@ -1426,10 +879,6 @@ class TypeScript static inline TYPESET *BytecodeTypes(JSScript *script, jsbytecode *pc, uint32_t *bytecodeMap, uint32_t *hint, TYPESET *typeArray); - /* Get a group for an allocation site in this script. */ - static inline ObjectGroup *InitGroup(JSContext *cx, JSScript *script, jsbytecode *pc, - JSProtoKey kind); - /* * Monitor a bytecode pushing any value. This must be called for any opcode * which is JOF_TYPESET, and where either the script has not been analyzed @@ -1477,12 +926,6 @@ class TypeScript void FillBytecodeTypeMap(JSScript *script, uint32_t *bytecodeMap); -ArrayObject * -GetOrFixupCopyOnWriteObject(JSContext *cx, HandleScript script, jsbytecode *pc); - -ArrayObject * -GetCopyOnWriteObject(JSScript *script, jsbytecode *pc); - class RecompileInfo; // Allocate a CompilerOutput for a finished compilation and generate the type @@ -1497,22 +940,6 @@ FinishCompilation(JSContext *cx, HandleScript script, CompilerConstraintList *co void FinishDefinitePropertiesAnalysis(JSContext *cx, CompilerConstraintList *constraints); -struct ArrayTableKey; -typedef HashMap ArrayTypeTable; - -struct ObjectTableKey; -struct ObjectTableEntry; -typedef HashMap ObjectTypeTable; - -struct AllocationSiteKey; -typedef HashMap AllocationSiteTable; - class HeapTypeSetKey; // Type set entry for either a JSObject with singleton type or a non-singleton ObjectGroup. @@ -1683,55 +1110,6 @@ class RecompileInfo typedef Vector RecompileInfoVector; -/* Type information for a compartment. */ -struct TypeCompartment -{ - /* Number of scripts in this compartment. */ - unsigned scriptCount; - - /* Table for referencing types of objects keyed to an allocation site. */ - AllocationSiteTable *allocationSiteTable; - - /* Tables for determining types of singleton/JSON objects. */ - ArrayTypeTable *arrayTypeTable; - ObjectTypeTable *objectTypeTable; - - private: - void setTypeToHomogenousArray(ExclusiveContext *cx, JSObject *obj, Type type); - - public: - void fixArrayGroup(ExclusiveContext *cx, ArrayObject *obj); - void fixObjectGroup(ExclusiveContext *cx, PlainObject *obj); - void fixRestArgumentsType(ExclusiveContext *cx, ArrayObject *obj); - - JSObject *newTypedObject(JSContext *cx, IdValuePair *properties, size_t nproperties); - - TypeCompartment(); - ~TypeCompartment(); - - inline JSCompartment *compartment(); - - // Prints results of this compartment if spew is enabled or force is set. - void print(JSContext *cx, bool force); - - ObjectGroup *newObjectGroup(ExclusiveContext *cx, const Class *clasp, Handle proto, - ObjectGroupFlags initialFlags = 0); - - // Get or make a group for an allocation site, and add to the allocation site table. - ObjectGroup *addAllocationSiteObjectGroup(JSContext *cx, AllocationSiteKey key); - - void clearTables(); - void sweep(FreeOp *fop); - void finalizeObjects(); - - void addSizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf, - size_t *allocationSiteTables, - size_t *arrayTypeTables, - size_t *objectTypeTables); -}; - -void FixRestArgumentsType(ExclusiveContext *cxArg, ArrayObject *obj); - struct AutoEnterAnalysis; struct TypeZone @@ -1819,6 +1197,10 @@ inline const char * ObjectGroupString(ObjectGroup *group) { return nullptr; } /* Print a warning, dump state and abort the program. */ MOZ_NORETURN MOZ_COLD void TypeFailure(JSContext *cx, const char *fmt, ...); +// Prints type information for a context if spew is enabled or force is set. +void +PrintTypes(JSContext *cx, JSCompartment *comp, bool force); + } /* namespace types */ } /* namespace js */ @@ -1826,7 +1208,7 @@ MOZ_NORETURN MOZ_COLD void TypeFailure(JSContext *cx, const char *fmt, ...); // with no associated compartment. namespace JS { namespace ubi { -template<> struct Concrete : TracerConcrete { }; +template<> struct Concrete : TracerConcrete { }; } } diff --git a/js/src/jsinferinlines.h b/js/src/jsinferinlines.h index d56d83ff1a65..e2100c156565 100644 --- a/js/src/jsinferinlines.h +++ b/js/src/jsinferinlines.h @@ -323,87 +323,6 @@ struct AutoEnterAnalysis // Interface functions ///////////////////////////////////////////////////////////////////// -inline const Class * -GetClassForProtoKey(JSProtoKey key) -{ - switch (key) { - case JSProto_Null: - case JSProto_Object: - return &PlainObject::class_; - case JSProto_Array: - return &ArrayObject::class_; - - case JSProto_Number: - return &NumberObject::class_; - case JSProto_Boolean: - return &BooleanObject::class_; - case JSProto_String: - return &StringObject::class_; - case JSProto_Symbol: - return &SymbolObject::class_; - case JSProto_RegExp: - return &RegExpObject::class_; - - case JSProto_Int8Array: - case JSProto_Uint8Array: - case JSProto_Int16Array: - case JSProto_Uint16Array: - case JSProto_Int32Array: - case JSProto_Uint32Array: - case JSProto_Float32Array: - case JSProto_Float64Array: - case JSProto_Uint8ClampedArray: - return &TypedArrayObject::classes[key - JSProto_Int8Array]; - - case JSProto_SharedInt8Array: - case JSProto_SharedUint8Array: - case JSProto_SharedInt16Array: - case JSProto_SharedUint16Array: - case JSProto_SharedInt32Array: - case JSProto_SharedUint32Array: - case JSProto_SharedFloat32Array: - case JSProto_SharedFloat64Array: - case JSProto_SharedUint8ClampedArray: - return &SharedTypedArrayObject::classes[key - JSProto_SharedInt8Array]; - - case JSProto_ArrayBuffer: - return &ArrayBufferObject::class_; - - case JSProto_SharedArrayBuffer: - return &SharedArrayBufferObject::class_; - - case JSProto_DataView: - return &DataViewObject::class_; - - default: - MOZ_CRASH("Bad proto key"); - } -} - -/* - * Get the default 'new' group for a given standard class, per the currently - * active global. - */ -inline ObjectGroup * -GetNewObjectGroup(JSContext *cx, JSProtoKey key) -{ - RootedObject proto(cx); - if (key != JSProto_Null && !GetBuiltinPrototype(cx, key, &proto)) - return nullptr; - return cx->getNewGroup(GetClassForProtoKey(key), TaggedProto(proto.get())); -} - -/* Get a group for the immediate allocation site within a native. */ -inline ObjectGroup * -GetCallerInitGroup(JSContext *cx, JSProtoKey key) -{ - jsbytecode *pc; - RootedScript script(cx, cx->currentScript(&pc)); - if (script) - return TypeScript::InitGroup(cx, script, pc, key); - return GetNewObjectGroup(cx, key); -} - void MarkIteratorUnknownSlow(JSContext *cx); void TypeMonitorCallSlow(JSContext *cx, JSObject *callee, const CallArgs &args, @@ -569,23 +488,6 @@ MarkObjectStateChange(ExclusiveContext *cx, JSObject *obj) obj->group()->markStateChange(cx); } -/* - * For an array or object which has not yet escaped and been referenced elsewhere, - * pick a new type based on the object's current contents. - */ - -inline void -FixArrayGroup(ExclusiveContext *cx, ArrayObject *obj) -{ - cx->compartment()->types.fixArrayGroup(cx, obj); -} - -inline void -FixObjectGroup(ExclusiveContext *cx, PlainObject *obj) -{ - cx->compartment()->types.fixObjectGroup(cx, obj); -} - /* Interface helpers for JSScript*. */ extern void TypeMonitorResult(JSContext *cx, JSScript *script, jsbytecode *pc, const js::Value &rval); @@ -679,85 +581,6 @@ TypeScript::BytecodeTypes(JSScript *script, jsbytecode *pc) hint, types->typeArray()); } -struct AllocationSiteKey : public DefaultHasher { - JSScript *script; - - uint32_t offset : 24; - JSProtoKey kind : 8; - - static const uint32_t OFFSET_LIMIT = (1 << 23); - - AllocationSiteKey() { mozilla::PodZero(this); } - - static inline uint32_t hash(AllocationSiteKey key) { - return uint32_t(size_t(key.script->offsetToPC(key.offset)) ^ key.kind); - } - - static inline bool match(const AllocationSiteKey &a, const AllocationSiteKey &b) { - return a.script == b.script && a.offset == b.offset && a.kind == b.kind; - } -}; - -/* Whether to use a singleton kind for an initializer opcode at script/pc. */ -js::NewObjectKind -UseSingletonForInitializer(JSScript *script, jsbytecode *pc, JSProtoKey key); - -js::NewObjectKind -UseSingletonForInitializer(JSScript *script, jsbytecode *pc, const Class *clasp); - -/* static */ inline ObjectGroup * -TypeScript::InitGroup(JSContext *cx, JSScript *script, jsbytecode *pc, JSProtoKey kind) -{ - MOZ_ASSERT(!UseSingletonForInitializer(script, pc, kind)); - - uint32_t offset = script->pcToOffset(pc); - - if (offset >= AllocationSiteKey::OFFSET_LIMIT) - return GetNewObjectGroup(cx, kind); - - AllocationSiteKey key; - key.script = script; - key.offset = offset; - key.kind = kind; - - if (!cx->compartment()->types.allocationSiteTable) - return cx->compartment()->types.addAllocationSiteObjectGroup(cx, key); - - AllocationSiteTable::Ptr p = cx->compartment()->types.allocationSiteTable->lookup(key); - - if (p) - return p->value(); - return cx->compartment()->types.addAllocationSiteObjectGroup(cx, key); -} - -/* Set the group to use for obj according to the site it was allocated at. */ -static inline bool -SetInitializerObjectGroup(JSContext *cx, HandleScript script, jsbytecode *pc, HandleObject obj, - NewObjectKind kind) -{ - JSProtoKey key = JSCLASS_CACHED_PROTO_KEY(obj->getClass()); - MOZ_ASSERT(key != JSProto_Null); - MOZ_ASSERT(kind == UseSingletonForInitializer(script, pc, key)); - - if (kind == SingletonObject) { - MOZ_ASSERT(obj->isSingleton()); - - /* - * Inference does not account for types of run-once initializer - * objects, as these may not be created until after the script - * has been analyzed. - */ - TypeScript::Monitor(cx, script, pc, ObjectValue(*obj)); - } else { - types::ObjectGroup *group = TypeScript::InitGroup(cx, script, pc, key); - if (!group) - return false; - obj->uninlinedSetGroup(group); - } - - return true; -} - /* static */ inline void TypeScript::Monitor(JSContext *cx, JSScript *script, jsbytecode *pc, const js::Value &rval) { @@ -808,8 +631,8 @@ TypeScript::SetThis(JSContext *cx, JSScript *script, Type type) if (!types->hasType(type)) { AutoEnterAnalysis enter(cx); - InferSpew(ISpewOps, "externalType: setThis #%u: %s", - script->id(), TypeString(type)); + InferSpew(ISpewOps, "externalType: setThis %p: %s", + script, TypeString(type)); types->addType(cx, type); } } @@ -830,8 +653,8 @@ TypeScript::SetArgument(JSContext *cx, JSScript *script, unsigned arg, Type type if (!types->hasType(type)) { AutoEnterAnalysis enter(cx); - InferSpew(ISpewOps, "externalType: setArg #%u %u: %s", - script->id(), arg, TypeString(type)); + InferSpew(ISpewOps, "externalType: setArg %p %u: %s", + script, arg, TypeString(type)); types->addType(cx, type); } } @@ -843,16 +666,6 @@ TypeScript::SetArgument(JSContext *cx, JSScript *script, unsigned arg, const js: SetArgument(cx, script, arg, type); } -///////////////////////////////////////////////////////////////////// -// TypeCompartment -///////////////////////////////////////////////////////////////////// - -inline JSCompartment * -TypeCompartment::compartment() -{ - return (JSCompartment *)((char *)this - offsetof(JSCompartment, types)); -} - ///////////////////////////////////////////////////////////////////// // TypeSet ///////////////////////////////////////////////////////////////////// @@ -1189,33 +1002,26 @@ TypeSet::getObjectClass(unsigned i) const } ///////////////////////////////////////////////////////////////////// -// ObjectGroup +// TypeNewScript ///////////////////////////////////////////////////////////////////// -inline -ObjectGroup::ObjectGroup(const Class *clasp, TaggedProto proto, ObjectGroupFlags initialFlags) -{ - mozilla::PodZero(this); - - /* Inner objects may not appear on prototype chains. */ - MOZ_ASSERT_IF(proto.isObject(), !proto.toObject()->getClass()->ext.outerObject); - - this->clasp_ = clasp; - this->proto_ = proto.raw(); - this->flags_ = initialFlags; - - setGeneration(zone()->types.generation); - - InferSpew(ISpewOps, "newGroup: %s", ObjectGroupString(this)); -} - inline void -ObjectGroup::finalize(FreeOp *fop) +TypeNewScript::writeBarrierPre(TypeNewScript *newScript) { - fop->delete_(newScriptDontCheckGeneration()); - fop->delete_(maybeUnboxedLayoutDontCheckGeneration()); + if (!newScript->function()->runtimeFromAnyThread()->needsIncrementalBarrier()) + return; + + JS::Zone *zone = newScript->function()->zoneFromAnyThread(); + if (zone->needsIncrementalBarrier()) + newScript->trace(zone->barrierTracer()); } +} // namespace types + +///////////////////////////////////////////////////////////////////// +// ObjectGroup +///////////////////////////////////////////////////////////////////// + inline uint32_t ObjectGroup::basePropertyCount() { @@ -1231,24 +1037,24 @@ ObjectGroup::setBasePropertyCount(uint32_t count) | (count << OBJECT_FLAG_PROPERTY_COUNT_SHIFT); } -inline HeapTypeSet * +inline types::HeapTypeSet * ObjectGroup::getProperty(ExclusiveContext *cx, jsid id) { MOZ_ASSERT(JSID_IS_VOID(id) || JSID_IS_EMPTY(id) || JSID_IS_STRING(id) || JSID_IS_SYMBOL(id)); - MOZ_ASSERT_IF(!JSID_IS_EMPTY(id), id == IdToTypeId(id)); + MOZ_ASSERT_IF(!JSID_IS_EMPTY(id), id == types::IdToTypeId(id)); MOZ_ASSERT(!unknownProperties()); - if (HeapTypeSet *types = maybeGetProperty(id)) + if (types::HeapTypeSet *types = maybeGetProperty(id)) return types; - Property *base = cx->typeLifoAlloc().new_(id); + types::Property *base = cx->typeLifoAlloc().new_(id); if (!base) { markUnknown(cx); return nullptr; } uint32_t propertyCount = basePropertyCount(); - Property **pprop = HashSetInsert + types::Property **pprop = types::HashSetInsert (cx->typeLifoAlloc(), propertySet, propertyCount, id); if (!pprop) { markUnknown(cx); @@ -1272,14 +1078,14 @@ ObjectGroup::getProperty(ExclusiveContext *cx, jsid id) return &base->types; } -inline HeapTypeSet * +inline types::HeapTypeSet * ObjectGroup::maybeGetProperty(jsid id) { MOZ_ASSERT(JSID_IS_VOID(id) || JSID_IS_EMPTY(id) || JSID_IS_STRING(id) || JSID_IS_SYMBOL(id)); - MOZ_ASSERT_IF(!JSID_IS_EMPTY(id), id == IdToTypeId(id)); + MOZ_ASSERT_IF(!JSID_IS_EMPTY(id), id == types::IdToTypeId(id)); MOZ_ASSERT(!unknownProperties()); - Property *prop = HashSetLookup + types::Property *prop = types::HashSetLookup (propertySet, basePropertyCount(), id); return prop ? &prop->types : nullptr; @@ -1289,50 +1095,22 @@ inline unsigned ObjectGroup::getPropertyCount() { uint32_t count = basePropertyCount(); - if (count > SET_ARRAY_SIZE) - return HashSetCapacity(count); + if (count > types::SET_ARRAY_SIZE) + return types::HashSetCapacity(count); return count; } -inline Property * +inline types::Property * ObjectGroup::getProperty(unsigned i) { MOZ_ASSERT(i < getPropertyCount()); if (basePropertyCount() == 1) { MOZ_ASSERT(i == 0); - return (Property *) propertySet; + return (types::Property *) propertySet; } return propertySet[i]; } -inline void -TypeNewScript::writeBarrierPre(TypeNewScript *newScript) -{ - if (!newScript->function()->runtimeFromAnyThread()->needsIncrementalBarrier()) - return; - - JS::Zone *zone = newScript->function()->zoneFromAnyThread(); - if (zone->needsIncrementalBarrier()) - newScript->trace(zone->barrierTracer()); -} - -} } /* namespace js::types */ - -inline js::types::TypeScript * -JSScript::types() -{ - maybeSweepTypes(nullptr); - return types_; -} - -inline bool -JSScript::ensureHasTypes(JSContext *cx) -{ - return types() || makeTypes(cx); -} - -namespace js { - template <> struct GCMethods { @@ -1355,4 +1133,17 @@ struct GCMethods } // namespace js +inline js::types::TypeScript * +JSScript::types() +{ + maybeSweepTypes(nullptr); + return types_; +} + +inline bool +JSScript::ensureHasTypes(JSContext *cx) +{ + return types() || makeTypes(cx); +} + #endif /* jsinferinlines_h */ diff --git a/js/src/jsiter.cpp b/js/src/jsiter.cpp index 6e8bdc3f5dd9..a6632f9a6be2 100644 --- a/js/src/jsiter.cpp +++ b/js/src/jsiter.cpp @@ -483,8 +483,8 @@ static inline PropertyIteratorObject * NewPropertyIteratorObject(JSContext *cx, unsigned flags) { if (flags & JSITER_ENUMERATE) { - RootedObjectGroup group(cx, cx->getNewGroup(&PropertyIteratorObject::class_, - TaggedProto(nullptr))); + RootedObjectGroup group(cx, ObjectGroup::defaultNewGroup(cx, &PropertyIteratorObject::class_, + TaggedProto(nullptr))); if (!group) return nullptr; @@ -580,7 +580,7 @@ VectorToKeyIterator(JSContext *cx, HandleObject obj, unsigned flags, AutoIdVecto if (obj->isSingleton() && !obj->setIteratedSingleton(cx)) return false; - types::MarkObjectGroupFlags(cx, obj, types::OBJECT_FLAG_ITERATED); + types::MarkObjectGroupFlags(cx, obj, OBJECT_FLAG_ITERATED); Rooted iterobj(cx, NewPropertyIteratorObject(cx, flags)); if (!iterobj) @@ -623,7 +623,7 @@ VectorToValueIterator(JSContext *cx, HandleObject obj, unsigned flags, AutoIdVec if (obj->isSingleton() && !obj->setIteratedSingleton(cx)) return false; - types::MarkObjectGroupFlags(cx, obj, types::OBJECT_FLAG_ITERATED); + types::MarkObjectGroupFlags(cx, obj, OBJECT_FLAG_ITERATED); Rooted iterobj(cx, NewPropertyIteratorObject(cx, flags)); if (!iterobj) diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index c38f81f28086..ed759fabac40 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -1059,19 +1059,6 @@ js::DefineProperties(JSContext *cx, HandleObject obj, HandleObject props) return true; } -js::types::ObjectGroup* -JSObject::uninlinedGetGroup(JSContext *cx) -{ - return getGroup(cx); -} - -void -JSObject::uninlinedSetGroup(js::types::ObjectGroup *group) -{ - setGroup(group); -} - - /*** Seal and freeze *****************************************************************************/ static unsigned @@ -1268,7 +1255,7 @@ NewObjectGCKind(const js::Class *clasp) } static inline JSObject * -NewObject(ExclusiveContext *cx, types::ObjectGroup *groupArg, JSObject *parent, gc::AllocKind kind, +NewObject(ExclusiveContext *cx, ObjectGroup *groupArg, JSObject *parent, gc::AllocKind kind, NewObjectKind newKind) { const Class *clasp = groupArg->clasp(); @@ -1367,7 +1354,7 @@ js::NewObjectWithGivenProto(ExclusiveContext *cxArg, const js::Class *clasp, Rooted proto(cxArg, protoArg); RootedObject parent(cxArg, parentArg); - types::ObjectGroup *group = cxArg->getNewGroup(clasp, proto, nullptr); + ObjectGroup *group = ObjectGroup::defaultNewGroup(cxArg, clasp, proto, nullptr); if (!group) return nullptr; @@ -1549,7 +1536,7 @@ js::NewObjectWithClassProtoCommon(ExclusiveContext *cxArg, return nullptr; Rooted taggedProto(cxArg, TaggedProto(proto)); - types::ObjectGroup *group = cxArg->getNewGroup(clasp, taggedProto); + ObjectGroup *group = ObjectGroup::defaultNewGroup(cxArg, clasp, taggedProto); if (!group) return nullptr; @@ -1618,16 +1605,16 @@ js::NewObjectScriptedCall(JSContext *cx, MutableHandleObject pobj) jsbytecode *pc; RootedScript script(cx, cx->currentScript(&pc)); gc::AllocKind allocKind = NewObjectGCKind(&PlainObject::class_); - NewObjectKind newKind = script - ? UseSingletonForInitializer(script, pc, &PlainObject::class_) - : GenericObject; + NewObjectKind newKind = GenericObject; + if (script && ObjectGroup::useSingletonForAllocationSite(script, pc, &PlainObject::class_)) + newKind = SingletonObject; RootedObject obj(cx, NewBuiltinClassInstance(cx, allocKind, newKind)); if (!obj) return false; if (script) { /* Try to specialize the group of the object to the scripted call site. */ - if (!types::SetInitializerObjectGroup(cx, script, pc, obj, newKind)) + if (!ObjectGroup::setAllocationSiteObjectGroup(cx, script, pc, obj, newKind == SingletonObject)) return false; } @@ -1707,8 +1694,8 @@ js::CreateThisForFunctionWithProto(JSContext *cx, HandleObject callee, JSObject RootedObject res(cx); if (proto) { - RootedObjectGroup group(cx, cx->getNewGroup(nullptr, TaggedProto(proto), - &callee->as())); + RootedObjectGroup group(cx, ObjectGroup::defaultNewGroup(cx, nullptr, TaggedProto(proto), + &callee->as())); if (!group) return nullptr; @@ -1719,8 +1706,8 @@ js::CreateThisForFunctionWithProto(JSContext *cx, HandleObject callee, JSObject if (regenerate) { // The script was analyzed successfully and may have changed // the new type table, so refetch the group. - group = cx->getNewGroup(nullptr, TaggedProto(proto), - &callee->as()); + group = ObjectGroup::defaultNewGroup(cx, nullptr, TaggedProto(proto), + &callee->as()); MOZ_ASSERT(group && group->newScript()); } } @@ -1980,9 +1967,9 @@ js::DeepCloneObjectLiteral(JSContext *cx, HandleNativeObject obj, NewObjectKind if (!JSObject::setSingleton(cx, clone)) return nullptr; } else if (obj->is()) { - FixArrayGroup(cx, &clone->as()); + ObjectGroup::fixArrayGroup(cx, &clone->as()); } else { - FixObjectGroup(cx, &clone->as()); + ObjectGroup::fixPlainObjectGroup(cx, &clone->as()); } if (obj->is() && obj->denseElementsAreCopyOnWrite()) { @@ -2190,9 +2177,9 @@ js::XDRObjectLiteral(XDRState *xdr, MutableHandleNativeObject obj) if (!JSObject::setSingleton(cx, obj)) return false; } else if (isArray) { - FixArrayGroup(cx, &obj->as()); + ObjectGroup::fixArrayGroup(cx, &obj->as()); } else { - FixObjectGroup(cx, &obj->as()); + ObjectGroup::fixPlainObjectGroup(cx, &obj->as()); } } @@ -2243,7 +2230,8 @@ js::CloneObjectLiteral(JSContext *cx, HandleObject parent, HandleObject srcObj) JSObject *proto = cx->global()->getOrCreateObjectPrototype(cx); if (!proto) return nullptr; - RootedObjectGroup group(cx, cx->getNewGroup(&PlainObject::class_, TaggedProto(proto))); + RootedObjectGroup group(cx, ObjectGroup::defaultNewGroup(cx, &PlainObject::class_, + TaggedProto(proto))); if (!group) return nullptr; @@ -2748,7 +2736,7 @@ js::SetClassAndProto(JSContext *cx, HandleObject obj, return false; } - ObjectGroup *group = cx->getNewGroup(clasp, proto); + ObjectGroup *group = ObjectGroup::defaultNewGroup(cx, clasp, proto); if (!group) return false; diff --git a/js/src/jsobj.h b/js/src/jsobj.h index 3ddbee62564e..5769ee407d1d 100644 --- a/js/src/jsobj.h +++ b/js/src/jsobj.h @@ -118,7 +118,7 @@ class JSObject : public js::gc::Cell bool *succeeded); // Make a new group to use for a singleton object. - static js::types::ObjectGroup *makeLazyGroup(JSContext *cx, js::HandleObject obj); + static js::ObjectGroup *makeLazyGroup(JSContext *cx, js::HandleObject obj); public: js::Shape * lastProperty() const { @@ -143,12 +143,12 @@ class JSObject : public js::gc::Cell return &getClass()->ops; } - js::types::ObjectGroup *group() const { + js::ObjectGroup *group() const { MOZ_ASSERT(!hasLazyGroup()); return groupRaw(); } - js::types::ObjectGroup *groupRaw() const { + js::ObjectGroup *groupRaw() const { return group_; } @@ -323,9 +323,7 @@ class JSObject : public js::gc::Cell */ static inline bool setSingleton(js::ExclusiveContext *cx, js::HandleObject obj); - // uninlinedGetGroup() is the same as getGroup(), but not inlined. - inline js::types::ObjectGroup* getGroup(JSContext *cx); - js::types::ObjectGroup* uninlinedGetGroup(JSContext *cx); + inline js::ObjectGroup* getGroup(JSContext *cx); const js::HeapPtrObjectGroup &groupFromGC() const { /* Direct field access for use by GC. */ @@ -390,13 +388,7 @@ class JSObject : public js::gc::Cell return lastProperty()->hasObjectFlag(js::BaseShape::IMMUTABLE_PROTOTYPE); } - // uninlinedSetGroup() is the same as setGroup(), but not inlined. - inline void setGroup(js::types::ObjectGroup *group); - void uninlinedSetGroup(js::types::ObjectGroup *group); - -#ifdef DEBUG - bool hasNewGroup(const js::Class *clasp, js::types::ObjectGroup *group); -#endif + inline void setGroup(js::ObjectGroup *group); /* * Mark an object that has been iterated over and is a singleton. We need diff --git a/js/src/jsobjinlines.h b/js/src/jsobjinlines.h index ba8de8a14879..7f15db094dff 100644 --- a/js/src/jsobjinlines.h +++ b/js/src/jsobjinlines.h @@ -75,8 +75,8 @@ JSObject::setSingleton(js::ExclusiveContext *cx, js::HandleObject obj) { MOZ_ASSERT_IF(cx->isJSContext(), !IsInsideNursery(obj)); - js::types::ObjectGroup *group = cx->getLazySingletonGroup(obj->getClass(), - obj->getTaggedProto()); + js::ObjectGroup *group = js::ObjectGroup::lazySingletonGroup(cx, obj->getClass(), + obj->getTaggedProto()); if (!group) return false; @@ -84,7 +84,7 @@ JSObject::setSingleton(js::ExclusiveContext *cx, js::HandleObject obj) return true; } -inline js::types::ObjectGroup* +inline js::ObjectGroup* JSObject::getGroup(JSContext *cx) { MOZ_ASSERT(cx->compartment() == compartment()); @@ -98,7 +98,7 @@ JSObject::getGroup(JSContext *cx) } inline void -JSObject::setGroup(js::types::ObjectGroup *group) +JSObject::setGroup(js::ObjectGroup *group) { MOZ_ASSERT(group); MOZ_ASSERT(!isSingleton()); diff --git a/js/src/jsscript.h b/js/src/jsscript.h index 72ae17a582b1..166afd92407a 100644 --- a/js/src/jsscript.h +++ b/js/src/jsscript.h @@ -875,13 +875,6 @@ class JSScript : public js::gc::TenuredCell * Reset if the script's JIT code is forcibly * discarded. */ -#ifdef DEBUG - // Unique identifier within the compartment for this script, used for - // printing analysis information. - uint32_t id_; - uint32_t idpad; -#endif - // 16-bit fields. uint16_t version; /* JS version under which script was compiled */ @@ -1459,12 +1452,6 @@ class JSScript : public js::gc::TenuredCell /* Return whether this script was compiled for 'eval' */ bool isForEval() { return isCachedEval() || isActiveEval(); } -#ifdef DEBUG - unsigned id(); -#else - unsigned id() { return 0; } -#endif - /* Ensure the script has a TypeScript. */ inline bool ensureHasTypes(JSContext *cx); diff --git a/js/src/jsstr.cpp b/js/src/jsstr.cpp index 908e40623ac9..4d11745d25df 100644 --- a/js/src/jsstr.cpp +++ b/js/src/jsstr.cpp @@ -3785,7 +3785,7 @@ js::str_split(JSContext *cx, unsigned argc, Value *vp) if (!str) return false; - RootedObjectGroup group(cx, GetCallerInitGroup(cx, JSProto_Array)); + RootedObjectGroup group(cx, ObjectGroup::callingAllocationSiteGroup(cx, JSProto_Array)); if (!group) return false; AddTypePropertyId(cx, group, JSID_VOID, Type::StringType()); diff --git a/js/src/moz.build b/js/src/moz.build index 239c858519b9..93330b7028e2 100644 --- a/js/src/moz.build +++ b/js/src/moz.build @@ -253,6 +253,7 @@ UNIFIED_SOURCES += [ 'vm/MemoryMetrics.cpp', 'vm/Monitor.cpp', 'vm/NativeObject.cpp', + 'vm/ObjectGroup.cpp', 'vm/PIC.cpp', 'vm/Probes.cpp', 'vm/ProxyObject.cpp', diff --git a/js/src/vm/ArgumentsObject.cpp b/js/src/vm/ArgumentsObject.cpp index f78218907a90..1d9ff6c822a3 100644 --- a/js/src/vm/ArgumentsObject.cpp +++ b/js/src/vm/ArgumentsObject.cpp @@ -167,7 +167,7 @@ ArgumentsObject::create(JSContext *cx, HandleScript script, HandleFunction calle bool strict = callee->strict(); const Class *clasp = strict ? &StrictArgumentsObject::class_ : &NormalArgumentsObject::class_; - RootedObjectGroup group(cx, cx->getNewGroup(clasp, TaggedProto(proto.get()))); + RootedObjectGroup group(cx, ObjectGroup::defaultNewGroup(cx, clasp, TaggedProto(proto.get()))); if (!group) return nullptr; diff --git a/js/src/vm/ArrayBufferObject.cpp b/js/src/vm/ArrayBufferObject.cpp index cb57b746ed77..9befbec20bec 100644 --- a/js/src/vm/ArrayBufferObject.cpp +++ b/js/src/vm/ArrayBufferObject.cpp @@ -523,7 +523,7 @@ ArrayBufferObject::neuter(JSContext *cx, Handle buffer, // flag change will be observed. if (!cx->global()->getGroup(cx)) CrashAtUnhandlableOOM("ArrayBufferObject::neuter"); - types::MarkObjectGroupFlags(cx, cx->global(), types::OBJECT_FLAG_TYPED_OBJECT_NEUTERED); + types::MarkObjectGroupFlags(cx, cx->global(), OBJECT_FLAG_TYPED_OBJECT_NEUTERED); cx->compartment()->neuteredTypedObjects = 1; } diff --git a/js/src/vm/ArrayObject-inl.h b/js/src/vm/ArrayObject-inl.h index eb2a75a93321..793656fda281 100644 --- a/js/src/vm/ArrayObject-inl.h +++ b/js/src/vm/ArrayObject-inl.h @@ -22,7 +22,7 @@ ArrayObject::setLength(ExclusiveContext *cx, uint32_t length) if (length > INT32_MAX) { /* Track objects with overflowing lengths in type information. */ - types::MarkObjectGroupFlags(cx, this, types::OBJECT_FLAG_LENGTH_OVERFLOW); + types::MarkObjectGroupFlags(cx, this, OBJECT_FLAG_LENGTH_OVERFLOW); } getElementsHeader()->length = length; diff --git a/js/src/vm/HelperThreads.cpp b/js/src/vm/HelperThreads.cpp index a022b33e6579..4b197b25a8a2 100644 --- a/js/src/vm/HelperThreads.cpp +++ b/js/src/vm/HelperThreads.cpp @@ -896,7 +896,7 @@ GlobalHelperThreadState::finishParseTask(JSContext *maybecx, JSRuntime *rt, void !iter.done(); iter.next()) { - types::ObjectGroup *group = iter.get(); + ObjectGroup *group = iter.get(); TaggedProto proto(group->proto()); if (!proto.isObject()) continue; diff --git a/js/src/vm/Interpreter.cpp b/js/src/vm/Interpreter.cpp index ce60266a18aa..e38e9314c624 100644 --- a/js/src/vm/Interpreter.cpp +++ b/js/src/vm/Interpreter.cpp @@ -509,7 +509,7 @@ js::Invoke(JSContext *cx, CallArgs args, MaybeConstruct construct) if (!iter.done() && iter.hasScript()) { JSScript *script = iter.script(); jsbytecode *pc = iter.pc(); - if (UseSingletonForNewObject(cx, script, pc)) + if (ObjectGroup::useSingletonForNewObject(cx, script, pc)) state.setCreateSingleton(); } } @@ -2564,7 +2564,7 @@ CASE(JSOP_FUNCALL) } InitialFrameFlags initial = construct ? INITIAL_CONSTRUCT : INITIAL_NONE; - bool createSingleton = UseSingletonForNewObject(cx, script, REGS.pc); + bool createSingleton = ObjectGroup::useSingletonForNewObject(cx, script, REGS.pc); TypeMonitorCall(cx, args, construct); @@ -3086,17 +3086,22 @@ CASE(JSOP_NEWINIT) MOZ_ASSERT(i == JSProto_Array || i == JSProto_Object); RootedObject &obj = rootObject0; - NewObjectKind newKind; + NewObjectKind newKind = GenericObject; if (i == JSProto_Array) { - newKind = UseSingletonForInitializer(script, REGS.pc, &ArrayObject::class_); + if (ObjectGroup::useSingletonForAllocationSite(script, REGS.pc, &ArrayObject::class_)) + newKind = SingletonObject; obj = NewDenseEmptyArray(cx, nullptr, newKind); } else { gc::AllocKind allocKind = GuessObjectGCKind(0); - newKind = UseSingletonForInitializer(script, REGS.pc, &PlainObject::class_); + if (ObjectGroup::useSingletonForAllocationSite(script, REGS.pc, &PlainObject::class_)) + newKind = SingletonObject; obj = NewBuiltinClassInstance(cx, allocKind, newKind); } - if (!obj || !SetInitializerObjectGroup(cx, script, REGS.pc, obj, newKind)) + if (!obj || !ObjectGroup::setAllocationSiteObjectGroup(cx, script, REGS.pc, obj, + newKind == SingletonObject)) + { goto error; + } PUSH_OBJECT(*obj); } @@ -3106,10 +3111,15 @@ CASE(JSOP_NEWARRAY) { unsigned count = GET_UINT24(REGS.pc); RootedObject &obj = rootObject0; - NewObjectKind newKind = UseSingletonForInitializer(script, REGS.pc, &ArrayObject::class_); + NewObjectKind newKind = GenericObject; + if (ObjectGroup::useSingletonForAllocationSite(script, REGS.pc, &ArrayObject::class_)) + newKind = SingletonObject; obj = NewDenseFullyAllocatedArray(cx, count, nullptr, newKind); - if (!obj || !SetInitializerObjectGroup(cx, script, REGS.pc, obj, newKind)) + if (!obj || !ObjectGroup::setAllocationSiteObjectGroup(cx, script, REGS.pc, obj, + newKind == SingletonObject)) + { goto error; + } PUSH_OBJECT(*obj); } @@ -3118,7 +3128,7 @@ END_CASE(JSOP_NEWARRAY) CASE(JSOP_NEWARRAY_COPYONWRITE) { RootedObject &baseobj = rootObject0; - baseobj = types::GetOrFixupCopyOnWriteObject(cx, script, REGS.pc); + baseobj = ObjectGroup::getOrFixupCopyOnWriteObject(cx, script, REGS.pc); if (!baseobj) goto error; @@ -3137,10 +3147,15 @@ CASE(JSOP_NEWOBJECT) baseobj = script->getObject(REGS.pc); RootedObject &obj = rootObject1; - NewObjectKind newKind = UseSingletonForInitializer(script, REGS.pc, baseobj->getClass()); + NewObjectKind newKind = GenericObject; + if (ObjectGroup::useSingletonForAllocationSite(script, REGS.pc, baseobj->getClass())) + newKind = SingletonObject; obj = CopyInitializerObject(cx, baseobj.as(), newKind); - if (!obj || !SetInitializerObjectGroup(cx, script, REGS.pc, obj, newKind)) + if (!obj || !ObjectGroup::setAllocationSiteObjectGroup(cx, script, REGS.pc, obj, + newKind == SingletonObject)) + { goto error; + } PUSH_OBJECT(*obj); } @@ -3965,7 +3980,7 @@ js::RunOnceScriptPrologue(JSContext *cx, HandleScript script) return false; types::MarkObjectGroupFlags(cx, script->functionNonDelazifying(), - types::OBJECT_FLAG_RUNONCE_INVALIDATED); + OBJECT_FLAG_RUNONCE_INVALIDATED); return true; } diff --git a/js/src/vm/JSONParser.cpp b/js/src/vm/JSONParser.cpp index ccf5808a2ca6..a8e892f382d2 100644 --- a/js/src/vm/JSONParser.cpp +++ b/js/src/vm/JSONParser.cpp @@ -581,12 +581,12 @@ JSObject * JSONParserBase::createFinishedObject(PropertyVector &properties) { /* - * Look for an existing cached type and shape for objects with this set of + * Look for an existing cached group and shape for objects with this set of * properties. */ { - JSObject *obj = cx->compartment()->types.newTypedObject(cx, properties.begin(), - properties.length()); + JSObject *obj = ObjectGroup::newPlainObject(cx, properties.begin(), + properties.length()); if (obj) return obj; } @@ -611,11 +611,11 @@ JSONParserBase::createFinishedObject(PropertyVector &properties) } /* - * Try to assign a new type to the object with type information for its + * Try to assign a new group to the object with type information for its * properties, and update the initializer object group cache with this * object's final shape. */ - cx->compartment()->types.fixObjectGroup(cx, obj); + ObjectGroup::fixPlainObjectGroup(cx, obj); return obj; } @@ -645,8 +645,8 @@ JSONParserBase::finishArray(MutableHandleValue vp, ElementVector &elements) if (!obj) return false; - /* Try to assign a new type to the array according to its elements. */ - cx->compartment()->types.fixArrayGroup(cx, obj); + /* Try to assign a new group to the array according to its elements. */ + ObjectGroup::fixArrayGroup(cx, obj); vp.setObject(*obj); if (!freeElements.append(&elements)) diff --git a/js/src/vm/MemoryMetrics.cpp b/js/src/vm/MemoryMetrics.cpp index f93d49bb24e9..450c47d9fbb8 100644 --- a/js/src/vm/MemoryMetrics.cpp +++ b/js/src/vm/MemoryMetrics.cpp @@ -550,7 +550,7 @@ StatsCellCallback(JSRuntime *rt, void *data, void *thing, JSGCTraceKind traceKin } case JSTRACE_OBJECT_GROUP: { - types::ObjectGroup *group = static_cast(thing); + ObjectGroup *group = static_cast(thing); zStats->objectGroupsGCHeap += thingSize; zStats->objectGroupsMallocHeap += group->sizeOfExcludingThis(rtStats->mallocSizeOf_); break; diff --git a/js/src/vm/NativeObject-inl.h b/js/src/vm/NativeObject-inl.h index 0146d2375416..4652d213011f 100644 --- a/js/src/vm/NativeObject-inl.h +++ b/js/src/vm/NativeObject-inl.h @@ -99,7 +99,7 @@ NativeObject::initDenseElementWithType(ExclusiveContext *cx, uint32_t index, inline void NativeObject::setDenseElementHole(ExclusiveContext *cx, uint32_t index) { - types::MarkObjectGroupFlags(cx, this, types::OBJECT_FLAG_NON_PACKED); + types::MarkObjectGroupFlags(cx, this, OBJECT_FLAG_NON_PACKED); setDenseElement(index, MagicValue(JS_ELEMENTS_HOLE)); } @@ -108,8 +108,8 @@ NativeObject::removeDenseElementForSparseIndex(ExclusiveContext *cx, HandleNativeObject obj, uint32_t index) { types::MarkObjectGroupFlags(cx, obj, - types::OBJECT_FLAG_NON_PACKED | - types::OBJECT_FLAG_SPARSE_INDEXES); + OBJECT_FLAG_NON_PACKED | + OBJECT_FLAG_SPARSE_INDEXES); if (obj->containsDenseElement(index)) obj->setDenseElement(index, MagicValue(JS_ELEMENTS_HOLE)); } @@ -124,7 +124,7 @@ inline void NativeObject::markDenseElementsNotPacked(ExclusiveContext *cx) { MOZ_ASSERT(isNative()); - MarkObjectGroupFlags(cx, this, types::OBJECT_FLAG_NON_PACKED); + types::MarkObjectGroupFlags(cx, this, OBJECT_FLAG_NON_PACKED); } inline void diff --git a/js/src/vm/ObjectGroup.cpp b/js/src/vm/ObjectGroup.cpp new file mode 100644 index 000000000000..974cb6ebd156 --- /dev/null +++ b/js/src/vm/ObjectGroup.cpp @@ -0,0 +1,1558 @@ +/* -*- 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 "vm/ObjectGroup.h" + +#include "jshashutil.h" +#include "jsobj.h" + +#include "gc/StoreBuffer.h" +#include "gc/Zone.h" +#include "vm/ArrayObject.h" +#include "vm/UnboxedObject.h" + +#include "jsgcinlines.h" +#include "jsinferinlines.h" +#include "jsobjinlines.h" + +using namespace js; +using namespace js::types; + +using mozilla::PodZero; + +///////////////////////////////////////////////////////////////////// +// ObjectGroup +///////////////////////////////////////////////////////////////////// + +ObjectGroup::ObjectGroup(const Class *clasp, TaggedProto proto, ObjectGroupFlags initialFlags) +{ + PodZero(this); + + /* Inner objects may not appear on prototype chains. */ + MOZ_ASSERT_IF(proto.isObject(), !proto.toObject()->getClass()->ext.outerObject); + + this->clasp_ = clasp; + this->proto_ = proto.raw(); + this->flags_ = initialFlags; + + setGeneration(zone()->types.generation); +} + +void +ObjectGroup::finalize(FreeOp *fop) +{ + fop->delete_(newScriptDontCheckGeneration()); + fop->delete_(maybeUnboxedLayoutDontCheckGeneration()); +} + +void +ObjectGroup::setProto(JSContext *cx, TaggedProto proto) +{ + MOZ_ASSERT(singleton()); + + if (proto.isObject() && IsInsideNursery(proto.toObject())) + addFlags(OBJECT_FLAG_NURSERY_PROTO); + + setProtoUnchecked(proto); +} + +size_t +ObjectGroup::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const +{ + size_t n = 0; + if (TypeNewScript *newScript = newScriptDontCheckGeneration()) + n += newScript->sizeOfIncludingThis(mallocSizeOf); + if (UnboxedLayout *layout = maybeUnboxedLayoutDontCheckGeneration()) + n += layout->sizeOfIncludingThis(mallocSizeOf); + return n; +} + +void +ObjectGroup::setAddendum(AddendumKind kind, void *addendum, bool writeBarrier /* = true */) +{ + MOZ_ASSERT(!needsSweep()); + MOZ_ASSERT(kind <= (OBJECT_FLAG_ADDENDUM_MASK >> OBJECT_FLAG_ADDENDUM_SHIFT)); + + if (writeBarrier) { + // Manually trigger barriers if we are clearing a TypeNewScript. Other + // kinds of addendums are immutable. + if (newScript()) + TypeNewScript::writeBarrierPre(newScript()); + else + MOZ_ASSERT(addendumKind() == Addendum_None || addendumKind() == kind); + } + + flags_ &= ~OBJECT_FLAG_ADDENDUM_MASK; + flags_ |= kind << OBJECT_FLAG_ADDENDUM_SHIFT; + addendum_ = addendum; +} + +/* static */ bool +ObjectGroup::useSingletonForClone(JSFunction *fun) +{ + if (!fun->isInterpreted()) + return false; + + if (fun->hasScript() && fun->nonLazyScript()->shouldCloneAtCallsite()) + return true; + + if (fun->isArrow()) + return false; + + if (fun->isSingleton()) + return false; + + /* + * When a function is being used as a wrapper for another function, it + * improves precision greatly to distinguish between different instances of + * the wrapper; otherwise we will conflate much of the information about + * the wrapped functions. + * + * An important example is the Class.create function at the core of the + * Prototype.js library, which looks like: + * + * var Class = { + * create: function() { + * return function() { + * this.initialize.apply(this, arguments); + * } + * } + * }; + * + * Each instance of the innermost function will have a different wrapped + * initialize method. We capture this, along with similar cases, by looking + * for short scripts which use both .apply and arguments. For such scripts, + * whenever creating a new instance of the function we both give that + * instance a singleton type and clone the underlying script. + */ + + uint32_t begin, end; + if (fun->hasScript()) { + if (!fun->nonLazyScript()->usesArgumentsApplyAndThis()) + return false; + begin = fun->nonLazyScript()->sourceStart(); + end = fun->nonLazyScript()->sourceEnd(); + } else { + if (!fun->lazyScript()->usesArgumentsApplyAndThis()) + return false; + begin = fun->lazyScript()->begin(); + end = fun->lazyScript()->end(); + } + + return end - begin <= 100; +} + +/* static */ bool +ObjectGroup::useSingletonForNewObject(JSContext *cx, JSScript *script, jsbytecode *pc) +{ + /* + * Make a heuristic guess at a use of JSOP_NEW that the constructed object + * should have a fresh group. We do this when the NEW is immediately + * followed by a simple assignment to an object's .prototype field. + * This is designed to catch common patterns for subclassing in JS: + * + * function Super() { ... } + * function Sub1() { ... } + * function Sub2() { ... } + * + * Sub1.prototype = new Super(); + * Sub2.prototype = new Super(); + * + * Using distinct groups for the particular prototypes of Sub1 and + * Sub2 lets us continue to distinguish the two subclasses and any extra + * properties added to those prototype objects. + */ + if (script->isGenerator()) + return false; + if (JSOp(*pc) != JSOP_NEW) + return false; + pc += JSOP_NEW_LENGTH; + if (JSOp(*pc) == JSOP_SETPROP) { + if (script->getName(pc) == cx->names().prototype) + return true; + } + return false; +} + +/* static */ bool +ObjectGroup::useSingletonForAllocationSite(JSScript *script, jsbytecode *pc, JSProtoKey key) +{ + // The return value of this method can either be tested like a boolean or + // passed to a NewObject method. + JS_STATIC_ASSERT(GenericObject == 0); + + /* + * Objects created outside loops in global and eval scripts should have + * singleton types. For now this is only done for plain objects and typed + * arrays, but not normal arrays. + */ + + if (script->functionNonDelazifying() && !script->treatAsRunOnce()) + return GenericObject; + + if (key != JSProto_Object && + !(key >= JSProto_Int8Array && key <= JSProto_Uint8ClampedArray) && + !(key >= JSProto_SharedInt8Array && key <= JSProto_SharedUint8ClampedArray)) + { + return GenericObject; + } + + /* + * All loops in the script will have a JSTRY_ITER or JSTRY_LOOP try note + * indicating their boundary. + */ + + if (!script->hasTrynotes()) + return SingletonObject; + + unsigned offset = script->pcToOffset(pc); + + JSTryNote *tn = script->trynotes()->vector; + JSTryNote *tnlimit = tn + script->trynotes()->length; + for (; tn < tnlimit; tn++) { + if (tn->kind != JSTRY_ITER && tn->kind != JSTRY_LOOP) + continue; + + unsigned startOffset = script->mainOffset() + tn->start; + unsigned endOffset = startOffset + tn->length; + + if (offset >= startOffset && offset < endOffset) + return GenericObject; + } + + return SingletonObject; +} + +/* static */ bool +ObjectGroup::useSingletonForAllocationSite(JSScript *script, jsbytecode *pc, const Class *clasp) +{ + return useSingletonForAllocationSite(script, pc, JSCLASS_CACHED_PROTO_KEY(clasp)); +} + +///////////////////////////////////////////////////////////////////// +// JSObject +///////////////////////////////////////////////////////////////////// + +bool +JSObject::shouldSplicePrototype(JSContext *cx) +{ + /* + * During bootstrapping, if inference is enabled we need to make sure not + * to splice a new prototype in for Function.prototype or the global + * object if their __proto__ had previously been set to null, as this + * will change the prototype for all other objects with the same type. + */ + if (getProto() != nullptr) + return false; + return isSingleton(); +} + +bool +JSObject::splicePrototype(JSContext *cx, const Class *clasp, Handle proto) +{ + MOZ_ASSERT(cx->compartment() == compartment()); + + RootedObject self(cx, this); + + /* + * For singleton groups representing only a single JSObject, the proto + * can be rearranged as needed without destroying type information for + * the old or new types. + */ + MOZ_ASSERT(self->isSingleton()); + + // Inner objects may not appear on prototype chains. + MOZ_ASSERT_IF(proto.isObject(), !proto.toObject()->getClass()->ext.outerObject); + + if (proto.isObject() && !proto.toObject()->setDelegate(cx)) + return false; + + // Force type instantiation when splicing lazy group. + RootedObjectGroup group(cx, self->getGroup(cx)); + if (!group) + return false; + RootedObjectGroup protoGroup(cx, nullptr); + if (proto.isObject()) { + protoGroup = proto.toObject()->getGroup(cx); + if (!protoGroup) + return false; + } + + group->setClasp(clasp); + group->setProto(cx, proto); + return true; +} + +/* static */ ObjectGroup * +JSObject::makeLazyGroup(JSContext *cx, HandleObject obj) +{ + MOZ_ASSERT(obj->hasLazyGroup()); + MOZ_ASSERT(cx->compartment() == obj->compartment()); + + /* De-lazification of functions can GC, so we need to do it up here. */ + if (obj->is() && obj->as().isInterpretedLazy()) { + RootedFunction fun(cx, &obj->as()); + if (!fun->getOrCreateScript(cx)) + return nullptr; + } + + // Find flags which need to be specified immediately on the object. + // Don't track whether singletons are packed. + ObjectGroupFlags initialFlags = OBJECT_FLAG_NON_PACKED; + + if (obj->lastProperty()->hasObjectFlag(BaseShape::ITERATED_SINGLETON)) + initialFlags |= OBJECT_FLAG_ITERATED; + + if (obj->isIndexed()) + initialFlags |= OBJECT_FLAG_SPARSE_INDEXES; + + if (obj->is() && obj->as().length() > INT32_MAX) + initialFlags |= OBJECT_FLAG_LENGTH_OVERFLOW; + + Rooted proto(cx, obj->getTaggedProto()); + ObjectGroup *group = ObjectGroupCompartment::makeGroup(cx, obj->getClass(), proto, + initialFlags); + if (!group) + return nullptr; + + AutoEnterAnalysis enter(cx); + + /* Fill in the type according to the state of this object. */ + + group->initSingleton(obj); + + if (obj->is() && obj->as().isInterpreted()) + group->setInterpretedFunction(&obj->as()); + + obj->group_ = group; + + return group; +} + +/* static */ bool +JSObject::setNewGroupUnknown(JSContext *cx, const js::Class *clasp, JS::HandleObject obj) +{ + ObjectGroup::setDefaultNewGroupUnknown(cx, clasp, obj); + return obj->setFlag(cx, BaseShape::NEW_GROUP_UNKNOWN); +} + +///////////////////////////////////////////////////////////////////// +// ObjectGroupCompartment NewTable +///////////////////////////////////////////////////////////////////// + +/* + * Entries for the per-compartment set of groups which are the default + * types to use for some prototype. An optional associated object is used which + * allows multiple groups to be created with the same prototype. The + * associated object may be a function (for types constructed with 'new') or a + * type descriptor (for typed objects). These entries are also used for the set + * of lazy groups in the compartment, which use a null associated object + * (though there are only a few of these per compartment). + */ +struct ObjectGroupCompartment::NewEntry +{ + ReadBarrieredObjectGroup group; + + // Note: This pointer is only used for equality and does not need a read barrier. + JSObject *associated; + + NewEntry(ObjectGroup *group, JSObject *associated) + : group(group), associated(associated) + {} + + struct Lookup { + const Class *clasp; + TaggedProto hashProto; + TaggedProto matchProto; + JSObject *associated; + + Lookup(const Class *clasp, TaggedProto proto, JSObject *associated) + : clasp(clasp), hashProto(proto), matchProto(proto), associated(associated) + {} + + /* + * For use by generational post barriers only. Look up an entry whose + * proto has been moved, but was hashed with the original value. + */ + Lookup(const Class *clasp, TaggedProto hashProto, TaggedProto matchProto, JSObject *associated) + : clasp(clasp), hashProto(hashProto), matchProto(matchProto), associated(associated) + {} + }; + + static inline HashNumber hash(const Lookup &lookup) { + return PointerHasher::hash(lookup.hashProto.raw()) ^ + PointerHasher::hash(lookup.clasp) ^ + PointerHasher::hash(lookup.associated); + } + + static inline bool match(const NewEntry &key, const Lookup &lookup) { + return key.group->proto() == lookup.matchProto && + (!lookup.clasp || key.group->clasp() == lookup.clasp) && + key.associated == lookup.associated; + } + + static void rekey(NewEntry &k, const NewEntry& newKey) { k = newKey; } +}; + +// This class is used to add a post barrier on a NewTable entry, as the key is +// calculated from a prototype object which may be moved by generational GC. +class ObjectGroupCompartment::NewTableRef : public gc::BufferableRef +{ + NewTable *table; + const Class *clasp; + JSObject *proto; + JSObject *associated; + + public: + NewTableRef(NewTable *table, const Class *clasp, JSObject *proto, JSObject *associated) + : table(table), clasp(clasp), proto(proto), associated(associated) + {} + + void mark(JSTracer *trc) { + JSObject *prior = proto; + trc->setTracingLocation(&*prior); + Mark(trc, &proto, "newObjectGroups set prototype"); + if (prior == proto) + return; + + NewTable::Ptr p = table->lookup(NewTable::Lookup(clasp, TaggedProto(prior), + TaggedProto(proto), + associated)); + if (!p) + return; + + table->rekeyAs(NewTable::Lookup(clasp, TaggedProto(prior), TaggedProto(proto), associated), + NewTable::Lookup(clasp, TaggedProto(proto), associated), *p); + } +}; + +/* static */ void +ObjectGroupCompartment::newTablePostBarrier(ExclusiveContext *cx, NewTable *table, + const Class *clasp, TaggedProto proto, + JSObject *associated) +{ + MOZ_ASSERT_IF(associated, !IsInsideNursery(associated)); + + if (!proto.isObject()) + return; + + if (!cx->isJSContext()) { + MOZ_ASSERT(!IsInsideNursery(proto.toObject())); + return; + } + + if (IsInsideNursery(proto.toObject())) { + gc::StoreBuffer &sb = cx->asJSContext()->runtime()->gc.storeBuffer; + sb.putGeneric(NewTableRef(table, clasp, proto.toObject(), associated)); + } +} + +/* static */ ObjectGroup * +ObjectGroup::defaultNewGroup(ExclusiveContext *cx, const Class *clasp, + TaggedProto proto, JSObject *associated) +{ + MOZ_ASSERT_IF(associated, proto.isObject()); + MOZ_ASSERT_IF(associated, associated->is() || associated->is()); + MOZ_ASSERT_IF(proto.isObject(), cx->isInsideCurrentCompartment(proto.toObject())); + + // A null lookup clasp is used for 'new' groups with an associated + // function. The group starts out as a plain object but might mutate into an + // unboxed plain object. + MOZ_ASSERT(!clasp == (associated && associated->is())); + + ObjectGroupCompartment::NewTable *&table = cx->compartment()->objectGroups.defaultNewTable; + + if (!table) { + table = cx->new_(); + if (!table || !table->init()) { + js_delete(table); + table = nullptr; + return nullptr; + } + } + + if (associated && associated->is()) { + MOZ_ASSERT(!clasp); + + // Canonicalize new functions to use the original one associated with its script. + JSFunction *fun = &associated->as(); + if (fun->hasScript()) + associated = fun->nonLazyScript()->functionNonDelazifying(); + else if (fun->isInterpretedLazy() && !fun->isSelfHostedBuiltin()) + associated = fun->lazyScript()->functionNonDelazifying(); + else + associated = nullptr; + + // If we have previously cleared the 'new' script information for this + // function, don't try to construct another one. + if (associated && associated->wasNewScriptCleared()) + associated = nullptr; + + if (!associated) + clasp = &PlainObject::class_; + } + + ObjectGroupCompartment::NewTable::AddPtr p = + table->lookupForAdd(ObjectGroupCompartment::NewEntry::Lookup(clasp, proto, associated)); + if (p) { + ObjectGroup *group = p->group; + MOZ_ASSERT_IF(clasp, group->clasp() == clasp); + MOZ_ASSERT_IF(!clasp, group->clasp() == &PlainObject::class_ || + group->clasp() == &UnboxedPlainObject::class_); + MOZ_ASSERT(group->proto() == proto); + return group; + } + + AutoEnterAnalysis enter(cx); + + if (proto.isObject() && !proto.toObject()->setDelegate(cx)) + return nullptr; + + ObjectGroupFlags initialFlags = 0; + if (!proto.isObject() || proto.toObject()->isNewGroupUnknown()) + initialFlags = OBJECT_FLAG_DYNAMIC_MASK; + + Rooted protoRoot(cx, proto); + ObjectGroup *group = ObjectGroupCompartment::makeGroup(cx, clasp ? clasp : &PlainObject::class_, + protoRoot, initialFlags); + if (!group) + return nullptr; + + if (!table->add(p, ObjectGroupCompartment::NewEntry(group, associated))) + return nullptr; + + ObjectGroupCompartment::newTablePostBarrier(cx, table, clasp, proto, associated); + + if (proto.isObject()) { + RootedObject obj(cx, proto.toObject()); + + if (associated) { + if (associated->is()) + TypeNewScript::make(cx->asJSContext(), group, &associated->as()); + else + group->setTypeDescr(&associated->as()); + } + + /* + * Some builtin objects have slotful native properties baked in at + * creation via the Shape::{insert,get}initialShape mechanism. Since + * these properties are never explicitly defined on new objects, update + * the type information for them here. + */ + + const JSAtomState &names = cx->names(); + + if (obj->is()) { + AddTypePropertyId(cx, group, NameToId(names.source), Type::StringType()); + AddTypePropertyId(cx, group, NameToId(names.global), Type::BooleanType()); + AddTypePropertyId(cx, group, NameToId(names.ignoreCase), Type::BooleanType()); + AddTypePropertyId(cx, group, NameToId(names.multiline), Type::BooleanType()); + AddTypePropertyId(cx, group, NameToId(names.sticky), Type::BooleanType()); + AddTypePropertyId(cx, group, NameToId(names.lastIndex), Type::Int32Type()); + } + + if (obj->is()) + AddTypePropertyId(cx, group, NameToId(names.length), Type::Int32Type()); + + if (obj->is()) { + AddTypePropertyId(cx, group, NameToId(names.fileName), Type::StringType()); + AddTypePropertyId(cx, group, NameToId(names.lineNumber), Type::Int32Type()); + AddTypePropertyId(cx, group, NameToId(names.columnNumber), Type::Int32Type()); + AddTypePropertyId(cx, group, NameToId(names.stack), Type::StringType()); + } + } + + return group; +} + +/* static */ ObjectGroup * +ObjectGroup::lazySingletonGroup(ExclusiveContext *cx, const Class *clasp, TaggedProto proto) +{ + MOZ_ASSERT_IF(proto.isObject(), cx->compartment() == proto.toObject()->compartment()); + + ObjectGroupCompartment::NewTable *&table = cx->compartment()->objectGroups.lazyTable; + + if (!table) { + table = cx->new_(); + if (!table || !table->init()) { + js_delete(table); + table = nullptr; + return nullptr; + } + } + + ObjectGroupCompartment::NewTable::AddPtr p = + table->lookupForAdd(ObjectGroupCompartment::NewEntry::Lookup(clasp, proto, nullptr)); + if (p) { + ObjectGroup *group = p->group; + MOZ_ASSERT(group->lazy()); + + return group; + } + + AutoEnterAnalysis enter(cx); + + Rooted protoRoot(cx, proto); + ObjectGroup *group = ObjectGroupCompartment::makeGroup(cx, clasp, protoRoot); + if (!group) + return nullptr; + + if (!table->add(p, ObjectGroupCompartment::NewEntry(group, nullptr))) + return nullptr; + + ObjectGroupCompartment::newTablePostBarrier(cx, table, clasp, proto, nullptr); + + group->initSingleton((JSObject *) ObjectGroup::LAZY_SINGLETON); + MOZ_ASSERT(group->singleton(), "created group must be a proper singleton"); + + return group; +} + +/* static */ void +ObjectGroup::setDefaultNewGroupUnknown(JSContext *cx, const Class *clasp, HandleObject obj) +{ + // If the object already has a new group, mark that group as unknown. + ObjectGroupCompartment::NewTable *table = cx->compartment()->objectGroups.defaultNewTable; + if (table) { + Rooted taggedProto(cx, TaggedProto(obj)); + ObjectGroupCompartment::NewTable::Ptr p = + table->lookup(ObjectGroupCompartment::NewEntry::Lookup(clasp, taggedProto, nullptr)); + if (p) + MarkObjectGroupUnknownProperties(cx, p->group); + } +} + +#ifdef DEBUG +/* static */ bool +ObjectGroup::hasDefaultNewGroup(JSObject *proto, const Class *clasp, ObjectGroup *group) +{ + ObjectGroupCompartment::NewTable *table = proto->compartment()->objectGroups.defaultNewTable; + + if (table) { + ObjectGroupCompartment::NewTable::Ptr p = + table->lookup(ObjectGroupCompartment::NewEntry::Lookup(clasp, TaggedProto(proto), nullptr)); + return p && p->group == group; + } + return false; +} +#endif /* DEBUG */ + +inline const Class * +GetClassForProtoKey(JSProtoKey key) +{ + switch (key) { + case JSProto_Null: + case JSProto_Object: + return &PlainObject::class_; + case JSProto_Array: + return &ArrayObject::class_; + + case JSProto_Number: + return &NumberObject::class_; + case JSProto_Boolean: + return &BooleanObject::class_; + case JSProto_String: + return &StringObject::class_; + case JSProto_Symbol: + return &SymbolObject::class_; + case JSProto_RegExp: + return &RegExpObject::class_; + + case JSProto_Int8Array: + case JSProto_Uint8Array: + case JSProto_Int16Array: + case JSProto_Uint16Array: + case JSProto_Int32Array: + case JSProto_Uint32Array: + case JSProto_Float32Array: + case JSProto_Float64Array: + case JSProto_Uint8ClampedArray: + return &TypedArrayObject::classes[key - JSProto_Int8Array]; + + case JSProto_SharedInt8Array: + case JSProto_SharedUint8Array: + case JSProto_SharedInt16Array: + case JSProto_SharedUint16Array: + case JSProto_SharedInt32Array: + case JSProto_SharedUint32Array: + case JSProto_SharedFloat32Array: + case JSProto_SharedFloat64Array: + case JSProto_SharedUint8ClampedArray: + return &SharedTypedArrayObject::classes[key - JSProto_SharedInt8Array]; + + case JSProto_ArrayBuffer: + return &ArrayBufferObject::class_; + + case JSProto_SharedArrayBuffer: + return &SharedArrayBufferObject::class_; + + case JSProto_DataView: + return &DataViewObject::class_; + + default: + MOZ_CRASH("Bad proto key"); + } +} + +/* static */ ObjectGroup * +ObjectGroup::defaultNewGroup(JSContext *cx, JSProtoKey key) +{ + RootedObject proto(cx); + if (key != JSProto_Null && !GetBuiltinPrototype(cx, key, &proto)) + return nullptr; + return defaultNewGroup(cx, GetClassForProtoKey(key), TaggedProto(proto.get())); +} + +///////////////////////////////////////////////////////////////////// +// ObjectGroupCompartment ArrayObjectTable +///////////////////////////////////////////////////////////////////// + +struct ObjectGroupCompartment::ArrayObjectKey : public DefaultHasher +{ + Type type; + JSObject *proto; + + ArrayObjectKey() + : type(Type::UndefinedType()), proto(nullptr) + {} + + ArrayObjectKey(Type type, JSObject *proto) + : type(type), proto(proto) + {} + + static inline uint32_t hash(const ArrayObjectKey &v) { + return (uint32_t) (v.type.raw() ^ ((uint32_t)(size_t)v.proto >> 2)); + } + + static inline bool match(const ArrayObjectKey &v1, const ArrayObjectKey &v2) { + return v1.type == v2.type && v1.proto == v2.proto; + } + + bool operator==(const ArrayObjectKey& other) { + return type == other.type && proto == other.proto; + } + + bool operator!=(const ArrayObjectKey& other) { + return !(*this == other); + } +}; + +static inline bool +NumberTypes(Type a, Type b) +{ + return (a.isPrimitive(JSVAL_TYPE_INT32) || a.isPrimitive(JSVAL_TYPE_DOUBLE)) + && (b.isPrimitive(JSVAL_TYPE_INT32) || b.isPrimitive(JSVAL_TYPE_DOUBLE)); +} + +/* + * As for GetValueType, but requires object types to be non-singletons with + * their default prototype. These are the only values that should appear in + * arrays and objects whose type can be fixed. + */ +static inline Type +GetValueTypeForTable(const Value &v) +{ + Type type = GetValueType(v); + MOZ_ASSERT(!type.isSingleton()); + return type; +} + +/* static */ void +ObjectGroup::fixArrayGroup(ExclusiveContext *cx, ArrayObject *obj) +{ + AutoEnterAnalysis enter(cx); + + /* + * If the array is of homogenous type, pick a group which will be + * shared with all other singleton/JSON arrays of the same type. + * If the array is heterogenous, keep the existing group, which has + * unknown properties. + */ + + unsigned len = obj->getDenseInitializedLength(); + if (len == 0) + return; + + Type type = GetValueTypeForTable(obj->getDenseElement(0)); + + for (unsigned i = 1; i < len; i++) { + Type ntype = GetValueTypeForTable(obj->getDenseElement(i)); + if (ntype != type) { + if (NumberTypes(type, ntype)) + type = Type::DoubleType(); + else + return; + } + } + + setGroupToHomogenousArray(cx, obj, type); +} + +/* static */ void +ObjectGroup::fixRestArgumentsGroup(ExclusiveContext *cx, ArrayObject *obj) +{ + AutoEnterAnalysis enter(cx); + + // Tracking element types for rest argument arrays is not worth it, but we + // still want it to be known that it's a dense array. + setGroupToHomogenousArray(cx, obj, Type::UnknownType()); +} + +/* static */ void +ObjectGroup::setGroupToHomogenousArray(ExclusiveContext *cx, JSObject *obj, Type elementType) +{ + MOZ_ASSERT(cx->zone()->types.activeAnalysis); + + ObjectGroupCompartment::ArrayObjectTable *&table = + cx->compartment()->objectGroups.arrayObjectTable; + + if (!table) { + table = cx->new_(); + if (!table || !table->init()) { + js_delete(table); + table = nullptr; + return; + } + } + + ObjectGroupCompartment::ArrayObjectKey key(elementType, obj->getProto()); + DependentAddPtr p(cx, *table, key); + if (p) { + obj->setGroup(p->value()); + } else { + // Make a new group to use for future arrays with the same elements. + RootedObject objProto(cx, obj->getProto()); + Rooted taggedProto(cx, TaggedProto(objProto)); + ObjectGroup *group = ObjectGroupCompartment::makeGroup(cx, &ArrayObject::class_, taggedProto); + if (!group) + return; + obj->setGroup(group); + + AddTypePropertyId(cx, group, JSID_VOID, elementType); + + key.proto = objProto; + (void) p.add(cx, *table, key, group); + } +} + +///////////////////////////////////////////////////////////////////// +// ObjectGroupCompartment PlainObjectTable +///////////////////////////////////////////////////////////////////// + +/* + * N.B. We could also use the initial shape of the object (before its type is + * fixed) as the key in the object table, but since all references in the table + * are weak the hash entries would usually be collected on GC even if objects + * with the new type/shape are still live. + */ +struct ObjectGroupCompartment::PlainObjectKey +{ + jsid *properties; + uint32_t nproperties; + uint32_t nfixed; + + struct Lookup { + IdValuePair *properties; + uint32_t nproperties; + uint32_t nfixed; + + Lookup(IdValuePair *properties, uint32_t nproperties, uint32_t nfixed) + : properties(properties), nproperties(nproperties), nfixed(nfixed) + {} + }; + + static inline HashNumber hash(const Lookup &lookup) { + return (HashNumber) (JSID_BITS(lookup.properties[lookup.nproperties - 1].id) ^ + lookup.nproperties ^ + lookup.nfixed); + } + + static inline bool match(const PlainObjectKey &v, const Lookup &lookup) { + if (lookup.nproperties != v.nproperties || lookup.nfixed != v.nfixed) + return false; + for (size_t i = 0; i < lookup.nproperties; i++) { + if (lookup.properties[i].id != v.properties[i]) + return false; + } + return true; + } +}; + +struct ObjectGroupCompartment::PlainObjectEntry +{ + ReadBarrieredObjectGroup group; + ReadBarrieredShape shape; + Type *types; +}; + +/* static */ void +ObjectGroupCompartment::updatePlainObjectEntryTypes(ExclusiveContext *cx, PlainObjectEntry &entry, + IdValuePair *properties, size_t nproperties) +{ + if (entry.group->unknownProperties()) + return; + for (size_t i = 0; i < nproperties; i++) { + Type type = entry.types[i]; + Type ntype = GetValueTypeForTable(properties[i].value); + if (ntype == type) + continue; + if (ntype.isPrimitive(JSVAL_TYPE_INT32) && + type.isPrimitive(JSVAL_TYPE_DOUBLE)) + { + /* The property types already reflect 'int32'. */ + } else { + if (ntype.isPrimitive(JSVAL_TYPE_DOUBLE) && + type.isPrimitive(JSVAL_TYPE_INT32)) + { + /* Include 'double' in the property types to avoid the update below later. */ + entry.types[i] = Type::DoubleType(); + } + AddTypePropertyId(cx, entry.group, IdToTypeId(properties[i].id), ntype); + } + } +} + +/* static */ void +ObjectGroup::fixPlainObjectGroup(ExclusiveContext *cx, PlainObject *obj) +{ + AutoEnterAnalysis enter(cx); + + ObjectGroupCompartment::PlainObjectTable *&table = + cx->compartment()->objectGroups.plainObjectTable; + + if (!table) { + table = cx->new_(); + if (!table || !table->init()) { + js_delete(table); + table = nullptr; + return; + } + } + + /* + * Use the same group for all singleton/JSON objects with the same + * base shape, i.e. the same fields written in the same order. + * + * Exclude some objects we can't readily associate common types for based on their + * shape. Objects with metadata are excluded so that the metadata does not need to + * be included in the table lookup (the metadata object might be in the nursery). + */ + if (obj->slotSpan() == 0 || obj->inDictionaryMode() || !obj->hasEmptyElements() || obj->getMetadata()) + return; + + Vector properties(cx); + if (!properties.resize(obj->slotSpan())) + return; + + Shape *shape = obj->lastProperty(); + while (!shape->isEmptyShape()) { + IdValuePair &entry = properties[shape->slot()]; + entry.id = shape->propid(); + entry.value = obj->getSlot(shape->slot()); + shape = shape->previous(); + } + + ObjectGroupCompartment::PlainObjectKey::Lookup lookup(properties.begin(), properties.length(), + obj->numFixedSlots()); + ObjectGroupCompartment::PlainObjectTable::AddPtr p = table->lookupForAdd(lookup); + + if (p) { + MOZ_ASSERT(obj->getProto() == p->value().group->proto().toObject()); + MOZ_ASSERT(obj->lastProperty() == p->value().shape); + + ObjectGroupCompartment::updatePlainObjectEntryTypes(cx, p->value(), + properties.begin(), + properties.length()); + obj->setGroup(p->value().group); + return; + } + + /* Make a new type to use for the object and similar future ones. */ + Rooted objProto(cx, obj->getTaggedProto()); + ObjectGroup *group = ObjectGroupCompartment::makeGroup(cx, &PlainObject::class_, objProto); + if (!group || !group->addDefiniteProperties(cx, obj->lastProperty())) + return; + + if (obj->isIndexed()) + group->setFlags(cx, OBJECT_FLAG_SPARSE_INDEXES); + + ScopedJSFreePtr ids(group->zone()->pod_calloc(properties.length())); + if (!ids) + return; + + ScopedJSFreePtr types(group->zone()->pod_calloc(properties.length())); + if (!types) + return; + + for (size_t i = 0; i < properties.length(); i++) { + ids[i] = properties[i].id; + types[i] = GetValueTypeForTable(obj->getSlot(i)); + AddTypePropertyId(cx, group, IdToTypeId(ids[i]), types[i]); + } + + ObjectGroupCompartment::PlainObjectKey key; + key.properties = ids; + key.nproperties = properties.length(); + key.nfixed = obj->numFixedSlots(); + MOZ_ASSERT(ObjectGroupCompartment::PlainObjectKey::match(key, lookup)); + + ObjectGroupCompartment::PlainObjectEntry entry; + entry.group.set(group); + entry.shape.set(obj->lastProperty()); + entry.types = types; + + obj->setGroup(group); + + p = table->lookupForAdd(lookup); + if (table->add(p, key, entry)) { + ids.forget(); + types.forget(); + } +} + +/* static */ PlainObject * +ObjectGroup::newPlainObject(JSContext *cx, IdValuePair *properties, size_t nproperties) +{ + AutoEnterAnalysis enter(cx); + + ObjectGroupCompartment::PlainObjectTable *table = + cx->compartment()->objectGroups.plainObjectTable; + + if (!table) + return nullptr; + + /* + * Use the object group table to allocate an object with the specified + * properties, filling in its final group and shape and failing if no table + * entry could be found for the properties. + */ + + /* + * Filter out a few cases where we don't want to use the object group table. + * Note that if the properties contain any duplicates or dense indexes, + * the lookup below will fail as such arrays of properties cannot be stored + * in the object group table --- fixObjectGroup populates the table with + * properties read off its input object, which cannot be duplicates, and + * ignores objects with dense indexes. + */ + if (!nproperties || nproperties >= PropertyTree::MAX_HEIGHT) + return nullptr; + + gc::AllocKind allocKind = gc::GetGCObjectKind(nproperties); + size_t nfixed = gc::GetGCKindSlots(allocKind, &PlainObject::class_); + + ObjectGroupCompartment::PlainObjectKey::Lookup lookup(properties, nproperties, nfixed); + ObjectGroupCompartment::PlainObjectTable::Ptr p = table->lookupForAdd(lookup); + + if (!p) + return nullptr; + + RootedPlainObject obj(cx, NewBuiltinClassInstance(cx, allocKind)); + if (!obj) { + cx->clearPendingException(); + return nullptr; + } + MOZ_ASSERT(obj->getProto() == p->value().group->proto().toObject()); + + RootedShape shape(cx, p->value().shape); + if (!NativeObject::setLastProperty(cx, obj, shape)) { + cx->clearPendingException(); + return nullptr; + } + + ObjectGroupCompartment::updatePlainObjectEntryTypes(cx, p->value(), properties, nproperties); + + for (size_t i = 0; i < nproperties; i++) + obj->setSlot(i, properties[i].value); + + obj->setGroup(p->value().group); + return obj; +} + +///////////////////////////////////////////////////////////////////// +// ObjectGroupCompartment AllocationSiteTable +///////////////////////////////////////////////////////////////////// + +struct ObjectGroupCompartment::AllocationSiteKey : public DefaultHasher { + JSScript *script; + + uint32_t offset : 24; + JSProtoKey kind : 8; + + static const uint32_t OFFSET_LIMIT = (1 << 23); + + AllocationSiteKey() { mozilla::PodZero(this); } + + static inline uint32_t hash(AllocationSiteKey key) { + return uint32_t(size_t(key.script->offsetToPC(key.offset)) ^ key.kind); + } + + static inline bool match(const AllocationSiteKey &a, const AllocationSiteKey &b) { + return a.script == b.script && a.offset == b.offset && a.kind == b.kind; + } +}; + +/* static */ ObjectGroup * +ObjectGroup::allocationSiteGroup(JSContext *cx, JSScript *script, jsbytecode *pc, + JSProtoKey kind) +{ + MOZ_ASSERT(!useSingletonForAllocationSite(script, pc, kind)); + + uint32_t offset = script->pcToOffset(pc); + + if (offset >= ObjectGroupCompartment::AllocationSiteKey::OFFSET_LIMIT) + return defaultNewGroup(cx, kind); + + ObjectGroupCompartment::AllocationSiteKey key; + key.script = script; + key.offset = offset; + key.kind = kind; + + ObjectGroupCompartment::AllocationSiteTable *&table = + cx->compartment()->objectGroups.allocationSiteTable; + + if (!table) { + table = cx->new_(); + if (!table || !table->init()) { + js_delete(table); + table = nullptr; + return nullptr; + } + } + + ObjectGroupCompartment::AllocationSiteTable::AddPtr p = table->lookupForAdd(key); + if (p) + return p->value(); + + AutoEnterAnalysis enter(cx); + + RootedObject proto(cx); + if (kind != JSProto_Null && !GetBuiltinPrototype(cx, kind, &proto)) + return nullptr; + + Rooted tagged(cx, TaggedProto(proto)); + ObjectGroup *res = ObjectGroupCompartment::makeGroup(cx, GetClassForProtoKey(kind), tagged, + OBJECT_FLAG_FROM_ALLOCATION_SITE); + if (!res) + return nullptr; + + if (JSOp(*pc) == JSOP_NEWOBJECT) { + // This object is always constructed the same way and will not be + // observed by other code before all properties have been added. Mark + // all the properties as definite properties of the object. + JSObject *baseobj = script->getObject(GET_UINT32_INDEX(pc)); + if (!res->addDefiniteProperties(cx, baseobj->lastProperty())) + return nullptr; + } + + if (!table->add(p, key, res)) + return nullptr; + + return res; +} + +/* static */ ObjectGroup * +ObjectGroup::callingAllocationSiteGroup(JSContext *cx, JSProtoKey key) +{ + jsbytecode *pc; + RootedScript script(cx, cx->currentScript(&pc)); + if (script) + return allocationSiteGroup(cx, script, pc, key); + return defaultNewGroup(cx, key); +} + +/* static */ bool +ObjectGroup::setAllocationSiteObjectGroup(JSContext *cx, + HandleScript script, jsbytecode *pc, + HandleObject obj, bool singleton) +{ + JSProtoKey key = JSCLASS_CACHED_PROTO_KEY(obj->getClass()); + MOZ_ASSERT(key != JSProto_Null); + MOZ_ASSERT(singleton == useSingletonForAllocationSite(script, pc, key)); + + if (singleton) { + MOZ_ASSERT(obj->isSingleton()); + + /* + * Inference does not account for types of run-once initializer + * objects, as these may not be created until after the script + * has been analyzed. + */ + TypeScript::Monitor(cx, script, pc, ObjectValue(*obj)); + } else { + ObjectGroup *group = allocationSiteGroup(cx, script, pc, key); + if (!group) + return false; + obj->setGroup(group); + } + + return true; +} + +/* static */ ArrayObject * +ObjectGroup::getOrFixupCopyOnWriteObject(JSContext *cx, HandleScript script, jsbytecode *pc) +{ + // Make sure that the template object for script/pc has a type indicating + // that the object and its copies have copy on write elements. + RootedArrayObject obj(cx, &script->getObject(GET_UINT32_INDEX(pc))->as()); + MOZ_ASSERT(obj->denseElementsAreCopyOnWrite()); + + if (obj->group()->fromAllocationSite()) { + MOZ_ASSERT(obj->group()->hasAnyFlags(OBJECT_FLAG_COPY_ON_WRITE)); + return obj; + } + + RootedObjectGroup group(cx, allocationSiteGroup(cx, script, pc, JSProto_Array)); + if (!group) + return nullptr; + + group->addFlags(OBJECT_FLAG_COPY_ON_WRITE); + + // Update type information in the initializer object group. + MOZ_ASSERT(obj->slotSpan() == 0); + for (size_t i = 0; i < obj->getDenseInitializedLength(); i++) { + const Value &v = obj->getDenseElement(i); + AddTypePropertyId(cx, group, JSID_VOID, v); + } + + obj->setGroup(group); + return obj; +} + +/* static */ ArrayObject * +ObjectGroup::getCopyOnWriteObject(JSScript *script, jsbytecode *pc) +{ + // getOrFixupCopyOnWriteObject should already have been called for + // script/pc, ensuring that the template object has a group with the + // COPY_ON_WRITE flag. We don't assert this here, due to a corner case + // where this property doesn't hold. See jsop_newarray_copyonwrite in + // IonBuilder. + ArrayObject *obj = &script->getObject(GET_UINT32_INDEX(pc))->as(); + MOZ_ASSERT(obj->denseElementsAreCopyOnWrite()); + + return obj; +} + +/* static */ bool +ObjectGroup::findAllocationSiteForType(JSContext *cx, Type type, + JSScript **script, uint32_t *offset) +{ + *script = nullptr; + *offset = 0; + + if (type.isUnknown() || type.isAnyObject() || !type.isGroup()) + return false; + ObjectGroup *obj = type.group(); + + const ObjectGroupCompartment::AllocationSiteTable *table = + cx->compartment()->objectGroups.allocationSiteTable; + + if (!table) + return false; + + for (ObjectGroupCompartment::AllocationSiteTable::Range r = table->all(); + !r.empty(); + r.popFront()) + { + if (obj == r.front().value()) { + *script = r.front().key().script; + *offset = r.front().key().offset; + return true; + } + } + + return false; +} + +///////////////////////////////////////////////////////////////////// +// ObjectGroupCompartment +///////////////////////////////////////////////////////////////////// + +ObjectGroupCompartment::ObjectGroupCompartment() +{ + PodZero(this); +} + +ObjectGroupCompartment::~ObjectGroupCompartment() +{ + js_delete(defaultNewTable); + js_delete(lazyTable); + js_delete(arrayObjectTable); + js_delete(plainObjectTable); + js_delete(allocationSiteTable); +} + +void +ObjectGroupCompartment::removeDefaultNewGroup(const Class *clasp, TaggedProto proto, + JSObject *associated) +{ + NewTable::Ptr p = defaultNewTable->lookup(NewEntry::Lookup(clasp, proto, associated)); + MOZ_ASSERT(p); + + defaultNewTable->remove(p); +} + +void +ObjectGroupCompartment::replaceDefaultNewGroup(const Class *clasp, TaggedProto proto, + JSObject *associated, ObjectGroup *group) +{ + NewEntry::Lookup lookup(clasp, proto, associated); + + NewTable::Ptr p = defaultNewTable->lookup(lookup); + MOZ_ASSERT(p); + defaultNewTable->remove(p); + defaultNewTable->putNew(lookup, NewEntry(group, associated)); +} + +/* static */ +ObjectGroup * +ObjectGroupCompartment::makeGroup(ExclusiveContext *cx, const Class *clasp, + Handle proto, + ObjectGroupFlags initialFlags /* = 0 */) +{ + MOZ_ASSERT_IF(proto.isObject(), cx->isInsideCurrentCompartment(proto.toObject())); + + if (cx->isJSContext()) { + if (proto.isObject() && IsInsideNursery(proto.toObject())) + initialFlags |= OBJECT_FLAG_NURSERY_PROTO; + } + + ObjectGroup *group = NewObjectGroup(cx); + if (!group) + return nullptr; + new(group) ObjectGroup(clasp, proto, initialFlags); + + return group; +} + +void +ObjectGroupCompartment::addSizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf, + size_t *allocationSiteTables, + size_t *arrayObjectGroupTables, + size_t *plainObjectGroupTables, + size_t *compartmentTables) +{ + if (allocationSiteTable) + *allocationSiteTables += allocationSiteTable->sizeOfIncludingThis(mallocSizeOf); + + if (arrayObjectTable) + *arrayObjectGroupTables += arrayObjectTable->sizeOfIncludingThis(mallocSizeOf); + + if (plainObjectTable) { + *plainObjectGroupTables += plainObjectTable->sizeOfIncludingThis(mallocSizeOf); + + for (PlainObjectTable::Enum e(*plainObjectTable); + !e.empty(); + e.popFront()) + { + const PlainObjectKey &key = e.front().key(); + const PlainObjectEntry &value = e.front().value(); + + /* key.ids and values.types have the same length. */ + *plainObjectGroupTables += mallocSizeOf(key.properties) + mallocSizeOf(value.types); + } + } + + if (defaultNewTable) + *compartmentTables += defaultNewTable->sizeOfIncludingThis(mallocSizeOf); + + if (lazyTable) + *compartmentTables += lazyTable->sizeOfIncludingThis(mallocSizeOf); +} + +void +ObjectGroupCompartment::clearTables() +{ + if (allocationSiteTable && allocationSiteTable->initialized()) + allocationSiteTable->clear(); + if (arrayObjectTable && arrayObjectTable->initialized()) + arrayObjectTable->clear(); + if (plainObjectTable && plainObjectTable->initialized()) + plainObjectTable->clear(); + if (defaultNewTable && defaultNewTable->initialized()) + defaultNewTable->clear(); + if (lazyTable && lazyTable->initialized()) + lazyTable->clear(); +} + +void +ObjectGroupCompartment::sweep(FreeOp *fop) +{ + /* + * Iterate through the array/object group tables and remove all entries + * referencing collected data. These tables only hold weak references. + */ + + if (arrayObjectTable) { + for (ArrayObjectTable::Enum e(*arrayObjectTable); !e.empty(); e.popFront()) { + ArrayObjectKey key = e.front().key(); + MOZ_ASSERT(key.type.isUnknown() || !key.type.isSingleton()); + + bool remove = false; + if (!key.type.isUnknown() && key.type.isGroup()) { + ObjectGroup *group = key.type.groupNoBarrier(); + if (IsObjectGroupAboutToBeFinalizedFromAnyThread(&group)) + remove = true; + else + key.type = Type::ObjectType(group); + } + if (key.proto && key.proto != TaggedProto::LazyProto && + IsObjectAboutToBeFinalizedFromAnyThread(&key.proto)) + { + remove = true; + } + if (IsObjectGroupAboutToBeFinalizedFromAnyThread(e.front().value().unsafeGet())) + remove = true; + + if (remove) + e.removeFront(); + else if (key != e.front().key()) + e.rekeyFront(key); + } + } + + if (plainObjectTable) { + for (PlainObjectTable::Enum e(*plainObjectTable); !e.empty(); e.popFront()) { + const PlainObjectKey &key = e.front().key(); + PlainObjectEntry &entry = e.front().value(); + + bool remove = false; + if (IsObjectGroupAboutToBeFinalizedFromAnyThread(entry.group.unsafeGet())) + remove = true; + if (IsShapeAboutToBeFinalizedFromAnyThread(entry.shape.unsafeGet())) + remove = true; + for (unsigned i = 0; !remove && i < key.nproperties; i++) { + if (JSID_IS_STRING(key.properties[i])) { + JSString *str = JSID_TO_STRING(key.properties[i]); + if (IsStringAboutToBeFinalizedFromAnyThread(&str)) + remove = true; + MOZ_ASSERT(AtomToId((JSAtom *)str) == key.properties[i]); + } else if (JSID_IS_SYMBOL(key.properties[i])) { + JS::Symbol *sym = JSID_TO_SYMBOL(key.properties[i]); + if (IsSymbolAboutToBeFinalizedFromAnyThread(&sym)) + remove = true; + } + + MOZ_ASSERT(!entry.types[i].isSingleton()); + ObjectGroup *group = nullptr; + if (entry.types[i].isGroup()) { + group = entry.types[i].groupNoBarrier(); + if (IsObjectGroupAboutToBeFinalizedFromAnyThread(&group)) + remove = true; + else if (group != entry.types[i].groupNoBarrier()) + entry.types[i] = Type::ObjectType(group); + } + } + + if (remove) { + js_free(key.properties); + js_free(entry.types); + e.removeFront(); + } + } + } + + if (allocationSiteTable) { + for (AllocationSiteTable::Enum e(*allocationSiteTable); !e.empty(); e.popFront()) { + AllocationSiteKey key = e.front().key(); + bool keyDying = IsScriptAboutToBeFinalizedFromAnyThread(&key.script); + bool valDying = IsObjectGroupAboutToBeFinalizedFromAnyThread(e.front().value().unsafeGet()); + if (keyDying || valDying) + e.removeFront(); + else if (key.script != e.front().key().script) + e.rekeyFront(key); + } + } + + sweepNewTable(defaultNewTable); + sweepNewTable(lazyTable); +} + +void +ObjectGroupCompartment::sweepNewTable(NewTable *table) +{ + if (table && table->initialized()) { + for (NewTable::Enum e(*table); !e.empty(); e.popFront()) { + NewEntry entry = e.front(); + if (IsObjectGroupAboutToBeFinalizedFromAnyThread(entry.group.unsafeGet()) || + (entry.associated && IsObjectAboutToBeFinalizedFromAnyThread(&entry.associated))) + { + e.removeFront(); + } else { + /* Any rekeying necessary is handled by fixupNewObjectGroupTable() below. */ + MOZ_ASSERT(entry.group.unbarrieredGet() == e.front().group.unbarrieredGet()); + MOZ_ASSERT(entry.associated == e.front().associated); + } + } + } +} + +void +ObjectGroupCompartment::fixupNewTableAfterMovingGC(NewTable *table) +{ + /* + * Each entry's hash depends on the object's prototype and we can't tell + * whether that has been moved or not in sweepNewObjectGroupTable(). + */ + if (table && table->initialized()) { + for (NewTable::Enum e(*table); !e.empty(); e.popFront()) { + NewEntry entry = e.front(); + bool needRekey = false; + if (IsForwarded(entry.group.get())) { + entry.group.set(Forwarded(entry.group.get())); + needRekey = true; + } + TaggedProto proto = entry.group->proto(); + if (proto.isObject() && IsForwarded(proto.toObject())) { + proto = TaggedProto(Forwarded(proto.toObject())); + needRekey = true; + } + if (entry.associated && IsForwarded(entry.associated)) { + entry.associated = Forwarded(entry.associated); + needRekey = true; + } + if (needRekey) { + const Class *clasp = entry.group->clasp(); + if (entry.associated && entry.associated->is()) + clasp = nullptr; + NewEntry::Lookup lookup(clasp, proto, entry.associated); + e.rekeyFront(lookup, entry); + } + } + } +} + +#ifdef JSGC_HASH_TABLE_CHECKS + +void +ObjectGroupCompartment::checkNewTableAfterMovingGC(NewTable *table) +{ + /* + * Assert that nothing points into the nursery or needs to be relocated, and + * that the hash table entries are discoverable. + */ + if (!table || !table->initialized()) + return; + + for (NewTable::Enum e(*table); !e.empty(); e.popFront()) { + NewEntry entry = e.front(); + CheckGCThingAfterMovingGC(entry.group.get()); + TaggedProto proto = entry.group->proto(); + if (proto.isObject()) + CheckGCThingAfterMovingGC(proto.toObject()); + CheckGCThingAfterMovingGC(entry.associated); + + const Class *clasp = entry.group->clasp(); + if (entry.associated && entry.associated->is()) + clasp = nullptr; + + NewEntry::Lookup lookup(clasp, proto, entry.associated); + NewTable::Ptr ptr = table->lookup(lookup); + MOZ_ASSERT(ptr.found() && &*ptr == &e.front()); + } +} + +#endif // JSGC_HASH_TABLE_CHECKS diff --git a/js/src/vm/ObjectGroup.h b/js/src/vm/ObjectGroup.h new file mode 100644 index 000000000000..511010344557 --- /dev/null +++ b/js/src/vm/ObjectGroup.h @@ -0,0 +1,686 @@ +/* -*- 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 vm_ObjectGroup_h +#define vm_ObjectGroup_h + +#include "jsbytecode.h" +#include "jsfriendapi.h" + +#include "ds/IdValuePair.h" +#include "gc/Barrier.h" + +namespace js { + +class TypeDescr; +class UnboxedLayout; + +namespace types { + +class Type; +class TypeNewScript; +class HeapTypeSet; +struct Property; +class AutoClearTypeInferenceStateOnOOM; +class CompilerConstraintList; + +} // namespace types + +// Information about an object prototype, which can be either a particular +// object, null, or a lazily generated object. The latter is only used by +// certain kinds of proxies. +class TaggedProto +{ + public: + static JSObject * const LazyProto; + + TaggedProto() : proto(nullptr) {} + explicit TaggedProto(JSObject *proto) : proto(proto) {} + + uintptr_t toWord() const { return uintptr_t(proto); } + + bool isLazy() const { + return proto == LazyProto; + } + bool isObject() const { + /* Skip nullptr and LazyProto. */ + return uintptr_t(proto) > uintptr_t(TaggedProto::LazyProto); + } + JSObject *toObject() const { + MOZ_ASSERT(isObject()); + return proto; + } + JSObject *toObjectOrNull() const { + MOZ_ASSERT(!proto || isObject()); + return proto; + } + JSObject *raw() const { return proto; } + + bool operator ==(const TaggedProto &other) { return proto == other.proto; } + bool operator !=(const TaggedProto &other) { return proto != other.proto; } + + private: + JSObject *proto; +}; + +template <> +struct RootKind +{ + static ThingRootKind rootKind() { return THING_ROOT_OBJECT; } +}; + +template <> struct GCMethods +{ + static TaggedProto initial() { return TaggedProto(); } + static bool poisoned(const TaggedProto &v) { return IsPoisonedPtr(v.raw()); } +}; + +template <> struct GCMethods +{ + static TaggedProto initial() { return TaggedProto(); } + static bool poisoned(const TaggedProto &v) { return IsPoisonedPtr(v.raw()); } +}; + +template +class TaggedProtoOperations +{ + const TaggedProto *value() const { + return static_cast(this)->extract(); + } + + public: + uintptr_t toWord() const { return value()->toWord(); } + inline bool isLazy() const { return value()->isLazy(); } + inline bool isObject() const { return value()->isObject(); } + inline JSObject *toObject() const { return value()->toObject(); } + inline JSObject *toObjectOrNull() const { return value()->toObjectOrNull(); } + JSObject *raw() const { return value()->raw(); } +}; + +template <> +class HandleBase : public TaggedProtoOperations > +{ + friend class TaggedProtoOperations >; + const TaggedProto * extract() const { + return static_cast*>(this)->address(); + } +}; + +template <> +class RootedBase : public TaggedProtoOperations > +{ + friend class TaggedProtoOperations >; + const TaggedProto *extract() const { + return static_cast *>(this)->address(); + } +}; + +/* Flags and other state stored in ObjectGroupFlags */ +enum : uint32_t { + /* Whether this group is associated with some allocation site. */ + OBJECT_FLAG_FROM_ALLOCATION_SITE = 0x1, + + /* + * If set, the object's prototype might be in the nursery and can't be + * used during Ion compilation (which may be occurring off thread). + */ + OBJECT_FLAG_NURSERY_PROTO = 0x2, + + /* Mask/shift for the number of properties in propertySet */ + OBJECT_FLAG_PROPERTY_COUNT_MASK = 0xfff8, + OBJECT_FLAG_PROPERTY_COUNT_SHIFT = 3, + OBJECT_FLAG_PROPERTY_COUNT_LIMIT = + OBJECT_FLAG_PROPERTY_COUNT_MASK >> OBJECT_FLAG_PROPERTY_COUNT_SHIFT, + + /* Whether any objects this represents may have sparse indexes. */ + OBJECT_FLAG_SPARSE_INDEXES = 0x00010000, + + /* Whether any objects this represents may not have packed dense elements. */ + OBJECT_FLAG_NON_PACKED = 0x00020000, + + /* + * Whether any objects this represents may be arrays whose length does not + * fit in an int32. + */ + OBJECT_FLAG_LENGTH_OVERFLOW = 0x00040000, + + /* Whether any objects have been iterated over. */ + OBJECT_FLAG_ITERATED = 0x00080000, + + /* For a global object, whether flags were set on the RegExpStatics. */ + OBJECT_FLAG_REGEXP_FLAGS_SET = 0x00100000, + + /* + * For the function on a run-once script, whether the function has actually + * run multiple times. + */ + OBJECT_FLAG_RUNONCE_INVALIDATED = 0x00200000, + + /* + * For a global object, whether any array buffers in this compartment with + * typed object views have been neutered. + */ + OBJECT_FLAG_TYPED_OBJECT_NEUTERED = 0x00400000, + + /* + * Whether objects with this type should be allocated directly in the + * tenured heap. + */ + OBJECT_FLAG_PRE_TENURE = 0x00800000, + + /* Whether objects with this type might have copy on write elements. */ + OBJECT_FLAG_COPY_ON_WRITE = 0x01000000, + + /* Whether this type has had its 'new' script cleared in the past. */ + OBJECT_FLAG_NEW_SCRIPT_CLEARED = 0x02000000, + + /* + * Whether all properties of this object are considered unknown. + * If set, all other flags in DYNAMIC_MASK will also be set. + */ + OBJECT_FLAG_UNKNOWN_PROPERTIES = 0x04000000, + + /* Flags which indicate dynamic properties of represented objects. */ + OBJECT_FLAG_DYNAMIC_MASK = 0x07ff0000, + + // Mask/shift for the kind of addendum attached to this group. + OBJECT_FLAG_ADDENDUM_MASK = 0x38000000, + OBJECT_FLAG_ADDENDUM_SHIFT = 27, + + // Mask/shift for this group's generation. If out of sync with the + // TypeZone's generation, this group hasn't been swept yet. + OBJECT_FLAG_GENERATION_MASK = 0x40000000, + OBJECT_FLAG_GENERATION_SHIFT = 30, +}; +typedef uint32_t ObjectGroupFlags; + +/* + * Lazy object groups overview. + * + * Object groups which represent at most one JS object are constructed lazily. + * These include groups for native functions, standard classes, scripted + * functions defined at the top level of global/eval scripts, and in some + * other cases. Typical web workloads often create many windows (and many + * copies of standard natives) and many scripts, with comparatively few + * non-singleton groups. + * + * We can recover the type information for the object from examining it, + * so don't normally track the possible types of its properties as it is + * updated. Property type sets for the object are only constructed when an + * analyzed script attaches constraints to it: the script is querying that + * property off the object or another which delegates to it, and the analysis + * information is sensitive to changes in the property's type. Future changes + * to the property (whether those uncovered by analysis or those occurring + * in the VM) will treat these properties like those of any other object group. + */ + +/* Type information about an object accessed by a script. */ +class ObjectGroup : public gc::TenuredCell +{ + /* Class shared by objects in this group. */ + const Class *clasp_; + + /* Prototype shared by objects in this group. */ + HeapPtrObject proto_; + + /* + * Whether there is a singleton JS object with this group. That JS object + * must appear in type sets instead of this; we include the back reference + * here to allow reverting the JS object to a lazy group. + */ + HeapPtrObject singleton_; + + public: + + const Class *clasp() const { + return clasp_; + } + + void setClasp(const Class *clasp) { + clasp_ = clasp; + } + + TaggedProto proto() const { + return TaggedProto(proto_); + } + + JSObject *singleton() const { + return singleton_; + } + + // For use during marking, don't call otherwise. + HeapPtrObject &protoRaw() { return proto_; } + HeapPtrObject &singletonRaw() { return singleton_; } + + void setProto(JSContext *cx, TaggedProto proto); + void setProtoUnchecked(TaggedProto proto) { + proto_ = proto.raw(); + } + + void initSingleton(JSObject *singleton) { + singleton_ = singleton; + } + + /* + * Value held by singleton if this is a standin group for a singleton JS + * object whose group has not been constructed yet. + */ + static const size_t LAZY_SINGLETON = 1; + bool lazy() const { return singleton() == (JSObject *) LAZY_SINGLETON; } + + private: + /* Flags for this group. */ + ObjectGroupFlags flags_; + + // Kinds of addendums which can be attached to ObjectGroups. + enum AddendumKind { + Addendum_None, + + // When used by interpreted function, the addendum stores the + // canonical JSFunction object. + Addendum_InterpretedFunction, + + // When used by the 'new' group when constructing an interpreted + // function, the addendum stores a TypeNewScript. + Addendum_NewScript, + + // When objects in this group have an unboxed representation, the + // addendum stores an UnboxedLayout (which might have a TypeNewScript + // as well, if the group is also constructed using 'new'). + Addendum_UnboxedLayout, + + // When used by typed objects, the addendum stores a TypeDescr. + Addendum_TypeDescr + }; + + // If non-null, holds additional information about this object, whose + // format is indicated by the object's addendum kind. + void *addendum_; + + void setAddendum(AddendumKind kind, void *addendum, bool writeBarrier = true); + + AddendumKind addendumKind() const { + return (AddendumKind) + ((flags_ & OBJECT_FLAG_ADDENDUM_MASK) >> OBJECT_FLAG_ADDENDUM_SHIFT); + } + + types::TypeNewScript *newScriptDontCheckGeneration() const { + if (addendumKind() == Addendum_NewScript) + return reinterpret_cast(addendum_); + return nullptr; + } + + UnboxedLayout *maybeUnboxedLayoutDontCheckGeneration() const { + if (addendumKind() == Addendum_UnboxedLayout) + return reinterpret_cast(addendum_); + return nullptr; + } + + types::TypeNewScript *anyNewScript(); + void detachNewScript(bool writeBarrier); + + public: + + ObjectGroupFlags flags() { + maybeSweep(nullptr); + return flags_; + } + + void addFlags(ObjectGroupFlags flags) { + maybeSweep(nullptr); + flags_ |= flags; + } + + void clearFlags(ObjectGroupFlags flags) { + maybeSweep(nullptr); + flags_ &= ~flags; + } + + types::TypeNewScript *newScript() { + maybeSweep(nullptr); + return newScriptDontCheckGeneration(); + } + + void setNewScript(types::TypeNewScript *newScript) { + setAddendum(Addendum_NewScript, newScript); + } + + UnboxedLayout *maybeUnboxedLayout() { + maybeSweep(nullptr); + return maybeUnboxedLayoutDontCheckGeneration(); + } + + UnboxedLayout &unboxedLayout() { + MOZ_ASSERT(addendumKind() == Addendum_UnboxedLayout); + return *maybeUnboxedLayout(); + } + + void setUnboxedLayout(UnboxedLayout *layout) { + setAddendum(Addendum_UnboxedLayout, layout); + } + + TypeDescr *maybeTypeDescr() { + // Note: there is no need to sweep when accessing the type descriptor + // of an object, as it is strongly held and immutable. + if (addendumKind() == Addendum_TypeDescr) + return reinterpret_cast(addendum_); + return nullptr; + } + + TypeDescr &typeDescr() { + MOZ_ASSERT(addendumKind() == Addendum_TypeDescr); + return *maybeTypeDescr(); + } + + void setTypeDescr(TypeDescr *descr) { + setAddendum(Addendum_TypeDescr, descr); + } + + JSFunction *maybeInterpretedFunction() { + // Note: as with type descriptors, there is no need to sweep when + // accessing the interpreted function associated with an object. + if (addendumKind() == Addendum_InterpretedFunction) + return reinterpret_cast(addendum_); + return nullptr; + } + + void setInterpretedFunction(JSFunction *fun) { + setAddendum(Addendum_InterpretedFunction, fun); + } + + private: + // Properties of this object. This may contain JSID_VOID, representing the + // types of all integer indexes of the object, and/or JSID_EMPTY, holding + // constraints listening to changes to the object's state. + // + // See types::Property for more detail about the types represented here. + types::Property **propertySet; + public: + + inline ObjectGroup(const Class *clasp, TaggedProto proto, ObjectGroupFlags initialFlags); + + inline bool hasAnyFlags(ObjectGroupFlags flags) { + MOZ_ASSERT((flags & OBJECT_FLAG_DYNAMIC_MASK) == flags); + return !!(this->flags() & flags); + } + bool hasAllFlags(ObjectGroupFlags flags) { + MOZ_ASSERT((flags & OBJECT_FLAG_DYNAMIC_MASK) == flags); + return (this->flags() & flags) == flags; + } + + bool unknownProperties() { + MOZ_ASSERT_IF(flags() & OBJECT_FLAG_UNKNOWN_PROPERTIES, + hasAllFlags(OBJECT_FLAG_DYNAMIC_MASK)); + return !!(flags() & OBJECT_FLAG_UNKNOWN_PROPERTIES); + } + + bool shouldPreTenure() { + return hasAnyFlags(OBJECT_FLAG_PRE_TENURE) && !unknownProperties(); + } + + bool hasTenuredProto() { + return !(flags() & OBJECT_FLAG_NURSERY_PROTO); + } + + gc::InitialHeap initialHeap(types::CompilerConstraintList *constraints); + + bool canPreTenure() { + return !unknownProperties(); + } + + bool fromAllocationSite() { + return flags() & OBJECT_FLAG_FROM_ALLOCATION_SITE; + } + + void setShouldPreTenure(ExclusiveContext *cx) { + MOZ_ASSERT(canPreTenure()); + setFlags(cx, OBJECT_FLAG_PRE_TENURE); + } + + /* + * Get or create a property of this object. Only call this for properties which + * a script accesses explicitly. + */ + inline types::HeapTypeSet *getProperty(ExclusiveContext *cx, jsid id); + + /* Get a property only if it already exists. */ + inline types::HeapTypeSet *maybeGetProperty(jsid id); + + inline unsigned getPropertyCount(); + inline types::Property *getProperty(unsigned i); + + /* Helpers */ + + void updateNewPropertyTypes(ExclusiveContext *cx, jsid id, types::HeapTypeSet *types); + bool addDefiniteProperties(ExclusiveContext *cx, Shape *shape); + bool matchDefiniteProperties(HandleObject obj); + void markPropertyNonData(ExclusiveContext *cx, jsid id); + void markPropertyNonWritable(ExclusiveContext *cx, jsid id); + void markStateChange(ExclusiveContext *cx); + void setFlags(ExclusiveContext *cx, ObjectGroupFlags flags); + void markUnknown(ExclusiveContext *cx); + void maybeClearNewScriptOnOOM(); + void clearNewScript(ExclusiveContext *cx); + bool isPropertyNonData(jsid id); + bool isPropertyNonWritable(jsid id); + + void print(); + + inline void clearProperties(); + void maybeSweep(types::AutoClearTypeInferenceStateOnOOM *oom); + + private: +#ifdef DEBUG + bool needsSweep(); +#endif + + uint32_t generation() { + return (flags_ & OBJECT_FLAG_GENERATION_MASK) >> OBJECT_FLAG_GENERATION_SHIFT; + } + + public: + void setGeneration(uint32_t generation) { + MOZ_ASSERT(generation <= (OBJECT_FLAG_GENERATION_MASK >> OBJECT_FLAG_GENERATION_SHIFT)); + flags_ &= ~OBJECT_FLAG_GENERATION_MASK; + flags_ |= generation << OBJECT_FLAG_GENERATION_SHIFT; + } + + size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const; + + void finalize(FreeOp *fop); + void fixupAfterMovingGC() {} + + static inline ThingRootKind rootKind() { return THING_ROOT_OBJECT_GROUP; } + + static inline uint32_t offsetOfClasp() { + return offsetof(ObjectGroup, clasp_); + } + + static inline uint32_t offsetOfProto() { + return offsetof(ObjectGroup, proto_); + } + + static inline uint32_t offsetOfAddendum() { + return offsetof(ObjectGroup, addendum_); + } + + static inline uint32_t offsetOfFlags() { + return offsetof(ObjectGroup, flags_); + } + + private: + inline uint32_t basePropertyCount(); + inline void setBasePropertyCount(uint32_t count); + + static void staticAsserts() { + JS_STATIC_ASSERT(offsetof(ObjectGroup, proto_) == offsetof(js::shadow::ObjectGroup, proto)); + } + + public: + // Whether to make a deep cloned singleton when cloning fun. + static bool useSingletonForClone(JSFunction *fun); + + // Whether to make a singleton when calling 'new' at script/pc. + static bool useSingletonForNewObject(JSContext *cx, JSScript *script, jsbytecode *pc); + + // Whether to make a singleton object at an allocation site. + static bool useSingletonForAllocationSite(JSScript *script, jsbytecode *pc, + JSProtoKey key); + static bool useSingletonForAllocationSite(JSScript *script, jsbytecode *pc, + const Class *clasp); + + // Static accessors for ObjectGroupCompartment NewTable. + + static ObjectGroup *defaultNewGroup(ExclusiveContext *cx, const Class *clasp, + TaggedProto proto, + JSObject *associated = nullptr); + static ObjectGroup *lazySingletonGroup(ExclusiveContext *cx, const Class *clasp, + TaggedProto proto); + + static void setDefaultNewGroupUnknown(JSContext *cx, const js::Class *clasp, JS::HandleObject obj); + +#ifdef DEBUG + static bool hasDefaultNewGroup(JSObject *proto, const Class *clasp, ObjectGroup *group); +#endif + + // Static accessors for ObjectGroupCompartment ArrayObjectTable and PlainObjectTable. + + // Update the group of a freshly created array or plain object according to + // the object's current contents. + static void fixArrayGroup(ExclusiveContext *cx, ArrayObject *obj); + static void fixPlainObjectGroup(ExclusiveContext *cx, PlainObject *obj); + + // Update the group of a freshly created 'rest' arguments object. + static void fixRestArgumentsGroup(ExclusiveContext *cx, ArrayObject *obj); + + static PlainObject *newPlainObject(JSContext *cx, IdValuePair *properties, size_t nproperties); + + // Static accessors for ObjectGroupCompartment AllocationSiteTable. + + // Get a non-singleton group to use for objects created at the specified + // allocation site. + static ObjectGroup *allocationSiteGroup(JSContext *cx, JSScript *script, jsbytecode *pc, + JSProtoKey key); + + // Get a non-singleton group to use for objects created in a JSNative call. + static ObjectGroup *callingAllocationSiteGroup(JSContext *cx, JSProtoKey key); + + // Set the group or singleton-ness of an object created for an allocation site. + static bool + setAllocationSiteObjectGroup(JSContext *cx, HandleScript script, jsbytecode *pc, + HandleObject obj, bool singleton); + + static ArrayObject *getOrFixupCopyOnWriteObject(JSContext *cx, HandleScript script, + jsbytecode *pc); + static ArrayObject *getCopyOnWriteObject(JSScript *script, jsbytecode *pc); + + // Returns false if not found. + static bool findAllocationSiteForType(JSContext *cx, types::Type type, + JSScript **script, uint32_t *offset); + + private: + static ObjectGroup *defaultNewGroup(JSContext *cx, JSProtoKey key); + static void setGroupToHomogenousArray(ExclusiveContext *cx, JSObject *obj, types::Type type); +}; + +// Structure used to manage the groups in a compartment. +class ObjectGroupCompartment +{ + friend class ObjectGroup; + + struct NewEntry; + typedef HashSet NewTable; + class NewTableRef; + + // Set of default 'new' or lazy groups in the compartment. + NewTable *defaultNewTable; + NewTable *lazyTable; + + struct ArrayObjectKey; + typedef HashMap ArrayObjectTable; + + struct PlainObjectKey; + struct PlainObjectEntry; + typedef HashMap PlainObjectTable; + + // Tables for managing groups common to the contents of large script + // singleton objects and JSON objects. These are vanilla ArrayObjects and + // PlainObjects, so we distinguish the groups of different ones by looking + // at the types of their properties. + // + // All singleton/JSON arrays which have the same prototype, are homogenous + // and of the same element type will share a group. All singleton/JSON + // objects which have the same shape and property types will also share a + // group. We don't try to collate arrays or objects with type mismatches. + ArrayObjectTable *arrayObjectTable; + PlainObjectTable *plainObjectTable; + + struct AllocationSiteKey; + typedef HashMap AllocationSiteTable; + + // Table for referencing types of objects keyed to an allocation site. + AllocationSiteTable *allocationSiteTable; + + public: + ObjectGroupCompartment(); + ~ObjectGroupCompartment(); + + void removeDefaultNewGroup(const Class *clasp, TaggedProto proto, JSObject *associated); + void replaceDefaultNewGroup(const Class *clasp, TaggedProto proto, JSObject *associated, + ObjectGroup *group); + + static ObjectGroup *makeGroup(ExclusiveContext *cx, const Class *clasp, + Handle proto, + ObjectGroupFlags initialFlags = 0); + + void addSizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf, + size_t *allocationSiteTables, + size_t *arrayGroupTables, + size_t *plainObjectGroupTables, + size_t *compartmentTables); + + void clearTables(); + + void sweep(FreeOp *fop); + +#ifdef JSGC_HASH_TABLE_CHECKS + void checkTablesAfterMovingGC() { + checkNewTableAfterMovingGC(defaultNewTable); + checkNewTableAfterMovingGC(lazyTable); + } +#endif + + void fixupTablesAfterMovingGC() { + fixupNewTableAfterMovingGC(defaultNewTable); + fixupNewTableAfterMovingGC(lazyTable); + } + + private: +#ifdef JSGC_HASH_TABLE_CHECKS + void checkNewTableAfterMovingGC(NewTable *table); +#endif + + void sweepNewTable(NewTable *table); + void fixupNewTableAfterMovingGC(NewTable *table); + + static void newTablePostBarrier(ExclusiveContext *cx, NewTable *table, + const Class *clasp, TaggedProto proto, JSObject *associated); + static void updatePlainObjectEntryTypes(ExclusiveContext *cx, PlainObjectEntry &entry, + IdValuePair *properties, size_t nproperties); +}; + +} // namespace js + +#endif /* vm_ObjectGroup_h */ diff --git a/js/src/vm/ProxyObject.cpp b/js/src/vm/ProxyObject.cpp index 80c1424110d1..324b5810ef7c 100644 --- a/js/src/vm/ProxyObject.cpp +++ b/js/src/vm/ProxyObject.cpp @@ -66,7 +66,7 @@ ProxyObject::New(JSContext *cx, const BaseProxyHandler *handler, HandleValue pri /* Don't track types of properties of non-DOM and non-singleton proxies. */ if (newKind != SingletonObject && !clasp->isDOMClass()) - MarkObjectGroupUnknownProperties(cx, proxy->group()); + types::MarkObjectGroupUnknownProperties(cx, proxy->group()); return proxy; } diff --git a/js/src/vm/RegExpObject.cpp b/js/src/vm/RegExpObject.cpp index 108d8fc83373..3d6b4a4557d7 100644 --- a/js/src/vm/RegExpObject.cpp +++ b/js/src/vm/RegExpObject.cpp @@ -708,8 +708,7 @@ RegExpCompartment::createMatchResultTemplateObject(JSContext *cx) // Create a new group for the template. Rooted proto(cx, templateObject->getTaggedProto()); - types::ObjectGroup *group = - cx->compartment()->types.newObjectGroup(cx, templateObject->getClass(), proto); + ObjectGroup *group = ObjectGroupCompartment::makeGroup(cx, templateObject->getClass(), proto); if (!group) return matchResultTemplateObject_; // = nullptr templateObject->setGroup(group); diff --git a/js/src/vm/RegExpStatics.cpp b/js/src/vm/RegExpStatics.cpp index e856b4b87ad8..4097fd9eb3af 100644 --- a/js/src/vm/RegExpStatics.cpp +++ b/js/src/vm/RegExpStatics.cpp @@ -76,7 +76,7 @@ RegExpStatics::markFlagsSet(JSContext *cx) // always be performed). MOZ_ASSERT_IF(cx->global()->hasRegExpStatics(), this == cx->global()->getRegExpStatics(cx)); - types::MarkObjectGroupFlags(cx, cx->global(), types::OBJECT_FLAG_REGEXP_FLAGS_SET); + types::MarkObjectGroupFlags(cx, cx->global(), OBJECT_FLAG_REGEXP_FLAGS_SET); } bool diff --git a/js/src/vm/Runtime-inl.h b/js/src/vm/Runtime-inl.h index 1b6d279222d2..ddd850f7b067 100644 --- a/js/src/vm/Runtime-inl.h +++ b/js/src/vm/Runtime-inl.h @@ -52,7 +52,7 @@ NewObjectCache::newObjectFromHit(JSContext *cx, EntryIndex entry_, js::gc::Initi // Do an end run around JSObject::group() to avoid doing AutoUnprotectCell // on the templateObj, which is not a GC thing and can't use runtimeFromAnyThread. - types::ObjectGroup *group = templateObj->group_; + ObjectGroup *group = templateObj->group_; if (group->shouldPreTenure()) heap = gc::TenuredHeap; diff --git a/js/src/vm/Runtime.h b/js/src/vm/Runtime.h index 6aca87bf5089..9bd61c97b722 100644 --- a/js/src/vm/Runtime.h +++ b/js/src/vm/Runtime.h @@ -287,7 +287,7 @@ class NewObjectCache inline bool lookupGlobal(const Class *clasp, js::GlobalObject *global, gc::AllocKind kind, EntryIndex *pentry); - bool lookupGroup(js::types::ObjectGroup *group, gc::AllocKind kind, EntryIndex *pentry) { + bool lookupGroup(js::ObjectGroup *group, gc::AllocKind kind, EntryIndex *pentry) { return lookup(group->clasp(), group, kind, pentry); } @@ -306,7 +306,7 @@ class NewObjectCache inline void fillGlobal(EntryIndex entry, const Class *clasp, js::GlobalObject *global, gc::AllocKind kind, NativeObject *obj); - void fillGroup(EntryIndex entry, js::types::ObjectGroup *group, gc::AllocKind kind, + void fillGroup(EntryIndex entry, js::ObjectGroup *group, gc::AllocKind kind, NativeObject *obj) { MOZ_ASSERT(obj->group() == group); @@ -347,7 +347,7 @@ class NewObjectCache static void copyCachedToObject(JSObject *dst, JSObject *src, gc::AllocKind kind) { js_memcpy(dst, src, gc::Arena::thingSize(kind)); Shape::writeBarrierPost(dst->shape_, &dst->shape_); - types::ObjectGroup::writeBarrierPost(dst->group_, &dst->group_); + ObjectGroup::writeBarrierPost(dst->group_, &dst->group_); } }; diff --git a/js/src/vm/ScopeObject.cpp b/js/src/vm/ScopeObject.cpp index d4ec087c9de1..97f473150977 100644 --- a/js/src/vm/ScopeObject.cpp +++ b/js/src/vm/ScopeObject.cpp @@ -153,7 +153,7 @@ CallObject::createSingleton(JSContext *cx, HandleShape shape, uint32_t lexicalBe MOZ_ASSERT(CanBeFinalizedInBackground(kind, &CallObject::class_)); kind = gc::GetBackgroundAllocKind(kind); - RootedObjectGroup group(cx, cx->getLazySingletonGroup(&class_, TaggedProto(nullptr))); + RootedObjectGroup group(cx, ObjectGroup::lazySingletonGroup(cx, &class_, TaggedProto(nullptr))); if (!group) return nullptr; RootedObject obj(cx, JSObject::create(cx, kind, gc::TenuredHeap, shape, group)); @@ -178,7 +178,7 @@ CallObject::createTemplateObject(JSContext *cx, HandleScript script, gc::Initial RootedShape shape(cx, script->bindings.callObjShape()); MOZ_ASSERT(shape->getObjectClass() == &class_); - RootedObjectGroup group(cx, cx->getNewGroup(&class_, TaggedProto(nullptr))); + RootedObjectGroup group(cx, ObjectGroup::defaultNewGroup(cx, &class_, TaggedProto(nullptr))); if (!group) return nullptr; @@ -326,7 +326,7 @@ DeclEnvObject::createTemplateObject(JSContext *cx, HandleFunction fun, gc::Initi { MOZ_ASSERT(IsNurseryAllocable(FINALIZE_KIND)); - RootedObjectGroup group(cx, cx->getNewGroup(&class_, TaggedProto(nullptr))); + RootedObjectGroup group(cx, ObjectGroup::defaultNewGroup(cx, &class_, TaggedProto(nullptr))); if (!group) return nullptr; @@ -400,7 +400,7 @@ js::XDRStaticWithObject(XDRState *, HandleObject, MutableHandlegetNewGroup(&class_, TaggedProto(nullptr))); + RootedObjectGroup group(cx, ObjectGroup::defaultNewGroup(cx, &class_, TaggedProto(nullptr))); if (!group) return nullptr; @@ -433,7 +433,8 @@ DynamicWithObject::create(JSContext *cx, HandleObject object, HandleObject enclo HandleObject staticWith, WithKind kind) { MOZ_ASSERT(staticWith->is()); - RootedObjectGroup group(cx, cx->getNewGroup(&class_, TaggedProto(staticWith.get()))); + RootedObjectGroup group(cx, ObjectGroup::defaultNewGroup(cx, &class_, + TaggedProto(staticWith.get()))); if (!group) return nullptr; @@ -563,7 +564,7 @@ const Class DynamicWithObject::class_ = { /* static */ StaticEvalObject * StaticEvalObject::create(JSContext *cx, HandleObject enclosing) { - RootedObjectGroup group(cx, cx->getNewGroup(&class_, TaggedProto(nullptr))); + RootedObjectGroup group(cx, ObjectGroup::defaultNewGroup(cx, &class_, TaggedProto(nullptr))); if (!group) return nullptr; @@ -596,7 +597,8 @@ ClonedBlockObject::create(JSContext *cx, Handle block, Hand { MOZ_ASSERT(block->getClass() == &BlockObject::class_); - RootedObjectGroup group(cx, cx->getNewGroup(&BlockObject::class_, TaggedProto(block.get()))); + RootedObjectGroup group(cx, ObjectGroup::defaultNewGroup(cx, &BlockObject::class_, + TaggedProto(block.get()))); if (!group) return nullptr; @@ -668,7 +670,8 @@ ClonedBlockObject::copyUnaliasedValues(AbstractFramePtr frame) StaticBlockObject * StaticBlockObject::create(ExclusiveContext *cx) { - RootedObjectGroup group(cx, cx->getNewGroup(&BlockObject::class_, TaggedProto(nullptr))); + RootedObjectGroup group(cx, ObjectGroup::defaultNewGroup(cx, &BlockObject::class_, + TaggedProto(nullptr))); if (!group) return nullptr; @@ -880,7 +883,7 @@ js::CloneNestedScopeObject(JSContext *cx, HandleObject enclosingScope, HandlegetNewGroup(&class_, TaggedProto(nullptr))); + RootedObjectGroup group(cx, ObjectGroup::defaultNewGroup(cx, &class_, TaggedProto(nullptr))); if (!group) return nullptr; diff --git a/js/src/vm/SelfHosting.cpp b/js/src/vm/SelfHosting.cpp index 81ce1fe76145..817b307c2781 100644 --- a/js/src/vm/SelfHosting.cpp +++ b/js/src/vm/SelfHosting.cpp @@ -324,7 +324,7 @@ js::intrinsic_NewDenseArray(JSContext *cx, unsigned argc, Value *vp) if (!buffer) return false; - types::ObjectGroup *newgroup = types::GetCallerInitGroup(cx, JSProto_Array); + ObjectGroup *newgroup = ObjectGroup::callingAllocationSiteGroup(cx, JSProto_Array); if (!newgroup) return false; buffer->setGroup(newgroup); @@ -507,7 +507,7 @@ js::intrinsic_IsPackedArray(JSContext *cx, unsigned argc, Value *vp) JSObject *obj = &args[0].toObject(); bool isPacked = obj->is() && !obj->hasLazyGroup() && - !obj->group()->hasAllFlags(types::OBJECT_FLAG_NON_PACKED) && + !obj->group()->hasAllFlags(OBJECT_FLAG_NON_PACKED) && obj->as().getDenseInitializedLength() == obj->as().length(); diff --git a/js/src/vm/Shape.cpp b/js/src/vm/Shape.cpp index f1e28749b397..821dfb9b9411 100644 --- a/js/src/vm/Shape.cpp +++ b/js/src/vm/Shape.cpp @@ -1724,7 +1724,7 @@ NewObjectCache::invalidateEntriesForShape(JSContext *cx, HandleShape shape, Hand kind = GetBackgroundAllocKind(kind); Rooted global(cx, &shape->getObjectParent()->global()); - RootedObjectGroup group(cx, cx->getNewGroup(clasp, TaggedProto(proto))); + RootedObjectGroup group(cx, ObjectGroup::defaultNewGroup(cx, clasp, TaggedProto(proto))); EntryIndex entry; if (lookupGlobal(clasp, global, kind, &entry)) diff --git a/js/src/vm/Shape.h b/js/src/vm/Shape.h index 8b9da498ce97..17c179d0b1d5 100644 --- a/js/src/vm/Shape.h +++ b/js/src/vm/Shape.h @@ -16,7 +16,6 @@ #include "jsapi.h" #include "jsfriendapi.h" -#include "jsinfer.h" #include "jspropertytree.h" #include "jstypes.h" #include "NamespaceImports.h" @@ -29,6 +28,7 @@ #include "js/MemoryMetrics.h" #include "js/RootingAPI.h" #include "js/UbiNode.h" +#include "vm/ObjectGroup.h" #include "vm/PropDesc.h" #ifdef _MSC_VER diff --git a/js/src/vm/SharedTypedArrayObject.cpp b/js/src/vm/SharedTypedArrayObject.cpp index ee9118aef0dd..26a6ed3119d8 100644 --- a/js/src/vm/SharedTypedArrayObject.cpp +++ b/js/src/vm/SharedTypedArrayObject.cpp @@ -135,7 +135,7 @@ class SharedTypedArrayObjectTemplate : public SharedTypedArrayObject if (!obj) return nullptr; - types::ObjectGroup *group = cx->getNewGroup(obj->getClass(), TaggedProto(proto.get())); + ObjectGroup *group = ObjectGroup::defaultNewGroup(cx, obj->getClass(), TaggedProto(proto.get())); if (!group) return nullptr; obj->setGroup(group); @@ -156,16 +156,17 @@ class SharedTypedArrayObjectTemplate : public SharedTypedArrayObject jsbytecode *pc; RootedScript script(cx, cx->currentScript(&pc)); - NewObjectKind newKind = script - ? UseSingletonForInitializer(script, pc, instanceClass()) - : GenericObject; + NewObjectKind newKind = GenericObject; + if (script && ObjectGroup::useSingletonForAllocationSite(script, pc, instanceClass())) + newKind = SingletonObject; RootedObject obj(cx, NewBuiltinClassInstance(cx, instanceClass(), allocKind, newKind)); if (!obj) return nullptr; - if (script) { - if (!types::SetInitializerObjectGroup(cx, script, pc, obj, newKind)) - return nullptr; + if (script && !ObjectGroup::setAllocationSiteObjectGroup(cx, script, pc, obj, + newKind == SingletonObject)) + { + return nullptr; } return &obj->as(); diff --git a/js/src/vm/Stack.cpp b/js/src/vm/Stack.cpp index 34d147c0799a..48c7c33282a1 100644 --- a/js/src/vm/Stack.cpp +++ b/js/src/vm/Stack.cpp @@ -135,7 +135,7 @@ InterpreterFrame::createRestParameter(JSContext *cx) ArrayObject *obj = NewDenseCopiedArray(cx, nrest, restvp, nullptr); if (!obj) return nullptr; - types::FixRestArgumentsType(cx, obj); + ObjectGroup::fixRestArgumentsGroup(cx, obj); return obj; } diff --git a/js/src/vm/Stack.h b/js/src/vm/Stack.h index 66e22bded0e8..d7d222aa254e 100644 --- a/js/src/vm/Stack.h +++ b/js/src/vm/Stack.h @@ -26,6 +26,7 @@ namespace js { class ArgumentsObject; class AsmJSModule; class InterpreterRegs; +class CallObject; class ScopeObject; class ScriptFrameIter; class SPSProfiler; diff --git a/js/src/vm/TypedArrayObject.cpp b/js/src/vm/TypedArrayObject.cpp index 6c6db9c9ba9d..8d48a1825d4d 100644 --- a/js/src/vm/TypedArrayObject.cpp +++ b/js/src/vm/TypedArrayObject.cpp @@ -305,7 +305,8 @@ class TypedArrayObjectTemplate : public TypedArrayObject if (!obj) return nullptr; - types::ObjectGroup *group = cx->getNewGroup(obj->getClass(), TaggedProto(proto.get())); + ObjectGroup *group = ObjectGroup::defaultNewGroup(cx, obj->getClass(), + TaggedProto(proto.get())); if (!group) return nullptr; obj->setGroup(group); @@ -326,16 +327,17 @@ class TypedArrayObjectTemplate : public TypedArrayObject jsbytecode *pc; RootedScript script(cx, cx->currentScript(&pc)); - NewObjectKind newKind = script - ? UseSingletonForInitializer(script, pc, clasp) - : GenericObject; + NewObjectKind newKind = GenericObject; + if (script && ObjectGroup::useSingletonForAllocationSite(script, pc, clasp)) + newKind = SingletonObject; RootedObject obj(cx, NewBuiltinClassInstance(cx, clasp, allocKind, newKind)); if (!obj) return nullptr; - if (script) { - if (!types::SetInitializerObjectGroup(cx, script, pc, obj, newKind)) - return nullptr; + if (script && !ObjectGroup::setAllocationSiteObjectGroup(cx, script, pc, obj, + newKind == SingletonObject)) + { + return nullptr; } return &obj->as(); @@ -972,9 +974,9 @@ DataViewNewObjectKind(JSContext *cx, uint32_t byteLength, JSObject *proto) return SingletonObject; jsbytecode *pc; JSScript *script = cx->currentScript(&pc); - if (!script) - return GenericObject; - return types::UseSingletonForInitializer(script, pc, &DataViewObject::class_); + if (script && ObjectGroup::useSingletonForAllocationSite(script, pc, &DataViewObject::class_)) + return SingletonObject; + return GenericObject; } inline DataViewObject * @@ -1000,7 +1002,7 @@ DataViewObject::create(JSContext *cx, uint32_t byteOffset, uint32_t byteLength, return nullptr; if (proto) { - types::ObjectGroup *group = cx->getNewGroup(&class_, TaggedProto(proto)); + ObjectGroup *group = ObjectGroup::defaultNewGroup(cx, &class_, TaggedProto(proto)); if (!group) return nullptr; obj->setGroup(group); @@ -1009,9 +1011,10 @@ DataViewObject::create(JSContext *cx, uint32_t byteOffset, uint32_t byteLength, } else { jsbytecode *pc; RootedScript script(cx, cx->currentScript(&pc)); - if (script) { - if (!types::SetInitializerObjectGroup(cx, script, pc, obj, newKind)) - return nullptr; + if (script && !ObjectGroup::setAllocationSiteObjectGroup(cx, script, pc, obj, + newKind == SingletonObject)) + { + return nullptr; } } diff --git a/js/src/vm/UbiNode.cpp b/js/src/vm/UbiNode.cpp index 5d3863ab95e8..2bbef9a0e0d9 100644 --- a/js/src/vm/UbiNode.cpp +++ b/js/src/vm/UbiNode.cpp @@ -60,15 +60,15 @@ Concrete::size(mozilla::MallocSizeOf mallocSizeof) const Node::Node(JSGCTraceKind kind, void *ptr) { switch (kind) { - case JSTRACE_OBJECT: construct(static_cast(ptr)); break; - case JSTRACE_SCRIPT: construct(static_cast(ptr)); break; - case JSTRACE_STRING: construct(static_cast(ptr)); break; - case JSTRACE_SYMBOL: construct(static_cast(ptr)); break; - case JSTRACE_BASE_SHAPE: construct(static_cast(ptr)); break; - case JSTRACE_JITCODE: construct(static_cast(ptr)); break; - case JSTRACE_LAZY_SCRIPT: construct(static_cast(ptr)); break; - case JSTRACE_SHAPE: construct(static_cast(ptr)); break; - case JSTRACE_OBJECT_GROUP: construct(static_cast(ptr)); break; + case JSTRACE_OBJECT: construct(static_cast(ptr)); break; + case JSTRACE_SCRIPT: construct(static_cast(ptr)); break; + case JSTRACE_STRING: construct(static_cast(ptr)); break; + case JSTRACE_SYMBOL: construct(static_cast(ptr)); break; + case JSTRACE_BASE_SHAPE: construct(static_cast(ptr)); break; + case JSTRACE_JITCODE: construct(static_cast(ptr)); break; + case JSTRACE_LAZY_SCRIPT: construct(static_cast(ptr)); break; + case JSTRACE_SHAPE: construct(static_cast(ptr)); break; + case JSTRACE_OBJECT_GROUP: construct(static_cast(ptr)); break; default: MOZ_CRASH("bad JSGCTraceKind passed to JS::ubi::Node::Node"); @@ -239,8 +239,8 @@ template<> const char16_t TracerConcrete::concreteTypeName[] = MOZ_UTF16("js::Shape"); template<> const char16_t TracerConcrete::concreteTypeName[] = MOZ_UTF16("js::BaseShape"); -template<> const char16_t TracerConcrete::concreteTypeName[] = - MOZ_UTF16("js::types::ObjectGroup"); +template<> const char16_t TracerConcrete::concreteTypeName[] = + MOZ_UTF16("js::ObjectGroup"); // Instantiate all the TracerConcrete and templates here, where @@ -255,7 +255,7 @@ template class TracerConcrete; template class TracerConcrete; template class TracerConcreteWithCompartment; template class TracerConcreteWithCompartment; -template class TracerConcrete; +template class TracerConcrete; } } diff --git a/js/src/vm/UnboxedObject.cpp b/js/src/vm/UnboxedObject.cpp index ba03c3ff56c4..ed3a3193ff19 100644 --- a/js/src/vm/UnboxedObject.cpp +++ b/js/src/vm/UnboxedObject.cpp @@ -419,7 +419,7 @@ UnboxedTypeIncludes(JSValueType supertype, JSValueType subtype) bool js::TryConvertToUnboxedLayout(JSContext *cx, Shape *templateShape, - types::ObjectGroup *group, types::PreliminaryObjectArray *objects) + ObjectGroup *group, types::PreliminaryObjectArray *objects) { if (!cx->runtime()->options().unboxedObjects()) return true; diff --git a/js/src/vm/UnboxedObject.h b/js/src/vm/UnboxedObject.h index 32f833728030..7a16954e45a8 100644 --- a/js/src/vm/UnboxedObject.h +++ b/js/src/vm/UnboxedObject.h @@ -182,7 +182,7 @@ class UnboxedPlainObject : public JSObject // preliminary objects and their group to the new unboxed representation. bool TryConvertToUnboxedLayout(JSContext *cx, Shape *templateShape, - types::ObjectGroup *group, types::PreliminaryObjectArray *objects); + ObjectGroup *group, types::PreliminaryObjectArray *objects); inline gc::AllocKind UnboxedLayout::getAllocKind() const From 41393c974dc0ebfc6b850b3f0247d867554f259c Mon Sep 17 00:00:00 2001 From: Kartikaya Gupta Date: Fri, 6 Feb 2015 09:26:44 -0500 Subject: [PATCH 22/62] Bug 1130129 - Better handle a case where the APZ hit-test disagrees with the main-thread hit-test results. r=botond --- dom/ipc/TabParent.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/dom/ipc/TabParent.cpp b/dom/ipc/TabParent.cpp index 218ab3e43408..021fd95475c0 100644 --- a/dom/ipc/TabParent.cpp +++ b/dom/ipc/TabParent.cpp @@ -2419,6 +2419,17 @@ TabParent::MaybeForwardEventToRenderFrame(WidgetInputEvent& aEvent, // id. if (aOutTargetGuid) { *aOutTargetGuid = InputAPZContext::GetTargetLayerGuid(); + + // There may be cases where the APZ hit-testing code came to a different + // conclusion than the main-thread hit-testing code as to where the event + // is destined. In such cases the layersId of the APZ result may not match + // the layersId of this renderframe. In such cases the main-thread hit- + // testing code "wins" so we need to update the guid to reflect this. + if (RenderFrameParent* rfp = GetRenderFrame()) { + if (aOutTargetGuid->mLayersId != rfp->GetLayersId()) { + *aOutTargetGuid = ScrollableLayerGuid(rfp->GetLayersId(), 0, FrameMetrics::NULL_SCROLL_ID); + } + } } if (aOutInputBlockId) { *aOutInputBlockId = InputAPZContext::GetInputBlockId(); From e9cd140c50400e2b8ba81a13413d5b1fec0d6ca4 Mon Sep 17 00:00:00 2001 From: Nathan Froyd Date: Tue, 3 Feb 2015 10:04:59 -0500 Subject: [PATCH 23/62] Bug 1128989 - part 1 - define Telemetry::ID as a uint32_t; r=gfritzsche We would like to be able to forward-declare Telemetry::ID, so fewer header files need to include Telemetry.h. Empirical evidence shows that forward-declaring enums requires either enum classes, or plain fixed-width enums. Let's opt for the latter here; there's no need to constrain the size to 16 bits, since Telemetry::IDs are rarely stored in data structures. --- toolkit/components/telemetry/gen-histogram-enum.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/toolkit/components/telemetry/gen-histogram-enum.py b/toolkit/components/telemetry/gen-histogram-enum.py index 9a473ca03266..821a144602d4 100644 --- a/toolkit/components/telemetry/gen-histogram-enum.py +++ b/toolkit/components/telemetry/gen-histogram-enum.py @@ -16,7 +16,7 @@ def main(argv): filename = argv[0] print banner - print "enum ID {" + print "enum ID : uint32_t {" for histogram in histogram_tools.from_file(filename): cpp_guard = histogram.cpp_guard() if cpp_guard: From e54d2ebfacb99c2dfb01ae74c76541463c4484f8 Mon Sep 17 00:00:00 2001 From: Nathan Froyd Date: Tue, 3 Feb 2015 10:05:49 -0500 Subject: [PATCH 24/62] Bug 1128989 - part 2 - forward-declare Telemetry::ID in Decoder.h; r=seth This change means that Decoder.h (and any files that include it) no longer depend on Telemetry.h. And since Telemetry.h can change rather frequently, this change helps minimize the number of files that need to be rebuilt when Telemetry.h does change. --- image/decoders/nsGIFDecoder2.cpp | 1 + image/decoders/nsJPEGDecoder.cpp | 1 + image/decoders/nsPNGDecoder.cpp | 1 + image/src/Decoder.cpp | 8 ++++++++ image/src/Decoder.h | 8 +++++--- 5 files changed, 16 insertions(+), 3 deletions(-) diff --git a/image/decoders/nsGIFDecoder2.cpp b/image/decoders/nsGIFDecoder2.cpp index acf214af93df..f70ab06b9a56 100644 --- a/image/decoders/nsGIFDecoder2.cpp +++ b/image/decoders/nsGIFDecoder2.cpp @@ -48,6 +48,7 @@ mailing address. #include "gfxPlatform.h" #include "qcms.h" #include +#include "mozilla/Telemetry.h" namespace mozilla { namespace image { diff --git a/image/decoders/nsJPEGDecoder.cpp b/image/decoders/nsJPEGDecoder.cpp index d0387a9bbbfc..f8c3c10446dc 100644 --- a/image/decoders/nsJPEGDecoder.cpp +++ b/image/decoders/nsJPEGDecoder.cpp @@ -19,6 +19,7 @@ #include "gfxPlatform.h" #include "mozilla/Endian.h" +#include "mozilla/Telemetry.h" extern "C" { #include "iccjpeg.h" diff --git a/image/decoders/nsPNGDecoder.cpp b/image/decoders/nsPNGDecoder.cpp index 7079b64421b0..769fb152b5fd 100644 --- a/image/decoders/nsPNGDecoder.cpp +++ b/image/decoders/nsPNGDecoder.cpp @@ -15,6 +15,7 @@ #include "nspr.h" #include "png.h" #include "RasterImage.h" +#include "mozilla/Telemetry.h" #include diff --git a/image/src/Decoder.cpp b/image/src/Decoder.cpp index 751273f43137..cf8cff4976cb 100644 --- a/image/src/Decoder.cpp +++ b/image/src/Decoder.cpp @@ -15,6 +15,7 @@ #include "nsProxyRelease.h" #include "nsServiceManagerUtils.h" #include "nsComponentManagerUtils.h" +#include "mozilla/Telemetry.h" using mozilla::gfx::IntSize; using mozilla::gfx::SurfaceFormat; @@ -701,5 +702,12 @@ Decoder::NeedNewFrame(uint32_t framenum, uint32_t x_offset, uint32_t y_offset, mNeedsNewFrame = true; } +Telemetry::ID +Decoder::SpeedHistogram() +{ + // Use HistogramCount as an invalid Histogram ID. + return Telemetry::HistogramCount; +} + } // namespace image } // namespace mozilla diff --git a/image/src/Decoder.h b/image/src/Decoder.h index f5b235a57100..b276f2e36235 100644 --- a/image/src/Decoder.h +++ b/image/src/Decoder.h @@ -13,10 +13,13 @@ #include "ImageMetadata.h" #include "Orientation.h" #include "SourceBuffer.h" -#include "mozilla/Telemetry.h" namespace mozilla { +namespace Telemetry { + enum ID : uint32_t; +} + namespace image { class Decoder : public IResumable @@ -263,8 +266,7 @@ public: return mImageMetadata.GetSize(); } - // Use HistogramCount as an invalid Histogram ID - virtual Telemetry::ID SpeedHistogram() { return Telemetry::HistogramCount; } + virtual Telemetry::ID SpeedHistogram(); ImageMetadata& GetImageMetadata() { return mImageMetadata; } From 913320b4cd10b55b1fccc2c7afefd229010517f7 Mon Sep 17 00:00:00 2001 From: Brian Hackett Date: Fri, 6 Feb 2015 09:26:44 -0700 Subject: [PATCH 25/62] Bug 1128644 - Use common offsets for unboxed layouts which are prefixes of each other, r=jandem. --- js/src/jscompartment.h | 3 ++ js/src/vm/UnboxedObject.cpp | 94 ++++++++++++++++++++++++++++++------- js/src/vm/UnboxedObject.h | 4 +- 3 files changed, 83 insertions(+), 18 deletions(-) diff --git a/js/src/jscompartment.h b/js/src/jscompartment.h index 4dc2dfeb5848..ff887ca10aee 100644 --- a/js/src/jscompartment.h +++ b/js/src/jscompartment.h @@ -302,6 +302,9 @@ struct JSCompartment // Map from typed objects to array buffers lazily created for them. js::LazyArrayBufferTable *lazyArrayBuffers; + // All unboxed layouts in the compartment. + mozilla::LinkedList unboxedLayouts; + /* During GC, stores the index of this compartment in rt->compartments. */ unsigned gcIndex; diff --git a/js/src/vm/UnboxedObject.cpp b/js/src/vm/UnboxedObject.cpp index ed3a3193ff19..15dfe30ba064 100644 --- a/js/src/vm/UnboxedObject.cpp +++ b/js/src/vm/UnboxedObject.cpp @@ -14,6 +14,7 @@ using mozilla::ArrayLength; using mozilla::DebugOnly; using mozilla::PodCopy; +using mozilla::UniquePtr; using namespace js; @@ -417,6 +418,26 @@ UnboxedTypeIncludes(JSValueType supertype, JSValueType subtype) return false; } +// Return whether the property names and types in layout are a subset of the +// specified vector. +static bool +PropertiesAreSuperset(const UnboxedLayout::PropertyVector &properties, UnboxedLayout *layout) +{ + for (size_t i = 0; i < layout->properties().length(); i++) { + const UnboxedLayout::Property &layoutProperty = layout->properties()[i]; + bool found = false; + for (size_t j = 0; j < properties.length(); j++) { + if (layoutProperty.name == properties[j].name) { + found = (layoutProperty.type == properties[j].type); + break; + } + } + if (!found) + return false; + } + return true; +} + bool js::TryConvertToUnboxedLayout(JSContext *cx, Shape *templateShape, ObjectGroup *group, types::PreliminaryObjectArray *objects) @@ -487,43 +508,83 @@ js::TryConvertToUnboxedLayout(JSContext *cx, Shape *templateShape, properties[slot].name = JSID_TO_ATOM(r.front().propid())->asPropertyName(); } - // Fill in all the unboxed object's property offsets, ordering fields from the - // largest down to avoid alignment issues. + // Fill in all the unboxed object's property offsets. uint32_t offset = 0; + // Search for an existing unboxed layout which is a subset of this one. + // If there are multiple such layouts, use the largest one. If we're able + // to find such a layout, use the same property offsets for the shared + // properties, which will allow us to generate better code if the objects + // have a subtype/supertype relation and are accessed at common sites. + UnboxedLayout *bestExisting = nullptr; + for (UnboxedLayout *existing = cx->compartment()->unboxedLayouts.getFirst(); + existing; + existing = existing->getNext()) + { + if (PropertiesAreSuperset(properties, existing)) { + if (!bestExisting || + existing->properties().length() > bestExisting->properties().length()) + { + bestExisting = existing; + } + } + } + if (bestExisting) { + for (size_t i = 0; i < bestExisting->properties().length(); i++) { + const UnboxedLayout::Property &existingProperty = bestExisting->properties()[i]; + for (size_t j = 0; j < templateShape->slotSpan(); j++) { + if (existingProperty.name == properties[j].name) { + MOZ_ASSERT(existingProperty.type == properties[j].type); + properties[j].offset = existingProperty.offset; + } + } + } + offset = bestExisting->size(); + } + + // Order remaining properties from the largest down for the best space + // utilization. static const size_t typeSizes[] = { 8, 4, 1 }; - Vector objectOffsets, stringOffsets; - - DebugOnly addedProperties = 0; for (size_t i = 0; i < ArrayLength(typeSizes); i++) { size_t size = typeSizes[i]; for (size_t j = 0; j < templateShape->slotSpan(); j++) { + if (properties[j].offset != UINT32_MAX) + continue; JSValueType type = properties[j].type; if (UnboxedTypeSize(type) == size) { - if (type == JSVAL_TYPE_OBJECT) { - if (!objectOffsets.append(offset)) - return false; - } else if (type == JSVAL_TYPE_STRING) { - if (!stringOffsets.append(offset)) - return false; - } - addedProperties++; + offset = JS_ROUNDUP(offset, size); properties[j].offset = offset; offset += size; } } } - MOZ_ASSERT(addedProperties == templateShape->slotSpan()); // The entire object must be allocatable inline. if (sizeof(JSObject) + offset > JSObject::MAX_BYTE_SIZE) return true; - UnboxedLayout *layout = group->zone()->new_(properties, offset); + UniquePtr > layout; + layout.reset(group->zone()->new_(properties, offset)); if (!layout) return false; + cx->compartment()->unboxedLayouts.insertFront(layout.get()); + + // Figure out the offsets of any objects or string properties. + Vector objectOffsets, stringOffsets; + for (size_t i = 0; i < templateShape->slotSpan(); i++) { + MOZ_ASSERT(properties[i].offset != UINT32_MAX); + JSValueType type = properties[i].type; + if (type == JSVAL_TYPE_OBJECT) { + if (!objectOffsets.append(properties[i].offset)) + return false; + } else if (type == JSVAL_TYPE_STRING) { + if (!stringOffsets.append(properties[i].offset)) + return false; + } + } + // Construct the layout's trace list. if (!objectOffsets.empty() || !stringOffsets.empty()) { Vector entries; @@ -582,7 +643,7 @@ js::TryConvertToUnboxedLayout(JSContext *cx, Shape *templateShape, layout->setNewScript(newScript); group->setClasp(&UnboxedPlainObject::class_); - group->setUnboxedLayout(layout); + group->setUnboxedLayout(layout.get()); size_t valueCursor = 0; for (size_t i = 0; i < types::PreliminaryObjectArray::COUNT; i++) { @@ -597,5 +658,6 @@ js::TryConvertToUnboxedLayout(JSContext *cx, Shape *templateShape, } MOZ_ASSERT(valueCursor == values.length()); + layout.release(); return true; } diff --git a/js/src/vm/UnboxedObject.h b/js/src/vm/UnboxedObject.h index 7a16954e45a8..75b926106bf9 100644 --- a/js/src/vm/UnboxedObject.h +++ b/js/src/vm/UnboxedObject.h @@ -35,7 +35,7 @@ UnboxedTypeNeedsPreBarrier(JSValueType type) } // Class describing the layout of an UnboxedPlainObject. -class UnboxedLayout +class UnboxedLayout : public mozilla::LinkedListElement { public: struct Property { @@ -44,7 +44,7 @@ class UnboxedLayout JSValueType type; Property() - : name(nullptr), offset(0), type(JSVAL_TYPE_MAGIC) + : name(nullptr), offset(UINT32_MAX), type(JSVAL_TYPE_MAGIC) {} }; From 9070262838b01fcfbcb7829908c401f60ea46cef Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Fri, 6 Feb 2015 11:27:15 -0500 Subject: [PATCH 26/62] Bug 1130259. Make sure the integer overload of ScrollBy calls the double one, not itself. r=kip --- dom/base/nsGlobalWindow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp index cf614604dec8..3a621a03996d 100644 --- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -7265,7 +7265,7 @@ nsGlobalWindow::ScrollTo(const CSSIntPoint& aScroll, NS_IMETHODIMP nsGlobalWindow::ScrollBy(int32_t aXScrollDif, int32_t aYScrollDif) { - ScrollBy(aXScrollDif, aYScrollDif); + ScrollBy(double(aXScrollDif), double(aYScrollDif)); return NS_OK; } From e297d45353e0a99ae307cdf23d038cd725bdd2c5 Mon Sep 17 00:00:00 2001 From: Jason Orendorff Date: Mon, 2 Feb 2015 13:59:55 -0600 Subject: [PATCH 27/62] Bug 1128648 - Remove fretting about DynamicWithObject in Shape::set. r=efaust. --HG-- extra : rebase_source : fc663cf11ee408207a25003db973364ad104c8df --- js/src/vm/Shape-inl.h | 13 ++----------- js/src/vm/Shape.h | 3 ++- 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/js/src/vm/Shape-inl.h b/js/src/vm/Shape-inl.h index 49a6483b464a..3892cb2377ec 100644 --- a/js/src/vm/Shape-inl.h +++ b/js/src/vm/Shape-inl.h @@ -41,10 +41,11 @@ Shape::search(ExclusiveContext *cx, jsid id) } inline bool -Shape::set(JSContext* cx, HandleObject obj, HandleObject receiver, bool strict, +Shape::set(JSContext* cx, HandleNativeObject obj, HandleObject receiver, bool strict, MutableHandleValue vp) { MOZ_ASSERT_IF(hasDefaultSetter(), hasGetterValue()); + MOZ_ASSERT(!obj->is()); // See bug 1128681. if (attrs & JSPROP_SETTER) { Value fval = setterValue(); @@ -58,16 +59,6 @@ Shape::set(JSContext* cx, HandleObject obj, HandleObject receiver, bool strict, return true; RootedId id(cx, propid()); - - /* - * |with (it) color='red';| ends up here. - * Avoid exposing the With object to native setters. - */ - if (obj->is()) { - RootedObject nobj(cx, &obj->as().object()); - return CallJSPropertyOpSetter(cx, setterOp(), nobj, id, strict, vp); - } - return CallJSPropertyOpSetter(cx, setterOp(), obj, id, strict, vp); } diff --git a/js/src/vm/Shape.h b/js/src/vm/Shape.h index 17c179d0b1d5..1a8041848e45 100644 --- a/js/src/vm/Shape.h +++ b/js/src/vm/Shape.h @@ -962,7 +962,8 @@ class Shape : public gc::TenuredCell setter() == rawSetter; } - bool set(JSContext* cx, HandleObject obj, HandleObject receiver, bool strict, MutableHandleValue vp); + bool set(JSContext* cx, HandleNativeObject obj, HandleObject receiver, bool strict, + MutableHandleValue vp); BaseShape *base() const { return base_.get(); } From 27a2ca0ba863376d4d9ef08125a0e4d37fe49789 Mon Sep 17 00:00:00 2001 From: Jason Orendorff Date: Fri, 30 Jan 2015 11:10:24 -0600 Subject: [PATCH 28/62] Bug 1128732 - Simplify js::DefineProperties. r=efaust. --HG-- extra : rebase_source : 679dd8ac62479a657bfe06889abd9f58527a22c3 --- js/src/jsobj.cpp | 38 +------------------------------------- 1 file changed, 1 insertion(+), 37 deletions(-) diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index ed759fabac40..5ff797bc5c8c 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -1014,45 +1014,9 @@ js::DefineProperties(JSContext *cx, HandleObject obj, HandleObject props) if (!ReadPropertyDescriptors(cx, props, true, &ids, &descs)) return false; - if (obj->is()) { - bool dummy; - Rooted arr(cx, &obj->as()); - for (size_t i = 0, len = ids.length(); i < len; i++) { - if (!DefinePropertyOnArray(cx, arr, ids[i], descs[i], true, &dummy)) - return false; - } - return true; - } - - if (IsAnyTypedArray(obj)) { - bool dummy; - for (size_t i = 0, len = ids.length(); i < len; i++) { - if (!DefinePropertyOnTypedArray(cx, obj, ids[i], descs[i], true, &dummy)) - return false; - } - return true; - } - - if (obj->is() && !obj->as().convertToNative(cx)) - return false; - - if (obj->getOps()->lookupProperty) { - if (obj->is()) { - Rooted pd(cx); - for (size_t i = 0, len = ids.length(); i < len; i++) { - descs[i].populatePropertyDescriptor(obj, &pd); - if (!Proxy::defineProperty(cx, obj, ids[i], &pd)) - return false; - } - return true; - } - bool dummy; - return Reject(cx, obj, JSMSG_OBJECT_NOT_EXTENSIBLE, true, &dummy); - } - bool dummy; for (size_t i = 0, len = ids.length(); i < len; i++) { - if (!DefinePropertyOnObject(cx, obj.as(), ids[i], descs[i], true, &dummy)) + if (!StandardDefineProperty(cx, obj, ids[i], descs[i], true, &dummy)) return false; } From 43b81b8d39faaf5aece1ceeca2e24945a37f7a87 Mon Sep 17 00:00:00 2001 From: Jason Orendorff Date: Tue, 3 Feb 2015 21:34:26 -0600 Subject: [PATCH 29/62] Bug 1129275 - Remove extra js::SetProperty template. r=efaust. --HG-- extra : rebase_source : 8c6eeeeac566402d54f8c615c6786b6a8e2ba31e --- js/src/jit/BaselineIC.cpp | 11 ++++------- js/src/vm/Interpreter.cpp | 11 ----------- js/src/vm/Interpreter.h | 4 ---- 3 files changed, 4 insertions(+), 22 deletions(-) diff --git a/js/src/jit/BaselineIC.cpp b/js/src/jit/BaselineIC.cpp index 02290db929bd..ae63ab99f25e 100644 --- a/js/src/jit/BaselineIC.cpp +++ b/js/src/jit/BaselineIC.cpp @@ -8248,13 +8248,10 @@ DoSetPropFallback(JSContext *cx, BaselineFrame *frame, ICSetProp_Fallback *stub_ obj->as().setAliasedVar(cx, ScopeCoordinate(pc), name, rhs); } else { MOZ_ASSERT(op == JSOP_SETPROP || op == JSOP_STRICTSETPROP); - if (op == JSOP_STRICTSETPROP) { - if (!js::SetProperty(cx, obj, id, rhs)) - return false; - } else { - if (!js::SetProperty(cx, obj, id, rhs)) - return false; - } + + RootedValue v(cx, rhs); + if (!SetProperty(cx, obj, obj, id, &v, op == JSOP_STRICTSETPROP)) + return false; } // Leave the RHS on the stack. diff --git a/js/src/vm/Interpreter.cpp b/js/src/vm/Interpreter.cpp index e38e9314c624..c65f41cd28b4 100644 --- a/js/src/vm/Interpreter.cpp +++ b/js/src/vm/Interpreter.cpp @@ -3791,17 +3791,6 @@ js::GetAndClearException(JSContext *cx, MutableHandleValue res) return CheckForInterrupt(cx); } -template -bool -js::SetProperty(JSContext *cx, HandleObject obj, HandleId id, const Value &value) -{ - RootedValue v(cx, value); - return SetProperty(cx, obj, obj, id, &v, strict); -} - -template bool js::SetProperty (JSContext *cx, HandleObject obj, HandleId id, const Value &value); -template bool js::SetProperty(JSContext *cx, HandleObject obj, HandleId id, const Value &value); - template bool js::DeleteProperty(JSContext *cx, HandleValue v, HandlePropertyName name, bool *bp) diff --git a/js/src/vm/Interpreter.h b/js/src/vm/Interpreter.h index cec256e9410d..269a5762341d 100644 --- a/js/src/vm/Interpreter.h +++ b/js/src/vm/Interpreter.h @@ -341,10 +341,6 @@ ModValues(JSContext *cx, MutableHandleValue lhs, MutableHandleValue rhs, Mutable bool UrshValues(JSContext *cx, MutableHandleValue lhs, MutableHandleValue rhs, MutableHandleValue res); -template -bool -SetProperty(JSContext *cx, HandleObject obj, HandleId id, const Value &value); - template bool DeleteProperty(JSContext *ctx, HandleValue val, HandlePropertyName name, bool *bv); From 0d4dda7bef6f3fe0cfb646d888aeaf5a81212e1f Mon Sep 17 00:00:00 2001 From: Jason Orendorff Date: Tue, 3 Feb 2015 20:47:18 -0600 Subject: [PATCH 30/62] Bug 1129271 - Follow-up fix to bug 1125930 for GDB support. r=jandem. --HG-- extra : rebase_source : f5770c7eb59f4853aab406572867e7ca23639370 extra : amend_source : 1b4cc04dedd8d1aeea7903bf6bf0054895b21f64 --- js/src/gdb/mozilla/JSObject.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/js/src/gdb/mozilla/JSObject.py b/js/src/gdb/mozilla/JSObject.py index eef0826ccf17..96a720df0bbe 100644 --- a/js/src/gdb/mozilla/JSObject.py +++ b/js/src/gdb/mozilla/JSObject.py @@ -34,8 +34,8 @@ class JSObjectPtrOrRef(prettyprinters.Pointer): def summary(self): shape = deref(self.value['shape_']) baseshape = deref(shape['base_']) - otype = deref(self.value['type_']) - class_name = otype['clasp_']['name'].string() + group = deref(self.value['group_']) + class_name = group['clasp_']['name'].string() flags = baseshape['flags'] is_delegate = bool(flags & self.otc.flag_DELEGATE) name = None From e51b53b9c0d9b269859b51536613ece95d6aa004 Mon Sep 17 00:00:00 2001 From: B2G Bumper Bot Date: Fri, 6 Feb 2015 09:10:27 -0800 Subject: [PATCH 31/62] Bumping gaia.json for 2 gaia revision(s) a=gaia-bump ======== https://hg.mozilla.org/integration/gaia-central/rev/fe771d80191f Author: Eli Perelman Desc: Merge pull request #27986 from eliperelman/bug-1129041-calendar Bug 1129041 - Calendar: remove user timing shim ======== https://hg.mozilla.org/integration/gaia-central/rev/122b281d3f82 Author: Eli Perelman Desc: Bug 1129041 - Calendar: remove user timing shim --- b2g/config/gaia.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/b2g/config/gaia.json b/b2g/config/gaia.json index e40258533106..ed2dab699b7d 100644 --- a/b2g/config/gaia.json +++ b/b2g/config/gaia.json @@ -1,9 +1,9 @@ { "git": { - "git_revision": "0244121522343877d65a69377226a836688e3004", + "git_revision": "96e10493bc95d63c8cd6b67bd2d602fba2b1bdf5", "remote": "https://git.mozilla.org/releases/gaia.git", "branch": "" }, - "revision": "33d9ca589ca27af7f98b29b97a232ca599f111fe", + "revision": "fe771d80191f255d563bdf7555295bf8cffdc27f", "repo_path": "integration/gaia-central" } From db3a723b35d782e528cbe0908bfa035409de73e3 Mon Sep 17 00:00:00 2001 From: B2G Bumper Bot Date: Fri, 6 Feb 2015 09:11:55 -0800 Subject: [PATCH 32/62] Bumping manifests a=b2g-bump --- b2g/config/dolphin/sources.xml | 2 +- b2g/config/emulator-ics/sources.xml | 2 +- b2g/config/emulator-jb/sources.xml | 2 +- b2g/config/emulator-kk/sources.xml | 2 +- b2g/config/emulator/sources.xml | 2 +- b2g/config/flame-kk/sources.xml | 2 +- b2g/config/flame/sources.xml | 2 +- b2g/config/nexus-4/sources.xml | 2 +- b2g/config/nexus-5-l/sources.xml | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/b2g/config/dolphin/sources.xml b/b2g/config/dolphin/sources.xml index 0931cffbf8b1..e85533c22586 100644 --- a/b2g/config/dolphin/sources.xml +++ b/b2g/config/dolphin/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/emulator-ics/sources.xml b/b2g/config/emulator-ics/sources.xml index 8df3d0248551..f0a08394f9ad 100644 --- a/b2g/config/emulator-ics/sources.xml +++ b/b2g/config/emulator-ics/sources.xml @@ -19,7 +19,7 @@ - + diff --git a/b2g/config/emulator-jb/sources.xml b/b2g/config/emulator-jb/sources.xml index 27c9f7610966..747af9028649 100644 --- a/b2g/config/emulator-jb/sources.xml +++ b/b2g/config/emulator-jb/sources.xml @@ -17,7 +17,7 @@ - + diff --git a/b2g/config/emulator-kk/sources.xml b/b2g/config/emulator-kk/sources.xml index 0194695809fc..1772e562dc2b 100644 --- a/b2g/config/emulator-kk/sources.xml +++ b/b2g/config/emulator-kk/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/emulator/sources.xml b/b2g/config/emulator/sources.xml index 8df3d0248551..f0a08394f9ad 100644 --- a/b2g/config/emulator/sources.xml +++ b/b2g/config/emulator/sources.xml @@ -19,7 +19,7 @@ - + diff --git a/b2g/config/flame-kk/sources.xml b/b2g/config/flame-kk/sources.xml index 4ca1b3822b17..b69023ed0023 100644 --- a/b2g/config/flame-kk/sources.xml +++ b/b2g/config/flame-kk/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/flame/sources.xml b/b2g/config/flame/sources.xml index 5344147e21d0..e4e54657771a 100644 --- a/b2g/config/flame/sources.xml +++ b/b2g/config/flame/sources.xml @@ -17,7 +17,7 @@ - + diff --git a/b2g/config/nexus-4/sources.xml b/b2g/config/nexus-4/sources.xml index 163972b68a6c..465f9bd7aa03 100644 --- a/b2g/config/nexus-4/sources.xml +++ b/b2g/config/nexus-4/sources.xml @@ -17,7 +17,7 @@ - + diff --git a/b2g/config/nexus-5-l/sources.xml b/b2g/config/nexus-5-l/sources.xml index dff4eb545101..aba61512da76 100644 --- a/b2g/config/nexus-5-l/sources.xml +++ b/b2g/config/nexus-5-l/sources.xml @@ -15,7 +15,7 @@ - + From a8c430384757b45394a0188f68e41df9e593e5e3 Mon Sep 17 00:00:00 2001 From: B2G Bumper Bot Date: Fri, 6 Feb 2015 09:50:26 -0800 Subject: [PATCH 33/62] Bumping gaia.json for 4 gaia revision(s) a=gaia-bump ======== https://hg.mozilla.org/integration/gaia-central/rev/a141318d7e02 Author: autolander Desc: Bug 1130011 - merge pull request #27979 from etiennesegonzac:bug-1130011 to mozilla-b2g:master ======== https://hg.mozilla.org/integration/gaia-central/rev/1c07c687c58b Author: Etienne Segonzac Desc: Bug 1130011 - Removing superfluous touch event listener on the whole window r=kgrandon ======== https://hg.mozilla.org/integration/gaia-central/rev/b0819aa2615b Author: autolander Desc: Bug 1129563 - merge pull request #27939 from davidflanagan:bug1129563 to mozilla-b2g:master ======== https://hg.mozilla.org/integration/gaia-central/rev/96719518e564 Author: David Flanagan Desc: Bug 1129563 - use window.location.hash instead of mozHasPendingMessages() --- b2g/config/gaia.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/b2g/config/gaia.json b/b2g/config/gaia.json index ed2dab699b7d..4c35cf57c36c 100644 --- a/b2g/config/gaia.json +++ b/b2g/config/gaia.json @@ -1,9 +1,9 @@ { "git": { - "git_revision": "96e10493bc95d63c8cd6b67bd2d602fba2b1bdf5", + "git_revision": "1d6bd73655ad106328c8083eb3166fa09bb7ee73", "remote": "https://git.mozilla.org/releases/gaia.git", "branch": "" }, - "revision": "fe771d80191f255d563bdf7555295bf8cffdc27f", + "revision": "a141318d7e02995fe3ca486a3361068ff68f5729", "repo_path": "integration/gaia-central" } From d9a46d592050421e8f139cb8c2b3c14140fd28c2 Mon Sep 17 00:00:00 2001 From: B2G Bumper Bot Date: Fri, 6 Feb 2015 09:51:56 -0800 Subject: [PATCH 34/62] Bumping manifests a=b2g-bump --- b2g/config/dolphin/sources.xml | 2 +- b2g/config/emulator-ics/sources.xml | 2 +- b2g/config/emulator-jb/sources.xml | 2 +- b2g/config/emulator-kk/sources.xml | 2 +- b2g/config/emulator/sources.xml | 2 +- b2g/config/flame-kk/sources.xml | 2 +- b2g/config/flame/sources.xml | 2 +- b2g/config/nexus-4/sources.xml | 2 +- b2g/config/nexus-5-l/sources.xml | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/b2g/config/dolphin/sources.xml b/b2g/config/dolphin/sources.xml index e85533c22586..6518c23dee38 100644 --- a/b2g/config/dolphin/sources.xml +++ b/b2g/config/dolphin/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/emulator-ics/sources.xml b/b2g/config/emulator-ics/sources.xml index f0a08394f9ad..0eb5165f39d4 100644 --- a/b2g/config/emulator-ics/sources.xml +++ b/b2g/config/emulator-ics/sources.xml @@ -19,7 +19,7 @@ - + diff --git a/b2g/config/emulator-jb/sources.xml b/b2g/config/emulator-jb/sources.xml index 747af9028649..a2dcc9095306 100644 --- a/b2g/config/emulator-jb/sources.xml +++ b/b2g/config/emulator-jb/sources.xml @@ -17,7 +17,7 @@ - + diff --git a/b2g/config/emulator-kk/sources.xml b/b2g/config/emulator-kk/sources.xml index 1772e562dc2b..c9bd6550bbeb 100644 --- a/b2g/config/emulator-kk/sources.xml +++ b/b2g/config/emulator-kk/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/emulator/sources.xml b/b2g/config/emulator/sources.xml index f0a08394f9ad..0eb5165f39d4 100644 --- a/b2g/config/emulator/sources.xml +++ b/b2g/config/emulator/sources.xml @@ -19,7 +19,7 @@ - + diff --git a/b2g/config/flame-kk/sources.xml b/b2g/config/flame-kk/sources.xml index b69023ed0023..7dca02869bb7 100644 --- a/b2g/config/flame-kk/sources.xml +++ b/b2g/config/flame-kk/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/flame/sources.xml b/b2g/config/flame/sources.xml index e4e54657771a..d4deb737e364 100644 --- a/b2g/config/flame/sources.xml +++ b/b2g/config/flame/sources.xml @@ -17,7 +17,7 @@ - + diff --git a/b2g/config/nexus-4/sources.xml b/b2g/config/nexus-4/sources.xml index 465f9bd7aa03..b56bc7ba67d5 100644 --- a/b2g/config/nexus-4/sources.xml +++ b/b2g/config/nexus-4/sources.xml @@ -17,7 +17,7 @@ - + diff --git a/b2g/config/nexus-5-l/sources.xml b/b2g/config/nexus-5-l/sources.xml index aba61512da76..18ee618c1e6b 100644 --- a/b2g/config/nexus-5-l/sources.xml +++ b/b2g/config/nexus-5-l/sources.xml @@ -15,7 +15,7 @@ - + From 5f998ddabecd3f25649d2dac8ca087962817da9b Mon Sep 17 00:00:00 2001 From: "jlal@mozilla.com" Date: Fri, 6 Feb 2015 00:18:42 -0800 Subject: [PATCH 35/62] Bug 1130106 - Schedule b2g-inbound jobs r=garndt - Update scopes in decision task to something easier to use locally - Schedule flame builds (they may fail now) - Add optional revision-hash argument to decision task mach target - Use b2gtest worker type for tests - Use build specific worker types --HG-- extra : rebase_source : dff37d59c35efcfc1698f2716e0fc0dc5e86937d --- testing/docker/builder/VERSION | 2 +- testing/taskcluster/mach_commands.py | 3 ++ .../tasks/branches/base_job_flags.yml | 2 ++ .../tasks/builds/b2g_emulator_ics_debug.yml | 1 + .../tasks/builds/b2g_emulator_ics_opt.yml | 1 + .../tasks/builds/b2g_emulator_jb_debug.yml | 1 + .../tasks/builds/b2g_emulator_jb_opt.yml | 1 + .../tasks/builds/b2g_emulator_kk_debug.yml | 2 +- .../tasks/builds/b2g_emulator_kk_opt.yml | 2 +- testing/taskcluster/tasks/decision/branch.yml | 33 +++++-------------- testing/taskcluster/tasks/test.yml | 2 +- 11 files changed, 22 insertions(+), 28 deletions(-) diff --git a/testing/docker/builder/VERSION b/testing/docker/builder/VERSION index 53a75d673557..0d91a54c7d43 100644 --- a/testing/docker/builder/VERSION +++ b/testing/docker/builder/VERSION @@ -1 +1 @@ -0.2.6 +0.3.0 diff --git a/testing/taskcluster/mach_commands.py b/testing/taskcluster/mach_commands.py index 7b46c9943d73..56c4b20f5436 100644 --- a/testing/taskcluster/mach_commands.py +++ b/testing/taskcluster/mach_commands.py @@ -105,6 +105,8 @@ class DecisionTask(object): @CommandArgument('--revision', required=True, help='Revision for this project') + @CommandArgument('--revision-hash', + help='Treeherder revision hash') @CommandArgument('--comment', required=True, help='Commit message for this revision') @@ -121,6 +123,7 @@ class DecisionTask(object): 'comment': params['comment'], 'url': params['url'], 'revision': params['revision'], + 'revision_hash': params.get('revision_hash', ''), 'owner': params['owner'], 'as_slugid': SlugidJar(), 'from_now': json_time_from_now, diff --git a/testing/taskcluster/tasks/branches/base_job_flags.yml b/testing/taskcluster/tasks/branches/base_job_flags.yml index 58136214304a..d67875c34a3e 100644 --- a/testing/taskcluster/tasks/branches/base_job_flags.yml +++ b/testing/taskcluster/tasks/branches/base_job_flags.yml @@ -11,6 +11,8 @@ flags: - linux64-mulet # Firefox desktop - b2g gecko linux 64 bit - macosx64_gecko # b2g desktop osx 64 bit - win32_gecko # b2g desktop win 32 bit + - flame-kk # b2g flame kitkat + - flame-kk-eng # b2g flame eng build tests: - cppunit diff --git a/testing/taskcluster/tasks/builds/b2g_emulator_ics_debug.yml b/testing/taskcluster/tasks/builds/b2g_emulator_ics_debug.yml index 8750c7987c81..8c2d8326d2a4 100644 --- a/testing/taskcluster/tasks/builds/b2g_emulator_ics_debug.yml +++ b/testing/taskcluster/tasks/builds/b2g_emulator_ics_debug.yml @@ -1,6 +1,7 @@ $inherits: from: 'tasks/builds/b2g_emulator_base.yml' task: + workerType: emulator-ics-debug scopes: - 'docker-worker:cache:build-emulator-ics-debug' metadata: diff --git a/testing/taskcluster/tasks/builds/b2g_emulator_ics_opt.yml b/testing/taskcluster/tasks/builds/b2g_emulator_ics_opt.yml index ebeb95679022..6e0a57f296c8 100644 --- a/testing/taskcluster/tasks/builds/b2g_emulator_ics_opt.yml +++ b/testing/taskcluster/tasks/builds/b2g_emulator_ics_opt.yml @@ -1,6 +1,7 @@ $inherits: from: 'tasks/builds/b2g_emulator_base.yml' task: + workerType: emulator-ics scopes: - 'docker-worker:cache:build-emulator-ics-opt' metadata: diff --git a/testing/taskcluster/tasks/builds/b2g_emulator_jb_debug.yml b/testing/taskcluster/tasks/builds/b2g_emulator_jb_debug.yml index cfcbbc0dba76..0158a64df82e 100644 --- a/testing/taskcluster/tasks/builds/b2g_emulator_jb_debug.yml +++ b/testing/taskcluster/tasks/builds/b2g_emulator_jb_debug.yml @@ -1,6 +1,7 @@ $inherits: from: 'tasks/builds/b2g_emulator_base.yml' task: + workerType: emulator-jb-debug scopes: - 'docker-worker:cache:build-emulator-jb-debug' metadata: diff --git a/testing/taskcluster/tasks/builds/b2g_emulator_jb_opt.yml b/testing/taskcluster/tasks/builds/b2g_emulator_jb_opt.yml index a396c4587889..44db1ff35d8c 100644 --- a/testing/taskcluster/tasks/builds/b2g_emulator_jb_opt.yml +++ b/testing/taskcluster/tasks/builds/b2g_emulator_jb_opt.yml @@ -1,6 +1,7 @@ $inherits: from: 'tasks/builds/b2g_emulator_base.yml' task: + workerType: emulator-jb scopes: - 'docker-worker:cache:build-emulator-jb-opt' metadata: diff --git a/testing/taskcluster/tasks/builds/b2g_emulator_kk_debug.yml b/testing/taskcluster/tasks/builds/b2g_emulator_kk_debug.yml index c826e4367194..0d412ea0cdc5 100644 --- a/testing/taskcluster/tasks/builds/b2g_emulator_kk_debug.yml +++ b/testing/taskcluster/tasks/builds/b2g_emulator_kk_debug.yml @@ -1,7 +1,7 @@ $inherits: from: 'tasks/builds/b2g_emulator_base.yml' task: - workerType: b2gbuild-emulator-kk + workerType: emulator-kk-debug scopes: - 'docker-worker:cache:build-emulator-kk-debug' metadata: diff --git a/testing/taskcluster/tasks/builds/b2g_emulator_kk_opt.yml b/testing/taskcluster/tasks/builds/b2g_emulator_kk_opt.yml index 67e05364d221..060e8e3c3cd4 100644 --- a/testing/taskcluster/tasks/builds/b2g_emulator_kk_opt.yml +++ b/testing/taskcluster/tasks/builds/b2g_emulator_kk_opt.yml @@ -1,7 +1,7 @@ $inherits: from: 'tasks/builds/b2g_emulator_base.yml' task: - workerType: b2gbuild-emulator-kk + workerType: emulator-kk scopes: - 'docker-worker:cache:build-emulator-kk-opt' metadata: diff --git a/testing/taskcluster/tasks/decision/branch.yml b/testing/taskcluster/tasks/decision/branch.yml index 50a53b30e2be..48455c8a0e2a 100644 --- a/testing/taskcluster/tasks/decision/branch.yml +++ b/testing/taskcluster/tasks/decision/branch.yml @@ -7,27 +7,11 @@ metadata: source: "{{source}}" scopes: - - "docker-worker:image:quay.io/mozilla/decision:*" - - "queue:define-task:aws-provisioner/gecko-decision" - - "queue:create-task:aws-provisioner/gecko-decision" - - "docker-worker:cache:tc-vcs-public-sources" - - "docker-worker:cache:build-emulator-jb-opt" - - "docker-worker:cache:build-mulet-linux-objects" - - "docker-worker:cache:build-emulator-ics-opt" - - "queue:define-task:aws-provisioner/b2gtest" - - "queue:create-task:aws-provisioner/b2gtest" - - "docker-worker:image:quay.io/mozilla/builder:*" - - "docker-worker:cache:tooltool-cache" - - "queue:define-task:aws-provisioner/b2gbuild" - - "queue:create-task:aws-provisioner/b2gbuild" - - "docker-worker:cache:build-emulator-kk-debug" - - "docker-worker:cache:build-b2g-desktop-objects" - - "docker-worker:cache:build-emulator-kk-opt" - - "docker-worker:cache:build-emulator-jb-debug" - - "docker-worker:cache:tc-vcs" - - "docker-worker:cache:sources-gecko" - - "docker-worker:cache:sources-gaia" - - "docker-worker:cache:build-emulator-ics-debug" + # Note the below scopes are insecure however these get overriden on the server + # side to whatever scopes are set by mozilla-taskcluster. + - queue:* + - docker-worker:* + - scheduler:* tasks: - taskId: '{{#as_slugid}}decision task{{/as_slugid}}' task: @@ -46,7 +30,7 @@ tasks: scopes: - "docker-worker:cache:tc-vcs-public-sources" - - "docker-worker:image:quay.io/mozilla/decision:0.0.3" + - "docker-worker:image:quay.io/mozilla/builder:0.3.0" payload: env: @@ -63,7 +47,7 @@ tasks: # Note: This task is built server side without the context or tooling that # exist in tree so we must hard code the version - image: 'quay.io/mozilla/decision:0.0.3' + image: 'quay.io/mozilla/builder:0.3.0' # Virtually no network or other potentially risky operations happen as part # of the task timeout aside from the initial clone. We intentionally have @@ -75,11 +59,12 @@ tasks: - /bin/bash - -cx - > - source $(which entrypoint) && + source ./bin/decision.sh && ./mach taskcluster-graph --message='{{comment}}' --project='{{project}}' --owner='{{owner}}' + --revision-hash='{{revision_hash}}' --extend-graph > /home/worker/graph.json graphs: - /home/worker/graph.json diff --git a/testing/taskcluster/tasks/test.yml b/testing/taskcluster/tasks/test.yml index 2a76e94753e5..2bc4cf0617c5 100644 --- a/testing/taskcluster/tasks/test.yml +++ b/testing/taskcluster/tasks/test.yml @@ -5,7 +5,7 @@ task: metadata: source: http://todo.com/soon owner: {{owner}} - workerType: test-c4-2xlarge + workerType: b2gtest provisionerId: aws-provisioner schedulerId: task-graph-scheduler From 8e0097faa19f7d79f0675e92346e13fffd941323 Mon Sep 17 00:00:00 2001 From: Nicolas Silva Date: Fri, 6 Feb 2015 18:02:59 +0100 Subject: [PATCH 36/62] Bug 1129360 - backout the part of the patch from bug 1127289 that causes intermittent r14 failures on the emulator. r=me --- gfx/layers/client/TiledContentClient.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/gfx/layers/client/TiledContentClient.cpp b/gfx/layers/client/TiledContentClient.cpp index afdf50dd3fcf..bcdffadb0696 100644 --- a/gfx/layers/client/TiledContentClient.cpp +++ b/gfx/layers/client/TiledContentClient.cpp @@ -1294,6 +1294,7 @@ ClientTiledLayerBuffer::ValidateTile(TileClient aTile, tileRegion.SubOut(GetValidRegion()); tileRegion.SubOut(aDirtyRegion); // Has now been validated + backBuffer->Unlock(); backBuffer->SetWaste(tileRegion.Area() * mResolution * mResolution); if (createdTextureClient) { From caa98c0c44cae3df07f904bf30eec1b2f9116641 Mon Sep 17 00:00:00 2001 From: Nick Fitzgerald Date: Fri, 6 Feb 2015 09:15:00 -0800 Subject: [PATCH 37/62] Bug 1117242 - Part 0: Define RootedGlobalObject in gc/Rooting.h instead of jsscript.cpp; r=jandem --- js/src/gc/Rooting.h | 2 ++ js/src/jsscript.cpp | 2 -- js/src/vm/GlobalObject.h | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/js/src/gc/Rooting.h b/js/src/gc/Rooting.h index ab38313521c0..2ec6de35d972 100644 --- a/js/src/gc/Rooting.h +++ b/js/src/gc/Rooting.h @@ -17,6 +17,7 @@ namespace js { class PropertyName; class NativeObject; class ArrayObject; +class GlobalObject; class PlainObject; class ScriptSourceObject; class Shape; @@ -31,6 +32,7 @@ typedef JS::Handle HandleAtom; typedef JS::Handle HandleLinearString; typedef JS::Handle HandlePropertyName; typedef JS::Handle HandleArrayObject; +typedef JS::Rooted RootedGlobalObject; typedef JS::Handle HandlePlainObject; typedef JS::Handle HandleScriptSource; diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp index f1da89afd6c0..3fea4b2c5bd6 100644 --- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -61,8 +61,6 @@ using mozilla::PodCopy; using mozilla::PodZero; using mozilla::RotateLeft; -typedef Rooted RootedGlobalObject; - /* static */ BindingIter Bindings::argumentsBinding(ExclusiveContext *cx, InternalBindingsHandle bindings) { diff --git a/js/src/vm/GlobalObject.h b/js/src/vm/GlobalObject.h index 628a07f8424a..65095e8473dc 100644 --- a/js/src/vm/GlobalObject.h +++ b/js/src/vm/GlobalObject.h @@ -306,7 +306,7 @@ class GlobalObject : public NativeObject NativeObject *getOrCreateObjectPrototype(JSContext *cx) { if (functionObjectClassesInitialized()) return &getPrototype(JSProto_Object).toObject().as(); - Rooted self(cx, this); + RootedGlobalObject self(cx, this); if (!ensureConstructor(cx, self, JSProto_Object)) return nullptr; return &self->getPrototype(JSProto_Object).toObject().as(); @@ -315,7 +315,7 @@ class GlobalObject : public NativeObject NativeObject *getOrCreateFunctionPrototype(JSContext *cx) { if (functionObjectClassesInitialized()) return &getPrototype(JSProto_Function).toObject().as(); - Rooted self(cx, this); + RootedGlobalObject self(cx, this); if (!ensureConstructor(cx, self, JSProto_Object)) return nullptr; return &self->getPrototype(JSProto_Function).toObject().as(); @@ -468,7 +468,7 @@ class GlobalObject : public NativeObject Value v = getSlotRef(slot); if (v.isObject()) return &v.toObject(); - Rooted self(cx, this); + RootedGlobalObject self(cx, this); if (!init(cx, self)) return nullptr; return &self->getSlot(slot).toObject(); @@ -546,7 +546,7 @@ class GlobalObject : public NativeObject } JSObject *getOrCreateDataViewPrototype(JSContext *cx) { - Rooted self(cx, this); + RootedGlobalObject self(cx, this); if (!ensureConstructor(cx, self, JSProto_DataView)) return nullptr; return &self->getPrototype(JSProto_DataView).toObject(); From 272bbfc82d42f7514faca3d234e17a29f7bb3946 Mon Sep 17 00:00:00 2001 From: Nick Fitzgerald Date: Fri, 6 Feb 2015 09:15:01 -0800 Subject: [PATCH 38/62] Bug 1117242 - Part 1: Make js::SavedFrame have a cached prototype and use js::ClassSpec; r=jandem --- js/src/jsprototypes.h | 2 + js/src/vm/GlobalObject.h | 7 ++ js/src/vm/SavedStacks.cpp | 131 +++++++++++++++++++------------------- js/src/vm/SavedStacks.h | 15 ++--- 4 files changed, 79 insertions(+), 76 deletions(-) diff --git a/js/src/jsprototypes.h b/js/src/jsprototypes.h index 467ee57608c2..07adfed41257 100644 --- a/js/src/jsprototypes.h +++ b/js/src/jsprototypes.h @@ -111,6 +111,8 @@ IF_SAB(real,imaginary)(SharedFloat64Array, 50, js_InitViaClassSpec, IF_SAB(real,imaginary)(SharedUint8ClampedArray, 51, js_InitViaClassSpec, SHARED_TYPED_ARRAY_CLASP(Uint8Clamped)) \ real(TypedArray, 52, js_InitViaClassSpec, &js::TypedArrayObject::sharedTypedArrayPrototypeClass) \ IF_SAB(real,imaginary)(Atomics, 53, js_InitAtomicsClass, OCLASP(Atomics)) \ + real(SavedFrame, 54, js_InitViaClassSpec, &js::SavedFrame::class_) \ + #define JS_FOR_EACH_PROTOTYPE(macro) JS_FOR_PROTOTYPES(macro,macro) diff --git a/js/src/vm/GlobalObject.h b/js/src/vm/GlobalObject.h index 65095e8473dc..69d824eed771 100644 --- a/js/src/vm/GlobalObject.h +++ b/js/src/vm/GlobalObject.h @@ -369,6 +369,13 @@ class GlobalObject : public NativeObject return nullptr; } + static NativeObject *getOrCreateSavedFramePrototype(JSContext *cx, + Handle global) { + if (!ensureConstructor(cx, global, JSProto_SavedFrame)) + return nullptr; + return &global->getPrototype(JSProto_SavedFrame).toObject().as(); + } + static JSObject *getOrCreateArrayBufferPrototype(JSContext *cx, Handle global) { if (!ensureConstructor(cx, global, JSProto_ArrayBuffer)) return nullptr; diff --git a/js/src/vm/SavedStacks.cpp b/js/src/vm/SavedStacks.cpp index b37e64dd4c26..0e2a9cb82e8d 100644 --- a/js/src/vm/SavedStacks.cpp +++ b/js/src/vm/SavedStacks.cpp @@ -16,12 +16,13 @@ #include "jshashutil.h" #include "jsmath.h" #include "jsnum.h" +#include "jsscript.h" #include "prmjtime.h" #include "gc/Marking.h" +#include "gc/Rooting.h" #include "js/Vector.h" #include "vm/Debugger.h" -#include "vm/GlobalObject.h" #include "vm/StringBuffer.h" #include "jscntxtinlines.h" @@ -136,18 +137,67 @@ SavedFrame::HashPolicy::rekey(Key &key, const Key &newKey) key = newKey; } +/* static */ bool +SavedFrame::finishSavedFrameInit(JSContext *cx, HandleObject ctor, HandleObject proto) +{ + // The only object with the SavedFrame::class_ that doesn't have a source + // should be the prototype. + proto->as().setReservedSlot(SavedFrame::JSSLOT_SOURCE, NullValue()); + + return FreezeObject(cx, proto); +} + /* static */ const Class SavedFrame::class_ = { "SavedFrame", JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS | - JSCLASS_HAS_RESERVED_SLOTS(SavedFrame::JSSLOT_COUNT), - nullptr, // addProperty - nullptr, // delProperty - nullptr, // getProperty - nullptr, // setProperty - nullptr, // enumerate - nullptr, // resolve - nullptr, // convert - SavedFrame::finalize + JSCLASS_HAS_RESERVED_SLOTS(SavedFrame::JSSLOT_COUNT) | + JSCLASS_HAS_CACHED_PROTO(JSProto_SavedFrame) | + JSCLASS_IS_ANONYMOUS, + nullptr, // addProperty + nullptr, // delProperty + nullptr, // getProperty + nullptr, // setProperty + nullptr, // enumerate + nullptr, // resolve + nullptr, // convert + SavedFrame::finalize, // finalize + nullptr, // call + nullptr, // hasInstance + nullptr, // construct + nullptr, // trace + + // ClassSpec + { + GenericCreateConstructor, + GenericCreatePrototype, + SavedFrame::staticFunctions, + SavedFrame::protoFunctions, + SavedFrame::protoAccessors, + SavedFrame::finishSavedFrameInit, + ClassSpec::DontDefineConstructor + } +}; + +/* static */ const JSFunctionSpec +SavedFrame::staticFunctions[] = { + JS_FS_END +}; + +/* static */ const JSFunctionSpec +SavedFrame::protoFunctions[] = { + JS_FN("constructor", SavedFrame::construct, 0, 0), + JS_FN("toString", SavedFrame::toStringMethod, 0, 0), + JS_FS_END +}; + +/* static */ const JSPropertySpec +SavedFrame::protoAccessors[] = { + JS_PSG("source", SavedFrame::sourceProperty, 0), + JS_PSG("line", SavedFrame::lineProperty, 0), + JS_PSG("column", SavedFrame::columnProperty, 0), + JS_PSG("functionDisplayName", SavedFrame::functionDisplayNameProperty, 0), + JS_PSG("parent", SavedFrame::parentProperty, 0), + JS_PS_END }; /* static */ void @@ -359,15 +409,6 @@ SavedFrame::parentProperty(JSContext *cx, unsigned argc, Value *vp) return true; } -/* static */ const JSPropertySpec SavedFrame::properties[] = { - JS_PSG("source", SavedFrame::sourceProperty, 0), - JS_PSG("line", SavedFrame::lineProperty, 0), - JS_PSG("column", SavedFrame::columnProperty, 0), - JS_PSG("functionDisplayName", SavedFrame::functionDisplayNameProperty, 0), - JS_PSG("parent", SavedFrame::parentProperty, 0), - JS_PS_END -}; - /* static */ bool SavedFrame::toStringMethod(JSContext *cx, unsigned argc, Value *vp) { @@ -403,12 +444,6 @@ SavedFrame::toStringMethod(JSContext *cx, unsigned argc, Value *vp) return true; } -/* static */ const JSFunctionSpec SavedFrame::methods[] = { - JS_FN("constructor", SavedFrame::construct, 0, 0), - JS_FN("toString", SavedFrame::toStringMethod, 0, 0), - JS_FS_END -}; - bool SavedStacks::init() { @@ -460,12 +495,6 @@ SavedStacks::sweep(JSRuntime *rt) } sweepPCLocationMap(); - - if (savedFrameProto.unbarrieredGet() && - IsObjectAboutToBeFinalizedFromAnyThread(savedFrameProto.unsafeGet())) - { - savedFrameProto.set(nullptr); - } } void @@ -587,49 +616,17 @@ SavedStacks::getOrCreateSavedFrame(JSContext *cx, SavedFrame::HandleLookup looku return frame; } -JSObject * -SavedStacks::getOrCreateSavedFramePrototype(JSContext *cx) -{ - if (savedFrameProto) - return savedFrameProto; - - Rooted global(cx, cx->compartment()->maybeGlobal()); - if (!global) - return nullptr; - - Rooted proto(cx, - NewObjectWithGivenProto(cx, global->getOrCreateObjectPrototype(cx), global)); - if (!proto - || !JS_DefineProperties(cx, proto, SavedFrame::properties) - || !JS_DefineFunctions(cx, proto, SavedFrame::methods) - || !FreezeObject(cx, proto)) - { - return nullptr; - } - - // The only object with the SavedFrame::class_ that doesn't have a source - // should be the prototype. - proto->setReservedSlot(SavedFrame::JSSLOT_SOURCE, NullValue()); - - savedFrameProto.set(proto); - return savedFrameProto; -} - SavedFrame * SavedStacks::createFrameFromLookup(JSContext *cx, SavedFrame::HandleLookup lookup) { - RootedObject proto(cx, getOrCreateSavedFramePrototype(cx)); + RootedGlobalObject global(cx, cx->global()); + assertSameCompartment(cx, global); + + RootedNativeObject proto(cx, GlobalObject::getOrCreateSavedFramePrototype(cx, global)); if (!proto) return nullptr; - assertSameCompartment(cx, proto); - RootedObject global(cx, cx->compartment()->maybeGlobal()); - if (!global) - return nullptr; - - assertSameCompartment(cx, global); - RootedObject frameObj(cx, NewObjectWithGivenProto(cx, &SavedFrame::class_, proto, global)); if (!frameObj) return nullptr; diff --git a/js/src/vm/SavedStacks.h b/js/src/vm/SavedStacks.h index 7ebde362a951..73e10465cbb7 100644 --- a/js/src/vm/SavedStacks.h +++ b/js/src/vm/SavedStacks.h @@ -20,10 +20,11 @@ class SavedFrame : public NativeObject { public: static const Class class_; static void finalize(FreeOp *fop, JSObject *obj); + static const JSPropertySpec protoAccessors[]; + static const JSFunctionSpec protoFunctions[]; + static const JSFunctionSpec staticFunctions[]; // Prototype methods and properties to be exposed to JS. - static const JSPropertySpec properties[]; - static const JSFunctionSpec methods[]; static bool construct(JSContext *cx, unsigned argc, Value *vp); static bool sourceProperty(JSContext *cx, unsigned argc, Value *vp); static bool lineProperty(JSContext *cx, unsigned argc, Value *vp); @@ -53,6 +54,7 @@ class SavedFrame : public NativeObject { class HandleLookup; private: + static bool finishSavedFrameInit(JSContext *cx, HandleObject ctor, HandleObject proto); void initFromLookup(HandleLookup lookup); enum { @@ -77,8 +79,8 @@ class SavedFrame : public NativeObject { // know that GC moved the parent and we need to update our private value and // rekey the saved frame in its hash set. These two methods are helpers for // this process. - bool parentMoved(); - void updatePrivateParent(); + bool parentMoved(); + void updatePrivateParent(); static SavedFrame *checkThis(JSContext *cx, CallArgs &args, const char *fnName); }; @@ -106,7 +108,6 @@ class SavedStacks { public: SavedStacks() : frames(), - savedFrameProto(nullptr), allocationSamplingProbability(1.0), allocationSkipCount(0), // XXX: Initialize the RNG state to 0 so that random_initSeed is lazily @@ -129,7 +130,6 @@ class SavedStacks { private: SavedFrame::Set frames; - ReadBarrieredObject savedFrameProto; double allocationSamplingProbability; uint32_t allocationSkipCount; uint64_t rngState; @@ -137,9 +137,6 @@ class SavedStacks { bool insertFrames(JSContext *cx, FrameIter &iter, MutableHandleSavedFrame frame, unsigned maxFrameCount = 0); SavedFrame *getOrCreateSavedFrame(JSContext *cx, SavedFrame::HandleLookup lookup); - // |SavedFrame.prototype| is created lazily and held weakly. It should only - // be accessed through this method. - JSObject *getOrCreateSavedFramePrototype(JSContext *cx); SavedFrame *createFrameFromLookup(JSContext *cx, SavedFrame::HandleLookup lookup); void chooseSamplingProbability(JSContext* cx); From 2b2ed10b4df38d57799d8d5a6cb16cb3e8a40dc2 Mon Sep 17 00:00:00 2001 From: Nick Fitzgerald Date: Fri, 6 Feb 2015 09:15:01 -0800 Subject: [PATCH 39/62] Bug 1117242 - Part 2: SavedFrame accessors should always check principals. r=jandem --- js/src/builtin/TestingFunctions.cpp | 35 ++++++-- .../tests/saved-stacks/principals-03.js | 23 ++++++ .../tests/saved-stacks/principals-04.js | 15 ++++ js/src/vm/SavedStacks.cpp | 82 ++++++++++++------- js/src/vm/SavedStacks.h | 12 +-- 5 files changed, 125 insertions(+), 42 deletions(-) create mode 100644 js/src/jit-test/tests/saved-stacks/principals-03.js create mode 100644 js/src/jit-test/tests/saved-stacks/principals-04.js diff --git a/js/src/builtin/TestingFunctions.cpp b/js/src/builtin/TestingFunctions.cpp index 2af889443b78..5c7df16e14ab 100644 --- a/js/src/builtin/TestingFunctions.cpp +++ b/js/src/builtin/TestingFunctions.cpp @@ -967,9 +967,30 @@ SaveStack(JSContext *cx, unsigned argc, jsval *vp) maxFrameCount = d; } - Rooted stack(cx); - if (!JS::CaptureCurrentStack(cx, &stack, maxFrameCount)) + JSCompartment *targetCompartment = cx->compartment(); + if (args.length() >= 2) { + if (!args[1].isObject()) { + js_ReportValueErrorFlags(cx, JSREPORT_ERROR, JSMSG_UNEXPECTED_TYPE, + JSDVG_SEARCH_STACK, args[0], JS::NullPtr(), + "not an object", NULL); + return false; + } + RootedObject obj(cx, UncheckedUnwrap(&args[1].toObject())); + if (!obj) + return false; + targetCompartment = obj->compartment(); + } + + RootedObject stack(cx); + { + AutoCompartment ac(cx, targetCompartment); + if (!JS::CaptureCurrentStack(cx, &stack, maxFrameCount)) + return false; + } + + if (stack && !cx->compartment()->wrap(cx, &stack)) return false; + args.rval().setObjectOrNull(stack); return true; } @@ -2396,13 +2417,15 @@ static const JSFunctionSpecWithHelp TestingFunctions[] = { " SavedStacks cache."), JS_FN_HELP("saveStack", SaveStack, 0, 0, -"saveStack()", -" Capture a stack.\n"), +"saveStack([maxDepth [, compartment]])", +" Capture a stack. If 'maxDepth' is given, capture at most 'maxDepth' number\n" +" of frames. If 'compartment' is given, allocate the js::SavedFrame instances\n" +" with the given object's compartment."), JS_FN_HELP("enableTrackAllocations", EnableTrackAllocations, 0, 0, "enableTrackAllocations()", -" Start capturing the JS stack at every allocation. Note that this sets an " -" object metadata callback that will override any other object metadata " +" Start capturing the JS stack at every allocation. Note that this sets an\n" +" object metadata callback that will override any other object metadata\n" " callback that may be set."), JS_FN_HELP("disableTrackAllocations", DisableTrackAllocations, 0, 0, diff --git a/js/src/jit-test/tests/saved-stacks/principals-03.js b/js/src/jit-test/tests/saved-stacks/principals-03.js new file mode 100644 index 000000000000..006b4477cd67 --- /dev/null +++ b/js/src/jit-test/tests/saved-stacks/principals-03.js @@ -0,0 +1,23 @@ +// With arrows representing child-to-parent links, create a SavedFrame stack +// like this: +// +// high.a -> low.b +// +// in `low`'s compartment and give `low` a reference to this stack. Assert the +// stack's youngest frame's properties doesn't leak information about `high.a` +// that `low` shouldn't have access to, and instead returns information about +// `low.b`. + +var low = newGlobal({ principal: 0 }); +var high = newGlobal({ principal: 0xfffff }); + +low.high = high; +high.low = low; + +high.eval("function a() { return saveStack(0, low); }"); +low.eval("function b() { return high.a(); }") + +var stack = low.b(); + +assertEq(stack.functionDisplayName, "b"); +assertEq(stack.parent, null); diff --git a/js/src/jit-test/tests/saved-stacks/principals-04.js b/js/src/jit-test/tests/saved-stacks/principals-04.js new file mode 100644 index 000000000000..3a9b57800584 --- /dev/null +++ b/js/src/jit-test/tests/saved-stacks/principals-04.js @@ -0,0 +1,15 @@ +// Test what happens when a compartment gets a SavedFrame that it doesn't have +// the principals to access any of its frames. + +var low = newGlobal({ principal: 0 }); +var high = newGlobal({ principal: 0xfffff }); + +low.high = high; +high.low = low; + +high.eval("function a() { return saveStack(1, low); }"); +var stack = low.eval("high.a();") + +assertEq(stack.functionDisplayName, null); +assertEq(stack.parent, null); +assertEq(stack.toString(), ""); diff --git a/js/src/vm/SavedStacks.cpp b/js/src/vm/SavedStacks.cpp index 0e2a9cb82e8d..bb3d233395f4 100644 --- a/js/src/vm/SavedStacks.cpp +++ b/js/src/vm/SavedStacks.cpp @@ -309,21 +309,42 @@ SavedFrame::construct(JSContext *cx, unsigned argc, Value *vp) return false; } -/* static */ SavedFrame * -SavedFrame::checkThis(JSContext *cx, CallArgs &args, const char *fnName) +// Return the first SavedFrame in the chain that starts with |frame| whose +// principals are subsumed by |principals|, according to |subsumes|. If there is +// no such frame, return nullptr. +static SavedFrame * +GetFirstSubsumedFrame(JSContext *cx, SavedFrame *frame) +{ + JSSubsumesOp subsumes = cx->runtime()->securityCallbacks->subsumes; + if (!subsumes) + return frame; + + JSPrincipals *principals = cx->compartment()->principals; + if (!principals) + return frame; + + while (frame && !subsumes(principals, frame->getPrincipals())) + frame = frame->getParent(); + + return frame; +} + +/* static */ bool +SavedFrame::checkThis(JSContext *cx, CallArgs &args, const char *fnName, + MutableHandleSavedFrame frame) { const Value &thisValue = args.thisv(); if (!thisValue.isObject()) { JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT); - return nullptr; + return false; } JSObject &thisObject = thisValue.toObject(); if (!thisObject.is()) { JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_INCOMPATIBLE_PROTO, SavedFrame::class_.name, fnName, thisObject.getClass()->name); - return nullptr; + return false; } // Check for SavedFrame.prototype, which has the same class as SavedFrame @@ -332,10 +353,13 @@ SavedFrame::checkThis(JSContext *cx, CallArgs &args, const char *fnName) if (thisObject.as().getReservedSlot(JSSLOT_SOURCE).isNull()) { JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_INCOMPATIBLE_PROTO, SavedFrame::class_.name, fnName, "prototype object"); - return nullptr; + return false; } - return &thisObject.as(); + // The caller might not have the principals to see this frame's data, so get + // the first one they _do_ have access to. + frame.set(GetFirstSubsumedFrame(cx, &thisObject.as())); + return true; } // Get the SavedFrame * from the current this value and handle any errors that @@ -346,19 +370,24 @@ SavedFrame::checkThis(JSContext *cx, CallArgs &args, const char *fnName) // - unsigned argc // - Value *vp // - const char *fnName +// - Value defaultVal // These parameters will be defined after calling this macro: // - CallArgs args // - Rooted frame (will be non-null) -#define THIS_SAVEDFRAME(cx, argc, vp, fnName, args, frame) \ - CallArgs args = CallArgsFromVp(argc, vp); \ - RootedSavedFrame frame(cx, checkThis(cx, args, fnName)); \ - if (!frame) \ - return false +#define THIS_SAVEDFRAME(cx, argc, vp, fnName, defaultVal, args, frame) \ + CallArgs args = CallArgsFromVp(argc, vp); \ + RootedSavedFrame frame(cx); \ + if (!checkThis(cx, args, fnName, &frame)) \ + return false; \ + if (!frame) { \ + args.rval().set(defaultVal); \ + return true; \ + } /* static */ bool SavedFrame::sourceProperty(JSContext *cx, unsigned argc, Value *vp) { - THIS_SAVEDFRAME(cx, argc, vp, "(get source)", args, frame); + THIS_SAVEDFRAME(cx, argc, vp, "(get source)", NullValue(), args, frame); args.rval().setString(frame->getSource()); return true; } @@ -366,7 +395,7 @@ SavedFrame::sourceProperty(JSContext *cx, unsigned argc, Value *vp) /* static */ bool SavedFrame::lineProperty(JSContext *cx, unsigned argc, Value *vp) { - THIS_SAVEDFRAME(cx, argc, vp, "(get line)", args, frame); + THIS_SAVEDFRAME(cx, argc, vp, "(get line)", NullValue(), args, frame); uint32_t line = frame->getLine(); args.rval().setNumber(line); return true; @@ -375,7 +404,7 @@ SavedFrame::lineProperty(JSContext *cx, unsigned argc, Value *vp) /* static */ bool SavedFrame::columnProperty(JSContext *cx, unsigned argc, Value *vp) { - THIS_SAVEDFRAME(cx, argc, vp, "(get column)", args, frame); + THIS_SAVEDFRAME(cx, argc, vp, "(get column)", NullValue(), args, frame); uint32_t column = frame->getColumn(); args.rval().setNumber(column); return true; @@ -384,7 +413,7 @@ SavedFrame::columnProperty(JSContext *cx, unsigned argc, Value *vp) /* static */ bool SavedFrame::functionDisplayNameProperty(JSContext *cx, unsigned argc, Value *vp) { - THIS_SAVEDFRAME(cx, argc, vp, "(get functionDisplayName)", args, frame); + THIS_SAVEDFRAME(cx, argc, vp, "(get functionDisplayName)", NullValue(), args, frame); RootedAtom name(cx, frame->getFunctionDisplayName()); if (name) args.rval().setString(name); @@ -396,30 +425,21 @@ SavedFrame::functionDisplayNameProperty(JSContext *cx, unsigned argc, Value *vp) /* static */ bool SavedFrame::parentProperty(JSContext *cx, unsigned argc, Value *vp) { - THIS_SAVEDFRAME(cx, argc, vp, "(get parent)", args, frame); - JSSubsumesOp subsumes = cx->runtime()->securityCallbacks->subsumes; - JSPrincipals *principals = cx->compartment()->principals; - - do - frame = frame->getParent(); - while (frame && principals && subsumes && - !subsumes(principals, frame->getPrincipals())); - - args.rval().setObjectOrNull(frame); + THIS_SAVEDFRAME(cx, argc, vp, "(get parent)", NullValue(), args, frame); + args.rval().setObjectOrNull(GetFirstSubsumedFrame(cx, frame->getParent())); return true; } /* static */ bool SavedFrame::toStringMethod(JSContext *cx, unsigned argc, Value *vp) { - THIS_SAVEDFRAME(cx, argc, vp, "toString", args, frame); + THIS_SAVEDFRAME(cx, argc, vp, "toString", StringValue(cx->runtime()->emptyString), args, frame); StringBuffer sb(cx); - JSSubsumesOp subsumes = cx->runtime()->securityCallbacks->subsumes; - JSPrincipals *principals = cx->compartment()->principals; + DebugOnly subsumes = cx->runtime()->securityCallbacks->subsumes; + DebugOnly principals = cx->compartment()->principals; do { - if (principals && subsumes && !subsumes(principals, frame->getPrincipals())) - continue; + MOZ_ASSERT_IF(principals && subsumes, (*subsumes)(principals, frame->getPrincipals())); if (frame->isSelfHosted()) continue; @@ -435,7 +455,7 @@ SavedFrame::toStringMethod(JSContext *cx, unsigned argc, Value *vp) { return false; } - } while ((frame = frame->getParent())); + } while ((frame = GetFirstSubsumedFrame(cx, frame->getParent()))); JSString *str = sb.finishString(); if (!str) diff --git a/js/src/vm/SavedStacks.h b/js/src/vm/SavedStacks.h index 73e10465cbb7..a73fa5d3f1cf 100644 --- a/js/src/vm/SavedStacks.h +++ b/js/src/vm/SavedStacks.h @@ -14,6 +14,11 @@ namespace js { +class SavedFrame; +typedef JS::Handle HandleSavedFrame; +typedef JS::MutableHandle MutableHandleSavedFrame; +typedef JS::Rooted RootedSavedFrame; + class SavedFrame : public NativeObject { friend class SavedStacks; @@ -82,13 +87,10 @@ class SavedFrame : public NativeObject { bool parentMoved(); void updatePrivateParent(); - static SavedFrame *checkThis(JSContext *cx, CallArgs &args, const char *fnName); + static bool checkThis(JSContext *cx, CallArgs &args, const char *fnName, + MutableHandleSavedFrame frame); }; -typedef JS::Handle HandleSavedFrame; -typedef JS::MutableHandle MutableHandleSavedFrame; -typedef JS::Rooted RootedSavedFrame; - struct SavedFrame::HashPolicy { typedef SavedFrame::Lookup Lookup; From e7ba3f4f4d2581ee8285759f7144af2f38edcdb3 Mon Sep 17 00:00:00 2001 From: Nick Fitzgerald Date: Fri, 6 Feb 2015 09:15:01 -0800 Subject: [PATCH 40/62] Bug 1117242 - Part 3: Don't skip subsumes checks when principals are null; r=jimb --- js/src/jit-test/tests/saved-stacks/principals-01.js | 2 +- js/src/jit-test/tests/saved-stacks/principals-02.js | 2 +- js/src/vm/SavedStacks.cpp | 4 +--- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/js/src/jit-test/tests/saved-stacks/principals-01.js b/js/src/jit-test/tests/saved-stacks/principals-01.js index 1c67956b2df7..62640472dc33 100644 --- a/js/src/jit-test/tests/saved-stacks/principals-01.js +++ b/js/src/jit-test/tests/saved-stacks/principals-01.js @@ -42,7 +42,7 @@ var count = 0; low .eval('function b() { check("b", extract(saveStack())); c(); }'); mid .eval('function c() { check("cba", extract(saveStack())); d(); }'); high.eval('function d() { check("dcba", extract(saveStack())); e(); }'); - eval('function e() { check("edcba", extract(saveStack())); f(); }'); // no principal, so checks skipped + eval('function e() { check("ecba", extract(saveStack())); f(); }'); low .eval('function f() { check("fb", extract(saveStack())); g(); }'); mid .eval('function g() { check("gfecba", extract(saveStack())); h(); }'); high.eval('function h() { check("hgfedcba", extract(saveStack())); }'); diff --git a/js/src/jit-test/tests/saved-stacks/principals-02.js b/js/src/jit-test/tests/saved-stacks/principals-02.js index 796c48b06944..24ffa82a875b 100644 --- a/js/src/jit-test/tests/saved-stacks/principals-02.js +++ b/js/src/jit-test/tests/saved-stacks/principals-02.js @@ -33,7 +33,7 @@ var high = newGlobal({ principal: 0xfffff }); low .eval('function b() { check("b", saveStack().toString()); c(); }'); mid .eval('function c() { check("cba", saveStack().toString()); d(); }'); high.eval('function d() { check("dcba", saveStack().toString()); e(); }'); - eval('function e() { check("edcba", saveStack().toString()); f(); }'); // no principal, so checks skipped + eval('function e() { check("ecba", saveStack().toString()); f(); }'); low .eval('function f() { check("fb", saveStack().toString()); g(); }'); mid .eval('function g() { check("gfecba", saveStack().toString()); h(); }'); high.eval('function h() { check("hgfedcba", saveStack().toString()); }'); diff --git a/js/src/vm/SavedStacks.cpp b/js/src/vm/SavedStacks.cpp index bb3d233395f4..4089510f02cc 100644 --- a/js/src/vm/SavedStacks.cpp +++ b/js/src/vm/SavedStacks.cpp @@ -320,8 +320,6 @@ GetFirstSubsumedFrame(JSContext *cx, SavedFrame *frame) return frame; JSPrincipals *principals = cx->compartment()->principals; - if (!principals) - return frame; while (frame && !subsumes(principals, frame->getPrincipals())) frame = frame->getParent(); @@ -439,7 +437,7 @@ SavedFrame::toStringMethod(JSContext *cx, unsigned argc, Value *vp) DebugOnly principals = cx->compartment()->principals; do { - MOZ_ASSERT_IF(principals && subsumes, (*subsumes)(principals, frame->getPrincipals())); + MOZ_ASSERT_IF(subsumes, (*subsumes)(principals, frame->getPrincipals())); if (frame->isSelfHosted()) continue; From af47ed917acbc9da2b32f64d102545eb43f8e588 Mon Sep 17 00:00:00 2001 From: Nick Fitzgerald Date: Fri, 6 Feb 2015 09:15:01 -0800 Subject: [PATCH 41/62] Bug 1117242 - Part 4: SavedFrame::checkThis should unwrap the this value; r=jimb --- js/src/vm/SavedStacks.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/js/src/vm/SavedStacks.cpp b/js/src/vm/SavedStacks.cpp index 4089510f02cc..3e356763720c 100644 --- a/js/src/vm/SavedStacks.cpp +++ b/js/src/vm/SavedStacks.cpp @@ -338,17 +338,18 @@ SavedFrame::checkThis(JSContext *cx, CallArgs &args, const char *fnName, return false; } - JSObject &thisObject = thisValue.toObject(); - if (!thisObject.is()) { + JSObject *thisObject = CheckedUnwrap(&thisValue.toObject()); + if (!thisObject || !thisObject->is()) { JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_INCOMPATIBLE_PROTO, - SavedFrame::class_.name, fnName, thisObject.getClass()->name); + SavedFrame::class_.name, fnName, + thisObject ? thisObject->getClass()->name : "object"); return false; } // Check for SavedFrame.prototype, which has the same class as SavedFrame // instances, however doesn't actually represent a captured stack frame. It // is the only object that is() but doesn't have a source. - if (thisObject.as().getReservedSlot(JSSLOT_SOURCE).isNull()) { + if (thisObject->as().getReservedSlot(JSSLOT_SOURCE).isNull()) { JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_INCOMPATIBLE_PROTO, SavedFrame::class_.name, fnName, "prototype object"); return false; @@ -356,7 +357,7 @@ SavedFrame::checkThis(JSContext *cx, CallArgs &args, const char *fnName, // The caller might not have the principals to see this frame's data, so get // the first one they _do_ have access to. - frame.set(GetFirstSubsumedFrame(cx, &thisObject.as())); + frame.set(GetFirstSubsumedFrame(cx, &thisObject->as())); return true; } From 26ceac32de8dc7dd37ff85a7fd3c511d84a18270 Mon Sep 17 00:00:00 2001 From: Nick Fitzgerald Date: Fri, 6 Feb 2015 09:15:01 -0800 Subject: [PATCH 42/62] Bug 1117242 - Part 5: Implement xray support for SavedFrame; r=bholley --- js/xpconnect/src/xpcprivate.h | 2 +- .../tests/unit/test_xray_SavedFrame.js | 108 ++++++++++++++++++ js/xpconnect/tests/unit/xpcshell.ini | 1 + js/xpconnect/wrappers/XrayWrapper.cpp | 1 + 4 files changed, 111 insertions(+), 1 deletion(-) create mode 100644 js/xpconnect/tests/unit/test_xray_SavedFrame.js diff --git a/js/xpconnect/src/xpcprivate.h b/js/xpconnect/src/xpcprivate.h index 7420f0a94b89..8816cf5026a9 100644 --- a/js/xpconnect/src/xpcprivate.h +++ b/js/xpconnect/src/xpcprivate.h @@ -507,7 +507,7 @@ public: // Mapping of often used strings to jsid atoms that live 'forever'. // // To add a new string: add to this list and to XPCJSRuntime::mStrings - // at the top of xpcjsruntime.cpp + // at the top of XPCJSRuntime.cpp enum { IDX_CONSTRUCTOR = 0 , IDX_TO_STRING , diff --git a/js/xpconnect/tests/unit/test_xray_SavedFrame.js b/js/xpconnect/tests/unit/test_xray_SavedFrame.js new file mode 100644 index 000000000000..6a931cff0cea --- /dev/null +++ b/js/xpconnect/tests/unit/test_xray_SavedFrame.js @@ -0,0 +1,108 @@ +// Bug 1117242: Test calling SavedFrame getters from globals that don't subsume +// that frame's principals. + +const Cc = Components.classes; +const Ci = Components.interfaces; +const Cu = Components.utils; + +Cu.import("resource://gre/modules/jsdebugger.jsm"); +addDebuggerToGlobal(this); + +const lowP = Cc["@mozilla.org/nullprincipal;1"].createInstance(Ci.nsIPrincipal); +const midP = [lowP, "http://other.com"]; +const highP = Cc["@mozilla.org/systemprincipal;1"].createInstance(Ci.nsIPrincipal); + +const low = new Cu.Sandbox(lowP); +const mid = new Cu.Sandbox(midP); +const high = new Cu.Sandbox(highP); + +function run_test() { + // Test that the priveleged view of a SavedFrame from a subsumed compartment + // is the same view that the subsumed compartment gets. Create the following + // chain of function calls (with some intermediate system-principaled frames + // due to implementation): + // + // low.lowF -> mid.midF -> high.highF -> high.saveStack + // + // Where high.saveStack gets monkey patched to create stacks in each of our + // sandboxes. + + Cu.evalInSandbox("function highF() { return saveStack(); }", high); + + mid.highF = () => high.highF(); + Cu.evalInSandbox("function midF() { return highF(); }", mid); + + low.midF = () => mid.midF(); + Cu.evalInSandbox("function lowF() { return midF(); }", low); + + const expected = [ + { + sandbox: low, + frames: ["lowF"], + }, + { + sandbox: mid, + frames: ["midF", "lowF"], + }, + { + sandbox: high, + frames: ["getSavedFrameInstanceFromSandbox", + "saveStack", + "highF", + "run_test/mid.highF", + "midF", + "run_test/low.midF", + "lowF", + "run_test", + "_execute_test", + null], + } + ]; + + for (let { sandbox, frames } of expected) { + high.saveStack = function saveStack() { + return getSavedFrameInstanceFromSandbox(sandbox); + }; + + const xrayStack = low.lowF(); + equal(xrayStack.functionDisplayName, "getSavedFrameInstanceFromSandbox", + "Xrays should always be able to see everything."); + + let waived = Cu.waiveXrays(xrayStack); + do { + ok(frames.length, + "There should still be more expected frames while we have actual frames."); + equal(waived.functionDisplayName, frames.shift(), + "The waived wrapper should give us the stack's compartment's view."); + waived = waived.parent; + } while (waived); + } +} + +// Get a SavedFrame instance from inside the given sandbox. +// +// We can't use Cu.getJSTestingFunctions().saveStack() because Cu isn't +// available to sandboxes that don't have the system principal. The easiest way +// to get the SavedFrame is to use the Debugger API to track allocation sites +// and then do an allocation. +function getSavedFrameInstanceFromSandbox(sandbox) { + const dbg = new Debugger(sandbox); + + dbg.memory.trackingAllocationSites = true; + Cu.evalInSandbox("new Object", sandbox); + const allocs = dbg.memory.drainAllocationsLog(); + dbg.memory.trackingAllocationSites = false; + + ok(allocs[0], "We should observe the allocation"); + const { frame } = allocs[0]; + + if (sandbox !== high) { + ok(Cu.isXrayWrapper(frame), "`frame` should be an xray..."); + equal(Object.prototype.toString.call(Cu.waiveXrays(frame)), + "[object SavedFrame]", + "...and that xray should wrap a SavedFrame"); + } + + return frame; +} + diff --git a/js/xpconnect/tests/unit/xpcshell.ini b/js/xpconnect/tests/unit/xpcshell.ini index 9195ca709125..9dd5fa698765 100644 --- a/js/xpconnect/tests/unit/xpcshell.ini +++ b/js/xpconnect/tests/unit/xpcshell.ini @@ -108,3 +108,4 @@ head = head_watchdog.js head = head_watchdog.js [test_writeToGlobalPrototype.js] [test_xrayed_iterator.js] +[test_xray_SavedFrame.js] \ No newline at end of file diff --git a/js/xpconnect/wrappers/XrayWrapper.cpp b/js/xpconnect/wrappers/XrayWrapper.cpp index a7d11ae12c4b..d869d144c1de 100644 --- a/js/xpconnect/wrappers/XrayWrapper.cpp +++ b/js/xpconnect/wrappers/XrayWrapper.cpp @@ -83,6 +83,7 @@ IsJSXraySupported(JSProtoKey key) case JSProto_Array: case JSProto_Function: case JSProto_TypedArray: + case JSProto_SavedFrame: return true; default: return false; From 1a7abb0ab07a1ce220543da4402710cf2634c92b Mon Sep 17 00:00:00 2001 From: Nick Fitzgerald Date: Fri, 6 Feb 2015 09:15:01 -0800 Subject: [PATCH 43/62] Bug 1117242 - Part 6: Document including or excluding chrome frames in SavedFrame stacks. r=me --- js/src/doc/SavedFrame/SavedFrame.md | 38 +++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/js/src/doc/SavedFrame/SavedFrame.md b/js/src/doc/SavedFrame/SavedFrame.md index 2bad954f35a1..3dcafe998a83 100644 --- a/js/src/doc/SavedFrame/SavedFrame.md +++ b/js/src/doc/SavedFrame/SavedFrame.md @@ -5,6 +5,44 @@ JavaScript call stack at a past moment of execution. Younger frames hold a reference to the frames that invoked them. The older tails are shared across many younger frames. +`SavedFrame` stacks should generally be captured, allocated, and live within the +compartment that is being observed or debugged. Usually this is a content +compartment. + +## Capturing `SavedFrame` Stacks + +### From C++ + +Use `JS::CaptureCurrentStack` declared in `jsapi.h`. + +### From JS + +Use `saveStack`, accessible via `Components.utils.getJSTestingFunction()`. + +## Including and Excluding Chrome Frames + +Consider the following `SavedFrame` stack. Arrows represent links from child to +parent frame, `content.js` is from a compartment with content principals, and +`chrome.js` is from a compartment with chrome principals. + + function A from content.js + | + V + function B from chrome.js + | + V + function C from content.js + +The content compartment will ever have one view of this stack: `A -> C`. + +However, a chrome compartment has a choice: it can either take the same view +that the content compartment has (`A -> C`), or it can view all stack frames, +including the frames from chrome compartments (`A -> B -> C`). To view +everything, use an `XrayWrapper`. This is the default wrapper. To see the stack +as the content compartment sees it, waive the xray wrapper with +`Components.utils.waiveXrays`: + + const contentViewOfStack = Components.utils.waiveXrays(someStack); ## Accessor Properties of the `SavedFrame.prototype` Object From 63b022725c5da305b27e13e6164f0d164010d257 Mon Sep 17 00:00:00 2001 From: Jan de Mooij Date: Fri, 6 Feb 2015 18:09:35 +0100 Subject: [PATCH 44/62] Bug 1129875 - Remove unused AssertOnScriptEntryHook. r=luke --HG-- extra : rebase_source : f97e83175753796c1f6865591e3696e180119041 --- js/src/jsfriendapi.cpp | 8 -------- js/src/jsfriendapi.h | 7 ------- js/src/vm/Interpreter.cpp | 5 ----- js/src/vm/Runtime.cpp | 3 --- js/src/vm/Runtime.h | 4 ---- 5 files changed, 27 deletions(-) diff --git a/js/src/jsfriendapi.cpp b/js/src/jsfriendapi.cpp index 498bfa05c0d7..746f361ff2e1 100644 --- a/js/src/jsfriendapi.cpp +++ b/js/src/jsfriendapi.cpp @@ -64,14 +64,6 @@ js::ForgetSourceHook(JSRuntime *rt) return Move(rt->sourceHook); } -#ifdef NIGHTLY_BUILD -JS_FRIEND_API(void) -js::SetAssertOnScriptEntryHook(JSRuntime *rt, AssertOnScriptEntryHook hook) -{ - rt->assertOnScriptEntryHook_ = hook; -} -#endif - JS_FRIEND_API(void) JS_SetGrayGCRootsTracer(JSRuntime *rt, JSTraceDataOp traceOp, void *data) { diff --git a/js/src/jsfriendapi.h b/js/src/jsfriendapi.h index 7638d2c9bf27..c4373ce6e37e 100644 --- a/js/src/jsfriendapi.h +++ b/js/src/jsfriendapi.h @@ -409,13 +409,6 @@ SetSourceHook(JSRuntime *rt, mozilla::UniquePtr hook); extern JS_FRIEND_API(mozilla::UniquePtr) ForgetSourceHook(JSRuntime *rt); -#ifdef NIGHTLY_BUILD -typedef void (*AssertOnScriptEntryHook)(JSContext *cx, JS::HandleScript script); - -extern JS_FRIEND_API(void) -SetAssertOnScriptEntryHook(JSRuntime *rt, AssertOnScriptEntryHook hook); -#endif - extern JS_FRIEND_API(JS::Zone *) GetCompartmentZone(JSCompartment *comp); diff --git a/js/src/vm/Interpreter.cpp b/js/src/vm/Interpreter.cpp index c65f41cd28b4..ee4c37708880 100644 --- a/js/src/vm/Interpreter.cpp +++ b/js/src/vm/Interpreter.cpp @@ -411,11 +411,6 @@ js::RunScript(JSContext *cx, RunState &state) { JS_CHECK_RECURSION(cx, return false); -#ifdef NIGHTLY_BUILD - if (AssertOnScriptEntryHook hook = cx->runtime()->assertOnScriptEntryHook_) - (*hook)(cx, state.script()); -#endif - SPSEntryMarker marker(cx->runtime(), state.script()); state.script()->ensureNonLazyCanonicalFunction(cx); diff --git a/js/src/vm/Runtime.cpp b/js/src/vm/Runtime.cpp index 69986ff8515a..3c740baa6b9e 100644 --- a/js/src/vm/Runtime.cpp +++ b/js/src/vm/Runtime.cpp @@ -164,9 +164,6 @@ JSRuntime::JSRuntime(JSRuntime *parentRuntime) negativeInfinityValue(DoubleValue(NegativeInfinity())), positiveInfinityValue(DoubleValue(PositiveInfinity())), emptyString(nullptr), -#ifdef NIGHTLY_BUILD - assertOnScriptEntryHook_(nullptr), -#endif spsProfiler(thisFromCtor()), profilingScripts(false), suppressProfilerSampling(false), diff --git a/js/src/vm/Runtime.h b/js/src/vm/Runtime.h index 9bd61c97b722..1a9152196f72 100644 --- a/js/src/vm/Runtime.h +++ b/js/src/vm/Runtime.h @@ -987,10 +987,6 @@ struct JSRuntime : public JS::shadow::Runtime, mozilla::UniquePtr sourceHook; -#ifdef NIGHTLY_BUILD - js::AssertOnScriptEntryHook assertOnScriptEntryHook_; -#endif - /* SPS profiling metadata */ js::SPSProfiler spsProfiler; From 39739425fcfcf5d9bebdc6775da6a8cfe3cc1ce8 Mon Sep 17 00:00:00 2001 From: Jan de Mooij Date: Fri, 6 Feb 2015 18:17:00 +0100 Subject: [PATCH 45/62] Bug 1129473 - Ensure off-thread parsing sets the is-delegate flag on builtin protos. r=bhackett --HG-- extra : rebase_source : 2eab0362e1207c1bc258346d427498f14ddf1b04 --- js/src/jsobj.h | 4 +--- js/src/vm/HelperThreads.cpp | 19 ++++++++++++++----- js/src/vm/ObjectGroup.cpp | 7 +++++++ js/src/vm/ObjectGroup.h | 4 +--- 4 files changed, 23 insertions(+), 11 deletions(-) diff --git a/js/src/jsobj.h b/js/src/jsobj.h index 5769ee407d1d..9ab325d74d94 100644 --- a/js/src/jsobj.h +++ b/js/src/jsobj.h @@ -353,9 +353,7 @@ class JSObject : public js::gc::Cell JSObject *getProto() const { MOZ_ASSERT(!uninlinedIsProxy()); - JSObject *proto = getTaggedProto().toObjectOrNull(); - MOZ_ASSERT_IF(proto && proto->isNative(), proto->isDelegate()); - return proto; + return getTaggedProto().toObjectOrNull(); } // Normal objects and a subset of proxies have uninteresting [[Prototype]]. diff --git a/js/src/vm/HelperThreads.cpp b/js/src/vm/HelperThreads.cpp index 4b197b25a8a2..5004630bd38b 100644 --- a/js/src/vm/HelperThreads.cpp +++ b/js/src/vm/HelperThreads.cpp @@ -845,6 +845,15 @@ LeaveParseTaskZone(JSRuntime *rt, ParseTask *task) rt->clearUsedByExclusiveThread(task->cx->zone()); } +static bool +EnsureConstructor(JSContext *cx, Handle global, JSProtoKey key) +{ + if (!GlobalObject::ensureConstructor(cx, global, key)) + return false; + + return global->getPrototype(key).toObject().setDelegate(cx); +} + JSScript * GlobalHelperThreadState::finishParseTask(JSContext *maybecx, JSRuntime *rt, void *token) { @@ -876,11 +885,11 @@ GlobalHelperThreadState::finishParseTask(JSContext *maybecx, JSRuntime *rt, void // Make sure we have all the constructors we need for the prototype // remapping below, since we can't GC while that's happening. Rooted global(cx, &cx->global()->as()); - if (!GlobalObject::ensureConstructor(cx, global, JSProto_Object) || - !GlobalObject::ensureConstructor(cx, global, JSProto_Array) || - !GlobalObject::ensureConstructor(cx, global, JSProto_Function) || - !GlobalObject::ensureConstructor(cx, global, JSProto_RegExp) || - !GlobalObject::ensureConstructor(cx, global, JSProto_Iterator)) + if (!EnsureConstructor(cx, global, JSProto_Object) || + !EnsureConstructor(cx, global, JSProto_Array) || + !EnsureConstructor(cx, global, JSProto_Function) || + !EnsureConstructor(cx, global, JSProto_RegExp) || + !EnsureConstructor(cx, global, JSProto_Iterator)) { LeaveParseTaskZone(rt, parseTask); return nullptr; diff --git a/js/src/vm/ObjectGroup.cpp b/js/src/vm/ObjectGroup.cpp index 974cb6ebd156..f1713e4b73fd 100644 --- a/js/src/vm/ObjectGroup.cpp +++ b/js/src/vm/ObjectGroup.cpp @@ -48,6 +48,13 @@ ObjectGroup::finalize(FreeOp *fop) fop->delete_(maybeUnboxedLayoutDontCheckGeneration()); } +void +ObjectGroup::setProtoUnchecked(TaggedProto proto) +{ + proto_ = proto.raw(); + MOZ_ASSERT_IF(proto_ && proto_->isNative(), proto_->isDelegate()); +} + void ObjectGroup::setProto(JSContext *cx, TaggedProto proto) { diff --git a/js/src/vm/ObjectGroup.h b/js/src/vm/ObjectGroup.h index 511010344557..6dcb6b9b26df 100644 --- a/js/src/vm/ObjectGroup.h +++ b/js/src/vm/ObjectGroup.h @@ -256,9 +256,7 @@ class ObjectGroup : public gc::TenuredCell HeapPtrObject &singletonRaw() { return singleton_; } void setProto(JSContext *cx, TaggedProto proto); - void setProtoUnchecked(TaggedProto proto) { - proto_ = proto.raw(); - } + void setProtoUnchecked(TaggedProto proto); void initSingleton(JSObject *singleton) { singleton_ = singleton; From aec1aac3c68e5fec8dddd5f064d2b672117e2d9e Mon Sep 17 00:00:00 2001 From: Andrew McCreight Date: Fri, 6 Feb 2015 09:54:21 -0800 Subject: [PATCH 46/62] Bug 1125005 - Change the reentrance assertion in IncrementalFinalizeRunnable to a warning. r=smaug --- xpcom/base/CycleCollectedJSRuntime.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xpcom/base/CycleCollectedJSRuntime.cpp b/xpcom/base/CycleCollectedJSRuntime.cpp index cbfedce9aaa9..3094af949952 100644 --- a/xpcom/base/CycleCollectedJSRuntime.cpp +++ b/xpcom/base/CycleCollectedJSRuntime.cpp @@ -1134,7 +1134,7 @@ void IncrementalFinalizeRunnable::ReleaseNow(bool aLimited) { if (mReleasing) { - MOZ_ASSERT(false, "Try to avoid re-entering ReleaseNow!"); + NS_WARNING("Re-entering ReleaseNow"); return; } { From 8781b7b74c28b843df2244d07683e89822e3fd57 Mon Sep 17 00:00:00 2001 From: Andrew McCreight Date: Fri, 6 Feb 2015 10:02:44 -0800 Subject: [PATCH 47/62] Bug 1129226 - Update LSan suppression for fixPlainObjectGroup. rs=ryanvm CLOSED TREE --- build/sanitizers/lsan_suppressions.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/sanitizers/lsan_suppressions.txt b/build/sanitizers/lsan_suppressions.txt index 9b7d6029e2cb..78865b3049a1 100644 --- a/build/sanitizers/lsan_suppressions.txt +++ b/build/sanitizers/lsan_suppressions.txt @@ -46,7 +46,7 @@ leak:mozilla::TransportLayerDtls::Setup ### # Bug 981195 - Small leak in the parser. m4 -leak:TypeCompartment::fixObjectGroup +leak:ObjectGroup::fixPlainObjectGroup # Bug 982111 - WebM is leaking. m1 leak:nestegg_read_packet From 573fa5213cd679d9eb33a7710ff52282a37b57f1 Mon Sep 17 00:00:00 2001 From: Nikhil Marathe Date: Fri, 6 Feb 2015 10:08:31 -0800 Subject: [PATCH 48/62] Bug 1127882 - Fix Promise include. --HG-- extra : rebase_source : 43aef21e2d432ef2a8a0a53890aed49b1ffd4a31 --- dom/workers/ServiceWorkerEvents.cpp | 1 - dom/workers/ServiceWorkerEvents.h | 7 +------ 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/dom/workers/ServiceWorkerEvents.cpp b/dom/workers/ServiceWorkerEvents.cpp index 74eb150d1766..2e53e4d6d598 100644 --- a/dom/workers/ServiceWorkerEvents.cpp +++ b/dom/workers/ServiceWorkerEvents.cpp @@ -8,7 +8,6 @@ #include "nsContentUtils.h" -#include "mozilla/dom/Promise.h" #include "mozilla/dom/WorkerScope.h" #include "mozilla/dom/workers/bindings/ServiceWorker.h" diff --git a/dom/workers/ServiceWorkerEvents.h b/dom/workers/ServiceWorkerEvents.h index 9c267260d99d..04f30ccef88c 100644 --- a/dom/workers/ServiceWorkerEvents.h +++ b/dom/workers/ServiceWorkerEvents.h @@ -9,12 +9,7 @@ #include "mozilla/dom/Event.h" #include "mozilla/dom/ExtendableEventBinding.h" #include "mozilla/dom/InstallEventBinding.h" - -namespace mozilla { -namespace dom { - class Promise; -} // namespace dom -} // namespace mozilla +#include "mozilla/dom/Promise.h" BEGIN_WORKERS_NAMESPACE From 43124d543d40967c7caef1bca72c2ed817b4bba0 Mon Sep 17 00:00:00 2001 From: B2G Bumper Bot Date: Fri, 6 Feb 2015 10:09:56 -0800 Subject: [PATCH 49/62] Bumping gaia.json for 2 gaia revision(s) a=gaia-bump ======== https://hg.mozilla.org/integration/gaia-central/rev/d007767cabd2 Author: Eitan Isaacson Desc: Merge pull request #26748 from goetsu/Bug-1069614---Albums-are-not-accessible- Bug 1069614 - making albums accessible in the main view r=squib ======== https://hg.mozilla.org/integration/gaia-central/rev/80918aeca58a Author: goetsu Desc: Bug 1069614 - making albums accessible in the main view --- b2g/config/gaia.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/b2g/config/gaia.json b/b2g/config/gaia.json index 4c35cf57c36c..105df4267994 100644 --- a/b2g/config/gaia.json +++ b/b2g/config/gaia.json @@ -1,9 +1,9 @@ { "git": { - "git_revision": "1d6bd73655ad106328c8083eb3166fa09bb7ee73", + "git_revision": "5553a118471e041be28ad6406f148a2c1a10841f", "remote": "https://git.mozilla.org/releases/gaia.git", "branch": "" }, - "revision": "a141318d7e02995fe3ca486a3361068ff68f5729", + "revision": "d007767cabd27f76572292414ad2304be6304bb8", "repo_path": "integration/gaia-central" } From 3581fbbefd28ba2a9630ce0f8094825c1d07149d Mon Sep 17 00:00:00 2001 From: B2G Bumper Bot Date: Fri, 6 Feb 2015 10:11:25 -0800 Subject: [PATCH 50/62] Bumping manifests a=b2g-bump --- b2g/config/dolphin/sources.xml | 2 +- b2g/config/emulator-ics/sources.xml | 2 +- b2g/config/emulator-jb/sources.xml | 2 +- b2g/config/emulator-kk/sources.xml | 2 +- b2g/config/emulator/sources.xml | 2 +- b2g/config/flame-kk/sources.xml | 2 +- b2g/config/flame/sources.xml | 2 +- b2g/config/nexus-4/sources.xml | 2 +- b2g/config/nexus-5-l/sources.xml | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/b2g/config/dolphin/sources.xml b/b2g/config/dolphin/sources.xml index 6518c23dee38..0b48b8d165f2 100644 --- a/b2g/config/dolphin/sources.xml +++ b/b2g/config/dolphin/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/emulator-ics/sources.xml b/b2g/config/emulator-ics/sources.xml index 0eb5165f39d4..9c8fe27049ae 100644 --- a/b2g/config/emulator-ics/sources.xml +++ b/b2g/config/emulator-ics/sources.xml @@ -19,7 +19,7 @@ - + diff --git a/b2g/config/emulator-jb/sources.xml b/b2g/config/emulator-jb/sources.xml index a2dcc9095306..a294b6217342 100644 --- a/b2g/config/emulator-jb/sources.xml +++ b/b2g/config/emulator-jb/sources.xml @@ -17,7 +17,7 @@ - + diff --git a/b2g/config/emulator-kk/sources.xml b/b2g/config/emulator-kk/sources.xml index c9bd6550bbeb..9225c63b0edf 100644 --- a/b2g/config/emulator-kk/sources.xml +++ b/b2g/config/emulator-kk/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/emulator/sources.xml b/b2g/config/emulator/sources.xml index 0eb5165f39d4..9c8fe27049ae 100644 --- a/b2g/config/emulator/sources.xml +++ b/b2g/config/emulator/sources.xml @@ -19,7 +19,7 @@ - + diff --git a/b2g/config/flame-kk/sources.xml b/b2g/config/flame-kk/sources.xml index 7dca02869bb7..3fe79aad0fd6 100644 --- a/b2g/config/flame-kk/sources.xml +++ b/b2g/config/flame-kk/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/flame/sources.xml b/b2g/config/flame/sources.xml index d4deb737e364..24e21832fdaa 100644 --- a/b2g/config/flame/sources.xml +++ b/b2g/config/flame/sources.xml @@ -17,7 +17,7 @@ - + diff --git a/b2g/config/nexus-4/sources.xml b/b2g/config/nexus-4/sources.xml index b56bc7ba67d5..784223aa9e32 100644 --- a/b2g/config/nexus-4/sources.xml +++ b/b2g/config/nexus-4/sources.xml @@ -17,7 +17,7 @@ - + diff --git a/b2g/config/nexus-5-l/sources.xml b/b2g/config/nexus-5-l/sources.xml index 18ee618c1e6b..2db432e97c85 100644 --- a/b2g/config/nexus-5-l/sources.xml +++ b/b2g/config/nexus-5-l/sources.xml @@ -15,7 +15,7 @@ - + From 14a0e8768e58a6b89bfb8bf417d859d1e76ef3c8 Mon Sep 17 00:00:00 2001 From: Ryan VanderMeulen Date: Fri, 6 Feb 2015 13:25:10 -0500 Subject: [PATCH 51/62] Backed out changeset 73b8ce222f9f (bug 1129360) for Android reftest failures. --- gfx/layers/client/TiledContentClient.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/gfx/layers/client/TiledContentClient.cpp b/gfx/layers/client/TiledContentClient.cpp index bcdffadb0696..afdf50dd3fcf 100644 --- a/gfx/layers/client/TiledContentClient.cpp +++ b/gfx/layers/client/TiledContentClient.cpp @@ -1294,7 +1294,6 @@ ClientTiledLayerBuffer::ValidateTile(TileClient aTile, tileRegion.SubOut(GetValidRegion()); tileRegion.SubOut(aDirtyRegion); // Has now been validated - backBuffer->Unlock(); backBuffer->SetWaste(tileRegion.Area() * mResolution * mResolution); if (createdTextureClient) { From 82cbc626c54f849308151a4176428a7fc30cade2 Mon Sep 17 00:00:00 2001 From: Ryan VanderMeulen Date: Fri, 6 Feb 2015 13:25:22 -0500 Subject: [PATCH 52/62] Backed out changeset 8a49d4f4bb25 (bug 1127289) for frequent B2G reftest failures. --- gfx/layers/client/TiledContentClient.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gfx/layers/client/TiledContentClient.cpp b/gfx/layers/client/TiledContentClient.cpp index afdf50dd3fcf..31c9bbd0b332 100644 --- a/gfx/layers/client/TiledContentClient.cpp +++ b/gfx/layers/client/TiledContentClient.cpp @@ -1091,11 +1091,9 @@ ClientTiledLayerBuffer::UnlockTile(TileClient aTile) // We locked the back buffer, and flipped so we now need to unlock the front if (aTile.mFrontBuffer && aTile.mFrontBuffer->IsLocked()) { aTile.mFrontBuffer->Unlock(); - aTile.mFrontBuffer->SyncWithObject(mCompositableClient->GetForwarder()->GetSyncObject()); } if (aTile.mFrontBufferOnWhite && aTile.mFrontBufferOnWhite->IsLocked()) { aTile.mFrontBufferOnWhite->Unlock(); - aTile.mFrontBufferOnWhite->SyncWithObject(mCompositableClient->GetForwarder()->GetSyncObject()); } if (aTile.mBackBuffer && aTile.mBackBuffer->IsLocked()) { aTile.mBackBuffer->Unlock(); @@ -1295,6 +1293,8 @@ ClientTiledLayerBuffer::ValidateTile(TileClient aTile, tileRegion.SubOut(aDirtyRegion); // Has now been validated backBuffer->SetWaste(tileRegion.Area() * mResolution * mResolution); + backBuffer->Unlock(); + backBuffer->SyncWithObject(mCompositableClient->GetForwarder()->GetSyncObject()); if (createdTextureClient) { if (!mCompositableClient->AddTextureClient(backBuffer)) { From 4e6972566501b633b5e9dd85169cc942454aac7d Mon Sep 17 00:00:00 2001 From: Ryan VanderMeulen Date: Fri, 6 Feb 2015 13:40:53 -0500 Subject: [PATCH 53/62] Backed out 7 changesets (bug 1117242) for mochitest failures. Backed out changeset 694f7ac58964 (bug 1117242) Backed out changeset b3f8122dd990 (bug 1117242) Backed out changeset 442d41779bd8 (bug 1117242) Backed out changeset ccf6dfe1ac75 (bug 1117242) Backed out changeset 86421767cd26 (bug 1117242) Backed out changeset 2f996950fb2f (bug 1117242) Backed out changeset 4414e9d0b66b (bug 1117242) CLOSED TREE --- js/src/builtin/TestingFunctions.cpp | 35 +-- js/src/doc/SavedFrame/SavedFrame.md | 38 --- js/src/gc/Rooting.h | 2 - .../tests/saved-stacks/principals-01.js | 2 +- .../tests/saved-stacks/principals-02.js | 2 +- .../tests/saved-stacks/principals-03.js | 23 -- .../tests/saved-stacks/principals-04.js | 15 -- js/src/jsprototypes.h | 2 - js/src/jsscript.cpp | 2 + js/src/vm/GlobalObject.h | 15 +- js/src/vm/SavedStacks.cpp | 220 ++++++++---------- js/src/vm/SavedStacks.h | 27 +-- js/xpconnect/src/xpcprivate.h | 2 +- .../tests/unit/test_xray_SavedFrame.js | 108 --------- js/xpconnect/tests/unit/xpcshell.ini | 1 - js/xpconnect/wrappers/XrayWrapper.cpp | 1 - 16 files changed, 131 insertions(+), 364 deletions(-) delete mode 100644 js/src/jit-test/tests/saved-stacks/principals-03.js delete mode 100644 js/src/jit-test/tests/saved-stacks/principals-04.js delete mode 100644 js/xpconnect/tests/unit/test_xray_SavedFrame.js diff --git a/js/src/builtin/TestingFunctions.cpp b/js/src/builtin/TestingFunctions.cpp index 5c7df16e14ab..2af889443b78 100644 --- a/js/src/builtin/TestingFunctions.cpp +++ b/js/src/builtin/TestingFunctions.cpp @@ -967,30 +967,9 @@ SaveStack(JSContext *cx, unsigned argc, jsval *vp) maxFrameCount = d; } - JSCompartment *targetCompartment = cx->compartment(); - if (args.length() >= 2) { - if (!args[1].isObject()) { - js_ReportValueErrorFlags(cx, JSREPORT_ERROR, JSMSG_UNEXPECTED_TYPE, - JSDVG_SEARCH_STACK, args[0], JS::NullPtr(), - "not an object", NULL); - return false; - } - RootedObject obj(cx, UncheckedUnwrap(&args[1].toObject())); - if (!obj) - return false; - targetCompartment = obj->compartment(); - } - - RootedObject stack(cx); - { - AutoCompartment ac(cx, targetCompartment); - if (!JS::CaptureCurrentStack(cx, &stack, maxFrameCount)) - return false; - } - - if (stack && !cx->compartment()->wrap(cx, &stack)) + Rooted stack(cx); + if (!JS::CaptureCurrentStack(cx, &stack, maxFrameCount)) return false; - args.rval().setObjectOrNull(stack); return true; } @@ -2417,15 +2396,13 @@ static const JSFunctionSpecWithHelp TestingFunctions[] = { " SavedStacks cache."), JS_FN_HELP("saveStack", SaveStack, 0, 0, -"saveStack([maxDepth [, compartment]])", -" Capture a stack. If 'maxDepth' is given, capture at most 'maxDepth' number\n" -" of frames. If 'compartment' is given, allocate the js::SavedFrame instances\n" -" with the given object's compartment."), +"saveStack()", +" Capture a stack.\n"), JS_FN_HELP("enableTrackAllocations", EnableTrackAllocations, 0, 0, "enableTrackAllocations()", -" Start capturing the JS stack at every allocation. Note that this sets an\n" -" object metadata callback that will override any other object metadata\n" +" Start capturing the JS stack at every allocation. Note that this sets an " +" object metadata callback that will override any other object metadata " " callback that may be set."), JS_FN_HELP("disableTrackAllocations", DisableTrackAllocations, 0, 0, diff --git a/js/src/doc/SavedFrame/SavedFrame.md b/js/src/doc/SavedFrame/SavedFrame.md index 3dcafe998a83..2bad954f35a1 100644 --- a/js/src/doc/SavedFrame/SavedFrame.md +++ b/js/src/doc/SavedFrame/SavedFrame.md @@ -5,44 +5,6 @@ JavaScript call stack at a past moment of execution. Younger frames hold a reference to the frames that invoked them. The older tails are shared across many younger frames. -`SavedFrame` stacks should generally be captured, allocated, and live within the -compartment that is being observed or debugged. Usually this is a content -compartment. - -## Capturing `SavedFrame` Stacks - -### From C++ - -Use `JS::CaptureCurrentStack` declared in `jsapi.h`. - -### From JS - -Use `saveStack`, accessible via `Components.utils.getJSTestingFunction()`. - -## Including and Excluding Chrome Frames - -Consider the following `SavedFrame` stack. Arrows represent links from child to -parent frame, `content.js` is from a compartment with content principals, and -`chrome.js` is from a compartment with chrome principals. - - function A from content.js - | - V - function B from chrome.js - | - V - function C from content.js - -The content compartment will ever have one view of this stack: `A -> C`. - -However, a chrome compartment has a choice: it can either take the same view -that the content compartment has (`A -> C`), or it can view all stack frames, -including the frames from chrome compartments (`A -> B -> C`). To view -everything, use an `XrayWrapper`. This is the default wrapper. To see the stack -as the content compartment sees it, waive the xray wrapper with -`Components.utils.waiveXrays`: - - const contentViewOfStack = Components.utils.waiveXrays(someStack); ## Accessor Properties of the `SavedFrame.prototype` Object diff --git a/js/src/gc/Rooting.h b/js/src/gc/Rooting.h index 2ec6de35d972..ab38313521c0 100644 --- a/js/src/gc/Rooting.h +++ b/js/src/gc/Rooting.h @@ -17,7 +17,6 @@ namespace js { class PropertyName; class NativeObject; class ArrayObject; -class GlobalObject; class PlainObject; class ScriptSourceObject; class Shape; @@ -32,7 +31,6 @@ typedef JS::Handle HandleAtom; typedef JS::Handle HandleLinearString; typedef JS::Handle HandlePropertyName; typedef JS::Handle HandleArrayObject; -typedef JS::Rooted RootedGlobalObject; typedef JS::Handle HandlePlainObject; typedef JS::Handle HandleScriptSource; diff --git a/js/src/jit-test/tests/saved-stacks/principals-01.js b/js/src/jit-test/tests/saved-stacks/principals-01.js index 62640472dc33..1c67956b2df7 100644 --- a/js/src/jit-test/tests/saved-stacks/principals-01.js +++ b/js/src/jit-test/tests/saved-stacks/principals-01.js @@ -42,7 +42,7 @@ var count = 0; low .eval('function b() { check("b", extract(saveStack())); c(); }'); mid .eval('function c() { check("cba", extract(saveStack())); d(); }'); high.eval('function d() { check("dcba", extract(saveStack())); e(); }'); - eval('function e() { check("ecba", extract(saveStack())); f(); }'); + eval('function e() { check("edcba", extract(saveStack())); f(); }'); // no principal, so checks skipped low .eval('function f() { check("fb", extract(saveStack())); g(); }'); mid .eval('function g() { check("gfecba", extract(saveStack())); h(); }'); high.eval('function h() { check("hgfedcba", extract(saveStack())); }'); diff --git a/js/src/jit-test/tests/saved-stacks/principals-02.js b/js/src/jit-test/tests/saved-stacks/principals-02.js index 24ffa82a875b..796c48b06944 100644 --- a/js/src/jit-test/tests/saved-stacks/principals-02.js +++ b/js/src/jit-test/tests/saved-stacks/principals-02.js @@ -33,7 +33,7 @@ var high = newGlobal({ principal: 0xfffff }); low .eval('function b() { check("b", saveStack().toString()); c(); }'); mid .eval('function c() { check("cba", saveStack().toString()); d(); }'); high.eval('function d() { check("dcba", saveStack().toString()); e(); }'); - eval('function e() { check("ecba", saveStack().toString()); f(); }'); + eval('function e() { check("edcba", saveStack().toString()); f(); }'); // no principal, so checks skipped low .eval('function f() { check("fb", saveStack().toString()); g(); }'); mid .eval('function g() { check("gfecba", saveStack().toString()); h(); }'); high.eval('function h() { check("hgfedcba", saveStack().toString()); }'); diff --git a/js/src/jit-test/tests/saved-stacks/principals-03.js b/js/src/jit-test/tests/saved-stacks/principals-03.js deleted file mode 100644 index 006b4477cd67..000000000000 --- a/js/src/jit-test/tests/saved-stacks/principals-03.js +++ /dev/null @@ -1,23 +0,0 @@ -// With arrows representing child-to-parent links, create a SavedFrame stack -// like this: -// -// high.a -> low.b -// -// in `low`'s compartment and give `low` a reference to this stack. Assert the -// stack's youngest frame's properties doesn't leak information about `high.a` -// that `low` shouldn't have access to, and instead returns information about -// `low.b`. - -var low = newGlobal({ principal: 0 }); -var high = newGlobal({ principal: 0xfffff }); - -low.high = high; -high.low = low; - -high.eval("function a() { return saveStack(0, low); }"); -low.eval("function b() { return high.a(); }") - -var stack = low.b(); - -assertEq(stack.functionDisplayName, "b"); -assertEq(stack.parent, null); diff --git a/js/src/jit-test/tests/saved-stacks/principals-04.js b/js/src/jit-test/tests/saved-stacks/principals-04.js deleted file mode 100644 index 3a9b57800584..000000000000 --- a/js/src/jit-test/tests/saved-stacks/principals-04.js +++ /dev/null @@ -1,15 +0,0 @@ -// Test what happens when a compartment gets a SavedFrame that it doesn't have -// the principals to access any of its frames. - -var low = newGlobal({ principal: 0 }); -var high = newGlobal({ principal: 0xfffff }); - -low.high = high; -high.low = low; - -high.eval("function a() { return saveStack(1, low); }"); -var stack = low.eval("high.a();") - -assertEq(stack.functionDisplayName, null); -assertEq(stack.parent, null); -assertEq(stack.toString(), ""); diff --git a/js/src/jsprototypes.h b/js/src/jsprototypes.h index 07adfed41257..467ee57608c2 100644 --- a/js/src/jsprototypes.h +++ b/js/src/jsprototypes.h @@ -111,8 +111,6 @@ IF_SAB(real,imaginary)(SharedFloat64Array, 50, js_InitViaClassSpec, IF_SAB(real,imaginary)(SharedUint8ClampedArray, 51, js_InitViaClassSpec, SHARED_TYPED_ARRAY_CLASP(Uint8Clamped)) \ real(TypedArray, 52, js_InitViaClassSpec, &js::TypedArrayObject::sharedTypedArrayPrototypeClass) \ IF_SAB(real,imaginary)(Atomics, 53, js_InitAtomicsClass, OCLASP(Atomics)) \ - real(SavedFrame, 54, js_InitViaClassSpec, &js::SavedFrame::class_) \ - #define JS_FOR_EACH_PROTOTYPE(macro) JS_FOR_PROTOTYPES(macro,macro) diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp index 3fea4b2c5bd6..f1da89afd6c0 100644 --- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -61,6 +61,8 @@ using mozilla::PodCopy; using mozilla::PodZero; using mozilla::RotateLeft; +typedef Rooted RootedGlobalObject; + /* static */ BindingIter Bindings::argumentsBinding(ExclusiveContext *cx, InternalBindingsHandle bindings) { diff --git a/js/src/vm/GlobalObject.h b/js/src/vm/GlobalObject.h index 69d824eed771..628a07f8424a 100644 --- a/js/src/vm/GlobalObject.h +++ b/js/src/vm/GlobalObject.h @@ -306,7 +306,7 @@ class GlobalObject : public NativeObject NativeObject *getOrCreateObjectPrototype(JSContext *cx) { if (functionObjectClassesInitialized()) return &getPrototype(JSProto_Object).toObject().as(); - RootedGlobalObject self(cx, this); + Rooted self(cx, this); if (!ensureConstructor(cx, self, JSProto_Object)) return nullptr; return &self->getPrototype(JSProto_Object).toObject().as(); @@ -315,7 +315,7 @@ class GlobalObject : public NativeObject NativeObject *getOrCreateFunctionPrototype(JSContext *cx) { if (functionObjectClassesInitialized()) return &getPrototype(JSProto_Function).toObject().as(); - RootedGlobalObject self(cx, this); + Rooted self(cx, this); if (!ensureConstructor(cx, self, JSProto_Object)) return nullptr; return &self->getPrototype(JSProto_Function).toObject().as(); @@ -369,13 +369,6 @@ class GlobalObject : public NativeObject return nullptr; } - static NativeObject *getOrCreateSavedFramePrototype(JSContext *cx, - Handle global) { - if (!ensureConstructor(cx, global, JSProto_SavedFrame)) - return nullptr; - return &global->getPrototype(JSProto_SavedFrame).toObject().as(); - } - static JSObject *getOrCreateArrayBufferPrototype(JSContext *cx, Handle global) { if (!ensureConstructor(cx, global, JSProto_ArrayBuffer)) return nullptr; @@ -475,7 +468,7 @@ class GlobalObject : public NativeObject Value v = getSlotRef(slot); if (v.isObject()) return &v.toObject(); - RootedGlobalObject self(cx, this); + Rooted self(cx, this); if (!init(cx, self)) return nullptr; return &self->getSlot(slot).toObject(); @@ -553,7 +546,7 @@ class GlobalObject : public NativeObject } JSObject *getOrCreateDataViewPrototype(JSContext *cx) { - RootedGlobalObject self(cx, this); + Rooted self(cx, this); if (!ensureConstructor(cx, self, JSProto_DataView)) return nullptr; return &self->getPrototype(JSProto_DataView).toObject(); diff --git a/js/src/vm/SavedStacks.cpp b/js/src/vm/SavedStacks.cpp index 3e356763720c..b37e64dd4c26 100644 --- a/js/src/vm/SavedStacks.cpp +++ b/js/src/vm/SavedStacks.cpp @@ -16,13 +16,12 @@ #include "jshashutil.h" #include "jsmath.h" #include "jsnum.h" -#include "jsscript.h" #include "prmjtime.h" #include "gc/Marking.h" -#include "gc/Rooting.h" #include "js/Vector.h" #include "vm/Debugger.h" +#include "vm/GlobalObject.h" #include "vm/StringBuffer.h" #include "jscntxtinlines.h" @@ -137,67 +136,18 @@ SavedFrame::HashPolicy::rekey(Key &key, const Key &newKey) key = newKey; } -/* static */ bool -SavedFrame::finishSavedFrameInit(JSContext *cx, HandleObject ctor, HandleObject proto) -{ - // The only object with the SavedFrame::class_ that doesn't have a source - // should be the prototype. - proto->as().setReservedSlot(SavedFrame::JSSLOT_SOURCE, NullValue()); - - return FreezeObject(cx, proto); -} - /* static */ const Class SavedFrame::class_ = { "SavedFrame", JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS | - JSCLASS_HAS_RESERVED_SLOTS(SavedFrame::JSSLOT_COUNT) | - JSCLASS_HAS_CACHED_PROTO(JSProto_SavedFrame) | - JSCLASS_IS_ANONYMOUS, - nullptr, // addProperty - nullptr, // delProperty - nullptr, // getProperty - nullptr, // setProperty - nullptr, // enumerate - nullptr, // resolve - nullptr, // convert - SavedFrame::finalize, // finalize - nullptr, // call - nullptr, // hasInstance - nullptr, // construct - nullptr, // trace - - // ClassSpec - { - GenericCreateConstructor, - GenericCreatePrototype, - SavedFrame::staticFunctions, - SavedFrame::protoFunctions, - SavedFrame::protoAccessors, - SavedFrame::finishSavedFrameInit, - ClassSpec::DontDefineConstructor - } -}; - -/* static */ const JSFunctionSpec -SavedFrame::staticFunctions[] = { - JS_FS_END -}; - -/* static */ const JSFunctionSpec -SavedFrame::protoFunctions[] = { - JS_FN("constructor", SavedFrame::construct, 0, 0), - JS_FN("toString", SavedFrame::toStringMethod, 0, 0), - JS_FS_END -}; - -/* static */ const JSPropertySpec -SavedFrame::protoAccessors[] = { - JS_PSG("source", SavedFrame::sourceProperty, 0), - JS_PSG("line", SavedFrame::lineProperty, 0), - JS_PSG("column", SavedFrame::columnProperty, 0), - JS_PSG("functionDisplayName", SavedFrame::functionDisplayNameProperty, 0), - JS_PSG("parent", SavedFrame::parentProperty, 0), - JS_PS_END + JSCLASS_HAS_RESERVED_SLOTS(SavedFrame::JSSLOT_COUNT), + nullptr, // addProperty + nullptr, // delProperty + nullptr, // getProperty + nullptr, // setProperty + nullptr, // enumerate + nullptr, // resolve + nullptr, // convert + SavedFrame::finalize }; /* static */ void @@ -309,56 +259,33 @@ SavedFrame::construct(JSContext *cx, unsigned argc, Value *vp) return false; } -// Return the first SavedFrame in the chain that starts with |frame| whose -// principals are subsumed by |principals|, according to |subsumes|. If there is -// no such frame, return nullptr. -static SavedFrame * -GetFirstSubsumedFrame(JSContext *cx, SavedFrame *frame) -{ - JSSubsumesOp subsumes = cx->runtime()->securityCallbacks->subsumes; - if (!subsumes) - return frame; - - JSPrincipals *principals = cx->compartment()->principals; - - while (frame && !subsumes(principals, frame->getPrincipals())) - frame = frame->getParent(); - - return frame; -} - -/* static */ bool -SavedFrame::checkThis(JSContext *cx, CallArgs &args, const char *fnName, - MutableHandleSavedFrame frame) +/* static */ SavedFrame * +SavedFrame::checkThis(JSContext *cx, CallArgs &args, const char *fnName) { const Value &thisValue = args.thisv(); if (!thisValue.isObject()) { JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT); - return false; + return nullptr; } - JSObject *thisObject = CheckedUnwrap(&thisValue.toObject()); - if (!thisObject || !thisObject->is()) { + JSObject &thisObject = thisValue.toObject(); + if (!thisObject.is()) { JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_INCOMPATIBLE_PROTO, - SavedFrame::class_.name, fnName, - thisObject ? thisObject->getClass()->name : "object"); - return false; + SavedFrame::class_.name, fnName, thisObject.getClass()->name); + return nullptr; } // Check for SavedFrame.prototype, which has the same class as SavedFrame // instances, however doesn't actually represent a captured stack frame. It // is the only object that is() but doesn't have a source. - if (thisObject->as().getReservedSlot(JSSLOT_SOURCE).isNull()) { + if (thisObject.as().getReservedSlot(JSSLOT_SOURCE).isNull()) { JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_INCOMPATIBLE_PROTO, SavedFrame::class_.name, fnName, "prototype object"); - return false; + return nullptr; } - // The caller might not have the principals to see this frame's data, so get - // the first one they _do_ have access to. - frame.set(GetFirstSubsumedFrame(cx, &thisObject->as())); - return true; + return &thisObject.as(); } // Get the SavedFrame * from the current this value and handle any errors that @@ -369,24 +296,19 @@ SavedFrame::checkThis(JSContext *cx, CallArgs &args, const char *fnName, // - unsigned argc // - Value *vp // - const char *fnName -// - Value defaultVal // These parameters will be defined after calling this macro: // - CallArgs args // - Rooted frame (will be non-null) -#define THIS_SAVEDFRAME(cx, argc, vp, fnName, defaultVal, args, frame) \ - CallArgs args = CallArgsFromVp(argc, vp); \ - RootedSavedFrame frame(cx); \ - if (!checkThis(cx, args, fnName, &frame)) \ - return false; \ - if (!frame) { \ - args.rval().set(defaultVal); \ - return true; \ - } +#define THIS_SAVEDFRAME(cx, argc, vp, fnName, args, frame) \ + CallArgs args = CallArgsFromVp(argc, vp); \ + RootedSavedFrame frame(cx, checkThis(cx, args, fnName)); \ + if (!frame) \ + return false /* static */ bool SavedFrame::sourceProperty(JSContext *cx, unsigned argc, Value *vp) { - THIS_SAVEDFRAME(cx, argc, vp, "(get source)", NullValue(), args, frame); + THIS_SAVEDFRAME(cx, argc, vp, "(get source)", args, frame); args.rval().setString(frame->getSource()); return true; } @@ -394,7 +316,7 @@ SavedFrame::sourceProperty(JSContext *cx, unsigned argc, Value *vp) /* static */ bool SavedFrame::lineProperty(JSContext *cx, unsigned argc, Value *vp) { - THIS_SAVEDFRAME(cx, argc, vp, "(get line)", NullValue(), args, frame); + THIS_SAVEDFRAME(cx, argc, vp, "(get line)", args, frame); uint32_t line = frame->getLine(); args.rval().setNumber(line); return true; @@ -403,7 +325,7 @@ SavedFrame::lineProperty(JSContext *cx, unsigned argc, Value *vp) /* static */ bool SavedFrame::columnProperty(JSContext *cx, unsigned argc, Value *vp) { - THIS_SAVEDFRAME(cx, argc, vp, "(get column)", NullValue(), args, frame); + THIS_SAVEDFRAME(cx, argc, vp, "(get column)", args, frame); uint32_t column = frame->getColumn(); args.rval().setNumber(column); return true; @@ -412,7 +334,7 @@ SavedFrame::columnProperty(JSContext *cx, unsigned argc, Value *vp) /* static */ bool SavedFrame::functionDisplayNameProperty(JSContext *cx, unsigned argc, Value *vp) { - THIS_SAVEDFRAME(cx, argc, vp, "(get functionDisplayName)", NullValue(), args, frame); + THIS_SAVEDFRAME(cx, argc, vp, "(get functionDisplayName)", args, frame); RootedAtom name(cx, frame->getFunctionDisplayName()); if (name) args.rval().setString(name); @@ -424,21 +346,39 @@ SavedFrame::functionDisplayNameProperty(JSContext *cx, unsigned argc, Value *vp) /* static */ bool SavedFrame::parentProperty(JSContext *cx, unsigned argc, Value *vp) { - THIS_SAVEDFRAME(cx, argc, vp, "(get parent)", NullValue(), args, frame); - args.rval().setObjectOrNull(GetFirstSubsumedFrame(cx, frame->getParent())); + THIS_SAVEDFRAME(cx, argc, vp, "(get parent)", args, frame); + JSSubsumesOp subsumes = cx->runtime()->securityCallbacks->subsumes; + JSPrincipals *principals = cx->compartment()->principals; + + do + frame = frame->getParent(); + while (frame && principals && subsumes && + !subsumes(principals, frame->getPrincipals())); + + args.rval().setObjectOrNull(frame); return true; } +/* static */ const JSPropertySpec SavedFrame::properties[] = { + JS_PSG("source", SavedFrame::sourceProperty, 0), + JS_PSG("line", SavedFrame::lineProperty, 0), + JS_PSG("column", SavedFrame::columnProperty, 0), + JS_PSG("functionDisplayName", SavedFrame::functionDisplayNameProperty, 0), + JS_PSG("parent", SavedFrame::parentProperty, 0), + JS_PS_END +}; + /* static */ bool SavedFrame::toStringMethod(JSContext *cx, unsigned argc, Value *vp) { - THIS_SAVEDFRAME(cx, argc, vp, "toString", StringValue(cx->runtime()->emptyString), args, frame); + THIS_SAVEDFRAME(cx, argc, vp, "toString", args, frame); StringBuffer sb(cx); - DebugOnly subsumes = cx->runtime()->securityCallbacks->subsumes; - DebugOnly principals = cx->compartment()->principals; + JSSubsumesOp subsumes = cx->runtime()->securityCallbacks->subsumes; + JSPrincipals *principals = cx->compartment()->principals; do { - MOZ_ASSERT_IF(subsumes, (*subsumes)(principals, frame->getPrincipals())); + if (principals && subsumes && !subsumes(principals, frame->getPrincipals())) + continue; if (frame->isSelfHosted()) continue; @@ -454,7 +394,7 @@ SavedFrame::toStringMethod(JSContext *cx, unsigned argc, Value *vp) { return false; } - } while ((frame = GetFirstSubsumedFrame(cx, frame->getParent()))); + } while ((frame = frame->getParent())); JSString *str = sb.finishString(); if (!str) @@ -463,6 +403,12 @@ SavedFrame::toStringMethod(JSContext *cx, unsigned argc, Value *vp) return true; } +/* static */ const JSFunctionSpec SavedFrame::methods[] = { + JS_FN("constructor", SavedFrame::construct, 0, 0), + JS_FN("toString", SavedFrame::toStringMethod, 0, 0), + JS_FS_END +}; + bool SavedStacks::init() { @@ -514,6 +460,12 @@ SavedStacks::sweep(JSRuntime *rt) } sweepPCLocationMap(); + + if (savedFrameProto.unbarrieredGet() && + IsObjectAboutToBeFinalizedFromAnyThread(savedFrameProto.unsafeGet())) + { + savedFrameProto.set(nullptr); + } } void @@ -635,17 +587,49 @@ SavedStacks::getOrCreateSavedFrame(JSContext *cx, SavedFrame::HandleLookup looku return frame; } +JSObject * +SavedStacks::getOrCreateSavedFramePrototype(JSContext *cx) +{ + if (savedFrameProto) + return savedFrameProto; + + Rooted global(cx, cx->compartment()->maybeGlobal()); + if (!global) + return nullptr; + + Rooted proto(cx, + NewObjectWithGivenProto(cx, global->getOrCreateObjectPrototype(cx), global)); + if (!proto + || !JS_DefineProperties(cx, proto, SavedFrame::properties) + || !JS_DefineFunctions(cx, proto, SavedFrame::methods) + || !FreezeObject(cx, proto)) + { + return nullptr; + } + + // The only object with the SavedFrame::class_ that doesn't have a source + // should be the prototype. + proto->setReservedSlot(SavedFrame::JSSLOT_SOURCE, NullValue()); + + savedFrameProto.set(proto); + return savedFrameProto; +} + SavedFrame * SavedStacks::createFrameFromLookup(JSContext *cx, SavedFrame::HandleLookup lookup) { - RootedGlobalObject global(cx, cx->global()); - assertSameCompartment(cx, global); - - RootedNativeObject proto(cx, GlobalObject::getOrCreateSavedFramePrototype(cx, global)); + RootedObject proto(cx, getOrCreateSavedFramePrototype(cx)); if (!proto) return nullptr; + assertSameCompartment(cx, proto); + RootedObject global(cx, cx->compartment()->maybeGlobal()); + if (!global) + return nullptr; + + assertSameCompartment(cx, global); + RootedObject frameObj(cx, NewObjectWithGivenProto(cx, &SavedFrame::class_, proto, global)); if (!frameObj) return nullptr; diff --git a/js/src/vm/SavedStacks.h b/js/src/vm/SavedStacks.h index a73fa5d3f1cf..7ebde362a951 100644 --- a/js/src/vm/SavedStacks.h +++ b/js/src/vm/SavedStacks.h @@ -14,22 +14,16 @@ namespace js { -class SavedFrame; -typedef JS::Handle HandleSavedFrame; -typedef JS::MutableHandle MutableHandleSavedFrame; -typedef JS::Rooted RootedSavedFrame; - class SavedFrame : public NativeObject { friend class SavedStacks; public: static const Class class_; static void finalize(FreeOp *fop, JSObject *obj); - static const JSPropertySpec protoAccessors[]; - static const JSFunctionSpec protoFunctions[]; - static const JSFunctionSpec staticFunctions[]; // Prototype methods and properties to be exposed to JS. + static const JSPropertySpec properties[]; + static const JSFunctionSpec methods[]; static bool construct(JSContext *cx, unsigned argc, Value *vp); static bool sourceProperty(JSContext *cx, unsigned argc, Value *vp); static bool lineProperty(JSContext *cx, unsigned argc, Value *vp); @@ -59,7 +53,6 @@ class SavedFrame : public NativeObject { class HandleLookup; private: - static bool finishSavedFrameInit(JSContext *cx, HandleObject ctor, HandleObject proto); void initFromLookup(HandleLookup lookup); enum { @@ -84,13 +77,16 @@ class SavedFrame : public NativeObject { // know that GC moved the parent and we need to update our private value and // rekey the saved frame in its hash set. These two methods are helpers for // this process. - bool parentMoved(); - void updatePrivateParent(); + bool parentMoved(); + void updatePrivateParent(); - static bool checkThis(JSContext *cx, CallArgs &args, const char *fnName, - MutableHandleSavedFrame frame); + static SavedFrame *checkThis(JSContext *cx, CallArgs &args, const char *fnName); }; +typedef JS::Handle HandleSavedFrame; +typedef JS::MutableHandle MutableHandleSavedFrame; +typedef JS::Rooted RootedSavedFrame; + struct SavedFrame::HashPolicy { typedef SavedFrame::Lookup Lookup; @@ -110,6 +106,7 @@ class SavedStacks { public: SavedStacks() : frames(), + savedFrameProto(nullptr), allocationSamplingProbability(1.0), allocationSkipCount(0), // XXX: Initialize the RNG state to 0 so that random_initSeed is lazily @@ -132,6 +129,7 @@ class SavedStacks { private: SavedFrame::Set frames; + ReadBarrieredObject savedFrameProto; double allocationSamplingProbability; uint32_t allocationSkipCount; uint64_t rngState; @@ -139,6 +137,9 @@ class SavedStacks { bool insertFrames(JSContext *cx, FrameIter &iter, MutableHandleSavedFrame frame, unsigned maxFrameCount = 0); SavedFrame *getOrCreateSavedFrame(JSContext *cx, SavedFrame::HandleLookup lookup); + // |SavedFrame.prototype| is created lazily and held weakly. It should only + // be accessed through this method. + JSObject *getOrCreateSavedFramePrototype(JSContext *cx); SavedFrame *createFrameFromLookup(JSContext *cx, SavedFrame::HandleLookup lookup); void chooseSamplingProbability(JSContext* cx); diff --git a/js/xpconnect/src/xpcprivate.h b/js/xpconnect/src/xpcprivate.h index 8816cf5026a9..7420f0a94b89 100644 --- a/js/xpconnect/src/xpcprivate.h +++ b/js/xpconnect/src/xpcprivate.h @@ -507,7 +507,7 @@ public: // Mapping of often used strings to jsid atoms that live 'forever'. // // To add a new string: add to this list and to XPCJSRuntime::mStrings - // at the top of XPCJSRuntime.cpp + // at the top of xpcjsruntime.cpp enum { IDX_CONSTRUCTOR = 0 , IDX_TO_STRING , diff --git a/js/xpconnect/tests/unit/test_xray_SavedFrame.js b/js/xpconnect/tests/unit/test_xray_SavedFrame.js deleted file mode 100644 index 6a931cff0cea..000000000000 --- a/js/xpconnect/tests/unit/test_xray_SavedFrame.js +++ /dev/null @@ -1,108 +0,0 @@ -// Bug 1117242: Test calling SavedFrame getters from globals that don't subsume -// that frame's principals. - -const Cc = Components.classes; -const Ci = Components.interfaces; -const Cu = Components.utils; - -Cu.import("resource://gre/modules/jsdebugger.jsm"); -addDebuggerToGlobal(this); - -const lowP = Cc["@mozilla.org/nullprincipal;1"].createInstance(Ci.nsIPrincipal); -const midP = [lowP, "http://other.com"]; -const highP = Cc["@mozilla.org/systemprincipal;1"].createInstance(Ci.nsIPrincipal); - -const low = new Cu.Sandbox(lowP); -const mid = new Cu.Sandbox(midP); -const high = new Cu.Sandbox(highP); - -function run_test() { - // Test that the priveleged view of a SavedFrame from a subsumed compartment - // is the same view that the subsumed compartment gets. Create the following - // chain of function calls (with some intermediate system-principaled frames - // due to implementation): - // - // low.lowF -> mid.midF -> high.highF -> high.saveStack - // - // Where high.saveStack gets monkey patched to create stacks in each of our - // sandboxes. - - Cu.evalInSandbox("function highF() { return saveStack(); }", high); - - mid.highF = () => high.highF(); - Cu.evalInSandbox("function midF() { return highF(); }", mid); - - low.midF = () => mid.midF(); - Cu.evalInSandbox("function lowF() { return midF(); }", low); - - const expected = [ - { - sandbox: low, - frames: ["lowF"], - }, - { - sandbox: mid, - frames: ["midF", "lowF"], - }, - { - sandbox: high, - frames: ["getSavedFrameInstanceFromSandbox", - "saveStack", - "highF", - "run_test/mid.highF", - "midF", - "run_test/low.midF", - "lowF", - "run_test", - "_execute_test", - null], - } - ]; - - for (let { sandbox, frames } of expected) { - high.saveStack = function saveStack() { - return getSavedFrameInstanceFromSandbox(sandbox); - }; - - const xrayStack = low.lowF(); - equal(xrayStack.functionDisplayName, "getSavedFrameInstanceFromSandbox", - "Xrays should always be able to see everything."); - - let waived = Cu.waiveXrays(xrayStack); - do { - ok(frames.length, - "There should still be more expected frames while we have actual frames."); - equal(waived.functionDisplayName, frames.shift(), - "The waived wrapper should give us the stack's compartment's view."); - waived = waived.parent; - } while (waived); - } -} - -// Get a SavedFrame instance from inside the given sandbox. -// -// We can't use Cu.getJSTestingFunctions().saveStack() because Cu isn't -// available to sandboxes that don't have the system principal. The easiest way -// to get the SavedFrame is to use the Debugger API to track allocation sites -// and then do an allocation. -function getSavedFrameInstanceFromSandbox(sandbox) { - const dbg = new Debugger(sandbox); - - dbg.memory.trackingAllocationSites = true; - Cu.evalInSandbox("new Object", sandbox); - const allocs = dbg.memory.drainAllocationsLog(); - dbg.memory.trackingAllocationSites = false; - - ok(allocs[0], "We should observe the allocation"); - const { frame } = allocs[0]; - - if (sandbox !== high) { - ok(Cu.isXrayWrapper(frame), "`frame` should be an xray..."); - equal(Object.prototype.toString.call(Cu.waiveXrays(frame)), - "[object SavedFrame]", - "...and that xray should wrap a SavedFrame"); - } - - return frame; -} - diff --git a/js/xpconnect/tests/unit/xpcshell.ini b/js/xpconnect/tests/unit/xpcshell.ini index 9dd5fa698765..9195ca709125 100644 --- a/js/xpconnect/tests/unit/xpcshell.ini +++ b/js/xpconnect/tests/unit/xpcshell.ini @@ -108,4 +108,3 @@ head = head_watchdog.js head = head_watchdog.js [test_writeToGlobalPrototype.js] [test_xrayed_iterator.js] -[test_xray_SavedFrame.js] \ No newline at end of file diff --git a/js/xpconnect/wrappers/XrayWrapper.cpp b/js/xpconnect/wrappers/XrayWrapper.cpp index d869d144c1de..a7d11ae12c4b 100644 --- a/js/xpconnect/wrappers/XrayWrapper.cpp +++ b/js/xpconnect/wrappers/XrayWrapper.cpp @@ -83,7 +83,6 @@ IsJSXraySupported(JSProtoKey key) case JSProto_Array: case JSProto_Function: case JSProto_TypedArray: - case JSProto_SavedFrame: return true; default: return false; From 614dc1b3da6db042c29066203d3d15eed0449019 Mon Sep 17 00:00:00 2001 From: B2G Bumper Bot Date: Fri, 6 Feb 2015 11:15:09 -0800 Subject: [PATCH 54/62] Bumping gaia.json for 4 gaia revision(s) a=gaia-bump ======== https://hg.mozilla.org/integration/gaia-central/rev/5a4176cf9719 Author: tamarahills Desc: Merge pull request #27982 from tamarahills/bugfix/1126379_force_ltr_on_emergency_dialer Bug 1126379 - Force LTR for phone number and delete in the Emergency Dia... ======== https://hg.mozilla.org/integration/gaia-central/rev/34357059ef72 Author: Tamara Hills Desc: Bug 1126379 - Force LTR for phone number and delete in the Emergency Dialer. ======== https://hg.mozilla.org/integration/gaia-central/rev/d935eff086fe Author: Michael Henretty Desc: Merge pull request #27948 from mikehenrty/bug-1125962-pin-retries Bug 1125962 - Reset SIM PIN form after each entry attempt ======== https://hg.mozilla.org/integration/gaia-central/rev/352ed34a4e56 Author: Michael Henretty Desc: Bug 1125962 - Reset SIM PIN form after each entry attempt --- b2g/config/gaia.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/b2g/config/gaia.json b/b2g/config/gaia.json index 105df4267994..1f9a48131aa5 100644 --- a/b2g/config/gaia.json +++ b/b2g/config/gaia.json @@ -1,9 +1,9 @@ { "git": { - "git_revision": "5553a118471e041be28ad6406f148a2c1a10841f", + "git_revision": "a42e6d7ac229e1fd68391ba36df4a0c75fd6b30d", "remote": "https://git.mozilla.org/releases/gaia.git", "branch": "" }, - "revision": "d007767cabd27f76572292414ad2304be6304bb8", + "revision": "5a4176cf971907e3071a9160d05434079865ae1f", "repo_path": "integration/gaia-central" } From c7170c4ca4a8a383808010c7ef5a9eab79e7bd32 Mon Sep 17 00:00:00 2001 From: B2G Bumper Bot Date: Fri, 6 Feb 2015 11:16:44 -0800 Subject: [PATCH 55/62] Bumping manifests a=b2g-bump --- b2g/config/dolphin/sources.xml | 2 +- b2g/config/emulator-ics/sources.xml | 2 +- b2g/config/emulator-jb/sources.xml | 2 +- b2g/config/emulator-kk/sources.xml | 2 +- b2g/config/emulator/sources.xml | 2 +- b2g/config/flame-kk/sources.xml | 2 +- b2g/config/flame/sources.xml | 2 +- b2g/config/nexus-4/sources.xml | 2 +- b2g/config/nexus-5-l/sources.xml | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/b2g/config/dolphin/sources.xml b/b2g/config/dolphin/sources.xml index 0b48b8d165f2..8e034d75044f 100644 --- a/b2g/config/dolphin/sources.xml +++ b/b2g/config/dolphin/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/emulator-ics/sources.xml b/b2g/config/emulator-ics/sources.xml index 9c8fe27049ae..e0bb42426814 100644 --- a/b2g/config/emulator-ics/sources.xml +++ b/b2g/config/emulator-ics/sources.xml @@ -19,7 +19,7 @@ - + diff --git a/b2g/config/emulator-jb/sources.xml b/b2g/config/emulator-jb/sources.xml index a294b6217342..b8613175d921 100644 --- a/b2g/config/emulator-jb/sources.xml +++ b/b2g/config/emulator-jb/sources.xml @@ -17,7 +17,7 @@ - + diff --git a/b2g/config/emulator-kk/sources.xml b/b2g/config/emulator-kk/sources.xml index 9225c63b0edf..b7224ae44121 100644 --- a/b2g/config/emulator-kk/sources.xml +++ b/b2g/config/emulator-kk/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/emulator/sources.xml b/b2g/config/emulator/sources.xml index 9c8fe27049ae..e0bb42426814 100644 --- a/b2g/config/emulator/sources.xml +++ b/b2g/config/emulator/sources.xml @@ -19,7 +19,7 @@ - + diff --git a/b2g/config/flame-kk/sources.xml b/b2g/config/flame-kk/sources.xml index 3fe79aad0fd6..654701abe994 100644 --- a/b2g/config/flame-kk/sources.xml +++ b/b2g/config/flame-kk/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/flame/sources.xml b/b2g/config/flame/sources.xml index 24e21832fdaa..ccf4875ebec7 100644 --- a/b2g/config/flame/sources.xml +++ b/b2g/config/flame/sources.xml @@ -17,7 +17,7 @@ - + diff --git a/b2g/config/nexus-4/sources.xml b/b2g/config/nexus-4/sources.xml index 784223aa9e32..2c50bf4b4092 100644 --- a/b2g/config/nexus-4/sources.xml +++ b/b2g/config/nexus-4/sources.xml @@ -17,7 +17,7 @@ - + diff --git a/b2g/config/nexus-5-l/sources.xml b/b2g/config/nexus-5-l/sources.xml index 2db432e97c85..7b8ef464f90a 100644 --- a/b2g/config/nexus-5-l/sources.xml +++ b/b2g/config/nexus-5-l/sources.xml @@ -15,7 +15,7 @@ - + From 2734148774b5f22dfe277439ca4b89025849014e Mon Sep 17 00:00:00 2001 From: B2G Bumper Bot Date: Fri, 6 Feb 2015 11:35:32 -0800 Subject: [PATCH 56/62] Bumping gaia.json for 2 gaia revision(s) a=gaia-bump ======== https://hg.mozilla.org/integration/gaia-central/rev/b3f95ed4290c Author: Yura Zenevich Desc: Merge pull request #27790 from yzen/bug-1068699 Bug 1068699 - for email item in the message list making its reading order more sensible for the screen reader. ======== https://hg.mozilla.org/integration/gaia-central/rev/885b7e600987 Author: Yura Zenevich Desc: Bug 1068699 - for email item in the message list making its reading order more sensible for the screen reader. --- b2g/config/gaia.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/b2g/config/gaia.json b/b2g/config/gaia.json index 1f9a48131aa5..7074b3afa500 100644 --- a/b2g/config/gaia.json +++ b/b2g/config/gaia.json @@ -1,9 +1,9 @@ { "git": { - "git_revision": "a42e6d7ac229e1fd68391ba36df4a0c75fd6b30d", + "git_revision": "47cda5850572ed93088106e86a69fcd3d0c5c31f", "remote": "https://git.mozilla.org/releases/gaia.git", "branch": "" }, - "revision": "5a4176cf971907e3071a9160d05434079865ae1f", + "revision": "b3f95ed4290ceed20f0e76e6882380c3bf8ddf34", "repo_path": "integration/gaia-central" } From 56b00391c347c898331658ec5bb0e016df640c34 Mon Sep 17 00:00:00 2001 From: Jeff Gilbert Date: Fri, 6 Feb 2015 11:37:04 -0800 Subject: [PATCH 57/62] Backout 80a88a3badba for causing bug 1130086. --- dom/canvas/WebGLContext.cpp | 28 +- dom/canvas/WebGLContext.h | 3 +- dom/canvas/WebGLContextGL.cpp | 1 + dom/canvas/WebGLContextUtils.cpp | 9 +- dom/canvas/WebGLContextValidate.cpp | 6 +- .../fmp4/android/AndroidDecoderModule.cpp | 2 +- dom/plugins/base/nsNPAPIPluginInstance.cpp | 5 +- gfx/gl/GLContext.cpp | 246 ++++++++---------- gfx/gl/GLContext.h | 107 ++++---- gfx/gl/GLContextCGL.h | 6 +- gfx/gl/GLContextFeatures.cpp | 10 - gfx/gl/GLContextProviderCGL.mm | 163 +++++------- gfx/gl/GLContextProviderEGL.cpp | 7 +- gfx/gl/GLContextProviderGLX.cpp | 7 +- gfx/gl/GLContextProviderImpl.h | 5 +- gfx/gl/GLContextProviderNull.cpp | 5 +- gfx/gl/GLContextProviderWGL.cpp | 7 +- gfx/gl/GLContextSymbols.h | 4 - gfx/gl/GLContextTypes.cpp | 5 + gfx/gl/GLContextTypes.h | 13 + gfx/gl/GLLibraryEGL.cpp | 26 +- gfx/gl/GLLibraryEGL.h | 1 - gfx/layers/GLImages.cpp | 2 +- gfx/layers/opengl/CompositorOGL.cpp | 5 +- gfx/tests/gtest/TestCompositor.cpp | 2 +- gfx/thebes/gfxPlatform.cpp | 5 +- widget/android/GfxInfo.cpp | 4 +- 27 files changed, 308 insertions(+), 376 deletions(-) diff --git a/dom/canvas/WebGLContext.cpp b/dom/canvas/WebGLContext.cpp index 38420ff232e2..749621074af9 100644 --- a/dom/canvas/WebGLContext.cpp +++ b/dom/canvas/WebGLContext.cpp @@ -505,7 +505,7 @@ IsFeatureInBlacklist(const nsCOMPtr& gfxInfo, int32_t feature) static already_AddRefed CreateHeadlessNativeGL(bool forceEnabled, const nsCOMPtr& gfxInfo, - bool requireCompatProfile, WebGLContext* webgl) + WebGLContext* webgl) { if (!forceEnabled && IsFeatureInBlacklist(gfxInfo, nsIGfxInfo::FEATURE_WEBGL_OPENGL)) @@ -515,7 +515,7 @@ CreateHeadlessNativeGL(bool forceEnabled, const nsCOMPtr& gfxInfo, return nullptr; } - nsRefPtr gl = gl::GLContextProvider::CreateHeadless(requireCompatProfile); + nsRefPtr gl = gl::GLContextProvider::CreateHeadless(); if (!gl) { webgl->GenerateWarning("Error during native OpenGL init."); return nullptr; @@ -530,7 +530,7 @@ CreateHeadlessNativeGL(bool forceEnabled, const nsCOMPtr& gfxInfo, // Eventually, we want to be able to pick ANGLE-EGL or native EGL. static already_AddRefed CreateHeadlessANGLE(bool forceEnabled, const nsCOMPtr& gfxInfo, - bool requireCompatProfile, WebGLContext* webgl) + WebGLContext* webgl) { nsRefPtr gl; @@ -543,7 +543,7 @@ CreateHeadlessANGLE(bool forceEnabled, const nsCOMPtr& gfxInfo, return nullptr; } - gl = gl::GLContextProviderEGL::CreateHeadless(requireCompatProfile); + gl = gl::GLContextProviderEGL::CreateHeadless(); if (!gl) { webgl->GenerateWarning("Error during ANGLE OpenGL init."); return nullptr; @@ -555,13 +555,13 @@ CreateHeadlessANGLE(bool forceEnabled, const nsCOMPtr& gfxInfo, } static already_AddRefed -CreateHeadlessEGL(bool forceEnabled, bool requireCompatProfile, +CreateHeadlessEGL(bool forceEnabled, const nsCOMPtr& gfxInfo, WebGLContext* webgl) { nsRefPtr gl; #ifdef ANDROID - gl = gl::GLContextProviderEGL::CreateHeadless(requireCompatProfile); + gl = gl::GLContextProviderEGL::CreateHeadless(); if (!gl) { webgl->GenerateWarning("Error during EGL OpenGL init."); return nullptr; @@ -583,22 +583,16 @@ CreateHeadlessGL(bool forceEnabled, const nsCOMPtr& gfxInfo, if (PR_GetEnv("MOZ_WEBGL_FORCE_OPENGL")) disableANGLE = true; - bool requireCompatProfile = webgl->IsWebGL2() ? false : true; - nsRefPtr gl; if (preferEGL) - gl = CreateHeadlessEGL(forceEnabled, requireCompatProfile, webgl); + gl = CreateHeadlessEGL(forceEnabled, gfxInfo, webgl); - if (!gl && !disableANGLE) { - gl = CreateHeadlessANGLE(forceEnabled, gfxInfo, requireCompatProfile, - webgl); - } + if (!gl && !disableANGLE) + gl = CreateHeadlessANGLE(forceEnabled, gfxInfo, webgl); - if (!gl) { - gl = CreateHeadlessNativeGL(forceEnabled, gfxInfo, - requireCompatProfile, webgl); - } + if (!gl) + gl = CreateHeadlessNativeGL(forceEnabled, gfxInfo, webgl); return gl.forget(); } diff --git a/dom/canvas/WebGLContext.h b/dom/canvas/WebGLContext.h index fdaada5f80b0..dabdd737782f 100644 --- a/dom/canvas/WebGLContext.h +++ b/dom/canvas/WebGLContext.h @@ -1209,10 +1209,9 @@ protected: // ------------------------------------------------------------------------- // WebGL 2 specifics (implemented in WebGL2Context.cpp) -public: + virtual bool IsWebGL2() const = 0; -protected: bool InitWebGL2(); // ------------------------------------------------------------------------- diff --git a/dom/canvas/WebGLContextGL.cpp b/dom/canvas/WebGLContextGL.cpp index 1e4d4c1b370a..999b71b67e42 100644 --- a/dom/canvas/WebGLContextGL.cpp +++ b/dom/canvas/WebGLContextGL.cpp @@ -2106,6 +2106,7 @@ WebGLContext::ReadPixels(GLint x, GLint y, GLsizei width, // if we're reading alpha, we may need to do fixup. Note that we don't allow // GL_ALPHA to readpixels currently, but we had the code written for it already. + const bool formatHasAlpha = format == LOCAL_GL_ALPHA || format == LOCAL_GL_RGBA; if (!formatHasAlpha) diff --git a/dom/canvas/WebGLContextUtils.cpp b/dom/canvas/WebGLContextUtils.cpp index caba53cac181..b0e02a185770 100644 --- a/dom/canvas/WebGLContextUtils.cpp +++ b/dom/canvas/WebGLContextUtils.cpp @@ -1117,12 +1117,11 @@ WebGLContext::AssertCachedState() AssertUintParamCorrect(gl, LOCAL_GL_STENCIL_CLEAR_VALUE, mStencilClearValue); GLint stencilBits = 0; - if (GetStencilBits(&stencilBits)) { - const GLuint stencilRefMask = (1 << stencilBits) - 1; + gl->fGetIntegerv(LOCAL_GL_STENCIL_BITS, &stencilBits); + const GLuint stencilRefMask = (1 << stencilBits) - 1; - AssertMaskedUintParamCorrect(gl, LOCAL_GL_STENCIL_REF, stencilRefMask, mStencilRefFront); - AssertMaskedUintParamCorrect(gl, LOCAL_GL_STENCIL_BACK_REF, stencilRefMask, mStencilRefBack); - } + AssertMaskedUintParamCorrect(gl, LOCAL_GL_STENCIL_REF, stencilRefMask, mStencilRefFront); + AssertMaskedUintParamCorrect(gl, LOCAL_GL_STENCIL_BACK_REF, stencilRefMask, mStencilRefBack); // GLES 3.0.4, $4.1.4, p177: // [...] the front and back stencil mask are both set to the value `2^s - 1`, where diff --git a/dom/canvas/WebGLContextValidate.cpp b/dom/canvas/WebGLContextValidate.cpp index e942610793b9..1dbc000a1416 100644 --- a/dom/canvas/WebGLContextValidate.cpp +++ b/dom/canvas/WebGLContextValidate.cpp @@ -1779,8 +1779,8 @@ WebGLContext::InitAndValidateGL() MakeContextCurrent(); - // For OpenGL compat. profiles, we always keep vertex attrib 0 array enabled. - if (gl->IsCompatibilityProfile()) + // on desktop OpenGL, we always keep vertex attrib 0 array enabled + if (!gl->IsGLES()) gl->fEnableVertexAttribArray(0); if (MinCapabilityMode()) @@ -1889,7 +1889,7 @@ WebGLContext::InitAndValidateGL() // Always 1 for GLES2 mMaxFramebufferColorAttachments = 1; - if (gl->IsCompatibilityProfile()) { + if (!gl->IsGLES()) { // gl_PointSize is always available in ES2 GLSL, but has to be // specifically enabled on desktop GLSL. gl->fEnable(LOCAL_GL_VERTEX_PROGRAM_POINT_SIZE); diff --git a/dom/media/fmp4/android/AndroidDecoderModule.cpp b/dom/media/fmp4/android/AndroidDecoderModule.cpp index bd00d07faa7f..84fbd4ef3f54 100644 --- a/dom/media/fmp4/android/AndroidDecoderModule.cpp +++ b/dom/media/fmp4/android/AndroidDecoderModule.cpp @@ -179,7 +179,7 @@ protected: return true; } - mGLContext = GLContextProvider::CreateHeadless(false); + mGLContext = GLContextProvider::CreateHeadless(); return mGLContext; } diff --git a/dom/plugins/base/nsNPAPIPluginInstance.cpp b/dom/plugins/base/nsNPAPIPluginInstance.cpp index 9f94d76639d1..811b75c31bf3 100644 --- a/dom/plugins/base/nsNPAPIPluginInstance.cpp +++ b/dom/plugins/base/nsNPAPIPluginInstance.cpp @@ -91,8 +91,9 @@ static nsRefPtr sPluginContext = nullptr; static bool EnsureGLContext() { if (!sPluginContext) { - bool requireCompatProfile = true; - sPluginContext = GLContextProvider::CreateHeadless(requireCompatProfile); + gfxIntSize dummySize(16, 16); + sPluginContext = GLContextProvider::CreateOffscreen(dummySize, + SurfaceCaps::Any()); } return sPluginContext != nullptr; diff --git a/gfx/gl/GLContext.cpp b/gfx/gl/GLContext.cpp index f84a47c54b02..b300ddff6085 100644 --- a/gfx/gl/GLContext.cpp +++ b/gfx/gl/GLContext.cpp @@ -8,7 +8,6 @@ #include #include #include -#include #include "GLContext.h" #include "GLBlitHelper.h" @@ -157,7 +156,8 @@ static const char *sExtensionNames[] = { "GL_OES_texture_half_float", "GL_OES_texture_half_float_linear", "GL_OES_texture_npot", - "GL_OES_vertex_array_object" + "GL_OES_vertex_array_object", + nullptr }; static bool @@ -501,8 +501,6 @@ GLContext::InitWithPrefix(const char *prefix, bool trygl) mInitialized = LoadSymbols(&symbols[0], trygl, prefix); MakeCurrent(); if (mInitialized) { - MOZ_ASSERT(mProfile != ContextProfile::Unknown); - uint32_t version = 0; ParseGLVersion(this, &version); @@ -658,15 +656,6 @@ GLContext::InitWithPrefix(const char *prefix, bool trygl) } } - if (IsFeatureProvidedByCoreSymbols(GLFeature::get_string_indexed)) { - SymLoadStruct moreSymbols[] = { - { (PRFuncPtr*) &mSymbols.fGetStringi, { "GetStringi", nullptr } }, - END_SYMBOLS - }; - - MOZ_ALWAYS_TRUE(LoadSymbols(moreSymbols, trygl, prefix)); - } - InitExtensions(); InitFeatures(); @@ -681,6 +670,12 @@ GLContext::InitWithPrefix(const char *prefix, bool trygl) MarkUnsupported(GLFeature::standard_derivatives); } + if (Vendor() == GLVendor::Imagination && + Renderer() == GLRenderer::SGX540) { + // Bug 980048 + MarkExtensionUnsupported(OES_EGL_sync); + } + if (Renderer() == GLRenderer::MicrosoftBasicRenderDriver) { // Bug 978966: on Microsoft's "Basic Render Driver" (software renderer) // multisampling hardcodes blending with the default blendfunc, which breaks WebGL. @@ -1473,13 +1468,10 @@ GLContext::InitWithPrefix(const char *prefix, bool trygl) // We're ready for final setup. fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0); - // TODO: Remove SurfaceCaps::any. - if (mCaps.any) { - mCaps.any = false; - mCaps.color = true; - mCaps.alpha = false; - } + if (mCaps.any) + DetermineCaps(); + UpdatePixelFormat(); UpdateGLFormats(mCaps); mTexGarbageBin = new TextureGarbageBin(this); @@ -1601,105 +1593,61 @@ GLContext::DebugCallback(GLenum source, void GLContext::InitExtensions() { - MOZ_ASSERT(IsCurrent()); + MakeCurrent(); + const char* extensions = (const char*)fGetString(LOCAL_GL_EXTENSIONS); + if (!extensions) + return; - std::vector driverExtensionList; + InitializeExtensionsBitSet(mAvailableExtensions, extensions, + sExtensionNames); - if (IsFeatureProvidedByCoreSymbols(GLFeature::get_string_indexed)) { - GLuint count = 0; - GetUIntegerv(LOCAL_GL_NUM_EXTENSIONS, &count); - for (GLuint i = 0; i < count; i++) { - // This is UTF-8. - const char* rawExt = (const char*)fGetStringi(LOCAL_GL_EXTENSIONS, i); + if (WorkAroundDriverBugs() && + Vendor() == GLVendor::Qualcomm) { - // We CANNOT use nsDependentCString here, because the spec doesn't guarantee - // that the pointers returned are different, only that their contents are. - // On Flame, each of these index string queries returns the same address. - driverExtensionList.push_back(nsCString(rawExt)); - } - } else { - MOZ_ALWAYS_TRUE(!fGetError()); - const char* rawExts = (const char*)fGetString(LOCAL_GL_EXTENSIONS); - MOZ_ALWAYS_TRUE(!fGetError()); - - if (rawExts) { - nsDependentCString exts(rawExts); - SplitByChar(exts, ' ', &driverExtensionList); - } + // Some Adreno drivers do not report GL_OES_EGL_sync, but they really do support it. + MarkExtensionSupported(OES_EGL_sync); } - const bool shouldDumpExts = ShouldDumpExts(); - if (shouldDumpExts) { - printf_stderr("%i GL driver extensions: (*: recognized)\n", - (uint32_t)driverExtensionList.size()); + if (WorkAroundDriverBugs() && + Renderer() == GLRenderer::AndroidEmulator) { + // the Android emulator, which we use to run B2G reftests on, + // doesn't expose the OES_rgb8_rgba8 extension, but it seems to + // support it (tautologically, as it only runs on desktop GL). + MarkExtensionSupported(OES_rgb8_rgba8); } - MarkBitfieldByStrings(driverExtensionList, shouldDumpExts, sExtensionNames, - &mAvailableExtensions); - - if (WorkAroundDriverBugs()) { - if (Vendor() == GLVendor::Qualcomm) { - // Some Adreno drivers do not report GL_OES_EGL_sync, but they really do support it. - MarkExtensionSupported(OES_EGL_sync); - } - - if (Vendor() == GLVendor::Imagination && - Renderer() == GLRenderer::SGX540) - { - // Bug 980048 - MarkExtensionUnsupported(OES_EGL_sync); - } - - if (Renderer() == GLRenderer::AndroidEmulator) { - // the Android emulator, which we use to run B2G reftests on, - // doesn't expose the OES_rgb8_rgba8 extension, but it seems to - // support it (tautologically, as it only runs on desktop GL). - MarkExtensionSupported(OES_rgb8_rgba8); - } - - if (Vendor() == GLVendor::VMware && - Renderer() == GLRenderer::GalliumLlvmpipe) - { - // The llvmpipe driver that is used on linux try servers appears to have - // buggy support for s3tc/dxt1 compressed textures. - // See Bug 975824. - MarkExtensionUnsupported(EXT_texture_compression_s3tc); - MarkExtensionUnsupported(EXT_texture_compression_dxt1); - MarkExtensionUnsupported(ANGLE_texture_compression_dxt3); - MarkExtensionUnsupported(ANGLE_texture_compression_dxt5); - } + if (WorkAroundDriverBugs() && + Vendor() == GLVendor::VMware && + Renderer() == GLRenderer::GalliumLlvmpipe) + { + // The llvmpipe driver that is used on linux try servers appears to have + // buggy support for s3tc/dxt1 compressed textures. + // See Bug 975824. + MarkExtensionUnsupported(EXT_texture_compression_s3tc); + MarkExtensionUnsupported(EXT_texture_compression_dxt1); + MarkExtensionUnsupported(ANGLE_texture_compression_dxt3); + MarkExtensionUnsupported(ANGLE_texture_compression_dxt5); + } #ifdef XP_MACOSX - // Bug 1009642: On OSX Mavericks (10.9), the driver for Intel HD - // 3000 appears to be buggy WRT updating sub-images of S3TC - // textures with glCompressedTexSubImage2D. Works on Intel HD 4000 - // and Intel HD 5000/Iris that I tested. - if (nsCocoaFeatures::OSXVersionMajor() == 10 && - nsCocoaFeatures::OSXVersionMinor() == 9 && - Renderer() == GLRenderer::IntelHD3000) - { - MarkExtensionUnsupported(EXT_texture_compression_s3tc); - } + // Bug 1009642: On OSX Mavericks (10.9), the driver for Intel HD + // 3000 appears to be buggy WRT updating sub-images of S3TC + // textures with glCompressedTexSubImage2D. Works on Intel HD 4000 + // and Intel HD 5000/Iris that I tested. + if (WorkAroundDriverBugs() && + nsCocoaFeatures::OSXVersionMajor() == 10 && + nsCocoaFeatures::OSXVersionMinor() == 9 && + Renderer() == GLRenderer::IntelHD3000) + { + MarkExtensionUnsupported(EXT_texture_compression_s3tc); + } #endif - } - - if (shouldDumpExts) { - printf_stderr("\nActivated extensions:\n"); - - for (size_t i = 0; i < mAvailableExtensions.size(); i++) { - if (!mAvailableExtensions[i]) - continue; - - const char* ext = sExtensionNames[i]; - printf_stderr("[%i] %s\n", (uint32_t)i, ext); - } - } } void GLContext::PlatformStartup() { - RegisterStrongMemoryReporter(new GfxTexturesReporter()); + RegisterStrongMemoryReporter(new GfxTexturesReporter()); } // Common code for checking for both GL extensions and GLX extensions. @@ -1740,6 +1688,66 @@ GLContext::ListHasExtension(const GLubyte *extensions, const char *extension) return false; } +void +GLContext::DetermineCaps() +{ + PixelBufferFormat format = QueryPixelFormat(); + + SurfaceCaps caps; + caps.color = !!format.red && !!format.green && !!format.blue; + caps.bpp16 = caps.color && format.ColorBits() == 16; + caps.alpha = !!format.alpha; + caps.depth = !!format.depth; + caps.stencil = !!format.stencil; + caps.antialias = format.samples > 1; + caps.preserve = true; + + mCaps = caps; +} + +PixelBufferFormat +GLContext::QueryPixelFormat() +{ + PixelBufferFormat format; + + ScopedBindFramebuffer autoFB(this, 0); + + fGetIntegerv(LOCAL_GL_RED_BITS , &format.red ); + fGetIntegerv(LOCAL_GL_GREEN_BITS, &format.green); + fGetIntegerv(LOCAL_GL_BLUE_BITS , &format.blue ); + fGetIntegerv(LOCAL_GL_ALPHA_BITS, &format.alpha); + + fGetIntegerv(LOCAL_GL_DEPTH_BITS, &format.depth); + fGetIntegerv(LOCAL_GL_STENCIL_BITS, &format.stencil); + + fGetIntegerv(LOCAL_GL_SAMPLES, &format.samples); + + return format; +} + +void +GLContext::UpdatePixelFormat() +{ + PixelBufferFormat format = QueryPixelFormat(); +#ifdef MOZ_GL_DEBUG + const SurfaceCaps& caps = Caps(); + MOZ_ASSERT(!caps.any, "Did you forget to DetermineCaps()?"); + + MOZ_ASSERT(caps.color == !!format.red); + MOZ_ASSERT(caps.color == !!format.green); + MOZ_ASSERT(caps.color == !!format.blue); + + // These we either must have if they're requested, or + // we can have if they're not. + MOZ_ASSERT(caps.alpha == !!format.alpha || !caps.alpha); + MOZ_ASSERT(caps.depth == !!format.depth || !caps.depth); + MOZ_ASSERT(caps.stencil == !!format.stencil || !caps.stencil); + + MOZ_ASSERT(caps.antialias == (format.samples > 1)); +#endif + mPixelFormat = new PixelBufferFormat(format); +} + GLFormats GLContext::ChooseGLFormats(const SurfaceCaps& caps) const { @@ -2409,13 +2417,6 @@ GLContext::FlushIfHeavyGLCallsSinceLastFlush() fFlush(); } -/*static*/ bool -GLContext::ShouldDumpExts() -{ - static bool ret = PR_GetEnv("MOZ_GL_DUMP_EXTS"); - return ret; -} - bool DoesStringMatch(const char* aString, const char *aWantedString) { @@ -2443,29 +2444,8 @@ DoesStringMatch(const char* aString, const char *aWantedString) /*static*/ bool GLContext::ShouldSpew() { - static bool ret = PR_GetEnv("MOZ_GL_SPEW"); - return ret; -} - -void -SplitByChar(const nsACString& str, const char delim, std::vector* const out) -{ - uint32_t start = 0; - while (true) { - int32_t end = str.FindChar(' ', start); - if (end == -1) - break; - - uint32_t len = (uint32_t)end - start; - nsDependentCSubstring substr(str, start, len); - out->push_back(nsCString(substr)); - - start = end + 1; - continue; - } - - nsDependentCSubstring substr(str, start); - out->push_back(nsCString(substr)); + static bool spew = PR_GetEnv("MOZ_GL_SPEW"); + return spew; } } /* namespace gl */ diff --git a/gfx/gl/GLContext.h b/gfx/gl/GLContext.h index cc6d8fcf2a42..9cc3a0906344 100644 --- a/gfx/gl/GLContext.h +++ b/gfx/gl/GLContext.h @@ -104,7 +104,6 @@ enum class GLFeature { get_integer_indexed, get_integer64_indexed, get_query_object_iv, - get_string_indexed, gpu_shader4, instanced_arrays, instanced_non_arrays, @@ -309,6 +308,7 @@ public: virtual bool IsCurrent() = 0; protected: + bool mInitialized; bool mIsOffscreen; bool mIsGlobalSharedContext; @@ -325,12 +325,9 @@ protected: GLVendor mVendor; GLRenderer mRenderer; - void SetProfileVersion(ContextProfile profile, uint32_t version) { - MOZ_ASSERT(!mInitialized, "SetProfileVersion can only be called before" - " initialization!"); - MOZ_ASSERT(profile != ContextProfile::Unknown && - profile != ContextProfile::OpenGL, - "Invalid `profile` for SetProfileVersion"); + inline void SetProfileVersion(ContextProfile profile, unsigned int version) { + MOZ_ASSERT(!mInitialized, "SetProfileVersion can only be called before initialization!"); + MOZ_ASSERT(profile != ContextProfile::Unknown && profile != ContextProfile::OpenGL, "Invalid `profile` for SetProfileVersion"); MOZ_ASSERT(version >= 100, "Invalid `version` for SetProfileVersion"); mVersion = version; @@ -460,7 +457,6 @@ public: return mAvailableExtensions[aKnownExtension]; } -protected: void MarkExtensionUnsupported(GLExtensions aKnownExtension) { mAvailableExtensions[aKnownExtension] = 0; } @@ -469,6 +465,42 @@ protected: mAvailableExtensions[aKnownExtension] = 1; } +public: + template + static void InitializeExtensionsBitSet(std::bitset& extensionsBitset, + const char* extStr, + const char** extList) + { + char* exts = ::strdup(extStr); + + if (ShouldSpew()) + printf_stderr("Extensions: %s\n", exts); + + char* cur = exts; + bool done = false; + while (!done) { + char* space = strchr(cur, ' '); + if (space) { + *space = '\0'; + } else { + done = true; + } + + for (int i = 0; extList[i]; ++i) { + if (PL_strcasecmp(cur, extList[i]) == 0) { + if (ShouldSpew()) + printf_stderr("Found extension %s\n", cur); + extensionsBitset[i] = true; + } + } + + cur = space + 1; + } + + free(exts); + } + +protected: std::bitset mAvailableExtensions; // ----------------------------------------------------------------------------- @@ -3148,17 +3180,6 @@ public: AFTER_GL_CALL; } -// ----------------------------------------------------------------------------- -// get_string_indexed - - const GLubyte* fGetStringi(GLenum name, GLuint index) { - BEFORE_GL_CALL; - ASSERT_SYMBOL_PRESENT(fGetStringi); - const GLubyte* ret = mSymbols.fGetStringi(name, index); - AFTER_GL_CALL; - return ret; - } - // ----------------------------------------------------------------------------- // Constructor protected: @@ -3427,9 +3448,11 @@ public: fViewport(0, 0, size.width, size.height); mCaps = mScreen->mCaps; - MOZ_ASSERT(!mCaps.any); + if (mCaps.any) + DetermineCaps(); UpdateGLFormats(mCaps); + UpdatePixelFormat(); return true; } @@ -3452,8 +3475,10 @@ public: protected: SurfaceCaps mCaps; nsAutoPtr mGLFormats; + nsAutoPtr mPixelFormat; public: + void DetermineCaps(); const SurfaceCaps& Caps() const { return mCaps; } @@ -3469,6 +3494,14 @@ public: return *mGLFormats; } + PixelBufferFormat QueryPixelFormat(); + void UpdatePixelFormat(); + + const PixelBufferFormat& GetPixelFormat() const { + MOZ_ASSERT(mPixelFormat); + return *mPixelFormat; + } + bool IsFramebufferComplete(GLuint fb, GLenum* status = nullptr); // Does not check completeness. @@ -3508,7 +3541,7 @@ public: } bool IsOffscreen() const { - return mIsOffscreen; + return !!mScreen; } GLScreenBuffer* Screen() const { @@ -3663,42 +3696,10 @@ protected: public: void FlushIfHeavyGLCallsSinceLastFlush(); static bool ShouldSpew(); - static bool ShouldDumpExts(); }; bool DoesStringMatch(const char* aString, const char *aWantedString); -void SplitByChar(const nsACString& str, const char delim, - std::vector* const out); - -template -bool -MarkBitfieldByString(const nsACString& str, const char* (&markStrList)[N], - std::bitset* const out_markList) -{ - for (size_t i = 0; i < N; i++) { - if (str.Equals(markStrList[i])) { - (*out_markList)[i] = 1; - return true; - } - } - return false; -} - -template -void -MarkBitfieldByStrings(const std::vector& strList, - bool dumpStrings, const char* (&markStrList)[N], - std::bitset* const out_markList) -{ - for (auto itr = strList.begin(); itr != strList.end(); ++itr) { - const nsACString& str = *itr; - const bool wasMarked = MarkBitfieldByString(str, markStrList, - out_markList); - if (dumpStrings) - printf_stderr(" %s%s\n", str.BeginReading(), wasMarked ? "(*)" : ""); - } -} } /* namespace gl */ } /* namespace mozilla */ diff --git a/gfx/gl/GLContextCGL.h b/gfx/gl/GLContextCGL.h index 5da7085450cb..9b3c52ddd8e5 100644 --- a/gfx/gl/GLContextCGL.h +++ b/gfx/gl/GLContextCGL.h @@ -28,8 +28,10 @@ class GLContextCGL : public GLContext public: MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(GLContextCGL, MOZ_OVERRIDE) - GLContextCGL(const SurfaceCaps& caps, NSOpenGLContext* context, - bool isOffscreen, ContextProfile profile); + GLContextCGL(const SurfaceCaps& caps, + GLContext *shareContext, + NSOpenGLContext *context, + bool isOffscreen = false); ~GLContextCGL(); diff --git a/gfx/gl/GLContextFeatures.cpp b/gfx/gl/GLContextFeatures.cpp index ed2fa69ec9e2..0e47ecbae087 100644 --- a/gfx/gl/GLContextFeatures.cpp +++ b/gfx/gl/GLContextFeatures.cpp @@ -274,16 +274,6 @@ static const FeatureInfo sFeatureInfoArr[] = { * ARB_occlusion_query (added by OpenGL 2.0). */ }, - { - "get_string_indexed", - GLVersion::GL3, - GLESVersion::ES3, - GLContext::Extension_None, - { - GLContext::Extensions_End - } - // glGetStringi - }, { "gpu_shader4", GLVersion::GL3, diff --git a/gfx/gl/GLContextProviderCGL.mm b/gfx/gl/GLContextProviderCGL.mm index a5c3a9baf3e6..3492e4ab4eac 100644 --- a/gfx/gl/GLContextProviderCGL.mm +++ b/gfx/gl/GLContextProviderCGL.mm @@ -21,14 +21,16 @@ namespace gl { using namespace mozilla::gfx; +static bool gUseDoubleBufferedWindows = true; + class CGLLibrary { public: CGLLibrary() - : mInitialized(false) - , mUseDoubleBufferedWindows(true) - , mOGLLibrary(nullptr) - {} + : mInitialized(false), + mOGLLibrary(nullptr), + mPixelFormat(nullptr) + { } bool EnsureInitialized() { @@ -44,33 +46,48 @@ public: } const char* db = PR_GetEnv("MOZ_CGL_DB"); - if (db) { - mUseDoubleBufferedWindows = *db != '0'; - } + gUseDoubleBufferedWindows = (!db || *db != '0'); mInitialized = true; return true; } - bool UseDoubleBufferedWindows() const { - MOZ_ASSERT(mInitialized); - return mUseDoubleBufferedWindows; - } + NSOpenGLPixelFormat *PixelFormat() + { + if (mPixelFormat == nullptr) { + NSOpenGLPixelFormatAttribute attribs[] = { + NSOpenGLPFAAccelerated, + NSOpenGLPFAAllowOfflineRenderers, + NSOpenGLPFADoubleBuffer, + 0 + }; + if (!gUseDoubleBufferedWindows) { + attribs[2] = 0; + } + + mPixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attribs]; + } + + return mPixelFormat; + } private: bool mInitialized; - bool mUseDoubleBufferedWindows; PRLibrary *mOGLLibrary; + NSOpenGLPixelFormat *mPixelFormat; }; CGLLibrary sCGLLibrary; -GLContextCGL::GLContextCGL(const SurfaceCaps& caps, NSOpenGLContext* context, - bool isOffscreen, ContextProfile profile) - : GLContext(caps, nullptr, isOffscreen) - , mContext(context) +GLContextCGL::GLContextCGL( + const SurfaceCaps& caps, + GLContext *shareContext, + NSOpenGLContext *context, + bool isOffscreen) + : GLContext(caps, shareContext, isOffscreen), + mContext(context) { - SetProfileVersion(profile, 210); + SetProfileVersion(ContextProfile::OpenGLCompatibility, 210); } GLContextCGL::~GLContextCGL() @@ -145,7 +162,7 @@ GLContextCGL::SetupLookupFunction() bool GLContextCGL::IsDoubleBuffered() const { - return sCGLLibrary.UseDoubleBufferedWindows(); + return gUseDoubleBufferedWindows; } bool @@ -165,66 +182,26 @@ GLContextCGL::SwapBuffers() } +static GLContextCGL * +GetGlobalContextCGL() +{ + return static_cast(GLContextProviderCGL::GetGlobalContext()); +} + already_AddRefed GLContextProviderCGL::CreateWrappingExisting(void*, void*) { return nullptr; } -static const NSOpenGLPixelFormatAttribute kAttribs_singleBuffered[] = { - NSOpenGLPFAAccelerated, - NSOpenGLPFAAllowOfflineRenderers, - 0 -}; - -static const NSOpenGLPixelFormatAttribute kAttribs_doubleBuffered[] = { - NSOpenGLPFAAccelerated, - NSOpenGLPFAAllowOfflineRenderers, - NSOpenGLPFADoubleBuffer, - 0 -}; - -static const NSOpenGLPixelFormatAttribute kAttribs_offscreen[] = { - NSOpenGLPFAPixelBuffer, - 0 -}; - -static const NSOpenGLPixelFormatAttribute kAttribs_offscreen_coreProfile[] = { - NSOpenGLPFAAccelerated, - NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core, - 0 -}; - -static NSOpenGLContext* -CreateWithFormat(const NSOpenGLPixelFormatAttribute* attribs) -{ - NSOpenGLPixelFormat* format = [[NSOpenGLPixelFormat alloc] - initWithAttributes:attribs]; - if (!format) - return nullptr; - - NSOpenGLContext* context = [[NSOpenGLContext alloc] initWithFormat:format - shareContext:nullptr]; - - [format release]; - - return context; -} - already_AddRefed GLContextProviderCGL::CreateForWindow(nsIWidget *aWidget) { - if (!sCGLLibrary.EnsureInitialized()) { - return nullptr; - } + GLContextCGL *shareContext = GetGlobalContextCGL(); - const NSOpenGLPixelFormatAttribute* attribs; - if (sCGLLibrary.UseDoubleBufferedWindows()) { - attribs = kAttribs_doubleBuffered; - } else { - attribs = kAttribs_singleBuffered; - } - NSOpenGLContext* context = CreateWithFormat(attribs); + NSOpenGLContext *context = [[NSOpenGLContext alloc] + initWithFormat:sCGLLibrary.PixelFormat() + shareContext:(shareContext ? shareContext->mContext : NULL)]; if (!context) { return nullptr; } @@ -234,13 +211,10 @@ GLContextProviderCGL::CreateForWindow(nsIWidget *aWidget) [context setValues:&opaque forParameter:NSOpenGLCPSurfaceOpacity]; SurfaceCaps caps = SurfaceCaps::ForRGBA(); - ContextProfile profile = ContextProfile::OpenGLCompatibility; - nsRefPtr glContext = new GLContextCGL(caps, context, false, - profile); - + nsRefPtr glContext = new GLContextCGL(caps, + shareContext, + context); if (!glContext->Init()) { - glContext = nullptr; - [context release]; return nullptr; } @@ -248,54 +222,49 @@ GLContextProviderCGL::CreateForWindow(nsIWidget *aWidget) } static already_AddRefed -CreateOffscreenFBOContext(bool requireCompatProfile) +CreateOffscreenFBOContext(bool aShare = true) { if (!sCGLLibrary.EnsureInitialized()) { return nullptr; } - ContextProfile profile; - NSOpenGLContext* context = nullptr; + GLContextCGL *shareContext = aShare ? GetGlobalContextCGL() : nullptr; + if (aShare && !shareContext) { + // if there is no share context, then we can't use FBOs. + return nullptr; + } - if (!requireCompatProfile) { - profile = ContextProfile::OpenGLCore; - context = CreateWithFormat(kAttribs_offscreen_coreProfile); - } - if (!context) { - profile = ContextProfile::OpenGLCompatibility; - context = CreateWithFormat(kAttribs_offscreen); - } + NSOpenGLContext *context = [[NSOpenGLContext alloc] + initWithFormat:sCGLLibrary.PixelFormat() + shareContext:shareContext ? shareContext->GetNSOpenGLContext() : NULL]; if (!context) { return nullptr; } SurfaceCaps dummyCaps = SurfaceCaps::Any(); - nsRefPtr glContext = new GLContextCGL(dummyCaps, context, - true, profile); + nsRefPtr glContext = new GLContextCGL(dummyCaps, shareContext, context, true); return glContext.forget(); } already_AddRefed -GLContextProviderCGL::CreateHeadless(bool requireCompatProfile) +GLContextProviderCGL::CreateHeadless() { - nsRefPtr gl; - gl = CreateOffscreenFBOContext(requireCompatProfile); - if (!gl) + nsRefPtr glContext = CreateOffscreenFBOContext(); + if (!glContext) return nullptr; - if (!gl->Init()) + if (!glContext->Init()) return nullptr; - return gl.forget(); + return glContext.forget(); } already_AddRefed GLContextProviderCGL::CreateOffscreen(const gfxIntSize& size, - const SurfaceCaps& caps, - bool requireCompatProfile) + const SurfaceCaps& caps) { - nsRefPtr glContext = CreateHeadless(requireCompatProfile); + nsRefPtr glContext = CreateHeadless(); if (!glContext->InitOffscreen(ToIntSize(size), caps)) return nullptr; @@ -330,7 +299,7 @@ GLContextProviderCGL::GetGlobalContext() void GLContextProviderCGL::Shutdown() { - gGlobalContext = nullptr; + gGlobalContext = nullptr; } } /* namespace gl */ diff --git a/gfx/gl/GLContextProviderEGL.cpp b/gfx/gl/GLContextProviderEGL.cpp index b946167fa66b..12c2068091db 100644 --- a/gfx/gl/GLContextProviderEGL.cpp +++ b/gfx/gl/GLContextProviderEGL.cpp @@ -878,7 +878,7 @@ GLContextEGL::CreateEGLPixmapOffscreenContext(const gfxIntSize& size) } already_AddRefed -GLContextProviderEGL::CreateHeadless(bool) +GLContextProviderEGL::CreateHeadless() { if (!sEGLLibrary.EnsureInitialized()) { return nullptr; @@ -897,10 +897,9 @@ GLContextProviderEGL::CreateHeadless(bool) // often without the ability to texture from them directly. already_AddRefed GLContextProviderEGL::CreateOffscreen(const gfxIntSize& size, - const SurfaceCaps& caps, - bool requireCompatProfile) + const SurfaceCaps& caps) { - nsRefPtr glContext = CreateHeadless(requireCompatProfile); + nsRefPtr glContext = CreateHeadless(); if (!glContext) return nullptr; diff --git a/gfx/gl/GLContextProviderGLX.cpp b/gfx/gl/GLContextProviderGLX.cpp index f95ae85dafae..bdbc984370d2 100644 --- a/gfx/gl/GLContextProviderGLX.cpp +++ b/gfx/gl/GLContextProviderGLX.cpp @@ -1215,7 +1215,7 @@ DONE_CREATING_PIXMAP: } already_AddRefed -GLContextProviderGLX::CreateHeadless(bool) +GLContextProviderGLX::CreateHeadless() { gfxIntSize dummySize = gfxIntSize(16, 16); nsRefPtr glContext = CreateOffscreenPixmapContext(dummySize); @@ -1227,10 +1227,9 @@ GLContextProviderGLX::CreateHeadless(bool) already_AddRefed GLContextProviderGLX::CreateOffscreen(const gfxIntSize& size, - const SurfaceCaps& caps, - bool requireCompatProfile) + const SurfaceCaps& caps) { - nsRefPtr glContext = CreateHeadless(requireCompatProfile); + nsRefPtr glContext = CreateHeadless(); if (!glContext) return nullptr; diff --git a/gfx/gl/GLContextProviderImpl.h b/gfx/gl/GLContextProviderImpl.h index 9e87170c8237..6efc65de064f 100644 --- a/gfx/gl/GLContextProviderImpl.h +++ b/gfx/gl/GLContextProviderImpl.h @@ -58,12 +58,11 @@ public: */ static already_AddRefed CreateOffscreen(const gfxIntSize& size, - const SurfaceCaps& caps, - bool requireCompatProfile); + const SurfaceCaps& caps); // Just create a context. We'll add offscreen stuff ourselves. static already_AddRefed - CreateHeadless(bool requireCompatProfile); + CreateHeadless(); /** * Create wrapping Gecko GLContext for external gl context. diff --git a/gfx/gl/GLContextProviderNull.cpp b/gfx/gl/GLContextProviderNull.cpp index 231c75be5f3f..61732a6e6b63 100644 --- a/gfx/gl/GLContextProviderNull.cpp +++ b/gfx/gl/GLContextProviderNull.cpp @@ -22,14 +22,13 @@ GLContextProviderNull::CreateWrappingExisting(void*, void*) already_AddRefed GLContextProviderNull::CreateOffscreen(const gfxIntSize&, - const SurfaceCaps&, - bool) + const SurfaceCaps&) { return nullptr; } already_AddRefed -GLContextProviderNull::CreateHeadless(bool) +GLContextProviderNull::CreateHeadless() { return nullptr; } diff --git a/gfx/gl/GLContextProviderWGL.cpp b/gfx/gl/GLContextProviderWGL.cpp index bf605c057e9a..a8c2124d6788 100644 --- a/gfx/gl/GLContextProviderWGL.cpp +++ b/gfx/gl/GLContextProviderWGL.cpp @@ -607,7 +607,7 @@ CreateWindowOffscreenContext() } already_AddRefed -GLContextProviderWGL::CreateHeadless(bool) +GLContextProviderWGL::CreateHeadless() { if (!sWGLLib.EnsureInitialized()) { return nullptr; @@ -641,10 +641,9 @@ GLContextProviderWGL::CreateHeadless(bool) already_AddRefed GLContextProviderWGL::CreateOffscreen(const gfxIntSize& size, - const SurfaceCaps& caps, - bool requireCompatProfile) + const SurfaceCaps& caps) { - nsRefPtr glContext = CreateHeadless(requireCompatProfile); + nsRefPtr glContext = CreateHeadless(); if (!glContext) return nullptr; diff --git a/gfx/gl/GLContextSymbols.h b/gfx/gl/GLContextSymbols.h index 91ff5ac71dc9..3904beac1736 100644 --- a/gfx/gl/GLContextSymbols.h +++ b/gfx/gl/GLContextSymbols.h @@ -666,10 +666,6 @@ struct GLContextSymbols GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid* data); PFNGLCOMPRESSEDTEXSUBIMAGE3D fCompressedTexSubImage3D; - - // get_string_indexed - typedef const GLubyte* (GLAPIENTRY * pfnGLGetStringiT)(GLenum name, GLuint index); - pfnGLGetStringiT fGetStringi; }; } diff --git a/gfx/gl/GLContextTypes.cpp b/gfx/gl/GLContextTypes.cpp index 2cca59dc96aa..b11c99098d28 100644 --- a/gfx/gl/GLContextTypes.cpp +++ b/gfx/gl/GLContextTypes.cpp @@ -12,3 +12,8 @@ GLFormats::GLFormats() { std::memset(this, 0, sizeof(GLFormats)); } + +PixelBufferFormat::PixelBufferFormat() +{ + std::memset(this, 0, sizeof(PixelBufferFormat)); +} diff --git a/gfx/gl/GLContextTypes.h b/gfx/gl/GLContextTypes.h index 979790bb1e58..f21cc11cf06e 100644 --- a/gfx/gl/GLContextTypes.h +++ b/gfx/gl/GLContextTypes.h @@ -43,6 +43,19 @@ struct GLFormats GLsizei samples; }; +struct PixelBufferFormat +{ + // Constructs a zeroed object: + PixelBufferFormat(); + + int red, green, blue; + int alpha; + int depth, stencil; + int samples; + + int ColorBits() const { return red + green + blue; } +}; + } /* namespace gl */ } /* namespace mozilla */ diff --git a/gfx/gl/GLLibraryEGL.cpp b/gfx/gl/GLLibraryEGL.cpp index 40cee8d0c98d..a07b3e79f3df 100644 --- a/gfx/gl/GLLibraryEGL.cpp +++ b/gfx/gl/GLLibraryEGL.cpp @@ -35,7 +35,8 @@ static const char *sEGLExtensionNames[] = { "EGL_EXT_create_context_robustness", "EGL_KHR_image", "EGL_KHR_fence_sync", - "EGL_ANDROID_native_fence_sync" + "EGL_ANDROID_native_fence_sync", + nullptr }; #if defined(ANDROID) @@ -239,8 +240,8 @@ GLLibraryEGL::EnsureInitialized() }; // Do not warn about the failure to load this - see bug 1092191 - GLLibraryLoader::LoadSymbols(mEGLLibrary, &optionalSymbols[0], nullptr, nullptr, - false); + GLLibraryLoader::LoadSymbols(mEGLLibrary, &optionalSymbols[0], + nullptr, nullptr, false); #if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 18 MOZ_RELEASE_ASSERT(mSymbols.fQueryStringImplementationANDROID, @@ -420,24 +421,15 @@ GLLibraryEGL::EnsureInitialized() void GLLibraryEGL::InitExtensions() { - std::vector driverExtensionList; + const char *extensions = (const char*)fQueryString(mEGLDisplay, LOCAL_EGL_EXTENSIONS); - const char* rawExts = (const char*)fQueryString(mEGLDisplay, LOCAL_EGL_EXTENSIONS); - if (rawExts) { - nsDependentCString exts(rawExts); - SplitByChar(exts, ' ', &driverExtensionList); - } else { + if (!extensions) { NS_WARNING("Failed to load EGL extension list!"); + return; } - const bool shouldDumpExts = GLContext::ShouldDumpExts(); - if (shouldDumpExts) { - printf_stderr("%i EGL driver extensions: (*: recognized)\n", - (uint32_t)driverExtensionList.size()); - } - - MarkBitfieldByStrings(driverExtensionList, shouldDumpExts, sEGLExtensionNames, - &mAvailableExtensions); + GLContext::InitializeExtensionsBitSet(mAvailableExtensions, extensions, + sEGLExtensionNames); } void diff --git a/gfx/gl/GLLibraryEGL.h b/gfx/gl/GLLibraryEGL.h index 4e055344c8f5..1d175a217efe 100644 --- a/gfx/gl/GLLibraryEGL.h +++ b/gfx/gl/GLLibraryEGL.h @@ -15,7 +15,6 @@ #include "GeckoProfiler.h" #include -#include #if defined(XP_WIN) diff --git a/gfx/layers/GLImages.cpp b/gfx/layers/GLImages.cpp index 7525eefd40fa..66fa218df961 100644 --- a/gfx/layers/GLImages.cpp +++ b/gfx/layers/GLImages.cpp @@ -39,7 +39,7 @@ GLImage::GetAsSourceSurface() MOZ_ASSERT(NS_IsMainThread(), "Should be on the main thread"); if (!sSnapshotContext) { - sSnapshotContext = GLContextProvider::CreateHeadless(false); + sSnapshotContext = GLContextProvider::CreateHeadless(); if (!sSnapshotContext) { NS_WARNING("Failed to create snapshot GLContext"); return nullptr; diff --git a/gfx/layers/opengl/CompositorOGL.cpp b/gfx/layers/opengl/CompositorOGL.cpp index 4aab23384e89..bc78494c155b 100644 --- a/gfx/layers/opengl/CompositorOGL.cpp +++ b/gfx/layers/opengl/CompositorOGL.cpp @@ -124,11 +124,8 @@ CompositorOGL::CreateContext() SurfaceCaps caps = SurfaceCaps::ForRGB(); caps.preserve = false; caps.bpp16 = gfxPlatform::GetPlatform()->GetOffscreenFormat() == gfxImageFormat::RGB16_565; - - bool requireCompatProfile = true; context = GLContextProvider::CreateOffscreen(gfxIntSize(mSurfaceSize.width, - mSurfaceSize.height), - caps, requireCompatProfile); + mSurfaceSize.height), caps); } if (!context) diff --git a/gfx/tests/gtest/TestCompositor.cpp b/gfx/tests/gtest/TestCompositor.cpp index 273fc5516a4f..70ff21d8a3a0 100644 --- a/gfx/tests/gtest/TestCompositor.cpp +++ b/gfx/tests/gtest/TestCompositor.cpp @@ -45,7 +45,7 @@ public: caps.preserve = false; caps.bpp16 = false; nsRefPtr context = GLContextProvider::CreateOffscreen( - gfxIntSize(gCompWidth, gCompHeight), caps, true); + gfxIntSize(gCompWidth, gCompHeight), caps); return context.forget().take(); } return nullptr; diff --git a/gfx/thebes/gfxPlatform.cpp b/gfx/thebes/gfxPlatform.cpp index 1394387fceba..2e271cf3f52b 100644 --- a/gfx/thebes/gfxPlatform.cpp +++ b/gfx/thebes/gfxPlatform.cpp @@ -1099,9 +1099,8 @@ gfxPlatform::GetSkiaGLGlue() * FIXME: This should be stored in TLS or something, since there needs to be one for each thread using it. As it * stands, this only works on the main thread. */ - bool requireCompatProfile = true; - nsRefPtr glContext; - glContext = mozilla::gl::GLContextProvider::CreateHeadless(requireCompatProfile); + mozilla::gl::SurfaceCaps caps = mozilla::gl::SurfaceCaps::ForRGBA(); + nsRefPtr glContext = mozilla::gl::GLContextProvider::CreateOffscreen(gfxIntSize(16, 16), caps); if (!glContext) { printf_stderr("Failed to create GLContext for SkiaGL!\n"); return nullptr; diff --git a/widget/android/GfxInfo.cpp b/widget/android/GfxInfo.cpp index 95bd0d409cd8..4ab9da311ede 100644 --- a/widget/android/GfxInfo.cpp +++ b/widget/android/GfxInfo.cpp @@ -72,8 +72,8 @@ public: } nsRefPtr gl; - bool requireCompatProfile = true; - gl = gl::GLContextProvider::CreateHeadless(requireCompatProfile); + gl = gl::GLContextProvider::CreateOffscreen(gfxIntSize(16, 16), + gl::SurfaceCaps::ForRGB()); if (!gl) { // Setting mReady to true here means that we won't retry. Everything will From c275b6a4a77197e2e7034fba1372d8673ccdc9cc Mon Sep 17 00:00:00 2001 From: B2G Bumper Bot Date: Fri, 6 Feb 2015 11:37:05 -0800 Subject: [PATCH 58/62] Bumping manifests a=b2g-bump --- b2g/config/dolphin/sources.xml | 2 +- b2g/config/emulator-ics/sources.xml | 2 +- b2g/config/emulator-jb/sources.xml | 2 +- b2g/config/emulator-kk/sources.xml | 2 +- b2g/config/emulator/sources.xml | 2 +- b2g/config/flame-kk/sources.xml | 2 +- b2g/config/flame/sources.xml | 2 +- b2g/config/nexus-4/sources.xml | 2 +- b2g/config/nexus-5-l/sources.xml | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/b2g/config/dolphin/sources.xml b/b2g/config/dolphin/sources.xml index 8e034d75044f..fc15110bb3a0 100644 --- a/b2g/config/dolphin/sources.xml +++ b/b2g/config/dolphin/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/emulator-ics/sources.xml b/b2g/config/emulator-ics/sources.xml index e0bb42426814..62c7bcd63436 100644 --- a/b2g/config/emulator-ics/sources.xml +++ b/b2g/config/emulator-ics/sources.xml @@ -19,7 +19,7 @@ - + diff --git a/b2g/config/emulator-jb/sources.xml b/b2g/config/emulator-jb/sources.xml index b8613175d921..9c2f81a5c9d2 100644 --- a/b2g/config/emulator-jb/sources.xml +++ b/b2g/config/emulator-jb/sources.xml @@ -17,7 +17,7 @@ - + diff --git a/b2g/config/emulator-kk/sources.xml b/b2g/config/emulator-kk/sources.xml index b7224ae44121..5939b6934022 100644 --- a/b2g/config/emulator-kk/sources.xml +++ b/b2g/config/emulator-kk/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/emulator/sources.xml b/b2g/config/emulator/sources.xml index e0bb42426814..62c7bcd63436 100644 --- a/b2g/config/emulator/sources.xml +++ b/b2g/config/emulator/sources.xml @@ -19,7 +19,7 @@ - + diff --git a/b2g/config/flame-kk/sources.xml b/b2g/config/flame-kk/sources.xml index 654701abe994..9eb59e50c003 100644 --- a/b2g/config/flame-kk/sources.xml +++ b/b2g/config/flame-kk/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/flame/sources.xml b/b2g/config/flame/sources.xml index ccf4875ebec7..f6be70727762 100644 --- a/b2g/config/flame/sources.xml +++ b/b2g/config/flame/sources.xml @@ -17,7 +17,7 @@ - + diff --git a/b2g/config/nexus-4/sources.xml b/b2g/config/nexus-4/sources.xml index 2c50bf4b4092..133c348a61b3 100644 --- a/b2g/config/nexus-4/sources.xml +++ b/b2g/config/nexus-4/sources.xml @@ -17,7 +17,7 @@ - + diff --git a/b2g/config/nexus-5-l/sources.xml b/b2g/config/nexus-5-l/sources.xml index 7b8ef464f90a..814fd744b7ea 100644 --- a/b2g/config/nexus-5-l/sources.xml +++ b/b2g/config/nexus-5-l/sources.xml @@ -15,7 +15,7 @@ - + From c64fc8bed62b36388a5a35a7c5d54b48b1799922 Mon Sep 17 00:00:00 2001 From: B2G Bumper Bot Date: Fri, 6 Feb 2015 12:15:04 -0800 Subject: [PATCH 59/62] Bumping gaia.json for 1 gaia revision(s) a=gaia-bump ======== https://hg.mozilla.org/integration/gaia-central/rev/0829f98e30c6 Author: Ryan VanderMeulen Desc: Revert "Bug 1130011 - Removing superfluous touch event listener on the whole window r=kgrandon" This reverts commit 33e864db8d1576eeef537c26af89f7a53b85213a. --- b2g/config/gaia.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/b2g/config/gaia.json b/b2g/config/gaia.json index 7074b3afa500..c85110c777b8 100644 --- a/b2g/config/gaia.json +++ b/b2g/config/gaia.json @@ -1,9 +1,9 @@ { "git": { - "git_revision": "47cda5850572ed93088106e86a69fcd3d0c5c31f", + "git_revision": "a0e71e61922bde009a3b6714cbe965021d3279f1", "remote": "https://git.mozilla.org/releases/gaia.git", "branch": "" }, - "revision": "b3f95ed4290ceed20f0e76e6882380c3bf8ddf34", + "revision": "0829f98e30c6f7795f66052d32e25456eb54bda5", "repo_path": "integration/gaia-central" } From 80b2776bdb98279951e0832b1ce0e5cab69de3c2 Mon Sep 17 00:00:00 2001 From: B2G Bumper Bot Date: Fri, 6 Feb 2015 12:16:37 -0800 Subject: [PATCH 60/62] Bumping manifests a=b2g-bump --- b2g/config/dolphin/sources.xml | 2 +- b2g/config/emulator-ics/sources.xml | 2 +- b2g/config/emulator-jb/sources.xml | 2 +- b2g/config/emulator-kk/sources.xml | 2 +- b2g/config/emulator/sources.xml | 2 +- b2g/config/flame-kk/sources.xml | 2 +- b2g/config/flame/sources.xml | 2 +- b2g/config/nexus-4/sources.xml | 2 +- b2g/config/nexus-5-l/sources.xml | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/b2g/config/dolphin/sources.xml b/b2g/config/dolphin/sources.xml index fc15110bb3a0..9006d3bcd51c 100644 --- a/b2g/config/dolphin/sources.xml +++ b/b2g/config/dolphin/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/emulator-ics/sources.xml b/b2g/config/emulator-ics/sources.xml index 62c7bcd63436..08f9699d0554 100644 --- a/b2g/config/emulator-ics/sources.xml +++ b/b2g/config/emulator-ics/sources.xml @@ -19,7 +19,7 @@ - + diff --git a/b2g/config/emulator-jb/sources.xml b/b2g/config/emulator-jb/sources.xml index 9c2f81a5c9d2..1b0893f608f4 100644 --- a/b2g/config/emulator-jb/sources.xml +++ b/b2g/config/emulator-jb/sources.xml @@ -17,7 +17,7 @@ - + diff --git a/b2g/config/emulator-kk/sources.xml b/b2g/config/emulator-kk/sources.xml index 5939b6934022..b2e9feaff5ca 100644 --- a/b2g/config/emulator-kk/sources.xml +++ b/b2g/config/emulator-kk/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/emulator/sources.xml b/b2g/config/emulator/sources.xml index 62c7bcd63436..08f9699d0554 100644 --- a/b2g/config/emulator/sources.xml +++ b/b2g/config/emulator/sources.xml @@ -19,7 +19,7 @@ - + diff --git a/b2g/config/flame-kk/sources.xml b/b2g/config/flame-kk/sources.xml index 9eb59e50c003..6f748f41b8de 100644 --- a/b2g/config/flame-kk/sources.xml +++ b/b2g/config/flame-kk/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/flame/sources.xml b/b2g/config/flame/sources.xml index f6be70727762..cb27a1a0b6dc 100644 --- a/b2g/config/flame/sources.xml +++ b/b2g/config/flame/sources.xml @@ -17,7 +17,7 @@ - + diff --git a/b2g/config/nexus-4/sources.xml b/b2g/config/nexus-4/sources.xml index 133c348a61b3..6efea03d0359 100644 --- a/b2g/config/nexus-4/sources.xml +++ b/b2g/config/nexus-4/sources.xml @@ -17,7 +17,7 @@ - + diff --git a/b2g/config/nexus-5-l/sources.xml b/b2g/config/nexus-5-l/sources.xml index 814fd744b7ea..75f5f8292c90 100644 --- a/b2g/config/nexus-5-l/sources.xml +++ b/b2g/config/nexus-5-l/sources.xml @@ -15,7 +15,7 @@ - + From a804a4d017f496eaa1df1d900c3eca9bbcecf5f1 Mon Sep 17 00:00:00 2001 From: Nicolas Silva Date: Fri, 6 Feb 2015 16:05:05 -0500 Subject: [PATCH 61/62] Bug 1127289 - Add missing synchronization in TiledContentClient with DrawTargetTiled. r=sotaro CLOSED TREE --- gfx/layers/client/TiledContentClient.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gfx/layers/client/TiledContentClient.cpp b/gfx/layers/client/TiledContentClient.cpp index 31c9bbd0b332..afdf50dd3fcf 100644 --- a/gfx/layers/client/TiledContentClient.cpp +++ b/gfx/layers/client/TiledContentClient.cpp @@ -1091,9 +1091,11 @@ ClientTiledLayerBuffer::UnlockTile(TileClient aTile) // We locked the back buffer, and flipped so we now need to unlock the front if (aTile.mFrontBuffer && aTile.mFrontBuffer->IsLocked()) { aTile.mFrontBuffer->Unlock(); + aTile.mFrontBuffer->SyncWithObject(mCompositableClient->GetForwarder()->GetSyncObject()); } if (aTile.mFrontBufferOnWhite && aTile.mFrontBufferOnWhite->IsLocked()) { aTile.mFrontBufferOnWhite->Unlock(); + aTile.mFrontBufferOnWhite->SyncWithObject(mCompositableClient->GetForwarder()->GetSyncObject()); } if (aTile.mBackBuffer && aTile.mBackBuffer->IsLocked()) { aTile.mBackBuffer->Unlock(); @@ -1293,8 +1295,6 @@ ClientTiledLayerBuffer::ValidateTile(TileClient aTile, tileRegion.SubOut(aDirtyRegion); // Has now been validated backBuffer->SetWaste(tileRegion.Area() * mResolution * mResolution); - backBuffer->Unlock(); - backBuffer->SyncWithObject(mCompositableClient->GetForwarder()->GetSyncObject()); if (createdTextureClient) { if (!mCompositableClient->AddTextureClient(backBuffer)) { From 6af72202792baa5b9b4781ffd29d1aa45195c993 Mon Sep 17 00:00:00 2001 From: Bhavana Bajaj Date: Fri, 6 Feb 2015 14:27:41 -0800 Subject: [PATCH 62/62] Backed out changeset cec0b3b4403a (bug 1129804) --- b2g/app/b2g.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/b2g/app/b2g.js b/b2g/app/b2g.js index 13d99dfbbc02..951bf358d0a1 100644 --- a/b2g/app/b2g.js +++ b/b2g/app/b2g.js @@ -319,7 +319,7 @@ pref("media.fragmented-mp4.gonk.enabled", true); pref("media.video-queue.default-size", 3); // optimize images' memory usage -pref("image.mem.decodeondraw", true); +pref("image.mem.decodeondraw", false); pref("image.mem.allow_locking_in_content_processes", false); /* don't allow image locking */ // Limit the surface cache to 1/8 of main memory or 128MB, whichever is smaller. // Almost everything that was factored into 'max_decoded_image_kb' is now stored