@scriptc/runtime 0.0.26 → 0.0.28
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/scr_array.c +1 -1
- package/src/scr_assert.c +4 -4
- package/src/scr_bytes.c +1 -1
- package/src/scr_closure.c +2 -2
- package/src/scr_console.c +1 -1
- package/src/scr_cycle.c +14 -14
- package/src/scr_error.c +3 -3
- package/src/scr_events_emitter.c +3 -3
- package/src/scr_exception.c +22 -12
- package/src/scr_inspect.c +10 -10
- package/src/scr_json.c +14 -14
- package/src/scr_lib.c +44 -17
- package/src/scr_library.c +33 -13
- package/src/scr_map.c +1 -1
- package/src/scr_object.c +1 -1
- package/src/scr_regex.c +2 -2
- package/src/scr_runtime.h +22 -4
- package/src/scr_string.c +4 -4
- package/src/scr_symbol.c +1 -1
- package/src/scr_union.c +1 -1
package/package.json
CHANGED
package/src/scr_array.c
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
/* Live heap-array count for the RC audit lane (-DSCR_RC_AUDIT); same
|
|
9
9
|
* contract as scr_str_live_count in scr_string.c. */
|
|
10
10
|
#ifdef SCR_RC_AUDIT
|
|
11
|
-
static long scr_live_arrays = 0;
|
|
11
|
+
static SCR_TL long scr_live_arrays = 0;
|
|
12
12
|
long scr_arr_live_count(void) { return scr_live_arrays; }
|
|
13
13
|
#endif
|
|
14
14
|
|
package/src/scr_assert.c
CHANGED
|
@@ -158,9 +158,9 @@ void scr_assert_ok(bool pass, ScrStr *message) {
|
|
|
158
158
|
* PAIR already being compared answers equal (the coinductive step —
|
|
159
159
|
* Node's memo behavior exactly). The stack is global (comparisons never
|
|
160
160
|
* interleave; the emitted walks cannot throw mid-compare). */
|
|
161
|
-
static struct { const void *a, *b; } *g_deq_stack;
|
|
162
|
-
static size_t g_deq_len;
|
|
163
|
-
static size_t g_deq_cap;
|
|
161
|
+
static SCR_TL struct { const void *a, *b; } *g_deq_stack;
|
|
162
|
+
static SCR_TL size_t g_deq_len;
|
|
163
|
+
static SCR_TL size_t g_deq_cap;
|
|
164
164
|
|
|
165
165
|
bool scr_assert_deq_enter(const void *a, const void *b) {
|
|
166
166
|
for (size_t i = 0; i < g_deq_len; i++) {
|
|
@@ -1228,7 +1228,7 @@ typedef struct {
|
|
|
1228
1228
|
ScrStr *val; /* owned: the string value, or the regex's /source/flags */
|
|
1229
1229
|
} ScrShapeSlot;
|
|
1230
1230
|
|
|
1231
|
-
static struct {
|
|
1231
|
+
static SCR_TL struct {
|
|
1232
1232
|
ScrError *err; /* borrowed — alive across the straight-line sequence */
|
|
1233
1233
|
ScrShapeSlot slots[3];
|
|
1234
1234
|
} scr_shape;
|
package/src/scr_bytes.c
CHANGED
package/src/scr_closure.c
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
#include <string.h>
|
|
6
6
|
|
|
7
7
|
#ifdef SCR_RC_AUDIT
|
|
8
|
-
static long scr_live_boxes = 0;
|
|
9
|
-
static long scr_live_closures = 0;
|
|
8
|
+
static SCR_TL long scr_live_boxes = 0;
|
|
9
|
+
static SCR_TL long scr_live_closures = 0;
|
|
10
10
|
long scr_box_live_count(void) { return scr_live_boxes; }
|
|
11
11
|
long scr_closure_live_count(void) { return scr_live_closures; }
|
|
12
12
|
#endif
|
package/src/scr_console.c
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
/* Set by scr_async.c at loop exhaustion; lives here (unconditionally) so
|
|
12
12
|
* binaries that link the console without the async runtime still link, and
|
|
13
13
|
* plain builds satisfy scr_async's reference. */
|
|
14
|
-
static long scr_abandoned_fibers = 0;
|
|
14
|
+
static SCR_TL long scr_abandoned_fibers = 0;
|
|
15
15
|
void scr_note_abandoned_fibers(long n) { scr_abandoned_fibers = n; }
|
|
16
16
|
|
|
17
17
|
#ifndef SCR_LIB
|
package/src/scr_cycle.c
CHANGED
|
@@ -95,7 +95,7 @@ static void scr_cyc_oom(void) {
|
|
|
95
95
|
}
|
|
96
96
|
|
|
97
97
|
/* Live cycle-headered objects — what the full-pass trigger watches. */
|
|
98
|
-
static size_t scr_cyc_live = 0;
|
|
98
|
+
static SCR_TL size_t scr_cyc_live = 0;
|
|
99
99
|
|
|
100
100
|
void *scr_cyc_alloc(size_t size, ScrTraceFn trace, ScrCycFreeFn free_fn) {
|
|
101
101
|
ScrCycHdr *h = calloc(1, sizeof(ScrCycHdr) + size);
|
|
@@ -137,25 +137,25 @@ static void scr_cyc_push(ScrVec *vec, void *obj) {
|
|
|
137
137
|
|
|
138
138
|
/* ── the candidate-root buffers (one per generation) ──────────────────── */
|
|
139
139
|
|
|
140
|
-
static ScrVec scr_roots[SCR_CYC_NGENS];
|
|
141
|
-
static bool scr_collecting = false;
|
|
140
|
+
static SCR_TL ScrVec scr_roots[SCR_CYC_NGENS];
|
|
141
|
+
static SCR_TL bool scr_collecting = false;
|
|
142
142
|
|
|
143
143
|
/* The candidates of the pass in flight, gathered across the generations it
|
|
144
144
|
* collects so the phases can walk them without re-filtering the buffers. */
|
|
145
|
-
static ScrVec scr_cands;
|
|
145
|
+
static SCR_TL ScrVec scr_cands;
|
|
146
146
|
|
|
147
147
|
/* Nursery survivors awaiting promotion (see scr_scan_black). */
|
|
148
|
-
static ScrVec scr_promote;
|
|
148
|
+
static SCR_TL ScrVec scr_promote;
|
|
149
149
|
|
|
150
150
|
/* The gathered white set (freed after the walk completes). */
|
|
151
|
-
static ScrVec scr_white;
|
|
151
|
+
static SCR_TL ScrVec scr_white;
|
|
152
152
|
|
|
153
153
|
/* Cross-generation targets pinned by the white set (see scr_xg_pin_visit),
|
|
154
154
|
* one entry per skipped edge. Drained after the teardowns. */
|
|
155
|
-
static ScrVec scr_xgen;
|
|
155
|
+
static SCR_TL ScrVec scr_xgen;
|
|
156
156
|
|
|
157
157
|
/* Objects above this generation are invisible to the pass in flight. */
|
|
158
|
-
static unsigned scr_gen_limit = SCR_CYC_MATURE;
|
|
158
|
+
static SCR_TL unsigned scr_gen_limit = SCR_CYC_MATURE;
|
|
159
159
|
|
|
160
160
|
static size_t scr_cyc_pass(unsigned gen_limit);
|
|
161
161
|
|
|
@@ -166,10 +166,10 @@ static size_t scr_cyc_pass(unsigned gen_limit);
|
|
|
166
166
|
#define SCR_CYC_FULL_FLOOR 4096 /* ...but not below this many objects */
|
|
167
167
|
|
|
168
168
|
/* Live count as of the end of the last full pass. */
|
|
169
|
-
static size_t scr_cyc_live_after_full = 0;
|
|
169
|
+
static SCR_TL size_t scr_cyc_live_after_full = 0;
|
|
170
170
|
|
|
171
171
|
static size_t scr_cyc_nursery_threshold(void) {
|
|
172
|
-
static size_t cached = 0;
|
|
172
|
+
static SCR_TL size_t cached = 0;
|
|
173
173
|
if (cached == 0) {
|
|
174
174
|
const char *env = getenv("SCR_CYCLE_THRESHOLD");
|
|
175
175
|
long v = env ? strtol(env, NULL, 10) : 0;
|
|
@@ -186,12 +186,12 @@ static size_t scr_cyc_nursery_threshold(void) {
|
|
|
186
186
|
* hysteresis a large mature buffer — which a nursery pass cannot drain —
|
|
187
187
|
* would re-arm on every single release. Both start at zero, so the first
|
|
188
188
|
* release runs one trivial pass that arms them properly. */
|
|
189
|
-
static size_t scr_cyc_nbuffered = 0;
|
|
190
|
-
static size_t scr_cyc_trigger = 0;
|
|
189
|
+
static SCR_TL size_t scr_cyc_nbuffered = 0;
|
|
190
|
+
static SCR_TL size_t scr_cyc_trigger = 0;
|
|
191
191
|
|
|
192
192
|
/* Scheduled nursery passes for which at least one mature root was waiting.
|
|
193
193
|
* A full pass resets the age; with no mature backlog there is nothing to age. */
|
|
194
|
-
static size_t scr_cyc_scheduled_mature_age = 0;
|
|
194
|
+
static SCR_TL size_t scr_cyc_scheduled_mature_age = 0;
|
|
195
195
|
|
|
196
196
|
static size_t scr_cyc_buffered(void) {
|
|
197
197
|
return scr_roots[SCR_CYC_NURSERY].n + scr_roots[SCR_CYC_MATURE].n;
|
|
@@ -404,7 +404,7 @@ static void scr_xg_pin_visit(void *child, void *ctx) {
|
|
|
404
404
|
}
|
|
405
405
|
|
|
406
406
|
/* Freed by the cross-generation drain, for the caller's fixpoint. */
|
|
407
|
-
static size_t scr_xg_freed = 0;
|
|
407
|
+
static SCR_TL size_t scr_xg_freed = 0;
|
|
408
408
|
|
|
409
409
|
static void scr_xg_release(void *obj);
|
|
410
410
|
static void scr_xg_child_visit(void *child, void *ctx) {
|
package/src/scr_error.c
CHANGED
|
@@ -17,7 +17,7 @@ static void scr_error_oom(void) {
|
|
|
17
17
|
scr_trap("scriptc: out of memory\n");
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
static bool scr_error_traced = false;
|
|
20
|
+
static SCR_TL bool scr_error_traced = false;
|
|
21
21
|
|
|
22
22
|
void scr_error_set_traced(void) { scr_error_traced = true; }
|
|
23
23
|
|
|
@@ -49,7 +49,7 @@ static void scr_error_gcfree(void *obj) {
|
|
|
49
49
|
* must stay linkable WITHOUT the checked-dynamic tree (the runtime C-unit tests link
|
|
50
50
|
* subsets), so the drop goes through a hook scr_json.c installs before
|
|
51
51
|
* any cause can exist (scr_domex_new is the only producer). */
|
|
52
|
-
static void (*scr_domex_cause_drop)(void *obj) = NULL;
|
|
52
|
+
static SCR_TL void (*scr_domex_cause_drop)(void *obj) = NULL;
|
|
53
53
|
|
|
54
54
|
void scr_domex_install_cause_drop(void (*fn)(void *obj)) {
|
|
55
55
|
scr_domex_cause_drop = fn;
|
|
@@ -90,7 +90,7 @@ static void scr_domex_reld(void *obj) {
|
|
|
90
90
|
|
|
91
91
|
/* Defaults cover only the instants before main() stamps the program's real
|
|
92
92
|
* preorder intervals; release is permanent. */
|
|
93
|
-
ScrVt scr_error_vts[5] = {
|
|
93
|
+
SCR_TL ScrVt scr_error_vts[5] = {
|
|
94
94
|
{0, 4, &scr_error_reld}, /* Error */
|
|
95
95
|
{1, 1, &scr_error_reld}, /* TypeError */
|
|
96
96
|
{2, 2, &scr_error_reld}, /* RangeError */
|
package/src/scr_events_emitter.c
CHANGED
|
@@ -97,11 +97,11 @@ struct ScrEeReg {
|
|
|
97
97
|
* stamps pre/post from the program's preorder numbering (the
|
|
98
98
|
* scr_error_vts precedent). release is the direct teardown below. */
|
|
99
99
|
static void scr_emitter_release_direct(void *obj);
|
|
100
|
-
ScrVt scr_emitter_vt = {0, 0, &scr_emitter_release_direct};
|
|
100
|
+
SCR_TL ScrVt scr_emitter_vt = {0, 0, &scr_emitter_release_direct};
|
|
101
101
|
|
|
102
|
-
double scr_emitter_default_max = 10; /* EventEmitter.defaultMaxListeners */
|
|
102
|
+
SCR_TL double scr_emitter_default_max = 10; /* EventEmitter.defaultMaxListeners */
|
|
103
103
|
|
|
104
|
-
static bool scr_ee_trace_hint_shown = false;
|
|
104
|
+
static SCR_TL bool scr_ee_trace_hint_shown = false;
|
|
105
105
|
|
|
106
106
|
/* Post-registration hook (scr_runtime.h): the stream unit's flow kick.
|
|
107
107
|
* NULL in stream-free builds — behavior byte-identical. */
|
package/src/scr_exception.c
CHANGED
|
@@ -35,28 +35,38 @@ _Noreturn void scr_trap_fmt(const char *fmt, ...) {
|
|
|
35
35
|
}
|
|
36
36
|
#endif /* !SCR_LIB */
|
|
37
37
|
|
|
38
|
-
static ScrExcCell scr_main_exc; /* fiber zero (the main stack) */
|
|
38
|
+
static SCR_TL ScrExcCell scr_main_exc; /* fiber zero (the main stack) */
|
|
39
|
+
#if defined(SCR_LIB) && defined(SCR_THREAD_INSTANCES)
|
|
40
|
+
/* A thread-local pointer cannot be initialized with &scr_main_exc — the
|
|
41
|
+
* address of a thread-local is not a constant expression — so NULL stands
|
|
42
|
+
* for the main cell and every read resolves it. Fibers never exist in
|
|
43
|
+
* library artifacts, so the cell only ever IS the main cell here. */
|
|
44
|
+
static SCR_TL ScrExcCell *scr_cur;
|
|
45
|
+
#define SCR_EXC_CUR() (scr_cur ? scr_cur : &scr_main_exc)
|
|
46
|
+
#else
|
|
39
47
|
static ScrExcCell *scr_cur = &scr_main_exc;
|
|
48
|
+
#define SCR_EXC_CUR() (scr_cur)
|
|
49
|
+
#endif
|
|
40
50
|
|
|
41
51
|
/* Fiber switching (scr_async.c) points the exception machinery at the
|
|
42
52
|
* incoming fiber's cell; returns the previous cell. */
|
|
43
53
|
ScrExcCell *scr_exc_swap_cell(ScrExcCell *cell) {
|
|
44
|
-
ScrExcCell *prev =
|
|
54
|
+
ScrExcCell *prev = SCR_EXC_CUR();
|
|
45
55
|
scr_cur = cell ? cell : &scr_main_exc;
|
|
46
56
|
return prev;
|
|
47
57
|
}
|
|
48
58
|
|
|
49
59
|
/* The ACTIVE cell, for runtime code that moves a pending payload out of it
|
|
50
60
|
* (a new-Promise executor throw rejecting the promise). */
|
|
51
|
-
ScrExcCell *scr_exc_current_cell(void) { return
|
|
61
|
+
ScrExcCell *scr_exc_current_cell(void) { return SCR_EXC_CUR(); }
|
|
52
62
|
|
|
53
|
-
#define scr_exc_kind (
|
|
54
|
-
#define scr_exc_f64 (
|
|
55
|
-
#define scr_exc_bool (
|
|
56
|
-
#define scr_exc_payload (
|
|
57
|
-
#define scr_exc_retain_fn (
|
|
58
|
-
#define scr_exc_release_fn (
|
|
59
|
-
#define scr_exc_trace_fn (
|
|
63
|
+
#define scr_exc_kind (SCR_EXC_CUR()->kind)
|
|
64
|
+
#define scr_exc_f64 (SCR_EXC_CUR()->f64)
|
|
65
|
+
#define scr_exc_bool (SCR_EXC_CUR()->b)
|
|
66
|
+
#define scr_exc_payload (SCR_EXC_CUR()->payload)
|
|
67
|
+
#define scr_exc_retain_fn (SCR_EXC_CUR()->retain_fn)
|
|
68
|
+
#define scr_exc_release_fn (SCR_EXC_CUR()->release_fn)
|
|
69
|
+
#define scr_exc_trace_fn (SCR_EXC_CUR()->trace_fn)
|
|
60
70
|
|
|
61
71
|
bool scr_exc_pending(void) { return scr_exc_kind != SCR_EXC_NONE; }
|
|
62
72
|
|
|
@@ -187,7 +197,7 @@ ScrStr *scr_caught_to_string(const ScrCaught *c) {
|
|
|
187
197
|
* delivery; only the 0x01-led verbatim path below bypasses assembly. */
|
|
188
198
|
void scr_library_check_exc(void) {
|
|
189
199
|
if (!scr_exc_pending()) return;
|
|
190
|
-
static char buf[1024]; /* the message is copied out before the payload dies */
|
|
200
|
+
static SCR_TL char buf[1024]; /* the message is copied out before the payload dies */
|
|
191
201
|
/* The ratified verbatim rule: a thrown message that ALREADY begins with
|
|
192
202
|
* the structured trap-teaching marker (0x01) is delivered exactly as
|
|
193
203
|
* authored — no "Uncaught " prefix, no added newline — which is how a
|
|
@@ -301,7 +311,7 @@ void scr_throw_obj(void *v, void *(*retain)(void *), void (*release)(void *),
|
|
|
301
311
|
* events unit's atexit, when linked) must see that code, like Node's.
|
|
302
312
|
* Lives HERE so the unit is self-contained (the reporters below and in
|
|
303
313
|
* scr_async.c both note it; scr_events.c reads it). */
|
|
304
|
-
static int scr_exit_code_hint = 0;
|
|
314
|
+
static SCR_TL int scr_exit_code_hint = 0;
|
|
305
315
|
void scr_exit_code_note(int code) { scr_exit_code_hint = code; }
|
|
306
316
|
int scr_exit_code_hint_get(void) { return scr_exit_code_hint; }
|
|
307
317
|
|
package/src/scr_inspect.c
CHANGED
|
@@ -237,11 +237,11 @@ typedef struct {
|
|
|
237
237
|
bool all_num; /* every entry so far flagged numeric (grouping order) */
|
|
238
238
|
} InspFrame;
|
|
239
239
|
|
|
240
|
-
static InspFrame *g_frames;
|
|
241
|
-
static size_t g_nframes;
|
|
242
|
-
static size_t g_frames_cap;
|
|
243
|
-
static size_t g_indent; /* ctx.indentationLvl */
|
|
244
|
-
static double g_cur_depth; /* ctx.currentDepth (last-entered composite) */
|
|
240
|
+
static SCR_TL InspFrame *g_frames;
|
|
241
|
+
static SCR_TL size_t g_nframes;
|
|
242
|
+
static SCR_TL size_t g_frames_cap;
|
|
243
|
+
static SCR_TL size_t g_indent; /* ctx.indentationLvl */
|
|
244
|
+
static SCR_TL double g_cur_depth; /* ctx.currentDepth (last-entered composite) */
|
|
245
245
|
|
|
246
246
|
static InspFrame *insp_top(void) { return &g_frames[g_nframes - 1]; }
|
|
247
247
|
|
|
@@ -297,12 +297,12 @@ typedef struct {
|
|
|
297
297
|
int id; /* circular id (0 while only on the stack) */
|
|
298
298
|
} InspSeenEnt;
|
|
299
299
|
|
|
300
|
-
static InspSeenEnt *g_seen;
|
|
301
|
-
static size_t g_nseen;
|
|
302
|
-
static size_t g_seen_cap;
|
|
300
|
+
static SCR_TL InspSeenEnt *g_seen;
|
|
301
|
+
static SCR_TL size_t g_nseen;
|
|
302
|
+
static SCR_TL size_t g_seen_cap;
|
|
303
303
|
/* Detection-numbered circular targets (persist across the call). */
|
|
304
|
-
static const void *g_circ[64];
|
|
305
|
-
static int g_ncirc;
|
|
304
|
+
static SCR_TL const void *g_circ[64];
|
|
305
|
+
static SCR_TL int g_ncirc;
|
|
306
306
|
|
|
307
307
|
static void insp_circ_reset(void) {
|
|
308
308
|
g_nseen = 0;
|
package/src/scr_json.c
CHANGED
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
/* Live dyn-node count for the RC audit lane (-DSCR_RC_AUDIT); same contract
|
|
32
32
|
* as scr_str_live_count in scr_string.c. */
|
|
33
33
|
#ifdef SCR_RC_AUDIT
|
|
34
|
-
static long scr_live_dyns = 0;
|
|
34
|
+
static SCR_TL long scr_live_dyns = 0;
|
|
35
35
|
long scr_dyn_live_count(void) { return scr_live_dyns; }
|
|
36
36
|
#endif
|
|
37
37
|
|
|
@@ -49,7 +49,7 @@ static void scr_json_oom(void) {
|
|
|
49
49
|
/* The ScrStr block behind a non-empty buffer. */
|
|
50
50
|
#define SCR_JB_STR(b) ((ScrStr *)((char *)(b)->data - offsetof(ScrStr, data)))
|
|
51
51
|
|
|
52
|
-
static size_t scr_jb_hint = 64;
|
|
52
|
+
static SCR_TL size_t scr_jb_hint = 64;
|
|
53
53
|
|
|
54
54
|
void scr_jb_init(ScrJsonBuf *b) {
|
|
55
55
|
b->data = NULL;
|
|
@@ -280,9 +280,9 @@ void scr_jb_edge_idx(ScrJsonBuf *b, size_t i) {
|
|
|
280
280
|
* (SEMANTICS.md documents the divergence). The emitted converters over
|
|
281
281
|
* cycle-capable containers bracket their walks with enter/leave; the
|
|
282
282
|
* stack is global (conversions never interleave). */
|
|
283
|
-
static const void **g_td_seen;
|
|
284
|
-
static size_t g_td_nseen;
|
|
285
|
-
static size_t g_td_cap;
|
|
283
|
+
static SCR_TL const void **g_td_seen;
|
|
284
|
+
static SCR_TL size_t g_td_nseen;
|
|
285
|
+
static SCR_TL size_t g_td_cap;
|
|
286
286
|
|
|
287
287
|
void scr_dyn_from_enter(const void *v) {
|
|
288
288
|
for (size_t i = 0; i < g_td_nseen; i++) {
|
|
@@ -315,8 +315,8 @@ void scr_dyn_from_leave(void) {
|
|
|
315
315
|
* strict alloc/free balance.
|
|
316
316
|
*/
|
|
317
317
|
#ifndef SCR_RC_AUDIT
|
|
318
|
-
static ScrDyn *scr_dyn_free_arr, *scr_dyn_free_obj, *scr_dyn_free_misc;
|
|
319
|
-
static size_t scr_dyn_free_count;
|
|
318
|
+
static SCR_TL ScrDyn *scr_dyn_free_arr, *scr_dyn_free_obj, *scr_dyn_free_misc;
|
|
319
|
+
static SCR_TL size_t scr_dyn_free_count;
|
|
320
320
|
#define SCR_DYN_FREE_MAX 8192
|
|
321
321
|
#endif
|
|
322
322
|
|
|
@@ -818,7 +818,7 @@ ScrBytes *scr_dyn_bytes_copy_out(const ScrDyn *d) {
|
|
|
818
818
|
* Per-chunk utf8 decode: a multibyte character split across chunks does
|
|
819
819
|
* not re-join (Node's StringDecoder holds the partial byte); ASCII-clean
|
|
820
820
|
* bodies — the overwhelming test shape — are exact. */
|
|
821
|
-
static bool scr_dyn_chunk_utf8;
|
|
821
|
+
static SCR_TL bool scr_dyn_chunk_utf8;
|
|
822
822
|
void scr_dyn_chunk_enc(bool utf8) { scr_dyn_chunk_utf8 = utf8; }
|
|
823
823
|
|
|
824
824
|
/* One 'data' payload as the dyn value the current window dictates:
|
|
@@ -1122,7 +1122,7 @@ ScrDyn *scr_dyn_alloc_promise(void (*release_fn)(ScrPromise *p)) {
|
|
|
1122
1122
|
* this allocator view and installs the engine-routing ops — the
|
|
1123
1123
|
* scr_dyn_alloc_promise story: a dynamic-free link never references
|
|
1124
1124
|
* engine symbols, and JSVAL nodes exist only after an install. */
|
|
1125
|
-
static const ScrDynJsvalOps *scr_dynjs_ops = NULL;
|
|
1125
|
+
static SCR_TL const ScrDynJsvalOps *scr_dynjs_ops = NULL;
|
|
1126
1126
|
|
|
1127
1127
|
ScrDyn *scr_dyn_alloc_jsval(ScrJsval *cell, const ScrDynJsvalOps *ops) {
|
|
1128
1128
|
scr_dynjs_ops = ops;
|
|
@@ -1256,8 +1256,8 @@ typedef struct {
|
|
|
1256
1256
|
ScrDyn *dv; /* dyn entry (+1); NULL for handle/undefined entries */
|
|
1257
1257
|
} ScrDynThisEnt;
|
|
1258
1258
|
|
|
1259
|
-
static ScrDynThisEnt *scr_dyn_this_stack;
|
|
1260
|
-
static size_t scr_dyn_this_n, scr_dyn_this_cap;
|
|
1259
|
+
static SCR_TL ScrDynThisEnt *scr_dyn_this_stack;
|
|
1260
|
+
static SCR_TL size_t scr_dyn_this_n, scr_dyn_this_cap;
|
|
1261
1261
|
|
|
1262
1262
|
static ScrDynThisEnt *scr_dyn_this_grow(void) {
|
|
1263
1263
|
if (scr_dyn_this_n == scr_dyn_this_cap) {
|
|
@@ -1526,9 +1526,9 @@ typedef struct {
|
|
|
1526
1526
|
ScrDyn *dyn; /* retained */
|
|
1527
1527
|
} ScrErrDynEnt;
|
|
1528
1528
|
|
|
1529
|
-
static ScrErrDynEnt *scr_errdyn_cache = NULL;
|
|
1530
|
-
static size_t scr_errdyn_n = 0, scr_errdyn_cap = 0;
|
|
1531
|
-
static bool scr_errdyn_teardown_registered = false;
|
|
1529
|
+
static SCR_TL ScrErrDynEnt *scr_errdyn_cache = NULL;
|
|
1530
|
+
static SCR_TL size_t scr_errdyn_n = 0, scr_errdyn_cap = 0;
|
|
1531
|
+
static SCR_TL bool scr_errdyn_teardown_registered = false;
|
|
1532
1532
|
|
|
1533
1533
|
static void scr_errdyn_teardown(void) {
|
|
1534
1534
|
for (size_t i = 0; i < scr_errdyn_n; i++) {
|
package/src/scr_lib.c
CHANGED
|
@@ -104,14 +104,14 @@ extern char **environ; /* env snapshot (scr_env_pairs) */
|
|
|
104
104
|
|
|
105
105
|
/* ── process ─────────────────────────────────────────────────────────── */
|
|
106
106
|
|
|
107
|
-
static int scr_lib_argc = 0;
|
|
108
|
-
static char **scr_lib_argv = NULL;
|
|
109
|
-
static ScrArr *scr_argv_arr = NULL; /* interned process.argv */
|
|
110
|
-
static ScrStr *scr_platform_str = NULL; /* interned process.platform */
|
|
111
|
-
static ScrStr *scr_exec_path_str = NULL; /* interned process.execPath */
|
|
112
|
-
static ScrStr *scr_arch_str = NULL; /* interned process.arch */
|
|
113
|
-
static ScrStr *scr_versions_node_str = NULL; /* interned process.versions.node */
|
|
114
|
-
static ScrStr *scr_versions_openssl_str = NULL; /* interned process.versions.openssl */
|
|
107
|
+
static SCR_TL int scr_lib_argc = 0;
|
|
108
|
+
static SCR_TL char **scr_lib_argv = NULL;
|
|
109
|
+
static SCR_TL ScrArr *scr_argv_arr = NULL; /* interned process.argv */
|
|
110
|
+
static SCR_TL ScrStr *scr_platform_str = NULL; /* interned process.platform */
|
|
111
|
+
static SCR_TL ScrStr *scr_exec_path_str = NULL; /* interned process.execPath */
|
|
112
|
+
static SCR_TL ScrStr *scr_arch_str = NULL; /* interned process.arch */
|
|
113
|
+
static SCR_TL ScrStr *scr_versions_node_str = NULL; /* interned process.versions.node */
|
|
114
|
+
static SCR_TL ScrStr *scr_versions_openssl_str = NULL; /* interned process.versions.openssl */
|
|
115
115
|
|
|
116
116
|
static void scr_lib_cleanup(void) {
|
|
117
117
|
scr_arr_release(scr_argv_arr);
|
|
@@ -1103,8 +1103,27 @@ void scr_process_exit(double code) {
|
|
|
1103
1103
|
* attribute monotonic stamp — the binary's own start, which is what
|
|
1104
1104
|
* "the current Node.js process" means for a compiled program). */
|
|
1105
1105
|
#ifdef _WIN32
|
|
1106
|
+
#if defined(SCR_LIB) && defined(SCR_THREAD_INSTANCES)
|
|
1107
|
+
/* The uptime anchor belongs to the host PROCESS, not to a library
|
|
1108
|
+
* instance. InitOnce keeps the lazy Windows spelling race-free when
|
|
1109
|
+
* several thread instances ask for the clock concurrently. */
|
|
1110
|
+
static INIT_ONCE scr_uptime_once = INIT_ONCE_STATIC_INIT;
|
|
1106
1111
|
static double scr_uptime_t0_ms;
|
|
1112
|
+
static BOOL CALLBACK scr_uptime_anchor_once(PINIT_ONCE once, PVOID param,
|
|
1113
|
+
PVOID *ctx) {
|
|
1114
|
+
(void)once;
|
|
1115
|
+
(void)param;
|
|
1116
|
+
(void)ctx;
|
|
1117
|
+
scr_uptime_t0_ms = (double)GetTickCount64();
|
|
1118
|
+
return TRUE;
|
|
1119
|
+
}
|
|
1120
|
+
static void scr_uptime_anchor_init(void) {
|
|
1121
|
+
InitOnceExecuteOnce(&scr_uptime_once, scr_uptime_anchor_once, NULL, NULL);
|
|
1122
|
+
}
|
|
1123
|
+
#else
|
|
1124
|
+
static SCR_TL double scr_uptime_t0_ms;
|
|
1107
1125
|
static void scr_uptime_anchor_init(void) { scr_uptime_t0_ms = (double)GetTickCount64(); }
|
|
1126
|
+
#endif
|
|
1108
1127
|
static double scr_uptime_now_ms(void) { return (double)GetTickCount64(); }
|
|
1109
1128
|
#else
|
|
1110
1129
|
#include <sys/resource.h>
|
|
@@ -1112,6 +1131,10 @@ static double scr_uptime_now_ms(void) { return (double)GetTickCount64(); }
|
|
|
1112
1131
|
#ifdef __APPLE__
|
|
1113
1132
|
#include <mach/mach.h>
|
|
1114
1133
|
#endif
|
|
1134
|
+
/* A load-time, process-wide anchor: the constructor runs on only the
|
|
1135
|
+
* initial thread, while thread-instanced archives are entered from worker
|
|
1136
|
+
* threads whose TLS slots would otherwise stay zero. It is immutable once
|
|
1137
|
+
* main starts, so sharing it adds no cross-instance mutable state. */
|
|
1115
1138
|
static double scr_uptime_t0_ms;
|
|
1116
1139
|
static double scr_uptime_now_ms(void) {
|
|
1117
1140
|
struct timespec ts;
|
|
@@ -1124,7 +1147,9 @@ __attribute__((constructor)) static void scr_uptime_anchor_init(void) {
|
|
|
1124
1147
|
#endif
|
|
1125
1148
|
|
|
1126
1149
|
double scr_process_uptime(void) {
|
|
1127
|
-
#
|
|
1150
|
+
#if defined(_WIN32) && defined(SCR_LIB) && defined(SCR_THREAD_INSTANCES)
|
|
1151
|
+
scr_uptime_anchor_init();
|
|
1152
|
+
#elif defined(_WIN32)
|
|
1128
1153
|
if (scr_uptime_t0_ms == 0) scr_uptime_anchor_init();
|
|
1129
1154
|
#endif
|
|
1130
1155
|
return (scr_uptime_now_ms() - scr_uptime_t0_ms) / 1000.0;
|
|
@@ -1134,7 +1159,9 @@ double scr_process_uptime(void) {
|
|
|
1134
1159
|
* start (Node's timeOrigin anchor), fractional — the same monotonic
|
|
1135
1160
|
* clock and anchor as uptime, in Node's performance.now units. */
|
|
1136
1161
|
double scr_perf_now(void) {
|
|
1137
|
-
#
|
|
1162
|
+
#if defined(_WIN32) && defined(SCR_LIB) && defined(SCR_THREAD_INSTANCES)
|
|
1163
|
+
scr_uptime_anchor_init();
|
|
1164
|
+
#elif defined(_WIN32)
|
|
1138
1165
|
if (scr_uptime_t0_ms == 0) scr_uptime_anchor_init();
|
|
1139
1166
|
#endif
|
|
1140
1167
|
return scr_uptime_now_ms() - scr_uptime_t0_ms;
|
|
@@ -1353,7 +1380,7 @@ double scr_available_memory(void) {
|
|
|
1353
1380
|
/* process._exiting — true once the exit sequence began (set above and by
|
|
1354
1381
|
* scr_run_exit_listeners in scr_events.c; the flag lives HERE so reading
|
|
1355
1382
|
* it never forces the events unit into the link). */
|
|
1356
|
-
bool scr_process_in_exit = false;
|
|
1383
|
+
SCR_TL bool scr_process_in_exit = false;
|
|
1357
1384
|
|
|
1358
1385
|
bool scr_process_exiting(void) { return scr_process_in_exit; }
|
|
1359
1386
|
|
|
@@ -1372,7 +1399,7 @@ double scr_process_umask(double mask) {
|
|
|
1372
1399
|
}
|
|
1373
1400
|
return (double)prev;
|
|
1374
1401
|
#elif defined(__wasi__)
|
|
1375
|
-
static mode_t current = 022;
|
|
1402
|
+
static SCR_TL mode_t current = 022;
|
|
1376
1403
|
mode_t prev = current;
|
|
1377
1404
|
if (mask >= 0) current = (mode_t)mask;
|
|
1378
1405
|
return (double)prev;
|
|
@@ -1399,7 +1426,7 @@ void scr_process_chdir(ScrStr *dir) {
|
|
|
1399
1426
|
/* net's process-wide happy-eyeballs attempt budget (Node's
|
|
1400
1427
|
* getDefaultAutoSelectFamilyAttemptTimeout pair, default 250ms). Lives in
|
|
1401
1428
|
* the core unit so the knob never forces scr_net.c into the link. */
|
|
1402
|
-
static double scr_net_autosel_timeout_ms = 250;
|
|
1429
|
+
static SCR_TL double scr_net_autosel_timeout_ms = 250;
|
|
1403
1430
|
|
|
1404
1431
|
double scr_net_get_autosel_timeout(void) { return scr_net_autosel_timeout_ms; }
|
|
1405
1432
|
|
|
@@ -2745,8 +2772,8 @@ double scr_process_columns(double fd) {
|
|
|
2745
2772
|
* NON-TTY stdin: Node's process.stdin is a Socket with no setRawMode
|
|
2746
2773
|
* member at all, so the call throws Node's exact catchable TypeError. */
|
|
2747
2774
|
#ifdef _WIN32
|
|
2748
|
-
static DWORD scr_stdin_cooked;
|
|
2749
|
-
static bool scr_stdin_cooked_saved = false;
|
|
2775
|
+
static SCR_TL DWORD scr_stdin_cooked;
|
|
2776
|
+
static SCR_TL bool scr_stdin_cooked_saved = false;
|
|
2750
2777
|
|
|
2751
2778
|
void scr_process_stdin_set_raw_mode(bool raw) {
|
|
2752
2779
|
if (!isatty(0)) {
|
|
@@ -2778,8 +2805,8 @@ void scr_process_stdin_set_raw_mode(bool raw) {
|
|
|
2778
2805
|
scr_throw_error_msg(SCR_ERR_TYPE, msg, sizeof msg - 1);
|
|
2779
2806
|
}
|
|
2780
2807
|
#else
|
|
2781
|
-
static struct termios scr_stdin_cooked;
|
|
2782
|
-
static bool scr_stdin_cooked_saved = false;
|
|
2808
|
+
static SCR_TL struct termios scr_stdin_cooked;
|
|
2809
|
+
static SCR_TL bool scr_stdin_cooked_saved = false;
|
|
2783
2810
|
|
|
2784
2811
|
void scr_process_stdin_set_raw_mode(bool raw) {
|
|
2785
2812
|
if (!isatty(0)) {
|
package/src/scr_library.c
CHANGED
|
@@ -10,6 +10,24 @@
|
|
|
10
10
|
* profile-agnostic and the program TU carries every profile-named symbol —
|
|
11
11
|
* one place for the conformance symbol audit to look.
|
|
12
12
|
*
|
|
13
|
+
* Multi-instance processes (the profile's abi.localize_runtime): the
|
|
14
|
+
* archive build demotes this file's externals — and every other runtime
|
|
15
|
+
* internal — to LOCAL symbols, so each linked archive carries its own
|
|
16
|
+
* private copy of all the state here: its own sink registration, poison
|
|
17
|
+
* flag, arena, and entry-symbol slot. Sinks therefore register per
|
|
18
|
+
* instance, and a trap poisons only the instance it fired in. Nothing in
|
|
19
|
+
* this file is thread-aware; the embedder contract is one thread per
|
|
20
|
+
* instance (an instance is never entered from two threads).
|
|
21
|
+
*
|
|
22
|
+
* Thread-instanced archives (the profile's abi.instance_per_thread) take
|
|
23
|
+
* the same story one level down: SCR_TL moves this file's state — and
|
|
24
|
+
* every other mutable static in the archive — into thread-local storage,
|
|
25
|
+
* so ONE linked archive serves one independent instance per embedder
|
|
26
|
+
* thread. A thread registers its own sink and calls the init entry before
|
|
27
|
+
* serving; its trap poisons only its own instance while sibling threads'
|
|
28
|
+
* instances keep answering. The one-thread-per-instance contract is
|
|
29
|
+
* unchanged — the calling thread IS the instance selector.
|
|
30
|
+
*
|
|
13
31
|
* State after a sink call: none is legal. The trap fired mid-operation with
|
|
14
32
|
* no unwinding — heap, arena, and collector state are unspecified; the library
|
|
15
33
|
* is POISONED. Every runtime-touching entry prologue aborts on the flag
|
|
@@ -23,9 +41,9 @@
|
|
|
23
41
|
|
|
24
42
|
/* ── sink registration + poison ───────────────────────────────────────── */
|
|
25
43
|
|
|
26
|
-
static ScrLibSinkFn scr_library_sink = NULL;
|
|
27
|
-
static void *scr_library_sink_ctx = NULL;
|
|
28
|
-
static bool scr_library_poisoned = false;
|
|
44
|
+
static SCR_TL ScrLibSinkFn scr_library_sink = NULL;
|
|
45
|
+
static SCR_TL void *scr_library_sink_ctx = NULL;
|
|
46
|
+
static SCR_TL bool scr_library_poisoned = false;
|
|
29
47
|
|
|
30
48
|
void scr_library_set_sink(ScrLibSinkFn fn, void *ctx) {
|
|
31
49
|
/* Latest registration wins; re-registration is permitted before a trap.
|
|
@@ -62,10 +80,12 @@ void scr_library_set_sink(ScrLibSinkFn fn, void *ctx) {
|
|
|
62
80
|
|
|
63
81
|
/* The current-entry slot: every generated entry's prologue records its
|
|
64
82
|
* external symbol before dispatching into core code. A single static slot
|
|
65
|
-
* is sound — exactly one core is live per
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
|
|
83
|
+
* is sound — exactly one core is live per copy of this state (the sole
|
|
84
|
+
* core in a classic process; each archive's own instance under
|
|
85
|
+
* abi.localize_runtime, where this slot is a per-instance local), entries
|
|
86
|
+
* never nest, and a trap can only fire while an entry is on the stack.
|
|
87
|
+
* NULL (never entered) renders as the empty symbol field. */
|
|
88
|
+
static SCR_TL const char *scr_library_entry_symbol = NULL;
|
|
69
89
|
|
|
70
90
|
/* Detected-trap classification: the runtime's trap sites self-classify
|
|
71
91
|
* through their message conventions (the exact bytes the executable lane
|
|
@@ -103,7 +123,7 @@ static _Noreturn void scr_library_trap_deliver(const char *msg, size_t len, uint
|
|
|
103
123
|
* no malloc on the failure path; text truncates before structure ever
|
|
104
124
|
* would (codes and symbols are short; an oversized remediation drops
|
|
105
125
|
* whole, never split). */
|
|
106
|
-
static char buf[2048];
|
|
126
|
+
static SCR_TL char buf[2048];
|
|
107
127
|
const char *code = scr_library_trap_code(msg, len);
|
|
108
128
|
const char *text = msg;
|
|
109
129
|
size_t text_len = len;
|
|
@@ -168,7 +188,7 @@ __attribute__((noinline)) _Noreturn void scr_trap_len(const char *msg, size_t le
|
|
|
168
188
|
}
|
|
169
189
|
|
|
170
190
|
__attribute__((noinline)) _Noreturn void scr_trap_fmt(const char *fmt, ...) {
|
|
171
|
-
static char buf[512]; /* no malloc on the invariant-failure path */
|
|
191
|
+
static SCR_TL char buf[512]; /* no malloc on the invariant-failure path */
|
|
172
192
|
va_list ap;
|
|
173
193
|
va_start(ap, fmt);
|
|
174
194
|
int n = vsnprintf(buf, sizeof buf, fmt, ap);
|
|
@@ -202,8 +222,8 @@ typedef struct {
|
|
|
202
222
|
bool is_str; /* ScrStr vs ScrBytes — picks the release */
|
|
203
223
|
} ScrCoreArenaEnt;
|
|
204
224
|
|
|
205
|
-
static ScrCoreArenaEnt *scr_library_arena = NULL;
|
|
206
|
-
static size_t scr_library_arena_n = 0, scr_library_arena_cap = 0;
|
|
225
|
+
static SCR_TL ScrCoreArenaEnt *scr_library_arena = NULL;
|
|
226
|
+
static SCR_TL size_t scr_library_arena_n = 0, scr_library_arena_cap = 0;
|
|
207
227
|
|
|
208
228
|
static void scr_library_arena_keep(void *v, bool is_str) {
|
|
209
229
|
if (scr_library_arena_n == scr_library_arena_cap) {
|
|
@@ -285,8 +305,8 @@ void scr_library_bytes_out(ScrBytes *b, const uint8_t **out, size_t *out_len) {
|
|
|
285
305
|
* satisfied because the entry persists. */
|
|
286
306
|
|
|
287
307
|
#define SCR_LIB_MAX_RESETS 32
|
|
288
|
-
static void (*scr_library_resets[SCR_LIB_MAX_RESETS])(void);
|
|
289
|
-
static size_t scr_library_nresets = 0;
|
|
308
|
+
static SCR_TL void (*scr_library_resets[SCR_LIB_MAX_RESETS])(void);
|
|
309
|
+
static SCR_TL size_t scr_library_nresets = 0;
|
|
290
310
|
|
|
291
311
|
void scr_library_register_reset(void (*fn)(void)) {
|
|
292
312
|
for (size_t i = 0; i < scr_library_nresets; i++) {
|
package/src/scr_map.c
CHANGED
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
/* Live heap-map count for the RC audit lane (-DSCR_RC_AUDIT); same contract
|
|
25
25
|
* as scr_str_live_count in scr_string.c. */
|
|
26
26
|
#ifdef SCR_RC_AUDIT
|
|
27
|
-
static long scr_live_maps = 0;
|
|
27
|
+
static SCR_TL long scr_live_maps = 0;
|
|
28
28
|
long scr_map_live_count(void) { return scr_live_maps; }
|
|
29
29
|
#endif
|
|
30
30
|
|
package/src/scr_object.c
CHANGED
|
@@ -33,7 +33,7 @@ void scr_record_key_miss(ScrStr *k) {
|
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
#ifdef SCR_RC_AUDIT
|
|
36
|
-
static long scr_live_objects = 0;
|
|
36
|
+
static SCR_TL long scr_live_objects = 0;
|
|
37
37
|
long scr_obj_live_count(void) { return scr_live_objects; }
|
|
38
38
|
void scr_obj_alloc_note(void) { scr_live_objects++; }
|
|
39
39
|
void scr_obj_free_note(void) { scr_live_objects--; }
|
package/src/scr_regex.c
CHANGED
|
@@ -82,8 +82,8 @@ void *lre_realloc(void *opaque, void *ptr, size_t size) {
|
|
|
82
82
|
* allocation audit sees the bytecode gone).
|
|
83
83
|
*/
|
|
84
84
|
|
|
85
|
-
static ScrRegex **scr_compiled = NULL;
|
|
86
|
-
static size_t scr_compiled_len = 0, scr_compiled_cap = 0;
|
|
85
|
+
static SCR_TL ScrRegex **scr_compiled = NULL;
|
|
86
|
+
static SCR_TL size_t scr_compiled_len = 0, scr_compiled_cap = 0;
|
|
87
87
|
|
|
88
88
|
static void scr_regex_free_bytecodes(void) {
|
|
89
89
|
for (size_t i = 0; i < scr_compiled_len; i++) {
|
package/src/scr_runtime.h
CHANGED
|
@@ -29,6 +29,24 @@ char *strcasestr(const char *hay, const char *needle);
|
|
|
29
29
|
void arc4random_buf(void *buf, size_t n);
|
|
30
30
|
#endif
|
|
31
31
|
|
|
32
|
+
/* ── thread-instanced library state ─────────────────────────────────────
|
|
33
|
+
* Archives built under the profile's abi.instance_per_thread compile every
|
|
34
|
+
* TU with -DSCR_THREAD_INSTANCES, and SCR_TL moves each unit's mutable
|
|
35
|
+
* state — and the emitted program's globals — into thread-local storage.
|
|
36
|
+
* A thread that calls the profile's init entry then owns a complete,
|
|
37
|
+
* independent instance: its own collector, result arena, panic-sink
|
|
38
|
+
* registration, poison flag, and program state. The instance's lifetime is
|
|
39
|
+
* the thread's; the one-thread-per-instance contract (an instance is never
|
|
40
|
+
* entered from two threads) is unchanged — this mode adds instances, not
|
|
41
|
+
* thread awareness. Expands to nothing everywhere else, so executable
|
|
42
|
+
* builds and classic library builds carry the exact bytes they always
|
|
43
|
+
* carried. Truly immutable tables (static const data) stay shared. */
|
|
44
|
+
#if defined(SCR_LIB) && defined(SCR_THREAD_INSTANCES)
|
|
45
|
+
#define SCR_TL _Thread_local
|
|
46
|
+
#else
|
|
47
|
+
#define SCR_TL
|
|
48
|
+
#endif
|
|
49
|
+
|
|
32
50
|
/* ── process ──────────────────────────────────────────────────────────── */
|
|
33
51
|
|
|
34
52
|
/* Called once at the top of main: private stdout formatter buffer,
|
|
@@ -445,7 +463,7 @@ enum {
|
|
|
445
463
|
SCR_ERR_DOMEX = 4, /* DOMException — ScrDomException, the wider layout */
|
|
446
464
|
};
|
|
447
465
|
|
|
448
|
-
extern ScrVt scr_error_vts[5]; /* indexed by SCR_ERR_*; main() stamps pre/post */
|
|
466
|
+
extern SCR_TL ScrVt scr_error_vts[5]; /* indexed by SCR_ERR_*; main() stamps pre/post */
|
|
449
467
|
|
|
450
468
|
struct ScrDyn; /* full declaration below (the checked-dynamic tree section) */
|
|
451
469
|
|
|
@@ -1373,8 +1391,8 @@ typedef struct ScrEmitter {
|
|
|
1373
1391
|
const char *cls; /* display name for the leak warning ("EventEmitter") */
|
|
1374
1392
|
} ScrEmitter;
|
|
1375
1393
|
|
|
1376
|
-
extern ScrVt scr_emitter_vt; /* main() stamps pre/post */
|
|
1377
|
-
extern double scr_emitter_default_max;
|
|
1394
|
+
extern SCR_TL ScrVt scr_emitter_vt; /* main() stamps pre/post */
|
|
1395
|
+
extern SCR_TL double scr_emitter_default_max;
|
|
1378
1396
|
|
|
1379
1397
|
ScrEmitter *scr_emitter_new(void); /* +1, collector-headered */
|
|
1380
1398
|
void scr_emitter_init(void *obj); /* super() into the prefix (no-op today) */
|
|
@@ -1976,7 +1994,7 @@ bool scr_process_kill_named(double pid, const ScrStr *signal);
|
|
|
1976
1994
|
void scr_process_exit(double code);
|
|
1977
1995
|
/* process._exiting: true once the exit sequence began (process.exit or
|
|
1978
1996
|
* the exit-listener runner set the flag). Never throws. */
|
|
1979
|
-
extern bool scr_process_in_exit;
|
|
1997
|
+
extern SCR_TL bool scr_process_in_exit;
|
|
1980
1998
|
bool scr_process_exiting(void);
|
|
1981
1999
|
/* umask(2): mask < 0 reads without setting; otherwise sets and answers
|
|
1982
2000
|
* the previous mask. Never throws. */
|
package/src/scr_string.c
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* leaks nothing and frees nothing twice (double-free shows up as ASan
|
|
11
11
|
* use-after-free on the rc field or a negative count here). */
|
|
12
12
|
#ifdef SCR_RC_AUDIT
|
|
13
|
-
static long scr_live_strings = 0;
|
|
13
|
+
static SCR_TL long scr_live_strings = 0;
|
|
14
14
|
long scr_str_live_count(void) { return scr_live_strings; }
|
|
15
15
|
#endif
|
|
16
16
|
|
|
@@ -41,8 +41,8 @@ typedef struct {
|
|
|
41
41
|
size_t u16len; /* SCR_U16_UNKNOWN until computed */
|
|
42
42
|
size_t cu, cb; /* cursor: byte offset cb starts the char at unit cu */
|
|
43
43
|
} ScrSidx;
|
|
44
|
-
static ScrSidx scr_sidx_tab[SCR_SIDX_N];
|
|
45
|
-
static unsigned scr_sidx_clock;
|
|
44
|
+
static SCR_TL ScrSidx scr_sidx_tab[SCR_SIDX_N];
|
|
45
|
+
static SCR_TL unsigned scr_sidx_clock;
|
|
46
46
|
|
|
47
47
|
static void scr_sidx_purge(const ScrStr *s) {
|
|
48
48
|
for (int i = 0; i < SCR_SIDX_N; i++) {
|
|
@@ -90,7 +90,7 @@ ScrStr *scr_str_new(const char *bytes, size_t len) {
|
|
|
90
90
|
* blocks instead of paging in fresh zero-filled memory 40k times. Disabled
|
|
91
91
|
* in the audit lane so ASan sees every logical free as a real free. */
|
|
92
92
|
#ifndef SCR_RC_AUDIT
|
|
93
|
-
static ScrStr *scr_str_spare;
|
|
93
|
+
static SCR_TL ScrStr *scr_str_spare;
|
|
94
94
|
#endif
|
|
95
95
|
|
|
96
96
|
/* A spare-block reuse must not waste grossly (cap <= 4x the need) and only
|
package/src/scr_symbol.c
CHANGED
|
@@ -55,7 +55,7 @@ ScrSym *scr_sym_new(ScrStr *desc) {
|
|
|
55
55
|
|
|
56
56
|
/* ── the Symbol.for global registry ──────────────────────────────────── */
|
|
57
57
|
|
|
58
|
-
static ScrSym *g_sym_registry = NULL;
|
|
58
|
+
static SCR_TL ScrSym *g_sym_registry = NULL;
|
|
59
59
|
|
|
60
60
|
static void scr_sym_registry_cleanup(void) {
|
|
61
61
|
ScrSym *s = g_sym_registry;
|
package/src/scr_union.c
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
/* Live union count for the RC audit lane (-DSCR_RC_AUDIT); same contract
|
|
16
16
|
* as scr_str_live_count in scr_string.c. */
|
|
17
17
|
#ifdef SCR_RC_AUDIT
|
|
18
|
-
static long scr_live_unions = 0;
|
|
18
|
+
static SCR_TL long scr_live_unions = 0;
|
|
19
19
|
long scr_union_live_count(void) { return scr_live_unions; }
|
|
20
20
|
#endif
|
|
21
21
|
|