Improve dump option support (#344)

- DUMP_XXX defined as nothing or 0 produces unconditional output
- DUMP_XXX defined as a bitmask produces conditional output based
    on command line option -d<bitmask>
- add `JS_SetDumpFlags()` to select active dump options
- accept -d[<hex mask>] and --dump[=<hex mask>] to specify active
    dump options, generalize command line option handling
- improve DUMP_READ_OBJECT output, fix indentation issue
This commit is contained in:
Charlie Gordon 2024-04-14 02:00:19 +02:00 committed by GitHub
parent bb674c0c3b
commit 16e7661fa0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 248 additions and 139 deletions

61
qjs.c
View file

@ -289,6 +289,7 @@ int main(int argc, char **argv)
char *expr = NULL; char *expr = NULL;
int interactive = 0; int interactive = 0;
int dump_memory = 0; int dump_memory = 0;
int dump_flags = 0;
int trace_memory = 0; int trace_memory = 0;
int empty_run = 0; int empty_run = 0;
int module = -1; int module = -1;
@ -308,12 +309,16 @@ int main(int argc, char **argv)
while (optind < argc && *argv[optind] == '-') { while (optind < argc && *argv[optind] == '-') {
char *arg = argv[optind] + 1; char *arg = argv[optind] + 1;
const char *longopt = ""; const char *longopt = "";
char *opt_arg = NULL;
/* a single - is not an option, it also stops argument scanning */ /* a single - is not an option, it also stops argument scanning */
if (!*arg) if (!*arg)
break; break;
optind++; optind++;
if (*arg == '-') { if (*arg == '-') {
longopt = arg + 1; longopt = arg + 1;
opt_arg = strchr(longopt, '=');
if (opt_arg)
*opt_arg++ = '\0';
arg += strlen(arg); arg += strlen(arg);
/* -- stops argument scanning */ /* -- stops argument scanning */
if (!*longopt) if (!*longopt)
@ -321,23 +326,25 @@ int main(int argc, char **argv)
} }
for (; *arg || *longopt; longopt = "") { for (; *arg || *longopt; longopt = "") {
char opt = *arg; char opt = *arg;
if (opt) if (opt) {
arg++; arg++;
if (!opt_arg && *arg)
opt_arg = arg;
}
if (opt == 'h' || opt == '?' || !strcmp(longopt, "help")) { if (opt == 'h' || opt == '?' || !strcmp(longopt, "help")) {
help(); help();
continue; continue;
} }
if (opt == 'e' || !strcmp(longopt, "eval")) { if (opt == 'e' || !strcmp(longopt, "eval")) {
if (*arg) { if (!opt_arg) {
expr = arg; if (optind >= argc) {
break; fprintf(stderr, "qjs: missing expression for -e\n");
exit(2);
}
opt_arg = argv[optind++];
} }
if (optind < argc) { expr = opt_arg;
expr = argv[optind++]; break;
break;
}
fprintf(stderr, "qjs: missing expression for -e\n");
exit(2);
} }
if (opt == 'I' || !strcmp(longopt, "include")) { if (opt == 'I' || !strcmp(longopt, "include")) {
if (optind >= argc) { if (optind >= argc) {
@ -364,6 +371,10 @@ int main(int argc, char **argv)
continue; continue;
} }
if (opt == 'd' || !strcmp(longopt, "dump")) { if (opt == 'd' || !strcmp(longopt, "dump")) {
if (opt_arg) {
dump_flags = strtol(opt_arg, NULL, 16);
break;
}
dump_memory++; dump_memory++;
continue; continue;
} }
@ -384,20 +395,28 @@ int main(int argc, char **argv)
continue; continue;
} }
if (!strcmp(longopt, "memory-limit")) { if (!strcmp(longopt, "memory-limit")) {
if (optind >= argc) { if (!opt_arg) {
fprintf(stderr, "expecting memory limit"); if (optind >= argc) {
exit(1); fprintf(stderr, "expecting memory limit");
exit(1);
}
opt_arg = argv[optind++];
} }
memory_limit = (size_t)strtod(argv[optind++], NULL); // TODO(chqrlie): accept kmg suffixes
continue; memory_limit = (size_t)strtod(opt_arg, NULL);
break;
} }
if (!strcmp(longopt, "stack-size")) { if (!strcmp(longopt, "stack-size")) {
if (optind >= argc) { if (!opt_arg) {
fprintf(stderr, "expecting stack size"); if (optind >= argc) {
exit(1); fprintf(stderr, "expecting stack size");
exit(1);
}
opt_arg = argv[optind++];
} }
stack_size = (size_t)strtod(argv[optind++], NULL); // TODO(chqrlie): accept kmg suffixes
continue; stack_size = (size_t)strtod(opt_arg, NULL);
break;
} }
if (opt) { if (opt) {
fprintf(stderr, "qjs: unknown option '-%c'\n", opt); fprintf(stderr, "qjs: unknown option '-%c'\n", opt);
@ -422,6 +441,8 @@ int main(int argc, char **argv)
JS_SetMemoryLimit(rt, memory_limit); JS_SetMemoryLimit(rt, memory_limit);
if (stack_size != 0) if (stack_size != 0)
JS_SetMaxStackSize(rt, stack_size); JS_SetMaxStackSize(rt, stack_size);
if (dump_flags != 0)
JS_SetDumpFlags(rt, dump_flags);
js_std_set_worker_new_context_func(JS_NewCustomContext); js_std_set_worker_new_context_func(JS_NewCustomContext);
js_std_init_handlers(rt); js_std_init_handlers(rt);
ctx = JS_NewCustomContext(rt); ctx = JS_NewCustomContext(rt);

325
quickjs.c
View file

@ -72,37 +72,35 @@
#define CONFIG_ATOMICS #define CONFIG_ATOMICS
#endif #endif
/* dump object free */ // Debug trace system:
//#define DUMP_FREE // uncomment one or more DUMP_XXX definition to produce debug output.
//#define DUMP_CLOSURE // define the DUMP_XXX symbol as empty or 0 for unconditional output
/* dump the bytecode of the compiled functions: combination of bits // otherwhise the debug output will be produced to the dump stream (currently
1: dump pass 3 final byte code // stdout) if qjs is invoked with -d<bitmask> with the corresponding bit set.
2: dump pass 2 code
4: dump pass 1 code
8: dump stdlib functions
16: dump bytecode in hex
32: dump line number table
64: dump compute_stack_size
128: dump executed bytecode
*/
//#define DUMP_BYTECODE (1)
/* dump the occurence of the automatic GC */
//#define DUMP_GC
/* dump objects freed by the garbage collector */
//#define DUMP_GC_FREE
/* dump objects leaking when freeing the runtime */
//#define DUMP_LEAKS 1
/* dump memory usage before running the garbage collector */
//#define DUMP_MEM
//#define DUMP_OBJECTS /* dump objects in JS_FreeContext */
//#define DUMP_ATOMS /* dump atoms in JS_FreeContext */
//#define DUMP_SHAPES /* dump shapes in JS_FreeContext */
//#define DUMP_MODULE_RESOLVE
//#define DUMP_PROMISE
//#define DUMP_READ_OBJECT
/* test the GC by forcing it before each object allocation */ //#define DUMP_BYTECODE_FINAL 0x01 /* dump pass 3 final byte code */
//#define FORCE_GC_AT_MALLOC //#define DUMP_BYTECODE_PASS2 0x02 /* dump pass 2 code */
//#define DUMP_BYTECODE_PASS1 0x04 /* dump pass 1 code */
//#define DUMP_BYTECODE_HEX 0x10 /* dump bytecode in hex */
//#define DUMP_BYTECODE_PC2LINE 0x20 /* dump line number table */
//#define DUMP_BYTECODE_STACK 0x40 /* dump compute_stack_size */
//#define DUMP_BYTECODE_STEP 0x80 /* dump executed bytecode */
//#define DUMP_READ_OBJECT 0x100 /* dump the marshalled objects at load time */
//#define DUMP_FREE 0x200 /* dump every object free */
//#define DUMP_GC 0x400 /* dump the occurrence of the automatic GC */
//#define DUMP_GC_FREE 0x800 /* dump objects freed by the GC */
//#define DUMP_MODULE_RESOLVE 0x1000 /* dump module resolution steps */
//#define DUMP_PROMISE 0x2000 /* dump promise steps */
//#define DUMP_LEAKS 0x4000 /* dump leaked objects and strings in JS_FreeRuntime */
//#define DUMP_ATOM_LEAKS 0x8000 /* dump leaked atoms in JS_FreeRuntime */
//#define DUMP_MEM 0x10000 /* dump memory usage in JS_FreeRuntime */
//#define DUMP_OBJECTS 0x20000 /* dump objects in JS_FreeRuntime */
//#define DUMP_ATOMS 0x40000 /* dump atoms in JS_FreeRuntime */
//#define DUMP_SHAPES 0x80000 /* dump shapes in JS_FreeRuntime */
//#define FORCE_GC_AT_MALLOC /* test the GC by forcing it before each object allocation */
#define check_dump_flag(rt, flag) ((rt->dump_flags & (flag +0)) == (flag +0))
#define STRINGIFY_(x) #x #define STRINGIFY_(x) #x
#define STRINGIFY(x) STRINGIFY_(x) #define STRINGIFY(x) STRINGIFY_(x)
@ -271,10 +269,12 @@ struct JSRuntime {
JSModuleLoaderFunc *module_loader_func; JSModuleLoaderFunc *module_loader_func;
void *module_loader_opaque; void *module_loader_opaque;
BOOL can_block : 8; /* TRUE if Atomics.wait can block */
/* used to allocate, free and clone SharedArrayBuffers */ /* used to allocate, free and clone SharedArrayBuffers */
JSSharedArrayBufferFunctions sab_funcs; JSSharedArrayBufferFunctions sab_funcs;
BOOL can_block : 8; /* TRUE if Atomics.wait can block */
uint32_t dump_flags : 24;
/* Shape hash table */ /* Shape hash table */
int shape_hash_bits; int shape_hash_bits;
int shape_hash_size; int shape_hash_size;
@ -1348,8 +1348,10 @@ static void js_trigger_gc(JSRuntime *rt, size_t size)
#endif #endif
if (force_gc) { if (force_gc) {
#ifdef DUMP_GC #ifdef DUMP_GC
printf("GC: size=%" PRIu64 "\n", if (check_dump_flag(rt, DUMP_GC)) {
(uint64_t)rt->malloc_state.malloc_size); printf("GC: size=%" PRIu64 "\n",
(uint64_t)rt->malloc_state.malloc_size);
}
#endif #endif
JS_RunGC(rt); JS_RunGC(rt);
rt->malloc_gc_threshold = rt->malloc_state.malloc_size + rt->malloc_gc_threshold = rt->malloc_state.malloc_size +
@ -1758,6 +1760,11 @@ void JS_SetMemoryLimit(JSRuntime *rt, size_t limit)
rt->malloc_state.malloc_limit = limit; rt->malloc_state.malloc_limit = limit;
} }
void JS_SetDumpFlags(JSRuntime *rt, uint64_t flags)
{
rt->dump_flags = flags;
}
/* use -1 to disable automatic GC */ /* use -1 to disable automatic GC */
void JS_SetGCThreshold(JSRuntime *rt, size_t gc_threshold) void JS_SetGCThreshold(JSRuntime *rt, size_t gc_threshold)
{ {
@ -1927,7 +1934,7 @@ void JS_FreeRuntime(JSRuntime *rt)
#ifdef DUMP_LEAKS #ifdef DUMP_LEAKS
/* leaking objects */ /* leaking objects */
{ if (check_dump_flag(rt, DUMP_LEAKS)) {
BOOL header_done; BOOL header_done;
JSGCObjectHeader *p; JSGCObjectHeader *p;
int count; int count;
@ -1977,9 +1984,9 @@ void JS_FreeRuntime(JSRuntime *rt)
bf_context_end(&rt->bf_ctx); bf_context_end(&rt->bf_ctx);
#ifdef DUMP_LEAKS #ifdef DUMP_ATOM_LEAKS
/* only the atoms defined in JS_InitAtoms() should be left */ /* only the atoms defined in JS_InitAtoms() should be left */
{ if (check_dump_flag(rt, DUMP_ATOM_LEAKS)) {
BOOL header_done = FALSE; BOOL header_done = FALSE;
for(i = 0; i < rt->atom_size; i++) { for(i = 0; i < rt->atom_size; i++) {
@ -2049,7 +2056,7 @@ void JS_FreeRuntime(JSRuntime *rt)
js_free_rt(rt, rt->atom_hash); js_free_rt(rt, rt->atom_hash);
js_free_rt(rt, rt->shape_hash); js_free_rt(rt, rt->shape_hash);
#ifdef DUMP_LEAKS #ifdef DUMP_LEAKS
if (!list_empty(&rt->string_list)) { if (check_dump_flag(rt, DUMP_LEAKS) && !list_empty(&rt->string_list)) {
if (rt->rt_info) { if (rt->rt_info) {
printf("%s:1: string leakage:", rt->rt_info); printf("%s:1: string leakage:", rt->rt_info);
} else { } else {
@ -2076,7 +2083,7 @@ void JS_FreeRuntime(JSRuntime *rt)
if (rt->rt_info) if (rt->rt_info)
printf("\n"); printf("\n");
} }
{ if (check_dump_flag(rt, DUMP_LEAKS)) {
JSMallocState *s = &rt->malloc_state; JSMallocState *s = &rt->malloc_state;
if (s->malloc_count > 1) { if (s->malloc_count > 1) {
if (rt->rt_info) if (rt->rt_info)
@ -2265,13 +2272,15 @@ void JS_FreeContext(JSContext *ctx)
assert(ctx->header.ref_count == 0); assert(ctx->header.ref_count == 0);
#ifdef DUMP_ATOMS #ifdef DUMP_ATOMS
JS_DumpAtoms(ctx->rt); if (check_dump_flag(rt, DUMP_ATOMS))
JS_DumpAtoms(ctx->rt);
#endif #endif
#ifdef DUMP_SHAPES #ifdef DUMP_SHAPES
JS_DumpShapes(ctx->rt); if (check_dump_flag(rt, DUMP_SHAPES))
JS_DumpShapes(ctx->rt);
#endif #endif
#ifdef DUMP_OBJECTS #ifdef DUMP_OBJECTS
{ if (check_dump_flag(rt, DUMP_OBJECTS)) {
struct list_head *el; struct list_head *el;
JSGCObjectHeader *p; JSGCObjectHeader *p;
printf("JSObjects: {\n"); printf("JSObjects: {\n");
@ -2284,7 +2293,7 @@ void JS_FreeContext(JSContext *ctx)
} }
#endif #endif
#ifdef DUMP_MEM #ifdef DUMP_MEM
{ if (check_dump_flag(rt, DUMP_MEM)) {
JSMemoryUsage stats; JSMemoryUsage stats;
JS_ComputeMemoryUsage(rt, &stats); JS_ComputeMemoryUsage(rt, &stats);
JS_DumpMemoryUsage(stdout, &stats, rt); JS_DumpMemoryUsage(stdout, &stats, rt);
@ -2371,7 +2380,7 @@ static inline BOOL is_strict_mode(JSContext *ctx)
static inline BOOL __JS_AtomIsConst(JSAtom v) static inline BOOL __JS_AtomIsConst(JSAtom v)
{ {
#if defined(DUMP_LEAKS) && DUMP_LEAKS > 1 #ifdef DUMP_ATOM_LEAKS
return (int32_t)v <= 0; return (int32_t)v <= 0;
#else #else
return (int32_t)v < JS_ATOM_END; return (int32_t)v < JS_ATOM_END;
@ -5456,7 +5465,7 @@ void __JS_FreeValueRT(JSRuntime *rt, JSValue v)
uint32_t tag = JS_VALUE_GET_TAG(v); uint32_t tag = JS_VALUE_GET_TAG(v);
#ifdef DUMP_FREE #ifdef DUMP_FREE
{ if (check_dump_flag(rt, DUMP_FREE)) {
/* Prevent invalid object access during GC */ /* Prevent invalid object access during GC */
if ((rt->gc_phase != JS_GC_PHASE_REMOVE_CYCLES) if ((rt->gc_phase != JS_GC_PHASE_REMOVE_CYCLES)
|| (tag != JS_TAG_OBJECT && tag != JS_TAG_FUNCTION_BYTECODE)) { || (tag != JS_TAG_OBJECT && tag != JS_TAG_FUNCTION_BYTECODE)) {
@ -5749,12 +5758,14 @@ 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:
#ifdef DUMP_GC_FREE #ifdef DUMP_GC_FREE
if (!header_done) { if (check_dump_flag(rt, DUMP_GC_FREE)) {
printf("Freeing cycles:\n"); if (!header_done) {
JS_DumpObjectHeader(rt); printf("Freeing cycles:\n");
header_done = TRUE; JS_DumpObjectHeader(rt);
header_done = TRUE;
}
JS_DumpGCObject(rt, p);
} }
JS_DumpGCObject(rt, p);
#endif #endif
free_gc_object(rt, p); free_gc_object(rt, p);
break; break;
@ -14488,6 +14499,15 @@ typedef enum {
#define FUNC_RET_YIELD 1 #define FUNC_RET_YIELD 1
#define FUNC_RET_YIELD_STAR 2 #define FUNC_RET_YIELD_STAR 2
#if defined(DUMP_BYTECODE_FINAL) || \
defined(DUMP_BYTECODE_PASS2) || \
defined(DUMP_BYTECODE_PASS1) || \
defined(DUMP_BYTECODE_STACK) || \
defined(DUMP_BYTECODE_STEP) || \
defined(DUMP_READ_OBJECT)
#define DUMP_BYTECODE
#endif
#ifdef DUMP_BYTECODE #ifdef DUMP_BYTECODE
static void dump_single_byte_code(JSContext *ctx, const uint8_t *pc, static void dump_single_byte_code(JSContext *ctx, const uint8_t *pc,
JSFunctionBytecode *b); JSFunctionBytecode *b);
@ -14511,8 +14531,9 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValue func_obj,
size_t alloca_size; size_t alloca_size;
JSInlineCache *ic; JSInlineCache *ic;
#if defined(DUMP_BYTECODE) && (DUMP_BYTECODE & 128) #ifdef DUMP_BYTECODE_STEP
#define DUMP_BYTECODE_OR_DONT(pc) dump_single_byte_code(ctx, pc, b); #define DUMP_BYTECODE_OR_DONT(pc) \
if (check_dump_flag(ctx->rt, DUMP_BYTECODE_STEP)) dump_single_byte_code(ctx, pc, b);
#else #else
#define DUMP_BYTECODE_OR_DONT(pc) #define DUMP_BYTECODE_OR_DONT(pc)
#endif #endif
@ -14622,8 +14643,9 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValue func_obj,
ctx = b->realm; /* set the current realm */ ctx = b->realm; /* set the current realm */
ic = b->ic; ic = b->ic;
#if defined(DUMP_BYTECODE) && (DUMP_BYTECODE & 128) #ifdef DUMP_BYTECODE_STEP
print_func_name(b); if (check_dump_flag(ctx->rt, DUMP_BYTECODE_STEP))
print_func_name(b);
#endif #endif
restart: restart:
@ -26342,6 +26364,14 @@ JSValue JS_GetModuleNamespace(JSContext *ctx, JSModuleDef *m)
return js_dup(m->module_ns); return js_dup(m->module_ns);
} }
#ifdef DUMP_MODULE_RESOLVE
#define module_trace(ctx, ...) \
do if (check_dump_flag(ctx->rt, DUMP_MODULE_RESOLVE)) \
printf(__VA_ARGS__); while (0)
#else
#define module_trace(...)
#endif
/* Load all the required modules for module 'm' */ /* Load all the required modules for module 'm' */
static int js_resolve_module(JSContext *ctx, JSModuleDef *m) static int js_resolve_module(JSContext *ctx, JSModuleDef *m)
{ {
@ -26351,7 +26381,7 @@ static int js_resolve_module(JSContext *ctx, JSModuleDef *m)
if (m->resolved) if (m->resolved)
return 0; return 0;
#ifdef DUMP_MODULE_RESOLVE #ifdef DUMP_MODULE_RESOLVE
{ if (check_dump_flag(ctx->rt, DUMP_MODULE_RESOLVE)) {
char buf1[ATOM_GET_STR_BUF_SIZE]; char buf1[ATOM_GET_STR_BUF_SIZE];
printf("resolving module '%s':\n", JS_AtomGetStr(ctx, buf1, sizeof(buf1), m->module_name)); printf("resolving module '%s':\n", JS_AtomGetStr(ctx, buf1, sizeof(buf1), m->module_name));
} }
@ -26427,9 +26457,9 @@ static int js_create_module_bytecode_function(JSContext *ctx, JSModuleDef *m)
var_ref = js_create_module_var(ctx, cv->is_lexical); var_ref = js_create_module_var(ctx, cv->is_lexical);
if (!var_ref) if (!var_ref)
goto fail; goto fail;
#ifdef DUMP_MODULE_RESOLVE
printf("local %d: %p\n", i, var_ref); module_trace(ctx, "local %d: %p\n", i, var_ref);
#endif
var_refs[i] = var_ref; var_refs[i] = var_ref;
} }
} }
@ -26500,7 +26530,7 @@ static int js_link_module(JSContext *ctx, JSModuleDef *m)
m->instantiated = TRUE; m->instantiated = TRUE;
#ifdef DUMP_MODULE_RESOLVE #ifdef DUMP_MODULE_RESOLVE
{ if (check_dump_flag(ctx->rt, DUMP_MODULE_RESOLVE)) {
char buf1[ATOM_GET_STR_BUF_SIZE]; char buf1[ATOM_GET_STR_BUF_SIZE];
printf("start instantiating module '%s':\n", JS_AtomGetStr(ctx, buf1, sizeof(buf1), m->module_name)); printf("start instantiating module '%s':\n", JS_AtomGetStr(ctx, buf1, sizeof(buf1), m->module_name));
} }
@ -26513,7 +26543,7 @@ static int js_link_module(JSContext *ctx, JSModuleDef *m)
} }
#ifdef DUMP_MODULE_RESOLVE #ifdef DUMP_MODULE_RESOLVE
{ if (check_dump_flag(ctx->rt, DUMP_MODULE_RESOLVE)) {
char buf1[ATOM_GET_STR_BUF_SIZE]; char buf1[ATOM_GET_STR_BUF_SIZE];
printf("instantiating module '%s':\n", JS_AtomGetStr(ctx, buf1, sizeof(buf1), m->module_name)); printf("instantiating module '%s':\n", JS_AtomGetStr(ctx, buf1, sizeof(buf1), m->module_name));
} }
@ -26536,7 +26566,7 @@ static int js_link_module(JSContext *ctx, JSModuleDef *m)
} }
#ifdef DUMP_MODULE_RESOLVE #ifdef DUMP_MODULE_RESOLVE
{ if (check_dump_flag(ctx->rt, DUMP_MODULE_RESOLVE)) {
printf("exported bindings:\n"); printf("exported bindings:\n");
for(i = 0; i < m->export_entries_count; i++) { for(i = 0; i < m->export_entries_count; i++) {
JSExportEntry *me = &m->export_entries[i]; JSExportEntry *me = &m->export_entries[i];
@ -26556,9 +26586,11 @@ static int js_link_module(JSContext *ctx, JSModuleDef *m)
for(i = 0; i < m->import_entries_count; i++) { for(i = 0; i < m->import_entries_count; i++) {
mi = &m->import_entries[i]; mi = &m->import_entries[i];
#ifdef DUMP_MODULE_RESOLVE #ifdef DUMP_MODULE_RESOLVE
printf("import var_idx=%d name=", mi->var_idx); if (check_dump_flag(ctx->rt, DUMP_MODULE_RESOLVE)) {
print_atom(ctx, mi->import_name); printf("import var_idx=%d name=", mi->var_idx);
printf(": "); print_atom(ctx, mi->import_name);
printf(": ");
}
#endif #endif
m1 = m->req_module_entries[mi->req_module_idx].module; m1 = m->req_module_entries[mi->req_module_idx].module;
if (mi->import_name == JS_ATOM__star_) { if (mi->import_name == JS_ATOM__star_) {
@ -26568,9 +26600,9 @@ static int js_link_module(JSContext *ctx, JSModuleDef *m)
if (JS_IsException(val)) if (JS_IsException(val))
goto fail; goto fail;
set_value(ctx, &var_refs[mi->var_idx]->value, val); set_value(ctx, &var_refs[mi->var_idx]->value, val);
#ifdef DUMP_MODULE_RESOLVE
printf("namespace\n"); module_trace(ctx, "namespace\n");
#endif
} else { } else {
JSResolveResultEnum ret; JSResolveResultEnum ret;
JSExportEntry *res_me; JSExportEntry *res_me;
@ -26598,9 +26630,9 @@ static int js_link_module(JSContext *ctx, JSModuleDef *m)
} }
set_value(ctx, &var_ref->value, val); set_value(ctx, &var_ref->value, val);
var_refs[mi->var_idx] = var_ref; var_refs[mi->var_idx] = var_ref;
#ifdef DUMP_MODULE_RESOLVE
printf("namespace from\n"); module_trace(ctx, "namespace from\n");
#endif
} else { } else {
var_ref = res_me->u.local.var_ref; var_ref = res_me->u.local.var_ref;
if (!var_ref) { if (!var_ref) {
@ -26609,9 +26641,8 @@ static int js_link_module(JSContext *ctx, JSModuleDef *m)
} }
var_ref->header.ref_count++; var_ref->header.ref_count++;
var_refs[mi->var_idx] = var_ref; var_refs[mi->var_idx] = var_ref;
#ifdef DUMP_MODULE_RESOLVE
printf("local export (var_ref=%p)\n", var_ref); module_trace(ctx, "local export (var_ref=%p)\n", var_ref);
#endif
} }
} }
} }
@ -26635,9 +26666,8 @@ static int js_link_module(JSContext *ctx, JSModuleDef *m)
JS_FreeValue(ctx, ret_val); JS_FreeValue(ctx, ret_val);
} }
#ifdef DUMP_MODULE_RESOLVE module_trace(ctx, "done instantiate\n");
printf("done instantiate\n");
#endif
return 0; return 0;
fail: fail:
return -1; return -1;
@ -27607,8 +27637,8 @@ static void dump_byte_code(JSContext *ctx, int pass,
printf("truncated opcode (0x%02x)\n", op); printf("truncated opcode (0x%02x)\n", op);
break; break;
} }
#if defined(DUMP_BYTECODE) && (DUMP_BYTECODE & 16) #ifdef DUMP_BYTECODE_HEX
{ if (check_dump_flag(ctx->rt, DUMP_BYTECODE_HEX)) {
int i, x, x0; int i, x, x0;
x = x0 = printf("%5d ", pos); x = x0 = printf("%5d ", pos);
for (i = 0; i < size; i++) { for (i = 0; i < size; i++) {
@ -27923,8 +27953,9 @@ static __maybe_unused void js_dump_function_bytecode(JSContext *ctx, JSFunctionB
b->closure_var, b->closure_var_count, b->closure_var, b->closure_var_count,
b->cpool, b->cpool_count, b->cpool, b->cpool_count,
b->source, b->line_num, NULL, b); b->source, b->line_num, NULL, b);
#if defined(DUMP_BYTECODE) && (DUMP_BYTECODE & 32) #ifdef DUMP_BYTECODE_PC2LINE
dump_pc2line(ctx, b->pc2line_buf, b->pc2line_len, b->line_num, b->col_num); if (check_dump_flag(ctx->rt, DUMP_BYTECODE_PC2LINE))
dump_pc2line(ctx, b->pc2line_buf, b->pc2line_len, b->line_num, b->col_num);
#endif #endif
printf("\n"); printf("\n");
} }
@ -30968,8 +30999,9 @@ static __exception int compute_stack_size(JSContext *ctx,
goto fail; goto fail;
} }
oi = &short_opcode_info(op); oi = &short_opcode_info(op);
#if defined(DUMP_BYTECODE) && (DUMP_BYTECODE & 64) #ifdef DUMP_BYTECODE_STACK
printf("%5d: %10s %5d %5d\n", pos, oi->name, stack_len, catch_pos); if (check_dump_flag(ctx->rt, DUMP_BYTECODE_STACK))
printf("%5d: %10s %5d %5d\n", pos, oi->name, stack_len, catch_pos);
#endif #endif
pos_next = pos + oi->size; pos_next = pos + oi->size;
if (pos_next > s->bc_len) { if (pos_next > s->bc_len) {
@ -31223,27 +31255,31 @@ static JSValue js_create_function(JSContext *ctx, JSFunctionDef *fd)
fd->cpool[cpool_idx] = func_obj; fd->cpool[cpool_idx] = func_obj;
} }
#if defined(DUMP_BYTECODE) && (DUMP_BYTECODE & 4) #ifdef DUMP_BYTECODE_PASS1
printf("pass 1\n"); if (check_dump_flag(ctx->rt, DUMP_BYTECODE_PASS1)) {
dump_byte_code(ctx, 1, fd->byte_code.buf, fd->byte_code.size, printf("pass 1\n");
fd->args, fd->arg_count, fd->vars, fd->var_count, dump_byte_code(ctx, 1, fd->byte_code.buf, fd->byte_code.size,
fd->closure_var, fd->closure_var_count, fd->args, fd->arg_count, fd->vars, fd->var_count,
fd->cpool, fd->cpool_count, fd->source, fd->line_num, fd->closure_var, fd->closure_var_count,
fd->label_slots, NULL); fd->cpool, fd->cpool_count, fd->source, fd->line_num,
printf("\n"); fd->label_slots, NULL);
printf("\n");
}
#endif #endif
if (resolve_variables(ctx, fd)) if (resolve_variables(ctx, fd))
goto fail; goto fail;
#if defined(DUMP_BYTECODE) && (DUMP_BYTECODE & 2) #ifdef DUMP_BYTECODE_PASS2
printf("pass 2\n"); if (check_dump_flag(ctx->rt, DUMP_BYTECODE_PASS2)) {
dump_byte_code(ctx, 2, fd->byte_code.buf, fd->byte_code.size, printf("pass 2\n");
fd->args, fd->arg_count, fd->vars, fd->var_count, dump_byte_code(ctx, 2, fd->byte_code.buf, fd->byte_code.size,
fd->closure_var, fd->closure_var_count, fd->args, fd->arg_count, fd->vars, fd->var_count,
fd->cpool, fd->cpool_count, fd->source, fd->line_num, fd->closure_var, fd->closure_var_count,
fd->label_slots, NULL); fd->cpool, fd->cpool_count, fd->source, fd->line_num,
printf("\n"); fd->label_slots, NULL);
printf("\n");
}
#endif #endif
if (resolve_labels(ctx, fd)) if (resolve_labels(ctx, fd))
@ -31344,8 +31380,9 @@ static JSValue js_create_function(JSContext *ctx, JSFunctionDef *fd)
add_gc_object(ctx->rt, &b->header, JS_GC_OBJ_TYPE_FUNCTION_BYTECODE); add_gc_object(ctx->rt, &b->header, JS_GC_OBJ_TYPE_FUNCTION_BYTECODE);
#if defined(DUMP_BYTECODE) && (DUMP_BYTECODE & 1) #ifdef DUMP_BYTECODE_FINAL
js_dump_function_bytecode(ctx, b); if (check_dump_flag(ctx->rt, DUMP_BYTECODE_FINAL))
js_dump_function_bytecode(ctx, b);
#endif #endif
if (fd->parent) { if (fd->parent) {
@ -33425,6 +33462,9 @@ static void __attribute__((format(printf, 2, 3))) bc_read_trace(BCReaderState *s
va_list ap; va_list ap;
int i, n, n0; int i, n, n0;
if (!check_dump_flag(s->ctx->rt, DUMP_READ_OBJECT))
return;
if (!s->ptr_last) if (!s->ptr_last)
s->ptr_last = s->buf_start; s->ptr_last = s->buf_start;
@ -33635,7 +33675,11 @@ static JSString *JS_ReadString(BCReaderState *s)
p->u.str8[size] = '\0'; /* add the trailing zero for 8 bit strings */ p->u.str8[size] = '\0'; /* add the trailing zero for 8 bit strings */
} }
#ifdef DUMP_READ_OBJECT #ifdef DUMP_READ_OBJECT
JS_DumpString(s->ctx->rt, p); printf("\n"); if (check_dump_flag(s->ctx->rt, DUMP_READ_OBJECT)) {
bc_read_trace(s, ""); // hex dump and indentation
JS_DumpString(s->ctx->rt, p);
printf("\n");
}
#endif #endif
return p; return p;
} }
@ -33683,7 +33727,11 @@ static int JS_ReadFunctionBytecode(BCReaderState *s, JSFunctionBytecode *b,
} }
put_u32(bc_buf + pos + 1, atom); put_u32(bc_buf + pos + 1, atom);
#ifdef DUMP_READ_OBJECT #ifdef DUMP_READ_OBJECT
bc_read_trace(s, "at %d, fixup atom: ", pos + 1); print_atom(s->ctx, atom); printf("\n"); if (check_dump_flag(s->ctx->rt, DUMP_READ_OBJECT)) {
bc_read_trace(s, "at %d, fixup atom: ", pos + 1);
print_atom(s->ctx, atom);
printf("\n");
}
#endif #endif
break; break;
default: default:
@ -33767,7 +33815,6 @@ static JSValue JS_ReadBigInt(BCReaderState *s)
a->tab[i] = v; a->tab[i] = v;
} }
} }
bc_read_trace(s, "}\n");
return obj; return obj;
fail: fail:
JS_FreeValue(s->ctx, obj); JS_FreeValue(s->ctx, obj);
@ -33876,7 +33923,13 @@ static JSValue JS_ReadFunctionTag(BCReaderState *s)
obj = JS_MKPTR(JS_TAG_FUNCTION_BYTECODE, b); obj = JS_MKPTR(JS_TAG_FUNCTION_BYTECODE, b);
#ifdef DUMP_READ_OBJECT #ifdef DUMP_READ_OBJECT
bc_read_trace(s, "name: "); print_atom(s->ctx, b->func_name); printf("\n"); if (check_dump_flag(s->ctx->rt, DUMP_READ_OBJECT)) {
if (b->func_name) {
bc_read_trace(s, "name: ");
print_atom(s->ctx, b->func_name);
printf("\n");
}
}
#endif #endif
bc_read_trace(s, "args=%d vars=%d defargs=%d closures=%d cpool=%d\n", bc_read_trace(s, "args=%d vars=%d defargs=%d closures=%d cpool=%d\n",
b->arg_count, b->var_count, b->defined_arg_count, b->arg_count, b->var_count, b->defined_arg_count,
@ -33903,7 +33956,11 @@ static JSValue JS_ReadFunctionTag(BCReaderState *s)
vd->is_lexical = bc_get_flags(v8, &idx, 1); vd->is_lexical = bc_get_flags(v8, &idx, 1);
vd->is_captured = bc_get_flags(v8, &idx, 1); vd->is_captured = bc_get_flags(v8, &idx, 1);
#ifdef DUMP_READ_OBJECT #ifdef DUMP_READ_OBJECT
bc_read_trace(s, "name: "); print_atom(s->ctx, vd->var_name); printf("\n"); if (check_dump_flag(s->ctx->rt, DUMP_READ_OBJECT)) {
bc_read_trace(s, "name: ");
print_atom(s->ctx, vd->var_name);
printf("\n");
}
#endif #endif
} }
bc_read_trace(s, "}\n"); bc_read_trace(s, "}\n");
@ -33927,7 +33984,11 @@ static JSValue JS_ReadFunctionTag(BCReaderState *s)
cv->is_lexical = bc_get_flags(v8, &idx, 1); cv->is_lexical = bc_get_flags(v8, &idx, 1);
cv->var_kind = bc_get_flags(v8, &idx, 4); cv->var_kind = bc_get_flags(v8, &idx, 4);
#ifdef DUMP_READ_OBJECT #ifdef DUMP_READ_OBJECT
bc_read_trace(s, "name: "); print_atom(s->ctx, cv->var_name); printf("\n"); if (check_dump_flag(s->ctx->rt, DUMP_READ_OBJECT)) {
bc_read_trace(s, "name: ");
print_atom(s->ctx, cv->var_name);
printf("\n");
}
#endif #endif
} }
bc_read_trace(s, "}\n"); bc_read_trace(s, "}\n");
@ -33946,9 +34007,17 @@ static JSValue JS_ReadFunctionTag(BCReaderState *s)
goto fail; goto fail;
if (bc_get_leb128_int(s, &b->col_num)) if (bc_get_leb128_int(s, &b->col_num))
goto fail; goto fail;
#ifdef DUMP_READ_OBJECT
if (check_dump_flag(s->ctx->rt, DUMP_READ_OBJECT)) {
bc_read_trace(s, "filename: ");
print_atom(s->ctx, b->filename);
printf(", line: %d, column: %d\n", b->line_num, b->col_num);
}
#endif
if (bc_get_leb128_int(s, &b->pc2line_len)) if (bc_get_leb128_int(s, &b->pc2line_len))
goto fail; goto fail;
if (b->pc2line_len) { if (b->pc2line_len) {
bc_read_trace(s, "positions: %d bytes\n", b->pc2line_len);
b->pc2line_buf = js_mallocz(ctx, b->pc2line_len); b->pc2line_buf = js_mallocz(ctx, b->pc2line_len);
if (!b->pc2line_buf) if (!b->pc2line_buf)
goto fail; goto fail;
@ -33958,6 +34027,7 @@ static JSValue JS_ReadFunctionTag(BCReaderState *s)
if (bc_get_leb128_int(s, &b->source_len)) if (bc_get_leb128_int(s, &b->source_len))
goto fail; goto fail;
if (b->source_len) { if (b->source_len) {
bc_read_trace(s, "source: %d bytes\n", b->source_len);
b->source = js_mallocz(ctx, b->source_len); b->source = js_mallocz(ctx, b->source_len);
if (!b->source) if (!b->source)
goto fail; goto fail;
@ -33975,6 +34045,7 @@ static JSValue JS_ReadFunctionTag(BCReaderState *s)
} }
bc_read_trace(s, "}\n"); bc_read_trace(s, "}\n");
} }
bc_read_trace(s, "}\n");
b->realm = JS_DupContext(ctx); b->realm = JS_DupContext(ctx);
return obj; return obj;
fail: fail:
@ -33994,7 +34065,11 @@ static JSValue JS_ReadModule(BCReaderState *s)
if (bc_get_atom(s, &module_name)) if (bc_get_atom(s, &module_name))
goto fail; goto fail;
#ifdef DUMP_READ_OBJECT #ifdef DUMP_READ_OBJECT
bc_read_trace(s, "name: "); print_atom(s->ctx, module_name); printf("\n"); if (check_dump_flag(s->ctx->rt, DUMP_READ_OBJECT)) {
bc_read_trace(s, "name: ");
print_atom(s->ctx, module_name);
printf("\n");
}
#endif #endif
m = js_new_module_def(ctx, module_name); m = js_new_module_def(ctx, module_name);
if (!m) if (!m)
@ -34101,7 +34176,11 @@ static JSValue JS_ReadObjectTag(BCReaderState *s)
if (bc_get_atom(s, &atom)) if (bc_get_atom(s, &atom))
goto fail; goto fail;
#ifdef DUMP_READ_OBJECT #ifdef DUMP_READ_OBJECT
bc_read_trace(s, "propname: "); print_atom(s->ctx, atom); printf("\n"); if (check_dump_flag(s->ctx->rt, DUMP_READ_OBJECT)) {
bc_read_trace(s, "propname: ");
print_atom(s->ctx, atom);
printf("\n");
}
#endif #endif
val = JS_ReadObjectRec(s); val = JS_ReadObjectRec(s);
if (JS_IsException(val)) { if (JS_IsException(val)) {
@ -45496,6 +45575,14 @@ static void promise_reaction_data_free(JSRuntime *rt,
js_free_rt(rt, rd); js_free_rt(rt, rd);
} }
#ifdef DUMP_PROMISE
#define promise_trace(ctx, ...) \
do if (check_dump_flag(ctx->rt, DUMP_PROMISE)) \
printf(__VA_ARGS__); while (0)
#else
#define promise_trace(...)
#endif
static JSValue promise_reaction_job(JSContext *ctx, int argc, static JSValue promise_reaction_job(JSContext *ctx, int argc,
JSValue *argv) JSValue *argv)
{ {
@ -45507,9 +45594,8 @@ static JSValue promise_reaction_job(JSContext *ctx, int argc,
handler = argv[2]; handler = argv[2];
is_reject = JS_ToBool(ctx, argv[3]); is_reject = JS_ToBool(ctx, argv[3]);
arg = argv[4]; arg = argv[4];
#ifdef DUMP_PROMISE
printf("promise_reaction_job: is_reject=%d\n", is_reject); promise_trace(ctx, "promise_reaction_job: is_reject=%d\n", is_reject);
#endif
if (JS_IsUndefined(handler)) { if (JS_IsUndefined(handler)) {
if (is_reject) { if (is_reject) {
@ -45558,9 +45644,9 @@ static void fulfill_or_reject_promise(JSContext *ctx, JSValue promise,
return; /* should never happen */ return; /* should never happen */
set_value(ctx, &s->promise_result, js_dup(value)); set_value(ctx, &s->promise_result, js_dup(value));
s->promise_state = JS_PROMISE_FULFILLED + is_reject; s->promise_state = JS_PROMISE_FULFILLED + is_reject;
#ifdef DUMP_PROMISE
printf("fulfill_or_reject_promise: is_reject=%d\n", is_reject); promise_trace(ctx, "fulfill_or_reject_promise: is_reject=%d\n", is_reject);
#endif
if (s->promise_state == JS_PROMISE_REJECTED && !s->is_handled) { if (s->promise_state == JS_PROMISE_REJECTED && !s->is_handled) {
JSRuntime *rt = ctx->rt; JSRuntime *rt = ctx->rt;
if (rt->host_promise_rejection_tracker) { if (rt->host_promise_rejection_tracker) {
@ -45600,9 +45686,8 @@ static JSValue js_promise_resolve_thenable_job(JSContext *ctx,
JSValue promise, thenable, then; JSValue promise, thenable, then;
JSValue args[2], res; JSValue args[2], res;
#ifdef DUMP_PROMISE promise_trace(ctx, "js_promise_resolve_thenable_job\n");
printf("js_promise_resolve_thenable_job\n");
#endif
assert(argc == 3); assert(argc == 3);
promise = argv[0]; promise = argv[0];
thenable = argv[1]; thenable = argv[1];
@ -45711,9 +45796,11 @@ static JSValue js_promise_resolve_function_call(JSContext *ctx,
else else
resolution = JS_UNDEFINED; resolution = JS_UNDEFINED;
#ifdef DUMP_PROMISE #ifdef DUMP_PROMISE
printf("js_promise_resolving_function_call: is_reject=%d resolution=", is_reject); if (check_dump_flag(ctx->rt, DUMP_PROMISE)) {
JS_DumpValue(ctx->rt, resolution); printf("js_promise_resolving_function_call: is_reject=%d resolution=", is_reject);
printf("\n"); JS_DumpValue(ctx->rt, resolution);
printf("\n");
}
#endif #endif
if (is_reject || !JS_IsObject(resolution)) { if (is_reject || !JS_IsObject(resolution)) {
goto done; goto done;

View file

@ -292,6 +292,7 @@ JS_EXTERN JSRuntime *JS_NewRuntime(void);
/* info lifetime must exceed that of rt */ /* info lifetime must exceed that of rt */
JS_EXTERN void JS_SetRuntimeInfo(JSRuntime *rt, const char *info); JS_EXTERN void JS_SetRuntimeInfo(JSRuntime *rt, const char *info);
JS_EXTERN void JS_SetMemoryLimit(JSRuntime *rt, size_t limit); JS_EXTERN void JS_SetMemoryLimit(JSRuntime *rt, size_t limit);
JS_EXTERN void JS_SetDumpFlags(JSRuntime *rt, uint64_t flags);
JS_EXTERN void JS_SetGCThreshold(JSRuntime *rt, size_t gc_threshold); JS_EXTERN void JS_SetGCThreshold(JSRuntime *rt, size_t gc_threshold);
/* use 0 to disable maximum stack size check */ /* use 0 to disable maximum stack size check */
JS_EXTERN void JS_SetMaxStackSize(JSRuntime *rt, size_t stack_size); JS_EXTERN void JS_SetMaxStackSize(JSRuntime *rt, size_t stack_size);