diff --git a/include/cubescript/cubescript.hh b/include/cubescript/cubescript.hh index 635259d..2ce4ad1 100644 --- a/include/cubescript/cubescript.hh +++ b/include/cubescript/cubescript.hh @@ -268,6 +268,7 @@ enum { struct bcode; struct internal_state; +struct thread_state; struct ident_impl; struct LIBCUBESCRIPT_EXPORT bcode_ref { @@ -534,7 +535,7 @@ struct LIBCUBESCRIPT_EXPORT state { friend inline internal_state *state_get_internal(state &); internal_state *p_state; - ident_link *p_callstack = nullptr; + thread_state *p_tstate; int identflags = 0; @@ -558,12 +559,9 @@ struct LIBCUBESCRIPT_EXPORT state { void swap(state &s) { std::swap(p_state, s.p_state); - std::swap(p_callstack, s.p_callstack); + std::swap(p_tstate, s.p_tstate); std::swap(identflags, s.identflags); - std::swap(p_pstate, s.p_pstate); - std::swap(p_inloop, s.p_inloop); std::swap(p_owner, s.p_owner); - std::swap(p_callhook, s.p_callhook); } state new_thread(); @@ -671,9 +669,7 @@ struct LIBCUBESCRIPT_EXPORT state { loop_state run_loop(bcode *code, any_value &ret); loop_state run_loop(bcode *code); - bool is_in_loop() const { - return p_inloop; - } + bool is_in_loop() const; void set_alias(std::string_view name, any_value v); @@ -740,12 +736,7 @@ private: void *alloc(void *ptr, size_t olds, size_t news); - codegen_state *p_pstate = nullptr; - void *p_errbuf = nullptr; - int p_inloop = 0; bool p_owner = false; - - hook_func p_callhook; }; struct stack_state_node { diff --git a/src/cs_error.cc b/src/cs_error.cc index 86445e8..5aad576 100644 --- a/src/cs_error.cc +++ b/src/cs_error.cc @@ -1,14 +1,15 @@ #include #include "cs_gen.hh" +#include "cs_thread.hh" namespace cubescript { LIBCUBESCRIPT_EXPORT char *error::request_buf( state &cs, std::size_t bufs, char *&sp ) { - charbuf &cb = *static_cast(cs.p_errbuf); - codegen_state *gs = cs.p_pstate; + charbuf &cb = cs.p_tstate->errbuf; + codegen_state *gs = cs.p_tstate->cstate; cb.clear(); std::size_t sz = 0; if (gs) { @@ -44,12 +45,14 @@ LIBCUBESCRIPT_EXPORT char *error::request_buf( } LIBCUBESCRIPT_EXPORT stack_state error::save_stack(state &cs) { - integer_var *dalias = static_cast(cs.p_state->identmap[ID_IDX_DBGALIAS]); + integer_var *dalias = static_cast( + cs.p_state->identmap[ID_IDX_DBGALIAS] + ); if (!dalias->get_value()) { - return stack_state(cs, nullptr, !!cs.p_callstack); + return stack_state(cs, nullptr, !!cs.p_tstate->callstack); } int total = 0, depth = 0; - for (ident_link *l = cs.p_callstack; l; l = l->next) { + for (ident_link *l = cs.p_tstate->callstack; l; l = l->next) { total++; } if (!total) { @@ -60,7 +63,7 @@ LIBCUBESCRIPT_EXPORT stack_state error::save_stack(state &cs) { ); stack_state_node *ret = st, *nd = st; ++st; - for (ident_link *l = cs.p_callstack; l; l = l->next) { + for (ident_link *l = cs.p_tstate->callstack; l; l = l->next) { ++depth; if (depth < dalias->get_value()) { nd->id = l->id; diff --git a/src/cs_gen.hh b/src/cs_gen.hh index 00d80ce..12dbabb 100644 --- a/src/cs_gen.hh +++ b/src/cs_gen.hh @@ -11,6 +11,7 @@ #include "cs_std.hh" #include "cs_bcode.hh" #include "cs_ident.hh" +#include "cs_thread.hh" namespace cubescript { @@ -32,10 +33,10 @@ struct codegen_state { codegen_state() = delete; codegen_state(state &csr): - cs{csr}, prevps{csr.p_pstate}, code{cs}, + cs{csr}, prevps{csr.p_tstate->cstate}, code{cs}, source{}, send{}, current_line{1}, src_name{} { - csr.p_pstate = this; + csr.p_tstate->cstate = this; } ~codegen_state() { @@ -46,7 +47,7 @@ struct codegen_state { if (!parsing) { return; } - cs.p_pstate = prevps; + cs.p_tstate->cstate = prevps; parsing = false; } diff --git a/src/cs_ident.cc b/src/cs_ident.cc index 659c6b6..e9d4953 100644 --- a/src/cs_ident.cc +++ b/src/cs_ident.cc @@ -2,6 +2,7 @@ #include "cs_bcode.hh" #include "cs_gen.hh" +#include "cs_thread.hh" namespace cubescript { @@ -155,8 +156,8 @@ void alias_impl::set_arg(state &cs, any_value &v) { p_val = std::move(v); clean_code(); } else { - push_arg(v, cs.p_callstack->argstack[get_index()], false); - cs.p_callstack->usedargs |= 1 << get_index(); + push_arg(v, cs.p_tstate->callstack->argstack[get_index()], false); + cs.p_tstate->callstack->usedargs |= 1 << get_index(); } } @@ -195,10 +196,10 @@ command_impl::command_impl( {} bool ident_is_used_arg(ident *id, state &cs) { - if (!cs.p_callstack) { + if (!cs.p_tstate->callstack) { return true; } - return cs.p_callstack->usedargs & (1 << id->get_index()); + return cs.p_tstate->callstack->usedargs & (1 << id->get_index()); } /* public interface */ diff --git a/src/cs_state.cc b/src/cs_state.cc index 5a8a06a..43bb31b 100644 --- a/src/cs_state.cc +++ b/src/cs_state.cc @@ -2,6 +2,7 @@ #include "cs_bcode.hh" #include "cs_state.hh" +#include "cs_thread.hh" #include "cs_strman.hh" #include "cs_gen.hh" // FIXME, only MAX_ARGUMENTS #include "cs_vm.hh" // break/continue, call_with_args @@ -49,7 +50,7 @@ void init_lib_list(state &cs); state::state(): state{default_alloc, nullptr} {} state::state(alloc_func func, void *data): - p_state{nullptr}, p_callhook{} + p_state{nullptr} { command *p; @@ -64,8 +65,7 @@ state::state(alloc_func func, void *data): new (p_state) internal_state{func, data}; p_owner = true; - /* will be used as message storage for errors */ - p_errbuf = p_state->create(*this); + p_tstate = p_state->create(p_state); for (int i = 0; i < MAX_ARGUMENTS; ++i) { char buf[32]; @@ -194,30 +194,30 @@ LIBCUBESCRIPT_EXPORT void state::destroy() { } p_state->destroy(i->p_impl); } - p_state->destroy(static_cast(p_errbuf)); + p_state->destroy(p_tstate); p_state->destroy(p_state); } state::state(internal_state *s): p_state(s), p_owner(false) -{} +{ + p_tstate = p_state->create(p_state); +} LIBCUBESCRIPT_EXPORT state state::new_thread() { return state{p_state}; } LIBCUBESCRIPT_EXPORT hook_func state::set_call_hook(hook_func func) { - auto hk = std::move(p_callhook); - p_callhook = std::move(func); - return hk; + return p_tstate->set_hook(std::move(func)); } LIBCUBESCRIPT_EXPORT hook_func const &state::get_call_hook() const { - return p_callhook; + return p_tstate->get_hook(); } LIBCUBESCRIPT_EXPORT hook_func &state::get_call_hook() { - return p_callhook; + return p_tstate->get_hook(); } LIBCUBESCRIPT_EXPORT var_print_func state::set_var_printer( diff --git a/src/cs_thread.hh b/src/cs_thread.hh new file mode 100644 index 0000000..1b50d43 --- /dev/null +++ b/src/cs_thread.hh @@ -0,0 +1,43 @@ +#ifndef LIBCUBESCRIPT_THREAD_HH +#define LIBCUBESCRIPT_THREAD_HH + +#include + +#include + +#include "cs_std.hh" +#include "cs_state.hh" + +namespace cubescript { + +struct codegen_state; + +struct thread_state { + /* thread call stack */ + ident_link *callstack{}; + /* current codegen state for diagnostics */ + codegen_state *cstate{}; + /* per-thread storage buffer for error messages */ + charbuf errbuf; + /* we can attach a hook to vm events */ + hook_func call_hook{}; + /* loop nesting level */ + int loop_level = 0; + + thread_state(internal_state *cs): + errbuf{cs} + {} + + hook_func set_hook(hook_func f) { + auto hk = std::move(call_hook); + call_hook = std::move(f); + return hk; + } + + hook_func &get_hook() { return call_hook; } + hook_func const &get_hook() const { return call_hook; } +}; + +} /* namespace cubescript */ + +#endif /* LIBCUBESCRIPT_THREAD_HH */ diff --git a/src/cs_vm.cc b/src/cs_vm.cc index 6c0cf3e..dd11dc5 100644 --- a/src/cs_vm.cc +++ b/src/cs_vm.cc @@ -280,16 +280,16 @@ static inline void call_alias( int oldflags = cs.identflags; cs.identflags |= a->get_flags()&IDENT_FLAG_OVERRIDDEN; ident_link aliaslink = { - a, cs.p_callstack, (1<callstack, (1<callstack = &aliaslink; uint32_t *codep = static_cast(a)->compile_code(cs)->get_raw(); bcode_incr(codep); call_with_cleanup([&]() { runcode(cs, codep+1, result); }, [&]() { bcode_decr(codep); - cs.p_callstack = aliaslink.next; + cs.p_tstate->callstack = aliaslink.next; cs.identflags = oldflags; for (int i = 0; i < callargs; i++) { static_cast(cs.p_state->identmap[i])->pop_arg(); @@ -750,9 +750,10 @@ static uint32_t *runcode(state &cs, uint32_t *code, any_value &result) { if (!ident_is_used_arg(a, cs)) { any_value nv{cs}; static_cast(a)->push_arg( - nv, cs.p_callstack->argstack[a->get_index()], false + nv, cs.p_tstate->callstack->argstack[a->get_index()], + false ); - cs.p_callstack->usedargs |= 1 << a->get_index(); + cs.p_tstate->callstack->usedargs |= 1 << a->get_index(); } args[numargs++].set_ident(a); continue; @@ -766,9 +767,10 @@ static uint32_t *runcode(state &cs, uint32_t *code, any_value &result) { if ((id->get_index() < MAX_ARGUMENTS) && !ident_is_used_arg(id, cs)) { any_value nv{cs}; static_cast(id)->push_arg( - nv, cs.p_callstack->argstack[id->get_index()], false + nv, cs.p_tstate->callstack->argstack[id->get_index()], + false ); - cs.p_callstack->usedargs |= 1 << id->get_index(); + cs.p_tstate->callstack->usedargs |= 1 << id->get_index(); } arg.set_ident(id); continue; @@ -1496,17 +1498,17 @@ any_value state::run(ident *id, std::span args) { } loop_state state::run_loop(bcode *code, any_value &ret) { - ++p_inloop; + ++p_tstate->loop_level; try { run(code, ret); } catch (break_exception) { - --p_inloop; + --p_tstate->loop_level; return loop_state::BREAK; } catch (continue_exception) { - --p_inloop; + --p_tstate->loop_level; return loop_state::CONTINUE; } catch (...) { - --p_inloop; + --p_tstate->loop_level; throw; } return loop_state::NORMAL; @@ -1517,4 +1519,8 @@ loop_state state::run_loop(bcode *code) { return run_loop(code, ret); } +bool state::is_in_loop() const { + return !!p_tstate->loop_level; +} + } /* namespace cubescript */ diff --git a/src/cs_vm.hh b/src/cs_vm.hh index 9940f7a..d44dd83 100644 --- a/src/cs_vm.hh +++ b/src/cs_vm.hh @@ -1,11 +1,12 @@ #ifndef LIBCUBESCRIPT_VM_HH #define LIBCUBESCRIPT_VM_HH -#include "cubescript/cubescript.hh" +#include #include "cs_std.hh" #include "cs_ident.hh" #include "cs_gen.hh" +#include "cs_thread.hh" namespace cubescript { @@ -17,12 +18,12 @@ struct continue_exception { template static void call_with_args(state &cs, F body) { - if (!cs.p_callstack) { + if (!cs.p_tstate->callstack) { body(); return; } valarray argstack{cs}; - int argmask1 = cs.p_callstack->usedargs; + int argmask1 = cs.p_tstate->callstack->usedargs; for (int i = 0; argmask1; argmask1 >>= 1, ++i) { if (argmask1 & 1) { static_cast(cs.p_state->identmap[i])->undo_arg( @@ -30,19 +31,19 @@ static void call_with_args(state &cs, F body) { ); } } - ident_link *prevstack = cs.p_callstack->next; + ident_link *prevstack = cs.p_tstate->callstack->next; ident_link aliaslink = { - cs.p_callstack->id, cs.p_callstack, + cs.p_tstate->callstack->id, cs.p_tstate->callstack, prevstack ? prevstack->usedargs : ((1 << MAX_ARGUMENTS) - 1), prevstack ? prevstack->argstack : nullptr }; - cs.p_callstack = &aliaslink; + cs.p_tstate->callstack = &aliaslink; call_with_cleanup(std::move(body), [&]() { if (prevstack) { prevstack->usedargs = aliaslink.usedargs; } - cs.p_callstack = aliaslink.next; - int argmask2 = cs.p_callstack->usedargs; + cs.p_tstate->callstack = aliaslink.next; + int argmask2 = cs.p_tstate->callstack->usedargs; for (int i = 0; argmask2; argmask2 >>= 1, ++i) { if (argmask2 & 1) { static_cast(cs.p_state->identmap[i])->redo_arg(