mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-24 02:35:41 +00:00
Bug 1519397 - Factor GC locking RAII classes out of vm/Runtime.h r=pbone
This commit is contained in:
parent
438136eb9e
commit
cc1da19831
@ -7,6 +7,7 @@
|
||||
#ifndef gc_Allocator_h
|
||||
#define gc_Allocator_h
|
||||
|
||||
#include "gc/GCLock.h"
|
||||
#include "gc/Heap.h"
|
||||
#include "js/RootingAPI.h"
|
||||
|
||||
|
@ -216,6 +216,7 @@
|
||||
#include "gc/FindSCCs.h"
|
||||
#include "gc/FreeOp.h"
|
||||
#include "gc/GCInternals.h"
|
||||
#include "gc/GCLock.h"
|
||||
#include "gc/GCTrace.h"
|
||||
#include "gc/Memory.h"
|
||||
#include "gc/Policy.h"
|
||||
|
118
js/src/gc/GCLock.h
Normal file
118
js/src/gc/GCLock.h
Normal file
@ -0,0 +1,118 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* vim: set ts=8 sts=2 et sw=2 tw=80:
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/*
|
||||
* GC-internal classes for acquiring and releasing the GC lock.
|
||||
*/
|
||||
|
||||
#ifndef gc_GCLock_h
|
||||
#define gc_GCLock_h
|
||||
|
||||
#include "vm/Runtime.h"
|
||||
|
||||
namespace js {
|
||||
|
||||
class AutoUnlockGC;
|
||||
|
||||
/*
|
||||
* RAII class that takes the GC lock while it is live.
|
||||
*
|
||||
* Usually functions will pass const references of this class. However
|
||||
* non-const references can be used to either temporarily release the lock by
|
||||
* use of AutoUnlockGC or to start background allocation when the lock is
|
||||
* released.
|
||||
*/
|
||||
class MOZ_RAII AutoLockGC {
|
||||
public:
|
||||
explicit AutoLockGC(JSRuntime* rt MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
: runtime_(rt) {
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
lock();
|
||||
}
|
||||
|
||||
~AutoLockGC() { lockGuard_.reset(); }
|
||||
|
||||
void lock() {
|
||||
MOZ_ASSERT(lockGuard_.isNothing());
|
||||
lockGuard_.emplace(runtime_->gc.lock);
|
||||
}
|
||||
|
||||
void unlock() {
|
||||
MOZ_ASSERT(lockGuard_.isSome());
|
||||
lockGuard_.reset();
|
||||
}
|
||||
|
||||
protected:
|
||||
js::LockGuard<js::Mutex>& guard() { return lockGuard_.ref(); }
|
||||
|
||||
JSRuntime* runtime() const { return runtime_; }
|
||||
|
||||
private:
|
||||
JSRuntime* runtime_;
|
||||
mozilla::Maybe<js::LockGuard<js::Mutex>> lockGuard_;
|
||||
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
|
||||
AutoLockGC(const AutoLockGC&) = delete;
|
||||
AutoLockGC& operator=(const AutoLockGC&) = delete;
|
||||
};
|
||||
|
||||
/*
|
||||
* Same as AutoLockGC except it can optionally start a background chunk
|
||||
* allocation task when the lock is released.
|
||||
*/
|
||||
class MOZ_RAII AutoLockGCBgAlloc : public AutoLockGC {
|
||||
public:
|
||||
explicit AutoLockGCBgAlloc(JSRuntime* rt)
|
||||
: AutoLockGC(rt), startBgAlloc(false) {}
|
||||
|
||||
~AutoLockGCBgAlloc() {
|
||||
unlock();
|
||||
|
||||
/*
|
||||
* We have to do this after releasing the lock because it may acquire
|
||||
* the helper lock which could cause lock inversion if we still held
|
||||
* the GC lock.
|
||||
*/
|
||||
if (startBgAlloc) {
|
||||
runtime()->gc.startBackgroundAllocTaskIfIdle(); // Ignore failure.
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This can be used to start a background allocation task (if one isn't
|
||||
* already running) that allocates chunks and makes them available in the
|
||||
* free chunks list. This happens after the lock is released in order to
|
||||
* avoid lock inversion.
|
||||
*/
|
||||
void tryToStartBackgroundAllocation() { startBgAlloc = true; }
|
||||
|
||||
private:
|
||||
// true if we should start a background chunk allocation task after the
|
||||
// lock is released.
|
||||
bool startBgAlloc;
|
||||
};
|
||||
|
||||
class MOZ_RAII AutoUnlockGC {
|
||||
public:
|
||||
explicit AutoUnlockGC(AutoLockGC& lock MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
: lock(lock) {
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
~AutoUnlockGC() { lock.lock(); }
|
||||
|
||||
private:
|
||||
AutoLockGC& lock;
|
||||
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
|
||||
AutoUnlockGC(const AutoUnlockGC&) = delete;
|
||||
AutoUnlockGC& operator=(const AutoUnlockGC&) = delete;
|
||||
};
|
||||
|
||||
} // namespace js
|
||||
|
||||
#endif /* gc_GCLock_h */
|
@ -13,6 +13,7 @@
|
||||
#endif
|
||||
|
||||
#include "gc/GCInternals.h"
|
||||
#include "gc/GCLock.h"
|
||||
#include "gc/PublicIterators.h"
|
||||
#include "gc/WeakMap.h"
|
||||
#include "gc/Zone.h"
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
#include "mozilla/Move.h"
|
||||
|
||||
#include "gc/GCLock.h"
|
||||
#include "gc/GCRuntime.h"
|
||||
#include "gc/Heap.h"
|
||||
|
||||
|
@ -1012,104 +1012,6 @@ struct JSRuntime : public js::MallocProvider<JSRuntime> {
|
||||
|
||||
namespace js {
|
||||
|
||||
/*
|
||||
* RAII class that takes the GC lock while it is live.
|
||||
*
|
||||
* Usually functions will pass const references of this class. However
|
||||
* non-const references can be used to either temporarily release the lock by
|
||||
* use of AutoUnlockGC or to start background allocation when the lock is
|
||||
* released.
|
||||
*/
|
||||
class MOZ_RAII AutoLockGC {
|
||||
public:
|
||||
explicit AutoLockGC(JSRuntime* rt MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
: runtime_(rt) {
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
lock();
|
||||
}
|
||||
|
||||
~AutoLockGC() { lockGuard_.reset(); }
|
||||
|
||||
void lock() {
|
||||
MOZ_ASSERT(lockGuard_.isNothing());
|
||||
lockGuard_.emplace(runtime_->gc.lock);
|
||||
}
|
||||
|
||||
void unlock() {
|
||||
MOZ_ASSERT(lockGuard_.isSome());
|
||||
lockGuard_.reset();
|
||||
}
|
||||
|
||||
js::LockGuard<js::Mutex>& guard() { return lockGuard_.ref(); }
|
||||
|
||||
protected:
|
||||
JSRuntime* runtime() const { return runtime_; }
|
||||
|
||||
private:
|
||||
JSRuntime* runtime_;
|
||||
mozilla::Maybe<js::LockGuard<js::Mutex>> lockGuard_;
|
||||
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
|
||||
AutoLockGC(const AutoLockGC&) = delete;
|
||||
AutoLockGC& operator=(const AutoLockGC&) = delete;
|
||||
};
|
||||
|
||||
/*
|
||||
* Same as AutoLockGC except it can optionally start a background chunk
|
||||
* allocation task when the lock is released.
|
||||
*/
|
||||
class MOZ_RAII AutoLockGCBgAlloc : public AutoLockGC {
|
||||
public:
|
||||
explicit AutoLockGCBgAlloc(JSRuntime* rt)
|
||||
: AutoLockGC(rt), startBgAlloc(false) {}
|
||||
|
||||
~AutoLockGCBgAlloc() {
|
||||
unlock();
|
||||
|
||||
/*
|
||||
* We have to do this after releasing the lock because it may acquire
|
||||
* the helper lock which could cause lock inversion if we still held
|
||||
* the GC lock.
|
||||
*/
|
||||
if (startBgAlloc) {
|
||||
runtime()->gc.startBackgroundAllocTaskIfIdle(); // Ignore failure.
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This can be used to start a background allocation task (if one isn't
|
||||
* already running) that allocates chunks and makes them available in the
|
||||
* free chunks list. This happens after the lock is released in order to
|
||||
* avoid lock inversion.
|
||||
*/
|
||||
void tryToStartBackgroundAllocation() { startBgAlloc = true; }
|
||||
|
||||
private:
|
||||
// true if we should start a background chunk allocation task after the
|
||||
// lock is released.
|
||||
bool startBgAlloc;
|
||||
};
|
||||
|
||||
class MOZ_RAII AutoUnlockGC {
|
||||
public:
|
||||
explicit AutoUnlockGC(AutoLockGC& lock MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
: lock(lock) {
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
~AutoUnlockGC() { lock.lock(); }
|
||||
|
||||
private:
|
||||
AutoLockGC& lock;
|
||||
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
|
||||
AutoUnlockGC(const AutoUnlockGC&) = delete;
|
||||
AutoUnlockGC& operator=(const AutoUnlockGC&) = delete;
|
||||
};
|
||||
|
||||
/************************************************************************/
|
||||
|
||||
static MOZ_ALWAYS_INLINE void MakeRangeGCSafe(Value* vec, size_t len) {
|
||||
// Don't PodZero here because JS::Value is non-trivial.
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
|
Loading…
Reference in New Issue
Block a user