Coverage Report

Created: 2026-06-13 06:07

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/spicy/hilti/runtime/include/hilti/rt/global-state.h
Line
Count
Source
1
// Copyright (c) 2020-now by the Zeek Project. See LICENSE for details.
2
3
#pragma once
4
#include <sys/resource.h>
5
6
#include <clocale> // IWYU pragma: keep
7
#include <memory>
8
#include <optional>
9
#include <string>
10
#include <unordered_map>
11
#include <vector>
12
13
#include <hilti/rt/context.h>
14
#include <hilti/rt/debug-logger.h>
15
#include <hilti/rt/init.h>
16
#include <hilti/rt/profiler-state.h>
17
18
// We collect all (or most) of the runtime's global state centrally. That's
19
// 1st good to see what we have (global state should be minimal) and 2nd
20
// helpful to ensure that JIT maps things correctly. Note that all code
21
// accessing any of this state is in charge of ensuring thread-safety itself.
22
// These globals are generally initialized through hilti::rt::init();
23
//
24
// TODO(robin): Accesses to global state are *not* completely thread-safe yet.
25
26
namespace hilti::rt {
27
struct Configuration;
28
29
namespace regexp::detail {
30
class CompiledRegExp;
31
} // namespace regexp::detail
32
33
} // namespace hilti::rt
34
35
namespace hilti::rt::detail {
36
37
#if defined(_WIN32)
38
using runtime_locale_t = _locale_t;
39
#else
40
using runtime_locale_t = locale_t;
41
#endif
42
43
/** Struct capturing all truly global runtime state. */
44
struct GlobalState {
45
14
    GlobalState() = default;
46
    ~GlobalState();
47
48
    GlobalState(const GlobalState&) = delete;
49
    GlobalState(GlobalState&&) = delete;
50
    GlobalState& operator=(const GlobalState&) = delete;
51
    GlobalState& operator=(GlobalState&&) = delete;
52
53
    /** True once `hilit::init()`` has finished. */
54
    bool runtime_is_initialized = false;
55
56
    /** True once `profiler::init()` has been called. */
57
    bool profiling_enabled = false;
58
59
    /** If not zero, `Configuration::abort_on_exception` is disabled. */
60
    int disable_abort_on_exceptions = 0;
61
62
    /** Resource usage at library initialization time. */
63
    ResourceUsage resource_usage_init;
64
65
    /** Profiler's global measurements. */
66
    std::unordered_map<std::string, profiler::detail::MeasurementState> profilers;
67
68
    /** Debug logger recording runtime diagnostics. */
69
    std::unique_ptr<hilti::rt::detail::DebugLogger> debug_logger;
70
71
    /** The context for the main thread. */
72
    std::unique_ptr<hilti::rt::Context> master_context;
73
74
    /**
75
     * List of HILTI modules registered with the runtime. This is filled through `registerModule()`, which in turn gets
76
     * called through a module's global constructors at initialization time.
77
     *
78
     * @note Must come last in this struct as destroying other fields may
79
     * still need this information.
80
     */
81
    std::vector<hilti::rt::detail::HiltiModule> hilti_modules;
82
83
    /** Cache of already compiled regular expressions. */
84
    std::unordered_map<std::string, std::shared_ptr<regexp::detail::CompiledRegExp>> regexp_cache;
85
86
    /** Cached C locale for use with C library functions. */
87
    std::optional<runtime_locale_t> c_locale;
88
};
89
90
/**
91
 * Pointer to the global state singleton. Do not access directly, use
92
 * `globalState()` instead.
93
 */
94
extern HILTI_JIT_IMPORT GlobalState* __global_state;
95
96
/** Creates the global state singleton. */
97
extern HILTI_JIT_IMPORT GlobalState* createGlobalState();
98
99
/**
100
 * Returns the global state singleton. This creates the state the first time
101
 * it's called.
102
 */
103
120M
inline auto globalState() {
104
120M
    if ( __global_state )
105
120M
        return __global_state;
106
107
14
    return createGlobalState();
108
120M
}
109
110
/**
111
 * Returns the current global configuration without checking if it's already
112
 * initialized. This is only safe to use if the runtime is already fully
113
 * initialized, and should be left to internal use only where performance
114
 * matters.
115
 */
116
322k
inline const GlobalState* unsafeGlobalState() {
117
322k
    assert(__global_state);
118
322k
    return __global_state;
119
322k
}
120
121
/** Returns the current context's array of HILTI global variables. */
122
0
inline auto hiltiGlobals() {
123
0
    assert(context::detail::current());
124
0
    return context::detail::current()->hilti_globals;
125
0
}
126
127
/**
128
 * Returns the current context's set of a  HILTI module's global variables.
129
 *
130
 * @param idx module's index inside the array of HILTI global variables;
131
 * this is determined by the HILTI linker
132
 */
133
template<typename T>
134
inline auto moduleGlobals(unsigned int idx) {
135
    const auto& globals = hiltiGlobals();
136
137
    assert(idx < globals.size());
138
139
    return std::static_pointer_cast<T>(globals[idx]);
140
}
141
142
/**
143
 * Initialized the current context's set of a HILTI module's global
144
 * variables.
145
 *
146
 * @param idx module's index inside the array of HILTI global variables;
147
 * this is determined by the HILTI linker
148
 */
149
template<typename T>
150
inline auto initModuleGlobals(unsigned int idx) {
151
    if ( context::detail::current()->hilti_globals.size() <= idx )
152
        context::detail::current()->hilti_globals.resize(idx + 1);
153
154
    context::detail::current()->hilti_globals[idx] = std::make_shared<T>();
155
}
156
157
} // namespace hilti::rt::detail