Remove JSFunctionBytecode.has_debug flag (#207)

And merge the debug struct into JSFunctionBytecode because it is now
always present.

Refs: https://github.com/quickjs-ng/quickjs/pull/193#pullrequestreview-1774511177
This commit is contained in:
Ben Noordhuis 2023-12-12 00:10:52 +01:00 committed by GitHub
parent 030a0ddf3f
commit b478329cdd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

260
quickjs.c
View file

@ -624,7 +624,6 @@ typedef struct JSFunctionBytecode {
uint8_t super_call_allowed : 1; uint8_t super_call_allowed : 1;
uint8_t super_allowed : 1; uint8_t super_allowed : 1;
uint8_t arguments_allowed : 1; uint8_t arguments_allowed : 1;
uint8_t has_debug : 1;
uint8_t backtrace_barrier : 1; /* stop backtrace on this function */ uint8_t backtrace_barrier : 1; /* stop backtrace on this function */
uint8_t read_only_bytecode : 1; uint8_t read_only_bytecode : 1;
/* XXX: 4 bits available */ /* XXX: 4 bits available */
@ -642,16 +641,13 @@ typedef struct JSFunctionBytecode {
int cpool_count; int cpool_count;
int closure_var_count; int closure_var_count;
JSInlineCache *ic; JSInlineCache *ic;
struct { JSAtom filename;
/* debug info, move to separate structure to save memory? */ int line_num;
JSAtom filename; int col_num;
int line_num; int source_len;
int col_num; int pc2line_len;
int source_len; uint8_t *pc2line_buf;
int pc2line_len; char *source;
uint8_t *pc2line_buf;
char *source;
} debug;
} JSFunctionBytecode; } JSFunctionBytecode;
typedef struct JSBoundFunction { typedef struct JSBoundFunction {
@ -5754,7 +5750,7 @@ static void compute_bytecode_size(JSFunctionBytecode *b, JSMemoryUsage_helper *h
int memory_used_count, js_func_size, i; int memory_used_count, js_func_size, i;
memory_used_count = 0; memory_used_count = 0;
js_func_size = offsetof(JSFunctionBytecode, debug); js_func_size = sizeof(*b);
if (b->vardefs) { if (b->vardefs) {
js_func_size += (b->arg_count + b->var_count) * sizeof(*b->vardefs); js_func_size += (b->arg_count + b->var_count) * sizeof(*b->vardefs);
} }
@ -5771,17 +5767,12 @@ static void compute_bytecode_size(JSFunctionBytecode *b, JSMemoryUsage_helper *h
if (!b->read_only_bytecode && b->byte_code_buf) { if (!b->read_only_bytecode && b->byte_code_buf) {
hp->js_func_code_size += b->byte_code_len; hp->js_func_code_size += b->byte_code_len;
} }
if (b->has_debug) { memory_used_count++;
js_func_size += sizeof(*b) - offsetof(JSFunctionBytecode, debug); js_func_size += b->source_len + 1;
if (b->debug.source) { if (b->pc2line_len) {
memory_used_count++; memory_used_count++;
js_func_size += b->debug.source_len + 1; hp->js_func_pc2line_count += 1;
} hp->js_func_pc2line_size += b->pc2line_len;
if (b->debug.pc2line_len) {
memory_used_count++;
hp->js_func_pc2line_count += 1;
hp->js_func_pc2line_size += b->debug.pc2line_len;
}
} }
hp->js_func_size += js_func_size; hp->js_func_size += js_func_size;
hp->js_func_count += 1; hp->js_func_count += 1;
@ -6291,16 +6282,11 @@ static int find_line_num(JSContext *ctx, JSFunctionBytecode *b,
unsigned int op; unsigned int op;
*col = 1; *col = 1;
if (!b->has_debug || !b->debug.pc2line_buf) { p = b->pc2line_buf;
/* function was stripped */ p_end = p + b->pc2line_len;
return -1;
}
p = b->debug.pc2line_buf;
p_end = p + b->debug.pc2line_len;
pc = 0; pc = 0;
line_num = b->debug.line_num; line_num = b->line_num;
col_num = b->debug.col_num; col_num = b->col_num;
while (p < p_end) { while (p < p_end) {
op = *p++; op = *p++;
if (op == 0) { if (op == 0) {
@ -6334,7 +6320,7 @@ static int find_line_num(JSContext *ctx, JSFunctionBytecode *b,
return line_num; return line_num;
fail: fail:
/* should never happen */ /* should never happen */
return b->debug.line_num; return b->line_num;
} }
/* in order to avoid executing arbitrary code during the stack trace /* in order to avoid executing arbitrary code during the stack trace
@ -6416,18 +6402,16 @@ static void build_backtrace(JSContext *ctx, JSValue error_obj,
b = p->u.func.function_bytecode; b = p->u.func.function_bytecode;
backtrace_barrier = b->backtrace_barrier; backtrace_barrier = b->backtrace_barrier;
if (b->has_debug) { line_num1 = find_line_num(ctx, b,
line_num1 = find_line_num(ctx, b, sf->cur_pc - b->byte_code_buf - 1,
sf->cur_pc - b->byte_code_buf - 1, &col_num1);
&col_num1); atom_str = JS_AtomToCString(ctx, b->filename);
atom_str = JS_AtomToCString(ctx, b->debug.filename); dbuf_printf(&dbuf, " (%s",
dbuf_printf(&dbuf, " (%s", atom_str ? atom_str : "<null>");
atom_str ? atom_str : "<null>"); JS_FreeCString(ctx, atom_str);
JS_FreeCString(ctx, atom_str); if (line_num1 != -1)
if (line_num1 != -1) dbuf_printf(&dbuf, ":%d:%d", line_num1, col_num1);
dbuf_printf(&dbuf, ":%d:%d", line_num1, col_num1); dbuf_putc(&dbuf, ')');
dbuf_putc(&dbuf, ')');
}
} else { } else {
dbuf_printf(&dbuf, " (native)"); dbuf_printf(&dbuf, " (native)");
} }
@ -13023,18 +13007,18 @@ static JSValue js_function_proto_fileName(JSContext *ctx,
JSValue this_val) JSValue this_val)
{ {
JSFunctionBytecode *b = JS_GetFunctionBytecode(this_val); JSFunctionBytecode *b = JS_GetFunctionBytecode(this_val);
if (b && b->has_debug) { if (b) {
return JS_AtomToString(ctx, b->debug.filename); return JS_AtomToString(ctx, b->filename);
} }
return JS_UNDEFINED; return JS_UNDEFINED;
} }
static JSValue js_function_proto_debug_int32(JSContext *ctx, static JSValue js_function_proto_int32(JSContext *ctx,
JSValue this_val, JSValue this_val,
int magic) int magic)
{ {
JSFunctionBytecode *b = JS_GetFunctionBytecode(this_val); JSFunctionBytecode *b = JS_GetFunctionBytecode(this_val);
if (b && b->has_debug) { if (b) {
int *field = (int *) ((char *)b + magic); int *field = (int *) ((char *)b + magic);
return js_int32(*field); return js_int32(*field);
} }
@ -26215,9 +26199,7 @@ JSAtom JS_GetScriptOrModuleName(JSContext *ctx, int n_stack_levels)
if (!js_class_has_bytecode(p->class_id)) if (!js_class_has_bytecode(p->class_id))
return JS_ATOM_NULL; return JS_ATOM_NULL;
b = p->u.func.function_bytecode; b = p->u.func.function_bytecode;
if (!b->has_debug) return JS_DupAtom(ctx, b->filename);
return JS_ATOM_NULL;
return JS_DupAtom(ctx, b->debug.filename);
} }
JSAtom JS_GetModuleName(JSContext *ctx, JSModuleDef *m) JSAtom JS_GetModuleName(JSContext *ctx, JSModuleDef *m)
@ -27335,29 +27317,22 @@ static __maybe_unused void dump_single_byte_code(JSContext *ctx,
JSFunctionBytecode *b) JSFunctionBytecode *b)
{ {
JSVarDef *args, *vars; JSVarDef *args, *vars;
int line_num;
args = vars = b->vardefs; args = vars = b->vardefs;
if (vars) if (vars)
vars = &vars[b->arg_count]; vars = &vars[b->arg_count];
line_num = -1;
if (b->has_debug)
line_num = b->debug.line_num;
dump_byte_code(ctx, /*pass*/3, pc, short_opcode_info(*pc).size, dump_byte_code(ctx, /*pass*/3, pc, short_opcode_info(*pc).size,
args, b->arg_count, vars, b->var_count, args, b->arg_count, vars, b->var_count,
b->closure_var, b->closure_var_count, b->closure_var, b->closure_var_count,
b->cpool, b->cpool_count, b->cpool, b->cpool_count,
NULL, line_num, NULL, b->line_num,
NULL, b); NULL, b);
} }
static __maybe_unused void print_func_name(JSFunctionBytecode *b) static __maybe_unused void print_func_name(JSFunctionBytecode *b)
{ {
if (b->has_debug) print_lines(b->source, 0, 1);
if (b->debug.source)
print_lines(b->debug.source, 0, 1);
} }
static __maybe_unused void dump_pc2line(JSContext *ctx, static __maybe_unused void dump_pc2line(JSContext *ctx,
@ -27422,9 +27397,9 @@ static __maybe_unused void js_dump_function_bytecode(JSContext *ctx, JSFunctionB
char atom_buf[ATOM_GET_STR_BUF_SIZE]; char atom_buf[ATOM_GET_STR_BUF_SIZE];
const char *str; const char *str;
if (b->has_debug && b->debug.filename != JS_ATOM_NULL) { if (b->filename != JS_ATOM_NULL) {
str = JS_AtomGetStr(ctx, atom_buf, sizeof(atom_buf), b->debug.filename); str = JS_AtomGetStr(ctx, atom_buf, sizeof(atom_buf), b->filename);
printf("%s:%d:%d: ", str, b->debug.line_num, b->debug.col_num); printf("%s:%d:%d: ", str, b->line_num, b->col_num);
} }
str = JS_AtomGetStr(ctx, atom_buf, sizeof(atom_buf), b->func_name); str = JS_AtomGetStr(ctx, atom_buf, sizeof(atom_buf), b->func_name);
@ -27479,12 +27454,9 @@ static __maybe_unused void js_dump_function_bytecode(JSContext *ctx, JSFunctionB
b->vardefs ? b->vardefs + b->arg_count : NULL, b->var_count, b->vardefs ? b->vardefs + b->arg_count : NULL, b->var_count,
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->has_debug ? b->debug.source : NULL, b->source, b->line_num, NULL, b);
b->has_debug ? b->debug.line_num : -1, NULL, b);
#if defined(DUMP_BYTECODE) && (DUMP_BYTECODE & 32) #if defined(DUMP_BYTECODE) && (DUMP_BYTECODE & 32)
if (b->has_debug) dump_pc2line(ctx, b->pc2line_buf, b->pc2line_len, b->line_num, b->col_num);
dump_pc2line(ctx, b->debug.pc2line_buf, b->debug.pc2line_len,
b->debug.line_num, b->debug.col_num);
#endif #endif
printf("\n"); printf("\n");
} }
@ -30792,17 +30764,16 @@ static JSValue js_create_function(JSContext *ctx, JSFunctionDef *fd)
/* XXX: source and pc2line info should be packed at the end of the /* XXX: source and pc2line info should be packed at the end of the
JSFunctionBytecode structure, avoiding allocation overhead JSFunctionBytecode structure, avoiding allocation overhead
*/ */
b->has_debug = 1; b->filename = fd->filename;
b->debug.filename = fd->filename; b->line_num = fd->line_num;
b->debug.line_num = fd->line_num; b->col_num = fd->col_num;
b->debug.col_num = fd->col_num;
b->debug.pc2line_buf = js_realloc(ctx, fd->pc2line.buf, fd->pc2line.size); b->pc2line_buf = js_realloc(ctx, fd->pc2line.buf, fd->pc2line.size);
if (!b->debug.pc2line_buf) if (!b->pc2line_buf)
b->debug.pc2line_buf = fd->pc2line.buf; b->pc2line_buf = fd->pc2line.buf;
b->debug.pc2line_len = fd->pc2line.size; b->pc2line_len = fd->pc2line.size;
b->debug.source = fd->source; b->source = fd->source;
b->debug.source_len = fd->source_len; b->source_len = fd->source_len;
if (fd->scopes != fd->def_scope_array) if (fd->scopes != fd->def_scope_array)
js_free(ctx, fd->scopes); js_free(ctx, fd->scopes);
@ -30879,11 +30850,9 @@ static void free_function_bytecode(JSRuntime *rt, JSFunctionBytecode *b)
JS_FreeContext(b->realm); JS_FreeContext(b->realm);
JS_FreeAtomRT(rt, b->func_name); JS_FreeAtomRT(rt, b->func_name);
if (b->has_debug) { JS_FreeAtomRT(rt, b->filename);
JS_FreeAtomRT(rt, b->debug.filename); js_free_rt(rt, b->pc2line_buf);
js_free_rt(rt, b->debug.pc2line_buf); js_free_rt(rt, b->source);
js_free_rt(rt, b->debug.source);
}
remove_gc_object(&b->header); remove_gc_object(&b->header);
if (rt->gc_phase == JS_GC_PHASE_REMOVE_CYCLES && b->header.ref_count != 0) { if (rt->gc_phase == JS_GC_PHASE_REMOVE_CYCLES && b->header.ref_count != 0) {
@ -32054,7 +32023,7 @@ typedef enum BCTagEnum {
BC_TAG_OBJECT_REFERENCE, BC_TAG_OBJECT_REFERENCE,
} BCTagEnum; } BCTagEnum;
#define BC_VERSION 5 #define BC_VERSION 6
typedef struct BCWriterState { typedef struct BCWriterState {
JSContext *ctx; JSContext *ctx;
@ -32421,7 +32390,6 @@ static int JS_WriteFunctionTag(BCWriterState *s, JSValue obj)
bc_set_flags(&flags, &idx, b->super_call_allowed, 1); bc_set_flags(&flags, &idx, b->super_call_allowed, 1);
bc_set_flags(&flags, &idx, b->super_allowed, 1); bc_set_flags(&flags, &idx, b->super_allowed, 1);
bc_set_flags(&flags, &idx, b->arguments_allowed, 1); bc_set_flags(&flags, &idx, b->arguments_allowed, 1);
bc_set_flags(&flags, &idx, b->has_debug, 1);
bc_set_flags(&flags, &idx, b->backtrace_barrier, 1); bc_set_flags(&flags, &idx, b->backtrace_barrier, 1);
assert(idx <= 16); assert(idx <= 16);
bc_put_u16(s, flags); bc_put_u16(s, flags);
@ -32472,24 +32440,22 @@ static int JS_WriteFunctionTag(BCWriterState *s, JSValue obj)
if (JS_WriteFunctionBytecode(s, b->byte_code_buf, b->byte_code_len)) if (JS_WriteFunctionBytecode(s, b->byte_code_buf, b->byte_code_len))
goto fail; goto fail;
if (b->has_debug) { bc_put_atom(s, b->filename);
bc_put_atom(s, b->debug.filename); bc_put_leb128(s, b->line_num);
bc_put_leb128(s, b->debug.line_num); bc_put_leb128(s, b->col_num);
bc_put_leb128(s, b->debug.col_num); bc_put_leb128(s, b->pc2line_len);
bc_put_leb128(s, b->debug.pc2line_len); dbuf_put(&s->dbuf, b->pc2line_buf, b->pc2line_len);
dbuf_put(&s->dbuf, b->debug.pc2line_buf, b->debug.pc2line_len);
/* compatibility */ /* compatibility */
dbuf_putc(&s->dbuf, 255); dbuf_putc(&s->dbuf, 255);
dbuf_putc(&s->dbuf, 73); // 'I' dbuf_putc(&s->dbuf, 73); // 'I'
dbuf_putc(&s->dbuf, 67); // 'C' dbuf_putc(&s->dbuf, 67); // 'C'
if (b->ic == NULL) { if (b->ic == NULL) {
bc_put_leb128(s, 0); bc_put_leb128(s, 0);
} else { } else {
bc_put_leb128(s, b->ic->count); bc_put_leb128(s, b->ic->count);
for (i = 0; i < b->ic->count; i++) { for (i = 0; i < b->ic->count; i++) {
bc_put_atom(s, b->ic->cache[i].atom); bc_put_atom(s, b->ic->cache[i].atom);
}
} }
} }
@ -33333,7 +33299,6 @@ static JSValue JS_ReadFunctionTag(BCReaderState *s)
bc.super_call_allowed = bc_get_flags(v16, &idx, 1); bc.super_call_allowed = bc_get_flags(v16, &idx, 1);
bc.super_allowed = bc_get_flags(v16, &idx, 1); bc.super_allowed = bc_get_flags(v16, &idx, 1);
bc.arguments_allowed = bc_get_flags(v16, &idx, 1); bc.arguments_allowed = bc_get_flags(v16, &idx, 1);
bc.has_debug = bc_get_flags(v16, &idx, 1);
bc.backtrace_barrier = bc_get_flags(v16, &idx, 1); bc.backtrace_barrier = bc_get_flags(v16, &idx, 1);
bc.read_only_bytecode = s->is_rom_data; bc.read_only_bytecode = s->is_rom_data;
if (bc_get_u8(s, &v8)) if (bc_get_u8(s, &v8))
@ -33358,11 +33323,7 @@ static JSValue JS_ReadFunctionTag(BCReaderState *s)
if (bc_get_leb128_int(s, &local_count)) if (bc_get_leb128_int(s, &local_count))
goto fail; goto fail;
if (bc.has_debug) { function_size = sizeof(*b);
function_size = sizeof(*b);
} else {
function_size = offsetof(JSFunctionBytecode, debug);
}
cpool_offset = function_size; cpool_offset = function_size;
function_size += bc.cpool_count * sizeof(*bc.cpool); function_size += bc.cpool_count * sizeof(*bc.cpool);
vardefs_offset = function_size; vardefs_offset = function_size;
@ -33378,7 +33339,7 @@ static JSValue JS_ReadFunctionTag(BCReaderState *s)
if (!b) if (!b)
return JS_EXCEPTION; return JS_EXCEPTION;
memcpy(b, &bc, offsetof(JSFunctionBytecode, debug)); memcpy(b, &bc, sizeof(*b));
b->header.ref_count = 1; b->header.ref_count = 1;
if (local_count != 0) { if (local_count != 0) {
b->vardefs = (void *)((uint8_t*)b + vardefs_offset); b->vardefs = (void *)((uint8_t*)b + vardefs_offset);
@ -33457,44 +33418,42 @@ static JSValue JS_ReadFunctionTag(BCReaderState *s)
goto fail; goto fail;
bc_read_trace(s, "}\n"); bc_read_trace(s, "}\n");
} }
if (b->has_debug) { /* read optional debug information */
/* read optional debug information */ bc_read_trace(s, "debug {\n");
bc_read_trace(s, "debug {\n"); if (bc_get_atom(s, &b->filename))
if (bc_get_atom(s, &b->debug.filename)) goto fail;
if (bc_get_leb128_int(s, &b->line_num))
goto fail;
if (bc_get_leb128_int(s, &b->col_num))
goto fail;
if (bc_get_leb128_int(s, &b->pc2line_len))
goto fail;
if (b->pc2line_len) {
b->pc2line_buf = js_mallocz(ctx, b->pc2line_len);
if (!b->pc2line_buf)
goto fail; goto fail;
if (bc_get_leb128_int(s, &b->debug.line_num)) if (bc_get_buf(s, b->pc2line_buf, b->pc2line_len))
goto fail; goto fail;
if (bc_get_leb128_int(s, &b->debug.col_num)) }
goto fail; if (s->buf_end - s->ptr > 3 && s->ptr[0] == 255 &&
if (bc_get_leb128_int(s, &b->debug.pc2line_len)) s->ptr[1] == 73 && s->ptr[2] == 67) {
goto fail; s->ptr += 3;
if (b->debug.pc2line_len) { bc_get_leb128(s, &ic_len);
b->debug.pc2line_buf = js_mallocz(ctx, b->debug.pc2line_len); if (ic_len == 0) {
if (!b->debug.pc2line_buf) b->ic = NULL;
} else {
b->ic = init_ic(ctx);
if (b->ic == NULL)
goto fail; goto fail;
if (bc_get_buf(s, b->debug.pc2line_buf, b->debug.pc2line_len)) for (i = 0; i < ic_len; i++) {
goto fail; bc_get_atom(s, &atom);
} add_ic_slot1(ctx, b->ic, atom);
if (s->buf_end - s->ptr > 3 && s->ptr[0] == 255 && JS_FreeAtom(ctx, atom);
s->ptr[1] == 73 && s->ptr[2] == 67) {
s->ptr += 3;
bc_get_leb128(s, &ic_len);
if (ic_len == 0) {
b->ic = NULL;
} else {
b->ic = init_ic(ctx);
if (b->ic == NULL)
goto fail;
for (i = 0; i < ic_len; i++) {
bc_get_atom(s, &atom);
add_ic_slot1(ctx, b->ic, atom);
JS_FreeAtom(ctx, atom);
}
rebuild_ic(ctx, b->ic);
} }
rebuild_ic(ctx, b->ic);
} }
#ifdef DUMP_READ_OBJECT #ifdef DUMP_READ_OBJECT
bc_read_trace(s, "filename: "); print_atom(s->ctx, b->debug.filename); printf("\n"); bc_read_trace(s, "filename: "); print_atom(s->ctx, b->filename); printf("\n");
#endif #endif
bc_read_trace(s, "}\n"); bc_read_trace(s, "}\n");
} }
@ -35933,10 +35892,7 @@ static JSValue js_function_toString(JSContext *ctx, JSValue this_val,
p = JS_VALUE_GET_OBJ(this_val); p = JS_VALUE_GET_OBJ(this_val);
if (js_class_has_bytecode(p->class_id)) { if (js_class_has_bytecode(p->class_id)) {
JSFunctionBytecode *b = p->u.func.function_bytecode; JSFunctionBytecode *b = p->u.func.function_bytecode;
if (b->has_debug && b->debug.source) { return JS_NewStringLen(ctx, b->source, b->source_len);
return JS_NewStringLen(ctx, b->debug.source, b->debug.source_len);
}
func_kind = b->func_kind;
} }
{ {
JSValue name; JSValue name;
@ -35983,10 +35939,10 @@ static const JSCFunctionListEntry js_function_proto_funcs[] = {
JS_CFUNC_DEF("toString", 0, js_function_toString ), JS_CFUNC_DEF("toString", 0, js_function_toString ),
JS_CFUNC_DEF("[Symbol.hasInstance]", 1, js_function_hasInstance ), JS_CFUNC_DEF("[Symbol.hasInstance]", 1, js_function_hasInstance ),
JS_CGETSET_DEF("fileName", js_function_proto_fileName, NULL ), JS_CGETSET_DEF("fileName", js_function_proto_fileName, NULL ),
JS_CGETSET_MAGIC_DEF("lineNumber", js_function_proto_debug_int32, NULL, JS_CGETSET_MAGIC_DEF("lineNumber", js_function_proto_int32, NULL,
offsetof(JSFunctionBytecode, debug.line_num)), offsetof(JSFunctionBytecode, line_num)),
JS_CGETSET_MAGIC_DEF("columnNumber", js_function_proto_debug_int32, NULL, JS_CGETSET_MAGIC_DEF("columnNumber", js_function_proto_int32, NULL,
offsetof(JSFunctionBytecode, debug.col_num)), offsetof(JSFunctionBytecode, col_num)),
}; };
/* Error class */ /* Error class */