From 74ec3cda8964936aa43e66de95dbfc0ef74dcf70 Mon Sep 17 00:00:00 2001 From: The Armadillo Date: Wed, 8 Jan 2025 19:41:00 -0600 Subject: [PATCH] update to latest --- CMakeLists.txt | 4 -- Makefile | 6 --- cutils.h | 4 -- docs/docs/projects.md | 4 ++ gen/function_source.c | 11 ++-- gen/hello_module.c | 11 ++-- gen/test_fib.c | 11 ++-- libunicode.c | 2 + qjs.c | 116 +++++++++++++++--------------------------- qjsc.c | 11 ++-- quickjs-libc.c | 33 +++++------- quickjs-libc.h | 3 +- quickjs.c | 30 ++++++++++- quickjs.h | 3 ++ repl.js | 6 ++- run-test262.c | 9 ++-- 16 files changed, 117 insertions(+), 147 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 11b2e2c..6420566 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -370,10 +370,6 @@ if(BUILD_EXAMPLES) target_link_libraries(test_fib qjs) endif() -add_executable(test_conv - tests/test_conv.c -) - # Install target # diff --git a/Makefile b/Makefile index ed60cb5..655b37e 100644 --- a/Makefile +++ b/Makefile @@ -58,9 +58,6 @@ $(QJS): $(BUILD_DIR) $(QJSC): $(BUILD_DIR) cmake --build $(BUILD_DIR) --target qjsc -j $(JOBS) -$(BUILD_DIR)/test_conv: $(BUILD_DIR) tests/test_conv.c - cmake --build $(BUILD_DIR) --target test_conv - install: $(QJS) $(QJSC) cmake --build $(BUILD_DIR) --target install @@ -99,9 +96,6 @@ cxxtest: cxxtest.cc quickjs.h test: $(QJS) $(RUN262) -c tests.conf -testconv: $(BUILD_DIR)/test_conv - $(BUILD_DIR)/test_conv - test262: $(QJS) $(RUN262) -m -c test262.conf -a diff --git a/cutils.h b/cutils.h index ea22834..18e6dc5 100644 --- a/cutils.h +++ b/cutils.h @@ -62,10 +62,6 @@ extern "C" { # define __maybe_unused # define __attribute__(x) # define __attribute(x) -# include -static void *__builtin_frame_address(unsigned int level) { - return (void *)((char*)_AddressOfReturnAddress() - sizeof(int *) - level * sizeof(int *)); -} #else # define likely(x) __builtin_expect(!!(x), 1) # define unlikely(x) __builtin_expect(!!(x), 0) diff --git a/docs/docs/projects.md b/docs/docs/projects.md index d499a09..c3cbdc5 100644 --- a/docs/docs/projects.md +++ b/docs/docs/projects.md @@ -26,3 +26,7 @@ JavaScript runtime for Nintendo Switch homebrew applications. ## [quickjs-rusty](https://github.com/Icemic/quickjs-rusty) Rust wrapper focus on embedding-ready and no-pain type conversion and interoperability. + +## [GodotJS](https://github.com/godotjs/GodotJS) + +This project adds TypeScript/JavaScript support for Godot 4.x. It supports multiple javascript runtimes, including QuicJS-NG. diff --git a/gen/function_source.c b/gen/function_source.c index 489dfa2..00b9aab 100644 --- a/gen/function_source.c +++ b/gen/function_source.c @@ -58,7 +58,6 @@ static JSContext *JS_NewCustomContext(JSRuntime *rt) int main(int argc, char **argv) { int r; - JSValue ret; JSRuntime *rt; JSContext *ctx; r = 0; @@ -69,14 +68,12 @@ int main(int argc, char **argv) ctx = JS_NewCustomContext(rt); js_std_add_helpers(ctx, argc, argv); js_std_eval_binary(ctx, qjsc_function_source, qjsc_function_source_size, 0); - ret = js_std_loop(ctx); - if (JS_IsException(ret)) { - js_std_dump_error1(ctx, ret); - r = 1; + r = js_std_loop(ctx); + if (r) { + js_std_dump_error(ctx); } - JS_FreeValue(ctx, ret); - JS_FreeContext(ctx); js_std_free_handlers(rt); + JS_FreeContext(ctx); JS_FreeRuntime(rt); return r; } diff --git a/gen/hello_module.c b/gen/hello_module.c index b6f1470..31987a5 100644 --- a/gen/hello_module.c +++ b/gen/hello_module.c @@ -85,7 +85,6 @@ static JSContext *JS_NewCustomContext(JSRuntime *rt) int main(int argc, char **argv) { int r; - JSValue ret; JSRuntime *rt; JSContext *ctx; r = 0; @@ -96,14 +95,12 @@ int main(int argc, char **argv) ctx = JS_NewCustomContext(rt); js_std_add_helpers(ctx, argc, argv); js_std_eval_binary(ctx, qjsc_hello_module, qjsc_hello_module_size, 0); - ret = js_std_loop(ctx); - if (JS_IsException(ret)) { - js_std_dump_error1(ctx, ret); - r = 1; + r = js_std_loop(ctx); + if (r) { + js_std_dump_error(ctx); } - JS_FreeValue(ctx, ret); - JS_FreeContext(ctx); js_std_free_handlers(rt); + JS_FreeContext(ctx); JS_FreeRuntime(rt); return r; } diff --git a/gen/test_fib.c b/gen/test_fib.c index 2826500..971ee69 100644 --- a/gen/test_fib.c +++ b/gen/test_fib.c @@ -59,7 +59,6 @@ static JSContext *JS_NewCustomContext(JSRuntime *rt) int main(int argc, char **argv) { int r; - JSValue ret; JSRuntime *rt; JSContext *ctx; r = 0; @@ -70,14 +69,12 @@ int main(int argc, char **argv) ctx = JS_NewCustomContext(rt); js_std_add_helpers(ctx, argc, argv); js_std_eval_binary(ctx, qjsc_test_fib, qjsc_test_fib_size, 0); - ret = js_std_loop(ctx); - if (JS_IsException(ret)) { - js_std_dump_error1(ctx, ret); - r = 1; + r = js_std_loop(ctx); + if (r) { + js_std_dump_error(ctx); } - JS_FreeValue(ctx, ret); - JS_FreeContext(ctx); js_std_free_handlers(rt); + JS_FreeContext(ctx); JS_FreeRuntime(rt); return r; } diff --git a/libunicode.c b/libunicode.c index e68b0ca..e880dad 100644 --- a/libunicode.c +++ b/libunicode.c @@ -1542,11 +1542,13 @@ static int unicode_prop_ops(CharRange *cr, ...) } } done: + va_end(ap); assert(stack_len == 1); ret = cr_copy(cr, &stack[0]); cr_free(&stack[0]); return ret; fail: + va_end(ap); for(i = 0; i < stack_len; i++) cr_free(&stack[i]); return -1; diff --git a/qjs.c b/qjs.c index d4061c0..b752303 100644 --- a/qjs.c +++ b/qjs.c @@ -154,33 +154,6 @@ static int eval_file(JSContext *ctx, const char *filename, int module) else eval_flags = JS_EVAL_TYPE_GLOBAL; - - //POLYFILLS FOR QJS FILES BEGIN - const char *pf = "globalThis.global = globalThis;\n" - "global.console.error = console.log\n" - "global.console.warn = console.log\n" - "globalThis.breakFunction = () => { throw new Error('Function Break'); };\n" - "\n" - "if (typeof os !== 'undefined') {\n" - " globalThis.sleep = os.sleep;\n" - " async function setTimeout2(func, ms) {globalThis.clearTimeout = false; await sleep(ms); if (!clearTimeout) { func(); } }\n" - " globalThis.setTimeout = setTimeout2\n" - "} else {\n" - " console.error('os is not defined.');\n" - "}\n" - "\n" - "if (typeof std !== 'undefined') {\n" - " globalThis.urlGet = std.urlGet;\n" - " globalThis.loadFile = std.loadFile;\n" - " globalThis.printf = console.log;\n" - " globalThis.evalFile = std.loadScript;\n" - " globalThis.require = (moduleSpecifier) => import(moduleSpecifier).then(mod => mod.default || mod);\n" - " globalThis.getURL = std.urlGet;\n" - "} else {\n" - " console.error('std is not defined.');\n" - "}\n"; - - eval_buf(ctx, pf, strlen(pf), "", JS_EVAL_TYPE_MODULE); ret = eval_buf(ctx, buf, buf_len, filename, eval_flags); js_free(ctx, buf); return ret; @@ -417,7 +390,6 @@ void help(void) " --exe select the executable to use as the base, defaults to the current one\n" " --memory-limit n limit the memory usage to 'n' Kbytes\n" " --stack-size n limit the stack size to 'n' Kbytes\n" - " --unhandled-rejection dump unhandled promise rejections\n" "-q --quit just instantiate the interpreter and quit\n", JS_GetVersion()); exit(1); } @@ -428,6 +400,7 @@ int main(int argc, char **argv) JSContext *ctx; JSValue ret = JS_UNDEFINED; struct trace_malloc_data trace_data = { NULL }; + int r = 0; int optind = 1; char *compile_file = NULL; char *exe = NULL; @@ -442,7 +415,6 @@ int main(int argc, char **argv) int empty_run = 0; int module = -1; int load_std = 0; - int dump_unhandled_promise_rejection = 0; char *include_list[32]; int i, include_count = 0; int64_t memory_limit = -1; @@ -542,10 +514,6 @@ int main(int argc, char **argv) load_std = 1; continue; } - if (!strcmp(longopt, "unhandled-rejection")) { - dump_unhandled_promise_rejection = 1; - continue; - } if (opt == 'q' || !strcmp(longopt, "quit")) { empty_run++; continue; @@ -650,25 +618,52 @@ start: /* loader for ES6 modules */ JS_SetModuleLoaderFunc(rt, NULL, js_module_loader, NULL); - if (dump_unhandled_promise_rejection) { - JS_SetHostPromiseRejectionTracker(rt, js_std_promise_rejection_tracker, - NULL); - } + /* exit on unhandled promise rejections */ + JS_SetHostPromiseRejectionTracker(rt, js_std_promise_rejection_tracker, NULL); if (!empty_run) { js_std_add_helpers(ctx, argc - optind, argv + optind); - /* make 'std' and 'os' visible to non module code */ - if (load_std) { - const char *str = + //POLYFILLS + const char *pf = "globalThis.global = globalThis;\n" + "global.console.error = console.log\n" + "global.console.warn = console.log\n" + "globalThis.breakFunction = () => { throw new Error('Function Break'); };\n" + "\n" + "if (typeof os !== 'undefined') {\n" + " globalThis.sleep = os.sleep;\n" + " async function setTimeout2(func, ms) {globalThis.clearTimeout = false; await sleep(ms); if (!clearTimeout) { func(); } }\n" + " globalThis.setTimeout = setTimeout2\n" + "} else {\n" + " console.error('os is not defined.');\n" + "}\n" + "\n" + "if (typeof std !== 'undefined') {\n" + " globalThis.urlGet = std.urlGet;\n" + " globalThis.loadFile = std.loadFile;\n" + " globalThis.doneRequire = std.loadScript;\n" + " globalThis.printf = console.log;\n" + " globalThis.evalFile = std.loadScript;\n" + " globalThis.require = (moduleSpecifier) => import(moduleSpecifier).then(mod => mod.default || mod);\n" + " globalThis.stdRequire = globalThis.require;\n" + " globalThis.safeGlobals = {} \n" + " globalThis.getURL = std.urlGet;\n" + "} else {\n" + " console.error('std is not defined.');\n" + "}\n"; + + const char *stdAndOS = "import * as bjson from 'qjs:bjson';\n" "import * as std from 'qjs:std';\n" "import * as os from 'qjs:os';\n" "globalThis.bjson = bjson;\n" "globalThis.std = std;\n" "globalThis.os = os;\n"; - eval_buf(ctx, str, strlen(str), "", JS_EVAL_TYPE_MODULE); - } + + + /* make 'std' 'os' and polyfills visible to non module code */ + eval_buf(ctx, stdAndOS, strlen(stdAndOS), "", JS_EVAL_TYPE_MODULE); + eval_buf(ctx, pf, strlen(pf), "", JS_EVAL_TYPE_MODULE); for(i = 0; i < include_count; i++) { if (eval_file(ctx, include_list[i], 0)) @@ -718,45 +713,18 @@ start: js_std_eval_binary(ctx, qjsc_repl, qjsc_repl_size, 0); } - //POLYFILLS FOR QJS FILES BEGIN - const char *pf = "globalThis.global = globalThis;\n" - "global.console.error = console.log\n" - "global.console.warn = console.log\n" - "globalThis.breakFunction = () => { throw new Error('Function Break'); };\n" - "\n" - "if (typeof os !== 'undefined') {\n" - " globalThis.sleep = os.sleep;\n" - " async function setTimeout2(func, ms) {globalThis.clearTimeout = false; await sleep(ms); if (!clearTimeout) { func(); } }\n" - " globalThis.setTimeout = setTimeout2\n" - "} else {\n" - " console.error('os is not defined.');\n" - "}\n" - "\n" - "if (typeof std !== 'undefined') {\n" - " globalThis.urlGet = std.urlGet;\n" - " globalThis.loadFile = std.loadFile;\n" - " globalThis.printf = console.log;\n" - " globalThis.evalFile = std.loadScript;\n" - " globalThis.require = (moduleSpecifier) => import(moduleSpecifier).then(mod => mod.default || mod);\n" - " globalThis.getURL = std.urlGet;\n" - "} else {\n" - " console.error('std is not defined.');\n" - "}\n"; - eval_buf(ctx, pf, strlen(pf), "", JS_EVAL_TYPE_MODULE); - if (standalone || compile_file) { if (JS_IsException(ret)) { - ret = JS_GetException(ctx); + r = 1; } else { JS_FreeValue(ctx, ret); - ret = js_std_loop(ctx); + r = js_std_loop(ctx); } } else { - ret = js_std_loop(ctx); + r = js_std_loop(ctx); } - if (!JS_IsUndefined(ret)) { - js_std_dump_error1(ctx, ret); - JS_FreeValue(ctx, ret); + if (r) { + js_std_dump_error(ctx); goto fail; } } diff --git a/qjsc.c b/qjsc.c index f5e42a7..3584472 100644 --- a/qjsc.c +++ b/qjsc.c @@ -315,7 +315,6 @@ static const char main_c_template1[] = "int main(int argc, char **argv)\n" "{\n" " int r;\n" - " JSValue ret;\n" " JSRuntime *rt;\n" " JSContext *ctx;\n" " r = 0;\n" @@ -325,14 +324,12 @@ static const char main_c_template1[] = ; static const char main_c_template2[] = - " ret = js_std_loop(ctx);\n" - " if (JS_IsException(ret)) {\n" - " js_std_dump_error1(ctx, ret);\n" - " r = 1;\n" + " r = js_std_loop(ctx);\n" + " if (r) {\n" + " js_std_dump_error(ctx);\n" " }\n" - " JS_FreeValue(ctx, ret);\n" - " JS_FreeContext(ctx);\n" " js_std_free_handlers(rt);\n" + " JS_FreeContext(ctx);\n" " JS_FreeRuntime(rt);\n" " return r;\n" "}\n"; diff --git a/quickjs-libc.c b/quickjs-libc.c index a7b334f..bf03132 100644 --- a/quickjs-libc.c +++ b/quickjs-libc.c @@ -161,7 +161,6 @@ typedef struct JSThreadState { struct list_head port_list; /* list of JSWorkerMessageHandler.link */ int eval_script_recurse; /* only used in the main thread */ int64_t next_timer_id; /* for setTimeout / setInterval */ - JSValue exc; /* current exception from one of our handlers */ BOOL can_js_os_poll; /* not used in the main thread */ JSWorkerMessagePipe *recv_pipe, *send_pipe; @@ -665,9 +664,9 @@ int js_module_set_import_meta(JSContext *ctx, JSValue func_val, if (use_realpath) { char *res = realpath(module_name, buf + strlen(buf)); if (!res) { - JS_ThrowTypeError(ctx, "realpath failure"); - JS_FreeCString(ctx, module_name); - return -1; + // JS_ThrowTypeError(ctx, "realpath failure"); // bugged so disabled + // JS_FreeCString(ctx, module_name); + // return -1; } } else #endif @@ -2274,12 +2273,8 @@ static int call_handler(JSContext *ctx, JSValue func) ret = JS_Call(ctx, func1, JS_UNDEFINED, 0, NULL); JS_FreeValue(ctx, func1); r = 0; - if (JS_IsException(ret)) { - JSRuntime *rt = JS_GetRuntime(ctx); - JSThreadState *ts = js_get_thread_state(rt); - ts->exc = JS_GetException(ctx); + if (JS_IsException(ret)) r = -1; - } JS_FreeValue(ctx, ret); return r; } @@ -3543,10 +3538,10 @@ static void *worker_func(void *opaque) js_std_dump_error(ctx); JS_FreeValue(ctx, val); - JS_FreeValue(ctx, js_std_loop(ctx)); + js_std_loop(ctx); - JS_FreeContext(ctx); js_std_free_handlers(rt); + JS_FreeContext(ctx); JS_FreeRuntime(rt); return NULL; } @@ -4082,7 +4077,6 @@ void js_std_init_handlers(JSRuntime *rt) init_list_head(&ts->port_list); ts->next_timer_id = 1; - ts->exc = JS_UNDEFINED; js_set_thread_state(rt, ts); JS_AddRuntimeFinalizer(rt, js_std_finalize, ts); @@ -4140,7 +4134,7 @@ static void js_dump_obj(JSContext *ctx, FILE *f, JSValue val) } } -void js_std_dump_error1(JSContext *ctx, JSValue exception_val) +static void js_std_dump_error1(JSContext *ctx, JSValue exception_val) { JSValue val; BOOL is_error; @@ -4172,16 +4166,17 @@ void js_std_promise_rejection_tracker(JSContext *ctx, JSValue promise, if (!is_handled) { fprintf(stderr, "Possibly unhandled promise rejection: "); js_std_dump_error1(ctx, reason); + fflush(stderr); + exit(1); } } /* main loop which calls the user JS callbacks */ -JSValue js_std_loop(JSContext *ctx) +int js_std_loop(JSContext *ctx) { JSRuntime *rt = JS_GetRuntime(ctx); JSThreadState *ts = js_get_thread_state(rt); JSContext *ctx1; - JSValue ret; int err; for(;;) { @@ -4189,10 +4184,8 @@ JSValue js_std_loop(JSContext *ctx) for(;;) { err = JS_ExecutePendingJob(JS_GetRuntime(ctx), &ctx1); if (err <= 0) { - if (err < 0) { - ts->exc = JS_GetException(ctx1); + if (err < 0) goto done; - } break; } } @@ -4201,9 +4194,7 @@ JSValue js_std_loop(JSContext *ctx) break; } done: - ret = ts->exc; - ts->exc = JS_UNDEFINED; - return ret; + return JS_HasException(ctx); } /* Wait for a promise and execute pending jobs while waiting for diff --git a/quickjs-libc.h b/quickjs-libc.h index f80cf71..19fad58 100644 --- a/quickjs-libc.h +++ b/quickjs-libc.h @@ -37,12 +37,11 @@ JSModuleDef *js_init_module_std(JSContext *ctx, const char *module_name); JSModuleDef *js_init_module_os(JSContext *ctx, const char *module_name); JSModuleDef *js_init_module_bjson(JSContext *ctx, const char *module_name); void js_std_add_helpers(JSContext *ctx, int argc, char **argv); -JSValue js_std_loop(JSContext *ctx); +int js_std_loop(JSContext *ctx); JSValue js_std_await(JSContext *ctx, JSValue obj); void js_std_init_handlers(JSRuntime *rt); void js_std_free_handlers(JSRuntime *rt); void js_std_dump_error(JSContext *ctx); -void js_std_dump_error1(JSContext *ctx, JSValue exception_val); uint8_t *js_load_file(JSContext *ctx, size_t *pbuf_len, const char *filename); int js_module_set_import_meta(JSContext *ctx, JSValue func_val, JS_BOOL use_realpath, JS_BOOL is_main); diff --git a/quickjs.c b/quickjs.c index 9e53701..0219a3f 100644 --- a/quickjs.c +++ b/quickjs.c @@ -33,6 +33,7 @@ #if !defined(_MSC_VER) #include #if defined(_WIN32) +#include #include #endif #endif @@ -1774,10 +1775,23 @@ static int init_class_range(JSRuntime *rt, JSClassShortDef const *tab, return 0; } -/* Note: OS and CPU dependent */ +/* Uses code from LLVM project. */ static inline uintptr_t js_get_stack_pointer(void) { +#if defined(__clang__) || defined(__GNUC__) return (uintptr_t)__builtin_frame_address(0); +#elif defined(_MSC_VER) + return (uintptr_t)_AddressOfReturnAddress(); +#else + char CharOnStack = 0; + // The volatile store here is intended to escape the local variable, to + // prevent the compiler from optimizing CharOnStack into anything other + // than a char on the stack. + // + // Tested on: MSVC 2015 - 2019, GCC 4.9 - 9, Clang 3.2 - 9, ICC 13 - 19. + char *volatile Ptr = &CharOnStack; + return (uintptr_t) Ptr; +#endif } static inline BOOL js_check_stack_overflow(JSRuntime *rt, size_t alloca_size) @@ -10086,6 +10100,13 @@ BOOL JS_SetConstructorBit(JSContext *ctx, JSValue func_obj, BOOL val) return TRUE; } +JS_BOOL JS_IsRegExp(JSValue val) +{ + if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT) + return FALSE; + return JS_VALUE_GET_OBJ(val)->class_id == JS_CLASS_REGEXP; +} + BOOL JS_IsError(JSContext *ctx, JSValue val) { JSObject *p; @@ -51266,6 +51287,13 @@ JSValue JS_NewDate(JSContext *ctx, double epoch_ms) return obj; } +JS_BOOL JS_IsDate(JSValue v) +{ + if (JS_VALUE_GET_TAG(v) != JS_TAG_OBJECT) + return FALSE; + return JS_VALUE_GET_OBJ(v)->class_id == JS_CLASS_DATE; +} + void JS_AddIntrinsicDate(JSContext *ctx) { JSValue obj; diff --git a/quickjs.h b/quickjs.h index 3ffeede..9709f8f 100644 --- a/quickjs.h +++ b/quickjs.h @@ -672,10 +672,13 @@ JS_EXTERN JS_BOOL JS_IsFunction(JSContext* ctx, JSValue val); JS_EXTERN JS_BOOL JS_IsConstructor(JSContext* ctx, JSValue val); JS_EXTERN JS_BOOL JS_SetConstructorBit(JSContext *ctx, JSValue func_obj, JS_BOOL val); +JS_EXTERN JS_BOOL JS_IsRegExp(JSValue val); + JS_EXTERN JSValue JS_NewArray(JSContext *ctx); JS_EXTERN int JS_IsArray(JSContext *ctx, JSValue val); JS_EXTERN JSValue JS_NewDate(JSContext *ctx, double epoch_ms); +JS_EXTERN JS_BOOL JS_IsDate(JSValue v); JS_EXTERN JSValue JS_GetProperty(JSContext *ctx, JSValue this_obj, JSAtom prop); JS_EXTERN JSValue JS_GetPropertyUint32(JSContext *ctx, JSValue this_obj, diff --git a/repl.js b/repl.js index f50dc3d..c763451 100644 --- a/repl.js +++ b/repl.js @@ -1549,7 +1549,11 @@ import * as bjson from "qjs:bjson"; } mexpr = ""; - eval_and_print(expr); + try { + eval_and_print(expr); + } catch (Exception ex) { + console.log(`Error: $(ex)`) + } return true; } diff --git a/run-test262.c b/run-test262.c index 8261abb..d721d12 100644 --- a/run-test262.c +++ b/run-test262.c @@ -1555,12 +1555,9 @@ static int eval_buf(JSContext *ctx, const char *buf, size_t buf_len, } if (local) { - JSValue val = js_std_loop(ctx); - if (JS_IsException(val)) { - js_std_dump_error1(ctx, val); - ret = -1; - } - JS_FreeValue(ctx, val); + ret = js_std_loop(ctx); + if (ret) + js_std_dump_error(ctx); } JS_FreeCString(ctx, error_name);