Bug 827274 - 'crash in [@ anonymous namespace::CTypesActivityCallback(JSContext*, js::CTypesActivityType)], add ctypes closure support to new worker memory reporting mechanism. r=khuey+mrbkap, a=jlebar.
authorBen Turner <bent.mozilla@gmail.com>
Mon, 07 Jan 2013 17:34:08 +0100
changeset 118320 c3008e662841c5e2f5c44caf8ba98d7efc2b3a82
parent 118319 8f8ceea47a265e7787230997bef25e0a5716915f
child 118321 776346e8fcda03657c400d16d3777d7be66ef083
push id270
push userpvanderbeken@mozilla.com
push dateThu, 06 Mar 2014 09:24:21 +0000
reviewerskhuey, jlebar
bugs827274
milestone20.0a1
Bug 827274 - 'crash in [@ anonymous namespace::CTypesActivityCallback(JSContext*, js::CTypesActivityType)], add ctypes closure support to new worker memory reporting mechanism. r=khuey+mrbkap, a=jlebar.
dom/workers/RuntimeService.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)
 {
--- 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
@@ -1558,24 +1558,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 = nullptr;
+        }
+    }
+};
+
 } /* namespace js */
 
 #endif /* jsfriendapi_h___ */