| Commit message (Collapse) | Author | Age | Files | Lines |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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
|
|
|
|
|
|
|
|
| |
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.
|
|
|
|
| |
In particular, in finalize operations.
|
|
|
|
|
| |
This has some cascade effects on the signatures of other methods, since
we now need to pass the JSTracer in.
|
| |
|
|
|
|
| |
See: https://bugzilla.mozilla.org/show_bug.cgi?id=1754405
|
|
|
|
|
|
|
|
|
|
|
| |
- 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::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>
|
|
|
|
|
|
|
| |
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.
|
|
|
|
|
|
|
| |
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
|
|\
| |
| |
| |
| |
| |
| | |
object: Use std::vector to hold Objects GClosure's
Closes #485
See merge request GNOME/gjs!758
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| | |
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
|
|/
|
|
|
|
|
|
|
|
|
|
| |
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.
|
|
|
|
|
|
|
|
| |
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
|
|
|
|
| |
Fixes #467
|
|
|
|
|
|
| |
There is a new API that ensures that all fields of the property descriptor
are set coherently ("complete"). setSetterObject() and setGetterObject()
no longer exist.
|
|
|
|
|
|
|
|
| |
- 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
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
|
|
|
|
|
|
| |
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.)
|
|
|
|
|
|
|
|
|
|
| |
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.
|
|
|
|
|
|
|
|
| |
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.
|
|
|
|
| |
Co-authored-by: Philip Chimento <philip.chimento@gmail.com>
|
|
|
|
|
|
|
|
|
| |
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
|
|
|
|
|
|
|
|
| |
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)
|
|
|
|
|
|
| |
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.
|
|
|
|
|
|
|
| |
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.
|
|
|
|
|
|
|
|
|
|
|
|
| |
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
|
|
|
|
|
|
|
|
| |
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
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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 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.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
|
|
|
|
|
|
|
|
|
|
| |
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
|
|
|
|
|
|
|
|
| |
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.
|
|
|
|
|
| |
We can handle the cleanups better and as bonus point we avoid allocating
the return gvalue when not needed.
|
|
|
|
|
|
|
|
|
| |
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.
|
| |
|
|
|
|
|
|
|
| |
- 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
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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
|
| |
|