prepare codebase for per-thread alias stack

master
Daniel Kolesa 2021-04-02 05:47:49 +02:00
parent e8856f8f9d
commit 881ba4bce9
9 changed files with 150 additions and 147 deletions

View File

@ -640,6 +640,7 @@ struct LIBCUBESCRIPT_EXPORT alias_local {
private:
alias *p_alias;
void *p_sp;
};
struct LIBCUBESCRIPT_EXPORT list_parser {

View File

@ -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<bcode *>(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<alias_impl *>(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<alias_impl *>(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<alias *>(a);
auto &ast = ts.get_astack(p_alias);
auto &st = ts.idstack.emplace_back(cs);
st.next = ast.node;
ast.node = &st;
p_sp = &ast;
static_cast<alias_impl *>(p_alias)->p_flags &= ~IDENT_FLAG_UNKNOWN;
}
LIBCUBESCRIPT_EXPORT alias_local::~alias_local() {
static_cast<alias_impl *>(p_alias)->pop_arg();
if (p_alias) {
auto &st = *static_cast<alias_stack *>(p_sp);
st.node = st.node->next;
}
}
LIBCUBESCRIPT_EXPORT bool alias_local::set(any_value val) {
if (!p_alias) {
return false;
}
static_cast<alias_impl *>(p_alias)->p_astack->val_s = std::move(val);
static_cast<alias_stack *>(p_sp)->node->val_s = std::move(val);
return true;
}

View File

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

View File

@ -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<alias_impl *>(id);
alias *a = static_cast<alias *>(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<alias_impl &>(id);
a.p_astack->val_s.set_str("");
a.p_astack->code = bcode_ref{};
auto &ast = p_tstate->get_astack(static_cast<alias *>(&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<alias_impl *>(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<alias_impl *>(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;
}

View File

@ -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<alias_impl *>(a)->p_astack;
}
} /* namespace cubescript */

View File

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

View File

@ -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<alias_impl *>(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<alias_impl *>(id)->pop_arg();
auto *aimp = static_cast<alias_impl *>(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<integer_var *>(
@ -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<alias_impl *>(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<alias *>(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<bcode *>(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<alias_impl *>(ts.istate->identmap[i])->pop_arg();
auto &ast = ts.get_astack(
static_cast<alias *>(ts.istate->identmap[i])
);
ast.node = ast.node->next;
amask[i] = false;
}
for (; amask.any(); ++callargs) {
if (amask[callargs]) {
static_cast<alias_impl *>(
ts.istate->identmap[callargs]
)->pop_arg();
auto &ast = ts.get_astack(
static_cast<alias *>(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<alias_impl *>(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<alias_impl *>(id)->push_arg(
ts.idstack.emplace_back(*ts.pstate)
);
auto *a = static_cast<alias *>(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<alias_impl *>(id)->p_astack->val_s;
arg = ts.get_astack(
static_cast<alias *>(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<alias_impl *>(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<alias_impl *>(
arg.set_int(ts.get_astack(static_cast<alias *>(
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<alias_impl *>(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<alias_impl *>(
arg.set_float(ts.get_astack(static_cast<alias *>(
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<alias_impl *>(
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<alias_impl *>(
id
)->p_astack->val_s.get_val(arg);
ts.get_astack(
static_cast<alias *>(id)
).node->val_s.get_val(arg);
continue;
case ID_SVAR:
arg.set_str(static_cast<string_var *>(id)->get_value());
@ -919,7 +948,7 @@ std::uint32_t *vm_exec(
if (!a) {
args.emplace_back(cs).set_none();
} else {
static_cast<alias_impl *>(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<alias_impl *>(
auto *a = static_cast<alias *>(
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<alias_impl *>(
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;
}

View File

@ -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<alias_impl *>(ts.istate->identmap[i])->undo_arg(
ts.idstack.emplace_back(*ts.pstate)
auto &ast = ts.get_astack(
static_cast<alias *>(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<alias_impl *>(ts.istate->identmap[i])->redo_arg(
ts.idstack[noff + nredo++]
);
ts.get_astack(
static_cast<alias *>(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(

View File

@ -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<alias_impl *>(cret)->set_alias(
*cs.thread_pointer(), result
);
static_cast<alias_impl *>(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) {