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;
|