#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); }