fix array gc bug; new gc error chasing
This commit is contained in:
150
source/runtime.c
150
source/runtime.c
@@ -1292,6 +1292,9 @@ static inline int ptr_in_range (void *p, uint8_t *b, uint8_t *e) {
|
||||
return q >= b && q < e;
|
||||
}
|
||||
|
||||
static const char *gc_dbg_phase = "?";
|
||||
static void *gc_dbg_parent = NULL;
|
||||
|
||||
JSValue gc_copy_value (JSContext *ctx, JSValue v, uint8_t *from_base, uint8_t *from_end, uint8_t *to_base, uint8_t **to_free, uint8_t *to_end) {
|
||||
if (!JS_IsPtr (v)) return v;
|
||||
|
||||
@@ -1317,8 +1320,8 @@ JSValue gc_copy_value (JSContext *ctx, JSValue v, uint8_t *from_base, uint8_t *f
|
||||
}
|
||||
|
||||
if (type != OBJ_ARRAY && type != OBJ_TEXT && type != OBJ_RECORD && type != OBJ_FUNCTION && type != OBJ_FRAME) {
|
||||
fprintf (stderr, "gc_copy_value: invalid object type %d at %p (hdr=0x%llx)\n", type, ptr, (unsigned long long)hdr);
|
||||
fprintf (stderr, " This may be an interior pointer or corrupt root\n");
|
||||
fprintf (stderr, "gc_copy_value: invalid type %d at %p (hdr=0x%llx) phase=%s parent=%p\n",
|
||||
type, ptr, (unsigned long long)hdr, gc_dbg_phase, gc_dbg_parent);
|
||||
fflush (stderr);
|
||||
abort ();
|
||||
}
|
||||
@@ -1412,7 +1415,37 @@ void gc_scan_object (JSContext *ctx, void *ptr, uint8_t *from_base, uint8_t *fro
|
||||
/* Scan all slots */
|
||||
uint64_t slot_count = objhdr_cap56 (frame->header);
|
||||
for (uint64_t i = 0; i < slot_count; i++) {
|
||||
frame->slots[i] = gc_copy_value (ctx, frame->slots[i], from_base, from_end, to_base, to_free, to_end);
|
||||
JSValue sv = frame->slots[i];
|
||||
#ifdef VALIDATE_GC
|
||||
if (JS_IsPtr (sv)) {
|
||||
void *sp = JS_VALUE_GET_PTR (sv);
|
||||
if (!is_ct_ptr (ctx, sp) && ptr_in_range (sp, from_base, from_end)) {
|
||||
objhdr_t sh = *(objhdr_t *)sp;
|
||||
uint8_t st = objhdr_type (sh);
|
||||
if (st != OBJ_FORWARD && st != OBJ_ARRAY && st != OBJ_TEXT &&
|
||||
st != OBJ_RECORD && st != OBJ_FUNCTION && st != OBJ_FRAME) {
|
||||
const char *fname = "?";
|
||||
const char *ffile = "?";
|
||||
uint16_t fnslots = 0;
|
||||
if (JS_IsPtr (frame->function)) {
|
||||
objhdr_t fh = *(objhdr_t *)JS_VALUE_GET_PTR (frame->function);
|
||||
if (objhdr_type (fh) == OBJ_FUNCTION) {
|
||||
JSFunction *fn = (JSFunction *)JS_VALUE_GET_PTR (frame->function);
|
||||
if (fn->kind == JS_FUNC_KIND_REGISTER && fn->u.reg.code) {
|
||||
if (fn->u.reg.code->name_cstr) fname = fn->u.reg.code->name_cstr;
|
||||
if (fn->u.reg.code->filename_cstr) ffile = fn->u.reg.code->filename_cstr;
|
||||
fnslots = fn->u.reg.code->nr_slots;
|
||||
}
|
||||
}
|
||||
}
|
||||
fprintf (stderr, "VALIDATE_GC: frame %p slot[%llu]=%p bad type %d (hdr=0x%llx) fn=%s (%s) nr_slots=%d\n",
|
||||
ptr, (unsigned long long)i, sp, st, (unsigned long long)sh, fname, ffile, fnslots);
|
||||
fflush (stderr);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
frame->slots[i] = gc_copy_value (ctx, sv, from_base, from_end, to_base, to_free, to_end);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -1466,6 +1499,63 @@ int ctx_gc (JSContext *ctx, int allow_grow, size_t alloc_size) {
|
||||
uint8_t *to_free = new_block;
|
||||
uint8_t *to_end = new_block + new_size;
|
||||
|
||||
gc_dbg_phase = "roots";
|
||||
gc_dbg_parent = NULL;
|
||||
|
||||
#ifdef VALIDATE_GC
|
||||
/* Pre-GC: walk live frame chain and check for bad slot values */
|
||||
if (JS_IsPtr (ctx->reg_current_frame)) {
|
||||
JSFrame *cf = (JSFrame *)JS_VALUE_GET_PTR (ctx->reg_current_frame);
|
||||
while (cf) {
|
||||
objhdr_t cfh = cf->header;
|
||||
while (objhdr_type (cfh) == OBJ_FORWARD) {
|
||||
cf = (JSFrame *)objhdr_fwd_ptr (cfh);
|
||||
cfh = cf->header;
|
||||
}
|
||||
if (objhdr_type (cfh) != OBJ_FRAME) break;
|
||||
uint64_t sc = objhdr_cap56 (cfh);
|
||||
for (uint64_t si = 0; si < sc; si++) {
|
||||
JSValue sv = cf->slots[si];
|
||||
if (JS_IsPtr (sv)) {
|
||||
void *sp = JS_VALUE_GET_PTR (sv);
|
||||
if (!is_ct_ptr (ctx, sp) && ptr_in_range (sp, from_base, from_end)) {
|
||||
objhdr_t th = *(objhdr_t *)sp;
|
||||
void *orig_sp = sp;
|
||||
while (objhdr_type (th) == OBJ_FORWARD) {
|
||||
sp = objhdr_fwd_ptr (th);
|
||||
if (!ptr_in_range (sp, from_base, from_end)) break;
|
||||
th = *(objhdr_t *)sp;
|
||||
}
|
||||
uint8_t tt = objhdr_type (th);
|
||||
if (tt != OBJ_FORWARD && tt != OBJ_ARRAY && tt != OBJ_TEXT &&
|
||||
tt != OBJ_RECORD && tt != OBJ_FUNCTION && tt != OBJ_FRAME) {
|
||||
const char *fn_name = "?";
|
||||
JSValue fn_v = cf->function;
|
||||
if (JS_IsPtr (fn_v)) {
|
||||
objhdr_t fnh = *(objhdr_t *)JS_VALUE_GET_PTR (fn_v);
|
||||
while (objhdr_type (fnh) == OBJ_FORWARD) {
|
||||
fn_v = JS_MKPTR (objhdr_fwd_ptr (fnh));
|
||||
fnh = *(objhdr_t *)JS_VALUE_GET_PTR (fn_v);
|
||||
}
|
||||
if (objhdr_type (fnh) == OBJ_FUNCTION) {
|
||||
JSFunction *fnp = (JSFunction *)JS_VALUE_GET_PTR (fn_v);
|
||||
if (fnp->kind == JS_FUNC_KIND_REGISTER && fnp->u.reg.code && fnp->u.reg.code->name_cstr)
|
||||
fn_name = fnp->u.reg.code->name_cstr;
|
||||
}
|
||||
}
|
||||
fprintf (stderr, "VALIDATE_GC: pre-gc frame %p slot[%llu] -> %p (chased %p) bad type %d (hdr=0x%llx) fn=%s\n",
|
||||
(void *)cf, (unsigned long long)si, orig_sp, sp, tt, (unsigned long long)th, fn_name);
|
||||
fflush (stderr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (JS_IsNull (cf->caller)) break;
|
||||
cf = (JSFrame *)JS_VALUE_GET_PTR (cf->caller);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Copy roots: global object, class prototypes, exception, etc. */
|
||||
#ifdef DUMP_GC_DETAIL
|
||||
printf(" roots: global_obj = 0x%llx\n", (unsigned long long)ctx->global_obj); fflush(stdout);
|
||||
@@ -1534,6 +1624,7 @@ int ctx_gc (JSContext *ctx, int allow_grow, size_t alloc_size) {
|
||||
}
|
||||
|
||||
/* Cheney scan: scan copied objects to find more references */
|
||||
gc_dbg_phase = "scan";
|
||||
uint8_t *scan = to_base;
|
||||
#ifdef DUMP_GC_DETAIL
|
||||
printf(" scan: to_base=%p to_free=%p to_end=%p\n", (void*)to_base, (void*)to_free, (void*)to_end);
|
||||
@@ -1550,6 +1641,7 @@ int ctx_gc (JSContext *ctx, int allow_grow, size_t alloc_size) {
|
||||
printf(" size=%zu\n", obj_size);
|
||||
fflush(stdout);
|
||||
#endif
|
||||
gc_dbg_parent = scan;
|
||||
gc_scan_object (ctx, scan, from_base, from_end, to_base, &to_free, to_end);
|
||||
scan += obj_size;
|
||||
}
|
||||
@@ -7973,11 +8065,18 @@ static JSValue js_cell_array (JSContext *ctx, JSValue this_val, int argc, JSValu
|
||||
}
|
||||
}
|
||||
|
||||
JSValue result = JS_NewArrayLen (ctx, count);
|
||||
if (JS_IsException (result)) {
|
||||
/* GC-protect result and arg across allocating calls */
|
||||
JSGCRef result_ref, arg_ref;
|
||||
JS_PushGCRef (ctx, &result_ref);
|
||||
JS_PushGCRef (ctx, &arg_ref);
|
||||
arg_ref.val = arg;
|
||||
result_ref.val = JS_NewArrayLen (ctx, count);
|
||||
if (JS_IsException (result_ref.val)) {
|
||||
JS_PopGCRef (ctx, &arg_ref);
|
||||
JS_PopGCRef (ctx, &result_ref);
|
||||
JS_FreeCString (ctx, cstr);
|
||||
JS_FreeCString (ctx, sep);
|
||||
return result;
|
||||
return result_ref.val;
|
||||
}
|
||||
|
||||
int64_t idx = 0;
|
||||
@@ -7986,22 +8085,24 @@ static JSValue js_cell_array (JSContext *ctx, JSValue this_val, int argc, JSValu
|
||||
|
||||
if (sep_len == 0) {
|
||||
for (int i = 0; i < len; i++) {
|
||||
JSValue ch = js_sub_string_val (ctx, arg, i, i + 1);
|
||||
JS_SetPropertyNumber (ctx, result, idx++, ch);
|
||||
JSValue ch = js_sub_string_val (ctx, arg_ref.val, i, i + 1);
|
||||
JS_SetPropertyNumber (ctx, result_ref.val, idx++, ch);
|
||||
}
|
||||
} else {
|
||||
while ((found = strstr (pos, sep)) != NULL) {
|
||||
JSValue part = JS_NewStringLen (ctx, pos, found - pos);
|
||||
JS_SetPropertyNumber (ctx, result, idx++, part);
|
||||
JS_SetPropertyNumber (ctx, result_ref.val, idx++, part);
|
||||
pos = found + sep_len;
|
||||
}
|
||||
JSValue part = JS_NewString (ctx, pos);
|
||||
JS_SetPropertyNumber (ctx, result, idx++, part);
|
||||
JS_SetPropertyNumber (ctx, result_ref.val, idx++, part);
|
||||
}
|
||||
|
||||
JS_PopGCRef (ctx, &arg_ref);
|
||||
JS_PopGCRef (ctx, &result_ref);
|
||||
JS_FreeCString (ctx, cstr);
|
||||
JS_FreeCString (ctx, sep);
|
||||
return result;
|
||||
return result_ref.val;
|
||||
}
|
||||
|
||||
if (mist_is_gc_object (argv[1]) && JS_IsRegExp (ctx, argv[1])) {
|
||||
@@ -8120,21 +8221,34 @@ static JSValue js_cell_array (JSContext *ctx, JSValue this_val, int argc, JSValu
|
||||
return JS_NULL;
|
||||
|
||||
int64_t count = (len + chunk_len - 1) / chunk_len;
|
||||
JSValue result = JS_NewArrayLen (ctx, count);
|
||||
if (JS_IsException (result))
|
||||
return result;
|
||||
/* GC-protect result and arg across allocating calls */
|
||||
JSGCRef result_ref, arg_ref;
|
||||
JS_PushGCRef (ctx, &result_ref);
|
||||
JS_PushGCRef (ctx, &arg_ref);
|
||||
arg_ref.val = arg;
|
||||
result_ref.val = JS_NewArrayLen (ctx, count);
|
||||
if (JS_IsException (result_ref.val)) {
|
||||
JS_PopGCRef (ctx, &arg_ref);
|
||||
JS_PopGCRef (ctx, &result_ref);
|
||||
return result_ref.val;
|
||||
}
|
||||
|
||||
int64_t idx = 0;
|
||||
for (int i = 0; i < len; i += chunk_len) {
|
||||
int end = i + chunk_len;
|
||||
if (end > len) end = len;
|
||||
JSValue chunk = js_sub_string_val (ctx, arg, i, end);
|
||||
if (JS_IsException (chunk))
|
||||
JSValue chunk = js_sub_string_val (ctx, arg_ref.val, i, end);
|
||||
if (JS_IsException (chunk)) {
|
||||
JS_PopGCRef (ctx, &arg_ref);
|
||||
JS_PopGCRef (ctx, &result_ref);
|
||||
return JS_EXCEPTION;
|
||||
JS_SetPropertyNumber (ctx, result, idx++, chunk);
|
||||
}
|
||||
JS_SetPropertyNumber (ctx, result_ref.val, idx++, chunk);
|
||||
}
|
||||
|
||||
return result;
|
||||
JS_PopGCRef (ctx, &arg_ref);
|
||||
JS_PopGCRef (ctx, &result_ref);
|
||||
return result_ref.val;
|
||||
}
|
||||
|
||||
return JS_NULL;
|
||||
|
||||
Reference in New Issue
Block a user