Bug 827274 - 'crash in [@ anonymous namespace::CTypesActivityCallback(JSContext*, js::CTypesActivityType)], add ctypes closure support to new worker memory reporting mechanism. r=khuey+mrbkap.
authorBen Turner <bent.mozilla@gmail.com>
Tue, 08 Jan 2013 13:57:44 +0100
changeset 118048 928550157e6e37a6eb35f3d0cdff14773391fbec
parent 118047 8f818068da0921c6689abb5150e9c781340e7c81
child 118049 1780bd0c3dee31a296d40d000a9451fd937c0f25
push id24146
push userbturner@mozilla.com
push dateTue, 08 Jan 2013 13:27:17 +0000
treeherdermozilla-central@928550157e6e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskhuey
bugs827274
milestone21.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 827274 - 'crash in [@ anonymous namespace::CTypesActivityCallback(JSContext*, js::CTypesActivityType)], add ctypes closure support to new worker memory reporting mechanism. r=khuey+mrbkap.
dom/workers/RuntimeService.cpp
dom/workers/WorkerPrivate.cpp
dom/workers/WorkerPrivate.h
js/src/ctypes/CTypes.cpp
js/src/jsfriendapi.cpp
js/src/jsfriendapi.h
--- a/dom/workers/RuntimeService.cpp
+++ b/dom/workers/RuntimeService.cpp
@@ -384,16 +384,24 @@ CTypesActivityCallback(JSContext* aCx,
     case js::CTYPES_CALL_BEGIN:
       worker->BeginCTypesCall();
       break;
 
     case js::CTYPES_CALL_END:
       worker->EndCTypesCall();
       break;
 
+    case js::CTYPES_CALLBACK_BEGIN:
+      worker->BeginCTypesCallback();
+      break;
+
+    case js::CTYPES_CALLBACK_END:
+      worker->EndCTypesCallback();
+      break;
+
     default:
       MOZ_NOT_REACHED("Unknown type flag!");
   }
 }
 
 JSContext*
 CreateJSContextForWorker(WorkerPrivate* aWorkerPrivate)
 {
@@ -429,17 +437,17 @@ CreateJSContextForWorker(WorkerPrivate* 
 
   JSContext* workerCx = JS_NewContext(runtime, 0);
   if (!workerCx) {
     JS_DestroyRuntime(runtime);
     NS_WARNING("Could not create new context!");
     return nullptr;
   }
 
-  JS_SetContextPrivate(workerCx, aWorkerPrivate);
+  JS_SetRuntimePrivate(runtime, aWorkerPrivate);
 
   JS_SetErrorReporter(workerCx, ErrorReporter);
 
   JS_SetOperationCallback(workerCx, OperationCallback);
 
   js::SetCTypesActivityCallback(runtime, CTypesActivityCallback);
 
   NS_ASSERTION((aWorkerPrivate->GetJSContextOptions() &
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -4195,17 +4195,17 @@ BEGIN_WORKERS_NAMESPACE
 
 // Force instantiation.
 template class WorkerPrivateParent<WorkerPrivate>;
 
 WorkerPrivate*
 GetWorkerPrivateFromContext(JSContext* aCx)
 {
   NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
-  return static_cast<WorkerPrivate*>(JS_GetContextPrivate(aCx));
+  return static_cast<WorkerPrivate*>(JS_GetRuntimePrivate(JS_GetRuntime(aCx)));
 }
 
 JSStructuredCloneCallbacks*
 WorkerStructuredCloneCallbacks(bool aMainRuntime)
 {
   return aMainRuntime ?
          &gMainThreadWorkerStructuredCloneCallbacks :
          &gWorkerStructuredCloneCallbacks;
--- a/dom/workers/WorkerPrivate.h
+++ b/dom/workers/WorkerPrivate.h
@@ -766,16 +766,32 @@ public:
   // This may block!
   void
   BeginCTypesCall();
 
   // This may block!
   void
   EndCTypesCall();
 
+  void
+  BeginCTypesCallback()
+  {
+    // If a callback is beginning then we need to do the exact same thing as
+    // when a ctypes call ends.
+    EndCTypesCall();
+  }
+
+  void
+  EndCTypesCallback()
+  {
+    // If a callback is ending then we need to do the exact same thing as
+    // when a ctypes call begins.
+    BeginCTypesCall();
+  }
+
 private:
   WorkerPrivate(JSContext* aCx, JSObject* aObject, WorkerPrivate* aParent,
                 JSContext* aParentJSContext, const nsAString& aScriptURL,
                 bool aIsChromeWorker, const nsACString& aDomain,
                 nsCOMPtr<nsPIDOMWindow>& aWindow,
                 nsCOMPtr<nsIScriptContext>& aScriptContext,
                 nsCOMPtr<nsIURI>& aBaseURI, nsCOMPtr<nsIPrincipal>& aPrincipal,
                 nsCOMPtr<nsIContentSecurityPolicy>& aCSP, bool aEvalAllowed,
--- a/js/src/ctypes/CTypes.cpp
+++ b/js/src/ctypes/CTypes.cpp
@@ -5785,19 +5785,17 @@ FunctionType::Call(JSContext* cx,
   TypeCode typeCode = CType::GetTypeCode(fninfo->mReturnType);
   if (typeCode != TYPE_void_t &&
       !returnValue.SizeToType(cx, fninfo->mReturnType)) {
     JS_ReportAllocationOverflow(cx);
     return false;
   }
 
   // Let the runtime callback know that we are about to call into C.
-  js::CTypesActivityCallback activityCallback = cx->runtime->ctypesActivityCallback;
-  if (activityCallback)
-    activityCallback(cx, js::CTYPES_CALL_BEGIN);
+  js::AutoCTypesActivityCallback autoCallback(cx, js::CTYPES_CALL_BEGIN, js::CTYPES_CALL_END);
 
   uintptr_t fn = *reinterpret_cast<uintptr_t*>(CData::GetData(obj));
 
 #if defined(XP_WIN)
   int32_t lastErrorStatus; // The status as defined by |GetLastError|
   int32_t savedLastError = GetLastError();
   SetLastError(0);
 #endif //defined(XP_WIN)
@@ -5816,18 +5814,18 @@ FunctionType::Call(JSContext* cx,
   errnoStatus = errno;
 #if defined(XP_WIN)
   lastErrorStatus = GetLastError();
   SetLastError(savedLastError);
 #endif // defined(XP_WIN)
 
   errno = savedErrno;
 
-  if (activityCallback)
-    activityCallback(cx, js::CTYPES_CALL_END);
+  // We're no longer calling into C.
+  autoCallback.DoEndCallback();
 
   // Store the error value for later consultation with |ctypes.getStatus|
   JSObject *objCTypes = CType::GetGlobalCTypes(cx, typeObj);
   if (!objCTypes)
     return false;
 
   JS_SetReservedSlot(objCTypes, SLOT_ERRNO, INT_TO_JSVAL(errnoStatus));
 #if defined(XP_WIN)
@@ -6100,16 +6098,22 @@ CClosure::ClosureStub(ffi_cif* cif, void
   JS_ASSERT(cif);
   JS_ASSERT(result);
   JS_ASSERT(args);
   JS_ASSERT(userData);
 
   // Retrieve the essentials from our closure object.
   ClosureInfo* cinfo = static_cast<ClosureInfo*>(userData);
   JSContext* cx = cinfo->cx;
+
+  // Let the runtime callback know that we are about to call into JS again. The end callback will
+  // fire automatically when we exit this function.
+  js::AutoCTypesActivityCallback autoCallback(cx, js::CTYPES_CALLBACK_BEGIN,
+                                              js::CTYPES_CALLBACK_END);
+
   RootedObject typeObj(cx, cinfo->typeObj);
   RootedObject thisObj(cx, cinfo->thisObj);
   RootedObject jsfnObj(cx, cinfo->jsfnObj);
 
   JS_AbortIfWrongThread(JS_GetRuntime(cx));
 
   JSAutoRequest ar(cx);
   JSAutoCompartment ac(cx, jsfnObj);
--- a/js/src/jsfriendapi.cpp
+++ b/js/src/jsfriendapi.cpp
@@ -985,8 +985,20 @@ js::GetListBaseExpandoSlot()
     return gListBaseExpandoSlot;
 }
 
 JS_FRIEND_API(void)
 js::SetCTypesActivityCallback(JSRuntime *rt, CTypesActivityCallback cb)
 {
     rt->ctypesActivityCallback = cb;
 }
+
+js::AutoCTypesActivityCallback::AutoCTypesActivityCallback(JSContext *cx,
+                                                           js::CTypesActivityType beginType,
+                                                           js::CTypesActivityType endType
+                                                           MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
+  : cx(cx), callback(cx->runtime->ctypesActivityCallback), beginType(beginType), endType(endType)
+{
+    MOZ_GUARD_OBJECT_NOTIFIER_INIT;
+
+    if (callback)
+        callback(cx, beginType);
+}
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -1564,24 +1564,49 @@ IdToJsval(jsid id)
 extern JS_FRIEND_API(bool)
 IsReadOnlyDateMethod(JS::IsAcceptableThis test, JS::NativeImpl method);
 
 extern JS_FRIEND_API(bool)
 IsTypedArrayThisCheck(JS::IsAcceptableThis test);
 
 enum CTypesActivityType {
     CTYPES_CALL_BEGIN,
-    CTYPES_CALL_END
+    CTYPES_CALL_END,
+    CTYPES_CALLBACK_BEGIN,
+    CTYPES_CALLBACK_END
 };
 
 typedef void
 (* CTypesActivityCallback)(JSContext *cx, CTypesActivityType type);
 
 /*
  * Sets a callback that is run whenever js-ctypes is about to be used when
  * calling into C.
  */
 JS_FRIEND_API(void)
 SetCTypesActivityCallback(JSRuntime *rt, CTypesActivityCallback cb);
 
+class JS_FRIEND_API(AutoCTypesActivityCallback) {
+  private:
+    JSContext *cx;
+    CTypesActivityCallback callback;
+    CTypesActivityType beginType;
+    CTypesActivityType endType;
+    MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
+
+  public:
+    AutoCTypesActivityCallback(JSContext *cx, CTypesActivityType beginType,
+                               CTypesActivityType endType
+                               MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
+    ~AutoCTypesActivityCallback() {
+        DoEndCallback();
+    }
+    void DoEndCallback() {
+        if (callback) {
+            callback(cx, endType);
+            callback = NULL;
+        }
+    }
+};
+
 } /* namespace js */
 
 #endif /* jsfriendapi_h___ */