mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-23 12:51:06 +00:00
Merge inbound to mozilla-central r=merge a=merge
This commit is contained in:
commit
a731ff981c
@ -929,7 +929,7 @@ D3D11DXVA2Manager::CopyToImage(IMFSample* aVideoSample,
|
||||
NS_ENSURE_TRUE(client, E_FAIL);
|
||||
|
||||
RefPtr<IDXGIKeyedMutex> mutex;
|
||||
HRESULT hr;
|
||||
HRESULT hr = S_OK;
|
||||
RefPtr<ID3D11Texture2D> texture = image->GetTexture();
|
||||
|
||||
texture->QueryInterface((IDXGIKeyedMutex**)getter_AddRefs(mutex));
|
||||
@ -987,7 +987,9 @@ D3D11DXVA2Manager::CopyToImage(IMFSample* aVideoSample,
|
||||
// It appears some race-condition may allow us to arrive here even when mSyncObject
|
||||
// is null. It's better to avoid that crash.
|
||||
client->SyncWithObject(mSyncObject);
|
||||
mSyncObject->Synchronize();
|
||||
if (!mSyncObject->Synchronize(true)) {
|
||||
return DXGI_ERROR_DEVICE_RESET;
|
||||
}
|
||||
}
|
||||
|
||||
image.forget(aOutImage);
|
||||
|
@ -115,6 +115,10 @@ WMFMediaDataDecoder::ProcessError(HRESULT aError, const char* aReason)
|
||||
SendTelemetry(aError);
|
||||
mRecordedError = true;
|
||||
}
|
||||
|
||||
//TODO: For the error DXGI_ERROR_DEVICE_RESET, we could return
|
||||
// NS_ERROR_DOM_MEDIA_NEED_NEW_DECODER to get the latest device. Maybe retry
|
||||
// up to 3 times.
|
||||
return DecodePromise::CreateAndReject(
|
||||
MediaResult(NS_ERROR_DOM_MEDIA_DECODE_ERR,
|
||||
RESULT_DETAIL("%s:%x", aReason, aError)),
|
||||
@ -127,7 +131,10 @@ WMFMediaDataDecoder::ProcessDecode(MediaRawData* aSample)
|
||||
DecodedData results;
|
||||
HRESULT hr = mMFTManager->Input(aSample);
|
||||
if (hr == MF_E_NOTACCEPTING) {
|
||||
ProcessOutput(results);
|
||||
hr = ProcessOutput(results);
|
||||
if (FAILED(hr)) {
|
||||
return ProcessError(hr, "MFTManager::Output(1)");
|
||||
}
|
||||
hr = mMFTManager->Input(aSample);
|
||||
}
|
||||
|
||||
@ -143,7 +150,7 @@ WMFMediaDataDecoder::ProcessDecode(MediaRawData* aSample)
|
||||
if (SUCCEEDED(hr) || hr == MF_E_TRANSFORM_NEED_MORE_INPUT) {
|
||||
return DecodePromise::CreateAndResolve(Move(results), __func__);
|
||||
}
|
||||
return ProcessError(hr, "MFTManager::Output");
|
||||
return ProcessError(hr, "MFTManager::Output(2)");
|
||||
}
|
||||
|
||||
HRESULT
|
||||
|
@ -108,6 +108,6 @@ load oscillator-ended-1.html
|
||||
load oscillator-ended-2.html
|
||||
skip-if(Android&&AndroidVersion=='22') load video-replay-after-audio-end.html # bug 1315125, bug 1358876
|
||||
# This needs to run at the end to avoid leaking busted state into other tests.
|
||||
load 691096-1.html
|
||||
skip-if(Android) load 691096-1.html # Bug 1365451
|
||||
load 1236639.html
|
||||
test-pref(media.navigator.permission.disabled,true) load 1388372.html
|
||||
|
@ -843,6 +843,7 @@ tags=msg
|
||||
skip-if = android_version == '17' # android(bug 1232305)
|
||||
tags=msg
|
||||
[test_mediarecorder_record_addtracked_stream.html]
|
||||
skip-if = toolkit == 'android' # Bug 1408241
|
||||
tags=msg capturestream
|
||||
[test_mediarecorder_record_audiocontext.html]
|
||||
skip-if = android_version == '17' # android(bug 1232305)
|
||||
|
@ -28,14 +28,15 @@ public:
|
||||
|
||||
static already_AddRefed<SyncObjectHost> CreateSyncObjectHost(
|
||||
#ifdef XP_WIN
|
||||
ID3D11Device* aDevice = nullptr
|
||||
ID3D11Device* aDevice = nullptr
|
||||
#endif
|
||||
);
|
||||
);
|
||||
|
||||
virtual bool Init() = 0;
|
||||
|
||||
virtual SyncHandle GetSyncHandle() = 0;
|
||||
|
||||
// Return false for failed synchronization.
|
||||
virtual bool Synchronize() = 0;
|
||||
|
||||
protected:
|
||||
@ -50,9 +51,9 @@ public:
|
||||
|
||||
static already_AddRefed<SyncObjectClient> CreateSyncObjectClient(SyncHandle aHandle
|
||||
#ifdef XP_WIN
|
||||
, ID3D11Device* aDevice = nullptr
|
||||
, ID3D11Device* aDevice = nullptr
|
||||
#endif
|
||||
);
|
||||
);
|
||||
|
||||
enum class SyncType {
|
||||
D3D11,
|
||||
@ -60,7 +61,8 @@ public:
|
||||
|
||||
virtual SyncType GetSyncType() = 0;
|
||||
|
||||
virtual void Synchronize() = 0;
|
||||
// Return false for failed synchronization.
|
||||
virtual bool Synchronize(bool aFallible = false) = 0;
|
||||
|
||||
virtual bool IsSyncObjectValid() = 0;
|
||||
|
||||
|
@ -1697,7 +1697,7 @@ SyncObjectD3D11Client::SyncObjectD3D11Client(SyncHandle aSyncHandle, ID3D11Devic
|
||||
}
|
||||
|
||||
bool
|
||||
SyncObjectD3D11Client::Init()
|
||||
SyncObjectD3D11Client::Init(bool aFallible)
|
||||
{
|
||||
if (mKeyedMutex) {
|
||||
return true;
|
||||
@ -1709,7 +1709,7 @@ SyncObjectD3D11Client::Init()
|
||||
(void**)(ID3D11Texture2D**)getter_AddRefs(mSyncTexture));
|
||||
if (FAILED(hr) || !mSyncTexture) {
|
||||
gfxCriticalNote << "Failed to OpenSharedResource for SyncObjectD3D11: " << hexa(hr);
|
||||
if (ShouldDevCrashOnSyncInitFailure()) {
|
||||
if (!aFallible && ShouldDevCrashOnSyncInitFailure()) {
|
||||
gfxDevCrash(LogReason::D3D11FinalizeFrame) << "Without device reset: " << hexa(hr);
|
||||
}
|
||||
return false;
|
||||
@ -1719,8 +1719,13 @@ SyncObjectD3D11Client::Init()
|
||||
if (FAILED(hr) || !mKeyedMutex) {
|
||||
// Leave both the critical error and MOZ_CRASH for now; the critical error lets
|
||||
// us "save" the hr value. We will probably eventually replace this with gfxDevCrash.
|
||||
gfxCriticalError() << "Failed to get KeyedMutex (2): " << hexa(hr);
|
||||
MOZ_CRASH("GFX: Cannot get D3D11 KeyedMutex");
|
||||
if (!aFallible) {
|
||||
gfxCriticalError() << "Failed to get KeyedMutex (2): " << hexa(hr);
|
||||
MOZ_CRASH("GFX: Cannot get D3D11 KeyedMutex");
|
||||
} else {
|
||||
gfxCriticalNote << "Failed to get KeyedMutex (3): " << hexa(hr);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -1747,8 +1752,8 @@ SyncObjectD3D11Client::IsSyncObjectValid()
|
||||
// into our sync object and only use a lock for this sync object.
|
||||
// This way, we don't have to sync every texture we send to the compositor.
|
||||
// We only have to do this once per transaction.
|
||||
void
|
||||
SyncObjectD3D11Client::Synchronize()
|
||||
bool
|
||||
SyncObjectD3D11Client::Synchronize(bool aFallible)
|
||||
{
|
||||
// Since this can be called from either the Paint or Main thread.
|
||||
// We don't want this to race since we initialize the sync texture here
|
||||
@ -1756,10 +1761,10 @@ SyncObjectD3D11Client::Synchronize()
|
||||
MutexAutoLock syncLock(mSyncLock);
|
||||
|
||||
if (!mSyncedTextures.size()) {
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
if (!Init()) {
|
||||
return;
|
||||
if (!Init(aFallible)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
HRESULT hr;
|
||||
@ -1768,9 +1773,14 @@ SyncObjectD3D11Client::Synchronize()
|
||||
if (hr == WAIT_TIMEOUT) {
|
||||
if (DeviceManagerDx::Get()->HasDeviceReset()) {
|
||||
gfxWarning() << "AcquireSync timed out because of device reset.";
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
gfxDevCrash(LogReason::D3D11SyncLock) << "Timeout on the D3D11 sync lock";
|
||||
if (aFallible) {
|
||||
gfxWarning() << "Timeout on the D3D11 sync lock.";
|
||||
} else {
|
||||
gfxDevCrash(LogReason::D3D11SyncLock) << "Timeout on the D3D11 sync lock.";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
D3D11_BOX box;
|
||||
@ -1782,13 +1792,13 @@ SyncObjectD3D11Client::Synchronize()
|
||||
|
||||
if (dev == DeviceManagerDx::Get()->GetContentDevice()) {
|
||||
if (DeviceManagerDx::Get()->HasDeviceReset()) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (dev != mDevice) {
|
||||
gfxWarning() << "Attempt to sync texture from invalid device.";
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
RefPtr<ID3D11DeviceContext> ctx;
|
||||
@ -1799,6 +1809,8 @@ SyncObjectD3D11Client::Synchronize()
|
||||
}
|
||||
|
||||
mSyncedTextures.clear();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
|
@ -478,7 +478,7 @@ class SyncObjectD3D11Client : public SyncObjectClient
|
||||
public:
|
||||
explicit SyncObjectD3D11Client(SyncHandle aSyncHandle, ID3D11Device* aDevice);
|
||||
|
||||
virtual void Synchronize() override;
|
||||
virtual bool Synchronize(bool aFallible) override;
|
||||
|
||||
virtual bool IsSyncObjectValid() override;
|
||||
|
||||
@ -487,7 +487,7 @@ public:
|
||||
void RegisterTexture(ID3D11Texture2D* aTexture);
|
||||
|
||||
private:
|
||||
bool Init();
|
||||
bool Init(bool aFallible);
|
||||
|
||||
SyncHandle mSyncHandle;
|
||||
RefPtr<ID3D11Device> mDevice;
|
||||
|
@ -1210,10 +1210,11 @@ class GCRuntime
|
||||
AtomMarkingRuntime atomMarking;
|
||||
|
||||
private:
|
||||
// When empty, chunks reside in the emptyChunks pool and are re-used as
|
||||
// needed or eventually expired if not re-used. The emptyChunks pool gets
|
||||
// refilled from the background allocation task heuristically so that empty
|
||||
// chunks should always available for immediate allocation without syscalls.
|
||||
// When chunks are empty, they reside in the emptyChunks pool and are
|
||||
// re-used as needed or eventually expired if not re-used. The emptyChunks
|
||||
// pool gets refilled from the background allocation task heuristically so
|
||||
// that empty chunks should always be available for immediate allocation
|
||||
// without syscalls.
|
||||
GCLockData<ChunkPool> emptyChunks_;
|
||||
|
||||
// Chunks which have had some, but not all, of their arenas allocated live
|
||||
|
@ -116,7 +116,8 @@ js::Nursery::Nursery(JSRuntime* rt)
|
||||
, currentStartPosition_(0)
|
||||
, currentEnd_(0)
|
||||
, currentChunk_(0)
|
||||
, maxNurseryChunks_(0)
|
||||
, maxChunkCount_(0)
|
||||
, chunkCountLimit_(0)
|
||||
, previousPromotionRate_(0)
|
||||
, profileThreshold_(0)
|
||||
, enableProfiling_(false)
|
||||
@ -140,15 +141,18 @@ js::Nursery::init(uint32_t maxNurseryBytes, AutoLockGCBgAlloc& lock)
|
||||
return false;
|
||||
|
||||
/* maxNurseryBytes parameter is rounded down to a multiple of chunk size. */
|
||||
maxNurseryChunks_ = maxNurseryBytes >> ChunkShift;
|
||||
chunkCountLimit_ = maxNurseryBytes >> ChunkShift;
|
||||
|
||||
/* If no chunks are specified then the nursery is permanently disabled. */
|
||||
if (maxNurseryChunks_ == 0)
|
||||
if (chunkCountLimit_ == 0)
|
||||
return true;
|
||||
|
||||
updateNumChunksLocked(1, lock);
|
||||
if (numChunks() == 0)
|
||||
maxChunkCount_ = 1;
|
||||
if (!allocateNextChunk(0, lock)) {
|
||||
maxChunkCount_ = 0;
|
||||
return false;
|
||||
}
|
||||
/* After this point the Nursery has been enabled */
|
||||
|
||||
setCurrentChunk(0);
|
||||
setStartPosition();
|
||||
@ -192,12 +196,17 @@ js::Nursery::enable()
|
||||
{
|
||||
MOZ_ASSERT(isEmpty());
|
||||
MOZ_ASSERT(!runtime()->gc.isVerifyPreBarriersEnabled());
|
||||
if (isEnabled() || !maxChunks())
|
||||
if (isEnabled() || !chunkCountLimit())
|
||||
return;
|
||||
|
||||
updateNumChunks(1);
|
||||
if (numChunks() == 0)
|
||||
return;
|
||||
{
|
||||
AutoLockGCBgAlloc lock(runtime());
|
||||
maxChunkCount_ = 1;
|
||||
if (!allocateNextChunk(0, lock)) {
|
||||
maxChunkCount_ = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
setCurrentChunk(0);
|
||||
setStartPosition();
|
||||
@ -215,8 +224,12 @@ js::Nursery::disable()
|
||||
MOZ_ASSERT(isEmpty());
|
||||
if (!isEnabled())
|
||||
return;
|
||||
updateNumChunks(0);
|
||||
|
||||
freeChunksFrom(0);
|
||||
maxChunkCount_ = 0;
|
||||
|
||||
currentEnd_ = 0;
|
||||
|
||||
runtime()->gc.storeBuffer().disable();
|
||||
}
|
||||
|
||||
@ -237,7 +250,7 @@ js::Nursery::isEmpty() const
|
||||
void
|
||||
js::Nursery::enterZealMode() {
|
||||
if (isEnabled())
|
||||
updateNumChunks(maxNurseryChunks_);
|
||||
maxChunkCount_ = chunkCountLimit();
|
||||
}
|
||||
|
||||
void
|
||||
@ -303,9 +316,19 @@ js::Nursery::allocate(size_t size)
|
||||
#endif
|
||||
|
||||
if (currentEnd() < position() + size) {
|
||||
if (currentChunk_ + 1 == numChunks())
|
||||
unsigned chunkno = currentChunk_ + 1;
|
||||
MOZ_ASSERT(chunkno <= chunkCountLimit());
|
||||
MOZ_ASSERT(chunkno <= maxChunkCount());
|
||||
MOZ_ASSERT(chunkno <= allocatedChunkCount());
|
||||
if (chunkno == maxChunkCount())
|
||||
return nullptr;
|
||||
setCurrentChunk(currentChunk_ + 1);
|
||||
if (MOZ_UNLIKELY(chunkno == allocatedChunkCount())) {
|
||||
AutoLockGCBgAlloc lock(runtime());
|
||||
if (!allocateNextChunk(chunkno, lock))
|
||||
return nullptr;
|
||||
MOZ_ASSERT(chunkno < allocatedChunkCount());
|
||||
}
|
||||
setCurrentChunk(chunkno);
|
||||
}
|
||||
|
||||
void* thing = (void*)position();
|
||||
@ -524,6 +547,7 @@ js::Nursery::renderProfileJSON(JSONPrinter& json) const
|
||||
json.property("bytes_used", previousGC.nurseryUsedBytes);
|
||||
json.property("cur_capacity", previousGC.nurseryCapacity);
|
||||
json.property("new_capacity", spaceToEnd());
|
||||
json.property("lazy_capacity", allocatedChunkCount() * ChunkSize);
|
||||
|
||||
json.beginObjectProperty("phase_times");
|
||||
|
||||
@ -686,7 +710,7 @@ js::Nursery::collect(JS::gcreason::Reason reason)
|
||||
// Disable the nursery if the user changed the configuration setting. The
|
||||
// nursery can only be re-enabled by resetting the configurationa and
|
||||
// restarting firefox.
|
||||
if (maxNurseryChunks_ == 0)
|
||||
if (chunkCountLimit_ == 0)
|
||||
disable();
|
||||
|
||||
endProfile(ProfileKey::Total);
|
||||
@ -709,7 +733,7 @@ js::Nursery::collect(JS::gcreason::Reason reason)
|
||||
fprintf(stderr, "MinorGC: %20s %5.1f%% %4u ",
|
||||
JS::gcreason::ExplainReason(reason),
|
||||
promotionRate * 100,
|
||||
numChunks());
|
||||
maxChunkCount());
|
||||
printProfileDurations(profileDurations_);
|
||||
|
||||
if (reportTenurings_) {
|
||||
@ -914,18 +938,18 @@ js::Nursery::clear()
|
||||
{
|
||||
#ifdef JS_GC_ZEAL
|
||||
/* Poison the nursery contents so touching a freed object will crash. */
|
||||
for (unsigned i = 0; i < numChunks(); i++)
|
||||
for (unsigned i = 0; i < allocatedChunkCount(); i++)
|
||||
chunk(i).poisonAndInit(runtime(), JS_SWEPT_NURSERY_PATTERN);
|
||||
|
||||
if (runtime()->hasZealMode(ZealMode::GenerationalGC)) {
|
||||
/* Only reset the alloc point when we are close to the end. */
|
||||
if (currentChunk_ + 1 == numChunks())
|
||||
if (currentChunk_ + 1 == maxChunkCount())
|
||||
setCurrentChunk(0);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
#ifdef JS_CRASH_DIAGNOSTICS
|
||||
for (unsigned i = 0; i < numChunks(); ++i)
|
||||
for (unsigned i = 0; i < allocatedChunkCount(); ++i)
|
||||
chunk(i).poisonAndInit(runtime(), JS_SWEPT_NURSERY_PATTERN);
|
||||
#endif
|
||||
setCurrentChunk(0);
|
||||
@ -938,7 +962,7 @@ js::Nursery::clear()
|
||||
size_t
|
||||
js::Nursery::spaceToEnd() const
|
||||
{
|
||||
unsigned lastChunk = numChunks() - 1;
|
||||
unsigned lastChunk = maxChunkCount() - 1;
|
||||
|
||||
MOZ_ASSERT(lastChunk >= currentStartChunk_);
|
||||
MOZ_ASSERT(currentStartPosition_ - chunk(currentStartChunk_).start() <= NurseryChunkUsableSize);
|
||||
@ -946,7 +970,7 @@ js::Nursery::spaceToEnd() const
|
||||
size_t bytes = (chunk(currentStartChunk_).end() - currentStartPosition_) +
|
||||
((lastChunk - currentStartChunk_) * NurseryChunkUsableSize);
|
||||
|
||||
MOZ_ASSERT(bytes <= numChunks() * NurseryChunkUsableSize);
|
||||
MOZ_ASSERT(bytes <= maxChunkCount() * NurseryChunkUsableSize);
|
||||
|
||||
return bytes;
|
||||
}
|
||||
@ -954,14 +978,40 @@ js::Nursery::spaceToEnd() const
|
||||
MOZ_ALWAYS_INLINE void
|
||||
js::Nursery::setCurrentChunk(unsigned chunkno)
|
||||
{
|
||||
MOZ_ASSERT(chunkno < maxChunks());
|
||||
MOZ_ASSERT(chunkno < numChunks());
|
||||
MOZ_ASSERT(chunkno < chunkCountLimit());
|
||||
MOZ_ASSERT(chunkno < allocatedChunkCount());
|
||||
currentChunk_ = chunkno;
|
||||
position_ = chunk(chunkno).start();
|
||||
currentEnd_ = chunk(chunkno).end();
|
||||
chunk(chunkno).poisonAndInit(runtime(), JS_FRESH_NURSERY_PATTERN);
|
||||
}
|
||||
|
||||
bool
|
||||
js::Nursery::allocateNextChunk(const unsigned chunkno,
|
||||
AutoLockGCBgAlloc& lock)
|
||||
{
|
||||
const unsigned priorCount = allocatedChunkCount();
|
||||
const unsigned newCount = priorCount + 1;
|
||||
|
||||
MOZ_ASSERT((chunkno == currentChunk_ + 1) || (chunkno == 0 && allocatedChunkCount() == 0));
|
||||
MOZ_ASSERT(chunkno == allocatedChunkCount());
|
||||
MOZ_ASSERT(chunkno < chunkCountLimit());
|
||||
MOZ_ASSERT(chunkno < maxChunkCount());
|
||||
|
||||
if (!chunks_.resize(newCount))
|
||||
return false;
|
||||
|
||||
Chunk* newChunk;
|
||||
newChunk = runtime()->gc.getOrAllocChunk(lock);
|
||||
if (!newChunk) {
|
||||
chunks_.shrinkTo(priorCount);
|
||||
return false;
|
||||
}
|
||||
|
||||
chunks_[chunkno] = NurseryChunk::fromChunk(newChunk);
|
||||
return true;
|
||||
}
|
||||
|
||||
MOZ_ALWAYS_INLINE void
|
||||
js::Nursery::setStartPosition()
|
||||
{
|
||||
@ -998,23 +1048,25 @@ js::Nursery::maybeResizeNursery(JS::gcreason::Reason reason)
|
||||
float(previousGC.tenuredBytes) / float(previousGC.nurseryCapacity);
|
||||
|
||||
newMaxNurseryChunks = runtime()->gc.tunables.gcMaxNurseryBytes() >> ChunkShift;
|
||||
if (newMaxNurseryChunks != maxNurseryChunks_) {
|
||||
maxNurseryChunks_ = newMaxNurseryChunks;
|
||||
if (newMaxNurseryChunks != chunkCountLimit_) {
|
||||
chunkCountLimit_ = newMaxNurseryChunks;
|
||||
/* The configured maximum nursery size is changing */
|
||||
const int extraChunks = numChunks() - newMaxNurseryChunks;
|
||||
if (extraChunks > 0) {
|
||||
if (maxChunkCount() > newMaxNurseryChunks) {
|
||||
/* We need to shrink the nursery */
|
||||
shrinkAllocableSpace(extraChunks);
|
||||
shrinkAllocableSpace(newMaxNurseryChunks);
|
||||
|
||||
previousPromotionRate_ = promotionRate;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (promotionRate > GrowThreshold)
|
||||
if (promotionRate > GrowThreshold) {
|
||||
// The GC nursery is an optimization and so if we fail to allocate
|
||||
// nursery chunks we do not report an error.
|
||||
growAllocableSpace();
|
||||
else if (promotionRate < ShrinkThreshold && previousPromotionRate_ < ShrinkThreshold)
|
||||
shrinkAllocableSpace(1);
|
||||
} else if (promotionRate < ShrinkThreshold && previousPromotionRate_ < ShrinkThreshold) {
|
||||
shrinkAllocableSpace(maxChunkCount() - 1);
|
||||
}
|
||||
|
||||
previousPromotionRate_ = promotionRate;
|
||||
}
|
||||
@ -1022,72 +1074,46 @@ js::Nursery::maybeResizeNursery(JS::gcreason::Reason reason)
|
||||
void
|
||||
js::Nursery::growAllocableSpace()
|
||||
{
|
||||
updateNumChunks(Min(numChunks() * 2, maxNurseryChunks_));
|
||||
maxChunkCount_ = Min(maxChunkCount() * 2, chunkCountLimit());
|
||||
}
|
||||
|
||||
void
|
||||
js::Nursery::shrinkAllocableSpace(unsigned removeNumChunks)
|
||||
js::Nursery::freeChunksFrom(unsigned firstFreeChunk)
|
||||
{
|
||||
MOZ_ASSERT(firstFreeChunk < chunks_.length());
|
||||
{
|
||||
AutoLockGC lock(runtime());
|
||||
for (unsigned i = firstFreeChunk; i < chunks_.length(); i++)
|
||||
runtime()->gc.recycleChunk(chunk(i).toChunk(runtime()), lock);
|
||||
}
|
||||
chunks_.shrinkTo(firstFreeChunk);
|
||||
}
|
||||
|
||||
void
|
||||
js::Nursery::shrinkAllocableSpace(unsigned newCount)
|
||||
{
|
||||
#ifdef JS_GC_ZEAL
|
||||
if (runtime()->hasZealMode(ZealMode::GenerationalGC))
|
||||
return;
|
||||
#endif
|
||||
updateNumChunks(Max(numChunks() - removeNumChunks, 1u));
|
||||
|
||||
// Don't shrink the nursery to zero (use Nursery::disable() instead) and
|
||||
// don't attempt to shrink it to the same size.
|
||||
if ((newCount == 0) || (newCount == maxChunkCount()))
|
||||
return;
|
||||
|
||||
MOZ_ASSERT(newCount < maxChunkCount());
|
||||
|
||||
if (newCount < allocatedChunkCount())
|
||||
freeChunksFrom(newCount);
|
||||
|
||||
maxChunkCount_ = newCount;
|
||||
}
|
||||
|
||||
void
|
||||
js::Nursery::minimizeAllocableSpace()
|
||||
{
|
||||
#ifdef JS_GC_ZEAL
|
||||
if (runtime()->hasZealMode(ZealMode::GenerationalGC))
|
||||
return;
|
||||
#endif
|
||||
updateNumChunks(1);
|
||||
}
|
||||
|
||||
void
|
||||
js::Nursery::updateNumChunks(unsigned newCount)
|
||||
{
|
||||
if (numChunks() != newCount) {
|
||||
AutoLockGCBgAlloc lock(runtime());
|
||||
updateNumChunksLocked(newCount, lock);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
js::Nursery::updateNumChunksLocked(unsigned newCount,
|
||||
AutoLockGCBgAlloc& lock)
|
||||
{
|
||||
// The GC nursery is an optimization and so if we fail to allocate nursery
|
||||
// chunks we do not report an error.
|
||||
|
||||
MOZ_ASSERT(newCount <= maxChunks());
|
||||
|
||||
unsigned priorCount = numChunks();
|
||||
MOZ_ASSERT(priorCount != newCount);
|
||||
|
||||
if (newCount < priorCount) {
|
||||
// Shrink the nursery and free unused chunks.
|
||||
for (unsigned i = newCount; i < priorCount; i++)
|
||||
runtime()->gc.recycleChunk(chunk(i).toChunk(runtime()), lock);
|
||||
chunks_.shrinkTo(newCount);
|
||||
return;
|
||||
}
|
||||
|
||||
// Grow the nursery and allocate new chunks.
|
||||
if (!chunks_.resize(newCount))
|
||||
return;
|
||||
|
||||
for (unsigned i = priorCount; i < newCount; i++) {
|
||||
auto newChunk = runtime()->gc.getOrAllocChunk(lock);
|
||||
if (!newChunk) {
|
||||
chunks_.shrinkTo(i);
|
||||
return;
|
||||
}
|
||||
|
||||
chunks_[i] = NurseryChunk::fromChunk(newChunk);
|
||||
chunk(i).poisonAndInit(runtime(), JS_FRESH_NURSERY_PATTERN);
|
||||
}
|
||||
shrinkAllocableSpace(1);
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -141,15 +141,22 @@ class Nursery
|
||||
|
||||
MOZ_MUST_USE bool init(uint32_t maxNurseryBytes, AutoLockGCBgAlloc& lock);
|
||||
|
||||
unsigned maxChunks() const { return maxNurseryChunks_; }
|
||||
unsigned numChunks() const { return chunks_.length(); }
|
||||
unsigned chunkCountLimit() const { return chunkCountLimit_; }
|
||||
|
||||
bool exists() const { return maxChunks() != 0; }
|
||||
size_t nurserySize() const { return maxChunks() << ChunkShift; }
|
||||
// Number of allocated (ready to use) chunks.
|
||||
unsigned allocatedChunkCount() const { return chunks_.length(); }
|
||||
|
||||
// Total number of chunks and the capacity of the nursery. Chunks will be
|
||||
// lazilly allocated and added to the chunks array up to this limit, after
|
||||
// that the nursery must be collected, this limit may be raised during
|
||||
// collection.
|
||||
unsigned maxChunkCount() const { return maxChunkCount_; }
|
||||
|
||||
bool exists() const { return chunkCountLimit() != 0; }
|
||||
|
||||
void enable();
|
||||
void disable();
|
||||
bool isEnabled() const { return numChunks() != 0; }
|
||||
bool isEnabled() const { return maxChunkCount() != 0; }
|
||||
|
||||
/* Return true if no allocations have been made since the last collection. */
|
||||
bool isEmpty() const;
|
||||
@ -234,7 +241,7 @@ class Nursery
|
||||
MOZ_MUST_USE bool queueDictionaryModeObjectToSweep(NativeObject* obj);
|
||||
|
||||
size_t sizeOfHeapCommitted() const {
|
||||
return numChunks() * gc::ChunkSize;
|
||||
return allocatedChunkCount() * gc::ChunkSize;
|
||||
}
|
||||
size_t sizeOfMallocedBuffers(mozilla::MallocSizeOf mallocSizeOf) const {
|
||||
if (!mallocedBuffers.initialized())
|
||||
@ -253,7 +260,7 @@ class Nursery
|
||||
MOZ_ALWAYS_INLINE size_t freeSpace() const {
|
||||
MOZ_ASSERT(currentEnd_ - position_ <= NurseryChunkUsableSize);
|
||||
return (currentEnd_ - position_) +
|
||||
(numChunks() - currentChunk_ - 1) * NurseryChunkUsableSize;
|
||||
(maxChunkCount() - currentChunk_ - 1) * NurseryChunkUsableSize;
|
||||
}
|
||||
|
||||
#ifdef JS_GC_ZEAL
|
||||
@ -311,8 +318,18 @@ class Nursery
|
||||
/* The index of the chunk that is currently being allocated from. */
|
||||
unsigned currentChunk_;
|
||||
|
||||
/* Maximum number of chunks to allocate for the nursery. */
|
||||
unsigned maxNurseryChunks_;
|
||||
/*
|
||||
* The nursery may grow the chunks_ vector up to this size without a
|
||||
* collection. This allows the nursery to grow lazilly. This limit may
|
||||
* change during maybeResizeNursery() each collection.
|
||||
*/
|
||||
unsigned maxChunkCount_;
|
||||
|
||||
/*
|
||||
* This limit is fixed by configuration. It represents the maximum size
|
||||
* the nursery is permitted to tune itself to in maybeResizeNursery();
|
||||
*/
|
||||
unsigned chunkCountLimit_;
|
||||
|
||||
/* Promotion rate for the previous minor collection. */
|
||||
float previousPromotionRate_;
|
||||
@ -419,8 +436,6 @@ class Nursery
|
||||
Canary* lastCanary_;
|
||||
#endif
|
||||
|
||||
NurseryChunk* allocChunk();
|
||||
|
||||
NurseryChunk& chunk(unsigned index) const {
|
||||
return *chunks_[index];
|
||||
}
|
||||
@ -428,9 +443,12 @@ class Nursery
|
||||
void setCurrentChunk(unsigned chunkno);
|
||||
void setStartPosition();
|
||||
|
||||
void updateNumChunks(unsigned newCount);
|
||||
void updateNumChunksLocked(unsigned newCount,
|
||||
AutoLockGCBgAlloc& lock);
|
||||
/*
|
||||
* Allocate the next chunk, or the first chunk for initialization.
|
||||
* Callers will probably want to call setCurrentChunk(0) next.
|
||||
*/
|
||||
MOZ_MUST_USE bool allocateNextChunk(unsigned chunkno,
|
||||
AutoLockGCBgAlloc& lock);
|
||||
|
||||
MOZ_ALWAYS_INLINE uintptr_t currentEnd() const;
|
||||
|
||||
@ -483,9 +501,13 @@ class Nursery
|
||||
/* Change the allocable space provided by the nursery. */
|
||||
void maybeResizeNursery(JS::gcreason::Reason reason);
|
||||
void growAllocableSpace();
|
||||
void shrinkAllocableSpace(unsigned removeNumChunks);
|
||||
void shrinkAllocableSpace(unsigned newCount);
|
||||
void minimizeAllocableSpace();
|
||||
|
||||
// Free the chunks starting at firstFreeChunk until the end of the chunks
|
||||
// vector. Shrinks the vector but does not update maxChunkCount().
|
||||
void freeChunksFrom(unsigned firstFreeChunk);
|
||||
|
||||
/* Profile recording and printing. */
|
||||
void maybeClearProfileDurations();
|
||||
void startProfile(ProfileKey key);
|
||||
|
@ -3263,7 +3263,7 @@ class ValueObserver final
|
||||
: public nsIObserver
|
||||
, public ValueObserverHashKey
|
||||
{
|
||||
~ValueObserver() { Preferences::RemoveObserver(this, mPrefName.get()); }
|
||||
~ValueObserver() = default;
|
||||
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
@ -4681,8 +4681,7 @@ pref_InitInitialObjects()
|
||||
|
||||
if (!strcmp(NS_STRINGIFY(MOZ_UPDATE_CHANNEL), "nightly") ||
|
||||
!strcmp(NS_STRINGIFY(MOZ_UPDATE_CHANNEL), "aurora") ||
|
||||
!strcmp(NS_STRINGIFY(MOZ_UPDATE_CHANNEL), "beta") ||
|
||||
developerBuild) {
|
||||
!strcmp(NS_STRINGIFY(MOZ_UPDATE_CHANNEL), "beta") || developerBuild) {
|
||||
PREF_SetBoolPref(kTelemetryPref, true, true);
|
||||
} else {
|
||||
PREF_SetBoolPref(kTelemetryPref, false, true);
|
||||
@ -4951,13 +4950,13 @@ NotifyObserver(const char* aPref, void* aClosure)
|
||||
}
|
||||
|
||||
static void
|
||||
RegisterPriorityCallback(PrefChangedFunc aCallback,
|
||||
const char* aPref,
|
||||
void* aClosure)
|
||||
RegisterCallbackHelper(PrefChangedFunc aCallback,
|
||||
const char* aPref,
|
||||
void* aClosure,
|
||||
Preferences::MatchKind aMatchKind,
|
||||
bool aIsPriority)
|
||||
{
|
||||
MOZ_ASSERT(Preferences::IsServiceAvailable());
|
||||
|
||||
ValueObserverHashKey hashKey(aPref, aCallback, Preferences::ExactMatch);
|
||||
ValueObserverHashKey hashKey(aPref, aCallback, aMatchKind);
|
||||
RefPtr<ValueObserver> observer;
|
||||
gObserverTable->Get(&hashKey, getter_AddRefs(observer));
|
||||
if (observer) {
|
||||
@ -4965,15 +4964,27 @@ RegisterPriorityCallback(PrefChangedFunc aCallback,
|
||||
return;
|
||||
}
|
||||
|
||||
observer = new ValueObserver(aPref, aCallback, Preferences::ExactMatch);
|
||||
observer = new ValueObserver(aPref, aCallback, aMatchKind);
|
||||
observer->AppendClosure(aClosure);
|
||||
PREF_RegisterCallback(aPref,
|
||||
NotifyObserver,
|
||||
static_cast<nsIObserver*>(observer),
|
||||
/* isPriority */ true);
|
||||
PREF_RegisterCallback(
|
||||
aPref, NotifyObserver, static_cast<nsIObserver*>(observer), aIsPriority);
|
||||
gObserverTable->Put(observer, observer);
|
||||
}
|
||||
|
||||
// RegisterVarCacheCallback uses high priority callbacks to ensure that cache
|
||||
// observers are called prior to ordinary pref observers. Doing this ensures
|
||||
// that ordinary observers will never get stale values from cache variables.
|
||||
static void
|
||||
RegisterVarCacheCallback(PrefChangedFunc aCallback,
|
||||
const char* aPref,
|
||||
void* aClosure)
|
||||
{
|
||||
MOZ_ASSERT(Preferences::IsServiceAvailable());
|
||||
|
||||
RegisterCallbackHelper(
|
||||
aCallback, aPref, aClosure, Preferences::ExactMatch, /* isPriority */ true);
|
||||
}
|
||||
|
||||
/* static */ nsresult
|
||||
Preferences::RegisterCallback(PrefChangedFunc aCallback,
|
||||
const char* aPref,
|
||||
@ -4983,20 +4994,8 @@ Preferences::RegisterCallback(PrefChangedFunc aCallback,
|
||||
MOZ_ASSERT(aCallback);
|
||||
NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
|
||||
|
||||
ValueObserverHashKey hashKey(aPref, aCallback, aMatchKind);
|
||||
RefPtr<ValueObserver> observer;
|
||||
gObserverTable->Get(&hashKey, getter_AddRefs(observer));
|
||||
if (observer) {
|
||||
observer->AppendClosure(aClosure);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
observer = new ValueObserver(aPref, aCallback, aMatchKind);
|
||||
observer->AppendClosure(aClosure);
|
||||
nsresult rv = AddStrongObserver(observer, aPref);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
gObserverTable->Put(observer, observer);
|
||||
RegisterCallbackHelper(
|
||||
aCallback, aPref, aClosure, aMatchKind, /* isPriority */ false);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -5037,15 +5036,14 @@ Preferences::UnregisterCallback(PrefChangedFunc aCallback,
|
||||
observer->RemoveClosure(aClosure);
|
||||
if (observer->HasNoClosures()) {
|
||||
// Delete the callback since its list of closures is empty.
|
||||
MOZ_ALWAYS_SUCCEEDS(
|
||||
PREF_UnregisterCallback(aPref, NotifyObserver, observer));
|
||||
|
||||
gObserverTable->Remove(observer);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// We insert cache observers using RegisterPriorityCallback to ensure they are
|
||||
// called prior to ordinary pref observers. Doing this ensures that ordinary
|
||||
// observers will never get stale values from cache variables.
|
||||
|
||||
static void
|
||||
BoolVarChanged(const char* aPref, void* aClosure)
|
||||
{
|
||||
@ -5076,7 +5074,7 @@ Preferences::AddBoolVarCache(bool* aCache, const char* aPref, bool aDefault)
|
||||
data->mCacheLocation = aCache;
|
||||
data->mDefaultValueBool = aDefault;
|
||||
CacheDataAppendElement(data);
|
||||
RegisterPriorityCallback(BoolVarChanged, aPref, data);
|
||||
RegisterVarCacheCallback(BoolVarChanged, aPref, data);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -5103,7 +5101,7 @@ Preferences::AddIntVarCache(int32_t* aCache,
|
||||
data->mCacheLocation = aCache;
|
||||
data->mDefaultValueInt = aDefault;
|
||||
CacheDataAppendElement(data);
|
||||
RegisterPriorityCallback(IntVarChanged, aPref, data);
|
||||
RegisterVarCacheCallback(IntVarChanged, aPref, data);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -5130,7 +5128,7 @@ Preferences::AddUintVarCache(uint32_t* aCache,
|
||||
data->mCacheLocation = aCache;
|
||||
data->mDefaultValueUint = aDefault;
|
||||
CacheDataAppendElement(data);
|
||||
RegisterPriorityCallback(UintVarChanged, aPref, data);
|
||||
RegisterVarCacheCallback(UintVarChanged, aPref, data);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -5159,7 +5157,7 @@ Preferences::AddAtomicUintVarCache(Atomic<uint32_t, Order>* aCache,
|
||||
data->mCacheLocation = aCache;
|
||||
data->mDefaultValueUint = aDefault;
|
||||
CacheDataAppendElement(data);
|
||||
RegisterPriorityCallback(AtomicUintVarChanged<Order>, aPref, data);
|
||||
RegisterVarCacheCallback(AtomicUintVarChanged<Order>, aPref, data);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -5192,7 +5190,7 @@ Preferences::AddFloatVarCache(float* aCache, const char* aPref, float aDefault)
|
||||
data->mCacheLocation = aCache;
|
||||
data->mDefaultValueFloat = aDefault;
|
||||
CacheDataAppendElement(data);
|
||||
RegisterPriorityCallback(FloatVarChanged, aPref, data);
|
||||
RegisterVarCacheCallback(FloatVarChanged, aPref, data);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -1338,6 +1338,8 @@ nsCookieService::TryInitDB(bool aRecreateDB)
|
||||
// No more upgrades. Update the schema version.
|
||||
rv = mDefaultDBState->syncConn->SetSchemaVersion(COOKIES_SCHEMA_VERSION);
|
||||
NS_ENSURE_SUCCESS(rv, RESULT_RETRY);
|
||||
|
||||
Telemetry::Accumulate(Telemetry::MOZ_SQLITE_COOKIES_OLD_SCHEMA, dbSchemaVersion);
|
||||
MOZ_FALLTHROUGH;
|
||||
|
||||
case COOKIES_SCHEMA_VERSION:
|
||||
@ -1429,6 +1431,7 @@ nsCookieService::TryInitDB(bool aRecreateDB)
|
||||
gCookieService->ImportCookies(oldCookieFile);
|
||||
oldCookieFile->Remove(false);
|
||||
gCookieService->mDBState = initialState;
|
||||
Telemetry::Accumulate(Telemetry::MOZ_SQLITE_COOKIES_OLD_SCHEMA, 0);
|
||||
});
|
||||
|
||||
NS_DispatchToMainThread(runnable);
|
||||
|
@ -4426,6 +4426,15 @@
|
||||
"n_buckets": 10,
|
||||
"description": "Time spent on SQLite read() (ms) *** No longer needed (bug 1156565). Delete histogram and accumulation code! ***"
|
||||
},
|
||||
"MOZ_SQLITE_COOKIES_OLD_SCHEMA": {
|
||||
"record_in_processes": ["main"],
|
||||
"expires_in_version": "62",
|
||||
"kind": "enumerated",
|
||||
"n_values": 10,
|
||||
"bug_numbers": [1412218],
|
||||
"alert_emails": ["necko@mozilla.com", "junior@mozilla.com"],
|
||||
"description": "Old schema version of the cookie database. 0 for having legacy cookies.txt."
|
||||
},
|
||||
"MOZ_SQLITE_COOKIES_BLOCK_MAIN_THREAD_MS": {
|
||||
"record_in_processes": ["main"],
|
||||
"expires_in_version": "never",
|
||||
|
Loading…
Reference in New Issue
Block a user