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

Bug#694452: marked as done (unblock: gjs/1.32.0-5)



Your message dated Thu, 3 Jan 2013 09:56:58 +0100
with message-id <20130103085658.GQ5634@radis.cristau.org>
and subject line Re: Bug#694452: unblock: gjs/1.32.0-5
has caused the Debian Bug report #694452,
regarding unblock: gjs/1.32.0-5
to be marked as done.

This means that you claim that the problem has been dealt with.
If this is not the case it is now your responsibility to reopen the
Bug report if necessary, and/or fix the problem forthwith.

(NB: If you are a system administrator and have no idea what this
message is talking about, this may indicate a serious mail system
misconfiguration somewhere. Please contact owner@bugs.debian.org
immediately.)


-- 
694452: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=694452
Debian Bug Tracking System
Contact owner@bugs.debian.org with problems
--- Begin Message ---
Package: release.debian.org
Severity: normal
User: release.debian.org@packages.debian.org
Usertags: unblock

Please unblock package gjs for an API extension that is necessary for a 
RC bugfix in gnome-documents.

gjs (1.32.0-3) unstable; urgency=low

  * 02_gerror_class.patch, 03_gerror_details.patch: patches from 
    upstream git. Introduce a class to manage GError correctly.
    Closes: #691551.
  * Bump shblibs version since this extends the API.

Please require 15 days before testing migration since there is a small 
but existing possiblity of impact on gnome-shell and gnome-sushi.

unblock gjs/1.32.0-3

Thanks,
-- 
 .''`.      Josselin Mouette
: :' :
`. `'
  `-
Index: debian/control
===================================================================
Index: debian/changelog
===================================================================
Index: debian/patches/02_gerror_class.patch
===================================================================
--- debian/patches/02_gerror_class.patch	(révision 0)
+++ debian/patches/02_gerror_class.patch	(révision 36381)
@@ -0,0 +1,1227 @@
+From 2ab1b3f090edc4ac64075fb1a7f387e724ba63ff Mon Sep 17 00:00:00 2001
+From: Giovanni Campagna <gcampagna@src.gnome.org>
+Date: Fri, 02 Mar 2012 20:17:13 +0000
+Subject: Introduce special marshalling for GErrors
+
+Previously GErrors were transformed into plain Error with a custom
+message, which removed the code and domain metadata. This commit
+introduces a new class hierarchy (derived from GLib.Error) for each
+enumeration representing an error domain, and modifies existing
+code to throw instances of that when a function fails.
+
+https://bugzilla.gnome.org/show_bug.cgi?id=591480
+---
+Index: gjs-1.32.0/Makefile.am
+===================================================================
+--- gjs-1.32.0.orig/Makefile.am	2012-11-26 10:59:32.382177869 +0100
++++ gjs-1.32.0/Makefile.am	2012-11-26 10:59:33.526183462 +0100
+@@ -53,7 +53,8 @@ nobase_gjs_module_include_HEADERS =	\
+ 	gi/function.h	\
+ 	gi/keep-alive.h	\
+ 	gi/interface.h	\
+-	gi/gtype.h
++	gi/gtype.h	\
++	gi/gerror.h
+ 
+ noinst_HEADERS +=		\
+ 	gjs/jsapi-private.h	\
+@@ -137,7 +138,8 @@ libgjs_la_SOURCES += \
+ 	gi/union.c	\
+         gi/value.c	\
+ 	gi/interface.c	\
+-	gi/gtype.c
++	gi/gtype.c	\
++	gi/gerror.c
+ 
+ # Also, these files used to be a separate library
+ gdbus_wrapper_source_files = \
+Index: gjs-1.32.0/gi/arg.c
+===================================================================
+--- gjs-1.32.0.orig/gi/arg.c	2012-03-21 14:51:34.000000000 +0100
++++ gjs-1.32.0/gi/arg.c	2012-11-26 10:59:33.534183501 +0100
+@@ -31,6 +31,7 @@
+ #include "union.h"
+ #include "param.h"
+ #include "value.h"
++#include "gerror.h"
+ #include "gjs/byteArray.h"
+ #include <gjs/gjs-module.h>
+ #include <gjs/compat.h>
+@@ -1326,7 +1327,6 @@ gjs_value_to_g_argument(JSContext      *
+                     arg->v_pointer = NULL;
+                     wrong = TRUE;
+                 }
+-
+             } else if (JSVAL_IS_NULL(value) &&
+                        interface_type != GI_INFO_TYPE_ENUM &&
+                        interface_type != GI_INFO_TYPE_FLAGS) {
+@@ -1336,8 +1336,16 @@ gjs_value_to_g_argument(JSContext      *
+                 if ((interface_type == GI_INFO_TYPE_STRUCT || interface_type == GI_INFO_TYPE_BOXED) &&
+                     /* We special case Closures later, so skip them here */
+                     !g_type_is_a(gtype, G_TYPE_CLOSURE)) {
+-                    arg->v_pointer = gjs_c_struct_from_boxed(context,
+-                                                             JSVAL_TO_OBJECT(value));
++
++                    /* special case GError too */
++                    if (g_type_is_a(gtype, G_TYPE_ERROR)) {
++                        arg->v_pointer = gjs_gerror_from_error(context,
++                                                               JSVAL_TO_OBJECT(value));
++                    } else {
++                        arg->v_pointer = gjs_c_struct_from_boxed(context,
++                                                                 JSVAL_TO_OBJECT(value));
++                    }
++
+                     if (transfer != GI_TRANSFER_NOTHING) {
+                         if (g_type_is_a(gtype, G_TYPE_BOXED))
+                             arg->v_pointer = g_boxed_copy (gtype, arg->v_pointer);
+@@ -2367,6 +2375,20 @@ gjs_value_from_g_argument (JSContext  *c
+             return JS_TRUE;
+         }
+ 
++    case GI_TYPE_TAG_ERROR:
++        {
++            if (arg->v_pointer) {
++                JSObject *obj = gjs_error_from_gerror(context, arg->v_pointer);
++                if (obj) {
++                    *value_p = OBJECT_TO_JSVAL(obj);
++                    return JS_TRUE;
++                }
++
++                return JS_FALSE;
++            }
++            return JS_TRUE;
++        }
++
+     case GI_TYPE_TAG_INTERFACE:
+         {
+             jsval value;
+@@ -2426,13 +2448,24 @@ gjs_value_from_g_argument (JSContext  *c
+                               "gtype of INTERFACE is %s", g_type_name(gtype));
+ 
+ 
+-            /* Test GValue before Struct, or it will be handled as the latter */
++            /* Test GValue and GError before Struct, or it will be handled as the latter */
+             if (g_type_is_a(gtype, G_TYPE_VALUE)) {
+                 if (!gjs_value_from_g_value(context, &value, arg->v_pointer))
+                     value = JSVAL_VOID; /* Make sure error is flagged */
+ 
+                 goto out;
+             }
++            if (g_type_is_a(gtype, G_TYPE_ERROR)) {
++                JSObject *obj;
++
++                obj = gjs_error_from_gerror(context, arg->v_pointer);
++                if (obj)
++                    value = OBJECT_TO_JSVAL(obj);
++                else
++                    value = JSVAL_VOID;
++
++                goto out;
++            }
+ 
+             if (interface_type == GI_INFO_TYPE_STRUCT || interface_type == GI_INFO_TYPE_BOXED) {
+                 JSObject *obj;
+Index: gjs-1.32.0/gi/enumeration.c
+===================================================================
+--- gjs-1.32.0.orig/gi/enumeration.c	2012-02-02 22:40:43.000000000 +0100
++++ gjs-1.32.0/gi/enumeration.c	2012-11-26 10:59:33.534183501 +0100
+@@ -103,17 +103,50 @@ gjs_define_enum_value(JSContext    *cont
+ }
+ 
+ JSBool
++gjs_define_enum_values(JSContext    *context,
++                       JSObject     *in_object,
++                       GIEnumInfo   *info)
++{
++    GType gtype;
++    int i, n_values;
++    jsval value;
++
++    /* Fill in enum values first, so we don't define the enum itself until we're
++     * sure we can finish successfully.
++     */
++    n_values = g_enum_info_get_n_values(info);
++    for (i = 0; i < n_values; ++i) {
++        GIValueInfo *value_info = g_enum_info_get_value(info, i);
++        gboolean failed;
++
++        failed = !gjs_define_enum_value(context, in_object, value_info);
++
++        g_base_info_unref( (GIBaseInfo*) value_info);
++
++        if (failed) {
++            return JS_FALSE;
++        }
++    }
++
++    gtype = g_registered_type_info_get_g_type((GIRegisteredTypeInfo*)info);
++    value = OBJECT_TO_JSVAL(gjs_gtype_create_gtype_wrapper(context, gtype));
++    JS_DefineProperty(context, in_object, "$gtype", value,
++                      NULL, NULL, JSPROP_PERMANENT);
++
++    return JS_TRUE;
++}
++
++
++JSBool
+ gjs_define_enumeration(JSContext    *context,
+                        JSObject     *in_object,
+                        GIEnumInfo   *info,
+                        JSObject    **enumeration_p)
+ {
+     const char *enum_name;
+-    GType gtype;
+     JSObject *enum_obj;
+     jsval value;
+-    int i;
+-    int n_values;
++
+ 
+     /* An enumeration is simply an object containing integer attributes for
+      * each enum value. It does not have a special JSClass.
+@@ -150,27 +183,8 @@ gjs_define_enumeration(JSContext    *con
+     JS_SetParent(context, enum_obj,
+                  gjs_get_import_global (context));
+ 
+-    /* Fill in enum values first, so we don't define the enum itself until we're
+-     * sure we can finish successfully.
+-     */
+-    n_values = g_enum_info_get_n_values(info);
+-    for (i = 0; i < n_values; ++i) {
+-        GIValueInfo *value_info = g_enum_info_get_value(info, i);
+-        gboolean failed;
+-
+-        failed = !gjs_define_enum_value(context, enum_obj, value_info);
+-
+-        g_base_info_unref( (GIBaseInfo*) value_info);
+-
+-        if (failed) {
+-            return JS_FALSE;
+-        }
+-    }
+-
+-    gtype = g_registered_type_info_get_g_type((GIRegisteredTypeInfo*)info);
+-    value = OBJECT_TO_JSVAL(gjs_gtype_create_gtype_wrapper(context, gtype));
+-    JS_DefineProperty(context, enum_obj, "$gtype", value,
+-                      NULL, NULL, JSPROP_PERMANENT);
++    if (!gjs_define_enum_values(context, enum_obj, info))
++        return JS_FALSE;
+ 
+     gjs_debug(GJS_DEBUG_GENUM,
+               "Defining %s.%s as %p",
+Index: gjs-1.32.0/gi/enumeration.h
+===================================================================
+--- gjs-1.32.0.orig/gi/enumeration.h	2011-06-10 00:31:56.000000000 +0200
++++ gjs-1.32.0/gi/enumeration.h	2012-11-26 10:59:33.534183501 +0100
+@@ -32,6 +32,9 @@
+ 
+ G_BEGIN_DECLS
+ 
++JSBool    gjs_define_enum_values       (JSContext    *context,
++                                        JSObject     *in_object,
++                                        GIEnumInfo   *info);
+ JSBool    gjs_define_enumeration       (JSContext    *context,
+                                         JSObject     *in_object,
+                                         GIEnumInfo   *info,
+Index: gjs-1.32.0/gi/function.c
+===================================================================
+--- gjs-1.32.0.orig/gi/function.c	2012-03-14 21:31:30.000000000 +0100
++++ gjs-1.32.0/gi/function.c	2012-11-26 10:59:33.538183526 +0100
+@@ -28,6 +28,7 @@
+ #include "object.h"
+ #include "boxed.h"
+ #include "union.h"
++#include "gerror.h"
+ #include <gjs/gjs-module.h>
+ #include <gjs/compat.h>
+ 
+@@ -674,7 +675,13 @@ gjs_invoke_c_function(JSContext      *co
+         g_assert_cmpuint(0, <, c_argc);
+ 
+         if (type == GI_INFO_TYPE_STRUCT || type == GI_INFO_TYPE_BOXED) {
+-            in_arg_cvalues[0].v_pointer = gjs_c_struct_from_boxed(context, obj);
++            GType gtype = g_registered_type_info_get_g_type ((GIRegisteredTypeInfo *)container);
++
++            /* GError must be special cased */
++            if (g_type_is_a(gtype, G_TYPE_ERROR))
++                in_arg_cvalues[0].v_pointer = gjs_gerror_from_error(context, obj);
++            else
++                in_arg_cvalues[0].v_pointer = gjs_c_struct_from_boxed(context, obj);
+         } else if (type == GI_INFO_TYPE_UNION) {
+             in_arg_cvalues[0].v_pointer = gjs_c_union_from_union(context, obj);
+         } else { /* by fallback is always object */
+@@ -1208,11 +1215,7 @@ release:
+     }
+ 
+     if (!failed && did_throw_gerror) {
+-        gjs_throw(context, "Error invoking %s.%s: %s",
+-                  g_base_info_get_namespace( (GIBaseInfo*) function->info),
+-                  g_base_info_get_name( (GIBaseInfo*) function->info),
+-                  local_error->message);
+-        g_error_free(local_error);
++        gjs_throw_g_error(context, local_error);
+         return JS_FALSE;
+     } else if (failed) {
+         return JS_FALSE;
+Index: gjs-1.32.0/gi/gerror.c
+===================================================================
+--- /dev/null	1970-01-01 00:00:00.000000000 +0000
++++ gjs-1.32.0/gi/gerror.c	2012-11-26 10:59:33.538183526 +0100
+@@ -0,0 +1,589 @@
++/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
++/*
++ * Copyright (c) 2008  litl, LLC
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this software and associated documentation files (the "Software"), to
++ * deal in the Software without restriction, including without limitation the
++ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
++ * sell copies of the Software, and to permit persons to whom the Software is
++ * furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
++ * IN THE SOFTWARE.
++ */
++
++#include <config.h>
++
++#include <string.h>
++
++#include <gjs/gjs-module.h>
++#include <gjs/compat.h>
++#include "boxed.h"
++#include "enumeration.h"
++#include "repo.h"
++#include "gerror.h"
++
++#include <util/log.h>
++
++#include <jsapi.h>
++
++#include <girepository.h>
++
++typedef struct {
++    GIEnumInfo *info;
++    GQuark domain;
++    GError *gerror; /* NULL if we are the prototype and not an instance */
++} Error;
++
++enum {
++    PROP_0,
++    PROP_DOMAIN,
++    PROP_CODE,
++    PROP_MESSAGE
++};
++
++static struct JSClass gjs_error_class;
++
++GJS_DEFINE_DYNAMIC_PRIV_FROM_JS(Error, gjs_error_class)
++
++GJS_NATIVE_CONSTRUCTOR_DECLARE(error)
++{
++    GJS_NATIVE_CONSTRUCTOR_VARIABLES(error)
++    Error *priv;
++    Error *proto_priv;
++    JSObject *proto;
++    jsval v_message, v_code;
++    gchar *message;
++
++    /* Check early to avoid allocating memory for nothing */
++    if (argc != 1 || !JSVAL_IS_OBJECT(argv[0])) {
++        gjs_throw(context, "Invalid parameters passed to GError constructor, expected one object");
++        return JS_FALSE;
++    }
++
++    GJS_NATIVE_CONSTRUCTOR_PRELUDE(error);
++
++    priv = g_slice_new0(Error);
++
++    GJS_INC_COUNTER(gerror);
++
++    g_assert(priv_from_js(context, object) == NULL);
++    JS_SetPrivate(context, object, priv);
++
++    gjs_debug_lifecycle(GJS_DEBUG_GERROR,
++                        "GError constructor, obj %p priv %p",
++                        object, priv);
++
++    proto = JS_GetPrototype(context, object);
++    gjs_debug_lifecycle(GJS_DEBUG_GERROR, "GError instance __proto__ is %p", proto);
++
++    /* If we're the prototype, then post-construct we'll fill in priv->info.
++     * If we are not the prototype, though, then we'll get ->info from the
++     * prototype and then create a GObject if we don't have one already.
++     */
++    proto_priv = priv_from_js(context, proto);
++    if (proto_priv == NULL) {
++        gjs_debug(GJS_DEBUG_GERROR,
++                  "Bad prototype set on GError? Must match JSClass of object. JS error should have been reported.");
++        return JS_FALSE;
++    }
++
++    priv->info = proto_priv->info;
++    g_base_info_ref( (GIBaseInfo*) priv->info);
++    priv->domain = proto_priv->domain;
++
++    if (!gjs_object_require_property (context, JSVAL_TO_OBJECT(argv[0]),
++                                      "GError constructor", "message", &v_message))
++        return JS_FALSE;
++    if (!gjs_object_require_property (context, JSVAL_TO_OBJECT(argv[0]),
++                                      "GError constructor", "code", &v_code))
++        return JS_FALSE;
++    if (!gjs_string_to_utf8 (context, v_message, &message))
++        return JS_FALSE;
++
++    priv->gerror = g_error_new_literal (priv->domain, JSVAL_TO_INT(v_code),
++                                        message);
++
++    g_free (message);
++
++    GJS_NATIVE_CONSTRUCTOR_FINISH(boxed);
++
++    return JS_TRUE;
++}
++
++static void
++error_finalize(JSContext *context,
++               JSObject  *obj)
++{
++    Error *priv;
++
++    priv = priv_from_js(context, obj);
++    gjs_debug_lifecycle(GJS_DEBUG_GERROR,
++                        "finalize, obj %p priv %p", obj, priv);
++    if (priv == NULL)
++        return; /* wrong class? */
++
++    g_clear_error (&priv->gerror);
++
++    if (priv->info) {
++        g_base_info_unref( (GIBaseInfo*) priv->info);
++        priv->info = NULL;
++    }
++
++    GJS_DEC_COUNTER(gerror);
++    g_slice_free(Error, priv);
++}
++
++static JSBool
++error_get_domain(JSContext *context, JSObject *obj, jsid id, jsval *vp)
++{
++    Error *priv;
++
++    priv = priv_from_js(context, obj);
++
++    if (priv == NULL)
++        return JS_FALSE;
++
++    *vp = INT_TO_JSVAL(priv->domain);
++    return JS_TRUE;
++}
++
++static JSBool
++error_get_message(JSContext *context, JSObject *obj, jsid id, jsval *vp)
++{
++    Error *priv;
++
++    priv = priv_from_js(context, obj);
++
++    if (priv == NULL)
++        return JS_FALSE;
++
++    if (priv->gerror == NULL) {
++        /* Object is prototype, not instance */
++        gjs_throw(context, "Can't get a field from a GError prototype");
++        return JS_FALSE;
++    }
++
++    return gjs_string_from_utf8(context, priv->gerror->message, -1, vp);
++}
++
++static JSBool
++error_get_code(JSContext *context, JSObject *obj, jsid id, jsval *vp)
++{
++    Error *priv;
++
++    priv = priv_from_js(context, obj);
++
++    if (priv == NULL)
++        return JS_FALSE;
++
++    if (priv->gerror == NULL) {
++        /* Object is prototype, not instance */
++        gjs_throw(context, "Can't get a field from a GError prototype");
++        return JS_FALSE;
++    }
++
++    *vp = INT_TO_JSVAL(priv->gerror->code);
++    return JS_TRUE;
++}
++
++static JSBool
++error_to_string(JSContext *context, uintN argc, jsval *vp)
++{
++    jsval v_self;
++    JSObject *self;
++    Error *priv;
++    jsval v_out;
++    gchar *descr;
++    JSBool retval;
++
++    v_self = JS_THIS(context, vp);
++    if (!JSVAL_IS_OBJECT(v_self)) {
++        /* Lie a bit here... */
++        gjs_throw(context, "GLib.Error.prototype.toString() called on a non object");
++        return JS_FALSE;
++    }
++
++    self = JSVAL_TO_OBJECT(v_self);
++    priv = priv_from_js(context, self);
++
++    if (priv == NULL)
++        return JS_FALSE;
++
++    v_out = JSVAL_VOID;
++    retval = JS_FALSE;
++
++    /* We follow the same pattern as standard JS errors, at the expense of
++       hiding some useful information */
++
++    if (priv->gerror == NULL) {
++        descr = g_strdup_printf("%s.%s",
++                                g_base_info_get_namespace(priv->info),
++                                g_base_info_get_name(priv->info));
++
++        if (!gjs_string_from_utf8(context, descr, -1, &v_out))
++            goto out;
++    } else {
++        descr = g_strdup_printf("%s.%s: %s",
++                                g_base_info_get_namespace(priv->info),
++                                g_base_info_get_name(priv->info),
++                                priv->gerror->message);
++
++        if (!gjs_string_from_utf8(context, descr, -1, &v_out))
++            goto out;
++    }
++
++    JS_SET_RVAL(context, vp, v_out);
++    retval = JS_TRUE;
++
++ out:
++    g_free(descr);
++    return retval;
++}
++
++static JSBool
++error_constructor_value_of(JSContext *context, uintN argc, jsval *vp)
++{
++    jsval v_self, v_prototype;
++    Error *priv;
++    jsval v_out;
++
++    v_self = JS_THIS(context, vp);
++    if (!JSVAL_IS_OBJECT(v_self)) {
++        /* Lie a bit here... */
++        gjs_throw(context, "GLib.Error.valueOf() called on a non object");
++        return JS_FALSE;
++    }
++
++    if (!gjs_object_require_property(context,
++                                     JSVAL_TO_OBJECT(v_self),
++                                     "constructor",
++                                     "prototype",
++                                     &v_prototype))
++        return JS_FALSE;
++
++    if (!JSVAL_IS_OBJECT(v_prototype)) {
++        gjs_throw(context, "GLib.Error.valueOf() called on something that is not"
++                  " a constructor");
++        return JS_FALSE;
++    }
++
++    priv = priv_from_js(context, JSVAL_TO_OBJECT(v_prototype));
++
++    if (priv == NULL)
++        return JS_FALSE;
++
++    v_out = INT_TO_JSVAL(priv->domain);
++
++    JS_SET_RVAL(context, vp, v_out);
++    return TRUE;
++}
++
++
++/* The bizarre thing about this vtable is that it applies to both
++ * instances of the object, and to the prototype that instances of the
++ * class have.
++ */
++static struct JSClass gjs_error_class = {
++    NULL, /* dynamic class, no name here */
++    JSCLASS_HAS_PRIVATE |
++    JSCLASS_NEW_RESOLVE |
++    JSCLASS_NEW_RESOLVE_GETS_START,
++    JS_PropertyStub,
++    JS_PropertyStub,
++    JS_PropertyStub,
++    JS_StrictPropertyStub,
++    JS_EnumerateStub,
++    JS_ResolveStub,
++    JS_ConvertStub,
++    error_finalize,
++    NULL,
++    NULL,
++    NULL,
++    NULL, NULL, NULL, NULL, NULL
++};
++
++/* We need to shadow all fields of GError, to prevent calling the getter from GBoxed
++   (which would trash memory accessing the instance private data) */
++static JSPropertySpec gjs_error_proto_props[] = {
++    { "domain", PROP_DOMAIN, GJS_MODULE_PROP_FLAGS | JSPROP_READONLY, error_get_domain, NULL },
++    { "code", PROP_CODE, GJS_MODULE_PROP_FLAGS | JSPROP_READONLY, error_get_code, NULL },
++    { "message", PROP_MESSAGE, GJS_MODULE_PROP_FLAGS | JSPROP_READONLY, error_get_message, NULL },
++    { NULL }
++};
++
++static JSFunctionSpec gjs_error_proto_funcs[] = {
++    { "toString", error_to_string, 0, GJS_MODULE_PROP_FLAGS },
++    JS_FS_END
++};
++
++static JSFunctionSpec gjs_error_constructor_funcs[] = {
++    { "valueOf", error_constructor_value_of, 0, GJS_MODULE_PROP_FLAGS },
++    JS_FS_END
++};
++
++JSObject*
++gjs_lookup_error_constructor(JSContext    *context,
++                             GIEnumInfo  *info)
++{
++    JSObject *ns;
++    JSObject *constructor;
++
++    ns = gjs_lookup_namespace_object(context, (GIBaseInfo*) info);
++
++    if (ns == NULL)
++        return NULL;
++
++    constructor = NULL;
++    if (gjs_define_error_class(context, ns, info,
++                               &constructor, NULL))
++        return constructor;
++    else
++        return NULL;
++}
++
++JSObject*
++gjs_lookup_error_prototype(JSContext   *context,
++                           GIEnumInfo  *info)
++{
++    JSObject *ns;
++    JSObject *proto;
++
++    ns = gjs_lookup_namespace_object(context, (GIBaseInfo*) info);
++
++    if (ns == NULL)
++        return NULL;
++
++    proto = NULL;
++    if (gjs_define_error_class(context, ns, info, NULL, &proto))
++        return proto;
++    else
++        return NULL;
++}
++
++JSClass*
++gjs_lookup_error_class(JSContext    *context,
++                       GIEnumInfo   *info)
++{
++    JSObject *prototype;
++
++    prototype = gjs_lookup_error_prototype(context, info);
++
++    return JS_GET_CLASS(context, prototype);
++}
++
++JSBool
++gjs_define_error_class(JSContext    *context,
++                       JSObject     *in_object,
++                       GIEnumInfo   *info,
++                       JSObject    **constructor_p,
++                       JSObject    **prototype_p)
++{
++    const char *constructor_name;
++    GIBoxedInfo *glib_error_info;
++    JSObject *prototype, *parent_proto;
++    JSObject *constructor;
++    jsval value;
++    Error *priv;
++
++    /* See the comment in gjs_define_boxed_class() for an
++     * explanation of how this all works; Error is pretty much the
++     * same as Boxed (except that we inherit from GLib.Error).
++     */
++
++    constructor_name = g_base_info_get_name( (GIBaseInfo*) info);
++
++    if (gjs_object_get_property(context, in_object, constructor_name, &value)) {
++        JSObject *constructor;
++
++        if (!JSVAL_IS_OBJECT(value)) {
++            gjs_throw(context, "Existing property '%s' does not look like a constructor",
++                         constructor_name);
++            return JS_FALSE;
++        }
++
++        constructor = JSVAL_TO_OBJECT(value);
++
++        gjs_object_get_property(context, constructor, "prototype", &value);
++        if (!JSVAL_IS_OBJECT(value)) {
++            gjs_throw(context, "error %s prototype property does not appear to exist or has wrong type", constructor_name);
++            return JS_FALSE;
++        } else {
++            if (prototype_p)
++                *prototype_p = JSVAL_TO_OBJECT(value);
++            if (constructor_p)
++                *constructor_p = constructor;
++
++            return JS_TRUE;
++        }
++    }
++
++    g_irepository_require(NULL, "GLib", "2.0", 0, NULL);
++    glib_error_info = (GIBoxedInfo*) g_irepository_find_by_name(NULL, "GLib", "Error");
++    parent_proto = gjs_lookup_boxed_prototype(context, glib_error_info);
++    g_base_info_unref((GIBaseInfo*)glib_error_info);
++
++    prototype = gjs_init_class_dynamic(context, in_object,
++                                          parent_proto,
++                                          g_base_info_get_namespace( (GIBaseInfo*) info),
++                                          constructor_name,
++                                          &gjs_error_class,
++                                          gjs_error_constructor,
++                                          /* number of constructor args (less can be passed) */
++                                          1,
++                                          /* props of prototype */
++                                          &gjs_error_proto_props[0],
++                                          /* funcs of prototype */
++                                          &gjs_error_proto_funcs[0],
++                                          /* props of constructor, MyConstructor.myprop */
++                                          NULL,
++                                          /* funcs of constructor, MyConstructor.myfunc() */
++                                          &gjs_error_constructor_funcs[0]);
++    if (prototype == NULL) {
++        gjs_log_exception(context, NULL);
++        gjs_fatal("Can't init class %s", constructor_name);
++    }
++
++    g_assert(gjs_object_has_property(context, in_object, constructor_name));
++
++    priv = g_slice_new0(Error);
++    priv->info = info;
++    g_base_info_ref( (GIBaseInfo*) priv->info);
++    priv->domain = g_quark_from_string (g_enum_info_get_error_domain(priv->info));
++
++    JS_SetPrivate(context, prototype, priv);
++
++    gjs_debug(GJS_DEBUG_GBOXED, "Defined class %s prototype is %p class %p in object %p",
++              constructor_name, prototype, JS_GET_CLASS(context, prototype), in_object);
++
++    constructor = NULL;
++    gjs_object_get_property(context, in_object, constructor_name, &value);
++    if (!JSVAL_IS_VOID(value)) {
++        if (!JSVAL_IS_OBJECT(value)) {
++            gjs_throw(context, "Property '%s' does not look like a constructor",
++                      constructor_name);
++            return JS_FALSE;
++        }
++    }
++
++    constructor = JSVAL_TO_OBJECT(value);
++
++    gjs_define_enum_values(context, constructor, priv->info);
++
++    if (constructor_p)
++        *constructor_p = constructor;
++
++    if (prototype_p)
++        *prototype_p = prototype;
++
++    return JS_TRUE;
++}
++
++static GIEnumInfo *
++find_error_domain_info(GQuark domain)
++{
++    GIEnumInfo *info;
++
++    /* first an attempt without loading extra libraries */
++    info = g_irepository_find_by_error_domain(NULL, domain);
++    if (info)
++        return info;
++
++    /* load standard stuff */
++    g_irepository_require(NULL, "GLib", "2.0", 0, NULL);
++    g_irepository_require(NULL, "GObject", "2.0", 0, NULL);
++    g_irepository_require(NULL, "Gio", "2.0", 0, NULL);
++    info = g_irepository_find_by_error_domain(NULL, domain);
++    if (info)
++        return info;
++
++    /* last attempt: load GIRepository (for invoke errors, rarely
++       needed) */
++    g_irepository_require(NULL, "GIRepository", "1.0", 0, NULL);
++    info = g_irepository_find_by_error_domain(NULL, domain);
++
++    return info;
++}
++
++JSObject*
++gjs_error_from_gerror(JSContext             *context,
++                      GError                *gerror)
++{
++    JSObject *obj;
++    JSObject *proto;
++    Error *priv;
++    Error *proto_priv;
++    GIEnumInfo *info;
++
++    if (gerror == NULL)
++        return NULL;
++
++    info = find_error_domain_info(gerror->domain);
++
++    if (!info) {
++        /* We don't have error domain metadata */
++        /* Marshal the error as a plain GError */
++        GIBaseInfo *glib_boxed;
++        JSObject *retval;
++
++        glib_boxed = g_irepository_find_by_name(NULL, "GLib", "Error");
++        retval = gjs_boxed_from_c_struct(context, glib_boxed, gerror, 0);
++
++        g_base_info_unref(glib_boxed);
++        return retval;
++    }
++
++    gjs_debug_marshal(GJS_DEBUG_GBOXED,
++                      "Wrapping struct %s %p with JSObject",
++                      g_base_info_get_name((GIBaseInfo *)info), gboxed);
++
++    proto = gjs_lookup_error_prototype(context, info);
++    proto_priv = priv_from_js(context, proto);
++
++    obj = JS_NewObjectWithGivenProto(context,
++                                     JS_GET_CLASS(context, proto), proto,
++                                     gjs_get_import_global (context));
++
++    priv = g_slice_new0(Error);
++    JS_SetPrivate(context, obj, priv);
++    priv->info = info;
++    priv->domain = proto_priv->domain;
++    g_base_info_ref( (GIBaseInfo*) priv->info);
++    priv->gerror = g_error_copy(gerror);
++
++    return obj;
++}
++
++GError*
++gjs_gerror_from_error(JSContext    *context,
++                      JSObject     *obj)
++{
++    Error *priv;
++
++    if (obj == NULL)
++        return NULL;
++
++    priv = priv_from_js(context, obj);
++
++    if (priv == NULL)
++        return NULL;
++
++    if (priv->gerror == NULL) {
++        gjs_throw(context,
++                  "Object is %s.%s.prototype, not an object instance - cannot convert to a boxed instance",
++                  g_base_info_get_namespace( (GIBaseInfo*) priv->info),
++                  g_base_info_get_name( (GIBaseInfo*) priv->info));
++        return NULL;
++    }
++
++    return priv->gerror;
++}
+Index: gjs-1.32.0/gi/gerror.h
+===================================================================
+--- /dev/null	1970-01-01 00:00:00.000000000 +0000
++++ gjs-1.32.0/gi/gerror.h	2012-11-26 10:59:33.538183526 +0100
+@@ -0,0 +1,53 @@
++/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
++/*
++ * Copyright (c) 2008  litl, LLC
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this software and associated documentation files (the "Software"), to
++ * deal in the Software without restriction, including without limitation the
++ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
++ * sell copies of the Software, and to permit persons to whom the Software is
++ * furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
++ * IN THE SOFTWARE.
++ */
++
++#ifndef __GJS_ERROR_H__
++#define __GJS_ERROR_H__
++
++#include <glib.h>
++
++#include <jsapi.h>
++
++#include <girepository.h>
++
++G_BEGIN_DECLS
++
++JSBool    gjs_define_error_class       (JSContext             *context,
++                                        JSObject              *in_object,
++                                        GIEnumInfo            *info,
++                                        JSObject             **constructor_p,
++                                        JSObject             **prototype_p);
++JSObject* gjs_lookup_error_constructor (JSContext             *context,
++                                        GIEnumInfo            *info);
++JSObject* gjs_lookup_error_prototype   (JSContext             *context,
++                                        GIEnumInfo            *info);
++JSClass*  gjs_lookup_error_class       (JSContext             *context,
++                                        GIEnumInfo            *info);
++GError*   gjs_gerror_from_error        (JSContext             *context,
++                                        JSObject              *obj);
++JSObject* gjs_error_from_gerror        (JSContext             *context,
++                                        GError                *gerror);
++
++G_END_DECLS
++
++#endif  /* __GJS_ERROR_H__ */
+Index: gjs-1.32.0/gi/repo.c
+===================================================================
+--- gjs-1.32.0.orig/gi/repo.c	2012-02-06 15:17:48.000000000 +0100
++++ gjs-1.32.0/gi/repo.c	2012-11-26 10:59:33.542183540 +0100
+@@ -34,6 +34,7 @@
+ #include "arg.h"
+ #include "foreign.h"
+ #include "interface.h"
++#include "gerror.h"
+ 
+ #include <gjs/compat.h>
+ 
+@@ -499,6 +500,13 @@ gjs_define_info(JSContext  *context,
+             return JS_FALSE;
+         break;
+     case GI_INFO_TYPE_ENUM:
++        if (g_enum_info_get_error_domain((GIEnumInfo*) info)) {
++            /* define as GError subclass */
++            if (!gjs_define_error_class(context, in_object, (GIEnumInfo*) info, NULL, NULL))
++                return JS_FALSE;
++        }
++        /* fall through */
++
+     case GI_INFO_TYPE_FLAGS:
+         if (!gjs_define_enumeration(context, in_object, (GIEnumInfo*) info, NULL))
+             return JS_FALSE;
+Index: gjs-1.32.0/gi/value.c
+===================================================================
+--- gjs-1.32.0.orig/gi/value.c	2012-03-05 15:48:49.000000000 +0100
++++ gjs-1.32.0/gi/value.c	2012-11-26 10:59:33.542183540 +0100
+@@ -33,6 +33,7 @@
+ #include "boxed.h"
+ #include "union.h"
+ #include "gtype.h"
++#include "gerror.h"
+ #include <gjs/gjs-module.h>
+ #include <gjs/compat.h>
+ 
+@@ -387,7 +388,13 @@ gjs_value_to_g_value_internal(JSContext
+         } else if (JSVAL_IS_OBJECT(value)) {
+             JSObject *obj;
+             obj = JSVAL_TO_OBJECT(value);
+-            gboxed = gjs_c_struct_from_boxed(context, obj);
++
++            if (g_type_is_a(gtype, G_TYPE_ERROR)) {
++                /* special case GError */
++                gboxed = gjs_gerror_from_error(context, obj);
++            } else {
++                gboxed = gjs_c_struct_from_boxed(context, obj);
++            }
+         } else {
+             gjs_throw(context,
+                       "Wrong type %s; boxed type %s expected",
+@@ -665,6 +672,14 @@ gjs_value_from_g_value_internal(JSContex
+             gboxed = g_value_get_variant(gvalue);
+         boxed_flags = GJS_BOXED_CREATION_NONE;
+ 
++        /* special case GError */
++        if (g_type_is_a(gtype, G_TYPE_ERROR)) {
++            obj = gjs_error_from_gerror(context, gboxed);
++            *value_p = OBJECT_TO_JSVAL(obj);
++
++            return TRUE;
++        }
++
+         /* The only way to differentiate unions and structs is from
+          * their g-i info as both GBoxed */
+         info = g_irepository_find_by_gtype(g_irepository_get_default(),
+@@ -693,6 +708,7 @@ gjs_value_from_g_value_internal(JSContex
+                       g_type_name(gtype));
+             return JS_FALSE;
+         }
++
+         *value_p = OBJECT_TO_JSVAL(obj);
+     } else if (g_type_is_a(gtype, G_TYPE_ENUM)) {
+         return convert_int_to_enum(context, value_p, gtype, g_value_get_enum(gvalue));
+Index: gjs-1.32.0/gjs/jsapi-util-error.c
+===================================================================
+--- gjs-1.32.0.orig/gjs/jsapi-util-error.c	2012-03-05 15:48:49.000000000 +0100
++++ gjs-1.32.0/gjs/jsapi-util-error.c	2012-11-26 10:59:33.546183565 +0100
+@@ -25,6 +25,7 @@
+ 
+ #include "jsapi-util.h"
+ #include "compat.h"
++#include "gi/gerror.h"
+ 
+ #include <util/log.h>
+ 
+@@ -46,13 +47,9 @@ gjs_throw_valist(JSContext       *contex
+                     va_list          args)
+ {
+     char *s;
+-    jsval retval;
+-    jsval argv[1];
+-    JSFunction *func;
+-    const char *body;
+     JSBool result;
+-    const char *names[] = { "message" };
+-    guint options;
++    jsval v_constructor, v_message;
++    JSObject *err_obj;
+ 
+     s = g_strdup_vprintf(format, args);
+ 
+@@ -79,53 +76,20 @@ gjs_throw_valist(JSContext       *contex
+ 
+     (void)JS_EnterLocalRootScope(context);
+ 
+-    if (!gjs_string_from_utf8(context, s, -1, &argv[0])) {
++    if (!gjs_string_from_utf8(context, s, -1, &v_message)) {
+         JS_ReportError(context, "Failed to copy exception string");
+         goto out;
+     }
+ 
+-    body = "throw new Error(message);";
+-    func = JS_CompileFunction(context,
+-                              JS_GetGlobalObject(context), /* parent object (scope chain) */
+-                              NULL, /* name of function if we wanted to define it in parent */
+-                              1, /* nargs */
+-                              &names[0], /* array of arg names if we had args */
+-                              body,
+-                              strlen(body),
+-                              "gjs_throw", /* file */
+-                              0); /* line */
+-
+-    if (func == NULL) {
+-        JS_ReportError(context, "Failed to compile function");
++    if (!gjs_object_get_property(context, JS_GetGlobalObject(context),
++                                 "Error", &v_constructor)) {
++        JS_ReportError(context, "??? Missing Error constructor in global object?");
+         goto out;
+     }
+ 
+-    /* we need JS_CallFunctionValue() to leave the exception set */
+-    options = JS_GetOptions(context);
+-    if (!(options & JSOPTION_DONT_REPORT_UNCAUGHT)) {
+-        JS_SetOptions(context, options | JSOPTION_DONT_REPORT_UNCAUGHT);
+-    }
+-
+-    retval = JSVAL_VOID;
+-
+-    /* note the return value is whether function succeeded, which it shouldn't, since it
+-     * throws...
+-     */
+-    JS_CallFunctionValue(context,
+-                         JS_GetGlobalObject(context),
+-                         OBJECT_TO_JSVAL(JS_GetFunctionObject(func)),
+-                         1, &argv[0],
+-                         &retval);
+-
+-    if (!(options & JSOPTION_DONT_REPORT_UNCAUGHT)) {
+-        JS_SetOptions(context, options);
+-    }
+-
+-    if (!JS_IsExceptionPending(context)) {
+-        JS_ReportError(context,
+-                       "Failed to set exception by calling our exception-setting function");
+-        goto out;
+-    }
++    /* throw new Error(message) */
++    err_obj = JS_New(context, JSVAL_TO_OBJECT(v_constructor), 1, &v_message);
++    JS_SetPendingException(context, OBJECT_TO_JSVAL(err_obj));
+ 
+     result = JS_TRUE;
+ 
+@@ -182,17 +146,26 @@ gjs_throw_literal(JSContext       *conte
+  * gjs_throw_g_error:
+  *
+  * Convert a GError into a JavaScript Exception, and
+- * frees the GError.  Like gjs_throw(), will not overwrite
+- * an already pending exception.
++ * frees the GError. Differently from gjs_throw(), it
++ * will overwrite an existing exception, as it is used
++ * to report errors from C functions.
+  */
+ void
+ gjs_throw_g_error (JSContext       *context,
+                    GError          *error)
+ {
++    JSObject *err_obj;
++
+     if (error == NULL)
+         return;
+-    gjs_throw_literal(context, error->message);
+-    g_error_free (error);
++
++    JS_BeginRequest(context);
++
++    err_obj = gjs_error_from_gerror(context, error);
++    if (err_obj)
++        JS_SetPendingException(context, OBJECT_TO_JSVAL(err_obj));
++
++    JS_EndRequest(context);
+ }
+ 
+ #if GJS_BUILD_TESTS
+Index: gjs-1.32.0/gjs/mem.c
+===================================================================
+--- gjs-1.32.0.orig/gjs/mem.c	2012-01-04 19:24:48.000000000 +0100
++++ gjs-1.32.0/gjs/mem.c	2012-11-26 10:59:33.546183565 +0100
+@@ -36,6 +36,7 @@
+ GJS_DEFINE_COUNTER(everything)
+ 
+ GJS_DEFINE_COUNTER(boxed)
++GJS_DEFINE_COUNTER(gerror)
+ GJS_DEFINE_COUNTER(closure)
+ GJS_DEFINE_COUNTER(database)
+ GJS_DEFINE_COUNTER(dbus_exports)
+@@ -54,6 +55,7 @@ GJS_DEFINE_COUNTER(interface)
+ 
+ static GjsMemCounter* counters[] = {
+     GJS_LIST_COUNTER(boxed),
++    GJS_LIST_COUNTER(gerror),
+     GJS_LIST_COUNTER(closure),
+     GJS_LIST_COUNTER(database),
+     GJS_LIST_COUNTER(dbus_exports),
+Index: gjs-1.32.0/gjs/mem.h
+===================================================================
+--- gjs-1.32.0.orig/gjs/mem.h	2012-01-04 19:24:48.000000000 +0100
++++ gjs-1.32.0/gjs/mem.h	2012-11-26 10:59:33.546183565 +0100
+@@ -44,6 +44,7 @@ typedef struct {
+ GJS_DECLARE_COUNTER(everything)
+ 
+ GJS_DECLARE_COUNTER(boxed)
++GJS_DECLARE_COUNTER(gerror)
+ GJS_DECLARE_COUNTER(closure)
+ GJS_DECLARE_COUNTER(database)
+ GJS_DECLARE_COUNTER(dbus_exports)
+Index: gjs-1.32.0/modules/overrides/GLib.js
+===================================================================
+--- gjs-1.32.0.orig/modules/overrides/GLib.js	2011-11-10 19:58:10.000000000 +0100
++++ gjs-1.32.0/modules/overrides/GLib.js	2012-11-26 10:59:33.550183579 +0100
+@@ -240,6 +240,11 @@ function _init() {
+ 
+     GLib = this;
+ 
++    // small HACK: we add a matches() method to standard Errors so that
++    // you can do "catch(e if e.matches(Ns.FooError, Ns.FooError.SOME_CODE))"
++    // without checking instanceof
++    Error.prototype.matches = function() { return false; }
++
+     this.Variant.new = function (sig, value) {
+ 	let signature = Array.prototype.slice.call(sig);
+ 
+Index: gjs-1.32.0/test/js/testEverythingBasic.js
+===================================================================
+--- gjs-1.32.0.orig/test/js/testEverythingBasic.js	2012-02-07 17:30:49.000000000 +0100
++++ gjs-1.32.0/test/js/testEverythingBasic.js	2012-11-26 10:59:33.550183579 +0100
+@@ -521,4 +521,33 @@ function testVariant() {
+     assertEquals(3, as.length);
+ }
+ 
++function testGError() {
++    assertEquals(Gio.io_error_quark(), Number(Gio.IOErrorEnum));
++
++    try {
++	let file = Gio.file_new_for_path("\\/,.^!@&$_don't exist");
++	file.read(null);
++    } catch (x) {
++	assertTrue(x instanceof Gio.IOErrorEnum);
++	assertTrue(x.matches(Gio.io_error_quark(), Gio.IOErrorEnum.NOT_FOUND));
++	assertTrue(x.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.NOT_FOUND));
++
++	assertEquals(Gio.io_error_quark(), x.domain);
++	assertEquals(Gio.IOErrorEnum.NOT_FOUND, x.code);
++    }
++
++    Everything.test_gerror_callback(function(e) {
++	assertTrue(e instanceof Gio.IOErrorEnum);
++	assertEquals(Gio.io_error_quark(), e.domain);
++	assertEquals(Gio.IOErrorEnum.NOT_SUPPORTED, e.code);
++	assertEquals('regression test error', e.message);
++    });
++    Everything.test_owned_gerror_callback(function(e) {
++	assertTrue(e instanceof Gio.IOErrorEnum);
++	assertEquals(Gio.io_error_quark(), e.domain);
++	assertEquals(Gio.IOErrorEnum.PERMISSION_DENIED, e.code);
++	assertEquals('regression test owned error', e.message);
++    });
++}
++
+ gjstestRun();
+Index: gjs-1.32.0/util/log.c
+===================================================================
+--- gjs-1.32.0.orig/util/log.c	2011-06-10 00:31:56.000000000 +0200
++++ gjs-1.32.0/util/log.c	2012-11-26 10:59:33.550183579 +0100
+@@ -277,6 +277,9 @@ gjs_debug(GjsDebugTopic topic,
+     case GJS_DEBUG_BYTE_ARRAY:
+         prefix = "JS BYTE ARRAY";
+         break;
++    case GJS_DEBUG_GERROR:
++        prefix = "JS G ERR";
++        break;
+     }
+ 
+     if (!is_allowed_prefix(prefix))
+Index: gjs-1.32.0/util/log.h
+===================================================================
+--- gjs-1.32.0.orig/util/log.h	2011-06-10 00:31:56.000000000 +0200
++++ gjs-1.32.0/util/log.h	2012-11-26 10:59:33.550183579 +0100
+@@ -60,7 +60,8 @@ typedef enum {
+     GJS_DEBUG_PROPS,
+     GJS_DEBUG_SCOPE,
+     GJS_DEBUG_HTTP,
+-    GJS_DEBUG_BYTE_ARRAY
++    GJS_DEBUG_BYTE_ARRAY,
++    GJS_DEBUG_GERROR,
+ } GjsDebugTopic;
+ 
+ /* These defines are because we have some pretty expensive and
Index: debian/patches/03_gerror_details.patch
===================================================================
--- debian/patches/03_gerror_details.patch	(révision 0)
+++ debian/patches/03_gerror_details.patch	(révision 36381)
@@ -0,0 +1,384 @@
+From 52e921dacf553564f6503668bf0be82cfb782d7c Mon Sep 17 00:00:00 2001
+From: Giovanni Campagna <gcampagna@src.gnome.org>
+Date: Sat, 03 Mar 2012 17:03:14 +0000
+Subject: GError: add stack, fileName and lineNumber
+
+Similar to native Errors(), GLib.Error is extended to provide debug
+information in the form of fileName, lineNumber and stack (obtained
+using the JS debug API). At the same time, the existing stack logging
+facility is modified to be similar in format to the native one, and
+logError is modified to avoid iterating object properties (which
+gives an undefined order, and does not include prototype properties)
+
+https://bugzilla.gnome.org/show_bug.cgi?id=591480
+---
+diff --git a/gi/arg.c b/gi/arg.c
+index af1750d..8250eb8 100644
+--- a/gi/arg.c
++++ b/gi/arg.c
+@@ -2379,7 +2379,7 @@ gjs_value_from_g_argument (JSContext  *context,
+     case GI_TYPE_TAG_ERROR:
+         {
+             if (arg->v_pointer) {
+-                JSObject *obj = gjs_error_from_gerror(context, arg->v_pointer);
++                JSObject *obj = gjs_error_from_gerror(context, arg->v_pointer, FALSE);
+                 if (obj) {
+                     *value_p = OBJECT_TO_JSVAL(obj);
+                     return JS_TRUE;
+@@ -2459,7 +2459,7 @@ gjs_value_from_g_argument (JSContext  *context,
+             if (g_type_is_a(gtype, G_TYPE_ERROR)) {
+                 JSObject *obj;
+ 
+-                obj = gjs_error_from_gerror(context, arg->v_pointer);
++                obj = gjs_error_from_gerror(context, arg->v_pointer, FALSE);
+                 if (obj)
+                     value = OBJECT_TO_JSVAL(obj);
+                 else
+diff --git a/gi/gerror.c b/gi/gerror.c
+index 5d50cd5..45dc387 100644
+--- a/gi/gerror.c
++++ b/gi/gerror.c
+@@ -35,6 +35,7 @@
+ #include <util/log.h>
+ 
+ #include <jsapi.h>
++#include <jsdbgapi.h>
+ 
+ #include <girepository.h>
+ 
+@@ -53,6 +54,8 @@ enum {
+ 
+ static struct JSClass gjs_error_class;
+ 
++static void define_error_properties(JSContext *, JSObject *);
++
+ GJS_DEFINE_DYNAMIC_PRIV_FROM_JS(Error, gjs_error_class)
+ 
+ GJS_NATIVE_CONSTRUCTOR_DECLARE(error)
+@@ -115,6 +118,9 @@ GJS_NATIVE_CONSTRUCTOR_DECLARE(error)
+ 
+     g_free (message);
+ 
++    /* We assume this error will be thrown in the same line as the constructor */
++    define_error_properties(context, object);
++
+     GJS_NATIVE_CONSTRUCTOR_FINISH(boxed);
+ 
+     return JS_TRUE;
+@@ -514,9 +520,61 @@ find_error_domain_info(GQuark domain)
+     return info;
+ }
+ 
++/* define properties that JS Error() expose, such as
++   fileName, lineNumber and stack
++*/
++static void
++define_error_properties(JSContext *context,
++                        JSObject  *obj)
++{
++    JSStackFrame *frame;
++    JSScript *script;
++    jsbytecode *pc;
++    jsval v;
++    GString *stack;
++    const char *filename;
++    GjsContext *gjs_context;
++
++    /* find the JS frame that triggered the error */
++    frame = NULL;
++    while (JS_FrameIterator(context, &frame)) {
++        if (JS_IsScriptFrame(context, frame))
++            break;
++    }
++
++    /* someone called gjs_throw at top of the stack?
++       well, no stack in that case
++    */
++    if (!frame)
++        return;
++
++    script = JS_GetFrameScript(context, frame);
++    pc = JS_GetFramePC(context, frame);
++
++    stack = g_string_new(NULL);
++    gjs_context = JS_GetContextPrivate(context);
++    gjs_context_print_stack_to_buffer(gjs_context, frame, stack);
++
++    if (gjs_string_from_utf8(context, stack->str, stack->len, &v))
++        JS_DefineProperty(context, obj, "stack", v,
++                          NULL, NULL, JSPROP_ENUMERATE);
++
++    filename = JS_GetScriptFilename(context, script);
++    if (gjs_string_from_filename(context, filename, -1, &v))
++        JS_DefineProperty(context, obj, "fileName", v,
++                          NULL, NULL, JSPROP_ENUMERATE);
++
++    v = INT_TO_JSVAL(JS_PCToLineNumber(context, script, pc));
++    JS_DefineProperty(context, obj, "lineNumber", v,
++                      NULL, NULL, JSPROP_ENUMERATE);
++
++    g_string_free(stack, TRUE);
++}
++
+ JSObject*
+ gjs_error_from_gerror(JSContext             *context,
+-                      GError                *gerror)
++                      GError                *gerror,
++                      gboolean               add_stack)
+ {
+     JSObject *obj;
+     JSObject *proto;
+@@ -560,6 +618,9 @@ gjs_error_from_gerror(JSContext             *context,
+     g_base_info_ref( (GIBaseInfo*) priv->info);
+     priv->gerror = g_error_copy(gerror);
+ 
++    if (add_stack)
++        define_error_properties(context, obj);
++
+     return obj;
+ }
+ 
+diff --git a/gi/gerror.h b/gi/gerror.h
+index 0d93c44..3940d1a 100644
+--- a/gi/gerror.h
++++ b/gi/gerror.h
+@@ -46,7 +46,8 @@ JSClass*  gjs_lookup_error_class       (JSContext             *context,
+ GError*   gjs_gerror_from_error        (JSContext             *context,
+                                         JSObject              *obj);
+ JSObject* gjs_error_from_gerror        (JSContext             *context,
+-                                        GError                *gerror);
++                                        GError                *gerror,
++                                        gboolean               add_stack);
+ 
+ G_END_DECLS
+ 
+diff --git a/gi/value.c b/gi/value.c
+index c64564f..4d02827 100644
+--- a/gi/value.c
++++ b/gi/value.c
+@@ -675,7 +675,7 @@ gjs_value_from_g_value_internal(JSContext    *context,
+ 
+         /* special case GError */
+         if (g_type_is_a(gtype, G_TYPE_ERROR)) {
+-            obj = gjs_error_from_gerror(context, gboxed);
++            obj = gjs_error_from_gerror(context, gboxed, FALSE);
+             *value_p = OBJECT_TO_JSVAL(obj);
+ 
+             return TRUE;
+diff --git a/gjs/context.h b/gjs/context.h
+index 4e01cc7..d19d8a5 100644
+--- a/gjs/context.h
++++ b/gjs/context.h
+@@ -68,7 +68,11 @@ gboolean        gjs_context_define_string_array  (GjsContext  *js_context,
+ GList*          gjs_context_get_all              (void);
+ void*           gjs_context_get_native_context   (GjsContext *js_context);
+ 
++/* initial_frame is a JSStackFrame, but cannot be exposed as such in the
++   public API. Pass NULL to get the topmost frame.
++*/
+ void            gjs_context_print_stack_to_buffer (GjsContext *js_context,
++                                                   void       *initial_frame,
+                                                    GString    *buf);
+ 
+ void            gjs_context_print_stack_stderr    (GjsContext *js_context);
+diff --git a/gjs/jsapi-util-error.c b/gjs/jsapi-util-error.c
+index 8bce07e..88ac97e 100644
+--- a/gjs/jsapi-util-error.c
++++ b/gjs/jsapi-util-error.c
+@@ -161,7 +161,7 @@ gjs_throw_g_error (JSContext       *context,
+ 
+     JS_BeginRequest(context);
+ 
+-    err_obj = gjs_error_from_gerror(context, error);
++    err_obj = gjs_error_from_gerror(context, error, TRUE);
+     if (err_obj)
+         JS_SetPendingException(context, OBJECT_TO_JSVAL(err_obj));
+ 
+diff --git a/gjs/jsapi-util.c b/gjs/jsapi-util.c
+index 6efd528..ca2965e 100644
+--- a/gjs/jsapi-util.c
++++ b/gjs/jsapi-util.c
+@@ -970,6 +970,21 @@ gjs_explain_scope(JSContext  *context,
+     JS_EndRequest(context);
+ }
+ 
++static void
++log_one_exception_property(JSContext  *context,
++                           JSObject   *object,
++                           const char *name)
++{
++    jsval v;
++    char *debugstr;
++
++    gjs_object_get_property(context, object, name, &v);
++
++    debugstr = gjs_value_debug_string(context, v);
++    gjs_debug(GJS_DEBUG_ERROR, "  %s = '%s'", name, debugstr);
++    g_free(debugstr);
++}
++
+ void
+ gjs_log_exception_props(JSContext *context,
+                         jsval      exc)
+@@ -988,23 +1003,10 @@ gjs_log_exception_props(JSContext *context,
+ 
+         exc_obj = JSVAL_TO_OBJECT(exc);
+ 
+-        /* I guess this is a SpiderMonkey bug.  If we don't get these
+-         * properties here, only 'message' shows up when we enumerate
+-         * all properties below. I did not debug in detail, so maybe
+-         * it's something wrong with our enumeration loop below. In
+-         * any case, if you remove this code block, check that "throw
+-         * Error()" still results in printing all four of these props.
+-         * For me right now, if you remove this block, only message
+-         * gets printed.
+-         */
+-        gjs_object_has_property(context, exc_obj, "stack");
+-        gjs_object_has_property(context, exc_obj, "fileName");
+-        gjs_object_has_property(context, exc_obj, "lineNumber");
+-        gjs_object_has_property(context, exc_obj, "message");
+-
+-        gjs_log_object_props(context, exc_obj,
+-                             GJS_DEBUG_ERROR,
+-                             "  ");
++        log_one_exception_property(context, exc_obj, "message");
++        log_one_exception_property(context, exc_obj, "fileName");
++        log_one_exception_property(context, exc_obj, "lineNumber");
++        log_one_exception_property(context, exc_obj, "stack");
+     } else if (JSVAL_IS_STRING(exc)) {
+         gjs_debug(GJS_DEBUG_ERROR,
+                   "Exception was a String");
+diff --git a/gjs/stack.c b/gjs/stack.c
+index 363366d..84e1c6a 100644
+--- a/gjs/stack.c
++++ b/gjs/stack.c
+@@ -48,34 +48,40 @@
+ #include "compat.h"
+ #include "jsapi-util.h"
+ 
++/* Mimick the behaviour exposed by standard Error objects
++   (http://mxr.mozilla.org/mozilla-central/source/js/src/jsexn.cpp#554)
++*/
+ static char*
+ jsvalue_to_string(JSContext* cx, jsval val, gboolean* is_string)
+ {
+     char* value = NULL;
+-    JSString* value_str;
+-
+-    (void)JS_EnterLocalRootScope(cx);
+-
+-    value_str = JS_ValueToString(cx, val);
+-    if (value_str)
+-        value = gjs_value_debug_string(cx, val);
+-    if (value) {
+-        const char* found = strstr(value, "function ");
+-        if(found && (value == found || value+1 == found || value+2 == found)) {
+-            g_free(value);
+-            value = g_strdup("[function]");
+-        }
++    JSString* value_str = NULL;
++
++    if (JSVAL_IS_PRIMITIVE(val)) {
++      value_str = JS_ValueToSource(cx, val);
++    } else {
++      JSObject *obj = JSVAL_TO_OBJECT(val);
++
++      if (JS_ObjectIsFunction(cx, obj)) {
++	JSFunction *fn = JS_ValueToFunction(cx, val);
++	value_str = JS_GetFunctionId(fn);
++
++	if (!value_str)
++	  value = g_strdup("[unknown function]");
++      } else {
++	value = g_strdup_printf("[object %s]", JS_GetClass(cx, obj)->name);
++      }
+     }
+ 
++    if (!value && value_str)
++      value = gjs_value_debug_string(cx, val);
++
+     if (is_string)
+         *is_string = JSVAL_IS_STRING(val);
+ 
+-    JS_LeaveLocalRootScope(cx);
+-
+     return value;
+ }
+ 
+-
+ static void
+ format_frame(JSContext* cx, JSStackFrame* fp,
+              GString *buf, int num)
+@@ -167,14 +173,10 @@ format_frame(JSContext* cx, JSStackFrame* fp,
+         guint32 k;
+         guint32 arg_count;
+         JSObject* args_obj = JSVAL_TO_OBJECT(val);
+-        if (JS_GetProperty(cx, args_obj, "length", &val) &&
+-            JS_ValueToECMAUint32(cx, val, &arg_count) &&
++        if (JS_GetArrayLength(cx, args_obj, &arg_count) &&
+             arg_count > named_arg_count) {
+             for (k = named_arg_count; k < arg_count; k++) {
+-                char number[8];
+-                g_snprintf(number, 8, "%d", (int) k);
+-
+-                if (JS_GetProperty(cx, args_obj, number, &val)) {
++                if (JS_GetElement(cx, args_obj, k, &val)) {
+                     char *value = jsvalue_to_string(cx, val, &is_string);
+                     g_string_append_printf(buf, "%s%s%s%s",
+                                            k ? ", " : "",
+@@ -189,38 +191,41 @@ format_frame(JSContext* cx, JSStackFrame* fp,
+ 
+     /* print filename and line number */
+ 
+-    g_string_append_printf(buf, "%s [\"%s\":%d]\n",
++    g_string_append_printf(buf, "%s@%s:%d\n",
+                            fun ? ")" : "",
+-                           filename ? filename : "<unknown>",
++                           filename ? filename : "",
+                            lineno);
++
+   out:
++    if (call_props.array)
++      JS_PutPropertyDescArray(cx, &call_props);
++
+     JS_LeaveLocalRootScope(cx);
+ }
+ 
+ void
+-gjs_context_print_stack_to_buffer(GjsContext* context, GString *buf)
++gjs_context_print_stack_to_buffer(GjsContext* context, void *initial, GString *buf)
+ {
+     JSContext *js_context = (JSContext*)gjs_context_get_native_context(context);
+-    JSStackFrame* fp;
+-    JSStackFrame* iter = NULL;
++    JSStackFrame* fp = initial;
+     int num = 0;
+ 
+-    g_string_append_printf(buf, "== Stack trace for context %p ==\n", context);
+-    while ((fp = JS_FrameIterator(js_context, &iter)) != NULL) {
++    while (fp) {
+         format_frame(js_context, fp, buf, num);
+         num++;
+-    }
+ 
+-    if(!num)
+-        g_string_append_printf(buf, "(JavaScript stack is empty)\n");
+-    g_string_append(buf, "\n");
++	JS_FrameIterator(js_context, &fp);
++    }
+ }
+ 
+ void
+ gjs_context_print_stack_stderr(GjsContext *context)
+ {
+   GString *str = g_string_new("");
+-  gjs_context_print_stack_to_buffer(context, str);
++
++  g_string_append_printf(str, "== Stack trace for context %p ==\n", context);
++  gjs_context_print_stack_to_buffer(context, NULL, str);
++
+   g_printerr("%s\n", str->str);
+   g_string_free(str, TRUE);
+ }
+--
+cgit v0.9.0.2
Index: debian/patches/series
===================================================================
--- debian/patches/series	(révision 34600)
+++ debian/patches/series	(copie de travail)
@@ -1 +1,3 @@
 0001-Fold-libgjs-gdbus.so-into-libgjs.so.patch
+02_gerror_class.patch
+03_gerror_details.patch
Index: debian/rules
===================================================================
--- debian/rules	(révision 34600)
+++ debian/rules	(copie de travail)
@@ -7,10 +7,13 @@
 include /usr/share/gnome-pkg-tools/1/rules/uploaders.mk
 include /usr/share/gnome-pkg-tools/1/rules/gnome-get-source.mk
 
+# SHVER := $(DEB_UPSTREAM_VERSION)
+SHVER := 1.32.0-3
+
 # Use recursive variables since this variable must not be expanded until 
 # files have been installed.
 LIBMOZJS = $(shell objdump -p debian/tmp/usr/lib/libgjs.so | awk '$$1=="NEEDED" && $$2~/^libmozjs/ { print $$2 }' | sed s/\\.so\\./-/ )
-DEB_DH_MAKESHLIBS_ARGS_libgjs0b = -Xusr/lib/gjs-1.0/ -V'libgjs0b (>= $(DEB_UPSTREAM_VERSION)), libgjs0-$(LIBMOZJS)' -- -c4
+DEB_DH_MAKESHLIBS_ARGS_libgjs0b = -Xusr/lib/gjs-1.0/ -V'libgjs0b (>= $(SHVER)), libgjs0-$(LIBMOZJS)' -- -c4
 
 DEB_MAKE_CHECK_TARGET := check || true
 

--- End Message ---
--- Begin Message ---
On Thu, Jan  3, 2013 at 01:50:33 +0100, Josselin Mouette wrote:

> Control: retitle -1 unblock: gjs/1.32.0-5
> 
> Le mardi 18 décembre 2012 à 21:39 +0100, Julien Cristau a écrit : 
> > gjs/context.h seems to be a public header, and
> > gjs_context_print_stack_to_buffer is exported.  This looks like ABI
> > breakage to me?
> 
> I have uploaded version 1.32.0-5 which reverts the ABI breakage.
> 
Thanks Joss, unblocked.

Cheers,
Julien

Attachment: signature.asc
Description: Digital signature


--- End Message ---

Reply to: