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 127025 c3008e662841c5e2f5c44caf8ba98d7efc2b3a82
parent 127024 8f8ceea47a265e7787230997bef25e0a5716915f
child 127026 776346e8fcda03657c400d16d3777d7be66ef083
push id2151
push userlsblakk@mozilla.com
push dateTue, 19 Feb 2013 18:06:57 +0000
treeherdermozilla-beta@4952e88741ec [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskhuey, jlebar
bugs827274
milestone20.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, 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___ */