Bug 835966 - Refactor {cx,rt,allocator}->malloc_ (r=luke)

This commit is contained in:
Bill McCloskey 2013-01-30 12:22:04 -08:00
parent c41e351bdc
commit 8ac8251ea5
5 changed files with 121 additions and 185 deletions

View File

@ -1343,7 +1343,13 @@ JSRuntime::setGCMaxMallocBytes(size_t value)
}
void
JSRuntime::updateMallocCounter(JSCompartment *comp, size_t nbytes)
JSRuntime::updateMallocCounter(size_t nbytes)
{
updateMallocCounter(NULL, nbytes);
}
void
JSRuntime::updateMallocCounter(JS::Zone *zone, size_t nbytes)
{
/* We tolerate any thread races when updating gcMallocBytes. */
ptrdiff_t oldCount = gcMallocBytes;
@ -1351,8 +1357,8 @@ JSRuntime::updateMallocCounter(JSCompartment *comp, size_t nbytes)
gcMallocBytes = newCount;
if (JS_UNLIKELY(newCount <= 0 && oldCount > 0))
onTooMuchMalloc();
else if (comp)
comp->updateMallocCounter(nbytes);
else if (zone)
zone->updateMallocCounter(nbytes);
}
JS_FRIEND_API(void)
@ -1361,6 +1367,12 @@ JSRuntime::onTooMuchMalloc()
TriggerGC(this, gcreason::TOO_MUCH_MALLOC);
}
JS_FRIEND_API(void *)
JSRuntime::onOutOfMemory(void *p, size_t nbytes)
{
return onOutOfMemory(p, nbytes, NULL);
}
JS_FRIEND_API(void *)
JSRuntime::onOutOfMemory(void *p, size_t nbytes, JSContext *cx)
{

View File

@ -495,15 +495,87 @@ class PerThreadData : public js::PerThreadDataFriendFields
bool associatedWith(const JSRuntime *rt) { return runtime_ == rt; }
};
template<class Client>
struct MallocProvider
{
void *malloc_(size_t bytes) {
Client *client = static_cast<Client *>(this);
client->updateMallocCounter(bytes);
void *p = js_malloc(bytes);
return JS_LIKELY(!!p) ? p : client->onOutOfMemory(NULL, bytes);
}
void *calloc_(size_t bytes) {
Client *client = static_cast<Client *>(this);
client->updateMallocCounter(bytes);
void *p = js_calloc(bytes);
return JS_LIKELY(!!p) ? p : client->onOutOfMemory(reinterpret_cast<void *>(1), bytes);
}
void *realloc_(void *p, size_t oldBytes, size_t newBytes) {
Client *client = static_cast<Client *>(this);
JS_ASSERT(oldBytes < newBytes);
client->updateMallocCounter(newBytes - oldBytes);
void *p2 = js_realloc(p, newBytes);
return JS_LIKELY(!!p2) ? p2 : client->onOutOfMemory(p, newBytes);
}
void *realloc_(void *p, size_t bytes) {
Client *client = static_cast<Client *>(this);
/*
* For compatibility we do not account for realloc that increases
* previously allocated memory.
*/
if (!p)
client->updateMallocCounter(bytes);
void *p2 = js_realloc(p, bytes);
return JS_LIKELY(!!p2) ? p2 : client->onOutOfMemory(p, bytes);
}
template <class T>
T *pod_malloc() {
return (T *)malloc_(sizeof(T));
}
template <class T>
T *pod_calloc() {
return (T *)calloc_(sizeof(T));
}
template <class T>
T *pod_malloc(size_t numElems) {
if (numElems & js::tl::MulOverflowMask<sizeof(T)>::result) {
Client *client = static_cast<Client *>(this);
client->reportAllocationOverflow();
return NULL;
}
return (T *)malloc_(numElems * sizeof(T));
}
template <class T>
T *pod_calloc(size_t numElems, JSCompartment *comp = NULL, JSContext *cx = NULL) {
if (numElems & js::tl::MulOverflowMask<sizeof(T)>::result) {
Client *client = static_cast<Client *>(this);
client->reportAllocationOverflow();
return NULL;
}
return (T *)calloc_(numElems * sizeof(T));
}
JS_DECLARE_NEW_METHODS(new_, malloc_, JS_ALWAYS_INLINE)
};
namespace gc {
class MarkingValidator;
} // namespace gc
} // namespace js
struct JSRuntime : js::RuntimeFriendFields
struct JSRuntime : js::RuntimeFriendFields,
public js::MallocProvider<JSRuntime>
{
/* Per-thread data for the main thread that is associated with
/*
* Per-thread data for the main thread that is associated with
* this JSRuntime, as opposed to any worker threads used in
* parallel sections. See definition of |PerThreadData| struct
* above for more details.
@ -512,7 +584,7 @@ struct JSRuntime : js::RuntimeFriendFields
* sizeof(RuntimeFriendFields). See
* PerThreadDataFriendFields::getMainThread.
*/
js::PerThreadData mainThread;
js::PerThreadData mainThread;
/* Default compartment. */
JSCompartment *atomsCompartment;
@ -1121,52 +1193,6 @@ struct JSRuntime : js::RuntimeFriendFields
JSRuntime *thisFromCtor() { return this; }
/*
* Call the system malloc while checking for GC memory pressure and
* reporting OOM error when cx is not null. We will not GC from here.
*/
inline void *malloc_(size_t bytes, JSCompartment *comp = NULL, JSContext *cx = NULL);
/*
* Call the system calloc while checking for GC memory pressure and
* reporting OOM error when cx is not null. We will not GC from here.
*/
inline void *calloc_(size_t bytes, JSCompartment *comp = NULL, JSContext *cx = NULL);
inline void *realloc_(void *p, size_t oldBytes, size_t newBytes, JSCompartment *comp = NULL, JSContext *cx = NULL);
inline void *realloc_(void *p, size_t bytes, JSCompartment *comp = NULL, JSContext *cx = NULL);
template <class T>
T *pod_malloc(JSCompartment *comp = NULL, JSContext *cx = NULL) {
return (T *)malloc_(sizeof(T), comp, cx);
}
template <class T>
T *pod_calloc(JSCompartment *comp = NULL, JSContext *cx = NULL) {
return (T *)calloc_(sizeof(T), comp, cx);
}
template <class T>
T *pod_malloc(size_t numElems, JSCompartment *comp = NULL, JSContext *cx = NULL) {
if (numElems & js::tl::MulOverflowMask<sizeof(T)>::result) {
js_ReportAllocationOverflow(cx);
return NULL;
}
return (T *)malloc_(numElems * sizeof(T), comp, cx);
}
template <class T>
T *pod_calloc(size_t numElems, JSCompartment *comp = NULL, JSContext *cx = NULL) {
if (numElems & js::tl::MulOverflowMask<sizeof(T)>::result) {
js_ReportAllocationOverflow(cx);
return NULL;
}
return (T *)calloc_(numElems * sizeof(T), comp, cx);
}
JS_DECLARE_NEW_METHODS(new_, malloc_, JS_ALWAYS_INLINE)
void setGCMaxMallocBytes(size_t value);
void resetGCMallocBytes() { gcMallocBytes = ptrdiff_t(gcMaxMallocBytes); }
@ -1179,7 +1205,10 @@ struct JSRuntime : js::RuntimeFriendFields
* The function must be called outside the GC lock and in case of OOM error
* the caller must ensure that no deadlock possible during OOM reporting.
*/
void updateMallocCounter(JSCompartment *comp, size_t nbytes);
void updateMallocCounter(size_t nbytes);
void updateMallocCounter(JS::Zone *zone, size_t nbytes);
void reportAllocationOverflow() { js_ReportAllocationOverflow(NULL); }
bool isTooMuchMalloc() const {
return gcMallocBytes <= 0;
@ -1198,6 +1227,7 @@ struct JSRuntime : js::RuntimeFriendFields
*
* The function must be called outside the GC lock.
*/
JS_FRIEND_API(void *) onOutOfMemory(void *p, size_t nbytes);
JS_FRIEND_API(void *) onOutOfMemory(void *p, size_t nbytes, JSContext *cx);
void triggerOperationCallback();
@ -1376,7 +1406,8 @@ FreeOp::free_(void *p)
} /* namespace js */
struct JSContext : js::ContextFriendFields,
public mozilla::LinkedListElement<JSContext>
public mozilla::LinkedListElement<JSContext>,
public js::MallocProvider<JSContext>
{
explicit JSContext(JSRuntime *rt);
JSContext *thisDuringConstruction() { return this; }
@ -1655,41 +1686,16 @@ struct JSContext : js::ContextFriendFields,
void enterGenerator(JSGenerator *gen);
void leaveGenerator(JSGenerator *gen);
inline void *malloc_(size_t bytes) {
return runtime->malloc_(bytes, compartment, this);
void *onOutOfMemory(void *p, size_t nbytes) {
return runtime->onOutOfMemory(p, nbytes, this);
}
inline void *calloc_(size_t bytes) {
return runtime->calloc_(bytes, compartment, this);
void updateMallocCounter(size_t nbytes) {
runtime->updateMallocCounter(compartment, nbytes);
}
inline void *realloc_(void *p, size_t bytes) {
return runtime->realloc_(p, bytes, compartment, this);
void reportAllocationOverflow() {
js_ReportAllocationOverflow(this);
}
inline void *realloc_(void *p, size_t oldBytes, size_t newBytes) {
return runtime->realloc_(p, oldBytes, newBytes, compartment, this);
}
template <class T> T *pod_malloc() {
return runtime->pod_malloc<T>(compartment, this);
}
template <class T> T *pod_calloc() {
return runtime->pod_calloc<T>(compartment, this);
}
template <class T> T *pod_malloc(size_t numElems) {
return runtime->pod_malloc<T>(numElems, compartment, this);
}
template <class T>
T *pod_calloc(size_t numElems) {
return runtime->pod_calloc<T>(numElems, compartment, this);
}
JS_DECLARE_NEW_METHODS(new_, malloc_, JS_ALWAYS_INLINE)
void purge();
bool isExceptionPending() {
@ -2306,46 +2312,4 @@ class ContextAllocPolicy
#pragma warning(pop)
#endif
void *
JSRuntime::malloc_(size_t bytes, JSCompartment *comp, JSContext *cx)
{
JS_ASSERT_IF(cx != NULL, cx->compartment == comp);
updateMallocCounter(comp, bytes);
void *p = js_malloc(bytes);
return JS_LIKELY(!!p) ? p : onOutOfMemory(NULL, bytes, cx);
}
void *
JSRuntime::calloc_(size_t bytes, JSCompartment *comp, JSContext *cx)
{
JS_ASSERT_IF(cx != NULL, cx->compartment == comp);
updateMallocCounter(comp, bytes);
void *p = js_calloc(bytes);
return JS_LIKELY(!!p) ? p : onOutOfMemory(reinterpret_cast<void *>(1), bytes, cx);
}
void *
JSRuntime::realloc_(void *p, size_t oldBytes, size_t newBytes, JSCompartment *comp, JSContext *cx)
{
JS_ASSERT_IF(cx != NULL, cx->compartment == comp);
JS_ASSERT(oldBytes < newBytes);
updateMallocCounter(comp, newBytes - oldBytes);
void *p2 = js_realloc(p, newBytes);
return JS_LIKELY(!!p2) ? p2 : onOutOfMemory(p, newBytes, cx);
}
void *
JSRuntime::realloc_(void *p, size_t bytes, JSCompartment *comp, JSContext *cx)
{
JS_ASSERT_IF(cx != NULL, cx->compartment == comp);
/*
* For compatibility we do not account for realloc that increases
* previously allocated memory.
*/
if (!p)
updateMallocCounter(comp, bytes);
void *p2 = js_realloc(p, bytes);
return JS_LIKELY(!!p2) ? p2 : onOutOfMemory(p, bytes, cx);
}
#endif /* jscntxt_h___ */

View File

@ -132,26 +132,20 @@ namespace js {
* parallel or sequential mode, you should make it take an
* |Allocator*| rather than a |JSContext*|.
*/
class Allocator
class Allocator : public MallocProvider<Allocator>
{
JSCompartment*const compartment;
JS::Zone *zone;
public:
explicit Allocator(JSCompartment *compartment);
explicit Allocator(JS::Zone *zone);
js::gc::ArenaLists arenas;
inline void *parallelNewGCThing(gc::AllocKind thingKind, size_t thingSize);
inline void *malloc_(size_t bytes);
inline void *calloc_(size_t bytes);
inline void *realloc_(void *p, size_t bytes);
inline void *realloc_(void *p, size_t oldBytes, size_t newBytes);
template <class T> inline T *pod_malloc();
template <class T> inline T *pod_calloc();
template <class T> inline T *pod_malloc(size_t numElems);
template <class T> inline T *pod_calloc(size_t numElems);
JS_DECLARE_NEW_METHODS(new_, malloc_, JS_ALWAYS_INLINE)
inline void *onOutOfMemory(void *p, size_t nbytes);
inline void updateMallocCounter(size_t nbytes);
inline void reportAllocationOverflow();
};
} /* namespace js */

View File

@ -27,62 +27,28 @@ js::AutoCompartment::~AutoCompartment()
cx_->leaveCompartment(origin_);
}
inline void *
js::Allocator::malloc_(size_t bytes)
void *
js::Allocator::onOutOfMemory(void *p, size_t nbytes)
{
return compartment->rt->malloc_(bytes, compartment);
return zone->rt->onOutOfMemory(p, nbytes);
}
inline void *
js::Allocator::calloc_(size_t bytes)
void
js::Allocator::updateMallocCounter(size_t nbytes)
{
return compartment->rt->calloc_(bytes, compartment);
zone->rt->updateMallocCounter(zone, nbytes);
}
inline void *
js::Allocator::realloc_(void *p, size_t bytes)
void
js::Allocator::reportAllocationOverflow()
{
return compartment->rt->realloc_(p, bytes, compartment);
}
inline void *
js::Allocator::realloc_(void* p, size_t oldBytes, size_t newBytes)
{
return compartment->rt->realloc_(p, oldBytes, newBytes, compartment);
}
template <class T>
inline T *
js::Allocator::pod_malloc()
{
return compartment->rt->pod_malloc<T>(compartment);
}
template <class T>
inline T *
js::Allocator::pod_calloc()
{
return compartment->rt->pod_calloc<T>(compartment);
}
template <class T>
inline T *
js::Allocator::pod_malloc(size_t numElems)
{
return compartment->rt->pod_malloc<T>(numElems, compartment);
}
template <class T>
inline T *
js::Allocator::pod_calloc(size_t numElems)
{
return compartment->rt->pod_calloc<T>(numElems, compartment);
js_ReportAllocationOverflow(NULL);
}
inline void *
js::Allocator::parallelNewGCThing(gc::AllocKind thingKind, size_t thingSize)
{
return arenas.parallelAllocate(compartment, thingKind, thingSize);
return arenas.parallelAllocate(zone, thingKind, thingSize);
}
#endif /* jscompartment_inlines_h___ */

View File

@ -1160,8 +1160,8 @@ JSCompartment::reduceGCTriggerBytes(size_t amount)
gcTriggerBytes -= amount;
}
Allocator::Allocator(JSCompartment *compartment)
: compartment(compartment)
Allocator::Allocator(Zone *zone)
: zone(zone)
{}
inline void