Hello there,
I'm implementing a toy programming language similar to javascript. being dynamically typed means more errors can only be detected during runtime. I want to be able to support meaningful error messages, including line number, token position, call stacks etc. But looking at the jit example, I don't know how this should be implemented.
I have 2 naive ideas. The first is defining a global function in rust and exposing it to my language. The purpose of the function is to report the current line number and token position. When generating the IR code, as soon as line number has changed, I insert a call to the above function to report such change to my runtime. In my runtime, I maintain a storage for these meta data. When an issue happens, I pull and print out the current line number.
But this must be very inefficient.
Another idea I have is when I generate the IR code, if the builder.ins().xxx functions could generate a location id, I can then maintain a mapping from the location id to line number. When IR code fails, I can know the location id and use it to look for the line number? like symbol files.
I'm not sure how this is implemented in a real programming language?
on a side note, I'm also interested in knowing how to implement break point.
Hi! There's actually a way to do this more efficiently, as you've guessed. The location id already exists, it's called SourceLoc
in Cranelift (you can also grep for srcloc
, which is the recurring variable name for those): you basically feed it with an index (which can be an index into a map with more metadata, like token pos, line number; or it can be a straightforward line number, for instance). Then, I don't quite know how it is passed in the JIT crate, but the CodeSink impls get information about source location + the event to which they're associated (trap => trap code, for instance), and when recovering on error, you can map from the trap code offset to the source location. (Since my understanding of the JIT crate is a bit limited, there might be other ways to do this in a simpler way!)
When using cranelift-module
for SourceLoc
you will need to access the context
after being passed into define_function
like so: https://github.com/bjorn3/rustc_codegen_cranelift/blob/ae6daf77ba9762f4f118b2342298ce5fa2e32a7a/src/debuginfo/line_info.rs#L205-L240 For TrapCode
the last argument of define_function
is an implementor of the TrapSink
trait.
Thank you very much!
Last updated: Dec 23 2024 at 12:05 UTC