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
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
This commit is contained in:
11
meson.build
11
meson.build
@@ -14,7 +14,7 @@ if get_option('bignum')
|
||||
add_project_arguments('-DCONFIG_BIGNUM', language : 'c')
|
||||
endif
|
||||
|
||||
lib_sources = ['libbf.c', 'libregexp.c', 'quickjs.c', 'libunicode.c', 'cutils.c']
|
||||
lib_sources = ['libregexp.c', 'quickjs.c', 'libunicode.c', 'cutils.c', 'dtoa.c']
|
||||
|
||||
libquickjs = library('quickjs',
|
||||
lib_sources,
|
||||
@@ -29,13 +29,6 @@ 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',
|
||||
@@ -44,7 +37,7 @@ qjsrepl_c = custom_target(
|
||||
)
|
||||
|
||||
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
|
||||
)
|
||||
|
||||
266
quickjs.c
266
quickjs.c
@@ -55164,3 +55164,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, we’ll 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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user