[gjs] global: Add a bootstrap system



commit 881e6b2e8e01f445abd8a347d37f3664a90431ca
Author: Philip Chimento <philip chimento gmail com>
Date:   Sat Sep 9 17:13:24 2017 -0700

    global: Add a bootstrap system
    
    Based on a patch by Jasper St. Pierre. This allows executing a JS script
    (which must be a resource in the directory
    resource:///org/gnome/gjs/modules/_bootstrap) in order to define extra
    properties on a global object when the global object is created.
    
    This is currently not used for anything, but will be used for the code
    coverage compartment, and likely for a debugger as well. It can also be
    used to implement things in JS that are currently implemented in C++,
    like the log() and logError() functions.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=777724

 gjs/context.cpp               |    2 +-
 gjs/coverage.cpp              |    3 +-
 gjs/global.cpp                |   64 ++++++++++++++++++++++++++++++++++++----
 gjs/global.h                  |    3 +-
 modules/_bootstrap/default.js |    7 ++++
 modules/modules.gresource.xml |    2 +
 6 files changed, 71 insertions(+), 10 deletions(-)
---
diff --git a/gjs/context.cpp b/gjs/context.cpp
index c105118..0aaa686 100644
--- a/gjs/context.cpp
+++ b/gjs/context.cpp
@@ -342,7 +342,7 @@ gjs_context_constructed(GObject *object)
 
     gjs_set_global_slot(cx, GJS_GLOBAL_SLOT_IMPORTS, JS::ObjectValue(*importer));
 
-    if (!gjs_define_global_properties(cx, global)) {
+    if (!gjs_define_global_properties(cx, global, "default")) {
         gjs_log_exception(cx);
         g_error("Failed to define properties on global object");
     }
diff --git a/gjs/coverage.cpp b/gjs/coverage.cpp
index b40e618..4f9c7f2 100644
--- a/gjs/coverage.cpp
+++ b/gjs/coverage.cpp
@@ -1574,7 +1574,8 @@ bootstrap_coverage(GjsCoverage *coverage)
             return false;
         }
 
-        if (!gjs_define_global_properties(context, debugger_compartment)) {
+        if (!gjs_define_global_properties(context, debugger_compartment,
+                                          "default")) {
             gjs_throw(context, "Failed to define global properties on debugger "
                       "compartment");
             return false;
diff --git a/gjs/global.cpp b/gjs/global.cpp
index 7d41273..4ff2465 100644
--- a/gjs/global.cpp
+++ b/gjs/global.cpp
@@ -31,6 +31,41 @@
 #include "jsapi-wrapper.h"
 
 static bool
+run_bootstrap(JSContext       *cx,
+              const char      *bootstrap_script,
+              JS::HandleObject global)
+{
+    GjsAutoChar path = g_strdup_printf("/org/gnome/gjs/modules/_bootstrap/%s.js",
+                                       bootstrap_script);
+    GError *error = nullptr;
+    std::unique_ptr<GBytes, decltype(&g_bytes_unref)> script_bytes(
+        g_resources_lookup_data(path, G_RESOURCE_LOOKUP_FLAGS_NONE, &error),
+        g_bytes_unref);
+    if (!script_bytes) {
+        gjs_throw_g_error(cx, error);
+        return false;
+    }
+
+    JSAutoCompartment ac(cx, global);
+
+    GjsAutoChar uri = g_strconcat("resource://", path.get(), nullptr);
+    JS::CompileOptions options(cx);
+    options.setUTF8(true)
+           .setFileAndLine(uri, 1)
+           .setSourceIsLazy(true);
+
+    JS::RootedScript compiled_script(cx);
+    size_t script_len;
+    auto script = static_cast<const char *>(g_bytes_get_data(script_bytes.get(),
+                                            &script_len));
+    if (!JS::Compile(cx, options, script, script_len, &compiled_script))
+        return false;
+
+    JS::RootedValue ignored(cx);
+    return JS::CloneAndExecuteScript(cx, compiled_script, &ignored);
+}
+
+static bool
 gjs_log(JSContext *cx,
         unsigned   argc,
         JS::Value *vp)
@@ -225,7 +260,8 @@ public:
 
     static bool
     define_properties(JSContext       *cx,
-                      JS::HandleObject global)
+                      JS::HandleObject global,
+                      const char      *bootstrap_script)
     {
         if (!JS_DefineProperty(cx, global, "window", global,
                                JSPROP_READONLY | JSPROP_PERMANENT) ||
@@ -240,9 +276,17 @@ public:
 
         /* Wrapping is a no-op if the importer is already in the same
          * compartment. */
-        return JS_WrapObject(cx, &root_importer) &&
-            gjs_object_define_property(cx, global, GJS_STRING_IMPORTS,
-                                       root_importer, GJS_MODULE_PROP_FLAGS);
+        if (!JS_WrapObject(cx, &root_importer) ||
+            !gjs_object_define_property(cx, global, GJS_STRING_IMPORTS,
+                                        root_importer, GJS_MODULE_PROP_FLAGS))
+            return false;
+
+        if (bootstrap_script) {
+            if (!run_bootstrap(cx, bootstrap_script, global))
+                return false;
+        }
+
+        return true;
     }
 };
 
@@ -265,8 +309,13 @@ gjs_create_global_object(JSContext *cx)
  * gjs_define_global_properties:
  * @cx: a #JSContext
  * @global: a JS global object that has not yet been passed to this function
+ * @bootstrap_script: (nullable): name of a bootstrap script (found at
+ * resource://org/gnome/gjs/modules/_bootstrap/@bootstrap_script) or %NULL for
+ * none
  *
- * Defines properties on the global object such as 'window' and 'imports'.
+ * Defines properties on the global object such as 'window' and 'imports', and
+ * runs a bootstrap JS script on the global object to define any properties
+ * that can be defined from JS.
  * This function completes the initialization of a new global object, but it
  * is separate from gjs_create_global_object() because all globals share the
  * same root importer.
@@ -283,9 +332,10 @@ gjs_create_global_object(JSContext *cx)
  */
 bool
 gjs_define_global_properties(JSContext       *cx,
-                             JS::HandleObject global)
+                             JS::HandleObject global,
+                             const char      *bootstrap_script)
 {
-    return GjsGlobal::define_properties(cx, global);
+    return GjsGlobal::define_properties(cx, global, bootstrap_script);
 }
 
 void
diff --git a/gjs/global.h b/gjs/global.h
index 31056d6..ae99b15 100644
--- a/gjs/global.h
+++ b/gjs/global.h
@@ -58,7 +58,8 @@ typedef enum {
 JSObject *gjs_create_global_object(JSContext *cx);
 
 bool gjs_define_global_properties(JSContext       *cx,
-                                  JS::HandleObject global);
+                                  JS::HandleObject global,
+                                  const char      *bootstrap_script);
 
 JS::Value gjs_get_global_slot(JSContext    *cx,
                               GjsGlobalSlot slot);
diff --git a/modules/_bootstrap/default.js b/modules/_bootstrap/default.js
new file mode 100644
index 0000000..29dbdb1
--- /dev/null
+++ b/modules/_bootstrap/default.js
@@ -0,0 +1,7 @@
+(function(exports) {
+    'use strict';
+
+    // Do early initialization here.
+    void exports;
+
+})(window);
diff --git a/modules/modules.gresource.xml b/modules/modules.gresource.xml
index 2f7cfb6..9ffa492 100644
--- a/modules/modules.gresource.xml
+++ b/modules/modules.gresource.xml
@@ -1,6 +1,8 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <gresources>
   <gresource prefix="/org/gnome/gjs">
+    <file>modules/_bootstrap/default.js</file>
+
     <file>modules/tweener/equations.js</file>
     <file>modules/tweener/tweener.js</file>
     <file>modules/tweener/tweenList.js</file>


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