From 07eb5e256176d496d67e3b37e3b67aa6c3038850 Mon Sep 17 00:00:00 2001 From: ValKmjolnir Date: Wed, 15 Apr 2026 00:27:34 +0800 Subject: [PATCH] :bug: fix issue #80 Signed-off-by: ValKmjolnir --- src/nasal_gc.cpp | 20 ++++++++++++++------ src/nasal_gc.h | 2 +- src/nasal_type.h | 9 ++++++--- test/gc_test.nas | 12 +++++------- 4 files changed, 26 insertions(+), 17 deletions(-) diff --git a/src/nasal_gc.cpp b/src/nasal_gc.cpp index 3e22e5d..4d7d9ce 100644 --- a/src/nasal_gc.cpp +++ b/src/nasal_gc.cpp @@ -33,8 +33,11 @@ void gc::mark() { while (!bfs.empty()) { var value = bfs.front(); bfs.pop(); - if (value.type <= vm_type::vm_num || - value.val.gcobj->mark != nas_val::gc_status::uncollected) { + if (value.type <= vm_type::vm_num) { + continue; + } + if (value.val.gcobj->mark != nas_val::gc_status::uncollected && + value.val.gcobj->mark != nas_val::gc_status::alloc_in_sweep_stage) { continue; } mark_var(bfs, value); @@ -170,7 +173,8 @@ void gc::sweep() { if (i->mark == nas_val::gc_status::uncollected) { unused[static_cast(i->type) - static_cast(vm_type::vm_str)].push_back(i); i->mark = nas_val::gc_status::collected; - } else if (i->mark == nas_val::gc_status::found) { + } else if (i->mark == nas_val::gc_status::found || + i->mark == nas_val::gc_status::alloc_in_sweep_stage) { i->mark = nas_val::gc_status::uncollected; } } @@ -297,10 +301,14 @@ var gc::alloc(const vm_type type) { var ret = var::gcobj(unused[index].back()); ret.val.gcobj->clear(); - // if incremental sweep stage, mark it as found - // but be aware that it may be collected in next gc cycle + // if incremental sweep stage, mark it with special state. + // to avoid miss-marking objects inside them, because mark stage + // will skip scanning objects with "found" mark + // if we mark it with "found" mark, objects inside it will not be marked + // so they may be treated as unreferenced, which is not expected. + // be aware that it will be collected in next gc cycle ret.val.gcobj->mark = in_incremental_sweep_stage - ? nas_val::gc_status::found + ? nas_val::gc_status::alloc_in_sweep_stage : nas_val::gc_status::uncollected; unused[index].pop_back(); return ret; diff --git a/src/nasal_gc.h b/src/nasal_gc.h index 8e27164..49adf35 100644 --- a/src/nasal_gc.h +++ b/src/nasal_gc.h @@ -66,7 +66,7 @@ struct gc { const u64 max_incr[GC_TYPE_SIZE] = { 8192, // vm_str 8192, // vm_vec - 4096, // vm_hash + 8192, // vm_hash 2048, // vm_func 2048, // vm_upval 256, // vm_obj diff --git a/src/nasal_type.h b/src/nasal_type.h index 05c0d66..d5a6bbf 100644 --- a/src/nasal_type.h +++ b/src/nasal_type.h @@ -51,9 +51,12 @@ struct nas_map; // mapper // nas_val includes gc-managed types struct nas_val { enum class gc_status: u8 { - uncollected = 0, - collected, - found + uncollected = 0, // will be collected by sweep + collected, // already collected and put into unused list + found, // marked as referenced + alloc_in_sweep_stage // mark it allocated in incremental sweep stage + // still scan in mark stage + // but do not sweep in this gc cycle }; gc_status mark; diff --git a/test/gc_test.nas b/test/gc_test.nas index b55ced4..f2c390a 100644 --- a/test/gc_test.nas +++ b/test/gc_test.nas @@ -24,10 +24,7 @@ var test_func = func(test_processes...) { var end_info = runtime.gc.info(); var gc_total_end = end_info.total; var duration = time_stamp.elapsedMSec(); - if (duration == nil) { - println(time_stamp.elapsedMSec); - die("remaining issue: time_stamp.elapsedMSec() entry = 0x559."); - } + print(" ", duration, " ms,\tgc ", int((gc_total_end-gc_total_begin)*100/duration), "%,\t", int(1000/(duration/size(test_processes))*10)/10, " test(s)/sec", @@ -113,7 +110,8 @@ var append_tree = func { append(res, { a: {b: {c:[1, 2, 3, 4]}}, d: {e: {}}, - j: {k: {l:{m:[{a:{b:{c:[{}, {}]}}}]}}} + j: {k: {l:{m:[{a:{b:{c:[{}, {}]}}}]}}}, + n: [[], []] }); } } @@ -122,12 +120,12 @@ var append_deep_tree = func { var res = {}; var tmp = []; for (var i = 0; i < MAX_ITER_NUM; i += 1) { - tmp = [[[tmp]]]; + tmp = [[[tmp, tmp]]]; } res["vec"] = tmp; tmp = {}; for (var i = 0; i < MAX_ITER_NUM; i += 1) { - tmp = {a : {a : {a : tmp}}}; + tmp = {a : {a : {a : tmp, b : tmp}}}; } res["hash"] = tmp; return res;