Berry stores compiled bytecode into IRAM, freeing space in heap

This commit is contained in:
Stephan Hadinger 2022-01-06 13:41:51 +01:00
parent 304e13911c
commit 6755b754e0
8 changed files with 70 additions and 4 deletions

View File

@ -11,6 +11,7 @@ All notable changes to this project will be documented in this file.
- PubSubClient library from v2.8.12 to v2.8.13
- From Semantic Versioning (SemVer) to Calendar Versioning (CalVer)
- Set ESP32 stack size with ``#define SET_ESP32_STACK_SIZE``, added ``StackLowMark`` metrics
- Berry stores compiled bytecode into IRAM, freeing space in heap
### Fixed
- Intermittent exceptions and heap corruption due to PubSubClient library buffer overflow (#13700)

View File

@ -214,6 +214,9 @@ extern "C" {
extern void *berry_malloc(size_t size);
extern void berry_free(void *ptr);
extern void *berry_realloc(void *ptr, size_t size);
extern void *berry_malloc32(size_t size);
extern void berry_free32(void *ptr);
extern void *berry_realloc32(void *ptr, size_t size);
#ifdef __cplusplus
}
#endif
@ -241,7 +244,7 @@ extern "C" {
/* Tasmota debug specific */
#ifdef USE_BERRY_DEBUG
#undef BE_DEBUG_RUNTIME_INFO
#define BE_DEBUG_RUNTIME_INFO 2 /* record line information in 16 bits */
#define BE_DEBUG_RUNTIME_INFO 1 /* record line information in 32 bits to be places in IRAM */
#endif // USE_BERRY_DEBUG
#endif

View File

@ -313,14 +313,14 @@ static void end_func(bparser *parser)
be_code_ret(finfo, NULL); /* append a return to last code */
end_block(parser); /* close block */
setupvals(finfo); /* close upvals */
proto->code = be_vector_release(vm, &finfo->code); /* compact all vectors and return NULL if empty */
proto->code = be_vector_release_32(vm, &finfo->code); /* compact all vectors and return NULL if empty */
proto->codesize = finfo->pc;
proto->ktab = be_vector_release(vm, &finfo->kvec);
proto->ktab = be_vector_release_32(vm, &finfo->kvec);
proto->nconst = be_vector_count(&finfo->kvec);
proto->ptab = be_vector_release(vm, &finfo->pvec);
proto->nproto = be_vector_count(&finfo->pvec);
#if BE_DEBUG_RUNTIME_INFO
proto->lineinfo = be_vector_release(vm, &finfo->linevec);
proto->lineinfo = be_vector_release_32(vm, &finfo->linevec);
proto->nlineinfo = be_vector_count(&finfo->linevec);
#endif
#if BE_DEBUG_VAR_INFO

View File

@ -110,6 +110,32 @@ void* be_vector_release(bvm *vm, bvector *vector)
return vector->data;
}
/* free not used */
void* be_vector_release_32(bvm *vm, bvector *vector)
{
size_t size = vector->size;
int count = be_vector_count(vector);
if (count == 0) {
be_free(vm, vector->data, vector->capacity * size);
vector->capacity = 0;
vector->data = NULL;
vector->end = NULL;
} else if (count < vector->capacity) {
vector->data = be_realloc(vm,
vector->data, vector->capacity * size, count * size); // TODO - can we skip that step?
void* iram = berry_malloc32(count * size);
if (iram) {
memcpy(iram, vector->data, count * size);
free(vector->data);
vector->data = iram;
}
// vm->gc.usage = vm->gc.usage + count * size - vector->capacity * size; /* update allocated count */
vector->end = (char*)vector->data + ((size_t)count - 1) * size;
vector->capacity = count;
}
return vector->data;
}
/* use binary search to find the vector capacity between 0-1024 */
static int binary_search(int value)
{

View File

@ -38,6 +38,7 @@ void be_vector_remove_end(bvector *vector);
void be_vector_resize(bvm *vm, bvector *vector, int count);
void be_vector_clear(bvector *vector);
void* be_vector_release(bvm *vm, bvector *vector);
void* be_vector_release_32(bvm *vm, bvector *vector); /* specialized call for 32 bits aligned accesses */
int be_nextsize(int value);
#endif

View File

@ -1009,6 +1009,7 @@
#define USE_BERRY_PYTHON_COMPAT // Enable by default `import python_compat`
#define USE_BERRY_TIMEOUT 4000 // Timeout in ms, will raise an exception if running time exceeds this timeout
#define USE_BERRY_PSRAM // Allocate Berry memory in PSRAM if PSRAM is connected - this might be slightly slower but leaves main memory intact
#define USE_BERRY_IRAM // Allocate some data structures in IRAM (which is ususally unused) when possible and if no PSRAM is available
// #define USE_BERRY_DEBUG // Compile Berry bytecode with line number information, makes exceptions easier to debug. Adds +8% of memory consumption for compiled code
#define USE_WEBCLIENT // Enable `webclient` to make HTTP/HTTPS requests. Can be disabled for security reasons.
// #define USE_WEBCLIENT_HTTPS // Enable HTTPS outgoing requests based on BearSSL (much ligher then mbedTLS, 42KB vs 150KB) in insecure mode (no verification of server's certificate)

View File

@ -503,6 +503,17 @@ void *special_calloc(size_t num, size_t size) {
}
}
// Variants for IRAM heap, which need all accesses to be 32 bits aligned
void *special_malloc32(uint32_t size) {
return heap_caps_malloc(size, UsePSRAM() ? MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT : MALLOC_CAP_32BIT);
}
void *special_realloc32(void *ptr, size_t size) {
return heap_caps_realloc(ptr, size, UsePSRAM() ? MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT : MALLOC_CAP_32BIT);
}
void *special_calloc32(size_t num, size_t size) {
return heap_caps_calloc(num, size, UsePSRAM() ? MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT : MALLOC_CAP_32BIT);
}
float CpuTemperature(void) {
#ifdef CONFIG_IDF_TARGET_ESP32
return (float)temperatureRead(); // In Celsius

View File

@ -84,6 +84,29 @@ extern "C" {
}
#endif // USE_BERRY_PSRAM
void *berry_malloc32(uint32_t size) {
#ifdef USE_BERRY_IRAM
return special_malloc32(size);
#else
return special_malloc(size);
#endif
}
void *berry_realloc32(void *ptr, size_t size) {
#ifdef USE_BERRY_IRAM
return special_realloc32(ptr, size);
#else
return special_realloc(ptr, size);
#endif
}
void *berry_calloc32(size_t num, size_t size) {
#ifdef USE_BERRY_IRAM
return special_calloc32(num, size);
#else
return special_calloc(num, size);
#endif
}
void berry_free(void *ptr) {
free(ptr);
}