Merge ~3v1n0/ubuntu/+source/gjs:ubuntu/bionic into ~ubuntu-desktop/ubuntu/+source/gjs:ubuntu/bionic
- Git
- lp:~3v1n0/ubuntu/+source/gjs
- ubuntu/bionic
- Merge into 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) |
||||||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Ubuntu Desktop | Pending | ||
Review via email: mp+361167@code.launchpad.net |
Commit message
Description of the change
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
1 | diff --git a/Makefile.in b/Makefile.in | |||
2 | index fea2a6b..ed5566b 100644 | |||
3 | --- a/Makefile.in | |||
4 | +++ b/Makefile.in | |||
5 | @@ -756,9 +756,8 @@ am__DIST_COMMON = $(srcdir)/Makefile-examples.am \ | |||
6 | 756 | $(srcdir)/config.h.in $(srcdir)/gjs-1.0.pc.in \ | 756 | $(srcdir)/config.h.in $(srcdir)/gjs-1.0.pc.in \ |
7 | 757 | $(srcdir)/gjs-modules-srcs.mk $(srcdir)/gjs-srcs.mk \ | 757 | $(srcdir)/gjs-modules-srcs.mk $(srcdir)/gjs-srcs.mk \ |
8 | 758 | $(top_srcdir)/win32/config.h.win32.in AUTHORS COPYING \ | 758 | $(top_srcdir)/win32/config.h.win32.in AUTHORS COPYING \ |
12 | 759 | ChangeLog INSTALL NEWS README compile config.guess \ | 759 | ChangeLog INSTALL NEWS README compile config.guess config.sub \ |
13 | 760 | config.rpath config.sub depcomp install-sh ltmain.sh missing \ | 760 | depcomp install-sh ltmain.sh missing tap-driver.sh |
11 | 761 | tap-driver.sh | ||
14 | 762 | DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) | 761 | DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) |
15 | 763 | distdir = $(PACKAGE)-$(VERSION) | 762 | distdir = $(PACKAGE)-$(VERSION) |
16 | 764 | top_distdir = $(distdir) | 763 | top_distdir = $(distdir) |
17 | diff --git a/NEWS b/NEWS | |||
18 | index 43feb1f..1e33aa5 100644 | |||
19 | --- a/NEWS | |||
20 | +++ b/NEWS | |||
21 | @@ -1,3 +1,76 @@ | |||
22 | 1 | Version 1.52.5 | ||
23 | 2 | -------------- | ||
24 | 3 | |||
25 | 4 | - This release includes the "Big Hammer" patch from GNOME 3.30 to reduce memory | ||
26 | 5 | usage. For more information, read the blog post at | ||
27 | 6 | https://feaneron.com/2018/04/20/the-infamous-gnome-shell-memory-leak/ | ||
28 | 7 | It was not originally intended to be backported to GNOME 3.28, but in practice | ||
29 | 8 | several Linux distributions already backported it, and it has been working | ||
30 | 9 | well to reduce memory usage, and the bugs have been ironed out of it. | ||
31 | 10 | |||
32 | 11 | It does decrease performance somewhat, so if you don't want that then don't | ||
33 | 12 | install this update. | ||
34 | 13 | |||
35 | 14 | - Closed bugs and merge requests: | ||
36 | 15 | |||
37 | 16 | * Ensure not to miss the force_gc flag [#150, !132, Carlos Garnacho] | ||
38 | 17 | * Make GC much more aggressive [#62, !50, Giovanni Campagna, Georges Basile | ||
39 | 18 | Stavracas Neto, Philip Chimento] | ||
40 | 19 | * Queue GC when a GObject reference is toggled down [#140, !114, !127, Georges | ||
41 | 20 | Basile Stavracas Neto] | ||
42 | 21 | * Reduce memory overhead of g_object_weak_ref() [#144, !122, Carlos Garnacho, | ||
43 | 22 | Philip Chimento] | ||
44 | 23 | * context: Defer and therefore batch forced GC runs [performance] [!236, | ||
45 | 24 | Daniel van Vugt] | ||
46 | 25 | * context: use timeout with seconds to schedule a gc trigger [!239, Marco | ||
47 | 26 | Trevisan] | ||
48 | 27 | * Use compacting GC on RSS size growth [!133, #151, Carlos Garnacho] | ||
49 | 28 | * GType memleak fixes [!244, Marco Trevisan] | ||
50 | 29 | |||
51 | 30 | Version 1.52.4 | ||
52 | 31 | -------------- | ||
53 | 32 | |||
54 | 33 | - Closed bugs and merge requests: | ||
55 | 34 | |||
56 | 35 | * `ARGV` encoding issues [#22, !108, Evan Welsh] | ||
57 | 36 | * Segfault on enumeration of GjSFileImporter properties when a searchpath | ||
58 | 37 | entry contains a symlink [#154, !144, Ole Jørgen Brønner] | ||
59 | 38 | * Possible refcounting bug around GtkListbox signal handlers [#24, !154, | ||
60 | 39 | Philip Chimento] | ||
61 | 40 | * Fix up GJS_DISABLE_JIT flag now the JIT is enabled by default in | ||
62 | 41 | SpiderMonkey [!159, Christopher Wheeldon] | ||
63 | 42 | * Expose GObject static property symbols. [!197, Evan Welsh] | ||
64 | 43 | * Do not run linters on tagged commits [!181, Claudio André] | ||
65 | 44 | * gjs-1.52.0 fails to compile against x86_64 musl systems [#132, !214, Philip | ||
66 | 45 | Chimento] | ||
67 | 46 | * gjs no longer builds after recent autoconf-archive updates [#149, !217, | ||
68 | 47 | Philip Chimento] | ||
69 | 48 | |||
70 | 49 | Version 1.52.3 | ||
71 | 50 | -------------- | ||
72 | 51 | |||
73 | 52 | - Closed bugs and merge requests: | ||
74 | 53 | |||
75 | 54 | * Include calc.js example from Seed [!130, William Barath, Philip Chimento] | ||
76 | 55 | * CI: Un-pin the Fedora Docker image [#141, !131, Claudio André] | ||
77 | 56 | * Reduce overhead of wrapped objects [#142, !121, Carlos Garnacho, Philip | ||
78 | 57 | Chimento] | ||
79 | 58 | * Various CI changes [!134, !136, Claudio André] | ||
80 | 59 | |||
81 | 60 | Version 1.52.2 | ||
82 | 61 | -------------- | ||
83 | 62 | |||
84 | 63 | - This is an unscheuled release in order to revert a commit that causes a crash | ||
85 | 64 | on exit, with some Cairo versions. | ||
86 | 65 | |||
87 | 66 | - Closed bugs and merge requests: | ||
88 | 67 | |||
89 | 68 | * CI: pinned Fedora to old tag [!119, Claudio André] | ||
90 | 69 | * heapgraph.py: adjust terminal output style [!120, Andy Holmes] | ||
91 | 70 | * CI: small tweaks [!123, Claudio André] | ||
92 | 71 | * Warn about compilation warnings [!125, Claudio André] | ||
93 | 72 | * Miscellaneous commits [Philip Chimento, Jason Hicks] | ||
94 | 73 | |||
95 | 1 | Version 1.52.1 | 74 | Version 1.52.1 |
96 | 2 | -------------- | 75 | -------------- |
97 | 3 | 76 | ||
98 | diff --git a/config.rpath b/config.rpath | |||
99 | 4 | deleted file mode 100644 | 77 | deleted file mode 100644 |
100 | index e69de29..0000000 | |||
101 | --- a/config.rpath | |||
102 | +++ /dev/null | |||
103 | diff --git a/configure b/configure | |||
104 | index 8410fb2..b79e278 100755 | |||
105 | --- a/configure | |||
106 | +++ b/configure | |||
107 | @@ -1,6 +1,6 @@ | |||
108 | 1 | #! /bin/sh | 1 | #! /bin/sh |
109 | 2 | # Guess values for system-dependent variables and create Makefiles. | 2 | # Guess values for system-dependent variables and create Makefiles. |
111 | 3 | # Generated by GNU Autoconf 2.69 for gjs 1.52.1. | 3 | # Generated by GNU Autoconf 2.69 for gjs 1.52.5. |
112 | 4 | # | 4 | # |
113 | 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>. |
114 | 6 | # | 6 | # |
115 | @@ -591,8 +591,8 @@ MAKEFLAGS= | |||
116 | 591 | # Identity of this package. | 591 | # Identity of this package. |
117 | 592 | PACKAGE_NAME='gjs' | 592 | PACKAGE_NAME='gjs' |
118 | 593 | PACKAGE_TARNAME='gjs' | 593 | PACKAGE_TARNAME='gjs' |
121 | 594 | PACKAGE_VERSION='1.52.1' | 594 | PACKAGE_VERSION='1.52.5' |
122 | 595 | PACKAGE_STRING='gjs 1.52.1' | 595 | PACKAGE_STRING='gjs 1.52.5' |
123 | 596 | PACKAGE_BUGREPORT='http://bugzilla.gnome.org/enter_bug.cgi?product=gjs' | 596 | PACKAGE_BUGREPORT='http://bugzilla.gnome.org/enter_bug.cgi?product=gjs' |
124 | 597 | PACKAGE_URL='https://wiki.gnome.org/Projects/Gjs' | 597 | PACKAGE_URL='https://wiki.gnome.org/Projects/Gjs' |
125 | 598 | 598 | ||
126 | @@ -1451,7 +1451,7 @@ if test "$ac_init_help" = "long"; then | |||
127 | 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. |
128 | 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. |
129 | 1453 | cat <<_ACEOF | 1453 | cat <<_ACEOF |
131 | 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. |
132 | 1455 | 1455 | ||
133 | 1456 | Usage: $0 [OPTION]... [VAR=VALUE]... | 1456 | Usage: $0 [OPTION]... [VAR=VALUE]... |
134 | 1457 | 1457 | ||
135 | @@ -1521,7 +1521,7 @@ fi | |||
136 | 1521 | 1521 | ||
137 | 1522 | if test -n "$ac_init_help"; then | 1522 | if test -n "$ac_init_help"; then |
138 | 1523 | case $ac_init_help in | 1523 | case $ac_init_help in |
140 | 1524 | short | recursive ) echo "Configuration of gjs 1.52.1:";; | 1524 | short | recursive ) echo "Configuration of gjs 1.52.5:";; |
141 | 1525 | esac | 1525 | esac |
142 | 1526 | cat <<\_ACEOF | 1526 | cat <<\_ACEOF |
143 | 1527 | 1527 | ||
144 | @@ -1700,7 +1700,7 @@ fi | |||
145 | 1700 | test -n "$ac_init_help" && exit $ac_status | 1700 | test -n "$ac_init_help" && exit $ac_status |
146 | 1701 | if $ac_init_version; then | 1701 | if $ac_init_version; then |
147 | 1702 | cat <<\_ACEOF | 1702 | cat <<\_ACEOF |
149 | 1703 | gjs configure 1.52.1 | 1703 | gjs configure 1.52.5 |
150 | 1704 | generated by GNU Autoconf 2.69 | 1704 | generated by GNU Autoconf 2.69 |
151 | 1705 | 1705 | ||
152 | 1706 | Copyright (C) 2012 Free Software Foundation, Inc. | 1706 | Copyright (C) 2012 Free Software Foundation, Inc. |
153 | @@ -2251,7 +2251,7 @@ cat >config.log <<_ACEOF | |||
154 | 2251 | This file contains any messages produced by compilers while | 2251 | This file contains any messages produced by compilers while |
155 | 2252 | running configure, to aid debugging if configure makes a mistake. | 2252 | running configure, to aid debugging if configure makes a mistake. |
156 | 2253 | 2253 | ||
158 | 2254 | It was created by gjs $as_me 1.52.1, which was | 2254 | It was created by gjs $as_me 1.52.5, which was |
159 | 2255 | generated by GNU Autoconf 2.69. Invocation command line was | 2255 | generated by GNU Autoconf 2.69. Invocation command line was |
160 | 2256 | 2256 | ||
161 | 2257 | $ $0 $@ | 2257 | $ $0 $@ |
162 | @@ -3114,7 +3114,7 @@ fi | |||
163 | 3114 | 3114 | ||
164 | 3115 | # Define the identity of the package. | 3115 | # Define the identity of the package. |
165 | 3116 | PACKAGE='gjs' | 3116 | PACKAGE='gjs' |
167 | 3117 | VERSION='1.52.1' | 3117 | VERSION='1.52.5' |
168 | 3118 | 3118 | ||
169 | 3119 | 3119 | ||
170 | 3120 | cat >>confdefs.h <<_ACEOF | 3120 | cat >>confdefs.h <<_ACEOF |
171 | @@ -3341,10 +3341,10 @@ ac_config_headers="$ac_config_headers config.h" | |||
172 | 3341 | 3341 | ||
173 | 3342 | 3342 | ||
174 | 3343 | 3343 | ||
176 | 3344 | GJS_VERSION=15201 | 3344 | GJS_VERSION=15205 |
177 | 3345 | 3345 | ||
178 | 3346 | 3346 | ||
180 | 3347 | $as_echo "#define GJS_VERSION (1 * 100 + 52) * 100 + 1" >>confdefs.h | 3347 | $as_echo "#define GJS_VERSION (1 * 100 + 52) * 100 + 5" >>confdefs.h |
181 | 3348 | 3348 | ||
182 | 3349 | 3349 | ||
183 | 3350 | GETTEXT_PACKAGE=gjs | 3350 | GETTEXT_PACKAGE=gjs |
184 | @@ -21806,6 +21806,7 @@ fi | |||
185 | 21806 | 21806 | ||
186 | 21807 | if test x$enable_profiler != xno; then : | 21807 | if test x$enable_profiler != xno; then : |
187 | 21808 | 21808 | ||
188 | 21809 | # Requires timer_settime() - only on Linux | ||
189 | 21809 | 21810 | ||
190 | 21810 | 21811 | ||
191 | 21811 | 21812 | ||
192 | @@ -21886,8 +21887,37 @@ done | |||
193 | 21886 | 21887 | ||
194 | 21887 | LIBS=$gl_saved_libs | 21888 | LIBS=$gl_saved_libs |
195 | 21888 | 21889 | ||
197 | 21889 | if test x$ac_cv_func_timer_settime = xno; then : | 21890 | # Requires SIGEV_THREAD_ID - not in some stdlibs |
198 | 21891 | have_sigev_thread_id=no | ||
199 | 21892 | { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Linux SIGEV_THREAD_ID" >&5 | ||
200 | 21893 | $as_echo_n "checking for Linux SIGEV_THREAD_ID... " >&6; } | ||
201 | 21894 | cat confdefs.h - <<_ACEOF >conftest.$ac_ext | ||
202 | 21895 | /* end confdefs.h. */ | ||
203 | 21896 | |||
204 | 21897 | #include <signal.h> | ||
205 | 21898 | int | ||
206 | 21899 | main () | ||
207 | 21900 | { | ||
208 | 21901 | return SIGEV_THREAD_ID; | ||
209 | 21902 | ; | ||
210 | 21903 | return 0; | ||
211 | 21904 | } | ||
212 | 21905 | |||
213 | 21906 | _ACEOF | ||
214 | 21907 | if ac_fn_cxx_try_compile "$LINENO"; then : | ||
215 | 21908 | |||
216 | 21909 | have_sigev_thread_id=yes | ||
217 | 21910 | { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 | ||
218 | 21911 | $as_echo "yes" >&6; } | ||
219 | 21912 | |||
220 | 21913 | else | ||
221 | 21914 | { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 | ||
222 | 21915 | $as_echo "no" >&6; } | ||
223 | 21916 | fi | ||
224 | 21917 | rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext | ||
225 | 21918 | if test x$ac_cv_func_timer_settime = xno -o x$have_sigev_thread_id = xno; then : | ||
226 | 21890 | as_fn_error $? "The profiler is currently only supported on Linux. | 21919 | as_fn_error $? "The profiler is currently only supported on Linux. |
227 | 21920 | The standard library must support timer_settime() and SIGEV_THREAD_ID. | ||
228 | 21891 | Configure with --disable-profiler to skip it on other platforms." "$LINENO" 5 | 21921 | Configure with --disable-profiler to skip it on other platforms." "$LINENO" 5 |
229 | 21892 | fi | 21922 | fi |
230 | 21893 | 21923 | ||
231 | @@ -23346,7 +23376,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 | |||
232 | 23346 | # report actual input values of CONFIG_FILES etc. instead of their | 23376 | # report actual input values of CONFIG_FILES etc. instead of their |
233 | 23347 | # values after options handling. | 23377 | # values after options handling. |
234 | 23348 | ac_log=" | 23378 | ac_log=" |
236 | 23349 | This file was extended by gjs $as_me 1.52.1, which was | 23379 | This file was extended by gjs $as_me 1.52.5, which was |
237 | 23350 | generated by GNU Autoconf 2.69. Invocation command line was | 23380 | generated by GNU Autoconf 2.69. Invocation command line was |
238 | 23351 | 23381 | ||
239 | 23352 | CONFIG_FILES = $CONFIG_FILES | 23382 | CONFIG_FILES = $CONFIG_FILES |
240 | @@ -23417,7 +23447,7 @@ _ACEOF | |||
241 | 23417 | cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 | 23447 | cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 |
242 | 23418 | ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" | 23448 | ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" |
243 | 23419 | ac_cs_version="\\ | 23449 | ac_cs_version="\\ |
245 | 23420 | gjs config.status 1.52.1 | 23450 | gjs config.status 1.52.5 |
246 | 23421 | configured by $0, generated by GNU Autoconf 2.69, | 23451 | configured by $0, generated by GNU Autoconf 2.69, |
247 | 23422 | with options \\"\$ac_cs_config\\" | 23452 | with options \\"\$ac_cs_config\\" |
248 | 23423 | 23453 | ||
249 | diff --git a/configure.ac b/configure.ac | |||
250 | index c7b7dcb..1c62d93 100644 | |||
251 | --- a/configure.ac | |||
252 | +++ b/configure.ac | |||
253 | @@ -3,7 +3,7 @@ | |||
254 | 3 | 3 | ||
255 | 4 | m4_define(pkg_major_version, 1) | 4 | m4_define(pkg_major_version, 1) |
256 | 5 | m4_define(pkg_minor_version, 52) | 5 | m4_define(pkg_minor_version, 52) |
258 | 6 | m4_define(pkg_micro_version, 1) | 6 | m4_define(pkg_micro_version, 5) |
259 | 7 | m4_define(pkg_version, pkg_major_version.pkg_minor_version.pkg_micro_version) | 7 | m4_define(pkg_version, pkg_major_version.pkg_minor_version.pkg_micro_version) |
260 | 8 | m4_define(pkg_int_version, (pkg_major_version * 100 + pkg_minor_version) * 100 + pkg_micro_version) | 8 | m4_define(pkg_int_version, (pkg_major_version * 100 + pkg_minor_version) * 100 + pkg_micro_version) |
261 | 9 | 9 | ||
262 | @@ -152,9 +152,20 @@ AS_IF([test x$have_gtk = xyes], [ | |||
263 | 152 | AC_ARG_ENABLE([profiler], | 152 | AC_ARG_ENABLE([profiler], |
264 | 153 | [AS_HELP_STRING([--disable-profiler], [Don't build profiler])]) | 153 | [AS_HELP_STRING([--disable-profiler], [Don't build profiler])]) |
265 | 154 | AS_IF([test x$enable_profiler != xno], [ | 154 | AS_IF([test x$enable_profiler != xno], [ |
266 | 155 | # Requires timer_settime() - only on Linux | ||
267 | 155 | gl_TIMER_TIME | 156 | gl_TIMER_TIME |
269 | 156 | AS_IF([test x$ac_cv_func_timer_settime = xno], | 157 | # Requires SIGEV_THREAD_ID - not in some stdlibs |
270 | 158 | have_sigev_thread_id=no | ||
271 | 159 | AC_MSG_CHECKING([for Linux SIGEV_THREAD_ID]) | ||
272 | 160 | AC_COMPILE_IFELSE([ | ||
273 | 161 | AC_LANG_PROGRAM([[#include <signal.h>]], [return SIGEV_THREAD_ID;]) | ||
274 | 162 | ], [ | ||
275 | 163 | have_sigev_thread_id=yes | ||
276 | 164 | AC_MSG_RESULT([yes]) | ||
277 | 165 | ], [AC_MSG_RESULT([no])]) | ||
278 | 166 | AS_IF([test x$ac_cv_func_timer_settime = xno -o x$have_sigev_thread_id = xno], | ||
279 | 157 | [AC_MSG_ERROR([The profiler is currently only supported on Linux. | 167 | [AC_MSG_ERROR([The profiler is currently only supported on Linux. |
280 | 168 | The standard library must support timer_settime() and SIGEV_THREAD_ID. | ||
281 | 158 | Configure with --disable-profiler to skip it on other platforms.])]) | 169 | Configure with --disable-profiler to skip it on other platforms.])]) |
282 | 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.]) |
283 | 160 | ]) | 171 | ]) |
284 | diff --git a/debian/changelog b/debian/changelog | |||
285 | index feae994..c276370 100644 | |||
286 | --- a/debian/changelog | |||
287 | +++ b/debian/changelog | |||
288 | @@ -1,3 +1,13 @@ | |||
289 | 1 | gjs (1.52.5-0~ubuntu18.04.1) UNRELEASED; urgency=medium | ||
290 | 2 | |||
291 | 3 | * New upstream release (LP: #1809181, LP: #1803271) | ||
292 | 4 | * d/p/fix-crashes-lp1763878-revert-575f1e2e077.patch, | ||
293 | 5 | d/p/fix-leaks-lp1672297-1-context-Add-API-to-force-GC-schedule.patch, | ||
294 | 6 | d/p/fix-leaks-lp1672297-2-object-Queue-a-forced-GC-when-toggling-down.patch: | ||
295 | 7 | - Drop patches included in new release | ||
296 | 8 | * debian/gbp.conf: | ||
297 | 9 | - Point branches and tag rules to ubuntu | ||
298 | 10 | |||
299 | 1 | gjs (1.52.1-1ubuntu1) bionic; urgency=medium | 11 | gjs (1.52.1-1ubuntu1) bionic; urgency=medium |
300 | 2 | 12 | ||
301 | 3 | * Add fix-crashes-lp1763878-revert-575f1e2e077.patch to fix shutdown | 13 | * Add fix-crashes-lp1763878-revert-575f1e2e077.patch to fix shutdown |
302 | diff --git a/debian/control b/debian/control | |||
303 | index bcbd2dc..d6cb30a 100644 | |||
304 | --- a/debian/control | |||
305 | +++ b/debian/control | |||
306 | @@ -25,8 +25,10 @@ Build-Depends: debhelper (>= 11), | |||
307 | 25 | xvfb <!nocheck> | 25 | xvfb <!nocheck> |
308 | 26 | Rules-Requires-Root: no | 26 | Rules-Requires-Root: no |
309 | 27 | Standards-Version: 4.1.3 | 27 | Standards-Version: 4.1.3 |
312 | 28 | Vcs-Git: https://salsa.debian.org/gnome-team/gjs.git | 28 | XS-Debian-Vcs-Browser: https://salsa.debian.org/gnome-team/gjs |
313 | 29 | Vcs-Browser: https://salsa.debian.org/gnome-team/gjs | 29 | XS-Debian-Vcs-Git: https://salsa.debian.org/gnome-team/gjs.git -b debian/1.52.x |
314 | 30 | Vcs-Browser: https://git.launchpad.net/~ubuntu-desktop/ubuntu/+source/gjs | ||
315 | 31 | Vcs-Git: https://git.launchpad.net/~ubuntu-desktop/ubuntu/+source/gjs -b ubuntu/bionic | ||
316 | 30 | Homepage: https://wiki.gnome.org/Projects/Gjs | 32 | Homepage: https://wiki.gnome.org/Projects/Gjs |
317 | 31 | 33 | ||
318 | 32 | Package: gjs | 34 | Package: gjs |
319 | diff --git a/debian/gbp.conf b/debian/gbp.conf | |||
320 | index e0196c4..0592ca0 100644 | |||
321 | --- a/debian/gbp.conf | |||
322 | +++ b/debian/gbp.conf | |||
323 | @@ -1,5 +1,6 @@ | |||
324 | 1 | [DEFAULT] | 1 | [DEFAULT] |
325 | 2 | pristine-tar = True | 2 | pristine-tar = True |
328 | 3 | debian-branch = debian/master | 3 | debian-branch = debian/bionic |
329 | 4 | upstream-branch = upstream/latest | 4 | debian-tag = ubuntu/%(version)s |
330 | 5 | upstream-branch = upstream/1.52.x | ||
331 | 5 | upstream-vcs-tag = %(version)s | 6 | upstream-vcs-tag = %(version)s |
332 | diff --git a/debian/patches/fix-crashes-lp1763878-revert-575f1e2e077.patch b/debian/patches/fix-crashes-lp1763878-revert-575f1e2e077.patch | |||
333 | 6 | deleted file mode 100644 | 7 | deleted file mode 100644 |
334 | index 4da9220..0000000 | |||
335 | --- a/debian/patches/fix-crashes-lp1763878-revert-575f1e2e077.patch | |||
336 | +++ /dev/null | |||
337 | @@ -1,69 +0,0 @@ | |||
338 | 1 | From 8510bede1dd1f8a5fb95a2f594b4d3a68289e5ea Mon Sep 17 00:00:00 2001 | ||
339 | 2 | From: Philip Chimento <philip.chimento@gmail.com> | ||
340 | 3 | Date: Sat, 14 Apr 2018 16:25:58 -0700 | ||
341 | 4 | Subject: [PATCH] Revert "engine: Free Cairo static data on shutdown" | ||
342 | 5 | |||
343 | 6 | This reverts commit 575f1e2e077af04a112b9e5eaabaf008b086568e. | ||
344 | 7 | Per https://bugs.freedesktop.org/show_bug.cgi?id=105466, calling | ||
345 | 8 | cairo_debug_reset_static_data() was supposed to be safe in production, | ||
346 | 9 | but actually it fails assertions on program exit, with certain Cairo | ||
347 | 10 | versions, including 1.14.12. | ||
348 | 11 | |||
349 | 12 | Unreviewed. | ||
350 | 13 | --- | ||
351 | 14 | gjs/engine.cpp | 18 ++---------------- | ||
352 | 15 | 1 file changed, 2 insertions(+), 16 deletions(-) | ||
353 | 16 | |||
354 | 17 | diff --git a/gjs/engine.cpp b/gjs/engine.cpp | ||
355 | 18 | index 90fa57c..67911ee 100644 | ||
356 | 19 | --- a/gjs/engine.cpp | ||
357 | 20 | +++ b/gjs/engine.cpp | ||
358 | 21 | @@ -37,10 +37,6 @@ | ||
359 | 22 | #include <windows.h> | ||
360 | 23 | #endif | ||
361 | 24 | |||
362 | 25 | -#ifdef ENABLE_CAIRO | ||
363 | 26 | -# include <cairo.h> | ||
364 | 27 | -#endif | ||
365 | 28 | - | ||
366 | 29 | /* Implementations of locale-specific operations; these are used | ||
367 | 30 | * in the implementation of String.localeCompare(), Date.toLocaleDateString(), | ||
368 | 31 | * and so forth. We take the straight-forward approach of converting | ||
369 | 32 | @@ -218,16 +214,6 @@ on_promise_unhandled_rejection(JSContext *cx, | ||
370 | 33 | std::move(stack)); | ||
371 | 34 | } | ||
372 | 35 | |||
373 | 36 | -static void | ||
374 | 37 | -shutdown(void) | ||
375 | 38 | -{ | ||
376 | 39 | - JS_ShutDown(); | ||
377 | 40 | - | ||
378 | 41 | -#ifdef ENABLE_CAIRO | ||
379 | 42 | - cairo_debug_reset_static_data(); /* for valgrind reports */ | ||
380 | 43 | -#endif | ||
381 | 44 | -} | ||
382 | 45 | - | ||
383 | 46 | #ifdef G_OS_WIN32 | ||
384 | 47 | HMODULE gjs_dll; | ||
385 | 48 | static bool gjs_is_inited = false; | ||
386 | 49 | @@ -245,7 +231,7 @@ LPVOID lpvReserved) | ||
387 | 50 | break; | ||
388 | 51 | |||
389 | 52 | case DLL_THREAD_DETACH: | ||
390 | 53 | - shutdown(); | ||
391 | 54 | + JS_ShutDown (); | ||
392 | 55 | break; | ||
393 | 56 | |||
394 | 57 | default: | ||
395 | 58 | @@ -265,7 +251,7 @@ public: | ||
396 | 59 | } | ||
397 | 60 | |||
398 | 61 | ~GjsInit() { | ||
399 | 62 | - shutdown(); | ||
400 | 63 | + JS_ShutDown(); | ||
401 | 64 | } | ||
402 | 65 | |||
403 | 66 | operator bool() { | ||
404 | 67 | -- | ||
405 | 68 | 2.17.0 | ||
406 | 69 | |||
407 | 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 | |||
408 | 70 | deleted file mode 100644 | 0 | deleted file mode 100644 |
409 | index 84944e6..0000000 | |||
410 | --- a/debian/patches/fix-leaks-lp1672297-1-context-Add-API-to-force-GC-schedule.patch | |||
411 | +++ /dev/null | |||
412 | @@ -1,90 +0,0 @@ | |||
413 | 1 | From 33cbbeb11b61a0ffc8ff50e261e5dd33806590f9 Mon Sep 17 00:00:00 2001 | ||
414 | 2 | From: Georges Basile Stavracas Neto <georges.stavracas@gmail.com> | ||
415 | 3 | Date: Fri, 30 Mar 2018 21:37:37 -0300 | ||
416 | 4 | Subject: [PATCH 1/2] context: Add API to force GC schedule | ||
417 | 5 | |||
418 | 6 | There are situations where we cannot run the | ||
419 | 7 | GC right away, but we also cannot ignore the | ||
420 | 8 | need of running it. | ||
421 | 9 | |||
422 | 10 | For those cases, add a new private function | ||
423 | 11 | that forces GC to happen on idle. | ||
424 | 12 | --- | ||
425 | 13 | gjs/context-private.h | 2 ++ | ||
426 | 14 | gjs/context.cpp | 29 +++++++++++++++++++++++++---- | ||
427 | 15 | 2 files changed, 27 insertions(+), 4 deletions(-) | ||
428 | 16 | |||
429 | 17 | diff --git a/gjs/context-private.h b/gjs/context-private.h | ||
430 | 18 | index 6dbe669..c45c8d0 100644 | ||
431 | 19 | --- a/gjs/context-private.h | ||
432 | 20 | +++ b/gjs/context-private.h | ||
433 | 21 | @@ -36,6 +36,8 @@ bool _gjs_context_destroying (GjsContext *js_context); | ||
434 | 22 | |||
435 | 23 | void _gjs_context_schedule_gc_if_needed (GjsContext *js_context); | ||
436 | 24 | |||
437 | 25 | +void _gjs_context_schedule_gc (GjsContext *js_context); | ||
438 | 26 | + | ||
439 | 27 | void _gjs_context_exit(GjsContext *js_context, | ||
440 | 28 | uint8_t exit_code); | ||
441 | 29 | |||
442 | 30 | diff --git a/gjs/context.cpp b/gjs/context.cpp | ||
443 | 31 | index c509943..77d7eaa 100644 | ||
444 | 32 | --- a/gjs/context.cpp | ||
445 | 33 | +++ b/gjs/context.cpp | ||
446 | 34 | @@ -90,6 +90,7 @@ struct _GjsContext { | ||
447 | 35 | uint8_t exit_code; | ||
448 | 36 | |||
449 | 37 | guint auto_gc_id; | ||
450 | 38 | + bool force_gc; | ||
451 | 39 | |||
452 | 40 | std::array<JS::PersistentRootedId*, GJS_STRING_LAST> const_strings; | ||
453 | 41 | |||
454 | 42 | @@ -592,21 +593,41 @@ trigger_gc_if_needed (gpointer user_data) | ||
455 | 43 | { | ||
456 | 44 | GjsContext *js_context = GJS_CONTEXT(user_data); | ||
457 | 45 | js_context->auto_gc_id = 0; | ||
458 | 46 | - gjs_gc_if_needed(js_context->context); | ||
459 | 47 | + | ||
460 | 48 | + if (js_context->force_gc) | ||
461 | 49 | + JS_GC(js_context->context); | ||
462 | 50 | + else | ||
463 | 51 | + gjs_gc_if_needed(js_context->context); | ||
464 | 52 | + | ||
465 | 53 | return G_SOURCE_REMOVE; | ||
466 | 54 | } | ||
467 | 55 | |||
468 | 56 | -void | ||
469 | 57 | -_gjs_context_schedule_gc_if_needed (GjsContext *js_context) | ||
470 | 58 | + | ||
471 | 59 | +static void | ||
472 | 60 | +_gjs_context_schedule_gc_internal (GjsContext *js_context, | ||
473 | 61 | + bool force_gc) | ||
474 | 62 | { | ||
475 | 63 | if (js_context->auto_gc_id > 0) | ||
476 | 64 | - return; | ||
477 | 65 | + g_source_remove(js_context->auto_gc_id); | ||
478 | 66 | |||
479 | 67 | + js_context->force_gc = force_gc; | ||
480 | 68 | js_context->auto_gc_id = g_idle_add_full(G_PRIORITY_LOW, | ||
481 | 69 | trigger_gc_if_needed, | ||
482 | 70 | js_context, NULL); | ||
483 | 71 | } | ||
484 | 72 | |||
485 | 73 | +void | ||
486 | 74 | +_gjs_context_schedule_gc (GjsContext *js_context) | ||
487 | 75 | +{ | ||
488 | 76 | + _gjs_context_schedule_gc_internal(js_context, true); | ||
489 | 77 | +} | ||
490 | 78 | + | ||
491 | 79 | +void | ||
492 | 80 | +_gjs_context_schedule_gc_if_needed (GjsContext *js_context) | ||
493 | 81 | +{ | ||
494 | 82 | + _gjs_context_schedule_gc_internal(js_context, false); | ||
495 | 83 | +} | ||
496 | 84 | + | ||
497 | 85 | void | ||
498 | 86 | _gjs_context_exit(GjsContext *js_context, | ||
499 | 87 | uint8_t exit_code) | ||
500 | 88 | -- | ||
501 | 89 | 2.17.0 | ||
502 | 90 | |||
503 | 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 | |||
504 | 91 | deleted file mode 100644 | 0 | deleted file mode 100644 |
505 | index 34f3d3b..0000000 | |||
506 | --- a/debian/patches/fix-leaks-lp1672297-2-object-Queue-a-forced-GC-when-toggling-down.patch | |||
507 | +++ /dev/null | |||
508 | @@ -1,123 +0,0 @@ | |||
509 | 1 | From 3f94b11a943c0e4d29c96930ced238580dc18fc7 Mon Sep 17 00:00:00 2001 | ||
510 | 2 | From: Georges Basile Stavracas Neto <georges.stavracas@gmail.com> | ||
511 | 3 | Date: Wed, 28 Mar 2018 19:21:52 -0300 | ||
512 | 4 | Subject: [PATCH 2/2] object: Queue a forced GC when toggling down | ||
513 | 5 | |||
514 | 6 | During a GC, the collector asks each object which other | ||
515 | 7 | objects that it wants to hold on to so if there's an entire | ||
516 | 8 | section of the heap graph that's not connected to anything | ||
517 | 9 | else, and not reachable from the root set, then it can be | ||
518 | 10 | trashed all at once. | ||
519 | 11 | |||
520 | 12 | GObjects, however, don't work like that, there's only a | ||
521 | 13 | reference count but no notion of who owns the reference so, | ||
522 | 14 | a JS object that's proxying a GObject is unconditionally held | ||
523 | 15 | alive as long as the GObject has >1 references. | ||
524 | 16 | |||
525 | 17 | Since we cannot know how many more wrapped GObjects are going | ||
526 | 18 | be marked for garbage collection after the owner is destroyed, | ||
527 | 19 | always queue a garbage collection when a toggle reference goes | ||
528 | 20 | down. | ||
529 | 21 | |||
530 | 22 | Issue: #140 | ||
531 | 23 | --- | ||
532 | 24 | gi/object.cpp | 22 ++++++++++++++++++++++ | ||
533 | 25 | gjs/context-private.h | 2 +- | ||
534 | 26 | gjs/context.cpp | 14 ++++++++------ | ||
535 | 27 | 3 files changed, 31 insertions(+), 7 deletions(-) | ||
536 | 28 | |||
537 | 29 | diff --git a/gi/object.cpp b/gi/object.cpp | ||
538 | 30 | index b20d8b9..f9cf3cc 100644 | ||
539 | 31 | --- a/gi/object.cpp | ||
540 | 32 | +++ b/gi/object.cpp | ||
541 | 33 | @@ -987,8 +987,30 @@ handle_toggle_down(GObject *gobj) | ||
542 | 34 | * collected by the GC | ||
543 | 35 | */ | ||
544 | 36 | if (priv->keep_alive.rooted()) { | ||
545 | 37 | + GjsContext *context; | ||
546 | 38 | + | ||
547 | 39 | gjs_debug_lifecycle(GJS_DEBUG_GOBJECT, "Unrooting object"); | ||
548 | 40 | priv->keep_alive.switch_to_unrooted(); | ||
549 | 41 | + | ||
550 | 42 | + /* During a GC, the collector asks each object which other | ||
551 | 43 | + * objects that it wants to hold on to so if there's an entire | ||
552 | 44 | + * section of the heap graph that's not connected to anything | ||
553 | 45 | + * else, and not reachable from the root set, then it can be | ||
554 | 46 | + * trashed all at once. | ||
555 | 47 | + * | ||
556 | 48 | + * GObjects, however, don't work like that, there's only a | ||
557 | 49 | + * reference count but no notion of who owns the reference so, | ||
558 | 50 | + * a JS object that's proxying a GObject is unconditionally held | ||
559 | 51 | + * alive as long as the GObject has >1 references. | ||
560 | 52 | + * | ||
561 | 53 | + * Since we cannot know how many more wrapped GObjects are going | ||
562 | 54 | + * be marked for garbage collection after the owner is destroyed, | ||
563 | 55 | + * always queue a garbage collection when a toggle reference goes | ||
564 | 56 | + * down. | ||
565 | 57 | + */ | ||
566 | 58 | + context = gjs_context_get_current(); | ||
567 | 59 | + if (!_gjs_context_destroying(context)) | ||
568 | 60 | + _gjs_context_schedule_gc(context); | ||
569 | 61 | } | ||
570 | 62 | } | ||
571 | 63 | |||
572 | 64 | diff --git a/gjs/context-private.h b/gjs/context-private.h | ||
573 | 65 | index c45c8d0..49c0cf9 100644 | ||
574 | 66 | --- a/gjs/context-private.h | ||
575 | 67 | +++ b/gjs/context-private.h | ||
576 | 68 | @@ -36,7 +36,7 @@ bool _gjs_context_destroying (GjsContext *js_context); | ||
577 | 69 | |||
578 | 70 | void _gjs_context_schedule_gc_if_needed (GjsContext *js_context); | ||
579 | 71 | |||
580 | 72 | -void _gjs_context_schedule_gc (GjsContext *js_context); | ||
581 | 73 | +void _gjs_context_schedule_gc(GjsContext *js_context); | ||
582 | 74 | |||
583 | 75 | void _gjs_context_exit(GjsContext *js_context, | ||
584 | 76 | uint8_t exit_code); | ||
585 | 77 | diff --git a/gjs/context.cpp b/gjs/context.cpp | ||
586 | 78 | index 77d7eaa..a2ce34a 100644 | ||
587 | 79 | --- a/gjs/context.cpp | ||
588 | 80 | +++ b/gjs/context.cpp | ||
589 | 81 | @@ -599,31 +599,33 @@ trigger_gc_if_needed (gpointer user_data) | ||
590 | 82 | else | ||
591 | 83 | gjs_gc_if_needed(js_context->context); | ||
592 | 84 | |||
593 | 85 | + js_context->force_gc = false; | ||
594 | 86 | + | ||
595 | 87 | return G_SOURCE_REMOVE; | ||
596 | 88 | } | ||
597 | 89 | |||
598 | 90 | |||
599 | 91 | static void | ||
600 | 92 | -_gjs_context_schedule_gc_internal (GjsContext *js_context, | ||
601 | 93 | - bool force_gc) | ||
602 | 94 | +_gjs_context_schedule_gc_internal(GjsContext *js_context, | ||
603 | 95 | + bool force_gc) | ||
604 | 96 | { | ||
605 | 97 | if (js_context->auto_gc_id > 0) | ||
606 | 98 | - g_source_remove(js_context->auto_gc_id); | ||
607 | 99 | + return; | ||
608 | 100 | |||
609 | 101 | - js_context->force_gc = force_gc; | ||
610 | 102 | + js_context->force_gc |= force_gc; | ||
611 | 103 | js_context->auto_gc_id = g_idle_add_full(G_PRIORITY_LOW, | ||
612 | 104 | trigger_gc_if_needed, | ||
613 | 105 | js_context, NULL); | ||
614 | 106 | } | ||
615 | 107 | |||
616 | 108 | void | ||
617 | 109 | -_gjs_context_schedule_gc (GjsContext *js_context) | ||
618 | 110 | +_gjs_context_schedule_gc(GjsContext *js_context) | ||
619 | 111 | { | ||
620 | 112 | _gjs_context_schedule_gc_internal(js_context, true); | ||
621 | 113 | } | ||
622 | 114 | |||
623 | 115 | void | ||
624 | 116 | -_gjs_context_schedule_gc_if_needed (GjsContext *js_context) | ||
625 | 117 | +_gjs_context_schedule_gc_if_needed(GjsContext *js_context) | ||
626 | 118 | { | ||
627 | 119 | _gjs_context_schedule_gc_internal(js_context, false); | ||
628 | 120 | } | ||
629 | 121 | -- | ||
630 | 122 | 2.17.0 | ||
631 | 123 | |||
632 | diff --git a/debian/patches/series b/debian/patches/series | |||
633 | 124 | deleted file mode 100644 | 0 | deleted file mode 100644 |
634 | index 1de36f6..0000000 | |||
635 | --- a/debian/patches/series | |||
636 | +++ /dev/null | |||
637 | @@ -1,6 +0,0 @@ | |||
638 | 1 | # Cherry picked from gjs master: | ||
639 | 2 | fix-crashes-lp1763878-revert-575f1e2e077.patch | ||
640 | 3 | |||
641 | 4 | # Critical leak fixes (not yet landed in gjs master): | ||
642 | 5 | fix-leaks-lp1672297-1-context-Add-API-to-force-GC-schedule.patch | ||
643 | 6 | fix-leaks-lp1672297-2-object-Queue-a-forced-GC-when-toggling-down.patch | ||
644 | diff --git a/gi/gtype.cpp b/gi/gtype.cpp | |||
645 | index 314f4b2..03920eb 100644 | |||
646 | --- a/gi/gtype.cpp | |||
647 | +++ b/gi/gtype.cpp | |||
648 | @@ -63,13 +63,18 @@ update_gtype_weak_pointers(JSContext *cx, | |||
649 | 63 | void *data) | 63 | void *data) |
650 | 64 | { | 64 | { |
651 | 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(); ) { |
653 | 66 | auto heap_wrapper = static_cast<JS::Heap<JSObject *> *>(g_type_get_qdata(*iter, gjs_get_gtype_wrapper_quark())); | 66 | GType gtype = *iter; |
654 | 67 | auto heap_wrapper = static_cast<JS::Heap<JSObject *> *>( | ||
655 | 68 | g_type_get_qdata(gtype, gjs_get_gtype_wrapper_quark())); | ||
656 | 67 | JS_UpdateWeakPointerAfterGC(heap_wrapper); | 69 | JS_UpdateWeakPointerAfterGC(heap_wrapper); |
657 | 68 | 70 | ||
658 | 69 | /* No read barriers are needed if the only thing we are doing with the | 71 | /* No read barriers are needed if the only thing we are doing with the |
659 | 70 | * pointer is comparing it to nullptr. */ | 72 | * pointer is comparing it to nullptr. */ |
661 | 71 | if (heap_wrapper->unbarrieredGet() == nullptr) | 73 | if (heap_wrapper->unbarrieredGet() == nullptr) { |
662 | 74 | g_type_set_qdata(gtype, gjs_get_gtype_wrapper_quark(), nullptr); | ||
663 | 72 | iter = weak_pointer_list.erase(iter); | 75 | iter = weak_pointer_list.erase(iter); |
664 | 76 | delete heap_wrapper; | ||
665 | 77 | } | ||
666 | 73 | else | 78 | else |
667 | 74 | iter++; | 79 | iter++; |
668 | 75 | } | 80 | } |
669 | @@ -95,8 +100,12 @@ gjs_gtype_finalize(JSFreeOp *fop, | |||
670 | 95 | if (G_UNLIKELY(gtype == 0)) | 100 | if (G_UNLIKELY(gtype == 0)) |
671 | 96 | return; | 101 | return; |
672 | 97 | 102 | ||
674 | 98 | weak_pointer_list.erase(gtype); | 103 | auto heap_wrapper = static_cast<JS::Heap<JSObject*>*>( |
675 | 104 | g_type_get_qdata(gtype, gjs_get_gtype_wrapper_quark())); | ||
676 | 105 | |||
677 | 99 | g_type_set_qdata(gtype, gjs_get_gtype_wrapper_quark(), NULL); | 106 | g_type_set_qdata(gtype, gjs_get_gtype_wrapper_quark(), NULL); |
678 | 107 | weak_pointer_list.erase(gtype); | ||
679 | 108 | delete heap_wrapper; | ||
680 | 100 | } | 109 | } |
681 | 101 | 110 | ||
682 | 102 | static bool | 111 | static bool |
683 | diff --git a/gi/object.cpp b/gi/object.cpp | |||
684 | index b20d8b9..fe381ec 100644 | |||
685 | --- a/gi/object.cpp | |||
686 | +++ b/gi/object.cpp | |||
687 | @@ -54,6 +54,65 @@ | |||
688 | 54 | #include <util/log.h> | 54 | #include <util/log.h> |
689 | 55 | #include <girepository.h> | 55 | #include <girepository.h> |
690 | 56 | 56 | ||
691 | 57 | typedef class GjsListLink GjsListLink; | ||
692 | 58 | typedef struct ObjectInstance ObjectInstance; | ||
693 | 59 | |||
694 | 60 | static GjsListLink* object_instance_get_link(ObjectInstance *priv); | ||
695 | 61 | |||
696 | 62 | class GjsListLink { | ||
697 | 63 | private: | ||
698 | 64 | ObjectInstance *m_prev; | ||
699 | 65 | ObjectInstance *m_next; | ||
700 | 66 | |||
701 | 67 | public: | ||
702 | 68 | ObjectInstance* prev() { | ||
703 | 69 | return m_prev; | ||
704 | 70 | } | ||
705 | 71 | |||
706 | 72 | ObjectInstance* next() { | ||
707 | 73 | return m_next; | ||
708 | 74 | } | ||
709 | 75 | |||
710 | 76 | void prepend(ObjectInstance *this_instance, | ||
711 | 77 | ObjectInstance *head) { | ||
712 | 78 | GjsListLink *elem = object_instance_get_link(head); | ||
713 | 79 | |||
714 | 80 | g_assert(object_instance_get_link(this_instance) == this); | ||
715 | 81 | |||
716 | 82 | if (elem->m_prev) { | ||
717 | 83 | GjsListLink *prev = object_instance_get_link(elem->m_prev); | ||
718 | 84 | prev->m_next = this_instance; | ||
719 | 85 | this->m_prev = elem->m_prev; | ||
720 | 86 | } | ||
721 | 87 | |||
722 | 88 | elem->m_prev = this_instance; | ||
723 | 89 | this->m_next = head; | ||
724 | 90 | } | ||
725 | 91 | |||
726 | 92 | void unlink() { | ||
727 | 93 | if (m_prev) | ||
728 | 94 | object_instance_get_link(m_prev)->m_next = m_next; | ||
729 | 95 | if (m_next) | ||
730 | 96 | object_instance_get_link(m_next)->m_prev = m_prev; | ||
731 | 97 | |||
732 | 98 | m_prev = m_next = NULL; | ||
733 | 99 | } | ||
734 | 100 | |||
735 | 101 | int size() { | ||
736 | 102 | GjsListLink *elem = this; | ||
737 | 103 | int count = 0; | ||
738 | 104 | |||
739 | 105 | do { | ||
740 | 106 | count++; | ||
741 | 107 | if (!elem->m_next) | ||
742 | 108 | break; | ||
743 | 109 | elem = object_instance_get_link(elem->m_next); | ||
744 | 110 | } while (elem); | ||
745 | 111 | |||
746 | 112 | return count; | ||
747 | 113 | } | ||
748 | 114 | }; | ||
749 | 115 | |||
750 | 57 | struct ObjectInstance { | 116 | struct ObjectInstance { |
751 | 58 | GIObjectInfo *info; | 117 | GIObjectInfo *info; |
752 | 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 */ |
753 | @@ -68,8 +127,15 @@ struct ObjectInstance { | |||
754 | 68 | prototypes) */ | 127 | prototypes) */ |
755 | 69 | GTypeClass *klass; | 128 | GTypeClass *klass; |
756 | 70 | 129 | ||
757 | 130 | GjsListLink instance_link; | ||
758 | 131 | |||
759 | 71 | unsigned js_object_finalized : 1; | 132 | unsigned js_object_finalized : 1; |
760 | 72 | unsigned g_object_finalized : 1; | 133 | unsigned g_object_finalized : 1; |
761 | 134 | |||
762 | 135 | /* True if this object has visible JS state, and thus its lifecycle is | ||
763 | 136 | * managed using toggle references. False if this object just keeps a | ||
764 | 137 | * hard ref on the underlying GObject, and may be finalized at will. */ | ||
765 | 138 | bool uses_toggle_ref : 1; | ||
766 | 73 | }; | 139 | }; |
767 | 74 | 140 | ||
768 | 75 | static std::stack<JS::PersistentRootedObject> object_init_list; | 141 | static std::stack<JS::PersistentRootedObject> object_init_list; |
769 | @@ -78,13 +144,15 @@ using ParamRef = std::unique_ptr<GParamSpec, decltype(&g_param_spec_unref)>; | |||
770 | 78 | using ParamRefArray = std::vector<ParamRef>; | 144 | using ParamRefArray = std::vector<ParamRef>; |
771 | 79 | static std::unordered_map<GType, ParamRefArray> class_init_properties; | 145 | static std::unordered_map<GType, ParamRefArray> class_init_properties; |
772 | 80 | 146 | ||
773 | 147 | static bool context_weak_pointer_callback = false; | ||
774 | 81 | static bool weak_pointer_callback = false; | 148 | static bool weak_pointer_callback = false; |
776 | 82 | static std::set<ObjectInstance *> wrapped_gobject_list; | 149 | ObjectInstance *wrapped_gobject_list; |
777 | 83 | 150 | ||
778 | 84 | extern struct JSClass gjs_object_instance_class; | 151 | extern struct JSClass gjs_object_instance_class; |
779 | 85 | GJS_DEFINE_PRIV_FROM_JS(ObjectInstance, gjs_object_instance_class) | 152 | GJS_DEFINE_PRIV_FROM_JS(ObjectInstance, gjs_object_instance_class) |
780 | 86 | 153 | ||
781 | 87 | static void disassociate_js_gobject (GObject *gobj); | 154 | static void disassociate_js_gobject (GObject *gobj); |
782 | 155 | static void ensure_uses_toggle_ref(JSContext *cx, ObjectInstance *priv); | ||
783 | 88 | 156 | ||
784 | 89 | typedef enum { | 157 | typedef enum { |
785 | 90 | SOME_ERROR_OCCURRED = false, | 158 | SOME_ERROR_OCCURRED = false, |
786 | @@ -152,7 +220,7 @@ get_object_qdata(GObject *gobj) | |||
787 | 152 | auto priv = static_cast<ObjectInstance *>(g_object_get_qdata(gobj, | 220 | auto priv = static_cast<ObjectInstance *>(g_object_get_qdata(gobj, |
788 | 153 | gjs_object_priv_quark())); | 221 | gjs_object_priv_quark())); |
789 | 154 | 222 | ||
791 | 155 | if (priv && G_UNLIKELY(priv->js_object_finalized)) { | 223 | if (priv && priv->uses_toggle_ref && G_UNLIKELY(priv->js_object_finalized)) { |
792 | 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. " |
793 | 157 | "This is some library doing dubious memory management inside dispose()", | 225 | "This is some library doing dubious memory management inside dispose()", |
794 | 158 | gobj, g_type_name(G_TYPE_FROM_INSTANCE(gobj))); | 226 | gobj, g_type_name(G_TYPE_FROM_INSTANCE(gobj))); |
795 | @@ -430,6 +498,9 @@ set_g_param_from_prop(JSContext *context, | |||
796 | 430 | case SOME_ERROR_OCCURRED: | 498 | case SOME_ERROR_OCCURRED: |
797 | 431 | return false; | 499 | return false; |
798 | 432 | case NO_SUCH_G_PROPERTY: | 500 | case NO_SUCH_G_PROPERTY: |
799 | 501 | /* We need to keep the wrapper alive in order not to lose custom | ||
800 | 502 | * "expando" properties */ | ||
801 | 503 | ensure_uses_toggle_ref(context, priv); | ||
802 | 433 | return result.succeed(); | 504 | return result.succeed(); |
803 | 434 | case VALUE_WAS_SET: | 505 | case VALUE_WAS_SET: |
804 | 435 | default: | 506 | default: |
805 | @@ -496,14 +567,7 @@ object_instance_set_prop(JSContext *context, | |||
806 | 496 | bool ret = true; | 567 | bool ret = true; |
807 | 497 | bool g_param_was_set = false; | 568 | bool g_param_was_set = false; |
808 | 498 | 569 | ||
809 | 499 | if (!gjs_get_string_id(context, id, &name)) | ||
810 | 500 | return result.succeed(); /* not resolved, but no error */ | ||
811 | 501 | |||
812 | 502 | priv = priv_from_js(context, obj); | 570 | priv = priv_from_js(context, obj); |
813 | 503 | gjs_debug_jsprop(GJS_DEBUG_GOBJECT, | ||
814 | 504 | "Set prop '%s' hook obj %p priv %p", | ||
815 | 505 | name.get(), obj.get(), priv); | ||
816 | 506 | |||
817 | 507 | if (priv == nullptr) | 571 | if (priv == nullptr) |
818 | 508 | /* see the comment in object_instance_get_prop() on this */ | 572 | /* see the comment in object_instance_get_prop() on this */ |
819 | 509 | return result.succeed(); | 573 | return result.succeed(); |
820 | @@ -521,6 +585,18 @@ object_instance_set_prop(JSContext *context, | |||
821 | 521 | return result.succeed(); | 585 | return result.succeed(); |
822 | 522 | } | 586 | } |
823 | 523 | 587 | ||
824 | 588 | if (!gjs_get_string_id(context, id, &name)) { | ||
825 | 589 | /* We need to keep the wrapper alive in order not to lose custom | ||
826 | 590 | * "expando" properties. In this case if gjs_get_string_id() is false | ||
827 | 591 | * then a number or symbol property was probably set. */ | ||
828 | 592 | ensure_uses_toggle_ref(context, priv); | ||
829 | 593 | return result.succeed(); /* not resolved, but no error */ | ||
830 | 594 | } | ||
831 | 595 | |||
832 | 596 | gjs_debug_jsprop(GJS_DEBUG_GOBJECT, | ||
833 | 597 | "Set prop '%s' hook obj %p priv %p", | ||
834 | 598 | name.get(), obj.get(), priv); | ||
835 | 599 | |||
836 | 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); |
837 | 525 | if (g_param_was_set || !ret) | 601 | if (g_param_was_set || !ret) |
838 | 526 | return ret; | 602 | return ret; |
839 | @@ -755,18 +831,6 @@ object_instance_resolve(JSContext *context, | |||
840 | 755 | return true; | 831 | return true; |
841 | 756 | } | 832 | } |
842 | 757 | 833 | ||
843 | 758 | if (priv->g_object_finalized) { | ||
844 | 759 | g_critical("Object %s.%s (%p), has been already finalized. " | ||
845 | 760 | "Impossible to resolve it.", | ||
846 | 761 | priv->info ? g_base_info_get_namespace( (GIBaseInfo*) priv->info) : "", | ||
847 | 762 | priv->info ? g_base_info_get_name( (GIBaseInfo*) priv->info) : g_type_name(priv->gtype), | ||
848 | 763 | priv->gobj); | ||
849 | 764 | gjs_dumpstack(); | ||
850 | 765 | |||
851 | 766 | *resolved = false; | ||
852 | 767 | return true; | ||
853 | 768 | } | ||
854 | 769 | |||
855 | 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), |
856 | 771 | * we need to look at exposing interfaces. Look up our interfaces through | 835 | * we need to look at exposing interfaces. Look up our interfaces through |
857 | 772 | * GType data, and then hope that *those* are introspectable. */ | 836 | * GType data, and then hope that *those* are introspectable. */ |
858 | @@ -945,6 +1009,28 @@ object_instance_props_to_g_parameters(JSContext *context, | |||
859 | 945 | return true; | 1009 | return true; |
860 | 946 | } | 1010 | } |
861 | 947 | 1011 | ||
862 | 1012 | static GjsListLink * | ||
863 | 1013 | object_instance_get_link(ObjectInstance *priv) | ||
864 | 1014 | { | ||
865 | 1015 | return &priv->instance_link; | ||
866 | 1016 | } | ||
867 | 1017 | |||
868 | 1018 | static void | ||
869 | 1019 | object_instance_unlink(ObjectInstance *priv) | ||
870 | 1020 | { | ||
871 | 1021 | if (wrapped_gobject_list == priv) | ||
872 | 1022 | wrapped_gobject_list = priv->instance_link.next(); | ||
873 | 1023 | priv->instance_link.unlink(); | ||
874 | 1024 | } | ||
875 | 1025 | |||
876 | 1026 | static void | ||
877 | 1027 | object_instance_link(ObjectInstance *priv) | ||
878 | 1028 | { | ||
879 | 1029 | if (wrapped_gobject_list) | ||
880 | 1030 | priv->instance_link.prepend(priv, wrapped_gobject_list); | ||
881 | 1031 | wrapped_gobject_list = priv; | ||
882 | 1032 | } | ||
883 | 1033 | |||
884 | 948 | static void | 1034 | static void |
885 | 949 | wrapped_gobj_dispose_notify(gpointer data, | 1035 | wrapped_gobj_dispose_notify(gpointer data, |
886 | 950 | GObject *where_the_object_was) | 1036 | GObject *where_the_object_was) |
887 | @@ -952,26 +1038,30 @@ wrapped_gobj_dispose_notify(gpointer data, | |||
888 | 952 | auto *priv = static_cast<ObjectInstance *>(data); | 1038 | auto *priv = static_cast<ObjectInstance *>(data); |
889 | 953 | 1039 | ||
890 | 954 | priv->g_object_finalized = true; | 1040 | priv->g_object_finalized = true; |
892 | 955 | wrapped_gobject_list.erase(priv); | 1041 | object_instance_unlink(priv); |
893 | 956 | gjs_debug_lifecycle(GJS_DEBUG_GOBJECT, "Wrapped GObject %p disposed", | 1042 | gjs_debug_lifecycle(GJS_DEBUG_GOBJECT, "Wrapped GObject %p disposed", |
894 | 957 | where_the_object_was); | 1043 | where_the_object_was); |
895 | 958 | } | 1044 | } |
896 | 959 | 1045 | ||
900 | 960 | static void | 1046 | void |
901 | 961 | gobj_no_longer_kept_alive_func(JS::HandleObject obj, | 1047 | gjs_object_context_dispose_notify(void *data, |
902 | 962 | void *data) | 1048 | GObject *where_the_object_was) |
903 | 963 | { | 1049 | { |
905 | 964 | ObjectInstance *priv; | 1050 | ObjectInstance *priv = wrapped_gobject_list; |
906 | 1051 | while (priv) { | ||
907 | 1052 | ObjectInstance *next = priv->instance_link.next(); | ||
908 | 965 | 1053 | ||
915 | 966 | priv = (ObjectInstance *) data; | 1054 | if (priv->keep_alive.rooted()) { |
916 | 967 | 1055 | gjs_debug_lifecycle(GJS_DEBUG_GOBJECT, "GObject wrapper %p for GObject " | |
917 | 968 | gjs_debug_lifecycle(GJS_DEBUG_GOBJECT, "GObject wrapper %p for GObject " | 1056 | "%p (%s) was rooted but is now unrooted due to " |
918 | 969 | "%p (%s) was rooted but is now unrooted due to " | 1057 | "GjsContext dispose", priv->keep_alive.get(), |
919 | 970 | "GjsContext dispose", obj.get(), priv->gobj, | 1058 | priv->gobj, G_OBJECT_TYPE_NAME(priv->gobj)); |
920 | 971 | G_OBJECT_TYPE_NAME(priv->gobj)); | 1059 | priv->keep_alive.reset(); |
921 | 1060 | object_instance_unlink(priv); | ||
922 | 1061 | } | ||
923 | 972 | 1062 | ||
926 | 973 | priv->keep_alive.reset(); | 1063 | priv = next; |
927 | 974 | wrapped_gobject_list.erase(priv); | 1064 | } |
928 | 975 | } | 1065 | } |
929 | 976 | 1066 | ||
930 | 977 | static void | 1067 | static void |
931 | @@ -987,8 +1077,30 @@ handle_toggle_down(GObject *gobj) | |||
932 | 987 | * collected by the GC | 1077 | * collected by the GC |
933 | 988 | */ | 1078 | */ |
934 | 989 | if (priv->keep_alive.rooted()) { | 1079 | if (priv->keep_alive.rooted()) { |
935 | 1080 | GjsContext *context; | ||
936 | 1081 | |||
937 | 990 | gjs_debug_lifecycle(GJS_DEBUG_GOBJECT, "Unrooting object"); | 1082 | gjs_debug_lifecycle(GJS_DEBUG_GOBJECT, "Unrooting object"); |
938 | 991 | priv->keep_alive.switch_to_unrooted(); | 1083 | priv->keep_alive.switch_to_unrooted(); |
939 | 1084 | |||
940 | 1085 | /* During a GC, the collector asks each object which other | ||
941 | 1086 | * objects that it wants to hold on to so if there's an entire | ||
942 | 1087 | * section of the heap graph that's not connected to anything | ||
943 | 1088 | * else, and not reachable from the root set, then it can be | ||
944 | 1089 | * trashed all at once. | ||
945 | 1090 | * | ||
946 | 1091 | * GObjects, however, don't work like that, there's only a | ||
947 | 1092 | * reference count but no notion of who owns the reference so, | ||
948 | 1093 | * a JS object that's proxying a GObject is unconditionally held | ||
949 | 1094 | * alive as long as the GObject has >1 references. | ||
950 | 1095 | * | ||
951 | 1096 | * Since we cannot know how many more wrapped GObjects are going | ||
952 | 1097 | * be marked for garbage collection after the owner is destroyed, | ||
953 | 1098 | * always queue a garbage collection when a toggle reference goes | ||
954 | 1099 | * down. | ||
955 | 1100 | */ | ||
956 | 1101 | context = gjs_context_get_current(); | ||
957 | 1102 | if (!_gjs_context_destroying(context)) | ||
958 | 1103 | _gjs_context_schedule_gc(context); | ||
959 | 992 | } | 1104 | } |
960 | 993 | } | 1105 | } |
961 | 994 | 1106 | ||
962 | @@ -1017,7 +1129,7 @@ handle_toggle_up(GObject *gobj) | |||
963 | 1017 | GjsContext *context = gjs_context_get_current(); | 1129 | GjsContext *context = gjs_context_get_current(); |
964 | 1018 | gjs_debug_lifecycle(GJS_DEBUG_GOBJECT, "Rooting object"); | 1130 | gjs_debug_lifecycle(GJS_DEBUG_GOBJECT, "Rooting object"); |
965 | 1019 | auto cx = static_cast<JSContext *>(gjs_context_get_native_context(context)); | 1131 | auto cx = static_cast<JSContext *>(gjs_context_get_native_context(context)); |
967 | 1020 | priv->keep_alive.switch_to_rooted(cx, gobj_no_longer_kept_alive_func, priv); | 1132 | priv->keep_alive.switch_to_rooted(cx); |
968 | 1021 | } | 1133 | } |
969 | 1022 | } | 1134 | } |
970 | 1023 | 1135 | ||
971 | @@ -1126,7 +1238,10 @@ static void | |||
972 | 1126 | release_native_object (ObjectInstance *priv) | 1238 | release_native_object (ObjectInstance *priv) |
973 | 1127 | { | 1239 | { |
974 | 1128 | priv->keep_alive.reset(); | 1240 | priv->keep_alive.reset(); |
976 | 1129 | g_object_remove_toggle_ref(priv->gobj, wrapped_gobj_toggle_notify, NULL); | 1241 | if (priv->uses_toggle_ref) |
977 | 1242 | g_object_remove_toggle_ref(priv->gobj, wrapped_gobj_toggle_notify, nullptr); | ||
978 | 1243 | else | ||
979 | 1244 | g_object_unref(priv->gobj); | ||
980 | 1130 | priv->gobj = NULL; | 1245 | priv->gobj = NULL; |
981 | 1131 | } | 1246 | } |
982 | 1132 | 1247 | ||
983 | @@ -1156,14 +1271,15 @@ gjs_object_prepare_shutdown(void) | |||
984 | 1156 | * toggle ref removal -> gobj dispose -> toggle ref notify | 1271 | * toggle ref removal -> gobj dispose -> toggle ref notify |
985 | 1157 | * by emptying the toggle queue earlier in the shutdown sequence. */ | 1272 | * by emptying the toggle queue earlier in the shutdown sequence. */ |
986 | 1158 | std::vector<ObjectInstance *> to_be_released; | 1273 | std::vector<ObjectInstance *> to_be_released; |
994 | 1159 | for (auto iter = wrapped_gobject_list.begin(); iter != wrapped_gobject_list.end(); ) { | 1274 | ObjectInstance *link = wrapped_gobject_list; |
995 | 1160 | ObjectInstance *priv = *iter; | 1275 | while (link) { |
996 | 1161 | if (priv->keep_alive.rooted()) { | 1276 | ObjectInstance *next = link->instance_link.next(); |
997 | 1162 | to_be_released.push_back(priv); | 1277 | if (link->keep_alive.rooted()) { |
998 | 1163 | iter = wrapped_gobject_list.erase(iter); | 1278 | to_be_released.push_back(link); |
999 | 1164 | } else { | 1279 | object_instance_unlink(link); |
993 | 1165 | iter++; | ||
1000 | 1166 | } | 1280 | } |
1001 | 1281 | |||
1002 | 1282 | link = next; | ||
1003 | 1167 | } | 1283 | } |
1004 | 1168 | for (ObjectInstance *priv : to_be_released) | 1284 | for (ObjectInstance *priv : to_be_released) |
1005 | 1169 | release_native_object(priv); | 1285 | release_native_object(priv); |
1006 | @@ -1209,16 +1325,18 @@ update_heap_wrapper_weak_pointers(JSContext *cx, | |||
1007 | 1209 | { | 1325 | { |
1008 | 1210 | gjs_debug_lifecycle(GJS_DEBUG_GOBJECT, "Weak pointer update callback, " | 1326 | gjs_debug_lifecycle(GJS_DEBUG_GOBJECT, "Weak pointer update callback, " |
1009 | 1211 | "%zu wrapped GObject(s) to examine", | 1327 | "%zu wrapped GObject(s) to examine", |
1011 | 1212 | wrapped_gobject_list.size()); | 1328 | wrapped_gobject_list ? |
1012 | 1329 | wrapped_gobject_list->instance_link.size() : 0); | ||
1013 | 1213 | 1330 | ||
1014 | 1214 | std::vector<GObject *> to_be_disassociated; | 1331 | std::vector<GObject *> to_be_disassociated; |
1015 | 1332 | ObjectInstance *priv = wrapped_gobject_list; | ||
1016 | 1215 | 1333 | ||
1023 | 1216 | for (auto iter = wrapped_gobject_list.begin(); iter != wrapped_gobject_list.end(); ) { | 1334 | while (priv) { |
1024 | 1217 | ObjectInstance *priv = *iter; | 1335 | ObjectInstance *next = priv->instance_link.next(); |
1025 | 1218 | if (priv->keep_alive.rooted() || priv->keep_alive == nullptr || | 1336 | |
1026 | 1219 | !priv->keep_alive.update_after_gc()) { | 1337 | if (!priv->keep_alive.rooted() && |
1027 | 1220 | iter++; | 1338 | priv->keep_alive != nullptr && |
1028 | 1221 | } else { | 1339 | priv->keep_alive.update_after_gc()) { |
1029 | 1222 | /* Ouch, the JS object is dead already. Disassociate the | 1340 | /* Ouch, the JS object is dead already. Disassociate the |
1030 | 1223 | * GObject and hope the GObject dies too. (Remove it from | 1341 | * GObject and hope the GObject dies too. (Remove it from |
1031 | 1224 | * the weak pointer list first, since the disassociation | 1342 | * the weak pointer list first, since the disassociation |
1032 | @@ -1229,8 +1347,10 @@ update_heap_wrapper_weak_pointers(JSContext *cx, | |||
1033 | 1229 | "%p (%s)", priv->keep_alive.get(), priv->gobj, | 1347 | "%p (%s)", priv->keep_alive.get(), priv->gobj, |
1034 | 1230 | G_OBJECT_TYPE_NAME(priv->gobj)); | 1348 | G_OBJECT_TYPE_NAME(priv->gobj)); |
1035 | 1231 | to_be_disassociated.push_back(priv->gobj); | 1349 | to_be_disassociated.push_back(priv->gobj); |
1037 | 1232 | iter = wrapped_gobject_list.erase(iter); | 1350 | object_instance_unlink(priv); |
1038 | 1233 | } | 1351 | } |
1039 | 1352 | |||
1040 | 1353 | priv = next; | ||
1041 | 1234 | } | 1354 | } |
1042 | 1235 | 1355 | ||
1043 | 1236 | for (GObject *gobj : to_be_disassociated) | 1356 | for (GObject *gobj : to_be_disassociated) |
1044 | @@ -1256,16 +1376,28 @@ associate_js_gobject (JSContext *context, | |||
1045 | 1256 | ObjectInstance *priv; | 1376 | ObjectInstance *priv; |
1046 | 1257 | 1377 | ||
1047 | 1258 | priv = priv_from_js(context, object); | 1378 | priv = priv_from_js(context, object); |
1048 | 1379 | priv->uses_toggle_ref = false; | ||
1049 | 1259 | priv->gobj = gobj; | 1380 | priv->gobj = gobj; |
1050 | 1260 | 1381 | ||
1051 | 1261 | g_assert(!priv->keep_alive.rooted()); | 1382 | g_assert(!priv->keep_alive.rooted()); |
1052 | 1262 | 1383 | ||
1053 | 1263 | set_object_qdata(gobj, priv); | 1384 | set_object_qdata(gobj, priv); |
1054 | 1264 | 1385 | ||
1055 | 1386 | priv->keep_alive = object; | ||
1056 | 1265 | ensure_weak_pointer_callback(context); | 1387 | ensure_weak_pointer_callback(context); |
1058 | 1266 | wrapped_gobject_list.insert(priv); | 1388 | object_instance_link(priv); |
1059 | 1267 | 1389 | ||
1060 | 1268 | g_object_weak_ref(gobj, wrapped_gobj_dispose_notify, priv); | 1390 | g_object_weak_ref(gobj, wrapped_gobj_dispose_notify, priv); |
1061 | 1391 | } | ||
1062 | 1392 | |||
1063 | 1393 | static void | ||
1064 | 1394 | ensure_uses_toggle_ref(JSContext *cx, | ||
1065 | 1395 | ObjectInstance *priv) | ||
1066 | 1396 | { | ||
1067 | 1397 | if (priv->uses_toggle_ref) | ||
1068 | 1398 | return; | ||
1069 | 1399 | |||
1070 | 1400 | g_assert(!priv->keep_alive.rooted()); | ||
1071 | 1269 | 1401 | ||
1072 | 1270 | /* OK, here is where things get complicated. We want the | 1402 | /* OK, here is where things get complicated. We want the |
1073 | 1271 | * wrapped gobj to keep the JSObject* wrapper alive, because | 1403 | * wrapped gobj to keep the JSObject* wrapper alive, because |
1074 | @@ -1278,8 +1410,14 @@ associate_js_gobject (JSContext *context, | |||
1075 | 1278 | * the wrapper to be garbage collected (and thus unref the | 1410 | * the wrapper to be garbage collected (and thus unref the |
1076 | 1279 | * wrappee). | 1411 | * wrappee). |
1077 | 1280 | */ | 1412 | */ |
1080 | 1281 | priv->keep_alive.root(context, object, gobj_no_longer_kept_alive_func, priv); | 1413 | priv->uses_toggle_ref = true; |
1081 | 1282 | g_object_add_toggle_ref(gobj, wrapped_gobj_toggle_notify, NULL); | 1414 | priv->keep_alive.switch_to_rooted(cx); |
1082 | 1415 | g_object_add_toggle_ref(priv->gobj, wrapped_gobj_toggle_notify, nullptr); | ||
1083 | 1416 | |||
1084 | 1417 | /* We now have both a ref and a toggle ref, we only want the toggle ref. | ||
1085 | 1418 | * This may immediately remove the GC root we just added, since refcount | ||
1086 | 1419 | * may drop to 1. */ | ||
1087 | 1420 | g_object_unref(priv->gobj); | ||
1088 | 1283 | } | 1421 | } |
1089 | 1284 | 1422 | ||
1090 | 1285 | static void | 1423 | static void |
1091 | @@ -1303,7 +1441,8 @@ disassociate_js_gobject(GObject *gobj) | |||
1092 | 1303 | ObjectInstance *priv = get_object_qdata(gobj); | 1441 | ObjectInstance *priv = get_object_qdata(gobj); |
1093 | 1304 | bool had_toggle_down, had_toggle_up; | 1442 | bool had_toggle_down, had_toggle_up; |
1094 | 1305 | 1443 | ||
1096 | 1306 | g_object_weak_unref(priv->gobj, wrapped_gobj_dispose_notify, priv); | 1444 | if (!priv->g_object_finalized) |
1097 | 1445 | g_object_weak_unref(gobj, wrapped_gobj_dispose_notify, priv); | ||
1098 | 1307 | 1446 | ||
1099 | 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, |
1100 | 1309 | * because the idle functions are not dispatched without a main loop. | 1448 | * because the idle functions are not dispatched without a main loop. |
1101 | @@ -1322,11 +1461,16 @@ disassociate_js_gobject(GObject *gobj) | |||
1102 | 1322 | gobj, G_OBJECT_TYPE_NAME(gobj)); | 1461 | gobj, G_OBJECT_TYPE_NAME(gobj)); |
1103 | 1323 | } | 1462 | } |
1104 | 1324 | 1463 | ||
1105 | 1464 | /* Fist, remove the wrapper pointer from the wrapped GObject */ | ||
1106 | 1465 | set_object_qdata(gobj, nullptr); | ||
1107 | 1466 | |||
1108 | 1467 | /* Now release all the resources the current wrapper has */ | ||
1109 | 1325 | invalidate_all_closures(priv); | 1468 | invalidate_all_closures(priv); |
1110 | 1326 | release_native_object(priv); | 1469 | release_native_object(priv); |
1111 | 1327 | 1470 | ||
1112 | 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 */ |
1113 | 1329 | priv->js_object_finalized = true; | 1472 | priv->js_object_finalized = true; |
1114 | 1473 | priv->keep_alive = nullptr; | ||
1115 | 1330 | } | 1474 | } |
1116 | 1331 | 1475 | ||
1117 | 1332 | static void | 1476 | static void |
1118 | @@ -1383,6 +1527,7 @@ G_GNUC_END_IGNORE_DEPRECATIONS | |||
1119 | 1383 | * we're not actually using it, so just let it get collected. Avoiding | 1527 | * we're not actually using it, so just let it get collected. Avoiding |
1120 | 1384 | * this would require a non-trivial amount of work. | 1528 | * this would require a non-trivial amount of work. |
1121 | 1385 | * */ | 1529 | * */ |
1122 | 1530 | ensure_uses_toggle_ref(context, other_priv); | ||
1123 | 1386 | object.set(other_priv->keep_alive); | 1531 | object.set(other_priv->keep_alive); |
1124 | 1387 | g_object_unref(gobj); /* We already own a reference */ | 1532 | g_object_unref(gobj); /* We already own a reference */ |
1125 | 1388 | gobj = NULL; | 1533 | gobj = NULL; |
1126 | @@ -1410,11 +1555,6 @@ G_GNUC_END_IGNORE_DEPRECATIONS | |||
1127 | 1410 | 1555 | ||
1128 | 1411 | if (priv->gobj == NULL) | 1556 | if (priv->gobj == NULL) |
1129 | 1412 | associate_js_gobject(context, object, gobj); | 1557 | associate_js_gobject(context, object, gobj); |
1130 | 1413 | /* We now have both a ref and a toggle ref, we only want the | ||
1131 | 1414 | * toggle ref. This may immediately remove the GC root | ||
1132 | 1415 | * we just added, since refcount may drop to 1. | ||
1133 | 1416 | */ | ||
1134 | 1417 | g_object_unref(gobj); | ||
1135 | 1418 | 1558 | ||
1136 | 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)", |
1137 | 1420 | priv->gobj, G_OBJECT_TYPE_NAME(priv->gobj)); | 1560 | priv->gobj, G_OBJECT_TYPE_NAME(priv->gobj)); |
1138 | @@ -1463,15 +1603,6 @@ object_instance_trace(JSTracer *tracer, | |||
1139 | 1463 | if (priv == NULL) | 1603 | if (priv == NULL) |
1140 | 1464 | return; | 1604 | return; |
1141 | 1465 | 1605 | ||
1142 | 1466 | if (priv->g_object_finalized) { | ||
1143 | 1467 | g_debug("Object %s.%s (%p), has been already finalized. " | ||
1144 | 1468 | "Impossible to trace it.", | ||
1145 | 1469 | priv->info ? g_base_info_get_namespace( (GIBaseInfo*) priv->info) : "", | ||
1146 | 1470 | priv->info ? g_base_info_get_name( (GIBaseInfo*) priv->info) : g_type_name(priv->gtype), | ||
1147 | 1471 | priv->gobj); | ||
1148 | 1472 | return; | ||
1149 | 1473 | } | ||
1150 | 1474 | |||
1151 | 1475 | for (GClosure *closure : priv->closures) | 1606 | for (GClosure *closure : priv->closures) |
1152 | 1476 | gjs_closure_trace(closure, tracer); | 1607 | gjs_closure_trace(closure, tracer); |
1153 | 1477 | } | 1608 | } |
1154 | @@ -1541,7 +1672,7 @@ object_instance_finalize(JSFreeOp *fop, | |||
1155 | 1541 | 1672 | ||
1156 | 1542 | priv->keep_alive.reset(); | 1673 | priv->keep_alive.reset(); |
1157 | 1543 | } | 1674 | } |
1159 | 1544 | wrapped_gobject_list.erase(priv); | 1675 | object_instance_unlink(priv); |
1160 | 1545 | 1676 | ||
1161 | 1546 | if (priv->info) { | 1677 | if (priv->info) { |
1162 | 1547 | g_base_info_unref( (GIBaseInfo*) priv->info); | 1678 | g_base_info_unref( (GIBaseInfo*) priv->info); |
1163 | @@ -1556,6 +1687,9 @@ object_instance_finalize(JSFreeOp *fop, | |||
1164 | 1556 | GJS_DEC_COUNTER(object); | 1687 | GJS_DEC_COUNTER(object); |
1165 | 1557 | priv->~ObjectInstance(); | 1688 | priv->~ObjectInstance(); |
1166 | 1558 | g_slice_free(ObjectInstance, priv); | 1689 | g_slice_free(ObjectInstance, priv); |
1167 | 1690 | |||
1168 | 1691 | /* Remove the ObjectInstance pointer from the JSObject */ | ||
1169 | 1692 | JS_SetPrivate(obj, nullptr); | ||
1170 | 1559 | } | 1693 | } |
1171 | 1560 | 1694 | ||
1172 | 1561 | static JSObject * | 1695 | static JSObject * |
1173 | @@ -1683,6 +1817,8 @@ real_connect_func(JSContext *context, | |||
1174 | 1683 | return true; | 1817 | return true; |
1175 | 1684 | } | 1818 | } |
1176 | 1685 | 1819 | ||
1177 | 1820 | ensure_uses_toggle_ref(context, priv); | ||
1178 | 1821 | |||
1179 | 1686 | if (argc != 2 || !argv[0].isString() || !JS::IsCallable(&argv[1].toObject())) { | 1822 | if (argc != 2 || !argv[0].isString() || !JS::IsCallable(&argv[1].toObject())) { |
1180 | 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"); |
1181 | 1688 | return false; | 1824 | return false; |
1182 | @@ -2123,9 +2259,6 @@ gjs_object_from_g_object(JSContext *context, | |||
1183 | 2123 | g_object_ref_sink(gobj); | 2259 | g_object_ref_sink(gobj); |
1184 | 2124 | associate_js_gobject(context, obj, gobj); | 2260 | associate_js_gobject(context, obj, gobj); |
1185 | 2125 | 2261 | ||
1186 | 2126 | /* see the comment in init_object_instance() for this */ | ||
1187 | 2127 | g_object_unref(gobj); | ||
1188 | 2128 | |||
1189 | 2129 | g_assert(priv->keep_alive == obj.get()); | 2262 | g_assert(priv->keep_alive == obj.get()); |
1190 | 2130 | } | 2263 | } |
1191 | 2131 | 2264 | ||
1192 | @@ -2142,6 +2275,19 @@ gjs_g_object_from_object(JSContext *context, | |||
1193 | 2142 | return NULL; | 2275 | return NULL; |
1194 | 2143 | 2276 | ||
1195 | 2144 | priv = priv_from_js(context, obj); | 2277 | priv = priv_from_js(context, obj); |
1196 | 2278 | |||
1197 | 2279 | if (priv->g_object_finalized) { | ||
1198 | 2280 | g_critical("Object %s.%s (%p), has been already deallocated - " | ||
1199 | 2281 | "impossible to access it. This might be caused by the " | ||
1200 | 2282 | "object having been destroyed from C code using something " | ||
1201 | 2283 | "such as destroy(), dispose(), or remove() vfuncs", | ||
1202 | 2284 | priv->info ? g_base_info_get_namespace(priv->info) : "", | ||
1203 | 2285 | priv->info ? g_base_info_get_name(priv->info) : g_type_name(priv->gtype), | ||
1204 | 2286 | priv->gobj); | ||
1205 | 2287 | gjs_dumpstack(); | ||
1206 | 2288 | return nullptr; | ||
1207 | 2289 | } | ||
1208 | 2290 | |||
1209 | 2145 | return priv->gobj; | 2291 | return priv->gobj; |
1210 | 2146 | } | 2292 | } |
1211 | 2147 | 2293 | ||
1212 | @@ -2188,19 +2334,7 @@ gjs_typecheck_object(JSContext *context, | |||
1213 | 2188 | return false; | 2334 | return false; |
1214 | 2189 | } | 2335 | } |
1215 | 2190 | 2336 | ||
1229 | 2191 | if (priv->g_object_finalized) { | 2337 | g_assert(priv->g_object_finalized || priv->gtype == G_OBJECT_TYPE(priv->gobj)); |
1217 | 2192 | g_critical("Object %s.%s (%p), has been already deallocated - impossible to access to it. " | ||
1218 | 2193 | "This might be caused by the fact that the object has been destroyed from C " | ||
1219 | 2194 | "code using something such as destroy(), dispose(), or remove() vfuncs", | ||
1220 | 2195 | priv->info ? g_base_info_get_namespace( (GIBaseInfo*) priv->info) : "", | ||
1221 | 2196 | priv->info ? g_base_info_get_name( (GIBaseInfo*) priv->info) : g_type_name(priv->gtype), | ||
1222 | 2197 | priv->gobj); | ||
1223 | 2198 | gjs_dumpstack(); | ||
1224 | 2199 | |||
1225 | 2200 | return true; | ||
1226 | 2201 | } | ||
1227 | 2202 | |||
1228 | 2203 | g_assert(priv->gtype == G_OBJECT_TYPE(priv->gobj)); | ||
1230 | 2204 | 2338 | ||
1231 | 2205 | if (expected_type != G_TYPE_NONE) | 2339 | if (expected_type != G_TYPE_NONE) |
1232 | 2206 | result = g_type_is_a (priv->gtype, expected_type); | 2340 | result = g_type_is_a (priv->gtype, expected_type); |
1233 | @@ -2657,6 +2791,10 @@ gjs_object_custom_init(GTypeInstance *instance, | |||
1234 | 2657 | 2791 | ||
1235 | 2658 | associate_js_gobject(context, object, G_OBJECT (instance)); | 2792 | associate_js_gobject(context, object, G_OBJECT (instance)); |
1236 | 2659 | 2793 | ||
1237 | 2794 | /* Custom JS objects will most likely have visible state, so | ||
1238 | 2795 | * just do this from the start */ | ||
1239 | 2796 | ensure_uses_toggle_ref(context, priv); | ||
1240 | 2797 | |||
1241 | 2660 | JS::RootedValue v(context); | 2798 | JS::RootedValue v(context); |
1242 | 2661 | if (!gjs_object_get_property(context, object, | 2799 | if (!gjs_object_get_property(context, object, |
1243 | 2662 | GJS_STRING_INSTANCE_INIT, &v)) { | 2800 | GJS_STRING_INSTANCE_INIT, &v)) { |
1244 | @@ -3109,6 +3247,9 @@ gjs_object_associate_closure(JSContext *cx, | |||
1245 | 3109 | if (!priv) | 3247 | if (!priv) |
1246 | 3110 | return false; | 3248 | return false; |
1247 | 3111 | 3249 | ||
1248 | 3250 | if (priv->gobj) | ||
1249 | 3251 | ensure_uses_toggle_ref(cx, priv); | ||
1250 | 3252 | |||
1251 | 3112 | do_associate_closure(priv, closure); | 3253 | do_associate_closure(priv, closure); |
1252 | 3113 | return true; | 3254 | return true; |
1253 | 3114 | } | 3255 | } |
1254 | diff --git a/gi/object.h b/gi/object.h | |||
1255 | index 63aeb37..1f1dce8 100644 | |||
1256 | --- a/gi/object.h | |||
1257 | +++ b/gi/object.h | |||
1258 | @@ -61,6 +61,8 @@ bool gjs_typecheck_is_object(JSContext *context, | |||
1259 | 61 | void gjs_object_prepare_shutdown(void); | 61 | void gjs_object_prepare_shutdown(void); |
1260 | 62 | void gjs_object_clear_toggles(void); | 62 | void gjs_object_clear_toggles(void); |
1261 | 63 | void gjs_object_shutdown_toggle_queue(void); | 63 | void gjs_object_shutdown_toggle_queue(void); |
1262 | 64 | void gjs_object_context_dispose_notify(void *data, | ||
1263 | 65 | GObject *where_the_object_was); | ||
1264 | 64 | 66 | ||
1265 | 65 | void gjs_object_define_static_methods(JSContext *context, | 67 | void gjs_object_define_static_methods(JSContext *context, |
1266 | 66 | JS::HandleObject constructor, | 68 | JS::HandleObject constructor, |
1267 | diff --git a/gjs/context-private.h b/gjs/context-private.h | |||
1268 | index 6dbe669..49c0cf9 100644 | |||
1269 | --- a/gjs/context-private.h | |||
1270 | +++ b/gjs/context-private.h | |||
1271 | @@ -36,6 +36,8 @@ bool _gjs_context_destroying (GjsContext *js_context); | |||
1272 | 36 | 36 | ||
1273 | 37 | void _gjs_context_schedule_gc_if_needed (GjsContext *js_context); | 37 | void _gjs_context_schedule_gc_if_needed (GjsContext *js_context); |
1274 | 38 | 38 | ||
1275 | 39 | void _gjs_context_schedule_gc(GjsContext *js_context); | ||
1276 | 40 | |||
1277 | 39 | void _gjs_context_exit(GjsContext *js_context, | 41 | void _gjs_context_exit(GjsContext *js_context, |
1278 | 40 | uint8_t exit_code); | 42 | uint8_t exit_code); |
1279 | 41 | 43 | ||
1280 | diff --git a/gjs/context.cpp b/gjs/context.cpp | |||
1281 | index c509943..fc88741 100644 | |||
1282 | --- a/gjs/context.cpp | |||
1283 | +++ b/gjs/context.cpp | |||
1284 | @@ -90,6 +90,7 @@ struct _GjsContext { | |||
1285 | 90 | uint8_t exit_code; | 90 | uint8_t exit_code; |
1286 | 91 | 91 | ||
1287 | 92 | guint auto_gc_id; | 92 | guint auto_gc_id; |
1288 | 93 | bool force_gc; | ||
1289 | 93 | 94 | ||
1290 | 94 | std::array<JS::PersistentRootedId*, GJS_STRING_LAST> const_strings; | 95 | std::array<JS::PersistentRootedId*, GJS_STRING_LAST> const_strings; |
1291 | 95 | 96 | ||
1292 | @@ -515,6 +516,8 @@ gjs_context_constructed(GObject *object) | |||
1293 | 515 | g_mutex_unlock (&contexts_lock); | 516 | g_mutex_unlock (&contexts_lock); |
1294 | 516 | 517 | ||
1295 | 517 | setup_dump_heap(); | 518 | setup_dump_heap(); |
1296 | 519 | |||
1297 | 520 | g_object_weak_ref(object, gjs_object_context_dispose_notify, nullptr); | ||
1298 | 518 | } | 521 | } |
1299 | 519 | 522 | ||
1300 | 520 | static void | 523 | static void |
1301 | @@ -592,19 +595,43 @@ trigger_gc_if_needed (gpointer user_data) | |||
1302 | 592 | { | 595 | { |
1303 | 593 | GjsContext *js_context = GJS_CONTEXT(user_data); | 596 | GjsContext *js_context = GJS_CONTEXT(user_data); |
1304 | 594 | js_context->auto_gc_id = 0; | 597 | js_context->auto_gc_id = 0; |
1306 | 595 | gjs_gc_if_needed(js_context->context); | 598 | |
1307 | 599 | if (js_context->force_gc) | ||
1308 | 600 | JS_GC(js_context->context); | ||
1309 | 601 | else | ||
1310 | 602 | gjs_gc_if_needed(js_context->context); | ||
1311 | 603 | |||
1312 | 604 | js_context->force_gc = false; | ||
1313 | 605 | |||
1314 | 596 | return G_SOURCE_REMOVE; | 606 | return G_SOURCE_REMOVE; |
1315 | 597 | } | 607 | } |
1316 | 598 | 608 | ||
1319 | 599 | void | 609 | |
1320 | 600 | _gjs_context_schedule_gc_if_needed (GjsContext *js_context) | 610 | static void |
1321 | 611 | _gjs_context_schedule_gc_internal(GjsContext *js_context, | ||
1322 | 612 | bool force_gc) | ||
1323 | 601 | { | 613 | { |
1324 | 614 | js_context->force_gc |= force_gc; | ||
1325 | 615 | |||
1326 | 602 | if (js_context->auto_gc_id > 0) | 616 | if (js_context->auto_gc_id > 0) |
1327 | 603 | return; | 617 | return; |
1328 | 604 | 618 | ||
1332 | 605 | js_context->auto_gc_id = g_idle_add_full(G_PRIORITY_LOW, | 619 | js_context->force_gc |= force_gc; |
1333 | 606 | trigger_gc_if_needed, | 620 | js_context->auto_gc_id = g_timeout_add_seconds_full(G_PRIORITY_LOW, 10, |
1334 | 607 | js_context, NULL); | 621 | trigger_gc_if_needed, |
1335 | 622 | js_context, NULL); | ||
1336 | 623 | } | ||
1337 | 624 | |||
1338 | 625 | void | ||
1339 | 626 | _gjs_context_schedule_gc(GjsContext *js_context) | ||
1340 | 627 | { | ||
1341 | 628 | _gjs_context_schedule_gc_internal(js_context, true); | ||
1342 | 629 | } | ||
1343 | 630 | |||
1344 | 631 | void | ||
1345 | 632 | _gjs_context_schedule_gc_if_needed(GjsContext *js_context) | ||
1346 | 633 | { | ||
1347 | 634 | _gjs_context_schedule_gc_internal(js_context, false); | ||
1348 | 608 | } | 635 | } |
1349 | 609 | 636 | ||
1350 | 610 | void | 637 | void |
1351 | diff --git a/gjs/engine.cpp b/gjs/engine.cpp | |||
1352 | index 90fa57c..720267d 100644 | |||
1353 | --- a/gjs/engine.cpp | |||
1354 | +++ b/gjs/engine.cpp | |||
1355 | @@ -37,10 +37,6 @@ | |||
1356 | 37 | #include <windows.h> | 37 | #include <windows.h> |
1357 | 38 | #endif | 38 | #endif |
1358 | 39 | 39 | ||
1359 | 40 | #ifdef ENABLE_CAIRO | ||
1360 | 41 | # include <cairo.h> | ||
1361 | 42 | #endif | ||
1362 | 43 | |||
1363 | 44 | /* Implementations of locale-specific operations; these are used | 40 | /* Implementations of locale-specific operations; these are used |
1364 | 45 | * in the implementation of String.localeCompare(), Date.toLocaleDateString(), | 41 | * in the implementation of String.localeCompare(), Date.toLocaleDateString(), |
1365 | 46 | * and so forth. We take the straight-forward approach of converting | 42 | * and so forth. We take the straight-forward approach of converting |
1366 | @@ -218,16 +214,6 @@ on_promise_unhandled_rejection(JSContext *cx, | |||
1367 | 218 | std::move(stack)); | 214 | std::move(stack)); |
1368 | 219 | } | 215 | } |
1369 | 220 | 216 | ||
1370 | 221 | static void | ||
1371 | 222 | shutdown(void) | ||
1372 | 223 | { | ||
1373 | 224 | JS_ShutDown(); | ||
1374 | 225 | |||
1375 | 226 | #ifdef ENABLE_CAIRO | ||
1376 | 227 | cairo_debug_reset_static_data(); /* for valgrind reports */ | ||
1377 | 228 | #endif | ||
1378 | 229 | } | ||
1379 | 230 | |||
1380 | 231 | #ifdef G_OS_WIN32 | 217 | #ifdef G_OS_WIN32 |
1381 | 232 | HMODULE gjs_dll; | 218 | HMODULE gjs_dll; |
1382 | 233 | static bool gjs_is_inited = false; | 219 | static bool gjs_is_inited = false; |
1383 | @@ -245,7 +231,7 @@ LPVOID lpvReserved) | |||
1384 | 245 | break; | 231 | break; |
1385 | 246 | 232 | ||
1386 | 247 | case DLL_THREAD_DETACH: | 233 | case DLL_THREAD_DETACH: |
1388 | 248 | shutdown(); | 234 | JS_ShutDown (); |
1389 | 249 | break; | 235 | break; |
1390 | 250 | 236 | ||
1391 | 251 | default: | 237 | default: |
1392 | @@ -265,7 +251,7 @@ public: | |||
1393 | 265 | } | 251 | } |
1394 | 266 | 252 | ||
1395 | 267 | ~GjsInit() { | 253 | ~GjsInit() { |
1397 | 268 | shutdown(); | 254 | JS_ShutDown(); |
1398 | 269 | } | 255 | } |
1399 | 270 | 256 | ||
1400 | 271 | operator bool() { | 257 | operator bool() { |
1401 | @@ -322,13 +308,14 @@ gjs_create_js_context(GjsContext *js_context) | |||
1402 | 322 | JS::ContextOptionsRef(cx).setExtraWarnings(true); | 308 | JS::ContextOptionsRef(cx).setExtraWarnings(true); |
1403 | 323 | } | 309 | } |
1404 | 324 | 310 | ||
1406 | 325 | if (!g_getenv("GJS_DISABLE_JIT")) { | 311 | bool enable_jit = !(g_getenv("GJS_DISABLE_JIT")); |
1407 | 312 | if (enable_jit) { | ||
1408 | 326 | gjs_debug(GJS_DEBUG_CONTEXT, "Enabling JIT"); | 313 | gjs_debug(GJS_DEBUG_CONTEXT, "Enabling JIT"); |
1409 | 327 | JS::ContextOptionsRef(cx) | ||
1410 | 328 | .setIon(true) | ||
1411 | 329 | .setBaseline(true) | ||
1412 | 330 | .setAsmJS(true); | ||
1413 | 331 | } | 314 | } |
1414 | 315 | JS::ContextOptionsRef(cx) | ||
1415 | 316 | .setIon(enable_jit) | ||
1416 | 317 | .setBaseline(enable_jit) | ||
1417 | 318 | .setAsmJS(enable_jit); | ||
1418 | 332 | 319 | ||
1419 | 333 | return cx; | 320 | return cx; |
1420 | 334 | } | 321 | } |
1421 | diff --git a/gjs/importer.cpp b/gjs/importer.cpp | |||
1422 | index b4ea3c8..4c42a84 100644 | |||
1423 | --- a/gjs/importer.cpp | |||
1424 | +++ b/gjs/importer.cpp | |||
1425 | @@ -706,7 +706,7 @@ importer_enumerate(JSContext *context, | |||
1426 | 706 | /* new_for_commandline_arg handles resource:/// paths */ | 706 | /* new_for_commandline_arg handles resource:/// paths */ |
1427 | 707 | GjsAutoUnref<GFile> dir = g_file_new_for_commandline_arg(dirname); | 707 | GjsAutoUnref<GFile> dir = g_file_new_for_commandline_arg(dirname); |
1428 | 708 | GjsAutoUnref<GFileEnumerator> direnum = | 708 | GjsAutoUnref<GFileEnumerator> direnum = |
1430 | 709 | g_file_enumerate_children(dir, G_FILE_ATTRIBUTE_STANDARD_TYPE, | 709 | g_file_enumerate_children(dir, "standard::name,standard::type", |
1431 | 710 | G_FILE_QUERY_INFO_NONE, NULL, NULL); | 710 | G_FILE_QUERY_INFO_NONE, NULL, NULL); |
1432 | 711 | 711 | ||
1433 | 712 | while (true) { | 712 | while (true) { |
1434 | diff --git a/gjs/jsapi-util-root.h b/gjs/jsapi-util-root.h | |||
1435 | index 5baed48..d64eccb 100644 | |||
1436 | --- a/gjs/jsapi-util-root.h | |||
1437 | +++ b/gjs/jsapi-util-root.h | |||
1438 | @@ -219,6 +219,7 @@ public: | |||
1439 | 219 | return m_root->get() == nullptr; | 219 | return m_root->get() == nullptr; |
1440 | 220 | return m_heap.unbarrieredGet() == nullptr; | 220 | return m_heap.unbarrieredGet() == nullptr; |
1441 | 221 | } | 221 | } |
1442 | 222 | inline bool operator!=(std::nullptr_t) const { return !(*this == nullptr); } | ||
1443 | 222 | 223 | ||
1444 | 223 | /* You can get a Handle<T> if the thing is rooted, so that you can use this | 224 | /* You can get a Handle<T> if the thing is rooted, so that you can use this |
1445 | 224 | * wrapper with stack rooting. However, you must not do this if the | 225 | * wrapper with stack rooting. However, you must not do this if the |
1446 | @@ -247,10 +248,12 @@ public: | |||
1447 | 247 | m_data = data; | 248 | m_data = data; |
1448 | 248 | m_root = new JS::PersistentRooted<T>(m_cx, thing); | 249 | m_root = new JS::PersistentRooted<T>(m_cx, thing); |
1449 | 249 | 250 | ||
1454 | 250 | auto gjs_cx = static_cast<GjsContext *>(JS_GetContextPrivate(m_cx)); | 251 | if (notify) { |
1455 | 251 | g_assert(GJS_IS_CONTEXT(gjs_cx)); | 252 | auto gjs_cx = static_cast<GjsContext *>(JS_GetContextPrivate(m_cx)); |
1456 | 252 | g_object_weak_ref(G_OBJECT(gjs_cx), on_context_destroy, this); | 253 | g_assert(GJS_IS_CONTEXT(gjs_cx)); |
1457 | 253 | m_has_weakref = true; | 254 | g_object_weak_ref(G_OBJECT(gjs_cx), on_context_destroy, this); |
1458 | 255 | m_has_weakref = true; | ||
1459 | 256 | } | ||
1460 | 254 | } | 257 | } |
1461 | 255 | 258 | ||
1462 | 256 | /* You can only assign directly to the GjsMaybeOwned wrapper in the | 259 | /* You can only assign directly to the GjsMaybeOwned wrapper in the |
1463 | diff --git a/gjs/jsapi-util.cpp b/gjs/jsapi-util.cpp | |||
1464 | index 322a41b..ed3e649 100644 | |||
1465 | --- a/gjs/jsapi-util.cpp | |||
1466 | +++ b/gjs/jsapi-util.cpp | |||
1467 | @@ -26,6 +26,8 @@ | |||
1468 | 26 | 26 | ||
1469 | 27 | #include <codecvt> | 27 | #include <codecvt> |
1470 | 28 | #include <locale> | 28 | #include <locale> |
1471 | 29 | #include "jsapi-wrapper.h" | ||
1472 | 30 | #include <js/GCAPI.h> | ||
1473 | 29 | 31 | ||
1474 | 30 | #include <util/log.h> | 32 | #include <util/log.h> |
1475 | 31 | #include <util/glib.h> | 33 | #include <util/glib.h> |
1476 | @@ -34,7 +36,6 @@ | |||
1477 | 34 | 36 | ||
1478 | 35 | #include "jsapi-class.h" | 37 | #include "jsapi-class.h" |
1479 | 36 | #include "jsapi-util.h" | 38 | #include "jsapi-util.h" |
1480 | 37 | #include "jsapi-wrapper.h" | ||
1481 | 38 | #include "context-private.h" | 39 | #include "context-private.h" |
1482 | 39 | #include <gi/boxed.h> | 40 | #include <gi/boxed.h> |
1483 | 40 | 41 | ||
1484 | @@ -313,8 +314,9 @@ gjs_build_string_array(JSContext *context, | |||
1485 | 313 | g_error("Unable to reserve memory for vector"); | 314 | g_error("Unable to reserve memory for vector"); |
1486 | 314 | 315 | ||
1487 | 315 | for (i = 0; i < array_length; ++i) { | 316 | for (i = 0; i < array_length; ++i) { |
1488 | 317 | JS::ConstUTF8CharsZ chars(array_values[i], strlen(array_values[i])); | ||
1489 | 316 | JS::RootedValue element(context, | 318 | JS::RootedValue element(context, |
1491 | 317 | JS::StringValue(JS_NewStringCopyZ(context, array_values[i]))); | 319 | JS::StringValue(JS_NewStringCopyUTF8Z(context, chars))); |
1492 | 318 | if (!elems.append(element)) | 320 | if (!elems.append(element)) |
1493 | 319 | g_error("Unable to append to vector"); | 321 | g_error("Unable to append to vector"); |
1494 | 320 | } | 322 | } |
1495 | @@ -731,7 +733,7 @@ gjs_gc_if_needed (JSContext *context) | |||
1496 | 731 | */ | 733 | */ |
1497 | 732 | if (rss_size > linux_rss_trigger) { | 734 | if (rss_size > linux_rss_trigger) { |
1498 | 733 | linux_rss_trigger = (gulong) MIN(G_MAXULONG, rss_size * 1.25); | 735 | linux_rss_trigger = (gulong) MIN(G_MAXULONG, rss_size * 1.25); |
1500 | 734 | JS_GC(context); | 736 | JS::GCForReason(context, GC_SHRINK, JS::gcreason::Reason::API); |
1501 | 735 | } else if (rss_size < (0.75 * linux_rss_trigger)) { | 737 | } else if (rss_size < (0.75 * linux_rss_trigger)) { |
1502 | 736 | /* If we've shrunk by 75%, lower the trigger */ | 738 | /* If we've shrunk by 75%, lower the trigger */ |
1503 | 737 | linux_rss_trigger = (rss_size * 1.25); | 739 | linux_rss_trigger = (rss_size * 1.25); |
1504 | diff --git a/installed-tests/extra/gjs.supp b/installed-tests/extra/gjs.supp | |||
1505 | index a768e27..b99eb25 100644 | |||
1506 | --- a/installed-tests/extra/gjs.supp | |||
1507 | +++ b/installed-tests/extra/gjs.supp | |||
1508 | @@ -1,35 +1,6 @@ | |||
1509 | 1 | # Valgrind suppressions file for GJS | 1 | # Valgrind suppressions file for GJS |
1510 | 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. |
1511 | 3 | 3 | ||
1512 | 4 | # We leak a small wrapper in GJS for each registered GType. | ||
1513 | 5 | |||
1514 | 6 | { | ||
1515 | 7 | gtype-wrapper-new | ||
1516 | 8 | Memcheck:Leak | ||
1517 | 9 | match-leak-kinds: definite | ||
1518 | 10 | fun:_Znwm | ||
1519 | 11 | fun:gjs_gtype_create_gtype_wrapper | ||
1520 | 12 | } | ||
1521 | 13 | |||
1522 | 14 | { | ||
1523 | 15 | gtype-wrapper-qdata | ||
1524 | 16 | Memcheck:Leak | ||
1525 | 17 | match-leak-kinds: possible | ||
1526 | 18 | ... | ||
1527 | 19 | fun:type_set_qdata_W | ||
1528 | 20 | fun:g_type_set_qdata | ||
1529 | 21 | fun:gjs_gtype_create_gtype_wrapper | ||
1530 | 22 | } | ||
1531 | 23 | |||
1532 | 24 | { | ||
1533 | 25 | g_type_register_fundamental never freed | ||
1534 | 26 | Memcheck:Leak | ||
1535 | 27 | fun:calloc | ||
1536 | 28 | ... | ||
1537 | 29 | fun:g_type_register_fundamental | ||
1538 | 30 | ... | ||
1539 | 31 | } | ||
1540 | 32 | |||
1541 | 33 | # SpiderMonkey leaks | 4 | # SpiderMonkey leaks |
1542 | 34 | 5 | ||
1543 | 35 | { | 6 | { |
1544 | @@ -143,6 +114,29 @@ | |||
1545 | 143 | fun:cairo_show_text | 114 | fun:cairo_show_text |
1546 | 144 | } | 115 | } |
1547 | 145 | 116 | ||
1548 | 117 | # Data that Cairo keeps around for the process lifetime | ||
1549 | 118 | # This could be freed by calling cairo_debug_reset_static_data(), but it's | ||
1550 | 119 | # not a good idea to call that function in production, because certain versions | ||
1551 | 120 | # of Cairo have bugs that cause it to fail assertions and crash. | ||
1552 | 121 | { | ||
1553 | 122 | cairo-static-data | ||
1554 | 123 | Memcheck:Leak | ||
1555 | 124 | match-leak-kinds: definite | ||
1556 | 125 | fun:malloc | ||
1557 | 126 | ... | ||
1558 | 127 | fun:FcPatternDuplicate | ||
1559 | 128 | fun:_cairo_ft_font_face_create_for_pattern | ||
1560 | 129 | fun:_cairo_ft_font_face_create_for_toy | ||
1561 | 130 | fun:_cairo_toy_font_face_create_impl_face | ||
1562 | 131 | fun:_cairo_toy_font_face_init | ||
1563 | 132 | fun:cairo_toy_font_face_create | ||
1564 | 133 | fun:_cairo_gstate_ensure_font_face | ||
1565 | 134 | fun:_cairo_gstate_ensure_scaled_font | ||
1566 | 135 | fun:_cairo_gstate_get_scaled_font | ||
1567 | 136 | fun:_cairo_default_context_get_scaled_font | ||
1568 | 137 | fun:cairo_show_text | ||
1569 | 138 | } | ||
1570 | 139 | |||
1571 | 146 | # SpiderMonkey data races | 140 | # SpiderMonkey data races |
1572 | 147 | 141 | ||
1573 | 148 | # These are in SpiderMonkey's atomics / thread barrier stuff so presumably | 142 | # These are in SpiderMonkey's atomics / thread barrier stuff so presumably |
1574 | diff --git a/installed-tests/extra/lsan.supp b/installed-tests/extra/lsan.supp | |||
1575 | index 179eb9c..3c69851 100644 | |||
1576 | --- a/installed-tests/extra/lsan.supp | |||
1577 | +++ b/installed-tests/extra/lsan.supp | |||
1578 | @@ -1,8 +1,5 @@ | |||
1579 | 1 | # SpiderMonkey leaks a mutex for each GC helper thread. | 1 | # SpiderMonkey leaks a mutex for each GC helper thread. |
1580 | 2 | leak:js::HelperThread::threadLoop | 2 | leak:js::HelperThread::threadLoop |
1581 | 3 | 3 | ||
1582 | 4 | # We leak a small wrapper in GJS for each registered GType. | ||
1583 | 5 | leak:gjs_gtype_create_gtype_wrapper | ||
1584 | 6 | |||
1585 | 7 | # https://bugs.freedesktop.org/show_bug.cgi?id=105466 | 4 | # https://bugs.freedesktop.org/show_bug.cgi?id=105466 |
1586 | 8 | leak:libfontconfig.so.1 | 5 | leak:libfontconfig.so.1 |
1587 | diff --git a/modules/overrides/GObject.js b/modules/overrides/GObject.js | |||
1588 | index 741a9f3..bf1ae97 100644 | |||
1589 | --- a/modules/overrides/GObject.js | |||
1590 | +++ b/modules/overrides/GObject.js | |||
1591 | @@ -441,6 +441,14 @@ function _init() { | |||
1592 | 441 | GObject._children = _children; | 441 | GObject._children = _children; |
1593 | 442 | GObject._internalChildren = _internalChildren; | 442 | GObject._internalChildren = _internalChildren; |
1594 | 443 | 443 | ||
1595 | 444 | // Expose GObject static properties for ES6 classes | ||
1596 | 445 | |||
1597 | 446 | GObject.GTypeName = GTypeName; | ||
1598 | 447 | GObject.requires = requires; | ||
1599 | 448 | GObject.interfaces = interfaces; | ||
1600 | 449 | GObject.properties = properties; | ||
1601 | 450 | GObject.signals = signals; | ||
1602 | 451 | |||
1603 | 444 | // fake enum for signal accumulators, keep in sync with gi/object.c | 452 | // fake enum for signal accumulators, keep in sync with gi/object.c |
1604 | 445 | this.AccumulatorType = { | 453 | this.AccumulatorType = { |
1605 | 446 | NONE: 0, | 454 | NONE: 0, |
1606 | diff --git a/modules/tweener/tweener.js b/modules/tweener/tweener.js | |||
1607 | index 98bde02..61c6654 100644 | |||
1608 | --- a/modules/tweener/tweener.js | |||
1609 | +++ b/modules/tweener/tweener.js | |||
1610 | @@ -368,7 +368,7 @@ function _onEnterFrame() { | |||
1611 | 368 | return true; | 368 | return true; |
1612 | 369 | } | 369 | } |
1613 | 370 | 370 | ||
1615 | 371 | const restrictedWords = { | 371 | var restrictedWords = { |
1616 | 372 | time: true, | 372 | time: true, |
1617 | 373 | delay: true, | 373 | delay: true, |
1618 | 374 | userFrames: true, | 374 | userFrames: true, |
1619 | diff --git a/win32/config.h.win32 b/win32/config.h.win32 | |||
1620 | index 7495f0a..1e78fa6 100644 | |||
1621 | --- a/win32/config.h.win32 | |||
1622 | +++ b/win32/config.h.win32 | |||
1623 | @@ -13,7 +13,7 @@ | |||
1624 | 13 | #define GETTEXT_PACKAGE "gjs" | 13 | #define GETTEXT_PACKAGE "gjs" |
1625 | 14 | 14 | ||
1626 | 15 | /* The gjs version as an integer */ | 15 | /* The gjs version as an integer */ |
1628 | 16 | #define GJS_VERSION 15201 | 16 | #define GJS_VERSION 15205 |
1629 | 17 | 17 | ||
1630 | 18 | /* define if the compiler supports basic C++11 syntax */ | 18 | /* define if the compiler supports basic C++11 syntax */ |
1631 | 19 | #define HAVE_CXX11 1 | 19 | #define HAVE_CXX11 1 |
1632 | @@ -74,7 +74,7 @@ | |||
1633 | 74 | #define PACKAGE_NAME "gjs" | 74 | #define PACKAGE_NAME "gjs" |
1634 | 75 | 75 | ||
1635 | 76 | /* Define to the full name and version of this package. */ | 76 | /* Define to the full name and version of this package. */ |
1637 | 77 | #define PACKAGE_STRING "gjs 1.52.1" | 77 | #define PACKAGE_STRING "gjs 1.52.5" |
1638 | 78 | 78 | ||
1639 | 79 | /* Define to the one symbol short name of this package. */ | 79 | /* Define to the one symbol short name of this package. */ |
1640 | 80 | #define PACKAGE_TARNAME "gjs" | 80 | #define PACKAGE_TARNAME "gjs" |
1641 | @@ -83,10 +83,10 @@ | |||
1642 | 83 | #define PACKAGE_URL "" | 83 | #define PACKAGE_URL "" |
1643 | 84 | 84 | ||
1644 | 85 | /* Define to the version of this package. */ | 85 | /* Define to the version of this package. */ |
1646 | 86 | #define PACKAGE_VERSION "1.52.1" | 86 | #define PACKAGE_VERSION "1.52.5" |
1647 | 87 | 87 | ||
1648 | 88 | /* Define to 1 if you have the ANSI C header files. */ | 88 | /* Define to 1 if you have the ANSI C header files. */ |
1649 | 89 | #define STDC_HEADERS 1 | 89 | #define STDC_HEADERS 1 |
1650 | 90 | 90 | ||
1651 | 91 | /* Version number of package */ | 91 | /* Version number of package */ |
1653 | 92 | #define VERSION "1.52.1" | 92 | #define VERSION "1.52.5" |