Files
cell/source/script.c
John Alanbrook e86138ec00
Some checks failed
Build and Deploy / build-linux (push) Successful in 1m20s
Build and Deploy / build-windows (CLANG64) (push) Failing after 10m58s
Build and Deploy / package-dist (push) Has been cancelled
Build and Deploy / deploy-itch (push) Has been cancelled
Build and Deploy / deploy-gitea (push) Has been cancelled
multirheading mailboxes fixed
2025-03-11 20:34:39 -05:00

247 lines
5.6 KiB
C

#include "script.h"
#include "jsffi.h"
#include "stb_ds.h"
#include <inttypes.h>
#include <limits.h>
#include <sys/stat.h>
#include <errno.h>
#include <stdarg.h>
#include "jsffi.h"
#include <stdlib.h>
#include <assert.h>
#include "quickjs.h"
#if defined(__APPLE__)
#include <malloc/malloc.h>
#elif defined(_WIN32)
#include <malloc.h>
#elif defined(__linux__) || defined(__GLIBC__)
#define _GNU_SOURCE
#include <malloc.h>
#endif
#include "physfs.h"
SDL_TLSID on_exception = {0};
SDL_TLSID js_id = {0};
#define ENGINE "scripts/core/engine.js"
#define JS_EVAL_FLAGS JS_EVAL_FLAG_STRICT
#ifdef TRACY_ENABLE
#include <tracy/TracyC.h>
#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
void script_startup(int argc, char **argv) {
JSRuntime *rt;
#ifdef TRACY_ENABLE
rt = JS_NewRuntime2(&tracy_malloc_funcs, NULL);
#else
rt = JS_NewRuntime();
#endif
JSContext *js = JS_NewContextRaw(rt);
SDL_SetTLS(&js_id, js, script_stop);
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);
JSValue *onexp = malloc(sizeof(JSValue));
*onexp = JS_UNDEFINED;
SDL_SetTLS(&on_exception, onexp, NULL);
ffi_load(js, argc, argv);
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);
JSValue v = script_eval(js, ENGINE, data);
uncaught_exception(js,v);
free(eng);
}
void script_stop(JSContext *js)
{
return;
JSValue *onexp = SDL_GetTLS(&on_exception);
JS_FreeValue(js,*onexp);
JSRuntime *rt = JS_GetRuntime(js);
JS_FreeContext(js);
JS_FreeRuntime(rt);
free(rt);
free(js);
free(onexp);
}
void uncaught_exception(JSContext *js, JSValue v)
{
if (!JS_IsException(v)) {
JS_FreeValue(js,v);
return;
}
JSValue *onexp = SDL_GetTLS(&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_FLAGS);
free(eval);
uncaught_exception(js,obj);
}
JSValue script_eval(JSContext *js, const char *file, const char *script)
{
return JS_Eval(js, script, strlen(script), file, JS_EVAL_FLAGS);
}