stm: Tidy up memory labels; optimise GC root scanning.

Addresses issues #272 and #273.
This commit is contained in:
Damien George 2014-02-10 22:50:44 +00:00
parent d46ca25757
commit ed378cd12f
6 changed files with 83 additions and 39 deletions

View File

@ -8,20 +8,36 @@
#include "gccollect.h"
#include "systick.h"
void gc_helper_get_regs_and_clean_stack(machine_uint_t *regs, machine_uint_t heap_end);
machine_uint_t gc_helper_get_regs_and_sp(machine_uint_t *regs);
// obsolete
// void gc_helper_get_regs_and_clean_stack(machine_uint_t *regs, machine_uint_t heap_end);
void gc_collect(void) {
// get current time, in case we want to time the GC
uint32_t start = sys_tick_counter;
// start the GC
gc_collect_start();
gc_collect_root((void**)&_ram_start, ((uint32_t)&_heap_start - (uint32_t)&_ram_start) / sizeof(uint32_t));
// scan everything in RAM before the heap
// this includes the data and bss segments
// TODO possibly don't need to scan data, since all pointers should start out NULL and be in bss
gc_collect_root((void**)&_ram_start, ((uint32_t)&_bss_end - (uint32_t)&_ram_start) / sizeof(uint32_t));
// get the registers and the sp
machine_uint_t regs[10];
gc_helper_get_regs_and_clean_stack(regs, (machine_uint_t)&_heap_end);
gc_collect_root((void**)&_heap_end, ((uint32_t)&_ram_end - (uint32_t)&_heap_end) / sizeof(uint32_t)); // will trace regs since they now live in this function on the stack
machine_uint_t sp = gc_helper_get_regs_and_sp(regs);
// trace the stack, including the registers (since they live on the stack in this function)
gc_collect_root((void**)sp, ((uint32_t)&_ram_end - sp) / sizeof(uint32_t));
// end the GC
gc_collect_end();
uint32_t ticks = sys_tick_counter - start; // TODO implement a function that does this properly
if (0) {
// print GC info
uint32_t ticks = sys_tick_counter - start; // TODO implement a function that does this properly
gc_info_t info;
gc_info(&info);
printf("GC@%lu %lums\n", start, ticks);

View File

@ -1,7 +1,16 @@
// variables defining memory layout
// (these probably belong somewhere else...)
extern uint32_t _text_end;
extern uint32_t _data_start_init;
extern uint32_t _ram_start;
extern uint32_t _data_start;
extern uint32_t _data_end;
extern uint32_t _bss_start;
extern uint32_t _bss_end;
extern uint32_t _heap_start;
extern uint32_t _ram_end;
extern uint32_t _heap_end;
extern uint32_t _stack_end;
extern uint32_t _ram_end;
void gc_collect(void);

View File

@ -4,6 +4,32 @@
.text
.align 2
@ uint gc_helper_get_regs_and_sp(r0=uint regs[10])
.global gc_helper_get_regs_and_sp
.thumb
.thumb_func
.type gc_helper_get_regs_and_sp, %function
gc_helper_get_regs_and_sp:
@ store registers into given array
str r4, [r0], #4
str r5, [r0], #4
str r6, [r0], #4
str r7, [r0], #4
str r8, [r0], #4
str r9, [r0], #4
str r10, [r0], #4
str r11, [r0], #4
str r12, [r0], #4
str r13, [r0], #4
@ return the sp
mov r0, sp
bx lr
@ this next function is now obsolete
.size gc_helper_get_regs_and_clean_stack, .-gc_helper_get_regs_and_clean_stack
@ void gc_helper_get_regs_and_clean_stack(r0=uint regs[10], r1=heap_end)
.global gc_helper_get_regs_and_clean_stack
.thumb

View File

@ -171,20 +171,13 @@ static mp_obj_t pyb_info(void) {
// to print info about memory
{
extern void *_sidata;
extern void *_sdata;
extern void *_edata;
extern void *_sbss;
extern void *_ebss;
extern void *_estack;
extern void *_etext;
printf("_etext=%p\n", &_etext);
printf("_sidata=%p\n", &_sidata);
printf("_sdata=%p\n", &_sdata);
printf("_edata=%p\n", &_edata);
printf("_sbss=%p\n", &_sbss);
printf("_ebss=%p\n", &_ebss);
printf("_estack=%p\n", &_estack);
printf("_text_end=%p\n", &_text_end);
printf("_data_start_init=%p\n", &_data_start_init);
printf("_data_start=%p\n", &_data_start);
printf("_data_end=%p\n", &_data_end);
printf("_bss_start=%p\n", &_bss_start);
printf("_bss_end=%p\n", &_bss_end);
printf("_stack_end=%p\n", &_stack_end);
printf("_ram_start=%p\n", &_ram_start);
printf("_heap_start=%p\n", &_heap_start);
printf("_heap_end=%p\n", &_heap_end);

View File

@ -47,15 +47,15 @@
/* start address for the initialization values of the .data section.
defined in linker script */
.word _sidata
.word _data_start_init
/* start address for the .data section. defined in linker script */
.word _sdata
.word _data_start
/* end address for the .data section. defined in linker script */
.word _edata
.word _data_end
/* start address for the .bss section. defined in linker script */
.word _sbss
.word _bss_start
/* end address for the .bss section. defined in linker script */
.word _ebss
.word _bss_end
/* stack used for SystemInit_ExtMemCtl; always internal RAM used */
/**
@ -90,9 +90,9 @@ LoopCopyDataInit:
cmp r2, r3
bcc CopyDataInit
*/
ldr r0, =_sidata @ source pointer
ldr r1, =_sdata @ destination pointer
ldr r2, =_edata @ maximum destination pointer
ldr r0, =_data_start_init @ source pointer
ldr r1, =_data_start @ destination pointer
ldr r2, =_data_end @ maximum destination pointer
b data_init_entry
data_init_loop:
ldr r3, [r0], #4
@ -117,8 +117,8 @@ LoopFillZerobss:
*/
movs r0, #0 @ source value
ldr r1, =_sbss @ destination pointer
ldr r2, =_ebss @ maximum destination pointer
ldr r1, =_bss_start @ destination pointer
ldr r2, =_bss_end @ maximum destination pointer
b bss_init_entry
bss_init_loop:
str r0, [r1], #4
@ -158,7 +158,7 @@ Infinite_Loop:
g_pfnVectors:
.word _estack
.word _stack_end
.word Reset_Handler
.word NMI_Handler
.word HardFault_Handler

View File

@ -17,7 +17,7 @@ _minimum_stack_size = 2K;
_minimum_heap_size = 16K;
/* top end of the stack */
_estack = ORIGIN(RAM) + LENGTH(RAM);
_stack_end = ORIGIN(RAM) + LENGTH(RAM);
/* RAM extents for the garbage collector */
_ram_end = ORIGIN(RAM) + LENGTH(RAM);
@ -47,8 +47,8 @@ SECTIONS
/* *(.glue_7t) */ /* glue thumb to arm code */
. = ALIGN(4);
_etext = .; /* define a global symbol at end of code */
_sidata = _etext; /* This is used by the startup in order to initialize the .data secion */
_text_end = .; /* define a global symbol at end of code */
_data_start_init = _text_end; /* This is used by the startup in order to initialize the .data secion */
} >FLASH_TEXT
/*
@ -69,29 +69,29 @@ SECTIONS
The program executes knowing that the data is in the RAM
but the loader puts the initial values in the FLASH (inidata).
It is one task of the startup to copy the initial values from FLASH to RAM. */
.data : AT ( _sidata )
.data : AT ( _data_start_init )
{
. = ALIGN(4);
_sdata = .; /* create a global symbol at data start; used by startup code in order to initialise the .data section in RAM */
_data_start = .; /* create a global symbol at data start; used by startup code in order to initialise the .data section in RAM */
_ram_start = .; /* create a global symbol at ram start for garbage collector */
*(.data) /* .data sections */
*(.data*) /* .data* sections */
. = ALIGN(4);
_edata = .; /* define a global symbol at data end; used by startup code in order to initialise the .data section in RAM */
_data_end = .; /* define a global symbol at data end; used by startup code in order to initialise the .data section in RAM */
} >RAM
/* Uninitialized data section */
.bss :
{
. = ALIGN(4);
_sbss = .; /* define a global symbol at bss start; used by startup code */
_bss_start = .; /* define a global symbol at bss start; used by startup code */
*(.bss)
*(.bss*)
*(COMMON)
. = ALIGN(4);
_ebss = .; /* define a global symbol at bss end; used by startup code */
_bss_end = .; /* define a global symbol at bss end; used by startup code and GC */
} >RAM
/* this is to define the start of the heap, and make sure we have a minimum size */