summaryrefslogtreecommitdiff
path: root/gi/object.cpp
Commit message (Collapse)AuthorAgeFilesLines
* stack: Print stack trace using glib logging functionsSebastian Keller2023-04-061-4/+2
| | | | | | | | | | | | | | | | When the gjs process is logging to the systemd journal directly via the glib logging functions, the stack trace would get logged indirectly via stderr. This however is not guaranteed to get added to the journal at the same time as the error messages logged via glib. This is especially noticeable when triggered from an endless loop or an idle callback. In some cases it even can result in the stack trace not getting logged at all. There is currently no public API in mozjs to dump a stack trace directly to a string from arbitrary threads, only to files, so this uses open_memstream() as a workaround. Related: https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/1868
* function: Do not leak strings returned by transfer-none trampolinesMarco Trevisan (Treviño)2023-03-041-0/+14
| | | | | | | | | | | | | When a VFunc or a callback returns a transfer-none string we were breaking the introspection because it was causing a leak. Now, in case these strings are returned by vfunc's of an object, we can just safely associate them to the object using qdata, while in case we're handling a callback we can use GLib internal strings to hold these strings just once in memory. While this is technically still a waste we're leaking just once, so it shouldn't be a big deal. Closes: #519
* maint: Update includes to match new version of IWYUPhilip Chimento2022-11-151-2/+1
|
* Revert "closure: Store JSFunction* pointer instead of JSObject*"Philip Chimento2022-11-061-22/+20
| | | | | | | | | | | | | | | | | | | This is basically a revert of commit 7140cac8, although so much has changed in the meantime that none of the revert applied cleanly, so it's more of an "un-rewrite". This fixes a regression that has been present for almost exactly 4 years. Storing a JSFunction* pointer in closures did not take into account the fact that not all callable JSObjects have an associated JSFunction. They could be exotic objects with a [[Call]] method. In particular, introspected functions are this, so this prevented g-i function objects from being used as signal handlers. (Less importantly, the same probably applied to callable Proxy objects.) Also adds a regression test so that this doesn't happen again. Closes: #518
* object: Try to lookup an object parent prototype from the parent gtypeMarco Trevisan (Treviño)2022-10-291-0/+6
| | | | | | | | In some cases we were not able to find the parent prototype by just looking at the saved gtypes, as they may be static types defined in C. This was leading to errors when initializing from static functions, so fix this.
* js: Replace JSFreeOp with JS::GCContextEvan Welsh2022-08-071-2/+2
| | | | In particular, in finalize operations.
* js: Add JSTracer* argument to JS_UpdateWeakPointerAfterGC()Evan Welsh2022-08-071-6/+6
| | | | | This has some cascade effects on the signatures of other methods, since we now need to pass the JSTracer in.
* js: Remove hasInstance member from JSClassOpsEvan Welsh2022-08-071-1/+0
|
* js: Adapt to new JS::PropertyKey APIEvan Welsh2022-08-071-3/+3
| | | | See: https://bugzilla.mozilla.org/show_bug.cgi?id=1754405
* js: Various functions moved out of jsapi.hPhilip Chimento2022-08-071-2/+4
| | | | | | | | | | | - js/CallAndConstruct.h: Now contains JS::Call, JS::Construct, and related - js/Debug.h: Already existed, but now contains JS_DefineDebuggerObject - js/GlobalObject.h: Now contains JS::CurrentGlobalOrNull - js/PropertyAndElement.h: Now contains APIs for getting, setting, and defining properties, as well as array elements - js/ScriptPrivate.h: Now contains JS::GetScriptPrivate/SetScriptPrivate - js/Stack.h: Now contains APIs that have to do with the call stack
* js: Replace class private pointers with reserved slotsPhilip Chimento2022-08-061-3/+2
| | | | | | | | | | | | | | | | | | | | | | | | | | JS::GetPrivate() and JS::SetPrivate() are going away in SpiderMonkey 102. The replacement is to stuff the pointer into a JS::PrivateValue and store it in an object's reserved slot. This is a change we can make prior to the switch. With SpiderMonkey 102, we are intended to use JS::GetMaybePtrFromReservedSlot() to retrieve the pointer. This function doesn't exist in SpiderMonkey 91, but it is a small inline function that we can open-code in jsapi-util.h. In most of the cases, we can encapsulate this access into three methods of CWrapperPointerOps: has_private(), init_private(), and unset_private(). (Retrieving the pointer was already encapsulated by the various for_js() methods.) This provides better safety anyway, because in init_private() we can enforce that there was no pointer already set. We define that reserved slot 0 is always the private pointer. BoxedInstance already used slot 0 for something else, so that moves to slot 1. Based on Evan's commit from the mozjs102 branch. Co-authored-by: Evan Welsh <contact@evanwelsh.com>
* object: Add constructor argumentEvan Welsh2022-08-061-1/+1
| | | | | | | mozjs91 had a convenience constructor for Rooted that would also construct the template type if its constructor had a single JSContext* argument. This constructor will be removed in mozjs102, so we have to pass the JSContext twice here.
* js: Use JS::PropertyKey::isVoidEvan Welsh2022-08-061-4/+4
| | | | | | | JSID_VOID is going away in mozjs102. The replacement is the isVoid() method of JS::PropertyKey. See: https://bugzilla.mozilla.org/show_bug.cgi?id=1754405
* Merge branch 'use-vector-for-closures' into 'master'Philip Chimento2022-07-251-12/+12
|\ | | | | | | | | | | | | object: Use std::vector to hold Objects GClosure's Closes #485 See merge request GNOME/gjs!758
| * object: Use std::vector to hold Objects GClosure'sMarco Trevisan (Treviño)2022-06-141-12/+12
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | We used a std::forward list to hold closure pointers in Object's to avoid adding a vector when not needed, but these structures are terribly slow as already pointed out in [1], and demonstrated even way poorer performances when testing signal connections (see [2], #485 and !758), so get rid of them and just use vectors everywhere which can boost performances up to 95% in our tests. This implies some more memory usage for each object, as we can't use a std::vector without the size member since C++11, but I think it's still better, given that size of std::forward_list is still bigger when with only two closures/vfuncs added (as each element requires two pointers). Fixes: #485 [1] https://github.com/3v1n0/stl-containers-benchmarks [2] https://gitlab.gnome.org/3v1n0/gjs/-/snippets/3608
* | maint: Fix IWYU includes in files that previously failedPhilip Chimento2022-07-241-0/+2
|/ | | | | | | | | | | | Due to the bug fixed by the previous commit, many files' includes had gotten out of sync. This fixes all of the IWYU complaints. We need to add some lines to the mapping file, either due to an IWYU upgrade or changes in the header files; I'm not sure. It's annoying that we have to list all the glib/*.h files separately, but that is for two reasons: there is no glob for glib/* that can leave out <glib/gstdio.h> and other public GLib headers; and glib/galloca.h should redirect to the system alloca.h.
* gi: Use new GObject Introspection callable APIEvan Welsh2022-03-061-3/+2
| | | | | | | | This avoids misusing the closure pointer by creating a clear separation between the native closure pointer and the pointer to the libffi closure. Fixes #428
* gi: Store interface function overrides on the calling this objectEvan Welsh2022-02-261-5/+42
| | | | Fixes #467
* Use new property descriptor API to create complete descriptorPhilip Chimento2022-01-161-4/+4
| | | | | | There is a new API that ensures that all fields of the property descriptor are set coherently ("complete"). setSetterObject() and setGetterObject() no longer exist.
* Some Object-related functions have moved to js/Object.hEvan Welsh2022-01-161-1/+2
| | | | | | | | - JS_[Get,Set]Private is now JS::[Get,Set]Private - JS_GetReservedSlot is now JS::GetReservedSlot - JS_SetReservedSlot still exists, but we'll update it now See https://bugzilla.mozilla.org/show_bug.cgi?id=1663365
* js: Update includes for headers split out of JSAPIEvan Welsh2022-01-161-1/+2
| | | | | | | | | | | | | | | | | | | | | | Added - js/experimental/TypedData.h - js/friend/DumpFunctions.h - js/Context.h - js/MapAndSet.h - js/String.h Updated - js/ErrorReport.h - js/Exception.h - js/GCAPI.h - js/Realm.h Removed - js/RequiredDefines.h See https://bugzilla.mozilla.org/show_bug.cgi?id=1708330 See https://bugzilla.mozilla.org/show_bug.cgi?id=1656411 See https://bugzilla.mozilla.org/show_bug.cgi?id=1663365
* object: Fix interface property descriptor flagsPhilip Chimento2022-01-161-3/+3
| | | | | | | | | | | Before the previous commit, the new property descriptor got the default flags because JS::PropertyDescriptor didn't have a copy constructor, so it was always configurable and non-enumerable. This changes the property descriptor to be enumerable, since we generally define introspected API properties to be enumerable. JSPROP_SETTER and JSPROP_GETTER are already set by setGetterObject() and setSetterObject(), so we don't need to provide them explicitly here.
* object: Don't fetch property descriptor on interfacePhilip Chimento2022-01-161-10/+8
| | | | | | | It seems that nothing is actually used from the property descriptor, we only check if it exists, which can be done with JS_HasProperty. Contrary to what the comment says, the old descriptor is not copied (which will be fixed in the next commit.)
* object: Add null check for debug assertionPhilip Chimento2022-01-151-1/+2
| | | | | | | | | | Without this, we may get a sudden crash when debug is enabled, if we are typechecking an ObjectInstance with a null GObject pointer. This may occur for example if you forget to do super._init() in your class's _init() method, or it may be valid in some cases. If it's a bug in your JS code, continuing on will give a better diagnostic message than failing the assertion here.
* gi: Refactor resolving prototypes in GIWrapperInstance constructorsEvan Welsh2022-01-091-9/+21
| | | | | | | | This commit enables usecases where the JavaScript prototype may not be the same as the native Prototype object. Additionally this commit refactors ObjectInstance construction to match the new GIWrapperInstance constructor pattern.
* gi: Use accessors to dynamically fetch prototype propertiesEvan Welsh2021-10-161-29/+110
| | | | Co-authored-by: Philip Chimento <philip.chimento@gmail.com>
* gi: Use interface wrapper prototype to define implemented methodsEvan Welsh2021-10-151-3/+68
| | | | | | | | | This change uses the GJS interface wrapper to resolve interface methods instead of defining unique copies for each interface method. This allows for overriding methods on interfaces as long as the override exists before the method is resolved for the first time. Fixes #189
* JSID_* macros have been replaced with a class-based APIEvan Welsh2021-10-081-4/+4
| | | | | | | | See https://bugzilla.mozilla.org/show_bug.cgi?id=1717279 See https://bugzilla.mozilla.org/show_bug.cgi?id=1695736 (Philip: Replaced ATOM stuff with String, as all atom IDs are string IDs and vice versa)
* object: Combine consecutive if-blocksPhilip Chimento2021-09-301-2/+1
| | | | | | There were two if-blocks with the same condition, and the condition was not modified in the body of the first block. When combining them, the code looks slightly odd though, so clarify why this is correct with a comment.
* Correctly chain constructor prototypes to enable static inheritanceEvan Welsh2021-09-241-7/+41
| | | | | | | In ES2015+ classes it is expected for constructors to inherit the static methods of their parent class, our implementation of classes previously did not do this as it was uncommon in ES5 era classes.
* Store interface gtypes on dynamic classes to not clobber vfuncsEvan Welsh2021-09-191-17/+61
| | | | | | | | | | | | We previously used g_type_interfaces to look up interfaces when hooking up vfuncs. Unfortunately, g_type_interfaces returns all interfaces a class adheres to, including ones its parent implements. This commit retains the g_type_interfaces usage to provide a helpful error message. Fixes #89
* Ensure instance constructor values are chained from Gtk.Widgetewlsh/fix-blow-upEvan Welsh2021-09-041-9/+12
| | | | | | | | If a wrapper for a GObject has already been created, _init is supposed to return the correct wrapper instead. We were not handling this correctly for Gtk.Widget Fixes #50
* object: Use vector for holding the list of wrapped objectsMarco Trevisan (Treviño)2021-08-011-77/+27
| | | | | | | | | | | | | | | | There's no point to use a custom implementation of a double-linked list to hold the list of ObjectInstances we've around, however while this can be a fast option for adding/removing objects it's way slower during iterating at garbage collection, and vector is always faster in such operations when it comes when handling pointers [1]. As plus: - we avoid wasting memory for all the "next" pointers (doubled size) - we can remove elements using the swap-and-pop idiom (avoids resizes) - we resize the array forcing it to shrink at garbage collection - being a static member, we only waste once the space for the size [1] https://github.com/3v1n0/stl-containers-benchmarks
* GjsMaybeOwned: Remove notifier support and move it into GjsPrivateContextMarco Trevisan (Treviño)2021-08-011-1/+1
| | | | | | | | | | | | | | GjsMaybeOwned had a notification support that was used only by Closures (other than tests), this was causing adding an extra pointer to all the types using it (including Object) that was mostly unused. So, move this into private context, re-implementing it using our own notifier (instead of relying on GObject's that needs a specific order) and use it in closures. Also add an hook to handle gc events on private context that will be in later changes to cleanup more things, but for now is used to shrink the closures vector once we've done.
* GjsCallBackTrampoline: Inherit from Gjs::Closure (and so GClosure)Marco Trevisan (Treviño)2021-08-011-10/+7
| | | | | | | | | | | | | | | | The callback trampoline is in fact a GClosure, but we were just composing one. We can instead just inherit from it now, given that the Gjs::Closure will allocate the needed memory via the closure allocator and handle the references via native closure reference system (avoid to duplicate that). As per this, some less memory used as we save a pointer and the reference counting. The only bit we need to handle is the destruction as we need to be sure to call the proper type destructor on closure finalization. So, adding an utility function that ensures this happens for each type and that we won't call the base destructor twice.
* closure: Reimplement to be a C++ class with custom heap allocatorMarco Trevisan (Treviño)2021-08-011-6/+5
| | | | | | | | | | | | | To create closures we used to create an internal closure structure that for which we were handling construction and destruction manually. C++ allows us to use some nicer features though, and we can take advantage of them once we leave the role of allocating and deallocating the memory to GClosure functions. This can be nicely done overriding the new and delete operators that will give us the size to allocate exactly as the closure creator function expects to receive.
* object: Enqueue toggle ups when the heap is collectingEvan Welsh2021-08-011-1/+3
| | | | | | | | | | | | | | | | | From my research it seems like .get() triggers an ExposeGCThingToActiveJS call which can't be called while the heap is collecting - we guard against that case in expose_to_js. Fix this by just queuing toggle ups if the heap is collecting. I'm pretty sure we're hitting this case: https://gitlab.gnome.org/GNOME/glib/-/blob/main/gobject/gobject.c#L4635 I tested it and it seems like we're not getting a toggle up on the object that is actually being finalized, so my only thought is perhaps it is an object that the object getting temporarily toggled up holds a reference to? If that is the case, I think it makes sense to guard toggles while the heap is collecting.
* object: Avoid setting construct properties multiple timesCarlos Garnacho2021-06-211-0/+6
| | | | | | | | | | | Construct-only properties may be defined several times in JS land with different casings (snake, kebab, camel), but they all resolve to the same GParamSpec. For these cases, discard the redundant GParamSpec lookups when collecting the value array for g_object_new_with_properties(). Fixes: https://gitlab.gnome.org/GNOME/gjs/-/issues/422
* object: Invalidate closures while iterating, avoiding recursionMarco Trevisan (Treviño)2021-05-191-10/+21
| | | | | | | | Clean the closures callbacks while going through it, de-registering the related callbacks that may cause searching and removing elements from the closures list. This is not only safer, but also faster.
* object: Use AutoGValueVector to build a list of GValue signal argumentsMarco Trevisan (Treviño)2021-05-181-37/+21
| | | | | We can handle the cleanups better and as bonus point we avoid allocating the return gvalue when not needed.
* Value: add Gjs::AutoGValue and use this to handle lifetime of GValuesMarco Trevisan (Treviño)2021-05-181-18/+6
| | | | | | | | | Add a simple structure that wraps GValue that allows us handling lifetime of GValue's in a nicer way and redefine AutoGValueVector with it transparently. In this way the allocated data keeps being structured as GValues but we handle its initializations without errors.
* object: Make ensure_toggle_reference to follow the JS API so we can throwMarco Trevisan (Treviño)2021-05-181-13/+33
|
* object: Optimize a bit AutoGValueVector usageMarco Trevisan (Treviño)2021-05-171-7/+5
| | | | | | | - Reserve it before using - Initialize the GValue only when needed - Use move constructor (via emplace) to initialize it - Rely on vector destructor to unset it
* object: Move private callbacks to the private scopeMarco Trevisan (Treviño)2021-05-171-1/+1
|
* object: Rely on next ToggleQueue iteration to handle already queued toggle ↵Marco Trevisan (Treviño)2021-05-031-17/+6
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | events When handling the toggle events from the main thread, we may have received a notification for a toggle event from multiple threads concurrently causing us to consider this an error. For example: Object 0x555555643b30 Toggle up, from main thread 1, queued down 1, up 1 Object 0x555555643b30 Toggle down, from main thread 1, queued down 1, up 1 Object 0x555555643b30 Toggle up, from main thread 0, queued down 0, up 0 Object 0x555555643b30 Toggle up, from main thread 1, queued down 0, up 0 Object 0x555555643b30 Toggle down, from main thread 0, queued down 0, up 0 Object 0x555555643b30 Toggle down, from main thread 1, queued down 1, up 0 Till the introduction of locked operations during toggle notifications we may not be sure how to handle this, but now we can be quite confident that we're working with the actual toggle queue state and so when an already-toggled event happens we can just be sure that it will be handled at next idle, and so we can stop considering it an error. To avoid having a queue of events that have no result, change the enqueue code to cancel a previously queued event that is the opposite of the one we're adding. We need to be able to add multiple events of the same type though (as could come from different threads), so adapt the cancellation code to this. As it's just something we can't control our level, but depends on other threads fired by applications. What we can do is only react properly, and now we do. Fixes: #297
* toggle: Enforce thread-safety using a per-thread spin-lockMarco Trevisan (Treviño)2021-05-031-17/+23
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | While the ToggleQueue is expected to be thread-safe, unfortunately the way we use isn't always true. In fact, while we always perform operations locking the shared data, we may act on it depending on results that may have been changed by another thread. For example, we check if an object is queued or we cancel a queued object and we assume that this is true for the rest of the execution, but this may have been already changed meanwhile, thus we error later. This happens repeatedly with applications doing many fast threaded operations (an example can be triggered via GFileMonitor when the fs is particularly active as bug #297 shows). To avoid this, we need to ensure that all the access to the queue are locked till we're not done with it, but at the same time we must not to stop the owner thread to access multiple time to the queue while it owns the lock (as it may happen on recursion of we want group various operations). To do this, control public access to the queue only via a structure that uses a spin-lock to block non-holder threads and that uses a refcounted system to handle the unlocking. So, any time we get the queue, we have a locked control of it, once the ToggleQueue::Locked structure is released, we unlock it only if no other instances in the current thread are using it. This serves us particularly well in the toggle notification callback where we had cases in which we were adding duplicate objects to the queue even if they were already there or vice versa we were not adding them because we the situation changed since the call to is_queued(). Now instead, we can be sure that each thread will work on the current queue state and behave accordingly. Related-to: #297
* toggle: Keep track of objects via ObjectInstance not GObject'sMarco Trevisan (Treviño)2021-05-031-37/+38
| | | | | | | | | | | | | | | | | | | | | | While the ToggleQueue serves us to track GObject's using their pointers is too fragile for us, because they can be also finalized from other threads and we may not be able to track when this happens, leaving them in the queue to be handled by the main thread, causing us to access to invalid memory. At the contrary, we totally control the life time of ObjectInstance's and we're sure that they always are created and destroyed in the main thread, so let's use them even inside the ToggleQueue. In this way: - We can keep using the same strategy to enqueue them - We don't have to rely on monitoring GObject's finalization to clear the queue (that again may not happen in main thread). - When an object wrapper is destroyed, we are sure that we've removed the gobject toggle reference, and so that we'll never get another toggle event queued again till another wrapper is created. Related to: #404
* toggle: Rely on wrapper to cancel finalized objects in queueMarco Trevisan (Treviño)2021-05-031-4/+6
| | | | | | | | | | | | | | | | | | | | | | | | While GObject provides native tools to check if an object has been finalized using GWeakRef's, they have proved to be too fragile for us because they don't work well when used with toggle references notifications (not thread safe as glib#2384 demonstrates) and because may not be cleared on finalization (glib#2390). So, instead of adding further qdata to monitor a queued object finalization, let's just ensure that a wrapper cancels the toggle queue when its wrapped object get finalized. Since we don't touch the references of the object while adding it to the queue, we can also ignore remembering the current handled object, as no recursion can happen now. It may still happen (mostly due to the way we lock) that a finalized or unhandled object will be handled by the toggle handler, but this can't be really fixed for all the racy cases even at enqueue phase (like in the case a thread enqueues a toggle event just after we've disassociated the wrapper for such object). Fixes: #404
* object: Block access to object only if it is finalizedMarco Trevisan (Treviño)2021-04-271-13/+22
| | | | | | | | | | | | | | | | | For some time now we're warning whether a disposed object is used and this is sane, however the data it holds may be still valid and in general all the C code we access to is meant to be used after disposition. While such code has not to be called when the object is finalized. Since now we properly track objects finalization we can go back to allow most of the object actions (all but the signals connections, these involve having toggle notifications that are not a tool we can use at this point) with the actual object pointer. In case the object is finalized instead we behave exactly as before. Adapted tests and added ones for finalization case
* object: Improve debugging during wrapping/unwrapping GObjectMarco Trevisan (Treviño)2021-04-221-2/+6
|