diff --git a/src/Interpreter/instructions.cpp b/src/Interpreter/instructions.cpp index fd666702..36731100 100644 --- a/src/Interpreter/instructions.cpp +++ b/src/Interpreter/instructions.cpp @@ -130,9 +130,9 @@ bool i_instr_if(Module *m, uint8_t *block_ptr) { sprintf(exception, "call stack exhausted"); return false; } + uint32_t cond = m->stack[m->sp--].value.uint32; m->warduino->interpreter->push_block(m, block, m->sp); - uint32_t cond = m->stack[m->sp--].value.uint32; if (cond == 0) { // if false (I32) // branch to else block or after end of if if (block->else_ptr == nullptr) { diff --git a/src/Interpreter/interpreter.cpp b/src/Interpreter/interpreter.cpp index ee021c58..1292858b 100644 --- a/src/Interpreter/interpreter.cpp +++ b/src/Interpreter/interpreter.cpp @@ -45,20 +45,20 @@ Block *Interpreter::pop_block(Module *m) { m->fp = frame->fp; // Restore frame pointer // Validate the return value - if (t->result_count == 1) { - if (m->stack[m->sp].value_type != t->results[0]) { + for (uint32_t i = 0; i < t->result_count; i++) { + if (m->stack[m->sp - (t->result_count - 1 - i)].value_type != + t->results[i]) { sprintf(exception, "call type mismatch"); return nullptr; } } - // Restore stack pointer - if (t->result_count == 1) { - // Save top value as result - if (frame->sp < m->sp) { - m->stack[frame->sp + 1] = m->stack[m->sp]; - m->sp = frame->sp + 1; + if (t->result_count > 0) { + for (uint32_t i = 0; i < t->result_count; i++) { + m->stack[frame->sp + 1 + i] = + m->stack[m->sp - (t->result_count - 1) + i]; } + m->sp = frame->sp + t->result_count; } else { if (frame->sp < m->sp) { m->sp = frame->sp; diff --git a/src/WARDuino.h b/src/WARDuino.h index 2069eda6..1f933adb 100644 --- a/src/WARDuino.h +++ b/src/WARDuino.h @@ -108,7 +108,9 @@ class WARDuino { void update_module(Module *old_module, uint8_t *wasm, uint32_t wasm_len); bool invoke(Module *m, uint32_t fidx, uint32_t arity = 0, - StackValue *args = nullptr); + StackValue *args = nullptr, uint32_t max_results = 0, + StackValue *out_results = nullptr, + uint32_t *out_result_count = nullptr); uint32_t get_export_fidx(Module *m, const char *name); diff --git a/src/WARDuino/WARDuino.cpp b/src/WARDuino/WARDuino.cpp index ae41c1fe..1896e5b1 100644 --- a/src/WARDuino/WARDuino.cpp +++ b/src/WARDuino/WARDuino.cpp @@ -74,21 +74,33 @@ void initTypes() { block_types[4].results = block_type_results[3]; } -Type *get_block_type(uint8_t value_type) { - switch (value_type) { - case 0x40: - return &block_types[0]; - case I32: - return &block_types[1]; - case I64: - return &block_types[2]; - case F32: - return &block_types[3]; - case F64: - return &block_types[4]; - default: - FATAL("invalid block_type value_type: %d\n", value_type); +Type *get_block_type(Module *m, uint8_t type) { + uint8_t *pos = &type; + int64_t type_s = read_LEB_signed(&pos, 33); + + if (type_s < 0) { + switch (type) { + case 0x40: + return &block_types[0]; // empty + case I32: + return &block_types[1]; + case I64: + return &block_types[2]; + case F32: + return &block_types[3]; + case F64: + return &block_types[4]; + default: + FATAL("invalid block_type value_type: %d\n", type); + return nullptr; + } + } else { + if ((uint32_t)type_s >= m->type_count) { + FATAL("block_type index out of bounds: %lld >= %u\n", + (long long)type_s, (unsigned int)m->type_count); return nullptr; + } + return &m->types[type_s]; } } @@ -215,7 +227,7 @@ void find_blocks(Module *m) { case 0x04: // if block = (Block *)acalloc(1, sizeof(Block), "Block"); block->block_type = opcode; - block->type = get_block_type(*(pos + 1)); + block->type = get_block_type(m, *(pos + 1)); block->start_ptr = pos; blockstack[++top] = block; m->block_lookup[pos] = block; @@ -261,7 +273,7 @@ void WARDuino::run_init_expr(Module *m, uint8_t type, uint8_t **pc) { WARDuino::instance()->program_state = WARDUINOinit; Block block; block.block_type = 0x01; - block.type = get_block_type(type); + block.type = get_block_type(m, type); block.start_ptr = *pc; m->pc_ptr = *pc; @@ -900,7 +912,8 @@ WARDuino::WARDuino() { // Return value of false means exception occurred bool WARDuino::invoke(Module *m, uint32_t fidx, uint32_t arity, - StackValue *args) { + StackValue *args, uint32_t max_results, + StackValue *out_results, uint32_t *out_result_count) { bool result; m->sp = -1; m->fp = -1; @@ -918,7 +931,25 @@ bool WARDuino::invoke(Module *m, uint32_t fidx, uint32_t arity, result = interpreter->interpret(m); dbg_trace("Interpretation ended\n"); dbg_dump_stack(m); - return result; + + if (!result) { + if (out_result_count) *out_result_count = 0; + return false; + } + + uint32_t rescount = 0; + Type *ftype = m->functions[fidx].type; + rescount = ftype->result_count; + + if (out_result_count) { + *out_result_count = rescount > max_results ? max_results : rescount; + + for (uint32_t i = 0; i < *out_result_count; ++i) { + out_results[i] = m->stack[m->sp - (rescount - 1) + i]; + } + } + + return true; } void WARDuino::setInterpreter(Interpreter *interpreter) { @@ -930,9 +961,15 @@ int WARDuino::run_module(Module *m) { // execute main if (fidx != UNDEF) { - this->invoke(m, fidx); - return m->stack->value.uint32; + StackValue outputs[8]; + uint32_t out_count = 0; + bool ok = this->invoke(m, fidx, 0, nullptr, 8, outputs, &out_count); + if (!ok) { + return 0; + } + return (int)outputs[0].value.uint32; } + fflush(stdout); // wait m->warduino->debugger->pauseRuntime(m);