diff --git a/accessible/windows/msaa/Compatibility.cpp b/accessible/windows/msaa/Compatibility.cpp index 94cce4cd723b..f6e66db1eddc 100644 --- a/accessible/windows/msaa/Compatibility.cpp +++ b/accessible/windows/msaa/Compatibility.cpp @@ -7,7 +7,9 @@ #include "Compatibility.h" #include "mozilla/WindowsVersion.h" +#if defined(MOZ_CRASHREPORTER) #include "nsExceptionHandler.h" +#endif // defined(MOZ_CRASHREPORTER) #include "nsUnicharUtils.h" #include "nsWindowsDllInterceptor.h" #include "nsWinUtils.h" @@ -353,11 +355,13 @@ UseIAccessibleProxyStub() return true; } +#if defined(MOZ_CRASHREPORTER) // If we reach this point then something is seriously wrong with the // IAccessible configuration in the computer's registry. Let's annotate this // so that we can easily determine this condition during crash analysis. CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("IAccessibleConfig"), NS_LITERAL_CSTRING("NoSystemTypeLibOrPS")); +#endif // defined(MOZ_CRASHREPORTER) return false; } diff --git a/browser/components/preferences/in-content-new/main.js b/browser/components/preferences/in-content-new/main.js index 125c1e59943d..281aaab8ff9e 100644 --- a/browser/components/preferences/in-content-new/main.js +++ b/browser/components/preferences/in-content-new/main.js @@ -5,6 +5,7 @@ /* import-globals-from preferences.js */ /* import-globals-from ../../../../toolkit/mozapps/preferences/fontbuilder.js */ +Components.utils.import("resource://gre/modules/Services.jsm"); Components.utils.import("resource://gre/modules/Downloads.jsm"); Components.utils.import("resource://gre/modules/FileUtils.jsm"); Components.utils.import("resource:///modules/ShellService.jsm"); @@ -56,7 +57,25 @@ var gMainPane = { // when the user will select the default. We refresh here periodically // in case the default changes. On other Windows OS's defaults can also // be set while the prefs are open. - window.setInterval(this.updateSetDefaultBrowser.bind(this), 1000); + let win = Services.wm.getMostRecentWindow("navigator:browser"); + + let pollForDefaultBrowser = () => { + let uri = win.gBrowser.currentURI.spec; + + if ((uri == "about:preferences" || uri == "about:preferences#general") && + document.visibilityState == "visible") { + this.updateSetDefaultBrowser(); + } + + // approximately a "requestIdleInterval" + window.setTimeout(() => { + window.requestIdleCallback(pollForDefaultBrowser); + }, 1000); + }; + + window.setTimeout(() => { + window.requestIdleCallback(pollForDefaultBrowser); + }, 1000); } } diff --git a/browser/components/shell/moz.build b/browser/components/shell/moz.build index 28cf72a31e80..d4a234b4a069 100644 --- a/browser/components/shell/moz.build +++ b/browser/components/shell/moz.build @@ -4,6 +4,11 @@ # 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/. +# For BinaryPath::GetLong for Windows +LOCAL_INCLUDES += [ + '/xpcom/build' +] + XPCSHELL_TESTS_MANIFESTS += ['test/unit/xpcshell.ini'] BROWSER_CHROME_MANIFESTS += ['test/browser.ini'] diff --git a/browser/components/shell/nsWindowsShellService.cpp b/browser/components/shell/nsWindowsShellService.cpp index 288ca84aa484..52631992721f 100644 --- a/browser/components/shell/nsWindowsShellService.cpp +++ b/browser/components/shell/nsWindowsShellService.cpp @@ -5,6 +5,7 @@ #include "nsWindowsShellService.h" +#include "BinaryPath.h" #include "city.h" #include "imgIContainer.h" #include "imgIRequest.h" @@ -228,13 +229,10 @@ nsWindowsShellService::IsDefaultBrowser(bool aStartupCheck, return NS_OK; } - wchar_t exePath[MAX_BUF] = L""; - if (!::GetModuleFileNameW(0, exePath, MAX_BUF)) { - return NS_OK; - } - // Convert the path to a long path since GetModuleFileNameW returns the path - // that was used to launch Firefox which is not necessarily a long path. - if (!::GetLongPathNameW(exePath, exePath, MAX_BUF)) { + wchar_t exePath[MAXPATHLEN] = L""; + nsresult rv = BinaryPath::GetLong(exePath); + + if (NS_FAILED(rv)) { return NS_OK; } diff --git a/dom/base/EventSource.cpp b/dom/base/EventSource.cpp index 3911b71ba7bd..085fa594f681 100644 --- a/dom/base/EventSource.cpp +++ b/dom/base/EventSource.cpp @@ -746,30 +746,6 @@ EventSourceImpl::ParseSegment(const char* aBuffer, uint32_t aLength) } } -class DataAvailableRunnable final : public Runnable -{ - private: - RefPtr mEventSourceImpl; - UniquePtr mData; - uint32_t mLength; - public: - DataAvailableRunnable(EventSourceImpl* aEventSourceImpl, - UniquePtr aData, - uint32_t aLength) - : Runnable("dom::DataAvailableRunnable") - , mEventSourceImpl(aEventSourceImpl) - , mData(Move(aData)) - , mLength(aLength) - { - } - - NS_IMETHOD Run() override - { - mEventSourceImpl->ParseSegment(mData.get(), mLength); - return NS_OK; - } -}; - NS_IMETHODIMP EventSourceImpl::OnDataAvailable(nsIRequest* aRequest, nsISupports* aContext, @@ -777,8 +753,7 @@ EventSourceImpl::OnDataAvailable(nsIRequest* aRequest, uint64_t aOffset, uint32_t aCount) { - // Although we try to retarget OnDataAvailable to target thread, it may fail - // and fallback to main thread. + AssertIsOnTargetThread(); NS_ENSURE_ARG_POINTER(aInputStream); if (IsClosed()) { return NS_ERROR_ABORT; @@ -788,28 +763,8 @@ EventSourceImpl::OnDataAvailable(nsIRequest* aRequest, NS_ENSURE_SUCCESS(rv, rv); uint32_t totalRead; - if (IsTargetThread()) { - rv = aInputStream->ReadSegments(EventSourceImpl::StreamReaderFunc, this, + return aInputStream->ReadSegments(EventSourceImpl::StreamReaderFunc, this, aCount, &totalRead); - } else { - // This could be happened when fail to retarget to target thread and - // fallback to the main thread. - AssertIsOnMainThread(); - auto data = MakeUniqueFallible(aCount); - if (!data) { - return NS_ERROR_OUT_OF_MEMORY; - } - rv = aInputStream->Read(data.get(), aCount, &totalRead); - NS_ENSURE_SUCCESS(rv, rv); - MOZ_ASSERT(totalRead <= aCount, "EventSource read more than available!!"); - - nsCOMPtr dataAvailable = - new DataAvailableRunnable(this, Move(data), totalRead); - - MOZ_ASSERT(mWorkerPrivate); - rv = Dispatch(dataAvailable.forget(), NS_DISPATCH_NORMAL); - } - return rv; } NS_IMETHODIMP diff --git a/dom/html/HTMLFormElement.cpp b/dom/html/HTMLFormElement.cpp index 8746689c65da..d132b6129359 100644 --- a/dom/html/HTMLFormElement.cpp +++ b/dom/html/HTMLFormElement.cpp @@ -100,14 +100,6 @@ HTMLFormElement::HTMLFormElement(already_AddRefed& aNode mSelectedRadioButtons(2), mRequiredRadioButtonCounts(2), mValueMissingRadioGroups(2), - mGeneratingSubmit(false), - mGeneratingReset(false), - mIsSubmitting(false), - mDeferSubmission(false), - mNotifiedObservers(false), - mNotifiedObserversResult(false), - mSubmitPopupState(openAbused), - mSubmitInitiatedFromUserInput(false), mPendingSubmission(nullptr), mSubmittingRequest(nullptr), mDefaultSubmitElement(nullptr), @@ -115,7 +107,15 @@ HTMLFormElement::HTMLFormElement(already_AddRefed& aNode mFirstSubmitNotInElements(nullptr), mImageNameLookupTable(FORM_CONTROL_LIST_HASHTABLE_LENGTH), mPastNameLookupTable(FORM_CONTROL_LIST_HASHTABLE_LENGTH), + mSubmitPopupState(openAbused), mInvalidElementsCount(0), + mGeneratingSubmit(false), + mGeneratingReset(false), + mIsSubmitting(false), + mDeferSubmission(false), + mNotifiedObservers(false), + mNotifiedObserversResult(false), + mSubmitInitiatedFromUserInput(false), mEverTriedInvalidSubmit(false) { // We start out valid. diff --git a/dom/html/HTMLFormElement.h b/dom/html/HTMLFormElement.h index 74a993be7c19..4f806b75f222 100644 --- a/dom/html/HTMLFormElement.h +++ b/dom/html/HTMLFormElement.h @@ -560,22 +560,6 @@ class HTMLFormElement final : public nsGenericHTMLElement, nsDataHashtable mRequiredRadioButtonCounts; /** The value missing state of each group */ nsDataHashtable mValueMissingRadioGroups; - /** Whether we are currently processing a submit event or not */ - bool mGeneratingSubmit; - /** Whether we are currently processing a reset event or not */ - bool mGeneratingReset; - /** Whether we are submitting currently */ - bool mIsSubmitting; - /** Whether the submission is to be deferred in case a script triggers it */ - bool mDeferSubmission; - /** Whether we notified NS_FORMSUBMIT_SUBJECT listeners already */ - bool mNotifiedObservers; - /** If we notified the listeners early, what was the result? */ - bool mNotifiedObserversResult; - /** Keep track of what the popup state was when the submit was initiated */ - PopupControlState mSubmitPopupState; - /** Keep track of whether a submission was user-initiated or not */ - bool mSubmitInitiatedFromUserInput; /** The pending submission object */ nsAutoPtr mPendingSubmission; @@ -612,6 +596,9 @@ class HTMLFormElement final : public nsGenericHTMLElement, nsInterfaceHashtable mPastNameLookupTable; + /** Keep track of what the popup state was when the submit was initiated */ + PopupControlState mSubmitPopupState; + /** * Number of invalid and candidate for constraint validation elements in the * form the last time UpdateValidity has been called. @@ -619,6 +606,20 @@ class HTMLFormElement final : public nsGenericHTMLElement, */ int32_t mInvalidElementsCount; + /** Whether we are currently processing a submit event or not */ + bool mGeneratingSubmit; + /** Whether we are currently processing a reset event or not */ + bool mGeneratingReset; + /** Whether we are submitting currently */ + bool mIsSubmitting; + /** Whether the submission is to be deferred in case a script triggers it */ + bool mDeferSubmission; + /** Whether we notified NS_FORMSUBMIT_SUBJECT listeners already */ + bool mNotifiedObservers; + /** If we notified the listeners early, what was the result? */ + bool mNotifiedObserversResult; + /** Keep track of whether a submission was user-initiated or not */ + bool mSubmitInitiatedFromUserInput; /** * Whether the submission of this form has been ever prevented because of * being invalid. diff --git a/gfx/2d/DrawEventRecorder.h b/gfx/2d/DrawEventRecorder.h index 88bd25ee565c..b9552d4e0cc2 100644 --- a/gfx/2d/DrawEventRecorder.h +++ b/gfx/2d/DrawEventRecorder.h @@ -11,11 +11,7 @@ #include #include -#if defined(_MSC_VER) #include -#else -#include -#endif namespace mozilla { namespace gfx { @@ -87,22 +83,10 @@ class DrawEventRecorderPrivate : public DrawEventRecorder protected: virtual void Flush() = 0; -#if defined(_MSC_VER) - typedef std::unordered_set ObjectSet; - typedef std::unordered_set Uint64Set; - typedef std::unordered_set FontSet; - typedef std::unordered_set SurfaceSet; -#else - typedef std::set ObjectSet; - typedef std::set Uint64Set; - typedef std::set FontSet; - typedef std::set SurfaceSet; -#endif - - ObjectSet mStoredObjects; - Uint64Set mStoredFontData; - FontSet mStoredFonts; - SurfaceSet mStoredSurfaces; + std::unordered_set mStoredObjects; + std::unordered_set mStoredFontData; + std::unordered_set mStoredFonts; + std::unordered_set mStoredSurfaces; }; class DrawEventRecorderFile : public DrawEventRecorderPrivate diff --git a/gfx/layers/composite/ContainerLayerComposite.cpp b/gfx/layers/composite/ContainerLayerComposite.cpp index 0fd655d63923..a5d4adf2a28f 100755 --- a/gfx/layers/composite/ContainerLayerComposite.cpp +++ b/gfx/layers/composite/ContainerLayerComposite.cpp @@ -185,6 +185,12 @@ ContainerPrepare(ContainerT* aContainer, LayerManagerComposite* aManager, const RenderTargetIntRect& aClipRect) { + // We can end up calling prepare multiple times if we duplicated + // layers due to preserve-3d plane splitting. The results + // should be identical, so we only need to do it once. + if (aContainer->mPrepared) { + return; + } aContainer->mPrepared = MakeUnique(); aContainer->mPrepared->mNeedsSurfaceCopy = false; @@ -585,7 +591,6 @@ ContainerRender(ContainerT* aContainer, } if (!surface) { - aContainer->mPrepared = nullptr; return; } @@ -688,6 +693,10 @@ void ContainerLayerComposite::Cleanup() { mPrepared = nullptr; + + for (Layer* l = GetFirstChild(); l; l = l->GetNextSibling()) { + static_cast(l->AsHostLayer())->Cleanup(); + } } void @@ -755,6 +764,16 @@ RefLayerComposite::Prepare(const RenderTargetIntRect& aClipRect) ContainerPrepare(this, mCompositeManager, aClipRect); } +void +RefLayerComposite::Cleanup() +{ + mPrepared = nullptr; + + for (Layer* l = GetFirstChild(); l; l = l->GetNextSibling()) { + static_cast(l->AsHostLayer())->Cleanup(); + } +} + void RefLayerComposite::CleanupResources() { diff --git a/gfx/layers/composite/ContainerLayerComposite.h b/gfx/layers/composite/ContainerLayerComposite.h index 5c7c6a7a79d6..d4959cff2ace 100644 --- a/gfx/layers/composite/ContainerLayerComposite.h +++ b/gfx/layers/composite/ContainerLayerComposite.h @@ -183,6 +183,8 @@ class RefLayerComposite : public RefLayer, DefaultComputeEffectiveTransforms(aTransformToSurface); } + virtual void Cleanup() override; + virtual void CleanupResources() override; virtual HostLayer* AsHostLayer() override { return this; } diff --git a/gfx/layers/d3d11/TextureD3D11.cpp b/gfx/layers/d3d11/TextureD3D11.cpp index 51ff3c6c502f..10e78f844df2 100644 --- a/gfx/layers/d3d11/TextureD3D11.cpp +++ b/gfx/layers/d3d11/TextureD3D11.cpp @@ -932,7 +932,9 @@ DXGITextureHostD3D11::EnsureTextureSource() } if (mProvider) { - MOZ_RELEASE_ASSERT(mProvider->IsValid()); + if (!mProvider->IsValid()) { + return false; + } mTextureSource = new DataTextureSourceD3D11(mFormat, mProvider, mTexture); } else { mTextureSource = new DataTextureSourceD3D11(mDevice, mFormat, mTexture); diff --git a/gfx/layers/ipc/CompositorBridgeParent.cpp b/gfx/layers/ipc/CompositorBridgeParent.cpp index 8e6e0460fb14..0ef25a6d21ed 100644 --- a/gfx/layers/ipc/CompositorBridgeParent.cpp +++ b/gfx/layers/ipc/CompositorBridgeParent.cpp @@ -1428,6 +1428,12 @@ CompositorBridgeParent::InitializeAdvancedLayers(const nsTArray& return false; } + // Currently LayerManagerMLGPU hardcodes a D3D11 device, so we reject using + // AL if LAYERS_D3D11 isn't in the backend hints. + if (!aBackendHints.Contains(LayersBackend::LAYERS_D3D11)) { + return false; + } + RefPtr manager = new LayerManagerMLGPU(mWidget); if (!manager->Initialize()) { return false; diff --git a/gfx/thebes/gfxWindowsPlatform.cpp b/gfx/thebes/gfxWindowsPlatform.cpp index 46eab05a8b39..6a65f819898c 100755 --- a/gfx/thebes/gfxWindowsPlatform.cpp +++ b/gfx/thebes/gfxWindowsPlatform.cpp @@ -459,7 +459,7 @@ gfxWindowsPlatform::UpdateBackendPrefs() BackendTypeBit(BackendType::SKIA); uint32_t contentMask = BackendTypeBit(BackendType::CAIRO) | BackendTypeBit(BackendType::SKIA); - BackendType defaultBackend = BackendType::CAIRO; + BackendType defaultBackend = BackendType::SKIA; if (gfxConfig::IsEnabled(Feature::DIRECT2D) && Factory::GetD2D1Device()) { contentMask |= BackendTypeBit(BackendType::DIRECT2D1_1); canvasMask |= BackendTypeBit(BackendType::DIRECT2D1_1); @@ -506,8 +506,8 @@ gfxWindowsPlatform::GetContentBackendFor(mozilla::layers::LayersBackend aLayers) } if (defaultBackend == BackendType::DIRECT2D1_1) { - // We can't have D2D without D3D11 layers, so fallback to Cairo. - return BackendType::CAIRO; + // We can't have D2D without D3D11 layers, so fallback to Skia. + return BackendType::SKIA; } // Otherwise we have some non-accelerated backend and that's ok. @@ -1387,27 +1387,39 @@ gfxWindowsPlatform::InitializeD3D11Config() d3d11.UserForceEnable("User force-enabled WARP"); } + InitializeAdvancedLayersConfig(); +} + +/* static */ void +gfxWindowsPlatform::InitializeAdvancedLayersConfig() +{ // Only enable Advanced Layers if D3D11 succeeded. - if (d3d11.IsEnabled()) { - FeatureState& al = gfxConfig::GetFeature(Feature::ADVANCED_LAYERS); - - al.SetDefaultFromPref( - gfxPrefs::GetAdvancedLayersEnabledDoNotUseDirectlyPrefName(), - true /* aIsEnablePref */, - gfxPrefs::GetAdvancedLayersEnabledDoNotUseDirectlyPrefDefault()); - - // Windows 7 has an extra pref since it uses totally different buffer paths - // that haven't been performance tested yet. - if (al.IsEnabled() && !IsWin8OrLater()) { - if (gfxPrefs::AdvancedLayersEnableOnWindows7()) { - al.UserEnable("Enabled for Windows 7 via user-preference"); - } else { - al.Disable(FeatureStatus::Disabled, - "Advanced Layers is disabled on Windows 7 by default", - NS_LITERAL_CSTRING("FEATURE_FAILURE_DISABLED_ON_WIN7")); - } + if (!gfxConfig::IsEnabled(Feature::D3D11_COMPOSITING)) { + return; + } + + FeatureState& al = gfxConfig::GetFeature(Feature::ADVANCED_LAYERS); + al.SetDefaultFromPref( + gfxPrefs::GetAdvancedLayersEnabledDoNotUseDirectlyPrefName(), + true /* aIsEnablePref */, + gfxPrefs::GetAdvancedLayersEnabledDoNotUseDirectlyPrefDefault()); + + // Windows 7 has an extra pref since it uses totally different buffer paths + // that haven't been performance tested yet. + if (al.IsEnabled() && !IsWin8OrLater()) { + if (gfxPrefs::AdvancedLayersEnableOnWindows7()) { + al.UserEnable("Enabled for Windows 7 via user-preference"); + } else { + al.Disable(FeatureStatus::Disabled, + "Advanced Layers is disabled on Windows 7 by default", + NS_LITERAL_CSTRING("FEATURE_FAILURE_DISABLED_ON_WIN7")); } } + + nsCString message, failureId; + if (!IsGfxInfoStatusOkay(nsIGfxInfo::FEATURE_ADVANCED_LAYERS, &message, failureId)) { + al.Disable(FeatureStatus::Blacklisted, message.get(), failureId); + } } /* static */ void diff --git a/gfx/thebes/gfxWindowsPlatform.h b/gfx/thebes/gfxWindowsPlatform.h index aaed607b683f..11bf66722515 100644 --- a/gfx/thebes/gfxWindowsPlatform.h +++ b/gfx/thebes/gfxWindowsPlatform.h @@ -258,6 +258,7 @@ class gfxWindowsPlatform : public gfxPlatform void InitializeD3D11Config(); void InitializeD2DConfig(); void InitializeDirectDrawConfig(); + void InitializeAdvancedLayersConfig(); RefPtr mDWriteFactory; RefPtr mRenderingParams[TEXT_RENDERING_COUNT]; diff --git a/ipc/mscom/EnsureMTA.h b/ipc/mscom/EnsureMTA.h index 8f03942d4389..d9553f9c3df4 100644 --- a/ipc/mscom/EnsureMTA.h +++ b/ipc/mscom/EnsureMTA.h @@ -69,7 +69,11 @@ class MOZ_STACK_CLASS EnsureMTA final return; } - static nsAutoHandle event(::CreateEventW(nullptr, FALSE, FALSE, nullptr)); + // Note that we might reenter the EnsureMTA constructor while we wait on + // this event due to APC dispatch, therefore we need a unique event object + // for each entry. If perf becomes an issue then we will want to maintain + // an array of events where the Nth event is unique to the Nth reentry. + nsAutoHandle event(::CreateEventW(nullptr, FALSE, FALSE, nullptr)); if (!event) { return; } diff --git a/js/src/gc/GCRuntime.h b/js/src/gc/GCRuntime.h index b6f1fe68d284..1509ca535a83 100644 --- a/js/src/gc/GCRuntime.h +++ b/js/src/gc/GCRuntime.h @@ -688,7 +688,8 @@ class GCRuntime MOZ_MUST_USE bool triggerGC(JS::gcreason::Reason reason); void maybeAllocTriggerZoneGC(Zone* zone, const AutoLockGC& lock); // The return value indicates if we were able to do the GC. - bool triggerZoneGC(Zone* zone, JS::gcreason::Reason reason); + bool triggerZoneGC(Zone* zone, JS::gcreason::Reason reason, + size_t usedBytes, size_t thresholdBytes); void maybeGC(Zone* zone); // The return value indicates whether a major GC was performed. bool gcIfRequested(); @@ -796,7 +797,10 @@ class GCRuntime MOZ_MUST_USE bool addBlackRootsTracer(JSTraceDataOp traceOp, void* data); void removeBlackRootsTracer(JSTraceDataOp traceOp, void* data); - bool triggerGCForTooMuchMalloc() { return triggerGC(JS::gcreason::TOO_MUCH_MALLOC); } + bool triggerGCForTooMuchMalloc() { + stats().recordTrigger(mallocCounter.bytes(), mallocCounter.maxBytes()); + return triggerGC(JS::gcreason::TOO_MUCH_MALLOC); + } int32_t getMallocBytes() const { return mallocCounter.bytes(); } size_t maxMallocBytesAllocated() const { return mallocCounter.maxBytes(); } bool isTooMuchMalloc() const { return mallocCounter.isTooMuchMalloc(); } diff --git a/js/src/gc/Statistics.cpp b/js/src/gc/Statistics.cpp index bc5385cc344f..5f98c12fadea 100644 --- a/js/src/gc/Statistics.cpp +++ b/js/src/gc/Statistics.cpp @@ -617,6 +617,11 @@ Statistics::formatJsonSliceDescription(unsigned i, const SliceData& slice, JSONP json.property("initial_state", gc::StateName(slice.initialState)); json.property("final_state", gc::StateName(slice.finalState)); json.property("budget", budgetDescription); + json.property("major_gc_number", startingMajorGCNumber); + if (thresholdTriggered) { + json.floatProperty("trigger_amount", triggerAmount, 0); + json.floatProperty("trigger_threshold", triggerThreshold, 0); + } json.property("page_faults", int64_t(slice.endFaults - slice.startFaults)); json.property("start_timestamp", slice.start - originTime, JSONPrinter::SECONDS); json.property("end_timestamp", slice.end - originTime, JSONPrinter::SECONDS); @@ -637,6 +642,9 @@ Statistics::Statistics(JSRuntime* rt) fp(nullptr), nonincrementalReason_(gc::AbortReason::None), preBytes(0), + thresholdTriggered(false), + triggerAmount(0.0), + triggerThreshold(0.0), maxPauseInInterval(0), sliceCallback(nullptr), nurseryCollectionCallback(nullptr), @@ -891,6 +899,7 @@ Statistics::endGC() // Clear the OOM flag. aborted = false; + thresholdTriggered = false; } void diff --git a/js/src/gc/Statistics.h b/js/src/gc/Statistics.h index b38e0b3866b6..6ebeef38849d 100644 --- a/js/src/gc/Statistics.h +++ b/js/src/gc/Statistics.h @@ -187,6 +187,12 @@ struct Statistics return uint32_t(counts[s]); } + void recordTrigger(double amount, double threshold) { + triggerAmount = amount; + triggerThreshold = threshold; + thresholdTriggered = true; + } + void beginNurseryCollection(JS::gcreason::Reason reason); void endNurseryCollection(JS::gcreason::Reason reason); @@ -296,6 +302,12 @@ struct Statistics /* Allocated space before the GC started. */ size_t preBytes; + /* If the GC was triggered by exceeding some threshold, record the + * threshold and the value that exceeded it. */ + bool thresholdTriggered; + double triggerAmount; + double triggerThreshold; + /* GC numbers as of the beginning of the collection. */ uint64_t startingMinorGCNumber; uint64_t startingMajorGCNumber; diff --git a/js/src/gc/Zone.h b/js/src/gc/Zone.h index 502fa012dc1d..e587b406b80c 100644 --- a/js/src/gc/Zone.h +++ b/js/src/gc/Zone.h @@ -407,10 +407,11 @@ struct Zone : public JS::shadow::Zone, bool triggerGCForTooMuchMalloc() { JSRuntime* rt = runtimeFromAnyThread(); - if (CurrentThreadCanAccessRuntime(rt)) - return rt->gc.triggerZoneGC(this, JS::gcreason::TOO_MUCH_MALLOC); - else - return false; + if (CurrentThreadCanAccessRuntime(rt)) { + return rt->gc.triggerZoneGC(this, JS::gcreason::TOO_MUCH_MALLOC, + gcMallocCounter.bytes(), gcMallocCounter.maxBytes()); + } + return false; } void resetGCMallocBytes() { gcMallocCounter.reset(); } diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index 85d283402a63..c84b2dbb6118 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -3030,7 +3030,7 @@ GCRuntime::maybeAllocTriggerZoneGC(Zone* zone, const AutoLockGC& lock) * The threshold has been surpassed, immediately trigger a GC, * which will be done non-incrementally. */ - triggerZoneGC(zone, JS::gcreason::ALLOC_TRIGGER); + triggerZoneGC(zone, JS::gcreason::ALLOC_TRIGGER, usedBytes, thresholdBytes); } else { bool wouldInterruptCollection; size_t igcThresholdBytes; @@ -3056,7 +3056,7 @@ GCRuntime::maybeAllocTriggerZoneGC(Zone* zone, const AutoLockGC& lock) // to try to avoid performing non-incremental GCs on zones // which allocate a lot of data, even when incremental slices // can't be triggered via scheduling in the event loop. - triggerZoneGC(zone, JS::gcreason::ALLOC_TRIGGER); + triggerZoneGC(zone, JS::gcreason::ALLOC_TRIGGER, usedBytes, igcThresholdBytes); // Delay the next slice until a certain amount of allocation // has been performed. @@ -3067,7 +3067,7 @@ GCRuntime::maybeAllocTriggerZoneGC(Zone* zone, const AutoLockGC& lock) } bool -GCRuntime::triggerZoneGC(Zone* zone, JS::gcreason::Reason reason) +GCRuntime::triggerZoneGC(Zone* zone, JS::gcreason::Reason reason, size_t used, size_t threshold) { MOZ_ASSERT(CurrentThreadCanAccessRuntime(rt)); @@ -3090,10 +3090,12 @@ GCRuntime::triggerZoneGC(Zone* zone, JS::gcreason::Reason reason) fullGCForAtomsRequested_ = true; return false; } + stats().recordTrigger(used, threshold); MOZ_RELEASE_ASSERT(triggerGC(reason)); return true; } + stats().recordTrigger(used, threshold); PrepareZoneForGC(zone); requestMajorGC(reason); return true; @@ -3115,11 +3117,12 @@ GCRuntime::maybeGC(Zone* zone) if (gcIfRequested()) return; - if (zone->usage.gcBytes() > 1024 * 1024 && - zone->usage.gcBytes() >= zone->threshold.allocTrigger(schedulingState.inHighFrequencyGCMode()) && - !isIncrementalGCInProgress() && - !isBackgroundSweeping()) + double threshold = zone->threshold.allocTrigger(schedulingState.inHighFrequencyGCMode()); + double usedBytes = zone->usage.gcBytes(); + if (usedBytes > 1024 * 1024 && usedBytes >= threshold && + !isIncrementalGCInProgress() && !isBackgroundSweeping()) { + stats().recordTrigger(usedBytes, threshold); PrepareZoneForGC(zone); startGC(GC_NORMAL, JS::gcreason::EAGER_ALLOC_TRIGGER); } diff --git a/memory/mozjemalloc/mozjemalloc.cpp b/memory/mozjemalloc/mozjemalloc.cpp index 32cc0eec3df6..60dc2717a76e 100644 --- a/memory/mozjemalloc/mozjemalloc.cpp +++ b/memory/mozjemalloc/mozjemalloc.cpp @@ -795,6 +795,13 @@ struct arena_s { arena_bin_t bins[1]; /* Dynamically sized. */ }; +enum ChunkType { + UNKNOWN_CHUNK, + ARENA_CHUNK, // used to back arena runs created by arena_run_alloc + HUGE_CHUNK, // used to back huge allocations (e.g. huge_malloc) + RECYCLED_CHUNK, // chunk has been stored for future use by chunk_recycle +}; + /******************************************************************************/ /* * Data. @@ -1027,7 +1034,7 @@ static size_t opt_chunk_2pow = CHUNK_2POW_DEFAULT; */ static void *chunk_alloc(size_t size, size_t alignment, bool base, bool zero); -static void chunk_dealloc(void *chunk, size_t size); +static void chunk_dealloc(void *chunk, size_t size, enum ChunkType type); static arena_t *arenas_extend(); static void *huge_malloc(size_t size, bool zero); static void *huge_palloc(size_t size, size_t alignment, bool zero); @@ -2021,7 +2028,7 @@ chunk_recycle(extent_tree_t *chunks_szad, extent_tree_t *chunks_ad, size_t size, malloc_mutex_unlock(&chunks_mtx); node = base_node_alloc(); if (!node) { - chunk_dealloc(ret, size); + chunk_dealloc(ret, size, RECYCLED_CHUNK); return nullptr; } malloc_mutex_lock(&chunks_mtx); @@ -2098,7 +2105,7 @@ chunk_alloc(size_t size, size_t alignment, bool base, bool zero) if (ret && base == false) { if (malloc_rtree_set(chunk_rtree, (uintptr_t)ret, ret)) { - chunk_dealloc(ret, size); + chunk_dealloc(ret, size, UNKNOWN_CHUNK); return nullptr; } } @@ -2109,13 +2116,19 @@ chunk_alloc(size_t size, size_t alignment, bool base, bool zero) static void chunk_record(extent_tree_t *chunks_szad, extent_tree_t *chunks_ad, void *chunk, - size_t size) + size_t size, enum ChunkType type) { bool unzeroed; extent_node_t *xnode, *node, *prev, *xprev, key; unzeroed = pages_purge(chunk, size); + /* If purge doesn't zero the chunk, only record arena chunks or + * previously recycled chunks. */ + if (unzeroed && type != ARENA_CHUNK && type != RECYCLED_CHUNK) { + return; + } + /* * Allocate a node before acquiring chunks_mtx even though it might not * be needed, because base_node_alloc() may cause a new base chunk to @@ -2209,7 +2222,7 @@ chunk_dalloc_mmap(void *chunk, size_t size) #undef CAN_RECYCLE static void -chunk_dealloc(void *chunk, size_t size) +chunk_dealloc(void *chunk, size_t size, enum ChunkType type) { MOZ_ASSERT(chunk); @@ -2220,7 +2233,7 @@ chunk_dealloc(void *chunk, size_t size) malloc_rtree_set(chunk_rtree, (uintptr_t)chunk, nullptr); if (chunk_dalloc_mmap(chunk, size)) - chunk_record(&chunks_szad_mmap, &chunks_ad_mmap, chunk, size); + chunk_record(&chunks_szad_mmap, &chunks_ad_mmap, chunk, size, type); } /* @@ -2704,7 +2717,7 @@ arena_chunk_dealloc(arena_t *arena, arena_chunk_t *chunk) LinkedList_Remove(&arena->spare->chunks_madvised_elem); #endif - chunk_dealloc((void *)arena->spare, chunksize); + chunk_dealloc((void *)arena->spare, chunksize, ARENA_CHUNK); arena->stats.mapped -= chunksize; arena->stats.committed -= arena_chunk_header_npages; } @@ -4222,7 +4235,7 @@ huge_dalloc(void *ptr) malloc_mutex_unlock(&huge_mtx); /* Unmap chunk. */ - chunk_dealloc(node->addr, CHUNK_CEILING(node->size)); + chunk_dealloc(node->addr, CHUNK_CEILING(node->size), HUGE_CHUNK); base_node_dealloc(node); } diff --git a/testing/talos/talos/test.py b/testing/talos/talos/test.py index 692a5e6425d1..f627f45da010 100644 --- a/testing/talos/talos/test.py +++ b/testing/talos/talos/test.py @@ -164,7 +164,7 @@ class sessionrestore(TsBase): extensions = \ '${talos}/startup_test/sessionrestore/addon/sessionrestore-signed.xpi' cycles = 10 - timeout = 1000000 + timeout = 900 gecko_profile_startup = True gecko_profile_entries = 10000000 profile_path = '${talos}/startup_test/sessionrestore/profile' diff --git a/toolkit/mozapps/extensions/internal/XPIInstall.jsm b/toolkit/mozapps/extensions/internal/XPIInstall.jsm index 06518f78024e..3c5d5364872d 100644 --- a/toolkit/mozapps/extensions/internal/XPIInstall.jsm +++ b/toolkit/mozapps/extensions/internal/XPIInstall.jsm @@ -71,7 +71,7 @@ XPCOMUtils.defineLazyModuleGetter(this, "XPIInternal", XPCOMUtils.defineLazyModuleGetter(this, "XPIProvider", "resource://gre/modules/addons/XPIProvider.jsm"); -/* globals AddonInternal, BOOTSTRAP_REASONS, KEY_APP_SYSTEM_ADDONS, KEY_APP_SYSTEM_DEFAULTS, KEY_APP_TEMPORARY, TEMPORARY_ADDON_SUFFIX, TOOLKIT_ID, XPIDatabase, XPIStates, applyBlocklistChanges, getExternalType, isTheme, isUsableAddon, isWebExtension, recordAddonTelemetry */ +/* globals AddonInternal, BOOTSTRAP_REASONS, KEY_APP_SYSTEM_ADDONS, KEY_APP_SYSTEM_DEFAULTS, KEY_APP_TEMPORARY, TEMPORARY_ADDON_SUFFIX, TOOLKIT_ID, XPIDatabase, XPIStates, getExternalType, isTheme, isUsableAddon, isWebExtension, recordAddonTelemetry */ const XPI_INTERNAL_SYMBOLS = [ "AddonInternal", "BOOTSTRAP_REASONS", @@ -82,7 +82,6 @@ const XPI_INTERNAL_SYMBOLS = [ "TOOLKIT_ID", "XPIDatabase", "XPIStates", - "applyBlocklistChanges", "getExternalType", "isTheme", "isUsableAddon", @@ -855,6 +854,7 @@ var loadManifestFromDir = async function(aDir, aInstallLocation) { addon.size = getFileSize(aDir); addon.signedState = await verifyDirSignedState(aDir, addon) .then(({signedState}) => signedState); + addon.updateBlocklistState(); addon.appDisabled = !isUsableAddon(addon); defineSyncGUID(addon); @@ -940,6 +940,7 @@ var loadManifestFromZipReader = async function(aZipReader, aInstallLocation) { addon.id = generateTemporaryInstallID(aZipReader.file); } } + addon.updateBlocklistState(); addon.appDisabled = !isUsableAddon(addon); defineSyncGUID(addon); @@ -2137,8 +2138,7 @@ this.LocalAddonInstall = class extends AddonInstall { }); this.existingAddon = addon; - if (addon) - applyBlocklistChanges(addon, this.addon); + this.addon.updateBlocklistState({oldAddon: this.existingAddon}); this.addon.updateDate = Date.now(); this.addon.installDate = addon ? addon.installDate : this.addon.updateDate; @@ -2543,10 +2543,10 @@ this.DownloadAddonInstall = class extends AddonInstall { if (this.existingAddon) { this.addon.existingAddonID = this.existingAddon.id; this.addon.installDate = this.existingAddon.installDate; - applyBlocklistChanges(this.existingAddon, this.addon); } else { this.addon.installDate = this.addon.updateDate; } + this.addon.updateBlocklistState({oldAddon: this.existingAddon}); if (AddonManagerPrivate.callInstallListeners("onDownloadEnded", this.listeners, diff --git a/toolkit/mozapps/extensions/internal/XPIProvider.jsm b/toolkit/mozapps/extensions/internal/XPIProvider.jsm index 88df76785400..4acc37dfbc0e 100644 --- a/toolkit/mozapps/extensions/internal/XPIProvider.jsm +++ b/toolkit/mozapps/extensions/internal/XPIProvider.jsm @@ -98,6 +98,7 @@ const nsIFile = Components.Constructor("@mozilla.org/file/local;1", "nsIFile", const PREF_DB_SCHEMA = "extensions.databaseSchema"; const PREF_XPI_STATE = "extensions.xpiState"; +const PREF_BLOCKLIST_ITEM_URL = "extensions.blocklist.itemURL"; const PREF_BOOTSTRAP_ADDONS = "extensions.bootstrappedAddons"; const PREF_PENDING_OPERATIONS = "extensions.pendingOperations"; const PREF_SKIN_SWITCHPENDING = "extensions.dss.switchPending"; @@ -189,7 +190,7 @@ const TOOLKIT_ID = "toolkit@mozilla.org"; const XPI_SIGNATURE_CHECK_PERIOD = 24 * 60 * 60; -XPCOMUtils.defineConstant(this, "DB_SCHEMA", 21); +XPCOMUtils.defineConstant(this, "DB_SCHEMA", 22); XPCOMUtils.defineLazyPreferenceGetter(this, "ALLOW_NON_MPC", PREF_ALLOW_NON_MPC); @@ -333,7 +334,6 @@ function loadLazyObjects() { syncLoadManifestFromFile, isUsableAddon, recordAddonTelemetry, - applyBlocklistChanges, flushChromeCaches, descriptorToPath, }); @@ -759,57 +759,6 @@ SafeInstallOperation.prototype = { } }; -/** - * Sets the userDisabled and softDisabled properties of an add-on based on what - * values those properties had for a previous instance of the add-on. The - * previous instance may be a previous install or in the case of an application - * version change the same add-on. - * - * NOTE: this may modify aNewAddon in place; callers should save the database if - * necessary - * - * @param aOldAddon - * The previous instance of the add-on - * @param aNewAddon - * The new instance of the add-on - * @param aAppVersion - * The optional application version to use when checking the blocklist - * or undefined to use the current application - * @param aPlatformVersion - * The optional platform version to use when checking the blocklist or - * undefined to use the current platform - */ -function applyBlocklistChanges(aOldAddon, aNewAddon, aOldAppVersion, - aOldPlatformVersion) { - // Copy the properties by default - aNewAddon.userDisabled = aOldAddon.userDisabled; - aNewAddon.softDisabled = aOldAddon.softDisabled; - - let oldBlocklistState = Blocklist.getAddonBlocklistState(aOldAddon.wrapper, - aOldAppVersion, - aOldPlatformVersion); - let newBlocklistState = Blocklist.getAddonBlocklistState(aNewAddon.wrapper); - - // If the blocklist state hasn't changed then the properties don't need to - // change - if (newBlocklistState == oldBlocklistState) - return; - - if (newBlocklistState == Blocklist.STATE_SOFTBLOCKED) { - if (aNewAddon.type != "theme") { - // The add-on has become softblocked, set softDisabled if it isn't already - // userDisabled - aNewAddon.softDisabled = !aNewAddon.userDisabled; - } else { - // Themes just get userDisabled to switch back to the default theme - aNewAddon.userDisabled = true; - } - } else { - // If the new add-on is not softblocked then it cannot be softDisabled - aNewAddon.softDisabled = false; - } -} - /** * Evaluates whether an add-on is allowed to run in safe mode. * @@ -4549,7 +4498,7 @@ this.XPIProvider = { XPIDatabase.updateAddonActive(aAddon, !isDisabled); if (isDisabled) { - if (aAddon.bootstrap) { + if (aAddon.bootstrap && this.activeAddons.has(aAddon.id)) { this.callBootstrapMethod(aAddon, aAddon._sourceBundle, "shutdown", BOOTSTRAP_REASONS.ADDON_DISABLE); this.unloadBootstrapScope(aAddon.id); @@ -4819,6 +4768,8 @@ AddonInternal.prototype = { userDisabled: false, appDisabled: false, softDisabled: false, + blocklistState: Ci.nsIBlocklistService.STATE_NOT_BLOCKED, + blocklistURL: null, sourceURI: null, releaseNotesURI: null, foreignInstall: false, @@ -4988,22 +4939,63 @@ AddonInternal.prototype = { return app; }, - get blocklistState() { + findBlocklistEntry() { let staticItem = findMatchingStaticBlocklistItem(this); - if (staticItem) - return staticItem.level; + if (staticItem) { + let url = Services.urlFormatter.formatURLPref(PREF_BLOCKLIST_ITEM_URL); + return { + state: staticItem.level, + url: url.replace(/%blockID%/g, staticItem.blockID) + }; + } - return Blocklist.getAddonBlocklistState(this.wrapper); + return Blocklist.getAddonBlocklistEntry(this.wrapper); }, - get blocklistURL() { - let staticItem = findMatchingStaticBlocklistItem(this); - if (staticItem) { - let url = Services.urlFormatter.formatURLPref("extensions.blocklist.itemURL"); - return url.replace(/%blockID%/g, staticItem.blockID); + updateBlocklistState(options = {}) { + let {applySoftBlock = true, oldAddon = null, updateDatabase = true} = options; + + if (oldAddon) { + this.userDisabled = oldAddon.userDisabled; + this.softDisabled = oldAddon.softDisabled; + this.blocklistState = oldAddon.blocklistState; + } + let oldState = this.blocklistState; + + let entry = this.findBlocklistEntry(); + let newState = entry ? entry.state : Blocklist.STATE_NOT_BLOCKED; + + this.blocklistState = newState; + this.blocklistURL = entry && entry.url; + + let userDisabled, softDisabled; + // After a blocklist update, the blocklist service manually applies + // new soft blocks after displaying a UI, in which cases we need to + // skip updating it here. + if (applySoftBlock && oldState != newState) { + if (newState == Blocklist.STATE_SOFTBLOCKED) { + if (this.type == "theme") { + userDisabled = true; + } else { + softDisabled = !this.userDisabled; + } + } else { + softDisabled = false; + } } - return Blocklist.getAddonBlocklistURL(this.wrapper); + if (this.inDatabase && updateDatabase) { + XPIProvider.updateAddonDisabledState(this, userDisabled, softDisabled); + XPIDatabase.saveChanges(); + } else { + this.appDisabled = !isUsableAddon(this); + if (userDisabled !== undefined) { + this.userDisabled = userDisabled; + } + if (softDisabled !== undefined) { + this.softDisabled = softDisabled; + } + } }, applyCompatibilityUpdate(aUpdate, aSyncCompatibility) { @@ -5423,6 +5415,10 @@ AddonWrapper.prototype = { return addon.bootstrap && canRunInSafeMode(addon); }, + updateBlocklistState(applySoftBlock = true) { + addonFor(this).updateBlocklistState({applySoftBlock}); + }, + get userDisabled() { let addon = addonFor(this); return addon.softDisabled || addon.userDisabled; @@ -6845,7 +6841,6 @@ this.XPIInternal = { TEMPORARY_ADDON_SUFFIX, TOOLKIT_ID, XPIStates, - applyBlocklistChanges, getExternalType, isTheme, isUsableAddon, diff --git a/toolkit/mozapps/extensions/internal/XPIProviderUtils.js b/toolkit/mozapps/extensions/internal/XPIProviderUtils.js index 1ccd143c0225..011ce4719c44 100644 --- a/toolkit/mozapps/extensions/internal/XPIProviderUtils.js +++ b/toolkit/mozapps/extensions/internal/XPIProviderUtils.js @@ -7,7 +7,7 @@ // These are injected from XPIProvider.jsm /* globals ADDON_SIGNING, SIGNED_TYPES, BOOTSTRAP_REASONS, DB_SCHEMA, AddonInternal, XPIProvider, XPIStates, syncLoadManifestFromFile, - isUsableAddon, recordAddonTelemetry, applyBlocklistChanges, + isUsableAddon, recordAddonTelemetry, flushChromeCaches, descriptorToPath */ var Cc = Components.classes; @@ -76,7 +76,8 @@ const PROP_JSON_FIELDS = ["id", "syncGUID", "location", "version", "type", "strictCompatibility", "locales", "targetApplications", "targetPlatforms", "multiprocessCompatible", "signedState", "seen", "dependencies", "hasEmbeddedWebExtension", "mpcOptedOut", - "userPermissions", "icons", "iconURL", "icon64URL"]; + "userPermissions", "icons", "iconURL", "icon64URL", + "blocklistState", "blocklistURL"]; // Time to wait before async save of XPI JSON database, in milliseconds const ASYNC_SAVE_DELAY_MS = 20; @@ -1324,13 +1325,14 @@ this.XPIDatabaseReconcile = { if (!aNewAddon) { let file = new nsIFile(aAddonState.path); aNewAddon = syncLoadManifestFromFile(file, aInstallLocation); - applyBlocklistChanges(aOldAddon, aNewAddon); // Carry over any pendingUninstall state to add-ons modified directly // in the profile. This is important when the attempt to remove the // add-on in processPendingFileChanges failed and caused an mtime // change to the add-ons files. aNewAddon.pendingUninstall = aOldAddon.pendingUninstall; + + aNewAddon.updateBlocklistState({oldAddon: aOldAddon}); } // The ID in the manifest that was loaded must match the ID of the old @@ -1430,9 +1432,7 @@ this.XPIDatabaseReconcile = { copyProperties(manifest, props, aOldAddon); } - // This updates the addon's JSON cached data in place - applyBlocklistChanges(aOldAddon, aOldAddon, aOldAppVersion, - aOldPlatformVersion); + aOldAddon.updateBlocklistState({updateDatabase: false}); aOldAddon.appDisabled = !isUsableAddon(aOldAddon); return aOldAddon; diff --git a/toolkit/mozapps/extensions/nsBlocklistService.js b/toolkit/mozapps/extensions/nsBlocklistService.js index df4c5684e12c..329b1dc3f521 100644 --- a/toolkit/mozapps/extensions/nsBlocklistService.js +++ b/toolkit/mozapps/extensions/nsBlocklistService.js @@ -380,8 +380,8 @@ Blocklist.prototype = { }, /** - * Private version of getAddonBlocklistState that allows the caller to pass in - * the add-on blocklist entries to compare against. + * Returns a matching blocklist entry for the given add-on, if one + * exists. * * @param id * The ID of the item to get the blocklist state for. @@ -395,16 +395,17 @@ Blocklist.prototype = { * @param toolkitVersion * The toolkit version to compare to, will use the current version if * null. - * @returns The blocklist state for the item, one of the STATE constants as - * defined in nsIBlocklistService. + * @returns A blocklist entry for this item, with `state` and `url` + * properties indicating the block state and URL, if there is + * a matching blocklist entry, or null otherwise. */ - _getAddonBlocklistState(addon, addonEntries, appVersion, toolkitVersion) { + _getAddonBlocklistEntry(addon, addonEntries, appVersion, toolkitVersion) { if (!gBlocklistEnabled) - return Ci.nsIBlocklistService.STATE_NOT_BLOCKED; + return null; // Not all applications implement nsIXULAppInfo (e.g. xpcshell doesn't). if (!appVersion && !gApp.version) - return Ci.nsIBlocklistService.STATE_NOT_BLOCKED; + return null; if (!appVersion) appVersion = gApp.version; @@ -413,13 +414,50 @@ Blocklist.prototype = { var blItem = this._findMatchingAddonEntry(addonEntries, addon); if (!blItem) - return Ci.nsIBlocklistService.STATE_NOT_BLOCKED; + return null; for (let currentblItem of blItem.versions) { - if (currentblItem.includesItem(addon.version, appVersion, toolkitVersion)) - return currentblItem.severity >= gBlocklistLevel ? Ci.nsIBlocklistService.STATE_BLOCKED : - Ci.nsIBlocklistService.STATE_SOFTBLOCKED; + if (currentblItem.includesItem(addon.version, appVersion, toolkitVersion)) { + return { + state: (currentblItem.severity >= gBlocklistLevel ? + Ci.nsIBlocklistService.STATE_BLOCKED : Ci.nsIBlocklistService.STATE_SOFTBLOCKED), + url: blItem.blockID && this._createBlocklistURL(blItem.blockID), + }; + } } + return null; + }, + + getAddonBlocklistEntry(addon, appVersion, toolkitVersion) { + if (!this._isBlocklistLoaded()) + this._loadBlocklist(); + return this._getAddonBlocklistEntry(addon, this._addonEntries, + appVersion, toolkitVersion); + }, + + /** + * Private version of getAddonBlocklistState that allows the caller to pass in + * the add-on blocklist entries to compare against. + * + * @param id + * The ID of the item to get the blocklist state for. + * @param version + * The version of the item to get the blocklist state for. + * @param addonEntries + * The add-on blocklist entries to compare against. + * @param appVersion + * The application version to compare to, will use the current + * version if null. + * @param toolkitVersion + * The toolkit version to compare to, will use the current version if + * null. + * @returns The blocklist state for the item, one of the STATE constants as + * defined in nsIBlocklistService. + */ + _getAddonBlocklistState(addon, addonEntries, appVersion, toolkitVersion) { + let entry = this._getAddonBlocklistEntry(addon, addonEntries, appVersion, toolkitVersion); + if (entry) + return entry.state; return Ci.nsIBlocklistService.STATE_NOT_BLOCKED; }, @@ -475,17 +513,11 @@ Blocklist.prototype = { /* See nsIBlocklistService */ getAddonBlocklistURL(addon, appVersion, toolkitVersion) { - if (!gBlocklistEnabled) - return ""; - if (!this._isBlocklistLoaded()) this._loadBlocklist(); - let blItem = this._findMatchingAddonEntry(this._addonEntries, addon); - if (!blItem || !blItem.blockID) - return null; - - return this._createBlocklistURL(blItem.blockID); + let entry = this._getAddonBlocklistEntry(addon, this._addonEntries); + return entry && entry.url; }, _createBlocklistURL(id) { @@ -1307,10 +1339,15 @@ Blocklist.prototype = { const types = ["extension", "theme", "locale", "dictionary", "service"]; AddonManager.getAddonsByTypes(types, addons => { for (let addon of addons) { - let oldState = Ci.nsIBlocklistService.STATE_NOTBLOCKED; - if (oldAddonEntries) + let oldState = addon.blocklistState; + if (addon.updateBlocklistState) { + addon.updateBlocklistState(false); + } else if (oldAddonEntries) { oldState = this._getAddonBlocklistState(addon, oldAddonEntries); - let state = this.getAddonBlocklistState(addon); + } else { + oldState = Ci.nsIBlocklistService.STATE_NOTBLOCKED; + } + let state = addon.blocklistState; LOG("Blocklist state for " + addon.id + " changed from " + oldState + " to " + state); @@ -1323,7 +1360,7 @@ Blocklist.prototype = { // It's a hard block. We must reset certain preferences. let prefs = this._getAddonPrefs(addon); resetPrefs(prefs); - } + } // Ensure that softDisabled is false if the add-on is not soft blocked if (state != Ci.nsIBlocklistService.STATE_SOFTBLOCKED) diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_bug335238.js b/toolkit/mozapps/extensions/test/xpcshell/test_bug335238.js index a28d8b54b7ad..304c547eb5a0 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/test_bug335238.js +++ b/toolkit/mozapps/extensions/test/xpcshell/test_bug335238.js @@ -88,6 +88,17 @@ var BlocklistService = { return Ci.nsIBlocklistService.STATE_NOT_BLOCKED; }, + getAddonBlocklistEntry(aAddon, aAppVersion, aToolkitVersion) { + let state = this.getAddonBlocklistState(aAddon, aAppVersion, aToolkitVersion); + if (state != Ci.nsIBlocklistService.STATE_NOT_BLOCKED) { + return { + state, + url: "http://example.com/", + }; + } + return null; + }, + getPluginBlocklistState(aPlugin, aVersion, aAppVersion, aToolkitVersion) { return Ci.nsIBlocklistService.STATE_NOT_BLOCKED; }, diff --git a/toolkit/mozapps/update/tests/data/xpcshellUtilsAUS.js b/toolkit/mozapps/update/tests/data/xpcshellUtilsAUS.js index 1de76a6d3ed3..162503a5776a 100644 --- a/toolkit/mozapps/update/tests/data/xpcshellUtilsAUS.js +++ b/toolkit/mozapps/update/tests/data/xpcshellUtilsAUS.js @@ -2647,6 +2647,7 @@ function waitForHelperExit() { */ function setupUpdaterTest(aMarFile, aPostUpdateAsync, aPostUpdateExeRelPathPrefix = "") { + debugDump("start - updater test setup"); let updatesPatchDir = getUpdatesPatchDir(); if (!updatesPatchDir.exists()) { updatesPatchDir.create(Ci.nsIFile.DIRECTORY_TYPE, PERMS_DIRECTORY); @@ -2662,6 +2663,7 @@ function setupUpdaterTest(aMarFile, aPostUpdateAsync, helperBin.copyToFollowingLinks(afterApplyBinDir, gPostUpdateBinFile); gTestFiles.forEach(function SUT_TF_FE(aTestFile) { + debugDump("start - setup test file: " + aTestFile.fileName); if (aTestFile.originalFile || aTestFile.originalContents) { let testDir = getApplyDirFile(aTestFile.relPathDir, true); if (!testDir.exists()) { @@ -2690,11 +2692,13 @@ function setupUpdaterTest(aMarFile, aPostUpdateAsync, } } } + debugDump("finish - setup test file: " + aTestFile.fileName); }); // Add the test directory that will be updated for a successful update or left // in the initial state for a failed update. gTestDirs.forEach(function SUT_TD_FE(aTestDir) { + debugDump("start - setup test directory: " + aTestDir.relPathDir); let testDir = getApplyDirFile(aTestDir.relPathDir, true); if (!testDir.exists()) { testDir.create(Ci.nsIFile.DIRECTORY_TYPE, PERMS_DIRECTORY); @@ -2726,6 +2730,7 @@ function setupUpdaterTest(aMarFile, aPostUpdateAsync, } }); } + debugDump("finish - setup test directory: " + aTestDir.relPathDir); }); setupActiveUpdate(); @@ -2734,6 +2739,7 @@ function setupUpdaterTest(aMarFile, aPostUpdateAsync, createUpdaterINI(aPostUpdateAsync, aPostUpdateExeRelPathPrefix); } + debugDump("finish - updater test setup"); setupAppFilesAsync(); } diff --git a/widget/nsIGfxInfo.idl b/widget/nsIGfxInfo.idl index d706b12a95aa..9c788aa8b7fb 100644 --- a/widget/nsIGfxInfo.idl +++ b/widget/nsIGfxInfo.idl @@ -127,7 +127,7 @@ interface nsIGfxInfo : nsISupports /* Whether Advanced Layers is supported, starting in 56 */ const long FEATURE_ADVANCED_LAYERS = 22; /* the maximum feature value. */ - const long FEATURE_MAX_VALUE = FEATURE_WEBGL2; + const long FEATURE_MAX_VALUE = FEATURE_ADVANCED_LAYERS; /* * A set of return values from GetFeatureStatus diff --git a/widget/windows/GfxInfo.cpp b/widget/windows/GfxInfo.cpp index 559f88b8fda2..29a318e2a638 100644 --- a/widget/windows/GfxInfo.cpp +++ b/widget/windows/GfxInfo.cpp @@ -1318,6 +1318,16 @@ GfxInfo::GetGfxDriverInfo() (nsAString&) GfxDriverInfo::GetDeviceVendor(VendorAMD), GfxDriverInfo::allDevices, nsIGfxInfo::FEATURE_DX_INTEROP2, nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION, DRIVER_LESS_THAN, GfxDriverInfo::allDriverVersions, "DX_INTEROP2_AMD_CRASH"); + + //////////////////////////////////// + // FEATURE_ADVANCED_LAYERS + + // bug 1377866 + APPEND_TO_DRIVER_BLOCKLIST2(OperatingSystem::Windows, + (nsAString&) GfxDriverInfo::GetDeviceVendor(VendorIntel), + (GfxDeviceFamily*) GfxDriverInfo::GetDeviceFamily(IntelHDGraphicsToSandyBridge), + nsIGfxInfo::FEATURE_ADVANCED_LAYERS, nsIGfxInfo::FEATURE_BLOCKED_DEVICE, + DRIVER_LESS_THAN, GfxDriverInfo::allDriverVersions, "FEATURE_FAILURE_BUG_1377866"); } return *mDriverInfo; } diff --git a/xpcom/build/BinaryPath.h b/xpcom/build/BinaryPath.h index 0160d7e0d0e5..8ec672f715c2 100644 --- a/xpcom/build/BinaryPath.h +++ b/xpcom/build/BinaryPath.h @@ -20,6 +20,8 @@ #include "mozilla/UniquePtrExtensions.h" #ifdef MOZILLA_INTERNAL_API +#include "nsCOMPtr.h" +#include "nsIFile.h" #include "nsString.h" #endif @@ -41,13 +43,51 @@ class BinaryPath return NS_OK; } + static nsresult GetLong(wchar_t aResult[MAXPATHLEN]) + { + static bool cached = false; + static wchar_t exeLongPath[MAXPATHLEN] = L""; + + if (!cached) { + nsresult rv = GetW(nullptr, exeLongPath); + + if (NS_FAILED(rv)) { + return rv; + } + + if (!::GetLongPathNameW(exeLongPath, exeLongPath, MAXPATHLEN)) { + return NS_ERROR_FAILURE; + } + + cached = true; + } + + if (wcscpy_s(aResult, MAXPATHLEN, exeLongPath)) { + return NS_ERROR_FAILURE; + } + + return NS_OK; + } + private: static nsresult GetW(const char* argv0, wchar_t aResult[MAXPATHLEN]) { - if (::GetModuleFileNameW(0, aResult, MAXPATHLEN)) { - return NS_OK; + static bool cached = false; + static wchar_t moduleFileName[MAXPATHLEN] = L""; + + if (!cached) { + if (!::GetModuleFileNameW(0, moduleFileName, MAXPATHLEN)) { + return NS_ERROR_FAILURE; + } + + cached = true; } - return NS_ERROR_FAILURE; + + if (wcscpy_s(aResult, MAXPATHLEN, moduleFileName)) { + return NS_ERROR_FAILURE; + } + + return NS_OK; } #elif defined(XP_MACOSX) diff --git a/xpcom/system/nsIBlocklistService.idl b/xpcom/system/nsIBlocklistService.idl index b70038431d7a..5db4868d2d27 100644 --- a/xpcom/system/nsIBlocklistService.idl +++ b/xpcom/system/nsIBlocklistService.idl @@ -92,6 +92,26 @@ interface nsIBlocklistService : nsISupports [optional] in AString appVersion, [optional] in AString toolkitVersion); + /** + * Returns the blocklist entry, as an object with `state` and `url` + * properties, if a blocklist entry for the add-on exists, or null + * othereise. + + * @param addon + * The addon object to match. + * @param appVersion + * The version of the application we are checking in the blocklist. + * If this parameter is null, the version of the running application + * is used. + * @param toolkitVersion + * The version of the toolkit we are checking in the blocklist. + * If this parameter is null, the version of the running toolkit + * is used. + */ + jsval getAddonBlocklistEntry(in jsval addon, + [optional] in AString appVersion, + [optional] in AString toolkitVersion); + /** * Determine the blocklist web page of a plugin. * @param plugin