WebAssembly / tail-call

Proposal to add tail calls to WebAssembly
https://webassembly.github.io/tail-call/
Other
111 stars 8 forks source link

Stack trace associated with failing return_call_indirect #20

Open yurydelendik opened 1 year ago

yurydelendik commented 1 year ago

Currently there are no strict requirements for produced stack in the WebAssembly.Exception Error. I wonder what will be expected stack trace for the return calls.

SpiderMonkey implementation of call_indirect checks the function signature at the callee side. Information about originating call site will be lost. The trap handler has no association of the trap code and its source/origin, so we are planning to start stack trace from the previous frame, or keep it empty if there are no other frames.

The https://github.com/WebAssembly/tail-call/blob/main/proposals/tail-call/Overview.md#execution-1 has no instructions on the subject.

fgmccabe commented 1 year ago

Yes. Technically, since EH is earlier in the standard cycle than tail call, that proposal should address this question. A related issue is what happens when you return_call in a try block. We did discuss that question, and the answer was that the semantics of a return_call is that you first of all 'return' and then 'call' the new function. (I.e., exceptions coming out of a return_called function in a try block are not expected to be caught in that try block. I suspect the same resolution will apply to traps.

yurydelendik commented 1 year ago

exceptions coming out of a return_called function in a try block are not expected to be caught in that try block

Just to narrow down the issue, let's scope this only to return_call_indirect and its calling with incorrect signature. The same will apply to return_call_ref.

fgmccabe commented 1 year ago

In general, traps are not catchable by wasm code.

yurydelendik commented 1 year ago

In general, traps are not catchable by wasm code.

That's correct.

I'm asking about content of the stack property for the WebAssembly.Exception WebAssembly.RuntimeError JS object.

fgmccabe commented 1 year ago

This should be pursued on the EH repo: https://github.com/WebAssembly/exception-handling

yurydelendik commented 1 year ago

(Sorry, changed the JS object name -- it is just regular JS Error since it is just trap) Not sure it is related to EH

thibaudmichaud commented 1 year ago

In V8 we check the signature from the caller, so if there is a signature mismatch during an return_call_indirect instruction, the caller does appear in the stack trace.

titzer commented 1 year ago

Wizard also checks the signature before unwinding the caller frame. Off the top of my head, callee-side checking can still be accomplished if the callee is also responsible for retracting the machine stack pointer and the caller does save the calling address somewhere. (Perhaps using an actual machine call that retracts the caller frame and discards the return address).

yurydelendik commented 1 year ago

Off the top of my head, callee-side checking can still be accomplished if the callee is also responsible for retracting the machine stack pointer and the caller does save the calling address somewhere.

Yes, this is a backup plan. It will be really nice to not reserve a register and instructions to pass the caller callsite ID.

Is this functionality really expected/needed from users point of view? I can read into execution overview both ways.

thibaudmichaud commented 1 year ago

The spec text is not ambiguous about the order of operations: https://webassembly.github.io/tail-call/core/exec/instructions.html#xref-syntax-instructions-syntax-instr-control-mathsf-return-call-indirect-x The signature check happens before the indirect call, so I would expect the tail-caller to be the topmost item of the stack trace. It also seems nicer from the perspective of a user trying to debug where the trap comes from. But this is just my biased opinion, the spec doesn't have requirements for the stack property AFAIK.

rossberg commented 1 year ago

Indeed, the spec does not care either way. Since stack traces are only observable in JS, the core Wasm spec is agnostic to them. But even JS does not specify stack traces. So it's up to implementations.

Personally, I'd find having the call site, before unwinding the stack, as the origin more natural. Conceptually, it is the [return_]call_indirect instruction performing the type check, not the callee.