move most thread state into an internal structure

master
Daniel Kolesa 2021-03-24 20:33:20 +01:00
parent 4ded59ce70
commit 00b8312ad5
8 changed files with 101 additions and 55 deletions

View File

@ -268,6 +268,7 @@ enum {
struct bcode; struct bcode;
struct internal_state; struct internal_state;
struct thread_state;
struct ident_impl; struct ident_impl;
struct LIBCUBESCRIPT_EXPORT bcode_ref { struct LIBCUBESCRIPT_EXPORT bcode_ref {
@ -534,7 +535,7 @@ struct LIBCUBESCRIPT_EXPORT state {
friend inline internal_state *state_get_internal(state &); friend inline internal_state *state_get_internal(state &);
internal_state *p_state; internal_state *p_state;
ident_link *p_callstack = nullptr; thread_state *p_tstate;
int identflags = 0; int identflags = 0;
@ -558,12 +559,9 @@ struct LIBCUBESCRIPT_EXPORT state {
void swap(state &s) { void swap(state &s) {
std::swap(p_state, s.p_state); 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(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_owner, s.p_owner);
std::swap(p_callhook, s.p_callhook);
} }
state new_thread(); 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, any_value &ret);
loop_state run_loop(bcode *code); loop_state run_loop(bcode *code);
bool is_in_loop() const { bool is_in_loop() const;
return p_inloop;
}
void set_alias(std::string_view name, any_value v); 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); 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; bool p_owner = false;
hook_func p_callhook;
}; };
struct stack_state_node { struct stack_state_node {

View File

@ -1,14 +1,15 @@
#include <cubescript/cubescript.hh> #include <cubescript/cubescript.hh>
#include "cs_gen.hh" #include "cs_gen.hh"
#include "cs_thread.hh"
namespace cubescript { namespace cubescript {
LIBCUBESCRIPT_EXPORT char *error::request_buf( LIBCUBESCRIPT_EXPORT char *error::request_buf(
state &cs, std::size_t bufs, char *&sp state &cs, std::size_t bufs, char *&sp
) { ) {
charbuf &cb = *static_cast<charbuf *>(cs.p_errbuf); charbuf &cb = cs.p_tstate->errbuf;
codegen_state *gs = cs.p_pstate; codegen_state *gs = cs.p_tstate->cstate;
cb.clear(); cb.clear();
std::size_t sz = 0; std::size_t sz = 0;
if (gs) { if (gs) {
@ -44,12 +45,14 @@ LIBCUBESCRIPT_EXPORT char *error::request_buf(
} }
LIBCUBESCRIPT_EXPORT stack_state error::save_stack(state &cs) { LIBCUBESCRIPT_EXPORT stack_state error::save_stack(state &cs) {
integer_var *dalias = static_cast<integer_var *>(cs.p_state->identmap[ID_IDX_DBGALIAS]); integer_var *dalias = static_cast<integer_var *>(
cs.p_state->identmap[ID_IDX_DBGALIAS]
);
if (!dalias->get_value()) { 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; 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++; total++;
} }
if (!total) { if (!total) {
@ -60,7 +63,7 @@ LIBCUBESCRIPT_EXPORT stack_state error::save_stack(state &cs) {
); );
stack_state_node *ret = st, *nd = st; stack_state_node *ret = st, *nd = st;
++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; ++depth;
if (depth < dalias->get_value()) { if (depth < dalias->get_value()) {
nd->id = l->id; nd->id = l->id;

View File

@ -11,6 +11,7 @@
#include "cs_std.hh" #include "cs_std.hh"
#include "cs_bcode.hh" #include "cs_bcode.hh"
#include "cs_ident.hh" #include "cs_ident.hh"
#include "cs_thread.hh"
namespace cubescript { namespace cubescript {
@ -32,10 +33,10 @@ struct codegen_state {
codegen_state() = delete; codegen_state() = delete;
codegen_state(state &csr): 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{} source{}, send{}, current_line{1}, src_name{}
{ {
csr.p_pstate = this; csr.p_tstate->cstate = this;
} }
~codegen_state() { ~codegen_state() {
@ -46,7 +47,7 @@ struct codegen_state {
if (!parsing) { if (!parsing) {
return; return;
} }
cs.p_pstate = prevps; cs.p_tstate->cstate = prevps;
parsing = false; parsing = false;
} }

View File

@ -2,6 +2,7 @@
#include "cs_bcode.hh" #include "cs_bcode.hh"
#include "cs_gen.hh" #include "cs_gen.hh"
#include "cs_thread.hh"
namespace cubescript { namespace cubescript {
@ -155,8 +156,8 @@ void alias_impl::set_arg(state &cs, any_value &v) {
p_val = std::move(v); p_val = std::move(v);
clean_code(); clean_code();
} else { } else {
push_arg(v, cs.p_callstack->argstack[get_index()], false); push_arg(v, cs.p_tstate->callstack->argstack[get_index()], false);
cs.p_callstack->usedargs |= 1 << get_index(); 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) { bool ident_is_used_arg(ident *id, state &cs) {
if (!cs.p_callstack) { if (!cs.p_tstate->callstack) {
return true; return true;
} }
return cs.p_callstack->usedargs & (1 << id->get_index()); return cs.p_tstate->callstack->usedargs & (1 << id->get_index());
} }
/* public interface */ /* public interface */

View File

@ -2,6 +2,7 @@
#include "cs_bcode.hh" #include "cs_bcode.hh"
#include "cs_state.hh" #include "cs_state.hh"
#include "cs_thread.hh"
#include "cs_strman.hh" #include "cs_strman.hh"
#include "cs_gen.hh" // FIXME, only MAX_ARGUMENTS #include "cs_gen.hh" // FIXME, only MAX_ARGUMENTS
#include "cs_vm.hh" // break/continue, call_with_args #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(): state{default_alloc, nullptr} {}
state::state(alloc_func func, void *data): state::state(alloc_func func, void *data):
p_state{nullptr}, p_callhook{} p_state{nullptr}
{ {
command *p; command *p;
@ -64,8 +65,7 @@ state::state(alloc_func func, void *data):
new (p_state) internal_state{func, data}; new (p_state) internal_state{func, data};
p_owner = true; p_owner = true;
/* will be used as message storage for errors */ p_tstate = p_state->create<thread_state>(p_state);
p_errbuf = p_state->create<charbuf>(*this);
for (int i = 0; i < MAX_ARGUMENTS; ++i) { for (int i = 0; i < MAX_ARGUMENTS; ++i) {
char buf[32]; char buf[32];
@ -194,30 +194,30 @@ LIBCUBESCRIPT_EXPORT void state::destroy() {
} }
p_state->destroy(i->p_impl); p_state->destroy(i->p_impl);
} }
p_state->destroy(static_cast<charbuf *>(p_errbuf)); p_state->destroy(p_tstate);
p_state->destroy(p_state); p_state->destroy(p_state);
} }
state::state(internal_state *s): state::state(internal_state *s):
p_state(s), p_owner(false) p_state(s), p_owner(false)
{} {
p_tstate = p_state->create<thread_state>(p_state);
}
LIBCUBESCRIPT_EXPORT state state::new_thread() { LIBCUBESCRIPT_EXPORT state state::new_thread() {
return state{p_state}; return state{p_state};
} }
LIBCUBESCRIPT_EXPORT hook_func state::set_call_hook(hook_func func) { LIBCUBESCRIPT_EXPORT hook_func state::set_call_hook(hook_func func) {
auto hk = std::move(p_callhook); return p_tstate->set_hook(std::move(func));
p_callhook = std::move(func);
return hk;
} }
LIBCUBESCRIPT_EXPORT hook_func const &state::get_call_hook() const { 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() { 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( LIBCUBESCRIPT_EXPORT var_print_func state::set_var_printer(

43
src/cs_thread.hh 100644
View File

@ -0,0 +1,43 @@
#ifndef LIBCUBESCRIPT_THREAD_HH
#define LIBCUBESCRIPT_THREAD_HH
#include <cubescript/cubescript.hh>
#include <utility>
#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 */

View File

@ -280,16 +280,16 @@ static inline void call_alias(
int oldflags = cs.identflags; int oldflags = cs.identflags;
cs.identflags |= a->get_flags()&IDENT_FLAG_OVERRIDDEN; cs.identflags |= a->get_flags()&IDENT_FLAG_OVERRIDDEN;
ident_link aliaslink = { ident_link aliaslink = {
a, cs.p_callstack, (1<<callargs)-1, &argstack[0] a, cs.p_tstate->callstack, (1<<callargs)-1, &argstack[0]
}; };
cs.p_callstack = &aliaslink; cs.p_tstate->callstack = &aliaslink;
uint32_t *codep = static_cast<alias_impl *>(a)->compile_code(cs)->get_raw(); uint32_t *codep = static_cast<alias_impl *>(a)->compile_code(cs)->get_raw();
bcode_incr(codep); bcode_incr(codep);
call_with_cleanup([&]() { call_with_cleanup([&]() {
runcode(cs, codep+1, result); runcode(cs, codep+1, result);
}, [&]() { }, [&]() {
bcode_decr(codep); bcode_decr(codep);
cs.p_callstack = aliaslink.next; cs.p_tstate->callstack = aliaslink.next;
cs.identflags = oldflags; cs.identflags = oldflags;
for (int i = 0; i < callargs; i++) { for (int i = 0; i < callargs; i++) {
static_cast<alias_impl *>(cs.p_state->identmap[i])->pop_arg(); static_cast<alias_impl *>(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)) { if (!ident_is_used_arg(a, cs)) {
any_value nv{cs}; any_value nv{cs};
static_cast<alias_impl *>(a)->push_arg( static_cast<alias_impl *>(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); args[numargs++].set_ident(a);
continue; 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)) { if ((id->get_index() < MAX_ARGUMENTS) && !ident_is_used_arg(id, cs)) {
any_value nv{cs}; any_value nv{cs};
static_cast<alias_impl *>(id)->push_arg( static_cast<alias_impl *>(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); arg.set_ident(id);
continue; continue;
@ -1496,17 +1498,17 @@ any_value state::run(ident *id, std::span<any_value> args) {
} }
loop_state state::run_loop(bcode *code, any_value &ret) { loop_state state::run_loop(bcode *code, any_value &ret) {
++p_inloop; ++p_tstate->loop_level;
try { try {
run(code, ret); run(code, ret);
} catch (break_exception) { } catch (break_exception) {
--p_inloop; --p_tstate->loop_level;
return loop_state::BREAK; return loop_state::BREAK;
} catch (continue_exception) { } catch (continue_exception) {
--p_inloop; --p_tstate->loop_level;
return loop_state::CONTINUE; return loop_state::CONTINUE;
} catch (...) { } catch (...) {
--p_inloop; --p_tstate->loop_level;
throw; throw;
} }
return loop_state::NORMAL; return loop_state::NORMAL;
@ -1517,4 +1519,8 @@ loop_state state::run_loop(bcode *code) {
return run_loop(code, ret); return run_loop(code, ret);
} }
bool state::is_in_loop() const {
return !!p_tstate->loop_level;
}
} /* namespace cubescript */ } /* namespace cubescript */

View File

@ -1,11 +1,12 @@
#ifndef LIBCUBESCRIPT_VM_HH #ifndef LIBCUBESCRIPT_VM_HH
#define LIBCUBESCRIPT_VM_HH #define LIBCUBESCRIPT_VM_HH
#include "cubescript/cubescript.hh" #include <cubescript/cubescript.hh>
#include "cs_std.hh" #include "cs_std.hh"
#include "cs_ident.hh" #include "cs_ident.hh"
#include "cs_gen.hh" #include "cs_gen.hh"
#include "cs_thread.hh"
namespace cubescript { namespace cubescript {
@ -17,12 +18,12 @@ struct continue_exception {
template<typename F> template<typename F>
static void call_with_args(state &cs, F body) { static void call_with_args(state &cs, F body) {
if (!cs.p_callstack) { if (!cs.p_tstate->callstack) {
body(); body();
return; return;
} }
valarray<ident_stack, MAX_ARGUMENTS> argstack{cs}; valarray<ident_stack, MAX_ARGUMENTS> argstack{cs};
int argmask1 = cs.p_callstack->usedargs; int argmask1 = cs.p_tstate->callstack->usedargs;
for (int i = 0; argmask1; argmask1 >>= 1, ++i) { for (int i = 0; argmask1; argmask1 >>= 1, ++i) {
if (argmask1 & 1) { if (argmask1 & 1) {
static_cast<alias_impl *>(cs.p_state->identmap[i])->undo_arg( static_cast<alias_impl *>(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 = { 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->usedargs : ((1 << MAX_ARGUMENTS) - 1),
prevstack ? prevstack->argstack : nullptr prevstack ? prevstack->argstack : nullptr
}; };
cs.p_callstack = &aliaslink; cs.p_tstate->callstack = &aliaslink;
call_with_cleanup(std::move(body), [&]() { call_with_cleanup(std::move(body), [&]() {
if (prevstack) { if (prevstack) {
prevstack->usedargs = aliaslink.usedargs; prevstack->usedargs = aliaslink.usedargs;
} }
cs.p_callstack = aliaslink.next; cs.p_tstate->callstack = aliaslink.next;
int argmask2 = cs.p_callstack->usedargs; int argmask2 = cs.p_tstate->callstack->usedargs;
for (int i = 0; argmask2; argmask2 >>= 1, ++i) { for (int i = 0; argmask2; argmask2 >>= 1, ++i) {
if (argmask2 & 1) { if (argmask2 & 1) {
static_cast<alias_impl *>(cs.p_state->identmap[i])->redo_arg( static_cast<alias_impl *>(cs.p_state->identmap[i])->redo_arg(