cached bootstrap
This commit is contained in:
136
source/cell.c
136
source/cell.c
@@ -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)) {
|
||||
|
||||
Reference in New Issue
Block a user