optimize frames; remove trampoline
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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 --- */
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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, ÷nd) < 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, ÷nd) < 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);
|
||||
|
||||
Reference in New Issue
Block a user