@scriptc/runtime 0.0.21 → 0.0.23
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_assert.c +23 -0
- package/src/scr_async.c +5 -2
- package/src/scr_bytes.c +7 -0
- package/src/scr_cycle.c +403 -62
- package/src/scr_dyn_invoke.c +58 -6
- package/src/scr_fetch.c +6200 -124
- package/src/scr_fetch_curl.c +21 -9
- package/src/scr_http.c +13 -0
- package/src/scr_inspect.c +6 -0
- package/src/scr_island.c +19 -0
- package/src/scr_json.c +413 -9
- package/src/scr_lib.c +277 -18
- package/src/scr_runtime.h +211 -27
- package/src/scr_tls.c +15 -11
- package/src/scr_tls_ca.c +35 -8
- package/src/scr_url.c +103 -15
- package/src/scr_web.c +77 -1
- package/vendor/README.md +4 -4
package/src/scr_runtime.h
CHANGED
|
@@ -197,9 +197,15 @@ void scr_library_bytes_out(ScrBytes *b, const uint8_t **out, size_t *out_len);
|
|
|
197
197
|
* collection walks the buffer (markGray: trial-decrement internal edges;
|
|
198
198
|
* scan: restore externally-referenced subgraphs; collectWhite: free the
|
|
199
199
|
* dead cycle members, releasing only edges that LEAVE the white set).
|
|
200
|
-
*
|
|
201
|
-
*
|
|
202
|
-
*
|
|
200
|
+
* It is GENERATIONAL: each header carries a generation, a pass names the
|
|
201
|
+
* oldest one it will walk, and objects that survive a pass are promoted out
|
|
202
|
+
* of the nursery so later nursery passes never re-walk them. That is what
|
|
203
|
+
* keeps a pass proportional to recent allocation rather than to the whole
|
|
204
|
+
* live heap — see the generation note in scr_cycle.c for the soundness
|
|
205
|
+
* argument and the schedule. Collection points: program exit (before the RC
|
|
206
|
+
* audit), event-loop quiescence, and the per-generation triggers.
|
|
207
|
+
* SCR_CYCLE_THRESHOLD pins the nursery trigger to a fixed candidate count.
|
|
208
|
+
* There is no concurrent or incremental collection.
|
|
203
209
|
*
|
|
204
210
|
* Contract for trace/teardown pairs (the compiler emits them for shapes,
|
|
205
211
|
* the runtime owns its own): trace(obj) visits exactly the strong
|
|
@@ -214,16 +220,44 @@ typedef void (*ScrTraceVisit)(void *child, void *ctx);
|
|
|
214
220
|
typedef void (*ScrTraceFn)(void *obj, ScrTraceVisit visit, void *ctx);
|
|
215
221
|
typedef void (*ScrCycFreeFn)(void *obj);
|
|
216
222
|
|
|
217
|
-
|
|
223
|
+
/* DOOMED is WHITE that collectWhite has already gathered: it stops the
|
|
224
|
+
* gather recursing twice, and distinguishes "about to be freed" from a
|
|
225
|
+
* survivor for the re-buffering step (see scr_cycle.c). */
|
|
226
|
+
enum {
|
|
227
|
+
SCR_CYC_BLACK = 0, SCR_CYC_PURPLE = 1, SCR_CYC_GRAY = 2, SCR_CYC_WHITE = 3,
|
|
228
|
+
SCR_CYC_DOOMED = 4
|
|
229
|
+
};
|
|
230
|
+
|
|
231
|
+
/* Generations. A candidate sits in the buffer named by its own `gen`, and a
|
|
232
|
+
* pass walks only objects at or below the generation it collects. */
|
|
233
|
+
enum { SCR_CYC_NURSERY = 0, SCR_CYC_MATURE = 1, SCR_CYC_NGENS = 2 };
|
|
218
234
|
|
|
219
235
|
typedef struct ScrCycHdr {
|
|
220
236
|
ScrTraceFn trace;
|
|
221
237
|
ScrCycFreeFn free_fn;
|
|
222
238
|
uint32_t color; /* SCR_CYC_* */
|
|
223
|
-
|
|
239
|
+
uint16_t buffered; /* 1 = sitting in its generation's candidate buffer */
|
|
240
|
+
uint16_t gen; /* SCR_CYC_NURSERY..SCR_CYC_MATURE (the walk filter) */
|
|
224
241
|
size_t buf_index; /* position there (O(1) removal when rc hits 0) */
|
|
225
242
|
} ScrCycHdr;
|
|
226
243
|
|
|
244
|
+
/* This layout is an ABI, not an implementation detail: the LLVM backend
|
|
245
|
+
* inlines scr_cyc_mark_live as a raw `store i32 0` at obj-16 (it is a
|
|
246
|
+
* static inline here, so there is no symbol to call) and reaches the header
|
|
247
|
+
* at obj-32. Three sites emit it — llvm/shapes.ts, llvm/classes.ts,
|
|
248
|
+
* llvm/emitter.ts. Nothing but `color` may share those four bytes: a field
|
|
249
|
+
* placed in them is silently zeroed by every retain, which is invisible to
|
|
250
|
+
* the type system and to the C compiler. Hence the assertions. */
|
|
251
|
+
_Static_assert(sizeof(ScrCycHdr) == 32, "LLVM backend reads the header at obj-32");
|
|
252
|
+
_Static_assert(offsetof(ScrCycHdr, color) == 16,
|
|
253
|
+
"LLVM backend's inlined mark-live stores i32 0 at obj-16");
|
|
254
|
+
_Static_assert(sizeof(((ScrCycHdr *)0)->color) == 4,
|
|
255
|
+
"mark-live is an i32 store: color must own all four bytes");
|
|
256
|
+
_Static_assert(SCR_CYC_BLACK == 0,
|
|
257
|
+
"the emitted mark-live stores the LITERAL 0, not the enumerator "
|
|
258
|
+
"— reordering the colors would make every compiled retain write "
|
|
259
|
+
"the wrong one");
|
|
260
|
+
|
|
227
261
|
static inline ScrCycHdr *scr_cyc_hdr(void *obj) { return (ScrCycHdr *)obj - 1; }
|
|
228
262
|
|
|
229
263
|
/* Zeroed allocation with a cycle header in front; returns the OBJECT
|
|
@@ -243,9 +277,18 @@ static inline void scr_cyc_mark_live(void *obj) {
|
|
|
243
277
|
scr_cyc_hdr(obj)->color = SCR_CYC_BLACK;
|
|
244
278
|
}
|
|
245
279
|
|
|
246
|
-
/*
|
|
280
|
+
/* Full sweep: trial-deletion passes over EVERY generation, to a fixpoint.
|
|
281
|
+
* This is the exit / session-reset entry point (the RC audit runs straight
|
|
282
|
+
* after and wants nothing reclaimable left), and it costs a walk of the
|
|
283
|
+
* live heap — do not put it on a per-turn path. */
|
|
247
284
|
void scr_collect_cycles(void);
|
|
248
285
|
|
|
286
|
+
/* One pass on the normal generational schedule, for callers that reach a
|
|
287
|
+
* natural collection point rather than a threshold (the event loop between
|
|
288
|
+
* turns). Cheap: usually a nursery pass; a waiting mature backlog ages into
|
|
289
|
+
* a bounded full pass so sparse roots cannot float forever. */
|
|
290
|
+
void scr_cyc_collect_scheduled(void);
|
|
291
|
+
|
|
249
292
|
/* ── class hierarchies (single inheritance) ───────────────────────────
|
|
250
293
|
* Classes in an `extends` hierarchy share a two-word object prefix: the
|
|
251
294
|
* usual `size_t rc`, then a pointer to the class's static vtable (emitted
|
|
@@ -2416,7 +2459,10 @@ ScrStr *scr_path_win32_to_namespaced_path(ScrStr *path);
|
|
|
2416
2459
|
* (failure throws the path-less "EBADF: bad file descriptor, close").
|
|
2417
2460
|
* The pair behind spawn's fd-stdio form. */
|
|
2418
2461
|
double scr_fs_open(ScrStr *path, ScrStr *flags);
|
|
2419
|
-
|
|
2462
|
+
/* position == -1 reads from and advances the descriptor's current offset;
|
|
2463
|
+
* nonnegative positions leave that offset unchanged (pread/ReadFile seam). */
|
|
2464
|
+
double scr_fs_read_sync(double fd, ScrBytes *buf, double offset, double length,
|
|
2465
|
+
double position);
|
|
2420
2466
|
void scr_fs_close(double fd);
|
|
2421
2467
|
|
|
2422
2468
|
/* ── WHATWG URL (scr_url.c) ──────────────────────────────────────────
|
|
@@ -2683,9 +2729,15 @@ typedef enum {
|
|
|
2683
2729
|
* a silent wrong answer. The dyn→cell edge is NOT visible to the cycle
|
|
2684
2730
|
* collector (the dyn→closure stance): a cycle dyn → cell → engine
|
|
2685
2731
|
* object → host closure → dyn is merely never collected (the
|
|
2686
|
-
* documented cross-boundary-cycle divergence).
|
|
2687
|
-
* the LLVM backend hardcodes the preceding kind numbers. */
|
|
2732
|
+
* documented cross-boundary-cycle divergence). */
|
|
2688
2733
|
SCR_DYN_JSVAL,
|
|
2734
|
+
/* A compiler-owned typed reference in transit through a native Web
|
|
2735
|
+
* stream. Unlike an ordinary typed→unknown conversion, this capsule
|
|
2736
|
+
* retains the original value so a statically typed reader can recover
|
|
2737
|
+
* its identity. `materialize` supplies the ordinary deep-copy view for
|
|
2738
|
+
* consumers such as fetch request bodies that need a dyn chunk. Enum
|
|
2739
|
+
* position: LAST — LLVM hardcodes every preceding kind number. */
|
|
2740
|
+
SCR_DYN_TYPED_REF,
|
|
2689
2741
|
} ScrDynKind;
|
|
2690
2742
|
|
|
2691
2743
|
/* The handle-type tags the checked-dynamic tree can carry. The set is deliberately the
|
|
@@ -2701,12 +2753,28 @@ typedef enum {
|
|
|
2701
2753
|
SCR_DYNH_H2_STREAM, /* ScrH2Stream — Http2Stream (client & server) */
|
|
2702
2754
|
SCR_DYNH_HTTP_CLIENT, /* ScrHttpClientReq — http.ClientRequest */
|
|
2703
2755
|
SCR_DYNH_HTTP_AGENT, /* ScrHttpAgent — http.Agent / https.Agent */
|
|
2756
|
+
SCR_DYNH_ABORT_SIGNAL, /* native static-fetch AbortSignal */
|
|
2757
|
+
SCR_DYNH_WEB_STREAM, /* native WHATWG ReadableStream */
|
|
2758
|
+
SCR_DYNH_WEB_READER, /* native ReadableStreamDefaultReader */
|
|
2759
|
+
SCR_DYNH_WEB_CONTROLLER, /* native ReadableStreamDefaultController */
|
|
2760
|
+
SCR_DYNH_FETCH_RESPONSE, /* native static-fetch Response */
|
|
2761
|
+
SCR_DYNH_FETCH_HEADERS, /* native static-fetch response Headers */
|
|
2762
|
+
SCR_DYNH_EVENT, /* native static-fetch abort Event */
|
|
2763
|
+
SCR_DYNH_ABORT_CONTROLLER, /* native static-fetch AbortController */
|
|
2704
2764
|
SCR_DYNH_COUNT,
|
|
2705
2765
|
} ScrDynHandleTag;
|
|
2706
2766
|
|
|
2707
2767
|
typedef struct ScrDyn ScrDyn;
|
|
2708
2768
|
typedef struct ScrBytes ScrBytes; /* full definition below (C11 repeat) */
|
|
2709
2769
|
typedef struct ScrClosure ScrClosure; /* full definition below (C11 repeat) */
|
|
2770
|
+
typedef struct ScrDynTypedCast {
|
|
2771
|
+
const char *type_key;
|
|
2772
|
+
size_t type_key_len;
|
|
2773
|
+
void *ptr;
|
|
2774
|
+
void *(*retain)(void *);
|
|
2775
|
+
void (*release)(void *);
|
|
2776
|
+
struct ScrDynTypedCast *next;
|
|
2777
|
+
} ScrDynTypedCast;
|
|
2710
2778
|
typedef struct ScrJsval ScrJsval; /* opaque island cell (C11 repeat; the
|
|
2711
2779
|
* always-linked dyn core never touches
|
|
2712
2780
|
* its engine value — only the gated ops
|
|
@@ -2752,7 +2820,19 @@ struct ScrDyn {
|
|
|
2752
2820
|
ScrStr *str; /* owned */
|
|
2753
2821
|
ScrBytes *bytes; /* owned (SCR_DYN_BYTES) */
|
|
2754
2822
|
struct { size_t len; size_t cap; ScrDyn **items; } arr; /* owned */
|
|
2755
|
-
struct {
|
|
2823
|
+
struct {
|
|
2824
|
+
size_t len;
|
|
2825
|
+
size_t cap;
|
|
2826
|
+
ScrDynEntry *entries;
|
|
2827
|
+
/* Optional identity of the typed record that produced this ordinary
|
|
2828
|
+
* deep-copy snapshot. EventTarget uses it to recognize the same
|
|
2829
|
+
* EventListenerObject across repeated static→dyn crossings without
|
|
2830
|
+
* changing generic dyn-object `===` semantics. */
|
|
2831
|
+
/* Owned through source_access(source_identity, false). Callback
|
|
2832
|
+
* interfaces may request a fresh snapshot with the true arm. */
|
|
2833
|
+
void *source_identity;
|
|
2834
|
+
ScrDyn *(*source_access)(void *, bool materialize);
|
|
2835
|
+
} obj; /* owned */
|
|
2756
2836
|
/* SCR_DYN_FUNC: the boxed closure (owned) + its call descriptor. `sig`
|
|
2757
2837
|
* and `name` are static compiler-emitted literals (never freed); name
|
|
2758
2838
|
* may be NULL (anonymous — inspect prints [Function (anonymous)]).
|
|
@@ -2767,6 +2847,23 @@ struct ScrDyn {
|
|
|
2767
2847
|
* so a listener capturing its own boxed handle never cycles past the
|
|
2768
2848
|
* settle — the settle-releases-listeners story. */
|
|
2769
2849
|
struct { void *ptr; ScrDynHandleTag tag; } handle;
|
|
2850
|
+
/* SCR_DYN_TYPED_REF: original static value + its compiler-emitted
|
|
2851
|
+
* identity tag, RC adapters, and ordinary dyn snapshot adapter. */
|
|
2852
|
+
struct {
|
|
2853
|
+
void *ptr;
|
|
2854
|
+
void *(*retain)(void *);
|
|
2855
|
+
void (*release)(void *);
|
|
2856
|
+
const char *type_key;
|
|
2857
|
+
size_t type_key_len;
|
|
2858
|
+
ScrDyn *(*materialize)(void *);
|
|
2859
|
+
void (*commit)(void *, const ScrDyn *);
|
|
2860
|
+
/* Both caches belong to this capsule. ReadableStream canonicalizes
|
|
2861
|
+
* capsules for repeated source references, so the refreshed dyn view
|
|
2862
|
+
* and every structurally converted static view keep JS reference
|
|
2863
|
+
* identity while the source reference remains observable. */
|
|
2864
|
+
ScrDyn *materialized;
|
|
2865
|
+
ScrDynTypedCast *casts;
|
|
2866
|
+
} typed_ref;
|
|
2770
2867
|
/* SCR_DYN_PROMISE: the retained promise. The boundary contract: it
|
|
2771
2868
|
* settles with a dyn payload (SCR_EXC_REF ScrDyn fulfillment or a
|
|
2772
2869
|
* void fulfillment awaiters read as the undefined value) — the
|
|
@@ -2841,6 +2938,14 @@ ScrDyn *scr_dyn_new_num(double n);
|
|
|
2841
2938
|
ScrDyn *scr_dyn_new_str(ScrStr *s);
|
|
2842
2939
|
ScrDyn *scr_dyn_new_arr(void);
|
|
2843
2940
|
ScrDyn *scr_dyn_new_obj(void);
|
|
2941
|
+
/* The ordinary deep-copy object plus a retained typed source. source_access
|
|
2942
|
+
* releases that source when materialize=false and returns a fresh dyn snapshot
|
|
2943
|
+
* when true. Generic dyn member reads and strict equality remain snapshot/node
|
|
2944
|
+
* based; callback-interface consumers opt into the live arm explicitly. */
|
|
2945
|
+
ScrDyn *scr_dyn_new_obj_with_identity(
|
|
2946
|
+
void *source, void *(*source_retain)(void *),
|
|
2947
|
+
ScrDyn *(*source_access)(void *, bool materialize));
|
|
2948
|
+
bool scr_dyn_obj_same_source(const ScrDyn *a, const ScrDyn *b);
|
|
2844
2949
|
/* Object.create(null): the fresh null-prototype dictionary (see the
|
|
2845
2950
|
* null_proto flavor flag above). */
|
|
2846
2951
|
ScrDyn *scr_dyn_new_obj_null_proto(void);
|
|
@@ -2850,6 +2955,26 @@ ScrDyn *scr_dyn_new_bytes_copy(const ScrBytes *b);
|
|
|
2850
2955
|
/* The Buffer-flavored twin (stream chunks): string coercion/toString
|
|
2851
2956
|
* decode utf8 instead of joining elements. */
|
|
2852
2957
|
ScrDyn *scr_dyn_new_buffer_copy(const ScrBytes *b);
|
|
2958
|
+
/* Identity-preserving transit capsule used by ReadableStream.from over
|
|
2959
|
+
* typed arrays. The constructor retains `ptr`; matching unbox returns +1.
|
|
2960
|
+
* materialize lazily creates and then retains one detached dyn snapshot.
|
|
2961
|
+
* The cast cache lets a non-exact dynCheck reuse one safe, compiler-built
|
|
2962
|
+
* target view instead of raw-casting structurally different layouts. */
|
|
2963
|
+
ScrDyn *scr_dyn_new_typed_ref(
|
|
2964
|
+
void *ptr, void *(*retain)(void *), void (*release)(void *),
|
|
2965
|
+
const char *type_key, size_t type_key_len,
|
|
2966
|
+
ScrDyn *(*materialize)(void *),
|
|
2967
|
+
void (*commit)(void *, const ScrDyn *));
|
|
2968
|
+
bool scr_dyn_typed_ref_is(
|
|
2969
|
+
const ScrDyn *d, const char *type_key, size_t type_key_len);
|
|
2970
|
+
void *scr_dyn_typed_ref_unbox(const ScrDyn *d); /* +1 */
|
|
2971
|
+
ScrDyn *scr_dyn_typed_ref_materialize(const ScrDyn *d); /* +1 */
|
|
2972
|
+
void scr_dyn_typed_ref_commit(ScrDyn *d);
|
|
2973
|
+
void *scr_dyn_typed_ref_cached_cast(
|
|
2974
|
+
const ScrDyn *d, const char *type_key, size_t type_key_len); /* +1/NULL */
|
|
2975
|
+
void scr_dyn_typed_ref_cache_cast(
|
|
2976
|
+
ScrDyn *d, const char *type_key, size_t type_key_len, void *ptr,
|
|
2977
|
+
void *(*retain)(void *), void (*release)(void *));
|
|
2853
2978
|
/* A fresh u8 COPY of a SCR_DYN_BYTES payload (+1) — the dynCheck
|
|
2854
2979
|
* extraction (`u as Uint8Array`). */
|
|
2855
2980
|
ScrBytes *scr_dyn_bytes_copy_out(const ScrDyn *d);
|
|
@@ -2902,6 +3027,7 @@ ScrStr *scr_dyn_string_coerce(const ScrDyn *d);
|
|
|
2902
3027
|
* called, their throws propagating) — the WHATWG USVString conversions.
|
|
2903
3028
|
* Borrows; +1 or NULL with the exception pending. */
|
|
2904
3029
|
ScrStr *scr_dyn_string_coerce_js(const ScrDyn *d);
|
|
3030
|
+
bool scr_dyn_number_coerce_js(const ScrDyn *d, double *out);
|
|
2905
3031
|
|
|
2906
3032
|
/* `d instanceof TypeError` (and the other builtin error classes) on a
|
|
2907
3033
|
* checked-dynamic value: the from_error cache resolves the dyn encoding
|
|
@@ -3137,9 +3263,10 @@ ScrDyn *scr_dyn_alloc_jsval(ScrJsval *cell, const ScrDynJsvalOps *ops);
|
|
|
3137
3263
|
/* The installed ops (traps on a missing install — impossible unless a
|
|
3138
3264
|
* JSVAL node was forged without the constructor). */
|
|
3139
3265
|
const ScrDynJsvalOps *scr_dyn_jsval_ops(void);
|
|
3140
|
-
/* dynTest arms that need the ENGINE's answer on a JSVAL node
|
|
3141
|
-
*
|
|
3142
|
-
*
|
|
3266
|
+
/* dynTest arms that need the ENGINE's answer on a JSVAL node, or the
|
|
3267
|
+
* materialized answer for a live typed-reference capsule. Each answers
|
|
3268
|
+
* false for every other kind (callers test unconditionally — the emitted
|
|
3269
|
+
* narrowing tests stay branch-free). Never throw. */
|
|
3143
3270
|
bool scr_dyn_isl_typeof_is(const ScrDyn *d, const char *name);
|
|
3144
3271
|
bool scr_dyn_isl_is_array(const ScrDyn *d);
|
|
3145
3272
|
bool scr_dyn_isl_is_error(const ScrDyn *d);
|
|
@@ -3819,6 +3946,35 @@ ScrGen *scr_gen_of_fiber(ScrFiber *f);
|
|
|
3819
3946
|
long scr_promise_live_count(void);
|
|
3820
3947
|
#endif
|
|
3821
3948
|
|
|
3949
|
+
/* ── fetch (scr_fetch.c) ──────────────────────────────────────────────
|
|
3950
|
+
* The native bridge over scr_net + scr_tls + scr_http's client parser.
|
|
3951
|
+
* Static fetch(url) resolves at the response head with native Response
|
|
3952
|
+
* and ReadableStream handles; Response.json consumes that same stream.
|
|
3953
|
+
* AbortSignal and streaming request bodies stay native too. Under
|
|
3954
|
+
* --dynamic the same TU boots the broader engine web surface. The
|
|
3955
|
+
* emitted main calls scr_fetch_install in either form. */
|
|
3956
|
+
void scr_fetch_install(void);
|
|
3957
|
+
ScrPromise *scr_fetch_static(ScrStr *url, ScrDyn *init); /* +1 promise<Response handle> */
|
|
3958
|
+
ScrDyn *scr_fetch_response_new(ScrDyn *body, ScrDyn *init); /* borrowed args; +1 Response handle or NULL pending */
|
|
3959
|
+
ScrPromise *scr_fetch_response_json(ScrDyn *response); /* +1 promise<dyn> */
|
|
3960
|
+
ScrPromise *scr_fetch_response_text(ScrDyn *response); /* +1 promise<dyn> */
|
|
3961
|
+
ScrPromise *scr_fetch_response_bytes(ScrDyn *response); /* +1 promise<dyn> */
|
|
3962
|
+
ScrDyn *scr_fetch_abort_controller_new(void); /* +1 AbortController handle */
|
|
3963
|
+
/* Borrowed number; +1 AbortSignal handle or NULL pending. */
|
|
3964
|
+
ScrDyn *scr_fetch_abort_timeout(ScrDyn *delay);
|
|
3965
|
+
ScrDyn *scr_fetch_abort_now(ScrDyn *reason); /* borrowed reason; +1 handle */
|
|
3966
|
+
ScrDyn *scr_fetch_abort_any(ScrDyn *signals); /* borrowed array; +1 handle or NULL pending */
|
|
3967
|
+
ScrDyn *scr_fetch_stream_new(ScrDyn *source); /* borrowed source; +1 handle or NULL pending */
|
|
3968
|
+
ScrDyn *scr_fetch_stream_from(ScrDyn *iterable); /* borrowed iterable; +1 handle or NULL pending */
|
|
3969
|
+
ScrDyn *scr_fetch_stream_from_array(
|
|
3970
|
+
ScrArr *iterable,
|
|
3971
|
+
ScrDyn *(*item)(ScrArr *, double)); /* borrowed array/callback; +1 handle */
|
|
3972
|
+
ScrDyn *scr_fetch_stream_from_bytes(
|
|
3973
|
+
ScrBytes *iterable); /* borrowed bytes; +1 handle */
|
|
3974
|
+
ScrDyn *scr_fetch_stream_from_string(
|
|
3975
|
+
ScrStr *iterable); /* borrowed string; +1 handle */
|
|
3976
|
+
ScrPromise *scr_fetch_reader_read(ScrDyn *reader); /* borrowed handle; +1 */
|
|
3977
|
+
|
|
3822
3978
|
/* ── dynamic island (scr_island.c; --dynamic builds ONLY) ────────────
|
|
3823
3979
|
* The embedded QuickJS-ng engine. Compiled and linked only under
|
|
3824
3980
|
* -DSCR_DYNAMIC; static builds never reference these symbols (nor the
|
|
@@ -3948,18 +4104,12 @@ bool scr_island_timers_due(void);
|
|
|
3948
4104
|
bool scr_island_timers_fire_due(void); /* true = fired at least one */
|
|
3949
4105
|
void scr_island_timers_teardown(void);
|
|
3950
4106
|
|
|
3951
|
-
/* ── fetch
|
|
3952
|
-
* The native bridge
|
|
3953
|
-
* scr_http's client parser + zlib), compiled and linked ONLY into
|
|
3954
|
-
* --dynamic builds whose graph references fetch. The emitted main calls
|
|
3955
|
-
* scr_fetch_install BEFORE any island entry; install registers the
|
|
3956
|
-
* bridge's hooks with the island, which boots the fetch glue with the
|
|
3957
|
-
* engine. The native bridge registers NO pending/poll hooks (its
|
|
4107
|
+
/* ── dynamic fetch hooks ──────────────────────────────────────────────
|
|
4108
|
+
* The native bridge registers NO pending/poll hooks (its
|
|
3958
4109
|
* transfers live on real sockets the loop's poller sleeps on); the curl
|
|
3959
4110
|
* reference implementation (scr_fetch_curl.c, SCRIPTC_FETCH_CURL=1 —
|
|
3960
4111
|
* one release as the flip's reference) still registers all four so the
|
|
3961
4112
|
* loop can sleep on curl's fds. */
|
|
3962
|
-
void scr_fetch_install(void);
|
|
3963
4113
|
void scr_island_set_fetch(void (*boot)(void *jsctx), bool (*pending)(void),
|
|
3964
4114
|
void (*poll)(double max_wait_ms), void (*teardown)(void));
|
|
3965
4115
|
|
|
@@ -4078,6 +4228,7 @@ ScrJsval *scr_jsval_destr_check(ScrJsval *v, const char *spell, const char *firs
|
|
|
4078
4228
|
ScrJsval *scr_jsval_iter_n(ScrJsval *v, double n);
|
|
4079
4229
|
int scr_jsval_set_idx(ScrJsval *o, ScrJsval *key, ScrJsval *v);
|
|
4080
4230
|
ScrJsval *scr_jsval_call_method(ScrJsval *o, const ScrStr *name, int argc, ScrJsval **argv);
|
|
4231
|
+
ScrJsval *scr_jsval_call_this(ScrJsval *f, ScrJsval *receiver, int argc, ScrJsval **argv);
|
|
4081
4232
|
/* `o.name?.(...)`: a nullish member answers the engine's undefined;
|
|
4082
4233
|
* anything else calls with this = o (non-callables throw in the engine). */
|
|
4083
4234
|
ScrJsval *scr_jsval_opt_call_method(ScrJsval *o, const ScrStr *name, int argc, ScrJsval **argv);
|
|
@@ -4297,10 +4448,13 @@ bool scr_num_same_value(double a, double b);
|
|
|
4297
4448
|
* en-US is the one embedded locale. Result +1; never throws. */
|
|
4298
4449
|
ScrStr *scr_intl_num_format_en_us(double x);
|
|
4299
4450
|
|
|
4300
|
-
/* ── Date, the
|
|
4301
|
-
* Date
|
|
4302
|
-
*
|
|
4451
|
+
/* ── Date, the read-only value slice (scr_lib.c) ──────────────────────
|
|
4452
|
+
* A Date value is its TimeClip'd epoch-millisecond scalar. Identity and
|
|
4453
|
+
* mutation are frontend-fenced; construction, storage, getters, and ISO
|
|
4454
|
+
* formatting are exact over this representation. */
|
|
4303
4455
|
double scr_date_now(void); /* integer ms since epoch, like Node */
|
|
4456
|
+
double scr_date_new_ms(double ms); /* TimeClip (NaN when invalid) */
|
|
4457
|
+
double scr_date_get_time(double ms);
|
|
4304
4458
|
/* Node's exact ISO 8601 UTC format (expanded ±YYYYYY years outside
|
|
4305
4459
|
* 0–9999). THROWS Node's "Invalid time value" RangeError on NaN or
|
|
4306
4460
|
* |ms| > 8.64e15 and returns NULL; +1 otherwise. */
|
|
@@ -4314,6 +4468,30 @@ double scr_date_parse_get_time(ScrStr *s);
|
|
|
4314
4468
|
* and years past V8's ±1e6 MakeDay bound. Never throws. */
|
|
4315
4469
|
double scr_date_utc(double y, double mo, double d,
|
|
4316
4470
|
double h, double mi, double s, double ms);
|
|
4471
|
+
double scr_date_get_full_year(double ms, bool utc);
|
|
4472
|
+
double scr_date_get_month(double ms, bool utc);
|
|
4473
|
+
double scr_date_get_date(double ms, bool utc);
|
|
4474
|
+
double scr_date_get_day(double ms, bool utc);
|
|
4475
|
+
double scr_date_get_hours(double ms, bool utc);
|
|
4476
|
+
double scr_date_get_minutes(double ms, bool utc);
|
|
4477
|
+
double scr_date_get_seconds(double ms, bool utc);
|
|
4478
|
+
double scr_date_get_milliseconds(double ms);
|
|
4479
|
+
double scr_date_get_timezone_offset(double ms);
|
|
4480
|
+
/* One-argument ABI wrappers used by the LLVM lib-call table. */
|
|
4481
|
+
double scr_date_get_full_year_local(double ms);
|
|
4482
|
+
double scr_date_get_full_year_utc(double ms);
|
|
4483
|
+
double scr_date_get_month_local(double ms);
|
|
4484
|
+
double scr_date_get_month_utc(double ms);
|
|
4485
|
+
double scr_date_get_date_local(double ms);
|
|
4486
|
+
double scr_date_get_date_utc(double ms);
|
|
4487
|
+
double scr_date_get_day_local(double ms);
|
|
4488
|
+
double scr_date_get_day_utc(double ms);
|
|
4489
|
+
double scr_date_get_hours_local(double ms);
|
|
4490
|
+
double scr_date_get_hours_utc(double ms);
|
|
4491
|
+
double scr_date_get_minutes_local(double ms);
|
|
4492
|
+
double scr_date_get_minutes_utc(double ms);
|
|
4493
|
+
double scr_date_get_seconds_local(double ms);
|
|
4494
|
+
double scr_date_get_seconds_utc(double ms);
|
|
4317
4495
|
|
|
4318
4496
|
/* ── bitwise operators (scr_lib.c) ────────────────────────────────────
|
|
4319
4497
|
* JS-exact ToInt32/ToUint32 semantics: NaN/±Infinity → 0, truncation
|
|
@@ -4468,6 +4646,9 @@ void scr_dataview_set(ScrBytes *b, double byte_off, double value, ScrDataViewGet
|
|
|
4468
4646
|
* toward zero, wrap mod 2^8/2^32), f32 by double→float rounding. */
|
|
4469
4647
|
double scr_bytes_get(const ScrBytes *b, double i);
|
|
4470
4648
|
void scr_bytes_set(ScrBytes *b, double i, double v);
|
|
4649
|
+
/* Replace a live typed-array capsule's fixed-size payload from its dyn
|
|
4650
|
+
* snapshot. Source and target have the same compiler-checked bytes type. */
|
|
4651
|
+
void scr_bytes_copy_contents(ScrBytes *dst, const ScrBytes *src);
|
|
4471
4652
|
|
|
4472
4653
|
/* TypedArray.prototype.slice(start, end): relative indices clamp like
|
|
4473
4654
|
* string/array slice (ToIntegerOrInfinity, negatives from the end); the
|
|
@@ -5125,9 +5306,12 @@ long scr_secure_ctx_live_count(void);
|
|
|
5125
5306
|
* /etc/ssl/cert.pem probe order scr_tls.c documents) stands in for both
|
|
5126
5307
|
* Node's compiled-in Mozilla roots ('bundled', rootCertificates) and the
|
|
5127
5308
|
* platform store ('system') — the established SEMANTICS divergence,
|
|
5128
|
-
* extended to introspection; 'extra'
|
|
5129
|
-
* are cached per type (+1 retained
|
|
5130
|
-
* caching, and the identity the suite pins
|
|
5309
|
+
* extended to introspection; 'extra' uses the NODE_EXTRA_CA_CERTS file
|
|
5310
|
+
* captured before user code runs. Arrays are cached per type (+1 retained
|
|
5311
|
+
* answers each call — Node's own caching, and the identity the suite pins
|
|
5312
|
+
* with strictEqual). */
|
|
5313
|
+
void scr_tls_ca_install(void); /* snapshots NODE_EXTRA_CA_CERTS + file bytes */
|
|
5314
|
+
bool scr_tls_ca_extra_pem(const char **pem, size_t *len); /* borrowed launch snapshot */
|
|
5131
5315
|
ScrArr *scr_tls_ca_get(ScrStr *type); /* +1; throws ERR_INVALID_ARG_VALUE on unknown types */
|
|
5132
5316
|
ScrArr *scr_tls_ca_root(void); /* +1; === getCACertificates("bundled") */
|
|
5133
5317
|
/* Replaces the 'default' set: entries filter to their PEM certificate
|
package/src/scr_tls.c
CHANGED
|
@@ -336,17 +336,14 @@ typedef struct ScrTlsCli {
|
|
|
336
336
|
} ScrTlsCli;
|
|
337
337
|
|
|
338
338
|
/* The default trust anchors when no `ca` option is given: the system
|
|
339
|
-
* bundle, standing in for Node's compiled-in Mozilla roots
|
|
340
|
-
*
|
|
341
|
-
* Alpine links it),
|
|
342
|
-
*
|
|
343
|
-
* only the first path exists, so
|
|
344
|
-
* A host with none leaves the
|
|
345
|
-
*
|
|
346
|
-
*
|
|
347
|
-
* shaped) — a no-`ca` client there fails verification like a bundle-less
|
|
348
|
-
* Unix host, which agrees with the oracle wherever the fixtures tread
|
|
349
|
-
* (their CAs are local, never in Node's Mozilla roots either). */
|
|
339
|
+
* bundle, standing in for Node's compiled-in Mozilla roots, plus
|
|
340
|
+
* NODE_EXTRA_CA_CERTS. The system bundle is probed once across the distro
|
|
341
|
+
* spellings — /etc/ssl/cert.pem first (macOS ships it; Alpine links it),
|
|
342
|
+
* then Debian/Ubuntu's ca-certificates.crt, Fedora/RHEL's ca-bundle.crt,
|
|
343
|
+
* and openSUSE's ca-bundle.pem. On macOS only the first path exists, so
|
|
344
|
+
* the probe order changes nothing there. A host with none leaves only the
|
|
345
|
+
* optional extra chain. Windows is that host by construction (no PEM
|
|
346
|
+
* bundle ships; the OS store is cert-database-shaped). */
|
|
350
347
|
static mbedtls_x509_crt scr_tls_system_roots;
|
|
351
348
|
static bool scr_tls_system_roots_loaded = false;
|
|
352
349
|
|
|
@@ -386,6 +383,13 @@ static mbedtls_x509_crt *scr_tls_system_ca(void) {
|
|
|
386
383
|
for (size_t i = 0; i < sizeof bundles / sizeof bundles[0]; i++) {
|
|
387
384
|
if (mbedtls_x509_crt_parse_file(&scr_tls_system_roots, bundles[i]) == 0) break;
|
|
388
385
|
}
|
|
386
|
+
const char *extra = NULL;
|
|
387
|
+
size_t extra_len = 0;
|
|
388
|
+
if (scr_tls_ca_extra_pem(&extra, &extra_len) && extra_len > 0) {
|
|
389
|
+
(void)mbedtls_x509_crt_parse(
|
|
390
|
+
&scr_tls_system_roots, (const unsigned char *)extra,
|
|
391
|
+
extra_len + 1);
|
|
392
|
+
}
|
|
389
393
|
}
|
|
390
394
|
return &scr_tls_system_roots;
|
|
391
395
|
}
|
package/src/scr_tls_ca.c
CHANGED
|
@@ -32,6 +32,9 @@ static ScrArr *scr_ca_bundled = NULL;
|
|
|
32
32
|
static ScrArr *scr_ca_system = NULL;
|
|
33
33
|
static ScrArr *scr_ca_extra = NULL;
|
|
34
34
|
static ScrArr *scr_ca_default = NULL;
|
|
35
|
+
static char *scr_ca_extra_buf = NULL;
|
|
36
|
+
static size_t scr_ca_extra_len = 0;
|
|
37
|
+
static bool scr_ca_installed = false;
|
|
35
38
|
static char *scr_ca_override_buf = NULL;
|
|
36
39
|
static size_t scr_ca_override_len = 0;
|
|
37
40
|
static uint64_t scr_ca_override_gen = 0; /* 0 = never set */
|
|
@@ -47,6 +50,9 @@ static void scr_ca_teardown(void) {
|
|
|
47
50
|
if (scr_ca_extra != NULL) scr_arr_release(scr_ca_extra);
|
|
48
51
|
if (scr_ca_default != NULL) scr_arr_release(scr_ca_default);
|
|
49
52
|
scr_ca_bundled = scr_ca_system = scr_ca_extra = scr_ca_default = NULL;
|
|
53
|
+
free(scr_ca_extra_buf);
|
|
54
|
+
scr_ca_extra_buf = NULL;
|
|
55
|
+
scr_ca_extra_len = 0;
|
|
50
56
|
free(scr_ca_override_buf);
|
|
51
57
|
scr_ca_override_buf = NULL;
|
|
52
58
|
}
|
|
@@ -123,6 +129,31 @@ static char *scr_ca_read_file(const char *path, size_t *out_len) {
|
|
|
123
129
|
return buf;
|
|
124
130
|
}
|
|
125
131
|
|
|
132
|
+
/*
|
|
133
|
+
* Node consumes NODE_EXTRA_CA_CERTS while the process is initialized:
|
|
134
|
+
* changing process.env or replacing the referenced file later does not
|
|
135
|
+
* alter either TLS trust or getCACertificates("extra"). Generated main
|
|
136
|
+
* calls this install hook before user code; the lazy fallback only serves
|
|
137
|
+
* library/direct-runtime callers that have no executable startup hook.
|
|
138
|
+
*/
|
|
139
|
+
void scr_tls_ca_install(void) {
|
|
140
|
+
if (scr_ca_installed) return;
|
|
141
|
+
scr_ca_installed = true;
|
|
142
|
+
scr_ca_arm_teardown();
|
|
143
|
+
const char *path = getenv("NODE_EXTRA_CA_CERTS");
|
|
144
|
+
if (path != NULL && path[0] != '\0') {
|
|
145
|
+
scr_ca_extra_buf = scr_ca_read_file(path, &scr_ca_extra_len);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
bool scr_tls_ca_extra_pem(const char **pem, size_t *len) {
|
|
150
|
+
scr_tls_ca_install();
|
|
151
|
+
if (scr_ca_extra_buf == NULL) return false;
|
|
152
|
+
*pem = scr_ca_extra_buf;
|
|
153
|
+
*len = scr_ca_extra_len;
|
|
154
|
+
return true;
|
|
155
|
+
}
|
|
156
|
+
|
|
126
157
|
/* The host bundle, probed in scr_tls.c's documented order. */
|
|
127
158
|
static ScrArr *scr_ca_load_host_bundle(void) {
|
|
128
159
|
ScrArr *arr = scr_arr_new(SCR_ELEM_STR, 128);
|
|
@@ -163,14 +194,10 @@ static ScrArr *scr_ca_extra_arr(void) {
|
|
|
163
194
|
if (scr_ca_extra == NULL) {
|
|
164
195
|
scr_ca_arm_teardown();
|
|
165
196
|
scr_ca_extra = scr_arr_new(SCR_ELEM_STR, 4);
|
|
166
|
-
const char *
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
if (text != NULL) {
|
|
171
|
-
scr_ca_push_pem_blocks(scr_ca_extra, text, len);
|
|
172
|
-
free(text);
|
|
173
|
-
}
|
|
197
|
+
const char *pem = NULL;
|
|
198
|
+
size_t len = 0;
|
|
199
|
+
if (scr_tls_ca_extra_pem(&pem, &len)) {
|
|
200
|
+
scr_ca_push_pem_blocks(scr_ca_extra, pem, len);
|
|
174
201
|
}
|
|
175
202
|
}
|
|
176
203
|
return scr_ca_extra;
|