do not use lambdas with captures in vm
parent
523586e3a6
commit
36fb06425b
124
src/cs_vm.cc
124
src/cs_vm.cc
|
@ -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: {
|
||||||
|
|
35
src/cs_vm.hh
35
src/cs_vm.hh
|
@ -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(
|
||||||
|
|
Loading…
Reference in New Issue