After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 614413 - [cairo] Instantiate wrappers properly
[cairo] Instantiate wrappers properly
Status: RESOLVED FIXED
Product: gjs
Classification: Bindings
Component: general
unspecified
Other All
: Normal normal
: ---
Assigned To: Philip Chimento
gjs-maint
Depends on:
Blocks:
 
 
Reported: 2010-03-30 23:06 UTC by Johan (not receiving bugmail) Dahlin
Modified: 2018-01-26 12:51 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
[jsapi] Export prototype in GJS_DEFINE_PROTO (2.03 KB, patch)
2010-03-30 23:06 UTC, Johan (not receiving bugmail) Dahlin
none Details | Review
[cairo] Send in prototype to JS_NewObject (8.58 KB, patch)
2010-03-30 23:06 UTC, Johan (not receiving bugmail) Dahlin
none Details | Review
tests: Ensure a Cairo context is fully created in GI (1.99 KB, patch)
2017-04-05 02:50 UTC, Philip Chimento
committed Details | Review
Export prototype in GJS_DEFINE_PROTO (2.47 KB, patch)
2017-04-07 15:48 UTC, Philip Chimento
committed Details | Review
Send in prototype to JS_NewObject (9.78 KB, patch)
2017-04-07 15:48 UTC, Philip Chimento
committed Details | Review
global: Remove GJS_GLOBAL_SLOT_KEEP_ALIVE (738 bytes, patch)
2017-04-07 15:48 UTC, Philip Chimento
committed Details | Review
jsapi-util: Return JSObject from create_proto (18.25 KB, patch)
2017-04-10 07:32 UTC, Philip Chimento
committed Details | Review
jsapi-util: GJS_DEFINE_PROTO stores protos in global slots (46.91 KB, patch)
2017-04-10 07:32 UTC, Philip Chimento
none Details | Review
jsapi-util: GJS_DEFINE_PROTO stores protos in global slots (46.75 KB, patch)
2017-04-11 05:13 UTC, Philip Chimento
accepted-commit_now Details | Review
jsapi-dynamic-class: Use JS_LinkConstructorAndPrototype() (1.34 KB, patch)
2017-04-11 05:13 UTC, Philip Chimento
committed Details | Review
jsapi-util: Add static function spec to GJS_DEFINE_PROTO (10.41 KB, patch)
2017-04-11 05:13 UTC, Philip Chimento
none Details | Review
importer: Add a JSClass constant (3.26 KB, patch)
2017-04-12 07:00 UTC, Philip Chimento
committed Details | Review
WIP - js: Create objects with JS_NewObjectWithGivenProto() (13.80 KB, patch)
2017-04-12 07:00 UTC, Philip Chimento
none Details | Review
jsapi-util: Split off class stuff into jsapi-class.h (39.12 KB, patch)
2017-04-13 06:13 UTC, Philip Chimento
committed Details | Review
jsapi-class: Get rid of "proto_name" argument (24.91 KB, patch)
2017-04-14 03:04 UTC, Philip Chimento
committed Details | Review
jsapi-class: GJS_DEFINE_PROTO stores protos in global slots (43.88 KB, patch)
2017-04-14 03:18 UTC, Philip Chimento
none Details | Review
jsapi-util: Add static function spec to GJS_DEFINE_PROTO (10.67 KB, patch)
2017-04-14 03:26 UTC, Philip Chimento
committed Details | Review
js: Create objects with JS_NewObjectWithGivenProto() (22.79 KB, patch)
2017-04-15 07:10 UTC, Philip Chimento
committed Details | Review
jsapi-class: GJS_DEFINE_PROTO stores protos in global slots (43.64 KB, patch)
2017-04-18 03:03 UTC, Philip Chimento
committed Details | Review

Description Johan (not receiving bugmail) Dahlin 2010-03-30 23:06:44 UTC
These two patches makes it possible to call Cairo.Context
methods on APIs created though gobject-introspection such as
Gdk.cairo_create, Clutter.CairoTexture.create etc.

Previously the wrappers returned were just empty objects without
any properties set.
Comment 1 Johan (not receiving bugmail) Dahlin 2010-03-30 23:06:50 UTC
Created attachment 157541 [details] [review]
[jsapi] Export prototype in GJS_DEFINE_PROTO

When creating a new prototype using the GJS_DEFINE_PROTO macros,
save a static reference to the JSObject* representing the created
prototype. Previously only a reference to the JSClass structure was
saved, which is basically just a vtable without any actual state.
This is necessary to be able to create new instances of that prototype
without calling the provided constructor.
Comment 2 Johan (not receiving bugmail) Dahlin 2010-03-30 23:06:56 UTC
Created attachment 157542 [details] [review]
[cairo] Send in prototype to JS_NewObject

Send in a reference to the prototype to JS_NewObject, this
makes sure that the created object contains all properties from
the prototypes. This makes it possible to call Cairo.Context methods
on wrappers created from API created through introspection.
Comment 3 Havoc Pennington 2010-03-31 03:04:07 UTC
Review of attachment 157541 [details] [review]:

::: gjs/jsapi-util.h
@@ +144,3 @@
     return JS_TRUE; \
 } \
+static JSObject * cname##_prototype; \

This isn't gc-rooted... the way we do it elsewhere in gjs iirc is to save it in JS, not in C. That is, just get the prototype by looking up imports.cairo.Context.prototype or whatever.
Comment 4 Johan (not receiving bugmail) Dahlin 2010-03-31 12:43:50 UTC
(In reply to comment #3)
> Review of attachment 157541 [details] [review]:
> 
> ::: gjs/jsapi-util.h
> @@ +144,3 @@
>      return JS_TRUE; \
>  } \
> +static JSObject * cname##_prototype; \
> 
> This isn't gc-rooted... the way we do it elsewhere in gjs iirc is to save it in
> JS, not in C. That is, just get the prototype by looking up
> imports.cairo.Context.prototype or whatever.

You could think of it as an optimization I guess, to avoid having to do the JS->C. Adding the prototype w/ JS_AddRoot is easy, I'm just not sure how a prototype object is finalized.
Comment 5 Havoc Pennington 2010-03-31 13:13:29 UTC
Basically you want the prototype to be gc'd if there are no instances of the object anymore and the module is unloaded (not something we support yet, but we should eventually probably)

I think the C variable with AddRoot would make it "resident" (impossible to unload).
Comment 6 Philip Chimento 2017-04-05 02:50:06 UTC
Created attachment 349270 [details] [review]
tests: Ensure a Cairo context is fully created in GI

According to the bug report, if you created a Cairo context through a GI
function such as Gdk.cairo_create(), it would be an empty wrapper. At some
point this was fixed, I suspect in SpiderMonkey itself, by associating the
prototype object with the JSClass and having JS_NewObject() look for it.

However, this behaviour may have changed in SpiderMonkey 45, so we should
add a test to make sure it doesn't regress.
Comment 7 Philip Chimento 2017-04-05 03:10:34 UTC
This currently works, so the above patch just adds a test.

BUT! The test fails on SpiderMonkey 45 because they've made a change to JS_NewObject(); it doesn't look for the appropriate prototype object anymore. Instead, you're supposed to use JS_NewObjectWithGivenProto() and pass it explicitly. So I will rebase the patches and update them anyway.

I think it's OK to have the prototypes permanently rooted since we don't have loadable or unloadable modules. SpiderMonkey itself sticks them in slots on the global object, which we could also do, I think.
Comment 8 Cosimo Cecchi 2017-04-06 02:28:57 UTC
Review of attachment 349270 [details] [review]:

++
Comment 9 Philip Chimento 2017-04-07 15:47:19 UTC
Comment on attachment 349270 [details] [review]
tests: Ensure a Cairo context is fully created in GI

Attachment 349270 [details] pushed as 23fb49b - tests: Ensure a Cairo context is fully created in GI
Comment 10 Philip Chimento 2017-04-07 15:48:22 UTC
Created attachment 349490 [details] [review]
Export prototype in GJS_DEFINE_PROTO

When creating a new prototype using the GJS_DEFINE_PROTO macros,
save a static reference to the JSObject* representing the created
prototype. Previously only a reference to the JSClass structure was
saved, which is basically just a vtable without any actual state.
This is necessary to be able to create new instances of that prototype
without calling the provided constructor.
Comment 11 Philip Chimento 2017-04-07 15:48:32 UTC
Created attachment 349491 [details] [review]
Send in prototype to JS_NewObject

Send in a reference to the prototype to JS_NewObject, this
makes sure that the created object contains all properties from
the prototypes. This makes it possible to call Cairo.Context methods
on wrappers created from API created through introspection.
Comment 12 Philip Chimento 2017-04-07 15:48:42 UTC
Created attachment 349492 [details] [review]
global: Remove GJS_GLOBAL_SLOT_KEEP_ALIVE

We don't have a keep-alive object anymore so we don't need a slot to keep
it in.
Comment 13 Philip Chimento 2017-04-07 15:50:01 UTC
I'm working on another patch to stick the prototypes in global object slots, but here are updates of Johan's patches.
Comment 14 Cosimo Cecchi 2017-04-07 17:45:15 UTC
Review of attachment 349490 [details] [review]:

++
Comment 15 Cosimo Cecchi 2017-04-07 17:45:57 UTC
Review of attachment 349491 [details] [review]:

++
Comment 16 Cosimo Cecchi 2017-04-07 17:46:09 UTC
Review of attachment 349492 [details] [review]:

++
Comment 17 Philip Chimento 2017-04-08 19:25:55 UTC
Attachment 349490 [details] pushed as 3141fc0 - Export prototype in GJS_DEFINE_PROTO
Attachment 349491 [details] pushed as bc8f143 - Send in prototype to JS_NewObject
Attachment 349492 [details] pushed as 0744d13 - global: Remove GJS_GLOBAL_SLOT_KEEP_ALIVE
Comment 18 Philip Chimento 2017-04-10 07:32:50 UTC
Created attachment 349585 [details] [review]
jsapi-util: Return JSObject from create_proto

The return value is a prototype object, so there's no use in returning
JS::Value here only to convert it to an object in the calling code.
Comment 19 Philip Chimento 2017-04-10 07:32:56 UTC
Created attachment 349586 [details] [review]
jsapi-util: GJS_DEFINE_PROTO stores protos in global slots

This refactors the GJS_DEFINE_PROTO family of macros to store the created
prototype objects in slots on the global object. We split up the
gjs_WHATEVER_create_proto() function into two functions: one that actually
creates the prototype or returns it if already found in a global slot,
called gjs_WHATEVER_ensure_proto(); and one that defines a constructor,
accessible from JS, as a property on a module object, called
gjs_WHATEVER_define_constructor(). (gjs_WHATEVER_create_proto() was kind of
a misnomer since it returned the constructor, not the prototype, and so we
do a corresponding rename in cairo-image-surface.cpp, for clarity.)

gjs_WHATEVER_define_constructor() is not necessary for every class; we only
need to call it if we actually want to define the constructor as a property
on a module object. Therefore we split it out into its own macro,
GJS_EXPORT_PROTO. This macro takes a "js_name" parameter, which is the name
of the property to define. Previously, the JS name was passed to the
gjs_WHATEVER_create_proto() function. It's better to keep that definition
together with the rest of the information about the class, fixed at compile
time.

We also add two macros, GJS_DEFINE_PROTO_WITH_PARENT and
GJS_DEFINE_PROTO_ABSTRACT_WITH_PARENT, which also move the definition of
the parent to compile time rather than runtime, and keep it in the same
place as the rest of each class's macro definition. Similarly, previously
we had to pass the parent prototype object to gjs_WHATEVER_create_proto().

This mostly affects the cairo module.
Comment 20 Cosimo Cecchi 2017-04-10 15:45:36 UTC
Review of attachment 349585 [details] [review]:

++
Comment 21 Cosimo Cecchi 2017-04-10 15:54:46 UTC
Review of attachment 349586 [details] [review]:

Feel free to push with these two nitpicks fixed.

::: gjs/jsapi-util.h
@@ +288,3 @@
+ * GJS_EXPORT_PROTO:
+ * @cn: The name of the prototype, separated by _
+        return false;                                                          \

Nitpick: the arguments in the macro are called cname and js_name.

@@ +291,3 @@
+ *
+ * Defines a function gjs_<cn>_define_constructor(JSContext *, HandleObject)
+    gjs_set_global_slot(cx, GJS_GLOBAL_SLOT_PROTOTYPE_##cname,                 \

Isn't that called gjs_<cname>_ensure_proto()?
Comment 22 Philip Chimento 2017-04-11 01:48:58 UTC
Comment on attachment 349585 [details] [review]
jsapi-util: Return JSObject from create_proto

Attachment 349585 [details] pushed as 06e37d7 - jsapi-util: Return JSObject from create_proto
Comment 23 Philip Chimento 2017-04-11 05:13:40 UTC
Created attachment 349651 [details] [review]
jsapi-util: GJS_DEFINE_PROTO stores protos in global slots

This refactors the GJS_DEFINE_PROTO family of macros to store the created
prototype objects in slots on the global object. We split up the
gjs_WHATEVER_create_proto() function into two functions: one that actually
creates the prototype or returns it if already found in a global slot,
called gjs_WHATEVER_ensure_proto(); and one that defines a constructor,
accessible from JS, as a property on a module object, called
gjs_WHATEVER_define_constructor(). (gjs_WHATEVER_create_proto() was kind of
a misnomer since it returned the constructor, not the prototype, and so we
do a corresponding rename in cairo-image-surface.cpp, for clarity.)

gjs_WHATEVER_define_constructor() is not necessary for every class; we only
need to call it if we actually want to define the constructor as a property
on a module object. Therefore we split it out into its own macro,
GJS_EXPORT_PROTO. This macro takes a "js_name" parameter, which is the name
of the property to define. Previously, the JS name was passed to the
gjs_WHATEVER_create_proto() function. It's better to keep that definition
together with the rest of the information about the class, fixed at compile
time.

We also add two macros, GJS_DEFINE_PROTO_WITH_PARENT and
GJS_DEFINE_PROTO_ABSTRACT_WITH_PARENT, which also move the definition of
the parent to compile time rather than runtime, and keep it in the same
place as the rest of each class's macro definition. Similarly, previously
we had to pass the parent prototype object to gjs_WHATEVER_create_proto().

This mostly affects the cairo module.
Comment 24 Philip Chimento 2017-04-11 05:13:44 UTC
Created attachment 349652 [details] [review]
jsapi-dynamic-class: Use JS_LinkConstructorAndPrototype()

Small cleanup; there is a function in the JSAPI that does exactly this,
automatically with the right flags.
Comment 25 Philip Chimento 2017-04-11 05:13:49 UTC
Created attachment 349653 [details] [review]
jsapi-util: Add static function spec to GJS_DEFINE_PROTO

This allows the GJS_DEFINE_PROTO_* family of macros to have a JSFunctionSpec
array for functions defined on the constructor, rather than on the
prototype: i.e. static functions.

We clean up an incongruity in cairo-image-surface.cpp where you had to pass
the constructor into gjs_cairo_image_surface_init() in order to get the
static functions defined.
Comment 26 Philip Chimento 2017-04-11 05:14:37 UTC
There's not much difference in the new version of "GJS_DEFINE_PROTO stores protos in global slots", just a few cleanups.

I still need to test this on my mozjs45 branch.
Comment 27 Cosimo Cecchi 2017-04-11 20:26:46 UTC
Review of attachment 349651 [details] [review]:

It's a bit unfortunate that you need to add separate declarations for all the ensure_proto implementations, and that you have to enumerate all the values manually in GjsGlobalSlot, but I don't have a better approach to offer.
Comment 28 Cosimo Cecchi 2017-04-11 20:27:06 UTC
Review of attachment 349652 [details] [review]:

Nice
Comment 29 Cosimo Cecchi 2017-04-11 20:28:23 UTC
Review of attachment 349653 [details] [review]:

Again, a bit unfortunate that you have to add empty arrays for every case here, but not sure if there's a better approach.
Comment 30 Philip Chimento 2017-04-12 02:35:07 UTC
Comment on attachment 349652 [details] [review]
jsapi-dynamic-class: Use JS_LinkConstructorAndPrototype()

Attachment 349652 [details] pushed as bd36b0b - jsapi-dynamic-class: Use JS_LinkConstructorAndPrototype()
Comment 31 Philip Chimento 2017-04-12 07:00:53 UTC
Created attachment 349704 [details] [review]
importer: Add a JSClass constant

We use a js::Class for the importer rather than a JSClass, but it is
easier to include a JSClass constant as well so that we don't have to
keep casting back to JSClass with js::Jsvalify().
Comment 32 Philip Chimento 2017-04-12 07:00:59 UTC
Created attachment 349705 [details] [review]
WIP - 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. This is a sample of how that work
looks when it's done.

FIXME - ByteArray already does something similar, but can be accomplished
in less code using these macros.
Comment 33 Philip Chimento 2017-04-12 07:08:00 UTC
This last patch is an example of what the cleanups would look like when applied to the other native classes. I checked on my mozjs45 branch and this is indeed required for SpiderMonkey 45; I have it down to only one failing test now!

I still have to do repo.cpp and byteArray.cpp, and I might still do some refactoring on "GJS_DEFINE_PROTO stores protos in global slots"; it might be if we pass in the module object to JS_InitClass then we don't even have to have gjs_WHATEVER_define_constructor() at all.

I do have an alternative to the macro hell; we could refactor it to use classes rather than macros. It would not solve the problem of having to add each class to the GjsGlobalSlot enum, though.
Comment 34 Cosimo Cecchi 2017-04-12 17:43:05 UTC
Review of attachment 349704 [details] [review]:

OK
Comment 35 Cosimo Cecchi 2017-04-12 18:05:51 UTC
(In reply to Philip Chimento from comment #33)
> This last patch is an example of what the cleanups would look like when
> applied to the other native classes. I checked on my mozjs45 branch and this
> is indeed required for SpiderMonkey 45; I have it down to only one failing
> test now!
> 
> I still have to do repo.cpp and byteArray.cpp, and I might still do some
> refactoring on "GJS_DEFINE_PROTO stores protos in global slots"; it might be
> if we pass in the module object to JS_InitClass then we don't even have to
> have gjs_WHATEVER_define_constructor() at all.

Sounds like a good plan, and I like the cleanup quite a bit.
 
> I do have an alternative to the macro hell; we could refactor it to use
> classes rather than macros. It would not solve the problem of having to add
> each class to the GjsGlobalSlot enum, though.

I don't particularly mind the macros -- they're not such an uncommon paradigm for this kind of things (see e.g. GObject).
Comment 36 Philip Chimento 2017-04-13 00:52:10 UTC
Comment on attachment 349704 [details] [review]
importer: Add a JSClass constant

Attachment 349704 [details] pushed as 7a0866c - importer: Add a JSClass constant
Comment 37 Philip Chimento 2017-04-13 06:13:23 UTC
Created attachment 349763 [details] [review]
jsapi-util: Split off class stuff into jsapi-class.h

I've been wishing I had done this for three days now; jsapi-util.h is far
too long, and it's no fun to recompile the entire program every time one
of the macros is changed. The class macros plus the dynamic class functions
make a fairly independent unit, so this seems logical.
Comment 38 Philip Chimento 2017-04-13 06:14:01 UTC
Still refactoring, but I split off this patch: it's driving me crazy to recompile the entire GJS every time :-)
Comment 39 Cosimo Cecchi 2017-04-13 23:55:46 UTC
Review of attachment 349763 [details] [review]:

Looks good.

::: gjs/jsapi-class.h
@@ +23,3 @@
+
+#ifndef GJS_JSAPI_CLASS_H
+#define GJS_JSAPI_CLASS_H

As an aside, any reason not to start using #pragma once? Or is that not compatible with Visual Studio?
Comment 40 Philip Chimento 2017-04-14 02:28:06 UTC
(In reply to Cosimo Cecchi from comment #39)
> As an aside, any reason not to start using #pragma once? Or is that not
> compatible with Visual Studio?

I don't know for sure, but it often doesn't support nice nonstandard extensions.
Comment 41 Philip Chimento 2017-04-14 02:33:13 UTC
Comment on attachment 349763 [details] [review]
jsapi-util: Split off class stuff into jsapi-class.h

Attachment 349763 [details] pushed as aa60fc5 - jsapi-util: Split off class stuff into jsapi-class.h
Comment 42 Philip Chimento 2017-04-14 03:04:35 UTC
Created attachment 349846 [details] [review]
jsapi-class: Get rid of "proto_name" argument

There's no need to have a "proto_name" that's different from the class's
name. Getting rid of this distinction will allow us to refactor things so
that JS_InitClass() defines the correct constructor directly on the global
object or the module object.

This is a small behavioural API break, since it changes the output of
toString() on the various Cairo objects, but I would say that people
should not be parsing the output of toString(). (I know we do in our tests,
but that's terrible.)
Comment 43 Philip Chimento 2017-04-14 03:18:23 UTC
Created attachment 349847 [details] [review]
jsapi-class: GJS_DEFINE_PROTO stores protos in global slots

This refactors the GJS_DEFINE_PROTO family of macros to store the created
prototype objects in slots on the global object. We split up the
gjs_WHATEVER_create_proto() function into two functions: one that must be
called at least once for each type to define the class, store the prototype
in a global slot, and define the constructor as a property on a passed-in
module or global object, gjs_WHATEVER_define_proto(); and one that
retrieves the prototype from its global slot, gjs_WHATEVER_get_proto().

We also add two macros, GJS_DEFINE_PROTO_WITH_PARENT and
GJS_DEFINE_PROTO_ABSTRACT_WITH_PARENT, which also move the definition of
the parent to compile time rather than runtime, and keep it in the same
place as the rest of each class's macro definition. Similarly, previously
we had to pass the parent prototype object to gjs_WHATEVER_create_proto().

This mostly affects the cairo module.
Comment 44 Philip Chimento 2017-04-14 03:20:08 UTC
This newest patch is, I think, a better version of the previous attempt. We don't need an extra GJS_EXPORT_PROTO macro. Instead, we directly pass in the global object or module object so that the constructor is defined as part of JS_InitClass().
Comment 45 Philip Chimento 2017-04-14 03:26:01 UTC
Created attachment 349848 [details] [review]
jsapi-util: Add static function spec to GJS_DEFINE_PROTO

This allows the GJS_DEFINE_PROTO_* family of macros to have a JSFunctionSpec
array for functions defined on the constructor, rather than on the
prototype: i.e. static functions.

We clean up an incongruity in cairo-image-surface.cpp where you had to pass
the constructor into gjs_cairo_image_surface_init() in order to get the
static functions defined.
Comment 46 Philip Chimento 2017-04-14 03:26:48 UTC
No change in this patch, just a rebase of the previous version.
Comment 47 Philip Chimento 2017-04-14 03:46:29 UTC
Review of attachment 349847 [details] [review]:

::: gjs/jsapi-class.h
@@ +227,3 @@
     JS::RootedId class_name(cx,                                              \
         gjs_intern_string_to_id(cx, gjs_##cname##_class.name));              \
+    if (ctor != nullptr) {                                                   \

There is one problem still with this patch: this line warns that "ctor" will never be null when you pass a constructor function. I seem to be having trouble to get _Pragma("GCC diagnostic ignored -Waddress") to ignore it, which may be because of the macro definition.

Or I could do something ridiculous like if (strcmp(#ctor, "nullptr")) but that's ridiculous.
Comment 48 Philip Chimento 2017-04-15 07:10:29 UTC
Created attachment 349883 [details] [review]
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.
Comment 49 Philip Chimento 2017-04-17 03:20:36 UTC
Review of attachment 349847 [details] [review]:

::: gjs/jsapi-class.h
@@ +227,3 @@
     JS::RootedId class_name(cx,                                              \
         gjs_intern_string_to_id(cx, gjs_##cname##_class.name));              \
+    if (ctor != nullptr) {                                                   \

Maybe the best solution would be to skip the check, and look up the constructor function, even in the case where we could optimize by assuming it's equal to the prototype object.
Comment 50 Cosimo Cecchi 2017-04-18 01:05:26 UTC
Review of attachment 349846 [details] [review]:

Looks good.
Comment 51 Cosimo Cecchi 2017-04-18 01:08:50 UTC
Review of attachment 349847 [details] [review]:

::: gjs/jsapi-class.h
@@ +227,3 @@
     JS::RootedId class_name(cx,                                              \
         gjs_intern_string_to_id(cx, gjs_##cname##_class.name));              \
+    if (ctor != nullptr) {                                                   \

I think that's the best approach here; it's not like this function is called in a hot path anyway, right?
Comment 52 Cosimo Cecchi 2017-04-18 01:11:24 UTC
Review of attachment 349848 [details] [review]:

I think I complained before about the fact that this introduces another array that has a default empty value most of the times, but if there's no way around it...
Comment 53 Cosimo Cecchi 2017-04-18 01:14:03 UTC
Review of attachment 349883 [details] [review]:

++
Comment 54 Philip Chimento 2017-04-18 02:53:27 UTC
Comment on attachment 349846 [details] [review]
jsapi-class: Get rid of "proto_name" argument

Attachment 349846 [details] pushed as dcc82c3 - jsapi-class: Get rid of "proto_name" argument
Comment 55 Philip Chimento 2017-04-18 03:03:27 UTC
Created attachment 349966 [details] [review]
jsapi-class: GJS_DEFINE_PROTO stores protos in global slots

This refactors the GJS_DEFINE_PROTO family of macros to store the created
prototype objects in slots on the global object. We split up the
gjs_WHATEVER_create_proto() function into two functions: one that must be
called at least once for each type to define the class, store the prototype
in a global slot, and define the constructor as a property on a passed-in
module or global object, gjs_WHATEVER_define_proto(); and one that
retrieves the prototype from its global slot, gjs_WHATEVER_get_proto().

We also add two macros, GJS_DEFINE_PROTO_WITH_PARENT and
GJS_DEFINE_PROTO_ABSTRACT_WITH_PARENT, which also move the definition of
the parent to compile time rather than runtime, and keep it in the same
place as the rest of each class's macro definition. Similarly, previously
we had to pass the parent prototype object to gjs_WHATEVER_create_proto().

This mostly affects the cairo module.
Comment 56 Philip Chimento 2017-04-18 03:08:20 UTC
(In reply to Cosimo Cecchi from comment #52)
> Review of attachment 349848 [details] [review] [review]:
> 
> I think I complained before about the fact that this introduces another
> array that has a default empty value most of the times, but if there's no
> way around it...

There are a few ways around it: 1) we could just not do the refactor, it's quite minor. 2) we could make the refactor bigger and move away from macros...
Comment 57 Philip Chimento 2017-04-19 03:35:23 UTC
I went ahead and pushed it with the approach that you acked in the previous review.

Attachment 349848 [details] pushed as 4b8dcca - jsapi-util: Add static function spec to GJS_DEFINE_PROTO
Attachment 349883 [details] pushed as d794f31 - js: Create objects with JS_NewObjectWithGivenProto()
Attachment 349966 [details] pushed as 8807af7 - jsapi-class: GJS_DEFINE_PROTO stores protos in global slots
Comment 58 Richard Jones 2017-12-10 14:33:43 UTC
This patch seems to introduce an assertion in some existing gobject bindings which have worked fine til now:

https://bugzilla.redhat.com/show_bug.cgi?id=1524125

Gjs:ERROR:gjs/byteArray.cpp:824:JSObject* gjs_byte_array_get_proto(JSContext*): assertion failed: (((void) "gjs_" "byte_array" "_define_proto() must be called before " "gjs_" "byte_array" "_get_proto()", !v_proto.isUndefined()))

This is when calling from C back into gobject code.

Is some change required to gis code or is it supposed to be internal?
Comment 59 Philip Chimento 2017-12-23 16:08:24 UTC
This is supposed to be internal, so what you found sounds like a bug in GJS.

Would you mind opening a bug on gitlab.gnome.org/GNOME/gjs with a minimal example or a link to the failing JS code? Thanks!
Comment 60 Richard Jones 2017-12-23 17:17:51 UTC
Trying to create an account on gitlab.gnome.org results in a 500
server error, so I couldn't do that.

However I have posted the affected code here (it is generated which
is why it's quite long):

http://oirase.annexia.org/tmp/gobject/src/session.c
(in the function event_callback where it calls g_signal_emit)
Comment 61 Philip Chimento 2017-12-24 14:05:16 UTC
(In reply to Richard Jones from comment #60)
> Trying to create an account on gitlab.gnome.org results in a 500
> server error, so I couldn't do that.

Could you try again please? You can also log in with a GitHub or several other kinds of account, if you have one. I won't be able to track this problem here.
Comment 62 Richard Jones 2018-01-25 15:55:19 UTC
After spending another 5 minutes doing the stupid "captcha", I
still got a 500 error.  Is there not some other forum where one
can file bugs?
Comment 63 Philip Chimento 2018-01-26 06:57:29 UTC
Please join #sysadmin or #gnome-hackers on IRC and ask csoriano or av about the login problems. This seems like a pretty serious problem with the GitLab instance. That said, I haven't seen any service outages on gitlab.gnome.org myself, so I wonder if there's a problem with account creation specifically.
Comment 64 Richard Jones 2018-01-26 12:51:44 UTC
Bug submitted here:
https://gitlab.gnome.org/GNOME/gjs/issues/39