Merge branch 'mcode_streamline' into runtime_rework
This commit is contained in:
@@ -11,8 +11,9 @@
|
||||
#include "cell_internal.h"
|
||||
#include "cJSON.h"
|
||||
|
||||
#define BOOTSTRAP_MCODE "boot/bootstrap.cm.mcode"
|
||||
#define BOOTSTRAP_SRC "internal/bootstrap.cm"
|
||||
#define BOOTSTRAP_MCODE "boot/bootstrap.cm.mcode"
|
||||
#define SEED_BOOTSTRAP_MCODE "boot/seed_bootstrap.cm.mcode"
|
||||
#define BOOTSTRAP_SRC "internal/bootstrap.cm"
|
||||
#define CELL_SHOP_DIR ".cell"
|
||||
#define CELL_CORE_DIR "packages/core"
|
||||
|
||||
@@ -362,6 +363,7 @@ static void print_usage(const char *prog)
|
||||
printf(" --core <path> Set core path directly (overrides CELL_CORE)\n");
|
||||
printf(" --shop <path> Set shop path (overrides CELL_SHOP)\n");
|
||||
printf(" --dev Dev mode (shop=.cell, core=.)\n");
|
||||
printf(" --seed Use seed bootstrap (minimal, for regen)\n");
|
||||
printf(" --test [heap_size] Run C test suite\n");
|
||||
printf(" -h, --help Show this help message\n");
|
||||
printf("\nEnvironment:\n");
|
||||
@@ -394,6 +396,7 @@ int cell_init(int argc, char **argv)
|
||||
|
||||
/* Default: run script through bootstrap pipeline */
|
||||
int arg_start = 1;
|
||||
int seed_mode = 0;
|
||||
const char *shop_override = NULL;
|
||||
const char *core_override = NULL;
|
||||
|
||||
@@ -413,6 +416,9 @@ int cell_init(int argc, char **argv)
|
||||
}
|
||||
core_override = argv[arg_start + 1];
|
||||
arg_start += 2;
|
||||
} else if (strcmp(argv[arg_start], "--seed") == 0) {
|
||||
seed_mode = 1;
|
||||
arg_start++;
|
||||
} else if (strcmp(argv[arg_start], "--dev") == 0) {
|
||||
shop_override = ".cell";
|
||||
core_override = ".";
|
||||
@@ -438,8 +444,9 @@ int cell_init(int argc, char **argv)
|
||||
|
||||
actor_initialize();
|
||||
|
||||
const char *boot_mcode = seed_mode ? SEED_BOOTSTRAP_MCODE : BOOTSTRAP_MCODE;
|
||||
size_t boot_size;
|
||||
char *boot_data = load_core_file(BOOTSTRAP_MCODE, &boot_size);
|
||||
char *boot_data = load_core_file(boot_mcode, &boot_size);
|
||||
if (!boot_data) {
|
||||
printf("ERROR: Could not load bootstrap from %s\n", core_path);
|
||||
return 1;
|
||||
@@ -460,7 +467,7 @@ int cell_init(int argc, char **argv)
|
||||
free(bin_data);
|
||||
return 1;
|
||||
}
|
||||
JSContext *ctx = JS_NewContextWithHeapSize(g_runtime, 16 * 1024 * 1024);
|
||||
JSContext *ctx = JS_NewContextWithHeapSize(g_runtime, 1024 * 1024);
|
||||
if (!ctx) {
|
||||
printf("Failed to create JS context\n");
|
||||
free(bin_data); JS_FreeRuntime(g_runtime);
|
||||
|
||||
128
source/mach.c
128
source/mach.c
@@ -442,7 +442,7 @@ JSFrameRegister *alloc_frame_register(JSContext *ctx, int slot_count) {
|
||||
if (!frame) return NULL;
|
||||
|
||||
/* cap56 = slot count (used by gc_object_size) */
|
||||
frame->hdr = objhdr_make(slot_count, OBJ_FRAME, 0, 0, 0, 0);
|
||||
frame->header = objhdr_make(slot_count, OBJ_FRAME, 0, 0, 0, 0);
|
||||
frame->function = JS_NULL;
|
||||
frame->caller = JS_NULL;
|
||||
frame->address = JS_NewInt32(ctx, 0);
|
||||
@@ -767,9 +767,7 @@ JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code,
|
||||
/* Setup initial frame — wrap top-level code in a function object so that
|
||||
returning from a called register function can read code/env from frame */
|
||||
JSValue top_fn = js_new_register_function(ctx, code, env_gc.val, of_gc.val);
|
||||
JS_PopGCRef(ctx, &of_gc);
|
||||
env = env_gc.val; /* refresh — GC may have moved env during allocation */
|
||||
JS_PopGCRef(ctx, &env_gc);
|
||||
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
||||
frame->function = top_fn;
|
||||
frame->slots[0] = this_gc.val; /* slot 0 = this */
|
||||
@@ -780,6 +778,8 @@ JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code,
|
||||
}
|
||||
for (int i = nargs_copy - 1; i >= 0; i--) JS_PopGCRef(ctx, &arg_gcs[i]);
|
||||
JS_PopGCRef(ctx, &this_gc);
|
||||
JS_PopGCRef(ctx, &of_gc);
|
||||
JS_PopGCRef(ctx, &env_gc);
|
||||
|
||||
uint32_t pc = code->entry_point;
|
||||
JSValue result = JS_NULL;
|
||||
@@ -1262,100 +1262,6 @@ JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code,
|
||||
|
||||
/* === New mcode-derived opcodes === */
|
||||
|
||||
/* Typed integer arithmetic — inline with overflow to float */
|
||||
case MACH_ADD_INT: {
|
||||
int32_t ia = JS_VALUE_GET_INT(frame->slots[b]);
|
||||
int32_t ib = JS_VALUE_GET_INT(frame->slots[c]);
|
||||
int64_t r = (int64_t)ia + (int64_t)ib;
|
||||
frame->slots[a] = (r >= INT32_MIN && r <= INT32_MAX)
|
||||
? JS_NewInt32(ctx, (int32_t)r) : JS_NewFloat64(ctx, (double)r);
|
||||
break;
|
||||
}
|
||||
case MACH_SUB_INT: {
|
||||
int32_t ia = JS_VALUE_GET_INT(frame->slots[b]);
|
||||
int32_t ib = JS_VALUE_GET_INT(frame->slots[c]);
|
||||
int64_t r = (int64_t)ia - (int64_t)ib;
|
||||
frame->slots[a] = (r >= INT32_MIN && r <= INT32_MAX)
|
||||
? JS_NewInt32(ctx, (int32_t)r) : JS_NewFloat64(ctx, (double)r);
|
||||
break;
|
||||
}
|
||||
case MACH_MUL_INT: {
|
||||
int32_t ia = JS_VALUE_GET_INT(frame->slots[b]);
|
||||
int32_t ib = JS_VALUE_GET_INT(frame->slots[c]);
|
||||
int64_t r = (int64_t)ia * (int64_t)ib;
|
||||
frame->slots[a] = (r >= INT32_MIN && r <= INT32_MAX)
|
||||
? JS_NewInt32(ctx, (int32_t)r) : JS_NewFloat64(ctx, (double)r);
|
||||
break;
|
||||
}
|
||||
case MACH_DIV_INT: {
|
||||
int32_t ia = JS_VALUE_GET_INT(frame->slots[b]);
|
||||
int32_t ib = JS_VALUE_GET_INT(frame->slots[c]);
|
||||
if (ib == 0) { frame->slots[a] = JS_NULL; break; }
|
||||
if (ia % ib == 0) frame->slots[a] = JS_NewInt32(ctx, ia / ib);
|
||||
else frame->slots[a] = JS_NewFloat64(ctx, (double)ia / (double)ib);
|
||||
break;
|
||||
}
|
||||
case MACH_MOD_INT: {
|
||||
int32_t ia = JS_VALUE_GET_INT(frame->slots[b]);
|
||||
int32_t ib = JS_VALUE_GET_INT(frame->slots[c]);
|
||||
if (ib == 0) { frame->slots[a] = JS_NULL; break; }
|
||||
frame->slots[a] = JS_NewInt32(ctx, ia % ib);
|
||||
break;
|
||||
}
|
||||
case MACH_NEG_INT: {
|
||||
int32_t i = JS_VALUE_GET_INT(frame->slots[b]);
|
||||
if (i == INT32_MIN)
|
||||
frame->slots[a] = JS_NewFloat64(ctx, -(double)i);
|
||||
else
|
||||
frame->slots[a] = JS_NewInt32(ctx, -i);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Typed float arithmetic */
|
||||
case MACH_ADD_FLOAT: {
|
||||
double da, db;
|
||||
JS_ToFloat64(ctx, &da, frame->slots[b]);
|
||||
JS_ToFloat64(ctx, &db, frame->slots[c]);
|
||||
frame->slots[a] = JS_NewFloat64(ctx, da + db);
|
||||
break;
|
||||
}
|
||||
case MACH_SUB_FLOAT: {
|
||||
double da, db;
|
||||
JS_ToFloat64(ctx, &da, frame->slots[b]);
|
||||
JS_ToFloat64(ctx, &db, frame->slots[c]);
|
||||
frame->slots[a] = JS_NewFloat64(ctx, da - db);
|
||||
break;
|
||||
}
|
||||
case MACH_MUL_FLOAT: {
|
||||
double da, db;
|
||||
JS_ToFloat64(ctx, &da, frame->slots[b]);
|
||||
JS_ToFloat64(ctx, &db, frame->slots[c]);
|
||||
frame->slots[a] = JS_NewFloat64(ctx, da * db);
|
||||
break;
|
||||
}
|
||||
case MACH_DIV_FLOAT: {
|
||||
double da, db;
|
||||
JS_ToFloat64(ctx, &da, frame->slots[b]);
|
||||
JS_ToFloat64(ctx, &db, frame->slots[c]);
|
||||
if (db == 0.0) { frame->slots[a] = JS_NULL; break; }
|
||||
frame->slots[a] = JS_NewFloat64(ctx, da / db);
|
||||
break;
|
||||
}
|
||||
case MACH_MOD_FLOAT: {
|
||||
double da, db;
|
||||
JS_ToFloat64(ctx, &da, frame->slots[b]);
|
||||
JS_ToFloat64(ctx, &db, frame->slots[c]);
|
||||
if (db == 0.0) { frame->slots[a] = JS_NULL; break; }
|
||||
frame->slots[a] = JS_NewFloat64(ctx, fmod(da, db));
|
||||
break;
|
||||
}
|
||||
case MACH_NEG_FLOAT: {
|
||||
double d;
|
||||
JS_ToFloat64(ctx, &d, frame->slots[b]);
|
||||
frame->slots[a] = JS_NewFloat64(ctx, -d);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Text concatenation */
|
||||
case MACH_CONCAT: {
|
||||
JSValue res = JS_ConcatString(ctx, frame->slots[b], frame->slots[c]);
|
||||
@@ -1653,7 +1559,7 @@ JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code,
|
||||
case MACH_INVOKE: {
|
||||
/* A=frame_slot, B=result_slot */
|
||||
JSFrameRegister *fr = (JSFrameRegister *)JS_VALUE_GET_PTR(frame->slots[a]);
|
||||
int nr = (int)objhdr_cap56(fr->hdr);
|
||||
int nr = (int)objhdr_cap56(fr->header);
|
||||
int c_argc = (nr >= 2) ? nr - 2 : 0;
|
||||
JSValue fn_val = fr->function;
|
||||
JSFunction *fn = JS_VALUE_GET_FUNCTION(fn_val);
|
||||
@@ -1704,7 +1610,7 @@ JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code,
|
||||
case MACH_GOINVOKE: {
|
||||
/* Tail call: replace current frame with callee */
|
||||
JSFrameRegister *fr = (JSFrameRegister *)JS_VALUE_GET_PTR(frame->slots[a]);
|
||||
int nr = (int)objhdr_cap56(fr->hdr);
|
||||
int nr = (int)objhdr_cap56(fr->header);
|
||||
int c_argc = (nr >= 2) ? nr - 2 : 0;
|
||||
JSValue fn_val = fr->function;
|
||||
JSFunction *fn = JS_VALUE_GET_FUNCTION(fn_val);
|
||||
@@ -2022,7 +1928,7 @@ static int mcode_reg_items(cJSON *it, cJSON **out) {
|
||||
{ ADD(1); return c; }
|
||||
|
||||
/* invoke: [1]=frame, [2]=dest (result register) */
|
||||
if (!strcmp(op, "invoke")) { ADD(1); ADD(2); return c; }
|
||||
if (!strcmp(op, "invoke") || !strcmp(op, "tail_invoke")) { ADD(1); ADD(2); return c; }
|
||||
/* goinvoke: [1]=frame only (no result) */
|
||||
if (!strcmp(op, "goinvoke")) { ADD(1); return c; }
|
||||
|
||||
@@ -2375,24 +2281,16 @@ static MachCode *mcode_lower_func(cJSON *fobj, const char *filename) {
|
||||
else if (strcmp(op, "false") == 0) { EM(MACH_ABC(MACH_LOADFALSE, A1, 0, 0)); }
|
||||
else if (strcmp(op, "null") == 0) { EM(MACH_ABC(MACH_LOADNULL, A1, 0, 0)); }
|
||||
else if (strcmp(op, "move") == 0) { AB2(MACH_MOVE); }
|
||||
/* Typed integer arithmetic */
|
||||
else if (strcmp(op, "add_int") == 0) { ABC3(MACH_ADD_INT); }
|
||||
else if (strcmp(op, "sub_int") == 0) { ABC3(MACH_SUB_INT); }
|
||||
else if (strcmp(op, "mul_int") == 0) { ABC3(MACH_MUL_INT); }
|
||||
else if (strcmp(op, "div_int") == 0) { ABC3(MACH_DIV_INT); }
|
||||
else if (strcmp(op, "mod_int") == 0) { ABC3(MACH_MOD_INT); }
|
||||
else if (strcmp(op, "neg_int") == 0) { AB2(MACH_NEG_INT); }
|
||||
/* Typed float arithmetic */
|
||||
else if (strcmp(op, "add_float") == 0) { ABC3(MACH_ADD_FLOAT); }
|
||||
else if (strcmp(op, "sub_float") == 0) { ABC3(MACH_SUB_FLOAT); }
|
||||
else if (strcmp(op, "mul_float") == 0) { ABC3(MACH_MUL_FLOAT); }
|
||||
else if (strcmp(op, "div_float") == 0) { ABC3(MACH_DIV_FLOAT); }
|
||||
else if (strcmp(op, "mod_float") == 0) { ABC3(MACH_MOD_FLOAT); }
|
||||
else if (strcmp(op, "neg_float") == 0) { AB2(MACH_NEG_FLOAT); }
|
||||
/* Text */
|
||||
else if (strcmp(op, "concat") == 0) { ABC3(MACH_CONCAT); }
|
||||
/* Generic arithmetic */
|
||||
else if (strcmp(op, "add") == 0) { ABC3(MACH_ADD); }
|
||||
else if (strcmp(op, "subtract") == 0) { ABC3(MACH_SUB); }
|
||||
else if (strcmp(op, "multiply") == 0) { ABC3(MACH_MUL); }
|
||||
else if (strcmp(op, "divide") == 0) { ABC3(MACH_DIV); }
|
||||
else if (strcmp(op, "modulo") == 0) { ABC3(MACH_MOD); }
|
||||
else if (strcmp(op, "pow") == 0) { ABC3(MACH_POW); }
|
||||
else if (strcmp(op, "negate") == 0) { AB2(MACH_NEG); }
|
||||
/* Typed integer comparisons */
|
||||
else if (strcmp(op, "eq_int") == 0) { ABC3(MACH_EQ_INT); }
|
||||
else if (strcmp(op, "ne_int") == 0) { ABC3(MACH_NE_INT); }
|
||||
@@ -2569,7 +2467,7 @@ static MachCode *mcode_lower_func(cJSON *fobj, const char *filename) {
|
||||
else if (strcmp(op, "setarg") == 0) {
|
||||
EM(MACH_ABC(MACH_SETARG, A1, A2, A3));
|
||||
}
|
||||
else if (strcmp(op, "invoke") == 0) {
|
||||
else if (strcmp(op, "invoke") == 0 || strcmp(op, "tail_invoke") == 0) {
|
||||
EM(MACH_ABC(MACH_INVOKE, A1, A2, 0));
|
||||
}
|
||||
else if (strcmp(op, "goframe") == 0) {
|
||||
|
||||
@@ -356,7 +356,7 @@ void cell_rt_setarg(JSValue frame_val, int64_t idx, JSValue val) {
|
||||
|
||||
JSValue cell_rt_invoke(JSContext *ctx, JSValue frame_val) {
|
||||
JSFrameRegister *fr = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_val);
|
||||
int nr_slots = (int)objhdr_cap56(fr->hdr);
|
||||
int nr_slots = (int)objhdr_cap56(fr->header);
|
||||
int c_argc = (nr_slots >= 2) ? nr_slots - 2 : 0;
|
||||
|
||||
/* Copy args to C stack */
|
||||
|
||||
@@ -115,6 +115,14 @@
|
||||
#define gc_poison_region(addr, size) ((void)0)
|
||||
#define gc_unpoison_region(addr, size) ((void)0)
|
||||
#endif
|
||||
|
||||
#include <sys/mman.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static inline size_t poison_page_align(size_t size) {
|
||||
size_t ps = (size_t)sysconf(_SC_PAGESIZE);
|
||||
return (size + ps - 1) & ~(ps - 1);
|
||||
}
|
||||
#endif /* POISON_HEAP */
|
||||
|
||||
#ifdef HAVE_ASAN
|
||||
@@ -361,13 +369,7 @@ struct JSClass {
|
||||
#define JS_MODE_BACKTRACE_BARRIER \
|
||||
(1 << 3) /* stop backtrace before this frame */
|
||||
|
||||
typedef struct JSFrameRegister {
|
||||
objhdr_t hdr; // capacity in this is the total number of words of the object, including the 4 words of overhead and all slots
|
||||
JSValue function; // JSFunction, function object being invoked
|
||||
JSValue caller; // JSFrameRegister, the frame that called this one
|
||||
JSValue address; // address of the instruction in the code that should be executed upon return
|
||||
JSValue slots[]; // inline memory. order is [this][input args][closed over vars][non closed over vars][temporaries]
|
||||
} JSFrameRegister; /// extra note: when this frame returns, caller should be set to 0. If caller is found to be 0, then the GC can reduce this frame's slots down to [this][input_args][closed over vars]; if no closed over vars it can be totally removed; may happen naturally in GC since it would have no refs?
|
||||
/* JSFrameRegister is now an alias for JSFrame — see JSFrame definition below */
|
||||
|
||||
/* ============================================================
|
||||
Register-Based VM Data Structures
|
||||
@@ -554,22 +556,6 @@ typedef enum MachOpcode {
|
||||
|
||||
/* === New mcode-derived opcodes (1:1 mapping to mcode IR) === */
|
||||
|
||||
/* Typed integer arithmetic (ABC) */
|
||||
MACH_ADD_INT, /* R(A) = R(B) + R(C) — int, overflow → float */
|
||||
MACH_SUB_INT, /* R(A) = R(B) - R(C) — int */
|
||||
MACH_MUL_INT, /* R(A) = R(B) * R(C) — int */
|
||||
MACH_DIV_INT, /* R(A) = R(B) / R(C) — int */
|
||||
MACH_MOD_INT, /* R(A) = R(B) % R(C) — int */
|
||||
MACH_NEG_INT, /* R(A) = -R(B) — int (AB) */
|
||||
|
||||
/* Typed float arithmetic (ABC) */
|
||||
MACH_ADD_FLOAT, /* R(A) = R(B) + R(C) — float */
|
||||
MACH_SUB_FLOAT, /* R(A) = R(B) - R(C) — float */
|
||||
MACH_MUL_FLOAT, /* R(A) = R(B) * R(C) — float */
|
||||
MACH_DIV_FLOAT, /* R(A) = R(B) / R(C) — float */
|
||||
MACH_MOD_FLOAT, /* R(A) = R(B) % R(C) — float */
|
||||
MACH_NEG_FLOAT, /* R(A) = -R(B) — float (AB) */
|
||||
|
||||
/* Text */
|
||||
MACH_CONCAT, /* R(A) = R(B) ++ R(C) — string concatenation */
|
||||
|
||||
@@ -723,18 +709,6 @@ static const char *mach_opcode_names[MACH_OP_COUNT] = {
|
||||
[MACH_NEQ_TOL] = "neq_tol",
|
||||
[MACH_NOP] = "nop",
|
||||
/* Mcode-derived */
|
||||
[MACH_ADD_INT] = "add_int",
|
||||
[MACH_SUB_INT] = "sub_int",
|
||||
[MACH_MUL_INT] = "mul_int",
|
||||
[MACH_DIV_INT] = "div_int",
|
||||
[MACH_MOD_INT] = "mod_int",
|
||||
[MACH_NEG_INT] = "neg_int",
|
||||
[MACH_ADD_FLOAT] = "add_float",
|
||||
[MACH_SUB_FLOAT] = "sub_float",
|
||||
[MACH_MUL_FLOAT] = "mul_float",
|
||||
[MACH_DIV_FLOAT] = "div_float",
|
||||
[MACH_MOD_FLOAT] = "mod_float",
|
||||
[MACH_NEG_FLOAT] = "neg_float",
|
||||
[MACH_CONCAT] = "concat",
|
||||
[MACH_EQ_INT] = "eq_int",
|
||||
[MACH_NE_INT] = "ne_int",
|
||||
@@ -823,17 +797,18 @@ typedef struct JSCodeRegister {
|
||||
} JSCodeRegister;
|
||||
|
||||
|
||||
/* Frame for closures - used by link-time relocation model where closures
|
||||
reference outer frames via (depth, slot) addressing.
|
||||
Stores function as JSValue to survive GC movements. */
|
||||
/* Unified frame struct — used by the register VM and closures.
|
||||
All fields are JSValues so the GC can scan them uniformly. */
|
||||
typedef struct JSFrame {
|
||||
objhdr_t header; /* OBJ_FRAME, cap56 = slot count */
|
||||
JSValue function; /* JSValue for GC safety (use JS_VALUE_GET_FUNCTION) */
|
||||
JSValue caller; /* JSValue for GC safety (unused currently) */
|
||||
uint32_t return_pc;
|
||||
JSValue function; /* JSFunction, function object being invoked */
|
||||
JSValue caller; /* JSFrame, the frame that called this one */
|
||||
JSValue address; /* return PC stored as JS_NewInt32 */
|
||||
JSValue slots[]; /* [this][args][captured][locals][temps] */
|
||||
} JSFrame;
|
||||
|
||||
typedef JSFrame JSFrameRegister;
|
||||
|
||||
static inline objhdr_t objhdr_set_s (objhdr_t h, bool s) {
|
||||
return s ? (h | OBJHDR_S_MASK) : (h & ~OBJHDR_S_MASK);
|
||||
}
|
||||
@@ -903,7 +878,8 @@ typedef struct JSArray {
|
||||
JSValue values[]; /* inline flexible array member */
|
||||
} JSArray;
|
||||
|
||||
/* JSBlob - binary data per memory.md */
|
||||
/* JSBlob — not allocated on GC heap (blobs use JSRecord + opaque).
|
||||
Struct kept for reference; gc_object_size/gc_scan_object do not handle OBJ_BLOB. */
|
||||
typedef struct JSBlob {
|
||||
objhdr_t mist_hdr;
|
||||
word_t length;
|
||||
@@ -926,7 +902,7 @@ typedef slot JSRecordEntry;
|
||||
|
||||
typedef struct JSRecord {
|
||||
objhdr_t mist_hdr;
|
||||
struct JSRecord *proto;
|
||||
JSValue proto; /* prototype as JSValue (JS_NULL if none) */
|
||||
word_t len; /* number of entries */
|
||||
slot slots[]; /* slots[0] reserved: key low32=class_id, key high32=rec_id, val=opaque */
|
||||
} JSRecord;
|
||||
@@ -1071,6 +1047,13 @@ static JS_BOOL JSText_equal_ascii (const JSText *text, JSValue imm) {
|
||||
enough to call the interrupt callback often. */
|
||||
#define JS_INTERRUPT_COUNTER_INIT 10000
|
||||
|
||||
/* Auto-rooted C call argv — GC updates values in-place */
|
||||
typedef struct CCallRoot {
|
||||
JSValue *argv; /* points to C-stack-local array */
|
||||
int argc;
|
||||
struct CCallRoot *prev; /* stack for nesting (C -> JS -> C -> ...) */
|
||||
} CCallRoot;
|
||||
|
||||
struct JSContext {
|
||||
JSRuntime *rt;
|
||||
|
||||
@@ -1081,18 +1064,18 @@ struct JSContext {
|
||||
size_t current_block_size; /* current block size (64KB initially) */
|
||||
size_t next_block_size; /* doubles if <10% recovered after GC */
|
||||
|
||||
/* Stone arena - permanent immutable allocations */
|
||||
uint8_t *stone_base; /* stone arena base */
|
||||
uint8_t *stone_free; /* stone arena bump pointer */
|
||||
uint8_t *stone_end; /* stone arena end */
|
||||
/* Constant text pool — compilation constants */
|
||||
uint8_t *ct_base; /* pool base */
|
||||
uint8_t *ct_free; /* pool bump pointer */
|
||||
uint8_t *ct_end; /* pool end */
|
||||
|
||||
/* Stone text intern table */
|
||||
void *st_pages; /* stone page list for large allocations */
|
||||
uint32_t *st_text_hash; /* hash table (slot -> id) */
|
||||
JSText **st_text_array; /* array of JSText pointers indexed by id */
|
||||
uint32_t st_text_size; /* hash table size (power of 2) */
|
||||
uint32_t st_text_count; /* number of interned texts */
|
||||
uint32_t st_text_resize; /* threshold for resize */
|
||||
/* Constant text intern table */
|
||||
void *ct_pages; /* page list for large allocations */
|
||||
uint32_t *ct_hash; /* hash table (slot -> id) */
|
||||
JSText **ct_array; /* array of JSText pointers indexed by id */
|
||||
uint32_t ct_size; /* hash table size (power of 2) */
|
||||
uint32_t ct_count; /* number of interned texts */
|
||||
uint32_t ct_resize_threshold; /* threshold for resize */
|
||||
|
||||
uint16_t binary_object_count;
|
||||
int binary_object_size;
|
||||
@@ -1102,6 +1085,7 @@ struct JSContext {
|
||||
|
||||
JSGCRef *top_gc_ref; /* used to reference temporary GC roots (stack top) */
|
||||
JSGCRef *last_gc_ref; /* used to reference temporary GC roots (list) */
|
||||
CCallRoot *c_call_root; /* stack of auto-rooted C call argv arrays */
|
||||
|
||||
int class_count; /* size of class_array and class_proto */
|
||||
JSClass *class_array;
|
||||
@@ -1161,22 +1145,22 @@ static inline const char *JS_KeyGetStr (JSContext *ctx, char *buf, size_t buf_si
|
||||
|
||||
|
||||
/* ============================================================
|
||||
Stone Arena Functions
|
||||
Constant Text Pool Functions
|
||||
============================================================ */
|
||||
|
||||
/* Stone page for large allocations */
|
||||
typedef struct StonePage {
|
||||
struct StonePage *next;
|
||||
/* Constant text page for large allocations */
|
||||
typedef struct CTPage {
|
||||
struct CTPage *next;
|
||||
size_t size;
|
||||
uint8_t data[];
|
||||
} StonePage;
|
||||
} CTPage;
|
||||
|
||||
/* Initial stone text table size */
|
||||
#define ST_TEXT_INITIAL_SIZE 256
|
||||
/* Initial constant text table size */
|
||||
#define CT_INITIAL_SIZE 256
|
||||
|
||||
/* Allocate from stone arena (permanent, immutable memory) */
|
||||
/* Allocate from constant text pool */
|
||||
|
||||
/* Resize the stone text intern hash table */
|
||||
/* Resize the constant text intern hash table */
|
||||
|
||||
/* Realloc with slack reporting (for bump allocator)
|
||||
WARNING: This function is NOT GC-safe! The caller must protect the source
|
||||
@@ -1192,9 +1176,9 @@ static int ctx_gc (JSContext *ctx, int allow_grow, size_t alloc_size);
|
||||
/* JS_MarkValue - mark a value during GC traversal.
|
||||
With copying GC, this is a no-op as we discover live objects by tracing. */
|
||||
|
||||
/* Helper to check if a pointer is in stone memory */
|
||||
static inline int is_stone_ptr (JSContext *ctx, void *ptr) {
|
||||
return (uint8_t *)ptr >= ctx->stone_base && (uint8_t *)ptr < ctx->stone_end;
|
||||
/* Helper to check if a pointer is in constant text pool memory */
|
||||
static inline int is_ct_ptr (JSContext *ctx, void *ptr) {
|
||||
return (uint8_t *)ptr >= ctx->ct_base && (uint8_t *)ptr < ctx->ct_end;
|
||||
}
|
||||
|
||||
/* Intern a UTF-32 string as a stone text, returning a JSValue string */
|
||||
@@ -1234,7 +1218,7 @@ typedef struct JSRegExp {
|
||||
|
||||
/* Get prototype from object (works for both JSRecord and JSRecord since they
|
||||
* share layout) */
|
||||
#define JS_OBJ_GET_PROTO(p) ((JSRecord *)((JSRecord *)(p))->proto)
|
||||
#define JS_OBJ_GET_PROTO(p) (JS_IsNull(((JSRecord *)(p))->proto) ? NULL : (JSRecord *)JS_VALUE_GET_PTR(((JSRecord *)(p))->proto))
|
||||
|
||||
/* Initial capacity for new records (mask = 7, 8 slots total) */
|
||||
#define JS_RECORD_INITIAL_MASK 7
|
||||
@@ -1554,9 +1538,9 @@ JSText *pretext_concat_value (JSContext *ctx, JSText *s, JSValue v);
|
||||
JSValue js_new_blob (JSContext *ctx, blob *b);
|
||||
/* Functions from header region (defined in runtime.c) */
|
||||
void *js_realloc (JSContext *ctx, void *ptr, size_t size);
|
||||
void *st_alloc (JSContext *ctx, size_t bytes, size_t align);
|
||||
void st_free_all (JSContext *ctx);
|
||||
int st_text_resize (JSContext *ctx);
|
||||
void *ct_alloc (JSContext *ctx, size_t bytes, size_t align);
|
||||
void ct_free_all (JSContext *ctx);
|
||||
int ct_resize (JSContext *ctx);
|
||||
JSValue intern_text_to_value (JSContext *ctx, const uint32_t *utf32, uint32_t len);
|
||||
JSValue js_key_new (JSContext *ctx, const char *str);
|
||||
JSValue js_key_new_len (JSContext *ctx, const char *str, size_t len);
|
||||
|
||||
763
source/runtime.c
763
source/runtime.c
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user