Comments (13)
Represent the snapshot as two arrays
- an array of frames
- an array of bytes
Frames are:
struct Frame {
uintptr_t pc;
// Index into the second array of start of string
// string is terminated with zero
unsigned fileOffset;
unsigned functionOffset;
int lineno;
};
Before creating the error object, use libbacktrace to create these two arrays, allocated with malloc/realloc.
Then store the snapshot with the error object in a single allocation from _bal_alloc.
typedef GC struct Error {
TaggedPtr message;
uint32_t lineNumber;
uint32_t nFrames;
Frame frames[];
} *ErrorPtr;
The second array of bytes follows the last frame. After constructing the error object, free the two arrays.
You should put a limit on the number of frames stored.
from nballerina.
@jclark, I have come up with a couple of approaches.
-
Use libbacktrace with debug info
Using this approach we can get the line numbers of the caller functions. But we need to inject debug info into our LLVM IR. We can get an output that is the same as jballerina. -
Use libbacktrace without debug info
This approach is easy to implement but we cannot get the line numbers we can only get the function names. -
Pass accumulated location info to each function. (Rust is using something like this just to print the location of the panic)
In this approach, we need compiler support to identify the location and pass the location to each caller. Also, we have to change the function signature. But we do not need a third-party library.
Since we need to be as lazy as possible as you mentioned above, I prefer to use the second approach. Really appreciate your input on this.
from nballerina.
Option 3 is what we are doing now, and it's a pain. It complicates the compiler and requires generating lots of extra basic blocks.
We will at some point need to generate debug info in the IR, because we will need to support debugging. So eventually we want to do 1, but I don't want to do this right now.
Can we just put a little bit of debug info in the IR and get some line numbers out of libbacktrace? For example, if the compiler generates a call to some runtime function foo which may panic, can the compiler just put a line number on that call and get something?
So my question: what is the absolute minimum amount of debug info needed to get some line numbers from libbacktrace?
from nballerina.
@jclark, This is a working example that prints the backtrace for panic https://github.com/KavinduZoysa/test-GCs/tree/backtrace.
In panic-example
folder, I have added two LLVM IRs to represent the difference between when there is no debug info and when there is debug info. As a summary, we have to add,
from nballerina.
@jclark My plan for the implementations is mentioned below. Appreciate your thoughts on this.
- Add a new field to ErrorPtr this field should be an array(TaggedPtrArray), each member of this array represents a string that includes method name and line number.
- Inside _bal_error_constructor, we have to call libbacktrace and get backtrace info. Using this backtrace info, we have to create stackFrames array. The backtrace info should contain the function name and line number(we have tested that in comment).
- Define langlib method called _Berror_stackTrace and it should accept tagged error ptr and return List of stackFrames.
from nballerina.
error:stackFrame is not part of the subset: we are a long, long way from having enough of the language implemented to support error:stackFrame.
The key point is what I mentioned at the beginning:
We want to be as lazy as possible here, i.e. do as little work as possible when taking the snapshot, because the backtrace may never be needed
So in _bal_error_construct you should call libbacktrace and, with minimum work, store a compact representation of the stack. Separately, you should have a function to print that representation out (which is what #6 would do).
from nballerina.
In the Error structure you should save the pc, lineno, filename and function. Probably best to use a linked list:
struct Frame {
struct Frame *next
uintptr_t pc;
// These can point either into the bytes array
// or into another frame.
char *filename;
char *function;
int lineno;
char[] bytes;
}
Search a few frames to avoid having multiple copies of the same filename/function.
from nballerina.
@jclark, I did not understand the use of having char[] bytes;
, can you please explain it?
from nballerina.
You have to copy the filename and function. Instead of having a separate allocation, you do a single allocation. Similar to MediumString.
from nballerina.
Unfortunately what I suggested isn't going to work with garbage allocation. We need to avoid doing any (GC) allocation in the callback.
from nballerina.
If I understand correctly, what we have to do is, allocations done inside the callback function should be copied to a new location (GC allocated) from outside the callback function(May be inside _bal_error_construct
). Then we have to free the allocations in callbackfunction. Am I correct?
from nballerina.
Note that neither backtrace_create_state
nor backtrace_simple
do much work. The expensive work (reading all the elf/dwarf structures) happens on the first call to any of backtrace_syminfo
/backtrace_pcinfo
/backtrace_full
.
from nballerina.
I guess -funwind
is needed because libbacktrace uses the compiler support _Unwind_Backtrace function, which may not get linked in unless -funwind
is used.
from nballerina.
Related Issues (20)
- Add ability to test the jni version of the compiler against the test suite
- Refactor `BinOp` and `UnaryOp` to use `ProperSubtypeData` HOT 1
- Look in to why certain optimizations not happening with object files
- Fix `xml<never>` to be a non-sequence
- Make top type of a basic type to be a BasicTypeBitSet at creation
- Be more eager in intersect
- Avoid maintaining the order of pre-defined atoms in two places
- Migrate to jBallerina 2201.3.0 HOT 1
- Introduce undef basic type HOT 1
- Decimal exact equals produce wrong result for different precision zeros at runtime HOT 1
- Change `jni.llvm` to use TypeInContext HOT 2
- Conformance tests not updating correctly
- Parse inconsistency in left shift
- Result type of shift operators is incorrect HOT 2
- Error when defining xml sequence type of length 2 or more
- Revert jni.llvm maven repository to maven central
- Refactor `Field` type to represent its details more obviously HOT 1
- Simplify table complement operator resultant `SubtypeData` representation
- Fix `MAPPING_ATOMIC_RO` being predefined twice HOT 1
- Extend undef for list type
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from nballerina.