clean up the call stack in a scoped way properly always

master
Daniel Kolesa 2016-09-08 23:42:14 +02:00
parent e3310ce74f
commit 5674375614
3 changed files with 66 additions and 36 deletions

View File

@ -2,6 +2,8 @@
#define LIBCUBESCRIPT_CS_UTIL_HH #define LIBCUBESCRIPT_CS_UTIL_HH
#include <ostd/string.hh> #include <ostd/string.hh>
#include <ostd/utility.hh>
#include <ostd/type_traits.hh>
namespace cscript { namespace cscript {
@ -13,6 +15,22 @@ CsFloat cs_parse_float(
ostd::ConstCharRange input, ostd::ConstCharRange *end = nullptr ostd::ConstCharRange input, ostd::ConstCharRange *end = nullptr
); );
template<typename F>
struct CsScopeExit {
template<typename FF>
CsScopeExit(FF &&f): func(ostd::forward<FF>(f)) {}
~CsScopeExit() {
func();
}
ostd::Decay<F> func;
};
template<typename F1, typename F2>
inline void cs_do_and_cleanup(F1 &&dof, F2 &&clf) {
CsScopeExit<F2> cleanup(ostd::forward<F2>(clf));
dof();
}
} /* namespace cscript */ } /* namespace cscript */
#endif /* LIBCUBESCRIPT_CS_UTIL_HH */ #endif /* LIBCUBESCRIPT_CS_UTIL_HH */

View File

@ -443,25 +443,28 @@ static inline void cs_call_alias(
CsAliasInternal::compile_code(a, cs) CsAliasInternal::compile_code(a, cs)
); );
bcode_incr(codep); bcode_incr(codep);
runcode(cs, codep+1, result); cs_do_and_cleanup([&]() {
bcode_decr(codep); runcode(cs, codep+1, result);
cs.p_callstack = aliaslink.next; }, [&]() {
cs.identflags = oldflags; bcode_decr(codep);
for (int i = 0; i < callargs; i++) { cs.p_callstack = aliaslink.next;
CsAliasInternal::pop_arg(static_cast<CsAlias *>(cs.identmap[i])); cs.identflags = oldflags;
} for (int i = 0; i < callargs; i++) {
int argmask = aliaslink.usedargs & (~0 << callargs); CsAliasInternal::pop_arg(static_cast<CsAlias *>(cs.identmap[i]));
for (; argmask; ++callargs) {
if (argmask & (1 << callargs)) {
CsAliasInternal::pop_arg(static_cast<CsAlias *>(
cs.identmap[callargs])
);
argmask &= ~(1 << callargs);
} }
} int argmask = aliaslink.usedargs & (~0 << callargs);
force_arg(result, op & CsCodeRetMask); for (; argmask; ++callargs) {
anargs->set_value(oldargs); if (argmask & (1 << callargs)) {
nargs = offset - skip; CsAliasInternal::pop_arg(static_cast<CsAlias *>(
cs.identmap[callargs])
);
argmask &= ~(1 << callargs);
}
}
force_arg(result, op & CsCodeRetMask);
anargs->set_value(oldargs);
nargs = offset - skip;
});
} }
static constexpr int MaxRunDepth = 255; static constexpr int MaxRunDepth = 255;
@ -631,10 +634,13 @@ static ostd::Uint32 *runcode(CsState &cs, ostd::Uint32 *code, CsValue &result) {
for (int i = 0; i < numlocals; ++i) { for (int i = 0; i < numlocals; ++i) {
cs_push_alias(args[offset + i].get_ident(), locals[i]); cs_push_alias(args[offset + i].get_ident(), locals[i]);
} }
code = runcode(cs, code, result); cs_do_and_cleanup([&]() {
for (int i = offset; i < numargs; i++) { code = runcode(cs, code, result);
cs_pop_alias(args[i].get_ident()); }, [&]() {
} for (int i = offset; i < numargs; i++) {
cs_pop_alias(args[i].get_ident());
}
});
goto exit; goto exit;
} }
@ -1448,10 +1454,13 @@ noid:
args[offset + j] args[offset + j]
), locals[j]); ), locals[j]);
} }
code = runcode(cs, code, result); cs_do_and_cleanup([&]() {
for (ostd::Size j = 0; j < ostd::Size(callargs); ++j) { code = runcode(cs, code, result);
cs_pop_alias(args[offset + j].get_ident()); }, [&]() {
} for (ostd::Size j = 0; j < ostd::Size(callargs); ++j) {
cs_pop_alias(args[offset + j].get_ident());
}
});
goto exit; goto exit;
} }
case CsIdIvar: case CsIdIvar:

View File

@ -8,6 +8,8 @@
#include <ostd/array.hh> #include <ostd/array.hh>
#include <ostd/vector.hh> #include <ostd/vector.hh>
#include "cs_util.hh"
namespace cscript { namespace cscript {
static constexpr int MaxArguments = 25; static constexpr int MaxArguments = 25;
@ -328,17 +330,18 @@ static void cs_do_args(CsState &cs, F body) {
cs.p_callstack->id, cs.p_callstack, prevstack->usedargs, prevstack->argstack cs.p_callstack->id, cs.p_callstack, prevstack->usedargs, prevstack->argstack
}; };
cs.p_callstack = &aliaslink; cs.p_callstack = &aliaslink;
body(); cs_do_and_cleanup(ostd::move(body), [&]() {
prevstack->usedargs = aliaslink.usedargs; prevstack->usedargs = aliaslink.usedargs;
cs.p_callstack = aliaslink.next; cs.p_callstack = aliaslink.next;
int argmask2 = cs.p_callstack->usedargs; int argmask2 = cs.p_callstack->usedargs;
for (int i = 0; argmask2; argmask2 >>= 1, ++i) { for (int i = 0; argmask2; argmask2 >>= 1, ++i) {
if (argmask2 & 1) { if (argmask2 & 1) {
CsAliasInternal::redo_arg( CsAliasInternal::redo_arg(
static_cast<CsAlias *>(cs.identmap[i]), argstack[i] static_cast<CsAlias *>(cs.identmap[i]), argstack[i]
); );
}
} }
} });
} }
CsBytecode *cs_copy_code(CsBytecode *c); CsBytecode *cs_copy_code(CsBytecode *c);