[gjs/wip/ptomato/mozjs45prep: 6/32] js: Create objects with JS_NewObjectWithGivenProto()



commit 4adfaf99e1f7d40b8f8756c8aa764399e3c8b5a7
Author: Philip Chimento <philip chimento gmail com>
Date:   Tue Apr 11 23:57:07 2017 -0700

    js: Create objects with JS_NewObjectWithGivenProto()
    
    Starting in SpiderMonkey 45 we have to pass in the prototype object to
    all our instances of native classes.
    
    Since we only need the _get_proto and _define_proto functions for the
    native classes, and not the JSClass like we do for gtype and cairo, we
    split them out into a separate macro family,
    GJS_DEFINE_PROTO_FUNCS[_WITH_PARENT].
    
    We also make a few amendments to the macro: g_error instead of throw an
    exception when JS_InitClass fails, since that's what the code we are
    replacing did; and a debug message on success. We have to change the debug
    topic to GJS_DEBUG_CONTEXT in order to avoid having to pass in yet another
    parameter to the macro just for debugging.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=614413

 gi/function.cpp   |   65 ++++++++++++++---------------------------------------
 gi/ns.cpp         |   53 +++++++++----------------------------------
 gi/repo.cpp       |   54 ++++++++-----------------------------------
 gjs/byteArray.cpp |   57 +++++++++++-----------------------------------
 gjs/importer.cpp  |   50 +++++++---------------------------------
 gjs/jsapi-class.h |   23 +++++++++++++++++-
 gjs/jsapi-util.h  |    6 ++++-
 7 files changed, 87 insertions(+), 221 deletions(-)
---
diff --git a/gi/function.cpp b/gi/function.cpp
index 1126ad7..bcdf62c 100644
--- a/gi/function.cpp
+++ b/gi/function.cpp
@@ -1500,18 +1500,20 @@ struct JSClass gjs_function_class = {
     function_call
 };
 
-JSPropertySpec gjs_function_proto_props[] = {
+static JSPropertySpec gjs_function_proto_props[] = {
     JS_PSG("length", get_num_arguments, JSPROP_PERMANENT),
     JS_PS_END
 };
 
 /* The original Function.prototype.toString complains when
    given a GIRepository function as an argument */
-JSFunctionSpec gjs_function_proto_funcs[] = {
+static JSFunctionSpec gjs_function_proto_funcs[] = {
     JS_FN("toString", function_to_string, 0, 0),
     JS_FS_END
 };
 
+static JSFunctionSpec *gjs_function_static_funcs = nullptr;
+
 static bool
 init_cached_function_data (JSContext      *context,
                            Function       *function,
@@ -1660,66 +1662,33 @@ init_cached_function_data (JSContext      *context,
     return true;
 }
 
+static inline JSObject *
+gjs_builtin_function_get_proto(JSContext *cx)
+{
+    JS::RootedObject global(cx, gjs_get_import_global(cx));
+    return JS_GetFunctionPrototype(cx, global);
+}
+
+GJS_DEFINE_PROTO_FUNCS_WITH_PARENT(function, builtin_function)
+
 static JSObject*
 function_new(JSContext      *context,
              GType           gtype,
              GICallableInfo *info)
 {
     Function *priv;
-    bool found;
 
-    /* put constructor for GIRepositoryFunction() in the global namespace */
-    JS::RootedObject global(context, gjs_get_import_global(context));
-
-    if (!JS_HasProperty(context, global, gjs_function_class.name, &found))
-        return NULL;
-    if (!found) {
-        JSObject *prototype;
-        JS::RootedObject parent_proto(context);
-        JS::RootedValue v_native_function(context);
-
-        JS_GetProperty(context, global, "Function", &v_native_function);
-        JS::RootedObject native_function(context, &v_native_function.toObject());
-        /* We take advantage from that fact that Function.__proto__ is Function.prototype */
-        JS_GetPrototype(context, native_function, &parent_proto);
-
-        prototype = JS_InitClass(context, global,
-                                 /* parent prototype JSObject* for
-                                  * prototype; NULL for
-                                  * Object.prototype
-                                  */
-                                 parent_proto,
-                                 &gjs_function_class,
-                                 /* constructor for instances (NULL for
-                                  * none - just name the prototype like
-                                  * Math - rarely correct)
-                                  */
-                                 gjs_function_constructor,
-                                 /* number of constructor args */
-                                 0,
-                                 /* props of prototype */
-                                 &gjs_function_proto_props[0],
-                                 /* funcs of prototype */
-                                 &gjs_function_proto_funcs[0],
-                                 /* props of constructor, MyConstructor.myprop */
-                                 NULL,
-                                 /* funcs of constructor, MyConstructor.myfunc() */
-                                 NULL);
-        if (prototype == NULL)
-            g_error("Can't init class %s", gjs_function_class.name);
-
-        gjs_debug(GJS_DEBUG_GFUNCTION, "Initialized class %s prototype %p",
-                  gjs_function_class.name, prototype);
-    }
+    JS::RootedObject proto(context);
+    if (!gjs_function_define_proto(context, JS::NullPtr(), &proto))
+        return nullptr;
 
     JS::RootedObject function(context,
-        JS_NewObject(context, &gjs_function_class, global));
+        JS_NewObjectWithGivenProto(context, &gjs_function_class, proto));
     if (function == NULL) {
         gjs_debug(GJS_DEBUG_GFUNCTION, "Failed to construct function");
         return NULL;
     }
 
-
     priv = g_slice_new0(Function);
 
     GJS_INC_COUNTER(function);
diff --git a/gi/ns.cpp b/gi/ns.cpp
index a45a288..9406cd6 100644
--- a/gi/ns.cpp
+++ b/gi/ns.cpp
@@ -170,59 +170,28 @@ struct JSClass gjs_ns_class = {
     ns_finalize
 };
 
-JSPropertySpec gjs_ns_proto_props[] = {
+static JSPropertySpec gjs_ns_proto_props[] = {
     JS_PSG("__name__", get_name, GJS_MODULE_PROP_FLAGS),
     JS_PS_END
 };
 
-JSFunctionSpec gjs_ns_proto_funcs[] = {
-    JS_FS_END
-};
+static JSFunctionSpec *gjs_ns_proto_funcs = nullptr;
+static JSFunctionSpec *gjs_ns_static_funcs = nullptr;
+
+GJS_DEFINE_PROTO_FUNCS(ns)
 
 static JSObject*
 ns_new(JSContext    *context,
        const char   *ns_name)
 {
     Ns *priv;
-    bool found;
-
-    /* put constructor in the global namespace */
-    JS::RootedObject global(context, gjs_get_import_global(context));
-
-    if (!JS_HasProperty(context, global, gjs_ns_class.name, &found))
-        return NULL;
-    if (!found) {
-        JSObject *prototype;
-        prototype = JS_InitClass(context, global,
-                                 /* parent prototype JSObject* for
-                                  * prototype; NULL for
-                                  * Object.prototype
-                                  */
-                                 JS::NullPtr(),
-                                 &gjs_ns_class,
-                                 /* constructor for instances (NULL for
-                                  * none - just name the prototype like
-                                  * Math - rarely correct)
-                                  */
-                                 gjs_ns_constructor,
-                                 /* number of constructor args */
-                                 0,
-                                 /* props of prototype */
-                                 &gjs_ns_proto_props[0],
-                                 /* funcs of prototype */
-                                 &gjs_ns_proto_funcs[0],
-                                 /* props of constructor, MyConstructor.myprop */
-                                 NULL,
-                                 /* funcs of constructor, MyConstructor.myfunc() */
-                                 NULL);
-        if (prototype == NULL)
-            g_error("Can't init class %s", gjs_ns_class.name);
-
-        gjs_debug(GJS_DEBUG_GNAMESPACE, "Initialized class %s prototype %p",
-                  gjs_ns_class.name, prototype);
-    }
 
-    JS::RootedObject ns(context, JS_NewObject(context, &gjs_ns_class, global));
+    JS::RootedObject proto(context);
+    if (!gjs_ns_define_proto(context, JS::NullPtr(), &proto))
+        return nullptr;
+
+    JS::RootedObject ns(context,
+        JS_NewObjectWithGivenProto(context, &gjs_ns_class, proto));
     if (ns == NULL)
         g_error("No memory to create ns object");
 
diff --git a/gi/repo.cpp b/gi/repo.cpp
index 18f2861..1785966 100644
--- a/gi/repo.cpp
+++ b/gi/repo.cpp
@@ -239,57 +239,23 @@ struct JSClass gjs_repo_class = {
     repo_finalize
 };
 
-JSPropertySpec gjs_repo_proto_props[] = {
-    JS_PS_END
-};
+static JSPropertySpec *gjs_repo_proto_props = nullptr;
+static JSFunctionSpec *gjs_repo_proto_funcs = nullptr;
+static JSFunctionSpec *gjs_repo_static_funcs = nullptr;
 
-JSFunctionSpec gjs_repo_proto_funcs[] = {
-    JS_FS_END
-};
+GJS_DEFINE_PROTO_FUNCS(repo)
 
 static JSObject*
 repo_new(JSContext *context)
 {
     Repo *priv;
-    bool found;
-
-    JS::RootedObject global(context, gjs_get_import_global(context));
 
-    if (!JS_HasProperty(context, global, gjs_repo_class.name, &found))
-        return NULL;
-    if (!found) {
-        JSObject *prototype;
-        prototype = JS_InitClass(context, global,
-                                 /* parent prototype JSObject* for
-                                  * prototype; NULL for
-                                  * Object.prototype
-                                  */
-                                 JS::NullPtr(),
-                                 &gjs_repo_class,
-                                 /* constructor for instances (NULL for
-                                  * none - just name the prototype like
-                                  * Math - rarely correct)
-                                  */
-                                 gjs_repo_constructor,
-                                 /* number of constructor args */
-                                 0,
-                                 /* props of prototype */
-                                 &gjs_repo_proto_props[0],
-                                 /* funcs of prototype */
-                                 &gjs_repo_proto_funcs[0],
-                                 /* props of constructor, MyConstructor.myprop */
-                                 NULL,
-                                 /* funcs of constructor, MyConstructor.myfunc() */
-                                 NULL);
-        if (prototype == NULL)
-            g_error("Can't init class %s", gjs_repo_class.name);
-
-        gjs_debug(GJS_DEBUG_GREPO, "Initialized class %s prototype %p",
-                  gjs_repo_class.name, prototype);
-    }
+    JS::RootedObject proto(context);
+    if (!gjs_repo_define_proto(context, JS::NullPtr(), &proto))
+        return nullptr;
 
     JS::RootedObject repo(context,
-        JS_NewObject(context, &gjs_repo_class, global));
+        JS_NewObjectWithGivenProto(context, &gjs_repo_class, proto));
     if (repo == NULL) {
         gjs_throw(context, "No memory to create repo object");
         return NULL;
@@ -305,7 +271,7 @@ repo_new(JSContext *context)
     gjs_debug_lifecycle(GJS_DEBUG_GREPO,
                         "repo constructor, obj %p priv %p", repo.get(), priv);
 
-    JS::RootedObject versions(context, JS_NewObject(context, NULL, global));
+    JS::RootedObject versions(context, JS_NewObject(context, NULL));
     gjs_object_define_property(context, repo, GJS_STRING_GI_VERSIONS,
                                versions, JSPROP_PERMANENT);
 
@@ -323,7 +289,7 @@ repo_new(JSContext *context)
                            JSPROP_PERMANENT))
         return nullptr;
 
-    JS::RootedObject private_ns(context, JS_NewObject(context, NULL, global));
+    JS::RootedObject private_ns(context, JS_NewObject(context, NULL));
     gjs_object_define_property(context, repo,
                                GJS_STRING_PRIVATE_NS_MARKER, private_ns,
                                JSPROP_PERMANENT);
diff --git a/gjs/byteArray.cpp b/gjs/byteArray.cpp
index acdb629..212629c 100644
--- a/gjs/byteArray.cpp
+++ b/gjs/byteArray.cpp
@@ -53,6 +53,7 @@ GJS_NATIVE_CONSTRUCTOR_DECLARE(byte_array);
 static void   byte_array_finalize      (JSFreeOp     *fop,
                                         JSObject     *obj);
 
+static JSObject *gjs_byte_array_get_proto(JSContext *);
 
 struct JSClass gjs_byte_array_class = {
     "ByteArray",
@@ -508,30 +509,12 @@ to_gbytes_func(JSContext *context,
     return true;
 }
 
-/* Ensure that the module and class objects exists, and that in turn
- * ensures that JS_InitClass has been called. */
-static JSObject *
-byte_array_get_prototype(JSContext *context)
-{
-    JS::RootedValue retval(context,
-        gjs_get_global_slot(context, GJS_GLOBAL_SLOT_BYTE_ARRAY_PROTOTYPE));
-
-    if (!retval.isObject()) {
-        if (!gjs_eval_with_scope(context, JS::NullPtr(),
-                                 "imports.byteArray.ByteArray.prototype;", -1,
-                                 "<internal>", &retval))
-            g_error ("Could not import byte array prototype\n");
-    }
-
-    return &retval.toObject();
-}
-
 static JSObject*
 byte_array_new(JSContext *context)
 {
     ByteArrayInstance *priv;
 
-    JS::RootedObject proto(context, byte_array_get_prototype(context));
+    JS::RootedObject proto(context, gjs_byte_array_get_proto(context));
     JS::RootedObject array(context,
         JS_NewObjectWithGivenProto(context, &gjs_byte_array_class, proto));
 
@@ -759,7 +742,7 @@ gjs_byte_array_from_byte_array (JSContext *context,
     g_return_val_if_fail(context != NULL, NULL);
     g_return_val_if_fail(array != NULL, NULL);
 
-    JS::RootedObject proto(context, byte_array_get_prototype(context));
+    JS::RootedObject proto(context, gjs_byte_array_get_proto(context));
     JS::RootedObject object(context,
         JS_NewObjectWithGivenProto(context, &gjs_byte_array_class, proto));
 
@@ -824,18 +807,20 @@ gjs_byte_array_peek_data (JSContext       *context,
     }
 }
 
-JSPropertySpec gjs_byte_array_proto_props[] = {
+static JSPropertySpec gjs_byte_array_proto_props[] = {
     JS_PSGS("length", byte_array_length_getter, byte_array_length_setter,
             JSPROP_PERMANENT),
     JS_PS_END
 };
 
-JSFunctionSpec gjs_byte_array_proto_funcs[] = {
+static JSFunctionSpec gjs_byte_array_proto_funcs[] = {
     JS_FS("toString", to_string_func, 0, 0),
     JS_FS("toGBytes", to_gbytes_func, 0, 0),
     JS_FS_END
 };
 
+static JSFunctionSpec *gjs_byte_array_static_funcs = nullptr;
+
 static JSFunctionSpec gjs_byte_array_module_funcs[] = {
     JS_FS("fromString", from_string_func, 1, 0),
     JS_FS("fromArray", from_array_func, 1, 0),
@@ -843,29 +828,15 @@ static JSFunctionSpec gjs_byte_array_module_funcs[] = {
     JS_FS_END
 };
 
+GJS_DEFINE_PROTO_FUNCS(byte_array)
+
 bool
-gjs_define_byte_array_stuff(JSContext              *context,
+gjs_define_byte_array_stuff(JSContext              *cx,
                             JS::MutableHandleObject module)
 {
-    JSObject *prototype;
+    module.set(JS_NewObject(cx, NULL));
 
-    module.set(JS_NewObject(context, NULL));
-
-    prototype = JS_InitClass(context, module, JS::NullPtr(),
-                             &gjs_byte_array_class,
-                             gjs_byte_array_constructor,
-                             0,
-                             &gjs_byte_array_proto_props[0],
-                             &gjs_byte_array_proto_funcs[0],
-                             NULL,
-                             NULL);
-
-    if (!JS_DefineFunctions(context, module, &gjs_byte_array_module_funcs[0]))
-        return false;
-
-    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,
-                        JS::ObjectOrNullValue(prototype));
-
-    return true;
+    JS::RootedObject proto(cx);
+    return gjs_byte_array_define_proto(cx, module, &proto) &&
+        JS_DefineFunctions(cx, module, gjs_byte_array_module_funcs);
 }
diff --git a/gjs/importer.cpp b/gjs/importer.cpp
index f09d0f0..d1ca30a 100644
--- a/gjs/importer.cpp
+++ b/gjs/importer.cpp
@@ -892,62 +892,30 @@ const js::Class gjs_importer_real_class = {
     }
 };
 
-JSPropertySpec gjs_importer_proto_props[] = {
-    JS_PS_END
-};
+static JSPropertySpec *gjs_importer_proto_props = nullptr;
+static JSFunctionSpec *gjs_importer_static_funcs = nullptr;
 
 JSFunctionSpec gjs_importer_proto_funcs[] = {
     JS_FS("toString", importer_to_string, 0, 0),
     JS_FS_END
 };
 
+GJS_DEFINE_PROTO_FUNCS(importer)
+
 static JSObject*
 importer_new(JSContext *context,
              bool       is_root)
 {
     Importer *priv;
-    bool found;
 
-    JS::RootedObject global(context, gjs_get_import_global(context));
-
-    if (!JS_HasProperty(context, global, gjs_importer_class.name, &found))
-        g_error("HasProperty call failed creating importer class");
-
-    if (!found) {
-        JSObject *prototype;
-        prototype = JS_InitClass(context, global,
-                                 /* parent prototype JSObject* for
-                                  * prototype; NULL for
-                                  * Object.prototype
-                                  */
-                                 JS::NullPtr(),
-                                 &gjs_importer_class,
-                                 /* constructor for instances (NULL for
-                                  * none - just name the prototype like
-                                  * Math - rarely correct)
-                                  */
-                                 gjs_importer_constructor,
-                                 /* number of constructor args */
-                                 0,
-                                 /* props of prototype */
-                                 &gjs_importer_proto_props[0],
-                                 /* funcs of prototype */
-                                 &gjs_importer_proto_funcs[0],
-                                 /* props of constructor, MyConstructor.myprop */
-                                 NULL,
-                                 /* funcs of constructor, MyConstructor.myfunc() */
-                                 NULL);
-        if (prototype == NULL)
-            g_error("Can't init class %s", gjs_importer_real_class.name);
-
-        gjs_debug(GJS_DEBUG_IMPORTER, "Initialized class %s prototype %p",
-                  gjs_importer_real_class.name, prototype);
-    }
+    JS::RootedObject proto(context);
+    if (!gjs_importer_define_proto(context, JS::NullPtr(), &proto))
+        g_error("Error creating importer prototype");
 
     JS::RootedObject importer(context,
-        JS_NewObject(context, &gjs_importer_class, global));
+        JS_NewObjectWithGivenProto(context, &gjs_importer_class, proto));
     if (importer == NULL)
-        g_error("No memory to create importer importer");
+        g_error("No memory to create importer");
 
     priv = g_slice_new0(Importer);
     priv->is_root = is_root;
diff --git a/gjs/jsapi-class.h b/gjs/jsapi-class.h
index c3f8e9a..1008dd5 100644
--- a/gjs/jsapi-class.h
+++ b/gjs/jsapi-class.h
@@ -26,6 +26,7 @@
 
 #include "jsapi-util.h"
 #include "jsapi-wrapper.h"
+#include "util/log.h"
 
 G_BEGIN_DECLS
 
@@ -181,6 +182,20 @@ static struct JSClass gjs_##cname##_class = {                                \
     nullptr,  /* convert */                                                  \
     gjs_##cname##_finalize                                                   \
 };                                                                           \
+_GJS_DEFINE_GET_PROTO(cname)                                                 \
+_GJS_DEFINE_DEFINE_PROTO(cname, parent_cname, ctor, gtype)
+
+#define GJS_DEFINE_PROTO_FUNCS_WITH_PARENT(cname, parent_cname)  \
+G_GNUC_UNUSED static                                             \
+_GJS_DEFINE_GET_PROTO(cname)                                     \
+G_GNUC_UNUSED static                                             \
+_GJS_DEFINE_DEFINE_PROTO(cname, parent_cname,                    \
+                         gjs_##cname##_constructor, G_TYPE_NONE)
+
+#define GJS_DEFINE_PROTO_FUNCS(cname)  \
+GJS_DEFINE_PROTO_FUNCS_WITH_PARENT(cname, no_parent)
+
+#define _GJS_DEFINE_GET_PROTO(cname)                                         \
 JSObject *                                                                   \
 gjs_##cname##_get_proto(JSContext *cx)                                       \
 {                                                                            \
@@ -191,7 +206,9 @@ gjs_##cname##_get_proto(JSContext *cx)                                       \
     g_assert(((void) "Someone stored some weird value in a global slot",     \
               v_proto.isObject()));                                          \
     return &v_proto.toObject();                                              \
-}                                                                            \
+}
+
+#define _GJS_DEFINE_DEFINE_PROTO(cname, parent_cname, ctor, gtype)           \
 bool                                                                         \
 gjs_##cname##_define_proto(JSContext              *cx,                       \
                            JS::HandleObject        module,                   \
@@ -219,7 +236,7 @@ gjs_##cname##_define_proto(JSContext              *cx,                       \
                            gjs_##cname##_proto_funcs, nullptr,               \
                            gjs_##cname##_static_funcs));                     \
     if (!proto)                                                              \
-        return false;                                                        \
+        g_error("Can't init class %s", gjs_##cname##_class.name);            \
     gjs_set_global_slot(cx, GJS_GLOBAL_SLOT_PROTOTYPE_##cname,               \
                         JS::ObjectValue(*proto));                            \
                                                                              \
@@ -252,6 +269,8 @@ gjs_##cname##_define_proto(JSContext              *cx,                       \
                                JSPROP_PERMANENT))                            \
             return false;                                                    \
     }                                                                        \
+    gjs_debug(GJS_DEBUG_CONTEXT, "Initialized class %s prototype %p",        \
+              gjs_##cname##_class.name, proto.get());                        \
     return true;                                                             \
 }
 
diff --git a/gjs/jsapi-util.h b/gjs/jsapi-util.h
index e8a6ca7..d94f813 100644
--- a/gjs/jsapi-util.h
+++ b/gjs/jsapi-util.h
@@ -75,7 +75,11 @@ enum {
 typedef enum {
     GJS_GLOBAL_SLOT_IMPORTS,
     GJS_GLOBAL_SLOT_PROTOTYPE_gtype,
-    GJS_GLOBAL_SLOT_BYTE_ARRAY_PROTOTYPE,
+    GJS_GLOBAL_SLOT_PROTOTYPE_function,
+    GJS_GLOBAL_SLOT_PROTOTYPE_ns,
+    GJS_GLOBAL_SLOT_PROTOTYPE_repo,
+    GJS_GLOBAL_SLOT_PROTOTYPE_byte_array,
+    GJS_GLOBAL_SLOT_PROTOTYPE_importer,
     GJS_GLOBAL_SLOT_PROTOTYPE_cairo_context,
     GJS_GLOBAL_SLOT_PROTOTYPE_cairo_gradient,
     GJS_GLOBAL_SLOT_PROTOTYPE_cairo_image_surface,


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