@mikrojs/native 0.18.3-next.20260829153835 → 0.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/mik_repl.cpp CHANGED
@@ -39,6 +39,18 @@ static MIKReplTransport* repl_transport = nullptr;
39
39
  static uint8_t ready_buf[384];
40
40
  static size_t ready_len = 0;
41
41
 
42
+ /* Memory left for the app, captured once when the first runtime attaches: that
43
+ * happens before the entry is evaluated, so these describe the floor the app is
44
+ * handed rather than whatever is left whenever a client happens to connect.
45
+ * Reported on MSG_READY so `mikro profile` is a read, not a deploy. */
46
+ static bool boot_mem_captured = false;
47
+ static uint32_t boot_heap_free = 0;
48
+ static uint32_t boot_system_free = 0;
49
+ /* The reserve that produced `mem_limit`, reported alongside the figures so the
50
+ * host can tell a config change apart from a firmware regression — and can spot
51
+ * a device still running a config older than the one in the project. */
52
+ static uint32_t boot_mem_reserved = 0;
53
+
42
54
  /* Transient flag: set by MIK_ProtocolExit to break the current ServeLoop
43
55
  * without closing the session. Distinct from repl_active (which signals
44
56
  * "session open"). Cleared at the top of each ServeLoop call. */
@@ -906,13 +918,13 @@ static void refresh_ready(MIKReplTransport* transport);
906
918
  /* Encodes the MSG_READY map into buf, or measures it when buf is null. Returns
907
919
  * the length the encoding needs, which exceeds cap when it did not fit. */
908
920
  static size_t encode_ready(uint8_t* buf, size_t cap, const char* chip, const char* id,
909
- const char* version, const char* fw, const char* name) {
921
+ const char* version, const char* fw, const char* name, bool mem) {
910
922
  /* Measuring calls pass buf=NULL; substitute a non-null base so
911
923
  * zero-length appends never hand memcpy a null pointer (UB). */
912
924
  static uint8_t measure_base;
913
925
  nanocbor_encoder_t enc;
914
926
  nanocbor_encoder_init(&enc, buf ? buf : &measure_base, buf ? cap : 0);
915
- nanocbor_fmt_map(&enc, 3 + (fw ? 1 : 0) + (name ? 1 : 0));
927
+ nanocbor_fmt_map(&enc, 3 + (fw ? 1 : 0) + (name ? 1 : 0) + (mem ? 3 : 0));
916
928
  nanocbor_put_tstr(&enc, "chip");
917
929
  nanocbor_put_tstr(&enc, chip);
918
930
  nanocbor_put_tstr(&enc, "id");
@@ -927,6 +939,14 @@ static size_t encode_ready(uint8_t* buf, size_t cap, const char* chip, const cha
927
939
  nanocbor_put_tstr(&enc, "name");
928
940
  nanocbor_put_tstr(&enc, name);
929
941
  }
942
+ if (mem) {
943
+ nanocbor_put_tstr(&enc, "heapFree");
944
+ nanocbor_fmt_uint(&enc, boot_heap_free);
945
+ nanocbor_put_tstr(&enc, "sysFree");
946
+ nanocbor_fmt_uint(&enc, boot_system_free);
947
+ nanocbor_put_tstr(&enc, "memRes");
948
+ nanocbor_fmt_uint(&enc, boot_mem_reserved);
949
+ }
930
950
  return nanocbor_encoded_len(&enc);
931
951
  }
932
952
 
@@ -955,13 +975,19 @@ static void refresh_ready(MIKReplTransport* transport) {
955
975
  * decodes as a different name at the host. `name` goes before `fw`: a
956
976
  * dropped `fw` reads as the host's own bundled firmware, re-enabling the
957
977
  * auto-reflash the identity exists to prevent. */
958
- if (name && encode_ready(nullptr, 0, chip, id, version, fw, name) > sizeof(ready_buf)) {
978
+ bool mem = boot_mem_captured;
979
+ /* Diagnostics are the first thing to go when the map does not fit: losing
980
+ * them costs a memory figure, while losing `name` or `fw` breaks identity. */
981
+ if (mem && encode_ready(nullptr, 0, chip, id, version, fw, name, mem) > sizeof(ready_buf)) {
982
+ mem = false;
983
+ }
984
+ if (name && encode_ready(nullptr, 0, chip, id, version, fw, name, mem) > sizeof(ready_buf)) {
959
985
  name = nullptr;
960
986
  }
961
- if (fw && encode_ready(nullptr, 0, chip, id, version, fw, name) > sizeof(ready_buf)) {
987
+ if (fw && encode_ready(nullptr, 0, chip, id, version, fw, name, mem) > sizeof(ready_buf)) {
962
988
  fw = nullptr;
963
989
  }
964
- ready_len = encode_ready(ready_buf, sizeof(ready_buf), chip, id, version, fw, name);
990
+ ready_len = encode_ready(ready_buf, sizeof(ready_buf), chip, id, version, fw, name, mem);
965
991
  if (ready_len > sizeof(ready_buf)) ready_len = 0;
966
992
  }
967
993
 
@@ -981,6 +1007,19 @@ void MIK_ProtocolAttach(MIKRuntime* mik_rt) {
981
1007
  if (!mik_rt) return;
982
1008
  repl_ctx = MIK_GetJSContext(mik_rt);
983
1009
  repl_mik_rt = mik_rt;
1010
+ /* First attach only. In test mode a fresh runtime attaches per file, and
1011
+ * those would otherwise overwrite the boot floor with per-test figures. */
1012
+ if (!boot_mem_captured) {
1013
+ JSMemoryUsage mem;
1014
+ JS_ComputeMemoryUsage(JS_GetRuntime(repl_ctx), &mem);
1015
+ boot_heap_free =
1016
+ mem.malloc_limit > (int64_t)mem.malloc_size
1017
+ ? (uint32_t)(mem.malloc_limit - (int64_t)mem.malloc_size)
1018
+ : 0;
1019
+ boot_system_free = (uint32_t)MIK_GetPlatform()->get_free_system_mem();
1020
+ boot_mem_reserved = mik_rt->config.mem_reserved;
1021
+ boot_mem_captured = true;
1022
+ }
984
1023
  }
985
1024
 
986
1025
  void MIK_ProtocolDetach(void) {