memfree for mcode
This commit is contained in:
165
source/quickjs.c
165
source/quickjs.c
@@ -2972,6 +2972,36 @@ static int ctx_gc (JSContext *ctx, int allow_grow, size_t alloc_size) {
|
||||
scan += obj_size;
|
||||
}
|
||||
|
||||
/* Post-GC verify: check all arrays have valid internal pointers */
|
||||
{
|
||||
uint8_t *vp = to_base;
|
||||
while (vp < to_free) {
|
||||
objhdr_t vh = *(objhdr_t *)vp;
|
||||
uint8_t vt = objhdr_type(vh);
|
||||
if (vt == OBJ_ARRAY) {
|
||||
JSArray *va = (JSArray *)vp;
|
||||
for (uint32_t vi = 0; vi < va->len; vi++) {
|
||||
JSValue ev = va->values[vi];
|
||||
if (JS_IsPtr(ev)) {
|
||||
void *ep = JS_VALUE_GET_PTR(ev);
|
||||
int in_to = ((uint8_t*)ep >= to_base && (uint8_t*)ep < to_free);
|
||||
int is_st = is_stone_ptr(ctx, ep);
|
||||
if (!in_to && !is_st) {
|
||||
fprintf(stderr, "GC VERIFY FAIL: array@%p values[%u]=%p not in to-space [%p,%p) or stone\n",
|
||||
(void*)va, vi, ep, (void*)to_base, (void*)to_free);
|
||||
/* Check if it's in from-space (stale) */
|
||||
int in_from = ((uint8_t*)ep >= from_base && (uint8_t*)ep < from_end);
|
||||
fprintf(stderr, " in_from=%d\n", in_from);
|
||||
fflush(stderr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
size_t sz = gc_object_size(vp);
|
||||
vp += sz;
|
||||
}
|
||||
}
|
||||
|
||||
/* Return old block (in poison mode, just poison it and leak) */
|
||||
heap_block_free (rt, from_base, old_heap_size);
|
||||
|
||||
@@ -4185,6 +4215,20 @@ static int js_intrinsic_array_set (JSContext *ctx, JSValue *arr_ptr, word_t idx,
|
||||
}
|
||||
|
||||
arr->values[idx] = val;
|
||||
/* DEBUG: check for stale values being stored */
|
||||
if (JS_IsPtr(val)) {
|
||||
void *vp = JS_VALUE_GET_PTR(val);
|
||||
int in_h = ((uint8_t*)vp >= ctx->heap_base && (uint8_t*)vp < ctx->heap_base + ctx->current_block_size);
|
||||
int is_s = is_stone_ptr(ctx, vp);
|
||||
if (!in_h && !is_s) {
|
||||
fprintf(stderr, "STALE STORE into array[%lu]: ptr=%p heap=[%p,%p)\n",
|
||||
(unsigned long)idx, vp, (void*)ctx->heap_base, (void*)(ctx->heap_base + ctx->current_block_size));
|
||||
fflush(stderr);
|
||||
/* Deliberately trigger ASAN to get a stack trace */
|
||||
volatile uint8_t x = *(uint8_t*)vp;
|
||||
(void)x;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -23027,6 +23071,35 @@ static JSValue js_cell_text_format (JSContext *ctx, JSValue this_val, int argc,
|
||||
}
|
||||
if (valid && idx >= 0) {
|
||||
cv_ref.val = JS_GetPropertyUint32 (ctx, coll_ref.val, (uint32_t)idx);
|
||||
if (JS_IsPtr(cv_ref.val)) {
|
||||
void *dp = JS_VALUE_GET_PTR(cv_ref.val);
|
||||
int in_h = ((uint8_t*)dp >= ctx->heap_base && (uint8_t*)dp < ctx->heap_base + ctx->current_block_size);
|
||||
int is_s = is_stone_ptr(ctx, dp);
|
||||
if (!in_h && !is_s) {
|
||||
fprintf(stderr, "STALE right after GetPropertyUint32: ptr=%p idx=%d heap=[%p,%p)\n",
|
||||
dp, idx, (void*)ctx->heap_base, (void*)(ctx->heap_base + ctx->current_block_size));
|
||||
/* Check the array and all its elements */
|
||||
JSArray *dbg_a = (JSArray *)chase(coll_ref.val);
|
||||
void *ap = (void*)dbg_a;
|
||||
int arr_in_h = ((uint8_t*)ap >= ctx->heap_base && (uint8_t*)ap < ctx->heap_base + ctx->current_block_size);
|
||||
fprintf(stderr, " array ptr=%p in_heap=%d arr->len=%u hdr=0x%llx\n", ap, arr_in_h, (unsigned)dbg_a->len, (unsigned long long)dbg_a->mist_hdr);
|
||||
for (uint32_t di = 0; di < dbg_a->len && di < 5; di++) {
|
||||
JSValue ev = dbg_a->values[di];
|
||||
if (JS_IsPtr(ev)) {
|
||||
void *evp = JS_VALUE_GET_PTR(ev);
|
||||
int ev_in = ((uint8_t*)evp >= ctx->heap_base && (uint8_t*)evp < ctx->heap_base + ctx->current_block_size);
|
||||
int ev_st = is_stone_ptr(ctx, evp);
|
||||
fprintf(stderr, " arr[%u]=%p in_heap=%d stone=%d\n", di, evp, ev_in, ev_st);
|
||||
}
|
||||
}
|
||||
/* Check the raw coll_ref.val pointer (before chase) */
|
||||
void *raw_arr = JS_VALUE_GET_PTR(coll_ref.val);
|
||||
objhdr_t raw_hdr = *(objhdr_t*)raw_arr;
|
||||
fprintf(stderr, " raw coll_ref ptr=%p hdr_type=%u is_fwd=%d\n",
|
||||
raw_arr, objhdr_type(raw_hdr), objhdr_type(raw_hdr) == OBJ_FORWARD);
|
||||
fflush(stderr);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
cv_ref.val = JS_GetProperty (ctx, coll_ref.val, name_val);
|
||||
@@ -23068,6 +23141,16 @@ static JSValue js_cell_text_format (JSContext *ctx, JSValue this_val, int argc,
|
||||
}
|
||||
|
||||
if (!made_substitution && !JS_IsNull (cv_ref.val)) {
|
||||
if (JS_IsPtr(cv_ref.val)) {
|
||||
void *dbg_ptr = JS_VALUE_GET_PTR(cv_ref.val);
|
||||
uint8_t *cur_base = ctx->heap_base;
|
||||
uint8_t *cur_end = cur_base + ctx->current_block_size;
|
||||
int in_cur = ((uint8_t*)dbg_ptr >= cur_base && (uint8_t*)dbg_ptr < cur_end);
|
||||
int is_stone = is_stone_ptr(ctx, dbg_ptr);
|
||||
fprintf(stderr, "DEBUG format: cv_ref.val=%p in_current=%d is_stone=%d is_array=%d top_gc=%p cv_ref_addr=%p heap=[%p,%p)\n",
|
||||
dbg_ptr, in_cur, is_stone, is_array, (void*)ctx->top_gc_ref, (void*)&cv_ref, (void*)cur_base, (void*)cur_end);
|
||||
fflush(stderr);
|
||||
}
|
||||
JSValue conv_text_val = JS_ToString (ctx, cv_ref.val);
|
||||
if (JS_IsText (conv_text_val)) {
|
||||
substitution = conv_text_val;
|
||||
@@ -35973,6 +36056,27 @@ static JSValue mcode_exec(JSContext *ctx, JSMCode *code, JSValue this_obj,
|
||||
cJSON *op_item = cJSON_GetArrayItem(instr, 0);
|
||||
const char *op = op_item->valuestring;
|
||||
|
||||
/* DEBUG: check all frame slots for stale pointers before each instruction */
|
||||
{
|
||||
static const char *prev_op = "(start)";
|
||||
static int prev_pc = -1;
|
||||
for (int si = 0; si < code->nr_slots; si++) {
|
||||
JSValue sv = frame->slots[si];
|
||||
if (JS_IsPtr(sv)) {
|
||||
void *sp = JS_VALUE_GET_PTR(sv);
|
||||
int in_heap = ((uint8_t*)sp >= ctx->heap_base && (uint8_t*)sp < ctx->heap_base + ctx->current_block_size);
|
||||
int in_stone = is_stone_ptr(ctx, sp);
|
||||
if (!in_heap && !in_stone) {
|
||||
fprintf(stderr, "STALE SLOT[%d]=%p before op '%s' pc=%d (prev='%s' pc=%d) heap=[%p,%p)\n",
|
||||
si, sp, op, pc-1, prev_op, prev_pc,
|
||||
(void*)ctx->heap_base, (void*)(ctx->heap_base + ctx->current_block_size));
|
||||
}
|
||||
}
|
||||
}
|
||||
prev_op = op;
|
||||
prev_pc = pc - 1;
|
||||
}
|
||||
|
||||
/* Operand extraction helpers — items 1,2,3 */
|
||||
cJSON *a1 = cJSON_GetArrayItem(instr, 1);
|
||||
cJSON *a2 = cJSON_GetArrayItem(instr, 2);
|
||||
@@ -36920,8 +37024,21 @@ static JSValue mcode_exec(JSContext *ctx, JSMCode *code, JSValue this_obj,
|
||||
int nr_slots = (int)objhdr_cap56(new_frame->hdr);
|
||||
int c_argc = (nr_slots >= 2) ? nr_slots - 2 : 0;
|
||||
int vs_base = ctx->value_stack_top;
|
||||
for (int i = 0; i < c_argc; i++)
|
||||
for (int i = 0; i < c_argc; i++) {
|
||||
ctx->value_stack[vs_base + i] = new_frame->slots[i + 1];
|
||||
/* DEBUG: check for stale values */
|
||||
JSValue dbg_v = new_frame->slots[i + 1];
|
||||
if (JS_IsPtr(dbg_v)) {
|
||||
void *dp = JS_VALUE_GET_PTR(dbg_v);
|
||||
int in_h = ((uint8_t*)dp >= ctx->heap_base && (uint8_t*)dp < ctx->heap_base + ctx->current_block_size);
|
||||
int is_s = is_stone_ptr(ctx, dp);
|
||||
if (!in_h && !is_s) {
|
||||
fprintf(stderr, "STALE invoke arg[%d]: ptr=%p heap=[%p,%p)\n",
|
||||
i, dp, (void*)ctx->heap_base, (void*)(ctx->heap_base + ctx->current_block_size));
|
||||
fflush(stderr);
|
||||
}
|
||||
}
|
||||
}
|
||||
ctx->value_stack_top = vs_base + c_argc;
|
||||
ctx->reg_current_frame = frame_ref.val;
|
||||
ctx->rt->current_register_pc = pc > 0 ? pc - 1 : 0;
|
||||
@@ -37057,11 +37174,41 @@ static JSValue mcode_exec(JSContext *ctx, JSMCode *code, JSValue this_obj,
|
||||
cJSON *p = a3->next;
|
||||
for (int i = 0; i < nargs; i++, p = p->next) {
|
||||
int areg = (int)p->valuedouble;
|
||||
/* DEBUG: check if the value we're about to store is stale */
|
||||
JSValue dbg_val = frame->slots[areg];
|
||||
if (JS_IsPtr(dbg_val)) {
|
||||
void *dvp = JS_VALUE_GET_PTR(dbg_val);
|
||||
int dv_in = ((uint8_t*)dvp >= ctx->heap_base && (uint8_t*)dvp < ctx->heap_base + ctx->current_block_size);
|
||||
int dv_st = is_stone_ptr(ctx, dvp);
|
||||
if (!dv_in && !dv_st) {
|
||||
fprintf(stderr, "STALE callmethod_dyn arg frame->slots[%d]=%p heap=[%p,%p)\n",
|
||||
areg, dvp, (void*)ctx->heap_base, (void*)(ctx->heap_base + ctx->current_block_size));
|
||||
fflush(stderr);
|
||||
}
|
||||
}
|
||||
JS_SetPropertyUint32(ctx, frame->slots[dest], i, frame->slots[areg]);
|
||||
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
||||
}
|
||||
ctx->value_stack[vs_base + 1] = frame->slots[dest];
|
||||
ctx->value_stack_top = vs_base + 2;
|
||||
/* DEBUG: verify array elements are in current heap */
|
||||
{
|
||||
JSValue dbg_arr_v = ctx->value_stack[vs_base + 1];
|
||||
JSArray *dbg_arr = (JSArray *)chase(dbg_arr_v);
|
||||
for (uint32_t di = 0; di < dbg_arr->len; di++) {
|
||||
JSValue ev = dbg_arr->values[di];
|
||||
if (JS_IsPtr(ev)) {
|
||||
void *ep = JS_VALUE_GET_PTR(ev);
|
||||
int in_heap = ((uint8_t*)ep >= ctx->heap_base && (uint8_t*)ep < ctx->heap_base + ctx->current_block_size);
|
||||
int is_st = is_stone_ptr(ctx, ep);
|
||||
if (!in_heap && !is_st) {
|
||||
fprintf(stderr, "STALE in callmethod_dyn array[%u]: ptr=%p heap=[%p,%p) nargs=%d\n",
|
||||
di, ep, (void*)ctx->heap_base, (void*)(ctx->heap_base + ctx->current_block_size), nargs);
|
||||
fflush(stderr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ctx->reg_current_frame = frame_ref.val;
|
||||
ctx->rt->current_register_pc = pc > 0 ? pc - 1 : 0;
|
||||
JSValue ret = JS_CallInternal(ctx, frame->slots[obj_reg], JS_NULL, 2, &ctx->value_stack[vs_base], 0);
|
||||
@@ -37084,14 +37231,14 @@ static JSValue mcode_exec(JSContext *ctx, JSMCode *code, JSValue this_obj,
|
||||
} else {
|
||||
JSFunction *fn = JS_VALUE_GET_FUNCTION(method);
|
||||
if (fn->kind == JS_FUNC_KIND_MCODE) {
|
||||
frame->slots[dest] = method; /* protect method from GC */
|
||||
JSFrameRegister *new_frame = alloc_frame_register(ctx, fn->u.mcode.code->nr_slots);
|
||||
if (!new_frame) {
|
||||
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
||||
goto disrupt;
|
||||
}
|
||||
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
||||
method = JS_GetProperty(ctx, frame->slots[obj_reg], frame->slots[key_reg]);
|
||||
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
||||
method = frame->slots[dest]; /* re-read after GC */
|
||||
fn = JS_VALUE_GET_FUNCTION(method);
|
||||
new_frame->function = method;
|
||||
new_frame->slots[0] = frame->slots[obj_reg]; /* this */
|
||||
@@ -37239,6 +37386,18 @@ static JSValue mcode_exec(JSContext *ctx, JSMCode *code, JSValue this_obj,
|
||||
cJSON *elem = cJSON_GetArrayItem(instr, 3 + i);
|
||||
if (elem) {
|
||||
int elem_slot = (int)elem->valuedouble;
|
||||
/* DEBUG: check if elem is stale before SetProperty */
|
||||
JSValue dbg_ev = frame->slots[elem_slot];
|
||||
if (JS_IsPtr(dbg_ev)) {
|
||||
void *ep = JS_VALUE_GET_PTR(dbg_ev);
|
||||
int in_h = ((uint8_t*)ep >= ctx->heap_base && (uint8_t*)ep < ctx->heap_base + ctx->current_block_size);
|
||||
int is_s = is_stone_ptr(ctx, ep);
|
||||
if (!in_h && !is_s) {
|
||||
fprintf(stderr, "STALE ELEM in array op: slot[%d]=%p heap=[%p,%p) i=%d nr_elems=%d\n",
|
||||
elem_slot, ep, (void*)ctx->heap_base, (void*)(ctx->heap_base + ctx->current_block_size), i, nr_elems);
|
||||
fflush(stderr);
|
||||
}
|
||||
}
|
||||
JS_SetPropertyUint32(ctx, frame->slots[dest], i, frame->slots[elem_slot]);
|
||||
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user