#ifdef _WIN32 #include #endif #include "wota.h" #define STB_DS_IMPLEMENTATION #include "stb_ds.h" #include "cell.h" #include "cell_internal.h" #include "cJSON.h" #define BOOTSTRAP_MCODE "boot/bootstrap.cm.mcode" #define ENGINE_SRC "internal/engine.cm" #define CELL_SHOP_DIR ".cell" #define CELL_CORE_DIR "packages/core" #include #include #include #include #include "monocypher.h" /* Test suite declarations */ int run_c_test_suite(JSContext *ctx); static int run_test_suite(size_t heap_size); cell_rt *root_cell = NULL; static char *shop_path = NULL; static char *core_path = NULL; static int native_mode = 0; static int warn_mode = 1; 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); if (!hex) return NULL; for (int i = 0; i < 32; i++) snprintf(hex + i * 2, 3, "%02x", hash[i]); return hex; } // Build cache path: shop_path/build/ (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 + 1; char *path = malloc(len); snprintf(path, len, "%s/build/%s", 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); if (!hex) return NULL; 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"); if (!home) { home = getenv("USERPROFILE"); // Windows fallback } return home; } // Resolve shop_path and core_path // core: --core flag > CELL_CORE env > derived from shop // shop: --shop flag > CELL_SHOP env > ~/.cell int find_cell_shop(const char *shop_override, const char *core_override) { // Resolve shop_path if (shop_override) { shop_path = strdup(shop_override); } else { const char *env = getenv("CELL_SHOP"); if (env) { shop_path = strdup(env); } else { const char *home = get_home_dir(); if (!home && !core_override && !getenv("CELL_CORE")) { printf("ERROR: Could not determine home directory. Set HOME environment variable.\n"); return 0; } if (home) { size_t path_len = strlen(home) + strlen("/" CELL_SHOP_DIR) + 1; shop_path = malloc(path_len); if (shop_path) snprintf(shop_path, path_len, "%s/" CELL_SHOP_DIR, home); } } } // Resolve core_path if (core_override) { core_path = strdup(core_override); } else { const char *env = getenv("CELL_CORE"); if (env) { core_path = strdup(env); } else if (shop_path) { size_t core_len = strlen(shop_path) + strlen("/" CELL_CORE_DIR) + 1; core_path = malloc(core_len); if (core_path) snprintf(core_path, core_len, "%s/" CELL_CORE_DIR, shop_path); } } if (!core_path) { printf("ERROR: No core path. Use --core or set CELL_CORE.\n"); return 0; } // Check if the core directory exists struct stat st; if (stat(core_path, &st) != 0 || !S_ISDIR(st.st_mode)) { printf("ERROR: Core not found at %s\n", core_path); return 0; } return 1; } // Load a file from the core directory static char* load_core_file(const char *filename, size_t *out_size) { if (!core_path) return NULL; size_t path_len = strlen(core_path) + 1 + strlen(filename) + 1; char *full_path = malloc(path_len); if (!full_path) return NULL; snprintf(full_path, path_len, "%s/%s", core_path, filename); FILE *fh = fopen(full_path, "rb"); free(full_path); if (!fh) return NULL; fseek(fh, 0, SEEK_END); long file_size = ftell(fh); fseek(fh, 0, SEEK_SET); char *data = malloc(file_size + 1); if (!data) { fclose(fh); return NULL; } if (fread(data, 1, file_size, fh) != (size_t)file_size) { free(data); fclose(fh); return NULL; } fclose(fh); data[file_size] = 0; if (out_size) *out_size = file_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); if (!hex) return NULL; 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; } void actor_disrupt(cell_rt *crt) { crt->disrupt = 1; JS_SetPauseFlag(crt->context, 2); if (crt->state != ACTOR_RUNNING) actor_free(crt); } JSValue js_core_internal_os_use(JSContext *js); JSValue js_core_json_use(JSContext *js); void script_startup(cell_rt *prt) { if (!g_runtime) { g_runtime = JS_NewRuntime(); } JSContext *js = JS_NewContext(g_runtime); JS_SetContextOpaque(js, prt); prt->context = js; /* Set per-actor heap memory limit */ JS_SetHeapMemoryLimit(js, ACTOR_MEMORY_LIMIT); /* Register all GCRef fields so the Cheney GC can relocate them. */ JS_AddGCRef(js, &prt->idx_buffer_ref); JS_AddGCRef(js, &prt->on_exception_ref); JS_AddGCRef(js, &prt->message_handle_ref); JS_AddGCRef(js, &prt->unneeded_ref); JS_AddGCRef(js, &prt->actor_sym_ref); prt->idx_buffer_ref.val = JS_NULL; prt->on_exception_ref.val = JS_NULL; prt->message_handle_ref.val = JS_NULL; prt->unneeded_ref.val = JS_NULL; prt->actor_sym_ref.val = JS_NULL; cell_rt *crt = JS_GetContextOpaque(js); JS_FreeValue(js, js_core_blob_use(js)); // 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; } 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_internal_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; } } // Build engine environment JSGCRef env_ref; JS_AddGCRef(js, &env_ref); env_ref.val = JS_NewObject(js); JSValue tmp; tmp = js_core_internal_os_use(js); JS_SetPropertyStr(js, env_ref.val, "os", tmp); tmp = js_core_json_use(js); JS_SetPropertyStr(js, env_ref.val, "json", tmp); crt->actor_sym_ref.val = JS_NewObject(js); JS_CellStone(js, crt->actor_sym_ref.val); JS_SetActorSym(js, JS_DupValue(js, crt->actor_sym_ref.val)); JS_SetPropertyStr(js, env_ref.val, "actorsym", JS_DupValue(js, crt->actor_sym_ref.val)); // Always set init (even if null) if (crt->init_wota) { JSGCRef init_ref; JS_PushGCRef(js, &init_ref); init_ref.val = wota2value(js, crt->init_wota); JS_SetPropertyStr(js, env_ref.val, "init", init_ref.val); JS_PopGCRef(js, &init_ref); free(crt->init_wota); crt->init_wota = NULL; } else { JS_SetPropertyStr(js, env_ref.val, "init", JS_NULL); } // Set args to null for actor spawn (not CLI mode) JS_SetPropertyStr(js, env_ref.val, "args", JS_NULL); if (core_path) { tmp = JS_NewString(js, core_path); JS_SetPropertyStr(js, env_ref.val, "core_path", tmp); } tmp = shop_path ? JS_NewString(js, shop_path) : JS_NULL; JS_SetPropertyStr(js, env_ref.val, "shop_path", tmp); // Stone the environment JSValue hidden_env = JS_Stone(js, env_ref.val); JS_DeleteGCRef(js, &env_ref); // 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); uncaught_exception(js, v); crt->state = ACTOR_IDLE; set_actor_state(crt); } static void signal_handler(int sig) { const char *str = NULL; #ifndef TARGET_PLAYDATE switch (sig) { case SIGABRT: str = "SIGABRT"; break; case SIGFPE: str = "SIGFPE"; break; case SIGILL: str = "SIGILL"; break; case SIGINT: str = "SIGINT"; break; case SIGSEGV: str = "SIGSEGV"; break; case SIGTERM: str = "SIGTERM"; break; } #endif if (!str) return; exit_handler(); } /* Run the C test suite with minimal runtime setup */ static int run_test_suite(size_t heap_size) { JSRuntime *rt = JS_NewRuntime(); if (!rt) { printf("Failed to create JS runtime\n"); return 1; } JSContext *ctx = JS_NewContextWithHeapSize(rt, heap_size); if (!ctx) { printf("Failed to create JS context\n"); JS_FreeRuntime(rt); return 1; } int result = run_c_test_suite(ctx); JS_FreeContext(ctx); JS_FreeRuntime(rt); return result; } static void print_usage(const char *prog) { printf("Usage: %s [options] [args...]\n\n", prog); printf("Run a cell program (.ce actor).\n\n"); printf("Options:\n"); printf(" --core Set core path directly (overrides CELL_CORE)\n"); printf(" --shop Set shop path (overrides CELL_SHOP)\n"); printf(" --dev Dev mode (shop=.cell, core=.)\n"); printf(" --native Use AOT native code instead of bytecode\n"); printf(" --heap Initial heap size (e.g. 256MB, 1GB)\n"); printf(" --test [heap_size] Run C test suite\n"); printf(" -h, --help Show this help message\n"); printf("\nEnvironment:\n"); printf(" CELL_CORE Core path (default: /packages/core)\n"); printf(" CELL_SHOP Shop path (default: ~/.cell)\n"); printf("\nRecompile after changes: make\n"); printf("Bootstrap from scratch: make bootstrap\n"); printf("Run the 'help' script like 'cell help' to see available scripts\n"); } int cell_init(int argc, char **argv) { /* Check for --help flag */ if (argc >= 2 && (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0)) { print_usage(argv[0]); return 0; } /* Check for --test flag to run C test suite */ if (argc >= 2 && strcmp(argv[1], "--test") == 0) { size_t heap_size = 64 * 1024; /* 64KB default */ if (argc >= 3) { heap_size = strtoull(argv[2], NULL, 0); /* Round up to power of 2 for buddy allocator */ size_t p = 1; while (p < heap_size) p <<= 1; heap_size = p; } return run_test_suite(heap_size); } /* Default: run script through engine pipeline */ int arg_start = 1; size_t heap_size = 1024 * 1024; /* 1MB default */ const char *shop_override = NULL; const char *core_override = NULL; // Parse flags (order-independent) while (arg_start < argc && argv[arg_start][0] == '-') { if (strcmp(argv[arg_start], "--shop") == 0) { if (arg_start + 1 >= argc) { printf("ERROR: --shop requires a path argument\n"); return 1; } shop_override = argv[arg_start + 1]; arg_start += 2; } else if (strcmp(argv[arg_start], "--core") == 0) { if (arg_start + 1 >= argc) { printf("ERROR: --core requires a path argument\n"); return 1; } core_override = argv[arg_start + 1]; arg_start += 2; } 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"); return 1; } char *end = NULL; heap_size = strtoull(argv[arg_start + 1], &end, 0); if (end && (*end == 'G' || *end == 'g')) heap_size *= 1024ULL * 1024 * 1024; else if (end && (*end == 'M' || *end == 'm')) heap_size *= 1024ULL * 1024; else if (end && (*end == 'K' || *end == 'k')) heap_size *= 1024ULL; arg_start += 2; } else if (strcmp(argv[arg_start], "--dev") == 0) { shop_override = ".cell"; core_override = "."; mkdir(".cell", 0755); mkdir(".cell/build", 0755); mkdir(".cell/cache", 0755); mkdir(".cell/packages", 0755); /* Ensure .cell/packages/core -> . symlink exists */ struct stat lst; if (lstat(".cell/packages/core", &lst) != 0) symlink("../..", ".cell/packages/core"); arg_start++; } else if (strcmp(argv[arg_start], "--native") == 0) { native_mode = 1; arg_start++; } else if (strcmp(argv[arg_start], "--no-warn") == 0) { warn_mode = 0; arg_start++; } else { break; } } if (arg_start >= argc) { print_usage(argv[0]); return 1; } if (!find_cell_shop(shop_override, core_override)) return 1; actor_initialize(); g_runtime = JS_NewRuntime(); if (!g_runtime) { printf("Failed to create JS runtime\n"); return 1; } JSContext *ctx = JS_NewContextWithHeapSize(g_runtime, heap_size); if (!ctx) { printf("Failed to create JS context\n"); JS_FreeRuntime(g_runtime); return 1; } /* Create a cell_rt for the CLI context so JS-C bridge functions work */ cell_rt *cli_rt = calloc(sizeof(*cli_rt), 1); cli_rt->mutex = malloc(sizeof(pthread_mutex_t)); pthread_mutexattr_t mattr; pthread_mutexattr_init(&mattr); pthread_mutexattr_settype(&mattr, PTHREAD_MUTEX_RECURSIVE); pthread_mutex_init(cli_rt->mutex, &mattr); cli_rt->msg_mutex = malloc(sizeof(pthread_mutex_t)); pthread_mutex_init(cli_rt->msg_mutex, &mattr); pthread_mutexattr_destroy(&mattr); cli_rt->context = ctx; JS_SetContextOpaque(ctx, cli_rt); JS_AddGCRef(ctx, &cli_rt->idx_buffer_ref); JS_AddGCRef(ctx, &cli_rt->on_exception_ref); JS_AddGCRef(ctx, &cli_rt->message_handle_ref); JS_AddGCRef(ctx, &cli_rt->unneeded_ref); JS_AddGCRef(ctx, &cli_rt->actor_sym_ref); cli_rt->idx_buffer_ref.val = JS_NULL; cli_rt->on_exception_ref.val = JS_NULL; cli_rt->message_handle_ref.val = JS_NULL; cli_rt->unneeded_ref.val = JS_NULL; cli_rt->actor_sym_ref.val = JS_NewObject(ctx); JS_CellStone(ctx, cli_rt->actor_sym_ref.val); JS_SetActorSym(ctx, JS_DupValue(ctx, cli_rt->actor_sym_ref.val)); root_cell = cli_rt; JS_FreeValue(ctx, js_core_blob_use(ctx)); int exit_code = 0; // 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_internal_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_internal_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); if (native_mode || !warn_mode) { JSGCRef init_ref; JS_AddGCRef(ctx, &init_ref); init_ref.val = JS_NewObject(ctx); if (native_mode) JS_SetPropertyStr(ctx, init_ref.val, "native_mode", JS_NewBool(ctx, 1)); if (!warn_mode) JS_SetPropertyStr(ctx, init_ref.val, "no_warn", JS_NewBool(ctx, 1)); JS_SetPropertyStr(ctx, env_ref.val, "init", init_ref.val); JS_DeleteGCRef(ctx, &init_ref); } else { 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(); exit_handler(); exit(0); } /* No actors spawned — clean up CLI context */ JS_DeleteGCRef(ctx, &cli_rt->idx_buffer_ref); JS_DeleteGCRef(ctx, &cli_rt->on_exception_ref); JS_DeleteGCRef(ctx, &cli_rt->message_handle_ref); JS_DeleteGCRef(ctx, &cli_rt->unneeded_ref); JS_DeleteGCRef(ctx, &cli_rt->actor_sym_ref); pthread_mutex_destroy(cli_rt->mutex); free(cli_rt->mutex); pthread_mutex_destroy(cli_rt->msg_mutex); free(cli_rt->msg_mutex); free(cli_rt); root_cell = NULL; JS_FreeContext(ctx); JS_FreeRuntime(g_runtime); g_runtime = NULL; exit_handler(); return exit_code; } int JS_ArrayLength(JSContext *js, JSValue a) { int64_t len; JS_GetLength(js, a, &len); return len; } int js2bool(JSContext *js, JSValue v) { return JS_ToBool(js,v); } JSValue bool2js(JSContext *js, int b) { return JS_NewBool(js,b); } JSValue number2js(JSContext *js, double g) { return JS_NewFloat64(js,g); } double js2number(JSContext *js, JSValue v) { double g; JS_ToFloat64(js, &g, v); if (isnan(g)) g = 0; return g; } uint64_t cell_random_fit() { uint64_t buf; randombytes((uint8_t *)&buf, sizeof(buf)); return buf >> 11; } double cell_random() { uint64_t buf = cell_random_fit(); return (double)buf / 9007199254740992.0; } void cell_trace_sethook(cell_hook hook) { (void)hook; } int uncaught_exception(JSContext *js, JSValue v) { int has_exc = JS_HasException(js); int is_exc = JS_IsException(v); if (!has_exc && !is_exc) return 1; /* Error message and backtrace were already printed to stderr by JS_ThrowError2 / print_backtrace. Just clear the flag. */ if (has_exc) JS_GetException(js); cell_rt *crt = JS_GetContextOpaque(js); if (crt && !JS_IsNull(crt->on_exception_ref.val)) { /* Disable interruption so actor_die can send messages without being re-interrupted. */ JS_SetPauseFlag(js, 0); JSValue err = JS_NewString(js, "interrupted"); JS_Call(js, crt->on_exception_ref.val, JS_NULL, 1, &err); /* Clear any secondary exception from the callback. */ if (JS_HasException(js)) JS_GetException(js); } return 0; }