diff --git a/src/cs_state.cc b/src/cs_state.cc index 93dc0a1..63a61aa 100644 --- a/src/cs_state.cc +++ b/src/cs_state.cc @@ -6,7 +6,7 @@ #include "cs_state.hh" #include "cs_thread.hh" #include "cs_strman.hh" -#include "cs_vm.hh" // break/continue, call_with_args +#include "cs_vm.hh" #include "cs_parser.hh" #include "cs_error.hh" @@ -179,9 +179,7 @@ state::state(alloc_func func, void *data) { static_cast(p)->p_type = ID_DO; p = &new_command("doargs", "b", [](auto &cs, auto args, auto &res) { - call_with_args(*cs.p_tstate, [&cs, &res, &args]() { - res = args[0].get_code().call(cs); - }); + res = exec_code_with_args(*cs.p_tstate, args[0].get_code()); }); static_cast(p)->p_type = ID_DOARGS; diff --git a/src/cs_vm.cc b/src/cs_vm.cc index ce32e7b..2a49e90 100644 --- a/src/cs_vm.cc +++ b/src/cs_vm.cc @@ -216,6 +216,62 @@ bool exec_alias( return true; } +any_value exec_code_with_args(thread_state &ts, bcode_ref const &body) { + if (!ts.callstack) { + return body.call(*ts.pstate); + } + auto mask = ts.callstack->usedargs; + std::size_t noff = ts.idstack.size(); + for (std::size_t i = 0; mask.any(); ++i) { + if (mask[0]) { + auto &ast = ts.get_astack( + static_cast(ts.istate->identmap[i]) + ); + auto &st = ts.idstack.emplace_back(); + st.next = ast.node; + ast.node = ast.node->next; + } + mask >>= 1; + } + ident_link *prevstack = ts.callstack->next; + ident_link aliaslink = { + ts.callstack->id, ts.callstack, + prevstack ? prevstack->usedargs : argset{} + }; + if (!prevstack) { + aliaslink.usedargs.set(); + } + ts.callstack = &aliaslink; + auto cleanup = []( + auto &tss, ident_link *pstack, ident_link &alink, std::size_t offn + ) { + if (pstack) { + pstack->usedargs = alink.usedargs; + } + tss.callstack = alink.next; + auto mask2 = tss.callstack->usedargs; + for (std::size_t i = 0, nredo = 0; mask2.any(); ++i) { + if (mask2[0]) { + tss.get_astack( + static_cast(tss.istate->identmap[i]) + ).node = tss.idstack[offn + nredo++].next; + } + mask2 >>= 1; + } + }; + any_value ret; + try { + ret = body.call(*ts.pstate); + } catch (...) { + cleanup(ts, prevstack, aliaslink, noff); + ts.idstack.resize(noff); + throw; + } + cleanup(ts, prevstack, aliaslink, noff); + ts.idstack.resize(noff); + return ret; +} + static inline alias *get_lookup_id( thread_state &ts, std::uint32_t op, alias_stack *&ast ) { @@ -412,16 +468,13 @@ std::uint32_t *vm_exec( return code; } - case BC_INST_DO_ARGS: - call_with_args(ts, []( - auto &css, std::uint32_t inst, auto &av, any_value &ret - ) { - auto v = std::move(av.back()); - av.pop_back(); - ret = v.get_code().call(css); - force_arg(css, ret, inst & BC_INST_RET_MASK); - }, cs, op, args, result); + case BC_INST_DO_ARGS: { + auto v = std::move(args.back()); + args.pop_back(); + result = exec_code_with_args(ts, v.get_code()); + force_arg(cs, result, op & BC_INST_RET_MASK); continue; + } case BC_INST_DO: { auto v = std::move(args.back()); diff --git a/src/cs_vm.hh b/src/cs_vm.hh index 690fa4b..2d763cd 100644 --- a/src/cs_vm.hh +++ b/src/cs_vm.hh @@ -17,62 +17,6 @@ struct break_exception { struct continue_exception { }; -template -static void call_with_args(thread_state &ts, F body, A &&...args) { - if (!ts.callstack) { - body(std::forward(args)...); - return; - } - auto mask = ts.callstack->usedargs; - std::size_t noff = ts.idstack.size(); - for (std::size_t i = 0; mask.any(); ++i) { - if (mask[0]) { - auto &ast = ts.get_astack( - static_cast(ts.istate->identmap[i]) - ); - auto &st = ts.idstack.emplace_back(); - st.next = ast.node; - ast.node = ast.node->next; - } - mask >>= 1; - } - ident_link *prevstack = ts.callstack->next; - ident_link aliaslink = { - ts.callstack->id, ts.callstack, - prevstack ? prevstack->usedargs : argset{} - }; - if (!prevstack) { - aliaslink.usedargs.set(); - } - ts.callstack = &aliaslink; - auto cleanup = []( - auto &tss, ident_link *pstack, ident_link &alink, std::size_t offn - ) { - if (pstack) { - pstack->usedargs = alink.usedargs; - } - tss.callstack = alink.next; - auto mask2 = tss.callstack->usedargs; - for (std::size_t i = 0, nredo = 0; mask2.any(); ++i) { - if (mask2[0]) { - tss.get_astack( - static_cast(tss.istate->identmap[i]) - ).node = tss.idstack[offn + nredo++].next; - } - mask2 >>= 1; - } - }; - try { - body(std::forward(args)...); - } catch (...) { - cleanup(ts, prevstack, aliaslink, noff); - ts.idstack.resize(noff); - throw; - } - cleanup(ts, prevstack, aliaslink, noff); - ts.idstack.resize(noff); -} - void exec_command( thread_state &ts, command_impl *id, ident *self, any_value *args, any_value &res, std::size_t nargs, bool lookup = false @@ -84,6 +28,8 @@ bool exec_alias( std::size_t skip, std::uint32_t op, bool ncheck = false ); +any_value exec_code_with_args(thread_state &ts, bcode_ref const &body); + std::uint32_t *vm_exec( thread_state &ts, std::uint32_t *code, any_value &result );