remove fixed-size argument stacks and reliance on argument ids

master
Daniel Kolesa 2021-03-30 00:28:06 +02:00
parent 9e82dc0d2f
commit 4154944726
9 changed files with 46 additions and 50 deletions

View File

@ -846,8 +846,8 @@ struct LIBCUBESCRIPT_EXPORT stacked_value: any_value {
bool pop();
private:
state &p_state;
alias *p_a;
ident_stack p_stack;
bool p_pushed;
};

View File

@ -157,7 +157,7 @@ void alias_impl::set_arg(thread_state &ts, any_value &v) {
p_val = std::move(v);
clean_code();
} else {
push_arg(v, ts.callstack->argstack[get_index()], false);
push_arg(v, ts.idstack.emplace_back(*ts.pstate), false);
ts.callstack->usedargs[get_index()] = true;
}
}
@ -196,6 +196,18 @@ command_impl::command_impl(
p_cargs{args}, p_cb_cftv{std::move(f)}, p_numargs{nargs}
{}
void command_impl::call(state &cs, std::span<any_value> args, any_value &ret) {
auto &ts = *cs.thread_pointer();
auto idstsz = ts.idstack.size();
try {
p_cb_cftv(cs, args, ret);
} catch (...) {
ts.idstack.resize(idstsz, ident_stack{cs});
throw;
}
ts.idstack.resize(idstsz, ident_stack{cs});
}
bool ident_is_used_arg(ident *id, thread_state &ts) {
if (!ts.callstack) {
return true;

View File

@ -19,7 +19,6 @@ enum {
struct ident_link {
ident *id;
ident_link *next;
ident_stack *argstack;
std::bitset<MAX_ARGUMENTS> usedargs;
};
@ -110,9 +109,7 @@ struct command_impl: ident_impl, command {
string_ref name, string_ref args, int numargs, command_func func
);
void call(state &cs, std::span<any_value> args, any_value &ret) {
p_cb_cftv(cs, args, ret);
}
void call(state &cs, std::span<any_value> args, any_value &ret);
string_ref p_cargs;
command_func p_cb_cftv;

View File

@ -28,30 +28,6 @@ inline void call_with_cleanup(F1 &&dof, F2 &&clf) {
dof();
}
/* a simple static array with elements constructed using ctor args */
template<typename T, std::size_t N>
struct valarray {
template<typename ...A>
valarray(A &&...args) {
for (std::size_t i = 0; i < N; ++i) {
new (&stor[i]) T{std::forward<A>(args)...};
}
}
~valarray() {
for (std::size_t i = 0; i < N; ++i) {
std::launder(reinterpret_cast<T *>(&stor[i]))->~T();
}
}
T &operator[](std::size_t i) {
return *std::launder(reinterpret_cast<T *>(&stor[i]));
}
std::aligned_storage_t<sizeof(T), alignof(T)> stor[N];
};
/* a value buffer */
template<typename T>

View File

@ -5,9 +5,10 @@
namespace cubescript {
thread_state::thread_state(internal_state *cs):
vmstack{cs}, errbuf{cs}
vmstack{cs}, idstack{cs}, errbuf{cs}
{
vmstack.reserve(32);
idstack.reserve(MAX_ARGUMENTS);
}
hook_func thread_state::set_hook(hook_func f) {

View File

@ -21,8 +21,10 @@ struct thread_state {
state *pstate{};
/* current codegen state for diagnostics */
codegen_state *cstate{};
/* value stack for VM */
/* VM stack */
valbuf<any_value> vmstack;
/* alias stack */
valbuf<ident_stack> idstack;
/* per-thread storage buffer for error messages */
charbuf errbuf;
/* we can attach a hook to vm events */

View File

@ -411,7 +411,7 @@ bool any_value::get_bool() const {
/* stacked value for easy stack management */
stacked_value::stacked_value(state &cs, ident *id):
any_value(cs), p_a(nullptr), p_stack{cs}, p_pushed(false)
any_value{cs}, p_state{cs}, p_a{nullptr}, p_pushed{false}
{
set_alias(id);
}
@ -451,8 +451,11 @@ bool stacked_value::push() {
if (!p_a) {
return false;
}
auto &ts = *p_state.thread_pointer();
if (!p_pushed) {
static_cast<alias_impl *>(p_a)->push_arg(*this, p_stack);
static_cast<alias_impl *>(p_a)->push_arg(
*this, ts.idstack.emplace_back(p_state)
);
p_pushed = true;
} else {
static_cast<alias_impl *>(p_a)->p_val = std::move(

View File

@ -205,11 +205,11 @@ void exec_alias(
integer_var *anargs = static_cast<integer_var *>(
ts.istate->identmap[ID_IDX_NUMARGS]
);
valarray<ident_stack, MAX_ARGUMENTS> argstack{*ts.pstate};
argset uargs{};
std::size_t noff = ts.idstack.size();
for(std::size_t i = 0; i < callargs; i++) {
static_cast<alias_impl *>(ts.istate->identmap[i])->push_arg(
args[offset + i], argstack[i], false
args[offset + i], ts.idstack.emplace_back(*ts.pstate), false
);
uargs[i] = true;
}
@ -217,9 +217,7 @@ void exec_alias(
anargs->set_value(callargs);
int oldflags = ts.pstate->identflags;
ts.pstate->identflags |= a->get_flags()&IDENT_FLAG_OVERRIDDEN;
ident_link aliaslink = {
a, ts.callstack, &argstack[0], uargs
};
ident_link aliaslink = {a, ts.callstack, uargs};
ts.callstack = &aliaslink;
std::uint32_t *codep = static_cast<
alias_impl *
@ -244,6 +242,7 @@ void exec_alias(
amask[callargs] = false;
}
}
ts.idstack.resize(noff, ident_stack{*ts.pstate});
force_arg(result, op & BC_INST_RET_MASK);
anargs->set_value(integer_type(oldargs));
nargs = offset - skip;
@ -513,9 +512,12 @@ std::uint32_t *vm_exec(
case BC_INST_LOCAL: {
std::size_t numlocals = op >> 8;
std::size_t offset = args.size() - numlocals;
valarray<ident_stack, MAX_ARGUMENTS> locals{cs};
std::size_t idstsz = ts.idstack.size();
for (std::size_t i = 0; i < numlocals; ++i) {
push_alias(cs, args[offset + i].get_ident(), locals[i]);
push_alias(
cs, args[offset + i].get_ident(),
ts.idstack.emplace_back(*ts.pstate)
);
}
call_with_cleanup([&]() {
code = vm_exec(ts, code, result);
@ -523,6 +525,7 @@ std::uint32_t *vm_exec(
for (std::size_t i = offset; i < args.size(); ++i) {
pop_alias(args[i].get_ident());
}
ts.idstack.resize(idstsz, ident_stack{*ts.pstate});
});
return code;
}
@ -725,7 +728,7 @@ std::uint32_t *vm_exec(
) {
any_value nv{cs};
static_cast<alias_impl *>(a)->push_arg(
nv, ts.callstack->argstack[a->get_index()],
nv, ts.idstack.emplace_back(*ts.pstate),
false
);
ts.callstack->usedargs[a->get_index()] = true;
@ -745,7 +748,7 @@ std::uint32_t *vm_exec(
) {
any_value nv{cs};
static_cast<alias_impl *>(id)->push_arg(
nv, ts.callstack->argstack[id->get_index()],
nv, ts.idstack.emplace_back(*ts.pstate),
false
);
ts.callstack->usedargs[id->get_index()] = true;
@ -1131,10 +1134,11 @@ noid:
args.resize(offset - 1, any_value{cs});
continue;
case ID_LOCAL: {
valarray<ident_stack, MAX_ARGUMENTS> locals{cs};
std::size_t idstsz = ts.idstack.size();
for (size_t j = 0; j < size_t(callargs); ++j) {
push_alias(
cs, args[offset + j].force_ident(cs), locals[j]
cs, args[offset + j].force_ident(cs),
ts.idstack.emplace_back(*ts.pstate)
);
}
call_with_cleanup([&]() {
@ -1143,6 +1147,7 @@ noid:
for (size_t j = 0; j < size_t(callargs); ++j) {
pop_alias(args[offset + j].get_ident());
}
ts.idstack.resize(idstsz, ident_stack{*ts.pstate});
});
return code;
}

View File

@ -47,12 +47,12 @@ static void call_with_args(thread_state &ts, F body) {
body();
return;
}
valarray<ident_stack, MAX_ARGUMENTS> argstack{*ts.pstate};
auto mask = ts.callstack->usedargs;
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(
argstack[i]
ts.idstack.emplace_back(*ts.pstate)
);
}
mask >>= 1;
@ -60,7 +60,6 @@ static void call_with_args(thread_state &ts, F body) {
ident_link *prevstack = ts.callstack->next;
ident_link aliaslink = {
ts.callstack->id, ts.callstack,
prevstack ? prevstack->argstack : nullptr,
prevstack ? prevstack->usedargs : argset{}
};
if (!prevstack) {
@ -73,14 +72,15 @@ static void call_with_args(thread_state &ts, F body) {
}
ts.callstack = aliaslink.next;
auto mask2 = ts.callstack->usedargs;
for (std::size_t i = 0; mask2.any(); ++i) {
for (std::size_t i = 0, nredo = 0; mask2.any(); ++i) {
if (mask2[0]) {
static_cast<alias_impl *>(ts.istate->identmap[i])->redo_arg(
argstack[i]
ts.idstack[noff + nredo++]
);
}
mask2 >>= 1;
}
ts.idstack.resize(noff, ident_stack{*ts.pstate});
});
}