LCOV - code coverage report
Current view: top level - gjs - context-private.h (source / functions) Hit Total Coverage
Test: gjs- Code Coverage Lines: 44 44 100.0 %
Date: 2024-02-27 17:05:05 Functions: 30 30 100.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 0 0 -

           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: 2014 Colin Walters <walters@verbum.org>
       4                 :            : 
       5                 :            : #ifndef GJS_CONTEXT_PRIVATE_H_
       6                 :            : #define GJS_CONTEXT_PRIVATE_H_
       7                 :            : 
       8                 :            : #include <config.h>
       9                 :            : 
      10                 :            : #include <stddef.h>  // for size_t
      11                 :            : #include <stdint.h>
      12                 :            : 
      13                 :            : #include <atomic>
      14                 :            : #include <string>
      15                 :            : #include <thread>
      16                 :            : #include <unordered_map>
      17                 :            : #include <utility>  // for pair
      18                 :            : #include <vector>
      19                 :            : 
      20                 :            : #include <gio/gio.h>  // for GMemoryMonitor
      21                 :            : #include <glib-object.h>
      22                 :            : #include <glib.h>
      23                 :            : 
      24                 :            : #include <js/AllocPolicy.h>
      25                 :            : #include <js/Context.h>
      26                 :            : #include <js/GCAPI.h>
      27                 :            : #include <js/GCHashTable.h>
      28                 :            : #include <js/GCVector.h>
      29                 :            : #include <js/HashTable.h>  // for DefaultHasher
      30                 :            : #include <js/Promise.h>
      31                 :            : #include <js/Realm.h>
      32                 :            : #include <js/RootingAPI.h>
      33                 :            : #include <js/TypeDecls.h>
      34                 :            : #include <js/UniquePtr.h>
      35                 :            : #include <js/Utility.h>  // for UniqueChars, FreePolicy
      36                 :            : #include <js/ValueArray.h>
      37                 :            : #include <jsfriendapi.h>  // for ScriptEnvironmentPreparer
      38                 :            : 
      39                 :            : #include "gi/closure.h"
      40                 :            : #include "gjs/context.h"
      41                 :            : #include "gjs/jsapi-util.h"
      42                 :            : #include "gjs/macros.h"
      43                 :            : #include "gjs/mainloop.h"
      44                 :            : #include "gjs/profiler.h"
      45                 :            : #include "gjs/promise.h"
      46                 :            : 
      47                 :            : class GjsAtoms;
      48                 :            : class JSTracer;
      49                 :            : 
      50                 :            : using JobQueueStorage =
      51                 :            :     JS::GCVector<JS::Heap<JSObject*>, 0, js::SystemAllocPolicy>;
      52                 :            : using ObjectInitList =
      53                 :            :     JS::GCVector<JS::Heap<JSObject*>, 0, js::SystemAllocPolicy>;
      54                 :            : using FundamentalTable =
      55                 :            :     JS::GCHashMap<void*, JS::Heap<JSObject*>, js::DefaultHasher<void*>,
      56                 :            :                   js::SystemAllocPolicy>;
      57                 :            : using GTypeTable =
      58                 :            :     JS::GCHashMap<GType, JS::Heap<JSObject*>, js::DefaultHasher<GType>,
      59                 :            :                   js::SystemAllocPolicy>;
      60                 :            : using FunctionVector = JS::GCVector<JSFunction*, 0, js::SystemAllocPolicy>;
      61                 :            : 
      62                 :            : class GjsContextPrivate : public JS::JobQueue {
      63                 :            :  public:
      64                 :            :     using DestroyNotify = void (*)(JSContext*, void* data);
      65                 :            : 
      66                 :            :  private:
      67                 :            :     GjsContext* m_public_context;
      68                 :            :     JSContext* m_cx;
      69                 :            :     JS::Heap<JSObject*> m_main_loop_hook;
      70                 :            :     JS::Heap<JSObject*> m_global;
      71                 :            :     JS::Heap<JSObject*> m_internal_global;
      72                 :            :     std::thread::id m_owner_thread;
      73                 :            : 
      74                 :            :     char* m_program_name;
      75                 :            :     char* m_program_path;
      76                 :            : 
      77                 :            :     char** m_search_path;
      78                 :            : 
      79                 :            :     unsigned m_auto_gc_id;
      80                 :            : 
      81                 :            :     GjsAtoms* m_atoms;
      82                 :            : 
      83                 :            :     std::vector<std::string> m_args;
      84                 :            : 
      85                 :            :     JobQueueStorage m_job_queue;
      86                 :            :     Gjs::PromiseJobDispatcher m_dispatcher;
      87                 :            :     Gjs::MainLoop m_main_loop;
      88                 :            :     GjsAutoUnref<GMemoryMonitor> m_memory_monitor;
      89                 :            : 
      90                 :            :     std::vector<std::pair<DestroyNotify, void*>> m_destroy_notifications;
      91                 :            :     std::vector<Gjs::Closure::Ptr> m_async_closures;
      92                 :            :     std::unordered_map<uint64_t, JS::UniqueChars> m_unhandled_rejection_stacks;
      93                 :            :     FunctionVector m_cleanup_tasks;
      94                 :            : 
      95                 :            :     GjsProfiler* m_profiler;
      96                 :            : 
      97                 :            :     /* Environment preparer needed for debugger, taken from SpiderMonkey's
      98                 :            :      * JS shell */
      99                 :            :     struct EnvironmentPreparer final : protected js::ScriptEnvironmentPreparer {
     100                 :            :         JSContext* m_cx;
     101                 :            : 
     102                 :        242 :         explicit EnvironmentPreparer(JSContext* cx) : m_cx(cx) {
     103                 :        242 :             js::SetScriptEnvironmentPreparer(m_cx, this);
     104                 :        242 :         }
     105                 :            : 
     106                 :            :         void invoke(JS::HandleObject scope, Closure& closure) override;
     107                 :            :     };
     108                 :            :     EnvironmentPreparer m_environment_preparer;
     109                 :            : 
     110                 :            :     // Weak pointer mapping from fundamental native pointer to JSObject
     111                 :            :     JS::WeakCache<FundamentalTable>* m_fundamental_table;
     112                 :            :     JS::WeakCache<GTypeTable>* m_gtype_table;
     113                 :            : 
     114                 :            :     // List that holds JSObject GObject wrappers for JS-created classes, from
     115                 :            :     // the time of their creation until their GObject instance init function is
     116                 :            :     // called
     117                 :            :     ObjectInitList m_object_init_list;
     118                 :            : 
     119                 :            :     uint8_t m_exit_code;
     120                 :            : 
     121                 :            :     /* flags */
     122                 :            :     std::atomic_bool m_destroying = ATOMIC_VAR_INIT(false);
     123                 :            :     bool m_in_gc_sweep : 1;
     124                 :            :     bool m_should_exit : 1;
     125                 :            :     bool m_force_gc : 1;
     126                 :            :     bool m_draining_job_queue : 1;
     127                 :            :     bool m_should_profile : 1;
     128                 :            :     bool m_exec_as_module : 1;
     129                 :            :     bool m_unhandled_exception : 1;
     130                 :            :     bool m_should_listen_sigusr2 : 1;
     131                 :            : 
     132                 :            :     // If profiling is enabled, we record the durations and reason for GC mark
     133                 :            :     // and sweep
     134                 :            :     int64_t m_gc_begin_time;
     135                 :            :     int64_t m_sweep_begin_time;
     136                 :            :     int64_t m_group_sweep_begin_time;
     137                 :            :     const char* m_gc_reason;  // statically allocated
     138                 :            : 
     139                 :            :     void schedule_gc_internal(bool force_gc);
     140                 :            :     static gboolean trigger_gc_if_needed(void* data);
     141                 :            :     void on_garbage_collection(JSGCStatus, JS::GCReason);
     142                 :            : 
     143                 :            :     class SavedQueue;
     144                 :            :     void start_draining_job_queue(void);
     145                 :            :     void stop_draining_job_queue(void);
     146                 :            : 
     147                 :            :     void warn_about_unhandled_promise_rejections();
     148                 :            : 
     149                 :            :     GJS_JSAPI_RETURN_CONVENTION bool run_main_loop_hook();
     150                 :            :     [[nodiscard]] bool handle_exit_code(bool no_sync_error_pending,
     151                 :            :                                         const char* source_type,
     152                 :            :                                         const char* identifier,
     153                 :            :                                         uint8_t* exit_code, GError** error);
     154                 :            :     [[nodiscard]] bool auto_profile_enter(void);
     155                 :            :     void auto_profile_exit(bool status);
     156                 :            : 
     157                 :            :     class AutoResetExit {
     158                 :            :         GjsContextPrivate* m_self;
     159                 :            : 
     160                 :            :      public:
     161                 :        368 :         explicit AutoResetExit(GjsContextPrivate* self) { m_self = self; }
     162                 :        366 :         ~AutoResetExit() {
     163                 :        366 :             m_self->m_should_exit = false;
     164                 :        366 :             m_self->m_exit_code = 0;
     165                 :        366 :         }
     166                 :            :     };
     167                 :            : 
     168                 :            :  public:
     169                 :            :     /* Retrieving a GjsContextPrivate from JSContext or GjsContext */
     170                 :     149600 :     [[nodiscard]] static GjsContextPrivate* from_cx(JSContext* cx) {
     171                 :     149600 :         return static_cast<GjsContextPrivate*>(JS_GetContextPrivate(cx));
     172                 :            :     }
     173                 :            :     [[nodiscard]] static GjsContextPrivate* from_object(
     174                 :            :         GObject* public_context);
     175                 :            :     [[nodiscard]] static GjsContextPrivate* from_object(
     176                 :            :         GjsContext* public_context);
     177                 :            :     [[nodiscard]] static GjsContextPrivate* from_current_context();
     178                 :            : 
     179                 :            :     GjsContextPrivate(JSContext* cx, GjsContext* public_context);
     180                 :            :     ~GjsContextPrivate(void);
     181                 :            : 
     182                 :            :     /* Accessors */
     183                 :            :     [[nodiscard]] GjsContext* public_context() const {
     184                 :            :         return m_public_context;
     185                 :            :     }
     186                 :            :     [[nodiscard]] bool set_main_loop_hook(JSObject* callable);
     187                 :        695 :     [[nodiscard]] bool has_main_loop_hook() { return !!m_main_loop_hook; }
     188                 :      30947 :     [[nodiscard]] JSContext* context() const { return m_cx; }
     189                 :      14354 :     [[nodiscard]] JSObject* global() const { return m_global.get(); }
     190                 :        484 :     [[nodiscard]] JSObject* internal_global() const {
     191                 :        484 :         return m_internal_global.get();
     192                 :            :     }
     193                 :        400 :     void main_loop_hold() { m_main_loop.hold(); }
     194                 :        397 :     void main_loop_release() { m_main_loop.release(); }
     195                 :          6 :     [[nodiscard]] GjsProfiler* profiler() const { return m_profiler; }
     196                 :      23817 :     [[nodiscard]] const GjsAtoms& atoms() const { return *m_atoms; }
     197                 :       3947 :     [[nodiscard]] bool destroying() const { return m_destroying.load(); }
     198                 :       8816 :     [[nodiscard]] bool sweeping() const { return m_in_gc_sweep; }
     199                 :         78 :     [[nodiscard]] const char* program_name() const { return m_program_name; }
     200                 :        242 :     void set_program_name(char* value) { m_program_name = value; }
     201                 :         78 :     GJS_USE const char* program_path(void) const { return m_program_path; }
     202                 :        242 :     void set_program_path(char* value) { m_program_path = value; }
     203                 :        242 :     void set_search_path(char** value) { m_search_path = value; }
     204                 :        242 :     void set_should_profile(bool value) { m_should_profile = value; }
     205                 :        242 :     void set_execute_as_module(bool value) { m_exec_as_module = value; }
     206                 :        242 :     void set_should_listen_sigusr2(bool value) {
     207                 :        242 :         m_should_listen_sigusr2 = value;
     208                 :        242 :     }
     209                 :            :     void set_args(std::vector<std::string>&& args);
     210                 :            :     GJS_JSAPI_RETURN_CONVENTION JSObject* build_args_array();
     211                 :       3386 :     [[nodiscard]] bool is_owner_thread() const {
     212                 :       3386 :         return m_owner_thread == std::this_thread::get_id();
     213                 :            :     }
     214                 :         30 :     [[nodiscard]] JS::WeakCache<FundamentalTable>& fundamental_table() {
     215                 :         30 :         return *m_fundamental_table;
     216                 :            :     }
     217                 :       5763 :     [[nodiscard]] JS::WeakCache<GTypeTable>& gtype_table() {
     218                 :       5763 :         return *m_gtype_table;
     219                 :            :     }
     220                 :       2530 :     [[nodiscard]] ObjectInitList& object_init_list() {
     221                 :       2530 :         return m_object_init_list;
     222                 :            :     }
     223                 :      67837 :     [[nodiscard]] static const GjsAtoms& atoms(JSContext* cx) {
     224                 :      67837 :         return *(from_cx(cx)->m_atoms);
     225                 :            :     }
     226                 :            :     [[nodiscard]] static JSObject* global(JSContext* cx) {
     227                 :            :         return from_cx(cx)->global();
     228                 :            :     }
     229                 :            : 
     230                 :            :     [[nodiscard]] bool eval(const char* script, size_t script_len,
     231                 :            :                             const char* filename, int* exit_status_p,
     232                 :            :                             GError** error);
     233                 :            :     GJS_JSAPI_RETURN_CONVENTION
     234                 :            :     bool eval_with_scope(JS::HandleObject scope_object, const char* script,
     235                 :            :                          size_t script_len, const char* filename,
     236                 :            :                          JS::MutableHandleValue retval);
     237                 :            :     [[nodiscard]] bool eval_module(const char* identifier, uint8_t* exit_code_p,
     238                 :            :                                    GError** error);
     239                 :            :     GJS_JSAPI_RETURN_CONVENTION
     240                 :            :     bool call_function(JS::HandleObject this_obj, JS::HandleValue func_val,
     241                 :            :                        const JS::HandleValueArray& args,
     242                 :            :                        JS::MutableHandleValue rval);
     243                 :            : 
     244                 :       1447 :     void schedule_gc(void) { schedule_gc_internal(true); }
     245                 :            :     void schedule_gc_if_needed(void);
     246                 :            : 
     247                 :          1 :     void report_unhandled_exception() { m_unhandled_exception = true; }
     248                 :            :     void exit(uint8_t exit_code);
     249                 :            :     [[nodiscard]] bool should_exit(uint8_t* exit_code_p) const;
     250                 :            :     [[noreturn]] void exit_immediately(uint8_t exit_code);
     251                 :            : 
     252                 :            :     // Implementations of JS::JobQueue virtual functions
     253                 :            :     GJS_JSAPI_RETURN_CONVENTION
     254                 :            :     JSObject* getIncumbentGlobal(JSContext* cx) override;
     255                 :            :     GJS_JSAPI_RETURN_CONVENTION
     256                 :            :     bool enqueuePromiseJob(JSContext* cx, JS::HandleObject promise,
     257                 :            :                            JS::HandleObject job,
     258                 :            :                            JS::HandleObject allocation_site,
     259                 :            :                            JS::HandleObject incumbent_global) override;
     260                 :            :     void runJobs(JSContext* cx) override;
     261                 :      12410 :     [[nodiscard]] bool empty() const override { return m_job_queue.empty(); }
     262                 :            :     js::UniquePtr<JS::JobQueue::SavedJobQueue> saveJobQueue(
     263                 :            :         JSContext* cx) override;
     264                 :            : 
     265                 :            :     GJS_JSAPI_RETURN_CONVENTION bool run_jobs_fallible();
     266                 :            :     void register_unhandled_promise_rejection(uint64_t id,
     267                 :            :                                               JS::UniqueChars&& stack);
     268                 :            :     void unregister_unhandled_promise_rejection(uint64_t id);
     269                 :            :     GJS_JSAPI_RETURN_CONVENTION bool queue_finalization_registry_cleanup(
     270                 :            :         JSFunction* cleanup_task);
     271                 :            :     GJS_JSAPI_RETURN_CONVENTION bool run_finalization_registry_cleanup();
     272                 :            : 
     273                 :            :     void register_notifier(DestroyNotify notify_func, void* data);
     274                 :            :     void unregister_notifier(DestroyNotify notify_func, void* data);
     275                 :            :     void async_closure_enqueue_for_gc(Gjs::Closure*);
     276                 :            : 
     277                 :            :     [[nodiscard]] bool register_module(const char* identifier,
     278                 :            :                                        const char* filename, GError** error);
     279                 :            : 
     280                 :            :     void set_gc_status(JSGCStatus status, JS::GCReason reason);
     281                 :            :     void set_finalize_status(JSFinalizeStatus status);
     282                 :            : 
     283                 :            :     static void trace(JSTracer* trc, void* data);
     284                 :            : 
     285                 :            :     void free_profiler(void);
     286                 :            :     void dispose(void);
     287                 :            : };
     288                 :            : 
     289                 :            : std::string gjs_dumpstack_string();
     290                 :            : 
     291                 :            : namespace Gjs {
     292                 :            : class AutoMainRealm : public JSAutoRealm {
     293                 :            :  public:
     294                 :            :     explicit AutoMainRealm(GjsContextPrivate* gjs);
     295                 :            :     explicit AutoMainRealm(JSContext* cx);
     296                 :            : };
     297                 :            : 
     298                 :            : class AutoInternalRealm : public JSAutoRealm {
     299                 :            :  public:
     300                 :            :     explicit AutoInternalRealm(GjsContextPrivate* gjs);
     301                 :            :     explicit AutoInternalRealm(JSContext* cx);
     302                 :            : };
     303                 :            : }  // namespace Gjs
     304                 :            : 
     305                 :            : #endif  // GJS_CONTEXT_PRIVATE_H_

Generated by: LCOV version 1.14