Skip to content

Commit dc8cc29

Browse files
authored
Implement stack trace API (#70)
1 parent 96d346c commit dc8cc29

File tree

6 files changed

+202
-4
lines changed

6 files changed

+202
-4
lines changed

example/trap.c

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,16 @@ own wasm_trap_t* fail_callback(
2020
}
2121

2222

23+
void print_frame(wasm_frame_t* frame) {
24+
printf("> %p @ 0x%zx = %"PRIu32".0x%zx\n",
25+
wasm_frame_instance(frame),
26+
wasm_frame_module_offset(frame),
27+
wasm_frame_func_index(frame),
28+
wasm_frame_func_offset(frame)
29+
);
30+
}
31+
32+
2333
int main(int argc, const char* argv[]) {
2434
// Initialize.
2535
printf("Initializing...\n");
@@ -104,6 +114,27 @@ int main(int argc, const char* argv[]) {
104114
wasm_trap_message(trap, &message);
105115
printf("> %s\n", message.data);
106116

117+
printf("Printing origin...\n");
118+
own wasm_frame_t* frame = wasm_trap_origin(trap);
119+
if (frame) {
120+
print_frame(frame);
121+
wasm_frame_delete(frame);
122+
} else {
123+
printf("> Empty origin.\n");
124+
}
125+
126+
printf("Printing trace...\n");
127+
own wasm_frame_vec_t trace;
128+
wasm_trap_trace(trap, &trace);
129+
if (trace.size > 0) {
130+
for (size_t i = 0; i < trace.size; ++i) {
131+
print_frame(trace.data[i]);
132+
}
133+
} else {
134+
printf("> Empty trace.\n");
135+
}
136+
137+
wasm_frame_vec_delete(&trace);
107138
wasm_trap_delete(trap);
108139
wasm_name_delete(&message);
109140
}

example/trap.cc

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,14 @@ auto fail_callback(
1717
}
1818

1919

20+
void print_frame(const wasm::Frame* frame) {
21+
std::cout << "> " << frame->instance();
22+
std::cout << " @ 0x" << std::hex << frame->module_offset();
23+
std::cout << " = " << frame->func_index();
24+
std::cout << ".0x" << std::hex << frame->func_offset() << std::endl;
25+
}
26+
27+
2028
void run() {
2129
// Initialize.
2230
std::cout << "Initializing..." << std::endl;
@@ -85,6 +93,24 @@ void run() {
8593

8694
std::cout << "Printing message..." << std::endl;
8795
std::cout << "> " << trap->message().get() << std::endl;
96+
97+
std::cout << "Printing origin..." << std::endl;
98+
auto frame = trap->origin();
99+
if (frame) {
100+
print_frame(frame.get());
101+
} else {
102+
std::cout << "> Empty origin." << std::endl;
103+
}
104+
105+
std::cout << "Printing trace..." << std::endl;
106+
auto trace = trap->trace();
107+
if (trace.size() > 0) {
108+
for (size_t i = 0; i < trace.size(); ++i) {
109+
print_frame(trace[i].get());
110+
}
111+
} else {
112+
std::cout << "> Empty trace." << std::endl;
113+
}
88114
}
89115

90116
// Shut down.

include/wasm.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,18 @@ WASM_DECLARE_VEC(val, )
345345
WASM_DECLARE_REF_BASE(ref)
346346

347347

348+
// Frames
349+
350+
WASM_DECLARE_OWN(frame)
351+
WASM_DECLARE_VEC(frame, *)
352+
own wasm_frame_t* wasm_frame_copy(const wasm_frame_t*);
353+
354+
struct wasm_instance_t* wasm_frame_instance(const wasm_frame_t*);
355+
uint32_t wasm_frame_func_index(const wasm_frame_t*);
356+
size_t wasm_frame_func_offset(const wasm_frame_t*);
357+
size_t wasm_frame_module_offset(const wasm_frame_t*);
358+
359+
348360
// Traps
349361

350362
typedef wasm_name_t wasm_message_t; // null terminated
@@ -354,6 +366,8 @@ WASM_DECLARE_REF(trap)
354366
own wasm_trap_t* wasm_trap_new(wasm_store_t* store, const wasm_message_t*);
355367

356368
void wasm_trap_message(const wasm_trap_t*, own wasm_message_t* out);
369+
own wasm_frame_t* wasm_trap_origin(const wasm_trap_t*);
370+
void wasm_trap_trace(const wasm_trap_t*, own wasm_frame_vec_t* out);
357371

358372

359373
// Foreign Objects

include/wasm.hh

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -584,6 +584,22 @@ template<> inline auto Val::get<uint64_t>() const -> uint64_t {
584584

585585
using Message = vec<byte_t>; // null terminated
586586

587+
class Instance;
588+
589+
class Frame {
590+
public:
591+
Frame() = delete;
592+
~Frame();
593+
void operator delete(void*);
594+
595+
auto copy() const -> own<Frame*>;
596+
597+
auto instance() const -> Instance*;
598+
auto func_index() const -> uint32_t;
599+
auto func_offset() const -> size_t;
600+
auto module_offset() const -> size_t;
601+
};
602+
587603
class Trap : public Ref {
588604
public:
589605
Trap() = delete;
@@ -593,6 +609,8 @@ public:
593609
auto copy() const -> own<Trap*>;
594610

595611
auto message() const -> Message;
612+
auto origin() const -> own<Frame*>; // may be null
613+
auto trace() const -> vec<Frame*>; // may be empty, origin first
596614
};
597615

598616

src/wasm-c.cc

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -668,6 +668,31 @@ void wasm_val_copy(wasm_val_t* out, const wasm_val_t* v) {
668668
///////////////////////////////////////////////////////////////////////////////
669669
// Runtime Objects
670670

671+
// Frames
672+
673+
WASM_DEFINE_OWN(frame, Frame)
674+
WASM_DEFINE_VEC(frame, Frame, *)
675+
676+
wasm_frame_t* wasm_frame_copy(const wasm_frame_t* frame) {
677+
return release(frame->copy());
678+
}
679+
680+
wasm_instance_t* wasm_frame_instance(const wasm_frame_t* frame);
681+
// Defined below along with wasm_instance_t.
682+
683+
uint32_t wasm_frame_func_index(const wasm_frame_t* frame) {
684+
return reveal(frame)->func_index();
685+
}
686+
687+
size_t wasm_frame_func_offset(const wasm_frame_t* frame) {
688+
return reveal(frame)->func_offset();
689+
}
690+
691+
size_t wasm_frame_module_offset(const wasm_frame_t* frame) {
692+
return reveal(frame)->module_offset();
693+
}
694+
695+
671696
// Traps
672697

673698
WASM_DEFINE_REF(trap, Trap)
@@ -681,6 +706,14 @@ void wasm_trap_message(const wasm_trap_t* trap, wasm_message_t* out) {
681706
*out = release(reveal(trap)->message());
682707
}
683708

709+
wasm_frame_t* wasm_trap_origin(const wasm_trap_t* trap) {
710+
return release(reveal(trap)->origin());
711+
}
712+
713+
void wasm_trap_trace(const wasm_trap_t* trap, wasm_frame_vec_t* out) {
714+
*out = release(reveal(trap)->trace());
715+
}
716+
684717

685718
// Foreign Objects
686719

@@ -982,4 +1015,9 @@ void wasm_instance_exports(
9821015
*out = release(instance->exports());
9831016
}
9841017

1018+
1019+
wasm_instance_t* wasm_frame_instance(const wasm_frame_t* frame) {
1020+
return hide(reveal(frame)->instance());
1021+
}
1022+
9851023
} // extern "C"

src/wasm-v8.cc

Lines changed: 75 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ namespace v8 {
2323
extern bool FLAG_experimental_wasm_mv;
2424
extern bool FLAG_experimental_wasm_anyref;
2525
extern bool FLAG_experimental_wasm_bulk_memory;
26+
extern bool FLAG_experimental_wasm_return_call;
2627
}
2728
}
2829

@@ -68,7 +69,7 @@ auto seal(const typename implement <C>::type* x) -> const C* {
6869

6970
struct Stats {
7071
enum category_t {
71-
BYTE, CONFIG, ENGINE, STORE,
72+
BYTE, CONFIG, ENGINE, STORE, FRAME,
7273
VALTYPE, FUNCTYPE, GLOBALTYPE, TABLETYPE, MEMORYTYPE,
7374
EXTERNTYPE, IMPORTTYPE, EXPORTTYPE,
7475
VAL, REF, TRAP,
@@ -176,7 +177,7 @@ struct Stats {
176177

177178
#ifdef DEBUG
178179
const char* Stats::name[STRONG_COUNT] = {
179-
"byte_t", "Config", "Engine", "Store",
180+
"byte_t", "Config", "Engine", "Store", "Frame",
180181
"ValType", "FuncType", "GlobalType", "TableType", "MemoryType",
181182
"ExternType", "ImportType", "ExportType",
182183
"Val", "Ref", "Trap",
@@ -210,6 +211,7 @@ Stats stats;
210211
}
211212

212213
DEFINE_VEC(byte_t, BYTE)
214+
DEFINE_VEC(Frame*, FRAME)
213215
DEFINE_VEC(ValType*, VALTYPE)
214216
DEFINE_VEC(FuncType*, FUNCTYPE)
215217
DEFINE_VEC(GlobalType*, GLOBALTYPE)
@@ -295,8 +297,9 @@ auto Engine::make(own<Config*>&& config) -> own<Engine*> {
295297
v8::internal::FLAG_expose_gc = true;
296298
v8::internal::FLAG_experimental_wasm_bigint = true;
297299
v8::internal::FLAG_experimental_wasm_mv = true;
298-
// v8::internal::FLAG_experimental_wasm_anyref = true;
299-
// v8::internal::FLAG_experimental_wasm_bulk_memory = true;
300+
v8::internal::FLAG_experimental_wasm_anyref = true;
301+
v8::internal::FLAG_experimental_wasm_bulk_memory = true;
302+
v8::internal::FLAG_experimental_wasm_return_call = true;
300303
// v8::V8::SetFlagsFromCommandLine(&argc, const_cast<char**>(argv), false);
301304
auto engine = new(std::nothrow) EngineImpl;
302305
if (!engine) return own<Engine*>();
@@ -1217,6 +1220,64 @@ void Ref::set_host_info(void* info, void (*finalizer)(void*)) {
12171220
///////////////////////////////////////////////////////////////////////////////
12181221
// Runtime Objects
12191222

1223+
// Frames
1224+
1225+
struct FrameImpl {
1226+
FrameImpl(
1227+
own<Instance*>&& instance, uint32_t func_index,
1228+
size_t func_offset, size_t module_offset
1229+
) :
1230+
instance(std::move(instance)),
1231+
func_index(func_index),
1232+
func_offset(func_offset),
1233+
module_offset(module_offset)
1234+
{
1235+
stats.make(Stats::FRAME, this);
1236+
}
1237+
1238+
~FrameImpl() { stats.free(Stats::FRAME, this); }
1239+
1240+
own<Instance*> instance;
1241+
uint32_t func_index;
1242+
size_t func_offset;
1243+
size_t module_offset;
1244+
};
1245+
1246+
template<> struct implement<Frame> { using type = FrameImpl; };
1247+
1248+
1249+
Frame::~Frame() {
1250+
impl(this)->~FrameImpl();
1251+
}
1252+
1253+
void Frame::operator delete(void *p) {
1254+
::operator delete(p);
1255+
}
1256+
1257+
auto Frame::copy() const -> own<Frame*> {
1258+
auto self = impl(this);
1259+
return own<Frame*>(seal<Frame>(new(std::nothrow) FrameImpl(
1260+
self->instance->copy(), self->func_index, self->func_offset,
1261+
self->module_offset)));
1262+
}
1263+
1264+
auto Frame::instance() const -> Instance* {
1265+
return impl(this)->instance.get();
1266+
}
1267+
1268+
auto Frame::func_index() const -> uint32_t {
1269+
return impl(this)->func_index;
1270+
}
1271+
1272+
auto Frame::func_offset() const -> size_t {
1273+
return impl(this)->func_offset;
1274+
}
1275+
1276+
auto Frame::module_offset() const -> size_t {
1277+
return impl(this)->module_offset;
1278+
}
1279+
1280+
12201281
// Traps
12211282

12221283
template<> struct implement<Trap> { using type = RefImpl<Trap>; };
@@ -1249,6 +1310,16 @@ auto Trap::message() const -> Message {
12491310
return vec<byte_t>::make(std::string(*string));
12501311
}
12511312

1313+
auto Trap::origin() const -> own<Frame*> {
1314+
// TODO(v8): implement
1315+
return own<Frame*>(nullptr);
1316+
}
1317+
1318+
auto Trap::trace() const -> vec<Frame*> {
1319+
// TODO(v8): implement
1320+
return vec<Frame*>::make();
1321+
}
1322+
12521323

12531324
// Foreign Objects
12541325

0 commit comments

Comments
 (0)