diff --git a/Makefile b/Makefile index 8bfc0646..af658e1d 100755 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ debug: FORCE - meson setup build_dbg -Dbuildtype=debugoptimized + meson setup build_dbg -Dbuildtype=debug meson compile -C build_dbg fast: FORCE diff --git a/meson.build b/meson.build index ac1d0315..c971c615 100644 --- a/meson.build +++ b/meson.build @@ -137,7 +137,7 @@ deps += dependency('soloud', static:true) deps += dependency('libqrencode', static: true) sources = [] -src += ['anim.c', 'config.c', 'datastream.c','font.c','HandmadeMath.c','jsffi.c','model.c','render.c','script.c','simplex.c','spline.c', 'transform.c','prosperon.c', 'wildmatch.c', 'sprite.c', 'rtree.c', 'qjs_dmon.c', 'qjs_nota.c', 'qjs_enet.c', 'qjs_soloud.c', 'qjs_qr.c', 'qjs_wota.c', 'monocypher.c'] +src += ['anim.c', 'config.c', 'datastream.c','font.c','HandmadeMath.c','jsffi.c','model.c','render.c','simplex.c','spline.c', 'transform.c','prosperon.c', 'wildmatch.c', 'sprite.c', 'rtree.c', 'qjs_dmon.c', 'qjs_nota.c', 'qjs_enet.c', 'qjs_soloud.c', 'qjs_qr.c', 'qjs_wota.c', 'monocypher.c'] # quirc src src += ['thirdparty/quirc/quirc.c', 'thirdparty/quirc/decode.c','thirdparty/quirc/identify.c', 'thirdparty/quirc/version_db.c'] diff --git a/scripts/core/engine.js b/scripts/core/engine.js index 23611cb2..8edaa5d0 100644 --- a/scripts/core/engine.js +++ b/scripts/core/engine.js @@ -87,7 +87,7 @@ prosperon.PATH = [ "scripts/modules/ext/", ] -console.print("HERE") + // path is the path of a module or script to resolve var script_fn = function script_fn(path) { @@ -132,6 +132,8 @@ function bare_load(file) { return undefined } + + var res_cache = {} function console_rec(category, priority, line, file, msg) { @@ -203,7 +205,7 @@ console.assert = function(op, str = `assertion failed [value '${op}']`) { if (!op) console.panic(str) } -//os.on('uncaught_exception', function(e) { console.log("HERRE!"); console.error(e); }) +os.on('uncaught_exception', function(e) { console.error(e); }) console[prosperon.DOC] = { doc: "The console object provides various logging, debugging, and output methods.", @@ -286,6 +288,8 @@ globalThis.use = function use(file) { return use_cache[file] } + + globalThis.json = use('json') var time = use('time') @@ -413,11 +417,10 @@ function cant_kill() { throw Error("Can't kill an object in its spawning code. Move the kill command to awake.") } -// OK if return here - actor.toString = function() { return this[FILE] } -actor.spawn = function spawn(script, config, callback) { +actor.spawn = function spawn(script, config) { + if (this[DEAD]) throw new Error("Attempting to spawn on a dead actor") var prog if (!script) { @@ -470,13 +473,11 @@ actor.spawn = function spawn(script, config, callback) { configurable:false }) - if (callback) callback(underling, { message:"created" }) - try { prog.prog_fn.call(underling) - } catch(e) { throw e } + } catch(e) { throw e; } - if (underling[DEAD]) return undefined + if (underling[DEAD]) return undefined; if (typeof config === 'object') Object.assign(underling, config) @@ -763,8 +764,8 @@ $_.unneeded = function(fn, seconds) { $_.unneeded[prosperon.DOC] = "registers a function that is called when the actor..." $_.delay = function(fn, seconds) { - var id = os.addtimer(prosperon.id, fn, seconds); - return function() { os.removetimer(prosperon.id, id); } + var id = os.delay(fn, seconds); + return function() { os.removetimer(id); } } $_.delay[prosperon.DOC] = "used to schedule the invocation of a function..." @@ -776,6 +777,8 @@ $_.couple = function(actor) { } $_.couple[prosperon.DOC] = "causes this actor to stop when another actor stops." + + function actor_send(actor, message) { if (!$_.is_actor(actor)) throw new Error(`Must send to an actor object. Attempted send to ${json.encode(actor)}`) if (typeof message !== 'object') throw new Error('Must send an object record.') @@ -846,8 +849,6 @@ else prosperon.id = prosperon.args.id os.register_actor(prosperon.id, handle_local); -tracy.thread_name(prosperon.id) - $_.__ACTORDATA__.id = prosperon.id if (prosperon.args.overling) overling = { __ACTORDATA__: {id: prosperon.args.overling} } @@ -875,6 +876,7 @@ function handle_actor_disconnect(id) { } function handle_local(msg) { + console.print("LOCAL!!!"); console.log("LOCAL MESSAGE"); handle_message(wota.decode(msg)) } @@ -929,6 +931,8 @@ function handle_message(msg) { var greeter = greeters[msg.id] if (greeter) greeter({type: "actor_started", actor: create_actor(msg)}) } -} +}; + +console.log('finished running main') })() diff --git a/scripts/modules/os.js b/scripts/modules/os.js index 4473ba5f..56b23ba9 100644 --- a/scripts/modules/os.js +++ b/scripts/modules/os.js @@ -15,9 +15,6 @@ os.exit[prosperon.DOC] = "Exit the application with the specified exit code." os.now[prosperon.DOC] = "Return current time (in seconds as a float) with high resolution." os.openurl[prosperon.DOC] = "Open the provided URL in the default web browser, if possible." -os.make_timer[prosperon.DOC] = "Create a new timer object that will call a specified function after a certain delay." -os.update_timers[prosperon.DOC] = "Advance all timers by the provided time delta (in seconds)." - os.sleep[prosperon.DOC] = "Block execution for the specified number of seconds." os.battery_pct[prosperon.DOC] = "Return the battery level (percentage) or negative if unknown." os.battery_voltage[prosperon.DOC] = "Return the current battery voltage in volts, if available." diff --git a/source/jsffi.c b/source/jsffi.c index 38d44442..f03d4a88 100644 --- a/source/jsffi.c +++ b/source/jsffi.c @@ -1,5 +1,4 @@ #include "jsffi.h" -#include "script.h" #include "font.h" #include "datastream.h" #include "stb_ds.h" @@ -6487,49 +6486,6 @@ JSC_SSCALL(os_eval, ret = JS_Eval(js, str2, strlen(str2), str, JS_EVAL_FLAG_STRICT); ) -Uint32 timer_cb(prosperon_rt *actor, SDL_TimerID id, Uint32 interval) -{ - int idx = hmgeti(actor->timers, id); - if (idx == -1) return 0; - - SDL_LockMutex(actor->mutex); - JSValue cb = actor->timers[idx].value; - hmdel(actor->timers, id); - arrput(actor->events, cb); - SDL_UnlockMutex(actor->mutex); - - actor_signal(actor); -} - -JSC_CCALL(os_addtimer, - char *guid = JS_ToCString(js,argv[0]); - prosperon_rt *actor = get_actor(guid); - JS_FreeCString(js, guid); - if (!actor) return JS_ThrowInternalError(js, "Could not get actor from guid."); - - Uint64 ns = js2number(js,argv[2]) * 1000000000.0f; - Uint32 id = SDL_AddTimerNS(ns, timer_cb, actor); - - // appropriately add it to the actor - SDL_LockMutex(actor->mutex); - hmput(actor->timers, id, JS_DupValue(js,argv[1])); - SDL_UnlockMutex(actor->mutex); -) - -JSC_CCALL(os_removetimer, - char *guid = JS_ToCString(js,argv[0]); - prosperon_rt *actor = get_actor(guid); - JS_FreeCString(js, guid); - if (!actor) return JS_ThrowInternalError(js, "Could not get actor from guid."); - - Uint32 timer_id = js2number(js,argv[1]); - SDL_RemoveTimer(timer_id); - - SDL_LockMutex(actor->mutex); - hmdel(actor->timers, timer_id); - SDL_UnlockMutex(actor->mutex); -) - // input: (encoded image data of jpg, png, bmp, tiff) JSC_CCALL(os_make_texture, size_t len; @@ -7145,6 +7101,7 @@ JSC_CCALL(os_register_actor, rt->message_handle = JS_DupValue(js, argv[1]); rt->context = js; JS_FreeCString(js, id); + printf("registered actor at %p with id %s, with function %p\n", rt, id, JS_VALUE_GET_PTR(rt->message_handle)); ) JSC_CCALL(os_mailbox_exist, @@ -7215,8 +7172,8 @@ static const JSCFunctionListEntry js_os_funcs[] = { MIST_FUNC_DEF(os, mailbox_push, 2), MIST_FUNC_DEF(os, mailbox_exist, 1), - MIST_FUNC_DEF(os, addtimer, 3), - MIST_FUNC_DEF(os, removetimer, 2), + MIST_FUNC_DEF(actor, delay, 2), + MIST_FUNC_DEF(actor, removetimer, 1), MIST_FUNC_DEF(os, register_actor, 2), MIST_FUNC_DEF(os, unneeded, 2), MIST_FUNC_DEF(os, destroy, 0), diff --git a/source/prosperon.c b/source/prosperon.c index c18885ca..056ef75a 100644 --- a/source/prosperon.c +++ b/source/prosperon.c @@ -1,185 +1,55 @@ -#include "script.h" -#include "physfs.h" #include #include #include #include #include +#include +#include +#include +#include +#include +#include +#include "physfs.h" #include "stb_ds.h" - -#include "prosperon.h" #include "jsffi.h" +#include "prosperon.h" + +#ifdef TRACY_ENABLE +#include +#if defined(__APPLE__) +#include +#define MALLOC_OVERHEAD 0 +#elif defined(_WIN32) +#include +#define MALLOC_OVERHEAD 8 +#elif defined(__linux__) || defined(__GLIBC__) +#define _GNU_SOURCE +#include +#define MALLOC_OVERHEAD 8 +#endif +#define likely(x) __builtin_expect(!!(x), 1) +#define unlikely(x) __builtin_expect(!!(x), 0) +#endif + +#define ENGINE "scripts/core/engine.js" static prosperon_rt **ready_queue = NULL; -static prosperon_rt **slow_queue = NULL; // Slow actors -static prosperon_rt **reclaim_queue = NULL; // Actors needing reclamation -static SDL_Mutex *queue_mutex = NULL; // Protects queue access -static SDL_Condition *queue_cond = NULL; // Signals when work is available +static prosperon_rt **slow_queue = NULL; +static prosperon_rt **reclaim_queue = NULL; +static SDL_Mutex *queue_mutex = NULL; +static SDL_Condition *queue_cond = NULL; +static struct { char *key; prosperon_rt *value; } *actors = NULL; +static unsigned char *zip_buffer_global = NULL; +static char *prosperon = NULL; -static struct { char *key; prosperon_rt *value } *actors; +static void set_actor_state(prosperon_rt *actor); -static unsigned char *zip_buffer_global; -static char *prosperon; - -SDL_ThreadID main_thread = 0; - -void free_zip(void) -{ - free(zip_buffer_global); - zip_buffer_global = NULL; -} - -int prosperon_mount_core() -{ -size_t size; - FILE *f = fopen(prosperon, "rb"); -if (!f) { perror("fopen"); return 0; } -if (fseek(f, 0, SEEK_END) != 0) { perror("fseek"); fclose(f); return 0; } -size = ftell(f); -if (size < 0) { perror("ftell"); fclose(f); return 0; } -zip_buffer_global = malloc(size); -if (!zip_buffer_global) { perror("malloc"); fclose(f); return 0; } -rewind(f); -if (fread(zip_buffer_global, 1, size, f) != (size_t)size) { - perror("fread"); - free(zip_buffer_global); - fclose(f); - return 0; -} -fclose(f); - // Search backwards for the EOCD signature "PK\x05\x06". - // The EOCD record is at most 0xFFFF (65535) bytes plus 22 bytes long. - long max_comment_len = 0xFFFF; - long eocd_search_start = (size > (max_comment_len + 22)) ? (size - (max_comment_len + 22)) : 0; - long eocd_pos = -1; - for (long i = size - 22; i >= eocd_search_start; i--) { - if (zip_buffer_global[i] == 'P' && - zip_buffer_global[i + 1] == 'K' && - zip_buffer_global[i + 2] == 0x05 && - zip_buffer_global[i + 3] == 0x06) { - eocd_pos = i; - break; - } - } - if (eocd_pos < 0) { - fprintf(stderr, "EOCD not found\n"); - free(zip_buffer_global); - return 0; - } - - // Parse the EOCD record. - // EOCD record layout (without the comment): - // Offset 0: 4 bytes signature ("PK\x05\x06") - // Offset 4: 2 bytes disk number - // Offset 6: 2 bytes disk with central directory - // Offset 8: 2 bytes number of central dir records on this disk - // Offset 10:2 bytes total number of central dir records - // Offset 12:4 bytes size of central directory (cd_size) - // Offset 16:4 bytes offset of start of central directory (cd_offset_rel, relative to zip start) - // Offset 20:2 bytes comment length - uint16_t comment_length = zip_buffer_global[eocd_pos + 20] | - (zip_buffer_global[eocd_pos + 21] << 8); - int eocd_size = 22 + comment_length; - uint32_t cd_size = zip_buffer_global[eocd_pos + 12] | - (zip_buffer_global[eocd_pos + 13] << 8) | - (zip_buffer_global[eocd_pos + 14] << 16) | - (zip_buffer_global[eocd_pos + 15] << 24); - uint32_t cd_offset_rel = zip_buffer_global[eocd_pos + 16] | - (zip_buffer_global[eocd_pos + 17] << 8) | - (zip_buffer_global[eocd_pos + 18] << 16) | - (zip_buffer_global[eocd_pos + 19] << 24); - - uint32_t appended_zip_size = cd_offset_rel + cd_size + eocd_size; - long zip_offset = size - appended_zip_size; - if (zip_offset < 0 || zip_offset >= size) { - fprintf(stderr, "Invalid zip offset computed: %ld\n", zip_offset); - free(zip_buffer_global); - return 0; - } - - int ret = PHYSFS_mountMemory(zip_buffer_global + zip_offset, appended_zip_size, free_zip, "core.zip", NULL, 0); - -if (!ret) { - printf("COULD NOT MOUNT! Reason: %s\n", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode())); - return 0; -} - - return 1; -} - -Uint32 actor_remove_cb(prosperon_rt *actor, Uint32 id, Uint32 interval) +static Uint32 actor_remove_cb(prosperon_rt *actor, Uint32 id, Uint32 interval) { + printf("freeing actor after %ud\n", interval); actor_free(actor); -} - -void actor_free(prosperon_rt *actor) -{ - // first, remove it from the queue - shdel(actors, actor->id); - JSContext *js = actor->context; - SDL_LockMutex(actor->mutex); - JS_FreeValue(js, actor->cycle_fn); - JS_FreeValue(js, actor->idx_buffer); - JS_FreeValue(js, actor->message_handle); - JS_FreeValue(js, actor->on_exception); - - SDL_RemoveTimer(actor->ar); - - for (int i = 0; i < arrlen(actor->js_swapchains); i++) - JS_FreeValue(js, actor->js_swapchains[i]); - - for (int i = 0; i < arrlen(actor->events); i++) - JS_FreeValue(js, actor->events[i]); - - for (int i = 0; i < hmlen(actor->timers); i++) - JS_FreeValue(js, actor->timers[i].value); - -// free(actor->timers); - arrfree(actor->js_swapchains); - arrfree(actor->events); - arrfree(actor->messages); - arrfree(actor->module_registry); - - SDL_DestroyMutex(actor->mutex); - - JSRuntime *rt = JS_GetRuntime(js); - JS_FreeContext(js); - JS_FreeRuntime(rt); - free(actor->id); - free(actor); -} - -void set_actor_state(prosperon_rt *actor) -{ - SDL_LockMutex(actor->mutex); - if (arrlen(actor->messages) == 0) { - actor->state = ACTOR_IDLE; - actor->ar = SDL_AddTimerNS(1e9, actor_remove_cb, actor); - } else { - actor->state = ACTOR_READY; - SDL_LockMutex(queue_mutex); - arrput(ready_queue, actor); - SDL_SignalCondition(queue_cond); - SDL_UnlockMutex(queue_mutex); - } - SDL_UnlockMutex(actor->mutex); -} - -// this function should be called to spin off a new thread with actor -prosperon_rt *create_actor(int argc, char **argv) -{ - prosperon_rt *rt = calloc(sizeof(*rt),1); - rt->cmd.argc = argc; - rt->cmd.argv = argv; - rt->cycle_fn = JS_UNDEFINED; - rt->idx_buffer = JS_UNDEFINED; - - script_startup(rt); - - set_actor_state(rt); - - return rt; + return 0; } void js_dofree(JSRuntime *rt, void *opaque, void *ptr) @@ -187,194 +57,157 @@ void js_dofree(JSRuntime *rt, void *opaque, void *ptr) js_free_rt(rt, ptr); } -void run_actor_turn(prosperon_rt *actor) +SDL_ThreadID main_thread = 0; +SDL_TLSID prosperon_id; + +#ifdef TRACY_ENABLE +static size_t js_tracy_malloc_usable_size(const void *ptr) { - SDL_LockMutex(actor->mutex); - actor->state = ACTOR_RUNNING; - - // Process all messages until the message queue is empty - while (arrlen(actor->messages) > 0) { - struct message msg = actor->messages[0]; - arrdel(actor->messages, 0); - JSValue arg = JS_NewArrayBuffer(actor->context, msg.data, msg.size, js_dofree, NULL, 0); - JSValue result = JS_Call(actor->context, actor->message_handle, JS_UNDEFINED, 1, &arg); - uncaught_exception(actor->context, result); - JS_FreeValue(actor->context, arg); // Free the argument after use - } - - // After all messages are processed, process one event if any exist - while (arrlen(actor->messages) > 0) { - JSValue event = actor->events[0]; - arrdel(actor->events, 0); - JSValue result = JS_Call(actor->context, event, JS_UNDEFINED, 0, NULL); - uncaught_exception(actor->context, result); - JS_FreeValue(actor->context, event); - } - - // Update state and re-queue if necessary - set_actor_state(actor); - SDL_UnlockMutex(actor->mutex); -} - -int reclaimer_thread(void *data) -{ - while (true) { - SDL_LockMutex(queue_mutex); - while (arrlen(reclaim_queue) == 0) - SDL_WaitCondition(queue_cond, queue_mutex); - - prosperon_rt *actor = reclaim_queue[0]; - arrdel(reclaim_queue, 0); - SDL_UnlockMutex(queue_mutex); - - SDL_LockMutex(actor->mutex); - if (actor->state == ACTOR_EXHAUSTED) { - actor->state = ACTOR_RECLAIMING; - JS_RunGC(JS_GetRuntime(actor->context)); - } - SDL_UnlockMutex(actor->mutex); - - actor_signal(actor); - } -} - -int crank_actor() -{ - while (true) { - prosperon_rt *actor = NULL; - SDL_LockMutex(queue_mutex); - if (arrlen(ready_queue) > 0) { - actor = ready_queue[0]; - arrdel(ready_queue, 0); - } else if (arrlen(slow_queue) > 0) { - actor = slow_queue[0]; - arrdel(slow_queue, 0); - } else { - SDL_WaitCondition(queue_cond, queue_mutex); - continue; - } - - SDL_UnlockMutex(queue_mutex); - if (actor) - run_actor_turn(actor); - } - + #if defined(__APPLE__) + return malloc_size(ptr); + #elif defined(_WIN32) + return _msize((void *)ptr); + #elif defined(EMSCRIPTEN) return 0; + #elif defined(__linux__) || defined(__GLIBC__) + return malloc_usable_size((void *)ptr); + #else + return malloc_usable_size((void *)ptr); + #endif } -static void signal_handler(int sig) { - const char *str = NULL; - 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; - } - if (!str) return; - - for (int i = 0; i < shlen(actors); i++) { - prosperon_rt *main = actors[i].value; - JSContext *js = main->context; - script_evalf(js, "prosperon.dispatch('%s')", str); - } - - switch(sig) { - case SIGTERM: - exit(1); - case SIGINT: - exit(1); - } -} - -static void exit_handler() +static void *js_tracy_malloc(JSMallocState *s, size_t size) { - for (int i = 0; i < shlen(actors); i++) { - prosperon_rt *main = actors[i].value; - JSContext *js = main->context; - script_evalf(js, "prosperon.dispatch('exit')", NULL); - } + void *ptr; + assert(size != 0); + if (unlikely(s->malloc_size + size > s->malloc_limit)) return NULL; + ptr = malloc(size); + if (!ptr) return NULL; + s->malloc_count++; + s->malloc_size += js_tracy_malloc_usable_size(ptr) + MALLOC_OVERHEAD; + TracyCAllocN(ptr, js_tracy_malloc_usable_size(ptr) + MALLOC_OVERHEAD, "quickjs"); + return ptr; } -int main(int argc, char **argv) { - SDL_Init(SDL_INIT_EVENTS | SDL_INIT_VIDEO); - int cores = SDL_GetNumLogicalCPUCores(); - if (cores == 1) { - printf("Platform has only one core!\n"); - return 1; +static void js_tracy_free(JSMallocState *s, void *ptr) +{ + if (!ptr) return; + s->malloc_count--; + s->malloc_size -= js_tracy_malloc_usable_size(ptr) + MALLOC_OVERHEAD; + TracyCFreeN(ptr, "quickjs"); + free(ptr); +} + +static void *js_tracy_realloc(JSMallocState *s, void *ptr, size_t size) +{ + size_t old_size; + if (!ptr) return size ? js_tracy_malloc(s, size) : NULL; + old_size = js_tracy_malloc_usable_size(ptr); + if (!size) { + s->malloc_count--; + s->malloc_size -= old_size + MALLOC_OVERHEAD; + TracyCFreeN(ptr, "quickjs"); + free(ptr); + return NULL; } - - main_thread = SDL_GetCurrentThreadID(); + if (s->malloc_size + size - old_size > s->malloc_limit) return NULL; + TracyCFreeN(ptr, "quickjs"); + ptr = realloc(ptr, size); + if (!ptr) return NULL; + s->malloc_size += js_tracy_malloc_usable_size(ptr) - old_size; + TracyCAllocN(ptr, js_tracy_malloc_usable_size(ptr) + MALLOC_OVERHEAD, "quickjs"); + return ptr; +} - if (!main_thread) { - printf("Platform does not support threads!\n"); - return 1; +static const JSMallocFunctions tracy_malloc_funcs = { + js_tracy_malloc, + js_tracy_free, + js_tracy_realloc, + js_tracy_malloc_usable_size +}; +#endif + +static void free_zip(void) +{ + free(zip_buffer_global); + zip_buffer_global = NULL; +} + +int prosperon_mount_core(void) +{ + size_t size; + FILE *f = fopen(prosperon, "rb"); + if (!f) return perror("fopen"), 0; + if (fseek(f, 0, SEEK_END) != 0) return perror("fseek"), fclose(f), 0; + size = ftell(f); + if (size < 0) return perror("ftell"), fclose(f), 0; + zip_buffer_global = malloc(size); + if (!zip_buffer_global) return perror("malloc"), fclose(f), 0; + rewind(f); + if (fread(zip_buffer_global, 1, size, f) != size) { + perror("fread"); + free(zip_buffer_global); + fclose(f); + return 0; } + fclose(f); - prosperon = argv[0]; + long max_comment_len = 0xFFFF; + long eocd_search_start = (size > max_comment_len + 22) ? size - (max_comment_len + 22) : 0; + long eocd_pos = -1; + for (long i = size - 22; i >= eocd_search_start; i--) + if (zip_buffer_global[i] == 'P' && zip_buffer_global[i + 1] == 'K' && + zip_buffer_global[i + 2] == 0x05 && zip_buffer_global[i + 3] == 0x06) { + eocd_pos = i; + break; + } + if (eocd_pos < 0) return fprintf(stderr, "EOCD not found\n"), free(zip_buffer_global), 0; - PHYSFS_init(argv[0]); - const char *base = PHYSFS_getBaseDir(); - PHYSFS_setWriteDir(base); + uint16_t comment_length = zip_buffer_global[eocd_pos + 20] | (zip_buffer_global[eocd_pos + 21] << 8); + int eocd_size = 22 + comment_length; + uint32_t cd_size = zip_buffer_global[eocd_pos + 12] | (zip_buffer_global[eocd_pos + 13] << 8) | + (zip_buffer_global[eocd_pos + 14] << 16) | (zip_buffer_global[eocd_pos + 15] << 24); + uint32_t cd_offset_rel = zip_buffer_global[eocd_pos + 16] | (zip_buffer_global[eocd_pos + 17] << 8) | + (zip_buffer_global[eocd_pos + 18] << 16) | (zip_buffer_global[eocd_pos + 19] << 24); + uint32_t appended_zip_size = cd_offset_rel + cd_size + eocd_size; + long zip_offset = size - appended_zip_size; + if (zip_offset < 0 || zip_offset >= size) return fprintf(stderr, "Invalid zip offset: %ld\n", zip_offset), free(zip_buffer_global), 0; - PHYSFS_mount(base, "/", 0); - int mounted = prosperon_mount_core(); - if (!mounted) - mounted = PHYSFS_mount("core.zip", NULL, 0); - if (!mounted) { - printf("Could not mount core. Reason: %s\n", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode())); - return 1; - } + int ret = PHYSFS_mountMemory(zip_buffer_global + zip_offset, appended_zip_size, free_zip, "core.zip", NULL, 0); + if (!ret) printf("COULD NOT MOUNT! Reason: %s\n", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode())); + return ret; +} - char **margv = malloc(sizeof(char*)); - for (int i = 0; i < argc; i++) - margv[i] = strdup(argv[i]); - - create_actor(argc, margv); - - queue_mutex = SDL_CreateMutex(); - queue_cond = SDL_CreateCondition(); +prosperon_rt *create_actor(int argc, char **argv) +{ + prosperon_rt *actor = calloc(sizeof(*actor), 1); + actor->cmd.argc = argc; + actor->cmd.argv = argv; + actor->cycle_fn = JS_UNDEFINED; + actor->idx_buffer = JS_UNDEFINED; + actor->message_handle = JS_UNDEFINED; + actor->unneeded = JS_UNDEFINED; + actor->on_exception = JS_UNDEFINED; + arrsetcap(actor->messages, 5); + actor->mutex = SDL_CreateMutex(); + SDL_LockMutex(actor->mutex); + printf("created actor %p\n", actor); + script_startup(actor); + const char *fnstr = JS_ToCString(actor->context, actor->message_handle); + printf("WWWWWW AFTER MAKE ACTOR WWWWWW\n"); + printf("NOW??? actor turn %p , fn at %p\n", actor, JS_VALUE_GET_PTR(actor->message_handle)); + printf("%s\n", fnstr); + JS_FreeCString(actor->context, fnstr); - for (int i = 0; i < 1; i++) - SDL_CreateThread(crank_actor, "actor_runner", NULL); - - SDL_CreateThread(reclaimer_thread, "reclaimer", NULL); - - signal(SIGINT, signal_handler); - signal(SIGTERM, signal_handler); - signal(SIGSEGV, signal_handler); - signal(SIGABRT, signal_handler); - atexit(exit_handler); - - SDL_Event *event; - while (SDL_WaitEvent(event)) { - printf("Got event!\n"); - if (event->type == SDL_EVENT_QUIT) - return 0; - } - - return 0; + set_actor_state(actor); + SDL_UnlockMutex(actor->mutex); + return actor; } prosperon_rt *get_actor(char *id) { int idx = shgeti(actors, id); - if (idx == -1) return NULL; - - return actors[idx].value; + return idx == -1 ? NULL : actors[idx].value; } char *register_actor(char *id, prosperon_rt *actor) @@ -389,13 +222,9 @@ void send_message(prosperon_rt *target, struct message msg) { SDL_LockMutex(target->mutex); arrput(target->messages, msg); - if (target->ar) { - SDL_RemoveTimer(target->ar); - target->ar = 0; - } - SDL_UnlockMutex(target->mutex); - + if (target->ar) SDL_RemoveTimer(target->ar), target->ar = 0; actor_signal(target); + SDL_UnlockMutex(target->mutex); } void actor_signal(prosperon_rt *actor) @@ -408,6 +237,290 @@ void actor_signal(prosperon_rt *actor) SDL_SignalCondition(queue_cond); SDL_UnlockMutex(queue_mutex); } - SDL_UnlockMutex(actor->mutex); } + +static void set_actor_state(prosperon_rt *actor) +{ + SDL_LockMutex(actor->mutex); + if (arrlen(actor->messages) == 0) { + actor->state = ACTOR_IDLE; + actor->ar = SDL_AddTimerNS(100e9, actor_remove_cb, actor); + } else { + actor->state = ACTOR_READY; + SDL_LockMutex(queue_mutex); + arrput(ready_queue, actor); + SDL_SignalCondition(queue_cond); + SDL_UnlockMutex(queue_mutex); + } + SDL_UnlockMutex(actor->mutex); +} + +void actor_turn(prosperon_rt *actor) +{ + printf("AAAAAAAAAAAAAAAAA ACTOR TAKE TURN %p\n", actor); + printf("actor turn %p , fn at %p\n", actor, JS_VALUE_GET_PTR(actor->message_handle)); + + SDL_LockMutex(actor->mutex); + actor->state = ACTOR_RUNNING; + + const char *fnstr = JS_ToCString(actor->context, actor->message_handle); + printf("NOW??? actor turn %p , fn at %p. S A FN???? %d\n", actor, JS_VALUE_GET_PTR(actor->message_handle), JS_IsFunction(actor->context, actor->message_handle)); + printf("%p\n", fnstr); + JS_FreeCString(actor->context, fnstr); + + + while (arrlen(actor->messages) > 0) { + struct message msg = actor->messages[0]; + arrdel(actor->messages, 0); + JSValue arg = JS_NewArrayBuffer(actor->context, msg.data, msg.size, js_dofree, NULL, 0); + JSValue result = JS_Call(actor->context, actor->message_handle, JS_UNDEFINED, 1, &arg); + uncaught_exception(actor->context, result); + } + + while (arrlen(actor->events) > 0) { + JSValue event = actor->events[0]; + arrdel(actor->events, 0); + JSValue result = JS_Call(actor->context, event, JS_UNDEFINED, 0, NULL); + uncaught_exception(actor->context, result); + } + + set_actor_state(actor); + SDL_UnlockMutex(actor->mutex); +} + +void actor_free(prosperon_rt *actor) +{ + printf("KILLING ACTOR %p\n", actor); + shdel(actors, actor->id); + JSContext *js = actor->context; + SDL_LockMutex(actor->mutex); + JS_FreeValue(js, actor->cycle_fn); + JS_FreeValue(js, actor->idx_buffer); + JS_FreeValue(js, actor->message_handle); + JS_FreeValue(js, actor->on_exception); + SDL_RemoveTimer(actor->ar); + for (int i = 0; i < arrlen(actor->js_swapchains); i++) JS_FreeValue(js, actor->js_swapchains[i]); + for (int i = 0; i < arrlen(actor->events); i++) JS_FreeValue(js, actor->events[i]); + for (int i = 0; i < hmlen(actor->timers); i++) JS_FreeValue(js, actor->timers[i].value); + arrfree(actor->js_swapchains); + arrfree(actor->events); + arrfree(actor->messages); + arrfree(actor->module_registry); + SDL_DestroyMutex(actor->mutex); + JSRuntime *rt = JS_GetRuntime(js); + JS_FreeContext(js); + JS_FreeRuntime(rt); + free(actor->id); + free(actor); +} + +Uint32 actor_timer_cb(prosperon_rt *actor, SDL_TimerID id, Uint32 interval) +{ + int idx = hmgeti(actor->timers, id); + if (idx == -1) return 0; + SDL_LockMutex(actor->mutex); + JSValue cb = actor->timers[idx].value; + hmdel(actor->timers, id); + arrput(actor->events, cb); + SDL_UnlockMutex(actor->mutex); + actor_signal(actor); + return interval; +} + +JSValue js_actor_delay(JSContext *js, JSValue self, int argc, JSValue *argv) +{ + prosperon_rt *actor = JS_GetContextOpaque(js); + double seconds; + JS_ToFloat64(js, &seconds, argv[2]); + Uint64 ns = seconds * 1000000000.0f; + Uint32 id = SDL_AddTimerNS(ns, actor_timer_cb, actor); + SDL_LockMutex(actor->mutex); + hmput(actor->timers, id, JS_DupValue(js, argv[1])); + SDL_UnlockMutex(actor->mutex); + return JS_UNDEFINED; +} + +JSValue js_actor_removetimer(JSContext *js, JSValue self, int argc, JSValue *argv) +{ + prosperon_rt *actor = JS_GetContextOpaque(js); + Uint32 timer_id; + JS_ToUint32(js, &timer_id, argv[1]); + SDL_RemoveTimer(timer_id); + SDL_LockMutex(actor->mutex); + hmdel(actor->timers, timer_id); + SDL_UnlockMutex(actor->mutex); + return JS_UNDEFINED; +} + +void script_startup(prosperon_rt *prt) +{ + JSRuntime *rt; + #ifdef TRACY_ENABLE + rt = JS_NewRuntime2(&tracy_malloc_funcs, NULL); + #else + rt = JS_NewRuntime(); + #endif + JSContext *js = JS_NewContextRaw(rt); + JS_AddIntrinsicBaseObjects(js); + JS_AddIntrinsicEval(js); + JS_AddIntrinsicRegExp(js); + JS_AddIntrinsicJSON(js); + JS_AddIntrinsicMapSet(js); + JS_AddIntrinsicTypedArrays(js); + JS_AddIntrinsicBigInt(js); + JS_AddIntrinsicBigFloat(js); + JS_AddIntrinsicBigDecimal(js); + JS_AddIntrinsicOperators(js); + JS_EnableBignumExt(js, 1); + JS_SetContextOpaque(js, prt); + prt->context = js; + ffi_load(js); + + PHYSFS_File *eng = PHYSFS_openRead(ENGINE); + if (!eng) { + printf("Could not open file! %s\n", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode())); + return; + } + PHYSFS_Stat stat; + PHYSFS_stat(ENGINE, &stat); + void *data = malloc(stat.filesize); + PHYSFS_readBytes(eng, data, stat.filesize); + PHYSFS_close(eng); + SDL_LockMutex(prt->mutex); + JSValue v = JS_Eval(js, data, strlen(data), ENGINE, JS_EVAL_FLAG_STRICT); + uncaught_exception(js, v); + SDL_UnlockMutex(prt->mutex); +} + +void uncaught_exception(JSContext *js, JSValue v) +{ + JS_FreeValue(js, v); + return; + prosperon_rt *rt = JS_GetContextOpaque(js); + SDL_LockMutex(rt->mutex); + if (!JS_HasException(js)) goto END; + + JSValue exp = JS_GetException(js); + printf("error in actor %p\n", rt); + printf("value is tagged with %d. is error? %d\n", JS_VALUE_GET_TAG(exp), JS_IsError(js, exp)); + if (JS_IsFunction(js, rt->on_exception)) { + JSValue ret = JS_Call(js, rt->on_exception, JS_UNDEFINED, 1, &exp); + JS_FreeValue(js, ret); + } else { + const char *msg = JS_ToCString(js, exp); + JSValue stack = JS_GetPropertyStr(js, exp, "stack"); + const char *st = JS_ToCString(js, stack); + printf("Unhandled exception: %s\n%s\n", msg, st); + JS_FreeCString(js, st); + JS_FreeCString(js, msg); + JS_FreeValue(js, stack); + } + JS_FreeValue(js, exp); +END: + SDL_UnlockMutex(rt->mutex); +} + +void script_evalf(JSContext *js, const char *format, ...) +{ + prosperon_rt *rt = JS_GetContextOpaque(js); + SDL_LockMutex(rt->mutex); + va_list args; + va_start(args, format); + int len = vsnprintf(NULL, 0, format, args); + va_end(args); + char *eval = malloc(len + 1); + va_start(args, format); + vsnprintf(eval, len + 1, format, args); + va_end(args); + JSValue obj = JS_Eval(js, eval, len, "C eval", JS_EVAL_FLAG_STRICT); + free(eval); + uncaught_exception(js, obj); + SDL_UnlockMutex(rt->mutex); +} + +static int crank_actor(void *data) +{ + while (true) { + prosperon_rt *actor = NULL; + SDL_LockMutex(queue_mutex); + if (arrlen(ready_queue) > 0) actor = ready_queue[0], arrdel(ready_queue, 0); + else if (arrlen(slow_queue) > 0) actor = slow_queue[0], arrdel(slow_queue, 0); + else { + SDL_WaitCondition(queue_cond, queue_mutex); + continue; + } + SDL_UnlockMutex(queue_mutex); + if (actor) actor_turn(actor); + } + return 0; +} + +static void signal_handler(int sig) +{ + const char *str = NULL; + 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; + } + if (!str) return; + for (int i = 0; i < shlen(actors); i++) { + prosperon_rt *main = actors[i].value; + JSContext *js = main->context; + script_evalf(js, "prosperon.dispatch('%s')", str); + } + if (sig == SIGTERM || sig == SIGINT) exit(1); +} + +static void exit_handler(void) +{ + for (int i = 0; i < shlen(actors); i++) { + prosperon_rt *main = actors[i].value; + JSContext *js = main->context; + script_evalf(js, "prosperon.dispatch('exit')"); + } +} + +int main(int argc, char **argv) +{ + SDL_Init(SDL_INIT_EVENTS | SDL_INIT_VIDEO); + int cores = SDL_GetNumLogicalCPUCores(); + if (cores == 1) return printf("Platform has only one core!\n"), 1; + main_thread = SDL_GetCurrentThreadID(); + if (!main_thread) return printf("Platform does not support threads!\n"), 1; + + prosperon = argv[0]; + PHYSFS_init(argv[0]); + const char *base = PHYSFS_getBaseDir(); + PHYSFS_setWriteDir(base); + PHYSFS_mount(base, "/", 0); + int mounted = prosperon_mount_core(); + if (!mounted) mounted = PHYSFS_mount("core.zip", NULL, 0); + if (!mounted) return printf("Could not mount core. Reason: %s\n", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode())), 1; + + queue_mutex = SDL_CreateMutex(); + queue_cond = SDL_CreateCondition(); + + char **margv = malloc(sizeof(char *) * argc); + for (int i = 0; i < argc; i++) margv[i] = strdup(argv[i]); + create_actor(argc, margv); + + SDL_CreateThread(crank_actor, "actor_runner", NULL); + + signal(SIGINT, signal_handler); + signal(SIGTERM, signal_handler); + signal(SIGSEGV, signal_handler); + signal(SIGABRT, signal_handler); + atexit(exit_handler); + + SDL_Event event; + while (SDL_WaitEvent(&event)) { + printf("Got event!\n"); + if (event.type == SDL_EVENT_QUIT) return 0; + } + return 0; +} diff --git a/source/prosperon.h b/source/prosperon.h index c0591957..15777ade 100644 --- a/source/prosperon.h +++ b/source/prosperon.h @@ -4,20 +4,23 @@ #include #include "quickjs.h" -typedef JSValue (*MODULEFN)(JSContext *js); - #define STATE_VECTOR_LENGTH 624 -#define STATE_VECTOR_M 397 /* changes to STATE_VECTOR_LENGTH also require changes to this */ +#define STATE_VECTOR_M 397 + +#define ACTOR_IDLE 0 +#define ACTOR_READY 1 +#define ACTOR_RUNNING 2 +#define ACTOR_EXHAUSTED 3 +#define ACTOR_RECLAIMING 4 +#define ACTOR_SLOW 5 + +typedef JSValue (*MODULEFN)(JSContext *js); typedef struct tagMTRand { uint32_t mt[STATE_VECTOR_LENGTH]; int32_t index; } MTRand; -extern SDL_ThreadID main_thread; - -extern SDL_TLSID prosperon_id; - typedef struct { const char *name; MODULEFN fn; @@ -33,40 +36,48 @@ struct message { size_t size; }; -#define ACTOR_IDLE 0 -#define ACTOR_READY 1 -#define ACTOR_RUNNING 2 -#define ACTOR_EXHAUSTED 3 // flagged when the actor is running GC -#define ACTOR_RECLAIMING 4 -#define ACTOR_SLOW 5 - typedef struct prosperon_rt { - cmdargs cmd; // args this actor was started with - JSContext *context; // The context this actor uses - char *id; - MTRand mrand; + cmdargs cmd; + JSContext *context; JSValue cycle_fn; JSValue idx_buffer; JSValue on_exception; JSValue message_handle; JSValue unneeded; - double unneeded_secs; - int idx_count; + struct { Uint32 key; JSValue value; } *timers; + JSValue *events; ModuleEntry *module_registry; JSValue *js_swapchains; - struct { Uint32 key; JSValue value; } *timers; - JSValue *events; // stack of events that need triggered on this actor - SDL_Mutex *mutex; // blocks access to modifying this actor + + SDL_Mutex *mutex; + + char *id; + MTRand mrand; + double unneeded_secs; + int idx_count; + struct message *messages; - int state; // - Uint32 ar; // "actor removal" timer + SDL_Mutex *msg_mutex; + int state; + Uint32 ar; } prosperon_rt; +extern SDL_ThreadID main_thread; +extern SDL_TLSID prosperon_id; + +prosperon_rt *create_actor(int argc, char **argv); prosperon_rt *get_actor(char *id); char *register_actor(char *id, prosperon_rt *actor); -prosperon_rt *create_actor(); void actor_signal(prosperon_rt *actor); -void actor_turn(prosperon_rt *actor); void send_message(prosperon_rt *actor, struct message msg); +void actor_turn(prosperon_rt *actor); void actor_free(prosperon_rt *actor); +Uint32 actor_timer_cb(prosperon_rt *actor, SDL_TimerID id, Uint32 interval); +JSValue js_actor_delay(JSContext *js, JSValue self, int argc, JSValue *argv); +JSValue js_actor_removetimer(JSContext *js, JSValue self, int argc, JSValue *argv); +void script_startup(prosperon_rt *rt); +void script_evalf(JSContext *js, const char *format, ...); +JSValue script_eval(JSContext *js, const char *file, const char *script); +void uncaught_exception(JSContext *js, JSValue v); + #endif diff --git a/source/qjs_enet.c b/source/qjs_enet.c index 5fadfb26..19042dd8 100644 --- a/source/qjs_enet.c +++ b/source/qjs_enet.c @@ -4,8 +4,7 @@ #include #include #include - -#include "script.h" +#include "prosperon.h" #define countof(a) (sizeof(a)/sizeof(*(a))) @@ -578,4 +577,4 @@ JSModuleDef *JS_INIT_MODULE(JSContext *ctx, const char *module_name) if (!m) return NULL; JS_AddModuleExport(ctx, m, "default"); return m; -} \ No newline at end of file +} diff --git a/source/qjs_tracy.c b/source/qjs_tracy.c index dc7544f7..dc31c293 100644 --- a/source/qjs_tracy.c +++ b/source/qjs_tracy.c @@ -100,19 +100,6 @@ static JSValue js_tracy_message(JSContext *js, JSValue self, int argc, JSValue * return JS_UNDEFINED; } -static JSValue js_tracy_thread_name(JSContext *js, JSValue self, int argc, JSValue *argv) -{ -#ifdef TRACY_ON_DEMAND - if (!TracyCIsConnected) - return JS_UNDEFINED; -#endif - - const char *str = JS_ToCString(js, argv[0]); - TracyCSetThreadName(str); - JS_FreeCString(js,str); - return JS_UNDEFINED; -} - static JSValue js_tracy_zone_begin(JSContext *js, JSValue self, int argc, JSValue *argv) { #ifdef TRACY_ON_DEMAND @@ -569,7 +556,6 @@ static const JSCFunctionListEntry js_tracy_funcs[] = { JS_CFUNC_DEF("gpu_init", 0, js_tracy_gpu_init), JS_CFUNC_DEF("gpu_sync", 0, js_tracy_gpu_sync), JS_CFUNC_DEF("end_frame", 0, js_tracy_frame_mark), - JS_CFUNC_DEF("thread_name", 1, js_tracy_thread_name), JS_CFUNC_DEF("zone", 1, js_tracy_zone_begin), JS_CFUNC_DEF("message", 1, js_tracy_message), JS_CFUNC_DEF("plot", 2, js_tracy_plot), diff --git a/source/script.c b/source/script.c deleted file mode 100644 index d4621dce..00000000 --- a/source/script.c +++ /dev/null @@ -1,226 +0,0 @@ -#include "script.h" -#include "jsffi.h" -#include "stb_ds.h" -#include -#include -#include -#include -#include -#include "jsffi.h" -#include -#include -#include "quickjs.h" - -#include "prosperon.h" - -#if defined(__APPLE__) - #include -#elif defined(_WIN32) - #include -#elif defined(__linux__) || defined(__GLIBC__) - #define _GNU_SOURCE - #include -#endif - -#include "physfs.h" - -#define ENGINE "scripts/core/engine.js" - -#ifdef TRACY_ENABLE -#include - -#if defined(__APPLE__) -#define MALLOC_OVERHEAD 0 -#else -#define MALLOC_OVERHEAD 8 -#endif - -#define likely(x) __builtin_expect(!!(x), 1) -#define unlikely(x) __builtin_expect(!!(x), 0) - -/* default memory allocation functions with memory limitation */ -static size_t js_tracy_malloc_usable_size(const void *ptr) -{ -#if defined(__APPLE__) - return malloc_size(ptr); -#elif defined(_WIN32) - return _msize((void *)ptr); -#elif defined(EMSCRIPTEN) - return 0; -#elif defined(__linux__) || defined(__GLIBC__) - return malloc_usable_size((void *)ptr); -#else - /* change this to `return 0;` if compilation fails */ - return malloc_usable_size((void *)ptr); -#endif -} - -static void *js_tracy_malloc(JSMallocState *s, size_t size) -{ - void *ptr; - - /* Do not allocate zero bytes: behavior is platform dependent */ - assert(size != 0); - - if (unlikely(s->malloc_size + size > s->malloc_limit)) - return NULL; - - ptr = malloc(size); - if (!ptr) - return NULL; - - s->malloc_count++; - s->malloc_size += js_tracy_malloc_usable_size(ptr) + MALLOC_OVERHEAD; - TracyCAllocN(ptr,js_tracy_malloc_usable_size(ptr) + MALLOC_OVERHEAD, "quickjs"); - return ptr; -} - -static void js_tracy_free(JSMallocState *s, void *ptr) -{ - if (!ptr) - return; - - s->malloc_count--; - s->malloc_size -= js_tracy_malloc_usable_size(ptr) + MALLOC_OVERHEAD; - - TracyCFreeN(ptr, "quickjs"); - - free(ptr); -} - -static void *js_tracy_realloc(JSMallocState *s, void *ptr, size_t size) -{ - size_t old_size; - - if (!ptr) { - if (size == 0) - return NULL; - return js_tracy_malloc(s, size); - } - old_size = js_tracy_malloc_usable_size(ptr); - if (size == 0) { - s->malloc_count--; - s->malloc_size -= old_size + MALLOC_OVERHEAD; - - TracyCFreeN(ptr, "quickjs"); - - free(ptr); - return NULL; - } - if (s->malloc_size + size - old_size > s->malloc_limit) - return NULL; - - TracyCFreeN(ptr, "quickjs"); - - ptr = realloc(ptr, size); - if (!ptr) - return NULL; - - s->malloc_size += js_tracy_malloc_usable_size(ptr) - old_size; - - TracyCAllocN(ptr,js_tracy_malloc_usable_size(ptr) + MALLOC_OVERHEAD, "quickjs"); - - return ptr; -} - -static const JSMallocFunctions tracy_malloc_funcs = { - js_tracy_malloc, - js_tracy_free, - js_tracy_realloc, - js_tracy_malloc_usable_size -}; - -#endif - -// this function takes control of the program. -void script_startup(prosperon_rt *prt) { - JSRuntime *rt; -#ifdef TRACY_ENABLE - rt = JS_NewRuntime2(&tracy_malloc_funcs, NULL); -#else - rt = JS_NewRuntime(); -#endif - JSContext *js = JS_NewContextRaw(rt); - JS_AddIntrinsicBaseObjects(js); - JS_AddIntrinsicEval(js); - JS_AddIntrinsicRegExp(js); - JS_AddIntrinsicJSON(js); - JS_AddIntrinsicMapSet(js); - JS_AddIntrinsicTypedArrays(js); - JS_AddIntrinsicBigInt(js); - JS_AddIntrinsicBigFloat(js); - JS_AddIntrinsicBigDecimal(js); - JS_AddIntrinsicOperators(js); - JS_EnableBignumExt(js, 1); - - JS_SetContextOpaque(js, prt); - prt->context = js; - - ffi_load(js); - - PHYSFS_File *eng = PHYSFS_openRead(ENGINE); - if (!eng) { - printf("Could not open file! %s\n", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode())); - return; - } - - PHYSFS_Stat stat; - PHYSFS_stat(ENGINE, &stat); - void *data = malloc(stat.filesize); - PHYSFS_readBytes(eng,data,stat.filesize); - PHYSFS_close(eng); - SDL_LockMutex(prt->mutex); - JSValue v = JS_Eval(js, data, strlen(data), ENGINE, JS_EVAL_FLAG_STRICT); - uncaught_exception(js,v); - SDL_UnlockMutex(prt->mutex); -} - -void uncaught_exception(JSContext *js, JSValue v) -{ - if (!JS_IsException(v)) { - JS_FreeValue(js,v); - return; - } - - prosperon_rt *rt = JS_GetContextOpaque(js); - - JSValue onexp = rt->on_exception; - - if (!JS_IsUndefined(onexp)) { - JSValue ex = JS_GetException(js); - JSValue ret = JS_Call(js, onexp, JS_UNDEFINED, 1, &ex); - JS_FreeValue(js,ret); - JS_FreeValue(js,ex); - } else { - JSValue ex = JS_GetException(js); - const char *strex = JS_ToCString(js,ex); - JSValue stack = JS_GetPropertyStr(js,ex,"stack"); - const char *st = JS_ToCString(js,stack); - printf("Unhandled exception: %s\n%s\n", strex, st); - JS_FreeValue(js,stack); - JS_FreeValue(js,ex); - JS_FreeCString(js,st); - JS_FreeCString(js,strex); - } - - JS_FreeValue(js,v); -} - -void script_evalf(JSContext *js, const char *format, ...) -{ - JSValue obj; - va_list args; - va_start(args, format); - int len = vsnprintf(NULL, 0, format, args); - va_end(args); - - char *eval = malloc(len+1); - va_start(args, format); - vsnprintf(eval, len+1, format, args); - va_end(args); - - obj = JS_Eval(js, eval, len, "C eval", JS_EVAL_FLAG_STRICT); - free(eval); - - uncaught_exception(js,obj); -} diff --git a/source/script.h b/source/script.h deleted file mode 100644 index ec3811ec..00000000 --- a/source/script.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef SCRIPT_H -#define SCRIPT_H - -#include "quickjs.h" -#include -#include "prosperon.h" - -void script_startup(prosperon_rt *rt); - -void script_evalf(JSContext *js, const char *format, ...); -JSValue script_eval(JSContext *js, const char *file, const char *script); -void uncaught_exception(JSContext *js, JSValue v); - -#endif diff --git a/source/sprite.h b/source/sprite.h index 7d48e930..c5eb75f9 100644 --- a/source/sprite.h +++ b/source/sprite.h @@ -2,8 +2,8 @@ #define SPRITE_H #include "HandmadeMath.h" -#include "script.h" #include "render.h" +#include "quickjs.h" struct sprite{ rect affine; diff --git a/source/transform.c b/source/transform.c index 1239d73b..c88e7be2 100644 --- a/source/transform.c +++ b/source/transform.c @@ -1,7 +1,6 @@ #include "transform.h" #include #include -#include "script.h" #include "stb_ds.h" static transform **dirties; diff --git a/tests/overling.js b/tests/overling.js index 52bba760..7c8a0939 100644 --- a/tests/overling.js +++ b/tests/overling.js @@ -13,3 +13,5 @@ $_.start(e => { $_.stop(e.actor) } }, "tests/underling.js"); + +console.log("OVELRING BOTTOM"); diff --git a/tests/underling.js b/tests/underling.js index a3dc93ce..39d079e9 100644 --- a/tests/underling.js +++ b/tests/underling.js @@ -3,3 +3,5 @@ var os = use('os') $_.receiver(e => { console.log(`got message: ${json.encode(e)}`) }) + +console.log("UNDERLING BOTTOM");