Something went wrong. Try again.
MIRROR: javascript for 🐜's, a tiny runtime with big ambitions ant.themackabu.dev
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237#include <compat.h> // IWYU pragma: keep#include <stdlib.h>
#include "ant.h"#include "errors.h"#include "handles.h"#include "internal.h"#include "reactor.h"#include "modules/timer.h"#include "isolate_internal.h"
typedef struct { ant_realm_t *cfunc_realm;} current_saved_t;
typedef struct { ant_guest_t *g; uv_poll_t poll; uv_timer_t timer; bool poll_open; bool polling; bool timer_open; uint32_t depth; bool destroy_pending;} current_state_t;
static current_state_t *current_state(ant_guest_t *g) { return g->transport;}
static inline __attribute__((always_inline)) void current_enter(ant_guest_t *g, current_saved_t *saved) { current_state_t *st = current_state(g); ant_t *host = g->host, *child = g->child; saved->cfunc_realm = ant_cfunc_intern_realm; if (st->depth++ == 0) { void *frame = __builtin_frame_address(0); uintptr_t sp = (uintptr_t)frame; uintptr_t base = (uintptr_t)host->cstk.base; size_t used = base > sp ? base - sp : 0; size_t room = host->cstk.limit > used ? host->cstk.limit - used : 0; js_setstackbase(child, frame); js_setstacklimit(child, room); } ant_cfunc_intern_realm = child->builtin_realm;}
static void current_destroy(ant_guest_t *g);
static void current_exit(ant_guest_t *g, current_saved_t *saved) { current_state_t *st = current_state(g); ant_cfunc_intern_realm = saved->cfunc_realm; if (--st->depth == 0 && st->destroy_pending) current_destroy(g);}
static void current_complete(ant_guest_t *g, guest_call_t *call) { call->done = true; if (!call->sync && g->host) guest_finish_host(g->host, g, call);}
static bool current_call_host(ant_guest_t *g, guest_host_call_t *call) { if (g->disposed) { call->status = GUEST_STATUS_DISPOSED; return true; } ant_realm_t *inner = ant_cfunc_intern_realm; ant_cfunc_intern_realm = g->host->builtin_realm; guest_host_run_callback(g->host, g, call); ant_cfunc_intern_realm = inner; return true;}
ant_value_t guest_current_host_call(ant_t *js, ant_guest_t *g, guest_host_call_t *call) { call->done = true; return js_mkundef();}
static void current_rearm(ant_guest_t *g);
static void current_drive(ant_guest_t *g) { if (g->disposed || !g->child) return; current_saved_t saved; current_enter(g, &saved); ant_uv_run(g->child->loop, UV_RUN_NOWAIT); process_microtasks(g->child); current_exit(g, &saved); current_rearm(g);}
static void current_poll_cb(uv_poll_t *handle, int status, int events) { current_drive(((current_state_t *)handle->data)->g);}
static void current_timer_cb(uv_timer_t *handle) { current_drive(((current_state_t *)handle->data)->g);}
static void current_rearm(ant_guest_t *g) { current_state_t *st = current_state(g); if (!st || g->disposed || !g->child) return;
bool alive = uv_loop_alive(g->child->loop); if (st->poll_open) { if (alive && !st->polling) st->polling = uv_poll_start(&st->poll, UV_READABLE, current_poll_cb) == 0; else if (!alive && st->polling) { uv_poll_stop(&st->poll); st->polling = false; } }
if (!st->timer_open) return; int timeout = alive ? uv_backend_timeout(g->child->loop) : -1; if (timeout >= 0) uv_timer_start(&st->timer, current_timer_cb, (uint64_t)timeout, 0); else uv_timer_stop(&st->timer);}
static void current_handle_closed(uv_handle_t *handle) { current_state_t *st = handle->data; if (handle == (uv_handle_t *)&st->poll) st->poll_open = false; else st->timer_open = false; if (st->poll_open || st->timer_open) return; guest_release(st->g); free(st);}
static void current_destroy(ant_guest_t *g) { current_state_t *st = current_state(g); ant_t *child = g->child; if (!child) return;
current_saved_t saved; current_enter(g, &saved); guest_child_teardown(g); st->depth--; ant_cfunc_intern_realm = saved.cfunc_realm;
child->terminating = false; atomic_store_explicit(&child->interrupt_pending, 0, memory_order_relaxed); g->child = NULL; js_destroy(child);
g->transport = NULL; bool closing = false; if (st->poll_open) { uv_close((uv_handle_t *)&st->poll, current_handle_closed); closing = true; } if (st->timer_open) { uv_close((uv_handle_t *)&st->timer, current_handle_closed); closing = true; } if (!closing) { guest_release(g); free(st); }}
ant_value_t guest_current_start(ant_t *js, ant_guest_t *g) { current_state_t *st = calloc(1, sizeof(*st)); if (!st) return js_mkerr(js, "out of memory"); st->g = guest_retain(g); g->transport = st; g->complete = current_complete; g->call_host = current_call_host;
ant_t *child = ant_create(&(ant_isolate_options_t){ .object_arena_bytes = g->arena_bytes }); if (!child) { g->transport = NULL; guest_release(g); free(st); return js_mkerr_code(js, JS_ERR_GENERIC, "ERR_ISOLATE_INIT_FAILED", "Isolate initialization failed"); }
g->child = child; child->interrupts_armed = true; current_saved_t saved; current_enter(g, &saved); bool ok = guest_child_boot(g, child); current_exit(g, &saved);
st->timer_open = uv_timer_init(js->loop, &st->timer) == 0; if (st->timer_open) st->timer.data = st; int fd = uv_backend_fd(child->loop); st->poll_open = fd >= 0 && uv_poll_init(js->loop, &st->poll, fd) == 0; if (st->poll_open) st->poll.data = st;
if (!ok) { g->disposed = true; current_destroy(g); return js_mkerr_code(js, JS_ERR_GENERIC, "ERR_ISOLATE_INIT_FAILED", "Isolate initialization failed"); }
current_rearm(g); return js_mkundef();}
ant_value_t guest_current_submit(ant_t *js, ant_guest_t *g, guest_call_t *call) { if (g->disposed || !g->child) { call->status = GUEST_STATUS_DISPOSED; call->done = true; return guest_finish_host(js, g, call); }
bool sync = call->sync; ant_value_t promise = call->promise; current_saved_t saved; current_enter(g, &saved); guest_child_execute(g, call); while (sync && !call->done && !g->disposed && g->child && uv_loop_alive(g->child->loop)) { ant_uv_run(g->child->loop, UV_RUN_ONCE); process_microtasks(g->child); } current_exit(g, &saved); current_rearm(g);
if (!sync) return promise; if (!call->done) call->status = g->disposed ? GUEST_STATUS_DISPOSED : GUEST_STATUS_THROW; return guest_finish_host(js, g, call);}
void guest_current_dispose(ant_guest_t *g) { current_state_t *st = current_state(g); g->disposed = true; if (!st) return;
if (st->depth > 0) { st->destroy_pending = true; if (g->child) { g->child->terminating = true; atomic_store_explicit(&g->child->interrupt_pending, 1, memory_order_relaxed); } return; }
current_destroy(g);}