Jakob Stoklund Olesen
2011-Jun-13 17:30 UTC
[LLVMdev] Is LLVM expressive enough to represent asynchronous exceptions?
On Jun 13, 2011, at 12:29 AM, John McCall wrote:> Let me make an analogy. We live in Germany. Sohail wants to drive to Spain. Duncan told him to go through France. You and Cameron are saying that the traffic in France is awful, and some friends who went to Italy didn't go through France. I am trying to point out that Italy is not Spain, even though they are both on the Mediterranean, and that you have to drive through France to get to Spain. > > There is really no alternative to putting EH edges on basic blocks if you're going to support preemptive asynchronous exceptions — some random multiply that gets hoisted out of a loop has to change exception handlers just in case that's where the PC lands during a signal. There isn't much point in complaining that doing so muddies the CFG, which is really just an inherent fact of handling asynchronous exceptions. That is not true for synchronous exceptions; you don't have to abandon the "internally throwing instructions are terminators" design at all, you just have to allow more things to be terminators.Before we go through the horrible traffic in France, we should make sure that Spain is actually there. It is one thing to define an IR that can handle async exceptions, but it has to be translated to machine code without phi nodes and atomic 512-bit stores. It seems impractical to me to generate code that can correctly handle an async exception after every (machine) instruction. Has anyone done this before? Do they allow functions to use anything other than atomic, volatile variables? Even that won't work: void *volatile p = 0; try { p = malloc(7); } finally { free(p); } The try block would look something like: call _malloc movq %rax, p(%rpb) If you take an exception between those two instructions, you are leaking memory. /jakob
John McCall
2011-Jun-13 17:50 UTC
[LLVMdev] Is LLVM expressive enough to represent asynchronous exceptions?
On Jun 13, 2011, at 10:30 AM, Jakob Stoklund Olesen wrote:> On Jun 13, 2011, at 12:29 AM, John McCall wrote: >> Let me make an analogy. We live in Germany. Sohail wants to drive to Spain. Duncan told him to go through France. You and Cameron are saying that the traffic in France is awful, and some friends who went to Italy didn't go through France. I am trying to point out that Italy is not Spain, even though they are both on the Mediterranean, and that you have to drive through France to get to Spain. >> >> There is really no alternative to putting EH edges on basic blocks if you're going to support preemptive asynchronous exceptions — some random multiply that gets hoisted out of a loop has to change exception handlers just in case that's where the PC lands during a signal. There isn't much point in complaining that doing so muddies the CFG, which is really just an inherent fact of handling asynchronous exceptions. That is not true for synchronous exceptions; you don't have to abandon the "internally throwing instructions are terminators" design at all, you just have to allow more things to be terminators. > > Before we go through the horrible traffic in France, we should make sure that Spain is actually there.That is a fair objection. :)> void *volatile p = 0; > try { > p = malloc(7); > } > finally { > free(p); > } > > The try block would look something like: > > call _malloc > movq %rax, p(%rpb) > > If you take an exception between those two instructions, you are leaking memory.This is primarily an argument that C is not a good language to write async-exceptions-safe code in. Java has similar potential races with async exceptions for non-memory resources that are cleaned up with finally blocks. Note that the IR actually has sufficient information for this if optimization is on; you'd just need completely ridiculous "where is this value at this specific instruction" logic in order to actually do the cleanup. :) But that's actually doable with DWARF.... Again, I tend to agree that there are fundamental semantics problems with async exceptions, and I am not trying to argue that we should tackle them. John.
Jakob Stoklund Olesen
2011-Jun-13 18:37 UTC
[LLVMdev] Is LLVM expressive enough to represent asynchronous exceptions?
On Jun 13, 2011, at 10:50 AM, John McCall wrote:> On Jun 13, 2011, at 10:30 AM, Jakob Stoklund Olesen wrote: >> The try block would look something like: >> >> call _malloc >> movq %rax, p(%rpb) >> >> If you take an exception between those two instructions, you are leaking memory. > > This is primarily an argument that C is not a good language to write async-exceptions-safe code in. Java has similar potential races with async exceptions for non-memory resources that are cleaned up with finally blocks. > > Note that the IR actually has sufficient information for this if optimization is on; you'd just need completely ridiculous "where is this value at this specific instruction" logic in order to actually do the cleanup. :) But that's actually doable with DWARF....I agree with 'doable' and 'ridiculous' ;-)> Again, I tend to agree that there are fundamental semantics problems with async exceptions, and I am not trying to argue that we should tackle them.Right. I agree that we would need EH edges on basic blocks to deal with async exceptions. It would also require a completely different way of dealing with exceptions in the optimizers and code generators. Synchronous exceptions are a completely different thing as you pointed out. They can be modeled with an explicit CFG, or with special EH edges on basic blocks. The explicit CFG forces the ordering of trapping instructions. Something that may not be a language requirement? /jakob
Reasonably Related Threads
- [LLVMdev] Is LLVM expressive enough to represent asynchronous exceptions?
- [LLVMdev] Is LLVM expressive enough to represent asynchronous exceptions?
- [LLVMdev] Is LLVM expressive enough to represent asynchronous exceptions?
- [LLVMdev] Is LLVM expressive enough to represent asynchronous exceptions?
- [LLVMdev] Is LLVM expressive enough to represent asynchronous exceptions?