[gjs/wip/ptomato/mozjs45: 5/33] js: Create objects with JS_NewObjectWithGivenProto()
- From: Philip Chimento <pchimento src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gjs/wip/ptomato/mozjs45: 5/33] js: Create objects with JS_NewObjectWithGivenProto()
- Date: Mon, 17 Apr 2017 07:27:04 +0000 (UTC)
commit 66c12889b7926fdcbb6abf72134e6f07f6ffe365
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]