[gjs/wip/ptomato/mozjs31prep] WIP - remove JSVAL macros



commit 2cbc3c7b73a4b8806e483195a251cd1b60f1d19a
Author: Philip Chimento <philip chimento gmail com>
Date:   Fri Sep 9 23:56:51 2016 -0700

    WIP - remove JSVAL macros

 gi/arg.cpp                        |  220 ++++++++++++++++++-------------------
 gi/boxed.cpp                      |   26 ++---
 gi/closure.cpp                    |    2 +-
 gi/enumeration.cpp                |    8 +-
 gi/function.cpp                   |   43 ++++----
 gi/fundamental.cpp                |   18 ++--
 gi/gerror.cpp                     |   36 +++----
 gi/gtype.cpp                      |   12 +-
 gi/interface.cpp                  |    4 +-
 gi/keep-alive.cpp                 |   12 +-
 gi/object.cpp                     |   76 ++++++-------
 gi/param.cpp                      |   10 +-
 gi/repo.cpp                       |   59 +++++-----
 gi/union.cpp                      |   10 +-
 gi/value.cpp                      |   90 ++++++++--------
 gjs/byteArray.cpp                 |   58 +++++-----
 gjs/compat.h                      |    4 +-
 gjs/context.cpp                   |   25 ++--
 gjs/coverage.cpp                  |   95 +++++++---------
 gjs/importer.cpp                  |   74 ++++++------
 gjs/jsapi-dynamic-class.cpp       |   14 +-
 gjs/jsapi-util-array.cpp          |    6 +-
 gjs/jsapi-util-string.cpp         |   12 +-
 gjs/jsapi-util.cpp                |  123 ++++++++++-----------
 gjs/jsapi-util.h                  |   14 +-
 gjs/runtime.cpp                   |   12 +-
 modules/cairo-context.cpp         |   93 ++++++++--------
 modules/cairo-gradient.cpp        |    8 +-
 modules/cairo-region.cpp          |   26 ++---
 modules/cairo-surface-pattern.cpp |   12 +-
 modules/cairo-surface.cpp         |   10 +-
 modules/cairo.cpp                 |   34 +++---
 modules/console.cpp               |    4 +-
 modules/system.cpp                |   12 +-
 test/gjs-test-coverage.cpp        |    2 +-
 test/gjs-tests.cpp                |   22 ++--
 36 files changed, 618 insertions(+), 668 deletions(-)
---
diff --git a/gi/arg.cpp b/gi/arg.cpp
index 787b65f..a41437d 100644
--- a/gi/arg.cpp
+++ b/gi/arg.cpp
@@ -308,9 +308,8 @@ gjs_array_to_g_list(JSContext   *context,
     for (i = 0; i < length; ++i) {
         GArgument elem_arg = { 0 };
 
-        elem = JSVAL_VOID;
-        if (!JS_GetElement(context, JSVAL_TO_OBJECT(array_value),
-                           i, &elem)) {
+        elem = JS::UndefinedValue();
+        if (!JS_GetElement(context, array_value.toObjectOrNull(), i, &elem)) {
             gjs_throw(context,
                       "Missing array element %u",
                       i);
@@ -363,8 +362,8 @@ gjs_object_to_g_hash(JSContext   *context,
     JSObject *iter;
     jsid prop_id;
 
-    g_assert(JSVAL_IS_OBJECT(hash_value));
-    props = JSVAL_TO_OBJECT(hash_value);
+    g_assert(hash_value.isObjectOrNull());
+    props = hash_value.toObjectOrNull();
 
     if (transfer == GI_TRANSFER_CONTAINER) {
         if (type_needs_release (key_param_info, g_type_info_get_tag(key_param_info)) ||
@@ -449,9 +448,9 @@ gjs_array_from_strv(JSContext   *context,
     if (obj == NULL)
         return false;
 
-    *value_p = OBJECT_TO_JSVAL(obj);
+    *value_p = JS::ObjectValue(*obj);
 
-    elem = JSVAL_VOID;
+    elem = JS::UndefinedValue();
     JS_AddValueRoot(context, &elem);
 
     for (i = 0; strv[i] != NULL; i++) {
@@ -486,9 +485,8 @@ gjs_array_to_strv(JSContext   *context,
     for (i = 0; i < length; ++i) {
         JS::Value elem;
 
-        elem = JSVAL_VOID;
-        if (!JS_GetElement(context, JSVAL_TO_OBJECT(array_value),
-                           i, &elem)) {
+        elem = JS::UndefinedValue();
+        if (!JS_GetElement(context, array_value.toObjectOrNull(), i, &elem)) {
             g_free(result);
             gjs_throw(context,
                       "Missing array element %u",
@@ -496,7 +494,7 @@ gjs_array_to_strv(JSContext   *context,
             return false;
         }
 
-        if (!JSVAL_IS_STRING(elem)) {
+        if (!elem.isString()) {
             gjs_throw(context,
                       "Invalid element in string array");
             g_strfreev(result);
@@ -571,9 +569,8 @@ gjs_array_to_intarray(JSContext   *context,
         JS::Value elem;
         bool success;
 
-        elem = JSVAL_VOID;
-        if (!JS_GetElement(context, JSVAL_TO_OBJECT(array_value),
-                           i, &elem)) {
+        elem = JS::UndefinedValue();
+        if (!JS_GetElement(context, array_value.toObjectOrNull(), i, &elem)) {
             g_free(result);
             gjs_throw(context,
                       "Missing array element %u",
@@ -626,18 +623,17 @@ gjs_gtypearray_to_array(JSContext   *context,
         JS::Value elem;
         GType gtype;
 
-        elem = JSVAL_VOID;
-        if (!JS_GetElement(context, JSVAL_TO_OBJECT(array_value),
-                           i, &elem)) {
+        elem = JS::UndefinedValue();
+        if (!JS_GetElement(context, array_value.toObjectOrNull(), i, &elem)) {
             g_free(result);
             gjs_throw(context, "Missing array element %u", i);
             return false;
         }
 
-        if (!JSVAL_IS_OBJECT(elem))
+        if (!elem.isObjectOrNull())
             goto err;
 
-        gtype = gjs_gtype_get_actual_gtype(context, JSVAL_TO_OBJECT(elem));
+        gtype = gjs_gtype_get_actual_gtype(context, elem.toObjectOrNull());
         if (gtype == G_TYPE_INVALID)
             goto err;
 
@@ -672,9 +668,8 @@ gjs_array_to_floatarray(JSContext   *context,
         double val;
         bool success;
 
-        elem = JSVAL_VOID;
-        if (!JS_GetElement(context, JSVAL_TO_OBJECT(array_value),
-                           i, &elem)) {
+        elem = JS::UndefinedValue();
+        if (!JS_GetElement(context, array_value.toObjectOrNull(), i, &elem)) {
             g_free(result);
             gjs_throw(context,
                       "Missing array element %u",
@@ -728,9 +723,8 @@ gjs_array_to_ptrarray(JSContext   *context,
 
         bool success;
 
-        elem = JSVAL_VOID;
-        if (!JS_GetElement(context, JSVAL_TO_OBJECT(array_value),
-                           i, &elem)) {
+        elem = JS::UndefinedValue();
+        if (!JS_GetElement(context, array_value.toObjectOrNull(), i, &elem)) {
             g_free(array);
             gjs_throw(context,
                       "Missing array element %u",
@@ -773,10 +767,9 @@ gjs_array_to_flat_gvalue_array(JSContext   *context,
 
     for (i = 0; i < length; i ++) {
         JS::Value elem;
-        elem = JSVAL_VOID;
+        elem = JS::UndefinedValue();
 
-        if (!JS_GetElement(context, JSVAL_TO_OBJECT(array_value),
-                           i, &elem)) {
+        if (!JS_GetElement(context, array_value.toObjectOrNull(), i, &elem)) {
             g_free(values);
             gjs_throw(context,
                       "Missing array element %u",
@@ -817,7 +810,7 @@ gjs_array_from_flat_gvalue_array(JSContext   *context,
     if (result) {
         JSObject *jsarray;
         jsarray = JS_NewArrayObject(context, length, elems);
-        *value = OBJECT_TO_JSVAL(jsarray);
+        *value = JS::ObjectOrNullValue(jsarray);
     }
 
     return result;
@@ -1093,29 +1086,29 @@ gjs_array_to_explicit_array_internal(JSContext       *context,
 
     param_info = g_type_info_get_param_type(type_info, 0);
 
-    if ((JSVAL_IS_NULL(value) && !may_be_null) ||
-        (!JSVAL_IS_STRING(value) && !JSVAL_IS_OBJECT(value) && !JSVAL_IS_NULL(value))) {
+    if ((value.isNull() && !may_be_null) ||
+        (!value.isString() && !value.isObjectOrNull())) {
         throw_invalid_argument(context, value, param_info, arg_name, arg_type);
         goto out;
     }
 
     length_name = gjs_context_get_const_string(context, GJS_STRING_LENGTH);
 
-    if (JSVAL_IS_NULL(value)) {
+    if (value.isNull()) {
         *contents = NULL;
         *length_p = 0;
-    } else if (JSVAL_IS_STRING(value)) {
+    } else if (value.isString()) {
         /* Allow strings as int8/uint8/int16/uint16 arrays */
         if (!gjs_string_to_intarray(context, value, param_info,
                                     contents, length_p))
             goto out;
-    } else if (JS_HasPropertyById(context, JSVAL_TO_OBJECT(value), length_name, &found_length) &&
+    } else if (JS_HasPropertyById(context, &value.toObject(), length_name, &found_length) &&
                found_length) {
         JS::Value length_value;
         guint32 length;
 
         if (!gjs_object_require_property(context,
-                                         JSVAL_TO_OBJECT(value), NULL,
+                                         &value.toObject(), NULL,
                                          length_name,
                                          &length_value) ||
             !JS_ValueToECMAUint32(context, length_value, &length)) {
@@ -1271,7 +1264,7 @@ gjs_value_to_g_argument(JSContext      *context,
         break;
 
     case GI_TYPE_TAG_UNICHAR:
-        if (JSVAL_IS_STRING(value)) {
+        if (value.isString()) {
             if (!gjs_unichar_from_string(context, value, &arg->v_uint32))
                 wrong = true;
         } else {
@@ -1281,9 +1274,9 @@ gjs_value_to_g_argument(JSContext      *context,
         break;
 
     case GI_TYPE_TAG_GTYPE:
-        if (JSVAL_IS_OBJECT(value)) {
+        if (value.isObjectOrNull()) {
             GType gtype;
-            gtype = gjs_gtype_get_actual_gtype(context, JSVAL_TO_OBJECT(value));
+            gtype = gjs_gtype_get_actual_gtype(context, value.toObjectOrNull());
             if (gtype == G_TYPE_INVALID)
                 wrong = true;
             arg->v_ssize = gtype;
@@ -1295,9 +1288,9 @@ gjs_value_to_g_argument(JSContext      *context,
 
     case GI_TYPE_TAG_FILENAME:
         nullable_type = true;
-        if (JSVAL_IS_NULL(value)) {
+        if (value.isNull()) {
             arg->v_pointer = NULL;
-        } else if (JSVAL_IS_STRING(value)) {
+        } else if (value.isString()) {
             char *filename_str;
             if (gjs_string_to_filename(context, value, &filename_str))
                 // doing this as a separate step to avoid type-punning
@@ -1311,9 +1304,9 @@ gjs_value_to_g_argument(JSContext      *context,
         break;
     case GI_TYPE_TAG_UTF8:
         nullable_type = true;
-        if (JSVAL_IS_NULL(value)) {
+        if (value.isNull()) {
             arg->v_pointer = NULL;
-        } else if (JSVAL_IS_STRING(value)) {
+        } else if (value.isString()) {
             char *utf8_str;
             if (gjs_string_to_utf8(context, value, &utf8_str))
                 // doing this as a separate step to avoid type-punning
@@ -1328,12 +1321,11 @@ gjs_value_to_g_argument(JSContext      *context,
 
     case GI_TYPE_TAG_ERROR:
         nullable_type = true;
-        if (JSVAL_IS_NULL(value)) {
+        if (value.isNull()) {
             arg->v_pointer = NULL;
-        } else if (JSVAL_IS_OBJECT(value)) {
-            if (gjs_typecheck_gerror(context, JSVAL_TO_OBJECT(value), true)) {
-                arg->v_pointer = gjs_gerror_from_error(context,
-                                                       JSVAL_TO_OBJECT(value));
+        } else if (value.isObject()) {
+            if (gjs_typecheck_gerror(context, &value.toObject(), true)) {
+                arg->v_pointer = gjs_gerror_from_error(context, &value.toObject());
 
                 if (transfer != GI_TRANSFER_NOTHING)
                     arg->v_pointer = g_error_copy ((const GError *) arg->v_pointer);
@@ -1414,20 +1406,19 @@ gjs_value_to_g_argument(JSContext      *context,
                     arg->v_pointer = NULL;
                     wrong = true;
                 }
-            } else if (expect_object != JSVAL_IS_OBJECT(value)) {
-                /* JSVAL_IS_OBJECT handles null too */
+            } else if (expect_object != value.isObjectOrNull()) {
                 wrong = true;
                 report_type_mismatch = true;
                 break;
-            } else if (JSVAL_IS_NULL(value)) {
+            } else if (value.isNull()) {
                 arg->v_pointer = NULL;
-            } else if (JSVAL_IS_OBJECT(value)) {
+            } else if (value.isObject()) {
                 if (interface_type == GI_INFO_TYPE_STRUCT &&
                     g_struct_info_is_gtype_struct((GIStructInfo*)interface_info)) {
                     GType gtype;
                     gpointer klass;
 
-                    gtype = gjs_gtype_get_actual_gtype(context, JSVAL_TO_OBJECT(value));
+                    gtype = gjs_gtype_get_actual_gtype(context, &value.toObject());
 
                     if (gtype == G_TYPE_NONE) {
                         wrong = true;
@@ -1451,27 +1442,27 @@ gjs_value_to_g_argument(JSContext      *context,
                     /* Handle Struct/Union first since we don't necessarily need a GType for them */
                     /* We special case Closures later, so skip them here */
                     !g_type_is_a(gtype, G_TYPE_CLOSURE)) {
-                    JSObject *obj = JSVAL_TO_OBJECT(value);
+                    JSObject *obj = &value.toObject();
 
                     if (g_type_is_a(gtype, G_TYPE_BYTES)
                         && gjs_typecheck_bytearray(context, obj, false)) {
                         arg->v_pointer = gjs_byte_array_get_bytes(context, obj);
                     } else if (g_type_is_a(gtype, G_TYPE_ERROR)) {
-                        if (!gjs_typecheck_gerror(context, JSVAL_TO_OBJECT(value), true)) {
+                        if (!gjs_typecheck_gerror(context, &value.toObject(), true)) {
                             arg->v_pointer = NULL;
                             wrong = true;
                         } else {
                             arg->v_pointer = gjs_gerror_from_error(context,
-                                                                   JSVAL_TO_OBJECT(value));
+                                                                   &value.toObject());
                         }
                     } else {
-                        if (!gjs_typecheck_boxed(context, JSVAL_TO_OBJECT(value),
+                        if (!gjs_typecheck_boxed(context, &value.toObject(),
                                                  interface_info, gtype, true)) {
                             arg->v_pointer = NULL;
                             wrong = true;
                         } else {
                             arg->v_pointer = gjs_c_struct_from_boxed(context,
-                                                                     JSVAL_TO_OBJECT(value));
+                                                                     &value.toObject());
                         }
                     }
 
@@ -1489,10 +1480,10 @@ gjs_value_to_g_argument(JSContext      *context,
                     }
 
                 } else if (interface_type == GI_INFO_TYPE_UNION) {
-                    if (gjs_typecheck_union(context, JSVAL_TO_OBJECT(value),
+                    if (gjs_typecheck_union(context, &value.toObject(),
                                             interface_info, gtype, true)) {
                         arg->v_pointer = gjs_c_union_from_union(context,
-                                                                JSVAL_TO_OBJECT(value));
+                                                                &value.toObject());
 
                         if (transfer != GI_TRANSFER_NOTHING) {
                             if (g_type_is_a(gtype, G_TYPE_BOXED))
@@ -1512,9 +1503,9 @@ gjs_value_to_g_argument(JSContext      *context,
 
                 } else if (gtype != G_TYPE_NONE) {
                     if (g_type_is_a(gtype, G_TYPE_OBJECT)) {
-                        if (gjs_typecheck_object(context, JSVAL_TO_OBJECT(value), gtype, true)) {
+                        if (gjs_typecheck_object(context, &value.toObject(), gtype, true)) {
                             arg->v_pointer = gjs_g_object_from_object(context,
-                                                                      JSVAL_TO_OBJECT(value));
+                                                                      &value.toObject());
 
                             if (transfer != GI_TRANSFER_NOTHING)
                                 g_object_ref(G_OBJECT(arg->v_pointer));
@@ -1523,8 +1514,8 @@ gjs_value_to_g_argument(JSContext      *context,
                             wrong = true;
                         }
                     } else if (g_type_is_a(gtype, G_TYPE_PARAM)) {
-                        if (gjs_typecheck_param(context, JSVAL_TO_OBJECT(value), gtype, true)) {
-                            arg->v_pointer = gjs_g_param_from_param(context, JSVAL_TO_OBJECT(value));
+                        if (gjs_typecheck_param(context, &value.toObject(), gtype, true)) {
+                            arg->v_pointer = gjs_g_param_from_param(context, &value.toObject());
                             if (transfer != GI_TRANSFER_NOTHING)
                                 g_param_spec_ref(G_PARAM_SPEC(arg->v_pointer));
                         } else {
@@ -1534,7 +1525,7 @@ gjs_value_to_g_argument(JSContext      *context,
                     } else if (g_type_is_a(gtype, G_TYPE_BOXED)) {
                         if (g_type_is_a(gtype, G_TYPE_CLOSURE)) {
                             arg->v_pointer = gjs_closure_new_marshaled(context,
-                                                                       JSVAL_TO_OBJECT(value),
+                                                                       &value.toObject(),
                                                                        "boxed");
                             g_closure_ref((GClosure *) arg->v_pointer);
                             g_closure_sink((GClosure *) arg->v_pointer);
@@ -1546,9 +1537,9 @@ gjs_value_to_g_argument(JSContext      *context,
                                       interface_type);
                         }
                     } else if (G_TYPE_IS_INSTANTIATABLE(gtype)) {
-                        if (gjs_typecheck_fundamental(context, JSVAL_TO_OBJECT(value), gtype, true)) {
+                        if (gjs_typecheck_fundamental(context, &value.toObject(), gtype, true)) {
                             arg->v_pointer = gjs_g_fundamental_from_object(context,
-                                                                           JSVAL_TO_OBJECT(value));
+                                                                           &value.toObject());
 
                             if (transfer != GI_TRANSFER_NOTHING)
                                 gjs_fundamental_ref(context, arg->v_pointer);
@@ -1559,19 +1550,19 @@ gjs_value_to_g_argument(JSContext      *context,
                     } else if (G_TYPE_IS_INTERFACE(gtype)) {
                         /* Could be a GObject interface that's missing a prerequisite, or could
                            be a fundamental */
-                        if (gjs_typecheck_object(context, JSVAL_TO_OBJECT(value), gtype, false)) {
-                            arg->v_pointer = gjs_g_object_from_object(context, JSVAL_TO_OBJECT(value));
+                        if (gjs_typecheck_object(context, &value.toObject(), gtype, false)) {
+                            arg->v_pointer = gjs_g_object_from_object(context, &value.toObject());
 
                             if (transfer != GI_TRANSFER_NOTHING)
                                 g_object_ref(arg->v_pointer);
-                        } else if (gjs_typecheck_fundamental(context, JSVAL_TO_OBJECT(value), gtype, false)) 
{
-                            arg->v_pointer = gjs_g_fundamental_from_object(context, JSVAL_TO_OBJECT(value));
+                        } else if (gjs_typecheck_fundamental(context, &value.toObject(), gtype, false)) {
+                            arg->v_pointer = gjs_g_fundamental_from_object(context, &value.toObject());
 
                             if (transfer != GI_TRANSFER_NOTHING)
                                 gjs_fundamental_ref(context, arg->v_pointer);
                         } else {
                             /* Call again with throw=true to set the exception */
-                            gjs_typecheck_object(context, JSVAL_TO_OBJECT(value), gtype, true);
+                            gjs_typecheck_object(context, &value.toObject(), gtype, true);
                             arg->v_pointer = NULL;
                             wrong = true;
                         }
@@ -1588,7 +1579,7 @@ gjs_value_to_g_argument(JSContext      *context,
                 if (arg->v_pointer == NULL) {
                     gjs_debug(GJS_DEBUG_GFUNCTION,
                               "conversion of JSObject %p type %s to type %s failed",
-                              JSVAL_TO_OBJECT(value),
+                              &value.toObject(),
                               JS_GetTypeName(context,
                                              JS_TypeOfValue(context, value)),
                               g_base_info_get_name ((GIBaseInfo *)interface_info));
@@ -1597,7 +1588,7 @@ gjs_value_to_g_argument(JSContext      *context,
                     wrong = true;
                 }
 
-            } else if (JSVAL_IS_NUMBER(value)) {
+            } else if (value.isNumber()) {
                 if (interface_type == GI_INFO_TYPE_ENUM) {
                     gint64 value_int64;
 
@@ -1650,15 +1641,14 @@ gjs_value_to_g_argument(JSContext      *context,
          * means empty array in JavaScript, it doesn't mean null in
          * JavaScript.
          */
-        if (!JSVAL_IS_NULL(value) &&
-            JSVAL_IS_OBJECT(value) &&
-            JS_HasPropertyById(context, JSVAL_TO_OBJECT(value), length_name, &found_length) &&
+        if (value.isObject() &&
+            JS_HasPropertyById(context, &value.toObject(), length_name, &found_length) &&
             found_length) {
             JS::Value length_value;
             guint32 length;
 
             if (!gjs_object_require_property(context,
-                                             JSVAL_TO_OBJECT(value), NULL,
+                                             &value.toObject(), NULL,
                                              length_name,
                                              &length_value) ||
                 !JS_ValueToECMAUint32(context, length_value, &length)) {
@@ -1700,13 +1690,13 @@ gjs_value_to_g_argument(JSContext      *context,
     }
 
     case GI_TYPE_TAG_GHASH:
-        if (JSVAL_IS_NULL(value)) {
+        if (value.isNull()) {
             arg->v_pointer = NULL;
             if (!may_be_null) {
                 wrong = true;
                 report_type_mismatch = true;
             }
-        } else if (!JSVAL_IS_OBJECT(value)) {
+        } else if (!value.isObject()) {
             wrong = true;
             report_type_mismatch = true;
         } else {
@@ -1748,10 +1738,10 @@ gjs_value_to_g_argument(JSContext      *context,
         /* First, let's handle the case where we're passed an instance
          * of our own byteArray class.
          */
-        if (JSVAL_IS_OBJECT(value) &&
-            gjs_typecheck_bytearray(context, JSVAL_TO_OBJECT(value), false))
+        if (value.isObjectOrNull() &&
+            gjs_typecheck_bytearray(context, value.toObjectOrNull(), false))
             {
-                JSObject *bytearray_obj = JSVAL_TO_OBJECT(value);
+                JSObject *bytearray_obj = value.toObjectOrNull();
                 if (array_type == GI_ARRAY_TYPE_BYTE_ARRAY) {
                     arg->v_pointer = gjs_byte_array_get_byte_array(context, bytearray_obj);
                     break;
@@ -2023,9 +2013,9 @@ gjs_array_from_g_list (JSContext  *context,
     if (obj == NULL)
         return false;
 
-    *value_p = OBJECT_TO_JSVAL(obj);
+    *value_p = JS::ObjectValue(*obj);
 
-    elem = JSVAL_VOID;
+    elem = JS::UndefinedValue();
     JS_AddValueRoot(context, &elem);
 
     result = false;
@@ -2104,7 +2094,7 @@ gjs_array_from_carray_internal (JSContext  *context,
         obj = gjs_byte_array_from_byte_array (context, &gbytearray);
         if (obj == NULL)
             return false;
-        *value_p = OBJECT_TO_JSVAL(obj);
+        *value_p = JS::ObjectValue(*obj);
         return true;
     } 
 
@@ -2112,9 +2102,9 @@ gjs_array_from_carray_internal (JSContext  *context,
     if (obj == NULL)
         return false;
 
-    *value_p = OBJECT_TO_JSVAL(obj);
+    *value_p = JS::ObjectValue(*obj);
 
-    elem = JSVAL_VOID;
+    elem = JS::UndefinedValue();
     JS_AddValueRoot(context, &elem);
 
 #define ITERATE(type) \
@@ -2270,7 +2260,7 @@ gjs_array_from_boxed_array (JSContext   *context,
     gsize length = 0;
 
     if (arg->v_pointer == NULL) {
-        *value_p = JSVAL_NULL;
+        *value_p = JS::UndefinedValue();
         return true;
     }
 
@@ -2321,7 +2311,7 @@ gjs_array_from_zero_terminated_c_array (JSContext  *context,
         obj = gjs_byte_array_from_byte_array (context, &gbytearray);
         if (obj == NULL)
             return false;
-        *value_p = OBJECT_TO_JSVAL(obj);
+        *value_p = JS::ObjectValue(*obj);
         return true;
     } 
 
@@ -2329,9 +2319,9 @@ gjs_array_from_zero_terminated_c_array (JSContext  *context,
     if (obj == NULL)
         return false;
 
-    *value_p = OBJECT_TO_JSVAL(obj);
+    *value_p = JS::ObjectValue(*obj);
 
-    elem = JSVAL_VOID;
+    elem = JS::UndefinedValue();
     JS_AddValueRoot(context, &elem);
 
 #define ITERATE(type) \
@@ -2420,7 +2410,7 @@ gjs_object_from_g_hash (JSContext  *context,
 
     // a NULL hash table becomes a null JS value
     if (hash==NULL) {
-        *value_p = JSVAL_NULL;
+        *value_p = JS::NullValue();
         return true;
     }
 
@@ -2428,13 +2418,13 @@ gjs_object_from_g_hash (JSContext  *context,
     if (obj == NULL)
         return false;
 
-    *value_p = OBJECT_TO_JSVAL(obj);
+    *value_p = JS::ObjectValue(*obj);
     JS_AddObjectRoot(context, &obj);
 
-    keyjs = JSVAL_VOID;
+    keyjs = JS::UndefinedValue();
     JS_AddValueRoot(context, &keyjs);
 
-    valjs = JSVAL_VOID;
+    valjs = JS::UndefinedValue();
     JS_AddValueRoot(context, &valjs);
 
     keystr = NULL;
@@ -2454,7 +2444,7 @@ gjs_object_from_g_hash (JSContext  *context,
         if (!keystr)
             goto out;
 
-        if (!gjs_string_to_utf8(context, STRING_TO_JSVAL(keystr), &keyutf8))
+        if (!gjs_string_to_utf8(context, JS::StringValue(keystr), &keyutf8))
             goto out;
 
         if (!gjs_value_from_g_argument(context, &valjs,
@@ -2497,15 +2487,15 @@ gjs_value_from_g_argument (JSContext  *context,
                       "Converting GArgument %s to JS::Value",
                       g_type_tag_to_string(type_tag));
 
-    *value_p = JSVAL_NULL;
+    *value_p = JS::NullValue();
 
     switch (type_tag) {
     case GI_TYPE_TAG_VOID:
-        *value_p = JSVAL_VOID; /* or JSVAL_NULL ? */
+        *value_p = JS::UndefinedValue(); /* or JS::NullValue() ? */
         break;
 
     case GI_TYPE_TAG_BOOLEAN:
-        *value_p = BOOLEAN_TO_JSVAL(!!arg->v_int);
+        *value_p = JS::BooleanValue(!!arg->v_int);
         break;
 
     case GI_TYPE_TAG_INT32:
@@ -2542,7 +2532,7 @@ gjs_value_from_g_argument (JSContext  *context,
         {
             JSObject *obj;
             obj = gjs_gtype_create_gtype_wrapper(context, arg->v_ssize);
-            *value_p = OBJECT_TO_JSVAL(obj);
+            *value_p = JS::ObjectOrNullValue(obj);
         }
         break;
 
@@ -2569,7 +2559,7 @@ gjs_value_from_g_argument (JSContext  *context,
         if (arg->v_pointer)
             return gjs_string_from_filename(context, (const char *) arg->v_pointer, -1, value_p);
         else {
-            /* For NULL we'll return JSVAL_NULL, which is already set
+            /* For NULL we'll return JS::NullValue(), which is already set
              * in *value_p
              */
             return true;
@@ -2578,7 +2568,7 @@ gjs_value_from_g_argument (JSContext  *context,
         if (arg->v_pointer)
             return gjs_string_from_utf8(context, (const char *) arg->v_pointer, -1, value_p);
         else {
-            /* For NULL we'll return JSVAL_NULL, which is already set
+            /* For NULL we'll return JS::NullValue(), which is already set
              * in *value_p
              */
             return true;
@@ -2589,7 +2579,7 @@ gjs_value_from_g_argument (JSContext  *context,
             if (arg->v_pointer) {
                 JSObject *obj = gjs_error_from_gerror(context, (GError *) arg->v_pointer, false);
                 if (obj) {
-                    *value_p = OBJECT_TO_JSVAL(obj);
+                    *value_p = JS::ObjectValue(*obj);
                     return true;
                 }
 
@@ -2608,7 +2598,7 @@ gjs_value_from_g_argument (JSContext  *context,
             interface_info = g_type_info_get_interface(type_info);
             g_assert(interface_info != NULL);
 
-            value = JSVAL_VOID;
+            value = JS::UndefinedValue();
 
             interface_type = g_base_info_get_type(interface_info);
 
@@ -2651,7 +2641,7 @@ gjs_value_from_g_argument (JSContext  *context,
 
             /* Everything else is a pointer type, NULL is the easy case */
             if (arg->v_pointer == NULL) {
-                value = JSVAL_NULL;
+                value = JS::NullValue();
                 goto out;
             }
 
@@ -2686,7 +2676,7 @@ gjs_value_from_g_argument (JSContext  *context,
             /* Test GValue and GError before Struct, or it will be handled as the latter */
             if (g_type_is_a(gtype, G_TYPE_VALUE)) {
                 if (!gjs_value_from_g_value(context, &value, (const GValue *) arg->v_pointer))
-                    value = JSVAL_VOID; /* Make sure error is flagged */
+                    value = JS::UndefinedValue(); /* Make sure error is flagged */
 
                 goto out;
             }
@@ -2695,9 +2685,9 @@ gjs_value_from_g_argument (JSContext  *context,
 
                 obj = gjs_error_from_gerror(context, (GError *) arg->v_pointer, false);
                 if (obj)
-                    value = OBJECT_TO_JSVAL(obj);
+                    value = JS::ObjectValue(*obj);
                 else
-                    value = JSVAL_VOID;
+                    value = JS::UndefinedValue();
 
                 goto out;
             }
@@ -2719,14 +2709,14 @@ gjs_value_from_g_argument (JSContext  *context,
                                               flags);
 
                 if (obj)
-                    value = OBJECT_TO_JSVAL(obj);
+                    value = JS::ObjectValue(*obj);
 
                 goto out;
             } else if (interface_type == GI_INFO_TYPE_UNION) {
                 JSObject *obj;
                 obj = gjs_union_from_c_union(context, (GIUnionInfo *)interface_info, arg->v_pointer);
                 if (obj)
-                        value = OBJECT_TO_JSVAL(obj);
+                        value = JS::ObjectValue(*obj);
 
                 goto out;
             }
@@ -2735,7 +2725,7 @@ gjs_value_from_g_argument (JSContext  *context,
                 JSObject *obj;
                 obj = gjs_object_from_g_object(context, G_OBJECT(arg->v_pointer));
                 if (obj)
-                    value = OBJECT_TO_JSVAL(obj);
+                    value = JS::ObjectValue(*obj);
             } else if (g_type_is_a(gtype, G_TYPE_BOXED) ||
                        g_type_is_a(gtype, G_TYPE_ENUM) ||
                        g_type_is_a(gtype, G_TYPE_FLAGS)) {
@@ -2749,14 +2739,14 @@ gjs_value_from_g_argument (JSContext  *context,
                 JSObject *obj;
                 obj = gjs_param_from_g_param(context, G_PARAM_SPEC(arg->v_pointer));
                 if (obj)
-                    value = OBJECT_TO_JSVAL(obj);
+                    value = JS::ObjectValue(*obj);
             } else if (gtype == G_TYPE_NONE) {
                 gjs_throw(context, "Unexpected unregistered type packing GArgument into JS::Value");
             } else if (G_TYPE_IS_INSTANTIATABLE(gtype) || G_TYPE_IS_INTERFACE(gtype)) {
                 JSObject *obj;
                 obj = gjs_object_from_g_fundamental(context, (GIObjectInfo *)interface_info, arg->v_pointer);
                 if (obj)
-                    value = OBJECT_TO_JSVAL(obj);
+                    value = JS::ObjectValue(*obj);
             } else {
                 gjs_throw(context, "Unhandled GType %s packing GArgument into JS::Value",
                           g_type_name(gtype));
@@ -2765,7 +2755,7 @@ gjs_value_from_g_argument (JSContext  *context,
          out:
             g_base_info_unref( (GIBaseInfo*) interface_info);
 
-            if (JSVAL_IS_VOID(value))
+            if (value.isUndefined())
                 return false;
 
             *value_p = value;
@@ -2805,7 +2795,7 @@ gjs_value_from_g_argument (JSContext  *context,
                 gjs_throw(context, "Couldn't convert GByteArray to a ByteArray");
                 return false;
             }
-            *value_p = OBJECT_TO_JSVAL(array);
+            *value_p = JS::ObjectValue(*array);
         } else {
             /* this assumes the array type is one of GArray, GPtrArray or
              * GByteArray */
diff --git a/gi/boxed.cpp b/gi/boxed.cpp
index c95bbc9..64be0db 100644
--- a/gi/boxed.cpp
+++ b/gi/boxed.cpp
@@ -201,10 +201,10 @@ boxed_get_copy_source(JSContext *context,
 {
     Boxed *source_priv;
 
-    if (!JSVAL_IS_OBJECT(value))
+    if (!value.isObject())
         return false;
 
-    if (!priv_from_js_with_typecheck(context, JSVAL_TO_OBJECT(value), &source_priv))
+    if (!priv_from_js_with_typecheck(context, &value.toObject(), &source_priv))
         return false;
 
     if (!g_base_info_equal((GIBaseInfo*) priv->info, (GIBaseInfo*) source_priv->info))
@@ -266,12 +266,12 @@ boxed_init_from_props(JSContext   *context,
     jsid prop_id;
     bool success = false;
 
-    if (!JSVAL_IS_OBJECT(props_value)) {
+    if (!props_value.isObject()) {
         gjs_throw(context, "argument should be a hash with fields to set");
         return false;
     }
 
-    props = JSVAL_TO_OBJECT(props_value);
+    props = &props_value.toObject();
 
     iter = JS_NewPropertyIterator(context, props);
     if (iter == NULL) {
@@ -338,7 +338,7 @@ boxed_invoke_constructor(JSContext   *context,
     if (!gjs_object_require_property(context, obj, NULL, constructor_const, &js_constructor))
         return false;
 
-    if (!gjs_object_require_property(context, JSVAL_TO_OBJECT(js_constructor), NULL,
+    if (!gjs_object_require_property(context, &js_constructor.toObject(), NULL,
                                      constructor_name, &js_constructor_func))
         return false;
 
@@ -485,13 +485,13 @@ GJS_NATIVE_CONSTRUCTOR_DECLARE(boxed)
        prepare the location for that
     */
 
-    actual_rval = JSVAL_VOID;
+    actual_rval = JS::UndefinedValue();
     JS_AddValueRoot(context, &actual_rval);
 
     retval = boxed_new(context, object, priv, argc, argv.array(), &actual_rval);
 
     if (retval) {
-        if (!JSVAL_IS_VOID (actual_rval))
+        if (!actual_rval.isUndefined())
             argv.rval().set(actual_rval);
         else
             GJS_NATIVE_CONSTRUCTOR_FINISH(boxed);
@@ -623,10 +623,9 @@ get_nested_interface_object (JSContext   *context,
     /* We never actually read the reserved slot, but we put the parent object
      * into it to hold onto the parent object.
      */
-    JS_SetReservedSlot(obj, 0,
-                       OBJECT_TO_JSVAL (parent_obj));
+    JS_SetReservedSlot(obj, 0, JS::ObjectValue(*parent_obj));
 
-    *value = OBJECT_TO_JSVAL(obj);
+    *value = JS::ObjectValue(*obj);
     return true;
 }
 
@@ -875,8 +874,7 @@ define_boxed_class_fields (JSContext *context,
         const char *field_name = g_base_info_get_name ((GIBaseInfo *)field);
         bool result;
 
-        result = JS_DefineProperty(context, proto, field_name,
-                                             JSVAL_NULL,
+        result = JS_DefineProperty(context, proto, field_name, JS::NullValue(),
                                              boxed_field_getter, boxed_field_setter,
                                              JSPROP_PERMANENT | JSPROP_SHARED);
 
@@ -895,7 +893,7 @@ to_string_func(JSContext *context,
                JS::Value *vp)
 {
     JS::CallReceiver rec = JS::CallReceiverFromVp(vp);
-    JSObject *obj = JSVAL_TO_OBJECT(rec.thisv());
+    JSObject *obj = rec.thisv().toObjectOrNull();
 
     Boxed *priv;
     bool ret = false;
@@ -1186,7 +1184,7 @@ gjs_define_boxed_class(JSContext    *context,
     define_boxed_class_fields (context, priv, prototype);
     gjs_define_static_methods (context, constructor, priv->gtype, priv->info);
 
-    value = OBJECT_TO_JSVAL(gjs_gtype_create_gtype_wrapper(context, priv->gtype));
+    value = JS::ObjectOrNullValue(gjs_gtype_create_gtype_wrapper(context, priv->gtype));
     JS_DefineProperty(context, constructor, "$gtype", value,
                       NULL, NULL, JSPROP_PERMANENT);
 }
diff --git a/gi/closure.cpp b/gi/closure.cpp
index 7590b09..696090b 100644
--- a/gi/closure.cpp
+++ b/gi/closure.cpp
@@ -276,7 +276,7 @@ gjs_closure_invoke(GClosure  *closure,
 
     if (!gjs_call_function_value(context,
                                  NULL, /* "this" object; NULL is some kind of default presumably */
-                                 OBJECT_TO_JSVAL(c->obj),
+                                 JS::ObjectValue(*c->obj),
                                  argc,
                                  argv,
                                  retval)) {
diff --git a/gi/enumeration.cpp b/gi/enumeration.cpp
index 962e491..257e9c6 100644
--- a/gi/enumeration.cpp
+++ b/gi/enumeration.cpp
@@ -55,10 +55,10 @@ gjs_lookup_enumeration(JSContext    *context,
     if (!JS_GetProperty(context, in_object, enum_name, &value))
         return NULL;
 
-    if (G_UNLIKELY (!JSVAL_IS_OBJECT(value)))
+    if (G_UNLIKELY (!value.isObject()))
         return NULL;
 
-    return JSVAL_TO_OBJECT(value);
+    return &value.toObject();
 }
 
 static bool
@@ -133,7 +133,7 @@ gjs_define_enum_values(JSContext    *context,
     }
 
     gtype = g_registered_type_info_get_g_type((GIRegisteredTypeInfo*)info);
-    value = OBJECT_TO_JSVAL(gjs_gtype_create_gtype_wrapper(context, gtype));
+    value = JS::ObjectOrNullValue(gjs_gtype_create_gtype_wrapper(context, gtype));
     JS_DefineProperty(context, in_object, "$gtype", value,
                       NULL, NULL, JSPROP_PERMANENT);
 
@@ -215,7 +215,7 @@ gjs_define_enumeration(JSContext    *context,
               enum_name, enum_obj);
 
     if (!JS_DefineProperty(context, in_object,
-                           enum_name, OBJECT_TO_JSVAL(enum_obj),
+                           enum_name, JS::ObjectValue(*enum_obj),
                            NULL, NULL,
                            GJS_MODULE_PROP_FLAGS)) {
         gjs_throw(context, "Unable to define enumeration property (no memory most likely)");
diff --git a/gi/function.cpp b/gi/function.cpp
index de22862..0bff7ce 100644
--- a/gi/function.cpp
+++ b/gi/function.cpp
@@ -251,7 +251,7 @@ gjs_callback_closure(ffi_cif *cif,
                     goto out;
 
                 if (!gjs_value_from_explicit_array(context, &jsargs[n_jsargs++],
-                                                   &type_info, (GArgument*) args[i], JSVAL_TO_INT(length)))
+                                                   &type_info, (GArgument*) args[i], length.toInt32()))
                     goto out;
                 break;
             }
@@ -269,7 +269,7 @@ gjs_callback_closure(ffi_cif *cif,
 
     if (trampoline->is_vfunc) {
         g_assert(n_args > 0);
-        this_object = JSVAL_TO_OBJECT(jsargs[0]);
+        this_object = jsargs[0].toObjectOrNull();
         jsargs++;
         n_jsargs--;
     } else {
@@ -340,7 +340,7 @@ gjs_callback_closure(ffi_cif *cif,
         if (!ret_type_is_void) {
             GIArgument argument;
 
-            if (!JS_GetElement(context, JSVAL_TO_OBJECT(rval), elem_idx, &elem))
+            if (!JS_GetElement(context, rval.toObjectOrNull(), elem_idx, &elem))
                 goto out;
 
             if (!gjs_value_to_g_argument(context,
@@ -368,7 +368,7 @@ gjs_callback_closure(ffi_cif *cif,
                 continue;
 
             g_arg_info_load_type(&arg_info, &type_info);
-            if (!JS_GetElement(context, JSVAL_TO_OBJECT(rval), elem_idx, &elem))
+            if (!JS_GetElement(context, rval.toObjectOrNull(), elem_idx, &elem))
                 goto out;
 
             if (!gjs_value_to_g_argument(context,
@@ -428,7 +428,7 @@ gjs_callback_trampoline_new(JSContext      *context,
     GjsCallbackTrampoline *trampoline;
     int n_args, i;
 
-    if (JSVAL_IS_NULL(function)) {
+    if (function.isNull()) {
         return NULL;
     }
 
@@ -848,7 +848,7 @@ gjs_invoke_c_function(JSContext      *context,
                 ffi_closure *closure;
                 JS::Value value = js_argv[js_arg_pos];
 
-                if (JSVAL_IS_NULL(value) && g_arg_info_may_be_null(&arg_info)) {
+                if (value.isNull() && g_arg_info_may_be_null(&arg_info)) {
                     closure = NULL;
                     trampoline = NULL;
                 } else {
@@ -912,7 +912,7 @@ gjs_invoke_c_function(JSContext      *context,
                 g_callable_info_load_arg(function->info, array_length_pos, &array_length_arg);
 
                 array_length_pos += is_method ? 1 : 0;
-                if (!gjs_value_to_arg(context, INT_TO_JSVAL(length), &array_length_arg,
+                if (!gjs_value_to_arg(context, JS::Int32Value(length), &array_length_arg,
                                       in_arg_cvalues + array_length_pos)) {
                     failed = true;
                     break;
@@ -1005,12 +1005,12 @@ gjs_invoke_c_function(JSContext      *context,
     }
 
     if (js_rval)
-        *js_rval = JSVAL_VOID;
+        *js_rval = JS::UndefinedValue();
 
     /* Only process return values if the function didn't throw */
     if (function->js_out_argc > 0 && !did_throw_gerror) {
         return_values = g_newa(JS::Value, function->js_out_argc);
-        gjs_set_values(context, return_values, function->js_out_argc, JSVAL_VOID);
+        gjs_set_values(context, return_values, function->js_out_argc, JS::UndefinedValue());
         gjs_root_value_locations(context, return_values, function->js_out_argc);
 
         if (return_tag != GI_TYPE_TAG_VOID) {
@@ -1040,14 +1040,14 @@ gjs_invoke_c_function(JSContext      *context,
                                                                 &return_values[next_rval],
                                                                 &return_info,
                                                                 &return_gargument,
-                                                                JSVAL_TO_INT(length));
+                                                                length.toInt32());
                 }
                 if (!arg_failed &&
                     !r_value &&
                     !gjs_g_argument_release_out_array(context,
                                                       transfer,
                                                       &return_info,
-                                                      JSVAL_TO_INT(length),
+                                                      length.toInt32(),
                                                       &return_gargument))
                     failed = true;
             } else {
@@ -1184,7 +1184,7 @@ release:
                                                                     &return_values[next_rval],
                                                                     &arg_type_info,
                                                                     arg,
-                                                                    JSVAL_TO_INT(array_length));
+                                                                    array_length.toInt32());
                     }
                 } else {
                     arg_failed = !gjs_value_from_g_argument(context,
@@ -1205,7 +1205,7 @@ release:
                     gjs_g_argument_release_out_array(context,
                                                      transfer,
                                                      &arg_type_info,
-                                                     JSVAL_TO_INT(array_length),
+                                                     array_length.toInt32(),
                                                      arg);
                 } else {
                     gjs_g_argument_release(context,
@@ -1272,7 +1272,7 @@ release:
                 if (array == NULL) {
                     failed = true;
                 } else {
-                    *js_rval = OBJECT_TO_JSVAL(array);
+                    *js_rval = JS::ObjectValue(*array);
                 }
             }
         }
@@ -1300,7 +1300,7 @@ function_call(JSContext *context,
               JS::Value *vp)
 {
     JS::CallArgs js_argv = JS::CallArgsFromVp (js_argc, vp);
-    JSObject *object = JSVAL_TO_OBJECT(js_argv.thisv());
+    JSObject *object = js_argv.thisv().toObjectOrNull();
     JSObject *callee = &js_argv.callee();
 
     bool success;
@@ -1311,7 +1311,7 @@ function_call(JSContext *context,
     gjs_debug_marshal(GJS_DEBUG_GFUNCTION,
                       "Call callee %p priv %p this obj %p %s", callee, priv,
                       object,
-                      JS_GetTypeName(context, JS_TypeOfValue(context, OBJECT_TO_JSVAL(object))));
+                      JS_GetTypeName(context, JS_TypeOfValue(context, JS::ObjectOrNullValue(object))));
 
     if (priv == NULL)
         return true; /* we are the prototype, or have the wrong class */
@@ -1389,8 +1389,7 @@ get_num_arguments (JSContext *context,
             continue;
     }
 
-    retval = INT_TO_JSVAL(n_jsargs);
-    rec.rval().set(retval);
+    rec.rval().setInt32(n_jsargs);
     return true;
 }
 
@@ -1410,12 +1409,12 @@ function_to_string (JSContext *context,
     gchar *arg_names;
 
     JS::CallReceiver rec = JS::CallReceiverFromVp(vp);
-    self = JSVAL_TO_OBJECT(rec.thisv());
 
-    if (!self) {
+    if (rec.thisv().isNull()) {
         gjs_throw(context, "this cannot be null");
         return false;
     }
+    self = &rec.thisv().toObject();
 
     priv = priv_from_js (context, self);
     if (priv == NULL) {
@@ -1679,7 +1678,7 @@ function_new(JSContext      *context,
 
         JS_GetProperty(context, global, "Function", &native_function);
         /* We take advantage from that fact that Function.__proto__ is Function.prototype */
-        JS_GetPrototype(context, JSVAL_TO_OBJECT(native_function), &parent_proto);
+        JS_GetPrototype(context, &native_function.toObject(), &parent_proto);
 
         prototype = JS_InitClass(context, global,
                                  /* parent prototype JSObject* for
@@ -1765,7 +1764,7 @@ gjs_define_function(JSContext      *context,
     }
 
     if (!JS_DefineProperty(context, in_object, name,
-                           OBJECT_TO_JSVAL(function),
+                           JS::ObjectValue(*function),
                            NULL, NULL,
                            GJS_MODULE_PROP_FLAGS)) {
         gjs_debug(GJS_DEBUG_GFUNCTION, "Failed to define function");
diff --git a/gi/fundamental.cpp b/gi/fundamental.cpp
index e329a49..8e4b1a2 100644
--- a/gi/fundamental.cpp
+++ b/gi/fundamental.cpp
@@ -402,7 +402,7 @@ fundamental_invoke_constructor(FundamentalInstance *priv,
         goto end;
     }
 
-    if (!gjs_object_require_property(context, JSVAL_TO_OBJECT(js_constructor), NULL,
+    if (!gjs_object_require_property(context, js_constructor.toObjectOrNull(), NULL,
                                      priv->prototype->constructor_name, &js_constructor_func)) {
         gjs_throw (context,
                    "Couldn't find a constructor for type %s.%s",
@@ -411,7 +411,7 @@ fundamental_invoke_constructor(FundamentalInstance *priv,
         goto end;
     }
 
-    ret = gjs_invoke_constructor_from_c(context, JSVAL_TO_OBJECT(js_constructor_func), obj, argc, argv, 
rvalue);
+    ret = gjs_invoke_constructor_from_c(context, js_constructor_func.toObjectOrNull(), obj, argc, argv, 
rvalue);
 
  end:
     return ret;
@@ -501,7 +501,7 @@ to_string_func(JSContext *context,
                JS::Value *vp)
 {
     JS::CallReceiver rec = JS::CallReceiverFromVp(vp);
-    JSObject *obj = JSVAL_TO_OBJECT(rec.thisv());
+    JSObject *obj = rec.thisv().toObjectOrNull();
 
     FundamentalInstance *priv;
     bool ret = false;
@@ -600,16 +600,16 @@ gjs_lookup_fundamental_prototype(JSContext    *context,
     if (!JS_GetProperty(context, in_object, constructor_name, &value))
         return NULL;
 
-    if (JSVAL_IS_VOID(value)) {
+    if (value.isUndefined()) {
         /* In case we're looking for a private type, and we don't find it,
            we need to define it first.
         */
         gjs_define_fundamental_class(context, in_object, info, &constructor, NULL);
     } else {
-        if (G_UNLIKELY (!JSVAL_IS_OBJECT(value) || JSVAL_IS_NULL(value)))
+        if (G_UNLIKELY (!value.isObject()))
             return NULL;
 
-        constructor = JSVAL_TO_OBJECT(value);
+        constructor = &value.toObject();
     }
 
     g_assert(constructor != NULL);
@@ -618,10 +618,10 @@ gjs_lookup_fundamental_prototype(JSContext    *context,
                                        GJS_STRING_PROTOTYPE, &value))
         return NULL;
 
-    if (G_UNLIKELY (!JSVAL_IS_OBJECT(value)))
+    if (G_UNLIKELY (!value.isObjectOrNull()))
         return NULL;
 
-    return JSVAL_TO_OBJECT(value);
+    return value.toObjectOrNull();
 }
 
 static JSObject*
@@ -735,7 +735,7 @@ gjs_define_fundamental_class(JSContext     *context,
 
     gjs_object_define_static_methods(context, constructor, gtype, info);
 
-    value = OBJECT_TO_JSVAL(gjs_gtype_create_gtype_wrapper(context, gtype));
+    value = JS::ObjectOrNullValue(gjs_gtype_create_gtype_wrapper(context, gtype));
     JS_DefineProperty(context, constructor, "$gtype", value,
                       NULL, NULL, JSPROP_PERMANENT);
 
diff --git a/gi/gerror.cpp b/gi/gerror.cpp
index 530d7bf..a6c6ec9 100644
--- a/gi/gerror.cpp
+++ b/gi/gerror.cpp
@@ -66,7 +66,7 @@ GJS_NATIVE_CONSTRUCTOR_DECLARE(error)
     gchar *message;
 
     /* Check early to avoid allocating memory for nothing */
-    if (argc != 1 || !JSVAL_IS_OBJECT(argv[0])) {
+    if (argc != 1 || !argv[0].isObject()) {
         gjs_throw(context, "Invalid parameters passed to GError constructor, expected one object");
         return false;
     }
@@ -104,16 +104,16 @@ GJS_NATIVE_CONSTRUCTOR_DECLARE(error)
 
     message_name = gjs_context_get_const_string(context, GJS_STRING_MESSAGE);
     code_name = gjs_context_get_const_string(context, GJS_STRING_CODE);
-    if (!gjs_object_require_property(context, JSVAL_TO_OBJECT(argv[0]),
+    if (!gjs_object_require_property(context, &argv[0].toObject(),
                                      "GError constructor", message_name, &v_message))
         return false;
-    if (!gjs_object_require_property(context, JSVAL_TO_OBJECT(argv[0]),
+    if (!gjs_object_require_property(context, &argv[0].toObject(),
                                      "GError constructor", code_name, &v_code))
         return false;
     if (!gjs_string_to_utf8 (context, v_message, &message))
         return false;
 
-    priv->gerror = g_error_new_literal(priv->domain, JSVAL_TO_INT(v_code),
+    priv->gerror = g_error_new_literal(priv->domain, v_code.toInt32(),
                                        message);
 
     g_free (message);
@@ -160,7 +160,7 @@ error_get_domain(JSContext *context, JS::HandleObject obj,
     if (priv == NULL)
         return false;
 
-    vp.set(INT_TO_JSVAL(priv->domain));
+    vp.setInt32(priv->domain);
     return true;
 }
 
@@ -201,7 +201,7 @@ error_get_code(JSContext *context, JS::HandleObject obj,
         return false;
     }
 
-    vp.set(INT_TO_JSVAL(priv->gerror->code));
+    vp.setInt32(priv->gerror->code);
     return true;
 }
 
@@ -219,19 +219,19 @@ error_to_string(JSContext *context,
 
     JS::CallReceiver rec = JS::CallReceiverFromVp(vp);
     v_self = rec.thisv();
-    if (!JSVAL_IS_OBJECT(v_self)) {
+    if (!v_self.isObject()) {
         /* Lie a bit here... */
         gjs_throw(context, "GLib.Error.prototype.toString() called on a non object");
         return false;
     }
 
-    self = JSVAL_TO_OBJECT(v_self);
+    self = &v_self.toObject();
     priv = priv_from_js(context, self);
 
     if (priv == NULL)
         return false;
 
-    v_out = JSVAL_VOID;
+    v_out = JS::UndefinedValue();
     retval = false;
 
     /* We follow the same pattern as standard JS errors, at the expense of
@@ -269,39 +269,33 @@ error_constructor_value_of(JSContext *context,
 {
     JS::Value v_self, v_prototype;
     Error *priv;
-    JS::Value v_out;
     jsid prototype_name;
 
     JS::CallReceiver rec = JS::CallReceiverFromVp(vp);
     v_self = rec.thisv();
-    if (!JSVAL_IS_OBJECT(v_self)) {
+    if (!v_self.isObject()) {
         /* Lie a bit here... */
         gjs_throw(context, "GLib.Error.valueOf() called on a non object");
         return false;
     }
 
     prototype_name = gjs_context_get_const_string(context, GJS_STRING_PROTOTYPE);
-    if (!gjs_object_require_property(context,
-                                     JSVAL_TO_OBJECT(v_self),
-                                     "constructor",
-                                     prototype_name,
-                                     &v_prototype))
+    if (!gjs_object_require_property(context, &v_self.toObject(), "constructor",
+                                     prototype_name, &v_prototype))
         return false;
 
-    if (!JSVAL_IS_OBJECT(v_prototype)) {
+    if (!v_prototype.isObject()) {
         gjs_throw(context, "GLib.Error.valueOf() called on something that is not"
                   " a constructor");
         return false;
     }
 
-    priv = priv_from_js(context, JSVAL_TO_OBJECT(v_prototype));
+    priv = priv_from_js(context, &v_prototype.toObject());
 
     if (priv == NULL)
         return false;
 
-    v_out = INT_TO_JSVAL(priv->domain);
-
-    rec.rval().set(v_out);
+    rec.rval().setInt32(priv->domain);
     return true;
 }
 
diff --git a/gi/gtype.cpp b/gi/gtype.cpp
index 24843e3..789e781 100644
--- a/gi/gtype.cpp
+++ b/gi/gtype.cpp
@@ -67,7 +67,7 @@ to_string_func(JSContext *context,
                JS::Value *vp)
 {
     JS::CallReceiver rec = JS::CallReceiverFromVp(vp);
-    JSObject *obj = JSVAL_TO_OBJECT(rec.thisv());
+    JSObject *obj = rec.thisv().toObjectOrNull();
 
     GType gtype;
     gchar *strval;
@@ -102,7 +102,7 @@ get_name_func (JSContext *context,
     gtype = GPOINTER_TO_SIZE(priv_from_js(context, obj));
 
     if (gtype == 0) {
-        rec.rval().set(JSVAL_NULL);
+        rec.rval().setNull();
         return true;
     } else {
         ret = gjs_string_from_utf8(context, g_type_name(gtype), -1, &retval);
@@ -162,7 +162,7 @@ _gjs_gtype_get_actual_gtype (JSContext *context,
                              int        recurse)
 {
     GType gtype = G_TYPE_INVALID;
-    JS::Value gtype_val = JSVAL_VOID;
+    JS::Value gtype_val = JS::UndefinedValue();
 
     JS_BeginRequest(context);
     if (JS_InstanceOf(context, object, &gjs_gtype_class, NULL)) {
@@ -173,7 +173,7 @@ _gjs_gtype_get_actual_gtype (JSContext *context,
     /* OK, we don't have a GType wrapper object -- grab the "$gtype"
      * property on that and hope it's a GType wrapper object */
     if (!JS_GetProperty(context, object, "$gtype", &gtype_val) ||
-        !JSVAL_IS_OBJECT(gtype_val)) {
+        !gtype_val.isObject()) {
 
         /* OK, so we're not a class. But maybe we're an instance. Check
            for "constructor" and recurse on that. */
@@ -181,8 +181,8 @@ _gjs_gtype_get_actual_gtype (JSContext *context,
             goto out;
     }
 
-    if (recurse > 0 && JSVAL_IS_OBJECT(gtype_val))
-        gtype = _gjs_gtype_get_actual_gtype(context, JSVAL_TO_OBJECT(gtype_val), recurse - 1);
+    if (recurse > 0 && gtype_val.isObject())
+        gtype = _gjs_gtype_get_actual_gtype(context, &gtype_val.toObject(), recurse - 1);
 
  out:
     JS_EndRequest(context);
diff --git a/gi/interface.cpp b/gi/interface.cpp
index f81c66f..6b4d264 100644
--- a/gi/interface.cpp
+++ b/gi/interface.cpp
@@ -230,7 +230,7 @@ gjs_define_interface_class(JSContext       *context,
     if (priv->info)
         gjs_define_static_methods(context, constructor, priv->gtype, priv->info);
 
-    value = OBJECT_TO_JSVAL(gjs_gtype_create_gtype_wrapper(context, priv->gtype));
+    value = JS::ObjectOrNullValue(gjs_gtype_create_gtype_wrapper(context, priv->gtype));
     JS_DefineProperty(context, constructor, "$gtype", value,
                       NULL, NULL, JSPROP_PERMANENT);
 
@@ -265,6 +265,6 @@ gjs_lookup_interface_constructor(JSContext *context,
 
     g_base_info_unref(interface_info);
 
-    *value_p = OBJECT_TO_JSVAL(constructor);
+    *value_p = JS::ObjectValue(*constructor);
     return true;
 }
diff --git a/gi/keep-alive.cpp b/gi/keep-alive.cpp
index f0af71d..690de40 100644
--- a/gi/keep-alive.cpp
+++ b/gi/keep-alive.cpp
@@ -122,8 +122,8 @@ trace_foreach(void *key,
     if (child->child != NULL) {
         JS::Value val;
         JS_SET_TRACING_DETAILS(tracer, NULL, "keep-alive", 0);
-        val = OBJECT_TO_JSVAL(child->child);
-        g_assert (JSVAL_TO_TRACEABLE (val));
+        val = JS::ObjectValue(*(child->child));
+        g_assert (val.toGCThing());  // FIXME WAT WAT WAT JSVAL_TO_TRACEABLE
         JS_CallValueTracer(tracer, &val, "keep-alive::val");
     }
 }
@@ -325,7 +325,7 @@ gjs_keep_alive_create(JSContext *context)
     if (!keep_alive)
         g_error("could not create keep_alive on global object, no memory?");
 
-    gjs_set_global_slot(context, GJS_GLOBAL_SLOT_KEEP_ALIVE, OBJECT_TO_JSVAL(keep_alive));
+    gjs_set_global_slot(context, GJS_GLOBAL_SLOT_KEEP_ALIVE, JS::ObjectValue(*keep_alive));
 
     JS_EndRequest(context);
     return keep_alive;
@@ -338,9 +338,9 @@ gjs_keep_alive_get_global_if_exists (JSContext *context)
 
     keep_alive = gjs_get_global_slot(context, GJS_GLOBAL_SLOT_KEEP_ALIVE);
 
-    if (G_LIKELY (JSVAL_IS_OBJECT(keep_alive)))
-        return JSVAL_TO_OBJECT(keep_alive);
-    
+    if (G_LIKELY (keep_alive.isObject()))
+        return &keep_alive.toObject();
+
     return NULL;
 }
 
diff --git a/gi/object.cpp b/gi/object.cpp
index 4022693..ea1662d 100644
--- a/gi/object.cpp
+++ b/gi/object.cpp
@@ -686,15 +686,15 @@ object_instance_props_to_g_parameters(JSContext   *context,
     gparams = g_array_new(/* nul term */ false, /* clear */ true,
                           sizeof(GParameter));
 
-    if (argc == 0 || JSVAL_IS_VOID(argv[0]))
+    if (argc == 0 || argv[0].isUndefined())
         goto out;
 
-    if (!JSVAL_IS_OBJECT(argv[0])) {
+    if (!argv[0].isObject()) {
         gjs_throw(context, "argument should be a hash with props to set");
         goto free_array_and_fail;
     }
 
-    props = JSVAL_TO_OBJECT(argv[0]);
+    props = &argv[0].toObject();
 
     iter = JS_NewPropertyIterator(context, props);
     if (iter == NULL) {
@@ -1350,11 +1350,11 @@ GJS_NATIVE_CONSTRUCTOR_DECLARE(object_instance)
     if (!gjs_object_require_property(context, object, "GObject instance", object_init_name, &initer))
         return false;
 
-    rval = JSVAL_VOID;
+    rval.setUndefined();
     ret = gjs_call_function_value(context, object, initer, argc, argv.array(), &rval);
 
-    if (JSVAL_IS_VOID(rval))
-        rval = OBJECT_TO_JSVAL(object);
+    if (rval.isUndefined())
+        rval.setObject(*object);
 
     argv.rval().set(rval);
     return ret;
@@ -1491,16 +1491,16 @@ gjs_lookup_object_constructor_from_info(JSContext    *context,
     if (!JS_GetProperty(context, in_object, constructor_name, &value))
         return NULL;
 
-    if (JSVAL_IS_VOID(value)) {
+    if (value.isUndefined()) {
         /* In case we're looking for a private type, and we don't find it,
            we need to define it first.
         */
         gjs_define_object_class(context, in_object, NULL, gtype, &constructor);
     } else {
-        if (G_UNLIKELY (!JSVAL_IS_OBJECT(value) || JSVAL_IS_NULL(value)))
+        if (G_UNLIKELY (!value.isObject()))
             return NULL;
 
-        constructor = JSVAL_TO_OBJECT(value);
+        constructor = &value.toObject();
     }
 
     g_assert(constructor != NULL);
@@ -1525,10 +1525,10 @@ gjs_lookup_object_prototype_from_info(JSContext    *context,
                                        GJS_STRING_PROTOTYPE, &value))
         return NULL;
 
-    if (G_UNLIKELY (!JSVAL_IS_OBJECT(value)))
+    if (G_UNLIKELY (!value.isObjectOrNull()))
         return NULL;
 
-    return JSVAL_TO_OBJECT(value);
+    return value.toObjectOrNull();
 }
 
 static JSObject *
@@ -1564,7 +1564,7 @@ real_connect_func(JSContext *context,
                   bool       after)
 {
     JS::CallArgs argv = JS::CallArgsFromVp (argc, vp);
-    JSObject *obj = JSVAL_TO_OBJECT(argv.thisv());
+    JSObject *obj = argv.thisv().toObjectOrNull();
 
     ObjectInstance *priv;
     GClosure *closure;
@@ -1599,9 +1599,7 @@ real_connect_func(JSContext *context,
      * JSClass::call, for example.
      */
 
-    if (argc != 2 ||
-        !JSVAL_IS_STRING(argv[0]) ||
-        !JSVAL_IS_OBJECT(argv[1])) {
+    if (argc != 2 || !argv[0].isString() || !argv[1].isObject()) {
         gjs_throw(context, "connect() takes two args, the signal name and the callback");
         return false;
     }
@@ -1621,7 +1619,7 @@ real_connect_func(JSContext *context,
         goto out;
     }
 
-    closure = gjs_closure_new_for_signal(context, JSVAL_TO_OBJECT(argv[1]), "signal callback", signal_id);
+    closure = gjs_closure_new_for_signal(context, &argv[1].toObject(), "signal callback", signal_id);
     if (closure == NULL)
         goto out;
 
@@ -1674,7 +1672,7 @@ emit_func(JSContext *context,
           JS::Value *vp)
 {
     JS::CallArgs argv = JS::CallArgsFromVp (argc, vp);
-    JSObject *obj = JSVAL_TO_OBJECT(argv.thisv());
+    JSObject *obj = argv.thisv().toObjectOrNull();
 
     ObjectInstance *priv;
     guint signal_id;
@@ -1707,8 +1705,7 @@ emit_func(JSContext *context,
         return false;
     }
 
-    if (argc < 1 ||
-        !JSVAL_IS_STRING(argv[0])) {
+    if (argc < 1 || !argv[0].isString()) {
         gjs_throw(context, "emit() first arg is the signal name");
         return false;
     }
@@ -1776,7 +1773,7 @@ emit_func(JSContext *context,
 
         g_value_unset(&rvalue);
     } else {
-        retval = JSVAL_VOID;
+        retval.setUndefined();
     }
 
     for (i = 0; i < (signal_query.n_params + 1); ++i) {
@@ -1798,7 +1795,7 @@ to_string_func(JSContext *context,
                JS::Value *vp)
 {
     JS::CallReceiver rec = JS::CallReceiverFromVp(vp);
-    JSObject *obj = JSVAL_TO_OBJECT(rec.thisv());
+    JSObject *obj = rec.thisv().toObjectOrNull();
 
     ObjectInstance *priv;
     bool ret = false;
@@ -1850,7 +1847,7 @@ init_func (JSContext *context,
            JS::Value *vp)
 {
     JS::CallArgs argv = JS::CallArgsFromVp (argc, vp);
-    JSObject *obj = JSVAL_TO_OBJECT(argv.thisv());
+    JSObject *obj = argv.thisv().toObjectOrNull();
 
     bool ret;
 
@@ -1860,7 +1857,7 @@ init_func (JSContext *context,
     ret = object_instance_init(context, &obj, argc, argv.array());
 
     if (ret)
-        argv.rval().set(OBJECT_TO_JSVAL(obj));
+        argv.rval().set(JS::ObjectValue(*obj));
 
     return ret;
 }
@@ -2036,7 +2033,7 @@ gjs_define_object_class(JSContext      *context,
     if (info)
         gjs_object_define_static_methods(context, constructor, gtype, info);
 
-    value = OBJECT_TO_JSVAL(gjs_gtype_create_gtype_wrapper(context, gtype));
+    value = JS::ObjectValue(*gjs_gtype_create_gtype_wrapper(context, gtype));
     JS_DefineProperty(context, constructor, "$gtype", value,
                       NULL, NULL, JSPROP_PERMANENT);
 
@@ -2311,7 +2308,7 @@ gjs_hook_up_vfunc(JSContext *cx,
      * This is awful, so abort now. */
     g_assert(info != NULL);
 
-    argv.rval().set(JSVAL_VOID);
+    argv.rval().set(JS::UndefinedValue());
 
     vfunc = find_vfunc_on_parents(info, name, NULL);
 
@@ -2365,7 +2362,8 @@ gjs_hook_up_vfunc(JSContext *cx,
         offset = g_field_info_get_offset(field_info);
         method_ptr = G_STRUCT_MEMBER_P(implementor_vtable, offset);
 
-        trampoline = gjs_callback_trampoline_new(cx, OBJECT_TO_JSVAL(function), callback_info,
+        trampoline = gjs_callback_trampoline_new(cx, JS::ObjectValue(*function),
+                                                 callback_info,
                                                  GI_SCOPE_TYPE_NOTIFIED, true);
 
         *((ffi_closure **)method_ptr) = trampoline->closure;
@@ -2483,7 +2481,7 @@ gjs_object_constructor (GType                  type,
                                     construct_properties[i].value,
                                     construct_properties[i].pspec);
 
-            argv = OBJECT_TO_JSVAL(args);
+            argv = JS::ObjectValue(*args);
             object = JS_New(context, constructor, 1, &argv);
         } else {
             object = JS_New(context, constructor, 0, NULL);
@@ -2663,7 +2661,7 @@ gjs_object_custom_init(GTypeInstance *instance,
         return;
     }
 
-    if (!JSVAL_IS_OBJECT(v) || JSVAL_IS_NULL(v))
+    if (!v.isObject())
         return;
 
     if (!JS_CallFunctionValue(context, object, v,
@@ -2962,7 +2960,7 @@ gjs_register_type(JSContext *cx,
     module = gjs_lookup_private_namespace(cx);
     gjs_define_object_class(cx, module, NULL, instance_type, &constructor);
 
-    argv.rval().set(OBJECT_TO_JSVAL(constructor));
+    argv.rval().set(JS::ObjectValue(*constructor));
 
     retval = true;
 
@@ -2997,12 +2995,12 @@ gjs_signal_new(JSContext *cx,
         goto out;
     }
 
-    obj = JSVAL_TO_OBJECT(argv[0]);
+    obj = &argv[0].toObject();
     if (!gjs_typecheck_gtype(cx, obj, true))
         return false;
 
     /* we only support standard accumulators for now */
-    switch (JSVAL_TO_INT(argv[3])) {
+    switch (argv[3].toInt32()) {
     case 1:
         accumulator = g_signal_accumulator_first_wins;
         break;
@@ -3014,7 +3012,7 @@ gjs_signal_new(JSContext *cx,
         accumulator = NULL;
     }
 
-    return_type = gjs_gtype_get_actual_gtype(cx, JSVAL_TO_OBJECT(argv[4]));
+    return_type = gjs_gtype_get_actual_gtype(cx, &argv[4].toObject());
 
     if (accumulator == g_signal_accumulator_true_handled && return_type != G_TYPE_BOOLEAN) {
         gjs_throw (cx, "GObject.SignalAccumulator.TRUE_HANDLED can only be used with boolean signals");
@@ -3022,28 +3020,28 @@ gjs_signal_new(JSContext *cx,
         goto out;
     }
 
-    if (!JS_GetArrayLength(cx, JSVAL_TO_OBJECT(argv[5]), &n_parameters)) {
+    if (!JS_GetArrayLength(cx, &argv[5].toObject(), &n_parameters)) {
         ret = false;
         goto out;
     }
     params = g_newa(GType, n_parameters);
     for (i = 0; i < n_parameters; i++) {
         JS::Value gtype_val;
-        if (!JS_GetElement(cx, JSVAL_TO_OBJECT(argv[5]), i, &gtype_val) ||
-            !JSVAL_IS_OBJECT(gtype_val)) {
+        if (!JS_GetElement(cx, &argv[5].toObject(), i, &gtype_val) ||
+            !gtype_val.isObject()) {
             gjs_throw(cx, "Invalid signal parameter number %d", i);
             ret = false;
             goto out;
         }
 
-        params[i] = gjs_gtype_get_actual_gtype(cx, JSVAL_TO_OBJECT(gtype_val));
+        params[i] = gjs_gtype_get_actual_gtype(cx, &gtype_val.toObject());
     }
 
     gtype = gjs_gtype_get_actual_gtype(cx, obj);
 
     signal_id = g_signal_newv(signal_name,
                               gtype,
-                              (GSignalFlags) JSVAL_TO_INT(argv[2]), /* signal_flags */
+                              (GSignalFlags) argv[2].toInt32(), /* signal_flags */
                               NULL, /* class closure */
                               accumulator,
                               NULL, /* accu_data */
@@ -3052,7 +3050,7 @@ gjs_signal_new(JSContext *cx,
                               n_parameters,
                               params);
 
-    argv.rval().set(INT_TO_JSVAL(signal_id));
+    argv.rval().set(JS::Int32Value(signal_id));
     ret = true;
 
  out:
@@ -3110,6 +3108,6 @@ gjs_lookup_object_constructor(JSContext *context,
     if (object_info)
         g_base_info_unref((GIBaseInfo*)object_info);
 
-    *value_p = OBJECT_TO_JSVAL(constructor);
+    *value_p = JS::ObjectValue(*constructor);
     return true;
 }
diff --git a/gi/param.cpp b/gi/param.cpp
index e99d035..c6e08f5 100644
--- a/gi/param.cpp
+++ b/gi/param.cpp
@@ -198,20 +198,20 @@ gjs_lookup_param_prototype(JSContext    *context)
     if (!JS_GetProperty(context, in_object, "ParamSpec", &value))
         return NULL;
 
-    if (G_UNLIKELY (!JSVAL_IS_OBJECT(value) || JSVAL_IS_NULL(value)))
+    if (G_UNLIKELY (!value.isObject()))
         return NULL;
 
-    constructor = JSVAL_TO_OBJECT(value);
+    constructor = &value.toObject();
     g_assert(constructor != NULL);
 
     if (!gjs_object_get_property_const(context, constructor,
                                        GJS_STRING_PROTOTYPE, &value))
         return NULL;
 
-    if (G_UNLIKELY (!JSVAL_IS_OBJECT(value)))
+    if (G_UNLIKELY (!value.isObjectOrNull()))
         return NULL;
 
-    return JSVAL_TO_OBJECT(value);
+    return value.toObjectOrNull();
 }
 
 void
@@ -245,7 +245,7 @@ gjs_define_param_class(JSContext    *context,
         g_error("Can't init class %s", constructor_name);
     }
 
-    value = OBJECT_TO_JSVAL(gjs_gtype_create_gtype_wrapper(context, G_TYPE_PARAM));
+    value = JS::ObjectOrNullValue(gjs_gtype_create_gtype_wrapper(context, G_TYPE_PARAM));
     JS_DefineProperty(context, constructor, "$gtype", value,
                       NULL, NULL, JSPROP_PERMANENT);
 
diff --git a/gi/repo.cpp b/gi/repo.cpp
index 02e8053..2a15439 100644
--- a/gi/repo.cpp
+++ b/gi/repo.cpp
@@ -69,16 +69,16 @@ get_version_for_ns (JSContext *context,
 
     versions_name = gjs_context_get_const_string(context, GJS_STRING_GI_VERSIONS);
     if (!gjs_object_require_property(context, repo_obj, "GI repository object", versions_name, 
&versions_val) ||
-        !JSVAL_IS_OBJECT(versions_val)) {
+        !versions_val.isObject()) {
         gjs_throw(context, "No 'versions' property in GI repository object");
         return false;
     }
 
-    versions = JSVAL_TO_OBJECT(versions_val);
+    versions = &versions_val.toObject();
 
     *version = NULL;
     if (JS_GetPropertyById(context, versions, ns_id, &version_val) &&
-        JSVAL_IS_STRING(version_val)) {
+        version_val.isString()) {
         gjs_string_to_utf8(context, version_val, version);
     }
 
@@ -130,7 +130,7 @@ resolve_namespace_object(JSContext  *context,
     /* Define the property early, to avoid reentrancy issues if
        the override module looks for namespaces that import this */
     if (!JS_DefineProperty(context, repo_obj,
-                           ns_name, OBJECT_TO_JSVAL(gi_namespace),
+                           ns_name, JS::ObjectValue(*gi_namespace),
                            NULL, NULL,
                            GJS_MODULE_PROP_FLAGS))
         g_error("no memory to define ns property");
@@ -138,7 +138,7 @@ resolve_namespace_object(JSContext  *context,
     override = lookup_override_function(context, ns_id);
     if (override && !JS_CallFunctionValue (context,
                                            gi_namespace, /* thisp */
-                                           OBJECT_TO_JSVAL(override), /* callee */
+                                           JS::ObjectValue(*override), /* callee */
                                            0, /* argc */
                                            NULL, /* argv */
                                            &result))
@@ -318,7 +318,7 @@ repo_new(JSContext *context)
     versions_name = gjs_context_get_const_string(context, GJS_STRING_GI_VERSIONS);
     JS_DefinePropertyById(context, repo,
                           versions_name,
-                          OBJECT_TO_JSVAL(versions),
+                          JS::ObjectValue(*versions),
                           NULL, NULL,
                           JSPROP_PERMANENT);
 
@@ -326,7 +326,7 @@ repo_new(JSContext *context)
     private_ns_name = gjs_context_get_const_string(context, GJS_STRING_PRIVATE_NS_MARKER);
     JS_DefinePropertyById(context, repo,
                           private_ns_name,
-                          OBJECT_TO_JSVAL(private_ns),
+                          JS::ObjectValue(*private_ns),
                           NULL, NULL, JSPROP_PERMANENT);
 
     /* FIXME - hack to make namespaces load, since
@@ -589,28 +589,28 @@ lookup_override_function(JSContext  *context,
     JS_BeginRequest(context);
 
     importer = gjs_get_global_slot(context, GJS_GLOBAL_SLOT_IMPORTS);
-    g_assert(JSVAL_IS_OBJECT(importer));
+    g_assert(importer.isObject());
 
-    overridespkg = JSVAL_VOID;
+    overridespkg = JS::UndefinedValue();
     overrides_name = gjs_context_get_const_string(context, GJS_STRING_GI_OVERRIDES);
-    if (!gjs_object_require_property(context, JSVAL_TO_OBJECT(importer), "importer",
+    if (!gjs_object_require_property(context, &importer.toObject(), "importer",
                                      overrides_name, &overridespkg) ||
-        !JSVAL_IS_OBJECT(overridespkg))
+        !overridespkg.isObject())
         goto fail;
 
-    module = JSVAL_VOID;
-    if (!gjs_object_require_property(context, JSVAL_TO_OBJECT(overridespkg), "GI repository object", 
ns_name, &module)
-        || !JSVAL_IS_OBJECT(module))
+    module = JS::UndefinedValue();
+    if (!gjs_object_require_property(context, &overridespkg.toObject(), "GI repository object", ns_name, 
&module)
+        || !module.isObject())
         goto fail;
 
     object_init_name = gjs_context_get_const_string(context, GJS_STRING_GOBJECT_INIT);
-    if (!gjs_object_require_property(context, JSVAL_TO_OBJECT(module), "override module",
+    if (!gjs_object_require_property(context, &module.toObject(), "override module",
                                      object_init_name, &function) ||
-        !JSVAL_IS_OBJECT(function))
+        !function.isObjectOrNull())
         goto fail;
 
     JS_EndRequest(context);
-    return JSVAL_TO_OBJECT(function);
+    return function.toObjectOrNull();
 
  fail:
     JS_ClearPendingException(context);
@@ -631,25 +631,25 @@ gjs_lookup_namespace_object_by_name(JSContext      *context,
     JS_BeginRequest(context);
 
     importer = gjs_get_global_slot(context, GJS_GLOBAL_SLOT_IMPORTS);
-    g_assert(JSVAL_IS_OBJECT(importer));
+    g_assert(importer.isObject());
 
-    girepository = JSVAL_VOID;
+    girepository = JS::UndefinedValue();
     gi_name = gjs_context_get_const_string(context, GJS_STRING_GI_MODULE);
-    if (!gjs_object_require_property(context, JSVAL_TO_OBJECT(importer), "importer",
+    if (!gjs_object_require_property(context, &importer.toObject(), "importer",
                                      gi_name, &girepository) ||
-        !JSVAL_IS_OBJECT(girepository)) {
+        !girepository.isObject()) {
         gjs_log_exception(context);
         gjs_throw(context, "No gi property in importer");
         goto fail;
     }
 
-    repo_obj = JSVAL_TO_OBJECT(girepository);
+    repo_obj = &girepository.toObject();
 
     if (!gjs_object_require_property(context, repo_obj, "GI repository object", ns_name, &ns_obj)) {
         goto fail;
     }
 
-    if (!JSVAL_IS_OBJECT(ns_obj)) {
+    if (!ns_obj.isObject()) {
         char *name;
 
         gjs_get_string_id(context, ns_name, &name);
@@ -660,7 +660,7 @@ gjs_lookup_namespace_object_by_name(JSContext      *context,
     }
 
     JS_EndRequest(context);
-    return JSVAL_TO_OBJECT(ns_obj);
+    return &ns_obj.toObject();
 
  fail:
     JS_EndRequest(context);
@@ -782,13 +782,10 @@ gjs_lookup_generic_constructor(JSContext  *context,
     if (!JS_GetProperty(context, in_object, constructor_name, &value))
         return NULL;
 
-    if (G_UNLIKELY (!JSVAL_IS_OBJECT(value) || JSVAL_IS_NULL(value)))
+    if (G_UNLIKELY (!value.isObject()))
         return NULL;
 
-    constructor = JSVAL_TO_OBJECT(value);
-    g_assert(constructor != NULL);
-
-    return constructor;
+    return &value.toObject();
 }
 
 JSObject *
@@ -806,8 +803,8 @@ gjs_lookup_generic_prototype(JSContext  *context,
                                        GJS_STRING_PROTOTYPE, &value))
         return NULL;
 
-    if (G_UNLIKELY (!JSVAL_IS_OBJECT(value)))
+    if (G_UNLIKELY (!value.isObjectOrNull()))
         return NULL;
 
-    return JSVAL_TO_OBJECT(value);
+    return value.toObjectOrNull();
 }
diff --git a/gi/union.cpp b/gi/union.cpp
index 318285e..1506c58 100644
--- a/gi/union.cpp
+++ b/gi/union.cpp
@@ -162,7 +162,7 @@ union_new(JSContext   *context,
 
             JS::Value rval;
 
-            rval = JSVAL_NULL;
+            rval = JS::NullValue();
             gjs_invoke_c_function_uncached(context, func_info, obj,
                                            0, NULL, &rval);
 
@@ -172,10 +172,10 @@ union_new(JSContext   *context,
              * creates a JSObject wrapper for the union that we immediately
              * discard.
              */
-            if (JSVAL_IS_NULL(rval))
+            if (rval.isNull())
                 return NULL;
             else
-                return gjs_c_union_from_union(context, JSVAL_TO_OBJECT(rval));
+                return gjs_c_union_from_union(context, &rval.toObject());
         }
 
         g_base_info_unref((GIBaseInfo*) func_info);
@@ -285,7 +285,7 @@ to_string_func(JSContext *context,
                JS::Value *vp)
 {
     JS::CallReceiver rec = JS::CallReceiverFromVp(vp);
-    JSObject *obj = JSVAL_TO_OBJECT(rec.thisv());
+    JSObject *obj = rec.thisv().toObjectOrNull();
 
     Union *priv;
     bool ret = false;
@@ -391,7 +391,7 @@ gjs_define_union_class(JSContext    *context,
     gjs_debug(GJS_DEBUG_GBOXED, "Defined class %s prototype is %p class %p in object %p",
               constructor_name, prototype, JS_GetClass(prototype), in_object);
 
-    value = OBJECT_TO_JSVAL(gjs_gtype_create_gtype_wrapper(context, gtype));
+    value = JS::ObjectOrNullValue(gjs_gtype_create_gtype_wrapper(context, gtype));
     JS_DefineProperty(context, constructor, "$gtype", value,
                       NULL, NULL, JSPROP_PERMANENT);
 
diff --git a/gi/value.cpp b/gi/value.cpp
index 58158ec..04563b7 100644
--- a/gi/value.cpp
+++ b/gi/value.cpp
@@ -107,7 +107,7 @@ gjs_value_from_array_and_length_values(JSContext    *context,
     array_arg.v_pointer = g_value_get_pointer(array_value);
 
     return gjs_value_from_explicit_array(context, value_p, array_type_info,
-                                         &array_arg, JSVAL_TO_INT(array_length));
+                                         &array_arg, array_length.toInt32());
 }
 
 static void
@@ -172,11 +172,11 @@ closure_marshal(GClosure        *closure,
     JSAutoCompartment ac(context, obj);
 
     argc = n_param_values;
-    rval = JSVAL_VOID;
+    rval = JS::UndefinedValue();
     if (argc > 0) {
         argv = g_newa(JS::Value, n_param_values);
 
-        gjs_set_values(context, argv, argc, JSVAL_VOID);
+        gjs_set_values(context, argv, argc, JS::UndefinedValue());
         gjs_root_value_locations(context, argv, argc);
     } else {
         /* squash a compiler warning */
@@ -287,7 +287,7 @@ closure_marshal(GClosure        *closure,
     gjs_closure_invoke(closure, argv_index, argv, &rval);
 
     if (return_value != NULL) {
-        if (JSVAL_IS_VOID(rval)) {
+        if (rval.isUndefined()) {
             /* something went wrong invoking, error should be set already */
             goto cleanup;
         }
@@ -340,23 +340,23 @@ static GType
 gjs_value_guess_g_type(JSContext *context,
                        JS::Value  value)
 {
-    if (JSVAL_IS_NULL(value))
+    if (value.isNull())
         return G_TYPE_POINTER;
 
-    if (JSVAL_IS_STRING(value))
+    if (value.isString())
         return G_TYPE_STRING;
 
-    if (JSVAL_IS_INT(value))
+    if (value.isInt32())
         return G_TYPE_INT;
 
-    if (JSVAL_IS_DOUBLE(value))
+    if (value.isDouble())
         return G_TYPE_DOUBLE;
 
-    if (JSVAL_IS_BOOLEAN(value))
+    if (value.isBoolean())
         return G_TYPE_BOOLEAN;
 
-    if (JSVAL_IS_OBJECT(value))
-        return gjs_gtype_get_actual_gtype(context, JSVAL_TO_OBJECT(value));
+    if (value.isObject())
+        return gjs_gtype_get_actual_gtype(context, &value.toObject());
 
     return G_TYPE_INVALID;
 }
@@ -395,9 +395,9 @@ gjs_value_to_g_value_internal(JSContext    *context,
         /* Don't use ValueToString since we don't want to just toString()
          * everything automatically
          */
-        if (JSVAL_IS_NULL(value)) {
+        if (value.isNull()) {
             g_value_set_string(gvalue, NULL);
-        } else if (JSVAL_IS_STRING(value)) {
+        } else if (value.isString()) {
             gchar *utf8_string;
 
             if (!gjs_string_to_utf8(context, value, &utf8_string))
@@ -489,11 +489,11 @@ gjs_value_to_g_value_internal(JSContext    *context,
         GObject *gobj;
 
         gobj = NULL;
-        if (JSVAL_IS_NULL(value)) {
+        if (value.isNull()) {
             /* nothing to do */
-        } else if (JSVAL_IS_OBJECT(value)) {
+        } else if (value.isObject()) {
             JSObject *obj;
-            obj = JSVAL_TO_OBJECT(value);
+            obj = &value.toObject();
 
             if (!gjs_typecheck_object(context, obj, gtype, true))
                 return false;
@@ -513,15 +513,15 @@ gjs_value_to_g_value_internal(JSContext    *context,
         JSBool found_length;
 
         length_name = gjs_context_get_const_string(context, GJS_STRING_LENGTH);
-        if (JSVAL_IS_NULL(value)) {
+        if (value.isNull()) {
             /* do nothing */
-        } else if (JS_HasPropertyById(context, JSVAL_TO_OBJECT(value), length_name, &found_length) &&
+        } else if (JS_HasPropertyById(context, &value.toObject(), length_name, &found_length) &&
                    found_length) {
             JS::Value length_value;
             guint32 length;
 
             if (!gjs_object_require_property(context,
-                                             JSVAL_TO_OBJECT(value), NULL,
+                                             &value.toObject(), NULL,
                                              length_name,
                                              &length_value) ||
                 !JS_ValueToECMAUint32(context, length_value, &length)) {
@@ -551,11 +551,11 @@ gjs_value_to_g_value_internal(JSContext    *context,
         void *gboxed;
 
         gboxed = NULL;
-        if (JSVAL_IS_NULL(value)) {
+        if (value.isNull()) {
             /* nothing to do */
-        } else if (JSVAL_IS_OBJECT(value)) {
+        } else if (value.isObject()) {
             JSObject *obj;
-            obj = JSVAL_TO_OBJECT(value);
+            obj = &value.toObject();
 
             if (g_type_is_a(gtype, G_TYPE_ERROR)) {
                 /* special case GError */
@@ -620,10 +620,10 @@ gjs_value_to_g_value_internal(JSContext    *context,
     } else if (g_type_is_a(gtype, G_TYPE_VARIANT)) {
         GVariant *variant = NULL;
 
-        if (JSVAL_IS_NULL(value)) {
+        if (value.isNull()) {
             /* nothing to do */
-        } else if (JSVAL_IS_OBJECT(value)) {
-            JSObject *obj = JSVAL_TO_OBJECT(value);
+        } else if (value.isObject()) {
+            JSObject *obj = &value.toObject();
 
             if (!gjs_typecheck_boxed(context, obj, NULL, G_TYPE_VARIANT, true))
                 return false;
@@ -652,7 +652,7 @@ gjs_value_to_g_value_internal(JSContext    *context,
             if (v == NULL) {
                 gjs_throw(context,
                           "%d is not a valid value for enumeration %s",
-                          JSVAL_TO_INT(value), g_type_name(gtype));
+                          value.toInt32(), g_type_name(gtype));
                 return false;
             }
 
@@ -684,11 +684,11 @@ gjs_value_to_g_value_internal(JSContext    *context,
         void *gparam;
 
         gparam = NULL;
-        if (JSVAL_IS_NULL(value)) {
+        if (value.isNull()) {
             /* nothing to do */
-        } else if (JSVAL_IS_OBJECT(value)) {
+        } else if (value.isObject()) {
             JSObject *obj;
-            obj = JSVAL_TO_OBJECT(value);
+            obj = &value.toObject();
 
             if (!gjs_typecheck_param(context, obj, gtype, true))
                 return false;
@@ -706,23 +706,23 @@ gjs_value_to_g_value_internal(JSContext    *context,
     } else if (g_type_is_a(gtype, G_TYPE_GTYPE)) {
         GType type;
 
-        if (!JSVAL_IS_OBJECT(value)) {
+        if (!value.isObject()) {
             gjs_throw(context, "Wrong type %s; expect a GType object",
                       gjs_get_type_name(value));
             return false;
         }
 
-        type = gjs_gtype_get_actual_gtype(context, JSVAL_TO_OBJECT(value));
+        type = gjs_gtype_get_actual_gtype(context, &value.toObject());
         g_value_set_gtype(gvalue, type);
     } else if (g_type_is_a(gtype, G_TYPE_POINTER)) {
-        if (JSVAL_IS_NULL(value)) {
+        if (value.isNull()) {
             /* Nothing to do */
         } else {
             gjs_throw(context,
                       "Cannot convert non-null JS value to G_POINTER");
             return false;
         }
-    } else if (JSVAL_IS_NUMBER(value) &&
+    } else if (value.isNumber() &&
                g_value_type_transformable(G_TYPE_INT, gtype)) {
         /* Only do this crazy gvalue transform stuff after we've
          * exhausted everything else. Adding this for
@@ -742,7 +742,7 @@ gjs_value_to_g_value_internal(JSContext    *context,
         }
     } else {
         gjs_debug(GJS_DEBUG_GCLOSURE, "JS::Value is number %d gtype fundamental %d transformable to int %d 
from int %d",
-                  JSVAL_IS_NUMBER(value),
+                  value.isNumber(),
                   G_TYPE_IS_FUNDAMENTAL(gtype),
                   g_value_type_transformable(gtype, G_TYPE_INT),
                   g_value_type_transformable(G_TYPE_INT, gtype));
@@ -819,8 +819,8 @@ gjs_value_from_g_value_internal(JSContext    *context,
         v = g_value_get_string(gvalue);
         if (v == NULL) {
             gjs_debug_marshal(GJS_DEBUG_GCLOSURE,
-                              "Converting NULL string to JSVAL_NULL");
-            *value_p = JSVAL_NULL;
+                              "Converting NULL string to JS::NullValue()");
+            *value_p = JS::NullValue();
         } else {
             if (!gjs_string_from_utf8(context, v, -1, value_p))
                 return false;
@@ -828,11 +828,11 @@ gjs_value_from_g_value_internal(JSContext    *context,
     } else if (gtype == G_TYPE_CHAR) {
         char v;
         v = g_value_get_schar(gvalue);
-        *value_p = INT_TO_JSVAL(v);
+        *value_p = JS::Int32Value(v);
     } else if (gtype == G_TYPE_UCHAR) {
         unsigned char v;
         v = g_value_get_uchar(gvalue);
-        *value_p = INT_TO_JSVAL(v);
+        *value_p = JS::Int32Value(v);
     } else if (gtype == G_TYPE_INT) {
         int v;
         v = g_value_get_int(gvalue);
@@ -852,7 +852,7 @@ gjs_value_from_g_value_internal(JSContext    *context,
     } else if (gtype == G_TYPE_BOOLEAN) {
         bool v;
         v = g_value_get_boolean(gvalue);
-        *value_p = BOOLEAN_TO_JSVAL(!!v);
+        *value_p = JS::BooleanValue(!!v);
     } else if (g_type_is_a(gtype, G_TYPE_OBJECT) || g_type_is_a(gtype, G_TYPE_INTERFACE)) {
         GObject *gobj;
         JSObject *obj;
@@ -860,7 +860,7 @@ gjs_value_from_g_value_internal(JSContext    *context,
         gobj = (GObject*) g_value_get_object(gvalue);
 
         obj = gjs_object_from_g_object(context, gobj);
-        *value_p = OBJECT_TO_JSVAL(obj);
+        *value_p = JS::ObjectOrNullValue(obj);
     } else if (gtype == G_TYPE_STRV) {
         if (!gjs_array_from_strv (context,
                                   value_p,
@@ -891,7 +891,7 @@ gjs_value_from_g_value_internal(JSContext    *context,
         /* special case GError */
         if (g_type_is_a(gtype, G_TYPE_ERROR)) {
             obj = gjs_error_from_gerror(context, (GError*) gboxed, false);
-            *value_p = OBJECT_TO_JSVAL(obj);
+            *value_p = JS::ObjectOrNullValue(obj);
 
             return true;
         }
@@ -936,7 +936,7 @@ gjs_value_from_g_value_internal(JSContext    *context,
             return false;
         }
 
-        *value_p = OBJECT_TO_JSVAL(obj);
+        *value_p = JS::ObjectOrNullValue(obj);
         g_base_info_unref(info);
     } else if (g_type_is_a(gtype, G_TYPE_ENUM)) {
         return convert_int_to_enum(context, value_p, gtype, g_value_get_enum(gvalue));
@@ -947,7 +947,7 @@ gjs_value_from_g_value_internal(JSContext    *context,
         gparam = g_value_get_param(gvalue);
 
         obj = gjs_param_from_g_param(context, gparam);
-        *value_p = OBJECT_TO_JSVAL(obj);
+        *value_p = JS::ObjectOrNullValue(obj);
     } else if (signal_query && g_type_is_a(gtype, G_TYPE_POINTER)) {
         bool res;
         GArgument arg;
@@ -991,7 +991,7 @@ gjs_value_from_g_value_internal(JSContext    *context,
         pointer = g_value_get_pointer(gvalue);
 
         if (pointer == NULL) {
-            *value_p = JSVAL_NULL;
+            *value_p = JS::NullValue();
         } else {
             gjs_throw(context,
                       "Can't convert non-null pointer to JS value");
@@ -1019,7 +1019,7 @@ gjs_value_from_g_value_internal(JSContext    *context,
         if (obj == NULL)
             return false;
         else
-            *value_p = OBJECT_TO_JSVAL(obj);
+            *value_p = JS::ObjectValue(*obj);
     } else {
         gjs_throw(context,
                   "Don't know how to convert GType %s to JavaScript object",
diff --git a/gjs/byteArray.cpp b/gjs/byteArray.cpp
index b4671d5..747392d 100644
--- a/gjs/byteArray.cpp
+++ b/gjs/byteArray.cpp
@@ -84,7 +84,7 @@ gjs_value_from_gsize(JSContext         *context,
                      JS::MutableHandleValue value_p)
 {
     if (v > (gsize) JSVAL_INT_MAX) {
-        value_p.set(INT_TO_JSVAL(v));
+        value_p.setInt32(v);
         return true;
     } else {
         return JS_NewNumberValue(context, v, value_p.address());
@@ -125,8 +125,8 @@ gjs_value_to_gsize(JSContext         *context,
      *  - JS_ValueToECMAUint32() always goes via a double which is slow
      *  - nicer error message on negative indices
      */
-    if (JSVAL_IS_INT(value)) {
-        int i = JSVAL_TO_INT(value);
+    if (value.isInt32()) {
+        int i = value.toInt32();
         if (i < 0) {
             gjs_throw(context, "Negative length or index %d is not allowed for ByteArray",
                       i);
@@ -188,7 +188,7 @@ byte_array_get_index(JSContext         *context,
         return false;
     }
 
-    value_p.set(INT_TO_JSVAL(data[idx]));
+    value_p.setInt32(data[idx]);
 
     return true;
 }
@@ -214,7 +214,7 @@ byte_array_get_prop(JSContext *context,
         return false;
 
     /* First handle array indexing */
-    if (JSVAL_IS_NUMBER(id_value)) {
+    if (id_value.isNumber()) {
         gsize idx;
         if (!gjs_value_to_gsize(context, id_value, &idx))
             return false;
@@ -299,7 +299,7 @@ byte_array_set_index(JSContext         *context,
     g_array_index(priv->array, guint8, idx) = v;
 
     /* Stop JS from storing a copy of the value */
-    value_p.set(JSVAL_VOID);
+    value_p.setUndefined();
 
     return true;
 }
@@ -326,7 +326,7 @@ byte_array_set_prop(JSContext *context,
         return false;
 
     /* First handle array indexing */
-    if (JSVAL_IS_NUMBER(id_value)) {
+    if (id_value.isNumber()) {
         gsize idx;
         if (!gjs_value_to_gsize(context, id_value, &idx))
             return false;
@@ -417,7 +417,7 @@ to_string_func(JSContext *context,
                JS::Value *vp)
 {
     JS::CallArgs argv = JS::CallArgsFromVp (argc, vp);
-    JSObject *object = JSVAL_TO_OBJECT(argv.thisv());
+    JSObject *object = argv.thisv().toObjectOrNull();
     ByteArrayInstance *priv;
     char *encoding;
     bool encoding_is_utf8;
@@ -430,8 +430,7 @@ to_string_func(JSContext *context,
 
     byte_array_ensure_array(priv);
 
-    if (argc >= 1 &&
-        JSVAL_IS_STRING(argv[0])) {
+    if (argc >= 1 && argv[0].isString()) {
         if (!gjs_string_to_utf8(context, argv[0], &encoding))
             return false;
 
@@ -502,7 +501,7 @@ to_string_func(JSContext *context,
                                 bytes_written / 2);
         if (s != NULL) {
             ok = true;
-            argv.rval().set(STRING_TO_JSVAL(s));
+            argv.rval().setString(s);
         }
 
         g_free(u16_str);
@@ -516,7 +515,7 @@ to_gbytes_func(JSContext *context,
                JS::Value *vp)
 {
     JS::CallReceiver rec = JS::CallReceiverFromVp(vp);
-    JSObject *object = JSVAL_TO_OBJECT(rec.thisv());
+    JSObject *object = rec.thisv().toObjectOrNull();
     ByteArrayInstance *priv;
     JSObject *ret_bytes_obj;
     GIBaseInfo *gbytes_info;
@@ -531,7 +530,7 @@ to_gbytes_func(JSContext *context,
     ret_bytes_obj = gjs_boxed_from_c_struct(context, (GIStructInfo*)gbytes_info,
                                             priv->bytes, GJS_BOXED_CREATION_NONE);
 
-    rec.rval().set(OBJECT_TO_JSVAL(ret_bytes_obj));
+    rec.rval().setObjectOrNull(ret_bytes_obj);
     return true;
 }
 
@@ -545,14 +544,14 @@ byte_array_get_prototype(JSContext *context)
 
     retval = gjs_get_global_slot (context, GJS_GLOBAL_SLOT_BYTE_ARRAY_PROTOTYPE);
 
-    if (!JSVAL_IS_OBJECT (retval)) {
+    if (!retval.isObject()) {
         if (!gjs_eval_with_scope(context, NULL,
                                  "imports.byteArray.ByteArray.prototype;", -1,
                                  "<internal>", &retval))
             g_error ("Could not import byte array prototype\n");
     }
 
-    return JSVAL_TO_OBJECT(retval);
+    return &retval.toObject();
 }
 
 static JSObject*
@@ -598,14 +597,13 @@ from_string_func(JSContext *context,
 
     priv->array = gjs_g_byte_array_new(0);
 
-    if (!JSVAL_IS_STRING(argv[0])) {
+    if (!argv[0].isString()) {
         gjs_throw(context,
                   "byteArray.fromString() called with non-string as first arg");
         goto out;
     }
 
-    if (argc > 1 &&
-        JSVAL_IS_STRING(argv[1])) {
+    if (argc > 1 && argv[1].isString()) {
         if (!gjs_string_to_utf8(context, argv[1], &encoding))
             goto out;
 
@@ -644,7 +642,7 @@ from_string_func(JSContext *context,
         const jschar *u16_chars;
         gsize u16_len;
 
-        u16_chars = JS_GetStringCharsAndLength(context, JSVAL_TO_STRING(argv[0]), &u16_len);
+        u16_chars = JS_GetStringCharsAndLength(context, argv[0].toString(), &u16_len);
         if (u16_chars == NULL)
             goto out;
 
@@ -669,7 +667,7 @@ from_string_func(JSContext *context,
         g_free(encoded);
     }
 
-    argv.rval().set(OBJECT_TO_JSVAL(obj));
+    argv.rval().setObject(*obj);
 
     retval = true;
  out:
@@ -703,13 +701,13 @@ from_array_func(JSContext *context,
 
     priv->array = gjs_g_byte_array_new(0);
 
-    if (!JS_IsArrayObject(context, JSVAL_TO_OBJECT(argv[0]))) {
+    if (!JS_IsArrayObject(context, &argv[0].toObject())) {
         gjs_throw(context,
                   "byteArray.fromArray() called with non-array as first arg");
         goto out;
     }
 
-    if (!JS_GetArrayLength(context, JSVAL_TO_OBJECT(argv[0]), &len)) {
+    if (!JS_GetArrayLength(context, &argv[0].toObject(), &len)) {
         gjs_throw(context,
                   "byteArray.fromArray() can't get length of first array arg");
         goto out;
@@ -721,15 +719,15 @@ from_array_func(JSContext *context,
         JS::Value elem;
         guint8 b;
 
-        elem = JSVAL_VOID;
-        if (!JS_GetElement(context, JSVAL_TO_OBJECT(argv[0]), i, &elem)) {
-            /* this means there was an exception, while elem == JSVAL_VOID
+        elem = JS::UndefinedValue();
+        if (!JS_GetElement(context, &argv[0].toObject(), i, &elem)) {
+            /* this means there was an exception, while elem.isUndefined()
              * means no element found
              */
             goto out;
         }
 
-        if (JSVAL_IS_VOID(elem))
+        if (elem.isUndefined())
             continue;
 
         if (!gjs_value_to_byte(context, elem, &b))
@@ -739,7 +737,7 @@ from_array_func(JSContext *context,
     }
 
     ret = true;
-    argv.rval().set(OBJECT_TO_JSVAL(obj));
+    argv.rval().setObject(*obj);
  out:
     JS_RemoveObjectRoot(context, &obj);
     return ret;
@@ -775,7 +773,7 @@ from_gbytes_func(JSContext *context,
     priv->bytes = g_bytes_ref(gbytes);
 
     ret = true;
-    argv.rval().set(OBJECT_TO_JSVAL(obj));
+    argv.rval().setObject(*obj);
     return ret;
 }
 
@@ -928,9 +926,9 @@ gjs_define_byte_array_stuff(JSContext  *context,
     if (!JS_DefineFunctions(context, module, &gjs_byte_array_module_funcs[0]))
         return false;
 
-    g_assert(JSVAL_IS_VOID(gjs_get_global_slot(context, GJS_GLOBAL_SLOT_BYTE_ARRAY_PROTOTYPE)));
+    g_assert(gjs_get_global_slot(context, GJS_GLOBAL_SLOT_BYTE_ARRAY_PROTOTYPE).isUndefined());
     gjs_set_global_slot(context, GJS_GLOBAL_SLOT_BYTE_ARRAY_PROTOTYPE,
-                        OBJECT_TO_JSVAL(prototype));
+                        JS::ObjectOrNullValue(prototype));
 
     *module_out = module;
     return true;
diff --git a/gjs/compat.h b/gjs/compat.h
index cfe4ca0..a51aab5 100644
--- a/gjs/compat.h
+++ b/gjs/compat.h
@@ -56,7 +56,7 @@ G_BEGIN_DECLS
 static bool G_GNUC_UNUSED JS_NewNumberValue(JSContext *cx, double d, JS::Value *rval)
     {
         *rval = JS_NumberValue(d);
-        return JSVAL_IS_NUMBER(*rval);
+        return rval->isNumber();
     }
 
 /**
@@ -99,7 +99,7 @@ gjs_##name##_constructor(JSContext  *context,           \
  * successfully.
  */
 #define GJS_NATIVE_CONSTRUCTOR_FINISH(name)             \
-    argv.rval().set(OBJECT_TO_JSVAL(object));
+    argv.rval().set(JS::ObjectValue(*object));
 
 /**
  * GJS_NATIVE_CONSTRUCTOR_DEFINE_ABSTRACT:
diff --git a/gjs/context.cpp b/gjs/context.cpp
index 7d758e0..1954d86 100644
--- a/gjs/context.cpp
+++ b/gjs/context.cpp
@@ -124,7 +124,7 @@ gjs_log(JSContext *context,
     exc_state = JS_SaveExceptionState(context);
     jstr = JS_ValueToString(context, argv[0]);
     if (jstr != NULL)
-        argv[0] = STRING_TO_JSVAL(jstr);    // GC root
+        argv[0] = JS::StringValue(jstr);    // GC root
     JS_RestoreExceptionState(context, exc_state);
 
     if (jstr == NULL) {
@@ -133,7 +133,7 @@ gjs_log(JSContext *context,
         return true;
     }
 
-    if (!gjs_string_to_utf8(context, STRING_TO_JSVAL(jstr), &s)) {
+    if (!gjs_string_to_utf8(context, JS::StringValue(jstr), &s)) {
         JS_EndRequest(context);
         return false;
     }
@@ -142,7 +142,7 @@ gjs_log(JSContext *context,
     g_free(s);
 
     JS_EndRequest(context);
-    argv.rval().set(JSVAL_VOID);
+    argv.rval().setUndefined();
     return true;
 }
 
@@ -155,8 +155,7 @@ gjs_log_error(JSContext *context,
     JSExceptionState *exc_state;
     JSString *jstr;
 
-    if ((argc != 1 && argc != 2) ||
-        !JSVAL_IS_OBJECT (argv[0])) {
+    if ((argc != 1 && argc != 2) || !argv[0].isObject()) {
         gjs_throw(context, "Must pass an exception and optionally a message to logError()");
         return false;
     }
@@ -169,7 +168,7 @@ gjs_log_error(JSContext *context,
         exc_state = JS_SaveExceptionState(context);
         jstr = JS_ValueToString(context, argv[1]);
         if (jstr != NULL)
-            argv[1] = STRING_TO_JSVAL(jstr);    // GC root
+            argv[1] = JS::StringValue(jstr);    // GC root
         JS_RestoreExceptionState(context, exc_state);
     } else {
         jstr = NULL;
@@ -178,7 +177,7 @@ gjs_log_error(JSContext *context,
     gjs_log_exception_full(context, argv[0], jstr);
 
     JS_EndRequest(context);
-    argv.rval().set(JSVAL_VOID);
+    argv.rval().setUndefined();
     return true;
 }
 
@@ -204,12 +203,12 @@ gjs_print_parse_args(JSContext *context,
 
         jstr = JS_ValueToString(context, argv[n]);
         if (jstr != NULL)
-            argv[n] = STRING_TO_JSVAL(jstr); // GC root
+            argv[n] = JS::StringValue(jstr); // GC root
 
         JS_RestoreExceptionState(context, exc_state);
 
         if (jstr != NULL) {
-            if (!gjs_string_to_utf8(context, STRING_TO_JSVAL(jstr), &s)) {
+            if (!gjs_string_to_utf8(context, JS::StringValue(jstr), &s)) {
                 JS_EndRequest(context);
                 g_string_free(str, true);
                 return false;
@@ -249,7 +248,7 @@ gjs_print(JSContext *context,
     g_print("%s\n", buffer);
     g_free(buffer);
 
-    argv.rval().set(JSVAL_VOID);
+    argv.rval().setUndefined();
     return true;
 }
 
@@ -268,7 +267,7 @@ gjs_printerr(JSContext *context,
     g_printerr("%s\n", buffer);
     g_free(buffer);
 
-    argv.rval().set(JSVAL_VOID);
+    argv.rval().setUndefined();
     return true;
 }
 
@@ -434,7 +433,7 @@ gjs_context_constructed(GObject *object)
     JSAutoCompartment ac(js_context->context, js_context->global);
 
     if (!JS_DefineProperty(js_context->context, js_context->global,
-                           "window", OBJECT_TO_JSVAL(js_context->global),
+                           "window", JS::ObjectValue(*js_context->global),
                            NULL, NULL,
                            JSPROP_READONLY | JSPROP_PERMANENT))
         g_error("No memory to export global object as 'window'");
@@ -652,7 +651,7 @@ gjs_context_eval(GjsContext   *js_context,
     }
 
     if (exit_status_p) {
-        if (JSVAL_IS_INT(retval)) {
+        if (retval.isInt32()) {
             int code;
             if (JS_ValueToInt32(js_context->context, retval, &code)) {
                 gjs_debug(GJS_DEBUG_CONTEXT,
diff --git a/gjs/coverage.cpp b/gjs/coverage.cpp
index 5f6eb0a..da4e64a 100644
--- a/gjs/coverage.cpp
+++ b/gjs/coverage.cpp
@@ -404,7 +404,7 @@ get_array_from_js_value(JSContext             *context,
     g_return_val_if_fail(out_array != NULL, false);
     g_return_val_if_fail(*out_array == NULL, false);
 
-    JSObject *js_array = JSVAL_TO_OBJECT(*value);
+    JSObject *js_array = &value->toObject();
 
     if (!JS_IsArrayObject(context, js_array)) {
         g_critical("Returned object from is not an array");
@@ -448,15 +448,13 @@ convert_and_insert_unsigned_int(GArray    *array,
                                 JSContext *context,
                                 JS::Value *element)
 {
-    if (!JSVAL_IS_INT(*element) &&
-        !JSVAL_IS_VOID(*element) &&
-        !JSVAL_IS_NULL(*element)) {
+    if (!element->isInt32() && !element->isUndefined() && !element->isNull()) {
         g_critical("Array element is not an integer or undefined or null");
         return false;
     }
 
-    if (JSVAL_IS_INT(*element)) {
-        unsigned int element_integer = JSVAL_TO_INT(*element);
+    if (element->isInt32()) {
+        unsigned int element_integer = element->toInt32();
         g_array_append_val(array, element_integer);
     } else {
         int not_executable = -1;
@@ -510,12 +508,13 @@ convert_and_insert_function_decl(GArray    *array,
                                  JSContext *context,
                                  JS::Value *element)
 {
-    JSObject *object = JSVAL_TO_OBJECT(*element);
+    JSObject *object;
 
-    if (!object) {
-        gjs_throw(context, "Converting element to object failed");
+    if (!element->isObject()) {
+        gjs_throw(context, "Function element is not an object");
         return false;
     }
+    object = &element->toObject();
 
     JS::Value function_name_property_value;
 
@@ -526,14 +525,14 @@ convert_and_insert_function_decl(GArray    *array,
 
     char *utf8_string;
 
-    if (JSVAL_IS_STRING(function_name_property_value)) {
+    if (function_name_property_value.isString()) {
         if (!gjs_string_to_utf8(context,
                                 function_name_property_value,
                                 &utf8_string)) {
             gjs_throw(context, "Failed to convert function_name to string");
             return false;
         }
-    } else if (JSVAL_IS_NULL(function_name_property_value)) {
+    } else if (function_name_property_value.isNull()) {
         utf8_string = NULL;
     } else {
         gjs_throw(context, "Unexpected type for function_name");
@@ -542,20 +541,20 @@ convert_and_insert_function_decl(GArray    *array,
 
     JS::Value hit_count_property_value;
     if (!JS_GetProperty(context, object, "hitCount", &hit_count_property_value) ||
-        !JSVAL_IS_INT(hit_count_property_value)) {
+        !hit_count_property_value.isInt32()) {
         gjs_throw(context, "Failed to get hitCount property for function object");
         return false;
     }
 
     JS::Value line_number_property_value;
     if (!JS_GetProperty(context, object, "line", &line_number_property_value) ||
-        !JSVAL_IS_INT(line_number_property_value)) {
+        !line_number_property_value.isInt32()) {
         gjs_throw(context, "Failed to get line property for function object");
         return false;
     }
 
-    unsigned int line_number = JSVAL_TO_INT(line_number_property_value);
-    unsigned int hit_count = JSVAL_TO_INT(hit_count_property_value);
+    unsigned int line_number = line_number_property_value.toInt32();
+    unsigned int hit_count = hit_count_property_value.toInt32();
 
     GjsCoverageFunction info;
     init_covered_function(&info,
@@ -612,39 +611,34 @@ convert_and_insert_branch_exit(GArray    *array,
                                JSContext *context,
                                JS::Value *element)
 {
-    if (!JSVAL_IS_OBJECT(*element)) {
+    if (!element->isObject()) {
         gjs_throw(context, "Branch exit array element is not an object");
         return false;
     }
 
-    JSObject *object = JSVAL_TO_OBJECT(*element);
-
-    if (!object) {
-        gjs_throw(context, "Converting element to object failed");
-        return false;
-    }
+    JSObject *object = &element->toObject();
 
     JS::Value line_value;
     int32_t line;
 
     if (!JS_GetProperty(context, object, "line", &line_value) ||
-        !JSVAL_IS_INT(line_value)) {
+        !line_value.isInt32()) {
         gjs_throw(context, "Failed to get line property from element");
         return false;
     }
 
-    line = JSVAL_TO_INT(line_value);
+    line = line_value.toInt32();
 
     JS::Value hit_count_value;
     int32_t hit_count;
 
     if (!JS_GetProperty(context, object, "hitCount", &hit_count_value) ||
-        !JSVAL_IS_INT(hit_count_value)) {
+        !hit_count_value.isInt32()) {
         gjs_throw(context, "Failed to get hitCount property from element");
         return false;
     }
 
-    hit_count = JSVAL_TO_INT(hit_count_value);
+    hit_count = hit_count_value.toInt32();
 
     GjsCoverageBranchExit exit = {
         (unsigned int) line,
@@ -661,47 +655,40 @@ convert_and_insert_branch_info(GArray    *array,
                                JSContext *context,
                                JS::Value *element)
 {
-    if (!JSVAL_IS_OBJECT(*element) &&
-        !JSVAL_IS_VOID(*element)) {
+    if (!element->isObject() && !element->isUndefined()) {
         gjs_throw(context, "Branch array element is not an object or undefined");
         return false;
     }
 
-    if (JSVAL_IS_OBJECT(*element)) {
-        JSObject *object = JSVAL_TO_OBJECT(*element);
-
-        if (!object) {
-            gjs_throw(context, "Converting element to object failed");
-            return false;
-        }
-
+    if (element->isObject()) {
+        JSObject *object = &element->toObject();
         JS::Value branch_point_value;
         int32_t branch_point;
 
         if (!JS_GetProperty(context, object, "point", &branch_point_value) ||
-            !JSVAL_IS_INT(branch_point_value)) {
+            !branch_point_value.isInt32()) {
             gjs_throw(context, "Failed to get point property from element");
             return false;
         }
 
-        branch_point = JSVAL_TO_INT(branch_point_value);
+        branch_point = branch_point_value.toInt32();
 
         JS::Value was_hit_value;
         bool was_hit;
 
         if (!JS_GetProperty(context, object, "hit", &was_hit_value) ||
-            !JSVAL_IS_BOOLEAN(was_hit_value)) {
+            !was_hit_value.isBoolean()) {
             gjs_throw(context, "Failed to get point property from element");
             return false;
         }
 
-        was_hit = JSVAL_TO_BOOLEAN(was_hit_value);
+        was_hit = was_hit_value.toBoolean();
 
         JS::Value branch_exits_value;
         GArray *branch_exits_array = NULL;
 
         if (!JS_GetProperty(context, object, "exits", &branch_exits_value) ||
-            !JSVAL_IS_OBJECT(branch_exits_value)) {
+            !branch_exits_value.isObject()) {
             gjs_throw(context, "Failed to get exits property from element");
             return false;
         }
@@ -766,7 +753,7 @@ fetch_coverage_file_statistics_from_js(JSContext                 *context,
     JSAutoRequest ar(context);
 
     JSString *filename_jsstr = JS_NewStringCopyZ(context, filename);
-    JS::Value filename_jsval = STRING_TO_JSVAL(filename_jsstr);
+    JS::Value filename_jsval = JS::StringValue(filename_jsstr);
 
     GArray *lines = get_executed_lines_for(context, coverage_statistics, &filename_jsval);
     GArray *functions = get_functions_for(context, coverage_statistics, &filename_jsval);
@@ -1066,10 +1053,10 @@ gjs_get_generic_object_constructor(JSContext        *context,
 
     JS::Value object_constructor_value;
     if (!JS_GetProperty(context, global_object, "Object", &object_constructor_value) ||
-        !JSVAL_IS_OBJECT(object_constructor_value))
+        !object_constructor_value.isObject())
         g_assert_not_reached();
 
-    return JSVAL_TO_OBJECT(object_constructor_value);
+    return &object_constructor_value.toObject();
 }
 
 static JSString *
@@ -1214,7 +1201,7 @@ coverage_statistics_has_stale_cache(GjsCoverage *coverage)
         g_error("Failed to call into javascript to get stale cache value. This is a bug");
     }
 
-    return JSVAL_TO_BOOLEAN(stale_cache_value);
+    return stale_cache_value.toBoolean();
 }
 
 static unsigned int _suppressed_coverage_messages_count = 0;
@@ -1365,7 +1352,7 @@ coverage_log(JSContext *context,
 
     if (!g_getenv("GJS_SHOW_COVERAGE_MESSAGES")) {
         _suppressed_coverage_messages_count++;
-        argv.rval().set(JSVAL_VOID);
+        argv.rval().set(JS::UndefinedValue());
         return true;
     }
 
@@ -1374,7 +1361,7 @@ coverage_log(JSContext *context,
     exc_state = JS_SaveExceptionState(context);
     jstr = JS_ValueToString(context, argv[0]);
     if (jstr != NULL)
-        argv[0] = STRING_TO_JSVAL(jstr);    // GC root
+        argv[0] = JS::StringValue(jstr);    // GC root
     JS_RestoreExceptionState(context, exc_state);
 
     if (jstr == NULL) {
@@ -1382,14 +1369,14 @@ coverage_log(JSContext *context,
         return true;
     }
 
-    if (!gjs_string_to_utf8(context, STRING_TO_JSVAL(jstr), &s)) {
+    if (!gjs_string_to_utf8(context, JS::StringValue(jstr), &s)) {
         return false;
     }
 
     g_message("JS COVERAGE MESSAGE: %s", s);
     g_free(s);
 
-    argv.rval().set(JSVAL_VOID);
+    argv.rval().set(JS::UndefinedValue());
     return true;
 }
 
@@ -1602,10 +1589,10 @@ gjs_wrap_root_importer_in_compartment(JSContext *context,
                               gjs_get_global_slot(context,
                                                   GJS_GLOBAL_SLOT_IMPORTS));
 
-    g_assert (!JSVAL_IS_VOID(importer));
+    g_assert (!importer.isUndefined());
 
     JS::RootedObject wrapped_importer(JS_GetRuntime(context),
-                                      JSVAL_TO_OBJECT(importer));
+                                      importer.toObjectOrNull());
     if (!JS_WrapObject(context, wrapped_importer.address())) {
         return NULL;
     }
@@ -1686,7 +1673,7 @@ bootstrap_coverage(GjsCoverage *coverage)
 
         JS::Value coverage_statistics_prototype_value;
         if (!JS_GetProperty(context, debugger_compartment, "CoverageStatistics", 
&coverage_statistics_prototype_value) ||
-            !JSVAL_IS_OBJECT(coverage_statistics_prototype_value)) {
+            !coverage_statistics_prototype_value.isObject()) {
             gjs_throw(context, "Failed to get CoverageStatistics prototype");
             return false;
         }
@@ -1709,13 +1696,13 @@ bootstrap_coverage(GjsCoverage *coverage)
             cache_value.set(JS::UndefinedValue());
         }
 
-        JSObject *coverage_statistics_constructor = JSVAL_TO_OBJECT(coverage_statistics_prototype_value);
+        JSObject *coverage_statistics_constructor = &coverage_statistics_prototype_value.toObject();
 
         /* Now create the array to pass the desired prefixes over */
         JSObject *prefixes = gjs_build_string_array(context, -1, priv->prefixes);
 
         JS::Value coverage_statistics_constructor_arguments[] = {
-            OBJECT_TO_JSVAL(prefixes),
+            JS::ObjectValue(*prefixes),
             cache_value.get()
         };
 
diff --git a/gjs/importer.cpp b/gjs/importer.cpp
index 03f1da1..9ecea53 100644
--- a/gjs/importer.cpp
+++ b/gjs/importer.cpp
@@ -71,7 +71,7 @@ define_meta_properties(JSContext  *context,
     if (full_path != NULL) {
         if (!JS_DefineProperty(context, module_obj,
                                "__file__",
-                               STRING_TO_JSVAL(JS_NewStringCopyZ(context, full_path)),
+                               JS::StringValue(JS_NewStringCopyZ(context, full_path)),
                                NULL, NULL,
                                /* don't set ENUMERATE since we wouldn't want to copy
                                 * this symbol to any other object for example.
@@ -83,8 +83,8 @@ define_meta_properties(JSContext  *context,
     if (!JS_DefineProperty(context, module_obj,
                            "__moduleName__",
                            parent_is_module ?
-                           STRING_TO_JSVAL(JS_NewStringCopyZ(context, module_name)) :
-                           JSVAL_NULL,
+                           JS::StringValue(JS_NewStringCopyZ(context, module_name)) :
+                           JS::NullValue(),
                            NULL, NULL,
                            /* don't set ENUMERATE since we wouldn't want to copy
                             * this symbol to any other object for example.
@@ -94,7 +94,7 @@ define_meta_properties(JSContext  *context,
 
     if (!JS_DefineProperty(context, module_obj,
                            "__parentModule__",
-                           parent_is_module ? OBJECT_TO_JSVAL(parent) : JSVAL_NULL,
+                           parent_is_module ? JS::ObjectValue(*parent) : JS::NullValue(),
                            NULL, NULL,
                            /* don't set ENUMERATE since we wouldn't want to copy
                             * this symbol to any other object for example.
@@ -132,7 +132,7 @@ define_import(JSContext  *context,
               const char *name)
 {
     if (!JS_DefineProperty(context, obj,
-                           name, OBJECT_TO_JSVAL(module_obj),
+                           name, JS::ObjectValue(*module_obj),
                            NULL, NULL,
                            GJS_MODULE_PROP_FLAGS & ~JSPROP_PERMANENT)) {
         gjs_debug(GJS_DEBUG_IMPORTER,
@@ -236,7 +236,7 @@ import_native_file(JSContext  *context,
     }
 
     if (!JS_DefineProperty(context, obj,
-                           name, OBJECT_TO_JSVAL(module_obj),
+                           name, JS::ObjectValue(*module_obj),
                            NULL, NULL, GJS_MODULE_PROP_FLAGS))
         goto out;
 
@@ -312,7 +312,7 @@ load_module_init(JSContext  *context,
                                in_object,
                                module_init_name,
                                &module_obj_val)) {
-            return JSVAL_TO_OBJECT(module_obj_val);
+            return &module_obj_val.toObject();
         }
     }
 
@@ -322,7 +322,7 @@ load_module_init(JSContext  *context,
         goto out;
 
     if (!JS_DefinePropertyById(context, in_object,
-                               module_init_name, OBJECT_TO_JSVAL(module_obj),
+                               module_init_name, JS::ObjectValue(*module_obj),
                                NULL, NULL,
                                GJS_MODULE_PROP_FLAGS & ~JSPROP_PERMANENT))
         goto out;
@@ -432,12 +432,12 @@ do_import(JSContext  *context,
         return false;
     }
 
-    if (!JSVAL_IS_OBJECT(search_path_val)) {
+    if (!search_path_val.isObject()) {
         gjs_throw(context, "searchPath property on importer is not an object");
         return false;
     }
 
-    search_path = JSVAL_TO_OBJECT(search_path_val);
+    search_path = &search_path_val.toObject();
 
     if (!JS_IsArrayObject(context, search_path)) {
         gjs_throw(context, "searchPath property on importer is not an array");
@@ -468,18 +468,18 @@ do_import(JSContext  *context,
     for (i = 0; i < search_path_len; ++i) {
         JS::Value elem;
 
-        elem = JSVAL_VOID;
+        elem = JS::UndefinedValue();
         if (!JS_GetElement(context, search_path, i, &elem)) {
-            /* this means there was an exception, while elem == JSVAL_VOID
+            /* this means there was an exception, while elem.isUndefined()
              * means no element found
              */
             goto out;
         }
 
-        if (JSVAL_IS_VOID(elem))
+        if (elem.isUndefined())
             continue;
 
-        if (!JSVAL_IS_STRING(elem)) {
+        if (!elem.isString()) {
             gjs_throw(context, "importer searchPath contains non-string");
             goto out;
         }
@@ -508,7 +508,7 @@ do_import(JSContext  *context,
                                module_obj,
                                name,
                                &obj_val)) {
-                if (!JSVAL_IS_VOID(obj_val) &&
+                if (!obj_val.isUndefined() &&
                     JS_DefineProperty(context, obj,
                                       name, obj_val,
                                       NULL, NULL,
@@ -649,7 +649,7 @@ importer_iterator_free(ImporterIterator *iter)
  * 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 JSVAL_NULL
+ * 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,
@@ -675,7 +675,7 @@ importer_new_enumerate(JSContext  *context,
         guint32 i;
         jsid search_path_name;
 
-        statep.set(JSVAL_NULL);
+        statep.setNull();
 
         idp.set(INT_TO_JSID(0));
 
@@ -689,12 +689,12 @@ importer_new_enumerate(JSContext  *context,
         if (!gjs_object_require_property(context, object, "importer", search_path_name, &search_path_val))
             return false;
 
-        if (!JSVAL_IS_OBJECT(search_path_val)) {
+        if (!search_path_val.isObject()) {
             gjs_throw(context, "searchPath property on importer is not an object");
             return false;
         }
 
-        search_path = JSVAL_TO_OBJECT(search_path_val);
+        search_path = &search_path_val.toObject();
 
         if (!JS_IsArrayObject(context, search_path)) {
             gjs_throw(context, "searchPath property on importer is not an array");
@@ -715,19 +715,19 @@ importer_new_enumerate(JSContext  *context,
             JS::Value elem;
             GDir *dir = NULL;
 
-            elem = JSVAL_VOID;
+            elem = JS::UndefinedValue();
             if (!JS_GetElement(context, search_path, i, &elem)) {
-                /* this means there was an exception, while elem == JSVAL_VOID
+                /* this means there was an exception, while elem.isUndefined()
                  * means no element found
                  */
                 importer_iterator_free(iter);
                 return false;
             }
 
-            if (JSVAL_IS_VOID(elem))
+            if (elem.isUndefined())
                 continue;
 
-            if (!JSVAL_IS_STRING(elem)) {
+            if (!elem.isString()) {
                 gjs_throw(context, "importer searchPath contains non-string");
                 importer_iterator_free(iter);
                 return false;
@@ -782,7 +782,7 @@ importer_new_enumerate(JSContext  *context,
             g_free(dirname);
         }
 
-        statep.set(PRIVATE_TO_JSVAL(iter));
+        statep.get().setPrivate(iter);
 
         idp.set(INT_TO_JSID(iter->elements->len));
 
@@ -792,10 +792,10 @@ importer_new_enumerate(JSContext  *context,
     case JSENUMERATE_NEXT: {
         JS::Value element_val;
 
-        if (JSVAL_IS_NULL(statep)) /* Iterating prototype */
+        if (statep.isNull()) /* Iterating prototype */
             return true;
 
-        iter = (ImporterIterator*) JSVAL_TO_PRIVATE(statep);
+        iter = (ImporterIterator*) statep.get().toPrivate();
 
         if (iter->index < iter->elements->len) {
             if (!gjs_string_from_utf8(context,
@@ -816,12 +816,12 @@ importer_new_enumerate(JSContext  *context,
     }
 
     case JSENUMERATE_DESTROY: {
-        if (!JSVAL_IS_NULL(statep)) {
-            iter = (ImporterIterator*) JSVAL_TO_PRIVATE(statep);
+        if (!statep.isNull()) {
+            iter = (ImporterIterator*) statep.get().toPrivate();
 
             importer_iterator_free(iter);
 
-            statep.set(JSVAL_NULL);
+            statep.setNull();
         }
     }
     }
@@ -1099,7 +1099,7 @@ gjs_define_importer(JSContext    *context,
                                    add_standard_search_path, false, in_object);
 
     if (!JS_DefineProperty(context, in_object,
-                           importer_name, OBJECT_TO_JSVAL(importer),
+                           importer_name, JS::ObjectValue(*importer),
                            NULL, NULL,
                            GJS_MODULE_PROP_FLAGS))
         g_error("no memory to define importer property");
@@ -1125,7 +1125,7 @@ gjs_create_root_importer(JSContext   *context,
 
     importer = gjs_get_global_slot(context, GJS_GLOBAL_SLOT_IMPORTS);
 
-    if (G_UNLIKELY (!JSVAL_IS_VOID(importer))) {
+    if (G_UNLIKELY (!importer.isUndefined())) {
         gjs_debug(GJS_DEBUG_IMPORTER,
                   "Someone else already created root importer, ignoring second request");
 
@@ -1133,10 +1133,10 @@ gjs_create_root_importer(JSContext   *context,
         return true;
     }
 
-    importer = OBJECT_TO_JSVAL(gjs_create_importer(context, "imports",
-                                                   initial_search_path,
-                                                   add_standard_search_path,
-                                                   true, NULL));
+    importer = JS::ObjectValue(*gjs_create_importer(context, "imports",
+                                                    initial_search_path,
+                                                    add_standard_search_path,
+                                                    true, NULL));
     gjs_set_global_slot(context, GJS_GLOBAL_SLOT_IMPORTS, importer);
 
     JS_EndRequest(context);
@@ -1155,7 +1155,7 @@ gjs_define_root_importer_object(JSContext        *context,
     JS_BeginRequest(context);
 
     JS::RootedValue importer (JS_GetRuntime(context),
-                              OBJECT_TO_JSVAL(root_importer));
+                              JS::ObjectValue(*root_importer));
     imports_name = gjs_context_get_const_string(context, GJS_STRING_IMPORTS);
     if (!JS_DefinePropertyById(context, in_object,
                                imports_name, importer,
@@ -1181,7 +1181,7 @@ gjs_define_root_importer(JSContext   *context,
     JS::RootedObject rooted_in_object(JS_GetRuntime(context),
                                       in_object);
     JS::RootedObject rooted_importer(JS_GetRuntime(context),
-                                     JSVAL_TO_OBJECT(importer));
+                                     &importer.toObject());
     return gjs_define_root_importer_object(context,
                                            rooted_in_object,
                                            rooted_importer);
diff --git a/gjs/jsapi-dynamic-class.cpp b/gjs/jsapi-dynamic-class.cpp
index 543919d..3cb4633 100644
--- a/gjs/jsapi-dynamic-class.cpp
+++ b/gjs/jsapi-dynamic-class.cpp
@@ -52,13 +52,13 @@ gjs_new_object_for_constructor(JSContext *context,
     JS::Value prototype;
 
     callee = JS_CALLEE(context, vp);
-    parent = JS_GetParent(JSVAL_TO_OBJECT (callee));
+    parent = JS_GetParent(&callee.toObject());
 
-    if (!gjs_object_get_property_const(context, JSVAL_TO_OBJECT(callee), GJS_STRING_PROTOTYPE, &prototype))
+    if (!gjs_object_get_property_const(context, &callee.toObject(), GJS_STRING_PROTOTYPE, &prototype))
         return NULL;
 
     return JS_NewObjectWithGivenProto(context, clasp,
-                                      JSVAL_TO_OBJECT(prototype), parent);
+                                      &prototype.toObject(), parent);
 }
 
 bool
@@ -135,16 +135,16 @@ gjs_init_class_dynamic(JSContext       *context,
     if (static_fs && !JS_DefineFunctions(context, constructor, static_fs))
         goto out;
 
-    if (!JS_DefineProperty(context, constructor, "prototype", OBJECT_TO_JSVAL(prototype),
+    if (!JS_DefineProperty(context, constructor, "prototype", JS::ObjectValue(*prototype),
                            JS_PropertyStub, JS_StrictPropertyStub, JSPROP_PERMANENT | JSPROP_READONLY))
         goto out;
-    if (!JS_DefineProperty(context, prototype, "constructor", OBJECT_TO_JSVAL(constructor),
+    if (!JS_DefineProperty(context, prototype, "constructor", JS::ObjectValue(*constructor),
                            JS_PropertyStub, JS_StrictPropertyStub, 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, OBJECT_TO_JSVAL(constructor),
+    if (!JS_DefineProperty(context, in_object, class_name, JS::ObjectValue(*constructor),
                            JS_PropertyStub, JS_StrictPropertyStub, GJS_MODULE_PROP_FLAGS))
         goto out;
 
@@ -214,7 +214,7 @@ gjs_construct_object_dynamic(JSContext      *context,
                                      constructor_name, &value))
         goto out;
 
-    constructor = JSVAL_TO_OBJECT(value);
+    constructor = &value.toObject();
     result = JS_New(context, constructor, argc, argv);
 
  out:
diff --git a/gjs/jsapi-util-array.cpp b/gjs/jsapi-util-array.cpp
index 5296f97..d3e5787 100644
--- a/gjs/jsapi-util-array.cpp
+++ b/gjs/jsapi-util-array.cpp
@@ -121,14 +121,14 @@ gjs_rooted_array_get(JSContext        *context,
 {
     GArray *garray;
 
-    g_return_val_if_fail(context != NULL, JSVAL_VOID);
-    g_return_val_if_fail(array != NULL, JSVAL_VOID);
+    g_return_val_if_fail(context != NULL, JS::UndefinedValue());
+    g_return_val_if_fail(array != NULL, JS::UndefinedValue());
 
     garray = (GArray*) array;
 
     if (i < 0 || i >= (int) garray->len) {
         gjs_throw(context, "Index %d is out of range", i);
-        return JSVAL_VOID;
+        return JS::UndefinedValue();
     }
 
     return g_array_index(garray, JS::Value, i);
diff --git a/gjs/jsapi-util-string.cpp b/gjs/jsapi-util-string.cpp
index 51eda5f..f845d15 100644
--- a/gjs/jsapi-util-string.cpp
+++ b/gjs/jsapi-util-string.cpp
@@ -39,14 +39,14 @@ gjs_string_to_utf8 (JSContext      *context,
 
     JS_BeginRequest(context);
 
-    if (!JSVAL_IS_STRING(value)) {
+    if (!value.isString()) {
         gjs_throw(context,
                   "Value is not a string, cannot convert to UTF-8");
         JS_EndRequest(context);
         return false;
     }
 
-    str = JSVAL_TO_STRING(value);
+    str = value.toString();
 
     len = JS_GetStringEncodingLength(context, str);
     if (len == (gsize)(-1)) {
@@ -100,7 +100,7 @@ gjs_string_from_utf8(JSContext  *context,
     str = JS_NewUCString(context, u16_string, u16_string_length);
 
     if (str && value_p)
-        *value_p = STRING_TO_JSVAL(str);
+        *value_p = JS::StringValue(str);
 
     JS_EndRequest(context);
     return str != NULL;
@@ -189,13 +189,13 @@ gjs_string_get_uint16_data(JSContext       *context,
 
     JS_BeginRequest(context);
 
-    if (!JSVAL_IS_STRING(value)) {
+    if (!value.isString()) {
         gjs_throw(context,
                   "Value is not a string, can't return binary data from it");
         goto out;
     }
 
-    js_data = JS_GetStringCharsAndLength(context, JSVAL_TO_STRING(value), len_p);
+    js_data = JS_GetStringCharsAndLength(context, value.toString(), len_p);
     if (js_data == NULL)
         goto out;
 
@@ -228,7 +228,7 @@ gjs_get_string_id (JSContext       *context,
     if (!JS_IdToValue(context, id, &id_val))
         return false;
 
-    if (JSVAL_IS_STRING(id_val)) {
+    if (id_val.isString()) {
         return gjs_string_to_utf8(context, id_val, name_p);
     } else {
         *name_p = NULL;
diff --git a/gjs/jsapi-util.cpp b/gjs/jsapi-util.cpp
index 01b94cc..c52c420 100644
--- a/gjs/jsapi-util.cpp
+++ b/gjs/jsapi-util.cpp
@@ -136,8 +136,8 @@ gjs_get_global_slot (JSContext     *context,
 
 /* Returns whether the object had the property; if the object did
  * not have the property, always sets an exception. Treats
- * "the property's value is JSVAL_VOID" the same as "no such property,".
- * Guarantees that *value_p is set to something, if only JSVAL_VOID,
+ * "the property's value is undefined" the same as "no such property,".
+ * Guarantees that *value_p is set to something, if only JS::UndefinedValue(),
  * even if an exception is set and false is returned.
  *
  * Requires request.
@@ -152,14 +152,14 @@ gjs_object_require_property(JSContext       *context,
     JS::Value value;
     char *name;
 
-    value = JSVAL_VOID;
+    value = JS::UndefinedValue();
     if (value_p)
         *value_p = value;
 
     if (G_UNLIKELY (!JS_GetPropertyById(context, obj, property_name, &value)))
         return false;
 
-    if (G_LIKELY (!JSVAL_IS_VOID(value))) {
+    if (G_LIKELY (!value.isUndefined())) {
         if (value_p)
             *value_p = value;
         return true;
@@ -202,10 +202,10 @@ gjs_throw_abstract_constructor_error(JSContext *context,
 
     callee = JS_CALLEE(context, vp);
 
-    if (JSVAL_IS_OBJECT(callee)) {
-        if (gjs_object_get_property_const(context, JSVAL_TO_OBJECT(callee),
+    if (callee.isObject()) {
+        if (gjs_object_get_property_const(context, &callee.toObject(),
                                           GJS_STRING_PROTOTYPE, &prototype)) {
-            proto_class = JS_GetClass(JSVAL_TO_OBJECT(prototype));
+            proto_class = JS_GetClass(&prototype.toObject());
             name = proto_class->name;
         }
     }
@@ -229,7 +229,7 @@ gjs_build_string_array(JSContext   *context,
 
     for (i = 0; i < array_length; ++i) {
         JS::Value element;
-        element = STRING_TO_JSVAL(JS_NewStringCopyZ(context, array_values[i]));
+        element = JS::StringValue(JS_NewStringCopyZ(context, array_values[i]));
         g_array_append_val(elems, element);
     }
 
@@ -255,7 +255,7 @@ gjs_define_string_array(JSContext   *context,
 
     if (array != NULL) {
         if (!JS_DefineProperty(context, in_object,
-                               array_name, OBJECT_TO_JSVAL(array),
+                               array_name, JS::ObjectValue(*array),
                                NULL, NULL, attrs))
             array = NULL;
     }
@@ -283,7 +283,7 @@ gjs_string_readable (JSContext   *context,
 
     g_string_append_c(buf, '"');
 
-    if (!gjs_string_to_utf8(context, STRING_TO_JSVAL(string), &chars)) {
+    if (!gjs_string_to_utf8(context, JS::StringValue(string), &chars)) {
         size_t i, len;
         const jschar *uchars;
 
@@ -324,8 +324,8 @@ gjs_value_debug_string(JSContext      *context,
     char *debugstr;
 
     /* Special case debug strings for strings */
-    if (JSVAL_IS_STRING(value)) {
-        return gjs_string_readable(context, JSVAL_TO_STRING(value));
+    if (value.isString()) {
+        return gjs_string_readable(context, value.toString());
     }
 
     JS_BeginRequest(context);
@@ -333,13 +333,13 @@ gjs_value_debug_string(JSContext      *context,
     str = JS_ValueToString(context, value);
 
     if (str == NULL) {
-        if (JSVAL_IS_OBJECT(value)) {
+        if (value.isObject()) {
             /* Specifically the Call object (see jsfun.c in spidermonkey)
              * does not have a toString; there may be others also.
              */
             JSClass *klass;
 
-            klass = JS_GetClass(JSVAL_TO_OBJECT(value));
+            klass = JS_GetClass(&value.toObject());
             if (klass != NULL) {
                 str = JS_NewStringCopyZ(context, klass->name);
                 JS_ClearPendingException(context);
@@ -447,7 +447,7 @@ gjs_explain_scope(JSContext  *context,
               "");
 
     global = JS_GetGlobalObject(context);
-    debugstr = gjs_value_debug_string(context, OBJECT_TO_JSVAL(global));
+    debugstr = gjs_value_debug_string(context, JS::ObjectOrNullValue(global));
     gjs_debug(GJS_DEBUG_SCOPE,
               "  Global: %p %s",
               global, debugstr);
@@ -457,7 +457,7 @@ gjs_explain_scope(JSContext  *context,
     chain = g_string_new(NULL);
     while (parent != NULL) {
         char *debug;
-        debug = gjs_value_debug_string(context, OBJECT_TO_JSVAL(parent));
+        debug = gjs_value_debug_string(context, JS::ObjectOrNullValue(parent));
 
         if (chain->len > 0)
             g_string_append(chain, ", ");
@@ -489,22 +489,22 @@ gjs_log_exception_full(JSContext *context,
 
     is_syntax = false;
 
-    if (JSVAL_IS_OBJECT(exc) &&
-        gjs_typecheck_boxed(context, JSVAL_TO_OBJECT(exc), NULL, G_TYPE_ERROR, false)) {
+    if (exc.isObject() &&
+        gjs_typecheck_boxed(context, &exc.toObject(), NULL, G_TYPE_ERROR, false)) {
         GError *gerror;
 
-        gerror = (GError*) gjs_c_struct_from_boxed(context, JSVAL_TO_OBJECT(exc));
+        gerror = (GError*) gjs_c_struct_from_boxed(context, &exc.toObject());
         utf8_exception = g_strdup_printf("GLib.Error %s: %s",
                                          g_quark_to_string(gerror->domain),
                                          gerror->message);
     } else {
-        if (JSVAL_IS_OBJECT(exc)) {
+        if (exc.isObject()) {
             JS::Value js_name;
             char *utf8_name;
 
-            if (gjs_object_get_property_const(context, JSVAL_TO_OBJECT(exc),
+            if (gjs_object_get_property_const(context, &exc.toObject(),
                                               GJS_STRING_NAME, &js_name) &&
-                JSVAL_IS_STRING(js_name) &&
+                js_name.isString() &&
                 gjs_string_to_utf8(context, js_name, &utf8_name)) {
                 is_syntax = strcmp("SyntaxError", utf8_name) == 0;
             }
@@ -512,13 +512,13 @@ gjs_log_exception_full(JSContext *context,
 
         exc_str = JS_ValueToString(context, exc);
         if (exc_str != NULL)
-            gjs_string_to_utf8(context, STRING_TO_JSVAL(exc_str), &utf8_exception);
+            gjs_string_to_utf8(context, JS::StringValue(exc_str), &utf8_exception);
         else
             utf8_exception = NULL;
     }
 
     if (message != NULL)
-        gjs_string_to_utf8(context, STRING_TO_JSVAL(message), &utf8_message);
+        gjs_string_to_utf8(context, JS::StringValue(message), &utf8_message);
     else
         utf8_message = NULL;
 
@@ -532,17 +532,17 @@ gjs_log_exception_full(JSContext *context,
         unsigned lineNumber;
         char *utf8_fileName;
 
-        gjs_object_get_property_const(context, JSVAL_TO_OBJECT(exc),
+        gjs_object_get_property_const(context, &exc.toObject(),
                                       GJS_STRING_LINE_NUMBER, &js_lineNumber);
-        gjs_object_get_property_const(context, JSVAL_TO_OBJECT(exc),
+        gjs_object_get_property_const(context, &exc.toObject(),
                                       GJS_STRING_FILENAME, &js_fileName);
 
-        if (JSVAL_IS_STRING(js_fileName))
+        if (js_fileName.isString())
             gjs_string_to_utf8(context, js_fileName, &utf8_fileName);
         else
             utf8_fileName = g_strdup("unknown");
 
-        lineNumber = JSVAL_TO_INT(js_lineNumber);
+        lineNumber = js_lineNumber.toInt32();
 
         if (utf8_message) {
             g_critical("JS ERROR: %s: %s @ %s:%u", utf8_message, utf8_exception,
@@ -556,10 +556,10 @@ gjs_log_exception_full(JSContext *context,
     } else {
         char *utf8_stack;
 
-        if (JSVAL_IS_OBJECT(exc) &&
-            gjs_object_get_property_const(context, JSVAL_TO_OBJECT(exc),
+        if (exc.isObject() &&
+            gjs_object_get_property_const(context, &exc.toObject(),
                                           GJS_STRING_STACK, &stack) &&
-            JSVAL_IS_STRING(stack))
+            stack.isString())
             gjs_string_to_utf8(context, stack, &utf8_stack);
         else
             utf8_stack = NULL;
@@ -591,7 +591,7 @@ static bool
 log_and_maybe_keep_exception(JSContext  *context,
                              bool        keep)
 {
-    JS::Value exc = JSVAL_VOID;
+    JS::Value exc = JS::UndefinedValue();
     bool retval = false;
 
     JS_BeginRequest(context);
@@ -646,33 +646,32 @@ try_to_chain_stack_trace(JSContext *src_context,
     JS_BeginRequest(src_context);
     JS_BeginRequest(dst_context);
 
-    if (!JSVAL_IS_OBJECT(src_exc))
+    if (!src_exc.isObject())
         goto out; // src_exc doesn't have a stack trace
 
     /* create a new exception in dst_context to get a stack trace */
     gjs_throw_literal(dst_context, "Chained exception");
-    if (!(JS_GetPendingException(dst_context, &chained) &&
-          JSVAL_IS_OBJECT(chained)))
+    if (!(JS_GetPendingException(dst_context, &chained) && chained.isObject()))
         goto out; // gjs_throw_literal didn't work?!
     JS_ClearPendingException(dst_context);
 
     /* get stack trace for src_exc and chained */
-    if (!(JS_GetProperty(dst_context, JSVAL_TO_OBJECT(chained),
+    if (!(JS_GetProperty(dst_context, &chained.toObject(),
                          "stack", &dst_stack) &&
-          JSVAL_IS_STRING(dst_stack)))
+          dst_stack.isString()))
         goto out; // couldn't get chained stack
-    if (!(JS_GetProperty(src_context, JSVAL_TO_OBJECT(src_exc),
+    if (!(JS_GetProperty(src_context, &src_exc.toObject(),
                          "stack", &src_stack) &&
-          JSVAL_IS_STRING(src_stack)))
+          src_stack.isString()))
         goto out; // couldn't get source stack
 
     /* add chained exception's stack trace to src_exc */
-    new_stack_str = JS_ConcatStrings
-        (dst_context, JSVAL_TO_STRING(src_stack), JSVAL_TO_STRING(dst_stack));
+    new_stack_str = JS_ConcatStrings(dst_context, src_stack.toString(),
+        dst_stack.toString());
     if (new_stack_str==NULL)
         goto out; // couldn't concatenate src and dst stacks?!
-    new_stack = STRING_TO_JSVAL(new_stack_str);
-    JS_SetProperty(dst_context, JSVAL_TO_OBJECT(src_exc), "stack", &new_stack);
+    new_stack = JS::StringValue(new_stack_str);
+    JS_SetProperty(dst_context, &src_exc.toObject(), "stack", &new_stack);
 
  out:
     JS_EndRequest(dst_context);
@@ -739,7 +738,7 @@ log_prop(JSContext  *context,
          JS::Value  *value_p,
          const char *what)
 {
-    if (JSVAL_IS_STRING(id)) {
+    if (id.isString()) {
         char *name;
 
         gjs_string_to_utf8(context, id, &name);
@@ -747,10 +746,10 @@ log_prop(JSContext  *context,
                   "prop %s: %s",
                   name, what);
         g_free(name);
-    } else if (JSVAL_IS_INT(id)) {
+    } else if (id.isInt32()) {
         gjs_debug(GJS_DEBUG_PROPS,
                   "prop %d: %s",
-                  JSVAL_TO_INT(id), what);
+                  id.toInt32(), what);
     } else {
         gjs_debug(GJS_DEBUG_PROPS,
                   "prop not-sure-what: %s",
@@ -800,19 +799,19 @@ gjs_delete_prop_verbose_stub(JSContext *context,
 const char*
 gjs_get_type_name(JS::Value value)
 {
-    if (JSVAL_IS_NULL(value)) {
+    if (value.isNull()) {
         return "null";
-    } else if (JSVAL_IS_VOID(value)) {
+    } else if (value.isUndefined()) {
         return "undefined";
-    } else if (JSVAL_IS_INT(value)) {
+    } else if (value.isInt32()) {
         return "integer";
-    } else if (JSVAL_IS_DOUBLE(value)) {
+    } else if (value.isDouble()) {
         return "double";
-    } else if (JSVAL_IS_BOOLEAN(value)) {
+    } else if (value.isBoolean()) {
         return "boolean";
-    } else if (JSVAL_IS_STRING(value)) {
+    } else if (value.isString()) {
         return "string";
-    } else if (JSVAL_IS_OBJECT(value)) {
+    } else if (value.isObject()) {
         return "object";
     } else {
         return "<unknown>";
@@ -843,8 +842,8 @@ gjs_value_to_int64(JSContext      *context,
                    const JS::Value val,
                    gint64         *result)
 {
-    if (JSVAL_IS_INT (val)) {
-        *result = JSVAL_TO_INT (val);
+    if (val.isInt32()) {
+        *result = val.toInt32();
         return true;
     } else {
         double value_double;
@@ -949,7 +948,7 @@ gjs_parse_args_valist (JSContext  *context,
         if (*fmt_iter == '?') {
             fmt_iter++;
 
-            if (JSVAL_IS_NULL (js_value)) {
+            if (js_value.isNull()) {
                 gpointer *arg = (gpointer*) arg_location;
                 *arg = NULL;
                 goto got_value;
@@ -958,20 +957,20 @@ gjs_parse_args_valist (JSContext  *context,
 
         switch (*fmt_iter) {
         case 'b': {
-            if (!JSVAL_IS_BOOLEAN(js_value)) {
+            if (!js_value.isBoolean()) {
                 arg_error_message = "Not a boolean";
             } else {
                 bool *arg = (bool*) arg_location;
-                *arg = JSVAL_TO_BOOLEAN(js_value);
+                *arg = js_value.toBoolean();
             }
         }
             break;
         case 'o': {
-            if (!JSVAL_IS_OBJECT(js_value)) {
+            if (!js_value.isObject()) {
                 arg_error_message = "Not an object";
             } else {
                 JSObject **arg = (JSObject**) arg_location;
-                *arg = JSVAL_TO_OBJECT(js_value);
+                *arg = &js_value.toObject();
             }
         }
             break;
@@ -1011,7 +1010,7 @@ gjs_parse_args_valist (JSContext  *context,
             break;
         case 'u': {
             gdouble num;
-            if (!JSVAL_IS_NUMBER(js_value) || !JS_ValueToNumber(context, js_value, &num)) {
+            if (!js_value.isNumber() || !JS_ValueToNumber(context, js_value, &num)) {
                 /* Our error message is going to be more useful */
                 JS_ClearPendingException(context);
                 arg_error_message = "Couldn't convert to unsigned integer";
@@ -1298,7 +1297,7 @@ gjs_eval_with_scope(JSContext    *context,
                     JS::Value    *retval_p)
 {
     int start_line_number = 1;
-    JS::Value retval = JSVAL_VOID;
+    JS::Value retval = JS::UndefinedValue();
     JSAutoRequest ar(context);
 
     if (script_len < 0)
diff --git a/gjs/jsapi-util.h b/gjs/jsapi-util.h
index e22a139..b68d6fc 100644
--- a/gjs/jsapi-util.h
+++ b/gjs/jsapi-util.h
@@ -170,8 +170,8 @@ JS::Value gjs_##cname##_create_proto(JSContext *context, JSObject *module, const
     JSObject *global = gjs_get_import_global(context); \
     jsid class_name = gjs_intern_string_to_id(context, gjs_##cname##_class.name); \
     if (!JS_GetPropertyById(context, global, class_name, &rval))                       \
-        return JSVAL_NULL; \
-    if (JSVAL_IS_VOID(rval)) { \
+        return JS::NullValue(); \
+    if (rval.isUndefined()) { \
         JS::Value value; \
         JSObject *prototype = JS_InitClass(context, global,     \
                                  parent, \
@@ -183,19 +183,19 @@ JS::Value gjs_##cname##_create_proto(JSContext *context, JSObject *module, const
                                  NULL, \
                                  NULL); \
         if (prototype == NULL) { \
-            return JSVAL_NULL; \
+            return JS::NullValue(); \
         } \
         if (!gjs_object_require_property( \
                 context, global, NULL, \
                 class_name, &rval)) { \
-            return JSVAL_NULL; \
+            return JS::NullValue(); \
         } \
         if (!JS_DefineProperty(context, module, proto_name, \
                                rval, NULL, NULL, GJS_MODULE_PROP_FLAGS)) \
-            return JSVAL_NULL; \
+            return JS::NullValue(); \
         if (gtype != G_TYPE_NONE) { \
-            value = OBJECT_TO_JSVAL(gjs_gtype_create_gtype_wrapper(context, gtype)); \
-            JS_DefineProperty(context, JSVAL_TO_OBJECT(rval), "$gtype", value, \
+            value = JS::ObjectOrNullValue(gjs_gtype_create_gtype_wrapper(context, gtype)); \
+            JS_DefineProperty(context, &rval.toObject(), "$gtype", value, \
                               NULL, NULL, JSPROP_PERMANENT);            \
         } \
     } \
diff --git a/gjs/runtime.cpp b/gjs/runtime.cpp
index 980cb12..de2e779 100644
--- a/gjs/runtime.cpp
+++ b/gjs/runtime.cpp
@@ -53,7 +53,7 @@ gjs_locale_to_upper_case (JSContext *context,
     char *utf8 = NULL;
     char *upper_case_utf8 = NULL;
 
-    if (!gjs_string_to_utf8(context, STRING_TO_JSVAL(src), &utf8))
+    if (!gjs_string_to_utf8(context, JS::StringValue(src), &utf8))
         goto out;
 
     upper_case_utf8 = g_utf8_strup (utf8, -1);
@@ -79,7 +79,7 @@ gjs_locale_to_lower_case (JSContext *context,
     char *utf8 = NULL;
     char *lower_case_utf8 = NULL;
 
-    if (!gjs_string_to_utf8(context, STRING_TO_JSVAL(src), &utf8))
+    if (!gjs_string_to_utf8(context, JS::StringValue(src), &utf8))
         goto out;
 
     lower_case_utf8 = g_utf8_strdown (utf8, -1);
@@ -104,14 +104,12 @@ gjs_locale_compare (JSContext *context,
 {
     bool success = false;
     char *utf8_1 = NULL, *utf8_2 = NULL;
-    int result;
 
-    if (!gjs_string_to_utf8(context, STRING_TO_JSVAL(src_1), &utf8_1) ||
-        !gjs_string_to_utf8(context, STRING_TO_JSVAL(src_2), &utf8_2))
+    if (!gjs_string_to_utf8(context, JS::StringValue(src_1), &utf8_1) ||
+        !gjs_string_to_utf8(context, JS::StringValue(src_2), &utf8_2))
         goto out;
 
-    result = g_utf8_collate (utf8_1, utf8_2);
-    retval.set(INT_TO_JSVAL(result));
+    retval.setInt32(g_utf8_collate(utf8_1, utf8_2));
 
     success = true;
 
diff --git a/modules/cairo-context.cpp b/modules/cairo-context.cpp
index a02b81d..4cb4e8f 100644
--- a/modules/cairo-context.cpp
+++ b/modules/cairo-context.cpp
@@ -37,7 +37,7 @@ mname##_func(JSContext *context,                    \
               JS::Value *vp)                        \
 {                                                   \
     JS::CallArgs argv = JS::CallArgsFromVp (argc, vp);             \
-    JSObject *obj = JSVAL_TO_OBJECT(argv.thisv());                  \
+    JSObject *obj = argv.thisv().toObjectOrNull();  \
     cairo_t *cr;
 
 #define _GJS_CAIRO_CONTEXT_DEFINE_FUNC_END                               \
@@ -54,7 +54,7 @@ mname##_func(JSContext *context,                    \
 _GJS_CAIRO_CONTEXT_DEFINE_FUNC_BEGIN(method)                               \
     cr = gjs_cairo_context_get_context(context, obj);                      \
     cfunc(cr);                                                             \
-    argv.rval().set(JSVAL_VOID);                                           \
+    argv.rval().setUndefined();                                            \
 _GJS_CAIRO_CONTEXT_DEFINE_FUNC_END
 
 #define _GJS_CAIRO_CONTEXT_DEFINE_FUNC0I(method, cfunc)                    \
@@ -72,7 +72,7 @@ _GJS_CAIRO_CONTEXT_DEFINE_FUNC_BEGIN(method)                               \
    _GJS_CAIRO_CONTEXT_CHECK_NO_ARGS(method)                                \
     cr = gjs_cairo_context_get_context(context, obj);                      \
     ret = cfunc(cr);                                                       \
-    argv.rval().set(BOOLEAN_TO_JSVAL(ret));                                \
+    argv.rval().setBoolean(ret);                                           \
 _GJS_CAIRO_CONTEXT_DEFINE_FUNC_END
 
 #define _GJS_CAIRO_CONTEXT_DEFINE_FUNC2FFAFF(method, cfunc, n1, n2)        \
@@ -92,7 +92,7 @@ _GJS_CAIRO_CONTEXT_DEFINE_FUNC_BEGIN(method)                               \
       if (!JS_SetElement(context, array, 0, &r)) return false;             \
       if (!JS_NewNumberValue(context, arg2, &r)) return false;             \
       if (!JS_SetElement(context, array, 1, &r)) return false;             \
-      argv.rval().set(OBJECT_TO_JSVAL(array));                    \
+      argv.rval().setObject(*array);                                       \
     }                                                                      \
 _GJS_CAIRO_CONTEXT_DEFINE_FUNC_END
 
@@ -111,7 +111,7 @@ _GJS_CAIRO_CONTEXT_DEFINE_FUNC_BEGIN(method)                               \
       if (!JS_SetElement(context, array, 0, &r)) return false;             \
       if (!JS_NewNumberValue(context, arg2, &r)) return false;             \
       if (!JS_SetElement(context, array, 1, &r)) return false;             \
-      argv.rval().set(OBJECT_TO_JSVAL(array));                    \
+      argv.rval().setObject(*array);                                       \
     }                                                                      \
 _GJS_CAIRO_CONTEXT_DEFINE_FUNC_END
 
@@ -134,7 +134,7 @@ _GJS_CAIRO_CONTEXT_DEFINE_FUNC_BEGIN(method)                               \
       if (!JS_SetElement(context, array, 2, &r)) return false;             \
       if (!JS_NewNumberValue(context, arg4, &r)) return false;             \
       if (!JS_SetElement(context, array, 3, &r)) return false;             \
-      argv.rval().set(OBJECT_TO_JSVAL(array));                    \
+      argv.rval().setObject(*array);                                       \
     }                                                                      \
 _GJS_CAIRO_CONTEXT_DEFINE_FUNC_END
 
@@ -158,7 +158,7 @@ _GJS_CAIRO_CONTEXT_DEFINE_FUNC_BEGIN(method)                               \
         return false;                                                      \
     cr = gjs_cairo_context_get_context(context, obj);                      \
     cfunc(cr, arg1);                                                       \
-    argv.rval().set(JSVAL_VOID);                                  \
+    argv.rval().setUndefined();                                            \
 _GJS_CAIRO_CONTEXT_DEFINE_FUNC_END
 
 #define _GJS_CAIRO_CONTEXT_DEFINE_FUNC2(method, cfunc, fmt, t1, n1, t2, n2) \
@@ -170,7 +170,7 @@ _GJS_CAIRO_CONTEXT_DEFINE_FUNC_BEGIN(method)                               \
         return false;                                                      \
     cr = gjs_cairo_context_get_context(context, obj);                      \
     cfunc(cr, arg1, arg2);                                                 \
-    argv.rval().set(JSVAL_VOID);                                  \
+    argv.rval().setUndefined();                                            \
 _GJS_CAIRO_CONTEXT_DEFINE_FUNC_END
 
 #define _GJS_CAIRO_CONTEXT_DEFINE_FUNC2B(method, cfunc, fmt, t1, n1, t2, n2) \
@@ -183,7 +183,7 @@ _GJS_CAIRO_CONTEXT_DEFINE_FUNC_BEGIN(method)                               \
         return false;                                                      \
     cr = gjs_cairo_context_get_context(context, obj);                      \
     ret = cfunc(cr, arg1, arg2);                                           \
-    argv.rval().set(BOOLEAN_TO_JSVAL(ret));                       \
+    argv.rval().setBoolean(ret);                                           \
 _GJS_CAIRO_CONTEXT_DEFINE_FUNC_END
 
 #define _GJS_CAIRO_CONTEXT_DEFINE_FUNC3(method, cfunc, fmt, t1, n1, t2, n2, t3, n3) \
@@ -196,7 +196,7 @@ _GJS_CAIRO_CONTEXT_DEFINE_FUNC_BEGIN(method)                               \
         return false;                                                      \
     cr = gjs_cairo_context_get_context(context, obj);                      \
     cfunc(cr, arg1, arg2, arg3);                                           \
-    argv.rval().set(JSVAL_VOID);                                  \
+    argv.rval().setUndefined();                                            \
 _GJS_CAIRO_CONTEXT_DEFINE_FUNC_END
 
 #define _GJS_CAIRO_CONTEXT_DEFINE_FUNC4(method, cfunc, fmt, t1, n1, t2, n2, t3, n3, t4, n4) \
@@ -225,7 +225,7 @@ _GJS_CAIRO_CONTEXT_DEFINE_FUNC_BEGIN(method)                               \
         return false;                                                      \
     cr = gjs_cairo_context_get_context(context, obj);                      \
     cfunc(cr, arg1, arg2, arg3, arg4, arg5);                               \
-    argv.rval().set(JSVAL_VOID);                                  \
+    argv.rval().setUndefined();                                            \
 _GJS_CAIRO_CONTEXT_DEFINE_FUNC_END
 
 #define _GJS_CAIRO_CONTEXT_DEFINE_FUNC6(method, cfunc, fmt, t1, n1, t2, n2, t3, n3, t4, n4, t5, n5, t6, n6) \
@@ -242,7 +242,7 @@ _GJS_CAIRO_CONTEXT_DEFINE_FUNC_BEGIN(method)                               \
         return false;                                                      \
     cr = gjs_cairo_context_get_context(context, obj);                      \
     cfunc(cr, arg1, arg2, arg3, arg4, arg5, arg6);                         \
-    argv.rval().set(JSVAL_VOID);                                  \
+    argv.rval().setUndefined();                                            \
 _GJS_CAIRO_CONTEXT_DEFINE_FUNC_END
 
 typedef struct {
@@ -410,7 +410,7 @@ dispose_func(JSContext *context,
              JS::Value *vp)
 {
     JS::CallReceiver rec = JS::CallReceiverFromVp(vp);
-    JSObject *obj = JSVAL_TO_OBJECT(rec.thisv());
+    JSObject *obj = rec.thisv().toObjectOrNull();
 
     GjsCairoContext *priv;
 
@@ -419,7 +419,7 @@ dispose_func(JSContext *context,
         cairo_destroy(priv->cr);
         priv->cr = NULL;
     }
-    rec.rval().set(JSVAL_VOID);
+    rec.rval().setUndefined();
     return true;
 }
 
@@ -429,7 +429,7 @@ appendPath_func(JSContext *context,
                 JS::Value *vp)
 {
     JS::CallArgs argv = JS::CallArgsFromVp (argc, vp);
-    JSObject *obj = JSVAL_TO_OBJECT(argv.thisv());
+    JSObject *obj = argv.thisv().toObjectOrNull();
 
     JSObject *path_wrapper;
     cairo_path_t *path;
@@ -447,7 +447,7 @@ appendPath_func(JSContext *context,
 
     cr = gjs_cairo_context_get_context(context, obj);
     cairo_append_path(cr, path);
-    argv.rval().set(JSVAL_VOID);
+    argv.rval().setUndefined();
     return true;
 }
 
@@ -457,7 +457,7 @@ copyPath_func(JSContext *context,
               JS::Value *vp)
 {
     JS::CallArgs argv = JS::CallArgsFromVp (argc, vp);
-    JSObject *obj = JSVAL_TO_OBJECT(argv.thisv());
+    JSObject *obj = argv.thisv().toObjectOrNull();
 
     cairo_path_t *path;
     cairo_t *cr;
@@ -467,8 +467,7 @@ copyPath_func(JSContext *context,
 
     cr = gjs_cairo_context_get_context(context, obj);
     path = cairo_copy_path(cr);
-    argv.rval().set(
-                OBJECT_TO_JSVAL(gjs_cairo_path_from_path(context, path)));
+    argv.rval().setObjectOrNull(gjs_cairo_path_from_path(context, path));
     return true;
 }
 
@@ -478,7 +477,7 @@ copyPathFlat_func(JSContext *context,
                   JS::Value *vp)
 {
     JS::CallArgs argv = JS::CallArgsFromVp (argc, vp);
-    JSObject *obj = JSVAL_TO_OBJECT(argv.thisv());
+    JSObject *obj = argv.thisv().toObjectOrNull();
 
     cairo_path_t *path;
     cairo_t *cr;
@@ -488,7 +487,7 @@ copyPathFlat_func(JSContext *context,
 
     cr = gjs_cairo_context_get_context(context, obj);
     path = cairo_copy_path_flat(cr);
-    argv.rval().set(OBJECT_TO_JSVAL(gjs_cairo_path_from_path(context, path)));
+    argv.rval().setObjectOrNull(gjs_cairo_path_from_path(context, path));
     return true;
 }
 
@@ -498,7 +497,7 @@ mask_func(JSContext *context,
           JS::Value *vp)
 {
     JS::CallArgs argv = JS::CallArgsFromVp (argc, vp);
-    JSObject *obj = JSVAL_TO_OBJECT(argv.thisv());
+    JSObject *obj = argv.thisv().toObjectOrNull();
 
     JSObject *pattern_wrapper;
     cairo_pattern_t *pattern;
@@ -520,7 +519,7 @@ mask_func(JSContext *context,
     if (!gjs_cairo_check_status(context, cairo_status(cr), "context"))
         return false;
 
-    argv.rval().set(JSVAL_VOID);
+    argv.rval().setUndefined();
     return true;
 }
 
@@ -530,7 +529,7 @@ maskSurface_func(JSContext *context,
                  JS::Value *vp)
 {
     JS::CallArgs argv = JS::CallArgsFromVp (argc, vp);
-    JSObject *obj = JSVAL_TO_OBJECT(argv.thisv());
+    JSObject *obj = argv.thisv().toObjectOrNull();
 
     JSObject *surface_wrapper;
     double x, y;
@@ -556,7 +555,7 @@ maskSurface_func(JSContext *context,
     if (!gjs_cairo_check_status(context, cairo_status(cr), "context"))
         return false;
 
-    argv.rval().set(JSVAL_VOID);
+    argv.rval().setUndefined();
     return true;
 }
 
@@ -566,7 +565,7 @@ setDash_func(JSContext *context,
              JS::Value *vp)
 {
     JS::CallArgs argv = JS::CallArgsFromVp (argc, vp);
-    JSObject *obj = JSVAL_TO_OBJECT(argv.thisv());
+    JSObject *obj = argv.thisv().toObjectOrNull();
 
     guint i;
     cairo_t *cr;
@@ -597,11 +596,11 @@ setDash_func(JSContext *context,
         JS::Value elem;
         double b;
 
-        elem = JSVAL_VOID;
+        elem = JS::UndefinedValue();
         if (!JS_GetElement(context, dashes, i, &elem)) {
             goto out;
         }
-        if (JSVAL_IS_VOID(elem))
+        if (elem.isUndefined())
             continue;
 
         if (!JS_ValueToNumber(context, elem, &b))
@@ -616,7 +615,7 @@ setDash_func(JSContext *context,
 
     cr = gjs_cairo_context_get_context(context, obj);
     cairo_set_dash(cr, (double*)dashes_c->data, dashes_c->len, offset);
-    argv.rval().set(JSVAL_VOID);
+    argv.rval().setUndefined();
     retval = true;
  out:
     if (dashes_c != NULL)
@@ -631,7 +630,7 @@ setSource_func(JSContext *context,
                JS::Value *vp)
 {
     JS::CallArgs argv = JS::CallArgsFromVp (argc, vp);
-    JSObject *obj = JSVAL_TO_OBJECT(argv.thisv());
+    JSObject *obj = argv.thisv().toObjectOrNull();
 
     JSObject *pattern_wrapper;
     cairo_pattern_t *pattern;
@@ -654,7 +653,7 @@ setSource_func(JSContext *context,
     if (!gjs_cairo_check_status(context, cairo_status(cr), "context"))
         return false;
 
-    argv.rval().set(JSVAL_VOID);
+    argv.rval().setUndefined();
 
     return true;
 }
@@ -665,7 +664,7 @@ setSourceSurface_func(JSContext *context,
                       JS::Value *vp)
 {
     JS::CallArgs argv = JS::CallArgsFromVp (argc, vp);
-    JSObject *obj = JSVAL_TO_OBJECT(argv.thisv());
+    JSObject *obj = argv.thisv().toObjectOrNull();
 
     JSObject *surface_wrapper;
     double x, y;
@@ -691,7 +690,7 @@ setSourceSurface_func(JSContext *context,
     if (!gjs_cairo_check_status(context, cairo_status(cr), "context"))
         return false;
 
-    argv.rval().set(JSVAL_VOID);
+    argv.rval().setUndefined();
 
     return true;
 }
@@ -702,7 +701,7 @@ showText_func(JSContext *context,
               JS::Value *vp)
 {
     JS::CallArgs argv = JS::CallArgsFromVp (argc, vp);
-    JSObject *obj = JSVAL_TO_OBJECT(argv.thisv());
+    JSObject *obj = argv.thisv().toObjectOrNull();
 
     char *utf8;
     cairo_t *cr;
@@ -719,7 +718,7 @@ showText_func(JSContext *context,
     if (!gjs_cairo_check_status(context, cairo_status(cr), "context"))
         return false;
 
-    argv.rval().set(JSVAL_VOID);
+    argv.rval().setUndefined();
 
     return true;
 }
@@ -730,7 +729,7 @@ selectFontFace_func(JSContext *context,
                     JS::Value *vp)
 {
     JS::CallArgs argv = JS::CallArgsFromVp (argc, vp);
-    JSObject *obj = JSVAL_TO_OBJECT(argv.thisv());
+    JSObject *obj = argv.thisv().toObjectOrNull();
 
     char *family;
     cairo_font_slant_t slant;
@@ -750,7 +749,7 @@ selectFontFace_func(JSContext *context,
 
     if (!gjs_cairo_check_status(context, cairo_status(cr), "context"))
         return false;
-    argv.rval().set(JSVAL_VOID);
+    argv.rval().setUndefined();
 
     return true;
 }
@@ -761,7 +760,7 @@ popGroup_func(JSContext *context,
               JS::Value *vp)
 {
     JS::CallReceiver rec = JS::CallReceiverFromVp(vp);
-    JSObject *obj = JSVAL_TO_OBJECT(rec.thisv());
+    JSObject *obj = rec.thisv().toObjectOrNull();
 
     cairo_t *cr;
     cairo_pattern_t *pattern;
@@ -784,7 +783,7 @@ popGroup_func(JSContext *context,
         return false;
     }
 
-    rec.rval().set(OBJECT_TO_JSVAL(pattern_wrapper));
+    rec.rval().setObject(*pattern_wrapper);
 
     return true;
 }
@@ -794,7 +793,7 @@ getSource_func(JSContext *context,
                JS::Value *vp)
 {
     JS::CallReceiver rec = JS::CallReceiverFromVp(vp);
-    JSObject *obj = JSVAL_TO_OBJECT(rec.thisv());
+    JSObject *obj = rec.thisv().toObjectOrNull();
 
     cairo_t *cr;
     cairo_pattern_t *pattern;
@@ -817,7 +816,7 @@ getSource_func(JSContext *context,
         return false;
     }
 
-    rec.rval().set(OBJECT_TO_JSVAL(pattern_wrapper));
+    rec.rval().setObject(*pattern_wrapper);
 
     return true;
 }
@@ -828,7 +827,7 @@ getTarget_func(JSContext *context,
                JS::Value *vp)
 {
     JS::CallReceiver rec = JS::CallReceiverFromVp(vp);
-    JSObject *obj = JSVAL_TO_OBJECT(rec.thisv());
+    JSObject *obj = rec.thisv().toObjectOrNull();
 
     cairo_t *cr;
     cairo_surface_t *surface;
@@ -851,7 +850,7 @@ getTarget_func(JSContext *context,
         return false;
     }
 
-    rec.rval().set(OBJECT_TO_JSVAL(surface_wrapper));
+    rec.rval().setObject(*surface_wrapper);
 
     return true;
 }
@@ -862,7 +861,7 @@ getGroupTarget_func(JSContext *context,
                     JS::Value *vp)
 {
     JS::CallReceiver rec = JS::CallReceiverFromVp(vp);
-    JSObject *obj = JSVAL_TO_OBJECT(rec.thisv());
+    JSObject *obj = rec.thisv().toObjectOrNull();
 
     cairo_t *cr;
     cairo_surface_t *surface;
@@ -885,7 +884,7 @@ getGroupTarget_func(JSContext *context,
         return false;
     }
 
-    rec.rval().set(OBJECT_TO_JSVAL(surface_wrapper));
+    rec.rval().setObject(*surface_wrapper);
 
     return true;
 }
@@ -1031,7 +1030,7 @@ context_to_g_argument(JSContext      *context,
     JSObject *obj;
     cairo_t *cr;
 
-    obj = JSVAL_TO_OBJECT(value);
+    obj = value.toObjectOrNull();
     cr = gjs_cairo_context_get_context(context, obj);
     if (!cr)
         return false;
@@ -1053,7 +1052,7 @@ context_from_g_argument(JSContext  *context,
     if (!obj)
         return false;
 
-    *value_p = OBJECT_TO_JSVAL(obj);
+    *value_p = JS::ObjectValue(*obj);
     return true;
 }
 
diff --git a/modules/cairo-gradient.cpp b/modules/cairo-gradient.cpp
index 508cdeb..a4e81c6 100644
--- a/modules/cairo-gradient.cpp
+++ b/modules/cairo-gradient.cpp
@@ -49,7 +49,7 @@ addColorStopRGB_func(JSContext *context,
                      JS::Value *vp)
 {
     JS::CallArgs argv = JS::CallArgsFromVp (argc, vp);
-    JSObject *obj = JSVAL_TO_OBJECT(argv.thisv());
+    JSObject *obj = argv.thisv().toObjectOrNull();
 
     double offset, red, green, blue;
     cairo_pattern_t *pattern;
@@ -68,7 +68,7 @@ addColorStopRGB_func(JSContext *context,
     if (!gjs_cairo_check_status(context, cairo_pattern_status(pattern), "pattern"))
         return false;
 
-    argv.rval().set(JSVAL_VOID);
+    argv.rval().setUndefined();
     return true;
 }
 
@@ -78,7 +78,7 @@ addColorStopRGBA_func(JSContext *context,
                       JS::Value *vp)
 {
     JS::CallArgs argv = JS::CallArgsFromVp (argc, vp);
-    JSObject *obj = JSVAL_TO_OBJECT(argv.thisv());
+    JSObject *obj = argv.thisv().toObjectOrNull();
 
     double offset, red, green, blue, alpha;
     cairo_pattern_t *pattern;
@@ -97,7 +97,7 @@ addColorStopRGBA_func(JSContext *context,
     if (!gjs_cairo_check_status(context, cairo_pattern_status(pattern), "pattern"))
         return false;
 
-    argv.rval().set(JSVAL_VOID);
+    argv.rval().setUndefined();
     return true;
 }
 
diff --git a/modules/cairo-region.cpp b/modules/cairo-region.cpp
index 1085bc1..f264039 100644
--- a/modules/cairo-region.cpp
+++ b/modules/cairo-region.cpp
@@ -55,7 +55,7 @@ fill_rectangle(JSContext *context, JSObject *obj,
 
 #define PRELUDE                                                 \
     JS::CallArgs argv = JS::CallArgsFromVp (argc, vp);          \
-    JSObject *obj = JSVAL_TO_OBJECT(argv.thisv());              \
+    JSObject *obj = argv.thisv().toObjectOrNull();              \
     cairo_region_t *this_region = get_region(context, obj);
 
 #define RETURN_STATUS                                           \
@@ -78,7 +78,7 @@ fill_rectangle(JSContext *context, JSObject *obj,
         other_region = get_region(context, other_obj);          \
                                                                 \
         cairo_region_##method(this_region, other_region);       \
-            argv.rval().set(JSVAL_VOID);               \
+            argv.rval().setUndefined();                         \
             RETURN_STATUS;                                      \
     }
 
@@ -99,7 +99,7 @@ fill_rectangle(JSContext *context, JSObject *obj,
             return false;                                       \
                                                                 \
         cairo_region_##method##_rectangle(this_region, &rect);  \
-            argv.rval().set(JSVAL_VOID);               \
+            argv.rval().setUndefined();                         \
             RETURN_STATUS;                                      \
     }
 
@@ -149,16 +149,16 @@ make_rectangle(JSContext *context,
     JSObject *rect_obj = JS_NewObject(context, NULL, NULL, NULL);
     JS::Value val;
 
-    val = INT_TO_JSVAL(rect->x);
+    val = JS::Int32Value(rect->x);
     JS_SetProperty(context, rect_obj, "x", &val);
 
-    val = INT_TO_JSVAL(rect->y);
+    val = JS::Int32Value(rect->y);
     JS_SetProperty(context, rect_obj, "y", &val);
 
-    val = INT_TO_JSVAL(rect->width);
+    val = JS::Int32Value(rect->width);
     JS_SetProperty(context, rect_obj, "width", &val);
 
-    val = INT_TO_JSVAL(rect->height);
+    val = JS::Int32Value(rect->height);
     JS_SetProperty(context, rect_obj, "height", &val);
 
     return rect_obj;
@@ -171,14 +171,12 @@ num_rectangles_func(JSContext *context,
 {
     PRELUDE;
     int n_rects;
-    JS::Value retval;
 
     if (!gjs_parse_call_args(context, "num_rectangles", "", argv))
         return false;
 
     n_rects = cairo_region_num_rectangles(this_region);
-    retval = INT_TO_JSVAL(n_rects);
-    argv.rval().set(retval);
+    argv.rval().setInt32(n_rects);
     RETURN_STATUS;
 }
 
@@ -191,7 +189,6 @@ get_rectangle_func(JSContext *context,
     int i;
     JSObject *rect_obj;
     cairo_rectangle_int_t rect;
-    JS::Value retval;
 
     if (!gjs_parse_call_args(context, "get_rectangle", "i", argv, "rect", &i))
         return false;
@@ -199,8 +196,7 @@ get_rectangle_func(JSContext *context,
     cairo_region_get_rectangle(this_region, i, &rect);
     rect_obj = make_rectangle(context, &rect);
 
-    retval = OBJECT_TO_JSVAL(rect_obj);
-    argv.rval().set(retval);
+    argv.rval().setObjectOrNull(rect_obj);
     RETURN_STATUS;
 }
 
@@ -301,7 +297,7 @@ region_to_g_argument(JSContext      *context,
     JSObject *obj;
     cairo_region_t *region;
 
-    obj = JSVAL_TO_OBJECT(value);
+    obj = &value.toObject();
     region = get_region(context, obj);
     if (!region)
         return false;
@@ -323,7 +319,7 @@ region_from_g_argument(JSContext  *context,
     if (!obj)
         return false;
 
-    *value_p = OBJECT_TO_JSVAL(obj);
+    *value_p = JS::ObjectValue(*obj);
     return true;
 }
 
diff --git a/modules/cairo-surface-pattern.cpp b/modules/cairo-surface-pattern.cpp
index c379088..4598e5a 100644
--- a/modules/cairo-surface-pattern.cpp
+++ b/modules/cairo-surface-pattern.cpp
@@ -80,7 +80,7 @@ setExtend_func(JSContext *context,
                JS::Value *vp)
 {
     JS::CallArgs argv = JS::CallArgsFromVp (argc, vp);
-    JSObject *obj = JSVAL_TO_OBJECT(argv.thisv());
+    JSObject *obj = argv.thisv().toObjectOrNull();
 
     cairo_extend_t extend;
     cairo_pattern_t *pattern;
@@ -95,7 +95,7 @@ setExtend_func(JSContext *context,
     if (!gjs_cairo_check_status(context, cairo_pattern_status(pattern), "pattern"))
         return false;
 
-    argv.rval().set(JSVAL_VOID);
+    argv.rval().setUndefined();
     return true;
 }
 
@@ -105,7 +105,7 @@ getExtend_func(JSContext *context,
                JS::Value *vp)
 {
     JS::CallReceiver rec = JS::CallReceiverFromVp(vp);
-    JSObject *obj = JSVAL_TO_OBJECT(rec.thisv());
+    JSObject *obj = rec.thisv().toObjectOrNull();
 
     cairo_extend_t extend;
     cairo_pattern_t *pattern;
@@ -132,7 +132,7 @@ setFilter_func(JSContext *context,
                JS::Value *vp)
 {
     JS::CallArgs argv = JS::CallArgsFromVp (argc, vp);
-    JSObject *obj = JSVAL_TO_OBJECT(argv.thisv());
+    JSObject *obj = argv.thisv().toObjectOrNull();
 
     cairo_filter_t filter;
     cairo_pattern_t *pattern;
@@ -147,7 +147,7 @@ setFilter_func(JSContext *context,
     if (!gjs_cairo_check_status(context, cairo_pattern_status(pattern), "pattern"))
         return false;
 
-    argv.rval().set(JSVAL_VOID);
+    argv.rval().setUndefined();
     return true;
 }
 
@@ -157,7 +157,7 @@ getFilter_func(JSContext *context,
                JS::Value *vp)
 {
     JS::CallReceiver rec = JS::CallReceiverFromVp(vp);
-    JSObject *obj = JSVAL_TO_OBJECT(rec.thisv());
+    JSObject *obj = rec.thisv().toObjectOrNull();
 
     cairo_filter_t filter;
     cairo_pattern_t *pattern;
diff --git a/modules/cairo-surface.cpp b/modules/cairo-surface.cpp
index bc00135..82848a0 100644
--- a/modules/cairo-surface.cpp
+++ b/modules/cairo-surface.cpp
@@ -63,7 +63,7 @@ writeToPNG_func(JSContext *context,
                 JS::Value *vp)
 {
     JS::CallArgs argv = JS::CallArgsFromVp (argc, vp);
-    JSObject *obj = JSVAL_TO_OBJECT(argv.thisv());
+    JSObject *obj = argv.thisv().toObjectOrNull();
 
     char *filename;
     cairo_surface_t *surface;
@@ -82,7 +82,7 @@ writeToPNG_func(JSContext *context,
     if (!gjs_cairo_check_status(context, cairo_surface_status(surface),
                                 "surface"))
         return false;
-    argv.rval().set(JSVAL_VOID);
+    argv.rval().setUndefined();
     return true;
 }
 
@@ -92,7 +92,7 @@ getType_func(JSContext *context,
              JS::Value *vp)
 {
     JS::CallReceiver rec = JS::CallReceiverFromVp(vp);
-    JSObject *obj = JSVAL_TO_OBJECT(rec.thisv());
+    JSObject *obj = rec.thisv().toObjectOrNull();
 
     cairo_surface_t *surface;
     cairo_surface_type_t type;
@@ -260,7 +260,7 @@ surface_to_g_argument(JSContext      *context,
     JSObject *obj;
     cairo_surface_t *s;
 
-    obj = JSVAL_TO_OBJECT(value);
+    obj = &value.toObject();
     s = gjs_cairo_surface_get_surface(context, obj);
     if (!s)
         return false;
@@ -282,7 +282,7 @@ surface_from_g_argument(JSContext  *context,
     if (!obj)
         return false;
 
-    *value_p = OBJECT_TO_JSVAL(obj);
+    *value_p = JS::ObjectValue(*obj);
     return true;
 }
 
diff --git a/modules/cairo.cpp b/modules/cairo.cpp
index 42de183..1a840c4 100644
--- a/modules/cairo.cpp
+++ b/modules/cairo.cpp
@@ -68,80 +68,80 @@ gjs_js_define_cairo_stuff(JSContext *context,
 
     obj = gjs_cairo_region_create_proto(context, module,
                                         "Region", NULL);
-    if (JSVAL_IS_NULL(obj))
+    if (obj.isNull())
         return false;
     gjs_cairo_region_init(context);
 
     obj = gjs_cairo_context_create_proto(context, module,
                                          "Context", NULL);
-    if (JSVAL_IS_NULL(obj))
+    if (obj.isNull())
         return false;
     gjs_cairo_context_init(context);
     gjs_cairo_surface_init(context);
 
     obj = gjs_cairo_surface_create_proto(context, module,
                                          "Surface", NULL);
-    if (JSVAL_IS_NULL(obj))
+    if (obj.isNull())
         return false;
-    surface_proto = JSVAL_TO_OBJECT(obj);
+    surface_proto = &obj.toObject();
 
     obj = gjs_cairo_image_surface_create_proto(context, module,
                                                "ImageSurface", surface_proto);
-    if (JSVAL_IS_NULL(obj))
+    if (obj.isNull())
         return false;
-    gjs_cairo_image_surface_init(context, JSVAL_TO_OBJECT(obj));
+    gjs_cairo_image_surface_init(context, &obj.toObject());
 
 #if CAIRO_HAS_PS_SURFACE
     obj = gjs_cairo_ps_surface_create_proto(context, module,
                                             "PSSurface", surface_proto);
-    if (JSVAL_IS_NULL(obj))
+    if (obj.isNull())
         return false;
 #endif
 
 #if CAIRO_HAS_PDF_SURFACE
     obj = gjs_cairo_pdf_surface_create_proto(context, module,
                                              "PDFSurface", surface_proto);
-    if (JSVAL_IS_NULL(obj))
+    if (obj.isNull())
         return false;
 #endif
 
 #if CAIRO_HAS_SVG_SURFACE
     obj = gjs_cairo_svg_surface_create_proto(context, module,
                                              "SVGSurface", surface_proto);
-    if (JSVAL_IS_NULL(obj))
+    if (obj.isNull())
         return false;
 #endif
 
     obj = gjs_cairo_pattern_create_proto(context, module,
                                          "Pattern", NULL);
-    if (JSVAL_IS_NULL(obj))
+    if (obj.isNull())
         return false;
-    pattern_proto = JSVAL_TO_OBJECT(obj);
+    pattern_proto = &obj.toObject();
 
     obj = gjs_cairo_gradient_create_proto(context, module,
                                          "Gradient", pattern_proto);
-    if (JSVAL_IS_NULL(obj))
+    if (obj.isNull())
         return false;
-    gradient_proto = JSVAL_TO_OBJECT(obj);
+    gradient_proto = &obj.toObject();
 
     obj = gjs_cairo_linear_gradient_create_proto(context, module,
                                                  "LinearGradient", gradient_proto);
-    if (JSVAL_IS_NULL(obj))
+    if (obj.isNull())
         return false;
 
     obj = gjs_cairo_radial_gradient_create_proto(context, module,
                                                  "RadialGradient", gradient_proto);
-    if (JSVAL_IS_NULL(obj))
+    if (obj.isNull())
         return false;
 
     obj = gjs_cairo_surface_pattern_create_proto(context, module,
                                                  "SurfacePattern", pattern_proto);
-    if (JSVAL_IS_NULL(obj))
+    if (obj.isNull())
         return false;
 
     obj = gjs_cairo_solid_pattern_create_proto(context, module,
                                                "SolidPattern", pattern_proto);
-    if (JSVAL_IS_NULL(obj))
+    if (obj.isNull())
         return false;
 
     *module_out = module;
diff --git a/modules/console.cpp b/modules/console.cpp
index c9bd8c1..c36068b 100644
--- a/modules/console.cpp
+++ b/modules/console.cpp
@@ -160,7 +160,7 @@ gjs_console_interact(JSContext *context,
                      JS::Value *vp)
 {
     JS::CallReceiver rec = JS::CallReceiverFromVp(vp);
-    JSObject *object = JSVAL_TO_OBJECT(rec.thisv());
+    JSObject *object = rec.thisv().toObjectOrNull();
     bool eof = false;
     JS::Value result;
     JSString *str;
@@ -205,7 +205,7 @@ gjs_console_interact(JSContext *context,
         if (JS_GetPendingException(context, &result)) {
             str = JS_ValueToString(context, result);
             JS_ClearPendingException(context);
-        } else if (JSVAL_IS_VOID(result)) {
+        } else if (result.isUndefined()) {
             goto next;
         } else {
             str = JS_ValueToString(context, result);
diff --git a/modules/system.cpp b/modules/system.cpp
index 3962c6b..333f86a 100644
--- a/modules/system.cpp
+++ b/modules/system.cpp
@@ -63,7 +63,6 @@ gjs_refcount(JSContext *context,
              JS::Value *vp)
 {
     JS::CallArgs argv = JS::CallArgsFromVp (argc, vp);
-    JS::Value retval;
     JSObject *target_obj;
     GObject *obj;
 
@@ -77,8 +76,7 @@ gjs_refcount(JSContext *context,
     if (obj == NULL)
         return false;
 
-    retval = INT_TO_JSVAL(obj->ref_count);
-    argv.rval().set(retval);
+    argv.rval().setInt32(obj->ref_count);
     return true;
 }
 
@@ -91,7 +89,7 @@ gjs_breakpoint(JSContext *context,
     if (!gjs_parse_call_args(context, "breakpoint", "", argv))
         return false;
     G_BREAKPOINT();
-    argv.rval().set(JSVAL_VOID);
+    argv.rval().setUndefined();
     return true;
 }
 
@@ -104,7 +102,7 @@ gjs_gc(JSContext *context,
     if (!gjs_parse_call_args(context, "gc", "", argv))
         return false;
     JS_GC(JS_GetRuntime(context));
-    argv.rval().set(JSVAL_VOID);
+    argv.rval().setUndefined();
     return true;
 }
 
@@ -136,7 +134,7 @@ gjs_clear_date_caches(JSContext *context,
     JS_ClearDateCaches(context);
     JS_EndRequest(context);
 
-    rec.rval().set(JSVAL_VOID);
+    rec.rval().setUndefined();
     return true;
 }
 
@@ -188,7 +186,7 @@ gjs_js_define_system_stuff(JSContext  *context,
 
     if (!JS_DefineProperty(context, module,
                            "version",
-                           INT_TO_JSVAL(GJS_VERSION),
+                           JS::Int32Value(GJS_VERSION),
                            JS_PropertyStub,
                            JS_StrictPropertyStub,
                            GJS_MODULE_PROP_FLAGS | JSPROP_READONLY))
diff --git a/test/gjs-test-coverage.cpp b/test/gjs-test-coverage.cpp
index fa54d6f..47e567d 100644
--- a/test/gjs-test-coverage.cpp
+++ b/test/gjs-test-coverage.cpp
@@ -1716,7 +1716,7 @@ test_coverage_cache_as_js_object_has_expected_properties(gpointer      fixture_d
     JS::RootedString cache_results(JS_GetRuntime((JSContext *) 
gjs_context_get_native_context(fixture->base_fixture.context)),
                                    gjs_deserialize_cache_to_object(fixture->base_fixture.coverage, cache));
     JS::RootedValue cache_result_value(JS_GetRuntime((JSContext *) 
gjs_context_get_native_context(fixture->base_fixture.context)),
-                                       STRING_TO_JSVAL(cache_results));
+                                       JS::StringValue(cache_results));
     gjs_inject_value_into_coverage_compartment(fixture->base_fixture.coverage,
                                                cache_result_value,
                                                "coverage_cache");
diff --git a/test/gjs-tests.cpp b/test/gjs-tests.cpp
index c1d7f69..f6267cf 100644
--- a/test/gjs-tests.cpp
+++ b/test/gjs-tests.cpp
@@ -110,7 +110,7 @@ gjstest_test_func_gjs_jsapi_util_array(void)
     JSCompartment *oldCompartment = JS_EnterCompartment(context, global);
 
     for (i = 0; i < N_ELEMS; i++) {
-        value = STRING_TO_JSVAL(JS_NewStringCopyZ(context, "abcdefghijk"));
+        value = JS::StringValue(JS_NewStringCopyZ(context, "abcdefghijk"));
         gjs_rooted_array_append(context, array, value);
     }
 
@@ -120,7 +120,7 @@ gjstest_test_func_gjs_jsapi_util_array(void)
         char *ascii;
 
         value = gjs_rooted_array_get(context, array, i);
-        g_assert(JSVAL_IS_STRING(value));
+        g_assert(value.isString());
         gjs_string_to_utf8(context, value, &ascii);
         g_assert(strcmp(ascii, "abcdefghijk") == 0);
         g_free(ascii);
@@ -151,7 +151,7 @@ gjstest_test_func_gjs_jsapi_util_string_js_string_utf8(void)
     JSCompartment *oldCompartment = JS_EnterCompartment(context, global);
 
     g_assert(gjs_string_from_utf8(context, utf8_string, -1, &js_string));
-    g_assert(JSVAL_IS_STRING(js_string));
+    g_assert(js_string.isString());
     g_assert(gjs_string_to_utf8(context, js_string, &utf8_result));
 
     JS_LeaveCompartment(context, oldCompartment);
@@ -182,15 +182,15 @@ gjstest_test_func_gjs_jsapi_util_error_throw(void)
 
     g_assert(JS_IsExceptionPending(context));
 
-    exc = JSVAL_VOID;
+    exc = JS::UndefinedValue();
     JS_GetPendingException(context, &exc);
-    g_assert(!JSVAL_IS_VOID(exc));
+    g_assert(!exc.isUndefined());
 
-    value = JSVAL_VOID;
-    JS_GetProperty(context, JSVAL_TO_OBJECT(exc), "message",
+    value = JS::UndefinedValue();
+    JS_GetProperty(context, &exc.toObject(), "message",
                    &value);
 
-    g_assert(JSVAL_IS_STRING(value));
+    g_assert(value.isString());
 
     gjs_string_to_utf8(context, value, &s);
     g_assert(s != NULL);
@@ -216,10 +216,10 @@ gjstest_test_func_gjs_jsapi_util_error_throw(void)
 
     g_assert(JS_IsExceptionPending(context));
 
-    exc = JSVAL_VOID;
+    exc = JS::UndefinedValue();
     JS_GetPendingException(context, &exc);
-    g_assert(!JSVAL_IS_VOID(exc));
-    g_assert(JSVAL_TO_OBJECT(exc) == JSVAL_TO_OBJECT(previous));
+    g_assert(!exc.isUndefined());
+    g_assert(&exc.toObject() == &previous.toObject());
 
     JS_RemoveValueRoot(context, &previous);
 


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