On Sat, May 7, 2016 at 2:19 PM, Yichao Yu <yyc1...@gmail.com> wrote:

> 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].
>

Yeah, that's the same idea. I don't care about restarts either, but in SBCL
(and... Python?) it made for a really nice debugger, since the stack isn't
unwound, and the debugger can just be a top-level `catch` block that
inspects the stack. I wonder how Gallium handles this.


> You probably want to do that **after** unwind the stack. Especially
> when you are throwing a stack overflow error for example =)
>

Judging by how undebuggable/unstable stack overflows in SBCL were, my
uneducated guess is that they ran the exception handlers *before* unwinding
the stack!


> 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)
>

Agreed. It may add an extra cost for every try block even on normal
execution...


> 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