Mark Shannon wrote:> Andrew Haley wrote: >> Mark Shannon wrote: >>> Andrew Haley wrote: >>>> Mark Shannon wrote: >>>>> Nick Johnson wrote: >>>>>>> probably there should be a switch to choose whether codegen should turn >>>>>>> unwind/invoke into dwarf or setjmp/longjmp style code. >>>>> It seems to me that there is an implicit, and undocumented, assumption >>>>> that unwinding needs to handle stack-allocated objects. >>>>> >>>>> In languages without stack-allocated objects (ie. most languages that >>>>> support exceptions) there is no need to unwind frame-by-frame, the >>>>> unwind simply needs to make a single jump to the invoke instruction and >>>>> restore the context (which in x86 is just 6 registers). >>>> Not quite. It's also necessary to execute all the pending POSIX >>>> pthread_cleanup_pop() actions. >>> POSIX pthread_cleanup_pop() can only be called directly from C++/C. >>> C doesn't haven't exceptions. >> But it does have pthread_exit(). >> >>> So yet again, this is a C++ issue. >> No, it isn't: >> >> The effect of calling longjmp() or siglongjmp() is undefined if there >> have been any calls to pthread_cleanup_push() or pthread_cleanup_pop() >> made without the matching call since the jump buffer was filled. >> > > We are not talking about longjmp() or siglongjmp() we are talking about > invoke/unwind!Let's go back a bit. Your claim is that there is no need to unwind frame-by-frame, an unwind simply needs to make a single jump to an invoke instruction and restore the context (which in x86 is just 6 registers). (This is, more or less, what longjmp() does.) Duncan Sands explained to you why that wouldn't work, saying "if you throw an exception using your proposed unwind implementation, then it wouldn't be caught by dwarf catch/cleanup regions". He's right. You can't just jump to the invoke instruction, you must also pop any cleanups. This is nothing to do with C++, and it has nothing to do with whether a language has stack-allocated objects. Andrew.
> > Let's go back a bit. Your claim is that there is no need to unwind > frame-by-frame, an unwind simply needs to make a single jump to an > invoke instruction and restore the context (which in x86 is just 6 > registers). (This is, more or less, what longjmp() does.) Duncan Sands > explained to you why that wouldn't work, saying "if you throw an > exception using your proposed unwind implementation, then it wouldn't > be caught by dwarf catch/cleanup regions". > > He's right. You can't just jump to the invoke instruction, you must > also pop any cleanups. This is nothing to do with C++, and it has > nothing to do with whether a language has stack-allocated objects. > > Andrew.But don't all functions that require cleanups issue invokes rather than calls? Unwind or __cxa_throw would just go to the nearest one, no?
Kenneth Uildriks wrote:>> Let's go back a bit. Your claim is that there is no need to unwind >> frame-by-frame, an unwind simply needs to make a single jump to an >> invoke instruction and restore the context (which in x86 is just 6 >> registers). (This is, more or less, what longjmp() does.) Duncan Sands >> explained to you why that wouldn't work, saying "if you throw an >> exception using your proposed unwind implementation, then it wouldn't >> be caught by dwarf catch/cleanup regions". >> >> He's right. You can't just jump to the invoke instruction, you must >> also pop any cleanups. This is nothing to do with C++, and it has >> nothing to do with whether a language has stack-allocated objects. > > But don't all functions that require cleanups issue invokes rather > than calls?I don't think so: any function in any language that has pthreads bindings can call pthread_cleanup_push() . Andrew.
Andrew Haley wrote:> Mark Shannon wrote: >> Andrew Haley wrote: >>> Mark Shannon wrote: >>>> Andrew Haley wrote: >>>>> Mark Shannon wrote: >>>>>> Nick Johnson wrote: >>>>>>>> probably there should be a switch to choose whether codegen should turn >>>>>>>> unwind/invoke into dwarf or setjmp/longjmp style code. >>>>>> It seems to me that there is an implicit, and undocumented, assumption >>>>>> that unwinding needs to handle stack-allocated objects. >>>>>> >>>>>> In languages without stack-allocated objects (ie. most languages that >>>>>> support exceptions) there is no need to unwind frame-by-frame, the >>>>>> unwind simply needs to make a single jump to the invoke instruction and >>>>>> restore the context (which in x86 is just 6 registers). >>>>> Not quite. It's also necessary to execute all the pending POSIX >>>>> pthread_cleanup_pop() actions. >>>> POSIX pthread_cleanup_pop() can only be called directly from C++/C. >>>> C doesn't haven't exceptions. >>> But it does have pthread_exit(). >>> >>>> So yet again, this is a C++ issue. >>> No, it isn't: >>> >>> The effect of calling longjmp() or siglongjmp() is undefined if there >>> have been any calls to pthread_cleanup_push() or pthread_cleanup_pop() >>> made without the matching call since the jump buffer was filled. >>> >> We are not talking about longjmp() or siglongjmp() we are talking about >> invoke/unwind! > > Let's go back a bit. Your claim is that there is no need to unwind > frame-by-frame, an unwind simply needs to make a single jump to an > invoke instruction and restore the context (which in x86 is just 6 > registers). (This is, more or less, what longjmp() does.) Duncan Sands > explained to you why that wouldn't work, saying "if you throw an > exception using your proposed unwind implementation, then it wouldn't > be caught by dwarf catch/cleanup regions".If you can make your point without any references to any C/C++ specific features it might be more convincing ;)> > He's right. You can't just jump to the invoke instruction, you must > also pop any cleanups. This is nothing to do with C++, and it has > nothing to do with whether a language has stack-allocated objects.What cleanups? If the C++ front end leaves all these dead objects on the stack and insists they are cleaned up promptly, then it its responsibility to clean them up. It shouldn't burden other front-ends. In a purely heap allocated language without finalizers, say ML or haskell, there is nothing to clean-up and a simple jump will suffice. For languages with finalizers such as Python or Java, a special finalizer thread can do the cleaning up lazily once the GC has collected the dead objects. It does depend on the language semantics, and a lot of languages allow lazy finalization of objects.> > Andrew. > _______________________________________________ > LLVM Developers mailing list > LLVMdev at cs.uiuc.edu http://llvm.cs.uiuc.edu > http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev >
On Mon, Jul 20, 2009 at 7:09 AM, Mark Shannon<marks at dcs.gla.ac.uk> wrote:> For languages with finalizers such as Python or Java, a special > finalizer thread can do the cleaning up lazily once the GC has collected > the dead objects.Both Java and Python support "finally" clauses, which are roughly equivalent in this context. -Eli
Mark Shannon wrote:> Andrew Haley wrote:>> Let's go back a bit. Your claim is that there is no need to unwind >> frame-by-frame, an unwind simply needs to make a single jump to an >> invoke instruction and restore the context (which in x86 is just 6 >> registers). (This is, more or less, what longjmp() does.) Duncan Sands >> explained to you why that wouldn't work, saying "if you throw an >> exception using your proposed unwind implementation, then it wouldn't >> be caught by dwarf catch/cleanup regions". > > If you can make your point without any references to any C/C++ specific > features it might be more convincing ;)Well, you seemed to be claiming that cleanups were due to stack-allocated objects in C++. I have shown that is not the case.>> He's right. You can't just jump to the invoke instruction, you must >> also pop any cleanups. This is nothing to do with C++, and it has >> nothing to do with whether a language has stack-allocated objects. > > What cleanups?The ones pushed by pthread_cleanup_push().> If the C++ front end leaves all these dead objects on the stack and > insists they are cleaned up promptly, then it its responsibility to > clean them up. > It shouldn't burden other front-ends.Like I said, it's nothing to do with C++, or with the C++ front end.> In a purely heap allocated language without finalizers, say ML or > haskell, there is nothing to clean-up and a simple jump will suffice. > > For languages with finalizers such as Python or Java, a special > finalizer thread can do the cleaning up lazily once the GC has collected > the dead objects.[Aside: That's not quite true for Java, where unwinding releases locks. This could be done by registering a handler at every site where a lock is acquired, but I don't think that's how it generally works.] Maybe there does exist a programming language that never calls (or is called by) programs in other programming languages and never runs in an environment where one of its threads may be terminated. In that case, interoperability of generated code doesn't matter. In the heterogeneous world of the contemporary OS I'm not sure if that's a common case. Andrew.
On Mon, Jul 20, 2009 at 10:09 AM, Mark Shannon<marks at dcs.gla.ac.uk> wrote:> Andrew Haley wrote: > If you can make your point without any references to any C/C++ specific > features it might be more convincing ;) >I did. Recall my mention of java/c#/ruby/python's finally/ensure blocks, or C#'s using blocks. For proper implementation, these need multi-level unwinds, as they specify that some code must run, even if an exception would bail-out.> I take it you have never used Python ;) > (Python uses exceptions to terminate loops, so it helps if they aren't > too slow)I have used python, and it is slow (sorry). In fact, python Exceptions are implemented in python as a second return value, thus EVERY function, even those which don't throw exceptions, must pay the price. And just because the python community does it, doesn't mean it's good programming practice.>Please try and get out of the C++ mindset, llvm may be implemented *in* >C++, but its not implemented just *for* C++ (at least I hope it isn't).That is exactly my argument. Multi-level unwinds are required by MANY languages. -- Nick Johnson