...
 
Commits (272)
......@@ -74,6 +74,8 @@ gjs_tests_gtester_LDADD = \
gjs_tests_gtester_SOURCES = \
test/gjs-tests.cpp \
test/gjs-test-common.cpp \
test/gjs-test-common.h \
test/gjs-test-utils.cpp \
test/gjs-test-utils.h \
test/gjs-test-call-args.cpp \
......@@ -284,7 +286,7 @@ AM_TESTS_ENVIRONMENT = \
export G_FILENAME_ENCODING=latin1; \
export LSAN_OPTIONS="suppressions=$(abs_top_srcdir)/installed-tests/extra/lsan.supp"; \
export NO_AT_BRIDGE=1; \
export LC_ALL=C.UTF-8; \
export LC_ALL=$(TESTS_LOCALE); \
$(COVERAGE_TESTS_ENVIRONMENT) \
$(GTK_TESTS_ENVIRONMENT) \
$(XVFB_START) \
......
This diff is collapsed.
Version 1.56.0
--------------
- No change from 1.55.92.
Version 1.55.92
---------------
- Closed bugs and merge requests:
* Fix CI failures [!269, Philip Chimento]
* Possible memory allocation/deallocation bug (possibly in js_free() in GJS)
[!270, Chun-wei Fan, Philip Chimento]
* cairo-context: Special-case 0-sized vector [!271, Florian Müllner]
* Add some more eslint rules [!272, Florian Müllner]
* win32/NMake: Fix introspection builds [!274, Chun-wei Fan]
* NMake/libgjs-private: Export all the public symbols there [!275, Chun-wei
Fan]
Version 1.55.91
---------------
- The problem of freezing while running the tests using GCC's sanitizers was
determined to be a bug in GCC, which was fixed in GCC 9.0.1.
- Closed bugs and merge requests:
* gnome-sound-recorder crashes deep inside libgjs [#223, !266, Philip
Chimento]
* Various maintenance [!267, Philip Chimento]
* wrapperutils: Define $gtype property as non-enumerable [!268, Philip
Chimento]
Version 1.55.90
---------------
- New JS API: It's now possible to call and implement DBus methods whose
parameters or return types include file descriptor lists (type signature 'h'.)
This involves passing or receiving a Gio.UnixFDList instance along with the
parameters or return values.
To call a method with a file descriptor list, pass the Gio.UnixFDList along
with the rest of the parameters, in any order, the same way you would pass a
Gio.Cancellable or async callback.
For return values, things are a little more complicated, in order to avoid
breaking existing code. Previously, synchronously called DBus proxy methods
would return an unpacked GVariant. Now, but only if called with a
Gio.UnixFDList, they will return [unpacked GVariant, Gio.UnixFDList]. This
does not break existing code because it was not possible to call a method with
a Gio.UnixFDList before, and the return value is unchanged if not calling with
a Gio.UnixFDList. This does mean, unfortunately, that if you have a method
with an 'h' in its return signature but not in its argument signatures, you
will have to call it with an empty FDList in order to receive an FDList with
the return value, when calling synchronously.
On the DBus service side, when receiving a method call, we now pass the
Gio.UnixFDList received from DBus to the called method. Previously, sync
methods were passed the parameters, and async methods were passed the
parameters plus the Gio.DBusInvocation object. Appending the Gio.UnixFDList to
those parameters also should not break existing code.
See the new tests in installed-tests/js/testGDBus.js for examples of calling
methods with FD lists.
- We have observed on the CI server that GJS 1.55.90 will hang forever while
running the test suite compiled with GCC 9.0.0 and configured with the
--enable-asan and --enable-ubsan arguments. This should be addressed in one of
the following 1.55.x releases.
- Closed bugs and merge requests:
* GDBus proxy overrides should support Gio.DBusProxy.call_with_unix_fd_list()
[#204, !263, Philip Chimento]
* Add regression tests for GObject vfuncs [!259, Jason Hicks]
* GjsPrivate: Sources should be C files [!262, Philip Chimento]
* build: Vendor last-good version of AX_CODE_COVERAGE [!264, Philip Chimento]
Version 1.55.4
--------------
- Closed bugs and merge requests:
* Various maintenance [!258, Philip Chimento]
* Boxed copy constructor should not be called, split Boxed into prototype and
instance structs [#215, !260, Philip Chimento]
Version 1.55.3
--------------
- Closed bugs and merge requests:
* Manually constructed ByteArray toString segfaults [#219, !254, Philip
Chimento]
* signals: Add _signalHandlerIsConnected method [!255, Jason Hicks]
* Various maintenance [!257, Philip Chimento]
Version 1.52.5
--------------
- This was a release consisting only of backports from the GNOME 3.30 branch to
the GNOME 3.28 branch.
- This release includes the "Big Hammer" patch from GNOME 3.30 to reduce memory
usage. For more information, read the blog post at
https://feaneron.com/2018/04/20/the-infamous-gnome-shell-memory-leak/
It was not originally intended to be backported to GNOME 3.28, but in practice
several Linux distributions already backported it, and it has been working
well to reduce memory usage, and the bugs have been ironed out of it.
It does decrease performance somewhat, so if you don't want that then don't
install this update.
- Closed bugs and merge requests:
* Ensure not to miss the force_gc flag [#150, !132, Carlos Garnacho]
* Make GC much more aggressive [#62, !50, Giovanni Campagna, Georges Basile
Stavracas Neto, Philip Chimento]
* Queue GC when a GObject reference is toggled down [#140, !114, !127, Georges
Basile Stavracas Neto]
* Reduce memory overhead of g_object_weak_ref() [#144, !122, Carlos Garnacho,
Philip Chimento]
* context: Defer and therefore batch forced GC runs [performance] [!236,
Daniel van Vugt]
* context: use timeout with seconds to schedule a gc trigger [!239, Marco
Trevisan]
* Use compacting GC on RSS size growth [!133, #151, Carlos Garnacho]
* GType memleak fixes [!244, Marco Trevisan]
Version 1.55.2
--------------
- Closed bugs and merge requests:
* Gnome-shell crashes on destroying cached param specs [#213, !240, Marco
Trevisan]
* Various maintenance [!235, !250, Philip Chimento]
* Auto pointers builder [!243, Marco Trevisan]
* configure.ac: Update bug link [!245, Andrea Azzarone]
* SIGSEGV when exiting gnome-shell [#212, !247, Andrea Azzarone, Philip
Chimento]
* Fix build with --enable-dtrace and create CI job to ensure it doesn't break
in the future [#196, !237, !253, Philip Chimento]
* Delay JSString-to-UTF8 conversion [!249, Philip Chimento]
* Annotate return values [!251, Philip Chimento]
* Fix a regression with GError toString() [!252, Philip Chimento]
* GType memleak fixes [!244, Marco Trevisan]
* Atoms refactor [!233, Philip Chimento, Marco Trevisan]
* Write a "Code Hospitable" README file [#17, !248, Philip Chimento, Andy
Holmes, Avi Zajac]
* object: Method lookup repeatedly traverses introspection [#54, !53, Colin
Walters, Philip Chimento]
* Handler of GtkEditable::insert-text signal is not run [#147, !143, Tomasz
Miąsko, Philip Chimento]
Version 1.54.3
--------------
......@@ -28,6 +177,48 @@ Version 1.54.2
- Backported various maintenance from 3.31 [Philip Chimento]
Version 1.55.1
--------------
- New API for programs that embed GJS: gjs_memory_report(). This was already an
internal API, but now it is exported.
- Closed bugs and merge requests:
* object: Implement newEnumerate hook for GObject [!155, Ole Jørgen Brønner]
* Various maintenance [!228, Philip Chimento]
* ByteArray.toString should stop at null bytes [#195, !232, Philip Chimento]
* Byte arrays that represent encoded strings should be 0-terminated [#203,
!232, Philip Chimento]
* context: Defer and therefore batch forced GC runs [performance] [!236,
Daniel van Vugt]
* context: use timeout with seconds to schedule a gc trigger [!239, Marco
Trevisan]
* arg: Add special-case for byte arrays going to C [#67, !49, Jasper
St. Pierre, Philip Chimento]
Version 1.52.4
--------------
- This was a release consisting only of backports from the GNOME 3.30 branch to
the GNOME 3.28 branch.
- Closed bugs and merge requests:
* `ARGV` encoding issues [#22, !108, Evan Welsh]
* Segfault on enumeration of GjSFileImporter properties when a searchpath
entry contains a symlink [#154, !144, Ole Jørgen Brønner]
* Possible refcounting bug around GtkListbox signal handlers [#24, !154,
Philip Chimento]
* Fix up GJS_DISABLE_JIT flag now the JIT is enabled by default in
SpiderMonkey [!159, Christopher Wheeldon]
* Expose GObject static property symbols. [!197, Evan Welsh]
* Do not run linters on tagged commits [!181, Claudio André]
* gjs-1.52.0 fails to compile against x86_64 musl systems [#132, !214, Philip
Chimento]
* gjs no longer builds after recent autoconf-archive updates [#149, !217,
Philip Chimento]
Version 1.54.1
--------------
......
......@@ -10,30 +10,81 @@
JavaScript bindings for GNOME
=============================
It's mainly based on Spidermonkey javascript engine and the GObject introspection framework.
Available as part of your GNOME distribution. Powers GNOME Shell, Polari,
GNOME Documents, and many other apps.
Use the GNOME platform libraries in your JavaScript programs.
GJS powers GNOME Shell, Polari, GNOME Documents, and many other apps.
Under the hood it uses SpiderMonkey, Mozilla's JavaScript engine
originally developed for Firefox.
Wiki: https://gitlab.gnome.org/GNOME/gjs/wikis/Home
How to build and run if you want to contribute to GJS: see doc/Hacking.md
## Installation
Available as part of your GNOME distribution by default.
In most package managers the package will be called `gjs`.
## Usage
GJS includes a command-line interpreter, usually installed in
`/usr/bin/gjs`.
Type `gjs` to start it and test out your JavaScript statements
interactively.
Hit Ctrl+D to exit.
`gjs filename.js` runs a whole program.
`gjs -d filename.js` does that and starts a debugger as well.
There are also facilities for generating code coverage reports.
Type `gjs --help` for more information.
## Contributing
For instructions on how to get started contributing to GJS, please read
the contributing guide,
<https://gitlab.gnome.org/GNOME/gjs/blob/master/CONTRIBUTING.md>.
## History
## Testing
GJS probably started in August 2008 with [this blog post][havocp] and
[this experimental code][gscript].
GJS in its current form was first developed in October 2008 at a company
called litl, for their [litl webbook] product.
It was soon adopted as the basis of [GNOME Shell]'s UI code and
extensions system and debuted as a fundamental component of GNOME 3.0.
Our CI (continuous integration) testing scheme stresses the source code using:
- Ubuntu 18.04, Fedora 29 (devel), and Ubuntu 18.10 (devel);
- gcc 7.3, gcc 8.1, and clang 6.0;
- C/C++ and Javascript Linters;
- Code Climate (https://codeclimate.com/);
- ASAN (address sanitizer) and UBSAN (undefined behavior sanitizer);
- Valgrind (https://en.wikipedia.org/wiki/Valgrind);
- Code Coverage (https://en.wikipedia.org/wiki/Code_coverage);
- Text only and graphics builds;
- Profiler enabled and disabled builds;
- ARMv8 and PPC64LE builds;
- And DevOps with Flatpak.
In February 2013 at the GNOME Developer Experience Hackfest GJS was
declared the ['first among equals'][treitter] of languages for GNOME
application development.
That proved controversial for many, and was later abandoned.
At the time of writing (2018) GJS is used in many systems including
Endless OS's [framework for offline content][eos-knowledge-lib] and, as
a forked version, [Cinnamon].
## Reading material
### JavaScript & SpiderMonkey
* https://github.com/spidermonkey-embedders/spidermonkey-embedding-examples
### GNOME Contribution
* https://wiki.gnome.org/GitLab
* https://wiki.gnome.org/Newcomers/
## License
Dual licensed under LGPL 2.0+ and MIT.
## Thanks ##
The form of this README was inspired by [Nadia Odunayo][hospitable] on
the Greater Than Code podcast.
[havocp]: https://blog.ometer.com/2008/08/25/embeddable-languages/
[gscript]: https://gitlab.gnome.org/Archive/gscript/tree/master/gscript
[litl webbook]: https://en.wikipedia.org/wiki/Litl
[GNOME Shell]: https://wiki.gnome.org/Projects/GnomeShell
[treitter]: https://treitter.livejournal.com/14871.html
[eos-knowledge-lib]: http://endlessm.github.io/eos-knowledge-lib/
[Cinnamon]: https://en.wikipedia.org/wiki/Cinnamon_(software)
[hospitable]: http://www.greaterthancode.com/2017/11/08/054-code-hospitality-with-nadia-odunayo/
......@@ -1228,7 +1228,6 @@ m4_include([m4/ax_append_flag.m4])
m4_include([m4/ax_append_link_flags.m4])
m4_include([m4/ax_check_compile_flag.m4])
m4_include([m4/ax_check_link_flag.m4])
m4_include([m4/ax_code_coverage.m4])
m4_include([m4/ax_compiler_flags.m4])
m4_include([m4/ax_compiler_flags_cflags.m4])
m4_include([m4/ax_compiler_flags_cxxflags.m4])
......@@ -1240,6 +1239,7 @@ m4_include([m4/ax_is_release.m4])
m4_include([m4/ax_pkg_check_modules.m4])
m4_include([m4/ax_require_defined.m4])
m4_include([m4/ax_valgrind_check.m4])
m4_include([m4/code_coverage.m4])
m4_include([m4/extensions.m4])
m4_include([m4/introspection.m4])
m4_include([m4/libtool.m4])
......
......@@ -54,6 +54,9 @@
/* Define to 1 if you have the <sys/stat.h> header file. */
#undef HAVE_SYS_STAT_H
/* Define to 1 if you have the <sys/syscall.h> header file. */
#undef HAVE_SYS_SYSCALL_H
/* Define to 1 if you have the <sys/types.h> header file. */
#undef HAVE_SYS_TYPES_H
......
This diff is collapsed.
......@@ -2,13 +2,13 @@
# Process this file with autoconf to produce a configure script.
m4_define(pkg_major_version, 1)
m4_define(pkg_minor_version, 54)
m4_define(pkg_micro_version, 3)
m4_define(pkg_minor_version, 56)
m4_define(pkg_micro_version, 0)
m4_define(pkg_version, pkg_major_version.pkg_minor_version.pkg_micro_version)
m4_define(pkg_int_version, (pkg_major_version * 100 + pkg_minor_version) * 100 + pkg_micro_version)
AC_PREREQ([2.64])
AC_INIT([gjs],[pkg_version],[http://bugzilla.gnome.org/enter_bug.cgi?product=gjs],[gjs],[https://wiki.gnome.org/Projects/Gjs])
AC_INIT([gjs],[pkg_version],[https://gitlab.gnome.org/GNOME/gjs/issues],[gjs],[https://wiki.gnome.org/Projects/Gjs])
AM_INIT_AUTOMAKE([1.11.1 subdir-objects dist-xz no-dist-gzip tar-ustar -Wno-portability])
AX_IS_RELEASE([git-directory])
AC_CONFIG_SRCDIR([gjs/console.cpp])
......@@ -29,10 +29,14 @@ AM_SILENT_RULES([yes])
PKG_PROG_PKG_CONFIG
PKG_INSTALLDIR
AC_PROG_CC
AC_PROG_CC_C99
AC_LANG([C++])
AC_USE_SYSTEM_EXTENSIONS
AC_PROG_CXX
AX_CXX_COMPILE_STDCXX_14
AC_CHECK_HEADERS([sys/syscall.h unistd.h])
LT_PREREQ([2.2.0])
# no stupid static libraries
......@@ -46,7 +50,7 @@ AC_PROG_AWK
AX_COMPILER_FLAGS
AX_CODE_COVERAGE
GJS_CODE_COVERAGE
dnl Clang does not need to link with -lgcov
AX_CHECK_LINK_FLAG([-lgcov],, [
CODE_COVERAGE_LIBS=
......@@ -265,7 +269,7 @@ AS_IF([test "x$enable_Bsymbolic" != "xno"],
[AX_APPEND_LINK_FLAGS([-Bsymbolic-functions])])
dnl
dnl Check for -fsanitize=address and -fsanitize=undefined support
dnl Check for sanitizer support
dnl
AC_ARG_ENABLE([asan],
[AS_HELP_STRING([--enable-asan], [Build with address sanitizer support @<:@default: no@:>@])])
......@@ -278,12 +282,12 @@ AS_IF([test "x$enable_asan" = "xyes"], [
])
AC_ARG_ENABLE([ubsan],
[AS_HELP_STRING([--enable-ubsan], [Build with undefined behavior sanitizer support @<:@default: no@:>@])])
[AS_HELP_STRING([--enable-ubsan], [Build with undefined behavior and integer overflow sanitizer support @<:@default: no@:>@])])
AS_IF([test "x$enable_ubsan" = "xyes"], [
AX_CHECK_COMPILE_FLAG([-fsanitize=undefined -fno-sanitize=vptr -fno-omit-frame-pointer -g], [
AX_CHECK_LINK_FLAG([-fsanitize=undefined -fno-sanitize=vptr])
SAN_FLAGS="$SAN_FLAGS -fsanitize=undefined -fno-sanitize=vptr"
AX_CHECK_COMPILE_FLAG([-fsanitize=undefined -fsanitize=integer -fno-sanitize=vptr -fno-omit-frame-pointer -g], [
AX_CHECK_LINK_FLAG([-fsanitize=undefined -fsanitize=integer -fno-sanitize=vptr])
SAN_FLAGS="$SAN_FLAGS -fsanitize=undefined -fsanitize=integer -fno-sanitize=vptr"
])
])
......@@ -334,6 +338,26 @@ AS_IF([test "x$with_dbus_tests" != "xno"], [
])
AM_CONDITIONAL([DBUS_TESTS], [test "x$with_dbus_tests" != "xno"])
AC_MSG_CHECKING([for a suitable UTF-8 locale to run the tests in])
LOCALES=$(locale -a)
AS_CASE([$LOCALES],
dnl Prefer C.UTF-8 although it is only available with newer libc
[*C.UTF-8*], [TESTS_LOCALE=C.UTF-8],
dnl Most systems will probably have this
[*en_US.UTF-8*], [TESTS_LOCALE=en_US.UTF-8],
[*en_US.utf8*], [TESTS_LOCALE=en_US.utf8],
dnl If not, fall back to any English UTF-8 locale or any UTF-8 locale at all
[*en_*.UTF-8*], [TESTS_LOCALE=$(echo $LOCALES | grep -m1 en_.\*\\.UTF-8)],
[*en_*.utf8*], [TESTS_LOCALE=$(echo $LOCALES | grep -m1 en_.\*\\.utf8)],
[*.UTF-8*], [TESTS_LOCALE=$(echo $LOCALES | grep -m1 \\.UTF-8)],
[*.utf8*], [TESTS_LOCALE=$(echo $LOCALES | grep -m1 \\.utf8)],
[TESTS_LOCALE=C])
AC_MSG_RESULT([$TESTS_LOCALE])
AC_SUBST([TESTS_LOCALE])
AC_SUBST([gjsjsdir], [\${datadir}/gjs-1.0])
dnl automake 1.11/1.12 defines this but does not substitute it
......@@ -354,11 +378,17 @@ AC_CONFIG_LINKS([
AC_OUTPUT
# Warn about conditions that affect runtime
PKG_CHECK_EXISTS([gobject-introspection-1.0 >= 1.53.4], [], [
PKG_CHECK_EXISTS([gobject-introspection-1.0 >= 1.57.2], [], [
AC_MSG_WARN([You do not have a new enough version of
gobject-introspection to run the tests. You can still build GJS, but some
tests will fail.])])
AS_IF([test "$TESTS_LOCALE" = "C"], [
AC_MSG_WARN([Your libc does not have the C.UTF-8 locale and no other
suitable UTF-8 fallback locale could be found. You can still build GJS, but
some tests will fail.])
])
TEST_MSG=
AM_COND_IF([XVFB_TESTS], [TEST_MSG="xvfb "])
AM_COND_IF([DBUS_TESTS], [TEST_MSG="${TEST_MSG}dbus"])
......
gjs (1.56.0-1) experimental; urgency=medium
* New upstream release
* Bump Standards-Version to 4.3.0
* debian/rules: Drop the "Provides=libgjs0-libmozjs-52-0". There aren't any
(currently buildable) references to this left in the archive.
* Update gbp.conf to standard settings.
-- Andrea Azzarone <andrea.azzarone@canonical.com> Thu, 14 Mar 2019 16:19:03 +0000
gjs (1.54.3-1) unstable; urgency=medium
* Team upload
......
......@@ -22,7 +22,7 @@ Build-Depends: debhelper (>= 11),
at-spi2-core <!nocheck>,
xvfb <!nocheck>
Rules-Requires-Root: no
Standards-Version: 4.2.1
Standards-Version: 4.3.0
Vcs-Git: https://salsa.debian.org/gnome-team/gjs.git
Vcs-Browser: https://salsa.debian.org/gnome-team/gjs
Homepage: https://gitlab.gnome.org/GNOME/gjs/wikis
......
......@@ -18,7 +18,7 @@ Build-Depends: debhelper (>= 11),
at-spi2-core <!nocheck>,
xvfb <!nocheck>
Rules-Requires-Root: no
Standards-Version: 4.2.1
Standards-Version: 4.3.0
Vcs-Git: https://salsa.debian.org/gnome-team/gjs.git
Vcs-Browser: https://salsa.debian.org/gnome-team/gjs
Homepage: https://gitlab.gnome.org/GNOME/gjs/wikis
......
......@@ -36,14 +36,3 @@ endif
override_dh_makeshlibs:
dh_makeshlibs -Xusr/lib/gjs-1.0/ -V'libgjs0g (>= $(DEB_VERSION_EPOCH_UPSTREAM))' -- -c4
# We don't actually use mozjs52 any more, but our ABI is compatible with
# the gjs that did.
#
# Yes, this really says libmozjs-52-0. Yes, this is intentional, even
# though we're now building against mozjs60. It's like this to avoid an
# unnecessary transition: programs built against gjs 1.52.x do not need
# to be rebuilt for 1.54.x.
override_dh_gencontrol:
echo gjs:Provides=libgjs0-libmozjs-52-0 >> debian/libgjs0g.substvars
dh_gencontrol
......@@ -2,41 +2,61 @@
## Setting up ##
We use the
[Google style guide](https://google.github.io/styleguide/cppguide.html)
for C++ code, with a few exceptions, 4-space indents being the main one.
There is a handy git commit hook that will autoformat your code when you
commit it.
First of all, if you are contributing C++ code, install the handy git
commit hook that will autoformat your code when you commit it.
In your GJS checkout directory, run
`tools/git-pre-commit-format install`.
For more information, see
<https://github.com/barisione/clang-format-hooks/>.
(You can skip this step if it doesn't work for you, but in that case
you'll need to manually format your code before it gets merged.
You can also skip this step if you are not writing any C++ code.)
For the time being, we recommend using JHBuild to develop GJS.
Follow the [instructions from GNOME](https://wiki.gnome.org/HowDoI/Jhbuild) for [JHBuild](https://git.gnome.org/browse/jhbuild/).
Even if your system includes a development package for mozjs, we
GJS requires four other libraries to be installed: GLib, libffi,
gobject-introspection, and SpiderMonkey (also called "mozjs60" on some
systems.)
The readline library is not required, but strongly recommended.
We recommend installing your system's development packages for libffi
and readline, and building the others with JHBuild.
(For example, on Ubuntu these packages are called `libffi-dev` and
`libreadline-dev`.)
Even if your system includes a development package for SpiderMonkey, we
recommend building it on JHBuild so that you can enable the debugging
features. Add this to your JHBuild configuration file:
features.
Add this to your JHBuild configuration file (usually
`~/.config/jhbuildrc`):
```python
module_autogenargs['mozjs60'] = '--enable-debug'
```
Make sure it is built first with `jhbuild build mozjs60`, otherwise
`jhbuild build gjs` will skip it if you have the system package
installed.
Debugging features in mozjs reduce performance by quite a lot, in
exchange for performing many runtime checks that can alert you when
you're not using the JS API correctly.
These debugging features reduce performance by quite a lot, but they
will help catch mistakes in the API that could otherwise go unnoticed
and cause crashes in gnome-shell later on.
## Making Sure Your Stuff Doesn't Break Anything Else ##
Make your changes in your GJS checkout directory, then run
`jhbuild make` to build a modified copy of GJS.
Each changeset should ensure that the test suite still passes.
In fact, each commit should ensure that the test suite still passes,
though there are some exceptions to this rule.
You can run the test suite with `jhbuild make check`.
For some contributions, it's a good idea to test your modified version
of GJS with GNOME Shell.
For this, build GNOME Shell with `jhbuild build gnome-shell`, and run
it with `jhbuild run gnome-shell --replace`.
You need to be logged into an Xorg session, not Wayland, for this to
work.
## Debugging ##
Mozilla has some pretty-printers that make debugging JSAPI code easier.
......
......@@ -14,17 +14,19 @@ This is a good approach for "embeddable" interpreters, because unlike say the Bo
An object has two forms.
* `JS::Value` is a type-tagged version, think of `GValue` (though it is much more efficient)
* inside a `JS::Value` can be one of: a 32-bit integer, a boolean, a double, a `JSString*`, or a `JSObject*`.
* inside a `JS::Value` can be one of: a 32-bit integer, a boolean, a double, a `JSString*`, a `JS::Symbol*`, or a `JSObject*`.
`JS::Value` is a 64 bits-wide union. Some of the bits are a type tag. However, don't rely on the layout of `JS::Value`, as it may change between API versions.
You check the type tag with the methods `val.isObject()`, `val.isInt32()`, `val.isDouble()`, `val.isString()`, `val.isBoolean()`. Use `val.isNull()` and `val.isUndefined()` rather than comparing `val == JSVAL_NULL` and `val == JSVAL_VOID` to avoid an extra memory access.
You check the type tag with the methods `val.isObject()`, `val.isInt32()`, `val.isDouble()`, `val.isString()`, `val.isBoolean()`, `val.isSymbol()`.
Use `val.isNull()` and `val.isUndefined()` rather than comparing `val == JSVAL_NULL` and `val == JSVAL_VOID` to avoid an extra memory access.
null does not count as an object, so `val.isObject()` does not return true for null. This contrasts with the behavior of `JSVAL_IS_OBJECT(val)`, which was the previous API, but this was changed because the object-or-null behavior was a source of bugs. If you still want this behaviour use `val.isObjectOrNull()`.
The methods `val.toObject()`, `val.toInt32()`, etc. are just accessing the appropriate members of the union.
The jsapi.h header is pretty readable, if you want to learn more. Types you see in there not mentioned above, such as `JSFunction*`, would show up as an object - `val.isObject()` would return true. From a `JS::Value` perspective, everything is one of object, string, double, int, boolean, null, or undefined.
The jsapi.h header is pretty readable, if you want to learn more. Types you see in there not mentioned above, such as `JSFunction*`, would show up as an object - `val.isObject()` would return true.
From a `JS::Value` perspective, everything is one of object, string, symbol, double, int, boolean, null, or undefined.
## Value types vs. allocated types; "gcthing" ##
......@@ -32,17 +34,21 @@ For integers, booleans, doubles, null, and undefined there is no pointer. The va
The importance is: these types just get ignored by the garbage collector.
However, strings and objects are all allocated pointers that get finalized eventually. These are what garbage collection applies to.
However, strings, symbols, and objects are all allocated pointers that get finalized eventually.
These are what garbage collection applies to.
The API refers to these allocated types as "GC things." The macro `val.toGCThing()` returns the value part of the union as a pointer. `val.isGCThing()` returns true for string, object, null; and false for void, boolean, double, integer.
The API refers to these allocated types as "GC things."
The macro `val.toGCThing()` returns the value part of the union as a pointer.
`val.isGCThing()` returns true for string, object, symbol, null; and false for void, boolean, double, integer.
## Tracing ##
The general rule is that SpiderMonkey has a set of GC roots. To do the garbage collection, it finds all objects accessible from those roots, and finalizes all objects that are not.
So if you have a `JS::Value` or `JSObject*`/`JSString*`/`JSFunction*` somewhere that is not reachable from one of SpiderMonkey's GC roots - say, declared on the stack or in the private data of an object - that will not be found. SpiderMonkey may try to finalize this object even though you have a reference to it.
So if you have a `JS::Value` or `JSObject*`/`JSString*`/`JSFunction*`/`JS::Symbol*` somewhere that is not reachable from one of SpiderMonkey's GC roots - say, declared on the stack or in the private data of an object - that will not be found.
SpiderMonkey may try to finalize this object even though you have a reference to it.
If you reference JavaScript objects from your custom object, you have to use `JS::Heap<T>` and set the `JSCLASS_MARK_IS_TRACE` flag in your JSClass, and define a trace function in the class struct. A trace function just invokes `JS_CallHeapValueTracer()`, `JS_CallHeapObjectTracer()`, etc. to tell SpiderMonkey about any objects you reference. See [JSTraceOp docs][2].
If you reference JavaScript objects from your custom object, you have to use `JS::Heap<T>` and set the `JSCLASS_MARK_IS_TRACE` flag in your JSClass, and define a trace function in the class struct. A trace function just invokes `JS::TraceEdge<T>()` to tell SpiderMonkey about any objects you reference. See [JSTraceOp docs][2].
Tracing doesn't add a GC thing to the GC root set!
It just notifies the interpreter that a thing is reachable from another thing.
......
......@@ -70,8 +70,6 @@ A more realistic example would be connecting to a signal on a
method of a prototype:
```js
const Lang = imports.lang;
MyPrototype = {
_init : function() {
fnorb.connect('frobate', this._onFnorbFrobate.bind(this));
......
const ByteArray = imports.byteArray;
const GLib = imports.gi.GLib;
const Gio = imports.gi.Gio;
......@@ -15,7 +16,7 @@ function cat(filename) {
loop.quit();
return;
}
print(contents);
print(ByteArray.toString(contents));
loop.quit();
});
......
This diff is collapsed.
......@@ -28,6 +28,7 @@
#include <glib.h>
#include "gjs/jsapi-util.h"
#include "gjs/macros.h"
#include <girepository.h>
......@@ -43,11 +44,13 @@ typedef enum {
GJS_ARGUMENT_ARRAY_ELEMENT
} GjsArgumentType;
GJS_JSAPI_RETURN_CONVENTION
bool gjs_value_to_arg(JSContext *context,
JS::HandleValue value,
GIArgInfo *arg_info,
GIArgument *arg);
GJS_JSAPI_RETURN_CONVENTION
bool gjs_value_to_explicit_array(JSContext *context,
JS::HandleValue value,
GIArgInfo *arg_info,
......@@ -58,6 +61,7 @@ void gjs_g_argument_init_default (JSContext *context,
GITypeInfo *type_info,
GArgument *arg);
GJS_JSAPI_RETURN_CONVENTION
bool gjs_value_to_g_argument (JSContext *context,
JS::HandleValue value,
GITypeInfo *type_info,
......@@ -67,48 +71,58 @@ bool gjs_value_to_g_argument (JSContext *context,
bool may_be_null,
GArgument *arg);
GJS_JSAPI_RETURN_CONVENTION
bool gjs_value_from_g_argument(JSContext *context,
JS::MutableHandleValue value_p,
GITypeInfo *type_info,
GIArgument *arg,
bool copy_structs);
GJS_JSAPI_RETURN_CONVENTION
bool gjs_value_from_explicit_array(JSContext *context,
JS::MutableHandleValue value_p,
GITypeInfo *type_info,
GIArgument *arg,
int length);
GJS_JSAPI_RETURN_CONVENTION
bool gjs_g_argument_release (JSContext *context,
GITransfer transfer,
GITypeInfo *type_info,
GArgument *arg);
GJS_JSAPI_RETURN_CONVENTION
bool gjs_g_argument_release_out_array (JSContext *context,
GITransfer transfer,
GITypeInfo *type_info,
guint length,
GArgument *arg);
GJS_JSAPI_RETURN_CONVENTION
bool gjs_g_argument_release_in_array (JSContext *context,
GITransfer transfer,
GITypeInfo *type_info,
guint length,
GArgument *arg);
GJS_JSAPI_RETURN_CONVENTION
bool gjs_g_argument_release_in_arg (JSContext *context,
GITransfer transfer,
GITypeInfo *type_info,
GArgument *arg);
GJS_JSAPI_RETURN_CONVENTION
bool _gjs_flags_value_is_valid (JSContext *context,
GType gtype,
gint64 value);
GJS_USE
gint64 _gjs_enum_from_int (GIEnumInfo *enum_info,
int int_value);
GJS_JSAPI_RETURN_CONVENTION
bool gjs_array_from_strv(JSContext *context,
JS::MutableHandleValue value_p,
const char **strv);
GJS_JSAPI_RETURN_CONVENTION
bool gjs_array_to_strv (JSContext *context,
JS::Value array_value,
unsigned int length,
......
This diff is collapsed.
......@@ -24,12 +24,16 @@
#ifndef __GJS_BOXED_H__
#define __GJS_BOXED_H__
#include <stdbool.h>
#include <girepository.h>
#include <glib.h>
#include "gi/wrapperutils.h"
#include "gjs/jsapi-util.h"
#include "gjs/jsapi-wrapper.h"
#include "gjs/macros.h"
#include "util/log.h"
#include <girepository.h>
#include "js/GCHashTable.h"
G_BEGIN_DECLS
......@@ -38,19 +42,195 @@ typedef enum {
GJS_BOXED_CREATION_NO_COPY = (1 << 0)
} GjsBoxedCreationFlags;
/* Hack for now... why doesn't gobject-introspection have this? */
typedef GIStructInfo GIBoxedInfo;
G_END_DECLS
class BoxedPrototype;
class BoxedInstance;
/* To conserve memory, we have two different kinds of private data for GBoxed
* JS wrappers: BoxedInstance, and BoxedPrototype. Both inherit from BoxedBase
* for their common functionality. For more information, see the notes in
* wrapperutils.h.
*/
class BoxedBase
: public GIWrapperBase<BoxedBase, BoxedPrototype, BoxedInstance> {
friend class GIWrapperBase<BoxedBase, BoxedPrototype, BoxedInstance>;
protected:
explicit BoxedBase(BoxedPrototype* proto = nullptr)
: GIWrapperBase(proto) {}
~BoxedBase(void) {}
static const GjsDebugTopic debug_topic = GJS_DEBUG_GBOXED;
static constexpr const char* debug_tag = "GBoxed";
static const struct JSClassOps class_ops;
static const struct JSClass klass;
// JS property accessors
GJS_JSAPI_RETURN_CONVENTION
static bool field_getter(JSContext* cx, unsigned argc, JS::Value* vp);
GJS_JSAPI_RETURN_CONVENTION
static bool field_setter(JSContext* cx, unsigned argc, JS::Value* vp);
// Helper methods that work on either instances or prototypes
GJS_USE const char* to_string_kind(void) const { return "boxed"; }
GJS_JSAPI_RETURN_CONVENTION
GIFieldInfo* get_field_info(JSContext* cx, uint32_t id) const;
public:
GJS_USE
BoxedBase* get_copy_source(JSContext* cx, JS::Value value) const;
};
class BoxedPrototype : public GIWrapperPrototype<BoxedBase, BoxedPrototype,
BoxedInstance, GIStructInfo> {
friend class GIWrapperPrototype<BoxedBase, BoxedPrototype, BoxedInstance,
GIStructInfo>;
friend class GIWrapperBase<BoxedBase, BoxedPrototype, BoxedInstance>;
using FieldMap =
JS::GCHashMap<JS::Heap<JSString*>, GjsAutoFieldInfo,
js::DefaultHasher<JSString*>, js::SystemAllocPolicy>;
int m_zero_args_constructor; // -1 if none
int m_default_constructor; // -1 if none
JS::Heap<jsid> m_default_constructor_name;
FieldMap* m_field_map;
bool m_can_allocate_directly : 1;
explicit BoxedPrototype(GIStructInfo* info, GType gtype);
~BoxedPrototype(void);
GJS_JSAPI_RETURN_CONVENTION bool init(JSContext* cx);
// Accessors
public:
GJS_USE
bool can_allocate_directly(void) const { return m_can_allocate_directly; }
GJS_USE
bool has_zero_args_constructor(void) const {
return m_zero_args_constructor >= 0;
}
GJS_USE
bool has_default_constructor(void) const {
return m_default_constructor >= 0;
}
GJS_USE
GIFunctionInfo* zero_args_constructor_info(void) const {
return g_struct_info_get_method(info(), m_zero_args_constructor);
}
// The ID is traced from the object, so it's OK to create a handle from it.
GJS_USE
JS::HandleId default_constructor_name(void) const {
return JS::HandleId::fromMarkedLocation(
m_default_constructor_name.address());
}
// JSClass operations
private:
GJS_JSAPI_RETURN_CONVENTION
bool resolve_impl(JSContext* cx, JS::HandleObject obj, JS::HandleId id,
const char* prop_name, bool* resolved);
void trace_impl(JSTracer* trc);
// Helper methods
GJS_JSAPI_RETURN_CONVENTION
static FieldMap* create_field_map(JSContext* cx, GIStructInfo* struct_info);
GJS_JSAPI_RETURN_CONVENTION
bool ensure_field_map(JSContext* cx);
public:
GJS_JSAPI_RETURN_CONVENTION
bool define_boxed_class_fields(JSContext* cx, JS::HandleObject proto);
GJS_JSAPI_RETURN_CONVENTION
GIFieldInfo* lookup_field(JSContext* cx, JSString* prop_name);
};
class BoxedInstance
: public GIWrapperInstance<BoxedBase, BoxedPrototype, BoxedInstance> {
friend class GIWrapperInstance<BoxedBase, BoxedPrototype, BoxedInstance>;
friend class GIWrapperBase<BoxedBase, BoxedPrototype, BoxedInstance>;
friend class BoxedBase; // for field_getter, etc.
bool m_allocated_directly : 1;
bool m_not_owning_ptr : 1; // if set, the JS wrapper does not own the C
// memory referred to by m_ptr.
explicit BoxedInstance(JSContext* cx, JS::HandleObject obj);
~BoxedInstance(void);
// Methods for different ways to allocate the GBoxed pointer
void allocate_directly(void);
void copy_boxed(void* boxed_ptr);
void copy_boxed(BoxedInstance* source);
void copy_memory(void* boxed_ptr);
void copy_memory(BoxedInstance* source);
// Helper methods
GJS_JSAPI_RETURN_CONVENTION
bool init_from_props(JSContext* cx, JSObject* obj, JS::Value props_value);
GJS_JSAPI_RETURN_CONVENTION
bool get_nested_interface_object(JSContext* cx, JSObject* parent_obj,
GIFieldInfo* field_info,
GIBaseInfo* interface_info,
JS::MutableHandleValue value) const;
GJS_JSAPI_RETURN_CONVENTION
bool set_nested_interface_object(JSContext* cx, GIFieldInfo* field_info,
GIBaseInfo* interface_info,
JS::HandleValue value);
// JS property accessors
GJS_JSAPI_RETURN_CONVENTION
bool field_getter_impl(JSContext* cx, JSObject* obj, GIFieldInfo* info,
JS::MutableHandleValue rval) const;
GJS_JSAPI_RETURN_CONVENTION
bool field_setter_impl(JSContext* cx, GIFieldInfo* info,
JS::HandleValue value);
// JS constructor
GJS_JSAPI_RETURN_CONVENTION
bool constructor_impl(JSContext* cx, JS::HandleObject obj,
const JS::CallArgs& args);
// Public API for initializing BoxedInstance JS object from C struct
public:
struct NoCopy {};
GJS_JSAPI_RETURN_CONVENTION
bool init_from_c_struct(JSContext* cx, void* gboxed);
GJS_JSAPI_RETURN_CONVENTION
bool init_from_c_struct(JSContext* cx, void* gboxed, NoCopy);
};
G_BEGIN_DECLS
void gjs_define_boxed_class (JSContext *context,
JS::HandleObject in_object,
GIBoxedInfo *info);
GJS_JSAPI_RETURN_CONVENTION
bool gjs_define_boxed_class(JSContext* cx, JS::HandleObject in_object,
GIStructInfo* info);
GJS_JSAPI_RETURN_CONVENTION
void* gjs_c_struct_from_boxed (JSContext *context,
JS::HandleObject obj);
GJS_JSAPI_RETURN_CONVENTION
JSObject* gjs_boxed_from_c_struct (JSContext *context,
GIStructInfo *info,
void *gboxed,
GjsBoxedCreationFlags flags);
GJS_USE
bool gjs_typecheck_boxed (JSContext *context,
JS::HandleObject obj,
GIStructInfo *expected_info,
......
......@@ -30,11 +30,11 @@
#include "closure.h"
#include "gjs/jsapi-util-root.h"
#include "gjs/jsapi-wrapper.h"
#include "gjs/mem.h"
#include "gjs/mem-private.h"
struct Closure {
JSContext *context;
GjsMaybeOwned<JSObject *> obj;
GjsMaybeOwned<JSFunction*> func;
};
struct GjsClosure {
......@@ -86,10 +86,10 @@ invalidate_js_pointers(GjsClosure *gc)
c = &gc->priv;
if (c->obj == nullptr)
if (!c->func)
return;
c->obj.reset();
c->func.reset();
c->context = NULL;
/* Notify any closure reference holders they
......@@ -98,19 +98,17 @@ invalidate_js_pointers(GjsClosure *gc)
g_closure_invalidate(&gc->base);
}
static void
global_context_finalized(JS::HandleObject obj,
void *data)
{
static void global_context_finalized(JS::HandleFunction func, void* data) {
GjsClosure *gc = (GjsClosure*) data;
Closure *c = &gc->priv;
gjs_debug_closure("Context global object destroy notifier on closure %p "
"which calls object %p",
c, c->obj.get());
gjs_debug_closure(
"Context global object destroy notifier on closure %p which calls "
"object %p",
c, c->func.debug_addr());
if (c->obj) {
g_assert(c->obj == obj.get());
if (c->func) {
g_assert(c->func == func.get());
invalidate_js_pointers(gc);
}
......@@ -136,10 +134,10 @@ closure_invalidated(gpointer data,
c = &((GjsClosure*) closure)->priv;
GJS_DEC_COUNTER(closure);
gjs_debug_closure("Invalidating closure %p which calls object %p",
closure, c->obj.get());
gjs_debug_closure("Invalidating closure %p which calls function %p",
closure, c->func.debug_addr());
if (c->obj == nullptr) {
if (!c->func) {
gjs_debug_closure(" (closure %p already dead, nothing to do)",
closure);
return;
......@@ -156,7 +154,7 @@ closure_invalidated(gpointer data,
"removing our destroy notifier on global object)",
closure);
c->obj.reset();
c->func.reset();
c->context = nullptr;
}
......@@ -166,11 +164,11 @@ closure_set_invalid(gpointer data,
{
Closure *self = &((GjsClosure*) closure)->priv;
gjs_debug_closure("Invalidating signal closure %p which calls object %p",
closure, self->obj.get());
gjs_debug_closure("Invalidating signal closure %p which calls function %p",
closure, self->func.debug_addr());
self->obj.prevent_collection();
self->obj.reset();
self->func.prevent_collection();
self->func.reset();
self->context = nullptr;
GJS_DEC_COUNTER(closure);
......@@ -197,7 +195,7 @@ gjs_closure_invoke(GClosure *closure,
c = &((GjsClosure*) closure)->priv;
if (c->obj == nullptr) {
if (!c->func) {
/* We were destroyed; become a no-op */
c->context = NULL;
return false;
......@@ -205,7 +203,7 @@ gjs_closure_invoke(GClosure *closure,
context = c->context;
JSAutoRequest ar(context);
JSAutoCompartment ac(context, c->obj);
JSAutoCompartment ac(context, JS_GetFunctionObject(c->func));
if (JS_IsExceptionPending(context)) {
gjs_debug_closure("Exception was pending before invoking callback??? "
......@@ -213,12 +211,13 @@ gjs_closure_invoke(GClosure *closure,
gjs_log_exception(context);
}
JS::RootedValue v_closure(context, JS::ObjectValue(*c->obj));
if (!gjs_call_function_value(context, this_obj, v_closure, args, retval)) {
JS::RootedFunction func(context, c->func);
if (!JS::Call(context, this_obj, func, args, retval)) {
/* Exception thrown... */
gjs_debug_closure("Closure invocation failed (exception should "
"have been thrown) closure %p callable %p",
closure, c->obj.get());
gjs_debug_closure(
"Closure invocation failed (exception should have been thrown) "
"closure %p function %p",
closure, c->func.debug_addr());
/* If an exception has been thrown, log it, unless the caller
* explicitly wants to handle it manually (for example to turn it
* into a GError), in which case it replaces the return value
......@@ -241,7 +240,8 @@ gjs_closure_invoke(GClosure *closure,
" - closure %p", closure);
}
JS_MaybeGC(context);
GjsContextPrivate* gjs = GjsContextPrivate::from_cx(context);
gjs->schedule_gc_if_needed();
return true;
}
......@@ -265,14 +265,12 @@ gjs_closure_get_context(GClosure *closure)
return c->context;
}
JSObject*
gjs_closure_get_callable(GClosure *closure)
{
JSFunction* gjs_closure_get_callable(GClosure* closure) {
Closure *c;
c = &((GjsClosure*) closure)->priv;
return c->obj;
return c->func;
}
void
......@@ -283,18 +281,14 @@ gjs_closure_trace(GClosure *closure,
c = &((GjsClosure*) closure)->priv;
if (c->obj == nullptr)
if (!c->func)
return;
c->obj.trace(tracer, "signal connection");
c->func.trace(tracer, "signal connection");
}
GClosure*
gjs_closure_new(JSContext *context,
JSObject *callable,
const char *description,
bool root_function)
{
GClosure* gjs_closure_new(JSContext* context, JSFunction* callable,
const char* description, bool root_function) {
GjsClosure *gc;
Closure *c;
......@@ -313,11 +307,11 @@ gjs_closure_new(JSContext *context,
if (root_function) {
/* Fully manage closure lifetime if so asked */
c->obj.root(context, callable, global_context_finalized, gc);
c->func.root(context, callable, global_context_finalized, gc);
g_closure_add_invalidate_notifier(&gc->base, NULL, closure_invalidated);
} else {
c->obj = callable;
c->func = callable;
/* Only mark the closure as invalid if memory is managed
outside (i.e. by object.c for signals) */
g_closure_add_invalidate_notifier(&gc->base, NULL, closure_set_invalid);
......@@ -325,8 +319,8 @@ gjs_closure_new(JSContext *context,
g_closure_add_finalize_notifier(&gc->base, NULL, closure_finalize);
gjs_debug_closure("Create closure %p which calls object %p '%s'",
gc, c->obj.get(), description);
gjs_debug_closure("Create closure %p which calls function %p '%s'", gc,
c->func.debug_addr(), description);
JS_EndRequest(context);
......
......@@ -28,23 +28,27 @@
#include <glib-object.h>
#include "gjs/jsapi-util.h"
#include "gjs/macros.h"
G_BEGIN_DECLS
GClosure* gjs_closure_new (JSContext *context,
JSObject *callable,
const char *description,
bool root_function);
GJS_USE
GClosure* gjs_closure_new(JSContext* cx, JSFunction* callable,
const char* description, bool root_function);
GJS_USE
bool gjs_closure_invoke(GClosure *closure,
JS::HandleObject this_obj,
const JS::HandleValueArray& args,
JS::MutableHandleValue retval,
bool return_exception);
GJS_USE
JSContext* gjs_closure_get_context (GClosure *closure);
GJS_USE
bool gjs_closure_is_valid (GClosure *closure);
JSObject* gjs_closure_get_callable (GClosure *closure);
GJS_USE
JSFunction* gjs_closure_get_callable(GClosure* closure);
void gjs_closure_trace (GClosure *closure,
JSTracer *tracer);
......
......@@ -25,10 +25,12 @@
#include <string.h>
#include "function.h"
#include "gi/wrapperutils.h"
#include "gjs/context-private.h"
#include "gjs/jsapi-wrapper.h"
#include "repo.h"
#include "gtype.h"
#include "function.h"
#include "repo.h"
#include <util/log.h>
......@@ -36,6 +38,7 @@
#include "enumeration.h"
GJS_JSAPI_RETURN_CONVENTION
static bool
gjs_define_enum_value(JSContext *context,
JS::HandleObject in_object,
......@@ -83,7 +86,6 @@ gjs_define_enum_values(JSContext *context,
JS::HandleObject in_object,
GIEnumInfo *info)
{
GType gtype;
int i, n_values;
/* Fill in enum values first, so we don't define the enum itself until we're
......@@ -102,47 +104,6 @@ gjs_define_enum_values(JSContext *context,
return false;
}
}
gtype = g_registered_type_info_get_g_type((GIRegisteredTypeInfo*)info);
JS::RootedObject gtype_obj(context,
gjs_gtype_create_gtype_wrapper(context, gtype));
JS_DefineProperty(context, in_object, "$gtype", gtype_obj, JSPROP_PERMANENT);
return true;
}
bool
gjs_define_enum_static_methods(JSContext *context,
JS::HandleObject constructor,
GIEnumInfo *enum_info)
{
int i, n_methods;
n_methods = g_enum_info_get_n_methods(enum_info);
for (i = 0; i < n_methods; i++) {
GIFunctionInfo *meth_info;
GIFunctionInfoFlags flags;
meth_info = g_enum_info_get_method(enum_info, i);
flags = g_function_info_get_flags(meth_info);
g_warn_if_fail(!(flags & GI_FUNCTION_IS_METHOD));
/* Anything that isn't a method we put on the prototype of the
* constructor. This includes <constructor> introspection
* methods, as well as the forthcoming "static methods"
* support. We may want to change this to use
* GI_FUNCTION_IS_CONSTRUCTOR and GI_FUNCTION_IS_STATIC or the
* like in the near future.
*/
if (!(flags & GI_FUNCTION_IS_METHOD)) {
gjs_define_function(context, constructor, G_TYPE_NONE,
(GICallableInfo *)meth_info);
}
g_base_info_unref((GIBaseInfo*) meth_info);
}
return true;
}
......@@ -166,14 +127,18 @@ gjs_define_enumeration(JSContext *context,
JS::RootedObject enum_obj(context, JS_NewPlainObject(context));
if (!enum_obj) {
g_error("Could not create enumeration %s.%s",
g_base_info_get_namespace( (GIBaseInfo*) info),
enum_name);
gjs_throw(context, "Could not create enumeration %s.%s",
g_base_info_get_namespace(info), enum_name);
return false;
}
if (!gjs_define_enum_values(context, enum_obj, info))
GType gtype = g_registered_type_info_get_g_type(info);
if (!gjs_define_enum_values(context, enum_obj, info) ||
!gjs_define_static_methods<InfoType::Enum>(context, enum_obj, gtype,
info) ||
!gjs_wrapper_define_gtype_prop(context, enum_obj, gtype))
return false;
gjs_define_enum_static_methods (context, enum_obj, info);
gjs_debug(GJS_DEBUG_GENUM,
"Defining %s.%s as %p",
......
......@@ -28,19 +28,18 @@
#include <glib.h>
#include "gjs/jsapi-util.h"
#include "gjs/macros.h"
#include <girepository.h>
G_BEGIN_DECLS
GJS_JSAPI_RETURN_CONVENTION
bool gjs_define_enum_values(JSContext *context,
JS::HandleObject in_object,
GIEnumInfo *info);
bool gjs_define_enum_static_methods(JSContext *context,
JS::HandleObject constructor,
GIEnumInfo *enum_info);
GJS_JSAPI_RETURN_CONVENTION
bool gjs_define_enumeration(JSContext *context,
JS::HandleObject in_object,
GIEnumInfo *info);
......
......@@ -28,6 +28,7 @@
#include "arg.h"
#include "foreign.h"
#include "gjs/context-private.h"
#include "gjs/jsapi-wrapper.h"
static struct {
......@@ -41,6 +42,7 @@ static struct {
static GHashTable* foreign_structs_table = NULL;
GJS_USE
static GHashTable*
get_foreign_structs(void)
{
......@@ -54,6 +56,7 @@ get_foreign_structs(void)
return foreign_structs_table;
}
GJS_USE
static bool
gjs_foreign_load_foreign_module(JSContext *context,
const gchar *gi_namespace)
......@@ -73,8 +76,9 @@ gjs_foreign_load_foreign_module(JSContext *context,
// and only execute this statement if isn't
script = g_strdup_printf("imports.%s;", gi_namespace);
JS::RootedValue retval(context);
if (!gjs_eval_with_scope(context, nullptr, script, strlen(script),
"<internal>", &retval)) {
GjsContextPrivate* gjs = GjsContextPrivate::from_cx(context);
if (!gjs->eval_with_scope(nullptr, script, strlen(script), "<internal>",
&retval)) {
g_critical("ERROR importing foreign module %s\n", gi_namespace);
g_free(script);
return false;
......@@ -87,22 +91,19 @@ gjs_foreign_load_foreign_module(JSContext *context,
return false;
}
bool
gjs_struct_foreign_register(const char *gi_namespace,
const char *type_name,
GjsForeignInfo *info)
{
void gjs_struct_foreign_register(const char* gi_namespace,
const char* type_name, GjsForeignInfo* info) {
char *canonical_name;
g_return_val_if_fail(info != NULL, false);
g_return_val_if_fail(info->to_func != NULL, false);
g_return_val_if_fail(info->from_func != NULL, false);
g_return_if_fail(info);
g_return_if_fail(info->to_func);
g_return_if_fail(info->from_func);
canonical_name = g_strdup_printf("%s.%s", gi_namespace, type_name);
g_hash_table_insert(get_foreign_structs(), canonical_name, info);
return true;
}
GJS_USE
static GjsForeignInfo *
gjs_struct_foreign_lookup(JSContext *context,
GIBaseInfo *interface_info)
......
......@@ -26,8 +26,9 @@
#include <stdbool.h>
#include <girepository.h>
#include <gjs/gjs.h>
#include "arg.h"
#include "gjs/macros.h"
typedef bool (*GjsArgOverrideToGArgumentFunc) (JSContext *context,
JS::Value value,
......@@ -51,10 +52,10 @@ typedef struct {
GjsArgOverrideReleaseGArgumentFunc release_func;
} GjsForeignInfo;
bool gjs_struct_foreign_register (const char *gi_namespace,
const char *type_name,
GjsForeignInfo *info);
void gjs_struct_foreign_register(const char* gi_namespace,
const char* type_name, GjsForeignInfo* info);
GJS_JSAPI_RETURN_CONVENTION
bool gjs_struct_foreign_convert_to_g_argument (JSContext *context,
JS::Value value,
GIBaseInfo *interface_info,
......@@ -63,11 +64,13 @@ bool gjs_struct_foreign_convert_to_g_argument (JSContext *context,