mask vm loop always by opcode (fewer switch cases)

master
Daniel Kolesa 2021-05-13 00:43:44 +02:00
parent a5536d6974
commit 523586e3a6
1 changed files with 95 additions and 162 deletions

View File

@ -254,39 +254,27 @@ std::uint32_t *vm_exec(
} }
for (;;) { for (;;) {
std::uint32_t op = *code++; std::uint32_t op = *code++;
switch (op & 0xFF) { switch (op & BC_INST_OP_MASK) {
case BC_INST_START: case BC_INST_START:
case BC_INST_OFFSET: case BC_INST_OFFSET:
continue; continue;
case BC_INST_NULL | BC_RET_NULL: case BC_INST_NULL:
case BC_INST_NULL | BC_RET_STRING:
case BC_INST_NULL | BC_RET_INT:
case BC_INST_NULL | BC_RET_FLOAT:
result.set_none(); result.set_none();
force_arg(cs, result, op & BC_INST_RET_MASK); force_arg(cs, result, op & BC_INST_RET_MASK);
continue; continue;
case BC_INST_FALSE | BC_RET_STRING: case BC_INST_FALSE:
case BC_INST_FALSE | BC_RET_NULL:
case BC_INST_FALSE | BC_RET_INT:
case BC_INST_FALSE | BC_RET_FLOAT:
result.set_integer(0); result.set_integer(0);
force_arg(cs, result, op & BC_INST_RET_MASK); force_arg(cs, result, op & BC_INST_RET_MASK);
continue; continue;
case BC_INST_TRUE | BC_RET_STRING: case BC_INST_TRUE:
case BC_INST_TRUE | BC_RET_NULL:
case BC_INST_TRUE | BC_RET_INT:
case BC_INST_TRUE | BC_RET_FLOAT:
result.set_integer(1); result.set_integer(1);
force_arg(cs, result, op & BC_INST_RET_MASK); force_arg(cs, result, op & BC_INST_RET_MASK);
continue; continue;
case BC_INST_NOT | BC_RET_STRING: case BC_INST_NOT:
case BC_INST_NOT | BC_RET_NULL:
case BC_INST_NOT | BC_RET_INT:
case BC_INST_NOT | BC_RET_FLOAT:
result.set_integer(!args.back().get_bool()); result.set_integer(!args.back().get_bool());
force_arg(cs, result, op & BC_INST_RET_MASK); force_arg(cs, result, op & BC_INST_RET_MASK);
args.pop_back(); args.pop_back();
@ -302,40 +290,26 @@ std::uint32_t *vm_exec(
code = vm_exec(ts, code, result); code = vm_exec(ts, code, result);
continue; continue;
case BC_INST_EXIT | BC_RET_NULL: case BC_INST_EXIT:
case BC_INST_EXIT | BC_RET_STRING:
case BC_INST_EXIT | BC_RET_INT:
case BC_INST_EXIT | BC_RET_FLOAT:
force_arg(cs, result, op & BC_INST_RET_MASK); force_arg(cs, result, op & BC_INST_RET_MASK);
return code; return code;
case BC_INST_RESULT | BC_RET_NULL: case BC_INST_RESULT:
case BC_INST_RESULT | BC_RET_STRING:
case BC_INST_RESULT | BC_RET_INT:
case BC_INST_RESULT | BC_RET_FLOAT:
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); force_arg(cs, result, op & BC_INST_RET_MASK);
continue; continue;
case BC_INST_RESULT_ARG | BC_RET_NULL: case BC_INST_RESULT_ARG:
case BC_INST_RESULT_ARG | BC_RET_STRING:
case BC_INST_RESULT_ARG | BC_RET_INT:
case BC_INST_RESULT_ARG | BC_RET_FLOAT:
force_arg(cs, result, op & BC_INST_RET_MASK); force_arg(cs, result, op & BC_INST_RET_MASK);
args.emplace_back(std::move(result)); args.emplace_back(std::move(result));
continue; continue;
case BC_INST_FORCE | BC_RET_STRING: case BC_INST_FORCE:
case BC_INST_FORCE | BC_RET_INT:
case BC_INST_FORCE | BC_RET_FLOAT:
force_arg(cs, args.back(), op & BC_INST_RET_MASK); force_arg(cs, args.back(), op & BC_INST_RET_MASK);
continue; continue;
case BC_INST_DUP | BC_RET_NULL: case BC_INST_DUP: {
case BC_INST_DUP | BC_RET_INT:
case BC_INST_DUP | BC_RET_FLOAT:
case BC_INST_DUP | BC_RET_STRING: {
auto &v = args.back(); auto &v = args.back();
auto &nv = args.emplace_back(); auto &nv = args.emplace_back();
nv = v; nv = v;
@ -343,49 +317,60 @@ std::uint32_t *vm_exec(
continue; continue;
} }
case BC_INST_VAL | BC_RET_STRING: { case BC_INST_VAL:
std::uint32_t len = op >> 8; switch (op & BC_INST_RET_MASK) {
args.emplace_back().set_string(std::string_view{ case BC_RET_STRING: {
reinterpret_cast<char const *>(code), len std::uint32_t len = op >> 8;
}, cs); args.emplace_back().set_string(std::string_view{
code += len / sizeof(std::uint32_t) + 1; reinterpret_cast<char const *>(code), len
continue; }, cs);
} code += len / sizeof(std::uint32_t) + 1;
case BC_INST_VAL_INT | BC_RET_STRING: { continue;
char s[4] = { }
char((op >> 8) & 0xFF), case BC_RET_INT:
char((op >> 16) & 0xFF), args.emplace_back().set_integer(
char((op >> 24) & 0xFF), '\0' *reinterpret_cast<integer_type const *>(code)
}; );
/* gotta cast or r.size() == potentially 3 */ code += bc_store_size<integer_type>;
args.emplace_back().set_string( continue;
static_cast<char const *>(s), cs case BC_RET_FLOAT:
); args.emplace_back().set_float(
continue; *reinterpret_cast<float_type const *>(code)
} );
case BC_INST_VAL | BC_RET_NULL: code += bc_store_size<float_type>;
case BC_INST_VAL_INT | BC_RET_NULL: continue;
default:
break;
}
args.emplace_back().set_none(); args.emplace_back().set_none();
continue; continue;
case BC_INST_VAL | BC_RET_INT:
args.emplace_back().set_integer( case BC_INST_VAL_INT:
*reinterpret_cast<integer_type const *>(code) switch (op & BC_INST_RET_MASK) {
); case BC_RET_STRING: {
code += bc_store_size<integer_type>; char s[4] = {
continue; char((op >> 8) & 0xFF),
case BC_INST_VAL_INT | BC_RET_INT: char((op >> 16) & 0xFF),
args.emplace_back().set_integer(integer_type(op) >> 8); char((op >> 24) & 0xFF), '\0'
continue; };
case BC_INST_VAL | BC_RET_FLOAT: /* gotta cast or r.size() == potentially 3 */
args.emplace_back().set_float( args.emplace_back().set_string(
*reinterpret_cast<float_type const *>(code) static_cast<char const *>(s), cs
); );
code += bc_store_size<float_type>; continue;
continue; }
case BC_INST_VAL_INT | BC_RET_FLOAT: case BC_RET_INT:
args.emplace_back().set_float( args.emplace_back().set_integer(integer_type(op) >> 8);
float_type(integer_type(op) >> 8) continue;
); case BC_RET_FLOAT:
args.emplace_back().set_float(
float_type(integer_type(op) >> 8)
);
continue;
default:
break;
}
args.emplace_back().set_none();
continue; continue;
case BC_INST_LOCAL: { case BC_INST_LOCAL: {
@ -414,10 +399,7 @@ std::uint32_t *vm_exec(
return code; return code;
} }
case BC_INST_DO_ARGS | BC_RET_NULL: case BC_INST_DO_ARGS:
case BC_INST_DO_ARGS | BC_RET_STRING:
case BC_INST_DO_ARGS | BC_RET_INT:
case BC_INST_DO_ARGS | BC_RET_FLOAT:
call_with_args(ts, [&]() { call_with_args(ts, [&]() {
auto v = std::move(args.back()); auto v = std::move(args.back());
args.pop_back(); args.pop_back();
@ -425,11 +407,8 @@ std::uint32_t *vm_exec(
force_arg(cs, result, op & BC_INST_RET_MASK); force_arg(cs, result, op & BC_INST_RET_MASK);
}); });
continue; continue;
/* fallthrough */
case BC_INST_DO | BC_RET_NULL: case BC_INST_DO: {
case BC_INST_DO | BC_RET_STRING:
case BC_INST_DO | BC_RET_INT:
case BC_INST_DO | BC_RET_FLOAT: {
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);
@ -442,23 +421,18 @@ std::uint32_t *vm_exec(
code += len; code += len;
continue; continue;
} }
case BC_INST_JUMP_B | BC_INST_FLAG_TRUE: {
case BC_INST_JUMP_B: {
std::uint32_t len = op >> 8; std::uint32_t len = op >> 8;
if (args.back().get_bool()) { /* BC_INST_FLAG_TRUE/FALSE */
if (args.back().get_bool() == !!(op & BC_INST_RET_MASK)) {
code += len; code += len;
} }
args.pop_back(); args.pop_back();
continue; continue;
} }
case BC_INST_JUMP_B | BC_INST_FLAG_FALSE: {
std::uint32_t len = op >> 8; case BC_INST_JUMP_RESULT: {
if (!args.back().get_bool()) {
code += len;
}
args.pop_back();
continue;
}
case BC_INST_JUMP_RESULT | BC_INST_FLAG_TRUE: {
std::uint32_t len = op >> 8; std::uint32_t len = op >> 8;
auto v = std::move(args.back()); auto v = std::move(args.back());
args.pop_back(); args.pop_back();
@ -467,37 +441,26 @@ std::uint32_t *vm_exec(
} else { } else {
result = std::move(v); result = std::move(v);
} }
if (result.get_bool()) { /* BC_INST_FLAG_TRUE/FALSE */
if (result.get_bool() == !!(op & BC_INST_RET_MASK)) {
code += len; code += len;
} }
continue; continue;
} }
case BC_INST_JUMP_RESULT | BC_INST_FLAG_FALSE: {
std::uint32_t len = op >> 8; case BC_INST_BREAK:
auto v = std::move(args.back());
args.pop_back();
if (v.type() == value_type::CODE) {
result = v.get_code().call(cs);
} else {
result = std::move(v);
}
if (!result.get_bool()) {
code += len;
}
continue;
}
case BC_INST_BREAK | BC_INST_FLAG_FALSE:
if (ts.loop_level) { if (ts.loop_level) {
throw break_exception(); if (op & BC_INST_RET_MASK) {
throw continue_exception{};
} else {
throw break_exception{};
}
} else { } else {
throw error{cs, "no loop to break"}; if (op & BC_INST_RET_MASK) {
} throw error{cs, "no loop to continue"};
break; } else {
case BC_INST_BREAK | BC_INST_FLAG_TRUE: throw error{cs, "no loop to break"};
if (ts.loop_level) { }
throw continue_exception();
} else {
throw error{cs, "no loop to continue"};
} }
break; break;
@ -510,10 +473,7 @@ std::uint32_t *vm_exec(
continue; continue;
} }
case BC_INST_EMPTY | BC_RET_NULL: case BC_INST_EMPTY:
case BC_INST_EMPTY | BC_RET_STRING:
case BC_INST_EMPTY | BC_RET_INT:
case BC_INST_EMPTY | BC_RET_FLOAT:
args.emplace_back().set_code(bcode_p::make_ref( args.emplace_back().set_code(bcode_p::make_ref(
bcode_get_empty(ts.istate->empty, op & BC_INST_RET_MASK) bcode_get_empty(ts.istate->empty, op & BC_INST_RET_MASK)
)); ));
@ -588,18 +548,12 @@ std::uint32_t *vm_exec(
continue; continue;
} }
case BC_INST_LOOKUP_U | BC_RET_STRING: case BC_INST_LOOKUP_U:
case BC_INST_LOOKUP_U | BC_RET_INT:
case BC_INST_LOOKUP_U | BC_RET_FLOAT:
case BC_INST_LOOKUP_U | BC_RET_NULL:
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); force_arg(cs, args.back(), op & BC_INST_RET_MASK);
continue; continue;
case BC_INST_LOOKUP | BC_RET_STRING: case BC_INST_LOOKUP: {
case BC_INST_LOOKUP | BC_RET_INT:
case BC_INST_LOOKUP | BC_RET_FLOAT:
case BC_INST_LOOKUP | BC_RET_NULL: {
alias_stack *ast; alias_stack *ast;
auto &v = args.emplace_back(); auto &v = args.emplace_back();
if (get_lookup_id(ts, op, ast)) { if (get_lookup_id(ts, op, ast)) {
@ -609,14 +563,8 @@ std::uint32_t *vm_exec(
continue; continue;
} }
case BC_INST_CONC | BC_RET_NULL: case BC_INST_CONC:
case BC_INST_CONC | BC_RET_STRING: case BC_INST_CONC_W: {
case BC_INST_CONC | BC_RET_FLOAT:
case BC_INST_CONC | BC_RET_INT:
case BC_INST_CONC_W | BC_RET_NULL:
case BC_INST_CONC_W | BC_RET_STRING:
case BC_INST_CONC_W | BC_RET_FLOAT:
case BC_INST_CONC_W | BC_RET_INT: {
std::size_t numconc = op >> 8; std::size_t numconc = op >> 8;
auto buf = concat_values( auto buf = concat_values(
cs, span_type<any_value>{ cs, span_type<any_value>{
@ -629,10 +577,7 @@ std::uint32_t *vm_exec(
continue; continue;
} }
case BC_INST_VAR | BC_RET_NULL: case BC_INST_VAR:
case BC_INST_VAR | BC_RET_INT:
case BC_INST_VAR | BC_RET_FLOAT:
case BC_INST_VAR | BC_RET_STRING:
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();
@ -660,10 +605,7 @@ std::uint32_t *vm_exec(
continue; continue;
} }
case BC_INST_CALL | BC_RET_NULL: case BC_INST_CALL: {
case BC_INST_CALL | BC_RET_STRING:
case BC_INST_CALL | BC_RET_FLOAT:
case BC_INST_CALL | BC_RET_INT: {
result.force_none(); result.force_none();
ident *id = ts.istate->identmap[op >> 8]; ident *id = ts.istate->identmap[op >> 8];
std::size_t callargs = *code++; std::size_t callargs = *code++;
@ -685,10 +627,7 @@ std::uint32_t *vm_exec(
continue; continue;
} }
case BC_INST_CALL_U | BC_RET_NULL: case BC_INST_CALL_U: {
case BC_INST_CALL_U | BC_RET_STRING:
case BC_INST_CALL_U | BC_RET_FLOAT:
case BC_INST_CALL_U | BC_RET_INT: {
std::size_t callargs = op >> 8; std::size_t callargs = op >> 8;
std::size_t nnargs = args.size(); std::size_t nnargs = args.size();
std::size_t offset = nnargs - callargs; std::size_t offset = nnargs - callargs;
@ -795,10 +734,7 @@ noid:
} }
} }
case BC_INST_COM | BC_RET_NULL: case BC_INST_COM: {
case BC_INST_COM | BC_RET_STRING:
case BC_INST_COM | BC_RET_FLOAT:
case BC_INST_COM | BC_RET_INT: {
command_impl *id = static_cast<command_impl *>( command_impl *id = static_cast<command_impl *>(
ts.istate->identmap[op >> 8] ts.istate->identmap[op >> 8]
); );
@ -812,10 +748,7 @@ noid:
continue; continue;
} }
case BC_INST_COM_V | BC_RET_NULL: case BC_INST_COM_V: {
case BC_INST_COM_V | BC_RET_STRING:
case BC_INST_COM_V | BC_RET_FLOAT:
case BC_INST_COM_V | BC_RET_INT: {
command_impl *id = static_cast<command_impl *>( command_impl *id = static_cast<command_impl *>(
ts.istate->identmap[op >> 8] ts.istate->identmap[op >> 8]
); );