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:"=
courier new",monospace;font-size:small">In your small examples, the ra=
ise expression was "inlined" into the function that includes the =
handler; thus, there is no change of frame when the "raise" happe=
ns; it'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> 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 -> | arg1 (a) =
=C2=A0 | =C2=A0&1504<br>...<br>stackBot -> | ........ =C2=A0 | =C2=
=A0 &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 -> | 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 -> | .......... | =C2=A0 &288<br><br>exnS=
tack: 1256<br><br>Here's what has changed: The `exnStack` value (1032) =
has been stored in the `link` slot of `g`'s frame; handler `L3` for thi=
s 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 t=
he link slot) + 8 (for the hand slot) - &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`'s frame; `stackTop` has been increased to point to the=
bottom of `f`'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 -> | 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&1504<br>...<br>stackBot -> | .......... | =C2=A0 &=
amp;288<br><br>exnStack: 1256<br><br>Now, suppose a `raise (v)` occurs.=C2=
=A0 We "simply" 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 -> | 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&1504<br>...<br>stackBot -> | .......... =
| =C2=A0 &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" 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`'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'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 -> | arg1 (a) =C2=A0 | =C2=A0&15=
04<br>...<br>stackBot -> | .......... | =C2=A0 &288<br><br>exnStack:=
1032<br><br><br>This is the general behavior.=C2=A0 There are some additio=
nal "optimizations" performed by the `implementHandlers` pass.=C2=
=A0 Note that the "old" and "new" `exnStack` values are=
the same for every handler that `g` installs.=C2=A0 Thus, we only need to =
copy the "old" `exnStack` to the `link` slot once.=C2=A0 Moreover=
, it doesn'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 <<a href=3D"mailto:[email protected]">jcmurphy@buf=
falo.edu</a>> 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 =
<<a href=3D"mailto:[email protected]" target=3D"_blank">matthew.fl=
[email protected]</a>> 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:"courier new",monospace;font-size:large">Y=
our example programs are too small; all of the `raise <exn>` 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:"courier new"=
;,monospace;font-size:large"><br></div><div class=3D"gmail_default" style=
=3D"font-family:"courier new",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's why you don't see a debugging messag=
e for them.</div><div class=3D"gmail_default" style=3D"font-family:"co=
urier new",monospace;font-size:large"><br></div><div class=3D"gmail_de=
fault" style=3D"font-family:"courier new",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:"courier new=
",monospace;font-size:large"><br></div><div class=3D"gmail_default" st=
yle=3D"font-family:"courier new",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> 13<br><br>val _ =3D print (con=
cat ["r =3D ", Int.toString r, "\n"])<br>[mtf@sulfur tm=
p]$ ../build/bin/mlton -codegen c -cc-opt '-DDEBUG_CCODEGEN=3DTRUE'=
-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>&=
1 | grep Raise<br>raise-example.0.c:1445: Raise()<br></div><div class=3D"gm=
ail_default" style=3D"font-family:"courier new",monospace;font-si=
ze:large"><br></div><div class=3D"gmail_default" style=3D"font-family:"=
;courier new",monospace;font-size:large">Is there a specific aspect of=
the exception handling implementation that you'd like to know about?</=
div><div class=3D"gmail_default" style=3D"font-family:"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 <<a href=3D"mailto:[email protected]" target=3D"_blank">=
[email protected]</a>> 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>&1 | grep Raise<br>
$ ./try4 2>&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> 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>&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==--