[gjs/wip/ptomato/mozjs38: 14/14] WIP - mozjs38



commit 6fd49fd631760453dec30999fe7977da2b067243
Author: Philip Chimento <philip chimento gmail com>
Date:   Mon Jan 9 21:49:04 2017 -0800

    WIP - mozjs38

 configure.ac                      |    2 +-
 gi/arg.cpp                        |   23 ++--
 gi/boxed.cpp                      |   59 ++++----
 gi/closure.cpp                    |    2 +-
 gi/enumeration.cpp                |    3 +-
 gi/function.cpp                   |   62 +++-----
 gi/function.h                     |    2 +-
 gi/fundamental.cpp                |  144 ++++++++---------
 gi/gerror.cpp                     |   28 ++--
 gi/interface.cpp                  |   50 +++---
 gi/ns.cpp                         |   67 ++++-----
 gi/object.cpp                     |  163 +++++++++++--------
 gi/param.cpp                      |   38 ++---
 gi/repo.cpp                       |   76 ++++-----
 gi/union.cpp                      |  120 +++++++-------
 gjs/byteArray.cpp                 |   19 ++-
 gjs/context.cpp                   |    5 +-
 gjs/coverage.cpp                  |   16 +-
 gjs/importer.cpp                  |  325 +++++++++++++------------------------
 gjs/jsapi-constructor-proxy.cpp   |   32 +++--
 gjs/jsapi-dynamic-class.cpp       |    9 +-
 gjs/jsapi-util-string.cpp         |   11 +-
 gjs/jsapi-util.cpp                |   26 ++--
 gjs/jsapi-util.h                  |   26 ++--
 gjs/jsapi-wrapper.h               |    4 +-
 gjs/runtime.cpp                   |   14 +-
 gjs/stack.cpp                     |   10 +-
 modules/cairo-context.cpp         |    2 +-
 modules/cairo-image-surface.cpp   |    4 +-
 modules/cairo-linear-gradient.cpp |    2 +-
 modules/cairo-path.cpp            |    2 +-
 modules/cairo-pdf-surface.cpp     |    2 +-
 modules/cairo-ps-surface.cpp      |    2 +-
 modules/cairo-radial-gradient.cpp |    2 +-
 modules/cairo-region.cpp          |    5 +-
 modules/cairo-solid-pattern.cpp   |    2 +-
 modules/cairo-surface-pattern.cpp |    2 +-
 modules/cairo-surface.cpp         |    2 +-
 modules/cairo-svg-surface.cpp     |    2 +-
 modules/cairo.cpp                 |    2 +-
 modules/console.cpp               |    4 +-
 modules/system.cpp                |   10 +-
 test/gjs-test-utils.cpp           |    2 +-
 43 files changed, 630 insertions(+), 753 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 84adfe7..61ae200 100644
--- a/configure.ac
+++ b/configure.ac
@@ -58,7 +58,7 @@ GOBJECT_INTROSPECTION_REQUIRE([1.41.4])
 
 GOBJECT_REQUIREMENT="gobject-2.0 >= glib_required_version"
 gjs_base_packages="$GOBJECT_REQUIREMENT gio-2.0"
-common_packages="gthread-2.0 gio-2.0 >= glib_required_version mozjs-31"
+common_packages="gthread-2.0 gio-2.0 >= glib_required_version mozjs-38"
 gjs_packages="gobject-introspection-1.0 libffi $common_packages"
 gjs_cairo_packages="cairo cairo-gobject $common_packages"
 gjs_gtk_packages="gtk+-3.0 >= 3.20"
diff --git a/gi/arg.cpp b/gi/arg.cpp
index 8f6ba96..d6f9c3c 100644
--- a/gi/arg.cpp
+++ b/gi/arg.cpp
@@ -574,7 +574,7 @@ gjs_array_from_strv(JSContext             *context,
 
     for (i = 0; strv[i] != NULL; i++) {
         elems.growBy(1);
-        if (!gjs_string_from_utf8(context, strv[i], -1, elems.handleAt(i)))
+        if (!gjs_string_from_utf8(context, strv[i], -1, elems[i]))
             return false;
     }
 
@@ -959,7 +959,7 @@ gjs_array_from_flat_gvalue_array(JSContext             *context,
 
     for (i = 0; i < length; i ++) {
         GValue *gvalue = &values[i];
-        result = gjs_value_from_g_value(context, elems.handleAt(i), gvalue);
+        result = gjs_value_from_g_value(context, elems[i], gvalue);
         if (!result)
             break;
     }
@@ -2156,8 +2156,7 @@ gjs_array_from_g_list (JSContext             *context,
             arg.v_pointer = list->data;
             elems.growBy(1);
 
-            if (!gjs_value_from_g_argument(context, elems.handleAt(i),
-                                           param_info, &arg,
+            if (!gjs_value_from_g_argument(context, elems[i], param_info, &arg,
                                            true))
                 return false;
             ++i;
@@ -2167,8 +2166,7 @@ gjs_array_from_g_list (JSContext             *context,
             arg.v_pointer = slist->data;
             elems.growBy(1);
 
-            if (!gjs_value_from_g_argument(context, elems.handleAt(i),
-                                           param_info, &arg,
+            if (!gjs_value_from_g_argument(context, elems[i], param_info, &arg,
                                            true))
                 return false;
             ++i;
@@ -2225,8 +2223,8 @@ gjs_array_from_carray_internal (JSContext             *context,
 #define ITERATE(type) \
     for (i = 0; i < length; i++) { \
         arg.v_##type = *(((g##type*)array) + i);                         \
-        if (!gjs_value_from_g_argument(context, elems.handleAt(i),       \
-                                       param_info, &arg, true))          \
+        if (!gjs_value_from_g_argument(context, elems[i], param_info,    \
+                                       &arg, true))                      \
             return false; \
     }
 
@@ -2285,8 +2283,8 @@ gjs_array_from_carray_internal (JSContext             *context,
               for (i = 0; i < length; i++) {
                   arg.v_pointer = ((char*)array) + (struct_size * i);
 
-                  if (!gjs_value_from_g_argument(context, elems.handleAt(i),
-                                                 param_info, &arg, true))
+                  if (!gjs_value_from_g_argument(context, elems[i], param_info,
+                                                 &arg, true))
                       return false;
               }
 
@@ -2441,7 +2439,7 @@ gjs_array_from_zero_terminated_c_array (JSContext             *context,
         for (i = 0; array[i]; i++) { \
             arg.v_##type = array[i]; \
             elems.growBy(1);                                            \
-            if (!gjs_value_from_g_argument(context, elems.handleAt(i),  \
+            if (!gjs_value_from_g_argument(context, elems[i],           \
                                            param_info, &arg, true))     \
                 return false; \
         } \
@@ -2531,8 +2529,7 @@ gjs_object_from_g_hash (JSContext             *context,
         return true;
     }
 
-    JS::RootedObject obj(context,
-        JS_NewObject(context, NULL, JS::NullPtr(), JS::NullPtr()));
+    JS::RootedObject obj(context, JS_NewObject(context, NULL));
     if (obj == NULL)
         return false;
 
diff --git a/gi/boxed.cpp b/gi/boxed.cpp
index f858531..c32f009 100644
--- a/gi/boxed.cpp
+++ b/gi/boxed.cpp
@@ -110,24 +110,25 @@ gjs_define_static_methods(JSContext       *context,
  * if id was resolved.
  */
 static bool
-boxed_new_resolve(JSContext *context,
-                  JS::HandleObject obj,
-                  JS::HandleId id,
-                  JS::MutableHandleObject objp)
+boxed_resolve(JSContext       *context,
+              JS::HandleObject obj,
+              JS::HandleId     id,
+              bool            *resolved)
 {
     Boxed *priv;
-    char *name;
-    bool ret = false;
+    g_autofree char *name = NULL;
 
-    if (!gjs_get_string_id(context, id, &name))
-        return true; /* not resolved, but no error */
+    if (!gjs_get_string_id(context, id, &name)) {
+        *resolved = false;
+        return true;
+    }
 
     priv = priv_from_js(context, obj);
     gjs_debug_jsprop(GJS_DEBUG_GBOXED, "Resolve prop '%s' hook obj %p priv %p",
                      name, obj.get(), priv);
 
     if (priv == NULL)
-        goto out; /* wrong class */
+        return false; /* wrong class */
 
     if (priv->gboxed == NULL) {
         /* We are the prototype, so look for methods and other class properties */
@@ -155,10 +156,12 @@ boxed_new_resolve(JSContext *context,
                 if (gjs_define_function(context, obj, priv->gtype,
                                         (GICallableInfo *)method_info) == NULL) {
                     g_base_info_unref( (GIBaseInfo*) method_info);
-                    goto out;
+                    return false;
                 }
 
-                objp.set(obj); /* we defined the prop in object_proto */
+                *resolved = true;
+            } else {
+                *resolved = false;
             }
 
             g_base_info_unref( (GIBaseInfo*) method_info);
@@ -171,12 +174,9 @@ boxed_new_resolve(JSContext *context,
          * see any changes made from C. So we use the get/set prop
          * hooks, not this resolve hook.
          */
+        *resolved = false;
     }
-    ret = true;
-
- out:
-    g_free(name);
-    return ret;
+    return true;
 }
 
 /* Check to see if JS::Value passed in is another Boxed object of the same,
@@ -842,8 +842,8 @@ define_boxed_class_fields (JSContext       *context,
         bool result;
 
         result = JS_DefineProperty(context, proto, field_name, JS::NullHandleValue,
-                                   JSPROP_PERMANENT | JSPROP_SHARED,
-                                   boxed_field_getter, boxed_field_setter);
+                                   JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_PROPOP_ACCESSORS,
+                                   (JSNative) boxed_field_getter, (JSNative) boxed_field_setter);
 
         g_base_info_unref ((GIBaseInfo *)field);
 
@@ -873,10 +873,10 @@ boxed_trace(JSTracer *tracer,
     if (priv == NULL)
         return;
 
-    JS_CallHeapIdTracer(tracer, &priv->zero_args_constructor_name,
-                        "Boxed::zero_args_constructor_name");
-    JS_CallHeapIdTracer(tracer, &priv->default_constructor_name,
-                        "Boxed::default_constructor_name");
+    JS_CallIdTracer(tracer, &priv->zero_args_constructor_name,
+                    "Boxed::zero_args_constructor_name");
+    JS_CallIdTracer(tracer, &priv->default_constructor_name,
+                    "Boxed::default_constructor_name");
 }
 
 /* The bizarre thing about this vtable is that it applies to both
@@ -891,16 +891,15 @@ boxed_trace(JSTracer *tracer,
 struct JSClass gjs_boxed_class = {
     "GObject_Boxed",
     JSCLASS_HAS_PRIVATE |
-    JSCLASS_NEW_RESOLVE |
     JSCLASS_IMPLEMENTS_BARRIERS |
     JSCLASS_HAS_RESERVED_SLOTS(1),
-    JS_PropertyStub,
-    JS_DeletePropertyStub,
-    JS_PropertyStub,
-    JS_StrictPropertyStub,
-    JS_EnumerateStub,
-    (JSResolveOp) boxed_new_resolve, /* needs cast since it's the new resolve signature */
-    JS_ConvertStub,
+    NULL,  /* addProperty */
+    NULL,  /* deleteProperty */
+    NULL,  /* getProperty */
+    NULL,  /* setProperty */
+    NULL,  /* enumerate */
+    boxed_resolve,
+    NULL,  /* convert */
     boxed_finalize,
     NULL,  /* call */
     NULL,  /* hasInstance */
diff --git a/gi/closure.cpp b/gi/closure.cpp
index 829a436..7925835 100644
--- a/gi/closure.cpp
+++ b/gi/closure.cpp
@@ -338,7 +338,7 @@ gjs_closure_trace(GClosure *closure,
     if (c->obj == NULL)
         return;
 
-    JS_CallHeapObjectTracer(tracer, &c->obj, "signal connection");
+    JS_CallObjectTracer(tracer, &c->obj, "signal connection");
 }
 
 GClosure*
diff --git a/gi/enumeration.cpp b/gi/enumeration.cpp
index d73622e..9d0eeb4 100644
--- a/gi/enumeration.cpp
+++ b/gi/enumeration.cpp
@@ -165,8 +165,7 @@ gjs_define_enumeration(JSContext       *context,
 
     enum_name = g_base_info_get_name( (GIBaseInfo*) info);
 
-    JS::RootedObject enum_obj(context, JS_NewObject(context, NULL, JS::NullPtr(),
-                                                    global));
+    JS::RootedObject enum_obj(context, JS_NewObject(context, NULL, global));
     if (enum_obj == NULL) {
         g_error("Could not create enumeration %s.%s",
                        g_base_info_get_namespace( (GIBaseInfo*) info),
diff --git a/gi/function.cpp b/gi/function.cpp
index 76aa885..6d161c9 100644
--- a/gi/function.cpp
+++ b/gi/function.cpp
@@ -83,14 +83,7 @@ gjs_callback_trampoline_unref(GjsCallbackTrampoline *trampoline)
 
     trampoline->ref_count--;
     if (trampoline->ref_count == 0) {
-        JSContext *context = trampoline->context;
-
-        if (!trampoline->is_vfunc) {
-            JS_BeginRequest(context);
-            JS::RemoveValueRoot(context, &trampoline->js_function);
-            JS_EndRequest(context);
-        }
-
+        delete trampoline->js_function;
         g_callable_info_free_closure(trampoline->info, trampoline->closure);
         g_base_info_unref( (GIBaseInfo*) trampoline->info);
         g_free (trampoline->param_types);
@@ -208,7 +201,7 @@ gjs_callback_closure(ffi_cif *cif,
     }
 
     JS_BeginRequest(context);
-    func_obj = &trampoline->js_function.toObject();
+    func_obj = &trampoline->js_function->toObject();
     JSAutoCompartment ac(context, func_obj);
 
     n_args = g_callable_info_get_n_args(trampoline->info);
@@ -219,7 +212,6 @@ gjs_callback_closure(ffi_cif *cif,
     JS::AutoValueVector jsargs(context);
     jsargs.reserve(n_args);
     JS::RootedValue rval(context);
-    JS::RootedValue rooted_function(context, trampoline->js_function);
     JS::RootedObject this_object(context);
 
     for (i = 0, n_jsargs = 0; i < n_args; i++) {
@@ -261,15 +253,14 @@ gjs_callback_closure(ffi_cif *cif,
                     goto out;
 
                 jsargs.growBy(1);
-                if (!gjs_value_from_explicit_array(context, jsargs.handleAt(n_jsargs++),
+                if (!gjs_value_from_explicit_array(context, jsargs[n_jsargs++],
                                                    &type_info, (GArgument*) args[i], length.toInt32()))
                     goto out;
                 break;
             }
             case PARAM_NORMAL:
                 jsargs.growBy(1);
-                if (!gjs_value_from_g_argument(context,
-                                               jsargs.handleAt(n_jsargs++),
+                if (!gjs_value_from_g_argument(context, jsargs[n_jsargs++],
                                                &type_info,
                                                (GArgument *) args[i], false))
                     goto out;
@@ -291,7 +282,7 @@ gjs_callback_closure(ffi_cif *cif,
 
     if (!JS_CallFunctionValue(context,
                               this_object,
-                              rooted_function,
+                              *trampoline->js_function,
                               jsargs,
                               &rval)) {
         goto out;
@@ -454,9 +445,7 @@ gjs_callback_trampoline_new(JSContext      *context,
     trampoline->context = context;
     trampoline->info = callable_info;
     g_base_info_ref((GIBaseInfo*)trampoline->info);
-    trampoline->js_function = function;
-    if (!is_vfunc)
-        JS::AddValueRoot(context, &trampoline->js_function);
+    trampoline->js_function = new JS::PersistentRootedValue(context, function);
 
     /* Analyze param types and directions, similarly to init_cached_function_data */
     n_args = g_callable_info_get_n_args(trampoline->info);
@@ -1010,7 +999,7 @@ gjs_invoke_c_function(JSContext                              *context,
         did_throw_gerror = false;
     }
 
-    if (!js_rval.empty())
+    if (js_rval)
         js_rval.ref().setUndefined();
 
     /* Only process return values if the function didn't throw */
@@ -1040,9 +1029,9 @@ gjs_invoke_c_function(JSContext                              *context,
                                                         &arg_type_info,
                                                         &out_arg_cvalues[array_length_pos],
                                                         true);
-                if (!arg_failed && !js_rval.empty()) {
+                if (!arg_failed && js_rval) {
                     arg_failed = !gjs_value_from_explicit_array(context,
-                                                                return_values.handleAt(next_rval),
+                                                                return_values[next_rval],
                                                                 &return_info,
                                                                 &return_gargument,
                                                                 length.toInt32());
@@ -1056,9 +1045,9 @@ gjs_invoke_c_function(JSContext                              *context,
                                                       &return_gargument))
                     failed = true;
             } else {
-                if (!js_rval.empty())
+                if (js_rval)
                     arg_failed = !gjs_value_from_g_argument(context,
-                                                            return_values.handleAt(next_rval),
+                                                            return_values[next_rval],
                                                             &return_info, &return_gargument,
                                                             true);
                 /* Free GArgument, the JS::Value should have ref'd or copied it */
@@ -1173,7 +1162,7 @@ release:
 
             array_length_pos = g_type_info_get_array_length(&arg_type_info);
 
-            if (!js_rval.empty()) {
+            if (js_rval) {
                 if (array_length_pos >= 0) {
                     GIArgInfo array_length_arg;
                     GITypeInfo array_length_type_info;
@@ -1187,14 +1176,14 @@ release:
                                                             true);
                     if (!arg_failed) {
                         arg_failed = !gjs_value_from_explicit_array(context,
-                                                                    return_values.handleAt(next_rval),
+                                                                    return_values[next_rval],
                                                                     &arg_type_info,
                                                                     arg,
                                                                     array_length.toInt32());
                     }
                 } else {
                     arg_failed = !gjs_value_from_g_argument(context,
-                                                            return_values.handleAt(next_rval),
+                                                            return_values[next_rval],
                                                             &arg_type_info,
                                                             arg,
                                                             true);
@@ -1267,7 +1256,7 @@ release:
          * on its own, otherwise return a JavaScript array with
          * [return value, out arg 1, out arg 2, ...]
          */
-        if (!js_rval.empty()) {
+        if (js_rval) {
             if (function->js_out_argc == 1) {
                 js_rval.ref().set(return_values[0]);
             } else {
@@ -1317,8 +1306,7 @@ function_call(JSContext *context,
         return true; /* we are the prototype, or have the wrong class */
 
     /* COMPAT: mozilla::Maybe gains a much more usable API in future versions */
-    mozilla::Maybe<JS::MutableHandleValue> m_retval;
-    m_retval.construct(&retval);
+    mozilla::Maybe<JS::MutableHandleValue> m_retval(mozilla::Some<JS::MutableHandleValue>(&retval));
     success = gjs_invoke_c_function(context, priv, object, js_argv, m_retval,
                                     NULL);
     if (success)
@@ -1463,13 +1451,13 @@ struct JSClass gjs_function_class = {
     "GIRepositoryFunction", /* means "new GIRepositoryFunction()" works */
     JSCLASS_HAS_PRIVATE |
     JSCLASS_BACKGROUND_FINALIZE,
-    JS_PropertyStub,
-    JS_DeletePropertyStub,
-    JS_PropertyStub,
-    JS_StrictPropertyStub,
-    JS_EnumerateStub,
-    JS_ResolveStub,
-    JS_ConvertStub,
+    NULL,  /* addProperty */
+    NULL,  /* deleteProperty */
+    NULL,  /* getProperty */
+    NULL,  /* setProperty */
+    NULL,  /* enumerate */
+    NULL,  /* resolve */
+    NULL,  /* convert */
     function_finalize,
     function_call
 };
@@ -1687,7 +1675,7 @@ function_new(JSContext      *context,
     }
 
     JS::RootedObject function(context,
-        JS_NewObject(context, &gjs_function_class, JS::NullPtr(), global));
+        JS_NewObject(context, &gjs_function_class, global));
     if (function == NULL) {
         gjs_debug(GJS_DEBUG_GFUNCTION, "Failed to construct function");
         return NULL;
@@ -1768,7 +1756,7 @@ gjs_invoke_c_function_uncached(JSContext                  *context,
 
   /* COMPAT: mozilla::Maybe gains a much more usable API in future versions */
   mozilla::Maybe<JS::MutableHandleValue> m_rval;
-  m_rval.construct(rval);
+  m_rval.emplace(rval);
   result = gjs_invoke_c_function(context, &function, obj, args, m_rval, NULL);
   uninit_cached_function_data (&function);
   return result;
diff --git a/gi/function.h b/gi/function.h
index 234b551..58e3922 100644
--- a/gi/function.h
+++ b/gi/function.h
@@ -45,7 +45,7 @@ typedef struct {
     gint ref_count;
     JSContext *context;
     GICallableInfo *info;
-    JS::Heap<JS::Value> js_function;
+    JS::PersistentRootedValue *js_function;
     ffi_cif cif;
     ffi_closure *closure;
     GIScopeType scope;
diff --git a/gi/fundamental.cpp b/gi/fundamental.cpp
index d7b3f1f..6e2d3ac 100644
--- a/gi/fundamental.cpp
+++ b/gi/fundamental.cpp
@@ -224,11 +224,11 @@ find_fundamental_constructor(JSContext    *context,
 /**/
 
 static bool
-fundamental_instance_new_resolve_interface(JSContext    *context,
-                                           JS::HandleObject obj,
-                                           JS::MutableHandleObject objp,
-                                           Fundamental  *proto_priv,
-                                           char         *name)
+fundamental_instance_resolve_interface(JSContext       *context,
+                                       JS::HandleObject obj,
+                                       bool            *resolved,
+                                       Fundamental     *proto_priv,
+                                       char            *name)
 {
     GIFunctionInfo *method_info;
     bool ret;
@@ -263,7 +263,7 @@ fundamental_instance_new_resolve_interface(JSContext    *context,
                 if (gjs_define_function(context, obj,
                                         proto_priv->gtype,
                                         (GICallableInfo *) method_info)) {
-                    objp.set(obj);
+                    *resolved = true;
                 } else {
                     ret = false;
                 }
@@ -278,22 +278,22 @@ fundamental_instance_new_resolve_interface(JSContext    *context,
 }
 
 /*
- * The *objp out parameter, on success, should be null to indicate that id
- * was not resolved; and non-null, referring to obj or one of its prototypes,
- * if id was resolved.
+ * The *resolved out parameter, on success, should be false to indicate that id
+ * was not resolved; and true if id was resolved.
  */
 static bool
-fundamental_instance_new_resolve(JSContext  *context,
-                                 JS::HandleObject obj,
-                                 JS::HandleId id,
-                                 JS::MutableHandleObject objp)
+fundamental_instance_resolve(JSContext       *context,
+                             JS::HandleObject obj,
+                             JS::HandleId     id,
+                             bool            *resolved)
 {
     FundamentalInstance *priv;
-    char *name;
-    bool ret = false;
+    g_autofree char *name = NULL;
 
-    if (!gjs_get_string_id(context, id, &name))
+    if (!gjs_get_string_id(context, id, &name)) {
+        *resolved = false;
         return true; /* not resolved, but no error */
+    }
 
     priv = priv_from_js(context, obj);
     gjs_debug_jsprop(GJS_DEBUG_GFUNDAMENTAL,
@@ -301,71 +301,70 @@ fundamental_instance_new_resolve(JSContext  *context,
                      name, obj.get(), priv);
 
     if (priv == NULL)
-        goto out; /* wrong class */
+        return false; /* wrong class */
 
-    if (priv->prototype == NULL) {
-        /* We are the prototype, so look for methods and other class properties */
-        Fundamental *proto_priv = (Fundamental *) priv;
-        GIFunctionInfo *method_info;
+    if (priv->prototype != NULL) {
+        /* We are an instance, not a prototype, so look for
+         * per-instance props that we want to define on the
+         * JSObject. Generally we do not want to cache these in JS, we
+         * want to always pull them from the C object, or JS would not
+         * see any changes made from C. So we use the get/set prop
+         * hooks, not this resolve hook.
+         */
+        *resolved = false;
+        return true;
+    }
 
-        method_info = g_object_info_find_method((GIStructInfo*) proto_priv->info,
-                                                name);
+    /* We are the prototype, so look for methods and other class properties */
+    Fundamental *proto_priv = (Fundamental *) priv;
+    GIFunctionInfo *method_info;
 
-        if (method_info != NULL) {
-            const char *method_name;
+    method_info = g_object_info_find_method((GIStructInfo*) proto_priv->info,
+                                            name);
+
+    if (method_info != NULL) {
+        const char *method_name;
 
 #if GJS_VERBOSE_ENABLE_GI_USAGE
-            _gjs_log_info_usage((GIBaseInfo *) method_info);
+        _gjs_log_info_usage((GIBaseInfo *) method_info);
 #endif
-            if (g_function_info_get_flags (method_info) & GI_FUNCTION_IS_METHOD) {
-                method_name = g_base_info_get_name((GIBaseInfo *) method_info);
-
-                /* we do not define deprecated methods in the prototype */
-                if (g_base_info_is_deprecated((GIBaseInfo *) method_info)) {
-                    gjs_debug(GJS_DEBUG_GFUNDAMENTAL,
-                              "Ignoring definition of deprecated method %s in prototype %s.%s",
-                              method_name,
-                              g_base_info_get_namespace((GIBaseInfo *) proto_priv->info),
-                              g_base_info_get_name((GIBaseInfo *) proto_priv->info));
-                    g_base_info_unref((GIBaseInfo *) method_info);
-                    ret = true;
-                    goto out;
-                }
+        if (g_function_info_get_flags (method_info) & GI_FUNCTION_IS_METHOD) {
+            method_name = g_base_info_get_name((GIBaseInfo *) method_info);
 
+            /* we do not define deprecated methods in the prototype */
+            if (g_base_info_is_deprecated((GIBaseInfo *) method_info)) {
                 gjs_debug(GJS_DEBUG_GFUNDAMENTAL,
-                          "Defining method %s in prototype for %s.%s",
+                          "Ignoring definition of deprecated method %s in prototype %s.%s",
                           method_name,
                           g_base_info_get_namespace((GIBaseInfo *) proto_priv->info),
                           g_base_info_get_name((GIBaseInfo *) proto_priv->info));
+                g_base_info_unref((GIBaseInfo *) method_info);
+                *resolved = false;
+                return true;
+            }
 
-                if (gjs_define_function(context, obj, proto_priv->gtype,
-                                        method_info) == NULL) {
-                    g_base_info_unref((GIBaseInfo *) method_info);
-                    goto out;
-                }
+            gjs_debug(GJS_DEBUG_GFUNDAMENTAL,
+                      "Defining method %s in prototype for %s.%s",
+                      method_name,
+                      g_base_info_get_namespace((GIBaseInfo *) proto_priv->info),
+                      g_base_info_get_name((GIBaseInfo *) proto_priv->info));
 
-                objp.set(obj);
+            if (gjs_define_function(context, obj, proto_priv->gtype,
+                                    method_info) == NULL) {
+                g_base_info_unref((GIBaseInfo *) method_info);
+                return false;
             }
 
-            g_base_info_unref((GIBaseInfo *) method_info);
+            *resolved = true;
         }
 
-        ret = fundamental_instance_new_resolve_interface(context, obj, objp,
-                                                         proto_priv, name);
+        g_base_info_unref((GIBaseInfo *) method_info);
     } else {
-        /* We are an instance, not a prototype, so look for
-         * per-instance props that we want to define on the
-         * JSObject. Generally we do not want to cache these in JS, we
-         * want to always pull them from the C object, or JS would not
-         * see any changes made from C. So we use the get/set prop
-         * hooks, not this resolve hook.
-         */
+        *resolved = false;
     }
 
-    ret = true;
- out:
-    g_free(name);
-    return ret;
+    return fundamental_instance_resolve_interface(context, obj, resolved,
+                                                  proto_priv, name);
 }
 
 static bool
@@ -381,7 +380,7 @@ fundamental_invoke_constructor(FundamentalInstance        *priv,
 
     if (!gjs_object_require_property_value(context, obj, NULL,
                                            constructor_const, &js_constructor) ||
-        priv->prototype->constructor_name == JSID_VOID) {
+        priv->prototype->constructor_name.get() == JSID_VOID) {
         gjs_throw (context,
                    "Couldn't find a constructor for type %s.%s",
                    g_base_info_get_namespace((GIBaseInfo*) priv->prototype->info),
@@ -517,8 +516,8 @@ fundamental_trace(JSTracer *tracer,
     if (priv == NULL)
         return;
 
-    JS_CallHeapIdTracer(tracer, &priv->constructor_name,
-                        "Fundamental::constructor_name");
+    JS_CallIdTracer(tracer, &priv->constructor_name,
+                    "Fundamental::constructor_name");
 }
 
 /* The bizarre thing about this vtable is that it applies to both
@@ -538,15 +537,14 @@ fundamental_trace(JSTracer *tracer,
 struct JSClass gjs_fundamental_instance_class = {
     "GFundamental_Object",
     JSCLASS_HAS_PRIVATE |
-    JSCLASS_IMPLEMENTS_BARRIERS |
-    JSCLASS_NEW_RESOLVE,
-    JS_PropertyStub,
-    JS_DeletePropertyStub,
-    JS_PropertyStub,
-    JS_StrictPropertyStub,
-    JS_EnumerateStub,
-    (JSResolveOp) fundamental_instance_new_resolve, /* needs cast since it's the new resolve signature */
-    JS_ConvertStub,
+    JSCLASS_IMPLEMENTS_BARRIERS,
+    NULL,  /* addProperty */
+    NULL,  /* deleteProperty */
+    NULL,  /* getProperty */
+    NULL,  /* setProperty */
+    NULL,  /* enumerate */
+    fundamental_instance_resolve,
+    NULL,  /* convert */
     fundamental_finalize,
     NULL,  /* call */
     NULL,  /* hasInstance */
diff --git a/gi/gerror.cpp b/gi/gerror.cpp
index 4e7e5c6..d8ec0f3 100644
--- a/gi/gerror.cpp
+++ b/gi/gerror.cpp
@@ -276,15 +276,14 @@ error_constructor_value_of(JSContext *context,
 struct JSClass gjs_error_class = {
     "GLib_Error",
     JSCLASS_HAS_PRIVATE |
-    JSCLASS_NEW_RESOLVE |
     JSCLASS_BACKGROUND_FINALIZE,
-    JS_PropertyStub,
-    JS_DeletePropertyStub,
-    JS_PropertyStub,
-    JS_StrictPropertyStub,
-    JS_EnumerateStub,
-    JS_ResolveStub,
-    JS_ConvertStub,
+    NULL,  /* addProperty */
+    NULL,  /* deleteProperty */
+    NULL,  /* getProperty */
+    NULL,  /* setProperty */
+    NULL,  /* enumerate */
+    NULL,  /* resolve */
+    NULL,  /* convert */
     error_finalize
 };
 
@@ -401,10 +400,9 @@ define_error_properties(JSContext       *context,
 {
     JS::RootedValue stack(context), fileName(context), lineNumber(context);
     /* COMPAT: mozilla::Maybe gains a much more usable API in future versions */
-    mozilla::Maybe<JS::MutableHandleValue> m_stack, m_file, m_line;
-    m_stack.construct(&stack);
-    m_file.construct(&fileName);
-    m_line.construct(&lineNumber);
+    auto m_stack = mozilla::Some<JS::MutableHandleValue>(&stack);
+    auto m_file = mozilla::Some<JS::MutableHandleValue>(&fileName);
+    auto m_line = mozilla::Some<JS::MutableHandleValue>(&lineNumber);
 
     if (!gjs_context_get_frame_info(context, m_stack, m_file, m_line))
         return;
@@ -417,13 +415,13 @@ define_error_properties(JSContext       *context,
         gjs_context_get_const_string(context, GJS_STRING_LINE_NUMBER));
 
     JS_DefinePropertyById(context, obj, stack_name, stack,
-                          NULL, NULL, JSPROP_ENUMERATE);
+                          JSPROP_ENUMERATE);
 
     JS_DefinePropertyById(context, obj, filename_name, fileName,
-                          NULL, NULL, JSPROP_ENUMERATE);
+                          JSPROP_ENUMERATE);
 
     JS_DefinePropertyById(context, obj, linenumber_name, lineNumber,
-                          NULL, NULL, JSPROP_ENUMERATE);
+                          JSPROP_ENUMERATE);
 }
 
 JSObject*
diff --git a/gi/interface.cpp b/gi/interface.cpp
index 0347812..51f6574 100644
--- a/gi/interface.cpp
+++ b/gi/interface.cpp
@@ -105,30 +105,31 @@ gjs_define_static_methods(JSContext       *context,
 }
 
 static bool
-interface_new_resolve(JSContext *context,
-                      JS::HandleObject obj,
-                      JS::HandleId id,
-                      JS::MutableHandleObject objp)
+interface_resolve(JSContext       *context,
+                  JS::HandleObject obj,
+                  JS::HandleId     id,
+                  bool            *resolved)
 {
     Interface *priv;
-    char *name;
-    bool ret = false;
+    g_autofree char *name = NULL;
     GIFunctionInfo *method_info;
 
-    if (!gjs_get_string_id(context, id, &name))
+    if (!gjs_get_string_id(context, id, &name)) {
+        *resolved = false;
         return true;
+    }
 
     priv = priv_from_js(context, obj);
 
     if (priv == NULL)
-        goto out;
+        return false;
 
     /* If we have no GIRepository information then this interface was defined
      * from within GJS. In that case, it has no properties that need to be
      * resolved from within C code, as interfaces cannot inherit. */
     if (priv->info == NULL) {
-        ret = true;
-        goto out;
+        *resolved = false;
+        return true;
     }
 
     method_info = g_interface_info_find_method((GIInterfaceInfo*) priv->info, name);
@@ -139,34 +140,33 @@ interface_new_resolve(JSContext *context,
                                     priv->gtype,
                                     (GICallableInfo*)method_info) == NULL) {
                 g_base_info_unref((GIBaseInfo*)method_info);
-                goto out;
+                return false;
             }
 
-            objp.set(obj);
+            *resolved = true;
+        } else {
+            *resolved = false;
         }
 
         g_base_info_unref((GIBaseInfo*)method_info);
+    } else {
+        *resolved = false;
     }
 
-    ret = true;
-
- out:
-    g_free (name);
-    return ret;
+    return true;
 }
 
 struct JSClass gjs_interface_class = {
     "GObject_Interface",
     JSCLASS_HAS_PRIVATE |
-    JSCLASS_NEW_RESOLVE |
     JSCLASS_BACKGROUND_FINALIZE,
-    JS_PropertyStub,
-    JS_DeletePropertyStub,
-    JS_PropertyStub,
-    JS_StrictPropertyStub,
-    JS_EnumerateStub,
-    (JSResolveOp) interface_new_resolve,
-    JS_ConvertStub,
+    NULL,  /* addProperty */
+    NULL,  /* deleteProperty */
+    NULL,  /* getProperty */
+    NULL,  /* setProperty */
+    NULL,  /* enumerate */
+    interface_resolve,
+    NULL,  /* convert */
     interface_finalize
 };
 
diff --git a/gi/ns.cpp b/gi/ns.cpp
index 2930db7..3ebbf17 100644
--- a/gi/ns.cpp
+++ b/gi/ns.cpp
@@ -48,26 +48,27 @@ GJS_DEFINE_PRIV_FROM_JS(Ns, gjs_ns_class)
  * if id was resolved.
  */
 static bool
-ns_new_resolve(JSContext *context,
-               JS::HandleObject obj,
-               JS::HandleId id,
-               JS::MutableHandleObject objp)
+ns_resolve(JSContext       *context,
+           JS::HandleObject obj,
+           JS::HandleId     id,
+           bool            *resolved)
 {
     Ns *priv;
-    char *name;
+    g_autofree char *name = NULL;
     GIRepository *repo;
     GIBaseInfo *info;
-    bool ret = false;
     bool defined;
 
-    if (!gjs_get_string_id(context, id, &name))
+    if (!gjs_get_string_id(context, id, &name)) {
+        *resolved = false;
         return true; /* not resolved, but no error */
+    }
 
     /* let Object.prototype resolve these */
     if (strcmp(name, "valueOf") == 0 ||
         strcmp(name, "toString") == 0) {
-        ret = true;
-        goto out;
+        *resolved = false;
+        return true;
     }
 
     priv = priv_from_js(context, obj);
@@ -76,20 +77,18 @@ ns_new_resolve(JSContext *context,
                      name, obj.get(), priv);
 
     if (priv == NULL) {
-        ret = true; /* we are the prototype, or have the wrong class */
-        goto out;
+        *resolved = false;  /* we are the prototype, or have the wrong class */
+        return true;
     }
 
-    JS_BeginRequest(context);
+    JSAutoRequest ar(context);
 
     repo = g_irepository_get_default();
 
     info = g_irepository_find_by_name(repo, priv->gi_namespace, name);
     if (info == NULL) {
-        /* No property defined, but no error either, so return true */
-        JS_EndRequest(context);
-        ret = true;
-        goto out;
+        *resolved = false; /* No property defined, but no error either */
+        return true;
     }
 
     gjs_debug(GJS_DEBUG_GNAMESPACE,
@@ -98,23 +97,19 @@ ns_new_resolve(JSContext *context,
               g_base_info_get_name(info),
               g_base_info_get_namespace(info));
 
-    if (gjs_define_info(context, obj, info, &defined)) {
-        g_base_info_unref(info);
-        if (defined)
-            objp.set(obj); /* we defined the property in this object */
-        ret = true;
-    } else {
+    if (!gjs_define_info(context, obj, info, &defined)) {
         gjs_debug(GJS_DEBUG_GNAMESPACE,
                   "Failed to define info '%s'",
                   g_base_info_get_name(info));
 
         g_base_info_unref(info);
+        return false;
     }
-    JS_EndRequest(context);
 
- out:
-    g_free(name);
-    return ret;
+    /* we defined the property in this object */
+    g_base_info_unref(info);
+    *resolved = true;
+    return true;
 }
 
 static bool
@@ -157,15 +152,14 @@ ns_finalize(JSFreeOp *fop,
  */
 struct JSClass gjs_ns_class = {
     "GIRepositoryNamespace",
-    JSCLASS_HAS_PRIVATE |
-    JSCLASS_NEW_RESOLVE,
-    JS_PropertyStub,
-    JS_DeletePropertyStub,
-    JS_PropertyStub,
-    JS_StrictPropertyStub,
-    JS_EnumerateStub,
-    (JSResolveOp) ns_new_resolve, /* needs cast since it's the new resolve signature */
-    JS_ConvertStub,
+    JSCLASS_HAS_PRIVATE,
+    NULL,  /* addProperty */
+    NULL,  /* deleteProperty */
+    NULL,  /* getProperty */
+    NULL,  /* setProperty */
+    NULL,  /* enumerate */
+    ns_resolve,
+    NULL,  /* convert */
     ns_finalize
 };
 
@@ -221,8 +215,7 @@ ns_new(JSContext    *context,
                   gjs_ns_class.name, prototype);
     }
 
-    JS::RootedObject ns(context, JS_NewObject(context, &gjs_ns_class,
-                                              JS::NullPtr(), global));
+    JS::RootedObject ns(context, JS_NewObject(context, &gjs_ns_class, global));
     if (ns == NULL)
         g_error("No memory to create ns object");
 
diff --git a/gi/object.cpp b/gi/object.cpp
index 1c12073..ac8db9d 100644
--- a/gi/object.cpp
+++ b/gi/object.cpp
@@ -23,6 +23,7 @@
 
 #include <config.h>
 
+#include <deque>
 #include <memory>
 #include <stack>
 #include <string.h>
@@ -95,6 +96,11 @@ static GHashTable *class_init_properties;
 
 static GjsKeepAlive keep_alive_list;
 
+static bool weak_pointer_callback = false;
+/* Use std::deque here instead of std::vector so that elements don't have to
+ * get moved around when the storage size changes */
+static std::deque<GObject *> weak_pointer_list;
+
 extern struct JSClass gjs_object_instance_class;
 static GThread *gjs_eval_thread;
 static volatile gint pending_idle_toggles;
@@ -603,20 +609,20 @@ find_vfunc_on_parents(GIObjectInfo *info,
 }
 
 static bool
-object_instance_new_resolve_no_info(JSContext       *context,
-                                    JS::HandleObject obj,
-                                    JS::MutableHandleObject objp,
-                                    ObjectInstance  *priv,
-                                    char            *name)
+object_instance_resolve_no_info(JSContext       *context,
+                                JS::HandleObject obj,
+                                bool            *resolved,
+                                ObjectInstance  *priv,
+                                char            *name)
 {
     GIFunctionInfo *method_info;
     bool ret;
-    GType *interfaces;
     guint n_interfaces;
     guint i;
 
     ret = true;
-    interfaces = g_type_interfaces(priv->gtype, &n_interfaces);
+    *resolved = false;  /* technically we shouldn't touch this if returning false? */
+    g_autofree GType *interfaces = g_type_interfaces(priv->gtype, &n_interfaces);
     for (i = 0; i < n_interfaces; i++) {
         GIBaseInfo *base_info;
         GIInterfaceInfo *iface_info;
@@ -641,7 +647,8 @@ object_instance_new_resolve_no_info(JSContext       *context,
             if (g_function_info_get_flags (method_info) & GI_FUNCTION_IS_METHOD) {
                 if (gjs_define_function(context, obj, priv->gtype,
                                         (GICallableInfo *)method_info)) {
-                    objp.set(obj);
+                    *resolved = true;
+                    ret = true;
                 } else {
                     ret = false;
                 }
@@ -651,7 +658,6 @@ object_instance_new_resolve_no_info(JSContext       *context,
         }
     }
 
-    g_free(interfaces);
     return ret;
 }
 
@@ -661,18 +667,19 @@ object_instance_new_resolve_no_info(JSContext       *context,
  * if id was resolved.
  */
 static bool
-object_instance_new_resolve(JSContext *context,
-                            JS::HandleObject obj,
-                            JS::HandleId id,
-                            JS::MutableHandleObject objp)
+object_instance_resolve(JSContext       *context,
+                        JS::HandleObject obj,
+                        JS::HandleId     id,
+                        bool            *resolved)
 {
     GIFunctionInfo *method_info;
     ObjectInstance *priv;
-    char *name;
-    bool ret = false;
+    g_autofree char *name = NULL;
 
-    if (!gjs_get_string_id(context, id, &name))
+    if (!gjs_get_string_id(context, id, &name)) {
+        *resolved = false;
         return true; /* not resolved, but no error */
+    }
 
     priv = priv_from_js(context, obj);
 
@@ -695,21 +702,20 @@ object_instance_new_resolve(JSContext *context,
          * will run afterwards will fail because of the "priv == NULL"
          * check there.
          */
-        ret = true;
-        goto out;
+        *resolved = false;
+        return true;
     }
 
     if (priv->gobj != NULL) {
-        ret = true;
-        goto out;
+        *resolved = false;
+        return true;
     }
 
     /* If we have no GIRepository information (we're a JS GObject subclass),
      * we need to look at exposing interfaces. Look up our interfaces through
      * GType data, and then hope that *those* are introspectable. */
     if (priv->info == NULL) {
-        ret = object_instance_new_resolve_no_info(context, obj, objp, priv, name);
-        goto out;
+        return object_instance_resolve_no_info(context, obj, resolved, priv, name);
     }
 
     if (g_str_has_prefix (name, "vfunc_")) {
@@ -737,15 +743,14 @@ object_instance_new_resolve(JSContext *context,
              * prototypal inheritance take over. */
             if (defined_by_parent && is_vfunc_unchanged(vfunc, priv->gtype)) {
                 g_base_info_unref((GIBaseInfo *)vfunc);
-                ret = true;
-                goto out;
+                *resolved = false;
+                return true;
             }
 
             gjs_define_function(context, obj, priv->gtype, vfunc);
-            objp.set(obj);
+            *resolved = true;
             g_base_info_unref((GIBaseInfo *)vfunc);
-            ret = true;
-            goto out;
+            return true;
         }
 
         /* If the vfunc wasn't found, fall through, back to normal
@@ -772,38 +777,33 @@ object_instance_new_resolve(JSContext *context,
      * this could be done better.  See
      * https://bugzilla.gnome.org/show_bug.cgi?id=632922
      */
-    if (method_info == NULL) {
-        ret = object_instance_new_resolve_no_info(context, obj, objp,
-                                                  priv, name);
-        goto out;
-    } else {
+    if (method_info == NULL)
+        return object_instance_resolve_no_info(context, obj, resolved, priv, name);
+
 #if GJS_VERBOSE_ENABLE_GI_USAGE
-        _gjs_log_info_usage((GIBaseInfo*) method_info);
+    _gjs_log_info_usage((GIBaseInfo*) method_info);
 #endif
 
-        if (g_function_info_get_flags (method_info) & GI_FUNCTION_IS_METHOD) {
-            gjs_debug(GJS_DEBUG_GOBJECT,
-                      "Defining method %s in prototype for %s (%s.%s)",
-                      g_base_info_get_name( (GIBaseInfo*) method_info),
-                      g_type_name(priv->gtype),
-                      g_base_info_get_namespace( (GIBaseInfo*) priv->info),
-                      g_base_info_get_name( (GIBaseInfo*) priv->info));
-
-            if (gjs_define_function(context, obj, priv->gtype, method_info) == NULL) {
-                g_base_info_unref( (GIBaseInfo*) method_info);
-                goto out;
-            }
+    if (g_function_info_get_flags (method_info) & GI_FUNCTION_IS_METHOD) {
+        gjs_debug(GJS_DEBUG_GOBJECT,
+                  "Defining method %s in prototype for %s (%s.%s)",
+                  g_base_info_get_name( (GIBaseInfo*) method_info),
+                  g_type_name(priv->gtype),
+                  g_base_info_get_namespace( (GIBaseInfo*) priv->info),
+                  g_base_info_get_name( (GIBaseInfo*) priv->info));
 
-            objp.set(obj); /* we defined the prop in obj */
+        if (gjs_define_function(context, obj, priv->gtype, method_info) == NULL) {
+            g_base_info_unref( (GIBaseInfo*) method_info);
+            return false;
         }
 
-        g_base_info_unref( (GIBaseInfo*) method_info);
+        *resolved = true; /* we defined the prop in obj */
+    } else {
+        *resolved = false;
     }
 
-    ret = true;
- out:
-    g_free(name);
-    return ret;
+    g_base_info_unref( (GIBaseInfo*) method_info);
+    return true;
 }
 
 static void
@@ -1209,16 +1209,7 @@ wrapped_gobj_toggle_notify(gpointer      data,
                 g_error("toggling up object %s that's already queued to toggle up\n",
                         G_OBJECT_TYPE_NAME(gobj));
             }
-            if (is_sweeping) {
-                if (JS_IsAboutToBeFinalized(ensure_heap_wrapper(gobj))) {
-                    /* Ouch, the JS object is dead already. Disassociate the GObject
-                     * and hope the GObject dies too.
-                     */
-                    disassociate_js_gobject(gobj);
-                }
-            } else {
-                handle_toggle_up(gobj);
-            }
+            handle_toggle_up(gobj);
         } else {
             queue_toggle_idle(gobj, TOGGLE_UP);
         }
@@ -1287,6 +1278,34 @@ init_object_private (JSContext       *context,
 }
 
 static void
+update_heap_wrapper_weak_pointers(JSRuntime *rt,
+                                  gpointer   data)
+{
+    for (auto iter = weak_pointer_list.begin(); iter != weak_pointer_list.end();
+         iter++) {
+        GObject *gobj = *iter;
+        auto heap_wrapper = ensure_heap_wrapper(gobj);
+        JS_UpdateWeakPointerAfterGC(heap_wrapper);
+
+        if (heap_wrapper == NULL) {
+            /* Ouch, the JS object is dead already. Disassociate the GObject
+             * and hope the GObject dies too.
+             */
+            disassociate_js_gobject(gobj);
+            iter = weak_pointer_list.erase(iter);
+        }
+    }
+}
+
+static void
+ensure_weak_pointer_callback(JSContext *cx)
+{
+    if (!weak_pointer_callback)
+        JS_AddWeakPointerCallback(JS_GetRuntime(cx),
+                                  update_heap_wrapper_weak_pointers, NULL);
+}
+
+static void
 associate_js_gobject (JSContext       *context,
                       JS::HandleObject object,
                       GObject         *gobj)
@@ -1296,6 +1315,8 @@ associate_js_gobject (JSContext       *context,
     priv = priv_from_js(context, object);
     priv->gobj = gobj;
 
+    ensure_weak_pointer_callback(context);
+
     g_assert(peek_js_obj(gobj) == NULL);
     set_js_obj(gobj, object);
 
@@ -1883,15 +1904,14 @@ to_string_func(JSContext *context,
 struct JSClass gjs_object_instance_class = {
     "GObject_Object",
     JSCLASS_HAS_PRIVATE |
-    JSCLASS_IMPLEMENTS_BARRIERS |
-    JSCLASS_NEW_RESOLVE,
-    JS_PropertyStub,
-    JS_DeletePropertyStub,
+    JSCLASS_IMPLEMENTS_BARRIERS,
+    NULL,  /* addProperty */
+    NULL,  /* deleteProperty */
     object_instance_get_prop,
     object_instance_set_prop,
-    JS_EnumerateStub,
-    (JSResolveOp) object_instance_new_resolve, /* needs cast since it's the new resolve signature */
-    JS_ConvertStub,
+    NULL,  /* enumerate */
+    object_instance_resolve,
+    NULL,  /* convert */
     object_instance_finalize,
     NULL,
     NULL,
@@ -2132,7 +2152,7 @@ static void
 set_js_obj(GObject  *gobj,
            JSObject *obj)
 {
-    ensure_heap_wrapper(gobj)->set(obj);
+    *ensure_heap_wrapper(gobj) = obj;
 }
 
 static void
@@ -2545,8 +2565,7 @@ gjs_object_constructor (GType                  type,
     if (n_construct_properties) {
         guint i;
 
-        JS::RootedObject props_hash(context,
-            JS_NewObject(context, NULL, JS::NullPtr(), JS::NullPtr()));
+        JS::RootedObject props_hash(context, JS_NewObject(context, NULL));
 
         for (i = 0; i < n_construct_properties; i++)
             jsobj_set_gproperty(context, props_hash,
@@ -3127,7 +3146,7 @@ bool
 gjs_define_private_gi_stuff(JSContext              *cx,
                             JS::MutableHandleObject module)
 {
-    module.set(JS_NewObject(cx, NULL, JS::NullPtr(), JS::NullPtr()));
+    module.set(JS_NewObject(cx, NULL));
     return JS_DefineFunctions(cx, module, &module_funcs[0]);
 }
 
diff --git a/gi/param.cpp b/gi/param.cpp
index 1b18150..9bcd911 100644
--- a/gi/param.cpp
+++ b/gi/param.cpp
@@ -45,20 +45,19 @@ extern struct JSClass gjs_param_class;
 GJS_DEFINE_PRIV_FROM_JS(Param, gjs_param_class)
 
 /*
- * The *objp out parameter, on success, should be null to indicate that id
- * was not resolved; and non-null, referring to obj or one of its prototypes,
- * if id was resolved.
+ * The *resolved out parameter, on success, should be false to indicate that id
+ * was not resolved; and true if id was resolved.
  */
 static bool
-param_new_resolve(JSContext *context,
-                  JS::HandleObject obj,
-                  JS::HandleId id,
-                  JS::MutableHandleObject objp)
+param_resolve(JSContext       *context,
+              JS::HandleObject obj,
+              JS::HandleId     id,
+              bool            *resolved)
 {
     GIObjectInfo *info = NULL;
     GIFunctionInfo *method_info;
     Param *priv;
-    char *name;
+    g_autofree char *name = NULL;
     bool ret = false;
 
     if (!gjs_get_string_id(context, id, &name))
@@ -68,14 +67,15 @@ param_new_resolve(JSContext *context,
 
     if (priv != NULL) {
         /* instance, not prototype */
-        ret = true;
-        goto out;
+        *resolved = false;
+        return true;
     }
 
     info = (GIObjectInfo*)g_irepository_find_by_gtype(g_irepository_get_default(), G_TYPE_PARAM);
     method_info = g_object_info_find_method(info, name);
 
     if (method_info == NULL) {
+        *resolved = false;
         ret = true;
         goto out;
     }
@@ -93,14 +93,13 @@ param_new_resolve(JSContext *context,
             goto out;
         }
 
-        objp.set(obj); /* we defined the prop in obj */
+        *resolved = true; /* we defined the prop in obj */
     }
 
     g_base_info_unref( (GIBaseInfo*) method_info);
 
     ret = true;
  out:
-    g_free(name);
     if (info != NULL)
         g_base_info_unref( (GIBaseInfo*)info);
 
@@ -145,15 +144,14 @@ param_finalize(JSFreeOp *fop,
 struct JSClass gjs_param_class = {
     "GObject_ParamSpec",
     JSCLASS_HAS_PRIVATE |
-    JSCLASS_NEW_RESOLVE |
     JSCLASS_BACKGROUND_FINALIZE,
-    JS_PropertyStub,
-    JS_DeletePropertyStub,
-    JS_PropertyStub,
-    JS_StrictPropertyStub,
-    JS_EnumerateStub,
-    (JSResolveOp) param_new_resolve,
-    JS_ConvertStub,
+    NULL,  /* addProperty */
+    NULL,  /* deleteProperty */
+    NULL,  /* getProperty */
+    NULL,  /* setProperty */
+    NULL,  /* enumerate */
+    param_resolve,
+    NULL,  /* convert */
     param_finalize
 };
 
diff --git a/gi/repo.cpp b/gi/repo.cpp
index dff585e..e450284 100644
--- a/gi/repo.cpp
+++ b/gi/repo.cpp
@@ -145,44 +145,42 @@ resolve_namespace_object(JSContext       *context,
 }
 
 /*
- * The *objp out parameter, on success, should be null to indicate that id
- * was not resolved; and non-null, referring to obj or one of its prototypes,
- * if id was resolved.
+ * The *resolved out parameter, on success, should be false to indicate that id
+ * was not resolved; and true if id was resolved.
  */
 static bool
-repo_new_resolve(JSContext *context,
-                 JS::HandleObject obj,
-                 JS::HandleId id,
-                 JS::MutableHandleObject objp)
+repo_resolve(JSContext       *context,
+             JS::HandleObject obj,
+             JS::HandleId     id,
+             bool            *resolved)
 {
     Repo *priv;
-    char *name;
-    bool ret = true;
+    g_autofree char *name = NULL;
 
-    if (!gjs_get_string_id(context, id, &name))
+    if (!gjs_get_string_id(context, id, &name)) {
+        *resolved = false;
         return true; /* not resolved, but no error */
+    }
 
     /* let Object.prototype resolve these */
     if (strcmp(name, "valueOf") == 0 ||
-        strcmp(name, "toString") == 0)
-        goto out;
+        strcmp(name, "toString") == 0) {
+        *resolved = false;
+        return true;
+    }
 
     priv = priv_from_js(context, obj);
     gjs_debug_jsprop(GJS_DEBUG_GREPO, "Resolve prop '%s' hook obj %p priv %p",
                      name, obj.get(), priv);
 
     if (priv == NULL) /* we are the prototype, or have the wrong class */
-        goto out;
+        return false;
 
-    if (!resolve_namespace_object(context, obj, id, name)) {
-        ret = false;
-    } else {
-        objp.set(obj); /* store the object we defined the prop in */
-    }
+    if (!resolve_namespace_object(context, obj, id, name))
+        return false;
 
- out:
-    g_free(name);
-    return ret;
+    *resolved = true;
+    return true;
 }
 
 GJS_NATIVE_CONSTRUCTOR_DEFINE_ABSTRACT(repo)
@@ -209,15 +207,14 @@ repo_finalize(JSFreeOp *fop,
  */
 struct JSClass gjs_repo_class = {
     "GIRepository", /* means "new GIRepository()" works */
-    JSCLASS_HAS_PRIVATE |
-    JSCLASS_NEW_RESOLVE,
-    JS_PropertyStub,
-    JS_DeletePropertyStub,
-    JS_PropertyStub,
-    JS_StrictPropertyStub,
-    JS_EnumerateStub,
-    (JSResolveOp) repo_new_resolve, /* needs cast since it's the new resolve signature */
-    JS_ConvertStub,
+    JSCLASS_HAS_PRIVATE,
+    NULL,  /* addProperty */
+    NULL,  /* deleteProperty */
+    NULL,  /* getProperty */
+    NULL,  /* setProperty */
+    NULL,  /* enumerate */
+    repo_resolve,
+    NULL,  /* convert */
     repo_finalize
 };
 
@@ -233,8 +230,6 @@ static JSObject*
 repo_new(JSContext *context)
 {
     Repo *priv;
-    JSObject *versions;
-    JSObject *private_ns;
     bool found;
 
     JS::RootedObject global(context, gjs_get_import_global(context));
@@ -273,7 +268,7 @@ repo_new(JSContext *context)
     }
 
     JS::RootedObject repo(context,
-        JS_NewObject(context, &gjs_repo_class, JS::NullPtr(), global));
+        JS_NewObject(context, &gjs_repo_class, global));
     if (repo == NULL) {
         gjs_throw(context, "No memory to create repo object");
         return NULL;
@@ -289,22 +284,17 @@ repo_new(JSContext *context)
     gjs_debug_lifecycle(GJS_DEBUG_GREPO,
                         "repo constructor, obj %p priv %p", repo.get(), priv);
 
-    versions = JS_NewObject(context, NULL, JS::NullPtr(), global);
+    JS::RootedObject versions(context, JS_NewObject(context, NULL, global));
     JS::RootedId versions_name(context,
         gjs_context_get_const_string(context, GJS_STRING_GI_VERSIONS));
-    JS_DefinePropertyById(context, repo,
-                          versions_name,
-                          JS::ObjectValue(*versions),
-                          NULL, NULL,
+    JS_DefinePropertyById(context, repo, versions_name, versions,
                           JSPROP_PERMANENT);
 
-    private_ns = JS_NewObject(context, NULL, JS::NullPtr(), global);
+    JS::RootedObject private_ns(context, JS_NewObject(context, NULL, global));
     JS::RootedId private_ns_name(context,
         gjs_context_get_const_string(context, GJS_STRING_PRIVATE_NS_MARKER));
-    JS_DefinePropertyById(context, repo,
-                          private_ns_name,
-                          JS::ObjectValue(*private_ns),
-                          NULL, NULL, JSPROP_PERMANENT);
+    JS_DefinePropertyById(context, repo, private_ns_name, private_ns,
+                          JSPROP_PERMANENT);
 
     /* FIXME - hack to make namespaces load, since
      * gobject-introspection does not yet search a path properly.
diff --git a/gi/union.cpp b/gi/union.cpp
index 38a1405..984eb1c 100644
--- a/gi/union.cpp
+++ b/gi/union.cpp
@@ -50,81 +50,82 @@ extern struct JSClass gjs_union_class;
 GJS_DEFINE_PRIV_FROM_JS(Union, gjs_union_class)
 
 /*
- * The *objp out parameter, on success, should be null to indicate that id
- * was not resolved; and non-null, referring to obj or one of its prototypes,
- * if id was resolved.
+ * The *resolved out parameter, on success, should be false to indicate that id
+ * was not resolved; and true if id was resolved.
  */
 static bool
-union_new_resolve(JSContext *context,
-                  JS::HandleObject obj,
-                  JS::HandleId id,
-                  JS::MutableHandleObject objp)
+union_resolve(JSContext       *context,
+              JS::HandleObject obj,
+              JS::HandleId     id,
+              bool            *resolved)
 {
     Union *priv;
-    char *name;
-    bool ret = true;
+    g_autofree char *name = NULL;
 
-    if (!gjs_get_string_id(context, id, &name))
+    if (!gjs_get_string_id(context, id, &name)) {
+        *resolved = false;
         return true; /* not resolved, but no error */
+    }
 
     priv = priv_from_js(context, obj);
     gjs_debug_jsprop(GJS_DEBUG_GBOXED, "Resolve prop '%s' hook obj %p priv %p",
                      name, obj.get(), priv);
 
-    if (priv == NULL) {
-        ret = false; /* wrong class */
-        goto out;
+    if (priv == NULL)
+        return false; /* wrong class */
+
+    if (priv->gboxed != NULL) {
+        /* We are an instance, not a prototype, so look for
+         * per-instance props that we want to define on the
+         * JSObject. Generally we do not want to cache these in JS, we
+         * want to always pull them from the C object, or JS would not
+         * see any changes made from C. So we use the get/set prop
+         * hooks, not this resolve hook.
+         */
+        *resolved = false;
+        return true;
     }
 
-    if (priv->gboxed == NULL) {
-        /* We are the prototype, so look for methods and other class properties */
-        GIFunctionInfo *method_info;
+    /* We are the prototype, so look for methods and other class properties */
+    GIFunctionInfo *method_info;
 
-        method_info = g_union_info_find_method((GIUnionInfo*) priv->info,
-                                               name);
+    method_info = g_union_info_find_method((GIUnionInfo*) priv->info,
+                                           name);
 
-        if (method_info != NULL) {
-            const char *method_name;
+    if (method_info != NULL) {
+        const char *method_name;
 
 #if GJS_VERBOSE_ENABLE_GI_USAGE
-            _gjs_log_info_usage((GIBaseInfo*) method_info);
+        _gjs_log_info_usage((GIBaseInfo*) method_info);
 #endif
-            if (g_function_info_get_flags (method_info) & GI_FUNCTION_IS_METHOD) {
-                method_name = g_base_info_get_name( (GIBaseInfo*) method_info);
-
-                gjs_debug(GJS_DEBUG_GBOXED,
-                          "Defining method %s in prototype for %s.%s",
-                          method_name,
-                          g_base_info_get_namespace( (GIBaseInfo*) priv->info),
-                          g_base_info_get_name( (GIBaseInfo*) priv->info));
-
-                /* obj is union proto */
-                if (gjs_define_function(context, obj,
-                                        g_registered_type_info_get_g_type(priv->info),
-                                        method_info) == NULL) {
-                    g_base_info_unref( (GIBaseInfo*) method_info);
-                    ret = false;
-                    goto out;
-                }
-
-                objp.set(obj); /* we defined the prop in object_proto */
+        if (g_function_info_get_flags (method_info) & GI_FUNCTION_IS_METHOD) {
+            method_name = g_base_info_get_name( (GIBaseInfo*) method_info);
+
+            gjs_debug(GJS_DEBUG_GBOXED,
+                      "Defining method %s in prototype for %s.%s",
+                      method_name,
+                      g_base_info_get_namespace( (GIBaseInfo*) priv->info),
+                      g_base_info_get_name( (GIBaseInfo*) priv->info));
+
+            /* obj is union proto */
+            if (gjs_define_function(context, obj,
+                                    g_registered_type_info_get_g_type(priv->info),
+                                    method_info) == NULL) {
+                g_base_info_unref( (GIBaseInfo*) method_info);
+                return false;
             }
 
-            g_base_info_unref( (GIBaseInfo*) method_info);
+            *resolved = true; /* we defined the prop in object_proto */
+        } else {
+            *resolved = false;
         }
+
+        g_base_info_unref( (GIBaseInfo*) method_info);
     } else {
-        /* We are an instance, not a prototype, so look for
-         * per-instance props that we want to define on the
-         * JSObject. Generally we do not want to cache these in JS, we
-         * want to always pull them from the C object, or JS would not
-         * see any changes made from C. So we use the get/set prop
-         * hooks, not this resolve hook.
-         */
+        *resolved = false;
     }
 
- out:
-    g_free(name);
-    return ret;
+    return true;
 }
 
 static void*
@@ -287,15 +288,14 @@ to_string_func(JSContext *context,
  */
 struct JSClass gjs_union_class = {
     "GObject_Union",
-    JSCLASS_HAS_PRIVATE |
-    JSCLASS_NEW_RESOLVE,
-    JS_PropertyStub,
-    JS_DeletePropertyStub,
-    JS_PropertyStub,
-    JS_StrictPropertyStub,
-    JS_EnumerateStub,
-    (JSResolveOp) union_new_resolve, /* needs cast since it's the new resolve signature */
-    JS_ConvertStub,
+    JSCLASS_HAS_PRIVATE,
+    NULL,  /* addProperty */
+    NULL,  /* deleteProperty */
+    NULL,  /* getProperty */
+    NULL,  /* setProperty */
+    NULL,  /* enumerate */
+    union_resolve,
+    NULL,  /* convert */
     union_finalize
 };
 
diff --git a/gjs/byteArray.cpp b/gjs/byteArray.cpp
index 78e6a18..f60d4bf 100644
--- a/gjs/byteArray.cpp
+++ b/gjs/byteArray.cpp
@@ -57,13 +57,13 @@ struct JSClass gjs_byte_array_class = {
     "ByteArray",
     JSCLASS_HAS_PRIVATE |
     JSCLASS_BACKGROUND_FINALIZE,
-    JS_PropertyStub,
-    JS_DeletePropertyStub,
+    NULL,  /* addProperty */
+    NULL,  /* deleteProperty */
     (JSPropertyOp)byte_array_get_prop,
     (JSStrictPropertyOp)byte_array_set_prop,
-    JS_EnumerateStub,
-    JS_ResolveStub,
-    JS_ConvertStub,
+    NULL,  /* enumerate */
+    NULL,  /* resolve */
+    NULL,  /* convert */
     byte_array_finalize
 };
 
@@ -531,7 +531,7 @@ byte_array_new(JSContext *context)
 
     JS::RootedObject proto(context, byte_array_get_prototype(context));
     JS::RootedObject array(context,
-        JS_NewObjectWithGivenProto(context, &gjs_byte_array_class, proto, JS::NullPtr()));
+        JS_NewObjectWithGivenProto(context, &gjs_byte_array_class, proto));
 
     priv = g_slice_new0(ByteArrayInstance);
 
@@ -607,8 +607,9 @@ from_string_func(JSContext *context,
         GError *error;
         const char16_t *u16_chars;
         gsize u16_len;
+        JS::AutoCheckCannotGC nogc;
 
-        u16_chars = JS_GetStringCharsAndLength(context, argv[0].toString(), &u16_len);
+        u16_chars = JS_GetTwoByteStringCharsAndLength(context, nogc, argv[0].toString(), &u16_len);
         if (u16_chars == NULL)
             return false;
 
@@ -741,7 +742,7 @@ gjs_byte_array_from_byte_array (JSContext *context,
 
     JS::RootedObject proto(context, byte_array_get_prototype(context));
     JS::RootedObject object(context,
-        JS_NewObjectWithGivenProto(context, &gjs_byte_array_class, proto, JS::NullPtr()));
+        JS_NewObjectWithGivenProto(context, &gjs_byte_array_class, proto));
 
     if (!object) {
         gjs_throw(context, "failed to create byte array");
@@ -829,7 +830,7 @@ gjs_define_byte_array_stuff(JSContext              *context,
 {
     JSObject *prototype;
 
-    module.set(JS_NewObject(context, NULL, JS::NullPtr(), JS::NullPtr()));
+    module.set(JS_NewObject(context, NULL));
 
     prototype = JS_InitClass(context, module, JS::NullPtr(),
                              &gjs_byte_array_class,
diff --git a/gjs/context.cpp b/gjs/context.cpp
index fe74d17..7d80621 100644
--- a/gjs/context.cpp
+++ b/gjs/context.cpp
@@ -78,6 +78,7 @@ struct _GjsContext {
 
     guint    auto_gc_id;
 
+    /* FIXME - array of PersistentRooted<jsid>? */
     jsid const_strings[GJS_STRING_LAST];
 };
 
@@ -371,7 +372,7 @@ static void
 gjs_context_tracer(JSTracer *trc, void *data)
 {
     GjsContext *gjs_context = reinterpret_cast<GjsContext *>(data);
-    JS_CallHeapObjectTracer(trc, &gjs_context->global, "GJS global object");
+    JS_CallObjectTracer(trc, &gjs_context->global, "GJS global object");
 }
 
 static void
@@ -494,7 +495,7 @@ gjs_context_constructed(GObject *object)
     if (!JS_DefineFunctions(js_context->context, global, &global_funcs[0]))
         g_error("Failed to define properties on the global object");
 
-    js_context->global.set(global);
+    js_context->global = global;
     JS_AddExtraGCRootsTracer(js_context->runtime, gjs_context_tracer, js_context);
 
     gjs_define_constructor_proxy_factory(js_context->context);
diff --git a/gjs/coverage.cpp b/gjs/coverage.cpp
index e50703f..7727b71 100644
--- a/gjs/coverage.cpp
+++ b/gjs/coverage.cpp
@@ -1261,13 +1261,13 @@ gjs_coverage_init(GjsCoverage *self)
 static JSClass coverage_global_class = {
     "GjsCoverageGlobal",
     JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(GJS_GLOBAL_SLOT_LAST),
-    JS_PropertyStub,
-    JS_DeletePropertyStub,
-    JS_PropertyStub,
-    JS_StrictPropertyStub,
-    JS_EnumerateStub,
-    JS_ResolveStub,
-    JS_ConvertStub,
+    NULL,  /* addProperty */
+    NULL,  /* deleteProperty */
+    NULL,  /* getProperty */
+    NULL,  /* setProperty */
+    NULL,  /* enumerate */
+    NULL,  /* resolve */
+    NULL,  /* convert */
     NULL,  /* finalize */
     NULL,  /* call */
     NULL,  /* hasInstance */
@@ -1497,7 +1497,7 @@ coverage_statistics_tracer(JSTracer *trc, void *data)
     GjsCoverage *coverage = (GjsCoverage *) data;
     GjsCoveragePrivate *priv = (GjsCoveragePrivate *) gjs_coverage_get_instance_private(coverage);
 
-    JS_CallHeapObjectTracer(trc, &priv->coverage_statistics, "coverage_statistics");
+    JS_CallObjectTracer(trc, &priv->coverage_statistics, "coverage_statistics");
 }
 
 /* This function is mainly used in the tests in order to fiddle with
diff --git a/gjs/importer.cpp b/gjs/importer.cpp
index 9f96f5c..02809cc 100644
--- a/gjs/importer.cpp
+++ b/gjs/importer.cpp
@@ -213,7 +213,7 @@ seal_import(JSContext       *cx,
 
     if (!JS_DefineProperty(cx, descr.object(), name, descr.value(),
                            descr.attributes() | JSPROP_PERMANENT,
-                           descr.getter(), descr.setter())) {
+                           (JSNative) descr.getter(), (JSNative) descr.setter())) {
         gjs_debug(GJS_DEBUG_IMPORTER,
                   "Failed to redefine attributes to seal '%s' in importer",
                   name);
@@ -313,12 +313,6 @@ import_native_file(JSContext       *context,
                              GJS_MODULE_PROP_FLAGS);
 }
 
-static JSObject *
-create_module_object(JSContext *context)
-{
-    return JS_NewObject(context, NULL, JS::NullPtr(), JS::NullPtr());
-}
-
 static bool
 import_file(JSContext       *context,
             const char      *name,
@@ -380,14 +374,13 @@ load_module_init(JSContext       *context,
         }
     }
 
-    JS::RootedObject module_obj(context, create_module_object(context));
+    JS::RootedObject module_obj(context, JS_NewObject(context, NULL));
     file = g_file_new_for_commandline_arg(full_path);
     if (!import_file (context, "__init__", file, module_obj))
         goto out;
 
     if (!JS_DefinePropertyById(context, in_object,
-                               module_init_name, JS::ObjectValue(*module_obj),
-                               NULL, NULL,
+                               module_init_name, module_obj,
                                GJS_MODULE_PROP_FLAGS & ~JSPROP_PERMANENT))
         goto out;
 
@@ -399,10 +392,9 @@ load_module_init(JSContext       *context,
 static void
 load_module_elements(JSContext        *cx,
                      JS::HandleObject  in_object,
-                     ImporterIterator *iter,
+                     JS::AutoIdVector& prop_ids,
                      const char       *init_path)
 {
-    size_t ix, length;
     JS::RootedObject module_obj(cx, load_module_init(cx, in_object, init_path));
 
     if (module_obj == NULL)
@@ -412,14 +404,9 @@ load_module_elements(JSContext        *cx,
     if (!ids)
         return;
 
-    for (ix = 0, length = ids.length(); ix < length; ix++) {
-        char *name;
-        if (!gjs_get_string_id(cx, ids[ix], &name))
-            continue;
-
-        /* Pass ownership of name */
-        g_ptr_array_add(iter->elements, name);
-    }
+    /* Is this allowed?? */
+    jsid vector_ref = ids[0];
+    prop_ids.append(&vector_ref, ids.length());
 }
 
 static bool
@@ -431,7 +418,7 @@ import_file_on_module(JSContext       *context,
     bool retval = false;
     char *full_path = NULL;
 
-    JS::RootedObject module_obj(context, create_module_object(context));
+    JS::RootedObject module_obj(context, JS_NewObject(context, NULL));
 
     if (!define_import(context, obj, module_obj, name))
         goto out;
@@ -664,201 +651,108 @@ do_import(JSContext       *context,
     return result;
 }
 
-static ImporterIterator *
-importer_iterator_new(void)
-{
-    ImporterIterator *iter;
-
-    iter = g_slice_new0(ImporterIterator);
-
-    iter->elements = g_ptr_array_new();
-    iter->index = 0;
-
-    return iter;
-}
-
-static void
-importer_iterator_free(ImporterIterator *iter)
-{
-    g_ptr_array_foreach(iter->elements, (GFunc)g_free, NULL);
-    g_ptr_array_free(iter->elements, true);
-    g_slice_free(ImporterIterator, iter);
-}
-
-/*
- * Like JSEnumerateOp, but enum provides contextual information as follows:
- *
- * JSENUMERATE_INIT: allocate private enum struct in state_p, return number
- * of elements in *id_p
- * JSENUMERATE_NEXT: return next property id in *id_p, and if no new property
- * free state_p and set to JS::NullValue()
- * JSENUMERATE_DESTROY : destroy state_p
- *
- * Note that in a for ... in loop, this will be called first on the object,
+/* Note that in a for ... in loop, this will be called first on the object,
  * then on its prototype.
- *
  */
 static bool
-importer_new_enumerate(JSContext  *context,
-                       JS::HandleObject object,
-                       JSIterateOp enum_op,
-                       JS::MutableHandleValue statep,
-                       JS::MutableHandleId idp)
+importer_enumerate(JSContext        *context,
+                   JS::HandleObject  object,
+                   JS::AutoIdVector& properties)
 {
-    ImporterIterator *iter;
+    Importer *priv;
+    guint32 search_path_len;
+    guint32 i;
 
-    switch (enum_op) {
-    case JSENUMERATE_INIT_ALL:
-    case JSENUMERATE_INIT: {
-        Importer *priv;
-        JS::RootedObject search_path(context);
-        guint32 search_path_len;
-        guint32 i;
+    priv = priv_from_js(context, object);
 
-        statep.setNull();
+    if (!priv)
+        /* we are enumerating the prototype properties */
+        return true;
 
-        idp.set(INT_TO_JSID(0));
+    JS::RootedObject search_path(context);
+    JS::RootedId search_path_name(context,
+        gjs_context_get_const_string(context, GJS_STRING_SEARCH_PATH));
+    if (!gjs_object_require_property_value(context, object, "importer",
+                                           search_path_name, &search_path))
+        return false;
 
-        priv = priv_from_js(context, object);
+    if (!JS_IsArrayObject(context, search_path)) {
+        gjs_throw(context, "searchPath property on importer is not an array");
+        return false;
+    }
 
-        if (!priv)
-            /* we are enumerating the prototype properties */
-            return true;
+    if (!JS_GetArrayLength(context, search_path, &search_path_len)) {
+        gjs_throw(context, "searchPath array has no length");
+        return false;
+    }
 
-        JS::RootedId search_path_name(context,
-            gjs_context_get_const_string(context, GJS_STRING_SEARCH_PATH));
-        if (!gjs_object_require_property_value(context, object, "importer",
-                                               search_path_name, &search_path))
-            return false;
+    JS::RootedValue elem(context);
+    for (i = 0; i < search_path_len; ++i) {
+        char *dirname = NULL;
+        char *init_path;
+        const char *filename;
+        GDir *dir = NULL;
 
-        if (!JS_IsArrayObject(context, search_path)) {
-            gjs_throw(context, "searchPath property on importer is not an array");
+        elem.setUndefined();
+        if (!JS_GetElement(context, search_path, i, &elem)) {
+            /* this means there was an exception, while elem.isUndefined()
+             * means no element found
+             */
             return false;
         }
 
-        if (!JS_GetArrayLength(context, search_path, &search_path_len)) {
-            gjs_throw(context, "searchPath array has no length");
+        if (elem.isUndefined())
+            continue;
+
+        if (!elem.isString()) {
+            gjs_throw(context, "importer searchPath contains non-string");
             return false;
         }
 
-        iter = importer_iterator_new();
-
-        JS::RootedValue elem(context);
-        for (i = 0; i < search_path_len; ++i) {
-            char *dirname = NULL;
-            char *init_path;
-            const char *filename;
-            GDir *dir = NULL;
-
-            elem = JS::UndefinedValue();
-            if (!JS_GetElement(context, search_path, i, &elem)) {
-                /* this means there was an exception, while elem.isUndefined()
-                 * means no element found
-                 */
-                importer_iterator_free(iter);
-                return false;
-            }
-
-            if (elem.isUndefined())
-                continue;
-
-            if (!elem.isString()) {
-                gjs_throw(context, "importer searchPath contains non-string");
-                importer_iterator_free(iter);
-                return false;
-            }
-
-            if (!gjs_string_to_utf8(context, elem, &dirname)) {
-                importer_iterator_free(iter);
-                return false; /* Error message already set */
-            }
-
-            init_path = g_build_filename(dirname, MODULE_INIT_FILENAME,
-                                         NULL);
-
-            load_module_elements(context, object, iter, init_path);
-
-            g_free(init_path);
-
-            dir = g_dir_open(dirname, 0, NULL);
-
-            if (!dir) {
-                g_free(dirname);
-                continue;
-            }
-
-            while ((filename = g_dir_read_name(dir))) {
-                char *full_path;
+        if (!gjs_string_to_utf8(context, elem, &dirname)) {
+            return false; /* Error message already set */
+        }
 
-                /* skip hidden files and directories (.svn, .git, ...) */
-                if (filename[0] == '.')
-                    continue;
+        init_path = g_build_filename(dirname, MODULE_INIT_FILENAME, NULL);
 
-                /* skip module init file */
-                if (strcmp(filename, MODULE_INIT_FILENAME) == 0)
-                    continue;
+        load_module_elements(context, object, properties, init_path);
 
-                full_path = g_build_filename(dirname, filename, NULL);
+        g_free(init_path);
 
-                if (g_file_test(full_path, G_FILE_TEST_IS_DIR)) {
-                    g_ptr_array_add(iter->elements, g_strdup(filename));
-                } else {
-                    if (g_str_has_suffix(filename, "." G_MODULE_SUFFIX) ||
-                        g_str_has_suffix(filename, ".js")) {
-                        g_ptr_array_add(iter->elements,
-                                        g_strndup(filename, strlen(filename) - 3));
-                    }
-                }
-
-                g_free(full_path);
-            }
-            g_dir_close(dir);
+        dir = g_dir_open(dirname, 0, NULL);
 
+        if (!dir) {
             g_free(dirname);
+            continue;
         }
 
-        statep.set(JS::PrivateValue(context));
+        while ((filename = g_dir_read_name(dir))) {
+            char *full_path;
 
-        idp.set(INT_TO_JSID(iter->elements->len));
-
-        break;
-    }
-
-    case JSENUMERATE_NEXT: {
-        if (statep.isNull()) /* Iterating prototype */
-            return true;
-
-        iter = (ImporterIterator*) statep.get().toPrivate();
-
-        if (iter->index < iter->elements->len) {
-            JS::RootedValue element_val(context);
-            if (!gjs_string_from_utf8(context,
-                                         (const char*) g_ptr_array_index(iter->elements,
-                                                           iter->index++),
-                                         -1,
-                                         &element_val))
-                return false;
-
-            if (!JS_ValueToId(context, element_val, idp))
-                return false;
+            /* skip hidden files and directories (.svn, .git, ...) */
+            if (filename[0] == '.')
+                continue;
 
-            break;
-        }
-        /* else fall through to destroying the iterator */
-    }
+            /* skip module init file */
+            if (strcmp(filename, MODULE_INIT_FILENAME) == 0)
+                continue;
 
-    case JSENUMERATE_DESTROY: {
-        if (!statep.isNull()) {
-            iter = (ImporterIterator*) statep.get().toPrivate();
+            full_path = g_build_filename(dirname, filename, NULL);
 
-            importer_iterator_free(iter);
+            if (g_file_test(full_path, G_FILE_TEST_IS_DIR)) {
+                properties.append(gjs_intern_string_to_id(context, filename));
+            } else if (g_str_has_suffix(filename, "." G_MODULE_SUFFIX) ||
+                       g_str_has_suffix(filename, ".js")) {
+                g_autofree char *filename_noext =
+                    g_strndup(filename, strlen(filename) - 3);
+                properties.append(gjs_intern_string_to_id(context, filename_noext));
+            }
 
-            statep.setNull();
+            g_free(full_path);
         }
-    }
+        g_dir_close(dir);
 
-    default:
-        ;
+        g_free(dirname);
     }
 
     return true;
@@ -870,19 +764,20 @@ importer_new_enumerate(JSContext  *context,
  * if id was resolved.
  */
 static bool
-importer_new_resolve(JSContext *context,
-                     JS::HandleObject obj,
-                     JS::HandleId id,
-                     JS::MutableHandleObject objp)
+importer_resolve(JSContext        *context,
+                 JS::HandleObject  obj,
+                 JS::HandleId      id,
+                 bool             *resolved)
 {
     Importer *priv;
-    char *name;
-    bool ret = true;
+    g_autofree char *name = NULL;
     jsid module_init_name;
 
     module_init_name = gjs_context_get_const_string(context, GJS_STRING_MODULE_INIT);
-    if (id == module_init_name)
+    if (id == module_init_name) {
+        *resolved = false;
         return true;
+    }
 
     if (!gjs_get_string_id(context, id, &name))
         return false;
@@ -890,26 +785,27 @@ importer_new_resolve(JSContext *context,
     /* let Object.prototype resolve these */
     if (strcmp(name, "valueOf") == 0 ||
         strcmp(name, "toString") == 0 ||
-        strcmp(name, "__iterator__") == 0)
-        goto out;
+        strcmp(name, "__iterator__") == 0) {
+        *resolved = false;
+        return true;
+    }
     priv = priv_from_js(context, obj);
 
     gjs_debug_jsprop(GJS_DEBUG_IMPORTER,
                      "Resolve prop '%s' hook obj %p priv %p",
                      name, obj.get(), priv);
-    if (priv == NULL) /* we are the prototype, or have the wrong class */
-        goto out;
-    JS_BeginRequest(context);
-    if (do_import(context, obj, priv, name)) {
-        objp.set(obj);
-    } else {
-        ret = false;
+    if (priv == NULL) {
+        /* we are the prototype, or have the wrong class */
+        *resolved = false;
+        return true;
     }
-    JS_EndRequest(context);
 
- out:
-    g_free(name);
-    return ret;
+    JSAutoRequest ar(context);
+    if (!do_import(context, obj, priv, name))
+        return false;
+
+    *resolved = true;
+    return true;
 }
 
 GJS_NATIVE_CONSTRUCTOR_DEFINE_ABSTRACT(importer)
@@ -936,16 +832,14 @@ importer_finalize(JSFreeOp *fop,
  */
 struct JSClass gjs_importer_class = {
     "GjsFileImporter",
-    JSCLASS_HAS_PRIVATE |
-    JSCLASS_NEW_RESOLVE |
-    JSCLASS_NEW_ENUMERATE,
-    JS_PropertyStub,
-    JS_DeletePropertyStub,
-    JS_PropertyStub,
-    JS_StrictPropertyStub,
-    (JSEnumerateOp) importer_new_enumerate, /* needs cast since it's the new enumerate signature */
-    (JSResolveOp) importer_new_resolve, /* needs cast since it's the new resolve signature */
-    JS_ConvertStub,
+    JSCLASS_HAS_PRIVATE,
+    NULL,  /* addProperty */
+    NULL,  /* deleteProperty */
+    NULL,  /* getProperty */
+    NULL,  /* setProperty */
+    NULL, // FIXME FIXME importer_enumerate,
+    importer_resolve,
+    NULL,  /* convert */
     importer_finalize
 };
 
@@ -1002,7 +896,7 @@ importer_new(JSContext *context,
     }
 
     JS::RootedObject importer(context,
-        JS_NewObject(context, &gjs_importer_class, JS::NullPtr(), global));
+        JS_NewObject(context, &gjs_importer_class, global));
     if (importer == NULL)
         g_error("No memory to create importer importer");
 
@@ -1179,7 +1073,6 @@ gjs_define_root_importer_object(JSContext        *context,
         gjs_context_get_const_string(context, GJS_STRING_IMPORTS));
     if (!JS_DefinePropertyById(context, in_object,
                                imports_name, importer,
-                               NULL, NULL,
                                GJS_MODULE_PROP_FLAGS)) {
         gjs_debug(GJS_DEBUG_IMPORTER, "DefineProperty imports on %p failed",
                   in_object.get());
diff --git a/gjs/jsapi-constructor-proxy.cpp b/gjs/jsapi-constructor-proxy.cpp
index 9dab6c0..02dc1a1 100644
--- a/gjs/jsapi-constructor-proxy.cpp
+++ b/gjs/jsapi-constructor-proxy.cpp
@@ -82,16 +82,15 @@ class GjsConstructorHandler : public js::DirectProxyHandler {
     }
 
 public:
-    GjsConstructorHandler() : js::DirectProxyHandler(&constructor_proxy_family)
-    {
-        setHasPrototype(true);
-    }
+    GjsConstructorHandler()
+    : js::DirectProxyHandler(&constructor_proxy_family, true /* hasPrototype */)
+    { }
 
     bool
     getPrototypeOf(JSContext              *cx,
                    JS::HandleObject        proxy,
                    JS::MutableHandleObject proto_p)
-    override
+    const override
     {
         proto_p.set(proto(proxy));
         return true;
@@ -102,13 +101,27 @@ public:
     void
     finalize(JSFreeOp *fop,
              JSObject *proxy)
-    override
+    const override
     {
         GJS_DEC_COUNTER(constructor_proxy);
         gjs_debug_lifecycle(GJS_DEBUG_PROXY,
                             "constructor proxy %p destroyed", proxy);
     }
 
+    bool
+    isCallable(JSObject *obj)
+    const override
+    {
+        return true;
+    }
+
+    bool
+    isConstructor(JSObject *obj)
+    const override
+    {
+        return true;
+    }
+
     static GjsConstructorHandler&
     singleton(void)
     {
@@ -141,14 +154,9 @@ create_gjs_constructor_proxy(JSContext *cx,
         return false;
     }
 
-    js::ProxyOptions options;
-    /* "true" makes the proxy callable, otherwise the "call" and "construct"
-     * traps are ignored */
-    options.selectDefaultClass(true);
-
     JS::RootedObject proxy(cx,
         js::NewProxyObject(cx, &GjsConstructorHandler::singleton(), args[0],
-                           &args[1].toObject(), nullptr, options));
+                           &args[1].toObject(), nullptr));
     /* We stick this extra object into one of the proxy object's "extra slots",
      * even though it is private data of the proxy handler. This is because
      * proxy handlers cannot have trace callbacks. The proxy object does have a
diff --git a/gjs/jsapi-dynamic-class.cpp b/gjs/jsapi-dynamic-class.cpp
index e53efcf..c219195 100644
--- a/gjs/jsapi-dynamic-class.cpp
+++ b/gjs/jsapi-dynamic-class.cpp
@@ -107,18 +107,15 @@ gjs_init_class_dynamic(JSContext              *context,
         goto out;
 
     if (!JS_DefineProperty(context, constructor, "prototype", prototype,
-                           JSPROP_PERMANENT | JSPROP_READONLY,
-                           JS_PropertyStub, JS_StrictPropertyStub))
+                           JSPROP_PERMANENT | JSPROP_READONLY))
         goto out;
-    if (!JS_DefineProperty(context, prototype, "constructor", constructor,
-                           0, JS_PropertyStub, JS_StrictPropertyStub))
+    if (!JS_DefineProperty(context, prototype, "constructor", constructor, 0))
         goto out;
 
     /* The constructor defined by JS_InitClass has no property attributes, but this
        is a more useful default for gjs */
     if (!JS_DefineProperty(context, in_object, class_name, constructor,
-                           GJS_MODULE_PROP_FLAGS,
-                           JS_PropertyStub, JS_StrictPropertyStub))
+                           GJS_MODULE_PROP_FLAGS))
         goto out;
 
     res = true;
diff --git a/gjs/jsapi-util-string.cpp b/gjs/jsapi-util-string.cpp
index 6143b47..509413f 100644
--- a/gjs/jsapi-util-string.cpp
+++ b/gjs/jsapi-util-string.cpp
@@ -191,7 +191,12 @@ gjs_string_get_char16_data(JSContext       *context,
         goto out;
     }
 
-    js_data = JS_GetStringCharsAndLength(context, value.toString(), len_p);
+    /* Scope for nogc */
+    {
+        JS::AutoCheckCannotGC nogc;
+        js_data = JS_GetTwoByteStringCharsAndLength(context, nogc,
+                                                    value.toString(), len_p);
+    }
     if (js_data == NULL)
         goto out;
 
@@ -231,7 +236,9 @@ gjs_string_to_ucs4(JSContext      *cx,
     size_t utf16_len;
     GError *error = NULL;
 
-    const char16_t *utf16 = JS_GetStringCharsAndLength(cx, str, &utf16_len);
+    JS::AutoCheckCannotGC nogc;
+    const char16_t *utf16 = JS_GetTwoByteStringCharsAndLength(cx, nogc, str,
+                                                              &utf16_len);
     if (utf16 == NULL) {
         gjs_throw(cx, "Failed to get UTF-16 string data");
         return false;
diff --git a/gjs/jsapi-util.cpp b/gjs/jsapi-util.cpp
index decac55..9229d62 100644
--- a/gjs/jsapi-util.cpp
+++ b/gjs/jsapi-util.cpp
@@ -47,13 +47,13 @@ gjs_util_error_quark (void)
 static JSClass global_class = {
     "GjsGlobal",
     JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(GJS_GLOBAL_SLOT_LAST),
-    JS_PropertyStub,
-    JS_DeletePropertyStub,
-    JS_PropertyStub,
-    JS_StrictPropertyStub,
-    JS_EnumerateStub,
-    JS_ResolveStub,
-    JS_ConvertStub,
+    NULL,  /* addProperty */
+    NULL,  /* deleteProperty */
+    NULL,  /* getProperty */
+    NULL,  /* setProperty */
+    NULL,  /* enumerate */
+    NULL,  /* resolve */
+    NULL,  /* convert */
     NULL,  /* finalize */
     NULL,  /* call */
     NULL,  /* hasInstance */
@@ -88,9 +88,8 @@ gjs_init_context_standard (JSContext              *context,
      *
      * setExtraWarnings: Report warnings to error reporter function.
      */
-    JS::ContextOptionsRef(context)
-        .setDontReportUncaught(true)
-        .setExtraWarnings(extra_warnings);
+    JS::ContextOptionsRef(context).setDontReportUncaught(true);
+    JS::RuntimeOptionsRef(context).setExtraWarnings(extra_warnings);
 
     if (!g_getenv("GJS_DISABLE_JIT")) {
         gjs_debug(GJS_DEBUG_CONTEXT, "Enabling JIT");
@@ -100,8 +99,6 @@ gjs_init_context_standard (JSContext              *context,
             .setAsmJS(true);
     }
 
-    JS_SetErrorReporter(context, gjs_error_reporter);
-
     compartment_options.setVersion(JSVERSION_LATEST);
     global.set(JS_NewGlobalObject(context, &global_class, NULL,
                                   JS::FireOnNewGlobalHook, compartment_options));
@@ -379,7 +376,8 @@ gjs_string_readable (JSContext   *context,
         size_t i, len;
         const char16_t *uchars;
 
-        uchars = JS_GetStringCharsAndLength(context, string, &len);
+        JS::AutoCheckCannotGC nogc;
+        uchars = JS_GetTwoByteStringCharsAndLength(context, nogc, string, &len);
 
         for (i = 0; i < len; i++) {
             char16_t c = uchars[i];
@@ -871,7 +869,7 @@ gjs_eval_with_scope(JSContext             *context,
 
     JS::RootedObject eval_obj(context, object);
     if (!eval_obj)
-        eval_obj = JS_NewObject(context, NULL, JS::NullPtr(), JS::NullPtr());
+        eval_obj = JS_NewObject(context, NULL);
 
     JS::CompileOptions options(context);
     options.setUTF8(true)
diff --git a/gjs/jsapi-util.h b/gjs/jsapi-util.h
index 8789c3b..09cc3a1 100644
--- a/gjs/jsapi-util.h
+++ b/gjs/jsapi-util.h
@@ -175,24 +175,24 @@ _GJS_DEFINE_PROTO_FULL(tn, cn, NULL, gtype, flags)
 extern JSPropertySpec gjs_##cname##_proto_props[]; \
 extern JSFunctionSpec gjs_##cname##_proto_funcs[]; \
 static void gjs_##cname##_finalize(JSFreeOp *fop, JSObject *obj); \
-static bool gjs_##cname##_new_resolve(JSContext *context, \
-                                      JSObject  *obj, \
-                                      JS::Value  id, \
-                                      JSObject **objp) \
+static bool gjs_##cname##_resolve(JSContext       *context,                    \
+                                  JS::HandleObject obj,                        \
+                                  JS::HandleId     id,                         \
+                                  bool             *resolved)                  \
 { \
+    *resolved = false;                                                         \
     return true; \
 } \
 static struct JSClass gjs_##cname##_class = { \
     type_name, \
-    JSCLASS_HAS_PRIVATE | \
-    JSCLASS_NEW_RESOLVE | jsclass_flags, \
-    JS_PropertyStub, \
-    JS_DeletePropertyStub, \
-    JS_PropertyStub, \
-    JS_StrictPropertyStub, \
-    JS_EnumerateStub,\
-    (JSResolveOp) gjs_##cname##_new_resolve, \
-    JS_ConvertStub, \
+    JSCLASS_HAS_PRIVATE | jsclass_flags,                                       \
+    NULL,  /* addProperty */                                                   \
+    NULL,  /* deleteProperty */                                                \
+    NULL,  /* getProperty */                                                   \
+    NULL,  /* setProperty */                                                   \
+    NULL,  /* enumerate */                                                     \
+    gjs_##cname##_resolve,                                                     \
+    NULL,  /* convert */                                                       \
     gjs_##cname##_finalize                                                     \
 }; \
 JS::Value                                                                      \
diff --git a/gjs/jsapi-wrapper.h b/gjs/jsapi-wrapper.h
index 37e7d71..021066a 100644
--- a/gjs/jsapi-wrapper.h
+++ b/gjs/jsapi-wrapper.h
@@ -37,7 +37,7 @@
 #endif
 #include <mozilla/Maybe.h>
 #include <jsapi.h>
-#include <js/OldDebugAPI.h>  /* Needed by some bits */
-#include <jsproxy.h>  /* For jsapi-constructor-proxy */
+#include <js/Conversions.h>
+#include <js/Proxy.h>  /* For jsapi-constructor-proxy */
 
 #endif  /* GJS_JSAPI_WRAPPER_H */
diff --git a/gjs/runtime.cpp b/gjs/runtime.cpp
index 816dbce..2f69271 100644
--- a/gjs/runtime.cpp
+++ b/gjs/runtime.cpp
@@ -169,13 +169,10 @@ static JSLocaleCallbacks gjs_locale_callbacks =
 static void
 gjs_finalize_callback(JSFreeOp         *fop,
                       JSFinalizeStatus  status,
-                      bool              isCompartment)
+                      bool              isCompartment,
+                      void             *user_data)
 {
-  JSRuntime *runtime;
-  RuntimeData *data;
-
-  runtime = fop->runtime();
-  data = (RuntimeData*) JS_GetRuntimePrivate(runtime);
+  RuntimeData *data = static_cast<RuntimeData *>(user_data);
 
   /* Implementation note for mozjs 24:
      sweeping happens in two phases, in the first phase all
@@ -259,7 +256,7 @@ gjs_runtime_for_current_thread(void)
 
     if (!runtime) {
         g_assert(gjs_is_inited);
-        runtime = JS_NewRuntime(32*1024*1024 /* max bytes */, JS_USE_HELPER_THREADS);
+        runtime = JS_NewRuntime(32*1024*1024 /* max bytes */);
         if (runtime == NULL)
             g_error("Failed to create javascript runtime");
 
@@ -269,7 +266,8 @@ gjs_runtime_for_current_thread(void)
         JS_SetNativeStackQuota(runtime, 1024*1024);
         JS_SetGCParameter(runtime, JSGC_MAX_BYTES, 0xffffffff);
         JS_SetLocaleCallbacks(runtime, &gjs_locale_callbacks);
-        JS_SetFinalizeCallback(runtime, gjs_finalize_callback);
+        JS_AddFinalizeCallback(runtime, gjs_finalize_callback, data);
+        JS_SetErrorReporter(runtime, gjs_error_reporter);
 
         g_private_set(&thread_runtime, runtime);
     }
diff --git a/gjs/stack.cpp b/gjs/stack.cpp
index 7dba9b1..45ef4fd 100644
--- a/gjs/stack.cpp
+++ b/gjs/stack.cpp
@@ -66,17 +66,17 @@ gjs_context_get_frame_info(JSContext                              *context,
     JS::RootedObject err_obj(context, JS_New(context, constructor,
                                              JS::HandleValueArray::empty()));
 
-    if (!stack.empty() &&
+    if (stack &&
         !gjs_object_get_property_const(context, err_obj, GJS_STRING_STACK,
                                        stack.ref()))
         return false;
 
-    if (!fileName.empty() &&
+    if (fileName &&
         !gjs_object_get_property_const(context, err_obj, GJS_STRING_FILENAME,
                                        fileName.ref()))
         return false;
 
-    if (!lineNumber.empty() &&
+    if (lineNumber &&
         !gjs_object_get_property_const(context, err_obj, GJS_STRING_LINE_NUMBER,
                                        lineNumber.ref()))
         return false;
@@ -95,8 +95,8 @@ gjs_context_print_stack_stderr(GjsContext *context)
 
     /* Stderr is locale encoding, so we use string_to_filename here */
     /* COMPAT: mozilla::Maybe gains a much more usable API in future versions */
-    mozilla::Maybe<JS::MutableHandleValue> m_stack, m_file, m_line;
-    m_stack.construct(&v_stack);
+    mozilla::Maybe<JS::MutableHandleValue> m_stack(mozilla::Some<JS::MutableHandleValue>(&v_stack)),
+        m_file, m_line;
     if (!gjs_context_get_frame_info(cx, m_stack, m_file, m_line) ||
         !gjs_string_to_filename(cx, v_stack, &stack)) {
         g_printerr("No stack trace available\n");
diff --git a/modules/cairo-context.cpp b/modules/cairo-context.cpp
index cf5efa5..5f1164b 100644
--- a/modules/cairo-context.cpp
+++ b/modules/cairo-context.cpp
@@ -923,7 +923,7 @@ gjs_cairo_context_from_context(JSContext *context,
                                cairo_t *cr)
 {
     JS::RootedObject object(context,
-        JS_NewObject(context, &gjs_cairo_context_class, JS::NullPtr(), JS::NullPtr()));
+        JS_NewObject(context, &gjs_cairo_context_class));
     if (!object)
         return NULL;
 
diff --git a/modules/cairo-image-surface.cpp b/modules/cairo-image-surface.cpp
index 2af2d79..408bc10 100644
--- a/modules/cairo-image-surface.cpp
+++ b/modules/cairo-image-surface.cpp
@@ -88,7 +88,7 @@ createFromPNG_func(JSContext *context,
         return false;
 
     JS::RootedObject surface_wrapper(context,
-        JS_NewObject(context, &gjs_cairo_image_surface_class, JS::NullPtr(), JS::NullPtr()));
+        JS_NewObject(context, &gjs_cairo_image_surface_class));
     if (!surface_wrapper) {
         gjs_throw(context, "failed to create surface");
         return false;
@@ -215,7 +215,7 @@ gjs_cairo_image_surface_from_surface(JSContext       *context,
     g_return_val_if_fail(cairo_surface_get_type(surface) == CAIRO_SURFACE_TYPE_IMAGE, NULL);
 
     JS::RootedObject object(context,
-        JS_NewObject(context, &gjs_cairo_image_surface_class, JS::NullPtr(), JS::NullPtr()));
+        JS_NewObject(context, &gjs_cairo_image_surface_class));
     if (!object) {
         gjs_throw(context, "failed to create image surface");
         return NULL;
diff --git a/modules/cairo-linear-gradient.cpp b/modules/cairo-linear-gradient.cpp
index 3c0b866..89fb087 100644
--- a/modules/cairo-linear-gradient.cpp
+++ b/modules/cairo-linear-gradient.cpp
@@ -82,7 +82,7 @@ gjs_cairo_linear_gradient_from_pattern(JSContext       *context,
     g_return_val_if_fail(cairo_pattern_get_type(pattern) == CAIRO_PATTERN_TYPE_LINEAR, NULL);
 
     JS::RootedObject object(context,
-        JS_NewObject(context, &gjs_cairo_linear_gradient_class, JS::NullPtr(), JS::NullPtr()));
+        JS_NewObject(context, &gjs_cairo_linear_gradient_class));
     if (!object) {
         gjs_throw(context, "failed to create linear gradient pattern");
         return NULL;
diff --git a/modules/cairo-path.cpp b/modules/cairo-path.cpp
index c4c0aed..5ffa05a 100644
--- a/modules/cairo-path.cpp
+++ b/modules/cairo-path.cpp
@@ -75,7 +75,7 @@ gjs_cairo_path_from_path(JSContext    *context,
     g_return_val_if_fail(path != NULL, NULL);
 
     JS::RootedObject object(context,
-        JS_NewObject(context, &gjs_cairo_path_class, JS::NullPtr(), JS::NullPtr()));
+        JS_NewObject(context, &gjs_cairo_path_class));
     if (!object) {
         gjs_throw(context, "failed to create path");
         return NULL;
diff --git a/modules/cairo-pdf-surface.cpp b/modules/cairo-pdf-surface.cpp
index 2e68a64..5ae5ff1 100644
--- a/modules/cairo-pdf-surface.cpp
+++ b/modules/cairo-pdf-surface.cpp
@@ -88,7 +88,7 @@ gjs_cairo_pdf_surface_from_surface(JSContext       *context,
     g_return_val_if_fail(cairo_surface_get_type(surface) == CAIRO_SURFACE_TYPE_PDF, NULL);
 
     JS::RootedObject object(context,
-        JS_NewObject(context, &gjs_cairo_pdf_surface_class, JS::NullPtr(), JS::NullPtr()));
+        JS_NewObject(context, &gjs_cairo_pdf_surface_class));
     if (!object) {
         gjs_throw(context, "failed to create pdf surface");
         return NULL;
diff --git a/modules/cairo-ps-surface.cpp b/modules/cairo-ps-surface.cpp
index 270c73d..0110708 100644
--- a/modules/cairo-ps-surface.cpp
+++ b/modules/cairo-ps-surface.cpp
@@ -97,7 +97,7 @@ gjs_cairo_ps_surface_from_surface(JSContext       *context,
     g_return_val_if_fail(cairo_surface_get_type(surface) == CAIRO_SURFACE_TYPE_PS, NULL);
 
     JS::RootedObject object(context,
-        JS_NewObject(context, &gjs_cairo_ps_surface_class, JS::NullPtr(), JS::NullPtr()));
+        JS_NewObject(context, &gjs_cairo_ps_surface_class));
     if (!object) {
         gjs_throw(context, "failed to create ps surface");
         return NULL;
diff --git a/modules/cairo-radial-gradient.cpp b/modules/cairo-radial-gradient.cpp
index f93ff29..308e69d 100644
--- a/modules/cairo-radial-gradient.cpp
+++ b/modules/cairo-radial-gradient.cpp
@@ -84,7 +84,7 @@ gjs_cairo_radial_gradient_from_pattern(JSContext       *context,
     g_return_val_if_fail(cairo_pattern_get_type(pattern) == CAIRO_PATTERN_TYPE_RADIAL, NULL);
 
     JS::RootedObject object(context,
-        JS_NewObject(context, &gjs_cairo_radial_gradient_class, JS::NullPtr(), JS::NullPtr()));
+        JS_NewObject(context, &gjs_cairo_radial_gradient_class));
     if (!object) {
         gjs_throw(context, "failed to create radial gradient pattern");
         return NULL;
diff --git a/modules/cairo-region.cpp b/modules/cairo-region.cpp
index 39ff07e..c22e7b0 100644
--- a/modules/cairo-region.cpp
+++ b/modules/cairo-region.cpp
@@ -147,8 +147,7 @@ static JSObject *
 make_rectangle(JSContext *context,
                cairo_rectangle_int_t *rect)
 {
-    JS::RootedObject rect_obj(context,
-        JS_NewObject(context, NULL, JS::NullPtr(), JS::NullPtr()));
+    JS::RootedObject rect_obj(context, JS_NewObject(context, NULL));
     JS::RootedValue val(context);
 
     val = JS::Int32Value(rect->x);
@@ -278,7 +277,7 @@ gjs_cairo_region_from_region(JSContext *context,
                              cairo_region_t *region)
 {
     JS::RootedObject object(context,
-        JS_NewObject(context, &gjs_cairo_region_class, JS::NullPtr(), JS::NullPtr()));
+        JS_NewObject(context, &gjs_cairo_region_class));
     if (!object)
         return NULL;
 
diff --git a/modules/cairo-solid-pattern.cpp b/modules/cairo-solid-pattern.cpp
index 9d994b8..d7fd747 100644
--- a/modules/cairo-solid-pattern.cpp
+++ b/modules/cairo-solid-pattern.cpp
@@ -112,7 +112,7 @@ gjs_cairo_solid_pattern_from_pattern(JSContext       *context,
     g_return_val_if_fail(cairo_pattern_get_type(pattern) == CAIRO_PATTERN_TYPE_SOLID, NULL);
 
     JS::RootedObject object(context,
-        JS_NewObject(context, &gjs_cairo_solid_pattern_class, JS::NullPtr(), JS::NullPtr()));
+        JS_NewObject(context, &gjs_cairo_solid_pattern_class));
     if (!object) {
         gjs_throw(context, "failed to create solid pattern");
         return NULL;
diff --git a/modules/cairo-surface-pattern.cpp b/modules/cairo-surface-pattern.cpp
index 43ba99e..c38ac56 100644
--- a/modules/cairo-surface-pattern.cpp
+++ b/modules/cairo-surface-pattern.cpp
@@ -187,7 +187,7 @@ gjs_cairo_surface_pattern_from_pattern(JSContext       *context,
     g_return_val_if_fail(cairo_pattern_get_type(pattern) == CAIRO_PATTERN_TYPE_SURFACE, NULL);
 
     JS::RootedObject object(context,
-        JS_NewObject(context, &gjs_cairo_surface_pattern_class, JS::NullPtr(), JS::NullPtr()));
+        JS_NewObject(context, &gjs_cairo_surface_pattern_class));
     if (!object) {
         gjs_throw(context, "failed to create surface pattern");
         return NULL;
diff --git a/modules/cairo-surface.cpp b/modules/cairo-surface.cpp
index 1bfdb73..abfb313 100644
--- a/modules/cairo-surface.cpp
+++ b/modules/cairo-surface.cpp
@@ -206,7 +206,7 @@ gjs_cairo_surface_from_surface(JSContext       *context,
         return gjs_cairo_svg_surface_from_surface(context, surface);
 
     JS::RootedObject object(context,
-        JS_NewObject(context, &gjs_cairo_surface_class, JS::NullPtr(), JS::NullPtr()));
+        JS_NewObject(context, &gjs_cairo_surface_class));
     if (!object) {
         gjs_throw(context, "failed to create surface");
         return NULL;
diff --git a/modules/cairo-svg-surface.cpp b/modules/cairo-svg-surface.cpp
index f18ee0f..b6807a7 100644
--- a/modules/cairo-svg-surface.cpp
+++ b/modules/cairo-svg-surface.cpp
@@ -88,7 +88,7 @@ gjs_cairo_svg_surface_from_surface(JSContext       *context,
     g_return_val_if_fail(cairo_surface_get_type(surface) == CAIRO_SURFACE_TYPE_SVG, NULL);
 
     JS::RootedObject object(context,
-        JS_NewObject(context, &gjs_cairo_svg_surface_class, JS::NullPtr(), JS::NullPtr()));
+        JS_NewObject(context, &gjs_cairo_svg_surface_class));
     if (!object) {
         gjs_throw(context, "failed to create svg surface");
         return NULL;
diff --git a/modules/cairo.cpp b/modules/cairo.cpp
index 15fadae..f3e4647 100644
--- a/modules/cairo.cpp
+++ b/modules/cairo.cpp
@@ -63,7 +63,7 @@ gjs_js_define_cairo_stuff(JSContext              *context,
     JS::RootedObject surface_proto(context), pattern_proto(context),
         gradient_proto(context);
 
-    module.set(JS_NewObject(context, NULL, JS::NullPtr(), JS::NullPtr()));
+    module.set(JS_NewObject(context, NULL));
 
     obj = gjs_cairo_region_create_proto(context, module,
                                         "Region", JS::NullPtr());
diff --git a/modules/console.cpp b/modules/console.cpp
index abcb175..60f095b 100644
--- a/modules/console.cpp
+++ b/modules/console.cpp
@@ -169,7 +169,7 @@ gjs_console_interact(JSContext *context,
     int startline;
     FILE *file = stdin;
 
-    JS_SetErrorReporter(context, gjs_console_error_reporter);
+    JS_SetErrorReporter(JS_GetRuntime(context), gjs_console_error_reporter);
 
         /* It's an interactive filehandle; drop into read-eval-print loop. */
     lineno = 1;
@@ -245,7 +245,7 @@ bool
 gjs_define_console_stuff(JSContext              *context,
                          JS::MutableHandleObject module)
 {
-    module.set(JS_NewObject(context, NULL, JS::NullPtr(), JS::NullPtr()));
+    module.set(JS_NewObject(context, NULL));
     return JS_DefineFunction(context, module, "interact", gjs_console_interact,
                              1, GJS_MODULE_PROP_FLAGS);
 }
diff --git a/modules/system.cpp b/modules/system.cpp
index c2c1551..823585e 100644
--- a/modules/system.cpp
+++ b/modules/system.cpp
@@ -160,7 +160,7 @@ gjs_js_define_system_stuff(JSContext              *context,
     char *program_name;
     bool retval;
 
-    module.set(JS_NewObject(context, NULL, JS::NullPtr(), JS::NullPtr()));
+    module.set(JS_NewObject(context, NULL));
 
     if (!JS_DefineFunctions(context, module, &module_funcs[0]))
         return false;
@@ -182,16 +182,12 @@ gjs_js_define_system_stuff(JSContext              *context,
     if (!JS_DefineProperty(context, module,
                            "programInvocationName",
                            value,
-                           GJS_MODULE_PROP_FLAGS | JSPROP_READONLY,
-                           JS_PropertyStub,
-                           JS_StrictPropertyStub))
+                           GJS_MODULE_PROP_FLAGS | JSPROP_READONLY))
         goto out;
 
     if (!JS_DefineProperty(context, module,
                            "version", GJS_VERSION,
-                           GJS_MODULE_PROP_FLAGS | JSPROP_READONLY,
-                           JS_PropertyStub,
-                           JS_StrictPropertyStub))
+                           GJS_MODULE_PROP_FLAGS | JSPROP_READONLY))
         goto out;
 
     retval = true;
diff --git a/test/gjs-test-utils.cpp b/test/gjs-test-utils.cpp
index 7ed2afd..f6e4f4b 100644
--- a/test/gjs-test-utils.cpp
+++ b/test/gjs-test-utils.cpp
@@ -58,7 +58,7 @@ gjs_unit_test_fixture_setup(GjsUnitTestFixture *fx,
 
     /* This is for shoving private data into the error reporter callback */
     g_object_set_data(G_OBJECT(fx->gjs_context), "test fixture", fx);
-    JS_SetErrorReporter(fx->cx, test_error_reporter);
+    JS_SetErrorReporter(JS_GetRuntime(fx->cx), test_error_reporter);
 
     JS_BeginRequest(fx->cx);
 


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