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