LCOV - code coverage report
Current view: top level - gjs - global.cpp (source / functions) Coverage Total Hit
Test: gjs- Code Coverage Lines: 78.1 % 201 157
Test Date: 2024-09-12 04:39:42 Functions: 82.6 % 23 19
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 52.6 % 78 41

             Branch data     Line data    Source code
       1                 :             : /* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
       2                 :             : // SPDX-License-Identifier: MIT OR LGPL-2.0-or-later
       3                 :             : // SPDX-FileCopyrightText: 2008 litl, LLC
       4                 :             : // SPDX-FileCopyrightText: 2009 Red Hat, Inc.
       5                 :             : // SPDX-FileCopyrightText: 2017 Philip Chimento <philip.chimento@gmail.com>
       6                 :             : // SPDX-FileCopyrightText: 2020 Evan Welsh <contact@evanwelsh.com>
       7                 :             : 
       8                 :             : #include <config.h>
       9                 :             : 
      10                 :             : #include <stddef.h>  // for size_t
      11                 :             : 
      12                 :             : #include <glib.h>
      13                 :             : 
      14                 :             : #include <js/CallArgs.h>           // for CallArgs, CallArgsFromVp
      15                 :             : #include <js/CharacterEncoding.h>  // for JS_EncodeStringToUTF8
      16                 :             : #include <js/Class.h>
      17                 :             : #include <js/CompilationAndEvaluation.h>
      18                 :             : #include <js/CompileOptions.h>
      19                 :             : #include <js/Debug.h>         // for JS_DefineDebuggerObject
      20                 :             : #include <js/GlobalObject.h>  // for CurrentGlobalOrNull, JS_NewGlobalObject
      21                 :             : #include <js/Id.h>
      22                 :             : #include <js/MapAndSet.h>
      23                 :             : #include <js/Object.h>
      24                 :             : #include <js/PropertyAndElement.h>
      25                 :             : #include <js/PropertyDescriptor.h>  // for JSPROP_PERMANENT, JSPROP_RE...
      26                 :             : #include <js/PropertySpec.h>
      27                 :             : #include <js/Realm.h>  // for GetObjectRealmOrNull, SetRealmPrivate
      28                 :             : #include <js/RealmOptions.h>
      29                 :             : #include <js/RootingAPI.h>
      30                 :             : #include <js/SourceText.h>
      31                 :             : #include <js/TypeDecls.h>
      32                 :             : #include <js/Utility.h>  // for UniqueChars
      33                 :             : #include <jsapi.h>       // for JS_IdToValue, JS_InitReflectParse
      34                 :             : 
      35                 :             : #include "gjs/atoms.h"
      36                 :             : #include "gjs/context-private.h"
      37                 :             : #include "gjs/engine.h"
      38                 :             : #include "gjs/global.h"
      39                 :             : #include "gjs/internal.h"
      40                 :             : #include "gjs/jsapi-util.h"
      41                 :             : #include "gjs/macros.h"
      42                 :             : #include "gjs/native.h"
      43                 :             : 
      44                 :             : namespace mozilla {
      45                 :             : union Utf8Unit;
      46                 :             : }
      47                 :             : 
      48                 :             : class GjsBaseGlobal {
      49                 :             :     GJS_JSAPI_RETURN_CONVENTION
      50                 :         561 :     static JSObject* base(JSContext* cx, const JSClass* clasp,
      51                 :             :                           JS::RealmCreationOptions options,
      52                 :             :                           JSPrincipals* principals = nullptr) {
      53                 :         561 :         JS::RealmBehaviors behaviors;
      54                 :         561 :         JS::RealmOptions compartment_options(options, behaviors);
      55                 :             : 
      56                 :         561 :         JS::RootedObject global{cx, JS_NewGlobalObject(cx, clasp, principals,
      57                 :             :                                                        JS::FireOnNewGlobalHook,
      58                 :         561 :                                                        compartment_options)};
      59         [ -  + ]:         561 :         if (!global)
      60                 :           0 :             return nullptr;
      61                 :             : 
      62                 :         561 :         JSAutoRealm ac(cx, global);
      63                 :             : 
      64         [ +  - ]:        1122 :         if (!JS_InitReflectParse(cx, global) ||
      65   [ -  +  -  + ]:        1122 :             !JS_DefineDebuggerObject(cx, global))
      66                 :           0 :             return nullptr;
      67                 :             : 
      68                 :         561 :         return global;
      69                 :         561 :     }
      70                 :             : 
      71                 :             :  protected:
      72                 :             :     GJS_JSAPI_RETURN_CONVENTION
      73                 :         326 :     static JSObject* create(
      74                 :             :         JSContext* cx, const JSClass* clasp,
      75                 :             :         JS::RealmCreationOptions options = JS::RealmCreationOptions(),
      76                 :             :         JSPrincipals* principals = nullptr) {
      77                 :         326 :         options.setNewCompartmentAndZone();
      78                 :         326 :         return base(cx, clasp, options, principals);
      79                 :             :     }
      80                 :             : 
      81                 :             :     GJS_JSAPI_RETURN_CONVENTION
      82                 :         235 :     static JSObject* create_with_compartment(
      83                 :             :         JSContext* cx, JS::HandleObject existing, const JSClass* clasp,
      84                 :             :         JS::RealmCreationOptions options = JS::RealmCreationOptions(),
      85                 :             :         JSPrincipals* principals = nullptr) {
      86                 :         235 :         options.setExistingCompartment(existing);
      87                 :         235 :         return base(cx, clasp, options, principals);
      88                 :             :     }
      89                 :             : 
      90                 :             :     GJS_JSAPI_RETURN_CONVENTION
      91                 :         326 :     static bool run_bootstrap(JSContext* cx, const char* bootstrap_script,
      92                 :             :                               JS::HandleObject global) {
      93                 :             :         GjsAutoChar uri = g_strdup_printf(
      94                 :             :             "resource:///org/gnome/gjs/modules/script/_bootstrap/%s.js",
      95                 :         326 :             bootstrap_script);
      96                 :             : 
      97                 :         326 :         JSAutoRealm ar(cx, global);
      98                 :             : 
      99                 :         326 :         JS::CompileOptions options(cx);
     100                 :         326 :         options.setFileAndLine(uri, 1).setSourceIsLazy(true);
     101                 :             : 
     102                 :             :         char* script;
     103                 :             :         size_t script_len;
     104         [ -  + ]:         326 :         if (!gjs_load_internal_source(cx, uri, &script, &script_len))
     105                 :           0 :             return false;
     106                 :             : 
     107                 :         326 :         JS::SourceText<mozilla::Utf8Unit> source;
     108         [ -  + ]:         326 :         if (!source.init(cx, script, script_len,
     109                 :             :                          JS::SourceOwnership::TakeOwnership))
     110                 :           0 :             return false;
     111                 :             : 
     112                 :         326 :         JS::RootedValue ignored(cx);
     113                 :         326 :         return JS::Evaluate(cx, options, source, &ignored);
     114                 :         326 :     }
     115                 :             : 
     116                 :             :     GJS_JSAPI_RETURN_CONVENTION
     117                 :          20 :     static bool load_native_module(JSContext* m_cx, unsigned argc,
     118                 :             :                                    JS::Value* vp) {
     119                 :          20 :         JS::CallArgs argv = JS::CallArgsFromVp(argc, vp);
     120                 :             : 
     121                 :             :         // This function should never be directly exposed to user code, so we
     122                 :             :         // can be strict.
     123                 :          20 :         g_assert(argc == 1);
     124                 :          20 :         g_assert(argv[0].isString());
     125                 :             : 
     126                 :          20 :         JS::RootedString str(m_cx, argv[0].toString());
     127                 :          20 :         JS::UniqueChars id(JS_EncodeStringToUTF8(m_cx, str));
     128                 :             : 
     129         [ -  + ]:          20 :         if (!id)
     130                 :           0 :             return false;
     131                 :             : 
     132                 :          20 :         JS::RootedObject native_obj(m_cx);
     133                 :             : 
     134         [ -  + ]:          20 :         if (!Gjs::NativeModuleDefineFuncs::get().define(m_cx, id.get(),
     135                 :             :                                                         &native_obj)) {
     136                 :           0 :             gjs_throw(m_cx, "Failed to load native module: %s", id.get());
     137                 :           0 :             return false;
     138                 :             :         }
     139                 :             : 
     140                 :          20 :         argv.rval().setObject(*native_obj);
     141                 :          20 :         return true;
     142                 :          20 :     }
     143                 :             : };
     144                 :             : 
     145                 :             : const JSClassOps defaultclassops = JS::DefaultGlobalClassOps;
     146                 :             : 
     147                 :             : class GjsGlobal : GjsBaseGlobal {
     148                 :             :     static constexpr JSClass klass = {
     149                 :             :         // Jasmine depends on the class name "GjsGlobal" to detect GJS' global
     150                 :             :         // object.
     151                 :             :         "GjsGlobal",
     152                 :             :         JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(
     153                 :             :             static_cast<uint32_t>(GjsGlobalSlot::LAST)),
     154                 :             :         &defaultclassops,
     155                 :             :     };
     156                 :             : 
     157                 :             :     // clang-format off
     158                 :             :     static constexpr JSPropertySpec static_props[] = {
     159                 :             :         JS_STRING_SYM_PS(toStringTag, "GjsGlobal", JSPROP_READONLY),
     160                 :             :         JS_PS_END};
     161                 :             :     // clang-format on
     162                 :             : 
     163                 :             :     static constexpr JSFunctionSpec static_funcs[] = {
     164                 :             :         JS_FS_END};
     165                 :             : 
     166                 :             :  public:
     167                 :             :     GJS_JSAPI_RETURN_CONVENTION
     168                 :           0 :     static JSObject* create(JSContext* cx) {
     169                 :           0 :         return GjsBaseGlobal::create(cx, &klass);
     170                 :             :     }
     171                 :             : 
     172                 :             :     GJS_JSAPI_RETURN_CONVENTION
     173                 :         235 :     static JSObject* create_with_compartment(JSContext* cx,
     174                 :             :                                              JS::HandleObject cmp_global) {
     175                 :         235 :         return GjsBaseGlobal::create_with_compartment(cx, cmp_global, &klass);
     176                 :             :     }
     177                 :             : 
     178                 :             :     GJS_JSAPI_RETURN_CONVENTION
     179                 :         235 :     static bool define_properties(JSContext* cx, JS::HandleObject global,
     180                 :             :                                   const char* realm_name,
     181                 :             :                                   const char* bootstrap_script) {
     182                 :         235 :         const GjsAtoms& atoms = GjsContextPrivate::atoms(cx);
     183                 :         235 :         if (!JS_DefinePropertyById(cx, global, atoms.window(), global,
     184                 :         235 :                                    JSPROP_READONLY | JSPROP_PERMANENT) ||
     185   [ +  -  +  -  :         470 :             !JS_DefineFunctions(cx, global, GjsGlobal::static_funcs) ||
                   -  + ]
     186         [ -  + ]:         235 :             !JS_DefineProperties(cx, global, GjsGlobal::static_props))
     187                 :           0 :             return false;
     188                 :             : 
     189                 :         235 :         JS::Realm* realm = JS::GetObjectRealmOrNull(global);
     190                 :         235 :         g_assert(realm && "Global object must be associated with a realm");
     191                 :             :         // const_cast is allowed here if we never free the realm data
     192                 :         235 :         JS::SetRealmPrivate(realm, const_cast<char*>(realm_name));
     193                 :             : 
     194                 :         235 :         JS::RootedObject native_registry(cx, JS::NewMapObject(cx));
     195         [ -  + ]:         235 :         if (!native_registry)
     196                 :           0 :             return false;
     197                 :             : 
     198                 :         235 :         gjs_set_global_slot(global, GjsGlobalSlot::NATIVE_REGISTRY,
     199                 :         235 :                             JS::ObjectValue(*native_registry));
     200                 :             : 
     201                 :         235 :         JS::RootedObject module_registry(cx, JS::NewMapObject(cx));
     202         [ -  + ]:         235 :         if (!module_registry)
     203                 :           0 :             return false;
     204                 :             : 
     205                 :         235 :         gjs_set_global_slot(global, GjsGlobalSlot::MODULE_REGISTRY,
     206                 :         235 :                             JS::ObjectValue(*module_registry));
     207                 :             : 
     208                 :             :         JS::Value v_importer =
     209                 :         235 :             gjs_get_global_slot(global, GjsGlobalSlot::IMPORTS);
     210                 :         235 :         g_assert(((void) "importer should be defined before passing null "
     211                 :             :                   "importer to GjsGlobal::define_properties",
     212                 :             :                   v_importer.isObject()));
     213                 :         235 :         JS::RootedObject root_importer(cx, &v_importer.toObject());
     214                 :             : 
     215                 :             :         // Wrapping is a no-op if the importer is already in the same realm.
     216         [ +  - ]:         470 :         if (!JS_WrapObject(cx, &root_importer) ||
     217   [ -  +  -  + ]:         470 :             !JS_DefinePropertyById(cx, global, atoms.imports(), root_importer,
     218                 :             :                                    GJS_MODULE_PROP_FLAGS))
     219                 :           0 :             return false;
     220                 :             : 
     221         [ +  - ]:         235 :         if (bootstrap_script) {
     222         [ -  + ]:         235 :             if (!run_bootstrap(cx, bootstrap_script, global))
     223                 :           0 :                 return false;
     224                 :             :         }
     225                 :             : 
     226                 :         235 :         return true;
     227                 :         235 :     }
     228                 :             : };
     229                 :             : 
     230                 :             : class GjsDebuggerGlobal : GjsBaseGlobal {
     231                 :             :     static constexpr JSClass klass = {
     232                 :             :         "GjsDebuggerGlobal",
     233                 :             :         JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(
     234                 :             :             static_cast<uint32_t>(GjsDebuggerGlobalSlot::LAST)),
     235                 :             :         &defaultclassops,
     236                 :             :     };
     237                 :             : 
     238                 :             :     static constexpr JSFunctionSpec static_funcs[] = {
     239                 :             :         JS_FN("loadNative", &load_native_module, 1, 0), JS_FS_END};
     240                 :             : 
     241                 :             :  public:
     242                 :             :     GJS_JSAPI_RETURN_CONVENTION
     243                 :          91 :     static JSObject* create(JSContext* cx) {
     244                 :          91 :         JS::RealmCreationOptions options;
     245                 :          91 :         options.setToSourceEnabled(true);  // debugger uses uneval()
     246                 :          91 :         return GjsBaseGlobal::create(cx, &klass, options);
     247                 :          91 :     }
     248                 :             : 
     249                 :             :     GJS_JSAPI_RETURN_CONVENTION
     250                 :           0 :     static JSObject* create_with_compartment(JSContext* cx,
     251                 :             :                                              JS::HandleObject cmp_global) {
     252                 :           0 :         return GjsBaseGlobal::create_with_compartment(cx, cmp_global, &klass);
     253                 :             :     }
     254                 :             : 
     255                 :             :     GJS_JSAPI_RETURN_CONVENTION
     256                 :          91 :     static bool define_properties(JSContext* cx, JS::HandleObject global,
     257                 :             :                                   const char* realm_name,
     258                 :             :                                   const char* bootstrap_script) {
     259                 :          91 :         const GjsAtoms& atoms = GjsContextPrivate::atoms(cx);
     260                 :          91 :         if (!JS_DefinePropertyById(cx, global, atoms.window(), global,
     261   [ +  -  -  + ]:         182 :                                    JSPROP_READONLY | JSPROP_PERMANENT) ||
     262         [ -  + ]:          91 :             !JS_DefineFunctions(cx, global, GjsDebuggerGlobal::static_funcs))
     263                 :           0 :             return false;
     264                 :             : 
     265                 :          91 :         JS::Realm* realm = JS::GetObjectRealmOrNull(global);
     266                 :          91 :         g_assert(realm && "Global object must be associated with a realm");
     267                 :             :         // const_cast is allowed here if we never free the realm data
     268                 :          91 :         JS::SetRealmPrivate(realm, const_cast<char*>(realm_name));
     269                 :             : 
     270         [ +  - ]:          91 :         if (bootstrap_script) {
     271         [ -  + ]:          91 :             if (!run_bootstrap(cx, bootstrap_script, global))
     272                 :           0 :                 return false;
     273                 :             :         }
     274                 :             : 
     275                 :          91 :         return true;
     276                 :             :     }
     277                 :             : };
     278                 :             : 
     279                 :             : class GjsInternalGlobal : GjsBaseGlobal {
     280                 :             :     static constexpr JSFunctionSpec static_funcs[] = {
     281                 :             :         JS_FN("compileModule", gjs_internal_compile_module, 2, 0),
     282                 :             :         JS_FN("compileInternalModule", gjs_internal_compile_internal_module, 2,
     283                 :             :               0),
     284                 :             :         JS_FN("getRegistry", gjs_internal_get_registry, 1, 0),
     285                 :             :         JS_FN("loadResourceOrFile", gjs_internal_load_resource_or_file, 1, 0),
     286                 :             :         JS_FN("loadResourceOrFileAsync",
     287                 :             :               gjs_internal_load_resource_or_file_async, 1, 0),
     288                 :             :         JS_FN("parseURI", gjs_internal_parse_uri, 1, 0),
     289                 :             :         JS_FN("resolveRelativeResourceOrFile",
     290                 :             :               gjs_internal_resolve_relative_resource_or_file, 2, 0),
     291                 :             :         JS_FN("setGlobalModuleLoader", gjs_internal_set_global_module_loader, 2,
     292                 :             :               0),
     293                 :             :         JS_FN("setModulePrivate", gjs_internal_set_module_private, 2, 0),
     294                 :             :         JS_FN("uriExists", gjs_internal_uri_exists, 1, 0),
     295                 :             :         JS_FS_END};
     296                 :             : 
     297                 :             :     static constexpr JSClass klass = {
     298                 :             :         "GjsInternalGlobal",
     299                 :             :         JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(
     300                 :             :             static_cast<uint32_t>(GjsInternalGlobalSlot::LAST)),
     301                 :             :         &defaultclassops,
     302                 :             :     };
     303                 :             : 
     304                 :             :  public:
     305                 :             :     GJS_JSAPI_RETURN_CONVENTION
     306                 :         235 :     static JSObject* create(JSContext* cx) {
     307                 :         235 :         return GjsBaseGlobal::create(cx, &klass, {}, get_internal_principals());
     308                 :             :     }
     309                 :             : 
     310                 :             :     GJS_JSAPI_RETURN_CONVENTION
     311                 :           0 :     static JSObject* create_with_compartment(JSContext* cx,
     312                 :             :                                              JS::HandleObject cmp_global) {
     313                 :           0 :         return GjsBaseGlobal::create_with_compartment(
     314                 :           0 :             cx, cmp_global, &klass, {}, get_internal_principals());
     315                 :             :     }
     316                 :             : 
     317                 :             :     GJS_JSAPI_RETURN_CONVENTION
     318                 :         235 :     static bool define_properties(JSContext* cx, JS::HandleObject global,
     319                 :             :                                   const char* realm_name,
     320                 :             :                                   const char* bootstrap_script
     321                 :             :                                   [[maybe_unused]]) {
     322                 :         235 :         JS::Realm* realm = JS::GetObjectRealmOrNull(global);
     323                 :         235 :         g_assert(realm && "Global object must be associated with a realm");
     324                 :             :         // const_cast is allowed here if we never free the realm data
     325                 :         235 :         JS::SetRealmPrivate(realm, const_cast<char*>(realm_name));
     326                 :             : 
     327                 :         235 :         JSAutoRealm ar(cx, global);
     328                 :         235 :         JS::RootedObject native_registry(cx, JS::NewMapObject(cx));
     329         [ -  + ]:         235 :         if (!native_registry)
     330                 :           0 :             return false;
     331                 :             : 
     332                 :         235 :         gjs_set_global_slot(global, GjsGlobalSlot::NATIVE_REGISTRY,
     333                 :         235 :                             JS::ObjectValue(*native_registry));
     334                 :             : 
     335                 :         235 :         JS::RootedObject module_registry(cx, JS::NewMapObject(cx));
     336         [ -  + ]:         235 :         if (!module_registry)
     337                 :           0 :             return false;
     338                 :             : 
     339                 :         235 :         gjs_set_global_slot(global, GjsGlobalSlot::MODULE_REGISTRY,
     340                 :         235 :                             JS::ObjectValue(*module_registry));
     341                 :             : 
     342                 :         235 :         return JS_DefineFunctions(cx, global, static_funcs);
     343                 :         235 :     }
     344                 :             : };
     345                 :             : 
     346                 :             : /**
     347                 :             :  * gjs_create_global_object:
     348                 :             :  * @cx: a #JSContext
     349                 :             :  *
     350                 :             :  * Creates a global object, and initializes it with the default API.
     351                 :             :  *
     352                 :             :  * Returns: the created global object on success, nullptr otherwise, in which
     353                 :             :  * case an exception is pending on @cx
     354                 :             :  */
     355                 :         561 : JSObject* gjs_create_global_object(JSContext* cx, GjsGlobalType global_type,
     356                 :             :                                    JS::HandleObject current_global) {
     357         [ +  + ]:         561 :     if (current_global) {
     358   [ +  -  -  - ]:         235 :         switch (global_type) {
     359                 :         235 :             case GjsGlobalType::DEFAULT:
     360                 :         235 :                 return GjsGlobal::create_with_compartment(cx, current_global);
     361                 :           0 :             case GjsGlobalType::DEBUGGER:
     362                 :           0 :                 return GjsDebuggerGlobal::create_with_compartment(
     363                 :           0 :                     cx, current_global);
     364                 :           0 :             case GjsGlobalType::INTERNAL:
     365                 :           0 :                 return GjsInternalGlobal::create_with_compartment(
     366                 :           0 :                     cx, current_global);
     367                 :           0 :             default:
     368                 :           0 :                 return nullptr;
     369                 :             :         }
     370                 :             :     }
     371                 :             : 
     372   [ -  +  +  - ]:         326 :     switch (global_type) {
     373                 :           0 :         case GjsGlobalType::DEFAULT:
     374                 :           0 :             return GjsGlobal::create(cx);
     375                 :          91 :         case GjsGlobalType::DEBUGGER:
     376                 :          91 :             return GjsDebuggerGlobal::create(cx);
     377                 :         235 :         case GjsGlobalType::INTERNAL:
     378                 :         235 :             return GjsInternalGlobal::create(cx);
     379                 :           0 :         default:
     380                 :           0 :             return nullptr;
     381                 :             :     }
     382                 :             : }
     383                 :             : 
     384                 :             : /**
     385                 :             :  * gjs_global_is_type:
     386                 :             :  *
     387                 :             :  * @param cx the current #JSContext
     388                 :             :  * @param type the global type to test for
     389                 :             :  *
     390                 :             :  * @returns whether the current global is the same type as #type
     391                 :             :  */
     392                 :        4143 : bool gjs_global_is_type(JSContext* cx, GjsGlobalType type) {
     393                 :        4143 :     JSObject* global = JS::CurrentGlobalOrNull(cx);
     394                 :             : 
     395                 :        4143 :     g_assert(global && "gjs_global_is_type called before a realm was entered.");
     396                 :             : 
     397                 :             :     JS::Value global_type =
     398                 :        4143 :         gjs_get_global_slot(global, GjsBaseGlobalSlot::GLOBAL_TYPE);
     399                 :             : 
     400                 :        4143 :     g_assert(global_type.isInt32());
     401                 :             : 
     402                 :        4143 :     return static_cast<GjsGlobalType>(global_type.toInt32()) == type;
     403                 :             : }
     404                 :             : 
     405                 :           0 : GjsGlobalType gjs_global_get_type(JSContext* cx) {
     406                 :           0 :     auto global = JS::CurrentGlobalOrNull(cx);
     407                 :             : 
     408                 :           0 :     g_assert(global &&
     409                 :             :              "gjs_global_get_type called before a realm was entered.");
     410                 :             : 
     411                 :             :     JS::Value global_type =
     412                 :           0 :         gjs_get_global_slot(global, GjsBaseGlobalSlot::GLOBAL_TYPE);
     413                 :             : 
     414                 :           0 :     g_assert(global_type.isInt32());
     415                 :             : 
     416                 :           0 :     return static_cast<GjsGlobalType>(global_type.toInt32());
     417                 :             : }
     418                 :             : 
     419                 :       16997 : GjsGlobalType gjs_global_get_type(JSObject* global) {
     420                 :             :     JS::Value global_type =
     421                 :       16997 :         gjs_get_global_slot(global, GjsBaseGlobalSlot::GLOBAL_TYPE);
     422                 :             : 
     423                 :       16997 :     g_assert(global_type.isInt32());
     424                 :             : 
     425                 :       16997 :     return static_cast<GjsGlobalType>(global_type.toInt32());
     426                 :             : }
     427                 :             : 
     428                 :             : /**
     429                 :             :  * gjs_global_registry_set:
     430                 :             :  *
     431                 :             :  * @brief This function inserts a module object into a global registry.
     432                 :             :  * Global registries are JS Map objects for easy reuse and access
     433                 :             :  * within internal JS. This function will assert if a module has
     434                 :             :  * already been inserted at the given key.
     435                 :             : 
     436                 :             :  * @param cx the current #JSContext
     437                 :             :  * @param registry a JS Map object
     438                 :             :  * @param key a module identifier, typically a string or symbol
     439                 :             :  * @param module a module object
     440                 :             :  */
     441                 :         512 : bool gjs_global_registry_set(JSContext* cx, JS::HandleObject registry,
     442                 :             :                              JS::PropertyKey key, JS::HandleObject module) {
     443                 :         512 :     JS::RootedValue v_key(cx);
     444         [ -  + ]:         512 :     if (!JS_IdToValue(cx, key, &v_key))
     445                 :           0 :         return false;
     446                 :             : 
     447                 :             :     bool has_key;
     448         [ -  + ]:         512 :     if (!JS::MapHas(cx, registry, v_key, &has_key))
     449                 :           0 :         return false;
     450                 :             : 
     451                 :         512 :     g_assert(!has_key && "Module key already exists in the registry");
     452                 :             : 
     453                 :         512 :     JS::RootedValue v_value(cx, JS::ObjectValue(*module));
     454                 :             : 
     455                 :         512 :     return JS::MapSet(cx, registry, v_key, v_value);
     456                 :         512 : }
     457                 :             : 
     458                 :             : /**
     459                 :             :  * gjs_global_registry_get:
     460                 :             :  *
     461                 :             :  * @brief This function retrieves a module record from the global registry,
     462                 :             :  * or %NULL if the module record is not present.
     463                 :             :  * Global registries are JS Map objects for easy reuse and access
     464                 :             :  * within internal JS.
     465                 :             : 
     466                 :             :  * @param cx the current #JSContext
     467                 :             :  * @param registry a JS Map object
     468                 :             :  * @param key a module identifier, typically a string or symbol
     469                 :             :  * @param module a module object
     470                 :             :  */
     471                 :       24123 : bool gjs_global_registry_get(JSContext* cx, JS::HandleObject registry,
     472                 :             :                              JS::PropertyKey key,
     473                 :             :                              JS::MutableHandleObject module_out) {
     474                 :       24123 :     JS::RootedValue v_key(cx), v_value(cx);
     475         [ +  - ]:       48246 :     if (!JS_IdToValue(cx, key, &v_key) ||
     476   [ -  +  -  + ]:       48246 :         !JS::MapGet(cx, registry, v_key, &v_value))
     477                 :           0 :         return false;
     478                 :             : 
     479                 :       24123 :     g_assert((v_value.isUndefined() || v_value.isObject()) &&
     480                 :             :              "Invalid value in module registry");
     481                 :             : 
     482         [ +  + ]:       24123 :     if (v_value.isObject()) {
     483                 :       23609 :         module_out.set(&v_value.toObject());
     484                 :       23609 :         return true;
     485                 :             :     }
     486                 :             : 
     487                 :         514 :     module_out.set(nullptr);
     488                 :         514 :     return true;
     489                 :       24123 : }
     490                 :             : 
     491                 :             : /**
     492                 :             :  * gjs_define_global_properties:
     493                 :             :  * @cx: a #JSContext
     494                 :             :  * @global: a JS global object that has not yet been passed to this function
     495                 :             :  * @realm_name: (nullable): name of the realm, for debug output
     496                 :             :  * @bootstrap_script: (nullable): name of a bootstrap script (found at
     497                 :             :  * resource://org/gnome/gjs/modules/script/_bootstrap/@bootstrap_script) or
     498                 :             :  * %NULL for none
     499                 :             :  *
     500                 :             :  * Defines properties on the global object such as 'window' and 'imports', and
     501                 :             :  * runs a bootstrap JS script on the global object to define any properties
     502                 :             :  * that can be defined from JS.
     503                 :             :  * This function completes the initialization of a new global object, but it
     504                 :             :  * is separate from gjs_create_global_object() because all globals share the
     505                 :             :  * same root importer.
     506                 :             :  * The code creating the main global for the JS context needs to create the
     507                 :             :  * root importer in between calling gjs_create_global_object() and
     508                 :             :  * gjs_define_global_properties().
     509                 :             :  *
     510                 :             :  * The caller of this function should be in the realm for @global.
     511                 :             :  * If the root importer object belongs to a different realm, this function will
     512                 :             :  * create a wrapper for it.
     513                 :             :  *
     514                 :             :  * Returns: true on success, false otherwise, in which case an exception is
     515                 :             :  * pending on @cx
     516                 :             :  */
     517                 :         561 : bool gjs_define_global_properties(JSContext* cx, JS::HandleObject global,
     518                 :             :                                   GjsGlobalType global_type,
     519                 :             :                                   const char* realm_name,
     520                 :             :                                   const char* bootstrap_script) {
     521                 :         561 :     gjs_set_global_slot(global.get(), GjsBaseGlobalSlot::GLOBAL_TYPE,
     522                 :             :                         JS::Int32Value(static_cast<uint32_t>(global_type)));
     523                 :             : 
     524   [ +  +  +  - ]:         561 :     switch (global_type) {
     525                 :         235 :         case GjsGlobalType::DEFAULT:
     526                 :         235 :             return GjsGlobal::define_properties(cx, global, realm_name,
     527                 :         235 :                                                 bootstrap_script);
     528                 :          91 :         case GjsGlobalType::DEBUGGER:
     529                 :          91 :             return GjsDebuggerGlobal::define_properties(cx, global, realm_name,
     530                 :          91 :                                                         bootstrap_script);
     531                 :         235 :         case GjsGlobalType::INTERNAL:
     532                 :         235 :             return GjsInternalGlobal::define_properties(cx, global, realm_name,
     533                 :         235 :                                                         bootstrap_script);
     534                 :             :     }
     535                 :             : 
     536                 :             :     // Global type does not handle define_properties
     537                 :             :     g_assert_not_reached();
     538                 :             : }
     539                 :             : 
     540                 :        2642 : void detail::set_global_slot(JSObject* global, uint32_t slot, JS::Value value) {
     541                 :        2642 :     JS::SetReservedSlot(global, JSCLASS_GLOBAL_SLOT_COUNT + slot, value);
     542                 :        2642 : }
     543                 :             : 
     544                 :       68266 : JS::Value detail::get_global_slot(JSObject* global, uint32_t slot) {
     545                 :       68266 :     return JS::GetReservedSlot(global, JSCLASS_GLOBAL_SLOT_COUNT + slot);
     546                 :             : }
     547                 :             : 
     548                 :             : decltype(GjsGlobal::klass) constexpr GjsGlobal::klass;
     549                 :             : decltype(GjsGlobal::static_funcs) constexpr GjsGlobal::static_funcs;
     550                 :             : decltype(GjsGlobal::static_props) constexpr GjsGlobal::static_props;
     551                 :             : 
     552                 :             : decltype(GjsDebuggerGlobal::klass) constexpr GjsDebuggerGlobal::klass;
     553                 :             : decltype(
     554                 :             :     GjsDebuggerGlobal::static_funcs) constexpr GjsDebuggerGlobal::static_funcs;
     555                 :             : 
     556                 :             : decltype(GjsInternalGlobal::klass) constexpr GjsInternalGlobal::klass;
     557                 :             : decltype(
     558                 :             :     GjsInternalGlobal::static_funcs) constexpr GjsInternalGlobal::static_funcs;
        

Generated by: LCOV version 2.0-1