[gjs] Use JS_SetRuntimePrivate() rather than GDataset for runtime data



commit e979fe2f218232e2f671e4b7af8498ac80a6e100
Author: Owen W. Taylor <otaylor fishsoup net>
Date:   Wed Sep 29 18:42:17 2010 -0400

    Use JS_SetRuntimePrivate() rather than GDataset for runtime data
    
    GDataset is slow - it requires thread locking and hash table lookups.
    Since we don't support foreign JSRuntimes at the moment we can use
    JS_SetRuntimePrivate() which will have better performance.
    
    The public API functions gjs_runtime_get/set_data() are removed; if
    they were being used outside of GJS the users will have to track their
    data themselves.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=630964

 gjs/context.c    |   20 +++---------
 gjs/jsapi-util.c |   86 +++++++++++++++++++++++++++++++++++++----------------
 gjs/jsapi-util.h |    9 ++----
 3 files changed, 68 insertions(+), 47 deletions(-)
---
diff --git a/gjs/context.c b/gjs/context.c
index 4079f6f..7c0363e 100644
--- a/gjs/context.c
+++ b/gjs/context.c
@@ -354,22 +354,11 @@ gjs_context_dispose(GObject *object)
 
     if (js_context->runtime != NULL) {
         if (js_context->we_own_runtime) {
-            gjs_debug(GJS_DEBUG_CONTEXT,
-                      "Destroying JS runtime");
-
-            JS_DestroyRuntime(js_context->runtime);
-
-            /* finalize the dataset from jsapi-util.c ...  for
-             * "foreign" runtimes this just never happens for
-             * now... we do this after the runtime itself is destroyed
-             * because we might have finalizers run by
-             * JS_DestroyRuntime() that rely on data we've set on the
-             * runtime, such as the dynamic class structs.
+            /* Cleans up data as well as destroying the runtime. Foreign
+             * contexts aren't supported at the moment; if we supported
+             * them, then the data simply would't get cleaned up.
              */
-            gjs_debug(GJS_DEBUG_CONTEXT,
-                      "Destroying any remaining dataset items on runtime");
-
-            g_dataset_destroy(js_context->runtime);
+            gjs_runtime_destroy(js_context->runtime);
         }
         js_context->runtime = NULL;
     }
@@ -533,6 +522,7 @@ gjs_context_constructor (GType                  type,
             gjs_fatal("Failed to create javascript runtime");
         JS_SetGCParameter(js_context->runtime, JSGC_MAX_BYTES, 0xffffffff);
         js_context->we_own_runtime = TRUE;
+        gjs_runtime_init(js_context->runtime);
     }
 
     js_context->context = JS_NewContext(js_context->runtime, 8192 /* stack chunk size */);
diff --git a/gjs/jsapi-util.c b/gjs/jsapi-util.c
index 6a3a138..0c55ed6 100644
--- a/gjs/jsapi-util.c
+++ b/gjs/jsapi-util.c
@@ -65,22 +65,6 @@ typedef struct {
 static RuntimeData* get_data_from_runtime(JSRuntime *runtime);
 static RuntimeData* get_data_from_context(JSContext *context);
 
-void*
-gjs_runtime_get_data(JSRuntime      *runtime,
-                     const char     *name)
-{
-    return g_dataset_get_data(runtime, name);
-}
-
-void
-gjs_runtime_set_data(JSRuntime      *runtime,
-                     const char     *name,
-                     void           *data,
-                     GDestroyNotify  dnotify)
-{
-    g_dataset_set_data_full(runtime, name, data, dnotify);
-}
-
 /**
  * gjs_get_import_global:
  * @context: a #JSContext
@@ -285,13 +269,67 @@ gjs_init_context_standard (JSContext       *context)
     return TRUE;
 }
 
-static void
-runtime_data_destroy_notify(void *data)
+/**
+ * gjs_runtime_init:
+ * @runtime: a #JSRuntime
+ *
+ * Initializes a #JSRuntime for use with GJS
+ *
+ * This should only be called by GJS, not by applications.
+ */
+void
+gjs_runtime_init(JSRuntime *runtime)
 {
-    RuntimeData *rd = data;
+    RuntimeData *rd;
+
+    /* If we went back to supporting foreign contexts, we couldn't use
+     * JS_SetRuntimePrivate() because the runtime's owner might
+     * already be using it. A simple solution would be to just store
+     * the runtime data in a global variable - multiple copies of GJS
+     * in the same process at the same time have issues anyways
+     * because of limitations of GObject toggle references - if two
+     * separate entities toggle reference an object it will leak.
+     */
+    if (JS_GetRuntimePrivate(runtime) != NULL)
+        gjs_fatal("JSRuntime already initialized or private data in use by someone else");
+
+    rd = g_slice_new0(RuntimeData);
+    rd->dynamic_classes = g_hash_table_new(g_direct_hash, g_direct_equal);
+    JS_SetRuntimePrivate(runtime, rd);
+}
+
+/**
+ * gjs_runtime_destroy:
+ * @runtime: a #JSRuntime
+ *
+ * Calls JS_DestroyRuntime() on runtime and frees data allocated by
+ * gjs_runtime_init(); these are unified into a single call because we
+ * need to order things so that the allocated data is cleaned up
+ * after JS_DestroyRuntime(). We might have finalizers run by
+ * JS_DestroyRuntime() that rely on the information stored in the data,
+ * such as the dynamic class structs.
+ *
+ * This should only be called by GJS, not by applications.
+ */
+void
+gjs_runtime_destroy(JSRuntime *runtime)
+{
+    RuntimeData *rd;
     void *key;
     void *value;
 
+    rd = JS_GetRuntimePrivate(runtime);
+    if (rd->context_stack != NULL || rd->current_frame.depth != 0)
+        gjs_fatal("gjs_runtime_destroy() called during gjs_push_context()");
+
+    gjs_debug(GJS_DEBUG_CONTEXT,
+              "Destroying JS runtime");
+
+    JS_DestroyRuntime(runtime);
+
+    gjs_debug(GJS_DEBUG_CONTEXT,
+              "Destroying any remaining dataset items on runtime");
+
     while (gjs_g_hash_table_remove_one(rd->dynamic_classes, &key, &value)) {
         JSClass *clasp = value;
 
@@ -312,13 +350,9 @@ get_data_from_runtime(JSRuntime *runtime)
 {
     RuntimeData *rd;
 
-    rd = gjs_runtime_get_data(runtime, "gjs-api-util-data");
-    if (rd == NULL) {
-        rd = g_slice_new0(RuntimeData);
-        rd->dynamic_classes = g_hash_table_new(g_direct_hash, g_direct_equal);
-        gjs_runtime_set_data(runtime, "gjs-api-util-data",
-                             rd, runtime_data_destroy_notify);
-    }
+    rd = JS_GetRuntimePrivate(runtime);
+    if (G_UNLIKELY(rd == NULL))
+        gjs_fatal("JSRuntime not initialized for use with GJS");
 
     return rd;
 }
diff --git a/gjs/jsapi-util.h b/gjs/jsapi-util.h
index f94e010..173c8b7 100644
--- a/gjs/jsapi-util.h
+++ b/gjs/jsapi-util.h
@@ -193,12 +193,9 @@ jsval cname##_create_proto(JSContext *context, JSObject *module, const char *pro
 
 gboolean    gjs_init_context_standard        (JSContext       *context);
 
-void*       gjs_runtime_get_data             (JSRuntime       *runtime,
-                                                 const char      *name);
-void        gjs_runtime_set_data             (JSRuntime       *runtime,
-                                                 const char      *name,
-                                                 void            *data,
-                                                 GDestroyNotify   dnotify);
+void        gjs_runtime_init                 (JSRuntime       *runtime);
+void        gjs_runtime_destroy              (JSRuntime       *runtime);
+
 JSContext*  gjs_runtime_get_current_context  (JSRuntime       *runtime);
 void        gjs_runtime_set_default_context  (JSRuntime       *runtime,
                                               JSContext       *context);



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