On Sat, May 7, 2016 at 1:21 PM, Cedric St-Jean <cedric.stj...@gmail.com> wrote:
> Thank you for the detailed explanation!
>
> Would it make sense to run the catch blocks/finalizers before unwinding the
> stack? I.e. each `try` pushes its catch/finally block as a "closure" onto a
> separate stack, to be run when an exception occurs, then the stack is only
> unwound once regular control flow is resumed, or collected if no handler was
> found. I was wondering how Common Lisp was able to provide restarts, this
> seems like a reasonable implementation strategy.

Possibly related [1].

You probably want to do that **after** unwind the stack. Especially
when you are throwing a stack overflow error for example =)
The info you need should all be in the closure anyway.

I think this would be mainly useful (avoiding a setjmp) for the try
blocks with only finally (or a catch block that does not return) since
otherwise you'll still need to restore the machine state in order to
continue execution.

Whether this can be implemented efficiently will also depend on if
capture variable in closure can be implemented efficiently. (In
general it's probably harder than issue 3 below)

P.S. this is exactly how automatic unlocking of julia runtime locks
are implemented[2]. Implemented for general julia code will be harder
though.

[1] 
https://groups.google.com/forum/#!searchin/julia-dev/Mason$20Bially/julia-dev/uTeuPv-DVKU/6T4JK3udAgAJ
[2] https://github.com/JuliaLang/julia/pull/14451

>
> On Saturday, May 7, 2016 at 10:28:18 AM UTC-4, Yichao Yu wrote:
>>
>> On Sat, May 7, 2016 at 8:46 AM, Cedric St-Jean <cedric...@gmail.com>
>> wrote:
>> >> mostly due to various technical reason
>>
>> In arbitrary order, the ones I can think of now.
>>
>> 1. We collect backtrace
>>
>>     There are many cases where we don't actually need this info, but
>> we need better code analysis to be able to figure that out.
>>
>> 2. We don't have zero cost exception frame so we need to spill many
>> registers.
>>
>>     It's hard for us to have zero cost exception frame unless all the
>> C libraries are compiled with unwind info. Also note that zero cost
>> exception frame means even more expensive exception throwing since the
>> registers are not explicitly saved and we need to unwind the call
>> stack to restore them. This is a trade off after all.
>>
>> 3. Preserving local variables across an exception requires spilling it
>> to stack and this adds some hidden cost.
>>
>>     It's a little hard to say how much cost this have, probably not
>> THAT much unless you have a lot of variables that is modified in try
>> and used after the exception is caught. Very likely strongly depending
>> on the code pattern.
>>
>> 4. The GC frame allocation is global (well, per-function) instead of
>> control flow local.
>>
>>     This cause allocation in not-taken branch to affect the
>> performance on the taken branch. This is not specific to exceptions
>> but is particularly bad for exceptions since throwing one sometimes
>> requires allocation that otherwise doesn't exist in the function (e.g.
>> `ArgumentError("My error message with $variable spliced in")`) and
>> these branches are meant to be not taken most of the time (if the
>> error can happen most of the time, you'd be better off with a error
>> code return, since exceptions are not designed for that).
>>
>> >
>> > Could you please go into those? I'd like to understand why unwinding the
>> > stack is costlier than returning from a function.
>> >
>> > On Saturday, May 7, 2016 at 8:38:03 AM UTC-4, Yichao Yu wrote:
>> >>
>> >> On Sat, May 7, 2016 at 6:58 AM, Ben Ward <axolotl...@gmail.com> wrote:
>> >> > Hi,
>> >> >
>> >> > I have a question which may be laughable to CS people (be gentle, I'm
>> >> > a
>> >> > Biologist), but we know from guidelines that Julia performs best,
>> >> > when a
>> >> > method always returns the same type of value.
>> >> > So the Julia type inference knows - ok, use this method with an Int,
>> >> > it
>> >> > will
>> >> > always return a bool say. How does throws fit into this? To my mind
>> >> > this
>> >> > means the method used with an Int may return a bool, but it also may
>> >> > result
>> >> > in a type of (e.g.) ArgumentError getting thrown. So how do throws in
>> >> > functions affect performance and julian's ability to infer types and
>> >> > optimise code (if at all?)?
>> >>
>> >> While throwing or catching an error itself is slow (mostly due to
>> >> various technical reason) they shouldn't affect type stability.
>> >>
>> >> The type inference currently do not reason about what type of
>> >> exception can be thrown and even if it does, this won't affect what we
>> >> usually call the type stability of a function since it is only about
>> >> the **return type** of a function and throwing an error is not return
>> >> (in the sense that `a = cond ? error() : 1`, if the next statement is
>> >> executed, a is always a `Int`).
>> >>
>> >> >
>> >> > Thanks,
>> >> > Ben W.

Reply via email to