60 llvm::raw_string_ostream os(s);
62 for (
auto &d : data) {
63 if (
auto s = std::get_if<std::string>(&d))
64 os <<
'"' << *s <<
'"';
65 else if (
auto u = std::get_if<uint64_t>(&d))
67 else if (
auto i = std::get_if<int64_t>(&d))
69 else if (
auto valobj = std::get_if<ValueObjectSP>(&d)) {
73 os <<
"object(" << valobj->get()->GetValueAsCString() <<
')';
74 }
else if (
auto type = std::get_if<CompilerType>(&d)) {
75 os <<
'(' << type->GetTypeName(
true) <<
')';
76 }
else if (
auto sel = std::get_if<FormatterBytecode::Selectors>(&d)) {
89 auto fmt = data.
Pop<std::string>();
91 llvm::formatv_object_base::parseFormatString(fmt, 0,
false);
93 llvm::raw_string_ostream os(s);
94 unsigned num_args = 0;
95 for (
const auto &r : replacements)
96 if (r.Type == llvm::ReplacementType::Format)
97 num_args = std::max(num_args, r.Index + 1);
99 if (data.size() < num_args)
100 return llvm::createStringError(
"not enough arguments");
102 for (
const auto &r : replacements) {
103 if (r.Type == llvm::ReplacementType::Literal) {
107 using namespace llvm::support::detail;
108 auto arg = data[data.size() - num_args + r.Index];
109 auto format = [&](format_adapter &&adapter) {
110 llvm::FmtAlign
Align(adapter, r.Where, r.Width, r.Pad);
111 Align.format(os, r.Options);
114 if (
auto s = std::get_if<std::string>(&arg))
115 format(build_format_adapter(s->c_str()));
116 else if (
auto u = std::get_if<uint64_t>(&arg))
117 format(build_format_adapter(u));
118 else if (
auto i = std::get_if<int64_t>(&arg))
119 format(build_format_adapter(i));
120 else if (
auto valobj = std::get_if<ValueObjectSP>(&arg)) {
122 format(build_format_adapter(
"null object"));
124 format(build_format_adapter(valobj->get()->GetValueAsCString()));
125 }
else if (
auto type = std::get_if<CompilerType>(&arg))
126 format(build_format_adapter(type->GetDisplayTypeName()));
127 else if (
auto sel = std::get_if<FormatterBytecode::Selectors>(&arg))
128 format(build_format_adapter(
toString(*sel)));
131 return llvm::Error::success();
134static llvm::Error
TypeCheck(llvm::ArrayRef<DataStackElement> data,
137 return llvm::createStringError(
"not enough elements on data stack");
139 auto &elem = data.back();
144 if (!std::holds_alternative<std::string>(elem))
145 return llvm::createStringError(
"expected String");
148 if (!std::holds_alternative<uint64_t>(elem))
149 return llvm::createStringError(
"expected UInt");
152 if (!std::holds_alternative<int64_t>(elem))
153 return llvm::createStringError(
"expected Int");
156 if (!std::holds_alternative<ValueObjectSP>(elem))
157 return llvm::createStringError(
"expected Object");
160 if (!std::holds_alternative<CompilerType>(elem))
161 return llvm::createStringError(
"expected Type");
164 if (!std::holds_alternative<Selectors>(elem))
165 return llvm::createStringError(
"expected Selector");
168 return llvm::Error::success();
187 return llvm::Error::success();
190 llvm::DataExtractor cur_block(control.back(),
true, 64);
191 llvm::DataExtractor::Cursor
pc(0);
193 while (!control.empty()) {
195 auto activate_block = [&]() {
197 if (control.size() > 1)
198 control[control.size() - 2] = cur_block.getData().drop_front(
pc.tell());
199 cur_block = llvm::DataExtractor(control.back(),
true, 64);
201 pc = llvm::DataExtractor::Cursor(0);
205 auto next_byte = [&]() -> uint8_t {
207 while (
pc.tell() >= cur_block.size() && !control.empty()) {
208 if (control.size() == 1) {
217 return cur_block.getU8(
pc);
222 if (control.empty() || !
pc)
223 return pc.takeError();
226 "[eval {0}] opcode={1}, control={2}, data={3}",
231#define TYPE_CHECK(...) \
232 if (auto error = TypeCheck(data, __VA_ARGS__)) \
235 auto error = [&](llvm::Twine msg) {
236 return llvm::createStringError(msg +
"(opcode=" +
toString(opcode) +
")");
243 data.
Push(data.back());
251 uint64_t idx = data.
Pop<uint64_t>();
252 if (idx >= data.size())
253 return error(
"index out of bounds");
254 data.
Push(data[idx]);
259 data.
Push(data[data.size() - 2]);
282 uint64_t length = cur_block.getULEB128(
pc);
284 return pc.takeError();
285 llvm::StringRef block = cur_block.getBytes(
pc, length);
287 return pc.takeError();
288 control.push_back(block);
293 if (data.
Pop<uint64_t>() != 0) {
294 if (!cur_block.size())
295 return error(
"empty control stack");
302 if (cur_block.size() < 2)
303 return error(
"empty control stack");
304 if (data.
Pop<uint64_t>() == 0)
305 control[control.size() - 2] = control.back();
311 return pc.takeError();
315 data.
Push(cur_block.getULEB128(
pc));
318 data.
Push(cur_block.getSLEB128(
pc));
320 case op_lit_selector:
323 case op_lit_string: {
324 uint64_t length = cur_block.getULEB128(
pc);
325 llvm::StringRef bytes = cur_block.getBytes(
pc, length);
326 data.
Push(bytes.str());
332 int64_t val = data.
Pop<int64_t>();
333 memcpy(&casted, &val,
sizeof(val));
340 uint64_t val = data.
Pop<uint64_t>();
341 memcpy(&casted, &val,
sizeof(val));
352#define BINOP_IMPL(OP, CHECK_ZERO) \
354 TYPE_CHECK(Any, Any); \
355 auto y = data.PopAny(); \
356 if (std::holds_alternative<uint64_t>(y)) { \
357 if (CHECK_ZERO && !std::get<uint64_t>(y)) \
358 return error(#OP " by zero"); \
360 data.Push((uint64_t)(data.Pop<uint64_t>() OP std::get<uint64_t>(y))); \
361 } else if (std::holds_alternative<int64_t>(y)) { \
362 if (CHECK_ZERO && !std::get<int64_t>(y)) \
363 return error(#OP " by zero"); \
365 data.Push((int64_t)(data.Pop<int64_t>() OP std::get<int64_t>(y))); \
367 return error("unsupported data types"); \
369#define BINOP(OP) BINOP_IMPL(OP, false)
370#define BINOP_CHECKZERO(OP) BINOP_IMPL(OP, true)
387#define SHIFTOP(OP, LEFT) \
389 TYPE_CHECK(Any, UInt); \
390 uint64_t y = data.Pop<uint64_t>(); \
392 return error("shift out of bounds"); \
393 if (std::holds_alternative<uint64_t>(data.back())) { \
394 uint64_t x = data.Pop<uint64_t>(); \
396 } else if (std::holds_alternative<int64_t>(data.back())) { \
397 int64_t x = data.Pop<int64_t>(); \
399 return error("left shift of negative value"); \
401 return error("shift out of bounds"); \
404 return error("unsupported data types"); \
422 data.
Push(~data.
Pop<uint64_t>());
447#define POP_VALOBJ(VALOBJ) \
448 auto VALOBJ = data.Pop<ValueObjectSP>(); \
450 return error("null object");
452 auto sel_error = [&](
const char *msg) {
453 return llvm::createStringError(
"{0} (opcode={1}, selector={2})", msg,
462 const char *summary = valobj->GetSummaryAsCString();
463 data.
Push(summary ? std::string(valobj->GetSummaryAsCString())
467 case sel_get_num_children: {
470 auto result = valobj->GetNumChildren();
472 return result.takeError();
473 data.
Push((uint64_t)*result);
476 case sel_get_child_at_index: {
478 auto index = data.
Pop<uint64_t>();
480 data.
Push(valobj->GetChildAtIndex(index));
483 case sel_get_child_with_name: {
485 auto name = data.
Pop<std::string>();
487 data.
Push(valobj->GetChildMemberWithName(name));
490 case sel_get_child_index: {
492 auto name = data.
Pop<std::string>();
494 if (
auto index_or_err = valobj->GetIndexOfChildWithName(name))
495 data.
Push((uint64_t)*index_or_err);
497 return index_or_err.takeError();
504 data.
Push(valobj->GetTypeImpl().GetCompilerType(
false));
507 case sel_get_template_argument_type: {
509 auto index = data.
Pop<uint64_t>();
512 data.
Push(type.GetTypeTemplateArgument(index,
true));
515 case sel_get_synthetic_value: {
518 data.
Push(valobj->GetSyntheticValue());
521 case sel_get_non_synthetic_value: {
524 data.
Push(valobj->GetNonSyntheticValue());
527 case sel_get_value: {
530 data.
Push(std::string(valobj->GetValueAsCString()));
533 case sel_get_value_as_unsigned: {
537 uint64_t val = valobj->GetValueAsUnsigned(0, &success);
540 return sel_error(
"failed to get value");
543 case sel_get_value_as_signed: {
547 int64_t val = valobj->GetValueAsSigned(0, &success);
550 return sel_error(
"failed to get value");
553 case sel_get_value_as_address: {
557 uint64_t addr = valobj->GetValueAsUnsigned(0, &success);
559 return sel_error(
"failed to get value");
560 if (
auto process_sp = valobj->GetProcessSP())
561 addr = process_sp->FixDataAddress(addr);
569 data.
Push(valobj->Cast(type));
574 data.
Push((uint64_t)data.
Pop<std::string>().size());
584 return sel_error(
"selector not implemented");
589 return error(
"opcode not implemented");
591 return pc.takeError();