[gjs] Add support for write barriers to classes with a custom trace
- From: Philip Chimento <pchimento src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gjs] Add support for write barriers to classes with a custom trace
- Date: Sat, 14 Jan 2017 06:22:16 +0000 (UTC)
commit ad5e1596521880bb7d9bef8b12c03521f3cf222b
Author: Giovanni Campagna <gcampagna src gnome org>
Date: Tue Feb 18 03:16:38 2014 +0100
Add support for write barriers to classes with a custom trace
To support write barriers (which are a prerequisite for incremental
GC), all manually traced pointers to GC things need to be converted
to JS::Heap<T>, and their holders made into C++ objects with
constructors and destructors.
https://bugzilla.gnome.org/show_bug.cgi?id=724797
gi/closure.cpp | 81 +++++++++++++++++++++++++++++++++++-----------------
gi/keep-alive.cpp | 16 ++++++----
2 files changed, 63 insertions(+), 34 deletions(-)
---
diff --git a/gi/closure.cpp b/gi/closure.cpp
index cdae2d2..3747296 100644
--- a/gi/closure.cpp
+++ b/gi/closure.cpp
@@ -32,13 +32,20 @@
#include "gjs/mem.h"
#include "keep-alive.h"
-typedef struct {
- GClosure base;
+struct Closure {
JSRuntime *runtime;
JSContext *context;
JS::Heap<JSObject *> obj;
guint unref_on_global_object_finalized : 1;
-} Closure;
+};
+
+struct GjsClosure {
+ GClosure base;
+
+ /* We need a separate object to be able to call
+ the C++ constructor without stomping on the base */
+ Closure priv;
+};
/*
* Memory management of closures is "interesting" because we're keeping around
@@ -75,8 +82,12 @@ typedef struct {
*/
static void
-invalidate_js_pointers(Closure *c)
+invalidate_js_pointers(GjsClosure *gc)
{
+ Closure *c;
+
+ c = &gc->priv;
+
if (c->obj == NULL)
return;
@@ -87,17 +98,18 @@ invalidate_js_pointers(Closure *c)
/* Notify any closure reference holders they
* may want to drop references.
*/
- g_closure_invalidate(&c->base);
+ g_closure_invalidate(&gc->base);
}
static void
global_context_finalized(JSObject *obj,
void *data)
{
+ GjsClosure *gc = (GjsClosure*) data;
Closure *c;
bool need_unref;
- c = (Closure *) data;
+ c = &gc->priv;
gjs_debug_closure("Context global object destroy notifier on closure %p "
"which calls object %p",
@@ -112,17 +124,18 @@ global_context_finalized(JSObject *obj,
if (c->obj != NULL) {
g_assert(c->obj == obj);
- invalidate_js_pointers(c);
+ invalidate_js_pointers(gc);
}
if (need_unref) {
- g_closure_unref(&c->base);
+ g_closure_unref(&gc->base);
}
}
static void
-check_context_valid(Closure *c)
+check_context_valid(GjsClosure *gc)
{
+ Closure *c = &gc->priv;
JSContext *a_context;
JSContext *iter;
@@ -142,7 +155,7 @@ check_context_valid(Closure *c)
c->context, c, c->obj);
/* Did not find the context. */
- invalidate_js_pointers(c);
+ invalidate_js_pointers(gc);
}
/* Invalidation is like "dispose" - it is guaranteed to happen at
@@ -162,7 +175,7 @@ closure_invalidated(gpointer data,
{
Closure *c;
- c = (Closure*) closure;
+ c = &((GjsClosure*) closure)->priv;
GJS_DEC_COUNTER(closure);
gjs_debug_closure("Invalidating closure %p which calls object %p",
@@ -176,7 +189,7 @@ closure_invalidated(gpointer data,
/* this will set c->obj to null if the context is dead
*/
- check_context_valid(c);
+ check_context_valid((GjsClosure*)closure);
if (c->obj == NULL) {
/* Context is dead here. This happens if, as a side effect of
@@ -208,7 +221,7 @@ closure_invalidated(gpointer data,
closure);
c->unref_on_global_object_finalized = true;
- g_closure_ref(&c->base);
+ g_closure_ref(closure);
} else {
/* If the context still exists, then remove our destroy
* notifier. Otherwise we would call the destroy notifier on
@@ -224,7 +237,7 @@ closure_invalidated(gpointer data,
gjs_keep_alive_remove_global_child(c->context,
global_context_finalized,
c->obj,
- c);
+ closure);
c->obj = NULL;
c->context = NULL;
@@ -236,7 +249,7 @@ static void
closure_set_invalid(gpointer data,
GClosure *closure)
{
- Closure *self = (Closure*) closure;
+ Closure *self = &((GjsClosure*) closure)->priv;
self->obj = NULL;
self->context = NULL;
@@ -245,6 +258,15 @@ closure_set_invalid(gpointer data,
GJS_DEC_COUNTER(closure);
}
+static void
+closure_finalize(gpointer data,
+ GClosure *closure)
+{
+ Closure *self = &((GjsClosure*) closure)->priv;
+
+ self->~Closure();
+}
+
void
gjs_closure_invoke(GClosure *closure,
const JS::HandleValueArray& args,
@@ -253,9 +275,9 @@ gjs_closure_invoke(GClosure *closure,
Closure *c;
JSContext *context;
- c = (Closure*) closure;
+ c = &((GjsClosure*) closure)->priv;
- check_context_valid(c);
+ check_context_valid((GjsClosure*)closure);
if (c->obj == NULL) {
/* We were destroyed; become a no-op */
@@ -302,7 +324,7 @@ gjs_closure_is_valid(GClosure *closure)
{
Closure *c;
- c = (Closure*) closure;
+ c = &((GjsClosure*) closure)->priv;
return c->context != NULL;
}
@@ -312,7 +334,7 @@ gjs_closure_get_context(GClosure *closure)
{
Closure *c;
- c = (Closure*) closure;
+ c = &((GjsClosure*) closure)->priv;
return c->context;
}
@@ -322,7 +344,7 @@ gjs_closure_get_callable(GClosure *closure)
{
Closure *c;
- c = (Closure*) closure;
+ c = &((GjsClosure*) closure)->priv;
return c->obj;
}
@@ -333,7 +355,7 @@ gjs_closure_trace(GClosure *closure,
{
Closure *c;
- c = (Closure*) closure;
+ c = &((GjsClosure*) closure)->priv;
if (c->obj == NULL)
return;
@@ -347,9 +369,12 @@ gjs_closure_new(JSContext *context,
const char *description,
bool root_function)
{
+ GjsClosure *gc;
Closure *c;
- c = (Closure*) g_closure_new_simple(sizeof(Closure), NULL);
+ gc = (GjsClosure*) g_closure_new_simple(sizeof(GjsClosure), NULL);
+ c = new (&gc->priv) Closure();
+
c->runtime = JS_GetRuntime(context);
/* The saved context is used for lifetime management, so that the closure will
* be torn down with the context that created it. The context could be attached to
@@ -369,19 +394,21 @@ gjs_closure_new(JSContext *context,
gjs_keep_alive_add_global_child(context,
global_context_finalized,
c->obj,
- c);
+ gc);
- g_closure_add_invalidate_notifier(&c->base, NULL, closure_invalidated);
+ g_closure_add_invalidate_notifier(&gc->base, NULL, closure_invalidated);
} else {
/* Only mark the closure as invalid if memory is managed
outside (i.e. by object.c for signals) */
- g_closure_add_invalidate_notifier(&c->base, NULL, closure_set_invalid);
+ g_closure_add_invalidate_notifier(&gc->base, NULL, closure_set_invalid);
}
+ g_closure_add_finalize_notifier(&gc->base, NULL, closure_finalize);
+
gjs_debug_closure("Create closure %p which calls object %p '%s'",
- c, c->obj, description);
+ gc, c->obj, description);
JS_EndRequest(context);
- return &c->base;
+ return &gc->base;
}
diff --git a/gi/keep-alive.cpp b/gi/keep-alive.cpp
index 4060935..df11e5a 100644
--- a/gi/keep-alive.cpp
+++ b/gi/keep-alive.cpp
@@ -29,11 +29,12 @@
#include <util/log.h>
#include <util/glib.h>
-typedef struct {
+struct Child {
+ JS::Heap<JSObject*> child;
+
GjsUnrootedFunc notify;
- JSObject *child;
void *data;
-} Child;
+};
typedef struct {
GHashTable *children;
@@ -52,7 +53,7 @@ child_hash(gconstpointer v)
return
GPOINTER_TO_UINT(child->notify) ^
- GPOINTER_TO_UINT(child->child) ^
+ GPOINTER_TO_UINT(child->child.get()) ^
GPOINTER_TO_UINT(child->data);
}
@@ -73,6 +74,8 @@ static void
child_free(void *data)
{
Child *child = (Child *) data;
+
+ child->~Child();
g_slice_free(Child, child);
}
@@ -118,9 +121,7 @@ trace_foreach(void *key,
JSTracer *tracer = (JSTracer *) data;
if (child->child != NULL) {
- JS::Value val;
- val = JS::ObjectValue(*(child->child));
- JS_CallValueTracer(tracer, &val, "keep-alive::val");
+ JS_CallHeapObjectTracer(tracer, &child->child, "keep-alive::val");
}
}
@@ -270,6 +271,7 @@ gjs_keep_alive_add_child(JSObject *keep_alive,
g_return_if_fail(!priv->inside_finalize);
child = g_slice_new0(Child);
+ child = new (child) Child();
child->notify = notify;
child->child = obj;
child->data = data;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]