icecat: add release icecat-140.10.1-1gnu1 for ecne

This commit is contained in:
Ark74 2026-05-04 16:58:41 -06:00
parent a5f93cb214
commit ff85d7c623
1256 changed files with 63469 additions and 24141 deletions

View file

@ -1018,18 +1018,40 @@ class FinalizationRegistryCleanup::CleanupRunnable
: public DiscardableRunnable {
public:
explicit CleanupRunnable(FinalizationRegistryCleanup* aCleanupWork)
: DiscardableRunnable("CleanupRunnable"), mCleanupWork(aCleanupWork) {}
: DiscardableRunnable("CleanupRunnable"), mCleanupWork(aCleanupWork) {
MOZ_ASSERT(aCleanupWork);
}
virtual ~CleanupRunnable() {
if (mCleanupWork) {
clearPendingRunnable();
}
}
// MOZ_CAN_RUN_SCRIPT_BOUNDARY until Runnable::Run is MOZ_CAN_RUN_SCRIPT. See
// bug 1535398.
MOZ_CAN_RUN_SCRIPT_BOUNDARY
NS_IMETHOD Run() override {
if (!mCleanupWork) {
// The FinalizationRegistryCleanup has been destroyed.
return NS_OK;
}
clearPendingRunnable();
mCleanupWork->DoCleanup();
mCleanupWork = nullptr;
return NS_OK;
}
void clearPendingRunnable() {
MOZ_ASSERT(mCleanupWork->mPendingRunnable == this);
mCleanupWork->mPendingRunnable = nullptr;
}
private:
FinalizationRegistryCleanup* mCleanupWork;
friend class FinalizationRegistryCleanup;
};
FinalizationRegistryCleanup::FinalizationRegistryCleanup(
@ -1039,6 +1061,10 @@ FinalizationRegistryCleanup::FinalizationRegistryCleanup(
void FinalizationRegistryCleanup::Destroy() {
// This must happen before the CycleCollectedJSContext destructor calls
// JS_DestroyContext().
if (mPendingRunnable) {
MOZ_ASSERT(mPendingRunnable->mCleanupWork == this);
mPendingRunnable->mCleanupWork = nullptr;
}
mCallbacks.reset();
}
@ -1059,7 +1085,7 @@ void FinalizationRegistryCleanup::QueueCallback(JSFunction* aDoCleanup,
void FinalizationRegistryCleanup::QueueCallback(JSFunction* aDoCleanup,
JSObject* aHostDefinedData) {
bool firstCallback = mCallbacks.empty();
MOZ_ASSERT_IF(!mCallbacks.empty(), mPendingRunnable);
JSObject* incumbentGlobal = nullptr;
@ -1074,9 +1100,9 @@ void FinalizationRegistryCleanup::QueueCallback(JSFunction* aDoCleanup,
MOZ_ALWAYS_TRUE(mCallbacks.append(Callback{aDoCleanup, incumbentGlobal}));
if (firstCallback) {
RefPtr<CleanupRunnable> cleanup = new CleanupRunnable(this);
NS_DispatchToCurrentThread(cleanup.forget());
if (!mPendingRunnable) {
mPendingRunnable = new CleanupRunnable(this);
NS_DispatchToCurrentThread(mPendingRunnable);
}
}

View file

@ -134,6 +134,10 @@ class FinalizationRegistryCleanup {
// pointer to its containing context here.
CycleCollectedJSContext* mContext;
// Weak pointer to a previously dispatched runnable. The CleanupRunnable::Run
// method will null out this pointer.
CleanupRunnable* mPendingRunnable = nullptr;
using CallbackVector = JS::GCVector<Callback, 0, InfallibleAllocPolicy>;
JS::PersistentRooted<CallbackVector> mCallbacks;
};

View file

@ -1762,8 +1762,15 @@ void CycleCollectedJSRuntime::JSObjectsTenured(JS::GCContext* aGCContext) {
for (auto iter = objects.Iter(); !iter.Done(); iter.Next()) {
nsWrapperCache* cache = iter.Get();
if (MOZ_UNLIKELY(!cache)) {
continue;
}
JSObject* wrapper = cache->GetWrapperMaybeDead();
MOZ_DIAGNOSTIC_ASSERT(wrapper);
if (MOZ_UNLIKELY(!wrapper)) {
// Wrapper might have been cleared temporarily while updating reflector
// global.
continue;
}
if (js::gc::InCollectedNurseryRegion(wrapper)) {
MOZ_ASSERT(!cache->PreservingWrapper());
@ -1789,6 +1796,17 @@ void CycleCollectedJSRuntime::NurseryWrapperAdded(nsWrapperCache* aCache) {
mNurseryObjects.InfallibleAppend(aCache);
}
void CycleCollectedJSRuntime::NurseryWrapperRemovedSlow(
nsWrapperCache* aCache) {
MOZ_ASSERT(aCache);
for (auto iter = mNurseryObjects.IterFromLast(); !iter.Done(); iter.Prev()) {
if (iter.Get() == aCache) {
iter.Get() = nullptr;
return;
}
}
}
void CycleCollectedJSRuntime::DeferredFinalize(
DeferredFinalizeAppendFunction aAppendFunc, DeferredFinalizeFunction aFunc,
void* aThing) {

View file

@ -529,6 +529,7 @@ class CycleCollectedJSRuntime {
// storage), because we do not want to keep it alive. nsWrapperCache handles
// this for us via its "object moved" handling.
void NurseryWrapperAdded(nsWrapperCache* aCache);
void NurseryWrapperRemovedSlow(nsWrapperCache* aCache);
void JSObjectsTenured(JS::GCContext* aGCContext);
void DeferredFinalize(DeferredFinalizeAppendFunction aAppendFunc,

View file

@ -167,6 +167,7 @@
#include <utility>
#include "js/friend/CycleCollector.h"
#include "js/SliceBudget.h"
#include "mozilla/Attributes.h"
#include "mozilla/Likely.h"
@ -1257,6 +1258,12 @@ class nsCycleCollector : public nsIMemoryReporter {
// returns whether anything was collected
bool CollectWhite();
void ClearWhiteJSWeakRefTargets();
public:
bool IsGCThingWhiteInCCGraph(JS::GCCellPtr aPtr);
private:
void CleanupAfterCollection();
};
@ -3223,6 +3230,8 @@ bool nsCycleCollector::CollectWhite() {
// - Unlink(whites), which drops outgoing links on each white.
// - Unroot(whites), which returns the whites to normal GC.
ClearWhiteJSWeakRefTargets();
// Segments are 4 KiB on 32-bit and 8 KiB on 64-bit.
static const size_t kSegmentSize = sizeof(void*) * 1024;
SegmentedVector<PtrInfo*, kSegmentSize, InfallibleAllocPolicy> whiteNodes(
@ -3314,6 +3323,31 @@ bool nsCycleCollector::CollectWhite() {
return numWhiteNodes > 0 || numWhiteGCed > 0 || numWhiteJSZones > 0;
}
static bool IsGCThingWhiteInCCGraph(JS::GCCellPtr aPtr, void* aData) {
auto* cc = static_cast<nsCycleCollector*>(aData);
return cc->IsGCThingWhiteInCCGraph(aPtr);
}
bool nsCycleCollector::IsGCThingWhiteInCCGraph(JS::GCCellPtr aPtr) {
PtrInfo* pinfo = mGraph.FindNode(aPtr.asCell());
if (!pinfo) {
return false;
}
MOZ_ASSERT(pinfo->mParticipant);
bool isWhite = pinfo->mColor == white;
MOZ_ASSERT_IF(isWhite, pinfo->IsGrayJS());
return isWhite;
}
void nsCycleCollector::ClearWhiteJSWeakRefTargets() {
// Clear the targets of JS WeakRef objects whose target is part of a cycle
// that we're about to unlink.
JSRuntime* runtime = Runtime()->Runtime();
JS::MaybeClearWeakRefTargets(runtime, &::IsGCThingWhiteInCCGraph, this);
}
////////////////////////
// Memory reporting
////////////////////////

View file

@ -20,6 +20,7 @@
#include "nsXPCOM.h"
#include <atomic>
#include <type_traits>
#include <utility>
#include "mozilla/Attributes.h"
#include "mozilla/Assertions.h"
#include "mozilla/Atomics.h"
@ -416,6 +417,31 @@ class ThreadSafeAutoRefCnt {
mValue.store(aValue, std::memory_order_release);
return aValue;
}
// Atomically decrements the refcount if it is strictly above Limit.
// Returns the pair of {success, new value}.
template <nsrefcnt Limit>
MOZ_ALWAYS_INLINE std::pair<bool, nsrefcnt> DecrementWithLimit() {
// This ensures we can never release the final reference on this thread.
// Callers which want to do that should use operator--() which adds the
// appropriate fencing.
static_assert(Limit > 0,
"DecrementWithLimit cannot release the final reference");
nsrefcnt count = mValue.load(std::memory_order_relaxed);
while (count > Limit) {
// Since this may be the last release on this thread, we need
// release semantics on success so that prior writes on this thread
// are visible to the thread that destroys the object when it reads
// mValue with acquire semantics.
// On failure, this thread still owns a reference to the object,
// so no synchronization is required.
if (mValue.compare_exchange_weak(count, count - 1,
std::memory_order_release,
std::memory_order_relaxed)) {
return {true, count - 1};
}
}
return {false, count};
}
MOZ_ALWAYS_INLINE operator nsrefcnt() const { return get(); }
MOZ_ALWAYS_INLINE nsrefcnt get() const {
// Use acquire semantics since we're not sure what the caller is