[gjs/wip/ptomato/mozjs31: 1/3] js: Call JS_Init() and JS_ShutDown()



commit ddb0b23064f5a0637229808a01eca4299f84780e
Author: Philip Chimento <philip endlessm com>
Date:   Fri Nov 4 19:02:55 2016 -0700

    js: Call JS_Init() and JS_ShutDown()
    
    Starting with mozjs31, JS_Init() is required. Calling JS_ShutDown() on
    exit is not required, but may become so in the future.
    
    This makes two new public functions in the API which do the necessary
    initialization and shutdown, because gnome-shell will need to call them
    as well.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=751252

 Makefile-insttest.am                      |    6 ----
 Makefile.am                               |    5 ++-
 NEWS                                      |   20 +++++++++++++++
 gjs/console.cpp                           |    7 +++-
 gjs/context-private.h                     |    3 --
 gjs/context.cpp                           |   39 +++++++++++++++++++++++++---
 gjs/context.h                             |    3 ++
 gjs/gjs.h                                 |    1 +
 installed-tests/gjs-unit.cpp              |    4 +++
 installed-tests/scripts/testSystemExit.js |    3 --
 test/gjs-tests.cpp                        |   29 +++++++++++++++++++++
 util/error.h                              |    3 +-
 12 files changed, 101 insertions(+), 22 deletions(-)
---
diff --git a/Makefile-insttest.am b/Makefile-insttest.am
index bb13b6b..4e2c78a 100644
--- a/Makefile-insttest.am
+++ b/Makefile-insttest.am
@@ -178,7 +178,6 @@ EXTRA_DIST +=                                               \
        installed-tests/js/testCairo.js                 \
        installed-tests/js/testGtk.js                   \
        installed-tests/js/testGDBus.js                 \
-       installed-tests/scripts/testSystemExit.js       \
        $(NULL)
 
 if BUILDOPT_INSTALL_TESTS
@@ -205,9 +204,4 @@ endif
                < $(srcdir)/installed-tests/script.test.in > $@.tmp && \
        mv $@.tmp $@
 
-jsscripttestsdir = $(gjsinsttestdir)/scripts
-jsscripttests_DATA = installed-tests/scripts/testSystemExit.js
-installedtestmeta_DATA += testSystemExit.test
 endif
-
-MAINTAINERCLEANFILES += testSystemExit.test
diff --git a/Makefile.am b/Makefile.am
index c0df6c2..ae1cf6e 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -34,7 +34,9 @@ gjs_public_includedir = $(includedir)/gjs-1.0
 ########################################################################
 nobase_gjs_public_include_HEADERS =    \
        gjs/context.h           \
-       gjs/gjs.h
+       gjs/gjs.h                       \
+       util/error.h                    \
+       $(NULL)
 
 ########################################################################
 pkgconfig_DATA = gjs-1.0.pc
@@ -93,7 +95,6 @@ libgjs_la_SOURCES =           \
        modules/modules.cpp     \
        modules/modules.h       \
        util/error.cpp          \
-       util/error.h                    \
        util/hash-x32.cpp               \
        util/hash-x32.h                 \
        util/glib.cpp           \
diff --git a/NEWS b/NEWS
index aaaefc2..ff5d26d 100644
--- a/NEWS
+++ b/NEWS
@@ -54,6 +54,26 @@ NEXT
   arguments into account for the time being, while still passing them on to the
   script. A warning will be logged if you are using the deprecated behaviour.
 
+- News for GJS embedders such as gnome-shell:
+
+  * New API: gjs_error_quark() is now exposed, and the error domain GJS_ERROR
+    and codes GJS_ERROR_FAILED and GJS_ERROR_SYSTEM_EXIT.
+
+  * Backwards-incompatible change: You must now call gjs_init() before calling
+    any other GJS functions, and call gjs_shutdown() after you release your last
+    reference to a GjsContext.
+
+    Calling System.exit() from JS code will now not abort the program
+    immediately, but instead will return immediately from gjs_context_eval() so
+    that you can unref your GjsContext and call gjs_shutdown().
+
+    If gjs_context_eval() or gjs_context_eval_file() returns an error with code
+    GJS_ERROR_SYSTEM_EXIT, it means that the JS code called System.exit(). The
+    exit code will be found in the 'exit_status_p' out parameter to
+    gjs_context_eval() or gjs_context_eval_file(). If you receive this error,
+    you should do any cleanup needed (including gjs_shutdown()) and exit your
+    program with the given exit code.
+
 Version 1.46.0
 --------------
 
diff --git a/gjs/console.cpp b/gjs/console.cpp
index d60840b..e0214a9 100644
--- a/gjs/console.cpp
+++ b/gjs/console.cpp
@@ -242,6 +242,8 @@ main(int argc, char **argv)
     /* This should be removed after a suitable time has passed */
     check_script_args_for_stray_gjs_args(script_argc, script_argv);
 
+    gjs_init();
+
     js_context = (GjsContext*) g_object_new(GJS_TYPE_CONTEXT,
                                             "search-path", include_path,
                                             "program-name", program_name,
@@ -290,8 +292,8 @@ main(int argc, char **argv)
     /* evaluate the script */
     if (!gjs_context_eval(js_context, script, len,
                           filename, &code, &error)) {
-        code = 1;
-        g_printerr("%s\n", error->message);
+        if (!g_error_matches(error, GJS_ERROR, GJS_ERROR_SYSTEM_EXIT))
+            g_printerr("%s\n", error->message);
         g_clear_error(&error);
         goto out;
     }
@@ -308,5 +310,6 @@ main(int argc, char **argv)
     g_strfreev(coverage_prefixes);
     g_object_unref(js_context);
     g_free(script);
+    gjs_shutdown();
     exit(code);
 }
diff --git a/gjs/context-private.h b/gjs/context-private.h
index 045909f..5b24b77 100644
--- a/gjs/context-private.h
+++ b/gjs/context-private.h
@@ -37,9 +37,6 @@ void         _gjs_context_schedule_gc_if_needed       (GjsContext *js_context);
 void _gjs_context_exit(GjsContext *js_context,
                        uint8_t     exit_code);
 
-bool _gjs_context_should_exit(GjsContext *js_context,
-                              uint8_t    *exit_code_p);
-
 G_END_DECLS
 
 #endif  /* __GJS_CONTEXT_PRIVATE_H__ */
diff --git a/gjs/context.cpp b/gjs/context.cpp
index 5c8c267..2805d03 100644
--- a/gjs/context.cpp
+++ b/gjs/context.cpp
@@ -568,15 +568,22 @@ _gjs_context_exit(GjsContext *js_context,
     js_context->exit_code = exit_code;
 }
 
-bool
-_gjs_context_should_exit(GjsContext *js_context,
-                         uint8_t    *exit_code_p)
+static bool
+context_should_exit(GjsContext *js_context,
+                    uint8_t    *exit_code_p)
 {
     if (exit_code_p != NULL)
         *exit_code_p = js_context->exit_code;
     return js_context->should_exit;
 }
 
+static void
+context_reset_exit(GjsContext *js_context)
+{
+    js_context->should_exit = false;
+    js_context->exit_code = 0;
+}
+
 /**
  * gjs_context_maybe_gc:
  * @context: a #GjsContext
@@ -671,14 +678,22 @@ gjs_context_eval(GjsContext   *js_context,
     if (!gjs_eval_with_scope(js_context->context, JS::NullPtr(), script,
                              script_len, filename, &retval)) {
         uint8_t code;
-        if (_gjs_context_should_exit(js_context, &code))
-            exit(code);
+        if (context_should_exit(js_context, &code)) {
+            /* exit_status_p is public API so can't be changed, but should be
+             * uint8_t, not int */
+            *exit_status_p = code;
+            g_set_error(error, GJS_ERROR, GJS_ERROR_SYSTEM_EXIT,
+                        "Exit with code %d", code);
+            goto out;  /* Don't log anything */
+        }
 
         gjs_log_exception(js_context->context);
         g_set_error(error,
                     GJS_ERROR,
                     GJS_ERROR_FAILED,
                     "JS_EvaluateScript() failed");
+        /* No exit code from script, but we don't want to exit(0) */
+        *exit_status_p = 1;
         goto out;
     }
 
@@ -698,6 +713,7 @@ gjs_context_eval(GjsContext   *js_context,
 
  out:
     g_object_unref(G_OBJECT(js_context));
+    context_reset_exit(js_context);
     return ret;
 }
 
@@ -819,3 +835,16 @@ gjs_get_import_global(JSContext *context)
     GjsContext *gjs_context = (GjsContext *) JS_GetContextPrivate(context);
     return gjs_context->global;
 }
+
+void
+gjs_init(void)
+{
+    if (!JS_Init())
+        g_error("Could not initialize Javascript");
+}
+
+void
+gjs_shutdown(void)
+{
+    JS_ShutDown();
+}
diff --git a/gjs/context.h b/gjs/context.h
index a459e5b..cf6c55d 100644
--- a/gjs/context.h
+++ b/gjs/context.h
@@ -76,6 +76,9 @@ void            gjs_context_maybe_gc              (GjsContext  *context);
 
 void            gjs_context_gc                    (GjsContext  *context);
 
+void gjs_init(void);
+void gjs_shutdown(void);
+
 void            gjs_dumpstack                     (void);
 
 G_END_DECLS
diff --git a/gjs/gjs.h b/gjs/gjs.h
index b2a32f2..5cb1810 100644
--- a/gjs/gjs.h
+++ b/gjs/gjs.h
@@ -25,5 +25,6 @@
 #define __GJS_GJS_H__
 
 #include <gjs/context.h>
+#include <util/error.h>
 
 #endif /* __GJS_GJS_H__ */
diff --git a/installed-tests/gjs-unit.cpp b/installed-tests/gjs-unit.cpp
index 034273f..29b41ae 100644
--- a/installed-tests/gjs-unit.cpp
+++ b/installed-tests/gjs-unit.cpp
@@ -164,6 +164,8 @@ main(int argc, char **argv)
     setlocale(LC_ALL, "");
     g_test_init(&argc, &argv, NULL);
 
+    gjs_init();
+
     /* Make sure to create the GjsContext class first, so we
      * can override the GjsPrivate lookup path.
      */
@@ -218,5 +220,7 @@ main(int argc, char **argv)
 
     g_type_class_unref (context_class);
 
+    gjs_shutdown();
+
     return retval;
 }
diff --git a/test/gjs-tests.cpp b/test/gjs-tests.cpp
index 64e9d96..24c8665 100644
--- a/test/gjs-tests.cpp
+++ b/test/gjs-tests.cpp
@@ -30,6 +30,7 @@
 #include "gjs/jsapi-util.h"
 #include "gjs/jsapi-wrapper.h"
 #include "gjs-test-utils.h"
+#include "util/error.h"
 
 static void
 gjstest_test_func_gjs_context_construct_destroy(void)
@@ -59,6 +60,31 @@ gjstest_test_func_gjs_context_construct_eval(void)
     g_object_unref (context);
 }
 
+static void
+gjstest_test_func_gjs_context_exit(void)
+{
+    GjsContext *context = gjs_context_new();
+    GError *error = NULL;
+    int status;
+
+    bool ok = gjs_context_eval(context, "imports.system.exit(0);", -1,
+                               "<input>", &status, &error);
+    g_assert_false(ok);
+    g_assert_error(error, GJS_ERROR, GJS_ERROR_SYSTEM_EXIT);
+    g_assert_cmpuint(status, ==, 0);
+
+    g_clear_error(&error);
+
+    ok = gjs_context_eval(context, "imports.system.exit(42);", -1, "<input>",
+                          &status, &error);
+    g_assert_false(ok);
+    g_assert_error(error, GJS_ERROR, GJS_ERROR_SYSTEM_EXIT);
+    g_assert_cmpuint(status, ==, 42);
+
+    g_clear_error(&error);
+    g_object_unref(context);
+}
+
 #define JS_CLASS "\
 const Lang    = imports.lang; \
 const GObject = imports.gi.GObject; \
@@ -251,6 +277,7 @@ main(int    argc,
 
     g_test_add_func("/gjs/context/construct/destroy", gjstest_test_func_gjs_context_construct_destroy);
     g_test_add_func("/gjs/context/construct/eval", gjstest_test_func_gjs_context_construct_eval);
+    g_test_add_func("/gjs/context/exit", gjstest_test_func_gjs_context_exit);
     g_test_add_func("/gjs/gobject/js_defined_type", gjstest_test_func_gjs_gobject_js_defined_type);
     g_test_add_func("/gjs/jsutil/strip_shebang/no_shebang", 
gjstest_test_strip_shebang_no_advance_for_no_shebang);
     g_test_add_func("/gjs/jsutil/strip_shebang/have_shebang", 
gjstest_test_strip_shebang_advance_for_shebang);
@@ -273,7 +300,9 @@ main(int    argc,
     gjs_test_add_tests_for_coverage ();
     gjs_test_add_tests_for_parse_call_args();
 
+    gjs_init();
     g_test_run();
+    gjs_shutdown();
 
     return 0;
 }
diff --git a/util/error.h b/util/error.h
index 85b2cb6..01fa96b 100644
--- a/util/error.h
+++ b/util/error.h
@@ -32,7 +32,8 @@ GQuark gjs_error_quark(void);
 #define GJS_ERROR gjs_error_quark()
 
 typedef enum {
-    GJS_ERROR_FAILED
+    GJS_ERROR_FAILED,
+    GJS_ERROR_SYSTEM_EXIT,
 } GjsError;
 
 G_END_DECLS


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]