452#if ARK_USE_COMPUTED_GOTOS
453# define TARGET(op) TARGET_##op:
454# define DISPATCH_GOTO() \
455 _Pragma("GCC diagnostic push") \
456 _Pragma("GCC diagnostic ignored \"-Wpedantic\"") goto* opcode_targets[inst];
457 _Pragma(
"GCC diagnostic pop")
458# define GOTO_HALT() goto dispatch_end
460# define TARGET(op) case op:
461# define DISPATCH_GOTO() goto dispatch_opcode
462# define GOTO_HALT() break
468 inst = m_state.inst(context.pp, context.ip); \
469 padding = m_state.inst(context.pp, context.ip + 1); \
470 arg = static_cast<uint16_t>((m_state.inst(context.pp, context.ip + 2) << 8) + \
471 m_state.inst(context.pp, context.ip + 3)); \
477#define UNPACK_ARGS() \
480 secondary_arg = static_cast<uint16_t>((padding << 4) | (arg & 0xf000) >> 12); \
481 primary_arg = arg & 0x0fff; \
484#if ARK_USE_COMPUTED_GOTOS
485# pragma GCC diagnostic push
486# pragma GCC diagnostic ignored "-Wpedantic"
487 constexpr std::array opcode_targets = {
490 &&TARGET_LOAD_SYMBOL,
491 &&TARGET_LOAD_SYMBOL_BY_INDEX,
493 &&TARGET_POP_JUMP_IF_TRUE,
496 &&TARGET_POP_JUMP_IF_FALSE,
500 &&TARGET_PUSH_RETURN_ADDRESS,
505 &&TARGET_MAKE_CLOSURE,
511 &&TARGET_APPEND_IN_PLACE,
512 &&TARGET_CONCAT_IN_PLACE,
514 &&TARGET_POP_LIST_IN_PLACE,
515 &&TARGET_SET_AT_INDEX,
516 &&TARGET_SET_AT_2_INDEX,
518 &&TARGET_SHORTCIRCUIT_AND,
519 &&TARGET_SHORTCIRCUIT_OR,
520 &&TARGET_CREATE_SCOPE,
521 &&TARGET_RESET_SCOPE_JUMP,
523 &&TARGET_GET_CURRENT_PAGE_ADDR,
548 &&TARGET_LOAD_CONST_LOAD_CONST,
549 &&TARGET_LOAD_CONST_STORE,
550 &&TARGET_LOAD_CONST_SET_VAL,
552 &&TARGET_STORE_FROM_INDEX,
553 &&TARGET_SET_VAL_FROM,
554 &&TARGET_SET_VAL_FROM_INDEX,
556 &&TARGET_INCREMENT_BY_INDEX,
557 &&TARGET_INCREMENT_STORE,
559 &&TARGET_DECREMENT_BY_INDEX,
560 &&TARGET_DECREMENT_STORE,
562 &&TARGET_STORE_TAIL_BY_INDEX,
564 &&TARGET_STORE_HEAD_BY_INDEX,
566 &&TARGET_SET_VAL_TAIL,
567 &&TARGET_SET_VAL_TAIL_BY_INDEX,
568 &&TARGET_SET_VAL_HEAD,
569 &&TARGET_SET_VAL_HEAD_BY_INDEX,
570 &&TARGET_CALL_BUILTIN,
571 &&TARGET_CALL_BUILTIN_WITHOUT_RETURN_ADDRESS,
572 &&TARGET_LT_CONST_JUMP_IF_FALSE,
573 &&TARGET_LT_CONST_JUMP_IF_TRUE,
574 &&TARGET_LT_SYM_JUMP_IF_FALSE,
575 &&TARGET_GT_CONST_JUMP_IF_TRUE,
576 &&TARGET_GT_CONST_JUMP_IF_FALSE,
577 &&TARGET_GT_SYM_JUMP_IF_FALSE,
578 &&TARGET_EQ_CONST_JUMP_IF_TRUE,
579 &&TARGET_EQ_SYM_INDEX_JUMP_IF_TRUE,
580 &&TARGET_NEQ_CONST_JUMP_IF_TRUE,
581 &&TARGET_NEQ_SYM_JUMP_IF_FALSE,
582 &&TARGET_CALL_SYMBOL,
583 &&TARGET_CALL_CURRENT_PAGE,
584 &&TARGET_GET_FIELD_FROM_SYMBOL,
585 &&TARGET_GET_FIELD_FROM_SYMBOL_INDEX,
587 &&TARGET_AT_SYM_INDEX_SYM_INDEX,
588 &&TARGET_CHECK_TYPE_OF,
589 &&TARGET_CHECK_TYPE_OF_BY_INDEX,
590 &&TARGET_APPEND_IN_PLACE_SYM,
591 &&TARGET_APPEND_IN_PLACE_SYM_INDEX
594 static_assert(opcode_targets.size() ==
static_cast<std::size_t
>(Instruction::InstructionsCount) &&
"Some instructions are not implemented in the VM");
595# pragma GCC diagnostic pop
603 uint16_t primary_arg = 0;
604 uint16_t secondary_arg = 0;
611#if !ARK_USE_COMPUTED_GOTOS
616#pragma region "Instructions"
643 context.
ip = arg * 4;
662 context.
ip = arg * 4;
668 context.
ip = arg * 4;
696 push(std::move(ip_or_val), context);
699 if (context.
fc <= untilFrameCount)
756 var->usertypeRef().del();
788 push(std::move(l), context);
799 std::vector<Value> args = { *list };
800 for (uint16_t i = 0; i < arg; ++i)
808 const auto size =
static_cast<uint16_t
>(list->
constList().size());
811 obj.
list().reserve(size + arg);
813 for (uint16_t i = 0; i < arg; ++i)
815 push(std::move(obj), context);
826 for (uint16_t i = 0; i < arg; ++i)
836 std::ranges::copy(next->
list(), std::back_inserter(obj.list()));
838 push(std::move(obj), context);
854 for (uint16_t i = 0; i < arg; ++i)
864 std::ranges::copy(next->
list(), std::back_inserter(list->
list()));
881 long idx =
static_cast<long>(number.
number());
882 idx = idx < 0 ? static_cast<long>(list.
list().size()) + idx : idx;
883 if (std::cmp_greater_equal(idx, list.
list().size()) || idx < 0)
886 fmt::format(
"pop index ({}) out of range (list size: {})", idx, list.
list().size()));
888 list.
list().erase(list.
list().begin() + idx);
906 long idx =
static_cast<long>(number.
number());
907 idx = idx < 0 ? static_cast<long>(list->
list().size()) + idx : idx;
908 if (std::cmp_greater_equal(idx, list->
list().size()) || idx < 0)
911 fmt::format(
"pop! index ({}) out of range (list size: {})", idx, list->
list().size()));
913 list->
list().erase(list->
list().begin() + idx);
936 { *list, number, new_value });
939 long idx =
static_cast<long>(number.
number());
940 idx = idx < 0 ? static_cast<long>(size) + idx : idx;
941 if (std::cmp_greater_equal(idx, size) || idx < 0)
944 fmt::format(
"@= index ({}) out of range (indexable size: {})", idx, size));
947 list->
list()[
static_cast<std::size_t
>(idx)] = new_value;
949 list->
stringRef()[
static_cast<std::size_t
>(idx)] = new_value.
string()[0];
970 { *list, x, y, new_value });
972 long idx_y =
static_cast<long>(x.
number());
973 idx_y = idx_y < 0 ? static_cast<long>(list->
list().size()) + idx_y : idx_y;
974 if (std::cmp_greater_equal(idx_y, list->
list().size()) || idx_y < 0)
977 fmt::format(
"@@= index (y: {}) out of range (list size: {})", idx_y, list->
list().size()));
979 if (!list->
list()[
static_cast<std::size_t
>(idx_y)].isIndexable() ||
993 { *list, x, y, new_value });
995 const bool is_list = list->
list()[
static_cast<std::size_t
>(idx_y)].valueType() ==
ValueType::List;
996 const std::size_t size =
998 ? list->
list()[
static_cast<std::size_t
>(idx_y)].list().size()
999 : list->
list()[
static_cast<std::size_t
>(idx_y)].stringRef().size();
1001 long idx_x =
static_cast<long>(y.
number());
1002 idx_x = idx_x < 0 ? static_cast<long>(size) + idx_x : idx_x;
1003 if (std::cmp_greater_equal(idx_x, size) || idx_x < 0)
1006 fmt::format(
"@@= index (x: {}) out of range (inner indexable size: {})", idx_x, size));
1009 list->
list()[
static_cast<std::size_t
>(idx_y)].list()[
static_cast<std::size_t
>(idx_x)] = new_value;
1011 list->
list()[
static_cast<std::size_t
>(idx_y)].stringRef()[
static_cast<std::size_t
>(idx_x)] = new_value.
string()[0];
1025 context.
ip = arg * 4;
1034 context.
ip = arg * 4;
1048 context.
locals.back().reset();
1049 context.
ip = arg * 4;
1055 context.
locals.pop_back();
1068#pragma region "Operators"
1124 throwVMError(ErrorKind::DivisionByZero, fmt::format(
"Can not compute expression (/ {} {})", a->toString(*
this), b->
toString(*
this)));
1293 long idx_y =
static_cast<long>(y->
number());
1294 idx_y = idx_y < 0 ? static_cast<long>(list.
list().size()) + idx_y : idx_y;
1295 if (std::cmp_greater_equal(idx_y, list.
list().size()) || idx_y < 0)
1298 fmt::format(
"@@ index ({}) out of range (list size: {})", idx_y, list.
list().size()));
1300 const bool is_list = list.
list()[
static_cast<std::size_t
>(idx_y)].valueType() ==
ValueType::List;
1301 const std::size_t size =
1303 ? list.
list()[
static_cast<std::size_t
>(idx_y)].list().size()
1304 : list.
list()[
static_cast<std::size_t
>(idx_y)].stringRef().size();
1306 long idx_x =
static_cast<long>(x->
number());
1307 idx_x = idx_x < 0 ? static_cast<long>(size) + idx_x : idx_x;
1308 if (std::cmp_greater_equal(idx_x, size) || idx_x < 0)
1311 fmt::format(
"@@ index (x: {}) out of range (inner indexable size: {})", idx_x, size));
1314 push(list.
list()[
static_cast<std::size_t
>(idx_y)].list()[
static_cast<std::size_t
>(idx_x)], context);
1316 push(
Value(std::string(1, list.
list()[
static_cast<std::size_t
>(idx_y)].stringRef()[
static_cast<std::size_t
>(idx_x)])), context);
1349 { *closure, *field });
1358 auto id =
static_cast<std::uint16_t
>(std::distance(
m_state.
m_symbols.begin(), it));
1373#pragma region "Super Instructions"
1440 { *var,
Value(secondary_arg) });
1461 { *var,
Value(secondary_arg) });
1479 setVal(primary_arg, &val, context);
1485 { *var,
Value(secondary_arg) });
1506 { *var,
Value(secondary_arg) });
1527 { *var,
Value(secondary_arg) });
1545 setVal(primary_arg, &val, context);
1551 { *var,
Value(secondary_arg) });
1562 store(secondary_arg, &tail, context);
1573 store(secondary_arg, &tail, context);
1584 store(secondary_arg, &head, context);
1595 store(secondary_arg, &head, context);
1605 store(secondary_arg, &l, context);
1616 setVal(secondary_arg, &tail, context);
1627 setVal(secondary_arg, &tail, context);
1638 setVal(secondary_arg, &head, context);
1649 setVal(secondary_arg, &head, context);
1679 context.
ip = secondary_arg * 4;
1688 context.
ip = secondary_arg * 4;
1696 if (!(*sym < *
loadSymbol(primary_arg, context)))
1697 context.
ip = secondary_arg * 4;
1707 context.
ip = secondary_arg * 4;
1717 context.
ip = secondary_arg * 4;
1727 context.
ip = secondary_arg * 4;
1736 context.
ip = secondary_arg * 4;
1745 context.
ip = secondary_arg * 4;
1754 context.
ip = secondary_arg * 4;
1762 if (*sym == *
loadSymbol(primary_arg, context))
1763 context.
ip = secondary_arg * 4;
1780 call(context, secondary_arg,
nullptr,
static_cast<PageAddr_t>(context.
pp));
1857#if ARK_USE_COMPUTED_GOTOS
1865 catch (
const Error& e)
1867 if (fail_with_exception)
1869 std::stringstream stream;
1878 catch (
const std::exception& e)
1880 if (fail_with_exception)
1882 std::stringstream stream;
1891 if (fail_with_exception)
1894#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
1897 fmt::println(
"Unknown error");
2024 const std::size_t saved_ip = context.
ip;
2025 const std::size_t saved_pp = context.
pp;
2026 const uint16_t saved_sp = context.
sp;
2027 const std::size_t max_consecutive_traces = 7;
2040 maybe_location->line,
2045 fmt::println(os,
"");
2053 std::string previous_trace;
2054 std::size_t displayed_traces = 0;
2055 std::size_t consecutive_similar_traces = 0;
2057 while (context.
fc != 0)
2060 const auto loc_as_text = maybe_call_loc ? fmt::format(
" ({}:{})",
m_state.
m_filenames[maybe_call_loc->filename_id], maybe_call_loc->line + 1) :
"";
2062 if (context.
pp != 0)
2069 if (func_name + loc_as_text != previous_trace)
2073 "[{:4}] In function `{}'{}",
2074 fmt::styled(context.
fc, colorize ? fmt::fg(fmt::color::cyan) : fmt::text_style()),
2075 fmt::styled(func_name, colorize ? fmt::fg(fmt::color::green) : fmt::text_style()),
2077 previous_trace = func_name + loc_as_text;
2079 consecutive_similar_traces = 0;
2081 else if (consecutive_similar_traces == 0)
2083 fmt::println(os,
" ...");
2084 ++consecutive_similar_traces;
2098 if (displayed_traces > max_consecutive_traces)
2100 fmt::println(os,
" ...");
2105 if (context.
pp == 0)
2108 const auto loc_as_text = maybe_call_loc ? fmt::format(
" ({}:{})",
m_state.
m_filenames[maybe_call_loc->filename_id], maybe_call_loc->line + 1) :
"";
2109 fmt::println(os,
"[{:4}] In global scope{}", fmt::styled(context.
fc, colorize ? fmt::fg(fmt::color::cyan) : fmt::text_style()), loc_as_text);
2113 fmt::println(os,
"\nCurrent scope variables values:");
2114 for (std::size_t i = 0, size = old_scope.
size(); i < size; ++i)
2119 fmt::styled(
m_state.
m_symbols[old_scope.
atPos(i).first], colorize ? fmt::fg(fmt::color::cyan) : fmt::text_style()),
2120 old_scope.
atPos(i).second.toString(*
this));
2126 "At IP: {}, PP: {}, SP: {}",
2128 fmt::styled(saved_ip / 4, colorize ? fmt::fg(fmt::color::cyan) : fmt::text_style()),
2129 fmt::styled(saved_pp, colorize ? fmt::fg(fmt::color::green) : fmt::text_style()),
2130 fmt::styled(saved_sp, colorize ? fmt::fg(fmt::color::yellow) : fmt::text_style()));