[gjs/mozjs31] js: Destroy runtime when last context is destroyed



commit 6348d8fcddd163c5554b1f64982325ea6602afab
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 |    4 ++--
 gjs/runtime.cpp |   41 +++++++++++++++++++++++++++++++++++++++--
 gjs/runtime.h   |    3 ++-
 3 files changed, 43 insertions(+), 5 deletions(-)
---
diff --git a/gjs/context.cpp b/gjs/context.cpp
index c3edd89..60a03da 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)
diff --git a/gjs/runtime.cpp b/gjs/runtime.cpp
index 5619e89..816dbce 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,6 +223,14 @@ gjs_finalize_callback(JSFreeOp         *fop,
     data->in_gc_sweep = false;
 }
 
+/* Destroys the current thread's runtime regardless of refcount. No-op if there
+ * is no runtime */
+static void
+gjs_destroy_runtime_for_current_thread(void)
+{
+    g_private_replace(&thread_runtime, NULL);
+}
+
 class GjsInit {
 public:
     GjsInit() {
@@ -230,6 +239,8 @@ public:
     }
 
     ~GjsInit() {
+        /* No-op if the runtime was already destroyed */
+        gjs_destroy_runtime_for_current_thread();
         JS_ShutDown();
     }
 
@@ -240,7 +251,7 @@ public:
 
 static GjsInit gjs_is_inited;
 
-JSRuntime *
+static JSRuntime *
 gjs_runtime_for_current_thread(void)
 {
     JSRuntime *runtime = (JSRuntime *) g_private_get(&thread_runtime);
@@ -265,3 +276,29 @@ 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();
+}
diff --git a/gjs/runtime.h b/gjs/runtime.h
index 0900e28..18285b6 100644
--- a/gjs/runtime.h
+++ b/gjs/runtime.h
@@ -26,7 +26,8 @@
 
 #include <stdbool.h>
 
-JSRuntime * gjs_runtime_for_current_thread (void);
+JSRuntime *gjs_runtime_ref(void);
+void gjs_runtime_unref(void);
 
 bool        gjs_runtime_is_sweeping        (JSRuntime *runtime);
 


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