optimize frames; remove trampoline

This commit is contained in:
2026-02-18 22:37:48 -06:00
parent 27ca008f18
commit e004b2c472
14 changed files with 318 additions and 91 deletions

View File

@@ -37,6 +37,7 @@ static char *compute_blake2_hex(const char *data, size_t size) {
uint8_t hash[32];
crypto_blake2b(hash, 32, (const uint8_t *)data, size);
char *hex = malloc(65);
if (!hex) return NULL;
for (int i = 0; i < 32; i++)
snprintf(hex + i * 2, 3, "%02x", hash[i]);
return hex;
@@ -64,6 +65,7 @@ static int write_cache_file(const char *path, const uint8_t *data, size_t size)
// Returns heap-allocated binary data and sets *out_size, or NULL on failure
static char *load_or_cache_bootstrap(const char *mcode_data, size_t mcode_size, size_t *out_size) {
char *hex = compute_blake2_hex(mcode_data, mcode_size);
if (!hex) return NULL;
char *cpath = build_cache_path(hex);
free(hex);
@@ -222,6 +224,7 @@ static char *try_engine_cache(size_t *out_size) {
char *hex = compute_blake2_hex(src, src_size);
free(src);
if (!hex) return NULL;
char *cpath = build_cache_path(hex);
if (!cpath) { free(hex); return NULL; }
free(hex);

View File

@@ -583,11 +583,13 @@ void cell_rt_put_closure(JSContext *ctx, void *fp, JSValue val, int64_t depth,
#define AOT_GC_REF_CHUNK_SIZE 1024
typedef struct AOTGCRefChunk {
JSGCRef refs[AOT_GC_REF_CHUNK_SIZE];
uint8_t inited[AOT_GC_REF_CHUNK_SIZE];
} AOTGCRefChunk;
static CELL_THREAD_LOCAL AOTGCRefChunk **g_aot_gc_ref_chunks = NULL;
static CELL_THREAD_LOCAL int g_aot_gc_ref_chunk_count = 0;
static CELL_THREAD_LOCAL int g_aot_depth = 0;
static CELL_THREAD_LOCAL JSContext *g_aot_gc_ref_ctx = NULL;
int cell_rt_native_active(void) {
return g_aot_depth > 0;
@@ -624,14 +626,50 @@ static inline JSGCRef *aot_gc_ref_at(int depth_index) {
return &g_aot_gc_ref_chunks[chunk_index]->refs[slot_index];
}
static inline uint8_t *aot_gc_ref_inited_at(int depth_index) {
int chunk_index = depth_index / AOT_GC_REF_CHUNK_SIZE;
int slot_index = depth_index % AOT_GC_REF_CHUNK_SIZE;
return &g_aot_gc_ref_chunks[chunk_index]->inited[slot_index];
}
/* GC refs are owned by a specific JSContext. If context changes on this thread,
unregister previous refs and reset per-slot initialization state. */
static void aot_gc_ref_reset_ctx(JSContext *ctx) {
if (g_aot_gc_ref_ctx == ctx)
return;
if (g_aot_gc_ref_ctx) {
for (int ci = 0; ci < g_aot_gc_ref_chunk_count; ci++) {
AOTGCRefChunk *chunk = g_aot_gc_ref_chunks[ci];
for (int si = 0; si < AOT_GC_REF_CHUNK_SIZE; si++) {
if (chunk->inited[si]) {
JS_DeleteGCRef(g_aot_gc_ref_ctx, &chunk->refs[si]);
chunk->inited[si] = 0;
chunk->refs[si].val = JS_NULL;
}
}
}
}
g_aot_gc_ref_ctx = ctx;
}
static inline void aot_gc_ref_activate(JSContext *ctx, int depth_index) {
JSGCRef *ref = aot_gc_ref_at(depth_index);
uint8_t *inited = aot_gc_ref_inited_at(depth_index);
if (!*inited) {
JS_AddGCRef(ctx, ref);
*inited = 1;
}
}
JSValue *cell_rt_enter_frame(JSContext *ctx, int64_t nr_slots) {
aot_gc_ref_reset_ctx(ctx);
if (!ensure_aot_gc_ref_slot(ctx, g_aot_depth)) {
return NULL;
}
JSFrameRegister *frame = alloc_frame_register(ctx, (int)nr_slots);
if (!frame) return NULL;
aot_gc_ref_activate(ctx, g_aot_depth);
JSGCRef *ref = aot_gc_ref_at(g_aot_depth);
JS_AddGCRef(ctx, ref);
ref->val = JS_MKPTR(frame);
g_aot_depth++;
return (JSValue *)frame->slots;
@@ -639,10 +677,11 @@ JSValue *cell_rt_enter_frame(JSContext *ctx, int64_t nr_slots) {
/* Push an already-allocated frame onto the active AOT frame stack. */
static int cell_rt_push_existing_frame(JSContext *ctx, JSValue frame_val) {
aot_gc_ref_reset_ctx(ctx);
if (!ensure_aot_gc_ref_slot(ctx, g_aot_depth))
return 0;
aot_gc_ref_activate(ctx, g_aot_depth);
JSGCRef *ref = aot_gc_ref_at(g_aot_depth);
JS_AddGCRef(ctx, ref);
ref->val = frame_val;
g_aot_depth++;
return 1;
@@ -682,12 +721,13 @@ JSValue *cell_rt_refresh_fp_checked(JSContext *ctx) {
}
void cell_rt_leave_frame(JSContext *ctx) {
(void)ctx;
if (g_aot_depth <= 0) {
fprintf(stderr, "[BUG] cell_rt_leave_frame underflow\n");
abort();
}
g_aot_depth--;
JS_DeleteGCRef(ctx, aot_gc_ref_at(g_aot_depth));
aot_gc_ref_at(g_aot_depth)->val = JS_NULL;
}
/* --- Function creation and calling --- */

View File

@@ -1426,8 +1426,6 @@ static JSValue js_cell_splat (JSContext *ctx, JSValue this_val, int argc, JSValu
static JSValue js_cell_meme (JSContext *ctx, JSValue this_val, int argc, JSValue *argv);
static JSValue js_cell_fn_apply (JSContext *ctx, JSValue this_val, int argc, JSValue *argv);
static JSValue js_cell_call (JSContext *ctx, JSValue this_val, int argc, JSValue *argv);
static JSValue js_cell_modulo (JSContext *ctx, JSValue this_val, int argc, JSValue *argv);
static JSValue js_cell_neg (JSContext *ctx, JSValue this_val, int argc, JSValue *argv);
static JSValue js_cell_not (JSContext *ctx, JSValue this_val, int argc, JSValue *argv);
JSValue js_cell_text_lower (JSContext *ctx, JSValue this_val, int argc, JSValue *argv);
JSValue js_cell_text_upper (JSContext *ctx, JSValue this_val, int argc, JSValue *argv);
@@ -1438,17 +1436,6 @@ static JSValue js_cell_text_search (JSContext *ctx, JSValue this_val, int argc,
static JSValue js_cell_text_extract (JSContext *ctx, JSValue this_val, int argc, JSValue *argv);
JSValue js_cell_character (JSContext *ctx, JSValue this_val, int argc, JSValue *argv);
static JSValue js_cell_number (JSContext *ctx, JSValue this_val, int argc, JSValue *argv);
static JSValue js_cell_number_abs (JSContext *ctx, JSValue this_val, int argc, JSValue *argv);
static JSValue js_cell_number_sign (JSContext *ctx, JSValue this_val, int argc, JSValue *argv);
static JSValue js_cell_number_floor (JSContext *ctx, JSValue this_val, int argc, JSValue *argv);
static JSValue js_cell_number_ceiling (JSContext *ctx, JSValue this_val, int argc, JSValue *argv);
static JSValue js_cell_number_round (JSContext *ctx, JSValue this_val, int argc, JSValue *argv);
static JSValue js_cell_number_trunc (JSContext *ctx, JSValue this_val, int argc, JSValue *argv);
static JSValue js_cell_number_whole (JSContext *ctx, JSValue this_val, int argc, JSValue *argv);
static JSValue js_cell_number_fraction (JSContext *ctx, JSValue this_val, int argc, JSValue *argv);
static JSValue js_cell_number_min (JSContext *ctx, JSValue this_val, int argc, JSValue *argv);
static JSValue js_cell_number_max (JSContext *ctx, JSValue this_val, int argc, JSValue *argv);
static JSValue js_cell_number_remainder (JSContext *ctx, JSValue this_val, int argc, JSValue *argv);
static JSValue js_cell_object (JSContext *ctx, JSValue this_val, int argc, JSValue *argv);
static JSValue js_cell_text_format (JSContext *ctx, JSValue this_val, int argc, JSValue *argv);
static JSValue js_print (JSContext *ctx, JSValue this_val, int argc, JSValue *argv);

View File

@@ -10514,15 +10514,46 @@ JSValue JS_CellCall (JSContext *ctx, JSValue fn, JSValue this_val, JSValue args)
return js_cell_call (ctx, JS_NULL, argc, argv);
}
static int js_cell_read_number_strict (JSValue val, double *out) {
uint32_t tag = JS_VALUE_GET_TAG (val);
if (tag == JS_TAG_INT) {
*out = (double)JS_VALUE_GET_INT (val);
return 0;
}
if (JS_TAG_IS_FLOAT64 (tag)) {
*out = JS_VALUE_GET_FLOAT64 (val);
return 0;
}
return -1;
}
static JSValue js_cell_number_from_double (JSContext *ctx, double d) {
if (d >= INT32_MIN && d <= INT32_MAX) {
int32_t i = (int32_t)d;
if ((double)i == d)
return JS_NewInt32 (ctx, i);
}
return JS_NewFloat64 (ctx, d);
}
/* C API: modulo(a, b) - modulo operation */
JSValue JS_CellModulo (JSContext *ctx, JSValue a, JSValue b) {
JSValue argv[2] = { a, b };
return js_cell_modulo (ctx, JS_NULL, 2, argv);
double dividend, divisor;
if (js_cell_read_number_strict (a, &dividend) < 0) return JS_NULL;
if (js_cell_read_number_strict (b, &divisor) < 0) return JS_NULL;
if (isnan (dividend) || isnan (divisor)) return JS_NULL;
if (divisor == 0.0) return JS_NULL;
if (dividend == 0.0) return JS_NewFloat64 (ctx, 0.0);
return js_cell_number_from_double (ctx,
dividend - (divisor * floor (dividend / divisor)));
}
/* C API: neg(val) - negate number */
JSValue JS_CellNeg (JSContext *ctx, JSValue val) {
return js_cell_neg (ctx, JS_NULL, 1, &val);
double d;
if (js_cell_read_number_strict (val, &d) < 0) return JS_NULL;
if (isnan (d)) return JS_NULL;
return js_cell_number_from_double (ctx, -d);
}
/* C API: not(val) - logical not */
@@ -10647,60 +10678,86 @@ JSValue JS_CellNumber (JSContext *ctx, JSValue val) {
/* C API: abs(num) - absolute value */
JSValue JS_CellAbs (JSContext *ctx, JSValue num) {
return js_cell_number_abs (ctx, JS_NULL, 1, &num);
double d;
if (js_cell_read_number_strict (num, &d) < 0) return JS_NULL;
return js_cell_number_from_double (ctx, fabs (d));
}
/* C API: sign(num) - sign of number (-1, 0, 1) */
JSValue JS_CellSign (JSContext *ctx, JSValue num) {
return js_cell_number_sign (ctx, JS_NULL, 1, &num);
double d;
if (js_cell_read_number_strict (num, &d) < 0) return JS_NULL;
if (d < 0) return JS_NewInt32 (ctx, -1);
if (d > 0) return JS_NewInt32 (ctx, 1);
return JS_NewInt32 (ctx, 0);
}
/* C API: floor(num) - floor */
JSValue JS_CellFloor (JSContext *ctx, JSValue num) {
return js_cell_number_floor (ctx, JS_NULL, 1, &num);
double d;
if (js_cell_read_number_strict (num, &d) < 0) return JS_NULL;
return js_cell_number_from_double (ctx, floor (d));
}
/* C API: ceiling(num) - ceiling */
JSValue JS_CellCeiling (JSContext *ctx, JSValue num) {
return js_cell_number_ceiling (ctx, JS_NULL, 1, &num);
double d;
if (js_cell_read_number_strict (num, &d) < 0) return JS_NULL;
return js_cell_number_from_double (ctx, ceil (d));
}
/* C API: round(num) - round to nearest integer */
JSValue JS_CellRound (JSContext *ctx, JSValue num) {
return js_cell_number_round (ctx, JS_NULL, 1, &num);
double d;
if (js_cell_read_number_strict (num, &d) < 0) return JS_NULL;
return js_cell_number_from_double (ctx, round (d));
}
/* C API: trunc(num) - truncate towards zero */
JSValue JS_CellTrunc (JSContext *ctx, JSValue num) {
return js_cell_number_trunc (ctx, JS_NULL, 1, &num);
double d;
if (js_cell_read_number_strict (num, &d) < 0) return JS_NULL;
return js_cell_number_from_double (ctx, trunc (d));
}
/* C API: whole(num) - integer part */
JSValue JS_CellWhole (JSContext *ctx, JSValue num) {
return js_cell_number_whole (ctx, JS_NULL, 1, &num);
double d;
if (js_cell_read_number_strict (num, &d) < 0) return JS_NULL;
return js_cell_number_from_double (ctx, trunc (d));
}
/* C API: fraction(num) - fractional part */
JSValue JS_CellFraction (JSContext *ctx, JSValue num) {
return js_cell_number_fraction (ctx, JS_NULL, 1, &num);
double d;
if (js_cell_read_number_strict (num, &d) < 0) return JS_NULL;
return js_cell_number_from_double (ctx, d - trunc (d));
}
/* C API: min(a, b) - minimum of two numbers */
JSValue JS_CellMin (JSContext *ctx, JSValue a, JSValue b) {
JSValue argv[2] = { a, b };
return js_cell_number_min (ctx, JS_NULL, 2, argv);
double da, db;
if (js_cell_read_number_strict (a, &da) < 0) return JS_NULL;
if (js_cell_read_number_strict (b, &db) < 0) return JS_NULL;
return js_cell_number_from_double (ctx, da < db ? da : db);
}
/* C API: max(a, b) - maximum of two numbers */
JSValue JS_CellMax (JSContext *ctx, JSValue a, JSValue b) {
JSValue argv[2] = { a, b };
return js_cell_number_max (ctx, JS_NULL, 2, argv);
double da, db;
if (js_cell_read_number_strict (a, &da) < 0) return JS_NULL;
if (js_cell_read_number_strict (b, &db) < 0) return JS_NULL;
return js_cell_number_from_double (ctx, da > db ? da : db);
}
/* C API: remainder(a, b) - remainder after division */
JSValue JS_CellRemainder (JSContext *ctx, JSValue a, JSValue b) {
JSValue argv[2] = { a, b };
return js_cell_number_remainder (ctx, JS_NULL, 2, argv);
double dividend, divisor;
if (js_cell_read_number_strict (a, &dividend) < 0) return JS_NULL;
if (js_cell_read_number_strict (b, &divisor) < 0) return JS_NULL;
if (divisor == 0.0) return JS_NULL;
return js_cell_number_from_double (ctx,
dividend - (trunc (dividend / divisor) * divisor));
}
/* Object functions */
@@ -11374,7 +11431,7 @@ static void JS_AddIntrinsicBaseObjects (JSContext *ctx) {
js_set_global_cfunc(ctx, "filter", js_cell_array_filter, 2);
js_set_global_cfunc(ctx, "sort", js_cell_array_sort, 2);
/* Number utility functions */
/* Number intrinsics: direct calls lower to mcode; globals remain for first-class use. */
js_set_global_cfunc(ctx, "whole", js_cell_number_whole, 1);
js_set_global_cfunc(ctx, "fraction", js_cell_number_fraction, 1);
js_set_global_cfunc(ctx, "floor", js_cell_number_floor, 2);