LCOV - code coverage report
Current view: top level - gjs - context-private.h (source / functions) Coverage Total Hit
Test: gjs- Code Coverage Lines: 100.0 % 44 44
Test Date: 2024-04-20 17:42:51 Functions: 100.0 % 30 30
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                 :         241 :         explicit EnvironmentPreparer(JSContext* cx) : m_cx(cx) {
     103                 :         241 :             js::SetScriptEnvironmentPreparer(m_cx, this);
     104                 :         241 :         }
     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                 :         365 :         explicit AutoResetExit(GjsContextPrivate* self) { m_self = self; }
     162                 :         363 :         ~AutoResetExit() {
     163                 :         363 :             m_self->m_should_exit = false;
     164                 :         363 :             m_self->m_exit_code = 0;
     165                 :         363 :         }
     166                 :             :     };
     167                 :             : 
     168                 :             :  public:
     169                 :             :     /* Retrieving a GjsContextPrivate from JSContext or GjsContext */
     170                 :      153318 :     [[nodiscard]] static GjsContextPrivate* from_cx(JSContext* cx) {
     171                 :      153318 :         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                 :         709 :     [[nodiscard]] bool has_main_loop_hook() { return !!m_main_loop_hook; }
     188                 :       31160 :     [[nodiscard]] JSContext* context() const { return m_cx; }
     189                 :       14411 :     [[nodiscard]] JSObject* global() const { return m_global.get(); }
     190                 :         482 :     [[nodiscard]] JSObject* internal_global() const {
     191                 :         482 :         return m_internal_global.get();
     192                 :             :     }
     193                 :         397 :     void main_loop_hold() { m_main_loop.hold(); }
     194                 :         394 :     void main_loop_release() { m_main_loop.release(); }
     195                 :           6 :     [[nodiscard]] GjsProfiler* profiler() const { return m_profiler; }
     196                 :       24115 :     [[nodiscard]] const GjsAtoms& atoms() const { return *m_atoms; }
     197                 :        3995 :     [[nodiscard]] bool destroying() const { return m_destroying.load(); }
     198                 :        8903 :     [[nodiscard]] bool sweeping() const { return m_in_gc_sweep; }
     199                 :          77 :     [[nodiscard]] const char* program_name() const { return m_program_name; }
     200                 :         241 :     void set_program_name(char* value) { m_program_name = value; }
     201                 :          77 :     GJS_USE const char* program_path(void) const { return m_program_path; }
     202                 :         241 :     void set_program_path(char* value) { m_program_path = value; }
     203                 :         241 :     void set_search_path(char** value) { m_search_path = value; }
     204                 :         241 :     void set_should_profile(bool value) { m_should_profile = value; }
     205                 :         241 :     void set_execute_as_module(bool value) { m_exec_as_module = value; }
     206                 :         241 :     void set_should_listen_sigusr2(bool value) {
     207                 :         241 :         m_should_listen_sigusr2 = value;
     208                 :         241 :     }
     209                 :             :     void set_args(std::vector<std::string>&& args);
     210                 :             :     GJS_JSAPI_RETURN_CONVENTION JSObject* build_args_array();
     211                 :        3406 :     [[nodiscard]] bool is_owner_thread() const {
     212                 :        3406 :         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                 :        5969 :     [[nodiscard]] JS::WeakCache<GTypeTable>& gtype_table() {
     218                 :        5969 :         return *m_gtype_table;
     219                 :             :     }
     220                 :        2525 :     [[nodiscard]] ObjectInitList& object_init_list() {
     221                 :        2525 :         return m_object_init_list;
     222                 :             :     }
     223                 :       70686 :     [[nodiscard]] static const GjsAtoms& atoms(JSContext* cx) {
     224                 :       70686 :         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                 :        1466 :     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                 :       12473 :     [[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 2.0-1