Re: [MLton] understanding exnstack and Raise()

Matthew Fluet <[email protected]> Thu, 20 Jun 2019 22:11:01 -0400
Newsgroups gmane.comp.lang.ml.mlton.devel
Message-ID <CAMrhFL5NnVkpf7-5-RX0pCS8aDpSbzOiyguNWXXOm6jwVxC5eQ@mail.gmail.com>
--===============2885379605117284331==
Content-Type: multipart/alternative; boundary="000000000000014fa4058bcbfa12"

--000000000000014fa4058bcbfa12
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

In your small examples, the raise expression was "inlined" into the
function that includes the handler; thus, there is no change of frame when
the "raise" happens; it's just a simple jump.

For an explanation of how exceptions adjust stackTop, consider the
following fragments of a SSA/SSA2/RSSA function:

fun g(a, b, c) : {returns: (int), raises: (exn)} =3D L0()
  ...
  L1():
    ...
    call L2 (f (x, y)) handle _ =3D> L3
  L2(n):
    ...
    raise (m)
 L3(e):
    ...
  ...

Consider the non-tail call in block L1: a non-tail call to function `f`
with arguments `x` and `y`; the function returns normally to block `L2` and
an exception that is raised (and not handled) during the call of `f` will
be handled by block `L3`.  Just before (the setup of) the call to `f`, the
stack will look something like this:

            | tmp3       |
            | tmp2       |
            | tmp1       |
            | earg: XX   |
            | hand: XX   |
            | link: XX   |
            | arg3 (c)   |
            | arg2 (b)   |
stackTop -> | arg1 (a)   |  &1504
...
stackBot -> | ........   |   &288

exnStack: 1032

`stackTop` (pointing to address 1504) is actually pointing to the bottom of
the frame for `g`.  The arguments of `g` (`a`, `b`, and `c`) are found at
the bottom of the stack (but, once they are no longer live in `g`, those
stack slots could be replaced by other locals).  Because `g` installs a
handler (for the call of `f` and possibly other non-tail calls), it
reserves 3 slots on its frame: `link` will remember the current `exnStack`
value to be restored after uninstalling a handler; `hand` will be the label
of the handler, and `earg` will be the value of the handled exception.
 (The `earg` slot is new (as of yesterday); see
https://github.com/MLton/mlton/pull/321.  In the version of MLton that you
are working with, the value of a handled exception is communicated through
a global variable.)  The `tmp1`, `tmp2`, and `tmp3` slots are local
variables of `g` that must be kept live across the non-tail call of `g`.
The current `exnStack` value is location of the handler for any raises that
`g` performs (e.g., the raise in L2); by adding `exnStack` to
`stackBottom`, one obtains the address of the label of the appropriate
handler.  Note that `stackBot` + `exnStack` =3D 1320, which is strictly bel=
ow
the stack for `g`.

Just after calling `f`, the stack will look something like:

...
            | arg2 (y)   |
stackTop -> | arg1 (x)   |
            | L2         |
            | tmp3       |
            | tmp2       |
            | tmp1       |
            | earg: XX   |
            | hand: L3   |
            | link: 1032 |
            | arg3 (c)   |
            | arg2 (b)   |
            | arg1 (a)   |  &1504
...
stackBot -> | .......... |   &288

exnStack: 1256

Here's what has changed: The `exnStack` value (1032) has been stored in the
`link` slot of `g`'s frame; handler `L3` for this non-tail call has been
stored in the `hand` slot of `g`'s frame; the address just above the `hand`
slot of `g`'s frame minus `stackBot` has been stored in `exnStack` (&1504 +
8 * 3 (for the arg slots) + 8 (for the link slot) + 8 (for the hand slot) -
&288 =3D 1256); the continuation label `L2` and the actual arguments `x` an=
d
`y` have been stored stored at the top of `g`'s frame; `stackTop` has been
increased to point to the bottom of `f`'s frame.

Suppose execution continues a bit more, so that `stackTop` grows yet
higher, but no other handlers are installed.  Then the stack will look like=
:

...
            | arg2 (j)   |
stackTop -> | arg1 (i)   |
...
            | arg2 (y)   |
            | arg1 (x)   |
            | L2         |
            | tmp3       |
            | tmp2       |
            | tmp1       |
            | earg: XX   |
            | hand: L3   |
            | link: 1032 |
            | arg3 (c)   |
            | arg2 (b)   |
            | arg1 (a)   |  &1504
...
stackBot -> | .......... |   &288

exnStack: 1256

Now, suppose a `raise (v)` occurs.  We "simply" perform the following:

1) Write `v` into `*(stackBot + exnStack)` (in the new code) or write `v`
into a global (in the old code); this communicates the raised value to the
handler.
2) Set `stackTop` to `stackBot + exnStack`; this cuts the stack down so
that `stackTop` is just above the appropriate handler label.

...
            | arg2 (j)   |
            | arg1 (i)   |
...
            | arg2 (y)   |
            | arg1 (x)   |
            | L2         |
            | tmp3       |
            | tmp2       |
            | tmp1       |
stackTop -> | earg (v)   |
            | hand: L3   |
            | link: 1032 |
            | arg3 (c)   |
            | arg2 (b)   |
            | arg1 (a)   |  &1504
...
stackBot -> | .......... |   &288

exnStack: 1256

3) Jump to `*(stackTop - 8)`; this transfers control to the handler.  (In
the C codegen, this "jump" might need to go through the trampoline.)
4) Subtract 40 from `stackTop`; this cuts the stack down so that it is back
at the bottom of `g`'s frame.  The appropriate amount to cut the stack is
known statically and is the `size` of the `frameInfo` for `L3` Handler
block.
5) Copy the raised value to where L3's argument variable has been allocated
(because the `earg` slot or the global needs to be available if `g`
installs another handler which receives a raised exception).
6) Write the value saved in the `link` slot to `exnStack`; this reinstalls
the previous exception handler.

...
            | arg2 (j)   |
            | arg1 (i)   |
...
            | arg2 (y)   |
            | arg1 (x)   |
            | L2         |
            | tmp3       |
            | tmp2       |
            | tmp1       |
            | earg (v)   |
            | hand: L3   |
            | link: 1032 |
            | arg3 (c)   |
            | arg2 (b)   |
stackTop -> | arg1 (a)   |  &1504
...
stackBot -> | .......... |   &288

exnStack: 1032


This is the general behavior.  There are some additional "optimizations"
performed by the `implementHandlers` pass.  Note that the "old" and "new"
`exnStack` values are the same for every handler that `g` installs.  Thus,
we only need to copy the "old" `exnStack` to the `link` slot once.
Moreover, it doesn't make sense to restore the value of the `link` slot to
`exnStack` if it is only going to be immediately overwritten by another
handler installed by `g`.  So, we look for opportunities to avoid restoring
and setting `exnStack`.  Similarly, if multiple non-tail calls in a
sequence have the same handler block, then the `hand` slot does not need to
be set before every non-tail call.


On Thu, Jun 20, 2019 at 3:40 PM Jeffrey Murphy <[email protected]> wrote=
:

> Starting with your final question first: I=E2=80=99m woking under the dir=
ection of
> Lukasz to make modifications to MLton. I=E2=80=99m working on modifying h=
ow stacks
> are organized in memory and I=E2=80=99m at the point (final point I hope!=
) of
> dealing with how an exception adjusts stackTop.  My approach so far has
> been to look at the compiler code (mainly backend.fun) and the output of
> the various stages to understand how exnStack is used to determine where
> stackTop points after an exception occurs.
>
> Now, for the case you pointed out where the raise is turned into a direct
> jump, what is the effect on stackTop? Is that case essentially the same a=
s
> a return to the previous stack frame?
>
>
> On Jun 20, 2019, at 1:21 PM, Matthew Fluet <[email protected]>
> wrote:
>
> Your example programs are too small; all of the `raise <exn>` expressions
> in them will be turned into direct jumps to the appropriate handler.
>
> The `Raise()` macros you see in the generated .c files are from `raise`
> expressions in the Basis Library implementation that correspond to error
> conditions that are never triggered; that's why you don't see a debugging
> message for them.
>
> You need a larger program.  In particular, you would want a non-tail
> recursive function that raises after growing the stack.  For example:
>
> [mtf@sulfur tmp]$ cat raise-example.sml
> val n =3D valOf (Int.fromString (hd (CommandLine.arguments ())))
> val m =3D valOf (Int.fromString (hd (tl (CommandLine.arguments ()))))
>
> exception E
> fun loop i =3D
>    if i =3D n
>       then raise E
>    else if i =3D 0
>       then n
>    else 1 + loop(i - 1)
>
> val r =3D loop m handle E =3D> 13
>
> val _ =3D print (concat ["r =3D ", Int.toString r, "\n"])
> [mtf@sulfur tmp]$ ../build/bin/mlton -codegen c -cc-opt
> '-DDEBUG_CCODEGEN=3DTRUE' -keep g -debug true -expert true -keep ssa -kee=
p
> ssa2 -keep rssa -keep machine raise-example.sml
> [mtf@sulfur tmp]$ ./raise-example 5 10 2>&1 | grep Raise
> raise-example.0.c:1445: Raise()
>
> Is there a specific aspect of the exception handling implementation that
> you'd like to know about?
>
>
> On Thu, Jun 20, 2019 at 12:02 PM Jeffrey Murphy <[email protected]>
> wrote:
>
>> Hi,
>>
>> I=E2=80=99m trying to understand how exception handling is implemented. =
When I
>> set DEBUG_CCODEGEN to true in c-chunk.h and use the C codegen, I can see
>> Raise() macros being emitted, but they seem to not be referenced (no
>> =E2=80=98Raise=E2=80=99 is printed when I run trivial programs). Is ther=
e doc I can read,
>> or hints anyone can give me?
>>
>> thanks,
>> jeff
>>
>>
>> trival ex 1 (try4.sml)
>>
>> $ cat try4.sml
>> exception A
>> val _ =3D raise A
>>
>> $ ./build/bin/mlton -codegen c -keep g -debug true -expert true -keep ss=
a
>> -keep ssa2 -keep rssa -keep machine  try4.sml
>> $ ./try4 2>&1 | grep Raise
>> $ ./try4 2>&1 | tail
>> try4.1.c:216: Push (-12)
>> try4.1.c:225: BNZ(0, L_106)
>> try4.1.c:225: BNZ(1, L_106)
>> try4.1.c:261: BNZ(0, L_35)
>> try4.1.c:261: BNZ(1, L_35)
>> try4.1.c:225: BNZ(1, L_106)
>> try4.1.c:261: BNZ(0, L_35)
>> try4.1.c:261: BNZ(1, L_35)
>> unhandled exception: A
>> try4.1.c:234: BNZ(0, L_26)
>>
>>
>>
>> trivial ex 2 (try5.sml)
>>
>> $ cat try5.sml
>> exception A
>> fun y z =3D raise A
>> fun x z =3D y z handle A =3D> 1
>> val _ =3D x 1
>>
>> $ ./build/bin/mlton -codegen c -keep g -debug true -expert true -keep ss=
a
>> -keep ssa2 -keep rssa -keep machine  try5.sml
>> $ ./try5 2>&1 | grep Raise
>> $
>>
>> $ git rev-parse --short HEAD
>> 05004a0
>> (May 15 commit)
>>
>>
>>
>>
>> _______________________________________________
>> MLton-devel mailing list
>> [email protected]; [email protected]
>> https://lists.sourceforge.net/lists/listinfo/mlton-devel
>>
> _______________________________________________
> MLton-devel mailing list
> [email protected]; [email protected]
> https://lists.sourceforge.net/lists/listinfo/mlton-devel
>
>
> _______________________________________________
> MLton-devel mailing list
> [email protected]; [email protected]
> https://lists.sourceforge.net/lists/listinfo/mlton-devel
>

--000000000000014fa4058bcbfa12
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr"><div class=3D"gmail_default" style=3D"font-size:large"><fo=
nt face=3D"courier new, monospace"></font><span style=3D"font-family:&quot;=
courier new&quot;,monospace;font-size:small">In your small examples, the ra=
ise expression was &quot;inlined&quot; into the function that includes the =
handler; thus, there is no change of frame when the &quot;raise&quot; happe=
ns; it&#39;s just a simple jump.</span></div><font face=3D"courier new, mon=
ospace"><br>For an explanation of how exceptions adjust stackTop, consider =
the following fragments of a SSA/SSA2/RSSA function:<br><br>fun g(a, b, c) =
: {returns: (int), raises: (exn)} =3D L0()<br>=C2=A0 ...<br>=C2=A0 L1():<br=
>=C2=A0 =C2=A0 ...<br>=C2=A0 =C2=A0 call L2 (f (x, y)) handle _ =3D&gt; L3<=
br>=C2=A0 L2(n):<br>=C2=A0 =C2=A0 ...<br>=C2=A0 =C2=A0 raise (m)<br>=C2=A0L=
3(e):<br>=C2=A0 =C2=A0 ...<br>=C2=A0 ...<br><br>Consider the non-tail call =
in block L1: a non-tail call to function `f` with arguments `x` and `y`; th=
e function returns normally to block `L2` and an exception that is raised (=
and not handled) during the call of `f` will be handled by block `L3`.=C2=
=A0 Just before (the setup of) the call to `f`, the stack will look somethi=
ng like this:<br><br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 | tmp3 =C2=
=A0 =C2=A0 =C2=A0 |<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 | tmp2 =C2=
=A0 =C2=A0 =C2=A0 |<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 | tmp1 =C2=
=A0 =C2=A0 =C2=A0 |<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 | earg: XX=
 =C2=A0 |<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 | hand: XX =C2=A0 |<=
br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 | link: XX =C2=A0 |<br>=C2=A0 =
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 | arg3 (c) =C2=A0 |<br>=C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0 | arg2 (b) =C2=A0 |<br>stackTop -&gt; | arg1 (a) =
=C2=A0 | =C2=A0&amp;1504<br>...<br>stackBot -&gt; | ........ =C2=A0 | =C2=
=A0 &amp;288<br><br>exnStack: 1032<br><br>`stackTop` (pointing to address 1=
504) is actually pointing to the bottom of the frame for `g`.=C2=A0 The arg=
uments of `g` (`a`, `b`, and `c`) are found at the bottom of the stack (but=
, once they are no longer live in `g`, those stack slots could be replaced =
by other locals).=C2=A0 Because `g` installs a handler (for the call of `f`=
 and possibly other non-tail calls), it reserves 3 slots on its frame: `lin=
k` will remember the current `exnStack` value to be restored after uninstal=
ling a handler; `hand` will be the label of the handler, and `earg` will be=
 the value of the handled exception. =C2=A0(The `earg` slot is new (as of y=
esterday); see <a href=3D"https://github.com/MLton/mlton/pull/321">https://=
github.com/MLton/mlton/pull/321</a>.=C2=A0 In the version of MLton that you=
 are working with, the value of a handled exception is communicated through=
 a global variable.) =C2=A0The `tmp1`, `tmp2`, and `tmp3` slots are local v=
ariables of `g` that must be kept live across the non-tail call of `g`.=C2=
=A0 The current `exnStack` value is location of the handler for any raises =
that `g` performs (e.g., the raise in L2); by adding `exnStack` to `stackBo=
ttom`, one obtains the address of the label of the appropriate handler.=C2=
=A0 Note that `stackBot` + `exnStack` =3D 1320, which is strictly below the=
 stack for `g`.<br><br>Just after calling `f`, the stack will look somethin=
g like:<br><br>...<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 | arg2 (y) =
=C2=A0 |<br>stackTop -&gt; | arg1 (x) =C2=A0 |<br>=C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 | L2 =C2=A0 =C2=A0 =C2=A0 =C2=A0 |<br>=C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0 | tmp3 =C2=A0 =C2=A0 =C2=A0 |<br>=C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0 | tmp2 =C2=A0 =C2=A0 =C2=A0 |<br>=C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0 | tmp1 =C2=A0 =C2=A0 =C2=A0 |<br>=C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0 | earg: XX =C2=A0 |<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0=
 =C2=A0 =C2=A0 | hand: L3 =C2=A0 |<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =
=C2=A0 | link: 1032 |<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 | arg3 (=
c) =C2=A0 |<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 | arg2 (b) =C2=A0 =
|<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 | arg1 (a) =C2=A0 | =C2=A0&a=
mp;1504<br>...<br>stackBot -&gt; | .......... | =C2=A0 &amp;288<br><br>exnS=
tack: 1256<br><br>Here&#39;s what has changed: The `exnStack` value (1032) =
has been stored in the `link` slot of `g`&#39;s frame; handler `L3` for thi=
s non-tail call has been stored in the `hand` slot of `g`&#39;s frame; the =
address just above the `hand` slot of `g`&#39;s frame minus `stackBot` has =
been stored in `exnStack` (&amp;1504 + 8 * 3 (for the arg slots) + 8 (for t=
he link slot) + 8 (for the hand slot) - &amp;288 =3D 1256); the continuatio=
n label `L2` and the actual arguments `x` and `y` have been stored stored a=
t the top of `g`&#39;s frame; `stackTop` has been increased to point to the=
 bottom of `f`&#39;s frame.<br><br>Suppose execution continues a bit more, =
so that `stackTop` grows yet higher, but no other handlers are installed.=
=C2=A0 Then the stack will look like:<br><br>...<br>=C2=A0 =C2=A0 =C2=A0 =
=C2=A0 =C2=A0 =C2=A0 | arg2 (j) =C2=A0 |<br>stackTop -&gt; | arg1 (i) =C2=
=A0 |<br>...<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 | arg2 (y) =C2=A0=
 |<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 | arg1 (x) =C2=A0 |<br>=C2=
=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 | L2 =C2=A0 =C2=A0 =C2=A0 =C2=A0 |<b=
r>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 | tmp3 =C2=A0 =C2=A0 =C2=A0 |<b=
r>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 | tmp2 =C2=A0 =C2=A0 =C2=A0 |<b=
r>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 | tmp1 =C2=A0 =C2=A0 =C2=A0 |<b=
r>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 | earg: XX =C2=A0 |<br>=C2=A0 =
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 | hand: L3 =C2=A0 |<br>=C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0 | link: 1032 |<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 | arg3 (c) =C2=A0 |<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=
 | arg2 (b) =C2=A0 |<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 | arg1 (a=
) =C2=A0 | =C2=A0&amp;1504<br>...<br>stackBot -&gt; | .......... | =C2=A0 &=
amp;288<br><br>exnStack: 1256<br><br>Now, suppose a `raise (v)` occurs.=C2=
=A0 We &quot;simply&quot; perform the following:<br><br>1) Write `v` into `=
*(stackBot + exnStack)` (in the new code) or write `v` into a global (in th=
e old code); this communicates the raised value to the handler.<br>2) Set `=
stackTop` to `stackBot + exnStack`; this cuts the stack down so that `stack=
Top` is just above the appropriate handler label.<br><br>...<br>=C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 | arg2 (j) =C2=A0 |<br>=C2=A0 =C2=A0 =C2=A0=
 =C2=A0 =C2=A0 =C2=A0 | arg1 (i) =C2=A0 |<br>...<br>=C2=A0 =C2=A0 =C2=A0 =
=C2=A0 =C2=A0 =C2=A0 | arg2 (y) =C2=A0 |<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 | arg1 (x) =C2=A0 |<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=
 | L2 =C2=A0 =C2=A0 =C2=A0 =C2=A0 |<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =
=C2=A0 | tmp3 =C2=A0 =C2=A0 =C2=A0 |<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =
=C2=A0 | tmp2 =C2=A0 =C2=A0 =C2=A0 |<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =
=C2=A0 | tmp1 =C2=A0 =C2=A0 =C2=A0 |<br>stackTop -&gt; | earg (v) =C2=A0 |<=
br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 | hand: L3 =C2=A0 |<br>=C2=A0 =
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 | link: 1032 |<br>=C2=A0 =C2=A0 =C2=A0 =
=C2=A0 =C2=A0 =C2=A0 | arg3 (c) =C2=A0 |<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 | arg2 (b) =C2=A0 |<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=
 | arg1 (a) =C2=A0 | =C2=A0&amp;1504<br>...<br>stackBot -&gt; | .......... =
| =C2=A0 &amp;288<br><br>exnStack: 1256<br><br>3) Jump to `*(stackTop - 8)`=
; this transfers control to the handler. =C2=A0(In the C codegen, this &quo=
t;jump&quot; might need to go through the trampoline.)<br>4) Subtract 40 fr=
om `stackTop`; this cuts the stack down so that it is back at the bottom of=
 `g`&#39;s frame.=C2=A0 The appropriate amount to cut the stack is known st=
atically and is the `size` of the `frameInfo` for `L3` Handler block.<br>5)=
 Copy the raised value to where L3&#39;s argument variable has been allocat=
ed (because the `earg` slot or the global needs to be available if `g` inst=
alls another handler which receives a raised exception).<br>6) Write the va=
lue saved in the `link` slot to `exnStack`; this reinstalls the previous ex=
ception handler.<br><br>...<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 | =
arg2 (j) =C2=A0 |<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 | arg1 (i) =
=C2=A0 |<br>...<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 | arg2 (y) =C2=
=A0 |<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 | arg1 (x) =C2=A0 |<br>=
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 | L2 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =
|<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 | tmp3 =C2=A0 =C2=A0 =C2=A0 =
|<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 | tmp2 =C2=A0 =C2=A0 =C2=A0 =
|<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 | tmp1 =C2=A0 =C2=A0 =C2=A0 =
|<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 | earg (v) =C2=A0 |<br>=C2=
=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 | hand: L3 =C2=A0 |<br>=C2=A0 =C2=A0=
 =C2=A0 =C2=A0 =C2=A0 =C2=A0 | link: 1032 |<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =
=C2=A0 =C2=A0 | arg3 (c) =C2=A0 |<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 | arg2 (b) =C2=A0 |<br>stackTop -&gt; | arg1 (a) =C2=A0 | =C2=A0&amp;15=
04<br>...<br>stackBot -&gt; | .......... | =C2=A0 &amp;288<br><br>exnStack:=
 1032<br><br><br>This is the general behavior.=C2=A0 There are some additio=
nal &quot;optimizations&quot; performed by the `implementHandlers` pass.=C2=
=A0 Note that the &quot;old&quot; and &quot;new&quot; `exnStack` values are=
 the same for every handler that `g` installs.=C2=A0 Thus, we only need to =
copy the &quot;old&quot; `exnStack` to the `link` slot once.=C2=A0 Moreover=
, it doesn&#39;t make sense to restore the value of the `link` slot to `exn=
Stack` if it is only going to be immediately overwritten by another handler=
 installed by `g`.=C2=A0 So, we look for opportunities to avoid restoring a=
nd setting `exnStack`.=C2=A0 Similarly, if multiple non-tail calls in a seq=
uence have the same handler block, then the `hand` slot does not need to be=
 set before every non-tail call.</font><br></div><br><br><div class=3D"gmai=
l_quote"><div dir=3D"ltr" class=3D"gmail_attr">On Thu, Jun 20, 2019 at 3:40=
 PM Jeffrey Murphy &lt;<a href=3D"mailto:[email protected]">jcmurphy@buf=
falo.edu</a>&gt; wrote:<br></div><blockquote class=3D"gmail_quote" style=3D=
"margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-le=
ft:1ex"><div style=3D"overflow-wrap: break-word;"><font size=3D"4">Starting=
 with your final question first: I=E2=80=99m woking under the direction of =
Lukasz to make modifications to MLton. I=E2=80=99m working on modifying how=
 stacks are organized in memory and I=E2=80=99m at the point (final point I=
 hope!) of dealing with how an exception adjusts stackTop.=C2=A0 My approac=
h so far has been to look at the compiler code (mainly backend.fun) and the=
 output of the various stages to understand how exnStack is used to determi=
ne where stackTop points after an exception occurs.=C2=A0</font><div><font =
size=3D"4"><br></font></div><div><font size=3D"4">Now, for the case you poi=
nted out where the raise is turned into a direct jump, what is the effect o=
n stackTop? Is that case essentially the same as a return to the previous s=
tack frame?=C2=A0<br></font><div><font size=3D"4"><br></font></div><div><br=
><blockquote type=3D"cite"><div>On Jun 20, 2019, at 1:21 PM, Matthew Fluet =
&lt;<a href=3D"mailto:[email protected]" target=3D"_blank">matthew.fl=
[email protected]</a>&gt; wrote:</div><br class=3D"gmail-m_1438575144002829419A=
pple-interchange-newline"><div><div dir=3D"ltr"><div class=3D"gmail_default=
" style=3D"font-family:&quot;courier new&quot;,monospace;font-size:large">Y=
our example programs are too small; all of the `raise &lt;exn&gt;` expressi=
ons in them will be turned into direct jumps to the appropriate handler.</d=
iv><div class=3D"gmail_default" style=3D"font-family:&quot;courier new&quot=
;,monospace;font-size:large"><br></div><div class=3D"gmail_default" style=
=3D"font-family:&quot;courier new&quot;,monospace;font-size:large">The `Rai=
se()` macros you see in the generated .c files are from `raise` expressions=
 in the Basis Library implementation that correspond to error conditions th=
at are never triggered; that&#39;s why you don&#39;t see a debugging messag=
e for them.</div><div class=3D"gmail_default" style=3D"font-family:&quot;co=
urier new&quot;,monospace;font-size:large"><br></div><div class=3D"gmail_de=
fault" style=3D"font-family:&quot;courier new&quot;,monospace;font-size:lar=
ge">You need a larger program.=C2=A0 In particular, you would want a non-ta=
il recursive function that raises after growing the stack.=C2=A0 For exampl=
e:</div><div class=3D"gmail_default" style=3D"font-family:&quot;courier new=
&quot;,monospace;font-size:large"><br></div><div class=3D"gmail_default" st=
yle=3D"font-family:&quot;courier new&quot;,monospace;font-size:large">[mtf@=
sulfur tmp]$ cat raise-example.sml<br>val n =3D valOf (Int.fromString (hd (=
CommandLine.arguments ())))<br>val m =3D valOf (Int.fromString (hd (tl (Com=
mandLine.arguments ()))))<br><br>exception E<br>fun loop i =3D<br>=C2=A0 =
=C2=A0if i =3D n<br>=C2=A0 =C2=A0 =C2=A0 then raise E<br>=C2=A0 =C2=A0else =
if i =3D 0<br>=C2=A0 =C2=A0 =C2=A0 then n<br>=C2=A0 =C2=A0else 1 + loop(i -=
 1)<br><br>val r =3D loop m handle E =3D&gt; 13<br><br>val _ =3D print (con=
cat [&quot;r =3D &quot;, Int.toString r, &quot;\n&quot;])<br>[mtf@sulfur tm=
p]$ ../build/bin/mlton -codegen c -cc-opt &#39;-DDEBUG_CCODEGEN=3DTRUE&#39;=
 -keep g -debug true -expert true -keep ssa -keep ssa2 -keep rssa -keep mac=
hine raise-example.sml<br>[mtf@sulfur tmp]$ ./raise-example 5 10 2&gt;&amp;=
1 | grep Raise<br>raise-example.0.c:1445: Raise()<br></div><div class=3D"gm=
ail_default" style=3D"font-family:&quot;courier new&quot;,monospace;font-si=
ze:large"><br></div><div class=3D"gmail_default" style=3D"font-family:&quot=
;courier new&quot;,monospace;font-size:large">Is there a specific aspect of=
 the exception handling implementation that you&#39;d like to know about?</=
div><div class=3D"gmail_default" style=3D"font-family:&quot;courier new&quo=
t;,monospace;font-size:large"><br></div></div><br><div class=3D"gmail_quote=
"><div dir=3D"ltr" class=3D"gmail_attr">On Thu, Jun 20, 2019 at 12:02 PM Je=
ffrey Murphy &lt;<a href=3D"mailto:[email protected]" target=3D"_blank">=
[email protected]</a>&gt; wrote:<br></div><blockquote class=3D"gmail_quo=
te" style=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204=
);padding-left:1ex">Hi, <br>
<br>
I=E2=80=99m trying to understand how exception handling is implemented. Whe=
n I set DEBUG_CCODEGEN to true in c-chunk.h and use the C codegen, I can se=
e Raise() macros being emitted, but they seem to not be referenced (no =E2=
=80=98Raise=E2=80=99 is printed when I run trivial programs). Is there doc =
I can read, or hints anyone can give me?<br>
<br>
thanks,<br>
jeff<br>
<br>
<br>
trival ex 1 (try4.sml)<br>
<br>
$ cat try4.sml<br>
exception A<br>
val _ =3D raise A<br>
<br>
$ ./build/bin/mlton -codegen c -keep g -debug true -expert true -keep ssa -=
keep ssa2 -keep rssa -keep machine=C2=A0 try4.sml<br>
$ ./try4 2&gt;&amp;1 | grep Raise<br>
$ ./try4 2&gt;&amp;1 | tail<br>
try4.1.c:216: Push (-12)<br>
try4.1.c:225: BNZ(0, L_106)<br>
try4.1.c:225: BNZ(1, L_106)<br>
try4.1.c:261: BNZ(0, L_35)<br>
try4.1.c:261: BNZ(1, L_35)<br>
try4.1.c:225: BNZ(1, L_106)<br>
try4.1.c:261: BNZ(0, L_35)<br>
try4.1.c:261: BNZ(1, L_35)<br>
unhandled exception: A<br>
try4.1.c:234: BNZ(0, L_26)<br>
<br>
<br>
<br>
trivial ex 2 (try5.sml)<br>
<br>
$ cat try5.sml<br>
exception A<br>
fun y z =3D raise A<br>
fun x z =3D y z handle A =3D&gt; 1<br>
val _ =3D x 1<br>
<br>
$ ./build/bin/mlton -codegen c -keep g -debug true -expert true -keep ssa -=
keep ssa2 -keep rssa -keep machine=C2=A0 try5.sml<br>
$ ./try5 2&gt;&amp;1 | grep Raise<br>
$<br>
<br>
$ git rev-parse --short HEAD<br>
05004a0<br>
(May 15 commit)<br>
<br>
<br>
<br>
<br>
_______________________________________________<br>
MLton-devel mailing list<br>
<a href=3D"mailto:[email protected]" target=3D"_blank">MLto=
[email protected]</a>; <a href=3D"mailto:[email protected]"=
 target=3D"_blank">[email protected]</a><br>
<a href=3D"https://lists.sourceforge.net/lists/listinfo/mlton-devel" rel=3D=
"noreferrer" target=3D"_blank">https://lists.sourceforge.net/lists/listinfo=
/mlton-devel</a><br>
</blockquote></div>
_______________________________________________<br>MLton-devel mailing list=
<br><a href=3D"mailto:[email protected]" target=3D"_blank">=
[email protected]</a>; <a href=3D"mailto:mlton-devel@mlton.=
org" target=3D"_blank">[email protected]</a><br><a href=3D"https://list=
s.sourceforge.net/lists/listinfo/mlton-devel" target=3D"_blank">https://lis=
ts.sourceforge.net/lists/listinfo/mlton-devel</a><br></div></blockquote></d=
iv><br></div></div>_______________________________________________<br>
MLton-devel mailing list<br>
<a href=3D"mailto:[email protected]" target=3D"_blank">MLto=
[email protected]</a>; <a href=3D"mailto:[email protected]"=
 target=3D"_blank">[email protected]</a><br>
<a href=3D"https://lists.sourceforge.net/lists/listinfo/mlton-devel" rel=3D=
"noreferrer" target=3D"_blank">https://lists.sourceforge.net/lists/listinfo=
/mlton-devel</a><br>
</blockquote></div>

--000000000000014fa4058bcbfa12--


--===============2885379605117284331==
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: inline


--===============2885379605117284331==
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: inline

_______________________________________________
MLton-devel mailing list
[email protected]; [email protected]
https://lists.sourceforge.net/lists/listinfo/mlton-devel

--===============2885379605117284331==--