From 4154944726f6de89b8c00797328f678142ba58ba Mon Sep 17 00:00:00 2001 From: Daniel Kolesa Date: Tue, 30 Mar 2021 00:28:06 +0200 Subject: [PATCH] remove fixed-size argument stacks and reliance on argument ids --- include/cubescript/cubescript.hh | 2 +- src/cs_ident.cc | 14 +++++++++++++- src/cs_ident.hh | 5 +---- src/cs_std.hh | 24 ------------------------ src/cs_thread.cc | 3 ++- src/cs_thread.hh | 4 +++- src/cs_val.cc | 7 +++++-- src/cs_vm.cc | 27 ++++++++++++++++----------- src/cs_vm.hh | 10 +++++----- 9 files changed, 46 insertions(+), 50 deletions(-) diff --git a/include/cubescript/cubescript.hh b/include/cubescript/cubescript.hh index 4f5bc21..ce5eeb6 100644 --- a/include/cubescript/cubescript.hh +++ b/include/cubescript/cubescript.hh @@ -846,8 +846,8 @@ struct LIBCUBESCRIPT_EXPORT stacked_value: any_value { bool pop(); private: + state &p_state; alias *p_a; - ident_stack p_stack; bool p_pushed; }; diff --git a/src/cs_ident.cc b/src/cs_ident.cc index 0d36480..b653f51 100644 --- a/src/cs_ident.cc +++ b/src/cs_ident.cc @@ -157,7 +157,7 @@ void alias_impl::set_arg(thread_state &ts, any_value &v) { p_val = std::move(v); clean_code(); } else { - push_arg(v, ts.callstack->argstack[get_index()], false); + push_arg(v, ts.idstack.emplace_back(*ts.pstate), false); ts.callstack->usedargs[get_index()] = true; } } @@ -196,6 +196,18 @@ command_impl::command_impl( p_cargs{args}, p_cb_cftv{std::move(f)}, p_numargs{nargs} {} +void command_impl::call(state &cs, std::span args, any_value &ret) { + auto &ts = *cs.thread_pointer(); + auto idstsz = ts.idstack.size(); + try { + p_cb_cftv(cs, args, ret); + } catch (...) { + ts.idstack.resize(idstsz, ident_stack{cs}); + throw; + } + ts.idstack.resize(idstsz, ident_stack{cs}); +} + bool ident_is_used_arg(ident *id, thread_state &ts) { if (!ts.callstack) { return true; diff --git a/src/cs_ident.hh b/src/cs_ident.hh index d946fa6..7d7eabc 100644 --- a/src/cs_ident.hh +++ b/src/cs_ident.hh @@ -19,7 +19,6 @@ enum { struct ident_link { ident *id; ident_link *next; - ident_stack *argstack; std::bitset usedargs; }; @@ -110,9 +109,7 @@ struct command_impl: ident_impl, command { string_ref name, string_ref args, int numargs, command_func func ); - void call(state &cs, std::span args, any_value &ret) { - p_cb_cftv(cs, args, ret); - } + void call(state &cs, std::span args, any_value &ret); string_ref p_cargs; command_func p_cb_cftv; diff --git a/src/cs_std.hh b/src/cs_std.hh index e1e590d..af1047b 100644 --- a/src/cs_std.hh +++ b/src/cs_std.hh @@ -28,30 +28,6 @@ inline void call_with_cleanup(F1 &&dof, F2 &&clf) { dof(); } -/* a simple static array with elements constructed using ctor args */ - -template -struct valarray { - template - valarray(A &&...args) { - for (std::size_t i = 0; i < N; ++i) { - new (&stor[i]) T{std::forward(args)...}; - } - } - - ~valarray() { - for (std::size_t i = 0; i < N; ++i) { - std::launder(reinterpret_cast(&stor[i]))->~T(); - } - } - - T &operator[](std::size_t i) { - return *std::launder(reinterpret_cast(&stor[i])); - } - - std::aligned_storage_t stor[N]; -}; - /* a value buffer */ template diff --git a/src/cs_thread.cc b/src/cs_thread.cc index 35485f1..549484a 100644 --- a/src/cs_thread.cc +++ b/src/cs_thread.cc @@ -5,9 +5,10 @@ namespace cubescript { thread_state::thread_state(internal_state *cs): - vmstack{cs}, errbuf{cs} + vmstack{cs}, idstack{cs}, errbuf{cs} { vmstack.reserve(32); + idstack.reserve(MAX_ARGUMENTS); } hook_func thread_state::set_hook(hook_func f) { diff --git a/src/cs_thread.hh b/src/cs_thread.hh index 8fbe3f4..5a59701 100644 --- a/src/cs_thread.hh +++ b/src/cs_thread.hh @@ -21,8 +21,10 @@ struct thread_state { state *pstate{}; /* current codegen state for diagnostics */ codegen_state *cstate{}; - /* value stack for VM */ + /* VM stack */ valbuf vmstack; + /* alias stack */ + valbuf idstack; /* per-thread storage buffer for error messages */ charbuf errbuf; /* we can attach a hook to vm events */ diff --git a/src/cs_val.cc b/src/cs_val.cc index 48a655e..44ee9ab 100644 --- a/src/cs_val.cc +++ b/src/cs_val.cc @@ -411,7 +411,7 @@ bool any_value::get_bool() const { /* stacked value for easy stack management */ stacked_value::stacked_value(state &cs, ident *id): - any_value(cs), p_a(nullptr), p_stack{cs}, p_pushed(false) + any_value{cs}, p_state{cs}, p_a{nullptr}, p_pushed{false} { set_alias(id); } @@ -451,8 +451,11 @@ bool stacked_value::push() { if (!p_a) { return false; } + auto &ts = *p_state.thread_pointer(); if (!p_pushed) { - static_cast(p_a)->push_arg(*this, p_stack); + static_cast(p_a)->push_arg( + *this, ts.idstack.emplace_back(p_state) + ); p_pushed = true; } else { static_cast(p_a)->p_val = std::move( diff --git a/src/cs_vm.cc b/src/cs_vm.cc index 5d416a3..4bd2f19 100644 --- a/src/cs_vm.cc +++ b/src/cs_vm.cc @@ -205,11 +205,11 @@ void exec_alias( integer_var *anargs = static_cast( ts.istate->identmap[ID_IDX_NUMARGS] ); - valarray argstack{*ts.pstate}; argset uargs{}; + std::size_t noff = ts.idstack.size(); for(std::size_t i = 0; i < callargs; i++) { static_cast(ts.istate->identmap[i])->push_arg( - args[offset + i], argstack[i], false + args[offset + i], ts.idstack.emplace_back(*ts.pstate), false ); uargs[i] = true; } @@ -217,9 +217,7 @@ void exec_alias( anargs->set_value(callargs); int oldflags = ts.pstate->identflags; ts.pstate->identflags |= a->get_flags()&IDENT_FLAG_OVERRIDDEN; - ident_link aliaslink = { - a, ts.callstack, &argstack[0], uargs - }; + ident_link aliaslink = {a, ts.callstack, uargs}; ts.callstack = &aliaslink; std::uint32_t *codep = static_cast< alias_impl * @@ -244,6 +242,7 @@ void exec_alias( amask[callargs] = false; } } + ts.idstack.resize(noff, ident_stack{*ts.pstate}); force_arg(result, op & BC_INST_RET_MASK); anargs->set_value(integer_type(oldargs)); nargs = offset - skip; @@ -513,9 +512,12 @@ std::uint32_t *vm_exec( case BC_INST_LOCAL: { std::size_t numlocals = op >> 8; std::size_t offset = args.size() - numlocals; - valarray locals{cs}; + std::size_t idstsz = ts.idstack.size(); for (std::size_t i = 0; i < numlocals; ++i) { - push_alias(cs, args[offset + i].get_ident(), locals[i]); + push_alias( + cs, args[offset + i].get_ident(), + ts.idstack.emplace_back(*ts.pstate) + ); } call_with_cleanup([&]() { code = vm_exec(ts, code, result); @@ -523,6 +525,7 @@ std::uint32_t *vm_exec( for (std::size_t i = offset; i < args.size(); ++i) { pop_alias(args[i].get_ident()); } + ts.idstack.resize(idstsz, ident_stack{*ts.pstate}); }); return code; } @@ -725,7 +728,7 @@ std::uint32_t *vm_exec( ) { any_value nv{cs}; static_cast(a)->push_arg( - nv, ts.callstack->argstack[a->get_index()], + nv, ts.idstack.emplace_back(*ts.pstate), false ); ts.callstack->usedargs[a->get_index()] = true; @@ -745,7 +748,7 @@ std::uint32_t *vm_exec( ) { any_value nv{cs}; static_cast(id)->push_arg( - nv, ts.callstack->argstack[id->get_index()], + nv, ts.idstack.emplace_back(*ts.pstate), false ); ts.callstack->usedargs[id->get_index()] = true; @@ -1131,10 +1134,11 @@ noid: args.resize(offset - 1, any_value{cs}); continue; case ID_LOCAL: { - valarray locals{cs}; + std::size_t idstsz = ts.idstack.size(); for (size_t j = 0; j < size_t(callargs); ++j) { push_alias( - cs, args[offset + j].force_ident(cs), locals[j] + cs, args[offset + j].force_ident(cs), + ts.idstack.emplace_back(*ts.pstate) ); } call_with_cleanup([&]() { @@ -1143,6 +1147,7 @@ noid: for (size_t j = 0; j < size_t(callargs); ++j) { pop_alias(args[offset + j].get_ident()); } + ts.idstack.resize(idstsz, ident_stack{*ts.pstate}); }); return code; } diff --git a/src/cs_vm.hh b/src/cs_vm.hh index aac4373..559958d 100644 --- a/src/cs_vm.hh +++ b/src/cs_vm.hh @@ -47,12 +47,12 @@ static void call_with_args(thread_state &ts, F body) { body(); return; } - valarray argstack{*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]) { static_cast(ts.istate->identmap[i])->undo_arg( - argstack[i] + ts.idstack.emplace_back(*ts.pstate) ); } mask >>= 1; @@ -60,7 +60,6 @@ static void call_with_args(thread_state &ts, F body) { ident_link *prevstack = ts.callstack->next; ident_link aliaslink = { ts.callstack->id, ts.callstack, - prevstack ? prevstack->argstack : nullptr, prevstack ? prevstack->usedargs : argset{} }; if (!prevstack) { @@ -73,14 +72,15 @@ static void call_with_args(thread_state &ts, F body) { } ts.callstack = aliaslink.next; auto mask2 = ts.callstack->usedargs; - for (std::size_t i = 0; mask2.any(); ++i) { + for (std::size_t i = 0, nredo = 0; mask2.any(); ++i) { if (mask2[0]) { static_cast(ts.istate->identmap[i])->redo_arg( - argstack[i] + ts.idstack[noff + nredo++] ); } mask2 >>= 1; } + ts.idstack.resize(noff, ident_stack{*ts.pstate}); }); }