add memory profiling tooling

This commit is contained in:
John Alanbrook 2024-08-06 14:23:21 -05:00
parent ceb728b1a7
commit 432d8200f3
10 changed files with 329 additions and 106 deletions

View file

@ -79,6 +79,7 @@ actor.delay = function(fn, seconds) {
var timers = this.timers; var timers = this.timers;
var stop = function() { var stop = function() {
timers.remove(stop); timers.remove(stop);
stop = undefined;
rm(); rm();
} }
@ -104,9 +105,21 @@ actor.delay = function(fn, seconds) {
timers.push(stop); timers.push(stop);
return stop; return stop;
}; };
actor.delay.doc = `Call 'fn' after 'seconds' with 'this' set to the actor.`; actor.delay.doc = `Call 'fn' after 'seconds' with 'this' set to the actor.`;
actor.interval = function(fn, seconds)
{
var self = this;
var stop;
var usefn = function() {
fn();
stop = self.delay(usefn, seconds);
}
stop = self.delay(usefn, seconds);
return stop;
}
actor.padawans = []; actor.padawans = [];
global.app = Object.create(actor); global.app = Object.create(actor);

View file

@ -1,7 +1,8 @@
"use math"; "use math";
prosperon.gc_start = function(){} os.mem_limit.doc = "Set the memory limit of the runtime in bytes.";
prosperon.gc_end = function(){} os.gc_threshold.doc = "Set the threshold before a GC pass is triggered in bytes. This is set to malloc_size + malloc_size>>1 after a GC pass.";
os.max_stacksize.doc = "Set the max stack size in bytes.";
Object.defineProperty(String.prototype, 'rm', { Object.defineProperty(String.prototype, 'rm', {
value: function(index, endidx = index+1) { return this.slice(0,index) + this.slice(endidx); } value: function(index, endidx = index+1) { return this.slice(0,index) + this.slice(endidx); }

View file

@ -294,6 +294,7 @@ profile.print_mem = function()
{ {
var mem = os.mem(); var mem = os.mem();
say('total memory used: ' + profile.best_mem(mem.memory_used_size)); say('total memory used: ' + profile.best_mem(mem.memory_used_size));
say('total malloced: ' + profile.best_mem(mem.malloc_size));
delete mem.memory_used_size; delete mem.memory_used_size;
delete mem.malloc_size; delete mem.malloc_size;
for (var i in mem) { for (var i in mem) {
@ -302,4 +303,21 @@ profile.print_mem = function()
} }
} }
profile.atom_count = function()
{
// return os.dump_atoms().split(
}
profile.print_gc = function()
{
var gc = os.check_gc();
if (!gc) return;
var mem = os.mem();
say("GC Hit");
say (`time: ${profile.best_t(gc.time)}`);
say(`new threshold: ${profile.best_mem(mem.gc_threshold)}`);
say(`memory checked: ${profile.best_mem(gc.mem)}`);
say(`memory freed: ${profile.best_mem(gc.startmem - gc.mem)}`);
}
return {profile}; return {profile};

View file

@ -972,6 +972,13 @@ prosperon.process = function process() {
var dt = profile.secs(profile.now()) - frame_t; var dt = profile.secs(profile.now()) - frame_t;
frame_t = profile.secs(profile.now()); frame_t = profile.secs(profile.now());
/* debugging: check for gc */
profile.print_gc();
var cycles = os.check_cycles();
if (cycles) say(cycles);
profile.frame("app update"); profile.frame("app update");
prosperon.appupdate(dt); prosperon.appupdate(dt);
profile.endframe(); profile.endframe();

View file

@ -34,6 +34,7 @@
#include "sokol_glue.h" #include "sokol_glue.h"
#include <chipmunk/chipmunk_unsafe.h> #include <chipmunk/chipmunk_unsafe.h>
#include <chipmunk/chipmunk_structs.h> #include <chipmunk/chipmunk_structs.h>
#include <stdint.h>
#include "gui.h" #include "gui.h"
#include "timer.h" #include "timer.h"
@ -2483,7 +2484,6 @@ static const JSCFunctionListEntry js_nota_funcs[] = {
MIST_FUNC_DEF(nota, decode, 1) MIST_FUNC_DEF(nota, decode, 1)
}; };
JSValue js_os_cwd(JSContext *js, JSValue self, int argc, JSValue *argv) JSValue js_os_cwd(JSContext *js, JSValue self, int argc, JSValue *argv)
{ {
char cwd[PATH_MAX]; char cwd[PATH_MAX];
@ -2522,17 +2522,69 @@ JSC_CCALL(os_mem_limit, script_mem_limit(js2number(argv[0])))
JSC_CCALL(os_gc_threshold, script_gc_threshold(js2number(argv[0]))) JSC_CCALL(os_gc_threshold, script_gc_threshold(js2number(argv[0])))
JSC_CCALL(os_max_stacksize, script_max_stacksize(js2number(argv[0]))) JSC_CCALL(os_max_stacksize, script_max_stacksize(js2number(argv[0])))
static JSValue tmp2js(FILE *tmp)
{
size_t size = ftell(tmp);
rewind(tmp);
char *buffer = calloc(size+1, sizeof(char));
fread(buffer, sizeof(char),size, tmp);
JSValue ret = str2js(buffer);
free(buffer);
return ret;
}
JSC_CCALL(os_dump_value,
FILE *tmp = tmpfile();
quickjs_set_dumpout(tmp);
JS_DumpMyValue(rt, argv[0]);
ret = tmp2js(tmp);
)
JSC_CCALL(os_dump_atoms,
FILE *tmp = tmpfile();
quickjs_set_dumpout(tmp);
JS_PrintAtoms(rt);
ret = tmp2js(tmp);
)
JSC_CCALL(os_dump_shapes,
FILE *tmp = tmpfile();
quickjs_set_dumpout(tmp);
JS_PrintShapes(rt);
size_t size = ftell(tmp);
rewind(tmp);
char buffer[size];
fgets(buffer, sizeof(char)*size, tmp);
fclose(tmp);
ret = str2js(buffer);
)
JSC_CCALL(os_calc_mem,
return number2js(JS_MyValueSize(rt, argv[0]));
)
#define JSOBJ_ADD_FIELD(OBJ, STRUCT, FIELD, TYPE) \ #define JSOBJ_ADD_FIELD(OBJ, STRUCT, FIELD, TYPE) \
js_setpropstr(OBJ, #FIELD, TYPE##2js(STRUCT.FIELD));\ js_setpropstr(OBJ, #FIELD, TYPE##2js(STRUCT.FIELD));\
#define JSJMEMRET(FIELD) JSOBJ_ADD_FIELD(ret, jsmem, FIELD, number) #define JSJMEMRET(FIELD) JSOBJ_ADD_FIELD(ret, jsmem, FIELD, number)
JSC_CCALL(os_memstate,
JSMemoryUsage jsmem;
JS_FillMemoryState(rt, &jsmem);
ret = JS_NewObject(js);
JSJMEMRET(malloc_size)
JSJMEMRET(malloc_limit)
JSJMEMRET(gc_threshold)
)
JSC_CCALL(os_mem, JSC_CCALL(os_mem,
JSMemoryUsage jsmem; JSMemoryUsage jsmem;
JS_ComputeMemoryUsage(rt, &jsmem); JS_ComputeMemoryUsage(rt, &jsmem);
ret = JS_NewObject(js); ret = JS_NewObject(js);
JSJMEMRET(malloc_size) JSJMEMRET(malloc_size)
JSJMEMRET(malloc_limit) JSJMEMRET(malloc_limit)
JSJMEMRET(gc_threshold)
JSJMEMRET(memory_used_size) JSJMEMRET(memory_used_size)
JSJMEMRET(memory_used_count) JSJMEMRET(memory_used_count)
JSJMEMRET(atom_count) JSJMEMRET(atom_count)
@ -2558,6 +2610,45 @@ JSC_CCALL(os_mem,
JSJMEMRET(binary_object_size) JSJMEMRET(binary_object_size)
) )
JSC_CCALL(os_dump_mem,
FILE *tmp = tmpfile();
JSMemoryUsage mem = {0};
JS_DumpMemoryUsage(tmp, &mem, rt);
ret = tmp2js(tmp);
)
static double gc_t = 0;
static double gc_mem = 0;
static double gc_startmem = 0;
void script_report_gc_time(double t, double startmem, double mem)
{
gc_t = t;
gc_mem = mem;
gc_startmem = startmem;
}
static FILE *cycles;
JSC_CCALL(os_check_cycles,
if (ftell(cycles) == 0) return JS_UNDEFINED;
ret = tmp2js(cycles);
cycles = tmpfile();
quickjs_set_cycleout(cycles);
)
JSC_CCALL(os_check_gc,
if (gc_t == 0) return JS_UNDEFINED;
JSValue gc = JS_NewObject(js);
js_setpropstr(gc, "time", number2js(gc_t));
js_setpropstr(gc, "mem", number2js(gc_mem));
js_setpropstr(gc, "startmem", number2js(gc_startmem));
gc_t = 0;
gc_mem = 0;
gc_startmem = 0;
return gc;
)
JSC_SSCALL(os_eval, ret = script_eval(str, str2)) JSC_SSCALL(os_eval, ret = script_eval(str, str2))
JSC_CCALL(os_make_body, JSC_CCALL(os_make_body,
@ -3007,7 +3098,15 @@ static const JSCFunctionListEntry js_os_funcs[] = {
MIST_FUNC_DEF(os, mem, 1), MIST_FUNC_DEF(os, mem, 1),
MIST_FUNC_DEF(os, mem_limit, 1), MIST_FUNC_DEF(os, mem_limit, 1),
MIST_FUNC_DEF(os, gc_threshold, 1), MIST_FUNC_DEF(os, gc_threshold, 1),
MIST_FUNC_DEF(os, max_stacksize, 1) MIST_FUNC_DEF(os, max_stacksize, 1),
MIST_FUNC_DEF(os, dump_value, 1),
MIST_FUNC_DEF(os, dump_mem, 0),
MIST_FUNC_DEF(os, dump_shapes, 0),
MIST_FUNC_DEF(os, dump_atoms,0),
MIST_FUNC_DEF(os, calc_mem, 1),
MIST_FUNC_DEF(os, check_gc, 0),
MIST_FUNC_DEF(os, check_cycles, 0),
MIST_FUNC_DEF(os, memstate, 0)
}; };
#include "steam.h" #include "steam.h"
@ -3018,6 +3117,9 @@ JS_SetPropertyFunctionList(js, js_##NAME, js_##NAME##_funcs, countof(js_##NAME##
JS_SetPrototype(js, js_##NAME, PARENT); \ JS_SetPrototype(js, js_##NAME, PARENT); \
void ffi_load() { void ffi_load() {
cycles = tmpfile();
quickjs_set_cycleout(cycles);
JSUNDEF = JS_UNDEFINED; JSUNDEF = JS_UNDEFINED;
globalThis = JS_GetGlobalObject(js); globalThis = JS_GetGlobalObject(js);

View file

@ -10,6 +10,8 @@ extern "C" {
#include <stdarg.h> #include <stdarg.h>
#include <chipmunk/chipmunk.h> #include <chipmunk/chipmunk.h>
void script_report_gc_time(double t, double startmem, double mem);
extern JSValue cpShape2js(cpShape *s); extern JSValue cpShape2js(cpShape *s);
#define MIST_CFUNC_DEF(name, length, func1) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE | JS_PROP_ENUMERABLE, JS_DEF_CFUNC, 0, .u = { .func = { length, JS_CFUNC_generic, { .generic = func1 } } } } #define MIST_CFUNC_DEF(name, length, func1) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE | JS_PROP_ENUMERABLE, JS_DEF_CFUNC, 0, .u = { .func = { length, JS_CFUNC_generic, { .generic = func1 } } } }

View file

@ -16,8 +16,7 @@ JSRuntime *rt = NULL;
#define JS_EVAL_FLAGS JS_EVAL_FLAG_STRICT | JS_EVAL_FLAG_STRIP #define JS_EVAL_FLAGS JS_EVAL_FLAG_STRICT | JS_EVAL_FLAG_STRIP
#endif #endif
static JSValue start_gc; static JSValue report_gc;
static JSValue end_gc;
void script_startup() { void script_startup() {
rt = JS_NewRuntime(); rt = JS_NewRuntime();

View file

@ -34,6 +34,11 @@ void script_mem_limit(size_t limit);
void script_gc_threshold(size_t threshold); void script_gc_threshold(size_t threshold);
void script_max_stacksize(size_t size); void script_max_stacksize(size_t size);
void _script_gcstart();
void _script_gcend();
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View file

@ -33,6 +33,9 @@
#include <fenv.h> #include <fenv.h>
#include <math.h> #include <math.h>
#include <script.h> #include <script.h>
#include <jsffi.h>
#include <sokol/sokol_time.h>
#if defined(__APPLE__) #if defined(__APPLE__)
#include <malloc/malloc.h> #include <malloc/malloc.h>
#elif defined(__linux__) || defined(__GLIBC__) #elif defined(__linux__) || defined(__GLIBC__)
@ -79,15 +82,17 @@
#endif #endif
static FILE *dumpout = NULL; static FILE *dumpout = NULL;
static FILE *cycleout = NULL;
void quickjs_set_dumpout(FILE *f) void quickjs_set_dumpout(FILE *f)
{ {
dumpout = f; dumpout = f;
} }
void quickjs_set_cycleout(FILE *f) { cycleout = f; }
/* dump object free */ /* dump object free */
//#define DUMP_FREE //#define DUMP_FREE
//#define DUMP_CLOSURE
/* dump the bytecode of the compiled functions: combination of bits /* dump the bytecode of the compiled functions: combination of bits
1: dump pass 3 final byte code 1: dump pass 3 final byte code
2: dump pass 2 code 2: dump pass 2 code
@ -116,13 +121,9 @@ void quickjs_set_dumpout(FILE *f)
#ifdef DUMP #ifdef DUMP
//#define DUMP_FREE //#define DUMP_FREE
//#define DUMP_MEM //#define DUMP_MEM
//#define DUMP_CLOSURE
#define DUMP_GC #define DUMP_GC
//#define DUMP_GC_FREE
#define DUMP_LEAKS 1 #define DUMP_LEAKS 1
//#define DUMP_OBJECTS //#define DUMP_OBJECTS
#define DUMP_CLOSURE
//#define DUMP_OBJECTS
//#define DUMP_ATOMS //#define DUMP_ATOMS
//#define DUMP_SHAPES //#define DUMP_SHAPES
//#define DUMP_MODULE_RESOLVE //#define DUMP_MODULE_RESOLVE
@ -329,6 +330,25 @@ struct JSRuntime {
void *user_opaque; void *user_opaque;
}; };
#define SETRT(FIELD) JS_SetPropertyStr(js, v, #FIELD, JS_NewFloat64(js, rt->FIELD));
JSValue JS_GetRTInfo(JSRuntime *rt, JSContext *js)
{
JSValue v = JS_NewObject(js);
SETRT(atom_hash_size);
SETRT(atom_count);
SETRT(atom_size);
SETRT(class_count);
SETRT(stack_size);
SETRT(stack_top);
SETRT(stack_limit);
SETRT(malloc_gc_threshold);
SETRT(malloc_state.malloc_count);
SETRT(malloc_state.malloc_size);
SETRT(malloc_state.malloc_limit);
return v;
}
struct JSClass { struct JSClass {
uint32_t class_id; /* 0 means free entry */ uint32_t class_id; /* 0 means free entry */
JSAtom class_name; JSAtom class_name;
@ -1068,12 +1088,12 @@ static JSValue JS_EvalObject(JSContext *ctx, JSValueConst this_obj,
JSValue __attribute__((format(printf, 2, 3))) JS_ThrowInternalError(JSContext *ctx, const char *fmt, ...); JSValue __attribute__((format(printf, 2, 3))) JS_ThrowInternalError(JSContext *ctx, const char *fmt, ...);
static __maybe_unused void JS_DumpAtoms(JSRuntime *rt); static __maybe_unused void JS_DumpAtoms(JSRuntime *rt);
static __maybe_unused void JS_DumpString(JSRuntime *rt, const JSString *p); static __maybe_unused void JS_DumpString(JSRuntime *rt, const JSString *p);
static __maybe_unused void JS_DumpObjectHeader(JSRuntime *rt); static __maybe_unused void JS_DumpObjectHeader(FILE *fp, JSRuntime *rt);
static __maybe_unused void JS_DumpObject(JSRuntime *rt, JSObject *p); static __maybe_unused void JS_DumpObject(FILE *fp, JSRuntime *rt, JSObject *p);
static __maybe_unused void JS_DumpGCObject(JSRuntime *rt, JSGCObjectHeader *p); static __maybe_unused void JS_DumpGCObject(FILE *fp, JSRuntime *rt, JSGCObjectHeader *p);
static __maybe_unused void JS_DumpValueShort(JSRuntime *rt, JSValueConst val); static __maybe_unused void JS_DumpValueShort(FILE *fp, JSRuntime *rt, JSValueConst val);
static __maybe_unused void JS_DumpValue(JSContext *ctx, JSValueConst val); static __maybe_unused void JS_DumpValue(FILE *fp, JSContext *ctx, JSValueConst val);
static __maybe_unused void JS_PrintValue(JSContext *ctx, static __maybe_unused void JS_PrintValue(FILE *fp,JSContext *ctx,
const char *str, const char *str,
JSValueConst val); JSValueConst val);
static __maybe_unused void JS_DumpShapes(JSRuntime *rt); static __maybe_unused void JS_DumpShapes(JSRuntime *rt);
@ -1309,6 +1329,27 @@ static const JSClassExoticMethods js_proxy_exotic_methods;
static const JSClassExoticMethods js_module_ns_exotic_methods; static const JSClassExoticMethods js_module_ns_exotic_methods;
static JSClassID js_class_id_alloc = JS_CLASS_INIT_COUNT; static JSClassID js_class_id_alloc = JS_CLASS_INIT_COUNT;
////// CUSTOM DUMP FUNCTIONS
void JS_DumpMyValue(JSRuntime *rt, JSValue v)
{
uint32_t tag = JS_VALUE_GET_TAG(v);
if (tag == JS_TAG_OBJECT)
JS_DumpObject(dumpout, rt, JS_VALUE_GET_OBJ(v));
else
JS_DumpValueShort(dumpout, rt, v);
}
void JS_PrintShapes(JSRuntime *rt)
{
JS_DumpShapes(rt);
}
void JS_PrintAtoms(JSRuntime *rt)
{
JS_DumpAtoms(rt);
}
static void js_trigger_gc(JSRuntime *rt, size_t size) static void js_trigger_gc(JSRuntime *rt, size_t size)
{ {
BOOL force_gc; BOOL force_gc;
@ -1320,7 +1361,7 @@ static void js_trigger_gc(JSRuntime *rt, size_t size)
#endif #endif
if (force_gc) { if (force_gc) {
#ifdef DUMP_GC #ifdef DUMP_GC
fprintf(dumpout, dumpout, "GC: size=%" PRIu64 "\n", fprintf(dumpout, "GC: size=%" PRIu64 "\n",
(uint64_t)rt->malloc_state.malloc_size); (uint64_t)rt->malloc_state.malloc_size);
#endif #endif
JS_RunGC(rt); JS_RunGC(rt);
@ -2004,11 +2045,11 @@ void JS_FreeRuntime(JSRuntime *rt)
p = list_entry(el, JSGCObjectHeader, link); p = list_entry(el, JSGCObjectHeader, link);
if (p->ref_count != 0) { if (p->ref_count != 0) {
if (!header_done) { if (!header_done) {
fprintf(dumpout, dumpout, "Object leaks:\n"); fprintf(cycleout, "Object leaks:\n");
JS_DumpObjectHeader(rt); JS_DumpObjectHeader(cycleout, rt);
header_done = TRUE; header_done = TRUE;
} }
JS_DumpGCObject(rt, p); JS_DumpGCObject(cycleout, rt, p);
} }
} }
@ -2020,7 +2061,7 @@ void JS_FreeRuntime(JSRuntime *rt)
} }
} }
if (count != 0) if (count != 0)
fprintf(dumpout, "Secondary object leaks: %d\n", count); fprintf(cycleout, "Secondary object leaks: %d\n", count);
} }
#endif #endif
assert(list_empty(&rt->gc_obj_list)); assert(list_empty(&rt->gc_obj_list));
@ -5837,7 +5878,7 @@ static void gc_free_cycles(JSRuntime *rt)
{ {
struct list_head *el, *el1; struct list_head *el, *el1;
JSGCObjectHeader *p; JSGCObjectHeader *p;
#ifdef DUMP_GC_FREE #ifdef DUMP
BOOL header_done = FALSE; BOOL header_done = FALSE;
#endif #endif
@ -5855,13 +5896,13 @@ static void gc_free_cycles(JSRuntime *rt)
case JS_GC_OBJ_TYPE_JS_OBJECT: case JS_GC_OBJ_TYPE_JS_OBJECT:
case JS_GC_OBJ_TYPE_FUNCTION_BYTECODE: case JS_GC_OBJ_TYPE_FUNCTION_BYTECODE:
case JS_GC_OBJ_TYPE_ASYNC_FUNCTION: case JS_GC_OBJ_TYPE_ASYNC_FUNCTION:
#ifdef DUMP_GC_FREE #ifdef DUMP
if (!header_done) { if (!header_done) {
fprintf(dumpout, "Freeing cycles:\n"); fprintf(cycleout, "Freeing cycles:\n");
JS_DumpObjectHeader(rt); JS_DumpObjectHeader(cycleout, rt);
header_done = TRUE; header_done = TRUE;
} }
JS_DumpGCObject(rt, p); JS_DumpGCObject(cycleout, rt, p);
#endif #endif
free_gc_object(rt, p); free_gc_object(rt, p);
break; break;
@ -5886,6 +5927,9 @@ static void gc_free_cycles(JSRuntime *rt)
void JS_RunGC(JSRuntime *rt) void JS_RunGC(JSRuntime *rt)
{ {
double n = stm_now();
double size = rt->malloc_state.malloc_size;
/* decrement the reference of the children of each object. mark = /* decrement the reference of the children of each object. mark =
1 after this pass. */ 1 after this pass. */
gc_decref(rt); gc_decref(rt);
@ -5895,6 +5939,8 @@ void JS_RunGC(JSRuntime *rt)
/* free the GC objects in a cycle */ /* free the GC objects in a cycle */
gc_free_cycles(rt); gc_free_cycles(rt);
script_report_gc_time(stm_now()-n, size, rt->malloc_state.malloc_size);
} }
/* Return false if not an object or if the object has already been /* Return false if not an object or if the object has already been
@ -5989,6 +6035,25 @@ static void compute_value_size(JSValueConst val, JSMemoryUsage_helper *hp)
} }
} }
double JS_MyValueSize(JSRuntime *rt, JSValue v)
{
JSMemoryUsage_helper mem = {0};
compute_value_size(v, &mem);
return mem.memory_used_count;
}
void JS_FillMemoryState(JSRuntime *rt, JSMemoryUsage *s)
{
s->malloc_count = rt->malloc_state.malloc_count;
s->malloc_size = rt->malloc_state.malloc_size;
s->malloc_limit = rt->malloc_state.malloc_limit;
s->gc_threshold = rt->malloc_gc_threshold;
s->memory_used_count = 2; /* rt + rt->class_array */
s->memory_used_size = sizeof(JSRuntime) + sizeof(JSValue) * rt->class_count;
}
void JS_ComputeMemoryUsage(JSRuntime *rt, JSMemoryUsage *s) void JS_ComputeMemoryUsage(JSRuntime *rt, JSMemoryUsage *s)
{ {
struct list_head *el, *el1; struct list_head *el, *el1;
@ -6000,6 +6065,8 @@ void JS_ComputeMemoryUsage(JSRuntime *rt, JSMemoryUsage *s)
s->malloc_size = rt->malloc_state.malloc_size; s->malloc_size = rt->malloc_state.malloc_size;
s->malloc_limit = rt->malloc_state.malloc_limit; s->malloc_limit = rt->malloc_state.malloc_limit;
s->gc_threshold = rt->malloc_gc_threshold;
s->memory_used_count = 2; /* rt + rt->class_array */ s->memory_used_count = 2; /* rt + rt->class_array */
s->memory_used_size = sizeof(JSRuntime) + sizeof(JSValue) * rt->class_count; s->memory_used_size = sizeof(JSRuntime) + sizeof(JSValue) * rt->class_count;
@ -6279,7 +6346,7 @@ void JS_ComputeMemoryUsage(JSRuntime *rt, JSMemoryUsage *s)
void JS_DumpMemoryUsage(FILE *fp, const JSMemoryUsage *s, JSRuntime *rt) void JS_DumpMemoryUsage(FILE *fp, const JSMemoryUsage *s, JSRuntime *rt)
{ {
fprintf(dumpout, fp, "QuickJS memory usage -- " fprintf(fp, "QuickJS memory usage -- "
#ifdef CONFIG_BIGNUM #ifdef CONFIG_BIGNUM
"BigNum " "BigNum "
#endif #endif
@ -6305,14 +6372,14 @@ void JS_DumpMemoryUsage(FILE *fp, const JSMemoryUsage *s, JSRuntime *rt)
unsigned int size1 = js_malloc_usable_size_rt(rt, p); unsigned int size1 = js_malloc_usable_size_rt(rt, p);
if (size1 >= size) { if (size1 >= size) {
usage_size_ok = 1; usage_size_ok = 1;
fprintf(dumpout, fp, " %3u + %-2u %s\n", fprintf(fp, " %3u + %-2u %s\n",
size, size1 - size, object_types[i].name); size, size1 - size, object_types[i].name);
} }
js_free_rt(rt, p); js_free_rt(rt, p);
} }
} }
if (!usage_size_ok) { if (!usage_size_ok) {
fprintf(dumpout, fp, " malloc_usable_size unavailable\n"); fprintf(fp, " malloc_usable_size unavailable\n");
} }
{ {
int obj_classes[JS_CLASS_INIT_COUNT + 1] = { 0 }; int obj_classes[JS_CLASS_INIT_COUNT + 1] = { 0 };
@ -6326,82 +6393,82 @@ void JS_DumpMemoryUsage(FILE *fp, const JSMemoryUsage *s, JSRuntime *rt)
obj_classes[min_uint32(p->class_id, JS_CLASS_INIT_COUNT)]++; obj_classes[min_uint32(p->class_id, JS_CLASS_INIT_COUNT)]++;
} }
} }
fprintf(dumpout, fp, "\n" "JSObject classes\n"); fprintf(fp, "\n" "JSObject classes\n");
if (obj_classes[0]) if (obj_classes[0])
fprintf(dumpout, fp, " %5d %2.0d %s\n", obj_classes[0], 0, "none"); fprintf(fp, " %5d %2.0d %s\n", obj_classes[0], 0, "none");
for (class_id = 1; class_id < JS_CLASS_INIT_COUNT; class_id++) { for (class_id = 1; class_id < JS_CLASS_INIT_COUNT; class_id++) {
if (obj_classes[class_id] && class_id < rt->class_count) { if (obj_classes[class_id] && class_id < rt->class_count) {
char buf[ATOM_GET_STR_BUF_SIZE]; char buf[ATOM_GET_STR_BUF_SIZE];
fprintf(dumpout, fp, " %5d %2.0d %s\n", obj_classes[class_id], class_id, fprintf(fp, " %5d %2.0d %s\n", obj_classes[class_id], class_id,
JS_AtomGetStrRT(rt, buf, sizeof(buf), rt->class_array[class_id].class_name)); JS_AtomGetStrRT(rt, buf, sizeof(buf), rt->class_array[class_id].class_name));
} }
} }
if (obj_classes[JS_CLASS_INIT_COUNT]) if (obj_classes[JS_CLASS_INIT_COUNT])
fprintf(dumpout, fp, " %5d %2.0d %s\n", obj_classes[JS_CLASS_INIT_COUNT], 0, "other"); fprintf(fp, " %5d %2.0d %s\n", obj_classes[JS_CLASS_INIT_COUNT], 0, "other");
} }
fprintf(dumpout, fp, "\n"); fprintf(fp, "\n");
} }
#endif #endif
fprintf(dumpout, fp, "%-20s %8s %8s\n", "NAME", "COUNT", "SIZE"); fprintf(fp, "%-20s %8s %8s\n", "NAME", "COUNT", "SIZE");
if (s->malloc_count) { if (s->malloc_count) {
fprintf(dumpout, fp, "%-20s %8"PRId64" %8"PRId64" (%0.1f per block)\n", fprintf(fp, "%-20s %8"PRId64" %8"PRId64" (%0.1f per block)\n",
"memory allocated", s->malloc_count, s->malloc_size, "memory allocated", s->malloc_count, s->malloc_size,
(double)s->malloc_size / s->malloc_count); (double)s->malloc_size / s->malloc_count);
fprintf(dumpout, fp, "%-20s %8"PRId64" %8"PRId64" (%d overhead, %0.1f average slack)\n", fprintf(fp, "%-20s %8"PRId64" %8"PRId64" (%d overhead, %0.1f average slack)\n",
"memory used", s->memory_used_count, s->memory_used_size, "memory used", s->memory_used_count, s->memory_used_size,
MALLOC_OVERHEAD, ((double)(s->malloc_size - s->memory_used_size) / MALLOC_OVERHEAD, ((double)(s->malloc_size - s->memory_used_size) /
s->memory_used_count)); s->memory_used_count));
} }
if (s->atom_count) { if (s->atom_count) {
fprintf(dumpout, fp, "%-20s %8"PRId64" %8"PRId64" (%0.1f per atom)\n", fprintf(fp, "%-20s %8"PRId64" %8"PRId64" (%0.1f per atom)\n",
"atoms", s->atom_count, s->atom_size, "atoms", s->atom_count, s->atom_size,
(double)s->atom_size / s->atom_count); (double)s->atom_size / s->atom_count);
} }
if (s->str_count) { if (s->str_count) {
fprintf(dumpout, fp, "%-20s %8"PRId64" %8"PRId64" (%0.1f per string)\n", fprintf(fp, "%-20s %8"PRId64" %8"PRId64" (%0.1f per string)\n",
"strings", s->str_count, s->str_size, "strings", s->str_count, s->str_size,
(double)s->str_size / s->str_count); (double)s->str_size / s->str_count);
} }
if (s->obj_count) { if (s->obj_count) {
fprintf(dumpout, fp, "%-20s %8"PRId64" %8"PRId64" (%0.1f per object)\n", fprintf(fp, "%-20s %8"PRId64" %8"PRId64" (%0.1f per object)\n",
"objects", s->obj_count, s->obj_size, "objects", s->obj_count, s->obj_size,
(double)s->obj_size / s->obj_count); (double)s->obj_size / s->obj_count);
fprintf(dumpout, fp, "%-20s %8"PRId64" %8"PRId64" (%0.1f per object)\n", fprintf(fp, "%-20s %8"PRId64" %8"PRId64" (%0.1f per object)\n",
" properties", s->prop_count, s->prop_size, " properties", s->prop_count, s->prop_size,
(double)s->prop_count / s->obj_count); (double)s->prop_count / s->obj_count);
fprintf(dumpout, fp, "%-20s %8"PRId64" %8"PRId64" (%0.1f per shape)\n", fprintf(fp, "%-20s %8"PRId64" %8"PRId64" (%0.1f per shape)\n",
" shapes", s->shape_count, s->shape_size, " shapes", s->shape_count, s->shape_size,
(double)s->shape_size / s->shape_count); (double)s->shape_size / s->shape_count);
} }
if (s->js_func_count) { if (s->js_func_count) {
fprintf(dumpout, fp, "%-20s %8"PRId64" %8"PRId64"\n", fprintf(fp, "%-20s %8"PRId64" %8"PRId64"\n",
"bytecode functions", s->js_func_count, s->js_func_size); "bytecode functions", s->js_func_count, s->js_func_size);
fprintf(dumpout, fp, "%-20s %8"PRId64" %8"PRId64" (%0.1f per function)\n", fprintf(fp, "%-20s %8"PRId64" %8"PRId64" (%0.1f per function)\n",
" bytecode", s->js_func_count, s->js_func_code_size, " bytecode", s->js_func_count, s->js_func_code_size,
(double)s->js_func_code_size / s->js_func_count); (double)s->js_func_code_size / s->js_func_count);
if (s->js_func_pc2line_count) { if (s->js_func_pc2line_count) {
fprintf(dumpout, fp, "%-20s %8"PRId64" %8"PRId64" (%0.1f per function)\n", fprintf(fp, "%-20s %8"PRId64" %8"PRId64" (%0.1f per function)\n",
" pc2line", s->js_func_pc2line_count, " pc2line", s->js_func_pc2line_count,
s->js_func_pc2line_size, s->js_func_pc2line_size,
(double)s->js_func_pc2line_size / s->js_func_pc2line_count); (double)s->js_func_pc2line_size / s->js_func_pc2line_count);
} }
} }
if (s->c_func_count) { if (s->c_func_count) {
fprintf(dumpout, fp, "%-20s %8"PRId64"\n", "C functions", s->c_func_count); fprintf(fp, "%-20s %8"PRId64"\n", "C functions", s->c_func_count);
} }
if (s->array_count) { if (s->array_count) {
fprintf(dumpout, fp, "%-20s %8"PRId64"\n", "arrays", s->array_count); fprintf(fp, "%-20s %8"PRId64"\n", "arrays", s->array_count);
if (s->fast_array_count) { if (s->fast_array_count) {
fprintf(dumpout, fp, "%-20s %8"PRId64"\n", " fast arrays", s->fast_array_count); fprintf(fp, "%-20s %8"PRId64"\n", " fast arrays", s->fast_array_count);
fprintf(dumpout, fp, "%-20s %8"PRId64" %8"PRId64" (%0.1f per fast array)\n", fprintf(fp, "%-20s %8"PRId64" %8"PRId64" (%0.1f per fast array)\n",
" elements", s->fast_array_elements, " elements", s->fast_array_elements,
s->fast_array_elements * (int)sizeof(JSValue), s->fast_array_elements * (int)sizeof(JSValue),
(double)s->fast_array_elements / s->fast_array_count); (double)s->fast_array_elements / s->fast_array_count);
} }
} }
if (s->binary_object_count) { if (s->binary_object_count) {
fprintf(dumpout, fp, "%-20s %8"PRId64" %8"PRId64"\n", fprintf(fp, "%-20s %8"PRId64" %8"PRId64"\n",
"binary objects", s->binary_object_count, s->binary_object_size); "binary objects", s->binary_object_count, s->binary_object_size);
} }
} }
@ -11874,14 +11941,14 @@ static JSValue JS_ToQuotedString(JSContext *ctx, JSValueConst val1)
return JS_EXCEPTION; return JS_EXCEPTION;
} }
static __maybe_unused void JS_DumpObjectHeader(JSRuntime *rt) static __maybe_unused void JS_DumpObjectHeader(FILE *fp, JSRuntime *rt)
{ {
fprintf(dumpout, "%14s %4s %4s %14s %10s %s\n", fprintf(fp, "%14s %4s %4s %14s %10s %s\n",
"ADDRESS", "REFS", "SHRF", "PROTO", "CLASS", "PROPS"); "ADDRESS", "REFS", "SHRF", "PROTO", "CLASS", "PROPS");
} }
/* for debug only: dump an object without side effect */ /* for debug only: dump an object without side effect */
static __maybe_unused void JS_DumpObject(JSRuntime *rt, JSObject *p) static __maybe_unused void JS_DumpObject(FILE *fp, JSRuntime *rt, JSObject *p)
{ {
uint32_t i; uint32_t i;
char atom_buf[ATOM_GET_STR_BUF_SIZE]; char atom_buf[ATOM_GET_STR_BUF_SIZE];
@ -11892,28 +11959,28 @@ static __maybe_unused void JS_DumpObject(JSRuntime *rt, JSObject *p)
/* XXX: should encode atoms with special characters */ /* XXX: should encode atoms with special characters */
sh = p->shape; /* the shape can be NULL while freeing an object */ sh = p->shape; /* the shape can be NULL while freeing an object */
fprintf(dumpout, "%14p %4d ", fprintf(fp, "%14p %4d ",
(void *)p, (void *)p,
p->header.ref_count); p->header.ref_count);
if (sh) { if (sh) {
fprintf(dumpout, "%3d%c %14p ", fprintf(fp, "%3d%c %14p ",
sh->header.ref_count, sh->header.ref_count,
" *"[sh->is_hashed], " *"[sh->is_hashed],
(void *)sh->proto); (void *)sh->proto);
} else { } else {
fprintf(dumpout, "%3s %14s ", "-", "-"); fprintf(fp, "%3s %14s ", "-", "-");
} }
fprintf(dumpout, "%10s ", fprintf(fp, "%10s ",
JS_AtomGetStrRT(rt, atom_buf, sizeof(atom_buf), rt->class_array[p->class_id].class_name)); JS_AtomGetStrRT(rt, atom_buf, sizeof(atom_buf), rt->class_array[p->class_id].class_name));
if (p->is_exotic && p->fast_array) { if (p->is_exotic && p->fast_array) {
fprintf(dumpout, "[ "); fprintf(fp, "[ ");
for(i = 0; i < p->u.array.count; i++) { for(i = 0; i < p->u.array.count; i++) {
if (i != 0) if (i != 0)
fprintf(dumpout, ", "); fprintf(fp, ", ");
switch (p->class_id) { switch (p->class_id) {
case JS_CLASS_ARRAY: case JS_CLASS_ARRAY:
case JS_CLASS_ARGUMENTS: case JS_CLASS_ARGUMENTS:
JS_DumpValueShort(rt, p->u.array.u.values[i]); JS_DumpValueShort(fp, rt, p->u.array.u.values[i]);
break; break;
case JS_CLASS_UINT8C_ARRAY: case JS_CLASS_UINT8C_ARRAY:
case JS_CLASS_INT8_ARRAY: case JS_CLASS_INT8_ARRAY:
@ -11930,40 +11997,40 @@ static __maybe_unused void JS_DumpObject(JSRuntime *rt, JSObject *p)
int size = 1 << typed_array_size_log2(p->class_id); int size = 1 << typed_array_size_log2(p->class_id);
const uint8_t *b = p->u.array.u.uint8_ptr + i * size; const uint8_t *b = p->u.array.u.uint8_ptr + i * size;
while (size-- > 0) while (size-- > 0)
fprintf(dumpout, "%02X", *b++); fprintf(fp, "%02X", *b++);
} }
break; break;
} }
} }
fprintf(dumpout, " ] "); fprintf(fp, " ] ");
} }
if (sh) { if (sh) {
fprintf(dumpout, "{ "); fprintf(fp, "{ ");
for(i = 0, prs = get_shape_prop(sh); i < sh->prop_count; i++, prs++) { for(i = 0, prs = get_shape_prop(sh); i < sh->prop_count; i++, prs++) {
if (prs->atom != JS_ATOM_NULL) { if (prs->atom != JS_ATOM_NULL) {
pr = &p->prop[i]; pr = &p->prop[i];
if (!is_first) if (!is_first)
fprintf(dumpout, ", "); fprintf(fp, ", ");
fprintf(dumpout, "%s: ", fprintf(fp, "%s: ",
JS_AtomGetStrRT(rt, atom_buf, sizeof(atom_buf), prs->atom)); JS_AtomGetStrRT(rt, atom_buf, sizeof(atom_buf), prs->atom));
if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) { if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) {
fprintf(dumpout, "[getset %p %p]", (void *)pr->u.getset.getter, fprintf(fp, "[getset %p %p]", (void *)pr->u.getset.getter,
(void *)pr->u.getset.setter); (void *)pr->u.getset.setter);
} else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) { } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) {
fprintf(dumpout, "[varref %p]", (void *)pr->u.var_ref); fprintf(fp, "[varref %p]", (void *)pr->u.var_ref);
} else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) { } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {
fprintf(dumpout, "[autoinit %p %d %p]", fprintf(fp, "[autoinit %p %d %p]",
(void *)js_autoinit_get_realm(pr), (void *)js_autoinit_get_realm(pr),
js_autoinit_get_id(pr), js_autoinit_get_id(pr),
(void *)pr->u.init.opaque); (void *)pr->u.init.opaque);
} else { } else {
JS_DumpValueShort(rt, pr->u.value); JS_DumpValueShort(fp, rt, pr->u.value);
} }
is_first = FALSE; is_first = FALSE;
} }
} }
fprintf(dumpout, " }"); fprintf(fp, " }");
} }
if (js_class_has_bytecode(p->class_id)) { if (js_class_has_bytecode(p->class_id)) {
@ -11971,53 +12038,53 @@ static __maybe_unused void JS_DumpObject(JSRuntime *rt, JSObject *p)
JSVarRef **var_refs; JSVarRef **var_refs;
if (b->closure_var_count) { if (b->closure_var_count) {
var_refs = p->u.func.var_refs; var_refs = p->u.func.var_refs;
fprintf(dumpout, " Closure:"); fprintf(fp, " Closure:");
for(i = 0; i < b->closure_var_count; i++) { for(i = 0; i < b->closure_var_count; i++) {
fprintf(dumpout, " "); fprintf(fp, " ");
JS_DumpValueShort(rt, var_refs[i]->value); JS_DumpValueShort(fp, rt, var_refs[i]->value);
} }
if (p->u.func.home_object) { if (p->u.func.home_object) {
fprintf(dumpout, " HomeObject: "); fprintf(fp, " HomeObject: ");
JS_DumpValueShort(rt, JS_MKPTR(JS_TAG_OBJECT, p->u.func.home_object)); JS_DumpValueShort(fp, rt, JS_MKPTR(JS_TAG_OBJECT, p->u.func.home_object));
} }
} }
} }
fprintf(dumpout, "\n"); fprintf(fp, "\n");
} }
static __maybe_unused void JS_DumpGCObject(JSRuntime *rt, JSGCObjectHeader *p) static __maybe_unused void JS_DumpGCObject(FILE *fp, JSRuntime *rt, JSGCObjectHeader *p)
{ {
if (p->gc_obj_type == JS_GC_OBJ_TYPE_JS_OBJECT) { if (p->gc_obj_type == JS_GC_OBJ_TYPE_JS_OBJECT) {
JS_DumpObject(rt, (JSObject *)p); JS_DumpObject(fp, rt, (JSObject *)p);
} else { } else {
fprintf(dumpout, "%14p %4d ", fprintf(fp, "%14p %4d ",
(void *)p, (void *)p,
p->ref_count); p->ref_count);
switch(p->gc_obj_type) { switch(p->gc_obj_type) {
case JS_GC_OBJ_TYPE_FUNCTION_BYTECODE: case JS_GC_OBJ_TYPE_FUNCTION_BYTECODE:
fprintf(dumpout, "[function bytecode]"); fprintf(fp, "[function bytecode]");
break; break;
case JS_GC_OBJ_TYPE_SHAPE: case JS_GC_OBJ_TYPE_SHAPE:
fprintf(dumpout, "[shape]"); fprintf(fp, "[shape]");
break; break;
case JS_GC_OBJ_TYPE_VAR_REF: case JS_GC_OBJ_TYPE_VAR_REF:
fprintf(dumpout, "[var_ref]"); fprintf(fp, "[var_ref]");
break; break;
case JS_GC_OBJ_TYPE_ASYNC_FUNCTION: case JS_GC_OBJ_TYPE_ASYNC_FUNCTION:
fprintf(dumpout, "[async_function]"); fprintf(fp, "[async_function]");
break; break;
case JS_GC_OBJ_TYPE_JS_CONTEXT: case JS_GC_OBJ_TYPE_JS_CONTEXT:
fprintf(dumpout, "[js_context]"); fprintf(fp, "[js_context]");
break; break;
default: default:
fprintf(dumpout, "[unknown %d]", p->gc_obj_type); fprintf(fp, "[unknown %d]", p->gc_obj_type);
break; break;
} }
fprintf(dumpout, "\n"); fprintf(fp, "\n");
} }
} }
static __maybe_unused void JS_DumpValueShort(JSRuntime *rt, static __maybe_unused void JS_DumpValueShort(FILE *fp, JSRuntime *rt,
JSValueConst val) JSValueConst val)
{ {
uint32_t tag = JS_VALUE_GET_NORM_TAG(val); uint32_t tag = JS_VALUE_GET_NORM_TAG(val);
@ -12025,7 +12092,7 @@ static __maybe_unused void JS_DumpValueShort(JSRuntime *rt,
switch(tag) { switch(tag) {
case JS_TAG_INT: case JS_TAG_INT:
fprintf(dumpout, "%d", JS_VALUE_GET_INT(val)); fprintf(fp, "%d", JS_VALUE_GET_INT(val));
break; break;
case JS_TAG_BOOL: case JS_TAG_BOOL:
if (JS_VALUE_GET_BOOL(val)) if (JS_VALUE_GET_BOOL(val))
@ -12045,10 +12112,10 @@ static __maybe_unused void JS_DumpValueShort(JSRuntime *rt,
case JS_TAG_UNDEFINED: case JS_TAG_UNDEFINED:
str = "undefined"; str = "undefined";
print_str: print_str:
fprintf(dumpout, "%s", str); fprintf(fp, "%s", str);
break; break;
case JS_TAG_FLOAT64: case JS_TAG_FLOAT64:
fprintf(dumpout, "%.14g", JS_VALUE_GET_FLOAT64(val)); fprintf(fp, "%.14g", JS_VALUE_GET_FLOAT64(val));
break; break;
case JS_TAG_BIG_INT: case JS_TAG_BIG_INT:
{ {
@ -12056,7 +12123,7 @@ static __maybe_unused void JS_DumpValueShort(JSRuntime *rt,
char *str; char *str;
str = bf_ftoa(NULL, &p->num, 10, 0, str = bf_ftoa(NULL, &p->num, 10, 0,
BF_RNDZ | BF_FTOA_FORMAT_FRAC); BF_RNDZ | BF_FTOA_FORMAT_FRAC);
fprintf(dumpout, "%sn", str); fprintf(fp, "%sn", str);
bf_realloc(&rt->bf_ctx, str, 0); bf_realloc(&rt->bf_ctx, str, 0);
} }
break; break;
@ -12067,7 +12134,7 @@ static __maybe_unused void JS_DumpValueShort(JSRuntime *rt,
char *str; char *str;
str = bf_ftoa(NULL, &p->num, 16, BF_PREC_INF, str = bf_ftoa(NULL, &p->num, 16, BF_PREC_INF,
BF_RNDZ | BF_FTOA_FORMAT_FREE | BF_FTOA_ADD_PREFIX); BF_RNDZ | BF_FTOA_FORMAT_FREE | BF_FTOA_ADD_PREFIX);
fprintf(dumpout, "%sl", str); fprintf(fp, "%sl", str);
bf_free(&rt->bf_ctx, str); bf_free(&rt->bf_ctx, str);
} }
break; break;
@ -12077,7 +12144,7 @@ static __maybe_unused void JS_DumpValueShort(JSRuntime *rt,
char *str; char *str;
str = bfdec_ftoa(NULL, &p->num, BF_PREC_INF, str = bfdec_ftoa(NULL, &p->num, BF_PREC_INF,
BF_RNDZ | BF_FTOA_FORMAT_FREE); BF_RNDZ | BF_FTOA_FORMAT_FREE);
fprintf(dumpout, "%sm", str); fprintf(fp, "%sm", str);
bf_free(&rt->bf_ctx, str); bf_free(&rt->bf_ctx, str);
} }
break; break;
@ -12093,7 +12160,7 @@ static __maybe_unused void JS_DumpValueShort(JSRuntime *rt,
{ {
JSFunctionBytecode *b = JS_VALUE_GET_PTR(val); JSFunctionBytecode *b = JS_VALUE_GET_PTR(val);
char buf[ATOM_GET_STR_BUF_SIZE]; char buf[ATOM_GET_STR_BUF_SIZE];
fprintf(dumpout, "[bytecode %s]", JS_AtomGetStrRT(rt, buf, sizeof(buf), b->func_name)); fprintf(fp, "[bytecode %s]", JS_AtomGetStrRT(rt, buf, sizeof(buf), b->func_name));
} }
break; break;
case JS_TAG_OBJECT: case JS_TAG_OBJECT:
@ -12101,7 +12168,7 @@ static __maybe_unused void JS_DumpValueShort(JSRuntime *rt,
JSObject *p = JS_VALUE_GET_OBJ(val); JSObject *p = JS_VALUE_GET_OBJ(val);
JSAtom atom = rt->class_array[p->class_id].class_name; JSAtom atom = rt->class_array[p->class_id].class_name;
char atom_buf[ATOM_GET_STR_BUF_SIZE]; char atom_buf[ATOM_GET_STR_BUF_SIZE];
fprintf(dumpout, "[%s %p]", fprintf(fp, "[%s %p]",
JS_AtomGetStrRT(rt, atom_buf, sizeof(atom_buf), atom), (void *)p); JS_AtomGetStrRT(rt, atom_buf, sizeof(atom_buf), atom), (void *)p);
} }
break; break;
@ -12109,32 +12176,32 @@ static __maybe_unused void JS_DumpValueShort(JSRuntime *rt,
{ {
JSAtomStruct *p = JS_VALUE_GET_PTR(val); JSAtomStruct *p = JS_VALUE_GET_PTR(val);
char atom_buf[ATOM_GET_STR_BUF_SIZE]; char atom_buf[ATOM_GET_STR_BUF_SIZE];
fprintf(dumpout, "Symbol(%s)", fprintf(fp, "Symbol(%s)",
JS_AtomGetStrRT(rt, atom_buf, sizeof(atom_buf), js_get_atom_index(rt, p))); JS_AtomGetStrRT(rt, atom_buf, sizeof(atom_buf), js_get_atom_index(rt, p)));
} }
break; break;
case JS_TAG_MODULE: case JS_TAG_MODULE:
fprintf(dumpout, "[module]"); fprintf(fp, "[module]");
break; break;
default: default:
fprintf(dumpout, "[unknown tag %d]", tag); fprintf(fp, "[unknown tag %d]", tag);
break; break;
} }
} }
static __maybe_unused void JS_DumpValue(JSContext *ctx, static __maybe_unused void JS_DumpValue(FILE *fp, JSContext *ctx,
JSValueConst val) JSValueConst val)
{ {
JS_DumpValueShort(ctx->rt, val); JS_DumpValueShort(fp, ctx->rt, val);
} }
static __maybe_unused void JS_PrintValue(JSContext *ctx, static __maybe_unused void JS_PrintValue(FILE *fp, JSContext *ctx,
const char *str, const char *str,
JSValueConst val) JSValueConst val)
{ {
fprintf(dumpout, "%s=", str); fprintf(fp, "%s=", str);
JS_DumpValueShort(ctx->rt, val); JS_DumpValueShort(fp, ctx->rt, val);
fprintf(dumpout, "\n"); fprintf(fp, "\n");
} }
/* return -1 if exception (proxy case) or TRUE/FALSE */ /* return -1 if exception (proxy case) or TRUE/FALSE */

View file

@ -92,7 +92,11 @@ typedef struct JSRefCountHeader {
} JSRefCountHeader; } JSRefCountHeader;
void quickjs_set_dumpout(FILE *f); void quickjs_set_dumpout(FILE *f);
void quickjs_set_cycleout(FILE *f);
void JS_SetInterruptRate(int count); void JS_SetInterruptRate(int count);
void JS_PrintShapes(JSRuntime *rt);
void JS_PrintAtoms(JSRuntime *rt);
#define JS_FLOAT64_NAN NAN #define JS_FLOAT64_NAN NAN
@ -339,6 +343,7 @@ JSRuntime *JS_NewRuntime(void);
void JS_SetRuntimeInfo(JSRuntime *rt, const char *info); void JS_SetRuntimeInfo(JSRuntime *rt, const char *info);
void JS_SetMemoryLimit(JSRuntime *rt, size_t limit); void JS_SetMemoryLimit(JSRuntime *rt, size_t limit);
void JS_SetGCThreshold(JSRuntime *rt, size_t gc_threshold); void JS_SetGCThreshold(JSRuntime *rt, size_t gc_threshold);
JSValue JS_GetRTInfo(JSRuntime *rt, JSContext *js);
/* use 0 to disable maximum stack size check */ /* use 0 to disable maximum stack size check */
void JS_SetMaxStackSize(JSRuntime *rt, size_t stack_size); void JS_SetMaxStackSize(JSRuntime *rt, size_t stack_size);
/* should be called when changing thread to update the stack top value /* should be called when changing thread to update the stack top value
@ -404,6 +409,7 @@ char *js_strndup(JSContext *ctx, const char *s, size_t n);
typedef struct JSMemoryUsage { typedef struct JSMemoryUsage {
int64_t malloc_size, malloc_limit, memory_used_size; int64_t malloc_size, malloc_limit, memory_used_size;
int64_t gc_threshold;
int64_t malloc_count; int64_t malloc_count;
int64_t memory_used_count; int64_t memory_used_count;
int64_t atom_count, atom_size; int64_t atom_count, atom_size;
@ -419,7 +425,10 @@ typedef struct JSMemoryUsage {
} JSMemoryUsage; } JSMemoryUsage;
void JS_ComputeMemoryUsage(JSRuntime *rt, JSMemoryUsage *s); void JS_ComputeMemoryUsage(JSRuntime *rt, JSMemoryUsage *s);
void JS_FillMemoryState(JSRuntime *rt, JSMemoryUsage *s);
void JS_DumpMemoryUsage(FILE *fp, const JSMemoryUsage *s, JSRuntime *rt); void JS_DumpMemoryUsage(FILE *fp, const JSMemoryUsage *s, JSRuntime *rt);
void JS_DumpMyValue(JSRuntime *rt, JSValue v);
double JS_MyValueSize(JSRuntime *rt, JSValue v);
/* atom support */ /* atom support */
#define JS_ATOM_NULL 0 #define JS_ATOM_NULL 0