diff --git a/js/src/xpconnect/idl/xpccomponents.idl b/js/src/xpconnect/idl/xpccomponents.idl index 2e0ad7b2a0a..4869985dbf0 100644 --- a/js/src/xpconnect/idl/xpccomponents.idl +++ b/js/src/xpconnect/idl/xpccomponents.idl @@ -120,10 +120,19 @@ interface nsIXPCComponents_utils_Sandbox : nsISupports { }; +/** + * interface for callback to be passed to Cu.schedulePreciseGC + */ +[scriptable, function, uuid(71000535-b0fd-44d1-8ce0-909760e3953c)] +interface ScheduledGCCallback : nsISupports +{ + void callback(); +}; + /** * interface of Components.utils */ -[scriptable, uuid(5f0acf45-135a-48d1-976c-082ce3b24ead)] +[scriptable, uuid(fed2d752-6cb3-4135-97b0-2c290e541e2d)] interface nsIXPCComponents_Utils : nsISupports { @@ -228,6 +237,13 @@ interface nsIXPCComponents_Utils : nsISupports */ void forceGC(); + /* + * Schedule a garbage collection cycle for a point in the future when no JS + * is running. Call the provided function once this has occurred. + */ + [implicit_jscontext] + void schedulePreciseGC(in ScheduledGCCallback callback); + /* * To be called from JS only. * diff --git a/js/src/xpconnect/src/xpccomponents.cpp b/js/src/xpconnect/src/xpccomponents.cpp index 0e8cb62b95a..de2248e3ca1 100644 --- a/js/src/xpconnect/src/xpccomponents.cpp +++ b/js/src/xpconnect/src/xpccomponents.cpp @@ -55,6 +55,7 @@ #include "nsNullPrincipal.h" #include "nsJSUtils.h" #include "mozJSComponentLoader.h" +#include "nsContentUtils.h" /***************************************************************************/ // stuff used by all @@ -3775,6 +3776,48 @@ nsXPCComponents_Utils::ForceGC() return NS_OK; } +class PreciseGCRunnable : public nsRunnable +{ + public: + PreciseGCRunnable(JSContext *aCx, ScheduledGCCallback* aCallback) + : mCallback(aCallback), mCx(aCx) {} + + NS_IMETHOD Run() + { + nsCOMPtr runtimeSvc = do_GetService("@mozilla.org/js/xpc/RuntimeService;1"); + NS_ENSURE_STATE(runtimeSvc); + + JSRuntime* rt = nsnull; + runtimeSvc->GetRuntime(&rt); + NS_ENSURE_STATE(rt); + + JSContext *cx; + JSContext *iter = nsnull; + while ((cx = JS_ContextIterator(rt, &iter)) != NULL) { + if (JS_IsRunning(cx)) { + return NS_DispatchToMainThread(this); + } + } + + JS_GC(mCx); + + mCallback->Callback(); + return NS_OK; + } + + private: + nsRefPtr mCallback; + JSContext *mCx; +}; + +/* [inline_jscontext] void schedulePreciseGC(in ScheduledGCCallback callback); */ +NS_IMETHODIMP +nsXPCComponents_Utils::SchedulePreciseGC(ScheduledGCCallback* aCallback, JSContext* aCx) +{ + nsRefPtr event = new PreciseGCRunnable(aCx, aCallback); + return NS_DispatchToMainThread(event); +} + /* void getGlobalForObject(); */ NS_IMETHODIMP nsXPCComponents_Utils::GetGlobalForObject() diff --git a/js/src/xpconnect/tests/chrome/Makefile.in b/js/src/xpconnect/tests/chrome/Makefile.in index 020dd6063f6..ac80ca682d8 100644 --- a/js/src/xpconnect/tests/chrome/Makefile.in +++ b/js/src/xpconnect/tests/chrome/Makefile.in @@ -66,6 +66,7 @@ _CHROME_FILES = \ test_bug596580.xul \ test_bug654370.xul \ test_bug658560.xul \ + test_precisegc.xul \ $(NULL) # Disabled until this test gets updated to test the new proxy based diff --git a/js/src/xpconnect/tests/chrome/test_precisegc.xul b/js/src/xpconnect/tests/chrome/test_precisegc.xul new file mode 100644 index 00000000000..aa956a42106 --- /dev/null +++ b/js/src/xpconnect/tests/chrome/test_precisegc.xul @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + +