move most thread state into an internal structure
parent
4ded59ce70
commit
00b8312ad5
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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 */
|
28
src/cs_vm.cc
28
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<<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 */
|
||||
|
|
17
src/cs_vm.hh
17
src/cs_vm.hh
|
@ -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(
|
||||
|
|
Loading…
Reference in New Issue