diff --git a/js/src/jscntxt.cpp b/js/src/jscntxt.cpp index 7af81a6711d..6d3bf9c33ec 100644 --- a/js/src/jscntxt.cpp +++ b/js/src/jscntxt.cpp @@ -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) { diff --git a/js/src/jscntxt.h b/js/src/jscntxt.h index 8002c28d587..0140f942d24 100644 --- a/js/src/jscntxt.h +++ b/js/src/jscntxt.h @@ -495,15 +495,87 @@ class PerThreadData : public js::PerThreadDataFriendFields bool associatedWith(const JSRuntime *rt) { return runtime_ == rt; } }; +template +struct MallocProvider +{ + void *malloc_(size_t bytes) { + Client *client = static_cast(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(this); + client->updateMallocCounter(bytes); + void *p = js_calloc(bytes); + return JS_LIKELY(!!p) ? p : client->onOutOfMemory(reinterpret_cast(1), bytes); + } + + void *realloc_(void *p, size_t oldBytes, size_t newBytes) { + Client *client = static_cast(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(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 + T *pod_malloc() { + return (T *)malloc_(sizeof(T)); + } + + template + T *pod_calloc() { + return (T *)calloc_(sizeof(T)); + } + + template + T *pod_malloc(size_t numElems) { + if (numElems & js::tl::MulOverflowMask::result) { + Client *client = static_cast(this); + client->reportAllocationOverflow(); + return NULL; + } + return (T *)malloc_(numElems * sizeof(T)); + } + + template + T *pod_calloc(size_t numElems, JSCompartment *comp = NULL, JSContext *cx = NULL) { + if (numElems & js::tl::MulOverflowMask::result) { + Client *client = static_cast(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 { - /* 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 - T *pod_malloc(JSCompartment *comp = NULL, JSContext *cx = NULL) { - return (T *)malloc_(sizeof(T), comp, cx); - } - - template - T *pod_calloc(JSCompartment *comp = NULL, JSContext *cx = NULL) { - return (T *)calloc_(sizeof(T), comp, cx); - } - - template - T *pod_malloc(size_t numElems, JSCompartment *comp = NULL, JSContext *cx = NULL) { - if (numElems & js::tl::MulOverflowMask::result) { - js_ReportAllocationOverflow(cx); - return NULL; - } - return (T *)malloc_(numElems * sizeof(T), comp, cx); - } - - template - T *pod_calloc(size_t numElems, JSCompartment *comp = NULL, JSContext *cx = NULL) { - if (numElems & js::tl::MulOverflowMask::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 + public mozilla::LinkedListElement, + public js::MallocProvider { 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 T *pod_malloc() { - return runtime->pod_malloc(compartment, this); - } - - template T *pod_calloc() { - return runtime->pod_calloc(compartment, this); - } - - template T *pod_malloc(size_t numElems) { - return runtime->pod_malloc(numElems, compartment, this); - } - - template - T *pod_calloc(size_t numElems) { - return runtime->pod_calloc(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(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___ */ diff --git a/js/src/jscompartment.h b/js/src/jscompartment.h index 2a3fbf0a7ca..b94c9de3582 100644 --- a/js/src/jscompartment.h +++ b/js/src/jscompartment.h @@ -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 { - 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 inline T *pod_malloc(); - template inline T *pod_calloc(); - template inline T *pod_malloc(size_t numElems); - template 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 */ diff --git a/js/src/jscompartmentinlines.h b/js/src/jscompartmentinlines.h index 8dfabd250c2..c333b259eea 100644 --- a/js/src/jscompartmentinlines.h +++ b/js/src/jscompartmentinlines.h @@ -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 -inline T * -js::Allocator::pod_malloc() -{ - return compartment->rt->pod_malloc(compartment); -} - -template -inline T * -js::Allocator::pod_calloc() -{ - return compartment->rt->pod_calloc(compartment); -} - -template -inline T * -js::Allocator::pod_malloc(size_t numElems) -{ - return compartment->rt->pod_malloc(numElems, compartment); -} - -template -inline T * -js::Allocator::pod_calloc(size_t numElems) -{ - return compartment->rt->pod_calloc(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___ */ diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index d75e7c9f040..855fef501a8 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -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