From f73b7dba01bee6e72451ad1a048ce34fc5d6185e Mon Sep 17 00:00:00 2001 From: checkroom Date: Tue, 10 Dec 2024 06:59:08 +0000 Subject: [PATCH 1/2] Implementing registration for hooks --- quickjs.c | 13 ++++++++++++- quickjs.h | 8 ++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/quickjs.c b/quickjs.c index 29beb4b2d..198b46a8f 100644 --- a/quickjs.c +++ b/quickjs.c @@ -305,6 +305,9 @@ struct JSRuntime { void *user_opaque; void *libc_opaque; JSRuntimeFinalizerState *finalizers; + + /* Unified handler for all the engine hooks */ + BOOL (*hooks)(JSRuntimeHooks type, void* opaque); }; struct JSClass { @@ -1810,6 +1813,8 @@ JSRuntime *JS_NewRuntime2(const JSMallocFunctions *mf, void *opaque) rt->malloc_state = ms; rt->malloc_gc_threshold = 256 * 1024; + rt->hooks = NULL; + bf_context_init(&rt->bf_ctx, js_bf_realloc, rt); init_list_head(&rt->context_list); @@ -1922,7 +1927,8 @@ void JS_SetDumpFlags(JSRuntime *rt, uint64_t flags) rt->dump_flags = flags; } -size_t JS_GetGCThreshold(JSRuntime *rt) { +size_t JS_GetGCThreshold(JSRuntime *rt) +{ return rt->malloc_gc_threshold; } @@ -1932,6 +1938,11 @@ void JS_SetGCThreshold(JSRuntime *rt, size_t gc_threshold) rt->malloc_gc_threshold = gc_threshold; } +void JS_SetHooksHandler(JSRuntime *rt, BOOL (*fn)(JSRuntimeHooks type, void* opaque)) +{ + rt->hooks = fn; +} + #define malloc(s) malloc_is_forbidden(s) #define free(p) free_is_forbidden(p) #define realloc(p,s) realloc_is_forbidden(p,s) diff --git a/quickjs.h b/quickjs.h index 9e8b5113f..4f3aa755c 100644 --- a/quickjs.h +++ b/quickjs.h @@ -324,6 +324,13 @@ typedef void JSRuntimeFinalizer(JSRuntime *rt, void *arg); typedef struct JSGCObjectHeader JSGCObjectHeader; +/* Engine hooks */ +typedef enum JSRuntimeHooks{ + JS_HOOK_NONE, + JS_HOOK_GC_BEFORE, + JS_HOOK_GC_AFTER, +} JSRuntimeHooks; + JS_EXTERN JSRuntime *JS_NewRuntime(void); /* info lifetime must exceed that of rt */ JS_EXTERN void JS_SetRuntimeInfo(JSRuntime *rt, const char *info); @@ -332,6 +339,7 @@ JS_EXTERN void JS_SetMemoryLimit(JSRuntime *rt, size_t limit); JS_EXTERN void JS_SetDumpFlags(JSRuntime *rt, uint64_t flags); JS_EXTERN size_t JS_GetGCThreshold(JSRuntime *rt); JS_EXTERN void JS_SetGCThreshold(JSRuntime *rt, size_t gc_threshold); +JS_EXTERN void JS_SetHooksHandler(JSRuntime *rt, BOOL (*fn)(JSRuntimeHooks type, void* opaque)); /* use 0 to disable maximum stack size check */ JS_EXTERN void JS_SetMaxStackSize(JSRuntime *rt, size_t stack_size); /* should be called when changing thread to update the stack top value From 4c60f3d3c996882792da7f7351ed32bacbce7df4 Mon Sep 17 00:00:00 2001 From: checkroom Date: Tue, 10 Dec 2024 07:33:55 +0000 Subject: [PATCH 2/2] Implemented hooks for GC --- quickjs.c | 16 +++++++++++++--- quickjs.h | 9 +++++---- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/quickjs.c b/quickjs.c index 198b46a8f..24be798b0 100644 --- a/quickjs.c +++ b/quickjs.c @@ -307,7 +307,7 @@ struct JSRuntime { JSRuntimeFinalizerState *finalizers; /* Unified handler for all the engine hooks */ - BOOL (*hooks)(JSRuntimeHooks type, void* opaque); + JS_BOOL (*hooks)(JSRuntimeHooks type, void* opaque); }; struct JSClass { @@ -1443,7 +1443,17 @@ static void js_trigger_gc(JSRuntime *rt, size_t size) (uint64_t)rt->malloc_state.malloc_size); } #endif - JS_RunGC(rt); + //To ensure JS_RunGC cannot be executed again within callbacks, disable and restore it after. + size_t tmp_threshold = rt->malloc_gc_threshold; + rt->malloc_gc_threshold=-1; + + if((rt->hooks == NULL) || rt->hooks(JS_HOOK_GC_BEFORE,NULL)){ + JS_RunGC(rt); + if(rt->hooks != NULL)rt->hooks(JS_HOOK_GC_AFTER,NULL); + } + + rt->malloc_gc_threshold=tmp_threshold; + rt->malloc_gc_threshold = rt->malloc_state.malloc_size + (rt->malloc_state.malloc_size >> 1); } @@ -1938,7 +1948,7 @@ void JS_SetGCThreshold(JSRuntime *rt, size_t gc_threshold) rt->malloc_gc_threshold = gc_threshold; } -void JS_SetHooksHandler(JSRuntime *rt, BOOL (*fn)(JSRuntimeHooks type, void* opaque)) +void JS_SetHooksHandler(JSRuntime *rt, JS_BOOL (*fn)(JSRuntimeHooks type, void* opaque)) { rt->hooks = fn; } diff --git a/quickjs.h b/quickjs.h index 4f3aa755c..3887875c5 100644 --- a/quickjs.h +++ b/quickjs.h @@ -326,9 +326,9 @@ typedef struct JSGCObjectHeader JSGCObjectHeader; /* Engine hooks */ typedef enum JSRuntimeHooks{ - JS_HOOK_NONE, - JS_HOOK_GC_BEFORE, - JS_HOOK_GC_AFTER, + JS_HOOK_NONE, //Don't use, just to catch potential bugs + JS_HOOK_GC_BEFORE, //Run before a GC event takes place. No payload. Return false if the hooks opposes the GC event to take place. + JS_HOOK_GC_AFTER, //Run after a GC event took place. No payload. Return value ignored. } JSRuntimeHooks; JS_EXTERN JSRuntime *JS_NewRuntime(void); @@ -339,7 +339,8 @@ JS_EXTERN void JS_SetMemoryLimit(JSRuntime *rt, size_t limit); JS_EXTERN void JS_SetDumpFlags(JSRuntime *rt, uint64_t flags); JS_EXTERN size_t JS_GetGCThreshold(JSRuntime *rt); JS_EXTERN void JS_SetGCThreshold(JSRuntime *rt, size_t gc_threshold); -JS_EXTERN void JS_SetHooksHandler(JSRuntime *rt, BOOL (*fn)(JSRuntimeHooks type, void* opaque)); +/* register a hook dispatcher for this runtime. The handler should always return true for hooks which are not supported. */ +JS_EXTERN void JS_SetHooksHandler(JSRuntime *rt, JS_BOOL (*fn)(JSRuntimeHooks type, void* opaque)); /* use 0 to disable maximum stack size check */ JS_EXTERN void JS_SetMaxStackSize(JSRuntime *rt, size_t stack_size); /* should be called when changing thread to update the stack top value