LCOV - code coverage report
Current view: top level - gjs - global.cpp (source / functions) Coverage Total Hit
Test: gjs- Code Coverage Lines: 78.9 % 223 176
Test Date: 2025-02-09 21:27:27 Functions: 83.3 % 24 20
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 53.5 % 86 46

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

Generated by: LCOV version 2.0-1