do not use lambdas with captures in vm

master
Daniel Kolesa 2021-05-13 04:48:55 +02:00
parent 523586e3a6
commit 36fb06425b
2 changed files with 86 additions and 73 deletions

View File

@ -52,13 +52,15 @@ void exec_command(
int i = -1, fakeargs = 0, numargs = int(nargs); int i = -1, fakeargs = 0, numargs = int(nargs);
bool rep = false; bool rep = false;
auto fmt = id->args(); auto fmt = id->args();
auto set_fake = [&i, &fakeargs, &rep, args, numargs]() { auto set_fake = [](
if (++i >= numargs) { int &idx, int &fargs, bool r, int argn, any_value *argp
if (rep) { ) {
if (++idx >= argn) {
if (r) {
return false; return false;
} }
args[i].set_none(); argp[idx].set_none();
++fakeargs; ++fargs;
return false; return false;
} }
return true; return true;
@ -66,25 +68,25 @@ void exec_command(
for (auto it = fmt.begin(); it != fmt.end(); ++it) { for (auto it = fmt.begin(); it != fmt.end(); ++it) {
switch (*it) { switch (*it) {
case 'i': case 'i':
if (set_fake()) { if (set_fake(i, fakeargs, rep, numargs, args)) {
args[i].force_integer(); args[i].force_integer();
} }
break; break;
case 'f': case 'f':
if (set_fake()) { if (set_fake(i, fakeargs, rep, numargs, args)) {
args[i].force_float(); args[i].force_float();
} }
break; break;
case 's': case 's':
if (set_fake()) { if (set_fake(i, fakeargs, rep, numargs, args)) {
args[i].force_string(*ts.pstate); args[i].force_string(*ts.pstate);
} }
break; break;
case 'a': case 'a':
set_fake(); set_fake(i, fakeargs, rep, numargs, args);
break; break;
case 'c': case 'c':
if (set_fake()) { if (set_fake(i, fakeargs, rep, numargs, args)) {
if (args[i].type() == value_type::STRING) { if (args[i].type() == value_type::STRING) {
auto str = args[i].get_string(*ts.pstate); auto str = args[i].get_string(*ts.pstate);
if (str.empty()) { if (str.empty()) {
@ -96,12 +98,12 @@ void exec_command(
} }
break; break;
case 'b': case 'b':
if (set_fake()) { if (set_fake(i, fakeargs, rep, numargs, args)) {
args[i].force_code(*ts.pstate); args[i].force_code(*ts.pstate);
} }
break; break;
case 'v': case 'v':
if (set_fake()) { if (set_fake(i, fakeargs, rep, numargs, args)) {
args[i].force_ident(*ts.pstate); args[i].force_ident(*ts.pstate);
} }
break; break;
@ -176,36 +178,41 @@ bool exec_alias(
aast.node->code = gs.steal_ref(); aast.node->code = gs.steal_ref();
} }
bcode_ref coderef = aast.node->code; bcode_ref coderef = aast.node->code;
auto cleanup = [&]() { auto cleanup = [](
ts.callstack = aliaslink.next; std::uint32_t inst, auto &tss, auto &alink, std::size_t cargs,
ts.ident_flags = oldflags; std::size_t nids, auto oflags, any_value &ret
auto amask = aliaslink.usedargs; ) {
for (std::size_t i = 0; i < callargs; i++) { tss.callstack = alink.next;
ts.get_astack( tss.ident_flags = oflags;
static_cast<alias *>(ts.istate->identmap[i]) auto amask = alink.usedargs;
for (std::size_t i = 0; i < cargs; i++) {
tss.get_astack(
static_cast<alias *>(tss.istate->identmap[i])
).pop(); ).pop();
amask[i] = false; amask[i] = false;
} }
for (; amask.any(); ++callargs) { for (; amask.any(); ++cargs) {
if (amask[callargs]) { if (amask[cargs]) {
ts.get_astack( tss.get_astack(
static_cast<alias *>(ts.istate->identmap[callargs]) static_cast<alias *>(tss.istate->identmap[cargs])
).pop(); ).pop();
amask[callargs] = false; amask[cargs] = false;
} }
} }
ts.idstack.resize(noff); tss.idstack.resize(nids);
force_arg(*ts.pstate, result, op & BC_INST_RET_MASK); force_arg(*tss.pstate, ret, inst & BC_INST_RET_MASK);
anargs->set_raw_value(*ts.pstate, std::move(oldargs));
nargs = offset - skip;
}; };
try { try {
vm_exec(ts, bcode_p{coderef}.get()->raw(), result); vm_exec(ts, bcode_p{coderef}.get()->raw(), result);
} catch (...) { } catch (...) {
cleanup(); cleanup(op, ts, aliaslink, callargs, noff, oldflags, result);
anargs->set_raw_value(*ts.pstate, std::move(oldargs));
nargs = offset - skip;
throw; throw;
} }
cleanup(); cleanup(op, ts, aliaslink, callargs, noff, oldflags, result);
anargs->set_raw_value(*ts.pstate, std::move(oldargs));
nargs = offset - skip;
return true; return true;
} }
@ -311,16 +318,15 @@ std::uint32_t *vm_exec(
case BC_INST_DUP: { case BC_INST_DUP: {
auto &v = args.back(); auto &v = args.back();
auto &nv = args.emplace_back(); args.emplace_back() = v;
nv = v; force_arg(cs, args.back(), op & BC_INST_RET_MASK);
force_arg(cs, nv, op & BC_INST_RET_MASK);
continue; continue;
} }
case BC_INST_VAL: case BC_INST_VAL:
switch (op & BC_INST_RET_MASK) { switch (op & BC_INST_RET_MASK) {
case BC_RET_STRING: { case BC_RET_STRING: {
std::uint32_t len = op >> 8; auto len = op >> 8;
args.emplace_back().set_string(std::string_view{ args.emplace_back().set_string(std::string_view{
reinterpret_cast<char const *>(code), len reinterpret_cast<char const *>(code), len
}, cs); }, cs);
@ -354,9 +360,7 @@ std::uint32_t *vm_exec(
char((op >> 24) & 0xFF), '\0' char((op >> 24) & 0xFF), '\0'
}; };
/* gotta cast or r.size() == potentially 3 */ /* gotta cast or r.size() == potentially 3 */
args.emplace_back().set_string( args.emplace_back().set_string(s, cs);
static_cast<char const *>(s), cs
);
continue; continue;
} }
case BC_RET_INT: case BC_RET_INT:
@ -383,29 +387,33 @@ std::uint32_t *vm_exec(
ts.idstack.emplace_back() ts.idstack.emplace_back()
); );
} }
auto cleanup = [&]() { auto cleanup = [](
for (std::size_t i = offset; i < args.size(); ++i) { auto &css, std::size_t off, std::size_t isz, auto &av
pop_alias(ts, args[i].get_ident(cs)); ) {
for (std::size_t i = off; i < av.size(); ++i) {
pop_alias(state_p{css}.ts(), av[i].get_ident(css));
} }
ts.idstack.resize(idstsz); state_p{css}.ts().idstack.resize(isz);
}; };
try { try {
code = vm_exec(ts, code, result); code = vm_exec(ts, code, result);
} catch (...) { } catch (...) {
cleanup(); cleanup(cs, offset, idstsz, args);
throw; throw;
} }
cleanup(); cleanup(cs, offset, idstsz, args);
return code; return code;
} }
case BC_INST_DO_ARGS: case BC_INST_DO_ARGS:
call_with_args(ts, [&]() { call_with_args(ts, [](
auto v = std::move(args.back()); auto &css, std::uint32_t inst, auto &av, any_value &ret
args.pop_back(); ) {
result = v.get_code().call(cs); auto v = std::move(av.back());
force_arg(cs, result, op & BC_INST_RET_MASK); av.pop_back();
}); ret = v.get_code().call(css);
force_arg(css, ret, inst & BC_INST_RET_MASK);
}, cs, op, args, result);
continue; continue;
case BC_INST_DO: { case BC_INST_DO: {
@ -676,25 +684,25 @@ noid:
} }
case ID_LOCAL: { case ID_LOCAL: {
std::size_t idstsz = ts.idstack.size(); std::size_t idstsz = ts.idstack.size();
for (size_t j = 0; j < size_t(callargs); ++j) { for (std::size_t j = 0; j < callargs; ++j) {
push_alias( push_alias(
ts, args[offset + j].force_ident(cs), ts, args[offset + j].force_ident(cs),
ts.idstack.emplace_back() ts.idstack.emplace_back()
); );
} }
auto cleanup = [&]() {
for (size_t j = 0; j < size_t(callargs); ++j) {
pop_alias(ts, args[offset + j].get_ident(cs));
}
ts.idstack.resize(idstsz);
};
try { try {
code = vm_exec(ts, code, result); code = vm_exec(ts, code, result);
} catch (...) { } catch (...) {
cleanup(); for (std::size_t j = 0; j < callargs; ++j) {
pop_alias(ts, args[offset + j].get_ident(cs));
}
ts.idstack.resize(idstsz);
throw; throw;
} }
cleanup(); for (std::size_t j = 0; j < callargs; ++j) {
pop_alias(ts, args[offset + j].get_ident(cs));
}
ts.idstack.resize(idstsz);
return code; return code;
} }
case ID_VAR: { case ID_VAR: {

View File

@ -7,6 +7,8 @@
#include "cs_ident.hh" #include "cs_ident.hh"
#include "cs_thread.hh" #include "cs_thread.hh"
#include <utility>
namespace cubescript { namespace cubescript {
struct break_exception { struct break_exception {
@ -42,10 +44,10 @@ struct stack_guard {
stack_guard(stack_guard &&) = delete; stack_guard(stack_guard &&) = delete;
}; };
template<typename F> template<typename F, typename ...A>
static void call_with_args(thread_state &ts, F body) { static void call_with_args(thread_state &ts, F body, A &&...args) {
if (!ts.callstack) { if (!ts.callstack) {
body(); body(std::forward<A>(args)...);
return; return;
} }
auto mask = ts.callstack->usedargs; auto mask = ts.callstack->usedargs;
@ -70,29 +72,32 @@ static void call_with_args(thread_state &ts, F body) {
aliaslink.usedargs.set(); aliaslink.usedargs.set();
} }
ts.callstack = &aliaslink; ts.callstack = &aliaslink;
auto cleanup = [&]() { auto cleanup = [](
if (prevstack) { auto &tss, ident_link *pstack, ident_link &alink, std::size_t offn
prevstack->usedargs = aliaslink.usedargs; ) {
if (pstack) {
pstack->usedargs = alink.usedargs;
} }
ts.callstack = aliaslink.next; tss.callstack = alink.next;
auto mask2 = ts.callstack->usedargs; auto mask2 = tss.callstack->usedargs;
for (std::size_t i = 0, nredo = 0; mask2.any(); ++i) { for (std::size_t i = 0, nredo = 0; mask2.any(); ++i) {
if (mask2[0]) { if (mask2[0]) {
ts.get_astack( tss.get_astack(
static_cast<alias *>(ts.istate->identmap[i]) static_cast<alias *>(tss.istate->identmap[i])
).node = ts.idstack[noff + nredo++].next; ).node = tss.idstack[offn + nredo++].next;
} }
mask2 >>= 1; mask2 >>= 1;
} }
ts.idstack.resize(noff);
}; };
try { try {
body(); body(std::forward<A>(args)...);
} catch (...) { } catch (...) {
cleanup(); cleanup(ts, prevstack, aliaslink, noff);
ts.idstack.resize(noff);
throw; throw;
} }
cleanup(); cleanup(ts, prevstack, aliaslink, noff);
ts.idstack.resize(noff);
} }
void exec_command( void exec_command(