Compare commits

4 Commits
mmmm ... master

Author SHA1 Message Date
John Alanbrook
86e653f592 remove mcmodel large
Some checks failed
ci / Linux (Ubuntu) (push) Failing after 1s
ci / macOS (push) Failing after 8s
ci / macos-asan (push) Failing after 6s
ci / macos-ubsan (push) Failing after 4s
ci / linux-asan (push) Failing after 11s
ci / Linux LTO (push) Failing after 9s
ci / Linux 32bit (push) Failing after 3s
ci / Windows (mingw) (push) Failing after 3s
ci / linux-ubsan (push) Failing after 31s
ci / freebsd (push) Failing after 1m31s
ci / Cosmopolitan (push) Successful in 57s
ci / MinGW Windows target (push) Failing after 3s
ci / qemu-alpine (linux/386) (push) Failing after 4s
ci / qemu-alpine (linux/arm/v6) (push) Failing after 3s
ci / qemu-alpine (linux/arm/v7) (push) Failing after 4s
ci / qemu-alpine (linux/arm64) (push) Failing after 4s
ci / qemu-alpine (linux/ppc64le) (push) Failing after 4s
ci / qemu-alpine (linux/riscv64) (push) Failing after 4s
ci / qemu-alpine (linux/s390x) (push) Failing after 4s
ci / Windows MSYS2 (push) Has been cancelled
2025-05-24 09:28:56 -05:00
John Alanbrook
8cffc76604 update meson build test suite
Some checks failed
ci / Linux (Ubuntu) (push) Failing after 0s
ci / linux-asan (push) Failing after 1s
ci / macOS (push) Failing after 3s
ci / macos-asan (push) Failing after 3s
ci / macos-ubsan (push) Failing after 3s
ci / Linux LTO (push) Failing after 30s
ci / Linux 32bit (push) Failing after 3s
ci / Windows (mingw) (push) Failing after 2s
ci / linux-ubsan (push) Failing after 28s
ci / Cosmopolitan (push) Has been cancelled
ci / MinGW Windows target (push) Has been cancelled
ci / Windows MSYS2 (push) Has been cancelled
ci / qemu-alpine (linux/386) (push) Has been cancelled
ci / qemu-alpine (linux/arm/v6) (push) Has been cancelled
ci / qemu-alpine (linux/arm/v7) (push) Has been cancelled
ci / qemu-alpine (linux/arm64) (push) Has been cancelled
ci / qemu-alpine (linux/ppc64le) (push) Has been cancelled
ci / qemu-alpine (linux/riscv64) (push) Has been cancelled
ci / qemu-alpine (linux/s390x) (push) Has been cancelled
ci / freebsd (push) Has been cancelled
2025-05-05 13:10:04 -05:00
John Alanbrook
4908cc5c62 fix clash with VERSION and new C++ header <version> on macos
Some checks failed
ci / Windows MSYS2 (push) Waiting to run
ci / Linux (Ubuntu) (push) Failing after 0s
ci / Linux 32bit (push) Failing after 3s
ci / linux-asan (push) Failing after 3s
ci / Windows (mingw) (push) Failing after 3s
ci / MinGW Windows target (push) Failing after 4s
ci / Linux LTO (push) Failing after 19s
ci / qemu-alpine (linux/386) (push) Failing after 5s
ci / qemu-alpine (linux/arm/v6) (push) Failing after 5s
ci / qemu-alpine (linux/arm/v7) (push) Failing after 4s
ci / qemu-alpine (linux/arm64) (push) Failing after 4s
ci / qemu-alpine (linux/ppc64le) (push) Failing after 4s
ci / qemu-alpine (linux/riscv64) (push) Failing after 4s
ci / qemu-alpine (linux/s390x) (push) Failing after 4s
ci / linux-ubsan (push) Failing after 34s
ci / Cosmopolitan (push) Successful in 1m2s
ci / freebsd (push) Failing after 12m7s
ci / macOS (push) Failing after 4s
ci / macos-asan (push) Failing after 3s
ci / macos-ubsan (push) Failing after 3s
2025-05-05 09:13:36 -05:00
John Alanbrook
ab8b09f183 fix up post merge
Some checks failed
ci / Linux (Ubuntu) (push) Failing after 0s
ci / linux-asan (push) Failing after 25s
ci / Linux 32bit (push) Failing after 3s
ci / Windows (mingw) (push) Failing after 3s
ci / MinGW Windows target (push) Failing after 3s
ci / qemu-alpine (linux/386) (push) Failing after 4s
ci / Linux LTO (push) Failing after 19s
ci / qemu-alpine (linux/arm/v6) (push) Failing after 4s
ci / qemu-alpine (linux/arm/v7) (push) Failing after 4s
ci / qemu-alpine (linux/arm64) (push) Failing after 4s
ci / qemu-alpine (linux/ppc64le) (push) Failing after 4s
ci / qemu-alpine (linux/riscv64) (push) Failing after 4s
ci / qemu-alpine (linux/s390x) (push) Failing after 4s
ci / macOS (push) Has been cancelled
ci / macos-asan (push) Has been cancelled
ci / macos-ubsan (push) Has been cancelled
ci / Windows MSYS2 (push) Has been cancelled
ci / linux-ubsan (push) Has been cancelled
ci / freebsd (push) Has been cancelled
ci / Cosmopolitan (push) Has been cancelled
2025-05-01 12:41:40 -05:00
4 changed files with 282 additions and 34 deletions

View File

@@ -147,7 +147,7 @@ CFLAGS+=-fwrapv # ensure that signed overflows behave as expected
ifdef CONFIG_WERROR
CFLAGS+=-Werror
endif
DEFINES:=-D_GNU_SOURCE -DCONFIG_VERSION=\"$(shell cat VERSION)\"
DEFINES:=-D_GNU_SOURCE -DCONFIG_VERSION=\"$(shell cat VERSION.md)\"
ifdef CONFIG_WIN32
DEFINES+=-D__USE_MINGW_ANSI_STDIO # for standard snprintf behavior
endif
@@ -423,7 +423,7 @@ build_doc: $(DOCS)
clean_doc:
rm -f $(DOCS)
doc/version.texi: VERSION
doc/version.texi: VERSION.md
@echo "@set VERSION `cat $<`" > $@
doc/%.pdf: doc/%.texi doc/version.texi

View File

View File

@@ -1,4 +1,4 @@
project('quickjs', 'c')
project('quickjs', 'c', meson_version: '>=1.1')
cc = meson.get_compiler('c')
@@ -8,13 +8,14 @@ deps = []
deps += cc.find_library('m', required:false)
deps += threads
add_project_arguments('-DCONFIG_VERSION="2024-02-14"', '-mcmodel=large', language: 'c')
fs = import('fs')
if get_option('bignum')
add_project_arguments('-DCONFIG_BIGNUM', language : 'c')
endif
ver_file = join_paths(meson.current_source_dir(), 'VERSION.md')
qjs_ver = fs.read(ver_file).strip()
lib_sources = ['libbf.c', 'libregexp.c', 'quickjs.c', 'libunicode.c', 'cutils.c']
add_project_arguments('-DCONFIG_VERSION="@0@"'.format(qjs_ver), language: 'c')
lib_sources = ['libregexp.c', 'quickjs.c', 'libunicode.c', 'cutils.c', 'dtoa.c']
libquickjs = library('quickjs',
lib_sources,
@@ -29,22 +30,15 @@ qjsc = executable('qjsc',
build_by_default:false
)
qjscalc_c = custom_target(
'qjscalc_c',
output: 'qjscalc.c',
input: 'qjscalc.js',
command: [qjsc, '-fbignum', '-c', '-o', '@OUTPUT@', '@INPUT@'],
)
qjsrepl_c = custom_target(
'qjsrepl_c',
output: 'repl.c',
input: 'repl.js',
command: [qjsc, '-fbignum', '-c', '-o', '@OUTPUT@', '-m', '@INPUT@'],
command: [qjsc, '-c', '-o', '@OUTPUT@', '-m', '@INPUT@'],
)
qjs = executable('qjs',
'qjs.c', 'quickjs-libc.c', qjscalc_c, qjsrepl_c,
'qjs.c', 'quickjs-libc.c', qjsrepl_c,
dependencies: [quickjs_dep, threads],
build_by_default:false
)
@@ -55,22 +49,11 @@ base_tests = {
'closure': ['test_closure.js'],
'language': ['test_language.js'],
'loop': ['test_loop.js'],
'op_overloading': ['--bignum', 'test_op_overloading.js'],
'bignum': ['--bignum', 'test_bignum.js'],
'qjscalc': ['--qjscalc', 'test_qjscalc.js']
'bigint': ['test_bigint.js'],
}
test_suite = base_tests
is_windows = host_machine.system() == 'windows'
if not is_windows
test_suite += {
'builtin': ['test_builtin.js'],
'std': ['test_std.js'],
'worker': ['test_worker.js']
}
endif
foreach test_name, test_args : test_suite
test(test_name, qjs, args: test_args, workdir: test_root)
endforeach

275
quickjs.c
View File

@@ -13243,8 +13243,6 @@ static __maybe_unused void JS_DumpObject(FILE *fp, JSRuntime *rt, JSObject *p)
static __maybe_unused void JS_DumpGCObject(FILE *fp, JSRuntime *rt, JSGCObjectHeader *p)
{
struct gc_object obj;
if (p->gc_obj_type == JS_GC_OBJ_TYPE_JS_OBJECT) {
JS_DumpObject(fp, rt, (JSObject *)p);
} else {
@@ -13423,7 +13421,8 @@ int JS_ArrayLength(JSContext *ctx, JSValueConst val)
JSObject *p = JS_VALUE_GET_OBJ(val);
if (p->class_id != JS_CLASS_ARRAY) return 0;
uint32_t len;
js_get_length32(ctx, &len, val);
if (js_get_length32(ctx, &len, val))
return 0;
return len;
}
@@ -54977,7 +54976,7 @@ void js_debug_info(JSContext *js, JSValue fn, js_debug *dbg)
if (!JS_IsObject(fn)) return;
JSObject *p = JS_VALUE_GET_OBJ(fn);
char *fn_name = get_func_name(js,fn);
const char *fn_name = get_func_name(js,fn);
if (!fn_name || fn_name[0] == 0)
dbg->name = js_strdup(js, "<anonymous>");
@@ -54992,7 +54991,7 @@ void js_debug_info(JSContext *js, JSValue fn, js_debug *dbg)
case JS_CLASS_BYTECODE_FUNCTION: {
JSFunctionBytecode *b = p->u.func.function_bytecode;
// get filename
char *filename = JS_AtomToCString(js, b->debug.filename);
const char *filename = JS_AtomToCString(js, b->debug.filename);
if (!filename || filename[0] == 0)
dbg->filename = js_strdup(js, "unknown");
else {
@@ -55164,3 +55163,269 @@ JSValue js_debugger_closure_variables(JSContext *ctx, JSValue fn) {
done:
return ret;
}
static JSValue shape_to_obj(JSContext *ctx, JSShape *sh) {
if (!sh)
return JS_UNDEFINED;
JSValue o = JS_NewObject(ctx);
// For debugging, well store the pointer addresses as strings
{
char buf[64];
snprintf(buf, sizeof(buf), "%p", (void *)sh);
JS_SetPropertyStr(ctx, o, "self", JS_NewString(ctx, buf));
}
// Also store proto pointer
{
char buf[64];
snprintf(buf, sizeof(buf), "%p", (void *)sh->proto);
JS_SetPropertyStr(ctx, o, "proto", JS_NewString(ctx, buf));
}
JS_SetPropertyStr(ctx, o, "ref_count", JS_NewInt32(ctx, sh->header.ref_count));
JS_SetPropertyStr(ctx, o, "is_hashed", JS_NewBool(ctx, sh->is_hashed));
JS_SetPropertyStr(ctx, o, "prop_size", JS_NewInt32(ctx, sh->prop_size));
JS_SetPropertyStr(ctx, o, "prop_count", JS_NewInt32(ctx, sh->prop_count));
// Collect property atoms into an array
JSValue arr = JS_NewArray(ctx);
int propIndex = 0;
for (int j = 0; j < sh->prop_count; j++) {
JSAtom atom = sh->prop[j].atom;
if (atom != JS_ATOM_NULL) {
// Convert to a JSValue (usually a string, or symbol, etc.)
JSValue val = JS_AtomToValue(ctx, atom);
// Append to array
JS_SetPropertyUint32(ctx, arr, propIndex++, val);
}
}
JS_SetPropertyStr(ctx, o, "props", arr);
return o;
}
JSValue js_dump_shapes(JSContext *ctx) {
JSRuntime *rt = ctx->rt;
JSValue ret = JS_NewObject(ctx);
JS_SetPropertyStr(ctx, ret, "shape_hash_size", JS_NewInt32(ctx, rt->shape_hash_size));
JSValue arr = JS_NewArray(ctx);
uint32_t idx = 0;
for (int i = 0; i < rt->shape_hash_size; i++) {
JSShape *sh = rt->shape_hash[i];
while (sh) {
JSValue shapeObj = shape_to_obj(ctx, sh);
JS_SetPropertyUint32(ctx, arr, idx++, shapeObj);
sh = sh->shape_hash_next;
}
}
struct list_head *el;
list_for_each(el, &rt->gc_obj_list) {
JSGCObjectHeader *gp = list_entry(el, JSGCObjectHeader, link);
if (gp->gc_obj_type == JS_GC_OBJ_TYPE_JS_OBJECT) {
JSObject *p = (JSObject *)gp;
if (!p->shape->is_hashed) {
JSValue shapeObj = shape_to_obj(ctx, p->shape);
JS_SetPropertyUint32(ctx, arr, idx++, shapeObj);
}
}
}
JS_SetPropertyStr(ctx, ret, "shapes", arr);
return ret;
}
void js_debug_sethook(JSContext *ctx, js_hook hook, int type)
{
if (type == JS_HOOK_CALL)
ctx->fn_start_hook = hook;
else if (type == JS_HOOK_RET)
ctx->fn_end_hook = hook;
else if (type == JS_HOOK_CYCLE)
ctx->fn_cycle_hook = hook;
else if (type == JS_HOOK_GC)
ctx->fn_gc_hook = hook;
}
JSValue js_dump_atoms(JSContext *js)
{
JSRuntime *rt = js->rt;
JSValue ret = JS_NewObject(js);
JS_SetPropertyStr(js,ret,"count", JS_NewFloat64(js,rt->atom_count));
JS_SetPropertyStr(js,ret,"atom_size", JS_NewFloat64(js,rt->atom_size));
JS_SetPropertyStr(js,ret,"hash_size", JS_NewFloat64(js,rt->atom_hash_size));
JSValue atoms = JS_NewArray(js);
int ac = 0;
for (int i = 0; i < rt->atom_hash_size; i++) {
int h = rt->atom_hash[i];
if (h) {
while(h) {
JSAtomStruct *p = rt->atom_array[h];
JSValue atobj = JS_NewObject(js);
JS_SetPropertyStr(js,atobj,"index", JS_NewInt32(js,h));
JS_SetPropertyStr(js,atobj,"hash", JS_NewUint32(js,p->hash));
JS_SetPropertyStr(js, atobj, "atom_type", JS_NewInt32(js, p->atom_type));
JS_SetPropertyStr(js,atobj,"value", JS_AtomToValue(js,h));
h = p->hash_next;
JS_SetPropertyUint32(js,atoms,ac++,atobj);
}
}
}
JS_SetPropertyStr(js,ret,"atoms", atoms);
return ret;
}
/* Returns a JS object containing selected JSMemoryUsage stats */
JSValue js_get_memory_usage(JSContext *ctx) {
JSMemoryUsage s;
JS_ComputeMemoryUsage(ctx->rt, &s);
JSValue obj = JS_NewObject(ctx);
/* For each field, store it as a property in the object */
#define SETM(name) \
JS_SetPropertyStr(ctx, obj, #name, JS_NewInt64(ctx, s.name));
SETM(malloc_size)
SETM(malloc_limit)
SETM(memory_used_size)
SETM(memory_used_count)
SETM(atom_count)
SETM(atom_size)
SETM(str_count)
SETM(str_size)
SETM(obj_count)
SETM(prop_count)
SETM(prop_size)
SETM(shape_count)
SETM(shape_size)
SETM(js_func_count)
SETM(js_func_size)
SETM(js_func_code_size)
SETM(js_func_pc2line_count)
SETM(js_func_pc2line_size)
SETM(c_func_count)
SETM(array_count)
SETM(fast_array_count)
SETM(fast_array_elements)
SETM(binary_object_count)
SETM(binary_object_size)
#undef SETM
return obj;
}
JSValue js_dump_objects(JSContext *ctx) {
JSValue arr = JS_NewArray(ctx);
return arr;
/* uint32_t idx = 0;
JSRuntime *rt = ctx->rt;
struct list_head *el;
list_for_each(el, &rt->gc_obj_list) {
JSGCObjectHeader *hdr = list_entry(el, JSGCObjectHeader, link);
// Dump any GC object, not just JSObject
JSValue desc = js_dump_object(ctx, hdr);
JS_SetPropertyUint32(ctx, arr, idx++, desc);
}
return arr;*/
}
JSValue js_get_object_type_overheads(JSContext *ctx) {
JSRuntime *rt = ctx->rt;
static const struct {
const char *name;
size_t size;
} object_types[] = {
{ "JSRuntime", sizeof(JSRuntime) },
{ "JSContext", sizeof(JSContext) },
{ "JSObject", sizeof(JSObject) },
{ "JSString", sizeof(JSString) },
{ "JSFunctionBytecode", sizeof(JSFunctionBytecode) },
};
int usage_size_ok = 0;
JSValue arr = JS_NewArray(ctx);
uint32_t idx = 0;
for (int i = 0; i < (int)(sizeof(object_types)/sizeof(object_types[0])); i++) {
unsigned int size = (unsigned int)object_types[i].size;
void *p = js_malloc_rt(rt, size);
if (!p) {
// out of memory? skip
continue;
}
unsigned int size1 = js_malloc_usable_size_rt(rt, p);
js_free_rt(rt, p);
if (size1 >= size) {
usage_size_ok = 1;
JSValue entry = JS_NewObject(ctx);
JS_SetPropertyStr(ctx, entry, "name", JS_NewString(ctx, object_types[i].name));
JS_SetPropertyStr(ctx, entry, "base_size", JS_NewUint32(ctx, size));
JS_SetPropertyStr(ctx, entry, "usable_size", JS_NewUint32(ctx, size1));
JS_SetPropertyUint32(ctx, arr, idx++, entry);
}
}
if (!usage_size_ok) {
// Possibly return a single object or just a boolean
JSValue notice = JS_NewString(ctx, "malloc_usable_size unavailable");
JS_SetPropertyUint32(ctx, arr, idx++, notice);
}
return arr;
}
JSValue js_get_object_class_distribution(JSContext *ctx) {
JSRuntime *rt = ctx->rt;
JSValue ret = JS_NewArray(ctx);
// For counting how many objects exist for each class
int obj_classes[JS_CLASS_INIT_COUNT + 1] = {0};
// 1) Gather stats
struct list_head *el;
list_for_each(el, &rt->gc_obj_list) {
JSGCObjectHeader *gp = list_entry(el, JSGCObjectHeader, link);
if (gp->gc_obj_type == JS_GC_OBJ_TYPE_JS_OBJECT) {
JSObject *p = (JSObject *)gp;
// Bound the index
uint32_t idx = p->class_id < JS_CLASS_INIT_COUNT ? p->class_id : JS_CLASS_INIT_COUNT;
obj_classes[idx]++;
}
}
// 2) Convert to array of objects
for (int class_id = 0; class_id <= JS_CLASS_INIT_COUNT; class_id++) {
int count = obj_classes[class_id];
if (!count) continue;
// Create something like: { class_id: 1, count: 20, name: "Object" }
JSValue entry = JS_NewObject(ctx);
JS_SetPropertyStr(ctx, entry, "class_id", JS_NewInt32(ctx, class_id));
JS_SetPropertyStr(ctx, entry, "count", JS_NewInt32(ctx, count));
if (class_id < rt->class_count) {
// We can get the class name atom
JSAtom cname_atom = rt->class_array[class_id].class_name;
// Convert to string
JSValue cname_val = JS_AtomToValue(ctx, cname_atom);
JS_SetPropertyStr(ctx, entry, "name", cname_val);
} else {
// "other" or "unknown"
JS_SetPropertyStr(ctx, entry, "name", JS_NewString(ctx, "other"));
}
JS_SetPropertyUint32(ctx, ret, class_id, entry);
}
return ret;
}