diff --git a/mozilla/profile/dirserviceprovider/public/nsProfileDirServiceProvider.h b/mozilla/profile/dirserviceprovider/public/nsProfileDirServiceProvider.h index 6f6386b7d7b..0b875bf380c 100755 --- a/mozilla/profile/dirserviceprovider/public/nsProfileDirServiceProvider.h +++ b/mozilla/profile/dirserviceprovider/public/nsProfileDirServiceProvider.h @@ -41,6 +41,7 @@ #include "nsILocalFile.h" #ifdef STANDALONE_PROFILEDIRSERVICE +#define MOZILLA_STRICT_API #include "nsEmbedString.h" #else #include "nsString.h" diff --git a/mozilla/profile/dirserviceprovider/src/nsProfileLock.cpp b/mozilla/profile/dirserviceprovider/src/nsProfileLock.cpp index aa7fdf2a2bc..76667f9e7ff 100644 --- a/mozilla/profile/dirserviceprovider/src/nsProfileLock.cpp +++ b/mozilla/profile/dirserviceprovider/src/nsProfileLock.cpp @@ -41,6 +41,7 @@ #include "nsProfileStringTypes.h" #include "nsProfileLock.h" +#include "nsCOMPtr.h" #if defined(XP_MAC) || defined(XP_MACOSX) #include diff --git a/mozilla/profile/dirserviceprovider/src/nsProfileStringTypes.h b/mozilla/profile/dirserviceprovider/src/nsProfileStringTypes.h index 7ad8ced4b08..796c7deeff3 100644 --- a/mozilla/profile/dirserviceprovider/src/nsProfileStringTypes.h +++ b/mozilla/profile/dirserviceprovider/src/nsProfileStringTypes.h @@ -50,6 +50,7 @@ */ #ifdef STANDALONE_PROFILEDIRSERVICE +#define MOZILLA_STRICT_API #include "nsEmbedString.h" typedef nsEmbedString nsString; diff --git a/mozilla/xpcom/base/nsIMemory.idl b/mozilla/xpcom/base/nsIMemory.idl index 071aed06606..315a8c22844 100644 --- a/mozilla/xpcom/base/nsIMemory.idl +++ b/mozilla/xpcom/base/nsIMemory.idl @@ -42,6 +42,10 @@ * nsIMemory: interface to allocate and deallocate memory. Also provides * for notifications in low-memory situations. * + * The frozen exported symbols NS_Alloc, NS_Realloc, and NS_Free + * provide a more efficient way to access XPCOM memory allocation. Using + * those symbols is preferred to using the methods on this interface. + * * A client that wishes to be notified of low memory situations (for * example, because the client maintains a large memory cache that * could be released when memory is tight) should register with the diff --git a/mozilla/xpcom/base/nsMemoryImpl.cpp b/mozilla/xpcom/base/nsMemoryImpl.cpp index 8aa16e58b96..c6e3a23ac96 100644 --- a/mozilla/xpcom/base/nsMemoryImpl.cpp +++ b/mozilla/xpcom/base/nsMemoryImpl.cpp @@ -35,14 +35,22 @@ * * ***** END LICENSE BLOCK ***** */ +#include "nsXPCOM.h" #include "nsMemoryImpl.h" -#include "prmem.h" -#include "nsAlgorithm.h" -#include "nsIServiceManager.h" -#include "nsIObserverService.h" -#include "nsAutoLock.h" -#include "nsIThread.h" + #include "nsIEventQueueService.h" +#include "nsIObserverService.h" +#include "nsIRunnable.h" +#include "nsIServiceManager.h" +#include "nsISupportsArray.h" +#include "nsIThread.h" + +#include "prmem.h" +#include "plevent.h" + +#include "nsAlgorithm.h" +#include "nsAutoLock.h" +#include "nsCOMPtr.h" #include "nsString.h" #if defined(XP_WIN) @@ -56,216 +64,6 @@ #undef NS_MEMORY_FLUSHER_THREAD #endif -//---------------------------------------------------------------------- - -#if defined(XDEBUG_waterson) -#define NS_TEST_MEMORY_FLUSHER -#endif - -/** - * A runnable that is used to periodically check the status - * of the system, determine if too much memory is in use, - * and if so, trigger a "memory flush". - */ -class MemoryFlusher : public nsIRunnable -{ -protected: - nsMemoryImpl* mMemoryImpl; // WEAK, it owns us. - PRBool mRunning; - PRIntervalTime mTimeout; - PRLock* mLock; - PRCondVar* mCVar; - - MemoryFlusher(nsMemoryImpl* aMemoryImpl); - - enum { - kInitialTimeout = 60 /*seconds*/ - }; - -private: - ~MemoryFlusher(); - -public: - /** - * Create a memory flusher. - * @param aResult the memory flusher - * @param aMemoryImpl the owning nsMemoryImpl object - * @return NS_OK if the memory flusher was created successfully - */ - static nsresult - Create(MemoryFlusher** aResult, nsMemoryImpl* aMemoryImpl); - - NS_DECL_ISUPPORTS - NS_DECL_NSIRUNNABLE - - /** - * Stop the memory flusher. - */ - nsresult Stop(); -}; - - -MemoryFlusher::MemoryFlusher(nsMemoryImpl* aMemoryImpl) - : mMemoryImpl(aMemoryImpl), - mRunning(PR_FALSE), - mTimeout(PR_SecondsToInterval(kInitialTimeout)), - mLock(nsnull), - mCVar(nsnull) -{ -} - -MemoryFlusher::~MemoryFlusher() -{ - if (mLock) - PR_DestroyLock(mLock); - - if (mCVar) - PR_DestroyCondVar(mCVar); -} - - -nsresult -MemoryFlusher::Create(MemoryFlusher** aResult, nsMemoryImpl* aMemoryImpl) -{ - MemoryFlusher* result = new MemoryFlusher(aMemoryImpl); - if (! result) - return NS_ERROR_OUT_OF_MEMORY; - - do { - if ((result->mLock = PR_NewLock()) == nsnull) - break; - - if ((result->mCVar = PR_NewCondVar(result->mLock)) == nsnull) - break; - - NS_ADDREF(*aResult = result); - return NS_OK; - } while (0); - - // Something bad happened if we get here... - delete result; - return NS_ERROR_OUT_OF_MEMORY; -} - -NS_IMPL_THREADSAFE_ISUPPORTS1(MemoryFlusher, nsIRunnable) - -NS_IMETHODIMP -MemoryFlusher::Run() -{ - nsresult rv; - - mRunning = PR_TRUE; - - while (1) { - PRStatus status; - - { - nsAutoLock l(mLock); - if (! mRunning) { - rv = NS_OK; - break; - } - - status = PR_WaitCondVar(mCVar, mTimeout); - } - - if (status != PR_SUCCESS) { - rv = NS_ERROR_FAILURE; - break; - } - - if (! mRunning) { - rv = NS_OK; - break; - } - - PRBool isLowMemory; - rv = mMemoryImpl->IsLowMemory(&isLowMemory); - if (NS_FAILED(rv)) - break; - -#ifdef NS_TEST_MEMORY_FLUSHER - // Fire the flusher *every* time - isLowMemory = PR_TRUE; -#endif - - if (isLowMemory) { - mMemoryImpl->FlushMemory(NS_LITERAL_STRING("low-memory").get(), PR_FALSE); - } - } - - mRunning = PR_FALSE; - - return rv; -} - - -nsresult -MemoryFlusher::Stop() -{ - if (mRunning) { - nsAutoLock l(mLock); - mRunning = PR_FALSE; - PR_NotifyCondVar(mCVar); - } - - return NS_OK; -} - -//---------------------------------------------------------------------- - -nsMemoryImpl* gMemory = nsnull; - -NS_IMPL_THREADSAFE_ISUPPORTS1(nsMemoryImpl, nsIMemory) - -NS_METHOD -nsMemoryImpl::Create(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr) -{ - NS_ENSURE_ARG_POINTER(aInstancePtr); - NS_ENSURE_PROPER_AGGREGATION(outer, aIID); - if (gMemory && NS_SUCCEEDED(gMemory->QueryInterface(aIID, aInstancePtr))) - return NS_OK; - - nsMemoryImpl* mm = new nsMemoryImpl(); - if (mm == NULL) - return NS_ERROR_OUT_OF_MEMORY; - - nsresult rv; - - do { - rv = mm->QueryInterface(aIID, aInstancePtr); - if (NS_FAILED(rv)) - break; - - rv = NS_ERROR_OUT_OF_MEMORY; - - mm->mFlushLock = PR_NewLock(); - if (! mm->mFlushLock) - break; - - rv = NS_OK; - } while (0); - - if (NS_FAILED(rv)) - delete mm; - - return rv; -} - - -nsMemoryImpl::nsMemoryImpl() - : mFlusher(nsnull), - mFlushLock(nsnull), - mIsFlushing(PR_FALSE) -{ -} - -nsMemoryImpl::~nsMemoryImpl() -{ - if (mFlushLock) - PR_DestroyLock(mFlushLock); -} - //////////////////////////////////////////////////////////////////////////////// // Define NS_OUT_OF_MEMORY_TESTER if you want to force memory failures @@ -316,35 +114,66 @@ reallocator(void* ptr, PRSize size, PRUint32& counter, PRUint32 max) #endif // NS_OUT_OF_MEMORY_TESTER -//////////////////////////////////////////////////////////////////////////////// +#if defined(XDEBUG_waterson) +#define NS_TEST_MEMORY_FLUSHER +#endif -NS_IMETHODIMP_(void *) +#ifdef NS_MEMORY_FLUSHER_THREAD +/** + * A runnable that is used to periodically check the status + * of the system, determine if too much memory is in use, + * and if so, trigger a "memory flush". + */ + +class MemoryFlusher : public nsIRunnable +{ +public: + // We don't use the generic macros because we are a special static object + NS_IMETHOD QueryInterface(REFNSIID aIID, void** aResult); + NS_IMETHOD_(nsrefcnt) AddRef(void) { return 1; } + NS_IMETHOD_(nsrefcnt) Release(void) { return 1; } + + NS_DECL_NSIRUNNABLE + + nsresult Init(); + void StopAndJoin(); + +private: + static PRBool sRunning; + static PRIntervalTime sTimeout; + static PRLock* sLock; + static PRCondVar* sCVar; + static nsIThread* sThread; + + enum { + kInitialTimeout = 60 /*seconds*/ + }; +}; + +static MemoryFlusher sGlobalMemoryFlusher; + +#endif // NS_MEMORY_FLUSHER_THREAD + +static nsMemoryImpl sGlobalMemory; + +NS_IMPL_QUERY_INTERFACE1(nsMemoryImpl, nsIMemory) + +NS_IMETHODIMP_(void*) nsMemoryImpl::Alloc(PRSize size) { - NS_ASSERTION(size, "nsMemoryImpl::Alloc of 0"); - void* result = MALLOC1(size); - if (! result) { - // Request an asynchronous flush - FlushMemory(NS_LITERAL_STRING("alloc-failure").get(), PR_FALSE); - } - return result; + return NS_Alloc(size); } -NS_IMETHODIMP_(void *) -nsMemoryImpl::Realloc(void * ptr, PRSize size) +NS_IMETHODIMP_(void*) +nsMemoryImpl::Realloc(void* ptr, PRSize size) { - void* result = REALLOC1(ptr, size); - if (! result) { - // Request an asynchronous flush - FlushMemory(NS_LITERAL_STRING("alloc-failure").get(), PR_FALSE); - } - return result; + return NS_Realloc(ptr, size); } NS_IMETHODIMP_(void) -nsMemoryImpl::Free(void * ptr) +nsMemoryImpl::Free(void* ptr) { - PR_Free(ptr); + NS_Free(ptr); } NS_IMETHODIMP @@ -397,6 +226,38 @@ nsMemoryImpl::IsLowMemory(PRBool *result) return NS_OK; } + +nsresult +nsMemoryImpl::Startup() +{ +#ifdef NS_MEMORY_FLUSHER_THREAD + sFlushLock = PR_NewLock(); + if (!sFlushLock) return NS_ERROR_FAILURE; + + return sGlobalMemoryFlusher.Init(); +#else + return NS_OK; +#endif +} + +void +nsMemoryImpl::Shutdown() +{ +#ifdef NS_MEMORY_FLUSHER_THREAD + sGlobalMemoryFlusher.StopAndJoin(); +#endif + + if (sFlushLock) PR_DestroyLock(sFlushLock); + sFlushLock = nsnull; +} + +nsresult +nsMemoryImpl::Create(nsISupports* outer, const nsIID& aIID, void **aResult) +{ + NS_ENSURE_NO_AGGREGATION(outer); + return sGlobalMemory.QueryInterface(aIID, aResult); +} + nsresult nsMemoryImpl::FlushMemory(const PRUnichar* aReason, PRBool aImmediate) { @@ -427,18 +288,18 @@ nsMemoryImpl::FlushMemory(const PRUnichar* aReason, PRBool aImmediate) { // Are we already flushing? - nsAutoLock l(mFlushLock); - if (mIsFlushing) + nsAutoLock l(sFlushLock); + if (sIsFlushing) return NS_OK; // Well, we are now! - mIsFlushing = PR_TRUE; + sIsFlushing = PR_TRUE; } // Run the flushers immediately if we can; otherwise, proxy to the // UI thread an run 'em asynchronously. if (aImmediate) { - rv = RunFlushers(this, aReason); + rv = RunFlushers(aReason); } else { nsCOMPtr eqs = do_GetService(NS_EVENTQUEUESERVICE_CONTRACTID, &rv); @@ -446,10 +307,10 @@ nsMemoryImpl::FlushMemory(const PRUnichar* aReason, PRBool aImmediate) nsCOMPtr eq; rv = eqs->GetThreadEventQueue(NS_UI_THREAD, getter_AddRefs(eq)); if (NS_SUCCEEDED(rv)) { - PL_InitEvent(&mFlushEvent.mEvent, this, HandleFlushEvent, DestroyFlushEvent); - mFlushEvent.mReason = aReason; + PL_InitEvent(&sFlushEvent.mEvent, this, HandleFlushEvent, DestroyFlushEvent); + sFlushEvent.mReason = aReason; - rv = eq->PostEvent(NS_REINTERPRET_CAST(PLEvent*, &mFlushEvent)); + rv = eq->PostEvent(NS_REINTERPRET_CAST(PLEvent*, &sFlushEvent)); } } } @@ -458,17 +319,17 @@ nsMemoryImpl::FlushMemory(const PRUnichar* aReason, PRBool aImmediate) } nsresult -nsMemoryImpl::RunFlushers(nsMemoryImpl* aSelf, const PRUnichar* aReason) +nsMemoryImpl::RunFlushers(const PRUnichar* aReason) { nsCOMPtr os = do_GetService("@mozilla.org/observer-service;1"); if (os) { - os->NotifyObservers(aSelf, "memory-pressure", aReason); + os->NotifyObservers(this, "memory-pressure", aReason); } { // Done flushing - nsAutoLock l(aSelf->mFlushLock); - aSelf->mIsFlushing = PR_FALSE; + nsAutoLock l(sFlushLock); + sIsFlushing = PR_FALSE; } return NS_OK; @@ -477,10 +338,9 @@ nsMemoryImpl::RunFlushers(nsMemoryImpl* aSelf, const PRUnichar* aReason) void* nsMemoryImpl::HandleFlushEvent(PLEvent* aEvent) { - nsMemoryImpl* self = NS_STATIC_CAST(nsMemoryImpl*, PL_GetEventOwner(aEvent)); FlushEvent* event = NS_REINTERPRET_CAST(FlushEvent*, aEvent); - RunFlushers(self, event->mReason); + sGlobalMemory.RunFlushers(event->mReason); return 0; } @@ -490,59 +350,159 @@ nsMemoryImpl::DestroyFlushEvent(PLEvent* aEvent) // no-op, since mEvent is a member of nsMemoryImpl } -static void -EnsureGlobalMemoryService() +PRLock* +nsMemoryImpl::sFlushLock; + +PRBool +nsMemoryImpl::sIsFlushing = PR_FALSE; + +nsMemoryImpl::FlushEvent +nsMemoryImpl::sFlushEvent; + +extern "C" NS_EXPORT void* +NS_Alloc(PRSize size) { - if (gMemory) return; - nsresult rv = nsMemoryImpl::Create(nsnull, NS_GET_IID(nsIMemory), (void**)&gMemory); - NS_ASSERTION(NS_SUCCEEDED(rv), "nsMemoryImpl::Create failed"); - NS_ASSERTION(gMemory, "improper xpcom initialization"); + NS_ASSERTION(size, "NS_Alloc of size 0"); + + void* result = MALLOC1(size); + if (! result) { + // Request an asynchronous flush + sGlobalMemory.FlushMemory(NS_LITERAL_STRING("alloc-failure").get(), PR_FALSE); + } + return result; } -nsresult -nsMemoryImpl::Startup() +extern "C" NS_EXPORT void* +NS_Realloc(void* ptr, PRSize size) { - EnsureGlobalMemoryService(); - if (! gMemory) - return NS_ERROR_FAILURE; + NS_ASSERTION(size, "NS_Realloc of size 0"); + void* result = REALLOC1(ptr, size); + if (! result) { + // Request an asynchronous flush + sGlobalMemory.FlushMemory(NS_LITERAL_STRING("alloc-failure").get(), PR_FALSE); + } + return result; +} + +extern "C" NS_EXPORT void +NS_Free(void* ptr) +{ + PR_Free(ptr); +} #ifdef NS_MEMORY_FLUSHER_THREAD + +NS_IMPL_QUERY_INTERFACE1(MemoryFlusher, nsIRunnable); + +NS_IMETHODIMP +MemoryFlusher::Run() +{ nsresult rv; - // Create and start a memory flusher thread - rv = MemoryFlusher::Create(&gMemory->mFlusher, gMemory); - if (NS_FAILED(rv)) return rv; + sRunning = PR_TRUE; - rv = NS_NewThread(getter_AddRefs(gMemory->mFlusherThread), - gMemory->mFlusher, - 0, /* XXX use default stack size? */ - PR_JOINABLE_THREAD); + while (1) { + PRStatus status; - if (NS_FAILED(rv)) return rv; -#endif + { + nsAutoLock l(sLock); + if (! sRunning) { + rv = NS_OK; + break; + } - return NS_OK; -} - -nsresult -nsMemoryImpl::Shutdown() -{ - if (gMemory) { -#ifdef NS_MEMORY_FLUSHER_THREAD - if (gMemory->mFlusher) { - // Stop the runnable... - gMemory->mFlusher->Stop(); - NS_RELEASE(gMemory->mFlusher); - - // ...and wait for the thread to exit - if (gMemory->mFlusherThread) - gMemory->mFlusherThread->Join(); + status = PR_WaitCondVar(sCVar, sTimeout); } + + if (status != PR_SUCCESS) { + rv = NS_ERROR_FAILURE; + break; + } + + if (! sRunning) { + rv = NS_OK; + break; + } + + PRBool isLowMemory; + rv = sGlobalMemory.IsLowMemory(&isLowMemory); + if (NS_FAILED(rv)) + break; + +#ifdef NS_TEST_MEMORY_FLUSHER + // Fire the flusher *every* time + isLowMemory = PR_TRUE; #endif - NS_RELEASE(gMemory); - gMemory = nsnull; + if (isLowMemory) { + sGlobalMemory.FlushMemory(NS_LITERAL_STRING("low-memory").get(), PR_FALSE); + } } - return NS_OK; + sRunning = PR_FALSE; + + return rv; +} + +nsresult +MemoryFlusher::Init() +{ + sTimeout = PR_SecondsToInterval(kInitialTimeout); + sLock = PR_NewLock(); + if (!sLock) return NS_ERROR_FAILURE; + + sCVar = PR_NewCondVar(sLock); + if (!sCVar) return NS_ERROR_FAILURE; + + return NS_NewThread(&sThread, + this, + 0, /* XXX use default stack size? */ + PR_JOINABLE_THREAD); +} + +void +MemoryFlusher::StopAndJoin() +{ + if (sRunning) { + { + nsAutoLock l(sLock); + sRunning = PR_FALSE; + PR_NotifyCondVar(sCVar); + } + + if (sThread) + sThread->Join(); + } + + NS_IF_RELEASE(sThread); + + if (sLock) + PR_DestroyLock(sLock); + + if (sCVar) + PR_DestroyCondVar(sCVar); +} + + +PRBool +MemoryFlusher::sRunning; + +PRIntervalTime +MemoryFlusher::sTimeout; + +PRLock* +MemoryFlusher::sLock; + +PRCondVar* +MemoryFlusher::sCVar; + +nsIThread* +MemoryFlusher::sThread; + +#endif // NS_MEMORY_FLUSHER_THREAD + +nsresult +NS_GetMemoryManager(nsIMemory* *result) +{ + return sGlobalMemory.QueryInterface(NS_GET_IID(nsIMemory), (void**) result); } diff --git a/mozilla/xpcom/base/nsMemoryImpl.h b/mozilla/xpcom/base/nsMemoryImpl.h index c9086d119e6..e179b1d52ba 100644 --- a/mozilla/xpcom/base/nsMemoryImpl.h +++ b/mozilla/xpcom/base/nsMemoryImpl.h @@ -38,54 +38,45 @@ #ifndef nsMemoryImpl_h__ #define nsMemoryImpl_h__ -#include "nsMemory.h" -#include "nsISupportsArray.h" -#include "nsIRunnable.h" -#include "nsIThread.h" -#include "nsCOMPtr.h" +#include "nsIMemory.h" +#include "prlock.h" #include "plevent.h" -struct PRLock; -class MemoryFlusher; +// nsMemoryImpl is a static object. We can do this because it doesn't have +// a constructor/destructor or any instance members. Please don't add +// instance member variables, only static member variables. class nsMemoryImpl : public nsIMemory { public: - NS_DECL_ISUPPORTS + // We don't use the generic macros because we are a special static object + NS_IMETHOD QueryInterface(REFNSIID aIID, void** aResult); + NS_IMETHOD_(nsrefcnt) AddRef(void) { return 1; } + NS_IMETHOD_(nsrefcnt) Release(void) { return 1; } + NS_DECL_NSIMEMORY - nsMemoryImpl(); + static NS_HIDDEN_(nsresult) Startup(); + static NS_HIDDEN_(void) Shutdown(); + static NS_METHOD Create(nsISupports* outer, + const nsIID& aIID, void **aResult); - nsresult FlushMemory(const PRUnichar* aReason, PRBool aImmediate); - - // called from xpcom initialization/finalization: - static nsresult Startup(); - static nsresult Shutdown(); - - static NS_METHOD - Create(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr); - -private: - ~nsMemoryImpl(); + NS_HIDDEN_(nsresult) FlushMemory(const PRUnichar* aReason, PRBool aImmediate); protected: - MemoryFlusher* mFlusher; - nsCOMPtr mFlusherThread; - - PRLock* mFlushLock; - PRBool mIsFlushing; - struct FlushEvent { PLEvent mEvent; const PRUnichar* mReason; }; - FlushEvent mFlushEvent; + NS_HIDDEN_(nsresult) RunFlushers(const PRUnichar* aReason); + static NS_HIDDEN_(void*) PR_CALLBACK HandleFlushEvent(PLEvent* aEvent); + static NS_HIDDEN_(void) PR_CALLBACK DestroyFlushEvent(PLEvent* aEvent); - static nsresult RunFlushers(nsMemoryImpl* aSelf, const PRUnichar* aReason); + static PRLock* sFlushLock; + static PRBool sIsFlushing; - static void* PR_CALLBACK HandleFlushEvent(PLEvent* aEvent); - static void PR_CALLBACK DestroyFlushEvent(PLEvent* aEvent); + static FlushEvent sFlushEvent; }; #endif // nsMemoryImpl_h__ diff --git a/mozilla/xpcom/build/nsXPCOM.h b/mozilla/xpcom/build/nsXPCOM.h index e8f5a13950b..1a0656563cf 100644 --- a/mozilla/xpcom/build/nsXPCOM.h +++ b/mozilla/xpcom/build/nsXPCOM.h @@ -50,6 +50,9 @@ # define NS_NewNativeLocalFile NS_NewNativeLocalFile_P # define NS_GetDebug NS_GetDebug_P # define NS_GetTraceRefcnt NS_GetTraceRefcnt_P +# define NS_Alloc NS_Alloc_P +# define NS_Realloc NS_Realloc_P +# define NS_Free NS_Free_P #endif #include "nscore.h" @@ -208,6 +211,52 @@ NS_NewNativeLocalFile(const nsACString &path, PRBool followLinks, nsILocalFile* *result); +/** + * Allocates a block of memory of a particular size. If the memory cannot + * be allocated (because of an out-of-memory condition), null is returned. + * + * @status FROZEN + * + * @param size The size of the block to allocate + * @result The block of memory + * @note This function is thread-safe. + */ +extern "C" NS_COM void* +NS_Alloc(PRSize size); + +/** + * Reallocates a block of memory to a new size. + * + * @status FROZEN + * + * @param ptr The block of memory to reallocate. This block must originally + have been allocated by NS_Alloc or NS_Realloc + * @param size The new size. If 0, frees the block like NS_Free + * @result The reallocated block of memory + * @note This function is thread-safe. + * + * If ptr is null, this function behaves like NS_Alloc. + * If s is the size of the block to which ptr points, the first min(s, size) + * bytes of ptr's block are copied to the new block. If the allocation + * succeeds, ptr is freed and a pointer to the new block is returned. If the + * allocation fails, ptr is not freed and null is returned. The returned + * value may be the same as ptr. + */ +extern "C" NS_COM void* +NS_Realloc(void* ptr, PRSize size); + +/** + * Frees a block of memory. Null is a permissible value, in which case no + * action is taken. + * + * @status FROZEN + * + * @param ptr The block of memory to free. This block must originally have + * been allocated by NS_Alloc or NS_Realloc + * @note This function is thread-safe. + */ +extern "C" NS_COM void +NS_Free(void* ptr); extern "C" NS_COM nsresult NS_GetDebug(nsIDebug* *result); diff --git a/mozilla/xpcom/build/nsXPCOMPrivate.h b/mozilla/xpcom/build/nsXPCOMPrivate.h index 2b51390733b..02db40df760 100644 --- a/mozilla/xpcom/build/nsXPCOMPrivate.h +++ b/mozilla/xpcom/build/nsXPCOMPrivate.h @@ -43,11 +43,11 @@ #ifndef MOZILLA_STRICT_API # define NS_RegisterXPCOMExitRoutine NS_RegisterXPCOMExitRoutine_P # define NS_UnregisterXPCOMExitRoutine NS_UnregisterXPCOMExitRoutine_P -# define NS_GetFrozenFunctions NS_GetFrozenFunctions_P #endif #include "nscore.h" #include "nsXPCOM.h" +#include "nsStringAPI.h" class nsStringContainer; class nsCStringContainer; @@ -111,8 +111,12 @@ typedef nsresult (* CStringSetDataFunc)(nsACString&, const char*, PRUint32); typedef nsresult (* CStringSetDataRangeFunc)(nsACString&, PRUint32, PRUint32, const char*, PRUint32); typedef nsresult (* CStringCopyFunc)(nsACString &, const nsACString &); -typedef nsresult (* CStringToUTF16)(const nsACString &, PRUint32, const nsAString &); -typedef nsresult (* UTF16ToCString)(const nsAString &, PRUint32, const nsACString &); +typedef nsresult (* CStringToUTF16)(const nsACString &, nsCStringEncoding, nsAString &); +typedef nsresult (* UTF16ToCString)(const nsAString &, nsCStringEncoding, nsACString &); + +typedef void* (* AllocFunc)(PRSize size); +typedef void* (* ReallocFunc)(void* ptr, PRSize size); +typedef void (* FreeFunc)(void* ptr); // PRIVATE typedef nsresult (* RegisterXPCOMExitRoutineFunc)(XPCOMExitRoutine exitRoutine, PRUint32 priority); @@ -155,6 +159,9 @@ typedef struct XPCOMFunctions{ UTF16ToCString utf16ToCString; StringCloneDataFunc stringCloneData; CStringCloneDataFunc cstringCloneData; + AllocFunc allocFunc; + ReallocFunc reallocFunc; + FreeFunc freeFunc; } XPCOMFunctions; diff --git a/mozilla/xpcom/build/nsXPComInit.cpp b/mozilla/xpcom/build/nsXPComInit.cpp index 50ad1d8a056..3b77e095a8e 100644 --- a/mozilla/xpcom/build/nsXPComInit.cpp +++ b/mozilla/xpcom/build/nsXPComInit.cpp @@ -384,21 +384,6 @@ static const nsModuleComponentInfo components[] = { const int components_length = sizeof(components) / sizeof(components[0]); -// gMemory will be freed during shutdown. -static nsIMemory* gMemory = nsnull; -nsresult NS_COM NS_GetMemoryManager(nsIMemory* *result) -{ - nsresult rv = NS_OK; - if (!gMemory) - { - rv = nsMemoryImpl::Create(nsnull, - NS_GET_IID(nsIMemory), - (void**)&gMemory); - } - NS_IF_ADDREF(*result = gMemory); - return rv; -} - // gDebug will be freed during shutdown. static nsIDebug* gDebug = nsnull; nsresult NS_COM NS_GetDebug(nsIDebug** result) @@ -856,7 +841,6 @@ nsresult NS_COM NS_ShutdownXPCOM(nsIServiceManager* servMgr) EmptyEnumeratorImpl::Shutdown(); nsMemoryImpl::Shutdown(); - NS_IF_RELEASE(gMemory); nsThread::Shutdown(); NS_PurgeAtomTable(); @@ -876,65 +860,3 @@ nsresult NS_COM NS_ShutdownXPCOM(nsIServiceManager* servMgr) return NS_OK; } - -#define GET_FUNC(_tag, _decl, _name) \ - functions->_tag = (_decl) PR_FindSymbol(xpcomLib, _name); \ - if (!functions->_tag) goto end - -nsresult NS_COM PR_CALLBACK -NS_GetFrozenFunctions(XPCOMFunctions *functions, const char* libraryPath) -{ - if (!functions) - return NS_ERROR_OUT_OF_MEMORY; - - if (functions->version != XPCOM_GLUE_VERSION) - return NS_ERROR_FAILURE; - - PRLibrary *xpcomLib = PR_LoadLibrary(libraryPath); - if (!xpcomLib) - return NS_ERROR_FAILURE; - - nsresult rv = NS_ERROR_FAILURE; - - GET_FUNC(init, InitFunc, "NS_InitXPCOM2"); - GET_FUNC(shutdown, ShutdownFunc, "NS_ShutdownXPCOM"); - GET_FUNC(getServiceManager, GetServiceManagerFunc, "NS_GetServiceManager"); - GET_FUNC(getComponentManager, GetComponentManagerFunc, "NS_GetComponentManager"); - GET_FUNC(getComponentRegistrar, GetComponentRegistrarFunc, "NS_GetComponentRegistrar"); - GET_FUNC(getMemoryManager, GetMemoryManagerFunc, "NS_GetMemoryManager"); - GET_FUNC(newLocalFile, NewLocalFileFunc, "NS_NewLocalFile"); - GET_FUNC(newNativeLocalFile, NewNativeLocalFileFunc, "NS_NewNativeLocalFile"); - GET_FUNC(registerExitRoutine, RegisterXPCOMExitRoutineFunc, "NS_RegisterXPCOMExitRoutine"); - GET_FUNC(unregisterExitRoutine, UnregisterXPCOMExitRoutineFunc, "NS_UnregisterXPCOMExitRoutine"); - - // these functions were added post 1.4 (need to check size of |functions|) - if (functions->size > offsetof(XPCOMFunctions, getTraceRefcnt)) { - GET_FUNC(getDebug, GetDebugFunc, "NS_GetDebug"); - GET_FUNC(getTraceRefcnt, GetTraceRefcntFunc, "NS_GetTraceRefcnt"); - } - - // these functions were added post 1.6 (need to check size of |functions|) - if (functions->size > offsetof(XPCOMFunctions, cstringCloneData)) { - GET_FUNC(stringContainerInit, StringContainerInitFunc, "NS_StringContainerInit"); - GET_FUNC(stringContainerFinish, StringContainerFinishFunc, "NS_StringContainerFinish"); - GET_FUNC(stringGetData, StringGetDataFunc, "NS_StringGetData"); - GET_FUNC(stringSetData, StringSetDataFunc, "NS_StringSetData"); - GET_FUNC(stringSetDataRange, StringSetDataRangeFunc, "NS_StringSetDataRange"); - GET_FUNC(stringCopy, StringCopyFunc, "NS_StringCopy"); - GET_FUNC(cstringContainerInit, CStringContainerInitFunc, "NS_CStringContainerInit"); - GET_FUNC(cstringContainerFinish, CStringContainerFinishFunc, "NS_CStringContainerFinish"); - GET_FUNC(cstringGetData, CStringGetDataFunc, "NS_CStringGetData"); - GET_FUNC(cstringSetData, CStringSetDataFunc, "NS_CStringSetData"); - GET_FUNC(cstringSetDataRange, CStringSetDataRangeFunc, "NS_CStringSetDataRange"); - GET_FUNC(cstringCopy, CStringCopyFunc, "NS_CStringCopy"); - GET_FUNC(cstringToUTF16, CStringToUTF16, "NS_CStringToUTF16"); - GET_FUNC(utf16ToCString, UTF16ToCString, "NS_UTF16ToCString"); - GET_FUNC(stringCloneData, StringCloneDataFunc, "NS_StringCloneData"); - GET_FUNC(cstringCloneData, CStringCloneDataFunc, "NS_CStringCloneData"); - } - - rv = NS_OK; -end: - PR_UnloadLibrary(xpcomLib); // the library is refcnt'ed above by the caller. - return rv; -} diff --git a/mozilla/xpcom/glue/Makefile.in b/mozilla/xpcom/glue/Makefile.in index e78e629de58..272e6bc76a7 100644 --- a/mozilla/xpcom/glue/Makefile.in +++ b/mozilla/xpcom/glue/Makefile.in @@ -48,7 +48,9 @@ DIRS = standalone MODULE = xpcom LIBRARY_NAME = xpcomglue_s -REQUIRES = $(NULL) +REQUIRES = \ + string \ + $(NULL) LOCAL_INCLUDES = \ -I$(srcdir)/../build \ diff --git a/mozilla/xpcom/glue/nsMemory.cpp b/mozilla/xpcom/glue/nsMemory.cpp index 45661026b41..787f37286ab 100644 --- a/mozilla/xpcom/glue/nsMemory.cpp +++ b/mozilla/xpcom/glue/nsMemory.cpp @@ -40,89 +40,25 @@ #include "nsXPCOMPrivate.h" #include "nsDebug.h" #include "nsISupportsUtils.h" - -static nsIMemory* gMemory = nsnull; - -static NS_METHOD FreeGlobalMemory(void) -{ - NS_IF_RELEASE(gMemory); - return NS_OK; -} - -#define ENSURE_ALLOCATOR \ - (gMemory ? PR_TRUE : (PRBool)(SetupGlobalMemory() != nsnull)) - -static nsIMemory* -SetupGlobalMemory() -{ - NS_ASSERTION(!gMemory, "bad call"); - NS_GetMemoryManager(&gMemory); - NS_ASSERTION(gMemory, "can't get memory manager!"); - NS_RegisterXPCOMExitRoutine(FreeGlobalMemory, 0); - return gMemory; -} - -#ifdef XPCOM_GLUE -nsresult GlueStartupMemory() -{ - NS_ASSERTION(!gMemory, "bad call"); - NS_GetMemoryManager(&gMemory); - NS_ASSERTION(gMemory, "can't get memory manager!"); - return NS_OK; -} - -void GlueShutdownMemory() -{ - NS_IF_RELEASE(gMemory); -} -#endif +#include "nsCOMPtr.h" //////////////////////////////////////////////////////////////////////////////// // nsMemory static helper routines -NS_COM_GLUE void* -nsMemory::Alloc(PRSize size) -{ - if (!ENSURE_ALLOCATOR) - return nsnull; - - return gMemory->Alloc(size); -} - -NS_COM_GLUE void* -nsMemory::Realloc(void* ptr, PRSize size) -{ - if (!ENSURE_ALLOCATOR) - return nsnull; - - return gMemory->Realloc(ptr, size); -} - -NS_COM_GLUE void -nsMemory::Free(void* ptr) -{ - if (!ENSURE_ALLOCATOR) - return; - - gMemory->Free(ptr); -} - NS_COM_GLUE nsresult nsMemory::HeapMinimize(PRBool aImmediate) { - if (!ENSURE_ALLOCATOR) - return NS_ERROR_FAILURE; + nsCOMPtr mem; + nsresult rv = NS_GetMemoryManager(getter_AddRefs(mem)); + NS_ENSURE_SUCCESS(rv, rv); - return gMemory->HeapMinimize(aImmediate); + return mem->HeapMinimize(aImmediate); } NS_COM_GLUE void* nsMemory::Clone(const void* ptr, PRSize size) { - if (!ENSURE_ALLOCATOR) - return nsnull; - - void* newPtr = gMemory->Alloc(size); + void* newPtr = NS_Alloc(size); if (newPtr) memcpy(newPtr, ptr, size); return newPtr; @@ -131,12 +67,11 @@ nsMemory::Clone(const void* ptr, PRSize size) NS_COM_GLUE nsIMemory* nsMemory::GetGlobalMemoryService() { - if (!ENSURE_ALLOCATOR) - return nsnull; + nsIMemory* mem; + nsresult rv = NS_GetMemoryManager(&mem); + if (NS_FAILED(rv)) return nsnull; - nsIMemory* result = gMemory; - NS_IF_ADDREF(result); - return result; + return mem; } //---------------------------------------------------------------------- diff --git a/mozilla/xpcom/glue/nsMemory.h b/mozilla/xpcom/glue/nsMemory.h index aae912ea31b..3e7947a2d37 100644 --- a/mozilla/xpcom/glue/nsMemory.h +++ b/mozilla/xpcom/glue/nsMemory.h @@ -38,6 +38,7 @@ #ifndef nsMemory_h__ #define nsMemory_h__ +#include "nsXPCOM.h" #include "nsIMemory.h" #define NS_MEMORY_CONTRACTID "@mozilla.org/xpcom/memory-service;1" @@ -63,11 +64,17 @@ class nsMemory { public: - static NS_COM_GLUE void* Alloc(size_t size); - static NS_COM_GLUE void* Realloc(void* ptr, size_t size); - static NS_COM_GLUE void Free(void* ptr); + static NS_HIDDEN_(void*) Alloc(size_t size) + { return NS_Alloc(size); } + + static NS_HIDDEN_(void*) Realloc(void* ptr, PRSize size) + { return NS_Realloc(ptr, size); } + + static NS_HIDDEN_(void) Free(void* ptr) + { NS_Free(ptr); } + static NS_COM_GLUE nsresult HeapMinimize(PRBool aImmediate); - static NS_COM_GLUE void* Clone(const void* ptr, size_t size); + static NS_COM_GLUE void* Clone(const void* ptr, PRSize size); static NS_COM_GLUE nsIMemory* GetGlobalMemoryService(); // AddRefs }; @@ -105,7 +112,7 @@ public: PRInt32 iter_ = PRInt32(size); \ while (--iter_ >= 0) \ freeFunc((array)[iter_]); \ - nsMemory::Free((array)); \ + NS_Free((array)); \ PR_END_MACRO // convenience macros for commonly used calls. mmmmm. syntactic sugar. @@ -121,7 +128,7 @@ public: * @param array The array to be freed. */ #define NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(size, array) \ - NS_FREE_XPCOM_POINTER_ARRAY((size), (array), nsMemory::Free) + NS_FREE_XPCOM_POINTER_ARRAY((size), (array), NS_Free) /** * Macro to free an array of pointers to nsISupports (or classes diff --git a/mozilla/xpcom/glue/standalone/nsXPCOMGlue.cpp b/mozilla/xpcom/glue/standalone/nsXPCOMGlue.cpp index 7af2ed2f69c..6f1b4740746 100644 --- a/mozilla/xpcom/glue/standalone/nsXPCOMGlue.cpp +++ b/mozilla/xpcom/glue/standalone/nsXPCOMGlue.cpp @@ -39,7 +39,6 @@ #include "nsXPCOMGlue.h" #include "nspr.h" -#include "nsMemory.h" #include "nsDebug.h" #include "nsIServiceManager.h" #include "nsGREDirServiceProvider.h" @@ -54,9 +53,7 @@ void GRE_AddGREToEnvironment(); -// functions provided by nsMemory.cpp and nsDebug.cpp -nsresult GlueStartupMemory(); -void GlueShutdownMemory(); +// functions provided by nsDebug.cpp nsresult GlueStartupDebug(); void GlueShutdownDebug(); @@ -152,13 +149,6 @@ nsresult XPCOMGlueStartup(const char* xpcomFile) if (NS_FAILED(rv)) goto bail; - // startup the nsMemory - rv = GlueStartupMemory(); - if (NS_FAILED(rv)) { - GlueShutdownDebug(); - goto bail; - } - GRE_AddGREToEnvironment(); return NS_OK; @@ -177,8 +167,6 @@ nsresult XPCOMGlueShutdown() return NS_OK; #else - GlueShutdownMemory(); - GlueShutdownDebug(); if (xpcomLib) { @@ -411,7 +399,7 @@ NS_CStringCopy(nsACString &aDest, const nsACString &aSrc) } extern "C" NS_COM nsresult -NS_CStringToUTF16(const nsACString &aSrc, PRUint32 aSrcEncoding, nsAString &aDest) +NS_CStringToUTF16(const nsACString &aSrc, nsCStringEncoding aSrcEncoding, nsAString &aDest) { if (!xpcomFunctions.cstringToUTF16) return NS_ERROR_NOT_INITIALIZED; @@ -419,13 +407,36 @@ NS_CStringToUTF16(const nsACString &aSrc, PRUint32 aSrcEncoding, nsAString &aDes } extern "C" NS_COM nsresult -NS_UTF16ToCString(const nsAString &aSrc, PRUint32 aDestEncoding, nsACString &aDest) +NS_UTF16ToCString(const nsAString &aSrc, nsCStringEncoding aDestEncoding, nsACString &aDest) { if (!xpcomFunctions.utf16ToCString) return NS_ERROR_NOT_INITIALIZED; return xpcomFunctions.utf16ToCString(aSrc, aDestEncoding, aDest); } +extern "C" NS_COM void* +NS_Alloc(PRSize size) +{ + if (!xpcomFunctions.allocFunc) + return nsnull; + return xpcomFunctions.allocFunc(size); +} + +extern "C" NS_COM void* +NS_Realloc(void* ptr, PRSize size) +{ + if (!xpcomFunctions.reallocFunc) + return nsnull; + return xpcomFunctions.reallocFunc(ptr, size); +} + +extern "C" NS_COM void +NS_Free(void* ptr) +{ + if (xpcomFunctions.freeFunc) + xpcomFunctions.freeFunc(ptr); +} + #endif // #ifndef XPCOM_GLUE_NO_DYNAMIC_LOADING diff --git a/mozilla/xpcom/string/public/nsEmbedString.h b/mozilla/xpcom/string/public/nsEmbedString.h index 72912051312..2586f8bf11f 100644 --- a/mozilla/xpcom/string/public/nsEmbedString.h +++ b/mozilla/xpcom/string/public/nsEmbedString.h @@ -40,6 +40,10 @@ #ifndef nsEmbedString_h___ #define nsEmbedString_h___ +#ifndef MOZILLA_STRICT_API +#error nsEmbedString requires defining MOZILLA_STRICT_API +#endif + #include "nsStringAPI.h" class nsEmbedString : public nsStringContainer diff --git a/mozilla/xpcom/string/public/nsStringAPI.h b/mozilla/xpcom/string/public/nsStringAPI.h index 8be1b858476..30730d5196a 100644 --- a/mozilla/xpcom/string/public/nsStringAPI.h +++ b/mozilla/xpcom/string/public/nsStringAPI.h @@ -637,14 +637,14 @@ NS_UTF16ToCString(const nsAString &aSource, nsCStringEncoding aDestEncoding, * internal definition of these classes from nsAString.h in the Mozilla tree. */ -#ifndef _IMPL_NS_STRINGAPI +#ifdef MOZILLA_STRICT_API #define nsAString_external nsAString #define nsACString_external nsACString #endif class nsAString_external { -#ifndef _IMPL_NS_STRINGAPI +#ifdef MOZILLA_STRICT_API public: typedef PRUnichar char_type; @@ -718,7 +718,7 @@ public: NS_HIDDEN_(void) Cut( index_type cutStart, size_type cutLength ) { Replace(cutStart, cutLength, nsnull, 0); } -#endif // _IMPL_NS_STRINGAPI +#endif // MOZILLA_STRICT_API private: void *v; @@ -726,7 +726,7 @@ private: class nsACString_external { -#ifndef _IMPL_NS_STRINGAPI +#ifdef MOZILLA_STRICT_API public: typedef char char_type; @@ -800,7 +800,7 @@ public: NS_HIDDEN_(void) Cut( index_type cutStart, size_type cutLength ) { Replace(cutStart, cutLength, nsnull, 0); } -#endif // _IMPL_NS_STRINGAPI +#endif // MOZILLA_STRICT_API private: void *v; diff --git a/mozilla/xpcom/stub/nsXPComStub.cpp b/mozilla/xpcom/stub/nsXPComStub.cpp index 045d7597f67..f02ef141ba0 100644 --- a/mozilla/xpcom/stub/nsXPComStub.cpp +++ b/mozilla/xpcom/stub/nsXPComStub.cpp @@ -19,6 +19,7 @@ * * Contributor(s): * Darin Fisher + * Benjamin Smedberg * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or @@ -38,6 +39,70 @@ #include "nsXPCOMPrivate.h" #include "nsStringAPI.h" +#include + +static const XPCOMFunctions kFrozenFunctions = { + XPCOM_GLUE_VERSION, + sizeof(XPCOMFunctions), + &NS_InitXPCOM2_P, + &NS_ShutdownXPCOM_P, + &NS_GetServiceManager_P, + &NS_GetComponentManager_P, + &NS_GetComponentRegistrar_P, + &NS_GetMemoryManager_P, + &NS_NewLocalFile_P, + &NS_NewNativeLocalFile_P, + &NS_RegisterXPCOMExitRoutine_P, + &NS_UnregisterXPCOMExitRoutine_P, + + // these functions were added post 1.4 + &NS_GetDebug_P, + &NS_GetTraceRefcnt_P, + + // these functions were added post 1.6 + &NS_StringContainerInit, + &NS_StringContainerFinish, + &NS_StringGetData, + &NS_StringSetData, + &NS_StringSetDataRange, + &NS_StringCopy, + &NS_CStringContainerInit, + &NS_CStringContainerFinish, + &NS_CStringGetData, + &NS_CStringSetData, + &NS_CStringSetDataRange, + &NS_CStringCopy, + &NS_CStringToUTF16, + &NS_UTF16ToCString, + &NS_StringCloneData, + &NS_CStringCloneData, + + // these functions were added post 1.7 (Firefox 1.0) + &NS_Alloc_P, + &NS_Realloc_P, + &NS_Free_P +}; + +extern "C" NS_EXPORT nsresult +NS_GetFrozenFunctions(XPCOMFunctions *functions, const char* /* libraryPath */) +{ + if (!functions) + return NS_ERROR_OUT_OF_MEMORY; + + if (functions->version != XPCOM_GLUE_VERSION) + return NS_ERROR_FAILURE; + + PRUint32 size = functions->size; + if (size > sizeof(XPCOMFunctions)) + size = sizeof(XPCOMFunctions); + + size -= offsetof(XPCOMFunctions, init); + + memcpy(&functions->init, &kFrozenFunctions.init, size); + + return NS_OK; +} + /* * Stubs for nsXPCOM.h */ @@ -136,9 +201,23 @@ NS_UnregisterXPCOMExitRoutine(XPCOMExitRoutine exitRoutine) return NS_UnregisterXPCOMExitRoutine_P(exitRoutine); } -#undef NS_GetFrozenFunctions -extern "C" NS_EXPORT nsresult -NS_GetFrozenFunctions(XPCOMFunctions *entryPoints, const char* libraryPath) +#undef NS_Alloc +extern "C" NS_EXPORT void* +NS_Alloc(PRSize size) { - return NS_GetFrozenFunctions_P(entryPoints, libraryPath); + return NS_Alloc_P(size); +} + +#undef NS_Realloc +extern "C" NS_EXPORT void* +NS_Realloc(void* ptr, PRSize size) +{ + return NS_Realloc_P(ptr, size); +} + +#undef NS_Free +extern "C" NS_EXPORT void +NS_Free(void* ptr) +{ + NS_Free_P(ptr); } diff --git a/mozilla/xpcom/tests/TestMinStringAPI.cpp b/mozilla/xpcom/tests/TestMinStringAPI.cpp index 5464673c712..c9de46af074 100644 --- a/mozilla/xpcom/tests/TestMinStringAPI.cpp +++ b/mozilla/xpcom/tests/TestMinStringAPI.cpp @@ -35,6 +35,8 @@ * * ***** END LICENSE BLOCK ***** */ +#define MOZILLA_STRICT_API + #include #include "nsStringAPI.h" #include "nsCRT.h"