[Mono-dev] Fixing Thread:Abort handling of finally clauses

Rodrigo Kumpera kumpera at gmail.com
Tue Mar 9 19:39:20 EST 2010


Hi Paolo,

I've spent some time talking with Zoltan and reading more code from the
runtime and I have the follow proposal for fixing the problem.
First, the problem is that we must not abort finally blocks, the exception
must be thrown right after it ends.
There are two options to fix this.

One is to patch the return address of a finally clause to jump into runtime
code that will handle raising the ThreadAbortException.
This is very tricky because we need to store precise unwind information to
be able to figure out where that value is. The advantage is
that is doesn't slow down the fast path.

The other option is to change how finally clauses work so they make this
easier. Zoltan mentioned that we should restore from EH context and use a
variable to tell what to do next. The pseudo-code for the fast-path are
something like:

Currently:
try_body:
   ...
  call finally
  jmp rest_of_function
finally:
  ...
  ret
rest_of_function:
  ...

Zoltan's suggestion:

try body:
  ...
  mov 0, [EBP + ?] //this is the variable that tells to resume unwinding or
not
  jmp finally;
finally:
 ...
 cmp 0, [EBP + ?]
 jmp_if_zero rest_of_function
 call resume_unwinding
rest_of_function:
 ...

Looking at the pseudo code, currently we do 3 branches (call, ret, jmp) with
Zoltan's suggestion
we would do only two (jmp, jz), thou one is conditional. The memory
bandwidth is the same,
both require one load and one store. Zoltan's suggestion should result in
larger code thou.

But his suggestion, of course, can be optimized to do a lot better,
something like the following
won't be unusual since ordinary "try {} finally {}" code is laid out
sequentialy:


try body:
  ...
  mov 0, [EBP + ?] //this is the variable that tells to resume unwinding or
jump somewhere else
  //no jmp, we just fall thru
finally:
  ...
  cmp 0, [EBP + ?]
  jmp_if_not_zero out_of_line_block
rest_of_function:
  ...

out_of_line_block:
  call resume_unwinding


The version is faster than what we currently generates and enables us to
trap finally handlers without doing something tricky as return address
patching.

For the cases where we have many leave instructions that target different
instructions
we can generate either a jump table, a series of tests or set the
destination variable to
an offset and use an indirect relative jump. All of those depending on what
platform/target
we are. (AOT x86 is better served with an indirect rel jump while ARM can
always use a
jump table).

>From our irc log, you raised a few issues with this approach, first that is
might cause
issues with the ppc ABI. This approach is basically the same to how we
handle catch
clauses and the later doesn't seen to have issues.

You also mentioned that a finally clause can be called in a different stack
frame that
of its original method. I fail to see how could that happen, specially if
we'll be restoring to it.

I do support Zoltan that this approach is the way to go, but I rather hear
your opinion first.
Even if it ends up been marginally slower, it has the advantage of been much
much simpler,
which wins us in development time and reliability.

Thanks,
Rodrigo
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.ximian.com/pipermail/mono-devel-list/attachments/20100309/7008410c/attachment.html 


More information about the Mono-devel-list mailing list