cached bootstrap

This commit is contained in:
2026-02-13 08:11:35 -06:00
parent 77fa058135
commit d26a96bc62
15 changed files with 8319 additions and 2688 deletions

View File

@@ -11,8 +11,7 @@
#include "cell_internal.h"
#include "cJSON.h"
#define BOOTSTRAP_MACH "internal/bootstrap.cm.mach"
#define BOOTSTRAP_MCODE "internal/bootstrap.cm.mcode"
#define BOOTSTRAP_MCODE "boot/bootstrap.cm.mcode"
#define BOOTSTRAP_SRC "internal/bootstrap.cm"
#define CELL_SHOP_DIR ".cell"
#define CELL_CORE_DIR "packages/core"
@@ -21,6 +20,7 @@
#include <signal.h>
#include <unistd.h>
#include <sys/stat.h>
#include "monocypher.h"
/* Test suite declarations */
int run_c_test_suite(JSContext *ctx);
@@ -31,6 +31,83 @@ static char *shop_path = NULL;
static char *core_path = NULL;
static JSRuntime *g_runtime = NULL;
// Compute blake2b hash of data and return hex string (caller must free)
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);
for (int i = 0; i < 32; i++)
snprintf(hex + i * 2, 3, "%02x", hash[i]);
return hex;
}
// Build cache path: shop_path/build/<hex>.mach (caller must free)
static char *build_cache_path(const char *hex) {
if (!shop_path) return NULL;
size_t len = strlen(shop_path) + strlen("/build/") + 64 + strlen(".mach") + 1;
char *path = malloc(len);
snprintf(path, len, "%s/build/%s.mach", shop_path, hex);
return path;
}
// Write binary data to file
static int write_cache_file(const char *path, const uint8_t *data, size_t size) {
FILE *fh = fopen(path, "wb");
if (!fh) return 0;
size_t written = fwrite(data, 1, size, fh);
fclose(fh);
return written == size;
}
// Load cached .mach or compile from .mcode and cache result
// 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);
char *cpath = build_cache_path(hex);
free(hex);
if (cpath) {
// Try loading from cache
FILE *fh = fopen(cpath, "rb");
if (fh) {
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);
free(cpath);
*out_size = file_size;
return data;
}
free(data);
fclose(fh);
}
}
// Cache miss: compile mcode to binary
cJSON *mcode = cJSON_Parse(mcode_data);
if (!mcode) { free(cpath); return NULL; }
MachCode *mc = mach_compile_mcode(mcode);
cJSON_Delete(mcode);
if (!mc) { free(cpath); return NULL; }
size_t bin_size;
uint8_t *bin = JS_SerializeMachCode(mc, &bin_size);
JS_FreeMachCode(mc);
if (!bin) { free(cpath); return NULL; }
// Write to cache
if (cpath) {
write_cache_file(cpath, bin, bin_size);
free(cpath);
}
*out_size = bin_size;
return (char *)bin;
}
// Get the home directory
static const char* get_home_dir(void) {
const char *home = getenv("HOME");
@@ -179,19 +256,23 @@ void script_startup(cell_rt *prt)
cell_rt *crt = JS_GetContextOpaque(js);
JS_FreeValue(js, js_blob_use(js));
// Load pre-compiled bootstrap (.cm.mach or .cm.mcode)
// Load pre-compiled bootstrap .mcode
size_t boot_size;
char *boot_data = load_core_file(BOOTSTRAP_MACH, &boot_size);
int boot_is_mcode = 0;
if (!boot_data) {
boot_data = load_core_file(BOOTSTRAP_MCODE, &boot_size);
boot_is_mcode = 1;
}
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
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;
}
// Create hidden environment
JSValue hidden_env = JS_NewObject(js);
JS_SetPropertyStr(js, hidden_env, "os", js_os_use(js));
@@ -222,12 +303,10 @@ void script_startup(cell_rt *prt)
// Stone the environment
hidden_env = JS_Stone(js, hidden_env);
// Run through MACH VM
// Run from binary
crt->state = ACTOR_RUNNING;
JSValue v = boot_is_mcode
? JS_RunMachMcode(js, boot_data, boot_size, hidden_env)
: JS_RunMachBin(js, (const uint8_t *)boot_data, boot_size, hidden_env);
free(boot_data);
JSValue v = JS_RunMachBin(js, (const uint8_t *)bin_data, bin_size, hidden_env);
free(bin_data);
uncaught_exception(js, v);
crt->state = ACTOR_IDLE;
set_actor_state(crt);
@@ -360,27 +439,31 @@ int cell_init(int argc, char **argv)
actor_initialize();
size_t boot_size;
char *boot_data = load_core_file(BOOTSTRAP_MACH, &boot_size);
int boot_is_mcode = 0;
if (!boot_data) {
boot_data = load_core_file(BOOTSTRAP_MCODE, &boot_size);
boot_is_mcode = 1;
}
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;
}
// 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(boot_data);
free(bin_data);
return 1;
}
JSContext *ctx = JS_NewContextWithHeapSize(g_runtime, 16 * 1024 * 1024);
if (!ctx) {
printf("Failed to create JS context\n");
free(boot_data); JS_FreeRuntime(g_runtime);
free(bin_data); JS_FreeRuntime(g_runtime);
return 1;
}
@@ -419,9 +502,6 @@ int cell_init(int argc, char **argv)
JS_SetPropertyStr(ctx, hidden_env, "core_path", JS_NewString(ctx, core_path));
JS_SetPropertyStr(ctx, hidden_env, "shop_path",
shop_path ? JS_NewString(ctx, shop_path) : JS_NULL);
/* TODO: remove after next 'make regen' — old bootstrap.mach reads these */
JS_SetPropertyStr(ctx, hidden_env, "emit_qbe", JS_FALSE);
JS_SetPropertyStr(ctx, hidden_env, "dump_mach", JS_FALSE);
JS_SetPropertyStr(ctx, hidden_env, "actorsym", JS_DupValue(ctx, cli_rt->actor_sym_ref.val));
JS_SetPropertyStr(ctx, hidden_env, "json", js_json_use(ctx));
JS_SetPropertyStr(ctx, hidden_env, "nota", js_nota_use(ctx));
@@ -435,10 +515,8 @@ int cell_init(int argc, char **argv)
JS_SetPropertyStr(ctx, hidden_env, "args", args_arr);
hidden_env = JS_Stone(ctx, hidden_env);
JSValue result = boot_is_mcode
? JS_RunMachMcode(ctx, boot_data, boot_size, hidden_env)
: JS_RunMachBin(ctx, (const uint8_t *)boot_data, boot_size, hidden_env);
free(boot_data);
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)) {