From 95636f6003106bc3411ac22fdc44fb93e9e89ff5 Mon Sep 17 00:00:00 2001 From: Abel Stuker Date: Mon, 13 Apr 2026 15:56:32 +0200 Subject: [PATCH 01/13] Add used heap size as primitive --- src/Primitives/arduino.cpp | 7 +++++++ src/Primitives/emulated.cpp | 8 ++++++++ src/Primitives/primitives.h | 9 +++++++++ src/WARDuino.h | 2 ++ src/WARDuino/WARDuino.cpp | 15 ++++++++++++++- 5 files changed, 40 insertions(+), 1 deletion(-) diff --git a/src/Primitives/arduino.cpp b/src/Primitives/arduino.cpp index 80329573..cb150d6a 100644 --- a/src/Primitives/arduino.cpp +++ b/src/Primitives/arduino.cpp @@ -692,6 +692,11 @@ def_prim(mqtt_loop, NoneToOneU32) { return true; } +def_prim(heap_used, zeroToOneU32) { + pushUInt32(m->warduino->get_heap_used()); + return true; +} + //------------------------------------------------------ // Util functions //------------------------------------------------------ @@ -863,6 +868,8 @@ void install_primitives(Interpreter *interpreter) { install_primitive(chip_ledc_attach); install_primitive(chip_ledc_set_duty); + install_primitive(heap_used); + dbg_info("INSTALLING ISRs\n"); install_isrs(); } diff --git a/src/Primitives/emulated.cpp b/src/Primitives/emulated.cpp index 94bccf83..885a4acd 100644 --- a/src/Primitives/emulated.cpp +++ b/src/Primitives/emulated.cpp @@ -462,6 +462,12 @@ def_prim(chip_ledc_attach_pin, twoToNoneU32) { return true; } +def_prim(heap_used, zeroToOneU32) { + printf("EMU: heap_used()\n"); + pushUInt32(m->warduino->get_heap_used()); + return true; +} + //------------------------------------------------------ // Installing all the primitives //------------------------------------------------------ @@ -516,6 +522,8 @@ void install_primitives(Interpreter *interpreter) { install_primitive(read_uart_sensor); install_primitive(nxt_touch_sensor); install_primitive(ev3_touch_sensor); + + install_primitive(heap_used); } Memory external_mem{}; diff --git a/src/Primitives/primitives.h b/src/Primitives/primitives.h index 2a58761c..b0c146c9 100644 --- a/src/Primitives/primitives.h +++ b/src/Primitives/primitives.h @@ -205,6 +205,15 @@ inline Type sevenToNoneU32 = { I32; 1 = I32; 1 = I32; 1 = I32*/ }; +inline Type zeroToOneU32 = { + .form = FUNC, + .param_count = 0, + .params = param_arr_len0, + .result_count = 1, + .results = param_I32_arr_len1, + .mask = 0x810 /* 0x8 1=I32 0=endRet ; no params*/ +}; + inline Type oneToOneU32 = { .form = FUNC, .param_count = 1, diff --git a/src/WARDuino.h b/src/WARDuino.h index c1e5aa07..150efe90 100644 --- a/src/WARDuino.h +++ b/src/WARDuino.h @@ -71,4 +71,6 @@ class WARDuino { void instantiate_module(Module *m, uint8_t *bytes, uint32_t byte_count); void free_module_state(Module *m); + + uint32_t get_heap_used(); }; diff --git a/src/WARDuino/WARDuino.cpp b/src/WARDuino/WARDuino.cpp index b08de243..04d9f949 100644 --- a/src/WARDuino/WARDuino.cpp +++ b/src/WARDuino/WARDuino.cpp @@ -1092,4 +1092,17 @@ uint32_t WARDuino::get_main_fidx(Module *m) { if (fidx == UNDEF) fidx = this->get_export_fidx(m, "_main"); if (fidx == UNDEF) fidx = this->get_export_fidx(m, "_Main"); return fidx; -} \ No newline at end of file +} + +#if defined(ESP) || defined(ARDUINO) +#include +#define TOTAL_MALLOC ESP.getHeapSize() - ESP.getFreeHeap() +#elif defined(__APPLE__) +#include +#define TOTAL_MALLOC mstats().bytes_used +#else +#include +#define TOTAL_MALLOC mallinfo().uordblks +#endif + +uint32_t WARDuino::get_heap_used() { return TOTAL_MALLOC; } \ No newline at end of file From 182bed9735b6887872a8c0b9f84140dc1b31dc55 Mon Sep 17 00:00:00 2001 From: Abel Stuker Date: Mon, 13 Apr 2026 15:57:05 +0200 Subject: [PATCH 02/13] Add debugger support for used heap size --- src/Debug/debugger.cpp | 22 ++++++++++++++++++---- src/Debug/debugger.h | 3 +++ 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/src/Debug/debugger.cpp b/src/Debug/debugger.cpp index f84651b0..56adf643 100644 --- a/src/Debug/debugger.cpp +++ b/src/Debug/debugger.cpp @@ -508,12 +508,14 @@ void Debugger::dump(Module *m, bool full) const { this->dumpCallstack(m); if (full) { - this->channel->write(R"(, "locals": )"); + this->channel->write(R"( "locals": )"); this->dumpLocals(m); this->channel->write(", "); this->dumpEvents(0, static_cast(CallbackHandler::event_count())); } + this->dumpHeapInfo(m); + this->channel->write("}\n\n"); // fflush(stdout); } @@ -581,7 +583,7 @@ void Debugger::dumpCallstack(Module *m) const { this->channel->write("\"start\":%" PRIu32 ",\"ra\":%d,\"callsite\":%d}%s", toVA(f->block->start_ptr), retaddr, - callsite_retaddr, (i < m->csp) ? "," : "]"); + callsite_retaddr, (i < m->csp) ? "," : "],"); } } @@ -668,6 +670,11 @@ void Debugger::dumpCallbackmapping() const { this->channel->write("%s\n", CallbackHandler::dump_callbacks().c_str()); } +void Debugger::dumpHeapInfo(Module *m) const { + this->channel->write(R"("heap":{"used":%u}})", + m->warduino->get_heap_used()); +} + /** * Read the change in bytes array. * @@ -776,7 +783,7 @@ bool Debugger::handlePushedEvent(char *bytes) const { } void Debugger::snapshot(Module *m) const { - uint16_t numberBytes = 12; + uint16_t numberBytes = 13; uint8_t state[] = {pcState, breakpointsState, callstackState, @@ -788,7 +795,8 @@ void Debugger::snapshot(Module *m) const { callbacksState, eventsState, ioState, - overridesState}; + overridesState, + heapState}; inspect(m, numberBytes, state); } @@ -970,6 +978,12 @@ void Debugger::inspect(Module *m, const uint16_t sizeStateArray, addComma = true; break; } + case heapState: { + uint32_t heap_used = m->warduino->get_heap_used(); + this->channel->write(R"(%s"heap":{"used":%d})", + addComma ? "," : "", heap_used); + break; + } default: { debug("dumpExecutionState: Received unknown state request\n"); break; diff --git a/src/Debug/debugger.h b/src/Debug/debugger.h index 1cfda22a..c612ddf8 100644 --- a/src/Debug/debugger.h +++ b/src/Debug/debugger.h @@ -51,6 +51,7 @@ enum ExecutionState { eventsState = 0x0A, ioState = 0x0B, overridesState = 0x0C, + heapState = 0x0D, }; enum InterruptTypes { @@ -186,6 +187,8 @@ class Debugger { void dumpCallbackmapping() const; + void dumpHeapInfo(Module *m) const; + void inspect(Module *m, uint16_t sizeStateArray, const uint8_t *state) const; From 1b48dedbbc15dceeb2ce58209977e31c18882dda Mon Sep 17 00:00:00 2001 From: Abel Stuker Date: Mon, 13 Apr 2026 16:27:03 +0200 Subject: [PATCH 03/13] Fix deprecated mallinfo and nonexisting header --- src/WARDuino/WARDuino.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/WARDuino/WARDuino.cpp b/src/WARDuino/WARDuino.cpp index 04d9f949..ec14ffa1 100644 --- a/src/WARDuino/WARDuino.cpp +++ b/src/WARDuino/WARDuino.cpp @@ -1095,14 +1095,14 @@ uint32_t WARDuino::get_main_fidx(Module *m) { } #if defined(ESP) || defined(ARDUINO) -#include +#include Arduino.h #define TOTAL_MALLOC ESP.getHeapSize() - ESP.getFreeHeap() #elif defined(__APPLE__) #include #define TOTAL_MALLOC mstats().bytes_used #else #include -#define TOTAL_MALLOC mallinfo().uordblks +#define TOTAL_MALLOC mallinfo2().uordblks #endif uint32_t WARDuino::get_heap_used() { return TOTAL_MALLOC; } \ No newline at end of file From 2b87cdc7803fe18db1db92833ef4190c45ef5f62 Mon Sep 17 00:00:00 2001 From: Abel Stuker Date: Mon, 13 Apr 2026 16:39:21 +0200 Subject: [PATCH 04/13] Fix header --- src/WARDuino/WARDuino.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/WARDuino/WARDuino.cpp b/src/WARDuino/WARDuino.cpp index ec14ffa1..06493934 100644 --- a/src/WARDuino/WARDuino.cpp +++ b/src/WARDuino/WARDuino.cpp @@ -1095,7 +1095,7 @@ uint32_t WARDuino::get_main_fidx(Module *m) { } #if defined(ESP) || defined(ARDUINO) -#include Arduino.h +#include #define TOTAL_MALLOC ESP.getHeapSize() - ESP.getFreeHeap() #elif defined(__APPLE__) #include From 194ddbd26bd00e04eecd6553d59609bfb5c6fb96 Mon Sep 17 00:00:00 2001 From: Abel Stuker Date: Mon, 13 Apr 2026 16:44:22 +0200 Subject: [PATCH 05/13] Fix header --- src/WARDuino/WARDuino.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/WARDuino/WARDuino.cpp b/src/WARDuino/WARDuino.cpp index 06493934..e6842b72 100644 --- a/src/WARDuino/WARDuino.cpp +++ b/src/WARDuino/WARDuino.cpp @@ -1095,7 +1095,7 @@ uint32_t WARDuino::get_main_fidx(Module *m) { } #if defined(ESP) || defined(ARDUINO) -#include +#include "Arduino.h" #define TOTAL_MALLOC ESP.getHeapSize() - ESP.getFreeHeap() #elif defined(__APPLE__) #include From 0e542a9c79ab85c2d041dc8a05317dd36719d0b1 Mon Sep 17 00:00:00 2001 From: Abel Stuker Date: Mon, 13 Apr 2026 16:54:22 +0200 Subject: [PATCH 06/13] Fix ESP-IDF header --- src/WARDuino/WARDuino.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/WARDuino/WARDuino.cpp b/src/WARDuino/WARDuino.cpp index e6842b72..cba40c15 100644 --- a/src/WARDuino/WARDuino.cpp +++ b/src/WARDuino/WARDuino.cpp @@ -1094,9 +1094,12 @@ uint32_t WARDuino::get_main_fidx(Module *m) { return fidx; } -#if defined(ESP) || defined(ARDUINO) -#include "Arduino.h" -#define TOTAL_MALLOC ESP.getHeapSize() - ESP.getFreeHeap() +#if defined(ARDUINO) +#include +#define TOTAL_MALLOC (ESP.getHeapSize() - ESP.getFreeHeap()) +#elif defined(ESP_PLATFORM) +#include +#define TOTAL_MALLOC (heap_caps_get_total_size(MALLOC_CAP_DEFAULT) - heap_caps_get_free_size(MALLOC_CAP_DEFAULT)) #elif defined(__APPLE__) #include #define TOTAL_MALLOC mstats().bytes_used @@ -1104,5 +1107,4 @@ uint32_t WARDuino::get_main_fidx(Module *m) { #include #define TOTAL_MALLOC mallinfo2().uordblks #endif - uint32_t WARDuino::get_heap_used() { return TOTAL_MALLOC; } \ No newline at end of file From 09bf5358a4ed1007be302f3fe757fb1f925341b8 Mon Sep 17 00:00:00 2001 From: Abel Stuker Date: Mon, 13 Apr 2026 16:57:40 +0200 Subject: [PATCH 07/13] Fix formatting --- src/WARDuino/WARDuino.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/WARDuino/WARDuino.cpp b/src/WARDuino/WARDuino.cpp index cba40c15..16a40f40 100644 --- a/src/WARDuino/WARDuino.cpp +++ b/src/WARDuino/WARDuino.cpp @@ -1099,7 +1099,9 @@ uint32_t WARDuino::get_main_fidx(Module *m) { #define TOTAL_MALLOC (ESP.getHeapSize() - ESP.getFreeHeap()) #elif defined(ESP_PLATFORM) #include -#define TOTAL_MALLOC (heap_caps_get_total_size(MALLOC_CAP_DEFAULT) - heap_caps_get_free_size(MALLOC_CAP_DEFAULT)) +#define TOTAL_MALLOC \ + (heap_caps_get_total_size(MALLOC_CAP_DEFAULT) - \ + heap_caps_get_free_size(MALLOC_CAP_DEFAULT)) #elif defined(__APPLE__) #include #define TOTAL_MALLOC mstats().bytes_used From a7babb10539514ef33ee2367c1749af1443e4906 Mon Sep 17 00:00:00 2001 From: Abel Stuker Date: Mon, 13 Apr 2026 17:46:01 +0200 Subject: [PATCH 08/13] Fix debugger dump --- src/Debug/debugger.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Debug/debugger.cpp b/src/Debug/debugger.cpp index 56adf643..7a439bc9 100644 --- a/src/Debug/debugger.cpp +++ b/src/Debug/debugger.cpp @@ -512,6 +512,7 @@ void Debugger::dump(Module *m, bool full) const { this->dumpLocals(m); this->channel->write(", "); this->dumpEvents(0, static_cast(CallbackHandler::event_count())); + this->channel->write(", "); } this->dumpHeapInfo(m); @@ -671,7 +672,7 @@ void Debugger::dumpCallbackmapping() const { } void Debugger::dumpHeapInfo(Module *m) const { - this->channel->write(R"("heap":{"used":%u}})", + this->channel->write(R"("heap":{"used":%u})", m->warduino->get_heap_used()); } @@ -982,6 +983,7 @@ void Debugger::inspect(Module *m, const uint16_t sizeStateArray, uint32_t heap_used = m->warduino->get_heap_used(); this->channel->write(R"(%s"heap":{"used":%d})", addComma ? "," : "", heap_used); + addComma = true; break; } default: { From d7caabef5efdbff193ba8e8ac6cfe206cfdf21c8 Mon Sep 17 00:00:00 2001 From: Abel Stuker Date: Mon, 13 Apr 2026 17:47:15 +0200 Subject: [PATCH 09/13] Fix formatting --- src/Debug/debugger.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Debug/debugger.cpp b/src/Debug/debugger.cpp index 7a439bc9..267f35ad 100644 --- a/src/Debug/debugger.cpp +++ b/src/Debug/debugger.cpp @@ -672,8 +672,7 @@ void Debugger::dumpCallbackmapping() const { } void Debugger::dumpHeapInfo(Module *m) const { - this->channel->write(R"("heap":{"used":%u})", - m->warduino->get_heap_used()); + this->channel->write(R"("heap":{"used":%u})", m->warduino->get_heap_used()); } /** From 28f0422ca7c613aa78d4bf6137ac5eae1d410ab1 Mon Sep 17 00:00:00 2001 From: Abel Stuker Date: Mon, 13 Apr 2026 22:21:50 +0200 Subject: [PATCH 10/13] Remove heap information from snapshot --- src/Debug/debugger.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Debug/debugger.cpp b/src/Debug/debugger.cpp index 267f35ad..1056e327 100644 --- a/src/Debug/debugger.cpp +++ b/src/Debug/debugger.cpp @@ -795,8 +795,7 @@ void Debugger::snapshot(Module *m) const { callbacksState, eventsState, ioState, - overridesState, - heapState}; + overridesState}; inspect(m, numberBytes, state); } From 49cc7b05a4dc85157c2e3c3c6d492ba14d331012 Mon Sep 17 00:00:00 2001 From: Abel Stuker Date: Tue, 14 Apr 2026 12:13:27 +0200 Subject: [PATCH 11/13] Add tutorial example for heap size primitive --- tutorials/wat/main/heap_size.wast | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 tutorials/wat/main/heap_size.wast diff --git a/tutorials/wat/main/heap_size.wast b/tutorials/wat/main/heap_size.wast new file mode 100644 index 00000000..d825bd22 --- /dev/null +++ b/tutorials/wat/main/heap_size.wast @@ -0,0 +1,24 @@ +;; This test program shows how to use the `heap_used` function +;; to determine how much of the heap is currently in use. + +;; The same used heap size can be obtained from the debugger, +;; but note that the debugger introduces some overhead, so +;; the value obtained there may be slightly higher +;; than the value obtained from teh `heap_used` primitive. + +(module + (import "env" "heap_used" (func $heap_used (result i32))) + (import "env" "print_int" (func $print_int (param i32))) + (memory (export "memory") 1) + + (func (export "main") + (call $heap_used) ;; A + (call $print_int) + + (memory.grow (i32.const 1)) ;; grow memory by 1 page (64KB = 65536 bytes) + (drop) + + (call $heap_used) ;; should be >= A + 65536 + (call $print_int) + ) +) \ No newline at end of file From 65da039edadc1b4d7ecf7055e0b042e638632a26 Mon Sep 17 00:00:00 2001 From: Abel Stuker Date: Tue, 14 Apr 2026 12:15:56 +0200 Subject: [PATCH 12/13] Rename heap size example to heap used --- tutorials/wat/main/{heap_size.wast => heap_used.wast} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tutorials/wat/main/{heap_size.wast => heap_used.wast} (100%) diff --git a/tutorials/wat/main/heap_size.wast b/tutorials/wat/main/heap_used.wast similarity index 100% rename from tutorials/wat/main/heap_size.wast rename to tutorials/wat/main/heap_used.wast From 895667ecde78a8b4dc4a8382f5678f07e30ad53b Mon Sep 17 00:00:00 2001 From: Abel Stuker Date: Sun, 19 Apr 2026 11:38:30 +0200 Subject: [PATCH 13/13] Fix number of snapshot state bytes --- src/Debug/debugger.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Debug/debugger.cpp b/src/Debug/debugger.cpp index 1056e327..c4fa6247 100644 --- a/src/Debug/debugger.cpp +++ b/src/Debug/debugger.cpp @@ -783,7 +783,7 @@ bool Debugger::handlePushedEvent(char *bytes) const { } void Debugger::snapshot(Module *m) const { - uint16_t numberBytes = 13; + uint16_t numberBytes = 12; uint8_t state[] = {pcState, breakpointsState, callstackState,