예제 #1
0
파일: closure.cpp 프로젝트: smspillaz/gjs
void
gjs_closure_invoke(GClosure *closure,
                   int       argc,
                   jsval    *argv,
                   jsval    *retval)
{
    Closure *c;
    JSContext *context;
    JSObject *global;

    c = (Closure*) closure;

    check_context_valid(c);

    if (c->obj == NULL) {
        /* We were destroyed; become a no-op */
        c->context = NULL;
        return;
    }

    context = gjs_runtime_get_context(c->runtime);
    JS_BeginRequest(context);
    global = JS_GetGlobalObject(context);
    JSAutoCompartment ac(context, global);

    if (JS_IsExceptionPending(context)) {
        gjs_debug_closure("Exception was pending before invoking callback??? "
                          "Not expected");
        gjs_log_exception(context);
    }

    if (!gjs_call_function_value(context,
                                 NULL, /* "this" object; NULL is some kind of default presumably */
                                 OBJECT_TO_JSVAL(c->obj),
                                 argc,
                                 argv,
                                 retval)) {
        /* Exception thrown... */
        gjs_debug_closure("Closure invocation failed (exception should "
                          "have been thrown) closure %p callable %p",
                          closure, c->obj);
        if (!gjs_log_exception(context))
            gjs_debug_closure("Closure invocation failed but no exception was set?");
        goto out;
    }

    if (gjs_log_exception(context)) {
        gjs_debug_closure("Closure invocation succeeded but an exception was set");
    }

 out:
    JS_EndRequest(context);
}
예제 #2
0
파일: closure.cpp 프로젝트: smspillaz/gjs
static void
global_context_finalized(JSObject *obj,
                         void     *data)
{
    Closure *c;
    gboolean need_unref;

    c = (Closure *) data;

    gjs_debug_closure("Context global object destroy notifier on closure %p "
                      "which calls object %p",
                      c, c->obj);

    /* invalidate_js_pointers() could free us so check flag now to avoid
     * invalid memory access
     */
    need_unref = c->unref_on_global_object_finalized;
    c->unref_on_global_object_finalized = FALSE;

    if (c->obj != NULL) {
        g_assert(c->obj == obj);

        invalidate_js_pointers(c);
    }

    if (need_unref) {
        g_closure_unref(&c->base);
    }
}
예제 #3
0
파일: closure.c 프로젝트: darkxst/gjs-js188
GClosure*
gjs_closure_new(JSContext  *context,
                JSObject   *callable,
                const char *description,
                gboolean    root_function)
{
    Closure *c;

    c = (Closure*) g_closure_new_simple(sizeof(Closure), NULL);
    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
     * the default context of the runtime using if we wanted the closure to survive
     * the context that created it.
     */
    c->context = context;
    JS_BeginRequest(context);

    c->obj = callable;
    c->unref_on_global_object_finalized = FALSE;

    GJS_INC_COUNTER(closure);
    /* the finalize notifier right now is purely to track the counter
     * of how many closures are alive.
     */
    g_closure_add_finalize_notifier(&c->base, NULL, closure_finalized);

    if (root_function) {
        /* Fully manage closure lifetime if so asked */
        gjs_keep_alive_add_global_child(context,
                                        global_context_finalized,
                                        c->obj,
                                        c);

        g_closure_add_invalidate_notifier(&c->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);
    }

    gjs_debug_closure("Create closure %p which calls object %p '%s'",
                      c, c->obj, description);

    JS_EndRequest(context);

    return &c->base;
}
예제 #4
0
파일: closure.cpp 프로젝트: smspillaz/gjs
static void
check_context_valid(Closure *c)
{
    JSContext *a_context;
    JSContext *iter;

    if (c->runtime == NULL)
        return;

    iter = NULL;
    while ((a_context = JS_ContextIterator(c->runtime,
                                           &iter)) != NULL) {
        if (a_context == c->context) {
            return;
        }
    }

    gjs_debug_closure("Context %p no longer exists, invalidating "
                      "closure %p which calls object %p",
                      c->context, c, c->obj);

    /* Did not find the context. */
    invalidate_js_pointers(c);
}
예제 #5
0
파일: closure.cpp 프로젝트: smspillaz/gjs
/* Invalidation is like "dispose" - it is guaranteed to happen at
 * finalize, but may happen before finalize. Normally, g_closure_invalidate()
 * is called when the "target" of the closure becomes invalid, so that the
 * source (the signal connection, say can be removed.) The usage above
 * in invalidate_js_pointers() is typical. Since the target of the closure
 * is under our control, it's unlikely that g_closure_invalidate() will ever
 * be called by anyone else, but in case it ever does, it's slightly better
 * to remove the "keep alive" here rather than in the finalize notifier.
 *
 * Unlike "dispose" invalidation only happens once.
 */
static void
closure_invalidated(gpointer data,
                    GClosure *closure)
{
    Closure *c;

    c = (Closure*) closure;

    GJS_DEC_COUNTER(closure);
    gjs_debug_closure("Invalidating closure %p which calls object %p",
                      closure, c->obj);

    if (c->obj == NULL) {
        gjs_debug_closure("   (closure %p already dead, nothing to do)",
                          closure);
        return;
    }

    /* this will set c->obj to null if the context is dead
     */
    check_context_valid(c);

    if (c->obj == NULL) {
        /* Context is dead here. This happens if, as a side effect of
         * tearing down the context, the closure was invalidated,
         * say be some other finalized object that had a ref to
         * the closure dropping said ref.
         *
         * Because c->obj was not NULL at the start of
         * closure_invalidated, we know that
         * global_context_finalized() has not been called.  So we know
         * we are not being invalidated from inside
         * global_context_finalized().
         *
         * That means global_context_finalized() has yet to be called,
         * but we know it will be called, because the context is dead
         * and thus its global object should be finalized.
         *
         * We can't call gjs_keep_alive_remove_global_child() because
         * the context is invalid memory and we can't get to the
         * global object that stores the keep alive.
         *
         * So global_context_finalized() could be called on an
         * already-finalized closure. To avoid this, we temporarily
         * ref ourselves, and set a flag to remove this ref
         * in global_context_finalized().
         */
        gjs_debug_closure("   (closure %p's context was dead, holding ref "
                          "until global object finalize)",
                          closure);

        c->unref_on_global_object_finalized = TRUE;
        g_closure_ref(&c->base);
    } else {
        /* If the context still exists, then remove our destroy
         * notifier.  Otherwise we would call the destroy notifier on
         * an already-freed closure.
         *
         * This happens in the normal case, when the closure is
         * invalidated for some reason other than destruction of the
         * JSContext.
         */
        gjs_debug_closure("   (closure %p's context was alive, "
                          "removing our destroy notifier on global object)",
                          closure);
        gjs_keep_alive_remove_global_child(c->context,
                                           global_context_finalized,
                                           c->obj,
                                           c);

        c->obj = NULL;
        c->context = NULL;
        c->runtime = NULL;
    }
}