10000 py/gc.c: Reduce image sizes when GC multi-heap disabled. · micropython/micropython@7c80102 · GitHub
[go: up one dir, main page]

Skip to content

Commit 7c80102

Browse files
committed
py/gc.c: Reduce image sizes when GC multi-heap disabled.
Use C macros to reduce size of firmware images when GC multiple heap feature is disabled. Image size diffs versus current master (28e7e15) when multi-heap *disabled*: bare-arm: +0 +0.000% minimal x86: +0 +0.000% unix x64: -16 -0.003% unix nanbox: -20 -0.004% stm32: -8 -0.002% PYBV10 cc3200: +0 +0.000% esp8266: +8 +0.001% GENERIC esp32: +0 +0.000% GENERIC nrf: -20 -0.011% pca10040 rp2: +0 +0.000% PICO samd: -4 -0.003% ADAFRUIT_ITSYBITSY_M4_EXPRESS Note that only the stm32 image gets slightly bigger (+8). Image size diffs versus current master when multi-heap is *enabled* with `MICROPY_GC_MULTIHEAP=1` (but not extra code to add more heaps): unix x64: +1032 +0.197% [incl +544(bss)] esp32: +592 +0.039% GENERIC[incl +16(data) +264(bss)]
1 parent a7ae684 commit 7c80102

File tree

2 files changed

+90
-44
lines changed

2 files changed

+90
-44
lines changed

py/gc.c

Lines changed: 85 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,7 @@ bool gc_is_locked(void) {
230230
return MP_STATE_THREAD(gc_lock_depth) != 0;
231231
}
232232

233+
#if MICROPY_GC_MULTIHEAP
233234
// Returns the area to which this pointer belongs, or NULL if it isn't
234235
// allocated on the GC-managed heap.
235236
STATIC inline mp_state_mem_area_t *gc_get_ptr_area(const void *ptr) {
@@ -244,6 +245,14 @@ STATIC inline mp_state_mem_area_t *gc_get_ptr_area(const void *ptr) {
244245
}
245246
return NULL;
246247
}
248+
#endif
249+
250+
// ptr should be of type void*
251+
#define VERIFY_PTR(ptr) ( \
252+
((uintptr_t)(ptr) & (BYTES_PER_BLOCK - 1)) == 0 /* must be aligned on a block */ \
253+
&& ptr >= (void *)MP_STATE_MEM(area).gc_pool_start /* must be above start of pool */ \
254+
&& ptr < (void *)MP_STATE_MEM(area).gc_pool_end /* must be below end of pool */ \
255+
)
247256

248257
#ifndef TRACE_MARK
249258
#if DEBUG_PRINT
@@ -257,18 +266,20 @@ STATIC inline mp_state_mem_area_t *gc_get_ptr_area(const void *ptr) {
257266
// children: mark the unmarked child blocks and put those newly marked
258267
// blocks on the stack. When all children have been checked, pop off the
259268
// topmost block on the stack and repeat with that one.
260-
STATIC void gc_mark_subtree(mp_gc_stack_item_t item) {
261-
// Start with the item passed in the argument.
269+
#if MICROPY_GC_MULTIHEAP
270+
STATIC void gc_mark_subtree(mp_state_mem_area_t *area, size_t block)
271+
#else
272+
STATIC void gc_mark_subtree(size_t block)
273+
#endif
274+
{
275+
// Start with the block passed in the argument.
262276
size_t sp = 0;
263277
for (;;) {
264278
MICROPY_GC_HOOK_LOOP
265279

266-
#if MICROPY_GC_MULTIHEAP
267-
mp_state_mem_area_t *area = item.area;
268-
#else
269-
mp_state_mem_area_t *area = &MP_STATE_MEM(area);
280+
#if !MICROPY_GC_MULTIHEAP
281+
mp_state_mem_area_t * area = &MP_STATE_MEM(area);
270282
#endif
271-
size_t block = item.block;
272283

273284
// work out number of consecutive blocks in the chain starting with this one
274285
size_t n_blocks = 0;
@@ -283,11 +294,18 @@ STATIC void gc_mark_subtree(mp_gc_stack_item_t item) {
283294
void *ptr = *ptrs;
284295
// If this is a heap pointer that hasn't been marked, mark it and push
285296
// it's children to the stack.
297+
#if MICROPY_GC_MULTIHEAP
286298
mp_state_mem_area_t *ptr_area = gc_get_ptr_area(ptr);
287299
if (!ptr_area) {
288300
// Not a heap-allocated pointer (might even be random data).
289301
continue;
290302
}
303+
#else
304+
if (!VERIFY_PTR(ptr)) {
305+
continue;
306+
}
307+
mp_state_mem_area_t *ptr_area = area;
308+
#endif
291309
size_t ptr_block = BLOCK_FROM_PTR(ptr_area, ptr);
292310
if (ATB_GET_KIND(ptr_area, ptr_block) != AT_HEAD) {
293311
// This block is already marked.
@@ -297,24 +315,27 @@ STATIC void gc_mark_subtree(mp_gc_stack_item_t item) {
297315
TRACE_MARK(ptr_block, ptr);
298316
ATB_HEAD_TO_MARK(ptr_area, ptr_block);
299317
if (sp < MICROPY_ALLOC_GC_STACK_SIZE) {
318+
MP_STATE_MEM(gc_block_stack)[sp] = ptr_block;
300319
#if MICROPY_GC_MULTIHEAP
301-
mp_gc_stack_item_t ptr_item = {ptr_area, ptr_block};
302-
#else
303-
mp_gc_stack_item_t ptr_item = {ptr_block};
320+
MP_STATE_MEM(gc_area_stack)[sp] = ptr_area;
304321
#endif
305-
MP_STATE_MEM(gc_stack)[sp++] = ptr_item;
322+
sp += 1;
306323
} else {
307324
MP_STATE_MEM(gc_stack_overflow) = 1;
308325
}
309326
}
310327

311-
// Are there any items on the stack?
328+
// Are there any blocks on the stack?
312329
if (sp == 0) {
313330
break; // No, stack is empty, we're done.
314331
}
315332

316-
// pop the next item off the stack
317-
item = MP_STATE_MEM(gc_stack)[--sp];
333+
// pop the next block off the stack
334+
sp -= 1;
335+
block = MP_STATE_MEM(gc_block_stack)[sp];
336+
#if MICROPY_GC_MULTIHEAP
337+
area = MP_STATE_MEM(gc_area_stack)[sp];
338+
#endif
318339
}
319340
}
320341

@@ -329,13 +350,10 @@ STATIC void gc_deal_with_stack_overflow(void) {
329350
// trace (again) if mark bit set
330351
if (ATB_GET_KIND(area, block) == AT_MARK) {
331352
#if MICROPY_GC_MULTIHEAP
332-
mp_gc_stack_item_t item = {area, block};
353+
gc_mark_subtree(area, block);
333354
#else
334-
mp_gc_stack_item_t item = {block};
355+
gc_mark_subtree(block);
335356
#endif
336-
// *MP_STATE_MEM(gc_sp)++ = item;
337-
// gc_drain_stack();
338-
gc_mark_subtree(item);
339357
}
340358
}
341359
}
@@ -435,23 +453,32 @@ static void *gc_get_ptr(void **ptrs, int i) {
435453
}
436454

437455
void gc_collect_root(void **ptrs, size_t len) {
456+
#if !MICROPY_GC_MULTIHEAP
457+
mp_state_mem_area_t *area = &MP_STATE_MEM(area);
458+
#endif
438459
for (size_t i = 0; i < len; i++) {
439460
MICROPY_GC_HOOK_LOOP
440461
// void *ptr = ptrs[i];
441462
void *ptr = gc_get_ptr(ptrs, i);
463+
#if MICROPY_GC_MULTIHEAP
442464
mp_state_mem_area_t *area = gc_get_ptr_area(ptr);
443-
if (area) {
444-
size_t block = BLOCK_FROM_PTR(area, ptr);
445-
if (ATB_GET_KIND(area, block) == AT_HEAD) {
446-
// An unmarked head: mark it, and mark all its children
447-
ATB_HEAD_TO_MARK(area, block);
448-
#if MICROPY_GC_MULTIHEAP
449-
mp_gc_stack_item_t item = {area, block};
450-
#else
451-
mp_gc_stack_item_t item = {block};
452-
#endif
453-
gc_mark_subtree(item);
454-
}
465+
if (!area) {
466+
continue;
467+
}
468+
#else
469+
if (!VERIFY_PTR(ptr)) {
470+
continue;
471+
}
472+
#endif
473+
size_t block = BLOCK_FROM_PTR(area, ptr);
474+
if (ATB_GET_KIND(area, block) == AT_HEAD) {
475+
// An unmarked head: mark it, and mark all its children
476+
ATB_HEAD_TO_MARK(area, block);
477+
#if MICROPY_GC_MULTIHEAP
478+
gc_mark_subtree(area, block);
479+
#else
480+
gc_mark_subtree(block);
481+
#endif
455482
}
456483
}
457484
}
@@ -717,8 +744,15 @@ void gc_free(void *ptr) {
717744
}
718745

719746
// get the GC block number corresponding to this pointer
720-
mp_state_mem_area_t *area = gc_get_ptr_area(ptr);
747+
mp_state_mem_area_t *area;
748+
#if MICROPY_GC_MULTIHEAP
749+
area = gc_get_ptr_area(ptr);
721750
assert(area);
751+
#else
752+
assert(VERIFY_PTR(ptr));
753+
area = &MP_STATE_MEM(area);
754+
#endif
755+
722756
size_t block = BLOCK_FROM_PTR(area, ptr);
723757
assert(ATB_GET_KIND(area, block) == AT_HEAD);
724758

@@ -761,7 +795,18 @@ void gc_free(void *ptr) {
761795

762796
size_t gc_nbytes(const void *ptr) {
763797
GC_ENTER();
764-
mp_state_mem_area_t *area = gc_get_ptr_area(ptr);
798+
799+
mp_state_mem_area_t *area;
800+
#if MICROPY_GC_MULTIHEAP
801+
area = gc_get_ptr_area(ptr);
802+
#else
803+
if (VERIFY_PTR(ptr)) {
804+
area = &MP_STATE_MEM(area);
805+
} else {
806+
area = NULL;
807+
}
808+
#endif
809+
765810
if (area) {
766811
size_t block = BLOCK_FROM_PTR(area, ptr);
767812
if (ATB_GET_KIND(area, block) == AT_HEAD) {
@@ -830,8 +875,14 @@ void *gc_realloc(void *ptr_in, size_t n_bytes, bool allow_move) {
830875
GC_ENTER();
831876

832877
// get the GC block number corresponding to this pointer
833-
mp_state_mem_area_t *area = gc_get_ptr_area(ptr);
878+
mp_state_mem_area_t *area;
879+
#if MICROPY_GC_MULTIHEAP
880+
area = gc_get_ptr_area(ptr);
834881
assert(area);
882+
#else
883+
assert(VERIFY_PTR(ptr));
884+
area = &MP_STATE_MEM(area);
885+
#endif
835886
size_t block = BLOCK_FROM_PTR(area, ptr);
836887
assert(ATB_GET_KIND(area, block) == AT_HEAD);
837888

py/mpstate.h

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -90,15 +90,6 @@ typedef struct _mp_state_mem_area_t {
9090
size_t gc_last_free_atb_index;
9191
} mp_state_mem_area_t;
9292

93-
// This structure holds a single stacked block and the area it is on. Used
94-
// during garbage collection.
95-
typedef struct {
96-
#if MICROPY_GC_MULTIHEAP
97-
mp_state_mem_area_t *area;
98-
#endif
99-
size_t block;
100-
} mp_gc_stack_item_t;
101-
10293
// This structure hold information about the memory allocation system.
10394
typedef struct _mp_state_mem_t {
10495
#if MICROPY_MEM_STATS
@@ -110,7 +101,11 @@ typedef struct _mp_state_mem_t {
110101
mp_state_mem_area_t area;
111102

112103
int gc_stack_overflow;
113-
mp_gc_stack_item_t gc_stack[MICROPY_ALLOC_GC_STACK_SIZE];
104+
MICROPY_GC_STACK_ENTRY_TYPE gc_block_stack[MICROPY_ALLOC_GC_STACK_SIZE];
105+
#if MICROPY_GC_MULTIHEAP
106+
// Array that that track area for each block on the stack.
107+
mp_state_mem_area_t *gc_area_stack[MICROPY_ALLOC_GC_STACK_SIZE];
108+
#endif
114109

115110
// This variable controls auto garbage collection. If set to 0 then the
116111
// GC won't automatically run when gc_alloc can't find enough blocks. But

0 commit comments

Comments
 (0)
0