Merge ~3v1n0/ubuntu/+source/gjs:ubuntu/bionic into ~ubuntu-desktop/ubuntu/+source/gjs:ubuntu/bionic

Proposed by Marco Trevisan (Treviño)
Status: Merged
Approved by: Jeremy Bícha
Approved revision: b7075ca403da21571a7caad617fb22f584ea0b29
Merged at revision: b7075ca403da21571a7caad617fb22f584ea0b29
Proposed branch: ~3v1n0/ubuntu/+source/gjs:ubuntu/bionic
Merge into: ~ubuntu-desktop/ubuntu/+source/gjs:ubuntu/bionic
Diff against target: 1653 lines (+481/-189)
22 files modified
Makefile.in (+2/-3)
NEWS (+73/-0)
configure (+43/-13)
configure.ac (+13/-2)
debian/changelog (+10/-0)
debian/control (+4/-2)
debian/gbp.conf (+3/-2)
dev/null (+0/-6)
gi/gtype.cpp (+12/-3)
gi/object.cpp (+227/-86)
gi/object.h (+2/-0)
gjs/context-private.h (+2/-0)
gjs/context.cpp (+33/-6)
gjs/engine.cpp (+8/-21)
gjs/importer.cpp (+1/-1)
gjs/jsapi-util-root.h (+7/-4)
gjs/jsapi-util.cpp (+5/-3)
installed-tests/extra/gjs.supp (+23/-29)
installed-tests/extra/lsan.supp (+0/-3)
modules/overrides/GObject.js (+8/-0)
modules/tweener/tweener.js (+1/-1)
win32/config.h.win32 (+4/-4)
Reviewer Review Type Date Requested Status
Ubuntu Desktop Pending
Review via email: mp+361167@code.launchpad.net
To post a comment you must log in.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
diff --git a/Makefile.in b/Makefile.in
index fea2a6b..ed5566b 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -756,9 +756,8 @@ am__DIST_COMMON = $(srcdir)/Makefile-examples.am \
756 $(srcdir)/config.h.in $(srcdir)/gjs-1.0.pc.in \756 $(srcdir)/config.h.in $(srcdir)/gjs-1.0.pc.in \
757 $(srcdir)/gjs-modules-srcs.mk $(srcdir)/gjs-srcs.mk \757 $(srcdir)/gjs-modules-srcs.mk $(srcdir)/gjs-srcs.mk \
758 $(top_srcdir)/win32/config.h.win32.in AUTHORS COPYING \758 $(top_srcdir)/win32/config.h.win32.in AUTHORS COPYING \
759 ChangeLog INSTALL NEWS README compile config.guess \759 ChangeLog INSTALL NEWS README compile config.guess config.sub \
760 config.rpath config.sub depcomp install-sh ltmain.sh missing \760 depcomp install-sh ltmain.sh missing tap-driver.sh
761 tap-driver.sh
762DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)761DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
763distdir = $(PACKAGE)-$(VERSION)762distdir = $(PACKAGE)-$(VERSION)
764top_distdir = $(distdir)763top_distdir = $(distdir)
diff --git a/NEWS b/NEWS
index 43feb1f..1e33aa5 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,76 @@
1Version 1.52.5
2--------------
3
4- This release includes the "Big Hammer" patch from GNOME 3.30 to reduce memory
5 usage. For more information, read the blog post at
6 https://feaneron.com/2018/04/20/the-infamous-gnome-shell-memory-leak/
7 It was not originally intended to be backported to GNOME 3.28, but in practice
8 several Linux distributions already backported it, and it has been working
9 well to reduce memory usage, and the bugs have been ironed out of it.
10
11 It does decrease performance somewhat, so if you don't want that then don't
12 install this update.
13
14- Closed bugs and merge requests:
15
16 * Ensure not to miss the force_gc flag [#150, !132, Carlos Garnacho]
17 * Make GC much more aggressive [#62, !50, Giovanni Campagna, Georges Basile
18 Stavracas Neto, Philip Chimento]
19 * Queue GC when a GObject reference is toggled down [#140, !114, !127, Georges
20 Basile Stavracas Neto]
21 * Reduce memory overhead of g_object_weak_ref() [#144, !122, Carlos Garnacho,
22 Philip Chimento]
23 * context: Defer and therefore batch forced GC runs [performance] [!236,
24 Daniel van Vugt]
25 * context: use timeout with seconds to schedule a gc trigger [!239, Marco
26 Trevisan]
27 * Use compacting GC on RSS size growth [!133, #151, Carlos Garnacho]
28 * GType memleak fixes [!244, Marco Trevisan]
29
30Version 1.52.4
31--------------
32
33- Closed bugs and merge requests:
34
35 * `ARGV` encoding issues [#22, !108, Evan Welsh]
36 * Segfault on enumeration of GjSFileImporter properties when a searchpath
37 entry contains a symlink [#154, !144, Ole Jørgen Brønner]
38 * Possible refcounting bug around GtkListbox signal handlers [#24, !154,
39 Philip Chimento]
40 * Fix up GJS_DISABLE_JIT flag now the JIT is enabled by default in
41 SpiderMonkey [!159, Christopher Wheeldon]
42 * Expose GObject static property symbols. [!197, Evan Welsh]
43 * Do not run linters on tagged commits [!181, Claudio André]
44 * gjs-1.52.0 fails to compile against x86_64 musl systems [#132, !214, Philip
45 Chimento]
46 * gjs no longer builds after recent autoconf-archive updates [#149, !217,
47 Philip Chimento]
48
49Version 1.52.3
50--------------
51
52- Closed bugs and merge requests:
53
54 * Include calc.js example from Seed [!130, William Barath, Philip Chimento]
55 * CI: Un-pin the Fedora Docker image [#141, !131, Claudio André]
56 * Reduce overhead of wrapped objects [#142, !121, Carlos Garnacho, Philip
57 Chimento]
58 * Various CI changes [!134, !136, Claudio André]
59
60Version 1.52.2
61--------------
62
63- This is an unscheuled release in order to revert a commit that causes a crash
64 on exit, with some Cairo versions.
65
66- Closed bugs and merge requests:
67
68 * CI: pinned Fedora to old tag [!119, Claudio André]
69 * heapgraph.py: adjust terminal output style [!120, Andy Holmes]
70 * CI: small tweaks [!123, Claudio André]
71 * Warn about compilation warnings [!125, Claudio André]
72 * Miscellaneous commits [Philip Chimento, Jason Hicks]
73
1Version 1.52.174Version 1.52.1
2--------------75--------------
376
diff --git a/config.rpath b/config.rpath
4deleted file mode 10064477deleted file mode 100644
index e69de29..0000000
--- a/config.rpath
+++ /dev/null
diff --git a/configure b/configure
index 8410fb2..b79e278 100755
--- a/configure
+++ b/configure
@@ -1,6 +1,6 @@
1#! /bin/sh1#! /bin/sh
2# Guess values for system-dependent variables and create Makefiles.2# Guess values for system-dependent variables and create Makefiles.
3# Generated by GNU Autoconf 2.69 for gjs 1.52.1.3# Generated by GNU Autoconf 2.69 for gjs 1.52.5.
4#4#
5# Report bugs to <http://bugzilla.gnome.org/enter_bug.cgi?product=gjs>.5# Report bugs to <http://bugzilla.gnome.org/enter_bug.cgi?product=gjs>.
6#6#
@@ -591,8 +591,8 @@ MAKEFLAGS=
591# Identity of this package.591# Identity of this package.
592PACKAGE_NAME='gjs'592PACKAGE_NAME='gjs'
593PACKAGE_TARNAME='gjs'593PACKAGE_TARNAME='gjs'
594PACKAGE_VERSION='1.52.1'594PACKAGE_VERSION='1.52.5'
595PACKAGE_STRING='gjs 1.52.1'595PACKAGE_STRING='gjs 1.52.5'
596PACKAGE_BUGREPORT='http://bugzilla.gnome.org/enter_bug.cgi?product=gjs'596PACKAGE_BUGREPORT='http://bugzilla.gnome.org/enter_bug.cgi?product=gjs'
597PACKAGE_URL='https://wiki.gnome.org/Projects/Gjs'597PACKAGE_URL='https://wiki.gnome.org/Projects/Gjs'
598598
@@ -1451,7 +1451,7 @@ if test "$ac_init_help" = "long"; then
1451 # Omit some internal or obsolete options to make the list less imposing.1451 # Omit some internal or obsolete options to make the list less imposing.
1452 # This message is too long to be a string in the A/UX 3.1 sh.1452 # This message is too long to be a string in the A/UX 3.1 sh.
1453 cat <<_ACEOF1453 cat <<_ACEOF
1454\`configure' configures gjs 1.52.1 to adapt to many kinds of systems.1454\`configure' configures gjs 1.52.5 to adapt to many kinds of systems.
14551455
1456Usage: $0 [OPTION]... [VAR=VALUE]...1456Usage: $0 [OPTION]... [VAR=VALUE]...
14571457
@@ -1521,7 +1521,7 @@ fi
15211521
1522if test -n "$ac_init_help"; then1522if test -n "$ac_init_help"; then
1523 case $ac_init_help in1523 case $ac_init_help in
1524 short | recursive ) echo "Configuration of gjs 1.52.1:";;1524 short | recursive ) echo "Configuration of gjs 1.52.5:";;
1525 esac1525 esac
1526 cat <<\_ACEOF1526 cat <<\_ACEOF
15271527
@@ -1700,7 +1700,7 @@ fi
1700test -n "$ac_init_help" && exit $ac_status1700test -n "$ac_init_help" && exit $ac_status
1701if $ac_init_version; then1701if $ac_init_version; then
1702 cat <<\_ACEOF1702 cat <<\_ACEOF
1703gjs configure 1.52.11703gjs configure 1.52.5
1704generated by GNU Autoconf 2.691704generated by GNU Autoconf 2.69
17051705
1706Copyright (C) 2012 Free Software Foundation, Inc.1706Copyright (C) 2012 Free Software Foundation, Inc.
@@ -2251,7 +2251,7 @@ cat >config.log <<_ACEOF
2251This file contains any messages produced by compilers while2251This file contains any messages produced by compilers while
2252running configure, to aid debugging if configure makes a mistake.2252running configure, to aid debugging if configure makes a mistake.
22532253
2254It was created by gjs $as_me 1.52.1, which was2254It was created by gjs $as_me 1.52.5, which was
2255generated by GNU Autoconf 2.69. Invocation command line was2255generated by GNU Autoconf 2.69. Invocation command line was
22562256
2257 $ $0 $@2257 $ $0 $@
@@ -3114,7 +3114,7 @@ fi
31143114
3115# Define the identity of the package.3115# Define the identity of the package.
3116 PACKAGE='gjs'3116 PACKAGE='gjs'
3117 VERSION='1.52.1'3117 VERSION='1.52.5'
31183118
31193119
3120cat >>confdefs.h <<_ACEOF3120cat >>confdefs.h <<_ACEOF
@@ -3341,10 +3341,10 @@ ac_config_headers="$ac_config_headers config.h"
33413341
33423342
33433343
3344GJS_VERSION=152013344GJS_VERSION=15205
33453345
33463346
3347$as_echo "#define GJS_VERSION (1 * 100 + 52) * 100 + 1" >>confdefs.h3347$as_echo "#define GJS_VERSION (1 * 100 + 52) * 100 + 5" >>confdefs.h
33483348
33493349
3350GETTEXT_PACKAGE=gjs3350GETTEXT_PACKAGE=gjs
@@ -21806,6 +21806,7 @@ fi
2180621806
21807if test x$enable_profiler != xno; then :21807if test x$enable_profiler != xno; then :
2180821808
21809 # Requires timer_settime() - only on Linux
2180921810
2181021811
2181121812
@@ -21886,8 +21887,37 @@ done
2188621887
21887 LIBS=$gl_saved_libs21888 LIBS=$gl_saved_libs
2188821889
21889 if test x$ac_cv_func_timer_settime = xno; then :21890 # Requires SIGEV_THREAD_ID - not in some stdlibs
21891 have_sigev_thread_id=no
21892 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Linux SIGEV_THREAD_ID" >&5
21893$as_echo_n "checking for Linux SIGEV_THREAD_ID... " >&6; }
21894 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
21895/* end confdefs.h. */
21896
21897 #include <signal.h>
21898int
21899main ()
21900{
21901return SIGEV_THREAD_ID;
21902 ;
21903 return 0;
21904}
21905
21906_ACEOF
21907if ac_fn_cxx_try_compile "$LINENO"; then :
21908
21909 have_sigev_thread_id=yes
21910 { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
21911$as_echo "yes" >&6; }
21912
21913else
21914 { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
21915$as_echo "no" >&6; }
21916fi
21917rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
21918 if test x$ac_cv_func_timer_settime = xno -o x$have_sigev_thread_id = xno; then :
21890 as_fn_error $? "The profiler is currently only supported on Linux.21919 as_fn_error $? "The profiler is currently only supported on Linux.
21920The standard library must support timer_settime() and SIGEV_THREAD_ID.
21891Configure with --disable-profiler to skip it on other platforms." "$LINENO" 521921Configure with --disable-profiler to skip it on other platforms." "$LINENO" 5
21892fi21922fi
2189321923
@@ -23346,7 +23376,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
23346# report actual input values of CONFIG_FILES etc. instead of their23376# report actual input values of CONFIG_FILES etc. instead of their
23347# values after options handling.23377# values after options handling.
23348ac_log="23378ac_log="
23349This file was extended by gjs $as_me 1.52.1, which was23379This file was extended by gjs $as_me 1.52.5, which was
23350generated by GNU Autoconf 2.69. Invocation command line was23380generated by GNU Autoconf 2.69. Invocation command line was
2335123381
23352 CONFIG_FILES = $CONFIG_FILES23382 CONFIG_FILES = $CONFIG_FILES
@@ -23417,7 +23447,7 @@ _ACEOF
23417cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=123447cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
23418ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"23448ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
23419ac_cs_version="\\23449ac_cs_version="\\
23420gjs config.status 1.52.123450gjs config.status 1.52.5
23421configured by $0, generated by GNU Autoconf 2.69,23451configured by $0, generated by GNU Autoconf 2.69,
23422 with options \\"\$ac_cs_config\\"23452 with options \\"\$ac_cs_config\\"
2342323453
diff --git a/configure.ac b/configure.ac
index c7b7dcb..1c62d93 100644
--- a/configure.ac
+++ b/configure.ac
@@ -3,7 +3,7 @@
33
4m4_define(pkg_major_version, 1)4m4_define(pkg_major_version, 1)
5m4_define(pkg_minor_version, 52)5m4_define(pkg_minor_version, 52)
6m4_define(pkg_micro_version, 1)6m4_define(pkg_micro_version, 5)
7m4_define(pkg_version, pkg_major_version.pkg_minor_version.pkg_micro_version)7m4_define(pkg_version, pkg_major_version.pkg_minor_version.pkg_micro_version)
8m4_define(pkg_int_version, (pkg_major_version * 100 + pkg_minor_version) * 100 + pkg_micro_version)8m4_define(pkg_int_version, (pkg_major_version * 100 + pkg_minor_version) * 100 + pkg_micro_version)
99
@@ -152,9 +152,20 @@ AS_IF([test x$have_gtk = xyes], [
152AC_ARG_ENABLE([profiler],152AC_ARG_ENABLE([profiler],
153 [AS_HELP_STRING([--disable-profiler], [Don't build profiler])])153 [AS_HELP_STRING([--disable-profiler], [Don't build profiler])])
154AS_IF([test x$enable_profiler != xno], [154AS_IF([test x$enable_profiler != xno], [
155 # Requires timer_settime() - only on Linux
155 gl_TIMER_TIME156 gl_TIMER_TIME
156 AS_IF([test x$ac_cv_func_timer_settime = xno],157 # Requires SIGEV_THREAD_ID - not in some stdlibs
158 have_sigev_thread_id=no
159 AC_MSG_CHECKING([for Linux SIGEV_THREAD_ID])
160 AC_COMPILE_IFELSE([
161 AC_LANG_PROGRAM([[#include <signal.h>]], [return SIGEV_THREAD_ID;])
162 ], [
163 have_sigev_thread_id=yes
164 AC_MSG_RESULT([yes])
165 ], [AC_MSG_RESULT([no])])
166 AS_IF([test x$ac_cv_func_timer_settime = xno -o x$have_sigev_thread_id = xno],
157 [AC_MSG_ERROR([The profiler is currently only supported on Linux.167 [AC_MSG_ERROR([The profiler is currently only supported on Linux.
168The standard library must support timer_settime() and SIGEV_THREAD_ID.
158Configure with --disable-profiler to skip it on other platforms.])])169Configure with --disable-profiler to skip it on other platforms.])])
159 AC_DEFINE([ENABLE_PROFILER], [1], [Define if the profiler should be built.])170 AC_DEFINE([ENABLE_PROFILER], [1], [Define if the profiler should be built.])
160])171])
diff --git a/debian/changelog b/debian/changelog
index feae994..c276370 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,13 @@
1gjs (1.52.5-0~ubuntu18.04.1) UNRELEASED; urgency=medium
2
3 * New upstream release (LP: #1809181, LP: #1803271)
4 * d/p/fix-crashes-lp1763878-revert-575f1e2e077.patch,
5 d/p/fix-leaks-lp1672297-1-context-Add-API-to-force-GC-schedule.patch,
6 d/p/fix-leaks-lp1672297-2-object-Queue-a-forced-GC-when-toggling-down.patch:
7 - Drop patches included in new release
8 * debian/gbp.conf:
9 - Point branches and tag rules to ubuntu
10
1gjs (1.52.1-1ubuntu1) bionic; urgency=medium11gjs (1.52.1-1ubuntu1) bionic; urgency=medium
212
3 * Add fix-crashes-lp1763878-revert-575f1e2e077.patch to fix shutdown13 * Add fix-crashes-lp1763878-revert-575f1e2e077.patch to fix shutdown
diff --git a/debian/control b/debian/control
index bcbd2dc..d6cb30a 100644
--- a/debian/control
+++ b/debian/control
@@ -25,8 +25,10 @@ Build-Depends: debhelper (>= 11),
25 xvfb <!nocheck>25 xvfb <!nocheck>
26Rules-Requires-Root: no26Rules-Requires-Root: no
27Standards-Version: 4.1.327Standards-Version: 4.1.3
28Vcs-Git: https://salsa.debian.org/gnome-team/gjs.git28XS-Debian-Vcs-Browser: https://salsa.debian.org/gnome-team/gjs
29Vcs-Browser: https://salsa.debian.org/gnome-team/gjs29XS-Debian-Vcs-Git: https://salsa.debian.org/gnome-team/gjs.git -b debian/1.52.x
30Vcs-Browser: https://git.launchpad.net/~ubuntu-desktop/ubuntu/+source/gjs
31Vcs-Git: https://git.launchpad.net/~ubuntu-desktop/ubuntu/+source/gjs -b ubuntu/bionic
30Homepage: https://wiki.gnome.org/Projects/Gjs32Homepage: https://wiki.gnome.org/Projects/Gjs
3133
32Package: gjs34Package: gjs
diff --git a/debian/gbp.conf b/debian/gbp.conf
index e0196c4..0592ca0 100644
--- a/debian/gbp.conf
+++ b/debian/gbp.conf
@@ -1,5 +1,6 @@
1[DEFAULT]1[DEFAULT]
2pristine-tar = True2pristine-tar = True
3debian-branch = debian/master3debian-branch = debian/bionic
4upstream-branch = upstream/latest4debian-tag = ubuntu/%(version)s
5upstream-branch = upstream/1.52.x
5upstream-vcs-tag = %(version)s6upstream-vcs-tag = %(version)s
diff --git a/debian/patches/fix-crashes-lp1763878-revert-575f1e2e077.patch b/debian/patches/fix-crashes-lp1763878-revert-575f1e2e077.patch
6deleted file mode 1006447deleted file mode 100644
index 4da9220..0000000
--- a/debian/patches/fix-crashes-lp1763878-revert-575f1e2e077.patch
+++ /dev/null
@@ -1,69 +0,0 @@
1From 8510bede1dd1f8a5fb95a2f594b4d3a68289e5ea Mon Sep 17 00:00:00 2001
2From: Philip Chimento <philip.chimento@gmail.com>
3Date: Sat, 14 Apr 2018 16:25:58 -0700
4Subject: [PATCH] Revert "engine: Free Cairo static data on shutdown"
5
6This reverts commit 575f1e2e077af04a112b9e5eaabaf008b086568e.
7Per https://bugs.freedesktop.org/show_bug.cgi?id=105466, calling
8cairo_debug_reset_static_data() was supposed to be safe in production,
9but actually it fails assertions on program exit, with certain Cairo
10versions, including 1.14.12.
11
12Unreviewed.
13---
14 gjs/engine.cpp | 18 ++----------------
15 1 file changed, 2 insertions(+), 16 deletions(-)
16
17diff --git a/gjs/engine.cpp b/gjs/engine.cpp
18index 90fa57c..67911ee 100644
19--- a/gjs/engine.cpp
20+++ b/gjs/engine.cpp
21@@ -37,10 +37,6 @@
22 #include <windows.h>
23 #endif
24
25-#ifdef ENABLE_CAIRO
26-# include <cairo.h>
27-#endif
28-
29 /* Implementations of locale-specific operations; these are used
30 * in the implementation of String.localeCompare(), Date.toLocaleDateString(),
31 * and so forth. We take the straight-forward approach of converting
32@@ -218,16 +214,6 @@ on_promise_unhandled_rejection(JSContext *cx,
33 std::move(stack));
34 }
35
36-static void
37-shutdown(void)
38-{
39- JS_ShutDown();
40-
41-#ifdef ENABLE_CAIRO
42- cairo_debug_reset_static_data(); /* for valgrind reports */
43-#endif
44-}
45-
46 #ifdef G_OS_WIN32
47 HMODULE gjs_dll;
48 static bool gjs_is_inited = false;
49@@ -245,7 +231,7 @@ LPVOID lpvReserved)
50 break;
51
52 case DLL_THREAD_DETACH:
53- shutdown();
54+ JS_ShutDown ();
55 break;
56
57 default:
58@@ -265,7 +251,7 @@ public:
59 }
60
61 ~GjsInit() {
62- shutdown();
63+ JS_ShutDown();
64 }
65
66 operator bool() {
67--
682.17.0
69
diff --git a/debian/patches/fix-leaks-lp1672297-1-context-Add-API-to-force-GC-schedule.patch b/debian/patches/fix-leaks-lp1672297-1-context-Add-API-to-force-GC-schedule.patch
70deleted file mode 1006440deleted file mode 100644
index 84944e6..0000000
--- a/debian/patches/fix-leaks-lp1672297-1-context-Add-API-to-force-GC-schedule.patch
+++ /dev/null
@@ -1,90 +0,0 @@
1From 33cbbeb11b61a0ffc8ff50e261e5dd33806590f9 Mon Sep 17 00:00:00 2001
2From: Georges Basile Stavracas Neto <georges.stavracas@gmail.com>
3Date: Fri, 30 Mar 2018 21:37:37 -0300
4Subject: [PATCH 1/2] context: Add API to force GC schedule
5
6There are situations where we cannot run the
7GC right away, but we also cannot ignore the
8need of running it.
9
10For those cases, add a new private function
11that forces GC to happen on idle.
12---
13 gjs/context-private.h | 2 ++
14 gjs/context.cpp | 29 +++++++++++++++++++++++++----
15 2 files changed, 27 insertions(+), 4 deletions(-)
16
17diff --git a/gjs/context-private.h b/gjs/context-private.h
18index 6dbe669..c45c8d0 100644
19--- a/gjs/context-private.h
20+++ b/gjs/context-private.h
21@@ -36,6 +36,8 @@ bool _gjs_context_destroying (GjsContext *js_context);
22
23 void _gjs_context_schedule_gc_if_needed (GjsContext *js_context);
24
25+void _gjs_context_schedule_gc (GjsContext *js_context);
26+
27 void _gjs_context_exit(GjsContext *js_context,
28 uint8_t exit_code);
29
30diff --git a/gjs/context.cpp b/gjs/context.cpp
31index c509943..77d7eaa 100644
32--- a/gjs/context.cpp
33+++ b/gjs/context.cpp
34@@ -90,6 +90,7 @@ struct _GjsContext {
35 uint8_t exit_code;
36
37 guint auto_gc_id;
38+ bool force_gc;
39
40 std::array<JS::PersistentRootedId*, GJS_STRING_LAST> const_strings;
41
42@@ -592,21 +593,41 @@ trigger_gc_if_needed (gpointer user_data)
43 {
44 GjsContext *js_context = GJS_CONTEXT(user_data);
45 js_context->auto_gc_id = 0;
46- gjs_gc_if_needed(js_context->context);
47+
48+ if (js_context->force_gc)
49+ JS_GC(js_context->context);
50+ else
51+ gjs_gc_if_needed(js_context->context);
52+
53 return G_SOURCE_REMOVE;
54 }
55
56-void
57-_gjs_context_schedule_gc_if_needed (GjsContext *js_context)
58+
59+static void
60+_gjs_context_schedule_gc_internal (GjsContext *js_context,
61+ bool force_gc)
62 {
63 if (js_context->auto_gc_id > 0)
64- return;
65+ g_source_remove(js_context->auto_gc_id);
66
67+ js_context->force_gc = force_gc;
68 js_context->auto_gc_id = g_idle_add_full(G_PRIORITY_LOW,
69 trigger_gc_if_needed,
70 js_context, NULL);
71 }
72
73+void
74+_gjs_context_schedule_gc (GjsContext *js_context)
75+{
76+ _gjs_context_schedule_gc_internal(js_context, true);
77+}
78+
79+void
80+_gjs_context_schedule_gc_if_needed (GjsContext *js_context)
81+{
82+ _gjs_context_schedule_gc_internal(js_context, false);
83+}
84+
85 void
86 _gjs_context_exit(GjsContext *js_context,
87 uint8_t exit_code)
88--
892.17.0
90
diff --git a/debian/patches/fix-leaks-lp1672297-2-object-Queue-a-forced-GC-when-toggling-down.patch b/debian/patches/fix-leaks-lp1672297-2-object-Queue-a-forced-GC-when-toggling-down.patch
91deleted file mode 1006440deleted file mode 100644
index 34f3d3b..0000000
--- a/debian/patches/fix-leaks-lp1672297-2-object-Queue-a-forced-GC-when-toggling-down.patch
+++ /dev/null
@@ -1,123 +0,0 @@
1From 3f94b11a943c0e4d29c96930ced238580dc18fc7 Mon Sep 17 00:00:00 2001
2From: Georges Basile Stavracas Neto <georges.stavracas@gmail.com>
3Date: Wed, 28 Mar 2018 19:21:52 -0300
4Subject: [PATCH 2/2] object: Queue a forced GC when toggling down
5
6During a GC, the collector asks each object which other
7objects that it wants to hold on to so if there's an entire
8section of the heap graph that's not connected to anything
9else, and not reachable from the root set, then it can be
10trashed all at once.
11
12GObjects, however, don't work like that, there's only a
13reference count but no notion of who owns the reference so,
14a JS object that's proxying a GObject is unconditionally held
15alive as long as the GObject has >1 references.
16
17Since we cannot know how many more wrapped GObjects are going
18be marked for garbage collection after the owner is destroyed,
19always queue a garbage collection when a toggle reference goes
20down.
21
22Issue: #140
23---
24 gi/object.cpp | 22 ++++++++++++++++++++++
25 gjs/context-private.h | 2 +-
26 gjs/context.cpp | 14 ++++++++------
27 3 files changed, 31 insertions(+), 7 deletions(-)
28
29diff --git a/gi/object.cpp b/gi/object.cpp
30index b20d8b9..f9cf3cc 100644
31--- a/gi/object.cpp
32+++ b/gi/object.cpp
33@@ -987,8 +987,30 @@ handle_toggle_down(GObject *gobj)
34 * collected by the GC
35 */
36 if (priv->keep_alive.rooted()) {
37+ GjsContext *context;
38+
39 gjs_debug_lifecycle(GJS_DEBUG_GOBJECT, "Unrooting object");
40 priv->keep_alive.switch_to_unrooted();
41+
42+ /* During a GC, the collector asks each object which other
43+ * objects that it wants to hold on to so if there's an entire
44+ * section of the heap graph that's not connected to anything
45+ * else, and not reachable from the root set, then it can be
46+ * trashed all at once.
47+ *
48+ * GObjects, however, don't work like that, there's only a
49+ * reference count but no notion of who owns the reference so,
50+ * a JS object that's proxying a GObject is unconditionally held
51+ * alive as long as the GObject has >1 references.
52+ *
53+ * Since we cannot know how many more wrapped GObjects are going
54+ * be marked for garbage collection after the owner is destroyed,
55+ * always queue a garbage collection when a toggle reference goes
56+ * down.
57+ */
58+ context = gjs_context_get_current();
59+ if (!_gjs_context_destroying(context))
60+ _gjs_context_schedule_gc(context);
61 }
62 }
63
64diff --git a/gjs/context-private.h b/gjs/context-private.h
65index c45c8d0..49c0cf9 100644
66--- a/gjs/context-private.h
67+++ b/gjs/context-private.h
68@@ -36,7 +36,7 @@ bool _gjs_context_destroying (GjsContext *js_context);
69
70 void _gjs_context_schedule_gc_if_needed (GjsContext *js_context);
71
72-void _gjs_context_schedule_gc (GjsContext *js_context);
73+void _gjs_context_schedule_gc(GjsContext *js_context);
74
75 void _gjs_context_exit(GjsContext *js_context,
76 uint8_t exit_code);
77diff --git a/gjs/context.cpp b/gjs/context.cpp
78index 77d7eaa..a2ce34a 100644
79--- a/gjs/context.cpp
80+++ b/gjs/context.cpp
81@@ -599,31 +599,33 @@ trigger_gc_if_needed (gpointer user_data)
82 else
83 gjs_gc_if_needed(js_context->context);
84
85+ js_context->force_gc = false;
86+
87 return G_SOURCE_REMOVE;
88 }
89
90
91 static void
92-_gjs_context_schedule_gc_internal (GjsContext *js_context,
93- bool force_gc)
94+_gjs_context_schedule_gc_internal(GjsContext *js_context,
95+ bool force_gc)
96 {
97 if (js_context->auto_gc_id > 0)
98- g_source_remove(js_context->auto_gc_id);
99+ return;
100
101- js_context->force_gc = force_gc;
102+ js_context->force_gc |= force_gc;
103 js_context->auto_gc_id = g_idle_add_full(G_PRIORITY_LOW,
104 trigger_gc_if_needed,
105 js_context, NULL);
106 }
107
108 void
109-_gjs_context_schedule_gc (GjsContext *js_context)
110+_gjs_context_schedule_gc(GjsContext *js_context)
111 {
112 _gjs_context_schedule_gc_internal(js_context, true);
113 }
114
115 void
116-_gjs_context_schedule_gc_if_needed (GjsContext *js_context)
117+_gjs_context_schedule_gc_if_needed(GjsContext *js_context)
118 {
119 _gjs_context_schedule_gc_internal(js_context, false);
120 }
121--
1222.17.0
123
diff --git a/debian/patches/series b/debian/patches/series
124deleted file mode 1006440deleted file mode 100644
index 1de36f6..0000000
--- a/debian/patches/series
+++ /dev/null
@@ -1,6 +0,0 @@
1# Cherry picked from gjs master:
2fix-crashes-lp1763878-revert-575f1e2e077.patch
3
4# Critical leak fixes (not yet landed in gjs master):
5fix-leaks-lp1672297-1-context-Add-API-to-force-GC-schedule.patch
6fix-leaks-lp1672297-2-object-Queue-a-forced-GC-when-toggling-down.patch
diff --git a/gi/gtype.cpp b/gi/gtype.cpp
index 314f4b2..03920eb 100644
--- a/gi/gtype.cpp
+++ b/gi/gtype.cpp
@@ -63,13 +63,18 @@ update_gtype_weak_pointers(JSContext *cx,
63 void *data)63 void *data)
64{64{
65 for (auto iter = weak_pointer_list.begin(); iter != weak_pointer_list.end(); ) {65 for (auto iter = weak_pointer_list.begin(); iter != weak_pointer_list.end(); ) {
66 auto heap_wrapper = static_cast<JS::Heap<JSObject *> *>(g_type_get_qdata(*iter, gjs_get_gtype_wrapper_quark()));66 GType gtype = *iter;
67 auto heap_wrapper = static_cast<JS::Heap<JSObject *> *>(
68 g_type_get_qdata(gtype, gjs_get_gtype_wrapper_quark()));
67 JS_UpdateWeakPointerAfterGC(heap_wrapper);69 JS_UpdateWeakPointerAfterGC(heap_wrapper);
6870
69 /* No read barriers are needed if the only thing we are doing with the71 /* No read barriers are needed if the only thing we are doing with the
70 * pointer is comparing it to nullptr. */72 * pointer is comparing it to nullptr. */
71 if (heap_wrapper->unbarrieredGet() == nullptr)73 if (heap_wrapper->unbarrieredGet() == nullptr) {
74 g_type_set_qdata(gtype, gjs_get_gtype_wrapper_quark(), nullptr);
72 iter = weak_pointer_list.erase(iter);75 iter = weak_pointer_list.erase(iter);
76 delete heap_wrapper;
77 }
73 else78 else
74 iter++;79 iter++;
75 }80 }
@@ -95,8 +100,12 @@ gjs_gtype_finalize(JSFreeOp *fop,
95 if (G_UNLIKELY(gtype == 0))100 if (G_UNLIKELY(gtype == 0))
96 return;101 return;
97102
98 weak_pointer_list.erase(gtype);103 auto heap_wrapper = static_cast<JS::Heap<JSObject*>*>(
104 g_type_get_qdata(gtype, gjs_get_gtype_wrapper_quark()));
105
99 g_type_set_qdata(gtype, gjs_get_gtype_wrapper_quark(), NULL);106 g_type_set_qdata(gtype, gjs_get_gtype_wrapper_quark(), NULL);
107 weak_pointer_list.erase(gtype);
108 delete heap_wrapper;
100}109}
101110
102static bool111static bool
diff --git a/gi/object.cpp b/gi/object.cpp
index b20d8b9..fe381ec 100644
--- a/gi/object.cpp
+++ b/gi/object.cpp
@@ -54,6 +54,65 @@
54#include <util/log.h>54#include <util/log.h>
55#include <girepository.h>55#include <girepository.h>
5656
57typedef class GjsListLink GjsListLink;
58typedef struct ObjectInstance ObjectInstance;
59
60static GjsListLink* object_instance_get_link(ObjectInstance *priv);
61
62class GjsListLink {
63 private:
64 ObjectInstance *m_prev;
65 ObjectInstance *m_next;
66
67 public:
68 ObjectInstance* prev() {
69 return m_prev;
70 }
71
72 ObjectInstance* next() {
73 return m_next;
74 }
75
76 void prepend(ObjectInstance *this_instance,
77 ObjectInstance *head) {
78 GjsListLink *elem = object_instance_get_link(head);
79
80 g_assert(object_instance_get_link(this_instance) == this);
81
82 if (elem->m_prev) {
83 GjsListLink *prev = object_instance_get_link(elem->m_prev);
84 prev->m_next = this_instance;
85 this->m_prev = elem->m_prev;
86 }
87
88 elem->m_prev = this_instance;
89 this->m_next = head;
90 }
91
92 void unlink() {
93 if (m_prev)
94 object_instance_get_link(m_prev)->m_next = m_next;
95 if (m_next)
96 object_instance_get_link(m_next)->m_prev = m_prev;
97
98 m_prev = m_next = NULL;
99 }
100
101 int size() {
102 GjsListLink *elem = this;
103 int count = 0;
104
105 do {
106 count++;
107 if (!elem->m_next)
108 break;
109 elem = object_instance_get_link(elem->m_next);
110 } while (elem);
111
112 return count;
113 }
114};
115
57struct ObjectInstance {116struct ObjectInstance {
58 GIObjectInfo *info;117 GIObjectInfo *info;
59 GObject *gobj; /* NULL if we are the prototype and not an instance */118 GObject *gobj; /* NULL if we are the prototype and not an instance */
@@ -68,8 +127,15 @@ struct ObjectInstance {
68 prototypes) */127 prototypes) */
69 GTypeClass *klass;128 GTypeClass *klass;
70129
130 GjsListLink instance_link;
131
71 unsigned js_object_finalized : 1;132 unsigned js_object_finalized : 1;
72 unsigned g_object_finalized : 1;133 unsigned g_object_finalized : 1;
134
135 /* True if this object has visible JS state, and thus its lifecycle is
136 * managed using toggle references. False if this object just keeps a
137 * hard ref on the underlying GObject, and may be finalized at will. */
138 bool uses_toggle_ref : 1;
73};139};
74140
75static std::stack<JS::PersistentRootedObject> object_init_list;141static std::stack<JS::PersistentRootedObject> object_init_list;
@@ -78,13 +144,15 @@ using ParamRef = std::unique_ptr<GParamSpec, decltype(&g_param_spec_unref)>;
78using ParamRefArray = std::vector<ParamRef>;144using ParamRefArray = std::vector<ParamRef>;
79static std::unordered_map<GType, ParamRefArray> class_init_properties;145static std::unordered_map<GType, ParamRefArray> class_init_properties;
80146
147static bool context_weak_pointer_callback = false;
81static bool weak_pointer_callback = false;148static bool weak_pointer_callback = false;
82static std::set<ObjectInstance *> wrapped_gobject_list;149ObjectInstance *wrapped_gobject_list;
83150
84extern struct JSClass gjs_object_instance_class;151extern struct JSClass gjs_object_instance_class;
85GJS_DEFINE_PRIV_FROM_JS(ObjectInstance, gjs_object_instance_class)152GJS_DEFINE_PRIV_FROM_JS(ObjectInstance, gjs_object_instance_class)
86153
87static void disassociate_js_gobject (GObject *gobj);154static void disassociate_js_gobject (GObject *gobj);
155static void ensure_uses_toggle_ref(JSContext *cx, ObjectInstance *priv);
88156
89typedef enum {157typedef enum {
90 SOME_ERROR_OCCURRED = false,158 SOME_ERROR_OCCURRED = false,
@@ -152,7 +220,7 @@ get_object_qdata(GObject *gobj)
152 auto priv = static_cast<ObjectInstance *>(g_object_get_qdata(gobj,220 auto priv = static_cast<ObjectInstance *>(g_object_get_qdata(gobj,
153 gjs_object_priv_quark()));221 gjs_object_priv_quark()));
154222
155 if (priv && G_UNLIKELY(priv->js_object_finalized)) {223 if (priv && priv->uses_toggle_ref && G_UNLIKELY(priv->js_object_finalized)) {
156 g_critical("Object %p (a %s) resurfaced after the JS wrapper was finalized. "224 g_critical("Object %p (a %s) resurfaced after the JS wrapper was finalized. "
157 "This is some library doing dubious memory management inside dispose()",225 "This is some library doing dubious memory management inside dispose()",
158 gobj, g_type_name(G_TYPE_FROM_INSTANCE(gobj)));226 gobj, g_type_name(G_TYPE_FROM_INSTANCE(gobj)));
@@ -430,6 +498,9 @@ set_g_param_from_prop(JSContext *context,
430 case SOME_ERROR_OCCURRED:498 case SOME_ERROR_OCCURRED:
431 return false;499 return false;
432 case NO_SUCH_G_PROPERTY:500 case NO_SUCH_G_PROPERTY:
501 /* We need to keep the wrapper alive in order not to lose custom
502 * "expando" properties */
503 ensure_uses_toggle_ref(context, priv);
433 return result.succeed();504 return result.succeed();
434 case VALUE_WAS_SET:505 case VALUE_WAS_SET:
435 default:506 default:
@@ -496,14 +567,7 @@ object_instance_set_prop(JSContext *context,
496 bool ret = true;567 bool ret = true;
497 bool g_param_was_set = false;568 bool g_param_was_set = false;
498569
499 if (!gjs_get_string_id(context, id, &name))
500 return result.succeed(); /* not resolved, but no error */
501
502 priv = priv_from_js(context, obj);570 priv = priv_from_js(context, obj);
503 gjs_debug_jsprop(GJS_DEBUG_GOBJECT,
504 "Set prop '%s' hook obj %p priv %p",
505 name.get(), obj.get(), priv);
506
507 if (priv == nullptr)571 if (priv == nullptr)
508 /* see the comment in object_instance_get_prop() on this */572 /* see the comment in object_instance_get_prop() on this */
509 return result.succeed();573 return result.succeed();
@@ -521,6 +585,18 @@ object_instance_set_prop(JSContext *context,
521 return result.succeed();585 return result.succeed();
522 }586 }
523587
588 if (!gjs_get_string_id(context, id, &name)) {
589 /* We need to keep the wrapper alive in order not to lose custom
590 * "expando" properties. In this case if gjs_get_string_id() is false
591 * then a number or symbol property was probably set. */
592 ensure_uses_toggle_ref(context, priv);
593 return result.succeed(); /* not resolved, but no error */
594 }
595
596 gjs_debug_jsprop(GJS_DEBUG_GOBJECT,
597 "Set prop '%s' hook obj %p priv %p",
598 name.get(), obj.get(), priv);
599
524 ret = set_g_param_from_prop(context, priv, name, g_param_was_set, value_p, result);600 ret = set_g_param_from_prop(context, priv, name, g_param_was_set, value_p, result);
525 if (g_param_was_set || !ret)601 if (g_param_was_set || !ret)
526 return ret;602 return ret;
@@ -755,18 +831,6 @@ object_instance_resolve(JSContext *context,
755 return true;831 return true;
756 }832 }
757833
758 if (priv->g_object_finalized) {
759 g_critical("Object %s.%s (%p), has been already finalized. "
760 "Impossible to resolve it.",
761 priv->info ? g_base_info_get_namespace( (GIBaseInfo*) priv->info) : "",
762 priv->info ? g_base_info_get_name( (GIBaseInfo*) priv->info) : g_type_name(priv->gtype),
763 priv->gobj);
764 gjs_dumpstack();
765
766 *resolved = false;
767 return true;
768 }
769
770 /* If we have no GIRepository information (we're a JS GObject subclass),834 /* If we have no GIRepository information (we're a JS GObject subclass),
771 * we need to look at exposing interfaces. Look up our interfaces through835 * we need to look at exposing interfaces. Look up our interfaces through
772 * GType data, and then hope that *those* are introspectable. */836 * GType data, and then hope that *those* are introspectable. */
@@ -945,6 +1009,28 @@ object_instance_props_to_g_parameters(JSContext *context,
945 return true;1009 return true;
946}1010}
9471011
1012static GjsListLink *
1013object_instance_get_link(ObjectInstance *priv)
1014{
1015 return &priv->instance_link;
1016}
1017
1018static void
1019object_instance_unlink(ObjectInstance *priv)
1020{
1021 if (wrapped_gobject_list == priv)
1022 wrapped_gobject_list = priv->instance_link.next();
1023 priv->instance_link.unlink();
1024}
1025
1026static void
1027object_instance_link(ObjectInstance *priv)
1028{
1029 if (wrapped_gobject_list)
1030 priv->instance_link.prepend(priv, wrapped_gobject_list);
1031 wrapped_gobject_list = priv;
1032}
1033
948static void1034static void
949wrapped_gobj_dispose_notify(gpointer data,1035wrapped_gobj_dispose_notify(gpointer data,
950 GObject *where_the_object_was)1036 GObject *where_the_object_was)
@@ -952,26 +1038,30 @@ wrapped_gobj_dispose_notify(gpointer data,
952 auto *priv = static_cast<ObjectInstance *>(data);1038 auto *priv = static_cast<ObjectInstance *>(data);
9531039
954 priv->g_object_finalized = true;1040 priv->g_object_finalized = true;
955 wrapped_gobject_list.erase(priv);1041 object_instance_unlink(priv);
956 gjs_debug_lifecycle(GJS_DEBUG_GOBJECT, "Wrapped GObject %p disposed",1042 gjs_debug_lifecycle(GJS_DEBUG_GOBJECT, "Wrapped GObject %p disposed",
957 where_the_object_was);1043 where_the_object_was);
958}1044}
9591045
960static void1046void
961gobj_no_longer_kept_alive_func(JS::HandleObject obj,1047gjs_object_context_dispose_notify(void *data,
962 void *data)1048 GObject *where_the_object_was)
963{1049{
964 ObjectInstance *priv;1050 ObjectInstance *priv = wrapped_gobject_list;
1051 while (priv) {
1052 ObjectInstance *next = priv->instance_link.next();
9651053
966 priv = (ObjectInstance *) data;1054 if (priv->keep_alive.rooted()) {
9671055 gjs_debug_lifecycle(GJS_DEBUG_GOBJECT, "GObject wrapper %p for GObject "
968 gjs_debug_lifecycle(GJS_DEBUG_GOBJECT, "GObject wrapper %p for GObject "1056 "%p (%s) was rooted but is now unrooted due to "
969 "%p (%s) was rooted but is now unrooted due to "1057 "GjsContext dispose", priv->keep_alive.get(),
970 "GjsContext dispose", obj.get(), priv->gobj,1058 priv->gobj, G_OBJECT_TYPE_NAME(priv->gobj));
971 G_OBJECT_TYPE_NAME(priv->gobj));1059 priv->keep_alive.reset();
1060 object_instance_unlink(priv);
1061 }
9721062
973 priv->keep_alive.reset();1063 priv = next;
974 wrapped_gobject_list.erase(priv);1064 }
975}1065}
9761066
977static void1067static void
@@ -987,8 +1077,30 @@ handle_toggle_down(GObject *gobj)
987 * collected by the GC1077 * collected by the GC
988 */1078 */
989 if (priv->keep_alive.rooted()) {1079 if (priv->keep_alive.rooted()) {
1080 GjsContext *context;
1081
990 gjs_debug_lifecycle(GJS_DEBUG_GOBJECT, "Unrooting object");1082 gjs_debug_lifecycle(GJS_DEBUG_GOBJECT, "Unrooting object");
991 priv->keep_alive.switch_to_unrooted();1083 priv->keep_alive.switch_to_unrooted();
1084
1085 /* During a GC, the collector asks each object which other
1086 * objects that it wants to hold on to so if there's an entire
1087 * section of the heap graph that's not connected to anything
1088 * else, and not reachable from the root set, then it can be
1089 * trashed all at once.
1090 *
1091 * GObjects, however, don't work like that, there's only a
1092 * reference count but no notion of who owns the reference so,
1093 * a JS object that's proxying a GObject is unconditionally held
1094 * alive as long as the GObject has >1 references.
1095 *
1096 * Since we cannot know how many more wrapped GObjects are going
1097 * be marked for garbage collection after the owner is destroyed,
1098 * always queue a garbage collection when a toggle reference goes
1099 * down.
1100 */
1101 context = gjs_context_get_current();
1102 if (!_gjs_context_destroying(context))
1103 _gjs_context_schedule_gc(context);
992 }1104 }
993}1105}
9941106
@@ -1017,7 +1129,7 @@ handle_toggle_up(GObject *gobj)
1017 GjsContext *context = gjs_context_get_current();1129 GjsContext *context = gjs_context_get_current();
1018 gjs_debug_lifecycle(GJS_DEBUG_GOBJECT, "Rooting object");1130 gjs_debug_lifecycle(GJS_DEBUG_GOBJECT, "Rooting object");
1019 auto cx = static_cast<JSContext *>(gjs_context_get_native_context(context));1131 auto cx = static_cast<JSContext *>(gjs_context_get_native_context(context));
1020 priv->keep_alive.switch_to_rooted(cx, gobj_no_longer_kept_alive_func, priv);1132 priv->keep_alive.switch_to_rooted(cx);
1021 }1133 }
1022}1134}
10231135
@@ -1126,7 +1238,10 @@ static void
1126release_native_object (ObjectInstance *priv)1238release_native_object (ObjectInstance *priv)
1127{1239{
1128 priv->keep_alive.reset();1240 priv->keep_alive.reset();
1129 g_object_remove_toggle_ref(priv->gobj, wrapped_gobj_toggle_notify, NULL);1241 if (priv->uses_toggle_ref)
1242 g_object_remove_toggle_ref(priv->gobj, wrapped_gobj_toggle_notify, nullptr);
1243 else
1244 g_object_unref(priv->gobj);
1130 priv->gobj = NULL;1245 priv->gobj = NULL;
1131}1246}
11321247
@@ -1156,14 +1271,15 @@ gjs_object_prepare_shutdown(void)
1156 * toggle ref removal -> gobj dispose -> toggle ref notify1271 * toggle ref removal -> gobj dispose -> toggle ref notify
1157 * by emptying the toggle queue earlier in the shutdown sequence. */1272 * by emptying the toggle queue earlier in the shutdown sequence. */
1158 std::vector<ObjectInstance *> to_be_released;1273 std::vector<ObjectInstance *> to_be_released;
1159 for (auto iter = wrapped_gobject_list.begin(); iter != wrapped_gobject_list.end(); ) {1274 ObjectInstance *link = wrapped_gobject_list;
1160 ObjectInstance *priv = *iter;1275 while (link) {
1161 if (priv->keep_alive.rooted()) {1276 ObjectInstance *next = link->instance_link.next();
1162 to_be_released.push_back(priv);1277 if (link->keep_alive.rooted()) {
1163 iter = wrapped_gobject_list.erase(iter);1278 to_be_released.push_back(link);
1164 } else {1279 object_instance_unlink(link);
1165 iter++;
1166 }1280 }
1281
1282 link = next;
1167 }1283 }
1168 for (ObjectInstance *priv : to_be_released)1284 for (ObjectInstance *priv : to_be_released)
1169 release_native_object(priv);1285 release_native_object(priv);
@@ -1209,16 +1325,18 @@ update_heap_wrapper_weak_pointers(JSContext *cx,
1209{1325{
1210 gjs_debug_lifecycle(GJS_DEBUG_GOBJECT, "Weak pointer update callback, "1326 gjs_debug_lifecycle(GJS_DEBUG_GOBJECT, "Weak pointer update callback, "
1211 "%zu wrapped GObject(s) to examine",1327 "%zu wrapped GObject(s) to examine",
1212 wrapped_gobject_list.size());1328 wrapped_gobject_list ?
1329 wrapped_gobject_list->instance_link.size() : 0);
12131330
1214 std::vector<GObject *> to_be_disassociated;1331 std::vector<GObject *> to_be_disassociated;
1332 ObjectInstance *priv = wrapped_gobject_list;
12151333
1216 for (auto iter = wrapped_gobject_list.begin(); iter != wrapped_gobject_list.end(); ) {1334 while (priv) {
1217 ObjectInstance *priv = *iter;1335 ObjectInstance *next = priv->instance_link.next();
1218 if (priv->keep_alive.rooted() || priv->keep_alive == nullptr ||1336
1219 !priv->keep_alive.update_after_gc()) {1337 if (!priv->keep_alive.rooted() &&
1220 iter++;1338 priv->keep_alive != nullptr &&
1221 } else {1339 priv->keep_alive.update_after_gc()) {
1222 /* Ouch, the JS object is dead already. Disassociate the1340 /* Ouch, the JS object is dead already. Disassociate the
1223 * GObject and hope the GObject dies too. (Remove it from1341 * GObject and hope the GObject dies too. (Remove it from
1224 * the weak pointer list first, since the disassociation1342 * the weak pointer list first, since the disassociation
@@ -1229,8 +1347,10 @@ update_heap_wrapper_weak_pointers(JSContext *cx,
1229 "%p (%s)", priv->keep_alive.get(), priv->gobj,1347 "%p (%s)", priv->keep_alive.get(), priv->gobj,
1230 G_OBJECT_TYPE_NAME(priv->gobj));1348 G_OBJECT_TYPE_NAME(priv->gobj));
1231 to_be_disassociated.push_back(priv->gobj);1349 to_be_disassociated.push_back(priv->gobj);
1232 iter = wrapped_gobject_list.erase(iter);1350 object_instance_unlink(priv);
1233 }1351 }
1352
1353 priv = next;
1234 }1354 }
12351355
1236 for (GObject *gobj : to_be_disassociated)1356 for (GObject *gobj : to_be_disassociated)
@@ -1256,16 +1376,28 @@ associate_js_gobject (JSContext *context,
1256 ObjectInstance *priv;1376 ObjectInstance *priv;
12571377
1258 priv = priv_from_js(context, object);1378 priv = priv_from_js(context, object);
1379 priv->uses_toggle_ref = false;
1259 priv->gobj = gobj;1380 priv->gobj = gobj;
12601381
1261 g_assert(!priv->keep_alive.rooted());1382 g_assert(!priv->keep_alive.rooted());
12621383
1263 set_object_qdata(gobj, priv);1384 set_object_qdata(gobj, priv);
12641385
1386 priv->keep_alive = object;
1265 ensure_weak_pointer_callback(context);1387 ensure_weak_pointer_callback(context);
1266 wrapped_gobject_list.insert(priv);1388 object_instance_link(priv);
12671389
1268 g_object_weak_ref(gobj, wrapped_gobj_dispose_notify, priv);1390 g_object_weak_ref(gobj, wrapped_gobj_dispose_notify, priv);
1391}
1392
1393static void
1394ensure_uses_toggle_ref(JSContext *cx,
1395 ObjectInstance *priv)
1396{
1397 if (priv->uses_toggle_ref)
1398 return;
1399
1400 g_assert(!priv->keep_alive.rooted());
12691401
1270 /* OK, here is where things get complicated. We want the1402 /* OK, here is where things get complicated. We want the
1271 * wrapped gobj to keep the JSObject* wrapper alive, because1403 * wrapped gobj to keep the JSObject* wrapper alive, because
@@ -1278,8 +1410,14 @@ associate_js_gobject (JSContext *context,
1278 * the wrapper to be garbage collected (and thus unref the1410 * the wrapper to be garbage collected (and thus unref the
1279 * wrappee).1411 * wrappee).
1280 */1412 */
1281 priv->keep_alive.root(context, object, gobj_no_longer_kept_alive_func, priv);1413 priv->uses_toggle_ref = true;
1282 g_object_add_toggle_ref(gobj, wrapped_gobj_toggle_notify, NULL);1414 priv->keep_alive.switch_to_rooted(cx);
1415 g_object_add_toggle_ref(priv->gobj, wrapped_gobj_toggle_notify, nullptr);
1416
1417 /* We now have both a ref and a toggle ref, we only want the toggle ref.
1418 * This may immediately remove the GC root we just added, since refcount
1419 * may drop to 1. */
1420 g_object_unref(priv->gobj);
1283}1421}
12841422
1285static void1423static void
@@ -1303,7 +1441,8 @@ disassociate_js_gobject(GObject *gobj)
1303 ObjectInstance *priv = get_object_qdata(gobj);1441 ObjectInstance *priv = get_object_qdata(gobj);
1304 bool had_toggle_down, had_toggle_up;1442 bool had_toggle_down, had_toggle_up;
13051443
1306 g_object_weak_unref(priv->gobj, wrapped_gobj_dispose_notify, priv);1444 if (!priv->g_object_finalized)
1445 g_object_weak_unref(gobj, wrapped_gobj_dispose_notify, priv);
13071446
1308 /* FIXME: this check fails when JS code runs after the main loop ends,1447 /* FIXME: this check fails when JS code runs after the main loop ends,
1309 * because the idle functions are not dispatched without a main loop.1448 * because the idle functions are not dispatched without a main loop.
@@ -1322,11 +1461,16 @@ disassociate_js_gobject(GObject *gobj)
1322 gobj, G_OBJECT_TYPE_NAME(gobj));1461 gobj, G_OBJECT_TYPE_NAME(gobj));
1323 }1462 }
13241463
1464 /* Fist, remove the wrapper pointer from the wrapped GObject */
1465 set_object_qdata(gobj, nullptr);
1466
1467 /* Now release all the resources the current wrapper has */
1325 invalidate_all_closures(priv);1468 invalidate_all_closures(priv);
1326 release_native_object(priv);1469 release_native_object(priv);
13271470
1328 /* Mark that a JS object once existed, but it doesn't any more */1471 /* Mark that a JS object once existed, but it doesn't any more */
1329 priv->js_object_finalized = true;1472 priv->js_object_finalized = true;
1473 priv->keep_alive = nullptr;
1330}1474}
13311475
1332static void1476static void
@@ -1383,6 +1527,7 @@ G_GNUC_END_IGNORE_DEPRECATIONS
1383 * we're not actually using it, so just let it get collected. Avoiding1527 * we're not actually using it, so just let it get collected. Avoiding
1384 * this would require a non-trivial amount of work.1528 * this would require a non-trivial amount of work.
1385 * */1529 * */
1530 ensure_uses_toggle_ref(context, other_priv);
1386 object.set(other_priv->keep_alive);1531 object.set(other_priv->keep_alive);
1387 g_object_unref(gobj); /* We already own a reference */1532 g_object_unref(gobj); /* We already own a reference */
1388 gobj = NULL;1533 gobj = NULL;
@@ -1410,11 +1555,6 @@ G_GNUC_END_IGNORE_DEPRECATIONS
14101555
1411 if (priv->gobj == NULL)1556 if (priv->gobj == NULL)
1412 associate_js_gobject(context, object, gobj);1557 associate_js_gobject(context, object, gobj);
1413 /* We now have both a ref and a toggle ref, we only want the
1414 * toggle ref. This may immediately remove the GC root
1415 * we just added, since refcount may drop to 1.
1416 */
1417 g_object_unref(gobj);
14181558
1419 gjs_debug_lifecycle(GJS_DEBUG_GOBJECT, "JSObject created with GObject %p (%s)",1559 gjs_debug_lifecycle(GJS_DEBUG_GOBJECT, "JSObject created with GObject %p (%s)",
1420 priv->gobj, G_OBJECT_TYPE_NAME(priv->gobj));1560 priv->gobj, G_OBJECT_TYPE_NAME(priv->gobj));
@@ -1463,15 +1603,6 @@ object_instance_trace(JSTracer *tracer,
1463 if (priv == NULL)1603 if (priv == NULL)
1464 return;1604 return;
14651605
1466 if (priv->g_object_finalized) {
1467 g_debug("Object %s.%s (%p), has been already finalized. "
1468 "Impossible to trace it.",
1469 priv->info ? g_base_info_get_namespace( (GIBaseInfo*) priv->info) : "",
1470 priv->info ? g_base_info_get_name( (GIBaseInfo*) priv->info) : g_type_name(priv->gtype),
1471 priv->gobj);
1472 return;
1473 }
1474
1475 for (GClosure *closure : priv->closures)1606 for (GClosure *closure : priv->closures)
1476 gjs_closure_trace(closure, tracer);1607 gjs_closure_trace(closure, tracer);
1477}1608}
@@ -1541,7 +1672,7 @@ object_instance_finalize(JSFreeOp *fop,
15411672
1542 priv->keep_alive.reset();1673 priv->keep_alive.reset();
1543 }1674 }
1544 wrapped_gobject_list.erase(priv);1675 object_instance_unlink(priv);
15451676
1546 if (priv->info) {1677 if (priv->info) {
1547 g_base_info_unref( (GIBaseInfo*) priv->info);1678 g_base_info_unref( (GIBaseInfo*) priv->info);
@@ -1556,6 +1687,9 @@ object_instance_finalize(JSFreeOp *fop,
1556 GJS_DEC_COUNTER(object);1687 GJS_DEC_COUNTER(object);
1557 priv->~ObjectInstance();1688 priv->~ObjectInstance();
1558 g_slice_free(ObjectInstance, priv);1689 g_slice_free(ObjectInstance, priv);
1690
1691 /* Remove the ObjectInstance pointer from the JSObject */
1692 JS_SetPrivate(obj, nullptr);
1559}1693}
15601694
1561static JSObject *1695static JSObject *
@@ -1683,6 +1817,8 @@ real_connect_func(JSContext *context,
1683 return true;1817 return true;
1684 }1818 }
16851819
1820 ensure_uses_toggle_ref(context, priv);
1821
1686 if (argc != 2 || !argv[0].isString() || !JS::IsCallable(&argv[1].toObject())) {1822 if (argc != 2 || !argv[0].isString() || !JS::IsCallable(&argv[1].toObject())) {
1687 gjs_throw(context, "connect() takes two args, the signal name and the callback");1823 gjs_throw(context, "connect() takes two args, the signal name and the callback");
1688 return false;1824 return false;
@@ -2123,9 +2259,6 @@ gjs_object_from_g_object(JSContext *context,
2123 g_object_ref_sink(gobj);2259 g_object_ref_sink(gobj);
2124 associate_js_gobject(context, obj, gobj);2260 associate_js_gobject(context, obj, gobj);
21252261
2126 /* see the comment in init_object_instance() for this */
2127 g_object_unref(gobj);
2128
2129 g_assert(priv->keep_alive == obj.get());2262 g_assert(priv->keep_alive == obj.get());
2130 }2263 }
21312264
@@ -2142,6 +2275,19 @@ gjs_g_object_from_object(JSContext *context,
2142 return NULL;2275 return NULL;
21432276
2144 priv = priv_from_js(context, obj);2277 priv = priv_from_js(context, obj);
2278
2279 if (priv->g_object_finalized) {
2280 g_critical("Object %s.%s (%p), has been already deallocated - "
2281 "impossible to access it. This might be caused by the "
2282 "object having been destroyed from C code using something "
2283 "such as destroy(), dispose(), or remove() vfuncs",
2284 priv->info ? g_base_info_get_namespace(priv->info) : "",
2285 priv->info ? g_base_info_get_name(priv->info) : g_type_name(priv->gtype),
2286 priv->gobj);
2287 gjs_dumpstack();
2288 return nullptr;
2289 }
2290
2145 return priv->gobj;2291 return priv->gobj;
2146}2292}
21472293
@@ -2188,19 +2334,7 @@ gjs_typecheck_object(JSContext *context,
2188 return false;2334 return false;
2189 }2335 }
21902336
2191 if (priv->g_object_finalized) {2337 g_assert(priv->g_object_finalized || priv->gtype == G_OBJECT_TYPE(priv->gobj));
2192 g_critical("Object %s.%s (%p), has been already deallocated - impossible to access to it. "
2193 "This might be caused by the fact that the object has been destroyed from C "
2194 "code using something such as destroy(), dispose(), or remove() vfuncs",
2195 priv->info ? g_base_info_get_namespace( (GIBaseInfo*) priv->info) : "",
2196 priv->info ? g_base_info_get_name( (GIBaseInfo*) priv->info) : g_type_name(priv->gtype),
2197 priv->gobj);
2198 gjs_dumpstack();
2199
2200 return true;
2201 }
2202
2203 g_assert(priv->gtype == G_OBJECT_TYPE(priv->gobj));
22042338
2205 if (expected_type != G_TYPE_NONE)2339 if (expected_type != G_TYPE_NONE)
2206 result = g_type_is_a (priv->gtype, expected_type);2340 result = g_type_is_a (priv->gtype, expected_type);
@@ -2657,6 +2791,10 @@ gjs_object_custom_init(GTypeInstance *instance,
26572791
2658 associate_js_gobject(context, object, G_OBJECT (instance));2792 associate_js_gobject(context, object, G_OBJECT (instance));
26592793
2794 /* Custom JS objects will most likely have visible state, so
2795 * just do this from the start */
2796 ensure_uses_toggle_ref(context, priv);
2797
2660 JS::RootedValue v(context);2798 JS::RootedValue v(context);
2661 if (!gjs_object_get_property(context, object,2799 if (!gjs_object_get_property(context, object,
2662 GJS_STRING_INSTANCE_INIT, &v)) {2800 GJS_STRING_INSTANCE_INIT, &v)) {
@@ -3109,6 +3247,9 @@ gjs_object_associate_closure(JSContext *cx,
3109 if (!priv)3247 if (!priv)
3110 return false;3248 return false;
31113249
3250 if (priv->gobj)
3251 ensure_uses_toggle_ref(cx, priv);
3252
3112 do_associate_closure(priv, closure);3253 do_associate_closure(priv, closure);
3113 return true;3254 return true;
3114}3255}
diff --git a/gi/object.h b/gi/object.h
index 63aeb37..1f1dce8 100644
--- a/gi/object.h
+++ b/gi/object.h
@@ -61,6 +61,8 @@ bool gjs_typecheck_is_object(JSContext *context,
61void gjs_object_prepare_shutdown(void);61void gjs_object_prepare_shutdown(void);
62void gjs_object_clear_toggles(void);62void gjs_object_clear_toggles(void);
63void gjs_object_shutdown_toggle_queue(void);63void gjs_object_shutdown_toggle_queue(void);
64void gjs_object_context_dispose_notify(void *data,
65 GObject *where_the_object_was);
6466
65void gjs_object_define_static_methods(JSContext *context,67void gjs_object_define_static_methods(JSContext *context,
66 JS::HandleObject constructor,68 JS::HandleObject constructor,
diff --git a/gjs/context-private.h b/gjs/context-private.h
index 6dbe669..49c0cf9 100644
--- a/gjs/context-private.h
+++ b/gjs/context-private.h
@@ -36,6 +36,8 @@ bool _gjs_context_destroying (GjsContext *js_context);
3636
37void _gjs_context_schedule_gc_if_needed (GjsContext *js_context);37void _gjs_context_schedule_gc_if_needed (GjsContext *js_context);
3838
39void _gjs_context_schedule_gc(GjsContext *js_context);
40
39void _gjs_context_exit(GjsContext *js_context,41void _gjs_context_exit(GjsContext *js_context,
40 uint8_t exit_code);42 uint8_t exit_code);
4143
diff --git a/gjs/context.cpp b/gjs/context.cpp
index c509943..fc88741 100644
--- a/gjs/context.cpp
+++ b/gjs/context.cpp
@@ -90,6 +90,7 @@ struct _GjsContext {
90 uint8_t exit_code;90 uint8_t exit_code;
9191
92 guint auto_gc_id;92 guint auto_gc_id;
93 bool force_gc;
9394
94 std::array<JS::PersistentRootedId*, GJS_STRING_LAST> const_strings;95 std::array<JS::PersistentRootedId*, GJS_STRING_LAST> const_strings;
9596
@@ -515,6 +516,8 @@ gjs_context_constructed(GObject *object)
515 g_mutex_unlock (&contexts_lock);516 g_mutex_unlock (&contexts_lock);
516517
517 setup_dump_heap();518 setup_dump_heap();
519
520 g_object_weak_ref(object, gjs_object_context_dispose_notify, nullptr);
518}521}
519522
520static void523static void
@@ -592,19 +595,43 @@ trigger_gc_if_needed (gpointer user_data)
592{595{
593 GjsContext *js_context = GJS_CONTEXT(user_data);596 GjsContext *js_context = GJS_CONTEXT(user_data);
594 js_context->auto_gc_id = 0;597 js_context->auto_gc_id = 0;
595 gjs_gc_if_needed(js_context->context);598
599 if (js_context->force_gc)
600 JS_GC(js_context->context);
601 else
602 gjs_gc_if_needed(js_context->context);
603
604 js_context->force_gc = false;
605
596 return G_SOURCE_REMOVE;606 return G_SOURCE_REMOVE;
597}607}
598608
599void609
600_gjs_context_schedule_gc_if_needed (GjsContext *js_context)610static void
611_gjs_context_schedule_gc_internal(GjsContext *js_context,
612 bool force_gc)
601{613{
614 js_context->force_gc |= force_gc;
615
602 if (js_context->auto_gc_id > 0)616 if (js_context->auto_gc_id > 0)
603 return;617 return;
604618
605 js_context->auto_gc_id = g_idle_add_full(G_PRIORITY_LOW,619 js_context->force_gc |= force_gc;
606 trigger_gc_if_needed,620 js_context->auto_gc_id = g_timeout_add_seconds_full(G_PRIORITY_LOW, 10,
607 js_context, NULL);621 trigger_gc_if_needed,
622 js_context, NULL);
623}
624
625void
626_gjs_context_schedule_gc(GjsContext *js_context)
627{
628 _gjs_context_schedule_gc_internal(js_context, true);
629}
630
631void
632_gjs_context_schedule_gc_if_needed(GjsContext *js_context)
633{
634 _gjs_context_schedule_gc_internal(js_context, false);
608}635}
609636
610void637void
diff --git a/gjs/engine.cpp b/gjs/engine.cpp
index 90fa57c..720267d 100644
--- a/gjs/engine.cpp
+++ b/gjs/engine.cpp
@@ -37,10 +37,6 @@
37#include <windows.h>37#include <windows.h>
38#endif38#endif
3939
40#ifdef ENABLE_CAIRO
41# include <cairo.h>
42#endif
43
44/* Implementations of locale-specific operations; these are used40/* Implementations of locale-specific operations; these are used
45 * in the implementation of String.localeCompare(), Date.toLocaleDateString(),41 * in the implementation of String.localeCompare(), Date.toLocaleDateString(),
46 * and so forth. We take the straight-forward approach of converting42 * and so forth. We take the straight-forward approach of converting
@@ -218,16 +214,6 @@ on_promise_unhandled_rejection(JSContext *cx,
218 std::move(stack));214 std::move(stack));
219}215}
220216
221static void
222shutdown(void)
223{
224 JS_ShutDown();
225
226#ifdef ENABLE_CAIRO
227 cairo_debug_reset_static_data(); /* for valgrind reports */
228#endif
229}
230
231#ifdef G_OS_WIN32217#ifdef G_OS_WIN32
232HMODULE gjs_dll;218HMODULE gjs_dll;
233static bool gjs_is_inited = false;219static bool gjs_is_inited = false;
@@ -245,7 +231,7 @@ LPVOID lpvReserved)
245 break;231 break;
246232
247 case DLL_THREAD_DETACH:233 case DLL_THREAD_DETACH:
248 shutdown();234 JS_ShutDown ();
249 break;235 break;
250236
251 default:237 default:
@@ -265,7 +251,7 @@ public:
265 }251 }
266252
267 ~GjsInit() {253 ~GjsInit() {
268 shutdown();254 JS_ShutDown();
269 }255 }
270256
271 operator bool() {257 operator bool() {
@@ -322,13 +308,14 @@ gjs_create_js_context(GjsContext *js_context)
322 JS::ContextOptionsRef(cx).setExtraWarnings(true);308 JS::ContextOptionsRef(cx).setExtraWarnings(true);
323 }309 }
324310
325 if (!g_getenv("GJS_DISABLE_JIT")) {311 bool enable_jit = !(g_getenv("GJS_DISABLE_JIT"));
312 if (enable_jit) {
326 gjs_debug(GJS_DEBUG_CONTEXT, "Enabling JIT");313 gjs_debug(GJS_DEBUG_CONTEXT, "Enabling JIT");
327 JS::ContextOptionsRef(cx)
328 .setIon(true)
329 .setBaseline(true)
330 .setAsmJS(true);
331 }314 }
315 JS::ContextOptionsRef(cx)
316 .setIon(enable_jit)
317 .setBaseline(enable_jit)
318 .setAsmJS(enable_jit);
332319
333 return cx;320 return cx;
334}321}
diff --git a/gjs/importer.cpp b/gjs/importer.cpp
index b4ea3c8..4c42a84 100644
--- a/gjs/importer.cpp
+++ b/gjs/importer.cpp
@@ -706,7 +706,7 @@ importer_enumerate(JSContext *context,
706 /* new_for_commandline_arg handles resource:/// paths */706 /* new_for_commandline_arg handles resource:/// paths */
707 GjsAutoUnref<GFile> dir = g_file_new_for_commandline_arg(dirname);707 GjsAutoUnref<GFile> dir = g_file_new_for_commandline_arg(dirname);
708 GjsAutoUnref<GFileEnumerator> direnum =708 GjsAutoUnref<GFileEnumerator> direnum =
709 g_file_enumerate_children(dir, G_FILE_ATTRIBUTE_STANDARD_TYPE,709 g_file_enumerate_children(dir, "standard::name,standard::type",
710 G_FILE_QUERY_INFO_NONE, NULL, NULL);710 G_FILE_QUERY_INFO_NONE, NULL, NULL);
711711
712 while (true) {712 while (true) {
diff --git a/gjs/jsapi-util-root.h b/gjs/jsapi-util-root.h
index 5baed48..d64eccb 100644
--- a/gjs/jsapi-util-root.h
+++ b/gjs/jsapi-util-root.h
@@ -219,6 +219,7 @@ public:
219 return m_root->get() == nullptr;219 return m_root->get() == nullptr;
220 return m_heap.unbarrieredGet() == nullptr;220 return m_heap.unbarrieredGet() == nullptr;
221 }221 }
222 inline bool operator!=(std::nullptr_t) const { return !(*this == nullptr); }
222223
223 /* You can get a Handle<T> if the thing is rooted, so that you can use this224 /* You can get a Handle<T> if the thing is rooted, so that you can use this
224 * wrapper with stack rooting. However, you must not do this if the225 * wrapper with stack rooting. However, you must not do this if the
@@ -247,10 +248,12 @@ public:
247 m_data = data;248 m_data = data;
248 m_root = new JS::PersistentRooted<T>(m_cx, thing);249 m_root = new JS::PersistentRooted<T>(m_cx, thing);
249250
250 auto gjs_cx = static_cast<GjsContext *>(JS_GetContextPrivate(m_cx));251 if (notify) {
251 g_assert(GJS_IS_CONTEXT(gjs_cx));252 auto gjs_cx = static_cast<GjsContext *>(JS_GetContextPrivate(m_cx));
252 g_object_weak_ref(G_OBJECT(gjs_cx), on_context_destroy, this);253 g_assert(GJS_IS_CONTEXT(gjs_cx));
253 m_has_weakref = true;254 g_object_weak_ref(G_OBJECT(gjs_cx), on_context_destroy, this);
255 m_has_weakref = true;
256 }
254 }257 }
255258
256 /* You can only assign directly to the GjsMaybeOwned wrapper in the259 /* You can only assign directly to the GjsMaybeOwned wrapper in the
diff --git a/gjs/jsapi-util.cpp b/gjs/jsapi-util.cpp
index 322a41b..ed3e649 100644
--- a/gjs/jsapi-util.cpp
+++ b/gjs/jsapi-util.cpp
@@ -26,6 +26,8 @@
2626
27#include <codecvt>27#include <codecvt>
28#include <locale>28#include <locale>
29#include "jsapi-wrapper.h"
30#include <js/GCAPI.h>
2931
30#include <util/log.h>32#include <util/log.h>
31#include <util/glib.h>33#include <util/glib.h>
@@ -34,7 +36,6 @@
3436
35#include "jsapi-class.h"37#include "jsapi-class.h"
36#include "jsapi-util.h"38#include "jsapi-util.h"
37#include "jsapi-wrapper.h"
38#include "context-private.h"39#include "context-private.h"
39#include <gi/boxed.h>40#include <gi/boxed.h>
4041
@@ -313,8 +314,9 @@ gjs_build_string_array(JSContext *context,
313 g_error("Unable to reserve memory for vector");314 g_error("Unable to reserve memory for vector");
314315
315 for (i = 0; i < array_length; ++i) {316 for (i = 0; i < array_length; ++i) {
317 JS::ConstUTF8CharsZ chars(array_values[i], strlen(array_values[i]));
316 JS::RootedValue element(context,318 JS::RootedValue element(context,
317 JS::StringValue(JS_NewStringCopyZ(context, array_values[i])));319 JS::StringValue(JS_NewStringCopyUTF8Z(context, chars)));
318 if (!elems.append(element))320 if (!elems.append(element))
319 g_error("Unable to append to vector");321 g_error("Unable to append to vector");
320 }322 }
@@ -731,7 +733,7 @@ gjs_gc_if_needed (JSContext *context)
731 */733 */
732 if (rss_size > linux_rss_trigger) {734 if (rss_size > linux_rss_trigger) {
733 linux_rss_trigger = (gulong) MIN(G_MAXULONG, rss_size * 1.25);735 linux_rss_trigger = (gulong) MIN(G_MAXULONG, rss_size * 1.25);
734 JS_GC(context);736 JS::GCForReason(context, GC_SHRINK, JS::gcreason::Reason::API);
735 } else if (rss_size < (0.75 * linux_rss_trigger)) {737 } else if (rss_size < (0.75 * linux_rss_trigger)) {
736 /* If we've shrunk by 75%, lower the trigger */738 /* If we've shrunk by 75%, lower the trigger */
737 linux_rss_trigger = (rss_size * 1.25);739 linux_rss_trigger = (rss_size * 1.25);
diff --git a/installed-tests/extra/gjs.supp b/installed-tests/extra/gjs.supp
index a768e27..b99eb25 100644
--- a/installed-tests/extra/gjs.supp
+++ b/installed-tests/extra/gjs.supp
@@ -1,35 +1,6 @@
1# Valgrind suppressions file for GJS1# Valgrind suppressions file for GJS
2# This is intended to be used in addition to GLib's glib.supp file.2# This is intended to be used in addition to GLib's glib.supp file.
33
4# We leak a small wrapper in GJS for each registered GType.
5
6{
7 gtype-wrapper-new
8 Memcheck:Leak
9 match-leak-kinds: definite
10 fun:_Znwm
11 fun:gjs_gtype_create_gtype_wrapper
12}
13
14{
15 gtype-wrapper-qdata
16 Memcheck:Leak
17 match-leak-kinds: possible
18 ...
19 fun:type_set_qdata_W
20 fun:g_type_set_qdata
21 fun:gjs_gtype_create_gtype_wrapper
22}
23
24{
25 g_type_register_fundamental never freed
26 Memcheck:Leak
27 fun:calloc
28 ...
29 fun:g_type_register_fundamental
30 ...
31}
32
33# SpiderMonkey leaks4# SpiderMonkey leaks
345
35{6{
@@ -143,6 +114,29 @@
143 fun:cairo_show_text114 fun:cairo_show_text
144}115}
145116
117# Data that Cairo keeps around for the process lifetime
118# This could be freed by calling cairo_debug_reset_static_data(), but it's
119# not a good idea to call that function in production, because certain versions
120# of Cairo have bugs that cause it to fail assertions and crash.
121{
122 cairo-static-data
123 Memcheck:Leak
124 match-leak-kinds: definite
125 fun:malloc
126 ...
127 fun:FcPatternDuplicate
128 fun:_cairo_ft_font_face_create_for_pattern
129 fun:_cairo_ft_font_face_create_for_toy
130 fun:_cairo_toy_font_face_create_impl_face
131 fun:_cairo_toy_font_face_init
132 fun:cairo_toy_font_face_create
133 fun:_cairo_gstate_ensure_font_face
134 fun:_cairo_gstate_ensure_scaled_font
135 fun:_cairo_gstate_get_scaled_font
136 fun:_cairo_default_context_get_scaled_font
137 fun:cairo_show_text
138}
139
146# SpiderMonkey data races140# SpiderMonkey data races
147141
148# These are in SpiderMonkey's atomics / thread barrier stuff so presumably142# These are in SpiderMonkey's atomics / thread barrier stuff so presumably
diff --git a/installed-tests/extra/lsan.supp b/installed-tests/extra/lsan.supp
index 179eb9c..3c69851 100644
--- a/installed-tests/extra/lsan.supp
+++ b/installed-tests/extra/lsan.supp
@@ -1,8 +1,5 @@
1# SpiderMonkey leaks a mutex for each GC helper thread.1# SpiderMonkey leaks a mutex for each GC helper thread.
2leak:js::HelperThread::threadLoop2leak:js::HelperThread::threadLoop
33
4# We leak a small wrapper in GJS for each registered GType.
5leak:gjs_gtype_create_gtype_wrapper
6
7# https://bugs.freedesktop.org/show_bug.cgi?id=1054664# https://bugs.freedesktop.org/show_bug.cgi?id=105466
8leak:libfontconfig.so.15leak:libfontconfig.so.1
diff --git a/modules/overrides/GObject.js b/modules/overrides/GObject.js
index 741a9f3..bf1ae97 100644
--- a/modules/overrides/GObject.js
+++ b/modules/overrides/GObject.js
@@ -441,6 +441,14 @@ function _init() {
441 GObject._children = _children;441 GObject._children = _children;
442 GObject._internalChildren = _internalChildren;442 GObject._internalChildren = _internalChildren;
443443
444 // Expose GObject static properties for ES6 classes
445
446 GObject.GTypeName = GTypeName;
447 GObject.requires = requires;
448 GObject.interfaces = interfaces;
449 GObject.properties = properties;
450 GObject.signals = signals;
451
444 // fake enum for signal accumulators, keep in sync with gi/object.c452 // fake enum for signal accumulators, keep in sync with gi/object.c
445 this.AccumulatorType = {453 this.AccumulatorType = {
446 NONE: 0,454 NONE: 0,
diff --git a/modules/tweener/tweener.js b/modules/tweener/tweener.js
index 98bde02..61c6654 100644
--- a/modules/tweener/tweener.js
+++ b/modules/tweener/tweener.js
@@ -368,7 +368,7 @@ function _onEnterFrame() {
368 return true;368 return true;
369}369}
370370
371const restrictedWords = {371var restrictedWords = {
372 time: true,372 time: true,
373 delay: true,373 delay: true,
374 userFrames: true,374 userFrames: true,
diff --git a/win32/config.h.win32 b/win32/config.h.win32
index 7495f0a..1e78fa6 100644
--- a/win32/config.h.win32
+++ b/win32/config.h.win32
@@ -13,7 +13,7 @@
13#define GETTEXT_PACKAGE "gjs"13#define GETTEXT_PACKAGE "gjs"
1414
15/* The gjs version as an integer */15/* The gjs version as an integer */
16#define GJS_VERSION 1520116#define GJS_VERSION 15205
1717
18/* define if the compiler supports basic C++11 syntax */18/* define if the compiler supports basic C++11 syntax */
19#define HAVE_CXX11 119#define HAVE_CXX11 1
@@ -74,7 +74,7 @@
74#define PACKAGE_NAME "gjs"74#define PACKAGE_NAME "gjs"
7575
76/* Define to the full name and version of this package. */76/* Define to the full name and version of this package. */
77#define PACKAGE_STRING "gjs 1.52.1"77#define PACKAGE_STRING "gjs 1.52.5"
7878
79/* Define to the one symbol short name of this package. */79/* Define to the one symbol short name of this package. */
80#define PACKAGE_TARNAME "gjs"80#define PACKAGE_TARNAME "gjs"
@@ -83,10 +83,10 @@
83#define PACKAGE_URL ""83#define PACKAGE_URL ""
8484
85/* Define to the version of this package. */85/* Define to the version of this package. */
86#define PACKAGE_VERSION "1.52.1"86#define PACKAGE_VERSION "1.52.5"
8787
88/* Define to 1 if you have the ANSI C header files. */88/* Define to 1 if you have the ANSI C header files. */
89#define STDC_HEADERS 189#define STDC_HEADERS 1
9090
91/* Version number of package */91/* Version number of package */
92#define VERSION "1.52.1"92#define VERSION "1.52.5"

Subscribers

People subscribed via source and target branches