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

View File

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