From 9b5dda0e76cd2afb52b4d32f495063d877743578 Mon Sep 17 00:00:00 2001 From: karurochari Date: Thu, 16 May 2024 02:31:15 +0000 Subject: [PATCH 1/6] Added more control over the GC events, and callbacks before the event --- quickjs.c | 3 +++ quickjs.h | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/quickjs.c b/quickjs.c index 57e907eca..224f67aa6 100644 --- a/quickjs.c +++ b/quickjs.c @@ -241,6 +241,9 @@ struct JSRuntime { struct list_head tmp_obj_list; /* used during GC */ JSGCPhaseEnum gc_phase : 8; size_t malloc_gc_threshold; + BOOL malloc_gc_fix_threshold : 8; + BOOL (*malloc_gc_before_callback)(); + void (*malloc_gc_after_callback)(); #ifdef DUMP_LEAKS struct list_head string_list; /* list of JSString.link */ #endif diff --git a/quickjs.h b/quickjs.h index cb5d52803..5a828dddd 100644 --- a/quickjs.h +++ b/quickjs.h @@ -302,6 +302,10 @@ JS_EXTERN void JS_SetRuntimeInfo(JSRuntime *rt, const char *info); JS_EXTERN void JS_SetMemoryLimit(JSRuntime *rt, size_t limit); JS_EXTERN void JS_SetDumpFlags(JSRuntime *rt, uint64_t flags); JS_EXTERN void JS_SetGCThreshold(JSRuntime *rt, size_t gc_threshold); +JS_EXTERN size_t JS_GetGCThreshold(JSRuntime *rt); +JS_EXTERN void JS_SetGCThresholdFixed(JSRuntime *rt, BOOL fixed); +JS_EXTERN void JS_SetGCBeforeCallback(JSRuntime *rt, BOOL(*fn)()); +JS_EXTERN void JS_SetGCAfterCallback(JSRuntime *rt, void(*fn)()); /* 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 e2539acad844c3559e4afed6cf9782fe7026bb7c Mon Sep 17 00:00:00 2001 From: karurochari Date: Thu, 16 May 2024 02:34:09 +0000 Subject: [PATCH 2/6] fixed bool --- quickjs.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/quickjs.h b/quickjs.h index 5a828dddd..56c8ff599 100644 --- a/quickjs.h +++ b/quickjs.h @@ -303,8 +303,8 @@ JS_EXTERN void JS_SetMemoryLimit(JSRuntime *rt, size_t limit); JS_EXTERN void JS_SetDumpFlags(JSRuntime *rt, uint64_t flags); JS_EXTERN void JS_SetGCThreshold(JSRuntime *rt, size_t gc_threshold); JS_EXTERN size_t JS_GetGCThreshold(JSRuntime *rt); -JS_EXTERN void JS_SetGCThresholdFixed(JSRuntime *rt, BOOL fixed); -JS_EXTERN void JS_SetGCBeforeCallback(JSRuntime *rt, BOOL(*fn)()); +JS_EXTERN void JS_SetGCThresholdFixed(JSRuntime *rt, JS_BOOL fixed); +JS_EXTERN void JS_SetGCBeforeCallback(JSRuntime *rt, JS_BOOL (*fn)()); JS_EXTERN void JS_SetGCAfterCallback(JSRuntime *rt, void(*fn)()); /* use 0 to disable maximum stack size check */ JS_EXTERN void JS_SetMaxStackSize(JSRuntime *rt, size_t stack_size); From 13e01ea5ab58027e870e2e133b04e8e7dc258cca Mon Sep 17 00:00:00 2001 From: karurochari Date: Thu, 16 May 2024 03:17:31 +0000 Subject: [PATCH 3/6] Somehow it was not saved --- quickjs.c | 98 ++++++++++++++++++++++++++++++++----------------------- quickjs.h | 5 +-- 2 files changed, 61 insertions(+), 42 deletions(-) diff --git a/quickjs.c b/quickjs.c index 224f67aa6..03a2c7b22 100644 --- a/quickjs.c +++ b/quickjs.c @@ -1357,9 +1357,21 @@ static void js_trigger_gc(JSRuntime *rt, size_t size) (uint64_t)rt->malloc_state.malloc_size); } #endif - JS_RunGC(rt); - rt->malloc_gc_threshold = rt->malloc_state.malloc_size + - (rt->malloc_state.malloc_size >> 1); + //To ensure JS_RunGC cannot be executed again within callbacks. + size_t tmp_threshold = rt->malloc_gc_threshold; + rt->malloc_gc_threshold=-1; + + if((rt->malloc_gc_before_callback == NULL) || rt->malloc_gc_before_callback()){ + JS_RunGC(rt); + if(rt->malloc_gc_after_callback != NULL)rt->malloc_gc_after_callback(); + } + + rt->malloc_gc_threshold=tmp_threshold; + + if(rt->malloc_gc_fix_threshold == FALSE) { + rt->malloc_gc_threshold = rt->malloc_state.malloc_size + + (rt->malloc_state.malloc_size >> 1); + } } } @@ -1626,6 +1638,10 @@ JSRuntime *JS_NewRuntime2(const JSMallocFunctions *mf, void *opaque) rt->malloc_state = ms; rt->malloc_gc_threshold = 256 * 1024; + rt->malloc_gc_fix_threshold = FALSE; + rt->malloc_gc_after_callback = NULL; + rt->malloc_gc_before_callback = NULL; + bf_context_init(&rt->bf_ctx, js_bf_realloc, rt); init_list_head(&rt->context_list); @@ -1768,6 +1784,28 @@ void JS_SetGCThreshold(JSRuntime *rt, size_t gc_threshold) rt->malloc_gc_threshold = gc_threshold; } +size_t JS_GetGCThreshold(JSRuntime *rt) +{ + return rt->malloc_gc_threshold; +} + +void JS_SetGCThresholdFixed(JSRuntime *rt, BOOL fix) +{ + rt->malloc_gc_fix_threshold = fix; +} + + +void JS_SetGCBeforeCallback(JSRuntime *rt, BOOL(*fn)()) +{ + rt->malloc_gc_before_callback = fn; +} + +void JS_SetGCAfterCallback(JSRuntime *rt, void(*fn)()) +{ + rt->malloc_gc_after_callback = fn; +} + + #define malloc(s) malloc_is_forbidden(s) #define free(p) free_is_forbidden(p) #define realloc(p,s) realloc_is_forbidden(p,s) @@ -6638,7 +6676,7 @@ static JSValue JS_ThrowError2(JSContext *ctx, JSErrorEnum error_num, const char *fmt, va_list ap, BOOL add_backtrace) { char buf[256]; - JSValue obj, ret, msg; + JSValue obj, ret; vsnprintf(buf, sizeof(buf), fmt, ap); obj = JS_NewObjectProtoClass(ctx, ctx->native_error_proto[error_num], @@ -6647,13 +6685,9 @@ static JSValue JS_ThrowError2(JSContext *ctx, JSErrorEnum error_num, /* out of memory: throw JS_NULL to avoid recursing */ obj = JS_NULL; } else { - msg = JS_NewString(ctx, buf); - if (JS_IsException(msg)) - msg = JS_NewString(ctx, "Invalid error message"); - if (!JS_IsException(msg)) { - JS_DefinePropertyValue(ctx, obj, JS_ATOM_message, msg, - JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); - } + JS_DefinePropertyValue(ctx, obj, JS_ATOM_message, + JS_NewString(ctx, buf), + JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); } if (add_backtrace) { build_backtrace(ctx, obj, NULL, 0, 0, 0); @@ -18640,33 +18674,11 @@ int __attribute__((format(printf, 2, 3))) js_parse_error(JSParseState *s, const static int js_parse_expect(JSParseState *s, int tok) { - char buf[ATOM_GET_STR_BUF_SIZE]; - - if (s->token.val == tok) - return next_token(s); - - switch(s->token.val) { - case TOK_EOF: - return js_parse_error(s, "Unexpected end of input"); - case TOK_NUMBER: - return js_parse_error(s, "Unexpected number"); - case TOK_STRING: - return js_parse_error(s, "Unexpected string"); - case TOK_TEMPLATE: - return js_parse_error(s, "Unexpected string template"); - case TOK_REGEXP: - return js_parse_error(s, "Unexpected regexp"); - case TOK_IDENT: - return js_parse_error(s, "Unexpected identifier '%s'", - JS_AtomGetStr(s->ctx, buf, sizeof(buf), - s->token.u.ident.atom)); - case TOK_ERROR: - return js_parse_error(s, "Invalid or unexpected token"); - default: - return js_parse_error(s, "Unexpected token '%.*s'", - (int)(s->buf_ptr - s->token.ptr), - (const char *)s->token.ptr); + if (s->token.val != tok) { + /* XXX: dump token correctly in all cases */ + return js_parse_error(s, "expecting '%c'", tok); } + return next_token(s); } static int js_parse_expect_semi(JSParseState *s) @@ -20840,7 +20852,7 @@ static int __exception js_parse_property_name(JSParseState *s, goto fail1; if (s->token.val == ':' || s->token.val == ',' || s->token.val == '}' || s->token.val == '(' || - s->token.val == '=' ) { + s->token.val == '=') { is_non_reserved_ident = TRUE; goto ident_found; } @@ -20856,7 +20868,8 @@ static int __exception js_parse_property_name(JSParseState *s, if (next_token(s)) goto fail1; if (s->token.val == ':' || s->token.val == ',' || - s->token.val == '}' || s->token.val == '(') { + s->token.val == '}' || s->token.val == '(' || + s->token.val == '=') { is_non_reserved_ident = TRUE; goto ident_found; } @@ -21612,7 +21625,12 @@ static __exception int js_parse_class(JSParseState *s, BOOL is_class_expr, goto fail; continue; } - is_static = (s->token.val == TOK_STATIC); + is_static = FALSE; + if (s->token.val == TOK_STATIC) { + int next = peek_token(s, TRUE); + if (!(next == ';' || next == '}' || next == '(' || next == '=')) + is_static = TRUE; + } prop_type = -1; if (is_static) { if (next_token(s)) diff --git a/quickjs.h b/quickjs.h index 56c8ff599..632d39969 100644 --- a/quickjs.h +++ b/quickjs.h @@ -303,9 +303,10 @@ JS_EXTERN void JS_SetMemoryLimit(JSRuntime *rt, size_t limit); JS_EXTERN void JS_SetDumpFlags(JSRuntime *rt, uint64_t flags); JS_EXTERN void JS_SetGCThreshold(JSRuntime *rt, size_t gc_threshold); JS_EXTERN size_t JS_GetGCThreshold(JSRuntime *rt); -JS_EXTERN void JS_SetGCThresholdFixed(JSRuntime *rt, JS_BOOL fixed); -JS_EXTERN void JS_SetGCBeforeCallback(JSRuntime *rt, JS_BOOL (*fn)()); +JS_EXTERN void JS_SetGCThresholdFixed(JSRuntime *rt, BOOL fixed); +JS_EXTERN void JS_SetGCBeforeCallback(JSRuntime *rt, BOOL(*fn)()); JS_EXTERN void JS_SetGCAfterCallback(JSRuntime *rt, void(*fn)()); + /* 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 e09c4eac72b8810724ca7a65b89cdd943a9ac661 Mon Sep 17 00:00:00 2001 From: karurochari Date: Thu, 16 May 2024 03:18:33 +0000 Subject: [PATCH 4/6] fixed bool --- quickjs.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/quickjs.h b/quickjs.h index 632d39969..e75cae501 100644 --- a/quickjs.h +++ b/quickjs.h @@ -303,8 +303,8 @@ JS_EXTERN void JS_SetMemoryLimit(JSRuntime *rt, size_t limit); JS_EXTERN void JS_SetDumpFlags(JSRuntime *rt, uint64_t flags); JS_EXTERN void JS_SetGCThreshold(JSRuntime *rt, size_t gc_threshold); JS_EXTERN size_t JS_GetGCThreshold(JSRuntime *rt); -JS_EXTERN void JS_SetGCThresholdFixed(JSRuntime *rt, BOOL fixed); -JS_EXTERN void JS_SetGCBeforeCallback(JSRuntime *rt, BOOL(*fn)()); +JS_EXTERN void JS_SetGCThresholdFixed(JSRuntime *rt, JS_BOOL fixed); +JS_EXTERN void JS_SetGCBeforeCallback(JSRuntime *rt, JS_BOOL(*fn)()); JS_EXTERN void JS_SetGCAfterCallback(JSRuntime *rt, void(*fn)()); /* use 0 to disable maximum stack size check */ From 5247ff3b62c82cbbf8bd1e9744da09efa6b8200e Mon Sep 17 00:00:00 2001 From: karurochari Date: Thu, 16 May 2024 03:25:17 +0000 Subject: [PATCH 5/6] Now it is fixed! --- quickjs.c | 55 +++++++++++++++++++++++++++++++++++++------------------ quickjs.h | 1 - 2 files changed, 37 insertions(+), 19 deletions(-) diff --git a/quickjs.c b/quickjs.c index 03a2c7b22..8b37ef12f 100644 --- a/quickjs.c +++ b/quickjs.c @@ -1805,7 +1805,6 @@ void JS_SetGCAfterCallback(JSRuntime *rt, void(*fn)()) rt->malloc_gc_after_callback = fn; } - #define malloc(s) malloc_is_forbidden(s) #define free(p) free_is_forbidden(p) #define realloc(p,s) realloc_is_forbidden(p,s) @@ -6676,7 +6675,7 @@ static JSValue JS_ThrowError2(JSContext *ctx, JSErrorEnum error_num, const char *fmt, va_list ap, BOOL add_backtrace) { char buf[256]; - JSValue obj, ret; + JSValue obj, ret, msg; vsnprintf(buf, sizeof(buf), fmt, ap); obj = JS_NewObjectProtoClass(ctx, ctx->native_error_proto[error_num], @@ -6685,9 +6684,13 @@ static JSValue JS_ThrowError2(JSContext *ctx, JSErrorEnum error_num, /* out of memory: throw JS_NULL to avoid recursing */ obj = JS_NULL; } else { - JS_DefinePropertyValue(ctx, obj, JS_ATOM_message, - JS_NewString(ctx, buf), - JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); + msg = JS_NewString(ctx, buf); + if (JS_IsException(msg)) + msg = JS_NewString(ctx, "Invalid error message"); + if (!JS_IsException(msg)) { + JS_DefinePropertyValue(ctx, obj, JS_ATOM_message, msg, + JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); + } } if (add_backtrace) { build_backtrace(ctx, obj, NULL, 0, 0, 0); @@ -18674,11 +18677,33 @@ int __attribute__((format(printf, 2, 3))) js_parse_error(JSParseState *s, const static int js_parse_expect(JSParseState *s, int tok) { - if (s->token.val != tok) { - /* XXX: dump token correctly in all cases */ - return js_parse_error(s, "expecting '%c'", tok); + char buf[ATOM_GET_STR_BUF_SIZE]; + + if (s->token.val == tok) + return next_token(s); + + switch(s->token.val) { + case TOK_EOF: + return js_parse_error(s, "Unexpected end of input"); + case TOK_NUMBER: + return js_parse_error(s, "Unexpected number"); + case TOK_STRING: + return js_parse_error(s, "Unexpected string"); + case TOK_TEMPLATE: + return js_parse_error(s, "Unexpected string template"); + case TOK_REGEXP: + return js_parse_error(s, "Unexpected regexp"); + case TOK_IDENT: + return js_parse_error(s, "Unexpected identifier '%s'", + JS_AtomGetStr(s->ctx, buf, sizeof(buf), + s->token.u.ident.atom)); + case TOK_ERROR: + return js_parse_error(s, "Invalid or unexpected token"); + default: + return js_parse_error(s, "Unexpected token '%.*s'", + (int)(s->buf_ptr - s->token.ptr), + (const char *)s->token.ptr); } - return next_token(s); } static int js_parse_expect_semi(JSParseState *s) @@ -20852,7 +20877,7 @@ static int __exception js_parse_property_name(JSParseState *s, goto fail1; if (s->token.val == ':' || s->token.val == ',' || s->token.val == '}' || s->token.val == '(' || - s->token.val == '=') { + s->token.val == '=' ) { is_non_reserved_ident = TRUE; goto ident_found; } @@ -20868,8 +20893,7 @@ static int __exception js_parse_property_name(JSParseState *s, if (next_token(s)) goto fail1; if (s->token.val == ':' || s->token.val == ',' || - s->token.val == '}' || s->token.val == '(' || - s->token.val == '=') { + s->token.val == '}' || s->token.val == '(') { is_non_reserved_ident = TRUE; goto ident_found; } @@ -21625,12 +21649,7 @@ static __exception int js_parse_class(JSParseState *s, BOOL is_class_expr, goto fail; continue; } - is_static = FALSE; - if (s->token.val == TOK_STATIC) { - int next = peek_token(s, TRUE); - if (!(next == ';' || next == '}' || next == '(' || next == '=')) - is_static = TRUE; - } + is_static = (s->token.val == TOK_STATIC); prop_type = -1; if (is_static) { if (next_token(s)) diff --git a/quickjs.h b/quickjs.h index e75cae501..7e98628ea 100644 --- a/quickjs.h +++ b/quickjs.h @@ -306,7 +306,6 @@ JS_EXTERN size_t JS_GetGCThreshold(JSRuntime *rt); JS_EXTERN void JS_SetGCThresholdFixed(JSRuntime *rt, JS_BOOL fixed); JS_EXTERN void JS_SetGCBeforeCallback(JSRuntime *rt, JS_BOOL(*fn)()); JS_EXTERN void JS_SetGCAfterCallback(JSRuntime *rt, void(*fn)()); - /* 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 b0e977cee76b7e3a5e3180c21b272a59b8d5c9df Mon Sep 17 00:00:00 2001 From: karurochari Date: Mon, 10 Jun 2024 07:49:30 +0000 Subject: [PATCH 6/6] Renamed variables, fixed code to work with latest changes in main --- quickjs.c | 31 +++++++++++++------------------ quickjs.h | 5 ++--- 2 files changed, 15 insertions(+), 21 deletions(-) diff --git a/quickjs.c b/quickjs.c index 66a153fdd..bed806d42 100644 --- a/quickjs.c +++ b/quickjs.c @@ -237,9 +237,9 @@ struct JSRuntime { struct list_head tmp_obj_list; /* used during GC */ JSGCPhaseEnum gc_phase : 8; size_t malloc_gc_threshold; - BOOL malloc_gc_fix_threshold : 8; - BOOL (*malloc_gc_before_callback)(); - void (*malloc_gc_after_callback)(); + BOOL fix_malloc_gc_threshold : 8; + BOOL (*gc_before_callback)(); /* Callback before the gc event takes place */ + void (*gc_after_callback)(); /* Callback after the gc event takes place */ #ifdef DUMP_LEAKS struct list_head string_list; /* list of JSString.link */ #endif @@ -1365,18 +1365,18 @@ static void js_trigger_gc(JSRuntime *rt, size_t size) (uint64_t)rt->malloc_state.malloc_size); } #endif - //To ensure JS_RunGC cannot be executed again within callbacks. + //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->malloc_gc_before_callback == NULL) || rt->malloc_gc_before_callback()){ + if((rt->gc_before_callback == NULL) || rt->gc_before_callback()){ JS_RunGC(rt); - if(rt->malloc_gc_after_callback != NULL)rt->malloc_gc_after_callback(); + if(rt->gc_after_callback != NULL)rt->gc_after_callback(); } rt->malloc_gc_threshold=tmp_threshold; - if(rt->malloc_gc_fix_threshold == FALSE) { + if(rt->fix_malloc_gc_threshold == FALSE) { rt->malloc_gc_threshold = rt->malloc_state.malloc_size + (rt->malloc_state.malloc_size >> 1); } @@ -1646,9 +1646,9 @@ JSRuntime *JS_NewRuntime2(const JSMallocFunctions *mf, void *opaque) rt->malloc_state = ms; rt->malloc_gc_threshold = 256 * 1024; - rt->malloc_gc_fix_threshold = FALSE; - rt->malloc_gc_after_callback = NULL; - rt->malloc_gc_before_callback = NULL; + rt->fix_malloc_gc_threshold = FALSE; + rt->gc_after_callback = NULL; + rt->gc_before_callback = NULL; bf_context_init(&rt->bf_ctx, js_bf_realloc, rt); @@ -1796,25 +1796,20 @@ void JS_SetGCThreshold(JSRuntime *rt, size_t gc_threshold) rt->malloc_gc_threshold = gc_threshold; } -size_t JS_GetGCThreshold(JSRuntime *rt) -{ - return rt->malloc_gc_threshold; -} - void JS_SetGCThresholdFixed(JSRuntime *rt, BOOL fix) { - rt->malloc_gc_fix_threshold = fix; + rt->fix_malloc_gc_threshold = fix; } void JS_SetGCBeforeCallback(JSRuntime *rt, BOOL(*fn)()) { - rt->malloc_gc_before_callback = fn; + rt->gc_before_callback = fn; } void JS_SetGCAfterCallback(JSRuntime *rt, void(*fn)()) { - rt->malloc_gc_after_callback = fn; + rt->gc_after_callback = fn; } #define malloc(s) malloc_is_forbidden(s) diff --git a/quickjs.h b/quickjs.h index 38129ee99..d5c3befc0 100644 --- a/quickjs.h +++ b/quickjs.h @@ -307,10 +307,9 @@ 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 size_t JS_GetGCThreshold(JSRuntime *rt); JS_EXTERN void JS_SetGCThresholdFixed(JSRuntime *rt, JS_BOOL fixed); -JS_EXTERN void JS_SetGCBeforeCallback(JSRuntime *rt, JS_BOOL(*fn)()); -JS_EXTERN void JS_SetGCAfterCallback(JSRuntime *rt, void(*fn)()); +JS_EXTERN void JS_SetGCBeforeCallback(JSRuntime *rt, JS_BOOL(*cb)()); +JS_EXTERN void JS_SetGCAfterCallback(JSRuntime *rt, void(*cb)()); /* 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