update to latest
Some checks are pending
ci / Linux (Ubuntu) (push) Waiting to run
ci / linux-asan (push) Waiting to run
ci / linux-msan (push) Waiting to run
ci / linux-ubsan (push) Waiting to run
ci / macOS (push) Waiting to run
ci / macos-asan (push) Waiting to run
ci / macos-ubsan (push) Waiting to run
ci / freebsd (push) Waiting to run
ci / qemu-alpine (arm32v6) (push) Waiting to run
ci / qemu-alpine (arm32v7) (push) Waiting to run
ci / qemu-alpine (arm64v8) (push) Waiting to run
ci / qemu-alpine (i386) (push) Waiting to run
ci / qemu-alpine (s390x) (push) Waiting to run

This commit is contained in:
Arma-Damna-Dillo 2025-01-08 19:41:00 -06:00
parent bad2bdc661
commit 74ec3cda89
16 changed files with 117 additions and 147 deletions

View file

@ -370,10 +370,6 @@ if(BUILD_EXAMPLES)
target_link_libraries(test_fib qjs)
endif()
add_executable(test_conv
tests/test_conv.c
)
# Install target
#

View file

@ -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

View file

@ -62,10 +62,6 @@ extern "C" {
# define __maybe_unused
# define __attribute__(x)
# define __attribute(x)
# include <intrin.h>
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)

View file

@ -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.

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;

116
qjs.c
View file

@ -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), "<input>", 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), "<input>", JS_EVAL_TYPE_MODULE);
}
/* make 'std' 'os' and polyfills visible to non module code */
eval_buf(ctx, stdAndOS, strlen(stdAndOS), "<input>", JS_EVAL_TYPE_MODULE);
eval_buf(ctx, pf, strlen(pf), "<input>", 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), "<input>", 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;
}
}

11
qjsc.c
View file

@ -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";

View file

@ -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

View file

@ -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);

View file

@ -33,6 +33,7 @@
#if !defined(_MSC_VER)
#include <sys/time.h>
#if defined(_WIN32)
#include <intrin.h>
#include <timezoneapi.h>
#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;

View file

@ -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,

View file

@ -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;
}

View file

@ -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);