refactor vm scope guard

master
Daniel Kolesa 2021-05-14 02:36:16 +02:00
parent 36fb06425b
commit 8b04bd1488
4 changed files with 35 additions and 47 deletions

View File

@ -358,14 +358,19 @@ LIBCUBESCRIPT_EXPORT any_value command::call(
auto nargs = args.size();
auto &ts = state_p{cs}.ts();
if (nargs < std::size_t(cimpl.arg_count())) {
stack_guard s{ts}; /* restore after call */
auto &targs = ts.vmstack;
auto osz = targs.size();
targs.resize(osz + cimpl.arg_count());
for (std::size_t i = 0; i < nargs; ++i) {
targs[osz + i] = args[i];
try {
for (std::size_t i = 0; i < nargs; ++i) {
targs[osz + i] = args[i];
}
exec_command(ts, &cimpl, this, &targs[osz], ret, nargs, false);
} catch (...) {
targs.resize(osz);
throw;
}
exec_command(ts, &cimpl, this, &targs[osz], ret, nargs, false);
targs.resize(osz);
} else {
exec_command(ts, &cimpl, this, &args[0], ret, nargs, false);
}

View File

@ -517,16 +517,19 @@ LIBCUBESCRIPT_EXPORT any_value state::lookup_value(std::string_view name) {
return static_cast<builtin_var *>(id)->value();
case ident_type::COMMAND: {
any_value val{};
/* make sure value stack gets restored */
stack_guard s{*p_tstate};
auto *cimpl = static_cast<command_impl *>(id);
auto &args = p_tstate->vmstack;
auto osz = args.size();
/* pad with as many empty values as we need */
args.resize(osz + cimpl->arg_count());
exec_command(
*p_tstate, cimpl, cimpl, &args[osz], val, 0, true
);
try {
exec_command(
*p_tstate, cimpl, cimpl, &args[osz], val, 0, true
);
} catch (...) {
args.resize(osz);
throw;
}
args.resize(osz);
return val;
}

View File

@ -216,15 +216,6 @@ bool exec_alias(
return true;
}
call_depth_guard::call_depth_guard(thread_state &ts): tsp(&ts) {
if (ts.max_call_depth && (ts.call_depth >= ts.max_call_depth)) {
throw error{*ts.pstate, "exceeded recursion limit"};
}
++ts.call_depth;
}
call_depth_guard::~call_depth_guard() { --tsp->call_depth; }
static inline alias *get_lookup_id(
thread_state &ts, std::uint32_t op, alias_stack *&ast
) {
@ -247,13 +238,29 @@ static inline alias *get_lookup_id(
return static_cast<alias *>(id);
}
struct vm_guard {
vm_guard(thread_state &s): ts{s}, oldtop{s.vmstack.size()} {
if (s.max_call_depth && (s.call_depth >= s.max_call_depth)) {
throw error{*s.pstate, "exceeded recursion limit"};
}
++s.call_depth;
}
~vm_guard() {
--ts.call_depth;
ts.vmstack.resize(oldtop);
}
thread_state &ts;
std::size_t oldtop;
};
std::uint32_t *vm_exec(
thread_state &ts, std::uint32_t *code, any_value &result
) {
result.set_none();
auto &cs = *ts.pstate;
call_depth_guard level{ts}; /* incr and decr on scope exit */
stack_guard guard{ts}; /* resize back to original */
vm_guard scope{ts}; /* keep track of recursion depth + manage stack */
auto &args = ts.vmstack;
auto &chook = cs.call_hook();
if (chook) {

View File

@ -17,33 +17,6 @@ struct break_exception {
struct continue_exception {
};
struct call_depth_guard {
call_depth_guard() = delete;
call_depth_guard(thread_state &ts);
call_depth_guard(call_depth_guard const &) = delete;
call_depth_guard(call_depth_guard &&) = delete;
~call_depth_guard();
thread_state *tsp;
};
struct stack_guard {
thread_state *tsp;
std::size_t oldtop;
stack_guard() = delete;
stack_guard(thread_state &ts):
tsp{&ts}, oldtop{ts.vmstack.size()}
{}
~stack_guard() {
tsp->vmstack.resize(oldtop);
}
stack_guard(stack_guard const &) = delete;
stack_guard(stack_guard &&) = delete;
};
template<typename F, typename ...A>
static void call_with_args(thread_state &ts, F body, A &&...args) {
if (!ts.callstack) {