Merge branch 'fix_core_scripts' into quicken_mcode
This commit is contained in:
269
source/cell.c
269
source/cell.c
@@ -12,8 +12,7 @@
|
||||
#include "cJSON.h"
|
||||
|
||||
#define BOOTSTRAP_MCODE "boot/bootstrap.cm.mcode"
|
||||
#define SEED_BOOTSTRAP_MCODE "boot/seed_bootstrap.cm.mcode"
|
||||
#define BOOTSTRAP_SRC "internal/bootstrap.cm"
|
||||
#define ENGINE_SRC "internal/engine.cm"
|
||||
#define CELL_SHOP_DIR ".cell"
|
||||
#define CELL_CORE_DIR "packages/core"
|
||||
|
||||
@@ -213,6 +212,37 @@ static char* load_core_file(const char *filename, size_t *out_size) {
|
||||
return data;
|
||||
}
|
||||
|
||||
// Try loading engine.cm from source-hash cache
|
||||
// Returns heap-allocated binary data and sets *out_size, or NULL on cache miss
|
||||
static char *try_engine_cache(size_t *out_size) {
|
||||
size_t src_size;
|
||||
char *src = load_core_file(ENGINE_SRC, &src_size);
|
||||
if (!src) return NULL;
|
||||
|
||||
char *hex = compute_blake2_hex(src, src_size);
|
||||
free(src);
|
||||
char *cpath = build_cache_path(hex);
|
||||
if (!cpath) { free(hex); return NULL; }
|
||||
free(hex);
|
||||
|
||||
FILE *fh = fopen(cpath, "rb");
|
||||
if (!fh) { free(cpath); return NULL; }
|
||||
free(cpath);
|
||||
|
||||
fseek(fh, 0, SEEK_END);
|
||||
long file_size = ftell(fh);
|
||||
fseek(fh, 0, SEEK_SET);
|
||||
char *data = malloc(file_size);
|
||||
if (data && fread(data, 1, file_size, fh) == (size_t)file_size) {
|
||||
fclose(fh);
|
||||
*out_size = file_size;
|
||||
return data;
|
||||
}
|
||||
free(data);
|
||||
fclose(fh);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Get the core path for use by scripts
|
||||
const char* cell_get_core_path(void) {
|
||||
return core_path;
|
||||
@@ -254,26 +284,57 @@ void script_startup(cell_rt *prt)
|
||||
cell_rt *crt = JS_GetContextOpaque(js);
|
||||
JS_FreeValue(js, js_core_blob_use(js));
|
||||
|
||||
// Load pre-compiled bootstrap .mcode
|
||||
size_t boot_size;
|
||||
char *boot_data = load_core_file(BOOTSTRAP_MCODE, &boot_size);
|
||||
if (!boot_data) {
|
||||
printf("ERROR: Could not load bootstrap from %s!\n", core_path);
|
||||
return;
|
||||
}
|
||||
|
||||
// Try cache or compile mcode → binary
|
||||
// Try engine fast-path: load engine.cm from source-hash cache
|
||||
size_t bin_size;
|
||||
char *bin_data = load_or_cache_bootstrap(boot_data, boot_size, &bin_size);
|
||||
free(boot_data);
|
||||
char *bin_data = try_engine_cache(&bin_size);
|
||||
|
||||
if (!bin_data) {
|
||||
printf("ERROR: Failed to compile bootstrap mcode!\n");
|
||||
return;
|
||||
// Cold path: run bootstrap to seed cache, then retry
|
||||
size_t boot_size;
|
||||
char *boot_data = load_core_file(BOOTSTRAP_MCODE, &boot_size);
|
||||
if (!boot_data) {
|
||||
printf("ERROR: Could not load bootstrap from %s!\n", core_path);
|
||||
return;
|
||||
}
|
||||
size_t boot_bin_size;
|
||||
char *boot_bin = load_or_cache_bootstrap(boot_data, boot_size, &boot_bin_size);
|
||||
free(boot_data);
|
||||
if (!boot_bin) {
|
||||
printf("ERROR: Failed to compile bootstrap mcode!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// Build env for bootstrap (only needs os, core_path, shop_path)
|
||||
JSGCRef boot_env_ref;
|
||||
JS_AddGCRef(js, &boot_env_ref);
|
||||
boot_env_ref.val = JS_NewObject(js);
|
||||
JSValue btmp;
|
||||
btmp = js_core_os_use(js);
|
||||
JS_SetPropertyStr(js, boot_env_ref.val, "os", btmp);
|
||||
if (core_path) {
|
||||
btmp = JS_NewString(js, core_path);
|
||||
JS_SetPropertyStr(js, boot_env_ref.val, "core_path", btmp);
|
||||
}
|
||||
btmp = shop_path ? JS_NewString(js, shop_path) : JS_NULL;
|
||||
JS_SetPropertyStr(js, boot_env_ref.val, "shop_path", btmp);
|
||||
JSValue boot_env = JS_Stone(js, boot_env_ref.val);
|
||||
JS_DeleteGCRef(js, &boot_env_ref);
|
||||
|
||||
crt->state = ACTOR_RUNNING;
|
||||
JSValue bv = JS_RunMachBin(js, (const uint8_t *)boot_bin, boot_bin_size, boot_env);
|
||||
free(boot_bin);
|
||||
uncaught_exception(js, bv);
|
||||
crt->state = ACTOR_IDLE;
|
||||
|
||||
// Retry engine from cache
|
||||
bin_data = try_engine_cache(&bin_size);
|
||||
if (!bin_data) {
|
||||
printf("ERROR: Bootstrap ran but engine.cm not in cache!\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Create hidden environment
|
||||
// Note: evaluate allocating calls into temporaries before passing to
|
||||
// JS_SetPropertyStr, so env_ref.val is read AFTER GC may have moved it.
|
||||
// Build engine environment
|
||||
JSGCRef env_ref;
|
||||
JS_AddGCRef(js, &env_ref);
|
||||
env_ref.val = JS_NewObject(js);
|
||||
@@ -311,7 +372,7 @@ void script_startup(cell_rt *prt)
|
||||
JSValue hidden_env = JS_Stone(js, env_ref.val);
|
||||
JS_DeleteGCRef(js, &env_ref);
|
||||
|
||||
// Run from binary
|
||||
// Run engine from binary
|
||||
crt->state = ACTOR_RUNNING;
|
||||
JSValue v = JS_RunMachBin(js, (const uint8_t *)bin_data, bin_size, hidden_env);
|
||||
free(bin_data);
|
||||
@@ -371,7 +432,6 @@ static void print_usage(const char *prog)
|
||||
printf(" --shop <path> Set shop path (overrides CELL_SHOP)\n");
|
||||
printf(" --dev Dev mode (shop=.cell, core=.)\n");
|
||||
printf(" --heap <size> Initial heap size (e.g. 256MB, 1GB)\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");
|
||||
@@ -402,9 +462,8 @@ int cell_init(int argc, char **argv)
|
||||
return run_test_suite(heap_size);
|
||||
}
|
||||
|
||||
/* Default: run script through bootstrap pipeline */
|
||||
/* Default: run script through engine pipeline */
|
||||
int arg_start = 1;
|
||||
int seed_mode = 0;
|
||||
size_t heap_size = 1024 * 1024; /* 1MB default */
|
||||
const char *shop_override = NULL;
|
||||
const char *core_override = NULL;
|
||||
@@ -425,9 +484,6 @@ 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], "--heap") == 0) {
|
||||
if (arg_start + 1 >= argc) {
|
||||
printf("ERROR: --heap requires a size argument (e.g. 1GB, 256MB, 65536)\n");
|
||||
@@ -464,33 +520,15 @@ 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(boot_mcode, &boot_size);
|
||||
if (!boot_data) {
|
||||
printf("ERROR: Could not load bootstrap from %s\n", core_path);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Try cache or compile mcode → binary
|
||||
size_t bin_size;
|
||||
char *bin_data = load_or_cache_bootstrap(boot_data, boot_size, &bin_size);
|
||||
free(boot_data);
|
||||
if (!bin_data) {
|
||||
printf("ERROR: Failed to compile bootstrap mcode\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
g_runtime = JS_NewRuntime();
|
||||
if (!g_runtime) {
|
||||
printf("Failed to create JS runtime\n");
|
||||
free(bin_data);
|
||||
return 1;
|
||||
}
|
||||
JSContext *ctx = JS_NewContextWithHeapSize(g_runtime, heap_size);
|
||||
if (!ctx) {
|
||||
printf("Failed to create JS context\n");
|
||||
free(bin_data); JS_FreeRuntime(g_runtime);
|
||||
JS_FreeRuntime(g_runtime);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -525,47 +563,116 @@ int cell_init(int argc, char **argv)
|
||||
|
||||
JS_FreeValue(ctx, js_core_blob_use(ctx));
|
||||
|
||||
JSGCRef env_ref;
|
||||
JS_AddGCRef(ctx, &env_ref);
|
||||
env_ref.val = JS_NewObject(ctx);
|
||||
JSValue tmp;
|
||||
tmp = js_core_os_use(ctx);
|
||||
JS_SetPropertyStr(ctx, env_ref.val, "os", tmp);
|
||||
tmp = JS_NewString(ctx, core_path);
|
||||
JS_SetPropertyStr(ctx, env_ref.val, "core_path", tmp);
|
||||
tmp = shop_path ? JS_NewString(ctx, shop_path) : JS_NULL;
|
||||
JS_SetPropertyStr(ctx, env_ref.val, "shop_path", tmp);
|
||||
JS_SetPropertyStr(ctx, env_ref.val, "actorsym", JS_DupValue(ctx, cli_rt->actor_sym_ref.val));
|
||||
tmp = js_core_json_use(ctx);
|
||||
JS_SetPropertyStr(ctx, env_ref.val, "json", tmp);
|
||||
JS_SetPropertyStr(ctx, env_ref.val, "init", JS_NULL);
|
||||
JSGCRef args_ref;
|
||||
JS_AddGCRef(ctx, &args_ref);
|
||||
args_ref.val = JS_NewArray(ctx);
|
||||
for (int i = arg_start; i < argc; i++) {
|
||||
JSValue str = JS_NewString(ctx, argv[i]);
|
||||
JS_ArrayPush(ctx, &args_ref.val, str);
|
||||
}
|
||||
JS_SetPropertyStr(ctx, env_ref.val, "args", args_ref.val);
|
||||
JS_DeleteGCRef(ctx, &args_ref);
|
||||
JSValue hidden_env = JS_Stone(ctx, env_ref.val);
|
||||
JS_DeleteGCRef(ctx, &env_ref);
|
||||
|
||||
JSValue result = JS_RunMachBin(ctx, (const uint8_t *)bin_data, bin_size, hidden_env);
|
||||
free(bin_data);
|
||||
|
||||
int exit_code = 0;
|
||||
if (JS_IsException(result)) {
|
||||
JS_GetException(ctx);
|
||||
exit_code = 1;
|
||||
} else if (!JS_IsNull(result)) {
|
||||
const char *str = JS_ToCString(ctx, result);
|
||||
if (str) {
|
||||
printf("%s\n", str);
|
||||
JS_FreeCString(ctx, str);
|
||||
|
||||
// Try engine fast-path: load engine.cm from source-hash cache
|
||||
size_t bin_size;
|
||||
char *bin_data = try_engine_cache(&bin_size);
|
||||
|
||||
if (!bin_data) {
|
||||
// Cold path: run bootstrap to seed cache, then retry
|
||||
size_t boot_size;
|
||||
char *boot_data = load_core_file(BOOTSTRAP_MCODE, &boot_size);
|
||||
if (!boot_data) {
|
||||
printf("ERROR: Could not load bootstrap from %s\n", core_path);
|
||||
return 1;
|
||||
}
|
||||
size_t boot_bin_size;
|
||||
char *boot_bin = load_or_cache_bootstrap(boot_data, boot_size, &boot_bin_size);
|
||||
free(boot_data);
|
||||
if (!boot_bin) {
|
||||
printf("ERROR: Failed to compile bootstrap mcode\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Build env for bootstrap (os, core_path, shop_path required;
|
||||
// args, json, actorsym provided for compatibility)
|
||||
JSGCRef boot_env_ref;
|
||||
JS_AddGCRef(ctx, &boot_env_ref);
|
||||
boot_env_ref.val = JS_NewObject(ctx);
|
||||
JSValue btmp;
|
||||
btmp = js_core_os_use(ctx);
|
||||
JS_SetPropertyStr(ctx, boot_env_ref.val, "os", btmp);
|
||||
btmp = JS_NewString(ctx, core_path);
|
||||
JS_SetPropertyStr(ctx, boot_env_ref.val, "core_path", btmp);
|
||||
btmp = shop_path ? JS_NewString(ctx, shop_path) : JS_NULL;
|
||||
JS_SetPropertyStr(ctx, boot_env_ref.val, "shop_path", btmp);
|
||||
JS_SetPropertyStr(ctx, boot_env_ref.val, "actorsym", JS_DupValue(ctx, cli_rt->actor_sym_ref.val));
|
||||
btmp = js_core_json_use(ctx);
|
||||
JS_SetPropertyStr(ctx, boot_env_ref.val, "json", btmp);
|
||||
JS_SetPropertyStr(ctx, boot_env_ref.val, "init", JS_NULL);
|
||||
JSGCRef boot_args_ref;
|
||||
JS_AddGCRef(ctx, &boot_args_ref);
|
||||
boot_args_ref.val = JS_NewArray(ctx);
|
||||
for (int i = arg_start; i < argc; i++) {
|
||||
JSValue str = JS_NewString(ctx, argv[i]);
|
||||
JS_ArrayPush(ctx, &boot_args_ref.val, str);
|
||||
}
|
||||
JS_SetPropertyStr(ctx, boot_env_ref.val, "args", boot_args_ref.val);
|
||||
JS_DeleteGCRef(ctx, &boot_args_ref);
|
||||
JSValue boot_env = JS_Stone(ctx, boot_env_ref.val);
|
||||
JS_DeleteGCRef(ctx, &boot_env_ref);
|
||||
|
||||
JSValue boot_result = JS_RunMachBin(ctx, (const uint8_t *)boot_bin, boot_bin_size, boot_env);
|
||||
free(boot_bin);
|
||||
if (JS_IsException(boot_result)) {
|
||||
JS_GetException(ctx);
|
||||
printf("ERROR: Bootstrap failed\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Retry engine from cache (new-style bootstrap seeds it)
|
||||
bin_data = try_engine_cache(&bin_size);
|
||||
if (!bin_data) {
|
||||
// Old-style bootstrap already ran the program — skip engine load
|
||||
goto check_actors;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// Build engine environment
|
||||
JSGCRef env_ref;
|
||||
JS_AddGCRef(ctx, &env_ref);
|
||||
env_ref.val = JS_NewObject(ctx);
|
||||
JSValue tmp;
|
||||
tmp = js_core_os_use(ctx);
|
||||
JS_SetPropertyStr(ctx, env_ref.val, "os", tmp);
|
||||
tmp = JS_NewString(ctx, core_path);
|
||||
JS_SetPropertyStr(ctx, env_ref.val, "core_path", tmp);
|
||||
tmp = shop_path ? JS_NewString(ctx, shop_path) : JS_NULL;
|
||||
JS_SetPropertyStr(ctx, env_ref.val, "shop_path", tmp);
|
||||
JS_SetPropertyStr(ctx, env_ref.val, "actorsym", JS_DupValue(ctx, cli_rt->actor_sym_ref.val));
|
||||
tmp = js_core_json_use(ctx);
|
||||
JS_SetPropertyStr(ctx, env_ref.val, "json", tmp);
|
||||
JS_SetPropertyStr(ctx, env_ref.val, "init", JS_NULL);
|
||||
JSGCRef args_ref;
|
||||
JS_AddGCRef(ctx, &args_ref);
|
||||
args_ref.val = JS_NewArray(ctx);
|
||||
for (int i = arg_start; i < argc; i++) {
|
||||
JSValue str = JS_NewString(ctx, argv[i]);
|
||||
JS_ArrayPush(ctx, &args_ref.val, str);
|
||||
}
|
||||
JS_SetPropertyStr(ctx, env_ref.val, "args", args_ref.val);
|
||||
JS_DeleteGCRef(ctx, &args_ref);
|
||||
JSValue hidden_env = JS_Stone(ctx, env_ref.val);
|
||||
|
||||
JSValue result = JS_RunMachBin(ctx, (const uint8_t *)bin_data, bin_size, hidden_env);
|
||||
JS_DeleteGCRef(ctx, &env_ref);
|
||||
free(bin_data);
|
||||
|
||||
if (JS_IsException(result)) {
|
||||
JS_GetException(ctx);
|
||||
exit_code = 1;
|
||||
} else if (!JS_IsNull(result)) {
|
||||
const char *str = JS_ToCString(ctx, result);
|
||||
if (str) {
|
||||
printf("%s\n", str);
|
||||
JS_FreeCString(ctx, str);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
check_actors:
|
||||
if (scheduler_actor_count() > 0) {
|
||||
scheduler_enable_quiescence();
|
||||
actor_loop();
|
||||
|
||||
Reference in New Issue
Block a user