MIRROR: javascript for ๐Ÿœ's, a tiny runtime with big ambitions
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

experimental mir GC support

+113 -3
+1
include/silver/engine.h
··· 172 172 173 173 #ifdef ANT_JIT 174 174 void *jit_code; 175 + void *jit_mir_item; 175 176 176 177 uint32_t call_count; 177 178 uint32_t back_edge_count;
+1
include/silver/swarm.h
··· 8 8 9 9 void sv_jit_init(ant_t *js); 10 10 void sv_jit_destroy(ant_t *js); 11 + void sv_jit_mark_roots(ant_t *js, void (*mark)(ant_t *, ant_value_t)); 11 12 12 13 sv_jit_func_t sv_jit_compile( 13 14 ant_t *js, sv_func_t *func,
+6
src/gc/objects.c
··· 5 5 #include "gc/modules.h" 6 6 #include "sugar.h" 7 7 #include "silver/engine.h" 8 + #ifdef ANT_JIT 9 + #include "silver/swarm.h" 10 + #endif 8 11 #include "shapes.h" 9 12 #include "runtime.h" 10 13 #include "modules/collections.h" ··· 487 490 gc_mark_value(js, js->cfunc_promote_cache.promoted[i]); 488 491 489 492 gc_visit_roots(js, gc_mark_value); 493 + #ifdef ANT_JIT 494 + sv_jit_mark_roots(js, gc_mark_value); 495 + #endif 490 496 gc_mark_timers(js, gc_mark_value); 491 497 gc_mark_atomics(js, gc_mark_value); 492 498 gc_mark_fetch(js, gc_mark_value);
+105 -3
src/silver/swarm.c
··· 20 20 #include <stdint.h> 21 21 #include <stddef.h> 22 22 23 + #define MCO_API extern 24 + #include <minicoro.h> 25 + 23 26 static const char *sv_op_name[] = { 24 27 #define OP_DEF(name, size, n_pop, n_push, f) [OP_##name] = #name, 25 28 #include "silver/opcode.h" ··· 27 30 28 31 typedef struct { 29 32 MIR_context_t ctx; 33 + MIR_item_t *func_items; 34 + size_t func_items_len; 35 + size_t func_items_cap; 30 36 bool externals_loaded; 31 37 } sv_jit_ctx_t; 32 38 ··· 40 46 41 47 static void jit_ctx_remove(ant_t *js) { 42 48 js->jit_ctx = NULL; 49 + } 50 + 51 + static bool jit_ctx_add_func(sv_jit_ctx_t *jc, MIR_item_t item) { 52 + if (!jc || !item) return false; 53 + if (jc->func_items_len == jc->func_items_cap) { 54 + size_t new_cap = jc->func_items_cap ? jc->func_items_cap * 2 : 64; 55 + MIR_item_t *new_items = realloc(jc->func_items, new_cap * sizeof(*new_items)); 56 + if (!new_items) return false; 57 + jc->func_items = new_items; 58 + jc->func_items_cap = new_cap; 59 + } 60 + jc->func_items[jc->func_items_len++] = item; 61 + return true; 43 62 } 44 63 45 64 static void jit_load_externals_once(sv_jit_ctx_t *jc) { ··· 129 148 if (!jc) return; 130 149 MIR_gen_finish(jc->ctx); 131 150 MIR_finish(jc->ctx); 151 + free(jc->func_items); 132 152 free(jc); 133 153 jit_ctx_remove(js); 134 154 } 135 155 156 + typedef struct { 157 + ant_t *js; 158 + void (*mark)(ant_t *, ant_value_t); 159 + } jit_gc_mark_ctx_t; 160 + 161 + static void jit_gc_mark_root(void *root_addr, void *data) { 162 + jit_gc_mark_ctx_t *ctx = (jit_gc_mark_ctx_t *)data; 163 + if (!root_addr || !ctx || !ctx->mark) return; 164 + ctx->mark(ctx->js, *(ant_value_t *)root_addr); 165 + } 166 + 167 + static bool jit_get_stack_bounds(ant_t *js, uintptr_t sp, uintptr_t *lo, uintptr_t *hi) { 168 + uintptr_t base = 0; 169 + mco_coro *running = mco_running(); 170 + if (running && running->stack_base && running->stack_size > 0) 171 + base = (uintptr_t)running->stack_base + running->stack_size; 172 + else if (js) 173 + base = (uintptr_t)js->cstk.base; 174 + 175 + if (!base || !sp) return false; 176 + uintptr_t minp = sp < base ? sp : base; 177 + uintptr_t maxp = sp < base ? base : sp; 178 + minp = (minp + sizeof(void *) - 1u) & ~(uintptr_t)(sizeof(void *) - 1u); 179 + maxp &= ~(uintptr_t)(sizeof(void *) - 1u); 180 + if (minp >= maxp) return false; 181 + *lo = minp; 182 + *hi = maxp; 183 + return true; 184 + } 185 + 186 + static bool jit_frame_in_bounds(void **fp, uintptr_t lo, uintptr_t hi) { 187 + uintptr_t addr = (uintptr_t)fp; 188 + return fp && (addr & (sizeof(void *) - 1u)) == 0 189 + && addr >= lo && addr + 2 * sizeof(void *) <= hi; 190 + } 191 + 192 + void sv_jit_mark_roots(ant_t *js, void (*mark)(ant_t *, ant_value_t)) { 193 + sv_jit_ctx_t *jc = jit_ctx_get(js); 194 + if (!jc || !mark || jc->func_items_len == 0) return; 195 + 196 + jit_gc_mark_ctx_t mark_ctx = { js, mark }; 197 + volatile uint8_t sp_marker = 0; 198 + uintptr_t stack_lo, stack_hi; 199 + if (!jit_get_stack_bounds(js, (uintptr_t)&sp_marker, &stack_lo, &stack_hi)) return; 200 + 201 + void **fp = __builtin_frame_address(0); 202 + for (int depth = 0; fp && depth < 256; depth++) { 203 + if (!jit_frame_in_bounds(fp, stack_lo, stack_hi)) break; 204 + void **next_fp = (void **)fp[0]; 205 + void *return_pc = fp[1]; 206 + 207 + for (size_t i = 0; i < jc->func_items_len; i++) 208 + MIR_visit_gc_roots(jc->ctx, jc->func_items[i], return_pc, fp, jit_gc_mark_root, &mark_ctx); 209 + 210 + if (!jit_frame_in_bounds(next_fp, stack_lo, stack_hi)) break; 211 + if (next_fp <= fp) break; 212 + fp = next_fp; 213 + } 214 + } 215 + 136 216 137 217 typedef struct { 138 218 MIR_reg_t *regs; ··· 208 288 } 209 289 210 290 211 - #define MIR_JSVAL MIR_T_I64 291 + #define MIR_JSVAL MIR_T_GC 212 292 213 293 #define JIT_ERR_TAG ((NANBOX_PREFIX >> NANBOX_TYPE_SHIFT) | T_ERR) 214 294 ··· 264 344 MIR_reg_t d_slot) { 265 345 if (!vs->slot_type) return; 266 346 for (int i = 0; i < vs->sp; i++) 347 + vstack_ensure_boxed(vs, i, ctx, fn, d_slot); 348 + } 349 + 350 + static void vstack_flush_range_to_boxed(jit_vstack_t *vs, int start, int end, 351 + MIR_context_t ctx, MIR_item_t fn, 352 + MIR_reg_t d_slot) { 353 + if (!vs->slot_type) return; 354 + if (start < 0) start = 0; 355 + if (end > vs->sp) end = vs->sp; 356 + for (int i = start; i < end; i++) 267 357 vstack_ensure_boxed(vs, i, ctx, fn, d_slot); 268 358 } 269 359 ··· 4703 4793 4704 4794 case OP_TAIL_CALL: 4705 4795 case OP_CALL: { 4706 - vstack_flush_to_boxed(&vs, ctx, jit_func, r_d_slot); 4707 4796 bool is_tail = (op == OP_TAIL_CALL); 4708 4797 uint16_t call_argc = sv_get_u16(ip + 1); 4709 4798 if (call_argc > 16 || vs.sp < (int)call_argc + 1) { ok = false; break; } 4799 + int call_base = vs.sp - (int)call_argc - 1; 4800 + if (is_tail) 4801 + vstack_flush_to_boxed(&vs, ctx, jit_func, r_d_slot); 4802 + else 4803 + vstack_flush_range_to_boxed(&vs, call_base, vs.sp, ctx, jit_func, r_d_slot); 4710 4804 4711 4805 if (!is_tail) { 4712 4806 sv_func_t *inline_callee = vs.known_func[vs.sp - call_argc - 1]; ··· 8221 8315 8222 8316 func->jit_compiled_tfb_ver = func->tfb_version; 8223 8317 func->jit_compiling = false; 8224 - return MIR_gen(ctx, jit_func); 8318 + sv_jit_func_t compiled = MIR_gen(ctx, jit_func); 8319 + if (!compiled) return NULL; 8320 + func->jit_mir_item = jit_func; 8321 + if (!jit_ctx_add_func(jc, jit_func)) { 8322 + func->jit_code = NULL; 8323 + func->jit_mir_item = NULL; 8324 + return NULL; 8325 + } 8326 + return compiled; 8225 8327 } 8226 8328 8227 8329 static void sv_jit_compile_callees(ant_t *js, sv_func_t *func) {