mirror of
https://github.com/micropython/micropython.git
synced 2025-07-21 04:51:12 +02:00
py/gc: Reorder static functions for clarity.
Some checks failed
JavaScript code lint and formatting with Biome / eslint (push) Has been cancelled
Check code formatting / code-formatting (push) Has been cancelled
Check spelling with codespell / codespell (push) Has been cancelled
Build docs / build (push) Has been cancelled
Check examples / embedding (push) Has been cancelled
Package mpremote / build (push) Has been cancelled
.mpy file format and tools / test (push) Has been cancelled
Build ports metadata / build (push) Has been cancelled
cc3200 port / build (push) Has been cancelled
esp32 port / build_idf (esp32_build_cmod_spiram_s2) (push) Has been cancelled
esp32 port / build_idf (esp32_build_s3_c3) (push) Has been cancelled
esp8266 port / build (push) Has been cancelled
mimxrt port / build (push) Has been cancelled
nrf port / build (push) Has been cancelled
powerpc port / build (push) Has been cancelled
qemu port / build_and_test_arm (push) Has been cancelled
qemu port / build_and_test_rv32 (push) Has been cancelled
renesas-ra port / build_renesas_ra_board (push) Has been cancelled
rp2 port / build (push) Has been cancelled
samd port / build (push) Has been cancelled
stm32 port / build_stm32 (stm32_misc_build) (push) Has been cancelled
stm32 port / build_stm32 (stm32_nucleo_build) (push) Has been cancelled
stm32 port / build_stm32 (stm32_pyb_build) (push) Has been cancelled
unix port / minimal (push) Has been cancelled
unix port / reproducible (push) Has been cancelled
unix port / standard (push) Has been cancelled
unix port / standard_v2 (push) Has been cancelled
unix port / coverage (push) Has been cancelled
unix port / coverage_32bit (push) Has been cancelled
unix port / nanbox (push) Has been cancelled
unix port / float (push) Has been cancelled
unix port / stackless_clang (push) Has been cancelled
unix port / float_clang (push) Has been cancelled
unix port / settrace (push) Has been cancelled
unix port / settrace_stackless (push) Has been cancelled
unix port / macos (push) Has been cancelled
unix port / qemu_mips (push) Has been cancelled
unix port / qemu_arm (push) Has been cancelled
unix port / qemu_riscv64 (push) Has been cancelled
webassembly port / build (push) Has been cancelled
windows port / build-vs (Debug, x64, windows-2022, dev, 2022, [17, 18)) (push) Has been cancelled
windows port / build-vs (Debug, x64, windows-latest, dev, 2017, [15, 16)) (push) Has been cancelled
windows port / build-vs (Debug, x86, windows-2022, dev, 2022, [17, 18)) (push) Has been cancelled
windows port / build-vs (Debug, x86, windows-latest, dev, 2017, [15, 16)) (push) Has been cancelled
windows port / build-vs (Release, x64, windows-2019, dev, 2019, [16, 17)) (push) Has been cancelled
windows port / build-vs (Release, x64, windows-2019, standard, 2019, [16, 17)) (push) Has been cancelled
windows port / build-vs (Release, x64, windows-2022, dev, 2022, [17, 18)) (push) Has been cancelled
windows port / build-vs (Release, x64, windows-2022, standard, 2022, [17, 18)) (push) Has been cancelled
windows port / build-vs (Release, x64, windows-latest, dev, 2017, [15, 16)) (push) Has been cancelled
windows port / build-vs (Release, x64, windows-latest, standard, 2017, [15, 16)) (push) Has been cancelled
windows port / build-vs (Release, x86, windows-2019, dev, 2019, [16, 17)) (push) Has been cancelled
windows port / build-vs (Release, x86, windows-2019, standard, 2019, [16, 17)) (push) Has been cancelled
windows port / build-vs (Release, x86, windows-2022, dev, 2022, [17, 18)) (push) Has been cancelled
windows port / build-vs (Release, x86, windows-2022, standard, 2022, [17, 18)) (push) Has been cancelled
windows port / build-vs (Release, x86, windows-latest, dev, 2017, [15, 16)) (push) Has been cancelled
windows port / build-vs (Release, x86, windows-latest, standard, 2017, [15, 16)) (push) Has been cancelled
windows port / build-mingw (i686, mingw32, dev) (push) Has been cancelled
windows port / build-mingw (i686, mingw32, standard) (push) Has been cancelled
windows port / build-mingw (x86_64, mingw64, dev) (push) Has been cancelled
windows port / build-mingw (x86_64, mingw64, standard) (push) Has been cancelled
windows port / cross-build-on-linux (push) Has been cancelled
zephyr port / build (push) Has been cancelled
Python code lint and formatting with ruff / ruff (push) Has been cancelled
Some checks failed
JavaScript code lint and formatting with Biome / eslint (push) Has been cancelled
Check code formatting / code-formatting (push) Has been cancelled
Check spelling with codespell / codespell (push) Has been cancelled
Build docs / build (push) Has been cancelled
Check examples / embedding (push) Has been cancelled
Package mpremote / build (push) Has been cancelled
.mpy file format and tools / test (push) Has been cancelled
Build ports metadata / build (push) Has been cancelled
cc3200 port / build (push) Has been cancelled
esp32 port / build_idf (esp32_build_cmod_spiram_s2) (push) Has been cancelled
esp32 port / build_idf (esp32_build_s3_c3) (push) Has been cancelled
esp8266 port / build (push) Has been cancelled
mimxrt port / build (push) Has been cancelled
nrf port / build (push) Has been cancelled
powerpc port / build (push) Has been cancelled
qemu port / build_and_test_arm (push) Has been cancelled
qemu port / build_and_test_rv32 (push) Has been cancelled
renesas-ra port / build_renesas_ra_board (push) Has been cancelled
rp2 port / build (push) Has been cancelled
samd port / build (push) Has been cancelled
stm32 port / build_stm32 (stm32_misc_build) (push) Has been cancelled
stm32 port / build_stm32 (stm32_nucleo_build) (push) Has been cancelled
stm32 port / build_stm32 (stm32_pyb_build) (push) Has been cancelled
unix port / minimal (push) Has been cancelled
unix port / reproducible (push) Has been cancelled
unix port / standard (push) Has been cancelled
unix port / standard_v2 (push) Has been cancelled
unix port / coverage (push) Has been cancelled
unix port / coverage_32bit (push) Has been cancelled
unix port / nanbox (push) Has been cancelled
unix port / float (push) Has been cancelled
unix port / stackless_clang (push) Has been cancelled
unix port / float_clang (push) Has been cancelled
unix port / settrace (push) Has been cancelled
unix port / settrace_stackless (push) Has been cancelled
unix port / macos (push) Has been cancelled
unix port / qemu_mips (push) Has been cancelled
unix port / qemu_arm (push) Has been cancelled
unix port / qemu_riscv64 (push) Has been cancelled
webassembly port / build (push) Has been cancelled
windows port / build-vs (Debug, x64, windows-2022, dev, 2022, [17, 18)) (push) Has been cancelled
windows port / build-vs (Debug, x64, windows-latest, dev, 2017, [15, 16)) (push) Has been cancelled
windows port / build-vs (Debug, x86, windows-2022, dev, 2022, [17, 18)) (push) Has been cancelled
windows port / build-vs (Debug, x86, windows-latest, dev, 2017, [15, 16)) (push) Has been cancelled
windows port / build-vs (Release, x64, windows-2019, dev, 2019, [16, 17)) (push) Has been cancelled
windows port / build-vs (Release, x64, windows-2019, standard, 2019, [16, 17)) (push) Has been cancelled
windows port / build-vs (Release, x64, windows-2022, dev, 2022, [17, 18)) (push) Has been cancelled
windows port / build-vs (Release, x64, windows-2022, standard, 2022, [17, 18)) (push) Has been cancelled
windows port / build-vs (Release, x64, windows-latest, dev, 2017, [15, 16)) (push) Has been cancelled
windows port / build-vs (Release, x64, windows-latest, standard, 2017, [15, 16)) (push) Has been cancelled
windows port / build-vs (Release, x86, windows-2019, dev, 2019, [16, 17)) (push) Has been cancelled
windows port / build-vs (Release, x86, windows-2019, standard, 2019, [16, 17)) (push) Has been cancelled
windows port / build-vs (Release, x86, windows-2022, dev, 2022, [17, 18)) (push) Has been cancelled
windows port / build-vs (Release, x86, windows-2022, standard, 2022, [17, 18)) (push) Has been cancelled
windows port / build-vs (Release, x86, windows-latest, dev, 2017, [15, 16)) (push) Has been cancelled
windows port / build-vs (Release, x86, windows-latest, standard, 2017, [15, 16)) (push) Has been cancelled
windows port / build-mingw (i686, mingw32, dev) (push) Has been cancelled
windows port / build-mingw (i686, mingw32, standard) (push) Has been cancelled
windows port / build-mingw (x86_64, mingw64, dev) (push) Has been cancelled
windows port / build-mingw (x86_64, mingw64, standard) (push) Has been cancelled
windows port / cross-build-on-linux (push) Has been cancelled
zephyr port / build (push) Has been cancelled
Python code lint and formatting with ruff / ruff (push) Has been cancelled
- Renamed gc_sweep to gc_sweep_free_blocks. - Call gc_sweep_run_finalisers from top level. - Reordered the gc static functions to be in approximate runtime sequence (with forward declarations) rather than in declaration order. This work was funded through GitHub Sponsors. Signed-off-by: Angus Gratton <angus@redyak.com.au>
This commit is contained in:
committed by
Damien George
parent
fd0e529a47
commit
990f50fbb8
175
py/gc.c
175
py/gc.c
@@ -123,6 +123,18 @@
|
||||
#define GC_EXIT()
|
||||
#endif
|
||||
|
||||
// Static functions for individual steps of the GC mark/sweep sequence
|
||||
static void gc_collect_start_common(void);
|
||||
static void *gc_get_ptr(void **ptrs, int i);
|
||||
#if MICROPY_GC_SPLIT_HEAP
|
||||
static void gc_mark_subtree(mp_state_mem_area_t *area, size_t block);
|
||||
#else
|
||||
static void gc_mark_subtree(size_t block);
|
||||
#endif
|
||||
static void gc_deal_with_stack_overflow(void);
|
||||
static void gc_sweep_run_finalisers(void);
|
||||
static void gc_sweep_free_blocks(void);
|
||||
|
||||
// TODO waste less memory; currently requires that all entries in alloc_table have a corresponding block in pool
|
||||
static void gc_setup_area(mp_state_mem_area_t *area, void *start, void *end) {
|
||||
// calculate parameters for GC (T=total, A=alloc table, F=finaliser table, P=pool; all in bytes):
|
||||
@@ -379,6 +391,64 @@ static inline mp_state_mem_area_t *gc_get_ptr_area(const void *ptr) {
|
||||
#endif
|
||||
#endif
|
||||
|
||||
void gc_collect_start(void) {
|
||||
gc_collect_start_common();
|
||||
#if MICROPY_GC_ALLOC_THRESHOLD
|
||||
MP_STATE_MEM(gc_alloc_amount) = 0;
|
||||
#endif
|
||||
|
||||
// Trace root pointers. This relies on the root pointers being organised
|
||||
// correctly in the mp_state_ctx structure. We scan nlr_top, dict_locals,
|
||||
// dict_globals, then the root pointer section of mp_state_vm.
|
||||
void **ptrs = (void **)(void *)&mp_state_ctx;
|
||||
size_t root_start = offsetof(mp_state_ctx_t, thread.dict_locals);
|
||||
size_t root_end = offsetof(mp_state_ctx_t, vm.qstr_last_chunk);
|
||||
gc_collect_root(ptrs + root_start / sizeof(void *), (root_end - root_start) / sizeof(void *));
|
||||
|
||||
#if MICROPY_ENABLE_PYSTACK
|
||||
// Trace root pointers from the Python stack.
|
||||
ptrs = (void **)(void *)MP_STATE_THREAD(pystack_start);
|
||||
gc_collect_root(ptrs, (MP_STATE_THREAD(pystack_cur) - MP_STATE_THREAD(pystack_start)) / sizeof(void *));
|
||||
#endif
|
||||
}
|
||||
|
||||
static void gc_collect_start_common(void) {
|
||||
GC_ENTER();
|
||||
assert((MP_STATE_THREAD(gc_lock_depth) & GC_COLLECT_FLAG) == 0);
|
||||
MP_STATE_THREAD(gc_lock_depth) |= GC_COLLECT_FLAG;
|
||||
MP_STATE_MEM(gc_stack_overflow) = 0;
|
||||
}
|
||||
|
||||
void gc_collect_root(void **ptrs, size_t len) {
|
||||
#if !MICROPY_GC_SPLIT_HEAP
|
||||
mp_state_mem_area_t *area = &MP_STATE_MEM(area);
|
||||
#endif
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
MICROPY_GC_HOOK_LOOP(i);
|
||||
void *ptr = gc_get_ptr(ptrs, i);
|
||||
#if MICROPY_GC_SPLIT_HEAP
|
||||
mp_state_mem_area_t *area = gc_get_ptr_area(ptr);
|
||||
if (!area) {
|
||||
continue;
|
||||
}
|
||||
#else
|
||||
if (!VERIFY_PTR(ptr)) {
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
size_t block = BLOCK_FROM_PTR(area, ptr);
|
||||
if (ATB_GET_KIND(area, block) == AT_HEAD) {
|
||||
// An unmarked head: mark it, and mark all its children
|
||||
ATB_HEAD_TO_MARK(area, block);
|
||||
#if MICROPY_GC_SPLIT_HEAP
|
||||
gc_mark_subtree(area, block);
|
||||
#else
|
||||
gc_mark_subtree(block);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Take the given block as the topmost block on the stack. Check all it's
|
||||
// children: mark the unmarked child blocks and put those newly marked
|
||||
// blocks on the stack. When all children have been checked, pop off the
|
||||
@@ -457,6 +527,25 @@ static void gc_mark_subtree(size_t block)
|
||||
}
|
||||
}
|
||||
|
||||
void gc_sweep_all(void) {
|
||||
gc_collect_start_common();
|
||||
gc_collect_end();
|
||||
}
|
||||
|
||||
void gc_collect_end(void) {
|
||||
gc_deal_with_stack_overflow();
|
||||
gc_sweep_run_finalisers();
|
||||
gc_sweep_free_blocks();
|
||||
#if MICROPY_GC_SPLIT_HEAP
|
||||
MP_STATE_MEM(gc_last_free_area) = &MP_STATE_MEM(area);
|
||||
#endif
|
||||
for (mp_state_mem_area_t *area = &MP_STATE_MEM(area); area != NULL; area = NEXT_AREA(area)) {
|
||||
area->gc_last_free_atb_index = 0;
|
||||
}
|
||||
MP_STATE_THREAD(gc_lock_depth) &= ~GC_COLLECT_FLAG;
|
||||
GC_EXIT();
|
||||
}
|
||||
|
||||
static void gc_deal_with_stack_overflow(void) {
|
||||
while (MP_STATE_MEM(gc_stack_overflow)) {
|
||||
MP_STATE_MEM(gc_stack_overflow) = 0;
|
||||
@@ -520,18 +609,16 @@ static void gc_sweep_run_finalisers(void) {
|
||||
#endif // MICROPY_ENABLE_FINALISER
|
||||
}
|
||||
|
||||
static void gc_sweep(void) {
|
||||
// Free unmarked heads and their tails
|
||||
static void gc_sweep_free_blocks(void) {
|
||||
#if MICROPY_PY_GC_COLLECT_RETVAL
|
||||
MP_STATE_MEM(gc_collected) = 0;
|
||||
#endif
|
||||
// free unmarked heads and their tails
|
||||
int free_tail = 0;
|
||||
#if MICROPY_GC_SPLIT_HEAP_AUTO
|
||||
mp_state_mem_area_t *prev_area = NULL;
|
||||
#endif
|
||||
|
||||
gc_sweep_run_finalisers();
|
||||
|
||||
for (mp_state_mem_area_t *area = &MP_STATE_MEM(area); area != NULL; area = NEXT_AREA(area)) {
|
||||
size_t last_used_block = 0;
|
||||
assert(area->gc_last_used_block <= area->gc_alloc_table_byte_len * BLOCKS_PER_ATB);
|
||||
@@ -541,7 +628,7 @@ static void gc_sweep(void) {
|
||||
switch (ATB_GET_KIND(area, block)) {
|
||||
case AT_HEAD:
|
||||
free_tail = 1;
|
||||
DEBUG_printf("gc_sweep(%p)\n", (void *)PTR_FROM_BLOCK(area, block));
|
||||
DEBUG_printf("gc_sweep_free_blocks(%p)\n", (void *)PTR_FROM_BLOCK(area, block));
|
||||
#if MICROPY_PY_GC_COLLECT_RETVAL
|
||||
MP_STATE_MEM(gc_collected)++;
|
||||
#endif
|
||||
@@ -572,7 +659,7 @@ static void gc_sweep(void) {
|
||||
#if MICROPY_GC_SPLIT_HEAP_AUTO
|
||||
// Free any empty area, aside from the first one
|
||||
if (last_used_block == 0 && prev_area != NULL) {
|
||||
DEBUG_printf("gc_sweep free empty area %p\n", area);
|
||||
DEBUG_printf("gc_sweep_free_blocks free empty area %p\n", area);
|
||||
NEXT_AREA(prev_area) = NEXT_AREA(area);
|
||||
MP_PLAT_FREE_HEAP(area);
|
||||
area = prev_area;
|
||||
@@ -582,34 +669,6 @@ static void gc_sweep(void) {
|
||||
}
|
||||
}
|
||||
|
||||
static void gc_collect_start_common(void) {
|
||||
GC_ENTER();
|
||||
assert((MP_STATE_THREAD(gc_lock_depth) & GC_COLLECT_FLAG) == 0);
|
||||
MP_STATE_THREAD(gc_lock_depth) |= GC_COLLECT_FLAG;
|
||||
MP_STATE_MEM(gc_stack_overflow) = 0;
|
||||
}
|
||||
|
||||
void gc_collect_start(void) {
|
||||
gc_collect_start_common();
|
||||
#if MICROPY_GC_ALLOC_THRESHOLD
|
||||
MP_STATE_MEM(gc_alloc_amount) = 0;
|
||||
#endif
|
||||
|
||||
// Trace root pointers. This relies on the root pointers being organised
|
||||
// correctly in the mp_state_ctx structure. We scan nlr_top, dict_locals,
|
||||
// dict_globals, then the root pointer section of mp_state_vm.
|
||||
void **ptrs = (void **)(void *)&mp_state_ctx;
|
||||
size_t root_start = offsetof(mp_state_ctx_t, thread.dict_locals);
|
||||
size_t root_end = offsetof(mp_state_ctx_t, vm.qstr_last_chunk);
|
||||
gc_collect_root(ptrs + root_start / sizeof(void *), (root_end - root_start) / sizeof(void *));
|
||||
|
||||
#if MICROPY_ENABLE_PYSTACK
|
||||
// Trace root pointers from the Python stack.
|
||||
ptrs = (void **)(void *)MP_STATE_THREAD(pystack_start);
|
||||
gc_collect_root(ptrs, (MP_STATE_THREAD(pystack_cur) - MP_STATE_THREAD(pystack_start)) / sizeof(void *));
|
||||
#endif
|
||||
}
|
||||
|
||||
// Address sanitizer needs to know that the access to ptrs[i] must always be
|
||||
// considered OK, even if it's a load from an address that would normally be
|
||||
// prohibited (due to being undefined, in a red zone, etc).
|
||||
@@ -625,54 +684,6 @@ static void *gc_get_ptr(void **ptrs, int i) {
|
||||
return ptrs[i];
|
||||
}
|
||||
|
||||
void gc_collect_root(void **ptrs, size_t len) {
|
||||
#if !MICROPY_GC_SPLIT_HEAP
|
||||
mp_state_mem_area_t *area = &MP_STATE_MEM(area);
|
||||
#endif
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
MICROPY_GC_HOOK_LOOP(i);
|
||||
void *ptr = gc_get_ptr(ptrs, i);
|
||||
#if MICROPY_GC_SPLIT_HEAP
|
||||
mp_state_mem_area_t *area = gc_get_ptr_area(ptr);
|
||||
if (!area) {
|
||||
continue;
|
||||
}
|
||||
#else
|
||||
if (!VERIFY_PTR(ptr)) {
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
size_t block = BLOCK_FROM_PTR(area, ptr);
|
||||
if (ATB_GET_KIND(area, block) == AT_HEAD) {
|
||||
// An unmarked head: mark it, and mark all its children
|
||||
ATB_HEAD_TO_MARK(area, block);
|
||||
#if MICROPY_GC_SPLIT_HEAP
|
||||
gc_mark_subtree(area, block);
|
||||
#else
|
||||
gc_mark_subtree(block);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void gc_collect_end(void) {
|
||||
gc_deal_with_stack_overflow();
|
||||
gc_sweep();
|
||||
#if MICROPY_GC_SPLIT_HEAP
|
||||
MP_STATE_MEM(gc_last_free_area) = &MP_STATE_MEM(area);
|
||||
#endif
|
||||
for (mp_state_mem_area_t *area = &MP_STATE_MEM(area); area != NULL; area = NEXT_AREA(area)) {
|
||||
area->gc_last_free_atb_index = 0;
|
||||
}
|
||||
MP_STATE_THREAD(gc_lock_depth) &= ~GC_COLLECT_FLAG;
|
||||
GC_EXIT();
|
||||
}
|
||||
|
||||
void gc_sweep_all(void) {
|
||||
gc_collect_start_common();
|
||||
gc_collect_end();
|
||||
}
|
||||
|
||||
void gc_info(gc_info_t *info) {
|
||||
GC_ENTER();
|
||||
info->total = 0;
|
||||
|
Reference in New Issue
Block a user