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 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 {

View File

@ -1,14 +1,15 @@
#include <cubescript/cubescript.hh>
#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<charbuf *>(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<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()) {
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;

View File

@ -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;
}

View File

@ -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 */

View File

@ -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<charbuf>(*this);
p_tstate = p_state->create<thread_state>(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<charbuf *>(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<thread_state>(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(

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;
cs.identflags |= a->get_flags()&IDENT_FLAG_OVERRIDDEN;
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();
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<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)) {
any_value nv{cs};
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);
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<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);
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) {
++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 */

View File

@ -1,11 +1,12 @@
#ifndef LIBCUBESCRIPT_VM_HH
#define LIBCUBESCRIPT_VM_HH
#include "cubescript/cubescript.hh"
#include <cubescript/cubescript.hh>
#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<typename F>
static void call_with_args(state &cs, F body) {
if (!cs.p_callstack) {
if (!cs.p_tstate->callstack) {
body();
return;
}
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) {
if (argmask1 & 1) {
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 = {
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<alias_impl *>(cs.p_state->identmap[i])->redo_arg(