various vm cleanups
parent
036362683c
commit
6ffdc7fa91
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
172
src/cs_vm.cc
172
src/cs_vm.cc
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in New Issue