various vm cleanups

master
Daniel Kolesa 2021-05-14 19:18:11 +02:00
parent 036362683c
commit 6ffdc7fa91
3 changed files with 75 additions and 101 deletions

View File

@ -335,7 +335,7 @@ LIBCUBESCRIPT_EXPORT any_value alias::call(
return ret; return ret;
} }
auto nargs = args.size(); auto nargs = args.size();
exec_alias(ts, this, &args[0], ret, nargs, nargs, 0, 0, BC_RET_NULL, true); exec_alias(ts, this, &args[0], ret, nargs, nargs, 0, 0, true);
return ret; return ret;
} }

View File

@ -31,20 +31,6 @@ static inline void pop_alias(thread_state &ts, ident &id) {
} }
} }
static inline void force_arg(state &cs, any_value &v, int type) {
switch (type) {
case BC_RET_STRING:
v.force_string(cs);
break;
case BC_RET_INT:
v.force_integer();
break;
case BC_RET_FLOAT:
v.force_float();
break;
}
}
void exec_command( void exec_command(
thread_state &ts, command_impl *id, ident *self, any_value *args, thread_state &ts, command_impl *id, ident *self, any_value *args,
any_value &res, std::size_t nargs, bool lookup any_value &res, std::size_t nargs, bool lookup
@ -138,7 +124,7 @@ void exec_command(
bool exec_alias( bool exec_alias(
thread_state &ts, alias *a, any_value *args, any_value &result, thread_state &ts, alias *a, any_value *args, any_value &result,
std::size_t callargs, std::size_t &nargs, std::size_t callargs, std::size_t &nargs,
std::size_t offset, std::size_t skip, std::uint32_t op, bool ncheck std::size_t offset, std::size_t skip, bool ncheck
) { ) {
auto &aast = ts.get_astack(a); auto &aast = ts.get_astack(a);
if (ncheck) { if (ncheck) {
@ -179,8 +165,8 @@ bool exec_alias(
} }
bcode_ref coderef = aast.node->code; bcode_ref coderef = aast.node->code;
auto cleanup = []( auto cleanup = [](
std::uint32_t inst, auto &tss, auto &alink, std::size_t cargs, auto &tss, auto &alink, std::size_t cargs,
std::size_t nids, auto oflags, any_value &ret std::size_t nids, auto oflags
) { ) {
tss.callstack = alink.next; tss.callstack = alink.next;
tss.ident_flags = oflags; tss.ident_flags = oflags;
@ -200,17 +186,16 @@ bool exec_alias(
} }
} }
tss.idstack.resize(nids); tss.idstack.resize(nids);
force_arg(*tss.pstate, ret, inst & BC_INST_RET_MASK);
}; };
try { try {
vm_exec(ts, bcode_p{coderef}.get()->raw(), result); vm_exec(ts, bcode_p{coderef}.get()->raw(), result);
} catch (...) { } catch (...) {
cleanup(op, ts, aliaslink, callargs, noff, oldflags, result); cleanup(ts, aliaslink, callargs, noff, oldflags);
anargs->set_raw_value(*ts.pstate, std::move(oldargs)); anargs->set_raw_value(*ts.pstate, std::move(oldargs));
nargs = offset - skip; nargs = offset - skip;
throw; throw;
} }
cleanup(op, ts, aliaslink, callargs, noff, oldflags, result); cleanup(ts, aliaslink, callargs, noff, oldflags);
anargs->set_raw_value(*ts.pstate, std::move(oldargs)); anargs->set_raw_value(*ts.pstate, std::move(oldargs));
nargs = offset - skip; nargs = offset - skip;
return true; return true;
@ -272,28 +257,6 @@ any_value exec_code_with_args(thread_state &ts, bcode_ref const &body) {
return ret; return ret;
} }
static inline alias *get_lookup_id(
thread_state &ts, std::uint32_t op, alias_stack *&ast
) {
ident *id = ts.istate->identmap[op >> 8];
auto *a = static_cast<alias_impl *>(id);
if (a->is_arg()) {
if (!ident_is_used_arg(id, ts)) {
return nullptr;
}
ast = &ts.get_astack(static_cast<alias *>(id));
} else {
ast = &ts.get_astack(static_cast<alias *>(id));
if (ast->flags & IDENT_FLAG_UNKNOWN) {
throw error_p::make(
*ts.pstate, "unknown alias lookup: %s", id->name().data()
);
}
}
return static_cast<alias *>(id);
}
struct vm_guard { struct vm_guard {
vm_guard(thread_state &s): ts{s}, oldtop{s.vmstack.size()} { vm_guard(thread_state &s): ts{s}, oldtop{s.vmstack.size()} {
if (s.max_call_depth && (s.call_depth >= s.max_call_depth)) { if (s.max_call_depth && (s.call_depth >= s.max_call_depth)) {
@ -322,6 +285,19 @@ std::uint32_t *vm_exec(
if (chook) { if (chook) {
chook(cs); chook(cs);
} }
auto force_val = [](state &s, any_value &v, int opn) {
switch (opn & BC_INST_RET_MASK) {
case BC_RET_STRING:
v.force_string(s);
break;
case BC_RET_INT:
v.force_integer();
break;
case BC_RET_FLOAT:
v.force_float();
break;
}
};
for (;;) { for (;;) {
std::uint32_t op = *code++; std::uint32_t op = *code++;
switch (op & BC_INST_OP_MASK) { switch (op & BC_INST_OP_MASK) {
@ -331,59 +307,52 @@ std::uint32_t *vm_exec(
case BC_INST_NULL: case BC_INST_NULL:
result.set_none(); result.set_none();
force_arg(cs, result, op & BC_INST_RET_MASK); goto use_result;
continue;
case BC_INST_FALSE: case BC_INST_FALSE:
result.set_integer(0); result.set_integer(0);
force_arg(cs, result, op & BC_INST_RET_MASK); goto use_result;
continue;
case BC_INST_TRUE: case BC_INST_TRUE:
result.set_integer(1); result.set_integer(1);
force_arg(cs, result, op & BC_INST_RET_MASK); goto use_result;
continue;
case BC_INST_NOT: case BC_INST_NOT:
result.set_integer(!args.back().get_bool()); result.set_integer(!args.back().get_bool());
force_arg(cs, result, op & BC_INST_RET_MASK);
args.pop_back(); args.pop_back();
continue; goto use_result;
case BC_INST_POP: case BC_INST_POP:
args.pop_back(); args.pop_back();
continue; continue;
case BC_INST_ENTER: case BC_INST_ENTER:
code = vm_exec(ts, code, args.emplace_back()); code = vm_exec(ts, code, args.emplace_back());
continue; continue;
case BC_INST_ENTER_RESULT: case BC_INST_ENTER_RESULT:
code = vm_exec(ts, code, result); code = vm_exec(ts, code, result);
continue; continue;
case BC_INST_EXIT: case BC_INST_EXIT:
force_arg(cs, result, op & BC_INST_RET_MASK); goto use_exit;
return code;
case BC_INST_RESULT: case BC_INST_RESULT:
result = std::move(args.back()); result = std::move(args.back());
args.pop_back(); args.pop_back();
force_arg(cs, result, op & BC_INST_RET_MASK); goto use_result;
continue;
case BC_INST_RESULT_ARG: case BC_INST_RESULT_ARG:
force_arg(cs, result, op & BC_INST_RET_MASK);
args.emplace_back(std::move(result)); args.emplace_back(std::move(result));
continue; goto use_top;
case BC_INST_FORCE: case BC_INST_FORCE:
force_arg(cs, args.back(), op & BC_INST_RET_MASK); goto use_top;
continue;
case BC_INST_DUP: { case BC_INST_DUP: {
auto &v = args.back(); auto &v = args.back();
args.emplace_back() = v; args.emplace_back() = v;
force_arg(cs, args.back(), op & BC_INST_RET_MASK); goto use_top;
continue;
} }
case BC_INST_VAL: case BC_INST_VAL:
@ -472,16 +441,14 @@ std::uint32_t *vm_exec(
auto v = std::move(args.back()); auto v = std::move(args.back());
args.pop_back(); args.pop_back();
result = exec_code_with_args(ts, v.get_code()); result = exec_code_with_args(ts, v.get_code());
force_arg(cs, result, op & BC_INST_RET_MASK); goto use_result;
continue;
} }
case BC_INST_DO: { case BC_INST_DO: {
auto v = std::move(args.back()); auto v = std::move(args.back());
args.pop_back(); args.pop_back();
result = v.get_code().call(cs); result = v.get_code().call(cs);
force_arg(cs, result, op & BC_INST_RET_MASK); goto use_result;
continue;
} }
case BC_INST_JUMP: { case BC_INST_JUMP: {
@ -618,17 +585,26 @@ std::uint32_t *vm_exec(
case BC_INST_LOOKUP_U: case BC_INST_LOOKUP_U:
args.back() = cs.lookup_value(args.back().get_string(cs)); args.back() = cs.lookup_value(args.back().get_string(cs));
force_arg(cs, args.back(), op & BC_INST_RET_MASK); goto use_top;
continue;
case BC_INST_LOOKUP: { case BC_INST_LOOKUP: {
alias_stack *ast; ident *id = ts.istate->identmap[op >> 8];
auto &v = args.emplace_back(); if (static_cast<alias *>(id)->is_arg()) {
if (get_lookup_id(ts, op, ast)) { auto &v = args.emplace_back();
v = ast->node->val_s; if (ident_is_used_arg(id, ts)) {
v = ts.get_astack(static_cast<alias *>(id)).node->val_s;
}
goto use_top;
} }
force_arg(cs, args.back(), op & BC_INST_RET_MASK); auto &ast = ts.get_astack(static_cast<alias *>(id));
continue; if (ast.flags & IDENT_FLAG_UNKNOWN) {
throw error_p::make(
*ts.pstate, "unknown alias lookup: %s",
id->name().data()
);
}
args.emplace_back() = ast.node->val_s;
goto use_top;
} }
case BC_INST_CONC: case BC_INST_CONC:
@ -641,16 +617,14 @@ std::uint32_t *vm_exec(
); );
args.resize(args.size() - numconc); args.resize(args.size() - numconc);
args.emplace_back().set_string(buf); args.emplace_back().set_string(buf);
force_arg(cs, args.back(), op & BC_INST_RET_MASK); goto use_top;
continue;
} }
case BC_INST_VAR: case BC_INST_VAR:
args.emplace_back() = static_cast<builtin_var *>( args.emplace_back() = static_cast<builtin_var *>(
ts.istate->identmap[op >> 8] ts.istate->identmap[op >> 8]
)->value(); )->value();
force_arg(cs, args.back(), op & BC_INST_RET_MASK); goto use_top;
continue;
case BC_INST_ALIAS: { case BC_INST_ALIAS: {
auto *a = static_cast<alias *>( auto *a = static_cast<alias *>(
@ -665,6 +639,7 @@ std::uint32_t *vm_exec(
args.pop_back(); args.pop_back();
continue; continue;
} }
case BC_INST_ALIAS_U: { case BC_INST_ALIAS_U: {
auto v = std::move(args.back()); auto v = std::move(args.back());
args.pop_back(); args.pop_back();
@ -683,16 +658,14 @@ std::uint32_t *vm_exec(
if (imp->is_arg()) { if (imp->is_arg()) {
if (!ident_is_used_arg(id, ts)) { if (!ident_is_used_arg(id, ts)) {
args.resize(offset); args.resize(offset);
force_arg(cs, result, op & BC_INST_RET_MASK); goto use_result;
continue;
} }
} }
exec_alias( exec_alias(
ts, imp, &args[0], result, callargs, ts, imp, &args[0], result, callargs, nnargs, offset, 0
nnargs, offset, 0, op
); );
args.resize(nnargs); args.resize(nnargs);
continue; goto use_result;
} }
case BC_INST_CALL_U: { case BC_INST_CALL_U: {
@ -703,9 +676,8 @@ std::uint32_t *vm_exec(
if (idarg.type() != value_type::STRING) { if (idarg.type() != value_type::STRING) {
litval: litval:
result = std::move(idarg); result = std::move(idarg);
force_arg(cs, result, op & BC_INST_RET_MASK);
args.resize(offset - 1); args.resize(offset - 1);
continue; goto use_result;
} }
auto idn = idarg.get_string(cs); auto idn = idarg.get_string(cs);
auto id = cs.get_ident(idn); auto id = cs.get_ident(idn);
@ -714,8 +686,6 @@ noid:
if (!is_valid_name(idn)) { if (!is_valid_name(idn)) {
goto litval; goto litval;
} }
result.force_none();
force_arg(cs, result, op & BC_INST_RET_MASK);
std::string_view ids{idn}; std::string_view ids{idn};
throw error_p::make( throw error_p::make(
cs, "unknown command: %s", ids.data() cs, "unknown command: %s", ids.data()
@ -726,8 +696,7 @@ noid:
default: default:
if (!ident_is_callable(&id->get())) { if (!ident_is_callable(&id->get())) {
args.resize(offset - 1); args.resize(offset - 1);
force_arg(cs, result, op & BC_INST_RET_MASK); goto use_result;
continue;
} }
/* fallthrough */ /* fallthrough */
case ID_COMMAND: { case ID_COMMAND: {
@ -738,9 +707,8 @@ noid:
exec_command( exec_command(
ts, cimp, cimp, &args[offset], result, callargs ts, cimp, cimp, &args[offset], result, callargs
); );
force_arg(cs, result, op & BC_INST_RET_MASK);
args.resize(offset - 1); args.resize(offset - 1);
continue; goto use_result;
} }
case ID_LOCAL: { case ID_LOCAL: {
std::size_t idstsz = ts.idstack.size(); std::size_t idstsz = ts.idstack.size();
@ -779,25 +747,23 @@ noid:
ts, cimp, &id->get(), &args[offset], ts, cimp, &id->get(), &args[offset],
result, callargs result, callargs
); );
force_arg(cs, result, op & BC_INST_RET_MASK);
args.resize(offset - 1); args.resize(offset - 1);
continue; goto use_result;
} }
case ID_ALIAS: { case ID_ALIAS: {
alias *a = static_cast<alias *>(&id->get()); alias *a = static_cast<alias *>(&id->get());
if (a->is_arg() && !ident_is_used_arg(a, ts)) { if (a->is_arg() && !ident_is_used_arg(a, ts)) {
args.resize(offset - 1); args.resize(offset - 1);
force_arg(cs, result, op & BC_INST_RET_MASK); goto use_result;
continue;
} }
if (!exec_alias( if (!exec_alias(
ts, a, &args[0], result, callargs, nnargs, ts, a, &args[0], result, callargs, nnargs,
offset, 1, op, true offset, 1, true
)) { )) {
goto noid; goto noid;
} }
args.resize(nnargs); args.resize(nnargs);
continue; goto use_result;
} }
} }
} }
@ -811,9 +777,8 @@ noid:
id->call(ts, span_type<any_value>{ id->call(ts, span_type<any_value>{
&args[offset], std::size_t(id->arg_count()) &args[offset], std::size_t(id->arg_count())
}, result); }, result);
force_arg(cs, result, op & BC_INST_RET_MASK);
args.resize(offset); args.resize(offset);
continue; goto use_result;
} }
case BC_INST_COM_V: { case BC_INST_COM_V: {
@ -826,11 +791,20 @@ noid:
id->call( id->call(
ts, span_type<any_value>{&args[offset], callargs}, result ts, span_type<any_value>{&args[offset], callargs}, result
); );
force_arg(cs, result, op & BC_INST_RET_MASK);
args.resize(offset); args.resize(offset);
continue; goto use_result;
} }
} }
continue;
use_result:
force_val(cs, result, op);
continue;
use_top:
force_val(cs, args.back(), op);
continue;
use_exit:
force_val(cs, result, op);
break;
} }
return code; return code;
} }

View File

@ -25,7 +25,7 @@ void exec_command(
bool exec_alias( bool exec_alias(
thread_state &ts, alias *a, any_value *args, any_value &result, thread_state &ts, alias *a, any_value *args, any_value &result,
std::size_t callargs, std::size_t &nargs, std::size_t offset, std::size_t callargs, std::size_t &nargs, std::size_t offset,
std::size_t skip, std::uint32_t op, bool ncheck = false std::size_t skip, bool ncheck = false
); );
any_value exec_code_with_args(thread_state &ts, bcode_ref const &body); any_value exec_code_with_args(thread_state &ts, bcode_ref const &body);