add uncaught exception handling

This commit is contained in:
2025-01-17 10:44:33 -06:00
parent bae3a94fa1
commit 406c7ea590
9 changed files with 239 additions and 103 deletions

View File

@@ -239,10 +239,15 @@ globalThis.print = console.print;
console.rec = function(category, priority, line, file, msg)
{
return `${file}:${line}: [${category} ${priority}]: ${msg}`;
return `${file}:${line}: [${category} ${priority}]: ${msg}` + "\n";
}
console.pprint = function pprint(msg, lvl = 0) {
var logfile = io.open('.prosperon/log.txt')
//logfile.buffer(1024*1024) // 1MB buffer
function pprint(msg, lvl = 0) {
if (lvl < console.stdout_lvl && !logfile) return;
if (typeof msg === "object") msg = JSON.stringify(msg, null, 2);
var file = "nofile";
@@ -258,43 +263,49 @@ console.pprint = function pprint(msg, lvl = 0) {
if (m) line = m;
}
var fmt = console.rec("script", lvl, line,file, msg);
console.log(fmt);
if (lvl >= console.stdout_lvl)
console.print(fmt)
if (logfile)
logfile.write(fmt)
if (tracy) tracy.message(fmt);
};
console.spam = function spam(msg) {
console.pprint(msg, 0);
pprint(msg, 0);
};
console.debug = function debug(msg) {
console.pprint(msg, 1);
pprint(msg, 1);
};
console.info = function info(msg) {
console.pprint(msg, 2);
pprint(msg, 2);
};
console.warn = function warn(msg) {
console.pprint(msg, 3);
};
console.error = function error (e) {
console.log(e);
console.log(e.stack);
};
console.panic = function (e) {
console.log("PANIC!")
console.error(e);
os.quit();
};
console.stackstr = function (skip = 0) {
var err = new Error();
var stack = err.stack.split("\n");
return stack.slice(skip, stack.length).join("\n");
pprint(msg, 3);
};
console.stack = function (skip = 0) {
var stack = console.stackstr(skip + 1);
console.log(stack);
return stack;
console.log = function(msg)
{
pprint(msg, 2)
}
console.error = function(e) {
if (!e)
e = new Error();
pprint(e, 4)
pprint(e.stack, 4)
};
console.panic = function (e) {
console.pprint(msg, 5)
os.quit();
};
os.on('uncaught_exception', function(e) { console.error(e); });
console.stdout_lvl = 1;
console.doc = {

View File

@@ -368,9 +368,8 @@ var entity = {
rmactor(this);
for (var i in this) {
for (var i in this)
if (this[i] instanceof Object || this[i] instanceof Function) delete this[i];
}
},
make_objs(objs) {

View File

@@ -67,16 +67,21 @@ var physlag = 0;
prosperon.SIGABRT = function()
{
console.log("ABORT");
console.stack();
console.error(new Error('SIGABRT'));
os.exit(1);
}
prosperon.SIGSEGV = function()
{
console.stack();
console.error(new Error('SIGSEGV'));
os.exit(1);
}
prosperon.exit = function()
{
}
prosperon.init = function () {
render.init();
// imgui.init(render._main);

View File

@@ -1071,20 +1071,34 @@ render.image = function image(image, rect = [0,0], rotation = 0, color, pipeline
current_queue.push(cmd)
};
var sprite_buf = [];
render.images = function images(image, rects, config)
{
if (!image) throw Error ('Need an image to render.');
if (typeof image === "string") image = game.texture(image);
var bb = [];
bb.width = image.texture.width;
bb.height = image.texture.height;
var sprites = [];
for (var rect of rects) {
// get sprite from sprite_buf, or make a new one
rect.__proto__ = bb;
var cmd = Object.create(std_sprite_cmd);
cmd.rect = rect;
cmd.image = image;
current_queue.push(cmd);
var sprite;
if (sprite_buf.length) sprite = sprite_buf.pop();
else sprite = os.make_sprite();
sprite.set_affine(rect);
sprite.set_image(image);
sprites.push(sprite)
}
// var sprites = os.rects_to_sprites(image,rects);
var cmds = render._main.make_sprite_queue(sprites, prosperon.camera, sprite_pipeline)
for (var i = 0; i < cmds.length; i++)
current_queue.push(cmds[i])
sprite_buf = sprite_buf.concat(sprites)
}
var tile_def = {repeat_x:true, repeat_y:true};

View File

@@ -1183,6 +1183,13 @@ QJSCLASS(SDL_GPUCopyPass)
QJSCLASS(SDL_GPURenderPass)
QJSCLASS(SDL_Cursor)
static void PHYSFS_File_free(JSRuntime *rt, PHYSFS_File *f)
{
PHYSFS_close(f);
}
QJSCLASS(PHYSFS_File)
void qtree_free(JSRuntime *rt, qtree *tree)
{
qtree_destroy(*tree);
@@ -1431,30 +1438,6 @@ JSValue vecarr2js(JSContext *js,HMM_Vec2 *points, int n) {
return array;
}
int js_print_exception(JSContext *js, JSValue v)
{
if (!js) return 0;
#ifndef NDEBUG
if (!JS_IsException(v))
return 0;
JSValue ex = JS_GetException(js);
const char *name = JS_ToCString(js, js_getpropertystr(js,ex, "name"));
const char *msg = JS_ToCString(js, js_getpropertystr(js,ex, "message"));
const char *stack = JS_ToCString(js, js_getpropertystr(js,ex, "stack"));
printf("%s :: %s\n%s\n", name, msg, stack);
JS_FreeCString(js, name);
JS_FreeCString(js, msg);
JS_FreeCString(js, stack);
JS_FreeValue(js,ex);
return 1;
#endif
return 0;
}
rect js2rect(JSContext *js,JSValue v) {
if (JS_IsUndefined(v)) return (rect){0,0,1,1};
rect rect;
@@ -2763,7 +2746,6 @@ JSC_CCALL(game_engine_input,
#endif
JSValue e = event2js(js,event);
JSValue ret = JS_Call(js,argv[0], JS_UNDEFINED, 1, &e);
js_print_exception(js,ret);
JS_FreeValue(js,ret);
}
)
@@ -4068,6 +4050,26 @@ void better_sort_sprites(sprite *arr, size_t length) {
free(temp);
}
int sort_sprite_backtofront(const sprite *a, const sprite *b)
{
if (a->layer != b->layer) return a->layer - b->layer;
if (a->tex != b->tex) return ((uintptr_t)a->tex < (uintptr_t)b->tex) ? -1 : 1;
return 0;
}
int sort_sprite_fronttoback(const sprite *a, const sprite *b)
{
if (a->layer != b->layer) return b->layer - a->layer;
if (a->tex != b->tex) return ((uintptr_t)a->tex < (uintptr_t)b->tex) ? -1 : 1;
return 0;
}
int sort_sprite_texture(const sprite *a, const sprite *b)
{
if (a->tex != b->tex) return ((uintptr_t)a->tex < (uintptr_t)b->tex) ? -1 : 1;
return 0;
}
int sort_sprite(const sprite *a, const sprite *b)
{
if (a->layer != b->layer) return a->layer - b->layer;
@@ -4219,6 +4221,7 @@ JSC_CCALL(gpu_make_sprite_mesh,
for (int i = 0; i < quads; i++) {
JSValue sub = JS_GetPropertyUint32(js,argv[0],i);
transform *tr;
rect src;
HMM_Vec4 color;
@@ -5535,7 +5538,6 @@ JSC_CCALL(input_mouse_show,
JSC_CCALL(input_cursor_set,
SDL_Cursor *c = js2SDL_Cursor(js,argv[0]);
printf("setting cursor to %p\n", c);
if (!SDL_SetCursor(c))
return JS_ThrowReferenceError(js, "could not set cursor: %s", SDL_GetError());
)
@@ -5617,26 +5619,14 @@ static const JSCFunctionListEntry js_time_funcs[] = {
MIST_FUNC_DEF(time, computer_zone, 0)
};
JSC_SCALL(console_log,
printf("%s\n", str);
JSC_SCALL(console_print,
printf("%s", str);
)
static const JSCFunctionListEntry js_console_funcs[] = {
MIST_FUNC_DEF(console,log,1),
MIST_FUNC_DEF(console,print,1),
};
static JSValue instr_v = JS_UNDEFINED;
int iiihandle(JSRuntime *rt, void *data)
{
script_call_sym(instr_v, 0, NULL);
return 0;
}
JSC_CCALL(profile_gather,
instr_v = JS_DupValue(js, argv[1]);
JS_SetInterruptHandler(JS_GetRuntime(js), iiihandle, NULL);
)
JSC_CCALL(profile_gather_rate,
JS_SetInterruptRate(js2number(js,argv[0]));
)
@@ -5665,7 +5655,6 @@ JSC_CCALL(profile_now, return number2js(js, SDL_GetTicksNS()/1000000000.f))
static const JSCFunctionListEntry js_profile_funcs[] = {
MIST_FUNC_DEF(profile,now,0),
MIST_FUNC_DEF(profile,best_t, 1),
MIST_FUNC_DEF(profile,gather,2),
MIST_FUNC_DEF(profile,gather_rate,1),
MIST_FUNC_DEF(profile,gather_stop,0),
};
@@ -5831,6 +5820,14 @@ JSC_CCALL(io_globfs,
JSC_CCALL(io_basedir, return JS_NewString(js,PHYSFS_getBaseDir()))
JSC_SCALL(io_open,
PHYSFS_File *f = PHYSFS_openWrite(str);
if (!f)
return JS_ThrowReferenceError(js,"%s", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
return PHYSFS_File2js(js,f);
)
static const JSCFunctionListEntry js_io_funcs[] = {
MIST_FUNC_DEF(io, rm, 1),
MIST_FUNC_DEF(io, mkdir, 1),
@@ -5844,6 +5841,55 @@ static const JSCFunctionListEntry js_io_funcs[] = {
MIST_FUNC_DEF(io,writepath, 1),
MIST_FUNC_DEF(io,basedir, 0),
MIST_FUNC_DEF(io, gamemode, 2),
MIST_FUNC_DEF(io, open, 2),
};
JSC_CCALL(file_close,
PHYSFS_File *f = js2PHYSFS_File(js,self);
PHYSFS_close(f);
)
JSC_CCALL(file_write,
PHYSFS_File *f = js2PHYSFS_File(js,self);
size_t len;
unsigned char *data;
if (JS_IsString(argv[0]))
data = JS_ToCStringLen(js,&len,argv[0]);
else
data = JS_GetArrayBuffer(js,&len, argv[0]);
size_t wrote = PHYSFS_writeBytes(f,data,len);
if (wrote == -1 || wrote < len)
return JS_ThrowReferenceError(js,"%s", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
)
JSC_CCALL(file_buffer,
PHYSFS_File *f = js2PHYSFS_File(js,self);
size_t size = js2number(js,argv[0]);
if (!PHYSFS_setBuffer(f,size))
return JS_ThrowReferenceError(js,"%s", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
)
JSC_CCALL(file_tell,
PHYSFS_File *f = js2PHYSFS_File(js,self);
size_t tell = PHYSFS_tell(f);
if (tell == -1)
return JS_ThrowReferenceError(js,"%s", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
return number2js(js,tell);
)
JSC_CCALL(file_eof,
PHYSFS_File *f = js2PHYSFS_File(js,self);
return JS_NewBool(js, PHYSFS_eof(f));
)
static const JSCFunctionListEntry js_PHYSFS_File_funcs[] = {
MIST_FUNC_DEF(file, close, 0),
MIST_FUNC_DEF(file, write, 1),
MIST_FUNC_DEF(file, buffer, 1),
MIST_FUNC_DEF(file, tell, 0),
MIST_FUNC_DEF(file, eof, 0),
};
JSC_GETSET_APPLY(transform, pos, vec3)
@@ -6059,9 +6105,12 @@ JSC_CCALL(performance_pack_num, return number2js(js,1.0))
JSC_CCALL(performance_pack_string, return JS_NewStringLen(js, STRTEST, sizeof(*STRTEST)))
JSC_CCALL(performance_unpack_string, JS_ToCString(js, argv[0]))
JSC_CCALL(performance_call_fn_n,
for (int i = 0; i < js2number(js,argv[1]); i++)
script_call_sym(argv[0],0,NULL);
script_call_sym(argv[2],0,NULL);
for (int i = 0; i < js2number(js,argv[1]); i++) {
JSValue r = JS_Call(js, argv[0], JS_UNDEFINED, 0, NULL);
if (JS_IsException(r)) return r;
JS_FreeValue(js,r);
}
ret = JS_Call(js,argv[2], JS_UNDEFINED, 0, NULL);
)
static const JSCFunctionListEntry js_performance_funcs[] = {
@@ -6364,7 +6413,7 @@ JSC_CCALL(os_check_gc,
return gc;
)
JSC_SSCALL(os_eval, ret = script_eval(str, str2))
JSC_SSCALL(os_eval, return ret = script_eval(js,str, str2))
JSC_CCALL(os_make_timer, return timer2js(js,timer_make(js,argv[0])))
JSC_CCALL(os_update_timers, timer_update(js, js2number(js,argv[0])))
@@ -7067,6 +7116,11 @@ JSC_CCALL(os_insertion_sort,
JSValue arr_j = JS_GetPropertyUint32(js, arr, j);
JSValue ret = JS_Call(js, cmp, JS_UNDEFINED, 2, (JSValue[]){ arr_j, key });
if (JS_IsException(ret)) {
JS_FreeValue(js,arr_j);
JS_FreeValue(js,key);
return ret;
}
double c = js2number(js, ret);
JS_FreeValue(js, ret);
@@ -7165,6 +7219,40 @@ JSC_CCALL(os_make_rtree,
return rtree2js(js,tree);
)
JSC_CCALL(os_rects_to_sprites,
ret = JS_NewArray(js);
JSValue image = argv[0];
JSValue jstex = JS_GetProperty(js,image,texture_atom);
double w, h = 0;
JS_GETATOM(js,w,jstex,width_atom,number)
JS_GETATOM(js,h,jstex,height_atom,number)
SDL_GPUTexture *tex = js2SDL_GPUTexture(js,jstex);
JS_FreeValue(js,jstex);
JSValue rects = argv[1];
rect uv;
JS_GETATOM(js,uv,image,rect_atom,rect)
ret = JS_NewArray(js);
int n = js_arrlen(js,rects);
for (int i = 0; i < n; i++) {
JSValue sub = JS_GetPropertyUint32(js,rects,i);
sprite *s = make_sprite();
s->affine = js2rect(js,sub);
s->affine.w = w;
s->affine.h = h;
s->image = JS_DupValue(js,image);
s->tex = tex;
s->uv = uv;
JS_SetPropertyUint32(js,ret,i,sprite2js(js,s));
JS_FreeValue(js,sub);
}
)
JSC_CCALL(os_on,
on_exception = JS_DupValue(js,argv[1]);
)
static const JSCFunctionListEntry js_os_funcs[] = {
MIST_FUNC_DEF(os, turbulence, 4),
MIST_FUNC_DEF(os, model_buffer, 1),
@@ -7230,6 +7318,8 @@ static const JSCFunctionListEntry js_os_funcs[] = {
MIST_FUNC_DEF(os, power_state, 0),
MIST_FUNC_DEF(os, insertion_sort, 2),
MIST_FUNC_DEF(os, cull_sprites, 2),
MIST_FUNC_DEF(os, rects_to_sprites,2),
MIST_FUNC_DEF(os, on, 2),
};
JSC_CCALL(qtree_insert,
@@ -7372,8 +7462,10 @@ JSC_GETSET(sprite, color, color)
JSC_CCALL(sprite_set_affine,
sprite *sp = js2sprite(js,self);
transform *t = js2transform(js,argv[0]);
// sp->affine = HMM_Mat4ToMat3(t->gcache);
sp->affine = transform2rect(t);
if (!t)
sp->affine = js2rect(js,argv[0]);
else
sp->affine = transform2rect(t);
)
JSC_CCALL(sprite_set_image,
@@ -7384,7 +7476,7 @@ JSC_CCALL(sprite_set_image,
if (JS_IsUndefined(sp->image)) return JS_UNDEFINED;
JSValue img = sp->image;
JS_GETATOM(js, sp->uv, img, rect_atom, rect)
JS_GETATOM(js, sp->tex, img, texture_atom, SDL_GPUTexture)
JS_GETATOM(js, sp->tex, img, texture_atom, SDL_GPUTexture);
)
static const JSCFunctionListEntry js_sprite_funcs[] = {
@@ -7451,7 +7543,6 @@ void ffi_load(JSContext *js) {
JSValue globalThis = JS_GetGlobalObject(js);
QJSCLASSPREP_FUNCS(qtree)
QJSCLASSPREP_FUNCS(rtree)
QJSCLASSPREP_FUNCS(SDL_Window)
@@ -7480,6 +7571,8 @@ void ffi_load(JSContext *js) {
QJSCLASSPREP_FUNCS(SDL_GPUBuffer)
// QJSCLASSPREP_FUNCS(SDL_GPUTransferBuffer)
QJSCLASSPREP_FUNCS(PHYSFS_File)
QJSGLOBALCLASS(os);
QJSCLASSPREP_FUNCS(transform);

View File

@@ -15,6 +15,9 @@ static JSRuntime *rt = NULL;
JSContext *global_js = NULL;
JSValue on_exception = JS_UNDEFINED;
#ifndef NDEBUG
#define JS_EVAL_FLAGS JS_EVAL_FLAG_STRICT
#else
@@ -78,7 +81,7 @@ void script_startup() {
ffi_load(js);
char *eng = read_file("core/scripts/engine.js");
JSValue v = script_eval("core/scripts/engine.js", eng);
JSValue v = script_eval(js, "core/scripts/engine.js", eng);
JS_FreeValue(js, v);
free(eng);
}
@@ -92,6 +95,15 @@ void script_stop()
rt = NULL;
}
void uncaught_exception(JSContext *js, JSValue v)
{
JSValue ret;
if (!JS_IsUndefined(on_exception) && JS_IsException(v))
ret = JS_Call(js, on_exception, JS_UNDEFINED, 1, &v);
JS_FreeValue(js,ret);
JS_FreeValue(js,v);
}
void script_mem_limit(size_t limit) { JS_SetMemoryLimit(rt, limit); }
void script_gc_threshold(size_t threshold) { JS_SetGCThreshold(rt, threshold); }
void script_max_stacksize(size_t size) { JS_SetMaxStackSize(rt, size); }
@@ -111,20 +123,11 @@ void script_evalf(const char *format, ...)
obj = JS_Eval(js, eval, len, "C eval", JS_EVAL_FLAGS);
free(eval);
js_print_exception(js,obj);
JS_FreeValue(js,obj);
uncaught_exception(js,obj);
}
JSValue script_eval(const char *file, const char *script)
JSValue script_eval(JSContext *js, const char *file, const char *script)
{
JSValue v = JS_Eval(js, script, strlen(script), file, JS_EVAL_FLAGS);
js_print_exception(js,v);
return v;
}
void script_call_sym(JSValue sym, int argc, JSValue *argv) {
if (!JS_IsFunction(js, sym)) return;
JSValue ret = JS_Call(js, sym, JS_UNDEFINED, argc, argv);
js_print_exception(js,ret);
JS_FreeValue(js, ret);
return JS_Eval(js, script, strlen(script), file, JS_EVAL_FLAGS);
}

View File

@@ -3,13 +3,14 @@
#include "quickjs.h"
extern JSValue on_exception;
void script_startup();
void script_stop();
void script_evalf(const char *format, ...);
JSValue script_eval(const char *file, const char *script);
void script_call_sym(JSValue sym, int argc, JSValue *argv);
JSValue script_eval(JSContext *js, const char *file, const char *script);
void uncaught_exception(JSContext *js, JSValue v);
extern JSContext *global_js;
#endif

View File

@@ -1,8 +1,17 @@
#include "sprite.h"
static sprite model = {
.affine = {x:0,y:0,w:0,h:0},
.image = JS_UNDEFINED,
.tex = NULL,
.uv = {x:0,y:0,w:1,h:1},
.layer = 0,
.color = {1,1,1,1}
};
sprite *make_sprite()
{
sprite *sprite = calloc(sizeof(*sprite),1);
sprite *sprite = malloc(sizeof(*sprite));
*sprite = model;
return sprite;
}

View File

@@ -34,7 +34,8 @@ void timer_update(JSContext *js, double dt)
if (timers[i]->remain <= 0) {
timers[i]->remain = -10000;
JSValue fn = JS_DupValue(js, timers[i]->fn);
script_call_sym(timers[i]->fn, 0, NULL);
JSValue r = JS_Call(js,fn, JS_UNDEFINED, 0, NULL);
uncaught_exception(js,r);
JS_FreeValue(js, fn);
}
}