From 881ba4bce92fd9fbc44712d782e302dc135d94a6 Mon Sep 17 00:00:00 2001 From: Daniel Kolesa Date: Fri, 2 Apr 2021 05:47:49 +0200 Subject: [PATCH] prepare codebase for per-thread alias stack --- include/cubescript/cubescript.hh | 1 + src/cs_ident.cc | 90 ++++++++------------- src/cs_ident.hh | 18 ++--- src/cs_state.cc | 24 +++--- src/cs_thread.cc | 4 + src/cs_thread.hh | 2 + src/cs_vm.cc | 129 +++++++++++++++++++------------ src/cs_vm.hh | 19 +++-- src/lib_base.cc | 10 +-- 9 files changed, 150 insertions(+), 147 deletions(-) diff --git a/include/cubescript/cubescript.hh b/include/cubescript/cubescript.hh index 7c300f7..d209f5d 100644 --- a/include/cubescript/cubescript.hh +++ b/include/cubescript/cubescript.hh @@ -640,6 +640,7 @@ struct LIBCUBESCRIPT_EXPORT alias_local { private: alias *p_alias; + void *p_sp; }; struct LIBCUBESCRIPT_EXPORT list_parser { diff --git a/src/cs_ident.cc b/src/cs_ident.cc index 2e05086..73002aa 100644 --- a/src/cs_ident.cc +++ b/src/cs_ident.cc @@ -114,56 +114,6 @@ alias_impl::alias_impl(state &cs, string_ref name, any_value v, int fl): p_initial.val_s = v; } -void alias_impl::push_arg(ident_stack &st) { - st.next = p_astack; - p_astack = &st; -} - -void alias_impl::pop_arg() { - if (p_astack == &p_initial) { - return; - } - p_astack = p_astack->next; -} - -void alias_impl::undo_arg(ident_stack &st) { - st.next = p_astack; - p_astack = p_astack->next; -} - -void alias_impl::redo_arg(ident_stack &st) { - p_astack = st.next; -} - -void alias_impl::set_arg(thread_state &ts, any_value &v) { - if (ident_is_used_arg(this, ts)) { - p_astack->code = bcode_ref{}; - } else { - push_arg(ts.idstack.emplace_back(*ts.pstate)); - ts.callstack->usedargs[get_index()] = true; - } - p_astack->val_s = std::move(v); -} - -void alias_impl::set_alias(thread_state &ts, any_value &v) { - p_astack->val_s = std::move(v); - p_astack->code = bcode_ref{}; - p_flags = (p_flags & ts.pstate->identflags) | ts.pstate->identflags; -} - -bcode_ref const &alias_impl::compile_code(thread_state &ts) { - if (!p_astack->code) { - codegen_state gs(ts); - gs.code.reserve(64); - gs.gen_main(p_astack->val_s.get_str()); - /* i wish i could steal the memory somehow */ - uint32_t *code = bcode_alloc(ts.istate, gs.code.size()); - memcpy(code, gs.code.data(), gs.code.size() * sizeof(uint32_t)); - p_astack->code = bcode_ref{reinterpret_cast(code + 1)}; - } - return p_astack->code; -} - command_impl::command_impl( string_ref name, string_ref args, int nargs, command_func f ): @@ -190,6 +140,25 @@ bool ident_is_used_arg(ident *id, thread_state &ts) { return ts.callstack->usedargs[id->get_index()]; } +void alias_stack::set_arg(alias *a, thread_state &ts, any_value &v) { + if (ident_is_used_arg(a, ts)) { + node->code = bcode_ref{}; + } else { + auto &st = ts.idstack.emplace_back(*ts.pstate); + st.next = node; + node = &st; + ts.callstack->usedargs[a->get_index()] = true; + } + node->val_s = std::move(v); +} + +void alias_stack::set_alias(alias *a, thread_state &ts, any_value &v) { + node->val_s = std::move(v); + node->code = bcode_ref{}; + auto *ai = static_cast(a); + ai->p_flags = (ai->p_flags & ts.pstate->identflags) | ts.pstate->identflags; +} + /* public interface */ LIBCUBESCRIPT_EXPORT int ident::get_raw_type() const { @@ -390,23 +359,28 @@ LIBCUBESCRIPT_EXPORT alias_local::alias_local(state &cs, ident *a) { p_alias = nullptr; return; } - auto *aimp = static_cast(p_alias); - p_alias = aimp; - aimp->push_arg( - cs.thread_pointer()->idstack.emplace_back(cs) - ); - aimp->p_flags &= ~IDENT_FLAG_UNKNOWN; + auto &ts = *cs.thread_pointer(); + p_alias = static_cast(a); + auto &ast = ts.get_astack(p_alias); + auto &st = ts.idstack.emplace_back(cs); + st.next = ast.node; + ast.node = &st; + p_sp = * + static_cast(p_alias)->p_flags &= ~IDENT_FLAG_UNKNOWN; } LIBCUBESCRIPT_EXPORT alias_local::~alias_local() { - static_cast(p_alias)->pop_arg(); + if (p_alias) { + auto &st = *static_cast(p_sp); + st.node = st.node->next; + } } LIBCUBESCRIPT_EXPORT bool alias_local::set(any_value val) { if (!p_alias) { return false; } - static_cast(p_alias)->p_astack->val_s = std::move(val); + static_cast(p_sp)->node->val_s = std::move(val); return true; } diff --git a/src/cs_ident.hh b/src/cs_ident.hh index 938dc73..7be2021 100644 --- a/src/cs_ident.hh +++ b/src/cs_ident.hh @@ -23,6 +23,13 @@ struct ident_stack { ident_stack(state &cs): val_s{cs}, code{}, next{nullptr} {} }; +struct alias_stack { + ident_stack *node; + + void set_arg(alias *a, thread_state &ts, any_value &v); + void set_alias(alias *a, thread_state &ts, any_value &v); +}; + struct ident_link { ident *id; ident_link *next; @@ -96,17 +103,8 @@ struct alias_impl: ident_impl, alias { alias_impl(state &cs, string_ref n, int flags); alias_impl(state &cs, string_ref n, any_value v, int flags); - void push_arg(ident_stack &st); - void pop_arg(); - void undo_arg(ident_stack &st); - void redo_arg(ident_stack &st); - void set_arg(thread_state &ts, any_value &v); - void set_alias(thread_state &ts, any_value &v); - - bcode_ref const &compile_code(thread_state &ts); - ident_stack p_initial; - ident_stack *p_astack; + alias_stack p_astack; }; struct command_impl: ident_impl, command { diff --git a/src/cs_state.cc b/src/cs_state.cc index da42896..1d3f266 100644 --- a/src/cs_state.cc +++ b/src/cs_state.cc @@ -365,11 +365,12 @@ LIBCUBESCRIPT_EXPORT void state::set_alias( if (id) { switch (id->get_type()) { case ident_type::ALIAS: { - alias_impl *a = static_cast(id); + alias *a = static_cast(id); + auto &ast = p_tstate->get_astack(a); if (a->get_flags() & IDENT_FLAG_ARG) { - a->set_arg(*p_tstate, v); + ast.set_arg(a, *p_tstate, v); } else { - a->set_alias(*p_tstate, v); + ast.set_alias(a, *p_tstate, v); } return; } @@ -459,9 +460,9 @@ LIBCUBESCRIPT_EXPORT void state::clear_override(ident &id) { } switch (id.get_type()) { case ident_type::ALIAS: { - alias_impl &a = static_cast(id); - a.p_astack->val_s.set_str(""); - a.p_astack->code = bcode_ref{}; + auto &ast = p_tstate->get_astack(static_cast(&id)); + ast.node->val_s.set_str(""); + ast.node->code = bcode_ref{}; break; } case ident_type::IVAR: { @@ -650,7 +651,7 @@ state::get_alias_val(std::string_view name) { if ((a->get_flags() & IDENT_FLAG_ARG) && !ident_is_used_arg(a, *p_tstate)) { return std::nullopt; } - return static_cast(a)->p_astack->val_s.get_str(); + return p_tstate->get_astack(a).node->val_s.get_str(); } integer_type clamp_var(state &cs, integer_var *iv, integer_type v) { @@ -871,14 +872,9 @@ LIBCUBESCRIPT_EXPORT void state::run( ) { break; } - if ( - static_cast(a)->p_astack->val_s.get_type() == - value_type::NONE - ) { - break; - } exec_alias( - *p_tstate, a, &args[0], ret, nargs, nargs, 0, 0, BC_RET_NULL + *p_tstate, a, &args[0], ret, nargs, nargs, 0, 0, + BC_RET_NULL, true ); break; } diff --git a/src/cs_thread.cc b/src/cs_thread.cc index 549484a..6d004ec 100644 --- a/src/cs_thread.cc +++ b/src/cs_thread.cc @@ -17,4 +17,8 @@ hook_func thread_state::set_hook(hook_func f) { return hk; } +alias_stack &thread_state::get_astack(alias *a) { + return static_cast(a)->p_astack; +} + } /* namespace cubescript */ diff --git a/src/cs_thread.hh b/src/cs_thread.hh index a49c471..68de1a1 100644 --- a/src/cs_thread.hh +++ b/src/cs_thread.hh @@ -41,6 +41,8 @@ struct thread_state { hook_func &get_hook() { return call_hook; } hook_func const &get_hook() const { return call_hook; } + + alias_stack &get_astack(alias *a); }; } /* namespace cubescript */ diff --git a/src/cs_vm.cc b/src/cs_vm.cc index d6c9092..58ed22e 100644 --- a/src/cs_vm.cc +++ b/src/cs_vm.cc @@ -9,17 +9,21 @@ namespace cubescript { -static inline void push_alias(ident *id, ident_stack &st) { +static inline void push_alias(thread_state &ts, ident *id, ident_stack &st) { if (id->is_alias() && !(id->get_flags() & IDENT_FLAG_ARG)) { auto *aimp = static_cast(id); - aimp->push_arg(st); + auto &ast = ts.get_astack(aimp); + st.next = ast.node; + ast.node = &st; aimp->p_flags &= ~IDENT_FLAG_UNKNOWN; } } -static inline void pop_alias(ident *id) { +static inline void pop_alias(thread_state &ts, ident *id) { if (id->is_alias() && !(id->get_flags() & IDENT_FLAG_ARG)) { - static_cast(id)->pop_arg(); + auto *aimp = static_cast(id); + auto &ast = ts.get_astack(aimp); + ast.node = ast.node->next; } } @@ -199,11 +203,15 @@ void exec_command( ); } -void exec_alias( +bool exec_alias( thread_state &ts, alias *a, any_value *args, any_value &result, std::size_t callargs, std::size_t &nargs, - std::size_t offset, std::size_t skip, std::uint32_t op + std::size_t offset, std::size_t skip, std::uint32_t op, bool ncheck ) { + auto &aast = ts.get_astack(a); + if (ncheck && aast.node->val_s.get_type() == value_type::NONE) { + return false; + } /* excess arguments get ignored (make error maybe?) */ callargs = std::min(callargs, MAX_ARGUMENTS); integer_var *anargs = static_cast( @@ -212,9 +220,13 @@ void exec_alias( argset uargs{}; std::size_t noff = ts.idstack.size(); for(std::size_t i = 0; i < callargs; i++) { - auto &ap = *static_cast(ts.istate->identmap[i]); - ap.push_arg(ts.idstack.emplace_back(*ts.pstate)); - ap.p_astack->val_s = std::move(args[offset + i]); + auto &ast = ts.get_astack( + static_cast(ts.istate->identmap[i]) + ); + auto &st = ts.idstack.emplace_back(*ts.pstate); + st.next = ast.node; + ast.node = &st; + st.val_s = std::move(args[offset + i]); uargs[i] = true; } auto oldargs = anargs->get_value(); @@ -223,22 +235,33 @@ void exec_alias( ts.pstate->identflags |= a->get_flags()&IDENT_FLAG_OVERRIDDEN; ident_link aliaslink = {a, ts.callstack, uargs}; ts.callstack = &aliaslink; - bcode_ref coderef = static_cast< - alias_impl * - >(a)->compile_code(ts); + if (!aast.node->code) { + codegen_state gs{ts}; + gs.code.reserve(64); + gs.gen_main(aast.node->val_s.get_str()); + /* i wish i could steal the memory somehow */ + uint32_t *code = bcode_alloc(ts.istate, gs.code.size()); + memcpy(code, gs.code.data(), gs.code.size() * sizeof(uint32_t)); + aast.node->code = bcode_ref{reinterpret_cast(code + 1)}; + } + bcode_ref coderef = aast.node->code; auto cleanup = [&]() { ts.callstack = aliaslink.next; ts.pstate->identflags = oldflags; auto amask = aliaslink.usedargs; for (std::size_t i = 0; i < callargs; i++) { - static_cast(ts.istate->identmap[i])->pop_arg(); + auto &ast = ts.get_astack( + static_cast(ts.istate->identmap[i]) + ); + ast.node = ast.node->next; amask[i] = false; } for (; amask.any(); ++callargs) { if (amask[callargs]) { - static_cast( - ts.istate->identmap[callargs] - )->pop_arg(); + auto &ast = ts.get_astack( + static_cast(ts.istate->identmap[callargs]) + ); + ast.node = ast.node->next; amask[callargs] = false; } } @@ -255,6 +278,7 @@ void exec_alias( throw; } cleanup(); + return true; } static constexpr int MaxRunDepth = 255; @@ -523,13 +547,13 @@ std::uint32_t *vm_exec( std::size_t idstsz = ts.idstack.size(); for (std::size_t i = 0; i < numlocals; ++i) { push_alias( - args[offset + i].get_ident(), + ts, args[offset + i].get_ident(), ts.idstack.emplace_back(*ts.pstate) ); } auto cleanup = [&]() { for (std::size_t i = offset; i < args.size(); ++i) { - pop_alias(args[i].get_ident()); + pop_alias(ts, args[i].get_ident()); } ts.idstack.resize(idstsz, ident_stack{*ts.pstate}); }; @@ -739,9 +763,10 @@ std::uint32_t *vm_exec( (a->get_flags() & IDENT_FLAG_ARG) && !ident_is_used_arg(a, ts) ) { - static_cast(a)->push_arg( - ts.idstack.emplace_back(*ts.pstate) - ); + auto &ast = ts.get_astack(a); + auto &st = ts.idstack.emplace_back(*ts.pstate); + st.next = ast.node; + ast.node = &st; ts.callstack->usedargs[a->get_index()] = true; } args.emplace_back(cs).set_ident(a); @@ -757,9 +782,11 @@ std::uint32_t *vm_exec( (id->get_flags() & IDENT_FLAG_ARG) && !ident_is_used_arg(id, ts) ) { - static_cast(id)->push_arg( - ts.idstack.emplace_back(*ts.pstate) - ); + auto *a = static_cast(id); + auto &ast = ts.get_astack(a); + auto &st = ts.idstack.emplace_back(*ts.pstate); + st.next = ast.node; + ast.node = &st; ts.callstack->usedargs[id->get_index()] = true; } arg.set_ident(id); @@ -771,7 +798,9 @@ std::uint32_t *vm_exec( any_value &arg = args.back(); switch (get_lookupu_type(ts, arg, id, op)) { case ID_ALIAS: - arg = static_cast(id)->p_astack->val_s; + arg = ts.get_astack( + static_cast(id) + ).node->val_s; arg.force_str(); continue; case ID_SVAR: @@ -799,7 +828,7 @@ std::uint32_t *vm_exec( args.emplace_back(cs).set_str(""); } else { auto &v = args.emplace_back(cs); - v = static_cast(a)->p_astack->val_s; + v = ts.get_astack(a).node->val_s; v.force_str(); } continue; @@ -810,9 +839,9 @@ std::uint32_t *vm_exec( any_value &arg = args.back(); switch (get_lookupu_type(ts, arg, id, op)) { case ID_ALIAS: - arg.set_int(static_cast( + arg.set_int(ts.get_astack(static_cast( id - )->p_astack->val_s.get_int()); + )).node->val_s.get_int()); continue; case ID_SVAR: arg.set_int(parse_int( @@ -840,7 +869,7 @@ std::uint32_t *vm_exec( args.emplace_back(cs).set_int(0); } else { args.emplace_back(cs).set_int( - static_cast(a)->p_astack->val_s.get_int() + ts.get_astack(a).node->val_s.get_int() ); } continue; @@ -850,9 +879,9 @@ std::uint32_t *vm_exec( any_value &arg = args.back(); switch (get_lookupu_type(ts, arg, id, op)) { case ID_ALIAS: - arg.set_float(static_cast( + arg.set_float(ts.get_astack(static_cast( id - )->p_astack->val_s.get_float()); + )).node->val_s.get_float()); continue; case ID_SVAR: arg.set_float(parse_float( @@ -881,9 +910,9 @@ std::uint32_t *vm_exec( if (!a) { args.emplace_back(cs).set_float(float_type(0)); } else { - args.emplace_back(cs).set_float(static_cast( - a - )->p_astack->val_s.get_float()); + args.emplace_back(cs).set_float( + ts.get_astack(a).node->val_s.get_float() + ); } continue; } @@ -892,9 +921,9 @@ std::uint32_t *vm_exec( any_value &arg = args.back(); switch (get_lookupu_type(ts, arg, id, op)) { case ID_ALIAS: - static_cast( - id - )->p_astack->val_s.get_val(arg); + ts.get_astack( + static_cast(id) + ).node->val_s.get_val(arg); continue; case ID_SVAR: arg.set_str(static_cast(id)->get_value()); @@ -919,7 +948,7 @@ std::uint32_t *vm_exec( if (!a) { args.emplace_back(cs).set_none(); } else { - static_cast(a)->p_astack->val_s.get_val( + ts.get_astack(a).node->val_s.get_val( args.emplace_back(cs) ); } @@ -1055,13 +1084,14 @@ std::uint32_t *vm_exec( } case BC_INST_ALIAS: { - auto *imp = static_cast( + auto *a = static_cast( ts.istate->identmap[op >> 8] ); - if (imp->get_flags() & IDENT_FLAG_ARG) { - imp->set_arg(ts, args.back()); + auto &ast = ts.get_astack(a); + if (a->get_flags() & IDENT_FLAG_ARG) { + ast.set_arg(a, ts, args.back()); } else { - imp->set_alias(ts, args.back()); + ast.set_alias(a, ts, args.back()); } args.pop_back(); continue; @@ -1154,13 +1184,13 @@ noid: std::size_t idstsz = ts.idstack.size(); for (size_t j = 0; j < size_t(callargs); ++j) { push_alias( - args[offset + j].force_ident(cs), + ts, args[offset + j].force_ident(cs), ts.idstack.emplace_back(*ts.pstate) ); } auto cleanup = [&]() { for (size_t j = 0; j < size_t(callargs); ++j) { - pop_alias(args[offset + j].get_ident()); + pop_alias(ts, args[offset + j].get_ident()); } ts.idstack.resize(idstsz, ident_stack{*ts.pstate}); }; @@ -1219,15 +1249,12 @@ noid: force_arg(result, op & BC_INST_RET_MASK); continue; } - if (static_cast( - a - )->p_astack->val_s.get_type() == value_type::NONE) { + if (!exec_alias( + ts, a, &args[0], result, callargs, nnargs, + offset, 1, op, true + )) { goto noid; } - exec_alias( - ts, a, &args[0], result, callargs, nnargs, - offset, 1, op - ); args.resize(nnargs, any_value{cs}); continue; } diff --git a/src/cs_vm.hh b/src/cs_vm.hh index e7f34e5..8e8f9e1 100644 --- a/src/cs_vm.hh +++ b/src/cs_vm.hh @@ -51,9 +51,12 @@ static void call_with_args(thread_state &ts, F body) { 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( - ts.idstack.emplace_back(*ts.pstate) + auto &ast = ts.get_astack( + static_cast(ts.istate->identmap[i]) ); + auto &st = ts.idstack.emplace_back(*ts.pstate); + st.next = ast.node; + ast.node = ast.node->next; } mask >>= 1; } @@ -74,9 +77,9 @@ static void call_with_args(thread_state &ts, F body) { auto mask2 = ts.callstack->usedargs; for (std::size_t i = 0, nredo = 0; mask2.any(); ++i) { if (mask2[0]) { - static_cast(ts.istate->identmap[i])->redo_arg( - ts.idstack[noff + nredo++] - ); + ts.get_astack( + static_cast(ts.istate->identmap[i]) + ).node = ts.idstack[noff + nredo++].next; } mask2 >>= 1; } @@ -96,10 +99,10 @@ void exec_command( std::size_t nargs, bool lookup = false ); -void exec_alias( +bool exec_alias( thread_state &ts, alias *a, any_value *args, any_value &result, - std::size_t callargs, std::size_t &nargs, - std::size_t offset, std::size_t skip, std::uint32_t op + std::size_t callargs, std::size_t &nargs, std::size_t offset, + std::size_t skip, std::uint32_t op, bool ncheck = false ); std::uint32_t *vm_exec( diff --git a/src/lib_base.cc b/src/lib_base.cc index dd87bd7..b199550 100644 --- a/src/lib_base.cc +++ b/src/lib_base.cc @@ -4,6 +4,7 @@ #include "cs_std.hh" #include "cs_ident.hh" +#include "cs_thread.hh" namespace cubescript { @@ -90,12 +91,9 @@ void init_lib_base(state &gcs) { rc = false; } ret.set_int(rc); - static_cast(cret)->set_alias( - *cs.thread_pointer(), result - ); - static_cast(css)->set_alias( - *cs.thread_pointer(), tback - ); + auto &ts = *cs.thread_pointer(); + ts.get_astack(cret).set_alias(cret, ts, result); + ts.get_astack(css).set_alias(css, ts, tback); }); gcs.new_command("?", "ttt", [](auto &, auto args, auto &res) {