[gjs/wip/ptomato/mozjs31: 2/3] js: Destroy runtime when last context is destroyed



commit 8bd1e455ee94763cadb0a5a0724beedfe83ba7f9
Author: Philip Chimento <philip endlessm com>
Date:   Tue Nov 8 16:35:37 2016 -0800

    js: Destroy runtime when last context is destroyed
    
    If you call JS_ShutDown() with a runtime still in existence, then
    SpiderMonkey will shout at you. No kidding, the error message really says
    "FIX THIS!"
    
    This adds refcounting to the per-thread runtime, so that if no
    GjsContexts are referencing it anymore, then it is destroyed.
    
    Note that in later SpiderMonkey versions there is only going to be one
    JSContext per JSRuntime allowed, and in an as-yet unreleased version the
    two are to be merged altogether.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=751252

 gjs/context.cpp |    6 ++++--
 gjs/runtime.cpp |   39 +++++++++++++++++++++++++++++++++++++--
 gjs/runtime.h   |    5 ++++-
 3 files changed, 45 insertions(+), 5 deletions(-)
---
diff --git a/gjs/context.cpp b/gjs/context.cpp
index 2805d03..9f5e84f 100644
--- a/gjs/context.cpp
+++ b/gjs/context.cpp
@@ -371,7 +371,7 @@ gjs_context_dispose(GObject *object)
         /* Tear down JS */
         JS_DestroyContext(js_context->context);
         js_context->context = NULL;
-        js_context->runtime = NULL;
+        g_clear_pointer(&js_context->runtime, gjs_runtime_unref);
     }
 
     G_OBJECT_CLASS(gjs_context_parent_class)->dispose(object);
@@ -420,7 +420,7 @@ gjs_context_constructed(GObject *object)
 
     G_OBJECT_CLASS(gjs_context_parent_class)->constructed(object);
 
-    js_context->runtime = gjs_runtime_for_current_thread();
+    js_context->runtime = gjs_runtime_ref();
 
     js_context->context = JS_NewContext(js_context->runtime, 8192 /* stack chunk size */);
     if (js_context->context == NULL)
@@ -846,5 +846,7 @@ gjs_init(void)
 void
 gjs_shutdown(void)
 {
+    /* No-op if the runtime was already destroyed */
+    gjs_destroy_runtime_for_current_thread();
     JS_ShutDown();
 }
diff --git a/gjs/runtime.cpp b/gjs/runtime.cpp
index 6fd9467..6336e4f 100644
--- a/gjs/runtime.cpp
+++ b/gjs/runtime.cpp
@@ -28,6 +28,7 @@
 #include "runtime.h"
 
 struct RuntimeData {
+  unsigned refcount;
   bool in_gc_sweep;
 };
 
@@ -151,8 +152,8 @@ destroy_runtime(gpointer data)
     JSRuntime *runtime = (JSRuntime *) data;
     RuntimeData *rtdata = (RuntimeData *) JS_GetRuntimePrivate(runtime);
 
-    g_free(rtdata);
     JS_DestroyRuntime(runtime);
+    g_free(rtdata);
 }
 
 static GPrivate thread_runtime = G_PRIVATE_INIT(destroy_runtime);
@@ -222,7 +223,7 @@ gjs_finalize_callback(JSFreeOp         *fop,
     data->in_gc_sweep = false;
 }
 
-JSRuntime *
+static JSRuntime *
 gjs_runtime_for_current_thread(void)
 {
     JSRuntime *runtime = (JSRuntime *) g_private_get(&thread_runtime);
@@ -246,3 +247,37 @@ gjs_runtime_for_current_thread(void)
 
     return runtime;
 }
+
+/* These two act on the current thread's runtime. In the future they will go
+ * away because SpiderMonkey is going to merge JSContext and JSRuntime.
+ */
+
+/* Creates a new runtime with one reference if there is no runtime yet */
+JSRuntime *
+gjs_runtime_ref(void)
+{
+    JSRuntime *rt = static_cast<JSRuntime *>(gjs_runtime_for_current_thread());
+    RuntimeData *data = static_cast<RuntimeData *>(JS_GetRuntimePrivate(rt));
+    g_atomic_int_inc(&data->refcount);
+    return rt;
+}
+
+/* No-op if there is no runtime */
+void
+gjs_runtime_unref(void)
+{
+    JSRuntime *rt = static_cast<JSRuntime *>(g_private_get(&thread_runtime));
+    if (rt == NULL)
+        return;
+    RuntimeData *data = static_cast<RuntimeData *>(JS_GetRuntimePrivate(rt));
+    if (g_atomic_int_dec_and_test(&data->refcount))
+        gjs_destroy_runtime_for_current_thread();
+}
+
+/* Destroys the current thread's runtime regardless of refcount. No-op if there
+ * is no runtime */
+void
+gjs_destroy_runtime_for_current_thread(void)
+{
+    g_private_replace(&thread_runtime, NULL);
+}
diff --git a/gjs/runtime.h b/gjs/runtime.h
index 0900e28..1946518 100644
--- a/gjs/runtime.h
+++ b/gjs/runtime.h
@@ -26,7 +26,10 @@
 
 #include <stdbool.h>
 
-JSRuntime * gjs_runtime_for_current_thread (void);
+JSRuntime *gjs_runtime_ref(void);
+void gjs_runtime_unref(void);
+
+void gjs_destroy_runtime_for_current_thread(void);
 
 bool        gjs_runtime_is_sweeping        (JSRuntime *runtime);
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]