67 llvm::raw_string_ostream os(s);
69 for (
auto &d : data) {
70 if (
auto s = std::get_if<std::string>(&d))
71 os <<
'"' << *s <<
'"';
72 else if (
auto u = std::get_if<uint64_t>(&d))
74 else if (
auto i = std::get_if<int64_t>(&d))
76 else if (
auto ap = std::get_if<llvm::APSInt>(&d))
78 else if (
auto valobj = std::get_if<ValueObjectSP>(&d)) {
82 os <<
"object(" << valobj->get()->GetValueAsCString() <<
')';
83 }
else if (
auto type = std::get_if<CompilerType>(&d)) {
84 os <<
'(' << type->GetTypeName(
true) <<
')';
85 }
else if (
auto sel = std::get_if<FormatterBytecode::Selectors>(&d)) {
87 }
else if (
auto *dict =
88 std::get_if<std::shared_ptr<FormatterBytecode::Dictionary>>(
90 os <<
"dict(" << (*dict ? (*dict)->size() : 0) <<
')';
102 auto fmt = data.
Pop<std::string>();
104 llvm::formatv_object_base::parseFormatString(fmt, 0,
false);
106 llvm::raw_string_ostream os(s);
107 unsigned num_args = 0;
108 for (
const auto &r : replacements)
109 if (r.Type == llvm::ReplacementType::Format)
110 num_args = std::max(num_args, r.Index + 1);
112 if (data.size() < num_args)
113 return llvm::createStringError(
"not enough arguments");
115 for (
const auto &r : replacements) {
116 if (r.Type == llvm::ReplacementType::Literal) {
120 using namespace llvm::support::detail;
121 auto arg = data[data.size() - num_args + r.Index];
122 auto format = [&](FormatFunctorRef &&adapter) {
123 llvm::FmtAlign
Align(adapter, r.Where, r.Width, r.Pad);
124 Align.format(os, r.Options);
127 if (
auto s = std::get_if<std::string>(&arg))
128 format(FormatFunctor(s->c_str()));
129 else if (
auto u = std::get_if<uint64_t>(&arg))
130 format(FormatFunctor(u));
131 else if (
auto i = std::get_if<int64_t>(&arg))
132 format(FormatFunctor(i));
133 else if (
auto ap = std::get_if<llvm::APSInt>(&arg))
134 format(FormatFunctor(*ap));
135 else if (
auto valobj = std::get_if<ValueObjectSP>(&arg)) {
137 format(FormatFunctor(
"null object"));
139 format(FormatFunctor(valobj->get()->GetValueAsCString()));
140 }
else if (
auto type = std::get_if<CompilerType>(&arg))
141 format(FormatFunctor(type->GetDisplayTypeName()));
142 else if (
auto sel = std::get_if<FormatterBytecode::Selectors>(&arg))
143 format(FormatFunctor(
toString(*sel)));
144 else if (std::holds_alternative<DictionarySP>(arg))
145 format(FormatFunctor(
"dict"));
148 return llvm::Error::success();
280 return llvm::Error::success();
283 llvm::DataExtractor cur_block(control.back(),
true);
284 llvm::DataExtractor::Cursor
pc(0);
286 while (!control.empty()) {
288 auto activate_block = [&]() {
290 if (control.size() > 1)
291 control[control.size() - 2] = cur_block.getData().drop_front(
pc.tell());
292 cur_block = llvm::DataExtractor(control.back(),
true);
294 pc = llvm::DataExtractor::Cursor(0);
298 auto next_byte = [&]() -> uint8_t {
300 while (
pc.tell() >= cur_block.size() && !control.empty()) {
301 if (control.size() == 1) {
310 return cur_block.getU8(
pc);
315 if (control.empty() || !
pc)
316 return pc.takeError();
319 "[eval {0}] opcode={1}, control={2}, data={3}",
324#define TYPE_CHECK(...) \
325 if (auto error = TypeCheck(data, __VA_ARGS__)) \
328 auto error = [&](llvm::Twine msg) {
329 return llvm::createStringError(msg +
"(opcode=" +
toString(opcode) +
")");
336 data.
Push(data.back());
344 uint64_t idx = data.
Pop<uint64_t>();
345 if (idx >= data.size())
346 return error(
"index out of bounds");
347 data.
Push(data[idx]);
352 data.
Push(data[data.size() - 2]);
375 uint64_t length = cur_block.getULEB128(
pc);
377 return pc.takeError();
378 llvm::StringRef block = cur_block.getBytes(
pc, length);
380 return pc.takeError();
381 control.push_back(block);
385 auto cond = data.
PopAny();
387 if (
auto *ap = std::get_if<llvm::APSInt>(&cond))
388 truthy = !ap->isZero();
389 else if (
auto *u = std::get_if<uint64_t>(&cond))
393 return error(
"expected Integer or UInt");
395 if (!cur_block.size())
396 return error(
"empty control stack");
403 if (cur_block.size() < 2)
404 return error(
"empty control stack");
405 auto cond = data.
PopAny();
407 if (
auto *ap = std::get_if<llvm::APSInt>(&cond))
408 truthy = !ap->isZero();
409 else if (
auto *u = std::get_if<uint64_t>(&cond))
413 return error(
"expected Integer or UInt");
415 control[control.size() - 2] = control.back();
422 return pc.takeError();
426 data.
Push(cur_block.getULEB128(
pc));
429 data.
Push(cur_block.getSLEB128(
pc));
432 data.
Push(cur_block.getSLEB128APSInt(
pc));
434 case op_lit_selector:
440 case op_lit_string: {
441 uint64_t length = cur_block.getULEB128(
pc);
442 llvm::StringRef bytes = cur_block.getBytes(
pc, length);
443 data.
Push(bytes.str());
449 int64_t val = data.
Pop<int64_t>();
450 memcpy(&casted, &val,
sizeof(val));
457 uint64_t val = data.
Pop<uint64_t>();
458 memcpy(&casted, &val,
sizeof(val));
469#define BINOP_IMPL(OP, CHECK_ZERO) \
471 TYPE_CHECK(Any, Any); \
472 auto y = data.PopAny(); \
473 if (std::holds_alternative<uint64_t>(y)) { \
474 if (CHECK_ZERO && !std::get<uint64_t>(y)) \
475 return error(#OP " by zero"); \
477 data.Push((uint64_t)(data.Pop<uint64_t>() OP std::get<uint64_t>(y))); \
478 } else if (std::holds_alternative<int64_t>(y)) { \
479 if (CHECK_ZERO && !std::get<int64_t>(y)) \
480 return error(#OP " by zero"); \
482 data.Push((int64_t)(data.Pop<int64_t>() OP std::get<int64_t>(y))); \
483 } else if (std::holds_alternative<llvm::APSInt>(y)) { \
484 TYPE_CHECK(Integer); \
485 llvm::APSInt rhs = std::get<llvm::APSInt>(y); \
486 llvm::APSInt lhs = data.Pop<llvm::APSInt>(); \
487 if (lhs.isUnsigned() || rhs.isUnsigned()) \
488 return error("unsupported unsigned value"); \
489 unsigned width = std::max(lhs.getBitWidth(), rhs.getBitWidth()); \
490 lhs = lhs.extend(width); \
491 rhs = rhs.extend(width); \
492 if (CHECK_ZERO && rhs.isZero()) \
493 return error(#OP " by zero"); \
494 data.Push(WrapAPSIntResult(lhs OP rhs, width, lhs.isUnsigned())); \
496 return error("unsupported data types"); \
498#define BINOP(OP) BINOP_IMPL(OP, false)
499#define BINOP_CHECKZERO(OP) BINOP_IMPL(OP, true)
504 TYPE_CHECK(Any, Any); \
505 auto y = data.PopAny(); \
506 if (std::holds_alternative<uint64_t>(y)) { \
508 data.Push((uint64_t)(data.Pop<uint64_t>() OP std::get<uint64_t>(y))); \
509 } else if (std::holds_alternative<int64_t>(y)) { \
511 data.Push((int64_t)(data.Pop<int64_t>() OP std::get<int64_t>(y))); \
512 } else if (std::holds_alternative<llvm::APSInt>(y)) { \
513 TYPE_CHECK(Integer); \
514 llvm::APSInt rhs = std::get<llvm::APSInt>(y); \
515 llvm::APSInt lhs = data.Pop<llvm::APSInt>(); \
516 if (lhs.isUnsigned() || rhs.isUnsigned()) \
517 return error("unsupported unsigned value"); \
518 unsigned width = std::max(lhs.getBitWidth(), rhs.getBitWidth()); \
519 lhs = lhs.extend(width); \
520 rhs = rhs.extend(width); \
521 data.Push(WrapAPSIntResult(lhs OP rhs, width, lhs.isUnsigned())); \
523 return error("unsupported data types"); \
532 TYPE_CHECK(Any, Any); \
533 auto y = data.PopAny(); \
534 if (std::holds_alternative<uint64_t>(y)) { \
536 data.Push((uint64_t)(data.Pop<uint64_t>() OP std::get<uint64_t>(y))); \
537 } else if (std::holds_alternative<int64_t>(y)) { \
539 data.Push((int64_t)(data.Pop<int64_t>() OP std::get<int64_t>(y))); \
540 } else if (std::holds_alternative<llvm::APSInt>(y)) { \
541 TYPE_CHECK(Integer); \
542 llvm::APSInt rhs = std::get<llvm::APSInt>(y); \
543 llvm::APSInt lhs = data.Pop<llvm::APSInt>(); \
544 unsigned width = std::max(lhs.getBitWidth(), rhs.getBitWidth()); \
545 llvm::APInt lhs_bits = \
546 static_cast<const llvm::APInt &>(lhs).zext(width); \
547 llvm::APInt rhs_bits = \
548 static_cast<const llvm::APInt &>(rhs).zext(width); \
549 llvm::APInt bits = lhs_bits OP rhs_bits; \
550 data.Push(llvm::APSInt(std::move(bits), false)); \
552 return error("unsupported data types"); \
571#define SHIFTOP(OP, LEFT) \
573 TYPE_CHECK(Any, UInt); \
574 uint64_t y = data.Pop<uint64_t>(); \
576 return error("shift out of bounds"); \
577 if (std::holds_alternative<uint64_t>(data.back())) { \
578 uint64_t x = data.Pop<uint64_t>(); \
580 } else if (std::holds_alternative<int64_t>(data.back())) { \
581 int64_t x = data.Pop<int64_t>(); \
583 return error("left shift of negative value"); \
585 return error("shift out of bounds"); \
587 } else if (std::holds_alternative<llvm::APSInt>(data.back())) { \
588 llvm::APSInt x = data.Pop<llvm::APSInt>(); \
589 if (y > x.getBitWidth()) \
590 return error("shift out of bounds"); \
591 const llvm::APInt &bits = x; \
592 llvm::APInt shifted = \
593 LEFT ? bits.shl((unsigned)y) : bits.lshr((unsigned)y); \
594 data.Push(llvm::APSInt(std::move(shifted), false)); \
596 return error("unsupported data types"); \
615 if (std::holds_alternative<uint64_t>(x))
616 data.
Push(~std::get<uint64_t>(x));
617 else if (
auto *ap = std::get_if<llvm::APSInt>(&x)) {
618 llvm::APInt
bits = ~static_cast<const llvm::APInt &>(*ap);
619 data.
Push(llvm::APSInt(std::move(
bits),
false));
621 return error(
"unsupported data types");
647#define POP_VALOBJ(VALOBJ) \
648 auto VALOBJ = data.Pop<ValueObjectSP>(); \
650 return error("null object");
652 auto sel_error = [&](
const char *msg) {
653 return llvm::createStringErrorV(
"{0} (opcode={1}, selector={2})", msg,
662 const char *summary = valobj->GetSummaryAsCString();
663 data.
Push(summary ? std::string(valobj->GetSummaryAsCString())
667 case sel_get_num_children: {
670 auto result = valobj->GetNumChildren();
672 return result.takeError();
676 case sel_get_child_at_index: {
680 index = data.
Pop<llvm::APSInt>().getLimitedValue(
UINT32_MAX);
683 index = data.
Pop<uint64_t>();
686 data.
Push(valobj->GetChildAtIndex(index));
689 case sel_get_child_with_name: {
691 auto name = data.
Pop<std::string>();
693 data.
Push(valobj->GetChildMemberWithName(name));
696 case sel_get_child_index: {
698 auto name = data.
Pop<std::string>();
700 if (
auto index_or_err = valobj->GetIndexOfChildWithName(name))
703 return index_or_err.takeError();
706 case sel_get_parent: {
709 auto *parent = valobj->GetParent();
717 data.
Push(valobj->GetTypeImpl().GetCompilerType(
false));
720 case sel_get_template_argument_type: {
724 index = data.
Pop<llvm::APSInt>().getLimitedValue();
727 index = data.
Pop<uint64_t>();
731 data.
Push(type.GetTypeTemplateArgument(index,
true));
734 case sel_get_synthetic_value: {
737 data.
Push(valobj->GetSyntheticValue());
740 case sel_get_non_synthetic_value: {
743 data.
Push(valobj->GetNonSyntheticValue());
746 case sel_get_value: {
749 data.
Push(std::string(valobj->GetValueAsCString()));
752 case sel_get_value_as_unsigned: {
756 uint64_t val = valobj->GetValueAsUnsigned(0, &success);
759 return sel_error(
"failed to get value");
762 case sel_get_value_as_signed: {
766 int64_t val = valobj->GetValueAsSigned(0, &success);
769 return sel_error(
"failed to get value");
772 case sel_get_value_as_address: {
776 uint64_t addr = valobj->GetValueAsUnsigned(0, &success);
778 return sel_error(
"failed to get value");
779 if (
auto process_sp = valobj->GetProcessSP())
780 addr = process_sp->FixDataAddress(addr);
788 data.
Push(valobj->Cast(type));
793 auto new_name = data.
Pop<std::string>();
795 data.
Push(valobj->Clone(new_name));
798 case sel_get_pointee_type: {
801 data.
Push(type.GetPointeeType());
804 case sel_get_byte_size: {
808 llvm::expectedToOptional(type.GetByteSize(
nullptr)).value_or(0);
809 data.
Push(llvm::APSInt::get(size));
812 case sel_create_child_at_offset: {
815 auto offset = data.
Pop<llvm::APSInt>().getLimitedValue(
UINT32_MAX);
818 data.
Push(valobj->GetSyntheticChildAtOffset(offset, type,
true, name));
823 auto size = data.
Pop<std::string>().size();
834 return sel_error(
"selector not implemented");
841 data.
Push(std::make_shared<Dictionary>());
845 auto value = data.
PopAny();
846 auto key = data.
Pop<std::string>();
848 if (
auto *nested_sp = std::get_if<DictionarySP>(&value))
849 if (
Reaches(nested_sp->get(), dict_sp.get()))
850 return error(
"dict_set would create a reference cycle");
851 (*dict_sp)[key] = std::move(value);
856 auto key = data.
Pop<std::string>();
858 auto it = dict_sp->find(key);
859 if (it == dict_sp->end())
860 return error(
"key not found in dictionary");
861 data.
Push(it->second);
866 auto key = data.
Pop<std::string>();
868 bool found = dict_sp->find(key) != dict_sp->end();
869 data.
Push(llvm::APSInt::get(found));
873 return error(
"opcode not implemented");
875 return pc.takeError();