Merge remote-tracking branch 'origin/ni/i4-deferred' into tmp-merge

This commit is contained in:
Malte Ubl
2026-10-22 21:14:40 -07:00
+94 -2
View File
@@ -499,13 +499,27 @@ static const ScrNodeBridgeHost ni_host = {
&scr_ni_host_shared_tdz,
};
typedef struct {
uint32_t event, listener;
const char *name;
int arg;
} NiEmit;
static void ni_emit_job(void *p) {
NiEmit *e = p;
ni_bridge->emit(e->event, e->listener, e->name, e->arg);
}
/* An island listener of a process event, on Node's stack (an exit listener
* runs from the runtime's exit sequence, on whatever stack called it). */
void scr_node_island_emit(uint32_t event, uint32_t listener, ScrStr *name, int arg) {
if (ni_bridge == NULL) return;
char *n = malloc(name->len + 1);
if (n == NULL) ni_oom();
memcpy(n, name->data, name->len);
n[name->len] = '\0';
ni_bridge->emit(event, listener, n, arg);
NiEmit e = {event, listener, n, arg};
ni_on_node_stack(ni_emit_job, &e);
free(n);
}
@@ -548,7 +562,75 @@ static int ni_run_loop(int continue_turn) {
return a.code;
}
/* The bridge as the hosted loop sees it: Node's loop runs on Node's stack. */
/* The bridge as the hosted loop sees it. Every entry that runs JavaScript
* (scheduling a tick, timer or immediate goes through the bootstrap's
* helpers; a checkpoint drains queues; Node's loop) runs on Node's stack,
* below the mark when it comes from an async fiber that a host callback
* resumed, like every other entry: V8 scans only Node's stack, so no frame
* of Node may live on a fiber's stack or the main thread's. */
typedef struct {
int op;
uint32_t a, b;
double d0, d1;
int i0;
uint32_t result;
} NiHosted;
enum {
NI_H_MICROTASK,
NI_H_TICK,
NI_H_TIMER,
NI_H_TIMER_CLEAR,
NI_H_TIMER_REF,
NI_H_TIMER_REFRESH,
NI_H_IMMEDIATE,
NI_H_IMMEDIATE_CLEAR,
NI_H_IMMEDIATE_REF,
NI_H_CHECKPOINT,
};
static void ni_hosted_job(void *p) {
NiHosted *h = p;
switch (h->op) {
case NI_H_MICROTASK: ni_bridge->microtask(h->a); break;
case NI_H_TICK: ni_bridge->tick(h->a); break;
case NI_H_TIMER: h->result = ni_bridge->timer(h->d0, h->d1, h->i0, h->a); break;
case NI_H_TIMER_CLEAR: ni_bridge->timer_clear(h->a); break;
case NI_H_TIMER_REF: ni_bridge->timer_ref(h->a, h->i0); break;
case NI_H_TIMER_REFRESH: ni_bridge->timer_refresh(h->a); break;
case NI_H_IMMEDIATE: h->result = ni_bridge->immediate(h->i0, h->a); break;
case NI_H_IMMEDIATE_CLEAR: ni_bridge->immediate_clear(h->a); break;
case NI_H_IMMEDIATE_REF: ni_bridge->immediate_ref(h->a, h->i0); break;
case NI_H_CHECKPOINT: ni_bridge->checkpoint(h->i0); break;
default: break;
}
}
static uint32_t ni_hosted_run(int op, uint32_t a, double d0, double d1, int i0) {
NiHosted h = {op, a, 0, d0, d1, i0, 0};
ni_on_node_stack(ni_hosted_job, &h);
return h.result;
}
static void ni_h_microtask(uint32_t token) { ni_hosted_run(NI_H_MICROTASK, token, 0, 0, 0); }
static void ni_h_tick(uint32_t token) { ni_hosted_run(NI_H_TICK, token, 0, 0, 0); }
static uint32_t ni_h_timer(double delay, double repeat, int ref, uint32_t token) {
return ni_hosted_run(NI_H_TIMER, token, delay, repeat, ref);
}
static void ni_h_timer_clear(uint32_t h) { ni_hosted_run(NI_H_TIMER_CLEAR, h, 0, 0, 0); }
static void ni_h_timer_ref(uint32_t h, int ref) { ni_hosted_run(NI_H_TIMER_REF, h, 0, 0, ref); }
static void ni_h_timer_refresh(uint32_t h) { ni_hosted_run(NI_H_TIMER_REFRESH, h, 0, 0, 0); }
static uint32_t ni_h_immediate(int ref, uint32_t token) {
return ni_hosted_run(NI_H_IMMEDIATE, token, 0, 0, ref);
}
static void ni_h_immediate_clear(uint32_t h) { ni_hosted_run(NI_H_IMMEDIATE_CLEAR, h, 0, 0, 0); }
static void ni_h_immediate_ref(uint32_t h, int ref) {
ni_hosted_run(NI_H_IMMEDIATE_REF, h, 0, 0, ref);
}
static void ni_h_checkpoint(int microtasks_first) {
ni_hosted_run(NI_H_CHECKPOINT, 0, 0, 0, microtasks_first);
}
static ScrNodeBridge ni_hosted;
/* ── loading Node ─────────────────────────────────────────────────────── */
@@ -622,6 +704,16 @@ static void ni_start(void) {
scr_atexit(ni_stop_atexit);
ni_hosted = *bridge;
ni_hosted.run_loop = &ni_run_loop;
ni_hosted.microtask = &ni_h_microtask;
ni_hosted.tick = &ni_h_tick;
ni_hosted.timer = &ni_h_timer;
ni_hosted.timer_clear = &ni_h_timer_clear;
ni_hosted.timer_ref = &ni_h_timer_ref;
ni_hosted.timer_refresh = &ni_h_timer_refresh;
ni_hosted.immediate = &ni_h_immediate;
ni_hosted.immediate_clear = &ni_h_immediate_clear;
ni_hosted.immediate_ref = &ni_h_immediate_ref;
ni_hosted.checkpoint = &ni_h_checkpoint;
scr_loop_host(&ni_hosted, since);
/* NI-7: deferred island modules evaluate now, before the operation that
* needed Node, in their import order. */