diff --git a/modules/plugin/test/mochitest/test_GCrace.html b/modules/plugin/test/mochitest/test_GCrace.html
new file mode 100644
index 000000000000..40e4f04e14df
--- /dev/null
+++ b/modules/plugin/test/mochitest/test_GCrace.html
@@ -0,0 +1,59 @@
+
+ GC race with actors on the parent
+
+
+
+
+
+
+
+
+
+
diff --git a/modules/plugin/test/testplugin/nptest.cpp b/modules/plugin/test/testplugin/nptest.cpp
index 393eeebe346d..0b203c7dac51 100644
--- a/modules/plugin/test/testplugin/nptest.cpp
+++ b/modules/plugin/test/testplugin/nptest.cpp
@@ -46,6 +46,7 @@
#ifdef XP_WIN
#include
#include
+#include
#define getpid _getpid
#else
#include
@@ -144,6 +145,7 @@ static bool setCookie(NPObject* npobj, const NPVariant* args, uint32_t argCount,
static bool getCookie(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
static bool getAuthInfo(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
static bool asyncCallbackTest(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
+static bool checkGCRace(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
static const NPUTF8* sPluginMethodIdentifierNames[] = {
"npnEvaluateTest",
@@ -181,6 +183,7 @@ static const NPUTF8* sPluginMethodIdentifierNames[] = {
"getCookie",
"getAuthInfo",
"asyncCallbackTest",
+ "checkGCRace",
};
static NPIdentifier sPluginMethodIdentifiers[ARRAY_LENGTH(sPluginMethodIdentifierNames)];
static const ScriptableFunction sPluginMethodFunctions[ARRAY_LENGTH(sPluginMethodIdentifierNames)] = {
@@ -219,6 +222,7 @@ static const ScriptableFunction sPluginMethodFunctions[ARRAY_LENGTH(sPluginMetho
getCookie,
getAuthInfo,
asyncCallbackTest,
+ checkGCRace,
};
struct URLNotifyData
@@ -2450,3 +2454,101 @@ asyncCallbackTest(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPV
return true;
}
+
+static bool
+GCRaceInvoke(NPObject*, NPIdentifier, const NPVariant*, uint32_t, NPVariant*)
+{
+ return false;
+}
+
+static bool
+GCRaceInvokeDefault(NPObject* o, const NPVariant* args, uint32_t argCount,
+ NPVariant* result)
+{
+ if (1 != argCount || !NPVARIANT_IS_INT32(args[0]) ||
+ 35 != NPVARIANT_TO_INT32(args[0]))
+ return false;
+
+ return true;
+}
+
+static const NPClass kGCRaceClass = {
+ NP_CLASS_STRUCT_VERSION,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ GCRaceInvoke,
+ GCRaceInvokeDefault,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+
+struct GCRaceData
+{
+ GCRaceData(NPP npp, NPObject* callback, NPObject* localFunc)
+ : npp_(npp)
+ , callback_(callback)
+ , localFunc_(localFunc)
+ {
+ NPN_RetainObject(callback_);
+ NPN_RetainObject(localFunc_);
+ }
+
+ ~GCRaceData()
+ {
+ NPN_ReleaseObject(callback_);
+ NPN_ReleaseObject(localFunc_);
+ }
+
+ NPP npp_;
+ NPObject* callback_;
+ NPObject* localFunc_;
+};
+
+static void
+FinishGCRace(void* closure)
+{
+ GCRaceData* rd = static_cast(closure);
+
+#ifdef XP_WIN
+ Sleep(5000);
+#else
+ sleep(5);
+#endif
+
+ NPVariant arg;
+ OBJECT_TO_NPVARIANT(rd->localFunc_, arg);
+
+ NPVariant result;
+ bool ok = NPN_InvokeDefault(rd->npp_, rd->callback_, &arg, 1, &result);
+ if (!ok)
+ return;
+
+ NPN_ReleaseVariantValue(&result);
+ delete rd;
+}
+
+bool
+checkGCRace(NPObject* npobj, const NPVariant* args, uint32_t argCount,
+ NPVariant* result)
+{
+ if (1 != argCount || !NPVARIANT_IS_OBJECT(args[0]))
+ return false;
+
+ NPP npp = static_cast(npobj)->npp;
+
+ NPObject* localFunc =
+ NPN_CreateObject(npp, const_cast(&kGCRaceClass));
+
+ GCRaceData* rd =
+ new GCRaceData(npp, NPVARIANT_TO_OBJECT(args[0]), localFunc);
+ NPN_PluginThreadAsyncCall(npp, FinishGCRace, rd);
+
+ OBJECT_TO_NPVARIANT(localFunc, *result);
+ return true;
+}