Skip to content
16 changes: 8 additions & 8 deletions src/Debug/debugger.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -844,7 +844,7 @@ void Debugger::inspect(Module *m, const uint16_t sizeStateArray,
this->channel->write("%s\"globals\":[", addComma ? "," : "");
addComma = true;
for (uint32_t j = 0; j < m->global_count; j++) {
auto v = m->globals + j;
auto v = (*(m->globals + j))->value;
printValue(v, j, j == (m->global_count - 1));
}
this->channel->write("]"); // closing globals
Expand Down Expand Up @@ -1063,15 +1063,15 @@ void Debugger::freeState(Module *m, uint8_t *interruptData) {
debug("globals freeing state and then allocating\n");
if (m->global_count > 0) free(m->globals);
if (amount > 0)
m->globals = static_cast<StackValue *>(
acalloc(amount, sizeof(StackValue), "globals"));
m->globals = static_cast<Global **>(
acalloc(amount, sizeof(Global *), "globals"));
} else {
debug("globals setting existing state to zero\n");
for (uint32_t i = 0; i < m->global_count; i++) {
debug("decreasing global_count\n");
StackValue *sv = &m->globals[i];
sv->value_type = 0;
sv->value.uint32 = 0;
Global *glob = m->globals[i];
glob->value->value_type = 0;
glob->value->value.uint32 = 0;
}
}
m->global_count = 0;
Expand Down Expand Up @@ -1221,7 +1221,7 @@ bool Debugger::saveState(Module *m, uint8_t *interruptData) {
if (type_index >= sizeof(valtypes)) {
FATAL("received unknown type %" PRIu8 "\n", type_index);
}
StackValue *sv = &m->globals[m->global_count++];
StackValue *sv = m->globals[m->global_count++]->value;
size_t qb = type_index == 0 || type_index == 2 ? 4 : 8;
debug("receiving type %" PRIu8 " and %d bytes \n",
type_index,
Expand Down Expand Up @@ -1539,7 +1539,7 @@ bool Debugger::handleUpdateGlobalValue(const Module *m, uint8_t *data) const {
if (index >= m->global_count) return false;

this->channel->write("Global %u being changed\n", index);
StackValue *v = &m->globals[index];
StackValue *v = m->globals[index]->value;
constexpr bool decodeType = false;
deserialiseStackValue(data, decodeType, v);
this->channel->write("Global %u changed to %u\n", index, v->value.uint32);
Expand Down
6 changes: 3 additions & 3 deletions src/Interpreter/instructions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -459,9 +459,9 @@ bool i_instr_tee_local(Module *m) {
bool i_instr_get_global(Module *m) {
int32_t arg = read_LEB_32(&m->pc_ptr);
#if TRACE
debug(" - arg: 0x%x, got %s\n", arg, value_repr(&m->globals[arg]));
debug(" - arg: 0x%x, got %s\n", arg, value_repr(m->globals[arg]));
#endif
m->stack[++m->sp] = m->globals[arg];
m->stack[++m->sp] = *m->globals[arg]->value;
return true;
}

Expand All @@ -470,7 +470,7 @@ bool i_instr_get_global(Module *m) {
*/
bool i_instr_set_global(Module *m) {
uint32_t arg = read_LEB_32(&m->pc_ptr);
m->globals[arg] = m->stack[m->sp--];
*m->globals[arg]->value = m->stack[m->sp--];
#if TRACE
debug(" - arg: 0x%x, got %s\n", arg, value_repr(&m->stack[m->sp + 1]));
#endif
Expand Down
36 changes: 35 additions & 1 deletion src/Primitives/arduino.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -136,8 +136,12 @@ int resolve_isr(int pin) {

#define ALL_PRIMITIVES (NUM_PRIMITIVES + NUM_PRIMITIVES_ARDUINO)

// Global index for installing primitives
#define NUM_GLOBALS 0
#define ALL_GLOBALS NUM_GLOBALS
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think the globals are part of the primitives. Can we move this to the interpreter or the WARDuino class? Now it will only get loaded on Arduino.

Copy link
Contributor Author

@abelstuker abelstuker Nov 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Globals can be defined by the host (e.g. status flags). These globals can then be imported in the Wasm module. As mentioned in the other comment, the number of host-defined globals is statically known. Similar to the host-defined function primitives, this host-defined globals functionality is added not only for arduino.cpp, but also for emulated.cpp, idf.cpp and zephyr.cpp. These platforms should not necessarily have the exact same host-defined globals.

Did I understand your comment correctly?

P.S. The NUM_GLOBALS 1 is incorrect and should be NUM_GLOBALS 0. It is a leftover from me testing the functionality of these host-defined globals. EDIT: corrected in 2dd47af.


// Indices for installing primitives and globals
int prim_index = 0;
int global_index = 0;

/*
Private macros to install a primitive
Expand Down Expand Up @@ -196,8 +200,25 @@ int prim_index = 0;
#define arg8 get_arg(m, 8)
#define arg9 get_arg(m, 9)

#define def_glob(name, type, mut, init_value) \
StackValue name##_sv{.value_type = type, init_value}; \
Global name = { \
.mutability = mut, .import_field = #name, .value = &name##_sv};

#define install_global(global_name) \
{ \
dbg_info("installing global: %s\n", #global_name); \
if (global_index < ALL_GLOBALS) { \
globals[global_index++] = (global_name); \
} else { \
FATAL("global_index out of bounds"); \
} \
}

// The primitive table
PrimitiveEntry primitives[ALL_PRIMITIVES];
// The globals table
Global globals[ALL_GLOBALS];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this array not always length 0 now? I think we need a dynamic array here since we only know how many globals will be exported at runtime (when loading the wasm module). Maybe I am missing something here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes indeed, for now all these arrays of globals are length 0 (not only in arduino.cpp, but also in the emulated.cpp, idf.cpp and zephyr.cpp). These arrays are intended only for globals that are defined by the host, available for import within the Wasm module (those exported by the module are not handled here). Since the number of such host-defined globals is known at compile time this array size can be statically determined. Currently, there are no such globals, but it is possible to add such importable globals in the future (e.g. status flags provided by the host ...).

On the contrary, the other, not imported globals in the module are indeed only known at runtime. Therefore, these globals are dynamically allocated during instantiation of the Wasm module (see case 6 of the big switch within the WARDuino::instantiate_module function in WARDuino.cpp). These globals can either stay local to the module or be exported in the export section. When exported, the host can retrieve the exported global by first retrieving the index of the global using WARDuino::get_export_global_idx in WARDuino.cpp and then accessing that global at that obtained index from the globals in the Module struct.

To summarize, the host-defined (importable) globals are statically known (and therefore also their array size). The module-defined (exportable) globals are dynamically allocated during instantiation.


//
uint32_t param_arr_len0[0] = {};
Expand Down Expand Up @@ -1076,6 +1097,19 @@ bool resolve_external_memory(char *symbol, Memory **val) {
return false;
}

bool resolve_external_global(char *symbol, Global **val) {
debug("Resolve external global for %s \n", symbol);

for (auto &global : globals) {
if (!strcmp(symbol, global.import_field)) {
*val = &global;
return true;
}
}
FATAL("Could not find global %s \n", symbol);
return false;
}

//------------------------------------------------------
// Restore external state when restoring a snapshot
//------------------------------------------------------
Expand Down
36 changes: 35 additions & 1 deletion src/Primitives/emulated.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,12 @@

#define ALL_PRIMITIVES (NUM_PRIMITIVES + NUM_PRIMITIVES_ARDUINO)

// Global index for installing primitives
#define NUM_GLOBALS 0
#define ALL_GLOBALS NUM_GLOBALS

// Indices for installing primitives and globals
int prim_index = 0;
int global_index = 0;

double sensor_emu = 0;

Expand Down Expand Up @@ -94,8 +98,25 @@ double sensor_emu = 0;
#define arg8 get_arg(m, 8)
#define arg9 get_arg(m, 9)

#define def_glob(name, type, mut, init_value) \
StackValue name##_sv{.value_type = type, init_value}; \
Global name = { \
.mutability = mut, .import_field = #name, .value = &name##_sv};

#define install_global(global_name) \
{ \
dbg_info("installing global: %s\n", #global_name); \
if (global_index < ALL_GLOBALS) { \
globals[global_index++] = (global_name); \
} else { \
FATAL("global_index out of bounds"); \
} \
}

// The primitive table
PrimitiveEntry primitives[ALL_PRIMITIVES];
// The globals table
Global globals[ALL_GLOBALS];

//
uint32_t param_arr_len0[0] = {};
Expand Down Expand Up @@ -728,6 +749,19 @@ bool resolve_external_memory(char *symbol, Memory **val) {
// return false; // unreachable
}

bool resolve_external_global(char *symbol, Global **val) {
debug("Resolve external global for %s \n", symbol);

for (auto &global : globals) {
if (!strcmp(symbol, global.import_field)) {
*val = &global;
return true;
}
}
FATAL("Could not find global %s \n", symbol);
// return false; // unreachable
}

//------------------------------------------------------
// Restore external state when restoring a snapshot
//------------------------------------------------------
Expand Down
36 changes: 35 additions & 1 deletion src/Primitives/idf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,12 @@

#define ALL_PRIMITIVES (NUM_PRIMITIVES + NUM_PRIMITIVES_ARDUINO)

// Global index for installing primitives
#define NUM_GLOBALS 0
#define ALL_GLOBALS NUM_GLOBALS

// Indices for installing primitives and globals
int prim_index = 0;
int global_index = 0;

double sensor_emu = 0;

Expand Down Expand Up @@ -94,8 +98,25 @@ double sensor_emu = 0;
#define arg8 get_arg(m, 8)
#define arg9 get_arg(m, 9)

#define def_glob(name, type, mut, init_value) \
StackValue name##_sv{.value_type = type, init_value}; \
Global name = { \
.mutability = mut, .import_field = #name, .value = &name##_sv};

#define install_global(global_name) \
{ \
dbg_info("installing global: %s\n", #global_name); \
if (global_index < ALL_GLOBALS) { \
globals[global_index++] = (global_name); \
} else { \
FATAL("global_index out of bounds"); \
} \
}

// The primitive table
PrimitiveEntry primitives[ALL_PRIMITIVES];
// The globals table
Global globals[ALL_GLOBALS];

//
uint32_t param_arr_len0[0] = {};
Expand Down Expand Up @@ -295,6 +316,19 @@ bool resolve_external_memory(char *symbol, Memory **val) {
return false;
}

bool resolve_external_global(char *symbol, Global **val) {
debug("Resolve external global for %s \n", symbol);

for (auto &global : globals) {
if (!strcmp(symbol, global.import_field)) {
*val = &global;
return true;
}
}
FATAL("Could not find global %s \n", symbol);
return false;
}

//------------------------------------------------------
// Restore external state when restoring a snapshot
//------------------------------------------------------
Expand Down
2 changes: 2 additions & 0 deletions src/Primitives/primitives.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ bool resolve_primitive(char *symbol, Primitive *val);
*/
bool resolve_external_memory(char *symbol, Memory **val);

bool resolve_external_global(char *symbol, Global **val);

void install_primitives();

std::vector<IOStateElement *> get_io_state(Module *m);
Expand Down
36 changes: 35 additions & 1 deletion src/Primitives/zephyr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,12 @@
#endif
#define ALL_PRIMITIVES OBB_PRIMITIVES + 7

// Global index for installing primitives
#define NUM_GLOBALS 0
#define ALL_GLOBALS NUM_GLOBALS

// Indices for installing primitives and globals
int prim_index = 0;
int global_index = 0;

double sensor_emu = 0;

Expand Down Expand Up @@ -101,8 +105,25 @@ double sensor_emu = 0;
#define arg8 get_arg(m, 8)
#define arg9 get_arg(m, 9)

#define def_glob(name, type, mut, init_value) \
StackValue name##_sv{.value_type = type, init_value}; \
Global name = { \
.mutability = mut, .import_field = #name, .value = &name##_sv};

#define install_global(global_name) \
{ \
dbg_info("installing global: %s\n", #global_name); \
if (global_index < ALL_GLOBALS) { \
globals[global_index++] = (global_name); \
} else { \
FATAL("global_index out of bounds"); \
} \
}

// The primitive table
PrimitiveEntry primitives[ALL_PRIMITIVES];
// The globals table
Global globals[ALL_GLOBALS];

//
uint32_t param_arr_len0[0] = {};
Expand Down Expand Up @@ -627,6 +648,19 @@ bool resolve_external_memory(char *symbol, Memory **val) {
return false;
}

bool resolve_external_global(char *symbol, Global **val) {
debug("Resolve external global for %s \n", symbol);

for (auto &global : globals) {
if (!strcmp(symbol, global.import_field)) {
*val = &global;
return true;
}
}
FATAL("Could not find global %s \n", symbol);
return false;
}

//------------------------------------------------------
// Restore external state when restoring a snapshot
//------------------------------------------------------
Expand Down
2 changes: 2 additions & 0 deletions src/WARDuino.h
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,8 @@ class WARDuino {

uint32_t get_export_fidx(Module *m, const char *name);

uint32_t get_export_global_idx(Module *m, const char *name);

void handleInterrupt(size_t len, uint8_t *buff) const;

void instantiate_module(Module *m, uint8_t *bytes, uint32_t byte_count);
Expand Down
5 changes: 3 additions & 2 deletions src/WARDuino/CallbackHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -193,8 +193,9 @@ Callback::Callback(Module *m, std::string id, uint32_t tidx) {
}

void Callback::resolve_event(const Event &e) {
dbg_trace("Callback(%s, %i): resolving Event(%s, \"%s\")\n", topic.c_str(),
table_index, e.topic.c_str(), e.payload);
dbg_trace("Callback(%s, %u): resolving Event(%s, \"%s\")\n", topic.c_str(),
static_cast<unsigned int>(table_index), e.topic.c_str(),
e.payload.c_str());

// Copy topic and payload to linear memory
uint32_t start = 10000; // TODO use reserved area in linear memory
Expand Down
Loading